mirror of https://github.com/zcash/halo2.git
Merge pull request #187 from zcash/poseidon-fq
primitives::poseidon: Add constants for Fq field modulus.
This commit is contained in:
commit
4f9c0be42e
|
@ -3,7 +3,7 @@ use std::array;
|
|||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||
use ff::Field;
|
||||
use orchard::primitives::{
|
||||
poseidon::{self, ConstantLength, OrchardNullifier},
|
||||
poseidon::{self, ConstantLength, P128Pow5T3},
|
||||
sinsemilla,
|
||||
};
|
||||
|
||||
|
@ -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(OrchardNullifier, ConstantLength).hash(message))
|
||||
b.iter(|| poseidon::Hash::init(P128Pow5T3, ConstantLength).hash(message))
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -244,7 +244,7 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
// Configuration for the Poseidon hash.
|
||||
let poseidon_config = PoseidonChip::configure(
|
||||
meta,
|
||||
poseidon::OrchardNullifier,
|
||||
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(),
|
||||
|
@ -499,7 +499,7 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
|| value.ok_or(plonk::Error::SynthesisError),
|
||||
)?;
|
||||
region.constrain_equal(var, message[i].cell())?;
|
||||
Ok(Word::<_, _, poseidon::OrchardNullifier, 3, 2>::from_inner(
|
||||
Ok(Word::<_, _, poseidon::P128Pow5T3, 3, 2>::from_inner(
|
||||
StateWord::new(var, value),
|
||||
))
|
||||
};
|
||||
|
|
|
@ -627,7 +627,7 @@ mod tests {
|
|||
use super::{PoseidonInstructions, Pow5T3Chip, Pow5T3Config, StateWord, WIDTH};
|
||||
use crate::{
|
||||
circuit::gadget::poseidon::{Hash, Word},
|
||||
primitives::poseidon::{self, ConstantLength, OrchardNullifier, Spec},
|
||||
primitives::poseidon::{self, ConstantLength, P128Pow5T3 as OrchardNullifier, Spec},
|
||||
};
|
||||
|
||||
struct PermuteCircuit {}
|
||||
|
@ -833,7 +833,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn hash_test_vectors() {
|
||||
for tv in crate::primitives::poseidon::test_vectors::hash() {
|
||||
for tv in crate::primitives::poseidon::test_vectors::fp::hash() {
|
||||
let message = [
|
||||
pallas::Base::from_repr(tv.input[0]).unwrap(),
|
||||
pallas::Base::from_repr(tv.input[1]).unwrap(),
|
||||
|
|
|
@ -7,14 +7,16 @@ use std::marker::PhantomData;
|
|||
|
||||
use halo2::arithmetic::FieldExt;
|
||||
|
||||
pub(crate) mod fp;
|
||||
pub(crate) mod fq;
|
||||
pub(crate) mod grain;
|
||||
pub(crate) mod mds;
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod test_vectors;
|
||||
|
||||
mod nullifier;
|
||||
pub use nullifier::OrchardNullifier;
|
||||
mod p128pow5t3;
|
||||
pub use p128pow5t3::P128Pow5T3;
|
||||
|
||||
use grain::SboxType;
|
||||
|
||||
|
@ -363,7 +365,7 @@ mod tests {
|
|||
use halo2::arithmetic::FieldExt;
|
||||
use pasta_curves::pallas;
|
||||
|
||||
use super::{permute, ConstantLength, Hash, OrchardNullifier, Spec};
|
||||
use super::{permute, ConstantLength, Hash, P128Pow5T3 as OrchardNullifier, Spec};
|
||||
|
||||
#[test]
|
||||
fn orchard_spec_equivalence() {
|
||||
|
|
|
@ -1,49 +1,11 @@
|
|||
use halo2::arithmetic::Field;
|
||||
//! https://github.com/daira/pasta-hadeshash
|
||||
//!
|
||||
//! $ sage generate_parameters_grain.sage 1 0 255 3 8 56 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
|
||||
use pasta_curves::pallas;
|
||||
|
||||
use super::{Mds, Spec};
|
||||
|
||||
/// Poseidon-128 using the $x^5$ S-box, with a width of 3 field elements, and the
|
||||
/// standard number of rounds for 128-bit security "with margin".
|
||||
///
|
||||
/// The standard specification for this set of parameters uses $R_F = 8, R_P = 56$.
|
||||
/// This is conveniently an even number of partial rounds, making it easier to
|
||||
/// construct a Halo 2 circuit.
|
||||
#[derive(Debug)]
|
||||
pub struct OrchardNullifier;
|
||||
|
||||
impl Spec<pallas::Base, 3, 2> for OrchardNullifier {
|
||||
fn full_rounds() -> usize {
|
||||
8
|
||||
}
|
||||
|
||||
fn partial_rounds() -> usize {
|
||||
56
|
||||
}
|
||||
|
||||
fn sbox(val: pallas::Base) -> pallas::Base {
|
||||
val.pow_vartime(&[5])
|
||||
}
|
||||
|
||||
fn secure_mds(&self) -> usize {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn constants(
|
||||
&self,
|
||||
) -> (
|
||||
Vec<[pallas::Base; 3]>,
|
||||
Mds<pallas::Base, 3>,
|
||||
Mds<pallas::Base, 3>,
|
||||
) {
|
||||
(ROUND_CONSTANTS[..].to_vec(), MDS, MDS_INV)
|
||||
}
|
||||
}
|
||||
|
||||
// $ sage generate_parameters_grain.sage 1 0 255 3 8 56 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
|
||||
// Number of round constants: 192
|
||||
// Round constants for GF(p):
|
||||
const ROUND_CONSTANTS: [[pallas::Base; 3]; 64] = [
|
||||
pub(crate) const ROUND_CONSTANTS: [[pallas::Base; 3]; 64] = [
|
||||
[
|
||||
pallas::Base::from_raw([
|
||||
0x5753_8c25_9642_6303,
|
||||
|
@ -1337,7 +1299,7 @@ const ROUND_CONSTANTS: [[pallas::Base; 3]; 64] = [
|
|||
// [True, None]
|
||||
// Prime number: 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
|
||||
// MDS matrix:
|
||||
const MDS: [[pallas::Base; 3]; 3] = [
|
||||
pub(crate) const MDS: [[pallas::Base; 3]; 3] = [
|
||||
[
|
||||
pallas::Base::from_raw([
|
||||
0x323f_2486_d7e1_1b63,
|
||||
|
@ -1400,7 +1362,7 @@ const MDS: [[pallas::Base; 3]; 3] = [
|
|||
],
|
||||
];
|
||||
|
||||
const MDS_INV: [[pallas::Base; 3]; 3] = [
|
||||
pub(crate) const MDS_INV: [[pallas::Base; 3]; 3] = [
|
||||
[
|
||||
pallas::Base::from_raw([
|
||||
0xc6de_463c_d140_4e6b,
|
||||
|
@ -1462,158 +1424,3 @@ const MDS_INV: [[pallas::Base; 3]; 3] = [
|
|||
]),
|
||||
],
|
||||
];
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use ff::PrimeField;
|
||||
use halo2::arithmetic::FieldExt;
|
||||
use pasta_curves::pallas;
|
||||
|
||||
use crate::primitives::poseidon::{permute, ConstantLength, Hash, Spec};
|
||||
|
||||
use super::{OrchardNullifier, MDS, MDS_INV, ROUND_CONSTANTS};
|
||||
|
||||
/// The same Poseidon specification as poseidon::OrchardNullifier, but constructed
|
||||
/// such that its constants will be generated at runtime.
|
||||
#[derive(Debug)]
|
||||
pub struct P128Pow5T3<F: FieldExt> {
|
||||
secure_mds: usize,
|
||||
_field: PhantomData<F>,
|
||||
}
|
||||
|
||||
impl<F: FieldExt> P128Pow5T3<F> {
|
||||
pub fn new(secure_mds: usize) -> Self {
|
||||
P128Pow5T3 {
|
||||
secure_mds,
|
||||
_field: PhantomData::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: FieldExt> Spec<F, 3, 2> for P128Pow5T3<F> {
|
||||
fn full_rounds() -> usize {
|
||||
8
|
||||
}
|
||||
|
||||
fn partial_rounds() -> usize {
|
||||
56
|
||||
}
|
||||
|
||||
fn sbox(val: F) -> F {
|
||||
val.pow_vartime(&[5])
|
||||
}
|
||||
|
||||
fn secure_mds(&self) -> usize {
|
||||
self.secure_mds
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_constants() {
|
||||
let poseidon = P128Pow5T3::<pallas::Base>::new(0);
|
||||
let (round_constants, mds, mds_inv) = poseidon.constants();
|
||||
|
||||
for (actual, expected) in round_constants
|
||||
.iter()
|
||||
.flatten()
|
||||
.zip(ROUND_CONSTANTS.iter().flatten())
|
||||
{
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
for (actual, expected) in mds.iter().flatten().zip(MDS.iter().flatten()) {
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
for (actual, expected) in mds_inv.iter().flatten().zip(MDS_INV.iter().flatten()) {
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_against_reference() {
|
||||
// This is the test vector output by the reference code at
|
||||
// <https://extgit.iaik.tugraz.at/krypto/hadeshash>, using parameters from
|
||||
// `generate_parameters_grain.sage 1 0 255 3 8 56 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001`.
|
||||
|
||||
let mut input = [
|
||||
pallas::Base::from_raw([
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
]),
|
||||
pallas::Base::from_raw([
|
||||
0x0000_0000_0000_0001,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
]),
|
||||
pallas::Base::from_raw([
|
||||
0x0000_0000_0000_0002,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
]),
|
||||
];
|
||||
|
||||
let expected_output = [
|
||||
pallas::Base::from_raw([
|
||||
0xaeb1_bc02_4aec_a456,
|
||||
0xf7e6_9a71_d0b6_42a0,
|
||||
0x94ef_b364_f966_240f,
|
||||
0x2a52_6acd_0b64_b453,
|
||||
]),
|
||||
pallas::Base::from_raw([
|
||||
0x012a_3e96_28e5_b82a,
|
||||
0xdcd4_2e7f_bed9_dafe,
|
||||
0x76ff_7dae_343d_5512,
|
||||
0x13c5_d156_8b4a_a430,
|
||||
]),
|
||||
pallas::Base::from_raw([
|
||||
0x3590_29a1_d34e_9ddd,
|
||||
0xf7cf_dfe1_bda4_2c7b,
|
||||
0x256f_cd59_7984_561a,
|
||||
0x0a49_c868_c697_6544,
|
||||
]),
|
||||
];
|
||||
|
||||
permute::<pallas::Base, P128Pow5T3<pallas::Base>, 3, 2>(&mut input, &MDS, &ROUND_CONSTANTS);
|
||||
assert_eq!(input, expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn permute_test_vectors() {
|
||||
let (round_constants, mds, _) = OrchardNullifier.constants();
|
||||
|
||||
for tv in crate::primitives::poseidon::test_vectors::permute() {
|
||||
let mut state = [
|
||||
pallas::Base::from_repr(tv.initial_state[0]).unwrap(),
|
||||
pallas::Base::from_repr(tv.initial_state[1]).unwrap(),
|
||||
pallas::Base::from_repr(tv.initial_state[2]).unwrap(),
|
||||
];
|
||||
|
||||
permute::<pallas::Base, OrchardNullifier, 3, 2>(&mut state, &mds, &round_constants);
|
||||
|
||||
for (expected, actual) in tv.final_state.iter().zip(state.iter()) {
|
||||
assert_eq!(&actual.to_repr(), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_test_vectors() {
|
||||
for tv in crate::primitives::poseidon::test_vectors::hash() {
|
||||
let message = [
|
||||
pallas::Base::from_repr(tv.input[0]).unwrap(),
|
||||
pallas::Base::from_repr(tv.input[1]).unwrap(),
|
||||
];
|
||||
|
||||
let result = Hash::init(OrchardNullifier, ConstantLength).hash(message);
|
||||
|
||||
assert_eq!(result.to_repr(), tv.output);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,318 @@
|
|||
use halo2::arithmetic::Field;
|
||||
use pasta_curves::{pallas::Base as Fp, vesta::Base as Fq};
|
||||
|
||||
use super::{Mds, Spec};
|
||||
|
||||
/// Poseidon-128 using the $x^5$ S-box, with a width of 3 field elements, and the
|
||||
/// standard number of rounds for 128-bit security "with margin".
|
||||
///
|
||||
/// The standard specification for this set of parameters (on either of the Pasta
|
||||
/// fields) uses $R_F = 8, R_P = 56$. This is conveniently an even number of
|
||||
/// partial rounds, making it easier to construct a Halo 2 circuit.
|
||||
#[derive(Debug)]
|
||||
pub struct P128Pow5T3;
|
||||
|
||||
impl Spec<Fp, 3, 2> for P128Pow5T3 {
|
||||
fn full_rounds() -> usize {
|
||||
8
|
||||
}
|
||||
|
||||
fn partial_rounds() -> usize {
|
||||
56
|
||||
}
|
||||
|
||||
fn sbox(val: Fp) -> Fp {
|
||||
val.pow_vartime(&[5])
|
||||
}
|
||||
|
||||
fn secure_mds(&self) -> usize {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn constants(&self) -> (Vec<[Fp; 3]>, Mds<Fp, 3>, Mds<Fp, 3>) {
|
||||
(
|
||||
super::fp::ROUND_CONSTANTS[..].to_vec(),
|
||||
super::fp::MDS,
|
||||
super::fp::MDS_INV,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Spec<Fq, 3, 2> for P128Pow5T3 {
|
||||
fn full_rounds() -> usize {
|
||||
8
|
||||
}
|
||||
|
||||
fn partial_rounds() -> usize {
|
||||
56
|
||||
}
|
||||
|
||||
fn sbox(val: Fq) -> Fq {
|
||||
val.pow_vartime(&[5])
|
||||
}
|
||||
|
||||
fn secure_mds(&self) -> usize {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn constants(&self) -> (Vec<[Fq; 3]>, Mds<Fq, 3>, Mds<Fq, 3>) {
|
||||
(
|
||||
super::fq::ROUND_CONSTANTS[..].to_vec(),
|
||||
super::fq::MDS,
|
||||
super::fq::MDS_INV,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ff::PrimeField;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use pasta_curves::arithmetic::FieldExt;
|
||||
|
||||
use super::{
|
||||
super::{fp, fq},
|
||||
Fp, Fq,
|
||||
};
|
||||
use crate::primitives::poseidon::{permute, ConstantLength, Hash, Spec};
|
||||
|
||||
/// 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>,
|
||||
}
|
||||
|
||||
impl<F: FieldExt> P128Pow5T3Gen<F> {
|
||||
pub fn new(secure_mds: usize) -> Self {
|
||||
P128Pow5T3Gen {
|
||||
secure_mds,
|
||||
_field: PhantomData::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: FieldExt> Spec<F, 3, 2> for P128Pow5T3Gen<F> {
|
||||
fn full_rounds() -> usize {
|
||||
8
|
||||
}
|
||||
|
||||
fn partial_rounds() -> usize {
|
||||
56
|
||||
}
|
||||
|
||||
fn sbox(val: F) -> F {
|
||||
val.pow_vartime(&[5])
|
||||
}
|
||||
|
||||
fn secure_mds(&self) -> usize {
|
||||
self.secure_mds
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_constants() {
|
||||
fn verify_constants_helper<F: FieldExt>(
|
||||
expected_round_constants: [[F; 3]; 64],
|
||||
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();
|
||||
|
||||
for (actual, expected) in round_constants
|
||||
.iter()
|
||||
.flatten()
|
||||
.zip(expected_round_constants.iter().flatten())
|
||||
{
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
for (actual, expected) in mds.iter().flatten().zip(expected_mds.iter().flatten()) {
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
for (actual, expected) in mds_inv
|
||||
.iter()
|
||||
.flatten()
|
||||
.zip(expected_mds_inv.iter().flatten())
|
||||
{
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
verify_constants_helper(fp::ROUND_CONSTANTS, fp::MDS, fp::MDS_INV);
|
||||
verify_constants_helper(fq::ROUND_CONSTANTS, fq::MDS, fq::MDS_INV);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_against_reference() {
|
||||
{
|
||||
// <https://github.com/daira/pasta-hadeshash>, using parameters from
|
||||
// `generate_parameters_grain.sage 1 0 255 3 8 56 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001`.
|
||||
// The test vector is generated by `sage poseidonperm_x5_pallas_3.sage --rust`
|
||||
|
||||
let mut input = [
|
||||
Fp::from_raw([
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0x0000_0000_0000_0001,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0x0000_0000_0000_0002,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
]),
|
||||
];
|
||||
|
||||
let expected_output = [
|
||||
Fp::from_raw([
|
||||
0xaeb1_bc02_4aec_a456,
|
||||
0xf7e6_9a71_d0b6_42a0,
|
||||
0x94ef_b364_f966_240f,
|
||||
0x2a52_6acd_0b64_b453,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0x012a_3e96_28e5_b82a,
|
||||
0xdcd4_2e7f_bed9_dafe,
|
||||
0x76ff_7dae_343d_5512,
|
||||
0x13c5_d156_8b4a_a430,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0x3590_29a1_d34e_9ddd,
|
||||
0xf7cf_dfe1_bda4_2c7b,
|
||||
0x256f_cd59_7984_561a,
|
||||
0x0a49_c868_c697_6544,
|
||||
]),
|
||||
];
|
||||
|
||||
permute::<Fp, P128Pow5T3Gen<Fp>, 3, 2>(&mut input, &fp::MDS, &fp::ROUND_CONSTANTS);
|
||||
assert_eq!(input, expected_output);
|
||||
}
|
||||
|
||||
{
|
||||
// <https://github.com/daira/pasta-hadeshash>, using parameters from
|
||||
// `generate_parameters_grain.sage 1 0 255 3 8 56 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001`.
|
||||
// The test vector is generated by `sage poseidonperm_x5_vesta_3.sage --rust`
|
||||
|
||||
let mut input = [
|
||||
Fq::from_raw([
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
]),
|
||||
Fq::from_raw([
|
||||
0x0000_0000_0000_0001,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
]),
|
||||
Fq::from_raw([
|
||||
0x0000_0000_0000_0002,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
0x0000_0000_0000_0000,
|
||||
]),
|
||||
];
|
||||
|
||||
let expected_output = [
|
||||
Fq::from_raw([
|
||||
0x0eb0_8ea8_13be_be59,
|
||||
0x4d43_d197_3dd3_36c6,
|
||||
0xeddd_74f2_2f8f_2ff7,
|
||||
0x315a_1f4c_db94_2f7c,
|
||||
]),
|
||||
Fq::from_raw([
|
||||
0xf9f1_26e6_1ea1_65f1,
|
||||
0x413e_e0eb_7bbd_2198,
|
||||
0x642a_dee0_dd13_aa48,
|
||||
0x3be4_75f2_d764_2bde,
|
||||
]),
|
||||
Fq::from_raw([
|
||||
0x14d5_4237_2a7b_a0d9,
|
||||
0x5019_bfd4_e042_3fa0,
|
||||
0x117f_db24_20d8_ea60,
|
||||
0x25ab_8aec_e953_7168,
|
||||
]),
|
||||
];
|
||||
|
||||
permute::<Fq, P128Pow5T3Gen<Fq>, 3, 2>(&mut input, &fq::MDS, &fq::ROUND_CONSTANTS);
|
||||
assert_eq!(input, expected_output);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn permute_test_vectors() {
|
||||
{
|
||||
let (round_constants, mds, _) = super::P128Pow5T3.constants();
|
||||
|
||||
for tv in crate::primitives::poseidon::test_vectors::fp::permute() {
|
||||
let mut state = [
|
||||
Fp::from_repr(tv.initial_state[0]).unwrap(),
|
||||
Fp::from_repr(tv.initial_state[1]).unwrap(),
|
||||
Fp::from_repr(tv.initial_state[2]).unwrap(),
|
||||
];
|
||||
|
||||
permute::<Fp, super::P128Pow5T3, 3, 2>(&mut state, &mds, &round_constants);
|
||||
|
||||
for (expected, actual) in tv.final_state.iter().zip(state.iter()) {
|
||||
assert_eq!(&actual.to_repr(), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let (round_constants, mds, _) = super::P128Pow5T3.constants();
|
||||
|
||||
for tv in crate::primitives::poseidon::test_vectors::fq::permute() {
|
||||
let mut state = [
|
||||
Fq::from_repr(tv.initial_state[0]).unwrap(),
|
||||
Fq::from_repr(tv.initial_state[1]).unwrap(),
|
||||
Fq::from_repr(tv.initial_state[2]).unwrap(),
|
||||
];
|
||||
|
||||
permute::<Fq, super::P128Pow5T3, 3, 2>(&mut state, &mds, &round_constants);
|
||||
|
||||
for (expected, actual) in tv.final_state.iter().zip(state.iter()) {
|
||||
assert_eq!(&actual.to_repr(), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_test_vectors() {
|
||||
for tv in crate::primitives::poseidon::test_vectors::fp::hash() {
|
||||
let message = [
|
||||
Fp::from_repr(tv.input[0]).unwrap(),
|
||||
Fp::from_repr(tv.input[1]).unwrap(),
|
||||
];
|
||||
|
||||
let result = Hash::init(super::P128Pow5T3, ConstantLength).hash(message);
|
||||
|
||||
assert_eq!(result.to_repr(), tv.output);
|
||||
}
|
||||
|
||||
for tv in crate::primitives::poseidon::test_vectors::fq::hash() {
|
||||
let message = [
|
||||
Fq::from_repr(tv.input[0]).unwrap(),
|
||||
Fq::from_repr(tv.input[1]).unwrap(),
|
||||
];
|
||||
|
||||
let result = Hash::init(super::P128Pow5T3, ConstantLength).hash(message);
|
||||
|
||||
assert_eq!(result.to_repr(), tv.output);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -212,7 +212,7 @@ 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::OrchardNullifier, poseidon::ConstantLength).hash([nk, rho])
|
||||
poseidon::Hash::init(poseidon::P128Pow5T3, poseidon::ConstantLength).hash([nk, rho])
|
||||
}
|
||||
|
||||
/// Defined in [Zcash Protocol Spec § 5.4.5.5: Orchard Key Agreement][concreteorchardkeyagreement].
|
||||
|
|
Loading…
Reference in New Issue