mirror of https://github.com/zcash/halo2.git
Simplify poseidon::Spec and remove poseidon::Generic
Poseidon specifications are now all concrete, and only generation of constants at runtime requires an instance of the specification.
This commit is contained in:
parent
266705166f
commit
5c8e9beea7
|
@ -14,98 +14,87 @@ use grain::SboxType;
|
|||
/// A specification for a Poseidon permutation.
|
||||
pub trait Spec<F: FieldExt> {
|
||||
/// The arity of this specification.
|
||||
fn arity(&self) -> usize;
|
||||
fn arity() -> usize;
|
||||
|
||||
/// The number of full rounds for this specification.
|
||||
fn full_rounds(&self) -> usize;
|
||||
fn full_rounds() -> usize;
|
||||
|
||||
/// The number of partial rounds for this specification.
|
||||
fn partial_rounds(&self) -> usize;
|
||||
fn partial_rounds() -> usize;
|
||||
|
||||
fn sbox(&self, val: F) -> F;
|
||||
/// The S-box for this specification.
|
||||
fn sbox(val: F) -> F;
|
||||
|
||||
/// Side-loaded index of the first correct and secure MDS that will be generated by
|
||||
/// the reference implementation.
|
||||
///
|
||||
/// This is used by the default implementation of [`Spec::constants`]. If you are
|
||||
/// hard-coding the constants, you may leave this unimplemented.
|
||||
fn secure_mds(&self) -> usize;
|
||||
|
||||
/// Generates `(round_constants, mds, mds^-1)` corresponding to this specification.
|
||||
fn constants(&self) -> (Vec<Vec<F>>, Vec<Vec<F>>, Vec<Vec<F>>);
|
||||
fn constants(&self) -> (Vec<Vec<F>>, Vec<Vec<F>>, Vec<Vec<F>>) {
|
||||
let t = Self::arity();
|
||||
let r_f = Self::full_rounds();
|
||||
let r_p = Self::partial_rounds();
|
||||
|
||||
let mut grain = grain::Grain::new(SboxType::Pow, t as u16, r_f as u16, r_p as u16);
|
||||
|
||||
let round_constants = (0..(r_f + r_p))
|
||||
.map(|_| (0..t).map(|_| grain.next_field_element()).collect())
|
||||
.collect();
|
||||
|
||||
let (mds, mds_inv) = mds::generate_mds(&mut grain, t, self.secure_mds());
|
||||
|
||||
(round_constants, mds, mds_inv)
|
||||
}
|
||||
}
|
||||
|
||||
/// A generic Poseidon specification.
|
||||
/// Poseidon-256 with arity 3, using the `x^5` S-box.
|
||||
#[derive(Debug)]
|
||||
pub struct Generic<F: FieldExt> {
|
||||
pow_sbox: u64,
|
||||
/// The arity of the Poseidon permutation.
|
||||
t: u16,
|
||||
/// The number of full rounds.
|
||||
r_f: u16,
|
||||
/// The number of partial rounds.
|
||||
r_p: u16,
|
||||
/// The index of the first secure MDS matrix that will be generated for the given
|
||||
/// parameters.
|
||||
pub struct P256Pow5T3<F: FieldExt> {
|
||||
secure_mds: usize,
|
||||
_field: PhantomData<F>,
|
||||
}
|
||||
|
||||
impl<F: FieldExt> Generic<F> {
|
||||
/// Creates a new Poseidon specification for a field, using the `x^\alpha` S-box.
|
||||
pub fn with_pow_sbox(
|
||||
pow_sbox: u64,
|
||||
arity: usize,
|
||||
full_rounds: usize,
|
||||
partial_rounds: usize,
|
||||
secure_mds: usize,
|
||||
) -> Self {
|
||||
Generic {
|
||||
pow_sbox,
|
||||
t: arity as u16,
|
||||
r_f: full_rounds as u16,
|
||||
r_p: partial_rounds as u16,
|
||||
impl<F: FieldExt> P256Pow5T3<F> {
|
||||
pub fn new(secure_mds: usize) -> Self {
|
||||
P256Pow5T3 {
|
||||
secure_mds,
|
||||
_field: PhantomData::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: FieldExt> Spec<F> for Generic<F> {
|
||||
fn arity(&self) -> usize {
|
||||
self.t as usize
|
||||
impl<F: FieldExt> Spec<F> for P256Pow5T3<F> {
|
||||
fn arity() -> usize {
|
||||
3
|
||||
}
|
||||
|
||||
fn full_rounds(&self) -> usize {
|
||||
self.r_f as usize
|
||||
fn full_rounds() -> usize {
|
||||
8
|
||||
}
|
||||
|
||||
fn partial_rounds(&self) -> usize {
|
||||
self.r_p as usize
|
||||
fn partial_rounds() -> usize {
|
||||
120
|
||||
}
|
||||
|
||||
fn sbox(&self, val: F) -> F {
|
||||
val.pow_vartime(&[self.pow_sbox])
|
||||
fn sbox(val: F) -> F {
|
||||
val.pow_vartime(&[5])
|
||||
}
|
||||
|
||||
fn constants(&self) -> (Vec<Vec<F>>, Vec<Vec<F>>, Vec<Vec<F>>) {
|
||||
let mut grain = grain::Grain::new(SboxType::Pow, self.t, self.r_f, self.r_p);
|
||||
|
||||
let round_constants = (0..(self.r_f + self.r_p))
|
||||
.map(|_| (0..self.t).map(|_| grain.next_field_element()).collect())
|
||||
.collect();
|
||||
|
||||
let (mds, mds_inv) = mds::generate_mds(&mut grain, self.t as usize, self.secure_mds);
|
||||
|
||||
(round_constants, mds, mds_inv)
|
||||
fn secure_mds(&self) -> usize {
|
||||
self.secure_mds
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs the Poseidon permutation on the given state.
|
||||
fn permute<F: FieldExt, S: Spec<F>>(
|
||||
state: &mut [F],
|
||||
spec: &S,
|
||||
mds: &[Vec<F>],
|
||||
round_constants: &[Vec<F>],
|
||||
) {
|
||||
fn permute<F: FieldExt, S: Spec<F>>(state: &mut [F], mds: &[Vec<F>], round_constants: &[Vec<F>]) {
|
||||
// TODO: Remove this when we can use const generics.
|
||||
assert!(state.len() == spec.arity());
|
||||
assert!(state.len() == S::arity());
|
||||
|
||||
let r_f = spec.full_rounds() / 2;
|
||||
let r_p = spec.partial_rounds();
|
||||
let r_f = S::full_rounds() / 2;
|
||||
let r_p = S::partial_rounds();
|
||||
|
||||
let apply_mds = |state: &mut [F]| {
|
||||
let new_state: Vec<_> = mds
|
||||
|
@ -124,7 +113,7 @@ fn permute<F: FieldExt, S: Spec<F>>(
|
|||
|
||||
let full_round = |state: &mut [F], rcs: &[F]| {
|
||||
for (word, rc) in state.iter_mut().zip(rcs.iter()) {
|
||||
*word = spec.sbox(*word + rc);
|
||||
*word = S::sbox(*word + rc);
|
||||
}
|
||||
apply_mds(state);
|
||||
};
|
||||
|
@ -133,7 +122,7 @@ fn permute<F: FieldExt, S: Spec<F>>(
|
|||
for (word, rc) in state.iter_mut().zip(rcs.iter()) {
|
||||
*word += rc;
|
||||
}
|
||||
state[0] = spec.sbox(state[0]);
|
||||
state[0] = S::sbox(state[0]);
|
||||
apply_mds(state);
|
||||
};
|
||||
|
||||
|
@ -166,41 +155,36 @@ enum SpongeState<F: FieldExt> {
|
|||
|
||||
/// A Poseidon duplex sponge.
|
||||
pub struct Duplex<F: FieldExt, S: Spec<F>> {
|
||||
spec: S,
|
||||
sponge: Option<SpongeState<F>>,
|
||||
state: Vec<F>,
|
||||
rate: usize,
|
||||
mds_matrix: Vec<Vec<F>>,
|
||||
round_constants: Vec<Vec<F>>,
|
||||
_marker: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<F: FieldExt, S: Spec<F>> Duplex<F, S> {
|
||||
/// Constructs a new duplex sponge with the given rate.
|
||||
pub fn new(spec: S, rate: usize) -> Self {
|
||||
assert!(rate < spec.arity());
|
||||
assert!(rate < S::arity());
|
||||
|
||||
let state = vec![F::zero(); spec.arity()];
|
||||
let state = vec![F::zero(); S::arity()];
|
||||
let (round_constants, mds_matrix, _) = spec.constants();
|
||||
|
||||
Duplex {
|
||||
spec,
|
||||
sponge: Some(SpongeState::Absorbing(vec![])),
|
||||
state,
|
||||
rate,
|
||||
mds_matrix,
|
||||
round_constants,
|
||||
_marker: PhantomData::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn process(&mut self, input: &[F]) -> Vec<F> {
|
||||
pad_and_add(&mut self.state[..self.rate], input);
|
||||
|
||||
permute(
|
||||
&mut self.state,
|
||||
&self.spec,
|
||||
&self.mds_matrix,
|
||||
&self.round_constants,
|
||||
);
|
||||
permute::<F, S>(&mut self.state, &self.mds_matrix, &self.round_constants);
|
||||
|
||||
self.state[..self.rate].to_vec()
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use halo2::arithmetic::FieldExt;
|
||||
use pasta_curves::pallas;
|
||||
|
||||
use super::{Generic, Spec};
|
||||
use super::{P256Pow5T3, Spec};
|
||||
|
||||
// $ sage generate_parameters_grain.sage 1 0 255 3 8 120 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
|
||||
// Number of round constants: 384
|
||||
|
@ -424,7 +424,7 @@ const MDS: [[&str; 3]; 3] = [
|
|||
|
||||
#[test]
|
||||
fn test_vectors() {
|
||||
let poseidon = Generic::<pallas::Base>::with_pow_sbox(5, 3, 8, 120, 0);
|
||||
let poseidon = P256Pow5T3::<pallas::Base>::new(0);
|
||||
let (round_constants, mds, _) = poseidon.constants();
|
||||
|
||||
for (actual, expected) in round_constants
|
||||
|
|
Loading…
Reference in New Issue