From 7cf729f00a6680f516ba6f3c6d583c68dcc30f57 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Sat, 29 Apr 2023 14:15:25 +0200 Subject: [PATCH] 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 --- README.md | 2 +- src/circuits.rs | 8 ++- src/nifs.rs | 39 ++++++++----- src/pedersen.rs | 88 +++++++++++++++++----------- src/sumcheck.rs | 61 ++++++++++++-------- src/transcript.rs | 144 ++++++++++++++++++++++++++++++++++++---------- 6 files changed, 236 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index e931567..7fee4ca 100644 --- a/README.md +++ b/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. diff --git a/src/circuits.rs b/src/circuits.rs index 16df7c1..c551a2b 100644 --- a/src/circuits.rs +++ b/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::::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec + let poseidon_config = poseidon_test_config::(); let cs = ConstraintSystem::::new_ref(); @@ -280,7 +282,9 @@ mod test { let fw1 = nifs::FWit::::new(w1.clone(), A.len()); let fw2 = nifs::FWit::::new(w2.clone(), A.len()); - let mut transcript_p = Transcript::::new(); + + let mut transcript_p = Transcript::::new(&poseidon_config); + let (fw3, phi1, phi2, T, cmT) = nifs::NIFS::::P( &mut transcript_p, &pedersen_params, @@ -304,6 +308,6 @@ mod test { let valid = NIFSGadget::::verify( rVar, cmTVar, phi1Var, phi2Var, phi3Var, ); - println!("num_constraints={:?}", cs.num_constraints()); + // println!("num_constraints={:?}", cs.num_constraints()); } } diff --git a/src/nifs.rs b/src/nifs.rs index 774190c..31438bc 100644 --- a/src/nifs.rs +++ b/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 { pub A: Vec>, @@ -35,7 +36,11 @@ pub struct FWit { rW: C::ScalarField, } -impl FWit { +impl FWit +where + ::ScalarField: Absorb, + ::BaseField: Absorb, +{ pub fn new(z: Vec, e_len: usize) -> Self { FWit:: { E: vec![C::ScalarField::zero(); e_len], @@ -60,7 +65,11 @@ pub struct NIFS { _phantom: PhantomData, } -impl NIFS { +impl NIFS +where + ::ScalarField: Absorb, + ::BaseField: Absorb, +{ // comp_T: compute cross-terms T pub fn comp_T( r1cs: &R1CS, @@ -138,7 +147,7 @@ impl NIFS { // NIFS.P pub fn P( - tr: &mut Transcript, + tr: &mut Transcript, pedersen_params: &PedersenParams, r: C::ScalarField, r1cs: &R1CS, @@ -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, + tr: &mut Transcript, pedersen_params: &PedersenParams, fw: &FWit, phi: &Phi, @@ -207,7 +216,7 @@ impl NIFS { (cmE_proof, cmW_proof, cmT_proof) } pub fn verify_commitments( - tr: &mut Transcript, + tr: &mut Transcript, pedersen_params: &PedersenParams, phi: Phi, cmT: Commitment, @@ -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::::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec + let poseidon_config = poseidon_test_config::(); 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::::verify(r, &phi1, &phi2, &phi3, &cmT)); // init Prover's transcript - let mut transcript_p: Transcript = Transcript::::new(); + let mut transcript_p = Transcript::::new(&poseidon_config); // init Verifier's transcript - let mut transcript_v: Transcript = Transcript::::new(); + let mut transcript_v = Transcript::::new(&poseidon_config); // check openings of phi3.cmE, phi3.cmW and cmT let (cmE_proof, cmW_proof, cmT_proof) = NIFS::::open_commitments( @@ -359,6 +370,7 @@ mod tests { fn test_two_fold() { let mut rng = ark_std::test_rng(); let pedersen_params = Pedersen::::new_params(&mut rng, 6); + let poseidon_config = poseidon_test_config::(); 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 = Transcript::::new(); + let mut transcript_p = Transcript::::new(&poseidon_config); // init Verifier's transcript - let mut transcript_v: Transcript = Transcript::::new(); + let mut transcript_v = Transcript::::new(&poseidon_config); // check openings of phi_123.cmE, phi_123.cmW and cmT_123 let (cmE_proof, cmW_proof, cmT_proof) = NIFS::::open_commitments( @@ -463,6 +475,7 @@ mod tests { fn test_nifs_interface() { let mut rng = ark_std::test_rng(); let pedersen_params = Pedersen::::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec + let poseidon_config = poseidon_test_config::(); 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::::new(w2.clone(), A.len()); // init Prover's transcript - let mut transcript_p: Transcript = Transcript::::new(); + let mut transcript_p = Transcript::::new(&poseidon_config); // NIFS.P let (fw3, phi1, phi2, T, cmT) = NIFS::::P(&mut transcript_p, &pedersen_params, r, &r1cs, fw1, fw2); // init Verifier's transcript - let mut transcript_v: Transcript = Transcript::::new(); + let mut transcript_v = Transcript::::new(&poseidon_config); // NIFS.V let phi3 = NIFS::::V(r, &phi1, &phi2, &cmT); diff --git a/src/pedersen.rs b/src/pedersen.rs index f48a1c1..13214f8 100644 --- a/src/pedersen.rs +++ b/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 { R: C, t1: C::ScalarField, @@ -26,11 +29,19 @@ pub struct Params { pub generators: Vec, } -pub struct Pedersen { - _phantom: PhantomData, +pub struct Pedersen +where + ::ScalarField: Absorb, + ::BaseField: Absorb, +{ + _c: PhantomData, } -impl Pedersen { +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(); @@ -63,19 +74,19 @@ impl Pedersen { pub fn prove_elem( params: &Params, - transcript: &mut Transcript, + transcript: &mut Transcript, cm: C, v: C::ScalarField, r: C::ScalarField, ) -> Proof_elem { - 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, - transcript: &mut Transcript, + 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(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, ¶ms.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, - transcript: &mut Transcript, + transcript: &mut Transcript, cm: Commitment, proof: Proof, ) -> 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_, ¶ms.generators); if lhs != rhs { @@ -126,17 +137,17 @@ impl Pedersen { pub fn verify_elem( params: &Params, - transcript: &mut Transcript, + transcript: &mut Transcript, cm: C, proof: Proof_elem, ) -> 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 CommitmentElem { +impl CommitmentElem +where + ::ScalarField: Absorb, + ::BaseField: Absorb, +{ pub fn prove( &self, params: &Params, - transcript: &mut Transcript, + transcript: &mut Transcript, v: C::ScalarField, ) -> Proof_elem { Pedersen::::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::::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 = Transcript::::new(); + let mut transcript_p = Transcript::::new(&poseidon_config); // init Verifier's transcript - let mut transcript_v: Transcript = Transcript::::new(); + let mut transcript_v = Transcript::::new(&poseidon_config); let v = Fr::rand(&mut rng); @@ -201,11 +218,12 @@ mod tests { 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 = Transcript::::new(); + let mut transcript_p = Transcript::::new(&poseidon_config); // init Verifier's transcript - let mut transcript_v: Transcript = Transcript::::new(); + let mut transcript_v = Transcript::::new(&poseidon_config); let v: Vec = vec![Fr::rand(&mut rng); n]; let r: Fr = Fr::rand(&mut rng); diff --git a/src/sumcheck.rs b/src/sumcheck.rs index 407131d..2b65ffc 100644 --- a/src/sumcheck.rs +++ b/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 + DenseUVPolynomial, MV: Polynomial + DenseMVPolynomial, > { _f: PhantomData, + _c: PhantomData, _uv: PhantomData, _mv: PhantomData, } impl< - F: PrimeField, + F: PrimeField + Absorb, + C: CurveGroup, UV: Polynomial + DenseUVPolynomial, MV: Polynomial + DenseMVPolynomial, - > SumCheck + > SumCheck +where + ::BaseField: Absorb, { fn partial_evaluate(g: &MV, point: &[Option]) -> UV { assert!(point.len() >= g.num_vars(), "Invalid evaluation domain"); @@ -121,12 +129,12 @@ impl< p } - pub fn prove(g: MV) -> (F, Vec, F) + pub fn prove(poseidon_config: &PoseidonConfig, g: MV) -> (F, Vec, F) where >::Point: From>, { // init transcript - let mut transcript: Transcript = Transcript::::new(); + let mut transcript = Transcript::::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 = Vec::new(); let mut r: Vec = 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, F)) -> bool { + pub fn verify(poseidon_config: &PoseidonConfig, proof: (F, Vec, F)) -> bool { // init transcript - let mut transcript: Transcript = Transcript::::new(); - transcript.add(b"H", &proof.0); + let mut transcript = Transcript::::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, SparsePolynomial>; + type SC = SumCheck, SparsePolynomial>; 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, SparsePolynomial>; + type SC = SumCheck, SparsePolynomial>; 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, SparsePolynomial>; + let poseidon_config = poseidon_test_config::(); + type SC = SumCheck, SparsePolynomial>; - 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, SparsePolynomial>; + let poseidon_config = poseidon_test_config::(); + type SC = SumCheck, SparsePolynomial>; - 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); } } diff --git a/src/transcript.rs b/src/transcript.rs index 3d56ba7..41fad64 100644 --- a/src/transcript.rs +++ b/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 { - phantom: PhantomData, - 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 Transcript { - pub fn new() -> Self { - Self { - phantom: PhantomData::default(), - transcript: MerlinTranscript::new(b"transcript"), +pub struct Transcript +where + ::BaseField: Absorb, +{ + // where F is the Constraint Field (eq. C::ScalarField) + sponge: PoseidonSponge, + _c: PhantomData, +} +impl Transcript +where + ::BaseField: Absorb, +{ + pub fn new(poseidon_config: &PoseidonConfig) -> Self { + let mut sponge = PoseidonSponge::::new(&poseidon_config); + Transcript { + sponge, + _c: PhantomData, } } - 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 - } - pub fn get_challenge_vec(&mut self, label: &'static [u8], n: usize) -> Vec { - let mut c: Vec = 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 { + let c = self.sponge.squeeze_field_elements(n); + self.sponge.absorb(&c); c } } + +pub struct TranscriptVar { + // where F is the Constraint Field + sponge: PoseidonSpongeVar, +} +impl TranscriptVar { + pub fn new(cs: ConstraintSystemRef, poseidon_config: PoseidonConfig) -> Self { + let mut sponge = PoseidonSpongeVar::::new(cs.clone(), &poseidon_config); + Self { sponge } + } + pub fn add(&mut self, v: FpVar) -> Result<(), SynthesisError> { + self.sponge.absorb(&v) + } + pub fn get_challenge(&mut self) -> Result, 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>, 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() -> PoseidonConfig { + let full_rounds = 8; + let partial_rounds = 31; + let alpha = 5; + let rate = 2; + + let (ark, mds) = find_poseidon_ark_and_mds::( + 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::(); +// let mut tr = Transcript::::new(&config); +// tr.add(&Fr::one()); +// println!("c {:?}", tr.get_challenge().to_string()); +// } +// }