From 10b3e562c142d80d445fc039d09cc6ef77bf908c Mon Sep 17 00:00:00 2001 From: Joe Rowell Date: Wed, 30 Aug 2023 16:59:25 +0100 Subject: [PATCH 1/7] Add the ability to make Pedersen commitments. --- Cargo.toml | 1 + src/pedersen/Cargo.toml | 15 ++++++++++++ src/pedersen/src/lib.rs | 38 +++++++++++++++++++++++++++++ src/pedersen/src/pedersen_config.rs | 10 ++++++++ src/t256/Cargo.toml | 2 ++ src/t256/src/curves/mod.rs | 15 ++++++++++++ src/t256/src/curves/tests.rs | 18 +++++++++++++- src/t384/Cargo.toml | 1 + src/t384/src/curves/mod.rs | 14 +++++++++-- src/t384/src/curves/tests.rs | 18 +++++++++++++- src/t384/src/lib.rs | 1 + 11 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 src/pedersen/Cargo.toml create mode 100644 src/pedersen/src/lib.rs create mode 100644 src/pedersen/src/pedersen_config.rs diff --git a/Cargo.toml b/Cargo.toml index a7cc349..81241b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ resolver = "2" merlin = "3.0.0" t256 = { path = "src/t256" } t384 = { path = "src/t384" } +pedersen = { path = "src/pedersen" } [profile.release] opt-level = 3 diff --git a/src/pedersen/Cargo.toml b/src/pedersen/Cargo.toml new file mode 100644 index 0000000..7c11703 --- /dev/null +++ b/src/pedersen/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "pedersen" +version = "0.0.1-alpha.1" +description = "A package implementing Pedersen Commitments" +include = ["Cargo.toml", "src"] +edition = "2021" + +[dependencies] +ark-ec = { version = "0.4.0", default-features = false } +ark-std = { version = "0.4.0", default-features = false } +rand = { version = "0.8.5" } +ark-ff = { version = "0.4.0"} +ark-serialize = { version = "0.4.0"} + + diff --git a/src/pedersen/src/lib.rs b/src/pedersen/src/lib.rs new file mode 100644 index 0000000..fe134c2 --- /dev/null +++ b/src/pedersen/src/lib.rs @@ -0,0 +1,38 @@ +#![forbid(unsafe_code)] + +use ark_ec::{ + CurveConfig, + CurveGroup, + short_weierstrass::{self as sw, SWCurveConfig}, +}; + +use ark_std::{UniformRand, ops::Mul}; + +use rand::RngCore; + +pub trait PedersenConfig : CurveConfig + SWCurveConfig { + /// Second generator that's used in Pedersen commitments. + const GENERATOR2: sw::Affine; +} + +pub struct PedersenComm { + pub x_comm: sw::Affine

, + pub x_r:

::ScalarField, + pub y_comm: sw::Affine

, + pub y_r:

::ScalarField +} + +impl PedersenComm

{ + pub fn new (x:

::ScalarField, y:

::ScalarField, rng: &mut dyn RngCore) -> Self { + let x_r =

::ScalarField::rand(rng); + let y_r =

::ScalarField::rand(rng); + + let x_p =

::GENERATOR.mul(x) + P::GENERATOR2.mul(x_r); + let y_p =

::GENERATOR.mul(y) + P::GENERATOR2.mul(y_r); + + Self {x_comm: x_p.into_affine(), x_r: x_r, y_comm: y_p.into_affine(), y_r: y_r} + } +} + + + diff --git a/src/pedersen/src/pedersen_config.rs b/src/pedersen/src/pedersen_config.rs new file mode 100644 index 0000000..3dad022 --- /dev/null +++ b/src/pedersen/src/pedersen_config.rs @@ -0,0 +1,10 @@ +use ark_ec::{ + models::CurveConfig, + short_weierstrass::{self as sw, SWCurveConfig}, +}; + +pub trait PedersenConfig : SWCurveConfig { + /// Second generator that's used in Pedersen commitments. + const GENERATOR2: sw::Affine; +} + diff --git a/src/t256/Cargo.toml b/src/t256/Cargo.toml index 307671a..7a5b259 100644 --- a/src/t256/Cargo.toml +++ b/src/t256/Cargo.toml @@ -10,6 +10,8 @@ ark-ff = { version = "0.4.0", default-features = false } ark-ec = { version = "0.4.0", default-features = false } ark-r1cs-std = { version = "0.4.0", default-features = false, optional = true } ark-std = { version = "0.4.0", default-features = false } +pedersen = { path="../pedersen" } +rand = { version = "0.8.5" } [dev-dependencies] ark-relations = { version = "0.4.0", default-features = false } diff --git a/src/t256/src/curves/mod.rs b/src/t256/src/curves/mod.rs index 3b4c502..2049135 100644 --- a/src/t256/src/curves/mod.rs +++ b/src/t256/src/curves/mod.rs @@ -3,6 +3,8 @@ use ark_ec::{ short_weierstrass::{self as sw, SWCurveConfig}, }; +use pedersen::PedersenConfig; + use ark_ff::{Field, MontFp}; use crate::{fq::Fq, fr::Fr}; @@ -41,13 +43,26 @@ impl SWCurveConfig for Config { const GENERATOR : Affine = Affine::new_unchecked(G_GENERATOR_X, G_GENERATOR_Y); } +impl PedersenConfig for Config { + /// GENERATOR2 = (G_GENERATOR_X2, G_GENERATOR_Y2) + const GENERATOR2 : Affine = Affine::new_unchecked(G_GENERATOR_X2, G_GENERATOR_Y2); +} + + + + /// G_GENERATOR_X = 3 pub const G_GENERATOR_X : Fq = MontFp!("3"); /// G_GENERATOR_Y = 40902200210088653215032584946694356296222563095503428277299570638400093548589 pub const G_GENERATOR_Y : Fq = MontFp!("40902200210088653215032584946694356296222563095503428277299570638400093548589"); +/// G_GENERATOR_X2 = 5 +pub const G_GENERATOR_X2 : Fq = MontFp!("5"); + +/// G_GENERATOR_Y2 = 28281484859698624956664858566852274012236038028101624500031073655422126514829 +pub const G_GENERATOR_Y2 : Fq = MontFp!("28281484859698624956664858566852274012236038028101624500031073655422126514829"); diff --git a/src/t256/src/curves/tests.rs b/src/t256/src/curves/tests.rs index 10ca142..883b49a 100644 --- a/src/t256/src/curves/tests.rs +++ b/src/t256/src/curves/tests.rs @@ -1,3 +1,19 @@ -use crate::Projective; +use crate::{Projective, Config}; use ark_algebra_test_templates::*; +use ark_std::{UniformRand}; +use ark_ec::{CurveConfig}; +use pedersen::{PedersenComm}; + test_group!(g1; Projective; sw); + +type PC = PedersenComm; + +#[test] +fn test_pedersen() { + let mut rng = ark_std::test_rng(); + let a = ::ScalarField::rand(&mut rng); + let b = ::ScalarField::rand(&mut rng); + let c : PC = PC::new(a, b, &mut rng); + assert!(c.x_comm.is_on_curve()); + assert!(c.y_comm.is_on_curve()); +} diff --git a/src/t384/Cargo.toml b/src/t384/Cargo.toml index 79a4d24..0a6bd2e 100644 --- a/src/t384/Cargo.toml +++ b/src/t384/Cargo.toml @@ -10,6 +10,7 @@ ark-ff = { version = "0.4.0", default-features = false } ark-ec = { version = "0.4.0", default-features = false } ark-r1cs-std = { version = "0.4.0", default-features = false, optional = true } ark-std = { version = "0.4.0", default-features = false } +pedersen = { path = "../pedersen" } [dev-dependencies] ark-relations = { version = "0.4.0", default-features = false } diff --git a/src/t384/src/curves/mod.rs b/src/t384/src/curves/mod.rs index 45cf139..03bd6aa 100644 --- a/src/t384/src/curves/mod.rs +++ b/src/t384/src/curves/mod.rs @@ -3,6 +3,8 @@ use ark_ec::{ short_weierstrass::{self as sw, SWCurveConfig}, }; +use pedersen::PedersenConfig; + use ark_ff::{Field, MontFp}; use crate::{fq::Fq, fr::Fr}; @@ -41,13 +43,21 @@ impl SWCurveConfig for Config { const GENERATOR : Affine = Affine::new_unchecked(G_GENERATOR_X, G_GENERATOR_Y); } +impl PedersenConfig for Config { + /// GENERATOR2 = (G_GENERATOR_X2, G_GENERATOR_Y2) + const GENERATOR2: Affine = Affine::new_unchecked(G_GENERATOR_X2, G_GENERATOR_Y2); +} + + /// G_GENERATOR_X = 18624522857557105898096886988538082729570911703609840597859472552101056293848159295245991160598223034723589185598549 pub const G_GENERATOR_X : Fq = MontFp!("18624522857557105898096886988538082729570911703609840597859472552101056293848159295245991160598223034723589185598549"); /// G_GENERATOR_Y = 16812635070577401701780555151784939373443796894181112771346367209071849423738982329774175396215506669421943316852710 pub const G_GENERATOR_Y : Fq = MontFp!("16812635070577401701780555151784939373443796894181112771346367209071849423738982329774175396215506669421943316852710"); +/// G_GENERATOR_X2 = 5 +pub const G_GENERATOR_X2 : Fq = MontFp!("5"); - - +/// G_GENERATOR_Y2 = 6363885786003242131136944941369369468464707802299146445548164183900284786157464900151666199152091187308687891798230 +pub const G_GENERATOR_Y2 : Fq = MontFp!("6363885786003242131136944941369369468464707802299146445548164183900284786157464900151666199152091187308687891798230"); diff --git a/src/t384/src/curves/tests.rs b/src/t384/src/curves/tests.rs index 10ca142..883b49a 100644 --- a/src/t384/src/curves/tests.rs +++ b/src/t384/src/curves/tests.rs @@ -1,3 +1,19 @@ -use crate::Projective; +use crate::{Projective, Config}; use ark_algebra_test_templates::*; +use ark_std::{UniformRand}; +use ark_ec::{CurveConfig}; +use pedersen::{PedersenComm}; + test_group!(g1; Projective; sw); + +type PC = PedersenComm; + +#[test] +fn test_pedersen() { + let mut rng = ark_std::test_rng(); + let a = ::ScalarField::rand(&mut rng); + let b = ::ScalarField::rand(&mut rng); + let c : PC = PC::new(a, b, &mut rng); + assert!(c.x_comm.is_on_curve()); + assert!(c.y_comm.is_on_curve()); +} diff --git a/src/t384/src/lib.rs b/src/t384/src/lib.rs index ff57fa7..30c8dcb 100644 --- a/src/t384/src/lib.rs +++ b/src/t384/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] +#![deny(nonstandard_style)] #![forbid(unsafe_code)] //! This library implements the 384-bit prime order curve used inside ZKAttest. From 4caf97335e74f1f571abe75ecb3a6adb8eff0392 Mon Sep 17 00:00:00 2001 From: Joe Rowell Date: Thu, 31 Aug 2023 13:38:24 +0100 Subject: [PATCH 2/7] Add basic proof classes. Features: 1. Equality proofs for Pedersen commitments. 2. Opening proofs for scalars. 3. Multiplication proofs for scalars. --- src/pedersen/Cargo.toml | 3 +- src/pedersen/src/equality_protocol.rs | 77 +++++++++++++++++ src/pedersen/src/lib.rs | 42 ++-------- src/pedersen/src/mul_protocol.rs | 113 +++++++++++++++++++++++++ src/pedersen/src/opening_protocol.rs | 76 +++++++++++++++++ src/pedersen/src/pedersen_config.rs | 17 ++++ src/pedersen/src/transcript.rs | 89 ++++++++++++++++++++ src/t256/Cargo.toml | 2 + src/t256/src/curves/mod.rs | 2 +- src/t256/src/curves/tests.rs | 116 ++++++++++++++++++++++++-- src/t384/Cargo.toml | 3 + src/t384/src/curves/mod.rs | 2 +- src/t384/src/curves/tests.rs | 116 ++++++++++++++++++++++++-- 13 files changed, 603 insertions(+), 55 deletions(-) create mode 100644 src/pedersen/src/equality_protocol.rs create mode 100644 src/pedersen/src/mul_protocol.rs create mode 100644 src/pedersen/src/opening_protocol.rs create mode 100644 src/pedersen/src/transcript.rs diff --git a/src/pedersen/Cargo.toml b/src/pedersen/Cargo.toml index 7c11703..2e50596 100644 --- a/src/pedersen/Cargo.toml +++ b/src/pedersen/Cargo.toml @@ -11,5 +11,4 @@ ark-std = { version = "0.4.0", default-features = false } rand = { version = "0.8.5" } ark-ff = { version = "0.4.0"} ark-serialize = { version = "0.4.0"} - - +merlin = { version = "3.0.0"} diff --git a/src/pedersen/src/equality_protocol.rs b/src/pedersen/src/equality_protocol.rs new file mode 100644 index 0000000..615df36 --- /dev/null +++ b/src/pedersen/src/equality_protocol.rs @@ -0,0 +1,77 @@ +//! Defines an Equality protocol for various PedersenConfig types. + +use merlin::Transcript; +use ark_ec::{ + CurveConfig, + CurveGroup, + short_weierstrass::{self as sw}, +}; + +use ark_serialize::{CanonicalSerialize, CanonicalDeserialize}; + +use ark_std::{UniformRand, ops::Mul}; +use rand::{RngCore, CryptoRng}; + +use crate::{transcript::EqualityTranscript, pedersen_config::PedersenConfig, pedersen_config::PedersenComm}; + +pub struct EqualityProof { + pub alpha: sw::Affine

, + pub z :

::ScalarField, +} + +impl EqualityProof

{ + + fn make_transcript(transcript: &mut Transcript, + c1: &PedersenComm

, + c2: &PedersenComm

, + alpha_p: &sw::Affine

) { + // This function just builds the transcript for both the create and verify functions. + // N.B Because of how we define the serialisation API to handle different numbers, + // we use a temporary buffer here. + transcript.domain_sep(); + let mut compressed_bytes = Vec::new(); + c1.comm.serialize_compressed(&mut compressed_bytes).unwrap(); + transcript.append_point(b"C1", &compressed_bytes[..]); + + c2.comm.serialize_compressed(&mut compressed_bytes).unwrap(); + transcript.append_point(b"C2", &compressed_bytes[..]); + + alpha_p.serialize_compressed(&mut compressed_bytes).unwrap(); + transcript.append_point(b"alpha", &compressed_bytes[..]); + } + + fn make_challenge(transcript: &mut Transcript) ->

::ScalarField { +

::ScalarField::deserialize_compressed(&transcript.challenge_scalar(b"c")[..]).unwrap() + } + + + pub fn create(transcript: &mut Transcript, + rng: &mut T, + c1: &PedersenComm

, + c2: &PedersenComm

) -> EqualityProof

{ + + let r =

::ScalarField::rand(rng); + let alpha = P::GENERATOR2.mul(r).into_affine(); + Self::make_transcript(transcript, c1, c2, &alpha); + + // Now make the challenge. + let chal = Self::make_challenge(transcript); + + let z = chal * (c1.r - c2.r) + r; + EqualityProof { + alpha: alpha, + z: z + } + } + + pub fn verify(&self, transcript: &mut Transcript, c1: &PedersenComm

, c2: &PedersenComm

) -> bool { + // Make the transcript. + Self::make_transcript(transcript, c1, c2, &self.alpha); + + // Now make the challenge and check. + let chal = Self::make_challenge(transcript); + + P::GENERATOR2.mul(self.z) == (c1.comm - c2.comm).mul(chal) + self.alpha + } +} + diff --git a/src/pedersen/src/lib.rs b/src/pedersen/src/lib.rs index fe134c2..197bfe6 100644 --- a/src/pedersen/src/lib.rs +++ b/src/pedersen/src/lib.rs @@ -1,38 +1,6 @@ #![forbid(unsafe_code)] - -use ark_ec::{ - CurveConfig, - CurveGroup, - short_weierstrass::{self as sw, SWCurveConfig}, -}; - -use ark_std::{UniformRand, ops::Mul}; - -use rand::RngCore; - -pub trait PedersenConfig : CurveConfig + SWCurveConfig { - /// Second generator that's used in Pedersen commitments. - const GENERATOR2: sw::Affine; -} - -pub struct PedersenComm { - pub x_comm: sw::Affine

, - pub x_r:

::ScalarField, - pub y_comm: sw::Affine

, - pub y_r:

::ScalarField -} - -impl PedersenComm

{ - pub fn new (x:

::ScalarField, y:

::ScalarField, rng: &mut dyn RngCore) -> Self { - let x_r =

::ScalarField::rand(rng); - let y_r =

::ScalarField::rand(rng); - - let x_p =

::GENERATOR.mul(x) + P::GENERATOR2.mul(x_r); - let y_p =

::GENERATOR.mul(y) + P::GENERATOR2.mul(y_r); - - Self {x_comm: x_p.into_affine(), x_r: x_r, y_comm: y_p.into_affine(), y_r: y_r} - } -} - - - +pub mod transcript; +pub mod equality_protocol; +pub mod opening_protocol; +pub mod mul_protocol; +pub mod pedersen_config; diff --git a/src/pedersen/src/mul_protocol.rs b/src/pedersen/src/mul_protocol.rs new file mode 100644 index 0000000..0b9ca08 --- /dev/null +++ b/src/pedersen/src/mul_protocol.rs @@ -0,0 +1,113 @@ +//! Defines a protocol for proof of multiplication. +//! That is, let p be a prime and let x, y be two values in F_p. +//! This protocol proves that C_3 is a Pedersen commitment to z = x * y (over F_p) + +use merlin::Transcript; +use ark_ec::{ + CurveConfig, + CurveGroup, + short_weierstrass::{self as sw}, +}; + +use ark_serialize::{CanonicalSerialize, CanonicalDeserialize}; +use ark_std::{UniformRand, ops::Mul}; +use rand::{RngCore, CryptoRng}; + +use crate::{transcript::MulTranscript, pedersen_config::PedersenConfig, pedersen_config::PedersenComm}; + +pub struct MulProof { + pub alpha: sw::Affine

, + pub beta: sw::Affine

, + pub delta: sw::Affine

, + + pub z1:

::ScalarField, + pub z2:

::ScalarField, + pub z3:

::ScalarField, + pub z4:

::ScalarField, + pub z5:

::ScalarField, +} + +impl MulProof

{ + + fn make_transcript(transcript: &mut Transcript, + c1: &PedersenComm

, + c2: &PedersenComm

, + c3: &PedersenComm

, + alpha: &sw::Affine

, + beta: &sw::Affine

, + delta: &sw::Affine

) { + + // This function just builds the transcript out of the various input values. + // N.B Because of how we define the serialisation API to handle different numbers, + // we use a temporary buffer here. + transcript.domain_sep(); + let mut compressed_bytes = Vec::new(); + c1.comm.serialize_compressed(&mut compressed_bytes).unwrap(); + transcript.append_point(b"C1", &compressed_bytes[..]); + + c2.comm.serialize_compressed(&mut compressed_bytes).unwrap(); + transcript.append_point(b"C2", &compressed_bytes[..]); + + c3.comm.serialize_compressed(&mut compressed_bytes).unwrap(); + transcript.append_point(b"C3", &compressed_bytes[..]); + + alpha.serialize_compressed(&mut compressed_bytes).unwrap(); + transcript.append_point(b"alpha", &compressed_bytes[..]); + + beta.serialize_compressed(&mut compressed_bytes).unwrap(); + transcript.append_point(b"beta", &compressed_bytes[..]); + + delta.serialize_compressed(&mut compressed_bytes).unwrap(); + transcript.append_point(b"delta", &compressed_bytes[..]); + } + + + fn make_challenge(transcript: &mut Transcript) ->

::ScalarField { +

::ScalarField::deserialize_compressed(&transcript.challenge_scalar(b"c")[..]).unwrap() + } + + pub fn create(transcript: &mut Transcript, + rng: &mut T, + x:

::ScalarField, + y:

::ScalarField, + c1: &PedersenComm

, + c2: &PedersenComm

, + c3: &PedersenComm

) -> Self { + + // Generate the random values. + let b1 =

::ScalarField::rand(rng); + let b2 =

::ScalarField::rand(rng); + let b3 =

::ScalarField::rand(rng); + let b4 =

::ScalarField::rand(rng); + let b5 =

::ScalarField::rand(rng); + + let alpha = (P::GENERATOR.mul(b1) + P::GENERATOR2.mul(b2)).into_affine(); + let beta = (P::GENERATOR.mul(b3) + P::GENERATOR2.mul(b4)).into_affine(); + let delta = (c1.comm.mul(b3) + P::GENERATOR2.mul(b5)).into_affine(); + + Self::make_transcript(transcript, c1, c2, c3, &alpha, &beta, &delta); + + // Now make the challenge. + let chal = Self::make_challenge(transcript); + + Self { + alpha: alpha, + beta: beta, + delta: delta, + z1: b1 + (chal * (x)), + z2: b2 + (chal * c1.r), + z3: b3 + (chal * (y)), + z4: b4 + (chal * c2.r), + z5: b5 + chal * (c3.r - (c1.r*(y))) + } + } + + pub fn verify(&self, transcript: &mut Transcript, c1: &PedersenComm

, c2: &PedersenComm

, c3: &PedersenComm

) -> bool { + Self::make_transcript(transcript, c1, c2, c3, &self.alpha, &self.beta, &self.delta); + let chal = Self::make_challenge(transcript); + + (self.alpha + c1.comm.mul(chal) == P::GENERATOR.mul(self.z1) + P::GENERATOR2.mul(self.z2)) && + (self.beta + c2.comm.mul(chal) == P::GENERATOR.mul(self.z3) + P::GENERATOR2.mul(self.z4)) && + (self.delta + c3.comm.mul(chal) == c1.comm.mul(self.z3) + P::GENERATOR2.mul(self.z5)) + } +} diff --git a/src/pedersen/src/opening_protocol.rs b/src/pedersen/src/opening_protocol.rs new file mode 100644 index 0000000..280b25b --- /dev/null +++ b/src/pedersen/src/opening_protocol.rs @@ -0,0 +1,76 @@ +//! Defines an Opening protocol for various PedersenConfig types. +//! That is, this protocol proves knowledge of a value x such that +//! C_0 = g^{x}h^{r} for a Pedersen Commitment C_0 with known generators `g`, `h` and +//! randomness `r`. + +use merlin::Transcript; +use ark_ec::{ + CurveConfig, + CurveGroup, + short_weierstrass::{self as sw}, +}; + +use ark_serialize::{CanonicalSerialize, CanonicalDeserialize}; +use ark_std::{UniformRand, ops::Mul}; +use rand::{RngCore, CryptoRng}; + +use crate::{transcript::OpeningTranscript, pedersen_config::PedersenConfig, pedersen_config::PedersenComm}; + +pub struct OpeningProof { + pub alpha: sw::Affine

, + pub z1:

::ScalarField, + pub z2:

::ScalarField, +} + +impl OpeningProof

{ + + fn make_transcript(transcript: &mut Transcript, + c1: &PedersenComm

, + alpha_p: &sw::Affine

) { + + // This function just builds the transcript out of the various input values. + // N.B Because of how we define the serialisation API to handle different numbers, + // we use a temporary buffer here. + transcript.domain_sep(); + let mut compressed_bytes = Vec::new(); + c1.comm.serialize_compressed(&mut compressed_bytes).unwrap(); + transcript.append_point(b"C1", &compressed_bytes[..]); + + alpha_p.serialize_compressed(&mut compressed_bytes).unwrap(); + transcript.append_point(b"alpha", &compressed_bytes[..]); + } + + fn make_challenge(transcript: &mut Transcript) ->

::ScalarField { +

::ScalarField::deserialize_compressed(&transcript.challenge_scalar(b"c")[..]).unwrap() + } + + pub fn create(transcript: &mut Transcript, + rng: &mut T, + x: &

::ScalarField, + c1: &PedersenComm

) -> Self { + + let t1 =

::ScalarField::rand(rng); + let t2 =

::ScalarField::rand(rng); + let alpha = (P::GENERATOR.mul(t1) + P::GENERATOR2.mul(t2)).into_affine(); + Self::make_transcript(transcript, c1, &alpha); + + // Now make the challenge. + let chal = Self::make_challenge(transcript); + + OpeningProof { + alpha: alpha, + z1: *x*chal + t1, + z2: c1.r * chal + t2 + } + } + + pub fn verify(&self, transcript: &mut Transcript, c1: &PedersenComm

) -> bool { + // Make the transcript. + Self::make_transcript(transcript, c1, &self.alpha); + + // Now make the challenge and check. + let chal = Self::make_challenge(transcript); + + P::GENERATOR.mul(self.z1) + P::GENERATOR2.mul(self.z2) == c1.comm.mul(chal) + self.alpha + } +} diff --git a/src/pedersen/src/pedersen_config.rs b/src/pedersen/src/pedersen_config.rs index 3dad022..d8e9adf 100644 --- a/src/pedersen/src/pedersen_config.rs +++ b/src/pedersen/src/pedersen_config.rs @@ -1,10 +1,27 @@ use ark_ec::{ models::CurveConfig, short_weierstrass::{self as sw, SWCurveConfig}, + CurveGroup, }; +use ark_std::{UniformRand, ops::Mul}; +use rand::{RngCore, CryptoRng}; + pub trait PedersenConfig : SWCurveConfig { /// Second generator that's used in Pedersen commitments. const GENERATOR2: sw::Affine; } +pub struct PedersenComm { + pub comm: sw::Affine

, + pub r:

::ScalarField, +} + +impl PedersenComm

{ + pub fn new (x:

::ScalarField, rng: &mut T) -> Self { + let x_r =

::ScalarField::rand(rng); + let x_p =

::GENERATOR.mul(x) + P::GENERATOR2.mul(x_r); + Self {comm: x_p.into_affine(), r: x_r } + } +} + diff --git a/src/pedersen/src/transcript.rs b/src/pedersen/src/transcript.rs new file mode 100644 index 0000000..673994a --- /dev/null +++ b/src/pedersen/src/transcript.rs @@ -0,0 +1,89 @@ +//! Declares a series of transcript types for Merlin transcripts. +//! WARNING: This trait differs slightly from how Merlin defines the same traits. Essentially, rather than +//! re-instantiating this type for each different point type that we use, we simply traffic bytes in and out for e.g +//! appending points or producing challenges. It is the responsibility of the caller to realise this functionality. + +use merlin::Transcript; + +pub trait EqualityTranscript { + /// Append a domain separator. + fn domain_sep(&mut self); + + /// Append a point. + fn append_point(&mut self, label: &'static[u8], point: &[u8]); + + /// Produce the challenge. + fn challenge_scalar(&mut self, label: &'static[u8]) -> [u8; 64]; +} + +impl EqualityTranscript for Transcript { + fn domain_sep(&mut self) { + self.append_message(b"dom-sep", b"equality-proof") + } + + fn append_point(&mut self, label: &'static[u8], point: &[u8]) { + self.append_message(label, point); + } + + fn challenge_scalar(&mut self, label: &'static[u8]) -> [u8; 64] { + let mut buf = [0u8; 64]; + self.challenge_bytes(label, &mut buf); + buf + } +} + + +pub trait OpeningTranscript { + /// Append a domain separator. + fn domain_sep(&mut self); + + /// Append a point. + fn append_point(&mut self, label: &'static[u8], point: &[u8]); + + /// Produce the challenge. + fn challenge_scalar(&mut self, label: &'static[u8]) -> [u8; 64]; +} + +impl OpeningTranscript for Transcript { + fn domain_sep(&mut self) { + self.append_message(b"dom-sep", b"open-proof") + } + + fn append_point(&mut self, label: &'static[u8], point: &[u8]) { + self.append_message(label, point); + } + + fn challenge_scalar(&mut self, label: &'static[u8]) -> [u8; 64] { + let mut buf = [0u8; 64]; + self.challenge_bytes(label, &mut buf); + buf + } +} + +pub trait MulTranscript { + /// Append a domain separator. + fn domain_sep(&mut self); + + /// Append a point. + fn append_point(&mut self, label: &'static[u8], point: &[u8]); + + /// Produce the challenge. + fn challenge_scalar(&mut self, label: &'static[u8]) -> [u8; 64]; +} + +impl MulTranscript for Transcript { + fn domain_sep(&mut self) { + self.append_message(b"dom-sep", b"mul-proof") + } + + fn append_point(&mut self, label: &'static[u8], point: &[u8]) { + self.append_message(label, point); + } + + fn challenge_scalar(&mut self, label: &'static[u8]) -> [u8; 64] { + let mut buf = [0u8; 64]; + self.challenge_bytes(label, &mut buf); + buf + } +} + diff --git a/src/t256/Cargo.toml b/src/t256/Cargo.toml index 7a5b259..44d5515 100644 --- a/src/t256/Cargo.toml +++ b/src/t256/Cargo.toml @@ -12,6 +12,8 @@ ark-r1cs-std = { version = "0.4.0", default-features = false, optional = true } ark-std = { version = "0.4.0", default-features = false } pedersen = { path="../pedersen" } rand = { version = "0.8.5" } +rand_core = { version = "0.6.4" } +merlin = { version = "3.0.0" } [dev-dependencies] ark-relations = { version = "0.4.0", default-features = false } diff --git a/src/t256/src/curves/mod.rs b/src/t256/src/curves/mod.rs index 2049135..9e4e2a6 100644 --- a/src/t256/src/curves/mod.rs +++ b/src/t256/src/curves/mod.rs @@ -3,7 +3,7 @@ use ark_ec::{ short_weierstrass::{self as sw, SWCurveConfig}, }; -use pedersen::PedersenConfig; +use pedersen::pedersen_config::PedersenConfig; use ark_ff::{Field, MontFp}; diff --git a/src/t256/src/curves/tests.rs b/src/t256/src/curves/tests.rs index 883b49a..241e0ee 100644 --- a/src/t256/src/curves/tests.rs +++ b/src/t256/src/curves/tests.rs @@ -2,7 +2,10 @@ use crate::{Projective, Config}; use ark_algebra_test_templates::*; use ark_std::{UniformRand}; use ark_ec::{CurveConfig}; -use pedersen::{PedersenComm}; + +use pedersen::{pedersen_config::PedersenComm, equality_protocol::EqualityProof as EP, opening_protocol::OpeningProof as OP, mul_protocol::MulProof as MP}; +use rand_core::OsRng; +use merlin::Transcript; test_group!(g1; Projective; sw); @@ -10,10 +13,109 @@ type PC = PedersenComm; #[test] fn test_pedersen() { - let mut rng = ark_std::test_rng(); - let a = ::ScalarField::rand(&mut rng); - let b = ::ScalarField::rand(&mut rng); - let c : PC = PC::new(a, b, &mut rng); - assert!(c.x_comm.is_on_curve()); - assert!(c.y_comm.is_on_curve()); + // Test that committing to a random point works. + let a = ::ScalarField::rand(&mut OsRng); + let c : PC = PC::new(a, &mut OsRng); + assert!(c.comm.is_on_curve()); +} + +#[test] +fn test_pedersen_equality() { + // Test that the equality proof goes through. + let label = b"PedersenEq"; + + let a = ::ScalarField::rand(&mut OsRng); + let c1 : PC = PC::new(a, &mut OsRng); + let c2 : PC = PC::new(a, &mut OsRng); + + let mut transcript = Transcript::new(label); + + // Build the proof. + let proof = EP::create(&mut transcript, &mut OsRng, &c1, &c2); + assert!(proof.alpha.is_on_curve()); + + // Make a new transcript and use that to verify. + let mut transcript_v = Transcript::new(label); + + // Now check that the proof verifies properly. + assert!(proof.verify(&mut transcript_v, &c1, &c2)); + + // Alternatively, check that a different proof would fail. + let mut b = ::ScalarField::rand(&mut OsRng); + + loop { + if b != a { break; } + b = ::ScalarField::rand(&mut OsRng); + } + + let c3 : PC = PC::new(b, &mut OsRng); + let mut transcript_f = Transcript::new(label); + assert!(!proof.verify(&mut transcript_f, &c1, &c3)); +} + +#[test] +fn test_pedersen_opening() { + // Test that the opening proof goes through. + let label = b"PedersenOpen"; + + let a = ::ScalarField::rand(&mut OsRng); + let c1 : PC = PC::new(a, &mut OsRng); + let mut transcript = Transcript::new(label); + + let proof = OP::create(&mut transcript, &mut OsRng, &a, &c1); + assert!(proof.alpha.is_on_curve()); + + // Now check that the proof verifies correctly. + let mut transcript_v = Transcript::new(label); + assert!(proof.verify(&mut transcript_v, &c1)); + + // Now check that an unrelated commitment would fail. + // Alternatively, check that a different proof would fail. + let mut b = ::ScalarField::rand(&mut OsRng); + + loop { + if b != a { break; } + b = ::ScalarField::rand(&mut OsRng); + } + + let c3 : PC = PC::new(b, &mut OsRng); + let mut transcript_f = Transcript::new(label); + assert!(!proof.verify(&mut transcript_f, &c3)); +} + +#[test] +fn test_pedersen_mul() { + // Test that the mul proof goes through. + let label = b"PedersenMul"; + + let a = ::ScalarField::rand(&mut OsRng); + let b = ::ScalarField::rand(&mut OsRng); + let z = a * b; + + let c1 : PC = PC::new(a, &mut OsRng); + let c2 : PC = PC::new(b, &mut OsRng); + let c3 : PC = PC::new(z, &mut OsRng); + + let mut transcript = Transcript::new(label); + let proof = MP::create(&mut transcript, &mut OsRng, a, b, &c1, &c2, &c3); + assert!(proof.alpha.is_on_curve()); + assert!(proof.beta.is_on_curve()); + assert!(proof.delta.is_on_curve()); + + // Now check that the proof verifies. + let mut transcript_v = Transcript::new(label); + assert!(proof.verify(&mut transcript_v, &c1, &c2, &c3)); + + // And now check it would fail on a different c3 value. + + let mut d = ::ScalarField::rand(&mut OsRng); + + loop { + if d != z {break;} + d = ::ScalarField::rand(&mut OsRng); + } + + let c4 : PC = PC::new(d, &mut OsRng); + let mut transcript_f = Transcript::new(label); + assert!(!proof.verify(&mut transcript_f, &c1, &c2, &c4)); } diff --git a/src/t384/Cargo.toml b/src/t384/Cargo.toml index 0a6bd2e..215ca8e 100644 --- a/src/t384/Cargo.toml +++ b/src/t384/Cargo.toml @@ -11,6 +11,9 @@ ark-ec = { version = "0.4.0", default-features = false } ark-r1cs-std = { version = "0.4.0", default-features = false, optional = true } ark-std = { version = "0.4.0", default-features = false } pedersen = { path = "../pedersen" } +rand = { version = "0.8.5" } +rand_core = { version = "0.6.4" } +merlin = { version = "3.0.0" } [dev-dependencies] ark-relations = { version = "0.4.0", default-features = false } diff --git a/src/t384/src/curves/mod.rs b/src/t384/src/curves/mod.rs index 03bd6aa..df6b822 100644 --- a/src/t384/src/curves/mod.rs +++ b/src/t384/src/curves/mod.rs @@ -3,7 +3,7 @@ use ark_ec::{ short_weierstrass::{self as sw, SWCurveConfig}, }; -use pedersen::PedersenConfig; +use pedersen::pedersen_config::PedersenConfig; use ark_ff::{Field, MontFp}; diff --git a/src/t384/src/curves/tests.rs b/src/t384/src/curves/tests.rs index 883b49a..241e0ee 100644 --- a/src/t384/src/curves/tests.rs +++ b/src/t384/src/curves/tests.rs @@ -2,7 +2,10 @@ use crate::{Projective, Config}; use ark_algebra_test_templates::*; use ark_std::{UniformRand}; use ark_ec::{CurveConfig}; -use pedersen::{PedersenComm}; + +use pedersen::{pedersen_config::PedersenComm, equality_protocol::EqualityProof as EP, opening_protocol::OpeningProof as OP, mul_protocol::MulProof as MP}; +use rand_core::OsRng; +use merlin::Transcript; test_group!(g1; Projective; sw); @@ -10,10 +13,109 @@ type PC = PedersenComm; #[test] fn test_pedersen() { - let mut rng = ark_std::test_rng(); - let a = ::ScalarField::rand(&mut rng); - let b = ::ScalarField::rand(&mut rng); - let c : PC = PC::new(a, b, &mut rng); - assert!(c.x_comm.is_on_curve()); - assert!(c.y_comm.is_on_curve()); + // Test that committing to a random point works. + let a = ::ScalarField::rand(&mut OsRng); + let c : PC = PC::new(a, &mut OsRng); + assert!(c.comm.is_on_curve()); +} + +#[test] +fn test_pedersen_equality() { + // Test that the equality proof goes through. + let label = b"PedersenEq"; + + let a = ::ScalarField::rand(&mut OsRng); + let c1 : PC = PC::new(a, &mut OsRng); + let c2 : PC = PC::new(a, &mut OsRng); + + let mut transcript = Transcript::new(label); + + // Build the proof. + let proof = EP::create(&mut transcript, &mut OsRng, &c1, &c2); + assert!(proof.alpha.is_on_curve()); + + // Make a new transcript and use that to verify. + let mut transcript_v = Transcript::new(label); + + // Now check that the proof verifies properly. + assert!(proof.verify(&mut transcript_v, &c1, &c2)); + + // Alternatively, check that a different proof would fail. + let mut b = ::ScalarField::rand(&mut OsRng); + + loop { + if b != a { break; } + b = ::ScalarField::rand(&mut OsRng); + } + + let c3 : PC = PC::new(b, &mut OsRng); + let mut transcript_f = Transcript::new(label); + assert!(!proof.verify(&mut transcript_f, &c1, &c3)); +} + +#[test] +fn test_pedersen_opening() { + // Test that the opening proof goes through. + let label = b"PedersenOpen"; + + let a = ::ScalarField::rand(&mut OsRng); + let c1 : PC = PC::new(a, &mut OsRng); + let mut transcript = Transcript::new(label); + + let proof = OP::create(&mut transcript, &mut OsRng, &a, &c1); + assert!(proof.alpha.is_on_curve()); + + // Now check that the proof verifies correctly. + let mut transcript_v = Transcript::new(label); + assert!(proof.verify(&mut transcript_v, &c1)); + + // Now check that an unrelated commitment would fail. + // Alternatively, check that a different proof would fail. + let mut b = ::ScalarField::rand(&mut OsRng); + + loop { + if b != a { break; } + b = ::ScalarField::rand(&mut OsRng); + } + + let c3 : PC = PC::new(b, &mut OsRng); + let mut transcript_f = Transcript::new(label); + assert!(!proof.verify(&mut transcript_f, &c3)); +} + +#[test] +fn test_pedersen_mul() { + // Test that the mul proof goes through. + let label = b"PedersenMul"; + + let a = ::ScalarField::rand(&mut OsRng); + let b = ::ScalarField::rand(&mut OsRng); + let z = a * b; + + let c1 : PC = PC::new(a, &mut OsRng); + let c2 : PC = PC::new(b, &mut OsRng); + let c3 : PC = PC::new(z, &mut OsRng); + + let mut transcript = Transcript::new(label); + let proof = MP::create(&mut transcript, &mut OsRng, a, b, &c1, &c2, &c3); + assert!(proof.alpha.is_on_curve()); + assert!(proof.beta.is_on_curve()); + assert!(proof.delta.is_on_curve()); + + // Now check that the proof verifies. + let mut transcript_v = Transcript::new(label); + assert!(proof.verify(&mut transcript_v, &c1, &c2, &c3)); + + // And now check it would fail on a different c3 value. + + let mut d = ::ScalarField::rand(&mut OsRng); + + loop { + if d != z {break;} + d = ::ScalarField::rand(&mut OsRng); + } + + let c4 : PC = PC::new(d, &mut OsRng); + let mut transcript_f = Transcript::new(label); + assert!(!proof.verify(&mut transcript_f, &c1, &c2, &c4)); } From 964f5a3b5641068bdbbb6d51652e4900c7f4da2f Mon Sep 17 00:00:00 2001 From: Joe Rowell Date: Tue, 5 Sep 2023 20:45:40 +0100 Subject: [PATCH 3/7] [WIP] Add ability to make from original curve. There's got to be a nicer way to do this: the From trait is probably the best way to go. --- src/pedersen/Cargo.toml | 1 + src/pedersen/src/pedersen_config.rs | 22 +++++++++++++++++++++- src/t256/Cargo.toml | 3 +++ src/t256/src/curves/mod.rs | 6 ++++++ src/t256/src/curves/tests.rs | 10 +++++++++- src/t384/Cargo.toml | 1 + src/t384/src/curves/mod.rs | 6 +++++- 7 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/pedersen/Cargo.toml b/src/pedersen/Cargo.toml index 2e50596..0cfb6e0 100644 --- a/src/pedersen/Cargo.toml +++ b/src/pedersen/Cargo.toml @@ -12,3 +12,4 @@ rand = { version = "0.8.5" } ark-ff = { version = "0.4.0"} ark-serialize = { version = "0.4.0"} merlin = { version = "3.0.0"} +num-bigint = { version = "0.4", default-features = false } \ No newline at end of file diff --git a/src/pedersen/src/pedersen_config.rs b/src/pedersen/src/pedersen_config.rs index d8e9adf..a417f4d 100644 --- a/src/pedersen/src/pedersen_config.rs +++ b/src/pedersen/src/pedersen_config.rs @@ -6,10 +6,16 @@ use ark_ec::{ use ark_std::{UniformRand, ops::Mul}; use rand::{RngCore, CryptoRng}; +use num_bigint; + pub trait PedersenConfig : SWCurveConfig { /// Second generator that's used in Pedersen commitments. const GENERATOR2: sw::Affine; + + /// The curve type that maps to this PedersenConfig. + /// For example, for T256 it would be P256. + type OCurve : CurveConfig; } pub struct PedersenComm { @@ -17,11 +23,25 @@ pub struct PedersenComm { pub r:

::ScalarField, } + impl PedersenComm

{ - pub fn new (x:

::ScalarField, rng: &mut T) -> Self { + pub fn new(x:

::ScalarField, rng: &mut T) -> Self { let x_r =

::ScalarField::rand(rng); let x_p =

::GENERATOR.mul(x) + P::GENERATOR2.mul(x_r); Self {comm: x_p.into_affine(), r: x_r } } + + pub fn new_from_ocurve(x : <

::OCurve as CurveConfig>::ScalarField, rng: &mut T) -> Self { + let x_r =

::ScalarField::rand(rng); + + // To make this work for types that don't necessarily map 1:1, we need to convert x into a + // big_uint first and then into the type in our field. This is annoying, but hopefully not too + // painful long term. + let x_bt : num_bigint::BigUint = x.into(); + let x_c =

::ScalarField::from(x_bt); + + let x_p =

::GENERATOR.mul(x_c) + P::GENERATOR2.mul(x_r); + Self { comm: x_p.into_affine(), r: x_r } + } } diff --git a/src/t256/Cargo.toml b/src/t256/Cargo.toml index 44d5515..a1d5e58 100644 --- a/src/t256/Cargo.toml +++ b/src/t256/Cargo.toml @@ -10,6 +10,7 @@ ark-ff = { version = "0.4.0", default-features = false } ark-ec = { version = "0.4.0", default-features = false } ark-r1cs-std = { version = "0.4.0", default-features = false, optional = true } ark-std = { version = "0.4.0", default-features = false } +ark-secp256r1 = {default-features = false, git = "https://github.com/arkworks-rs/curves" } pedersen = { path="../pedersen" } rand = { version = "0.8.5" } rand_core = { version = "0.6.4" } @@ -21,6 +22,8 @@ ark-serialize = { version = "0.4.0", default-features = false } ark-algebra-test-templates = { version = "0.4.0", default-features = false } ark-algebra-bench-templates = { version = "0.4.0", default-features = false } ark-curve-constraint-tests = {version = "0.4.0", default-features = false } +ark-secp256r1 = {default-features = false, git = "https://github.com/arkworks-rs/curves" } + [features] default = [] diff --git a/src/t256/src/curves/mod.rs b/src/t256/src/curves/mod.rs index 9e4e2a6..91b47be 100644 --- a/src/t256/src/curves/mod.rs +++ b/src/t256/src/curves/mod.rs @@ -3,12 +3,15 @@ use ark_ec::{ short_weierstrass::{self as sw, SWCurveConfig}, }; + use pedersen::pedersen_config::PedersenConfig; use ark_ff::{Field, MontFp}; use crate::{fq::Fq, fr::Fr}; +use ark_secp256r1::Config as secp256r1conf; + #[cfg(test)] mod tests; @@ -44,6 +47,9 @@ impl SWCurveConfig for Config { } impl PedersenConfig for Config { + type OCurve = secp256r1conf; + + /// GENERATOR2 = (G_GENERATOR_X2, G_GENERATOR_Y2) const GENERATOR2 : Affine = Affine::new_unchecked(G_GENERATOR_X2, G_GENERATOR_Y2); } diff --git a/src/t256/src/curves/tests.rs b/src/t256/src/curves/tests.rs index 241e0ee..511cd53 100644 --- a/src/t256/src/curves/tests.rs +++ b/src/t256/src/curves/tests.rs @@ -3,7 +3,7 @@ use ark_algebra_test_templates::*; use ark_std::{UniformRand}; use ark_ec::{CurveConfig}; -use pedersen::{pedersen_config::PedersenComm, equality_protocol::EqualityProof as EP, opening_protocol::OpeningProof as OP, mul_protocol::MulProof as MP}; +use pedersen::{pedersen_config::PedersenComm, pedersen_config::PedersenConfig, equality_protocol::EqualityProof as EP, opening_protocol::OpeningProof as OP, mul_protocol::MulProof as MP}; use rand_core::OsRng; use merlin::Transcript; @@ -19,6 +19,14 @@ fn test_pedersen() { assert!(c.comm.is_on_curve()); } +#[test] +fn test_pedersen_from_ocurve() { + // Test that committing a random point from P256 works. + let a = <::OCurve as CurveConfig>::ScalarField::rand(&mut OsRng); + let c : PC = PC::new_from_ocurve(a, &mut OsRng); + assert!(c.comm.is_on_curve()); +} + #[test] fn test_pedersen_equality() { // Test that the equality proof goes through. diff --git a/src/t384/Cargo.toml b/src/t384/Cargo.toml index 215ca8e..8501552 100644 --- a/src/t384/Cargo.toml +++ b/src/t384/Cargo.toml @@ -14,6 +14,7 @@ pedersen = { path = "../pedersen" } rand = { version = "0.8.5" } rand_core = { version = "0.6.4" } merlin = { version = "3.0.0" } +ark-secp384r1 = {default-features = false, git = "https://github.com/arkworks-rs/curves" } [dev-dependencies] ark-relations = { version = "0.4.0", default-features = false } diff --git a/src/t384/src/curves/mod.rs b/src/t384/src/curves/mod.rs index df6b822..91600f8 100644 --- a/src/t384/src/curves/mod.rs +++ b/src/t384/src/curves/mod.rs @@ -1,6 +1,6 @@ use ark_ec::{ models::CurveConfig, - short_weierstrass::{self as sw, SWCurveConfig}, + short_weierstrass::{self as sw, SWCurveConfig}, }; use pedersen::pedersen_config::PedersenConfig; @@ -9,6 +9,8 @@ use ark_ff::{Field, MontFp}; use crate::{fq::Fq, fr::Fr}; +use ark_secp384r1::Config as secp384r1conf; + #[cfg(test)] mod tests; @@ -44,6 +46,8 @@ impl SWCurveConfig for Config { } impl PedersenConfig for Config { + type OCurve = secp384r1conf; + /// GENERATOR2 = (G_GENERATOR_X2, G_GENERATOR_Y2) const GENERATOR2: Affine = Affine::new_unchecked(G_GENERATOR_X2, G_GENERATOR_Y2); } From 283391f443ca7e7808eec26cb5a77885542b6de6 Mon Sep 17 00:00:00 2001 From: Joe Rowell Date: Wed, 6 Sep 2023 11:40:39 +0100 Subject: [PATCH 4/7] Add conversion operators. --- src/pedersen/src/pedersen_config.rs | 22 ++---- src/t256/src/curves/mod.rs | 3 - src/t256/src/curves/tests.rs | 114 ++++++++++++++++++++++++++- src/t256/src/fields/fq.rs | 2 - src/t384/src/curves/tests.rs | 118 +++++++++++++++++++++++++++- src/t384/src/fields/fq.rs | 2 - 6 files changed, 234 insertions(+), 27 deletions(-) diff --git a/src/pedersen/src/pedersen_config.rs b/src/pedersen/src/pedersen_config.rs index a417f4d..f801025 100644 --- a/src/pedersen/src/pedersen_config.rs +++ b/src/pedersen/src/pedersen_config.rs @@ -6,8 +6,6 @@ use ark_ec::{ use ark_std::{UniformRand, ops::Mul}; use rand::{RngCore, CryptoRng}; -use num_bigint; - pub trait PedersenConfig : SWCurveConfig { /// Second generator that's used in Pedersen commitments. @@ -16,6 +14,11 @@ pub trait PedersenConfig : SWCurveConfig { /// The curve type that maps to this PedersenConfig. /// For example, for T256 it would be P256. type OCurve : CurveConfig; + + fn from_oc(x: ::ScalarField) -> ::ScalarField { + let x_bt : num_bigint::BigUint = x.into(); + ::ScalarField::from(x_bt) + } } pub struct PedersenComm { @@ -29,19 +32,6 @@ impl PedersenComm

{ let x_r =

::ScalarField::rand(rng); let x_p =

::GENERATOR.mul(x) + P::GENERATOR2.mul(x_r); Self {comm: x_p.into_affine(), r: x_r } - } - - pub fn new_from_ocurve(x : <

::OCurve as CurveConfig>::ScalarField, rng: &mut T) -> Self { - let x_r =

::ScalarField::rand(rng); - - // To make this work for types that don't necessarily map 1:1, we need to convert x into a - // big_uint first and then into the type in our field. This is annoying, but hopefully not too - // painful long term. - let x_bt : num_bigint::BigUint = x.into(); - let x_c =

::ScalarField::from(x_bt); - - let x_p =

::GENERATOR.mul(x_c) + P::GENERATOR2.mul(x_r); - Self { comm: x_p.into_affine(), r: x_r } - } + } } diff --git a/src/t256/src/curves/mod.rs b/src/t256/src/curves/mod.rs index 91b47be..8efe7e5 100644 --- a/src/t256/src/curves/mod.rs +++ b/src/t256/src/curves/mod.rs @@ -54,9 +54,6 @@ impl PedersenConfig for Config { const GENERATOR2 : Affine = Affine::new_unchecked(G_GENERATOR_X2, G_GENERATOR_Y2); } - - - /// G_GENERATOR_X = 3 pub const G_GENERATOR_X : Fq = MontFp!("3"); diff --git a/src/t256/src/curves/tests.rs b/src/t256/src/curves/tests.rs index 511cd53..f5df5e1 100644 --- a/src/t256/src/curves/tests.rs +++ b/src/t256/src/curves/tests.rs @@ -20,10 +20,10 @@ fn test_pedersen() { } #[test] -fn test_pedersen_from_ocurve() { - // Test that committing a random point from P256 works. +fn test_pedersen_convert() { + // Test that a commitment from the NIST curve to the T curve works. let a = <::OCurve as CurveConfig>::ScalarField::rand(&mut OsRng); - let c : PC = PC::new_from_ocurve(a, &mut OsRng); + let c : PC = PC::new(::from_oc(a), &mut OsRng); assert!(c.comm.is_on_curve()); } @@ -61,6 +61,40 @@ fn test_pedersen_equality() { assert!(!proof.verify(&mut transcript_f, &c1, &c3)); } +#[test] +fn test_pedersen_equality_nist() { + // Test that the equality proof goes through. + let label = b"PedersenEq"; + + let a = <::OCurve as CurveConfig>::ScalarField::rand(&mut OsRng); + let c1 : PC = PC::new(::from_oc(a), &mut OsRng); + let c2 : PC = PC::new(::from_oc(a), &mut OsRng); + + let mut transcript = Transcript::new(label); + + // Build the proof. + let proof = EP::create(&mut transcript, &mut OsRng, &c1, &c2); + assert!(proof.alpha.is_on_curve()); + + // Make a new transcript and use that to verify. + let mut transcript_v = Transcript::new(label); + + // Now check that the proof verifies properly. + assert!(proof.verify(&mut transcript_v, &c1, &c2)); + + // Alternatively, check that a different proof would fail. + let mut b = <::OCurve as CurveConfig>::ScalarField::rand(&mut OsRng); + + loop { + if b != a { break; } + b = <::OCurve as CurveConfig>::ScalarField::rand(&mut OsRng); + } + + let c3 : PC = PC::new(::from_oc(b), &mut OsRng); + let mut transcript_f = Transcript::new(label); + assert!(!proof.verify(&mut transcript_f, &c1, &c3)); +} + #[test] fn test_pedersen_opening() { // Test that the opening proof goes through. @@ -91,6 +125,39 @@ fn test_pedersen_opening() { assert!(!proof.verify(&mut transcript_f, &c3)); } +#[test] +fn test_pedersen_opening_nist() { + // Test that the opening proof goes through. + let label = b"PedersenOpen"; + + let a_t = <::OCurve as CurveConfig>::ScalarField::rand(&mut OsRng); + let a = ::from_oc(a_t); + + let c1 : PC = PC::new(a, &mut OsRng); + + let mut transcript = Transcript::new(label); + + let proof = OP::create(&mut transcript, &mut OsRng, &a, &c1); + assert!(proof.alpha.is_on_curve()); + + // Now check that the proof verifies correctly. + let mut transcript_v = Transcript::new(label); + assert!(proof.verify(&mut transcript_v, &c1)); + + // Now check that an unrelated commitment would fail. + // Alternatively, check that a different proof would fail. + let mut b = ::ScalarField::rand(&mut OsRng); + + loop { + if b != a { break; } + b = ::ScalarField::rand(&mut OsRng); + } + + let c3 : PC = PC::new(b, &mut OsRng); + let mut transcript_f = Transcript::new(label); + assert!(!proof.verify(&mut transcript_f, &c3)); +} + #[test] fn test_pedersen_mul() { // Test that the mul proof goes through. @@ -127,3 +194,44 @@ fn test_pedersen_mul() { let mut transcript_f = Transcript::new(label); assert!(!proof.verify(&mut transcript_f, &c1, &c2, &c4)); } + +#[test] +fn test_pedersen_mul_nist() { + // Test that the mul proof goes through. + let label = b"PedersenMul"; + + let a_t = <::OCurve as CurveConfig>::ScalarField::rand(&mut OsRng); + let b_t = <::OCurve as CurveConfig>::ScalarField::rand(&mut OsRng); + + let a = ::from_oc(a_t); + let b = ::from_oc(b_t); + + let z = a * b; + + let c1 : PC = PC::new(a, &mut OsRng); + let c2 : PC = PC::new(b, &mut OsRng); + let c3 : PC = PC::new(z, &mut OsRng); + + let mut transcript = Transcript::new(label); + let proof = MP::create(&mut transcript, &mut OsRng, a, b, &c1, &c2, &c3); + assert!(proof.alpha.is_on_curve()); + assert!(proof.beta.is_on_curve()); + assert!(proof.delta.is_on_curve()); + + // Now check that the proof verifies. + let mut transcript_v = Transcript::new(label); + assert!(proof.verify(&mut transcript_v, &c1, &c2, &c3)); + + // And now check it would fail on a different c3 value. + + let mut d = ::ScalarField::rand(&mut OsRng); + + loop { + if d != z {break;} + d = ::ScalarField::rand(&mut OsRng); + } + + let c4 : PC = PC::new(d, &mut OsRng); + let mut transcript_f = Transcript::new(label); + assert!(!proof.verify(&mut transcript_f, &c1, &c2, &c4)); +} diff --git a/src/t256/src/fields/fq.rs b/src/t256/src/fields/fq.rs index d7ab609..5840484 100644 --- a/src/t256/src/fields/fq.rs +++ b/src/t256/src/fields/fq.rs @@ -1,8 +1,6 @@ use ark_ff::fields::{Fp256, MontBackend, MontConfig}; - #[derive(MontConfig)] #[modulus = "115792089210356248762697446949407573530594504085698471288169790229257723883799"] #[generator = "3"] - pub struct FqConfig; pub type Fq = Fp256>; diff --git a/src/t384/src/curves/tests.rs b/src/t384/src/curves/tests.rs index 241e0ee..f5df5e1 100644 --- a/src/t384/src/curves/tests.rs +++ b/src/t384/src/curves/tests.rs @@ -3,7 +3,7 @@ use ark_algebra_test_templates::*; use ark_std::{UniformRand}; use ark_ec::{CurveConfig}; -use pedersen::{pedersen_config::PedersenComm, equality_protocol::EqualityProof as EP, opening_protocol::OpeningProof as OP, mul_protocol::MulProof as MP}; +use pedersen::{pedersen_config::PedersenComm, pedersen_config::PedersenConfig, equality_protocol::EqualityProof as EP, opening_protocol::OpeningProof as OP, mul_protocol::MulProof as MP}; use rand_core::OsRng; use merlin::Transcript; @@ -19,6 +19,14 @@ fn test_pedersen() { assert!(c.comm.is_on_curve()); } +#[test] +fn test_pedersen_convert() { + // Test that a commitment from the NIST curve to the T curve works. + let a = <::OCurve as CurveConfig>::ScalarField::rand(&mut OsRng); + let c : PC = PC::new(::from_oc(a), &mut OsRng); + assert!(c.comm.is_on_curve()); +} + #[test] fn test_pedersen_equality() { // Test that the equality proof goes through. @@ -53,6 +61,40 @@ fn test_pedersen_equality() { assert!(!proof.verify(&mut transcript_f, &c1, &c3)); } +#[test] +fn test_pedersen_equality_nist() { + // Test that the equality proof goes through. + let label = b"PedersenEq"; + + let a = <::OCurve as CurveConfig>::ScalarField::rand(&mut OsRng); + let c1 : PC = PC::new(::from_oc(a), &mut OsRng); + let c2 : PC = PC::new(::from_oc(a), &mut OsRng); + + let mut transcript = Transcript::new(label); + + // Build the proof. + let proof = EP::create(&mut transcript, &mut OsRng, &c1, &c2); + assert!(proof.alpha.is_on_curve()); + + // Make a new transcript and use that to verify. + let mut transcript_v = Transcript::new(label); + + // Now check that the proof verifies properly. + assert!(proof.verify(&mut transcript_v, &c1, &c2)); + + // Alternatively, check that a different proof would fail. + let mut b = <::OCurve as CurveConfig>::ScalarField::rand(&mut OsRng); + + loop { + if b != a { break; } + b = <::OCurve as CurveConfig>::ScalarField::rand(&mut OsRng); + } + + let c3 : PC = PC::new(::from_oc(b), &mut OsRng); + let mut transcript_f = Transcript::new(label); + assert!(!proof.verify(&mut transcript_f, &c1, &c3)); +} + #[test] fn test_pedersen_opening() { // Test that the opening proof goes through. @@ -83,6 +125,39 @@ fn test_pedersen_opening() { assert!(!proof.verify(&mut transcript_f, &c3)); } +#[test] +fn test_pedersen_opening_nist() { + // Test that the opening proof goes through. + let label = b"PedersenOpen"; + + let a_t = <::OCurve as CurveConfig>::ScalarField::rand(&mut OsRng); + let a = ::from_oc(a_t); + + let c1 : PC = PC::new(a, &mut OsRng); + + let mut transcript = Transcript::new(label); + + let proof = OP::create(&mut transcript, &mut OsRng, &a, &c1); + assert!(proof.alpha.is_on_curve()); + + // Now check that the proof verifies correctly. + let mut transcript_v = Transcript::new(label); + assert!(proof.verify(&mut transcript_v, &c1)); + + // Now check that an unrelated commitment would fail. + // Alternatively, check that a different proof would fail. + let mut b = ::ScalarField::rand(&mut OsRng); + + loop { + if b != a { break; } + b = ::ScalarField::rand(&mut OsRng); + } + + let c3 : PC = PC::new(b, &mut OsRng); + let mut transcript_f = Transcript::new(label); + assert!(!proof.verify(&mut transcript_f, &c3)); +} + #[test] fn test_pedersen_mul() { // Test that the mul proof goes through. @@ -119,3 +194,44 @@ fn test_pedersen_mul() { let mut transcript_f = Transcript::new(label); assert!(!proof.verify(&mut transcript_f, &c1, &c2, &c4)); } + +#[test] +fn test_pedersen_mul_nist() { + // Test that the mul proof goes through. + let label = b"PedersenMul"; + + let a_t = <::OCurve as CurveConfig>::ScalarField::rand(&mut OsRng); + let b_t = <::OCurve as CurveConfig>::ScalarField::rand(&mut OsRng); + + let a = ::from_oc(a_t); + let b = ::from_oc(b_t); + + let z = a * b; + + let c1 : PC = PC::new(a, &mut OsRng); + let c2 : PC = PC::new(b, &mut OsRng); + let c3 : PC = PC::new(z, &mut OsRng); + + let mut transcript = Transcript::new(label); + let proof = MP::create(&mut transcript, &mut OsRng, a, b, &c1, &c2, &c3); + assert!(proof.alpha.is_on_curve()); + assert!(proof.beta.is_on_curve()); + assert!(proof.delta.is_on_curve()); + + // Now check that the proof verifies. + let mut transcript_v = Transcript::new(label); + assert!(proof.verify(&mut transcript_v, &c1, &c2, &c3)); + + // And now check it would fail on a different c3 value. + + let mut d = ::ScalarField::rand(&mut OsRng); + + loop { + if d != z {break;} + d = ::ScalarField::rand(&mut OsRng); + } + + let c4 : PC = PC::new(d, &mut OsRng); + let mut transcript_f = Transcript::new(label); + assert!(!proof.verify(&mut transcript_f, &c1, &c2, &c4)); +} diff --git a/src/t384/src/fields/fq.rs b/src/t384/src/fields/fq.rs index dbe747c..09eb42f 100644 --- a/src/t384/src/fields/fq.rs +++ b/src/t384/src/fields/fq.rs @@ -1,8 +1,6 @@ use ark_ff::fields::{Fp384, MontBackend, MontConfig}; - #[derive(MontConfig)] #[modulus = "39402006196394479212279040100143613805079739270465446667940039326625812510850684806287457257749692633059273959086021"] #[generator = "3"] - pub struct FqConfig; pub type Fq = Fp384>; From e05341c4ae331bb387eda3740c1b4afa12cb4705 Mon Sep 17 00:00:00 2001 From: Joe Rowell Date: Wed, 6 Sep 2023 11:57:17 +0100 Subject: [PATCH 5/7] Add addition, subtract. Also add derives for Clones + Copies because, quite frankly, the idea that operators take ownership is kinda stupid. --- src/pedersen/src/pedersen_config.rs | 18 ++++++++++++ src/t256/src/curves/tests.rs | 43 ++++++++++++++++++++++++++++- src/t384/src/curves/tests.rs | 43 ++++++++++++++++++++++++++++- 3 files changed, 102 insertions(+), 2 deletions(-) diff --git a/src/pedersen/src/pedersen_config.rs b/src/pedersen/src/pedersen_config.rs index f801025..d1064d8 100644 --- a/src/pedersen/src/pedersen_config.rs +++ b/src/pedersen/src/pedersen_config.rs @@ -2,9 +2,11 @@ use ark_ec::{ models::CurveConfig, short_weierstrass::{self as sw, SWCurveConfig}, CurveGroup, + AffineRepr, }; use ark_std::{UniformRand, ops::Mul}; +use std::ops; use rand::{RngCore, CryptoRng}; pub trait PedersenConfig : SWCurveConfig { @@ -21,11 +23,27 @@ pub trait PedersenConfig : SWCurveConfig { } } +#[derive(Clone, Copy)] pub struct PedersenComm { pub comm: sw::Affine

, pub r:

::ScalarField, } +impl ops::Add> for PedersenComm

{ + type Output = PedersenComm

; + + fn add(self, rhs: PedersenComm

) -> PedersenComm

{ + Self::Output { comm: (self.comm.into_group() + rhs.comm).into(), r: self.r + rhs.r } + } +} + +impl ops::Sub> for PedersenComm

{ + type Output = PedersenComm

; + + fn sub(self, rhs: PedersenComm

) -> PedersenComm

{ + Self::Output { comm: (self.comm.into_group() - rhs.comm).into(), r: self.r - rhs.r } + } +} impl PedersenComm

{ pub fn new(x:

::ScalarField, rng: &mut T) -> Self { diff --git a/src/t256/src/curves/tests.rs b/src/t256/src/curves/tests.rs index f5df5e1..dfd987d 100644 --- a/src/t256/src/curves/tests.rs +++ b/src/t256/src/curves/tests.rs @@ -1,7 +1,12 @@ use crate::{Projective, Config}; use ark_algebra_test_templates::*; use ark_std::{UniformRand}; -use ark_ec::{CurveConfig}; + +use ark_ec::{ + models::CurveConfig, + short_weierstrass::{self as sw}, + AffineRepr, +}; use pedersen::{pedersen_config::PedersenComm, pedersen_config::PedersenConfig, equality_protocol::EqualityProof as EP, opening_protocol::OpeningProof as OP, mul_protocol::MulProof as MP}; use rand_core::OsRng; @@ -27,6 +32,42 @@ fn test_pedersen_convert() { assert!(c.comm.is_on_curve()); } +#[test] +fn test_pedersen_add() { + // Test that adding two random pedersen commitments works. + let a = ::ScalarField::rand(&mut OsRng); + let c1 : PC = PC::new(a, &mut OsRng); + assert!(c1.comm.is_on_curve()); + + let b = ::ScalarField::rand(&mut OsRng); + let c2 : PC = PC::new(b, &mut OsRng); + assert!(c2.comm.is_on_curve()); + + let c3 = c1 + c2; + + let c_act : sw::Affine = (c1.comm.into_group() + c2.comm).into(); + assert!(c3.comm == c_act); + assert!(c3.r == c1.r + c2.r); +} + +#[test] +fn test_pedersen_sub() { + // Same as for addition, but subtraction instead. + let a = ::ScalarField::rand(&mut OsRng); + let c1 : PC = PC::new(a, &mut OsRng); + assert!(c1.comm.is_on_curve()); + + let b = ::ScalarField::rand(&mut OsRng); + let c2 : PC = PC::new(b, &mut OsRng); + assert!(c2.comm.is_on_curve()); + + let c3 = c1 - c2; + + let c_act : sw::Affine = (c1.comm.into_group() - c2.comm).into(); + assert!(c3.comm == c_act); + assert!(c3.r == c1.r - c2.r); +} + #[test] fn test_pedersen_equality() { // Test that the equality proof goes through. diff --git a/src/t384/src/curves/tests.rs b/src/t384/src/curves/tests.rs index f5df5e1..dfd987d 100644 --- a/src/t384/src/curves/tests.rs +++ b/src/t384/src/curves/tests.rs @@ -1,7 +1,12 @@ use crate::{Projective, Config}; use ark_algebra_test_templates::*; use ark_std::{UniformRand}; -use ark_ec::{CurveConfig}; + +use ark_ec::{ + models::CurveConfig, + short_weierstrass::{self as sw}, + AffineRepr, +}; use pedersen::{pedersen_config::PedersenComm, pedersen_config::PedersenConfig, equality_protocol::EqualityProof as EP, opening_protocol::OpeningProof as OP, mul_protocol::MulProof as MP}; use rand_core::OsRng; @@ -27,6 +32,42 @@ fn test_pedersen_convert() { assert!(c.comm.is_on_curve()); } +#[test] +fn test_pedersen_add() { + // Test that adding two random pedersen commitments works. + let a = ::ScalarField::rand(&mut OsRng); + let c1 : PC = PC::new(a, &mut OsRng); + assert!(c1.comm.is_on_curve()); + + let b = ::ScalarField::rand(&mut OsRng); + let c2 : PC = PC::new(b, &mut OsRng); + assert!(c2.comm.is_on_curve()); + + let c3 = c1 + c2; + + let c_act : sw::Affine = (c1.comm.into_group() + c2.comm).into(); + assert!(c3.comm == c_act); + assert!(c3.r == c1.r + c2.r); +} + +#[test] +fn test_pedersen_sub() { + // Same as for addition, but subtraction instead. + let a = ::ScalarField::rand(&mut OsRng); + let c1 : PC = PC::new(a, &mut OsRng); + assert!(c1.comm.is_on_curve()); + + let b = ::ScalarField::rand(&mut OsRng); + let c2 : PC = PC::new(b, &mut OsRng); + assert!(c2.comm.is_on_curve()); + + let c3 = c1 - c2; + + let c_act : sw::Affine = (c1.comm.into_group() - c2.comm).into(); + assert!(c3.comm == c_act); + assert!(c3.r == c1.r - c2.r); +} + #[test] fn test_pedersen_equality() { // Test that the equality proof goes through. From 9fbfb6b80292e546358c4cdc9467748ccadd3958 Mon Sep 17 00:00:00 2001 From: Joe Rowell Date: Wed, 6 Sep 2023 12:08:37 +0100 Subject: [PATCH 6/7] OK, fine, I'll overload them all. --- src/pedersen/src/pedersen_config.rs | 50 +++++++++++++++++++++++++++++ src/t256/src/curves/tests.rs | 34 +++++++++++++++++++- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/pedersen/src/pedersen_config.rs b/src/pedersen/src/pedersen_config.rs index d1064d8..4249c87 100644 --- a/src/pedersen/src/pedersen_config.rs +++ b/src/pedersen/src/pedersen_config.rs @@ -37,6 +37,30 @@ impl ops::Add> for PedersenComm

{ } } +impl ops::Add<&PedersenComm

> for &PedersenComm

{ + type Output = PedersenComm

; + + fn add(self, rhs: &PedersenComm

) -> PedersenComm

{ + Self::Output { comm: (self.comm.into_group() + rhs.comm).into(), r: self.r + rhs.r } + } +} + +impl ops::Add<&PedersenComm

> for PedersenComm

{ + type Output = PedersenComm

; + + fn add(self, rhs: &PedersenComm

) -> PedersenComm

{ + Self::Output { comm: (self.comm.into_group() + rhs.comm).into(), r: self.r + rhs.r } + } +} + +impl ops::Add> for &PedersenComm

{ + type Output = PedersenComm

; + + fn add(self, rhs: PedersenComm

) -> PedersenComm

{ + Self::Output { comm: (self.comm.into_group() + rhs.comm).into(), r: self.r + rhs.r } + } +} + impl ops::Sub> for PedersenComm

{ type Output = PedersenComm

; @@ -45,6 +69,32 @@ impl ops::Sub> for PedersenComm

{ } } +impl ops::Sub<&PedersenComm

> for &PedersenComm

{ + type Output = PedersenComm

; + + fn sub(self, rhs: &PedersenComm

) -> PedersenComm

{ + Self::Output { comm: (self.comm.into_group() - rhs.comm).into(), r: self.r - rhs.r } + } +} + +impl ops::Sub<&PedersenComm

> for PedersenComm

{ + type Output = PedersenComm

; + + fn sub(self, rhs: &PedersenComm

) -> PedersenComm

{ + Self::Output { comm: (self.comm.into_group() - rhs.comm).into(), r: self.r - rhs.r } + } +} + +impl ops::Sub> for &PedersenComm

{ + type Output = PedersenComm

; + + fn sub(self, rhs: PedersenComm

) -> PedersenComm

{ + Self::Output { comm: (self.comm.into_group() - rhs.comm).into(), r: self.r - rhs.r } + } +} + + + impl PedersenComm

{ pub fn new(x:

::ScalarField, rng: &mut T) -> Self { let x_r =

::ScalarField::rand(rng); diff --git a/src/t256/src/curves/tests.rs b/src/t256/src/curves/tests.rs index dfd987d..8b72e4a 100644 --- a/src/t256/src/curves/tests.rs +++ b/src/t256/src/curves/tests.rs @@ -48,6 +48,21 @@ fn test_pedersen_add() { let c_act : sw::Affine = (c1.comm.into_group() + c2.comm).into(); assert!(c3.comm == c_act); assert!(c3.r == c1.r + c2.r); + + // Same if by reference. + let c3r = c1 + &c2; + assert!(c3r.comm == c_act); + assert!(c3r.r == c1.r + c2.r); + + // Or if by reference the other way. + let c3rv = &c1 + c2; + assert!(c3rv.comm == c_act); + assert!(c3rv.r == c1.r + c2.r); + + // Or even if both. + let c3rr = &c1 + &c2; + assert!(c3rr.comm == c_act); + assert!(c3rr.r == c1.r + c2.r); } #[test] @@ -65,7 +80,24 @@ fn test_pedersen_sub() { let c_act : sw::Affine = (c1.comm.into_group() - c2.comm).into(); assert!(c3.comm == c_act); - assert!(c3.r == c1.r - c2.r); + assert!(c3.r == c1.r - c2.r); + + + // Same if by reference. + let c3r = c1 - &c2; + assert!(c3r.comm == c_act); + assert!(c3r.r == c1.r - c2.r); + + // Or if by reference the other way. + let c3rv = &c1 - c2; + assert!(c3rv.comm == c_act); + assert!(c3rv.r == c1.r - c2.r); + + // Or even if both. + let c3rr = &c1 - &c2; + assert!(c3rr.comm == c_act); + assert!(c3rr.r == c1.r - c2.r); + } #[test] From 27906f85b016bec9284dd873ef679f51e71812cf Mon Sep 17 00:00:00 2001 From: Joe Rowell Date: Wed, 6 Sep 2023 15:29:36 +0100 Subject: [PATCH 7/7] EC Point addition protocol + tests + conversion functions. --- src/pedersen/src/ec_point_add_protocol.rs | 157 ++++++++++++++++++++++ src/pedersen/src/lib.rs | 1 + src/pedersen/src/mul_protocol.rs | 4 +- src/pedersen/src/pedersen_config.rs | 11 +- src/pedersen/src/transcript.rs | 28 ++++ src/t256/src/curves/mod.rs | 71 +++++++++- src/t256/src/curves/tests.rs | 56 +++++++- src/t256/src/fields/fq.rs | 1 + src/t384/src/curves/mod.rs | 62 ++++++++- src/t384/src/curves/tests.rs | 90 ++++++++++++- 10 files changed, 463 insertions(+), 18 deletions(-) create mode 100644 src/pedersen/src/ec_point_add_protocol.rs diff --git a/src/pedersen/src/ec_point_add_protocol.rs b/src/pedersen/src/ec_point_add_protocol.rs new file mode 100644 index 0000000..4a782b5 --- /dev/null +++ b/src/pedersen/src/ec_point_add_protocol.rs @@ -0,0 +1,157 @@ +//! Defines a protocol for proof of elliptic curve point addition. +//! Namely, this protocol proves that A + B = T, for A, B, T \in E(F_{q}). +//! This protocol is the same as the protocol described in Theorem 4 of the paper. + +use merlin::Transcript; +use ark_ec::{ + CurveConfig, +}; + +use ark_serialize::{CanonicalSerialize}; +use ark_ff::fields::Field; + +use rand::{RngCore, CryptoRng}; + +use crate::{pedersen_config::PedersenConfig, pedersen_config::PedersenComm, transcript::ECPointAdditionTranscript, mul_protocol::MulProof, opening_protocol::OpeningProof}; + +pub struct ECPointAddProof { + /// c1: the commitment to a_x. + pub c1: PedersenComm

, + /// c2: the commitment to a_y. + pub c2: PedersenComm

, + /// c3: the commitment to b_x. + pub c3: PedersenComm

, + /// c4: the commitment to b_y. + pub c4: PedersenComm

, + /// c5: the commitment to t_x. + pub c5: PedersenComm

, + /// c6: the commitment to t_y. + pub c6: PedersenComm

, + + /// c7: the commitment to tau = (b_y - a_y)/(b_x - a_x) + pub c7: PedersenComm

, + + /// mp1: the multiplication proof that verifies that equation 1 holds. + pub mp1: MulProof

, + + /// mp2: the multiplication proof that verifies that equation 2 holds. + pub mp2: MulProof

, + + /// mp3: the multiplication proof that verifies that equation 3 holds. + pub mp3: MulProof

, + + /// op: the opening proof of C2. + pub op: OpeningProof

, +} + +impl ECPointAddProof

{ + fn make_transcript(transcript: &mut Transcript, + c1: &PedersenComm

, + c2: &PedersenComm

, + c3: &PedersenComm

, + c4: &PedersenComm

, + c5: &PedersenComm

, + c6: &PedersenComm

, + c7: &PedersenComm

) { + + // This function just builds the transcript for both the create and verify functions. + // N.B Because of how we define the serialisation API to handle different numbers, + // we use a temporary buffer here. + ECPointAdditionTranscript::domain_sep(transcript); + + let mut compressed_bytes = Vec::new(); + c1.comm.serialize_compressed(&mut compressed_bytes).unwrap(); + ECPointAdditionTranscript::append_point(transcript, b"C1", &compressed_bytes[..]); + + c2.comm.serialize_compressed(&mut compressed_bytes).unwrap(); + ECPointAdditionTranscript::append_point(transcript, b"C2", &compressed_bytes[..]); + + c3.comm.serialize_compressed(&mut compressed_bytes).unwrap(); + ECPointAdditionTranscript::append_point(transcript, b"C3", &compressed_bytes[..]); + + c4.comm.serialize_compressed(&mut compressed_bytes).unwrap(); + ECPointAdditionTranscript::append_point(transcript, b"C4", &compressed_bytes[..]); + + c5.comm.serialize_compressed(&mut compressed_bytes).unwrap(); + ECPointAdditionTranscript::append_point(transcript, b"C5", &compressed_bytes[..]); + + c6.comm.serialize_compressed(&mut compressed_bytes).unwrap(); + ECPointAdditionTranscript::append_point(transcript, b"C6", &compressed_bytes[..]); + + c7.comm.serialize_compressed(&mut compressed_bytes).unwrap(); + ECPointAdditionTranscript::append_point(transcript, b"C7", &compressed_bytes[..]); + } + + + fn make_commitment (val: <

::OCurve as CurveConfig>::BaseField, rng: &mut T) -> PedersenComm

{ + let val_p =

::from_ob_to_sf(val); + PedersenComm::new(val_p, rng) + } + + pub fn create(transcript: &mut Transcript, + rng: &mut T, + a_x: <

::OCurve as CurveConfig>::BaseField, + a_y: <

::OCurve as CurveConfig>::BaseField, + b_x: <

::OCurve as CurveConfig>::BaseField, + b_y: <

::OCurve as CurveConfig>::BaseField, + t_x: <

::OCurve as CurveConfig>::BaseField, + t_y: <

::OCurve as CurveConfig>::BaseField) -> Self { + + + // Commit to each of the co-ordinate pairs. + let c1 = Self::make_commitment(a_x, rng); + let c2 = Self::make_commitment(a_y, rng); + let c3 = Self::make_commitment(b_x, rng); + let c4 = Self::make_commitment(b_y, rng); + let c5 = Self::make_commitment(t_x, rng); + let c6 = Self::make_commitment(t_y, rng); + + // c7 is the commitment to tau, the gradient. + let tau = (b_y - a_y) * ((b_x - a_x).inverse().unwrap()); + let taua =

::from_ob_to_sf(tau); + let c7 = PedersenComm::new(taua, rng); + + + // Now commit to all of them. + Self::make_transcript(transcript, &c1, &c2, &c3, &c4, &c5, &c6, &c7); + + // And now we simply invoke each of the sub-protocols. + let z1 = &c3 - &c1; + let z2 = &c4 - &c2; + let x1 =

::from_ob_to_sf(b_x - a_x); + let mp1 = MulProof::create(transcript, rng, &x1, &taua, &z1, &c7, &z2); + + + let z4 = &c1 + &c3 + &c5; + let mp2 = MulProof::create(transcript, rng, &taua, &taua, &c7, &c7, &z4); + assert!(mp2.alpha.is_on_curve()); + assert!(mp2.beta.is_on_curve()); + assert!(mp2.delta.is_on_curve()); + + let x3 =

::from_ob_to_sf(a_x - t_x); + + let z5 = &c1 - &c5; + let z6 = &c2 + &c6; + let mp3 = MulProof::create(transcript, rng, &taua, &x3, &c7, &z5, &z6); + + let op = OpeningProof::create(transcript, rng, &taua, &c7); + + // And now we just return. + Self { c1: c1, c2: c2, c3: c3, c4: c4, c5: c5, c6: c6, c7: c7, mp1: mp1, mp2: mp2, mp3: mp3, op: op } + } + + pub fn verify(&self, transcript: &mut Transcript) -> bool { + Self::make_transcript(transcript, &self.c1, &self.c2, &self.c3, &self.c4, &self.c5, &self.c6, &self.c7); + + let z1 = &self.c3 - &self.c1; + let z2 = &self.c7; + let z3 = &self.c4 - &self.c2; + let z4 = &self.c1 + &self.c3 + &self.c5; + let z5 = &self.c1 - &self.c5; + let z6 = &self.c2 + &self.c6; + + self.mp1.verify(transcript, &z1, &z2, &z3) && self.mp2.verify(transcript, &self.c7, &self.c7, &z4) && + self.mp3.verify(transcript, &z2, &z5, &z6) && self.op.verify(transcript, &self.c7) + } +} + diff --git a/src/pedersen/src/lib.rs b/src/pedersen/src/lib.rs index 197bfe6..3009f47 100644 --- a/src/pedersen/src/lib.rs +++ b/src/pedersen/src/lib.rs @@ -4,3 +4,4 @@ pub mod equality_protocol; pub mod opening_protocol; pub mod mul_protocol; pub mod pedersen_config; +pub mod ec_point_add_protocol; diff --git a/src/pedersen/src/mul_protocol.rs b/src/pedersen/src/mul_protocol.rs index 0b9ca08..49c741f 100644 --- a/src/pedersen/src/mul_protocol.rs +++ b/src/pedersen/src/mul_protocol.rs @@ -68,8 +68,8 @@ impl MulProof

{ pub fn create(transcript: &mut Transcript, rng: &mut T, - x:

::ScalarField, - y:

::ScalarField, + x: &

::ScalarField, + y: &

::ScalarField, c1: &PedersenComm

, c2: &PedersenComm

, c3: &PedersenComm

) -> Self { diff --git a/src/pedersen/src/pedersen_config.rs b/src/pedersen/src/pedersen_config.rs index 4249c87..4518ffb 100644 --- a/src/pedersen/src/pedersen_config.rs +++ b/src/pedersen/src/pedersen_config.rs @@ -5,6 +5,7 @@ use ark_ec::{ AffineRepr, }; + use ark_std::{UniformRand, ops::Mul}; use std::ops; use rand::{RngCore, CryptoRng}; @@ -15,15 +16,17 @@ pub trait PedersenConfig : SWCurveConfig { /// The curve type that maps to this PedersenConfig. /// For example, for T256 it would be P256. - type OCurve : CurveConfig; - + type OCurve: CurveConfig; + fn from_oc(x: ::ScalarField) -> ::ScalarField { let x_bt : num_bigint::BigUint = x.into(); ::ScalarField::from(x_bt) - } + } + + fn from_ob_to_sf(x: ::BaseField) -> ::ScalarField; } -#[derive(Clone, Copy)] +#[derive(Copy, Clone)] pub struct PedersenComm { pub comm: sw::Affine

, pub r:

::ScalarField, diff --git a/src/pedersen/src/transcript.rs b/src/pedersen/src/transcript.rs index 673994a..c497401 100644 --- a/src/pedersen/src/transcript.rs +++ b/src/pedersen/src/transcript.rs @@ -87,3 +87,31 @@ impl MulTranscript for Transcript { } } +pub trait ECPointAdditionTranscript { + + /// Append a domain separator. + fn domain_sep(&mut self); + + /// Append a point. + fn append_point(&mut self, label: &'static[u8], point: &[u8]); + + /// Produce the challenge. + fn challenge_scalar(&mut self, label: &'static[u8]) -> [u8; 64]; +} + +impl ECPointAdditionTranscript for Transcript { + + fn domain_sep(&mut self) { + self.append_message(b"dom-sep", b"ec-point-addition-proof"); + } + + fn append_point(&mut self, label: &'static[u8], point: &[u8]) { + self.append_message(label, point); + } + + fn challenge_scalar(&mut self, label: &'static[u8]) -> [u8; 64] { + let mut buf = [0u8; 64]; + self.challenge_bytes(label, &mut buf); + buf + } +} diff --git a/src/t256/src/curves/mod.rs b/src/t256/src/curves/mod.rs index 8efe7e5..058add4 100644 --- a/src/t256/src/curves/mod.rs +++ b/src/t256/src/curves/mod.rs @@ -6,11 +6,65 @@ use ark_ec::{ use pedersen::pedersen_config::PedersenConfig; -use ark_ff::{Field, MontFp}; +use ark_ff::{Field, MontFp, MontConfig}; +use ark_ff::{BigInt}; + +use crate::{fq::Fq, fr::Fr, fr::FrConfig}; -use crate::{fq::Fq, fr::Fr}; use ark_secp256r1::Config as secp256r1conf; +use ark_secp256r1::Fq as secp256r1Fq; +use ark_secp256r1::FqConfig as secp256FqConfig; +type OtherBaseField = ::BaseField; + +// Define the various conversion structs. +struct FrStruct(Fr); +impl FrStruct { + pub fn new(x: Fr) -> FrStruct { + FrStruct(x) + } + + pub fn as_fr(&self) -> Fr { + self.0 + } +} + +impl From> for FrStruct { + fn from(x: BigInt<4>) -> Self { + let x_t = FrConfig::from_bigint(x).unwrap(); + FrStruct::new(x_t) + } +} + +impl Into> for FrStruct { + fn into(self) -> BigInt<4> { + FrConfig::into_bigint(self.0) + } +} + +struct Secp256r1base(OtherBaseField); + +impl Secp256r1base { + + pub fn new(x: secp256r1Fq) -> Secp256r1base { + Secp256r1base(x) + } +} + + +impl Into> for Secp256r1base { + fn into(self) -> BigInt<4> { + secp256FqConfig::into_bigint(self.0) + } +} + +impl From> for Secp256r1base { + fn from(x: BigInt<4>) -> Self { + let x_t = secp256FqConfig::from_bigint(x).unwrap(); + Secp256r1base::new(x_t) + } +} + #[cfg(test)] mod tests; @@ -48,10 +102,17 @@ impl SWCurveConfig for Config { impl PedersenConfig for Config { type OCurve = secp256r1conf; - + + /// GENERATOR2 = (G_GENERATOR_X2, G_GENERATOR_Y2) const GENERATOR2 : Affine = Affine::new_unchecked(G_GENERATOR_X2, G_GENERATOR_Y2); + + fn from_ob_to_sf(x: OtherBaseField) -> ::ScalarField { + let x_t : BigInt<4> = x.into(); + let x_v : FrStruct = FrStruct::from(x_t); + x_v.as_fr() + } } /// G_GENERATOR_X = 3 @@ -68,4 +129,8 @@ pub const G_GENERATOR_X2 : Fq = MontFp!("5"); pub const G_GENERATOR_Y2 : Fq = MontFp!("28281484859698624956664858566852274012236038028101624500031073655422126514829"); +// We also need to define the ability to convert between points on the NIST curve and points on the Tom Curve, +// which means that we need to be able to take BaseField values from P256 and turn them into ScalarField values +// on T256. +// This is not supported by arkworks, so we'll do it manually. diff --git a/src/t256/src/curves/tests.rs b/src/t256/src/curves/tests.rs index 8b72e4a..472e3f5 100644 --- a/src/t256/src/curves/tests.rs +++ b/src/t256/src/curves/tests.rs @@ -6,15 +6,18 @@ use ark_ec::{ models::CurveConfig, short_weierstrass::{self as sw}, AffineRepr, + CurveGroup, }; -use pedersen::{pedersen_config::PedersenComm, pedersen_config::PedersenConfig, equality_protocol::EqualityProof as EP, opening_protocol::OpeningProof as OP, mul_protocol::MulProof as MP}; +use pedersen::{pedersen_config::PedersenComm, pedersen_config::PedersenConfig, equality_protocol::EqualityProof as EP, opening_protocol::OpeningProof as OP, mul_protocol::MulProof as MP, ec_point_add_protocol::ECPointAddProof as EPAP}; use rand_core::OsRng; use merlin::Transcript; +use ark_secp256r1::Config as secp256r1conf; test_group!(g1; Projective; sw); type PC = PedersenComm; +type OtherProjectiveType = sw::Projective; #[test] fn test_pedersen() { @@ -245,7 +248,7 @@ fn test_pedersen_mul() { let c3 : PC = PC::new(z, &mut OsRng); let mut transcript = Transcript::new(label); - let proof = MP::create(&mut transcript, &mut OsRng, a, b, &c1, &c2, &c3); + let proof = MP::create(&mut transcript, &mut OsRng, &a, &b, &c1, &c2, &c3); assert!(proof.alpha.is_on_curve()); assert!(proof.beta.is_on_curve()); assert!(proof.delta.is_on_curve()); @@ -286,7 +289,7 @@ fn test_pedersen_mul_nist() { let c3 : PC = PC::new(z, &mut OsRng); let mut transcript = Transcript::new(label); - let proof = MP::create(&mut transcript, &mut OsRng, a, b, &c1, &c2, &c3); + let proof = MP::create(&mut transcript, &mut OsRng, &a, &b, &c1, &c2, &c3); assert!(proof.alpha.is_on_curve()); assert!(proof.beta.is_on_curve()); assert!(proof.delta.is_on_curve()); @@ -308,3 +311,50 @@ fn test_pedersen_mul_nist() { let mut transcript_f = Transcript::new(label); assert!(!proof.verify(&mut transcript_f, &c1, &c2, &c4)); } + + +#[test] +fn test_pedersen_point_add() { + // Test that the point addition proof goes through. + let label = b"PedersenECPointAdd"; + let a = OtherProjectiveType::rand(&mut OsRng).into_affine(); + let mut b = OtherProjectiveType::rand(&mut OsRng).into_affine(); + + loop { + if b != a { break; } + b = OtherProjectiveType::rand(&mut OsRng).into_affine(); + } + + // Note: this needs to be forced into affine too, or the underlying + // proof system breaks (this seems to be an ark_ff thing). + let t = (a + b).into_affine(); + + let mut transcript = Transcript::new(label); + let proof : EPAP = EPAP::create(&mut transcript, &mut OsRng, a.x, a.y, b.x, b.y, t.x, t.y); + + assert!(proof.c1.comm.is_on_curve()); + assert!(proof.c2.comm.is_on_curve()); + assert!(proof.c3.comm.is_on_curve()); + assert!(proof.c4.comm.is_on_curve()); + assert!(proof.c5.comm.is_on_curve()); + assert!(proof.c6.comm.is_on_curve()); + assert!(proof.c7.comm.is_on_curve()); + + // Now check that it verifies. + let mut transcript_v = Transcript::new(label); + assert!(proof.verify(&mut transcript_v)); + + // Alternatively, generate a false proof and watch it fail. + let mut tf = OtherProjectiveType::rand(&mut OsRng).into_affine(); + loop { + if tf != t { break; } + tf = OtherProjectiveType::rand(&mut OsRng).into_affine(); + } + + // Now show it fails. + let mut transcript_f1 = Transcript::new(label); + let proof_f : EPAP = EPAP::create(&mut transcript_f1, &mut OsRng, a.x, a.y, b.x, b.y, tf.x, tf.y); + + let mut transcript_f2 = Transcript::new(label); + assert!(!proof_f.verify(&mut transcript_f2)); +} diff --git a/src/t256/src/fields/fq.rs b/src/t256/src/fields/fq.rs index 5840484..6f3a38c 100644 --- a/src/t256/src/fields/fq.rs +++ b/src/t256/src/fields/fq.rs @@ -1,4 +1,5 @@ use ark_ff::fields::{Fp256, MontBackend, MontConfig}; + #[derive(MontConfig)] #[modulus = "115792089210356248762697446949407573530594504085698471288169790229257723883799"] #[generator = "3"] diff --git a/src/t384/src/curves/mod.rs b/src/t384/src/curves/mod.rs index 91600f8..d7635f1 100644 --- a/src/t384/src/curves/mod.rs +++ b/src/t384/src/curves/mod.rs @@ -5,11 +5,63 @@ use ark_ec::{ use pedersen::pedersen_config::PedersenConfig; -use ark_ff::{Field, MontFp}; +use ark_ff::{Field, MontFp, MontConfig}; +use ark_ff::{BigInt}; -use crate::{fq::Fq, fr::Fr}; +use crate::{fq::Fq, fr::Fr, fr::FrConfig}; use ark_secp384r1::Config as secp384r1conf; +use ark_secp384r1::Fq as secp384r1Fq; +use ark_secp384r1::FqConfig as secp384FqConfig; +type OtherBaseField = ::BaseField; + +// Define the various conversion structs. +struct FrStruct(Fr); +impl FrStruct { + pub fn new(x: Fr) -> FrStruct { + FrStruct(x) + } + + pub fn as_fr(&self) -> Fr { + self.0 + } +} + +impl From> for FrStruct { + fn from(x: BigInt<6>) -> Self { + let x_t = FrConfig::from_bigint(x).unwrap(); + FrStruct::new(x_t) + } +} + +impl Into> for FrStruct { + fn into(self) -> BigInt<6> { + FrConfig::into_bigint(self.0) + } +} + +struct Secp384r1base(OtherBaseField); + +impl Secp384r1base { + + pub fn new(x: secp384r1Fq) -> Secp384r1base { + Secp384r1base(x) + } +} + + +impl Into> for Secp384r1base { + fn into(self) -> BigInt<6> { + secp384FqConfig::into_bigint(self.0) + } +} + +impl From> for Secp384r1base { + fn from(x: BigInt<6>) -> Self { + let x_t = secp384FqConfig::from_bigint(x).unwrap(); + Secp384r1base::new(x_t) + } +} #[cfg(test)] mod tests; @@ -50,6 +102,12 @@ impl PedersenConfig for Config { /// GENERATOR2 = (G_GENERATOR_X2, G_GENERATOR_Y2) const GENERATOR2: Affine = Affine::new_unchecked(G_GENERATOR_X2, G_GENERATOR_Y2); + + fn from_ob_to_sf(x: OtherBaseField) -> ::ScalarField { + let x_t : BigInt<6> = x.into(); + let x_v : FrStruct = FrStruct::from(x_t); + x_v.as_fr() + } } diff --git a/src/t384/src/curves/tests.rs b/src/t384/src/curves/tests.rs index dfd987d..09466bd 100644 --- a/src/t384/src/curves/tests.rs +++ b/src/t384/src/curves/tests.rs @@ -6,15 +6,18 @@ use ark_ec::{ models::CurveConfig, short_weierstrass::{self as sw}, AffineRepr, + CurveGroup, }; -use pedersen::{pedersen_config::PedersenComm, pedersen_config::PedersenConfig, equality_protocol::EqualityProof as EP, opening_protocol::OpeningProof as OP, mul_protocol::MulProof as MP}; +use pedersen::{pedersen_config::PedersenComm, pedersen_config::PedersenConfig, equality_protocol::EqualityProof as EP, opening_protocol::OpeningProof as OP, mul_protocol::MulProof as MP, ec_point_add_protocol::ECPointAddProof as EPAP}; use rand_core::OsRng; use merlin::Transcript; +use ark_secp384r1::Config as secp384r1conf; test_group!(g1; Projective; sw); type PC = PedersenComm; +type OtherProjectiveType = sw::Projective; #[test] fn test_pedersen() { @@ -48,6 +51,21 @@ fn test_pedersen_add() { let c_act : sw::Affine = (c1.comm.into_group() + c2.comm).into(); assert!(c3.comm == c_act); assert!(c3.r == c1.r + c2.r); + + // Same if by reference. + let c3r = c1 + &c2; + assert!(c3r.comm == c_act); + assert!(c3r.r == c1.r + c2.r); + + // Or if by reference the other way. + let c3rv = &c1 + c2; + assert!(c3rv.comm == c_act); + assert!(c3rv.r == c1.r + c2.r); + + // Or even if both. + let c3rr = &c1 + &c2; + assert!(c3rr.comm == c_act); + assert!(c3rr.r == c1.r + c2.r); } #[test] @@ -65,7 +83,24 @@ fn test_pedersen_sub() { let c_act : sw::Affine = (c1.comm.into_group() - c2.comm).into(); assert!(c3.comm == c_act); - assert!(c3.r == c1.r - c2.r); + assert!(c3.r == c1.r - c2.r); + + + // Same if by reference. + let c3r = c1 - &c2; + assert!(c3r.comm == c_act); + assert!(c3r.r == c1.r - c2.r); + + // Or if by reference the other way. + let c3rv = &c1 - c2; + assert!(c3rv.comm == c_act); + assert!(c3rv.r == c1.r - c2.r); + + // Or even if both. + let c3rr = &c1 - &c2; + assert!(c3rr.comm == c_act); + assert!(c3rr.r == c1.r - c2.r); + } #[test] @@ -213,7 +248,7 @@ fn test_pedersen_mul() { let c3 : PC = PC::new(z, &mut OsRng); let mut transcript = Transcript::new(label); - let proof = MP::create(&mut transcript, &mut OsRng, a, b, &c1, &c2, &c3); + let proof = MP::create(&mut transcript, &mut OsRng, &a, &b, &c1, &c2, &c3); assert!(proof.alpha.is_on_curve()); assert!(proof.beta.is_on_curve()); assert!(proof.delta.is_on_curve()); @@ -254,7 +289,7 @@ fn test_pedersen_mul_nist() { let c3 : PC = PC::new(z, &mut OsRng); let mut transcript = Transcript::new(label); - let proof = MP::create(&mut transcript, &mut OsRng, a, b, &c1, &c2, &c3); + let proof = MP::create(&mut transcript, &mut OsRng, &a, &b, &c1, &c2, &c3); assert!(proof.alpha.is_on_curve()); assert!(proof.beta.is_on_curve()); assert!(proof.delta.is_on_curve()); @@ -276,3 +311,50 @@ fn test_pedersen_mul_nist() { let mut transcript_f = Transcript::new(label); assert!(!proof.verify(&mut transcript_f, &c1, &c2, &c4)); } + + +#[test] +fn test_pedersen_point_add() { + // Test that the point addition proof goes through. + let label = b"PedersenECPointAdd"; + let a = OtherProjectiveType::rand(&mut OsRng).into_affine(); + let mut b = OtherProjectiveType::rand(&mut OsRng).into_affine(); + + loop { + if b != a { break; } + b = OtherProjectiveType::rand(&mut OsRng).into_affine(); + } + + // Note: this needs to be forced into affine too, or the underlying + // proof system breaks (this seems to be an ark_ff thing). + let t = (a + b).into_affine(); + + let mut transcript = Transcript::new(label); + let proof : EPAP = EPAP::create(&mut transcript, &mut OsRng, a.x, a.y, b.x, b.y, t.x, t.y); + + assert!(proof.c1.comm.is_on_curve()); + assert!(proof.c2.comm.is_on_curve()); + assert!(proof.c3.comm.is_on_curve()); + assert!(proof.c4.comm.is_on_curve()); + assert!(proof.c5.comm.is_on_curve()); + assert!(proof.c6.comm.is_on_curve()); + assert!(proof.c7.comm.is_on_curve()); + + // Now check that it verifies. + let mut transcript_v = Transcript::new(label); + assert!(proof.verify(&mut transcript_v)); + + // Alternatively, generate a false proof and watch it fail. + let mut tf = OtherProjectiveType::rand(&mut OsRng).into_affine(); + loop { + if tf != t { break; } + tf = OtherProjectiveType::rand(&mut OsRng).into_affine(); + } + + // Now show it fails. + let mut transcript_f1 = Transcript::new(label); + let proof_f : EPAP = EPAP::create(&mut transcript_f1, &mut OsRng, a.x, a.y, b.x, b.y, tf.x, tf.y); + + let mut transcript_f2 = Transcript::new(label); + assert!(!proof_f.verify(&mut transcript_f2)); +}