From 78f1c87313daf2df92ac59a2b4266943d9ef6cc5 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Mon, 17 Apr 2023 23:44:51 +0200 Subject: [PATCH] pedersen commitment with merlin transcript --- .gitignore | 2 + Cargo.toml | 19 ++++++++ src/pedersen.rs | 122 ++++++++++++++++++++++++++++++++++++++++++++++ src/transcript.rs | 32 ++++++++++++ 4 files changed, 175 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/pedersen.rs create mode 100644 src/transcript.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..cbccfb8 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "nova-study" +version = "0.0.1" +edition = "2021" +authors = ["arnaucube "] +license = "GPL-3.0" +repository = "https://github.com/arnaucube/nova-study" + +[dependencies] +ark-std = "0.4.0" +ark-ff = "0.4.0" +ark-ec = { version = "0.4.0", default-features = false } +ark-poly = "0.4.0" +ark-serialize = { version = "0.4.0", default-features = false, features = [ "derive" ] } +rand = { version = "0.8", features = [ "std", "std_rng" ] } +merlin = { version = "3.0.0" } + +[dev-dependencies] +ark-bn254 = { version = "0.4.0", default-features = false, features=["curve"] } diff --git a/src/pedersen.rs b/src/pedersen.rs new file mode 100644 index 0000000..2092ed1 --- /dev/null +++ b/src/pedersen.rs @@ -0,0 +1,122 @@ +use ark_ec::AffineRepr; +use ark_std::{rand::RngCore, UniformRand}; +use std::marker::PhantomData; + +use crate::transcript::Transcript; + +pub struct Proof { + R: C, + t1: C::ScalarField, + t2: C::ScalarField, +} + +pub struct Params { + g: C, + h: C, +} + +pub struct Pedersen { + _phantom: PhantomData, +} + +impl Pedersen { + pub fn commit( + rng: &mut R, + params: &Params, + v: &C::ScalarField, + ) -> (C, C::ScalarField) { + let r = C::ScalarField::rand(rng); + let cm: C = (params.g.mul(v) + params.h.mul(r)).into(); + (cm, r) + } + pub fn prove( + params: &Params, + transcript: &mut Transcript, + cm: C, + v: C::ScalarField, + r: C::ScalarField, + ) -> Proof { + let s1 = transcript.get_challenge(b"s_1"); + let s2 = transcript.get_challenge(b"s_2"); + + let R: C = (params.g.mul(s1) + params.h.mul(s2)).into(); + + transcript.add(b"cm", &cm); + transcript.add(b"R", &R); + let c = transcript.get_challenge(b"c"); + + let t1 = s1 + v * c; + let t2 = s2 + r * c; + + Proof:: { R, t1, t2 } + } + + pub fn verify( + params: &Params, + transcript: &mut Transcript, + cm: C, + proof: Proof, + ) -> bool { + // s1, s2 just to match Prover's transcript + transcript.get_challenge(b"s_1"); + transcript.get_challenge(b"s_2"); + + transcript.add(b"cm", &cm); + transcript.add(b"R", &proof.R); + let c = transcript.get_challenge(b"c"); + let lhs = proof.R + cm.mul(c); + let rhs = params.g.mul(proof.t1) + params.h.mul(proof.t2); + if lhs != rhs { + return false; + } + true + } +} + +pub struct Commitment { + pub cm: C, + pub r: C::ScalarField, +} +impl Commitment { + pub fn prove( + self, + params: &Params, + transcript: &mut Transcript, + v: C::ScalarField, + ) -> Proof { + Pedersen::::prove(params, transcript, self.cm, v, self.r) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use ark_bn254::{g1::G1Affine, Fr}; + use ark_ec::CurveGroup; + use std::ops::Mul; + + #[test] + fn test_pedersen() { + let mut rng = ark_std::test_rng(); + + // setup params + let h_scalar = Fr::rand(&mut rng); + let g: G1Affine = G1Affine::generator(); + let params: Params = Params:: { + g, + h: g.mul(h_scalar).into_affine(), + }; + + // init Prover's transcript + let mut transcript_p: Transcript = Transcript::::new(); + // init Verifier's transcript + let mut transcript_v: Transcript = Transcript::::new(); + + let v = Fr::rand(&mut rng); + + let (cm, r) = Pedersen::commit(&mut rng, ¶ms, &v); + let proof = Pedersen::prove(¶ms, &mut transcript_p, cm, v, r); + let v = Pedersen::verify(¶ms, &mut transcript_v, cm, proof); + assert!(v); + } +} diff --git a/src/transcript.rs b/src/transcript.rs new file mode 100644 index 0000000..499a5b6 --- /dev/null +++ b/src/transcript.rs @@ -0,0 +1,32 @@ +use ark_ff::PrimeField; +use ark_serialize::CanonicalSerialize; +use merlin::Transcript as MerlinTranscript; +use std::marker::PhantomData; + +// This Transcript approach is a modified version from https://github.com/arkworks-rs/gemini , +// using Merlin transcript (https://merlin.cool). +pub struct Transcript { + phantom: PhantomData, + transcript: MerlinTranscript, +} + +impl Transcript { + pub fn new() -> Self { + Self { + phantom: PhantomData::default(), + transcript: MerlinTranscript::new(b"transcript"), + } + } + pub fn add(&mut self, label: &'static [u8], r: &S) { + let mut msg = Vec::new(); + r.serialize_uncompressed(&mut msg).unwrap(); + self.transcript.append_message(label, &msg); + } + pub fn get_challenge(&mut self, label: &'static [u8]) -> F { + let mut bytes = [0u8; 64]; + self.transcript.challenge_bytes(label, &mut bytes); + let challenge = F::from_le_bytes_mod_order(bytes.as_ref()); + self.add(b"get challenge", &challenge); + challenge + } +}