From 652475a57a4adb662bdbfe4f2bc828a3cb2c416c Mon Sep 17 00:00:00 2001 From: thelitfire Date: Tue, 23 Dec 2025 13:09:47 +0800 Subject: [PATCH 1/3] Trait for save_to of CommitmentKey --- examples/kzg_keygen_tools.rs | 2 +- src/provider/hyperkzg.rs | 6 +++--- src/provider/pedersen.rs | 6 +++--- src/traits/commitment.rs | 18 +++++++++++++++++- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/examples/kzg_keygen_tools.rs b/examples/kzg_keygen_tools.rs index d94c1e6d..802ffd08 100644 --- a/examples/kzg_keygen_tools.rs +++ b/examples/kzg_keygen_tools.rs @@ -10,7 +10,7 @@ use nova_snark::{ hyperkzg::{CommitmentEngine, CommitmentKey}, Bn256EngineKZG, }, - traits::commitment::CommitmentEngineTrait, + traits::commitment::{CommitmentEngineTrait, SaveTo}, }; use rand_core::OsRng; diff --git a/src/provider/hyperkzg.rs b/src/provider/hyperkzg.rs index 635c3bec..7f280be1 100644 --- a/src/provider/hyperkzg.rs +++ b/src/provider/hyperkzg.rs @@ -13,7 +13,7 @@ use crate::{ gadgets::utils::to_bignat_repr, provider::traits::{DlogGroup, DlogGroupExt, PairingGroup}, traits::{ - commitment::{CommitmentEngineTrait, CommitmentTrait, Len}, + commitment::{CommitmentEngineTrait, CommitmentTrait, Len, SaveTo}, evaluation::EvaluationEngineTrait, AbsorbInRO2Trait, AbsorbInROTrait, Engine, ROTrait, TranscriptEngineTrait, TranscriptReprTrait, }, @@ -132,13 +132,13 @@ where } } -impl CommitmentKey +impl SaveTo for CommitmentKey where E::GE: PairingGroup, { /// Save keys #[cfg(feature = "io")] - pub fn save_to( + fn save_to( &self, mut writer: &mut (impl std::io::Write + std::io::Seek), ) -> Result<(), PtauFileError> { diff --git a/src/provider/pedersen.rs b/src/provider/pedersen.rs index 328b84d6..fc33e381 100644 --- a/src/provider/pedersen.rs +++ b/src/provider/pedersen.rs @@ -6,7 +6,7 @@ use crate::{ gadgets::utils::to_bignat_repr, provider::traits::{DlogGroup, DlogGroupExt}, traits::{ - commitment::{CommitmentEngineTrait, CommitmentTrait, Len}, + commitment::{CommitmentEngineTrait, CommitmentTrait, Len, SaveTo}, AbsorbInRO2Trait, AbsorbInROTrait, Engine, ROTrait, TranscriptReprTrait, }, }; @@ -188,12 +188,12 @@ pub struct CommitmentEngine { _p: PhantomData, } -impl CommitmentKey +impl SaveTo for CommitmentKey where E::GE: DlogGroup, { #[cfg(feature = "io")] - pub fn save_to(&self, writer: &mut impl std::io::Write) -> Result<(), PtauFileError> { + fn save_to(&self, writer: &mut impl std::io::Write) -> Result<(), PtauFileError> { writer.write_all(&KEY_FILE_HEAD)?; let mut points = Vec::with_capacity(self.ck.len() + 1); points.push(self.h); diff --git a/src/traits/commitment.rs b/src/traits/commitment.rs index 61a53c80..ba0a9552 100644 --- a/src/traits/commitment.rs +++ b/src/traits/commitment.rs @@ -47,11 +47,27 @@ pub trait Len { fn length(&self) -> usize; } +/// A trait for saving structures to a writer +pub trait SaveTo { + /// Saves the structure to the provided writer. + fn save_to( + &self, + writer: &mut (impl std::io::Write + std::io::Seek), + ) -> Result<(), PtauFileError>; +} + /// A trait that ties different pieces of the commitment generation together pub trait CommitmentEngineTrait: Clone + Send + Sync { /// Holds the type of the commitment key /// The key should quantify its length in terms of group generators. - type CommitmentKey: Len + Clone + Debug + Send + Sync + Serialize + for<'de> Deserialize<'de>; + type CommitmentKey: Len + + SaveTo + + Clone + + Debug + + Send + + Sync + + Serialize + + for<'de> Deserialize<'de>; /// Holds the type of the derandomization key type DerandKey: Clone + Debug + Send + Sync + Serialize + for<'de> Deserialize<'de>; From 4b6e7ae1ae9c0cff30f17ad331e9bab2dee1ba8c Mon Sep 17 00:00:00 2001 From: thelitfire Date: Tue, 23 Dec 2025 14:06:54 +0800 Subject: [PATCH 2/3] Trait for checking key file sanity --- examples/kzg_keygen_tools.rs | 2 +- src/provider/hyperkzg.rs | 17 ++++++++++++++--- src/provider/pedersen.rs | 20 ++++++++++++++++++-- src/traits/commitment.rs | 16 ++++++++++++---- 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/examples/kzg_keygen_tools.rs b/examples/kzg_keygen_tools.rs index 802ffd08..17a3f484 100644 --- a/examples/kzg_keygen_tools.rs +++ b/examples/kzg_keygen_tools.rs @@ -10,7 +10,7 @@ use nova_snark::{ hyperkzg::{CommitmentEngine, CommitmentKey}, Bn256EngineKZG, }, - traits::commitment::{CommitmentEngineTrait, SaveTo}, + traits::commitment::{CommitmentEngineTrait, CommitmentKeyFileTrait}, }; use rand_core::OsRng; diff --git a/src/provider/hyperkzg.rs b/src/provider/hyperkzg.rs index 7f280be1..20538223 100644 --- a/src/provider/hyperkzg.rs +++ b/src/provider/hyperkzg.rs @@ -11,9 +11,12 @@ use crate::provider::{ptau::PtauFileError, read_ptau, write_ptau}; use crate::{ errors::NovaError, gadgets::utils::to_bignat_repr, - provider::traits::{DlogGroup, DlogGroupExt, PairingGroup}, + provider::{ + check_sanity_of_ptau_file, + traits::{DlogGroup, DlogGroupExt, PairingGroup}, + }, traits::{ - commitment::{CommitmentEngineTrait, CommitmentTrait, Len, SaveTo}, + commitment::{CommitmentEngineTrait, CommitmentKeyFileTrait, CommitmentTrait, Len}, evaluation::EvaluationEngineTrait, AbsorbInRO2Trait, AbsorbInROTrait, Engine, ROTrait, TranscriptEngineTrait, TranscriptReprTrait, }, @@ -132,7 +135,7 @@ where } } -impl SaveTo for CommitmentKey +impl CommitmentKeyFileTrait for CommitmentKey where E::GE: PairingGroup, { @@ -149,6 +152,14 @@ where write_ptau(&mut writer, g1_points, g2_points, power) } + + fn check_sanity_of_key_file( + path: impl AsRef, + num_g1: usize, + num_g2: usize, + ) -> Result<(), PtauFileError> { + check_sanity_of_ptau_file::<::AffineGroupElement>(&path, num_g1, num_g2) + } } impl Default for Commitment diff --git a/src/provider/pedersen.rs b/src/provider/pedersen.rs index fc33e381..3daeb3a9 100644 --- a/src/provider/pedersen.rs +++ b/src/provider/pedersen.rs @@ -6,7 +6,7 @@ use crate::{ gadgets::utils::to_bignat_repr, provider::traits::{DlogGroup, DlogGroupExt}, traits::{ - commitment::{CommitmentEngineTrait, CommitmentTrait, Len, SaveTo}, + commitment::{CommitmentEngineTrait, CommitmentKeyFileTrait, CommitmentTrait, Len}, AbsorbInRO2Trait, AbsorbInROTrait, Engine, ROTrait, TranscriptReprTrait, }, }; @@ -20,6 +20,7 @@ use num_integer::Integer; use num_traits::ToPrimitive; use rayon::prelude::*; use serde::{Deserialize, Serialize}; +use std::{fs::File, io::Read}; #[cfg(feature = "io")] const KEY_FILE_HEAD: [u8; 12] = *b"PEDERSEN_KEY"; @@ -188,7 +189,7 @@ pub struct CommitmentEngine { _p: PhantomData, } -impl SaveTo for CommitmentKey +impl CommitmentKeyFileTrait for CommitmentKey where E::GE: DlogGroup, { @@ -200,6 +201,21 @@ where points.extend(self.ck.iter().cloned()); write_points(writer, points) } + + fn check_sanity_of_key_file( + path: impl AsRef, + _num_g1: usize, + _num_g2: usize, + ) -> Result<(), PtauFileError> { + let mut reader = File::open(path)?; + let mut head = [0u8; 12]; + reader.read_exact(&mut head)?; + if head != KEY_FILE_HEAD { + Err(PtauFileError::InvalidHead) + } else { + Ok(()) + } + } } impl CommitmentEngineTrait for CommitmentEngine diff --git a/src/traits/commitment.rs b/src/traits/commitment.rs index ba0a9552..09ca2200 100644 --- a/src/traits/commitment.rs +++ b/src/traits/commitment.rs @@ -11,6 +11,7 @@ use num_integer::Integer; use num_traits::ToPrimitive; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use serde::{Deserialize, Serialize}; +use std::path::Path; /// A helper trait for types implementing scalar multiplication. pub trait ScalarMul: Mul + MulAssign {} @@ -47,13 +48,20 @@ pub trait Len { fn length(&self) -> usize; } -/// A trait for saving structures to a writer -pub trait SaveTo { - /// Saves the structure to the provided writer. +/// A trait for saving key to a writer and checking sanity of key file +pub trait CommitmentKeyFileTrait { + /// Saves the key to the provided writer. fn save_to( &self, writer: &mut (impl std::io::Write + std::io::Seek), ) -> Result<(), PtauFileError>; + + /// Checks the sanity of the key file at the provided path. + fn check_sanity_of_key_file( + path: impl AsRef, + num_g1: usize, + num_g2: usize, + ) -> Result<(), PtauFileError>; } /// A trait that ties different pieces of the commitment generation together @@ -61,7 +69,7 @@ pub trait CommitmentEngineTrait: Clone + Send + Sync { /// Holds the type of the commitment key /// The key should quantify its length in terms of group generators. type CommitmentKey: Len - + SaveTo + + CommitmentKeyFileTrait + Clone + Debug + Send From ac57f70a3e1a7230110df2d7ed1b220390d6ebff Mon Sep 17 00:00:00 2001 From: thelitfire Date: Wed, 7 Jan 2026 11:35:48 +0800 Subject: [PATCH 3/3] Move save to the same trait of load key file --- examples/kzg_keygen_tools.rs | 4 +-- src/provider/hyperkzg.rs | 68 +++++++++++++++--------------------- src/provider/pedersen.rs | 49 ++++++++------------------ src/traits/commitment.rs | 33 +++++------------ 4 files changed, 54 insertions(+), 100 deletions(-) diff --git a/examples/kzg_keygen_tools.rs b/examples/kzg_keygen_tools.rs index 17a3f484..9626d294 100644 --- a/examples/kzg_keygen_tools.rs +++ b/examples/kzg_keygen_tools.rs @@ -10,7 +10,7 @@ use nova_snark::{ hyperkzg::{CommitmentEngine, CommitmentKey}, Bn256EngineKZG, }, - traits::commitment::{CommitmentEngineTrait, CommitmentKeyFileTrait}, + traits::commitment::CommitmentEngineTrait, }; use rand_core::OsRng; @@ -61,7 +61,7 @@ fn keygen_save_large() { let mut writer = BufWriter::with_capacity(BUFFER_SIZE, &file); let (_, dur) = timeit!(|| { - ck.save_to(&mut writer).unwrap(); + CommitmentEngine::::save_setup(&ck, &mut writer).unwrap(); }); println!( diff --git a/src/provider/hyperkzg.rs b/src/provider/hyperkzg.rs index 20538223..5d03cfc7 100644 --- a/src/provider/hyperkzg.rs +++ b/src/provider/hyperkzg.rs @@ -11,12 +11,9 @@ use crate::provider::{ptau::PtauFileError, read_ptau, write_ptau}; use crate::{ errors::NovaError, gadgets::utils::to_bignat_repr, - provider::{ - check_sanity_of_ptau_file, - traits::{DlogGroup, DlogGroupExt, PairingGroup}, - }, + provider::traits::{DlogGroup, DlogGroupExt, PairingGroup}, traits::{ - commitment::{CommitmentEngineTrait, CommitmentKeyFileTrait, CommitmentTrait, Len}, + commitment::{CommitmentEngineTrait, CommitmentTrait, Len}, evaluation::EvaluationEngineTrait, AbsorbInRO2Trait, AbsorbInROTrait, Engine, ROTrait, TranscriptEngineTrait, TranscriptReprTrait, }, @@ -135,33 +132,6 @@ where } } -impl CommitmentKeyFileTrait for CommitmentKey -where - E::GE: PairingGroup, -{ - /// Save keys - #[cfg(feature = "io")] - fn save_to( - &self, - mut writer: &mut (impl std::io::Write + std::io::Seek), - ) -> Result<(), PtauFileError> { - let g1_points = self.ck.clone(); - - let g2_points = vec![self.tau_H, self.tau_H]; - let power = g1_points.len().next_power_of_two().trailing_zeros() + 1; - - write_ptau(&mut writer, g1_points, g2_points, power) - } - - fn check_sanity_of_key_file( - path: impl AsRef, - num_g1: usize, - num_g2: usize, - ) -> Result<(), PtauFileError> { - check_sanity_of_ptau_file::<::AffineGroupElement>(&path, num_g1, num_g2) - } -} - impl Default for Commitment where E::GE: PairingGroup, @@ -558,6 +528,7 @@ where ) -> Result { let num = n.next_power_of_two(); + // read points as well as check sanity of ptau file let (g1_points, g2_points) = read_ptau(reader, num, 2)?; let ck = g1_points.to_vec(); @@ -569,6 +540,20 @@ where Ok(CommitmentKey { ck, h, tau_H }) } + /// Save keys + #[cfg(feature = "io")] + fn save_setup( + ck: &Self::CommitmentKey, + mut writer: &mut (impl std::io::Write + std::io::Seek), + ) -> Result<(), PtauFileError> { + let g1_points = ck.ck.clone(); + + let g2_points = vec![ck.tau_H, ck.tau_H]; + let power = g1_points.len().next_power_of_two().trailing_zeros() + 1; + + write_ptau(&mut writer, g1_points, g2_points, power) + } + fn commit_small_range + Copy + Sync + ToPrimitive>( ck: &Self::CommitmentKey, v: &[T], @@ -1040,17 +1025,19 @@ where #[cfg(test)] mod tests { - use std::{ - fs::OpenOptions, - io::{BufReader, BufWriter}, - }; - use super::*; + #[cfg(feature = "io")] + use crate::provider::hyperkzg; use crate::{ - provider::{hyperkzg, keccak::Keccak256Transcript, Bn256EngineKZG}, + provider::{keccak::Keccak256Transcript, Bn256EngineKZG}, spartan::polys::multilinear::MultilinearPolynomial, }; use rand::SeedableRng; + #[cfg(feature = "io")] + use std::{ + fs::OpenOptions, + io::{BufReader, BufWriter}, + }; type E = Bn256EngineKZG; type Fr = ::Scalar; @@ -1204,6 +1191,7 @@ mod tests { } } + #[cfg(feature = "io")] #[ignore = "only available with external ptau files"] #[test] fn test_hyperkzg_large_from_file() { @@ -1263,6 +1251,7 @@ mod tests { } } + #[cfg(feature = "io")] #[test] fn test_save_load_ck() { const BUFFER_SIZE: usize = 64 * 1024; @@ -1281,7 +1270,7 @@ mod tests { .unwrap(); let mut writer = BufWriter::with_capacity(BUFFER_SIZE, file); - ck.save_to(&mut writer).unwrap(); + CommitmentEngine::save_setup(&ck, &mut writer).unwrap(); let file = OpenOptions::new().read(true).open(filename).unwrap(); @@ -1298,6 +1287,7 @@ mod tests { } } + #[cfg(feature = "io")] #[ignore = "only available with external ptau files"] #[test] fn test_load_ptau() { diff --git a/src/provider/pedersen.rs b/src/provider/pedersen.rs index 3daeb3a9..29a42540 100644 --- a/src/provider/pedersen.rs +++ b/src/provider/pedersen.rs @@ -6,7 +6,7 @@ use crate::{ gadgets::utils::to_bignat_repr, provider::traits::{DlogGroup, DlogGroupExt}, traits::{ - commitment::{CommitmentEngineTrait, CommitmentKeyFileTrait, CommitmentTrait, Len}, + commitment::{CommitmentEngineTrait, CommitmentTrait, Len}, AbsorbInRO2Trait, AbsorbInROTrait, Engine, ROTrait, TranscriptReprTrait, }, }; @@ -20,7 +20,6 @@ use num_integer::Integer; use num_traits::ToPrimitive; use rayon::prelude::*; use serde::{Deserialize, Serialize}; -use std::{fs::File, io::Read}; #[cfg(feature = "io")] const KEY_FILE_HEAD: [u8; 12] = *b"PEDERSEN_KEY"; @@ -189,35 +188,6 @@ pub struct CommitmentEngine { _p: PhantomData, } -impl CommitmentKeyFileTrait for CommitmentKey -where - E::GE: DlogGroup, -{ - #[cfg(feature = "io")] - fn save_to(&self, writer: &mut impl std::io::Write) -> Result<(), PtauFileError> { - writer.write_all(&KEY_FILE_HEAD)?; - let mut points = Vec::with_capacity(self.ck.len() + 1); - points.push(self.h); - points.extend(self.ck.iter().cloned()); - write_points(writer, points) - } - - fn check_sanity_of_key_file( - path: impl AsRef, - _num_g1: usize, - _num_g2: usize, - ) -> Result<(), PtauFileError> { - let mut reader = File::open(path)?; - let mut head = [0u8; 12]; - reader.read_exact(&mut head)?; - if head != KEY_FILE_HEAD { - Err(PtauFileError::InvalidHead) - } else { - Ok(()) - } - } -} - impl CommitmentEngineTrait for CommitmentEngine where E::GE: DlogGroupExt, @@ -319,6 +289,18 @@ where h: first[0], }) } + + #[cfg(feature = "io")] + fn save_setup( + ck: &Self::CommitmentKey, + writer: &mut impl std::io::Write, + ) -> Result<(), PtauFileError> { + writer.write_all(&KEY_FILE_HEAD)?; + let mut points = Vec::with_capacity(ck.ck.len() + 1); + points.push(ck.h); + points.extend(ck.ck.iter().cloned()); + write_points(writer, points) + } } /// A trait listing properties of a commitment key that can be managed in a divide-and-conquer fashion @@ -422,6 +404,7 @@ where } } +#[cfg(feature = "io")] #[cfg(test)] mod tests { use super::*; @@ -439,9 +422,7 @@ mod tests { let keys = CommitmentEngine::::setup(LABEL, 100); - keys - .save_to(&mut BufWriter::new(File::create(path).unwrap())) - .unwrap(); + CommitmentEngine::save_setup(&keys, &mut BufWriter::new(File::create(path).unwrap())).unwrap(); let keys_read = CommitmentEngine::load_setup(&mut File::open(path).unwrap(), LABEL, 100); diff --git a/src/traits/commitment.rs b/src/traits/commitment.rs index 09ca2200..ae7f5bc1 100644 --- a/src/traits/commitment.rs +++ b/src/traits/commitment.rs @@ -11,7 +11,6 @@ use num_integer::Integer; use num_traits::ToPrimitive; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use serde::{Deserialize, Serialize}; -use std::path::Path; /// A helper trait for types implementing scalar multiplication. pub trait ScalarMul: Mul + MulAssign {} @@ -48,34 +47,11 @@ pub trait Len { fn length(&self) -> usize; } -/// A trait for saving key to a writer and checking sanity of key file -pub trait CommitmentKeyFileTrait { - /// Saves the key to the provided writer. - fn save_to( - &self, - writer: &mut (impl std::io::Write + std::io::Seek), - ) -> Result<(), PtauFileError>; - - /// Checks the sanity of the key file at the provided path. - fn check_sanity_of_key_file( - path: impl AsRef, - num_g1: usize, - num_g2: usize, - ) -> Result<(), PtauFileError>; -} - /// A trait that ties different pieces of the commitment generation together pub trait CommitmentEngineTrait: Clone + Send + Sync { /// Holds the type of the commitment key /// The key should quantify its length in terms of group generators. - type CommitmentKey: Len - + CommitmentKeyFileTrait - + Clone - + Debug - + Send - + Sync - + Serialize - + for<'de> Deserialize<'de>; + type CommitmentKey: Len + Clone + Debug + Send + Sync + Serialize + for<'de> Deserialize<'de>; /// Holds the type of the derandomization key type DerandKey: Clone + Debug + Send + Sync + Serialize + for<'de> Deserialize<'de>; @@ -91,6 +67,13 @@ pub trait CommitmentEngineTrait: Clone + Send + Sync { n: usize, ) -> Result; + /// Saves the key to the provided writer. + #[cfg(feature = "io")] + fn save_setup( + ck: &Self::CommitmentKey, + writer: &mut (impl std::io::Write + std::io::Seek), + ) -> Result<(), PtauFileError>; + /// Samples a new commitment key of a specified size fn setup(label: &'static [u8], n: usize) -> Self::CommitmentKey;