mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
halo2: Add poseidon hash primitives
This commit is contained in:
2
examples/halo2/src/lib.rs
Normal file
2
examples/halo2/src/lib.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod circuit;
|
||||
pub mod primitives;
|
||||
1
examples/halo2/src/primitives.rs
Normal file
1
examples/halo2/src/primitives.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod poseidon;
|
||||
363
examples/halo2/src/primitives/poseidon.rs
Normal file
363
examples/halo2/src/primitives/poseidon.rs
Normal file
@@ -0,0 +1,363 @@
|
||||
use std::array;
|
||||
use std::fmt;
|
||||
use std::iter;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use halo2::arithmetic::FieldExt;
|
||||
|
||||
pub(crate) mod grain;
|
||||
pub(crate) mod mds;
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod test_vectors;
|
||||
|
||||
mod nullifier;
|
||||
pub use nullifier::OrchardNullifier;
|
||||
|
||||
use grain::SboxType;
|
||||
|
||||
/// The type used to hold permutation state.
|
||||
pub type State<F, const T: usize> = [F; T];
|
||||
|
||||
/// The type used to hold duplex sponge state.
|
||||
pub type SpongeState<F, const RATE: usize> = [Option<F>; RATE];
|
||||
|
||||
/// The type used to hold the MDS matrix and its inverse.
|
||||
pub type Mds<F, const T: usize> = [[F; T]; T];
|
||||
|
||||
/// A specification for a Poseidon permutation.
|
||||
pub trait Spec<F: FieldExt, const T: usize, const RATE: usize> {
|
||||
/// The number of full rounds for this specification.
|
||||
///
|
||||
/// This must be an even number.
|
||||
fn full_rounds() -> usize;
|
||||
|
||||
/// The number of partial rounds for this specification.
|
||||
fn partial_rounds() -> usize;
|
||||
|
||||
/// 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<[F; T]>, Mds<F, T>, Mds<F, T>) {
|
||||
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(|_| {
|
||||
let mut rc_row = [F::zero(); T];
|
||||
for (rc, value) in rc_row
|
||||
.iter_mut()
|
||||
.zip((0..T).map(|_| grain.next_field_element()))
|
||||
{
|
||||
*rc = value;
|
||||
}
|
||||
rc_row
|
||||
})
|
||||
.collect();
|
||||
|
||||
let (mds, mds_inv) = mds::generate_mds::<F, T>(&mut grain, self.secure_mds());
|
||||
|
||||
(round_constants, mds, mds_inv)
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs the Poseidon permutation on the given state.
|
||||
pub(crate) fn permute<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize>(
|
||||
state: &mut State<F, T>,
|
||||
mds: &Mds<F, T>,
|
||||
round_constants: &[[F; T]],
|
||||
) {
|
||||
let r_f = S::full_rounds() / 2;
|
||||
let r_p = S::partial_rounds();
|
||||
|
||||
let apply_mds = |state: &mut State<F, T>| {
|
||||
let mut new_state = [F::zero(); T];
|
||||
// Matrix multiplication
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
for i in 0..T {
|
||||
for j in 0..T {
|
||||
new_state[i] += mds[i][j] * state[j];
|
||||
}
|
||||
}
|
||||
*state = new_state;
|
||||
};
|
||||
|
||||
let full_round = |state: &mut State<F, T>, rcs: &[F; T]| {
|
||||
for (word, rc) in state.iter_mut().zip(rcs.iter()) {
|
||||
*word = S::sbox(*word + rc);
|
||||
}
|
||||
apply_mds(state);
|
||||
};
|
||||
|
||||
let part_round = |state: &mut State<F, T>, rcs: &[F; T]| {
|
||||
for (word, rc) in state.iter_mut().zip(rcs.iter()) {
|
||||
*word += rc;
|
||||
}
|
||||
// In a partial round, the S-box is only applied to the first state word.
|
||||
state[0] = S::sbox(state[0]);
|
||||
apply_mds(state);
|
||||
};
|
||||
|
||||
iter::empty()
|
||||
.chain(iter::repeat(&full_round as &dyn Fn(&mut State<F, T>, &[F; T])).take(r_f))
|
||||
.chain(iter::repeat(&part_round as &dyn Fn(&mut State<F, T>, &[F; T])).take(r_p))
|
||||
.chain(iter::repeat(&full_round as &dyn Fn(&mut State<F, T>, &[F; T])).take(r_f))
|
||||
.zip(round_constants.iter())
|
||||
.fold(state, |state, (round, rcs)| {
|
||||
round(state, rcs);
|
||||
state
|
||||
});
|
||||
}
|
||||
|
||||
fn poseidon_duplex<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize>(
|
||||
state: &mut State<F, T>,
|
||||
input: &SpongeState<F, RATE>,
|
||||
pad_and_add: &dyn Fn(&mut State<F, T>, &SpongeState<F, RATE>),
|
||||
mds_matrix: &Mds<F, T>,
|
||||
round_constants: &[[F; T]],
|
||||
) -> SpongeState<F, RATE> {
|
||||
pad_and_add(state, input);
|
||||
|
||||
permute::<F, S, T, RATE>(state, mds_matrix, round_constants);
|
||||
|
||||
let mut output = [None; RATE];
|
||||
for (word, value) in output.iter_mut().zip(state.iter()) {
|
||||
*word = Some(*value);
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
pub(crate) enum Sponge<F, const RATE: usize> {
|
||||
Absorbing(SpongeState<F, RATE>),
|
||||
Squeezing(SpongeState<F, RATE>),
|
||||
}
|
||||
|
||||
impl<F: Copy, const RATE: usize> Sponge<F, RATE> {
|
||||
pub(crate) fn absorb(val: F) -> Self {
|
||||
let mut input = [None; RATE];
|
||||
input[0] = Some(val);
|
||||
Sponge::Absorbing(input)
|
||||
}
|
||||
}
|
||||
|
||||
/// A Poseidon duplex sponge.
|
||||
pub struct Duplex<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize> {
|
||||
sponge: Sponge<F, RATE>,
|
||||
state: State<F, T>,
|
||||
pad_and_add: Box<dyn Fn(&mut State<F, T>, &SpongeState<F, RATE>)>,
|
||||
mds_matrix: Mds<F, T>,
|
||||
round_constants: Vec<[F; T]>,
|
||||
_marker: PhantomData<S>,
|
||||
}
|
||||
|
||||
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 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 input = [None; RATE];
|
||||
let mut state = [F::zero(); T];
|
||||
state[RATE] = initial_capacity_element;
|
||||
|
||||
Duplex {
|
||||
sponge: Sponge::Absorbing(input),
|
||||
state,
|
||||
pad_and_add,
|
||||
mds_matrix,
|
||||
round_constants,
|
||||
_marker: PhantomData::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Absorbs an element into the sponge.
|
||||
pub fn absorb(&mut self, value: F) {
|
||||
match self.sponge {
|
||||
Sponge::Absorbing(ref mut input) => {
|
||||
for entry in input.iter_mut() {
|
||||
if entry.is_none() {
|
||||
*entry = Some(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We've already absorbed as many elements as we can
|
||||
let _ = poseidon_duplex::<F, S, T, RATE>(
|
||||
&mut self.state,
|
||||
input,
|
||||
&self.pad_and_add,
|
||||
&self.mds_matrix,
|
||||
&self.round_constants,
|
||||
);
|
||||
self.sponge = Sponge::absorb(value);
|
||||
}
|
||||
Sponge::Squeezing(_) => {
|
||||
// Drop the remaining output elements
|
||||
self.sponge = Sponge::absorb(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Squeezes an element from the sponge.
|
||||
pub fn squeeze(&mut self) -> F {
|
||||
loop {
|
||||
match self.sponge {
|
||||
Sponge::Absorbing(ref input) => {
|
||||
self.sponge = Sponge::Squeezing(poseidon_duplex::<F, S, T, RATE>(
|
||||
&mut self.state,
|
||||
input,
|
||||
&self.pad_and_add,
|
||||
&self.mds_matrix,
|
||||
&self.round_constants,
|
||||
));
|
||||
}
|
||||
Sponge::Squeezing(ref mut output) => {
|
||||
for entry in output.iter_mut() {
|
||||
if let Some(e) = entry.take() {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
// We've already squeezed out all available elements
|
||||
self.sponge = Sponge::Absorbing([None; RATE]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A domain in which a Poseidon hash function is being used.
|
||||
pub trait Domain<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize>:
|
||||
Copy + fmt::Debug
|
||||
{
|
||||
/// The initial capacity element, encoding this domain.
|
||||
fn initial_capacity_element(&self) -> F;
|
||||
|
||||
fn padding(&self) -> SpongeState<F, RATE>;
|
||||
|
||||
/// Returns a function that will update the given state with the given input to a
|
||||
/// duplex permutation round, applying padding according to this domain specification.
|
||||
fn pad_and_add(&self) -> Box<dyn Fn(&mut State<F, T>, &SpongeState<F, RATE>)>;
|
||||
}
|
||||
|
||||
/// A Poseidon hash function used with constant input length.
|
||||
///
|
||||
/// Domain specified in section 4.2 of https://eprint.iacr.org/2019/458.pdf
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ConstantLength<const L: usize>;
|
||||
|
||||
impl<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize, const L: usize>
|
||||
Domain<F, S, T, RATE> for ConstantLength<L>
|
||||
{
|
||||
fn initial_capacity_element(&self) -> F {
|
||||
// Capacity value is $length \cdot 2^64 + (o-1)$ where o is the output length.
|
||||
// We hard-code an output length of 1.
|
||||
F::from_u128((L as u128) << 64)
|
||||
}
|
||||
|
||||
fn padding(&self) -> SpongeState<F, RATE> {
|
||||
// For constant-input-length hashing, padding consists of the field elements being
|
||||
// zero.
|
||||
let mut padding = [None; RATE];
|
||||
for word in padding.iter_mut().skip(L) {
|
||||
*word = Some(F::zero());
|
||||
}
|
||||
padding
|
||||
}
|
||||
|
||||
fn pad_and_add(&self) -> Box<dyn Fn(&mut State<F, T>, &SpongeState<F, RATE>)> {
|
||||
Box::new(|state, input| {
|
||||
// `Iterator::zip` short-circuits when one iterator completes, so this will only
|
||||
// mutate the rate portion of the state.
|
||||
for (word, value) in state.iter_mut().zip(input.iter()) {
|
||||
// For constant-input-length hashing, padding consists of the field
|
||||
// elements being zero, so we don't add anything to the state.
|
||||
if let Some(value) = value {
|
||||
*word += value;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A Poseidon hash function, built around a duplex sponge.
|
||||
pub struct Hash<
|
||||
F: FieldExt,
|
||||
S: Spec<F, T, RATE>,
|
||||
D: Domain<F, S, T, RATE>,
|
||||
const T: usize,
|
||||
const RATE: usize,
|
||||
> {
|
||||
duplex: Duplex<F, S, T, RATE>,
|
||||
domain: D,
|
||||
}
|
||||
|
||||
impl<
|
||||
F: FieldExt,
|
||||
S: Spec<F, T, RATE>,
|
||||
D: Domain<F, S, T, RATE>,
|
||||
const T: usize,
|
||||
const RATE: usize,
|
||||
> Hash<F, S, D, T, RATE>
|
||||
{
|
||||
/// Initializes a new hasher.
|
||||
pub fn init(spec: S, domain: D) -> Self {
|
||||
Hash {
|
||||
duplex: Duplex::new(
|
||||
spec,
|
||||
domain.initial_capacity_element(),
|
||||
domain.pad_and_add(),
|
||||
),
|
||||
domain,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: FieldExt, S: Spec<F, T, RATE>, const T: usize, const RATE: usize, const L: usize>
|
||||
Hash<F, S, ConstantLength<L>, T, RATE>
|
||||
{
|
||||
/// Hashes the given input.
|
||||
pub fn hash(mut self, message: [F; L]) -> F {
|
||||
for value in array::IntoIter::new(message) {
|
||||
self.duplex.absorb(value);
|
||||
}
|
||||
self.duplex.squeeze()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use halo2::arithmetic::FieldExt;
|
||||
use pasta_curves::pallas;
|
||||
|
||||
use super::{permute, ConstantLength, Hash, OrchardNullifier, Spec};
|
||||
|
||||
#[test]
|
||||
fn orchard_spec_equivalence() {
|
||||
let message = [pallas::Base::from_u64(6), pallas::Base::from_u64(42)];
|
||||
|
||||
let (round_constants, mds, _) = OrchardNullifier.constants();
|
||||
|
||||
let hasher = Hash::init(OrchardNullifier, ConstantLength);
|
||||
let result = hasher.hash(message);
|
||||
|
||||
// The result should be equivalent to just directly applying the permutation and
|
||||
// taking the first state element as the output.
|
||||
let mut state = [message[0], message[1], pallas::Base::from_u128(2 << 64)];
|
||||
permute::<_, OrchardNullifier, 3, 2>(&mut state, &mds, &round_constants);
|
||||
assert_eq!(state[0], result);
|
||||
}
|
||||
}
|
||||
193
examples/halo2/src/primitives/poseidon/grain.rs
Normal file
193
examples/halo2/src/primitives/poseidon/grain.rs
Normal file
@@ -0,0 +1,193 @@
|
||||
//! The Grain LFSR in self-shrinking mode, as used by Poseidon.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use bitvec::prelude::*;
|
||||
use halo2::arithmetic::FieldExt;
|
||||
|
||||
const STATE: usize = 80;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(super) enum FieldType {
|
||||
/// GF(2^n)
|
||||
#[allow(dead_code)]
|
||||
Binary,
|
||||
/// GF(p)
|
||||
PrimeOrder,
|
||||
}
|
||||
|
||||
impl FieldType {
|
||||
fn tag(&self) -> u8 {
|
||||
match self {
|
||||
FieldType::Binary => 0,
|
||||
FieldType::PrimeOrder => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(super) enum SboxType {
|
||||
/// x^alpha
|
||||
Pow,
|
||||
/// x^(-1)
|
||||
#[allow(dead_code)]
|
||||
Inv,
|
||||
}
|
||||
|
||||
impl SboxType {
|
||||
fn tag(&self) -> u8 {
|
||||
match self {
|
||||
SboxType::Pow => 0,
|
||||
SboxType::Inv => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct Grain<F: FieldExt> {
|
||||
state: BitArr!(for 80, in Msb0, u8),
|
||||
next_bit: usize,
|
||||
_field: PhantomData<F>,
|
||||
}
|
||||
|
||||
impl<F: FieldExt> Grain<F> {
|
||||
pub(super) fn new(sbox: SboxType, t: u16, r_f: u16, r_p: u16) -> Self {
|
||||
// Initialize the LFSR state.
|
||||
let mut state = bitarr![Msb0, u8; 1; STATE];
|
||||
let mut set_bits = |offset: usize, len, value| {
|
||||
// Poseidon reference impl sets initial state bits in MSB order.
|
||||
for i in 0..len {
|
||||
*state.get_mut(offset + len - 1 - i).unwrap() = (value >> i) & 1 != 0;
|
||||
}
|
||||
};
|
||||
set_bits(0, 2, FieldType::PrimeOrder.tag() as u16);
|
||||
set_bits(2, 4, sbox.tag() as u16);
|
||||
set_bits(6, 12, F::NUM_BITS as u16);
|
||||
set_bits(18, 12, t);
|
||||
set_bits(30, 10, r_f);
|
||||
set_bits(40, 10, r_p);
|
||||
|
||||
let mut grain = Grain {
|
||||
state,
|
||||
next_bit: STATE,
|
||||
_field: PhantomData::default(),
|
||||
};
|
||||
|
||||
// Discard the first 160 bits.
|
||||
for _ in 0..20 {
|
||||
grain.load_next_8_bits();
|
||||
grain.next_bit = STATE;
|
||||
}
|
||||
|
||||
grain
|
||||
}
|
||||
|
||||
fn load_next_8_bits(&mut self) {
|
||||
let mut new_bits = 0u8;
|
||||
for i in 0..8 {
|
||||
new_bits |= ((self.state[i + 62]
|
||||
^ self.state[i + 51]
|
||||
^ self.state[i + 38]
|
||||
^ self.state[i + 23]
|
||||
^ self.state[i + 13]
|
||||
^ self.state[i]) as u8)
|
||||
<< i;
|
||||
}
|
||||
self.state.rotate_left(8);
|
||||
self.next_bit -= 8;
|
||||
for i in 0..8 {
|
||||
*self.state.get_mut(self.next_bit + i).unwrap() = (new_bits >> i) & 1 != 0;
|
||||
}
|
||||
}
|
||||
|
||||
fn get_next_bit(&mut self) -> bool {
|
||||
if self.next_bit == STATE {
|
||||
self.load_next_8_bits();
|
||||
}
|
||||
let ret = self.state[self.next_bit];
|
||||
self.next_bit += 1;
|
||||
ret
|
||||
}
|
||||
|
||||
/// Returns the next field element from this Grain instantiation.
|
||||
pub(super) fn next_field_element(&mut self) -> F {
|
||||
// Loop until we get an element in the field.
|
||||
loop {
|
||||
let mut bytes = F::Repr::default();
|
||||
|
||||
// Poseidon reference impl interprets the bits as a repr in MSB order, because
|
||||
// it's easy to do that in Python. Meanwhile, our field elements all use LSB
|
||||
// order. There's little motivation to diverge from the reference impl; these
|
||||
// are all constants, so we aren't introducing big-endianness into the rest of
|
||||
// the circuit (assuming unkeyed Poseidon, but we probably wouldn't want to
|
||||
// implement Grain inside a circuit, so we'd use a different round constant
|
||||
// derivation function there).
|
||||
let view = bytes.as_mut();
|
||||
for (i, bit) in self.take(F::NUM_BITS as usize).enumerate() {
|
||||
// If we diverged from the reference impl and interpreted the bits in LSB
|
||||
// order, we would remove this line.
|
||||
let i = F::NUM_BITS as usize - 1 - i;
|
||||
|
||||
view[i / 8] |= if bit { 1 << (i % 8) } else { 0 };
|
||||
}
|
||||
|
||||
if let Some(f) = F::from_repr(bytes) {
|
||||
break f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the next field element from this Grain instantiation, without using
|
||||
/// rejection sampling.
|
||||
pub(super) fn next_field_element_without_rejection(&mut self) -> F {
|
||||
let mut bytes = [0u8; 64];
|
||||
|
||||
// Poseidon reference impl interprets the bits as a repr in MSB order, because
|
||||
// it's easy to do that in Python. Additionally, it does not use rejection
|
||||
// sampling in cases where the constants don't specifically need to be uniformly
|
||||
// random for security. We do not provide APIs that take a field-element-sized
|
||||
// array and reduce it modulo the field order, because those are unsafe APIs to
|
||||
// offer generally (accidentally using them can lead to divergence in consensus
|
||||
// systems due to not rejecting canonical forms).
|
||||
//
|
||||
// Given that we don't want to diverge from the reference implementation, we hack
|
||||
// around this restriction by serializing the bits into a 64-byte array and then
|
||||
// calling F::from_bytes_wide. PLEASE DO NOT COPY THIS INTO YOUR OWN CODE!
|
||||
let view = bytes.as_mut();
|
||||
for (i, bit) in self.take(F::NUM_BITS as usize).enumerate() {
|
||||
// If we diverged from the reference impl and interpreted the bits in LSB
|
||||
// order, we would remove this line.
|
||||
let i = F::NUM_BITS as usize - 1 - i;
|
||||
|
||||
view[i / 8] |= if bit { 1 << (i % 8) } else { 0 };
|
||||
}
|
||||
|
||||
F::from_bytes_wide(&bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: FieldExt> Iterator for Grain<F> {
|
||||
type Item = bool;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
// Evaluate bits in pairs:
|
||||
// - If the first bit is a 1, output the second bit.
|
||||
// - If the first bit is a 0, discard the second bit.
|
||||
while !self.get_next_bit() {
|
||||
self.get_next_bit();
|
||||
}
|
||||
Some(self.get_next_bit())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pasta_curves::Fp;
|
||||
|
||||
use super::{Grain, SboxType};
|
||||
|
||||
#[test]
|
||||
fn grain() {
|
||||
let mut grain = Grain::<Fp>::new(SboxType::Pow, 3, 8, 56);
|
||||
let _f = grain.next_field_element();
|
||||
}
|
||||
}
|
||||
123
examples/halo2/src/primitives/poseidon/mds.rs
Normal file
123
examples/halo2/src/primitives/poseidon/mds.rs
Normal file
@@ -0,0 +1,123 @@
|
||||
use halo2::arithmetic::FieldExt;
|
||||
|
||||
use super::{grain::Grain, Mds};
|
||||
|
||||
pub(super) fn generate_mds<F: FieldExt, const T: usize>(
|
||||
grain: &mut Grain<F>,
|
||||
mut select: usize,
|
||||
) -> (Mds<F, T>, Mds<F, T>) {
|
||||
let (xs, ys, mds) = loop {
|
||||
// Generate two [F; T] arrays of unique field elements.
|
||||
let (xs, ys) = loop {
|
||||
let mut vals: Vec<_> = (0..2 * T)
|
||||
.map(|_| grain.next_field_element_without_rejection())
|
||||
.collect();
|
||||
|
||||
// Check that we have unique field elements.
|
||||
let mut unique = vals.clone();
|
||||
unique.sort_unstable();
|
||||
unique.dedup();
|
||||
if vals.len() == unique.len() {
|
||||
let rhs = vals.split_off(T);
|
||||
break (vals, rhs);
|
||||
}
|
||||
};
|
||||
|
||||
// We need to ensure that the MDS is secure. Instead of checking the MDS against
|
||||
// the relevant algorithms directly, we witness a fixed number of MDS matrices
|
||||
// that we need to sample from the given Grain state before obtaining a secure
|
||||
// matrix. This can be determined out-of-band via the reference implementation in
|
||||
// Sage.
|
||||
if select != 0 {
|
||||
select -= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Generate a Cauchy matrix, with elements a_ij in the form:
|
||||
// a_ij = 1/(x_i + y_j); x_i + y_j != 0
|
||||
//
|
||||
// It would be much easier to use the alternate definition:
|
||||
// a_ij = 1/(x_i - y_j); x_i - y_j != 0
|
||||
//
|
||||
// These are clearly equivalent on `y <- -y`, but it is easier to work with the
|
||||
// negative formulation, because ensuring that xs ∪ ys is unique implies that
|
||||
// x_i - y_j != 0 by construction (whereas the positive case does not hold). It
|
||||
// also makes computation of the matrix inverse simpler below (the theorem used
|
||||
// was formulated for the negative definition).
|
||||
//
|
||||
// However, the Poseidon paper and reference impl use the positive formulation,
|
||||
// and we want to rely on the reference impl for MDS security, so we use the same
|
||||
// formulation.
|
||||
let mut mds = [[F::zero(); T]; T];
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
for i in 0..T {
|
||||
for j in 0..T {
|
||||
let sum = xs[i] + ys[j];
|
||||
// We leverage the secure MDS selection counter to also check this.
|
||||
assert!(!sum.is_zero());
|
||||
mds[i][j] = sum.invert().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
break (xs, ys, mds);
|
||||
};
|
||||
|
||||
// Compute the inverse. All square Cauchy matrices have a non-zero determinant and
|
||||
// thus are invertible. The inverse for a Cauchy matrix of the form:
|
||||
//
|
||||
// a_ij = 1/(x_i - y_j); x_i - y_j != 0
|
||||
//
|
||||
// has elements b_ij given by:
|
||||
//
|
||||
// b_ij = (x_j - y_i) A_j(y_i) B_i(x_j) (Schechter 1959, Theorem 1)
|
||||
//
|
||||
// where A_i(x) and B_i(x) are the Lagrange polynomials for xs and ys respectively.
|
||||
//
|
||||
// We adapt this to the positive Cauchy formulation by negating ys.
|
||||
let mut mds_inv = [[F::zero(); T]; T];
|
||||
let l = |xs: &[F], j, x: F| {
|
||||
let x_j = xs[j];
|
||||
xs.iter().enumerate().fold(F::one(), |acc, (m, x_m)| {
|
||||
if m == j {
|
||||
acc
|
||||
} else {
|
||||
// We can invert freely; by construction, the elements of xs are distinct.
|
||||
acc * (x - x_m) * (x_j - x_m).invert().unwrap()
|
||||
}
|
||||
})
|
||||
};
|
||||
let neg_ys: Vec<_> = ys.iter().map(|y| -*y).collect();
|
||||
for i in 0..T {
|
||||
for j in 0..T {
|
||||
mds_inv[i][j] = (xs[j] - neg_ys[i]) * l(&xs, j, neg_ys[i]) * l(&neg_ys, i, xs[j]);
|
||||
}
|
||||
}
|
||||
|
||||
(mds, mds_inv)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pasta_curves::Fp;
|
||||
|
||||
use super::{generate_mds, Grain};
|
||||
|
||||
#[test]
|
||||
fn poseidon_mds() {
|
||||
const T: usize = 3;
|
||||
let mut grain = Grain::new(super::super::grain::SboxType::Pow, T as u16, 8, 56);
|
||||
let (mds, mds_inv) = generate_mds::<Fp, T>(&mut grain, 0);
|
||||
|
||||
// Verify that MDS * MDS^-1 = I.
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
for i in 0..T {
|
||||
for j in 0..T {
|
||||
let expected = if i == j { Fp::one() } else { Fp::zero() };
|
||||
assert_eq!(
|
||||
(0..T).fold(Fp::zero(), |acc, k| acc + (mds[i][k] * mds_inv[k][j])),
|
||||
expected
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1619
examples/halo2/src/primitives/poseidon/nullifier.rs
Normal file
1619
examples/halo2/src/primitives/poseidon/nullifier.rs
Normal file
File diff suppressed because it is too large
Load Diff
632
examples/halo2/src/primitives/poseidon/test_vectors.rs
Normal file
632
examples/halo2/src/primitives/poseidon/test_vectors.rs
Normal file
@@ -0,0 +1,632 @@
|
||||
//! Test vectors for [`OrchardNullifier`].
|
||||
|
||||
pub(crate) struct PermuteTestVector {
|
||||
pub(crate) initial_state: [[u8; 32]; 3],
|
||||
pub(crate) final_state: [[u8; 32]; 3],
|
||||
}
|
||||
|
||||
pub(crate) struct HashTestVector {
|
||||
pub(crate) input: [[u8; 32]; 2],
|
||||
pub(crate) output: [u8; 32],
|
||||
}
|
||||
|
||||
pub(crate) fn permute() -> Vec<PermuteTestVector> {
|
||||
use PermuteTestVector as TestVector;
|
||||
|
||||
// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/orchard_poseidon.py
|
||||
vec![
|
||||
TestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
],
|
||||
[
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
],
|
||||
[
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x56, 0xa4, 0xec, 0x4a, 0x02, 0xbc, 0xb1, 0xae, 0xa0, 0x42, 0xb6, 0xd0, 0x71,
|
||||
0x9a, 0xe6, 0xf7, 0x0f, 0x24, 0x66, 0xf9, 0x64, 0xb3, 0xef, 0x94, 0x53, 0xb4,
|
||||
0x64, 0x0b, 0xcd, 0x6a, 0x52, 0x2a,
|
||||
],
|
||||
[
|
||||
0x2a, 0xb8, 0xe5, 0x28, 0x96, 0x3e, 0x2a, 0x01, 0xfe, 0xda, 0xd9, 0xbe, 0x7f,
|
||||
0x2e, 0xd4, 0xdc, 0x12, 0x55, 0x3d, 0x34, 0xae, 0x7d, 0xff, 0x76, 0x30, 0xa4,
|
||||
0x4a, 0x8b, 0x56, 0xd1, 0xc5, 0x13,
|
||||
],
|
||||
[
|
||||
0xdd, 0x9d, 0x4e, 0xd3, 0xa1, 0x29, 0x90, 0x35, 0x7b, 0x2c, 0xa4, 0xbd, 0xe1,
|
||||
0xdf, 0xcf, 0xf7, 0x1a, 0x56, 0x84, 0x79, 0x59, 0xcd, 0x6f, 0x25, 0x44, 0x65,
|
||||
0x97, 0xc6, 0x68, 0xc8, 0x49, 0x0a,
|
||||
],
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0x5c, 0x7a, 0x8f, 0x73, 0xad, 0xfc, 0x70, 0xfb, 0x3f, 0x13, 0x94, 0x49, 0xac,
|
||||
0x6b, 0x57, 0x07, 0x4c, 0x4d, 0x6e, 0x66, 0xb1, 0x64, 0x93, 0x9d, 0xaf, 0xfa,
|
||||
0x2e, 0xf6, 0xee, 0x69, 0x21, 0x08,
|
||||
],
|
||||
[
|
||||
0x1a, 0xdd, 0x86, 0xb3, 0xf2, 0xe1, 0xbd, 0xa6, 0x2a, 0x5d, 0x2e, 0x0e, 0x98,
|
||||
0x2b, 0x77, 0xe6, 0xb0, 0xef, 0x9c, 0xa3, 0xf2, 0x49, 0x88, 0xc7, 0xb3, 0x53,
|
||||
0x42, 0x01, 0xcf, 0xb1, 0xcd, 0x0d,
|
||||
],
|
||||
[
|
||||
0xbd, 0x69, 0xb8, 0x25, 0x32, 0xb6, 0x94, 0x0f, 0xf2, 0x59, 0x0f, 0x67, 0x9b,
|
||||
0xa9, 0xc7, 0x27, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, 0xa5, 0xe2,
|
||||
0x9d, 0x4e, 0x30, 0xa7, 0x35, 0x14,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0xd0, 0x6e, 0x2f, 0x83, 0x38, 0x92, 0x8a, 0x7e, 0xe7, 0x38, 0x0c, 0x77, 0x92,
|
||||
0x80, 0x87, 0xcd, 0xa2, 0xfd, 0x29, 0x61, 0xa1, 0x52, 0x69, 0x03, 0x7a, 0x22,
|
||||
0xd6, 0xd1, 0x20, 0xae, 0xdd, 0x21,
|
||||
],
|
||||
[
|
||||
0x29, 0x55, 0xa4, 0x5f, 0x41, 0x6f, 0x10, 0xd6, 0xbc, 0x79, 0xac, 0x94, 0xd0,
|
||||
0xc0, 0x69, 0xc9, 0x49, 0xe5, 0xf4, 0xbd, 0x09, 0x48, 0x1e, 0x1f, 0x36, 0x8c,
|
||||
0xb9, 0xb8, 0xee, 0x51, 0x14, 0x0d,
|
||||
],
|
||||
[
|
||||
0x0d, 0x83, 0x76, 0xbb, 0xe9, 0xd6, 0x5d, 0x2b, 0x1e, 0x13, 0x6f, 0xb7, 0xd9,
|
||||
0x82, 0xab, 0x87, 0xc5, 0x1c, 0x40, 0x30, 0x44, 0xbe, 0x5c, 0x79, 0x9d, 0x56,
|
||||
0xbb, 0x68, 0xac, 0xf9, 0x5b, 0x10,
|
||||
],
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0xbc, 0x50, 0x98, 0x42, 0x55, 0xd6, 0xaf, 0xbe, 0x9e, 0xf9, 0x28, 0x48, 0xed,
|
||||
0x5a, 0xc0, 0x08, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, 0xbc, 0xb6, 0x4b, 0x69,
|
||||
0x68, 0x91, 0x2a, 0x63, 0x81, 0x0e,
|
||||
],
|
||||
[
|
||||
0x3d, 0xc1, 0x66, 0xd5, 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x55, 0x1d, 0xb5,
|
||||
0xfd, 0x93, 0x13, 0xe8, 0xc7, 0x20, 0x3d, 0x99, 0x6a, 0xf7, 0xd4, 0x77, 0x08,
|
||||
0x37, 0x56, 0xd5, 0x9a, 0xf8, 0x0d,
|
||||
],
|
||||
[
|
||||
0x05, 0xa7, 0x45, 0xf4, 0x5d, 0x7f, 0xf6, 0xdb, 0x10, 0xbc, 0x67, 0xfd, 0xf0,
|
||||
0xf0, 0x3e, 0xbf, 0x81, 0x30, 0xab, 0x33, 0x36, 0x26, 0x97, 0xb0, 0xe4, 0xe4,
|
||||
0xc7, 0x63, 0xcc, 0xb8, 0xf6, 0x36,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x0b, 0x77, 0xec, 0x53, 0x07, 0x14, 0x5a, 0x0c, 0x05, 0x2d, 0xc7, 0xa9, 0xd6,
|
||||
0xf9, 0x6a, 0xc3, 0x41, 0xae, 0x72, 0x64, 0x08, 0x32, 0xd5, 0x8e, 0x51, 0xeb,
|
||||
0x92, 0xa4, 0x17, 0x80, 0x17, 0x12,
|
||||
],
|
||||
[
|
||||
0x3b, 0x52, 0x3f, 0x44, 0xf0, 0x0e, 0x46, 0x3f, 0x8b, 0x0f, 0xd7, 0xd4, 0xfc,
|
||||
0x0e, 0x28, 0x0c, 0xdb, 0xde, 0xb9, 0x27, 0xf1, 0x81, 0x68, 0x07, 0x7b, 0xb3,
|
||||
0x62, 0xf2, 0x67, 0x5a, 0x2e, 0x18,
|
||||
],
|
||||
[
|
||||
0x95, 0x7a, 0x97, 0x06, 0xff, 0xcc, 0x35, 0x15, 0x64, 0xae, 0x80, 0x2a, 0x99,
|
||||
0x11, 0x31, 0x4c, 0x05, 0xe2, 0x3e, 0x22, 0xaf, 0xcf, 0x83, 0x40, 0x59, 0xdf,
|
||||
0x80, 0xfa, 0xc1, 0x05, 0x76, 0x26,
|
||||
],
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, 0xfa, 0x3d, 0x5a, 0x57,
|
||||
0xef, 0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, 0xfb, 0x1a, 0x38,
|
||||
0xe0, 0x1d, 0x94, 0x90, 0x3d, 0x3c,
|
||||
],
|
||||
[
|
||||
0x3d, 0x0a, 0xd3, 0x36, 0x1f, 0xec, 0x09, 0x77, 0x90, 0xd9, 0xbe, 0x0e, 0x42,
|
||||
0x98, 0x8d, 0x7d, 0x25, 0xc9, 0xa1, 0x38, 0xf4, 0x9b, 0x1a, 0x53, 0x7e, 0xdc,
|
||||
0xf0, 0x4b, 0xe3, 0x4a, 0x98, 0x11,
|
||||
],
|
||||
[
|
||||
0xa4, 0xaf, 0x9d, 0xb6, 0xd2, 0x7b, 0x50, 0x72, 0x83, 0x5f, 0x0c, 0x3e, 0x88,
|
||||
0x39, 0x5e, 0xd7, 0xa4, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, 0xb9, 0xda,
|
||||
0x94, 0x8d, 0x32, 0x0d, 0xad, 0x16,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x67, 0x80, 0x08, 0x3f, 0x7f, 0x82, 0xcb, 0x42, 0x54, 0xe7, 0xb6, 0x6f, 0x4b,
|
||||
0x83, 0x84, 0x6a, 0xc9, 0x77, 0x3f, 0xb9, 0xc3, 0x9c, 0x6e, 0xc9, 0x81, 0x8b,
|
||||
0x06, 0x22, 0x23, 0x09, 0x55, 0x2a,
|
||||
],
|
||||
[
|
||||
0xa5, 0xf9, 0xa5, 0x7e, 0x2c, 0x40, 0xb1, 0x58, 0xd8, 0x16, 0x53, 0x43, 0xe6,
|
||||
0x02, 0x65, 0x2c, 0x3e, 0xfc, 0x0b, 0x64, 0xdd, 0xca, 0xee, 0xe5, 0xce, 0x3d,
|
||||
0x95, 0x1f, 0xd5, 0x9f, 0x50, 0x08,
|
||||
],
|
||||
[
|
||||
0xdc, 0xa4, 0x64, 0x36, 0x12, 0x7c, 0x47, 0x7e, 0x83, 0x95, 0x0f, 0xa0, 0x7c,
|
||||
0xc6, 0x8a, 0x56, 0x6e, 0x54, 0x18, 0x55, 0xad, 0xc2, 0x68, 0x52, 0x97, 0x87,
|
||||
0x35, 0x24, 0x88, 0x92, 0x1e, 0x3b,
|
||||
],
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0x4d, 0x54, 0x31, 0xe6, 0x43, 0x7d, 0x0b, 0x5b, 0xed, 0xbb, 0xcd, 0xaf, 0x34,
|
||||
0x5b, 0x86, 0xc4, 0x12, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, 0x42, 0x76,
|
||||
0xd3, 0x8d, 0x47, 0xf1, 0xe1, 0x11,
|
||||
],
|
||||
[
|
||||
0xdd, 0x0c, 0x7a, 0x1d, 0x81, 0x1c, 0x7d, 0x9c, 0xd4, 0x6d, 0x37, 0x7b, 0x3f,
|
||||
0xde, 0xab, 0x3f, 0xb6, 0x79, 0xf3, 0xdc, 0x60, 0x1d, 0x00, 0x82, 0x85, 0xed,
|
||||
0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0x3c,
|
||||
],
|
||||
[
|
||||
0x19, 0xe4, 0xaa, 0xc0, 0x35, 0x90, 0x17, 0xec, 0x85, 0xa1, 0x83, 0xd2, 0x20,
|
||||
0x53, 0xdb, 0x33, 0xf7, 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, 0x37, 0x83,
|
||||
0x65, 0xc8, 0xf7, 0x39, 0x3c, 0x14,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x89, 0x99, 0x8e, 0x5e, 0x0f, 0xa1, 0x95, 0x2a, 0x40, 0xb8, 0xb5, 0x2b, 0x62,
|
||||
0xd9, 0x45, 0x70, 0xa4, 0x9a, 0x7d, 0x91, 0xdd, 0x22, 0x6d, 0x69, 0x2b, 0xc9,
|
||||
0xb1, 0xa6, 0x13, 0xc9, 0x08, 0x30,
|
||||
],
|
||||
[
|
||||
0xd0, 0xee, 0x44, 0xd9, 0xa9, 0x0d, 0x90, 0x79, 0xef, 0xfb, 0x24, 0x86, 0xd3,
|
||||
0xd8, 0x4d, 0x1a, 0x18, 0x4e, 0xdf, 0x14, 0x97, 0x0b, 0xac, 0x36, 0xc7, 0x48,
|
||||
0x04, 0xc7, 0xff, 0xbe, 0xe5, 0x0b,
|
||||
],
|
||||
[
|
||||
0x04, 0x81, 0x45, 0xa6, 0x61, 0xce, 0x78, 0x7c, 0x7e, 0x12, 0x2a, 0xc6, 0x44,
|
||||
0x7e, 0x9b, 0xa3, 0x93, 0xd3, 0x67, 0xac, 0x05, 0x4f, 0xaa, 0xc5, 0xb7, 0xb5,
|
||||
0xf7, 0x19, 0x2b, 0x2f, 0xde, 0x21,
|
||||
],
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, 0x79,
|
||||
0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, 0x32, 0xb4,
|
||||
0xf4, 0x73, 0xf4, 0x68, 0xa0, 0x08,
|
||||
],
|
||||
[
|
||||
0xe6, 0x23, 0x89, 0xfc, 0x16, 0x57, 0xe0, 0xde, 0xf0, 0xb6, 0x32, 0xc6, 0xae,
|
||||
0x25, 0xf9, 0xf7, 0x83, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, 0x15, 0x3d, 0x88, 0x2d,
|
||||
0x2b, 0x21, 0x03, 0x59, 0x65, 0x15,
|
||||
],
|
||||
[
|
||||
0xeb, 0x94, 0x94, 0xc6, 0xd2, 0x27, 0xe2, 0x16, 0x3b, 0x46, 0x99, 0xd9, 0x91,
|
||||
0xf4, 0x33, 0xbf, 0x94, 0x86, 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, 0x73, 0x1e,
|
||||
0x98, 0x5d, 0x99, 0x58, 0x9c, 0x0b,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0xce, 0x2d, 0x1f, 0x8d, 0x67, 0x7f, 0xfb, 0xfd, 0x73, 0xb2, 0x35, 0xe8, 0xc6,
|
||||
0x87, 0xfb, 0x42, 0x18, 0x7f, 0x78, 0x81, 0xc3, 0xce, 0x9c, 0x79, 0x4f, 0x2b,
|
||||
0xd4, 0x61, 0x40, 0xf7, 0xcc, 0x2a,
|
||||
],
|
||||
[
|
||||
0xaf, 0x82, 0x92, 0x39, 0xb6, 0xd5, 0x5d, 0x5f, 0x43, 0xec, 0x6f, 0x32, 0xb8,
|
||||
0x4a, 0x2a, 0x01, 0x1e, 0x64, 0xc5, 0x74, 0x73, 0x9f, 0x87, 0xcb, 0x47, 0xdc,
|
||||
0x70, 0x23, 0x83, 0xfa, 0x5a, 0x34,
|
||||
],
|
||||
[
|
||||
0x03, 0xd1, 0x08, 0x5b, 0x21, 0x4c, 0x69, 0xb8, 0xbf, 0xe8, 0x91, 0x02, 0xbd,
|
||||
0x61, 0x7e, 0xce, 0x0c, 0x54, 0x00, 0x17, 0x96, 0x40, 0x41, 0x05, 0xc5, 0x33,
|
||||
0x30, 0xd2, 0x49, 0x58, 0x1d, 0x0f,
|
||||
],
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0xb7, 0x38, 0xe8, 0xaa, 0x0a, 0x15, 0x26, 0xa5, 0xbd, 0xef, 0x61, 0x31, 0x20,
|
||||
0x37, 0x2e, 0x83, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, 0xeb, 0xbc,
|
||||
0x86, 0x2d, 0xed, 0x42, 0x43, 0x1e,
|
||||
],
|
||||
[
|
||||
0x91, 0x47, 0x69, 0x30, 0xe3, 0x38, 0x5c, 0xd3, 0xe3, 0x37, 0x9e, 0x38, 0x53,
|
||||
0xd9, 0x34, 0x67, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, 0x6d, 0x75,
|
||||
0xa4, 0xa6, 0xf2, 0x65, 0x72, 0x10,
|
||||
],
|
||||
[
|
||||
0x4b, 0x19, 0x22, 0x32, 0xec, 0xb9, 0xf0, 0xc0, 0x24, 0x11, 0xe5, 0x25, 0x96,
|
||||
0xbc, 0x5e, 0x90, 0x45, 0x7e, 0x74, 0x59, 0x39, 0xff, 0xed, 0xbd, 0x12, 0x86,
|
||||
0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x5f, 0xcc, 0xd8, 0x7d, 0x2f, 0x66, 0x7b, 0x9e, 0xe3, 0x88, 0xf3, 0x4c, 0x1c,
|
||||
0x71, 0x06, 0x87, 0x12, 0x7b, 0xff, 0x5b, 0x02, 0x21, 0xfd, 0x8a, 0x52, 0x94,
|
||||
0x88, 0x66, 0x91, 0x57, 0x94, 0x2b,
|
||||
],
|
||||
[
|
||||
0x89, 0x62, 0xb5, 0x80, 0x30, 0xaa, 0x63, 0x52, 0xd9, 0x90, 0xf3, 0xb9, 0x00,
|
||||
0x1c, 0xcb, 0xe8, 0x8a, 0x56, 0x27, 0x58, 0x1b, 0xbf, 0xb9, 0x01, 0xac, 0x4a,
|
||||
0x6a, 0xed, 0xfa, 0xe5, 0xc6, 0x34,
|
||||
],
|
||||
[
|
||||
0x7c, 0x0b, 0x76, 0x59, 0xf2, 0x4c, 0x98, 0xaf, 0x31, 0x0e, 0x3e, 0x8d, 0x82,
|
||||
0xb5, 0xf3, 0x99, 0x43, 0x3c, 0xdd, 0xa5, 0x8f, 0x48, 0xd9, 0xef, 0x8d, 0xd0,
|
||||
0xca, 0x86, 0x42, 0x72, 0xda, 0x3f,
|
||||
],
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0x7b, 0x41, 0x7a, 0xdb, 0x63, 0xb3, 0x71, 0x22, 0xa5, 0xbf, 0x62, 0xd2, 0x6f,
|
||||
0x1e, 0x7f, 0x26, 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, 0x82, 0x85,
|
||||
0x7d, 0xee, 0xcc, 0x40, 0xa9, 0x0d,
|
||||
],
|
||||
[
|
||||
0x5e, 0x29, 0x35, 0x39, 0x71, 0xb3, 0x49, 0x94, 0xb6, 0x21, 0xb0, 0xb2, 0x61,
|
||||
0xae, 0xb3, 0x78, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, 0xb9, 0x27,
|
||||
0xb7, 0xfa, 0xe2, 0xdb, 0x58, 0x31,
|
||||
],
|
||||
[
|
||||
0x05, 0x41, 0x5d, 0x46, 0x42, 0x78, 0x9d, 0x38, 0xf5, 0x0b, 0x8d, 0xbc, 0xc1,
|
||||
0x29, 0xca, 0xb3, 0xd1, 0x7d, 0x19, 0xf3, 0x35, 0x5b, 0xcf, 0x73, 0xce, 0xcb,
|
||||
0x8c, 0xb8, 0xa5, 0xda, 0x01, 0x30,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x9e, 0xe1, 0xad, 0xdc, 0x6f, 0x64, 0xda, 0xb6, 0xac, 0xdc, 0xea, 0xec, 0xc1,
|
||||
0xfb, 0xbc, 0x8a, 0x32, 0x45, 0x8e, 0x49, 0xc1, 0x9e, 0x79, 0x85, 0x56, 0xc6,
|
||||
0x4b, 0x59, 0x8b, 0xa6, 0xff, 0x14,
|
||||
],
|
||||
[
|
||||
0x42, 0xcc, 0x10, 0x36, 0x4f, 0xd6, 0x59, 0xc3, 0xcc, 0x77, 0x25, 0x84, 0xdb,
|
||||
0x91, 0xc4, 0x9a, 0x38, 0x67, 0x2b, 0x69, 0x24, 0x93, 0xb9, 0x07, 0x5f, 0x16,
|
||||
0x53, 0xca, 0x1f, 0xae, 0x1c, 0x33,
|
||||
],
|
||||
[
|
||||
0xff, 0x41, 0xf3, 0x51, 0x80, 0x14, 0x56, 0xc4, 0x96, 0x0b, 0x39, 0x3a, 0xff,
|
||||
0xa8, 0x62, 0x13, 0xa7, 0xea, 0xc0, 0x6c, 0x66, 0x21, 0x3b, 0x45, 0xc3, 0xb5,
|
||||
0x0e, 0xc6, 0x48, 0xd6, 0x7d, 0x0d,
|
||||
],
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0x71, 0x52, 0xf1, 0x39, 0x36, 0xa2, 0x70, 0x57, 0x26, 0x70, 0xdc, 0x82, 0xd3,
|
||||
0x90, 0x26, 0xc6, 0xcb, 0x4c, 0xd4, 0xb0, 0xf7, 0xf5, 0xaa, 0x2a, 0x4f, 0x5a,
|
||||
0x53, 0x41, 0xec, 0x5d, 0xd7, 0x15,
|
||||
],
|
||||
[
|
||||
0x40, 0x6f, 0x2f, 0xdd, 0x2a, 0xfa, 0x73, 0x3f, 0x5f, 0x64, 0x1c, 0x8c, 0x21,
|
||||
0x86, 0x2a, 0x1b, 0xaf, 0xce, 0x26, 0x09, 0xd9, 0xee, 0xcf, 0xa1, 0x58, 0xcf,
|
||||
0xb5, 0xcd, 0x79, 0xf8, 0x80, 0x08,
|
||||
],
|
||||
[
|
||||
0xe2, 0x15, 0xdc, 0x7d, 0x96, 0x57, 0xba, 0xd3, 0xfb, 0x88, 0xb0, 0x1e, 0x99,
|
||||
0x38, 0x44, 0x54, 0x36, 0x24, 0xc2, 0x5f, 0xa9, 0x59, 0xcc, 0x97, 0x48, 0x9c,
|
||||
0xe7, 0x57, 0x45, 0x82, 0x4b, 0x37,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x63, 0x09, 0x15, 0xd7, 0xd8, 0x25, 0xeb, 0x74, 0x37, 0xb0, 0xe4, 0x6e, 0x37,
|
||||
0x28, 0x6a, 0x88, 0xb3, 0x89, 0xdc, 0x69, 0x85, 0x93, 0x07, 0x11, 0x6d, 0x34,
|
||||
0x7b, 0x98, 0xca, 0x14, 0x5c, 0x31,
|
||||
],
|
||||
[
|
||||
0xaa, 0x58, 0x1b, 0xae, 0xe9, 0x4f, 0xb5, 0x46, 0xa7, 0x61, 0xf1, 0x7a, 0x5d,
|
||||
0x6e, 0xaa, 0x70, 0x29, 0x52, 0x78, 0x42, 0xf3, 0x1c, 0x39, 0x87, 0xb8, 0x68,
|
||||
0xed, 0x7d, 0xaf, 0xfd, 0xb5, 0x34,
|
||||
],
|
||||
[
|
||||
0x7d, 0xc1, 0x17, 0xb3, 0x39, 0x1a, 0xab, 0x85, 0xde, 0x9f, 0x42, 0x4d, 0xb6,
|
||||
0x65, 0x1e, 0x00, 0x45, 0xab, 0x79, 0x98, 0xf2, 0x8e, 0x54, 0x10, 0x15, 0x35,
|
||||
0x90, 0x61, 0x99, 0xce, 0x1f, 0x1a,
|
||||
],
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0x86, 0x8c, 0x53, 0x23, 0x9c, 0xfb, 0xdf, 0x73, 0xca, 0xec, 0x65, 0x60, 0x40,
|
||||
0x37, 0x31, 0x4f, 0xaa, 0xce, 0xb5, 0x62, 0x18, 0xc6, 0xbd, 0x30, 0xf8, 0x37,
|
||||
0x4a, 0xc1, 0x33, 0x86, 0x79, 0x3f,
|
||||
],
|
||||
[
|
||||
0x21, 0xa9, 0xfb, 0x80, 0xad, 0x03, 0xbc, 0x0c, 0xda, 0x4a, 0x44, 0x94, 0x6c,
|
||||
0x00, 0xe1, 0xb1, 0xa1, 0xdf, 0x0e, 0x5b, 0x87, 0xb5, 0xbe, 0xce, 0x47, 0x7a,
|
||||
0x70, 0x96, 0x49, 0xe9, 0x50, 0x06,
|
||||
],
|
||||
[
|
||||
0x04, 0x91, 0x39, 0x48, 0x25, 0x64, 0xf1, 0x85, 0xc7, 0x90, 0x0e, 0x83, 0xc7,
|
||||
0x38, 0x07, 0x0a, 0xf6, 0x55, 0x6d, 0xf6, 0xed, 0x4b, 0x4d, 0xdd, 0x3d, 0x9a,
|
||||
0x69, 0xf5, 0x33, 0x57, 0xd7, 0x36,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x6a, 0x5a, 0x19, 0x19, 0xa4, 0x49, 0xa5, 0xe0, 0x29, 0x71, 0x1f, 0x48, 0x8a,
|
||||
0xdb, 0xd6, 0xb0, 0x3e, 0x5c, 0x92, 0x7b, 0x6f, 0x9d, 0x9d, 0x35, 0xc5, 0xb3,
|
||||
0xcc, 0xeb, 0x76, 0x60, 0x52, 0x03,
|
||||
],
|
||||
[
|
||||
0x80, 0x47, 0x5b, 0x46, 0x89, 0x59, 0x61, 0x47, 0xab, 0x2a, 0xdf, 0x01, 0x73,
|
||||
0xdb, 0x28, 0x9b, 0x3a, 0x26, 0xa1, 0x04, 0x84, 0x21, 0x73, 0xe8, 0x8b, 0xdb,
|
||||
0xfe, 0xc0, 0x4a, 0x28, 0x67, 0x1b,
|
||||
],
|
||||
[
|
||||
0x1e, 0xf3, 0xc8, 0xd0, 0xf5, 0x44, 0x44, 0xf5, 0x55, 0xb1, 0x5f, 0x7b, 0xc9,
|
||||
0xfa, 0x4f, 0xfa, 0x0f, 0x56, 0x7c, 0x0f, 0x19, 0xac, 0x7d, 0x0f, 0xf9, 0x44,
|
||||
0xfd, 0x36, 0x42, 0x6e, 0x32, 0x3a,
|
||||
],
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0x7d, 0x4f, 0x5c, 0xcb, 0x01, 0x64, 0x3c, 0x31, 0xdb, 0x84, 0x5e, 0xec, 0xd5,
|
||||
0xd6, 0x3d, 0xc1, 0x6a, 0x95, 0xe3, 0x02, 0x5b, 0x97, 0x92, 0xff, 0xf7, 0xf2,
|
||||
0x44, 0xfc, 0x71, 0x62, 0x69, 0x39,
|
||||
],
|
||||
[
|
||||
0x26, 0xd6, 0x2e, 0x95, 0x96, 0xfa, 0x82, 0x5c, 0x6b, 0xf2, 0x1a, 0xff, 0x9e,
|
||||
0x68, 0x62, 0x5a, 0x19, 0x24, 0x40, 0xea, 0x06, 0x82, 0x81, 0x23, 0xd9, 0x78,
|
||||
0x84, 0x80, 0x6f, 0x15, 0xfa, 0x08,
|
||||
],
|
||||
[
|
||||
0xd9, 0x52, 0x75, 0x4a, 0x23, 0x64, 0xb6, 0x66, 0xff, 0xc3, 0x0f, 0xdb, 0x01,
|
||||
0x47, 0x86, 0xda, 0x3a, 0x61, 0x28, 0xae, 0xf7, 0x84, 0xa6, 0x46, 0x10, 0xa8,
|
||||
0x9d, 0x1a, 0x70, 0x99, 0x21, 0x2d,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x1b, 0x4a, 0xc9, 0xbe, 0xf5, 0x6b, 0xdb, 0x6f, 0xb4, 0x2d, 0x3e, 0x3c, 0xd3,
|
||||
0xa2, 0xac, 0x70, 0xa4, 0xc4, 0x0c, 0x42, 0x5b, 0x0b, 0xd6, 0x67, 0x9c, 0xa5,
|
||||
0x7b, 0x30, 0x7e, 0xf1, 0xd4, 0x2f,
|
||||
],
|
||||
[
|
||||
0x1a, 0x2e, 0xf4, 0x11, 0x94, 0xaa, 0xa2, 0x34, 0x32, 0xe0, 0x86, 0xed, 0x8a,
|
||||
0xdb, 0xd1, 0xde, 0xec, 0x3c, 0x7c, 0xb3, 0x96, 0xde, 0x35, 0xba, 0xe9, 0x5a,
|
||||
0xaf, 0x5a, 0x08, 0xa0, 0xec, 0x36,
|
||||
],
|
||||
[
|
||||
0x68, 0xeb, 0x80, 0xc7, 0x3e, 0x2c, 0xcb, 0xde, 0xe1, 0xba, 0x71, 0x24, 0x77,
|
||||
0x61, 0xd5, 0xb5, 0xec, 0xc6, 0x20, 0xe6, 0xe4, 0x8e, 0x00, 0x3b, 0x02, 0x3d,
|
||||
0x9f, 0x55, 0x61, 0x66, 0x2f, 0x20,
|
||||
],
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
pub(crate) fn hash() -> Vec<HashTestVector> {
|
||||
use HashTestVector as TestVector;
|
||||
|
||||
// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/orchard_poseidon_hash.py
|
||||
vec![
|
||||
TestVector {
|
||||
input: [
|
||||
[
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
],
|
||||
[
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0x83, 0x58, 0xd7, 0x11, 0xa0, 0x32, 0x9d, 0x38, 0xbe, 0xcd, 0x54, 0xfb, 0xa7, 0xc2,
|
||||
0x83, 0xed, 0x3e, 0x08, 0x9a, 0x39, 0xc9, 0x1b, 0x6a, 0x9d, 0x10, 0xef, 0xb0, 0x2b,
|
||||
0xc3, 0xf1, 0x2f, 0x06,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
input: [
|
||||
[
|
||||
0x5c, 0x7a, 0x8f, 0x73, 0xad, 0xfc, 0x70, 0xfb, 0x3f, 0x13, 0x94, 0x49, 0xac,
|
||||
0x6b, 0x57, 0x07, 0x4c, 0x4d, 0x6e, 0x66, 0xb1, 0x64, 0x93, 0x9d, 0xaf, 0xfa,
|
||||
0x2e, 0xf6, 0xee, 0x69, 0x21, 0x08,
|
||||
],
|
||||
[
|
||||
0x1a, 0xdd, 0x86, 0xb3, 0xf2, 0xe1, 0xbd, 0xa6, 0x2a, 0x5d, 0x2e, 0x0e, 0x98,
|
||||
0x2b, 0x77, 0xe6, 0xb0, 0xef, 0x9c, 0xa3, 0xf2, 0x49, 0x88, 0xc7, 0xb3, 0x53,
|
||||
0x42, 0x01, 0xcf, 0xb1, 0xcd, 0x0d,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0xdb, 0x26, 0x75, 0xff, 0x3e, 0xf8, 0xfe, 0x30, 0xc4, 0xd5, 0xde, 0x61, 0xca, 0xc0,
|
||||
0x2a, 0x8e, 0xf1, 0xa0, 0x85, 0x23, 0xbe, 0x92, 0x39, 0x4b, 0x79, 0xd2, 0x67, 0x26,
|
||||
0x30, 0x3b, 0xe6, 0x03,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
input: [
|
||||
[
|
||||
0xbd, 0x69, 0xb8, 0x25, 0x32, 0xb6, 0x94, 0x0f, 0xf2, 0x59, 0x0f, 0x67, 0x9b,
|
||||
0xa9, 0xc7, 0x27, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, 0xa5, 0xe2,
|
||||
0x9d, 0x4e, 0x30, 0xa7, 0x35, 0x14,
|
||||
],
|
||||
[
|
||||
0xbc, 0x50, 0x98, 0x42, 0x55, 0xd6, 0xaf, 0xbe, 0x9e, 0xf9, 0x28, 0x48, 0xed,
|
||||
0x5a, 0xc0, 0x08, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, 0xbc, 0xb6, 0x4b, 0x69,
|
||||
0x68, 0x91, 0x2a, 0x63, 0x81, 0x0e,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0xf5, 0x12, 0x1d, 0x1e, 0x1d, 0x5c, 0xfe, 0x8d, 0xa8, 0x96, 0xac, 0x0f, 0x9c, 0x18,
|
||||
0x3d, 0x76, 0x00, 0x31, 0xf6, 0xef, 0x8c, 0x7a, 0x41, 0xe6, 0x5e, 0xb0, 0x07, 0xcd,
|
||||
0xdc, 0x1d, 0x14, 0x3d,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
input: [
|
||||
[
|
||||
0x3d, 0xc1, 0x66, 0xd5, 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x55, 0x1d, 0xb5,
|
||||
0xfd, 0x93, 0x13, 0xe8, 0xc7, 0x20, 0x3d, 0x99, 0x6a, 0xf7, 0xd4, 0x77, 0x08,
|
||||
0x37, 0x56, 0xd5, 0x9a, 0xf8, 0x0d,
|
||||
],
|
||||
[
|
||||
0x05, 0xa7, 0x45, 0xf4, 0x5d, 0x7f, 0xf6, 0xdb, 0x10, 0xbc, 0x67, 0xfd, 0xf0,
|
||||
0xf0, 0x3e, 0xbf, 0x81, 0x30, 0xab, 0x33, 0x36, 0x26, 0x97, 0xb0, 0xe4, 0xe4,
|
||||
0xc7, 0x63, 0xcc, 0xb8, 0xf6, 0x36,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0xa4, 0x16, 0xa5, 0xe7, 0x13, 0x51, 0x36, 0xa0, 0x50, 0x56, 0x90, 0x00, 0x58, 0xfa,
|
||||
0x50, 0xbf, 0x18, 0x6a, 0xd7, 0x33, 0x90, 0xac, 0xe6, 0x32, 0x3d, 0x8d, 0x81, 0xaa,
|
||||
0x8a, 0xdb, 0xd4, 0x11,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
input: [
|
||||
[
|
||||
0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, 0xfa, 0x3d, 0x5a, 0x57,
|
||||
0xef, 0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, 0xfb, 0x1a, 0x38,
|
||||
0xe0, 0x1d, 0x94, 0x90, 0x3d, 0x3c,
|
||||
],
|
||||
[
|
||||
0x3d, 0x0a, 0xd3, 0x36, 0x1f, 0xec, 0x09, 0x77, 0x90, 0xd9, 0xbe, 0x0e, 0x42,
|
||||
0x98, 0x8d, 0x7d, 0x25, 0xc9, 0xa1, 0x38, 0xf4, 0x9b, 0x1a, 0x53, 0x7e, 0xdc,
|
||||
0xf0, 0x4b, 0xe3, 0x4a, 0x98, 0x11,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0x1a, 0xba, 0xf3, 0x06, 0xfe, 0xd0, 0x5f, 0xa8, 0x92, 0x84, 0x8c, 0x49, 0xf6, 0xba,
|
||||
0x10, 0x41, 0x63, 0x43, 0x3f, 0x3f, 0x63, 0x31, 0x08, 0xa1, 0x3b, 0xc1, 0x5b, 0x2a,
|
||||
0x1d, 0x55, 0xd4, 0x0c,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
input: [
|
||||
[
|
||||
0xa4, 0xaf, 0x9d, 0xb6, 0xd2, 0x7b, 0x50, 0x72, 0x83, 0x5f, 0x0c, 0x3e, 0x88,
|
||||
0x39, 0x5e, 0xd7, 0xa4, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, 0xb9, 0xda,
|
||||
0x94, 0x8d, 0x32, 0x0d, 0xad, 0x16,
|
||||
],
|
||||
[
|
||||
0x4d, 0x54, 0x31, 0xe6, 0x43, 0x7d, 0x0b, 0x5b, 0xed, 0xbb, 0xcd, 0xaf, 0x34,
|
||||
0x5b, 0x86, 0xc4, 0x12, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, 0x42, 0x76,
|
||||
0xd3, 0x8d, 0x47, 0xf1, 0xe1, 0x11,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0x04, 0xa1, 0x8a, 0xeb, 0x59, 0x3f, 0x79, 0x0b, 0x76, 0xa3, 0x99, 0xb7, 0xc1, 0x52,
|
||||
0x8a, 0xcd, 0xed, 0xe9, 0x3b, 0x3b, 0x2c, 0x49, 0x6b, 0xd7, 0x1b, 0xd5, 0x87, 0xcb,
|
||||
0xd7, 0xcf, 0xdf, 0x35,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
input: [
|
||||
[
|
||||
0xdd, 0x0c, 0x7a, 0x1d, 0x81, 0x1c, 0x7d, 0x9c, 0xd4, 0x6d, 0x37, 0x7b, 0x3f,
|
||||
0xde, 0xab, 0x3f, 0xb6, 0x79, 0xf3, 0xdc, 0x60, 0x1d, 0x00, 0x82, 0x85, 0xed,
|
||||
0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0x3c,
|
||||
],
|
||||
[
|
||||
0x19, 0xe4, 0xaa, 0xc0, 0x35, 0x90, 0x17, 0xec, 0x85, 0xa1, 0x83, 0xd2, 0x20,
|
||||
0x53, 0xdb, 0x33, 0xf7, 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, 0x37, 0x83,
|
||||
0x65, 0xc8, 0xf7, 0x39, 0x3c, 0x14,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0x11, 0x03, 0xcc, 0xdc, 0x00, 0xd0, 0xf3, 0x5f, 0x65, 0x83, 0x14, 0x11, 0x6b, 0xc2,
|
||||
0xbc, 0xd9, 0x43, 0x74, 0xa9, 0x1f, 0xf9, 0x87, 0x7e, 0x70, 0x66, 0x33, 0x29, 0x04,
|
||||
0x2b, 0xd2, 0xf6, 0x1f,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
input: [
|
||||
[
|
||||
0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, 0x79,
|
||||
0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, 0x32, 0xb4,
|
||||
0xf4, 0x73, 0xf4, 0x68, 0xa0, 0x08,
|
||||
],
|
||||
[
|
||||
0xe6, 0x23, 0x89, 0xfc, 0x16, 0x57, 0xe0, 0xde, 0xf0, 0xb6, 0x32, 0xc6, 0xae,
|
||||
0x25, 0xf9, 0xf7, 0x83, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, 0x15, 0x3d, 0x88, 0x2d,
|
||||
0x2b, 0x21, 0x03, 0x59, 0x65, 0x15,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0xf8, 0xf8, 0xc6, 0x5f, 0x43, 0x7c, 0x45, 0xbe, 0xac, 0x11, 0xeb, 0x7d, 0x9e, 0x47,
|
||||
0x58, 0x6d, 0x87, 0x9a, 0xfd, 0x6f, 0x93, 0x04, 0x35, 0xbe, 0x0c, 0x01, 0xd1, 0x9c,
|
||||
0x89, 0x5b, 0x8d, 0x10,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
input: [
|
||||
[
|
||||
0xeb, 0x94, 0x94, 0xc6, 0xd2, 0x27, 0xe2, 0x16, 0x3b, 0x46, 0x99, 0xd9, 0x91,
|
||||
0xf4, 0x33, 0xbf, 0x94, 0x86, 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, 0x73, 0x1e,
|
||||
0x98, 0x5d, 0x99, 0x58, 0x9c, 0x0b,
|
||||
],
|
||||
[
|
||||
0xb7, 0x38, 0xe8, 0xaa, 0x0a, 0x15, 0x26, 0xa5, 0xbd, 0xef, 0x61, 0x31, 0x20,
|
||||
0x37, 0x2e, 0x83, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, 0xeb, 0xbc,
|
||||
0x86, 0x2d, 0xed, 0x42, 0x43, 0x1e,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0x5a, 0xeb, 0x48, 0x96, 0x21, 0xb0, 0x2e, 0x8e, 0x69, 0x27, 0xb9, 0x4f, 0xd2, 0x9a,
|
||||
0x61, 0x01, 0x83, 0xdf, 0x7f, 0x42, 0x87, 0xe9, 0xcb, 0xf1, 0xcc, 0xc8, 0x81, 0xd7,
|
||||
0xd0, 0xb7, 0x38, 0x27,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
input: [
|
||||
[
|
||||
0x91, 0x47, 0x69, 0x30, 0xe3, 0x38, 0x5c, 0xd3, 0xe3, 0x37, 0x9e, 0x38, 0x53,
|
||||
0xd9, 0x34, 0x67, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, 0x6d, 0x75,
|
||||
0xa4, 0xa6, 0xf2, 0x65, 0x72, 0x10,
|
||||
],
|
||||
[
|
||||
0x4b, 0x19, 0x22, 0x32, 0xec, 0xb9, 0xf0, 0xc0, 0x24, 0x11, 0xe5, 0x25, 0x96,
|
||||
0xbc, 0x5e, 0x90, 0x45, 0x7e, 0x74, 0x59, 0x39, 0xff, 0xed, 0xbd, 0x12, 0x86,
|
||||
0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0xb0, 0x14, 0x47, 0x20, 0xf5, 0xf2, 0xa2, 0x5d, 0x49, 0x2a, 0x50, 0x4e, 0xc0, 0x73,
|
||||
0x7f, 0x09, 0x7e, 0xd8, 0x52, 0x17, 0x4f, 0x55, 0xf5, 0x86, 0x30, 0x91, 0x30, 0x6c,
|
||||
0x1a, 0xf2, 0x00, 0x35,
|
||||
],
|
||||
},
|
||||
TestVector {
|
||||
input: [
|
||||
[
|
||||
0x7b, 0x41, 0x7a, 0xdb, 0x63, 0xb3, 0x71, 0x22, 0xa5, 0xbf, 0x62, 0xd2, 0x6f,
|
||||
0x1e, 0x7f, 0x26, 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, 0x82, 0x85,
|
||||
0x7d, 0xee, 0xcc, 0x40, 0xa9, 0x0d,
|
||||
],
|
||||
[
|
||||
0x5e, 0x29, 0x35, 0x39, 0x71, 0xb3, 0x49, 0x94, 0xb6, 0x21, 0xb0, 0xb2, 0x61,
|
||||
0xae, 0xb3, 0x78, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, 0xb9, 0x27,
|
||||
0xb7, 0xfa, 0xe2, 0xdb, 0x58, 0x31,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0xbb, 0xbe, 0xb7, 0x42, 0xd6, 0xe7, 0xc0, 0x1a, 0xdb, 0xf4, 0xd3, 0x85, 0x5e, 0x35,
|
||||
0xfe, 0xc4, 0x62, 0x04, 0x30, 0x89, 0xc1, 0x8b, 0xa8, 0x02, 0x90, 0x64, 0x7b, 0xb0,
|
||||
0xe5, 0x81, 0xad, 0x11,
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user