halo2: Add poseidon hash primitives

This commit is contained in:
parazyd
2021-08-12 17:19:48 +02:00
parent 5b7bd7cbcd
commit afc0759480
7 changed files with 2933 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
pub mod circuit;
pub mod primitives;

View File

@@ -0,0 +1 @@
pub mod poseidon;

View 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);
}
}

View 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();
}
}

View 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
);
}
}
}
}

File diff suppressed because it is too large Load Diff

View 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,
],
},
]
}