Browse Source

Implement poseidon based Transcript & integrate it

- remove Merlin based transcript
- implement poseidon based Transcript
- implement TranscriptVar gadget
- update transcript usage in the other modules to new Transcript
  interface
ivc-proofs
arnaucube 1 year ago
parent
commit
7cf729f00a
6 changed files with 236 additions and 106 deletions
  1. +1
    -1
      README.md
  2. +6
    -2
      src/circuits.rs
  3. +26
    -13
      src/nifs.rs
  4. +53
    -35
      src/pedersen.rs
  5. +36
    -25
      src/sumcheck.rs
  6. +114
    -30
      src/transcript.rs

+ 1
- 1
README.md

@ -9,4 +9,4 @@ This repo is an ongoing implementation, the code will be dirty for a while and n
Thanks to [Levs57](https://twitter.com/levs57), [Nalin Bhardwaj](https://twitter.com/nibnalin) and [Carlos Pérez](https://twitter.com/cperezz19) for clarifications on the Nova paper.
### Details
Initial impl using a cycle of pairing-friendly curves with Groth16 for the folding proofs (as an example, the tests use MNT4, MNT6 curves), once the full scheme works, will see how many constraints the folding circuits need and might change one of the sides to a non-pairing curve with a non-pairing proof instead of Groth16. Eventually would like to explore also using BN254 with Grumpkin for ending up verifying the proofs in Ethereum.
Current implementation uses a cycle of pairing-friendly curves with Groth16 for the folding proofs (as an example, the tests use MNT4, MNT6 curves), once the full scheme works, will see how many constraints the folding circuits need and might change one of the sides to a non-pairing curve with a non-pairing proof instead of Groth16. Eventually would like to explore also using BN254 with Grumpkin for ending up verifying the proofs in Ethereum.

+ 6
- 2
src/circuits.rs

@ -239,6 +239,7 @@ mod test {
use crate::nifs;
use crate::pedersen;
use crate::transcript::poseidon_test_config;
use ark_ec::CurveGroup;
// use ark_ed_on_mnt4_298::{constraints::EdwardsVar, EdwardsProjective};
use crate::pedersen::Commitment;
@ -270,6 +271,7 @@ mod test {
fn test_nifs_gadget() {
let mut rng = ark_std::test_rng();
let pedersen_params = pedersen::Pedersen::<MNT6G1Projective>::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec
let poseidon_config = poseidon_test_config::<Fq>();
let cs = ConstraintSystem::<Fr>::new_ref();
@ -280,7 +282,9 @@ mod test {
let fw1 = nifs::FWit::<MNT6G1Projective>::new(w1.clone(), A.len());
let fw2 = nifs::FWit::<MNT6G1Projective>::new(w2.clone(), A.len());
let mut transcript_p = Transcript::<Fq>::new();
let mut transcript_p = Transcript::<Fq, MNT6G1Projective>::new(&poseidon_config);
let (fw3, phi1, phi2, T, cmT) = nifs::NIFS::<MNT6G1Projective>::P(
&mut transcript_p,
&pedersen_params,
@ -304,6 +308,6 @@ mod test {
let valid = NIFSGadget::<MNT6G1Projective, MNT6G1Var>::verify(
rVar, cmTVar, phi1Var, phi2Var, phi3Var,
);
println!("num_constraints={:?}", cs.num_constraints());
// println!("num_constraints={:?}", cs.num_constraints());
}
}

+ 26
- 13
src/nifs.rs

@ -1,5 +1,5 @@
// use ark_ec::AffineRepr;
use ark_ec::CurveGroup;
use ark_ec::{CurveGroup, Group};
use ark_ff::fields::PrimeField;
use ark_std::{
rand::{Rng, RngCore},
@ -11,6 +11,7 @@ use std::marker::PhantomData;
use crate::pedersen::{Commitment, Params as PedersenParams, Pedersen, Proof as PedersenProof};
use crate::transcript::Transcript;
use crate::utils::*;
use ark_crypto_primitives::sponge::Absorb;
pub struct R1CS<F: PrimeField> {
pub A: Vec<Vec<F>>,
@ -35,7 +36,11 @@ pub struct FWit {
rW: C::ScalarField,
}
impl<C: CurveGroup> FWit<C> {
impl<C: CurveGroup> FWit<C>
where
<C as Group>::ScalarField: Absorb,
<C as CurveGroup>::BaseField: Absorb,
{
pub fn new(z: Vec<C::ScalarField>, e_len: usize) -> Self {
FWit::<C> {
E: vec![C::ScalarField::zero(); e_len],
@ -60,7 +65,11 @@ pub struct NIFS {
_phantom: PhantomData<C>,
}
impl<C: CurveGroup> NIFS<C> {
impl<C: CurveGroup> NIFS<C>
where
<C as Group>::ScalarField: Absorb,
<C as CurveGroup>::BaseField: Absorb,
{
// comp_T: compute cross-terms T
pub fn comp_T(
r1cs: &R1CS<C::ScalarField>,
@ -138,7 +147,7 @@ impl NIFS {
// NIFS.P
pub fn P(
tr: &mut Transcript<C::ScalarField>,
tr: &mut Transcript<C::ScalarField, C>,
pedersen_params: &PedersenParams<C>,
r: C::ScalarField,
r1cs: &R1CS<C::ScalarField>,
@ -151,7 +160,7 @@ impl NIFS {
// compute cross terms
let T = Self::comp_T(&r1cs, phi1.u, phi2.u, &fw1.W, &fw2.W);
let rT = tr.get_challenge(b"rT");
let rT = tr.get_challenge(); // r_T
let cmT = Pedersen::commit(&pedersen_params, &T, &rT);
// fold witness
@ -193,7 +202,7 @@ impl NIFS {
}
pub fn open_commitments(
tr: &mut Transcript<C::ScalarField>,
tr: &mut Transcript<C::ScalarField, C>,
pedersen_params: &PedersenParams<C>,
fw: &FWit<C>,
phi: &Phi<C>,
@ -207,7 +216,7 @@ impl NIFS {
(cmE_proof, cmW_proof, cmT_proof)
}
pub fn verify_commitments(
tr: &mut Transcript<C::ScalarField>,
tr: &mut Transcript<C::ScalarField, C>,
pedersen_params: &PedersenParams<C>,
phi: Phi<C>,
cmT: Commitment<C>,
@ -273,6 +282,7 @@ pub fn gen_test_values(
mod tests {
use super::*;
use crate::pedersen::Pedersen;
use crate::transcript::poseidon_test_config;
use ark_ec::CurveGroup;
use ark_mnt4_298::{Fr, G1Projective};
use ark_std::{
@ -287,6 +297,7 @@ mod tests {
fn test_one_fold() {
let mut rng = ark_std::test_rng();
let pedersen_params = Pedersen::<G1Projective>::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec
let poseidon_config = poseidon_test_config::<Fr>();
let (r1cs, w1, w2, _, x1, x2, _) = gen_test_values(&mut rng);
let (A, B, C) = (r1cs.A.clone(), r1cs.B.clone(), r1cs.C.clone());
@ -329,9 +340,9 @@ mod tests {
assert!(NIFS::<G1Projective>::verify(r, &phi1, &phi2, &phi3, &cmT));
// init Prover's transcript
let mut transcript_p: Transcript<Fr> = Transcript::<Fr>::new();
let mut transcript_p = Transcript::<Fr, G1Projective>::new(&poseidon_config);
// init Verifier's transcript
let mut transcript_v: Transcript<Fr> = Transcript::<Fr>::new();
let mut transcript_v = Transcript::<Fr, G1Projective>::new(&poseidon_config);
// check openings of phi3.cmE, phi3.cmW and cmT
let (cmE_proof, cmW_proof, cmT_proof) = NIFS::<G1Projective>::open_commitments(
@ -359,6 +370,7 @@ mod tests {
fn test_two_fold() {
let mut rng = ark_std::test_rng();
let pedersen_params = Pedersen::<G1Projective>::new_params(&mut rng, 6);
let poseidon_config = poseidon_test_config::<Fr>();
let (r1cs, w1, w2, w3, x1, x2, x3) = gen_test_values(&mut rng);
@ -433,9 +445,9 @@ mod tests {
assert_eq!(phi_123_expected.cmW.0, phi_123.cmW.0);
// init Prover's transcript
let mut transcript_p: Transcript<Fr> = Transcript::<Fr>::new();
let mut transcript_p = Transcript::<Fr, G1Projective>::new(&poseidon_config);
// init Verifier's transcript
let mut transcript_v: Transcript<Fr> = Transcript::<Fr>::new();
let mut transcript_v = Transcript::<Fr, G1Projective>::new(&poseidon_config);
// check openings of phi_123.cmE, phi_123.cmW and cmT_123
let (cmE_proof, cmW_proof, cmT_proof) = NIFS::<G1Projective>::open_commitments(
@ -463,6 +475,7 @@ mod tests {
fn test_nifs_interface() {
let mut rng = ark_std::test_rng();
let pedersen_params = Pedersen::<G1Projective>::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec
let poseidon_config = poseidon_test_config::<Fr>();
let (r1cs, w1, w2, _, x1, x2, _) = gen_test_values(&mut rng);
let (A, B, C) = (r1cs.A.clone(), r1cs.B.clone(), r1cs.C.clone());
@ -473,14 +486,14 @@ mod tests {
let fw2 = FWit::<G1Projective>::new(w2.clone(), A.len());
// init Prover's transcript
let mut transcript_p: Transcript<Fr> = Transcript::<Fr>::new();
let mut transcript_p = Transcript::<Fr, G1Projective>::new(&poseidon_config);
// NIFS.P
let (fw3, phi1, phi2, T, cmT) =
NIFS::<G1Projective>::P(&mut transcript_p, &pedersen_params, r, &r1cs, fw1, fw2);
// init Verifier's transcript
let mut transcript_v: Transcript<Fr> = Transcript::<Fr>::new();
let mut transcript_v = Transcript::<Fr, G1Projective>::new(&poseidon_config);
// NIFS.V
let phi3 = NIFS::<G1Projective>::V(r, &phi1, &phi2, &cmT);

+ 53
- 35
src/pedersen.rs

@ -1,14 +1,17 @@
use ark_ec::AffineRepr;
use ark_ec::CurveGroup;
use ark_ec::{CurveGroup, Group};
use ark_std::{
rand::{Rng, RngCore},
UniformRand,
};
use std::marker::PhantomData;
use crate::transcript::Transcript;
use crate::utils::{naive_msm, vec_add, vector_elem_product};
use crate::transcript::Transcript;
use ark_crypto_primitives::sponge::Absorb;
use ark_ff::PrimeField;
pub struct Proof_elem<C: CurveGroup> {
R: C,
t1: C::ScalarField,
@ -26,11 +29,19 @@ pub struct Params {
pub generators: Vec<C>,
}
pub struct Pedersen<C: CurveGroup> {
_phantom: PhantomData<C>,
pub struct Pedersen<C: CurveGroup>
where
<C as Group>::ScalarField: Absorb,
<C as CurveGroup>::BaseField: Absorb,
{
_c: PhantomData<C>,
}
impl<C: CurveGroup> Pedersen<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();
@ -63,19 +74,19 @@ impl Pedersen {
pub fn prove_elem(
params: &Params<C>,
transcript: &mut Transcript<C::ScalarField>,
transcript: &mut Transcript<C::ScalarField, C>,
cm: C,
v: C::ScalarField,
r: C::ScalarField,
) -> Proof_elem<C> {
let r1 = transcript.get_challenge(b"r_1");
let r2 = transcript.get_challenge(b"r_2");
let r1 = transcript.get_challenge();
let r2 = transcript.get_challenge();
let R: C = (params.g.mul(r1) + params.h.mul(r2));
transcript.add(b"cm", &cm);
transcript.add(b"R", &R);
let e = transcript.get_challenge(b"e");
transcript.add_point(&cm);
transcript.add_point(&R);
let e = transcript.get_challenge();
let t1 = r1 + v * e;
let t2 = r2 + r * e;
@ -84,19 +95,19 @@ impl Pedersen {
}
pub fn prove(
params: &Params<C>,
transcript: &mut Transcript<C::ScalarField>,
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(b"r_1");
let d = transcript.get_challenge_vec(b"d", v.len());
let r1 = transcript.get_challenge();
let d = transcript.get_challenge_vec(v.len());
let R: C = params.h.mul(r1) + naive_msm(&d, &params.generators);
transcript.add(b"cm", &cm.0);
transcript.add(b"R", &R);
let e = transcript.get_challenge(b"e");
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;
@ -105,17 +116,17 @@ impl Pedersen {
}
pub fn verify(
params: &Params<C>,
transcript: &mut Transcript<C::ScalarField>,
transcript: &mut Transcript<C::ScalarField, C>,
cm: Commitment<C>,
proof: Proof<C>,
) -> bool {
// r1, d just to match Prover's transcript
transcript.get_challenge(b"r_1");
transcript.get_challenge_vec(b"d", proof.u_.len());
transcript.get_challenge(); // r_1
transcript.get_challenge_vec(proof.u_.len()); // d
transcript.add(b"cm", &cm.0);
transcript.add(b"R", &proof.R);
let e = transcript.get_challenge(b"e");
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_, &params.generators);
if lhs != rhs {
@ -126,17 +137,17 @@ impl Pedersen {
pub fn verify_elem(
params: &Params<C>,
transcript: &mut Transcript<C::ScalarField>,
transcript: &mut Transcript<C::ScalarField, C>,
cm: C,
proof: Proof_elem<C>,
) -> bool {
// s1, s2 just to match Prover's transcript
transcript.get_challenge(b"r_1");
transcript.get_challenge(b"r_2");
transcript.get_challenge(); // r_1
transcript.get_challenge(); // r_2
transcript.add(b"cm", &cm);
transcript.add(b"R", &proof.R);
let e = transcript.get_challenge(b"e");
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 {
@ -153,11 +164,15 @@ pub struct CommitmentElem {
pub cm: C,
pub r: C::ScalarField,
}
impl<C: CurveGroup> CommitmentElem<C> {
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>,
transcript: &mut Transcript<C::ScalarField, C>,
v: C::ScalarField,
) -> Proof_elem<C> {
Pedersen::<C>::prove_elem(params, transcript, self.cm, v, self.r)
@ -167,6 +182,7 @@ impl CommitmentElem {
#[cfg(test)]
mod tests {
use super::*;
use crate::transcript::poseidon_test_config;
use ark_ec::CurveGroup;
use ark_mnt4_298::{Fr, G1Projective};
use std::ops::Mul;
@ -179,11 +195,12 @@ mod tests {
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> = Transcript::<Fr>::new();
let mut transcript_p = Transcript::<Fr, G1Projective>::new(&poseidon_config);
// init Verifier's transcript
let mut transcript_v: Transcript<Fr> = Transcript::<Fr>::new();
let mut transcript_v = Transcript::<Fr, G1Projective>::new(&poseidon_config);
let v = Fr::rand(&mut rng);
@ -201,11 +218,12 @@ mod tests {
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> = Transcript::<Fr>::new();
let mut transcript_p = Transcript::<Fr, G1Projective>::new(&poseidon_config);
// init Verifier's transcript
let mut transcript_v: Transcript<Fr> = Transcript::<Fr>::new();
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);

+ 36
- 25
src/sumcheck.rs

@ -1,6 +1,7 @@
// this file contains a sum-check protocol initial implementation, not used by the rest of the repo
// but implemented as an exercise and it will probably be used in the future.
use ark_ec::{CurveGroup, Group};
use ark_ff::{BigInteger, PrimeField};
use ark_poly::{
multivariate::{SparsePolynomial, SparseTerm, Term},
@ -14,23 +15,30 @@ use ark_std::marker::PhantomData;
use ark_std::ops::Mul;
use ark_std::{rand::Rng, UniformRand};
use ark_crypto_primitives::sponge::{poseidon::PoseidonConfig, Absorb};
use crate::transcript::Transcript;
pub struct SumCheck<
F: PrimeField,
F: PrimeField + Absorb,
C: CurveGroup,
UV: Polynomial<F> + DenseUVPolynomial<F>,
MV: Polynomial<F> + DenseMVPolynomial<F>,
> {
_f: PhantomData<F>,
_c: PhantomData<C>,
_uv: PhantomData<UV>,
_mv: PhantomData<MV>,
}
impl<
F: PrimeField,
F: PrimeField + Absorb,
C: CurveGroup,
UV: Polynomial<F> + DenseUVPolynomial<F>,
MV: Polynomial<F> + DenseMVPolynomial<F>,
> SumCheck<F, UV, MV>
> SumCheck<F, C, UV, MV>
where
<C as CurveGroup>::BaseField: Absorb,
{
fn partial_evaluate(g: &MV, point: &[Option<F>]) -> UV {
assert!(point.len() >= g.num_vars(), "Invalid evaluation domain");
@ -121,12 +129,12 @@ impl<
p
}
pub fn prove(g: MV) -> (F, Vec<UV>, F)
pub fn prove(poseidon_config: &PoseidonConfig<F>, g: MV) -> (F, Vec<UV>, F)
where
<MV as Polynomial<F>>::Point: From<Vec<F>>,
{
// init transcript
let mut transcript: Transcript<F> = Transcript::<F>::new();
let mut transcript = Transcript::<F, C>::new(poseidon_config);
let v = g.num_vars();
@ -137,12 +145,12 @@ impl<
H = H + g.evaluate(&p.into());
}
transcript.add(b"H", &H);
transcript.add(&H);
let mut ss: Vec<UV> = Vec::new();
let mut r: Vec<F> = vec![];
for i in 0..v {
let r_i = transcript.get_challenge(b"r_i");
let r_i = transcript.get_challenge();
r.push(r_i);
let var_slots = v - 1 - i;
@ -153,7 +161,7 @@ impl<
let point = Self::point(r[..i].to_vec(), true, v, j);
s_i = s_i + Self::partial_evaluate(&g, &point);
}
transcript.add(b"s_i", &s_i);
transcript.add_vec(s_i.coeffs());
ss.push(s_i);
}
@ -161,10 +169,10 @@ impl<
(H, ss, last_g_eval)
}
pub fn verify(proof: (F, Vec<UV>, F)) -> bool {
pub fn verify(poseidon_config: &PoseidonConfig<F>, proof: (F, Vec<UV>, F)) -> bool {
// init transcript
let mut transcript: Transcript<F> = Transcript::<F>::new();
transcript.add(b"H", &proof.0);
let mut transcript = Transcript::<F, C>::new(poseidon_config);
transcript.add(&proof.0);
let (c, ss, last_g_eval) = proof;
@ -175,18 +183,18 @@ impl<
if c != s.evaluate(&F::zero()) + s.evaluate(&F::one()) {
return false;
}
let r_i = transcript.get_challenge(b"r_i");
let r_i = transcript.get_challenge();
r.push(r_i);
transcript.add(b"s_i", s);
transcript.add_vec(s.coeffs());
continue;
}
let r_i = transcript.get_challenge(b"r_i");
let r_i = transcript.get_challenge();
r.push(r_i);
if ss[i - 1].evaluate(&r[i - 1]) != s.evaluate(&F::zero()) + s.evaluate(&F::one()) {
return false;
}
transcript.add(b"s_i", s);
transcript.add_vec(s.coeffs());
}
// last round
if ss[ss.len() - 1].evaluate(&r[r.len() - 1]) != last_g_eval {
@ -200,14 +208,15 @@ impl<
#[cfg(test)]
mod tests {
use super::*;
use ark_mnt4_298::Fr; // scalar field
use crate::transcript::poseidon_test_config;
use ark_mnt4_298::{Fr, G1Projective}; // scalar field
#[test]
fn test_new_point() {
let f4 = Fr::from(4_u32);
let f1 = Fr::from(1);
let f0 = Fr::from(0);
type SC = SumCheck<Fr, DensePolynomial<Fr>, SparsePolynomial<Fr, SparseTerm>>;
type SC = SumCheck<Fr, G1Projective, DensePolynomial<Fr>, SparsePolynomial<Fr, SparseTerm>>;
let p = SC::point(vec![Fr::from(4_u32)], true, 5, 0);
assert_eq!(vec![Some(f4), None, Some(f0), Some(f0), Some(f0),], p);
@ -265,7 +274,7 @@ mod tests {
];
let p = SparsePolynomial::from_coefficients_slice(3, &terms);
type SC = SumCheck<Fr, DensePolynomial<Fr>, SparsePolynomial<Fr, SparseTerm>>;
type SC = SumCheck<Fr, G1Projective, DensePolynomial<Fr>, SparsePolynomial<Fr, SparseTerm>>;
let e0 = SC::partial_evaluate(&p, &[Some(Fr::from(2_u32)), None, Some(Fr::from(0_u32))]);
assert_eq!(e0.coeffs(), vec![Fr::from(16_u32)]);
@ -293,13 +302,14 @@ mod tests {
let p = SparsePolynomial::from_coefficients_slice(3, &terms);
// println!("p {:?}", p);
type SC = SumCheck<Fr, DensePolynomial<Fr>, SparsePolynomial<Fr, SparseTerm>>;
let poseidon_config = poseidon_test_config::<Fr>();
type SC = SumCheck<Fr, G1Projective, DensePolynomial<Fr>, SparsePolynomial<Fr, SparseTerm>>;
let proof = SC::prove(p);
let proof = SC::prove(&poseidon_config, p);
assert_eq!(proof.0, Fr::from(12_u32));
// println!("proof {:?}", proof);
let v = SC::verify(proof);
let v = SC::verify(&poseidon_config, proof);
assert!(v);
}
@ -335,12 +345,13 @@ mod tests {
let p = rand_poly(3, 3, &mut rng);
// println!("p {:?}", p);
type SC = SumCheck<Fr, DensePolynomial<Fr>, SparsePolynomial<Fr, SparseTerm>>;
let poseidon_config = poseidon_test_config::<Fr>();
type SC = SumCheck<Fr, G1Projective, DensePolynomial<Fr>, SparsePolynomial<Fr, SparseTerm>>;
let proof = SC::prove(p);
println!("proof.s len {:?}", proof.1.len());
let proof = SC::prove(&poseidon_config, p);
// println!("proof.s len {:?}", proof.1.len());
let v = SC::verify(proof);
let v = SC::verify(&poseidon_config, proof);
assert!(v);
}
}

+ 114
- 30
src/transcript.rs

@ -1,41 +1,125 @@
use ark_ec::{AffineRepr, CurveGroup, Group};
use ark_ff::PrimeField;
use ark_serialize::CanonicalSerialize;
use merlin::Transcript as MerlinTranscript;
use std::marker::PhantomData;
// TODO poseidon transcript (not keccak)
use ark_r1cs_std::fields::fp::FpVar;
// This Transcript approach is a modified version from https://github.com/arkworks-rs/gemini ,
// using Merlin transcript (https://merlin.cool).
pub struct Transcript<F: PrimeField> {
phantom: PhantomData<F>,
transcript: MerlinTranscript,
}
use ark_crypto_primitives::sponge::poseidon::{
constraints::PoseidonSpongeVar, PoseidonConfig, PoseidonSponge,
};
use ark_crypto_primitives::sponge::{
constraints::CryptographicSpongeVar, Absorb, CryptographicSponge,
};
use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};
use ark_poly::DenseUVPolynomial;
impl<F: PrimeField> Transcript<F> {
pub fn new() -> Self {
Self {
phantom: PhantomData::default(),
transcript: MerlinTranscript::new(b"transcript"),
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 mut sponge = PoseidonSponge::<F>::new(&poseidon_config);
Transcript {
sponge,
_c: PhantomData,
}
}
pub fn add<S: CanonicalSerialize>(&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
}
pub fn get_challenge_vec(&mut self, label: &'static [u8], n: usize) -> Vec<F> {
let mut c: Vec<F> = vec![F::zero(); n];
for i in 0..n {
c[i] = self.get_challenge(label);
}
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
}
}
pub struct TranscriptVar<F: PrimeField> {
// where F is the Constraint Field
sponge: PoseidonSpongeVar<F>,
}
impl<F: PrimeField> TranscriptVar<F> {
pub fn new(cs: ConstraintSystemRef<F>, poseidon_config: PoseidonConfig<F>) -> Self {
let mut sponge = PoseidonSpongeVar::<F>::new(cs.clone(), &poseidon_config);
Self { sponge }
}
pub fn add(&mut self, v: FpVar<F>) -> Result<(), SynthesisError> {
self.sponge.absorb(&v)
}
pub fn get_challenge(&mut self) -> Result<FpVar<F>, SynthesisError> {
let c = self.sponge.squeeze_field_elements(1)?;
self.sponge.absorb(&c[0]);
Ok(c[0].clone())
}
pub fn get_challenge_vec(&mut self, n: usize) -> Result<Vec<FpVar<F>>, SynthesisError> {
let c = self.sponge.squeeze_field_elements(n)?;
self.sponge.absorb(&c);
Ok(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,
)
}
// #[cfg(test)]
// mod tests {
// use super::*;
// use ark_mnt4_298::{Fr, G1Projective}; // scalar field
// use ark_std::{One, Zero};
//
// #[test]
// fn test_poseidon() {
// let config = poseidon_test_config::<Fr>();
// let mut tr = Transcript::<Fr, G1Projective>::new(&config);
// tr.add(&Fr::one());
// println!("c {:?}", tr.get_challenge().to_string());
// }
// }

Loading…
Cancel
Save