From 22ce978e2f47d76ff5b933c9a2090dbabda01fd8 Mon Sep 17 00:00:00 2001 From: onyinyang <10108092+onyiny-ang@users.noreply.github.com> Date: Mon, 23 Oct 2023 12:35:29 -0400 Subject: [PATCH 1/3] Update repo to use current dalek-cryptography dependencies --- Cargo.toml | 13 ++++--------- README.md | 9 --------- src/toolbox/batch_verifier.rs | 2 +- src/toolbox/verifier.rs | 2 +- tests/sig_and_vrf_example.rs | 2 +- tests/zkp.rs | 6 +++--- 6 files changed, 10 insertions(+), 24 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7a1c6ec..5723a4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,23 +18,18 @@ exclude = [ features = ["nightly"] [dependencies] -merlin = "2" -rand = "0.7" +merlin = "3" +rand = { version = "0.8", features = ["std"] } serde = "1" serde_derive = "1" thiserror = "1" # Disable default features to deselect a backend, then select one below -curve25519-dalek = { version = "2", default-features = false, features = ["serde", "std"] } +curve25519-dalek = { version = "4", default-features = false, features = ["serde", "rand_core", "alloc", "digest", "precomputed-tables"] } [dev-dependencies] bincode = "1" -sha2 = "0.8" +sha2 = "0.10" [features] -nightly = ["curve25519-dalek/nightly"] debug-transcript = ["merlin/debug-transcript"] bench = [] -default = ["u64_backend"] -u32_backend = ["curve25519-dalek/u32_backend"] -u64_backend = ["curve25519-dalek/u64_backend"] -simd_backend = ["curve25519-dalek/simd_backend"] diff --git a/README.md b/README.md index 8005057..0426eb6 100644 --- a/README.md +++ b/README.md @@ -64,15 +64,6 @@ extern crate zkp; The `nightly` feature enables nightly-specific features. It is required to build the documentation. -#### Backend selection - -`zkp` provides the following pass-through features to select a -`curve25519-dalek` backend: - -* `u32_backend` -* `u64_backend` -* `simd_backend` - #### Transcript debugging The `debug-transcript` feature is for development and testing, and diff --git a/src/toolbox/batch_verifier.rs b/src/toolbox/batch_verifier.rs index 8b99293..9fa25c9 100644 --- a/src/toolbox/batch_verifier.rs +++ b/src/toolbox/batch_verifier.rs @@ -170,7 +170,7 @@ impl<'a> BatchVerifier<'a> { let num_i = self.instance_points.len(); let num_c = self.constraints.len(); - let mut static_coeffs = vec![Scalar::zero(); num_s]; + let mut static_coeffs = vec![Scalar::ZERO; num_s]; let mut instance_coeffs = Matrix::::new(num_i + num_c, self.batch_size); for i in 0..num_c { diff --git a/src/toolbox/verifier.rs b/src/toolbox/verifier.rs index fe1ed2a..f0a2d54 100644 --- a/src/toolbox/verifier.rs +++ b/src/toolbox/verifier.rs @@ -144,7 +144,7 @@ impl<'a> Verifier<'a> { let commitments_offset = self.points.len(); let combined_points = self.points.iter().chain(proof.commitments.iter()); - let mut coeffs = vec![Scalar::zero(); self.points.len() + proof.commitments.len()]; + let mut coeffs = vec![Scalar::ZERO; self.points.len() + proof.commitments.len()]; // For each constraint of the form Q = sum(P_i, x_i), // we want to ensure Q_com = sum(P_i, resp_i) - c * Q, // so add the check rand*( sum(P_i, resp_i) - c * Q - Q_com ) == 0 diff --git a/tests/sig_and_vrf_example.rs b/tests/sig_and_vrf_example.rs index 0c95cd5..e9ef126 100644 --- a/tests/sig_and_vrf_example.rs +++ b/tests/sig_and_vrf_example.rs @@ -55,7 +55,7 @@ pub struct PublicKey(RistrettoPoint, CompressedRistretto); impl<'a> From<&'a SecretKey> for PublicKey { fn from(sk: &'a SecretKey) -> PublicKey { - let pk = &sk.0 * &dalek_constants::RISTRETTO_BASEPOINT_TABLE; + let pk = &sk.0 * dalek_constants::RISTRETTO_BASEPOINT_TABLE; PublicKey(pk, pk.compress()) } } diff --git a/tests/zkp.rs b/tests/zkp.rs index 3efe3ef..faee435 100644 --- a/tests/zkp.rs +++ b/tests/zkp.rs @@ -33,7 +33,7 @@ fn create_and_verify_compact() { let (proof, points) = { let H = RistrettoPoint::hash_from_bytes::(b"A VRF input, for instance"); let x = Scalar::from(89327492234u64).invert(); - let A = &x * &dalek_constants::RISTRETTO_BASEPOINT_TABLE; + let A = &x * dalek_constants::RISTRETTO_BASEPOINT_TABLE; let B = &x * &H; let mut transcript = Transcript::new(b"DLEQTest"); @@ -76,7 +76,7 @@ fn create_and_verify_batchable() { let (proof, points) = { let H = RistrettoPoint::hash_from_bytes::(b"A VRF input, for instance"); let x = Scalar::from(89327492234u64).invert(); - let A = &x * &dalek_constants::RISTRETTO_BASEPOINT_TABLE; + let A = &x * dalek_constants::RISTRETTO_BASEPOINT_TABLE; let B = &x * &H; let mut transcript = Transcript::new(b"DLEQTest"); @@ -129,7 +129,7 @@ fn create_batch_and_batch_verify() { for (i, message) in messages.iter().enumerate() { let H = RistrettoPoint::hash_from_bytes::(message.as_bytes()); let x = Scalar::from(89327492234u64) * Scalar::from((i + 1) as u64); - let A = &x * &dalek_constants::RISTRETTO_BASEPOINT_TABLE; + let A = &x * dalek_constants::RISTRETTO_BASEPOINT_TABLE; let B = &x * &H; let mut transcript = Transcript::new(b"DLEQTest"); From 8da38e1f094bc0b734d61c40f8aa39079ccd9f10 Mon Sep 17 00:00:00 2001 From: onyinyang <10108092+onyiny-ang@users.noreply.github.com> Date: Mon, 23 Oct 2023 12:35:30 -0400 Subject: [PATCH 2/3] Fix bug that occurs when public point is the identity --- src/macros.rs | 2 +- src/toolbox/verifier.rs | 15 ++++++ tests/vrf_public_zero.rs | 98 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 tests/vrf_public_zero.rs diff --git a/src/macros.rs b/src/macros.rs index 2e9524d..d7ab385 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -292,7 +292,7 @@ macro_rules! define_proof { let public_vars = PublicVars { $( - $instance_var: verifier.allocate_point( + $instance_var: verifier.allocate_public_point( TRANSCRIPT_LABELS.$instance_var.as_bytes(), *assignments.$instance_var, )?, diff --git a/src/toolbox/verifier.rs b/src/toolbox/verifier.rs index f0a2d54..6a233c2 100644 --- a/src/toolbox/verifier.rs +++ b/src/toolbox/verifier.rs @@ -62,6 +62,21 @@ impl<'a> Verifier<'a> { ScalarVar(self.num_scalars - 1) } + /// Attempt to allocate a public point variable, or fail verification if + /// the assignment is invalid. This function allows for public points being the identity. + pub fn allocate_public_point( + &mut self, + label: &'static [u8], + assignment: CompressedRistretto, + ) -> Result { + let encoding = assignment.decompress(); + self.transcript + .append_point_var(label, &encoding.unwrap()); + self.points.push(assignment); + self.point_labels.push(label); + Ok(PointVar(self.points.len() - 1)) + } + /// Attempt to allocate a point variable, or fail verification if /// the assignment is invalid. pub fn allocate_point( diff --git a/tests/vrf_public_zero.rs b/tests/vrf_public_zero.rs new file mode 100644 index 0000000..f711ee2 --- /dev/null +++ b/tests/vrf_public_zero.rs @@ -0,0 +1,98 @@ +// We really want points to be capital letters and scalars to be +// lowercase letters +#![allow(non_snake_case)] + +#[macro_use] +extern crate zkp; + +use curve25519_dalek::constants as dalek_constants; +use curve25519_dalek::ristretto::RistrettoPoint; +use curve25519_dalek::scalar::Scalar; + +use zkp::Transcript; + +define_proof! { + testproof, + "Test Proof", + (s, a, b, c), + (W, X, Y, Z), + (B): + Z = (s*B + a*W + b*X + c*Y) +} + +// Test the generation and verification of the proof where (W,X,Y) = +// (w*B, x*B, y*B) and B is the Ristretto generator. This situation +// comes up in the issuing protocol of CMZ14 credentials, where w, x, +// and y are the (public) attributes on the credential being issued. +pub fn test_issue(w: &Scalar, x: &Scalar, y: &Scalar) { + let B: RistrettoPoint = dalek_constants::RISTRETTO_BASEPOINT_POINT; + + // Public points based on the public attributes + let (W, X, Y) = (w*B, x*B, y*B); + + let mut rng = rand::thread_rng(); + // Private coefficients (the prover's MAC key) + let a = Scalar::random(&mut rng); + let b = Scalar::random(&mut rng); + let c = Scalar::random(&mut rng); + let s = Scalar::random(&mut rng); + + // (Part of the) public MAC + let Z = s*B + a*W + b*X + c*Y; + + // Construct the proof + let mut prv_transcript = Transcript::new(b"test transcript"); + let pi = testproof::prove_compact( + &mut prv_transcript, + testproof::ProveAssignments { + B: &B, + W: &W, + X: &X, + Y: &Y, + Z: &Z, + a: &a, + b: &b, + c: &c, + s: &s, + }, + ) + .0; + + // Send (Z, pi) to the verifier + + // The verifier will recompute W, Y, Z as above and then verify: + + let mut vrf_transcript = Transcript::new(b"test transcript"); + let result = testproof::verify_compact( + &pi, + &mut vrf_transcript, + testproof::VerifyAssignments { + B: &B.compress(), + W: &W.compress(), + X: &X.compress(), + Y: &Y.compress(), + Z: &Z.compress(), + }, + ); + + assert!(result.is_ok()); +} + +#[test] +fn test_nozero() { + let mut rng = rand::thread_rng(); + let w = Scalar::random(&mut rng); + let x = Scalar::random(&mut rng); + let y = Scalar::random(&mut rng); + test_issue(&w, &x, &y); +} + +#[test] +fn test_zero() { + let mut rng = rand::thread_rng(); + let w = Scalar::random(&mut rng); + let x = Scalar::ZERO; + let y = Scalar::random(&mut rng); + test_issue(&w, &x, &y); +} + From d45bb2eb6bd14a7c99a846cdb6fb41f3f3a703df Mon Sep 17 00:00:00 2001 From: onyinyang <10108092+onyiny-ang@users.noreply.github.com> Date: Mon, 23 Oct 2023 12:35:30 -0400 Subject: [PATCH 3/3] Update changelog with changes from previous commits --- CHANGELOG.md | 8 ++++++++ Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dc4574..991a50f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ Entries are listed in reverse chronological order. +## 0.8.0 +* update `curve25519-dalek` dependency to 4.0 +* update `merlin` dependency to 3 +* update `rand` dependency to 0.8 +* update `sha2` dependency to 0.10 +* remove backend features to be consistent with upstream dalek-cryptography +* fix bug that occurs when public point is the identity + ## 0.7.0 * Update `curve25519-dalek`, `merlin` dependencies to 2.0. diff --git a/Cargo.toml b/Cargo.toml index 5723a4f..e14ea30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zkp" -version = "0.7.0" +version = "0.8.0" authors = ["Henry de Valence "] edition = "2018" license = "CC0-1.0"