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..0cfb6e0 --- /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"} +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/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/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 new file mode 100644 index 0000000..3009f47 --- /dev/null +++ b/src/pedersen/src/lib.rs @@ -0,0 +1,7 @@ +#![forbid(unsafe_code)] +pub mod transcript; +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 new file mode 100644 index 0000000..49c741f --- /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 new file mode 100644 index 0000000..4518ffb --- /dev/null +++ b/src/pedersen/src/pedersen_config.rs @@ -0,0 +1,108 @@ +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 { + /// 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; + + 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(Copy, Clone)] +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::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

; + + 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<&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); + 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..c497401 --- /dev/null +++ b/src/pedersen/src/transcript.rs @@ -0,0 +1,117 @@ +//! 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 + } +} + +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/Cargo.toml b/src/t256/Cargo.toml index 307671a..a1d5e58 100644 --- a/src/t256/Cargo.toml +++ b/src/t256/Cargo.toml @@ -10,6 +10,11 @@ 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" } +merlin = { version = "3.0.0" } [dev-dependencies] ark-relations = { version = "0.4.0", default-features = false } @@ -17,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 3b4c502..058add4 100644 --- a/src/t256/src/curves/mod.rs +++ b/src/t256/src/curves/mod.rs @@ -3,9 +3,68 @@ use ark_ec::{ short_weierstrass::{self as sw, SWCurveConfig}, }; -use ark_ff::{Field, MontFp}; -use crate::{fq::Fq, fr::Fr}; +use pedersen::pedersen_config::PedersenConfig; + +use ark_ff::{Field, MontFp, MontConfig}; +use ark_ff::{BigInt}; + +use crate::{fq::Fq, fr::Fr, fr::FrConfig}; + + +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; @@ -41,13 +100,37 @@ impl SWCurveConfig for Config { const GENERATOR : Affine = Affine::new_unchecked(G_GENERATOR_X, G_GENERATOR_Y); } +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 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"); +// 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 10ca142..472e3f5 100644 --- a/src/t256/src/curves/tests.rs +++ b/src/t256/src/curves/tests.rs @@ -1,3 +1,360 @@ -use crate::Projective; +use crate::{Projective, Config}; use ark_algebra_test_templates::*; +use ark_std::{UniformRand}; + +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, 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() { + // 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_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_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); + + // 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] +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); + + + // 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] +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_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. + 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_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. + 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)); +} + +#[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)); +} + + +#[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 d7ab609..6f3a38c 100644 --- a/src/t256/src/fields/fq.rs +++ b/src/t256/src/fields/fq.rs @@ -3,6 +3,5 @@ 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/Cargo.toml b/src/t384/Cargo.toml index 79a4d24..8501552 100644 --- a/src/t384/Cargo.toml +++ b/src/t384/Cargo.toml @@ -10,6 +10,11 @@ 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" } +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 45cf139..d7635f1 100644 --- a/src/t384/src/curves/mod.rs +++ b/src/t384/src/curves/mod.rs @@ -1,11 +1,67 @@ use ark_ec::{ models::CurveConfig, - short_weierstrass::{self as sw, SWCurveConfig}, + short_weierstrass::{self as sw, SWCurveConfig}, }; -use ark_ff::{Field, MontFp}; +use pedersen::pedersen_config::PedersenConfig; -use crate::{fq::Fq, fr::Fr}; +use ark_ff::{Field, MontFp, MontConfig}; +use ark_ff::{BigInt}; + +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; @@ -41,13 +97,29 @@ impl SWCurveConfig for Config { const GENERATOR : Affine = Affine::new_unchecked(G_GENERATOR_X, G_GENERATOR_Y); } +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); + + 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() + } +} + + /// 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..09466bd 100644 --- a/src/t384/src/curves/tests.rs +++ b/src/t384/src/curves/tests.rs @@ -1,3 +1,360 @@ -use crate::Projective; +use crate::{Projective, Config}; use ark_algebra_test_templates::*; +use ark_std::{UniformRand}; + +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, 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() { + // 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_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_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); + + // 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] +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); + + + // 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] +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_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. + 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_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. + 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)); +} + +#[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)); +} + + +#[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/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>; 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.