mirror of
https://github.com/arnaucube/Nova.git
synced 2026-01-11 08:31:29 +01:00
trait updates to support using Poseidon as RO (#43)
This commit is contained in:
@@ -335,6 +335,7 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
bellperson::r1cs::{NovaShape, NovaWitness},
|
bellperson::r1cs::{NovaShape, NovaWitness},
|
||||||
commitments::CommitTrait,
|
commitments::CommitTrait,
|
||||||
|
traits::HashFuncConstantsTrait,
|
||||||
};
|
};
|
||||||
use ff::PrimeField;
|
use ff::PrimeField;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
//! 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::traits::{ChallengeTrait, CompressedGroup, Group};
|
use crate::{
|
||||||
|
poseidon::PoseidonRO,
|
||||||
|
traits::{ChallengeTrait, CompressedGroup, Group},
|
||||||
|
};
|
||||||
use core::ops::Mul;
|
use core::ops::Mul;
|
||||||
use ff::Field;
|
use ff::Field;
|
||||||
use merlin::Transcript;
|
use merlin::Transcript;
|
||||||
@@ -33,6 +36,7 @@ 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>;
|
||||||
|
|
||||||
fn vartime_multiscalar_mul(
|
fn vartime_multiscalar_mul(
|
||||||
scalars: &[Self::Scalar],
|
scalars: &[Self::Scalar],
|
||||||
@@ -120,6 +124,7 @@ 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>;
|
||||||
|
|
||||||
fn vartime_multiscalar_mul(
|
fn vartime_multiscalar_mul(
|
||||||
scalars: &[Self::Scalar],
|
scalars: &[Self::Scalar],
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//! Poseidon Constants and Poseidon-based RO used in Nova
|
//! Poseidon Constants and Poseidon-based RO used in Nova
|
||||||
|
use crate::traits::{HashFuncConstantsTrait, HashFuncTrait};
|
||||||
use bellperson::{
|
use bellperson::{
|
||||||
gadgets::{
|
gadgets::{
|
||||||
boolean::{AllocatedBit, Boolean},
|
boolean::{AllocatedBit, Boolean},
|
||||||
@@ -6,36 +7,34 @@ use bellperson::{
|
|||||||
},
|
},
|
||||||
ConstraintSystem, SynthesisError,
|
ConstraintSystem, SynthesisError,
|
||||||
};
|
};
|
||||||
|
use core::marker::PhantomData;
|
||||||
use ff::{PrimeField, PrimeFieldBits};
|
use ff::{PrimeField, PrimeFieldBits};
|
||||||
use generic_array::typenum::{U27, U8};
|
use generic_array::typenum::{U27, U8};
|
||||||
use neptune::{
|
use neptune::{
|
||||||
circuit::poseidon_hash,
|
circuit::poseidon_hash,
|
||||||
poseidon::{Poseidon, PoseidonConstants},
|
poseidon::{Poseidon, PoseidonConstants},
|
||||||
|
Strength,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
use neptune::Strength;
|
|
||||||
|
|
||||||
/// All Poseidon Constants that are used in Nova
|
/// All Poseidon Constants that are used in Nova
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct NovaPoseidonConstants<F>
|
pub struct NovaPoseidonConstants<Scalar>
|
||||||
where
|
where
|
||||||
F: PrimeField,
|
Scalar: PrimeField,
|
||||||
{
|
{
|
||||||
constants8: PoseidonConstants<F, U8>,
|
constants8: PoseidonConstants<Scalar, U8>,
|
||||||
constants27: PoseidonConstants<F, U27>,
|
constants27: PoseidonConstants<Scalar, U27>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
impl<Scalar> HashFuncConstantsTrait<Scalar> for NovaPoseidonConstants<Scalar>
|
||||||
impl<F> NovaPoseidonConstants<F>
|
|
||||||
where
|
where
|
||||||
F: PrimeField,
|
Scalar: PrimeField + PrimeFieldBits,
|
||||||
{
|
{
|
||||||
/// Generate Poseidon constants for the arities that Nova uses
|
/// Generate Poseidon constants for the arities that Nova uses
|
||||||
#[allow(clippy::new_without_default)]
|
#[allow(clippy::new_without_default)]
|
||||||
pub fn new() -> Self {
|
fn new() -> Self {
|
||||||
let constants8 = PoseidonConstants::<F, U8>::new_with_strength(Strength::Strengthened);
|
let constants8 = PoseidonConstants::<Scalar, U8>::new_with_strength(Strength::Strengthened);
|
||||||
let constants27 = PoseidonConstants::<F, U27>::new_with_strength(Strength::Strengthened);
|
let constants27 = PoseidonConstants::<Scalar, U27>::new_with_strength(Strength::Strengthened);
|
||||||
Self {
|
Self {
|
||||||
constants8,
|
constants8,
|
||||||
constants27,
|
constants27,
|
||||||
@@ -44,41 +43,28 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A Poseidon-based RO to use outside circuits
|
/// A Poseidon-based RO to use outside circuits
|
||||||
pub struct PoseidonRO<Scalar>
|
pub struct PoseidonRO<Base, Scalar>
|
||||||
where
|
where
|
||||||
|
Base: PrimeField + PrimeFieldBits,
|
||||||
Scalar: PrimeField + PrimeFieldBits,
|
Scalar: PrimeField + PrimeFieldBits,
|
||||||
{
|
{
|
||||||
// Internal State
|
// Internal State
|
||||||
state: Vec<Scalar>,
|
state: Vec<Base>,
|
||||||
// Constants for Poseidon
|
// Constants for Poseidon
|
||||||
constants: NovaPoseidonConstants<Scalar>,
|
constants: NovaPoseidonConstants<Base>,
|
||||||
|
_p: PhantomData<Scalar>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Scalar> PoseidonRO<Scalar>
|
impl<Base, Scalar> PoseidonRO<Base, Scalar>
|
||||||
where
|
where
|
||||||
|
Base: PrimeField + PrimeFieldBits,
|
||||||
Scalar: PrimeField + PrimeFieldBits,
|
Scalar: PrimeField + PrimeFieldBits,
|
||||||
{
|
{
|
||||||
#[allow(dead_code)]
|
fn hash_inner(&self) -> Base {
|
||||||
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 {
|
|
||||||
match self.state.len() {
|
match self.state.len() {
|
||||||
8 => {
|
8 => Poseidon::<Base, U8>::new_with_preimage(&self.state, &self.constants.constants8).hash(),
|
||||||
Poseidon::<Scalar, U8>::new_with_preimage(&self.state, &self.constants.constants8).hash()
|
|
||||||
}
|
|
||||||
27 => {
|
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!(
|
panic!(
|
||||||
@@ -88,10 +74,33 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
/// Compute a challenge by hashing the current state
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn get_challenge(&mut self) -> Scalar {
|
fn get_challenge(&self) -> Scalar {
|
||||||
let hash = self.hash_inner();
|
let hash = self.hash_inner();
|
||||||
// Only keep 128 bits
|
// Only keep 128 bits
|
||||||
let bits = hash.to_le_bits();
|
let bits = hash.to_le_bits();
|
||||||
@@ -107,7 +116,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn get_hash(&mut self) -> Scalar {
|
fn get_hash(&self) -> Scalar {
|
||||||
let hash = self.hash_inner();
|
let hash = self.hash_inner();
|
||||||
// Only keep 250 bits
|
// Only keep 250 bits
|
||||||
let bits = hash.to_le_bits();
|
let bits = hash.to_le_bits();
|
||||||
@@ -214,6 +223,7 @@ where
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
type S = pasta_curves::pallas::Scalar;
|
type S = pasta_curves::pallas::Scalar;
|
||||||
|
type B = pasta_curves::vesta::Scalar;
|
||||||
type G = pasta_curves::pallas::Point;
|
type G = pasta_curves::pallas::Point;
|
||||||
use crate::{bellperson::solver::SatisfyingAssignment, gadgets::utils::le_bits_to_num};
|
use crate::{bellperson::solver::SatisfyingAssignment, gadgets::utils::le_bits_to_num};
|
||||||
use ff::Field;
|
use ff::Field;
|
||||||
@@ -224,7 +234,7 @@ mod tests {
|
|||||||
// 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 = NovaPoseidonConstants::new();
|
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 ro_gadget: PoseidonROGadget<S> = PoseidonROGadget::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 {
|
||||||
@@ -240,6 +250,6 @@ mod tests {
|
|||||||
let num = ro.get_challenge();
|
let num = ro.get_challenge();
|
||||||
let num2_bits = ro_gadget.get_challenge(&mut cs).unwrap();
|
let num2_bits = ro_gadget.get_challenge(&mut cs).unwrap();
|
||||||
let num2 = le_bits_to_num(&mut cs, num2_bits).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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,10 @@ pub trait Group:
|
|||||||
/// A type representing preprocessed group element
|
/// A type representing preprocessed group element
|
||||||
type PreprocessedGroupElement;
|
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
|
/// A method to compute a multiexponentation
|
||||||
fn vartime_multiscalar_mul(
|
fn vartime_multiscalar_mul(
|
||||||
scalars: &[Self::Scalar],
|
scalars: &[Self::Scalar],
|
||||||
@@ -70,6 +74,30 @@ pub trait ChallengeTrait {
|
|||||||
fn challenge(label: &'static [u8], transcript: &mut Transcript) -> Self;
|
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.
|
/// 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>
|
||||||
|
|||||||
Reference in New Issue
Block a user