From 2587d3aa81846ce99a26258a7c628f0a2cafd001 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 2 Feb 2024 15:29:40 +0200 Subject: [PATCH] update to work with PSE halo2 0.3.0 - simpify protocol - rebase on dev - add mock backend - fix failing tests - use dedicated field element for salt --- authdecode/Cargo.toml | 35 + authdecode/authdecode_diagram.pdf | Bin 0 -> 30034 bytes authdecode/src/backend/halo2/circuit.rs | 731 ++ .../src/backend/halo2/circuit_diagram.pdf | Bin 0 -> 75083 bytes authdecode/src/backend/halo2/mod.rs | 27 + authdecode/src/backend/halo2/onetimesetup.rs | 57 + .../backend/halo2/poseidon/circuit_config.rs | 74 + authdecode/src/backend/halo2/poseidon/mod.rs | 34 + .../backend/halo2/poseidon/rate15_params.rs | 10229 ++++++++++++++++ .../backend/halo2/poseidon/rate1_params.rs | 988 ++ .../backend/halo2/poseidon/rate2_params.rs | 1436 +++ authdecode/src/backend/halo2/poseidon/spec.rs | 117 + authdecode/src/backend/halo2/prover.rs | 436 + authdecode/src/backend/halo2/utils.rs | 273 + authdecode/src/backend/halo2/verifier.rs | 129 + authdecode/src/backend/mock/circuit.rs | 50 + authdecode/src/backend/mock/mod.rs | 75 + authdecode/src/backend/mock/prover.rs | 79 + authdecode/src/backend/mock/verifier.rs | 47 + authdecode/src/backend/mod.rs | 2 + authdecode/src/encodings.rs | 305 + authdecode/src/lib.rs | 146 + authdecode/src/prover/backend.rs | 24 + authdecode/src/prover/error.rs | 37 + authdecode/src/prover/mod.rs | 44 + authdecode/src/prover/prover.rs | 295 + authdecode/src/prover/state.rs | 55 + authdecode/src/utils.rs | 136 + authdecode/src/verifier/backend.rs | 20 + authdecode/src/verifier/error.rs | 15 + authdecode/src/verifier/mod.rs | 5 + authdecode/src/verifier/state.rs | 44 + authdecode/src/verifier/verifier.rs | 179 + 33 files changed, 16124 insertions(+) create mode 100644 authdecode/Cargo.toml create mode 100644 authdecode/authdecode_diagram.pdf create mode 100644 authdecode/src/backend/halo2/circuit.rs create mode 100644 authdecode/src/backend/halo2/circuit_diagram.pdf create mode 100644 authdecode/src/backend/halo2/mod.rs create mode 100644 authdecode/src/backend/halo2/onetimesetup.rs create mode 100644 authdecode/src/backend/halo2/poseidon/circuit_config.rs create mode 100644 authdecode/src/backend/halo2/poseidon/mod.rs create mode 100644 authdecode/src/backend/halo2/poseidon/rate15_params.rs create mode 100644 authdecode/src/backend/halo2/poseidon/rate1_params.rs create mode 100644 authdecode/src/backend/halo2/poseidon/rate2_params.rs create mode 100644 authdecode/src/backend/halo2/poseidon/spec.rs create mode 100644 authdecode/src/backend/halo2/prover.rs create mode 100644 authdecode/src/backend/halo2/utils.rs create mode 100644 authdecode/src/backend/halo2/verifier.rs create mode 100644 authdecode/src/backend/mock/circuit.rs create mode 100644 authdecode/src/backend/mock/mod.rs create mode 100644 authdecode/src/backend/mock/prover.rs create mode 100644 authdecode/src/backend/mock/verifier.rs create mode 100644 authdecode/src/backend/mod.rs create mode 100644 authdecode/src/encodings.rs create mode 100644 authdecode/src/lib.rs create mode 100644 authdecode/src/prover/backend.rs create mode 100644 authdecode/src/prover/error.rs create mode 100644 authdecode/src/prover/mod.rs create mode 100644 authdecode/src/prover/prover.rs create mode 100644 authdecode/src/prover/state.rs create mode 100644 authdecode/src/utils.rs create mode 100644 authdecode/src/verifier/backend.rs create mode 100644 authdecode/src/verifier/error.rs create mode 100644 authdecode/src/verifier/mod.rs create mode 100644 authdecode/src/verifier/state.rs create mode 100644 authdecode/src/verifier/verifier.rs diff --git a/authdecode/Cargo.toml b/authdecode/Cargo.toml new file mode 100644 index 0000000000..fba94578ba --- /dev/null +++ b/authdecode/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "authdecode" +version = "0.1.0" +edition = "2021" + +[lib] +name = "authdecode" + +[dependencies] +thiserror = "1.0.56" +num = "0.4.1" +rand = "0.8.5" +rand_chacha = "0.3.1" +sha2 = { version = "0.10.8", features = ["compress"] } +opaque-debug = "0.3.0" +mpz-core = { git = "https://github.com/privacy-scaling-explorations/mpz", commit = "499b75d20397235f8399817a53c65fa2d399d3b8"} +blake3 = "1.3.3" +serde = "1" +bincode = "1" + +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2", tag = "v0.3.0", default-features = false} +halo2_poseidon = { git = "https://github.com/privacy-scaling-explorations/poseidon-gadget", rev="764a682"} + +group = "0.13" +ff = "0.13" + + +[dev-dependencies] +hex = "0.4.3" +num-bigint = { version = "0.4.4", features = ["rand"] } +criterion = "0.5.1" +rand_chacha = "0.3" +rand = "0.8" +rand_core = "0.6" +rstest = "0.12" diff --git a/authdecode/authdecode_diagram.pdf b/authdecode/authdecode_diagram.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6809b7ca7ed3fb82437dc0b79b61c8e6d5b20c39 GIT binary patch literal 30034 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 T4%jm$PIgYl&!nUxvZDVFCJwSZ literal 0 HcmV?d00001 diff --git a/authdecode/src/backend/halo2/circuit.rs b/authdecode/src/backend/halo2/circuit.rs new file mode 100644 index 0000000000..3a0c723b62 --- /dev/null +++ b/authdecode/src/backend/halo2/circuit.rs @@ -0,0 +1,731 @@ +use crate::backend::halo2::{poseidon::spec::Spec2, utils::biguint_to_f}; +use halo2_poseidon::poseidon::{primitives::ConstantLength, Hash, Pow5Chip, Pow5Config}; +use halo2_proofs::{ + circuit::{AssignedCell, Layouter, Region, SimpleFloorPlanner, Value}, + halo2curves::bn256::Fr as F, + plonk::{ + Advice, Circuit, Column, ConstraintSystem, Constraints, Error, Expression, Instance, + Selector, + }, + poly::Rotation, +}; + +use super::{ + poseidon::{ + circuit_config::{ + configure_poseidon_rate_1, configure_poseidon_rate_15, configure_poseidon_rate_2, + }, + spec::{Spec1, Spec15}, + }, + utils::{bigint_to_256bits, bits_to_limbs, f_to_bigint}, +}; + +use num::BigUint; +use std::convert::TryInto; + +// See circuit_diagram.pdf for a diagram of the circuit + +// The AuthDecode protocol decodes a chunk of X bits at a time. +// Each of the bit requires 1 corresponding public input - a delta. +// We want the deltas to use up as few instance columns as possible +// because more instance columns means more prover time. We also want +// K to stay as low as possible since low K also improves prover time. +// The best ratio is achieved with K==6 and 68 instance columns. + +// However, 68-bit limbs are awkward to work with. So we choose to have +// 64 columns and 4 rows, to place all the field element's bits into. + +// Our circuit's K is 6, which gives us 2^6-6=58 useful rows +// (halo2 reserves 6 rows for internal purposes). +// It requires 4 64-cell rows in order to hold all the bits of one field element. + +// The total amount of field elements we can decode is 58/4 = 14 1/2, +// which we round down to 14. + +// We could have much simpler logic if we just used 253 instance columns. +// But compared to 64 columns, that would increase the prover time 2x. + +/// The amount of field elements. Plaintext bits are packed +/// into these field elements. +pub const FIELD_ELEMENTS: usize = 14; + +/// The parameter informing halo2 about the upper bound of how many rows our +/// circuit uses. This is a power of 2. +pub const K: u32 = 6; + +/// For one row of the circuit, this is the amount of advice cells to put +/// plaintext bits into and also this is the amount of instance cells to +/// put deltas into. +pub const CELLS_PER_ROW: usize = 64; + +/// The amount of rows that can be used by the circuit. +/// +/// When K == 6, halo2 reserves 6 rows internally, so the actual amount of rows +/// that the circuit can use is 2^K - 6 = 58. +/// If we ever change K, we should re-compute the number of reserved rows with +/// (cs.blinding_factors() + 1) +pub const USEFUL_ROWS: usize = 56; + +/// Bitsize of salt used in plaintext commitment. +pub const SALT_SIZE: usize = 128; + +#[derive(Clone, Debug)] +pub struct TopLevelConfig { + /// Each plaintext field element is decomposed into 256 bits + /// and each 64-bit limb is places on a row + bits: [Column; CELLS_PER_ROW], + /// Space to calculate intermediate sums + scratch_space: [Column; 5], + /// Expected dot product for each 64-bit limb + dot_product: Column, + /// Expected 64-bit limb composed into an integer + expected_limbs: Column, + /// The first row of this column is used for the plaintext salt, + /// the second one is for the encoding sum salt. + salt: Column, + + /// Each row of deltas corresponds to one limb of plaintext + deltas: [Column; CELLS_PER_ROW], + + /// Since halo2 does not allow to constrain public inputs in instance columns + /// directly, we first need to copy the inputs into this advice column + advice_from_instance: Column, + + // SELECTORS. + // Below is the description of what happens when a selector + // is activated for a given row: + /// Computes a dot product + selector_dot_product: Selector, + /// Composes a given limb from bits into an integer. + /// The highest limb corresponds to the selector with index 0. + selector_compose: [Selector; 4], + /// Checks binariness of decomposed bits + selector_binary_check: Selector, + /// Sums 4 cells + selector_sum4: Selector, + /// Sums 2 cells + selector_sum2: Selector, + /// Left-shifts the first cell by the size of the plaintext salt and adds the salt + selector_add_plaintext_salt: Selector, + /// Left-shifts the first cell by the size of the encoding sum salt and adds the salt + selector_add_encoding_sum_salt: Selector, + + /// config for Poseidon with rate 15 + poseidon_config_rate15: Pow5Config, + /// config for Poseidon with rate 2 + poseidon_config_rate2: Pow5Config, + + /// Contains 3 public input in this order: + /// [plaintext hash, label sum hash, zero sum]. + /// Does **NOT** contain deltas. + public_inputs: Column, +} + +#[derive(Clone, Debug)] +pub struct AuthDecodeCircuit { + /// plaintext is private input + plaintext: Option<[F; FIELD_ELEMENTS]>, + /// Salt used to create a plaintext commitment. + plaintext_salt: Option, + /// Salt used to create an encoding sum commitment. + encoding_sum_salt: Option, + /// deltas is a public input. + /// Since halo2 doesn't allow to access deltas which we passed in + /// [crate::prover::Prove::prove], + /// we pass it here again to be able to compute the in-circuit expected values. + /// To make handling simpler, this is a matrix of rows, where each row corresponds + /// to a 64-bit limb of the plaintext. + deltas: [[F; CELLS_PER_ROW]; USEFUL_ROWS], +} + +impl Circuit for AuthDecodeCircuit { + type Config = TopLevelConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self { + plaintext: None, + plaintext_salt: None, + encoding_sum_salt: None, + deltas: self.deltas.clone(), + } + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + // keep this in case we modify the circuit and change K but forget + // to update USEFUL_ROWS + // UPDATE: since we temporary changed [K] from 6 to 7, commenting out + // this assert. Uncomment when + // assert!(((1 << K) as usize) - (meta.blinding_factors() + 1) == USEFUL_ROWS); + + // ADVICE COLUMNS + + let bits: [Column; CELLS_PER_ROW] = (0..CELLS_PER_ROW) + .map(|_| meta.advice_column()) + .collect::>() + .try_into() + .unwrap(); + + let dot_product = meta.advice_column(); + meta.enable_equality(dot_product); + + let expected_limbs = meta.advice_column(); + meta.enable_equality(expected_limbs); + + // The first row of this column is used for the plaintext salt, + // the second one is for the encoding sum salt + let salt = meta.advice_column(); + meta.enable_equality(salt); + + let scratch_space: [Column; 5] = (0..5) + .map(|_| { + let c = meta.advice_column(); + meta.enable_equality(c); + c + }) + .collect::>() + .try_into() + .unwrap(); + + let advice_from_instance = meta.advice_column(); + meta.enable_equality(advice_from_instance); + + // INSTANCE COLUMNS + + let deltas: [Column; CELLS_PER_ROW] = (0..CELLS_PER_ROW) + .map(|_| meta.instance_column()) + .collect::>() + .try_into() + .unwrap(); + + let public_inputs = meta.instance_column(); + meta.enable_equality(public_inputs); + + // SELECTORS + + let selector_dot_product = meta.selector(); + let selector_binary_check = meta.selector(); + let selector_compose: [Selector; 4] = (0..4) + .map(|_| meta.selector()) + .collect::>() + .try_into() + .unwrap(); + let selector_sum4 = meta.selector(); + let selector_sum2 = meta.selector(); + let selector_add_plaintext_salt = meta.selector(); + let selector_add_encoding_sum_salt = meta.selector(); + + // POSEIDON + + let poseidon_config_rate15 = configure_poseidon_rate_15::(15, meta); + let poseidon_config_rate2 = configure_poseidon_rate_2::(2, meta); + // we need to designate one column for global constants which the Poseidon + // chip uses + let global_constants = meta.fixed_column(); + meta.enable_constant(global_constants); + + // CONFIG + + // Put everything initialized above into a config + let cfg = TopLevelConfig { + bits, + scratch_space, + dot_product, + expected_limbs, + salt, + advice_from_instance, + + deltas, + + selector_dot_product, + selector_compose, + selector_binary_check, + selector_sum4, + selector_sum2, + selector_add_plaintext_salt, + selector_add_encoding_sum_salt, + + poseidon_config_rate15, + poseidon_config_rate2, + + public_inputs, + }; + + // MISC + + // build Expressions containing powers of 2, to be used in some gates + let two = BigUint::from(2u8); + let pow_2_x: Vec<_> = (0..256) + .map(|i| Expression::Constant(biguint_to_f(&two.pow(i as u32)))) + .collect(); + + // GATES + + // Computes the dot product of 2 sets of cells + meta.create_gate("dot product", |meta| { + let mut product = Expression::Constant(F::from(0)); + + for i in 0..CELLS_PER_ROW { + let delta = meta.query_instance(cfg.deltas[i], Rotation::cur()); + let bit = meta.query_advice(cfg.bits[i], Rotation::cur()); + product = product + delta * bit; + } + + // constrain to match the expected value + let expected = meta.query_advice(cfg.dot_product, Rotation::cur()); + let sel = meta.query_selector(cfg.selector_dot_product); + vec![sel * (product - expected)] + }); + + // Batch-checks binariness of multiple bits + meta.create_gate("binary check", |meta| { + // create one Expression for each cell to be checked + let expressions: [Expression; CELLS_PER_ROW] = (0..CELLS_PER_ROW) + .map(|i| { + let bit = meta.query_advice(cfg.bits[i], Rotation::cur()); + bit.clone() * bit.clone() - bit + }) + .collect::>() + .try_into() + .unwrap(); + let sel = meta.query_selector(cfg.selector_binary_check); + + // constrain all expressions to be equal to 0 + Constraints::with_selector(sel, expressions) + }); + + // create 4 gates, each processing a different limb + for idx in 0..4 { + // compose the bits of a 64-bit limb into a field element and shift the + // limb to the left depending in the limb's index `idx` + meta.create_gate("compose limb", |meta| { + let mut sum_total = Expression::Constant(F::from(0)); + + for i in 0..CELLS_PER_ROW { + // the first bit is the highest bit. It is multiplied by the + // highest power of 2 for that limb. + let bit = meta.query_advice(cfg.bits[i], Rotation::cur()); + sum_total = sum_total + bit * pow_2_x[255 - (CELLS_PER_ROW * idx) - i].clone(); + } + + // constrain to match the expected value + let expected = meta.query_advice(cfg.expected_limbs, Rotation::cur()); + let sel = meta.query_selector(cfg.selector_compose[idx]); + vec![sel * (sum_total - expected)] + }); + } + + // sums 4 cells + meta.create_gate("sum4", |meta| { + let mut sum = Expression::Constant(F::from(0)); + + for i in 0..4 { + let dot_product = meta.query_advice(cfg.scratch_space[i], Rotation::cur()); + sum = sum + dot_product; + } + + // constrain to match the expected value + let expected = meta.query_advice(cfg.scratch_space[4], Rotation::cur()); + let sel = meta.query_selector(cfg.selector_sum4); + vec![sel * (sum - expected)] + }); + + // sums 2 cells + meta.create_gate("sum2", |meta| { + let mut sum = Expression::Constant(F::from(0)); + + for i in 0..2 { + let dot_product = meta.query_advice(cfg.scratch_space[i], Rotation::cur()); + sum = sum + dot_product; + } + + // constrain to match the expected value + let expected = meta.query_advice(cfg.scratch_space[4], Rotation::cur()); + let sel = meta.query_selector(cfg.selector_sum2); + vec![sel * (sum - expected)] + }); + + cfg + } + + // Creates the circuit + fn synthesize(&self, cfg: Self::Config, mut layouter: impl Layouter) -> Result<(), Error> { + let (label_sum_salted, plaintext_salted) = layouter.assign_region( + || "main", + |mut region| { + // dot products for each row + let mut assigned_dot_products = Vec::new(); + // limb for each row + let mut assigned_limbs = Vec::new(); + + // plaintext salt + let assigned_plaintext_salt = region.assign_advice( + || "", + cfg.salt, + 0, + || Value::known(self.plaintext_salt.unwrap()), + )?; + + // encoding sum salt + let assigned_encoding_sum_salt = region.assign_advice( + || "", + cfg.salt, + 1, + || Value::known(self.encoding_sum_salt.unwrap()), + )?; + + for j in 0..FIELD_ELEMENTS { + // decompose the private field element into bits + let bits = bigint_to_256bits(f_to_bigint(&self.plaintext.unwrap()[j])); + + let max_row = 4; + + for row in 0..max_row { + // convert bits into field elements and put them on the same row + for i in 0..CELLS_PER_ROW { + region.assign_advice( + || "", + cfg.bits[i], + j * 4 + row, + || Value::known(F::from(bits[CELLS_PER_ROW * row + i])), + )?; + } + // constrain the whole row of bits to be binary + cfg.selector_binary_check.enable(&mut region, j * 4 + row)?; + + let limbs = bits_to_limbs(bits); + // place expected limbs for each row + assigned_limbs.push(region.assign_advice( + || "", + cfg.expected_limbs, + j * 4 + row, + || Value::known(biguint_to_f(&limbs[row].clone())), + )?); + // constrain the expected limb to match what the gate + // composes from bits + cfg.selector_compose[row].enable(&mut region, j * 4 + row)?; + + // compute the expected dot product for this row + let mut dot_product = F::from(0); + for i in 0..CELLS_PER_ROW { + dot_product += self.deltas[j * 4 + row][i] + * F::from(bits[CELLS_PER_ROW * (row) + i]); + } + + // place it into a cell for the expected dot_product + assigned_dot_products.push(region.assign_advice( + || "", + cfg.dot_product, + j * 4 + row, + || Value::known(dot_product), + )?); + // constrain the expected dot product to match what the gate computes + cfg.selector_dot_product.enable(&mut region, j * 4 + row)?; + } + } + + // the grand sum of all dot products + // safe to .unwrap because we will always have exactly 58 dot_product + let (dot_product, mut offset) = self.compute_58_cell_sum( + &assigned_dot_products.try_into().unwrap(), + &mut region, + &cfg, + 0, + )?; + + // move `zero_sum` into `scratch_space` area to be used in computations + let zero_sum = region.assign_advice_from_instance( + || "", + cfg.public_inputs, + 2, + cfg.scratch_space[0], + offset, + )?; + offset += 1; + + // add zero_sum to all dot_products to get label_sum + let label_sum = + self.fold_sum(&[vec![dot_product, zero_sum]], &mut region, &cfg, offset)?[0] + .clone(); + offset += 1; + + // add encoding sum salt + // let label_sum_salted = self.add_encoding_sum_salt( + // label_sum, + // assigned_encoding_sum_salt.clone(), + // &mut region, + // &cfg, + // offset, + // )?; + // offset += 1; + let label_sum_salted = vec![label_sum, assigned_encoding_sum_salt]; + + // Constrains each chunks of 4 limbs to be equal to a cell and + // returns the constrained cells containing the original plaintext + // (the private input to the circuit). + let plaintext: Result>, Error> = assigned_limbs + .chunks(4) + .map(|c| { + let sum = + self.fold_sum(&[c.to_vec()], &mut region, &cfg, offset)?[0].clone(); + offset += 1; + Ok(sum) + }) + .collect(); + let mut plaintext = plaintext?; + + // add salt to the last field element of the plaintext + // let pt_len = plaintext.len(); + // let last_with_salt = self.add_plaintext_salt( + // plaintext[pt_len - 1].clone(), + // assigned_plaintext_salt, + // &mut region, + // &cfg, + // offset, + // )?; + // uncomment if we need to do more computations in the scratch space + // offset += 1; + + // replace the last field element with the one with salt + // plaintext[pt_len - 1] = last_with_salt; + + plaintext.push(assigned_plaintext_salt); + + //println!("{:?} final `scratch_space` offset", offset); + Ok((label_sum_salted, plaintext)) + }, + )?; + + // Hash the label sum and constrain the digest to match the public input + + let chip = Pow5Chip::construct(cfg.poseidon_config_rate2.clone()); + + let hasher = Hash::, 3, 2>::init( + chip, + layouter.namespace(|| "init"), + )?; + //println!("will hash sum {:?}", label_sum_salted); + //println!(); + + let output = hasher.hash( + layouter.namespace(|| "hash"), + label_sum_salted.try_into().unwrap(), + )?; + + layouter.assign_region( + || "constrain output", + |mut region| { + let expected = region.assign_advice_from_instance( + || "", + cfg.public_inputs, + 1, + cfg.advice_from_instance, + 0, + )?; + region.constrain_equal(output.cell(), expected.cell())?; + Ok(()) + }, + )?; + + // Hash the plaintext and constrain the digest to match the public input + + let chip = Pow5Chip::construct(cfg.poseidon_config_rate15.clone()); + + let hasher = Hash::, 16, 15>::init( + chip, + layouter.namespace(|| "init"), + )?; + // unwrap() is safe since we use exactly 15 field elements in plaintext + //println!("will hash plaintext {:?}", plaintext_salted); + //println!(); + let output = hasher.hash( + layouter.namespace(|| "hash"), + plaintext_salted.try_into().unwrap(), + )?; + + layouter.assign_region( + || "constrain output", + |mut region| { + let expected = region.assign_advice_from_instance( + || "", + cfg.public_inputs, + 0, + cfg.advice_from_instance, + 1, + )?; + region.constrain_equal(output.cell(), expected.cell())?; + Ok(()) + }, + )?; + + Ok(()) + } +} + +impl AuthDecodeCircuit { + pub fn new( + plaintext: [F; FIELD_ELEMENTS], + plaintext_salt: F, + encoding_sum_salt: F, + deltas: [[F; CELLS_PER_ROW]; USEFUL_ROWS], + ) -> Self { + Self { + plaintext: Some(plaintext), + plaintext_salt: Some(plaintext_salt), + encoding_sum_salt: Some(encoding_sum_salt), + deltas, + } + } + // Computes the sum of 58 `cells` and outputs the cell containing the sum + // and the amount of rows used up during computation. + // Computations are done in the `scratch_space` area starting at the `row_offset` + // row. Constrains all intermediate values as necessary, so that + // the resulting cell is a properly constrained sum. + fn compute_58_cell_sum( + &self, + cells: &[AssignedCell; 56], + region: &mut Region, + config: &TopLevelConfig, + row_offset: usize, + ) -> Result<(AssignedCell, usize), Error> { + let original_offset = row_offset; + let mut offset = row_offset; + + // copy chunks of 4 cells to `scratch_space` and compute their sums + let l1_chunks: Vec>> = cells.chunks(4).map(|c| c.to_vec()).collect(); + + let l2_sums = self.fold_sum(&l1_chunks, region, config, offset)?; + + offset += l1_chunks.len(); + + // we now have 14 level-2 subsums which need to be summed with each + // other in batches of 4. + + let l2_chunks: Vec>> = + l2_sums.chunks(4).map(|c| c.to_vec()).collect(); + + // we now have 4 level-3 subsums which need to be summed with each + // other in batches of 4. + let l3_sums = self.fold_sum(&l2_chunks, region, config, offset)?; + + offset += l2_chunks.len(); + + // 4 level-3 subsums into the final level-4 sum which is the final + // sum + + let l3_chunks: Vec>> = + l3_sums.chunks(4).map(|c| c.to_vec()).collect(); + + let final_sum = self.fold_sum(&l3_chunks, region, config, offset)?[0].clone(); + + offset += 1; + + Ok((final_sum, offset - original_offset)) + } + + // Puts the cells on the same row and computes their sum. Places the resulting + // cell into the 5th column of the `scratch_space` and returns it. Returns + // as many sums as there are chunks of cells. + fn fold_sum( + &self, + chunks: &[Vec>], + region: &mut Region, + config: &TopLevelConfig, + row_offset: usize, + ) -> Result>, Error> { + (0..chunks.len()) + .map(|i| { + let size = chunks[i].len(); + assert!(size == 2 || size == 4); + + let mut sum = Value::known(F::from(0)); + // copy the cells onto the same row + for j in 0..size { + chunks[i][j].copy_advice( + || "", + region, + config.scratch_space[j], + row_offset + i, + )?; + sum = sum + chunks[i][j].value(); + } + let assigned_sum = + region.assign_advice(|| "", config.scratch_space[4], row_offset + i, || sum)?; + + // activate the gate which performs the actual constraining + if size == 4 { + config.selector_sum4.enable(region, row_offset + i)?; + } else { + config.selector_sum2.enable(region, row_offset + i)?; + } + + Ok(assigned_sum) + }) + .collect() + } + + // Puts two cells on the same row. The second cell is the salt. Left-shifts + // the first cell's value by the size of the salt and adds the salt to it. + // Places the resulting cell into the 5th column of the `scratch_space` and + // returns it. + fn add_salt( + &self, + cell: AssignedCell, + salt: AssignedCell, + region: &mut Region, + config: &TopLevelConfig, + row_offset: usize, + salt_size: usize, + ) -> Result, Error> { + // copy the cells onto the same row + cell.copy_advice(|| "", region, config.scratch_space[0], row_offset)?; + salt.copy_advice(|| "", region, config.scratch_space[1], row_offset)?; + + // compute the expected sum and put it into the 5th cell + let two = BigUint::from(2u8); + let pow_2_salt = biguint_to_f(&two.pow(salt_size as u32)); + let sum = cell.value() * Value::known(pow_2_salt) + salt.value(); + let assigned_sum = + region.assign_advice(|| "", config.scratch_space[4], row_offset, || sum)?; + + // activate the gate which performs the actual constraining + // TODO: this is a quick hack + if salt_size == SALT_SIZE { + config + .selector_add_plaintext_salt + .enable(region, row_offset)?; + } else { + config + .selector_add_encoding_sum_salt + .enable(region, row_offset)?; + } + + Ok(assigned_sum) + } + + fn add_plaintext_salt( + &self, + cell: AssignedCell, + salt: AssignedCell, + region: &mut Region, + config: &TopLevelConfig, + row_offset: usize, + ) -> Result, Error> { + self.add_salt(cell, salt, region, config, row_offset, SALT_SIZE) + } + + fn add_encoding_sum_salt( + &self, + cell: AssignedCell, + salt: AssignedCell, + region: &mut Region, + config: &TopLevelConfig, + row_offset: usize, + ) -> Result, Error> { + self.add_salt(cell, salt, region, config, row_offset, SALT_SIZE) + } +} + +/// The circuit is tested from [super::prover::tests] +#[cfg(test)] +mod tests {} diff --git a/authdecode/src/backend/halo2/circuit_diagram.pdf b/authdecode/src/backend/halo2/circuit_diagram.pdf new file mode 100644 index 0000000000000000000000000000000000000000..65769954bafc4cd2ca247500ff488bfa0b833074 GIT binary patch literal 75083 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%0AI>L(A^ehUj9aX)xe4%eGVGJvF371CuDjdv${ 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 OV+az8iu$Go68{6wRCmk( literal 0 HcmV?d00001 diff --git a/authdecode/src/backend/halo2/mod.rs b/authdecode/src/backend/halo2/mod.rs new file mode 100644 index 0000000000..e6d64d6b45 --- /dev/null +++ b/authdecode/src/backend/halo2/mod.rs @@ -0,0 +1,27 @@ +mod circuit; +pub mod onetimesetup; +mod poseidon; +pub mod prover; +mod utils; +pub mod verifier; + +/// The amount of LSBs of a field element that are being used. +const USEFUL_BITS: usize = 253; + +/// The size of the chunk of plaintext +/// We use 14 field elements. Only [USEFUL_BITS] of each field element are used. +const CHUNK_SIZE: usize = 3542; + +#[cfg(test)] +pub(crate) mod tests { + use super::{prover::Prover, verifier::Verifier}; + + pub fn backend_pair() -> (Prover, Verifier) { + let params = super::onetimesetup::OneTimeSetup::params(); + + let proving_key = super::onetimesetup::OneTimeSetup::proving_key(params.clone()); + let verification_key = super::onetimesetup::OneTimeSetup::verification_key(params); + + (Prover::new(proving_key), Verifier::new(verification_key)) + } +} diff --git a/authdecode/src/backend/halo2/onetimesetup.rs b/authdecode/src/backend/halo2/onetimesetup.rs new file mode 100644 index 0000000000..2fd247022d --- /dev/null +++ b/authdecode/src/backend/halo2/onetimesetup.rs @@ -0,0 +1,57 @@ +use super::{ + circuit::{AuthDecodeCircuit, CELLS_PER_ROW, K, USEFUL_ROWS}, + prover::PK, + verifier::VK, +}; +use halo2_proofs::{ + halo2curves::bn256::Bn256, + plonk, + poly::{commitment::ParamsProver, kzg::commitment::ParamsKZG}, +}; + +pub struct OneTimeSetup {} + +/// OneTimeSetup generates the proving key and the verification key. It can be +/// run ahead of time before the actual zk proving/verification takes place. +/// +/// Note that as of Oct 2022 halo2 does not support serializing the proving/verification +/// keys. That's why we can't use cached keys but need to call this one-time setup every +/// time when we instantiate the halo2 prover/verifier. +impl OneTimeSetup { + /// Returns the verification key for the AuthDecode circuit + pub fn verification_key(params: ParamsKZG) -> VK { + // we need an instance of the circuit, the exact inputs don't matter + let circuit = AuthDecodeCircuit::new( + Default::default(), + Default::default(), + Default::default(), + [[Default::default(); CELLS_PER_ROW]; USEFUL_ROWS], + ); + + // safe to unwrap since we are inputting deterministic params and circuit + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + VK { key: vk, params } + } + + /// Returns the proving key for the AuthDecode circuit + pub fn proving_key(params: ParamsKZG) -> PK { + // we need an instance of the circuit, the exact inputs don't matter + let circuit = AuthDecodeCircuit::new( + Default::default(), + Default::default(), + Default::default(), + [[Default::default(); CELLS_PER_ROW]; USEFUL_ROWS], + ); + + // safe to unwrap, we are inputting deterministic params and circuit on every + // invocation + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + let pk = plonk::keygen_pk(¶ms, vk, &circuit).unwrap(); + + PK { key: pk, params } + } + + pub fn params() -> ParamsKZG { + ParamsKZG::::new(K) + } +} diff --git a/authdecode/src/backend/halo2/poseidon/circuit_config.rs b/authdecode/src/backend/halo2/poseidon/circuit_config.rs new file mode 100644 index 0000000000..a5769200b6 --- /dev/null +++ b/authdecode/src/backend/halo2/poseidon/circuit_config.rs @@ -0,0 +1,74 @@ +use halo2_poseidon::poseidon::{primitives::Spec, Pow5Chip, Pow5Config}; +use halo2_proofs::{halo2curves::bn256::Fr as F, plonk::ConstraintSystem}; + +/// Configures the in-circuit Poseidon for rate 15 and returns the config +/// +/// Patterned after [halo2_gadgets::poseidon::pow5] +/// (see in that file tests::impl Circuit for PermuteCircuit::configure()) +pub fn configure_poseidon_rate_15>( + rate: usize, + meta: &mut ConstraintSystem, +) -> Pow5Config { + let width = rate + 1; + let state = (0..width).map(|_| meta.advice_column()).collect::>(); + let partial_sbox = meta.advice_column(); + + let rc_a = (0..width).map(|_| meta.fixed_column()).collect::>(); + let rc_b = (0..width).map(|_| meta.fixed_column()).collect::>(); + + Pow5Chip::configure::( + meta, + state.try_into().unwrap(), + partial_sbox, + rc_a.try_into().unwrap(), + rc_b.try_into().unwrap(), + ) +} + +/// Configures the in-circuit Poseidon for rate 1 and returns the config +/// +/// Patterned after [halo2_gadgets::poseidon::pow5] +/// (see in that file tests::impl Circuit for PermuteCircuit::configure()) +pub fn configure_poseidon_rate_1>( + rate: usize, + meta: &mut ConstraintSystem, +) -> Pow5Config { + let width = rate + 1; + let state = (0..width).map(|_| meta.advice_column()).collect::>(); + let partial_sbox = meta.advice_column(); + + let rc_a = (0..width).map(|_| meta.fixed_column()).collect::>(); + let rc_b = (0..width).map(|_| meta.fixed_column()).collect::>(); + + Pow5Chip::configure::( + meta, + state.try_into().unwrap(), + partial_sbox, + rc_a.try_into().unwrap(), + rc_b.try_into().unwrap(), + ) +} + +/// Configures the in-circuit Poseidon for rate 2 and returns the config +/// +/// Patterned after [halo2_gadgets::poseidon::pow5] +/// (see in that file tests::impl Circuit for PermuteCircuit::configure()) +pub fn configure_poseidon_rate_2>( + rate: usize, + meta: &mut ConstraintSystem, +) -> Pow5Config { + let width = rate + 1; + let state = (0..width).map(|_| meta.advice_column()).collect::>(); + let partial_sbox = meta.advice_column(); + + let rc_a = (0..width).map(|_| meta.fixed_column()).collect::>(); + let rc_b = (0..width).map(|_| meta.fixed_column()).collect::>(); + + Pow5Chip::configure::( + meta, + state.try_into().unwrap(), + partial_sbox, + rc_a.try_into().unwrap(), + rc_b.try_into().unwrap(), + ) +} diff --git a/authdecode/src/backend/halo2/poseidon/mod.rs b/authdecode/src/backend/halo2/poseidon/mod.rs new file mode 100644 index 0000000000..80d5bdcf45 --- /dev/null +++ b/authdecode/src/backend/halo2/poseidon/mod.rs @@ -0,0 +1,34 @@ +pub(crate) mod circuit_config; +mod rate15_params; +mod rate1_params; +mod rate2_params; +pub(crate) mod spec; + +use halo2_poseidon::poseidon::primitives::{ConstantLength, Hash}; +use halo2_proofs::halo2curves::bn256::Fr as F; + +use spec::{Spec1, Spec15, Spec2}; + +/// Hashes inputs with rate 15 Poseidon and returns the digest +/// +/// Patterned after [halo2_gadgets::poseidon::pow5] +/// (see in that file tests::poseidon_hash()) +pub fn poseidon_15(field_elements: &[F; 15]) -> F { + Hash::, 16, 15>::init().hash(*field_elements) +} + +/// Hashes inputs with rate 2 Poseidon and returns the digest +/// +/// Patterned after [halo2_gadgets::poseidon::pow5] +/// (see in that file tests::poseidon_hash()) +pub fn poseidon_2(field_elements: &[F; 2]) -> F { + Hash::, 3, 2>::init().hash(*field_elements) +} + +/// Hashes inputs with rate 1 Poseidon and returns the digest +/// +/// Patterned after [halo2_gadgets::poseidon::pow5] +/// (see in that file tests::poseidon_hash()) +pub fn poseidon_1(field_elements: &[F; 1]) -> F { + Hash::, 2, 1>::init().hash(*field_elements) +} diff --git a/authdecode/src/backend/halo2/poseidon/rate15_params.rs b/authdecode/src/backend/halo2/poseidon/rate15_params.rs new file mode 100644 index 0000000000..46eb70dffc --- /dev/null +++ b/authdecode/src/backend/halo2/poseidon/rate15_params.rs @@ -0,0 +1,10229 @@ +//! Parameters for using rate 15 Poseidon with the bn256 scalar field. +//! Patterned after [halo2_gadgets::poseidon::primitives::fp] +//! +//! The parameters can be reproduced by running the following Sage script from +//! [this repository](https://github.com/daira/pasta-hadeshash): +//! +//! ```text +//! $ sage generate_parameters_grain.sage 1 0 254 16 8 64 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 --rust +//! ``` +//! +//! where 1 means "prime field", 0 means "non-negative sbox", 254 is the bitsize +//! of the field, 16 is the Poseidon width (rate + 1), 8 is the number of full +//! rounds, 64 is the number of partial rounds. + +use halo2_proofs::halo2curves::bn256::Fr as F; + +// Number of round constants: 1152 +// Round constants for GF(p): +pub(crate) const ROUND_CONSTANTS: [[F; 16]; 72] = [ + [ + F::from_raw([ + 0xde22_2fa2_2ad0_b101, + 0xa778_bc33_aedb_cd09, + 0x48a3_3297_4d07_ccee, + 0x11e2_7da7_b7ef_9649, + ]), + F::from_raw([ + 0x0c53_f036_a306_5b65, + 0x5fbf_55f7_9133_c574, + 0xe65a_0f41_42fa_aafc, + 0x1f60_381b_83b4_4a8f, + ]), + F::from_raw([ + 0xd70a_706a_1b6d_add8, + 0x4823_4d02_92ad_fe1c, + 0xbdbf_a45d_cc51_5765, + 0x0fc1_e1ac_8ad3_524e, + ]), + F::from_raw([ + 0xc070_084c_e78b_8d76, + 0x426b_bd22_82a8_1dcd, + 0x8bcd_8f10_bb15_cb0c, + 0x0a40_798e_ad3a_12b7, + ]), + F::from_raw([ + 0x675e_a5f4_62f4_a9c5, + 0xbf39_3b01_35f5_1e2f, + 0x987e_a955_9443_6b6c, + 0x2dc0_9d33_5705_1155, + ]), + F::from_raw([ + 0xe46d_dc54_181d_a088, + 0xd175_ee15_0f34_9033, + 0x32ed_a181_de1a_154d, + 0x104b_9241_d534_2645, + ]), + F::from_raw([ + 0x4f1b_8d8a_c9d1_2698, + 0x7b3b_91f0_622f_1708, + 0x87b8_02fa_44ca_b203, + 0x127a_6208_d98f_6cd3, + ]), + F::from_raw([ + 0x0ec1_8f86_25f8_6d4d, + 0x1dfd_cde6_5995_5a93, + 0xdc02_fb1f_50d9_38ce, + 0x2d07_5cee_bab5_4341, + ]), + F::from_raw([ + 0x43fe_7275_8042_010c, + 0xf40c_6039_a3dd_0d74, + 0x2ad9_23be_be15_a477, + 0x044f_d5c2_101a_20be, + ]), + F::from_raw([ + 0xf084_9628_e09f_9bc8, + 0x8a8f_2a8e_b77f_96c7, + 0x2b81_5564_c539_9acb, + 0x2b30_2c85_11fb_d370, + ]), + F::from_raw([ + 0xee87_222c_ce99_e22b, + 0xd302_c92a_79b1_d0f4, + 0x55d1_eded_1e8a_870b, + 0x07cb_e339_db90_5994, + ]), + F::from_raw([ + 0x28ff_a810_5deb_e211, + 0xe548_394c_94c3_df2f, + 0x4ef2_4c97_c809_f78a, + 0x1326_7493_12c6_e8bd, + ]), + F::from_raw([ + 0x929b_223f_2697_80e0, + 0x7a79_7cd2_36da_d92d, + 0x7080_e7c2_4530_4e4b, + 0x0540_2140_6b8d_1f8c, + ]), + F::from_raw([ + 0xf406_d08f_2787_cc42, + 0x8691_a8d0_18f1_279b, + 0xb23a_9d55_9eae_ecf9, + 0x05c0_e033_b589_f8dd, + ]), + F::from_raw([ + 0x15b1_2eca_3858_4bb1, + 0xa16e_ad43_30e3_5d54, + 0xb61c_749d_566c_9459, + 0x2508_a8cd_d450_f969, + ]), + F::from_raw([ + 0xb2ba_e8d3_68ff_12d2, + 0xe990_9621_fd4f_4169, + 0xe736_da25_072b_d8fb, + 0x264d_ccc0_2e57_4ca7, + ]), + ], + [ + F::from_raw([ + 0x2a6b_02dd_a519_5db3, + 0x01b9_f4bf_1418_d109, + 0x763e_c3ba_10c1_a260, + 0x2a93_8c25_40d6_3615, + ]), + F::from_raw([ + 0x2852_a75a_865a_400c, + 0xc1b0_70fa_a318_5baf, + 0x4ab2_7a62_03f3_a161, + 0x254f_370b_85f5_8a7e, + ]), + F::from_raw([ + 0xcab0_b29c_1495_2ac8, + 0x3d62_23e5_1c44_cb2d, + 0xbf83_712c_7414_c895, + 0x0480_1896_f126_8e5a, + ]), + F::from_raw([ + 0x3dd2_721f_99da_561f, + 0x71d0_a1f1_8c30_106e, + 0x37f4_8fda_b22e_874e, + 0x1f71_88e4_d4f7_5494, + ]), + F::from_raw([ + 0x6059_f755_edeb_68a0, + 0x21d6_5aea_6163_5333, + 0x231c_e443_af1d_80bf, + 0x2b92_7370_1ae0_2d7b, + ]), + F::from_raw([ + 0x7060_196d_b937_42c6, + 0x6e50_9a0f_7bc1_86fb, + 0xd829_620a_acdc_fac7, + 0x1597_224c_b8e9_05ce, + ]), + F::from_raw([ + 0x7fd1_7a82_c5e1_2716, + 0x841e_6323_e96b_39da, + 0x7cfd_57a7_5237_2196, + 0x1d8c_5a65_2883_4690, + ]), + F::from_raw([ + 0x9f58_1570_c1dc_6630, + 0x920d_2bec_1879_8d43, + 0x8251_b86a_7e1a_5139, + 0x1b75_dce9_5073_1f50, + ]), + F::from_raw([ + 0x2c8f_d015_8ee8_f2ab, + 0x9ff8_dedd_fac6_e4ed, + 0x59d5_ad82_09b3_3711, + 0x2773_a018_69bf_9ad3, + ]), + F::from_raw([ + 0x0198_4f62_2651_5b7c, + 0xe593_0bd3_b9d4_c1ee, + 0x10cb_e7ad_0e9b_1b8a, + 0x1a5d_4788_3f24_4626, + ]), + F::from_raw([ + 0x47b2_d9c3_9850_6cfd, + 0x9b1c_a590_9b96_281a, + 0x073c_d90a_09ad_5414, + 0x1982_7732_0594_61e2, + ]), + F::from_raw([ + 0x9f2b_30ea_37b1_a4f6, + 0x8551_bbe9_8475_1f3e, + 0xff27_2465_fb88_1c91, + 0x297c_8bf5_4b03_a6f7, + ]), + F::from_raw([ + 0xdc30_7eba_7722_e40e, + 0xab15_a308_7c5a_e8a6, + 0xb078_b69f_5f3a_7d4b, + 0x01f3_da36_b1ff_5283, + ]), + F::from_raw([ + 0xbd41_c98d_37b4_f132, + 0xff24_7d86_f9a6_a6bc, + 0xd655_eddd_2abe_6c68, + 0x167c_ed6e_39dd_3bd6, + ]), + F::from_raw([ + 0x9f11_3e75_26b8_208f, + 0xa6db_9a7b_f45e_741f, + 0x9f32_da54_1445_e8a8, + 0x085d_19b0_e16f_0ac2, + ]), + F::from_raw([ + 0xf829_f743_5525_ea4d, + 0xe2a0_d363_f169_7f3e, + 0xc165_3cc6_fd8e_93ca, + 0x04f3_65f7_10e9_acd5, + ]), + ], + [ + F::from_raw([ + 0xa91f_f493_be9c_a715, + 0x29ca_f0fa_cbc1_a67b, + 0xd3a2_2cda_ef6b_11f3, + 0x128d_4f03_d03d_7097, + ]), + F::from_raw([ + 0xaca3_6eaa_02db_1021, + 0xd3e6_6805_c616_7415, + 0x3c9f_ae77_0b79_9aff, + 0x2802_10dd_4126_8b13, + ]), + F::from_raw([ + 0xee73_b0ca_64d4_5cc2, + 0x0e3d_bb59_c45b_51dc, + 0xca65_faad_631e_703e, + 0x204e_e7c7_d4ea_06f7, + ]), + F::from_raw([ + 0x03f7_388e_ac33_d786, + 0x2666_fdc0_e549_822b, + 0xfd73_65a6_dca0_f117, + 0x3042_aff0_9c17_65b4, + ]), + F::from_raw([ + 0x939f_66d4_1554_c7fc, + 0xd318_670b_b82f_33c2, + 0xe777_9045_861c_ce3a, + 0x23b7_8077_e751_602b, + ]), + F::from_raw([ + 0x6cdc_3bf7_1292_cec7, + 0x1a62_7996_b935_121e, + 0x7703_cf9a_906b_ad79, + 0x0f35_1e14_bd3a_41ad, + ]), + F::from_raw([ + 0x11a5_07bd_401d_0ee4, + 0x8944_1022_d45b_5b46, + 0x9674_9f9f_a858_5c37, + 0x0e67_b013_5f71_d485, + ]), + F::from_raw([ + 0x3d59_09f5_18da_9df3, + 0x769e_4331_4e0e_b85e, + 0xbd68_c14c_e6ee_1662, + 0x06e8_4634_966d_462b, + ]), + F::from_raw([ + 0x7948_41e8_561f_c02b, + 0x2c7d_6da4_0169_b8f5, + 0x9642_2bb4_6796_f57c, + 0x1761_112f_15f3_57cf, + ]), + F::from_raw([ + 0xcafe_14e5_afe0_39c7, + 0xfe37_7a73_8552_6c8a, + 0x7756_999b_fac4_95b8, + 0x2438_7ac5_7313_799c, + ]), + F::from_raw([ + 0x2b66_d358_cdcf_2370, + 0xa287_a312_99f0_dd16, + 0x06e3_526f_ea7b_3218, + 0x1f3c_817c_bf94_302a, + ]), + F::from_raw([ + 0x6a95_ecc3_c499_6fc9, + 0x74bc_0b93_8ed7_3bf1, + 0x39f1_a6f3_0d43_d40f, + 0x0b13_cf25_c272_dae3, + ]), + F::from_raw([ + 0xe4ea_8596_6599_7f02, + 0x19cb_50ae_7737_044f, + 0x56cd_465c_4a5e_8d57, + 0x2c73_1e62_db4c_c41c, + ]), + F::from_raw([ + 0x7a49_4c0f_0601_156b, + 0xbeb4_a563_2a82_64f1, + 0x8f3a_dfc1_27fd_b17e, + 0x0961_bfea_8f9f_2a70, + ]), + F::from_raw([ + 0x75fd_01a5_8ef7_139a, + 0x1f59_9b92_54e5_be2c, + 0x1963_f112_dd35_7ed5, + 0x1eef_b99f_e9da_c9a9, + ]), + F::from_raw([ + 0x5938_55a1_ff57_4123, + 0xafbd_93c7_0417_b8a0, + 0x3de1_16b1_d6aa_56a8, + 0x02ff_9863_fa2a_6cae, + ]), + ], + [ + F::from_raw([ + 0xaa16_ee59_8fd0_31f1, + 0xfd0f_df41_de89_b42e, + 0xdd2b_00ca_ba52_7938, + 0x2965_5fc0_30f0_a0f6, + ]), + F::from_raw([ + 0x0b59_b82e_ab27_b050, + 0x97f5_6721_beb1_ca23, + 0x8986_9fc2_05e9_4876, + 0x2d9f_e744_f2be_adb9, + ]), + F::from_raw([ + 0x6def_bf0c_2cb9_ef92, + 0x0552_451c_edbf_5ab9, + 0x3898_4828_0e6e_006c, + 0x04b4_c3f4_f1c2_1d6f, + ]), + F::from_raw([ + 0xa567_6f02_47e8_428e, + 0xfbdf_0770_2456_4bc2, + 0xb9e9_5966_2a06_9638, + 0x13a8_f3f3_d0e8_7d53, + ]), + F::from_raw([ + 0xfe17_52f9_1985_9b7f, + 0xeda7_e486_cf62_43c2, + 0xe1a5_5638_8fd8_1741, + 0x1875_c2e8_f43d_9660, + ]), + F::from_raw([ + 0xd902_0dba_f5ba_5371, + 0x6a6c_c23c_1db5_abfa, + 0x1677_24af_4ea3_2b1f, + 0x0db7_a917_f7ef_c1d2, + ]), + F::from_raw([ + 0xb1ad_cf13_2dd4_a7c3, + 0x48a4_288b_99ea_bd50, + 0x94b2_67dc_e45a_4dba, + 0x01c5_6db7_a81f_c78b, + ]), + F::from_raw([ + 0x1f05_678e_4be8_2853, + 0xd416_801d_9640_3985, + 0xc31c_a077_43d1_d7b4, + 0x1c9c_b5a5_d027_4d9d, + ]), + F::from_raw([ + 0x452a_075f_60df_e92a, + 0x88b8_252b_4f5a_3f4a, + 0x66ab_6566_94d5_3489, + 0x02f7_86db_f83b_dbec, + ]), + F::from_raw([ + 0xf100_1c3b_ec44_88c4, + 0x8145_93c0_fea1_fd25, + 0xd384_ecf0_3842_9f75, + 0x18b9_789a_7a68_183a, + ]), + F::from_raw([ + 0xb7c8_a19e_3888_1d61, + 0x29df_2b4c_947c_29ce, + 0x2b55_482a_946b_daaa, + 0x28eb_1c34_f770_ab91, + ]), + F::from_raw([ + 0x3f95_dfe6_5ee7_8e81, + 0x2747_87a8_3223_43c0, + 0xd6a4_c694_bb0c_6fec, + 0x26e9_c9da_ab62_a9f1, + ]), + F::from_raw([ + 0x44a7_5907_a4c2_ed15, + 0x94fe_ddb0_a802_cfa9, + 0x675b_a7f1_d70f_3012, + 0x0111_9778_5887_9145, + ]), + F::from_raw([ + 0xa72a_9d75_6ba5_2cf3, + 0xbac6_1ee7_0c23_573f, + 0xa1a7_d841_5fab_b683, + 0x164f_34b7_c356_b9fd, + ]), + F::from_raw([ + 0x88a7_dd66_38b2_b3a5, + 0xbbeb_76a9_e323_b7c7, + 0x4e75_b1e6_f756_57e0, + 0x1632_19ca_5322_b377, + ]), + F::from_raw([ + 0x4194_ce63_2b96_11b2, + 0xc390_02a1_bc43_5708, + 0x8576_b8fb_bab4_058d, + 0x0441_594f_59c6_5d1a, + ]), + ], + [ + F::from_raw([ + 0x140c_b24b_7e4a_691e, + 0xe20b_3ca5_afb6_0b06, + 0x9c4a_bc50_b639_a8e6, + 0x04cb_005b_4d43_931c, + ]), + F::from_raw([ + 0x220e_95d3_434a_04d2, + 0xe73f_2272_2864_7f9d, + 0x399c_83c6_74cf_ceb4, + 0x25eb_5020_3caa_c17c, + ]), + F::from_raw([ + 0x1277_ee10_6931_6776, + 0x9cd6_d2fd_076d_7dc1, + 0x5045_2352_5169_c668, + 0x0a60_5f7f_e9e3_6bb7, + ]), + F::from_raw([ + 0x163e_b0e8_36a4_6c58, + 0xc14d_991a_b3b8_d04a, + 0x9007_248c_b7ca_36b4, + 0x0ab2_fe20_9b9d_fc7c, + ]), + F::from_raw([ + 0x9956_6f5d_2346_1326, + 0x3134_54e6_747a_f5f3, + 0x90f9_4996_5603_320b, + 0x0e14_59cb_5c0a_dd6f, + ]), + F::from_raw([ + 0xbb04_cca4_5fce_07aa, + 0x616d_26e7_6013_675a, + 0x80dc_442e_dce9_682a, + 0x045a_e1dc_4a86_d1ec, + ]), + F::from_raw([ + 0xe081_47e4_d397_a970, + 0xe15d_d0e9_c331_9865, + 0x9160_59cb_cc88_975f, + 0x1834_f47c_1369_8cbb, + ]), + F::from_raw([ + 0x2374_22ed_5318_9f5c, + 0xf620_960d_8893_3ed5, + 0x7a69_4b5c_5b4e_1b44, + 0x2039_a1c7_335a_7e4c, + ]), + F::from_raw([ + 0x6949_e3f0_3350_bb3f, + 0x00d8_d5e8_7ec5_dbb6, + 0x2e2a_dcdc_292a_350a, + 0x2a10_316f_1e66_acf3, + ]), + F::from_raw([ + 0xe5cb_e276_1176_824a, + 0x281f_973d_c181_33ce, + 0x840e_df14_826a_ea05, + 0x1360_b914_1545_9da5, + ]), + F::from_raw([ + 0x990c_faa4_0f6a_5f6b, + 0xba40_dacd_4ec1_d61a, + 0x081d_b6f0_8a89_7bf2, + 0x1505_e255_267d_336a, + ]), + F::from_raw([ + 0x4c12_b8e4_58f7_7d33, + 0x7adb_1842_691e_8a36, + 0x779d_9813_a0b6_5097, + 0x0350_e302_0ea3_0d1e, + ]), + F::from_raw([ + 0x9f4b_9d42_cc12_cafb, + 0x8dbd_0641_3b60_7ba6, + 0xb82d_96d6_4b0d_221a, + 0x0eeb_bd4c_2b0c_9b32, + ]), + F::from_raw([ + 0x1f12_26b3_74d8_7f8c, + 0x4314_7cac_3d14_2871, + 0x444a_2404_f700_3ee0, + 0x15b2_d4b3_61df_49e3, + ]), + F::from_raw([ + 0x4e89_2c35_d380_b18e, + 0x14dd_e9d6_6535_ef62, + 0x7fd4_9f93_16b4_9508, + 0x29c8_338c_5cfe_98df, + ]), + F::from_raw([ + 0x7f8d_ce7e_9ac7_98e6, + 0x5fd1_0f11_2f8e_a71a, + 0xcc81_b775_580c_cde9, + 0x1d7a_2627_f55a_ece0, + ]), + ], + [ + F::from_raw([ + 0xe69c_7e5d_345d_75ed, + 0xde2f_5492_0055_87ae, + 0x8abd_a156_af45_6572, + 0x0cd6_34c2_7ab4_0605, + ]), + F::from_raw([ + 0xc44d_7bc5_9b72_7adc, + 0x4930_35a9_721d_354f, + 0xe7a1_6ca8_e852_3131, + 0x1303_fd48_e265_6565, + ]), + F::from_raw([ + 0x4628_19c9_c9e9_06ab, + 0x17bc_908a_3dc6_b1e7, + 0xff06_ffea_6179_e586, + 0x052f_5a43_86ea_22f5, + ]), + F::from_raw([ + 0xd8c2_a7aa_7595_9293, + 0xc714_a6b0_c10b_a2b4, + 0x3702_fc0a_42c4_5ba5, + 0x077e_3bc5_ed1c_34ba, + ]), + F::from_raw([ + 0xb0b7_f104_6f95_3d65, + 0x85c9_9efc_fe14_7bac, + 0xca60_4490_4e7a_984f, + 0x08d8_8160_882f_c8af, + ]), + F::from_raw([ + 0x0419_d1aa_d796_a189, + 0xb4d5_ae4b_19ef_69c4, + 0xc7e5_b632_6029_c6bc, + 0x1ce3_b22d_ff95_f834, + ]), + F::from_raw([ + 0x09db_d8c2_b988_ab8e, + 0x683e_3eff_bf50_6e53, + 0x2df5_f3c0_c9ad_fec2, + 0x0d4f_d994_dbcc_1526, + ]), + F::from_raw([ + 0x7cd0_44e8_2abd_94b3, + 0x78c7_4fd0_49e6_b865, + 0x6251_1ef5_a38a_4f8c, + 0x2ba6_be5c_d79a_ff74, + ]), + F::from_raw([ + 0x1b9c_39dc_8e96_864a, + 0x92da_6fe5_c0f0_2cdf, + 0x7c95_4004_00da_96a1, + 0x0976_7a2d_9dfa_39e6, + ]), + F::from_raw([ + 0x3662_ec84_f104_c05e, + 0xd2e0_45b2_a018_e109, + 0xfefc_35bf_e0ce_7e33, + 0x0105_21c7_23f4_7dc5, + ]), + F::from_raw([ + 0x2fd8_ccb4_57bd_e1ed, + 0xbb7b_3e8b_bf03_63e6, + 0xc086_5fa6_4d22_0d6d, + 0x144f_09b8_0346_ccfb, + ]), + F::from_raw([ + 0x63da_e83d_b5ed_6baa, + 0x2052_76ca_3e3b_1249, + 0x56d0_9315_cc6a_8e86, + 0x1fc0_b993_2f74_b4db, + ]), + F::from_raw([ + 0x514b_b8f9_72c8_361e, + 0x2e1a_3b1b_7870_36e3, + 0x4a8b_e7b5_f2fc_ebb0, + 0x0776_d2d9_72a0_04c0, + ]), + F::from_raw([ + 0x7c56_755f_0767_58d6, + 0x28be_49af_3aee_cc9d, + 0x6651_28f3_7e1c_3125, + 0x221d_6e56_0e54_eb27, + ]), + F::from_raw([ + 0x06d8_aee6_7b88_e1fc, + 0xbbd2_0de6_2f96_5ad4, + 0x1c1f_8372_e999_ba27, + 0x1641_89cd_fd98_33b7, + ]), + F::from_raw([ + 0x2639_3e10_3b08_a3cb, + 0x0352_3eaf_82d9_2745, + 0xabf7_1a4d_863d_8b6d, + 0x1e3e_736e_cf97_45b4, + ]), + ], + [ + F::from_raw([ + 0x53f6_39d3_79c1_0051, + 0xa0ba_2cfa_9dfc_589c, + 0xf501_ec92_0b16_22d2, + 0x1ff3_d30b_3286_b988, + ]), + F::from_raw([ + 0x873a_7252_3008_3a7e, + 0x396c_d361_940a_bc3f, + 0xd22b_c08a_592b_1a6d, + 0x0a50_d982_4fcc_95a9, + ]), + F::from_raw([ + 0xba28_f208_9657_40ed, + 0xd2e4_721b_93a0_7edf, + 0x63d4_2de5_1689_d990, + 0x2db5_0a1e_16be_63bb, + ]), + F::from_raw([ + 0xea01_1d89_b202_bb92, + 0xee7d_3444_5566_fc9d, + 0xa581_a228_fb44_05f2, + 0x1282_594f_f202_12e8, + ]), + F::from_raw([ + 0xfe06_80c0_ec6e_f09b, + 0x5d0b_ceae_cc46_dcce, + 0x35ff_789b_7b4d_63ff, + 0x0ade_27c0_7795_1cd3, + ]), + F::from_raw([ + 0xeb62_adce_2f3e_67e3, + 0x324c_a24f_2ee4_3e24, + 0xd078_fa4e_7136_92be, + 0x2737_4adf_1b38_ac62, + ]), + F::from_raw([ + 0x7d86_e975_3824_2e11, + 0x70cf_7aca_6a0e_c3b3, + 0x9b6a_c0ac_b78d_a929, + 0x2eff_75fa_36e8_716c, + ]), + F::from_raw([ + 0x5327_642e_82fa_e68e, + 0x0fae_33a6_1a78_3b84, + 0x6478_4b11_ec7e_ff19, + 0x1a28_2255_82a1_edd4, + ]), + F::from_raw([ + 0xf5ac_6ee8_62c9_f439, + 0x7f3d_8d85_704c_44f5, + 0x04e5_1a8c_c3f2_0004, + 0x0e11_13e8_1de1_bcf2, + ]), + F::from_raw([ + 0x9662_2390_3a47_9f5c, + 0x0738_ed0c_4fa0_9b6f, + 0xb807_074e_72a6_72a5, + 0x2105_75d2_0f3c_2816, + ]), + F::from_raw([ + 0x4dc4_8c59_71a1_4351, + 0x83f0_3bf9_f337_bdba, + 0xfaff_a9e2_64ac_61b9, + 0x21e8_97f7_49c8_4ac2, + ]), + F::from_raw([ + 0x7bbc_de7d_9738_a66a, + 0x5019_3d83_1c07_90ee, + 0x2aed_85c5_0e70_cbeb, + 0x1a56_87dc_bbac_6297, + ]), + F::from_raw([ + 0xd556_d2f2_44e4_9577, + 0x806b_1072_96b3_06c4, + 0x15fe_0a40_d742_844e, + 0x0410_5499_d5cf_eaf1, + ]), + F::from_raw([ + 0xd57a_ece7_20c6_be48, + 0x26b5_0a06_8769_67cd, + 0x4956_e80f_4f07_2e2f, + 0x1af9_497a_7280_e141, + ]), + F::from_raw([ + 0x7e30_8ee3_2e2c_6031, + 0xc16c_dbfa_2247_b8bc, + 0xce7e_0eb1_667e_8ed0, + 0x2a0e_2d3e_ec62_59b7, + ]), + F::from_raw([ + 0x14b0_cd3e_84ac_5ed1, + 0xf853_89f1_e31d_bc88, + 0xc701_05e4_8492_160e, + 0x2d7c_986d_3d3d_3be8, + ]), + ], + [ + F::from_raw([ + 0x9e5a_596d_4e1e_22bb, + 0x271d_e5e4_389e_84c0, + 0x38b7_df4a_8c0f_5019, + 0x251d_1231_e763_9792, + ]), + F::from_raw([ + 0xcfa1_fab8_c56c_37ec, + 0x675b_abed_6364_ae12, + 0xf5cb_7b8b_d922_a290, + 0x263b_8dc0_3ac7_d253, + ]), + F::from_raw([ + 0x7e5e_1c19_38a2_c28f, + 0x9ddf_c527_a696_786b, + 0x30b9_4c89_7ce7_016c, + 0x07c5_9c31_f979_dba9, + ]), + F::from_raw([ + 0x31bf_1a4e_63af_2150, + 0x17bd_7574_e071_c7bb, + 0x6b54_e751_dd5a_4bf9, + 0x009f_47f0_21fa_65de, + ]), + F::from_raw([ + 0x8e7a_9813_f741_ddee, + 0x969f_2731_383e_524c, + 0xce44_1d49_f280_4832, + 0x1c16_0043_dcff_2330, + ]), + F::from_raw([ + 0xde09_8587_35cb_837c, + 0x92cd_6c71_1dbe_66bf, + 0x9cb2_3f21_b32c_2690, + 0x0c5b_6896_687f_066b, + ]), + F::from_raw([ + 0xc785_0933_b9b7_0cf0, + 0xf0d5_0cf8_23f0_2804, + 0x72a7_ec44_2e66_84c8, + 0x23ac_bd7f_928b_be5b, + ]), + F::from_raw([ + 0x0ead_4caf_c21d_7ddf, + 0x05e5_189a_65df_9ac4, + 0x7829_4138_47ca_8571, + 0x0e8a_e8a1_d114_1dc0, + ]), + F::from_raw([ + 0x3680_54da_7795_e302, + 0x6a0b_c7a5_abd5_71f3, + 0x07ab_296a_0224_fda3, + 0x2eca_0989_f9ab_916d, + ]), + F::from_raw([ + 0xec15_d122_37cd_8f24, + 0x8b7b_4cf3_7629_6771, + 0x8fe0_6b7b_0fe8_3ea8, + 0x2c76_ceb7_d040_b4e5, + ]), + F::from_raw([ + 0xab7e_0060_ee1e_3044, + 0x9335_cec4_194b_105a, + 0x73d1_4ab7_db8e_a41b, + 0x0c53_afd1_b381_167d, + ]), + F::from_raw([ + 0x74cd_6c6b_1455_5322, + 0xb3a1_6736_02e9_70f1, + 0xe58c_c15b_fdce_2392, + 0x0c36_6295_62a7_dc67, + ]), + F::from_raw([ + 0x8aa4_ecf2_6f4c_9bd1, + 0xf88c_b7a7_1b14_df9d, + 0x8f74_0002_75db_8525, + 0x052d_66b6_1425_3ade, + ]), + F::from_raw([ + 0x3db4_1450_9f60_8f9c, + 0x75f8_37ee_5dec_2796, + 0xd832_0fd0_ebf9_fc52, + 0x0de6_ba14_0904_6058, + ]), + F::from_raw([ + 0x99fc_00a2_57bc_1b4a, + 0x8856_8b7f_8bdb_c4b3, + 0x87e8_8c2f_a3a1_6f63, + 0x109a_e052_4afc_2b11, + ]), + F::from_raw([ + 0xdc17_da40_b904_5053, + 0x3e13_fe23_7ce8_6ede, + 0xca49_bec2_9ffc_b5da, + 0x0b13_e5f2_c901_b454, + ]), + ], + [ + F::from_raw([ + 0x85f1_7282_09ec_059b, + 0x4582_9ef6_e4e7_a4ab, + 0x3b55_3e95_c68b_bb3b, + 0x0c9a_986a_f2ad_5848, + ]), + F::from_raw([ + 0xea6d_c319_a073_5cca, + 0x4124_9eb0_b000_8264, + 0x2108_90e7_41a1_4ffe, + 0x0093_a4e1_fc46_b86a, + ]), + F::from_raw([ + 0x3015_ed1b_a712_657a, + 0xcdf8_f5c8_1227_637b, + 0x3754_9923_dfb7_e35f, + 0x01be_a7e5_2a3a_ca29, + ]), + F::from_raw([ + 0xcd3a_36c6_308f_d596, + 0xbc9a_ab63_47f0_bf97, + 0x9542_fbc2_3832_e749, + 0x11e8_8dc0_b590_0bd2, + ]), + F::from_raw([ + 0x1033_855c_eba4_302d, + 0x91f0_f58e_c195_200f, + 0x97f2_1f21_2e76_3664, + 0x1387_41f5_ecbf_3959, + ]), + F::from_raw([ + 0xa1e0_f1b9_5dd3_66d1, + 0x30e4_19df_4fbb_4d68, + 0x240b_4713_db8d_27e1, + 0x2447_012a_9469_27a4, + ]), + F::from_raw([ + 0x67be_9830_a2f6_74d9, + 0x9e5d_cace_04b9_768e, + 0xb903_9453_71e5_341b, + 0x0276_193a_782f_6de5, + ]), + F::from_raw([ + 0x1c49_fb88_0ded_7bca, + 0x8886_77c9_85d3_ef1f, + 0xc064_f6c4_7d51_7b13, + 0x0df9_bd68_c4fc_32c8, + ]), + F::from_raw([ + 0xe2a5_5305_c2b0_f8c1, + 0x1cab_647a_8901_957e, + 0xcba4_f4c0_def5_0fce, + 0x2909_1c18_6139_63c6, + ]), + F::from_raw([ + 0x4128_3f2f_e825_c959, + 0xb41f_d67a_5416_de36, + 0xfed4_7ee6_07e2_5f21, + 0x0b78_f8ec_c657_7966, + ]), + F::from_raw([ + 0x4eea_4159_c62b_6b3a, + 0x0c80_36be_1769_c534, + 0x11b0_17f8_7e90_0fd7, + 0x2e8f_059c_9b78_f624, + ]), + F::from_raw([ + 0x38ad_7d30_9d1b_6732, + 0xac28_7ba3_51f2_5217, + 0x029c_b701_8f65_7b52, + 0x03e3_4c28_76a8_3413, + ]), + F::from_raw([ + 0x62db_308c_e86f_6b2c, + 0xd6b5_2c5f_05a1_ec42, + 0xcf01_b505_c1a4_7fcd, + 0x13a1_f660_a875_57ce, + ]), + F::from_raw([ + 0x48f3_2456_87f1_4d35, + 0x520a_8e93_e7ed_551b, + 0x0b6b_7861_02ca_d914, + 0x010e_9a59_96f8_e339, + ]), + F::from_raw([ + 0x24b3_8d20_8ff4_8c4d, + 0xd850_7604_1b07_c3e2, + 0xd9d5_4f04_3327_9044, + 0x0bdb_ee98_46a8_d67c, + ]), + F::from_raw([ + 0x419a_661c_782c_1f8a, + 0x17d5_86d1_6d5e_eeb7, + 0xd6fb_861e_16ca_28d1, + 0x2381_dfdd_9bc3_37d5, + ]), + ], + [ + F::from_raw([ + 0x5851_1f1f_a484_fcc6, + 0x91e1_c378_1f8a_9c4f, + 0xf0f1_ded0_ef19_2046, + 0x0b85_6bd8_fdd6_ebb7, + ]), + F::from_raw([ + 0x2cfc_18c9_1317_8b70, + 0x10b1_696b_8151_9b0a, + 0x13ca_a8a3_fef0_b2fc, + 0x16ec_1595_9be8_3575, + ]), + F::from_raw([ + 0x0a21_5b16_5948_6e31, + 0x4146_d548_cdfd_42e4, + 0x4265_9121_156a_773f, + 0x1943_d70c_0ec1_3c91, + ]), + F::from_raw([ + 0xccaf_1e31_1af2_edb2, + 0x1eff_acb1_501b_8582, + 0xfbc2_cb4f_98e2_c2a0, + 0x29e5_268a_c796_d26e, + ]), + F::from_raw([ + 0x66f3_da8a_8978_e4fe, + 0x4ea1_b7dc_ffff_94c8, + 0x6269_37f7_5af2_2f74, + 0x0fd7_2d28_e75b_e53d, + ]), + F::from_raw([ + 0x902a_c70c_cc0c_e370, + 0x7062_fcd6_c75d_afce, + 0xc45b_fecb_1f11_2a5f, + 0x19ce_9f98_a369_869e, + ]), + F::from_raw([ + 0x1b01_dbd3_bd5e_91ff, + 0x64d2_11d3_a97c_702c, + 0x70bc_9ce6_7043_8eea, + 0x08a4_d149_a8a2_7a21, + ]), + F::from_raw([ + 0x7160_02f3_a698_3910, + 0xf1ab_aa13_f5a0_68cb, + 0x4de7_ebf9_8d59_fc9a, + 0x1915_0be3_8fa5_e5fe, + ]), + F::from_raw([ + 0xab80_8374_d8da_f697, + 0xb15e_e7bf_31ff_7374, + 0xf1c0_c23e_e7aa_f5d8, + 0x23c4_5261_1014_40de, + ]), + F::from_raw([ + 0x8964_14cb_5a0c_b126, + 0xebaf_2df5_3e4e_905e, + 0x8fea_b653_e9a4_6aac, + 0x204a_9542_c690_fe33, + ]), + F::from_raw([ + 0x1a45_8124_723a_df10, + 0xfacd_0e9c_46f4_65c5, + 0xc21b_2191_3ce5_2665, + 0x128e_fd4c_6254_cd03, + ]), + F::from_raw([ + 0xcb0e_758a_ae5e_ce7f, + 0x71b1_815a_faaf_6218, + 0x42c9_528e_4b92_76d8, + 0x305b_ecd1_cba0_7fb7, + ]), + F::from_raw([ + 0x9f3a_4e32_0bfa_c6a0, + 0xfee9_a391_a537_2ad1, + 0x46fb_9130_1af3_2682, + 0x0bb1_4b69_696f_fb4a, + ]), + F::from_raw([ + 0x54bf_183f_c3ae_de0a, + 0xf256_e7e6_86a6_0cb7, + 0x9c6f_ed80_79fe_44a2, + 0x2f98_1d8e_ec99_50e3, + ]), + F::from_raw([ + 0x57d2_969f_7836_9337, + 0xeb3d_0b28_e48d_df8b, + 0xed98_2c48_3a2a_7951, + 0x2e38_c6f6_a748_9a54, + ]), + F::from_raw([ + 0x0ddb_51c1_3ee5_83cd, + 0xe72b_8b72_e1c1_bb6f, + 0xce1b_eba3_9a67_cbad, + 0x1bd7_086e_b715_0c0d, + ]), + ], + [ + F::from_raw([ + 0x76d1_527b_2315_b461, + 0x1872_0311_96a4_3ffe, + 0x71e6_b62f_b698_e8af, + 0x1c8b_437f_2be3_e616, + ]), + F::from_raw([ + 0x65cc_ae60_3156_6fc1, + 0x4c96_6943_1f10_243a, + 0x3e16_35e8_eecd_50ba, + 0x2b91_c7a7_8289_a7c4, + ]), + F::from_raw([ + 0xc110_ee74_7137_0f83, + 0x7b73_8f9c_dbff_5d15, + 0x451c_4561_ca77_ba70, + 0x0bdf_989e_7ddd_d8d9, + ]), + F::from_raw([ + 0x16a4_d2b4_30bb_d479, + 0xafe8_5a45_e749_12d6, + 0x6cff_1a4d_86ca_1f19, + 0x0ad1_a321_7e86_645a, + ]), + F::from_raw([ + 0xc78d_4ace_ad07_aa08, + 0xb592_5342_f08f_944a, + 0x6857_8044_8f2f_8c55, + 0x256f_f8d3_f524_e4ea, + ]), + F::from_raw([ + 0x460c_11eb_fb1b_6b01, + 0x2168_3d20_ae56_1c6d, + 0x5820_7d3c_eda7_b2e1, + 0x209d_7ab2_97f5_a312, + ]), + F::from_raw([ + 0xd669_b55c_e5b8_bf52, + 0xfc86_d3ec_4112_16e3, + 0xff60_0244_1b98_ea52, + 0x09af_ce8a_c2c2_cf3a, + ]), + F::from_raw([ + 0x89e6_a347_1222_c934, + 0x33ed_9c26_dcff_3b2c, + 0x5099_f010_4815_897e, + 0x29f8_2b1e_c02e_68c2, + ]), + F::from_raw([ + 0x00ce_ef89_ed02_1dd2, + 0x2800_2119_7bdb_71f8, + 0x6132_2f7a_dc22_1ada, + 0x03cd_f7f8_fb01_5f68, + ]), + F::from_raw([ + 0x636d_f044_d8cb_0b61, + 0x2270_33dd_0215_3365, + 0x24d8_5f2a_7538_0469, + 0x27eb_263d_bf7c_eac8, + ]), + F::from_raw([ + 0x2f98_ae76_a9d5_5984, + 0x2210_1ae4_a043_d33b, + 0x9a9e_3ccb_fc5b_d087, + 0x1628_cf08_4280_bc14, + ]), + F::from_raw([ + 0x8955_209f_1b61_ab93, + 0xb8e9_c4da_d7b0_4c4a, + 0x6a44_fdd5_6186_17dc, + 0x2b16_8bfb_1e6c_4ced, + ]), + F::from_raw([ + 0xaf8a_463b_a18c_85ff, + 0x7785_4905_7aeb_7a7d, + 0x236a_6a8c_cb3f_1720, + 0x057d_e070_94dc_a307, + ]), + F::from_raw([ + 0xfd79_f100_ac8c_a101, + 0xbe5e_7f7d_6c1a_6103, + 0x8603_c60e_8b54_5313, + 0x0fb0_7965_0d5e_e3f7, + ]), + F::from_raw([ + 0x2cab_aeb2_72fb_06bd, + 0x336e_7b40_2659_149b, + 0x3732_0b91_d329_5c8e, + 0x18d9_76ed_9d44_fb74, + ]), + F::from_raw([ + 0x327c_aa22_e93f_f45f, + 0xbd02_0abf_ccb4_32ee, + 0x7c4c_7f3a_d1e2_cc81, + 0x1edf_bbef_1801_42c4, + ]), + ], + [ + F::from_raw([ + 0xf672_aeb7_da1f_925a, + 0x5f03_97bb_8c85_505a, + 0x290a_2ad3_b451_9c81, + 0x2510_fbda_0c1b_8256, + ]), + F::from_raw([ + 0x0090_4fc0_60cf_0424, + 0x3613_8dc4_0625_5b92, + 0x364d_0e46_defa_666d, + 0x1478_3ce9_bd49_860f, + ]), + F::from_raw([ + 0xf63a_ce31_e3b5_6857, + 0x331b_fe37_7db3_3e66, + 0x778f_e653_6974_4816, + 0x100e_0047_7369_c0c6, + ]), + F::from_raw([ + 0xc3d7_f2ee_2e0c_45c3, + 0xbde9_96b7_2f9c_b00c, + 0x0439_ddfb_7e2f_8774, + 0x1aea_93b5_1726_a8d7, + ]), + F::from_raw([ + 0x0e80_df7e_6f76_cb49, + 0x3a55_1b88_9694_dfd3, + 0x7721_3161_4012_2976, + 0x0b14_c0df_6b22_22d9, + ]), + F::from_raw([ + 0x2729_c60e_ecac_354d, + 0x73fb_1a64_c395_1b67, + 0xb1ef_9c82_74ba_8eab, + 0x0a64_3ba7_2531_a192, + ]), + F::from_raw([ + 0x9a8c_b283_9f39_6b02, + 0xcc63_5ced_8c84_21ef, + 0x979b_13a1_6b87_a12b, + 0x0c36_a12c_83a4_45a6, + ]), + F::from_raw([ + 0x0e50_a951_897d_5d39, + 0xbec1_c438_98e2_22fd, + 0xd3a3_c2e8_7f72_9c5e, + 0x25cb_792a_cf14_7080, + ]), + F::from_raw([ + 0xb277_b588_5b09_bf99, + 0xef64_31de_ac35_046f, + 0x86db_fa2c_2c83_579f, + 0x1e10_64f6_5448_3554, + ]), + F::from_raw([ + 0x9506_76ed_20f8_7854, + 0x3b26_1d7e_d7b9_13e2, + 0x3799_80c1_834a_3b2f, + 0x2644_0ee4_fc4c_477d, + ]), + F::from_raw([ + 0xd4c9_b2ab_843a_afc0, + 0xbfc4_495d_d512_5247, + 0x681b_43a6_ea7b_482c, + 0x300a_cf3e_9a90_1b9c, + ]), + F::from_raw([ + 0x5ca7_a170_1c38_49cb, + 0xb004_de15_2c64_7194, + 0x5d9a_5306_96c5_2693, + 0x0d27_833d_a8ad_cc21, + ]), + F::from_raw([ + 0x159a_528c_f886_aae6, + 0xc16a_6098_572e_f58d, + 0x33f8_5346_2a29_5e0c, + 0x1c4e_8f60_24bb_7963, + ]), + F::from_raw([ + 0x3c9d_5841_2b1a_5939, + 0xdf1c_f79d_c9f2_4d2f, + 0xee5d_77ac_780d_ceaa, + 0x0db3_8e10_7121_8ef0, + ]), + F::from_raw([ + 0x3906_da7a_77f8_bc22, + 0xdd7f_e591_a4ae_e3ae, + 0xddd6_efc4_69f4_dd9d, + 0x0f8a_423d_040a_ef0e, + ]), + F::from_raw([ + 0x2966_756f_ad85_90c1, + 0x59dd_362f_796a_6914, + 0x94e3_b2e7_a2e2_55f0, + 0x09da_570d_55e2_f64c, + ]), + ], + [ + F::from_raw([ + 0x3c52_0d78_af40_057e, + 0xdbc2_c09b_25f0_78b2, + 0x1a59_e444_8c67_c7ad, + 0x0d7c_d5c2_65cf_b5b0, + ]), + F::from_raw([ + 0x0b26_1fa4_0b95_df69, + 0x3a74_5c13_51c7_d123, + 0x15ac_68bd_b464_ae19, + 0x2c9c_47bc_4c33_2aac, + ]), + F::from_raw([ + 0x2975_9393_a178_9c8a, + 0x01ec_75e7_6adf_a145, + 0xa7b9_4e0b_9115_3591, + 0x1ab1_35f3_c81f_c395, + ]), + F::from_raw([ + 0x907e_c782_d3df_af9c, + 0x6828_4acf_1214_3d85, + 0x3a12_b7c8_e41d_1fd9, + 0x3052_1d40_82f5_8b8f, + ]), + F::from_raw([ + 0x4569_8a11_f5ed_996d, + 0x82b7_6cd3_fa2f_3301, + 0xb7f8_f26c_7bd0_68dd, + 0x1b90_1022_1027_9a42, + ]), + F::from_raw([ + 0x0b89_5131_0339_8096, + 0xd4f0_b265_e4a8_e1c7, + 0x6cdb_c624_b320_8030, + 0x2e9a_c434_1790_2982, + ]), + F::from_raw([ + 0x41fb_483c_df8e_ee37, + 0x96e7_00ad_9783_b23f, + 0x1854_96e3_fc7c_3699, + 0x2784_c3d7_1d12_5586, + ]), + F::from_raw([ + 0x1dd5_e326_91e6_2ba8, + 0x8ed1_b1bc_3f06_acdd, + 0x4da2_ab05_c3b7_6226, + 0x0253_0542_8921_f6e3, + ]), + F::from_raw([ + 0xc254_3dc0_ac99_daa9, + 0x9a6d_0a4c_867f_ed2c, + 0xb582_8b5b_5a23_716f, + 0x1d30_06e6_c572_5e17, + ]), + F::from_raw([ + 0x6473_9988_a3a6_f0bc, + 0xb8f9_af07_1ff2_6025, + 0x2fe6_682b_f6ac_8bb5, + 0x1687_6732_3e50_97bb, + ]), + F::from_raw([ + 0x5d8a_f551_421e_1bd7, + 0xb797_d0ad_3589_89a1, + 0x500f_5268_dc31_9e00, + 0x0a5d_80b2_00e7_ee00, + ]), + F::from_raw([ + 0xb655_0f72_4d7b_8282, + 0xaae6_dcfd_0e90_508c, + 0x861f_9982_f522_b0c3, + 0x25db_b542_3ee2_a7d7, + ]), + F::from_raw([ + 0xc9f4_c5c3_362a_b026, + 0x1d1e_f182_6441_5d4f, + 0x000a_cf7e_e101_175d, + 0x25e1_b972_aa75_76ff, + ]), + F::from_raw([ + 0xad25_5231_b985_00ff, + 0x0fe3_cdb7_64e2_ef99, + 0x87b8_b606_a5c2_31ae, + 0x27a9_c670_e696_ec52, + ]), + F::from_raw([ + 0x0d11_2ca2_eb7b_df05, + 0x1143_16d8_71a7_a2b9, + 0xbb35_8fa4_15ce_13ce, + 0x260d_6606_a1db_4854, + ]), + F::from_raw([ + 0x6542_08ee_cecb_28f9, + 0x3173_0c74_5a7d_389e, + 0xad37_98bb_ce56_7eb6, + 0x2397_a374_f84a_29a5, + ]), + ], + [ + F::from_raw([ + 0x89dd_93b3_a91f_1f2e, + 0x2126_e64e_2796_ffba, + 0x020f_88f6_a48f_a407, + 0x11ee_1c61_6304_dccf, + ]), + F::from_raw([ + 0x2bf0_ae18_67ef_9215, + 0x2ee9_8781_a8c2_944d, + 0xb5a7_7d3b_5f37_7a25, + 0x055a_e011_520b_4ec5, + ]), + F::from_raw([ + 0x01c5_0cfa_2fb8_ed4b, + 0xcbe1_8e9a_9c3b_a1ac, + 0x581a_f879_d136_d587, + 0x1700_7f74_a2fe_2b85, + ]), + F::from_raw([ + 0x948b_15fa_1304_ec1a, + 0x6a85_fcf0_f15e_380f, + 0x0329_7fec_fc88_f4d0, + 0x214a_c964_b34b_210e, + ]), + F::from_raw([ + 0x75c4_7c2e_2d57_4042, + 0xda53_cc27_28a7_96c3, + 0xa480_b444_285f_dd1c, + 0x1c21_46ea_153d_e11f, + ]), + F::from_raw([ + 0xa922_59b3_c158_076b, + 0xdd79_8762_c18f_06bd, + 0x8ff6_340d_ee9e_c828, + 0x0ca0_af02_4d98_3aea, + ]), + F::from_raw([ + 0xae1a_b86c_055c_a6e8, + 0xaf18_0c6d_4b5d_98c5, + 0xa657_3554_8988_e6e0, + 0x012f_82ce_9da7_6870, + ]), + F::from_raw([ + 0x2a7b_97ca_0d44_cf6c, + 0x78f1_3e53_5f7e_ca2a, + 0xe925_26e3_9d37_63fa, + 0x255f_614a_333b_1375, + ]), + F::from_raw([ + 0x7ed3_d3de_082e_7b92, + 0xc89e_4df6_081c_049b, + 0xffa7_aaee_c444_29ff, + 0x0d03_54ad_322f_5e1d, + ]), + F::from_raw([ + 0x1311_b5da_fc27_eba0, + 0x9280_eda0_326d_5a19, + 0xfaff_69cf_331a_848e, + 0x039f_496e_8bf7_6be9, + ]), + F::from_raw([ + 0xdb09_25ff_03cf_5794, + 0xa129_517f_a698_941f, + 0xa090_3ccb_d518_edc5, + 0x1b0b_0e8d_d862_523d, + ]), + F::from_raw([ + 0x3afe_6eaa_cf2e_b6b0, + 0x7ceb_937e_e692_fbec, + 0x87b9_1fd4_1c76_54d3, + 0x221b_67c9_b923_2773, + ]), + F::from_raw([ + 0x6860_8f65_bec5_1157, + 0xad14_80f8_b3f0_20e4, + 0x9c1d_cdaa_6de2_9ab9, + 0x1252_49ba_3c9a_c4c5, + ]), + F::from_raw([ + 0x3b85_3818_11d1_e730, + 0x807e_3414_b407_7b53, + 0xc4ae_35d9_e353_60d7, + 0x0264_e939_0b7b_2787, + ]), + F::from_raw([ + 0xf7b1_8e09_d19b_752d, + 0xe70c_1770_6e32_688c, + 0xac40_ac89_c5ff_2347, + 0x1a8d_fa17_839a_f5cd, + ]), + F::from_raw([ + 0x1bca_058f_802e_1da5, + 0xf7bb_0378_ce46_226c, + 0xe9c1_86eb_710c_2b3c, + 0x02dd_b274_e22f_13d1, + ]), + ], + [ + F::from_raw([ + 0xfb52_64c3_40f9_45ce, + 0xaa32_36dc_72dc_772f, + 0xd856_6bbc_aaf6_3b0a, + 0x1ed9_1d70_a1e0_e229, + ]), + F::from_raw([ + 0x683f_2113_1c52_05ba, + 0x2f88_6164_0906_580d, + 0xd62b_1fc9_bedc_cae0, + 0x258d_9714_748c_a3ba, + ]), + F::from_raw([ + 0xaef5_7849_297a_f20b, + 0x3e70_f633_8fd5_98ed, + 0x7073_de7a_1261_bf0f, + 0x2809_4fb0_c9ce_3fa3, + ]), + F::from_raw([ + 0xfdf6_9475_603e_4779, + 0x0b2b_d9b2_7d8a_731d, + 0xd8d6_0f48_3092_8fd1, + 0x01b2_6824_5960_a242, + ]), + F::from_raw([ + 0xbe73_330a_d18b_dd6a, + 0xab3a_3f2f_6497_f939, + 0x1861_8873_ace0_bbf4, + 0x1ccd_c2c4_8249_4968, + ]), + F::from_raw([ + 0xb14f_81ed_72c7_1f6b, + 0x682d_7fd6_ba71_0e8f, + 0x887f_51ec_5639_a447, + 0x10d7_b6fd_7c71_bab6, + ]), + F::from_raw([ + 0x0c6d_b5ee_3b12_5757, + 0xcc32_7c8a_3e4b_a600, + 0x7dac_c928_f8bd_5234, + 0x14a1_36a1_e482_7d70, + ]), + F::from_raw([ + 0x639b_14d7_7cc2_5858, + 0xc328_9c9b_bf2b_6d5e, + 0xb11c_6180_db57_f479, + 0x2991_2088_42fe_b5c9, + ]), + F::from_raw([ + 0xb518_1c66_eab3_485e, + 0x2f1e_fd1e_3571_7c91, + 0x0d51_cc2d_6eed_ca09, + 0x0864_276f_06cf_5050, + ]), + F::from_raw([ + 0x8437_c903_63a5_cd18, + 0x2f3d_e504_caec_08f1, + 0x42d5_12b0_3bc2_962d, + 0x01da_1115_c035_901d, + ]), + F::from_raw([ + 0xf996_3b5a_8a29_7613, + 0x7fdd_1d00_213f_2deb, + 0x66ed_d2dd_df68_3b40, + 0x0ce4_c615_22cf_118b, + ]), + F::from_raw([ + 0xe4b3_ebf4_f94c_0138, + 0x979d_a22e_b522_bb3e, + 0xdd11_1018_ad3a_4818, + 0x2282_2be1_4736_c770, + ]), + F::from_raw([ + 0xceee_194c_13f3_a44f, + 0x1ced_4900_0d09_ef6c, + 0x80e8_26af_298a_f3b8, + 0x0248_8c2e_f3ce_cdf9, + ]), + F::from_raw([ + 0x4fa2_a4d7_ff5b_5ebd, + 0x05ea_72c2_1441_ddb1, + 0x2e98_9fd0_633e_3528, + 0x22b3_bd43_bd13_0c0e, + ]), + F::from_raw([ + 0x62d9_fc05_4c59_2acf, + 0x5f4b_02b9_ae18_2eb2, + 0xcd8e_4632_e92d_28e5, + 0x0ffe_a11d_900b_5c13, + ]), + F::from_raw([ + 0x0042_94d9_e376_721e, + 0x815c_c53e_1ebb_fd39, + 0xfe80_adbb_43ba_56e4, + 0x14ac_dc06_5935_230e, + ]), + ], + [ + F::from_raw([ + 0x60a0_d4a9_5a03_c6a1, + 0xcd1e_3ada_c0d0_a324, + 0x6fae_a51f_c1ad_ec10, + 0x15fc_1e7c_b819_924b, + ]), + F::from_raw([ + 0x7739_b4c7_6762_2c51, + 0x3c9c_8f41_e1c4_fbcd, + 0x0035_790e_e7f3_6ab7, + 0x0547_d191_2834_376f, + ]), + F::from_raw([ + 0x2b31_1457_3789_8099, + 0x4e52_ae25_5e2a_69e2, + 0xb9cd_b5ce_ba5a_cb9a, + 0x135f_9f4c_16f9_7545, + ]), + F::from_raw([ + 0x6c28_f0ed_b334_5e83, + 0xdc9f_ed82_6c40_60aa, + 0xc564_f0c3_8c66_20ed, + 0x08ce_4af4_0d7d_e598, + ]), + F::from_raw([ + 0x08ab_4bad_29c1_61e7, + 0xcedb_9119_c477_4b5b, + 0xed9b_7287_2104_b340, + 0x21d6_a6d9_7125_9296, + ]), + F::from_raw([ + 0xa5ca_e999_5c6e_eeb4, + 0x5c8c_e1b4_d3a7_7c51, + 0x1f36_52aa_962d_4b04, + 0x2abc_622a_c35f_5024, + ]), + F::from_raw([ + 0xd5f3_2dec_dbc4_c82d, + 0xb216_2728_8953_6260, + 0x42f8_a456_2de1_061e, + 0x2545_b28d_54fd_cebe, + ]), + F::from_raw([ + 0xbb88_5bf7_fbb4_ade2, + 0xe1da_68f4_173a_4028, + 0x2afd_22d8_c9fd_8c22, + 0x2854_260e_63dc_45d2, + ]), + F::from_raw([ + 0xf491_cfe7_78e8_fb9c, + 0xa26d_6155_8a37_0609, + 0xc379_dce4_6d67_8537, + 0x095d_54e5_6898_7ae7, + ]), + F::from_raw([ + 0x6dc6_3157_057c_f8d2, + 0xf8c7_51cc_463b_9197, + 0x53a4_f633_e704_bb41, + 0x2ac0_3c44_0c8a_e0f7, + ]), + F::from_raw([ + 0x1a95_7736_7989_70be, + 0x18eb_42bf_9a4b_7d79, + 0xccef_d26e_a346_c306, + 0x0ce5_9770_0fa4_ef07, + ]), + F::from_raw([ + 0x8665_95cd_9503_b836, + 0xf78d_deef_9f8d_1ac0, + 0x3680_a29b_7268_e1ea, + 0x02c1_3a40_27f4_153b, + ]), + F::from_raw([ + 0x0da6_80ef_5aba_11c2, + 0x5eca_c4f7_8b77_f683, + 0xf38f_bbb1_73b5_b0eb, + 0x21a6_4383_9be3_51a4, + ]), + F::from_raw([ + 0xd187_7ab4_4ba3_5cca, + 0xcf3c_a016_b2ce_545c, + 0x113a_bd07_05fd_f242, + 0x053b_07c7_1cd8_64b2, + ]), + F::from_raw([ + 0xc7ed_de52_e1d4_ba39, + 0x51fc_6ad1_caa1_4755, + 0x3f20_c8b3_2fbe_daad, + 0x1889_c705_02e3_edfb, + ]), + F::from_raw([ + 0x51e0_5fec_7b8e_df61, + 0xf1bf_20d4_df6e_707d, + 0xce9e_1a79_887a_f71f, + 0x1686_6b66_4aa3_f628, + ]), + ], + [ + F::from_raw([ + 0xc7a5_7018_e7dc_7834, + 0x546d_4a3d_84d0_ff71, + 0x2204_12e1_c304_b812, + 0x0ab4_7c20_1ad3_15c7, + ]), + F::from_raw([ + 0xff3c_d22f_3a5d_db65, + 0x4a54_8600_2f75_81c9, + 0xc622_257c_eedb_3d2f, + 0x0577_bfc9_3b1a_b50e, + ]), + F::from_raw([ + 0xc297_e448_732d_6ccb, + 0x1a74_a0bb_7f73_0166, + 0x718e_5284_a448_5f24, + 0x0790_0aa3_52bf_959e, + ]), + F::from_raw([ + 0x3d1b_e955_4bab_45f9, + 0x07e6_5c1c_9650_2c69, + 0xde29_8ce9_e18d_3109, + 0x2635_df95_6b7d_f3f7, + ]), + F::from_raw([ + 0x72e5_fd21_c837_4306, + 0x172f_ad9a_2948_3b48, + 0x5adf_c872_6139_22aa, + 0x2e71_15f1_d6bb_75fd, + ]), + F::from_raw([ + 0x7a53_0b6c_859e_5728, + 0x77dc_a676_b461_8ac2, + 0x34db_eaf1_969d_5669, + 0x28e3_30b6_e413_acf3, + ]), + F::from_raw([ + 0x7276_66f9_36b0_e82e, + 0x1de5_52ce_b2cc_34ee, + 0xe130_ad99_1acb_e2c7, + 0x27e8_21c2_0528_6813, + ]), + F::from_raw([ + 0xf063_adac_c9c2_c38b, + 0x68a5_9e5d_9da2_1ae8, + 0x0f96_2ddf_78b2_c565, + 0x0822_2684_d801_5493, + ]), + F::from_raw([ + 0x2e25_dfc5_b4db_8fda, + 0x254f_cf9b_593a_bdb8, + 0x084d_bd74_3112_c05f, + 0x0ffb_7cc3_c05e_d4a3, + ]), + F::from_raw([ + 0x9662_eb9e_b915_d279, + 0x22f0_a4a3_f793_dc6c, + 0x12b0_34fd_8706_8fdc, + 0x0d6e_11d9_b51e_f8fa, + ]), + F::from_raw([ + 0x244c_cf64_80c6_960c, + 0x9f2c_10d9_af52_677d, + 0xd919_f398_1e5f_27a9, + 0x2c5d_6dde_18d2_8b08, + ]), + F::from_raw([ + 0x0b9a_22db_6ecb_c0f9, + 0x169a_4727_ed9e_1c14, + 0xc952_5501_28ef_ee21, + 0x1058_2dfc_5f53_99c4, + ]), + F::from_raw([ + 0xf7d8_ac84_a3de_f0bf, + 0x4c2e_6074_aba6_1d95, + 0x34d5_1900_6cae_7180, + 0x1c58_fda6_8ba7_4bd5, + ]), + F::from_raw([ + 0x1916_c9c5_c2b1_d8cc, + 0x8e95_34e8_d23a_8c2a, + 0x3dc4_6ddb_909f_f407, + 0x2710_44c8_d54e_1a64, + ]), + F::from_raw([ + 0x9c20_365c_d3f5_d335, + 0x14b8_5966_768c_e1b3, + 0xa140_d7f5_ecec_132b, + 0x186c_5e24_015f_b0b6, + ]), + F::from_raw([ + 0xc816_c5f6_9b13_65ad, + 0x6425_56af_8166_4859, + 0xa1d3_f0ea_a865_3e2a, + 0x1ef5_2812_43bd_23e1, + ]), + ], + [ + F::from_raw([ + 0x9698_85d3_7cfa_68b3, + 0xc80a_f154_cfa6_cf64, + 0x35a0_2725_89b5_c3b0, + 0x0e9a_f532_15e2_3649, + ]), + F::from_raw([ + 0x93f6_315c_62a0_2337, + 0xcf06_8882_7f6c_1d6d, + 0x4048_5a02_4f1c_f7c7, + 0x0c0a_5c9b_f118_a075, + ]), + F::from_raw([ + 0x8d5f_a0f1_4ccf_b4c6, + 0xf855_cb88_8ff5_5dca, + 0x9a2b_9f7d_940b_9301, + 0x0275_2ea3_cdf4_1016, + ]), + F::from_raw([ + 0x9f82_2475_289e_3d66, + 0xfdcd_8ff1_52dc_56dc, + 0xcd25_7eb7_9fc5_2785, + 0x1f48_4d4e_14af_3b11, + ]), + F::from_raw([ + 0xfd18_ce26_4f98_af14, + 0x9968_6bc0_7b1e_e828, + 0x034a_6b7e_836a_f6ba, + 0x18a4_2e21_ac35_ebf3, + ]), + F::from_raw([ + 0x4c02_7aaf_8792_2fa8, + 0xef1b_df24_c612_8a96, + 0x0800_167e_4d38_6431, + 0x17bc_4fcf_e167_ed74, + ]), + F::from_raw([ + 0x7531_6c20_4bb4_a3bc, + 0x9402_b6b5_0c9d_8447, + 0x5c63_7749_d9fe_90d8, + 0x2fc3_b7b4_10ac_ae01, + ]), + F::from_raw([ + 0xb841_a792_151e_8e18, + 0x998a_f3ee_48ff_b141, + 0x1186_ced8_876f_0c35, + 0x2305_0b36_6676_8fa9, + ]), + F::from_raw([ + 0x9711_e84d_7a69_6e7b, + 0x82fc_864a_87bf_5289, + 0x4789_9511_5900_3f68, + 0x091b_b332_b35d_6e46, + ]), + F::from_raw([ + 0x518d_6196_e3fb_1ad9, + 0x39b3_2c66_b51c_3e0e, + 0x612d_3f32_37b1_81d8, + 0x2ee7_bf6c_eadb_5749, + ]), + F::from_raw([ + 0x4c93_8916_803c_a018, + 0xa760_0253_c75f_28d1, + 0x8434_6cb5_c04b_a1c9, + 0x0e50_37b3_87cd_decb, + ]), + F::from_raw([ + 0x90ca_dd91_0ec7_397e, + 0x80b8_d81b_1450_0480, + 0xdbb6_9cdf_14cc_0830, + 0x1556_d870_d39b_b506, + ]), + F::from_raw([ + 0x40cf_aa83_30db_37eb, + 0x3468_6452_66ce_1236, + 0x65f9_3ad7_e28b_cab7, + 0x2199_4dd0_12c1_07a1, + ]), + F::from_raw([ + 0x4b9c_2326_0e28_144e, + 0xcdaa_76e6_d2bb_2c7a, + 0xd9bd_bc75_b6c8_8634, + 0x2da9_4256_d843_094d, + ]), + F::from_raw([ + 0x077d_7821_d9b5_37b1, + 0x47dd_a548_1fae_1dfd, + 0x808d_50a0_3956_b3e8, + 0x0be0_a92e_dc48_db09, + ]), + F::from_raw([ + 0xcef3_fa74_568b_662e, + 0x4f0b_b9e2_0163_8579, + 0xdd31_6307_189d_93e1, + 0x1d33_2c7d_075c_c815, + ]), + ], + [ + F::from_raw([ + 0x4c2b_a40e_136b_a98c, + 0x7b48_e5c1_a48a_65f0, + 0xe047_e330_b99e_b900, + 0x15a8_d58d_d7b4_43b1, + ]), + F::from_raw([ + 0xa321_ea37_907c_7942, + 0x0375_faf5_cee7_8716, + 0x2d3c_fe67_bb7d_2fc2, + 0x15f0_ba26_2ebc_5d72, + ]), + F::from_raw([ + 0xeae9_1934_fb36_f1ea, + 0xac12_b9d7_8c64_0336, + 0x5efa_9458_687c_d92c, + 0x2cfb_417b_5ebb_b001, + ]), + F::from_raw([ + 0x830a_8ff4_395b_9dca, + 0xecdd_d7e7_c3c5_459d, + 0x3774_1c8c_b532_728d, + 0x0d33_1b32_2888_5327, + ]), + F::from_raw([ + 0x509b_9b04_d702_3d5e, + 0x1198_0e3f_5197_e53c, + 0x9000_2d9b_bacc_7fc0, + 0x188a_4855_919f_14b7, + ]), + F::from_raw([ + 0x0092_0a66_d243_ea9f, + 0x6123_d343_f4bb_f02d, + 0x3f97_8607_c188_fb90, + 0x08ce_e96a_66c1_ed7e, + ]), + F::from_raw([ + 0xa611_426f_1a82_d558, + 0xe78e_cf25_d029_bf4b, + 0xa5db_37ab_fb71_7521, + 0x20b6_1c43_e264_decc, + ]), + F::from_raw([ + 0x3870_450c_22c1_cd02, + 0xd345_2804_196e_e87a, + 0x74ce_d836_9d56_11aa, + 0x1b70_bea2_73a4_0aaa, + ]), + F::from_raw([ + 0x136a_94f7_5a1a_7796, + 0x7ac6_dc82_a335_4d6e, + 0x54ef_ab01_5050_a01b, + 0x24c2_34bd_6c73_e172, + ]), + F::from_raw([ + 0x4e3c_a2b8_07a7_7047, + 0x4f8f_ce88_f64f_5f49, + 0xb107_0ca3_9d55_3ec7, + 0x2a21_a559_4707_eef1, + ]), + F::from_raw([ + 0x4ee4_cc69_0717_5f35, + 0x7fd0_e338_313e_3bde, + 0x1b3c_6dbc_1681_386b, + 0x09cd_cfd5_0395_8b90, + ]), + F::from_raw([ + 0x719e_a82f_b5d1_5563, + 0xc38b_1e33_deff_6a0e, + 0x9836_0612_5320_f73e, + 0x0372_13fd_6b9a_df8b, + ]), + F::from_raw([ + 0xae02_2472_5d6d_5d85, + 0x21dc_db1d_a137_4cc2, + 0x2ec7_58e8_3ec5_76f5, + 0x2be5_b55d_83cc_6fb3, + ]), + F::from_raw([ + 0x509d_bfa1_8858_9300, + 0x43d5_e204_bae3_ab38, + 0x10fd_0088_fd06_054e, + 0x1f9b_9850_a392_f6da, + ]), + F::from_raw([ + 0xfe47_54c0_3ca1_caa3, + 0x3ba9_1a12_ed80_e30a, + 0x73e1_a103_9b2a_b253, + 0x0968_a47a_748d_b23b, + ]), + F::from_raw([ + 0xd839_57ab_f6a3_dd15, + 0x2bfe_450a_124e_267d, + 0x8ef9_d81a_fed0_c861, + 0x1a62_4785_eae4_83bd, + ]), + ], + [ + F::from_raw([ + 0x46eb_5489_62bf_1586, + 0x69d9_cb5e_d095_2cd4, + 0xeeb1_298b_c198_76d9, + 0x25ac_240c_7126_a642, + ]), + F::from_raw([ + 0x7ea8_9be4_3ec1_67f5, + 0x17db_bb8c_b47c_1e84, + 0x383b_f455_3bc9_282c, + 0x2715_1bce_d14b_6f53, + ]), + F::from_raw([ + 0x0548_a1fd_905f_df49, + 0x0caa_e162_e3fd_b06e, + 0x272f_8f2f_11fc_a0c0, + 0x01ec_e2be_c2de_7891, + ]), + F::from_raw([ + 0x59ea_11d7_d737_4c43, + 0x4934_5e99_d695_6a66, + 0x93cf_1d0c_05a1_0d18, + 0x27e8_56df_227c_ff7d, + ]), + F::from_raw([ + 0x4e99_157b_62b8_c467, + 0x1588_4127_d62b_a02b, + 0xdf09_0347_74a8_36e3, + 0x1ba8_591a_f1c5_8a45, + ]), + F::from_raw([ + 0x5340_980d_a12e_532f, + 0x7c95_a431_928d_16b8, + 0xd308_181c_6596_dce7, + 0x2f11_fa94_02c5_853b, + ]), + F::from_raw([ + 0xce63_a2bf_8462_32ed, + 0x0892_cc17_cbf3_8ebf, + 0x18c8_e432_618f_abdd, + 0x19dc_cdf3_6783_961a, + ]), + F::from_raw([ + 0x757f_0876_8dd5_2d6d, + 0x2f01_83bf_f9fb_fd01, + 0x3b6a_9df1_a39a_c7d7, + 0x1350_eca5_a8cb_c2c5, + ]), + F::from_raw([ + 0xd5a0_46fe_7b25_1272, + 0x3578_564f_80a8_6702, + 0xdc66_2070_eb37_eb1c, + 0x2305_85af_7582_b6a4, + ]), + F::from_raw([ + 0xe2b5_3108_ef83_1183, + 0xbe01_9383_dc14_f99f, + 0x1e7b_b9ab_1a61_30cf, + 0x052a_71b5_daed_70d1, + ]), + F::from_raw([ + 0x7164_f2c5_74c3_d337, + 0xc88e_0491_0bea_0d83, + 0x7b8a_08a0_5bd1_de3d, + 0x0785_1ddc_73a2_c6f9, + ]), + F::from_raw([ + 0xf976_5fef_df46_0e8f, + 0x1095_e26b_3e6b_5e35, + 0xa996_cbc5_a831_ba00, + 0x0699_9528_7fee_f5bb, + ]), + F::from_raw([ + 0x2868_c7da_e84c_74ab, + 0xfa58_1ba2_def6_924e, + 0x7329_7aa4_bf15_6b07, + 0x0a69_2041_50bd_c7bc, + ]), + F::from_raw([ + 0xcd69_26ad_2628_5114, + 0xcb81_705e_267c_dc3b, + 0xeacd_f276_78b7_0436, + 0x20fd_9fbd_1536_a33d, + ]), + F::from_raw([ + 0xb241_b602_1364_eb40, + 0x9e62_282b_bb02_9f0c, + 0x78a9_21d8_e77d_a62f, + 0x2eb1_a2ea_f15d_b5d5, + ]), + F::from_raw([ + 0x01f2_f233_979d_5de5, + 0xe210_ad37_0348_36b4, + 0x5e69_b79f_d695_fd54, + 0x051f_55bc_0974_ccb7, + ]), + ], + [ + F::from_raw([ + 0x9f3c_8ab1_c25d_c3b9, + 0x7f1b_4318_a7dd_5d95, + 0xd00a_da2b_f963_03b1, + 0x0ea1_386d_77c0_f896, + ]), + F::from_raw([ + 0x7111_e0e0_148b_4c2f, + 0xf1db_91a1_cdbc_79f4, + 0x88e0_a639_a5f1_dd20, + 0x11e2_fce0_eb7e_64e4, + ]), + F::from_raw([ + 0xcb0e_1266_3eb9_de8b, + 0x8e92_9ab6_749a_17cb, + 0x4d1f_02a9_55a7_475f, + 0x2263_3874_fb5a_e477, + ]), + F::from_raw([ + 0xc8d8_465b_edd6_213f, + 0x528e_52b3_6a5c_d114, + 0x8c3b_b5f3_8f8e_7427, + 0x1ee2_613b_8ed5_faea, + ]), + F::from_raw([ + 0x1b07_e0b9_895a_cb23, + 0x9274_a713_1883_4b56, + 0x05ab_f42d_dde2_8312, + 0x1b3e_f253_5d75_9add, + ]), + F::from_raw([ + 0xbbd4_ed75_e478_bc35, + 0x3fbe_fe25_e650_77f1, + 0x07a3_0c5f_1651_b984, + 0x24a0_84ea_c600_612e, + ]), + F::from_raw([ + 0xa535_c386_e2e2_3fb0, + 0xf52c_9155_86b5_2be3, + 0x668e_8d6a_2831_d20b, + 0x049c_2e0e_7e17_7a16, + ]), + F::from_raw([ + 0xdd2c_4a93_615b_609c, + 0x62f8_0f04_bc7a_8f61, + 0x3a2d_bad1_ddd1_1f72, + 0x0769_d2b5_6d0d_4805, + ]), + F::from_raw([ + 0x609d_f0dd_8d0c_8279, + 0x3c4e_4daf_9d4b_6fc5, + 0x305f_b243_2c89_7ce8, + 0x1aa2_0a25_e452_6401, + ]), + F::from_raw([ + 0x3cfc_66f7_3776_32ae, + 0x125e_2ea6_1b21_2614, + 0x9a8f_57b3_6f6d_6bb2, + 0x2021_4d53_4469_f096, + ]), + F::from_raw([ + 0x94b8_c9b3_b909_5345, + 0xc712_e116_2b92_1c95, + 0xc72e_a94d_a35f_c305, + 0x02c2_5b9f_5db0_feef, + ]), + F::from_raw([ + 0xb91a_8798_6426_f3a2, + 0xb56b_efd0_a7ad_4d1c, + 0xb209_f082_64e1_f638, + 0x11d0_6d5c_d841_4889, + ]), + F::from_raw([ + 0xdf78_e52b_53a8_1813, + 0x5008_128e_9494_6e47, + 0x1f08_b73d_c281_48ef, + 0x0111_8c66_33ad_bbfa, + ]), + F::from_raw([ + 0xb29e_d581_59d3_c0bb, + 0xb604_2066_4da9_6477, + 0x0cfc_3447_d598_7790, + 0x10cb_d0a9_7124_3c10, + ]), + F::from_raw([ + 0xc173_401d_5a01_be7c, + 0xd406_8e7f_ef2f_8e47, + 0x2e64_b31e_0d84_fb39, + 0x2d7d_efa5_6218_b1d0, + ]), + F::from_raw([ + 0x5cb1_d90e_75a8_a935, + 0x0a93_0f45_38ab_235d, + 0xd096_4a66_03d4_4cb7, + 0x035b_fa1a_3f16_472a, + ]), + ], + [ + F::from_raw([ + 0x3fcb_ce0f_6340_fff1, + 0x2626_20cc_d838_892f, + 0xe7f3_7612_e637_f8a0, + 0x0a17_2329_742a_de46, + ]), + F::from_raw([ + 0x160c_ab89_96bd_747d, + 0xa9b6_00a0_5541_6858, + 0x42d1_9dd8_230a_0e10, + 0x2c58_c487_ea60_7692, + ]), + F::from_raw([ + 0x99e9_0138_9723_45d7, + 0x0429_294a_7bbf_5625, + 0x4cbc_e8a9_2176_fe0d, + 0x1075_3b36_168e_f481, + ]), + F::from_raw([ + 0x6348_7949_675a_b3c3, + 0xaf0b_2926_4229_7fd7, + 0x9f27_c615_1315_ddb0, + 0x05ca_b98d_fb32_70bc, + ]), + F::from_raw([ + 0x0348_5252_8b8c_c286, + 0x6c3c_21a1_e437_9c64, + 0x3068_b387_e78f_064b, + 0x244b_abd3_1403_6a35, + ]), + F::from_raw([ + 0x6518_c5dd_989b_4ef4, + 0x635a_fe80_fb15_43ff, + 0x5108_f928_975e_ea4f, + 0x189d_6ea1_9754_20c1, + ]), + F::from_raw([ + 0xda29_e5b9_3172_7e11, + 0x588c_9677_ea3b_4729, + 0xe013_b589_c306_629d, + 0x2834_b06e_2f31_e1c2, + ]), + F::from_raw([ + 0x43b2_95b7_edbc_050b, + 0xdfb7_a9b0_c58d_1c3c, + 0x208b_ee93_d6f7_2e79, + 0x2ea6_5573_cad7_061d, + ]), + F::from_raw([ + 0x507b_b244_e79f_3b64, + 0x80fb_b099_2bd0_0c0d, + 0x3319_c642_c939_fee3, + 0x2a8a_faf3_24dc_a28c, + ]), + F::from_raw([ + 0xc4b5_4ca7_14e8_cca5, + 0x70fd_8350_ecd8_93f4, + 0xc6ec_1339_a9eb_d061, + 0x2700_ca96_4456_2122, + ]), + F::from_raw([ + 0xc496_484e_527c_affd, + 0x5d0a_0e45_4246_6625, + 0x1693_51e5_ae53_82a6, + 0x088d_20ba_63d5_235d, + ]), + F::from_raw([ + 0xd61d_09ca_b543_651c, + 0xcbae_59cd_ea2d_f8c9, + 0x3221_d31c_2c9d_2af6, + 0x1e3b_2b69_2746_db2e, + ]), + F::from_raw([ + 0xd6ba_10b4_8f57_be7b, + 0x9340_9e17_c8a8_ba14, + 0xbbc6_eabd_67e3_1505, + 0x0320_140e_2c36_34e2, + ]), + F::from_raw([ + 0x049e_4d99_aa35_c63c, + 0xc0ca_d966_b89d_e9db, + 0xf6fa_958d_7d01_bb57, + 0x25fc_ceae_7afc_449c, + ]), + F::from_raw([ + 0x988f_85dd_7f61_659e, + 0x5760_672f_bbda_bcac, + 0x52da_3c40_aaa7_dc95, + 0x2d08_ac7c_3d1e_f442, + ]), + F::from_raw([ + 0x83de_d755_0128_8e21, + 0x17f7_7b40_3f42_3837, + 0x58c5_d67e_8f00_82a1, + 0x0772_3b7f_34c3_1a1d, + ]), + ], + [ + F::from_raw([ + 0x7565_f7fc_bed5_31dc, + 0xdf0a_99ad_9ae5_26bc, + 0x3b57_ebe7_bb4f_2c7f, + 0x08f9_3f11_a628_5882, + ]), + F::from_raw([ + 0xdc83_53f1_4f5f_e9ce, + 0x78ba_030c_c08a_31d4, + 0xb7cb_f186_072c_da34, + 0x2505_c089_66f4_18cb, + ]), + F::from_raw([ + 0xd4f4_9e60_3f33_c1e0, + 0xbcca_0a5f_aa48_ab37, + 0xa6c5_607e_cbeb_ac0f, + 0x2273_0c77_bace_ee5f, + ]), + F::from_raw([ + 0x8bbd_d83f_37b9_3ba7, + 0x45e3_3f05_9a6f_d8db, + 0x177e_d99c_a0e5_e28c, + 0x2866_da8f_65ce_f794, + ]), + F::from_raw([ + 0xe5ed_6969_14d2_794b, + 0xa213_aab1_df75_8cc0, + 0x9b81_8634_b401_8a00, + 0x2cbb_d169_f4a3_2d67, + ]), + F::from_raw([ + 0x1f66_feee_723b_adfc, + 0xbb58_f19c_0646_1853, + 0xa829_9188_6c6e_1841, + 0x152d_67da_16d2_4a00, + ]), + F::from_raw([ + 0x9a64_73cf_2b87_7b5b, + 0xa247_af07_493e_dff5, + 0x502f_6ddf_8fee_96e7, + 0x064e_bd9f_00d3_aa92, + ]), + F::from_raw([ + 0x9726_4457_be3a_920a, + 0x5ae1_d005_432e_9655, + 0x924e_c688_9b87_0e3a, + 0x17bf_7430_be0e_d0a5, + ]), + F::from_raw([ + 0xb649_74cd_1228_f26a, + 0x921b_6890_9a69_dedf, + 0x6a07_9273_c4b7_89b7, + 0x02d8_cd6c_4dab_fab4, + ]), + F::from_raw([ + 0x1d77_95fc_fafe_d0be, + 0x4546_4ec0_5242_217c, + 0x1670_0dd7_4086_0e14, + 0x0616_e7fc_0178_5aef, + ]), + F::from_raw([ + 0x2e7d_9306_1a31_f3c9, + 0x33ea_83fe_6b9a_be2c, + 0x1301_e0ca_3d42_a880, + 0x18d3_0927_7b33_ca48, + ]), + F::from_raw([ + 0x4550_6870_3198_4655, + 0x040d_cc15_f0af_a3e0, + 0x2cf3_c558_2cad_662b, + 0x0752_4811_ca35_7fc3, + ]), + F::from_raw([ + 0xbbe5_23b3_7394_1339, + 0xd7a1_4141_62d1_db45, + 0xf74f_d337_db8c_6e0f, + 0x1ec0_65e0_ec95_640e, + ]), + F::from_raw([ + 0xa371_12e9_c2b0_115d, + 0x42f8_cf20_24d6_e519, + 0x2180_e68c_6ac6_bd08, + 0x2471_7563_86b3_496c, + ]), + F::from_raw([ + 0xb3dc_c596_5302_bc70, + 0xb088_bce5_b17e_f437, + 0xab86_76da_c041_a3d2, + 0x15b1_6796_e573_ee84, + ]), + F::from_raw([ + 0x014f_0139_c02f_fa42, + 0xac98_acaa_a66d_5738, + 0xfd5a_ca4b_eaf9_6fcf, + 0x218e_6f09_1731_868a, + ]), + ], + [ + F::from_raw([ + 0x57db_4811_dc17_c808, + 0x7e45_aad6_4a7c_8dca, + 0x3fe9_71dc_f326_08a5, + 0x109f_ba9e_59cf_5520, + ]), + F::from_raw([ + 0x9df1_9051_cef9_b19e, + 0x12ec_2945_ca6a_51bc, + 0x166b_acb3_647b_f54f, + 0x125a_6c05_1a78_16c5, + ]), + F::from_raw([ + 0x7420_49e1_57d5_ee1a, + 0x4677_b2dd_8af7_4f4d, + 0xdcdc_30e3_eff2_ffd3, + 0x1b2e_6621_d945_8cd5, + ]), + F::from_raw([ + 0xdfd8_2a0e_9acc_72ca, + 0x6718_21a6_81cd_df68, + 0xc60a_1937_2b13_b8d1, + 0x0ee6_a186_4ab8_5f0c, + ]), + F::from_raw([ + 0xbca5_1e63_6c5d_d5a3, + 0xdaf2_127a_92c7_7bb3, + 0x55d4_a381_1ea4_ace1, + 0x2c5e_a8b8_d22c_f4ce, + ]), + F::from_raw([ + 0xe46e_ef91_a79b_2d81, + 0x02f2_6785_f701_a0f6, + 0x925e_09d2_f116_3a66, + 0x0476_9ebd_949f_424f, + ]), + F::from_raw([ + 0x5589_bd5a_9d56_64f9, + 0x8b91_1a23_9d86_b45c, + 0x27c3_5360_6e8e_bbd4, + 0x14ca_5631_f730_9cdd, + ]), + F::from_raw([ + 0x10d3_fdb9_1040_ecc5, + 0x8ca3_80cf_1761_5edd, + 0x01d4_5c2f_eba1_c8c1, + 0x1708_5e09_1ccb_55cb, + ]), + F::from_raw([ + 0x235c_d990_c3ec_82ab, + 0xba88_aaf0_1bbb_fab7, + 0x8431_9845_8a97_4bc7, + 0x2b58_062e_0609_7f47, + ]), + F::from_raw([ + 0xdd81_1c4d_d677_ee49, + 0x7263_9533_c18c_98b2, + 0x4b62_2e55_b5bf_45bc, + 0x05f1_9742_b6b9_cbf1, + ]), + F::from_raw([ + 0x20ef_f166_e68c_4589, + 0xc1f4_2972_af48_d648, + 0x8f5b_0775_bdce_cc6e, + 0x2af4_cba3_4b33_65d6, + ]), + F::from_raw([ + 0x5efd_ae39_2c33_4ea2, + 0x7916_52ba_f6d9_810a, + 0xdea0_0e9a_2b84_87dd, + 0x304e_f965_cfc0_cc4c, + ]), + F::from_raw([ + 0xe3a4_d694_34c2_ce4f, + 0xcf05_e0e9_9c40_c7ed, + 0xaae6_7e03_b820_be7b, + 0x0c6b_7005_0e17_d95e, + ]), + F::from_raw([ + 0xcfec_0dce_364f_ae76, + 0x2ec2_8037_ce70_9adf, + 0xf4d2_864e_af1d_3b05, + 0x1520_5156_7b1e_d7d6, + ]), + F::from_raw([ + 0x54a4_a88b_27bd_5a56, + 0xc040_c764_04d7_1445, + 0x769d_1fdb_eaa9_2abb, + 0x196a_7e50_cb51_7e21, + ]), + F::from_raw([ + 0xc69a_8b1a_296b_9a0a, + 0x7264_acf6_8750_4ae4, + 0x9bb2_a7a3_2f9c_c978, + 0x1dba_4d6d_2eba_8433, + ]), + ], + [ + F::from_raw([ + 0x6507_ad75_5c4d_375b, + 0xe322_21d3_4ff8_6ab9, + 0x3a83_3d40_316e_eb28, + 0x114f_b358_39dd_b57c, + ]), + F::from_raw([ + 0x93c5_c135_6b01_5832, + 0xf091_8e05_fae4_f402, + 0x0396_5412_bca5_b020, + 0x1520_86d1_247d_a805, + ]), + F::from_raw([ + 0x3b89_d743_ae95_2fef, + 0xfcaa_fc9f_606a_5969, + 0x49b9_7c34_03dd_5f08, + 0x248f_8659_574c_27b3, + ]), + F::from_raw([ + 0x4ece_f935_e5fb_ce2d, + 0x4f5b_42cb_3246_e7a6, + 0x0b70_8d1f_0dda_3a8e, + 0x2121_24ce_d78b_b0cd, + ]), + F::from_raw([ + 0x6b66_026a_7c9e_8b52, + 0x6e2d_fc0b_661c_c952, + 0x4da7_16b3_dc29_a6aa, + 0x09d6_8a71_7d84_1786, + ]), + F::from_raw([ + 0x6889_ac36_51b3_2a01, + 0x742d_d6af_7eca_2e5e, + 0x7b59_d758_418c_a3c0, + 0x1009_d903_3011_387d, + ]), + F::from_raw([ + 0xf754_0f1a_03de_6851, + 0x79fa_fab7_b317_5b12, + 0x6f58_1010_8713_c095, + 0x1dce_d906_04d2_9cc6, + ]), + F::from_raw([ + 0x40d3_b315_c3cf_4d50, + 0xc1db_3368_aff5_148d, + 0x71f3_700e_73d3_a357, + 0x12d4_25da_9511_6570, + ]), + F::from_raw([ + 0x94b4_782b_07ff_59b8, + 0x25df_e522_6108_9137, + 0x287c_8be5_5469_8099, + 0x027b_dc06_8f23_f8f9, + ]), + F::from_raw([ + 0x8790_02bd_20e6_74bb, + 0x2b36_0afa_4f96_46af, + 0x91e7_b66d_1550_e377, + 0x07d9_0919_6d6c_bd20, + ]), + F::from_raw([ + 0xdfc5_8877_bafb_84f4, + 0x713a_47b5_5272_6332, + 0x7269_604e_73d1_2733, + 0x2c54_0823_4e47_3efa, + ]), + F::from_raw([ + 0xd433_46f4_6a5b_cd21, + 0x6e04_cbc7_138b_fc02, + 0x4f09_473a_ac60_815c, + 0x0991_a9a7_548e_3c5c, + ]), + F::from_raw([ + 0x327e_f1bc_5a9b_d57e, + 0x07bf_92c3_fe5e_bc26, + 0xb0db_74b2_0f67_78c5, + 0x0e6c_6e47_926d_2386, + ]), + F::from_raw([ + 0xe08d_28e1_32ff_f211, + 0xcdba_27e8_c49b_d819, + 0x3bfd_c1b9_376b_38e8, + 0x01db_7d7f_5995_3833, + ]), + F::from_raw([ + 0x9a38_e3c7_a006_267c, + 0xf6f6_c1c1_01e8_e723, + 0x0f86_8051_00c2_84d8, + 0x14e0_d2bb_b596_9c1e, + ]), + F::from_raw([ + 0x1cd8_6c8a_f510_6755, + 0xbbf9_9ceb_b2d5_bac2, + 0x9d57_a171_138b_2f2b, + 0x26ba_784e_04d9_2ef5, + ]), + ], + [ + F::from_raw([ + 0xbd49_166a_9725_f72c, + 0xbbe7_4f21_9b8c_53f8, + 0x880d_0985_49ad_3e1c, + 0x07de_069e_bcd6_7dd5, + ]), + F::from_raw([ + 0x83df_0300_b4a0_d843, + 0x8fb9_b9d5_e708_77bd, + 0x5aa6_b460_691d_837d, + 0x3028_949b_0dd3_3e01, + ]), + F::from_raw([ + 0x1069_fe30_1200_38f3, + 0x0a8c_b08d_3f1d_7ed4, + 0xee48_42f6_6347_9d9b, + 0x0b5f_2ccb_84db_3c03, + ]), + F::from_raw([ + 0xf292_3dfa_4d93_f821, + 0x87d6_9c08_2814_1922, + 0xb178_f692_5309_45d1, + 0x0f56_a30d_c396_d6c1, + ]), + F::from_raw([ + 0x0b4f_bb42_d711_8f98, + 0x1c03_e4ea_8c17_77b2, + 0x6a45_e782_6eca_5915, + 0x16a8_73c3_f3cd_80fd, + ]), + F::from_raw([ + 0xd077_47ac_71c7_b474, + 0xe2c5_148f_5b42_a5ac, + 0x4de8_06df_ff98_d05e, + 0x2274_79dd_4a5e_86e4, + ]), + F::from_raw([ + 0x03ba_1b22_5514_994d, + 0x79f8_1fb4_0494_98c0, + 0x4bb0_241c_f0d0_84ed, + 0x247f_1772_04c1_391a, + ]), + F::from_raw([ + 0xe26d_ecf3_ab74_118e, + 0x511a_4c50_8aac_4a3e, + 0x639b_98ed_cca6_409b, + 0x1a7a_0d3e_02dd_fd68, + ]), + F::from_raw([ + 0xd050_932f_4422_35f5, + 0x20c8_e386_2abd_69a5, + 0x6189_de28_0af6_d0c8, + 0x0610_9074_715f_9019, + ]), + F::from_raw([ + 0x6309_b77c_a91b_c2fe, + 0x28c3_116f_e545_20e7, + 0x3f34_862c_d955_d296, + 0x112e_f9d4_64e2_ed0c, + ]), + F::from_raw([ + 0xc285_8b8e_c5a4_dbac, + 0xcad2_d7e1_9b48_0f50, + 0x44e7_3c54_eae6_ac05, + 0x052a_fd34_88a8_75bc, + ]), + F::from_raw([ + 0x7b31_3447_fb2a_1f9d, + 0xb571_0a62_4297_be76, + 0xf4f7_bea4_f3b7_be7c, + 0x07fe_a891_1b7c_2841, + ]), + F::from_raw([ + 0xf103_5b11_8373_12e7, + 0x62f9_cf54_7bb6_1fa5, + 0x934d_7e98_f4a1_3036, + 0x253b_88bb_f461_0d15, + ]), + F::from_raw([ + 0x91d3_3835_0283_4a88, + 0x8851_6684_3709_4696, + 0x8d4b_642a_5b58_4207, + 0x10ef_8f2a_1e54_a3e0, + ]), + F::from_raw([ + 0xc786_4e3b_f92c_8e35, + 0xd792_040f_3ea1_5285, + 0x6982_c758_e015_40c6, + 0x2de7_38c0_1f72_522b, + ]), + F::from_raw([ + 0xe06a_06f8_9b30_93f5, + 0x57ef_de65_f850_9325, + 0xe2ca_33fa_d840_b078, + 0x1869_a05c_2435_f4ed, + ]), + ], + [ + F::from_raw([ + 0x93f7_26da_e825_93eb, + 0x1998_d543_6243_ba1e, + 0x95a3_bba2_18c6_3c45, + 0x044a_3c58_9cff_1b00, + ]), + F::from_raw([ + 0xe239_d265_d10f_1fcd, + 0x88e2_53ad_ae6f_0551, + 0x2e54_014b_5643_1689, + 0x0edf_15cc_47ab_50a9, + ]), + F::from_raw([ + 0xb613_541d_4103_f409, + 0x01e0_41fc_3415_b5d6, + 0x075a_fd6b_6a13_3547, + 0x1dde_71a3_88e1_a9cb, + ]), + F::from_raw([ + 0xd8b1_20c8_a945_f82b, + 0xdebc_886d_cb5a_15bb, + 0x9bd2_657e_cbc3_1deb, + 0x1310_1734_082c_b23f, + ]), + F::from_raw([ + 0xf083_c39f_f729_37d5, + 0x4ad0_ab30_8b97_4260, + 0xdffe_c4d7_a17c_d304, + 0x25a3_a7c1_28ac_6ffd, + ]), + F::from_raw([ + 0xd8be_5657_2466_1b4b, + 0xa308_3967_a294_e62e, + 0x071e_3b9f_2fe3_c58c, + 0x0c5a_9383_9301_6ffa, + ]), + F::from_raw([ + 0x2053_2600_8cba_6e17, + 0x4e68_2ada_dc66_6db1, + 0xb3a3_3c63_fd00_d2da, + 0x1b63_a0be_e070_72df, + ]), + F::from_raw([ + 0x74b5_1b2f_8b0f_60c8, + 0xef9d_38d4_1a20_9ebe, + 0xffe9_c6ab_9671_9b2c, + 0x26f9_9a34_fc19_ea7d, + ]), + F::from_raw([ + 0x6b2d_1c40_1e49_83bf, + 0x75ce_66ad_7700_87b6, + 0xc0e0_aae8_8ac6_6863, + 0x1f18_84b1_cf3f_e36c, + ]), + F::from_raw([ + 0x5c51_77a8_a4df_812a, + 0xa98e_69d7_fd5e_4e20, + 0xc502_ca25_b440_455d, + 0x0d7f_0e22_06d6_a092, + ]), + F::from_raw([ + 0x82cd_7b73_da98_050a, + 0x5a47_6252_fe71_8895, + 0x6086_1f12_5fb5_390f, + 0x184d_a09f_d45f_dba3, + ]), + F::from_raw([ + 0x249c_8b26_3bb0_1573, + 0x33b0_719f_e283_333c, + 0xa903_5f8b_1ba6_51c8, + 0x1840_7815_6295_5cc1, + ]), + F::from_raw([ + 0x44b4_8023_b6f3_cdc8, + 0x290d_a147_7d06_d6a2, + 0xd9d8_b1a6_19ea_6063, + 0x02d0_77d0_27f3_9896, + ]), + F::from_raw([ + 0xc2b5_d9c9_7781_3660, + 0x2230_b491_5e15_6c43, + 0xa361_1676_9a2a_17ff, + 0x2cba_8f30_5b00_9310, + ]), + F::from_raw([ + 0x24f8_a8b3_7bb7_921a, + 0xaa99_0b64_9384_4ad7, + 0x6832_a968_be9f_79bc, + 0x1e1c_46b0_68f4_807d, + ]), + F::from_raw([ + 0x5d1a_e768_a0e1_a419, + 0xaa1e_48fc_6c76_f62f, + 0xdb53_55e5_cc47_9dc1, + 0x21ad_3574_04bb_8cd9, + ]), + ], + [ + F::from_raw([ + 0x430e_14b7_4cea_c5fe, + 0x4eee_11f6_609b_60cf, + 0xc73a_3538_e919_f48d, + 0x00e1_9ce8_b72c_6453, + ]), + F::from_raw([ + 0xa767_6eb6_6194_d06c, + 0xe58f_ff3b_13a6_fd1e, + 0x7bc6_3b93_7036_d40f, + 0x0f89_d945_566a_286b, + ]), + F::from_raw([ + 0x43ed_1cec_ba61_137d, + 0x318b_ab0b_e211_9a86, + 0x03c4_e91e_066b_483a, + 0x15e6_a57c_bb53_2208, + ]), + F::from_raw([ + 0x675e_9170_3f0e_2327, + 0xe9e4_68ef_83e1_e7c6, + 0x75a4_6c99_1154_5c14, + 0x1c45_c884_1fd5_d4e6, + ]), + F::from_raw([ + 0xf1db_bbbf_e8d8_8a01, + 0x0a0f_10f5_3cf4_c5b6, + 0x2314_58b2_0f4b_7748, + 0x10ea_93f0_2575_126c, + ]), + F::from_raw([ + 0x7714_2767_ad0c_5ff1, + 0x3a45_0088_05ac_7424, + 0xb8b7_4b71_4d17_266e, + 0x01bb_b778_4b1f_4971, + ]), + F::from_raw([ + 0x4fdc_2ca2_24c3_405a, + 0x6f94_2938_6ad7_ca20, + 0x374f_cf01_90a4_1cc8, + 0x1389_41fb_4f66_6acf, + ]), + F::from_raw([ + 0x7405_52c8_2594_3423, + 0x54fb_a717_27c2_2957, + 0x6716_2631_ec34_91ef, + 0x2c89_91fb_3b62_95cd, + ]), + F::from_raw([ + 0x3a32_c5db_418c_7501, + 0xd78d_fad6_2871_6a84, + 0x6781_bc62_9c1b_3989, + 0x0de6_6b24_c1d4_e2e5, + ]), + F::from_raw([ + 0xd973_b4e0_104b_b2a5, + 0xff5c_15be_286b_1e82, + 0x55cb_2779_0ac5_23f5, + 0x0e8b_37c1_6fb6_2812, + ]), + F::from_raw([ + 0xcf8b_5fed_9289_c85e, + 0xa0cb_d615_02e0_6898, + 0x840b_8828_0597_d436, + 0x0fb4_1067_dfd9_ee6e, + ]), + F::from_raw([ + 0xfbc3_3ef7_acf8_57db, + 0xef4b_8eb7_0d6b_ee07, + 0x7a7b_0e64_479a_9a77, + 0x0119_c19d_f693_f80a, + ]), + F::from_raw([ + 0x87e7_1aac_bf09_5795, + 0xd843_4b81_2058_bd18, + 0x96cf_c181_797f_6133, + 0x2826_c0eb_3ae0_b75c, + ]), + F::from_raw([ + 0x4332_2a87_b647_7c76, + 0x037a_ab08_2b80_4e21, + 0x1ebc_d319_a685_8178, + 0x1d13_8c87_3341_4f70, + ]), + F::from_raw([ + 0x2175_87e4_955d_7c07, + 0x7949_4b1d_970e_0c79, + 0x7e31_d69e_4277_c3e6, + 0x22e3_2c8a_1a9e_200d, + ]), + F::from_raw([ + 0x7660_a660_ad5c_f6e7, + 0xc51f_8a4f_075b_8e6d, + 0x13f2_88d6_7ace_22c5, + 0x2d52_b655_82b8_3b5d, + ]), + ], + [ + F::from_raw([ + 0x93b4_d4ab_6ab9_021c, + 0x5947_cb26_064a_22e7, + 0x10e0_827e_add1_24a3, + 0x2e2e_7048_c0a0_db89, + ]), + F::from_raw([ + 0x9361_e2ab_8930_41c2, + 0x370d_acb7_b679_9e3f, + 0xc13f_5224_a40d_d495, + 0x234f_9d96_cf48_3333, + ]), + F::from_raw([ + 0x758a_1070_70ba_481c, + 0xc8e2_d55e_255f_e81d, + 0xf549_9a27_49dd_7e36, + 0x0bb3_e002_22cd_3d72, + ]), + F::from_raw([ + 0x0775_9b82_eee7_6612, + 0x21d1_1594_eb52_a079, + 0x5f54_bd2b_9ca9_dc0f, + 0x199a_e52b_7547_a3da, + ]), + F::from_raw([ + 0x199c_2655_0f3a_181b, + 0x3ecc_d076_9689_d612, + 0x1c18_d1ab_2e10_666d, + 0x01a3_d804_8dad_0958, + ]), + F::from_raw([ + 0x3851_396d_ecc0_fd1b, + 0xa143_91b0_e06f_be26, + 0x8c5c_c86e_ec75_1353, + 0x1666_ba94_ac2c_b3a5, + ]), + F::from_raw([ + 0xb811_872a_f404_2e8d, + 0x5989_16ed_5634_4727, + 0xc00b_7976_817c_5969, + 0x15c3_034c_d79c_ae75, + ]), + F::from_raw([ + 0xd8ea_2c6d_f75b_8789, + 0x6d5d_70f4_dc3b_1e1e, + 0xe418_b612_5028_51e0, + 0x086a_c693_2de6_1a9c, + ]), + F::from_raw([ + 0xd3a1_768b_c722_b72d, + 0x41ab_43b1_9925_a1b4, + 0xe057_6bb2_7764_6561, + 0x0f43_a70c_864e_7a81, + ]), + F::from_raw([ + 0x399a_f298_3fa1_45f4, + 0xb34a_09ea_1f98_ed30, + 0x0706_8d97_508d_f5ff, + 0x1db3_a2b7_c6b5_38ad, + ]), + F::from_raw([ + 0x3cc3_547d_17e7_dfd9, + 0x1826_aab3_4ea8_7d3a, + 0x8ea4_8570_d759_416f, + 0x1b15_391c_a852_37ee, + ]), + F::from_raw([ + 0x4542_6341_e0f3_8f33, + 0x268d_f561_51e7_9df3, + 0x5e67_f9a0_9901_feed, + 0x0263_aaa9_f9e8_3c25, + ]), + F::from_raw([ + 0xf3bd_65c1_2913_8213, + 0x90f0_4e8c_dd01_6cbb, + 0xd71f_aeea_ede7_93d9, + 0x2da8_4ec3_8f77_07d5, + ]), + F::from_raw([ + 0x8910_c55e_8f77_be9e, + 0xbb2d_3eb8_1dcd_223e, + 0xd28d_3796_42ba_7b79, + 0x13ae_9ded_4812_d1f4, + ]), + F::from_raw([ + 0xa060_359f_b523_bf6a, + 0x0d45_e709_5119_29ce, + 0x2b13_0493_7efd_c34a, + 0x25b1_81c7_2550_002c, + ]), + F::from_raw([ + 0xae90_7458_3f6b_64ba, + 0xd464_4283_8f3a_e21a, + 0x47f2_da27_abbe_0504, + 0x2d14_1f87_778e_baf6, + ]), + ], + [ + F::from_raw([ + 0x1ca4_14ff_53ef_5505, + 0x0b65_e2c1_97f5_9483, + 0x30c1_4bfd_4c87_741a, + 0x05cf_b569_8f68_cf51, + ]), + F::from_raw([ + 0x996c_c8dd_9da3_1d9e, + 0x0cc5_ea34_72ec_30e0, + 0x8154_085c_8457_a298, + 0x0fba_377e_6949_b390, + ]), + F::from_raw([ + 0xc33b_4852_d9b5_07b5, + 0x1597_2b20_3e21_d3ca, + 0x585a_c883_e574_5012, + 0x2ea5_bc22_fd3e_4ee8, + ]), + F::from_raw([ + 0xa6ee_35a5_c724_f8db, + 0x76f9_224f_ac1d_1b3d, + 0x72e7_2b0f_fbc7_e76a, + 0x0db2_fe84_aa7d_1374, + ]), + F::from_raw([ + 0xfeda_1c72_f0a4_db23, + 0xb042_c12c_e349_a00d, + 0x3db1_ab26_8297_9afd, + 0x11c8_04a4_19c4_7dc7, + ]), + F::from_raw([ + 0xc192_7d27_76da_f241, + 0x861f_e0d8_9746_24df, + 0xc3e8_0af6_99fe_fabb, + 0x1423_df99_c89e_fe43, + ]), + F::from_raw([ + 0x5314_0de0_e3cb_4ee0, + 0x4607_e83c_308f_4da2, + 0x1bd8_9157_87ca_74c0, + 0x2e07_c1f8_1bba_9f8e, + ]), + F::from_raw([ + 0x16db_144a_b27f_a3ca, + 0xb28b_6331_2b32_78cd, + 0x0a23_926c_a553_7b49, + 0x1b94_5ccb_17bc_27e1, + ]), + F::from_raw([ + 0x532b_7cc9_db7a_575d, + 0xd4cb_abc9_3781_f36d, + 0xa937_3b03_2275_d32d, + 0x0ae9_8212_43e0_3b7e, + ]), + F::from_raw([ + 0x1b5a_d135_d41c_4c02, + 0x7c3f_3541_fc0c_e8ef, + 0x9935_8234_fa6a_0c90, + 0x18f2_e62f_9e91_c3e3, + ]), + F::from_raw([ + 0x30ee_f7e0_6c40_49fd, + 0x54b1_7ad7_a5a2_c572, + 0x1943_cf83_3425_4f97, + 0x17d7_aee2_92db_a3de, + ]), + F::from_raw([ + 0x4f4a_3bf2_118f_9836, + 0x6f9d_31b1_0a09_03b2, + 0x86be_efd9_f5d8_bf6f, + 0x0ff7_5f8f_f73a_55d4, + ]), + F::from_raw([ + 0x36de_37e9_dfc6_5a4e, + 0x0e34_b0ec_8dcf_6d74, + 0xb2f3_8c69_7bff_d310, + 0x2f82_19f3_c7c1_48dc, + ]), + F::from_raw([ + 0x5cf3_a043_f7d8_20e6, + 0x9123_f7d7_8901_9ecb, + 0xd9d1_4221_6659_d99b, + 0x16ec_1ee6_a74f_79dd, + ]), + F::from_raw([ + 0x6aea_f18b_0216_b57e, + 0x2507_8d26_04db_f20a, + 0x4e22_4078_cbf3_907f, + 0x0fe5_612d_8e5f_e5ff, + ]), + F::from_raw([ + 0x7ddd_32fe_0b0c_fc8d, + 0xe06b_2a7e_aaca_605b, + 0x0bc3_8524_2c52_63ea, + 0x0802_1977_7df4_7cea, + ]), + ], + [ + F::from_raw([ + 0x37cf_9c0c_4040_3e77, + 0x1b2c_94ee_ed51_32c6, + 0x815e_c08e_b142_106a, + 0x08e9_0c05_a909_1040, + ]), + F::from_raw([ + 0x1aac_51de_c7f9_f026, + 0x362c_5997_0e31_aaf0, + 0xee7a_4990_3b7e_6ef1, + 0x279d_2ce8_3467_31fd, + ]), + F::from_raw([ + 0x2d44_3727_79bd_f165, + 0xf1d8_db8f_b383_7859, + 0xfbf8_1e99_cc13_e2b9, + 0x117e_0047_acd2_2b61, + ]), + F::from_raw([ + 0x39d5_a176_52d9_411f, + 0x2f32_f222_487e_c9ec, + 0x51d0_f8d0_5118_9da2, + 0x02bc_7053_dc85_295a, + ]), + F::from_raw([ + 0x44dd_bb6e_645f_c010, + 0x32ca_5378_678e_b8c7, + 0x3225_cf72_e60c_0264, + 0x0790_684b_4d26_b9a8, + ]), + F::from_raw([ + 0x1c1d_6072_e3ab_079d, + 0x3f37_3a33_8957_7449, + 0xb877_0981_2e1f_7868, + 0x08ce_a9f0_2523_e9dc, + ]), + F::from_raw([ + 0xd2a7_061f_63ad_35f3, + 0x5f02_33fe_045f_0da2, + 0x0f36_10ce_30bf_f1cd, + 0x1a28_f554_8ebe_2c21, + ]), + F::from_raw([ + 0x63c6_3474_cbc6_713d, + 0x61b6_6010_29c5_6fc8, + 0x7242_f5bf_4351_9ad5, + 0x1551_491a_a0e0_3578, + ]), + F::from_raw([ + 0xa3c9_b54b_49c6_44f6, + 0xf4b4_57e9_0e7e_8b16, + 0x38cf_e6b3_d042_e4e5, + 0x2705_e735_56fd_298b, + ]), + F::from_raw([ + 0x8de5_07dc_8947_2728, + 0x7bd5_8d6e_dcb0_3807, + 0xe372_e01c_3835_b716, + 0x19ed_b848_62a4_a113, + ]), + F::from_raw([ + 0x24a0_915d_bd2a_3429, + 0xde37_5510_950d_4752, + 0x4148_906f_e0e9_0f9a, + 0x0938_b1c2_6530_2b7e, + ]), + F::from_raw([ + 0xba1d_fb7a_7e88_7c08, + 0x4441_6231_62e5_b636, + 0x8bba_1a46_48b7_3af6, + 0x0435_d661_e18d_8bb2, + ]), + F::from_raw([ + 0x8957_f9c8_6286_b2cc, + 0xb147_7573_b261_f9d3, + 0x1ea3_3f99_ddd4_2227, + 0x2ce7_1ce2_4316_6291, + ]), + F::from_raw([ + 0xefd9_bf39_060f_1df4, + 0x4fd2_8038_a87a_50a6, + 0x4b2e_d397_99b7_47fb, + 0x17c7_5da1_521b_d3f4, + ]), + F::from_raw([ + 0x0794_567f_f4ff_187a, + 0xbb83_e9a8_6c5d_af77, + 0x3eaa_57f7_1aba_15a8, + 0x2fa1_8e89_595e_6999, + ]), + F::from_raw([ + 0x740f_0467_3ccc_d983, + 0x80fa_8ec6_3600_8628, + 0x4614_dbdd_9ca0_6eed, + 0x0a97_b5f7_307b_9b6b, + ]), + ], + [ + F::from_raw([ + 0x115c_e510_d1ee_90da, + 0xfd90_705c_b65f_2f99, + 0xe3be_a786_52a3_dd50, + 0x2fb0_2323_a8db_7ba7, + ]), + F::from_raw([ + 0x88b8_7834_b46a_645f, + 0x23c6_4314_35ff_3877, + 0xc7d0_51c0_6a00_2008, + 0x0109_8491_5fbc_bcb2, + ]), + F::from_raw([ + 0xdb24_fd02_8cb9_5e74, + 0x045f_9835_0fe8_020e, + 0x9b35_16ed_4453_6847, + 0x25fa_efb5_4ae7_e8ac, + ]), + F::from_raw([ + 0x97c8_5d21_07dc_ff77, + 0xf8a3_5410_4960_ac70, + 0x6406_aec4_3091_656d, + 0x163e_9a85_8051_6638, + ]), + F::from_raw([ + 0x4586_8a40_c23f_e53d, + 0x8f81_d0a2_5706_436c, + 0x0039_3dbc_7927_3782, + 0x2e01_e39f_dd20_9edd, + ]), + F::from_raw([ + 0xc34f_f4b4_59dc_fa61, + 0x9484_6348_83e6_4cb6, + 0x3a7f_0272_6338_c925, + 0x1ee6_ca01_56ee_bed4, + ]), + F::from_raw([ + 0x7e7a_3436_6a92_3f44, + 0x25c6_ad69_6ac0_ab5a, + 0x6ebb_6571_af7a_1513, + 0x25ef_fb4b_84c2_c090, + ]), + F::from_raw([ + 0x9e21_43e2_d1bf_94c4, + 0x199d_a41c_0b29_4c04, + 0x941a_f09f_6e85_e6c9, + 0x0901_8508_6d0c_fbdf, + ]), + F::from_raw([ + 0x268d_3728_d0ba_ccbd, + 0xae06_cede_d49f_f948, + 0x7cf6_bf76_b7fd_8dba, + 0x1969_21a3_7402_0f2f, + ]), + F::from_raw([ + 0xd437_aa9c_1108_0577, + 0xecd2_d819_7682_2b2e, + 0xb66b_b1fe_9232_d73a, + 0x2e30_a88a_9c1a_48de, + ]), + F::from_raw([ + 0xc163_5685_2253_43cd, + 0x2d57_f549_acdc_4f86, + 0xf4de_54cd_023b_0b55, + 0x18fc_95ef_b840_dd52, + ]), + F::from_raw([ + 0x1a22_ef6e_2d95_c08b, + 0xae99_d86d_be6b_d786, + 0x5141_b3be_470e_865d, + 0x0bd2_326b_0caa_ea6d, + ]), + F::from_raw([ + 0xe627_6701_8655_a8c3, + 0x2534_0ea0_b5a5_0702, + 0x2fe3_c503_dcb0_a583, + 0x04de_1aa3_fb98_07b2, + ]), + F::from_raw([ + 0x2dfc_737a_187e_b989, + 0xe6e1_271a_084c_55f4, + 0x181d_5081_8279_40f6, + 0x279d_2165_7b39_b694, + ]), + F::from_raw([ + 0xafe6_d70d_3dc9_7a8b, + 0x4abc_e18c_dbfe_b509, + 0x3d64_510b_ac3b_3041, + 0x2594_a942_15dc_c6c7, + ]), + F::from_raw([ + 0xbadd_db27_6ddd_2920, + 0x4598_95b6_cea1_0edf, + 0xba98_8583_3c61_4bbf, + 0x0951_42e3_ce6e_5fbd, + ]), + ], + [ + F::from_raw([ + 0x47be_3ad1_b677_3261, + 0x90f4_19b8_4130_3426, + 0xdbf8_bbf9_5fc1_af46, + 0x04f7_c712_281e_cc56, + ]), + F::from_raw([ + 0x1fce_a8c5_15fc_e483, + 0x8a42_448b_7a8e_e56d, + 0xa5cf_af70_de3e_998f, + 0x150c_295b_b04a_6280, + ]), + F::from_raw([ + 0xaba7_ea9c_e598_3783, + 0x0681_ba42_d927_05be, + 0x4846_2b3c_9696_5e07, + 0x040b_073a_ea01_b559, + ]), + F::from_raw([ + 0x13f1_89c4_caa3_6c9e, + 0x0975_aaa2_a90a_eb87, + 0x616d_a7b0_2a6b_2ef3, + 0x2858_54aa_e042_c3ea, + ]), + F::from_raw([ + 0x205e_8dd5_3bea_3b04, + 0x165c_eb65_2b69_56c1, + 0x42ec_8fb9_b5cb_61f9, + 0x0ab0_0bbe_e202_a51e, + ]), + F::from_raw([ + 0x9a0a_a262_cde1_3f80, + 0xbb50_1954_b721_f385, + 0x5f38_a6bd_f0a4_eb0e, + 0x0115_2e19_1309_1cde, + ]), + F::from_raw([ + 0xd1b2_e253_2e8a_4d15, + 0x0117_1bd0_9b78_0d43, + 0x9794_42d8_5dda_5285, + 0x2df4_a938_e948_8825, + ]), + F::from_raw([ + 0xd7e9_e958_1927_9a77, + 0xb2bc_6f21_a2fb_3d37, + 0x3ad4_9d71_ac02_7dc4, + 0x1d10_433e_676c_08dc, + ]), + F::from_raw([ + 0xedb6_2cc5_2676_df26, + 0xaff6_a429_c231_e5ff, + 0x0490_93f7_30c2_a461, + 0x087e_2ac1_2cd1_267a, + ]), + F::from_raw([ + 0x3fb0_0411_8718_ac38, + 0x6826_f7c3_a6ca_8b99, + 0x6fc9_fedb_b6b7_6085, + 0x0f37_6973_7a44_340e, + ]), + F::from_raw([ + 0xf18a_8220_f36c_f76f, + 0x2e7c_35d3_c0a4_f00c, + 0x800e_e613_b445_8525, + 0x29f6_d54a_21cc_0209, + ]), + F::from_raw([ + 0x3b76_c13c_d4ee_465e, + 0x5e39_2d63_c6d2_2e18, + 0x5004_c6d0_7927_2898, + 0x0010_6dfd_6a05_f7c5, + ]), + F::from_raw([ + 0x9b46_0331_f8e3_6e3e, + 0x690c_50b9_960d_aed5, + 0xab85_ed24_f30b_fb88, + 0x3024_b665_3dfd_68a1, + ]), + F::from_raw([ + 0x447a_7ea5_4e9a_89ff, + 0x1c7c_f5d2_7a4c_83dc, + 0x10c2_911a_5048_37d7, + 0x2f17_9ae3_fa16_7361, + ]), + F::from_raw([ + 0xfe65_e2c1_87b3_97bd, + 0x680d_3d0f_b5de_cc4d, + 0xf4ad_03ad_49ab_3386, + 0x0577_40fb_88ed_21c6, + ]), + F::from_raw([ + 0xf1c8_8100_6d3d_2286, + 0x189b_c833_55c7_d831, + 0xb385_2c96_5bb0_0bc1, + 0x157f_8573_cc1f_9773, + ]), + ], + [ + F::from_raw([ + 0xd376_44d2_0e8f_449c, + 0x7471_e76e_961a_3b30, + 0x3e06_0fe4_67c7_dd0b, + 0x21da_e9de_84c8_96fb, + ]), + F::from_raw([ + 0x30af_a9b7_6e47_03c8, + 0x5a29_d2a3_54ed_d542, + 0xb9dc_ed3f_9da1_acad, + 0x2d76_eba3_7f90_108b, + ]), + F::from_raw([ + 0x1e07_1f99_ba36_0196, + 0xb897_5082_8052_255b, + 0x0628_6237_2715_383d, + 0x2041_ea40_d491_d2f1, + ]), + F::from_raw([ + 0xc9bf_c72d_6821_c673, + 0xe3d6_a8af_8da4_cc79, + 0x5a42_cb89_68bb_f928, + 0x25b9_39e2_c40c_6e07, + ]), + F::from_raw([ + 0xa75a_8b07_605c_e461, + 0xef6e_5a1f_20d5_0cf7, + 0xb2ff_4ecd_6edf_b287, + 0x2ca8_f0a1_5978_2d2a, + ]), + F::from_raw([ + 0x7e7c_0470_7d2f_1ffb, + 0xd780_e8b3_f592_153b, + 0x5a74_fcf2_a5df_d866, + 0x08e1_8252_ecd5_8de8, + ]), + F::from_raw([ + 0xe85d_3e3b_a0c5_767e, + 0x14f4_0e3a_ba46_a2d6, + 0xabaa_17ca_7dca_2bfc, + 0x0e74_2fa2_6b84_08ad, + ]), + F::from_raw([ + 0x0a7a_f80a_3b3f_da7f, + 0x6179_d812_75e5_2dc3, + 0xad23_dae6_9782_95d2, + 0x2874_3cad_3d87_2842, + ]), + F::from_raw([ + 0x2eaf_e79a_eafb_e868, + 0x7059_fde3_40d3_886c, + 0x05e5_08cc_47a3_c2a3, + 0x2b78_a477_72df_0f80, + ]), + F::from_raw([ + 0xa562_94c2_f350_af7b, + 0xd3f9_1a57_dd9e_e5e9, + 0x90e8_8f89_e047_b4ec, + 0x1699_4b81_5229_f66f, + ]), + F::from_raw([ + 0xb157_f577_2129_430f, + 0x1b85_a545_f4d6_42ff, + 0x520e_db18_97af_5ab1, + 0x0e0f_16cd_7504_1288, + ]), + F::from_raw([ + 0x6d07_e98f_9a73_ef04, + 0x9f01_7da3_e15d_4865, + 0x4ac7_5612_2f8e_79aa, + 0x1b01_e8e9_1d77_3dbd, + ]), + F::from_raw([ + 0xe575_c04e_567d_332d, + 0x176a_4497_c158_8c8b, + 0x3e9d_7617_0afe_6f51, + 0x0d1f_2525_b6ad_f501, + ]), + F::from_raw([ + 0x994e_2d16_e3f4_5210, + 0x527e_ab1f_97c0_a6b0, + 0xffe1_0f31_6fdc_c134, + 0x0ad1_5029_4588_59dc, + ]), + F::from_raw([ + 0xc239_361e_ea4a_f45c, + 0x2b41_d429_feb2_a66b, + 0x04f0_f188_115c_01e2, + 0x2eef_7903_4f8c_c2ee, + ]), + F::from_raw([ + 0x343f_95ce_50c6_2dad, + 0xe72d_e3aa_38a8_573d, + 0x3f05_b36c_fc48_5e97, + 0x25e4_2a21_e65e_99f6, + ]), + ], + [ + F::from_raw([ + 0xbcc3_4c4f_166f_7c8e, + 0x52ef_8531_eedd_3263, + 0x0619_7861_3c9b_a2a0, + 0x06c6_2c05_6404_aa31, + ]), + F::from_raw([ + 0x20d4_1eed_ee9d_4cfd, + 0x3f82_be37_618a_cdc1, + 0x5e30_7795_1228_0402, + 0x17a6_98b5_83a7_6914, + ]), + F::from_raw([ + 0xf068_1ce5_a11f_520c, + 0x7385_9363_b0be_e9cf, + 0x0928_2179_563a_b3e2, + 0x0e1c_bcc1_1d65_e214, + ]), + F::from_raw([ + 0xa9d2_a1c1_620d_d0ad, + 0xbc2a_560b_fe98_b02c, + 0x36db_6bff_cbac_d9bc, + 0x220b_8ec0_7c64_9191, + ]), + F::from_raw([ + 0xf142_505c_2ea3_5645, + 0xc2ad_5352_b63d_111c, + 0x7c2d_4d7f_8d10_7d91, + 0x1f71_95b3_bf18_9a99, + ]), + F::from_raw([ + 0x49c3_99c3_8b56_6709, + 0x7f99_680f_6299_a802, + 0xea74_9730_aa63_636b, + 0x0946_e22a_5fe1_252c, + ]), + F::from_raw([ + 0xdd99_e863_2931_3b5d, + 0x1647_2189_b7b2_a7d7, + 0xdc76_560d_af9d_c2b0, + 0x2478_5875_bdec_9ee2, + ]), + F::from_raw([ + 0xe3e9_49d2_d351_05ba, + 0xc432_9fd0_5d5b_c33c, + 0x2953_1e9a_90ca_b696, + 0x24d6_da0a_ff84_53f0, + ]), + F::from_raw([ + 0x7973_80fd_2b70_1512, + 0xdacc_ecee_91d4_4a9c, + 0x93bd_dbb1_1591_cdba, + 0x195e_3e21_079c_a380, + ]), + F::from_raw([ + 0x4fea_adeb_c010_209e, + 0xc011_6cc4_e699_08fc, + 0x2b13_0323_317c_cf68, + 0x1bff_6b43_a453_e16b, + ]), + F::from_raw([ + 0xa86b_89f3_c0e9_c78a, + 0x2e8c_5900_8763_0266, + 0xef62_884f_ba9a_3143, + 0x073f_9d5f_5269_4d81, + ]), + F::from_raw([ + 0x25c7_0f27_ab07_17e9, + 0x3335_c21a_6fb6_f3c3, + 0xce43_6f93_d492_a73d, + 0x2be3_fe4d_ab84_c18c, + ]), + F::from_raw([ + 0x66b2_669e_d687_4db5, + 0x3c0a_0454_7216_dec7, + 0xacc0_2208_28c3_7411, + 0x280f_7583_50e2_ce22, + ]), + F::from_raw([ + 0xbd79_02e3_81d5_f251, + 0x4152_9082_50eb_ad77, + 0x2ba6_3fc3_1e73_c470, + 0x06a4_b8aa_a363_261c, + ]), + F::from_raw([ + 0x410a_76dc_5bdf_dd5e, + 0xa103_713b_9100_4027, + 0x96d3_0a61_9687_7ee0, + 0x0611_8135_c6b1_997f, + ]), + F::from_raw([ + 0x0eef_4744_94c3_1c07, + 0x1213_05f7_b314_89f5, + 0x3444_5917_055b_958f, + 0x1a89_b2b1_0aba_25ad, + ]), + ], + [ + F::from_raw([ + 0x9498_4127_afe1_f4c0, + 0x0392_1db4_bb14_75fd, + 0xfcb3_b92b_4059_1c38, + 0x2e34_c3a2_4b90_fa5a, + ]), + F::from_raw([ + 0x528c_bd84_95d8_9b76, + 0x40b9_241a_f6be_3fa3, + 0x8c1e_0cbe_36c0_b538, + 0x29f4_cd64_b7c9_daa8, + ]), + F::from_raw([ + 0x7261_ade0_06dc_5da4, + 0x4128_528f_8ca2_fc62, + 0x654e_e734_cf59_0713, + 0x1130_34f8_99c9_af84, + ]), + F::from_raw([ + 0x6789_60f7_9a03_c221, + 0x1c12_c29e_5245_a94e, + 0xfd30_3a18_2c7c_e4da, + 0x0dd5_e41e_4d00_2d17, + ]), + F::from_raw([ + 0x054e_6d5f_f531_cb67, + 0xcf9a_e088_6814_6f80, + 0xa3c2_928a_4241_3f02, + 0x0949_5239_a4fe_d063, + ]), + F::from_raw([ + 0x271f_63b8_ca6e_8d82, + 0x06a6_3a0b_6e25_b1fb, + 0x8afe_5329_8198_4b6c, + 0x1548_6ff3_6b73_2552, + ]), + F::from_raw([ + 0x0e91_8f01_a14e_4835, + 0xe37c_1392_7e8d_61fb, + 0x6b3b_1aa0_b244_929c, + 0x2d8a_ae1d_082a_60db, + ]), + F::from_raw([ + 0x3601_616f_6935_45e0, + 0x7a5c_69e9_bd09_0090, + 0xb3d8_6831_1700_fb83, + 0x0094_ebb5_501d_ae50, + ]), + F::from_raw([ + 0x07cc_cb26_e690_c7e2, + 0xc42f_d8da_9083_d2ac, + 0x154b_16c9_aa2c_8859, + 0x1fda_ffac_adac_41b6, + ]), + F::from_raw([ + 0x594d_764a_a5b2_41c9, + 0x30db_9118_a5b4_779b, + 0x3017_e3a2_e83e_8158, + 0x0b75_84ce_e1c7_8e90, + ]), + F::from_raw([ + 0xc293_6f37_0c40_c875, + 0xd728_f2e0_d566_a56c, + 0x0a11_d27f_f0c4_609b, + 0x1412_e854_da8a_4c9e, + ]), + F::from_raw([ + 0xe74e_269e_f5da_2981, + 0xcc99_1c49_edfb_396e, + 0xd12a_edfa_5e11_de27, + 0x03d3_4dbc_2e6f_77a1, + ]), + F::from_raw([ + 0x532b_a1a1_f4d3_17c3, + 0x6395_0d10_8a7e_6910, + 0xc913_7838_82d4_a454, + 0x2aed_d579_5046_dbc6, + ]), + F::from_raw([ + 0xd6ca_2d5e_c880_e283, + 0x93ed_c4af_a7d3_b171, + 0x1d27_5f91_ed2f_ea37, + 0x0a5d_ce1e_c5c7_d199, + ]), + F::from_raw([ + 0x24d6_c708_cd38_959e, + 0x5b37_178a_9e5a_76be, + 0x4bac_80a4_9f4a_9344, + 0x158e_7fc9_d159_6cf0, + ]), + F::from_raw([ + 0x604b_4e65_e6fa_595e, + 0xec6e_6a97_52f8_5e7f, + 0x3093_e05e_80f0_494c, + 0x08d7_3061_d983_610d, + ]), + ], + [ + F::from_raw([ + 0x1f64_1d53_60d7_f209, + 0x8974_df29_cf53_f17e, + 0xc737_2015_b5f1_6ab1, + 0x2eb1_6d92_356a_9ce2, + ]), + F::from_raw([ + 0x4c1f_08f6_6506_d6d4, + 0x8d04_5485_7a93_f2db, + 0x1448_bcf3_cb18_9e3c, + 0x2e9b_fb1c_072f_fa1f, + ]), + F::from_raw([ + 0xe217_9128_7baa_4d08, + 0x758c_3223_aab8_5cd4, + 0x250e_e9f3_2095_b2d3, + 0x04da_3ae9_ccf2_3c44, + ]), + F::from_raw([ + 0xe7e3_6193_2272_6e5d, + 0xa9f8_4d70_a2eb_1265, + 0x205c_a14f_4882_b6d5, + 0x1644_9574_9ccd_7eae, + ]), + F::from_raw([ + 0x7c13_e8fa_199d_ba98, + 0xc7a0_830f_c90d_4f96, + 0x2305_2a1e_de80_c8ed, + 0x1c81_b393_3e30_2e2a, + ]), + F::from_raw([ + 0x1af7_d71b_e82a_cebb, + 0x7d26_bbe3_d3a1_0f8f, + 0x6727_a6e8_790b_4b38, + 0x0de7_7902_a2da_45cf, + ]), + F::from_raw([ + 0x978a_0546_b275_a224, + 0xf7c5_758b_f121_ae97, + 0x01d2_18cc_4283_d9f4, + 0x0fbc_8f1f_39fa_56f5, + ]), + F::from_raw([ + 0xe8cd_1742_8e9f_9c25, + 0xffd9_226e_c1fc_9f5f, + 0x75ac_5a03_3d06_9543, + 0x1b15_8898_ddea_f570, + ]), + F::from_raw([ + 0xf33c_0723_3157_f7d0, + 0x7c07_23d4_3248_59b8, + 0xb71c_e382_82c5_5004, + 0x10a9_ba7d_8fc3_6249, + ]), + F::from_raw([ + 0xbbed_33f3_f0a4_1013, + 0x62eb_21ae_e00b_0a12, + 0xc1cc_b782_6515_c00d, + 0x1e62_b7c5_3f51_0e60, + ]), + F::from_raw([ + 0x4b75_9eec_1839_97e8, + 0x6b1f_2c54_6a29_8dbe, + 0x9bd3_8f69_e6bf_e5fc, + 0x21e2_a309_73e6_0146, + ]), + F::from_raw([ + 0x37fb_ae34_3a0d_b862, + 0x607c_81ee_be0c_efce, + 0xc632_4b60_59b1_96f6, + 0x1f42_56c0_12bd_b73c, + ]), + F::from_raw([ + 0xdf1e_ecc0_1c31_0936, + 0xe332_5fef_fff2_0d60, + 0xab6a_80b4_b790_3592, + 0x2838_1540_6e80_c945, + ]), + F::from_raw([ + 0xbd6b_3e24_ffcf_f3f9, + 0x7811_9624_47de_a07b, + 0x6708_a7bb_1424_540d, + 0x0cb4_ce0d_e05f_fede, + ]), + F::from_raw([ + 0xd3b3_7127_cbad_9683, + 0x3230_df90_46b8_a338, + 0x3d0b_41e3_1a7f_6ba5, + 0x23f9_dadf_82c5_22df, + ]), + F::from_raw([ + 0xafcb_5d05_8a5c_d059, + 0xf214_5ab7_6ce5_13d4, + 0x0286_d8b6_29d4_cc7b, + 0x2113_06e1_9fb6_5ae1, + ]), + ], + [ + F::from_raw([ + 0x6b08_0757_c8bc_abc1, + 0xd320_2ee7_ee29_1ff6, + 0x57d9_406c_53b1_703e, + 0x26f1_8bb0_9eef_a702, + ]), + F::from_raw([ + 0xa504_c104_ec4f_7dc7, + 0x2457_7e3b_faff_f58e, + 0x1ca0_7dc9_a240_6f24, + 0x2d69_b464_23fe_79aa, + ]), + F::from_raw([ + 0xcb2a_d319_6d2c_7e32, + 0xc8c7_50a3_0b5d_9d39, + 0xdccf_76d5_215c_11ff, + 0x0746_5ba3_3026_ed23, + ]), + F::from_raw([ + 0xc45a_390b_4d46_d64b, + 0xae20_f047_ac4f_ab2c, + 0x8877_3810_e532_7946, + 0x0e41_46de_e78c_eba6, + ]), + F::from_raw([ + 0xffae_eac0_2066_dd85, + 0x5f60_a688_9863_457f, + 0x876e_a8b2_e211_5cdb, + 0x1624_e960_b1dc_56e5, + ]), + F::from_raw([ + 0x2ee5_a5f9_358d_7ac4, + 0xebfd_f38d_f0ef_7f01, + 0xe655_bf8e_0247_a719, + 0x1fd0_e3ae_2786_ca41, + ]), + F::from_raw([ + 0x2a05_c36b_1776_96a1, + 0x2e7b_50f2_558c_bf86, + 0x0e6d_174c_9664_9a3d, + 0x2052_c36e_6b89_e184, + ]), + F::from_raw([ + 0x158a_47f3_dc9b_187d, + 0x9f59_8187_578d_2fd1, + 0x69d6_2f5c_25d1_cb82, + 0x12c7_be80_bf7f_f89d, + ]), + F::from_raw([ + 0x44ad_a63f_0dc8_8482, + 0x8a02_2400_3bc7_24f0, + 0xf9ee_1e5b_b9bc_ec09, + 0x1e71_2263_67cf_0e67, + ]), + F::from_raw([ + 0xe2a5_61d6_2d47_32f9, + 0x6a7c_84e6_747a_8b1f, + 0xa9ca_9dd1_4d8d_9c54, + 0x1b1a_efde_27d4_009d, + ]), + F::from_raw([ + 0x99bb_a3b0_901f_5b4f, + 0xdb03_9945_9e4e_0086, + 0xd19d_64c6_8bfd_2467, + 0x28fb_6fbe_80d1_61b9, + ]), + F::from_raw([ + 0x137b_0231_4914_ce19, + 0x716f_b1c8_7571_f71f, + 0x5980_5f96_d8a1_d9b7, + 0x2703_4c9a_18b5_5f52, + ]), + F::from_raw([ + 0x9130_dc9f_6102_c8ae, + 0xafd9_11d9_d74f_6b96, + 0x9cec_94c7_ab90_989c, + 0x2e6a_de49_ee96_d2b9, + ]), + F::from_raw([ + 0xc3cc_faa2_5e81_9665, + 0xa941_6d69_3329_14e0, + 0x68d4_f311_4902_e480, + 0x1efa_ca3d_5ae8_7a5f, + ]), + F::from_raw([ + 0x2ad3_8e17_b660_b8e0, + 0xb0b5_23c4_3f61_778b, + 0x3919_5ab9_8b2f_4fe7, + 0x1dbf_a12b_b1e7_b0cf, + ]), + F::from_raw([ + 0xfe33_7e64_d998_1dca, + 0xa5ac_4e2a_81c8_ba83, + 0xaa39_5e9d_acc6_7153, + 0x1d21_adc5_95bb_3462, + ]), + ], + [ + F::from_raw([ + 0xa7eb_62a9_9c62_a4e0, + 0x2aa7_ea98_81b0_a4c8, + 0x57aa_61b9_3f71_f8ea, + 0x183a_031f_6528_3a2c, + ]), + F::from_raw([ + 0x004a_1fb5_7005_b3f6, + 0xde81_a58c_e5a2_c4fa, + 0x23dc_5679_872d_9bbf, + 0x0550_5d70_3f7f_ffd3, + ]), + F::from_raw([ + 0x7d46_3fd0_2c66_5b2d, + 0x74ea_e4df_a857_bc92, + 0x5fbb_d374_f111_a549, + 0x2fa9_4b93_636e_509a, + ]), + F::from_raw([ + 0x3d18_3d38_fdbb_60d8, + 0x2916_8ad4_68c9_f343, + 0x288d_bcc4_174d_2eeb, + 0x2f18_24ef_ee6b_90c7, + ]), + F::from_raw([ + 0x4d4e_a123_6a77_d294, + 0x4586_d79b_f4ed_d4ce, + 0x252a_365a_6536_b5ee, + 0x2f8b_0043_c7ab_7df1, + ]), + F::from_raw([ + 0x06ea_da31_27f4_b346, + 0x8042_0f92_541d_0dcb, + 0x8df6_1a3e_eee9_2a7a, + 0x2a06_6fa8_1175_4a4c, + ]), + F::from_raw([ + 0x8dd9_72b7_e9d9_e144, + 0xf74d_a812_7ece_fbe7, + 0xa85d_ca41_7491_88c4, + 0x2dd4_8397_5bf2_124f, + ]), + F::from_raw([ + 0xc41e_65e0_a70f_7a8c, + 0xd6dc_bce9_d23d_c4a3, + 0x1647_46fa_30f7_835e, + 0x0387_5224_d3d0_b40a, + ]), + F::from_raw([ + 0xe774_772c_6514_c1c6, + 0xc736_cbfe_6483_9b0f, + 0x066e_7046_d93c_e678, + 0x2984_8fee_6265_08de, + ]), + F::from_raw([ + 0x20b0_067c_1256_7a3b, + 0x12a2_7e7f_a6cb_d78d, + 0xa515_c855_0248_e344, + 0x28a7_d8ae_abfc_1efa, + ]), + F::from_raw([ + 0x2339_61e6_415f_92b7, + 0x6ffc_24dc_149a_d29f, + 0x2b1f_98c9_a1e4_95b3, + 0x1950_7b15_686e_20fe, + ]), + F::from_raw([ + 0x4144_945b_0075_cb95, + 0x908d_929f_f863_9bdc, + 0x4be2_f676_b267_ea44, + 0x0a61_b968_f505_e070, + ]), + F::from_raw([ + 0x78d7_a768_5905_9f5a, + 0x330d_42b3_1bd5_c8a4, + 0xabc4_d5cd_2e8d_2b5d, + 0x1097_5a7f_7060_b302, + ]), + F::from_raw([ + 0xb85f_be18_b4c8_9a2c, + 0xbf75_c90f_73c5_bc30, + 0xd621_634f_43b2_4232, + 0x23d1_ef3b_42d0_c153, + ]), + F::from_raw([ + 0x5dcb_7f8c_63b7_aa74, + 0xfe02_b825_6d2c_9c18, + 0xd296_4117_894f_3c43, + 0x15b6_6bd3_ea79_86c7, + ]), + F::from_raw([ + 0x3261_9442_b8fd_f8e4, + 0x7255_af54_c53f_732d, + 0xa6a5_b961_fbd9_45f0, + 0x09e4_6a8c_efa8_9c5c, + ]), + ], + [ + F::from_raw([ + 0x33b8_79e4_af6c_6bd9, + 0xc0a6_33cd_6953_8cb6, + 0x121c_bfbd_1c08_3459, + 0x0e72_db48_726c_3049, + ]), + F::from_raw([ + 0x1214_2016_a64d_7846, + 0xcc44_4330_c3ed_4458, + 0x38ac_fc1d_ebd3_9a91, + 0x16f0_5309_db91_b39d, + ]), + F::from_raw([ + 0x0f5a_6606_dd0c_dfc5, + 0xaccb_2d87_fd6c_e427, + 0x9795_f83c_9d69_c8b3, + 0x06ff_fdee_b381_cbf3, + ]), + F::from_raw([ + 0x5cf3_9fa6_d384_e77d, + 0x5fca_1a22_11de_1f90, + 0x4af6_1bb2_f75c_65cf, + 0x1a25_2b1f_347d_8d89, + ]), + F::from_raw([ + 0xfb9c_1f27_8772_10ed, + 0xd2d9_3e09_22da_b327, + 0xaaf7_e1c5_95bf_155a, + 0x2315_61bb_687a_5aa8, + ]), + F::from_raw([ + 0xddaa_351e_7007_913d, + 0x4be3_2f03_6e80_b42a, + 0x6da7_9f63_04cd_a6b0, + 0x00f8_d403_0eac_93ec, + ]), + F::from_raw([ + 0xde3f_2cca_6cdc_80d2, + 0xcb7b_479b_e123_e003, + 0xe9d3_dd48_bb57_022c, + 0x2f49_ddf5_65cb_5324, + ]), + F::from_raw([ + 0x1165_6a43_5bf0_684e, + 0x31f9_d7c3_d76f_ee98, + 0xe304_4063_7725_8655, + 0x1dfe_e898_7696_c32d, + ]), + F::from_raw([ + 0x387f_c29d_4dc7_4380, + 0xf3a4_3c23_83ce_ef12, + 0x6892_ccea_e218_f7fd, + 0x0582_17bd_eb30_6554, + ]), + F::from_raw([ + 0x54ba_2423_560d_4f55, + 0x3b5c_f563_3e19_9ebf, + 0xc7d7_0f1c_a1f7_2b9e, + 0x05f8_4239_2a9a_07d4, + ]), + F::from_raw([ + 0x2ebb_69b9_d175_2e4b, + 0xe603_aea0_72b7_712f, + 0xbd5c_36ec_c676_c2fe, + 0x188b_0807_b791_05dc, + ]), + F::from_raw([ + 0x0af1_3cdb_0055_548e, + 0x037c_52ef_cbb4_93f1, + 0xec6f_695e_0792_9a36, + 0x1103_f6ea_09ca_e621, + ]), + F::from_raw([ + 0x5372_be43_7b0f_c08c, + 0xa22f_8a0b_f037_45d1, + 0x2924_8b4a_ed61_9c81, + 0x1a40_f8ba_3192_f0c9, + ]), + F::from_raw([ + 0x20e5_1821_645f_9d2f, + 0xa347_7da2_1520_0ba4, + 0xf5c9_a889_1cbf_3dc7, + 0x0088_23b7_625f_84a5, + ]), + F::from_raw([ + 0xe443_5bc6_161f_3f32, + 0xd25f_c6c6_267b_6f7d, + 0x031d_8799_4f26_4905, + 0x052a_494a_f3ec_def5, + ]), + F::from_raw([ + 0x4c8e_53d5_0f15_77be, + 0x69a5_4292_3111_3dff, + 0x8d0c_6c59_856e_6ba3, + 0x0fc8_cd19_ee31_da01, + ]), + ], + [ + F::from_raw([ + 0xd54a_02e8_ff2d_e3c0, + 0x89aa_0725_b446_c9e8, + 0x2610_3560_0d99_b113, + 0x0bec_e887_08ff_447f, + ]), + F::from_raw([ + 0x0d9c_a1bf_6dc2_ef92, + 0x7154_4f8d_feca_0225, + 0x1f5e_d0ab_6c4c_dfb7, + 0x2bc2_fc2f_7c93_245f, + ]), + F::from_raw([ + 0x0310_dfa1_bf80_5fd6, + 0xf86d_e80d_901b_b697, + 0x9907_af42_6801_01e4, + 0x22b1_6f83_25f2_a2c6, + ]), + F::from_raw([ + 0x70ae_6449_f25a_6cb6, + 0x6ae7_ff36_c0fd_acd8, + 0x414c_280c_fd8d_ec81, + 0x2782_823d_5188_cf5d, + ]), + F::from_raw([ + 0xbece_5c5f_e23d_b5bf, + 0xb2d9_c24f_4591_20de, + 0x45b0_6a1f_7415_98df, + 0x12da_3c90_acc4_189b, + ]), + F::from_raw([ + 0x111b_5510_6b5a_df0b, + 0x9726_bac7_bb70_78f4, + 0x8f75_4643_481d_0808, + 0x2d81_a5f9_fa41_73f5, + ]), + F::from_raw([ + 0xb758_fc32_cb60_0c6f, + 0x875f_0afa_5121_9ab2, + 0x1e26_3788_5d4d_2904, + 0x286d_bc99_0140_046e, + ]), + F::from_raw([ + 0xe839_7f8f_c115_197d, + 0x54ca_6a42_5826_0375, + 0xd042_2636_2e73_219b, + 0x20e7_a367_4a06_6766, + ]), + F::from_raw([ + 0x3c3c_1247_6913_fcdf, + 0xf153_14ea_e937_b39a, + 0xe0c1_dc51_4de4_c642, + 0x2289_f322_7f4c_eeba, + ]), + F::from_raw([ + 0x06a1_1807_53aa_4616, + 0x4a09_3dd0_4524_0167, + 0xf27f_a197_0426_f9d4, + 0x2132_51e3_0a76_1990, + ]), + F::from_raw([ + 0xf276_59c1_3f30_19ee, + 0xa2df_2aaf_a1ef_69f7, + 0x3cd3_1db2_48c7_b627, + 0x0916_5561_2a93_f5be, + ]), + F::from_raw([ + 0x4f8b_1625_06b8_d5e9, + 0xbb42_df76_c12b_10f1, + 0xf194_1195_b02e_6463, + 0x1af6_0faf_34b0_5755, + ]), + F::from_raw([ + 0xacff_016e_af10_7fd8, + 0x903b_fb46_db3c_7a23, + 0x0c0d_3b70_123b_7731, + 0x21b4_1d0e_ffd2_b044, + ]), + F::from_raw([ + 0xe5b7_a56c_408d_84b4, + 0xcad3_1638_c4e3_8cec, + 0xdde8_2c8f_1e10_22c5, + 0x16a0_876c_96d4_5b59, + ]), + F::from_raw([ + 0x79f3_164b_690f_6407, + 0x2c5f_dede_1701_5a7d, + 0x9d42_a62a_b4f6_41d6, + 0x1853_29f9_e4aa_85d4, + ]), + F::from_raw([ + 0x1552_4969_639e_a3e1, + 0x34d2_d8ba_793d_601f, + 0x9563_35d1_6ae7_1525, + 0x123f_208d_b0c4_ef54, + ]), + ], + [ + F::from_raw([ + 0xacd1_3b09_739c_263a, + 0x784c_80ef_4f4b_b032, + 0x0da7_6be7_8853_81c1, + 0x1aa5_6542_78de_2238, + ]), + F::from_raw([ + 0x0e0d_7f33_16ea_6ce8, + 0x44a1_4c78_ca87_d1e3, + 0x10ad_8e04_92e8_2d10, + 0x0955_b8a1_677a_5b63, + ]), + F::from_raw([ + 0xf0e6_a6e8_8f7c_0e58, + 0xd18f_9b6f_e995_a575, + 0x9275_6b51_7392_8904, + 0x0c7f_efd4_edd4_ba7d, + ]), + F::from_raw([ + 0x08de_d150_3eca_fb06, + 0xc5cf_a588_fbe5_490f, + 0xe2af_2aec_8a5d_b1eb, + 0x116d_1889_97ee_c6a1, + ]), + F::from_raw([ + 0x5393_ac8f_fe94_7ea6, + 0x6e28_b100_18f3_e7f4, + 0xf0b3_94b6_a3cc_d2d9, + 0x258d_2eed_2c2d_e759, + ]), + F::from_raw([ + 0xafb5_e888_349a_6c44, + 0xb12e_7fd7_ffe6_b9b3, + 0xaa7e_db78_fbfb_5d7f, + 0x229d_e8c2_965a_eac1, + ]), + F::from_raw([ + 0xca1a_03d7_518f_83ab, + 0xda71_702c_0e9d_41c6, + 0xf637_2170_d4c5_95ad, + 0x0b1f_b0fe_afe9_8d6c, + ]), + F::from_raw([ + 0x9067_80ca_636c_4cbb, + 0xe6b1_53d8_80d8_acf6, + 0xf2d0_f28f_2e32_f5cc, + 0x285a_05be_9b2d_fd8a, + ]), + F::from_raw([ + 0xfe85_7596_9ce4_f295, + 0xdff9_1854_34f3_a4e4, + 0xee2b_7609_9db0_3d74, + 0x1d82_40e9_9023_94ed, + ]), + F::from_raw([ + 0x4146_78b3_12d5_7f93, + 0x1248_6448_5108_31e6, + 0x3319_8934_9ec4_bd9b, + 0x2160_be82_33ce_1b0b, + ]), + F::from_raw([ + 0x6c8f_18a5_adab_52fe, + 0x0db9_96cd_5b5d_ff42, + 0xfc5b_f2cc_815e_e791, + 0x2929_b839_d44b_d2b3, + ]), + F::from_raw([ + 0x99de_0334_5920_ec08, + 0x91f9_7725_e469_82d1, + 0xe5f0_dead_5516_e94b, + 0x07d0_d43c_3f63_3701, + ]), + F::from_raw([ + 0xcce3_78a7_f023_93ef, + 0xfd52_bceb_ac12_70b1, + 0x53b3_7132_622f_ddc5, + 0x0b99_c27d_aff9_0cc0, + ]), + F::from_raw([ + 0x1f41_28c7_f3d7_8691, + 0xce78_9650_83b8_53ac, + 0x02cc_a7e9_565e_edfe, + 0x2e95_2dfc_c924_c081, + ]), + F::from_raw([ + 0x3f7e_9c23_b55c_ca5f, + 0x35e5_0137_6b52_99cd, + 0x6d6d_26f3_d746_20ec, + 0x2190_b77f_9633_9106, + ]), + F::from_raw([ + 0xb081_5f2a_9116_8652, + 0x5510_208a_aebb_5dce, + 0x0d0b_0d16_1f7b_a719, + 0x05be_919c_52d2_f1dc, + ]), + ], + [ + F::from_raw([ + 0xa7be_cc8f_f9a0_672f, + 0x9df9_97dc_bf93_df22, + 0x22cb_fffb_76e6_f30f, + 0x0b4e_4b3c_a8aa_8346, + ]), + F::from_raw([ + 0xb764_08d1_1614_4fd4, + 0x3335_82e5_f6ee_1c3c, + 0xc45d_51e5_363f_94f9, + 0x1620_522a_88c3_b531, + ]), + F::from_raw([ + 0xe893_ef19_e3c7_390a, + 0x2b38_e479_d8ad_7074, + 0x8871_5f58_41a6_90cb, + 0x0f44_2ea2_6883_f8e1, + ]), + F::from_raw([ + 0x0303_5d53_b59b_a710, + 0xc1e0_e4d1_bb03_130e, + 0xad81_ddf0_e7be_dd80, + 0x1a85_5bfb_e80a_7886, + ]), + F::from_raw([ + 0x9149_a17c_aa20_b66d, + 0x036c_c14b_1ce3_c7b1, + 0xd609_8de0_b812_6649, + 0x06a9_3868_6122_33e3, + ]), + F::from_raw([ + 0x83de_e528_130d_4c44, + 0xc4a6_7c52_4267_c45a, + 0x9266_12e9_c066_1665, + 0x0671_4249_62e9_23da, + ]), + F::from_raw([ + 0xea32_b5f4_483b_6d45, + 0x5b82_426e_00ae_6cec, + 0x775c_d4a7_1a8c_5d45, + 0x0b11_9799_f6ee_67e2, + ]), + F::from_raw([ + 0xf123_3213_796c_165b, + 0x9064_2b77_cafa_7741, + 0xea14_16dc_a0f7_ea51, + 0x26d4_68d5_5dc3_1cd5, + ]), + F::from_raw([ + 0x5d2f_7129_eae8_0325, + 0xbc1a_41ea_ca53_1c7f, + 0x8010_494b_e0ae_d24a, + 0x276f_cfe1_7ef8_2181, + ]), + F::from_raw([ + 0x81ab_efc1_8c21_e93b, + 0xf510_0568_d71a_6d1e, + 0xbea1_455c_c92b_6d73, + 0x238d_40c8_36db_7215, + ]), + F::from_raw([ + 0x34d7_6ce3_99fb_49b9, + 0x5c7c_db02_30cc_8e0e, + 0xdfc7_dcac_cd4a_b7ad, + 0x064c_4fd1_c50e_f587, + ]), + F::from_raw([ + 0x7b66_997b_07b2_a425, + 0x9431_ecb5_7f3d_b1ba, + 0xdc38_474a_7540_6af2, + 0x0371_8669_f16f_e30a, + ]), + F::from_raw([ + 0x5e94_5666_2421_098f, + 0xf507_3fc5_0c47_db88, + 0x2d62_1a27_4a32_5c49, + 0x19f1_04f9_0bbc_0376, + ]), + F::from_raw([ + 0xb760_229c_0ce2_7ba7, + 0x65fd_7591_bd84_d535, + 0xbea4_ef9a_e6cb_9b8f, + 0x2486_c93e_ffa2_4890, + ]), + F::from_raw([ + 0x924b_7b92_d01e_cbf5, + 0x1d7b_caa0_63a8_18c5, + 0x269f_b022_937c_78a9, + 0x29ef_7d3e_a32d_9632, + ]), + F::from_raw([ + 0x84cf_2050_4a02_52f7, + 0xff0c_152c_b881_9e86, + 0xabc8_d7c5_49cb_b1be, + 0x26d9_1e7c_ce1d_8dee, + ]), + ], + [ + F::from_raw([ + 0x6b9b_09c3_934a_d167, + 0x415c_4ad1_54eb_5361, + 0x54ec_885a_f2a3_8d3e, + 0x0248_d089_93b5_ebb2, + ]), + F::from_raw([ + 0xe9cc_d7dd_0251_8db0, + 0xa053_8a7d_f6d2_5dfd, + 0x9bca_7431_dcd2_31d5, + 0x20ae_46ea_2b70_1d37, + ]), + F::from_raw([ + 0x7df0_f478_ec51_db0c, + 0x9614_950d_8e39_1f52, + 0x4919_3e5c_0248_680b, + 0x0a48_4d6f_4b86_578d, + ]), + F::from_raw([ + 0xe5b8_ca92_bcf8_4f3e, + 0x2b04_bf97_eca7_7613, + 0xc2b3_5c01_e28c_5697, + 0x0671_7f5b_869d_2656, + ]), + F::from_raw([ + 0x1e51_1817_c4c4_a350, + 0xa329_d633_ac53_3e81, + 0x92dd_2a76_fccf_0119, + 0x0378_3c71_3038_e548, + ]), + F::from_raw([ + 0x2cb3_1f75_2e4f_9d34, + 0x7376_afde_0da0_e70e, + 0x9412_3557_19d7_9deb, + 0x0f13_bbfe_c1c7_fa9b, + ]), + F::from_raw([ + 0xff6c_aec9_3a61_82a0, + 0xcfeb_26f1_faac_f9bf, + 0x9377_0f16_94a3_7887, + 0x251a_dccc_e531_7c98, + ]), + F::from_raw([ + 0x83b9_af12_84f6_3dbf, + 0x95be_6f6c_aaa1_fdc9, + 0xa9e5_72c7_32e7_aa85, + 0x0f82_5a06_fc69_017c, + ]), + F::from_raw([ + 0x3f1c_d6d2_51eb_a933, + 0x8fdc_d61f_74eb_b24d, + 0x5897_5d96_ffb8_95de, + 0x0a3c_f2fb_30ad_2c73, + ]), + F::from_raw([ + 0x23d6_f91b_9bf7_7a42, + 0x13bb_d7df_46d1_fd91, + 0x019e_c04c_54d7_446c, + 0x0251_b2e0_61b1_2c56, + ]), + F::from_raw([ + 0x043c_a471_bcc2_d379, + 0x12ec_8de2_8180_75fb, + 0xba6d_0463_be4c_a34e, + 0x2951_702d_fa12_6f50, + ]), + F::from_raw([ + 0x43b7_089e_ab71_5698, + 0x28a5_29bb_951a_3556, + 0xe646_5ccd_361b_57ca, + 0x182c_9f08_809a_2953, + ]), + F::from_raw([ + 0x85c1_1d5a_e6b6_f850, + 0xf463_0db6_292f_1d60, + 0x9fb4_5008_8cdb_061d, + 0x0dea_1f64_0e09_dcd6, + ]), + F::from_raw([ + 0x8aa1_bb6f_49e1_7c6d, + 0xdabc_ce70_70c5_09e7, + 0x1ec7_0253_bc16_022d, + 0x1574_10eb_e0e8_a0c8, + ]), + F::from_raw([ + 0xb594_90aa_6ff5_58ab, + 0x6f79_7cfe_1f4b_4a55, + 0x6163_ef64_7d60_969d, + 0x117b_09b3_4738_397c, + ]), + F::from_raw([ + 0xb9fa_c367_8a76_2fe7, + 0xa61c_bd4d_1a54_bb5f, + 0x4aec_578a_73d8_6e4d, + 0x1573_7e5a_5b31_340f, + ]), + ], + [ + F::from_raw([ + 0x256e_dc3e_b713_f115, + 0xec5f_0be0_0025_5a3d, + 0x5db2_00d1_264c_03c1, + 0x196b_0672_513f_279f, + ]), + F::from_raw([ + 0xbb6f_2b18_c076_f698, + 0x8a09_5e69_e10a_3a56, + 0x0cdb_18e6_89d2_e067, + 0x0bbd_ce03_8ba7_9230, + ]), + F::from_raw([ + 0x8b40_974a_53dc_dac6, + 0x060b_e0eb_c3f6_faa9, + 0x7c55_ccb2_cc02_c666, + 0x08e4_fb5e_144e_2d86, + ]), + F::from_raw([ + 0xbda7_d56a_2d6b_aa68, + 0x27a2_ac1a_fef9_dae8, + 0x23b5_46a4_0516_f9ad, + 0x254c_c53a_e8ae_dc83, + ]), + F::from_raw([ + 0x91ca_61cb_0028_7204, + 0xfd93_6ca3_76a8_bf34, + 0x8de7_2810_20ad_784d, + 0x1a2c_40f1_984d_d233, + ]), + F::from_raw([ + 0xdc03_a3a9_bf53_2100, + 0x3794_9942_80c6_33b7, + 0x0f98_b6bb_ee9b_a25f, + 0x0b02_a14f_5ed5_fbe3, + ]), + F::from_raw([ + 0x6a98_6948_0744_160e, + 0x0581_663d_cdc7_7e5b, + 0x6aef_3fd0_e965_f2bd, + 0x1522_8b44_db99_15e5, + ]), + F::from_raw([ + 0xc605_cca7_4176_6317, + 0x32ea_1048_f0a4_5c3e, + 0x98b1_e19c_0e2b_2d25, + 0x24ef_8fa2_3231_f34c, + ]), + F::from_raw([ + 0x2f76_6b7b_dd45_66ac, + 0x2738_a6e9_4fde_2ec7, + 0xd0b5_7f22_fc07_ca33, + 0x25cd_05a9_267e_21e2, + ]), + F::from_raw([ + 0x13ad_ad98_acf7_1272, + 0x3a66_3698_4c8b_ae01, + 0x6313_f7d6_e519_9ed2, + 0x0cee_a6b6_d86d_de8d, + ]), + F::from_raw([ + 0x492e_a402_f901_4657, + 0x2b6e_f465_bde4_b950, + 0xf1d7_7f6f_1a14_726d, + 0x2263_c070_1b49_306d, + ]), + F::from_raw([ + 0xf084_c38f_005e_e10e, + 0xe443_d181_6e16_a3c1, + 0x48f9_8a46_3036_9337, + 0x2fb6_56f4_df02_8412, + ]), + F::from_raw([ + 0x4aa2_45c6_f3a9_6619, + 0x60bc_d459_8e64_1d89, + 0x4016_757e_12e6_4147, + 0x0e6f_9efe_b418_fa0b, + ]), + F::from_raw([ + 0xea94_36e2_cdbb_8314, + 0x5f82_72f3_88d7_b512, + 0x0044_151b_b698_f576, + 0x0249_6c73_9951_24ae, + ]), + F::from_raw([ + 0x6626_79e3_61bd_695f, + 0xebb1_6f4f_2112_1a3f, + 0xbecb_1940_994f_1cdc, + 0x0df3_c49b_c65b_7087, + ]), + F::from_raw([ + 0xf7ae_28b9_fbb4_b312, + 0x8aaf_f713_1761_a180, + 0xaea2_ad4d_f26c_3762, + 0x0234_3f6b_8018_6e6c, + ]), + ], + [ + F::from_raw([ + 0xc61b_2fb0_be85_46e7, + 0xfc3a_30f7_8266_d8e7, + 0x6481_0daf_baa4_0ce8, + 0x276b_8652_e613_3ec1, + ]), + F::from_raw([ + 0x6790_9ead_95ea_85fd, + 0x14bf_00da_1194_0184, + 0x7e56_f002_df7b_0042, + 0x2bf0_9a23_5c89_febe, + ]), + F::from_raw([ + 0xdbff_08ad_95b7_3e73, + 0xf4b6_e1fb_368c_abc0, + 0x7581_b609_ac57_2bdc, + 0x1ef9_064c_20f8_3e8c, + ]), + F::from_raw([ + 0x646b_c1dc_b8cf_8e83, + 0xf5b0_f55d_ac02_3e27, + 0xa4e8_0b3c_937e_1906, + 0x210b_418e_297e_ee3d, + ]), + F::from_raw([ + 0x6aff_5993_665b_eebd, + 0x1a7d_019e_89a6_d6f7, + 0x0675_3624_075d_e077, + 0x2ca9_e6ee_5998_c2ad, + ]), + F::from_raw([ + 0x51dd_c7f5_256c_86a0, + 0xb0ff_ea7e_e776_4b1f, + 0xd562_2657_5f1e_5c4f, + 0x174a_e2a5_db32_dca4, + ]), + F::from_raw([ + 0xef52_040d_8bbd_9025, + 0x546a_5235_d229_52cd, + 0x4d63_8995_f693_f324, + 0x1862_319c_ee8d_e3ee, + ]), + F::from_raw([ + 0xb263_390e_caf9_cd49, + 0xe032_128c_ce09_179b, + 0xb66c_50f1_40b8_b579, + 0x1221_906c_9979_8cde, + ]), + F::from_raw([ + 0x0913_7e3f_8a12_2f1f, + 0x53d0_3192_6fb0_d14d, + 0x3b29_c69c_de8e_0bbb, + 0x084d_d25a_4d14_1a72, + ]), + F::from_raw([ + 0xd324_d6e3_3138_1411, + 0x6ed2_c794_7b01_769e, + 0x9d3a_c654_d445_0a38, + 0x2934_1ad0_4e73_a6e6, + ]), + F::from_raw([ + 0xcea1_7633_9993_dc08, + 0xfdf6_e3d7_18ea_c4e5, + 0xeef8_d0fb_4e72_e46b, + 0x1aab_0dc9_6516_1f77, + ]), + F::from_raw([ + 0x0999_85c7_00d2_6984, + 0x675f_d5df_3615_5a66, + 0xfe3e_568f_e27a_ce0b, + 0x1852_c126_862b_742f, + ]), + F::from_raw([ + 0xeed9_6a93_1202_f0c4, + 0xe8f0_d7b4_8c4e_fb62, + 0x0fbe_2241_77ac_7a16, + 0x026e_abee_5c1a_5c1b, + ]), + F::from_raw([ + 0x07d7_6113_bcda_a492, + 0x4b41_c3e8_ed9c_a5a7, + 0x6a1e_b65d_b5fa_72a5, + 0x268b_607a_7549_8aa8, + ]), + F::from_raw([ + 0x180f_3a9b_d502_9beb, + 0xf94d_1077_ddbf_456a, + 0xbfc0_ec7b_6be5_6add, + 0x10a5_051f_064f_edc0, + ]), + F::from_raw([ + 0x5471_dd85_ff64_1214, + 0x9c22_066c_b3dd_0f76, + 0x8d5e_5335_9bce_ca5a, + 0x2c27_938c_e4e1_e0f9, + ]), + ], + [ + F::from_raw([ + 0x7f95_bafb_d367_a3ff, + 0x490f_1c20_d605_f62b, + 0x8ed0_dbc2_903c_ecdf, + 0x0603_90a2_0345_9963, + ]), + F::from_raw([ + 0x480d_010b_effe_c7cb, + 0xcd3e_bdf0_2263_8f5e, + 0xa13f_f62b_c3cb_d0eb, + 0x2109_e7dc_4aaf_6cb2, + ]), + F::from_raw([ + 0xb0a6_703e_ebe3_ed2c, + 0x35ac_8a16_7282_b44c, + 0xbdaf_48cd_5c19_432d, + 0x0106_959e_10ce_6819, + ]), + F::from_raw([ + 0x17a1_9ee9_3c8d_cb40, + 0x50df_7f76_6be9_0c83, + 0x1591_bc58_8392_605b, + 0x276a_cf8b_ce26_b932, + ]), + F::from_raw([ + 0x8d2c_c4ae_a3dc_924b, + 0xc043_21d2_2340_e5ee, + 0x5e03_4079_8d10_b774, + 0x2625_cb1b_e09f_f63c, + ]), + F::from_raw([ + 0xca3d_b3a6_9ddc_ff22, + 0xfad1_ac9b_afc7_5c76, + 0x6feb_991a_4fc5_5f02, + 0x1752_23b5_6bbc_74a4, + ]), + F::from_raw([ + 0xe0df_6c31_ea6b_9970, + 0xd561_9bae_25fe_c69b, + 0x3e74_2213_606f_1558, + 0x22cd_6e17_bd14_26b1, + ]), + F::from_raw([ + 0xd3e6_afdf_283b_1836, + 0xbdb9_1a0f_b9f3_a4ba, + 0xe629_5611_e360_36aa, + 0x0333_0791_7f2f_058a, + ]), + F::from_raw([ + 0xa819_9363_2ba4_114b, + 0xbf94_4c68_157c_4135, + 0xa8ab_91df_7afb_9d4e, + 0x0c74_e27d_536a_6274, + ]), + F::from_raw([ + 0x1369_ca5d_87a9_a809, + 0xef74_875f_b213_f076, + 0xcb3b_4a56_39ce_7825, + 0x11b2_212a_08cb_877c, + ]), + F::from_raw([ + 0xebce_eb63_8ba6_eef8, + 0x005d_ceb1_697d_9623, + 0x15d4_c8dc_0f20_c3c3, + 0x2c8c_8d42_080e_2e96, + ]), + F::from_raw([ + 0x111e_206d_c19f_7be5, + 0xd1fa_3bf6_ca50_8399, + 0xa08d_463b_9a3a_3a1c, + 0x0d61_124d_06cd_75ba, + ]), + F::from_raw([ + 0x91fb_5924_a073_40c0, + 0x87e4_b08f_8fdc_991e, + 0xd5eb_3540_6b0c_d46b, + 0x18a8_cce9_e7aa_6df3, + ]), + F::from_raw([ + 0x3148_5d7c_0f07_1a80, + 0x6648_b9a0_7fc1_0aac, + 0x40fb_71f1_51e3_e534, + 0x0145_3226_c757_42b8, + ]), + F::from_raw([ + 0x548e_0c08_cfb8_e60d, + 0x4f66_b921_c80f_be68, + 0xb551_7add_b97a_d913, + 0x0eb0_5f52_0679_35d0, + ]), + F::from_raw([ + 0x2e02_17d3_8db4_020a, + 0xfea8_22bc_f612_d7e8, + 0xfbe3_da64_0fdc_df02, + 0x1788_3a0f_afa3_7d03, + ]), + ], + [ + F::from_raw([ + 0x5c48_6363_3b0e_19c7, + 0xd0ea_9971_7705_95a8, + 0x050b_d2ec_21b1_8bb9, + 0x0751_6cbb_3f67_dbbc, + ]), + F::from_raw([ + 0x090c_550c_30bf_e2d3, + 0x457b_aeea_ff2a_e9f0, + 0xa59d_a67e_1c2a_223e, + 0x1f86_ef94_7144_3b26, + ]), + F::from_raw([ + 0xf38c_de33_c69e_9f03, + 0x85f0_2613_d9b4_8612, + 0xab69_709d_4fed_9066, + 0x0b84_ec63_55cb_fb43, + ]), + F::from_raw([ + 0xef66_ca98_ce78_9730, + 0xa1b9_ef80_65cd_08cc, + 0x23c5_bdb4_e9d2_fc71, + 0x1ac0_16b4_0d30_d267, + ]), + F::from_raw([ + 0x467c_c4bf_aeb5_85f1, + 0x3381_be96_12e8_3815, + 0x6176_a004_568c_ea6c, + 0x10b2_fa89_de45_4560, + ]), + F::from_raw([ + 0xca2e_6631_b404_d5e8, + 0xe510_639b_3435_4e53, + 0xfd4c_b75c_e7f2_6710, + 0x00bf_5674_a5ea_1ce6, + ]), + F::from_raw([ + 0xd046_68e0_4c01_37b8, + 0x9714_7a3e_8664_866d, + 0x3ba2_1c5e_c1f2_8dab, + 0x2fe1_4399_93bd_3378, + ]), + F::from_raw([ + 0x52df_4896_fdcc_4034, + 0x2853_628f_4378_a74a, + 0x6768_a3a9_c7f6_5669, + 0x2f40_3be7_d38c_a733, + ]), + F::from_raw([ + 0x3d48_decd_8817_db94, + 0x33c3_e23f_e89e_7e22, + 0x25d2_42d1_d704_54b8, + 0x0e1c_171b_aa0b_a3e8, + ]), + F::from_raw([ + 0x1ff3_1a62_f6e4_fb87, + 0x9f83_5913_f73b_71d5, + 0x9d27_e078_3fc6_0340, + 0x172f_c861_c822_a045, + ]), + F::from_raw([ + 0x51f5_b91f_0823_523c, + 0x6642_cd9b_0a97_8c02, + 0x8cbe_31dd_75b3_3d9d, + 0x1bb9_e245_4a33_c3c0, + ]), + F::from_raw([ + 0xefc7_2034_308d_4c3a, + 0xd6cd_5b4a_7866_2625, + 0x3dc6_94f4_d998_46cc, + 0x2929_3f84_22d4_f96e, + ]), + F::from_raw([ + 0x4e13_f1d9_c694_9d13, + 0x2994_edb6_4baa_4379, + 0xf37d_475c_8306_9053, + 0x29b3_78f2_446a_9a31, + ]), + F::from_raw([ + 0xcfc2_0fd9_8c19_616e, + 0xcf55_a8f9_5556_f2aa, + 0x7b76_1794_760e_090a, + 0x018a_82c7_4bad_8aac, + ]), + F::from_raw([ + 0x7db5_4755_921b_1644, + 0x9e46_618c_f492_1863, + 0x9f1c_639c_ed48_dd8c, + 0x2c1f_c04d_ed87_e37d, + ]), + F::from_raw([ + 0xcad7_d5ef_e674_b2be, + 0xe777_8bcf_a3dc_0377, + 0xb3ff_1ce6_d277_2502, + 0x29ea_0e1e_015e_5cae, + ]), + ], + [ + F::from_raw([ + 0x8ec3_7968_610f_3349, + 0x03d2_28d5_939d_ea92, + 0x16ce_3371_f140_a659, + 0x2a17_53c6_a4c7_c437, + ]), + F::from_raw([ + 0xaa68_e852_6c09_e1df, + 0xb102_9350_d474_6394, + 0xd77e_f1ef_c595_0519, + 0x02d9_4aa3_bb54_98d0, + ]), + F::from_raw([ + 0x88a7_be85_0485_dbf0, + 0x6c2b_04b8_db60_27ee, + 0x0a11_780e_abd8_e8f9, + 0x08f2_6908_4ee6_3762, + ]), + F::from_raw([ + 0x060d_fb45_d82e_7db2, + 0xa426_1c24_19f3_e055, + 0x5093_d3b5_f898_a111, + 0x03ab_f553_fb5a_4b9d, + ]), + F::from_raw([ + 0x27fc_7a70_bfbc_bbb0, + 0x6be7_c714_d079_5364, + 0xc9be_2926_6233_61fc, + 0x1b9d_84d1_89c5_a22b, + ]), + F::from_raw([ + 0x1ec7_3513_65c8_85c1, + 0xa60b_cf5c_b72c_41a6, + 0x496b_4046_294d_b690, + 0x23af_c200_414f_23e7, + ]), + F::from_raw([ + 0x1abd_d27c_e145_3799, + 0xa0dc_d5fe_9d6c_2acf, + 0x6e1a_3731_8938_d4dd, + 0x26a5_ce6e_a63b_fd9e, + ]), + F::from_raw([ + 0x70c3_454e_f255_f9ce, + 0xa694_9903_1691_8ad6, + 0x9022_5223_7859_f0b8, + 0x227f_c041_2f71_fbe4, + ]), + F::from_raw([ + 0xa09a_90f9_6c67_2bec, + 0x568f_75d7_249d_ea4d, + 0xfbfc_f34c_b758_d847, + 0x0c6b_448a_7dea_e48a, + ]), + F::from_raw([ + 0xb96a_2751_69f8_e9d9, + 0x217a_9907_a9a8_b0ed, + 0x19c4_cb2d_ed95_12dc, + 0x218c_92e3_9e62_dfc1, + ]), + F::from_raw([ + 0x33cf_76c2_5016_bba5, + 0xfeec_1c18_020c_3803, + 0x0f72_6df3_d051_5aa6, + 0x106b_f92a_017c_308f, + ]), + F::from_raw([ + 0x543a_65b1_8ca3_adaa, + 0x49cf_7000_6925_46ac, + 0x3b7c_35ea_1e71_9316, + 0x1f28_3fea_1724_4f04, + ]), + F::from_raw([ + 0xc1f4_1d1a_26ee_7dae, + 0x7bdf_2c2c_179b_817f, + 0x0ebf_3fd2_a2c8_dffe, + 0x1fc5_f58e_5a06_e1c7, + ]), + F::from_raw([ + 0x6dd8_6c91_938f_d560, + 0x3cec_70fe_dd54_beef, + 0x96cf_cd8a_27a2_4630, + 0x22d0_d77f_0ae4_cd93, + ]), + F::from_raw([ + 0x6d58_3510_8eec_5f0d, + 0x35b3_e8d5_bd47_045c, + 0x7a5e_0399_5727_6e99, + 0x1ce5_1121_2d86_8853, + ]), + F::from_raw([ + 0x092c_1130_12d1_c3f6, + 0xf52a_4290_f9c7_c1d3, + 0xe742_36c4_9f93_09dd, + 0x1c83_ca5d_f6ac_477a, + ]), + ], + [ + F::from_raw([ + 0xcee6_d128_a974_42ee, + 0x88af_0ad1_1294_b350, + 0xc95f_8a91_3d87_a106, + 0x2e72_da0e_1d1d_1cac, + ]), + F::from_raw([ + 0x6f68_1b7e_05b0_d0fc, + 0x6102_b49e_b2cf_1ddb, + 0xb8e7_c259_7d97_871d, + 0x0455_ee8e_7552_be76, + ]), + F::from_raw([ + 0x848d_3eda_04e6_c449, + 0x9490_2e3b_8da1_71b8, + 0xdd06_ab14_f132_1597, + 0x1078_63da_f4ca_c318, + ]), + F::from_raw([ + 0x7317_17b6_bc63_a9d8, + 0x91f1_7f19_10fb_dc06, + 0x8982_da9d_5d2f_e911, + 0x0132_abaf_80e3_3ac4, + ]), + F::from_raw([ + 0x99a8_4677_0f4a_ac21, + 0x14f0_0f9e_2637_5f62, + 0xc47b_163f_a304_ac8d, + 0x134e_4567_b290_ed94, + ]), + F::from_raw([ + 0x8a1b_e2b5_2351_64fb, + 0x1e9a_a6d7_65a2_e532, + 0x4a1d_d9e6_194a_360c, + 0x0e6c_1008_a6d6_cf30, + ]), + F::from_raw([ + 0xf77d_508b_fd38_28a2, + 0x3c2f_56e9_736e_91f0, + 0xa3d5_98a9_343d_638a, + 0x2f8d_bc0f_86cd_3308, + ]), + F::from_raw([ + 0x5bae_6734_7e5d_a7d1, + 0x40d6_c70d_7fa8_2e08, + 0x3cd9_efd1_bea7_e468, + 0x1eed_a9a9_c6d8_a03c, + ]), + F::from_raw([ + 0x11fb_26db_a1ae_0fc4, + 0x5572_05a8_7714_cd80, + 0x0931_5622_837f_eb89, + 0x1e2b_dca3_589d_22bc, + ]), + F::from_raw([ + 0xbaa1_66b7_e012_04a5, + 0x32a9_c4da_459f_c5f3, + 0xf2ab_d9d6_051f_3aff, + 0x1feb_9591_1217_5ba6, + ]), + F::from_raw([ + 0x320b_b5bd_d3ad_d66f, + 0x04b6_472a_91d0_5f96, + 0x9837_654b_1fba_8aca, + 0x1b6a_4bf2_fb32_031b, + ]), + F::from_raw([ + 0xfc5d_8ea6_0dc1_8cbc, + 0x14d8_97d3_202b_e009, + 0x04ef_2fa6_0c6c_f5d0, + 0x0bc2_0762_60db_797f, + ]), + F::from_raw([ + 0x31ad_e6db_b227_3cc5, + 0xb6c0_2e40_50ad_8ae9, + 0xd65b_8c44_bdd1_d423, + 0x039a_5ff3_24ca_a9dc, + ]), + F::from_raw([ + 0x4c4e_6b4b_a088_ff35, + 0xcb47_0867_0638_b16e, + 0x614e_a267_e0c2_2039, + 0x1e50_c1f7_a5bd_8a96, + ]), + F::from_raw([ + 0xe6f0_31ed_d51b_8c0a, + 0x861a_df64_8212_141b, + 0x4a9e_890d_85fb_3786, + 0x2431_5140_db1e_03d3, + ]), + F::from_raw([ + 0xfa06_df8b_ea2b_b5dd, + 0xd664_d98d_011e_892b, + 0x5c72_a073_c4f9_037d, + 0x012c_b6f3_5a18_d948, + ]), + ], + [ + F::from_raw([ + 0x9edf_fb39_5148_1615, + 0xd774_e3f1_b2c6_dabe, + 0xe066_de9d_a417_7803, + 0x149a_528e_7303_119c, + ]), + F::from_raw([ + 0x19d8_c963_d5b6_5d33, + 0x74c6_f6af_d477_79a1, + 0xdc0e_6b52_69bd_1dde, + 0x0099_0738_ffec_c6f8, + ]), + F::from_raw([ + 0xde4c_bd64_659f_c741, + 0xed3b_f307_72e6_81ba, + 0x1ede_6542_ff98_3cb2, + 0x15b3_19e4_f51a_c893, + ]), + F::from_raw([ + 0x7d35_1a5c_30b4_26f0, + 0x305a_08e8_d5c5_3278, + 0x6a6d_8532_af3e_489d, + 0x1553_343f_95b1_ff22, + ]), + F::from_raw([ + 0x5a8f_b8d1_9c5a_2314, + 0x8a2c_a1b4_3dd2_21b5, + 0x10e2_54fc_e373_986e, + 0x124d_40c1_54d4_454d, + ]), + F::from_raw([ + 0x0f65_ea0f_48c1_7a03, + 0xd389_5dbf_ef58_c5f8, + 0xa43f_4dfe_a050_8cb6, + 0x0863_2672_fa42_36ac, + ]), + F::from_raw([ + 0x9267_4c69_0bda_36a9, + 0x6f74_66e5_e361_01fd, + 0x7107_021a_ecb7_06f7, + 0x18ed_4202_e081_efeb, + ]), + F::from_raw([ + 0xba36_fd37_5d84_0091, + 0xfa9c_fe04_7ead_601e, + 0x674d_c97f_43d7_ec63, + 0x22b6_2d63_e4da_a7c6, + ]), + F::from_raw([ + 0x2cd7_dc1b_e7ec_16d5, + 0x2866_c5e3_1bca_72d1, + 0x50cf_e2ab_65ca_a646, + 0x1f76_ba18_8448_c2dc, + ]), + F::from_raw([ + 0x627e_ba45_d732_60dd, + 0x3bb1_b30a_728a_cd45, + 0x8590_bb52_1b2b_ef5f, + 0x259b_4968_f9e4_c328, + ]), + F::from_raw([ + 0xa080_3870_fcdf_21d1, + 0x0907_2a2b_7edb_ac04, + 0xbad2_4c5a_54ad_ccd0, + 0x1a1a_f241_8b1e_cd4e, + ]), + F::from_raw([ + 0x1118_08cf_cf13_e8f7, + 0x0c74_c010_5d22_5a6b, + 0x2f58_c265_a0d7_6d45, + 0x13c4_88ef_b576_d98b, + ]), + F::from_raw([ + 0xa4c9_99b1_5fe3_6beb, + 0xc02e_2682_9581_9bb0, + 0x4c52_a364_e5aa_39d4, + 0x2e02_7893_3d94_b843, + ]), + F::from_raw([ + 0x6755_0bb4_e6c1_db59, + 0xa3aa_4a76_cd8b_d4fe, + 0x202e_95e5_866e_679e, + 0x26fc_6a0f_560e_5781, + ]), + F::from_raw([ + 0xba0c_51da_68fe_9488, + 0x02e5_c992_4878_6be8, + 0xd5d3_621a_fb91_732d, + 0x2d7c_e035_4e6a_457e, + ]), + F::from_raw([ + 0x5061_560f_2693_cfd7, + 0x0aa2_6989_a693_86ce, + 0x1838_596c_ce66_e8bb, + 0x2de1_db6d_ab7e_00b8, + ]), + ], + [ + F::from_raw([ + 0x641f_abad_4944_f587, + 0x8e4f_a13b_9932_c928, + 0xbabe_836e_6fe4_8eea, + 0x2e30_6809_073d_4a00, + ]), + F::from_raw([ + 0xada7_7506_d16b_66f7, + 0x56ae_2afc_1d7b_d7a2, + 0x7a20_a8aa_9ef9_a17d, + 0x21b9_bc5b_a7bd_e078, + ]), + F::from_raw([ + 0xc6ad_0f8c_3914_c711, + 0xd9f6_63ae_39a0_e3b6, + 0x0ef4_8a32_5774_80a4, + 0x037e_1223_8029_fbbd, + ]), + F::from_raw([ + 0x280e_9498_bb7b_9e9c, + 0x7ddd_749d_9ffb_d5a6, + 0x10fe_c854_ff5f_a903, + 0x0623_40ef_a1a3_0619, + ]), + F::from_raw([ + 0x646c_4ff4_4beb_9dec, + 0x86f7_2512_7f15_64d1, + 0x574e_4e92_409b_4176, + 0x28e2_ec67_52d0_7e64, + ]), + F::from_raw([ + 0x5a95_e0ff_4f3c_4541, + 0x847c_a334_8a9b_6eaf, + 0xac8c_fdaf_b8c4_785a, + 0x1081_db39_ef41_961a, + ]), + F::from_raw([ + 0x8666_2fbb_b7a2_2370, + 0x80ae_a622_9d08_b3c9, + 0xa8b8_475c_e16d_306f, + 0x0ac0_3c48_add6_876e, + ]), + F::from_raw([ + 0x64a0_55aa_7ea0_7d8e, + 0xdc2a_75da_2d0f_1743, + 0x7df8_6078_2d53_fe8a, + 0x0994_1366_c573_43c5, + ]), + F::from_raw([ + 0xc37b_a58b_74bb_4dce, + 0x5c1f_729b_7ea6_bbd8, + 0xc712_1c8a_a04c_1d95, + 0x0dc9_38da_60ab_9182, + ]), + F::from_raw([ + 0xd71b_e7d7_eba9_30eb, + 0x41e8_5ed8_6dd2_1ff5, + 0x7484_0d4a_3a64_b405, + 0x0742_6bd1_2d47_69e1, + ]), + F::from_raw([ + 0x1787_7f6a_3a2d_666b, + 0xf070_5b3d_2e48_74db, + 0x0547_1caa_3ac6_604e, + 0x2ca3_4511_5393_37cf, + ]), + F::from_raw([ + 0x8354_58d3_3c18_33a9, + 0xc09c_2237_2b5a_6814, + 0x0dfc_9a2a_bf11_86aa, + 0x23db_1c11_8022_fca9, + ]), + F::from_raw([ + 0xc781_acc0_20c6_8558, + 0x2076_8e67_9c43_b319, + 0x33a9_f9a3_6899_a249, + 0x282b_5996_2607_ed3c, + ]), + F::from_raw([ + 0x0206_0ddf_23ba_a05e, + 0x5c08_7ade_03a1_2cc2, + 0x83d5_4462_3cfb_2ecf, + 0x1cec_719a_4e8f_db83, + ]), + F::from_raw([ + 0xa2c1_7718_c534_ea41, + 0x43b7_11ab_1317_a31e, + 0x3bcc_e66e_0a6d_d984, + 0x279d_1490_e81c_eeb7, + ]), + F::from_raw([ + 0x3364_f888_d2a7_15a5, + 0x7607_3925_61e6_ffba, + 0x35e7_0e85_321b_10b6, + 0x168d_a84e_bb30_3fa9, + ]), + ], + [ + F::from_raw([ + 0xfb98_3028_7caf_3502, + 0x0c43_c922_3fd7_1c41, + 0xaa33_b5f8_f637_e920, + 0x164c_7be1_367b_220d, + ]), + F::from_raw([ + 0xb015_0849_4216_2bcf, + 0x6ec6_c61b_20d1_cc91, + 0x5852_c50e_1d6a_bebb, + 0x1c09_e997_ba2b_d162, + ]), + F::from_raw([ + 0x82d0_89ee_4583_36c5, + 0x5206_34bb_30d0_0dc6, + 0x1671_12b1_491d_5877, + 0x2ec3_85a2_ef59_f594, + ]), + F::from_raw([ + 0x20ec_5f1e_5da1_ae83, + 0x238b_2f90_e13a_e6e5, + 0x06d3_8e24_6428_7368, + 0x0cfa_9efe_4507_9638, + ]), + F::from_raw([ + 0xa22e_512c_c0c1_03b9, + 0xa534_403d_922f_9bf5, + 0x3bb0_f4d4_acc6_21b5, + 0x22f8_fee0_b313_2a95, + ]), + F::from_raw([ + 0xd71c_63fc_7cbb_42be, + 0x823e_2506_c60d_b669, + 0x4074_3b43_c583_2193, + 0x1447_3dd3_650a_7bf1, + ]), + F::from_raw([ + 0xe115_e33a_08df_45c6, + 0x536e_84f1_5ca7_b509, + 0x1214_8920_e5b9_c30b, + 0x16f9_1395_a42f_68a9, + ]), + F::from_raw([ + 0x271c_8ba6_faf3_0da4, + 0xd899_1175_13b1_60c0, + 0xcbdf_f49c_bd78_6036, + 0x0d9f_494e_e675_c250, + ]), + F::from_raw([ + 0x5af3_db3e_13d6_97fa, + 0xe5ab_346d_5f14_c918, + 0xd84d_d07c_f6d0_a9c9, + 0x0bf3_6d4c_6fff_4101, + ]), + F::from_raw([ + 0x5ef1_3189_3257_7905, + 0xc686_b57a_87f0_41f7, + 0x93e5_9802_66f1_e752, + 0x2345_2880_a7cb_59d3, + ]), + F::from_raw([ + 0xa0fb_45ce_ca2f_57f6, + 0x25e3_e721_f20c_0c21, + 0xa4d6_2da4_c168_4236, + 0x305f_2a14_df15_90ba, + ]), + F::from_raw([ + 0x08b4_35f8_a340_7acd, + 0x533a_c0bf_f5b8_730a, + 0xe490_f603_8848_6781, + 0x1947_f017_5a8a_9f3b, + ]), + F::from_raw([ + 0xea36_2257_345e_748b, + 0x44c3_b611_0deb_4f47, + 0xcf86_d9ab_f49a_d411, + 0x2de4_17a9_60b5_66ab, + ]), + F::from_raw([ + 0xdc2b_03bc_0683_bea3, + 0x201d_5572_df24_4b98, + 0xae0d_20fa_2533_0e19, + 0x13b8_87c7_7592_f15d, + ]), + F::from_raw([ + 0xdabb_4abf_2c44_5370, + 0x0916_e49e_f1eb_ca21, + 0x05e1_6fd0_490c_e056, + 0x097b_35dd_0b26_e468, + ]), + F::from_raw([ + 0x3bc2_d754_56dd_4151, + 0x1e58_917b_143f_1723, + 0xed59_37d3_cce3_8ed9, + 0x237a_037a_d96a_360a, + ]), + ], + [ + F::from_raw([ + 0x9c0b_4826_774a_db46, + 0x29a6_d912_4e8c_190a, + 0xfb04_9427_0af4_822c, + 0x18cd_c036_5a8d_fabc, + ]), + F::from_raw([ + 0xbc3f_6a47_a8b3_bf6b, + 0x8d62_a74d_001e_6684, + 0x5901_613a_1cde_d9f2, + 0x1634_28bf_9660_8596, + ]), + F::from_raw([ + 0xa606_5b6d_49c3_32df, + 0xa5bd_3f7d_d508_167e, + 0xe59b_940d_81b3_af27, + 0x1dae_0d15_fa18_22a5, + ]), + F::from_raw([ + 0xc05f_f8fc_a0d9_77dd, + 0xc172_d4ad_c75a_c1fe, + 0x4927_fac6_754b_5cbc, + 0x02ad_d9c7_4cf2_2d1e, + ]), + F::from_raw([ + 0x36f5_fb26_d14f_67df, + 0x3640_78dc_212d_e0ad, + 0x4a0b_647b_9069_0fe3, + 0x1edb_562e_5b43_7632, + ]), + F::from_raw([ + 0x1012_31ed_8fe9_a1f7, + 0xe402_1973_af1d_9e7d, + 0x1ec1_00e5_9b59_d78f, + 0x301d_da97_e290_a7a0, + ]), + F::from_raw([ + 0xef5e_6ec5_4eb9_8da1, + 0xdb5c_27c0_c94b_3b36, + 0x4edb_05ac_080d_d24d, + 0x170a_115e_7fb0_e76a, + ]), + F::from_raw([ + 0xfb2a_609e_4d47_e9f4, + 0xbee9_39a6_6fb3_21b9, + 0xda99_faee_2d6c_5059, + 0x2976_3815_5775_9f24, + ]), + F::from_raw([ + 0x03b4_d7c6_c81e_ffa6, + 0x2140_713f_97cc_7c85, + 0xc7b6_c2a5_df2d_d631, + 0x0858_c7c6_f9fe_c77c, + ]), + F::from_raw([ + 0xa46b_cad3_514d_39a6, + 0xc301_ccc3_0b2c_8475, + 0xec11_2701_d805_7a1d, + 0x1255_7c61_2c0f_7718, + ]), + F::from_raw([ + 0x4ba3_f832_de64_dcb6, + 0x2d75_e6f0_0c67_ce02, + 0x5bce_2900_f37d_819f, + 0x1ab0_63ff_dffa_216a, + ]), + F::from_raw([ + 0x499c_0a14_1bd2_a580, + 0x152b_8235_4636_3589, + 0xa6e9_4f79_cb1a_f1d4, + 0x2849_3d04_6720_68c6, + ]), + F::from_raw([ + 0xd95c_6e0d_8d8a_f345, + 0x237e_e587_7579_7c67, + 0xddf2_c16c_0d08_a831, + 0x023e_f9e5_d468_8380, + ]), + F::from_raw([ + 0x0b32_7ffd_9464_a5c1, + 0x14eb_1841_0bf9_1557, + 0x36ca_f30b_ee53_c0ef, + 0x1093_3251_0072_2f88, + ]), + F::from_raw([ + 0x893f_3525_9dde_8d55, + 0x13c9_3354_7800_3810, + 0x78d4_f103_d38e_b474, + 0x1705_479c_f3bd_bbaf, + ]), + F::from_raw([ + 0x15a3_b37b_b8b3_48e6, + 0xceee_2b38_b068_174f, + 0xeb7f_6f9e_de3a_b477, + 0x0089_6c2b_79cf_dda5, + ]), + ], + [ + F::from_raw([ + 0x36bd_e3f0_4eb5_0cb2, + 0x0f7d_5c77_31e5_9e9f, + 0x15b3_78a2_747d_fba9, + 0x149f_13bc_3e4e_2b05, + ]), + F::from_raw([ + 0x2bb7_f631_99b8_712e, + 0x3540_c729_5ca0_e47f, + 0x68ec_febf_7094_4b59, + 0x2e14_2224_48be_50c0, + ]), + F::from_raw([ + 0x7a1c_f7f6_d870_50d3, + 0x1871_8703_3b13_8fb2, + 0x6db1_81ac_92b2_29a5, + 0x1e22_c039_6024_ba3f, + ]), + F::from_raw([ + 0xf777_8563_e05e_07c6, + 0x42fb_54af_88ec_4b73, + 0x5d58_6143_53f0_a298, + 0x2c5a_1e45_3406_fcda, + ]), + F::from_raw([ + 0x216a_f1c4_65d8_abee, + 0x53c2_27b1_88d8_7559, + 0x50a6_60e7_1b1c_d318, + 0x2d08_dae6_f1fb_7e02, + ]), + F::from_raw([ + 0xc769_f93c_a2b4_d7b3, + 0x2a12_5076_6139_ea38, + 0x6411_8a80_81d8_7e21, + 0x2155_33a7_7776_2266, + ]), + F::from_raw([ + 0xe4df_3ac2_8729_2edd, + 0xc074_092f_cdbf_0079, + 0xc7bd_f835_ec9d_1ee0, + 0x1cbb_bb26_f991_a721, + ]), + F::from_raw([ + 0xaec2_f991_2292_4e8e, + 0x9259_f691_04c2_2206, + 0x1f00_5500_427a_d539, + 0x08f5_7bdc_3c7c_9568, + ]), + F::from_raw([ + 0xdb8c_cd75_ed39_912e, + 0x97cf_97aa_6699_664f, + 0x6f33_5203_2150_0d12, + 0x1b45_938c_7b84_f017, + ]), + F::from_raw([ + 0xe916_ac2c_fd3f_bade, + 0xee6c_bef7_26e2_69d0, + 0x4487_b791_6e6b_4033, + 0x2aeb_2090_4486_8ca8, + ]), + F::from_raw([ + 0xc9e1_1977_403a_3eb2, + 0x9240_3dba_10ac_3706, + 0xaff0_b836_5966_07a7, + 0x2763_5bd2_ae7e_0cac, + ]), + F::from_raw([ + 0x07e7_eaa1_7fe5_7301, + 0xfe9e_7260_55fc_0cdd, + 0x7938_149b_f16f_ce07, + 0x22e5_93b7_a679_3502, + ]), + F::from_raw([ + 0x9694_da83_cbd0_87c7, + 0xa427_edeb_d237_11b8, + 0xa183_de49_169d_6b83, + 0x1795_962b_b510_0236, + ]), + F::from_raw([ + 0xf488_7fce_4707_c437, + 0xcdf2_8827_ed35_707c, + 0x283c_2532_1bf3_7598, + 0x0077_fc8d_7cd9_adbc, + ]), + F::from_raw([ + 0x6a45_ecd8_27dd_1280, + 0xcb7a_d8f6_571b_7748, + 0x2442_d1d0_bd59_b65e, + 0x0ae5_b494_d166_f6a3, + ]), + F::from_raw([ + 0x7f01_634a_8b89_2c87, + 0x9272_cdfe_8954_55d7, + 0xfe63_719a_da70_41e6, + 0x2924_229b_6d64_8184, + ]), + ], + [ + F::from_raw([ + 0xf0c8_d15b_0687_16d5, + 0x4298_1c08_52a6_ca6a, + 0xf221_0367_4933_6851, + 0x051e_8409_03dd_abdb, + ]), + F::from_raw([ + 0xa0a6_adf3_c8bf_2f84, + 0xf626_19c5_3096_85d0, + 0x47a8_5971_bfcb_e28d, + 0x0fc5_08b7_e620_bb6c, + ]), + F::from_raw([ + 0xb558_ac5f_c0f0_f22c, + 0x2bd8_7739_2e2b_56af, + 0xd189_bb32_010b_95fc, + 0x19f7_621b_bd65_9b27, + ]), + F::from_raw([ + 0x5006_d8f2_98b7_21bb, + 0xf7c5_72c0_a131_adec, + 0x9268_0a79_56e0_b932, + 0x303e_98ee_35bf_cad2, + ]), + F::from_raw([ + 0x901d_997e_31b2_ea07, + 0x51f4_a531_d123_5a8a, + 0xcbc7_42d8_7923_b27c, + 0x1a78_253e_57f8_25b0, + ]), + F::from_raw([ + 0xe344_9e7f_a2f3_9320, + 0x4c43_85a7_4d84_5e20, + 0x3ab2_9deb_f3b0_884a, + 0x15e2_2093_9ba6_4b3a, + ]), + F::from_raw([ + 0x76b5_04bc_cd29_0b94, + 0x21ec_1b0e_c73d_1964, + 0xe901_23a4_e43f_d692, + 0x1604_86b6_e621_dfa0, + ]), + F::from_raw([ + 0xa798_feca_7631_1006, + 0x21b5_ae38_6f2c_2a34, + 0xe279_624b_acdb_614b, + 0x2bee_b424_04db_8ab5, + ]), + F::from_raw([ + 0xfe9c_4b5e_c021_f0e1, + 0xb8be_8adb_b4fd_5af8, + 0x459b_1db9_7406_70bd, + 0x24b4_0750_0416_ffb0, + ]), + F::from_raw([ + 0x39a0_c350_6b7c_042b, + 0xaeb1_03bf_fc97_df68, + 0x9bcf_fff2_3fc1_123b, + 0x07f5_fdae_9882_85c4, + ]), + F::from_raw([ + 0x6af0_4275_9a39_9503, + 0x755c_7bee_8190_d780, + 0x853e_67d2_8af6_eb4c, + 0x2ce9_b5a0_8dec_ce4b, + ]), + F::from_raw([ + 0xb018_1288_45bf_d022, + 0xbf16_e4aa_2e32_de94, + 0xe5f4_2cb1_2301_7f1f, + 0x1daa_dc91_1c3e_c3b8, + ]), + F::from_raw([ + 0xf99a_16e3_f220_5651, + 0x64dd_14ed_8eda_e148, + 0x5aae_fbee_67aa_64bd, + 0x1ff8_0b16_9617_b7ee, + ]), + F::from_raw([ + 0x82b5_ae02_3bfc_6ee9, + 0x8249_8b50_68d3_cd3b, + 0xab85_c008_f300_c508, + 0x2aff_68cd_38d1_88b8, + ]), + F::from_raw([ + 0x6f47_2d92_eb70_86df, + 0x50ea_0247_d8f2_4e8f, + 0x5cc4_db5a_1feb_1c47, + 0x114d_0b3f_54f1_4de4, + ]), + F::from_raw([ + 0x3a02_1cf8_d02a_bb9c, + 0x258f_85ae_8d8c_aa8a, + 0x69e0_f756_850d_cc21, + 0x12b6_0757_8c2d_349b, + ]), + ], + [ + F::from_raw([ + 0x4b04_4269_0795_a054, + 0x7dfe_c7ec_4f3a_4294, + 0x5509_2bbe_9505_89f4, + 0x14c6_92eb_cd07_fcef, + ]), + F::from_raw([ + 0xb3d7_5a8b_0819_9f20, + 0x6763_7d75_ffa4_39ed, + 0x8344_eb56_d746_d070, + 0x2229_dbdf_b92a_e7eb, + ]), + F::from_raw([ + 0xf873_a556_b6ec_f6be, + 0x73ad_9a2b_cad0_4ac0, + 0xc572_f583_51e4_b007, + 0x16f4_648a_c47c_197f, + ]), + F::from_raw([ + 0x7437_eba6_6212_2ff6, + 0xea70_a7e3_d013_fcb1, + 0x4dd0_4f5c_6aeb_639b, + 0x12d9_0d55_c8d3_ec18, + ]), + F::from_raw([ + 0xbc7d_c074_9045_216f, + 0x7f15_626e_c443_6dee, + 0x26af_9d93_9411_caf8, + 0x04e2_c497_56b8_b5ac, + ]), + F::from_raw([ + 0x31d3_5c56_dbd0_bb36, + 0xdd50_7857_e9e5_9818, + 0x6b07_f819_4895_5c45, + 0x2191_7d72_3a33_db26, + ]), + F::from_raw([ + 0xe9f3_a5f5_ee0c_2661, + 0x23e7_bfc4_1089_48b5, + 0xf81b_4d23_6512_268c, + 0x0d13_b46a_a1b4_1168, + ]), + F::from_raw([ + 0xf86a_08b2_eef1_fb70, + 0x1a4b_cbb9_e3b0_2a26, + 0x7ca1_b8ec_47cb_12df, + 0x17bd_7312_75d6_02d1, + ]), + F::from_raw([ + 0xbd13_629b_dc69_2745, + 0x2f3d_1cec_2c5c_89f5, + 0x698a_4bc7_74e6_dafc, + 0x0240_ee60_1a68_23ec, + ]), + F::from_raw([ + 0xc207_a8ad_75bf_252c, + 0x877a_3bed_8d00_7f6f, + 0x0593_d110_22d3_c77b, + 0x2663_ff9d_0eaa_6e91, + ]), + F::from_raw([ + 0xe8c8_4a72_c7c3_fbe7, + 0xc40e_9cc3_8cbb_e294, + 0xd7a2_44ab_3ab0_b41f, + 0x02c4_5b53_fa72_d7a0, + ]), + F::from_raw([ + 0x5388_5abd_dd12_22b7, + 0xa319_3762_3df3_fd29, + 0x2872_880f_9683_4d23, + 0x10bb_8a75_31ab_05d2, + ]), + F::from_raw([ + 0x25ae_69d2_ba79_b031, + 0xd42e_6125_4dd6_53bd, + 0x2122_a353_d148_2744, + 0x2222_950c_8a1c_cc1c, + ]), + F::from_raw([ + 0x030f_bd6b_0445_7db4, + 0xc9d6_d918_e37f_2e97, + 0xde7b_fb8e_f626_5d26, + 0x2c3d_3eb7_2053_7d2d, + ]), + F::from_raw([ + 0xd50a_72cf_98a3_0895, + 0x312e_19e5_b351_8ef5, + 0x9314_296d_e56d_c874, + 0x0539_a696_e151_9816, + ]), + F::from_raw([ + 0xbfa5_ef5a_1fcd_5ad1, + 0x7d67_72b1_08ac_5c4c, + 0xeeaf_50d0_1664_f96f, + 0x25e2_a5fe_1f15_5a2e, + ]), + ], + [ + F::from_raw([ + 0xe181_2e08_70b9_0fc5, + 0x4164_220c_9e3f_ef27, + 0xd454_efca_9cc3_0f15, + 0x2f5d_3e87_df69_04ab, + ]), + F::from_raw([ + 0x4fc9_e68e_89dc_300e, + 0xde71_d6ea_a821_596e, + 0x42e4_e543_e8be_6c2e, + 0x0dee_20e4_731c_0e75, + ]), + F::from_raw([ + 0xa921_9403_4e9d_2e54, + 0x11be_741c_bfcb_d2b3, + 0x3961_5cd8_afc0_bc9e, + 0x0614_42c1_3b9d_1fb3, + ]), + F::from_raw([ + 0xaf57_16fe_2299_3123, + 0x8410_d3d2_ca99_1f79, + 0xa0eb_af7c_d4a0_1cd1, + 0x23a5_6185_e12d_6230, + ]), + F::from_raw([ + 0xd49e_81e5_1742_35bc, + 0x4220_2ee3_c4a3_6db2, + 0xb7c3_d64f_e1ee_c353, + 0x0334_4b7b_9adb_15a3, + ]), + F::from_raw([ + 0x4995_b08a_b661_e675, + 0x536d_392b_113d_06db, + 0xa2b5_940a_1a1e_e1ec, + 0x284b_751e_d61d_484b, + ]), + F::from_raw([ + 0xc3a0_aab3_9634_0820, + 0x3030_9c5f_4bcd_0c6d, + 0x4d58_a4c8_191f_9d47, + 0x1701_ad26_a42d_e77f, + ]), + F::from_raw([ + 0x93f2_f634_49ff_3d4b, + 0x9e8f_a238_6cc0_2965, + 0x08d7_aa6e_9102_f6b2, + 0x27ca_dda5_19a8_3701, + ]), + F::from_raw([ + 0xb267_e4ad_261e_d696, + 0x2f5b_9059_eb99_4807, + 0xb327_12d5_9f0e_3b1b, + 0x2626_d61c_b110_bb03, + ]), + F::from_raw([ + 0x41a9_f045_7915_138e, + 0x0865_f3fa_841e_c484, + 0xf15f_5e8b_8da5_7bed, + 0x1cf3_3308_97c5_4f25, + ]), + F::from_raw([ + 0xf6c8_4d68_e148_f64e, + 0x3a72_56a7_feb9_fd8a, + 0xa490_d3d8_6e8c_92c8, + 0x01b5_bcce_9d69_9e55, + ]), + F::from_raw([ + 0xfbba_a8d8_1120_26ef, + 0xc8ca_468d_1d4a_a999, + 0xcf5b_cb27_46b3_c81f, + 0x2a17_5105_d15b_a3fe, + ]), + F::from_raw([ + 0x6a0f_298a_77f9_b26b, + 0x637d_7ec7_92d3_0eca, + 0x1c88_8cef_8111_5ae0, + 0x20a2_3822_95ec_a0a6, + ]), + F::from_raw([ + 0x239e_f812_6bad_2e51, + 0x1cb6_91c9_ab5b_2786, + 0xe4b2_18b2_9ca7_9e22, + 0x0515_49bb_9adb_ce26, + ]), + F::from_raw([ + 0x4c71_185f_e688_e079, + 0xb18b_ea43_09cf_02f4, + 0xca08_0bfc_534c_8b30, + 0x081c_a534_9e64_d60b, + ]), + F::from_raw([ + 0xbce7_3323_82c0_b82d, + 0x03b1_7fd7_02e0_0420, + 0xca7b_aa7c_3c9a_ca55, + 0x285a_400d_61a5_cbd6, + ]), + ], + [ + F::from_raw([ + 0x79e6_af2e_7344_0b21, + 0x268a_db66_2ac2_4594, + 0x7082_62e3_ff14_8bea, + 0x04e1_bf8c_955b_c3c8, + ]), + F::from_raw([ + 0xa92b_30bc_268b_0b4b, + 0x8059_c91f_501b_2f26, + 0xeec3_2c9e_6b7d_d7bc, + 0x0bbe_19ac_4f5c_67e9, + ]), + F::from_raw([ + 0xa893_4c60_8d2e_8f6a, + 0x9248_d34f_fbbf_4c4c, + 0x9e66_44b8_e7b7_665d, + 0x2724_ac58_e1ea_4df1, + ]), + F::from_raw([ + 0xfd60_a9ab_70ff_f709, + 0x5bfb_4330_cb25_14df, + 0xa830_d1a6_ca8d_2d08, + 0x0446_788d_9542_6afe, + ]), + F::from_raw([ + 0xa6aa_ec5c_dff5_758f, + 0xc0e6_5cb2_9142_69a6, + 0xbd91_0c2b_37ac_40bf, + 0x0e1e_cf26_c286_c86a, + ]), + F::from_raw([ + 0x386d_7d0c_05ea_4ba3, + 0x3f25_7130_83b1_611c, + 0x01a8_4914_8a24_4910, + 0x29a2_67dc_9f3d_12d6, + ]), + F::from_raw([ + 0x881c_34ce_b99d_2d3b, + 0x9dc2_cbeb_9d2b_90ba, + 0xf421_2558_6ea2_a5b4, + 0x1dc3_4a60_e783_b5da, + ]), + F::from_raw([ + 0x24d1_0eec_82be_4e5b, + 0x578c_a9c4_35d8_3210, + 0x86c3_220f_0ff9_026f, + 0x2b9f_ce58_534b_f4a4, + ]), + F::from_raw([ + 0xca5a_344c_3d66_6d19, + 0x9a9d_1f8b_a630_dd24, + 0x1ca5_e07e_3681_c1dd, + 0x2fd9_c97f_0105_4fe6, + ]), + F::from_raw([ + 0x1b70_8239_f433_e647, + 0xbfb4_69ce_c9fe_e37f, + 0x5037_f0a8_2c1b_c746, + 0x004e_6a71_46c2_ac01, + ]), + F::from_raw([ + 0xf849_c738_3c07_943c, + 0x62db_8612_dae0_58d0, + 0x3013_b7ef_e0c1_3847, + 0x0f5b_eba2_020a_fde7, + ]), + F::from_raw([ + 0x3e60_c63e_0a18_667e, + 0x249e_1b1b_bcf7_d05d, + 0x4b6e_0d32_d590_dc5b, + 0x1c5e_1e6e_f1be_1aaf, + ]), + F::from_raw([ + 0x497d_33fd_5c8c_fa79, + 0x795f_1bf8_8109_5e98, + 0xa8dd_4206_0883_a7e9, + 0x0956_75c6_e1e8_f6da, + ]), + F::from_raw([ + 0xe802_7125_8099_dccc, + 0xf033_198c_22d2_1f3e, + 0xbba7_4af7_18e1_9a10, + 0x0600_93cc_9e1f_54f7, + ]), + F::from_raw([ + 0xe4f1_2e04_4ace_0dc1, + 0x49c5_337c_c360_1c44, + 0x5093_ce1c_b92c_8d0a, + 0x2c44_a35c_a8e2_4a9f, + ]), + F::from_raw([ + 0x15a4_0743_43e6_8f68, + 0x70e3_d5c8_3d50_f307, + 0x65bb_a16e_cb1a_8a5a, + 0x03e8_9623_477c_5f13, + ]), + ], + [ + F::from_raw([ + 0x2843_5f2d_49cf_734a, + 0x4d00_1cbf_3afb_2023, + 0xd161_8a75_6349_9f6b, + 0x1925_fd58_6e67_8334, + ]), + F::from_raw([ + 0xca7f_1971_0577_19bb, + 0x6e55_6a6e_9030_4a1a, + 0x2016_8e8b_725a_76c9, + 0x1a18_7d62_deb6_39b8, + ]), + F::from_raw([ + 0xc114_82ad_4484_aa0e, + 0xb47d_53ba_d425_dc3b, + 0xcab6_6395_7ff5_4c74, + 0x1723_8dde_447d_9bc6, + ]), + F::from_raw([ + 0xfbbc_e871_1357_0291, + 0x4658_91cb_699d_069e, + 0xe7ea_e8a9_8418_1a77, + 0x2d7a_0593_a56b_d337, + ]), + F::from_raw([ + 0x740b_5ff2_58a7_33af, + 0x895e_cb43_495b_f90a, + 0x12f0_6531_a312_b777, + 0x2783_87c4_eeee_6ace, + ]), + F::from_raw([ + 0x892a_4525_0e01_f478, + 0x849f_4a86_d3d7_9e12, + 0x903f_41b5_7eee_a056, + 0x181a_e209_7099_83bd, + ]), + F::from_raw([ + 0x801d_416d_7344_1a68, + 0xb6bf_8840_2c04_9e91, + 0x663b_038c_9622_b41c, + 0x2867_934e_be66_c335, + ]), + F::from_raw([ + 0xbe01_6c66_72b4_db55, + 0x767e_7980_6151_5e43, + 0x5a21_8d81_1e46_4fc4, + 0x0165_1870_d1a0_d7d0, + ]), + F::from_raw([ + 0xda79_5be0_c1a7_0024, + 0xcfb9_11a7_846d_5cf2, + 0xd501_26d2_7513_4f29, + 0x0f17_095f_8a2b_21ed, + ]), + F::from_raw([ + 0x990e_838e_dcb5_1ce8, + 0x1da7_7302_1717_13e2, + 0x9d01_cd88_9e63_1973, + 0x0f29_ea40_097b_34f3, + ]), + F::from_raw([ + 0x0a2d_9a05_2b60_8901, + 0x8087_3673_8631_5b53, + 0xdc0e_e252_9112_d576, + 0x0345_0341_8f27_ccfb, + ]), + F::from_raw([ + 0xd4f6_b9f1_69bf_34f6, + 0xc22e_ea96_a956_b8c8, + 0x066c_c982_a3a4_a62f, + 0x2da6_58ae_ea1d_b7b2, + ]), + F::from_raw([ + 0xffb4_4dac_fbee_6877, + 0xd4cf_2eb7_850a_5496, + 0xdb73_4fb0_bc6c_8e14, + 0x0998_91e8_f220_5b9e, + ]), + F::from_raw([ + 0x10cf_4637_3565_b251, + 0x7bcd_c390_089d_3ab2, + 0xb7d9_d425_f4b2_f4d5, + 0x22b2_8527_a9e2_7d65, + ]), + F::from_raw([ + 0x86f3_b755_76d2_49fa, + 0x16ae_8d4c_7230_864b, + 0x05f4_8938_a1ba_8927, + 0x24ac_41c2_1e03_2f12, + ]), + F::from_raw([ + 0x0653_8c2c_bccd_8601, + 0xc7dd_5234_7c0d_d3ad, + 0xc8dd_3fc9_d479_6eef, + 0x0efd_e17c_5618_9b5d, + ]), + ], + [ + F::from_raw([ + 0x17df_1ea1_6f39_3998, + 0xc23a_2db5_80cd_e1fd, + 0x1c5d_5a99_85d4_50f6, + 0x01f3_21a1_be55_e4b4, + ]), + F::from_raw([ + 0x622f_6bc5_b14a_028a, + 0xc269_1235_9379_7a44, + 0xbab1_61fc_58a3_e85e, + 0x1284_635e_8aa1_7e34, + ]), + F::from_raw([ + 0xf978_3bb6_bcca_af5c, + 0xc642_2ea6_f34e_fe55, + 0x80f7_eb86_264a_a0ef, + 0x1840_3a5e_df30_cb86, + ]), + F::from_raw([ + 0xb2b4_d19f_3c95_d995, + 0x7174_bbfa_7edc_fe28, + 0x961d_4b67_0c29_9804, + 0x29ad_7c5e_7c5e_e93c, + ]), + F::from_raw([ + 0x8a4f_61d9_3330_9ce1, + 0x6487_3808_7770_d65a, + 0x8c4e_b559_aef8_b289, + 0x2685_b8de_c710_9c00, + ]), + F::from_raw([ + 0x9408_ef4a_701c_03e0, + 0x72e2_737c_9f6d_a978, + 0x7a93_b448_ac11_d959, + 0x06d1_a1bc_a752_2d69, + ]), + F::from_raw([ + 0xdcaa_084c_a728_be2c, + 0x5ff1_8a8e_22a0_adda, + 0x17f2_bba9_8679_cd21, + 0x159f_8629_446b_261b, + ]), + F::from_raw([ + 0x3c18_5676_8e13_4361, + 0xd17a_89c1_b027_4fde, + 0x4c52_7571_d1f2_a268, + 0x2100_c160_5b40_e164, + ]), + F::from_raw([ + 0x26b6_dd8a_0c29_7f3a, + 0x8ea1_b01e_865a_d849, + 0x965a_6cd8_10d3_aa70, + 0x14cd_5837_63c5_aaa5, + ]), + F::from_raw([ + 0xbfe5_4d44_0206_8272, + 0x5b29_e2f4_52c9_5006, + 0x97cc_f724_cdc0_6015, + 0x2f9a_fdf2_575f_8444, + ]), + F::from_raw([ + 0x036c_7e5a_a960_ecd2, + 0x2132_730d_5d97_6c4d, + 0xe694_9086_a278_91cb, + 0x0b6c_e3f0_6fc2_3b61, + ]), + F::from_raw([ + 0x58c0_a4f3_3def_65fa, + 0xaa0f_38a0_5ba4_44b1, + 0xd94c_9758_4f8b_d1e1, + 0x2096_a4ac_e19c_c7c0, + ]), + F::from_raw([ + 0x910d_a738_7926_bec3, + 0xf7db_0e01_111a_d80e, + 0xfb5c_6ce8_b23f_6b85, + 0x1742_909d_20f9_f17e, + ]), + F::from_raw([ + 0x2b07_db79_541a_4d9d, + 0x5cc4_bfa4_1a00_b11a, + 0x176c_8977_7872_f6f6, + 0x133c_486c_3be9_d399, + ]), + F::from_raw([ + 0x30c8_ae22_233f_c358, + 0x1d30_4c3d_0b5d_bfe9, + 0x5d6e_3fad_5ef7_c20c, + 0x060b_5bc9_b94f_4549, + ]), + F::from_raw([ + 0xd69f_3310_7949_dcac, + 0x2439_c4fa_deb2_6028, + 0xebb1_a97f_70dd_86bb, + 0x16c0_f928_6769_51fa, + ]), + ], + [ + F::from_raw([ + 0xedc6_5731_d2b0_c43e, + 0x1762_4771_58c3_d9b2, + 0xde33_69ba_d13b_6832, + 0x0457_f42d_bda7_cb38, + ]), + F::from_raw([ + 0xdfbc_fe40_a7fc_ca47, + 0x38ef_0f94_c775_d737, + 0x477d_5bf8_c5de_1e7f, + 0x05bc_53f4_bf38_8b5f, + ]), + F::from_raw([ + 0xb7df_819f_fd10_bcdb, + 0x000b_cb54_9e7d_cdb9, + 0xdbc5_d264_1226_c6f6, + 0x20d0_57e3_0e25_63d7, + ]), + F::from_raw([ + 0xad9a_c1af_b928_7583, + 0xc31f_2943_5a73_6c33, + 0x5ece_cc36_f959_0719, + 0x16f0_574e_7c13_b41c, + ]), + F::from_raw([ + 0x1765_835d_b5fd_ce7e, + 0xbf1b_1a89_468e_549d, + 0xa5f9_c524_4adb_c287, + 0x1b96_29d5_678b_18ec, + ]), + F::from_raw([ + 0xd914_e3fa_60fd_bb1e, + 0x4d47_db59_73d0_c736, + 0x3d07_d2c6_4460_dd64, + 0x27d8_0f15_6488_fd90, + ]), + F::from_raw([ + 0x0e48_c993_fe79_d950, + 0xeaba_63b4_9dcd_0791, + 0x7350_19cd_d791_1cfc, + 0x2119_7bb3_fd8b_66d8, + ]), + F::from_raw([ + 0x0a5a_5cc6_7dde_bf9e, + 0xe91c_c1d7_8701_d44a, + 0x2a66_a2d3_77eb_299d, + 0x28f5_f497_28da_9653, + ]), + F::from_raw([ + 0xe2fe_b2e1_9b79_13f5, + 0xac5e_7ecc_12d1_2514, + 0x1242_76f5_3cb2_8883, + 0x165b_bce0_d62d_6841, + ]), + F::from_raw([ + 0x0db5_6f68_cada_4bf7, + 0xb72e_282b_216f_ae91, + 0x2234_699c_5f3b_12f1, + 0x1493_7807_a2d9_d72d, + ]), + F::from_raw([ + 0xea1b_801e_78f0_445d, + 0x0485_516b_7b82_7d75, + 0x4ec4_c74f_1685_c35b, + 0x0714_2fc4_901f_0e21, + ]), + F::from_raw([ + 0x27c2_abd6_843b_ba53, + 0xc7be_39c9_3129_b9d9, + 0x6c4d_a2cf_468c_59fc, + 0x2714_d6a7_7ac0_ac76, + ]), + F::from_raw([ + 0xaf0f_951b_1db2_cc69, + 0x587a_f977_b5fb_b83e, + 0x70da_7b04_8a8b_c859, + 0x1d31_1037_9d97_c5ca, + ]), + F::from_raw([ + 0x07ab_d5e6_32e2_b96e, + 0xadbe_2719_c660_eab1, + 0x6b1b_0bb0_2122_91b0, + 0x122f_9b48_0060_c35e, + ]), + F::from_raw([ + 0xc4ad_9087_603e_5b5b, + 0x937a_f5ef_bc80_2621, + 0xb8f2_c429_82cf_182c, + 0x0281_5f76_f3ee_ca94, + ]), + F::from_raw([ + 0x1455_19ce_1397_904b, + 0x3400_c24a_10d1_a3cf, + 0xe816_0bd5_9c93_8c5d, + 0x228a_cef6_7746_6bbc, + ]), + ], + [ + F::from_raw([ + 0xab4d_3bda_d8b1_b1d2, + 0xaa1d_7b38_f241_98dd, + 0xc4e3_1639_c1d9_8e57, + 0x2f6f_0800_c73e_0b58, + ]), + F::from_raw([ + 0x8efc_8f7f_b11f_cd3d, + 0x9592_c8d3_0682_6ee1, + 0x3e44_0eea_b56d_23b4, + 0x12dc_b00b_96e9_729e, + ]), + F::from_raw([ + 0x0d40_e044_2ee6_cd82, + 0xd0c3_65fd_7a72_7f2b, + 0xb539_ff3c_7269_2317, + 0x14c9_34fd_db9e_93c1, + ]), + F::from_raw([ + 0xcda3_a80c_45a8_0c62, + 0xe5c6_0151_3b0c_cce1, + 0xf59a_d9b1_2483_ed7b, + 0x1f5b_48fb_b10c_ea0e, + ]), + F::from_raw([ + 0x2b07_5ab0_b0de_8f38, + 0xbbbd_30c0_b5d9_ca3d, + 0x5ee5_de52_6111_0d22, + 0x0768_ab8a_a5cd_040e, + ]), + F::from_raw([ + 0x99a6_7a9b_7a87_0347, + 0xb050_1f7b_e8a3_81d0, + 0xadc1_edc0_691f_5bff, + 0x2b84_fe02_c304_f24f, + ]), + F::from_raw([ + 0x5406_ca0c_ad18_251c, + 0xd1f9_6c3f_d79e_dd64, + 0x1a20_0bd9_68f5_ca9c, + 0x1827_d119_1b15_dcf5, + ]), + F::from_raw([ + 0xef87_eca0_180b_fadd, + 0x8231_b0ff_de5b_2281, + 0x5ef7_59d0_a439_45c4, + 0x0169_50a0_6b92_b548, + ]), + F::from_raw([ + 0x74d6_fe28_2a83_1607, + 0x24cf_043f_6fae_a68a, + 0x43f3_ccd7_0a88_c152, + 0x2112_97da_4d70_cf7d, + ]), + F::from_raw([ + 0x5f39_ff21_721e_4d85, + 0x0a74_2f81_8689_3db9, + 0xfecf_5e80_1814_b406, + 0x0a18_1217_d131_5fc3, + ]), + F::from_raw([ + 0x54c8_0948_6d83_4444, + 0x34a0_c187_f029_8108, + 0x9d7b_6053_e6d2_279d, + 0x2860_58ed_6304_f12c, + ]), + F::from_raw([ + 0xa7ad_459f_81dd_f9a9, + 0x0639_841f_53c6_03b1, + 0xf840_cda2_4da4_d306, + 0x2cd0_a562_1326_78f5, + ]), + F::from_raw([ + 0x5408_67c8_6ef3_0135, + 0x89df_be75_cac1_fe58, + 0xd9e7_9428_cd90_5ad4, + 0x21ce_26e8_e7c8_3045, + ]), + F::from_raw([ + 0x0675_78c1_7758_c517, + 0x6b11_45ee_2a21_3e3c, + 0xf890_ed27_9b6a_2965, + 0x014a_ddc6_7a9e_923f, + ]), + F::from_raw([ + 0xa466_c129_3618_db80, + 0x2ce9_48d0_e92a_06e3, + 0x4f9b_5b9f_9d44_d08c, + 0x0afa_b4df_7911_d115, + ]), + F::from_raw([ + 0xcbe3_06a0_b9a0_0228, + 0x8d07_c0c6_8f84_fed9, + 0xae20_299e_ac58_c3d5, + 0x0756_ddc4_6866_ba28, + ]), + ], + [ + F::from_raw([ + 0x3bfe_afbd_30c4_1227, + 0x9e5f_672e_c4fa_5bb5, + 0xc3d2_90e7_2d8e_be6f, + 0x15ea_177d_8bc1_f254, + ]), + F::from_raw([ + 0xb7fc_c994_e326_3025, + 0xc99f_e627_5c38_f12f, + 0x671e_1ea6_167e_bb3d, + 0x12d4_1992_accc_7258, + ]), + F::from_raw([ + 0x822d_834e_689c_f8ee, + 0x1249_eb2a_583b_7060, + 0x79ae_47d4_2f9e_3e37, + 0x0570_a070_21e7_f0c9, + ]), + F::from_raw([ + 0x5f7e_f63f_63e6_d70a, + 0x6ddd_c3d2_7bbb_50c4, + 0x292e_4900_ac89_f5ba, + 0x21b6_e9c4_d6dc_7798, + ]), + F::from_raw([ + 0xeffd_5f31_f01f_c1f3, + 0x34a0_1c54_adc7_3f1a, + 0xaf16_96a4_973b_ac5a, + 0x0bd7_383d_ae8f_d3f1, + ]), + F::from_raw([ + 0x487a_a7ac_c82d_ee9d, + 0x3036_11f3_450d_52f0, + 0x90c3_9c5a_4a41_5ec8, + 0x11a8_66fd_59e5_ba1d, + ]), + F::from_raw([ + 0xaed1_5c82_979b_33d0, + 0xf44f_dd2f_a188_d4a4, + 0x73ad_9e1b_a623_3fda, + 0x2e33_0e0f_b295_5d84, + ]), + F::from_raw([ + 0x4d52_b1a4_f17d_9dab, + 0x9c04_c381_1b99_def6, + 0xb467_c5f2_4e44_2c93, + 0x2ec6_1414_7652_44f6, + ]), + F::from_raw([ + 0x0c0a_c783_b023_967b, + 0x5a90_f20b_a2dd_5132, + 0x04e7_7682_7dc3_72e5, + 0x137a_7708_38d8_5237, + ]), + F::from_raw([ + 0xe152_b332_765e_0c86, + 0x5dca_f294_0198_68e4, + 0x32a8_9f30_2002_00af, + 0x1d6a_e523_7bba_6b6e, + ]), + F::from_raw([ + 0x2e4d_703b_62fa_69de, + 0x0fd0_2029_9ac3_94ee, + 0x5773_c913_e88a_e791, + 0x1f90_37f9_189a_53ad, + ]), + F::from_raw([ + 0x6c9d_b1ea_bbb7_cf7d, + 0xb3b3_3146_5577_4774, + 0x77d0_2c61_bf2b_4b3d, + 0x2c60_1225_9c33_281c, + ]), + F::from_raw([ + 0x7b77_42b5_73d2_89eb, + 0x606b_2717_75f4_6edb, + 0x7520_9a75_abdc_35fa, + 0x1217_df83_0ec5_6445, + ]), + F::from_raw([ + 0xc663_fff5_7f8f_cbd3, + 0x5e71_d003_f19a_9fc0, + 0xd3d5_155c_58c5_4548, + 0x1d39_b721_d48d_3be9, + ]), + F::from_raw([ + 0xeeb1_dae5_7227_c237, + 0x2b0f_7560_26d7_9f32, + 0xc07e_41d2_859d_3df7, + 0x144e_f6b5_29a1_9c55, + ]), + F::from_raw([ + 0x1738_d767_4728_efd4, + 0x0164_4cb8_c381_ea3d, + 0x7303_e2eb_45b6_620d, + 0x2d26_6907_d986_d7e0, + ]), + ], + [ + F::from_raw([ + 0x2f87_d49d_4fb0_fe66, + 0x6a63_b122_f164_fd3d, + 0x52e6_4ce0_4b84_4efc, + 0x1b31_b63b_9c97_3636, + ]), + F::from_raw([ + 0x0228_0945_37ec_f537, + 0x5841_c562_0dab_1941, + 0xa253_80d7_38c6_cf4e, + 0x1a8c_452a_31af_dc62, + ]), + F::from_raw([ + 0x0ca3_46aa_a8b2_aca6, + 0xb68c_e7fa_8604_3591, + 0xc7a4_9079_76b7_b77f, + 0x0d9d_810f_c7da_5931, + ]), + F::from_raw([ + 0x3237_5a10_fecd_c8a5, + 0x1004_f8ad_f496_8190, + 0x4ad0_0ba4_aef9_a424, + 0x15e7_3088_41e8_2cb4, + ]), + F::from_raw([ + 0x30a7_d16f_e355_f765, + 0xc41b_face_db13_e095, + 0xe72b_481f_0c77_9a84, + 0x2e17_f718_ae9f_7897, + ]), + F::from_raw([ + 0xb6e1_e881_d4d0_2fa3, + 0xe58c_7ae6_7292_80d1, + 0x4c94_22ed_54f6_1b63, + 0x127e_7ffc_6ff8_ba19, + ]), + F::from_raw([ + 0x1a00_156d_3285_93f2, + 0x0863_fab1_0d19_4991, + 0xb6d5_e7fa_69d4_7f09, + 0x0c73_0999_ebda_c150, + ]), + F::from_raw([ + 0x46d3_5ef1_99f9_2a27, + 0xc576_2191_ef61_f1ef, + 0x8d64_9c5a_2fc4_136a, + 0x1114_1825_4b9d_16ef, + ]), + F::from_raw([ + 0x35ee_7c4b_754b_c846, + 0x95e0_26da_abb9_efc9, + 0x5699_b9bd_1150_8fe4, + 0x00d0_e323_2f7b_e8a9, + ]), + F::from_raw([ + 0x2281_1838_3790_c927, + 0x8d60_f80b_f80c_8d5f, + 0xb4ae_4dbf_64f1_96f4, + 0x2513_0e97_7ec4_f6be, + ]), + F::from_raw([ + 0x8fef_6b5b_290d_b4ca, + 0xe959_f6a6_843d_1f7a, + 0x163e_c1b6_1ac9_5a45, + 0x0cbd_22ca_7030_0072, + ]), + F::from_raw([ + 0x103e_5455_48b5_812c, + 0x69c0_8055_1d22_28d8, + 0xbc89_392e_b577_5c77, + 0x0c4e_5c71_b46e_2663, + ]), + F::from_raw([ + 0x9953_17a3_9d43_a3d1, + 0x921b_4aba_2d5b_f2d5, + 0x0bdb_bed3_e0f3_d8dc, + 0x0763_b557_31d1_0522, + ]), + F::from_raw([ + 0x40b1_42b0_66ac_f145, + 0x252b_1fea_5d30_b968, + 0x2cf2_48f9_d25e_724b, + 0x2e57_8b9c_3527_502c, + ]), + F::from_raw([ + 0x8869_875e_33a6_9381, + 0xf62c_afaf_5116_14bc, + 0xf785_0e56_ab93_4537, + 0x2d72_62bd_89e7_3f64, + ]), + F::from_raw([ + 0x0033_873c_59a8_db85, + 0xf31c_6f67_74dd_6933, + 0x433f_ac49_0b72_a375, + 0x233e_5ef3_9766_1c73, + ]), + ], + [ + F::from_raw([ + 0x226b_f73d_c724_bfb8, + 0xb574_4730_ee78_d2fc, + 0x4b9e_9e92_0145_3c82, + 0x2047_881d_542b_bf97, + ]), + F::from_raw([ + 0x61de_e56f_020c_ae02, + 0x8573_640d_fa8c_fb22, + 0x778f_5023_ac57_7ed5, + 0x1392_e09d_8e3d_6943, + ]), + F::from_raw([ + 0x1265_da3b_8009_8b29, + 0x9848_6c94_3d98_8b57, + 0x1edb_f8e4_0a58_f7f1, + 0x113c_e564_1e8c_0840, + ]), + F::from_raw([ + 0x5075_9ad6_6df3_ecf6, + 0x6fd4_88b7_a1a4_24bc, + 0xdbaa_7567_04f0_acca, + 0x06fe_34ae_e963_32c0, + ]), + F::from_raw([ + 0x75aa_d73c_a0c4_5808, + 0x51da_afd3_d4e6_2a8a, + 0x37ee_7f4d_b012_fa70, + 0x210e_eda9_0df0_688f, + ]), + F::from_raw([ + 0x6441_c8ec_db71_6178, + 0xcec1_e628_de46_f435, + 0xe26e_38e2_0658_61f3, + 0x28f5_5311_ca52_6e39, + ]), + F::from_raw([ + 0x7025_0016_052d_9532, + 0x64f5_b345_c86e_0ccf, + 0x5514_2e64_2194_ac4a, + 0x0fb3_a80a_4b52_8a89, + ]), + F::from_raw([ + 0x5f43_aaf9_30ae_a3a5, + 0xb71a_b147_df10_7fa7, + 0xb3ca_95f5_dec0_761b, + 0x1f67_8a57_a757_75bb, + ]), + F::from_raw([ + 0x1bf8_1c0a_a74b_a6c3, + 0x70e5_80de_e5cb_2916, + 0xce5d_def9_961b_5997, + 0x073e_e51a_98ae_a4e9, + ]), + F::from_raw([ + 0x7480_3ade_a417_e9b6, + 0x0da1_bcc9_f23b_afc7, + 0x0a04_f193_5069_1899, + 0x1236_c1a9_259a_cec5, + ]), + F::from_raw([ + 0x479d_261a_ad5d_780a, + 0xa827_3112_f54b_1f63, + 0x18a1_7756_db55_75e9, + 0x169a_b9a5_8355_57f5, + ]), + F::from_raw([ + 0x373c_81ad_4187_6f07, + 0xaaa4_9b61_0c7a_f1df, + 0xc241_30f5_9936_a05d, + 0x223d_c979_f283_3569, + ]), + F::from_raw([ + 0x9cf0_615a_614b_2a7c, + 0x7e85_338a_7cc7_b8db, + 0x4750_8f77_67fa_d20b, + 0x2a7e_07c4_2b26_4f88, + ]), + F::from_raw([ + 0x4682_2ffc_5833_20b2, + 0x9f9b_4c5e_0d3e_4286, + 0x7b0c_f45b_5f6a_e5b0, + 0x2d37_4c9e_c148_2f4d, + ]), + F::from_raw([ + 0x2522_8bb6_b171_9fcc, + 0xcf1b_1e67_920c_c619, + 0xc31e_2e9c_8a7c_1be2, + 0x1772_2a6c_97af_3611, + ]), + F::from_raw([ + 0x3f24_6ef1_7266_5c6c, + 0x0697_9950_789c_762d, + 0xab82_4d2c_7343_9bf3, + 0x1bec_21bd_2b79_bf0a, + ]), + ], + [ + F::from_raw([ + 0xc247_60c2_3b3d_2b94, + 0x7df0_e408_6f1b_6c13, + 0x0d0f_2e12_43ce_5e4d, + 0x1e4f_5c4c_1516_6b2b, + ]), + F::from_raw([ + 0x5924_2e34_7da9_08ab, + 0x042f_c65f_f587_a374, + 0x7e5b_bbae_d240_7aca, + 0x1b26_6d6a_03fe_6a66, + ]), + F::from_raw([ + 0x337d_6f7f_38f1_9d4f, + 0x6746_4d45_a092_c369, + 0x6123_1d07_2974_da78, + 0x0f82_ebb4_a3a2_d9c0, + ]), + F::from_raw([ + 0xb9cd_9d3c_da71_7c55, + 0xacb8_d63f_8ee7_34d9, + 0x98d9_57cd_63f2_c511, + 0x035f_0f51_0df0_53ad, + ]), + F::from_raw([ + 0xc864_8328_706e_59d0, + 0x8d8a_2f3a_98b6_80bd, + 0xaadc_256d_0ad6_4945, + 0x239e_2246_410f_90ab, + ]), + F::from_raw([ + 0xb852_b170_50a2_fe7d, + 0x5dd0_4f7b_91a2_64d4, + 0xb69e_8378_bec5_ecd4, + 0x230a_64e0_e395_31ba, + ]), + F::from_raw([ + 0xc7d4_ef53_76da_2669, + 0xe335_56e8_0ba5_1ec6, + 0xd97e_da0c_1ef8_f54a, + 0x201d_9359_2e63_dd8e, + ]), + F::from_raw([ + 0x76a0_d38c_d8aa_24a0, + 0x984c_18e2_c9ff_df6f, + 0xa698_85e6_3537_eecb, + 0x1bfe_78c5_0d0b_855a, + ]), + F::from_raw([ + 0x2427_4c56_27b8_bfbe, + 0x1b9e_c712_6ad7_30c1, + 0xc5c0_ddcd_865d_174e, + 0x3029_708c_7f3b_5baf, + ]), + F::from_raw([ + 0x8cca_d531_1d41_9393, + 0x9d61_3ed7_1ac7_39e8, + 0x54dc_fb7b_cca7_d8c6, + 0x15a0_692e_2778_0cc1, + ]), + F::from_raw([ + 0xc040_7f6e_79f9_9663, + 0xdcbc_6f67_e4c5_bbe3, + 0xb1f5_9255_bc74_ac46, + 0x1585_8088_5b45_21fa, + ]), + F::from_raw([ + 0xf0c5_a4c6_d8c5_bf53, + 0xefcf_2262_96ce_6b99, + 0xfda8_d1c5_9e5d_f8a9, + 0x22e5_4270_9e13_6b18, + ]), + F::from_raw([ + 0x1a43_0f92_3484_5fc8, + 0x074b_711b_1068_13e3, + 0xb189_b56d_89e1_fe31, + 0x0009_84d1_84c2_0909, + ]), + F::from_raw([ + 0xb878_0093_af2e_76c8, + 0x63fe_f919_1377_9d6a, + 0x4bba_3c23_af14_460e, + 0x260b_b2c2_f561_af7b, + ]), + F::from_raw([ + 0x0f47_b2d1_2076_5cae, + 0x21c4_326c_188c_47b7, + 0x1ae5_6bbe_1978_6ebf, + 0x0026_e2ea_372b_4982, + ]), + F::from_raw([ + 0x02ae_a30a_e1a2_f4d5, + 0xbaf3_8b59_f96f_d0aa, + 0x39d9_6876_a304_0224, + 0x0b6c_4d9d_36fa_c303, + ]), + ], + [ + F::from_raw([ + 0xd6ec_65b3_c137_53f3, + 0xab9a_8bd9_d382_86f8, + 0xb374_3bfa_bc21_490b, + 0x2cf5_fc3d_75ef_42b5, + ]), + F::from_raw([ + 0x16ce_4fdc_40ff_1e62, + 0xff1e_7be7_bdf6_00be, + 0x4000_f044_143f_a266, + 0x0846_aa6a_a21f_18c7, + ]), + F::from_raw([ + 0xada0_53ac_d9d3_ba40, + 0xd0a9_5204_d648_fbce, + 0xb3e4_c638_7338_94d5, + 0x002f_8d0e_c8cf_06bd, + ]), + F::from_raw([ + 0xcbdd_959f_6112_6f87, + 0xdb96_30f3_bf59_63f1, + 0xea0b_cdd5_8063_f744, + 0x1ce8_ff9b_74b7_9c4c, + ]), + F::from_raw([ + 0xe84f_4dee_795d_c1cd, + 0x33a8_a9e0_8628_bbe1, + 0xe615_c442_c6ef_0833, + 0x017d_7911_1e38_5452, + ]), + F::from_raw([ + 0xab74_953c_08b3_c55c, + 0xd899_b06d_63af_1036, + 0x8c96_92ab_e74e_7db7, + 0x27d0_64df_b09c_5134, + ]), + F::from_raw([ + 0xe512_1d74_e2bf_2f53, + 0x5961_ea46_2f0c_4817, + 0x6925_46b8_8bc0_79d8, + 0x1468_74a6_8df3_3461, + ]), + F::from_raw([ + 0xdd17_d373_e9a9_4852, + 0xf6cf_de55_9b24_e7df, + 0xcf5d_1e50_b877_0c1b, + 0x052b_6352_c27d_080d, + ]), + F::from_raw([ + 0xcb0f_3b19_d469_1159, + 0x6693_6757_2252_eb82, + 0x1bef_0f79_ab4f_9604, + 0x1e74_3894_6d79_cd19, + ]), + F::from_raw([ + 0x376e_fc73_8670_2426, + 0x2e91_e141_0e5d_d9ac, + 0x3d61_6d59_fe10_10c9, + 0x0470_9da1_736f_aef4, + ]), + F::from_raw([ + 0xddc5_17db_813f_62fc, + 0xb363_62f8_85b7_53b1, + 0xb06b_b696_c5e7_ec20, + 0x2838_1d4a_02a8_a55f, + ]), + F::from_raw([ + 0x4cbf_ff15_07a4_7113, + 0xd7fb_a825_6b9a_52fb, + 0xd3f4_0b2c_be9f_0a6a, + 0x160e_cf90_b4e2_7a49, + ]), + F::from_raw([ + 0xaabc_c947_35a4_704b, + 0xdf96_d086_7bbf_d6cc, + 0x836f_39b2_7733_745f, + 0x030e_521d_91a1_e1f8, + ]), + F::from_raw([ + 0x58ba_d9e4_4657_c43a, + 0x8fd3_e909_d9a3_b037, + 0x3cfb_6652_16f8_6b45, + 0x2b66_af33_183a_a4e5, + ]), + F::from_raw([ + 0xca5b_c8a7_52aa_bb53, + 0x04d6_1ab3_67a2_1058, + 0xa92d_8b88_d6fd_8f9b, + 0x1e85_16b0_a227_6dcb, + ]), + F::from_raw([ + 0x4eb7_e20d_5118_26b8, + 0xe0b8_ab75_b8ad_f804, + 0xebdf_6b89_af51_6d2a, + 0x2b21_72b7_3311_ff4e, + ]), + ], + [ + F::from_raw([ + 0x9145_21ba_b143_71e6, + 0x14e7_df6b_b6d5_2cb8, + 0x2291_2c8b_aa94_c39e, + 0x064c_2e06_3684_5a3b, + ]), + F::from_raw([ + 0x964d_6a4e_b059_b417, + 0xbd47_b34c_60df_f0ac, + 0xfe5a_1860_1bfe_d7d2, + 0x1bd4_f896_7e44_3e8e, + ]), + F::from_raw([ + 0xeda9_5827_4d54_3430, + 0xf030_092e_0f16_f539, + 0xbe10_620e_adb0_fafb, + 0x04ef_c234_a173_6354, + ]), + F::from_raw([ + 0xebde_88b8_78df_46db, + 0x7e8e_6632_d30e_28aa, + 0xe413_777f_74a3_53c5, + 0x2f42_fc1f_05d9_0dbc, + ]), + F::from_raw([ + 0x22be_96f2_9d9b_5369, + 0xfd23_e6d4_d490_6d06, + 0x7731_f599_4f19_3b35, + 0x0a3f_dc6b_2d46_b004, + ]), + F::from_raw([ + 0xeced_2ceb_b547_d960, + 0xff03_1aa4_6a27_c92c, + 0x1450_314f_356f_ccee, + 0x0a9a_381a_6f2b_e5b7, + ]), + F::from_raw([ + 0x25c5_57eb_3ffa_487a, + 0x4515_d3ec_c6ee_6d99, + 0x5bc0_60a3_9053_d85f, + 0x2bf2_a0d3_ac00_be9e, + ]), + F::from_raw([ + 0x72d4_ca49_fd02_cfa0, + 0x2753_4148_7b48_09a9, + 0xf9ba_a0b0_aa9d_bb3a, + 0x149c_ea4a_cc9d_345a, + ]), + F::from_raw([ + 0x7dbb_9bcb_58a0_bf21, + 0x25f5_0f15_03cf_4a63, + 0x0e1b_35af_19c9_3b0c, + 0x2ead_343a_42b0_ea57, + ]), + F::from_raw([ + 0xb157_7394_d752_7edf, + 0x432d_e342_5186_51f8, + 0xf6ad_891a_db1c_c2ef, + 0x1c12_759c_6c33_c9cb, + ]), + F::from_raw([ + 0x74b3_1fcd_353d_879b, + 0xa8b0_83a3_8c0d_4bae, + 0xf6bc_79b2_c720_4eb8, + 0x1619_230f_eafc_8101, + ]), + F::from_raw([ + 0xeb56_3580_8ecd_b46e, + 0x75cf_af7b_a591_f02e, + 0x1ace_09b0_abe8_b6dd, + 0x2bdc_4bb8_7fec_eca6, + ]), + F::from_raw([ + 0x78b6_bf95_d7df_6a3d, + 0x41f0_f98e_36b6_2519, + 0xe697_2fdf_0057_80ae, + 0x1d83_3c71_35d2_7610, + ]), + F::from_raw([ + 0x8342_2e98_7782_009d, + 0xba34_01fe_c67b_6b6d, + 0x96fc_ca19_6dd0_4f81, + 0x1ff7_a459_526e_7963, + ]), + F::from_raw([ + 0x16a9_7f94_d8d6_6b28, + 0xf3ba_1748_ccb0_6f3a, + 0x771a_e135_94f3_1b06, + 0x2440_fbb4_876c_f36a, + ]), + F::from_raw([ + 0x8bb5_51cf_f3eb_b3e6, + 0x5c9a_7527_3911_cded, + 0x79fe_d067_da28_04f7, + 0x10e5_d84b_11ab_8648, + ]), + ], + [ + F::from_raw([ + 0x2e9e_3928_4f3f_6262, + 0xb4f1_d179_3962_9fea, + 0x3064_d0f7_7480_bc78, + 0x2e56_c183_0fe6_6370, + ]), + F::from_raw([ + 0x0881_9e75_029f_46f5, + 0x66b9_8cc4_dd0e_a74f, + 0x087a_2f4b_38ca_ddb3, + 0x0a09_9027_ca6f_5c10, + ]), + F::from_raw([ + 0x4ee7_8ff8_5294_9904, + 0x602d_e695_fc53_9d28, + 0x57de_c26d_d4f1_7af8, + 0x1a97_468d_8d9b_841a, + ]), + F::from_raw([ + 0x3187_a751_a908_358d, + 0x6455_a216_2f13_7438, + 0xf499_5c77_b6b7_f9ce, + 0x0394_a645_8349_a524, + ]), + F::from_raw([ + 0x63c0_f86d_79de_9591, + 0x48c6_dcde_faac_70bd, + 0x5263_5296_432f_576a, + 0x1216_cf8f_079a_0988, + ]), + F::from_raw([ + 0xab66_5cc5_8c0a_6003, + 0x3343_b8ba_65e3_f969, + 0x99fd_185a_be97_7262, + 0x21c5_3a9e_e1d8_f710, + ]), + F::from_raw([ + 0x00a4_141f_e92a_1275, + 0x8459_d452_a345_60c0, + 0x25c7_0990_6332_ec21, + 0x0d00_e1ec_990e_bd52, + ]), + F::from_raw([ + 0x6bc3_1130_e994_2fd9, + 0x8cc1_3bee_d3e4_9d99, + 0x4f6a_52cc_876b_33ec, + 0x0790_36df_6b30_a36b, + ]), + F::from_raw([ + 0x3420_cabd_acc1_6580, + 0xd576_6d43_a8f3_2473, + 0x1407_e647_c129_0a42, + 0x0731_6c90_d570_97c2, + ]), + F::from_raw([ + 0x95d7_4803_8570_85b3, + 0x8d6a_c61c_96a2_1f31, + 0xbb0f_cf41_14d8_4dba, + 0x2caa_85f3_b813_2001, + ]), + F::from_raw([ + 0x5f2e_9243_fdd9_8df5, + 0xcd11_dd07_31f9_69f9, + 0x430f_ce23_3abf_e21f, + 0x1a5b_32a1_2269_6df0, + ]), + F::from_raw([ + 0x30a5_eacb_0ba0_2e1a, + 0x3b3a_d2bc_79f7_c8c9, + 0xb58b_a0cd_d75b_31f8, + 0x1d46_a763_3417_0cf0, + ]), + F::from_raw([ + 0x36d8_a8be_f084_e956, + 0xab3a_1202_4e23_0e85, + 0x71ea_6998_f890_a532, + 0x0d99_bf04_8437_a3cc, + ]), + F::from_raw([ + 0x339c_d87b_f2de_f560, + 0xf447_302a_246b_922e, + 0x04c6_1726_fec2_2341, + 0x1afc_2f4c_8ba1_26e3, + ]), + F::from_raw([ + 0x27b1_4c4c_53ff_491c, + 0x2ba8_1407_e713_21c7, + 0x4da9_bcf4_5bde_c1d9, + 0x1c9f_11e8_631c_d466, + ]), + F::from_raw([ + 0x9d6b_a1a1_dd94_d3e0, + 0x0872_1eb8_81f6_a49e, + 0x2a29_efe1_8ea8_7ec1, + 0x1992_68e3_ac14_b60c, + ]), + ], + [ + F::from_raw([ + 0x8a5d_d88c_af5d_5657, + 0x5bdc_e03e_3eac_b2ee, + 0x31e8_3de4_2d47_ab80, + 0x22c3_35d4_7bf6_7180, + ]), + F::from_raw([ + 0xed8d_d5fb_75db_41b9, + 0x1cfa_192e_406b_bef5, + 0xb8ef_2d15_be5a_3a8d, + 0x1160_bf99_f0f4_ec07, + ]), + F::from_raw([ + 0xe674_d8ca_01cb_f08c, + 0xe001_94f7_472f_a41d, + 0x1387_dac3_554c_fc9d, + 0x2254_cd32_fd40_87b7, + ]), + F::from_raw([ + 0x8033_602e_73d6_47e5, + 0x5ec6_73bf_25d6_93d9, + 0x6fe3_0958_a36b_d6e7, + 0x1919_751c_378a_8250, + ]), + F::from_raw([ + 0xa512_0a63_cb4f_768e, + 0x4e82_a539_fcf5_c899, + 0x2381_ac94_cdf8_8b3a, + 0x2791_6b3e_4a0c_8992, + ]), + F::from_raw([ + 0x7310_c749_b779_85c8, + 0x3ec2_08dc_0434_1455, + 0x7361_6a6a_5a1b_81c9, + 0x268d_3ff9_e18d_c9c3, + ]), + F::from_raw([ + 0xdc9e_59bb_ba66_9f2c, + 0xd5c9_1117_3de4_1ac1, + 0x7b3a_2ae3_ec04_6c13, + 0x2128_6d51_d350_476f, + ]), + F::from_raw([ + 0xfc9b_720f_2229_941d, + 0x4125_db54_d560_0a06, + 0x4b6c_b632_4f70_5434, + 0x20fb_f8d6_843b_ac84, + ]), + F::from_raw([ + 0x435e_bcac_cc77_4f44, + 0xa84d_a724_036a_003d, + 0x030a_ab81_b256_c8b9, + 0x1a2f_b574_43a3_a3d7, + ]), + F::from_raw([ + 0xa076_4b6b_190f_a139, + 0x4a35_a8cf_0771_061c, + 0x2bbc_e32f_178f_5907, + 0x21b1_3b9a_4cb8_e971, + ]), + F::from_raw([ + 0x0ba1_5573_bba3_c5d6, + 0xc292_a63d_d9f7_d309, + 0xf71f_d201_baa6_412a, + 0x2c7a_1181_5a42_0038, + ]), + F::from_raw([ + 0xf91c_a06a_37f7_fb35, + 0x8ace_7068_2325_3bf6, + 0xe58b_ffd7_17b1_287c, + 0x18c9_6380_9462_6db7, + ]), + F::from_raw([ + 0xbf3d_9f9d_f1aa_1cc7, + 0x4764_481d_e793_f828, + 0x4b5b_ff23_de0d_41bb, + 0x136f_b4ab_c4e0_94fb, + ]), + F::from_raw([ + 0xe193_2572_c657_96a8, + 0x6afa_a5ba_d677_24d8, + 0xa188_a011_089b_92d2, + 0x03ec_0f79_bf77_30bd, + ]), + F::from_raw([ + 0x2b9d_c250_5412_57d0, + 0xea0b_e483_fe4f_631c, + 0x2c77_94c3_2da9_5ada, + 0x0629_f306_d8b1_a068, + ]), + F::from_raw([ + 0xac09_72ea_3984_10d6, + 0xa12c_28a0_a793_5c0b, + 0x2168_4270_879d_f687, + 0x1f08_54ee_6861_4917, + ]), + ], + [ + F::from_raw([ + 0xfafe_98ef_48ea_713c, + 0x310d_87f9_5042_402f, + 0x2585_ac43_9ae4_eda9, + 0x0589_28f7_c7b8_503a, + ]), + F::from_raw([ + 0xfb97_2ee5_19ac_e172, + 0xe86c_0434_41cd_3623, + 0xfa9a_cfce_e249_f788, + 0x2fe5_a4fa_c888_cf8d, + ]), + F::from_raw([ + 0x1d50_24dc_885b_8d98, + 0xdd5c_d3b3_4d41_5654, + 0x12ff_8402_ad22_2c21, + 0x29e9_5404_5ccc_ab96, + ]), + F::from_raw([ + 0x1f11_791e_6395_7b20, + 0x3927_2092_312a_2a77, + 0x8de8_81d1_0464_3c9c, + 0x251a_3962_ba0f_3e9f, + ]), + F::from_raw([ + 0xee8d_26cd_c64b_101d, + 0xd102_c670_1083_c6af, + 0x0ee5_bbc4_704e_c638, + 0x0eb0_4f89_599c_ba10, + ]), + F::from_raw([ + 0xb77f_6e2d_2368_b082, + 0xb300_8c26_3e73_8ed1, + 0x3133_00f8_a161_c6d6, + 0x2d20_57eb_b487_8c47, + ]), + F::from_raw([ + 0x7e76_3cc8_c097_1556, + 0xf8af_e02e_faa7_24d9, + 0x2061_f594_6a10_f248, + 0x0f53_7c76_81ea_ad75, + ]), + F::from_raw([ + 0x06fa_7878_232f_1cfb, + 0xa043_561b_79e8_b6c3, + 0xee68_0f23_d34b_a07e, + 0x1e40_b9aa_000d_70d6, + ]), + F::from_raw([ + 0xe033_678f_ac84_b2f7, + 0xb118_0c41_d758_5ef4, + 0xe3ff_99d0_ae54_aa6c, + 0x1aa3_8f4a_119f_a9c3, + ]), + F::from_raw([ + 0x1c6f_2383_a619_49a9, + 0x5daf_6496_7bab_03b9, + 0xc425_af8e_dbc5_a45a, + 0x0566_1c02_3cc8_ffad, + ]), + F::from_raw([ + 0x9cd1_b29e_2db1_50e0, + 0x3e96_25fd_44f1_f138, + 0xfc1c_27cb_6b1d_ec66, + 0x023c_4d9d_809b_0d3a, + ]), + F::from_raw([ + 0x89b3_e407_03db_42b6, + 0xdcbb_f265_9627_8dc7, + 0xe796_5393_a8bf_d15d, + 0x09fa_c0eb_9231_850d, + ]), + F::from_raw([ + 0xa623_1bb4_780e_354d, + 0xd474_9cd1_9105_1bf8, + 0xed5a_c312_f5d4_4e27, + 0x040b_84ab_0073_7103, + ]), + F::from_raw([ + 0x4899_e57d_70df_f93b, + 0x8196_28b2_6456_d724, + 0x67ce_846c_9eb2_23e3, + 0x2e2e_b4b8_3545_72c2, + ]), + F::from_raw([ + 0x7b1f_8bad_50c9_7e35, + 0xc588_ac10_b738_ccad, + 0x3cf8_7bfe_b881_0be5, + 0x1987_28ec_996a_d095, + ]), + F::from_raw([ + 0xbd8d_f388_870c_5b24, + 0x9834_0052_516b_3a54, + 0xa91c_1cc7_0772_ed6f, + 0x2f8a_8ee4_1d90_aac2, + ]), + ], +]; +// n: 254 +// t: 16 +// N: 4064 +// Result Algorithm 1: +// [True, 0] +// Result Algorithm 2: +// [True, None] +// Result Algorithm 3: +// [True, None] +// Prime number: 0x0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 +// MDS matrix: +pub(crate) const MDS: [[F; 16]; 16] = [ + [ + F::from_raw([ + 0x1839_3373_7a8b_8099, + 0x5a12_255c_37ab_51ae, + 0x206c_43da_ac75_2b76, + 0x2b6f_d7bc_3a3b_595c, + ]), + F::from_raw([ + 0x9c90_665a_a2d9_2cb3, + 0xcffe_78d7_47fa_edad, + 0xd3f0_7d0c_3e6c_ecd6, + 0x069b_1779_dec3_eade, + ]), + F::from_raw([ + 0x8a6f_4cf7_76d1_3b99, + 0x554d_ddda_89d3_2dcf, + 0xaaa5_98b7_771f_88a0, + 0x1fa4_effc_8349_8d19, + ]), + F::from_raw([ + 0x9204_3dff_cb26_bf41, + 0xdeeb_0996_4769_8815, + 0x4c37_ec8a_e1a8_314b, + 0x0167_6f5c_0741_7ab5, + ]), + F::from_raw([ + 0xb9b7_e744_48ee_27ff, + 0x814f_e687_b4c8_eb81, + 0x58aa_07bf_54ff_324b, + 0x1f4e_7bbc_8d42_779e, + ]), + F::from_raw([ + 0x0df9_05d4_cbd1_dfa9, + 0x35c2_9647_9f48_4b68, + 0xa99a_04c8_c96a_e5db, + 0x0f6b_18c9_8fc8_9fbf, + ]), + F::from_raw([ + 0xc439_f5c1_f4fe_f54b, + 0xb004_5af0_6c2d_86d0, + 0xc6c1_91d3_6329_f30e, + 0x00e6_cd10_883e_1e11, + ]), + F::from_raw([ + 0xcc28_4d98_3bca_8757, + 0xa514_198b_296a_1629, + 0xbc71_70a2_ffc2_4eb6, + 0x0425_a964_1fb0_1558, + ]), + F::from_raw([ + 0x0e82_33c5_8dd5_0335, + 0xcd5c_ad2c_3988_8495, + 0x9413_48de_45ae_c442, + 0x0039_7a7d_7434_b0aa, + ]), + F::from_raw([ + 0xec20_d3b9_3252_ad04, + 0x0bac_2f7c_d9df_accd, + 0x1385_c22e_203d_c08f, + 0x1d66_f208_fc04_411a, + ]), + F::from_raw([ + 0xbd96_7e6a_3676_f356, + 0xe7ec_8188_5a07_a5bc, + 0xdd1f_db17_b9c7_c648, + 0x0ec1_ed3a_e3be_ac4d, + ]), + F::from_raw([ + 0xd69a_3f79_0b27_c603, + 0xc1cc_2c0e_d812_6534, + 0x0214_362c_8419_474d, + 0x0b3e_601e_36a5_d82e, + ]), + F::from_raw([ + 0x090a_07e1_4af1_0b0d, + 0xdc4c_e592_6771_8cc6, + 0x7b25_b095_a3aa_a8cf, + 0x163c_b4e3_a5ec_92e5, + ]), + F::from_raw([ + 0xccde_3aa3_a51d_41cb, + 0x3364_6b89_620d_d0a8, + 0x895f_48d7_a129_0d7a, + 0x2dca_90f3_e5a1_5b29, + ]), + F::from_raw([ + 0x1122_d64f_729c_ff22, + 0x93cb_33ff_671b_737a, + 0xbeb9_dc07_33c4_bb18, + 0x2c78_ee5e_a16d_38f0, + ]), + F::from_raw([ + 0x6647_1fa7_30f1_9c79, + 0xff75_3e32_92bb_f62e, + 0xdcf0_0439_c75a_294b, + 0x2af3_24ec_4f9e_7786, + ]), + ], + [ + F::from_raw([ + 0x6946_efbf_a489_3e97, + 0x076d_61f4_3509_4ea1, + 0xdf87_412a_537f_6601, + 0x111d_04c0_83f5_1a6f, + ]), + F::from_raw([ + 0x4144_8abb_632a_764b, + 0xc6d0_0bde_82bd_7f54, + 0xb370_2351_8a07_1675, + 0x187a_ae26_1ef3_ee21, + ]), + F::from_raw([ + 0xb1a7_aa21_6638_22b1, + 0x576e_5b28_2f28_4795, + 0x96a2_568b_2dd7_a584, + 0x0da2_8ede_7f63_f755, + ]), + F::from_raw([ + 0xf215_ab1f_7f03_498b, + 0xcc76_4f9b_1c8b_a463, + 0xa3b2_da5e_3010_7716, + 0x2043_bfe5_2d29_64e4, + ]), + F::from_raw([ + 0x8c40_d908_dd25_70ee, + 0x59fb_fbe7_1e09_6d51, + 0x938a_ea3e_b552_0915, + 0x27b4_8a63_6a39_b51a, + ]), + F::from_raw([ + 0x1686_4f3c_73eb_b7f9, + 0xac62_ade0_c501_347b, + 0x2acf_7856_d6de_a3bb, + 0x17fe_75a3_d11b_4b9d, + ]), + F::from_raw([ + 0xc7cc_6f6d_3752_2a59, + 0x152c_a963_2124_216c, + 0x8526_54fb_13ff_f42a, + 0x2326_c3dc_a7aa_b6b1, + ]), + F::from_raw([ + 0xea5c_6517_b046_eb9e, + 0xcb0c_6f7d_0c41_55bd, + 0x9da9_2e33_237f_9a82, + 0x080c_4429_0922_7f4a, + ]), + F::from_raw([ + 0x81cd_9316_96fd_7837, + 0x65c3_7d3b_c6c4_b39b, + 0x9133_1bc9_0739_7db8, + 0x2b1c_00ea_0089_3f9f, + ]), + F::from_raw([ + 0xe90b_b68b_9010_9746, + 0xb014_5fc2_055e_4d5b, + 0xa859_43ff_af9c_04db, + 0x092f_03c7_e98e_61c2, + ]), + F::from_raw([ + 0x82d2_d65c_0fd8_d7ff, + 0xdbc2_1642_a16f_cc41, + 0x26c9_a2a6_6be4_ec75, + 0x2a0f_77bb_3624_fc48, + ]), + F::from_raw([ + 0xc568_7334_b607_da7c, + 0x7e86_692e_529b_6a1e, + 0xb79b_80e7_dc04_a72f, + 0x1083_b742_d353_32a8, + ]), + F::from_raw([ + 0x0f3c_9ef5_1e28_e76d, + 0xd9cb_ced9_7ccf_1006, + 0x9d44_7b6c_edd0_b6aa, + 0x053e_95f9_455b_c649, + ]), + F::from_raw([ + 0x6cae_b89d_9e34_ee6e, + 0x0e85_19e2_b17c_fa01, + 0xe127_49b2_7d64_6e62, + 0x0590_4dae_3470_d40c, + ]), + F::from_raw([ + 0x6a4f_7927_4f2f_6b9b, + 0x19c7_7fd6_eea5_0612, + 0xa93f_476b_466e_3710, + 0x2e56_3b9d_c5a3_d4d5, + ]), + F::from_raw([ + 0xac5f_cc08_7ba2_d5b8, + 0x7ace_a41d_7f48_ff11, + 0xdd40_c942_6cff_4146, + 0x1456_0083_d980_d172, + ]), + ], + [ + F::from_raw([ + 0x5c78_5b70_988a_3a88, + 0x349f_d22f_2d53_530e, + 0xaa86_0d03_18f6_a4b4, + 0x0133_c591_3f25_ff5e, + ]), + F::from_raw([ + 0x6f0f_d509_b8eb_9c31, + 0x4cfa_d4f9_6dcc_7d63, + 0x2947_1e3f_ddc9_ef99, + 0x1695_3809_4d4f_7525, + ]), + F::from_raw([ + 0xee57_81a6_4f08_2439, + 0xf674_fcfa_1eb7_87df, + 0xc591_ebe5_14c7_f283, + 0x1998_35da_95f6_eb22, + ]), + F::from_raw([ + 0xeabb_b49a_25f1_05e5, + 0x3b56_5a0c_d2f2_18d6, + 0x0991_b39d_a129_f9d0, + 0x0dbd_8662_511d_d700, + ]), + F::from_raw([ + 0xd2ca_f613_920e_390b, + 0x1099_54d9_9e18_d72c, + 0x5db5_5077_dfa4_6e08, + 0x0dd0_c118_f15a_e07e, + ]), + F::from_raw([ + 0x22f4_afd1_8674_08c9, + 0xc246_9498_b9c1_e4d3, + 0x8a60_b0e5_f292_bb03, + 0x07c9_21bf_45e3_5484, + ]), + F::from_raw([ + 0x4e9b_895a_e141_da86, + 0xe555_b89c_0f49_b613, + 0x5bc0_26a1_864d_568b, + 0x1f69_4d1a_cbaa_b0ea, + ]), + F::from_raw([ + 0x7222_4d33_7402_bdec, + 0x4024_25ba_c3b8_5e3a, + 0xd5d8_3954_0a10_05ed, + 0x1604_de6a_2db1_22bd, + ]), + F::from_raw([ + 0x4f6f_e660_7523_aa08, + 0xec29_146d_f06f_db5b, + 0xf221_267b_b1be_1656, + 0x2597_0ce3_1b7b_10ce, + ]), + F::from_raw([ + 0xe532_636c_c607_82e8, + 0x711c_b8bc_b538_dd98, + 0xee97_e2eb_070e_9df2, + 0x1495_6f80_a65b_01f9, + ]), + F::from_raw([ + 0x0bbd_2cc9_eb1b_0a53, + 0x0503_dc4b_74da_40ba, + 0xf30e_dc47_b9e8_2adc, + 0x01d7_99ae_83ef_6552, + ]), + F::from_raw([ + 0xfacf_e546_66f5_90af, + 0xdceb_8399_1919_a9ca, + 0x013b_2b48_71c4_e9b0, + 0x1241_7c00_1be8_6197, + ]), + F::from_raw([ + 0x9462_b443_fa40_cdc5, + 0xb0c8_7d78_b46d_93bb, + 0x6a81_9e24_d0ac_ef08, + 0x2171_fd11_f944_8546, + ]), + F::from_raw([ + 0x958a_f462_efd6_45ff, + 0x5186_9bd3_0528_c378, + 0x3cc7_4fb3_d83d_4e33, + 0x22e9_bf2a_a02f_e65e, + ]), + F::from_raw([ + 0x80ff_4ef7_cc73_f0d9, + 0x7bbf_b315_1df5_10d0, + 0x9fbc_ea41_4a91_e7b2, + 0x072e_a2f5_cdc8_a378, + ]), + F::from_raw([ + 0x7025_0178_e9a5_2cf5, + 0x0bd8_4acf_7eb6_8548, + 0x61b8_f374_8c84_791c, + 0x260f_751c_7823_abae, + ]), + ], + [ + F::from_raw([ + 0x0e7d_0307_520a_56cf, + 0xaade_2840_6722_8f44, + 0xc2df_51a7_86bf_2207, + 0x0887_5f47_d6f5_18c8, + ]), + F::from_raw([ + 0xd422_0166_ea09_82d7, + 0xae11_57bf_507e_7799, + 0xb2f8_9be2_7373_d397, + 0x0a68_830f_19c0_a729, + ]), + F::from_raw([ + 0x5e98_41be_f7b9_210d, + 0xd99b_cba0_75ab_82b5, + 0xcc7f_78a4_d6e2_cd3f, + 0x2af5_6060_0b3e_25ab, + ]), + F::from_raw([ + 0x57d5_a844_7bdb_d6fc, + 0xfe28_dc0b_d8cb_1a44, + 0x581c_ac02_0051_de26, + 0x11b3_3a9f_1818_ed7f, + ]), + F::from_raw([ + 0xc8ec_5966_d6a4_c788, + 0x5a3b_69fa_7b7c_2ae2, + 0xfb8d_76e8_d380_322e, + 0x045c_617f_604c_1ac9, + ]), + F::from_raw([ + 0x9b56_9dc3_4f06_4c1a, + 0x3472_04b8_77e7_f85d, + 0xef7f_9b93_0355_312b, + 0x0e61_97fe_5023_28d0, + ]), + F::from_raw([ + 0xa7a8_4383_33f8_79cb, + 0xe8ff_323a_20be_6a6a, + 0x8dfb_6c03_88b9_daa1, + 0x0cdf_e099_e7a1_5427, + ]), + F::from_raw([ + 0xf42b_1f65_53bc_c655, + 0x8ae8_5803_aec7_a204, + 0x3fea_ddde_22ff_36fa, + 0x15de_d859_d501_c273, + ]), + F::from_raw([ + 0x81f6_1dd6_d621_4cef, + 0xdbcd_4224_0ed8_60f6, + 0xa300_abaf_2e1d_5c32, + 0x2d40_26bf_a7b3_7a19, + ]), + F::from_raw([ + 0x15bc_bbb6_5b12_88c0, + 0x6716_e6cb_5f89_5d27, + 0x8464_944f_7192_ecff, + 0x0bcc_b669_cb01_6d49, + ]), + F::from_raw([ + 0xa4fc_e114_6639_d0d5, + 0x72c7_71e1_0275_dccf, + 0x90ac_0f1f_45ec_2fb8, + 0x05de_1099_c65f_08a9, + ]), + F::from_raw([ + 0x44e2_b8e5_c437_9478, + 0x1f34_0461_72a8_2cce, + 0x9338_b427_b318_4d94, + 0x2c46_5d9b_5eb8_52d7, + ]), + F::from_raw([ + 0xf84d_4acf_d959_2d59, + 0xddd6_6835_94ef_9a83, + 0xbefc_2b17_1f99_ebe9, + 0x2391_8075_c8fa_0929, + ]), + F::from_raw([ + 0xe730_6967_480a_287d, + 0x757f_144d_f166_479e, + 0x5d97_452a_3c06_d9fa, + 0x15d7_fba6_2bac_57be, + ]), + F::from_raw([ + 0x7e51_811a_6831_1bbf, + 0x9f24_f1c6_e264_3094, + 0x9013_5595_5cc4_ddb9, + 0x02b6_f16f_812b_a903, + ]), + F::from_raw([ + 0x6068_5d89_0a24_fdeb, + 0xff0d_53a9_8e94_a2bc, + 0xea74_aaa7_802c_9c73, + 0x0f66_73b7_fb4b_e8cd, + ]), + ], + [ + F::from_raw([ + 0x9a7e_fe47_c947_3f21, + 0x728f_5f5c_a684_0664, + 0x23fb_a66f_2bc3_4152, + 0x0ba9_f44a_107a_81cb, + ]), + F::from_raw([ + 0xb85a_6569_7895_e63f, + 0xcb14_9b0a_fe38_d1bb, + 0xd1fc_5f05_fa0f_87dd, + 0x018a_e390_86ee_bb98, + ]), + F::from_raw([ + 0xc6d1_5683_3b34_c52a, + 0xb322_1fd9_b434_61dd, + 0xb549_b24a_65ec_84f1, + 0x1015_44d1_3145_4f20, + ]), + F::from_raw([ + 0xdb1d_6a77_71ec_6650, + 0x2488_5ec2_1762_bbb1, + 0x59bb_9520_6ce3_ed31, + 0x026f_2f58_d63c_a6ef, + ]), + F::from_raw([ + 0x13c8_ca91_c820_c2d1, + 0x3440_ead0_9995_8653, + 0xe4c6_246e_35f8_02e0, + 0x25b9_74fc_5129_d82a, + ]), + F::from_raw([ + 0x4bee_f9f6_21da_2ba2, + 0xbb67_3220_7925_d3ce, + 0xeca7_397d_0650_23f0, + 0x2d40_9bf7_8bd6_f6a4, + ]), + F::from_raw([ + 0x3855_0473_6aa8_6de6, + 0x6683_d30b_0241_5dfd, + 0x476e_7056_8d2d_cb0b, + 0x17f7_32cc_1354_b1fb, + ]), + F::from_raw([ + 0xb0fb_7a55_6889_3aac, + 0x6a2b_33e7_a22e_2710, + 0x7b74_a431_25cf_34d8, + 0x040d_b0de_fe6b_a479, + ]), + F::from_raw([ + 0x80e5_444e_5a52_c9c7, + 0x106e_0f5f_37d1_f2ab, + 0xff68_33d6_e227_42d4, + 0x29e8_9034_9424_14a1, + ]), + F::from_raw([ + 0x4175_4fd4_9f51_b225, + 0xb6f9_3f1e_537d_7d15, + 0xcf44_aacf_1044_cd6a, + 0x121d_2ba5_bd8f_232e, + ]), + F::from_raw([ + 0x94ad_f066_243f_f6bd, + 0xbb17_6a92_129b_34a2, + 0x2d8c_e73d_1cec_2b6c, + 0x0f09_13eb_4ee7_d3c0, + ]), + F::from_raw([ + 0x35e0_423f_b207_d979, + 0xfb14_d646_5f9d_1df8, + 0xc776_1008_732a_0097, + 0x0a0f_e66c_0d4d_e00c, + ]), + F::from_raw([ + 0x3189_9b06_46b2_f061, + 0x3452_8a07_52b3_9283, + 0xff6a_ba32_de5f_8194, + 0x0898_ed1e_c1a4_3687, + ]), + F::from_raw([ + 0x0d0d_a900_95a1_3262, + 0xb6e5_10d7_61e0_da17, + 0xd6d2_2805_974f_2539, + 0x11e0_b234_3ef3_71d2, + ]), + F::from_raw([ + 0xb974_a7f2_bc99_c946, + 0x77c7_d39e_f1b4_9166, + 0x4789_9377_da35_b7e6, + 0x1d59_d5c1_0b0c_9dd3, + ]), + F::from_raw([ + 0xf819_bdb5_fe54_241d, + 0x5f1b_bfae_b115_5f1a, + 0x2e6a_74f4_ec7c_d245, + 0x1a15_b7e2_de27_125f, + ]), + ], + [ + F::from_raw([ + 0x9769_8413_153b_a6f1, + 0xa244_2e99_8c53_81ba, + 0x4b54_7a10_6603_7152, + 0x0542_832a_b23b_6c7a, + ]), + F::from_raw([ + 0x9495_f7d7_b7f0_6cb1, + 0xe609_7abc_3d34_6f04, + 0x6127_6571_0bfc_b1c2, + 0x04c5_ebc7_7134_4cc0, + ]), + F::from_raw([ + 0x0d53_09e0_7d41_0e4e, + 0x66a1_1afb_5bc9_3cf1, + 0x4d4b_d7bf_5ce5_466a, + 0x1a51_740c_da5e_45ea, + ]), + F::from_raw([ + 0x21d7_cf32_90dc_6d08, + 0x390c_2488_6e1f_122d, + 0xad3c_b237_064e_c68e, + 0x2eb6_ed56_8377_b696, + ]), + F::from_raw([ + 0xef43_561d_58c5_926e, + 0xc25a_7ce5_8df0_6f13, + 0x492f_c3ec_7d8c_a8e3, + 0x1815_89b1_40c9_109e, + ]), + F::from_raw([ + 0xc50a_f8b2_92c0_ea42, + 0x9ebe_1ff0_9929_2b4b, + 0x668c_70fc_b415_82ee, + 0x205a_6d5a_ab2d_224b, + ]), + F::from_raw([ + 0x5c6b_4fa5_4014_8f43, + 0xaf73_6d4e_e6ed_991d, + 0xff7b_9aa8_de9e_3d81, + 0x2823_9a88_2dc7_b2f3, + ]), + F::from_raw([ + 0x578f_9fef_9a5b_b283, + 0xd458_60cc_0158_49df, + 0x77e6_15c8_c260_2193, + 0x1ab1_5f2f_de6f_535e, + ]), + F::from_raw([ + 0x312e_488d_8d6f_194b, + 0x30b5_39d5_c5ba_13b5, + 0xe1b2_81d0_fe20_6dff, + 0x032b_6266_f240_17fd, + ]), + F::from_raw([ + 0x7be9_3c9e_0c92_f3eb, + 0x16bb_ec3c_76ab_6a5f, + 0xf405_8a05_6110_a268, + 0x04e3_58f2_59a3_3244, + ]), + F::from_raw([ + 0x0196_d7e1_69c9_3b84, + 0x6ea6_0e63_858e_c5b5, + 0x9892_7b52_c24f_3879, + 0x25a9_ac2d_1ef8_4abd, + ]), + F::from_raw([ + 0x3dd5_df78_d340_721d, + 0x3886_755f_52bf_ec7d, + 0xe2bf_8484_fbbc_3984, + 0x2f52_1f24_bc02_286a, + ]), + F::from_raw([ + 0x2dfb_c38c_b679_d06d, + 0x4108_d8b1_4692_6655, + 0xacca_d181_b6e2_6547, + 0x1dc3_f7a6_5953_0a13, + ]), + F::from_raw([ + 0xf482_22bc_9020_92a8, + 0x1c7f_6400_5a83_a6f7, + 0x6fd3_83e5_35d5_6762, + 0x2ba3_9845_393f_cc77, + ]), + F::from_raw([ + 0x0f82_af5c_664d_6ea2, + 0x57e4_7085_2215_7bfe, + 0xa514_5a5c_48e6_0c54, + 0x0473_0fe0_4e01_08c9, + ]), + F::from_raw([ + 0x1e99_b5e0_8f01_cc74, + 0x77c8_51e1_a511_85f3, + 0x2ac7_fef2_7591_e76a, + 0x075a_09e4_1e74_de8a, + ]), + ], + [ + F::from_raw([ + 0xd1e9_e2ed_2690_6fa8, + 0xf937_906a_8166_41e0, + 0x2942_ccb6_edf0_51c8, + 0x0ba1_f764_3673_6095, + ]), + F::from_raw([ + 0x3ca3_ccac_81d9_e1e1, + 0xadf2_72a1_bfec_3c44, + 0x88d4_a601_e77b_d80a, + 0x29fa_a7da_dc8b_7e95, + ]), + F::from_raw([ + 0x88f0_a3b2_537b_dadd, + 0x40c0_085d_d5d6_065b, + 0x1b17_7901_28be_9f24, + 0x1324_558b_8a5d_4ba6, + ]), + F::from_raw([ + 0x4821_e034_7faf_53ec, + 0x92f3_8e02_ce36_3582, + 0xdbbd_12f4_08bd_5c5b, + 0x18fa_af1c_91e0_02f7, + ]), + F::from_raw([ + 0x9996_a32e_7cc5_23f3, + 0x5298_4134_4538_d649, + 0x38dd_2629_2b39_e260, + 0x0ee1_288b_2985_5e2e, + ]), + F::from_raw([ + 0x8e77_17b7_a52b_f106, + 0x1090_a4c7_ecbd_4e63, + 0xa7d1_16f4_a933_7eb3, + 0x2380_ab05_1d0a_c580, + ]), + F::from_raw([ + 0x397c_1c94_f650_f2cd, + 0x627a_5bd3_1315_808d, + 0xb321_b293_bb8a_8647, + 0x1589_26b9_e94b_10fc, + ]), + F::from_raw([ + 0xc278_e10b_f0bf_f5e5, + 0xdbbd_1197_a90a_456d, + 0x7675_1a89_5242_c30c, + 0x264f_adcc_791a_a18e, + ]), + F::from_raw([ + 0xc304_0528_e4a3_dfda, + 0x202b_7334_cf2e_0dd8, + 0x2239_bd94_11c0_a6c4, + 0x2ea0_14b6_1ed5_7539, + ]), + F::from_raw([ + 0x58d5_e6ee_caea_8fb1, + 0x3e15_a0b1_e4d9_3952, + 0x3531_8204_ba50_6066, + 0x2da2_603a_26d4_fdec, + ]), + F::from_raw([ + 0x2e98_d98f_9bb9_d104, + 0xc69e_c788_5bcd_0d2c, + 0x6af1_00df_df63_f8bd, + 0x20a0_e3f4_e124_9c4c, + ]), + F::from_raw([ + 0xdca8_ab88_6212_f0fb, + 0x1224_b5ef_b8b1_eb1c, + 0x6797_11e0_30bd_bae5, + 0x02f1_d3ee_d360_18f9, + ]), + F::from_raw([ + 0xfc36_6eae_770e_435d, + 0x2cf4_ffbd_9c69_4163, + 0xe372_080e_997a_3139, + 0x0e38_8bb1_0524_2406, + ]), + F::from_raw([ + 0x6217_0471_55c5_bf1e, + 0x50f8_9788_e277_6689, + 0xb00b_f34d_2aa1_a8e4, + 0x2514_3649_c13e_08d4, + ]), + F::from_raw([ + 0x4881_a271_9276_be0e, + 0x209d_8d22_b8b2_1ac2, + 0x9f95_2550_a223_a52d, + 0x12ec_2423_9ba1_b0fc, + ]), + F::from_raw([ + 0x9736_5146_bef9_c6ce, + 0x5cec_a9d6_5fba_020f, + 0x7dd0_bebe_9536_0064, + 0x079c_0494_4d50_b477, + ]), + ], + [ + F::from_raw([ + 0x34d3_cb6c_fd8b_7ffc, + 0x141f_4ed0_dc4b_0228, + 0x7bfa_f512_f21a_4081, + 0x2e06_11fa_4ca3_985d, + ]), + F::from_raw([ + 0x3b51_2e6e_8e8f_7fcc, + 0x7c89_33bf_aeb5_d746, + 0x8724_e7ce_da24_31e9, + 0x2acf_3493_012b_bd81, + ]), + F::from_raw([ + 0x0a80_8d66_f2d0_6b91, + 0xaab1_50d3_753a_5425, + 0xa774_3e7d_f8fc_8375, + 0x1347_3024_ba41_9fc2, + ]), + F::from_raw([ + 0x6aa6_5a9e_be69_788e, + 0x2043_9fcb_2a09_0e34, + 0x1f0e_3995_5f26_04bf, + 0x2943_7af1_b14f_637a, + ]), + F::from_raw([ + 0xc692_ac34_d7c9_8d34, + 0x946e_a86d_7304_b6a2, + 0x280c_c643_b947_9f49, + 0x206e_4d44_5315_b764, + ]), + F::from_raw([ + 0x729d_ca1f_9a74_e59f, + 0x11f5_d988_5e58_a9ed, + 0xe9ef_d80a_163e_6501, + 0x1382_c3c2_4bf2_489f, + ]), + F::from_raw([ + 0xc499_8135_fa5f_4aa0, + 0xdf93_5a82_f2a6_f432, + 0x0867_d372_64b4_ca14, + 0x17cd_1186_4fd2_c73d, + ]), + F::from_raw([ + 0x05c9_8d55_4db6_fad3, + 0xe9e3_ab32_fdff_0b3b, + 0x23a9_1a6c_d1aa_fb58, + 0x2de2_79fc_f77a_2708, + ]), + F::from_raw([ + 0x55d4_09ef_7512_00b9, + 0x80f6_e57d_c077_32a7, + 0xb7ab_e0cb_ea26_3966, + 0x12ce_d525_4e26_0a9d, + ]), + F::from_raw([ + 0x200f_b687_a8ea_5c83, + 0x8043_ab0b_ddf9_b9c3, + 0x1264_cf1a_36e0_fe4b, + 0x0ef5_f9ee_6ba1_ae1d, + ]), + F::from_raw([ + 0xc419_5a85_4722_bdfd, + 0x6693_be65_7489_492a, + 0xe4ef_0807_8e81_28a0, + 0x06b7_e18d_01b4_7ff8, + ]), + F::from_raw([ + 0x2be8_3767_06de_b20e, + 0x58a4_dbc7_c4b1_2eab, + 0xeec9_f35a_2998_6bc9, + 0x23aa_7ccc_3751_b740, + ]), + F::from_raw([ + 0x5189_e774_06a7_e86b, + 0x92af_6aaa_a7b8_44f3, + 0x3903_605d_7cc9_4d5a, + 0x2273_c370_eb58_10c0, + ]), + F::from_raw([ + 0x7c15_9c26_b963_2cd1, + 0xae84_20b1_ea46_60dd, + 0xe202_87a9_1abe_388a, + 0x2a73_10e7_5faf_e902, + ]), + F::from_raw([ + 0x1714_eea7_c7d8_2d49, + 0x5c8c_5083_f9d6_9bff, + 0x93ff_d3e4_81e4_a7b9, + 0x2009_8399_725e_e15d, + ]), + F::from_raw([ + 0x29be_8013_7fd8_972c, + 0x7392_3052_b6a0_1f3c, + 0x4e68_4123_f0ff_e221, + 0x02ca_2bac_7c1a_a0c6, + ]), + ], + [ + F::from_raw([ + 0x2500_8766_9789_7fb7, + 0x64b6_c08c_b954_a14a, + 0xec68_341a_8783_0fb8, + 0x0e6f_23c0_ef6f_159d, + ]), + F::from_raw([ + 0x1085_383b_6f6e_c4a3, + 0xad23_2d9b_f63c_8882, + 0xb312_ca0e_0cf7_0034, + 0x23b3_4612_e7d0_52f6, + ]), + F::from_raw([ + 0x3baf_dd99_3561_75f0, + 0xaedb_1013_9e30_53e8, + 0x3834_4655_0534_dc57, + 0x13f1_5bc6_453d_f6f9, + ]), + F::from_raw([ + 0x8877_8f72_8793_8d8e, + 0xdf77_6407_0a82_63cf, + 0x27c6_6f34_9486_2d75, + 0x0edf_86bf_1b15_99fe, + ]), + F::from_raw([ + 0xc5cd_a6ef_a8c9_93b1, + 0xf258_ba73_8f90_94e7, + 0x297d_aaa6_d4dd_b6a2, + 0x1641_648c_26b5_a2dc, + ]), + F::from_raw([ + 0x5062_5f2b_e52f_3a41, + 0xb834_1890_c332_9af0, + 0xc391_e94c_70f8_7120, + 0x280c_4522_ad0f_fd92, + ]), + F::from_raw([ + 0xcf71_ff5d_c0d6_1b1b, + 0xa44f_20af_3386_e13b, + 0xdb8e_7506_e6f0_372c, + 0x1d77_2098_b615_4921, + ]), + F::from_raw([ + 0x0702_0a22_614a_808a, + 0x39bf_355e_aca8_cc7b, + 0xf4b9_8149_2018_3dd8, + 0x053e_d8ad_550d_8992, + ]), + F::from_raw([ + 0x016a_c5ed_63a9_9a5e, + 0x7953_8d63_bce3_44f9, + 0x193b_9f87_0f44_9560, + 0x1d4f_9ba4_fd8c_e4ef, + ]), + F::from_raw([ + 0x41de_22c8_ba84_68a4, + 0xa2cf_b9fc_3c1e_791d, + 0xc471_5274_ad67_a5d6, + 0x0d53_d61c_8a52_14e0, + ]), + F::from_raw([ + 0x7f66_6f6b_a613_89b0, + 0x9d16_a87d_89c8_8905, + 0x287e_975f_2b4f_5b90, + 0x12cf_8725_3913_d45d, + ]), + F::from_raw([ + 0xd25f_0f23_7ff6_07fd, + 0xd329_f9a8_7824_69c4, + 0xabc3_25bb_a32a_a343, + 0x2b08_8cd3_0a10_899b, + ]), + F::from_raw([ + 0x96eb_e872_e1c1_9475, + 0xa43c_7ee2_0c88_e290, + 0x8be4_fb28_e4b1_9efa, + 0x1997_2ffd_de78_98ec, + ]), + F::from_raw([ + 0x0f91_0a75_e6f4_7739, + 0xbc80_4313_ef8c_6d8b, + 0xa16e_e604_2529_ff02, + 0x1fa6_9447_03fe_0012, + ]), + F::from_raw([ + 0x99d6_45ba_20f1_fc26, + 0xe28b_8f21_d033_fbf0, + 0x8ac8_4e62_3f48_3a6b, + 0x1823_7af7_33bc_4441, + ]), + F::from_raw([ + 0x05d2_07bd_317e_19cf, + 0x24fd_ca0e_95ba_9cac, + 0x4dce_f0f0_8edd_2415, + 0x13d9_035a_0dc7_98b0, + ]), + ], + [ + F::from_raw([ + 0xd9b8_b1b2_da46_1cbc, + 0x1c8f_7c2e_d2de_bace, + 0x5f72_0302_bead_7ca2, + 0x01a7_a2a4_a08d_87e7, + ]), + F::from_raw([ + 0x1876_7c97_cbe0_a197, + 0x31d8_6c4d_03a9_6dfc, + 0x0a4c_d360_7017_fa83, + 0x1168_0cc6_e80b_0e43, + ]), + F::from_raw([ + 0x8dfb_2210_b529_b4e5, + 0x36e2_b58b_fdce_b3d4, + 0x4453_2c9f_054b_3796, + 0x1314_b54f_8786_0962, + ]), + F::from_raw([ + 0x53a0_ce3e_29c7_eedd, + 0x1063_fa3f_6358_87e7, + 0xc832_46a9_6ebd_de35, + 0x1336_b208_e00d_8eba, + ]), + F::from_raw([ + 0xd7e9_71c4_4c04_8239, + 0x976e_087e_b899_0c76, + 0x0482_ef3b_dcf7_ef17, + 0x1887_be87_f7a3_5241, + ]), + F::from_raw([ + 0x61b6_2000_3b88_8204, + 0xd6bc_8139_82a0_e715, + 0x9756_8f1b_dcd6_d58c, + 0x1f40_5a94_8331_1e14, + ]), + F::from_raw([ + 0xc1e6_e486_0413_4264, + 0xf048_9a8e_900a_5f14, + 0x9fe2_b832_9125_e7df, + 0x2095_76be_72db_7b0c, + ]), + F::from_raw([ + 0x9fff_3cb3_8b22_245a, + 0xf620_f058_bf01_86ce, + 0xede9_4319_5269_c00b, + 0x0027_9702_b135_d144, + ]), + F::from_raw([ + 0x6591_df20_8b6b_2583, + 0x1fc7_edae_637c_c611, + 0xeb5b_714d_7b2e_bcd8, + 0x02c9_c313_5cf6_4b89, + ]), + F::from_raw([ + 0xc978_4cd6_4b18_3fbf, + 0x1871_f711_28ee_e3f0, + 0x7f51_8bb9_c6a4_ce50, + 0x252e_78b4_838a_d500, + ]), + F::from_raw([ + 0xcb39_8f71_c95b_668e, + 0xea9b_1bc9_621b_654f, + 0x3986_7842_fd0e_7d41, + 0x29a7_d554_e9ff_bee6, + ]), + F::from_raw([ + 0x50b6_0419_3e79_bc3f, + 0x4363_f21b_d720_3473, + 0x8e99_1382_9f56_0250, + 0x305a_0c2c_2c4d_3599, + ]), + F::from_raw([ + 0xd397_02b2_14dd_c5fa, + 0xecef_8907_5e96_c943, + 0xe2d9_6833_5b73_e15f, + 0x061d_78e1_953d_1943, + ]), + F::from_raw([ + 0x3179_d4bb_99da_cdc8, + 0xcf98_730a_9785_de39, + 0x2247_3b8e_39f9_48b9, + 0x261f_975b_abd7_6928, + ]), + F::from_raw([ + 0x995a_443e_d7df_68e9, + 0xcf06_a6eb_f58d_fa7a, + 0x23d1_b381_a6c5_8d0e, + 0x1e3d_6cef_37f9_bdac, + ]), + F::from_raw([ + 0x0489_b983_4540_32d4, + 0x2402_46a2_d0f8_5443, + 0xc56b_6e9a_201f_8b7b, + 0x1d66_57d7_9183_1169, + ]), + ], + [ + F::from_raw([ + 0x70ce_8613_4597_9d1d, + 0xbfc1_0ee4_86ec_c5b6, + 0x87db_b442_b482_cae5, + 0x1d80_05df_48c8_5659, + ]), + F::from_raw([ + 0xc8ae_6132_a3d6_907f, + 0x6298_f8f3_0a2d_1010, + 0x4446_23d6_7fe9_9111, + 0x1fa7_72eb_de6f_3732, + ]), + F::from_raw([ + 0x649a_f576_467f_d798, + 0x21c5_60df_2fd3_f6c2, + 0x63d7_b603_ef8c_d063, + 0x056a_8ecd_232a_674c, + ]), + F::from_raw([ + 0x6784_cc60_04d8_928b, + 0x48fc_5338_91f5_57e9, + 0xd560_84cb_4850_0fac, + 0x2646_341e_b44b_4800, + ]), + F::from_raw([ + 0xbc8d_3a6e_5822_09f2, + 0x2723_5a22_a1ed_4f88, + 0xb4a6_d9c9_8bbb_c160, + 0x231f_2c98_bda8_d48b, + ]), + F::from_raw([ + 0xb4d5_3128_26e8_9942, + 0xd8ad_d16b_5cbe_fb54, + 0x4857_b0bd_7d73_92b8, + 0x1caf_cfb6_2926_fbc0, + ]), + F::from_raw([ + 0x4ffb_4711_ade1_eb0f, + 0x03d5_94cf_4a0c_c67b, + 0xf773_7f04_4161_902f, + 0x0b7a_b1ef_17ff_6235, + ]), + F::from_raw([ + 0x73cc_7766_f96d_9948, + 0x6df4_29ec_c224_71be, + 0xb38e_b582_ac4a_bbb1, + 0x179a_82b7_7f2c_cb94, + ]), + F::from_raw([ + 0x23e1_e9ee_20b4_2558, + 0xdd1f_a01c_7ce6_121d, + 0x1904_8563_7844_2151, + 0x18b6_3685_f6fe_d2aa, + ]), + F::from_raw([ + 0xfcc4_7fec_5763_ce93, + 0x0366_68d0_a863_be50, + 0xae17_24f3_2f21_a06b, + 0x0a27_a8d1_af6a_0460, + ]), + F::from_raw([ + 0x8f3e_999f_b610_ed38, + 0xc274_4152_156f_bf7e, + 0x639c_dabb_acd0_1bf3, + 0x1867_5677_5058_d09c, + ]), + F::from_raw([ + 0x1c2b_2896_6d96_180c, + 0xa659_6598_a270_31ea, + 0x19dd_1da0_49be_b39f, + 0x08bd_9ddd_192d_797a, + ]), + F::from_raw([ + 0xdb93_c263_11a7_2017, + 0xf590_3e1e_75a5_0536, + 0x63ed_7a7b_d071_253e, + 0x1941_84a8_25de_9e9b, + ]), + F::from_raw([ + 0x9da3_567a_6dd6_ce82, + 0xa987_6792_d391_5c8b, + 0x643b_3008_085a_27f4, + 0x2e08_b28b_dcc4_17d9, + ]), + F::from_raw([ + 0xaaf5_401d_2c86_7e02, + 0x009b_079d_e877_fd54, + 0x16d5_dbe1_dd05_b22c, + 0x28e5_5b0b_ed59_1912, + ]), + F::from_raw([ + 0xcda4_23bb_b3ff_a786, + 0xb18a_c6b8_0e40_65fc, + 0x82ad_8f7b_d41c_12c3, + 0x1c89_d8f9_75f0_3042, + ]), + ], + [ + F::from_raw([ + 0x76d4_9d08_86da_16f3, + 0x82e5_e127_1618_858e, + 0xacb7_e98f_557e_7962, + 0x2812_2254_823f_8926, + ]), + F::from_raw([ + 0x25e3_3e19_b3c9_8494, + 0x8127_14d6_6041_32d5, + 0x8317_f259_2ebd_8db0, + 0x2e63_f174_0332_f57e, + ]), + F::from_raw([ + 0xc1c7_f95c_152e_e262, + 0x38b7_39d0_6158_2543, + 0x31e7_5132_e050_bf38, + 0x0098_b740_976c_2a10, + ]), + F::from_raw([ + 0xb1e5_edfb_1602_140f, + 0x4a04_bd9b_a5aa_2765, + 0x48e1_12a0_742d_8ae8, + 0x06f5_3c79_fed9_e098, + ]), + F::from_raw([ + 0xaa5e_5d11_561f_b145, + 0x98cb_53da_b519_9750, + 0x1fe1_1116_06af_396e, + 0x1fce_a892_86dc_1db6, + ]), + F::from_raw([ + 0x44a5_ffe9_e159_508b, + 0x083e_7e94_eec2_3e0f, + 0xeb20_3be5_6594_416b, + 0x0a12_e162_620e_71be, + ]), + F::from_raw([ + 0x8366_9680_8b12_d8e5, + 0x5730_86a5_d818_c038, + 0x716a_0e28_990c_af17, + 0x1b1b_bf4e_9f70_6051, + ]), + F::from_raw([ + 0xaa8f_6510_2123_efd7, + 0xa9b7_0e6d_5a60_3fba, + 0x5fc1_d5af_2f2b_5d47, + 0x089e_fed0_0e9d_993f, + ]), + F::from_raw([ + 0x3504_f9ab_26a4_3d15, + 0xb27c_df5a_0b83_ff8f, + 0x3d68_aacf_9c3a_8fff, + 0x2b20_2e1d_2626_c679, + ]), + F::from_raw([ + 0x061b_e3d4_d248_c862, + 0x25f7_5cee_9036_e66a, + 0xe5a5_3163_3ac2_2bb8, + 0x0304_8a26_5d0e_eb40, + ]), + F::from_raw([ + 0x5988_bf6d_fc01_0a6f, + 0xc6fb_6d4c_f885_f113, + 0xc3a7_ac50_b80e_c330, + 0x2532_dd74_87fc_ae0d, + ]), + F::from_raw([ + 0xc801_b789_79af_9e61, + 0x60ae_c058_348f_f220, + 0x8451_7ab3_def4_87c4, + 0x12ce_e8e3_d1ca_c1ca, + ]), + F::from_raw([ + 0xb9c9_b075_3ffa_efee, + 0xb295_1839_f71f_329c, + 0x6131_83ea_827b_91c1, + 0x21c0_d187_4dec_af90, + ]), + F::from_raw([ + 0x397d_5b6c_b805_387f, + 0xf6e5_419d_32f5_668d, + 0x768b_0e55_ec0d_4a85, + 0x017e_9ed1_91c5_641d, + ]), + F::from_raw([ + 0x7712_b35c_a26d_d045, + 0xc125_927b_d16d_e280, + 0x7449_19fc_555c_77c0, + 0x0c6c_9ec3_1c9e_3be0, + ]), + F::from_raw([ + 0xeb75_0145_f1a7_7400, + 0x95a6_446a_7605_3543, + 0x8965_e49c_8f31_5c29, + 0x2082_9ef3_df9c_183f, + ]), + ], + [ + F::from_raw([ + 0xaeed_6c61_050e_05cd, + 0x23b2_dcff_d579_a8e6, + 0xdf68_1328_e68a_582d, + 0x2414_d4ae_fc7b_4857, + ]), + F::from_raw([ + 0x9ed2_88bd_779b_14f1, + 0xb6b1_0c2a_09ea_eaa2, + 0x846e_9083_4efc_911e, + 0x1202_e349_d1d7_b805, + ]), + F::from_raw([ + 0x3cdb_48dc_8b65_f8e4, + 0x240b_acd8_1433_23c5, + 0x3fa3_2c2c_8e77_58cb, + 0x024b_96db_ebfa_b6d2, + ]), + F::from_raw([ + 0xd9c0_5c63_4b43_947e, + 0xad04_4291_f769_1974, + 0x5a1b_5155_2642_6384, + 0x2a3c_9f55_afac_ee73, + ]), + F::from_raw([ + 0x84ec_89a4_ae9e_d209, + 0xfab4_4a6b_f4fc_8ef3, + 0x144c_ee44_636b_dead, + 0x0f7b_fcfa_b17d_b34c, + ]), + F::from_raw([ + 0x8be5_6a0c_d44e_71ab, + 0x0dfc_6aa3_6f22_bdde, + 0x17be_2c27_d1c4_c596, + 0x1720_3c4d_2e1a_428a, + ]), + F::from_raw([ + 0xb14e_da9a_9752_329b, + 0xb625_5a6d_d820_81d6, + 0xcf7a_a03f_dd42_0c6b, + 0x22a8_ee74_3674_13ec, + ]), + F::from_raw([ + 0x9eda_be74_768b_60c0, + 0xe08c_cb03_e77c_5e0b, + 0xde25_ba60_5a86_cc08, + 0x21e2_5f0a_7f8e_dc38, + ]), + F::from_raw([ + 0xdad5_95da_7c6f_ecc6, + 0x9352_7dff_b43f_552c, + 0x41a0_89c1_5f95_3a21, + 0x06a7_8dfd_e145_8ee3, + ]), + F::from_raw([ + 0x7737_b1e5_a7d6_0d52, + 0x0aa4_9616_5d64_4d5d, + 0x3d31_a282_530d_5424, + 0x03fd_94e5_1bbd_a684, + ]), + F::from_raw([ + 0xd4f2_b88c_d13c_9fe5, + 0xab6a_f164_1fb1_f7aa, + 0x1d6f_e7fb_8a71_f1ea, + 0x02ef_e529_db1d_e3c0, + ]), + F::from_raw([ + 0xbacd_6840_06c3_7185, + 0x9441_7acb_2539_2342, + 0x0950_9f85_d3fb_d94e, + 0x0cab_504b_22a3_573d, + ]), + F::from_raw([ + 0x4749_05a4_fa36_d70e, + 0xce77_5a8d_af86_8e0c, + 0x0634_4343_2a84_7bcc, + 0x1cb3_3ad2_ba7d_d0c2, + ]), + F::from_raw([ + 0x593f_4454_5212_61f7, + 0x077c_d543_198e_1c27, + 0x6e34_7ec7_0596_2379, + 0x0aaf_37d1_f53d_d055, + ]), + F::from_raw([ + 0xae55_0d28_b365_4e73, + 0x86e8_102c_2b5a_d15c, + 0x0e84_e9bc_3e4b_4bac, + 0x2a60_7fac_d393_6fdd, + ]), + F::from_raw([ + 0xf283_0853_b9f9_039c, + 0xaf81_2d2e_f4d6_b037, + 0xdb98_1546_5332_02f3, + 0x14a2_bd5a_56f8_7009, + ]), + ], + [ + F::from_raw([ + 0xa33b_96e9_5d37_46b6, + 0x2b02_65d1_3e23_26a9, + 0xd87c_bffd_5566_5b47, + 0x2f71_0c72_d6da_19c7, + ]), + F::from_raw([ + 0x38f8_ce5c_d04c_237c, + 0x0ed5_c980_d3db_424d, + 0x034a_d4a4_fafe_e89f, + 0x168f_dc32_d4aa_8dc9, + ]), + F::from_raw([ + 0xc626_09de_da2d_0278, + 0xc909_a279_6d1f_77d0, + 0x0804_f2b9_b37e_069f, + 0x15bb_d561_9f0d_5979, + ]), + F::from_raw([ + 0x34ba_6106_7c6b_6d6a, + 0x553c_e86b_bc4c_349a, + 0x023b_ce34_2724_4ad6, + 0x1e16_e9ca_2502_d696, + ]), + F::from_raw([ + 0x612a_d4c2_8fd9_f9fa, + 0xad8d_5fc9_8f19_61f2, + 0x9f58_3bd0_ad35_de13, + 0x01dd_0a55_0274_3aaa, + ]), + F::from_raw([ + 0x9f6a_2226_e7a9_5db4, + 0xcd32_2bfd_6b50_f9ad, + 0xa7d1_f694_0f91_4e8e, + 0x0ed2_cfae_7b36_f470, + ]), + F::from_raw([ + 0xff2b_8e04_92b4_4d83, + 0x40fd_414a_be24_f0a9, + 0x5d08_f106_d5f9_9183, + 0x2c78_5f9d_8834_f5cf, + ]), + F::from_raw([ + 0x07f2_42e4_5b86_5eaa, + 0xb18d_3d78_a4f7_0fef, + 0x5c30_c488_46d7_bb0e, + 0x0d8d_bc3f_c854_c066, + ]), + F::from_raw([ + 0x3a9f_83b8_e8e5_8ffa, + 0x244c_f021_4b6b_543d, + 0x6ac2_512a_25db_9925, + 0x22f6_2e45_e500_8469, + ]), + F::from_raw([ + 0x7ffc_843f_6c77_d7ad, + 0x222a_307e_38fa_fc3e, + 0x439c_9f54_6abb_35a1, + 0x2f26_bc13_ae48_520a, + ]), + F::from_raw([ + 0xf207_9d3d_50e6_d4ea, + 0x99f2_b85c_1b89_fc5f, + 0x85f5_4476_2d9d_efdc, + 0x0af8_25f7_ca24_b4a2, + ]), + F::from_raw([ + 0xcccc_1ac9_a29d_2a53, + 0xf423_d37b_f483_c36a, + 0xf556_11c6_4489_12fd, + 0x1605_9096_8429_f480, + ]), + F::from_raw([ + 0x6082_ef18_b1d5_228a, + 0x38b4_051a_e251_4d4b, + 0xdb1b_6c56_493d_4c93, + 0x2bb3_2cf6_0f8d_469e, + ]), + F::from_raw([ + 0x57a5_95e7_fccd_c404, + 0x4429_8ba5_8fb5_04be, + 0xf6fd_e750_a184_7e5b, + 0x2a4a_72e9_dfe5_bf25, + ]), + F::from_raw([ + 0x93e7_3203_6f07_9d12, + 0x4160_8bbb_b6b5_503c, + 0x9041_0bea_34a8_9197, + 0x0c50_9a4b_f48a_d76e, + ]), + F::from_raw([ + 0x0561_9b12_a7fd_4e2a, + 0xde22_d372_0431_fc16, + 0xcd14_8461_617e_8e46, + 0x1997_33da_4aee_d8d6, + ]), + ], + [ + F::from_raw([ + 0xdbc7_c3c3_0320_c00e, + 0xd76d_a821_1b04_a236, + 0xb41d_6480_8368_50e4, + 0x2e28_5441_d0be_d90b, + ]), + F::from_raw([ + 0xe5d4_b182_0489_028f, + 0x130d_18c4_9464_d86f, + 0x651b_4b66_e34f_521b, + 0x0b9a_e9f5_ee6a_d70a, + ]), + F::from_raw([ + 0xc7b8_02e0_8948_e108, + 0x1c03_8ebc_dfdd_4025, + 0x2548_bed7_657f_17c6, + 0x0476_0054_bd5d_0713, + ]), + F::from_raw([ + 0xda96_306d_b1e3_a40d, + 0xd611_dbe2_5d1c_048a, + 0x96ef_8173_ae5f_e87b, + 0x02a4_c6d3_2597_79c3, + ]), + F::from_raw([ + 0x0b60_1667_4f3f_5efb, + 0x51b8_7b43_e591_81be, + 0xf483_4903_73e7_5b04, + 0x1959_db01_f5c8_bb0c, + ]), + F::from_raw([ + 0x443b_94f8_b1ce_7212, + 0xbcb9_3e1c_ef25_04af, + 0xc32d_891b_71fa_f500, + 0x1849_cd09_10d7_2eac, + ]), + F::from_raw([ + 0x90c6_bab1_59ca_4fb9, + 0xafc7_57ee_2677_3a02, + 0xa718_a102_e0ca_9177, + 0x04b5_dc20_57b8_8170, + ]), + F::from_raw([ + 0xc0a8_30c3_7e5d_cdc8, + 0x1b9d_af48_a433_74bd, + 0x22ce_3c50_ef47_1109, + 0x17bd_f338_0728_84b5, + ]), + F::from_raw([ + 0xe476_7e3c_10d3_b40e, + 0x78b2_1f09_0c53_042b, + 0xb849_6b8a_0a0a_90d5, + 0x2d93_79e6_9b17_8208, + ]), + F::from_raw([ + 0x3637_7f1c_5e67_ec30, + 0xa9e3_42a1_9e88_d423, + 0x3c16_6e18_fe90_4def, + 0x0140_57d0_2e5e_bcf3, + ]), + F::from_raw([ + 0xe986_b140_3cf2_70df, + 0xd884_1153_6618_12bb, + 0x0d8f_4f1a_458c_6a21, + 0x1781_8dd0_254b_291d, + ]), + F::from_raw([ + 0xd3f7_9379_7d7c_0a35, + 0xe10f_8d5b_db01_8032, + 0x4cdb_7f75_0a0f_e86c, + 0x1c95_c291_7353_c53b, + ]), + F::from_raw([ + 0x2829_ffdf_b3c1_a3c4, + 0x04d7_9dec_5658_2c29, + 0x4180_8149_333f_c43f, + 0x0249_5b3c_1bfe_c607, + ]), + F::from_raw([ + 0xaa39_e670_1595_3231, + 0xa911_700c_8d35_288b, + 0x38b2_bda6_e773_2990, + 0x2ade_c854_9dff_de72, + ]), + F::from_raw([ + 0xf90b_aaa3_b644_c4c6, + 0xf952_f8f4_cf84_d815, + 0x5e37_6584_b8b8_dfb7, + 0x1780_7430_3b90_d898, + ]), + F::from_raw([ + 0x8267_6448_95e6_737f, + 0x9a81_040e_a9a0_4c56, + 0x11fc_9477_f4fa_ffe7, + 0x1f5f_c060_028b_a07d, + ]), + ], + [ + F::from_raw([ + 0xc201_2e36_a19d_c95c, + 0x2077_a287_434b_da4e, + 0xa1a6_5936_62ae_b9e1, + 0x2964_901a_2b42_e9ae, + ]), + F::from_raw([ + 0xd67a_920d_8567_040a, + 0xef49_a540_fd2e_aea0, + 0xca13_a2a5_e322_3104, + 0x06c2_194a_f72f_ac58, + ]), + F::from_raw([ + 0x1755_f38a_c340_50ad, + 0xdc14_dc0e_4e74_e03d, + 0x72c3_6fd2_2d98_fe72, + 0x0a54_94c9_bcfa_06aa, + ]), + F::from_raw([ + 0xca79_156b_d56f_e339, + 0x8c15_5e36_75fa_df92, + 0x378e_0198_f0b5_f775, + 0x265c_a211_180b_012c, + ]), + F::from_raw([ + 0x5c85_9193_2ce7_dab7, + 0x7782_f4e8_431f_87af, + 0x7f17_d637_cd6f_54a2, + 0x21f6_59fe_daf6_c261, + ]), + F::from_raw([ + 0xcff6_8f9a_5e68_28f4, + 0x1d5d_3550_e3d5_801f, + 0x7aa1_049f_4f09_1a2f, + 0x1e46_3ae3_f4c3_bd04, + ]), + F::from_raw([ + 0xece8_448a_4373_eadf, + 0x4124_f481_45c6_1ff4, + 0x27a1_1d29_0e4b_439a, + 0x2741_2191_fa2b_2e53, + ]), + F::from_raw([ + 0x4e63_3bf7_d943_615f, + 0xbb05_6a2f_0ec0_f98e, + 0x2603_95ee_4f34_8f88, + 0x0b3a_769c_8b37_1562, + ]), + F::from_raw([ + 0x0c07_2716_7c06_d0b8, + 0x9628_79c2_0c8c_3a17, + 0x8fe5_ae26_d014_77e3, + 0x1adb_4c87_433d_866e, + ]), + F::from_raw([ + 0x0e18_4ae5_88cb_e215, + 0xf634_ba05_a9ca_7a85, + 0x7241_c2c7_6017_6662, + 0x1fc2_6ed0_27db_7b9e, + ]), + F::from_raw([ + 0x6c75_f27e_2609_87c7, + 0x96ed_db78_29a5_0e94, + 0x6af3_0682_f36f_bab3, + 0x1017_5fb6_f81b_1643, + ]), + F::from_raw([ + 0x5bcd_b6a6_782b_57fb, + 0xcd5c_ae23_f7e7_bb91, + 0xdbcf_314a_3c0b_1fde, + 0x23d3_0037_3bb8_ebf7, + ]), + F::from_raw([ + 0x4bcf_ff38_e89d_edee, + 0x64dc_3efa_9247_aa0d, + 0x7415_2526_1306_c176, + 0x0f04_17fa_6237_167e, + ]), + F::from_raw([ + 0x1489_0b0f_92a4_7d90, + 0x212b_f887_bc59_6158, + 0x4e2c_4353_d8f8_2b4b, + 0x1e8f_d20a_8030_fdd9, + ]), + F::from_raw([ + 0x947a_3d01_9bb4_1b6f, + 0xabae_013c_5450_d9e4, + 0xeca4_d3c7_1d11_0b04, + 0x1857_2826_385d_fc6e, + ]), + F::from_raw([ + 0x5f73_def1_4de7_a220, + 0xce21_7d92_5f40_d287, + 0x4a1b_d13a_02a9_4681, + 0x208b_7c8c_1ff8_422d, + ]), + ], +]; + +// Inverse MDS matrix: +pub(crate) const MDS_INV: [[F; 16]; 16] = [ + [ + F::from_raw([ + 0x7630_4951_9127_a276, + 0xf6b5_ddb4_8b02_a98e, + 0x8c30_bab5_df12_9693, + 0x276a_3c4a_91e0_bcf5, + ]), + F::from_raw([ + 0xc2a4_5f2e_f2d0_d0d2, + 0xc2ad_a645_1315_c91e, + 0x75af_97d8_fc77_7d69, + 0x116f_225b_ad8b_5c8e, + ]), + F::from_raw([ + 0xe6e2_f33c_da64_5297, + 0x5688_aa32_6fdf_19cd, + 0xb05d_3b1d_0d80_7f7c, + 0x2b22_bbb7_74ab_c45a, + ]), + F::from_raw([ + 0x2b06_163a_72da_6639, + 0xeec9_4f79_3473_2e6d, + 0x0cc0_51be_6e19_cf22, + 0x013a_0233_4a2a_d83d, + ]), + F::from_raw([ + 0xd1bc_8683_699a_8a42, + 0xe485_3171_834c_9135, + 0x8ac6_00a0_1b68_fe25, + 0x0d09_1f12_d614_2467, + ]), + F::from_raw([ + 0x4bf4_9e20_7819_9fe0, + 0x1352_d313_c48b_222c, + 0x090d_e9dc_ff95_8519, + 0x1293_e1e7_a8a8_ecc9, + ]), + F::from_raw([ + 0x9fd2_d135_d9b5_dcf2, + 0xfaee_98c4_f68d_b5b6, + 0xe031_23a4_d7d9_837c, + 0x2569_d743_5d27_bf46, + ]), + F::from_raw([ + 0x1a7a_5754_0d6c_b38c, + 0xf485_29a1_d507_bf70, + 0x1fef_333a_4730_1ea2, + 0x08b0_5767_8e2e_a00d, + ]), + F::from_raw([ + 0xc1f8_94a5_973e_8d75, + 0xff5d_6810_49b2_e486, + 0xc9f3_4c8b_9f2e_6db6, + 0x2159_3452_af81_1dd9, + ]), + F::from_raw([ + 0x300b_7c88_07f4_f6ad, + 0x4992_082d_bad2_1f6d, + 0x5bd6_a7f6_ae4d_0220, + 0x0b02_6a68_c5e0_b7d5, + ]), + F::from_raw([ + 0x7ae2_61ba_c8e2_e86b, + 0x6c4d_97ce_1abf_6200, + 0x82cb_1015_2de9_4936, + 0x2f1e_d0b8_f38e_6beb, + ]), + F::from_raw([ + 0x30eb_e63f_df60_4713, + 0x71c8_12cf_87d8_2d51, + 0xa7ee_05d1_0918_0f3a, + 0x0587_c177_ef78_e206, + ]), + F::from_raw([ + 0x6733_ee05_0252_69f9, + 0xef75_9039_132f_90e1, + 0xdff7_487e_c193_65b2, + 0x275a_685c_fd4c_c42c, + ]), + F::from_raw([ + 0x7bba_3895_0184_8a8f, + 0xa3a8_8ffd_23d0_9d6d, + 0x490a_e5e6_96b1_958d, + 0x1a8b_eac6_84e6_6281, + ]), + F::from_raw([ + 0x59ba_2904_1f97_166f, + 0x51ea_4327_4ca9_ce1d, + 0xe3e8_6755_169b_b1c9, + 0x2b26_c659_9d29_14f3, + ]), + F::from_raw([ + 0x0c26_e32a_f0e9_bbae, + 0xdc6e_9b87_1b74_c73c, + 0xf38b_b5f4_5aa1_f7a3, + 0x2e94_8f97_e269_aa01, + ]), + ], + [ + F::from_raw([ + 0xb54e_d796_c3d7_28d4, + 0xe3f6_4c45_5932_55f9, + 0xdab5_cd21_0826_e0d5, + 0x15ff_7111_d9f2_6302, + ]), + F::from_raw([ + 0x5d87_c067_7c06_1a74, + 0xa543_f22e_86da_b8b0, + 0x0a37_a105_9d1e_49c8, + 0x0bc3_e0b9_3482_f27f, + ]), + F::from_raw([ + 0x77eb_23ee_7b0a_9604, + 0x731b_5b62_52b2_8b76, + 0x6319_25c9_cf21_42fe, + 0x1916_dba9_5d56_e94a, + ]), + F::from_raw([ + 0x9655_0517_d081_6fcb, + 0x1781_1ed2_5f17_63c6, + 0xc8db_e0fa_0601_3a39, + 0x2bee_c191_157c_2e48, + ]), + F::from_raw([ + 0xb70a_f8ca_d271_9e5a, + 0x8e38_4135_f561_7df3, + 0xc75e_6cdd_33e9_0823, + 0x24e8_73de_bcd2_a22c, + ]), + F::from_raw([ + 0x2d2b_2d58_fafd_bb68, + 0x800a_3b05_6061_ac6b, + 0x562d_f276_924b_2c72, + 0x21db_1d45_56d8_949b, + ]), + F::from_raw([ + 0xacac_d077_f7ce_068f, + 0x3030_e7c1_c4bc_41d3, + 0xc1a2_ccab_2964_1049, + 0x1db3_11b1_d509_c08f, + ]), + F::from_raw([ + 0x613f_72f1_58aa_bf9d, + 0xcb53_466d_a5eb_3e34, + 0x6e78_2fbe_bf5d_913a, + 0x144e_3a65_3867_7892, + ]), + F::from_raw([ + 0x09ba_dd35_7f1e_7a83, + 0x0572_7ba2_a043_ec79, + 0x506c_295e_1823_34d5, + 0x298b_4d96_6bd8_9d0a, + ]), + F::from_raw([ + 0x5e58_b9b2_fb70_e025, + 0x86ff_2999_a157_9d20, + 0x9d06_663d_aafd_fd95, + 0x0b10_db67_b618_db16, + ]), + F::from_raw([ + 0x2d6c_a7ba_8bac_046c, + 0x8b5d_297f_c704_8ba0, + 0x95ba_d594_2281_0950, + 0x1158_86f7_bc31_2592, + ]), + F::from_raw([ + 0xd37d_d4c8_bafb_795c, + 0x0e44_abb6_9d77_620f, + 0x1f7d_ac01_b917_3cff, + 0x0425_62a7_cbde_c989, + ]), + F::from_raw([ + 0x2b36_5298_17f1_0af6, + 0x77eb_1803_e08c_61f5, + 0x048b_fb61_2a32_9bef, + 0x2f97_9b64_8227_2494, + ]), + F::from_raw([ + 0x6c67_56b9_e66f_4ae0, + 0x4d0f_7b47_2c7e_9214, + 0x2a7a_2ee0_2986_dba1, + 0x0c2f_edb7_ee83_ea1d, + ]), + F::from_raw([ + 0x7fc5_1931_9938_7d35, + 0x0836_4cb3_0986_0724, + 0x43a3_0b1c_bcc7_9c45, + 0x142e_eeaa_8a6f_f2d9, + ]), + F::from_raw([ + 0x5927_c801_61e0_ad7c, + 0xb177_8777_fc84_6a36, + 0x38b0_2d1a_2a04_e95b, + 0x2878_98eb_cd62_192a, + ]), + ], + [ + F::from_raw([ + 0x89e3_732c_e00f_d543, + 0x8bc2_582d_d625_2726, + 0xeb56_fd21_065b_c583, + 0x23a3_dec8_6a0e_58e6, + ]), + F::from_raw([ + 0x2c98_0a23_3145_659a, + 0x2686_21a8_e99a_f16f, + 0x3b80_5ba1_7063_9758, + 0x1309_e832_7944_4022, + ]), + F::from_raw([ + 0xe211_33dd_e2cd_15d7, + 0x7b28_82a8_a7b0_db6b, + 0x3da8_7019_1798_bb72, + 0x24f4_f1e6_b8f6_f10f, + ]), + F::from_raw([ + 0x2125_383c_213b_6527, + 0xdda0_6219_8687_f8e9, + 0xde0d_d003_d3eb_dc1f, + 0x1733_0097_9976_3853, + ]), + F::from_raw([ + 0xb545_af07_ae31_445b, + 0x7719_63e8_9f12_36a6, + 0x5c61_85a5_9f2c_74fa, + 0x09d3_d071_3f4c_beb9, + ]), + F::from_raw([ + 0xe0ec_0adb_98aa_fcaa, + 0xffd3_772a_f60c_6b91, + 0x715a_0fb7_315f_7ae2, + 0x2d57_08f6_79f5_2dc7, + ]), + F::from_raw([ + 0xab53_e311_5caa_99e2, + 0xd8b6_7a32_5132_d346, + 0x0b74_2051_d5cb_40d6, + 0x2e71_943e_fead_3bf6, + ]), + F::from_raw([ + 0x4a8c_d5a9_6fdd_6f78, + 0xd9c2_53c5_d73b_d1ce, + 0x133e_0edc_db1f_3b85, + 0x2247_3cb7_25c2_0d44, + ]), + F::from_raw([ + 0x1754_9dc0_e60a_3292, + 0xaa1d_d181_c33a_bebd, + 0x7c70_48ee_ca2f_53b9, + 0x175e_ada2_f0b2_cbb0, + ]), + F::from_raw([ + 0x574b_1b6b_b12d_7c45, + 0x8c2c_b746_a66d_610f, + 0x89f9_d85f_3290_b76a, + 0x0ecb_2928_9e8a_dac3, + ]), + F::from_raw([ + 0xbb5a_d898_a987_7eca, + 0x3e56_cdf3_7d9c_f669, + 0x2353_9681_948c_b81b, + 0x1c03_7832_b61e_6827, + ]), + F::from_raw([ + 0xea10_8c39_c055_0b8f, + 0x3537_9bc2_d041_6b08, + 0x82b4_d9cb_243b_dc87, + 0x094d_5dfa_b019_2cad, + ]), + F::from_raw([ + 0xe214_1f94_3fbd_2641, + 0x94f9_affe_1198_fbc2, + 0xf3f9_7426_b629_31a2, + 0x13e5_56cd_ac0f_14dd, + ]), + F::from_raw([ + 0x7ab4_e903_46d7_e8d8, + 0x1868_03a4_f685_0f6c, + 0x58db_061c_f5ee_2224, + 0x0e23_4f38_6bc7_20a7, + ]), + F::from_raw([ + 0xdf16_aada_084c_cbe4, + 0x8ed6_4f34_85c0_6528, + 0xedc6_f4b3_389e_1d67, + 0x1706_b720_6684_5bfb, + ]), + F::from_raw([ + 0x0107_5638_c3e8_6190, + 0x7160_2887_1d5d_d296, + 0x9944_416e_4956_8380, + 0x2ac3_129b_9672_fafc, + ]), + ], + [ + F::from_raw([ + 0x9c4d_5bf7_2829_06d7, + 0xdd1f_0450_d817_f1d9, + 0x120e_1220_9bf0_08ef, + 0x020f_3653_a5e8_e41a, + ]), + F::from_raw([ + 0x96d0_e17d_302e_86cb, + 0x40c8_da37_453e_d8a4, + 0x0a5c_4da1_3c99_28b7, + 0x2032_8d4c_559a_c233, + ]), + F::from_raw([ + 0x1818_9952_9771_a2eb, + 0x5895_cfda_61ba_71fe, + 0x0061_8f14_9645_b19f, + 0x135b_a1be_d2b0_76bb, + ]), + F::from_raw([ + 0x78cd_e791_d6fb_7505, + 0x74e6_4aa0_c204_8b6f, + 0xa2bb_4e00_bc47_21e8, + 0x0383_c83a_0810_5a9c, + ]), + F::from_raw([ + 0x2e4c_3b9d_a745_07ca, + 0xc8fc_45d2_4726_e5f4, + 0x4655_f85d_92b8_4327, + 0x15e1_ab06_8a79_7ab8, + ]), + F::from_raw([ + 0x8f0d_6418_7cc7_5aad, + 0xa2fa_c097_9df4_2aa8, + 0xf17b_38f4_a75f_089f, + 0x0532_5548_cecc_632e, + ]), + F::from_raw([ + 0x9fc5_7487_2cf5_3195, + 0x26e5_a543_e112_559c, + 0x2651_5edd_decd_38c8, + 0x11c1_c9d5_7a28_fb4f, + ]), + F::from_raw([ + 0x2b18_55ff_f5c1_1843, + 0xc15a_5ff5_edf5_f11a, + 0x8162_34f0_c0f8_6fa9, + 0x3044_b9a5_603c_7bf9, + ]), + F::from_raw([ + 0xdd5d_151e_7b63_e415, + 0x7303_0e4b_16e2_f242, + 0xbdf6_7f7d_12ef_5795, + 0x0ad0_c553_c7cc_4fdd, + ]), + F::from_raw([ + 0x886d_f2c7_815f_9298, + 0xc88c_30c9_2418_ac0f, + 0x5354_d74f_66af_fa4a, + 0x1584_57ec_7d18_3740, + ]), + F::from_raw([ + 0x53e0_21db_0540_af31, + 0xaa9a_0d55_3d4b_2980, + 0x2f8e_efce_87c1_e375, + 0x0d9b_1964_d82a_e8d9, + ]), + F::from_raw([ + 0x145c_f208_7ac2_bf22, + 0x65e3_1716_18ae_8422, + 0xd239_922e_0959_5cdc, + 0x2e98_ee09_b096_27aa, + ]), + F::from_raw([ + 0x0272_e855_68e5_77dd, + 0x3bca_6270_8114_62eb, + 0x631e_f804_0bce_1f8d, + 0x1458_26a2_42eb_aefd, + ]), + F::from_raw([ + 0xfdde_3ab8_76a6_9663, + 0xfe11_3b50_62fa_6dc2, + 0x8a49_3f28_db5d_1bb9, + 0x17a5_7812_a07a_986a, + ]), + F::from_raw([ + 0x9403_6e05_79de_a81f, + 0xce1d_85c8_7631_bad5, + 0xb702_ab97_a983_d1ea, + 0x1892_ce6c_96bc_e64b, + ]), + F::from_raw([ + 0xabdb_9921_dd09_da9e, + 0xaa9e_461f_d561_0a39, + 0xf170_bd62_cfd2_96f6, + 0x263f_b93d_37be_cf91, + ]), + ], + [ + F::from_raw([ + 0x8013_f1bf_9a70_1a30, + 0x479b_ccab_fef3_82c4, + 0xac74_e5db_628d_5b94, + 0x2263_d5dd_fec1_1180, + ]), + F::from_raw([ + 0x81e4_1148_f3e2_1354, + 0x2848_b358_ce31_5c83, + 0x7a34_8951_cad0_5778, + 0x0918_c8bf_1add_e3dd, + ]), + F::from_raw([ + 0x7b86_579c_a7c5_72ee, + 0xf374_f67e_af3d_e51c, + 0x35b5_9d8a_cb38_bfda, + 0x1781_241d_e2c6_6d5c, + ]), + F::from_raw([ + 0x14af_0900_3c34_aae3, + 0xe1a7_3d48_26d9_bdbd, + 0xf625_9454_8389_ae0c, + 0x1b46_1cc6_d9a2_828a, + ]), + F::from_raw([ + 0x015b_59ab_fb17_0a42, + 0x5928_e2b8_1bcd_b9b4, + 0x3272_25ab_0a32_1515, + 0x2970_1de0_34ee_d25e, + ]), + F::from_raw([ + 0xa9a5_683c_3440_3043, + 0x1495_1021_3eea_b536, + 0xecf5_e213_1315_b882, + 0x2fbc_766f_6931_5d17, + ]), + F::from_raw([ + 0x73d1_1fdf_5bda_743a, + 0xf471_1ba0_259c_f950, + 0xa7c4_8a39_651f_9130, + 0x0992_fbcf_0645_cff8, + ]), + F::from_raw([ + 0x17b1_7ecd_450a_f494, + 0xcc7a_dbda_0837_036e, + 0x93df_9670_2151_58d3, + 0x13ed_73c7_bb1d_f01e, + ]), + F::from_raw([ + 0xf4ba_259e_e050_c86a, + 0xc5cd_0ecf_d13e_659b, + 0x4419_bdcb_d579_e540, + 0x0193_d3a7_2c26_db30, + ]), + F::from_raw([ + 0x0e73_c27e_e8b6_1efd, + 0x7a1b_1b07_f953_2745, + 0xf3ad_573b_b75e_0367, + 0x10c6_d4d1_08b2_1364, + ]), + F::from_raw([ + 0x0af9_ed44_0f61_c2f9, + 0x7e61_6ce6_43f1_ec93, + 0xb64d_95a3_2422_37bb, + 0x20ff_722a_d79a_f145, + ]), + F::from_raw([ + 0xa7f9_ebd8_83a2_883a, + 0x8863_2309_465e_b50e, + 0xe1e5_de65_68ec_036e, + 0x08ff_4b02_79f5_5dcf, + ]), + F::from_raw([ + 0xa045_2bf3_e82b_b6d8, + 0x4fd4_c1ec_4182_a654, + 0x0bf1_0a75_bd2c_0fca, + 0x1fb1_72fc_9b10_989a, + ]), + F::from_raw([ + 0x6d76_9957_7d20_b60f, + 0x2192_b4c0_3e21_e3ca, + 0x6939_afe2_533d_396d, + 0x2d45_8a70_6969_ffcd, + ]), + F::from_raw([ + 0xf57d_4462_41d8_6e71, + 0x9c52_f04e_ab03_576c, + 0xb1f3_088e_49e8_6b5c, + 0x0cd0_444f_531f_86cf, + ]), + F::from_raw([ + 0xc69c_4786_7c80_ce11, + 0x05fb_0438_b95c_8ae1, + 0xf119_1351_9e02_665e, + 0x1d39_4d25_7d7e_fccb, + ]), + ], + [ + F::from_raw([ + 0x5172_ad55_59a2_743a, + 0xe5ff_3402_d888_ca89, + 0x24eb_85e6_e704_d9d7, + 0x11bf_30b3_c94d_4208, + ]), + F::from_raw([ + 0x271d_e44c_72a1_c281, + 0x97fb_abe1_77ac_dc31, + 0x4c63_cd18_657c_6933, + 0x14af_e906_d6e8_fbd4, + ]), + F::from_raw([ + 0x7b65_1b8a_b7e8_bd8a, + 0x1513_014f_2952_7a04, + 0x918a_cfde_f02e_5fe7, + 0x1cf7_28c0_4b55_ec09, + ]), + F::from_raw([ + 0x34d9_1b64_165a_e57a, + 0xeed8_bbe3_3fac_1779, + 0xb611_3cb1_d199_70ee, + 0x2321_b1cb_a29e_babc, + ]), + F::from_raw([ + 0xe9a3_8fcd_b5a9_c81b, + 0x33a6_99b2_ab5f_22bb, + 0x169f_4a4c_2b38_60c1, + 0x27e7_7701_fc11_7ccc, + ]), + F::from_raw([ + 0x331b_a9a9_58b7_b607, + 0x7ea7_4e48_c6a1_e795, + 0x1f24_ef04_4fc9_6234, + 0x257f_473c_f8df_9958, + ]), + F::from_raw([ + 0x785e_2c69_7551_d5c4, + 0x2ac2_2df4_b288_b2b8, + 0xd6cc_8c27_1ced_4945, + 0x1723_1d1a_5800_be98, + ]), + F::from_raw([ + 0xdd8b_b01c_6486_d9e0, + 0xbeea_beea_9bd3_1396, + 0x647d_72e6_46d6_063b, + 0x288d_776d_19bc_ccbc, + ]), + F::from_raw([ + 0xb1c6_e403_5af7_94bb, + 0x2e7f_e479_a44f_6d04, + 0x383a_914e_0e3e_cd93, + 0x230a_40d4_9a7a_da4e, + ]), + F::from_raw([ + 0x16be_89bf_2492_ae81, + 0x143e_4375_454d_2645, + 0x2e94_ec69_e053_3057, + 0x285d_cdc7_f5ac_3af8, + ]), + F::from_raw([ + 0x9ebb_0240_e22a_87b9, + 0x6d8e_00bc_2254_1083, + 0xb8c8_e4f6_ae56_d171, + 0x2cf6_48b3_a2c3_d314, + ]), + F::from_raw([ + 0x56a8_a137_860b_2f81, + 0xed79_5254_a3b5_79ca, + 0x0d6d_32f6_4381_579c, + 0x0b02_8e8c_471b_65c3, + ]), + F::from_raw([ + 0xdbbe_6c7d_dda7_4bfe, + 0x5857_fde1_f721_93ad, + 0xdfcd_aa76_ea75_e864, + 0x0fc2_e316_4108_3b85, + ]), + F::from_raw([ + 0x25ca_2ea5_a618_067c, + 0x29e6_6e49_dc23_2935, + 0x55ce_1de1_1b96_c2dc, + 0x18da_72a0_69af_d822, + ]), + F::from_raw([ + 0x2b90_dbf6_cd05_f1b4, + 0x1130_940d_9095_eb5e, + 0x4d46_70c4_87df_cf3b, + 0x272b_660e_0886_7505, + ]), + F::from_raw([ + 0xca6a_ca37_3475_f493, + 0xf45e_80d0_3fa6_6ad6, + 0x52b0_3b48_47cf_cc87, + 0x1d69_7653_8fb3_4e8d, + ]), + ], + [ + F::from_raw([ + 0x7f7a_7ac5_db1b_0d45, + 0x45c0_efe5_e9d5_16a7, + 0x41e3_0d8d_6399_2dcf, + 0x22f2_194c_4864_5462, + ]), + F::from_raw([ + 0x7065_9fee_b887_78c5, + 0xbb47_d087_1a72_1169, + 0x18e1_bb13_5c93_9e6b, + 0x06d5_9066_3340_fad7, + ]), + F::from_raw([ + 0xe8f9_03a0_6cac_7768, + 0xf906_a223_bafc_df16, + 0x46d7_f878_aa2b_4f7a, + 0x17a8_1fe8_7f28_374a, + ]), + F::from_raw([ + 0x30fc_68f8_851c_56da, + 0xd5fd_af01_c15c_1567, + 0xffbe_4085_9450_251e, + 0x1756_9b8f_f1b5_3a55, + ]), + F::from_raw([ + 0xf4d3_7db5_5c35_2107, + 0xf1ba_5b41_fabc_0c39, + 0x4b83_9dc7_a206_1912, + 0x0cd1_ee89_4113_5ab1, + ]), + F::from_raw([ + 0xf968_22ed_9859_5b32, + 0x61fd_aba9_7440_a488, + 0x5e44_068e_b69c_7638, + 0x19c6_ced0_44b6_9ad1, + ]), + F::from_raw([ + 0x28cb_6221_8fc1_e553, + 0x1c7c_fa56_fdc3_11a3, + 0x64f7_aab9_033b_0de7, + 0x029c_4c8d_8eee_b2b2, + ]), + F::from_raw([ + 0xe0ea_119d_8525_b0aa, + 0x376a_a739_29d6_6589, + 0x3c03_7de0_a4e3_7025, + 0x15a7_6a95_df01_b9d3, + ]), + F::from_raw([ + 0x7e8c_1c05_4b83_9c3b, + 0xa6b3_540b_4c3b_0367, + 0xce34_5234_892f_ec4c, + 0x1e5b_7928_8eb7_2889, + ]), + F::from_raw([ + 0x0628_4eba_bc33_3527, + 0xf426_100f_d9c0_35b4, + 0x2380_710d_c3b3_bfc1, + 0x0fc0_56cf_071a_5c6d, + ]), + F::from_raw([ + 0xb7ab_63de_c541_e6c0, + 0xc106_e7df_7f05_4bcb, + 0xcecf_c8f4_4047_3d2b, + 0x0c6f_610b_951d_18aa, + ]), + F::from_raw([ + 0xe3f2_69c2_05c0_2712, + 0x14e4_ac17_4884_df95, + 0x555b_0684_daa3_1406, + 0x058e_3355_b38b_ca75, + ]), + F::from_raw([ + 0x180e_6d76_3046_fbf0, + 0xf322_03ea_5d90_dfa4, + 0xa750_9c86_01a2_3f55, + 0x2011_bc98_2504_e79c, + ]), + F::from_raw([ + 0x886f_4b86_3331_845b, + 0xdf25_471e_597b_7cc0, + 0xa0e2_011d_c35e_4666, + 0x2613_c5a3_6525_cfa5, + ]), + F::from_raw([ + 0xf88a_f901_e365_2a2f, + 0x71bb_6210_1b62_f5ad, + 0x6590_3700_22be_ae5b, + 0x0383_f19e_d782_143f, + ]), + F::from_raw([ + 0xb436_6547_fd5a_512d, + 0x74ff_cbec_16e7_d110, + 0xaa55_e828_67e5_4b2b, + 0x1758_bb83_c966_d97c, + ]), + ], + [ + F::from_raw([ + 0x8ae8_1fe2_b913_0ac7, + 0xd384_4671_2075_b6e3, + 0x5740_0ec8_4e85_a814, + 0x14bf_10bb_e43d_5ebe, + ]), + F::from_raw([ + 0x59c4_456f_acd5_bb36, + 0x6de8_30d5_d8a9_50d8, + 0x5ab3_0143_6000_9c8a, + 0x2220_761b_03d9_9df1, + ]), + F::from_raw([ + 0x1c9f_b84e_7005_7134, + 0x736e_39e3_befb_3ffe, + 0x9c47_6120_4b62_215a, + 0x1a16_01bf_f6e8_56b9, + ]), + F::from_raw([ + 0xe909_110f_8285_f976, + 0x45ba_f9e1_366b_e0b7, + 0x57c7_4cff_9b80_5670, + 0x02ef_14ea_beae_6e33, + ]), + F::from_raw([ + 0xa970_1e94_4c1e_7279, + 0x944f_84cb_63a4_653d, + 0xc370_7a71_64af_e11c, + 0x28dc_e4ea_625d_ab66, + ]), + F::from_raw([ + 0xb72a_a593_38f0_40be, + 0x3096_b2d7_77f4_aec4, + 0x9082_e844_e902_2aa6, + 0x1cb4_1456_4c27_4815, + ]), + F::from_raw([ + 0x69d3_913a_b1b0_718d, + 0xcc46_a559_9be6_7d31, + 0xe008_1bda_ba3d_dfd8, + 0x0105_a57d_0112_eae8, + ]), + F::from_raw([ + 0x829e_c55c_4e8d_df83, + 0xa28b_45d3_69c1_7f2c, + 0x7076_79fc_de2c_797c, + 0x12a4_d040_691b_b315, + ]), + F::from_raw([ + 0x2c7b_d785_5515_7e32, + 0x5f1f_ae39_bf29_4da5, + 0x5683_1448_ffe3_0d3a, + 0x169a_e993_c16e_b093, + ]), + F::from_raw([ + 0x58ee_a222_60c1_db46, + 0xbeb4_0677_ba5c_66e9, + 0x3a2b_ae5d_bcbb_2a08, + 0x2ddb_0595_adf0_2c27, + ]), + F::from_raw([ + 0x69e8_7f60_26fb_21c6, + 0xa3bd_03c0_4576_07ac, + 0x746f_845b_acd7_acb3, + 0x0cd9_20c4_f592_b3ca, + ]), + F::from_raw([ + 0x701b_f946_2338_a74d, + 0x2931_c5f1_3cad_ba8c, + 0xcde5_fcee_a83f_615f, + 0x2fe8_c607_62d6_56a8, + ]), + F::from_raw([ + 0x3773_0c7c_d424_bf96, + 0x2500_48f5_8264_0f44, + 0x6f1f_1013_4ad5_29b5, + 0x217a_2eca_857e_7d45, + ]), + F::from_raw([ + 0x1900_c84f_2ee7_0c99, + 0x6ad1_e45e_bad9_bac9, + 0xab75_d857_23a7_4657, + 0x03d3_a2df_2bde_8e32, + ]), + F::from_raw([ + 0x876a_d327_3ac6_334a, + 0x5bcb_c4b2_1dd1_c585, + 0xa30f_86ba_bf80_9c0e, + 0x0e10_eb8a_0137_a3a3, + ]), + F::from_raw([ + 0x8ddc_dbc3_22bb_d0a4, + 0xb5c3_b74e_216a_3207, + 0x0f3d_2bd6_892c_29c4, + 0x138d_34e2_bfca_e849, + ]), + ], + [ + F::from_raw([ + 0x8f02_ab19_12aa_6990, + 0x22ea_7e7b_62ac_878f, + 0x31ab_5e0c_912f_45a7, + 0x0b56_fa14_288b_5570, + ]), + F::from_raw([ + 0xd08b_1a9a_a76f_054d, + 0x43e4_33dd_bd6a_9ba9, + 0xb943_75f4_7286_8a29, + 0x1146_5398_755d_174a, + ]), + F::from_raw([ + 0x9e1e_ce02_f4e0_c7d3, + 0xc3f3_964d_11bb_3955, + 0xd658_5806_20a9_c42f, + 0x2c35_76b9_c4ee_f71e, + ]), + F::from_raw([ + 0x81c3_8a24_b5f3_6e29, + 0x8403_1f2d_aa96_6b4a, + 0x7ad3_6886_8391_578c, + 0x1ec5_0576_2ec8_9b13, + ]), + F::from_raw([ + 0x3f23_2a5b_d93a_4642, + 0x1bd0_4ddb_e6a7_5f54, + 0xa204_ba61_bb32_946a, + 0x11b7_33d3_185b_0e09, + ]), + F::from_raw([ + 0x0091_4034_b70c_294f, + 0x7159_ed0d_93c3_1e1d, + 0x9e78_4530_c36e_cd43, + 0x04be_a8f5_0b16_2aa9, + ]), + F::from_raw([ + 0x5ebf_0daf_5cff_108b, + 0x8233_7a23_c8f7_573a, + 0x5f01_1141_97a1_2b3d, + 0x0fc4_a035_c779_598b, + ]), + F::from_raw([ + 0xfa9f_153d_2ef7_e90b, + 0xd2ac_09da_b551_0b28, + 0x1042_4d3b_e172_2274, + 0x216b_9833_8516_283d, + ]), + F::from_raw([ + 0xf42a_1d95_a8a6_a39c, + 0x7b6a_5f75_9bac_e586, + 0x7d82_8035_b81d_99f6, + 0x091b_ea4f_e41f_7dc9, + ]), + F::from_raw([ + 0x70f0_8954_42a3_50cb, + 0x784f_f491_a6bf_c978, + 0xc5b0_5495_af73_fea8, + 0x2494_6965_0cc4_aa92, + ]), + F::from_raw([ + 0x6000_ec5c_a41a_4e0c, + 0x8a75_1888_3f2a_028b, + 0x6d2f_7d26_bf42_4f3d, + 0x0a72_3f0b_9a77_0037, + ]), + F::from_raw([ + 0xe4c9_eb2f_c4b7_5cbc, + 0x42e9_b6c0_373a_c862, + 0x7a77_2025_5ce3_6b50, + 0x2cb6_d414_8e0b_1e99, + ]), + F::from_raw([ + 0xe863_90e9_30d7_632c, + 0x9e21_2ece_4de1_38a2, + 0xe25b_9acd_0fee_9819, + 0x0150_d845_cd2f_e645, + ]), + F::from_raw([ + 0x5f8b_a8ae_fcf1_8656, + 0xabee_d9e9_380c_99fc, + 0x60ac_ca9a_6f13_a2fd, + 0x229c_ade3_5b0e_6de3, + ]), + F::from_raw([ + 0x7817_393c_abdd_5019, + 0xe6b5_5a87_44ff_a3f9, + 0xe38a_adb9_74a9_8fb0, + 0x1cf7_edff_3aa5_23d8, + ]), + F::from_raw([ + 0xc15b_a0f1_5166_c975, + 0x2309_f19a_084c_6768, + 0xb37b_3590_78c7_9362, + 0x2586_cf08_ca36_2ea2, + ]), + ], + [ + F::from_raw([ + 0x4bb9_ac8a_8772_6b85, + 0xdedb_6810_b650_daee, + 0x9f31_c4d3_ae7e_4720, + 0x0ac4_26b2_09bd_3cb2, + ]), + F::from_raw([ + 0xf132_f9f0_be98_a954, + 0xfd4b_f51f_cb88_f997, + 0x6775_4c61_de13_126a, + 0x2fa2_539f_1317_82f3, + ]), + F::from_raw([ + 0xf7cb_8eb4_e330_f83b, + 0xd691_c981_b10a_73eb, + 0x522f_958c_d611_23d0, + 0x18b4_e23c_2d90_634d, + ]), + F::from_raw([ + 0x913e_07d6_e9c7_d110, + 0x2ee8_1a6b_b7f1_67f2, + 0x9b45_3097_966c_dad7, + 0x02ae_ff50_63de_dfb7, + ]), + F::from_raw([ + 0xf7f8_3490_c2e9_b3e7, + 0x6dc3_63d3_bd1d_b347, + 0xd0e8_1401_9982_9736, + 0x2c88_0528_e053_8a32, + ]), + F::from_raw([ + 0x1de0_7748_b4e4_2339, + 0x55b7_18f3_b3e4_c547, + 0xa277_040e_3801_146e, + 0x2d76_2dea_d354_6cd8, + ]), + F::from_raw([ + 0x3a27_9d34_6627_e7f4, + 0x3136_3ac5_20bb_56e0, + 0x8aa7_03a1_7158_fb8f, + 0x13fa_1376_dcfd_487c, + ]), + F::from_raw([ + 0x492c_5332_b57c_65f6, + 0x2e5a_fc54_097b_135f, + 0x6bd7_8a0e_c8a0_22be, + 0x1e86_d89e_5071_ae9a, + ]), + F::from_raw([ + 0xb7e3_06ea_5aef_12a6, + 0xbfea_9728_0a45_8b03, + 0x7d84_f2bc_020a_a075, + 0x2277_5a40_23a5_8e19, + ]), + F::from_raw([ + 0xdbff_92cb_bcd6_2d16, + 0x2b65_6c40_a253_8b80, + 0x9177_49ff_38f1_4b6a, + 0x18d4_7a40_b297_ef1c, + ]), + F::from_raw([ + 0xadb2_68a4_56f8_91c5, + 0xd5b0_9dd1_78a3_6ade, + 0xa42f_82e4_61c0_de2b, + 0x1a20_3202_5554_5100, + ]), + F::from_raw([ + 0x3f57_c852_716c_63d6, + 0xe7bb_cfce_a58f_0062, + 0x379f_055d_0513_a069, + 0x14a5_69c3_8a81_f524, + ]), + F::from_raw([ + 0x674f_9610_9d6f_4adb, + 0xf539_d080_71ef_f3ae, + 0x1f9f_280d_a98c_7c8b, + 0x2021_7a48_285c_efff, + ]), + F::from_raw([ + 0xf06c_4937_f3dc_5e95, + 0xfb5f_f460_4df3_2d33, + 0x2112_d674_0d8b_83bb, + 0x07a9_cef3_d55e_b07a, + ]), + F::from_raw([ + 0xda75_158a_9a59_6636, + 0x1fdd_ef83_10da_3802, + 0x0055_c4f4_d26b_3e91, + 0x108a_e2fb_2402_26e5, + ]), + F::from_raw([ + 0x927f_71eb_f36c_ddc6, + 0xe0c5_0295_512a_4d2b, + 0x760f_df00_4f4b_eb65, + 0x289d_50fa_3c8d_2440, + ]), + ], + [ + F::from_raw([ + 0xbe38_d050_f04c_25d7, + 0x2c8e_bdf2_f929_470f, + 0xfcfa_d3da_5036_ba7b, + 0x18c4_47f8_cd5b_8ebb, + ]), + F::from_raw([ + 0x5c72_a6ef_4369_0b0d, + 0x33ff_39fe_03e2_f3fe, + 0x94f0_5229_4357_c7cf, + 0x16eb_3f87_955e_4d78, + ]), + F::from_raw([ + 0xa4c4_6a66_57ca_1876, + 0xd20e_2cb5_8681_035e, + 0xf42a_5a48_6f2d_cd07, + 0x0ac0_6db9_31b7_0bfa, + ]), + F::from_raw([ + 0x6f7b_733d_38d8_78a4, + 0xd2d9_7922_d10b_9c04, + 0xe526_476d_b290_f312, + 0x23cb_13a4_428b_fea9, + ]), + F::from_raw([ + 0xd93d_decf_fb8f_787a, + 0x23dc_1234_a3fd_de7d, + 0x70e7_e7df_59b4_da6c, + 0x09ca_cda4_e110_d573, + ]), + F::from_raw([ + 0x2a25_cbff_def9_efd1, + 0x2d9a_11a6_335c_886e, + 0x255d_dd94_4348_411f, + 0x120c_3038_fe6a_c27b, + ]), + F::from_raw([ + 0x725c_afba_3b1b_c8e5, + 0xb121_12c9_711a_508e, + 0x4fb3_227b_8ff9_aafd, + 0x2f85_8d27_e11f_e631, + ]), + F::from_raw([ + 0xd295_408f_1f76_227c, + 0x19d9_1a8c_25f1_0df3, + 0xbb82_cd3e_4681_0091, + 0x01ca_90f2_e02d_f65c, + ]), + F::from_raw([ + 0x5844_42a2_9540_c508, + 0x8e7e_76bb_0714_dbed, + 0xef5e_b3ad_bb5b_1a44, + 0x084f_f4c6_0580_d297, + ]), + F::from_raw([ + 0x297e_0597_bf96_2d1c, + 0x0260_65ce_7120_b4a1, + 0xcceb_d5ef_2131_f81c, + 0x2b8d_a871_e76c_2ab0, + ]), + F::from_raw([ + 0x3d5b_aae9_6cf7_8fe2, + 0x6305_885d_4a27_2276, + 0x9d74_3273_72db_470f, + 0x2eef_8834_ef80_e591, + ]), + F::from_raw([ + 0xed00_2123_aab0_3c74, + 0x8a63_440c_c995_2fb0, + 0xde58_330b_bd7a_bc10, + 0x02c4_93df_1262_09ce, + ]), + F::from_raw([ + 0x9be8_3282_8e32_a6fb, + 0xa8b7_7db5_692a_9eaa, + 0xb4fc_d17e_59e8_165a, + 0x2b9a_5e21_9fa5_e879, + ]), + F::from_raw([ + 0xa41c_5fa5_84d8_7aa1, + 0xa9b7_ec94_b5fc_4d00, + 0x4299_e85d_b768_d3ef, + 0x0a31_67aa_0c3b_67d2, + ]), + F::from_raw([ + 0xb423_d044_90c0_e81c, + 0x417c_f35f_4a13_ec6b, + 0x4f85_75b0_8952_9aa2, + 0x0a39_3018_0bd3_1495, + ]), + F::from_raw([ + 0x6f69_1828_fbee_c3af, + 0xc8b8_5299_ecd9_01c9, + 0xf609_e610_6842_e742, + 0x0d17_7580_1888_8df4, + ]), + ], + [ + F::from_raw([ + 0x0e11_9813_680c_c1d8, + 0x0b5f_6476_f338_a301, + 0xb0f1_a7ab_d06d_2561, + 0x2bc1_f9b5_bc9a_9185, + ]), + F::from_raw([ + 0xdeb9_239f_48f9_2dd9, + 0x36d3_8814_d28a_0607, + 0x726f_5731_aec8_bdbf, + 0x1fcb_ccb2_2d95_c167, + ]), + F::from_raw([ + 0x1a40_bedf_0c62_28b4, + 0x97ba_884e_807b_22c5, + 0xd5a2_e0ec_4b60_f01f, + 0x305b_d2d5_48ed_5198, + ]), + F::from_raw([ + 0x396f_91fc_8ffb_8864, + 0xf5ac_91d7_8aef_a33f, + 0x7ca4_8898_de9c_5c8f, + 0x0363_3b69_c0a4_ec46, + ]), + F::from_raw([ + 0x95fb_90b4_3fbc_83cb, + 0x3ae6_9acc_6215_e4b5, + 0x6d22_97ba_9749_4b3b, + 0x0c0e_ed71_b721_92bc, + ]), + F::from_raw([ + 0xa009_b20b_ddd4_1a8a, + 0xe682_89c2_8db6_b394, + 0xf0b0_a245_7d7f_855b, + 0x13bd_0185_f2a6_720d, + ]), + F::from_raw([ + 0x9f22_12f9_9538_eae1, + 0x62b3_3e4b_0402_5702, + 0x4f03_edda_323f_2a8d, + 0x0ef7_9e84_b256_3692, + ]), + F::from_raw([ + 0x2232_beaf_06d5_8466, + 0xef04_eabe_6ea3_2c87, + 0x9144_1fdc_c12b_e12a, + 0x0ab5_1570_c4b0_666e, + ]), + F::from_raw([ + 0x39e5_b55b_599e_9ffc, + 0x9569_957b_0b8a_b761, + 0x2b83_570f_48af_4e81, + 0x06d7_cef9_2ef2_a316, + ]), + F::from_raw([ + 0x6441_a949_bf20_bc0b, + 0x4a71_1d1b_7396_1168, + 0x4078_9197_f873_7d22, + 0x1d6b_d58c_bde9_7b4b, + ]), + F::from_raw([ + 0x3d68_a391_3a38_a6c5, + 0x1135_840e_e62c_6b2a, + 0x5ea5_38ed_723e_5ead, + 0x027f_d178_6b7d_a45a, + ]), + F::from_raw([ + 0xfd6b_614a_b144_c3be, + 0x7be3_8d97_985c_5657, + 0xc74e_97f5_a1e7_6a3b, + 0x1e08_332f_6cf9_1995, + ]), + F::from_raw([ + 0x758a_f2de_0a93_8c16, + 0x6bf5_ae0b_aca8_c39a, + 0xbc57_92ce_b748_39b0, + 0x1227_1626_2dfb_4f7a, + ]), + F::from_raw([ + 0x458a_d34f_3884_30cd, + 0x5cfd_c625_bbc6_b953, + 0x90a9_4952_d200_4d92, + 0x1db8_e100_4451_8823, + ]), + F::from_raw([ + 0x9474_f632_7f19_c18f, + 0x2e24_8bf1_79b0_6178, + 0x9bf4_b4e3_a778_1bf7, + 0x1ef0_5a1a_0dff_126f, + ]), + F::from_raw([ + 0xb173_af35_f0b7_c9e5, + 0x5dea_5164_9929_dbd5, + 0x309d_0188_94fa_8678, + 0x0b02_e932_f957_a48e, + ]), + ], + [ + F::from_raw([ + 0x176e_2bb8_c17d_9cdc, + 0x3a18_a8af_969f_951f, + 0xf3f7_2f87_aaca_9e27, + 0x0688_98d3_dabf_9e79, + ]), + F::from_raw([ + 0x9904_7ee3_9d20_a368, + 0x87cf_fadf_c327_f904, + 0x441d_484d_d788_6c23, + 0x2c56_1f74_d713_dcb2, + ]), + F::from_raw([ + 0x9216_86be_3ee9_ce2e, + 0xa3c7_e205_a4f4_ec72, + 0xa63e_614c_64f9_c4bc, + 0x1775_2592_f74b_ae49, + ]), + F::from_raw([ + 0xcaac_d0e1_ba02_54da, + 0x87c6_4df9_67bf_1fec, + 0xe63d_198a_527f_8545, + 0x2315_e700_5667_a061, + ]), + F::from_raw([ + 0x74ba_18d5_0793_eaf9, + 0x18de_60c3_f56a_9577, + 0x188b_b242_8d4c_9cff, + 0x0b81_cce4_b55a_0554, + ]), + F::from_raw([ + 0x914d_89d5_fed5_2f82, + 0x617e_e94f_80cb_3046, + 0x55ec_634d_981b_abf2, + 0x16d3_0437_2b2a_5405, + ]), + F::from_raw([ + 0x4721_8a2e_2af6_cfd3, + 0x77bb_50a8_e256_8444, + 0xa46e_5fbe_8463_d69d, + 0x1787_31c4_ec46_dfd9, + ]), + F::from_raw([ + 0x218e_af62_40f7_8489, + 0x5e35_1ff9_d1d3_060c, + 0x80eb_7047_7353_55c5, + 0x2a8b_47f5_de93_7209, + ]), + F::from_raw([ + 0x5041_9d0b_3d7e_ea06, + 0xa853_850b_7e13_c73b, + 0x2a91_0c83_4596_f8ee, + 0x2f66_39a7_5f05_853b, + ]), + F::from_raw([ + 0x66f4_366e_5e2b_8a09, + 0x9fae_8795_6bce_b955, + 0x1391_c6aa_8e67_ae97, + 0x167e_1f79_b596_386d, + ]), + F::from_raw([ + 0xf26e_33bb_4153_3ec4, + 0xbdf2_af1c_52ca_6626, + 0x0886_9a43_a9c9_433a, + 0x1c08_9532_c879_f514, + ]), + F::from_raw([ + 0xacaa_938c_fe93_97f5, + 0xd4f6_cb8f_379c_f39e, + 0xd1b1_cb60_83b2_4445, + 0x068a_3ae2_e048_bdc5, + ]), + F::from_raw([ + 0x1db5_41a9_b0ea_ba5a, + 0x0024_2091_cd56_78d1, + 0x850a_86ec_9918_5287, + 0x1e79_4df6_f61e_d159, + ]), + F::from_raw([ + 0x6e14_b31a_e759_a82d, + 0x7645_cfc0_834e_7d50, + 0x4d72_b17c_5bbf_6c2b, + 0x185a_2297_4594_bc22, + ]), + F::from_raw([ + 0xb48b_4984_d2d3_a1d8, + 0x71c6_9858_79bf_7887, + 0xa8dd_cf4f_04dd_ffcf, + 0x25d3_538f_4a73_2f89, + ]), + F::from_raw([ + 0xc4af_9eef_9742_2c42, + 0xc78a_b577_bd5c_defb, + 0x59b2_0a2c_7105_cd0e, + 0x1ff6_ad72_2bb1_b4c0, + ]), + ], + [ + F::from_raw([ + 0xb2af_aadf_81d8_b099, + 0x97fd_d452_22a8_8475, + 0x4d23_78e5_e2a3_fe2e, + 0x02aa_79ad_a9da_901e, + ]), + F::from_raw([ + 0x5352_20df_12bc_6c1e, + 0xc8e6_1928_6cb9_b2f1, + 0xe40a_d6cf_462b_af46, + 0x1918_676a_41e6_d451, + ]), + F::from_raw([ + 0x9951_682e_529f_d610, + 0x85e3_2a3b_416e_ff3b, + 0x6c14_44ec_aacd_3e19, + 0x1f75_6a40_27c2_123f, + ]), + F::from_raw([ + 0xbb15_a427_c071_da68, + 0xa086_06ef_8389_30aa, + 0x559f_3112_40b6_5e4f, + 0x1ec8_58d7_e1c6_adb5, + ]), + F::from_raw([ + 0xcded_036f_b1ce_63c6, + 0x974f_c133_e2e7_af63, + 0xb9e6_5059_7168_8ff2, + 0x0c7c_497c_8872_e9db, + ]), + F::from_raw([ + 0x4b94_8194_d6ff_014e, + 0xb561_81a5_b3f1_73b0, + 0xe42b_cd5b_e720_c9ec, + 0x1b37_eb69_4b65_bcae, + ]), + F::from_raw([ + 0x20d8_9ce8_6336_e0ba, + 0x610e_7061_8b78_474e, + 0x406d_3cc3_3826_2420, + 0x267a_7c94_025f_cfc8, + ]), + F::from_raw([ + 0xbc61_cc7e_5aef_b24a, + 0x21da_30e5_fa7f_e7cb, + 0x0acc_a73f_738c_f65f, + 0x096a_ef4a_8888_3b15, + ]), + F::from_raw([ + 0x33dc_1014_f042_a724, + 0x68d9_ef1b_3259_7df6, + 0xac80_62b8_7302_de2f, + 0x17b4_05cd_db8e_b7a5, + ]), + F::from_raw([ + 0x6cd6_414a_b0f2_f824, + 0x8351_93ea_82f1_cabd, + 0x92af_7a7c_6ec9_74f7, + 0x1620_016a_87d3_e050, + ]), + F::from_raw([ + 0x3a7f_c33d_e574_e4d3, + 0x3137_84e8_9ba9_a25d, + 0x8c53_a0bd_f74a_f4c0, + 0x301d_c12d_e9d2_883a, + ]), + F::from_raw([ + 0xd556_fa04_0cfe_4e3e, + 0x8deb_9daa_15b8_2d65, + 0xeb40_9dfc_e39d_384c, + 0x1632_c755_bc6f_04b3, + ]), + F::from_raw([ + 0x1cbb_a8c4_8abe_7926, + 0xddee_314a_4167_f9e8, + 0x9206_9809_7659_51ba, + 0x0487_e5da_fa05_e188, + ]), + F::from_raw([ + 0x27d3_1f5d_a744_80a6, + 0xa12d_080a_c0b8_3897, + 0x797d_7dcb_15e8_2024, + 0x0095_dc43_131a_ca12, + ]), + F::from_raw([ + 0x8013_02b9_8aab_0473, + 0x3796_f33a_81b1_21d5, + 0xace9_963a_bb00_2868, + 0x0c43_f2e7_8cc4_d482, + ]), + F::from_raw([ + 0xb32a_255c_3b79_5315, + 0xca3c_85c5_69a6_83fc, + 0x6cc5_c677_1f83_c683, + 0x045f_7d4b_7168_10ee, + ]), + ], + [ + F::from_raw([ + 0xbf0a_b666_5936_5692, + 0x9ecd_f23d_f144_cafc, + 0x70ea_5b2f_e542_f63a, + 0x01a9_fe77_674a_bce7, + ]), + F::from_raw([ + 0xd9cc_3748_4910_4e5b, + 0x3cd9_63d5_587d_89fc, + 0xdd72_a3e6_9495_52a6, + 0x21a9_258c_4aaa_b318, + ]), + F::from_raw([ + 0x7964_0981_e030_2c42, + 0xf2b6_060f_2ff2_83b3, + 0xdc0c_8242_8b7a_9f73, + 0x24c7_2eda_ff51_2bf3, + ]), + F::from_raw([ + 0xd49f_b200_1af3_fab3, + 0x8c81_4d6a_de24_34f3, + 0x98aa_a3ef_bb08_4fca, + 0x220d_e60c_2fff_d823, + ]), + F::from_raw([ + 0xcdbe_19d1_8dd2_f8ac, + 0x3d36_add4_02b2_b467, + 0x0ef7_6500_2956_7de2, + 0x2e12_982c_1ffb_969f, + ]), + F::from_raw([ + 0xf076_dc48_4356_429e, + 0x9e56_5aee_4b03_1ab7, + 0x6505_deda_bb1e_5c48, + 0x0cb1_a115_0988_2259, + ]), + F::from_raw([ + 0xaf59_9443_de2b_6377, + 0xe793_48cd_4d90_2e21, + 0xe53f_3fde_5e4a_fef5, + 0x0c52_47e4_2b1e_d24a, + ]), + F::from_raw([ + 0x7919_15d9_bca0_49fa, + 0x7529_424e_b1cd_776a, + 0x4f9b_4cd8_35a1_e296, + 0x27c3_6101_aa23_a3cc, + ]), + F::from_raw([ + 0xbeb2_a33a_03a7_9d1d, + 0x7cbe_76c2_01b5_be3a, + 0x0aa9_99ef_2ff4_a6d9, + 0x1963_3a34_ad79_cba9, + ]), + F::from_raw([ + 0xe994_abc2_cbf9_fb26, + 0xf1ad_7e8f_90d3_ed8b, + 0x5479_ecf5_4d91_af29, + 0x1c10_7f0a_6e0a_c756, + ]), + F::from_raw([ + 0x16c5_e318_8d4f_17d5, + 0x8ec4_c995_8ac2_087c, + 0x2f48_ef2b_3232_4ba9, + 0x0351_1c0b_5f1d_fb53, + ]), + F::from_raw([ + 0x383f_070e_0f00_7eee, + 0xcb3b_26a0_e136_834a, + 0xb705_8bb2_ff35_cdb7, + 0x0906_ad70_264a_dcb9, + ]), + F::from_raw([ + 0x58da_d94a_16c0_3dbd, + 0x1a36_ce1a_526d_6711, + 0x14a8_079c_2b02_346b, + 0x2f78_cd6f_5a78_1aad, + ]), + F::from_raw([ + 0xdeab_c1f3_dff1_1388, + 0x8893_72ce_1f7c_ae09, + 0x6664_7d12_cf98_d7b7, + 0x2929_575d_b96a_3325, + ]), + F::from_raw([ + 0xfb04_8e18_0f59_fbe6, + 0xc825_5340_9bb9_fede, + 0x65fe_227d_9ada_b9c1, + 0x06ca_65bc_0814_1875, + ]), + F::from_raw([ + 0xfc47_0fe2_45f7_a1d3, + 0xeecc_e632_a46c_235e, + 0xd8d2_9810_1daf_69ec, + 0x177c_93f5_e264_5e30, + ]), + ], + [ + F::from_raw([ + 0xe8fe_8bcc_71a1_7647, + 0x63d9_28e8_8830_7e30, + 0x9d39_357e_06c2_aacc, + 0x04c7_9a18_df9d_ae9c, + ]), + F::from_raw([ + 0xbee5_b6de_14ff_8624, + 0x4826_5ce3_bdb8_184c, + 0x981f_1e89_4bbc_6ad5, + 0x1cd8_c881_3638_b883, + ]), + F::from_raw([ + 0xf9d6_8b34_cba3_62da, + 0x4979_f38a_2d8e_df56, + 0x4a19_47be_6ed6_b261, + 0x2289_f24f_7e8e_bb6e, + ]), + F::from_raw([ + 0x03e1_85b7_0641_a8ee, + 0xca8a_65cf_44ff_0913, + 0x6873_b03a_4ca3_6b0a, + 0x2d4a_6ccd_1976_19bb, + ]), + F::from_raw([ + 0x55b3_878b_3b07_5fa9, + 0x60ec_e476_6b85_d08d, + 0x204a_e840_74ca_b66d, + 0x2fec_52f6_b2b2_8005, + ]), + F::from_raw([ + 0xaa93_01fe_f221_3e86, + 0xf3b5_d7ec_939e_8b7a, + 0x88d1_f505_6d87_8840, + 0x0bb1_d510_ecfa_990e, + ]), + F::from_raw([ + 0x9533_029f_3677_c742, + 0x5a16_2cfd_5032_8d48, + 0x4754_e1ac_d8a8_1e18, + 0x2d41_4a2c_6dd1_85a5, + ]), + F::from_raw([ + 0xcc5b_cfce_7a93_f0e3, + 0xb931_2f8b_75e7_aa08, + 0x71b6_98e2_ba99_0f64, + 0x262d_1403_5117_9f49, + ]), + F::from_raw([ + 0xa7c2_597d_1aca_7baa, + 0x945b_9546_5ea7_b793, + 0x712f_0da9_0f70_603f, + 0x247e_31d9_e7e9_3428, + ]), + F::from_raw([ + 0xca86_6d55_e457_8da8, + 0xe2d8_a9e5_5580_0119, + 0x5510_7d9d_216f_47d5, + 0x122c_cc55_c833_e29f, + ]), + F::from_raw([ + 0x0379_87c6_12e1_a1f4, + 0x26e7_05bf_4b64_0184, + 0xc602_8ee0_1989_11f2, + 0x261f_1094_8e6a_90c2, + ]), + F::from_raw([ + 0x1261_3a10_0e3d_35ab, + 0xb3a6_3ff8_16cb_e80e, + 0xea74_d0e4_523c_569b, + 0x164f_b57e_8b00_d2ac, + ]), + F::from_raw([ + 0xb3fe_911c_da21_e935, + 0x35c6_ddd1_a51e_018a, + 0x7625_4b4f_ed32_92a1, + 0x12f5_cd69_8e79_c755, + ]), + F::from_raw([ + 0x7a48_c552_8f40_6d59, + 0x611c_8798_98f9_64e6, + 0xb516_177d_24cd_9897, + 0x2bea_27cc_0a95_8f81, + ]), + F::from_raw([ + 0xd6c1_a31e_8a39_97a4, + 0x5aba_4b1f_9ce9_4d24, + 0x6970_4f8f_10c4_382c, + 0x2722_ecbc_4c32_f01e, + ]), + F::from_raw([ + 0x0ae8_4f07_a448_3fcf, + 0xea5a_c87e_01ac_54da, + 0x0a35_8c8d_8d2f_cf5f, + 0x0216_7894_cedb_67b2, + ]), + ], +]; diff --git a/authdecode/src/backend/halo2/poseidon/rate1_params.rs b/authdecode/src/backend/halo2/poseidon/rate1_params.rs new file mode 100644 index 0000000000..0398eccd57 --- /dev/null +++ b/authdecode/src/backend/halo2/poseidon/rate1_params.rs @@ -0,0 +1,988 @@ +//! Parameters for using rate 1 Poseidon with the bn256 scalar field. +//! Patterned after [halo2_gadgets::poseidon::primitives::fp] +//! +//! The parameteres can be reproduced by running the following Sage script from +//! [this repository](https://github.com/daira/pasta-hadeshash): +//! +//! ```text +//! $ sage generate_parameters_grain.sage 1 0 254 2 8 56 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 --rust +//! ``` +//! +//! where 1 means "prime field", 0 means "non-negative sbox", 254 is the bitsize +//! of the field, 2 is the Poseidon width (rate + 1), 8 is the number of full +//! rounds, 56 is the number of partial rounds. + +use halo2_proofs::halo2curves::bn256::Fr as F; + +//Number of round constants: 128 +//Round constants for GF(p): +pub(crate) const ROUND_CONSTANTS: [[F; 2]; 64] = [ + [ + F::from_raw([ + 0x6c7d_c0db_d0ab_d7a7, + 0xa71a_a177_534c_dd1b, + 0xfe1f_aaba_294c_ba38, + 0x09c4_6e9e_c68e_9bd4, + ]), + F::from_raw([ + 0x3c1d_83ff_a604_cb81, + 0xc514_2b3a_e405_b834, + 0x2a97_ed93_7f31_35cf, + 0x0c03_5653_0896_eec4, + ]), + ], + [ + F::from_raw([ + 0x317e_a977_cc15_4a30, + 0xa00e_a5aa_bd62_68bd, + 0x142e_5118_2bb5_4cf4, + 0x1e28_a1d9_3569_8ad1, + ]), + F::from_raw([ + 0x4cf9_e2b1_2b91_251f, + 0x0e57_57c3_e008_db96, + 0x0809_65db_30e2_98e4, + 0x27af_2d83_1a9d_2748, + ]), + ], + [ + F::from_raw([ + 0x79aa_f435_45b7_4e03, + 0x4129_1462_f214_cd08, + 0x3a6a_3cfe_16ae_175a, + 0x1e6f_11ce_60fc_8f51, + ]), + F::from_raw([ + 0xf719_2062_68d1_42d3, + 0x0446_2ed1_4c36_13d8, + 0x8541_819c_b681_f0be, + 0x2a67_384d_3bbd_5e43, + ]), + ], + [ + F::from_raw([ + 0x3640_8f5d_5c9f_45d0, + 0xb985_e381_f025_1889, + 0x1609_f8e1_2fbf_ecf0, + 0x0b66_fdf3_5609_3a61, + ]), + F::from_raw([ + 0xdaa6_852d_bdb0_9e21, + 0x0b26_c83c_c5ce_beed, + 0x830c_6109_3c2a_de37, + 0x012e_e3ec_1e78_d470, + ]), + ], + [ + F::from_raw([ + 0x2d10_8e7b_445b_b1b9, + 0x6cd1_c431_b099_b6bb, + 0xfd88_f67f_8175_e3fd, + 0x0252_ba5f_6760_bfbd, + ]), + F::from_raw([ + 0xef5a_eaad_7ca9_32f1, + 0x5439_1a89_35ff_71d6, + 0x6c6b_ec3c_ef54_2963, + 0x1794_74cc_eca5_ff67, + ]), + ], + [ + F::from_raw([ + 0x7e1a_2589_bbed_2b91, + 0x9c1f_974a_2649_69b3, + 0x9228_ff4a_503f_d4ed, + 0x2c24_2613_79a5_1bfa, + ]), + F::from_raw([ + 0x53e6_6c05_5180_1b05, + 0xc2f6_3f50_01fc_0fc5, + 0xac2f_288b_d069_5b43, + 0x1cc1_d7b6_2692_e63e, + ]), + ], + [ + F::from_raw([ + 0x5d9e_ff5f_d9c9_1b56, + 0x0078_4dbf_17fb_acd0, + 0xb2ed_55f8_5297_9e96, + 0x2550_5930_1aad_a98b, + ]), + F::from_raw([ + 0xb11c_29ce_7e59_efd9, + 0xaea2_4234_970a_8193, + 0x79e1_f5c0_eccd_32b3, + 0x2843_7be3_ac1c_b2e4, + ]), + ], + [ + F::from_raw([ + 0x3387_62c3_7f5f_2043, + 0x1854_8da8_fb4f_78d4, + 0x1ca4_fa6b_5376_6eb1, + 0x2821_6a44_2f2e_1f71, + ]), + F::from_raw([ + 0x131f_2377_3234_82c9, + 0xeee1_efce_0309_4581, + 0x1f39_f4e7_056d_d03f, + 0x2c1f_47cd_17fa_5adf, + ]), + ], + [ + F::from_raw([ + 0x646b_8566_a621_afc9, + 0xd9da_fca2_7663_8a63, + 0x8632_bcc9_356c_eb7d, + 0x07ab_ad02_b7a5_ebc4, + ]), + F::from_raw([ + 0x37da_0c4d_15f9_6c3c, + 0x9429_f908_80a6_9cd1, + 0x275b_33ff_aab5_1dfe, + 0x0230_2646_01ff_df29, + ]), + ], + [ + F::from_raw([ + 0x717e_5d66_899a_a0a9, + 0xa864_4145_57ee_289e, + 0xa0f1_6865_6497_ca40, + 0x1bc9_7305_4e51_d905, + ]), + F::from_raw([ + 0x2a6b_2228_8f0a_67fc, + 0xd249_aff5_c2d8_421f, + 0x206c_3157_e863_41ed, + 0x2e1c_22f9_6443_5008, + ]), + ], + [ + F::from_raw([ + 0xa704_52bc_2bba_86b8, + 0x9e8e_a159_8e46_c9f7, + 0x121c_1d5f_461b_bc50, + 0x1224_f38d_f67c_5378, + ]), + F::from_raw([ + 0x69d2_9891_86cd_e20e, + 0xd7bf_e8cd_9dfe_da19, + 0x9280_b4bd_9ed0_068f, + 0x02e4_e69d_8ba5_9e51, + ]), + ], + [ + F::from_raw([ + 0x6d47_e973_5d98_018e, + 0x4f19_ee36_4e65_3f07, + 0x7f5d_f81f_c04f_f3ee, + 0x1f1e_ccc3_4aab_a013, + ]), + F::from_raw([ + 0xeacb_8a4d_4284_f582, + 0x1424_4480_32cd_1819, + 0x7426_6c30_39a9_a731, + 0x1672_ad3d_709a_3539, + ]), + ], + [ + F::from_raw([ + 0x1d2e_d602_df8c_8fc7, + 0xcda6_961f_284d_2499, + 0x56f4_4af5_192b_4ae9, + 0x283e_3fdc_2c6e_420c, + ]), + F::from_raw([ + 0x614f_bd69_ff39_4bcc, + 0x6837_51f8_fdff_59d6, + 0xd0db_0957_170f_a013, + 0x1c2a_3d12_0c55_0ecf, + ]), + ], + [ + F::from_raw([ + 0x96cb_6b81_7765_3fbd, + 0x143a_9a43_773e_a6f2, + 0xf789_7a73_2345_6efe, + 0x216f_8487_7aac_6172, + ]), + F::from_raw([ + 0x11a1_f515_52f9_4788, + 0xceaa_47ea_61ca_59a4, + 0x64ba_7e8e_3e28_d12b, + 0x2c0d_272b_ecf2_a757, + ]), + ], + [ + F::from_raw([ + 0xcb4a_6c3d_8954_6f43, + 0x170a_5480_abe0_508f, + 0x484e_e7a7_4c45_4e9f, + 0x16e3_4299_865c_0e28, + ]), + F::from_raw([ + 0x48cd_9397_5548_8fc5, + 0x7720_4776_5802_290f, + 0x375a_232a_6fb9_cc71, + 0x175c_eba5_99e9_6f5b, + ]), + ], + [ + F::from_raw([ + 0xd8c5_ffbb_44a1_ee32, + 0x6aa4_10bf_bc35_4f54, + 0xfead_9e17_58b0_2806, + 0x0c75_9444_0dc4_8c16, + ]), + F::from_raw([ + 0x9247_9882_d919_fd8d, + 0x760e_2001_3ccf_912c, + 0xc466_db7d_7eb6_fd8f, + 0x1a3c_29bc_39f2_1bb5, + ]), + ], + [ + F::from_raw([ + 0x95c8_eeab_cd22_e68f, + 0x0855_d349_074f_5a66, + 0xc098_6ea0_49b2_5340, + 0x0ccf_dd90_6f34_26e5, + ]), + F::from_raw([ + 0xe0e6_99b6_7dd9_e796, + 0x66a7_a8a3_fd06_5b3c, + 0x2bdb_475c_e6c9_4118, + 0x14f6_bc81_d9f1_86f6, + ]), + ], + [ + F::from_raw([ + 0x88ed_eb73_86b9_7052, + 0xcc09_9810_c9c4_95c8, + 0x9702_ca70_b2f6_c5aa, + 0x0962_b827_89fb_3d12, + ]), + F::from_raw([ + 0xafef_0c8f_6a31_a86d, + 0x1328_4ab0_1ef0_2575, + 0xbf20_c79d_e251_27bc, + 0x1a88_0af7_074d_18b3, + ]), + ], + [ + F::from_raw([ + 0x4c30_12bb_7ae9_311b, + 0x20af_2924_fc20_ff3f, + 0xcd5e_77f0_211c_154b, + 0x10cb_a184_19a6_a332, + ]), + F::from_raw([ + 0x756a_2849_f302_f10d, + 0xfa27_b731_9cae_3406, + 0xbdc7_6ba6_3a9e_aca8, + 0x057e_62a9_a8f8_9b3e, + ]), + ], + [ + F::from_raw([ + 0xafa0_413b_4428_0cee, + 0xb961_303b_bf65_cff5, + 0xd44a_df53_84b4_988c, + 0x287c_971d_e91d_c0ab, + ]), + F::from_raw([ + 0x6f7f_7960_e306_891d, + 0x1e56_2bc4_6d4a_ba4e, + 0xb3bc_a9da_0cca_908f, + 0x21df_3388_af16_87bb, + ]), + ], + [ + F::from_raw([ + 0x3eff_8b56_0e16_82b3, + 0x789d_f8f7_0b49_8fd8, + 0x3e25_cc97_4d09_34cd, + 0x1be5_c887_d25b_ce70, + ]), + F::from_raw([ + 0x48d5_9c27_06a0_d5c1, + 0xd2cb_5d42_fda5_acea, + 0x6811_7175_cea2_cd0d, + 0x268d_a36f_76e5_68fb, + ]), + ], + [ + F::from_raw([ + 0xbd06_460c_c26a_5ed6, + 0xc5d8_bb74_135e_bd05, + 0xc609_beaf_5510_ecec, + 0x0e17_ab09_1f6e_ae50, + ]), + F::from_raw([ + 0x040f_5caa_1f62_af40, + 0x91ef_62d8_cf83_d270, + 0x7aee_535a_b074_a430, + 0x04d7_27e7_28ff_a0a6, + ]), + ], + [ + F::from_raw([ + 0x2b15_417d_7e39_ca6e, + 0x3370_2ac1_0f1b_fd86, + 0x81b5_4976_2bc0_22ed, + 0x0ddb_d7bf_9c29_3415, + ]), + F::from_raw([ + 0x8a29_c49c_8789_654b, + 0x34f5_b0d1_d3af_9b58, + 0x7681_62e8_2989_c6c2, + 0x2790_eb33_5162_1752, + ]), + ], + [ + F::from_raw([ + 0x84b7_6420_6142_f9e9, + 0x395f_3d9a_b8b2_fd09, + 0x4471_9501_93d8_a570, + 0x1e45_7c60_1a63_b73e, + ]), + F::from_raw([ + 0xc4c6_86fc_46e0_91b0, + 0xfa90_ecd0_c43f_f91f, + 0x638d_6ab2_bbe7_135f, + 0x21ae_6430_1dca_9625, + ]), + ], + [ + F::from_raw([ + 0x5858_534e_ed8d_350b, + 0x854b_e9e3_432e_0955, + 0x4da2_9316_6f49_4928, + 0x0379_f63c_8ce3_468d, + ]), + F::from_raw([ + 0x8c9f_58a3_24c3_5049, + 0xca0e_4921_a466_86ac, + 0x6a74_4a08_0809_e054, + 0x002d_5642_0359_d026, + ]), + ], + [ + F::from_raw([ + 0x0fc2_c5af_9635_15a6, + 0xda8d_6245_9e21_f409, + 0x1d68_b3cd_32e1_0bbe, + 0x1231_58e5_965b_5d9b, + ]), + F::from_raw([ + 0x60c8_0eb4_9cad_9ec1, + 0x0fbb_2b6f_5283_6d4e, + 0x661d_14bb_f6cb_e042, + 0x0be2_9fc4_0847_a941, + ]), + ], + [ + F::from_raw([ + 0x2338_02f2_4fdf_4c1a, + 0x36db_9d85_9cad_5f9a, + 0x5771_6142_015a_453c, + 0x1ac9_6991_dec2_bb05, + ]), + F::from_raw([ + 0x51ca_3355_bcb0_627e, + 0x5e12_c9fa_97f1_8a92, + 0x5f49_64fc_61d2_3b3e, + 0x1596_443f_763d_bcc2, + ]), + ], + [ + F::from_raw([ + 0xd6d0_49ea_e3ba_3212, + 0xf185_7d9f_17e7_15ae, + 0x6b28_61d4_ec3a_eae0, + 0x12e0_bcd3_654b_dfa7, + ]), + F::from_raw([ + 0x04e6_c76c_7cf9_64ba, + 0xceab_ac7f_3715_4b19, + 0x9ea7_3d4a_f9af_2a50, + 0x0fc9_2b4f_1bbe_a82b, + ]), + ], + [ + F::from_raw([ + 0x9c7e_9652_3387_2762, + 0xb14f_7c77_2223_6f4f, + 0xd6f2_e592_a801_3f40, + 0x1f9c_0b16_1044_6442, + ]), + F::from_raw([ + 0x8d15_9f64_3dbb_f4d3, + 0x050d_914d_a38b_4c05, + 0xf8cd_e061_57a7_82f4, + 0x0ebd_7424_4ae7_2675, + ]), + ], + [ + F::from_raw([ + 0x7a83_9839_dccf_c6d1, + 0x3b06_71e9_7346_ee39, + 0x69a9_fafd_4ab9_51c0, + 0x2cb7_f0ed_39e1_6e9f, + ]), + F::from_raw([ + 0x90c7_2bca_7352_d9bf, + 0xce76_1d05_14ce_5266, + 0x5605_443e_e41b_ab20, + 0x1a9d_6e2e_cff0_22cc, + ]), + ], + [ + F::from_raw([ + 0x87da_182d_648e_c72f, + 0xd0c1_3326_a9a7_ba30, + 0x5ea8_3c3b_c44a_9331, + 0x2a11_5439_607f_335a, + ]), + F::from_raw([ + 0x9535_c115_c5a4_c060, + 0xe738_b563_05cd_44f2, + 0x15b8_fa7a_ee3e_3410, + 0x23f9_b652_9b5d_040d, + ]), + ], + [ + F::from_raw([ + 0x260e_b939_f0e6_e8a7, + 0xa3ce_97c1_6d58_b68b, + 0x249a_c6ba_484b_b9c3, + 0x0587_2c16_db0f_72a2, + ]), + F::from_raw([ + 0x2b62_4a7c_dedd_f6a7, + 0x0219_b615_1d55_b5c5, + 0xca20_fb80_1180_75f4, + 0x1300_bdee_08bb_7824, + ]), + ], + [ + F::from_raw([ + 0x072e_4e7b_7d52_b376, + 0x8d7a_d299_16d9_8cb1, + 0xe638_1786_3a8f_6c28, + 0x19b9_b63d_2f10_8e17, + ]), + F::from_raw([ + 0x24a2_0128_481b_4f7f, + 0x13d1_c887_26b5_ec42, + 0xb5bd_a237_6685_22f6, + 0x015b_ee13_57e3_c015, + ]), + ], + [ + F::from_raw([ + 0xea92_c785_b128_ffd1, + 0xfe1e_1ce4_bab2_18cb, + 0x1b97_07a4_f161_5e4e, + 0x2953_736e_94bb_6b9f, + ]), + F::from_raw([ + 0x4ce7_266e_d660_8dfc, + 0x851b_98d3_72b4_5f54, + 0x862f_8061_80c0_385f, + 0x0b06_9353_ba09_1618, + ]), + ], + [ + F::from_raw([ + 0x4f58_8ac9_7d81_f429, + 0x55ae_b7eb_9306_b64e, + 0x15e4_e0bc_fb93_817e, + 0x304f_74d4_61cc_c131, + ]), + F::from_raw([ + 0xb8ee_5415_cde9_13fc, + 0xaad2_a164_a461_7a4c, + 0xe8a3_3f5e_77df_e4f5, + 0x15bb_f146_ce9b_ca09, + ]), + ], + [ + F::from_raw([ + 0xa9ff_2385_9572_c8c6, + 0x9b8f_4b85_0405_c10c, + 0x4490_1031_4879_64ed, + 0x0ab4_dfe0_c274_2cde, + ]), + F::from_raw([ + 0x251d_e39f_9639_779a, + 0xef5e_edfe_a546_dea9, + 0x97f4_5f76_49a1_9675, + 0x0e32_db32_0a04_4e31, + ]), + ], + [ + F::from_raw([ + 0xa307_8efa_516d_a016, + 0x6797_733a_8277_4896, + 0xb276_35a7_8b68_88e6, + 0x0a17_56aa_1f37_8ca4, + ]), + F::from_raw([ + 0x4254_d6a2_a25d_93ef, + 0x95e6_1d32_8f85_efa9, + 0x47fd_1717_7f95_2ef8, + 0x044c_4a33_b10f_6934, + ]), + ], + [ + F::from_raw([ + 0xd37b_07b5_466c_4b8b, + 0xfe08_79d7_9a49_6891, + 0xbe65_5b53_7f66_f700, + 0x2ed3_611b_725b_8a70, + ]), + F::from_raw([ + 0xd833_9ea7_1208_58aa, + 0xadfd_eb9c_fdd3_47b5, + 0xc8ec_c3d7_22aa_2e0e, + 0x1f9b_a4e8_bab7_ce42, + ]), + ], + [ + F::from_raw([ + 0xb740_56f8_65c5_d3da, + 0xa38e_82ac_4502_066d, + 0x8f7e_e907_a84e_518a, + 0x1b23_3043_052e_8c28, + ]), + F::from_raw([ + 0xca2f_97b0_2087_5954, + 0x9020_53bf_c0f1_4db0, + 0x7403_1ab7_2bd5_5b4c, + 0x2431_e1cc_164b_b8d0, + ]), + ], + [ + F::from_raw([ + 0xa791_f273_9658_01fd, + 0xa13e_3220_9758_3319, + 0x30cd_6953_a0a7_db45, + 0x082f_934c_91f5_aac3, + ]), + F::from_raw([ + 0x9ad6_bb93_0c48_997c, + 0xc772_45e2_ae7c_be99, + 0xa34b_e074_3155_42a3, + 0x2b9a_0a22_3e75_38b0, + ]), + ], + [ + F::from_raw([ + 0xb0b5_89cc_7021_4e7d, + 0x8164_163e_75a8_a00e, + 0xceb8_5483_b887_a9be, + 0x0e1c_d91e_dd2c_fa2c, + ]), + F::from_raw([ + 0x88d3_2460_1ceb_e2f9, + 0x9977_4f19_854d_00f5, + 0xc951_f614_77e3_6989, + 0x2e1e_ac0f_2bfd_fd63, + ]), + ], + [ + F::from_raw([ + 0x23d7_4811_5b50_0b83, + 0x7345_784d_8efd_b33c, + 0x0c76_158e_769d_6d15, + 0x0cbf_a95f_37fb_7406, + ]), + F::from_raw([ + 0x980c_232d_fa4a_4f84, + 0x76d9_91e3_a775_13d9, + 0xd65a_d49d_8a61_e9a6, + 0x08f0_5b3b_e923_ed44, + ]), + ], + [ + F::from_raw([ + 0x25a2_dd51_0c04_7ef6, + 0xe728_4925_dc07_58a3, + 0x52bf_8e21_984d_0443, + 0x2271_9e2a_070b_cd08, + ]), + F::from_raw([ + 0xf41f_62b2_f268_30c0, + 0x7bdb_f036_1199_82c0, + 0xc060_f7fc_c3a1_ab4c, + 0x041f_596a_9ee1_cb2b, + ]), + ], + [ + F::from_raw([ + 0x19fc_dd09_86b1_0f89, + 0x021b_e1c2_d0dc_464a, + 0x8762_8eb0_6f6b_1d4c, + 0x233f_d35d_e1be_520a, + ]), + F::from_raw([ + 0xefcb_453c_61c9_c267, + 0xd31e_078a_a1b4_707e, + 0x4325_e0a4_23eb_c810, + 0x0524_b46d_1aa8_7a5e, + ]), + ], + [ + F::from_raw([ + 0xcc44_8623_7c51_5211, + 0x4227_bb95_4b0f_3199, + 0xce47_fcac_894b_8582, + 0x2c34_f424_c81e_5716, + ]), + F::from_raw([ + 0xf330_1032_7de4_915e, + 0x2dd2_025b_5457_cc97, + 0x207e_ffc2_b554_1fb7, + 0x0b5f_2a4b_6338_7819, + ]), + ], + [ + F::from_raw([ + 0xaefa_c41f_e05c_659f, + 0xc174_35d2_f57a_f6ce, + 0xc5b7_2fe4_39d2_cfd6, + 0x2220_7856_082c_cc54, + ]), + F::from_raw([ + 0x2785_4048_ce2c_8171, + 0xcdfb_2101_94ca_f79f, + 0x4e24_159b_7f89_50b5, + 0x24d5_7a8b_f5da_63fe, + ]), + ], + [ + F::from_raw([ + 0x7391_9bb2_3b79_396e, + 0x374a_d709_7bb0_1a85, + 0x3b37_1d75_bd69_3f98, + 0x0afa_b181_fdd5_e058, + ]), + F::from_raw([ + 0xf162_90d6_2b11_28ee, + 0x76c0_0571_94c1_6c0b, + 0x998a_52ef_ac7c_bd56, + 0x2dba_9b10_8f20_8772, + ]), + ], + [ + F::from_raw([ + 0x5aff_13e6_bce4_20b3, + 0xcbb8_3de0_bd59_2b25, + 0x56f8_81c7_88f5_3f83, + 0x2634_9b66_edb8_b16f, + ]), + F::from_raw([ + 0x2352_88a3_e6f1_37db, + 0xd81a_56d2_8ecc_193b, + 0x685e_95f9_2339_753a, + 0x25af_7ce0_e5e1_0357, + ]), + ], + [ + F::from_raw([ + 0x1f7c_0187_fe35_011f, + 0x70ee_d7aa_e88b_2bff, + 0xc094_d6a5_5edd_68b9, + 0x25b4_ce7b_d229_4390, + ]), + F::from_raw([ + 0x8cb9_d54c_1e02_b631, + 0xde9c_ef28_ebdf_30b1, + 0x387e_53f1_908a_88e5, + 0x22c5_43f1_0f6c_89ec, + ]), + ], + [ + F::from_raw([ + 0xdf66_8e74_882f_87a9, + 0x425e_906a_919d_7a34, + 0x4fc7_908a_9f19_1e1e, + 0x0236_f93e_7789_c472, + ]), + F::from_raw([ + 0x9cb4_97af_980c_4b52, + 0x652b_dae1_14eb_0165, + 0x0e7d_27e3_7d05_da99, + 0x2935_0b40_1166_ca01, + ]), + ], + [ + F::from_raw([ + 0xee12_6091_6652_363f, + 0x65ed_b75d_844e_bb89, + 0x6bd3_1bba_b547_f75a, + 0x0eed_787d_6582_0d3f, + ]), + F::from_raw([ + 0x1906_f656_f4de_6fad, + 0xfdcd_0e99_bd94_297d, + 0x036a_753f_520b_3291, + 0x07cc_1170_f13b_46f2, + ]), + ], + [ + F::from_raw([ + 0x2059_4356_89e8_acea, + 0x9087_86d7_f9f5_d10c, + 0xf49b_cf61_3a3d_30b1, + 0x22b9_3923_3b1d_7205, + ]), + F::from_raw([ + 0xadd6_50ac_e60a_e5a6, + 0x740f_083a_5aa8_5438, + 0x8aad_1dc8_bc33_e870, + 0x0145_1762_a0aa_b81c, + ]), + ], + [ + F::from_raw([ + 0xe704_fec0_892f_ce89, + 0xe32e_aa61_dec7_da57, + 0x61fa_bf10_25d4_6d1f, + 0x2350_6bb5_d872_7d44, + ]), + F::from_raw([ + 0x7f8b_d689_0735_5522, + 0x2a37_0953_1e1e_fea9, + 0xbac0_6ae3_f71b_dd09, + 0x2e48_4c44_e838_aea0, + ]), + ], + [ + F::from_raw([ + 0x4541_8da2_6835_b54c, + 0xaf4a_5945_45ce_dc25, + 0x379e_78c5_0bd2_e42b, + 0x0f4b_c7d0_7eba_fd64, + ]), + F::from_raw([ + 0xe620_996d_50d8_e74e, + 0x5158_2388_725d_f460, + 0xfa76_6378_62fa_aee8, + 0x1f4d_3c8f_6583_e9e5, + ]), + ], + [ + F::from_raw([ + 0x53eb_9bcb_48fe_7389, + 0xfae0_2abc_7b68_1d91, + 0x2660_d07b_e0e4_a988, + 0x0935_14e0_c707_11f8, + ]), + F::from_raw([ + 0x4a58_e0a3_47e1_53d8, + 0x43ee_83ec_e472_28f2, + 0x4669_9a2b_5f3b_c036, + 0x1ada_b0c8_e2b3_bad3, + ]), + ], + [ + F::from_raw([ + 0x1a22_dbef_9e80_dad2, + 0x378c_1b94_b807_2bac, + 0xd147_09eb_b474_641a, + 0x1672_b172_6057_d99d, + ]), + F::from_raw([ + 0x30d4_7b23_9b47_9c14, + 0xc5d8_e2fa_e0ac_c4ee, + 0x8f44_f53f_dcab_468c, + 0x1dfd_53d4_576a_f2e3, + ]), + ], + [ + F::from_raw([ + 0xbc7f_2077_5320_5c60, + 0xe6d7_7d64_0f6f_c3de, + 0xa70a_3626_3a37_e17f, + 0x0c68_88a1_0b75_b0f3, + ]), + F::from_raw([ + 0x8509_1ecc_a9d1_e508, + 0x611a_61e0_0ee6_848b, + 0x92b3_4a7e_77d1_2fe8, + 0x1add_b933_a65b_e770, + ]), + ], + [ + F::from_raw([ + 0x7935_628e_299d_1791, + 0xf638_ff54_25f0_afff, + 0x5c10_ae18_d1de_933c, + 0x00d7_540d_cd26_8a84, + ]), + F::from_raw([ + 0xd316_939d_20b8_2c0e, + 0x26fe_dde4_acd9_9db1, + 0x01b2_827a_5664_ca9c, + 0x140c_0e42_687e_9ead, + ]), + ], + [ + F::from_raw([ + 0xc091_e2ae_5656_5984, + 0xc20a_0f9b_24f8_c5ed, + 0x91ba_89b8_d13d_1806, + 0x2f0c_3a11_5d43_17d1, + ]), + F::from_raw([ + 0xd8c5_38a1_dc95_8c61, + 0x08a0_cff6_70b2_2b82, + 0x3006_ed22_0cf9_c810, + 0x0c4e_e778_ff7c_1455, + ]), + ], + [ + F::from_raw([ + 0x27c3_d748_5de7_4c69, + 0x9424_ed26_c0ac_c662, + 0x3693_f004_40cc_c360, + 0x1704_f276_6d46_f82c, + ]), + F::from_raw([ + 0x39b6_6fe9_009c_3cfa, + 0xf076_9c9f_8544_e402, + 0xa7a0_2c1b_51d2_44ab, + 0x2f2d_19cc_3ea5_d78e, + ]), + ], + [ + F::from_raw([ + 0xd6c7_66a8_06fc_6629, + 0xdd7e_e6cb_9cfe_d9c7, + 0x5053_f112_e2a8_e8dc, + 0x1ae0_3853_b75f_caba, + ]), + F::from_raw([ + 0x4e41_a86d_daf0_56d5, + 0x3556_921b_2d6f_014e, + 0x51d1_31d0_fa61_aa5f, + 0x0971_aabf_7952_41df, + ]), + ], + [ + F::from_raw([ + 0x5f5c_29f7_bfe2_f646, + 0xda62_4f83_80df_1c87, + 0x91d4_cf6b_6e0d_e73e, + 0x1408_c316_e601_4e1a, + ]), + F::from_raw([ + 0x4169_1f39_822e_f5bd, + 0x6c89_f1f7_73ef_2853, + 0x248a_be42_b543_093b, + 0x1667_f3fe_2edb_e850, + ]), + ], + [ + F::from_raw([ + 0x424c_6957_6500_fe37, + 0x5b81_7184_09e5_c133, + 0xa48b_0a03_557c_df91, + 0x13bf_7c5d_0d2c_4376, + ]), + F::from_raw([ + 0x19bc_0ba7_43a6_2c2c, + 0x024b_9534_7856_b797, + 0x3016_adf3_d353_3c24, + 0x0762_0a6d_fb0b_6cec, + ]), + ], + [ + F::from_raw([ + 0x1675_de3e_1982_b4d0, + 0x75d2_959e_2f32_2b73, + 0x36a8_ca08_bdbd_d8b0, + 0x1574_c7ef_0c43_545f, + ]), + F::from_raw([ + 0xc06e_03a7_ff83_78f0, + 0x5bd4_1845_71c2_54fd, + 0xfd56_7970_a717_ceec, + 0x269e_4b5b_7a2e_b21a, + ]), + ], +]; +//n: 254 +//t: 2 +//N: 508 +//Result Algorithm 1: +// [True, 0] +//Result Algorithm 2: +// [True, None] +//Result Algorithm 3: +// [True, None] +//Prime number: 0x0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 +//MDS matrix: +pub(crate) const MDS: [[F; 2]; 2] = [ + [ + F::from_raw([ + 0xbcec_a70b_d2af_7ad5, + 0xaf07_f38a_f8c9_52a7, + 0xec10_3453_51a2_3a3a, + 0x066f_6f85_d6f6_8a85, + ]), + F::from_raw([ + 0x0546_2b9f_8125_b1e8, + 0x20a7_c02b_bd8b_ea73, + 0x7782_e150_9b1d_0fdb, + 0x2b9d_4b41_10c9_ae99, + ]), + ], + [ + F::from_raw([ + 0xf573_f431_221f_8ff9, + 0xb6c0_9d55_7013_fff1, + 0x2bf6_7a44_93cc_262f, + 0x0cc5_7cdb_b085_07d6, + ]), + F::from_raw([ + 0x21bc_d147_9432_03c8, + 0xade8_57e8_6eb5_c3a1, + 0xa31a_6ed6_9724_e1ad, + 0x1274_e649_a32e_d355, + ]), + ], +]; +//Inverse MDS matrix: +pub(crate) const MDS_INV: [[F; 2]; 2] = [ + [ + F::from_raw([ + 0x8dbe_bd0f_a8c5_3e66, + 0x0554_569d_9b29_d1ea, + 0x7081_9ab1_c784_6f21, + 0x13ab_ec39_0ada_7f43, + ]), + F::from_raw([ + 0xaaf6_185b_1a1e_60fe, + 0xbd52_1ead_5dfe_0345, + 0x4c98_62a1_d97d_1510, + 0x1eb9_e1dc_19a3_3a62, + ]), + ], + [ + F::from_raw([ + 0x763f_7875_036b_cb02, + 0x8ce5_1690_30a2_ad69, + 0x601a_bc49_fdad_4f03, + 0x0fc1_c939_4db8_9bb2, + ]), + F::from_raw([ + 0x8abc_ed6b_d147_c8be, + 0x2b7e_ac34_3459_61bc, + 0x9502_054e_dc03_e7b2, + 0x16a9_e98c_493a_902b, + ]), + ], +]; diff --git a/authdecode/src/backend/halo2/poseidon/rate2_params.rs b/authdecode/src/backend/halo2/poseidon/rate2_params.rs new file mode 100644 index 0000000000..706419f376 --- /dev/null +++ b/authdecode/src/backend/halo2/poseidon/rate2_params.rs @@ -0,0 +1,1436 @@ +//! Parameters for using rate 2 Poseidon with the bn256 scalar field. +//! Patterned after [halo2_gadgets::poseidon::primitives::fp] +//! +//! The parameteres can be reproduced by running the following Sage script from +//! [this repository](https://github.com/daira/pasta-hadeshash): +//! +//! ```text +//! $ sage generate_parameters_grain.sage 1 0 254 3 8 56 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 --rust +//! ``` +//! +//! where 1 means "prime field", 0 means "non-negative sbox", 254 is the bitsize +//! of the field, 2 is the Poseidon width (rate + 1), 8 is the number of full +//! rounds, 56 is the number of partial rounds. + +use halo2_proofs::halo2curves::bn256::Fr as F; + +// Number of round constants: 192 +// Round constants for GF(p): +pub(crate) const ROUND_CONSTANTS: [[F; 3]; 64] = [ + [ + F::from_raw([ + 0x59a0_9a1a_9705_2816, + 0x7f8f_cde4_8bb4_c37a, + 0x8bdd_d3a9_3f78_04ef, + 0x1d06_6a25_5517_b7fd, + ]), + F::from_raw([ + 0xb723_8547_d32c_1610, + 0xb7c6_fef3_1367_b68e, + 0xac3f_089c_ebcc_6120, + 0x29da_efb5_5f6f_2dc6, + ]), + F::from_raw([ + 0x9e8b_7ad7_b0b4_e1d1, + 0x2572_d76f_08ec_5c4f, + 0x1ecb_d88a_d959_d701, + 0x1f2c_b162_4a78_ee00, + ]), + ], + [ + F::from_raw([ + 0xdb06_72de_d84f_31e5, + 0xb11f_092a_53bb_c6e1, + 0xbd77_c0ed_3d14_aa27, + 0x0aad_2e79_f157_35f2, + ]), + F::from_raw([ + 0x091c_cf15_95b4_3f28, + 0x3702_8a98_f1de_ce66, + 0xd6f6_61dd_4094_375f, + 0x2252_624f_8617_738c, + ]), + F::from_raw([ + 0xd49f_4f2c_9018_d735, + 0x91c2_0626_524b_2b87, + 0x5a65_a84a_291d_a1ff, + 0x1a24_913a_928b_3848, + ]), + ], + [ + F::from_raw([ + 0x4fd6_dae1_508f_c47a, + 0x0a41_515d_dff4_97b1, + 0x7bfc_427b_5f11_ebb1, + 0x22fc_468f_1759_b74d, + ]), + F::from_raw([ + 0xefd6_5515_617f_6e4d, + 0xe619_56ff_0b41_21d5, + 0x9cd0_26e9_c9ca_107a, + 0x1059_ca78_7f1f_89ed, + ]), + F::from_raw([ + 0xa45c_bbfa_e8b9_81ce, + 0x2123_011f_0bf6_f155, + 0xf61f_3536_d877_de98, + 0x02be_9473_3584_61d8, + ]), + ], + [ + F::from_raw([ + 0xa1ff_3a44_1a50_84a4, + 0xaba9_b669_ac5b_8736, + 0x2778_a749_c82e_d623, + 0x0ec9_6c8e_3296_2d46, + ]), + F::from_raw([ + 0x48fb_2e4d_814d_f57e, + 0x5a47_a7cd_b8c9_9f96, + 0x5442_d955_3c45_fa3f, + 0x292f_906e_0736_7740, + ]), + F::from_raw([ + 0x0c63_f0b2_ffe5_657e, + 0xcc61_1160_a394_ea46, + 0x26c1_1b9a_0f5e_39a5, + 0x2749_8244_4157_b867, + ]), + ], + [ + F::from_raw([ + 0x4995_73f2_3597_d4b5, + 0xcedd_192f_4730_8731, + 0xb63e_1855_bff0_15b8, + 0x1a1d_063e_54b1_e764, + ]), + F::from_raw([ + 0xb91b_002c_5b25_7c37, + 0x0823_5dcc_c1aa_3793, + 0x839d_1095_6259_0637, + 0x26ab_c66f_3fdf_8e68, + ]), + F::from_raw([ + 0x0b3c_2b12_ff4d_7be8, + 0x0754_427a_abca_92a7, + 0x81a5_78cf_ed5a_ed37, + 0x0c7c_64a9_d887_3853, + ]), + ], + [ + F::from_raw([ + 0xedd3_8383_1354_b495, + 0xba2e_bac3_0dc3_86b0, + 0x9e17_f0b6_d08b_2d1e, + 0x1cf5_9987_69e9_fab7, + ]), + F::from_raw([ + 0x7aba_0b97_e66b_0109, + 0x1982_8764_a966_9bc1, + 0x564c_a604_61e9_e08b, + 0x0f5e_3a85_66be_31b7, + ]), + F::from_raw([ + 0x42bf_3d7a_531c_976e, + 0xf359_a53a_180b_7d4b, + 0x95e6_0e4d_b079_4a01, + 0x18df_6a9d_19ea_90d8, + ]), + ], + [ + F::from_raw([ + 0x4e32_4055_fa31_23dc, + 0xd0ea_1d3a_3b9d_25ef, + 0x6e4b_782c_3c6e_601a, + 0x04f7_bf2c_5c05_38ac, + ]), + F::from_raw([ + 0xe55d_5462_8b89_ebe6, + 0xe770_c058_4aa2_328c, + 0x3c40_0585_2374_8531, + 0x29c7_6ce2_2255_206e, + ]), + F::from_raw([ + 0x00e0_e945_dbc5_ff15, + 0x65b1_b8e9_c610_8dbe, + 0xc053_659a_b434_7f5d, + 0x198d_425a_45b7_8e85, + ]), + ], + [ + F::from_raw([ + 0x49d3_a9a9_0c3f_df74, + 0xa7ff_7f68_78b3_c49d, + 0x6af3_cc79_c598_a1da, + 0x25ee_27ab_6296_cd5e, + ]), + F::from_raw([ + 0xc0f8_8687_a96d_1381, + 0x0584_5d7d_0c55_b1b2, + 0x2456_1001_c0b6_eb15, + 0x138e_a8e0_af41_a1e0, + ]), + F::from_raw([ + 0x4013_370a_01d9_5687, + 0x4285_1b5b_9811_f2ca, + 0xf6e7_c2cb_a2ee_fd0e, + 0x3061_97fb_3fab_671e, + ]), + ], + [ + F::from_raw([ + 0x8641_9eaf_00e8_f620, + 0x21db_7565_e5b4_2504, + 0x2b66_f0b4_894d_4f1a, + 0x1a0c_7d52_dc32_a443, + ]), + F::from_raw([ + 0xaa52_997d_a2c5_4a9f, + 0xebfb_e5f5_5163_cd6c, + 0x3ff8_6a8e_5c8b_dfcc, + 0x2b46_b418_de80_915f, + ]), + F::from_raw([ + 0xfb46_e312_b582_9f64, + 0x613a_1af5_db48_e05b, + 0x01f8_b777_b967_3af9, + 0x12d3_e0dc_0085_8737, + ]), + ], + [ + F::from_raw([ + 0xba33_8a5c_b19b_3a1f, + 0xfb2b_f768_230f_648d, + 0x70f5_002e_d21d_089f, + 0x2633_90cf_74dc_3a88, + ]), + F::from_raw([ + 0x7d54_3db5_2b00_3dcd, + 0xf8ab_b5af_40f9_6f1d, + 0x0ac8_84b4_ca60_7ad0, + 0x0a14_f33a_5fe6_68a6, + ]), + F::from_raw([ + 0xd847_df82_9bc6_83b9, + 0x27be_3a4f_0117_1a1d, + 0x1a5e_8650_9d68_b2da, + 0x28ea_d9c5_8651_3eab, + ]), + ], + [ + F::from_raw([ + 0xea16_cda6_e1a7_416c, + 0x888f_0ea1_abe7_1cff, + 0x0972_031f_1bdb_2ac9, + 0x1c6a_b1c3_28c3_c643, + ]), + F::from_raw([ + 0x3234_6015_c5b4_2c94, + 0x4f6d_ecd6_08cb_98a9, + 0x2b25_0023_9f7f_8de0, + 0x1fc7_e71b_c0b8_1979, + ]), + F::from_raw([ + 0xe6dd_85b9_3a0d_daa8, + 0xc0c1_e197_c952_650e, + 0xe380_e0d8_6029_8f17, + 0x03e1_07eb_3a42_b2ec, + ]), + ], + [ + F::from_raw([ + 0x4545_05f6_941d_78cd, + 0x4645_2ca5_7c08_697f, + 0x69c0_d52b_f88b_772c, + 0x2d35_4a25_1f38_1a46, + ]), + F::from_raw([ + 0xd14b_4606_826f_794b, + 0x5225_51d6_1606_eda3, + 0xf687_ef14_bc56_6d1c, + 0x094a_f88a_b05d_94ba, + ]), + F::from_raw([ + 0xd52b_2d24_9d13_96f7, + 0xe1ab_5b6f_2e31_95a9, + 0x19bc_aeab_f02f_8ca5, + 0x1970_5b78_3bf3_d2dc, + ]), + ], + [ + F::from_raw([ + 0x60ce_f685_2271_200e, + 0x8723_b16b_7d74_0a3e, + 0x1fcc_33fe_e54f_c5b2, + 0x09bf_4acc_3a8b_ce3f, + ]), + F::from_raw([ + 0x543a_073f_3f3b_5e4e, + 0x3413_732f_301f_7058, + 0x50f8_3c0c_8fab_6284, + 0x1803_f820_0db6_013c, + ]), + F::from_raw([ + 0xd41f_7fef_2faf_3e5c, + 0xbf6f_b02d_4454_c0ad, + 0x3059_5b16_0b8d_1f38, + 0x0f80_afb5_0462_44de, + ]), + ], + [ + F::from_raw([ + 0x7dc3_f982_1952_9d78, + 0xabcf_cf64_3f4a_6fea, + 0xd77f_0088_c1cf_c964, + 0x126e_e1f8_504f_15c3, + ]), + F::from_raw([ + 0xef86_f991_d7d0_a591, + 0x0ffb_4ee6_3175_ddf8, + 0x69bf_b3d9_1955_2ca1, + 0x23c2_03d1_0cfc_c60f, + ]), + F::from_raw([ + 0x7c5a_339f_7744_fb94, + 0x3dec_1ee4_eec2_cf74, + 0xec0d_0970_5fa3_a630, + 0x2a2a_e15d_8b14_3709, + ]), + ], + [ + F::from_raw([ + 0xb6b5_d890_8197_0b2b, + 0xc3d3_b300_6cb4_61bb, + 0x47e5_c381_ab63_43ec, + 0x07b6_0dee_586e_d6ef, + ]), + F::from_raw([ + 0x132c_fe58_3c93_11bd, + 0x8a98_a320_baa7_d152, + 0x885d_95c4_94c1_ae3d, + 0x2731_6b55_9be3_edfd, + ]), + F::from_raw([ + 0x2f5f_9af0_c034_2e76, + 0xef83_4cc2_a743_ed66, + 0xd893_7cb2_d3f8_4311, + 0x1d5c_49ba_157c_32b8, + ]), + ], + [ + F::from_raw([ + 0x7c24_bd59_4096_8488, + 0x09c0_1bf6_9799_38f6, + 0x3327_74e0_b850_b5ec, + 0x2f8b_124e_7816_3b2f, + ]), + F::from_raw([ + 0x665f_7526_0113_b3d5, + 0x1d4c_ba65_54e5_1d84, + 0xdc5b_7aa0_9a9c_e21b, + 0x1e68_43a5_4574_16b6, + ]), + F::from_raw([ + 0x1f5b_c79f_2164_1d4b, + 0xa68d_af9a_c6a1_89ab, + 0x5fca_25c9_929c_8ad9, + 0x11cd_f00a_35f6_50c5, + ]), + ], + [ + F::from_raw([ + 0xe82b_5b9b_7eb5_60bc, + 0x608b_2815_c773_55b7, + 0x2ef3_6e58_8158_d6d4, + 0x2163_2de3_d3bb_c5e4, + ]), + F::from_raw([ + 0x49d7_b5c5_1c18_498a, + 0x255a_e48e_f2a3_29e4, + 0x97b2_7025_fbd2_45e0, + 0x0de6_2575_8452_efbd, + ]), + F::from_raw([ + 0x9b09_546b_a083_8098, + 0xdd9e_1e1c_6f0f_b6b0, + 0xe2fe_bfd4_d976_cc01, + 0x2ad2_53c0_53e7_5213, + ]), + ], + [ + F::from_raw([ + 0xd357_02e3_8d60_b077, + 0x3dd4_9cdd_13c8_13b7, + 0x6ec7_681e_c39b_3be9, + 0x1d6b_169e_d638_72dc, + ]), + F::from_raw([ + 0xc3a5_4e70_6cfe_f7fe, + 0x0be3_ea70_a24d_5568, + 0xb912_7c49_41b6_7fed, + 0x1660_b740_a143_664b, + ]), + F::from_raw([ + 0x96a2_9f10_376c_cbfe, + 0xceac_dddb_12cf_8790, + 0x114f_4ca2_deef_76e0, + 0x0065_a92d_1de8_1f34, + ]), + ], + [ + F::from_raw([ + 0xcf30_d50a_5871_040d, + 0x353e_be2c_cbc4_869b, + 0x7367_f823_da7d_672c, + 0x1f11_f065_2025_3598, + ]), + F::from_raw([ + 0x1108_52d1_7df0_693e, + 0x3bd1_d1a3_9b67_59ba, + 0xb437_ce7b_14a2_c3dd, + 0x2659_6f5c_5dd5_a5d1, + ]), + F::from_raw([ + 0x6743_db15_af91_860f, + 0x8539_c416_3a5f_1e70, + 0x7bf3_056e_fcf8_b6d3, + 0x16f4_9bc7_27e4_5a2f, + ]), + ], + [ + F::from_raw([ + 0xe1a4_e743_8dd3_9e5f, + 0x568f_eaf7_ea8b_3dc5, + 0x9954_175e_fb33_1bf4, + 0x1abe_1deb_45b3_e311, + ]), + F::from_raw([ + 0x020d_34ae_a15f_ba59, + 0x9f5d_b92a_aec5_f102, + 0xd899_3a74_ca54_8b77, + 0x0e42_6cca_b669_84d1, + ]), + F::from_raw([ + 0xa841_9243_03f6_a6c6, + 0x0071_684b_902d_534f, + 0x4933_bd19_4205_3f1f, + 0x0e7c_30c2_e2e8_957f, + ]), + ], + [ + F::from_raw([ + 0x4c76_e1f3_1d3f_c69d, + 0x6166_ded6_e352_8ead, + 0x1622_708f_c7ed_ff1d, + 0x0812_a017_ca92_cf0a, + ]), + F::from_raw([ + 0x2e27_6b47_cf01_0d54, + 0x68af_e502_6edd_7a9c, + 0xbba9_49d1_db96_0400, + 0x21a5_ade3_df2b_c1b5, + ]), + F::from_raw([ + 0x72b1_a523_3f87_49ce, + 0xbd10_1945_f50e_5afe, + 0xad71_1bf1_a058_c6c6, + 0x01f3_0354_6381_6c84, + ]), + ], + [ + F::from_raw([ + 0x4dca_a82b_0f0c_1c8b, + 0x8bf2_f939_8dbd_0fdf, + 0x028c_2aaf_c2d0_6a5e, + 0x0b11_5572_f038_c0e2, + ]), + F::from_raw([ + 0x3460_613b_6ef5_9e2f, + 0x27fc_24db_42bc_910a, + 0xf0ef_2555_43f5_0d2e, + 0x1c38_ec0b_99b6_2fd4, + ]), + F::from_raw([ + 0xb1d0_b254_d880_c53e, + 0x2f5d_3146_06a2_97d4, + 0x425c_3ff1_f4ac_737b, + 0x1c89_c6d9_6662_72e8, + ]), + ], + [ + F::from_raw([ + 0x8b71_e231_1bb8_8f8f, + 0x21ad_4880_097a_5eb3, + 0xf6d4_4008_ae4c_042a, + 0x0332_6e64_3580_356b, + ]), + F::from_raw([ + 0x5bdd_e229_9910_a4c9, + 0x50f2_7a64_34b5_dceb, + 0x67ce_e9ea_0e51_e3ad, + 0x2680_76b0_054f_b73f, + ]), + F::from_raw([ + 0x78d0_4aa6_f874_7ad0, + 0x5da1_8ea9_d8e4_f101, + 0x626e_d934_91bd_a32e, + 0x1acd_63c6_7fbc_9ab1, + ]), + ], + [ + F::from_raw([ + 0xca8c_86cd_2a28_b5a5, + 0x1bf9_3375_e232_3ec3, + 0xc4e3_144b_e58e_f690, + 0x19f8_a5d6_70e8_ab66, + ]), + F::from_raw([ + 0xe1cf_bb5f_7b9b_6893, + 0x0681_93ea_51f6_c92a, + 0x6efa_40d2_df10_a011, + 0x1c0d_c443_519a_d7a8, + ]), + F::from_raw([ + 0x180e_4c32_2498_7d3d, + 0xfbea_b33c_b4f6_a2c4, + 0x50fe_7190_e421_dc19, + 0x14b3_9e7a_a406_8dbe, + ]), + ], + [ + F::from_raw([ + 0xafb1_e35e_28b0_795e, + 0xb820_fc51_9f01_f021, + 0x8f28_c63e_a6c5_61b7, + 0x1d44_9b71_bd82_6ec5, + ]), + F::from_raw([ + 0x7652_4dc0_a9e9_87fc, + 0x89de_1416_89d1_2522, + 0x60fa_97fe_60fe_9d8e, + 0x1ea2_c9a8_9baa_ddbb, + ]), + F::from_raw([ + 0x134d_5cef_db3c_7ff1, + 0x591f_9a46_a0e9_c058, + 0xb57e_9c1c_3d6a_2bd7, + 0x0478_d66d_4353_5a8c, + ]), + ], + [ + F::from_raw([ + 0x1cde_5e4a_7b00_bebe, + 0x662e_26ad_86c4_00b2, + 0xf608_f3b2_717f_9cd2, + 0x1927_2db7_1eec_e6a6, + ]), + F::from_raw([ + 0x039b_e846_af13_4166, + 0xb2dd_1bd6_6a87_ef75, + 0xc749_c746_f092_08ab, + 0x1422_6537_335c_ab33, + ]), + F::from_raw([ + 0xf912_f449_61f9_a9ce, + 0xb21c_21e4_a1c2_e823, + 0x9dfe_38c0_d976_a088, + 0x01fd_6af1_5956_294f, + ]), + ], + [ + F::from_raw([ + 0x5ad8_518d_4e5f_2a57, + 0xaee2_e62e_d229_ba5a, + 0x7bca_190b_8b2c_ab1a, + 0x18e5_abed_d626_ec30, + ]), + F::from_raw([ + 0x0e2d_54dc_1c84_fda6, + 0x97c0_21a3_a409_926d, + 0xabbd_ffa6_d3b3_5e32, + 0x0fc1_bbce_ba05_90f5, + ]), + F::from_raw([ + 0x7225_1309_1c0f_90c9, + 0x69e7_3748_1ad3_376d, + 0xca1d_8a1e_828d_6fb9, + 0x3034_7f53_e91a_637f, + ]), + ], + [ + F::from_raw([ + 0x9552_54e8_1e2f_98b7, + 0x2b47_5bca_9222_507c, + 0x5bbb_3625_c3b0_71a4, + 0x0de5_9a35_8f0e_cd2d, + ]), + F::from_raw([ + 0xcc96_f373_156e_cf16, + 0x74b7_7a8d_e808_8d62, + 0x6ade_0fad_0239_7438, + 0x1923_67e6_5f92_3e2f, + ]), + F::from_raw([ + 0x87fb_421d_18dc_887d, + 0x85c6_6aff_c3a6_b6ca, + 0x3f83_0a97_9873_e596, + 0x01a9_92b6_af04_24b9, + ]), + ], + [ + F::from_raw([ + 0x69ac_d5bd_3ef7_4ec8, + 0xe69f_f2b4_a806_9c88, + 0x01bb_81c2_f854_ad8e, + 0x1e9b_df54_27a5_6207, + ]), + F::from_raw([ + 0x547f_82d6_082f_7a42, + 0xba8d_4ada_f1d0_5142, + 0x9daa_27f2_0a01_7a07, + 0x1b25_6e0f_b7d5_ec33, + ]), + F::from_raw([ + 0x2825_6d1b_1ef3_8e70, + 0x2b4d_b734_215d_1b8d, + 0x42a5_3a53_1910_f9a3, + 0x2a5b_c4ad_2574_99ea, + ]), + ], + [ + F::from_raw([ + 0x008f_29a5_1b83_7f90, + 0x18f4_bb1c_58e4_9c51, + 0x471c_4df7_05b5_9ac0, + 0x27fc_ec3b_431b_efcb, + ]), + F::from_raw([ + 0x5533_ef85_5627_8a6c, + 0x7e1b_8f20_e812_73eb, + 0xe1b5_7afc_e557_ef94, + 0x2296_1d12_dc1f_96bc, + ]), + F::from_raw([ + 0x824d_8597_f7a1_ee1d, + 0xcaea_a208_6307_c785, + 0x159d_c124_b2dd_142f, + 0x011c_5653_ac8b_64cd, + ]), + ], + [ + F::from_raw([ + 0x5a05_9c31_d456_81df, + 0xa358_56fd_fbff_1bf8, + 0x1bb7_f14a_272f_5535, + 0x1d51_9fea_e982_7d0b, + ]), + F::from_raw([ + 0x0bfb_2ace_24f8_5c7c, + 0xd48b_a408_40a7_3618, + 0x3617_767f_0740_7f43, + 0x2ee9_619a_cd36_e9ec, + ]), + F::from_raw([ + 0xbf49_e225_9305_93db, + 0x98c6_70f6_363a_7e83, + 0x06ef_aadc_0c12_122e, + 0x2637_f99f_ce74_63a9, + ]), + ], + [ + F::from_raw([ + 0x892c_7bc6_de6c_5fa8, + 0x0b9e_4526_c415_ac38, + 0xfd8f_1545_6b01_1e1d, + 0x1c12_7457_3782_4622, + ]), + F::from_raw([ + 0x3947_c8be_4d4e_e971, + 0xcf46_a209_c7c5_6316, + 0xc78f_bb1e_b365_c232, + 0x19b9_8d3f_c8e2_b487, + ]), + F::from_raw([ + 0x05e1_2bf8_d3e3_fecf, + 0x2548_edbb_ea40_951a, + 0x8c9e_5fc1_8119_0a5c, + 0x04bf_0ee4_4e25_b5b0, + ]), + ], + [ + F::from_raw([ + 0xd3a7_8921_6b7f_6718, + 0x7efc_62d6_2e31_404e, + 0xf7da_6feb_b711_16e4, + 0x1508_862a_7254_2035, + ]), + F::from_raw([ + 0xc934_83c5_8e65_1560, + 0xa6c0_0164_1752_ccd3, + 0x0d17_cd47_6adc_475c, + 0x2968_4ced_e059_b92e, + ]), + F::from_raw([ + 0x5b13_525d_22fa_e357, + 0x7a5d_7203_cedf_2e1e, + 0xf9de_635c_42f2_f481, + 0x11fb_a1de_926d_c812, + ]), + ], + [ + F::from_raw([ + 0xae6e_048d_1407_695c, + 0xb62d_c322_9bd5_951b, + 0xaa2c_ab67_a1e3_77f0, + 0x1c79_b44b_a583_f341, + ]), + F::from_raw([ + 0xf0e2_6527_2d40_6547, + 0x9d4e_d20e_9a72_5159, + 0x5f89_81e3_bef4_65f4, + 0x0efa_c663_7312_c702, + ]), + F::from_raw([ + 0xa4c3_1ec2_9a65_ed71, + 0x0414_b3ca_42d9_9011, + 0x9bda_e426_61a2_494d, + 0x0202_e9ab_de9c_9628, + ]), + ], + [ + F::from_raw([ + 0xbdab_55f7_bd7a_6e36, + 0xeb65_d920_99c4_f2e6, + 0x25ba_84ad_7540_b380, + 0x1829_65cf_a2bd_9015, + ]), + F::from_raw([ + 0x78d8_4810_e5b3_fcbc, + 0xd50c_d22e_08bb_9c70, + 0x13de_9019_8396_845e, + 0x2b22_8d89_43f9_f31b, + ]), + F::from_raw([ + 0xa82b_f5b7_f8b5_3189, + 0x7134_dcc6_7af2_9cce, + 0xbdaf_4f7a_66de_2321, + 0x00d5_77d3_7875_1869, + ]), + ], + [ + F::from_raw([ + 0x4b12_16cf_0071_35b6, + 0xac4a_b168_a524_ecc1, + 0xcbe2_e286_dcdc_284c, + 0x243b_0fa8_8aed_c975, + ]), + F::from_raw([ + 0xbb64_b331_e0e8_f39f, + 0x7dbe_d93e_fbf3_9852, + 0x6b69_3322_655a_fe50, + 0x27c7_ca4b_f429_0d1e, + ]), + F::from_raw([ + 0x5a84_3236_4a9f_2b9b, + 0xc9b1_b6d3_330a_13e0, + 0x3165_2793_025c_0b3b, + 0x27d0_ab1d_52d5_dafa, + ]), + ], + [ + F::from_raw([ + 0x6676_32a1_0a62_37bf, + 0x3b71_e8cd_c6b2_0a2c, + 0x70cf_9be3_4446_1198, + 0x14ae_1c11_de51_20e6, + ]), + F::from_raw([ + 0x54ab_0fee_62b0_3e8b, + 0x2380_4c38_7d91_e980, + 0x75a0_abaa_b437_3896, + 0x23d1_b30e_1e91_dc02, + ]), + F::from_raw([ + 0x9eaa_36ec_4a76_8011, + 0x07b4_0466_97f4_4a6a, + 0x3728_c4c9_4520_0c5d, + 0x2d30_71b4_4b08_19a3, + ]), + ], + [ + F::from_raw([ + 0xe9c1_7584_f057_8bdb, + 0x19ab_e4e7_4255_d170, + 0x4358_8e11_dce4_4e8d, + 0x1c91_2117_1052_6c8d, + ]), + F::from_raw([ + 0x3fe7_e877_658e_3154, + 0x8c97_0c63_e9de_1a17, + 0xc949_4762_bd42_3bf0, + 0x124d_84d9_4425_e4dc, + ]), + F::from_raw([ + 0xe96e_0364_7116_69b8, + 0x632e_9182_08bc_645f, + 0x30f5_9af8_443b_4f79, + 0x0a04_87e7_fe65_3ff6, + ]), + ], + [ + F::from_raw([ + 0xca94_8833_0a03_7bb8, + 0xce6d_f40b_60a1_58fa, + 0x1020_2d63_a195_e5a1, + 0x10a8_c9fa_3ae6_b3f0, + ]), + F::from_raw([ + 0x3dc5_7d60_43d7_821c, + 0x8203_8795_51cc_c4bf, + 0x8d97_b24a_7199_0ed3, + 0x168d_c103_f522_a455, + ]), + F::from_raw([ + 0x955e_954c_18b3_3a8b, + 0x3e0f_7be7_d6d8_e2a1, + 0x6f6b_4d36_d00a_86b0, + 0x2241_7ea9_7fa7_ab92, + ]), + ], + [ + F::from_raw([ + 0x4d4c_4588_ddd6_2c84, + 0xaabf_ae97_ef1e_6664, + 0x8e45_39a1_bc5d_2c88, + 0x2a61_74d4_b9fa_9053, + ]), + F::from_raw([ + 0xeb4a_3dbd_496d_ef2f, + 0xa0ec_8f30_53b0_6f4f, + 0xf1f7_53f5_f85f_e03b, + 0x1cc2_4805_7eb0_fd28, + ]), + F::from_raw([ + 0x664e_502b_ea28_462e, + 0x5191_7d56_eb9e_6779, + 0xdb26_d857_4656_2d0b, + 0x14db_cc08_b921_c358, + ]), + ], + [ + F::from_raw([ + 0xaddb_965b_f3e3_a372, + 0xebd3_eb9d_a785_7fb0, + 0x1ebd_f33a_fcb5_babf, + 0x1d28_a4f9_cd61_4655, + ]), + F::from_raw([ + 0x5574_a808_5d74_b5b3, + 0x1df7_f00f_ca9d_73b5, + 0x7996_15f5_f529_6146, + 0x1596_900c_e091_cea8, + ]), + F::from_raw([ + 0xea76_84bb_b6e1_8837, + 0xe5ca_3101_c2ea_84e1, + 0xc2ff_0dbc_a6a3_4784, + 0x0978_d75a_71e9_cccc, + ]), + ], + [ + F::from_raw([ + 0x6644_e73d_8d92_5dd7, + 0xe7fa_17c0_7587_2e05, + 0x14d1_5872_6ce9_6b73, + 0x1b1f_1cb1_31cb_037d, + ]), + F::from_raw([ + 0xac95_b019_3493_8e62, + 0xe508_af74_557f_b1da, + 0x73e4_8276_2012_502e, + 0x156e_ecc3_45d1_1b00, + ]), + F::from_raw([ + 0x15df_5568_1554_8d02, + 0x6def_8d1f_1640_804b, + 0x3cd9_0416_eb80_593e, + 0x2244_21a4_d0a2_fe50, + ]), + ], + [ + F::from_raw([ + 0x4fe5_832c_b47e_437d, + 0x6a9a_1065_33a6_7720, + 0x8c75_3762_32df_a666, + 0x0a17_879c_f1b3_0bea, + ]), + F::from_raw([ + 0xf605_c498_e663_c817, + 0x6db9_bb4e_be63_7705, + 0x6269_ed32_efbc_55ee, + 0x25da_7517_3ebc_bd28, + ]), + F::from_raw([ + 0x8e98_3b16_4292_9927, + 0xbbbd_c335_dcbd_30fd, + 0x3e11_86ef_3ded_b586, + 0x0aa0_0a02_a185_7406, + ]), + ], + [ + F::from_raw([ + 0xd1fe_9358_f8b9_4aad, + 0x2c44_1c1c_b34c_4001, + 0x75f5_0acd_aa37_9c04, + 0x300e_19c4_8ed4_8661, + ]), + F::from_raw([ + 0x3a5e_a1b0_c4f6_d630, + 0x808e_3653_d322_ac30, + 0x7c99_e04f_7d34_d725, + 0x2f22_e43e_2ec2_35da, + ]), + F::from_raw([ + 0x005a_50cc_f490_ea4c, + 0xe7c7_665e_c79d_a9ee, + 0xb61f_76a0_122c_0b67, + 0x03ad_cd0e_d603_2a56, + ]), + ], + [ + F::from_raw([ + 0x5ab8_807f_cd24_35a7, + 0xb3e9_be47_a9c9_768f, + 0xcbdf_5121_cf44_d611, + 0x2352_97c1_14d2_7b55, + ]), + F::from_raw([ + 0x14be_7287_a2f8_b4c8, + 0x8916_8f09_c65e_d441, + 0x75f3_375e_ff83_9c26, + 0x10f1_182b_447c_ff33, + ]), + F::from_raw([ + 0xa10c_4fcf_49a5_7966, + 0x61c2_ab95_de1e_7ffb, + 0x7b64_4170_3ce1_a57e, + 0x1e6a_dbf9_3972_4780, + ]), + ], + [ + F::from_raw([ + 0x1a4b_0453_8013_5456, + 0xa889_39a3_3c81_0f76, + 0x6383_3020_c75e_b00e, + 0x01a0_c48c_7936_505b, + ]), + F::from_raw([ + 0xa4e7_7703_be6d_030e, + 0x57bc_ebd0_12ae_5e7a, + 0xc357_7fba_a65b_4fda, + 0x2dbc_47b5_0219_36f8, + ]), + F::from_raw([ + 0xeb33_2b35_ee5a_468c, + 0x1185_a3c9_28b0_9d46, + 0x5756_d280_9219_5e93, + 0x1327_666b_8498_4cf6, + ]), + ], + [ + F::from_raw([ + 0x18ac_39d3_0863_6ca9, + 0x7e16_9397_ed56_d8be, + 0x3c28_edc8_c725_f79d, + 0x2bc9_34e3_f919_21ec, + ]), + F::from_raw([ + 0xf8f0_3221_824a_5cc0, + 0xb878_02d6_6f89_7aea, + 0xd564_b267_c43b_5e5e, + 0x183d_d789_40fb_b6ec, + ]), + F::from_raw([ + 0xc236_88ac_a7fa_205b, + 0x167c_5456_3dd3_50fa, + 0x5cf5_a937_7346_efac, + 0x2c3b_99c1_13ca_a821, + ]), + ], + [ + F::from_raw([ + 0xe8ef_87a9_d828_30cd, + 0xf010_313b_ec24_06b7, + 0x9778_2519_24fc_bb0d, + 0x0cfc_218f_63c5_a59e, + ]), + F::from_raw([ + 0x2b6e_0759_92bc_073d, + 0x7595_39b2_7c2f_4d93, + 0xa3c9_fbb8_e1cd_ba31, + 0x301a_1be9_217e_2cbf, + ]), + F::from_raw([ + 0xbcfc_996f_0a8b_8d4f, + 0x5ecb_8636_f42c_4e2c, + 0x2bd5_6d3b_0530_3d39, + 0x0451_168d_b641_6d9a, + ]), + ], + [ + F::from_raw([ + 0x6e52_da33_bd11_7458, + 0x662b_ee64_1c5d_f4a9, + 0x8032_c8ae_75f1_aca0, + 0x0279_fe38_1976_eda4, + ]), + F::from_raw([ + 0x2952_7d36_c740_e678, + 0x747e_f420_a5f0_d758, + 0x7939_4827_0d81_4241, + 0x2dd3_f1de_a0c8_d9f4, + ]), + F::from_raw([ + 0x8d81_dbb2_6682_f28b, + 0xfdf2_55ac_8d66_94d1, + 0xeaec_0104_a000_8897, + 0x1bde_2068_fd10_ccc3, + ]), + ], + [ + F::from_raw([ + 0xbe59_a321_3b04_7613, + 0xdff8_4104_178e_67c3, + 0xc819_de04_a1a1_5e1b, + 0x18e9_925c_649a_6bf7, + ]), + F::from_raw([ + 0x95d0_55cb_4323_bd14, + 0x0371_6d7a_ad74_c227, + 0x2722_a9b1_37a6_25c9, + 0x0281_fc39_2973_d497, + ]), + F::from_raw([ + 0xdf4e_63e8_db36_3415, + 0x4fe2_6ae2_e9c7_d161, + 0x9b3d_7a20_e784_5f38, + 0x0757_134b_e627_b5ff, + ]), + ], + [ + F::from_raw([ + 0x78d8_dee4_db8c_b576, + 0xdb33_2e1e_5c0f_67d7, + 0xb45d_f537_5e5a_ff61, + 0x1e96_e7da_7803_2be3, + ]), + F::from_raw([ + 0xbd0b_65b9_76de_377c, + 0x50fd_257d_13c8_7c4b, + 0x5c6f_4c61_5904_cbde, + 0x10e2_9927_e946_e814, + ]), + F::from_raw([ + 0xe7e9_8192_104d_6c60, + 0x67bc_3bc3_340b_86ea, + 0x4a0e_03d4_f115_e831, + 0x104f_7527_6d0d_a236, + ]), + ], + [ + F::from_raw([ + 0x04b0_bd5e_d1cd_62dc, + 0x6962_4075_cb6d_fa5a, + 0xd255_e95d_5e96_2ba9, + 0x01c6_368c_b969_e2f8, + ]), + F::from_raw([ + 0x37a5_a15c_d32b_e88f, + 0xb30a_6e06_7bef_ab88, + 0x764a_f0e7_f768_56e1, + 0x106f_ffc9_4ca4_acbd, + ]), + F::from_raw([ + 0x569b_5201_0f0c_95a2, + 0x4fcb_c351_5aed_35dd, + 0x7dbd_8a01_5572_8c64, + 0x15e7_8bf1_f7c8_bfe1, + ]), + ], + [ + F::from_raw([ + 0xa38f_5515_985d_16b8, + 0x8d8c_192e_3c02_d598, + 0x718f_e666_4670_55d1, + 0x000c_ab14_c0ff_2cf1, + ]), + F::from_raw([ + 0x0178_03bb_1abf_9c75, + 0x3f45_d4de_ea6c_e7ff, + 0x9f32_8e61_4190_9b90, + 0x23f3_4102_470d_9482, + ]), + F::from_raw([ + 0xee0f_c2aa_a693_5da6, + 0xe2cf_207b_0d32_3ba0, + 0x1d65_f6ef_7284_f392, + 0x1fd2_d8ce_7613_d6b6, + ]), + ], + [ + F::from_raw([ + 0x02cb_dd24_374f_ad45, + 0xdf03_695b_ad70_b3ac, + 0xfa13_fc8a_57d0_78f0, + 0x0c63_086a_8a20_a108, + ]), + F::from_raw([ + 0xaab6_31aa_e5a2_b54c, + 0x6b18_5fcc_2f0e_548e, + 0xfdb2_15a5_c8d9_67f4, + 0x27cd_3730_e471_4199, + ]), + F::from_raw([ + 0x5ec7_9c1e_524b_e22b, + 0x4cd1_a1cf_69f1_5fca, + 0x186c_0d4d_4a01_6460, + 0x15ad_aa75_fc1f_1595, + ]), + ], + [ + F::from_raw([ + 0x8531_83fb_7ae1_9d02, + 0xd1e1_5619_a346_a9e8, + 0x6fe7_1314_cdc4_d64b, + 0x05aa_5e4f_b849_3122, + ]), + F::from_raw([ + 0x31c1_3fb6_a57c_4022, + 0x3ccb_7a9a_8ea2_45ac, + 0x5831_3959_fcfc_621a, + 0x27fb_8cd6_94fc_d1d0, + ]), + F::from_raw([ + 0x713b_207a_d34e_c7a7, + 0x1756_5d61_af26_c621, + 0xe463_ee9a_3f70_e3e8, + 0x2be0_953f_d8b1_d2f6, + ]), + ], + [ + F::from_raw([ + 0xfce0_3b25_d20c_25a2, + 0x469f_cbe8_7b9c_1ab6, + 0xf116_ca2a_15fc_36cc, + 0x2171_43e8_ae45_8a9e, + ]), + F::from_raw([ + 0x16fa_11b3_d593_28f2, + 0xf945_e1eb_a04f_bcd9, + 0xcffd_3123_a011_8d90, + 0x29c3_b69f_65b5_cfd2, + ]), + F::from_raw([ + 0xf81c_16c8_4ed3_2fe9, + 0x8e99_662b_3311_144e, + 0x603d_e573_d119_18a9, + 0x2951_ccd2_0b0a_35b9, + ]), + ], + [ + F::from_raw([ + 0xac4b_cfba_87db_d048, + 0x7b9e_e088_de1d_b8b7, + 0xb69b_64f3_e7d6_0961, + 0x202d_7cf4_1dcb_bb10, + ]), + F::from_raw([ + 0x9b1a_d068_6c37_43b5, + 0xc036_a1e0_d377_cfcc, + 0x5b39_dddc_6f03_95ee, + 0x014d_390c_7229_d74a, + ]), + F::from_raw([ + 0xdd7e_9729_2296_262e, + 0x16f7_dfa3_ebfc_c3d4, + 0x4082_0dc1_1e59_d9bf, + 0x1479_c1cf_bd48_8172, + ]), + ], + [ + F::from_raw([ + 0x816f_cd74_b562_dfa0, + 0xd4a9_6d8b_6c61_ded5, + 0x0f65_d893_3ab4_3397, + 0x0684_d98b_b967_6175, + ]), + F::from_raw([ + 0xe400_8373_c894_47a8, + 0x892c_d501_79df_7ce1, + 0xda05_a729_297a_2a5f, + 0x1f4f_4cd3_2539_eddc, + ]), + F::from_raw([ + 0xd958_ffb0_4635_b84f, + 0x1dfd_792a_5351_c10b, + 0x3717_31b5_752d_957d, + 0x0332_6d7f_dcd6_ccc2, + ]), + ], + [ + F::from_raw([ + 0xbd76_a271_cb6e_876d, + 0x0a56_88d7_e496_5aaf, + 0x75bd_7f99_d1a9_5d7f, + 0x1d5b_99cb_1e95_e9d9, + ]), + F::from_raw([ + 0x496f_0513_d2af_1054, + 0x4174_cc9f_6ff6_b8ba, + 0x4e99_78da_e7f7_7a01, + 0x13d9_09a6_21a8_6fcb, + ]), + F::from_raw([ + 0x13c4_5e28_174d_17ce, + 0x1822_1f7b_d7f8_99e3, + 0xcdbf_3270_e8bf_1c4f, + 0x16e7_671d_2d3a_50c7, + ]), + ], + [ + F::from_raw([ + 0x0c53_2368_4153_fdcd, + 0x294c_6af6_b590_0c70, + 0xad82_466f_062d_38d8, + 0x03aa_c5e5_2aed_b6ac, + ]), + F::from_raw([ + 0x96d0_886c_8191_6d34, + 0xdf3a_4c8c_93e2_92c9, + 0xdc2c_19a3_332f_aba6, + 0x086f_0806_c45c_f713, + ]), + F::from_raw([ + 0x34e1_f85a_2e20_e969, + 0x1f98_07d5_75b0_d88a, + 0x1a40_a146_87da_5aa9, + 0x2a84_5e4c_b083_84e5, + ]), + ], + [ + F::from_raw([ + 0x742d_1e0e_ccf0_6e8b, + 0xcab1_8b6a_62ef_e2f4, + 0x005f_3b28_04cb_eea1, + 0x18d2_a592_57af_c8bd, + ]), + F::from_raw([ + 0x9b8a_d15b_e536_1be9, + 0x610d_ea28_7318_1602, + 0x4d53_e693_38e5_fb98, + 0x1a2d_3094_ec69_31ac, + ]), + F::from_raw([ + 0xaeca_0df6_089c_ad6d, + 0xd300_2102_60c1_d589, + 0x5299_978e_53f5_55dc, + 0x1cfe_7a33_0a50_0182, + ]), + ], + [ + F::from_raw([ + 0x7e27_8453_0825_b921, + 0x33f2_fdbc_1925_5305, + 0xea59_002d_4023_0b89, + 0x0da4_0fff_9f10_c73a, + ]), + F::from_raw([ + 0xc039_3df0_1e07_9ff5, + 0x6561_de1f_aec7_0eef, + 0xdbf6_e8e2_34f3_0c84, + 0x0e05_b77a_1a39_6b75, + ]), + F::from_raw([ + 0x325f_9180_29bf_262e, + 0x2151_bec4_0f30_84b4, + 0xdcd5_8b95_d665_6a45, + 0x1a04_4b84_6a4b_b239, + ]), + ], + [ + F::from_raw([ + 0xa894_93b0_ea18_9784, + 0xc349_540d_b935_e2bc, + 0x7804_3335_ddca_b1b8, + 0x2e13_9ae5_1418_b64f, + ]), + F::from_raw([ + 0x70ee_063a_7f67_6240, + 0xe4f2_8f77_af51_5b11, + 0x94a0_2286_6312_5866, + 0x0741_8089_12ca_9cbf, + ]), + F::from_raw([ + 0x7f69_b40d_94e8_cc91, + 0x8642_e046_0032_1880, + 0xf70f_9059_bb80_e360, + 0x0b29_628e_e57e_1d55, + ]), + ], + [ + F::from_raw([ + 0x565f_9499_33fb_f9d1, + 0xa21d_df46_b463_1583, + 0xdd54_75cd_cabc_e8af, + 0x0608_04c3_1fb3_be30, + ]), + F::from_raw([ + 0x36d3_955e_853b_3592, + 0xd195_fa25_2b0c_d84f, + 0x63f9_bd30_d8cb_6002, + 0x2760_f6b6_590a_73a8, + ]), + F::from_raw([ + 0x67d6_f228_492c_2c5b, + 0x2c65_b571_104d_ef5a, + 0x6fa5_3cb6_d2e0_537c, + 0x14aa_7543_a56c_144a, + ]), + ], +]; +// n: 254 +// t: 3 +// N: 762 +// Result Algorithm 1: +// [True, 0] +// Result Algorithm 2: +// [True, None] +// Result Algorithm 3: +// [True, None] +// Prime number: 0x0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 +// MDS matrix: +pub(crate) const MDS: [[F; 3]; 3] = [ + [ + F::from_raw([ + 0x227f_14ac_41bc_4cd3, + 0x76f4_79f8_fa4b_34f1, + 0x625e_a9db_1f24_7c63, + 0x0960_0146_bec7_f4fd, + ]), + F::from_raw([ + 0x570e_848c_b09c_9292, + 0x4808_0f6a_139f_5a64, + 0x41b4_30e8_1e9f_5fa6, + 0x1eb8_32b9_08b8_73be, + ]), + F::from_raw([ + 0x8b63_cccb_ea20_d8af, + 0x7a26_db16_0ae2_8eb9, + 0x5b01_fc0c_44f5_d236, + 0x0086_8c36_77aa_eb8a, + ]), + ], + [ + F::from_raw([ + 0x99a4_614a_9650_4ebe, + 0x4466_3a2b_f55d_b569, + 0x0ece_763c_bb20_94c4, + 0x0b9a_382d_b828_9f52, + ]), + F::from_raw([ + 0x4bbc_da5a_cdc4_35ec, + 0xef4e_1936_fb87_6d03, + 0xd287_9cdc_c47c_1113, + 0x2de7_7724_76f3_03a6, + ]), + F::from_raw([ + 0xbc44_e7a2_dd3d_793d, + 0x24da_6487_f1b1_8fdb, + 0x0557_2ebb_de23_6b76, + 0x2794_8d4b_cb6d_6652, + ]), + ], + [ + F::from_raw([ + 0xf645_4712_6534_4dc4, + 0xa1e3_1f41_f7ce_7631, + 0xed02_8865_d2f9_ef22, + 0x1fce_fc21_8b56_75fe, + ]), + F::from_raw([ + 0xae61_2716_ce44_4b3b, + 0x9677_0fdc_936f_9b16, + 0xdfd8_2802_4c17_2965, + 0x0d7b_02b0_f922_e679, + ]), + F::from_raw([ + 0x46fd_c664_ee45_11c7, + 0xf174_10f2_29a1_271d, + 0xca16_a9f3_c1f9_bc4f, + 0x1ee2_3b55_6368_74a2, + ]), + ], +]; +// Inverse MDS matrix: +pub(crate) const MDS_INV: [[F; 3]; 3] = [ + [ + F::from_raw([ + 0x2f1e_66ed_55f9_c9fc, + 0x3e91_e733_06f0_cd43, + 0x4def_04f6_7ea4_695d, + 0x1853_f03f_9b25_2eeb, + ]), + F::from_raw([ + 0x22b5_6ca4_29c3_63fc, + 0x44db_50db_384d_01a1, + 0x531c_e5e3_792c_9936, + 0x1321_8551_6ff7_885d, + ]), + F::from_raw([ + 0xe9f2_6d10_3899_37e7, + 0x79a6_862e_163c_5e40, + 0x7ccd_2f5f_d6e0_a05b, + 0x048c_9fd0_418a_78de, + ]), + ], + [ + F::from_raw([ + 0xb782_b5fc_2ef1_eef5, + 0x0e6a_2162_b331_1237, + 0x2253_5c06_4181_40c4, + 0x1c57_f77f_7c6e_2d70, + ]), + F::from_raw([ + 0x670a_ef95_c403_752a, + 0x40e6_4ba0_515d_988e, + 0x249a_cf6a_f5d2_bddc, + 0x1e83_0536_4450_74ac, + ]), + F::from_raw([ + 0x8051_c963_2e14_2537, + 0x025c_31fa_1047_3f62, + 0x34ad_7a91_8013_2c72, + 0x255e_4660_7289_f388, + ]), + ], + [ + F::from_raw([ + 0x24eb_ea47_2f8a_4181, + 0xa617_25cb_ff02_7a2e, + 0xc0ec_02fc_e8d5_1fde, + 0x092c_a526_b2fd_ef96, + ]), + F::from_raw([ + 0xa7cb_e164_eddf_2ed1, + 0x6939_6c30_ce1a_1bf4, + 0xa2c3_0b2e_3432_d199, + 0x00f2_3802_4958_0f86, + ]), + F::from_raw([ + 0x80de_8813_ede1_71ea, + 0xa0e3_f64c_e8b0_590a, + 0x100b_ea16_d54e_c9e3, + 0x0f03_e31e_3423_5cbb, + ]), + ], +]; diff --git a/authdecode/src/backend/halo2/poseidon/spec.rs b/authdecode/src/backend/halo2/poseidon/spec.rs new file mode 100644 index 0000000000..f9d4f2ec2e --- /dev/null +++ b/authdecode/src/backend/halo2/poseidon/spec.rs @@ -0,0 +1,117 @@ +use super::{rate15_params, rate1_params}; +use crate::backend::halo2::poseidon::rate2_params; +use group::ff::Field; +use halo2_poseidon::poseidon::primitives::Spec; +use halo2_proofs::halo2curves::bn256::Fr as F; + +/// The type used to hold the MDS matrix and its inverse. +pub(crate) type Mds = [[F; T]; T]; + +/// Spec for rate 15 Poseidon. halo2 uses this spec both inside +/// the zk circuit and in the clear. +/// +/// Compare it to the spec which zcash uses: +/// [halo2_gadgets::poseidon::primitives::P128Pow5T3] +#[derive(Debug)] +pub struct Spec15; + +impl Spec for Spec15 { + fn full_rounds() -> usize { + 8 + } + + fn partial_rounds() -> usize { + // Taken from https://github.com/iden3/circomlib/blob/master/circuits/poseidon.circom + // (see "var N_ROUNDS_P[16]"), where they use 64 partial rounds for 15-rate Poseidon + 64 + } + + fn sbox(val: F) -> F { + val.pow_vartime(&[5]) + } + + fn secure_mds() -> usize { + unimplemented!() + } + + fn constants() -> (Vec<[F; 16]>, Mds, Mds) { + ( + rate15_params::ROUND_CONSTANTS[..].to_vec(), + rate15_params::MDS, + rate15_params::MDS_INV, + ) + } +} + +/// Spec for rate 2 Poseidon which halo2 uses both inside +/// the zk circuit and in the clear. +/// +/// Compare it to the spec which zcash uses: +/// [halo2_gadgets::poseidon::primitives::P128Pow5T3] +#[derive(Debug)] +pub struct Spec2; + +impl Spec for Spec2 { + fn full_rounds() -> usize { + 8 + } + + fn partial_rounds() -> usize { + // Taken from https://github.com/iden3/circomlib/blob/master/circuits/poseidon.circom + // (see "var N_ROUNDS_P[16]"), where they use 57 partial rounds for 2-rate Poseidon. + // TODO: investigate why setting this > 56 gives errors. + 56 + } + + fn sbox(val: F) -> F { + val.pow_vartime(&[5]) + } + + fn secure_mds() -> usize { + unimplemented!() + } + + fn constants() -> (Vec<[F; 3]>, Mds, Mds) { + ( + rate2_params::ROUND_CONSTANTS[..].to_vec(), + rate2_params::MDS, + rate2_params::MDS_INV, + ) + } +} + +/// Spec for rate 1 Poseidon which halo2 uses both inside +/// the zk circuit and in the clear. +/// +/// Compare it to the spec which zcash uses: +/// [halo2_gadgets::poseidon::primitives::P128Pow5T3] +#[derive(Debug)] +pub struct Spec1; + +impl Spec for Spec1 { + fn full_rounds() -> usize { + 8 + } + + fn partial_rounds() -> usize { + // Taken from https://github.com/iden3/circomlib/blob/master/circuits/poseidon.circom + // (see "var N_ROUNDS_P[16]"), where they use 56 partial rounds for 1-rate Poseidon + 56 + } + + fn sbox(val: F) -> F { + val.pow_vartime(&[5]) + } + + fn secure_mds() -> usize { + unimplemented!() + } + + fn constants() -> (Vec<[F; 2]>, Mds, Mds) { + ( + rate1_params::ROUND_CONSTANTS[..].to_vec(), + rate1_params::MDS, + rate1_params::MDS_INV, + ) + } +} diff --git a/authdecode/src/backend/halo2/prover.rs b/authdecode/src/backend/halo2/prover.rs new file mode 100644 index 0000000000..81cf3754ac --- /dev/null +++ b/authdecode/src/backend/halo2/prover.rs @@ -0,0 +1,436 @@ +use crate::{ + backend::halo2::{poseidon::poseidon_2, utils::biguint_to_f}, + prover::{backend::Backend, error::ProverError}, + utils::{bits_to_biguint, u8vec_to_boolvec}, + Proof, ProofInput, +}; +use halo2_proofs::{ + halo2curves::bn256::{Bn256, Fr as F, G1Affine}, + plonk, + plonk::ProvingKey, + poly::{ + commitment::CommitmentScheme, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG}, + multiopen::ProverGWC, + }, + }, + transcript::{Blake2bWrite, Challenge255, TranscriptWriterBuffer}, +}; + +use rand::Rng; +use std::time::Instant; + +use super::{ + circuit::{AuthDecodeCircuit, FIELD_ELEMENTS}, + poseidon::{poseidon_1, poseidon_15}, + utils::{deltas_to_matrices, f_to_bigint}, + CHUNK_SIZE, USEFUL_BITS, +}; +use crate::backend::halo2::circuit::SALT_SIZE; + +use num::BigUint; +use rand::thread_rng; + +/// halo2's native ProvingKey can't be used without params, so we wrap +/// them in one struct. +#[derive(Clone)] +pub struct PK { + pub key: ProvingKey< as CommitmentScheme>::Curve>, + pub params: ParamsKZG, +} + +/// Implements the Prover in the authdecode protocol using halo2 +/// proof system. +pub struct Prover { + proving_key: PK, +} + +impl Backend for Prover { + fn commit_plaintext( + &self, + mut plaintext: Vec, + ) -> Result<(BigUint, BigUint), ProverError> { + if plaintext.len() > CHUNK_SIZE { + // TODO proper error + return Err(ProverError::InternalError); + } + + // Right-pad the plaintext with zeroes to the size of the chunk. + plaintext.extend(vec![false; CHUNK_SIZE - plaintext.len()]); + + // Generate random salt and add it to the plaintext. + let mut rng = thread_rng(); + let salt: Vec = core::iter::repeat_with(|| rng.gen::()) + .take(SALT_SIZE) + .collect::>(); + let salt = bits_to_biguint(&salt); + + // Convert bits into field elements + let mut field_elements: Vec = + plaintext.chunks(USEFUL_BITS).map(bits_to_biguint).collect(); + // Add salt + field_elements.push(salt.clone()); + + let pt_digest = hash_internal(&field_elements)?; + + Ok((pt_digest, salt)) + } + + fn commit_encoding_sum( + &self, + encoding_sum: BigUint, + ) -> Result<(BigUint, BigUint), ProverError> { + // Generate random salt + let mut rng = thread_rng(); + let salt: Vec = core::iter::repeat_with(|| rng.gen::()) + .take(SALT_SIZE) + .collect::>(); + + // Commit to encodings + + let mut enc_sum_bits = u8vec_to_boolvec(&encoding_sum.to_bytes_be()); + debug_assert!(enc_sum_bits.len() <= 125); + + if enc_sum_bits.len() > USEFUL_BITS { + // TODO proper error + return Err(ProverError::InternalError); + } + + let enc_sum = bits_to_biguint(&enc_sum_bits); + let salt = bits_to_biguint(&salt); + + // Pack sum and salt into a single field element, to achive this order starting from the MSB: + // zero padding | sum | salt + + let enc_digest = hash_internal(&[enc_sum, salt.clone()])?; + + Ok((enc_digest, salt)) + } + + fn prove(&self, input: Vec) -> Result, ProverError> { + // TODO: implement a better proving strategy. + // For now we just prove one chunk with one proof. + let mut rng = thread_rng(); + + let proofs = input + .iter() + .map(|input| { + // convert into matrices + let (deltas_as_rows, deltas_as_columns) = + deltas_to_matrices(&input.deltas, self.useful_bits()); + + // Pad plaintext to chunk size and split up into integers. + let mut plaintext = input.plaintext.clone(); + plaintext.extend(vec![false; self.chunk_size() - plaintext.len()]); + let plaintext = plaintext + .chunks(self.useful_bits()) + .map(bits_to_biguint) + .collect::>(); + + // convert plaintext into F type + let plaintext: [F; FIELD_ELEMENTS] = plaintext + .iter() + .map(biguint_to_f) + .collect::>() + .try_into() + .unwrap(); + + // arrange into the format which halo2 expects + let mut all_inputs: Vec<&[F]> = + deltas_as_columns.iter().map(|v| v.as_slice()).collect(); + + // add another column with public inputs + let tmp = &[ + biguint_to_f(&input.plaintext_hash), + biguint_to_f(&input.encoding_sum_hash), + biguint_to_f(&input.zero_sum), + ]; + all_inputs.push(tmp); + + let circuit = AuthDecodeCircuit::new( + plaintext, + biguint_to_f(&input.plaintext_salt), + biguint_to_f(&input.encoding_sum_salt), + deltas_as_rows, + ); + + let now = Instant::now(); + + let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); + + let res = plonk::create_proof::< + KZGCommitmentScheme, + ProverGWC<'_, Bn256>, + Challenge255, + _, + Blake2bWrite, G1Affine, Challenge255<_>>, + _, + >( + &self.proving_key.params, + &self.proving_key.key, + &[circuit.clone()], + &[all_inputs.as_slice()], + &mut rng, + &mut transcript, + ); + if res.is_err() { + return Err(ProverError::ProvingBackendError); + } + + println!("Proof created in [{:?}]", now.elapsed()); + let proof = transcript.finalize(); + println!("Proof size [{} kB]", proof.len() as f64 / 1024.0); + Ok(proof) + }) + .collect::, ProverError>>()?; + + Ok(proofs) + } + + fn chunk_size(&self) -> usize { + CHUNK_SIZE + } +} + +impl Prover { + pub fn new(pk: PK) -> Self { + Self { proving_key: pk } + } + + fn useful_bits(&self) -> usize { + USEFUL_BITS + } +} + +/// Hashes `inputs` with Poseidon and returns the digest as `BigUint`. +fn hash_internal(inputs: &[BigUint]) -> Result { + let digest = match inputs.len() { + 15 => { + // hash with rate-15 Poseidon + let fes: [F; 15] = inputs + .iter() + .map(biguint_to_f) + .collect::>() + .try_into() + .unwrap(); + poseidon_15(&fes) + } + 2 => { + // hash with rate-2 Poseidon + let fes: [F; 2] = inputs + .iter() + .map(biguint_to_f) + .collect::>() + .try_into() + .unwrap(); + poseidon_2(&fes) + } + 1 => { + // hash with rate-1 Poseidon + let fes: [F; 1] = inputs + .iter() + .map(biguint_to_f) + .collect::>() + .try_into() + .unwrap(); + poseidon_1(&fes) + } + _ => return Err(ProverError::WrongPoseidonInput), + }; + Ok(f_to_bigint(&digest)) +} + +// #[cfg(test)] +// mod tests { +// use super::*; +// use crate::{ +// backend::halo2{ +// circuit::{CELLS_PER_ROW, K}, +// prover::hash_internal, +// utils::bigint_to_256bits, +// Curve, +// }, +// prover::{ProofInput, Prove, ProverError}, +// tests::run_until_proofs_are_generated, +// verifier::{VerificationInput, VerifierError, Verify}, +// Proof, +// }; +// use halo2_proofs::{dev::MockProver, plonk::Assignment}; +// use num::BigUint; + +// /// TestHalo2Prover is a test prover. It is the same as [Prover] except: +// /// - it doesn't require a proving key +// /// - it uses a `MockProver` inside `prove()` +// /// +// /// This allows us to test the circuit with the correct inputs from the authdecode +// /// protocol execution. Also allows us to corrupt each of the circuit inputs and +// /// expect a failure. +// struct TestHalo2Prover {} +// impl Prove for TestHalo2Prover { +// fn prove(&self, input: ProofInput) -> Result { +// // convert into matrices +// let (deltas_as_rows, deltas_as_columns) = +// deltas_to_matrices(&input.deltas, self.useful_bits()); + +// // convert plaintext into F type +// let good_plaintext: [F; TOTAL_FIELD_ELEMENTS] = input +// .plaintext +// .iter() +// .map(bigint_to_f) +// .collect::>() +// .try_into() +// .unwrap(); + +// // arrange into the format which halo2 expects +// let mut good_inputs: Vec> = +// deltas_as_columns.iter().map(|v| v.to_vec()).collect(); + +// // add another column with public inputs +// let tmp = vec![ +// bigint_to_f(&input.plaintext_hash), +// bigint_to_f(&input.label_sum_hash), +// bigint_to_f(&input.sum_of_zero_labels), +// ]; +// good_inputs.push(tmp); + +// let circuit = +// AuthDecodeCircuit::new(good_plaintext, bigint_to_f(&input.salt), deltas_as_rows); + +// // Test with the correct inputs. +// // Expect successful verification. + +// let prover = MockProver::run(K, &circuit, good_inputs.clone()).unwrap(); +// let res = prover.verify(); +// println!("{:?}", res); +// assert!(res.is_ok()); + +// // Find one delta which corresponds to plaintext bit 1 and corrupt +// // the delta: + +// // Find the first bit 1 in plaintext +// let bits = bigint_to_256bits(input.plaintext[0].clone()); +// let mut offset: i32 = -1; +// for (i, b) in bits.iter().enumerate() { +// if *b { +// offset = i as i32; +// break; +// } +// } +// // first field element of the plaintext is not expected to have all +// // bits set to zero. +// assert!(offset != -1); +// let offset = offset as usize; + +// // Find the position of the corresponding delta. The position is +// // row/column in the halo2 table +// let col = offset % CELLS_PER_ROW; +// let row = offset / CELLS_PER_ROW; + +// // Corrupt the delta +// let mut bad_input1 = good_inputs.clone(); +// bad_input1[col][row] = F::from(123); + +// let prover = MockProver::run(K, &circuit, bad_input1.clone()).unwrap(); +// assert!(prover.verify().is_err()); + +// // One-by-one corrupt the plaintext hash, the label sum hash, the zero sum. +// // Expect verification error. + +// for i in 0..3 { +// let mut bad_public_input = good_inputs.clone(); +// bad_public_input[CELLS_PER_ROW][i] = F::from(123); +// let prover = MockProver::run(K, &circuit, bad_public_input.clone()).unwrap(); +// assert!(prover.verify().is_err()); +// } + +// // Corrupt only the plaintext. +// // Expect verification error. + +// let mut bad_plaintext = good_plaintext; +// bad_plaintext[0] = F::from(123); +// let circuit = +// AuthDecodeCircuit::new(bad_plaintext, bigint_to_f(&input.salt), deltas_as_rows); +// let prover = MockProver::run(K, &circuit, good_inputs.clone()).unwrap(); +// assert!(prover.verify().is_err()); + +// // Corrupt only the salt. +// // Expect verification error. + +// let bad_salt = BigUint::from(123u8); +// let circuit = +// AuthDecodeCircuit::new(good_plaintext, bigint_to_f(&bad_salt), deltas_as_rows); +// let prover = MockProver::run(K, &circuit, good_inputs.clone()).unwrap(); +// assert!(prover.verify().is_err()); + +// Ok(Default::default()) +// } + +// fn useful_bits(&self) -> usize { +// USEFUL_BITS +// } + +// fn poseidon_rate(&self) -> usize { +// TOTAL_FIELD_ELEMENTS +// } + +// fn permutation_count(&self) -> usize { +// 1 +// } + +// fn salt_size(&self) -> usize { +// SALT_SIZE +// } + +// fn chunk_size(&self) -> usize { +// CHUNK_SIZE +// } + +// fn hash(&self, inputs: &[BigUint]) -> Result { +// hash_internal(inputs) +// } +// } + +// impl TestHalo2Prover { +// pub fn new() -> Self { +// Self {} +// } +// } + +// /// This verifier is the same as [crate::halo2_backend::verifier::Verifier] except: +// /// - it doesn't require a verifying key +// /// - it does not verify since `MockProver` does that already +// struct TestHalo2Verifier {} + +// impl TestHalo2Verifier { +// pub fn new() -> Self { +// Self {} +// } +// } + +// impl Verify for TestHalo2Verifier { +// fn verify(&self, _: VerificationInput) -> Result { +// Ok(false) +// } + +// fn field_size(&self) -> usize { +// 254 +// } + +// fn useful_bits(&self) -> usize { +// USEFUL_BITS +// } + +// fn chunk_size(&self) -> usize { +// CHUNK_SIZE +// } +// } + +// #[test] +// /// Tests the circuit with a mock prover. +// fn test_circuit() { +// let prover = Box::new(TestHalo2Prover::new()); +// let verifier = Box::new(TestHalo2Verifier::new()); +// let _ = run_until_proofs_are_generated(prover, verifier); +// } +// } diff --git a/authdecode/src/backend/halo2/utils.rs b/authdecode/src/backend/halo2/utils.rs new file mode 100644 index 0000000000..8f0a945852 --- /dev/null +++ b/authdecode/src/backend/halo2/utils.rs @@ -0,0 +1,273 @@ +use super::circuit::{CELLS_PER_ROW, USEFUL_ROWS}; +use crate::{ + backend::halo2::CHUNK_SIZE, + utils::{boolvec_to_u8vec, u8vec_to_boolvec}, + Delta, +}; +use ff::{FromUniformBytes, PrimeField}; +use halo2_proofs::halo2curves::bn256::Fr as F; +use num::{bigint::Sign, BigInt, BigUint, Signed}; + +/// Decomposes a `BigUint` into bits and returns the bits in MSB-first bit order, +/// left padding them with zeroes to the size of 256. +/// The assumption is that `bigint` was sanitized earlier and is not larger +/// than 256 bits +pub fn bigint_to_256bits(bigint: BigUint) -> [bool; 256] { + let bits = u8vec_to_boolvec(&bigint.to_bytes_be()); + let mut bits256 = [false; 256]; + bits256[256 - bits.len()..].copy_from_slice(&bits); + bits256 +} + +/// Converts a `BigUint` into an field element type. +/// The assumption is that `bigint` was sanitized earlier and is not larger +/// than [crate::verifier::Verify::field_size] +pub fn biguint_to_f(biguint: &BigUint) -> F { + let le = biguint.to_bytes_le(); + let mut wide = [0u8; 64]; + wide[0..le.len()].copy_from_slice(&le); + F::from_uniform_bytes(&wide) +} + +/// Converts a `BigInt` into an field element type. +/// The assumption is that `bigint` was sanitized earlier and is not larger +/// than [crate::verifier::Verify::field_size] +pub fn bigint_to_f(bigint: &BigInt) -> F { + let sign = bigint.sign(); + // Safe to unwrap since .abs() always returns a non-negative integer. + let f = biguint_to_f(&bigint.abs().to_biguint().unwrap()); + if sign == Sign::Minus { + -f + } else { + f + } +} + +/// Converts `F` into a `BigUint` type. +/// The assumption is that the field is <= 256 bits +pub fn f_to_bigint(f: &F) -> BigUint { + let tmp: [u8; 32] = f.try_into().unwrap(); + BigUint::from_bytes_le(&tmp) +} + +/// Converts a vec of deltas into a matrix of rows and a matrix of +/// columns and returns them. +/// +/// Panics if the length of `deltas` is > CHUNK_SIZE. +pub fn deltas_to_matrices( + deltas: &[Delta], + useful_bits: usize, +) -> ( + [[F; CELLS_PER_ROW]; USEFUL_ROWS], + [[F; USEFUL_ROWS]; CELLS_PER_ROW], +) { + assert!(deltas.len() <= CHUNK_SIZE); + // Pad with zero deltas to a total count of USEFUL_ROWS * CELLS_PER_ROW deltas. + let mut deltas = deltas.to_vec(); + deltas.extend(vec![Delta::from(0u8); CHUNK_SIZE - deltas.len()]); + + let deltas = convert_and_pad_deltas(&deltas, useful_bits); + let deltas_as_rows = deltas_to_matrix_of_rows(&deltas); + + let deltas_as_columns = transpose_rows(&deltas_as_rows); + + (deltas_as_rows, deltas_as_columns) +} + +/// Splits up 256 bits into 4 limbs, shifts each limb left +/// and returns the shifted limbs as `BigUint`s. +pub fn bits_to_limbs(bits: [bool; 256]) -> [BigUint; 4] { + // break up the field element into 4 64-bit limbs + // the limb at index 0 is the high limb + let limbs: [BigUint; 4] = bits + .chunks(64) + .map(|c| BigUint::from_bytes_be(&boolvec_to_u8vec(c))) + .collect::>() + .try_into() + .unwrap(); + + // shift each limb to the left: + + let two = BigUint::from(2u8); + // how many bits to left-shift each limb by + let shift_by: [BigUint; 4] = [192, 128, 64, 0] + .iter() + .map(|s| two.pow(*s)) + .collect::>() + .try_into() + .unwrap(); + limbs + .iter() + .zip(shift_by.iter()) + .map(|(l, s)| l * s) + .collect::>() + .try_into() + .unwrap() +} + +/// To make handling inside the circuit simpler, we pad each chunk (except for +/// the last one) of deltas with zero values on the left to the size 256. +/// Note that the last chunk (corresponding to the 15th field element) will +/// contain only 128 deltas, so we do NOT pad it. +/// +/// Returns padded deltas +fn convert_and_pad_deltas(deltas: &[Delta], useful_bits: usize) -> Vec { + // convert deltas into F type + let deltas: Vec = deltas.iter().map(bigint_to_f).collect(); + + deltas + .chunks(useful_bits) + .enumerate() + .flat_map(|(i, c)| { + if i < 14 { + let mut v = vec![F::from(0); 256 - c.len()]; + v.extend(c.to_vec()); + v + } else { + c.to_vec() + } + }) + .collect() +} + +/// Converts a vec of padded deltas into a matrix of rows and returns it. +fn deltas_to_matrix_of_rows(deltas: &[F]) -> [[F; CELLS_PER_ROW]; USEFUL_ROWS] { + deltas + .chunks(CELLS_PER_ROW) + .map(|c| c.try_into().unwrap()) + .collect::>() + .try_into() + .unwrap() +} + +/// Transposes a matrix of rows of fixed size. +fn transpose_rows(matrix: &[[F; CELLS_PER_ROW]; USEFUL_ROWS]) -> [[F; USEFUL_ROWS]; CELLS_PER_ROW] { + (0..CELLS_PER_ROW) + .map(|i| { + matrix + .iter() + .map(|inner| inner[i]) + .collect::>() + .try_into() + .unwrap() + }) + .collect::>() + .try_into() + .unwrap() +} + +#[test] +fn test_bigint_to_256bits() { + use num_bigint::RandomBits; + use rand::{thread_rng, Rng}; + + // test with a fixed number + let res = bigint_to_256bits(BigUint::from(3u8)); + let expected: [bool; 256] = [vec![false; 254], vec![true; 2]] + .concat() + .try_into() + .unwrap(); + assert_eq!(res, expected); + + // test with a random number + let mut rng = thread_rng(); + let b: BigUint = rng.sample(RandomBits::new(256)); + let mut expected_bits: [bool; 256] = (0..256) + .map(|i| b.bit(i)) + .collect::>() + .try_into() + .unwrap(); + expected_bits.reverse(); + assert_eq!(bigint_to_256bits(b), expected_bits); +} + +#[test] +fn test_biguint_to_f() { + // Test that the sum of 2 random `BigUint`s matches the sum of 2 field elements + use num_bigint::RandomBits; + use rand::{thread_rng, Rng}; + let mut rng = thread_rng(); + + let a: BigUint = rng.sample(RandomBits::new(253)); + let b: BigUint = rng.sample(RandomBits::new(253)); + let c = a.clone() + b.clone(); + + let a_f = biguint_to_f(&a); + let b_f = biguint_to_f(&b); + let c_f = a_f + b_f; + + assert_eq!(biguint_to_f(&c), c_f); +} + +#[test] +fn test_f_to_bigint() { + // Test that the sum of 2 random `F`s matches the expected sum + use rand::{thread_rng, Rng}; + let mut rng = thread_rng(); + + let a = rng.gen::(); + let b = rng.gen::(); + + let res = f_to_bigint(&(F::from_u128(a) + F::from_u128(b))); + let expected: BigUint = BigUint::from(a) + BigUint::from(b); + + assert_eq!(res, expected); +} + +#[test] +fn test_bits_to_limbs() { + use std::str::FromStr; + + let bits: [bool; 256] = [ + vec![false; 63], + vec![true], + vec![false; 63], + vec![true], + vec![false; 63], + vec![true], + vec![false; 63], + vec![true], + ] + .concat() + .try_into() + .unwrap(); + let res = bits_to_limbs(bits); + let expected = [ + BigUint::from_str("6277101735386680763835789423207666416102355444464034512896").unwrap(), + BigUint::from_str("340282366920938463463374607431768211456").unwrap(), + BigUint::from_str("18446744073709551616").unwrap(), + BigUint::from_str("1").unwrap(), + ]; + assert_eq!(res, expected); +} + +#[test] +fn test_deltas_to_matrices() { + use super::CHUNK_SIZE; + + // all deltas except the penultimate one are 1. The penultimate delta is 2. + let deltas = [ + vec![Delta::from(1u8); CHUNK_SIZE - 2], + vec![BigInt::from(2u8)], + vec![BigInt::from(1u8)], + ] + .concat(); + + let (deltas_as_rows, deltas_as_columns) = deltas_to_matrices(&deltas, 253); + let dar_concat = deltas_as_rows.concat(); + let dac_concat = deltas_as_columns.concat(); + + // both matrices must contain equal amount of elements + assert_eq!(dar_concat.len(), dac_concat.len()); + + // 3 extra padding deltas were added 14 times + assert_eq!(dar_concat.len(), deltas.len() + 14 * 3); + + // the penultimate element in the last row should be 2 + let row = deltas_as_rows[deltas_as_rows.len() - 1]; + assert_eq!(row[row.len() - 2], F::from(2)); + + // the last element in the penultimate column should be 2 + let col = deltas_as_columns[deltas_as_columns.len() - 2]; + assert_eq!(col[col.len() - 1], F::from(2)); +} diff --git a/authdecode/src/backend/halo2/verifier.rs b/authdecode/src/backend/halo2/verifier.rs new file mode 100644 index 0000000000..83c0ca8fde --- /dev/null +++ b/authdecode/src/backend/halo2/verifier.rs @@ -0,0 +1,129 @@ +use super::{utils::deltas_to_matrices, CHUNK_SIZE, USEFUL_BITS}; +use crate::{ + backend::halo2::utils::biguint_to_f, + verifier::{backend::Backend, error::VerifierError, verifier::VerificationInput}, + Proof, +}; +use std::time::Instant; + +use ff::{FromUniformBytes, WithSmallOrderMulGroup}; +use halo2_proofs::{ + halo2curves::bn256::{Bn256, Fr as F}, + plonk::{verify_proof as verify_plonk_proof, VerifyingKey}, + poly::{ + commitment::{CommitmentScheme, Verifier as CommitmentVerifier}, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG}, + multiopen::VerifierGWC, + strategy::AccumulatorStrategy, + }, + VerificationStrategy, + }, + transcript::{Blake2bRead, Challenge255, EncodedChallenge, TranscriptReadBuffer}, +}; + +/// halo2's native [halo2::VerifyingKey] can't be used without params, so we wrap +/// them in one struct. +#[derive(Clone)] +pub struct VK { + pub key: VerifyingKey< as CommitmentScheme>::Curve>, + pub params: ParamsKZG, +} + +/// Implements the Verifier in the authdecode protocol. +pub struct Verifier { + verification_key: VK, +} +impl Verifier { + pub fn new(vk: VK) -> Self { + Self { + verification_key: vk, + } + } + + fn useful_bits(&self) -> usize { + USEFUL_BITS + } +} + +impl Backend for Verifier { + fn verify( + &self, + inputs: Vec, + proofs: Vec, + ) -> Result<(), VerifierError> { + // TODO: implement a better proving strategy. + // For now we just assume that one proof proves one chunk. + assert!(inputs.len() == proofs.len()); + + let params = &self.verification_key.params; + let vk = &self.verification_key.key; + + for (input, proof) in inputs.iter().zip(proofs) { + // convert deltas into a matrix which halo2 expects + let (_, deltas_as_columns) = deltas_to_matrices(&input.deltas, self.useful_bits()); + + let mut all_inputs: Vec<&[F]> = + deltas_as_columns.iter().map(|v| v.as_slice()).collect(); + + // add another column with public inputs + let tmp = &[ + biguint_to_f(&input.plaintext_hash), + biguint_to_f(&input.encoding_sum_hash), + biguint_to_f(&input.zero_sum), + ]; + all_inputs.push(tmp); + + let now = Instant::now(); + verify_proof::< + KZGCommitmentScheme, + VerifierGWC<'_, Bn256>, + _, + Blake2bRead<_, _, Challenge255<_>>, + AccumulatorStrategy<_>, + >(params, vk, &proof, &[all_inputs.as_slice()])?; + println!("Proof verified in [{:?}]", now.elapsed()); + } + + Ok(()) + } + + fn chunk_size(&self) -> usize { + CHUNK_SIZE + } +} + +fn verify_proof< + 'a, + 'params, + Scheme: CommitmentScheme, + V: CommitmentVerifier<'params, Scheme>, + E: EncodedChallenge, + T: TranscriptReadBuffer<&'a [u8], Scheme::Curve, E>, + Strategy: VerificationStrategy<'params, Scheme, V, Output = Strategy>, +>( + params_verifier: &'params Scheme::ParamsVerifier, + vk: &VerifyingKey, + proof: &'a [u8], + instances: &[&[&[F]]], +) -> Result<(), VerifierError> +where + Scheme::Scalar: Ord + WithSmallOrderMulGroup<3> + FromUniformBytes<64>, +{ + let mut transcript = T::init(proof); + + let strategy = Strategy::new(params_verifier); + let strategy = verify_plonk_proof(params_verifier, vk, strategy, instances, &mut transcript); + + if strategy.is_err() { + return Err(VerifierError::VerificationFailed); + } + + let str = strategy.unwrap(); + + if !str.finalize() { + return Err(VerifierError::VerificationFailed); + } + + Ok(()) +} diff --git a/authdecode/src/backend/mock/circuit.rs b/authdecode/src/backend/mock/circuit.rs new file mode 100644 index 0000000000..0c07ada110 --- /dev/null +++ b/authdecode/src/backend/mock/circuit.rs @@ -0,0 +1,50 @@ +use crate::{backend::mock::prover::hash, utils::boolvec_to_u8vec, Delta}; +use num::{bigint::ToBigInt, BigInt, BigUint}; + +/// Checks in the clear that the given inputs satisfy all constraints of the AuthDecode circuit. +pub fn is_circuit_satisfied( + plaintext_hash: BigUint, + encoding_sum_hash: BigUint, + zero_sum: BigUint, + deltas: Vec, + plaintext: Vec, + plaintext_salt: BigUint, + encoding_sum_salt: BigUint, +) -> bool { + assert!(plaintext.len() == deltas.len()); + // Compute dot product of plaintext and deltas. + let dot_product = plaintext + .iter() + .zip(deltas.iter()) + .fold(BigInt::from(0u128), |acc, x| { + let bit = if *(x.0) { + BigInt::from(1u8) + } else { + BigInt::from(0u8) + }; + let delta = x.1; + acc + bit * delta + }); + + // Compute encoding sum, add salt, hash it and compare to the expected hash. + // (Unwraps are safe since the encoding sum is non-negative by definition). + let encoding_sum = (zero_sum.to_bigint().unwrap() + dot_product) + .to_biguint() + .unwrap(); + let mut encoding_sum = encoding_sum.to_bytes_be(); + encoding_sum.extend(encoding_sum_salt.to_bytes_be()); + let digest = BigUint::from_bytes_be(&hash(&encoding_sum)); + if digest != encoding_sum_hash { + return false; + } + + // Add salt to plaintext, hash it and compare to the expected hash. + let mut plaintext = boolvec_to_u8vec(&plaintext); + plaintext.extend(&plaintext_salt.to_bytes_be()); + let digest = BigUint::from_bytes_be(&hash(&plaintext)); + if digest != plaintext_hash { + return false; + } + + true +} diff --git a/authdecode/src/backend/mock/mod.rs b/authdecode/src/backend/mock/mod.rs new file mode 100644 index 0000000000..6fd7505b69 --- /dev/null +++ b/authdecode/src/backend/mock/mod.rs @@ -0,0 +1,75 @@ +use num::BigUint; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +pub mod circuit; +pub mod prover; +pub mod verifier; +pub use prover::MockProverBackend; +pub use verifier::MockVerifierBackend; + +/// Chunk size in bits. +pub const CHUNK_SIZE: usize = 300 * 8; + +/// A mock proof. +/// +/// Normally, the prover proves in zk the knowledge of private inputs which satisfy the circuit's +/// constraints. Here the private inputs are simply revealed without zk. +#[derive(Serialize, Deserialize)] +pub struct MockProof { + plaintext: Vec, + #[serde( + serialize_with = "biguint_serialize", + deserialize_with = "biguint_deserialize" + )] + plaintext_salt: BigUint, + #[serde( + serialize_with = "biguint_serialize", + deserialize_with = "biguint_deserialize" + )] + encoding_sum_salt: BigUint, +} + +impl MockProof { + /// Creates a new mock proof. + pub fn new(plaintext: Vec, plaintext_salt: BigUint, encoding_sum_salt: BigUint) -> Self { + Self { + plaintext, + plaintext_salt, + encoding_sum_salt, + } + } + + /// Serializes `self` into bytes. + pub fn to_bytes(&self) -> Vec { + bincode::serialize(self).unwrap() + } + + /// Deserializes `self` from bytes + pub fn from_bytes(bytes: Vec) -> Self { + bincode::deserialize(&bytes).unwrap() + } +} + +fn biguint_serialize(biguint: &BigUint, serializer: S) -> Result +where + S: Serializer, +{ + serializer.serialize_bytes(&biguint.to_bytes_be()) +} + +fn biguint_deserialize<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let bytes: Vec = Vec::deserialize(deserializer)?; + Ok(BigUint::from_bytes_be(&bytes)) +} + +#[cfg(test)] +pub(crate) mod tests { + use super::{MockProverBackend, MockVerifierBackend}; + + pub fn backend_pair() -> (MockProverBackend, MockVerifierBackend) { + (MockProverBackend::new(), MockVerifierBackend::new()) + } +} diff --git a/authdecode/src/backend/mock/prover.rs b/authdecode/src/backend/mock/prover.rs new file mode 100644 index 0000000000..0862624a34 --- /dev/null +++ b/authdecode/src/backend/mock/prover.rs @@ -0,0 +1,79 @@ +use crate::{ + backend::mock::{MockProof, CHUNK_SIZE}, + prover::{backend::Backend as ProverBackend, error::ProverError}, + utils::boolvec_to_u8vec, + Proof, ProofInput, +}; +use num::BigUint; +use rand::{thread_rng, Rng}; + +/// A mock prover backend. +pub struct MockProverBackend {} + +impl MockProverBackend { + pub fn new() -> Self { + Self {} + } +} + +impl ProverBackend for MockProverBackend { + fn commit_plaintext(&self, plaintext: Vec) -> Result<(BigUint, BigUint), ProverError> { + if plaintext.len() > self.chunk_size() { + // TODO proper error + return Err(ProverError::InternalError); + } + // Generate random salt and add it to the plaintext. + let mut rng = thread_rng(); + let salt: u128 = rng.gen(); + let salt = salt.to_be_bytes(); + let salt_as_biguint = BigUint::from_bytes_be(&salt); + + let mut plaintext = boolvec_to_u8vec(&plaintext); + plaintext.extend(salt); + let plaintext_hash = BigUint::from_bytes_be(&hash(&plaintext)); + + Ok((plaintext_hash, salt_as_biguint)) + } + + fn commit_encoding_sum( + &self, + encoding_sum: BigUint, + ) -> Result<(BigUint, BigUint), ProverError> { + // Generate random salt + let mut rng = thread_rng(); + let salt: u128 = rng.gen(); + let salt = salt.to_be_bytes(); + let salt_as_biguint = BigUint::from_bytes_be(&salt); + + let mut enc_sum = encoding_sum.to_bytes_be(); + enc_sum.extend(salt); + let enc_sum_hash = BigUint::from_bytes_be(&hash(&enc_sum)); + + Ok((enc_sum_hash, salt_as_biguint)) + } + + fn chunk_size(&self) -> usize { + CHUNK_SIZE + } + + fn prove(&self, input: Vec) -> Result, ProverError> { + // Use the default strategy of one proof for one chunk. + Ok(input + .iter() + .map(|input| { + MockProof::new( + input.plaintext.clone(), + input.plaintext_salt.clone(), + input.encoding_sum_salt.clone(), + ) + .to_bytes() + }) + .collect::>()) + } +} + +pub fn hash(bytes: &[u8]) -> [u8; 32] { + let mut hasher = blake3::Hasher::new(); + hasher.update(bytes); + hasher.finalize().into() +} diff --git a/authdecode/src/backend/mock/verifier.rs b/authdecode/src/backend/mock/verifier.rs new file mode 100644 index 0000000000..bcd0537589 --- /dev/null +++ b/authdecode/src/backend/mock/verifier.rs @@ -0,0 +1,47 @@ +use crate::{ + backend::mock::CHUNK_SIZE, + verifier::{backend::Backend, error::VerifierError, verifier::VerificationInput}, + Proof, +}; + +use super::{circuit::is_circuit_satisfied, MockProof}; + +/// A mock verifier backend. +pub struct MockVerifierBackend {} + +impl MockVerifierBackend { + pub fn new() -> Self { + Self {} + } +} + +impl Backend for MockVerifierBackend { + fn verify( + &self, + inputs: Vec, + proofs: Vec, + ) -> Result<(), VerifierError> { + // Use the default strategy of one proof for one chunk. + assert!(proofs.len() == inputs.len()); + for (proof, input) in proofs.iter().zip(inputs) { + let proof = MockProof::from_bytes(proof.to_vec()); + if !is_circuit_satisfied( + input.plaintext_hash, + input.encoding_sum_hash, + input.zero_sum, + input.deltas, + proof.plaintext, + proof.plaintext_salt, + proof.encoding_sum_salt, + ) { + return Err(VerifierError::VerificationFailed); + }; + } + + Ok(()) + } + + fn chunk_size(&self) -> usize { + CHUNK_SIZE + } +} diff --git a/authdecode/src/backend/mod.rs b/authdecode/src/backend/mod.rs new file mode 100644 index 0000000000..4aa6c463d1 --- /dev/null +++ b/authdecode/src/backend/mod.rs @@ -0,0 +1,2 @@ +pub mod halo2; +pub mod mock; diff --git a/authdecode/src/encodings.rs b/authdecode/src/encodings.rs new file mode 100644 index 0000000000..1c08a8e0ec --- /dev/null +++ b/authdecode/src/encodings.rs @@ -0,0 +1,305 @@ +use mpz_core::utils::blake3; +use num::{traits::ToBytes, BigInt, BigUint}; +use std::slice::Chunks; + +/// Statistical security parameter. +pub const SSP: usize = 40; + +/// The state of the encoding. +#[derive(PartialEq, Clone)] +pub enum EncodingState { + /// The original unmodified state. + Original, + /// The state where the correlation between this encoding and its complementary encoding + /// was removed. + Uncorrelated, + /// The state after the encoding was made uncorrelated and truncated. + Converted, +} + +/// An encoding of a value of a bit, i.e. it encodes either the 0 or the 1 value. +#[derive(Clone, PartialEq)] +pub struct Encoding { + value: BigUint, + state: EncodingState, +} +impl Encoding { + pub fn new(value: BigUint) -> Self { + Self { + value, + state: EncodingState::Original, + } + } + + /// Converts the encoding into a `UncorrelatedAndTruncated` state. + pub fn convert(&self, bit: bool) -> Self { + let uncorrelated = self.break_correlation(bit); + uncorrelated.truncate() + } + + /// Breaks the correlation which this encoding has with its complementary encoding. + /// Returns an uncorrelated encoding. + /// + /// In half-gates garbling scheme, each pair of bit encodings is correlated by a global delta. + /// It is essential for the security of the AuthDecode protocol that this correlation is removed. + /// + /// # Panics + /// + /// Panics it the encoding is not in the `Original` state. + fn break_correlation(&self, bit: bool) -> Self { + assert!(self.state == EncodingState::Original); + + // Hash the encoding if it encodes bit 1, otherwise keep the encoding. + if bit { + let mut bytes = [0u8; 16]; + bytes.copy_from_slice(&blake3(&self.value.to_be_bytes())[0..16]); + Self { + value: BigUint::from_bytes_be(&bytes), + state: EncodingState::Uncorrelated, + } + } else { + Self { + value: self.value.clone(), + state: EncodingState::Uncorrelated, + } + } + } + + /// Truncates the encoding to SSP most significant bits. + /// + /// Truncation is an optimization. Using encodings of bitlength > SSP is also acceptable. + /// + /// Note: this implementation assumes that the MSBs are private. This is in line with + /// most garbled circuits implementations which designate the LSB as a public "pointer" bit. + /// # Panics + /// + /// Panics it the encoding is not in the `Uncorrelated` state. + fn truncate(self) -> Self { + assert!(self.state == EncodingState::Uncorrelated); + + let mut digits = self.value.to_radix_be(2); + // In an unlikely case when there are too few bits, prepend zero bits. + if digits.len() < SSP { + digits = [vec![0u8; SSP - digits.len()], digits].concat(); + } + Self { + // Safe to unwrap, since all digits are radix-2. + value: BigUint::from_radix_be(&digits[0..SSP], 2).unwrap(), + state: EncodingState::Converted, + } + } + + pub fn value(&self) -> BigUint { + self.value.clone() + } +} + +/// Active encodings. +#[derive(Clone, Default, PartialEq)] +pub struct ActiveEncodings(Vec); + +impl ActiveEncodings { + pub fn new(encodings: Vec) -> Self { + Self(encodings) + } + + /// Returns the number of active encodings. + pub fn len(&self) -> usize { + self.0.len() + } + + /// Returns an iterator over `chunk_size` elements at a time. + pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, Encoding> { + self.0.chunks(chunk_size) + } + + pub fn extend(&mut self, other: ActiveEncodings) { + self.0.extend(other.0) + } + + /// Converts the encodings ... TODO + /// + /// Panics + pub fn convert(&self, bits: &[bool]) -> Self { + assert!(self.0.len() == bits.len()); + + let converted = self + .0 + .iter() + .zip(bits) + .map(|(enc, bit)| enc.convert(*bit)) + .collect::>(); + + Self(converted) + } + + /// Computes the arithmetic sum of the converted encodings. + /// + /// Panics if any of the encodings has not yet been converted. + pub fn compute_encoding_sum(&self) -> BigUint { + self.0.iter().fold(BigUint::from(0u128), |acc, x| { + assert!(x.state == EncodingState::Converted); + acc + x.value() + }) + } + + /// Returns an iterator ... TODO + pub fn into_chunks(self, chunk_size: usize) -> ActiveEncodingsChunks { + ActiveEncodingsChunks { + chunk_size, + encodings: self.0, + } + } +} + +pub struct ActiveEncodingsChunks { + chunk_size: usize, + encodings: Vec, +} + +impl Iterator for ActiveEncodingsChunks { + type Item = ActiveEncodings; + + fn next(&mut self) -> Option { + let remaining = self.encodings.len(); + if remaining == 0 { + return None; + } + + let encodings = if remaining <= self.chunk_size { + std::mem::take(&mut self.encodings) + } else { + // TODO use iter() with take + let new_after_split = self.encodings.split_off(self.chunk_size); + let split = self.encodings.clone(); + self.encodings = new_after_split; + split + }; + + Some(ActiveEncodings(encodings)) + } +} + +pub trait ToActiveEncodings { + fn to_active_encodings(&self) -> ActiveEncodings; +} + +/// Full encodings. +/// +/// Each pair of encodings encodes the 0 and 1 values of a bit. +#[derive(Clone, Default, PartialEq)] +pub struct FullEncodings(Vec<[Encoding; 2]>); +// TODO we need to add state here as well + +impl FullEncodings { + pub fn new(encodings: Vec<[Encoding; 2]>) -> Self { + Self(encodings) + } + + /// Returns the number of pairs of full encodings. + pub fn len(&self) -> usize { + self.0.len() + } + + /// Returns an iterator over `chunk_size` elements at a time. + pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, [Encoding; 2]> { + self.0.chunks(chunk_size) + } + + pub fn convert(self) -> Self { + // TODO add state and check that no prev. conversion happened + let converted = self + .0 + .iter() + .map(|pair| [pair[0].convert(false), pair[1].convert(true)]) + .collect::>(); + Self(converted) + // TODO modify in-place instead + } + + /// Returns an iterator ... TODO + pub fn into_chunks(self, chunk_size: usize) -> FullEncodingsChunks { + FullEncodingsChunks { + chunk_size, + encodings: self.0, + } + } + + /// Divides one slice into two at an index... TODO + /// + /// # Panics + /// + /// Panics if `mid > len`. + pub fn split_at(&self, mid: usize) -> (Self, Self) { + let (left, right) = self.0.split_at(mid); + (Self(left.to_vec()), Self(right.to_vec())) + } + + /// Encodes the provided bits. + /// + /// Panics TODO + pub fn encode(&self, bits: &[bool]) -> ActiveEncodings { + assert!(self.len() == bits.len()); + + let active = self + .0 + .iter() + .zip(bits.iter()) + .map(|(enc_pair, bit)| { + if *bit { + enc_pair[1].clone() + } else { + enc_pair[0].clone() + } + }) + .collect::>(); + + ActiveEncodings::new(active) + } + + /// Computes the arithmetic sum of the 0 bit encodings. + pub fn compute_zero_sum(&self) -> BigUint { + self.0 + .iter() + .fold(BigUint::from(0u8), |acc, x| acc + x[0].value()) + } + + /// Computes the arithmetic difference between a pair of encodings. + pub fn compute_deltas(&self) -> Vec { + self.0 + .iter() + .map(|pair| BigInt::from(pair[1].value()) - BigInt::from(pair[0].value())) + .collect() + } +} + +pub struct FullEncodingsChunks { + chunk_size: usize, + encodings: Vec<[Encoding; 2]>, +} + +impl Iterator for FullEncodingsChunks { + type Item = FullEncodings; + + fn next(&mut self) -> Option { + let remaining = self.encodings.len(); + if remaining == 0 { + return None; + } + + let encodings = if remaining <= self.chunk_size { + std::mem::take(&mut self.encodings) + } else { + let new_after_split = self.encodings.split_off(self.chunk_size); + let split = self.encodings.clone(); + self.encodings = new_after_split; + split + }; + + Some(FullEncodings(encodings)) + } +} + +pub trait ToFullEncodings { + fn to_full_encodings(&self) -> FullEncodings; +} diff --git a/authdecode/src/lib.rs b/authdecode/src/lib.rs new file mode 100644 index 0000000000..31644cf386 --- /dev/null +++ b/authdecode/src/lib.rs @@ -0,0 +1,146 @@ +//! Implementation of the AuthDecode protocol. +//! The protocol performs authenticated decoding of encodings in zero knowledge. +//! +//! The purpose of AuthDecode is to allow the GC evaluator to produce a zk-friendly +//! hash commitment to the GC output. Computing a zk-friendly hash directly inside +//! the GC is too expensive, hence the need for this protocol. +//! +//! The high-level overview of Authdecode is: +//! - The Verifier first reveals all of his secret inputs to the GC +//! - The Prover computes the expected output of GC ("the plaintext") in the +//! clear and commits to it +//! - The Verifier sends the GC but withholds the output decoding information +//! - The Prover evaluates the circuit and commits to his active output labels +//! - The Verifier reveals all the output labels of the circuit +//! - The Prover, without revealing the plaintext, creates a zero-knowledge proof +//! that the plaintext he committed to earlier is the true output of the GC evaluation +//! +//! Authdecode assumes a privacy-free setting for the garbler, i.e. the protocol +//! MUST ONLY start AFTER the garbler reveals all his secret GC inputs. +//! Specifically, in the context of the TLSNotary protocol, AuthDecode MUST ONLY +//! start AFTER the Notary (who is the garbler) has revealed all of his TLS session +//! keys' shares. +//! +//! See ../authdecode_diagram.pdf for a diagram of the whole protocol + +#[allow(unused_imports)] +pub mod backend; +pub mod encodings; +pub mod prover; +pub mod utils; +pub mod verifier; + +use crate::prover::prover::ProofInput; +use num::BigInt; + +/// An arithmetic difference between the arithmetic label "one" and the +/// arithmetic label "zero". +type Delta = BigInt; + +/// An opaque proof of the AuthDecode circuit. +type Proof = Vec; + +/// A zk proof with the corresponding public inputs. +struct ProofProperties { + proof: Proof, + public_inputs: ProofInput, +} + +#[cfg(test)] +mod tests { + use crate::{ + backend::{ + halo2, + halo2::{ + prover::Prover as Halo2ProverBackend, verifier::Verifier as Halo2VerififerBackend, + }, + mock::{MockProverBackend, MockVerifierBackend}, + }, + encodings::{ActiveEncodings, Encoding, FullEncodings, ToActiveEncodings}, + prover::{ + backend::Backend as ProverBackend, + error::ProverError, + prover::{ProofInput, Prover}, + InitData, ToInitData, + }, + utils::{choose, u8vec_to_boolvec}, + verifier::{backend::Backend as VerifierBackend, verifier::Verifier}, + Proof, + }; + + use hex::encode; + use num::BigUint; + use rand::{Rng, SeedableRng}; + use rand_chacha::ChaCha12Rng; + use rstest::rstest; + + /// The size of plaintext in bytes; + const PLAINTEXT_SIZE: usize = 1000; + + // A dummy encodings verifier. + struct DummyEncodingsVerifier {} + impl crate::prover::EncodingVerifier for DummyEncodingsVerifier { + fn init(&self, init_data: InitData) {} + + fn verify( + &self, + _encodings: &FullEncodings, + ) -> Result<(), crate::prover::EncodingVerifierError> { + Ok(()) + } + } + + #[rstest] + #[case(crate::backend::mock::tests::backend_pair())] + #[case(crate::backend::halo2::tests::backend_pair())] + // Test the protocol with different + fn test_authdecode( + #[case] pair: (impl ProverBackend + 'static, impl VerifierBackend + 'static), + ) { + let prover = Prover::new(Box::new(pair.0)); + let verifier = Verifier::new(Box::new(pair.1)); + + let mut rng = ChaCha12Rng::from_seed([0; 32]); + + // Generate random plaintext. + let plaintext: Vec = core::iter::repeat_with(|| rng.gen::()) + .take(PLAINTEXT_SIZE) + .collect(); + + // Generate Verifier's full encodings for each bit of the plaintext. + let full_encodings: Vec<[u128; 2]> = core::iter::repeat_with(|| rng.gen::<[u128; 2]>()) + .take(PLAINTEXT_SIZE * 8) + .collect(); + let full_encodings = full_encodings + .into_iter() + .map(|pair| { + [ + Encoding::new(BigUint::from(pair[0])), + Encoding::new(BigUint::from(pair[1])), + ] + }) + .collect::>(); + let full_encodings = FullEncodings::new(full_encodings); + + // Prover's active encodings. + let active_encodings = full_encodings.encode(&u8vec_to_boolvec(&plaintext)); + + let (prover, commitments) = prover.commit(vec![(plaintext, active_encodings)]).unwrap(); + + let (verifier, verification_data) = verifier + .receive_commitments( + commitments, + vec![full_encodings.clone()], + InitData::new(vec![1u8; 100]), + ) + .unwrap(); + + let prover = prover + .check(verification_data, DummyEncodingsVerifier {}) + .unwrap(); + + let (prover, proof_sets) = prover.prove().unwrap(); + + let verifier = verifier.verify(proof_sets).unwrap(); + } +} diff --git a/authdecode/src/prover/backend.rs b/authdecode/src/prover/backend.rs new file mode 100644 index 0000000000..c0eabb88f6 --- /dev/null +++ b/authdecode/src/prover/backend.rs @@ -0,0 +1,24 @@ +use crate::{prover::error::ProverError, Proof, ProofInput}; +use num::{BigInt, BigUint}; + +/// A trait for zk proof generation backend. +pub trait Backend { + /// Creates a commitment to the plaintext, padding the plaintext if necessary. + /// + /// Returns the commitment and the salt used to create the commitment. + fn commit_plaintext(&self, plaintext: Vec) -> Result<(BigUint, BigUint), ProverError>; + + /// Creates a commitment to the encoding sum. + /// + /// Returns the commitment and the salt used to create the commitment. + fn commit_encoding_sum(&self, encoding_sum: BigUint) + -> Result<(BigUint, BigUint), ProverError>; + + /// Given the `input` to the AuthDecode zk circuit, generates and returns `Proof`(s) + fn prove(&self, input: Vec) -> Result, ProverError>; + + /// How many bits of [Plaintext] can fit into one [Chunk]. This does not + /// include the [Salt] of the hash - which takes up the remaining least bits + /// of the last field element of each chunk. + fn chunk_size(&self) -> usize; +} diff --git a/authdecode/src/prover/error.rs b/authdecode/src/prover/error.rs new file mode 100644 index 0000000000..bd0dd6d0fb --- /dev/null +++ b/authdecode/src/prover/error.rs @@ -0,0 +1,37 @@ +#[derive(Debug, PartialEq, Eq, thiserror::Error)] +pub enum ProverError { + #[error("Provided empty plaintext")] + EmptyPlaintext, + #[error("todo")] + Mismatch, + #[error("Unable to put the salt of the hash into one field element")] + NoRoomForSalt, + #[error("Exceeded the maximum supported size of one chunk of plaintext")] + MaxChunkSizeExceeded, + #[error("Exceeded the maximum supported number of chunks of plaintext")] + MaxChunkCountExceeded, + #[error("Internal error: WrongFieldElementCount")] + WrongFieldElementCount, + #[error("Internal error: WrongPoseidonInput")] + WrongPoseidonInput, + #[error("Provided encrypted arithmetic labels of unexpected size. Expected {0}. Got {1}.")] + IncorrectEncryptedLabelSize(usize, usize), + #[error("Provided binary labels of unexpected size. Expected {0}. Got {1}.")] + IncorrectBinaryLabelSize(usize, usize), + #[error("Internal error: ErrorInPoseidonImplementation")] + ErrorInPoseidonImplementation, + #[error("Cannot proceed because the binary labels were not authenticated")] + BinaryLabelAuthenticationFailed, + #[error("Binary labels were not provided")] + BinaryLabelsNotProvided, + #[error("Failed to authenticate the arithmetic labels")] + ArithmeticLabelAuthenticationFailed, + #[error("The proof system returned an error when generating a proof")] + ProvingBackendError, + #[error("Internal error: WrongLastFieldElementBitCount")] + WrongLastFieldElementBitCount, + #[error("An internal error was encountered")] + InternalError, + #[error(transparent)] + EncodingsVerifierError(#[from] crate::prover::EncodingVerifierError), +} diff --git a/authdecode/src/prover/mod.rs b/authdecode/src/prover/mod.rs new file mode 100644 index 0000000000..f0a898c7a6 --- /dev/null +++ b/authdecode/src/prover/mod.rs @@ -0,0 +1,44 @@ +#[allow(unused_imports)] +pub mod backend; +pub mod error; +pub mod prover; +pub mod state; +use crate::encodings::{FullEncodings, ToFullEncodings}; + +pub struct VerificationData { + /// One set corresponds to one commitment. + pub full_encodings_sets: Vec, + pub init_data: InitData, +} + +pub struct InitData(Vec); +impl InitData { + pub fn new(init_data: Vec) -> Self { + Self(init_data) + } +} + +pub trait ToInitData { + fn to_init_data(&self) -> InitData; +} + +impl ToInitData for &Box { + fn to_init_data(&self) -> InitData { + self.as_ref().to_init_data() + } +} + +#[derive(Debug, PartialEq, Eq, thiserror::Error)] +pub enum EncodingVerifierError { + #[error("Verification failed")] + VerificationFailed, +} + +pub trait EncodingVerifier { + /// Initializes the verifier with initialization data and prepares it to verify + /// encodings. + fn init(&self, init_data: InitData); + + /// Verifies the authenticity of the provided full encodings. + fn verify(&self, encodings: &FullEncodings) -> Result<(), EncodingVerifierError>; +} diff --git a/authdecode/src/prover/prover.rs b/authdecode/src/prover/prover.rs new file mode 100644 index 0000000000..60373f2257 --- /dev/null +++ b/authdecode/src/prover/prover.rs @@ -0,0 +1,295 @@ +use crate::{ + encodings::{ActiveEncodings, FullEncodings}, + prover::{backend::Backend, error, error::ProverError, state}, + utils::u8vec_to_boolvec, + Delta, +}; + +use mpz_core::utils::blake3; +use num::{BigInt, BigUint}; + +use super::{EncodingVerifier, VerificationData}; +use crate::encodings::ToActiveEncodings; + +/// Details pertaining to an AuthDecode commitment to a single chunk of the plaintext. +#[derive(Clone)] +pub struct ChunkCommitmentDetails { + /// The chunk of plaintext to commit to. + pub plaintext: Vec, + pub plaintext_hash: BigUint, + pub plaintext_salt: BigUint, + + // The converted (i.e. uncorrelated and truncated) encodings to commit to. + pub encodings: ActiveEncodings, + pub encoding_sum: BigUint, + pub encoding_sum_hash: BigUint, + pub encoding_sum_salt: BigUint, +} + +/// Details pertaining to an AuthDecode commitment to plaintext of arbitrary length. +#[derive(Clone, Default)] +pub struct CommitmentDetails { + /// Details pertaining to commitments to each chunk of the plaintext. + pub chunk_commitments: Vec, +} + +impl CommitmentDetails { + /// Returns the plaintext of this commitment. + pub fn plaintext(&self) -> Vec { + self.chunk_commitments + .iter() + .map(|com| com.plaintext.clone()) + .flatten() + .collect() + } + + /// Returns the encodings of the plaintext of this commitment. + pub fn encodings(&self) -> ActiveEncodings { + let mut active = ActiveEncodings::default(); + for chunk in self.chunk_commitments.clone() { + active.extend(chunk.encodings); + } + active + } +} + +// Public and private inputs to the zk circuit +#[derive(Clone, Default)] +pub struct ProofInput { + // Public + pub plaintext_hash: BigUint, + pub encoding_sum_hash: BigUint, + /// The sum of encodings which encode the 0 bit. + pub zero_sum: BigUint, + pub deltas: Vec, + + // Private + pub plaintext: Vec, + pub plaintext_salt: BigUint, + pub encoding_sum_salt: BigUint, +} + +/// Prover in the AuthDecode protocol. +pub struct Prover { + backend: Box, + pub state: T, +} + +impl Prover { + /// Creates a new prover. + pub fn new(backend: Box) -> Self { + Prover { + backend, + state: state::Initialized {}, + } + } + + /// Creates a commitment to each (`plaintext`, `encodings` of the `plaintext` bits) tuple. + pub fn commit( + self, + plaintext_and_encodings: Vec<(Vec, ActiveEncodings)>, + ) -> Result<(Prover, Vec), ProverError> { + let commitments = plaintext_and_encodings + .iter() + .map(|(plaintext, encodings)| { + if plaintext.is_empty() { + return Err(ProverError::EmptyPlaintext); + } + + let plaintext = u8vec_to_boolvec(plaintext); + + if plaintext.len() != encodings.len() { + return Err(ProverError::Mismatch); + } + + // Chunk up the plaintext and encodings and commit to them. + let chunk_commitments = plaintext + .chunks(self.backend.chunk_size()) + .zip(encodings.clone().into_chunks(self.backend.chunk_size())) + .map(|(plaintext, encodings)| { + // Convert the encodings and compute their sum. + let encodings = encodings.convert(plaintext); + let sum = encodings.compute_encoding_sum(); + + let (plaintext_hash, plaintext_salt) = + self.backend.commit_plaintext(plaintext.to_vec())?; + + let (encoding_sum_hash, encoding_sum_salt) = + self.backend.commit_encoding_sum(sum.clone())?; + + Ok(ChunkCommitmentDetails { + plaintext: plaintext.to_vec(), + plaintext_hash, + plaintext_salt, + encodings, + encoding_sum: sum, + encoding_sum_hash, + encoding_sum_salt, + }) + }) + .collect::, ProverError>>()?; + Ok(CommitmentDetails { chunk_commitments }) + }) + .collect::, ProverError>>()?; + + Ok(( + Prover { + backend: self.backend, + state: state::Committed { + commitments: commitments.clone(), + }, + }, + // TODO we need to convert into a form which can be publicly revealed + commitments, + )) + } +} + +impl Prover { + /// Checks the authenticity of the peer's encodings used to create commitments. + /// + /// The verifier encodings must be in the same order in which the commitments were made. + pub fn check( + self, + // TODO: the verifier should only pass init data + verification_data: VerificationData, + verifier: impl EncodingVerifier, + ) -> Result, ProverError> { + if verification_data.full_encodings_sets.len() != self.state.commitments.len() { + // TODO proper error + return Err(ProverError::InternalError); + } + + verifier.init(verification_data.init_data); + + // Verify encodings of each commitment. + let verified_encodings = self + .state + .commitments + .iter() + .zip(verification_data.full_encodings_sets.iter()) + .map(|(com, full_encodings)| { + verifier.verify(full_encodings)?; + + if com.encodings().len() != full_encodings.len() { + // TODO proper error + return Err(ProverError::InternalError); + } + // Get active converted encodings. + let active_converted = full_encodings + .encode(&com.plaintext()) + .convert(&com.plaintext()); + + if active_converted != com.encodings() { + // TODO proper error + return Err(ProverError::InternalError); + } + Ok(full_encodings.clone().convert()) + }) + .collect::, ProverError>>()?; + + Ok(Prover { + backend: self.backend, + state: state::Checked { + commitments: self.state.commitments, + full_encodings_sets: verified_encodings, + }, + }) + } +} + +impl Prover { + /// Generates a zk proof(s). + pub fn prove(self) -> Result<(Prover, Vec>), ProverError> { + let commitments = self.state.commitments.clone(); + let mut sets = self.state.full_encodings_sets.clone(); + + // Collect proof inputs to prove each chunk of plaintext committed to. + let all_inputs = commitments + .iter() + .zip(sets.iter()) + .flat_map(|(com, set)| { + let mut set = set.clone(); + com.chunk_commitments + .iter() + .map(|com| { + let (split, remaining) = set.split_at(com.plaintext.len()); + set = remaining; + + ProofInput { + deltas: split.compute_deltas(), + plaintext_hash: com.plaintext_hash.clone(), + encoding_sum_hash: com.encoding_sum_hash.clone(), + zero_sum: split.compute_zero_sum(), + plaintext: com.plaintext.clone(), + plaintext_salt: com.plaintext_salt.clone(), + encoding_sum_salt: com.encoding_sum_salt.clone(), + } + }) + .collect::>() + }) + .collect::>(); + + let proofs = self.backend.prove(all_inputs)?; + + Ok(( + Prover { + backend: self.backend, + state: state::ProofCreated { + commitments, + proofs: proofs.clone(), + }, + }, + proofs, + )) + } +} + +#[cfg(test)] +mod tests { + use crate::{ + prover::{ + backend::Backend as ProverBackend, + error::ProverError, + prover::{ProofInput, Prover}, + }, + Proof, + }; + use num::BigUint; + + /// The prover who implements `Prove` with the correct values + struct CorrectTestProver {} + impl ProverBackend for CorrectTestProver { + fn prove(&self, _: Vec) -> Result, ProverError> { + Ok(vec![Proof::default()]) + } + + fn chunk_size(&self) -> usize { + 3670 + } + + fn commit_plaintext( + &self, + plaintext: Vec, + ) -> Result<(BigUint, BigUint), ProverError> { + Ok((BigUint::default(), BigUint::default())) + } + + fn commit_encoding_sum( + &self, + encoding_sum: BigUint, + ) -> Result<(BigUint, BigUint), ProverError> { + Ok((BigUint::default(), BigUint::default())) + } + } + + // #[test] + // /// Inputs empty plaintext and triggers [ProverError::EmptyPlaintext] + // fn test_error_empty_plaintext() { + // let lsp = Prover::new(Box::new(CorrectTestProver {})); + + // let pt: Vec = Vec::new(); + // let res = lsp.commit(vec![(pt, vec![1u128])]); + // assert_eq!(res.err().unwrap(), ProverError::EmptyPlaintext); + // } +} diff --git a/authdecode/src/prover/state.rs b/authdecode/src/prover/state.rs new file mode 100644 index 0000000000..45cdf62a73 --- /dev/null +++ b/authdecode/src/prover/state.rs @@ -0,0 +1,55 @@ +//! AuthDecode prover states. + +use crate::{ + encodings::FullEncodings, + prover::{ + backend::Backend, + prover::{ChunkCommitmentDetails, CommitmentDetails}, + }, + Proof, ProofProperties, +}; +use num::BigUint; + +/// Entry state +pub struct Initialized {} + +opaque_debug::implement!(Initialized); + +/// State after prover has made a commitment. +pub struct Committed { + pub commitments: Vec, +} + +opaque_debug::implement!(Committed); + +pub struct Checked { + pub commitments: Vec, + /// Authenticated encodings, uncorrelated and truncated. + /// Each set corresponds to each commitment + pub full_encodings_sets: Vec, +} + +opaque_debug::implement!(Checked); + +pub struct ProofCreated { + pub commitments: Vec, + pub proofs: Vec, +} + +opaque_debug::implement!(ProofCreated); + +#[allow(missing_docs)] +pub trait ProverState: sealed::Sealed {} + +impl ProverState for Initialized {} +impl ProverState for Committed {} +impl ProverState for Checked {} +impl ProverState for ProofCreated {} + +mod sealed { + pub trait Sealed {} + impl Sealed for super::Initialized {} + impl Sealed for super::Committed {} + impl Sealed for super::Checked {} + impl Sealed for super::ProofCreated {} +} diff --git a/authdecode/src/utils.rs b/authdecode/src/utils.rs new file mode 100644 index 0000000000..8c839ab699 --- /dev/null +++ b/authdecode/src/utils.rs @@ -0,0 +1,136 @@ +use crate::Delta; +use num::{BigInt, BigUint}; +use sha2::{Digest, Sha256}; + +/// Converts bits in MSB-first order into a `BigUint` +pub fn bits_to_biguint(bits: &[bool]) -> BigUint { + BigUint::from_bytes_be(&boolvec_to_u8vec(bits)) +} +#[test] +fn test_bits_to_bigint() { + let bits = [true, false]; + assert_eq!(bits_to_biguint(&bits), 2u8.into()); +} + +/// Converts bits in MSB-first order into BE bytes. The bits will be left-padded +/// with zeroes to the nearest multiple of 8. +pub fn boolvec_to_u8vec(bv: &[bool]) -> Vec { + let rem = bv.len() % 8; + let first_byte_bitsize = if rem == 0 { 8 } else { rem }; + let offset = if rem == 0 { 0 } else { 1 }; + let mut v = vec![0u8; bv.len() / 8 + offset]; + // implicitely left-pad the first byte with zeroes + for (i, b) in bv[0..first_byte_bitsize].iter().enumerate() { + v[i / 8] |= (*b as u8) << (first_byte_bitsize - 1 - i); + } + for (i, b) in bv[first_byte_bitsize..].iter().enumerate() { + v[1 + i / 8] |= (*b as u8) << (7 - (i % 8)); + } + v +} + +/// Unzips a slice of pairs, returning items corresponding to choice +pub fn choose(items: &[[T; 2]], choice: &[bool]) -> Vec { + assert!(items.len() == choice.len(), "arrays are different length"); + items + .iter() + .zip(choice) + .map(|(items, choice)| items[*choice as usize].clone()) + .collect() +} + +#[test] +fn test_boolvec_to_u8vec() { + let bits = [true, false]; + assert_eq!(boolvec_to_u8vec(&bits), [2]); + + let bits = [true, false, false, false, false, false, false, true, true]; + assert_eq!(boolvec_to_u8vec(&bits), [1, 3]); +} + +/// Converts BE bytes into bits in MSB-first order, left-padding with zeroes +/// to the nearest multiple of 8. +pub fn u8vec_to_boolvec(v: &[u8]) -> Vec { + let mut bv = Vec::with_capacity(v.len() * 8); + for byte in v.iter() { + for i in 0..8 { + bv.push(((byte >> (7 - i)) & 1) != 0); + } + } + bv +} +#[test] +fn test_u8vec_to_boolvec() { + let bytes = [1]; + assert_eq!( + u8vec_to_boolvec(&bytes), + [false, false, false, false, false, false, false, true] + ); + + let bytes = [255, 2]; + assert_eq!( + u8vec_to_boolvec(&bytes), + [ + true, true, true, true, true, true, true, true, false, false, false, false, false, + false, true, false + ] + ); + + // convert to bits and back to bytes + let bignum: BigUint = 3898219876643u128.into(); + let bits = u8vec_to_boolvec(&bignum.to_bytes_be()); + let bytes = boolvec_to_u8vec(&bits); + assert_eq!(bignum, BigUint::from_bytes_be(&bytes)); +} + +/// Returns sha256 hash digest +pub fn sha256(data: &[u8]) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update(data); + hasher.finalize().into() +} + +/// Returns the sum of all zero labels and deltas for each label pair. +pub fn compute_zero_sum_and_deltas( + arithmetic_label_pairs: &[[BigUint; 2]], +) -> (BigUint, Vec) { + let mut deltas: Vec = Vec::with_capacity(arithmetic_label_pairs.len()); + let mut zero_sum: BigUint = 0u8.into(); + for label_pair in arithmetic_label_pairs { + // calculate the sum of all zero labels + zero_sum += label_pair[0].clone(); + // put deltas from into one vec + deltas.push(BigInt::from(label_pair[1].clone()) - BigInt::from(label_pair[0].clone())); + } + (zero_sum, deltas) +} + +#[test] +/// Tests compute_zero_sum_and_deltas() +fn test_compute_zero_sum_and_deltas() { + let labels: [[BigUint; 2]; 2] = [[1u8.into(), 2u8.into()], [3u8.into(), 4u8.into()]]; + let (z, d) = compute_zero_sum_and_deltas(&labels); + + assert_eq!(z, 4u8.into()); + assert_eq!(d, [1u8.into(), 1u8.into()]); +} + +/// Make sure that the `BigUint`s bitsize is not larger than `bitsize` +pub fn sanitize_biguint(input: &BigUint, bitsize: usize) -> Result<(), String> { + if (input.bits() as usize) > bitsize { + Err("error".to_string()) + } else { + Ok(()) + } +} +#[test] +/// Tests sanitize_biguint() +fn test_sanitize_biguint() { + let good = BigUint::from(2u8).pow(253) - BigUint::from(1u8); + let res = sanitize_biguint(&good, 253); + assert!(res.is_ok()); + + let bad = BigUint::from(2u8).pow(253); + let res = sanitize_biguint(&bad, 253); + assert!(res.is_err()); +} diff --git a/authdecode/src/verifier/backend.rs b/authdecode/src/verifier/backend.rs new file mode 100644 index 0000000000..03ea7ab322 --- /dev/null +++ b/authdecode/src/verifier/backend.rs @@ -0,0 +1,20 @@ +use crate::{ + verifier::{error::VerifierError, verifier::VerificationInput}, + Proof, +}; + +/// A trait for zk proof verification backend. +pub trait Backend { + /// Verifies multiple inputs against multiple proofs. + /// Which inputs correspond to which proof is determined internally by the backend. + fn verify( + &self, + inputs: Vec, + proofs: Vec, + ) -> Result<(), VerifierError>; + + /// How many bits of [Plaintext] can fit into one [Chunk]. This does not + /// include the [Salt] of the hash - which takes up the remaining least bits + /// of the last field element of each chunk. + fn chunk_size(&self) -> usize; +} diff --git a/authdecode/src/verifier/error.rs b/authdecode/src/verifier/error.rs new file mode 100644 index 0000000000..34cef4d91e --- /dev/null +++ b/authdecode/src/verifier/error.rs @@ -0,0 +1,15 @@ +#[derive(Debug, PartialEq, Eq, thiserror::Error)] +pub enum VerifierError { + #[error("The prover has provided the wrong number of proofs. Expected {0}. Got {1}.")] + WrongProofCount(usize, usize), + #[error("The Prover has provided an input that is larger than expected")] + BigUintTooLarge, + #[error("The proving system returned an error when verifying a proof")] + VerifyingBackendError, + #[error("Proof verification failed")] + VerificationFailed, + #[error("An internal error was encountered")] + InternalError, + #[error("An custom error was encountered {0}")] + CustomError(String), +} diff --git a/authdecode/src/verifier/mod.rs b/authdecode/src/verifier/mod.rs new file mode 100644 index 0000000000..fcf53c03bd --- /dev/null +++ b/authdecode/src/verifier/mod.rs @@ -0,0 +1,5 @@ +#[allow(unused_imports)] +pub mod backend; +pub mod error; +pub mod state; +pub mod verifier; diff --git a/authdecode/src/verifier/state.rs b/authdecode/src/verifier/state.rs new file mode 100644 index 0000000000..8fc9dc1fa8 --- /dev/null +++ b/authdecode/src/verifier/state.rs @@ -0,0 +1,44 @@ +//! AuthDecode verifier states. + +use crate::{ + encodings::FullEncodings, + prover::{prover::CommitmentDetails, state::ProofCreated}, + verifier::backend::Backend, + Proof, ProofProperties, +}; +use num::BigUint; + +/// Entry state +pub struct Initialized {} + +opaque_debug::implement!(Initialized); + +/// State after verifier received prover's commitment. +pub struct CommitmentReceived { + pub commitments: Vec, + pub full_encodings_sets: Vec, +} + +opaque_debug::implement!(CommitmentReceived); + +pub struct VerifiedSuccessfully { + // TODO this should be just Poseidon hashes + // with the corresponding ranges and direction + // each hash of a chunk should have its own metadata + pub commitments: Vec, +} +opaque_debug::implement!(VerifiedSuccessfully); + +#[allow(missing_docs)] +pub trait VerifierState: sealed::Sealed {} + +impl VerifierState for Initialized {} +impl VerifierState for CommitmentReceived {} +impl VerifierState for VerifiedSuccessfully {} + +mod sealed { + pub trait Sealed {} + impl Sealed for super::Initialized {} + impl Sealed for super::CommitmentReceived {} + impl Sealed for super::VerifiedSuccessfully {} +} diff --git a/authdecode/src/verifier/verifier.rs b/authdecode/src/verifier/verifier.rs new file mode 100644 index 0000000000..599a205118 --- /dev/null +++ b/authdecode/src/verifier/verifier.rs @@ -0,0 +1,179 @@ +use crate::{ + encodings::FullEncodings, + prover::{prover::CommitmentDetails, InitData, VerificationData}, + verifier::{backend::Backend, error::VerifierError, state}, + Delta, Proof, +}; + +use crate::prover::ToInitData; +use mpz_core::utils::blake3; +use num::{BigInt, BigUint}; +use std::ops::Shr; + +/// Public inputs and a zk proof that needs to be verified. +#[derive(Default, Clone)] +pub struct VerificationInput { + pub plaintext_hash: BigUint, + pub encoding_sum_hash: BigUint, + pub zero_sum: BigUint, + pub deltas: Vec, +} + +/// Verifier in the AuthDecode protocol. +pub struct Verifier { + backend: Box, + state: T, +} + +impl Verifier { + /// Creates a new verifier. + pub fn new(backend: Box) -> Self { + Verifier { + backend, + state: state::Initialized {}, + } + } + + // TODO CommitmentDetails must be converted into their public form before sending + // + /// Receives the commitments and returns the data needed by the prover to check the authenticity + /// of the encodings. + pub fn receive_commitments( + self, + commitments: Vec, + // Full encodings for each commitment. + full_encodings_sets: Vec, + // initialization data to be sent to the prover to initialize the encoding verifier + init_data: InitData, + ) -> Result<(Verifier, VerificationData), VerifierError> { + if commitments.len() != full_encodings_sets.len() { + // TODO proper error, count mismatch + return Err(VerifierError::InternalError); + } + + Ok(( + Verifier { + backend: self.backend, + state: state::CommitmentReceived { + commitments, + full_encodings_sets: full_encodings_sets.clone(), + }, + }, + VerificationData { + // TODO passing encodings is unnecessary + full_encodings_sets, + init_data, + }, + )) + + // TODO return GC/OT randomness to the Prover + } +} + +impl Verifier { + /// Verifies proofs corresponding to the commitments received earlier. + /// The ordering of `proofs` and `self.state.encoding_pairs_sets` must match. + pub fn verify( + self, + // Zk proofs. Their ordering corresponds to the ordering of the commitments. + proof_sets: Vec, + ) -> Result, VerifierError> { + // Get encodings for each chunk + let chunk_encodings = self + .state + .full_encodings_sets + .iter() + .map(|set| set.clone().into_chunks(self.backend.chunk_size())) + .flatten() + .collect::>(); + + // Get commitments for each chunk + let chunk_commitments = self + .state + .commitments + .iter() + .map(|c| c.chunk_commitments.clone()) + .flatten() + .collect::>(); + + if chunk_commitments.len() != chunk_encodings.len() { + // TODO proper error, count mismatch + return Err(VerifierError::CustomError( + "if chunk_com.len() != chunk_data.len() {".to_string(), + )); + } + + // Compute public inputs for each chunk of plaintext + let public_inputs = chunk_commitments + .iter() + .zip(chunk_encodings) + .map(|(com, enc)| { + // convert encodings + let enc = enc.convert(); + self.create_verification_input( + enc.compute_deltas(), + enc.compute_zero_sum(), + com.plaintext_hash.clone(), + com.encoding_sum_hash.clone(), + ) + }) + .collect::>(); + + // For now the halo2 backend only knows how to verify one chunk against one proof, + // Commenting the line below and instead verifying the chunks one by one. + // self.backend.verify(public_inputs, proof_sets)?; + assert!(public_inputs.len() == proof_sets.len()); + self.backend.verify(public_inputs, proof_sets)?; + + Ok(Verifier { + backend: self.backend, + state: state::VerifiedSuccessfully { + commitments: self.state.commitments, + }, + }) + } + + /// Construct public inputs for the zk circuit for each [Chunk]. + fn create_verification_input( + &self, + mut deltas: Vec, + zero_sum: BigUint, + pt_hash: BigUint, + enc_hash: BigUint, + ) -> VerificationInput { + VerificationInput { + plaintext_hash: pt_hash, + encoding_sum_hash: enc_hash, + zero_sum, + deltas, + } + } +} + +#[cfg(test)] +mod tests { + use crate::{ + verifier::{ + backend::Backend, + verifier::{VerificationInput, VerifierError}, + }, + Proof, + }; + use num::BigUint; + + /// The verifier who implements `Verify` with the correct values + struct CorrectTestVerifier {} + impl Backend for CorrectTestVerifier { + fn verify( + &self, + inputs: Vec, + proofs: Vec, + ) -> Result<(), VerifierError> { + Ok(()) + } + + fn chunk_size(&self) -> usize { + 3670 + } + } +}