Browse Source

port pedersen.rs & transcript.rs from https://github.com/arnaucube/nova-study

main
arnaucube 1 year ago
parent
commit
95078deca2
5 changed files with 344 additions and 13 deletions
  1. +11
    -0
      Cargo.toml
  2. +7
    -13
      src/lib.rs
  3. +232
    -0
      src/pedersen.rs
  4. +77
    -0
      src/transcript.rs
  5. +17
    -0
      src/utils.rs

+ 11
- 0
Cargo.toml

@ -6,3 +6,14 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [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" }
ark-crypto-primitives = { version = "^0.4.0", default-features = false, features = [ "r1cs", "snark", "sponge", "crh" ] }
[dev-dependencies]
ark-bls12-381 = "0.4.0"

+ 7
- 13
src/lib.rs

@ -1,14 +1,8 @@
pub fn add(left: usize, right: usize) -> usize {
left + right
}
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(unused)] // TMP
#![allow(dead_code)] // TMP
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
pub mod pedersen;
pub mod transcript;
pub mod utils;

+ 232
- 0
src/pedersen.rs

@ -0,0 +1,232 @@
/// pedersen.rs file and adapted from https://github.com/arnaucube/nova-study
use ark_ec::{CurveGroup, Group};
use ark_std::{
rand::{Rng, RngCore},
UniformRand,
};
use std::marker::PhantomData;
use crate::utils::{vec_add, vec_scalar_mul};
use crate::transcript::Transcript;
use ark_crypto_primitives::sponge::Absorb;
pub struct ProofElem<C: CurveGroup> {
R: C,
t1: C::ScalarField,
t2: C::ScalarField,
}
pub struct Proof<C: CurveGroup> {
R: C,
u_: Vec<C::ScalarField>,
ru_: C::ScalarField,
}
pub struct Params<C: CurveGroup> {
g: C,
h: C,
pub generators: Vec<C::Affine>,
}
pub struct Pedersen<C: CurveGroup>
where
<C as Group>::ScalarField: Absorb,
<C as CurveGroup>::BaseField: Absorb,
{
_c: PhantomData<C>,
}
impl<C: CurveGroup> Pedersen<C>
where
<C as Group>::ScalarField: Absorb,
<C as CurveGroup>::BaseField: Absorb,
{
pub fn new_params<R: Rng>(rng: &mut R, max: usize) -> Params<C> {
let h_scalar = C::ScalarField::rand(rng);
let g: C = C::generator();
let generators: Vec<C::Affine> = vec![C::Affine::rand(rng); max];
let params: Params<C> = Params::<C> {
g,
h: g.mul(h_scalar),
generators,
};
params
}
pub fn commit_elem<R: RngCore>(
rng: &mut R,
params: &Params<C>,
v: &C::ScalarField,
) -> CommitmentElem<C> {
let r = C::ScalarField::rand(rng);
let cm: C = params.g.mul(v) + params.h.mul(r);
CommitmentElem::<C> { cm, r }
}
pub fn commit(
params: &Params<C>,
v: &Vec<C::ScalarField>,
r: &C::ScalarField, // random value is provided, in order to be choosen by other parts of the protocol
) -> Commitment<C> {
let cm = params.h.mul(r) + C::msm(&params.generators, v).unwrap();
Commitment::<C>(cm)
}
pub fn prove_elem(
params: &Params<C>,
transcript: &mut Transcript<C::ScalarField, C>,
cm: C,
v: C::ScalarField,
r: C::ScalarField,
) -> ProofElem<C> {
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;
ProofElem::<C> { R, t1, t2 }
}
pub fn prove(
params: &Params<C>,
transcript: &mut Transcript<C::ScalarField, C>,
cm: &Commitment<C>, // TODO maybe it makes sense to not have a type wrapper and use directly C
v: &Vec<C::ScalarField>,
r: &C::ScalarField,
) -> Proof<C> {
let r1 = transcript.get_challenge();
let d = transcript.get_challenge_vec(v.len());
let R: C = params.h.mul(r1) + C::msm(&params.generators, &d).unwrap();
transcript.add_point(&cm.0);
transcript.add_point(&R);
let e = transcript.get_challenge();
let u_ = vec_add(&vec_scalar_mul(v, &e), &d);
let ru_ = e * r + r1;
Proof::<C> { R, u_, ru_ }
}
pub fn verify(
params: &Params<C>,
transcript: &mut Transcript<C::ScalarField, C>,
cm: Commitment<C>,
proof: Proof<C>,
) -> 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_) + C::msm(&params.generators, &proof.u_).unwrap();
if lhs != rhs {
return false;
}
true
}
pub fn verify_elem(
params: &Params<C>,
transcript: &mut Transcript<C::ScalarField, C>,
cm: C,
proof: ProofElem<C>,
) -> 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<C: CurveGroup>(pub C);
pub struct CommitmentElem<C: CurveGroup> {
pub cm: C,
pub r: C::ScalarField,
}
impl<C: CurveGroup> CommitmentElem<C>
where
<C as Group>::ScalarField: Absorb,
<C as CurveGroup>::BaseField: Absorb,
{
pub fn prove(
&self,
params: &Params<C>,
transcript: &mut Transcript<C::ScalarField, C>,
v: C::ScalarField,
) -> ProofElem<C> {
Pedersen::<C>::prove_elem(params, transcript, self.cm, v, self.r)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::transcript::poseidon_test_config;
use ark_bls12_381::{Fr, G1Projective};
#[test]
fn test_pedersen_single_element() {
let mut rng = ark_std::test_rng();
// setup params
let params = Pedersen::<G1Projective>::new_params(
&mut rng, 0, /* 0, as here we don't use commit_vec */
);
let poseidon_config = poseidon_test_config::<Fr>();
// init Prover's transcript
let mut transcript_p = Transcript::<Fr, G1Projective>::new(&poseidon_config);
// init Verifier's transcript
let mut transcript_v = Transcript::<Fr, G1Projective>::new(&poseidon_config);
let v = Fr::rand(&mut rng);
let cm = Pedersen::commit_elem(&mut rng, &params, &v);
let proof = cm.prove(&params, &mut transcript_p, v);
// also can use:
// let proof = Pedersen::prove_elem(&params, &mut transcript_p, cm.cm, v, cm.r);
let v = Pedersen::verify_elem(&params, &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::<G1Projective>::new_params(&mut rng, n);
let poseidon_config = poseidon_test_config::<Fr>();
// init Prover's transcript
let mut transcript_p = Transcript::<Fr, G1Projective>::new(&poseidon_config);
// init Verifier's transcript
let mut transcript_v = Transcript::<Fr, G1Projective>::new(&poseidon_config);
let v: Vec<Fr> = vec![Fr::rand(&mut rng); n];
let r: Fr = Fr::rand(&mut rng);
let cm = Pedersen::commit(&params, &v, &r);
let proof = Pedersen::prove(&params, &mut transcript_p, &cm, &v, &r);
let v = Pedersen::verify(&params, &mut transcript_v, cm, proof);
assert!(v);
}
}

+ 77
- 0
src/transcript.rs

@ -0,0 +1,77 @@
/// transcript.rs file and adapted from https://github.com/arnaucube/nova-study
use ark_ec::{AffineRepr, CurveGroup};
use ark_ff::PrimeField;
use std::marker::PhantomData;
use ark_crypto_primitives::sponge::poseidon::{PoseidonConfig, PoseidonSponge};
use ark_crypto_primitives::sponge::{Absorb, CryptographicSponge};
pub struct Transcript<F: PrimeField + Absorb, C: CurveGroup>
where
<C as CurveGroup>::BaseField: Absorb,
{
// where F is the Constraint Field (eq. C::ScalarField)
sponge: PoseidonSponge<F>,
_c: PhantomData<C>,
}
impl<F: PrimeField + Absorb, C: CurveGroup> Transcript<F, C>
where
<C as CurveGroup>::BaseField: Absorb,
{
pub fn new(poseidon_config: &PoseidonConfig<F>) -> Self {
let sponge = PoseidonSponge::<F>::new(poseidon_config);
Transcript {
sponge,
_c: PhantomData,
}
}
pub fn add(&mut self, v: &F) {
self.sponge.absorb(&v);
}
pub fn add_vec(&mut self, v: &[F]) {
self.sponge.absorb(&v);
}
pub fn add_point(&mut self, v: &C) {
let v_affine = v.into_affine();
let xy = v_affine.xy().unwrap(); // WIP
self.sponge.absorb(&vec![xy.0, xy.1]);
}
pub fn get_challenge(&mut self) -> F {
let c = self.sponge.squeeze_field_elements(1);
self.add(&c[0]);
c[0]
}
pub fn get_challenge_vec(&mut self, n: usize) -> Vec<F> {
let c = self.sponge.squeeze_field_elements(n);
self.sponge.absorb(&c);
c
}
}
use ark_crypto_primitives::sponge::poseidon::find_poseidon_ark_and_mds;
// WARNING this is for test only
pub fn poseidon_test_config<F: PrimeField>() -> PoseidonConfig<F> {
let full_rounds = 8;
let partial_rounds = 31;
let alpha = 5;
let rate = 2;
let (ark, mds) = find_poseidon_ark_and_mds::<F>(
F::MODULUS_BIT_SIZE as u64,
rate,
full_rounds,
partial_rounds,
0,
);
PoseidonConfig::new(
full_rounds as usize,
partial_rounds as usize,
alpha,
mds,
ark,
rate,
1,
)
}

+ 17
- 0
src/utils.rs

@ -0,0 +1,17 @@
use ark_ff::fields::PrimeField;
pub fn vec_add<F: PrimeField>(a: &Vec<F>, b: &[F]) -> Vec<F> {
let mut r: Vec<F> = vec![F::zero(); a.len()];
for i in 0..a.len() {
r[i] = a[i] + b[i];
}
r
}
pub fn vec_scalar_mul<F: PrimeField>(vec: &[F], c: &F) -> Vec<F> {
let mut result = vec![F::zero(); vec.len()];
for (i, a) in vec.iter().enumerate() {
result[i] = *a * c;
}
result
}

Loading…
Cancel
Save