use ark_ec::{CurveGroup, Group}; use ark_std::{ rand::{Rng, RngCore}, UniformRand, }; use std::marker::PhantomData; use crate::utils::{naive_msm, vec_add, vector_elem_product}; use crate::transcript::Transcript; use ark_crypto_primitives::sponge::Absorb; pub struct Proof_elem { R: C, t1: C::ScalarField, t2: C::ScalarField, } pub struct Proof { R: C, u_: Vec, ru_: C::ScalarField, } pub struct Params { g: C, h: C, pub generators: Vec, } pub struct Pedersen where ::ScalarField: Absorb, ::BaseField: Absorb, { _c: PhantomData, } impl Pedersen where ::ScalarField: Absorb, ::BaseField: Absorb, { pub fn new_params(rng: &mut R, max: usize) -> Params { let h_scalar = C::ScalarField::rand(rng); let g: C = C::generator(); let generators: Vec = vec![C::rand(rng); max]; let params: Params = Params:: { g, h: g.mul(h_scalar), generators, }; params } pub fn commit_elem( rng: &mut R, params: &Params, v: &C::ScalarField, ) -> CommitmentElem { let r = C::ScalarField::rand(rng); let cm: C = params.g.mul(v) + params.h.mul(r); CommitmentElem:: { cm, r } } pub fn commit( params: &Params, v: &Vec, r: &C::ScalarField, // random value is provided, in order to be choosen by other parts of the protocol ) -> Commitment { let cm = params.h.mul(r) + naive_msm(v, ¶ms.generators); Commitment::(cm) } pub fn prove_elem( params: &Params, transcript: &mut Transcript, cm: C, v: C::ScalarField, r: C::ScalarField, ) -> Proof_elem { let r1 = transcript.get_challenge(); let r2 = transcript.get_challenge(); let R: C = params.g.mul(r1) + params.h.mul(r2); transcript.add_point(&cm); transcript.add_point(&R); let e = transcript.get_challenge(); let t1 = r1 + v * e; let t2 = r2 + r * e; Proof_elem:: { R, t1, t2 } } pub fn prove( params: &Params, transcript: &mut Transcript, cm: &Commitment, // TODO maybe it makes sense to not have a type wrapper and use directly C v: &Vec, r: &C::ScalarField, ) -> Proof { let r1 = transcript.get_challenge(); let d = transcript.get_challenge_vec(v.len()); let R: C = params.h.mul(r1) + naive_msm(&d, ¶ms.generators); transcript.add_point(&cm.0); transcript.add_point(&R); let e = transcript.get_challenge(); let u_ = vec_add(&vector_elem_product(v, &e), &d); let ru_ = e * r + r1; Proof:: { R, u_, ru_ } } pub fn verify( params: &Params, transcript: &mut Transcript, cm: Commitment, proof: Proof, ) -> bool { // r1, d just to match Prover's transcript transcript.get_challenge(); // r_1 transcript.get_challenge_vec(proof.u_.len()); // d transcript.add_point(&cm.0); transcript.add_point(&proof.R); let e = transcript.get_challenge(); let lhs = proof.R + cm.0.mul(e); let rhs = params.h.mul(proof.ru_) + naive_msm(&proof.u_, ¶ms.generators); if lhs != rhs { return false; } true } pub fn verify_elem( params: &Params, transcript: &mut Transcript, cm: C, proof: Proof_elem, ) -> bool { // s1, s2 just to match Prover's transcript transcript.get_challenge(); // r_1 transcript.get_challenge(); // r_2 transcript.add_point(&cm); transcript.add_point(&proof.R); let e = transcript.get_challenge(); let lhs = proof.R + cm.mul(e); let rhs = params.g.mul(proof.t1) + params.h.mul(proof.t2); if lhs != rhs { return false; } true } } #[derive(Clone, Debug)] pub struct Commitment(pub C); pub struct CommitmentElem { pub cm: C, pub r: C::ScalarField, } impl CommitmentElem where ::ScalarField: Absorb, ::BaseField: Absorb, { pub fn prove( &self, params: &Params, transcript: &mut Transcript, v: C::ScalarField, ) -> Proof_elem { Pedersen::::prove_elem(params, transcript, self.cm, v, self.r) } } #[cfg(test)] mod tests { use super::*; use crate::transcript::poseidon_test_config; use ark_mnt4_298::{Fr, G1Projective}; #[test] fn test_pedersen_single_element() { let mut rng = ark_std::test_rng(); // setup params let params = Pedersen::::new_params( &mut rng, 0, /* 0, as here we don't use commit_vec */ ); let poseidon_config = poseidon_test_config::(); // init Prover's transcript let mut transcript_p = Transcript::::new(&poseidon_config); // init Verifier's transcript let mut transcript_v = Transcript::::new(&poseidon_config); let v = Fr::rand(&mut rng); let cm = Pedersen::commit_elem(&mut rng, ¶ms, &v); let proof = cm.prove(¶ms, &mut transcript_p, v); // also can use: // let proof = Pedersen::prove_elem(¶ms, &mut transcript_p, cm.cm, v, cm.r); let v = Pedersen::verify_elem(¶ms, &mut transcript_v, cm.cm, proof); assert!(v); } #[test] fn test_pedersen_vector() { let mut rng = ark_std::test_rng(); const n: usize = 10; // setup params let params = Pedersen::::new_params(&mut rng, n); let poseidon_config = poseidon_test_config::(); // init Prover's transcript let mut transcript_p = Transcript::::new(&poseidon_config); // init Verifier's transcript let mut transcript_v = Transcript::::new(&poseidon_config); let v: Vec = vec![Fr::rand(&mut rng); n]; let r: Fr = Fr::rand(&mut rng); let cm = Pedersen::commit(¶ms, &v, &r); let proof = Pedersen::prove(¶ms, &mut transcript_p, &cm, &v, &r); let v = Pedersen::verify(¶ms, &mut transcript_v, cm, proof); assert!(v); } }