poseidon: Make Spec trait methods not take (&self) parameter.

This commit is contained in:
therealyingtong 2021-11-03 14:12:24 +01:00
parent aa251befbc
commit b63c868591
6 changed files with 38 additions and 49 deletions

View File

@ -21,7 +21,7 @@ fn bench_primitives(c: &mut Criterion) {
let message = [pallas::Base::random(rng), pallas::Base::random(rng)];
group.bench_function("2-to-1", |b| {
b.iter(|| poseidon::Hash::init(P128Pow5T3, ConstantLength).hash(message))
b.iter(|| poseidon::Hash::<_, P128Pow5T3, _, 3, 2>::init(ConstantLength).hash(message))
});
}

View File

@ -239,9 +239,8 @@ impl plonk::Circuit<pallas::Base> for Circuit {
let ecc_config = EccChip::configure(meta, advices, lagrange_coeffs, range_check.clone());
// Configuration for the Poseidon hash.
let poseidon_config = PoseidonChip::configure(
let poseidon_config = PoseidonChip::configure::<poseidon::P128Pow5T3>(
meta,
poseidon::P128Pow5T3,
// We place the state columns after the partial_sbox column so that the
// pad-and-add region can be layed out more efficiently.
advices[6..9].try_into().unwrap(),

View File

@ -52,7 +52,6 @@ impl<F: FieldExt, const WIDTH: usize, const RATE: usize> Pow5Chip<F, WIDTH, RATE
// necessary for the permutation.
pub fn configure<S: Spec<F, WIDTH, RATE>>(
meta: &mut ConstraintSystem<F>,
spec: S,
state: [Column<Advice>; WIDTH],
partial_sbox: Column<Advice>,
rc_a: [Column<Fixed>; WIDTH],
@ -65,7 +64,7 @@ impl<F: FieldExt, const WIDTH: usize, const RATE: usize> Pow5Chip<F, WIDTH, RATE
assert!(S::partial_rounds() & 1 == 0);
let half_full_rounds = S::full_rounds() / 2;
let half_partial_rounds = S::partial_rounds() / 2;
let (round_constants, m_reg, m_inv) = spec.constants();
let (round_constants, m_reg, m_inv) = S::constants();
// This allows state words to be initialized (by constraining them equal to fixed
// values), and used in a permutation from an arbitrary region. rc_a is used in
@ -649,7 +648,7 @@ mod tests {
meta.fixed_column(),
];
Pow5Chip::configure(meta, OrchardNullifier, state, partial_sbox, rc_a, rc_b)
Pow5Chip::configure::<OrchardNullifier>(meta, state, partial_sbox, rc_a, rc_b)
}
fn synthesize(
@ -685,7 +684,7 @@ mod tests {
// For the purpose of this test, compute the real final state inline.
let mut expected_final_state = [Fp::zero(), Fp::one(), Fp::from_u64(2)];
let (round_constants, mds, _) = OrchardNullifier.constants();
let (round_constants, mds, _) = OrchardNullifier::constants();
poseidon::permute::<_, OrchardNullifier, WIDTH, RATE>(
&mut expected_final_state,
&mds,
@ -758,7 +757,7 @@ mod tests {
meta.enable_constant(rc_b[0]);
Pow5Chip::configure(meta, OrchardNullifier, state, partial_sbox, rc_a, rc_b)
Pow5Chip::configure::<OrchardNullifier>(meta, state, partial_sbox, rc_a, rc_b)
}
fn synthesize(
@ -811,7 +810,8 @@ mod tests {
#[test]
fn poseidon_hash() {
let message = [Fp::rand(), Fp::rand()];
let output = poseidon::Hash::init(OrchardNullifier, ConstantLength::<2>).hash(message);
let output =
poseidon::Hash::<_, OrchardNullifier, _, 3, 2>::init(ConstantLength::<2>).hash(message);
let k = 6;
let circuit = HashCircuit {
@ -829,7 +829,8 @@ mod tests {
pallas::Base::from_repr(tv.input[0]).unwrap(),
pallas::Base::from_repr(tv.input[1]).unwrap(),
];
let output = poseidon::Hash::init(OrchardNullifier, ConstantLength).hash(message);
let output =
poseidon::Hash::<_, OrchardNullifier, _, 3, 2>::init(ConstantLength).hash(message);
let k = 6;
let circuit = HashCircuit {

View File

@ -47,10 +47,10 @@ pub trait Spec<F: FieldExt, const T: usize, const RATE: usize> {
///
/// 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;
fn secure_mds() -> usize;
/// Generates `(round_constants, mds, mds^-1)` corresponding to this specification.
fn constants(&self) -> (Vec<[F; T]>, Mds<F, T>, Mds<F, T>) {
fn constants() -> (Vec<[F; T]>, Mds<F, T>, Mds<F, T>) {
let r_f = Self::full_rounds();
let r_p = Self::partial_rounds();
@ -69,7 +69,7 @@ pub trait Spec<F: FieldExt, const T: usize, const RATE: usize> {
})
.collect();
let (mds, mds_inv) = mds::generate_mds::<F, T>(&mut grain, self.secure_mds());
let (mds, mds_inv) = mds::generate_mds::<F, T>(&mut grain, Self::secure_mds());
(round_constants, mds, mds_inv)
}
@ -167,11 +167,10 @@ pub(crate) struct Duplex<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const
impl<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize> Duplex<F, S, T, RATE> {
/// Constructs a new duplex sponge for the given Poseidon specification.
pub(crate) fn new(
spec: S,
initial_capacity_element: F,
pad_and_add: Box<dyn Fn(&mut State<F, T>, &SpongeState<F, RATE>)>,
) -> Self {
let (round_constants, mds_matrix, _) = spec.constants();
let (round_constants, mds_matrix, _) = S::constants();
let input = [None; RATE];
let mut state = [F::zero(); T];
@ -336,13 +335,9 @@ impl<
> Hash<F, S, D, T, RATE>
{
/// Initializes a new hasher.
pub fn init(spec: S, domain: D) -> Self {
pub fn init(domain: D) -> Self {
Hash {
duplex: Duplex::new(
spec,
domain.initial_capacity_element(),
domain.pad_and_add(),
),
duplex: Duplex::new(domain.initial_capacity_element(), domain.pad_and_add()),
domain,
}
}
@ -371,9 +366,9 @@ mod tests {
fn orchard_spec_equivalence() {
let message = [pallas::Base::from_u64(6), pallas::Base::from_u64(42)];
let (round_constants, mds, _) = OrchardNullifier.constants();
let (round_constants, mds, _) = OrchardNullifier::constants();
let hasher = Hash::init(OrchardNullifier, ConstantLength);
let hasher = Hash::<_, OrchardNullifier, _, 3, 2>::init(ConstantLength);
let result = hasher.hash(message);
// The result should be equivalent to just directly applying the permutation and

View File

@ -25,11 +25,11 @@ impl Spec<Fp, 3, 2> for P128Pow5T3 {
val.pow_vartime(&[5])
}
fn secure_mds(&self) -> usize {
fn secure_mds() -> usize {
unimplemented!()
}
fn constants(&self) -> (Vec<[Fp; 3]>, Mds<Fp, 3>, Mds<Fp, 3>) {
fn constants() -> (Vec<[Fp; 3]>, Mds<Fp, 3>, Mds<Fp, 3>) {
(
super::fp::ROUND_CONSTANTS[..].to_vec(),
super::fp::MDS,
@ -51,11 +51,11 @@ impl Spec<Fq, 3, 2> for P128Pow5T3 {
val.pow_vartime(&[5])
}
fn secure_mds(&self) -> usize {
fn secure_mds() -> usize {
unimplemented!()
}
fn constants(&self) -> (Vec<[Fq; 3]>, Mds<Fq, 3>, Mds<Fq, 3>) {
fn constants() -> (Vec<[Fq; 3]>, Mds<Fq, 3>, Mds<Fq, 3>) {
(
super::fq::ROUND_CONSTANTS[..].to_vec(),
super::fq::MDS,
@ -80,21 +80,15 @@ mod tests {
/// The same Poseidon specification as poseidon::P128Pow5T3, but constructed
/// such that its constants will be generated at runtime.
#[derive(Debug)]
pub struct P128Pow5T3Gen<F: FieldExt> {
secure_mds: usize,
_field: PhantomData<F>,
}
pub struct P128Pow5T3Gen<F: FieldExt, const SECURE_MDS: usize>(PhantomData<F>);
impl<F: FieldExt> P128Pow5T3Gen<F> {
pub fn new(secure_mds: usize) -> Self {
P128Pow5T3Gen {
secure_mds,
_field: PhantomData::default(),
}
impl<F: FieldExt, const SECURE_MDS: usize> P128Pow5T3Gen<F, SECURE_MDS> {
pub fn new() -> Self {
P128Pow5T3Gen(PhantomData::default())
}
}
impl<F: FieldExt> Spec<F, 3, 2> for P128Pow5T3Gen<F> {
impl<F: FieldExt, const SECURE_MDS: usize> Spec<F, 3, 2> for P128Pow5T3Gen<F, SECURE_MDS> {
fn full_rounds() -> usize {
8
}
@ -107,8 +101,8 @@ mod tests {
val.pow_vartime(&[5])
}
fn secure_mds(&self) -> usize {
self.secure_mds
fn secure_mds() -> usize {
SECURE_MDS
}
}
@ -119,8 +113,7 @@ mod tests {
expected_mds: [[F; 3]; 3],
expected_mds_inv: [[F; 3]; 3],
) {
let poseidon = P128Pow5T3Gen::<F>::new(0);
let (round_constants, mds, mds_inv) = poseidon.constants();
let (round_constants, mds, mds_inv) = P128Pow5T3Gen::<F, 0>::constants();
for (actual, expected) in round_constants
.iter()
@ -196,7 +189,7 @@ mod tests {
]),
];
permute::<Fp, P128Pow5T3Gen<Fp>, 3, 2>(&mut input, &fp::MDS, &fp::ROUND_CONSTANTS);
permute::<Fp, P128Pow5T3Gen<Fp, 0>, 3, 2>(&mut input, &fp::MDS, &fp::ROUND_CONSTANTS);
assert_eq!(input, expected_output);
}
@ -247,7 +240,7 @@ mod tests {
]),
];
permute::<Fq, P128Pow5T3Gen<Fq>, 3, 2>(&mut input, &fq::MDS, &fq::ROUND_CONSTANTS);
permute::<Fq, P128Pow5T3Gen<Fq, 0>, 3, 2>(&mut input, &fq::MDS, &fq::ROUND_CONSTANTS);
assert_eq!(input, expected_output);
}
}
@ -255,7 +248,7 @@ mod tests {
#[test]
fn permute_test_vectors() {
{
let (round_constants, mds, _) = super::P128Pow5T3.constants();
let (round_constants, mds, _) = super::P128Pow5T3::constants();
for tv in crate::primitives::poseidon::test_vectors::fp::permute() {
let mut state = [
@ -273,7 +266,7 @@ mod tests {
}
{
let (round_constants, mds, _) = super::P128Pow5T3.constants();
let (round_constants, mds, _) = super::P128Pow5T3::constants();
for tv in crate::primitives::poseidon::test_vectors::fq::permute() {
let mut state = [
@ -299,7 +292,7 @@ mod tests {
Fp::from_repr(tv.input[1]).unwrap(),
];
let result = Hash::init(super::P128Pow5T3, ConstantLength).hash(message);
let result = Hash::<_, super::P128Pow5T3, _, 3, 2>::init(ConstantLength).hash(message);
assert_eq!(result.to_repr(), tv.output);
}
@ -310,7 +303,7 @@ mod tests {
Fq::from_repr(tv.input[1]).unwrap(),
];
let result = Hash::init(super::P128Pow5T3, ConstantLength).hash(message);
let result = Hash::<_, super::P128Pow5T3, _, 3, 2>::init(ConstantLength).hash(message);
assert_eq!(result.to_repr(), tv.output);
}

View File

@ -212,7 +212,8 @@ pub(crate) fn diversify_hash(d: &[u8; 11]) -> NonIdentityPallasPoint {
///
/// [concreteprfs]: https://zips.z.cash/protocol/nu5.pdf#concreteprfs
pub(crate) fn prf_nf(nk: pallas::Base, rho: pallas::Base) -> pallas::Base {
poseidon::Hash::init(poseidon::P128Pow5T3, poseidon::ConstantLength).hash([nk, rho])
poseidon::Hash::<_, poseidon::P128Pow5T3, _, 3, 2>::init(poseidon::ConstantLength)
.hash([nk, rho])
}
/// Defined in [Zcash Protocol Spec § 5.4.5.5: Orchard Key Agreement][concreteorchardkeyagreement].