Browse Source

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>
main
arnaucube 1 year ago
committed by GitHub
parent
commit
16e261bbed
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 240 additions and 0 deletions
  1. +2
    -0
      .gitignore
  2. +17
    -0
      Cargo.toml
  3. +85
    -0
      src/lib.rs
  4. +14
    -0
      src/transcript/mod.rs
  5. +122
    -0
      src/transcript/poseidon.rs

+ 2
- 0
.gitignore

@ -0,0 +1,2 @@
/target
Cargo.lock

+ 17
- 0
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"

+ 85
- 0
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>;
}

+ 14
- 0
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>;
}

+ 122
- 0
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());
}
}

Loading…
Cancel
Save