Browse Source

Abstract the RO used in the circuit with traits (#84)

* cleanup RO usage inside the circuit: use traits

* Add a note

* rename types for clarity
main
Srinath Setty 2 years ago
committed by GitHub
parent
commit
6667d2f8b5
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 118 additions and 74 deletions
  1. +8
    -8
      src/circuit.rs
  2. +5
    -6
      src/gadgets/r1cs.rs
  3. +23
    -23
      src/lib.rs
  4. +3
    -3
      src/nifs.rs
  5. +5
    -3
      src/pasta.rs
  6. +37
    -30
      src/poseidon.rs
  7. +37
    -1
      src/traits.rs

+ 8
- 8
src/circuit.rs

@ -15,9 +15,8 @@ use super::{
alloc_num_equals, alloc_scalar_as_base, alloc_zero, conditionally_select, le_bits_to_num, alloc_num_equals, alloc_scalar_as_base, alloc_zero, conditionally_select, le_bits_to_num,
}, },
}, },
poseidon::{PoseidonROGadget, ROConstantsCircuit},
r1cs::{R1CSInstance, RelaxedR1CSInstance}, r1cs::{R1CSInstance, RelaxedR1CSInstance},
traits::{Group, StepCircuit},
traits::{Group, HashFuncCircuitTrait, HashFuncConstantsCircuit, StepCircuit},
}; };
use bellperson::{ use bellperson::{
gadgets::{ gadgets::{
@ -91,7 +90,7 @@ where
SC: StepCircuit<G::Base>, SC: StepCircuit<G::Base>,
{ {
params: NIFSVerifierCircuitParams, params: NIFSVerifierCircuitParams,
ro_consts: ROConstantsCircuit<G::Base>,
ro_consts: HashFuncConstantsCircuit<G>,
inputs: Option<NIFSVerifierCircuitInputs<G>>, inputs: Option<NIFSVerifierCircuitInputs<G>>,
step_circuit: SC, // The function that is applied for each step step_circuit: SC, // The function that is applied for each step
} }
@ -106,7 +105,7 @@ where
params: NIFSVerifierCircuitParams, params: NIFSVerifierCircuitParams,
inputs: Option<NIFSVerifierCircuitInputs<G>>, inputs: Option<NIFSVerifierCircuitInputs<G>>,
step_circuit: SC, step_circuit: SC,
ro_consts: ROConstantsCircuit<G::Base>,
ro_consts: HashFuncConstantsCircuit<G>,
) -> Self { ) -> Self {
Self { Self {
params, params,
@ -221,7 +220,7 @@ where
T: AllocatedPoint<G::Base>, T: AllocatedPoint<G::Base>,
) -> Result<(AllocatedRelaxedR1CSInstance<G>, AllocatedBit), SynthesisError> { ) -> Result<(AllocatedRelaxedR1CSInstance<G>, AllocatedBit), SynthesisError> {
// Check that u.x[0] = Hash(params, U, i, z0, zi) // Check that u.x[0] = Hash(params, U, i, z0, zi)
let mut ro: PoseidonROGadget<G::Base> = PoseidonROGadget::new(self.ro_consts.clone());
let mut ro = G::HashFuncCircuit::new(self.ro_consts.clone());
ro.absorb(params.clone()); ro.absorb(params.clone());
ro.absorb(i); ro.absorb(i);
ro.absorb(z_0); ro.absorb(z_0);
@ -328,7 +327,7 @@ where
.synthesize(&mut cs.namespace(|| "F"), z_input)?; .synthesize(&mut cs.namespace(|| "F"), z_input)?;
// Compute the new hash H(params, Unew, i+1, z0, z_{i+1}) // Compute the new hash H(params, Unew, i+1, z0, z_{i+1})
let mut ro: PoseidonROGadget<G::Base> = PoseidonROGadget::new(self.ro_consts);
let mut ro = G::HashFuncCircuit::new(self.ro_consts);
ro.absorb(params); ro.absorb(params);
ro.absorb(i_new.clone()); ro.absorb(i_new.clone());
ro.absorb(z_0); ro.absorb(z_0);
@ -356,6 +355,7 @@ mod tests {
use crate::constants::{BN_LIMB_WIDTH, BN_N_LIMBS}; use crate::constants::{BN_LIMB_WIDTH, BN_N_LIMBS};
use crate::{ use crate::{
bellperson::r1cs::{NovaShape, NovaWitness}, bellperson::r1cs::{NovaShape, NovaWitness},
poseidon::PoseidonConstantsCircuit,
traits::HashFuncConstantsTrait, traits::HashFuncConstantsTrait,
}; };
use ff::PrimeField; use ff::PrimeField;
@ -388,8 +388,8 @@ mod tests {
// In the following we use 1 to refer to the primary, and 2 to refer to the secondary circuit // In the following we use 1 to refer to the primary, and 2 to refer to the secondary circuit
let params1 = NIFSVerifierCircuitParams::new(BN_LIMB_WIDTH, BN_N_LIMBS, true); let params1 = NIFSVerifierCircuitParams::new(BN_LIMB_WIDTH, BN_N_LIMBS, true);
let params2 = NIFSVerifierCircuitParams::new(BN_LIMB_WIDTH, BN_N_LIMBS, false); let params2 = NIFSVerifierCircuitParams::new(BN_LIMB_WIDTH, BN_N_LIMBS, false);
let ro_consts1: ROConstantsCircuit<<G2 as Group>::Base> = ROConstantsCircuit::new();
let ro_consts2: ROConstantsCircuit<<G1 as Group>::Base> = ROConstantsCircuit::new();
let ro_consts1: HashFuncConstantsCircuit<G2> = PoseidonConstantsCircuit::new();
let ro_consts2: HashFuncConstantsCircuit<G1> = PoseidonConstantsCircuit::new();
// Initialize the shape and gens for the primary // Initialize the shape and gens for the primary
let circuit1: NIFSVerifierCircuit<G2, TestCircuit<<G2 as Group>::Base>> = let circuit1: NIFSVerifierCircuit<G2, TestCircuit<<G2 as Group>::Base>> =

+ 5
- 6
src/gadgets/r1cs.rs

@ -7,9 +7,8 @@ use crate::{
conditionally_select_bignat, le_bits_to_num, conditionally_select_bignat, le_bits_to_num,
}, },
}, },
poseidon::{PoseidonROGadget, ROConstantsCircuit},
r1cs::{R1CSInstance, RelaxedR1CSInstance}, r1cs::{R1CSInstance, RelaxedR1CSInstance},
traits::Group,
traits::{Group, HashFuncCircuitTrait, HashFuncConstantsCircuit},
}; };
use bellperson::{ use bellperson::{
gadgets::{boolean::Boolean, num::AllocatedNum, Assignment}, gadgets::{boolean::Boolean, num::AllocatedNum, Assignment},
@ -61,7 +60,7 @@ where
} }
/// Absorb the provided instance in the RO /// Absorb the provided instance in the RO
pub fn absorb_in_ro(&self, ro: &mut PoseidonROGadget<G::Base>) {
pub fn absorb_in_ro(&self, ro: &mut G::HashFuncCircuit) {
ro.absorb(self.W.x.clone()); ro.absorb(self.W.x.clone());
ro.absorb(self.W.y.clone()); ro.absorb(self.W.y.clone());
ro.absorb(self.W.is_infinity.clone()); ro.absorb(self.W.is_infinity.clone());
@ -208,7 +207,7 @@ where
pub fn absorb_in_ro<CS: ConstraintSystem<<G as Group>::Base>>( pub fn absorb_in_ro<CS: ConstraintSystem<<G as Group>::Base>>(
&self, &self,
mut cs: CS, mut cs: CS,
ro: &mut PoseidonROGadget<G::Base>,
ro: &mut G::HashFuncCircuit,
) -> Result<(), SynthesisError> { ) -> Result<(), SynthesisError> {
ro.absorb(self.W.x.clone()); ro.absorb(self.W.x.clone());
ro.absorb(self.W.y.clone()); ro.absorb(self.W.y.clone());
@ -263,12 +262,12 @@ where
params: AllocatedNum<G::Base>, // hash of R1CSShape of F' params: AllocatedNum<G::Base>, // hash of R1CSShape of F'
u: AllocatedR1CSInstance<G>, u: AllocatedR1CSInstance<G>,
T: AllocatedPoint<G::Base>, T: AllocatedPoint<G::Base>,
ro_consts: ROConstantsCircuit<G::Base>,
ro_consts: HashFuncConstantsCircuit<G>,
limb_width: usize, limb_width: usize,
n_limbs: usize, n_limbs: usize,
) -> Result<AllocatedRelaxedR1CSInstance<G>, SynthesisError> { ) -> Result<AllocatedRelaxedR1CSInstance<G>, SynthesisError> {
// Compute r: // Compute r:
let mut ro: PoseidonROGadget<G::Base> = PoseidonROGadget::new(ro_consts);
let mut ro = G::HashFuncCircuit::new(ro_consts);
ro.absorb(params); ro.absorb(params);
self.absorb_in_ro(cs.namespace(|| "absorb running instance"), &mut ro)?; self.absorb_in_ro(cs.namespace(|| "absorb running instance"), &mut ro)?;
u.absorb_in_ro(&mut ro); u.absorb_in_ro(&mut ro);

+ 23
- 23
src/lib.rs

@ -33,31 +33,30 @@ use errors::NovaError;
use ff::Field; use ff::Field;
use gadgets::utils::scalar_as_base; use gadgets::utils::scalar_as_base;
use nifs::NIFS; use nifs::NIFS;
use poseidon::ROConstantsCircuit; // TODO: make this a trait so we can use it without the concrete implementation
use r1cs::{ use r1cs::{
R1CSGens, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness, R1CSGens, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness,
}; };
use snark::RelaxedR1CSSNARKTrait; use snark::RelaxedR1CSSNARKTrait;
use traits::{AbsorbInROTrait, Group, HashFuncConstantsTrait, HashFuncTrait, StepCircuit};
type ROConstants<G> =
<<G as Group>::HashFunc as HashFuncTrait<<G as Group>::Base, <G as Group>::Scalar>>::Constants;
use traits::{
AbsorbInROTrait, Group, HashFuncConstants, HashFuncConstantsCircuit, HashFuncConstantsTrait,
HashFuncTrait, StepCircuit,
};
/// A type that holds public parameters of Nova /// A type that holds public parameters of Nova
pub struct PublicParams<G1, G2, C1, C2> pub struct PublicParams<G1, G2, C1, C2>
where where
G1: Group<Base = <G2 as Group>::Scalar>, G1: Group<Base = <G2 as Group>::Scalar>,
G2: Group<Base = <G1 as Group>::Scalar>, G2: Group<Base = <G1 as Group>::Scalar>,
C1: StepCircuit<G1::Scalar> + Clone,
C2: StepCircuit<G2::Scalar> + Clone,
C1: StepCircuit<G1::Scalar>,
C2: StepCircuit<G2::Scalar>,
{ {
ro_consts_primary: ROConstants<G1>,
ro_consts_circuit_primary: ROConstantsCircuit<<G2 as Group>::Base>,
ro_consts_primary: HashFuncConstants<G1>,
ro_consts_circuit_primary: HashFuncConstantsCircuit<G2>,
r1cs_gens_primary: R1CSGens<G1>, r1cs_gens_primary: R1CSGens<G1>,
r1cs_shape_primary: R1CSShape<G1>, r1cs_shape_primary: R1CSShape<G1>,
r1cs_shape_padded_primary: R1CSShape<G1>, r1cs_shape_padded_primary: R1CSShape<G1>,
ro_consts_secondary: ROConstants<G2>,
ro_consts_circuit_secondary: ROConstantsCircuit<<G1 as Group>::Base>,
ro_consts_secondary: HashFuncConstants<G2>,
ro_consts_circuit_secondary: HashFuncConstantsCircuit<G1>,
r1cs_gens_secondary: R1CSGens<G2>, r1cs_gens_secondary: R1CSGens<G2>,
r1cs_shape_secondary: R1CSShape<G2>, r1cs_shape_secondary: R1CSShape<G2>,
r1cs_shape_padded_secondary: R1CSShape<G2>, r1cs_shape_padded_secondary: R1CSShape<G2>,
@ -71,21 +70,22 @@ impl PublicParams
where where
G1: Group<Base = <G2 as Group>::Scalar>, G1: Group<Base = <G2 as Group>::Scalar>,
G2: Group<Base = <G1 as Group>::Scalar>, G2: Group<Base = <G1 as Group>::Scalar>,
C1: StepCircuit<G1::Scalar> + Clone,
C2: StepCircuit<G2::Scalar> + Clone,
C1: StepCircuit<G1::Scalar>,
C2: StepCircuit<G2::Scalar>,
{ {
/// Create a new `PublicParams` /// Create a new `PublicParams`
pub fn setup(c_primary: C1, c_secondary: C2) -> Self { pub fn setup(c_primary: C1, c_secondary: C2) -> Self {
let params_primary = NIFSVerifierCircuitParams::new(BN_LIMB_WIDTH, BN_N_LIMBS, true); let params_primary = NIFSVerifierCircuitParams::new(BN_LIMB_WIDTH, BN_N_LIMBS, true);
let params_secondary = NIFSVerifierCircuitParams::new(BN_LIMB_WIDTH, BN_N_LIMBS, false); let params_secondary = NIFSVerifierCircuitParams::new(BN_LIMB_WIDTH, BN_N_LIMBS, false);
let ro_consts_primary: ROConstants<G1> = ROConstants::<G1>::new();
let ro_consts_secondary: ROConstants<G2> = ROConstants::<G2>::new();
let ro_consts_primary: HashFuncConstants<G1> = HashFuncConstants::<G1>::new();
let ro_consts_secondary: HashFuncConstants<G2> = HashFuncConstants::<G2>::new();
let ro_consts_circuit_primary: ROConstantsCircuit<<G2 as Group>::Base> =
ROConstantsCircuit::new();
let ro_consts_circuit_secondary: ROConstantsCircuit<<G1 as Group>::Base> =
ROConstantsCircuit::new();
// ro_consts_circuit_primart are parameterized by G2 because the type alias uses G2::Base = G1::Scalar
let ro_consts_circuit_primary: HashFuncConstantsCircuit<G2> =
HashFuncConstantsCircuit::<G2>::new();
let ro_consts_circuit_secondary: HashFuncConstantsCircuit<G1> =
HashFuncConstantsCircuit::<G1>::new();
// Initialize gens for the primary // Initialize gens for the primary
let circuit_primary: NIFSVerifierCircuit<G2, C1> = NIFSVerifierCircuit::new( let circuit_primary: NIFSVerifierCircuit<G2, C1> = NIFSVerifierCircuit::new(
@ -135,8 +135,8 @@ pub struct RecursiveSNARK
where where
G1: Group<Base = <G2 as Group>::Scalar>, G1: Group<Base = <G2 as Group>::Scalar>,
G2: Group<Base = <G1 as Group>::Scalar>, G2: Group<Base = <G1 as Group>::Scalar>,
C1: StepCircuit<G1::Scalar> + Clone,
C2: StepCircuit<G2::Scalar> + Clone,
C1: StepCircuit<G1::Scalar>,
C2: StepCircuit<G2::Scalar>,
{ {
r_W_primary: RelaxedR1CSWitness<G1>, r_W_primary: RelaxedR1CSWitness<G1>,
r_U_primary: RelaxedR1CSInstance<G1>, r_U_primary: RelaxedR1CSInstance<G1>,
@ -156,8 +156,8 @@ impl RecursiveSNARK
where where
G1: Group<Base = <G2 as Group>::Scalar>, G1: Group<Base = <G2 as Group>::Scalar>,
G2: Group<Base = <G1 as Group>::Scalar>, G2: Group<Base = <G1 as Group>::Scalar>,
C1: StepCircuit<G1::Scalar> + Clone,
C2: StepCircuit<G2::Scalar> + Clone,
C1: StepCircuit<G1::Scalar>,
C2: StepCircuit<G2::Scalar>,
{ {
/// Create a new `RecursiveSNARK` /// Create a new `RecursiveSNARK`
pub fn prove( pub fn prove(

+ 3
- 3
src/nifs.rs

@ -17,7 +17,7 @@ pub struct NIFS {
_p: PhantomData<G>, _p: PhantomData<G>,
} }
type ROConstants<G> =
type HashFuncConstants<G> =
<<G as Group>::HashFunc as HashFuncTrait<<G as Group>::Base, <G as Group>::Scalar>>::Constants; <<G as Group>::HashFunc as HashFuncTrait<<G as Group>::Base, <G as Group>::Scalar>>::Constants;
impl<G: Group> NIFS<G> { impl<G: Group> NIFS<G> {
@ -29,7 +29,7 @@ impl NIFS {
/// if and only if `W1` satisfies `U1` and `W2` satisfies `U2`. /// if and only if `W1` satisfies `U1` and `W2` satisfies `U2`.
pub fn prove( pub fn prove(
gens: &R1CSGens<G>, gens: &R1CSGens<G>,
ro_consts: &ROConstants<G>,
ro_consts: &HashFuncConstants<G>,
S: &R1CSShape<G>, S: &R1CSShape<G>,
U1: &RelaxedR1CSInstance<G>, U1: &RelaxedR1CSInstance<G>,
W1: &RelaxedR1CSWitness<G>, W1: &RelaxedR1CSWitness<G>,
@ -78,7 +78,7 @@ impl NIFS {
/// if and only if `U1` and `U2` are satisfiable. /// if and only if `U1` and `U2` are satisfiable.
pub fn verify( pub fn verify(
&self, &self,
ro_consts: &ROConstants<G>,
ro_consts: &HashFuncConstants<G>,
S: &R1CSShape<G>, S: &R1CSShape<G>,
U1: &RelaxedR1CSInstance<G>, U1: &RelaxedR1CSInstance<G>,
U2: &R1CSInstance<G>, U2: &R1CSInstance<G>,

+ 5
- 3
src/pasta.rs

@ -1,6 +1,6 @@
//! This module implements the Nova traits for pallas::Point, pallas::Scalar, vesta::Point, vesta::Scalar. //! This module implements the Nova traits for pallas::Point, pallas::Scalar, vesta::Point, vesta::Scalar.
use crate::{ use crate::{
poseidon::PoseidonRO,
poseidon::{PoseidonHashFunc, PoseidonHashFuncCircuit},
traits::{ChallengeTrait, CompressedGroup, Group}, traits::{ChallengeTrait, CompressedGroup, Group},
}; };
use digest::{ExtendableOutput, Input}; use digest::{ExtendableOutput, Input};
@ -40,7 +40,8 @@ impl Group for pallas::Point {
type Scalar = pallas::Scalar; type Scalar = pallas::Scalar;
type CompressedGroupElement = PallasCompressedElementWrapper; type CompressedGroupElement = PallasCompressedElementWrapper;
type PreprocessedGroupElement = pallas::Affine; type PreprocessedGroupElement = pallas::Affine;
type HashFunc = PoseidonRO<Self::Base, Self::Scalar>;
type HashFunc = PoseidonHashFunc<Self::Base, Self::Scalar>;
type HashFuncCircuit = PoseidonHashFuncCircuit<Self::Base>;
fn vartime_multiscalar_mul( fn vartime_multiscalar_mul(
scalars: &[Self::Scalar], scalars: &[Self::Scalar],
@ -137,7 +138,8 @@ impl Group for vesta::Point {
type Scalar = vesta::Scalar; type Scalar = vesta::Scalar;
type CompressedGroupElement = VestaCompressedElementWrapper; type CompressedGroupElement = VestaCompressedElementWrapper;
type PreprocessedGroupElement = vesta::Affine; type PreprocessedGroupElement = vesta::Affine;
type HashFunc = PoseidonRO<Self::Base, Self::Scalar>;
type HashFunc = PoseidonHashFunc<Self::Base, Self::Scalar>;
type HashFuncCircuit = PoseidonHashFuncCircuit<Self::Base>;
fn vartime_multiscalar_mul( fn vartime_multiscalar_mul(
scalars: &[Self::Scalar], scalars: &[Self::Scalar],

+ 37
- 30
src/poseidon.rs

@ -1,7 +1,7 @@
//! Poseidon Constants and Poseidon-based RO used in Nova //! Poseidon Constants and Poseidon-based RO used in Nova
use super::{ use super::{
constants::{NUM_CHALLENGE_BITS, NUM_HASH_BITS}, constants::{NUM_CHALLENGE_BITS, NUM_HASH_BITS},
traits::{HashFuncConstantsTrait, HashFuncTrait},
traits::{HashFuncCircuitTrait, HashFuncConstantsTrait, HashFuncTrait},
}; };
use bellperson::{ use bellperson::{
gadgets::{ gadgets::{
@ -21,7 +21,7 @@ use neptune::{
/// All Poseidon Constants that are used in Nova /// All Poseidon Constants that are used in Nova
#[derive(Clone)] #[derive(Clone)]
pub struct ROConstantsCircuit<Scalar>
pub struct PoseidonConstantsCircuit<Scalar>
where where
Scalar: PrimeField, Scalar: PrimeField,
{ {
@ -29,7 +29,7 @@ where
constants32: PoseidonConstants<Scalar, U32>, constants32: PoseidonConstants<Scalar, U32>,
} }
impl<Scalar> HashFuncConstantsTrait<Scalar> for ROConstantsCircuit<Scalar>
impl<Scalar> HashFuncConstantsTrait<Scalar> for PoseidonConstantsCircuit<Scalar>
where where
Scalar: PrimeField + PrimeFieldBits, Scalar: PrimeField + PrimeFieldBits,
{ {
@ -46,7 +46,7 @@ where
} }
/// A Poseidon-based RO to use outside circuits /// A Poseidon-based RO to use outside circuits
pub struct PoseidonRO<Base, Scalar>
pub struct PoseidonHashFunc<Base, Scalar>
where where
Base: PrimeField + PrimeFieldBits, Base: PrimeField + PrimeFieldBits,
Scalar: PrimeField + PrimeFieldBits, Scalar: PrimeField + PrimeFieldBits,
@ -54,11 +54,11 @@ where
// Internal State // Internal State
state: Vec<Base>, state: Vec<Base>,
// Constants for Poseidon // Constants for Poseidon
constants: ROConstantsCircuit<Base>,
constants: PoseidonConstantsCircuit<Base>,
_p: PhantomData<Scalar>, _p: PhantomData<Scalar>,
} }
impl<Base, Scalar> PoseidonRO<Base, Scalar>
impl<Base, Scalar> PoseidonHashFunc<Base, Scalar>
where where
Base: PrimeField + PrimeFieldBits, Base: PrimeField + PrimeFieldBits,
Scalar: PrimeField + PrimeFieldBits, Scalar: PrimeField + PrimeFieldBits,
@ -81,14 +81,14 @@ where
} }
} }
impl<Base, Scalar> HashFuncTrait<Base, Scalar> for PoseidonRO<Base, Scalar>
impl<Base, Scalar> HashFuncTrait<Base, Scalar> for PoseidonHashFunc<Base, Scalar>
where where
Base: PrimeField + PrimeFieldBits, Base: PrimeField + PrimeFieldBits,
Scalar: PrimeField + PrimeFieldBits, Scalar: PrimeField + PrimeFieldBits,
{ {
type Constants = ROConstantsCircuit<Base>;
type Constants = PoseidonConstantsCircuit<Base>;
fn new(constants: ROConstantsCircuit<Base>) -> Self {
fn new(constants: PoseidonConstantsCircuit<Base>) -> Self {
Self { Self {
state: Vec::new(), state: Vec::new(),
constants, constants,
@ -134,32 +134,19 @@ where
} }
/// A Poseidon-based RO gadget to use inside the verifier circuit. /// A Poseidon-based RO gadget to use inside the verifier circuit.
pub struct PoseidonROGadget<Scalar>
pub struct PoseidonHashFuncCircuit<Scalar>
where where
Scalar: PrimeField + PrimeFieldBits, Scalar: PrimeField + PrimeFieldBits,
{ {
// Internal state // Internal state
state: Vec<AllocatedNum<Scalar>>, state: Vec<AllocatedNum<Scalar>>,
constants: ROConstantsCircuit<Scalar>,
constants: PoseidonConstantsCircuit<Scalar>,
} }
impl<Scalar> PoseidonROGadget<Scalar>
impl<Scalar> PoseidonHashFuncCircuit<Scalar>
where where
Scalar: PrimeField + PrimeFieldBits, Scalar: PrimeField + PrimeFieldBits,
{ {
/// Initialize the internal state and set the poseidon constants
pub fn new(constants: ROConstantsCircuit<Scalar>) -> Self {
Self {
state: Vec::new(),
constants,
}
}
/// Absorb a new number into the state of the oracle
pub fn absorb(&mut self, e: AllocatedNum<Scalar>) {
self.state.push(e);
}
fn hash_inner<CS>(&mut self, mut cs: CS) -> Result<Vec<AllocatedBit>, SynthesisError> fn hash_inner<CS>(&mut self, mut cs: CS) -> Result<Vec<AllocatedBit>, SynthesisError>
where where
CS: ConstraintSystem<Scalar>, CS: ConstraintSystem<Scalar>,
@ -195,9 +182,29 @@ where
.collect(), .collect(),
) )
} }
}
impl<Scalar> HashFuncCircuitTrait<Scalar> for PoseidonHashFuncCircuit<Scalar>
where
Scalar: PrimeField + PrimeFieldBits,
{
type Constants = PoseidonConstantsCircuit<Scalar>;
/// Initialize the internal state and set the poseidon constants
fn new(constants: PoseidonConstantsCircuit<Scalar>) -> Self {
Self {
state: Vec::new(),
constants,
}
}
/// Absorb a new number into the state of the oracle
fn absorb(&mut self, e: AllocatedNum<Scalar>) {
self.state.push(e);
}
/// Compute a challenge by hashing the current state /// Compute a challenge by hashing the current state
pub fn get_challenge<CS>(&mut self, mut cs: CS) -> Result<Vec<AllocatedBit>, SynthesisError>
fn get_challenge<CS>(&mut self, mut cs: CS) -> Result<Vec<AllocatedBit>, SynthesisError>
where where
CS: ConstraintSystem<Scalar>, CS: ConstraintSystem<Scalar>,
{ {
@ -205,7 +212,7 @@ where
Ok(bits[..NUM_CHALLENGE_BITS].into()) Ok(bits[..NUM_CHALLENGE_BITS].into())
} }
pub fn get_hash<CS>(&mut self, mut cs: CS) -> Result<Vec<AllocatedBit>, SynthesisError>
fn get_hash<CS>(&mut self, mut cs: CS) -> Result<Vec<AllocatedBit>, SynthesisError>
where where
CS: ConstraintSystem<Scalar>, CS: ConstraintSystem<Scalar>,
{ {
@ -228,9 +235,9 @@ mod tests {
fn test_poseidon_ro() { fn test_poseidon_ro() {
// Check that the number computed inside the circuit is equal to the number computed outside the circuit // Check that the number computed inside the circuit is equal to the number computed outside the circuit
let mut csprng: OsRng = OsRng; let mut csprng: OsRng = OsRng;
let constants = ROConstantsCircuit::new();
let mut ro: PoseidonRO<S, B> = PoseidonRO::new(constants.clone());
let mut ro_gadget: PoseidonROGadget<S> = PoseidonROGadget::new(constants);
let constants = PoseidonConstantsCircuit::new();
let mut ro: PoseidonHashFunc<S, B> = PoseidonHashFunc::new(constants.clone());
let mut ro_gadget: PoseidonHashFuncCircuit<S> = PoseidonHashFuncCircuit::new(constants);
let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new(); let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new();
for i in 0..27 { for i in 0..27 {
let num = S::random(&mut csprng); let num = S::random(&mut csprng);

+ 37
- 1
src/traits.rs

@ -1,5 +1,8 @@
//! This module defines various traits required by the users of the library to implement. //! This module defines various traits required by the users of the library to implement.
use bellperson::{gadgets::num::AllocatedNum, ConstraintSystem, SynthesisError};
use bellperson::{
gadgets::{boolean::AllocatedBit, num::AllocatedNum},
ConstraintSystem, SynthesisError,
};
use core::{ use core::{
fmt::Debug, fmt::Debug,
ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign}, ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign},
@ -38,6 +41,9 @@ pub trait Group:
/// from the base field and squeezes out elements of the scalar field /// from the base field and squeezes out elements of the scalar field
type HashFunc: HashFuncTrait<Self::Base, Self::Scalar>; type HashFunc: HashFuncTrait<Self::Base, Self::Scalar>;
/// An alternate implementation of Self::HashFunc in the circuit model
type HashFuncCircuit: HashFuncCircuitTrait<Self::Base>;
/// A method to compute a multiexponentation /// A method to compute a multiexponentation
fn vartime_multiscalar_mul( fn vartime_multiscalar_mul(
scalars: &[Self::Scalar], scalars: &[Self::Scalar],
@ -108,12 +114,42 @@ pub trait HashFuncTrait {
fn get_hash(&self) -> Scalar; fn get_hash(&self) -> Scalar;
} }
/// A helper trait that defines the behavior of a hash function that we use as an RO in the circuit model
pub trait HashFuncCircuitTrait<Base: PrimeField> {
/// A type representing constants/parameters associated with the hash function
type Constants: HashFuncConstantsTrait<Base> + Clone + Send + Sync;
/// Initializes the hash function
fn new(constants: Self::Constants) -> Self;
/// Adds a scalar to the internal state
fn absorb(&mut self, e: AllocatedNum<Base>);
/// Returns a random challenge by hashing the internal state
fn get_challenge<CS>(&mut self, cs: CS) -> Result<Vec<AllocatedBit>, SynthesisError>
where
CS: ConstraintSystem<Base>;
/// Returns a hash of the internal state
fn get_hash<CS>(&mut self, cs: CS) -> Result<Vec<AllocatedBit>, SynthesisError>
where
CS: ConstraintSystem<Base>;
}
/// A helper trait that defines the constants associated with a hash function /// A helper trait that defines the constants associated with a hash function
pub trait HashFuncConstantsTrait<Base> { pub trait HashFuncConstantsTrait<Base> {
/// produces constants/parameters associated with the hash function /// produces constants/parameters associated with the hash function
fn new() -> Self; fn new() -> Self;
} }
/// An alias for constants associated with G::HashFunc
pub type HashFuncConstants<G> =
<<G as Group>::HashFunc as HashFuncTrait<<G as Group>::Base, <G as Group>::Scalar>>::Constants;
/// An alias for constants associated with G::HashFuncCircuit
pub type HashFuncConstantsCircuit<G> =
<<G as Group>::HashFuncCircuit as HashFuncCircuitTrait<<G as Group>::Base>>::Constants;
/// A helper trait for types with a group operation. /// A helper trait for types with a group operation.
pub trait GroupOps<Rhs = Self, Output = Self>: pub trait GroupOps<Rhs = Self, Output = Self>:
Add<Rhs, Output = Output> + Sub<Rhs, Output = Output> + AddAssign<Rhs> + SubAssign<Rhs> Add<Rhs, Output = Output> + Sub<Rhs, Output = Output> + AddAssign<Rhs> + SubAssign<Rhs>

Loading…
Cancel
Save