arnaucube
arnaucube/sonobePublic Self-hosted repository
Feature/traits (#3)

* feat: draft traits `FoldingScheme` and `Decider`

Co-authored-by: arnaucube <root@arnaucube.com>

* Add Transcript trait, with PoseidonTranscript impl (#1)

Add also the PoseidonTranscriptVar (gadget).

* Update FoldingScheme trait to take C1 & C2 as params (#2)

* Update FoldingScheme trait to take C1 & C2 as params

Update FoldingScheme trait to take C1 & C2 as params which are used by
the diverse folding schemes as a cycle of curves.

* Add constraint to FoldingScheme C1,C2 fields swap.

Co-authored-by: Han <tinghan0110@gmail.com>

---------

Co-authored-by: Han <tinghan0110@gmail.com>

* move transcript to it's own mod

---------

Co-authored-by: han0110 <tinghan0110@gmail.com>
arnaucube 17317030+arnaucube@users.noreply.github.com
Thu, 17 Aug 2023 10:32:26 +0200
commit

16e261bbed5c4b7d5b34529e7c36ef5feff08016

parent

eea9bf2a883ab9f598a9563100cd5cd86e472889

5 files changed, 240 insertions(+), 0 deletions(-)

jump to
A .gitignore

@@ -0,0 +1,2 @@

+/target +Cargo.lock
A Cargo.toml

@@ -0,0 +1,17 @@

+[package] +name = "folding-schemes" +version = "0.1.0" +edition = "2021" + +[dependencies] +ark-ec = "0.4.2" +ark-ff = "0.4.2" +ark-std = "0.4.0" +ark-poly = "0.4.0" +ark-crypto-primitives = { version = "^0.4.0", default-features = false, features = [ "r1cs", "sponge" ] } +ark-relations = { version = "^0.4.0", default-features = false } +ark-r1cs-std = { version = "^0.4.0", default-features = false } +thiserror = "1.0" + +[dev-dependencies] +ark-bls12-381 = "0.4.0"
A src/lib.rs

@@ -0,0 +1,85 @@

+#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] + +use ark_ec::CurveGroup; +use ark_ff::PrimeField; +use ark_std::{fmt::Debug, rand::RngCore}; +use thiserror::Error; + +pub mod transcript; +use transcript::Transcript; + +#[derive(Debug, Error)] +pub enum Error { + #[error("Relation not satisfied")] + NotSatisfied, +} + +/// FoldingScheme defines trait that is implemented by the diverse folding schemes. It is defined +/// 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 +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 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>; + + fn init_accumulator( + pp: &Self::ProverParam, + ) -> Result<Self::CommittedInstanceWithWitness, Error>; + + fn prove( + pp: &Self::ProverParam, + running_instance: &mut Self::CommittedInstanceWithWitness, + incomming_instances: &[Self::FreshInstance], + transcript: &mut impl Transcript<C1::ScalarField>, + rng: impl RngCore, + ) -> 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, + ) -> Result<(), Error>; +} + +pub trait Decider<C: CurveGroup>: Clone + Debug { + type PreprocessorParam: Debug; + type ProverParam: Debug; + type VerifierParam: Debug; + type FreshInstance: Debug; + type PublicInput: Debug; + type CommittedInstanceWithWitness: Debug; + type CommittedInstance: Clone + Debug; + + fn prove( + pp: &Self::ProverParam, + running_instance: &Self::CommittedInstanceWithWitness, + transcript: &mut impl Transcript<C::ScalarField>, + rng: impl RngCore, + ) -> Result<(), Error>; + + fn verify( + vp: &Self::VerifierParam, + running_instance: &Self::CommittedInstance, + transcript: &mut impl Transcript<C::ScalarField>, + rng: impl RngCore, + ) -> Result<(), Error>; +}
A src/transcript/mod.rs

@@ -0,0 +1,14 @@

+use ark_ff::PrimeField; +use ark_std::fmt::Debug; + +pub mod poseidon; + +pub trait Transcript<F: PrimeField> { + 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>; +}
A src/transcript/poseidon.rs

@@ -0,0 +1,122 @@

+use ark_crypto_primitives::sponge::{ + constraints::CryptographicSpongeVar, + poseidon::{constraints::PoseidonSpongeVar, PoseidonConfig, PoseidonSponge}, + Absorb, CryptographicSponge, +}; +use ark_ff::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>, +} + +impl<F: PrimeField + Absorb> Transcript<F> for PoseidonTranscript<F> { + type TranscriptConfig = PoseidonConfig<F>; + + fn new(poseidon_config: &Self::TranscriptConfig) -> Self { + let sponge = PoseidonSponge::<F>::new(poseidon_config); + Self { sponge } + } + fn absorb(&mut self, v: &F) { + self.sponge.absorb(&v); + } + fn absorb_vec(&mut self, v: &[F]) { + self.sponge.absorb(&v); + } + fn get_challenge(&mut self) -> F { + let c = self.sponge.squeeze_field_elements(1); + self.sponge.absorb(&c[0]); + c[0] + } + fn get_challenges(&mut self, n: usize) -> Vec<F> { + let c = self.sponge.squeeze_field_elements(n); + self.sponge.absorb(&c); + c + } +} + +/// PoseidonTranscriptVar implements the gadget compatible with PoseidonTranscript +pub struct PoseidonTranscriptVar<F: PrimeField> { + sponge: PoseidonSpongeVar<F>, +} +impl<F: PrimeField> PoseidonTranscriptVar<F> { + pub fn new(cs: ConstraintSystemRef<F>, poseidon_config: &PoseidonConfig<F>) -> Self { + let sponge = PoseidonSpongeVar::<F>::new(cs, poseidon_config); + Self { sponge } + } + pub fn absorb(&mut self, v: FpVar<F>) -> Result<(), SynthesisError> { + self.sponge.absorb(&v) + } + pub fn absorb_vec(&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_challenges(&mut self, n: usize) -> Result<Vec<FpVar<F>>, SynthesisError> { + let c = self.sponge.squeeze_field_elements(n)?; + self.sponge.absorb(&c)?; + Ok(c) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use ark_bls12_381::Fr; + 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; + + /// WARNING the method poseidon_test_config is for tests only + #[cfg(test)] + 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, + ) + } + + #[test] + fn test_transcript_and_transcriptvar() { + // use 'native' transcript + let config = poseidon_test_config::<Fr>(); + let mut tr = PoseidonTranscript::<Fr>::new(&config); + tr.absorb(&Fr::from(42_u32)); + let c = tr.get_challenge(); + + // use 'gadget' transcript + let cs = ConstraintSystem::<Fr>::new_ref(); + let mut tr_var = PoseidonTranscriptVar::<Fr>::new(cs.clone(), &config); + let v = FpVar::<Fr>::new_witness(cs.clone(), || Ok(Fr::from(42_u32))).unwrap(); + tr_var.absorb(v).unwrap(); + let c_var = tr_var.get_challenge().unwrap(); + + // assert that native & gadget transcripts return the same challenge + assert_eq!(c, c_var.value().unwrap()); + } +}