arnaucube
arnaucube/NovaPublic Self-hosted repository
trait updates to support using Poseidon as RO (#43)

Srinath Setty srinath@microsoft.com
Wed, 11 May 2022 11:06:24 +0530
commit

f11a8f19d162b4336af8d27c0943476978a50a66

parent

9a466d14671a6927a38bcc69d15b3c3a05c7e5f3

4 files changed, 85 insertions(+), 41 deletions(-)

jump to
M src/circuit.rs → src/circuit.rs

@@ -335,6 +335,7 @@ type G2 = pasta_curves::vesta::Point;

use crate::{ bellperson::r1cs::{NovaShape, NovaWitness}, commitments::CommitTrait, + traits::HashFuncConstantsTrait, }; use ff::PrimeField; use std::marker::PhantomData;
M src/pasta.rs → src/pasta.rs

@@ -1,5 +1,8 @@

//! This module implements the Nova traits for pallas::Point, pallas::Scalar, vesta::Point, vesta::Scalar. -use crate::traits::{ChallengeTrait, CompressedGroup, Group}; +use crate::{ + poseidon::PoseidonRO, + traits::{ChallengeTrait, CompressedGroup, Group}, +}; use core::ops::Mul; use ff::Field; use merlin::Transcript;

@@ -33,6 +36,7 @@ type Base = pallas::Base;

type Scalar = pallas::Scalar; type CompressedGroupElement = PallasCompressedElementWrapper; type PreprocessedGroupElement = pallas::Affine; + type HashFunc = PoseidonRO<Self::Base, Self::Scalar>; fn vartime_multiscalar_mul( scalars: &[Self::Scalar],

@@ -120,6 +124,7 @@ type Base = vesta::Base;

type Scalar = vesta::Scalar; type CompressedGroupElement = VestaCompressedElementWrapper; type PreprocessedGroupElement = vesta::Affine; + type HashFunc = PoseidonRO<Self::Base, Self::Scalar>; fn vartime_multiscalar_mul( scalars: &[Self::Scalar],
M src/poseidon.rs → src/poseidon.rs

@@ -1,4 +1,5 @@

//! Poseidon Constants and Poseidon-based RO used in Nova +use crate::traits::{HashFuncConstantsTrait, HashFuncTrait}; use bellperson::{ gadgets::{ boolean::{AllocatedBit, Boolean},

@@ -6,36 +7,34 @@ num::AllocatedNum,

}, ConstraintSystem, SynthesisError, }; +use core::marker::PhantomData; use ff::{PrimeField, PrimeFieldBits}; use generic_array::typenum::{U27, U8}; use neptune::{ circuit::poseidon_hash, poseidon::{Poseidon, PoseidonConstants}, + Strength, }; - -#[cfg(test)] -use neptune::Strength; /// All Poseidon Constants that are used in Nova #[derive(Clone)] -pub struct NovaPoseidonConstants<F> +pub struct NovaPoseidonConstants<Scalar> where - F: PrimeField, + Scalar: PrimeField, { - constants8: PoseidonConstants<F, U8>, - constants27: PoseidonConstants<F, U27>, + constants8: PoseidonConstants<Scalar, U8>, + constants27: PoseidonConstants<Scalar, U27>, } -#[cfg(test)] -impl<F> NovaPoseidonConstants<F> +impl<Scalar> HashFuncConstantsTrait<Scalar> for NovaPoseidonConstants<Scalar> where - F: PrimeField, + Scalar: PrimeField + PrimeFieldBits, { /// Generate Poseidon constants for the arities that Nova uses #[allow(clippy::new_without_default)] - pub fn new() -> Self { - let constants8 = PoseidonConstants::<F, U8>::new_with_strength(Strength::Strengthened); - let constants27 = PoseidonConstants::<F, U27>::new_with_strength(Strength::Strengthened); + fn new() -> Self { + let constants8 = PoseidonConstants::<Scalar, U8>::new_with_strength(Strength::Strengthened); + let constants27 = PoseidonConstants::<Scalar, U27>::new_with_strength(Strength::Strengthened); Self { constants8, constants27,

@@ -44,41 +43,28 @@ }

} /// A Poseidon-based RO to use outside circuits -pub struct PoseidonRO<Scalar> +pub struct PoseidonRO<Base, Scalar> where + Base: PrimeField + PrimeFieldBits, Scalar: PrimeField + PrimeFieldBits, { // Internal State - state: Vec<Scalar>, + state: Vec<Base>, // Constants for Poseidon - constants: NovaPoseidonConstants<Scalar>, + constants: NovaPoseidonConstants<Base>, + _p: PhantomData<Scalar>, } -impl<Scalar> PoseidonRO<Scalar> +impl<Base, Scalar> PoseidonRO<Base, Scalar> where + Base: PrimeField + PrimeFieldBits, Scalar: PrimeField + PrimeFieldBits, { - #[allow(dead_code)] - pub fn new(constants: NovaPoseidonConstants<Scalar>) -> Self { - Self { - state: Vec::new(), - constants, - } - } - - /// Absorb a new number into the state of the oracle - #[allow(dead_code)] - pub fn absorb(&mut self, e: Scalar) { - self.state.push(e); - } - - fn hash_inner(&mut self) -> Scalar { + fn hash_inner(&self) -> Base { match self.state.len() { - 8 => { - Poseidon::<Scalar, U8>::new_with_preimage(&self.state, &self.constants.constants8).hash() - } + 8 => Poseidon::<Base, U8>::new_with_preimage(&self.state, &self.constants.constants8).hash(), 27 => { - Poseidon::<Scalar, U27>::new_with_preimage(&self.state, &self.constants.constants27).hash() + Poseidon::<Base, U27>::new_with_preimage(&self.state, &self.constants.constants27).hash() } _ => { panic!(

@@ -88,10 +74,33 @@ );

} } } +} + +impl<Base, Scalar> HashFuncTrait<Base, Scalar> for PoseidonRO<Base, Scalar> +where + Base: PrimeField + PrimeFieldBits, + Scalar: PrimeField + PrimeFieldBits, +{ + type Constants = NovaPoseidonConstants<Base>; + + #[allow(dead_code)] + fn new(constants: NovaPoseidonConstants<Base>) -> Self { + Self { + state: Vec::new(), + constants, + _p: PhantomData::default(), + } + } + + /// Absorb a new number into the state of the oracle + #[allow(dead_code)] + fn absorb(&mut self, e: Base) { + self.state.push(e); + } /// Compute a challenge by hashing the current state #[allow(dead_code)] - pub fn get_challenge(&mut self) -> Scalar { + fn get_challenge(&self) -> Scalar { let hash = self.hash_inner(); // Only keep 128 bits let bits = hash.to_le_bits();

@@ -107,7 +116,7 @@ res

} #[allow(dead_code)] - pub fn get_hash(&mut self) -> Scalar { + fn get_hash(&self) -> Scalar { let hash = self.hash_inner(); // Only keep 250 bits let bits = hash.to_le_bits();

@@ -214,6 +223,7 @@ #[cfg(test)]

mod tests { use super::*; type S = pasta_curves::pallas::Scalar; + type B = pasta_curves::vesta::Scalar; type G = pasta_curves::pallas::Point; use crate::{bellperson::solver::SatisfyingAssignment, gadgets::utils::le_bits_to_num}; use ff::Field;

@@ -224,7 +234,7 @@ fn test_poseidon_ro() {

// Check that the number computed inside the circuit is equal to the number computed outside the circuit let mut csprng: OsRng = OsRng; let constants = NovaPoseidonConstants::new(); - let mut ro: PoseidonRO<S> = PoseidonRO::new(constants.clone()); + let mut ro: PoseidonRO<S, B> = PoseidonRO::new(constants.clone()); let mut ro_gadget: PoseidonROGadget<S> = PoseidonROGadget::new(constants); let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new(); for i in 0..27 {

@@ -240,6 +250,6 @@ }

let num = ro.get_challenge(); let num2_bits = ro_gadget.get_challenge(&mut cs).unwrap(); let num2 = le_bits_to_num(&mut cs, num2_bits).unwrap(); - assert_eq!(num, num2.get_value().unwrap()); + assert_eq!(num.to_repr(), num2.get_value().unwrap().to_repr()); } }
M src/traits.rs → src/traits.rs

@@ -32,6 +32,10 @@

/// A type representing preprocessed group element type PreprocessedGroupElement; + /// A type that represents a hash function that consumes elements + /// from the base field and squeezes out elements of the scalar field + type HashFunc: HashFuncTrait<Self::Base, Self::Scalar>; + /// A method to compute a multiexponentation fn vartime_multiscalar_mul( scalars: &[Self::Scalar],

@@ -68,6 +72,30 @@ /// A helper trait to generate challenges using a transcript object

pub trait ChallengeTrait { /// Returns a Scalar representing the challenge using the transcript fn challenge(label: &'static [u8], transcript: &mut Transcript) -> Self; +} + +/// A helper trait that defines the behavior of a hash function that we use as an RO +pub trait HashFuncTrait<Base, Scalar> { + /// A type representing constants/parameters associated with the hash function + type Constants: HashFuncConstantsTrait<Base>; + + /// Initializes the hash function + fn new(constants: Self::Constants) -> Self; + + /// Adds a scalar to the internal state + fn absorb(&mut self, e: Base); + + /// Returns a random challenge by hashing the internal state + fn get_challenge(&self) -> Scalar; + + /// Returns a hash of the internal state + fn get_hash(&self) -> Scalar; +} + +/// A helper trait that defines the constants associated with a hash function +pub trait HashFuncConstantsTrait<Base> { + /// produces constants/parameters associated with the hash function + fn new() -> Self; } /// A helper trait for types with a group operation.