diff --git a/Cargo.toml b/Cargo.toml index 805d87f..89c44ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,8 @@ sha2 = { version = "0.10", default-features = false } rand_chacha = { version = "0.3", default-features = false } rayon = { version = "1.10", default-features = false, optional = true } hmac = {version = "0.12", default-features = false, optional = true } -w3f-ring-proof = { version = "0.0.2", default-features = false, optional = true } +w3f-ring-proof = { git = "https://github.com/davxy/ring-proof", branch = "ring-proof-batching-fflonk-fix", default-features = false, optional = true } +# w3f-ring-proof = { version = "0.0.2", default-features = false, optional = true } # Curves ark-secp256r1 = { version = "0.5", default-features = false, optional = true } ark-ed25519 = { version = "0.5", default-features = false, optional = true } diff --git a/src/ring.rs b/src/ring.rs index 15bbe23..92505af 100644 --- a/src/ring.rs +++ b/src/ring.rs @@ -84,7 +84,7 @@ pub trait RingSuite: } /// KZG Polinomial Commitment Scheme. -pub type Pcs = ring_proof::pcs::kzg::KZG<::Pairing>; +pub type Kzg = ring_proof::pcs::kzg::KZG<::Pairing>; /// KZG commitment. pub type PcsCommitment = @@ -105,23 +105,29 @@ pub type PiopParams = ring_proof::PiopParams, CurveConfig>; pub type RingCommitment = ring_proof::FixedColumnsCommitted, PcsCommitment>; /// Ring prover key. -pub type RingProverKey = ring_proof::ProverKey, Pcs, TEAffine>>; +pub type RingProverKey = ring_proof::ProverKey, Kzg, TEAffine>>; /// Ring verifier key. -pub type RingVerifierKey = ring_proof::VerifierKey, Pcs>; +pub type RingVerifierKey = ring_proof::VerifierKey, Kzg>; /// Ring prover. -pub type RingProver = ring_proof::ring_prover::RingProver, Pcs, CurveConfig>; +pub type RingProver = ring_proof::ring_prover::RingProver, Kzg, CurveConfig>; /// Ring verifier. pub type RingVerifier = - ring_proof::ring_verifier::RingVerifier, Pcs, CurveConfig>; + ring_proof::ring_verifier::RingVerifier, Kzg, CurveConfig>; + +pub type RingBatchVerifier = ring_proof::ring_verifier::KzgBatchVerifier< + ::Pairing, + CurveConfig, + ring_proof::ArkTranscript, +>; /// Raw ring proof. /// /// This is the primitive ring proof used in conjunction with Pedersen proof to /// construct the actual ring vrf proof [`Proof`]. -pub type RingBareProof = ring_proof::RingProof, Pcs>; +pub type RingBareProof = ring_proof::RingProof, Kzg>; /// Ring VRF proof. /// @@ -186,6 +192,40 @@ pub trait Verifier { ) -> Result<(), Error>; } +pub struct BatchVerifier { + batch: RingBatchVerifier, +} + +impl BatchVerifier { + pub fn new(ring_verifier: RingVerifier) -> Self { + Self { + batch: ring_verifier.kzg_batch_verifier(), + } + } + + pub fn push( + &mut self, + input: Input, + output: Output, + ad: impl AsRef<[u8]>, + proof: &Proof, + ) -> Result<(), Error> { + use pedersen::Verifier as PedersenVerifier; + as PedersenVerifier>::verify(input, output, ad, &proof.pedersen_proof)?; + let key_commitment = proof.pedersen_proof.key_commitment().into_te(); + self.batch.push(proof.ring_proof.clone(), key_commitment); + Ok(()) + } + + pub fn verify(&self) -> Result<(), Error> { + if self.batch.verify() { + Ok(()) + } else { + Err(Error::VerificationFailure) + } + } +} + impl Prover for Secret { fn prove( &self, @@ -210,13 +250,13 @@ impl Verifier for Public { input: Input, output: Output, ad: impl AsRef<[u8]>, - sig: &Proof, + proof: &Proof, verifier: &RingVerifier, ) -> Result<(), Error> { use pedersen::Verifier as PedersenVerifier; - >::verify(input, output, ad, &sig.pedersen_proof)?; - let key_commitment = sig.pedersen_proof.key_commitment().into_te(); - if !verifier.verify(sig.ring_proof.clone(), key_commitment) { + >::verify(input, output, ad, &proof.pedersen_proof)?; + let key_commitment = proof.pedersen_proof.key_commitment().into_te(); + if !verifier.verify(proof.ring_proof.clone(), key_commitment) { return Err(Error::VerificationFailure); } Ok(()) @@ -261,7 +301,7 @@ impl RingProofParams { pub fn from_rand(ring_size: usize, rng: &mut impl ark_std::rand::RngCore) -> Self { use ring_proof::pcs::PCS; let max_degree = pcs_domain_size::(ring_size) - 1; - let pcs_params = Pcs::::setup(max_degree, rng); + let pcs_params = Kzg::::setup(max_degree, rng); Self::from_pcs_params(ring_size, pcs_params).expect("PCS params is correct") } @@ -671,6 +711,8 @@ pub(crate) mod testing { pub const TEST_RING_SIZE: usize = 8; + const MAX_AD_LEN: usize = 100; + fn find_complement_point() -> SWAffine { use ark_ff::{One, Zero}; assert!(!C::cofactor_is_one()); @@ -720,6 +762,33 @@ pub(crate) mod testing { } } + struct BatchItem { + input: Input, + output: Output, + ad: Vec, + proof: Proof, + } + + impl BatchItem { + fn new( + secret: &Secret, + prover: &RingProver, + rng: &mut dyn ark_std::rand::RngCore, + ) -> Self { + let input = Input::from(common::random_val(Some(rng))); + let output = secret.output(input); + let ad_len = common::random_val::(Some(rng)) % (MAX_AD_LEN + 1); + let ad = common::random_vec(ad_len, Some(rng)); + let proof = secret.prove(input, output, &ad, prover); + Self { + input, + output, + ad, + proof, + } + } + } + #[allow(unused)] pub fn prove_verify() { let rng = &mut ark_std::test_rng(); @@ -727,35 +796,69 @@ pub(crate) mod testing { let secret = Secret::::from_seed(TEST_SEED); let public = secret.public(); - let input = Input::from(common::random_val(Some(rng))); - let output = secret.output(input); - - let ring_size = params.max_ring_size(); - let piop_dom_size = piop_domain_size::(ring_size); - let pcs_dom_size = pcs_domain_size::(ring_size); - - // Verify domain size relationships - assert_eq!(pcs_dom_size, params.pcs.powers_in_g1.len()); - assert_eq!(pcs_dom_size, 3 * piop_dom_size + 1); - assert_eq!( - max_ring_size_from_pcs_domain_size::(pcs_dom_size), - ring_size - ); + let mut pks = common::random_vec::>(TEST_RING_SIZE, Some(rng)); let prover_idx = 3; - let mut pks = common::random_vec::>(ring_size, Some(rng)); pks[prover_idx] = public.0; let prover_key = params.prover_key(&pks); let prover = params.prover(prover_key, prover_idx); - let proof = secret.prove(input, output, b"foo", &prover); + + let item = BatchItem::::new(&secret, &prover, rng); let verifier_key = params.verifier_key(&pks); let verifier = params.verifier(verifier_key); - let result = Public::verify(input, output, b"foo", &proof, &verifier); + let result = Public::verify(item.input, item.output, &item.ad, &item.proof, &verifier); assert!(result.is_ok()); } + #[allow(unused)] + pub fn prove_verify_batch() { + const BATCH_SIZE: usize = 2 * TEST_RING_SIZE; + + let rng = &mut ark_std::test_rng(); + let params = RingProofParams::::from_rand(TEST_RING_SIZE, rng); + + // Prepare secrets and place their public keys in the ring + let secrets: Vec<_> = (0..TEST_RING_SIZE) + .map(|i| Secret::::from_seed(&[i as u8; 32])) + .collect(); + let pks = secrets.iter().map(|s| s.public().0).collect::>(); + + // Build verifier from the complete ring + let verifier_key = params.verifier_key(&pks); + let verifier = params.verifier(verifier_key); + // Pre-built provers (lazily populated) + let mut provers: Vec>> = std::iter::repeat_with(|| None) + .take(TEST_RING_SIZE) + .collect(); + + // Generate proofs for each secret + let mut batch = Vec::with_capacity(BATCH_SIZE); + for _ in 0..BATCH_SIZE { + let prover_idx = common::random_val::(Some(rng)) % TEST_RING_SIZE; + let prover = provers[prover_idx].get_or_insert_with(|| { + let prover_key = params.prover_key(&pks); + params.prover(prover_key, prover_idx) + }); + let item = BatchItem::::new(&secrets[prover_idx], prover, rng); + batch.push(item); + } + + // Batch verify all proofs + let mut batch_verifier = BatchVerifier::::new(verifier); + // Empty batch + let res = batch_verifier.verify(); + assert!(res.is_ok()); + // Prove incrementally constructed batches + for (i, item) in batch.iter().enumerate() { + let res = batch_verifier.push(item.input, item.output, &item.ad, &item.proof); + assert!(res.is_ok()); + let res = batch_verifier.verify(); + assert!(res.is_ok()); + } + } + #[allow(unused)] pub fn padding_check() where @@ -905,6 +1008,11 @@ pub(crate) mod testing { $crate::ring::testing::prove_verify::<$suite>() } + #[test] + fn prove_verify_batch() { + $crate::ring::testing::prove_verify_batch::<$suite>() + } + #[test] fn padding_check() { $crate::ring::testing::padding_check::<$suite>()