From 16e261bbed5c4b7d5b34529e7c36ef5feff08016 Mon Sep 17 00:00:00 2001 From: arnaucube <17317030+arnaucube@users.noreply.github.com> Date: Thu, 17 Aug 2023 10:32:26 +0200 Subject: [PATCH] Feature/traits (#3) * feat: draft traits `FoldingScheme` and `Decider` Co-authored-by: arnaucube * 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 --------- Co-authored-by: Han * move transcript to it's own mod --------- Co-authored-by: han0110 --- .gitignore | 2 + Cargo.toml | 17 ++++++ src/lib.rs | 85 ++++++++++++++++++++++++++ src/transcript/mod.rs | 14 +++++ src/transcript/poseidon.rs | 122 +++++++++++++++++++++++++++++++++++++ 5 files changed, 240 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/lib.rs create mode 100644 src/transcript/mod.rs create mode 100644 src/transcript/poseidon.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..869df07 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..fa62bcf --- /dev/null +++ b/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" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..44aeb0b --- /dev/null +++ b/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: Clone + Debug +where + C1: CurveGroup, + C2::BaseField: PrimeField, +{ + // type PCS: PolynomialCommitmentScheme; // 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: &>::Param, + prep_param: &Self::PreprocessorParam, + ) -> Result<(Self::ProverParam, Self::VerifierParam), Error>; + + fn init_accumulator( + pp: &Self::ProverParam, + ) -> Result; + + fn prove( + pp: &Self::ProverParam, + running_instance: &mut Self::CommittedInstanceWithWitness, + incomming_instances: &[Self::FreshInstance], + transcript: &mut impl Transcript, + rng: impl RngCore, + ) -> Result<(), Error>; + + fn verify( + vp: &Self::VerifierParam, + running_instance: &mut Self::CommittedInstance, + incomming_instances: &[Self::PublicInput], + transcript: &mut impl Transcript, + rng: impl RngCore, + ) -> Result<(), Error>; +} + +pub trait Decider: 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, + rng: impl RngCore, + ) -> Result<(), Error>; + + fn verify( + vp: &Self::VerifierParam, + running_instance: &Self::CommittedInstance, + transcript: &mut impl Transcript, + rng: impl RngCore, + ) -> Result<(), Error>; +} diff --git a/src/transcript/mod.rs b/src/transcript/mod.rs new file mode 100644 index 0000000..cc1424f --- /dev/null +++ b/src/transcript/mod.rs @@ -0,0 +1,14 @@ +use ark_ff::PrimeField; +use ark_std::fmt::Debug; + +pub mod poseidon; + +pub trait Transcript { + 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; +} diff --git a/src/transcript/poseidon.rs b/src/transcript/poseidon.rs new file mode 100644 index 0000000..4636ca3 --- /dev/null +++ b/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 { + sponge: PoseidonSponge, +} + +impl Transcript for PoseidonTranscript { + type TranscriptConfig = PoseidonConfig; + + fn new(poseidon_config: &Self::TranscriptConfig) -> Self { + let sponge = PoseidonSponge::::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 { + let c = self.sponge.squeeze_field_elements(n); + self.sponge.absorb(&c); + c + } +} + +/// PoseidonTranscriptVar implements the gadget compatible with PoseidonTranscript +pub struct PoseidonTranscriptVar { + sponge: PoseidonSpongeVar, +} +impl PoseidonTranscriptVar { + pub fn new(cs: ConstraintSystemRef, poseidon_config: &PoseidonConfig) -> Self { + let sponge = PoseidonSpongeVar::::new(cs, poseidon_config); + Self { sponge } + } + pub fn absorb(&mut self, v: FpVar) -> Result<(), SynthesisError> { + self.sponge.absorb(&v) + } + pub fn absorb_vec(&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_challenges(&mut self, n: usize) -> Result>, 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() -> 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, + ) + } + + #[test] + fn test_transcript_and_transcriptvar() { + // use 'native' transcript + let config = poseidon_test_config::(); + let mut tr = PoseidonTranscript::::new(&config); + tr.absorb(&Fr::from(42_u32)); + let c = tr.get_challenge(); + + // use 'gadget' transcript + let cs = ConstraintSystem::::new_ref(); + let mut tr_var = PoseidonTranscriptVar::::new(cs.clone(), &config); + let v = FpVar::::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()); + } +}