Skip to content

Commit

Permalink
Add utils::vec & pedersen modules (#5)
Browse files Browse the repository at this point in the history
- utils::vec module: port a mix of vec utils from nova-study, multifolding-poc and protogalaxy-poc repos
- pedersen.rs: Pedersen commitment module
- other:
  - update FoldingScheme trait interface: rm rng, update internal types naming as agreed in today's call
  - update Cargo.toml dev-dependencies imports, since bn254 - grumpkin is not ready yet, use bls12-377 - bw6-761 curve cycle
  - transcript module: add absorb_point method
  • Loading branch information
arnaucube authored Aug 22, 2023
1 parent 77a0c8e commit bc81fbe
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 33 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ ark-r1cs-std = { version = "^0.4.0", default-features = false }
thiserror = "1.0"

[dev-dependencies]
ark-bls12-381 = "0.4.0"
ark-bls12-377 = "0.4.0"
ark-bw6-761 = "0.4.0"

[features]
default = []
24 changes: 11 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use thiserror::Error;

pub mod transcript;
use transcript::Transcript;
pub mod pedersen;
pub mod utils;

#[derive(Debug, Error)]
pub enum Error {
Expand All @@ -19,23 +21,21 @@ pub enum Error {
/// over a cycle of curves (C1, C2), where:
/// - C1 is the main curve, which ScalarField we use as our F for al the field operations
/// - C2 is the auxiliary curve, which we use for the commitments, whose BaseField (for point
/// coordinates) are in the C1::ScalarField
/// coordinates) are in the C1::ScalarField.
/// In other words, C1.Fq == C2.Fr, and C1.Fr == C2.Fq.
pub trait FoldingScheme<C1: CurveGroup, C2: CurveGroup>: Clone + Debug
where
C1: CurveGroup<BaseField = C2::ScalarField, ScalarField = C2::BaseField>,
C2::BaseField: PrimeField,
{
// type PCS: PolynomialCommitmentScheme<C>; // maybe not needed, just PedersenCommitment
type PreprocessorParam: Debug;
type ProverParam: Debug;
type VerifierParam: Debug;
type FreshInstance: Debug;
type PublicInput: Debug;
type Witness: Debug;
type CommittedInstanceWithWitness: Debug;
type CommittedInstance: Clone + Debug;

fn preprocess(
// pcs_param: &<Self::CS as PolynomialCommitmentScheme<C>>::Param,
prep_param: &Self::PreprocessorParam,
) -> Result<(Self::ProverParam, Self::VerifierParam), Error>;

Expand All @@ -46,17 +46,15 @@ where
fn prove(
pp: &Self::ProverParam,
running_instance: &mut Self::CommittedInstanceWithWitness,
incomming_instances: &[Self::FreshInstance],
transcript: &mut impl Transcript<C1::ScalarField>,
rng: impl RngCore,
incomming_instances: &[Self::Witness],
transcript: &mut impl Transcript<C1>,
) -> Result<(), Error>;

fn verify(
vp: &Self::VerifierParam,
running_instance: &mut Self::CommittedInstance,
incomming_instances: &[Self::PublicInput],
transcript: &mut impl Transcript<C1::ScalarField>,
rng: impl RngCore,
incomming_instances: &[Self::CommittedInstance],
transcript: &mut impl Transcript<C1>,
) -> Result<(), Error>;
}

Expand All @@ -72,14 +70,14 @@ pub trait Decider<C: CurveGroup>: Clone + Debug {
fn prove(
pp: &Self::ProverParam,
running_instance: &Self::CommittedInstanceWithWitness,
transcript: &mut impl Transcript<C::ScalarField>,
transcript: &mut impl Transcript<C>,
rng: impl RngCore,
) -> Result<(), Error>;

fn verify(
vp: &Self::VerifierParam,
running_instance: &Self::CommittedInstance,
transcript: &mut impl Transcript<C::ScalarField>,
transcript: &mut impl Transcript<C>,
rng: impl RngCore,
) -> Result<(), Error>;
}
127 changes: 127 additions & 0 deletions src/pedersen.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use ark_ec::{CurveGroup, Group};
use ark_std::{rand::Rng, UniformRand};
use std::marker::PhantomData;

use crate::utils::vec::{vec_add, vec_scalar_mul};

use crate::transcript::Transcript;
use ark_crypto_primitives::sponge::Absorb;

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Proof<C: CurveGroup> {
R: C,
u: Vec<C::ScalarField>,
r_u: C::ScalarField,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Params<C: CurveGroup> {
h: C,
pub generators: Vec<C::Affine>,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Pedersen<C: CurveGroup>
where
<C as Group>::ScalarField: Absorb,
{
_c: PhantomData<C>,
}

impl<C: CurveGroup> Pedersen<C>
where
<C as Group>::ScalarField: Absorb,
{
pub fn new_params<R: Rng>(rng: &mut R, max: usize) -> Params<C> {
let generators: Vec<C::Affine> = std::iter::repeat_with(|| C::Affine::rand(rng))
.take(max.next_power_of_two())
.collect();
let params: Params<C> = Params::<C> {
h: C::rand(rng),
generators,
};
params
}

pub fn commit(params: &Params<C>, v: &Vec<C::ScalarField>, r: &C::ScalarField) -> C {
// h⋅r + <g, v>
params.h.mul(r) + C::msm(&params.generators[..v.len()], v).unwrap()
}

pub fn prove(
params: &Params<C>,
transcript: &mut impl Transcript<C>,
cm: &C,
v: &Vec<C::ScalarField>,
r: &C::ScalarField,
) -> Proof<C> {
transcript.absorb_point(cm);
let r1 = transcript.get_challenge();
let d = transcript.get_challenges(v.len());

// R = h⋅r_1 + <g, d>
let R: C = params.h.mul(r1) + C::msm(&params.generators[..d.len()], &d).unwrap();

transcript.absorb_point(&R);
let e = transcript.get_challenge();

// u = d + v⋅e
let u = vec_add(&vec_scalar_mul(v, &e), &d);
// r_u = e⋅r + r_1
let r_u = e * r + r1;

Proof::<C> { R, u, r_u }
}

pub fn verify(
params: &Params<C>,
transcript: &mut impl Transcript<C>,
cm: C,
proof: Proof<C>,
) -> bool {
transcript.absorb_point(&cm);
transcript.get_challenge(); // r_1
transcript.get_challenges(proof.u.len()); // d
transcript.absorb_point(&proof.R);
let e = transcript.get_challenge();

// check that: R + cm == h⋅r_u + <g, u>
let lhs = proof.R + cm.mul(e);
let rhs = params.h.mul(proof.r_u)
+ C::msm(&params.generators[..proof.u.len()], &proof.u).unwrap();
if lhs != rhs {
return false;
}
true
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::transcript::poseidon::{tests::poseidon_test_config, PoseidonTranscript};

use ark_bls12_377::{Fr, G1Projective};

#[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 = PoseidonTranscript::<G1Projective>::new(&poseidon_config);
// init Verifier's transcript
let mut transcript_v = PoseidonTranscript::<G1Projective>::new(&poseidon_config);

let v: Vec<Fr> = vec![Fr::rand(&mut rng); n];
let r: Fr = Fr::rand(&mut rng);
let cm = Pedersen::<G1Projective>::commit(&params, &v, &r);
let proof = Pedersen::<G1Projective>::prove(&params, &mut transcript_p, &cm, &v, &r);
let v = Pedersen::<G1Projective>::verify(&params, &mut transcript_v, cm, proof);
assert!(v);
}
}
13 changes: 7 additions & 6 deletions src/transcript/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use ark_ff::PrimeField;
use ark_ec::CurveGroup;
use ark_std::fmt::Debug;

pub mod poseidon;

pub trait Transcript<F: PrimeField> {
pub trait Transcript<C: CurveGroup> {
type TranscriptConfig: Debug;

fn new(config: &Self::TranscriptConfig) -> Self;
fn absorb(&mut self, v: &F);
fn absorb_vec(&mut self, v: &[F]);
fn get_challenge(&mut self) -> F;
fn get_challenges(&mut self, n: usize) -> Vec<F>;
fn absorb(&mut self, v: &C::ScalarField);
fn absorb_vec(&mut self, v: &[C::ScalarField]);
fn absorb_point(&mut self, v: &C);
fn get_challenge(&mut self) -> C::ScalarField;
fn get_challenges(&mut self, n: usize) -> Vec<C::ScalarField>;
}
59 changes: 46 additions & 13 deletions src/transcript/poseidon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,75 @@ use ark_crypto_primitives::sponge::{
poseidon::{constraints::PoseidonSpongeVar, PoseidonConfig, PoseidonSponge},
Absorb, CryptographicSponge,
};
use ark_ff::PrimeField;
use ark_ec::{AffineRepr, CurveGroup, Group};
use ark_ff::{BigInteger, Field, PrimeField};
use ark_r1cs_std::fields::fp::FpVar;
use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};

use crate::transcript::Transcript;

/// PoseidonTranscript implements the Transcript trait using the Poseidon hash
pub struct PoseidonTranscript<F: PrimeField + Absorb> {
sponge: PoseidonSponge<F>,
pub struct PoseidonTranscript<C: CurveGroup>
where
<C as Group>::ScalarField: Absorb,
{
sponge: PoseidonSponge<C::ScalarField>,
}

impl<F: PrimeField + Absorb> Transcript<F> for PoseidonTranscript<F> {
type TranscriptConfig = PoseidonConfig<F>;
impl<C: CurveGroup> Transcript<C> for PoseidonTranscript<C>
where
<C as Group>::ScalarField: Absorb,
{
type TranscriptConfig = PoseidonConfig<C::ScalarField>;

fn new(poseidon_config: &Self::TranscriptConfig) -> Self {
let sponge = PoseidonSponge::<F>::new(poseidon_config);
let sponge = PoseidonSponge::<C::ScalarField>::new(poseidon_config);
Self { sponge }
}
fn absorb(&mut self, v: &F) {
fn absorb(&mut self, v: &C::ScalarField) {
self.sponge.absorb(&v);
}
fn absorb_vec(&mut self, v: &[F]) {
fn absorb_vec(&mut self, v: &[C::ScalarField]) {
self.sponge.absorb(&v);
}
fn get_challenge(&mut self) -> F {
fn absorb_point(&mut self, p: &C) {
self.sponge.absorb(&prepare_point(p));
}
fn get_challenge(&mut self) -> C::ScalarField {
let c = self.sponge.squeeze_field_elements(1);
self.sponge.absorb(&c[0]);
c[0]
}
fn get_challenges(&mut self, n: usize) -> Vec<F> {
fn get_challenges(&mut self, n: usize) -> Vec<C::ScalarField> {
let c = self.sponge.squeeze_field_elements(n);
self.sponge.absorb(&c);
c
}
}

// Returns the point coordinates in Fr, so it can be absrobed by the transcript. It does not work
// over bytes in order to have a logic that can be reproduced in-circuit.
fn prepare_point<C: CurveGroup>(p: &C) -> Vec<C::ScalarField> {
let binding = p.into_affine();
let p_coords = &binding.xy().unwrap();
let x_bi = p_coords
.0
.to_base_prime_field_elements()
.next()
.expect("a")
.into_bigint();
let y_bi = p_coords
.1
.to_base_prime_field_elements()
.next()
.expect("a")
.into_bigint();
vec![
C::ScalarField::from_le_bytes_mod_order(x_bi.to_bytes_le().as_ref()),
C::ScalarField::from_le_bytes_mod_order(y_bi.to_bytes_le().as_ref()),
]
}

/// PoseidonTranscriptVar implements the gadget compatible with PoseidonTranscript
pub struct PoseidonTranscriptVar<F: PrimeField> {
sponge: PoseidonSpongeVar<F>,
Expand Down Expand Up @@ -67,9 +100,9 @@ impl<F: PrimeField> PoseidonTranscriptVar<F> {
}

#[cfg(test)]
mod tests {
pub mod tests {
use super::*;
use ark_bls12_381::Fr;
use ark_bls12_377::{Fr, G1Projective};
use ark_crypto_primitives::sponge::poseidon::find_poseidon_ark_and_mds;
use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, R1CSVar};
use ark_relations::r1cs::ConstraintSystem;
Expand Down Expand Up @@ -105,7 +138,7 @@ mod tests {
fn test_transcript_and_transcriptvar() {
// use 'native' transcript
let config = poseidon_test_config::<Fr>();
let mut tr = PoseidonTranscript::<Fr>::new(&config);
let mut tr = PoseidonTranscript::<G1Projective>::new(&config);
tr.absorb(&Fr::from(42_u32));
let c = tr.get_challenge();

Expand Down
1 change: 1 addition & 0 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod vec;
Loading

0 comments on commit bc81fbe

Please sign in to comment.