diff --git a/bbs_plus/Cargo.toml b/bbs_plus/Cargo.toml index 580a9f35..0696384b 100644 --- a/bbs_plus/Cargo.toml +++ b/bbs_plus/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bbs_plus" -version = "0.17.0" +version = "0.18.0" edition.workspace = true authors.workspace = true license.workspace = true @@ -19,10 +19,10 @@ ark-std.workspace = true digest.workspace = true rayon = {workspace = true, optional = true} itertools.workspace = true -schnorr_pok = { version = "0.15.0", default-features = false, path = "../schnorr_pok" } +schnorr_pok = { version = "0.16.0", default-features = false, path = "../schnorr_pok" } dock_crypto_utils = { version = "0.16.0", default-features = false, path = "../utils" } -oblivious_transfer_protocols = { version = "0.4.0", default-features = false, path = "../oblivious_transfer" } -secret_sharing_and_dkg = { version = "0.8.0", default-features = false, path = "../secret_sharing_and_dkg" } +oblivious_transfer_protocols = { version = "0.5.0", default-features = false, path = "../oblivious_transfer" } +secret_sharing_and_dkg = { version = "0.9.0", default-features = false, path = "../secret_sharing_and_dkg" } sha3 = { version = "0.10.6", default-features = false } serde.workspace = true serde_with.workspace = true diff --git a/benches/Cargo.toml b/benches/Cargo.toml index e2f45fa8..d4b267a5 100644 --- a/benches/Cargo.toml +++ b/benches/Cargo.toml @@ -6,9 +6,9 @@ authors.workspace = true license.workspace = true [dependencies] -bbs_plus = { version = "0.17.0", default-features = false, path = "../bbs_plus" } -schnorr_pok = { version = "0.15.0", default-features = false, path = "../schnorr_pok" } -vb_accumulator = { version = "0.18.0", default-features = false, path = "../vb_accumulator" } +bbs_plus = { default-features = false, path = "../bbs_plus" } +schnorr_pok = { default-features = false, path = "../schnorr_pok" } +vb_accumulator = { default-features = false, path = "../vb_accumulator" } test_utils = { default-features = false, path = "../test_utils" } ark-ff.workspace = true ark-ec.workspace = true @@ -18,8 +18,8 @@ serde.workspace = true serde_with.workspace = true blake2 = { version = "0.10", default-features = false } itertools.workspace = true -coconut-crypto = { version = "0.6.0", default-features = false, path = "../coconut" } -oblivious_transfer_protocols = { version = "0.4.0", default-features = false, path = "../oblivious_transfer" } +coconut-crypto = { default-features = false, path = "../coconut" } +oblivious_transfer_protocols = { default-features = false, path = "../oblivious_transfer" } dock_crypto_utils = { default-features = false, path = "../utils" } zeroize.workspace = true diff --git a/benches/benches/dkls19_batch_mul_2p.rs b/benches/benches/dkls19_batch_mul_2p.rs index 5edd396d..14447c63 100644 --- a/benches/benches/dkls19_batch_mul_2p.rs +++ b/benches/benches/dkls19_batch_mul_2p.rs @@ -82,7 +82,7 @@ fn batch_multiplication(c: &mut Criterion) { ) .unwrap(); - let (party2, _, kos_rlc, gamma_b) = Party2::new( + let (party2, U, kos_rlc, gamma_b) = Party2::new( &mut rng, beta.clone(), base_ot_sender_keys.clone(), diff --git a/bulletproofs_plus_plus/Cargo.toml b/bulletproofs_plus_plus/Cargo.toml index affd77c0..7dc905f3 100644 --- a/bulletproofs_plus_plus/Cargo.toml +++ b/bulletproofs_plus_plus/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bulletproofs_plus_plus" -version = "0.1.0" +version = "0.2.0" edition.workspace = true authors.workspace = true license.workspace = true diff --git a/bulletproofs_plus_plus/src/rangeproof.rs b/bulletproofs_plus_plus/src/rangeproof.rs index d6b55524..eaa3049f 100644 --- a/bulletproofs_plus_plus/src/rangeproof.rs +++ b/bulletproofs_plus_plus/src/rangeproof.rs @@ -6,7 +6,7 @@ //! //! Notation follows the bulletproofs++ paper. -use ark_ec::{AffineRepr, CurveGroup, VariableBaseMSM}; +use ark_ec::AffineRepr; use ark_ff::{batch_inversion, Field, PrimeField, Zero}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::{ @@ -750,13 +750,13 @@ impl Proof { &self, alpha_r: &[G::ScalarField], alpha_r2: &[G::ScalarField], - t3: &G::ScalarField, + t_cube: &G::ScalarField, q_pows: &[G::ScalarField], alpha_d_q_inv_pows: &[G::ScalarField], alpha_d: &[G::ScalarField], total_num_digits: usize, ) -> G::ScalarField { - let two_t_3 = t3.double(); + let two_t_3 = t_cube.double(); let two_t_3_v = vec![two_t_3; total_num_digits]; let v_hat_1 = inner_product(&two_t_3_v, q_pows); @@ -790,7 +790,7 @@ impl Proof { let t_pows = TPowers::new(t, setup_params.H_vec.len() as u32); let c_vec = create_c_vec(y, &t_pows); - let (t_inv, t2, t3) = ( + let (t_inv, t_sqr, t_cube) = ( t_pows.nth_power(-1), t_pows.nth_power(2), t_pows.nth_power(3), @@ -815,13 +815,13 @@ impl Proof { let g_offset = self.g_offset( &alpha_r, &alpha_r2, - t3, + t_cube, &q_pows, &alpha_d_q_inv_pow, &alpha_d, total_num_digits, ); - let g_vec_pub_offsets = self.g_vec_pub_offsets( + let mut g_vec_pub_offsets = self.g_vec_pub_offsets( e, x, &alpha_r_q_inv_pows, @@ -830,26 +830,45 @@ impl Proof { &alpha_d_q_inv_pow, ); - // let (r1_comm, r2_comm, r3_comm, norm_proof) = - // (self.r1_comm, self.r2_comm, self.r3_comm, self.norm_proof); - let (S, M, D, R) = ( - self.r3_comm.S, - self.r1_comm.M, - self.r1_comm.D, - self.r2_comm.R, - ); + let two_t_cube = t_cube.double(); + + // C = * t^3 * 2 + S * t_inv + M * delta + D * t + R * t^2 + + G * g_offset + + // RHS of above can be created using an MSM + let msm_size = 5 + V.len() + g_vec_pub_offsets.len(); + let mut bases = Vec::with_capacity(msm_size); + let mut scalars = Vec::with_capacity(msm_size); + + // For * t^3 * 2 + bases.extend_from_slice(V); + scalars.append(&mut scale(&lambda_powers, &two_t_cube)); + + // For S * t_inv + M * delta + D * t + R * t^2 + bases.push(self.r3_comm.S); + bases.push(self.r1_comm.M); + bases.push(self.r1_comm.D); + bases.push(self.r2_comm.R); + scalars.push(*t_inv); + scalars.push(delta); + scalars.push(t); + scalars.push(*t_sqr); - let two_t3 = t3.double(); + // For + bases.extend_from_slice(&setup_params.G_vec[0..g_vec_pub_offsets.len()]); + scalars.append(&mut g_vec_pub_offsets); - // \sum_i(V_i * lambda_powers_i * t3 * 2) - let V = G::Group::msm_unchecked(V, &scale(&lambda_powers, &two_t3)); - // TODO: C can be created using an MSM - let C = S * t_inv + M * delta + D * t + R * t2 + V; - let P = G::Group::msm_unchecked(&setup_params.G_vec, &g_vec_pub_offsets); - let C = C + P + (setup_params.G * g_offset); + // For G * g_offset + bases.push(setup_params.G); + scalars.push(g_offset); - self.norm_proof - .verify(c_vec, r, &C.into_affine(), setup_params, transcript) + self.norm_proof.verify_given_commitment_multiplicands( + c_vec, + r, + bases, + scalars, + setup_params, + transcript, + ) } } diff --git a/bulletproofs_plus_plus/src/weighted_norm_linear_argument.rs b/bulletproofs_plus_plus/src/weighted_norm_linear_argument.rs index f2943816..cd4c4563 100644 --- a/bulletproofs_plus_plus/src/weighted_norm_linear_argument.rs +++ b/bulletproofs_plus_plus/src/weighted_norm_linear_argument.rs @@ -1,15 +1,16 @@ -//! Weighted Norm Linear argument for +//! Weighted Norm Linear argument for relation `v = + {|n|_mu}^2` given commitment `C = v*G + + ` use crate::error::BulletproofsPlusPlusError; use ark_ec::{AffineRepr, CurveGroup, VariableBaseMSM}; -use ark_ff::{Field, One}; +use ark_ff::{Field, One, Zero}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use ark_std::{cfg_into_iter, cfg_iter, format, vec, vec::Vec}; +use ark_std::{cfg_into_iter, cfg_iter, cfg_iter_mut, format, ops::Neg, vec, vec::Vec}; use dock_crypto_utils::{ ff::{inner_product, weighted_inner_product, weighted_norm}, transcript::Transcript, }; +use dock_crypto_utils::ff::scale; #[cfg(feature = "parallel")] use rayon::prelude::*; @@ -24,6 +25,7 @@ pub struct WeightedNormLinearArgument { } impl WeightedNormLinearArgument { + /// Create new argument pub fn new( mut l: Vec, mut n: Vec, @@ -95,17 +97,52 @@ impl WeightedNormLinearArgument { let scaled_n_0 = cfg_iter!(n_0).map(|n| *n * rho_inv).collect::>(); let scaled_n_1 = cfg_iter!(n_1).map(|n| *n * rho).collect::>(); - // TODO: Create one big MSM - let X_i = g.mul(v_x) - + G::Group::msm_unchecked(&h_0, &l_1) - + G::Group::msm_unchecked(&h_1, &l_0) - + G::Group::msm_unchecked(&g_0, &scaled_n_1) - + G::Group::msm_unchecked(&g_1, &scaled_n_0); - - // TODO: Create one big MSM - let R_i = g.mul(v_r) - + G::Group::msm_unchecked(&h_1, &l_1) - + G::Group::msm_unchecked(&g_1, &n_1); + + // X_i = g * v_x + + + + + + // Create X_i using MSM + let msm_size = 1 + l_1.len() + l_0.len() + n_1.len() + n_0.len(); + let mut bases = Vec::with_capacity(msm_size); + let mut scalars = Vec::with_capacity(msm_size); + bases.push(g); + scalars.push(v_x); + // For + let min = core::cmp::min(h_0.len(), l_1.len()); + bases.extend_from_slice(&h_0[0..min]); + scalars.extend_from_slice(&l_1[0..min]); + // For + let min = core::cmp::min(h_1.len(), l_0.len()); + bases.extend_from_slice(&h_1[0..min]); + scalars.extend_from_slice(&l_0[0..min]); + // For + let min = core::cmp::min(g_0.len(), scaled_n_1.len()); + bases.extend_from_slice(&g_0[0..min]); + scalars.extend_from_slice(&scaled_n_1[0..min]); + // + let min = core::cmp::min(g_1.len(), scaled_n_0.len()); + bases.extend_from_slice(&g_1[0..min]); + scalars.extend_from_slice(&scaled_n_0[0..min]); + + let X_i = G::Group::msm_unchecked(&bases, &scalars); + + // R_i = g * v_r + + + + // Create R_i using MSM + let msm_size = 1 + l_1.len() + n_1.len(); + let mut bases = Vec::with_capacity(msm_size); + let mut scalars = Vec::with_capacity(msm_size); + bases.push(g); + scalars.push(v_r); + // For + let min = core::cmp::min(h_1.len(), l_1.len()); + bases.extend_from_slice(&h_1[0..min]); + scalars.extend_from_slice(&l_1[0..min]); + // For + let min = core::cmp::min(g_1.len(), n_1.len()); + bases.extend_from_slice(&g_1[0..min]); + scalars.extend_from_slice(&n_1[0..min]); + + let R_i = G::Group::msm_unchecked(&bases, &scalars); transcript.append(b"X", &X_i); transcript.append(b"R", &R_i); @@ -153,6 +190,7 @@ impl WeightedNormLinearArgument { }) } + /// Verify the argument. pub fn verify( &self, c: Vec, @@ -161,59 +199,49 @@ impl WeightedNormLinearArgument { setup_params: &SetupParams, transcript: &mut impl Transcript, ) -> Result<(), BulletproofsPlusPlusError> { - let SetupParams { - G: g, - G_vec: g_vec, - H_vec: h_vec, - } = setup_params; - if c.len() != h_vec.len() { - return Err(BulletproofsPlusPlusError::UnexpectedLengthOfVectors( - format!( - "length of c={} not equal to length of H_vec={}", - c.len(), - h_vec.len() - ), - )); - } - if self.X.len() != self.R.len() { - return Err(BulletproofsPlusPlusError::UnexpectedLengthOfVectors( - format!( - "length of X={} not equal to length of R={}", - self.X.len(), - self.X.len() - ), - )); - } - let mut mu = rho.square(); - let mut gamma = Vec::with_capacity(self.X.len()); - let mut gamma_sq_minus_1 = Vec::with_capacity(self.X.len()); - for i in 0..self.X.len() { - transcript.append(b"X", &self.X[i]); - transcript.append(b"R", &self.R[i]); - gamma.push(transcript.challenge_scalar::(b"gamma")); - gamma_sq_minus_1.push(gamma[i].square() - G::ScalarField::one()); - } - for _ in 0..g_vec.len().ilog2() { - mu.square_in_place(); + // Check if given commitment C == g * v + * l + * n - - + let (bases, scalars) = + self.get_bases_and_scalars_for_reduced_commitment(c, rho, setup_params, transcript)?; + + if commitment.into_group() != G::Group::msm_unchecked(&bases, &scalars) { + return Err(BulletproofsPlusPlusError::WeightedNormLinearArgumentVerificationFailed); } - let g_multiples = Self::get_g_multiples(g_vec.len(), &rho, &gamma); - let h_multiples = Self::get_h_multiples(h_vec.len(), &gamma); + Ok(()) + } - let v = self.l[0] * inner_product(&c, &h_multiples) + weighted_norm(&self.n, &mu); - // TODO: Replace following 2 lines with a single MSM - let C_prime = *g * v - + (G::Group::msm_unchecked(h_vec, &h_multiples) * self.l[0]) - + (G::Group::msm_unchecked(g_vec, &g_multiples) * self.n[0]); - if (commitment.into_group() - + G::Group::msm_unchecked(&self.X, &gamma) - + G::Group::msm_unchecked(&self.R, &gamma_sq_minus_1)) - != C_prime - { + /// Same as `Self::verify` except that it does not take the commitment directly but takes the `bases` and `scalars` + /// whose inner product (MSM) gives the commitment. This is used when the calling protocol (range-proof in this case) + /// has to create the commitment. The calling protocol rather than creating the commitment by MSM, passed the vectors here + /// thus resulting in only 1 large MSM rather than 2 as verification also does an MSM + pub fn verify_given_commitment_multiplicands( + &self, + c: Vec, + rho: G::ScalarField, + mut commitment_bases: Vec, + mut commitment_scalars: Vec, + setup_params: &SetupParams, + transcript: &mut impl Transcript, + ) -> Result<(), BulletproofsPlusPlusError> { + let (mut bases, mut scalars) = + self.get_bases_and_scalars_for_reduced_commitment(c, rho, setup_params, transcript)?; + + // Check if given commitment C == g * v + * l + * n - - + // But C = + // so check g * v + * l + * n - - - == 0 + + bases.append(&mut commitment_bases); + cfg_iter_mut!(commitment_scalars).for_each(|elem| *elem = elem.neg()); + scalars.append(&mut commitment_scalars); + + if !G::Group::msm_unchecked(&bases, &scalars).is_zero() { return Err(BulletproofsPlusPlusError::WeightedNormLinearArgumentVerificationFailed); } + Ok(()) } + /// Verify the argument recursively. This is inefficient compared to `Self::verify` and only used for debugging + #[cfg(test)] pub fn verify_recursively( &self, mut c: Vec, @@ -350,6 +378,81 @@ impl WeightedNormLinearArgument { } multiples } + + fn get_bases_and_scalars_for_reduced_commitment( + &self, + c: Vec, + rho: G::ScalarField, + setup_params: &SetupParams, + transcript: &mut impl Transcript, + ) -> Result<(Vec, Vec), BulletproofsPlusPlusError> { + let SetupParams { + G: g, + G_vec: g_vec, + H_vec: h_vec, + } = setup_params; + if c.len() != h_vec.len() { + return Err(BulletproofsPlusPlusError::UnexpectedLengthOfVectors( + format!( + "length of c={} not equal to length of H_vec={}", + c.len(), + h_vec.len() + ), + )); + } + if self.X.len() != self.R.len() { + return Err(BulletproofsPlusPlusError::UnexpectedLengthOfVectors( + format!( + "length of X={} not equal to length of R={}", + self.X.len(), + self.R.len() + ), + )); + } + let mut mu = rho.square(); + let mut gamma = Vec::with_capacity(self.X.len()); + let mut gamma_sq_minus_1 = Vec::with_capacity(self.X.len()); + for i in 0..self.X.len() { + transcript.append(b"X", &self.X[i]); + transcript.append(b"R", &self.R[i]); + gamma.push(transcript.challenge_scalar::(b"gamma")); + gamma_sq_minus_1.push(gamma[i].square() - G::ScalarField::one()); + } + for _ in 0..g_vec.len().ilog2() { + mu.square_in_place(); + } + let g_multiples = Self::get_g_multiples(g_vec.len(), &rho, &gamma); + let h_multiples = Self::get_h_multiples(h_vec.len(), &gamma); + + let v = self.l[0] * inner_product(&c, &h_multiples) + weighted_norm(&self.n, &mu); + + // C' = g * v + * l + * n + // Check if C + + == C' + // => C == C' - - + // => C == g * v + * l + * n - - + + // RHS of above can be created using an MSM + let msm_size = + 1 + h_multiples.len() + g_multiples.len() + gamma.len() + gamma_sq_minus_1.len(); + let mut bases = Vec::with_capacity(msm_size); + let mut scalars = Vec::with_capacity(msm_size); + // For g*v + bases.push(*g); + scalars.push(v); + // For * l + bases.extend_from_slice(&h_vec[0..h_multiples.len()]); + scalars.append(&mut scale(&h_multiples, &self.l[0])); + // For * n + bases.extend_from_slice(&g_vec[0..g_multiples.len()]); + scalars.append(&mut scale(&g_multiples, &self.n[0])); + // For - + bases.extend_from_slice(&self.X); + scalars.append(&mut scale(&gamma, &G::ScalarField::one().neg())); + // For - + bases.extend_from_slice(&self.R); + scalars.append(&mut scale(&gamma_sq_minus_1, &G::ScalarField::one().neg())); + Ok((bases, scalars)) + } } #[cfg(test)] diff --git a/coconut/Cargo.toml b/coconut/Cargo.toml index aa4864c3..19227ee1 100644 --- a/coconut/Cargo.toml +++ b/coconut/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "coconut-crypto" -version = "0.6.0" +version = "0.7.0" edition.workspace = true authors.workspace = true license.workspace = true @@ -23,8 +23,8 @@ zeroize.workspace = true serde_with.workspace = true rayon = { workspace = true, optional = true } utils = { package = "dock_crypto_utils", version = "0.16.0", default-features = false, path = "../utils" } -schnorr_pok = { version = "0.15.0", default-features = false, path = "../schnorr_pok" } -secret_sharing_and_dkg = { version = "0.8.0", default-features = false, path = "../secret_sharing_and_dkg" } +schnorr_pok = { version = "0.16.0", default-features = false, path = "../schnorr_pok" } +secret_sharing_and_dkg = { version = "0.9.0", default-features = false, path = "../secret_sharing_and_dkg" } [dev-dependencies] blake2.workspace = true diff --git a/delegatable_credentials/Cargo.toml b/delegatable_credentials/Cargo.toml index 524135f6..5a9777df 100644 --- a/delegatable_credentials/Cargo.toml +++ b/delegatable_credentials/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "delegatable_credentials" -version = "0.6.0" +version = "0.7.0" edition.workspace = true authors.workspace = true license.workspace = true @@ -20,7 +20,7 @@ serde_with.workspace = true dock_crypto_utils = { version = "0.16.0", default-features = false, path = "../utils" } zeroize.workspace = true num-bigint = { version = "0.4.0", default-features = false } -schnorr_pok = { version = "0.15.0", default-features = false, path = "../schnorr_pok" } +schnorr_pok = { version = "0.16.0", default-features = false, path = "../schnorr_pok" } [dependencies.num-integer] version = "0.1.42" features = ["i128"] diff --git a/kvac/Cargo.toml b/kvac/Cargo.toml index 089a1899..f2bdd26d 100644 --- a/kvac/Cargo.toml +++ b/kvac/Cargo.toml @@ -15,7 +15,7 @@ ark-serialize.workspace = true digest.workspace = true zeroize.workspace = true dock_crypto_utils = { version = "0.16.0", default-features = false, path = "../utils" } -schnorr_pok = { version = "0.15.0", default-features = false, path = "../schnorr_pok" } +schnorr_pok = { version = "0.16.0", default-features = false, path = "../schnorr_pok" } rayon = {workspace = true, optional = true} [dev-dependencies] diff --git a/merlin/src/transcript.rs b/merlin/src/transcript.rs index b9f0dd89..48a3828b 100644 --- a/merlin/src/transcript.rs +++ b/merlin/src/transcript.rs @@ -17,7 +17,7 @@ fn encode_u64(x: u64) -> [u8; 8] { fn encode_usize_as_u32(x: usize) -> [u8; 4] { use byteorder::{ByteOrder, LittleEndian}; - assert!(x <= (u32::max_value() as usize)); + assert!(x <= (u32::MAX as usize)); let mut buf = [0; 4]; LittleEndian::write_u32(&mut buf, x as u32); diff --git a/oblivious_transfer/Cargo.toml b/oblivious_transfer/Cargo.toml index 5fbbeff9..c4881f03 100644 --- a/oblivious_transfer/Cargo.toml +++ b/oblivious_transfer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "oblivious_transfer_protocols" -version = "0.4.0" +version = "0.5.0" edition.workspace = true authors.workspace = true license.workspace = true @@ -17,7 +17,7 @@ serde.workspace = true serde_with.workspace = true zeroize.workspace = true dock_crypto_utils = { version = "0.16.0", default-features = false, path = "../utils" } -schnorr_pok = { version = "0.15.0", default-features = false, path = "../schnorr_pok" } +schnorr_pok = { version = "0.16.0", default-features = false, path = "../schnorr_pok" } cipher = { version = "0.4.4", default-features = false, features = ["alloc"] } rayon = {workspace = true, optional = true} sha3 = { version = "0.10.6", default-features = false } diff --git a/proof_system/Cargo.toml b/proof_system/Cargo.toml index 469c48a2..8a4fb19e 100644 --- a/proof_system/Cargo.toml +++ b/proof_system/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "proof_system" -version = "0.23.0" +version = "0.24.0" edition.workspace = true authors.workspace = true license.workspace = true @@ -18,9 +18,9 @@ ark-ec.workspace = true ark-std.workspace = true digest.workspace = true rayon = {workspace = true, optional = true} -bbs_plus = { version = "0.17.0", default-features = false, path = "../bbs_plus" } -schnorr_pok = { version = "0.15.0", default-features = false, path = "../schnorr_pok" } -vb_accumulator = { version = "0.18.0", default-features = false, path = "../vb_accumulator" } +bbs_plus = { version = "0.18.0", default-features = false, path = "../bbs_plus" } +schnorr_pok = { version = "0.16.0", default-features = false, path = "../schnorr_pok" } +vb_accumulator = { version = "0.19.0", default-features = false, path = "../vb_accumulator" } dock_crypto_utils = { version = "0.16.0", default-features = false, path = "../utils" } saver = { version = "0.14.0", default-features = false, path = "../saver" } serde.workspace = true @@ -29,11 +29,11 @@ ark-groth16.workspace = true ark-r1cs-std.workspace = true ark-relations.workspace = true zeroize.workspace = true -coconut-crypto = { version = "0.6.0", default-features = false, path = "../coconut" } +coconut-crypto = { version = "0.7.0", default-features = false, path = "../coconut" } merlin = { package = "dock_merlin", version = "2.0", default-features = false, path = "../merlin" } legogroth16 = { version = "0.11.0", default-features = false, features = ["circom", "aggregation"], path = "../legogroth16" } -bulletproofs_plus_plus = { version = "0.1.0", default-features = false, path = "../bulletproofs_plus_plus" } -smc_range_proof = { version = "0.1.0", default-features = false, path = "../smc_range_proof" } +bulletproofs_plus_plus = { version = "0.2.0", default-features = false, path = "../bulletproofs_plus_plus" } +smc_range_proof = { version = "0.2.0", default-features = false, path = "../smc_range_proof" } itertools.workspace = true [dev-dependencies] diff --git a/proof_system/src/derived_params.rs b/proof_system/src/derived_params.rs index d1826a7f..d2df6d0d 100644 --- a/proof_system/src/derived_params.rs +++ b/proof_system/src/derived_params.rs @@ -29,6 +29,7 @@ use saver::{ PreparedVerifyingKey as SaverPreparedVerifyingKey, VerifyingKey as SaverVerifyingKey, }, }; +use schnorr_pok::inequality::CommitmentKey; use smc_range_proof::prelude::MemberCommitmentKey; use vb_accumulator::setup::{ PreparedPublicKey as PreparedAccumPk, PreparedSetupParams as PreparedAccumParams, @@ -159,6 +160,14 @@ impl<'a, E: Pairing> DerivedParams<'a, MemberCommitmentKey, [E::G1A } } +impl<'a, E: Pairing, G: AffineRepr> DerivedParams<'a, CommitmentKey, [G; 2]> + for DerivedParamsTracker<'a, CommitmentKey, [G; 2], E> +{ + fn new_derived(ck: &CommitmentKey) -> [G; 2] { + [ck.g, ck.h] + } +} + macro_rules! impl_derived_for_prepared_ref { ($(#[$doc:meta])* $unprepared: ident, $prepared: ident) => { diff --git a/proof_system/src/proof_spec.rs b/proof_system/src/proof_spec.rs index 3487f19e..a5093af0 100644 --- a/proof_system/src/proof_spec.rs +++ b/proof_system/src/proof_spec.rs @@ -31,6 +31,7 @@ use saver::prelude::{ PreparedEncryptionKey, PreparedVerifyingKey as SaverPreparedVerifyingKey, VerifyingKey as SaverVerifyingKey, }; +use schnorr_pok::inequality::CommitmentKey; use serde::{Deserialize, Serialize}; use smc_range_proof::prelude::MemberCommitmentKey; @@ -233,6 +234,7 @@ where StatementDerivedParams>, StatementDerivedParams<[G; 2]>, StatementDerivedParams<[E::G1Affine; 2]>, + StatementDerivedParams<[G; 2]>, ), ProofSystemError, > { @@ -250,6 +252,7 @@ where let mut derived_bound_check_bpp_comm = DerivedParamsTracker::<(G, G), [G; 2], E>::new(); let mut derived_bound_check_smc_comm = DerivedParamsTracker::, [E::G1Affine; 2], E>::new(); + let mut derived_ineq_comm = DerivedParamsTracker::, [G; 2], E>::new(); // To avoid creating variable with short lifetime let mut saver_comm_keys = BTreeMap::new(); @@ -343,6 +346,10 @@ where }; derived_bound_check_smc_comm.on_new_statement_idx(comm_key, s_idx); } + Statement::PublicInequality(s) => { + let ck = s.get_comm_key(&self.setup_params, s_idx)?; + derived_ineq_comm.on_new_statement_idx(ck, s_idx); + } _ => (), } } @@ -353,6 +360,7 @@ where derived_r1cs_comm.finish(), derived_bound_check_bpp_comm.finish(), derived_bound_check_smc_comm.finish(), + derived_ineq_comm.finish(), )) } diff --git a/proof_system/src/prover.rs b/proof_system/src/prover.rs index 6c8e012a..6c3573c2 100644 --- a/proof_system/src/prover.rs +++ b/proof_system/src/prover.rs @@ -27,6 +27,7 @@ use crate::{ bound_check_legogroth16::BoundCheckLegoGrothProtocol, bound_check_smc::BoundCheckSmcProtocol, bound_check_smc_with_kv::BoundCheckSmcWithKVProtocol, + inequality::InequalityProtocol, r1cs_legogorth16::R1CSLegogroth16Protocol, saver::SaverProtocol, schnorr::SchnorrProtocol, @@ -147,6 +148,7 @@ where r1cs_comm_keys, bound_check_bpp_comm, bound_check_smc_comm, + ineq_comm, ) = proof_spec.derive_commitment_keys()?; let mut sub_protocols = @@ -460,6 +462,17 @@ where } _ => err_incompat_witness!(s_idx, s, witness), }, + Statement::PublicInequality(s) => match witness { + Witness::PublicInequality(w) => { + let blinding = blindings.remove(&(s_idx, 0)); + let comm_key = s.get_comm_key(&proof_spec.setup_params, s_idx)?; + let mut sp = + InequalityProtocol::new(s_idx, s.inequal_to.clone(), &comm_key); + sp.init(rng, ineq_comm.get(s_idx).unwrap().as_slice(), w, blinding)?; + sub_protocols.push(SubProtocol::Inequality(sp)); + } + _ => err_incompat_witness!(s_idx, s, witness), + }, _ => return Err(ProofSystemError::InvalidStatement), } } diff --git a/proof_system/src/setup_params.rs b/proof_system/src/setup_params.rs index d28401a3..a301ab73 100644 --- a/proof_system/src/setup_params.rs +++ b/proof_system/src/setup_params.rs @@ -25,6 +25,7 @@ use saver::prelude::{ ChunkedCommitmentGens, EncryptionGens, EncryptionKey, ProvingKey as SaverSnarkProvingKey, VerifyingKey as SaverSnarkVerifyingKey, }; +use schnorr_pok::inequality::CommitmentKey; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use vb_accumulator::prelude::{ @@ -62,6 +63,7 @@ pub enum SetupParams { SmcParamsAndCommKeyAndSk( #[serde_as(as = "ArkObjectBytes")] SmcParamsAndCommitmentKeyAndSecretKey, ), + CommitmentKey(#[serde_as(as = "ArkObjectBytes")] CommitmentKey), } macro_rules! delegate { @@ -90,7 +92,8 @@ macro_rules! delegate { BBSSignatureParams23, BppSetupParams, SmcParamsAndCommKey, - SmcParamsAndCommKeyAndSk + SmcParamsAndCommKeyAndSk, + CommitmentKey : $($tt)+ } }}; @@ -122,7 +125,8 @@ macro_rules! delegate_reverse { BBSSignatureParams23, BppSetupParams, SmcParamsAndCommKey, - SmcParamsAndCommKeyAndSk + SmcParamsAndCommKeyAndSk, + CommitmentKey : $($tt)+ } diff --git a/proof_system/src/statement/bound_check_smc_with_kv.rs b/proof_system/src/statement/bound_check_smc_with_kv.rs index 25cd369c..69bf5ff9 100644 --- a/proof_system/src/statement/bound_check_smc_with_kv.rs +++ b/proof_system/src/statement/bound_check_smc_with_kv.rs @@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize}; use serde_with::serde_as; use smc_range_proof::prelude::{MemberCommitmentKey, SecretKey, SetMembershipCheckParams}; -/// Used by the verifier as it knows the secret key +/// Used by the verifier as it knows the secret key. Should not be shared with the prover #[serde_as] #[derive( Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize, diff --git a/proof_system/src/statement/inequality.rs b/proof_system/src/statement/inequality.rs new file mode 100644 index 00000000..59c36686 --- /dev/null +++ b/proof_system/src/statement/inequality.rs @@ -0,0 +1,62 @@ +use ark_ec::{pairing::Pairing, AffineRepr}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_std::vec::Vec; +use dock_crypto_utils::serde_utils::*; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; + +use crate::{error::ProofSystemError, setup_params::SetupParams, statement::Statement}; +use schnorr_pok::inequality::CommitmentKey; + +#[serde_as] +#[derive( + Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize, +)] +#[serde(bound = "")] +pub struct PublicInequality { + /// The public value with which the inequalty is being proven + #[serde_as(as = "ArkObjectBytes")] + pub inequal_to: G::ScalarField, + #[serde_as(as = "Option")] + pub comm_key: Option>, + pub comm_key_ref: Option, +} + +impl PublicInequality { + pub fn new_statement_from_params( + inequal_to: G::ScalarField, + comm_key: CommitmentKey, + ) -> Statement { + Statement::PublicInequality(Self { + inequal_to, + comm_key: Some(comm_key), + comm_key_ref: None, + }) + } + + pub fn new_statement_from_params_ref( + inequal_to: G::ScalarField, + comm_key_ref: usize, + ) -> Statement { + Statement::PublicInequality(Self { + inequal_to, + comm_key: None, + comm_key_ref: Some(comm_key_ref), + }) + } + + pub fn get_comm_key<'a, E: Pairing>( + &'a self, + setup_params: &'a [SetupParams], + st_idx: usize, + ) -> Result<&'a CommitmentKey, ProofSystemError> { + extract_param!( + setup_params, + &self.comm_key, + self.comm_key_ref, + CommitmentKey, + IncompatibleBoundCheckSetupParamAtIndex, + st_idx + ) + } +} diff --git a/proof_system/src/statement/mod.rs b/proof_system/src/statement/mod.rs index 5e7750a8..985b37a6 100644 --- a/proof_system/src/statement/mod.rs +++ b/proof_system/src/statement/mod.rs @@ -14,6 +14,7 @@ pub mod bound_check_bpp; pub mod bound_check_legogroth16; pub mod bound_check_smc; pub mod bound_check_smc_with_kv; +pub mod inequality; pub mod ped_comm; pub mod ps_signature; pub mod r1cs_legogroth16; @@ -57,6 +58,8 @@ pub enum Statement { BoundCheckSmcWithKVProver(bound_check_smc_with_kv::BoundCheckSmcWithKVProver), /// Used by the verifier for bound check using set-membership check with keyed verification based protocols BoundCheckSmcWithKVVerifier(bound_check_smc_with_kv::BoundCheckSmcWithKVVerifier), + /// To prove inequality of a signed message with a public value + PublicInequality(inequality::PublicInequality), } /// A collection of statements @@ -111,7 +114,8 @@ macro_rules! delegate { BoundCheckBpp, BoundCheckSmc, BoundCheckSmcWithKVProver, - BoundCheckSmcWithKVVerifier + BoundCheckSmcWithKVVerifier, + PublicInequality : $($tt)+ } }} @@ -136,7 +140,8 @@ macro_rules! delegate_reverse { BoundCheckBpp, BoundCheckSmc, BoundCheckSmcWithKVProver, - BoundCheckSmcWithKVVerifier + BoundCheckSmcWithKVVerifier, + PublicInequality : $($tt)+ } diff --git a/proof_system/src/statement_proof.rs b/proof_system/src/statement_proof.rs index b859c5dc..a86ba493 100644 --- a/proof_system/src/statement_proof.rs +++ b/proof_system/src/statement_proof.rs @@ -36,6 +36,7 @@ pub enum StatementProof { BoundCheckBpp(BoundCheckBppProof), BoundCheckSmc(BoundCheckSmcProof), BoundCheckSmcWithKV(BoundCheckSmcWithKVProof), + Inequality(InequalityProof), } macro_rules! delegate { @@ -56,7 +57,8 @@ macro_rules! delegate { PoKBBSSignature23G1, BoundCheckBpp, BoundCheckSmc, - BoundCheckSmcWithKV + BoundCheckSmcWithKV, + Inequality : $($tt)+ } }}; @@ -80,7 +82,8 @@ macro_rules! delegate_reverse { PoKBBSSignature23G1, BoundCheckBpp, BoundCheckSmc, - BoundCheckSmcWithKV + BoundCheckSmcWithKV, + Inequality : $($tt)+ } @@ -334,6 +337,25 @@ impl BoundCheckSmcWithKVProof { } } +#[serde_as] +#[derive( + Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize, +)] +#[serde(bound = "")] +pub struct InequalityProof { + #[serde_as(as = "ArkObjectBytes")] + pub proof: schnorr_pok::inequality::InequalityProof, + #[serde_as(as = "ArkObjectBytes")] + pub comm: G, + pub sp: PedersenCommitmentProof, +} + +impl InequalityProof { + pub fn get_schnorr_response_for_message(&self) -> Result<&G::ScalarField, ProofSystemError> { + self.sp.response.get_response(0).map_err(|e| e.into()) + } +} + mod serialization { use super::{ AffineRepr, CanonicalDeserialize, CanonicalSerialize, Pairing, Read, SerializationError, diff --git a/proof_system/src/sub_protocols/bound_check_legogroth16.rs b/proof_system/src/sub_protocols/bound_check_legogroth16.rs index 86b0abc6..6c4c072f 100644 --- a/proof_system/src/sub_protocols/bound_check_legogroth16.rs +++ b/proof_system/src/sub_protocols/bound_check_legogroth16.rs @@ -405,9 +405,7 @@ mod tests { }; let v = Fr::rand(&mut rng); - let proof = create_random_proof(circuit, v, &proving_key, &mut rng).unwrap(); - - assert!(verify_proof(&pvk, &proof, &[Fr::from(min), Fr::from(max)],).is_err()); + assert!(create_random_proof(circuit, v, &proving_key, &mut rng).is_err()); } } } diff --git a/proof_system/src/sub_protocols/bound_check_smc.rs b/proof_system/src/sub_protocols/bound_check_smc.rs index 818363a2..6ee557f9 100644 --- a/proof_system/src/sub_protocols/bound_check_smc.rs +++ b/proof_system/src/sub_protocols/bound_check_smc.rs @@ -30,7 +30,6 @@ pub struct BoundCheckSmcProtocol<'a, E: Pairing> { pub params_and_comm_key: &'a SmcParamsAndCommitmentKey, pub comm: Option, pub smc_protocol: Option>, - pub smc_proof: Option>, pub sp: Option>, } @@ -43,7 +42,6 @@ impl<'a, E: Pairing> BoundCheckSmcProtocol<'a, E> { params_and_comm_key: params, comm: None, smc_protocol: None, - smc_proof: None, sp: None, } } diff --git a/proof_system/src/sub_protocols/bound_check_smc_with_kv.rs b/proof_system/src/sub_protocols/bound_check_smc_with_kv.rs index c7325c82..d975aaa9 100644 --- a/proof_system/src/sub_protocols/bound_check_smc_with_kv.rs +++ b/proof_system/src/sub_protocols/bound_check_smc_with_kv.rs @@ -30,7 +30,6 @@ pub struct BoundCheckSmcWithKVProtocol<'a, E: Pairing> { pub params_and_comm_key_and_sk: Option<&'a SmcParamsAndCommitmentKeyAndSecretKey>, pub comm: Option, pub smc_protocol: Option>, - pub smc_proof: Option>, pub sp: Option>, } @@ -49,7 +48,6 @@ impl<'a, E: Pairing> BoundCheckSmcWithKVProtocol<'a, E> { params_and_comm_key_and_sk: None, comm: None, smc_protocol: None, - smc_proof: None, sp: None, } } @@ -68,7 +66,6 @@ impl<'a, E: Pairing> BoundCheckSmcWithKVProtocol<'a, E> { params_and_comm_key_and_sk: Some(params), comm: None, smc_protocol: None, - smc_proof: None, sp: None, } } diff --git a/proof_system/src/sub_protocols/inequality.rs b/proof_system/src/sub_protocols/inequality.rs new file mode 100644 index 00000000..1b4ec9ab --- /dev/null +++ b/proof_system/src/sub_protocols/inequality.rs @@ -0,0 +1,170 @@ +use crate::{ + error::ProofSystemError, + statement_proof::{InequalityProof, StatementProof}, + sub_protocols::schnorr::SchnorrProtocol, +}; +use ark_ec::{pairing::Pairing, AffineRepr}; +use ark_serialize::CanonicalSerialize; +use ark_std::{collections::BTreeMap, io::Write, rand::RngCore, vec, UniformRand}; +use schnorr_pok::inequality::{CommitmentKey, DiscreteLogInequalityProtocol}; + +#[derive(Clone, Debug, PartialEq)] +pub struct InequalityProtocol<'a, G: AffineRepr> { + pub id: usize, + /// The public value with which the inequalty is being proven + pub inequal_to: G::ScalarField, + pub comm_key: &'a CommitmentKey, + pub comm: Option, + pub inequality_protocol: Option>, + pub sp: Option>, +} + +impl<'a, G: AffineRepr> InequalityProtocol<'a, G> { + pub fn new(id: usize, inequal_to: G::ScalarField, comm_key: &'a CommitmentKey) -> Self { + Self { + id, + inequal_to, + comm_key, + comm: None, + inequality_protocol: None, + sp: None, + } + } + + pub fn init( + &mut self, + rng: &mut R, + comm_key_as_slice: &'a [G], + message: G::ScalarField, + blinding: Option, + ) -> Result<(), ProofSystemError> { + if self.sp.is_some() { + return Err(ProofSystemError::SubProtocolAlreadyInitialized(self.id)); + } + let randomness = G::ScalarField::rand(rng); + let comm = self.comm_key.commit(&message, &randomness); + self.inequality_protocol = Some( + DiscreteLogInequalityProtocol::new_for_inequality_with_public_value( + rng, + message, + randomness, + &comm, + &self.inequal_to, + &self.comm_key, + )?, + ); + self.comm = Some(comm); + self.init_schnorr_protocol(rng, comm_key_as_slice, message, blinding, randomness) + } + + fn init_schnorr_protocol( + &mut self, + rng: &mut R, + comm_key: &'a [G], + message: G::ScalarField, + blinding: Option, + blinding_for_ineqality_protocol_commitment: G::ScalarField, + ) -> Result<(), ProofSystemError> { + let blinding = if blinding.is_none() { + G::ScalarField::rand(rng) + } else { + blinding.unwrap() + }; + let mut blindings = BTreeMap::new(); + blindings.insert(0, blinding); + + // NOTE: value of id is dummy + let mut sp = SchnorrProtocol::new(10000, &comm_key, self.comm.unwrap()); + sp.init( + rng, + blindings.clone(), + vec![message, blinding_for_ineqality_protocol_commitment], + )?; + self.sp = Some(sp); + Ok(()) + } + + pub fn challenge_contribution(&self, mut writer: W) -> Result<(), ProofSystemError> { + if self.sp.is_none() { + return Err(ProofSystemError::SubProtocolNotReadyToGenerateChallenge( + self.id, + )); + } + self.inequality_protocol + .as_ref() + .unwrap() + .challenge_contribution_for_public_inequality( + self.comm.as_ref().unwrap(), + &self.inequal_to, + &self.comm_key, + &mut writer, + )?; + self.sp + .as_ref() + .unwrap() + .challenge_contribution(&mut writer)?; + Ok(()) + } + + pub fn gen_proof_contribution( + &mut self, + challenge: &G::ScalarField, + ) -> Result, ProofSystemError> { + if self.sp.is_none() { + return Err(ProofSystemError::SubProtocolNotReadyToGenerateProof( + self.id, + )); + } + let proof = self + .inequality_protocol + .take() + .unwrap() + .gen_proof(challenge)?; + Ok(StatementProof::Inequality(InequalityProof { + proof, + comm: self.comm.take().unwrap(), + sp: self + .sp + .take() + .unwrap() + .gen_proof_contribution_as_struct(challenge)?, + })) + } + + pub fn verify_proof_contribution( + &self, + challenge: &G::ScalarField, + proof: &InequalityProof, + comm_key_as_slice: &[G], + ) -> Result<(), ProofSystemError> { + proof.proof.verify_for_inequality_with_public_value( + &proof.comm, + &self.inequal_to, + challenge, + &self.comm_key, + )?; + // NOTE: value of id is dummy + let sp = SchnorrProtocol::new(10000, comm_key_as_slice, proof.comm); + + sp.verify_proof_contribution_as_struct(challenge, &proof.sp) + } + + pub fn compute_challenge_contribution( + comm_key_as_slice: &[G], + proof: &InequalityProof, + inequal_to: &G::ScalarField, + comm_key: &CommitmentKey, + mut writer: W, + ) -> Result<(), ProofSystemError> { + proof.proof.challenge_contribution_for_public_inequality( + &proof.comm, + inequal_to, + comm_key, + &mut writer, + )?; + comm_key_as_slice.serialize_compressed(&mut writer)?; + proof.comm.serialize_compressed(&mut writer)?; + proof.sp.t.serialize_compressed(&mut writer)?; + Ok(()) + } +} diff --git a/proof_system/src/sub_protocols/mod.rs b/proof_system/src/sub_protocols/mod.rs index 1bf92efd..e485a640 100644 --- a/proof_system/src/sub_protocols/mod.rs +++ b/proof_system/src/sub_protocols/mod.rs @@ -6,6 +6,7 @@ pub mod bound_check_bpp; pub mod bound_check_legogroth16; pub mod bound_check_smc; pub mod bound_check_smc_with_kv; +pub mod inequality; pub mod ps_signature; pub mod r1cs_legogorth16; pub mod saver; @@ -25,7 +26,7 @@ use crate::{ bound_check_bpp::BoundCheckBppProtocol, bound_check_legogroth16::BoundCheckLegoGrothProtocol, bound_check_smc::BoundCheckSmcProtocol, - bound_check_smc_with_kv::BoundCheckSmcWithKVProtocol, + bound_check_smc_with_kv::BoundCheckSmcWithKVProtocol, inequality::InequalityProtocol, r1cs_legogorth16::R1CSLegogroth16Protocol, }, }; @@ -48,9 +49,14 @@ pub enum SubProtocol<'a, E: Pairing, G: AffineRepr> { PSSignaturePoK(ps_signature::PSSignaturePoK<'a, E>), /// For BBS signature in group G1 PoKBBSSignature23G1(bbs_23::PoKBBSSigG1SubProtocol<'a, E>), + /// For range proof using Bulletproofs++ BoundCheckBpp(BoundCheckBppProtocol<'a, G>), + /// For range proof using set-membership check BoundCheckSmc(BoundCheckSmcProtocol<'a, E>), + /// For range proof using set-membership check with keyed verification BoundCheckSmcWithKV(BoundCheckSmcWithKVProtocol<'a, E>), + /// To prove inequality of a signed message with a public value + Inequality(InequalityProtocol<'a, G>), } macro_rules! delegate { @@ -68,7 +74,8 @@ macro_rules! delegate { PoKBBSSignature23G1, BoundCheckBpp, BoundCheckSmc, - BoundCheckSmcWithKV + BoundCheckSmcWithKV, + Inequality : $($tt)+ } }}; diff --git a/proof_system/src/verifier.rs b/proof_system/src/verifier.rs index 5922cdd4..4d435629 100644 --- a/proof_system/src/verifier.rs +++ b/proof_system/src/verifier.rs @@ -12,6 +12,7 @@ use crate::{ bound_check_legogroth16::BoundCheckLegoGrothProtocol, bound_check_smc::BoundCheckSmcProtocol, bound_check_smc_with_kv::BoundCheckSmcWithKVProtocol, + inequality::InequalityProtocol, ps_signature::PSSignaturePoK, r1cs_legogorth16::R1CSLegogroth16Protocol, saver::SaverProtocol, @@ -166,6 +167,7 @@ where r1cs_comm_keys, bound_check_bpp_comm, bound_check_smc_comm, + ineq_comm, ) = proof_spec.derive_commitment_keys()?; // Prepare required parameters for pairings @@ -568,6 +570,28 @@ where } _ => err_incompat_proof!(s_idx, s, proof), }, + Statement::PublicInequality(s) => match proof { + StatementProof::Inequality(p) => { + check_resp_for_equalities_with_err!( + witness_equalities, + s_idx, + p, + get_schnorr_response_for_message, + Self, + responses_for_equalities + ); + + let comm_key_slice = ineq_comm.get(s_idx).unwrap(); + InequalityProtocol::compute_challenge_contribution( + comm_key_slice.as_slice(), + p, + &s.inequal_to, + s.get_comm_key(&proof_spec.setup_params, s_idx)?, + &mut challenge_bytes, + )?; + } + _ => err_incompat_proof!(s_idx, s, proof), + }, _ => return Err(ProofSystemError::InvalidStatement), } } @@ -885,6 +909,15 @@ where } _ => err_incompat_proof!(s_idx, s, proof), }, + Statement::PublicInequality(s) => match proof { + StatementProof::Inequality(ref iq_proof) => { + let comm_key = s.get_comm_key(&proof_spec.setup_params, s_idx)?; + let sp = InequalityProtocol::new(s_idx, s.inequal_to, comm_key); + let comm_key = ineq_comm.get(s_idx).unwrap(); + sp.verify_proof_contribution(&challenge, iq_proof, comm_key.as_slice())? + } + _ => err_incompat_proof!(s_idx, s, proof), + }, _ => return Err(ProofSystemError::InvalidStatement), } } diff --git a/proof_system/src/witness.rs b/proof_system/src/witness.rs index 9881d51e..0a7cff0c 100644 --- a/proof_system/src/witness.rs +++ b/proof_system/src/witness.rs @@ -34,6 +34,7 @@ pub enum Witness { BoundCheckBpp(#[serde_as(as = "ArkObjectBytes")] E::ScalarField), BoundCheckSmc(#[serde_as(as = "ArkObjectBytes")] E::ScalarField), BoundCheckSmcWithKV(#[serde_as(as = "ArkObjectBytes")] E::ScalarField), + PublicInequality(#[serde_as(as = "ArkObjectBytes")] E::ScalarField), } macro_rules! delegate { @@ -51,7 +52,8 @@ macro_rules! delegate { PoKBBSSignature23G1, BoundCheckBpp, BoundCheckSmc, - BoundCheckSmcWithKV + BoundCheckSmcWithKV, + PublicInequality : $($tt)+ } }} @@ -72,7 +74,8 @@ macro_rules! delegate_reverse { PoKBBSSignature23G1, BoundCheckBpp, BoundCheckSmc, - BoundCheckSmcWithKV + BoundCheckSmcWithKV, + PublicInequality : $($tt)+ } diff --git a/proof_system/tests/bbs_plus_and_accumulator.rs b/proof_system/tests/bbs_plus_and_accumulator.rs index a395b8ea..9b9e2c44 100644 --- a/proof_system/tests/bbs_plus_and_accumulator.rs +++ b/proof_system/tests/bbs_plus_and_accumulator.rs @@ -23,6 +23,7 @@ use proof_system::{ }, bbs_23::PoKBBSSignature23G1 as PoKSignatureBBS23G1Stmt, bbs_plus::PoKBBSSignatureG1 as PoKSignatureBBSG1Stmt, + inequality::PublicInequality as InequalityStmt, ped_comm::PedersenCommitment as PedersenCommitmentStmt, Statements, }, @@ -31,10 +32,11 @@ use proof_system::{ PoKBBSSignature23G1 as PoKSignatureBBS23G1Wit, PoKBBSSignatureG1 as PoKSignatureBBSG1Wit, }, }; +use schnorr_pok::inequality::CommitmentKey; use test_utils::{accumulators::*, bbs::*, test_serialization, Fr, ProofG1}; macro_rules! gen_tests { - ($test1_name: ident, $test2_name: ident, $test3_name: ident, $test4_name: ident, $test5_name: ident, $setup_fn_name: ident, $sig: ident, $stmt: ident, $wit: ident, $setup_param_name: ident) => { + ($test1_name: ident, $test2_name: ident, $test3_name: ident, $test4_name: ident, $test5_name: ident, $test6_name: ident, $setup_fn_name: ident, $sig: ident, $stmt: ident, $wit: ident, $setup_param_name: ident) => { #[test] fn $test1_name() { // Prove knowledge of 3 BBS+ signatures and 3 of the messages are same among them. @@ -810,9 +812,9 @@ macro_rules! gen_tests { #[test] fn $test3_name() { - // Prove knowledge of commitment in Pedersen commitments and equality with a BBS+ signature. - // Useful when requesting a blind signature and proving knowledge of a signature along with - // some the equality of certain messages in the commitment and signature + // Prove knowledge of commitment in Pedersen commitments and equality of the committed message + // with certain message(s) in the signature. Useful when requesting a blind signature and proving + // knowledge of a signature along with some the equality of certain messages in the commitment and signature let mut rng = StdRng::seed_from_u64(0u64); @@ -1250,6 +1252,127 @@ macro_rules! gen_tests { start.elapsed() ); } + + #[test] + fn $test6_name() { + // Prove inequality of a signed message with a public value. + + let mut rng = StdRng::seed_from_u64(0u64); + + let comm_key = CommitmentKey::::new::(b"test"); + + let msg_count = 5; + let (msgs, sig_params, sig_keypair, sig) = $setup_fn_name(&mut rng, msg_count as u32); + let inequal_to = Fr::rand(&mut rng); + let inequal_msg_idx = 1; + assert_ne!(msgs[inequal_msg_idx], inequal_to); + + let mut statements = Statements::new(); + statements.add($stmt::new_statement_from_params( + sig_params.clone(), + sig_keypair.public_key.clone(), + BTreeMap::new(), + )); + statements.add(InequalityStmt::new_statement_from_params( + inequal_to.clone(), + comm_key.clone(), + )); + + test_serialization!(Statements, statements); + + let mut meta_statements = MetaStatements::new(); + meta_statements.add_witness_equality(EqualWitnesses( + vec![(0, inequal_msg_idx), (1, 0)] + .into_iter() + .collect::>(), + )); + + let context = Some(b"test".to_vec()); + let proof_spec = ProofSpec::new(statements.clone(), meta_statements, vec![], context.clone()); + proof_spec.validate().unwrap(); + + test_serialization!(ProofSpec, proof_spec); + + let mut witnesses = Witnesses::new(); + witnesses.add($wit::new_as_witness( + sig.clone(), + msgs.clone().into_iter().enumerate().collect(), + )); + witnesses.add(Witness::PublicInequality(msgs[inequal_msg_idx].clone())); + + test_serialization!(Witnesses, witnesses); + + let nonce = Some(b"test nonce".to_vec()); + let proof = ProofG1::new::( + &mut rng, + proof_spec.clone(), + witnesses.clone(), + nonce.clone(), + Default::default(), + ) + .unwrap() + .0; + + test_serialization!(ProofG1, proof); + + proof + .verify::(&mut rng, proof_spec.clone(), nonce.clone(), Default::default()) + .unwrap(); + + + // Equality should fail to verify + let mut wrong_statements = Statements::new(); + wrong_statements.add($stmt::new_statement_from_params( + sig_params, + sig_keypair.public_key.clone(), + BTreeMap::new(), + )); + // Statement mentions wrong inequal, i.e the value is equal to the signed message + wrong_statements.add(InequalityStmt::new_statement_from_params( + msgs[inequal_msg_idx].clone(), + comm_key.clone(), + )); + + let mut meta_statements = MetaStatements::new(); + meta_statements.add_witness_equality(EqualWitnesses( + vec![(0, inequal_msg_idx), (1, 0)] + .into_iter() + .collect::>(), + )); + + // proof spec with wrong statement + let wrong_proof_spec = ProofSpec::new(wrong_statements.clone(), meta_statements, vec![], None); + + let mut witnesses = Witnesses::new(); + witnesses.add($wit::new_as_witness( + sig, + msgs.clone().into_iter().enumerate().collect(), + )); + witnesses.add(Witness::PublicInequality(msgs[inequal_msg_idx].clone())); + + // Proof can't be created when the values are equal + assert!(ProofG1::new::( + &mut rng, + wrong_proof_spec.clone(), + witnesses.clone(), + None, + Default::default(), + ).is_err()); + + // Create proof with inequal value + let proof = ProofG1::new::( + &mut rng, + proof_spec, + witnesses.clone(), + None, + Default::default(), + ) + .unwrap() + .0; + + // Try to verify the proof with equal value + assert!(proof.verify::(&mut rng, wrong_proof_spec, None, Default::default()).is_err()) + } } } @@ -1259,6 +1382,7 @@ gen_tests!( pok_of_knowledge_in_pedersen_commitment_and_bbs_plus_sig, verifier_local_linkability_with_bbs_plus, pok_of_bbs_plus_sig_with_reusing_setup_params, + pok_of_bbs_plus_sig_and_inequality_with_public_value, bbs_plus_sig_setup, SignatureG1, PoKSignatureBBSG1Stmt, @@ -1271,6 +1395,7 @@ gen_tests!( pok_of_knowledge_in_pedersen_commitment_and_bbs_sig, verifier_local_linkability_with_bbs, pok_of_bbs_sig_with_reusing_setup_params, + pok_of_bbs_sig_and_inequality_with_public_value, bbs_sig_setup, Signature23G1, PoKSignatureBBS23G1Stmt, diff --git a/proof_system/tests/bound_check_smc_with_kv.rs b/proof_system/tests/bound_check_smc_with_kv.rs index 66808d5c..9ea3eac1 100644 --- a/proof_system/tests/bound_check_smc_with_kv.rs +++ b/proof_system/tests/bound_check_smc_with_kv.rs @@ -23,7 +23,7 @@ use proof_system::{ BoundCheckSmcWithKVVerifier as BoundCheckVerifierStmt, }, }, - sub_protocols::{should_use_cls}, + sub_protocols::should_use_cls, witness::PoKBBSSignatureG1 as PoKSignatureBBSG1Wit, }; diff --git a/schnorr_pok/Cargo.toml b/schnorr_pok/Cargo.toml index 70a243c9..d5ee22e4 100644 --- a/schnorr_pok/Cargo.toml +++ b/schnorr_pok/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "schnorr_pok" -version = "0.15.0" +version = "0.16.0" edition.workspace = true authors.workspace = true license.workspace = true diff --git a/schnorr_pok/README.md b/schnorr_pok/README.md index a3ee0aa4..65ecfa7e 100644 --- a/schnorr_pok/README.md +++ b/schnorr_pok/README.md @@ -1,4 +1,6 @@ -# schnorr_pok +# Schnorr's proof of knowledge + + Schnorr protocol to prove knowledge of 1 or more discrete logs in zero knowledge. Refer [this](https://crypto.stanford.edu/cs355/19sp/lec5.pdf) for more details of Schnorr protocol. @@ -25,4 +27,9 @@ There is another variant of Schnorr which gives shorter proof but is not impleme 4. Verifier creates `T'` as `T' = s * G - c * Y` and computes `c'` as `c' = Hash(G||Y||T')` 5. Proof if valid if `c == c'` -License: Apache-2.0 +Also implements the proof of inequality of discrete log (a value committed in a Pedersen commitment), +either with a public value or with another discrete log in [`Inequality`] + +[`Inequality`]: https://docs.rs/schnorr_pok/latest/schnorr_pok/inequality/ + + diff --git a/schnorr_pok/src/error.rs b/schnorr_pok/src/error.rs index a0159f8e..e26f1384 100644 --- a/schnorr_pok/src/error.rs +++ b/schnorr_pok/src/error.rs @@ -12,6 +12,8 @@ pub enum SchnorrError { InvalidResponse, #[serde(with = "ArkSerializationError")] Serialization(SerializationError), + ValueMustNotBeEqual, + InvalidProofOfEquality, } impl From for SchnorrError { diff --git a/schnorr_pok/src/inequality.rs b/schnorr_pok/src/inequality.rs new file mode 100644 index 00000000..5d385484 --- /dev/null +++ b/schnorr_pok/src/inequality.rs @@ -0,0 +1,411 @@ +//! Protocol to prove inequality (≠) of a discrete log in zero knowledge. Based on section 1 of this +//! [paper](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/U-Prove20Inequality20Proof20Extension.pdf) but is an optimized version of it. +//! We have a commitment to a value `m` as `C = g * m + h * r` and we want to prove that `m` ≠ `v` where `m` is not known to verifier but `C` and `v` are. +//! The protocol works as follows: +//! 1. Prover choose a random `a` and computes `k = -a * r` +//! 2. Prover computes `B = g * (m - v) * a`. If `B` is sent to the verifier and the verifier checks that `B` ≠ 1 then it +//! will be convinced that `m` ≠ `v`. Multiplication with `a` is necessary to stop the verifier from computing `g * m` from `B` +//! 3. `B` can also be written as `(C - g * v) * a + h * k` as `C * a - g * v * a + h * k = g * (m-v) * a + h * r * a + h * -a * r`. +//! 4. The prover runs 3 instances of Schnorr's proof of knowledge as below: +//! a. knowledge of `m` and `r` in `C = g * m + h * r` +//! b. knowledge of `(m - v) * a` in `B = g * (m - v) * a`. +//! c. knowledge of `a` and `k` in `B = (C - g * v) * a + h * k` +//! +//! For proving inequality of 2 committed values, i.e. to prove `m1` ≠ `m2` when given commitments `C1 = g * m1 + h * r1` and `C2 = g * m2 + h * r2`, +//! use the above protocol with commitment set to `C1 - C2` and `v = 0` as `C1 - C2 = g * (m1 - m2) + h * (r1 - r2)`. If `(m1 - m2)` ≠ 0, then `m1` ≠ `m2`` + +use crate::{ + error::SchnorrError, impl_proof_of_knowledge_of_discrete_log, SchnorrCommitment, + SchnorrResponse, +}; +use ark_ec::{AffineRepr, CurveGroup}; +use ark_ff::{PrimeField, Zero}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_std::{fmt::Debug, io::Write, rand::RngCore, vec::Vec, UniformRand}; +use digest::Digest; +use dock_crypto_utils::{ + concat_slices, hashing_utils::affine_group_elem_from_try_and_incr, misc::n_rand, serde_utils::*, +}; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; +use zeroize::{Zeroize, ZeroizeOnDrop}; + +impl_proof_of_knowledge_of_discrete_log!(KnowledgeOfExpProtocol, KnowledgeOfExpProof); + +/// The commitment key for commitment `C` +#[derive(Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize)] +pub struct CommitmentKey { + pub g: G, + pub h: G, +} + +impl CommitmentKey { + pub fn new(label: &[u8]) -> Self { + let g = affine_group_elem_from_try_and_incr::(&concat_slices![label, b" : G"]); + let h = affine_group_elem_from_try_and_incr::(&concat_slices![label, b" : H"]); + Self { g, h } + } + + pub fn commit(&self, member: &G::ScalarField, randomness: &G::ScalarField) -> G { + (self.g * member + self.h * randomness).into() + } +} + +/// Protocol to prove inequality of discrete log (committed in a Pedersen commitment) with either a +/// public value or another discrete log +#[derive( + Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop, CanonicalSerialize, CanonicalDeserialize, +)] +pub struct DiscreteLogInequalityProtocol { + pub value: G::ScalarField, + pub randomness: G::ScalarField, + pub a: G::ScalarField, + pub k: G::ScalarField, + pub b: G, + pub sc_c: SchnorrCommitment, + pub sc_b: KnowledgeOfExpProtocol, + pub sc_b_ped: SchnorrCommitment, +} + +/// Proof created using `DiscreteLogInequalityProtocol` +#[derive(Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize)] +pub struct InequalityProof { + pub b: G, + pub sc_c: SchnorrResponse, + pub t_c: G, + pub sc_b: KnowledgeOfExpProof, + pub sc_b_ped: SchnorrResponse, + pub t_b_ped: G, +} + +impl DiscreteLogInequalityProtocol { + /// Initiate proof generation when proving discrete log inequality with a public value, + /// i.e. `value` ≠ `inequal_to` given commitment `commitment = g * value + h * randomness` + pub fn new_for_inequality_with_public_value( + rng: &mut R, + value: G::ScalarField, + randomness: G::ScalarField, + commitment: &G, + inequal_to: &G::ScalarField, + comm_key: &CommitmentKey, + ) -> Result { + if &value == inequal_to { + return Err(SchnorrError::ValueMustNotBeEqual); + } + let a = G::ScalarField::rand(rng); + let k = -(randomness * a); + let sc_c = SchnorrCommitment::new(&[comm_key.g, comm_key.h], n_rand(rng, 2).collect()); + let w = (value - inequal_to) * a; + let b = comm_key.g * w; + let sc_b = KnowledgeOfExpProtocol::init(w, G::ScalarField::rand(rng), &comm_key.g); + let sc_b_ped = SchnorrCommitment::new( + &[ + Self::base_for_b(commitment, inequal_to, comm_key), + comm_key.h, + ], + n_rand(rng, 2).collect(), + ); + Ok(Self { + value, + randomness, + a, + k, + b: b.into_affine(), + sc_c, + sc_b, + sc_b_ped, + }) + } + + /// Initiate proof generation when proving discrete log inequality with another discrete log, + /// i.e. `value1` ≠ `value2` given commitments `commitment1 = g * value1 + h * randomness1` and + /// `commitment2 = g * value2 + h * randomness2` + pub fn new_for_inequality_with_committed_value( + rng: &mut R, + value1: G::ScalarField, + randomness1: G::ScalarField, + commitment1: &G, + value2: G::ScalarField, + randomness2: G::ScalarField, + commitment2: &G, + comm_key: &CommitmentKey, + ) -> Result { + if value1 == value2 { + return Err(SchnorrError::ValueMustNotBeEqual); + } + Self::new_for_inequality_with_public_value( + rng, + value1 - value2, + randomness1 - randomness2, + &Self::transformed_commitments_for_committed_inequality(commitment1, commitment2), + &G::ScalarField::zero(), + comm_key, + ) + } + + pub fn challenge_contribution_for_public_inequality( + &self, + commitment: &G, + inequal_to: &G::ScalarField, + comm_key: &CommitmentKey, + writer: W, + ) -> Result<(), SchnorrError> { + Self::compute_challenge_contribution( + &self.b, + commitment, + inequal_to, + &self.sc_c.t, + &self.sc_b.t, + &self.sc_b_ped.t, + comm_key, + writer, + ) + } + + pub fn challenge_contribution_for_committed_inequality( + &self, + commitment1: &G, + commitment2: &G, + comm_key: &CommitmentKey, + writer: W, + ) -> Result<(), SchnorrError> { + Self::compute_challenge_contribution( + &self.b, + &Self::transformed_commitments_for_committed_inequality(commitment1, commitment2), + &G::ScalarField::zero(), + &self.sc_c.t, + &self.sc_b.t, + &self.sc_b_ped.t, + comm_key, + writer, + ) + } + + pub fn gen_proof(self, challenge: &G::ScalarField) -> Result, SchnorrError> { + let sc_c = self + .sc_c + .response(&[self.value, self.randomness], challenge)?; + let sc_b = self.sc_b.clone().gen_proof(challenge); + let sc_b_ped = self.sc_b_ped.response(&[self.a, self.k], challenge)?; + Ok(InequalityProof { + b: self.b, + sc_c, + t_c: self.sc_c.t, + sc_b, + sc_b_ped, + t_b_ped: self.sc_b_ped.t, + }) + } + + pub fn compute_challenge_contribution( + b: &G, + commitment: &G, + inequal_to: &G::ScalarField, + t_c: &G, + t_b: &G, + t_b_ped: &G, + comm_key: &CommitmentKey, + mut writer: W, + ) -> Result<(), SchnorrError> { + comm_key.g.serialize_compressed(&mut writer)?; + comm_key.h.serialize_compressed(&mut writer)?; + commitment.serialize_compressed(&mut writer)?; + t_c.serialize_compressed(&mut writer)?; + b.serialize_compressed(&mut writer)?; + t_b.serialize_compressed(&mut writer)?; + Self::base_for_b(commitment, inequal_to, comm_key).serialize_compressed(&mut writer)?; + t_b_ped.serialize_compressed(&mut writer)?; + Ok(()) + } + + fn transformed_commitments_for_committed_inequality(commitment1: &G, commitment2: &G) -> G { + (commitment1.into_group() - commitment2.into_group()).into() + } + + fn base_for_b(commitment: &G, inequal_to: &G::ScalarField, comm_key: &CommitmentKey) -> G { + (commitment.into_group() - (comm_key.g * inequal_to)).into() + } +} + +impl InequalityProof { + pub fn verify_for_inequality_with_public_value( + &self, + commitment: &G, + inequal_to: &G::ScalarField, + challenge: &G::ScalarField, + comm_key: &CommitmentKey, + ) -> Result<(), SchnorrError> { + if self.b.is_zero() { + return Err(SchnorrError::InvalidProofOfEquality); + } + self.sc_c + .is_valid(&[comm_key.g, comm_key.h], commitment, &self.t_c, challenge) + .map_err(|_| SchnorrError::InvalidProofOfEquality)?; + if !self.sc_b.verify(&self.b, &comm_key.g, challenge) { + return Err(SchnorrError::InvalidProofOfEquality); + } + self.sc_b_ped + .is_valid( + &[ + DiscreteLogInequalityProtocol::base_for_b(commitment, inequal_to, comm_key), + comm_key.h, + ], + &self.b, + &self.t_b_ped, + challenge, + ) + .map_err(|_| SchnorrError::InvalidProofOfEquality)?; + Ok(()) + } + + pub fn verify_for_inequality_with_committed_value( + &self, + commitment1: &G, + commitment2: &G, + challenge: &G::ScalarField, + comm_key: &CommitmentKey, + ) -> Result<(), SchnorrError> { + self.verify_for_inequality_with_public_value( + &DiscreteLogInequalityProtocol::transformed_commitments_for_committed_inequality( + commitment1, + commitment2, + ), + &G::ScalarField::zero(), + challenge, + comm_key, + ) + } + + pub fn challenge_contribution_for_public_inequality( + &self, + commitment: &G, + inequal_to: &G::ScalarField, + comm_key: &CommitmentKey, + writer: W, + ) -> Result<(), SchnorrError> { + DiscreteLogInequalityProtocol::compute_challenge_contribution( + &self.b, + commitment, + inequal_to, + &self.t_c, + &self.sc_b.t, + &self.t_b_ped, + comm_key, + writer, + ) + } + + pub fn challenge_contribution_for_committed_inequality( + &self, + commitment1: &G, + commitment2: &G, + comm_key: &CommitmentKey, + writer: W, + ) -> Result<(), SchnorrError> { + DiscreteLogInequalityProtocol::compute_challenge_contribution( + &self.b, + &DiscreteLogInequalityProtocol::transformed_commitments_for_committed_inequality( + commitment1, + commitment2, + ), + &G::ScalarField::zero(), + &self.t_c, + &self.sc_b.t, + &self.t_b_ped, + comm_key, + writer, + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::compute_random_oracle_challenge; + use ark_bls12_381::{Bls12_381, G1Affine}; + use ark_ec::pairing::Pairing; + use ark_std::{ + rand::{rngs::StdRng, SeedableRng}, + UniformRand, + }; + use blake2::Blake2b512; + + type Fr = ::ScalarField; + + #[test] + fn inequality_proof() { + let mut rng = StdRng::seed_from_u64(0u64); + let comm_key = CommitmentKey::::new::(b"test"); + let value = Fr::rand(&mut rng); + let randomness = Fr::rand(&mut rng); + let in_equal = Fr::rand(&mut rng); + let randomness2 = Fr::rand(&mut rng); + assert_ne!(value, in_equal); + + let comm = (comm_key.g * value + comm_key.h * randomness).into_affine(); + let comm2 = (comm_key.g * in_equal + comm_key.h * randomness2).into_affine(); + + let protocol = DiscreteLogInequalityProtocol::new_for_inequality_with_public_value( + &mut rng, value, randomness, &comm, &in_equal, &comm_key, + ) + .unwrap(); + + let mut bytes = vec![]; + protocol + .challenge_contribution_for_public_inequality(&comm, &in_equal, &comm_key, &mut bytes) + .unwrap(); + let challenge_prover = compute_random_oracle_challenge::(&bytes); + + let proof = protocol.gen_proof(&challenge_prover).unwrap(); + + let mut bytes = vec![]; + proof + .challenge_contribution_for_public_inequality(&comm, &in_equal, &comm_key, &mut bytes) + .unwrap(); + let challenge_verifier = compute_random_oracle_challenge::(&bytes); + + proof + .verify_for_inequality_with_public_value( + &comm, + &in_equal, + &challenge_verifier, + &comm_key, + ) + .unwrap(); + + let protocol = DiscreteLogInequalityProtocol::new_for_inequality_with_committed_value( + &mut rng, + value, + randomness, + &comm, + in_equal, + randomness2, + &comm2, + &comm_key, + ) + .unwrap(); + + let mut bytes = vec![]; + protocol + .challenge_contribution_for_committed_inequality(&comm, &comm2, &comm_key, &mut bytes) + .unwrap(); + let challenge_prover = compute_random_oracle_challenge::(&bytes); + + let proof = protocol.gen_proof(&challenge_prover).unwrap(); + + let mut bytes = vec![]; + proof + .challenge_contribution_for_committed_inequality(&comm, &comm2, &comm_key, &mut bytes) + .unwrap(); + let challenge_verifier = compute_random_oracle_challenge::(&bytes); + + proof + .verify_for_inequality_with_committed_value( + &comm, + &comm2, + &challenge_verifier, + &comm_key, + ) + .unwrap(); + } +} diff --git a/schnorr_pok/src/lib.rs b/schnorr_pok/src/lib.rs index eb4fa2a7..66169aae 100644 --- a/schnorr_pok/src/lib.rs +++ b/schnorr_pok/src/lib.rs @@ -24,6 +24,11 @@ //! 3. Prover creates response `s = r + c*x` and sends `c` and `s` to the Verifier as proof. //! 4. Verifier creates `T'` as `T' = s * G - c * Y` and computes `c'` as `c' = Hash(G||Y||T')` //! 5. Proof if valid if `c == c'` +//! +//! Also implements the proof of inequality of discrete log (a value committed in a Pedersen commitment), +//! either with a public value or with another discrete log in [`Inequality`] +//! +//! [`Inequality`]: crate::inequality use crate::error::SchnorrError; use ark_ec::{AffineRepr, CurveGroup, VariableBaseMSM}; @@ -43,6 +48,7 @@ use serde_with::serde_as; use rayon::prelude::*; pub mod error; +pub mod inequality; /// Trait implemented by Schnorr-based protocols for returning their contribution to the overall challenge. /// i.e. overall challenge is of form Hash({m_i}), and this function returns the bytecode for m_j for some j. diff --git a/secret_sharing_and_dkg/Cargo.toml b/secret_sharing_and_dkg/Cargo.toml index 0dc13940..88d35361 100644 --- a/secret_sharing_and_dkg/Cargo.toml +++ b/secret_sharing_and_dkg/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret_sharing_and_dkg" -version = "0.8.0" +version = "0.9.0" edition.workspace = true authors.workspace = true license.workspace = true @@ -19,7 +19,7 @@ serde.workspace = true serde_with.workspace = true zeroize.workspace = true dock_crypto_utils = { version = "0.16.0", default-features = false, path = "../utils" } -schnorr_pok = { version = "0.15.0", default-features = false, path = "../schnorr_pok" } +schnorr_pok = { version = "0.16.0", default-features = false, path = "../schnorr_pok" } [dev-dependencies] blake2.workspace = true diff --git a/smc_range_proof/Cargo.toml b/smc_range_proof/Cargo.toml index 34ff7bdd..9a452ba7 100644 --- a/smc_range_proof/Cargo.toml +++ b/smc_range_proof/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "smc_range_proof" -version = "0.1.0" +version = "0.2.0" edition.workspace = true authors.workspace = true license.workspace = true @@ -20,7 +20,7 @@ rayon = {workspace = true, optional = true} [dev-dependencies] blake2.workspace = true ark-bls12-381.workspace = true -schnorr_pok = { version = "0.15.0", default-features = false, path = "../schnorr_pok" } +schnorr_pok = { version = "0.16.0", default-features = false, path = "../schnorr_pok" } [features] default = [ "parallel"] diff --git a/smc_range_proof/src/cls_range_proof/range_proof.rs b/smc_range_proof/src/cls_range_proof/range_proof.rs index c7bab63b..9773849b 100644 --- a/smc_range_proof/src/cls_range_proof/range_proof.rs +++ b/smc_range_proof/src/cls_range_proof/range_proof.rs @@ -105,12 +105,6 @@ impl CLSRangeProofProtocol { if randomness_multiple != 1 { value = value * (base - 1) as u64; } - // let mut randomness_multiple = 1; - // if range % ((base - 1) as u64) != 0 { - // range = range * (base - 1) as u64; - // value = value * (base - 1) as u64; - // randomness_multiple = randomness_multiple * (base - 1); - // } let l = util::find_number_of_digits(range, base); let G = util::find_sumset_boundaries(range, base, l); diff --git a/smc_range_proof/src/common.rs b/smc_range_proof/src/common.rs index 3c5766a6..1a2f5b4e 100644 --- a/smc_range_proof/src/common.rs +++ b/smc_range_proof/src/common.rs @@ -32,11 +32,12 @@ impl MemberCommitmentKey { } } - /// Pedersen commitment to the set member + /// Pedersen commitment to the set member, `g * member + h * randomness` pub fn commit(&self, member: &G::ScalarField, randomness: &G::ScalarField) -> G { (self.g * member + self.h * randomness).into() } + /// Given `base`-ary representation of a value, commit to its `digits`, `g * (1 * digits[0] + base * digits[1] + base^2 * digits[2] + base^{n-1} * digits[n-1]) + h * randomness` pub fn commit_decomposed( &self, base: u16, @@ -47,6 +48,7 @@ impl MemberCommitmentKey { self.commit_decomposed_given_base_powers(&base_powers, digits, randomness) } + /// Same as `commit_decomposed` but takes `[1, base, base^2, ..., base^{n-1}]` pub fn commit_decomposed_given_base_powers( &self, base_powers: &[G::ScalarField], diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index 92117d9f..87d09473 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -6,16 +6,16 @@ authors.workspace = true license.workspace = true [dependencies] -bbs_plus = { version = "0.17.0", default-features = false, path = "../bbs_plus" } -schnorr_pok = { version = "0.15.0", default-features = false, path = "../schnorr_pok" } -vb_accumulator = { version = "0.18.0", default-features = false, path = "../vb_accumulator" } +bbs_plus = { version = "0.18.0", default-features = false, path = "../bbs_plus" } +schnorr_pok = { version = "0.16.0", default-features = false, path = "../schnorr_pok" } +vb_accumulator = { version = "0.19.0", default-features = false, path = "../vb_accumulator" } ark-ff.workspace = true ark-ec.workspace = true ark-std.workspace = true ark-bls12-381.workspace = true ark-serialize.workspace = true blake2.workspace = true -proof_system = { version = "0.23.0", default-features = false, path = "../proof_system"} +proof_system = { version = "0.24.0", default-features = false, path = "../proof_system"} [features] default = ["parallel"] diff --git a/vb_accumulator/Cargo.toml b/vb_accumulator/Cargo.toml index d9af2f8d..95226730 100644 --- a/vb_accumulator/Cargo.toml +++ b/vb_accumulator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vb_accumulator" -version = "0.18.0" +version = "0.19.0" edition.workspace = true authors.workspace = true license.workspace = true @@ -22,7 +22,7 @@ rayon = {workspace = true, optional = true} serde.workspace = true serde_with.workspace = true zeroize.workspace = true -schnorr_pok = { version = "0.15.0", default-features = false, path = "../schnorr_pok" } +schnorr_pok = { version = "0.16.0", default-features = false, path = "../schnorr_pok" } dock_crypto_utils = { version = "0.16.0", default-features = false, path = "../utils" } [dev-dependencies]