Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic structure and point addition proofs #22

Merged
merged 7 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 15 additions & 0 deletions src/pedersen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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 }
157 changes: 157 additions & 0 deletions src/pedersen/src/ec_point_add_protocol.rs
Original file line number Diff line number Diff line change
@@ -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<P: PedersenConfig> {
/// c1: the commitment to a_x.
pub c1: PedersenComm<P>,
/// c2: the commitment to a_y.
pub c2: PedersenComm<P>,
/// c3: the commitment to b_x.
pub c3: PedersenComm<P>,
/// c4: the commitment to b_y.
pub c4: PedersenComm<P>,
/// c5: the commitment to t_x.
pub c5: PedersenComm<P>,
/// c6: the commitment to t_y.
pub c6: PedersenComm<P>,

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

/// mp1: the multiplication proof that verifies that equation 1 holds.
pub mp1: MulProof<P>,

/// mp2: the multiplication proof that verifies that equation 2 holds.
pub mp2: MulProof<P>,

/// mp3: the multiplication proof that verifies that equation 3 holds.
pub mp3: MulProof<P>,

/// op: the opening proof of C2.
pub op: OpeningProof<P>,
}

impl <P: PedersenConfig> ECPointAddProof<P> {
fn make_transcript(transcript: &mut Transcript,
c1: &PedersenComm<P>,
c2: &PedersenComm<P>,
c3: &PedersenComm<P>,
c4: &PedersenComm<P>,
c5: &PedersenComm<P>,
c6: &PedersenComm<P>,
c7: &PedersenComm<P>) {

// 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<T: RngCore + CryptoRng> (val: <<P as PedersenConfig>::OCurve as CurveConfig>::BaseField, rng: &mut T) -> PedersenComm<P> {
let val_p = <P as PedersenConfig>::from_ob_to_sf(val);
PedersenComm::new(val_p, rng)
}

pub fn create<T: RngCore + CryptoRng>(transcript: &mut Transcript,
rng: &mut T,
a_x: <<P as PedersenConfig>::OCurve as CurveConfig>::BaseField,
a_y: <<P as PedersenConfig>::OCurve as CurveConfig>::BaseField,
b_x: <<P as PedersenConfig>::OCurve as CurveConfig>::BaseField,
b_y: <<P as PedersenConfig>::OCurve as CurveConfig>::BaseField,
t_x: <<P as PedersenConfig>::OCurve as CurveConfig>::BaseField,
t_y: <<P as PedersenConfig>::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 = <P as PedersenConfig>::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 = <P as PedersenConfig>::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 = <P as PedersenConfig>::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)
}
}

77 changes: 77 additions & 0 deletions src/pedersen/src/equality_protocol.rs
Original file line number Diff line number Diff line change
@@ -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<P: PedersenConfig> {
pub alpha: sw::Affine<P>,
pub z : <P as CurveConfig>::ScalarField,
}

impl<P: PedersenConfig> EqualityProof<P> {

fn make_transcript(transcript: &mut Transcript,
c1: &PedersenComm<P>,
c2: &PedersenComm<P>,
alpha_p: &sw::Affine<P>) {
// 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) -> <P as CurveConfig>::ScalarField {
<P as CurveConfig>::ScalarField::deserialize_compressed(&transcript.challenge_scalar(b"c")[..]).unwrap()
}


pub fn create<T: RngCore + CryptoRng>(transcript: &mut Transcript,
rng: &mut T,
c1: &PedersenComm<P>,
c2: &PedersenComm<P>) -> EqualityProof<P> {

let r = <P as CurveConfig>::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<P>, c2: &PedersenComm<P>) -> 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
}
}

7 changes: 7 additions & 0 deletions src/pedersen/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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;
113 changes: 113 additions & 0 deletions src/pedersen/src/mul_protocol.rs
Original file line number Diff line number Diff line change
@@ -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<P: PedersenConfig> {
pub alpha: sw::Affine<P>,
pub beta: sw::Affine<P>,
pub delta: sw::Affine<P>,

pub z1: <P as CurveConfig>::ScalarField,
pub z2: <P as CurveConfig>::ScalarField,
pub z3: <P as CurveConfig>::ScalarField,
pub z4: <P as CurveConfig>::ScalarField,
pub z5: <P as CurveConfig>::ScalarField,
}

impl <P: PedersenConfig> MulProof<P> {

fn make_transcript(transcript: &mut Transcript,
c1: &PedersenComm<P>,
c2: &PedersenComm<P>,
c3: &PedersenComm<P>,
alpha: &sw::Affine<P>,
beta: &sw::Affine<P>,
delta: &sw::Affine<P>) {

// 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) -> <P as CurveConfig>::ScalarField {
<P as CurveConfig>::ScalarField::deserialize_compressed(&transcript.challenge_scalar(b"c")[..]).unwrap()
}

pub fn create<T: RngCore + CryptoRng>(transcript: &mut Transcript,
rng: &mut T,
x: &<P as CurveConfig>::ScalarField,
y: &<P as CurveConfig>::ScalarField,
c1: &PedersenComm<P>,
c2: &PedersenComm<P>,
c3: &PedersenComm<P>) -> Self {

// Generate the random values.
let b1 = <P as CurveConfig>::ScalarField::rand(rng);
let b2 = <P as CurveConfig>::ScalarField::rand(rng);
let b3 = <P as CurveConfig>::ScalarField::rand(rng);
let b4 = <P as CurveConfig>::ScalarField::rand(rng);
let b5 = <P as CurveConfig>::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<P>, c2: &PedersenComm<P>, c3: &PedersenComm<P>) -> 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))
}
}
Loading