From 889e8f71bbd59d79341b7c571660f0634db3b357 Mon Sep 17 00:00:00 2001 From: CPerezz Date: Mon, 18 Dec 2023 09:44:15 +0100 Subject: [PATCH] remove: Delete the `gadgets` folder and stop support As was proposed in https://github.com/privacy-scaling-explorations/halo2/pull/169#issuecomment-1855682764 and we've been considering for some time already, it makes not much sense to keep maintaining the `halo2-gadgets` repo as no-one is using it and, at the same time it is time-consuming to maintain. For this reason, is getting removed. --- Cargo.toml | 1 - halo2_gadgets/CHANGELOG.md | 121 - halo2_gadgets/Cargo.toml | 73 - halo2_gadgets/README.md | 25 - halo2_gadgets/benches/poseidon.rs | 238 - halo2_gadgets/benches/primitives.rs | 68 - halo2_gadgets/benches/sha256.rs | 181 - halo2_gadgets/katex-header.html | 15 - .../proptest-regressions/constants/util.txt | 7 - halo2_gadgets/src/ecc.rs | 920 - halo2_gadgets/src/ecc/chip.rs | 614 - halo2_gadgets/src/ecc/chip/add.rs | 457 - halo2_gadgets/src/ecc/chip/add_incomplete.rs | 195 - halo2_gadgets/src/ecc/chip/constants.rs | 277 - halo2_gadgets/src/ecc/chip/mul.rs | 586 - halo2_gadgets/src/ecc/chip/mul/complete.rs | 196 - halo2_gadgets/src/ecc/chip/mul/incomplete.rs | 373 - halo2_gadgets/src/ecc/chip/mul/overflow.rs | 208 - halo2_gadgets/src/ecc/chip/mul_fixed.rs | 498 - .../src/ecc/chip/mul_fixed/base_field_elem.rs | 528 - .../src/ecc/chip/mul_fixed/full_width.rs | 316 - halo2_gadgets/src/ecc/chip/mul_fixed/short.rs | 669 - halo2_gadgets/src/ecc/chip/witness_point.rs | 174 - halo2_gadgets/src/lib.rs | 32 - halo2_gadgets/src/poseidon.rs | 297 - halo2_gadgets/src/poseidon/pow5.rs | 887 - halo2_gadgets/src/poseidon/primitives.rs | 408 - halo2_gadgets/src/poseidon/primitives/fp.rs | 1431 -- halo2_gadgets/src/poseidon/primitives/fq.rs | 1431 -- .../src/poseidon/primitives/grain.rs | 196 - halo2_gadgets/src/poseidon/primitives/mds.rs | 124 - .../src/poseidon/primitives/p128pow5t3.rs | 319 - .../src/poseidon/primitives/test_vectors.rs | 1261 -- halo2_gadgets/src/sha256.rs | 166 - halo2_gadgets/src/sha256/table16.rs | 517 - .../src/sha256/table16/compression.rs | 1007 -- .../table16/compression/compression_gates.rs | 442 - .../table16/compression/compression_util.rs | 991 -- .../table16/compression/subregion_digest.rs | 102 - .../table16/compression/subregion_initial.rs | 157 - .../table16/compression/subregion_main.rs | 127 - halo2_gadgets/src/sha256/table16/gates.rs | 125 - .../src/sha256/table16/message_schedule.rs | 457 - .../message_schedule/schedule_gates.rs | 394 - .../table16/message_schedule/schedule_util.rs | 181 - .../table16/message_schedule/subregion1.rs | 223 - .../table16/message_schedule/subregion2.rs | 487 - .../table16/message_schedule/subregion3.rs | 320 - .../src/sha256/table16/spread_table.rs | 448 - halo2_gadgets/src/sha256/table16/util.rs | 117 - halo2_gadgets/src/sinsemilla.rs | 754 - halo2_gadgets/src/sinsemilla/chip.rs | 327 - .../src/sinsemilla/chip/generator_table.rs | 98 - .../src/sinsemilla/chip/hash_to_point.rs | 414 - halo2_gadgets/src/sinsemilla/merkle.rs | 400 - halo2_gadgets/src/sinsemilla/merkle/chip.rs | 529 - halo2_gadgets/src/sinsemilla/message.rs | 68 - halo2_gadgets/src/sinsemilla/primitives.rs | 308 - .../src/sinsemilla/primitives/addition.rs | 73 - .../src/sinsemilla/primitives/sinsemilla_s.rs | 14344 ---------------- halo2_gadgets/src/utilities.rs | 497 - halo2_gadgets/src/utilities/cond_swap.rs | 296 - .../src/utilities/decompose_running_sum.rs | 390 - .../src/utilities/lookup_range_check.rs | 658 - 64 files changed, 38543 deletions(-) delete mode 100644 halo2_gadgets/CHANGELOG.md delete mode 100644 halo2_gadgets/Cargo.toml delete mode 100644 halo2_gadgets/README.md delete mode 100644 halo2_gadgets/benches/poseidon.rs delete mode 100644 halo2_gadgets/benches/primitives.rs delete mode 100644 halo2_gadgets/benches/sha256.rs delete mode 100644 halo2_gadgets/katex-header.html delete mode 100644 halo2_gadgets/proptest-regressions/constants/util.txt delete mode 100644 halo2_gadgets/src/ecc.rs delete mode 100644 halo2_gadgets/src/ecc/chip.rs delete mode 100644 halo2_gadgets/src/ecc/chip/add.rs delete mode 100644 halo2_gadgets/src/ecc/chip/add_incomplete.rs delete mode 100644 halo2_gadgets/src/ecc/chip/constants.rs delete mode 100644 halo2_gadgets/src/ecc/chip/mul.rs delete mode 100644 halo2_gadgets/src/ecc/chip/mul/complete.rs delete mode 100644 halo2_gadgets/src/ecc/chip/mul/incomplete.rs delete mode 100644 halo2_gadgets/src/ecc/chip/mul/overflow.rs delete mode 100644 halo2_gadgets/src/ecc/chip/mul_fixed.rs delete mode 100644 halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs delete mode 100644 halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs delete mode 100644 halo2_gadgets/src/ecc/chip/mul_fixed/short.rs delete mode 100644 halo2_gadgets/src/ecc/chip/witness_point.rs delete mode 100644 halo2_gadgets/src/lib.rs delete mode 100644 halo2_gadgets/src/poseidon.rs delete mode 100644 halo2_gadgets/src/poseidon/pow5.rs delete mode 100644 halo2_gadgets/src/poseidon/primitives.rs delete mode 100644 halo2_gadgets/src/poseidon/primitives/fp.rs delete mode 100644 halo2_gadgets/src/poseidon/primitives/fq.rs delete mode 100644 halo2_gadgets/src/poseidon/primitives/grain.rs delete mode 100644 halo2_gadgets/src/poseidon/primitives/mds.rs delete mode 100644 halo2_gadgets/src/poseidon/primitives/p128pow5t3.rs delete mode 100644 halo2_gadgets/src/poseidon/primitives/test_vectors.rs delete mode 100644 halo2_gadgets/src/sha256.rs delete mode 100644 halo2_gadgets/src/sha256/table16.rs delete mode 100644 halo2_gadgets/src/sha256/table16/compression.rs delete mode 100644 halo2_gadgets/src/sha256/table16/compression/compression_gates.rs delete mode 100644 halo2_gadgets/src/sha256/table16/compression/compression_util.rs delete mode 100644 halo2_gadgets/src/sha256/table16/compression/subregion_digest.rs delete mode 100644 halo2_gadgets/src/sha256/table16/compression/subregion_initial.rs delete mode 100644 halo2_gadgets/src/sha256/table16/compression/subregion_main.rs delete mode 100644 halo2_gadgets/src/sha256/table16/gates.rs delete mode 100644 halo2_gadgets/src/sha256/table16/message_schedule.rs delete mode 100644 halo2_gadgets/src/sha256/table16/message_schedule/schedule_gates.rs delete mode 100644 halo2_gadgets/src/sha256/table16/message_schedule/schedule_util.rs delete mode 100644 halo2_gadgets/src/sha256/table16/message_schedule/subregion1.rs delete mode 100644 halo2_gadgets/src/sha256/table16/message_schedule/subregion2.rs delete mode 100644 halo2_gadgets/src/sha256/table16/message_schedule/subregion3.rs delete mode 100644 halo2_gadgets/src/sha256/table16/spread_table.rs delete mode 100644 halo2_gadgets/src/sha256/table16/util.rs delete mode 100644 halo2_gadgets/src/sinsemilla.rs delete mode 100644 halo2_gadgets/src/sinsemilla/chip.rs delete mode 100644 halo2_gadgets/src/sinsemilla/chip/generator_table.rs delete mode 100644 halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs delete mode 100644 halo2_gadgets/src/sinsemilla/merkle.rs delete mode 100644 halo2_gadgets/src/sinsemilla/merkle/chip.rs delete mode 100644 halo2_gadgets/src/sinsemilla/message.rs delete mode 100644 halo2_gadgets/src/sinsemilla/primitives.rs delete mode 100644 halo2_gadgets/src/sinsemilla/primitives/addition.rs delete mode 100644 halo2_gadgets/src/sinsemilla/primitives/sinsemilla_s.rs delete mode 100644 halo2_gadgets/src/utilities.rs delete mode 100644 halo2_gadgets/src/utilities/cond_swap.rs delete mode 100644 halo2_gadgets/src/utilities/decompose_running_sum.rs delete mode 100644 halo2_gadgets/src/utilities/lookup_range_check.rs diff --git a/Cargo.toml b/Cargo.toml index b7878ae843..b44700ec43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,5 @@ [workspace] members = [ "halo2", - "halo2_gadgets", "halo2_proofs", ] diff --git a/halo2_gadgets/CHANGELOG.md b/halo2_gadgets/CHANGELOG.md deleted file mode 100644 index 41019f9cea..0000000000 --- a/halo2_gadgets/CHANGELOG.md +++ /dev/null @@ -1,121 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to Rust's notion of -[Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [Unreleased] - -## [0.2.0] - 2022-06-23 -### Added -- `halo2_gadgets::utilities::RangeConstrained>::bitrange_of` - -### Changed -All APIs that represented witnessed values as `Option` now represent them as -`halo2_proofs::circuit::Value`. The core API changes are listed below. - -- Migrated to `halo2_proofs 0.2.0`. -- The following APIs now take `Value<_>` instead of `Option<_>`: - - `halo2_gadgets::ecc`: - - `EccInstructions::{witness_point, witness_point_non_id}` - - `EccInstructions::{witness_scalar_var, witness_scalar_fixed}` - - `ScalarVar::new` - - `ScalarFixed::new` - - `NonIdentityPoint::new` - - `Point::new` - - `halo2_gadgets::sinsemilla`: - - `SinsemillaInstructions::witness_message_piece` - - `MessagePiece::{from_field_elem, from_subpieces}` - - `halo2_gadgets::sinsemilla::merkle`: - - `MerklePath::construct` - - `halo2_gadgets::utilities`: - - `UtilitiesInstructions::load_private` - - `RangeConstrained::witness_short` - - `halo2_gadgets::utilities::cond_swap`: - - `CondSwapInstructions::swap` - - `halo2_gadgets::utilities::decompose_running_sum`: - - `RunningSumConfig::witness_decompose` - - `halo2_gadgets::utilities::lookup_range_check`: - - `LookupRangeCheckConfig::{witness_check, witness_short_check}` -- The following APIs now return `Value<_>` instead of `Option<_>`: - - `halo2_gadgets::ecc::chip`: - - `EccPoint::{point, is_identity}` - - `NonIdentityEccPoint::point` - - `halo2_gadgets::utilities`: - - `FieldValue::value` - - `Var::value` - - `RangeConstrained::value` -- `halo2_gadgets::sha256::BlockWord` is now a newtype wrapper around - `Value` instead of `Option`. - -### Removed -- `halo2_gadgets::utilities::RangeConstrained>::bitrange_of` - -## [0.1.0] - 2022-05-10 -### Added -- `halo2_gadgets::utilities`: - - `FieldValue` trait. - - `RangeConstrained` newtype wrapper. -- `halo2_gadgets::ecc`: - - `EccInstructions::witness_scalar_var` API to witness a full-width scalar - used in variable-base scalar multiplication. - - `EccInstructions::witness_scalar_fixed`, to witness a full-width scalar - used in fixed-base scalar multiplication. - - `EccInstructions::scalar_fixed_from_signed_short`, to construct a signed - short scalar used in fixed-base scalar multiplication from its magnitude and - sign. - - `BaseFitsInScalarInstructions` trait that can be implemented for a curve - whose base field fits into its scalar field. This provides a method - `scalar_var_from_base` that converts a base field element that exists as - a variable in the circuit, into a scalar to be used in variable-base - scalar multiplication. - - `ScalarFixed::new` - - `ScalarFixedShort::new` - - `ScalarVar::new` and `ScalarVar::from_base` gadget APIs. -- `halo2_gadgets::ecc::chip`: - - `ScalarVar` enum with `BaseFieldElem` and `FullWidth` variants. `FullWidth` - is unimplemented for `halo2_gadgets v0.1.0`. -- `halo2_gadgets::poseidon`: - - `primitives` (moved from `halo2_gadgets::primitives::poseidon`) -- `halo2_gadgets::sinsemilla`: - - `primitives` (moved from `halo2_gadgets::primitives::sinsemilla`) - - `MessagePiece::from_subpieces` - -### Changed -- `halo2_gadgets::ecc`: - - `EccInstructions::ScalarVar` is now treated as a full-width scalar, instead - of being restricted to a base field element. - - `EccInstructions::mul` now takes a `Self::ScalarVar` as argument, instead - of assuming that the scalar fits in a base field element `Self::Var`. - - `EccInstructions::mul_fixed` now takes a `Self::ScalarFixed` as argument, - instead of requiring that the chip always witness a new scalar. - - `EccInstructions::mul_fixed_short` now takes a `Self::ScalarFixedShort` as - argument, instead of the magnitude and sign directly. - - `FixedPoint::mul` now takes `ScalarFixed` instead of `Option`. - - `FixedPointShort::mul` now takes `ScalarFixedShort` instead of - `(EccChip::Var, EccChip::Var)`. -- `halo2_gadgets::ecc::chip`: - - `FixedPoint::u` now returns `Vec<[::Repr; H]>` - instead of `Vec<[[u8; 32]; H]>`. - - `ScalarKind` has been renamed to `FixedScalarKind`. -- `halo2_gadgets::sinsemilla`: - - `CommitDomain::{commit, short_commit}` now take the trapdoor `r` as an - `ecc::ScalarFixed` instead of `Option`. - - `merkle::MerklePath` can now be constructed with more or fewer than two - `MerkleChip`s. - -### Removed -- `halo2_gadgets::primitives` (use `halo2_gadgets::poseidon::primitives` or - `halo2_gadgets::sinsemilla::primitives` instead). - -## [0.1.0-beta.3] - 2022-04-06 -### Changed -- Migrated to `halo2_proofs 0.1.0-beta.4`. - -## [0.1.0-beta.2] - 2022-03-22 -### Changed -- Migrated to `halo2_proofs 0.1.0-beta.3`. - -## [0.1.0-beta.1] - 2022-02-14 -Initial release! diff --git a/halo2_gadgets/Cargo.toml b/halo2_gadgets/Cargo.toml deleted file mode 100644 index 374efda83b..0000000000 --- a/halo2_gadgets/Cargo.toml +++ /dev/null @@ -1,73 +0,0 @@ -[package] -name = "halo2_gadgets" -version = "0.2.0" -authors = [ - "Sean Bowe ", - "Jack Grigg ", - "Daira Hopwood ", - "Ying Tong Lai ", - "Kris Nuttycombe ", -] -edition = "2021" -rust-version = "1.66.0" -description = "Reusable gadgets and chip implementations for Halo 2" -license = "MIT OR Apache-2.0" -repository = "https://github.com/zcash/halo2" -readme = "README.md" -categories = ["cryptography"] -keywords = ["halo", "proofs", "zcash", "zkp", "zkSNARKs"] - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs", "--html-in-header", "katex-header.html"] - -[dependencies] -arrayvec = "0.7.0" -bitvec = "1" -ff = { version = "0.13", features = ["bits"] } -group = "0.13" -halo2_proofs = { version = "0.2", path = "../halo2_proofs", default-features = false } -lazy_static = "1" -halo2curves = { version = "0.1.0" } -proptest = { version = "1.0.0", optional = true } -rand = "0.8" -subtle = "2.3" -uint = "0.9.2" - -# Developer tooling dependencies -plotters = { version = "0.3.0", default-features = false, optional = true } - -[dev-dependencies] -criterion = "0.3" -proptest = "1.0.0" - -[target.'cfg(unix)'.dev-dependencies] -pprof = { version = "0.8", features = ["criterion", "flamegraph"] } # MSRV 1.56 - -[lib] -bench = false - -[features] -test-dev-graph = [ - "halo2_proofs/dev-graph", - "plotters", - "plotters/bitmap_backend", - "plotters/bitmap_encoder", - "plotters/ttf", -] -circuit-params = ["halo2_proofs/circuit-params"] -test-dependencies = ["proptest"] -unstable = [] - -[[bench]] -name = "primitives" -harness = false - -[[bench]] -name = "poseidon" -harness = false - -[[bench]] -name = "sha256" -harness = false -required-features = ["unstable"] diff --git a/halo2_gadgets/README.md b/halo2_gadgets/README.md deleted file mode 100644 index 4ed744f81f..0000000000 --- a/halo2_gadgets/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# halo2_gadgets [![Crates.io](https://img.shields.io/crates/v/halo2_gadgets.svg)](https://crates.io/crates/halo2_gadgets) # - -Requires Rust 1.56.1+. - -## Documentation - -- [The Halo 2 Book](https://zcash.github.io/halo2/) -- [Crate documentation](https://docs.rs/halo2_gadgets) - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/halo2_gadgets/benches/poseidon.rs b/halo2_gadgets/benches/poseidon.rs deleted file mode 100644 index 4175318399..0000000000 --- a/halo2_gadgets/benches/poseidon.rs +++ /dev/null @@ -1,238 +0,0 @@ -use ff::Field; -use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - plonk::{ - create_proof, keygen_pk, keygen_vk, verify_proof, Advice, Circuit, Column, - ConstraintSystem, Error, Instance, - }, - poly::{ - commitment::ParamsProver, - ipa::{ - commitment::{IPACommitmentScheme, ParamsIPA}, - multiopen::ProverIPA, - strategy::SingleStrategy, - }, - VerificationStrategy, - }, - transcript::{ - Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, - }, -}; -use halo2curves::pasta::{pallas, vesta, EqAffine, Fp}; - -use halo2_gadgets::poseidon::{ - primitives::{self as poseidon, generate_constants, ConstantLength, Mds, Spec}, - Hash, Pow5Chip, Pow5Config, -}; -use std::convert::TryInto; -use std::marker::PhantomData; - -use criterion::{criterion_group, criterion_main, Criterion}; -use rand::rngs::OsRng; - -#[derive(Clone, Copy)] -struct HashCircuit -where - S: Spec + Clone + Copy, -{ - message: Value<[Fp; L]>, - _spec: PhantomData, -} - -#[derive(Debug, Clone)] -struct MyConfig { - input: [Column; L], - expected: Column, - poseidon_config: Pow5Config, -} - -impl Circuit - for HashCircuit -where - S: Spec + Copy + Clone, -{ - type Config = MyConfig; - type FloorPlanner = SimpleFloorPlanner; - #[cfg(feature = "circuit-params")] - type Params = (); - - fn without_witnesses(&self) -> Self { - Self { - message: Value::unknown(), - _spec: PhantomData, - } - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let state = (0..WIDTH).map(|_| meta.advice_column()).collect::>(); - let expected = meta.instance_column(); - meta.enable_equality(expected); - 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::>(); - - meta.enable_constant(rc_b[0]); - - Self::Config { - input: state[..RATE].try_into().unwrap(), - expected, - poseidon_config: Pow5Chip::configure::( - meta, - state.try_into().unwrap(), - partial_sbox, - rc_a.try_into().unwrap(), - rc_b.try_into().unwrap(), - ), - } - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let chip = Pow5Chip::construct(config.poseidon_config.clone()); - - let message = layouter.assign_region( - || "load message", - |mut region| { - let message_word = |i: usize| { - let value = self.message.map(|message_vals| message_vals[i]); - region.assign_advice( - || format!("load message_{}", i), - config.input[i], - 0, - || value, - ) - }; - - let message: Result, Error> = (0..L).map(message_word).collect(); - Ok(message?.try_into().unwrap()) - }, - )?; - - let hasher = Hash::<_, _, S, ConstantLength, WIDTH, RATE>::init( - chip, - layouter.namespace(|| "init"), - )?; - let output = hasher.hash(layouter.namespace(|| "hash"), message)?; - - layouter.constrain_instance(output.cell(), config.expected, 0) - } -} - -#[derive(Debug, Clone, Copy)] -struct MySpec; - -impl Spec for MySpec { - fn full_rounds() -> usize { - 8 - } - - fn partial_rounds() -> usize { - 56 - } - - fn sbox(val: Fp) -> Fp { - val.pow_vartime([5]) - } - - fn secure_mds() -> usize { - 0 - } - - fn constants() -> (Vec<[Fp; WIDTH]>, Mds, Mds) { - generate_constants::<_, Self, WIDTH, RATE>() - } -} - -const K: u32 = 7; - -fn bench_poseidon( - name: &str, - c: &mut Criterion, -) where - S: Spec + Copy + Clone, -{ - // Initialize the polynomial commitment parameters - let params: ParamsIPA = ParamsIPA::new(K); - - let empty_circuit = HashCircuit:: { - message: Value::unknown(), - _spec: PhantomData, - }; - - // Initialize the proving key - let vk = keygen_vk(¶ms, &empty_circuit).expect("keygen_vk should not fail"); - let pk = keygen_pk(¶ms, vk, &empty_circuit).expect("keygen_pk should not fail"); - - let prover_name = name.to_string() + "-prover"; - let verifier_name = name.to_string() + "-verifier"; - - let mut rng = OsRng; - let message: [Fp; L] = (0..L) - .map(|_| pallas::Base::random(rng)) - .collect::>() - .try_into() - .unwrap(); - let output = poseidon::Hash::<_, S, ConstantLength, WIDTH, RATE>::init().hash(message); - - let circuit = HashCircuit:: { - message: Value::known(message), - _spec: PhantomData, - }; - - c.bench_function(&prover_name, |b| { - // Create a proof - let mut transcript = Blake2bWrite::<_, EqAffine, Challenge255<_>>::init(vec![]); - b.iter(|| { - create_proof::, ProverIPA<_>, _, _, _, _>( - ¶ms, - &pk, - &[circuit], - &[&[&[output]]], - &mut rng, - &mut transcript, - ) - .expect("proof generation should not fail") - }) - }); - - // Create a proof - let mut transcript = Blake2bWrite::<_, EqAffine, Challenge255<_>>::init(vec![]); - create_proof::, ProverIPA<_>, _, _, _, _>( - ¶ms, - &pk, - &[circuit], - &[&[&[output]]], - &mut rng, - &mut transcript, - ) - .expect("proof generation should not fail"); - let proof = transcript.finalize(); - - c.bench_function(&verifier_name, |b| { - b.iter(|| { - let strategy = SingleStrategy::new(¶ms); - let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]); - assert!(verify_proof( - ¶ms, - pk.get_vk(), - strategy, - &[&[&[output]]], - &mut transcript - ) - .is_ok()); - }); - }); -} - -fn criterion_benchmark(c: &mut Criterion) { - bench_poseidon::, 3, 2, 2>("WIDTH = 3, RATE = 2", c); - bench_poseidon::, 9, 8, 8>("WIDTH = 9, RATE = 8", c); - bench_poseidon::, 12, 11, 11>("WIDTH = 12, RATE = 11", c); -} - -criterion_group!(benches, criterion_benchmark); -criterion_main!(benches); diff --git a/halo2_gadgets/benches/primitives.rs b/halo2_gadgets/benches/primitives.rs deleted file mode 100644 index 5397efce05..0000000000 --- a/halo2_gadgets/benches/primitives.rs +++ /dev/null @@ -1,68 +0,0 @@ -use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; -use ff::Field; -use halo2_gadgets::{ - poseidon::primitives::{self as poseidon, ConstantLength, P128Pow5T3}, - sinsemilla::primitives as sinsemilla, -}; - -use halo2curves::pasta::pallas; -#[cfg(unix)] -use pprof::criterion::{Output, PProfProfiler}; -use rand::{rngs::OsRng, Rng}; - -fn bench_primitives(c: &mut Criterion) { - let mut rng = OsRng; - - { - let mut group = c.benchmark_group("Poseidon"); - - let message = [pallas::Base::random(rng), pallas::Base::random(rng)]; - - group.bench_function("2-to-1", |b| { - b.iter(|| { - poseidon::Hash::<_, P128Pow5T3, ConstantLength<2>, 3, 2>::init().hash(message) - }) - }); - } - - { - let mut group = c.benchmark_group("Sinsemilla"); - - let hasher = sinsemilla::HashDomain::new("hasher"); - let committer = sinsemilla::CommitDomain::new("committer"); - let bits: Vec = (0..1086).map(|_| rng.gen()).collect(); - let r = pallas::Scalar::random(rng); - - // Benchmark the input sizes we use in Orchard: - // - 510 bits for Commit^ivk - // - 520 bits for MerkleCRH - // - 1086 bits for NoteCommit - for size in [510, 520, 1086] { - group.bench_function(BenchmarkId::new("hash-to-point", size), |b| { - b.iter(|| hasher.hash_to_point(bits[..size].iter().cloned())) - }); - - group.bench_function(BenchmarkId::new("hash", size), |b| { - b.iter(|| hasher.hash(bits[..size].iter().cloned())) - }); - - group.bench_function(BenchmarkId::new("commit", size), |b| { - b.iter(|| committer.commit(bits[..size].iter().cloned(), &r)) - }); - - group.bench_function(BenchmarkId::new("short-commit", size), |b| { - b.iter(|| committer.commit(bits[..size].iter().cloned(), &r)) - }); - } - } -} - -#[cfg(unix)] -criterion_group! { - name = benches; - config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); - targets = bench_primitives -} -#[cfg(not(unix))] -criterion_group!(benches, bench_primitives); -criterion_main!(benches); diff --git a/halo2_gadgets/benches/sha256.rs b/halo2_gadgets/benches/sha256.rs deleted file mode 100644 index 6a7e9b0bd9..0000000000 --- a/halo2_gadgets/benches/sha256.rs +++ /dev/null @@ -1,181 +0,0 @@ -use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - plonk::{create_proof, keygen_pk, keygen_vk, verify_proof, Circuit, ConstraintSystem, Error}, - poly::commitment::Params, - transcript::{Blake2bRead, Blake2bWrite, Challenge255}, -}; -use halo2curves::pasta::{pallas, EqAffine}; -use rand::rngs::OsRng; - -use std::{ - fs::{create_dir_all, File}, - io::{prelude::*, BufReader}, - path::Path, -}; - -use criterion::{criterion_group, criterion_main, Criterion}; - -use halo2_gadgets::sha256::{BlockWord, Sha256, Table16Chip, Table16Config, BLOCK_SIZE}; - -use halo2_proofs::{ - poly::{ - commitment::ParamsProver, - ipa::{ - commitment::{IPACommitmentScheme, ParamsIPA}, - multiopen::{ProverIPA, VerifierIPA}, - strategy::AccumulatorStrategy, - }, - }, - transcript::{TranscriptReadBuffer, TranscriptWriterBuffer}, -}; - -#[allow(dead_code)] -fn bench(name: &str, k: u32, c: &mut Criterion) { - #[derive(Default)] - struct MyCircuit {} - - impl Circuit for MyCircuit { - type Config = Table16Config; - type FloorPlanner = SimpleFloorPlanner; - #[cfg(feature = "circuit-params")] - type Params = (); - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - Table16Chip::configure(meta) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - Table16Chip::load(config.clone(), &mut layouter)?; - let table16_chip = Table16Chip::construct(config); - - // Test vector: "abc" - let test_input = [ - BlockWord(Value::known(0b01100001011000100110001110000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000011000)), - ]; - - // Create a message of length 31 blocks - let mut input = Vec::with_capacity(31 * BLOCK_SIZE); - for _ in 0..31 { - input.extend_from_slice(&test_input); - } - - Sha256::digest(table16_chip, layouter.namespace(|| "'abc' * 2"), &input)?; - - Ok(()) - } - } - - // Create parent directory for assets - create_dir_all("./benches/sha256_assets").expect("Failed to create sha256_assets directory"); - - // Initialize the polynomial commitment parameters - let params_path = Path::new("./benches/sha256_assets/sha256_params"); - if File::open(params_path).is_err() { - let params: ParamsIPA = ParamsIPA::new(k); - let mut buf = Vec::new(); - - params.write(&mut buf).expect("Failed to write params"); - let mut file = File::create(params_path).expect("Failed to create sha256_params"); - - file.write_all(&buf[..]) - .expect("Failed to write params to file"); - } - - let params_fs = File::open(params_path).expect("couldn't load sha256_params"); - let params: ParamsIPA = - ParamsIPA::read::<_>(&mut BufReader::new(params_fs)).expect("Failed to read params"); - - let empty_circuit: MyCircuit = MyCircuit {}; - - // Initialize the proving key - let vk = keygen_vk(¶ms, &empty_circuit).expect("keygen_vk should not fail"); - let pk = keygen_pk(¶ms, vk, &empty_circuit).expect("keygen_pk should not fail"); - - let circuit: MyCircuit = MyCircuit {}; - - // let prover_name = name.to_string() + "-prover"; - let verifier_name = name.to_string() + "-verifier"; - - // /// Benchmark proof creation - // c.bench_function(&prover_name, |b| { - // b.iter(|| { - // let mut transcript = Blake2bWrite::init(Fq::one()); - // create_proof(¶ms, &pk, &circuit, &[], &mut transcript) - // .expect("proof generation should not fail"); - // let proof: Vec = transcript.finalize(); - // }); - // }); - - // Create a proof - let proof_path = Path::new("./benches/sha256_assets/sha256_proof"); - if File::open(proof_path).is_err() { - let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); - create_proof::, ProverIPA<_>, _, _, _, _>( - ¶ms, - &pk, - &[circuit], - &[&[]], - OsRng, - &mut transcript, - ) - .expect("proof generation should not fail"); - let proof: Vec = transcript.finalize(); - let mut file = File::create(proof_path).expect("Failed to create sha256_proof"); - file.write_all(&proof[..]).expect("Failed to write proof"); - } - - let mut proof_fs = File::open(proof_path).expect("couldn't load sha256_proof"); - let mut proof = Vec::::new(); - proof_fs - .read_to_end(&mut proof) - .expect("Couldn't read proof"); - - c.bench_function(&verifier_name, |b| { - b.iter(|| { - use halo2_proofs::poly::VerificationStrategy; - let strategy = AccumulatorStrategy::new(¶ms); - let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]); - let strategy = verify_proof::, VerifierIPA<_>, _, _, _>( - ¶ms, - pk.get_vk(), - strategy, - &[&[]], - &mut transcript, - ) - .unwrap(); - assert!(strategy.finalize()); - }); - }); -} - -#[allow(dead_code)] -fn criterion_benchmark(c: &mut Criterion) { - bench("sha256", 17, c); - // bench("sha256", 20, c); -} - -criterion_group!(benches, criterion_benchmark); -criterion_main!(benches); diff --git a/halo2_gadgets/katex-header.html b/halo2_gadgets/katex-header.html deleted file mode 100644 index 98e85904fa..0000000000 --- a/halo2_gadgets/katex-header.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - \ No newline at end of file diff --git a/halo2_gadgets/proptest-regressions/constants/util.txt b/halo2_gadgets/proptest-regressions/constants/util.txt deleted file mode 100644 index 9e49b54616..0000000000 --- a/halo2_gadgets/proptest-regressions/constants/util.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Seeds for failure cases proptest has generated in the past. It is -# automatically read and these particular cases re-run before any -# novel cases are generated. -# -# It is recommended to check this file in to source control so that -# everyone who runs the test benefits from these saved cases. -cc 251d6e9f7ad2f5cd8679dec6b69aa9c879baae8742791b19669c136aef12deac # shrinks to scalar = 0x0000000000000000000000000000000000000000000000000000000000000000, window_num_bits = 6 diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs deleted file mode 100644 index 8d71db8580..0000000000 --- a/halo2_gadgets/src/ecc.rs +++ /dev/null @@ -1,920 +0,0 @@ -//! Elliptic curve operations. - -use std::fmt::Debug; - -use halo2_proofs::{ - arithmetic::CurveAffine, - circuit::{Chip, Layouter, Value}, - plonk::Error, -}; - -use crate::utilities::UtilitiesInstructions; - -pub mod chip; - -/// The set of circuit instructions required to use the ECC gadgets. -pub trait EccInstructions: - Chip + UtilitiesInstructions + Clone + Debug + Eq -{ - /// Variable representing a scalar used in variable-base scalar mul. - /// - /// This type is treated as a full-width scalar. However, if `Self` implements - /// [`BaseFitsInScalarInstructions`] then this may also be constructed from an element - /// of the base field. - type ScalarVar: Clone + Debug; - /// Variable representing a full-width element of the elliptic curve's - /// scalar field, to be used for fixed-base scalar mul. - type ScalarFixed: Clone + Debug; - /// Variable representing a signed short element of the elliptic curve's - /// scalar field, to be used for fixed-base scalar mul. - /// - /// A `ScalarFixedShort` must be in the range [-(2^64 - 1), 2^64 - 1]. - type ScalarFixedShort: Clone + Debug; - /// Variable representing an elliptic curve point. - type Point: From + Clone + Debug; - /// Variable representing a non-identity elliptic curve point. - type NonIdentityPoint: Clone + Debug; - /// Variable representing the affine short Weierstrass x-coordinate of an - /// elliptic curve point. - type X: Clone + Debug; - /// Enumeration of the set of fixed bases to be used in scalar mul. - /// TODO: When associated consts can be used as const generics, introduce - /// `Self::NUM_WINDOWS`, `Self::NUM_WINDOWS_BASE_FIELD`, `Self::NUM_WINDOWS_SHORT` - /// and use them to differentiate `FixedPoints` types. - type FixedPoints: FixedPoints; - - /// Constrains point `a` to be equal in value to point `b`. - fn constrain_equal( - &self, - layouter: &mut impl Layouter, - a: &Self::Point, - b: &Self::Point, - ) -> Result<(), Error>; - - /// Witnesses the given point as a private input to the circuit. - /// This allows the point to be the identity, mapped to (0, 0) in - /// affine coordinates. - fn witness_point( - &self, - layouter: &mut impl Layouter, - value: Value, - ) -> Result; - - /// Witnesses the given point as a private input to the circuit. - /// This returns an error if the point is the identity. - fn witness_point_non_id( - &self, - layouter: &mut impl Layouter, - value: Value, - ) -> Result; - - /// Witnesses a full-width scalar to be used in variable-base multiplication. - fn witness_scalar_var( - &self, - layouter: &mut impl Layouter, - value: Value, - ) -> Result; - - /// Witnesses a full-width scalar to be used in fixed-base multiplication. - fn witness_scalar_fixed( - &self, - layouter: &mut impl Layouter, - value: Value, - ) -> Result; - - /// Converts a magnitude and sign that exists as variables in the circuit into a - /// signed short scalar to be used in fixed-base scalar multiplication. - fn scalar_fixed_from_signed_short( - &self, - layouter: &mut impl Layouter, - magnitude_sign: (Self::Var, Self::Var), - ) -> Result; - - /// Extracts the x-coordinate of a point. - fn extract_p + Clone>(point: &Point) -> Self::X; - - /// Performs incomplete point addition, returning `a + b`. - /// - /// This returns an error in exceptional cases. - fn add_incomplete( - &self, - layouter: &mut impl Layouter, - a: &Self::NonIdentityPoint, - b: &Self::NonIdentityPoint, - ) -> Result; - - /// Performs complete point addition, returning `a + b`. - fn add + Clone, B: Into + Clone>( - &self, - layouter: &mut impl Layouter, - a: &A, - b: &B, - ) -> Result; - - /// Performs variable-base scalar multiplication, returning `[scalar] base`. - fn mul( - &self, - layouter: &mut impl Layouter, - scalar: &Self::ScalarVar, - base: &Self::NonIdentityPoint, - ) -> Result<(Self::Point, Self::ScalarVar), Error>; - - /// Performs fixed-base scalar multiplication using a full-width scalar, returning `[scalar] base`. - fn mul_fixed( - &self, - layouter: &mut impl Layouter, - scalar: &Self::ScalarFixed, - base: &>::FullScalar, - ) -> Result<(Self::Point, Self::ScalarFixed), Error>; - - /// Performs fixed-base scalar multiplication using a short signed scalar, returning - /// `[scalar] base`. - fn mul_fixed_short( - &self, - layouter: &mut impl Layouter, - scalar: &Self::ScalarFixedShort, - base: &>::ShortScalar, - ) -> Result<(Self::Point, Self::ScalarFixedShort), Error>; - - /// Performs fixed-base scalar multiplication using a base field element as the scalar. - /// In the current implementation, this base field element must be output from another - /// instruction. - fn mul_fixed_base_field_elem( - &self, - layouter: &mut impl Layouter, - base_field_elem: Self::Var, - base: &>::Base, - ) -> Result; -} - -/// Instructions that can be implemented for a curve whose base field fits into -/// its scalar field. -pub trait BaseFitsInScalarInstructions: EccInstructions { - /// Converts a base field element that exists as a variable in the circuit - /// into a scalar to be used in variable-base scalar multiplication. - fn scalar_var_from_base( - &self, - layouter: &mut impl Layouter, - base: &Self::Var, - ) -> Result; -} - -/// Defines the fixed points for a given instantiation of the ECC chip. -pub trait FixedPoints: Debug + Eq + Clone { - /// Fixed points that can be used with full-width scalar multiplication. - type FullScalar: Debug + Eq + Clone; - /// Fixed points that can be used with short scalar multiplication. - type ShortScalar: Debug + Eq + Clone; - /// Fixed points that can be multiplied by base field elements. - type Base: Debug + Eq + Clone; -} - -/// An integer representing an element of the scalar field for a specific elliptic curve. -#[derive(Debug)] -pub struct ScalarVar> { - chip: EccChip, - inner: EccChip::ScalarVar, -} - -impl> ScalarVar { - /// Witnesses the given full-width scalar. - /// - /// Depending on the `EccChip` implementation, this may either witness the scalar - /// immediately, or delay witnessing until its first use in [`NonIdentityPoint::mul`]. - pub fn new( - chip: EccChip, - mut layouter: impl Layouter, - value: Value, - ) -> Result { - let scalar = chip.witness_scalar_var(&mut layouter, value); - scalar.map(|inner| ScalarVar { chip, inner }) - } -} - -impl> ScalarVar { - /// Constructs a scalar from an existing base-field element. - pub fn from_base( - chip: EccChip, - mut layouter: impl Layouter, - base: &EccChip::Var, - ) -> Result { - let scalar = chip.scalar_var_from_base(&mut layouter, base); - scalar.map(|inner| ScalarVar { chip, inner }) - } -} - -/// An integer representing an element of the scalar field for a specific elliptic curve, -/// for [`FixedPoint`] scalar multiplication. -#[derive(Debug)] -pub struct ScalarFixed> { - chip: EccChip, - inner: EccChip::ScalarFixed, -} - -impl> ScalarFixed { - /// Witnesses the given full-width scalar. - /// - /// Depending on the `EccChip` implementation, this may either witness the scalar - /// immediately, or delay witnessing until its first use in [`FixedPoint::mul`]. - pub fn new( - chip: EccChip, - mut layouter: impl Layouter, - value: Value, - ) -> Result { - let scalar = chip.witness_scalar_fixed(&mut layouter, value); - scalar.map(|inner| ScalarFixed { chip, inner }) - } -} - -/// A signed short (64-bit) integer represented as an element of the scalar field for a -/// specific elliptic curve, to be used for [`FixedPointShort`] scalar multiplication. -#[derive(Debug)] -pub struct ScalarFixedShort> { - chip: EccChip, - inner: EccChip::ScalarFixedShort, -} - -impl> ScalarFixedShort { - /// Converts the given signed short scalar. - /// - /// `magnitude_sign` must be a tuple of two circuit-assigned values: - /// - An unsigned integer of at most 64 bits. - /// - A sign value that is either 1 or -1. - /// - /// Depending on the `EccChip` implementation, the scalar may either be constrained - /// immediately by this constructor, or lazily constrained when it is first used in - /// [`FixedPointShort::mul`]. - pub fn new( - chip: EccChip, - mut layouter: impl Layouter, - magnitude_sign: (EccChip::Var, EccChip::Var), - ) -> Result { - let scalar = chip.scalar_fixed_from_signed_short(&mut layouter, magnitude_sign); - scalar.map(|inner| ScalarFixedShort { chip, inner }) - } -} - -/// A point on a specific elliptic curve that is guaranteed to not be the identity. -#[derive(Copy, Clone, Debug)] -pub struct NonIdentityPoint> { - chip: EccChip, - inner: EccChip::NonIdentityPoint, -} - -impl> NonIdentityPoint { - /// Constructs a new point with the given value. - pub fn new( - chip: EccChip, - mut layouter: impl Layouter, - value: Value, - ) -> Result { - let point = chip.witness_point_non_id(&mut layouter, value); - point.map(|inner| NonIdentityPoint { chip, inner }) - } - - /// Constrains this point to be equal in value to another point. - pub fn constrain_equal> + Clone>( - &self, - mut layouter: impl Layouter, - other: &Other, - ) -> Result<(), Error> { - let other: Point = (other.clone()).into(); - self.chip.constrain_equal( - &mut layouter, - &Point::::from(self.clone()).inner, - &other.inner, - ) - } - - /// Returns the inner point. - pub fn inner(&self) -> &EccChip::NonIdentityPoint { - &self.inner - } - - /// Extracts the x-coordinate of a point. - pub fn extract_p(&self) -> X { - X::from_inner(self.chip.clone(), EccChip::extract_p(&self.inner)) - } - - /// Wraps the given point (obtained directly from an instruction) in a gadget. - pub fn from_inner(chip: EccChip, inner: EccChip::NonIdentityPoint) -> Self { - NonIdentityPoint { chip, inner } - } - - /// Returns `self + other` using complete addition. - pub fn add> + Clone>( - &self, - mut layouter: impl Layouter, - other: &Other, - ) -> Result, Error> { - let other: Point = (other.clone()).into(); - - assert_eq!(self.chip, other.chip); - self.chip - .add(&mut layouter, &self.inner, &other.inner) - .map(|inner| Point { - chip: self.chip.clone(), - inner, - }) - } - - /// Returns `self + other` using incomplete addition. - /// The arguments are type-constrained not to be the identity point, - /// and since exceptional cases return an Error, the result also cannot - /// be the identity point. - pub fn add_incomplete( - &self, - mut layouter: impl Layouter, - other: &Self, - ) -> Result { - assert_eq!(self.chip, other.chip); - self.chip - .add_incomplete(&mut layouter, &self.inner, &other.inner) - .map(|inner| NonIdentityPoint { - chip: self.chip.clone(), - inner, - }) - } - - /// Returns `[by] self`. - #[allow(clippy::type_complexity)] - pub fn mul( - &self, - mut layouter: impl Layouter, - by: ScalarVar, - ) -> Result<(Point, ScalarVar), Error> { - assert_eq!(self.chip, by.chip); - self.chip - .mul(&mut layouter, &by.inner, &self.inner.clone()) - .map(|(point, scalar)| { - ( - Point { - chip: self.chip.clone(), - inner: point, - }, - ScalarVar { - chip: self.chip.clone(), - inner: scalar, - }, - ) - }) - } -} - -impl + Clone + Debug + Eq> - From> for Point -{ - fn from(non_id_point: NonIdentityPoint) -> Self { - Self { - chip: non_id_point.chip, - inner: non_id_point.inner.into(), - } - } -} - -/// A point on a specific elliptic curve. -#[derive(Copy, Clone, Debug)] -pub struct Point + Clone + Debug + Eq> { - chip: EccChip, - inner: EccChip::Point, -} - -impl + Clone + Debug + Eq> Point { - /// Constructs a new point with the given value. - pub fn new( - chip: EccChip, - mut layouter: impl Layouter, - value: Value, - ) -> Result { - let point = chip.witness_point(&mut layouter, value); - point.map(|inner| Point { chip, inner }) - } - - /// Constrains this point to be equal in value to another point. - pub fn constrain_equal> + Clone>( - &self, - mut layouter: impl Layouter, - other: &Other, - ) -> Result<(), Error> { - let other: Point = (other.clone()).into(); - self.chip - .constrain_equal(&mut layouter, &self.inner, &other.inner) - } - - /// Returns the inner point. - pub fn inner(&self) -> &EccChip::Point { - &self.inner - } - - /// Extracts the x-coordinate of a point. - pub fn extract_p(&self) -> X { - X::from_inner(self.chip.clone(), EccChip::extract_p(&self.inner)) - } - - /// Wraps the given point (obtained directly from an instruction) in a gadget. - pub fn from_inner(chip: EccChip, inner: EccChip::Point) -> Self { - Point { chip, inner } - } - - /// Returns `self + other` using complete addition. - pub fn add> + Clone>( - &self, - mut layouter: impl Layouter, - other: &Other, - ) -> Result, Error> { - let other: Point = (other.clone()).into(); - - assert_eq!(self.chip, other.chip); - self.chip - .add(&mut layouter, &self.inner, &other.inner) - .map(|inner| Point { - chip: self.chip.clone(), - inner, - }) - } -} - -/// The affine short Weierstrass x-coordinate of a point on a specific elliptic curve. -#[derive(Debug)] -pub struct X> { - chip: EccChip, - inner: EccChip::X, -} - -impl> X { - /// Wraps the given x-coordinate (obtained directly from an instruction) in a gadget. - pub fn from_inner(chip: EccChip, inner: EccChip::X) -> Self { - X { chip, inner } - } - - /// Returns the inner x-coordinate. - pub fn inner(&self) -> &EccChip::X { - &self.inner - } -} - -/// Precomputed multiples of a fixed point, for full-width scalar multiplication. -/// -/// Fixing the curve point enables window tables to be baked into the circuit, making -/// scalar multiplication more efficient. These window tables are tuned to full-width -/// scalar multiplication. -#[derive(Clone, Debug)] -pub struct FixedPoint> { - chip: EccChip, - inner: >::FullScalar, -} - -/// Precomputed multiples of a fixed point, that can be multiplied by base-field elements. -/// -/// Fixing the curve point enables window tables to be baked into the circuit, making -/// scalar multiplication more efficient. These window tables are tuned to scalar -/// multiplication by base-field elements. -#[derive(Clone, Debug)] -pub struct FixedPointBaseField> { - chip: EccChip, - inner: >::Base, -} - -/// Precomputed multiples of a fixed point, for short signed scalar multiplication. -#[derive(Clone, Debug)] -pub struct FixedPointShort> { - chip: EccChip, - inner: >::ShortScalar, -} - -impl> FixedPoint { - #[allow(clippy::type_complexity)] - /// Returns `[by] self`. - pub fn mul( - &self, - mut layouter: impl Layouter, - by: ScalarFixed, - ) -> Result<(Point, ScalarFixed), Error> { - assert_eq!(self.chip, by.chip); - self.chip - .mul_fixed(&mut layouter, &by.inner, &self.inner) - .map(|(point, scalar)| { - ( - Point { - chip: self.chip.clone(), - inner: point, - }, - ScalarFixed { - chip: self.chip.clone(), - inner: scalar, - }, - ) - }) - } - - /// Wraps the given fixed base (obtained directly from an instruction) in a gadget. - pub fn from_inner( - chip: EccChip, - inner: >::FullScalar, - ) -> Self { - Self { chip, inner } - } -} - -impl> FixedPointBaseField { - #[allow(clippy::type_complexity)] - /// Returns `[by] self`. - pub fn mul( - &self, - mut layouter: impl Layouter, - by: EccChip::Var, - ) -> Result, Error> { - self.chip - .mul_fixed_base_field_elem(&mut layouter, by, &self.inner) - .map(|inner| Point { - chip: self.chip.clone(), - inner, - }) - } - - /// Wraps the given fixed base (obtained directly from an instruction) in a gadget. - pub fn from_inner( - chip: EccChip, - inner: >::Base, - ) -> Self { - Self { chip, inner } - } -} - -impl> FixedPointShort { - #[allow(clippy::type_complexity)] - /// Returns `[by] self`. - pub fn mul( - &self, - mut layouter: impl Layouter, - by: ScalarFixedShort, - ) -> Result<(Point, ScalarFixedShort), Error> { - assert_eq!(self.chip, by.chip); - self.chip - .mul_fixed_short(&mut layouter, &by.inner, &self.inner) - .map(|(point, scalar)| { - ( - Point { - chip: self.chip.clone(), - inner: point, - }, - ScalarFixedShort { - chip: self.chip.clone(), - inner: scalar, - }, - ) - }) - } - - /// Wraps the given fixed base (obtained directly from an instruction) in a gadget. - pub fn from_inner( - chip: EccChip, - inner: >::ShortScalar, - ) -> Self { - Self { chip, inner } - } -} - -#[cfg(test)] -pub(crate) mod tests { - use ff::PrimeField; - use group::{prime::PrimeCurveAffine, Curve, Group}; - - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use halo2curves::pasta::pallas; - use lazy_static::lazy_static; - - use super::{ - chip::{ - find_zs_and_us, BaseFieldElem, EccChip, EccConfig, FixedPoint, FullScalar, ShortScalar, - H, NUM_WINDOWS, NUM_WINDOWS_SHORT, - }, - FixedPoints, - }; - use crate::utilities::lookup_range_check::LookupRangeCheckConfig; - - #[derive(Debug, Eq, PartialEq, Clone)] - pub(crate) struct TestFixedBases; - #[derive(Debug, Eq, PartialEq, Clone)] - pub(crate) struct FullWidth(pallas::Affine, &'static [(u64, [pallas::Base; H])]); - #[derive(Debug, Eq, PartialEq, Clone)] - pub(crate) struct BaseField; - #[derive(Debug, Eq, PartialEq, Clone)] - pub(crate) struct Short; - - lazy_static! { - static ref BASE: pallas::Affine = pallas::Point::generator().to_affine(); - static ref ZS_AND_US: Vec<(u64, [pallas::Base; H])> = - find_zs_and_us(*BASE, NUM_WINDOWS).unwrap(); - static ref ZS_AND_US_SHORT: Vec<(u64, [pallas::Base; H])> = - find_zs_and_us(*BASE, NUM_WINDOWS_SHORT).unwrap(); - } - - impl FullWidth { - pub(crate) fn from_pallas_generator() -> Self { - FullWidth(*BASE, &ZS_AND_US) - } - - pub(crate) fn from_parts( - base: pallas::Affine, - zs_and_us: &'static [(u64, [pallas::Base; H])], - ) -> Self { - FullWidth(base, zs_and_us) - } - } - - impl FixedPoint for FullWidth { - type FixedScalarKind = FullScalar; - - fn generator(&self) -> pallas::Affine { - self.0 - } - - fn u(&self) -> Vec<[[u8; 32]; H]> { - self.1 - .iter() - .map(|(_, us)| { - [ - us[0].to_repr(), - us[1].to_repr(), - us[2].to_repr(), - us[3].to_repr(), - us[4].to_repr(), - us[5].to_repr(), - us[6].to_repr(), - us[7].to_repr(), - ] - }) - .collect() - } - - fn z(&self) -> Vec { - self.1.iter().map(|(z, _)| *z).collect() - } - } - - impl FixedPoint for BaseField { - type FixedScalarKind = BaseFieldElem; - - fn generator(&self) -> pallas::Affine { - *BASE - } - - fn u(&self) -> Vec<[[u8; 32]; H]> { - ZS_AND_US - .iter() - .map(|(_, us)| { - [ - us[0].to_repr(), - us[1].to_repr(), - us[2].to_repr(), - us[3].to_repr(), - us[4].to_repr(), - us[5].to_repr(), - us[6].to_repr(), - us[7].to_repr(), - ] - }) - .collect() - } - - fn z(&self) -> Vec { - ZS_AND_US.iter().map(|(z, _)| *z).collect() - } - } - - impl FixedPoint for Short { - type FixedScalarKind = ShortScalar; - - fn generator(&self) -> pallas::Affine { - *BASE - } - - fn u(&self) -> Vec<[[u8; 32]; H]> { - ZS_AND_US_SHORT - .iter() - .map(|(_, us)| { - [ - us[0].to_repr(), - us[1].to_repr(), - us[2].to_repr(), - us[3].to_repr(), - us[4].to_repr(), - us[5].to_repr(), - us[6].to_repr(), - us[7].to_repr(), - ] - }) - .collect() - } - - fn z(&self) -> Vec { - ZS_AND_US_SHORT.iter().map(|(z, _)| *z).collect() - } - } - - impl FixedPoints for TestFixedBases { - type FullScalar = FullWidth; - type ShortScalar = Short; - type Base = BaseField; - } - - struct MyCircuit { - test_errors: bool, - } - - #[allow(non_snake_case)] - impl Circuit for MyCircuit { - type Config = EccConfig; - type FloorPlanner = SimpleFloorPlanner; - #[cfg(feature = "circuit-params")] - type Params = (); - - fn without_witnesses(&self) -> Self { - MyCircuit { test_errors: false } - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let advices = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - let lookup_table = meta.lookup_table_column(); - let lagrange_coeffs = [ - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - ]; - // Shared fixed column for loading constants - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table); - EccChip::::configure(meta, advices, lagrange_coeffs, range_check) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let chip = EccChip::construct(config.clone()); - - // Load 10-bit lookup table. In the Action circuit, this will be - // provided by the Sinsemilla chip. - config.lookup_config.load(&mut layouter)?; - - // Generate a random non-identity point P - let p_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); // P - let p = super::NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "P"), - Value::known(p_val), - )?; - let p_neg = -p_val; - let p_neg = super::NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "-P"), - Value::known(p_neg), - )?; - - // Generate a random non-identity point Q - let q_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); // Q - let q = super::NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "Q"), - Value::known(q_val), - )?; - - // Make sure P and Q are not the same point. - assert_ne!(p_val, q_val); - - // Test that we can witness the identity as a point, but not as a non-identity point. - { - let _ = super::Point::new( - chip.clone(), - layouter.namespace(|| "identity"), - Value::known(pallas::Affine::identity()), - )?; - - super::NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "identity"), - Value::known(pallas::Affine::identity()), - ) - .expect_err("Trying to witness the identity should return an error"); - } - - // Test witness non-identity point - { - super::chip::witness_point::tests::test_witness_non_id( - chip.clone(), - layouter.namespace(|| "witness non-identity point"), - ) - } - - // Test complete addition - { - super::chip::add::tests::test_add( - chip.clone(), - layouter.namespace(|| "complete addition"), - p_val, - &p, - q_val, - &q, - &p_neg, - )?; - } - - // Test incomplete addition - { - super::chip::add_incomplete::tests::test_add_incomplete( - chip.clone(), - layouter.namespace(|| "incomplete addition"), - p_val, - &p, - q_val, - &q, - &p_neg, - self.test_errors, - )?; - } - - // Test variable-base scalar multiplication - { - super::chip::mul::tests::test_mul( - chip.clone(), - layouter.namespace(|| "variable-base scalar mul"), - &p, - p_val, - )?; - } - - // Test full-width fixed-base scalar multiplication - { - super::chip::mul_fixed::full_width::tests::test_mul_fixed( - chip.clone(), - layouter.namespace(|| "full-width fixed-base scalar mul"), - )?; - } - - // Test signed short fixed-base scalar multiplication - { - super::chip::mul_fixed::short::tests::test_mul_fixed_short( - chip.clone(), - layouter.namespace(|| "signed short fixed-base scalar mul"), - )?; - } - - // Test fixed-base scalar multiplication with a base field element - { - super::chip::mul_fixed::base_field_elem::tests::test_mul_fixed_base_field( - chip, - layouter.namespace(|| "fixed-base scalar mul with base field element"), - )?; - } - - Ok(()) - } - } - - #[test] - fn ecc_chip() { - let k = 13; - let circuit = MyCircuit { test_errors: true }; - let prover = MockProver::run(k, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())) - } - - #[cfg(feature = "test-dev-graph")] - #[test] - fn print_ecc_chip() { - use plotters::prelude::*; - - let root = BitMapBackend::new("ecc-chip-layout.png", (1024, 7680)).into_drawing_area(); - root.fill(&WHITE).unwrap(); - let root = root.titled("Ecc Chip Layout", ("sans-serif", 60)).unwrap(); - - let circuit = MyCircuit { test_errors: false }; - halo2_proofs::dev::CircuitLayout::default() - .render(13, &circuit, &root) - .unwrap(); - } -} diff --git a/halo2_gadgets/src/ecc/chip.rs b/halo2_gadgets/src/ecc/chip.rs deleted file mode 100644 index 466234e6b7..0000000000 --- a/halo2_gadgets/src/ecc/chip.rs +++ /dev/null @@ -1,614 +0,0 @@ -//! Chip implementations for the ECC gadgets. - -use super::{BaseFitsInScalarInstructions, EccInstructions, FixedPoints}; -use crate::{ - sinsemilla::primitives as sinsemilla, - utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, -}; -use arrayvec::ArrayVec; - -use ff::PrimeField; -use group::prime::PrimeCurveAffine; -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{Advice, Assigned, Column, ConstraintSystem, Error, Fixed}, -}; -use halo2curves::{pasta::pallas, CurveAffine}; - -use std::convert::TryInto; - -pub(super) mod add; -pub(super) mod add_incomplete; -pub mod constants; -pub(super) mod mul; -pub(super) mod mul_fixed; -pub(super) mod witness_point; - -pub use constants::*; - -// Exposed for Sinsemilla. -pub(crate) use mul::incomplete::DoubleAndAdd; - -/// A curve point represented in affine (x, y) coordinates, or the -/// identity represented as (0, 0). -/// Each coordinate is assigned to a cell. -#[derive(Clone, Debug)] -pub struct EccPoint { - /// x-coordinate - /// - /// Stored as an `Assigned` to enable batching inversions. - x: AssignedCell, pallas::Base>, - /// y-coordinate - /// - /// Stored as an `Assigned` to enable batching inversions. - y: AssignedCell, pallas::Base>, -} - -impl EccPoint { - /// Constructs a point from its coordinates, without checking they are on the curve. - /// - /// This is an internal API that we only use where we know we have a valid curve point - /// (specifically inside Sinsemilla). - pub(crate) fn from_coordinates_unchecked( - x: AssignedCell, pallas::Base>, - y: AssignedCell, pallas::Base>, - ) -> Self { - EccPoint { x, y } - } - - /// Returns the value of this curve point, if known. - pub fn point(&self) -> Value { - self.x.value().zip(self.y.value()).map(|(x, y)| { - if x.is_zero_vartime() && y.is_zero_vartime() { - pallas::Affine::identity() - } else { - pallas::Affine::from_xy(x.evaluate(), y.evaluate()).unwrap() - } - }) - } - /// The cell containing the affine short-Weierstrass x-coordinate, - /// or 0 for the zero point. - pub fn x(&self) -> AssignedCell { - self.x.clone().evaluate() - } - /// The cell containing the affine short-Weierstrass y-coordinate, - /// or 0 for the zero point. - pub fn y(&self) -> AssignedCell { - self.y.clone().evaluate() - } - - #[cfg(test)] - fn is_identity(&self) -> Value { - self.x.value().map(|x| x.is_zero_vartime()) - } -} - -/// A non-identity point represented in affine (x, y) coordinates. -/// Each coordinate is assigned to a cell. -#[derive(Clone, Debug)] -pub struct NonIdentityEccPoint { - /// x-coordinate - /// - /// Stored as an `Assigned` to enable batching inversions. - x: AssignedCell, pallas::Base>, - /// y-coordinate - /// - /// Stored as an `Assigned` to enable batching inversions. - y: AssignedCell, pallas::Base>, -} - -impl NonIdentityEccPoint { - /// Constructs a point from its coordinates, without checking they are on the curve. - /// - /// This is an internal API that we only use where we know we have a valid non-identity - /// curve point (specifically inside Sinsemilla). - pub(crate) fn from_coordinates_unchecked( - x: AssignedCell, pallas::Base>, - y: AssignedCell, pallas::Base>, - ) -> Self { - NonIdentityEccPoint { x, y } - } - - /// Returns the value of this curve point, if known. - pub fn point(&self) -> Value { - self.x.value().zip(self.y.value()).map(|(x, y)| { - assert!(!x.is_zero_vartime() && !y.is_zero_vartime()); - pallas::Affine::from_xy(x.evaluate(), y.evaluate()).unwrap() - }) - } - /// The cell containing the affine short-Weierstrass x-coordinate. - pub fn x(&self) -> AssignedCell { - self.x.clone().evaluate() - } - /// The cell containing the affine short-Weierstrass y-coordinate. - pub fn y(&self) -> AssignedCell { - self.y.clone().evaluate() - } -} - -impl From for EccPoint { - fn from(non_id_point: NonIdentityEccPoint) -> Self { - Self { - x: non_id_point.x, - y: non_id_point.y, - } - } -} - -/// Configuration for [`EccChip`]. -#[derive(Clone, Debug, Eq, PartialEq)] -#[allow(non_snake_case)] -pub struct EccConfig> { - /// Advice columns needed by instructions in the ECC chip. - pub advices: [Column; 10], - - /// Incomplete addition - add_incomplete: add_incomplete::Config, - - /// Complete addition - add: add::Config, - - /// Variable-base scalar multiplication - mul: mul::Config, - - /// Fixed-base full-width scalar multiplication - mul_fixed_full: mul_fixed::full_width::Config, - /// Fixed-base signed short scalar multiplication - mul_fixed_short: mul_fixed::short::Config, - /// Fixed-base mul using a base field element as a scalar - mul_fixed_base_field: mul_fixed::base_field_elem::Config, - - /// Witness point - witness_point: witness_point::Config, - - /// Lookup range check using 10-bit lookup table - pub lookup_config: LookupRangeCheckConfig, -} - -/// A trait representing the kind of scalar used with a particular `FixedPoint`. -/// -/// This trait exists because of limitations around const generics. -pub trait FixedScalarKind { - /// The number of windows that this scalar kind requires. - const NUM_WINDOWS: usize; -} - -/// Type marker representing a full-width scalar for use in fixed-base scalar -/// multiplication. -#[derive(Debug)] -pub enum FullScalar {} -impl FixedScalarKind for FullScalar { - const NUM_WINDOWS: usize = NUM_WINDOWS; -} - -/// Type marker representing a signed 64-bit scalar for use in fixed-base scalar -/// multiplication. -#[derive(Debug)] -pub enum ShortScalar {} -impl FixedScalarKind for ShortScalar { - const NUM_WINDOWS: usize = NUM_WINDOWS_SHORT; -} - -/// Type marker representing a base field element being used as a scalar in fixed-base -/// scalar multiplication. -#[derive(Debug)] -pub enum BaseFieldElem {} -impl FixedScalarKind for BaseFieldElem { - const NUM_WINDOWS: usize = NUM_WINDOWS; -} - -/// Returns information about a fixed point that is required by [`EccChip`]. -/// -/// For each window required by `Self::FixedScalarKind`, $z$ is a field element such that for -/// each point $(x, y)$ in the window: -/// - $z + y = u^2$ (some square in the field); and -/// - $z - y$ is not a square. -/// -/// TODO: When associated consts can be used as const generics, introduce a -/// `const NUM_WINDOWS: usize` associated const, and return `NUM_WINDOWS`-sized -/// arrays instead of `Vec`s. -pub trait FixedPoint: std::fmt::Debug + Eq + Clone { - /// The kind of scalar that this fixed point can be multiplied by. - type FixedScalarKind: FixedScalarKind; - - /// Returns the generator for this fixed point. - fn generator(&self) -> C; - - /// Returns the $u$ values for this fixed point. - fn u(&self) -> Vec<[::Repr; H]>; - - /// Returns the $z$ value for this fixed point. - fn z(&self) -> Vec; - - /// Returns the Lagrange coefficients for this fixed point. - fn lagrange_coeffs(&self) -> Vec<[C::Base; H]> { - compute_lagrange_coeffs(self.generator(), Self::FixedScalarKind::NUM_WINDOWS) - } -} - -/// An [`EccInstructions`] chip that uses 10 advice columns. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct EccChip> { - config: EccConfig, -} - -impl> Chip for EccChip { - type Config = EccConfig; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -impl> UtilitiesInstructions - for EccChip -{ - type Var = AssignedCell; -} - -impl> EccChip { - /// Reconstructs this chip from the given config. - pub fn construct(config: >::Config) -> Self { - Self { config } - } - - /// # Side effects - /// - /// All columns in `advices` will be equality-enabled. - #[allow(non_snake_case)] - pub fn configure( - meta: &mut ConstraintSystem, - advices: [Column; 10], - lagrange_coeffs: [Column; 8], - range_check: LookupRangeCheckConfig, - ) -> >::Config { - // Create witness point gate - let witness_point = witness_point::Config::configure(meta, advices[0], advices[1]); - // Create incomplete point addition gate - let add_incomplete = - add_incomplete::Config::configure(meta, advices[0], advices[1], advices[2], advices[3]); - - // Create complete point addition gate - let add = add::Config::configure( - meta, advices[0], advices[1], advices[2], advices[3], advices[4], advices[5], - advices[6], advices[7], advices[8], - ); - - // Create variable-base scalar mul gates - let mul = mul::Config::configure(meta, add, range_check, advices); - - // Create config that is shared across short, base-field, and full-width - // fixed-base scalar mul. - let mul_fixed = mul_fixed::Config::::configure( - meta, - lagrange_coeffs, - advices[4], - advices[5], - add, - add_incomplete, - ); - - // Create gate that is only used in full-width fixed-base scalar mul. - let mul_fixed_full = - mul_fixed::full_width::Config::::configure(meta, mul_fixed.clone()); - - // Create gate that is only used in short fixed-base scalar mul. - let mul_fixed_short = - mul_fixed::short::Config::::configure(meta, mul_fixed.clone()); - - // Create gate that is only used in fixed-base mul using a base field element. - let mul_fixed_base_field = mul_fixed::base_field_elem::Config::::configure( - meta, - advices[6..9].try_into().unwrap(), - range_check, - mul_fixed, - ); - - EccConfig { - advices, - add_incomplete, - add, - mul, - mul_fixed_full, - mul_fixed_short, - mul_fixed_base_field, - witness_point, - lookup_config: range_check, - } - } -} - -/// A full-width scalar used for fixed-base scalar multiplication. -/// This is decomposed into 85 3-bit windows in little-endian order, -/// i.e. `windows` = [k_0, k_1, ..., k_84] (for a 255-bit scalar) -/// where `scalar = k_0 + k_1 * (2^3) + ... + k_84 * (2^3)^84` and -/// each `k_i` is in the range [0..2^3). -#[derive(Clone, Debug)] -pub struct EccScalarFixed { - value: Value, - /// The circuit-assigned windows representing this scalar, or `None` if the scalar has - /// not been used yet. - windows: Option, { NUM_WINDOWS }>>, -} - -// TODO: Make V a `u64` -type MagnitudeCell = AssignedCell; -// TODO: Make V an enum Sign { Positive, Negative } -type SignCell = AssignedCell; -type MagnitudeSign = (MagnitudeCell, SignCell); - -/// A signed short scalar used for fixed-base scalar multiplication. -/// A short scalar must have magnitude in the range [0..2^64), with -/// a sign of either 1 or -1. -/// This is decomposed into 3-bit windows in little-endian order -/// using a running sum `z`, where z_{i+1} = (z_i - a_i) / (2^3) -/// for element α = a_0 + (2^3) a_1 + ... + (2^{3(n-1)}) a_{n-1}. -/// Each `a_i` is in the range [0..2^3). -/// -/// `windows` = [k_0, k_1, ..., k_21] (for a 64-bit magnitude) -/// where `scalar = k_0 + k_1 * (2^3) + ... + k_84 * (2^3)^84` and -/// each `k_i` is in the range [0..2^3). -/// k_21 must be a single bit, i.e. 0 or 1. -#[derive(Clone, Debug)] -pub struct EccScalarFixedShort { - magnitude: MagnitudeCell, - sign: SignCell, - /// The circuit-assigned running sum constraining this signed short scalar, or `None` - /// if the scalar has not been used yet. - running_sum: - Option, { NUM_WINDOWS_SHORT + 1 }>>, -} - -/// A base field element used for fixed-base scalar multiplication. -/// This is decomposed into 3-bit windows in little-endian order -/// using a running sum `z`, where z_{i+1} = (z_i - a_i) / (2^3) -/// for element α = a_0 + (2^3) a_1 + ... + (2^{3(n-1)}) a_{n-1}. -/// Each `a_i` is in the range [0..2^3). -/// -/// `running_sum` = [z_0, ..., z_85], where we expect z_85 = 0. -/// Since z_0 is initialized as the scalar α, we store it as -/// `base_field_elem`. -#[derive(Clone, Debug)] -struct EccBaseFieldElemFixed { - base_field_elem: AssignedCell, - running_sum: ArrayVec, { NUM_WINDOWS + 1 }>, -} - -impl EccBaseFieldElemFixed { - fn base_field_elem(&self) -> AssignedCell { - self.base_field_elem.clone() - } -} - -/// An enumeration of the possible types of scalars used in variable-base -/// multiplication. -#[derive(Clone, Debug)] -pub enum ScalarVar { - /// An element of the elliptic curve's base field, that is used as a scalar - /// in variable-base scalar mul. - /// - /// It is not true in general that a scalar field element fits in a curve's - /// base field, and in particular it is untrue for the Pallas curve, whose - /// scalar field `Fq` is larger than its base field `Fp`. - /// - /// However, the only use of variable-base scalar mul in the Orchard protocol - /// is in deriving diversified addresses `[ivk] g_d`, and `ivk` is guaranteed - /// to be in the base field of the curve. (See non-normative notes in - /// [4.2.3 Orchard Key Components][orchardkeycomponents].) - /// - /// [orchardkeycomponents]: https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents - BaseFieldElem(AssignedCell), - /// A full-width scalar. This is unimplemented for halo2_gadgets v0.1.0. - FullWidth, -} - -impl> EccInstructions for EccChip -where - >::Base: - FixedPoint, - >::FullScalar: - FixedPoint, - >::ShortScalar: - FixedPoint, -{ - type ScalarFixed = EccScalarFixed; - type ScalarFixedShort = EccScalarFixedShort; - type ScalarVar = ScalarVar; - type Point = EccPoint; - type NonIdentityPoint = NonIdentityEccPoint; - type X = AssignedCell; - type FixedPoints = Fixed; - - fn constrain_equal( - &self, - layouter: &mut impl Layouter, - a: &Self::Point, - b: &Self::Point, - ) -> Result<(), Error> { - layouter.assign_region( - || "constrain equal", - |mut region| { - // Constrain x-coordinates - region.constrain_equal(a.x().cell(), b.x().cell())?; - // Constrain x-coordinates - region.constrain_equal(a.y().cell(), b.y().cell()) - }, - ) - } - - fn witness_point( - &self, - layouter: &mut impl Layouter, - value: Value, - ) -> Result { - let config = self.config().witness_point; - layouter.assign_region( - || "witness point", - |mut region| config.point(value, 0, &mut region), - ) - } - - fn witness_point_non_id( - &self, - layouter: &mut impl Layouter, - value: Value, - ) -> Result { - let config = self.config().witness_point; - layouter.assign_region( - || "witness non-identity point", - |mut region| config.point_non_id(value, 0, &mut region), - ) - } - - fn witness_scalar_var( - &self, - _layouter: &mut impl Layouter, - _value: Value, - ) -> Result { - // This is unimplemented for halo2_gadgets v0.1.0. - todo!() - } - - fn witness_scalar_fixed( - &self, - _layouter: &mut impl Layouter, - value: Value, - ) -> Result { - Ok(EccScalarFixed { - value, - // This chip uses lazy witnessing. - windows: None, - }) - } - - fn scalar_fixed_from_signed_short( - &self, - _layouter: &mut impl Layouter, - (magnitude, sign): MagnitudeSign, - ) -> Result { - Ok(EccScalarFixedShort { - magnitude, - sign, - // This chip uses lazy constraining. - running_sum: None, - }) - } - - fn extract_p + Clone>(point: &Point) -> Self::X { - let point: EccPoint = (point.clone()).into(); - point.x() - } - - fn add_incomplete( - &self, - layouter: &mut impl Layouter, - a: &Self::NonIdentityPoint, - b: &Self::NonIdentityPoint, - ) -> Result { - let config = self.config().add_incomplete; - layouter.assign_region( - || "incomplete point addition", - |mut region| config.assign_region(a, b, 0, &mut region), - ) - } - - fn add + Clone, B: Into + Clone>( - &self, - layouter: &mut impl Layouter, - a: &A, - b: &B, - ) -> Result { - let config = self.config().add; - layouter.assign_region( - || "complete point addition", - |mut region| { - config.assign_region(&(a.clone()).into(), &(b.clone()).into(), 0, &mut region) - }, - ) - } - - fn mul( - &self, - layouter: &mut impl Layouter, - scalar: &Self::ScalarVar, - base: &Self::NonIdentityPoint, - ) -> Result<(Self::Point, Self::ScalarVar), Error> { - let config = self.config().mul; - match scalar { - ScalarVar::BaseFieldElem(scalar) => config.assign( - layouter.namespace(|| "variable-base scalar mul"), - scalar.clone(), - base, - ), - ScalarVar::FullWidth => { - todo!() - } - } - } - - fn mul_fixed( - &self, - layouter: &mut impl Layouter, - scalar: &Self::ScalarFixed, - base: &>::FullScalar, - ) -> Result<(Self::Point, Self::ScalarFixed), Error> { - let config = self.config().mul_fixed_full.clone(); - config.assign( - layouter.namespace(|| format!("fixed-base mul of {:?}", base)), - scalar, - base, - ) - } - - fn mul_fixed_short( - &self, - layouter: &mut impl Layouter, - scalar: &Self::ScalarFixedShort, - base: &>::ShortScalar, - ) -> Result<(Self::Point, Self::ScalarFixedShort), Error> { - let config = self.config().mul_fixed_short.clone(); - config.assign( - layouter.namespace(|| format!("short fixed-base mul of {:?}", base)), - scalar, - base, - ) - } - - fn mul_fixed_base_field_elem( - &self, - layouter: &mut impl Layouter, - base_field_elem: AssignedCell, - base: &>::Base, - ) -> Result { - let config = self.config().mul_fixed_base_field.clone(); - config.assign( - layouter.namespace(|| format!("base-field elem fixed-base mul of {:?}", base)), - base_field_elem, - base, - ) - } -} - -impl> BaseFitsInScalarInstructions - for EccChip -where - >::Base: - FixedPoint, - >::FullScalar: - FixedPoint, - >::ShortScalar: - FixedPoint, -{ - fn scalar_var_from_base( - &self, - _layouter: &mut impl Layouter, - base: &Self::Var, - ) -> Result { - Ok(ScalarVar::BaseFieldElem(base.clone())) - } -} diff --git a/halo2_gadgets/src/ecc/chip/add.rs b/halo2_gadgets/src/ecc/chip/add.rs deleted file mode 100644 index 11661d51e2..0000000000 --- a/halo2_gadgets/src/ecc/chip/add.rs +++ /dev/null @@ -1,457 +0,0 @@ -use super::EccPoint; -use ff::PrimeField; -use halo2_proofs::{ - circuit::Region, - plonk::{Advice, Assigned, Column, ConstraintSystem, Constraints, Error, Expression, Selector}, - poly::Rotation, -}; -use halo2curves::pasta::pallas; -use std::collections::HashSet; - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct Config { - q_add: Selector, - // lambda - lambda: Column, - // x-coordinate of P in P + Q = R - pub x_p: Column, - // y-coordinate of P in P + Q = R - pub y_p: Column, - // x-coordinate of Q or R in P + Q = R - pub x_qr: Column, - // y-coordinate of Q or R in P + Q = R - pub y_qr: Column, - // α = inv0(x_q - x_p) - alpha: Column, - // β = inv0(x_p) - beta: Column, - // γ = inv0(x_q) - gamma: Column, - // δ = inv0(y_p + y_q) if x_q = x_p, 0 otherwise - delta: Column, -} - -impl Config { - #[allow(clippy::too_many_arguments)] - pub(super) fn configure( - meta: &mut ConstraintSystem, - x_p: Column, - y_p: Column, - x_qr: Column, - y_qr: Column, - lambda: Column, - alpha: Column, - beta: Column, - gamma: Column, - delta: Column, - ) -> Self { - meta.enable_equality(x_p); - meta.enable_equality(y_p); - meta.enable_equality(x_qr); - meta.enable_equality(y_qr); - - let config = Self { - q_add: meta.selector(), - x_p, - y_p, - x_qr, - y_qr, - lambda, - alpha, - beta, - gamma, - delta, - }; - - config.create_gate(meta); - - config - } - - pub(crate) fn advice_columns(&self) -> HashSet> { - [ - self.x_p, - self.y_p, - self.x_qr, - self.y_qr, - self.lambda, - self.alpha, - self.beta, - self.gamma, - self.delta, - ] - .into_iter() - .collect() - } - - pub(crate) fn output_columns(&self) -> HashSet> { - [self.x_qr, self.y_qr].into_iter().collect() - } - - fn create_gate(&self, meta: &mut ConstraintSystem) { - // https://p.z.cash/halo2-0.1:ecc-complete-addition - meta.create_gate("complete addition", |meta| { - let q_add = meta.query_selector(self.q_add); - let x_p = meta.query_advice(self.x_p, Rotation::cur()); - let y_p = meta.query_advice(self.y_p, Rotation::cur()); - let x_q = meta.query_advice(self.x_qr, Rotation::cur()); - let y_q = meta.query_advice(self.y_qr, Rotation::cur()); - let x_r = meta.query_advice(self.x_qr, Rotation::next()); - let y_r = meta.query_advice(self.y_qr, Rotation::next()); - let lambda = meta.query_advice(self.lambda, Rotation::cur()); - - // α = inv0(x_q - x_p) - let alpha = meta.query_advice(self.alpha, Rotation::cur()); - // β = inv0(x_p) - let beta = meta.query_advice(self.beta, Rotation::cur()); - // γ = inv0(x_q) - let gamma = meta.query_advice(self.gamma, Rotation::cur()); - // δ = inv0(y_p + y_q) if x_q = x_p, 0 otherwise - let delta = meta.query_advice(self.delta, Rotation::cur()); - - // Useful composite expressions - // (x_q − x_p) - let x_q_minus_x_p = x_q.clone() - x_p.clone(); - // (x_p - x_r) - let x_p_minus_x_r = x_p.clone() - x_r.clone(); - // (y_q + y_p) - let y_q_plus_y_p = y_q.clone() + y_p.clone(); - // α ⋅(x_q - x_p) - let if_alpha = x_q_minus_x_p.clone() * alpha; - // β ⋅ x_p - let if_beta = x_p.clone() * beta; - // γ ⋅ x_q - let if_gamma = x_q.clone() * gamma; - // δ ⋅(y_q + y_p) - let if_delta = y_q_plus_y_p.clone() * delta; - - // Useful constants - let one = Expression::Constant(pallas::Base::one()); - let two = Expression::Constant(pallas::Base::from(2)); - let three = Expression::Constant(pallas::Base::from(3)); - - // (x_q − x_p)⋅((x_q − x_p)⋅λ − (y_q−y_p)) = 0 - let poly1 = { - let y_q_minus_y_p = y_q.clone() - y_p.clone(); // (y_q − y_p) - let incomplete = x_q_minus_x_p.clone() * lambda.clone() - y_q_minus_y_p; // (x_q − x_p)⋅λ − (y_q−y_p) - - // q_add ⋅(x_q − x_p)⋅((x_q − x_p)⋅λ − (y_q−y_p)) - x_q_minus_x_p.clone() * incomplete - }; - - // (1 - (x_q - x_p)⋅α)⋅(2y_p ⋅λ - 3x_p^2) = 0 - let poly2 = { - let three_x_p_sq = three * x_p.clone().square(); // 3x_p^2 - let two_y_p = two * y_p.clone(); // 2y_p - let tangent_line = two_y_p * lambda.clone() - three_x_p_sq; // (2y_p ⋅λ - 3x_p^2) - - // q_add ⋅(1 - (x_q - x_p)⋅α)⋅(2y_p ⋅λ - 3x_p^2) - (one.clone() - if_alpha.clone()) * tangent_line - }; - - // (λ^2 - x_p - x_q - x_r) - let nonexceptional_x_r = - lambda.clone().square() - x_p.clone() - x_q.clone() - x_r.clone(); - // (λ ⋅(x_p - x_r) - y_p - y_r) - let nonexceptional_y_r = lambda * x_p_minus_x_r - y_p.clone() - y_r.clone(); - - // x_p⋅x_q⋅(x_q - x_p)⋅(λ^2 - x_p - x_q - x_r) = 0 - let poly3a = - x_p.clone() * x_q.clone() * x_q_minus_x_p.clone() * nonexceptional_x_r.clone(); - - // x_p⋅x_q⋅(x_q - x_p)⋅(λ ⋅(x_p - x_r) - y_p - y_r) = 0 - let poly3b = x_p.clone() * x_q.clone() * x_q_minus_x_p * nonexceptional_y_r.clone(); - - // x_p⋅x_q⋅(y_q + y_p)⋅(λ^2 - x_p - x_q - x_r) = 0 - let poly3c = x_p.clone() * x_q.clone() * y_q_plus_y_p.clone() * nonexceptional_x_r; - - // x_p⋅x_q⋅(y_q + y_p)⋅(λ ⋅(x_p - x_r) - y_p - y_r) = 0 - let poly3d = x_p.clone() * x_q.clone() * y_q_plus_y_p * nonexceptional_y_r; - - // (1 - x_p * β) * (x_r - x_q) = 0 - let poly4a = (one.clone() - if_beta.clone()) * (x_r.clone() - x_q); - - // (1 - x_p * β) * (y_r - y_q) = 0 - let poly4b = (one.clone() - if_beta) * (y_r.clone() - y_q); - - // (1 - x_q * γ) * (x_r - x_p) = 0 - let poly5a = (one.clone() - if_gamma.clone()) * (x_r.clone() - x_p); - - // (1 - x_q * γ) * (y_r - y_p) = 0 - let poly5b = (one.clone() - if_gamma) * (y_r.clone() - y_p); - - // ((1 - (x_q - x_p) * α - (y_q + y_p) * δ)) * x_r - let poly6a = (one.clone() - if_alpha.clone() - if_delta.clone()) * x_r; - - // ((1 - (x_q - x_p) * α - (y_q + y_p) * δ)) * y_r - let poly6b = (one - if_alpha - if_delta) * y_r; - - Constraints::with_selector( - q_add, - [ - ("1", poly1), - ("2", poly2), - ("3a", poly3a), - ("3b", poly3b), - ("3c", poly3c), - ("3d", poly3d), - ("4a", poly4a), - ("4b", poly4b), - ("5a", poly5a), - ("5b", poly5b), - ("6a", poly6a), - ("6b", poly6b), - ], - ) - }); - } - - pub(super) fn assign_region( - &self, - p: &EccPoint, - q: &EccPoint, - offset: usize, - region: &mut Region<'_, pallas::Base>, - ) -> Result { - // Enable `q_add` selector - self.q_add.enable(region, offset)?; - - // Copy point `p` into `x_p`, `y_p` columns - p.x.copy_advice(|| "x_p", region, self.x_p, offset)?; - p.y.copy_advice(|| "y_p", region, self.y_p, offset)?; - - // Copy point `q` into `x_qr`, `y_qr` columns - q.x.copy_advice(|| "x_q", region, self.x_qr, offset)?; - q.y.copy_advice(|| "y_q", region, self.y_qr, offset)?; - - let (x_p, y_p) = (p.x.value(), p.y.value()); - let (x_q, y_q) = (q.x.value(), q.y.value()); - - // Assign α = inv0(x_q - x_p) - let alpha = (x_q - x_p).invert(); - region.assign_advice(|| "α", self.alpha, offset, || alpha)?; - - // Assign β = inv0(x_p) - let beta = x_p.invert(); - region.assign_advice(|| "β", self.beta, offset, || beta)?; - - // Assign γ = inv0(x_q) - let gamma = x_q.invert(); - region.assign_advice(|| "γ", self.gamma, offset, || gamma)?; - - // Assign δ = inv0(y_q + y_p) if x_q = x_p, 0 otherwise - let delta = x_p - .zip(x_q) - .zip(y_p) - .zip(y_q) - .map(|(((x_p, x_q), y_p), y_q)| { - if x_q == x_p { - (y_q + y_p).invert() - } else { - Assigned::Zero - } - }); - region.assign_advice(|| "δ", self.delta, offset, || delta)?; - - #[allow(clippy::collapsible_else_if)] - // Assign lambda - let lambda = - x_p.zip(y_p) - .zip(x_q) - .zip(y_q) - .zip(alpha) - .map(|((((x_p, y_p), x_q), y_q), alpha)| { - if x_q != x_p { - // λ = (y_q - y_p)/(x_q - x_p) - // Here, alpha = inv0(x_q - x_p), which suffices since we - // know that x_q != x_p in this branch. - (y_q - y_p) * alpha - } else { - if !y_p.is_zero_vartime() { - // 3(x_p)^2 - let three_x_p_sq = x_p.square() * pallas::Base::from(3); - // 1 / 2(y_p) - let inv_two_y_p = y_p.invert() * pallas::Base::TWO_INV; - // λ = 3(x_p)^2 / 2(y_p) - three_x_p_sq * inv_two_y_p - } else { - Assigned::Zero - } - } - }); - region.assign_advice(|| "λ", self.lambda, offset, || lambda)?; - - // Calculate (x_r, y_r) - let r = - x_p.zip(y_p) - .zip(x_q) - .zip(y_q) - .zip(lambda) - .map(|((((x_p, y_p), x_q), y_q), lambda)| { - { - if x_p.is_zero_vartime() { - // 0 + Q = Q - (*x_q, *y_q) - } else if x_q.is_zero_vartime() { - // P + 0 = P - (*x_p, *y_p) - } else if (x_q == x_p) && (*y_q == -y_p) { - // P + (-P) maps to (0,0) - (Assigned::Zero, Assigned::Zero) - } else { - // x_r = λ^2 - x_p - x_q - let x_r = lambda.square() - x_p - x_q; - // y_r = λ(x_p - x_r) - y_p - let y_r = lambda * (x_p - x_r) - y_p; - (x_r, y_r) - } - } - }); - - // Assign x_r - let x_r = r.map(|r| r.0); - let x_r_cell = region.assign_advice(|| "x_r", self.x_qr, offset + 1, || x_r)?; - - // Assign y_r - let y_r = r.map(|r| r.1); - let y_r_cell = region.assign_advice(|| "y_r", self.y_qr, offset + 1, || y_r)?; - - let result = EccPoint { - x: x_r_cell, - y: y_r_cell, - }; - - #[cfg(test)] - // Check that the correct sum is obtained. - { - use group::Curve; - - let p = p.point(); - let q = q.point(); - let real_sum = p.zip(q).map(|(p, q)| p + q); - let result = result.point(); - - real_sum - .zip(result) - .assert_if_known(|(real_sum, result)| &real_sum.to_affine() == result); - } - - Ok(result) - } -} - -#[cfg(test)] -pub mod tests { - use group::{prime::PrimeCurveAffine, Curve}; - use halo2_proofs::{ - circuit::{Layouter, Value}, - plonk::Error, - }; - use halo2curves::{pasta::pallas, CurveExt}; - - use crate::ecc::{chip::EccPoint, EccInstructions, NonIdentityPoint}; - - #[allow(clippy::too_many_arguments)] - pub fn test_add< - EccChip: EccInstructions + Clone + Eq + std::fmt::Debug, - >( - chip: EccChip, - mut layouter: impl Layouter, - p_val: pallas::Affine, - p: &NonIdentityPoint, - q_val: pallas::Affine, - q: &NonIdentityPoint, - p_neg: &NonIdentityPoint, - ) -> Result<(), Error> { - // Make sure P and Q are not the same point. - assert_ne!(p_val, q_val); - - // Check complete addition P + (-P) - let zero = { - let result = p.add(layouter.namespace(|| "P + (-P)"), p_neg)?; - result - .inner() - .is_identity() - .assert_if_known(|is_identity| *is_identity); - result - }; - - // Check complete addition 𝒪 + 𝒪 - { - let result = zero.add(layouter.namespace(|| "𝒪 + 𝒪"), &zero)?; - result.constrain_equal(layouter.namespace(|| "𝒪 + 𝒪 = 𝒪"), &zero)?; - } - - // Check P + Q - { - let result = p.add(layouter.namespace(|| "P + Q"), q)?; - let witnessed_result = NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "witnessed P + Q"), - Value::known((p_val + q_val).to_affine()), - )?; - result.constrain_equal(layouter.namespace(|| "constrain P + Q"), &witnessed_result)?; - } - - // P + P - { - let result = p.add(layouter.namespace(|| "P + P"), p)?; - let witnessed_result = NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "witnessed P + P"), - Value::known((p_val + p_val).to_affine()), - )?; - result.constrain_equal(layouter.namespace(|| "constrain P + P"), &witnessed_result)?; - } - - // P + 𝒪 - { - let result = p.add(layouter.namespace(|| "P + 𝒪"), &zero)?; - result.constrain_equal(layouter.namespace(|| "P + 𝒪 = P"), p)?; - } - - // 𝒪 + P - { - let result = zero.add(layouter.namespace(|| "𝒪 + P"), p)?; - result.constrain_equal(layouter.namespace(|| "𝒪 + P = P"), p)?; - } - - // (x, y) + (ζx, y) should behave like normal P + Q. - let endo_p = p_val.to_curve().endo(); - let endo_p = NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "endo(P)"), - Value::known(endo_p.to_affine()), - )?; - p.add(layouter.namespace(|| "P + endo(P)"), &endo_p)?; - - // (x, y) + (ζx, -y) should also behave like normal P + Q. - let endo_p_neg = (-p_val).to_curve().endo(); - let endo_p_neg = NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "endo(-P)"), - Value::known(endo_p_neg.to_affine()), - )?; - p.add(layouter.namespace(|| "P + endo(-P)"), &endo_p_neg)?; - - // (x, y) + ((ζ^2)x, y) - let endo_2_p = p_val.to_curve().endo().endo(); - let endo_2_p = NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "endo^2(P)"), - Value::known(endo_2_p.to_affine()), - )?; - p.add(layouter.namespace(|| "P + endo^2(P)"), &endo_2_p)?; - - // (x, y) + ((ζ^2)x, -y) - let endo_2_p_neg = (-p_val).to_curve().endo().endo(); - let endo_2_p_neg = NonIdentityPoint::new( - chip, - layouter.namespace(|| "endo^2(-P)"), - Value::known(endo_2_p_neg.to_affine()), - )?; - p.add(layouter.namespace(|| "P + endo^2(-P)"), &endo_2_p_neg)?; - - Ok(()) - } -} diff --git a/halo2_gadgets/src/ecc/chip/add_incomplete.rs b/halo2_gadgets/src/ecc/chip/add_incomplete.rs deleted file mode 100644 index a28391c9e1..0000000000 --- a/halo2_gadgets/src/ecc/chip/add_incomplete.rs +++ /dev/null @@ -1,195 +0,0 @@ -use std::collections::HashSet; - -use super::NonIdentityEccPoint; -use halo2_proofs::{ - circuit::Region, - plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Selector}, - poly::Rotation, -}; -use halo2curves::pasta::pallas; - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct Config { - q_add_incomplete: Selector, - // x-coordinate of P in P + Q = R - pub x_p: Column, - // y-coordinate of P in P + Q = R - pub y_p: Column, - // x-coordinate of Q or R in P + Q = R - pub x_qr: Column, - // y-coordinate of Q or R in P + Q = R - pub y_qr: Column, -} - -impl Config { - pub(super) fn configure( - meta: &mut ConstraintSystem, - x_p: Column, - y_p: Column, - x_qr: Column, - y_qr: Column, - ) -> Self { - meta.enable_equality(x_p); - meta.enable_equality(y_p); - meta.enable_equality(x_qr); - meta.enable_equality(y_qr); - - let config = Self { - q_add_incomplete: meta.selector(), - x_p, - y_p, - x_qr, - y_qr, - }; - - config.create_gate(meta); - - config - } - - pub(crate) fn advice_columns(&self) -> HashSet> { - [self.x_p, self.y_p, self.x_qr, self.y_qr] - .into_iter() - .collect() - } - - fn create_gate(&self, meta: &mut ConstraintSystem) { - // https://p.z.cash/halo2-0.1:ecc-incomplete-addition - meta.create_gate("incomplete addition", |meta| { - let q_add_incomplete = meta.query_selector(self.q_add_incomplete); - let x_p = meta.query_advice(self.x_p, Rotation::cur()); - let y_p = meta.query_advice(self.y_p, Rotation::cur()); - let x_q = meta.query_advice(self.x_qr, Rotation::cur()); - let y_q = meta.query_advice(self.y_qr, Rotation::cur()); - let x_r = meta.query_advice(self.x_qr, Rotation::next()); - let y_r = meta.query_advice(self.y_qr, Rotation::next()); - - // (x_r + x_q + x_p)⋅(x_p − x_q)^2 − (y_p − y_q)^2 = 0 - let poly1 = { - (x_r.clone() + x_q.clone() + x_p.clone()) - * (x_p.clone() - x_q.clone()) - * (x_p.clone() - x_q.clone()) - - (y_p.clone() - y_q.clone()).square() - }; - - // (y_r + y_q)(x_p − x_q) − (y_p − y_q)(x_q − x_r) = 0 - let poly2 = (y_r + y_q.clone()) * (x_p - x_q.clone()) - (y_p - y_q) * (x_q - x_r); - - Constraints::with_selector(q_add_incomplete, [("x_r", poly1), ("y_r", poly2)]) - }); - } - - pub(super) fn assign_region( - &self, - p: &NonIdentityEccPoint, - q: &NonIdentityEccPoint, - offset: usize, - region: &mut Region<'_, pallas::Base>, - ) -> Result { - // Enable `q_add_incomplete` selector - self.q_add_incomplete.enable(region, offset)?; - - // Handle exceptional cases - let (x_p, y_p) = (p.x.value(), p.y.value()); - let (x_q, y_q) = (q.x.value(), q.y.value()); - x_p.zip(y_p) - .zip(x_q) - .zip(y_q) - .error_if_known_and(|(((x_p, y_p), x_q), y_q)| { - // P is point at infinity - (x_p.is_zero_vartime() && y_p.is_zero_vartime()) - // Q is point at infinity - || (x_q.is_zero_vartime() && y_q.is_zero_vartime()) - // x_p = x_q - || (x_p == x_q) - })?; - - // Copy point `p` into `x_p`, `y_p` columns - p.x.copy_advice(|| "x_p", region, self.x_p, offset)?; - p.y.copy_advice(|| "y_p", region, self.y_p, offset)?; - - // Copy point `q` into `x_qr`, `y_qr` columns - q.x.copy_advice(|| "x_q", region, self.x_qr, offset)?; - q.y.copy_advice(|| "y_q", region, self.y_qr, offset)?; - - // Compute the sum `P + Q = R` - let r = x_p - .zip(y_p) - .zip(x_q) - .zip(y_q) - .map(|(((x_p, y_p), x_q), y_q)| { - { - // λ = (y_q - y_p)/(x_q - x_p) - let lambda = (y_q - y_p) * (x_q - x_p).invert(); - // x_r = λ^2 - x_p - x_q - let x_r = lambda.square() - x_p - x_q; - // y_r = λ(x_p - x_r) - y_p - let y_r = lambda * (x_p - x_r) - y_p; - (x_r, y_r) - } - }); - - // Assign the sum to `x_qr`, `y_qr` columns in the next row - let x_r = r.map(|r| r.0); - let x_r_var = region.assign_advice(|| "x_r", self.x_qr, offset + 1, || x_r)?; - - let y_r = r.map(|r| r.1); - let y_r_var = region.assign_advice(|| "y_r", self.y_qr, offset + 1, || y_r)?; - - let result = NonIdentityEccPoint { - x: x_r_var, - y: y_r_var, - }; - - Ok(result) - } -} - -#[cfg(test)] -pub mod tests { - use group::Curve; - use halo2_proofs::{ - circuit::{Layouter, Value}, - plonk::Error, - }; - use halo2curves::pasta::pallas; - - use crate::ecc::{EccInstructions, NonIdentityPoint}; - - #[allow(clippy::too_many_arguments)] - pub fn test_add_incomplete< - EccChip: EccInstructions + Clone + Eq + std::fmt::Debug, - >( - chip: EccChip, - mut layouter: impl Layouter, - p_val: pallas::Affine, - p: &NonIdentityPoint, - q_val: pallas::Affine, - q: &NonIdentityPoint, - p_neg: &NonIdentityPoint, - test_errors: bool, - ) -> Result<(), Error> { - // P + Q - { - let result = p.add_incomplete(layouter.namespace(|| "P + Q"), q)?; - let witnessed_result = NonIdentityPoint::new( - chip, - layouter.namespace(|| "witnessed P + Q"), - Value::known((p_val + q_val).to_affine()), - )?; - result.constrain_equal(layouter.namespace(|| "constrain P + Q"), &witnessed_result)?; - } - - if test_errors { - // P + P should return an error - p.add_incomplete(layouter.namespace(|| "P + P"), p) - .expect_err("P + P should return an error"); - - // P + (-P) should return an error - p.add_incomplete(layouter.namespace(|| "P + (-P)"), p_neg) - .expect_err("P + (-P) should return an error"); - } - - Ok(()) - } -} diff --git a/halo2_gadgets/src/ecc/chip/constants.rs b/halo2_gadgets/src/ecc/chip/constants.rs deleted file mode 100644 index 90a989b9af..0000000000 --- a/halo2_gadgets/src/ecc/chip/constants.rs +++ /dev/null @@ -1,277 +0,0 @@ -//! Constants required for the ECC chip. - -use arrayvec::ArrayVec; -use group::{ - ff::{Field, PrimeField}, - Curve, -}; -use halo2_proofs::arithmetic::lagrange_interpolate; -use halo2curves::{pasta::pallas, CurveAffine}; - -/// Window size for fixed-base scalar multiplication -pub const FIXED_BASE_WINDOW_SIZE: usize = 3; - -/// $2^{`FIXED_BASE_WINDOW_SIZE`}$ -pub const H: usize = 1 << FIXED_BASE_WINDOW_SIZE; - -/// Number of windows for a full-width scalar -pub const NUM_WINDOWS: usize = - (pallas::Scalar::NUM_BITS as usize + FIXED_BASE_WINDOW_SIZE - 1) / FIXED_BASE_WINDOW_SIZE; - -/// Number of windows for a short signed scalar -pub const NUM_WINDOWS_SHORT: usize = - (L_SCALAR_SHORT + FIXED_BASE_WINDOW_SIZE - 1) / FIXED_BASE_WINDOW_SIZE; - -/// $\ell_\mathsf{value}$ -/// Number of bits in an unsigned short scalar. -pub(crate) const L_SCALAR_SHORT: usize = 64; - -/// The Pallas scalar field modulus is $q = 2^{254} + \mathsf{t_q}$. -/// -pub(crate) const T_Q: u128 = 45560315531506369815346746415080538113; - -/// The Pallas base field modulus is $p = 2^{254} + \mathsf{t_p}$. -/// -pub(crate) const T_P: u128 = 45560315531419706090280762371685220353; - -/// For each fixed base, we calculate its scalar multiples in three-bit windows. -/// Each window will have $2^3 = 8$ points. The tables are computed as described in -/// [the Halo 2 book](https://zcash.github.io/halo2/design/gadgets/ecc/fixed-base-scalar-mul.html#load-fixed-base). -fn compute_window_table(base: C, num_windows: usize) -> Vec<[C; H]> { - let mut window_table: Vec<[C; H]> = Vec::with_capacity(num_windows); - - // Generate window table entries for all windows but the last. - // For these first `num_windows - 1` windows, we compute the multiple [(k+2)*(2^3)^w]B. - // Here, w ranges from [0..`num_windows - 1`) - for w in 0..(num_windows - 1) { - window_table.push( - (0..H) - .map(|k| { - // scalar = (k+2)*(8^w) - let scalar = - C::Scalar::from(k as u64 + 2) * C::Scalar::from(H as u64).pow([w as u64]); - (base * scalar).to_affine() - }) - .collect::>() - .into_inner() - .unwrap(), - ); - } - - // Generate window table entries for the last window, w = `num_windows - 1`. - // For the last window, we compute [k * (2^3)^w - sum]B, where sum is defined - // as sum = \sum_{j = 0}^{`num_windows - 2`} 2^{3j+1} - let sum = (0..(num_windows - 1)).fold(C::Scalar::ZERO, |acc, j| { - acc + C::Scalar::from(2).pow([FIXED_BASE_WINDOW_SIZE as u64 * j as u64 + 1]) - }); - window_table.push( - (0..H) - .map(|k| { - // scalar = k * (2^3)^w - sum, where w = `num_windows - 1` - let scalar = C::Scalar::from(k as u64) - * C::Scalar::from(H as u64).pow([(num_windows - 1) as u64]) - - sum; - (base * scalar).to_affine() - }) - .collect::>() - .into_inner() - .unwrap(), - ); - - window_table -} - -/// For each window, we interpolate the $x$-coordinate. -/// Here, we pre-compute and store the coefficients of the interpolation polynomial. -pub fn compute_lagrange_coeffs(base: C, num_windows: usize) -> Vec<[C::Base; H]> { - // We are interpolating over the 3-bit window, k \in [0..8) - let points: Vec<_> = (0..H).map(|i| C::Base::from(i as u64)).collect(); - - let window_table = compute_window_table(base, num_windows); - - window_table - .iter() - .map(|window_points| { - let x_window_points: Vec<_> = window_points - .iter() - .map(|point| *point.coordinates().unwrap().x()) - .collect(); - lagrange_interpolate(&points, &x_window_points) - .into_iter() - .collect::>() - .into_inner() - .unwrap() - }) - .collect() -} - -/// For each window, $z$ is a field element such that for each point $(x, y)$ in the window: -/// - $z + y = u^2$ (some square in the field); and -/// - $z - y$ is not a square. -/// If successful, return a vector of `(z: u64, us: [C::Base; H])` for each window. -/// -/// This function was used to generate the `z`s and `u`s for the Orchard fixed -/// bases. The outputs of this function have been stored as constants, and it -/// is not called anywhere in this codebase. However, we keep this function here -/// as a utility for those who wish to use it with different parameters. -pub fn find_zs_and_us( - base: C, - num_windows: usize, -) -> Option> { - // Closure to find z and u's for one window - let find_z_and_us = |window_points: &[C]| { - assert_eq!(H, window_points.len()); - - let ys: Vec<_> = window_points - .iter() - .map(|point| *point.coordinates().unwrap().y()) - .collect(); - (0..(1000 * (1 << (2 * H)))).find_map(|z| { - ys.iter() - .map(|&y| { - if (-y + C::Base::from(z)).sqrt().is_none().into() { - (y + C::Base::from(z)).sqrt().into() - } else { - None - } - }) - .collect::>>() - .map(|us| (z, us.into_inner().unwrap())) - }) - }; - - let window_table = compute_window_table(base, num_windows); - window_table - .iter() - .map(|window_points| find_z_and_us(window_points)) - .collect() -} - -/// Test that the z-values and u-values satisfy the conditions: -/// 1. z + y = u^2, -/// 2. z - y is not a square -/// for the y-coordinate of each fixed-base multiple in each window. -#[cfg(any(test, feature = "test-dependencies"))] -#[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] -pub fn test_zs_and_us(base: C, z: &[u64], u: &[[[u8; 32]; H]], num_windows: usize) { - let window_table = compute_window_table(base, num_windows); - - for ((u, z), window_points) in u.iter().zip(z.iter()).zip(window_table) { - for (u, point) in u.iter().zip(window_points.iter()) { - let y = *point.coordinates().unwrap().y(); - let mut u_repr = ::Repr::default(); - u_repr.as_mut().copy_from_slice(u); - let u = C::Base::from_repr(u_repr).unwrap(); - assert_eq!(C::Base::from(*z) + y, u * u); // allow either square root - assert!(bool::from((C::Base::from(*z) - y).sqrt().is_none())); - } - } -} - -/// Test that Lagrange interpolation coefficients reproduce the correct x-coordinate -/// for each fixed-base multiple in each window. -#[cfg(any(test, feature = "test-dependencies"))] -#[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] -pub fn test_lagrange_coeffs(base: C, num_windows: usize) { - /// Evaluate y = f(x) given the coefficients of f(x) - fn evaluate(x: u8, coeffs: &[C::Base]) -> C::Base { - let x = C::Base::from(x as u64); - coeffs - .iter() - .rev() - .cloned() - .reduce(|acc, coeff| acc * x + coeff) - .unwrap_or(C::Base::ZERO) - } - - let lagrange_coeffs = compute_lagrange_coeffs(base, num_windows); - - // Check first 84 windows, i.e. `k_0, k_1, ..., k_83` - for (idx, coeffs) in lagrange_coeffs[0..(num_windows - 1)].iter().enumerate() { - // Test each three-bit chunk in this window. - for bits in 0..(H as u8) { - { - // Interpolate the x-coordinate using this window's coefficients - let interpolated_x = evaluate::(bits, coeffs); - - // Compute the actual x-coordinate of the multiple [(k+2)*(8^w)]B. - let point = base - * C::Scalar::from(bits as u64 + 2) - * C::Scalar::from(H as u64).pow([idx as u64]); - let x = *point.to_affine().coordinates().unwrap().x(); - - // Check that the interpolated x-coordinate matches the actual one. - assert_eq!(x, interpolated_x); - } - } - } - - // Check last window. - for bits in 0..(H as u8) { - // Interpolate the x-coordinate using the last window's coefficients - let interpolated_x = evaluate::(bits, &lagrange_coeffs[num_windows - 1]); - - // Compute the actual x-coordinate of the multiple [k * (8^84) - offset]B, - // where offset = \sum_{j = 0}^{83} 2^{3j+1} - let offset = (0..(num_windows - 1)).fold(C::Scalar::ZERO, |acc, w| { - acc + C::Scalar::from(2).pow([FIXED_BASE_WINDOW_SIZE as u64 * w as u64 + 1]) - }); - let scalar = C::Scalar::from(bits as u64) - * C::Scalar::from(H as u64).pow([(num_windows - 1) as u64]) - - offset; - let point = base * scalar; - let x = *point.to_affine().coordinates().unwrap().x(); - - // Check that the interpolated x-coordinate matches the actual one. - assert_eq!(x, interpolated_x); - } -} - -#[cfg(test)] -mod tests { - use ff::FromUniformBytes; - use group::{ff::Field, Curve, Group}; - use halo2curves::{pasta::pallas, CurveAffine}; - use proptest::prelude::*; - - use super::{compute_window_table, find_zs_and_us, test_lagrange_coeffs, H, NUM_WINDOWS}; - - prop_compose! { - /// Generate an arbitrary Pallas point. - pub fn arb_point()(bytes in prop::array::uniform32(0u8..)) -> pallas::Point { - // Instead of rejecting out-of-range bytes, let's reduce them. - let mut buf = [0; 64]; - buf[..32].copy_from_slice(&bytes); - let scalar = pallas::Scalar::from_uniform_bytes(&buf); - pallas::Point::generator() * scalar - } - } - - proptest! { - #[test] - fn lagrange_coeffs( - base in arb_point(), - ) { - test_lagrange_coeffs(base.to_affine(), NUM_WINDOWS); - } - } - - #[test] - fn zs_and_us() { - let base = pallas::Point::random(rand::rngs::OsRng); - let (z, u): (Vec, Vec<[pallas::Base; H]>) = - find_zs_and_us(base.to_affine(), NUM_WINDOWS) - .unwrap() - .into_iter() - .unzip(); - let window_table = compute_window_table(base.to_affine(), NUM_WINDOWS); - - for ((u, z), window_points) in u.iter().zip(z.iter()).zip(window_table) { - for (u, point) in u.iter().zip(window_points.iter()) { - let y = *point.coordinates().unwrap().y(); - assert_eq!(pallas::Base::from(*z) + y, u * u); // allow either square root - assert!(bool::from((pallas::Base::from(*z) - y).sqrt().is_none())); - } - } - } -} diff --git a/halo2_gadgets/src/ecc/chip/mul.rs b/halo2_gadgets/src/ecc/chip/mul.rs deleted file mode 100644 index 7896bf58bd..0000000000 --- a/halo2_gadgets/src/ecc/chip/mul.rs +++ /dev/null @@ -1,586 +0,0 @@ -use super::{add, EccPoint, NonIdentityEccPoint, ScalarVar, T_Q}; -use crate::{ - sinsemilla::primitives as sinsemilla, - utilities::{bool_check, lookup_range_check::LookupRangeCheckConfig, ternary}, -}; -use std::{ - convert::TryInto, - ops::{Deref, Range}, -}; - -use halo2_proofs::{ - arithmetic::Field, - circuit::{AssignedCell, Layouter, Region, Value}, - plonk::{Advice, Assigned, Column, ConstraintSystem, Constraints, Error, Selector}, - poly::Rotation, -}; -use halo2curves::group::ff::PrimeField; -use halo2curves::pasta::pallas; -use uint::construct_uint; - -mod complete; -pub(super) mod incomplete; -mod overflow; - -/// Number of bits for which complete addition needs to be used in variable-base -/// scalar multiplication -const NUM_COMPLETE_BITS: usize = 3; - -// Bits used in incomplete addition. k_{254} to k_{4} inclusive -const INCOMPLETE_LEN: usize = pallas::Scalar::NUM_BITS as usize - 1 - NUM_COMPLETE_BITS; -const INCOMPLETE_RANGE: Range = 0..INCOMPLETE_LEN; - -// Bits k_{254} to k_{4} inclusive are used in incomplete addition. -// The `hi` half is k_{254} to k_{130} inclusive (length 125 bits). -// (It is a coincidence that k_{130} matches the boundary of the -// overflow check described in [the book](https://zcash.github.io/halo2/design/gadgets/ecc/var-base-scalar-mul.html#overflow-check).) -const INCOMPLETE_HI_RANGE: Range = 0..INCOMPLETE_HI_LEN; -const INCOMPLETE_HI_LEN: usize = INCOMPLETE_LEN / 2; - -// Bits k_{254} to k_{4} inclusive are used in incomplete addition. -// The `lo` half is k_{129} to k_{4} inclusive (length 126 bits). -const INCOMPLETE_LO_RANGE: Range = INCOMPLETE_HI_LEN..INCOMPLETE_LEN; -const INCOMPLETE_LO_LEN: usize = INCOMPLETE_LEN - INCOMPLETE_HI_LEN; - -// Bits k_{3} to k_{1} inclusive are used in complete addition. -// Bit k_{0} is handled separately. -const COMPLETE_RANGE: Range = INCOMPLETE_LEN..(INCOMPLETE_LEN + NUM_COMPLETE_BITS); - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { - // Selector used to check switching logic on LSB - q_mul_lsb: Selector, - // Configuration used in complete addition - add_config: add::Config, - // Configuration used for `hi` bits of the scalar - hi_config: incomplete::Config, - // Configuration used for `lo` bits of the scalar - lo_config: incomplete::Config, - // Configuration used for complete addition part of double-and-add algorithm - complete_config: complete::Config, - // Configuration used to check for overflow - overflow_config: overflow::Config, -} - -impl Config { - pub(super) fn configure( - meta: &mut ConstraintSystem, - add_config: add::Config, - lookup_config: LookupRangeCheckConfig, - advices: [Column; 10], - ) -> Self { - let hi_config = incomplete::Config::configure( - meta, advices[9], advices[3], advices[0], advices[1], advices[4], advices[5], - ); - let lo_config = incomplete::Config::configure( - meta, advices[6], advices[7], advices[0], advices[1], advices[8], advices[2], - ); - let complete_config = complete::Config::configure(meta, advices[9], add_config); - let overflow_config = - overflow::Config::configure(meta, lookup_config, advices[6..9].try_into().unwrap()); - - let config = Self { - q_mul_lsb: meta.selector(), - add_config, - hi_config, - lo_config, - complete_config, - overflow_config, - }; - - config.create_gate(meta); - - assert_eq!( - config.hi_config.double_and_add.x_p, config.lo_config.double_and_add.x_p, - "x_p is shared across hi and lo halves." - ); - assert_eq!( - config.hi_config.y_p, config.lo_config.y_p, - "y_p is shared across hi and lo halves." - ); - - // For both hi_config and lo_config: - // z and lambda1 are assigned on the same row as the add_config output. - // Therefore, z and lambda1 must not overlap with add_config.x_qr, add_config.y_qr. - let add_config_outputs = config.add_config.output_columns(); - { - assert!( - !add_config_outputs.contains(&config.hi_config.z), - "incomplete config z cannot overlap with complete addition columns." - ); - assert!( - !add_config_outputs.contains(&config.hi_config.double_and_add.lambda_1), - "incomplete config lambda1 cannot overlap with complete addition columns." - ); - } - { - assert!( - !add_config_outputs.contains(&config.lo_config.z), - "incomplete config z cannot overlap with complete addition columns." - ); - assert!( - !add_config_outputs.contains(&config.lo_config.double_and_add.lambda_1), - "incomplete config lambda1 cannot overlap with complete addition columns." - ); - } - - config - } - - fn create_gate(&self, meta: &mut ConstraintSystem) { - // If `lsb` is 0, (x, y) = (x_p, -y_p). If `lsb` is 1, (x, y) = (0,0). - // https://p.z.cash/halo2-0.1:ecc-var-mul-lsb-gate?partial - meta.create_gate("LSB check", |meta| { - let q_mul_lsb = meta.query_selector(self.q_mul_lsb); - - let z_1 = meta.query_advice(self.complete_config.z_complete, Rotation::cur()); - let z_0 = meta.query_advice(self.complete_config.z_complete, Rotation::next()); - let x_p = meta.query_advice(self.add_config.x_p, Rotation::cur()); - let y_p = meta.query_advice(self.add_config.y_p, Rotation::cur()); - let base_x = meta.query_advice(self.add_config.x_p, Rotation::next()); - let base_y = meta.query_advice(self.add_config.y_p, Rotation::next()); - - // z_0 = 2 * z_1 + k_0 - // => k_0 = z_0 - 2 * z_1 - let lsb = z_0 - z_1 * pallas::Base::from(2); - - let bool_check = bool_check(lsb.clone()); - - // `lsb` = 0 => (x_p, y_p) = (x, -y) - // `lsb` = 1 => (x_p, y_p) = (0,0) - let lsb_x = ternary(lsb.clone(), x_p.clone(), x_p - base_x); - let lsb_y = ternary(lsb, y_p.clone(), y_p + base_y); - - Constraints::with_selector( - q_mul_lsb, - [ - ("bool_check", bool_check), - ("lsb_x", lsb_x), - ("lsb_y", lsb_y), - ], - ) - }); - } - - pub(super) fn assign( - &self, - mut layouter: impl Layouter, - alpha: AssignedCell, - base: &NonIdentityEccPoint, - ) -> Result<(EccPoint, ScalarVar), Error> { - let (result, zs): (EccPoint, Vec>) = layouter.assign_region( - || "variable-base scalar mul", - |mut region| { - let offset = 0; - - // Case `base` into an `EccPoint` for later use. - let base_point: EccPoint = base.clone().into(); - - // Decompose `k = alpha + t_q` bitwise (big-endian bit order). - let bits = decompose_for_scalar_mul(alpha.value()); - - // Define ranges for each part of the algorithm. - let bits_incomplete_hi = &bits[INCOMPLETE_HI_RANGE]; - let bits_incomplete_lo = &bits[INCOMPLETE_LO_RANGE]; - let lsb = bits[pallas::Scalar::NUM_BITS as usize - 1]; - - // Initialize the accumulator `acc = [2]base` using complete addition. - let acc = - self.add_config - .assign_region(&base_point, &base_point, offset, &mut region)?; - - // Increase the offset by 1 after complete addition. - let offset = offset + 1; - - // Initialize the running sum for scalar decomposition to zero. - // - // `incomplete::Config::double_and_add` will copy this cell directly into - // itself. This is fine because we are just assigning the same value to - // the same cell twice, and then applying an equality constraint between - // the cell and itself (which the permutation argument treats as a no-op). - let z_init = Z(region.assign_advice_from_constant( - || "z_init = 0", - self.hi_config.z, - offset, - pallas::Base::zero(), - )?); - - // Double-and-add (incomplete addition) for the `hi` half of the scalar decomposition - let (x_a, y_a, zs_incomplete_hi) = self.hi_config.double_and_add( - &mut region, - offset, - base, - bits_incomplete_hi, - (X(acc.x), Y(acc.y), z_init.clone()), - )?; - - // Double-and-add (incomplete addition) for the `lo` half of the scalar decomposition - let z = zs_incomplete_hi.last().expect("should not be empty"); - let (x_a, y_a, zs_incomplete_lo) = self.lo_config.double_and_add( - &mut region, - offset, - base, - bits_incomplete_lo, - (x_a, y_a, z.clone()), - )?; - - // Move from incomplete addition to complete addition. - // Inside incomplete::double_and_add, the offset was increased once after initialization - // of the running sum. - // Then, the final assignment of double-and-add was made on row + offset + 1. - // Outside of incomplete addition, we must account for these offset increases by adding - // 2 to the incomplete addition length. - assert!(INCOMPLETE_LO_RANGE.len() >= INCOMPLETE_HI_RANGE.len()); - let offset = offset + INCOMPLETE_LO_RANGE.len() + 2; - - // Complete addition - let (acc, zs_complete) = { - let z = zs_incomplete_lo.last().expect("should not be empty"); - // Bits used in complete addition. k_{3} to k_{1} inclusive - // The LSB k_{0} is handled separately. - let bits_complete = &bits[COMPLETE_RANGE]; - self.complete_config.assign_region( - &mut region, - offset, - bits_complete, - &base_point, - x_a, - y_a, - z.clone(), - )? - }; - - // Each iteration of the complete addition uses two rows. - let offset = offset + COMPLETE_RANGE.len() * 2; - - // Process the least significant bit - let z_1 = zs_complete.last().unwrap().clone(); - let (result, z_0) = self.process_lsb(&mut region, offset, base, acc, z_1, lsb)?; - - #[cfg(test)] - // Check that the correct multiple is obtained. - { - use group::Curve; - - let base = base.point(); - let alpha = alpha - .value() - .map(|alpha| pallas::Scalar::from_repr(alpha.to_repr()).unwrap()); - let real_mul = base.zip(alpha).map(|(base, alpha)| base * alpha); - let result = result.point(); - - real_mul - .zip(result) - .assert_if_known(|(real_mul, result)| &real_mul.to_affine() == result); - } - - let zs = { - let mut zs = std::iter::empty() - .chain(Some(z_init)) - .chain(zs_incomplete_hi.into_iter()) - .chain(zs_incomplete_lo.into_iter()) - .chain(zs_complete.into_iter()) - .chain(Some(z_0)) - .collect::>(); - assert_eq!(zs.len(), pallas::Scalar::NUM_BITS as usize + 1); - - // This reverses zs to give us [z_0, z_1, ..., z_{254}, z_{255}]. - zs.reverse(); - zs - }; - - Ok((result, zs)) - }, - )?; - - self.overflow_config.overflow_check( - layouter.namespace(|| "overflow check"), - alpha.clone(), - &zs, - )?; - - Ok((result, ScalarVar::BaseFieldElem(alpha))) - } - - /// Processes the final scalar bit `k_0`. - /// - /// Assumptions for this sub-region: - /// - `acc_x` and `acc_y` are assigned in row `offset` by the previous complete - /// addition. They will be copied into themselves. - /// - `z_1 is assigned in row `offset` by the mul::complete region assignment. We only - /// use its value here. - /// - /// `x_p` and `y_p` are assigned here, and then copied into themselves by the complete - /// addition subregion. - /// - /// ```text - /// | x_p | y_p | acc_x | acc_y | complete addition | z_1 | q_mul_lsb = 1 - /// |base_x|base_y| res_x | res_y | | | | | | z_0 | - /// ``` - /// - /// [Specification](https://p.z.cash/halo2-0.1:ecc-var-mul-lsb-gate?partial). - fn process_lsb( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - base: &NonIdentityEccPoint, - acc: EccPoint, - z_1: Z, - lsb: Value, - ) -> Result<(EccPoint, Z), Error> { - // Enforce switching logic on LSB using a custom gate - self.q_mul_lsb.enable(region, offset)?; - - // z_1 has been assigned at (z_complete, offset). - // Assign z_0 = 2⋅z_1 + k_0 - let z_0 = { - let z_0_val = z_1.value().zip(lsb).map(|(z_1, lsb)| { - let lsb = pallas::Base::from(lsb as u64); - z_1 * pallas::Base::from(2) + lsb - }); - let z_0_cell = region.assign_advice( - || "z_0", - self.complete_config.z_complete, - offset + 1, - || z_0_val, - )?; - - Z(z_0_cell) - }; - - // Copy in `base_x`, `base_y` to use in the LSB gate - base.x() - .copy_advice(|| "copy base_x", region, self.add_config.x_p, offset + 1)?; - base.y() - .copy_advice(|| "copy base_y", region, self.add_config.y_p, offset + 1)?; - - // If `lsb` is 0, return `Acc + (-P)`. If `lsb` is 1, simply return `Acc + 0`. - let x = lsb.and_then(|lsb| { - if !lsb { - base.x.value().cloned() - } else { - Value::known(Assigned::Zero) - } - }); - - let y = lsb.and_then(|lsb| { - if !lsb { - -base.y.value() - } else { - Value::known(Assigned::Zero) - } - }); - - let x_cell = region.assign_advice(|| "x", self.add_config.x_p, offset, || x)?; - let y_cell = region.assign_advice(|| "y", self.add_config.y_p, offset, || y)?; - - let p = EccPoint { - x: x_cell, - y: y_cell, - }; - - // Return the result of the final complete addition as `[scalar]B` - let result = self.add_config.assign_region(&p, &acc, offset, region)?; - - Ok((result, z_0)) - } -} - -#[derive(Clone, Debug)] -// `x`-coordinate of the accumulator. -struct X(AssignedCell, F>); -impl Deref for X { - type Target = AssignedCell, F>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Clone, Debug)] -// `y`-coordinate of the accumulator. -struct Y(AssignedCell, F>); -impl Deref for Y { - type Target = AssignedCell, F>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Clone, Debug)] -// Cumulative sum `z` used to decompose the scalar. -struct Z(AssignedCell); -impl Deref for Z { - type Target = AssignedCell; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -// https://p.z.cash/halo2-0.1:ecc-var-mul-witness-scalar?partial -#[allow(clippy::assign_op_pattern)] -#[allow(clippy::ptr_offset_with_cast)] -fn decompose_for_scalar_mul(scalar: Value<&pallas::Base>) -> Vec> { - construct_uint! { - struct U256(4); - } - - let bitstring = scalar.map(|scalar| { - // We use `k = scalar + t_q` in the double-and-add algorithm, where - // the scalar field `F_q = 2^254 + t_q`. - // Note that the addition `scalar + t_q` is not reduced. - // - let scalar = U256::from_little_endian(&scalar.to_repr()); - let t_q = U256::from_little_endian(&T_Q.to_le_bytes()); - let k = scalar + t_q; - - // Little-endian bit representation of `k`. - let bitstring = { - let mut le_bytes = [0u8; 32]; - k.to_little_endian(&mut le_bytes); - le_bytes - .into_iter() - .flat_map(|byte| (0..8).map(move |shift| (byte >> shift) % 2 == 1)) - }; - - // Take the first 255 bits. - bitstring - .take(pallas::Scalar::NUM_BITS as usize) - .collect::>() - }); - - // Transpose. - let mut bitstring = bitstring.transpose_vec(pallas::Scalar::NUM_BITS as usize); - // Reverse to get the big-endian bit representation. - bitstring.reverse(); - bitstring -} - -#[cfg(test)] -pub mod tests { - use group::{ - ff::{Field, PrimeField}, - Curve, - }; - use halo2_proofs::{ - circuit::{Chip, Layouter, Value}, - plonk::Error, - }; - use halo2curves::pasta::pallas; - use rand::rngs::OsRng; - - use crate::{ - ecc::{ - chip::{EccChip, EccPoint}, - tests::TestFixedBases, - EccInstructions, NonIdentityPoint, Point, ScalarVar, - }, - utilities::UtilitiesInstructions, - }; - - pub(crate) fn test_mul( - chip: EccChip, - mut layouter: impl Layouter, - p: &NonIdentityPoint>, - p_val: pallas::Affine, - ) -> Result<(), Error> { - let column = chip.config().advices[0]; - - fn constrain_equal_non_id< - EccChip: EccInstructions + Clone + Eq + std::fmt::Debug, - >( - chip: EccChip, - mut layouter: impl Layouter, - base_val: pallas::Affine, - scalar_val: pallas::Base, - result: Point, - ) -> Result<(), Error> { - // Move scalar from base field into scalar field (which always fits - // for Pallas). - let scalar = pallas::Scalar::from_repr(scalar_val.to_repr()).unwrap(); - let expected = NonIdentityPoint::new( - chip, - layouter.namespace(|| "expected point"), - Value::known((base_val * scalar).to_affine()), - )?; - result.constrain_equal(layouter.namespace(|| "constrain result"), &expected) - } - - // [a]B - { - let scalar_val = pallas::Base::random(OsRng); - let (result, _) = { - let scalar = chip.load_private( - layouter.namespace(|| "random scalar"), - column, - Value::known(scalar_val), - )?; - let scalar = ScalarVar::from_base( - chip.clone(), - layouter.namespace(|| "ScalarVar from_base"), - &scalar, - )?; - p.mul(layouter.namespace(|| "random [a]B"), scalar)? - }; - constrain_equal_non_id( - chip.clone(), - layouter.namespace(|| "random [a]B"), - p_val, - scalar_val, - result, - )?; - } - - // [0]B should return (0,0) since variable-base scalar multiplication - // uses complete addition for the final bits of the scalar. - { - let scalar_val = pallas::Base::zero(); - let (result, _) = { - let scalar = chip.load_private( - layouter.namespace(|| "zero"), - column, - Value::known(scalar_val), - )?; - let scalar = ScalarVar::from_base( - chip.clone(), - layouter.namespace(|| "ScalarVar from_base"), - &scalar, - )?; - p.mul(layouter.namespace(|| "[0]B"), scalar)? - }; - result - .inner() - .is_identity() - .assert_if_known(|is_identity| *is_identity); - } - - // [-1]B (the largest possible base field element) - { - let scalar_val = -pallas::Base::one(); - let (result, _) = { - let scalar = chip.load_private( - layouter.namespace(|| "-1"), - column, - Value::known(scalar_val), - )?; - let scalar = ScalarVar::from_base( - chip.clone(), - layouter.namespace(|| "ScalarVar from_base"), - &scalar, - )?; - p.mul(layouter.namespace(|| "[-1]B"), scalar)? - }; - constrain_equal_non_id( - chip, - layouter.namespace(|| "[-1]B"), - p_val, - scalar_val, - result, - )?; - } - - Ok(()) - } -} diff --git a/halo2_gadgets/src/ecc/chip/mul/complete.rs b/halo2_gadgets/src/ecc/chip/mul/complete.rs deleted file mode 100644 index d23294d2fb..0000000000 --- a/halo2_gadgets/src/ecc/chip/mul/complete.rs +++ /dev/null @@ -1,196 +0,0 @@ -use super::super::{add, EccPoint}; -use super::{COMPLETE_RANGE, X, Y, Z}; -use crate::utilities::{bool_check, ternary}; - -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Expression, Selector}, - poly::Rotation, -}; - -use halo2curves::pasta::pallas; - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { - // Selector used to constrain the cells used in complete addition. - q_mul_decompose_var: Selector, - // Advice column used to decompose scalar in complete addition. - pub z_complete: Column, - // Configuration used in complete addition - add_config: add::Config, -} - -impl Config { - pub(super) fn configure( - meta: &mut ConstraintSystem, - z_complete: Column, - add_config: add::Config, - ) -> Self { - meta.enable_equality(z_complete); - - let config = Self { - q_mul_decompose_var: meta.selector(), - z_complete, - add_config, - }; - - config.create_gate(meta); - - config - } - - /// Gate used to check scalar decomposition is correct. - /// This is used to check the bits used in complete addition, since the incomplete - /// addition gate (controlled by `q_mul`) already checks scalar decomposition for - /// the other bits. - fn create_gate(&self, meta: &mut ConstraintSystem) { - // | y_p | z_complete | - // -------------------- - // | y_p | z_{i + 1} | - // | | base_y | - // | | z_i | - // https://p.z.cash/halo2-0.1:ecc-var-mul-complete-gate - meta.create_gate( - "Decompose scalar for complete bits of variable-base mul", - |meta| { - let q_mul_decompose_var = meta.query_selector(self.q_mul_decompose_var); - // z_{i + 1} - let z_prev = meta.query_advice(self.z_complete, Rotation::prev()); - // z_i - let z_next = meta.query_advice(self.z_complete, Rotation::next()); - - // k_{i} = z_{i} - 2⋅z_{i+1} - let k = z_next - Expression::Constant(pallas::Base::from(2)) * z_prev; - // (k_i) ⋅ (1 - k_i) = 0 - let bool_check = bool_check(k.clone()); - - // base_y - let base_y = meta.query_advice(self.z_complete, Rotation::cur()); - // y_p - let y_p = meta.query_advice(self.add_config.y_p, Rotation::prev()); - - // k_i = 0 => y_p = -base_y - // k_i = 1 => y_p = base_y - let y_switch = ternary(k, base_y.clone() - y_p.clone(), base_y + y_p); - - Constraints::with_selector( - q_mul_decompose_var, - [("bool_check", bool_check), ("y_switch", y_switch)], - ) - }, - ); - } - - #[allow(clippy::type_complexity)] - #[allow(non_snake_case)] - #[allow(clippy::too_many_arguments)] - pub(super) fn assign_region( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - bits: &[Value], - base: &EccPoint, - x_a: X, - y_a: Y, - z: Z, - ) -> Result<(EccPoint, Vec>), Error> { - // Make sure we have the correct number of bits for the complete addition - // part of variable-base scalar mul. - assert_eq!(bits.len(), COMPLETE_RANGE.len()); - - // Enable selectors for complete range - for row in 0..COMPLETE_RANGE.len() { - // Each iteration uses 2 rows (two complete additions) - let row = 2 * row; - // Check scalar decomposition for each iteration. Since the gate enabled by - // `q_mul_decompose_var` queries the previous row, we enable the selector on - // `row + offset + 1` (instead of `row + offset`). - self.q_mul_decompose_var.enable(region, row + offset + 1)?; - } - - // Use x_a, y_a output from incomplete addition - let mut acc = EccPoint { x: x_a.0, y: y_a.0 }; - - // Copy running sum `z` from incomplete addition - let mut z = { - let z = z.copy_advice( - || "Copy `z` running sum from incomplete addition", - region, - self.z_complete, - offset, - )?; - Z(z) - }; - - // Store interstitial running sum `z`s in vector - let mut zs: Vec> = Vec::with_capacity(bits.len()); - - // Complete addition - for (iter, k) in bits.iter().enumerate() { - // Each iteration uses 2 rows (two complete additions) - let row = 2 * iter; - - // | x_p | y_p | x_qr | y_qr | z_complete | - // ------------------------------------------ - // | U_x | U_y | acc_x | acc_y | z_{i + 1} | row + offset - // |acc_x|acc_y|acc+U_x|acc+U_y| base_y | - // | | | res_x | res_y | z_i | - - // Update `z`. - z = { - // z_next = z_cur * 2 + k_next - let z_val = z.value() * Value::known(pallas::Base::from(2)) - + k.map(|k| pallas::Base::from(k as u64)); - let z_cell = - region.assign_advice(|| "z", self.z_complete, row + offset + 2, || z_val)?; - Z(z_cell) - }; - zs.push(z.clone()); - - // Assign `y_p` for complete addition. - let y_p = { - let base_y = base.y.copy_advice( - || "Copy `base.y`", - region, - self.z_complete, - row + offset + 1, - )?; - - // If the bit is set, use `y`; if the bit is not set, use `-y` - let y_p = - base_y - .value() - .cloned() - .zip(k.as_ref()) - .map(|(base_y, k)| if !k { -base_y } else { base_y }); - - // Assign the conditionally-negated y coordinate into the cell it will be - // used from by both the complete addition gate, and the decomposition and - // conditional negation gate. - // - // The complete addition gate will copy this cell onto itself. This is - // fine because we are just assigning the same value to the same cell - // twice, and then applying an equality constraint between the cell and - // itself (which the permutation argument treats as a no-op). - region.assign_advice(|| "y_p", self.add_config.y_p, row + offset, || y_p)? - }; - - // U = P if the bit is set; U = -P is the bit is not set. - let U = EccPoint { - x: base.x.clone(), - y: y_p, - }; - - // Acc + U - let tmp_acc = self - .add_config - .assign_region(&U, &acc, row + offset, region)?; - - // Acc + U + Acc - acc = self - .add_config - .assign_region(&acc, &tmp_acc, row + offset + 1, region)?; - } - Ok((acc, zs)) - } -} diff --git a/halo2_gadgets/src/ecc/chip/mul/incomplete.rs b/halo2_gadgets/src/ecc/chip/mul/incomplete.rs deleted file mode 100644 index 9b1d7494e6..0000000000 --- a/halo2_gadgets/src/ecc/chip/mul/incomplete.rs +++ /dev/null @@ -1,373 +0,0 @@ -use super::super::NonIdentityEccPoint; -use super::{X, Y, Z}; -use crate::utilities::bool_check; -use ff::PrimeField; -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::{ - Advice, Column, ConstraintSystem, Constraints, Error, Expression, Selector, VirtualCells, - }, - poly::Rotation, -}; -use halo2curves::pasta::pallas; - -/// A helper struct for implementing single-row double-and-add using incomplete addition. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub(crate) struct DoubleAndAdd { - // x-coordinate of the accumulator in each double-and-add iteration. - pub(crate) x_a: Column, - // x-coordinate of the point being added in each double-and-add iteration. - pub(crate) x_p: Column, - // lambda1 in each double-and-add iteration. - pub(crate) lambda_1: Column, - // lambda2 in each double-and-add iteration. - pub(crate) lambda_2: Column, -} - -impl DoubleAndAdd { - /// Derives the expression `x_r = lambda_1^2 - x_a - x_p`. - pub(crate) fn x_r( - &self, - meta: &mut VirtualCells, - rotation: Rotation, - ) -> Expression { - let x_a = meta.query_advice(self.x_a, rotation); - let x_p = meta.query_advice(self.x_p, rotation); - let lambda_1 = meta.query_advice(self.lambda_1, rotation); - lambda_1.square() - x_a - x_p - } - - /// Derives the expression `Y_A = (lambda_1 + lambda_2) * (x_a - x_r)`. - /// - /// Note that this is missing the factor of `1/2`; the Sinsemilla constraints factor - /// it out, so we leave it up to the caller to handle it. - #[allow(non_snake_case)] - pub(crate) fn Y_A( - &self, - meta: &mut VirtualCells, - rotation: Rotation, - ) -> Expression { - let x_a = meta.query_advice(self.x_a, rotation); - let lambda_1 = meta.query_advice(self.lambda_1, rotation); - let lambda_2 = meta.query_advice(self.lambda_2, rotation); - (lambda_1 + lambda_2) * (x_a - self.x_r(meta, rotation)) - } -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub(crate) struct Config { - // Selector constraining the first row of incomplete addition. - pub(super) q_mul_1: Selector, - // Selector constraining the main loop of incomplete addition. - pub(super) q_mul_2: Selector, - // Selector constraining the last row of incomplete addition. - pub(super) q_mul_3: Selector, - // Cumulative sum used to decompose the scalar. - pub(super) z: Column, - // Logic specific to merged double-and-add. - pub(super) double_and_add: DoubleAndAdd, - // y-coordinate of the point being added in each double-and-add iteration. - pub(super) y_p: Column, -} - -impl Config { - pub(super) fn configure( - meta: &mut ConstraintSystem, - z: Column, - x_a: Column, - x_p: Column, - y_p: Column, - lambda_1: Column, - lambda_2: Column, - ) -> Self { - meta.enable_equality(z); - meta.enable_equality(lambda_1); - - let config = Self { - q_mul_1: meta.selector(), - q_mul_2: meta.selector(), - q_mul_3: meta.selector(), - z, - double_and_add: DoubleAndAdd { - x_a, - x_p, - lambda_1, - lambda_2, - }, - y_p, - }; - - config.create_gate(meta); - - config - } - - // Gate for incomplete addition part of variable-base scalar multiplication. - fn create_gate(&self, meta: &mut ConstraintSystem) { - // Closure to compute x_{R,i} = λ_{1,i}^2 - x_{A,i} - x_{P,i} - let x_r = |meta: &mut VirtualCells, rotation: Rotation| { - self.double_and_add.x_r(meta, rotation) - }; - - // Closure to compute y_{A,i} = (λ_{1,i} + λ_{2,i}) * (x_{A,i} - x_{R,i}) / 2 - let y_a = |meta: &mut VirtualCells, rotation: Rotation| { - self.double_and_add.Y_A(meta, rotation) * pallas::Base::TWO_INV - }; - - // Constraints used for q_mul_{2, 3} == 1 - // https://p.z.cash/halo2-0.1:ecc-var-mul-incomplete-main-loop?partial - // https://p.z.cash/halo2-0.1:ecc-var-mul-incomplete-last-row?partial - let for_loop = |meta: &mut VirtualCells, - y_a_next: Expression| { - let one = Expression::Constant(pallas::Base::one()); - - // z_i - let z_cur = meta.query_advice(self.z, Rotation::cur()); - // z_{i+1} - let z_prev = meta.query_advice(self.z, Rotation::prev()); - // x_{A,i} - let x_a_cur = meta.query_advice(self.double_and_add.x_a, Rotation::cur()); - // x_{A,i-1} - let x_a_next = meta.query_advice(self.double_and_add.x_a, Rotation::next()); - // x_{P,i} - let x_p_cur = meta.query_advice(self.double_and_add.x_p, Rotation::cur()); - // y_{P,i} - let y_p_cur = meta.query_advice(self.y_p, Rotation::cur()); - // λ_{1,i} - let lambda1_cur = meta.query_advice(self.double_and_add.lambda_1, Rotation::cur()); - // λ_{2,i} - let lambda2_cur = meta.query_advice(self.double_and_add.lambda_2, Rotation::cur()); - - let y_a_cur = y_a(meta, Rotation::cur()); - - // The current bit in the scalar decomposition, k_i = z_i - 2⋅z_{i+1}. - // Recall that we assigned the cumulative variable `z_i` in descending order, - // i from n down to 0. So z_{i+1} corresponds to the `z_prev` query. - let k = z_cur - z_prev * pallas::Base::from(2); - // Check booleanity of decomposition. - let bool_check = bool_check(k.clone()); - - // λ_{1,i}⋅(x_{A,i} − x_{P,i}) − y_{A,i} + (2k_i - 1) y_{P,i} = 0 - let gradient_1 = lambda1_cur * (x_a_cur.clone() - x_p_cur) - y_a_cur.clone() - + (k * pallas::Base::from(2) - one) * y_p_cur; - - // λ_{2,i}^2 − x_{A,i-1} − x_{R,i} − x_{A,i} = 0 - let secant_line = lambda2_cur.clone().square() - - x_a_next.clone() - - x_r(meta, Rotation::cur()) - - x_a_cur.clone(); - - // λ_{2,i}⋅(x_{A,i} − x_{A,i-1}) − y_{A,i} − y_{A,i-1} = 0 - let gradient_2 = lambda2_cur * (x_a_cur - x_a_next) - y_a_cur - y_a_next; - - std::iter::empty() - .chain(Some(("bool_check", bool_check))) - .chain(Some(("gradient_1", gradient_1))) - .chain(Some(("secant_line", secant_line))) - .chain(Some(("gradient_2", gradient_2))) - }; - - // q_mul_1 == 1 checks - // https://p.z.cash/halo2-0.1:ecc-var-mul-incomplete-first-row - meta.create_gate("q_mul_1 == 1 checks", |meta| { - let q_mul_1 = meta.query_selector(self.q_mul_1); - - let y_a_next = y_a(meta, Rotation::next()); - let y_a_witnessed = meta.query_advice(self.double_and_add.lambda_1, Rotation::cur()); - Constraints::with_selector(q_mul_1, Some(("init y_a", y_a_witnessed - y_a_next))) - }); - - // q_mul_2 == 1 checks - // https://p.z.cash/halo2-0.1:ecc-var-mul-incomplete-main-loop?partial - meta.create_gate("q_mul_2 == 1 checks", |meta| { - let q_mul_2 = meta.query_selector(self.q_mul_2); - - let y_a_next = y_a(meta, Rotation::next()); - - // x_{P,i} - let x_p_cur = meta.query_advice(self.double_and_add.x_p, Rotation::cur()); - // x_{P,i-1} - let x_p_next = meta.query_advice(self.double_and_add.x_p, Rotation::next()); - // y_{P,i} - let y_p_cur = meta.query_advice(self.y_p, Rotation::cur()); - // y_{P,i-1} - let y_p_next = meta.query_advice(self.y_p, Rotation::next()); - - // The base used in double-and-add remains constant. We check that its - // x- and y- coordinates are the same throughout. - let x_p_check = x_p_cur - x_p_next; - let y_p_check = y_p_cur - y_p_next; - - Constraints::with_selector( - q_mul_2, - std::iter::empty() - .chain(Some(("x_p_check", x_p_check))) - .chain(Some(("y_p_check", y_p_check))) - .chain(for_loop(meta, y_a_next)), - ) - }); - - // q_mul_3 == 1 checks - // https://p.z.cash/halo2-0.1:ecc-var-mul-incomplete-last-row?partial - meta.create_gate("q_mul_3 == 1 checks", |meta| { - let q_mul_3 = meta.query_selector(self.q_mul_3); - let y_a_final = meta.query_advice(self.double_and_add.lambda_1, Rotation::next()); - Constraints::with_selector(q_mul_3, for_loop(meta, y_a_final)) - }); - } - - /// We perform incomplete addition on all but the last three bits of the - /// decomposed scalar. - /// We split the bits in the incomplete addition range into "hi" and "lo" - /// halves and process them side by side, using the same rows but with - /// non-overlapping columns. The base is never the identity point even at - /// the boundary between halves. - /// Returns (x, y, z). - #[allow(clippy::type_complexity)] - pub(super) fn double_and_add( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - base: &NonIdentityEccPoint, - bits: &[Value], - acc: (X, Y, Z), - ) -> Result<(X, Y, Vec>), Error> { - // Check that we have the correct number of bits for this double-and-add. - assert_eq!(bits.len(), NUM_BITS); - - // Handle exceptional cases - let (x_p, y_p) = (base.x.value().cloned(), base.y.value().cloned()); - let (x_a, y_a) = (acc.0.value().cloned(), acc.1.value().cloned()); - - x_a.zip(y_a) - .zip(x_p.zip(y_p)) - .error_if_known_and(|((x_a, y_a), (x_p, y_p))| { - // A is point at infinity - (x_p.is_zero_vartime() && y_p.is_zero_vartime()) - // Q is point at infinity - || (x_a.is_zero_vartime() && y_a.is_zero_vartime()) - // x_p = x_a - || (x_p == x_a) - })?; - - // Set q_mul values - { - // q_mul_1 = 1 on offset 0 - self.q_mul_1.enable(region, offset)?; - - let offset = offset + 1; - // q_mul_2 = 1 on all rows after offset 0, excluding the last row. - for idx in 0..(NUM_BITS - 1) { - self.q_mul_2.enable(region, offset + idx)?; - } - - // q_mul_3 = 1 on the last row. - self.q_mul_3.enable(region, offset + NUM_BITS - 1)?; - } - - // Initialise double-and-add - let (mut x_a, mut y_a, mut z) = { - // Initialise the running `z` sum for the scalar bits. - let z = acc.2.copy_advice(|| "starting z", region, self.z, offset)?; - - // Initialise acc - let x_a = acc.0.copy_advice( - || "starting x_a", - region, - self.double_and_add.x_a, - offset + 1, - )?; - let y_a = acc.1.copy_advice( - || "starting y_a", - region, - self.double_and_add.lambda_1, - offset, - )?; - - (x_a, y_a.value().cloned(), z) - }; - - // Increase offset by 1; we used row 0 for initializing `z`. - let offset = offset + 1; - - // Initialise vector to store all interstitial `z` running sum values. - let mut zs: Vec> = Vec::with_capacity(bits.len()); - - // Incomplete addition - for (row, k) in bits.iter().enumerate() { - // z_{i} = 2 * z_{i+1} + k_i - // https://p.z.cash/halo2-0.1:ecc-var-mul-witness-scalar?partial - let z_val = z - .value() - .zip(k.as_ref()) - .map(|(z_val, k)| pallas::Base::from(2) * z_val + pallas::Base::from(*k as u64)); - z = region.assign_advice(|| "z", self.z, row + offset, || z_val)?; - zs.push(Z(z.clone())); - - // Assign `x_p`, `y_p` - region.assign_advice(|| "x_p", self.double_and_add.x_p, row + offset, || x_p)?; - region.assign_advice(|| "y_p", self.y_p, row + offset, || y_p)?; - - // If the bit is set, use `y`; if the bit is not set, use `-y` - let y_p = y_p - .zip(k.as_ref()) - .map(|(y_p, k)| if !k { -y_p } else { y_p }); - - // Compute and assign λ1⋅(x_A − x_P) = y_A − y_P - let lambda1 = y_a - .zip(y_p) - .zip(x_a.value()) - .zip(x_p) - .map(|(((y_a, y_p), x_a), x_p)| (y_a - y_p) * (x_a - x_p).invert()); - region.assign_advice( - || "lambda1", - self.double_and_add.lambda_1, - row + offset, - || lambda1, - )?; - - // x_R = λ1^2 - x_A - x_P - let x_r = lambda1 - .zip(x_a.value()) - .zip(x_p) - .map(|((lambda1, x_a), x_p)| lambda1.square() - x_a - x_p); - - // λ2 = (2(y_A) / (x_A - x_R)) - λ1 - let lambda2 = - lambda1 - .zip(y_a) - .zip(x_a.value()) - .zip(x_r) - .map(|(((lambda1, y_a), x_a), x_r)| { - y_a * pallas::Base::from(2) * (x_a - x_r).invert() - lambda1 - }); - region.assign_advice( - || "lambda2", - self.double_and_add.lambda_2, - row + offset, - || lambda2, - )?; - - // Compute and assign `x_a` for the next row - let x_a_new = lambda2.square() - x_a.value() - x_r; - y_a = lambda2 * (x_a.value() - x_a_new) - y_a; - let x_a_val = x_a_new; - x_a = region.assign_advice( - || "x_a", - self.double_and_add.x_a, - row + offset + 1, - || x_a_val, - )?; - } - - // Witness final y_a - let y_a = region.assign_advice( - || "y_a", - self.double_and_add.lambda_1, - offset + NUM_BITS, - || y_a, - )?; - - Ok((X(x_a), Y(y_a), zs)) - } -} diff --git a/halo2_gadgets/src/ecc/chip/mul/overflow.rs b/halo2_gadgets/src/ecc/chip/mul/overflow.rs deleted file mode 100644 index 3625ff73db..0000000000 --- a/halo2_gadgets/src/ecc/chip/mul/overflow.rs +++ /dev/null @@ -1,208 +0,0 @@ -use super::{T_Q, Z}; -use crate::{ - sinsemilla::primitives as sinsemilla, utilities::lookup_range_check::LookupRangeCheckConfig, -}; - -use halo2_proofs::circuit::AssignedCell; -use halo2_proofs::{ - circuit::Layouter, - plonk::{Advice, Assigned, Column, ConstraintSystem, Constraints, Error, Expression, Selector}, - poly::Rotation, -}; -use halo2curves::group::ff::PrimeField; -use halo2curves::pasta::pallas; - -use std::iter; - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { - // Selector to check z_0 = alpha + t_q (mod p) - q_mul_overflow: Selector, - // 10-bit lookup table - lookup_config: LookupRangeCheckConfig, - // Advice columns - advices: [Column; 3], -} - -impl Config { - pub(super) fn configure( - meta: &mut ConstraintSystem, - lookup_config: LookupRangeCheckConfig, - advices: [Column; 3], - ) -> Self { - for advice in advices.iter() { - meta.enable_equality(*advice); - } - - let config = Self { - q_mul_overflow: meta.selector(), - lookup_config, - advices, - }; - - config.create_gate(meta); - - config - } - - fn create_gate(&self, meta: &mut ConstraintSystem) { - // https://p.z.cash/halo2-0.1:ecc-var-mul-overflow - meta.create_gate("overflow checks", |meta| { - let q_mul_overflow = meta.query_selector(self.q_mul_overflow); - - // Constant expressions - let one = Expression::Constant(pallas::Base::one()); - let two_pow_124 = Expression::Constant(pallas::Base::from_u128(1 << 124)); - let two_pow_130 = - two_pow_124.clone() * Expression::Constant(pallas::Base::from_u128(1 << 6)); - - let z_0 = meta.query_advice(self.advices[0], Rotation::prev()); - let z_130 = meta.query_advice(self.advices[0], Rotation::cur()); - let eta = meta.query_advice(self.advices[0], Rotation::next()); - - let k_254 = meta.query_advice(self.advices[1], Rotation::prev()); - let alpha = meta.query_advice(self.advices[1], Rotation::cur()); - - // s_minus_lo_130 = s - sum_{i = 0}^{129} 2^i ⋅ s_i - let s_minus_lo_130 = meta.query_advice(self.advices[1], Rotation::next()); - - let s = meta.query_advice(self.advices[2], Rotation::cur()); - let s_check = s - (alpha.clone() + k_254.clone() * two_pow_130); - - // q = 2^254 + t_q is the Pallas scalar field modulus. - // We cast t_q into the base field to check alpha + t_q (mod p). - let t_q = Expression::Constant(pallas::Base::from_u128(T_Q)); - - // z_0 - alpha - t_q = 0 (mod p) - let recovery = z_0 - alpha - t_q; - - // k_254 * (z_130 - 2^124) = 0 - let lo_zero = k_254.clone() * (z_130.clone() - two_pow_124); - - // k_254 * s_minus_lo_130 = 0 - let s_minus_lo_130_check = k_254.clone() * s_minus_lo_130.clone(); - - // (1 - k_254) * (1 - z_130 * eta) * s_minus_lo_130 = 0 - let canonicity = (one.clone() - k_254) * (one - z_130 * eta) * s_minus_lo_130; - - Constraints::with_selector( - q_mul_overflow, - iter::empty() - .chain(Some(("s_check", s_check))) - .chain(Some(("recovery", recovery))) - .chain(Some(("lo_zero", lo_zero))) - .chain(Some(("s_minus_lo_130_check", s_minus_lo_130_check))) - .chain(Some(("canonicity", canonicity))), - ) - }); - } - - pub(super) fn overflow_check( - &self, - mut layouter: impl Layouter, - alpha: AssignedCell, - zs: &[Z], // [z_0, z_1, ..., z_{254}, z_{255}] - ) -> Result<(), Error> { - // s = alpha + k_254 ⋅ 2^130 is witnessed here, and then copied into - // the decomposition as well as the overflow check gate. - // In the overflow check gate, we check that s is properly derived - // from alpha and k_254. - let s = { - let k_254 = zs[254].clone(); - let s_val = alpha - .value() - .zip(k_254.value()) - .map(|(alpha, k_254)| alpha + k_254 * pallas::Base::from_u128(1 << 65).square()); - - layouter.assign_region( - || "s = alpha + k_254 ⋅ 2^130", - |mut region| { - region.assign_advice( - || "s = alpha + k_254 ⋅ 2^130", - self.advices[0], - 0, - || s_val, - ) - }, - )? - }; - - // Subtract the first 130 low bits of s = alpha + k_254 ⋅ 2^130 - // using thirteen 10-bit lookups, s_{0..=129} - let s_minus_lo_130 = - self.s_minus_lo_130(layouter.namespace(|| "decompose s_{0..=129}"), s.clone())?; - - layouter.assign_region( - || "overflow check", - |mut region| { - let offset = 0; - - // Enable overflow check gate - self.q_mul_overflow.enable(&mut region, offset + 1)?; - - // Copy `z_0` - zs[0].copy_advice(|| "copy z_0", &mut region, self.advices[0], offset)?; - - // Copy `z_130` - zs[130].copy_advice(|| "copy z_130", &mut region, self.advices[0], offset + 1)?; - - // Witness η = inv0(z_130), where inv0(x) = 0 if x = 0, 1/x otherwise - { - let eta = zs[130].value().map(|z_130| Assigned::from(z_130).invert()); - region.assign_advice( - || "η = inv0(z_130)", - self.advices[0], - offset + 2, - || eta, - )?; - } - - // Copy `k_254` = z_254 - zs[254].copy_advice(|| "copy k_254", &mut region, self.advices[1], offset)?; - - // Copy original alpha - alpha.copy_advice( - || "copy original alpha", - &mut region, - self.advices[1], - offset + 1, - )?; - - // Copy weighted sum of the decomposition of s = alpha + k_254 ⋅ 2^130. - s_minus_lo_130.copy_advice( - || "copy s_minus_lo_130", - &mut region, - self.advices[1], - offset + 2, - )?; - - // Copy witnessed s to check that it was properly derived from alpha and k_254. - s.copy_advice(|| "copy s", &mut region, self.advices[2], offset + 1)?; - - Ok(()) - }, - )?; - - Ok(()) - } - - fn s_minus_lo_130( - &self, - mut layouter: impl Layouter, - s: AssignedCell, - ) -> Result, Error> { - // Number of k-bit words we can use in the lookup decomposition. - let num_words = 130 / sinsemilla::K; - assert!(num_words * sinsemilla::K == 130); - - // Decompose the low 130 bits of `s` using thirteen 10-bit lookups. - let zs = self.lookup_config.copy_check( - layouter.namespace(|| "Decompose low 130 bits of s"), - s, - num_words, - false, - )?; - // (s - (2^0 s_0 + 2^1 s_1 + ... + 2^129 s_129)) / 2^130 - Ok(zs[zs.len() - 1].clone()) - } -} diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed.rs b/halo2_gadgets/src/ecc/chip/mul_fixed.rs deleted file mode 100644 index ce478fdb86..0000000000 --- a/halo2_gadgets/src/ecc/chip/mul_fixed.rs +++ /dev/null @@ -1,498 +0,0 @@ -use super::{ - add, add_incomplete, EccBaseFieldElemFixed, EccScalarFixed, EccScalarFixedShort, FixedPoint, - NonIdentityEccPoint, FIXED_BASE_WINDOW_SIZE, H, -}; -use crate::utilities::decompose_running_sum::RunningSumConfig; - -use std::marker::PhantomData; - -use group::{ - ff::{Field, PrimeField, PrimeFieldBits}, - Curve, -}; -use halo2_proofs::{ - circuit::{AssignedCell, Region, Value}, - plonk::{ - Advice, Column, ConstraintSystem, Constraints, Error, Expression, Fixed, Selector, - VirtualCells, - }, - poly::Rotation, -}; -use halo2curves::{pasta::pallas, CurveAffine}; -use lazy_static::lazy_static; - -pub mod base_field_elem; -pub mod full_width; -pub mod short; - -lazy_static! { - static ref TWO_SCALAR: pallas::Scalar = pallas::Scalar::from(2); - // H = 2^3 (3-bit window) - static ref H_SCALAR: pallas::Scalar = pallas::Scalar::from(H as u64); - static ref H_BASE: pallas::Base = pallas::Base::from(H as u64); -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Config> { - running_sum_config: RunningSumConfig, - // The fixed Lagrange interpolation coefficients for `x_p`. - lagrange_coeffs: [Column; H], - // The fixed `z` for each window such that `y + z = u^2`. - fixed_z: Column, - // Decomposition of an `n-1`-bit scalar into `k`-bit windows: - // a = a_0 + 2^k(a_1) + 2^{2k}(a_2) + ... + 2^{(n-1)k}(a_{n-1}) - window: Column, - // y-coordinate of accumulator (only used in the final row). - u: Column, - // Configuration for `add` - add_config: add::Config, - // Configuration for `add_incomplete` - add_incomplete_config: add_incomplete::Config, - _marker: PhantomData, -} - -impl> Config { - #[allow(clippy::too_many_arguments)] - pub(super) fn configure( - meta: &mut ConstraintSystem, - lagrange_coeffs: [Column; H], - window: Column, - u: Column, - add_config: add::Config, - add_incomplete_config: add_incomplete::Config, - ) -> Self { - meta.enable_equality(window); - meta.enable_equality(u); - - let q_running_sum = meta.selector(); - let running_sum_config = RunningSumConfig::configure(meta, q_running_sum, window); - - let config = Self { - running_sum_config, - lagrange_coeffs, - fixed_z: meta.fixed_column(), - window, - u, - add_config, - add_incomplete_config, - _marker: PhantomData, - }; - - // Check relationships between `add_config` and `add_incomplete_config`. - assert_eq!( - config.add_config.x_p, config.add_incomplete_config.x_p, - "add and add_incomplete are used internally in mul_fixed." - ); - assert_eq!( - config.add_config.y_p, config.add_incomplete_config.y_p, - "add and add_incomplete are used internally in mul_fixed." - ); - for advice in [config.window, config.u].iter() { - assert_ne!( - *advice, config.add_config.x_qr, - "Do not overlap with output columns of add." - ); - assert_ne!( - *advice, config.add_config.y_qr, - "Do not overlap with output columns of add." - ); - } - - config.running_sum_coords_gate(meta); - - config - } - - /// Check that each window in the running sum decomposition uses the correct y_p - /// and interpolated x_p. - /// - /// This gate is used both in the mul_fixed::base_field_elem and mul_fixed::short - /// helpers, which decompose the scalar using a running sum. - /// - /// This gate is not used in the mul_fixed::full_width helper, since the full-width - /// scalar is witnessed directly as three-bit windows instead of being decomposed - /// via a running sum. - fn running_sum_coords_gate(&self, meta: &mut ConstraintSystem) { - meta.create_gate("Running sum coordinates check", |meta| { - let q_mul_fixed_running_sum = - meta.query_selector(self.running_sum_config.q_range_check()); - - let z_cur = meta.query_advice(self.window, Rotation::cur()); - let z_next = meta.query_advice(self.window, Rotation::next()); - - // z_{i+1} = (z_i - a_i) / 2^3 - // => a_i = z_i - z_{i+1} * 2^3 - let word = z_cur - z_next * pallas::Base::from(H as u64); - - Constraints::with_selector(q_mul_fixed_running_sum, self.coords_check(meta, word)) - }); - } - - /// [Specification](https://p.z.cash/halo2-0.1:ecc-fixed-mul-coordinates). - #[allow(clippy::op_ref)] - fn coords_check( - &self, - meta: &mut VirtualCells<'_, pallas::Base>, - window: Expression, - ) -> Vec<(&'static str, Expression)> { - let y_p = meta.query_advice(self.add_config.y_p, Rotation::cur()); - let x_p = meta.query_advice(self.add_config.x_p, Rotation::cur()); - let z = meta.query_fixed(self.fixed_z, Rotation::cur()); - let u = meta.query_advice(self.u, Rotation::cur()); - - let window_pow: Vec> = (0..H) - .map(|pow| { - (0..pow).fold(Expression::Constant(pallas::Base::one()), |acc, _| { - acc * window.clone() - }) - }) - .collect(); - - let interpolated_x = window_pow.iter().zip(self.lagrange_coeffs.iter()).fold( - Expression::Constant(pallas::Base::zero()), - |acc, (window_pow, coeff)| { - acc + (window_pow.clone() * meta.query_fixed(*coeff, Rotation::cur())) - }, - ); - - // Check interpolation of x-coordinate - let x_check = interpolated_x - x_p.clone(); - // Check that `y + z = u^2`, where `z` is fixed and `u`, `y` are witnessed - let y_check = u.square() - y_p.clone() - z; - // Check that (x, y) is on the curve - let on_curve = - y_p.square() - x_p.clone().square() * x_p - Expression::Constant(pallas::Affine::b()); - - vec![ - ("check x", x_check), - ("check y", y_check), - ("on-curve", on_curve), - ] - } - - #[allow(clippy::type_complexity)] - fn assign_region_inner, const NUM_WINDOWS: usize>( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - scalar: &ScalarFixed, - base: &F, - coords_check_toggle: Selector, - ) -> Result<(NonIdentityEccPoint, NonIdentityEccPoint), Error> { - // Assign fixed columns for given fixed base - self.assign_fixed_constants::(region, offset, base, coords_check_toggle)?; - - // Initialize accumulator - let acc = self.initialize_accumulator::(region, offset, base, scalar)?; - - // Process all windows excluding least and most significant windows - let acc = self.add_incomplete::(region, offset, acc, base, scalar)?; - - // Process most significant window - let mul_b = self.process_msb::(region, offset, base, scalar)?; - - Ok((acc, mul_b)) - } - - /// [Specification](https://p.z.cash/halo2-0.1:ecc-fixed-mul-load-base). - fn assign_fixed_constants, const NUM_WINDOWS: usize>( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - base: &F, - coords_check_toggle: Selector, - ) -> Result<(), Error> { - let mut constants = None; - let build_constants = || { - let lagrange_coeffs = base.lagrange_coeffs(); - assert_eq!(lagrange_coeffs.len(), NUM_WINDOWS); - - let z = base.z(); - assert_eq!(z.len(), NUM_WINDOWS); - - (lagrange_coeffs, z) - }; - - // Assign fixed columns for given fixed base - for window in 0..NUM_WINDOWS { - coords_check_toggle.enable(region, window + offset)?; - - // Assign x-coordinate Lagrange interpolation coefficients - for k in 0..H { - region.assign_fixed( - || { - format!( - "Lagrange interpolation coeff for window: {:?}, k: {:?}", - window, k - ) - }, - self.lagrange_coeffs[k], - window + offset, - || { - if constants.as_ref().is_none() { - constants = Some(build_constants()); - } - let lagrange_coeffs = &constants.as_ref().unwrap().0; - Value::known(lagrange_coeffs[window][k]) - }, - )?; - } - - // Assign z-values for each window - region.assign_fixed( - || format!("z-value for window: {:?}", window), - self.fixed_z, - window + offset, - || { - let z = &constants.as_ref().unwrap().1; - Value::known(pallas::Base::from(z[window])) - }, - )?; - } - - Ok(()) - } - - /// Assigns the values used to process a window. - fn process_window, const NUM_WINDOWS: usize>( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - w: usize, - k_usize: Value, - window_scalar: Value, - base: &F, - ) -> Result { - let base_value = base.generator(); - let base_u = base.u(); - assert_eq!(base_u.len(), NUM_WINDOWS); - - // Compute [window_scalar]B - let mul_b = { - let mul_b = window_scalar.map(|scalar| base_value * scalar); - let mul_b = mul_b.map(|mul_b| mul_b.to_affine().coordinates().unwrap()); - - let x = mul_b.map(|mul_b| { - let x = *mul_b.x(); - assert!(x != pallas::Base::zero()); - x.into() - }); - let x = region.assign_advice( - || format!("mul_b_x, window {}", w), - self.add_config.x_p, - offset + w, - || x, - )?; - - let y = mul_b.map(|mul_b| { - let y = *mul_b.y(); - assert!(y != pallas::Base::zero()); - y.into() - }); - let y = region.assign_advice( - || format!("mul_b_y, window {}", w), - self.add_config.y_p, - offset + w, - || y, - )?; - - NonIdentityEccPoint { x, y } - }; - - // Assign u = (y_p + z_w).sqrt() - let u_val = k_usize.map(|k| pallas::Base::from_repr(base_u[w][k]).unwrap()); - region.assign_advice(|| "u", self.u, offset + w, || u_val)?; - - Ok(mul_b) - } - - fn initialize_accumulator, const NUM_WINDOWS: usize>( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - base: &F, - scalar: &ScalarFixed, - ) -> Result { - // Recall that the message at each window `w` is represented as - // `m_w = [(k_w + 2) ⋅ 8^w]B`. - // When `w = 0`, we have `m_0 = [(k_0 + 2)]B`. - let w = 0; - let k0 = scalar.windows_field()[0]; - let k0_usize = scalar.windows_usize()[0]; - self.process_lower_bits::<_, NUM_WINDOWS>(region, offset, w, k0, k0_usize, base) - } - - fn add_incomplete, const NUM_WINDOWS: usize>( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - mut acc: NonIdentityEccPoint, - base: &F, - scalar: &ScalarFixed, - ) -> Result { - let scalar_windows_field = scalar.windows_field(); - let scalar_windows_usize = scalar.windows_usize(); - assert_eq!(scalar_windows_field.len(), NUM_WINDOWS); - - for (w, (k, k_usize)) in scalar_windows_field - .into_iter() - .zip(scalar_windows_usize) - .enumerate() - // The MSB is processed separately. - .take(NUM_WINDOWS - 1) - // Skip k_0 (already processed). - .skip(1) - { - // Compute [(k_w + 2) ⋅ 8^w]B - // - // This assigns the coordinates of the returned point into the input cells for - // the incomplete addition gate, which will then copy them into themselves. - let mul_b = - self.process_lower_bits::<_, NUM_WINDOWS>(region, offset, w, k, k_usize, base)?; - - // Add to the accumulator. - // - // After the first loop, the accumulator will already be in the input cells - // for the incomplete addition gate, and will be copied into themselves. - acc = self - .add_incomplete_config - .assign_region(&mul_b, &acc, offset + w, region)?; - } - Ok(acc) - } - - /// Assigns the values used to process a window that does not contain the MSB. - fn process_lower_bits, const NUM_WINDOWS: usize>( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - w: usize, - k: Value, - k_usize: Value, - base: &F, - ) -> Result { - // `scalar = [(k_w + 2) ⋅ 8^w] - let scalar = k.map(|k| (k + *TWO_SCALAR) * (*H_SCALAR).pow([w as u64])); - - self.process_window::<_, NUM_WINDOWS>(region, offset, w, k_usize, scalar, base) - } - - /// Assigns the values used to process the window containing the MSB. - fn process_msb, const NUM_WINDOWS: usize>( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - base: &F, - scalar: &ScalarFixed, - ) -> Result { - let k_usize = scalar.windows_usize()[NUM_WINDOWS - 1]; - - // offset_acc = \sum_{j = 0}^{NUM_WINDOWS - 2} 2^{FIXED_BASE_WINDOW_SIZE*j + 1} - let offset_acc = (0..(NUM_WINDOWS - 1)).fold(pallas::Scalar::zero(), |acc, w| { - acc + (*TWO_SCALAR).pow([FIXED_BASE_WINDOW_SIZE as u64 * w as u64 + 1]) - }); - - // `scalar = [k * 8^(NUM_WINDOWS - 1) - offset_acc]`. - let scalar = scalar.windows_field()[scalar.windows_field().len() - 1] - .map(|k| k * (*H_SCALAR).pow([(NUM_WINDOWS - 1) as u64]) - offset_acc); - - self.process_window::<_, NUM_WINDOWS>( - region, - offset, - NUM_WINDOWS - 1, - k_usize, - scalar, - base, - ) - } -} - -enum ScalarFixed { - FullWidth(EccScalarFixed), - Short(EccScalarFixedShort), - BaseFieldElem(EccBaseFieldElemFixed), -} - -impl From<&EccScalarFixed> for ScalarFixed { - fn from(scalar_fixed: &EccScalarFixed) -> Self { - Self::FullWidth(scalar_fixed.clone()) - } -} - -impl From<&EccScalarFixedShort> for ScalarFixed { - fn from(scalar_fixed: &EccScalarFixedShort) -> Self { - Self::Short(scalar_fixed.clone()) - } -} - -impl From<&EccBaseFieldElemFixed> for ScalarFixed { - fn from(base_field_elem: &EccBaseFieldElemFixed) -> Self { - Self::BaseFieldElem(base_field_elem.clone()) - } -} - -impl ScalarFixed { - /// The scalar decomposition was done in the base field. For computation - /// outside the circuit, we now convert them back into the scalar field. - /// - /// This function does not require that the base field fits inside the scalar field, - /// because the window size fits into either field. - fn windows_field(&self) -> Vec> { - let running_sum_to_windows = |zs: Vec>| { - (0..(zs.len() - 1)) - .map(|idx| { - let z_cur = zs[idx].value(); - let z_next = zs[idx + 1].value(); - let word = z_cur - z_next * Value::known(*H_BASE); - // This assumes that the endianness of the encodings of pallas::Base - // and pallas::Scalar are the same. They happen to be, but we need to - // be careful if this is generalised. - word.map(|word| pallas::Scalar::from_repr(word.to_repr()).unwrap()) - }) - .collect::>() - }; - match self { - Self::BaseFieldElem(scalar) => running_sum_to_windows(scalar.running_sum.to_vec()), - Self::Short(scalar) => running_sum_to_windows( - scalar - .running_sum - .as_ref() - .expect("EccScalarFixedShort has been constrained") - .to_vec(), - ), - Self::FullWidth(scalar) => scalar - .windows - .as_ref() - .expect("EccScalarFixed has been witnessed") - .iter() - .map(|bits| { - // This assumes that the endianness of the encodings of pallas::Base - // and pallas::Scalar are the same. They happen to be, but we need to - // be careful if this is generalised. - bits.value() - .map(|value| pallas::Scalar::from_repr(value.to_repr()).unwrap()) - }) - .collect::>(), - } - } - - /// The scalar decomposition is guaranteed to be in three-bit windows, so we construct - /// `usize` indices from the lowest three bits of each window field element for - /// convenient indexing into `u`-values. - fn windows_usize(&self) -> Vec> { - self.windows_field() - .iter() - .map(|window| { - window.map(|window| { - window - .to_le_bits() - .iter() - .by_vals() - .take(FIXED_BASE_WINDOW_SIZE) - .rev() - .fold(0, |acc, b| 2 * acc + usize::from(b)) - }) - }) - .collect::>() - } -} diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs deleted file mode 100644 index 91671847a2..0000000000 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs +++ /dev/null @@ -1,528 +0,0 @@ -use super::super::{EccBaseFieldElemFixed, EccPoint, FixedPoints, NUM_WINDOWS, T_P}; -use super::H_BASE; - -use crate::utilities::bool_check; -use crate::{ - sinsemilla::primitives as sinsemilla, - utilities::{bitrange_subset, lookup_range_check::LookupRangeCheckConfig, range_check}, -}; - -use group::ff::PrimeField; -use halo2_proofs::{ - circuit::{AssignedCell, Layouter}, - plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Expression, Selector}, - poly::Rotation, -}; -use halo2curves::pasta::pallas; - -use std::convert::TryInto; - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Config> { - q_mul_fixed_base_field: Selector, - canon_advices: [Column; 3], - lookup_config: LookupRangeCheckConfig, - super_config: super::Config, -} - -impl> Config { - pub(crate) fn configure( - meta: &mut ConstraintSystem, - canon_advices: [Column; 3], - lookup_config: LookupRangeCheckConfig, - super_config: super::Config, - ) -> Self { - for advice in canon_advices.iter() { - meta.enable_equality(*advice); - } - - let config = Self { - q_mul_fixed_base_field: meta.selector(), - canon_advices, - lookup_config, - super_config, - }; - - let add_incomplete_advices = config.super_config.add_incomplete_config.advice_columns(); - for canon_advice in config.canon_advices.iter() { - assert!( - !add_incomplete_advices.contains(canon_advice), - "Deconflict canon_advice columns with incomplete addition columns." - ); - } - - config.create_gate(meta); - - config - } - - fn create_gate(&self, meta: &mut ConstraintSystem) { - // Check that the base field element is canonical. - // https://p.z.cash/halo2-0.1:ecc-fixed-mul-base-canonicity - meta.create_gate("Canonicity checks", |meta| { - let q_mul_fixed_base_field = meta.query_selector(self.q_mul_fixed_base_field); - - let alpha = meta.query_advice(self.canon_advices[0], Rotation::prev()); - // The last three bits of α. - let z_84_alpha = meta.query_advice(self.canon_advices[2], Rotation::prev()); - - // Decompose α into three pieces, in little-endian order: - // α = α_0 (252 bits) || α_1 (2 bits) || α_2 (1 bit). - // - // α_0 is derived, not witnessed. - let alpha_0 = { - let two_pow_252 = pallas::Base::from_u128(1 << 126).square(); - alpha - (z_84_alpha.clone() * two_pow_252) - }; - let alpha_1 = meta.query_advice(self.canon_advices[1], Rotation::cur()); - let alpha_2 = meta.query_advice(self.canon_advices[2], Rotation::cur()); - - let alpha_0_prime = meta.query_advice(self.canon_advices[0], Rotation::cur()); - let z_13_alpha_0_prime = meta.query_advice(self.canon_advices[0], Rotation::next()); - let z_44_alpha = meta.query_advice(self.canon_advices[1], Rotation::next()); - let z_43_alpha = meta.query_advice(self.canon_advices[2], Rotation::next()); - - let decomposition_checks = { - // Range-constrain α_1 to be 2 bits - let alpha_1_range_check = range_check(alpha_1.clone(), 1 << 2); - // Boolean-constrain α_2 - let alpha_2_range_check = bool_check(alpha_2.clone()); - // Check that α_1 + 2^2 α_2 = z_84_alpha - let z_84_alpha_check = z_84_alpha.clone() - - (alpha_1.clone() + alpha_2.clone() * pallas::Base::from(1 << 2)); - - std::iter::empty() - .chain(Some(("alpha_1_range_check", alpha_1_range_check))) - .chain(Some(("alpha_2_range_check", alpha_2_range_check))) - .chain(Some(("z_84_alpha_check", z_84_alpha_check))) - }; - - // Check α_0_prime = α_0 + 2^130 - t_p - let alpha_0_prime_check = { - let two_pow_130 = Expression::Constant(pallas::Base::from_u128(1 << 65).square()); - let t_p = Expression::Constant(pallas::Base::from_u128(T_P)); - alpha_0_prime - (alpha_0 + two_pow_130 - t_p) - }; - - // We want to enforce canonicity of a 255-bit base field element, α. - // That is, we want to check that 0 ≤ α < p, where p is Pallas base - // field modulus p = 2^254 + t_p - // = 2^254 + 45560315531419706090280762371685220353. - // Note that t_p < 2^130. - // - // α has been decomposed into three pieces in little-endian order: - // α = α_0 (252 bits) || α_1 (2 bits) || α_2 (1 bit). - // = α_0 + 2^252 α_1 + 2^254 α_2. - // - // If the MSB α_2 = 1, then: - // - α_2 = 1 => α_1 = 0, and - // - α_2 = 1 => α_0 < t_p. To enforce this: - // - α_2 = 1 => 0 ≤ α_0 < 2^130 - // - alpha_0_hi_120 = 0 (constrain α_0 to be 132 bits) - // - a_43 = 0 or 1 (constrain α_0[130..=131] to be 0) - // - α_2 = 1 => 0 ≤ α_0 + 2^130 - t_p < 2^130 - // => 13 ten-bit lookups of α_0 + 2^130 - t_p - // => z_13_alpha_0_prime = 0 - // - let canon_checks = { - // alpha_0_hi_120 = z_44 - 2^120 z_84 - let alpha_0_hi_120 = { - let two_pow_120 = - Expression::Constant(pallas::Base::from_u128(1 << 60).square()); - z_44_alpha.clone() - z_84_alpha * two_pow_120 - }; - // a_43 = z_43 - (2^3)z_44 - let a_43 = z_43_alpha - z_44_alpha * *H_BASE; - - std::iter::empty() - .chain(Some(("MSB = 1 => alpha_1 = 0", alpha_2.clone() * alpha_1))) - .chain(Some(( - "MSB = 1 => alpha_0_hi_120 = 0", - alpha_2.clone() * alpha_0_hi_120, - ))) - .chain(Some(( - "MSB = 1 => a_43 = 0 or 1", - alpha_2.clone() * bool_check(a_43), - ))) - .chain(Some(( - "MSB = 1 => z_13_alpha_0_prime = 0", - alpha_2 * z_13_alpha_0_prime, - ))) - }; - - Constraints::with_selector( - q_mul_fixed_base_field, - canon_checks - .chain(decomposition_checks) - .chain(Some(("alpha_0_prime check", alpha_0_prime_check))), - ) - }); - } - - pub fn assign( - &self, - mut layouter: impl Layouter, - scalar: AssignedCell, - base: &>::Base, - ) -> Result - where - >::Base: super::super::FixedPoint, - { - let (scalar, acc, mul_b) = layouter.assign_region( - || "Base-field elem fixed-base mul (incomplete addition)", - |mut region| { - let offset = 0; - - // Decompose scalar - let scalar = { - let running_sum = self.super_config.running_sum_config.copy_decompose( - &mut region, - offset, - scalar.clone(), - true, - pallas::Base::NUM_BITS as usize, - NUM_WINDOWS, - )?; - EccBaseFieldElemFixed { - base_field_elem: running_sum[0].clone(), - running_sum: (*running_sum).as_slice().try_into().unwrap(), - } - }; - - let (acc, mul_b) = self.super_config.assign_region_inner::<_, NUM_WINDOWS>( - &mut region, - offset, - &(&scalar).into(), - base, - self.super_config.running_sum_config.q_range_check(), - )?; - - Ok((scalar, acc, mul_b)) - }, - )?; - - // Add to the accumulator and return the final result as `[scalar]B`. - let result = layouter.assign_region( - || "Base-field elem fixed-base mul (complete addition)", - |mut region| { - self.super_config.add_config.assign_region( - &mul_b.clone().into(), - &acc.clone().into(), - 0, - &mut region, - ) - }, - )?; - - #[cfg(test)] - // Check that the correct multiple is obtained. - { - use super::super::FixedPoint; - use group::Curve; - - let scalar = &scalar - .base_field_elem() - .value() - .map(|scalar| pallas::Scalar::from_repr(scalar.to_repr()).unwrap()); - let real_mul = scalar.map(|scalar| base.generator() * scalar); - let result = result.point(); - - real_mul - .zip(result) - .assert_if_known(|(real_mul, result)| &real_mul.to_affine() == result); - } - - // We want to enforce canonicity of a 255-bit base field element, α. - // That is, we want to check that 0 ≤ α < p, where p is Pallas base - // field modulus p = 2^254 + t_p - // = 2^254 + 45560315531419706090280762371685220353. - // Note that t_p < 2^130. - // - // α has been decomposed into three pieces in little-endian order: - // α = α_0 (252 bits) || α_1 (2 bits) || α_2 (1 bit). - // = α_0 + 2^252 α_1 + 2^254 α_2. - // - // If the MSB α_2 = 1, then: - // - α_2 = 1 => α_1 = 0, and - // - α_2 = 1 => α_0 < t_p. To enforce this: - // - α_2 = 1 => 0 ≤ α_0 < 2^130 - // => 13 ten-bit lookups of α_0 - // - α_2 = 1 => 0 ≤ α_0 + 2^130 - t_p < 2^130 - // => 13 ten-bit lookups of α_0 + 2^130 - t_p - // => z_13_alpha_0_prime = 0 - // - let (alpha, running_sum) = (scalar.base_field_elem, &scalar.running_sum); - let z_43_alpha = running_sum[43].clone(); - let z_44_alpha = running_sum[44].clone(); - let z_84_alpha = running_sum[84].clone(); - - // α_0 = α - z_84_alpha * 2^252 - let alpha_0 = alpha - .value() - .zip(z_84_alpha.value()) - .map(|(alpha, z_84_alpha)| { - let two_pow_252 = pallas::Base::from_u128(1 << 126).square(); - alpha - z_84_alpha * two_pow_252 - }); - - let (alpha_0_prime, z_13_alpha_0_prime) = { - // alpha_0_prime = alpha + 2^130 - t_p. - let alpha_0_prime = alpha_0.map(|alpha_0| { - let two_pow_130 = pallas::Base::from_u128(1 << 65).square(); - let t_p = pallas::Base::from_u128(T_P); - alpha_0 + two_pow_130 - t_p - }); - let zs = self.lookup_config.witness_check( - layouter.namespace(|| "Lookup range check alpha_0 + 2^130 - t_p"), - alpha_0_prime, - 13, - false, - )?; - let alpha_0_prime = zs[0].clone(); - - (alpha_0_prime, zs[13].clone()) - }; - - layouter.assign_region( - || "Canonicity checks", - |mut region| { - // Activate canonicity check gate - self.q_mul_fixed_base_field.enable(&mut region, 1)?; - - // Offset 0 - { - let offset = 0; - - // Copy α - alpha.copy_advice(|| "Copy α", &mut region, self.canon_advices[0], offset)?; - - // z_84_alpha = the top three bits of alpha. - z_84_alpha.copy_advice( - || "Copy z_84_alpha", - &mut region, - self.canon_advices[2], - offset, - )?; - } - - // Offset 1 - { - let offset = 1; - // Copy alpha_0_prime = alpha_0 + 2^130 - t_p. - // We constrain this in the custom gate to be derived correctly. - alpha_0_prime.copy_advice( - || "Copy α_0 + 2^130 - t_p", - &mut region, - self.canon_advices[0], - offset, - )?; - - // Decompose α into three pieces, - // α = α_0 (252 bits) || α_1 (2 bits) || α_2 (1 bit). - // We only need to witness α_1 and α_2. α_0 is derived in the gate. - // Witness α_1 = α[252..=253] - let alpha_1 = alpha.value().map(|alpha| bitrange_subset(alpha, 252..254)); - region.assign_advice( - || "α_1 = α[252..=253]", - self.canon_advices[1], - offset, - || alpha_1, - )?; - - // Witness the MSB α_2 = α[254] - let alpha_2 = alpha.value().map(|alpha| bitrange_subset(alpha, 254..255)); - region.assign_advice( - || "α_2 = α[254]", - self.canon_advices[2], - offset, - || alpha_2, - )?; - } - - // Offset 2 - { - let offset = 2; - // Copy z_13_alpha_0_prime - z_13_alpha_0_prime.copy_advice( - || "Copy z_13_alpha_0_prime", - &mut region, - self.canon_advices[0], - offset, - )?; - - // Copy z_44_alpha - z_44_alpha.copy_advice( - || "Copy z_44_alpha", - &mut region, - self.canon_advices[1], - offset, - )?; - - // Copy z_43_alpha - z_43_alpha.copy_advice( - || "Copy z_43_alpha", - &mut region, - self.canon_advices[2], - offset, - )?; - } - - Ok(()) - }, - )?; - - Ok(result) - } -} - -#[cfg(test)] -pub mod tests { - use group::{ - ff::{Field, PrimeField}, - Curve, - }; - use halo2_proofs::{ - circuit::{Chip, Layouter, Value}, - plonk::Error, - }; - use halo2curves::pasta::pallas; - use rand::rngs::OsRng; - - use crate::{ - ecc::{ - chip::{EccChip, FixedPoint, H}, - tests::{BaseField, TestFixedBases}, - FixedPointBaseField, NonIdentityPoint, Point, - }, - utilities::UtilitiesInstructions, - }; - - pub(crate) fn test_mul_fixed_base_field( - chip: EccChip, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - test_single_base( - chip.clone(), - layouter.namespace(|| "base_field_elem"), - FixedPointBaseField::from_inner(chip, BaseField), - BaseField.generator(), - ) - } - - #[allow(clippy::op_ref)] - fn test_single_base( - chip: EccChip, - mut layouter: impl Layouter, - base: FixedPointBaseField>, - base_val: pallas::Affine, - ) -> Result<(), Error> { - let rng = OsRng; - - let column = chip.config().advices[0]; - - fn constrain_equal_non_id( - chip: EccChip, - mut layouter: impl Layouter, - base_val: pallas::Affine, - scalar_val: pallas::Base, - result: Point>, - ) -> Result<(), Error> { - // Move scalar from base field into scalar field (which always fits for Pallas). - let scalar = pallas::Scalar::from_repr(scalar_val.to_repr()).unwrap(); - let expected = NonIdentityPoint::new( - chip, - layouter.namespace(|| "expected point"), - Value::known((base_val * scalar).to_affine()), - )?; - result.constrain_equal(layouter.namespace(|| "constrain result"), &expected) - } - - // [a]B - { - let scalar_fixed = pallas::Base::random(rng); - let result = { - let scalar_fixed = chip.load_private( - layouter.namespace(|| "random base field element"), - column, - Value::known(scalar_fixed), - )?; - base.mul(layouter.namespace(|| "random [a]B"), scalar_fixed)? - }; - constrain_equal_non_id( - chip.clone(), - layouter.namespace(|| "random [a]B"), - base_val, - scalar_fixed, - result, - )?; - } - - // There is a single canonical sequence of window values for which a doubling occurs on the last step: - // 1333333333333333333333333333333333333333333333333333333333333333333333333333333333334 in octal. - // (There is another *non-canonical* sequence - // 5333333333333333333333333333333333333333332711161673731021062440252244051273333333333 in octal.) - { - let h = pallas::Base::from(H as u64); - let scalar_fixed = "1333333333333333333333333333333333333333333333333333333333333333333333333333333333334" - .chars() - .fold(pallas::Base::zero(), |acc, c| { - acc * &h + &pallas::Base::from(c.to_digit(8).unwrap() as u64) - }); - let result = { - let scalar_fixed = chip.load_private( - layouter.namespace(|| "mul with double"), - column, - Value::known(scalar_fixed), - )?; - base.mul(layouter.namespace(|| "mul with double"), scalar_fixed)? - }; - constrain_equal_non_id( - chip.clone(), - layouter.namespace(|| "mul with double"), - base_val, - scalar_fixed, - result, - )?; - } - - // [0]B should return (0,0) since it uses complete addition - // on the last step. - { - let scalar_fixed = pallas::Base::zero(); - let result = { - let scalar_fixed = chip.load_private( - layouter.namespace(|| "zero"), - column, - Value::known(scalar_fixed), - )?; - base.mul(layouter.namespace(|| "mul by zero"), scalar_fixed)? - }; - result - .inner() - .is_identity() - .assert_if_known(|is_identity| *is_identity); - } - - // [-1]B is the largest base field element - { - let scalar_fixed = -pallas::Base::one(); - let result = { - let scalar_fixed = chip.load_private( - layouter.namespace(|| "-1"), - column, - Value::known(scalar_fixed), - )?; - base.mul(layouter.namespace(|| "mul by -1"), scalar_fixed)? - }; - constrain_equal_non_id( - chip, - layouter.namespace(|| "mul by -1"), - base_val, - scalar_fixed, - result, - )?; - } - - Ok(()) - } -} diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs deleted file mode 100644 index 607c51e534..0000000000 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs +++ /dev/null @@ -1,316 +0,0 @@ -use super::super::{EccPoint, EccScalarFixed, FixedPoints, FIXED_BASE_WINDOW_SIZE, H, NUM_WINDOWS}; - -use crate::utilities::{decompose_word, range_check}; -use arrayvec::ArrayVec; -use ff::PrimeField; -use halo2_proofs::{ - circuit::{AssignedCell, Layouter, Region, Value}, - plonk::{ConstraintSystem, Constraints, Error, Selector}, - poly::Rotation, -}; -use halo2curves::pasta::pallas; - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Config> { - q_mul_fixed_full: Selector, - super_config: super::Config, -} - -impl> Config { - pub(crate) fn configure( - meta: &mut ConstraintSystem, - super_config: super::Config, - ) -> Self { - let config = Self { - q_mul_fixed_full: meta.selector(), - super_config, - }; - - config.create_gate(meta); - - config - } - - fn create_gate(&self, meta: &mut ConstraintSystem) { - // Check that each window `k` is within 3 bits - // https://p.z.cash/halo2-0.1:ecc-fixed-mul-full-word - meta.create_gate("Full-width fixed-base scalar mul", |meta| { - let q_mul_fixed_full = meta.query_selector(self.q_mul_fixed_full); - let window = meta.query_advice(self.super_config.window, Rotation::cur()); - - Constraints::with_selector( - q_mul_fixed_full, - self.super_config - .coords_check(meta, window.clone()) - .into_iter() - // Constrain each window to a 3-bit value: - // window * (1 - window) * ... * (7 - window) - .chain(Some(("window range check", range_check(window, H)))), - ) - }); - } - - /// Witnesses the given scalar as `NUM_WINDOWS` 3-bit windows. - /// - /// The scalar is allowed to be non-canonical. - fn witness( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - scalar: Value, - ) -> Result { - let windows = self.decompose_scalar_fixed::<{ pallas::Scalar::NUM_BITS as usize }>( - scalar, offset, region, - )?; - - Ok(EccScalarFixed { - value: scalar, - windows: Some(windows), - }) - } - - /// Witnesses the given scalar as `NUM_WINDOWS` 3-bit windows. - /// - /// The scalar is allowed to be non-canonical. - fn decompose_scalar_fixed( - &self, - scalar: Value, - offset: usize, - region: &mut Region<'_, pallas::Base>, - ) -> Result, NUM_WINDOWS>, Error> { - // Enable `q_mul_fixed_full` selector - for idx in 0..NUM_WINDOWS { - self.q_mul_fixed_full.enable(region, offset + idx)?; - } - - // Decompose scalar into `k-bit` windows - let scalar_windows: Value> = scalar.map(|scalar| { - decompose_word::(&scalar, SCALAR_NUM_BITS, FIXED_BASE_WINDOW_SIZE) - }); - - // Transpose `Value>` into `Vec>`. - let scalar_windows = scalar_windows - .map(|windows| { - windows - .into_iter() - .map(|window| pallas::Base::from(window as u64)) - }) - .transpose_vec(NUM_WINDOWS); - - // Store the scalar decomposition - let mut windows: ArrayVec, NUM_WINDOWS> = - ArrayVec::new(); - for (idx, window) in scalar_windows.into_iter().enumerate() { - let window_cell = region.assign_advice( - || format!("k[{:?}]", offset + idx), - self.super_config.window, - offset + idx, - || window, - )?; - windows.push(window_cell); - } - - Ok(windows) - } - - pub fn assign( - &self, - mut layouter: impl Layouter, - scalar: &EccScalarFixed, - base: &>::FullScalar, - ) -> Result<(EccPoint, EccScalarFixed), Error> - where - >::FullScalar: - super::super::FixedPoint, - { - let (scalar, acc, mul_b) = layouter.assign_region( - || "Full-width fixed-base mul (incomplete addition)", - |mut region| { - let offset = 0; - - // Lazily witness the scalar. - let scalar = match scalar.windows { - None => self.witness(&mut region, offset, scalar.value), - Some(_) => todo!("unimplemented for halo2_gadgets v0.1.0"), - }?; - - let (acc, mul_b) = self.super_config.assign_region_inner::<_, NUM_WINDOWS>( - &mut region, - offset, - &(&scalar).into(), - base, - self.q_mul_fixed_full, - )?; - - Ok((scalar, acc, mul_b)) - }, - )?; - - // Add to the accumulator and return the final result as `[scalar]B`. - let result = layouter.assign_region( - || "Full-width fixed-base mul (last window, complete addition)", - |mut region| { - self.super_config.add_config.assign_region( - &mul_b.clone().into(), - &acc.clone().into(), - 0, - &mut region, - ) - }, - )?; - - #[cfg(test)] - // Check that the correct multiple is obtained. - { - use super::super::FixedPoint; - use group::Curve; - - let real_mul = scalar.value.map(|scalar| base.generator() * scalar); - let result = result.point(); - - real_mul - .zip(result) - .assert_if_known(|(real_mul, result)| &real_mul.to_affine() == result); - } - - Ok((result, scalar)) - } -} - -#[cfg(test)] -pub mod tests { - use group::{ff::Field, Curve}; - use halo2_proofs::{ - circuit::{Layouter, Value}, - plonk::Error, - }; - use halo2curves::pasta::pallas; - use rand::rngs::OsRng; - - use crate::ecc::{ - chip::{EccChip, FixedPoint as _, H}, - tests::{FullWidth, TestFixedBases}, - FixedPoint, NonIdentityPoint, Point, ScalarFixed, - }; - - pub(crate) fn test_mul_fixed( - chip: EccChip, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let test_base = FullWidth::from_pallas_generator(); - test_single_base( - chip.clone(), - layouter.namespace(|| "full_width"), - FixedPoint::from_inner(chip, test_base.clone()), - test_base.generator(), - )?; - - Ok(()) - } - - #[allow(clippy::op_ref)] - fn test_single_base( - chip: EccChip, - mut layouter: impl Layouter, - base: FixedPoint>, - base_val: pallas::Affine, - ) -> Result<(), Error> { - fn constrain_equal_non_id( - chip: EccChip, - mut layouter: impl Layouter, - base_val: pallas::Affine, - scalar_val: pallas::Scalar, - result: Point>, - ) -> Result<(), Error> { - let expected = NonIdentityPoint::new( - chip, - layouter.namespace(|| "expected point"), - Value::known((base_val * scalar_val).to_affine()), - )?; - result.constrain_equal(layouter.namespace(|| "constrain result"), &expected) - } - - // [a]B - { - let scalar_fixed = pallas::Scalar::random(OsRng); - let by = ScalarFixed::new( - chip.clone(), - layouter.namespace(|| "random a"), - Value::known(scalar_fixed), - )?; - - let (result, _) = base.mul(layouter.namespace(|| "random [a]B"), by)?; - constrain_equal_non_id( - chip.clone(), - layouter.namespace(|| "random [a]B"), - base_val, - scalar_fixed, - result, - )?; - } - - // There is a single canonical sequence of window values for which a doubling occurs on the last step: - // 1333333333333333333333333333333333333333333333333333333333333333333333333333333333334 in octal. - // (There is another *non-canonical* sequence - // 5333333333333333333333333333333333333333332711161673731021062440252244051273333333333 in octal.) - { - const LAST_DOUBLING: &str = "1333333333333333333333333333333333333333333333333333333333333333333333333333333333334"; - let h = pallas::Scalar::from(H as u64); - let scalar_fixed = LAST_DOUBLING - .chars() - .fold(pallas::Scalar::zero(), |acc, c| { - acc * &h + &pallas::Scalar::from(c.to_digit(8).unwrap() as u64) - }); - let by = ScalarFixed::new( - chip.clone(), - layouter.namespace(|| LAST_DOUBLING), - Value::known(scalar_fixed), - )?; - let (result, _) = base.mul(layouter.namespace(|| "mul with double"), by)?; - - constrain_equal_non_id( - chip.clone(), - layouter.namespace(|| "mul with double"), - base_val, - scalar_fixed, - result, - )?; - } - - // [0]B should return (0,0) since it uses complete addition - // on the last step. - { - let scalar_fixed = pallas::Scalar::zero(); - let zero = ScalarFixed::new( - chip.clone(), - layouter.namespace(|| "0"), - Value::known(scalar_fixed), - )?; - let (result, _) = base.mul(layouter.namespace(|| "mul by zero"), zero)?; - result - .inner() - .is_identity() - .assert_if_known(|is_identity| *is_identity); - } - - // [-1]B is the largest scalar field element. - { - let scalar_fixed = -pallas::Scalar::ONE; - let neg_1 = ScalarFixed::new( - chip.clone(), - layouter.namespace(|| "-1"), - Value::known(scalar_fixed), - )?; - let (result, _) = base.mul(layouter.namespace(|| "mul by -1"), neg_1)?; - constrain_equal_non_id( - chip, - layouter.namespace(|| "mul by -1"), - base_val, - scalar_fixed, - result, - )?; - } - - Ok(()) - } -} diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs deleted file mode 100644 index 42363baa11..0000000000 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs +++ /dev/null @@ -1,669 +0,0 @@ -use std::convert::TryInto; - -use super::super::{EccPoint, EccScalarFixedShort, FixedPoints, L_SCALAR_SHORT, NUM_WINDOWS_SHORT}; -use crate::{ecc::chip::MagnitudeSign, utilities::bool_check}; - -use halo2_proofs::{ - circuit::{Layouter, Region}, - plonk::{ConstraintSystem, Constraints, Error, Expression, Selector}, - poly::Rotation, -}; -use halo2curves::pasta::pallas; - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Config> { - // Selector used for fixed-base scalar mul with short signed exponent. - q_mul_fixed_short: Selector, - super_config: super::Config, -} - -impl> Config { - pub(crate) fn configure( - meta: &mut ConstraintSystem, - super_config: super::Config, - ) -> Self { - let config = Self { - q_mul_fixed_short: meta.selector(), - super_config, - }; - - config.create_gate(meta); - - config - } - - fn create_gate(&self, meta: &mut ConstraintSystem) { - // Gate contains the following constraints: - // - https://p.z.cash/halo2-0.1:ecc-fixed-mul-short-msb - // - https://p.z.cash/halo2-0.1:ecc-fixed-mul-short-conditional-neg - meta.create_gate("Short fixed-base mul gate", |meta| { - let q_mul_fixed_short = meta.query_selector(self.q_mul_fixed_short); - let y_p = meta.query_advice(self.super_config.add_config.y_p, Rotation::cur()); - let y_a = meta.query_advice(self.super_config.add_config.y_qr, Rotation::cur()); - // z_21 = k_21 - let last_window = meta.query_advice(self.super_config.u, Rotation::cur()); - let sign = meta.query_advice(self.super_config.window, Rotation::cur()); - - let one = Expression::Constant(pallas::Base::one()); - - // Check that last window is either 0 or 1. - let last_window_check = bool_check(last_window); - // Check that sign is either 1 or -1. - let sign_check = sign.clone().square() - one; - - // `(x_a, y_a)` is the result of `[m]B`, where `m` is the magnitude. - // We conditionally negate this result using `y_p = y_a * s`, where `s` is the sign. - - // Check that the final `y_p = y_a` or `y_p = -y_a` - // - // This constraint is redundant / unnecessary, because `sign` is constrained - // to -1 or 1 by `sign_check`, and `negation_check` therefore permits a strict - // subset of the cases that this constraint permits. - let y_check = (y_p.clone() - y_a.clone()) * (y_p.clone() + y_a.clone()); - - // Check that the correct sign is witnessed s.t. sign * y_p = y_a - let negation_check = sign * y_p - y_a; - - Constraints::with_selector( - q_mul_fixed_short, - [ - ("last_window_check", last_window_check), - ("sign_check", sign_check), - ("y_check", y_check), - ("negation_check", negation_check), - ], - ) - }); - } - - /// Constraints `magnitude` to be at most 66 bits. - /// - /// The final window is separately constrained to be a single bit, which completes the - /// 64-bit range constraint. - fn decompose( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - magnitude_sign: MagnitudeSign, - ) -> Result { - let (magnitude, sign) = magnitude_sign; - - // Decompose magnitude - let running_sum = self.super_config.running_sum_config.copy_decompose( - region, - offset, - magnitude.clone(), - true, - L_SCALAR_SHORT, - NUM_WINDOWS_SHORT, - )?; - - Ok(EccScalarFixedShort { - magnitude, - sign, - running_sum: Some((*running_sum).as_slice().try_into().unwrap()), - }) - } - - pub fn assign( - &self, - mut layouter: impl Layouter, - scalar: &EccScalarFixedShort, - base: &>::ShortScalar, - ) -> Result<(EccPoint, EccScalarFixedShort), Error> - where - >::ShortScalar: - super::super::FixedPoint, - { - let (scalar, acc, mul_b) = layouter.assign_region( - || "Short fixed-base mul (incomplete addition)", - |mut region| { - let offset = 0; - - // Decompose the scalar - let scalar = match scalar.running_sum { - None => self.decompose( - &mut region, - offset, - (scalar.magnitude.clone(), scalar.sign.clone()), - ), - Some(_) => todo!("unimplemented for halo2_gadgets v0.1.0"), - }?; - - let (acc, mul_b) = self - .super_config - .assign_region_inner::<_, NUM_WINDOWS_SHORT>( - &mut region, - offset, - &(&scalar).into(), - base, - self.super_config.running_sum_config.q_range_check(), - )?; - - Ok((scalar, acc, mul_b)) - }, - )?; - - // Last window - let result = layouter.assign_region( - || "Short fixed-base mul (most significant word)", - |mut region| { - let offset = 0; - // Add to the cumulative sum to get `[magnitude]B`. - let magnitude_mul = self.super_config.add_config.assign_region( - &mul_b.clone().into(), - &acc.clone().into(), - offset, - &mut region, - )?; - - // Increase offset by 1 after complete addition - let offset = offset + 1; - - // Copy sign to `window` column - let sign = scalar.sign.copy_advice( - || "sign", - &mut region, - self.super_config.window, - offset, - )?; - - // Copy last window to `u` column. - // (Although the last window is not a `u` value; we are copying it into the `u` - // column because there is an available cell there.) - let z_21 = scalar.running_sum.as_ref().unwrap()[21].clone(); - z_21.copy_advice(|| "last_window", &mut region, self.super_config.u, offset)?; - - // Conditionally negate `y`-coordinate - let y_val = sign.value().and_then(|sign| { - if sign == &-pallas::Base::one() { - -magnitude_mul.y.value() - } else { - magnitude_mul.y.value().cloned() - } - }); - - // Enable mul_fixed_short selector on final row - self.q_mul_fixed_short.enable(&mut region, offset)?; - - // Assign final `y` to `y_p` column and return final point - let y_var = region.assign_advice( - || "y_var", - self.super_config.add_config.y_p, - offset, - || y_val, - )?; - - Ok(EccPoint { - x: magnitude_mul.x, - y: y_var, - }) - }, - )?; - - #[cfg(test)] - // Check that the correct multiple is obtained. - // This inlined test is only done for valid 64-bit magnitudes - // and valid +/- 1 signs. - // Invalid values result in constraint failures which are - // tested at the circuit-level. - { - use super::super::FixedPoint; - use ff::Field; - use group::{ff::PrimeField, Curve}; - - scalar - .magnitude - .value() - .zip(scalar.sign.value()) - .zip(result.point()) - .assert_if_known(|((magnitude, sign), result)| { - let magnitude_is_valid = - magnitude <= &&pallas::Base::from(0xFFFF_FFFF_FFFF_FFFFu64); - let sign_is_valid = sign.square() == pallas::Base::one(); - // Only check the result if the magnitude and sign are valid. - !(magnitude_is_valid && sign_is_valid) || { - let scalar = { - // Move magnitude from base field into scalar field (which always fits - // for Pallas). - let magnitude = pallas::Scalar::from_repr(magnitude.to_repr()).unwrap(); - - let sign = if sign == &&pallas::Base::one() { - pallas::Scalar::ONE - } else { - -pallas::Scalar::ONE - }; - - magnitude * sign - }; - let real_mul = base.generator() * scalar; - - &real_mul.to_affine() == result - } - }); - } - - Ok((result, scalar)) - } -} - -#[cfg(test)] -pub mod tests { - use group::{ - ff::{Field, PrimeField}, - Curve, - }; - use halo2_proofs::{ - arithmetic::CurveAffine, - circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{Any, Error}, - }; - use halo2curves::pasta::pallas; - - use crate::{ - ecc::{ - chip::{EccChip, FixedPoint, MagnitudeSign}, - tests::{Short, TestFixedBases}, - FixedPointShort, NonIdentityPoint, Point, ScalarFixedShort, - }, - utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, - }; - - #[allow(clippy::op_ref)] - pub(crate) fn test_mul_fixed_short( - chip: EccChip, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // test_short - let base_val = Short.generator(); - let test_short = FixedPointShort::from_inner(chip.clone(), Short); - - fn load_magnitude_sign( - chip: EccChip, - mut layouter: impl Layouter, - magnitude: pallas::Base, - sign: pallas::Base, - ) -> Result { - let column = chip.config().advices[0]; - let magnitude = chip.load_private( - layouter.namespace(|| "magnitude"), - column, - Value::known(magnitude), - )?; - let sign = - chip.load_private(layouter.namespace(|| "sign"), column, Value::known(sign))?; - - Ok((magnitude, sign)) - } - - fn constrain_equal_non_id( - chip: EccChip, - mut layouter: impl Layouter, - base_val: pallas::Affine, - scalar_val: pallas::Scalar, - result: Point>, - ) -> Result<(), Error> { - let expected = NonIdentityPoint::new( - chip, - layouter.namespace(|| "expected point"), - Value::known((base_val * scalar_val).to_affine()), - )?; - result.constrain_equal(layouter.namespace(|| "constrain result"), &expected) - } - - let magnitude_signs = [ - ("random [a]B", pallas::Base::from(rand::random::()), { - let mut random_sign = pallas::Base::one(); - if rand::random::() { - random_sign = -random_sign; - } - random_sign - }), - ( - "[2^64 - 1]B", - pallas::Base::from(0xFFFF_FFFF_FFFF_FFFFu64), - pallas::Base::one(), - ), - ( - "-[2^64 - 1]B", - pallas::Base::from(0xFFFF_FFFF_FFFF_FFFFu64), - -pallas::Base::one(), - ), - // There is a single canonical sequence of window values for which a doubling occurs on the last step: - // 1333333333333333333334 in octal. - // [0xB6DB_6DB6_DB6D_B6DC] B - ( - "mul_with_double", - pallas::Base::from(0xB6DB_6DB6_DB6D_B6DCu64), - pallas::Base::one(), - ), - ( - "mul_with_double negative", - pallas::Base::from(0xB6DB_6DB6_DB6D_B6DCu64), - -pallas::Base::one(), - ), - ]; - - for (name, magnitude, sign) in magnitude_signs.iter() { - let (result, _) = { - let magnitude_sign = load_magnitude_sign( - chip.clone(), - layouter.namespace(|| *name), - *magnitude, - *sign, - )?; - let by = ScalarFixedShort::new( - chip.clone(), - layouter.namespace(|| "signed short scalar"), - magnitude_sign, - )?; - test_short.mul(layouter.namespace(|| *name), by)? - }; - // Move from base field into scalar field - let scalar = { - let magnitude = pallas::Scalar::from_repr(magnitude.to_repr()).unwrap(); - let sign = if *sign == pallas::Base::one() { - pallas::Scalar::ONE - } else { - -pallas::Scalar::ONE - }; - magnitude * sign - }; - constrain_equal_non_id( - chip.clone(), - layouter.namespace(|| *name), - base_val, - scalar, - result, - )?; - } - - let zero_magnitude_signs = [ - ("mul by +zero", pallas::Base::zero(), pallas::Base::one()), - ("mul by -zero", pallas::Base::zero(), -pallas::Base::one()), - ]; - - for (name, magnitude, sign) in zero_magnitude_signs.iter() { - let (result, _) = { - let magnitude_sign = load_magnitude_sign( - chip.clone(), - layouter.namespace(|| *name), - *magnitude, - *sign, - )?; - let by = ScalarFixedShort::new( - chip.clone(), - layouter.namespace(|| "signed short scalar"), - magnitude_sign, - )?; - test_short.mul(layouter.namespace(|| *name), by)? - }; - result - .inner() - .is_identity() - .assert_if_known(|is_identity| *is_identity); - } - - Ok(()) - } - - #[test] - fn invalid_magnitude_sign() { - use crate::{ - ecc::chip::{EccConfig, FixedPoint}, - utilities::UtilitiesInstructions, - }; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::{FailureLocation, MockProver, VerifyFailure}, - plonk::{Circuit, ConstraintSystem, Error}, - }; - - #[derive(Default)] - struct MyCircuit { - magnitude: Value, - sign: Value, - // For test checking - magnitude_error: Value, - } - - impl UtilitiesInstructions for MyCircuit { - type Var = AssignedCell; - } - - impl Circuit for MyCircuit { - type Config = EccConfig; - type FloorPlanner = SimpleFloorPlanner; - #[cfg(feature = "circuit-params")] - type Params = (); - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let advices = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - let lookup_table = meta.lookup_table_column(); - let lagrange_coeffs = [ - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - ]; - - // Shared fixed column for loading constants - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table); - EccChip::::configure(meta, advices, lagrange_coeffs, range_check) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let column = config.advices[0]; - - let short_config = config.mul_fixed_short.clone(); - let magnitude_sign = { - let magnitude = self.load_private( - layouter.namespace(|| "load magnitude"), - column, - self.magnitude, - )?; - let sign = - self.load_private(layouter.namespace(|| "load sign"), column, self.sign)?; - ScalarFixedShort::new( - EccChip::construct(config), - layouter.namespace(|| "signed short scalar"), - (magnitude, sign), - )? - }; - - short_config.assign(layouter, &magnitude_sign.inner, &Short)?; - - Ok(()) - } - } - - // Copied from halo2_proofs::dev::util - fn format_value(v: pallas::Base) -> String { - use ff::Field; - if v.is_zero_vartime() { - "0".into() - } else if v == pallas::Base::one() { - "1".into() - } else if v == -pallas::Base::one() { - "-1".into() - } else { - // Format value as hex. - let s = format!("{:?}", v); - // Remove leading zeroes. - let s = s.strip_prefix("0x").unwrap(); - let s = s.trim_start_matches('0'); - format!("0x{}", s) - } - } - - // Magnitude larger than 64 bits should fail - { - let circuits = [ - // 2^64 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 64)), - sign: Value::known(pallas::Base::one()), - magnitude_error: Value::known(pallas::Base::from(1 << 1)), - }, - // -2^64 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 64)), - sign: Value::known(-pallas::Base::one()), - magnitude_error: Value::known(pallas::Base::from(1 << 1)), - }, - // 2^66 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 66)), - sign: Value::known(pallas::Base::one()), - magnitude_error: Value::known(pallas::Base::from(1 << 3)), - }, - // -2^66 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 66)), - sign: Value::known(-pallas::Base::one()), - magnitude_error: Value::known(pallas::Base::from(1 << 3)), - }, - // 2^254 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 127).square()), - sign: Value::known(pallas::Base::one()), - magnitude_error: Value::known( - pallas::Base::from_u128(1 << 95).square() * pallas::Base::from(2), - ), - }, - // -2^254 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 127).square()), - sign: Value::known(-pallas::Base::one()), - magnitude_error: Value::known( - pallas::Base::from_u128(1 << 95).square() * pallas::Base::from(2), - ), - }, - ]; - - for circuit in circuits.iter() { - let prover = MockProver::::run(11, circuit, vec![]).unwrap(); - circuit.magnitude_error.assert_if_known(|magnitude_error| { - assert_eq!( - prover.verify(), - Err(vec![ - VerifyFailure::ConstraintNotSatisfied { - constraint: ( - (17, "Short fixed-base mul gate").into(), - 0, - "last_window_check", - ) - .into(), - location: FailureLocation::InRegion { - region: (3, "Short fixed-base mul (most significant word)") - .into(), - offset: 1, - }, - cell_values: vec![( - ((Any::advice(), 5).into(), 0).into(), - format_value(*magnitude_error), - )], - }, - VerifyFailure::Permutation { - column: (Any::Fixed, 9).into(), - location: FailureLocation::OutsideRegion { row: 0 }, - }, - VerifyFailure::Permutation { - column: (Any::advice(), 4).into(), - location: FailureLocation::InRegion { - region: (2, "Short fixed-base mul (incomplete addition)") - .into(), - offset: 22, - }, - }, - ]) - ); - true - }); - } - } - - // Sign that is not +/- 1 should fail - { - let magnitude_u64 = rand::random::(); - let circuit = MyCircuit { - magnitude: Value::known(pallas::Base::from(magnitude_u64)), - sign: Value::known(pallas::Base::zero()), - magnitude_error: Value::unknown(), - }; - - let negation_check_y = { - *(Short.generator() * pallas::Scalar::from(magnitude_u64)) - .to_affine() - .coordinates() - .unwrap() - .y() - }; - - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![ - VerifyFailure::ConstraintNotSatisfied { - constraint: ((17, "Short fixed-base mul gate").into(), 1, "sign_check") - .into(), - location: FailureLocation::InRegion { - region: (3, "Short fixed-base mul (most significant word)").into(), - offset: 1, - }, - cell_values: vec![(((Any::advice(), 4).into(), 0).into(), "0".to_string())], - }, - VerifyFailure::ConstraintNotSatisfied { - constraint: ( - (17, "Short fixed-base mul gate").into(), - 3, - "negation_check" - ) - .into(), - location: FailureLocation::InRegion { - region: (3, "Short fixed-base mul (most significant word)").into(), - offset: 1, - }, - cell_values: vec![ - ( - ((Any::advice(), 1).into(), 0).into(), - format_value(negation_check_y), - ), - ( - ((Any::advice(), 3).into(), 0).into(), - format_value(negation_check_y), - ), - (((Any::advice(), 4).into(), 0).into(), "0".to_string()), - ], - } - ]) - ); - } - } -} diff --git a/halo2_gadgets/src/ecc/chip/witness_point.rs b/halo2_gadgets/src/ecc/chip/witness_point.rs deleted file mode 100644 index ef83bbde54..0000000000 --- a/halo2_gadgets/src/ecc/chip/witness_point.rs +++ /dev/null @@ -1,174 +0,0 @@ -use super::{EccPoint, NonIdentityEccPoint}; - -use group::prime::PrimeCurveAffine; - -use halo2_proofs::{ - circuit::{AssignedCell, Region, Value}, - plonk::{ - Advice, Assigned, Column, ConstraintSystem, Constraints, Error, Expression, Selector, - VirtualCells, - }, - poly::Rotation, -}; -use halo2curves::{pasta::pallas, CurveAffine}; - -type Coordinates = ( - AssignedCell, pallas::Base>, - AssignedCell, pallas::Base>, -); - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct Config { - q_point: Selector, - q_point_non_id: Selector, - // x-coordinate - pub x: Column, - // y-coordinate - pub y: Column, -} - -impl Config { - pub(super) fn configure( - meta: &mut ConstraintSystem, - x: Column, - y: Column, - ) -> Self { - let config = Self { - q_point: meta.selector(), - q_point_non_id: meta.selector(), - x, - y, - }; - - config.create_gate(meta); - - config - } - - fn create_gate(&self, meta: &mut ConstraintSystem) { - let curve_eqn = |meta: &mut VirtualCells| { - let x = meta.query_advice(self.x, Rotation::cur()); - let y = meta.query_advice(self.y, Rotation::cur()); - - // y^2 = x^3 + b - y.square() - (x.clone().square() * x) - Expression::Constant(pallas::Affine::b()) - }; - - // https://p.z.cash/halo2-0.1:ecc-witness-point - meta.create_gate("witness point", |meta| { - // Check that the point being witnessed is either: - // - the identity, which is mapped to (0, 0) in affine coordinates; or - // - a valid curve point y^2 = x^3 + b, where b = 5 in the Pallas equation - - let q_point = meta.query_selector(self.q_point); - let x = meta.query_advice(self.x, Rotation::cur()); - let y = meta.query_advice(self.y, Rotation::cur()); - - // We can't use `Constraints::with_selector` because that creates constraints - // of the form `q_point * (x * curve_eqn)`, but this was implemented without - // parentheses, and thus evaluates as `(q_point * x) * curve_eqn`, which is - // structurally different in the pinned verifying key. - [ - ("x == 0 v on_curve", q_point.clone() * x * curve_eqn(meta)), - ("y == 0 v on_curve", q_point * y * curve_eqn(meta)), - ] - }); - - // https://p.z.cash/halo2-0.1:ecc-witness-non-identity-point - meta.create_gate("witness non-identity point", |meta| { - // Check that the point being witnessed is a valid curve point y^2 = x^3 + b, - // where b = 5 in the Pallas equation - - let q_point_non_id = meta.query_selector(self.q_point_non_id); - - Constraints::with_selector(q_point_non_id, Some(("on_curve", curve_eqn(meta)))) - }); - } - - fn assign_xy( - &self, - value: Value<(Assigned, Assigned)>, - offset: usize, - region: &mut Region<'_, pallas::Base>, - ) -> Result { - // Assign `x` value - let x_val = value.map(|value| value.0); - let x_var = region.assign_advice(|| "x", self.x, offset, || x_val)?; - - // Assign `y` value - let y_val = value.map(|value| value.1); - let y_var = region.assign_advice(|| "y", self.y, offset, || y_val)?; - - Ok((x_var, y_var)) - } - - /// Assigns a point that can be the identity. - pub(super) fn point( - &self, - value: Value, - offset: usize, - region: &mut Region<'_, pallas::Base>, - ) -> Result { - // Enable `q_point` selector - self.q_point.enable(region, offset)?; - - let value = value.map(|value| { - // Map the identity to (0, 0). - if value == pallas::Affine::identity() { - (Assigned::Zero, Assigned::Zero) - } else { - let value = value.coordinates().unwrap(); - (value.x().into(), value.y().into()) - } - }); - - self.assign_xy(value, offset, region) - .map(|(x, y)| EccPoint { x, y }) - } - - /// Assigns a non-identity point. - pub(super) fn point_non_id( - &self, - value: Value, - offset: usize, - region: &mut Region<'_, pallas::Base>, - ) -> Result { - // Enable `q_point_non_id` selector - self.q_point_non_id.enable(region, offset)?; - - // Return an error if the point is the identity. - value.error_if_known_and(|value| value == &pallas::Affine::identity())?; - - let value = value.map(|value| { - let value = value.coordinates().unwrap(); - (value.x().into(), value.y().into()) - }); - - self.assign_xy(value, offset, region) - .map(|(x, y)| NonIdentityEccPoint { x, y }) - } -} - -#[cfg(test)] -pub mod tests { - use halo2_proofs::circuit::Layouter; - use halo2curves::pasta::pallas; - - use super::*; - use crate::ecc::{EccInstructions, NonIdentityPoint}; - - pub fn test_witness_non_id< - EccChip: EccInstructions + Clone + Eq + std::fmt::Debug, - >( - chip: EccChip, - mut layouter: impl Layouter, - ) { - // Witnessing the identity should return an error. - NonIdentityPoint::new( - chip, - layouter.namespace(|| "witness identity"), - Value::known(pallas::Affine::identity()), - ) - .expect_err("witnessing 𝒪 should return an error"); - } -} diff --git a/halo2_gadgets/src/lib.rs b/halo2_gadgets/src/lib.rs deleted file mode 100644 index 8d4d4292b0..0000000000 --- a/halo2_gadgets/src/lib.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! This crate provides various common gadgets and chips for use with `halo2_proofs`. -//! -//! # Gadgets -//! -//! Gadgets are an abstraction for writing reusable and interoperable circuit logic. They -//! do not create any circuit constraints or assignments themselves, instead interacting -//! with the circuit through a defined "instruction set". A circuit developer uses gadgets -//! by instantiating them with a particular choice of chip. -//! -//! # Chips -//! -//! Chips implement the low-level circuit constraints. The same instructions may be -//! implemented by multiple chips, enabling different performance trade-offs to be made. -//! Chips can be highly optimised by their developers, as long as they conform to the -//! defined instructions. - -#![cfg_attr(docsrs, feature(doc_cfg))] -// Temporary until we have more of the crate implemented. -#![allow(dead_code)] -// Catch documentation errors caused by code changes. -#![deny(rustdoc::broken_intra_doc_links)] -#![deny(missing_debug_implementations)] -#![deny(missing_docs)] -#![deny(unsafe_code)] - -pub mod ecc; -pub mod poseidon; -#[cfg(feature = "unstable")] -#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] -pub mod sha256; -pub mod sinsemilla; -pub mod utilities; diff --git a/halo2_gadgets/src/poseidon.rs b/halo2_gadgets/src/poseidon.rs deleted file mode 100644 index bfd78f3dee..0000000000 --- a/halo2_gadgets/src/poseidon.rs +++ /dev/null @@ -1,297 +0,0 @@ -//! The Poseidon algebraic hash function. - -use std::convert::TryInto; -use std::fmt; -use std::marker::PhantomData; - -use ff::PrimeField; -use group::ff::Field; -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter}, - plonk::Error, -}; - -mod pow5; -pub use pow5::{Pow5Chip, Pow5Config, StateWord}; - -pub mod primitives; -use primitives::{Absorbing, ConstantLength, Domain, Spec, SpongeMode, Squeezing, State}; - -/// A word from the padded input to a Poseidon sponge. -#[derive(Clone, Debug)] -pub enum PaddedWord { - /// A message word provided by the prover. - Message(AssignedCell), - /// A padding word, that will be fixed in the circuit parameters. - Padding(F), -} - -/// The set of circuit instructions required to use the Poseidon permutation. -pub trait PoseidonInstructions, const T: usize, const RATE: usize>: - Chip -{ - /// Variable representing the word over which the Poseidon permutation operates. - type Word: Clone + fmt::Debug + From> + Into>; - - /// Applies the Poseidon permutation to the given state. - fn permute( - &self, - layouter: &mut impl Layouter, - initial_state: &State, - ) -> Result, Error>; -} - -/// The set of circuit instructions required to use the [`Sponge`] and [`Hash`] gadgets. -/// -/// [`Hash`]: self::Hash -pub trait PoseidonSpongeInstructions< - F: Field, - S: Spec, - D: Domain, - const T: usize, - const RATE: usize, ->: PoseidonInstructions -{ - /// Returns the initial empty state for the given domain. - fn initial_state(&self, layouter: &mut impl Layouter) - -> Result, Error>; - - /// Adds the given input to the state. - fn add_input( - &self, - layouter: &mut impl Layouter, - initial_state: &State, - input: &Absorbing, RATE>, - ) -> Result, Error>; - - /// Extracts sponge output from the given state. - fn get_output(state: &State) -> Squeezing; -} - -/// A word over which the Poseidon permutation operates. -#[derive(Debug)] -pub struct Word< - F: Field, - PoseidonChip: PoseidonInstructions, - S: Spec, - const T: usize, - const RATE: usize, -> { - inner: PoseidonChip::Word, -} - -impl< - F: Field, - PoseidonChip: PoseidonInstructions, - S: Spec, - const T: usize, - const RATE: usize, - > Word -{ - /// The word contained in this gadget. - pub fn inner(&self) -> PoseidonChip::Word { - self.inner.clone() - } - - /// Construct a [`Word`] gadget from the inner word. - pub fn from_inner(inner: PoseidonChip::Word) -> Self { - Self { inner } - } -} - -fn poseidon_sponge< - F: Field, - PoseidonChip: PoseidonSpongeInstructions, - S: Spec, - D: Domain, - const T: usize, - const RATE: usize, ->( - chip: &PoseidonChip, - mut layouter: impl Layouter, - state: &mut State, - input: Option<&Absorbing, RATE>>, -) -> Result, Error> { - if let Some(input) = input { - *state = chip.add_input(&mut layouter, state, input)?; - } - *state = chip.permute(&mut layouter, state)?; - Ok(PoseidonChip::get_output(state)) -} - -/// A Poseidon sponge. -#[derive(Debug)] -pub struct Sponge< - F: Field, - PoseidonChip: PoseidonSpongeInstructions, - S: Spec, - M: SpongeMode, - D: Domain, - const T: usize, - const RATE: usize, -> { - chip: PoseidonChip, - mode: M, - state: State, - _marker: PhantomData, -} - -impl< - F: Field, - PoseidonChip: PoseidonSpongeInstructions, - S: Spec, - D: Domain, - const T: usize, - const RATE: usize, - > Sponge, RATE>, D, T, RATE> -{ - /// Constructs a new duplex sponge for the given Poseidon specification. - pub fn new(chip: PoseidonChip, mut layouter: impl Layouter) -> Result { - chip.initial_state(&mut layouter).map(|state| Sponge { - chip, - mode: Absorbing( - (0..RATE) - .map(|_| None) - .collect::>() - .try_into() - .unwrap(), - ), - state, - _marker: PhantomData, - }) - } - - /// Absorbs an element into the sponge. - pub fn absorb( - &mut self, - mut layouter: impl Layouter, - value: PaddedWord, - ) -> Result<(), Error> { - for entry in self.mode.0.iter_mut() { - if entry.is_none() { - *entry = Some(value); - return Ok(()); - } - } - - // We've already absorbed as many elements as we can - let _ = poseidon_sponge( - &self.chip, - layouter.namespace(|| "PoseidonSponge"), - &mut self.state, - Some(&self.mode), - )?; - self.mode = Absorbing::init_with(value); - - Ok(()) - } - - /// Transitions the sponge into its squeezing state. - #[allow(clippy::type_complexity)] - pub fn finish_absorbing( - mut self, - mut layouter: impl Layouter, - ) -> Result, D, T, RATE>, Error> - { - let mode = poseidon_sponge( - &self.chip, - layouter.namespace(|| "PoseidonSponge"), - &mut self.state, - Some(&self.mode), - )?; - - Ok(Sponge { - chip: self.chip, - mode, - state: self.state, - _marker: PhantomData, - }) - } -} - -impl< - F: Field, - PoseidonChip: PoseidonSpongeInstructions, - S: Spec, - D: Domain, - const T: usize, - const RATE: usize, - > Sponge, D, T, RATE> -{ - /// Squeezes an element from the sponge. - pub fn squeeze(&mut self, mut layouter: impl Layouter) -> Result, Error> { - loop { - for entry in self.mode.0.iter_mut() { - if let Some(inner) = entry.take() { - return Ok(inner.into()); - } - } - - // We've already squeezed out all available elements - self.mode = poseidon_sponge( - &self.chip, - layouter.namespace(|| "PoseidonSponge"), - &mut self.state, - None, - )?; - } - } -} - -/// A Poseidon hash function, built around a sponge. -#[derive(Debug)] -pub struct Hash< - F: Field, - PoseidonChip: PoseidonSpongeInstructions, - S: Spec, - D: Domain, - const T: usize, - const RATE: usize, -> { - sponge: Sponge, RATE>, D, T, RATE>, -} - -impl< - F: Field, - PoseidonChip: PoseidonSpongeInstructions, - S: Spec, - D: Domain, - const T: usize, - const RATE: usize, - > Hash -{ - /// Initializes a new hasher. - pub fn init(chip: PoseidonChip, layouter: impl Layouter) -> Result { - Sponge::new(chip, layouter).map(|sponge| Hash { sponge }) - } -} - -impl< - F: PrimeField, - PoseidonChip: PoseidonSpongeInstructions, T, RATE>, - S: Spec, - const T: usize, - const RATE: usize, - const L: usize, - > Hash, T, RATE> -{ - /// Hashes the given input. - pub fn hash( - mut self, - mut layouter: impl Layouter, - message: [AssignedCell; L], - ) -> Result, Error> { - for (i, value) in message - .into_iter() - .map(PaddedWord::Message) - .chain( as Domain>::padding(L).map(PaddedWord::Padding)) - .enumerate() - { - self.sponge - .absorb(layouter.namespace(|| format!("absorb_{}", i)), value)?; - } - self.sponge - .finish_absorbing(layouter.namespace(|| "finish absorbing"))? - .squeeze(layouter.namespace(|| "squeeze")) - } -} diff --git a/halo2_gadgets/src/poseidon/pow5.rs b/halo2_gadgets/src/poseidon/pow5.rs deleted file mode 100644 index 51c1f059ca..0000000000 --- a/halo2_gadgets/src/poseidon/pow5.rs +++ /dev/null @@ -1,887 +0,0 @@ -use std::convert::TryInto; -use std::iter; - -use halo2_proofs::{ - arithmetic::Field, - circuit::{AssignedCell, Cell, Chip, Layouter, Region, Value}, - plonk::{ - Advice, Any, Column, ConstraintSystem, Constraints, Error, Expression, Fixed, Selector, - }, - poly::Rotation, -}; - -use super::{ - primitives::{Absorbing, Domain, Mds, Spec, Squeezing, State}, - PaddedWord, PoseidonInstructions, PoseidonSpongeInstructions, -}; -use crate::utilities::Var; - -/// Configuration for a [`Pow5Chip`]. -#[derive(Clone, Debug)] -pub struct Pow5Config { - pub(crate) state: [Column; WIDTH], - partial_sbox: Column, - rc_a: [Column; WIDTH], - rc_b: [Column; WIDTH], - s_full: Selector, - s_partial: Selector, - s_pad_and_add: Selector, - - half_full_rounds: usize, - half_partial_rounds: usize, - alpha: [u64; 4], - round_constants: Vec<[F; WIDTH]>, - m_reg: Mds, - m_inv: Mds, -} - -/// A Poseidon chip using an $x^5$ S-Box. -/// -/// The chip is implemented using a single round per row for full rounds, and two rounds -/// per row for partial rounds. -#[derive(Debug)] -pub struct Pow5Chip { - config: Pow5Config, -} - -impl Pow5Chip { - /// Configures this chip for use in a circuit. - /// - /// # Side-effects - /// - /// All columns in `state` will be equality-enabled. - // - // TODO: Does the rate need to be hard-coded here, or only the width? It probably - // needs to be known wherever we implement the hashing gadget, but it isn't strictly - // necessary for the permutation. - pub fn configure>( - meta: &mut ConstraintSystem, - state: [Column; WIDTH], - partial_sbox: Column, - rc_a: [Column; WIDTH], - rc_b: [Column; WIDTH], - ) -> Pow5Config { - assert_eq!(RATE, WIDTH - 1); - // Generate constants for the Poseidon permutation. - // This gadget requires R_F and R_P to be even. - assert!(S::full_rounds() & 1 == 0); - assert!(S::partial_rounds() & 1 == 0); - let half_full_rounds = S::full_rounds() / 2; - let half_partial_rounds = S::partial_rounds() / 2; - let (round_constants, m_reg, m_inv) = S::constants(); - - // This allows state words to be initialized (by constraining them equal to fixed - // values), and used in a permutation from an arbitrary region. rc_a is used in - // every permutation round, while rc_b is empty in the initial and final full - // rounds, so we use rc_b as "scratch space" for fixed values (enabling potential - // layouter optimisations). - for column in iter::empty() - .chain(state.iter().cloned().map(Column::::from)) - .chain(rc_b.iter().cloned().map(Column::::from)) - { - meta.enable_equality(column); - } - - let s_full = meta.selector(); - let s_partial = meta.selector(); - let s_pad_and_add = meta.selector(); - - let alpha = [5, 0, 0, 0]; - let pow_5 = |v: Expression| { - let v2 = v.clone() * v.clone(); - v2.clone() * v2 * v - }; - - meta.create_gate("full round", |meta| { - let s_full = meta.query_selector(s_full); - - Constraints::with_selector( - s_full, - (0..WIDTH) - .map(|next_idx| { - let state_next = meta.query_advice(state[next_idx], Rotation::next()); - let expr = (0..WIDTH) - .map(|idx| { - let state_cur = meta.query_advice(state[idx], Rotation::cur()); - let rc_a = meta.query_fixed(rc_a[idx], Rotation::cur()); - pow_5(state_cur + rc_a) * m_reg[next_idx][idx] - }) - .reduce(|acc, term| acc + term) - .expect("WIDTH > 0"); - expr - state_next - }) - .collect::>(), - ) - }); - - meta.create_gate("partial rounds", |meta| { - let cur_0 = meta.query_advice(state[0], Rotation::cur()); - let mid_0 = meta.query_advice(partial_sbox, Rotation::cur()); - - let rc_a0 = meta.query_fixed(rc_a[0], Rotation::cur()); - let rc_b0 = meta.query_fixed(rc_b[0], Rotation::cur()); - - let s_partial = meta.query_selector(s_partial); - - use halo2_proofs::plonk::VirtualCells; - let mid = |idx: usize, meta: &mut VirtualCells| { - let mid = mid_0.clone() * m_reg[idx][0]; - (1..WIDTH).fold(mid, |acc, cur_idx| { - let cur = meta.query_advice(state[cur_idx], Rotation::cur()); - let rc_a = meta.query_fixed(rc_a[cur_idx], Rotation::cur()); - acc + (cur + rc_a) * m_reg[idx][cur_idx] - }) - }; - - let next = |idx: usize, meta: &mut VirtualCells| { - (0..WIDTH) - .map(|next_idx| { - let next = meta.query_advice(state[next_idx], Rotation::next()); - next * m_inv[idx][next_idx] - }) - .reduce(|acc, next| acc + next) - .expect("WIDTH > 0") - }; - - let partial_round_linear = |idx: usize, meta: &mut VirtualCells| { - let rc_b = meta.query_fixed(rc_b[idx], Rotation::cur()); - mid(idx, meta) + rc_b - next(idx, meta) - }; - - Constraints::with_selector( - s_partial, - std::iter::empty() - // state[0] round a - .chain(Some(pow_5(cur_0 + rc_a0) - mid_0.clone())) - // state[0] round b - .chain(Some(pow_5(mid(0, meta) + rc_b0) - next(0, meta))) - .chain((1..WIDTH).map(|idx| partial_round_linear(idx, meta))) - .collect::>(), - ) - }); - - meta.create_gate("pad-and-add", |meta| { - let initial_state_rate = meta.query_advice(state[RATE], Rotation::prev()); - let output_state_rate = meta.query_advice(state[RATE], Rotation::next()); - - let s_pad_and_add = meta.query_selector(s_pad_and_add); - - let pad_and_add = |idx: usize| { - let initial_state = meta.query_advice(state[idx], Rotation::prev()); - let input = meta.query_advice(state[idx], Rotation::cur()); - let output_state = meta.query_advice(state[idx], Rotation::next()); - - // We pad the input by storing the required padding in fixed columns and - // then constraining the corresponding input columns to be equal to it. - initial_state + input - output_state - }; - - Constraints::with_selector( - s_pad_and_add, - (0..RATE) - .map(pad_and_add) - // The capacity element is never altered by the input. - .chain(Some(initial_state_rate - output_state_rate)) - .collect::>(), - ) - }); - - Pow5Config { - state, - partial_sbox, - rc_a, - rc_b, - s_full, - s_partial, - s_pad_and_add, - half_full_rounds, - half_partial_rounds, - alpha, - round_constants, - m_reg, - m_inv, - } - } - - /// Construct a [`Pow5Chip`]. - pub fn construct(config: Pow5Config) -> Self { - Pow5Chip { config } - } -} - -impl Chip for Pow5Chip { - type Config = Pow5Config; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -impl, const WIDTH: usize, const RATE: usize> - PoseidonInstructions for Pow5Chip -{ - type Word = StateWord; - - fn permute( - &self, - layouter: &mut impl Layouter, - initial_state: &State, - ) -> Result, Error> { - let config = self.config(); - - layouter.assign_region( - || "permute state", - |mut region| { - // Load the initial state into this region. - let state = Pow5State::load(&mut region, config, initial_state)?; - - let state = (0..config.half_full_rounds) - .try_fold(state, |res, r| res.full_round(&mut region, config, r, r))?; - - let state = (0..config.half_partial_rounds).try_fold(state, |res, r| { - res.partial_round( - &mut region, - config, - config.half_full_rounds + 2 * r, - config.half_full_rounds + r, - ) - })?; - - let state = (0..config.half_full_rounds).try_fold(state, |res, r| { - res.full_round( - &mut region, - config, - config.half_full_rounds + 2 * config.half_partial_rounds + r, - config.half_full_rounds + config.half_partial_rounds + r, - ) - })?; - - Ok(state.0) - }, - ) - } -} - -impl< - F: Field, - S: Spec, - D: Domain, - const WIDTH: usize, - const RATE: usize, - > PoseidonSpongeInstructions for Pow5Chip -{ - fn initial_state( - &self, - layouter: &mut impl Layouter, - ) -> Result, Error> { - let config = self.config(); - let state = layouter.assign_region( - || format!("initial state for domain {}", D::name()), - |mut region| { - let mut state = Vec::with_capacity(WIDTH); - let mut load_state_word = |i: usize, value: F| -> Result<_, Error> { - let var = region.assign_advice_from_constant( - || format!("state_{}", i), - config.state[i], - 0, - value, - )?; - state.push(StateWord(var)); - - Ok(()) - }; - - for i in 0..RATE { - load_state_word(i, F::ZERO)?; - } - load_state_word(RATE, D::initial_capacity_element())?; - - Ok(state) - }, - )?; - - Ok(state.try_into().unwrap()) - } - - fn add_input( - &self, - layouter: &mut impl Layouter, - initial_state: &State, - input: &Absorbing, RATE>, - ) -> Result, Error> { - let config = self.config(); - layouter.assign_region( - || format!("add input for domain {}", D::name()), - |mut region| { - config.s_pad_and_add.enable(&mut region, 1)?; - - // Load the initial state into this region. - let load_state_word = |i: usize| { - initial_state[i] - .0 - .copy_advice( - || format!("load state_{}", i), - &mut region, - config.state[i], - 0, - ) - .map(StateWord) - }; - let initial_state: Result, Error> = - (0..WIDTH).map(load_state_word).collect(); - let initial_state = initial_state?; - - // Load the input into this region. - let load_input_word = |i: usize| { - let constraint_var = match input.0[i].clone() { - Some(PaddedWord::Message(word)) => word, - Some(PaddedWord::Padding(padding_value)) => region.assign_fixed( - || format!("load pad_{}", i), - config.rc_b[i], - 1, - || Value::known(padding_value), - )?, - _ => panic!("Input is not padded"), - }; - constraint_var - .copy_advice( - || format!("load input_{}", i), - &mut region, - config.state[i], - 1, - ) - .map(StateWord) - }; - let input: Result, Error> = (0..RATE).map(load_input_word).collect(); - let input = input?; - - // Constrain the output. - let constrain_output_word = |i: usize| { - let value = initial_state[i].0.value().copied() - + input - .get(i) - .map(|word| word.0.value().cloned()) - // The capacity element is never altered by the input. - .unwrap_or_else(|| Value::known(F::ZERO)); - region - .assign_advice( - || format!("load output_{}", i), - config.state[i], - 2, - || value, - ) - .map(StateWord) - }; - - let output: Result, Error> = (0..WIDTH).map(constrain_output_word).collect(); - output.map(|output| output.try_into().unwrap()) - }, - ) - } - - fn get_output(state: &State) -> Squeezing { - Squeezing( - state[..RATE] - .iter() - .map(|word| Some(word.clone())) - .collect::>() - .try_into() - .unwrap(), - ) - } -} - -/// A word in the Poseidon state. -#[derive(Clone, Debug)] -pub struct StateWord(AssignedCell); - -impl From> for AssignedCell { - fn from(state_word: StateWord) -> AssignedCell { - state_word.0 - } -} - -impl From> for StateWord { - fn from(cell_value: AssignedCell) -> StateWord { - StateWord(cell_value) - } -} - -impl Var for StateWord { - fn cell(&self) -> Cell { - self.0.cell() - } - - fn value(&self) -> Value { - self.0.value().cloned() - } -} - -#[derive(Debug)] -struct Pow5State([StateWord; WIDTH]); - -impl Pow5State { - fn full_round( - self, - region: &mut Region, - config: &Pow5Config, - round: usize, - offset: usize, - ) -> Result { - Self::round(region, config, round, offset, config.s_full, |_| { - let q = self.0.iter().enumerate().map(|(idx, word)| { - word.0 - .value() - .map(|v| *v + config.round_constants[round][idx]) - }); - let r: Value> = q.map(|q| q.map(|q| q.pow(config.alpha))).collect(); - let m = &config.m_reg; - let state = m.iter().map(|m_i| { - r.as_ref().map(|r| { - r.iter() - .enumerate() - .fold(F::ZERO, |acc, (j, r_j)| acc + m_i[j] * r_j) - }) - }); - - Ok((round + 1, state.collect::>().try_into().unwrap())) - }) - } - - fn partial_round( - self, - region: &mut Region, - config: &Pow5Config, - round: usize, - offset: usize, - ) -> Result { - Self::round(region, config, round, offset, config.s_partial, |region| { - let m = &config.m_reg; - let p: Value> = self.0.iter().map(|word| word.0.value().cloned()).collect(); - - let r: Value> = p.map(|p| { - let r_0 = (p[0] + config.round_constants[round][0]).pow(config.alpha); - let r_i = p[1..] - .iter() - .enumerate() - .map(|(i, p_i)| *p_i + config.round_constants[round][i + 1]); - std::iter::empty().chain(Some(r_0)).chain(r_i).collect() - }); - - region.assign_advice( - || format!("round_{} partial_sbox", round), - config.partial_sbox, - offset, - || r.as_ref().map(|r| r[0]), - )?; - - let p_mid: Value> = m - .iter() - .map(|m_i| { - r.as_ref().map(|r| { - m_i.iter() - .zip(r.iter()) - .fold(F::ZERO, |acc, (m_ij, r_j)| acc + *m_ij * r_j) - }) - }) - .collect(); - - // Load the second round constants. - let mut load_round_constant = |i: usize| { - region.assign_fixed( - || format!("round_{} rc_{}", round + 1, i), - config.rc_b[i], - offset, - || Value::known(config.round_constants[round + 1][i]), - ) - }; - for i in 0..WIDTH { - load_round_constant(i)?; - } - - let r_mid: Value> = p_mid.map(|p| { - let r_0 = (p[0] + config.round_constants[round + 1][0]).pow(config.alpha); - let r_i = p[1..] - .iter() - .enumerate() - .map(|(i, p_i)| *p_i + config.round_constants[round + 1][i + 1]); - std::iter::empty().chain(Some(r_0)).chain(r_i).collect() - }); - - let state: Vec> = m - .iter() - .map(|m_i| { - r_mid.as_ref().map(|r| { - m_i.iter() - .zip(r.iter()) - .fold(F::ZERO, |acc, (m_ij, r_j)| acc + *m_ij * r_j) - }) - }) - .collect(); - - Ok((round + 2, state.try_into().unwrap())) - }) - } - - fn load( - region: &mut Region, - config: &Pow5Config, - initial_state: &State, WIDTH>, - ) -> Result { - let load_state_word = |i: usize| { - initial_state[i] - .0 - .copy_advice(|| format!("load state_{}", i), region, config.state[i], 0) - .map(StateWord) - }; - - let state: Result, _> = (0..WIDTH).map(load_state_word).collect(); - state.map(|state| Pow5State(state.try_into().unwrap())) - } - - fn round( - region: &mut Region, - config: &Pow5Config, - round: usize, - offset: usize, - round_gate: Selector, - round_fn: impl FnOnce(&mut Region) -> Result<(usize, [Value; WIDTH]), Error>, - ) -> Result { - // Enable the required gate. - round_gate.enable(region, offset)?; - - // Load the round constants. - let mut load_round_constant = |i: usize| { - region.assign_fixed( - || format!("round_{} rc_{}", round, i), - config.rc_a[i], - offset, - || Value::known(config.round_constants[round][i]), - ) - }; - for i in 0..WIDTH { - load_round_constant(i)?; - } - - // Compute the next round's state. - let (next_round, next_state) = round_fn(region)?; - - let next_state_word = |i: usize| { - let value = next_state[i]; - let var = region.assign_advice( - || format!("round_{} state_{}", next_round, i), - config.state[i], - offset + 1, - || value, - )?; - Ok(StateWord(var)) - }; - - let next_state: Result, _> = (0..WIDTH).map(next_state_word).collect(); - next_state.map(|next_state| Pow5State(next_state.try_into().unwrap())) - } -} - -#[cfg(test)] -mod tests { - use group::ff::{Field, PrimeField}; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use halo2curves::pasta::{pallas, Fp}; - use rand::rngs::OsRng; - - use super::{PoseidonInstructions, Pow5Chip, Pow5Config, StateWord}; - use crate::poseidon::{ - primitives::{self as poseidon, ConstantLength, P128Pow5T3 as OrchardNullifier, Spec}, - Hash, - }; - use std::convert::TryInto; - use std::marker::PhantomData; - - struct PermuteCircuit, const WIDTH: usize, const RATE: usize>( - PhantomData, - ); - - impl, const WIDTH: usize, const RATE: usize> Circuit - for PermuteCircuit - { - type Config = Pow5Config; - type FloorPlanner = SimpleFloorPlanner; - #[cfg(feature = "circuit-params")] - type Params = (); - - fn without_witnesses(&self) -> Self { - PermuteCircuit::(PhantomData) - } - - fn configure(meta: &mut ConstraintSystem) -> Pow5Config { - 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(), - ) - } - - fn synthesize( - &self, - config: Pow5Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let initial_state = layouter.assign_region( - || "prepare initial state", - |mut region| { - let state_word = |i: usize| { - let value = Value::known(Fp::from(i as u64)); - let var = region.assign_advice( - || format!("load state_{}", i), - config.state[i], - 0, - || value, - )?; - Ok(StateWord(var)) - }; - - let state: Result, Error> = (0..WIDTH).map(state_word).collect(); - Ok(state?.try_into().unwrap()) - }, - )?; - - let chip = Pow5Chip::construct(config.clone()); - let final_state = as PoseidonInstructions< - Fp, - S, - WIDTH, - RATE, - >>::permute(&chip, &mut layouter, &initial_state)?; - - // For the purpose of this test, compute the real final state inline. - let mut expected_final_state = (0..WIDTH) - .map(|idx| Fp::from(idx as u64)) - .collect::>() - .try_into() - .unwrap(); - let (round_constants, mds, _) = S::constants(); - poseidon::permute::<_, S, WIDTH, RATE>( - &mut expected_final_state, - &mds, - &round_constants, - ); - - layouter.assign_region( - || "constrain final state", - |mut region| { - let mut final_state_word = |i: usize| { - let var = region.assign_advice( - || format!("load final_state_{}", i), - config.state[i], - 0, - || Value::known(expected_final_state[i]), - )?; - region.constrain_equal(final_state[i].0.cell(), var.cell()) - }; - - for i in 0..(WIDTH) { - final_state_word(i)?; - } - - Ok(()) - }, - ) - } - } - - #[test] - fn poseidon_permute() { - let k = 6; - let circuit = PermuteCircuit::(PhantomData); - let prover = MockProver::run(k, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())) - } - - struct HashCircuit< - S: Spec, - const WIDTH: usize, - const RATE: usize, - const L: usize, - > { - message: Value<[Fp; L]>, - // For the purpose of this test, witness the result. - // TODO: Move this into an instance column. - output: Value, - _spec: PhantomData, - } - - impl, const WIDTH: usize, const RATE: usize, const L: usize> - Circuit for HashCircuit - { - type Config = Pow5Config; - type FloorPlanner = SimpleFloorPlanner; - #[cfg(feature = "circuit-params")] - type Params = (); - - fn without_witnesses(&self) -> Self { - Self { - message: Value::unknown(), - output: Value::unknown(), - _spec: PhantomData, - } - } - - fn configure(meta: &mut ConstraintSystem) -> Pow5Config { - 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::>(); - - meta.enable_constant(rc_b[0]); - - Pow5Chip::configure::( - meta, - state.try_into().unwrap(), - partial_sbox, - rc_a.try_into().unwrap(), - rc_b.try_into().unwrap(), - ) - } - - fn synthesize( - &self, - config: Pow5Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let chip = Pow5Chip::construct(config.clone()); - - let message = layouter.assign_region( - || "load message", - |mut region| { - let message_word = |i: usize| { - let value = self.message.map(|message_vals| message_vals[i]); - region.assign_advice( - || format!("load message_{}", i), - config.state[i], - 0, - || value, - ) - }; - - let message: Result, Error> = (0..L).map(message_word).collect(); - Ok(message?.try_into().unwrap()) - }, - )?; - - let hasher = Hash::<_, _, S, ConstantLength, WIDTH, RATE>::init( - chip, - layouter.namespace(|| "init"), - )?; - let output = hasher.hash(layouter.namespace(|| "hash"), message)?; - - layouter.assign_region( - || "constrain output", - |mut region| { - let expected_var = region.assign_advice( - || "load output", - config.state[0], - 0, - || self.output, - )?; - region.constrain_equal(output.cell(), expected_var.cell()) - }, - ) - } - } - - #[test] - fn poseidon_hash() { - let rng = OsRng; - - let message = [Fp::random(rng), Fp::random(rng)]; - let output = - poseidon::Hash::<_, OrchardNullifier, ConstantLength<2>, 3, 2>::init().hash(message); - - let k = 6; - let circuit = HashCircuit:: { - message: Value::known(message), - output: Value::known(output), - _spec: PhantomData, - }; - let prover = MockProver::run(k, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())) - } - - #[test] - fn poseidon_hash_longer_input() { - let rng = OsRng; - - let message = [Fp::random(rng), Fp::random(rng), Fp::random(rng)]; - let output = - poseidon::Hash::<_, OrchardNullifier, ConstantLength<3>, 3, 2>::init().hash(message); - - let k = 7; - let circuit = HashCircuit:: { - message: Value::known(message), - output: Value::known(output), - _spec: PhantomData, - }; - let prover = MockProver::run(k, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())) - } - - #[test] - fn hash_test_vectors() { - for tv in crate::poseidon::primitives::test_vectors::fp::hash() { - let message = [ - pallas::Base::from_repr(tv.input[0]).unwrap(), - pallas::Base::from_repr(tv.input[1]).unwrap(), - ]; - let output = poseidon::Hash::<_, OrchardNullifier, ConstantLength<2>, 3, 2>::init() - .hash(message); - - let k = 6; - let circuit = HashCircuit:: { - message: Value::known(message), - output: Value::known(output), - _spec: PhantomData, - }; - let prover = MockProver::run(k, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - } - - #[cfg(feature = "test-dev-graph")] - #[test] - fn print_poseidon_chip() { - use plotters::prelude::*; - - let root = BitMapBackend::new("poseidon-chip-layout.png", (1024, 768)).into_drawing_area(); - root.fill(&WHITE).unwrap(); - let root = root - .titled("Poseidon Chip Layout", ("sans-serif", 60)) - .unwrap(); - - let circuit = HashCircuit:: { - message: Value::unknown(), - output: Value::unknown(), - _spec: PhantomData, - }; - halo2_proofs::dev::CircuitLayout::default() - .render(6, &circuit, &root) - .unwrap(); - } -} diff --git a/halo2_gadgets/src/poseidon/primitives.rs b/halo2_gadgets/src/poseidon/primitives.rs deleted file mode 100644 index c456c87f54..0000000000 --- a/halo2_gadgets/src/poseidon/primitives.rs +++ /dev/null @@ -1,408 +0,0 @@ -//! The Poseidon algebraic hash function. - -use std::convert::TryInto; -use std::fmt; -use std::iter; -use std::marker::PhantomData; - -use ff::FromUniformBytes; -use ff::PrimeField; -use halo2_proofs::arithmetic::Field; - -pub(crate) mod fp; -pub(crate) mod fq; -pub(crate) mod grain; -pub(crate) mod mds; - -#[cfg(test)] -pub(crate) mod test_vectors; - -mod p128pow5t3; -pub use p128pow5t3::P128Pow5T3; - -use grain::SboxType; - -/// The type used to hold permutation state. -pub(crate) type State = [F; T]; - -/// The type used to hold sponge rate. -pub(crate) type SpongeRate = [Option; RATE]; - -/// The type used to hold the MDS matrix and its inverse. -pub type Mds = [[F; T]; T]; - -/// A specification for a Poseidon permutation. -pub trait Spec: fmt::Debug { - /// The number of full rounds for this specification. - /// - /// This must be an even number. - fn full_rounds() -> usize; - - /// The number of partial rounds for this specification. - fn partial_rounds() -> usize; - - /// The S-box for this specification. - fn sbox(val: F) -> F; - - /// Side-loaded index of the first correct and secure MDS that will be generated by - /// the reference implementation. - /// - /// This is used by the default implementation of [`Spec::constants`]. If you are - /// hard-coding the constants, you may leave this unimplemented. - fn secure_mds() -> usize; - - /// Generates `(round_constants, mds, mds^-1)` corresponding to this specification. - fn constants() -> (Vec<[F; T]>, Mds, Mds); -} - -/// Generates `(round_constants, mds, mds^-1)` corresponding to this specification. -pub fn generate_constants< - F: FromUniformBytes<64> + Ord, - S: Spec, - const T: usize, - const RATE: usize, ->() -> (Vec<[F; T]>, Mds, Mds) { - let r_f = S::full_rounds(); - let r_p = S::partial_rounds(); - - let mut grain = grain::Grain::new(SboxType::Pow, T as u16, r_f as u16, r_p as u16); - - let round_constants = (0..(r_f + r_p)) - .map(|_| { - let mut rc_row = [F::ZERO; T]; - for (rc, value) in rc_row - .iter_mut() - .zip((0..T).map(|_| grain.next_field_element())) - { - *rc = value; - } - rc_row - }) - .collect(); - - let (mds, mds_inv) = mds::generate_mds::(&mut grain, S::secure_mds()); - - (round_constants, mds, mds_inv) -} - -/// Runs the Poseidon permutation on the given state. -pub(crate) fn permute, const T: usize, const RATE: usize>( - state: &mut State, - mds: &Mds, - round_constants: &[[F; T]], -) { - let r_f = S::full_rounds() / 2; - let r_p = S::partial_rounds(); - - let apply_mds = |state: &mut State| { - let mut new_state = [F::ZERO; T]; - // Matrix multiplication - #[allow(clippy::needless_range_loop)] - for i in 0..T { - for j in 0..T { - new_state[i] += mds[i][j] * state[j]; - } - } - *state = new_state; - }; - - let full_round = |state: &mut State, rcs: &[F; T]| { - for (word, rc) in state.iter_mut().zip(rcs.iter()) { - *word = S::sbox(*word + rc); - } - apply_mds(state); - }; - - let part_round = |state: &mut State, rcs: &[F; T]| { - for (word, rc) in state.iter_mut().zip(rcs.iter()) { - *word += rc; - } - // In a partial round, the S-box is only applied to the first state word. - state[0] = S::sbox(state[0]); - apply_mds(state); - }; - - iter::empty() - .chain(iter::repeat(&full_round as &dyn Fn(&mut State, &[F; T])).take(r_f)) - .chain(iter::repeat(&part_round as &dyn Fn(&mut State, &[F; T])).take(r_p)) - .chain(iter::repeat(&full_round as &dyn Fn(&mut State, &[F; T])).take(r_f)) - .zip(round_constants.iter()) - .fold(state, |state, (round, rcs)| { - round(state, rcs); - state - }); -} - -fn poseidon_sponge, const T: usize, const RATE: usize>( - state: &mut State, - input: Option<&Absorbing>, - mds_matrix: &Mds, - round_constants: &[[F; T]], -) -> Squeezing { - if let Some(Absorbing(input)) = input { - // `Iterator::zip` short-circuits when one iterator completes, so this will only - // mutate the rate portion of the state. - for (word, value) in state.iter_mut().zip(input.iter()) { - *word += value.expect("poseidon_sponge is called with a padded input"); - } - } - - permute::(state, mds_matrix, round_constants); - - let mut output = [None; RATE]; - for (word, value) in output.iter_mut().zip(state.iter()) { - *word = Some(*value); - } - Squeezing(output) -} - -mod private { - pub trait SealedSpongeMode {} - impl SealedSpongeMode for super::Absorbing {} - impl SealedSpongeMode for super::Squeezing {} -} - -/// The state of the `Sponge`. -pub trait SpongeMode: private::SealedSpongeMode {} - -/// The absorbing state of the `Sponge`. -#[derive(Debug, Clone)] -pub struct Absorbing(pub(crate) SpongeRate); - -/// The squeezing state of the `Sponge`. -#[derive(Debug)] -pub struct Squeezing(pub(crate) SpongeRate); - -impl SpongeMode for Absorbing {} -impl SpongeMode for Squeezing {} - -impl Absorbing { - pub(crate) fn init_with(val: F) -> Self { - Self( - iter::once(Some(val)) - .chain((1..RATE).map(|_| None)) - .collect::>() - .try_into() - .unwrap(), - ) - } -} - -#[derive(Clone)] -/// A Poseidon sponge. -pub(crate) struct Sponge< - F: Field, - S: Spec, - M: SpongeMode, - const T: usize, - const RATE: usize, -> { - mode: M, - state: State, - mds_matrix: Mds, - round_constants: Vec<[F; T]>, - _marker: PhantomData, -} - -impl, const T: usize, const RATE: usize> - Sponge, T, RATE> -{ - /// Constructs a new sponge for the given Poseidon specification. - pub(crate) fn new(initial_capacity_element: F) -> Self { - let (round_constants, mds_matrix, _) = S::constants(); - - let mode = Absorbing([None; RATE]); - let mut state = [F::ZERO; T]; - state[RATE] = initial_capacity_element; - - Sponge { - mode, - state, - mds_matrix, - round_constants, - _marker: PhantomData, - } - } - - /// Absorbs an element into the sponge. - pub(crate) fn absorb(&mut self, value: F) { - for entry in self.mode.0.iter_mut() { - if entry.is_none() { - *entry = Some(value); - return; - } - } - - // We've already absorbed as many elements as we can - let _ = poseidon_sponge::( - &mut self.state, - Some(&self.mode), - &self.mds_matrix, - &self.round_constants, - ); - self.mode = Absorbing::init_with(value); - } - - /// Transitions the sponge into its squeezing state. - pub(crate) fn finish_absorbing(mut self) -> Sponge, T, RATE> { - let mode = poseidon_sponge::( - &mut self.state, - Some(&self.mode), - &self.mds_matrix, - &self.round_constants, - ); - - Sponge { - mode, - state: self.state, - mds_matrix: self.mds_matrix, - round_constants: self.round_constants, - _marker: PhantomData, - } - } -} - -impl, const T: usize, const RATE: usize> - Sponge, T, RATE> -{ - /// Squeezes an element from the sponge. - pub(crate) fn squeeze(&mut self) -> F { - loop { - for entry in self.mode.0.iter_mut() { - if let Some(e) = entry.take() { - return e; - } - } - - // We've already squeezed out all available elements - self.mode = poseidon_sponge::( - &mut self.state, - None, - &self.mds_matrix, - &self.round_constants, - ); - } - } -} - -/// A domain in which a Poseidon hash function is being used. -pub trait Domain { - /// Iterator that outputs padding field elements. - type Padding: IntoIterator; - - /// The name of this domain, for debug formatting purposes. - fn name() -> String; - - /// The initial capacity element, encoding this domain. - fn initial_capacity_element() -> F; - - /// Returns the padding to be appended to the input. - fn padding(input_len: usize) -> Self::Padding; -} - -/// A Poseidon hash function used with constant input length. -/// -/// Domain specified in [ePrint 2019/458 section 4.2](https://eprint.iacr.org/2019/458.pdf). -#[derive(Clone, Copy, Debug)] -pub struct ConstantLength; - -impl Domain for ConstantLength { - type Padding = iter::Take>; - - fn name() -> String { - format!("ConstantLength<{}>", L) - } - - fn initial_capacity_element() -> F { - // Capacity value is $length \cdot 2^64 + (o-1)$ where o is the output length. - // We hard-code an output length of 1. - F::from_u128((L as u128) << 64) - } - - fn padding(input_len: usize) -> Self::Padding { - assert_eq!(input_len, L); - // For constant-input-length hashing, we pad the input with zeroes to a multiple - // of RATE. On its own this would not be sponge-compliant padding, but the - // Poseidon authors encode the constant length into the capacity element, ensuring - // that inputs of different lengths do not share the same permutation. - let k = (L + RATE - 1) / RATE; - iter::repeat(F::ZERO).take(k * RATE - L) - } -} - -#[derive(Clone)] -/// A Poseidon hash function, built around a sponge. -pub struct Hash< - F: Field, - S: Spec, - D: Domain, - const T: usize, - const RATE: usize, -> { - sponge: Sponge, T, RATE>, - _domain: PhantomData, -} - -impl, D: Domain, const T: usize, const RATE: usize> - fmt::Debug for Hash -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Hash") - .field("width", &T) - .field("rate", &RATE) - .field("R_F", &S::full_rounds()) - .field("R_P", &S::partial_rounds()) - .field("domain", &D::name()) - .finish() - } -} - -impl, D: Domain, const T: usize, const RATE: usize> - Hash -{ - /// Initializes a new hasher. - pub fn init() -> Self { - Hash { - sponge: Sponge::new(D::initial_capacity_element()), - _domain: PhantomData, - } - } -} - -impl, const T: usize, const RATE: usize, const L: usize> - Hash, T, RATE> -{ - /// Hashes the given input. - pub fn hash(mut self, message: [F; L]) -> F { - for value in message - .into_iter() - .chain( as Domain>::padding(L)) - { - self.sponge.absorb(value); - } - self.sponge.finish_absorbing().squeeze() - } -} - -#[cfg(test)] -mod tests { - use super::{permute, ConstantLength, Hash, P128Pow5T3 as OrchardNullifier, Spec}; - use ff::PrimeField; - use halo2curves::pasta::pallas; - - #[test] - fn orchard_spec_equivalence() { - let message = [pallas::Base::from(6), pallas::Base::from(42)]; - - let (round_constants, mds, _) = OrchardNullifier::constants(); - - let hasher = Hash::<_, OrchardNullifier, ConstantLength<2>, 3, 2>::init(); - let result = hasher.hash(message); - - // The result should be equivalent to just directly applying the permutation and - // taking the first state element as the output. - let mut state = [message[0], message[1], pallas::Base::from_u128(2 << 64)]; - permute::<_, OrchardNullifier, 3, 2>(&mut state, &mds, &round_constants); - assert_eq!(state[0], result); - } -} diff --git a/halo2_gadgets/src/poseidon/primitives/fp.rs b/halo2_gadgets/src/poseidon/primitives/fp.rs deleted file mode 100644 index 38b38937fb..0000000000 --- a/halo2_gadgets/src/poseidon/primitives/fp.rs +++ /dev/null @@ -1,1431 +0,0 @@ -//! Constants for using Poseidon with the Pallas field. -//! -//! The constants 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 255 3 8 56 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001 -//! ``` -use halo2curves::pasta::pallas; - -// Number of round constants: 192 -// Round constants for GF(p): -pub(crate) const ROUND_CONSTANTS: [[pallas::Base; 3]; 64] = [ - [ - pallas::Base::from_raw([ - 0x5753_8c25_9642_6303, - 0x4e71_162f_3100_3b70, - 0x353f_628f_76d1_10f3, - 0x360d_7470_611e_473d, - ]), - pallas::Base::from_raw([ - 0xbdb7_4213_bf63_188b, - 0x4908_ac2f_12eb_e06f, - 0x5dc3_c6c5_febf_aa31, - 0x2bab_94d7_ae22_2d13, - ]), - pallas::Base::from_raw([ - 0x0939_d927_53cc_5dc8, - 0xef77_e7d7_3676_6c5d, - 0x2bf0_3e1a_29aa_871f, - 0x150c_93fe_f652_fb1c, - ]), - ], - [ - pallas::Base::from_raw([ - 0x1425_9dce_5377_82b2, - 0x03cc_0a60_141e_894e, - 0x955d_55db_56dc_57c1, - 0x3270_661e_6892_8b3a, - ]), - pallas::Base::from_raw([ - 0xce9f_b9ff_c345_afb3, - 0xb407_c370_f2b5_a1cc, - 0xa0b7_afe4_e205_7299, - 0x073f_116f_0412_2e25, - ]), - pallas::Base::from_raw([ - 0x8eba_d76f_c715_54d8, - 0x55c9_cd20_61ae_93ca, - 0x7aff_d09c_1f53_f5fd, - 0x2a32_ec5c_4ee5_b183, - ]), - ], - [ - pallas::Base::from_raw([ - 0x2d8c_cbe2_92ef_eead, - 0x634d_24fc_6e25_59f2, - 0x651e_2cfc_7406_28ca, - 0x2703_26ee_039d_f19e, - ]), - pallas::Base::from_raw([ - 0xa068_fc37_c182_e274, - 0x8af8_95bc_e012_f182, - 0xdc10_0fe7_fcfa_5491, - 0x27c6_642a_c633_bc66, - ]), - pallas::Base::from_raw([ - 0x9ca1_8682_e26d_7ff9, - 0x710e_1fb6_ab97_6a45, - 0xd27f_5739_6989_129d, - 0x1bdf_d8b0_1401_c70a, - ]), - ], - [ - pallas::Base::from_raw([ - 0xc832_d824_261a_35ea, - 0xf4f6_fb3f_9054_d373, - 0x14b9_d6a9_c84d_d678, - 0x162a_14c6_2f9a_89b8, - ]), - pallas::Base::from_raw([ - 0xf798_2466_7b5b_6bec, - 0xac0a_1fc7_1e2c_f0c0, - 0x2af6_f79e_3127_feea, - 0x2d19_3e0f_76de_586b, - ]), - pallas::Base::from_raw([ - 0x5d0b_f58d_c8a4_aa94, - 0x4fef_f829_8499_0ff8, - 0x8169_6ef1_104e_674f, - 0x044c_a3cc_4a85_d73b, - ]), - ], - [ - pallas::Base::from_raw([ - 0x6198_785f_0cd6_b9af, - 0xb8d9_e2d4_f314_f46f, - 0x1d04_5341_6d3e_235c, - 0x1cba_f2b3_71da_c6a8, - ]), - pallas::Base::from_raw([ - 0x343e_0761_0f3f_ede5, - 0x293c_4ab0_38fd_bbdc, - 0x0e6c_49d0_61b6_b5f4, - 0x1d5b_2777_692c_205b, - ]), - pallas::Base::from_raw([ - 0xf60e_971b_8d73_b04f, - 0x06a9_adb0_c1e6_f962, - 0xaa30_535b_dd74_9a7e, - 0x2e9b_dbba_3dd3_4bff, - ]), - ], - [ - pallas::Base::from_raw([ - 0x035a_1366_1f22_418b, - 0xde40_fbe2_6d04_7b05, - 0x8bd5_bae3_6969_299f, - 0x2de1_1886_b180_11ca, - ]), - pallas::Base::from_raw([ - 0xbc99_8884_ba96_a721, - 0x2ab9_395c_449b_e947, - 0x0d5b_4a3f_1841_dcd8, - 0x2e07_de17_80b8_a70d, - ]), - pallas::Base::from_raw([ - 0x825e_4c2b_b749_25ca, - 0x2504_40a9_9d6b_8af3, - 0xbbdb_63db_d52d_ad16, - 0x0f69_f185_4d20_ca0c, - ]), - ], - [ - pallas::Base::from_raw([ - 0x816c_0594_22dc_705e, - 0x6ce5_1135_07f9_6de9, - 0x0d13_5dc6_39fb_09a4, - 0x2eb1_b254_17fe_1767, - ]), - pallas::Base::from_raw([ - 0xb8b1_bdf4_953b_d82c, - 0xff36_c661_d26c_c42d, - 0x8c24_cb44_c3fa_b48a, - 0x115c_d0a0_643c_fb98, - ]), - pallas::Base::from_raw([ - 0xde80_1612_311d_04cd, - 0xbb57_ddf1_4e0f_958a, - 0x066d_7378_b999_868b, - 0x26ca_293f_7b2c_462d, - ]), - ], - [ - pallas::Base::from_raw([ - 0xf520_9d14_b248_20ca, - 0x0f16_0bf9_f71e_967f, - 0x2a83_0aa1_6241_2cd9, - 0x17bf_1b93_c4c7_e01a, - ]), - pallas::Base::from_raw([ - 0x05c8_6f2e_7dc2_93c5, - 0xe03c_0354_bd8c_fd38, - 0xa24f_8456_369c_85df, - 0x35b4_1a7a_c4f3_c571, - ]), - pallas::Base::from_raw([ - 0x72ac_156a_f435_d09e, - 0x64e1_4d3b_eb2d_ddde, - 0x4359_2799_4849_bea9, - 0x3b14_8008_0523_c439, - ]), - ], - [ - pallas::Base::from_raw([ - 0x2716_18d8_74b1_4c6d, - 0x08e2_8644_2a2d_3eb2, - 0x4950_856d_c907_d575, - 0x2cc6_8100_31dc_1b0d, - ]), - pallas::Base::from_raw([ - 0x91f3_18c0_9f0c_b566, - 0x9e51_7aa9_3b78_341d, - 0x0596_18e2_afd2_ef99, - 0x25bd_bbed_a1bd_e8c1, - ]), - pallas::Base::from_raw([ - 0xc631_3487_073f_7f7b, - 0x2a5e_d0a2_7b61_926c, - 0xb95f_33c2_5dde_8ac0, - 0x392a_4a87_58e0_6ee8, - ]), - ], - [ - pallas::Base::from_raw([ - 0xe7bb_cef0_2eb5_866c, - 0x5e6a_6fd1_5db8_9365, - 0x9aa6_111f_4de0_0948, - 0x272a_5587_8a08_442b, - ]), - pallas::Base::from_raw([ - 0x9b92_5b3c_5b21_e0e2, - 0xa6eb_ba01_1694_dd12, - 0xefa1_3c4e_60e2_6239, - 0x2d5b_308b_0cf0_2cdf, - ]), - pallas::Base::from_raw([ - 0xef38_c57c_3116_73ac, - 0x44df_f42f_18b4_6c56, - 0xdd5d_293d_72e2_e5f2, - 0x1654_9fc6_af2f_3b72, - ]), - ], - [ - pallas::Base::from_raw([ - 0x9b71_26d9_b468_60df, - 0x7639_8265_3442_0311, - 0xfa69_c3a2_ad52_f76d, - 0x1b10_bb7a_82af_ce39, - ]), - pallas::Base::from_raw([ - 0x90d2_7f6a_00b7_dfc8, - 0xd1b3_6968_ba04_05c0, - 0xc79c_2df7_dc98_a3be, - 0x0f1e_7505_ebd9_1d2f, - ]), - pallas::Base::from_raw([ - 0xff45_7756_b819_bb20, - 0x797f_d6e3_f18e_b1ca, - 0x537a_7497_a3b4_3f46, - 0x2f31_3faf_0d3f_6187, - ]), - ], - [ - pallas::Base::from_raw([ - 0xf0bc_3e73_2ecb_26f6, - 0x5cad_11eb_f0f7_ceb8, - 0xfa3c_a61c_0ed1_5bc5, - 0x3a5c_bb6d_e450_b481, - ]), - pallas::Base::from_raw([ - 0x8655_27cb_ca91_5982, - 0x51ba_a6e2_0f89_2b62, - 0xd920_86e2_53b4_39d6, - 0x3dab_54bc_9bef_688d, - ]), - pallas::Base::from_raw([ - 0x3680_45ac_f2b7_1ae3, - 0x4c24_b33b_410f_efd4, - 0xe280_d316_7012_3f74, - 0x06db_fb42_b979_884d, - ]), - ], - [ - pallas::Base::from_raw([ - 0xa7fc_32d2_2f18_b9d3, - 0xb8d2_de72_e3d2_c9ec, - 0xc6f0_39ea_1973_a63e, - 0x068d_6b46_08aa_e810, - ]), - pallas::Base::from_raw([ - 0x2b5d_fcc5_5725_55df, - 0xb868_a7d7_e1f1_f69a, - 0x0ee2_58c9_b8fd_fccd, - 0x366e_bfaf_a3ad_381c, - ]), - pallas::Base::from_raw([ - 0xe6bc_229e_95bc_76b1, - 0x7ef6_6d89_d044_d022, - 0x04db_3024_f41d_3f56, - 0x3967_8f65_512f_1ee4, - ]), - ], - [ - pallas::Base::from_raw([ - 0xe534_c88f_e53d_85fe, - 0xcf82_c25f_99dc_01a4, - 0xd58b_7750_a3bc_2fe1, - 0x2166_8f01_6a80_63c0, - ]), - pallas::Base::from_raw([ - 0x4bef_429b_c533_1608, - 0xe34d_ea56_439f_e195, - 0x1bc7_4936_3e98_a768, - 0x39d0_0994_a8a5_046a, - ]), - pallas::Base::from_raw([ - 0x770c_956f_60d8_81b3, - 0xb163_d416_05d3_9f99, - 0x6b20_3bbe_12fb_3425, - 0x1f9d_bdc3_f843_1263, - ]), - ], - [ - pallas::Base::from_raw([ - 0x9794_a9f7_c336_eab2, - 0xbe0b_c829_fe5e_66c6, - 0xe5f1_7b9e_0ee0_cab6, - 0x0277_45a9_cddf_ad95, - ]), - pallas::Base::from_raw([ - 0x5202_5657_abd8_aee0, - 0x2fa4_3fe2_0a45_c78d, - 0x788d_695c_61e9_3212, - 0x1cec_0803_c504_b635, - ]), - pallas::Base::from_raw([ - 0xd387_2a95_59a0_3a73, - 0xed50_82c8_dbf3_1365, - 0x7207_7448_ef87_cc6e, - 0x1235_23d7_5e9f_abc1, - ]), - ], - [ - pallas::Base::from_raw([ - 0x0017_79e3_a1d3_57f4, - 0x27fe_ba35_975e_e7e5, - 0xf419_b848_e5d6_94bf, - 0x1723_d145_2c9c_f02d, - ]), - pallas::Base::from_raw([ - 0x9dab_1ee4_dcf9_6622, - 0x21c3_f776_f572_836d, - 0xfcc0_573d_7e61_3694, - 0x1739_d180_a160_10bd, - ]), - pallas::Base::from_raw([ - 0x7029_0452_042d_048d, - 0xfafa_96fb_eb0a_b893, - 0xacce_3239_1794_b627, - 0x2d4e_6354_da9c_c554, - ]), - ], - [ - pallas::Base::from_raw([ - 0x670b_cf6f_8b48_5dcd, - 0x8f3b_d43f_9926_0621, - 0x4a86_9553_c9d0_07f8, - 0x153e_e614_2e53_5e33, - ]), - pallas::Base::from_raw([ - 0xd258_d2e2_b778_2172, - 0x968a_d442_4af8_3700, - 0x635e_f7e7_a430_b486, - 0x0c45_bfd3_a69a_aa65, - ]), - pallas::Base::from_raw([ - 0x0e56_33d2_51f7_3307, - 0x6897_ac0a_8ffa_5ff1, - 0xf2d5_6aec_8314_4600, - 0x0adf_d53b_256a_6957, - ]), - ], - [ - pallas::Base::from_raw([ - 0xac9d_36a8_b751_6d63, - 0x3f87_b28f_1c1b_e4bd, - 0x8cd1_726b_7cba_b8ee, - 0x315d_2ac8_ebdb_ac3c, - ]), - pallas::Base::from_raw([ - 0x299c_e44e_a423_d8e1, - 0xc9bb_60d1_f695_9879, - 0xcfae_c23d_2b16_883f, - 0x1b84_7271_2d02_eef4, - ]), - pallas::Base::from_raw([ - 0xc4a5_4041_98ad_f70c, - 0x367d_2c54_e369_28c9, - 0xbd0b_70fa_2255_eb6f, - 0x3c1c_d07e_fda6_ff24, - ]), - ], - [ - pallas::Base::from_raw([ - 0xbbe5_23ae_f9ab_107a, - 0x4a16_073f_738f_7e0c, - 0x687f_4e51_b2e1_dcd3, - 0x1360_52d2_6bb3_d373, - ]), - pallas::Base::from_raw([ - 0x676c_36c2_4ef9_67dd, - 0x7b3c_fbb8_7303_2681, - 0xc1bd_d859_a123_2a1d, - 0x16c9_6bee_f6a0_a848, - ]), - pallas::Base::from_raw([ - 0x067e_ec7f_2d63_40c4, - 0x0123_87ba_b4f1_662d, - 0x2ab7_fed8_f499_a9fb, - 0x284b_38c5_7ff6_5c26, - ]), - ], - [ - pallas::Base::from_raw([ - 0xaf1d_ff20_4c92_2f86, - 0xfc06_772c_1c04_11a6, - 0x39e2_4219_8897_d17c, - 0x0c59_93d1_75e8_1f66, - ]), - pallas::Base::from_raw([ - 0xbbf5_3f67_b1f8_7b15, - 0xf248_87ad_48e1_7759, - 0xfcda_655d_1ba9_c8f9, - 0x03bf_7a3f_7bd0_43da, - ]), - pallas::Base::from_raw([ - 0x9b5c_d09e_36d8_be62, - 0x4c8f_9cbe_69f0_e827, - 0xb0cf_9995_67f0_0e73, - 0x3188_fe4e_e9f9_fafb, - ]), - ], - [ - pallas::Base::from_raw([ - 0xafea_99a2_ec6c_595a, - 0x3af5_bf77_c1c4_2652, - 0x5a39_768c_480d_61e1, - 0x171f_528c_cf65_8437, - ]), - pallas::Base::from_raw([ - 0x5a05_63b9_b8e9_f1d5, - 0x812c_3286_ee70_0067, - 0x196e_4185_9b35_ef88, - 0x12f4_175c_4ab4_5afc, - ]), - pallas::Base::from_raw([ - 0x0e74_d4d3_6911_8b79, - 0x7e23_e1aa_be96_cfab, - 0x8f8f_dcf8_00a9_ac69, - 0x3a50_9e15_5cb7_ebfd, - ]), - ], - [ - pallas::Base::from_raw([ - 0x9871_2c65_678c_fd30, - 0x984b_c8f2_e4c1_b69e, - 0x1a89_920e_2504_c3b3, - 0x10f2_a685_df4a_27c8, - ]), - pallas::Base::from_raw([ - 0xe8a1_6728_cc9d_4918, - 0x5457_3c93_33c5_6321, - 0x1d8d_93d5_4ab9_1a0e, - 0x09e5_f497_90c8_a0e2, - ]), - pallas::Base::from_raw([ - 0x609a_7403_47cf_5fea, - 0x42d1_7ed6_ee0f_ab7e, - 0x2bf3_5705_d9f8_4a34, - 0x352d_69be_d80e_e3e5, - ]), - ], - [ - pallas::Base::from_raw([ - 0x3a75_8af6_fa84_e0e8, - 0xc634_debd_281b_76a6, - 0x4915_62fa_f2b1_90d3, - 0x058e_e73b_a9f3_f293, - ]), - pallas::Base::from_raw([ - 0x621a_1325_10a4_3904, - 0x092c_b921_19bc_76be, - 0xcd0f_1fc5_5b1a_3250, - 0x232f_99cc_911e_ddd9, - ]), - pallas::Base::from_raw([ - 0xc3b9_7c1e_301b_c213, - 0xf9ef_d52c_a6bc_2961, - 0x86c2_2c6c_5d48_69f0, - 0x201b_eed7_b8f3_ab81, - ]), - ], - [ - pallas::Base::from_raw([ - 0xbf6b_3431_ba94_e9bc, - 0x2938_8842_744a_1210, - 0xa1c9_291d_5860_2f51, - 0x1376_dce6_5800_30c6, - ]), - pallas::Base::from_raw([ - 0x6454_843c_5486_d7b3, - 0x072b_a8b0_2d92_e722, - 0x2b33_56c3_8238_f761, - 0x1793_199e_6fd6_ba34, - ]), - pallas::Base::from_raw([ - 0x06a3_f1d3_b433_311b, - 0x3c66_160d_c62a_acac, - 0x9fee_9c20_c87a_67df, - 0x22de_7a74_88dc_c735, - ]), - ], - [ - pallas::Base::from_raw([ - 0x30d6_e3fd_516b_47a8, - 0xdbe0_b77f_ae77_e1d0, - 0xdf8f_f37f_e2d8_edf8, - 0x3514_d5e9_066b_b160, - ]), - pallas::Base::from_raw([ - 0x1937_7427_137a_81c7, - 0xff45_3d6f_900f_144a, - 0xf919_a00d_abbf_5fa5, - 0x30cd_3006_931a_d636, - ]), - pallas::Base::from_raw([ - 0x5b6a_7422_0692_b506, - 0x8f9e_4b2c_ae2e_bb51, - 0x41f8_1a5c_f613_c8df, - 0x253d_1a5c_5293_4127, - ]), - ], - [ - pallas::Base::from_raw([ - 0x73f6_66cb_86a4_8e8e, - 0x851b_3a59_c990_fafc, - 0xa35e_9613_e7f5_fe92, - 0x035b_461c_02d7_9d19, - ]), - pallas::Base::from_raw([ - 0x7cfb_f86a_3aa0_4780, - 0x92b1_283c_2d5f_ccde, - 0x5bc0_0eed_d56b_93e0, - 0x23a9_9280_79d1_75bd, - ]), - pallas::Base::from_raw([ - 0xf1e4_ccd7_3fa0_0a82, - 0xb5e2_ea34_36ee_f957, - 0xf159_4a07_63c6_11ab, - 0x13a7_785a_e134_ea92, - ]), - ], - [ - pallas::Base::from_raw([ - 0xbbf0_4f52_52de_4279, - 0x3889_c578_6344_6d88, - 0x4962_ae3c_0da1_7e31, - 0x39fc_e308_b7d4_3c57, - ]), - pallas::Base::from_raw([ - 0x3b57_e344_89b5_3fad, - 0xbef0_0a08_c6ed_38d2, - 0xc0fd_f016_62f6_0d22, - 0x1aae_1883_3f8e_1d3a, - ]), - pallas::Base::from_raw([ - 0x5551_3e03_3398_513f, - 0x27c1_b3fd_8f85_d8a8, - 0x8b2e_80c0_64fd_83ed, - 0x1a76_1ce8_2400_af01, - ]), - ], - [ - pallas::Base::from_raw([ - 0x5244_ca74_9b73_e481, - 0xdcf6_af28_30a5_0287, - 0x16dd_1a87_ca22_e1cc, - 0x275a_03e4_5add_a7c3, - ]), - pallas::Base::from_raw([ - 0x58a2_53cf_b6a9_5786, - 0x07e5_6145_3fc5_648b, - 0xeb08_e47e_5fea_bcf8, - 0x2e5a_10f0_8b5a_b8bb, - ]), - pallas::Base::from_raw([ - 0xe033_d82c_efe7_8ce3, - 0xc141_a5b6_d594_bec4, - 0xb84e_9c33_3b29_32f1, - 0x1459_cb85_8720_8473, - ]), - ], - [ - pallas::Base::from_raw([ - 0x5cec_7e7b_338f_be1b, - 0x52f9_332f_bffc_fbbd, - 0x7b92_ce81_0e14_a400, - 0x193a_e592_1d78_b5de, - ]), - pallas::Base::from_raw([ - 0x6022_4be6_7248_e82c, - 0x3743_84f4_a072_8205, - 0x8911_1fb2_c466_0281, - 0x3097_898a_5d00_11a4, - ]), - pallas::Base::from_raw([ - 0x5499_80de_8629_30f5, - 0x1979_b2d1_c465_b4d9, - 0x5717_82fd_96ce_54b4, - 0x378d_97bf_8c86_4ae7, - ]), - ], - [ - pallas::Base::from_raw([ - 0x37ea_32a9_71d1_7884, - 0xdbc7_f5cb_4609_3421, - 0x8813_6287_ce37_6b08, - 0x2eb0_4ea7_c01d_97ec, - ]), - pallas::Base::from_raw([ - 0xead3_726f_1af2_e7b0, - 0x861c_bda4_7680_4e6c, - 0x2302_a1c2_2e49_baec, - 0x3642_5347_ea03_f641, - ]), - pallas::Base::from_raw([ - 0xecd6_27e5_9590_d09e, - 0x3f5b_5ca5_a19a_9701, - 0xcc99_6cd8_5c98_a1d8, - 0x26b7_2df4_7408_ad42, - ]), - ], - [ - pallas::Base::from_raw([ - 0x59be_ce31_f0a3_1e95, - 0xde01_212e_e458_8f89, - 0x1f05_636c_610b_89aa, - 0x1301_80e4_4e29_24db, - ]), - pallas::Base::from_raw([ - 0x9ea8_e7bc_7926_3550, - 0xdf77_93cc_89e5_b52f, - 0x7327_5aca_ed5f_579c, - 0x219e_9773_7d39_79ba, - ]), - pallas::Base::from_raw([ - 0x9c12_635d_f251_d153, - 0x3b06_72dd_7d42_cbb4, - 0x3461_363f_81c4_89a2, - 0x3cdb_9359_8a5c_a528, - ]), - ], - [ - pallas::Base::from_raw([ - 0x2861_ce16_f219_d5a9, - 0x4ad0_4470_45a7_c5aa, - 0x2072_4b92_7a0c_a81c, - 0x0e59_e6f3_32d7_ed37, - ]), - pallas::Base::from_raw([ - 0x43b0_a3fc_ff20_36bd, - 0x172c_c07b_9d33_fbf9, - 0x3d73_6946_7222_697a, - 0x1b06_4342_d51a_4275, - ]), - pallas::Base::from_raw([ - 0x3eb3_1022_8a0e_5f6c, - 0x78fa_9fb9_1712_21b7, - 0x2f36_3c55_b288_2e0b, - 0x30b8_2a99_8cbd_8e8a, - ]), - ], - [ - pallas::Base::from_raw([ - 0xe46f_6d42_9874_0107, - 0x8ad7_1ea7_15be_0573, - 0x63df_7a76_e858_a4aa, - 0x23e4_ab37_183a_cba4, - ]), - pallas::Base::from_raw([ - 0xfca9_95e2_b599_14a1, - 0xacfe_1464_0de0_44f2, - 0x5d33_094e_0bed_a75b, - 0x2795_d5c5_fa42_8022, - ]), - pallas::Base::from_raw([ - 0xc26d_909d_ee8b_53c0, - 0xa668_7c3d_f16c_8fe4, - 0xd765_f26d_d03f_4c45, - 0x3001_ca40_1e89_601c, - ]), - ], - [ - pallas::Base::from_raw([ - 0xe7fe_a6bd_f347_1380, - 0xe84b_5beb_ae4e_501d, - 0xf7bf_86e8_9280_827f, - 0x0072_e45c_c676_b08e, - ]), - pallas::Base::from_raw([ - 0xd0c5_4dde_b26b_86c0, - 0xb648_29e2_d40e_41bd, - 0xe2ab_e4c5_18ce_599e, - 0x13de_7054_8487_4bb5, - ]), - pallas::Base::from_raw([ - 0x3891_5b43_2a99_59a5, - 0x82bb_18e5_af1b_05bb, - 0x3159_50f1_211d_efe8, - 0x0408_a9fc_f9d6_1abf, - ]), - ], - [ - pallas::Base::from_raw([ - 0x3407_0cbe_e268_86a0, - 0xae4d_23b0_b41b_e9a8, - 0xbb4e_4a14_00cc_d2c4, - 0x2780_b9e7_5b55_676e, - ]), - pallas::Base::from_raw([ - 0x9405_5920_98b4_056f, - 0xdc4d_8fbe_fe24_405a, - 0xf803_33ec_8563_4ac9, - 0x3a57_0d4d_7c4e_7ac3, - ]), - pallas::Base::from_raw([ - 0x78d2_b247_8995_20b4, - 0xe2cc_1507_bebd_cc62, - 0xf347_c247_fcf0_9294, - 0x0c13_cca7_cb1f_9d2c, - ]), - ], - [ - pallas::Base::from_raw([ - 0x2e8c_88f7_7074_70e0, - 0x0b50_bb2e_b82d_f74d, - 0xd261_4a19_7c6b_794b, - 0x14f5_9baa_03cd_0ca4, - ]), - pallas::Base::from_raw([ - 0xbe52_476e_0a16_f3be, - 0xa51d_54ed_e661_67f5, - 0x6f54_6e17_04c3_9c60, - 0x307d_efee_925d_fb43, - ]), - pallas::Base::from_raw([ - 0x380b_67d8_0473_dce3, - 0x6611_0683_6adf_e5e7, - 0x7a07_e767_4b5a_2621, - 0x1960_cd51_1a91_e060, - ]), - ], - [ - pallas::Base::from_raw([ - 0x15aa_f1f7_7125_89dd, - 0xb8ee_335d_8828_4cbe, - 0xca2a_d0fb_5667_2500, - 0x2301_ef9c_63ea_84c5, - ]), - pallas::Base::from_raw([ - 0x5e68_478c_4d60_27a9, - 0xc861_82d1_b424_6b58, - 0xd10f_4cd5_2be9_7f6b, - 0x029a_5a47_da79_a488, - ]), - pallas::Base::from_raw([ - 0x2cc4_f962_eaae_2260, - 0xf97f_e46b_6a92_5428, - 0x2360_d17d_890e_55cb, - 0x32d7_b16a_7f11_cc96, - ]), - ], - [ - pallas::Base::from_raw([ - 0xc0ca_b915_d536_3d9f, - 0xa5f2_404c_d7b3_5eb0, - 0x18e8_57a9_8d49_8cf7, - 0x2670_3e48_c03b_81ca, - ]), - pallas::Base::from_raw([ - 0xf691_123a_e112_b928, - 0xf443_88bd_6b89_221e, - 0x88ac_8d25_a246_03f1, - 0x0486_82a3_5b32_65bc, - ]), - pallas::Base::from_raw([ - 0x3ab7_defc_b8d8_03e2, - 0x91d6_e171_5164_775e, - 0xd72c_ddc6_cf06_b507, - 0x06b1_3904_41fa_7030, - ]), - ], - [ - pallas::Base::from_raw([ - 0xbcd7_9541_4a6e_2e86, - 0x43b3_60f6_386a_86d7, - 0x1689_426d_ce05_fcd8, - 0x31aa_0eeb_868c_626d, - ]), - pallas::Base::from_raw([ - 0xed77_f5d5_76b9_9cc3, - 0x90ef_d8f4_1b20_78b2, - 0x057a_bad3_764c_104b, - 0x2394_64f7_5bf7_b6af, - ]), - pallas::Base::from_raw([ - 0xb2cb_4873_07c1_cecf, - 0xa5cc_47c5_9654_b2a7, - 0xa45e_19ed_813a_54ab, - 0x0a64_d4c0_4fd4_26bd, - ]), - ], - [ - pallas::Base::from_raw([ - 0x1f73_1532_2f65_8735, - 0x777c_7a92_1a06_2e9d, - 0x576a_4ad2_5986_0fb1, - 0x21fb_bdbb_7367_0734, - ]), - pallas::Base::from_raw([ - 0x6743_2400_3fc5_2146, - 0x5b86_d294_63d3_1564, - 0xd937_1ca2_eb95_acf3, - 0x31b8_6f3c_f017_05d4, - ]), - pallas::Base::from_raw([ - 0x7045_f48a_a4eb_4f6f, - 0x1354_1d65_157e_e1ce, - 0x05ef_1736_d090_56f6, - 0x2bfd_e533_5437_7c91, - ]), - ], - [ - pallas::Base::from_raw([ - 0x5a13_a58d_2001_1e2f, - 0xf4d5_239c_11d0_eafa, - 0xd558_f36e_65f8_eca7, - 0x1233_ca93_6ec2_4671, - ]), - pallas::Base::from_raw([ - 0x6e70_af0a_7a92_4b3a, - 0x8780_58d0_234a_576f, - 0xc437_846d_8e0b_2b30, - 0x27d4_52a4_3ac7_dea2, - ]), - pallas::Base::from_raw([ - 0xa025_76b9_4392_f980, - 0x6a30_641a_1c3d_87b2, - 0xe816_ea8d_a493_e0fa, - 0x2699_dba8_2184_e413, - ]), - ], - [ - pallas::Base::from_raw([ - 0x608c_6f7a_61b5_6e55, - 0xf185_8466_4f8c_ab49, - 0xc398_8bae_e42e_4b10, - 0x36c7_22f0_efcc_8803, - ]), - pallas::Base::from_raw([ - 0x6e49_ac17_0dbb_7fcd, - 0x85c3_8899_a7b5_a833, - 0x08b0_f2ec_89cc_aa37, - 0x02b3_ff48_861e_339b, - ]), - pallas::Base::from_raw([ - 0xa8c5_ae03_ad98_e405, - 0x6fc3_ff4c_49eb_59ad, - 0x6016_2f44_27bc_657b, - 0x0b70_d061_d58d_8a7f, - ]), - ], - [ - pallas::Base::from_raw([ - 0x2e06_cc4a_f33b_0a06, - 0xad3d_e8be_46ed_9693, - 0xf875_3ade_b9d7_cee2, - 0x3fc2_a13f_127f_96a4, - ]), - pallas::Base::from_raw([ - 0xc120_80ac_117e_e15f, - 0x00cb_3d62_1e17_1d80, - 0x1bd6_3434_ac8c_419f, - 0x0c41_a6e4_8dd2_3a51, - ]), - pallas::Base::from_raw([ - 0x9685_213e_9692_f5e1, - 0x72aa_ad7e_4e75_339d, - 0xed44_7653_7169_084e, - 0x2de8_072a_6bd8_6884, - ]), - ], - [ - pallas::Base::from_raw([ - 0x0ad0_1184_567b_027c, - 0xb81c_f735_cc9c_39c0, - 0x9d34_96a3_d9fe_05ec, - 0x0355_7a8f_7b38_a17f, - ]), - pallas::Base::from_raw([ - 0x45bc_b5ac_0082_6abc, - 0x060f_4336_3d81_8e54, - 0xee97_6d34_282f_1a37, - 0x0b5f_5955_2f49_8735, - ]), - pallas::Base::from_raw([ - 0x2f29_09e1_7e22_b0df, - 0xf5d6_46e5_7507_e548, - 0xfedb_b185_70dc_7300, - 0x0e29_23a5_fee7_b878, - ]), - ], - [ - pallas::Base::from_raw([ - 0xf71e_ed73_f15b_3326, - 0xcf1c_b37c_3b03_2af6, - 0xc787_be97_020a_7fdd, - 0x1d78_5005_a7a0_0592, - ]), - pallas::Base::from_raw([ - 0x0acf_bfb2_23f8_f00d, - 0xa590_b88a_3b06_0294, - 0x0ba5_fedc_b8f2_5bd2, - 0x1ad7_72c2_73d9_c6df, - ]), - pallas::Base::from_raw([ - 0xc1ce_13d6_0f2f_5031, - 0x8105_10eb_61f0_672d, - 0xa78f_3275_c278_234b, - 0x027b_d647_85fc_bd2a, - ]), - ], - [ - pallas::Base::from_raw([ - 0x8337_f5e0_7923_a853, - 0xe224_3134_6945_7b8e, - 0xce6f_8ffe_a103_1b6d, - 0x2080_0f44_1b4a_0526, - ]), - pallas::Base::from_raw([ - 0xa33d_7bed_89a4_408a, - 0x36cd_c8ee_d662_ad37, - 0x6eea_2cd4_9f43_12b4, - 0x3d5a_d61d_7b65_f938, - ]), - pallas::Base::from_raw([ - 0x3bbb_ae94_cc19_5284, - 0x1df9_6cc0_3ea4_b26d, - 0x02c5_f91b_e4dd_8e3d, - 0x1333_8bc3_51fc_46dd, - ]), - ], - [ - pallas::Base::from_raw([ - 0xc527_1c29_7852_819e, - 0x646c_49f9_b46c_bf19, - 0xb87d_b1e2_af3e_a923, - 0x25e5_2be5_07c9_2760, - ]), - pallas::Base::from_raw([ - 0x5c38_0ab7_01b5_2ea9, - 0xa34c_83a3_485c_6b2d, - 0x7109_6d8b_1b98_3c98, - 0x1c49_2d64_c157_aaa4, - ]), - pallas::Base::from_raw([ - 0xa20c_0b3d_a0da_4ca3, - 0xd434_87bc_288d_f682, - 0xf4e6_c5e7_a573_f592, - 0x0c5b_8015_7999_2718, - ]), - ], - [ - pallas::Base::from_raw([ - 0x7ea3_3c93_e408_33cf, - 0x584e_9e62_a7f9_554e, - 0x6869_5c0c_d7cb_f43d, - 0x1090_b1b4_d2be_be7a, - ]), - pallas::Base::from_raw([ - 0xe383_e1ec_3baa_8d69, - 0x1b21_8e35_ecf2_328e, - 0x68f5_ce5c_bed1_9cad, - 0x33e3_8018_a801_387a, - ]), - pallas::Base::from_raw([ - 0xb76b_0b3d_787e_e953, - 0x5f4a_02d2_8729_e3ae, - 0xeef8_d83d_0e87_6bac, - 0x1654_af18_772b_2da5, - ]), - ], - [ - pallas::Base::from_raw([ - 0xef7c_e6a0_1326_5477, - 0xbb08_9387_0367_ec6c, - 0x4474_2de8_8c5a_b0d5, - 0x1678_be3c_c9c6_7993, - ]), - pallas::Base::from_raw([ - 0xaf5d_4789_3348_f766, - 0xdaf1_8183_55b1_3b4f, - 0x7ff9_c6be_546e_928a, - 0x3780_bd1e_01f3_4c22, - ]), - pallas::Base::from_raw([ - 0xa123_8032_0d7c_c1de, - 0x5d11_e69a_a6c0_b98c, - 0x0786_018e_7cb7_7267, - 0x1e83_d631_5c9f_125b, - ]), - ], - [ - pallas::Base::from_raw([ - 0x1799_603e_855c_e731, - 0xc486_894d_76e0_c33b, - 0x160b_4155_2f29_31c8, - 0x354a_fd0a_2f9d_0b26, - ]), - pallas::Base::from_raw([ - 0x8b99_7ee0_6be1_bff3, - 0x60b0_0dbe_1fac_ed07, - 0x2d8a_ffa6_2905_c5a5, - 0x00cd_6d29_f166_eadc, - ]), - pallas::Base::from_raw([ - 0x08d0_6419_1708_2f2c, - 0xc60d_0197_3f18_3057, - 0xdbe0_e3d7_cdbc_66ef, - 0x1d62_1935_2768_e3ae, - ]), - ], - [ - pallas::Base::from_raw([ - 0xfa08_dd98_0638_7577, - 0xafe3_ca1d_b8d4_f529, - 0xe48d_2370_d7d1_a142, - 0x1463_36e2_5db5_181d, - ]), - pallas::Base::from_raw([ - 0xa901_d3ce_84de_0ad4, - 0x022e_54b4_9c13_d907, - 0x997a_2116_3e2e_43df, - 0x0005_d8e0_85fd_72ee, - ]), - pallas::Base::from_raw([ - 0x1c36_f313_4196_4484, - 0x6f8e_bc1d_2296_021a, - 0x0dd5_e61c_8a4e_8642, - 0x364e_97c7_a389_3227, - ]), - ], - [ - pallas::Base::from_raw([ - 0xd7a0_0c03_d2e0_baaa, - 0xfa97_ec80_ad30_7a52, - 0x561c_6fff_1534_6878, - 0x0118_9910_671b_c16b, - ]), - pallas::Base::from_raw([ - 0x63fd_8ac5_7a95_ca8c, - 0x4c0f_7e00_1df4_90aa, - 0x5229_dfaa_0123_1a45, - 0x162a_7c80_f4d2_d12e, - ]), - pallas::Base::from_raw([ - 0x32e6_9efb_22f4_0b96, - 0xcaff_31b4_fda3_2124, - 0x2604_e4af_b09f_8603, - 0x2a0d_6c09_5766_66bb, - ]), - ], - [ - pallas::Base::from_raw([ - 0xc0a0_180f_8cbf_c0d2, - 0xf444_d10d_63a7_4e2c, - 0xe16a_4d60_3d5a_808e, - 0x0978_e5c5_1e1e_5649, - ]), - pallas::Base::from_raw([ - 0x03f4_460e_bc35_1b6e, - 0x0508_7d90_3bda_cfd1, - 0xebe1_9bbd_ce25_1011, - 0x1bdc_ee3a_aca9_cd25, - ]), - pallas::Base::from_raw([ - 0xf619_64bf_3ade_7670, - 0x0c94_7321_e007_5e3f, - 0xe494_7914_0b19_44fd, - 0x1862_cccb_70b5_b885, - ]), - ], - [ - pallas::Base::from_raw([ - 0xc326_7da6_e94a_dc50, - 0x39ee_99c1_cc6e_5dda, - 0xbc26_cc88_3a19_87e1, - 0x1f3e_91d8_63c1_6922, - ]), - pallas::Base::from_raw([ - 0x0f85_b4ac_2c36_7406, - 0xfa66_1465_c656_ad99, - 0xef5c_08f8_478f_663a, - 0x1af4_7a48_a601_6a49, - ]), - pallas::Base::from_raw([ - 0x0eab_cd87_e7d0_1b15, - 0x1c36_98b0_a2e3_da10, - 0x009d_5733_8c69_3505, - 0x3c8e_e901_956e_3d3f, - ]), - ], - [ - pallas::Base::from_raw([ - 0x8b94_7721_8967_3476, - 0xe10c_e2b7_069f_4dbd, - 0x68d0_b024_f591_b520, - 0x1660_a8cd_e7fe_c553, - ]), - pallas::Base::from_raw([ - 0x9d8d_0f67_fdaa_79d5, - 0x3963_c2c1_f558_6e2f, - 0x1303_9363_34dd_1132, - 0x0f6d_9919_29d5_e4e7, - ]), - pallas::Base::from_raw([ - 0x7a43_3091_e1ce_2d3a, - 0x4e7f_da77_0712_f343, - 0xcc62_5eaa_ab52_b4dc, - 0x02b9_cea1_921c_d9f6, - ]), - ], - [ - pallas::Base::from_raw([ - 0x3797_b2d8_3760_43b3, - 0xd8ca_f468_976f_0472, - 0x214f_7c67_84ac_b565, - 0x14a3_23b9_9b90_0331, - ]), - pallas::Base::from_raw([ - 0x347f_ef2c_00f0_953a, - 0x718b_7fbc_7788_af78, - 0xec01_ea79_642d_5760, - 0x1904_76b5_80cb_9277, - ]), - pallas::Base::from_raw([ - 0xff4e_7e6f_b268_dfd7, - 0x9660_902b_6008_7651, - 0xa424_63d3_0b44_2b6f, - 0x090a_3a9d_869d_2eef, - ]), - ], - [ - pallas::Base::from_raw([ - 0xf983_387e_a045_6203, - 0xe365_0013_04f9_a11e, - 0x0dbe_8fd2_270a_6795, - 0x3877_a955_8636_7567, - ]), - pallas::Base::from_raw([ - 0x39c0_af0f_e01f_4a06, - 0x6011_8c53_a218_1352, - 0x5df3_9a2c_c63d_dc0a, - 0x2d89_4691_240f_e953, - ]), - pallas::Base::from_raw([ - 0x1aca_9eaf_9bba_9850, - 0x5914_e855_eeb4_4aa1, - 0x7ef7_1780_2016_6189, - 0x21b9_c182_92bd_bc59, - ]), - ], - [ - pallas::Base::from_raw([ - 0x33f5_09a7_4ad9_d39b, - 0x272e_1cc6_c36a_2968, - 0x505a_05f2_a6ae_834c, - 0x2fe7_6be7_cff7_23e2, - ]), - pallas::Base::from_raw([ - 0x0df9_fa97_277f_a8b4, - 0xd15b_ff84_0dda_e8a5, - 0x9299_81d7_cfce_253b, - 0x187a_a448_f391_e3ca, - ]), - pallas::Base::from_raw([ - 0xf0c6_6af5_ffc7_3736, - 0x663c_cf7b_2ffe_4b5e, - 0x007a_b3aa_3617_f422, - 0x0b70_83ad_7517_07bf, - ]), - ], - [ - pallas::Base::from_raw([ - 0x2f9b_20f1_fbd4_9791, - 0x1975_b962_f6cb_8e0b, - 0x3bc4_ca99_02c5_2acb, - 0x030d_dbb4_7049_3f16, - ]), - pallas::Base::from_raw([ - 0x3a1c_62ca_8fbf_2525, - 0x8fb8_ab9d_60ea_17b2, - 0x950b_0ab1_8d35_46df, - 0x3130_fbaf_fb5a_a82a, - ]), - pallas::Base::from_raw([ - 0x43a8_7618_0dc3_82e0, - 0x15ce_2ead_2fcd_051e, - 0x4f74_d74b_ac2e_e457, - 0x337f_5447_07c4_30f0, - ]), - ], - [ - pallas::Base::from_raw([ - 0x26de_98a8_736d_1d11, - 0x7d8e_471a_9fb9_5fef, - 0xac9d_91b0_930d_ac75, - 0x3499_7991_9015_394f, - ]), - pallas::Base::from_raw([ - 0xccfc_b618_31d5_c775, - 0x3bf9_3da6_fff3_1d95, - 0x2305_cd7a_921e_c5f1, - 0x027c_c4ef_e3fb_35dd, - ]), - pallas::Base::from_raw([ - 0xc3fa_2629_635d_27de, - 0x67f1_c6b7_3147_64af, - 0x61b7_1a36_9868_2ad2, - 0x037f_9f23_6595_4c5b, - ]), - ], - [ - pallas::Base::from_raw([ - 0x77c5_b024_8483_71ae, - 0x6041_4abe_362d_01c9, - 0x10f1_cc6d_f8b4_bcd7, - 0x1f69_7cac_4d07_feb7, - ]), - pallas::Base::from_raw([ - 0x786a_dd24_4aa0_ef29, - 0x3145_c478_0631_09d6, - 0x26e6_c851_fbd5_72a6, - 0x267a_750f_e5d7_cfbc, - ]), - pallas::Base::from_raw([ - 0x180e_2b4d_3e75_6f65, - 0xaf28_5fa8_2ce4_fae5, - 0x678c_9996_d9a4_72c8, - 0x0c91_feab_4a43_193a, - ]), - ], - [ - pallas::Base::from_raw([ - 0x79c4_7c57_3ac4_10f7, - 0x7e3b_83af_4a4b_a3ba, - 0x2186_c303_8ea0_5e69, - 0x1745_569a_0a3e_3014, - ]), - pallas::Base::from_raw([ - 0x1e03_8852_2696_191f, - 0xfdff_66c6_f3b5_ffe1, - 0xeca5_1207_78a5_6711, - 0x2986_3d54_6e7e_7c0d, - ]), - pallas::Base::from_raw([ - 0x2f22_5e63_66bf_e390, - 0xa79a_03df_8339_94c6, - 0xbf06_bae4_9ef8_53f6, - 0x1148_d6ab_2bd0_0192, - ]), - ], - [ - pallas::Base::from_raw([ - 0xf4f6_331a_8b26_5d15, - 0xf745_f45d_350d_41d4, - 0xe18b_1499_060d_a366, - 0x02e0_e121_b0f3_dfef, - ]), - pallas::Base::from_raw([ - 0x078a_e6aa_1510_54b7, - 0x6904_0173_6d44_a653, - 0xb89e_f73a_40a2_b274, - 0x0d0a_a46e_76a6_a278, - ]), - pallas::Base::from_raw([ - 0x9a4d_532c_7b6e_0958, - 0x392d_de71_0f1f_06db, - 0xeee5_45f3_fa6d_3d08, - 0x1394_3675_b04a_a986, - ]), - ], - [ - pallas::Base::from_raw([ - 0x961f_c818_dcbb_66b5, - 0xc9f2_b325_7530_dafe, - 0xd97a_11d6_3088_f5d9, - 0x2901_ec61_942d_34aa, - ]), - pallas::Base::from_raw([ - 0xfdf5_44b9_63d1_fdc7, - 0x22ff_a2a2_af9f_a3e3, - 0xf431_d544_34a3_e0cf, - 0x2020_4a21_05d2_2e7e, - ]), - pallas::Base::from_raw([ - 0x1211_b9e2_190d_6852, - 0xa004_abe8_e015_28c4, - 0x5c1e_3e9e_27a5_71c3, - 0x3a8a_6282_9512_1d5c, - ]), - ], -]; -// Secure MDS: 0 -// n: 255 -// t: 3 -// N: 765 -// Result Algorithm 1: -// [True, 0] -// Result Algorithm 2: -// [True, None] -// Result Algorithm 3: -// [True, None] -// Prime number: 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001 -// MDS matrix: -pub(crate) const MDS: [[pallas::Base; 3]; 3] = [ - [ - pallas::Base::from_raw([ - 0x323f_2486_d7e1_1b63, - 0x97d7_a0ab_2385_0b56, - 0xb3d5_9fbd_c8c9_ead4, - 0x0ab5_e5b8_74a6_8de7, - ]), - pallas::Base::from_raw([ - 0x8eca_5596_e996_ab5e, - 0x240d_4a7c_bf73_5736, - 0x293f_0f0d_886c_7954, - 0x3191_6628_e58a_5abb, - ]), - pallas::Base::from_raw([ - 0x19d1_cf25_d8e8_345d, - 0xa0a3_b71a_5fb1_5735, - 0xd803_952b_bb36_4fdf, - 0x07c0_45d5_f5e9_e5a6, - ]), - ], - [ - pallas::Base::from_raw([ - 0xd049_cdc8_d085_167c, - 0x3a0a_4640_48bd_770a, - 0xf8e2_4f66_822c_2d9f, - 0x2331_6263_0ebf_9ed7, - ]), - pallas::Base::from_raw([ - 0x4022_7011_3e04_7a2e, - 0x78f8_365c_85bb_ab07, - 0xb366_6454_8d60_957d, - 0x25ca_e259_9892_a8b0, - ]), - pallas::Base::from_raw([ - 0xf84d_806f_685f_747a, - 0x9aad_3d82_62ef_d83f, - 0x7493_8717_989a_1957, - 0x22f5_b5e1_e608_1c97, - ]), - ], - [ - pallas::Base::from_raw([ - 0xfee7_a994_4f84_dbe4, - 0x2168_0eab_c56b_c15d, - 0xf333_aa91_c383_3464, - 0x2e29_dd59_c64b_1037, - ]), - pallas::Base::from_raw([ - 0xc771_effa_4326_3664, - 0xcbea_f48b_3a06_24c3, - 0x92d1_5e7d_ceef_1665, - 0x1d1a_ab4e_c1cd_6788, - ]), - pallas::Base::from_raw([ - 0x1563_9415_f6e8_5ef1, - 0x7587_2c39_b59a_31f6, - 0x51e0_cbea_d655_16b9, - 0x3bf7_6308_6a18_9364, - ]), - ], -]; - -pub(crate) const MDS_INV: [[pallas::Base; 3]; 3] = [ - [ - pallas::Base::from_raw([ - 0xc6de_463c_d140_4e6b, - 0x4543_705f_35e9_8ab5, - 0xcc59_ffd0_0de8_6443, - 0x2cc0_57f3_fa14_687a, - ]), - pallas::Base::from_raw([ - 0x1718_4041_7cab_7576, - 0xfadb_f8ae_7ae2_4796, - 0x5fd7_2b55_df20_8385, - 0x32e7_c439_f2f9_67e5, - ]), - pallas::Base::from_raw([ - 0x9426_45bd_7d44_64e0, - 0x1403_db6f_5030_2040, - 0xf461_778a_bf6c_91fa, - 0x2eae_5df8_c311_5969, - ]), - ], - [ - pallas::Base::from_raw([ - 0xa1ca_1516_a4a1_a6a0, - 0x13f0_74fd_e9a1_8b29, - 0xdb18_b4ae_fe68_d26d, - 0x07bf_3684_8106_7199, - ]), - pallas::Base::from_raw([ - 0xe824_25bc_1b23_a059, - 0xbb1d_6504_0c85_c1bf, - 0x018a_918b_9dac_5dad, - 0x2aec_6906_c63f_3cf1, - ]), - pallas::Base::from_raw([ - 0xe054_1adf_238e_0781, - 0x76b2_a713_9db7_1b36, - 0x1215_944a_64a2_46b2, - 0x0952_e024_3aec_2af0, - ]), - ], - [ - pallas::Base::from_raw([ - 0x2a41_8d8d_73a7_c908, - 0xaef9_112e_952f_dbb5, - 0x723a_63a0_c09d_ab26, - 0x2fcb_ba6f_9159_a219, - ]), - pallas::Base::from_raw([ - 0x76ef_ab42_d4fb_a90b, - 0xc5e4_960d_7424_cd37, - 0xb4dd_d4b4_d645_2256, - 0x1ec7_3725_74f3_851b, - ]), - pallas::Base::from_raw([ - 0xadc8_933c_6f3c_72ee, - 0x87a7_435d_30f8_be81, - 0x3c26_fa4b_7d25_b1e4, - 0x0d0c_2efd_6472_f12a, - ]), - ], -]; diff --git a/halo2_gadgets/src/poseidon/primitives/fq.rs b/halo2_gadgets/src/poseidon/primitives/fq.rs deleted file mode 100644 index 3629318adc..0000000000 --- a/halo2_gadgets/src/poseidon/primitives/fq.rs +++ /dev/null @@ -1,1431 +0,0 @@ -//! Constants for using Poseidon with the Vesta field. -//! -//! The constants 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 255 3 8 56 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001 -//! ``` -use halo2curves::pasta::vesta; - -// Number of round constants: 192 -// Round constants for GF(p): -pub(crate) const ROUND_CONSTANTS: [[vesta::Base; 3]; 64] = [ - [ - vesta::Base::from_raw([ - 0x5753_8c25_9642_6303, - 0x4e71_162f_3100_3b70, - 0x353f_628f_76d1_10f3, - 0x360d_7470_611e_473d, - ]), - vesta::Base::from_raw([ - 0xbdb7_4213_bf63_188b, - 0x4908_ac2f_12eb_e06f, - 0x5dc3_c6c5_febf_aa31, - 0x2bab_94d7_ae22_2d13, - ]), - vesta::Base::from_raw([ - 0x0939_d927_53cc_5dc8, - 0xef77_e7d7_3676_6c5d, - 0x2bf0_3e1a_29aa_871f, - 0x150c_93fe_f652_fb1c, - ]), - ], - [ - vesta::Base::from_raw([ - 0x1425_9dce_5377_82b2, - 0x03cc_0a60_141e_894e, - 0x955d_55db_56dc_57c1, - 0x3270_661e_6892_8b3a, - ]), - vesta::Base::from_raw([ - 0xce9f_b9ff_c345_afb3, - 0xb407_c370_f2b5_a1cc, - 0xa0b7_afe4_e205_7299, - 0x073f_116f_0412_2e25, - ]), - vesta::Base::from_raw([ - 0x8eba_d76f_c715_54d8, - 0x55c9_cd20_61ae_93ca, - 0x7aff_d09c_1f53_f5fd, - 0x2a32_ec5c_4ee5_b183, - ]), - ], - [ - vesta::Base::from_raw([ - 0x2d8c_cbe2_92ef_eead, - 0x634d_24fc_6e25_59f2, - 0x651e_2cfc_7406_28ca, - 0x2703_26ee_039d_f19e, - ]), - vesta::Base::from_raw([ - 0xa068_fc37_c182_e274, - 0x8af8_95bc_e012_f182, - 0xdc10_0fe7_fcfa_5491, - 0x27c6_642a_c633_bc66, - ]), - vesta::Base::from_raw([ - 0x9ca1_8682_e26d_7ff9, - 0x710e_1fb6_ab97_6a45, - 0xd27f_5739_6989_129d, - 0x1bdf_d8b0_1401_c70a, - ]), - ], - [ - vesta::Base::from_raw([ - 0xc832_d824_261a_35ea, - 0xf4f6_fb3f_9054_d373, - 0x14b9_d6a9_c84d_d678, - 0x162a_14c6_2f9a_89b8, - ]), - vesta::Base::from_raw([ - 0xf798_2466_7b5b_6bec, - 0xac0a_1fc7_1e2c_f0c0, - 0x2af6_f79e_3127_feea, - 0x2d19_3e0f_76de_586b, - ]), - vesta::Base::from_raw([ - 0x5d0b_f58d_c8a4_aa94, - 0x4fef_f829_8499_0ff8, - 0x8169_6ef1_104e_674f, - 0x044c_a3cc_4a85_d73b, - ]), - ], - [ - vesta::Base::from_raw([ - 0x6198_785f_0cd6_b9af, - 0xb8d9_e2d4_f314_f46f, - 0x1d04_5341_6d3e_235c, - 0x1cba_f2b3_71da_c6a8, - ]), - vesta::Base::from_raw([ - 0x343e_0761_0f3f_ede5, - 0x293c_4ab0_38fd_bbdc, - 0x0e6c_49d0_61b6_b5f4, - 0x1d5b_2777_692c_205b, - ]), - vesta::Base::from_raw([ - 0xf60e_971b_8d73_b04f, - 0x06a9_adb0_c1e6_f962, - 0xaa30_535b_dd74_9a7e, - 0x2e9b_dbba_3dd3_4bff, - ]), - ], - [ - vesta::Base::from_raw([ - 0x035a_1366_1f22_418b, - 0xde40_fbe2_6d04_7b05, - 0x8bd5_bae3_6969_299f, - 0x2de1_1886_b180_11ca, - ]), - vesta::Base::from_raw([ - 0xbc99_8884_ba96_a721, - 0x2ab9_395c_449b_e947, - 0x0d5b_4a3f_1841_dcd8, - 0x2e07_de17_80b8_a70d, - ]), - vesta::Base::from_raw([ - 0x825e_4c2b_b749_25ca, - 0x2504_40a9_9d6b_8af3, - 0xbbdb_63db_d52d_ad16, - 0x0f69_f185_4d20_ca0c, - ]), - ], - [ - vesta::Base::from_raw([ - 0x816c_0594_22dc_705e, - 0x6ce5_1135_07f9_6de9, - 0x0d13_5dc6_39fb_09a4, - 0x2eb1_b254_17fe_1767, - ]), - vesta::Base::from_raw([ - 0xb8b1_bdf4_953b_d82c, - 0xff36_c661_d26c_c42d, - 0x8c24_cb44_c3fa_b48a, - 0x115c_d0a0_643c_fb98, - ]), - vesta::Base::from_raw([ - 0xde80_1612_311d_04cd, - 0xbb57_ddf1_4e0f_958a, - 0x066d_7378_b999_868b, - 0x26ca_293f_7b2c_462d, - ]), - ], - [ - vesta::Base::from_raw([ - 0xf520_9d14_b248_20ca, - 0x0f16_0bf9_f71e_967f, - 0x2a83_0aa1_6241_2cd9, - 0x17bf_1b93_c4c7_e01a, - ]), - vesta::Base::from_raw([ - 0x05c8_6f2e_7dc2_93c5, - 0xe03c_0354_bd8c_fd38, - 0xa24f_8456_369c_85df, - 0x35b4_1a7a_c4f3_c571, - ]), - vesta::Base::from_raw([ - 0x72ac_156a_f435_d09e, - 0x64e1_4d3b_eb2d_ddde, - 0x4359_2799_4849_bea9, - 0x3b14_8008_0523_c439, - ]), - ], - [ - vesta::Base::from_raw([ - 0x2716_18d8_74b1_4c6d, - 0x08e2_8644_2a2d_3eb2, - 0x4950_856d_c907_d575, - 0x2cc6_8100_31dc_1b0d, - ]), - vesta::Base::from_raw([ - 0x91f3_18c0_9f0c_b566, - 0x9e51_7aa9_3b78_341d, - 0x0596_18e2_afd2_ef99, - 0x25bd_bbed_a1bd_e8c1, - ]), - vesta::Base::from_raw([ - 0xc631_3487_073f_7f7b, - 0x2a5e_d0a2_7b61_926c, - 0xb95f_33c2_5dde_8ac0, - 0x392a_4a87_58e0_6ee8, - ]), - ], - [ - vesta::Base::from_raw([ - 0xe7bb_cef0_2eb5_866c, - 0x5e6a_6fd1_5db8_9365, - 0x9aa6_111f_4de0_0948, - 0x272a_5587_8a08_442b, - ]), - vesta::Base::from_raw([ - 0x9b92_5b3c_5b21_e0e2, - 0xa6eb_ba01_1694_dd12, - 0xefa1_3c4e_60e2_6239, - 0x2d5b_308b_0cf0_2cdf, - ]), - vesta::Base::from_raw([ - 0xef38_c57c_3116_73ac, - 0x44df_f42f_18b4_6c56, - 0xdd5d_293d_72e2_e5f2, - 0x1654_9fc6_af2f_3b72, - ]), - ], - [ - vesta::Base::from_raw([ - 0x9b71_26d9_b468_60df, - 0x7639_8265_3442_0311, - 0xfa69_c3a2_ad52_f76d, - 0x1b10_bb7a_82af_ce39, - ]), - vesta::Base::from_raw([ - 0x90d2_7f6a_00b7_dfc8, - 0xd1b3_6968_ba04_05c0, - 0xc79c_2df7_dc98_a3be, - 0x0f1e_7505_ebd9_1d2f, - ]), - vesta::Base::from_raw([ - 0xff45_7756_b819_bb20, - 0x797f_d6e3_f18e_b1ca, - 0x537a_7497_a3b4_3f46, - 0x2f31_3faf_0d3f_6187, - ]), - ], - [ - vesta::Base::from_raw([ - 0xf0bc_3e73_2ecb_26f6, - 0x5cad_11eb_f0f7_ceb8, - 0xfa3c_a61c_0ed1_5bc5, - 0x3a5c_bb6d_e450_b481, - ]), - vesta::Base::from_raw([ - 0x8655_27cb_ca91_5982, - 0x51ba_a6e2_0f89_2b62, - 0xd920_86e2_53b4_39d6, - 0x3dab_54bc_9bef_688d, - ]), - vesta::Base::from_raw([ - 0x3680_45ac_f2b7_1ae3, - 0x4c24_b33b_410f_efd4, - 0xe280_d316_7012_3f74, - 0x06db_fb42_b979_884d, - ]), - ], - [ - vesta::Base::from_raw([ - 0xa7fc_32d2_2f18_b9d3, - 0xb8d2_de72_e3d2_c9ec, - 0xc6f0_39ea_1973_a63e, - 0x068d_6b46_08aa_e810, - ]), - vesta::Base::from_raw([ - 0x2b5d_fcc5_5725_55df, - 0xb868_a7d7_e1f1_f69a, - 0x0ee2_58c9_b8fd_fccd, - 0x366e_bfaf_a3ad_381c, - ]), - vesta::Base::from_raw([ - 0xe6bc_229e_95bc_76b1, - 0x7ef6_6d89_d044_d022, - 0x04db_3024_f41d_3f56, - 0x3967_8f65_512f_1ee4, - ]), - ], - [ - vesta::Base::from_raw([ - 0xe534_c88f_e53d_85fe, - 0xcf82_c25f_99dc_01a4, - 0xd58b_7750_a3bc_2fe1, - 0x2166_8f01_6a80_63c0, - ]), - vesta::Base::from_raw([ - 0x4bef_429b_c533_1608, - 0xe34d_ea56_439f_e195, - 0x1bc7_4936_3e98_a768, - 0x39d0_0994_a8a5_046a, - ]), - vesta::Base::from_raw([ - 0x770c_956f_60d8_81b3, - 0xb163_d416_05d3_9f99, - 0x6b20_3bbe_12fb_3425, - 0x1f9d_bdc3_f843_1263, - ]), - ], - [ - vesta::Base::from_raw([ - 0x9794_a9f7_c336_eab2, - 0xbe0b_c829_fe5e_66c6, - 0xe5f1_7b9e_0ee0_cab6, - 0x0277_45a9_cddf_ad95, - ]), - vesta::Base::from_raw([ - 0x5202_5657_abd8_aee0, - 0x2fa4_3fe2_0a45_c78d, - 0x788d_695c_61e9_3212, - 0x1cec_0803_c504_b635, - ]), - vesta::Base::from_raw([ - 0xd387_2a95_59a0_3a73, - 0xed50_82c8_dbf3_1365, - 0x7207_7448_ef87_cc6e, - 0x1235_23d7_5e9f_abc1, - ]), - ], - [ - vesta::Base::from_raw([ - 0x0017_79e3_a1d3_57f4, - 0x27fe_ba35_975e_e7e5, - 0xf419_b848_e5d6_94bf, - 0x1723_d145_2c9c_f02d, - ]), - vesta::Base::from_raw([ - 0x9dab_1ee4_dcf9_6622, - 0x21c3_f776_f572_836d, - 0xfcc0_573d_7e61_3694, - 0x1739_d180_a160_10bd, - ]), - vesta::Base::from_raw([ - 0x7029_0452_042d_048d, - 0xfafa_96fb_eb0a_b893, - 0xacce_3239_1794_b627, - 0x2d4e_6354_da9c_c554, - ]), - ], - [ - vesta::Base::from_raw([ - 0x670b_cf6f_8b48_5dcd, - 0x8f3b_d43f_9926_0621, - 0x4a86_9553_c9d0_07f8, - 0x153e_e614_2e53_5e33, - ]), - vesta::Base::from_raw([ - 0xd258_d2e2_b778_2172, - 0x968a_d442_4af8_3700, - 0x635e_f7e7_a430_b486, - 0x0c45_bfd3_a69a_aa65, - ]), - vesta::Base::from_raw([ - 0x0e56_33d2_51f7_3307, - 0x6897_ac0a_8ffa_5ff1, - 0xf2d5_6aec_8314_4600, - 0x0adf_d53b_256a_6957, - ]), - ], - [ - vesta::Base::from_raw([ - 0xac9d_36a8_b751_6d63, - 0x3f87_b28f_1c1b_e4bd, - 0x8cd1_726b_7cba_b8ee, - 0x315d_2ac8_ebdb_ac3c, - ]), - vesta::Base::from_raw([ - 0x299c_e44e_a423_d8e1, - 0xc9bb_60d1_f695_9879, - 0xcfae_c23d_2b16_883f, - 0x1b84_7271_2d02_eef4, - ]), - vesta::Base::from_raw([ - 0xc4a5_4041_98ad_f70c, - 0x367d_2c54_e369_28c9, - 0xbd0b_70fa_2255_eb6f, - 0x3c1c_d07e_fda6_ff24, - ]), - ], - [ - vesta::Base::from_raw([ - 0xbbe5_23ae_f9ab_107a, - 0x4a16_073f_738f_7e0c, - 0x687f_4e51_b2e1_dcd3, - 0x1360_52d2_6bb3_d373, - ]), - vesta::Base::from_raw([ - 0x676c_36c2_4ef9_67dd, - 0x7b3c_fbb8_7303_2681, - 0xc1bd_d859_a123_2a1d, - 0x16c9_6bee_f6a0_a848, - ]), - vesta::Base::from_raw([ - 0x067e_ec7f_2d63_40c4, - 0x0123_87ba_b4f1_662d, - 0x2ab7_fed8_f499_a9fb, - 0x284b_38c5_7ff6_5c26, - ]), - ], - [ - vesta::Base::from_raw([ - 0xaf1d_ff20_4c92_2f86, - 0xfc06_772c_1c04_11a6, - 0x39e2_4219_8897_d17c, - 0x0c59_93d1_75e8_1f66, - ]), - vesta::Base::from_raw([ - 0xbbf5_3f67_b1f8_7b15, - 0xf248_87ad_48e1_7759, - 0xfcda_655d_1ba9_c8f9, - 0x03bf_7a3f_7bd0_43da, - ]), - vesta::Base::from_raw([ - 0x9b5c_d09e_36d8_be62, - 0x4c8f_9cbe_69f0_e827, - 0xb0cf_9995_67f0_0e73, - 0x3188_fe4e_e9f9_fafb, - ]), - ], - [ - vesta::Base::from_raw([ - 0xafea_99a2_ec6c_595a, - 0x3af5_bf77_c1c4_2652, - 0x5a39_768c_480d_61e1, - 0x171f_528c_cf65_8437, - ]), - vesta::Base::from_raw([ - 0x5a05_63b9_b8e9_f1d5, - 0x812c_3286_ee70_0067, - 0x196e_4185_9b35_ef88, - 0x12f4_175c_4ab4_5afc, - ]), - vesta::Base::from_raw([ - 0x0e74_d4d3_6911_8b79, - 0x7e23_e1aa_be96_cfab, - 0x8f8f_dcf8_00a9_ac69, - 0x3a50_9e15_5cb7_ebfd, - ]), - ], - [ - vesta::Base::from_raw([ - 0x9871_2c65_678c_fd30, - 0x984b_c8f2_e4c1_b69e, - 0x1a89_920e_2504_c3b3, - 0x10f2_a685_df4a_27c8, - ]), - vesta::Base::from_raw([ - 0xe8a1_6728_cc9d_4918, - 0x5457_3c93_33c5_6321, - 0x1d8d_93d5_4ab9_1a0e, - 0x09e5_f497_90c8_a0e2, - ]), - vesta::Base::from_raw([ - 0x609a_7403_47cf_5fea, - 0x42d1_7ed6_ee0f_ab7e, - 0x2bf3_5705_d9f8_4a34, - 0x352d_69be_d80e_e3e5, - ]), - ], - [ - vesta::Base::from_raw([ - 0x3a75_8af6_fa84_e0e8, - 0xc634_debd_281b_76a6, - 0x4915_62fa_f2b1_90d3, - 0x058e_e73b_a9f3_f293, - ]), - vesta::Base::from_raw([ - 0x621a_1325_10a4_3904, - 0x092c_b921_19bc_76be, - 0xcd0f_1fc5_5b1a_3250, - 0x232f_99cc_911e_ddd9, - ]), - vesta::Base::from_raw([ - 0xc3b9_7c1e_301b_c213, - 0xf9ef_d52c_a6bc_2961, - 0x86c2_2c6c_5d48_69f0, - 0x201b_eed7_b8f3_ab81, - ]), - ], - [ - vesta::Base::from_raw([ - 0xbf6b_3431_ba94_e9bc, - 0x2938_8842_744a_1210, - 0xa1c9_291d_5860_2f51, - 0x1376_dce6_5800_30c6, - ]), - vesta::Base::from_raw([ - 0x6454_843c_5486_d7b3, - 0x072b_a8b0_2d92_e722, - 0x2b33_56c3_8238_f761, - 0x1793_199e_6fd6_ba34, - ]), - vesta::Base::from_raw([ - 0x06a3_f1d3_b433_311b, - 0x3c66_160d_c62a_acac, - 0x9fee_9c20_c87a_67df, - 0x22de_7a74_88dc_c735, - ]), - ], - [ - vesta::Base::from_raw([ - 0x30d6_e3fd_516b_47a8, - 0xdbe0_b77f_ae77_e1d0, - 0xdf8f_f37f_e2d8_edf8, - 0x3514_d5e9_066b_b160, - ]), - vesta::Base::from_raw([ - 0x1937_7427_137a_81c7, - 0xff45_3d6f_900f_144a, - 0xf919_a00d_abbf_5fa5, - 0x30cd_3006_931a_d636, - ]), - vesta::Base::from_raw([ - 0x5b6a_7422_0692_b506, - 0x8f9e_4b2c_ae2e_bb51, - 0x41f8_1a5c_f613_c8df, - 0x253d_1a5c_5293_4127, - ]), - ], - [ - vesta::Base::from_raw([ - 0x73f6_66cb_86a4_8e8e, - 0x851b_3a59_c990_fafc, - 0xa35e_9613_e7f5_fe92, - 0x035b_461c_02d7_9d19, - ]), - vesta::Base::from_raw([ - 0x7cfb_f86a_3aa0_4780, - 0x92b1_283c_2d5f_ccde, - 0x5bc0_0eed_d56b_93e0, - 0x23a9_9280_79d1_75bd, - ]), - vesta::Base::from_raw([ - 0xf1e4_ccd7_3fa0_0a82, - 0xb5e2_ea34_36ee_f957, - 0xf159_4a07_63c6_11ab, - 0x13a7_785a_e134_ea92, - ]), - ], - [ - vesta::Base::from_raw([ - 0xbbf0_4f52_52de_4279, - 0x3889_c578_6344_6d88, - 0x4962_ae3c_0da1_7e31, - 0x39fc_e308_b7d4_3c57, - ]), - vesta::Base::from_raw([ - 0x3b57_e344_89b5_3fad, - 0xbef0_0a08_c6ed_38d2, - 0xc0fd_f016_62f6_0d22, - 0x1aae_1883_3f8e_1d3a, - ]), - vesta::Base::from_raw([ - 0x5551_3e03_3398_513f, - 0x27c1_b3fd_8f85_d8a8, - 0x8b2e_80c0_64fd_83ed, - 0x1a76_1ce8_2400_af01, - ]), - ], - [ - vesta::Base::from_raw([ - 0x5244_ca74_9b73_e481, - 0xdcf6_af28_30a5_0287, - 0x16dd_1a87_ca22_e1cc, - 0x275a_03e4_5add_a7c3, - ]), - vesta::Base::from_raw([ - 0x58a2_53cf_b6a9_5786, - 0x07e5_6145_3fc5_648b, - 0xeb08_e47e_5fea_bcf8, - 0x2e5a_10f0_8b5a_b8bb, - ]), - vesta::Base::from_raw([ - 0xe033_d82c_efe7_8ce3, - 0xc141_a5b6_d594_bec4, - 0xb84e_9c33_3b29_32f1, - 0x1459_cb85_8720_8473, - ]), - ], - [ - vesta::Base::from_raw([ - 0x5cec_7e7b_338f_be1b, - 0x52f9_332f_bffc_fbbd, - 0x7b92_ce81_0e14_a400, - 0x193a_e592_1d78_b5de, - ]), - vesta::Base::from_raw([ - 0x6022_4be6_7248_e82c, - 0x3743_84f4_a072_8205, - 0x8911_1fb2_c466_0281, - 0x3097_898a_5d00_11a4, - ]), - vesta::Base::from_raw([ - 0x5499_80de_8629_30f5, - 0x1979_b2d1_c465_b4d9, - 0x5717_82fd_96ce_54b4, - 0x378d_97bf_8c86_4ae7, - ]), - ], - [ - vesta::Base::from_raw([ - 0x37ea_32a9_71d1_7884, - 0xdbc7_f5cb_4609_3421, - 0x8813_6287_ce37_6b08, - 0x2eb0_4ea7_c01d_97ec, - ]), - vesta::Base::from_raw([ - 0xead3_726f_1af2_e7b0, - 0x861c_bda4_7680_4e6c, - 0x2302_a1c2_2e49_baec, - 0x3642_5347_ea03_f641, - ]), - vesta::Base::from_raw([ - 0xecd6_27e5_9590_d09e, - 0x3f5b_5ca5_a19a_9701, - 0xcc99_6cd8_5c98_a1d8, - 0x26b7_2df4_7408_ad42, - ]), - ], - [ - vesta::Base::from_raw([ - 0x59be_ce31_f0a3_1e95, - 0xde01_212e_e458_8f89, - 0x1f05_636c_610b_89aa, - 0x1301_80e4_4e29_24db, - ]), - vesta::Base::from_raw([ - 0x9ea8_e7bc_7926_3550, - 0xdf77_93cc_89e5_b52f, - 0x7327_5aca_ed5f_579c, - 0x219e_9773_7d39_79ba, - ]), - vesta::Base::from_raw([ - 0x9c12_635d_f251_d153, - 0x3b06_72dd_7d42_cbb4, - 0x3461_363f_81c4_89a2, - 0x3cdb_9359_8a5c_a528, - ]), - ], - [ - vesta::Base::from_raw([ - 0x2861_ce16_f219_d5a9, - 0x4ad0_4470_45a7_c5aa, - 0x2072_4b92_7a0c_a81c, - 0x0e59_e6f3_32d7_ed37, - ]), - vesta::Base::from_raw([ - 0x43b0_a3fc_ff20_36bd, - 0x172c_c07b_9d33_fbf9, - 0x3d73_6946_7222_697a, - 0x1b06_4342_d51a_4275, - ]), - vesta::Base::from_raw([ - 0x3eb3_1022_8a0e_5f6c, - 0x78fa_9fb9_1712_21b7, - 0x2f36_3c55_b288_2e0b, - 0x30b8_2a99_8cbd_8e8a, - ]), - ], - [ - vesta::Base::from_raw([ - 0xe46f_6d42_9874_0107, - 0x8ad7_1ea7_15be_0573, - 0x63df_7a76_e858_a4aa, - 0x23e4_ab37_183a_cba4, - ]), - vesta::Base::from_raw([ - 0xfca9_95e2_b599_14a1, - 0xacfe_1464_0de0_44f2, - 0x5d33_094e_0bed_a75b, - 0x2795_d5c5_fa42_8022, - ]), - vesta::Base::from_raw([ - 0xc26d_909d_ee8b_53c0, - 0xa668_7c3d_f16c_8fe4, - 0xd765_f26d_d03f_4c45, - 0x3001_ca40_1e89_601c, - ]), - ], - [ - vesta::Base::from_raw([ - 0xe7fe_a6bd_f347_1380, - 0xe84b_5beb_ae4e_501d, - 0xf7bf_86e8_9280_827f, - 0x0072_e45c_c676_b08e, - ]), - vesta::Base::from_raw([ - 0xd0c5_4dde_b26b_86c0, - 0xb648_29e2_d40e_41bd, - 0xe2ab_e4c5_18ce_599e, - 0x13de_7054_8487_4bb5, - ]), - vesta::Base::from_raw([ - 0x3891_5b43_2a99_59a5, - 0x82bb_18e5_af1b_05bb, - 0x3159_50f1_211d_efe8, - 0x0408_a9fc_f9d6_1abf, - ]), - ], - [ - vesta::Base::from_raw([ - 0x3407_0cbe_e268_86a0, - 0xae4d_23b0_b41b_e9a8, - 0xbb4e_4a14_00cc_d2c4, - 0x2780_b9e7_5b55_676e, - ]), - vesta::Base::from_raw([ - 0x9405_5920_98b4_056f, - 0xdc4d_8fbe_fe24_405a, - 0xf803_33ec_8563_4ac9, - 0x3a57_0d4d_7c4e_7ac3, - ]), - vesta::Base::from_raw([ - 0x78d2_b247_8995_20b4, - 0xe2cc_1507_bebd_cc62, - 0xf347_c247_fcf0_9294, - 0x0c13_cca7_cb1f_9d2c, - ]), - ], - [ - vesta::Base::from_raw([ - 0x2e8c_88f7_7074_70e0, - 0x0b50_bb2e_b82d_f74d, - 0xd261_4a19_7c6b_794b, - 0x14f5_9baa_03cd_0ca4, - ]), - vesta::Base::from_raw([ - 0xbe52_476e_0a16_f3be, - 0xa51d_54ed_e661_67f5, - 0x6f54_6e17_04c3_9c60, - 0x307d_efee_925d_fb43, - ]), - vesta::Base::from_raw([ - 0x380b_67d8_0473_dce3, - 0x6611_0683_6adf_e5e7, - 0x7a07_e767_4b5a_2621, - 0x1960_cd51_1a91_e060, - ]), - ], - [ - vesta::Base::from_raw([ - 0x15aa_f1f7_7125_89dd, - 0xb8ee_335d_8828_4cbe, - 0xca2a_d0fb_5667_2500, - 0x2301_ef9c_63ea_84c5, - ]), - vesta::Base::from_raw([ - 0x5e68_478c_4d60_27a9, - 0xc861_82d1_b424_6b58, - 0xd10f_4cd5_2be9_7f6b, - 0x029a_5a47_da79_a488, - ]), - vesta::Base::from_raw([ - 0x2cc4_f962_eaae_2260, - 0xf97f_e46b_6a92_5428, - 0x2360_d17d_890e_55cb, - 0x32d7_b16a_7f11_cc96, - ]), - ], - [ - vesta::Base::from_raw([ - 0xc0ca_b915_d536_3d9f, - 0xa5f2_404c_d7b3_5eb0, - 0x18e8_57a9_8d49_8cf7, - 0x2670_3e48_c03b_81ca, - ]), - vesta::Base::from_raw([ - 0xf691_123a_e112_b928, - 0xf443_88bd_6b89_221e, - 0x88ac_8d25_a246_03f1, - 0x0486_82a3_5b32_65bc, - ]), - vesta::Base::from_raw([ - 0x3ab7_defc_b8d8_03e2, - 0x91d6_e171_5164_775e, - 0xd72c_ddc6_cf06_b507, - 0x06b1_3904_41fa_7030, - ]), - ], - [ - vesta::Base::from_raw([ - 0xbcd7_9541_4a6e_2e86, - 0x43b3_60f6_386a_86d7, - 0x1689_426d_ce05_fcd8, - 0x31aa_0eeb_868c_626d, - ]), - vesta::Base::from_raw([ - 0xed77_f5d5_76b9_9cc3, - 0x90ef_d8f4_1b20_78b2, - 0x057a_bad3_764c_104b, - 0x2394_64f7_5bf7_b6af, - ]), - vesta::Base::from_raw([ - 0xb2cb_4873_07c1_cecf, - 0xa5cc_47c5_9654_b2a7, - 0xa45e_19ed_813a_54ab, - 0x0a64_d4c0_4fd4_26bd, - ]), - ], - [ - vesta::Base::from_raw([ - 0x1f73_1532_2f65_8735, - 0x777c_7a92_1a06_2e9d, - 0x576a_4ad2_5986_0fb1, - 0x21fb_bdbb_7367_0734, - ]), - vesta::Base::from_raw([ - 0x6743_2400_3fc5_2146, - 0x5b86_d294_63d3_1564, - 0xd937_1ca2_eb95_acf3, - 0x31b8_6f3c_f017_05d4, - ]), - vesta::Base::from_raw([ - 0x7045_f48a_a4eb_4f6f, - 0x1354_1d65_157e_e1ce, - 0x05ef_1736_d090_56f6, - 0x2bfd_e533_5437_7c91, - ]), - ], - [ - vesta::Base::from_raw([ - 0x5a13_a58d_2001_1e2f, - 0xf4d5_239c_11d0_eafa, - 0xd558_f36e_65f8_eca7, - 0x1233_ca93_6ec2_4671, - ]), - vesta::Base::from_raw([ - 0x6e70_af0a_7a92_4b3a, - 0x8780_58d0_234a_576f, - 0xc437_846d_8e0b_2b30, - 0x27d4_52a4_3ac7_dea2, - ]), - vesta::Base::from_raw([ - 0xa025_76b9_4392_f980, - 0x6a30_641a_1c3d_87b2, - 0xe816_ea8d_a493_e0fa, - 0x2699_dba8_2184_e413, - ]), - ], - [ - vesta::Base::from_raw([ - 0x608c_6f7a_61b5_6e55, - 0xf185_8466_4f8c_ab49, - 0xc398_8bae_e42e_4b10, - 0x36c7_22f0_efcc_8803, - ]), - vesta::Base::from_raw([ - 0x6e49_ac17_0dbb_7fcd, - 0x85c3_8899_a7b5_a833, - 0x08b0_f2ec_89cc_aa37, - 0x02b3_ff48_861e_339b, - ]), - vesta::Base::from_raw([ - 0xa8c5_ae03_ad98_e405, - 0x6fc3_ff4c_49eb_59ad, - 0x6016_2f44_27bc_657b, - 0x0b70_d061_d58d_8a7f, - ]), - ], - [ - vesta::Base::from_raw([ - 0x2e06_cc4a_f33b_0a06, - 0xad3d_e8be_46ed_9693, - 0xf875_3ade_b9d7_cee2, - 0x3fc2_a13f_127f_96a4, - ]), - vesta::Base::from_raw([ - 0xc120_80ac_117e_e15f, - 0x00cb_3d62_1e17_1d80, - 0x1bd6_3434_ac8c_419f, - 0x0c41_a6e4_8dd2_3a51, - ]), - vesta::Base::from_raw([ - 0x9685_213e_9692_f5e1, - 0x72aa_ad7e_4e75_339d, - 0xed44_7653_7169_084e, - 0x2de8_072a_6bd8_6884, - ]), - ], - [ - vesta::Base::from_raw([ - 0x0ad0_1184_567b_027c, - 0xb81c_f735_cc9c_39c0, - 0x9d34_96a3_d9fe_05ec, - 0x0355_7a8f_7b38_a17f, - ]), - vesta::Base::from_raw([ - 0x45bc_b5ac_0082_6abc, - 0x060f_4336_3d81_8e54, - 0xee97_6d34_282f_1a37, - 0x0b5f_5955_2f49_8735, - ]), - vesta::Base::from_raw([ - 0x2f29_09e1_7e22_b0df, - 0xf5d6_46e5_7507_e548, - 0xfedb_b185_70dc_7300, - 0x0e29_23a5_fee7_b878, - ]), - ], - [ - vesta::Base::from_raw([ - 0xf71e_ed73_f15b_3326, - 0xcf1c_b37c_3b03_2af6, - 0xc787_be97_020a_7fdd, - 0x1d78_5005_a7a0_0592, - ]), - vesta::Base::from_raw([ - 0x0acf_bfb2_23f8_f00d, - 0xa590_b88a_3b06_0294, - 0x0ba5_fedc_b8f2_5bd2, - 0x1ad7_72c2_73d9_c6df, - ]), - vesta::Base::from_raw([ - 0xc1ce_13d6_0f2f_5031, - 0x8105_10eb_61f0_672d, - 0xa78f_3275_c278_234b, - 0x027b_d647_85fc_bd2a, - ]), - ], - [ - vesta::Base::from_raw([ - 0x8337_f5e0_7923_a853, - 0xe224_3134_6945_7b8e, - 0xce6f_8ffe_a103_1b6d, - 0x2080_0f44_1b4a_0526, - ]), - vesta::Base::from_raw([ - 0xa33d_7bed_89a4_408a, - 0x36cd_c8ee_d662_ad37, - 0x6eea_2cd4_9f43_12b4, - 0x3d5a_d61d_7b65_f938, - ]), - vesta::Base::from_raw([ - 0x3bbb_ae94_cc19_5284, - 0x1df9_6cc0_3ea4_b26d, - 0x02c5_f91b_e4dd_8e3d, - 0x1333_8bc3_51fc_46dd, - ]), - ], - [ - vesta::Base::from_raw([ - 0xc527_1c29_7852_819e, - 0x646c_49f9_b46c_bf19, - 0xb87d_b1e2_af3e_a923, - 0x25e5_2be5_07c9_2760, - ]), - vesta::Base::from_raw([ - 0x5c38_0ab7_01b5_2ea9, - 0xa34c_83a3_485c_6b2d, - 0x7109_6d8b_1b98_3c98, - 0x1c49_2d64_c157_aaa4, - ]), - vesta::Base::from_raw([ - 0xa20c_0b3d_a0da_4ca3, - 0xd434_87bc_288d_f682, - 0xf4e6_c5e7_a573_f592, - 0x0c5b_8015_7999_2718, - ]), - ], - [ - vesta::Base::from_raw([ - 0x7ea3_3c93_e408_33cf, - 0x584e_9e62_a7f9_554e, - 0x6869_5c0c_d7cb_f43d, - 0x1090_b1b4_d2be_be7a, - ]), - vesta::Base::from_raw([ - 0xe383_e1ec_3baa_8d69, - 0x1b21_8e35_ecf2_328e, - 0x68f5_ce5c_bed1_9cad, - 0x33e3_8018_a801_387a, - ]), - vesta::Base::from_raw([ - 0xb76b_0b3d_787e_e953, - 0x5f4a_02d2_8729_e3ae, - 0xeef8_d83d_0e87_6bac, - 0x1654_af18_772b_2da5, - ]), - ], - [ - vesta::Base::from_raw([ - 0xef7c_e6a0_1326_5477, - 0xbb08_9387_0367_ec6c, - 0x4474_2de8_8c5a_b0d5, - 0x1678_be3c_c9c6_7993, - ]), - vesta::Base::from_raw([ - 0xaf5d_4789_3348_f766, - 0xdaf1_8183_55b1_3b4f, - 0x7ff9_c6be_546e_928a, - 0x3780_bd1e_01f3_4c22, - ]), - vesta::Base::from_raw([ - 0xa123_8032_0d7c_c1de, - 0x5d11_e69a_a6c0_b98c, - 0x0786_018e_7cb7_7267, - 0x1e83_d631_5c9f_125b, - ]), - ], - [ - vesta::Base::from_raw([ - 0x1799_603e_855c_e731, - 0xc486_894d_76e0_c33b, - 0x160b_4155_2f29_31c8, - 0x354a_fd0a_2f9d_0b26, - ]), - vesta::Base::from_raw([ - 0x8b99_7ee0_6be1_bff3, - 0x60b0_0dbe_1fac_ed07, - 0x2d8a_ffa6_2905_c5a5, - 0x00cd_6d29_f166_eadc, - ]), - vesta::Base::from_raw([ - 0x08d0_6419_1708_2f2c, - 0xc60d_0197_3f18_3057, - 0xdbe0_e3d7_cdbc_66ef, - 0x1d62_1935_2768_e3ae, - ]), - ], - [ - vesta::Base::from_raw([ - 0xfa08_dd98_0638_7577, - 0xafe3_ca1d_b8d4_f529, - 0xe48d_2370_d7d1_a142, - 0x1463_36e2_5db5_181d, - ]), - vesta::Base::from_raw([ - 0xa901_d3ce_84de_0ad4, - 0x022e_54b4_9c13_d907, - 0x997a_2116_3e2e_43df, - 0x0005_d8e0_85fd_72ee, - ]), - vesta::Base::from_raw([ - 0x1c36_f313_4196_4484, - 0x6f8e_bc1d_2296_021a, - 0x0dd5_e61c_8a4e_8642, - 0x364e_97c7_a389_3227, - ]), - ], - [ - vesta::Base::from_raw([ - 0xd7a0_0c03_d2e0_baaa, - 0xfa97_ec80_ad30_7a52, - 0x561c_6fff_1534_6878, - 0x0118_9910_671b_c16b, - ]), - vesta::Base::from_raw([ - 0x63fd_8ac5_7a95_ca8c, - 0x4c0f_7e00_1df4_90aa, - 0x5229_dfaa_0123_1a45, - 0x162a_7c80_f4d2_d12e, - ]), - vesta::Base::from_raw([ - 0x32e6_9efb_22f4_0b96, - 0xcaff_31b4_fda3_2124, - 0x2604_e4af_b09f_8603, - 0x2a0d_6c09_5766_66bb, - ]), - ], - [ - vesta::Base::from_raw([ - 0xc0a0_180f_8cbf_c0d2, - 0xf444_d10d_63a7_4e2c, - 0xe16a_4d60_3d5a_808e, - 0x0978_e5c5_1e1e_5649, - ]), - vesta::Base::from_raw([ - 0x03f4_460e_bc35_1b6e, - 0x0508_7d90_3bda_cfd1, - 0xebe1_9bbd_ce25_1011, - 0x1bdc_ee3a_aca9_cd25, - ]), - vesta::Base::from_raw([ - 0xf619_64bf_3ade_7670, - 0x0c94_7321_e007_5e3f, - 0xe494_7914_0b19_44fd, - 0x1862_cccb_70b5_b885, - ]), - ], - [ - vesta::Base::from_raw([ - 0xc326_7da6_e94a_dc50, - 0x39ee_99c1_cc6e_5dda, - 0xbc26_cc88_3a19_87e1, - 0x1f3e_91d8_63c1_6922, - ]), - vesta::Base::from_raw([ - 0x0f85_b4ac_2c36_7406, - 0xfa66_1465_c656_ad99, - 0xef5c_08f8_478f_663a, - 0x1af4_7a48_a601_6a49, - ]), - vesta::Base::from_raw([ - 0x0eab_cd87_e7d0_1b15, - 0x1c36_98b0_a2e3_da10, - 0x009d_5733_8c69_3505, - 0x3c8e_e901_956e_3d3f, - ]), - ], - [ - vesta::Base::from_raw([ - 0x8b94_7721_8967_3476, - 0xe10c_e2b7_069f_4dbd, - 0x68d0_b024_f591_b520, - 0x1660_a8cd_e7fe_c553, - ]), - vesta::Base::from_raw([ - 0x9d8d_0f67_fdaa_79d5, - 0x3963_c2c1_f558_6e2f, - 0x1303_9363_34dd_1132, - 0x0f6d_9919_29d5_e4e7, - ]), - vesta::Base::from_raw([ - 0x7a43_3091_e1ce_2d3a, - 0x4e7f_da77_0712_f343, - 0xcc62_5eaa_ab52_b4dc, - 0x02b9_cea1_921c_d9f6, - ]), - ], - [ - vesta::Base::from_raw([ - 0x3797_b2d8_3760_43b3, - 0xd8ca_f468_976f_0472, - 0x214f_7c67_84ac_b565, - 0x14a3_23b9_9b90_0331, - ]), - vesta::Base::from_raw([ - 0x347f_ef2c_00f0_953a, - 0x718b_7fbc_7788_af78, - 0xec01_ea79_642d_5760, - 0x1904_76b5_80cb_9277, - ]), - vesta::Base::from_raw([ - 0xff4e_7e6f_b268_dfd7, - 0x9660_902b_6008_7651, - 0xa424_63d3_0b44_2b6f, - 0x090a_3a9d_869d_2eef, - ]), - ], - [ - vesta::Base::from_raw([ - 0xf983_387e_a045_6203, - 0xe365_0013_04f9_a11e, - 0x0dbe_8fd2_270a_6795, - 0x3877_a955_8636_7567, - ]), - vesta::Base::from_raw([ - 0x39c0_af0f_e01f_4a06, - 0x6011_8c53_a218_1352, - 0x5df3_9a2c_c63d_dc0a, - 0x2d89_4691_240f_e953, - ]), - vesta::Base::from_raw([ - 0x1aca_9eaf_9bba_9850, - 0x5914_e855_eeb4_4aa1, - 0x7ef7_1780_2016_6189, - 0x21b9_c182_92bd_bc59, - ]), - ], - [ - vesta::Base::from_raw([ - 0x33f5_09a7_4ad9_d39b, - 0x272e_1cc6_c36a_2968, - 0x505a_05f2_a6ae_834c, - 0x2fe7_6be7_cff7_23e2, - ]), - vesta::Base::from_raw([ - 0x0df9_fa97_277f_a8b4, - 0xd15b_ff84_0dda_e8a5, - 0x9299_81d7_cfce_253b, - 0x187a_a448_f391_e3ca, - ]), - vesta::Base::from_raw([ - 0xf0c6_6af5_ffc7_3736, - 0x663c_cf7b_2ffe_4b5e, - 0x007a_b3aa_3617_f422, - 0x0b70_83ad_7517_07bf, - ]), - ], - [ - vesta::Base::from_raw([ - 0x2f9b_20f1_fbd4_9791, - 0x1975_b962_f6cb_8e0b, - 0x3bc4_ca99_02c5_2acb, - 0x030d_dbb4_7049_3f16, - ]), - vesta::Base::from_raw([ - 0x3a1c_62ca_8fbf_2525, - 0x8fb8_ab9d_60ea_17b2, - 0x950b_0ab1_8d35_46df, - 0x3130_fbaf_fb5a_a82a, - ]), - vesta::Base::from_raw([ - 0x43a8_7618_0dc3_82e0, - 0x15ce_2ead_2fcd_051e, - 0x4f74_d74b_ac2e_e457, - 0x337f_5447_07c4_30f0, - ]), - ], - [ - vesta::Base::from_raw([ - 0x26de_98a8_736d_1d11, - 0x7d8e_471a_9fb9_5fef, - 0xac9d_91b0_930d_ac75, - 0x3499_7991_9015_394f, - ]), - vesta::Base::from_raw([ - 0xccfc_b618_31d5_c775, - 0x3bf9_3da6_fff3_1d95, - 0x2305_cd7a_921e_c5f1, - 0x027c_c4ef_e3fb_35dd, - ]), - vesta::Base::from_raw([ - 0xc3fa_2629_635d_27de, - 0x67f1_c6b7_3147_64af, - 0x61b7_1a36_9868_2ad2, - 0x037f_9f23_6595_4c5b, - ]), - ], - [ - vesta::Base::from_raw([ - 0x77c5_b024_8483_71ae, - 0x6041_4abe_362d_01c9, - 0x10f1_cc6d_f8b4_bcd7, - 0x1f69_7cac_4d07_feb7, - ]), - vesta::Base::from_raw([ - 0x786a_dd24_4aa0_ef29, - 0x3145_c478_0631_09d6, - 0x26e6_c851_fbd5_72a6, - 0x267a_750f_e5d7_cfbc, - ]), - vesta::Base::from_raw([ - 0x180e_2b4d_3e75_6f65, - 0xaf28_5fa8_2ce4_fae5, - 0x678c_9996_d9a4_72c8, - 0x0c91_feab_4a43_193a, - ]), - ], - [ - vesta::Base::from_raw([ - 0x79c4_7c57_3ac4_10f7, - 0x7e3b_83af_4a4b_a3ba, - 0x2186_c303_8ea0_5e69, - 0x1745_569a_0a3e_3014, - ]), - vesta::Base::from_raw([ - 0x1e03_8852_2696_191f, - 0xfdff_66c6_f3b5_ffe1, - 0xeca5_1207_78a5_6711, - 0x2986_3d54_6e7e_7c0d, - ]), - vesta::Base::from_raw([ - 0x2f22_5e63_66bf_e390, - 0xa79a_03df_8339_94c6, - 0xbf06_bae4_9ef8_53f6, - 0x1148_d6ab_2bd0_0192, - ]), - ], - [ - vesta::Base::from_raw([ - 0xf4f6_331a_8b26_5d15, - 0xf745_f45d_350d_41d4, - 0xe18b_1499_060d_a366, - 0x02e0_e121_b0f3_dfef, - ]), - vesta::Base::from_raw([ - 0x078a_e6aa_1510_54b7, - 0x6904_0173_6d44_a653, - 0xb89e_f73a_40a2_b274, - 0x0d0a_a46e_76a6_a278, - ]), - vesta::Base::from_raw([ - 0x9a4d_532c_7b6e_0958, - 0x392d_de71_0f1f_06db, - 0xeee5_45f3_fa6d_3d08, - 0x1394_3675_b04a_a986, - ]), - ], - [ - vesta::Base::from_raw([ - 0x961f_c818_dcbb_66b5, - 0xc9f2_b325_7530_dafe, - 0xd97a_11d6_3088_f5d9, - 0x2901_ec61_942d_34aa, - ]), - vesta::Base::from_raw([ - 0xfdf5_44b9_63d1_fdc7, - 0x22ff_a2a2_af9f_a3e3, - 0xf431_d544_34a3_e0cf, - 0x2020_4a21_05d2_2e7e, - ]), - vesta::Base::from_raw([ - 0x1211_b9e2_190d_6852, - 0xa004_abe8_e015_28c4, - 0x5c1e_3e9e_27a5_71c3, - 0x3a8a_6282_9512_1d5c, - ]), - ], -]; - -// n: 255 -// t: 3 -// N: 765 -// Result Algorithm 1: -// [True, 0] -// Result Algorithm 2: -// [True, None] -// Result Algorithm 3: -// [True, None] -// Prime number: 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001 -// MDS matrix: -pub(crate) const MDS: [[vesta::Base; 3]; 3] = [ - [ - vesta::Base::from_raw([ - 0xeb4f_1f74_2963_421f, - 0x5f71_0afc_43dd_c5f6, - 0x9191_3f56_cf21_af2b, - 0x1853_b497_7c6f_a227, - ]), - vesta::Base::from_raw([ - 0x45e5_1db6_ac6f_e4a7, - 0x5a0f_a4df_a500_bcad, - 0x63f4_84c1_0fcf_0586, - 0x3d83_1189_cfbb_c452, - ]), - vesta::Base::from_raw([ - 0xd188_37f9_8347_f137, - 0x3f89_65c7_8083_8a94, - 0x4ba8_8b9e_4017_19c0, - 0x3a0e_3f84_d3c1_77d8, - ]), - ], - [ - vesta::Base::from_raw([ - 0x84fd_7923_337c_f77e, - 0x2896_f8d0_fd5c_9a75, - 0x8e9d_c529_f471_8f83, - 0x35e2_6e39_8450_6279, - ]), - vesta::Base::from_raw([ - 0x3eb9_24f5_6fff_7908, - 0x3641_cecf_3a2a_5a8a, - 0x00cd_7dbe_a799_70ab, - 0x10a8_1663_02cb_753c, - ]), - vesta::Base::from_raw([ - 0xb672_27c1_a141_ae94, - 0x198e_1aee_777e_2521, - 0xf434_92ce_5121_4b00, - 0x314f_762a_506d_321b, - ]), - ], - [ - vesta::Base::from_raw([ - 0xabcb_d614_eaf5_eba1, - 0xa90f_28b0_cb31_76fb, - 0xcb2e_ab86_ef31_d915, - 0x07b8_5627_c832_782a, - ]), - vesta::Base::from_raw([ - 0xc255_efd0_06b5_db1c, - 0xb5d9_85dc_1630_a4b2, - 0x9756_4e1b_5d1a_c72f, - 0x2a2d_e13e_70f2_7e16, - ]), - vesta::Base::from_raw([ - 0xcffd_f529_3334_29fc, - 0x21e3_af7e_f123_32cd, - 0xfff5_40a8_7327_c7ce, - 0x2c60_94d1_c6e1_caba, - ]), - ], -]; - -pub(crate) const MDS_INV: [[vesta::Base; 3]; 3] = [ - [ - vesta::Base::from_raw([ - 0xb204_ddc6_5e58_2044, - 0x47a6_0484_b0a9_9c91, - 0xcaf5_4d78_24c1_200e, - 0x36df_4950_21cf_7828, - ]), - vesta::Base::from_raw([ - 0x6a6b_94ad_aa0d_9c9e, - 0xe2cd_38b9_59d4_61ff, - 0xe43e_c4bf_3e0d_f00c, - 0x034f_beae_4650_c2c7, - ]), - vesta::Base::from_raw([ - 0xa862_7a02_8c1a_f7d6, - 0x841b_ebf1_a15b_746e, - 0x1fd5_6832_d0ab_5570, - 0x20a8_64d6_790f_7c1c, - ]), - ], - [ - vesta::Base::from_raw([ - 0x3470_d5c5_53bc_9d20, - 0x1f95_660f_eb5d_b121, - 0xdd31_97ac_c894_9076, - 0x2d08_703d_48ec_d7dc, - ]), - vesta::Base::from_raw([ - 0x6b5b_42b0_67d8_30f3, - 0x6169_b6fa_721a_470e, - 0xeff3_18a2_8983_158a, - 0x2db1_0ecd_507a_2f27, - ]), - vesta::Base::from_raw([ - 0xfbae_b537_d278_4760, - 0x0068_e709_07e7_089d, - 0x926a_5fc0_cc1e_f726, - 0x0c8a_58c0_6473_cdfa, - ]), - ], - [ - vesta::Base::from_raw([ - 0x3a5a_ca10_7129_6e61, - 0x4ad4_442e_96c9_d5e8, - 0x5432_f0c0_b908_a411, - 0x2a64_2dca_695d_744d, - ]), - vesta::Base::from_raw([ - 0x1bd9_bfcb_be02_5ff1, - 0x24f6_ad43_b703_ad90, - 0xebb7_238d_f00d_17e7, - 0x114e_c796_fb40_3f5f, - ]), - vesta::Base::from_raw([ - 0x67f0_642e_14a9_c3bf, - 0xf6a6_9176_7069_7a97, - 0x0408_110d_c66e_b147, - 0x2825_e067_5968_dbeb, - ]), - ], -]; diff --git a/halo2_gadgets/src/poseidon/primitives/grain.rs b/halo2_gadgets/src/poseidon/primitives/grain.rs deleted file mode 100644 index 1a780d5899..0000000000 --- a/halo2_gadgets/src/poseidon/primitives/grain.rs +++ /dev/null @@ -1,196 +0,0 @@ -//! The Grain LFSR in self-shrinking mode, as used by Poseidon. - -use std::marker::PhantomData; - -use bitvec::prelude::*; -use ff::{FromUniformBytes, PrimeField}; -use halo2_proofs::arithmetic::Field; - -const STATE: usize = 80; - -#[derive(Debug, Clone, Copy)] -pub(super) enum FieldType { - /// GF(2^n) - #[allow(dead_code)] - Binary, - /// GF(p) - PrimeOrder, -} - -impl FieldType { - fn tag(&self) -> u8 { - match self { - FieldType::Binary => 0, - FieldType::PrimeOrder => 1, - } - } -} - -#[derive(Debug, Clone, Copy)] -pub(super) enum SboxType { - /// x^alpha - Pow, - /// x^(-1) - #[allow(dead_code)] - Inv, -} - -impl SboxType { - fn tag(&self) -> u8 { - match self { - SboxType::Pow => 0, - SboxType::Inv => 1, - } - } -} - -pub(super) struct Grain { - state: BitArr!(for 80, in u8, Msb0), - next_bit: usize, - _field: PhantomData, -} - -impl Grain { - pub(super) fn new(sbox: SboxType, t: u16, r_f: u16, r_p: u16) -> Self { - // Initialize the LFSR state. - let mut state = bitarr![u8, Msb0; 1; STATE]; - let mut set_bits = |offset: usize, len, value| { - // Poseidon reference impl sets initial state bits in MSB order. - for i in 0..len { - *state.get_mut(offset + len - 1 - i).unwrap() = (value >> i) & 1 != 0; - } - }; - set_bits(0, 2, FieldType::PrimeOrder.tag() as u16); - set_bits(2, 4, sbox.tag() as u16); - set_bits(6, 12, F::NUM_BITS as u16); - set_bits(18, 12, t); - set_bits(30, 10, r_f); - set_bits(40, 10, r_p); - - let mut grain = Grain { - state, - next_bit: STATE, - _field: PhantomData, - }; - - // Discard the first 160 bits. - for _ in 0..20 { - grain.load_next_8_bits(); - grain.next_bit = STATE; - } - - grain - } - - fn load_next_8_bits(&mut self) { - let mut new_bits = 0u8; - for i in 0..8 { - new_bits |= ((self.state[i + 62] - ^ self.state[i + 51] - ^ self.state[i + 38] - ^ self.state[i + 23] - ^ self.state[i + 13] - ^ self.state[i]) as u8) - << i; - } - self.state.rotate_left(8); - self.next_bit -= 8; - for i in 0..8 { - *self.state.get_mut(self.next_bit + i).unwrap() = (new_bits >> i) & 1 != 0; - } - } - - fn get_next_bit(&mut self) -> bool { - if self.next_bit == STATE { - self.load_next_8_bits(); - } - let ret = self.state[self.next_bit]; - self.next_bit += 1; - ret - } - - /// Returns the next field element from this Grain instantiation. - pub(super) fn next_field_element(&mut self) -> F { - // Loop until we get an element in the field. - loop { - let mut bytes = F::Repr::default(); - - // Poseidon reference impl interprets the bits as a repr in MSB order, because - // it's easy to do that in Python. Meanwhile, our field elements all use LSB - // order. There's little motivation to diverge from the reference impl; these - // are all constants, so we aren't introducing big-endianness into the rest of - // the circuit (assuming unkeyed Poseidon, but we probably wouldn't want to - // implement Grain inside a circuit, so we'd use a different round constant - // derivation function there). - let view = bytes.as_mut(); - for (i, bit) in self.take(F::NUM_BITS as usize).enumerate() { - // If we diverged from the reference impl and interpreted the bits in LSB - // order, we would remove this line. - let i = F::NUM_BITS as usize - 1 - i; - - view[i / 8] |= if bit { 1 << (i % 8) } else { 0 }; - } - - if let Some(f) = F::from_repr_vartime(bytes) { - break f; - } - } - } -} - -impl> Grain { - /// Returns the next field element from this Grain instantiation, without using - /// rejection sampling. - pub(super) fn next_field_element_without_rejection(&mut self) -> F { - let mut bytes = [0u8; 64]; - - // Poseidon reference impl interprets the bits as a repr in MSB order, because - // it's easy to do that in Python. Additionally, it does not use rejection - // sampling in cases where the constants don't specifically need to be uniformly - // random for security. We do not provide APIs that take a field-element-sized - // array and reduce it modulo the field order, because those are unsafe APIs to - // offer generally (accidentally using them can lead to divergence in consensus - // systems due to not rejecting canonical forms). - // - // Given that we don't want to diverge from the reference implementation, we hack - // around this restriction by serializing the bits into a 64-byte array and then - // calling F::from_bytes_wide. PLEASE DO NOT COPY THIS INTO YOUR OWN CODE! - let view = bytes.as_mut(); - for (i, bit) in self.take(F::NUM_BITS as usize).enumerate() { - // If we diverged from the reference impl and interpreted the bits in LSB - // order, we would remove this line. - let i = F::NUM_BITS as usize - 1 - i; - - view[i / 8] |= if bit { 1 << (i % 8) } else { 0 }; - } - - F::from_uniform_bytes(&bytes) - } -} - -impl Iterator for Grain { - type Item = bool; - - fn next(&mut self) -> Option { - // Evaluate bits in pairs: - // - If the first bit is a 1, output the second bit. - // - If the first bit is a 0, discard the second bit. - while !self.get_next_bit() { - self.get_next_bit(); - } - Some(self.get_next_bit()) - } -} - -#[cfg(test)] -mod tests { - use halo2curves::pasta::Fp; - - use super::{Grain, SboxType}; - - #[test] - fn grain() { - let mut grain = Grain::::new(SboxType::Pow, 3, 8, 56); - let _f = grain.next_field_element(); - } -} diff --git a/halo2_gadgets/src/poseidon/primitives/mds.rs b/halo2_gadgets/src/poseidon/primitives/mds.rs deleted file mode 100644 index f1642d21c3..0000000000 --- a/halo2_gadgets/src/poseidon/primitives/mds.rs +++ /dev/null @@ -1,124 +0,0 @@ -use ff::FromUniformBytes; - -use super::{grain::Grain, Mds}; - -pub(super) fn generate_mds + Ord, const T: usize>( - grain: &mut Grain, - mut select: usize, -) -> (Mds, Mds) { - let (xs, ys, mds) = loop { - // Generate two [F; T] arrays of unique field elements. - let (xs, ys) = loop { - let mut vals: Vec<_> = (0..2 * T) - .map(|_| grain.next_field_element_without_rejection()) - .collect(); - - // Check that we have unique field elements. - let mut unique = vals.clone(); - unique.sort_unstable(); - unique.dedup(); - if vals.len() == unique.len() { - let rhs = vals.split_off(T); - break (vals, rhs); - } - }; - - // We need to ensure that the MDS is secure. Instead of checking the MDS against - // the relevant algorithms directly, we witness a fixed number of MDS matrices - // that we need to sample from the given Grain state before obtaining a secure - // matrix. This can be determined out-of-band via the reference implementation in - // Sage. - if select != 0 { - select -= 1; - continue; - } - - // Generate a Cauchy matrix, with elements a_ij in the form: - // a_ij = 1/(x_i + y_j); x_i + y_j != 0 - // - // It would be much easier to use the alternate definition: - // a_ij = 1/(x_i - y_j); x_i - y_j != 0 - // - // These are clearly equivalent on `y <- -y`, but it is easier to work with the - // negative formulation, because ensuring that xs ∪ ys is unique implies that - // x_i - y_j != 0 by construction (whereas the positive case does not hold). It - // also makes computation of the matrix inverse simpler below (the theorem used - // was formulated for the negative definition). - // - // However, the Poseidon paper and reference impl use the positive formulation, - // and we want to rely on the reference impl for MDS security, so we use the same - // formulation. - let mut mds = [[F::ZERO; T]; T]; - #[allow(clippy::needless_range_loop)] - for i in 0..T { - for j in 0..T { - let sum = xs[i] + ys[j]; - // We leverage the secure MDS selection counter to also check this. - assert!(!sum.is_zero_vartime()); - mds[i][j] = sum.invert().unwrap(); - } - } - - break (xs, ys, mds); - }; - - // Compute the inverse. All square Cauchy matrices have a non-zero determinant and - // thus are invertible. The inverse for a Cauchy matrix of the form: - // - // a_ij = 1/(x_i - y_j); x_i - y_j != 0 - // - // has elements b_ij given by: - // - // b_ij = (x_j - y_i) A_j(y_i) B_i(x_j) (Schechter 1959, Theorem 1) - // - // where A_i(x) and B_i(x) are the Lagrange polynomials for xs and ys respectively. - // - // We adapt this to the positive Cauchy formulation by negating ys. - let mut mds_inv = [[F::ZERO; T]; T]; - let l = |xs: &[F], j, x: F| { - let x_j = xs[j]; - xs.iter().enumerate().fold(F::ONE, |acc, (m, x_m)| { - if m == j { - acc - } else { - // We can invert freely; by construction, the elements of xs are distinct. - let diff: F = x_j - *x_m; - acc * (x - x_m) * diff.invert().unwrap() - } - }) - }; - let neg_ys: Vec<_> = ys.iter().map(|y| -*y).collect(); - for i in 0..T { - for j in 0..T { - mds_inv[i][j] = (xs[j] - neg_ys[i]) * l(&xs, j, neg_ys[i]) * l(&neg_ys, i, xs[j]); - } - } - - (mds, mds_inv) -} - -#[cfg(test)] -mod tests { - use halo2curves::pasta::Fp; - - use super::{generate_mds, Grain}; - - #[test] - fn poseidon_mds() { - const T: usize = 3; - let mut grain = Grain::new(super::super::grain::SboxType::Pow, T as u16, 8, 56); - let (mds, mds_inv) = generate_mds::(&mut grain, 0); - - // Verify that MDS * MDS^-1 = I. - #[allow(clippy::needless_range_loop)] - for i in 0..T { - for j in 0..T { - let expected = if i == j { Fp::one() } else { Fp::zero() }; - assert_eq!( - (0..T).fold(Fp::zero(), |acc, k| acc + (mds[i][k] * mds_inv[k][j])), - expected - ); - } - } - } -} diff --git a/halo2_gadgets/src/poseidon/primitives/p128pow5t3.rs b/halo2_gadgets/src/poseidon/primitives/p128pow5t3.rs deleted file mode 100644 index fdd4b22959..0000000000 --- a/halo2_gadgets/src/poseidon/primitives/p128pow5t3.rs +++ /dev/null @@ -1,319 +0,0 @@ -use halo2_proofs::arithmetic::Field; -use halo2curves::pasta::{pallas::Base as Fp, vesta::Base as Fq}; - -use super::{Mds, Spec}; - -/// Poseidon-128 using the $x^5$ S-box, with a width of 3 field elements, and the -/// standard number of rounds for 128-bit security "with margin". -/// -/// The standard specification for this set of parameters (on either of the Pasta -/// fields) uses $R_F = 8, R_P = 56$. This is conveniently an even number of -/// partial rounds, making it easier to construct a Halo 2 circuit. -#[derive(Debug)] -pub struct P128Pow5T3; - -impl Spec for P128Pow5T3 { - fn full_rounds() -> usize { - 8 - } - - fn partial_rounds() -> usize { - 56 - } - - fn sbox(val: Fp) -> Fp { - val.pow_vartime([5]) - } - - fn secure_mds() -> usize { - unimplemented!() - } - - fn constants() -> (Vec<[Fp; 3]>, Mds, Mds) { - ( - super::fp::ROUND_CONSTANTS[..].to_vec(), - super::fp::MDS, - super::fp::MDS_INV, - ) - } -} - -impl Spec for P128Pow5T3 { - fn full_rounds() -> usize { - 8 - } - - fn partial_rounds() -> usize { - 56 - } - - fn sbox(val: Fq) -> Fq { - val.pow_vartime([5]) - } - - fn secure_mds() -> usize { - unimplemented!() - } - - fn constants() -> (Vec<[Fq; 3]>, Mds, Mds) { - ( - super::fq::ROUND_CONSTANTS[..].to_vec(), - super::fq::MDS, - super::fq::MDS_INV, - ) - } -} - -#[cfg(test)] -mod tests { - use super::{ - super::{fp, fq}, - Fp, Fq, - }; - use crate::poseidon::primitives::{ - generate_constants, permute, ConstantLength, Hash, Mds, Spec, - }; - use ff::PrimeField; - use ff::{Field, FromUniformBytes}; - use std::marker::PhantomData; - - /// The same Poseidon specification as poseidon::P128Pow5T3, but constructed - /// such that its constants will be generated at runtime. - #[derive(Debug)] - pub struct P128Pow5T3Gen(PhantomData); - - impl P128Pow5T3Gen { - pub fn new() -> Self { - P128Pow5T3Gen(PhantomData) - } - } - - impl + Ord, const SECURE_MDS: usize> Spec - for P128Pow5T3Gen - { - fn full_rounds() -> usize { - 8 - } - - fn partial_rounds() -> usize { - 56 - } - - fn sbox(val: F) -> F { - val.pow_vartime([5]) - } - - fn secure_mds() -> usize { - SECURE_MDS - } - - fn constants() -> (Vec<[F; 3]>, Mds, Mds) { - generate_constants::<_, Self, 3, 2>() - } - } - - #[test] - fn verify_constants() { - fn verify_constants_helper + Ord>( - expected_round_constants: [[F; 3]; 64], - expected_mds: [[F; 3]; 3], - expected_mds_inv: [[F; 3]; 3], - ) { - let (round_constants, mds, mds_inv) = P128Pow5T3Gen::::constants(); - - for (actual, expected) in round_constants - .iter() - .flatten() - .zip(expected_round_constants.iter().flatten()) - { - assert_eq!(actual, expected); - } - - for (actual, expected) in mds.iter().flatten().zip(expected_mds.iter().flatten()) { - assert_eq!(actual, expected); - } - - for (actual, expected) in mds_inv - .iter() - .flatten() - .zip(expected_mds_inv.iter().flatten()) - { - assert_eq!(actual, expected); - } - } - - verify_constants_helper(fp::ROUND_CONSTANTS, fp::MDS, fp::MDS_INV); - verify_constants_helper(fq::ROUND_CONSTANTS, fq::MDS, fq::MDS_INV); - } - - #[test] - fn test_against_reference() { - { - // , using parameters from - // `generate_parameters_grain.sage 1 0 255 3 8 56 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001`. - // The test vector is generated by `sage poseidonperm_x5_pallas_3.sage --rust` - - let mut input = [ - Fp::from_raw([ - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - ]), - Fp::from_raw([ - 0x0000_0000_0000_0001, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - ]), - Fp::from_raw([ - 0x0000_0000_0000_0002, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - ]), - ]; - - let expected_output = [ - Fp::from_raw([ - 0xaeb1_bc02_4aec_a456, - 0xf7e6_9a71_d0b6_42a0, - 0x94ef_b364_f966_240f, - 0x2a52_6acd_0b64_b453, - ]), - Fp::from_raw([ - 0x012a_3e96_28e5_b82a, - 0xdcd4_2e7f_bed9_dafe, - 0x76ff_7dae_343d_5512, - 0x13c5_d156_8b4a_a430, - ]), - Fp::from_raw([ - 0x3590_29a1_d34e_9ddd, - 0xf7cf_dfe1_bda4_2c7b, - 0x256f_cd59_7984_561a, - 0x0a49_c868_c697_6544, - ]), - ]; - - permute::, 3, 2>(&mut input, &fp::MDS, &fp::ROUND_CONSTANTS); - assert_eq!(input, expected_output); - } - - { - // , using parameters from - // `generate_parameters_grain.sage 1 0 255 3 8 56 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001`. - // The test vector is generated by `sage poseidonperm_x5_vesta_3.sage --rust` - - let mut input = [ - Fq::from_raw([ - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - ]), - Fq::from_raw([ - 0x0000_0000_0000_0001, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - ]), - Fq::from_raw([ - 0x0000_0000_0000_0002, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - ]), - ]; - - let expected_output = [ - Fq::from_raw([ - 0x0eb0_8ea8_13be_be59, - 0x4d43_d197_3dd3_36c6, - 0xeddd_74f2_2f8f_2ff7, - 0x315a_1f4c_db94_2f7c, - ]), - Fq::from_raw([ - 0xf9f1_26e6_1ea1_65f1, - 0x413e_e0eb_7bbd_2198, - 0x642a_dee0_dd13_aa48, - 0x3be4_75f2_d764_2bde, - ]), - Fq::from_raw([ - 0x14d5_4237_2a7b_a0d9, - 0x5019_bfd4_e042_3fa0, - 0x117f_db24_20d8_ea60, - 0x25ab_8aec_e953_7168, - ]), - ]; - - permute::, 3, 2>(&mut input, &fq::MDS, &fq::ROUND_CONSTANTS); - assert_eq!(input, expected_output); - } - } - - #[test] - fn permute_test_vectors() { - { - let (round_constants, mds, _) = super::P128Pow5T3::constants(); - - for tv in crate::poseidon::primitives::test_vectors::fp::permute() { - let mut state = [ - Fp::from_repr(tv.initial_state[0]).unwrap(), - Fp::from_repr(tv.initial_state[1]).unwrap(), - Fp::from_repr(tv.initial_state[2]).unwrap(), - ]; - - permute::(&mut state, &mds, &round_constants); - - for (expected, actual) in tv.final_state.iter().zip(state.iter()) { - assert_eq!(&actual.to_repr(), expected); - } - } - } - - { - let (round_constants, mds, _) = super::P128Pow5T3::constants(); - - for tv in crate::poseidon::primitives::test_vectors::fq::permute() { - let mut state = [ - Fq::from_repr(tv.initial_state[0]).unwrap(), - Fq::from_repr(tv.initial_state[1]).unwrap(), - Fq::from_repr(tv.initial_state[2]).unwrap(), - ]; - - permute::(&mut state, &mds, &round_constants); - - for (expected, actual) in tv.final_state.iter().zip(state.iter()) { - assert_eq!(&actual.to_repr(), expected); - } - } - } - } - - #[test] - fn hash_test_vectors() { - for tv in crate::poseidon::primitives::test_vectors::fp::hash() { - let message = [ - Fp::from_repr(tv.input[0]).unwrap(), - Fp::from_repr(tv.input[1]).unwrap(), - ]; - - let result = - Hash::<_, super::P128Pow5T3, ConstantLength<2>, 3, 2>::init().hash(message); - - assert_eq!(result.to_repr(), tv.output); - } - - for tv in crate::poseidon::primitives::test_vectors::fq::hash() { - let message = [ - Fq::from_repr(tv.input[0]).unwrap(), - Fq::from_repr(tv.input[1]).unwrap(), - ]; - - let result = - Hash::<_, super::P128Pow5T3, ConstantLength<2>, 3, 2>::init().hash(message); - - assert_eq!(result.to_repr(), tv.output); - } - } -} diff --git a/halo2_gadgets/src/poseidon/primitives/test_vectors.rs b/halo2_gadgets/src/poseidon/primitives/test_vectors.rs deleted file mode 100644 index 1c345a4853..0000000000 --- a/halo2_gadgets/src/poseidon/primitives/test_vectors.rs +++ /dev/null @@ -1,1261 +0,0 @@ -//! Test vectors for [`OrchardNullifier`]. - -pub(crate) struct PermuteTestVector { - pub(crate) initial_state: [[u8; 32]; 3], - pub(crate) final_state: [[u8; 32]; 3], -} - -pub(crate) struct HashTestVector { - pub(crate) input: [[u8; 32]; 2], - pub(crate) output: [u8; 32], -} - -pub(crate) mod fp { - use super::*; - - pub(crate) fn permute() -> Vec { - use PermuteTestVector as TestVector; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/orchard_poseidon/permute/fp.py - vec![ - TestVector { - initial_state: [ - [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - [ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - [ - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - ], - final_state: [ - [ - 0x56, 0xa4, 0xec, 0x4a, 0x02, 0xbc, 0xb1, 0xae, 0xa0, 0x42, 0xb6, 0xd0, - 0x71, 0x9a, 0xe6, 0xf7, 0x0f, 0x24, 0x66, 0xf9, 0x64, 0xb3, 0xef, 0x94, - 0x53, 0xb4, 0x64, 0x0b, 0xcd, 0x6a, 0x52, 0x2a, - ], - [ - 0x2a, 0xb8, 0xe5, 0x28, 0x96, 0x3e, 0x2a, 0x01, 0xfe, 0xda, 0xd9, 0xbe, - 0x7f, 0x2e, 0xd4, 0xdc, 0x12, 0x55, 0x3d, 0x34, 0xae, 0x7d, 0xff, 0x76, - 0x30, 0xa4, 0x4a, 0x8b, 0x56, 0xd1, 0xc5, 0x13, - ], - [ - 0xdd, 0x9d, 0x4e, 0xd3, 0xa1, 0x29, 0x90, 0x35, 0x7b, 0x2c, 0xa4, 0xbd, - 0xe1, 0xdf, 0xcf, 0xf7, 0x1a, 0x56, 0x84, 0x79, 0x59, 0xcd, 0x6f, 0x25, - 0x44, 0x65, 0x97, 0xc6, 0x68, 0xc8, 0x49, 0x0a, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x5c, 0x7a, 0x8f, 0x73, 0xad, 0xfc, 0x70, 0xfb, 0x3f, 0x13, 0x94, 0x49, - 0xac, 0x6b, 0x57, 0x07, 0x4c, 0x4d, 0x6e, 0x66, 0xb1, 0x64, 0x93, 0x9d, - 0xaf, 0xfa, 0x2e, 0xf6, 0xee, 0x69, 0x21, 0x08, - ], - [ - 0x1a, 0xdd, 0x86, 0xb3, 0xf2, 0xe1, 0xbd, 0xa6, 0x2a, 0x5d, 0x2e, 0x0e, - 0x98, 0x2b, 0x77, 0xe6, 0xb0, 0xef, 0x9c, 0xa3, 0xf2, 0x49, 0x88, 0xc7, - 0xb3, 0x53, 0x42, 0x01, 0xcf, 0xb1, 0xcd, 0x0d, - ], - [ - 0xbd, 0x69, 0xb8, 0x25, 0x32, 0xb6, 0x94, 0x0f, 0xf2, 0x59, 0x0f, 0x67, - 0x9b, 0xa9, 0xc7, 0x27, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, - 0xa5, 0xe2, 0x9d, 0x4e, 0x30, 0xa7, 0x35, 0x14, - ], - ], - final_state: [ - [ - 0xd0, 0x6e, 0x2f, 0x83, 0x38, 0x92, 0x8a, 0x7e, 0xe7, 0x38, 0x0c, 0x77, - 0x92, 0x80, 0x87, 0xcd, 0xa2, 0xfd, 0x29, 0x61, 0xa1, 0x52, 0x69, 0x03, - 0x7a, 0x22, 0xd6, 0xd1, 0x20, 0xae, 0xdd, 0x21, - ], - [ - 0x29, 0x55, 0xa4, 0x5f, 0x41, 0x6f, 0x10, 0xd6, 0xbc, 0x79, 0xac, 0x94, - 0xd0, 0xc0, 0x69, 0xc9, 0x49, 0xe5, 0xf4, 0xbd, 0x09, 0x48, 0x1e, 0x1f, - 0x36, 0x8c, 0xb9, 0xb8, 0xee, 0x51, 0x14, 0x0d, - ], - [ - 0x0d, 0x83, 0x76, 0xbb, 0xe9, 0xd6, 0x5d, 0x2b, 0x1e, 0x13, 0x6f, 0xb7, - 0xd9, 0x82, 0xab, 0x87, 0xc5, 0x1c, 0x40, 0x30, 0x44, 0xbe, 0x5c, 0x79, - 0x9d, 0x56, 0xbb, 0x68, 0xac, 0xf9, 0x5b, 0x10, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0xbc, 0x50, 0x98, 0x42, 0x55, 0xd6, 0xaf, 0xbe, 0x9e, 0xf9, 0x28, 0x48, - 0xed, 0x5a, 0xc0, 0x08, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, 0xbc, 0xb6, - 0x4b, 0x69, 0x68, 0x91, 0x2a, 0x63, 0x81, 0x0e, - ], - [ - 0x3d, 0xc1, 0x66, 0xd5, 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x55, 0x1d, - 0xb5, 0xfd, 0x93, 0x13, 0xe8, 0xc7, 0x20, 0x3d, 0x99, 0x6a, 0xf7, 0xd4, - 0x77, 0x08, 0x37, 0x56, 0xd5, 0x9a, 0xf8, 0x0d, - ], - [ - 0x05, 0xa7, 0x45, 0xf4, 0x5d, 0x7f, 0xf6, 0xdb, 0x10, 0xbc, 0x67, 0xfd, - 0xf0, 0xf0, 0x3e, 0xbf, 0x81, 0x30, 0xab, 0x33, 0x36, 0x26, 0x97, 0xb0, - 0xe4, 0xe4, 0xc7, 0x63, 0xcc, 0xb8, 0xf6, 0x36, - ], - ], - final_state: [ - [ - 0x0b, 0x77, 0xec, 0x53, 0x07, 0x14, 0x5a, 0x0c, 0x05, 0x2d, 0xc7, 0xa9, - 0xd6, 0xf9, 0x6a, 0xc3, 0x41, 0xae, 0x72, 0x64, 0x08, 0x32, 0xd5, 0x8e, - 0x51, 0xeb, 0x92, 0xa4, 0x17, 0x80, 0x17, 0x12, - ], - [ - 0x3b, 0x52, 0x3f, 0x44, 0xf0, 0x0e, 0x46, 0x3f, 0x8b, 0x0f, 0xd7, 0xd4, - 0xfc, 0x0e, 0x28, 0x0c, 0xdb, 0xde, 0xb9, 0x27, 0xf1, 0x81, 0x68, 0x07, - 0x7b, 0xb3, 0x62, 0xf2, 0x67, 0x5a, 0x2e, 0x18, - ], - [ - 0x95, 0x7a, 0x97, 0x06, 0xff, 0xcc, 0x35, 0x15, 0x64, 0xae, 0x80, 0x2a, - 0x99, 0x11, 0x31, 0x4c, 0x05, 0xe2, 0x3e, 0x22, 0xaf, 0xcf, 0x83, 0x40, - 0x59, 0xdf, 0x80, 0xfa, 0xc1, 0x05, 0x76, 0x26, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, 0xfa, 0x3d, 0x5a, - 0x57, 0xef, 0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, 0xfb, - 0x1a, 0x38, 0xe0, 0x1d, 0x94, 0x90, 0x3d, 0x3c, - ], - [ - 0x3d, 0x0a, 0xd3, 0x36, 0x1f, 0xec, 0x09, 0x77, 0x90, 0xd9, 0xbe, 0x0e, - 0x42, 0x98, 0x8d, 0x7d, 0x25, 0xc9, 0xa1, 0x38, 0xf4, 0x9b, 0x1a, 0x53, - 0x7e, 0xdc, 0xf0, 0x4b, 0xe3, 0x4a, 0x98, 0x11, - ], - [ - 0xa4, 0xaf, 0x9d, 0xb6, 0xd2, 0x7b, 0x50, 0x72, 0x83, 0x5f, 0x0c, 0x3e, - 0x88, 0x39, 0x5e, 0xd7, 0xa4, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, - 0xb9, 0xda, 0x94, 0x8d, 0x32, 0x0d, 0xad, 0x16, - ], - ], - final_state: [ - [ - 0x67, 0x80, 0x08, 0x3f, 0x7f, 0x82, 0xcb, 0x42, 0x54, 0xe7, 0xb6, 0x6f, - 0x4b, 0x83, 0x84, 0x6a, 0xc9, 0x77, 0x3f, 0xb9, 0xc3, 0x9c, 0x6e, 0xc9, - 0x81, 0x8b, 0x06, 0x22, 0x23, 0x09, 0x55, 0x2a, - ], - [ - 0xa5, 0xf9, 0xa5, 0x7e, 0x2c, 0x40, 0xb1, 0x58, 0xd8, 0x16, 0x53, 0x43, - 0xe6, 0x02, 0x65, 0x2c, 0x3e, 0xfc, 0x0b, 0x64, 0xdd, 0xca, 0xee, 0xe5, - 0xce, 0x3d, 0x95, 0x1f, 0xd5, 0x9f, 0x50, 0x08, - ], - [ - 0xdc, 0xa4, 0x64, 0x36, 0x12, 0x7c, 0x47, 0x7e, 0x83, 0x95, 0x0f, 0xa0, - 0x7c, 0xc6, 0x8a, 0x56, 0x6e, 0x54, 0x18, 0x55, 0xad, 0xc2, 0x68, 0x52, - 0x97, 0x87, 0x35, 0x24, 0x88, 0x92, 0x1e, 0x3b, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x4d, 0x54, 0x31, 0xe6, 0x43, 0x7d, 0x0b, 0x5b, 0xed, 0xbb, 0xcd, 0xaf, - 0x34, 0x5b, 0x86, 0xc4, 0x12, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, - 0x42, 0x76, 0xd3, 0x8d, 0x47, 0xf1, 0xe1, 0x11, - ], - [ - 0xdd, 0x0c, 0x7a, 0x1d, 0x81, 0x1c, 0x7d, 0x9c, 0xd4, 0x6d, 0x37, 0x7b, - 0x3f, 0xde, 0xab, 0x3f, 0xb6, 0x79, 0xf3, 0xdc, 0x60, 0x1d, 0x00, 0x82, - 0x85, 0xed, 0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0x3c, - ], - [ - 0x19, 0xe4, 0xaa, 0xc0, 0x35, 0x90, 0x17, 0xec, 0x85, 0xa1, 0x83, 0xd2, - 0x20, 0x53, 0xdb, 0x33, 0xf7, 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, - 0x37, 0x83, 0x65, 0xc8, 0xf7, 0x39, 0x3c, 0x14, - ], - ], - final_state: [ - [ - 0x89, 0x99, 0x8e, 0x5e, 0x0f, 0xa1, 0x95, 0x2a, 0x40, 0xb8, 0xb5, 0x2b, - 0x62, 0xd9, 0x45, 0x70, 0xa4, 0x9a, 0x7d, 0x91, 0xdd, 0x22, 0x6d, 0x69, - 0x2b, 0xc9, 0xb1, 0xa6, 0x13, 0xc9, 0x08, 0x30, - ], - [ - 0xd0, 0xee, 0x44, 0xd9, 0xa9, 0x0d, 0x90, 0x79, 0xef, 0xfb, 0x24, 0x86, - 0xd3, 0xd8, 0x4d, 0x1a, 0x18, 0x4e, 0xdf, 0x14, 0x97, 0x0b, 0xac, 0x36, - 0xc7, 0x48, 0x04, 0xc7, 0xff, 0xbe, 0xe5, 0x0b, - ], - [ - 0x04, 0x81, 0x45, 0xa6, 0x61, 0xce, 0x78, 0x7c, 0x7e, 0x12, 0x2a, 0xc6, - 0x44, 0x7e, 0x9b, 0xa3, 0x93, 0xd3, 0x67, 0xac, 0x05, 0x4f, 0xaa, 0xc5, - 0xb7, 0xb5, 0xf7, 0x19, 0x2b, 0x2f, 0xde, 0x21, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, - 0x79, 0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, - 0x32, 0xb4, 0xf4, 0x73, 0xf4, 0x68, 0xa0, 0x08, - ], - [ - 0xe6, 0x23, 0x89, 0xfc, 0x16, 0x57, 0xe0, 0xde, 0xf0, 0xb6, 0x32, 0xc6, - 0xae, 0x25, 0xf9, 0xf7, 0x83, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, 0x15, 0x3d, - 0x88, 0x2d, 0x2b, 0x21, 0x03, 0x59, 0x65, 0x15, - ], - [ - 0xeb, 0x94, 0x94, 0xc6, 0xd2, 0x27, 0xe2, 0x16, 0x3b, 0x46, 0x99, 0xd9, - 0x91, 0xf4, 0x33, 0xbf, 0x94, 0x86, 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, - 0x73, 0x1e, 0x98, 0x5d, 0x99, 0x58, 0x9c, 0x0b, - ], - ], - final_state: [ - [ - 0xce, 0x2d, 0x1f, 0x8d, 0x67, 0x7f, 0xfb, 0xfd, 0x73, 0xb2, 0x35, 0xe8, - 0xc6, 0x87, 0xfb, 0x42, 0x18, 0x7f, 0x78, 0x81, 0xc3, 0xce, 0x9c, 0x79, - 0x4f, 0x2b, 0xd4, 0x61, 0x40, 0xf7, 0xcc, 0x2a, - ], - [ - 0xaf, 0x82, 0x92, 0x39, 0xb6, 0xd5, 0x5d, 0x5f, 0x43, 0xec, 0x6f, 0x32, - 0xb8, 0x4a, 0x2a, 0x01, 0x1e, 0x64, 0xc5, 0x74, 0x73, 0x9f, 0x87, 0xcb, - 0x47, 0xdc, 0x70, 0x23, 0x83, 0xfa, 0x5a, 0x34, - ], - [ - 0x03, 0xd1, 0x08, 0x5b, 0x21, 0x4c, 0x69, 0xb8, 0xbf, 0xe8, 0x91, 0x02, - 0xbd, 0x61, 0x7e, 0xce, 0x0c, 0x54, 0x00, 0x17, 0x96, 0x40, 0x41, 0x05, - 0xc5, 0x33, 0x30, 0xd2, 0x49, 0x58, 0x1d, 0x0f, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0xb7, 0x38, 0xe8, 0xaa, 0x0a, 0x15, 0x26, 0xa5, 0xbd, 0xef, 0x61, 0x31, - 0x20, 0x37, 0x2e, 0x83, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, - 0xeb, 0xbc, 0x86, 0x2d, 0xed, 0x42, 0x43, 0x1e, - ], - [ - 0x91, 0x47, 0x69, 0x30, 0xe3, 0x38, 0x5c, 0xd3, 0xe3, 0x37, 0x9e, 0x38, - 0x53, 0xd9, 0x34, 0x67, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, - 0x6d, 0x75, 0xa4, 0xa6, 0xf2, 0x65, 0x72, 0x10, - ], - [ - 0x4b, 0x19, 0x22, 0x32, 0xec, 0xb9, 0xf0, 0xc0, 0x24, 0x11, 0xe5, 0x25, - 0x96, 0xbc, 0x5e, 0x90, 0x45, 0x7e, 0x74, 0x59, 0x39, 0xff, 0xed, 0xbd, - 0x12, 0x86, 0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11, - ], - ], - final_state: [ - [ - 0x5f, 0xcc, 0xd8, 0x7d, 0x2f, 0x66, 0x7b, 0x9e, 0xe3, 0x88, 0xf3, 0x4c, - 0x1c, 0x71, 0x06, 0x87, 0x12, 0x7b, 0xff, 0x5b, 0x02, 0x21, 0xfd, 0x8a, - 0x52, 0x94, 0x88, 0x66, 0x91, 0x57, 0x94, 0x2b, - ], - [ - 0x89, 0x62, 0xb5, 0x80, 0x30, 0xaa, 0x63, 0x52, 0xd9, 0x90, 0xf3, 0xb9, - 0x00, 0x1c, 0xcb, 0xe8, 0x8a, 0x56, 0x27, 0x58, 0x1b, 0xbf, 0xb9, 0x01, - 0xac, 0x4a, 0x6a, 0xed, 0xfa, 0xe5, 0xc6, 0x34, - ], - [ - 0x7c, 0x0b, 0x76, 0x59, 0xf2, 0x4c, 0x98, 0xaf, 0x31, 0x0e, 0x3e, 0x8d, - 0x82, 0xb5, 0xf3, 0x99, 0x43, 0x3c, 0xdd, 0xa5, 0x8f, 0x48, 0xd9, 0xef, - 0x8d, 0xd0, 0xca, 0x86, 0x42, 0x72, 0xda, 0x3f, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x7b, 0x41, 0x7a, 0xdb, 0x63, 0xb3, 0x71, 0x22, 0xa5, 0xbf, 0x62, 0xd2, - 0x6f, 0x1e, 0x7f, 0x26, 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, - 0x82, 0x85, 0x7d, 0xee, 0xcc, 0x40, 0xa9, 0x0d, - ], - [ - 0x5e, 0x29, 0x35, 0x39, 0x71, 0xb3, 0x49, 0x94, 0xb6, 0x21, 0xb0, 0xb2, - 0x61, 0xae, 0xb3, 0x78, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, - 0xb9, 0x27, 0xb7, 0xfa, 0xe2, 0xdb, 0x58, 0x31, - ], - [ - 0x05, 0x41, 0x5d, 0x46, 0x42, 0x78, 0x9d, 0x38, 0xf5, 0x0b, 0x8d, 0xbc, - 0xc1, 0x29, 0xca, 0xb3, 0xd1, 0x7d, 0x19, 0xf3, 0x35, 0x5b, 0xcf, 0x73, - 0xce, 0xcb, 0x8c, 0xb8, 0xa5, 0xda, 0x01, 0x30, - ], - ], - final_state: [ - [ - 0x9e, 0xe1, 0xad, 0xdc, 0x6f, 0x64, 0xda, 0xb6, 0xac, 0xdc, 0xea, 0xec, - 0xc1, 0xfb, 0xbc, 0x8a, 0x32, 0x45, 0x8e, 0x49, 0xc1, 0x9e, 0x79, 0x85, - 0x56, 0xc6, 0x4b, 0x59, 0x8b, 0xa6, 0xff, 0x14, - ], - [ - 0x42, 0xcc, 0x10, 0x36, 0x4f, 0xd6, 0x59, 0xc3, 0xcc, 0x77, 0x25, 0x84, - 0xdb, 0x91, 0xc4, 0x9a, 0x38, 0x67, 0x2b, 0x69, 0x24, 0x93, 0xb9, 0x07, - 0x5f, 0x16, 0x53, 0xca, 0x1f, 0xae, 0x1c, 0x33, - ], - [ - 0xff, 0x41, 0xf3, 0x51, 0x80, 0x14, 0x56, 0xc4, 0x96, 0x0b, 0x39, 0x3a, - 0xff, 0xa8, 0x62, 0x13, 0xa7, 0xea, 0xc0, 0x6c, 0x66, 0x21, 0x3b, 0x45, - 0xc3, 0xb5, 0x0e, 0xc6, 0x48, 0xd6, 0x7d, 0x0d, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x71, 0x52, 0xf1, 0x39, 0x36, 0xa2, 0x70, 0x57, 0x26, 0x70, 0xdc, 0x82, - 0xd3, 0x90, 0x26, 0xc6, 0xcb, 0x4c, 0xd4, 0xb0, 0xf7, 0xf5, 0xaa, 0x2a, - 0x4f, 0x5a, 0x53, 0x41, 0xec, 0x5d, 0xd7, 0x15, - ], - [ - 0x40, 0x6f, 0x2f, 0xdd, 0x2a, 0xfa, 0x73, 0x3f, 0x5f, 0x64, 0x1c, 0x8c, - 0x21, 0x86, 0x2a, 0x1b, 0xaf, 0xce, 0x26, 0x09, 0xd9, 0xee, 0xcf, 0xa1, - 0x58, 0xcf, 0xb5, 0xcd, 0x79, 0xf8, 0x80, 0x08, - ], - [ - 0xe2, 0x15, 0xdc, 0x7d, 0x96, 0x57, 0xba, 0xd3, 0xfb, 0x88, 0xb0, 0x1e, - 0x99, 0x38, 0x44, 0x54, 0x36, 0x24, 0xc2, 0x5f, 0xa9, 0x59, 0xcc, 0x97, - 0x48, 0x9c, 0xe7, 0x57, 0x45, 0x82, 0x4b, 0x37, - ], - ], - final_state: [ - [ - 0x63, 0x09, 0x15, 0xd7, 0xd8, 0x25, 0xeb, 0x74, 0x37, 0xb0, 0xe4, 0x6e, - 0x37, 0x28, 0x6a, 0x88, 0xb3, 0x89, 0xdc, 0x69, 0x85, 0x93, 0x07, 0x11, - 0x6d, 0x34, 0x7b, 0x98, 0xca, 0x14, 0x5c, 0x31, - ], - [ - 0xaa, 0x58, 0x1b, 0xae, 0xe9, 0x4f, 0xb5, 0x46, 0xa7, 0x61, 0xf1, 0x7a, - 0x5d, 0x6e, 0xaa, 0x70, 0x29, 0x52, 0x78, 0x42, 0xf3, 0x1c, 0x39, 0x87, - 0xb8, 0x68, 0xed, 0x7d, 0xaf, 0xfd, 0xb5, 0x34, - ], - [ - 0x7d, 0xc1, 0x17, 0xb3, 0x39, 0x1a, 0xab, 0x85, 0xde, 0x9f, 0x42, 0x4d, - 0xb6, 0x65, 0x1e, 0x00, 0x45, 0xab, 0x79, 0x98, 0xf2, 0x8e, 0x54, 0x10, - 0x15, 0x35, 0x90, 0x61, 0x99, 0xce, 0x1f, 0x1a, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x86, 0x8c, 0x53, 0x23, 0x9c, 0xfb, 0xdf, 0x73, 0xca, 0xec, 0x65, 0x60, - 0x40, 0x37, 0x31, 0x4f, 0xaa, 0xce, 0xb5, 0x62, 0x18, 0xc6, 0xbd, 0x30, - 0xf8, 0x37, 0x4a, 0xc1, 0x33, 0x86, 0x79, 0x3f, - ], - [ - 0x21, 0xa9, 0xfb, 0x80, 0xad, 0x03, 0xbc, 0x0c, 0xda, 0x4a, 0x44, 0x94, - 0x6c, 0x00, 0xe1, 0xb1, 0xa1, 0xdf, 0x0e, 0x5b, 0x87, 0xb5, 0xbe, 0xce, - 0x47, 0x7a, 0x70, 0x96, 0x49, 0xe9, 0x50, 0x06, - ], - [ - 0x04, 0x91, 0x39, 0x48, 0x25, 0x64, 0xf1, 0x85, 0xc7, 0x90, 0x0e, 0x83, - 0xc7, 0x38, 0x07, 0x0a, 0xf6, 0x55, 0x6d, 0xf6, 0xed, 0x4b, 0x4d, 0xdd, - 0x3d, 0x9a, 0x69, 0xf5, 0x33, 0x57, 0xd7, 0x36, - ], - ], - final_state: [ - [ - 0x6a, 0x5a, 0x19, 0x19, 0xa4, 0x49, 0xa5, 0xe0, 0x29, 0x71, 0x1f, 0x48, - 0x8a, 0xdb, 0xd6, 0xb0, 0x3e, 0x5c, 0x92, 0x7b, 0x6f, 0x9d, 0x9d, 0x35, - 0xc5, 0xb3, 0xcc, 0xeb, 0x76, 0x60, 0x52, 0x03, - ], - [ - 0x80, 0x47, 0x5b, 0x46, 0x89, 0x59, 0x61, 0x47, 0xab, 0x2a, 0xdf, 0x01, - 0x73, 0xdb, 0x28, 0x9b, 0x3a, 0x26, 0xa1, 0x04, 0x84, 0x21, 0x73, 0xe8, - 0x8b, 0xdb, 0xfe, 0xc0, 0x4a, 0x28, 0x67, 0x1b, - ], - [ - 0x1e, 0xf3, 0xc8, 0xd0, 0xf5, 0x44, 0x44, 0xf5, 0x55, 0xb1, 0x5f, 0x7b, - 0xc9, 0xfa, 0x4f, 0xfa, 0x0f, 0x56, 0x7c, 0x0f, 0x19, 0xac, 0x7d, 0x0f, - 0xf9, 0x44, 0xfd, 0x36, 0x42, 0x6e, 0x32, 0x3a, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x7d, 0x4f, 0x5c, 0xcb, 0x01, 0x64, 0x3c, 0x31, 0xdb, 0x84, 0x5e, 0xec, - 0xd5, 0xd6, 0x3d, 0xc1, 0x6a, 0x95, 0xe3, 0x02, 0x5b, 0x97, 0x92, 0xff, - 0xf7, 0xf2, 0x44, 0xfc, 0x71, 0x62, 0x69, 0x39, - ], - [ - 0x26, 0xd6, 0x2e, 0x95, 0x96, 0xfa, 0x82, 0x5c, 0x6b, 0xf2, 0x1a, 0xff, - 0x9e, 0x68, 0x62, 0x5a, 0x19, 0x24, 0x40, 0xea, 0x06, 0x82, 0x81, 0x23, - 0xd9, 0x78, 0x84, 0x80, 0x6f, 0x15, 0xfa, 0x08, - ], - [ - 0xd9, 0x52, 0x75, 0x4a, 0x23, 0x64, 0xb6, 0x66, 0xff, 0xc3, 0x0f, 0xdb, - 0x01, 0x47, 0x86, 0xda, 0x3a, 0x61, 0x28, 0xae, 0xf7, 0x84, 0xa6, 0x46, - 0x10, 0xa8, 0x9d, 0x1a, 0x70, 0x99, 0x21, 0x2d, - ], - ], - final_state: [ - [ - 0x1b, 0x4a, 0xc9, 0xbe, 0xf5, 0x6b, 0xdb, 0x6f, 0xb4, 0x2d, 0x3e, 0x3c, - 0xd3, 0xa2, 0xac, 0x70, 0xa4, 0xc4, 0x0c, 0x42, 0x5b, 0x0b, 0xd6, 0x67, - 0x9c, 0xa5, 0x7b, 0x30, 0x7e, 0xf1, 0xd4, 0x2f, - ], - [ - 0x1a, 0x2e, 0xf4, 0x11, 0x94, 0xaa, 0xa2, 0x34, 0x32, 0xe0, 0x86, 0xed, - 0x8a, 0xdb, 0xd1, 0xde, 0xec, 0x3c, 0x7c, 0xb3, 0x96, 0xde, 0x35, 0xba, - 0xe9, 0x5a, 0xaf, 0x5a, 0x08, 0xa0, 0xec, 0x36, - ], - [ - 0x68, 0xeb, 0x80, 0xc7, 0x3e, 0x2c, 0xcb, 0xde, 0xe1, 0xba, 0x71, 0x24, - 0x77, 0x61, 0xd5, 0xb5, 0xec, 0xc6, 0x20, 0xe6, 0xe4, 0x8e, 0x00, 0x3b, - 0x02, 0x3d, 0x9f, 0x55, 0x61, 0x66, 0x2f, 0x20, - ], - ], - }, - ] - } - - pub(crate) fn hash() -> Vec { - use HashTestVector as TestVector; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/orchard_poseidon/hash/fp.py - vec![ - TestVector { - input: [ - [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - [ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - ], - output: [ - 0x83, 0x58, 0xd7, 0x11, 0xa0, 0x32, 0x9d, 0x38, 0xbe, 0xcd, 0x54, 0xfb, 0xa7, - 0xc2, 0x83, 0xed, 0x3e, 0x08, 0x9a, 0x39, 0xc9, 0x1b, 0x6a, 0x9d, 0x10, 0xef, - 0xb0, 0x2b, 0xc3, 0xf1, 0x2f, 0x06, - ], - }, - TestVector { - input: [ - [ - 0x5c, 0x7a, 0x8f, 0x73, 0xad, 0xfc, 0x70, 0xfb, 0x3f, 0x13, 0x94, 0x49, - 0xac, 0x6b, 0x57, 0x07, 0x4c, 0x4d, 0x6e, 0x66, 0xb1, 0x64, 0x93, 0x9d, - 0xaf, 0xfa, 0x2e, 0xf6, 0xee, 0x69, 0x21, 0x08, - ], - [ - 0x1a, 0xdd, 0x86, 0xb3, 0xf2, 0xe1, 0xbd, 0xa6, 0x2a, 0x5d, 0x2e, 0x0e, - 0x98, 0x2b, 0x77, 0xe6, 0xb0, 0xef, 0x9c, 0xa3, 0xf2, 0x49, 0x88, 0xc7, - 0xb3, 0x53, 0x42, 0x01, 0xcf, 0xb1, 0xcd, 0x0d, - ], - ], - output: [ - 0xdb, 0x26, 0x75, 0xff, 0x3e, 0xf8, 0xfe, 0x30, 0xc4, 0xd5, 0xde, 0x61, 0xca, - 0xc0, 0x2a, 0x8e, 0xf1, 0xa0, 0x85, 0x23, 0xbe, 0x92, 0x39, 0x4b, 0x79, 0xd2, - 0x67, 0x26, 0x30, 0x3b, 0xe6, 0x03, - ], - }, - TestVector { - input: [ - [ - 0xbd, 0x69, 0xb8, 0x25, 0x32, 0xb6, 0x94, 0x0f, 0xf2, 0x59, 0x0f, 0x67, - 0x9b, 0xa9, 0xc7, 0x27, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, - 0xa5, 0xe2, 0x9d, 0x4e, 0x30, 0xa7, 0x35, 0x14, - ], - [ - 0xbc, 0x50, 0x98, 0x42, 0x55, 0xd6, 0xaf, 0xbe, 0x9e, 0xf9, 0x28, 0x48, - 0xed, 0x5a, 0xc0, 0x08, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, 0xbc, 0xb6, - 0x4b, 0x69, 0x68, 0x91, 0x2a, 0x63, 0x81, 0x0e, - ], - ], - output: [ - 0xf5, 0x12, 0x1d, 0x1e, 0x1d, 0x5c, 0xfe, 0x8d, 0xa8, 0x96, 0xac, 0x0f, 0x9c, - 0x18, 0x3d, 0x76, 0x00, 0x31, 0xf6, 0xef, 0x8c, 0x7a, 0x41, 0xe6, 0x5e, 0xb0, - 0x07, 0xcd, 0xdc, 0x1d, 0x14, 0x3d, - ], - }, - TestVector { - input: [ - [ - 0x3d, 0xc1, 0x66, 0xd5, 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x55, 0x1d, - 0xb5, 0xfd, 0x93, 0x13, 0xe8, 0xc7, 0x20, 0x3d, 0x99, 0x6a, 0xf7, 0xd4, - 0x77, 0x08, 0x37, 0x56, 0xd5, 0x9a, 0xf8, 0x0d, - ], - [ - 0x05, 0xa7, 0x45, 0xf4, 0x5d, 0x7f, 0xf6, 0xdb, 0x10, 0xbc, 0x67, 0xfd, - 0xf0, 0xf0, 0x3e, 0xbf, 0x81, 0x30, 0xab, 0x33, 0x36, 0x26, 0x97, 0xb0, - 0xe4, 0xe4, 0xc7, 0x63, 0xcc, 0xb8, 0xf6, 0x36, - ], - ], - output: [ - 0xa4, 0x16, 0xa5, 0xe7, 0x13, 0x51, 0x36, 0xa0, 0x50, 0x56, 0x90, 0x00, 0x58, - 0xfa, 0x50, 0xbf, 0x18, 0x6a, 0xd7, 0x33, 0x90, 0xac, 0xe6, 0x32, 0x3d, 0x8d, - 0x81, 0xaa, 0x8a, 0xdb, 0xd4, 0x11, - ], - }, - TestVector { - input: [ - [ - 0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, 0xfa, 0x3d, 0x5a, - 0x57, 0xef, 0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, 0xfb, - 0x1a, 0x38, 0xe0, 0x1d, 0x94, 0x90, 0x3d, 0x3c, - ], - [ - 0x3d, 0x0a, 0xd3, 0x36, 0x1f, 0xec, 0x09, 0x77, 0x90, 0xd9, 0xbe, 0x0e, - 0x42, 0x98, 0x8d, 0x7d, 0x25, 0xc9, 0xa1, 0x38, 0xf4, 0x9b, 0x1a, 0x53, - 0x7e, 0xdc, 0xf0, 0x4b, 0xe3, 0x4a, 0x98, 0x11, - ], - ], - output: [ - 0x1a, 0xba, 0xf3, 0x06, 0xfe, 0xd0, 0x5f, 0xa8, 0x92, 0x84, 0x8c, 0x49, 0xf6, - 0xba, 0x10, 0x41, 0x63, 0x43, 0x3f, 0x3f, 0x63, 0x31, 0x08, 0xa1, 0x3b, 0xc1, - 0x5b, 0x2a, 0x1d, 0x55, 0xd4, 0x0c, - ], - }, - TestVector { - input: [ - [ - 0xa4, 0xaf, 0x9d, 0xb6, 0xd2, 0x7b, 0x50, 0x72, 0x83, 0x5f, 0x0c, 0x3e, - 0x88, 0x39, 0x5e, 0xd7, 0xa4, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, - 0xb9, 0xda, 0x94, 0x8d, 0x32, 0x0d, 0xad, 0x16, - ], - [ - 0x4d, 0x54, 0x31, 0xe6, 0x43, 0x7d, 0x0b, 0x5b, 0xed, 0xbb, 0xcd, 0xaf, - 0x34, 0x5b, 0x86, 0xc4, 0x12, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, - 0x42, 0x76, 0xd3, 0x8d, 0x47, 0xf1, 0xe1, 0x11, - ], - ], - output: [ - 0x04, 0xa1, 0x8a, 0xeb, 0x59, 0x3f, 0x79, 0x0b, 0x76, 0xa3, 0x99, 0xb7, 0xc1, - 0x52, 0x8a, 0xcd, 0xed, 0xe9, 0x3b, 0x3b, 0x2c, 0x49, 0x6b, 0xd7, 0x1b, 0xd5, - 0x87, 0xcb, 0xd7, 0xcf, 0xdf, 0x35, - ], - }, - TestVector { - input: [ - [ - 0xdd, 0x0c, 0x7a, 0x1d, 0x81, 0x1c, 0x7d, 0x9c, 0xd4, 0x6d, 0x37, 0x7b, - 0x3f, 0xde, 0xab, 0x3f, 0xb6, 0x79, 0xf3, 0xdc, 0x60, 0x1d, 0x00, 0x82, - 0x85, 0xed, 0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0x3c, - ], - [ - 0x19, 0xe4, 0xaa, 0xc0, 0x35, 0x90, 0x17, 0xec, 0x85, 0xa1, 0x83, 0xd2, - 0x20, 0x53, 0xdb, 0x33, 0xf7, 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, - 0x37, 0x83, 0x65, 0xc8, 0xf7, 0x39, 0x3c, 0x14, - ], - ], - output: [ - 0x11, 0x03, 0xcc, 0xdc, 0x00, 0xd0, 0xf3, 0x5f, 0x65, 0x83, 0x14, 0x11, 0x6b, - 0xc2, 0xbc, 0xd9, 0x43, 0x74, 0xa9, 0x1f, 0xf9, 0x87, 0x7e, 0x70, 0x66, 0x33, - 0x29, 0x04, 0x2b, 0xd2, 0xf6, 0x1f, - ], - }, - TestVector { - input: [ - [ - 0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, - 0x79, 0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, - 0x32, 0xb4, 0xf4, 0x73, 0xf4, 0x68, 0xa0, 0x08, - ], - [ - 0xe6, 0x23, 0x89, 0xfc, 0x16, 0x57, 0xe0, 0xde, 0xf0, 0xb6, 0x32, 0xc6, - 0xae, 0x25, 0xf9, 0xf7, 0x83, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, 0x15, 0x3d, - 0x88, 0x2d, 0x2b, 0x21, 0x03, 0x59, 0x65, 0x15, - ], - ], - output: [ - 0xf8, 0xf8, 0xc6, 0x5f, 0x43, 0x7c, 0x45, 0xbe, 0xac, 0x11, 0xeb, 0x7d, 0x9e, - 0x47, 0x58, 0x6d, 0x87, 0x9a, 0xfd, 0x6f, 0x93, 0x04, 0x35, 0xbe, 0x0c, 0x01, - 0xd1, 0x9c, 0x89, 0x5b, 0x8d, 0x10, - ], - }, - TestVector { - input: [ - [ - 0xeb, 0x94, 0x94, 0xc6, 0xd2, 0x27, 0xe2, 0x16, 0x3b, 0x46, 0x99, 0xd9, - 0x91, 0xf4, 0x33, 0xbf, 0x94, 0x86, 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, - 0x73, 0x1e, 0x98, 0x5d, 0x99, 0x58, 0x9c, 0x0b, - ], - [ - 0xb7, 0x38, 0xe8, 0xaa, 0x0a, 0x15, 0x26, 0xa5, 0xbd, 0xef, 0x61, 0x31, - 0x20, 0x37, 0x2e, 0x83, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, - 0xeb, 0xbc, 0x86, 0x2d, 0xed, 0x42, 0x43, 0x1e, - ], - ], - output: [ - 0x5a, 0xeb, 0x48, 0x96, 0x21, 0xb0, 0x2e, 0x8e, 0x69, 0x27, 0xb9, 0x4f, 0xd2, - 0x9a, 0x61, 0x01, 0x83, 0xdf, 0x7f, 0x42, 0x87, 0xe9, 0xcb, 0xf1, 0xcc, 0xc8, - 0x81, 0xd7, 0xd0, 0xb7, 0x38, 0x27, - ], - }, - TestVector { - input: [ - [ - 0x91, 0x47, 0x69, 0x30, 0xe3, 0x38, 0x5c, 0xd3, 0xe3, 0x37, 0x9e, 0x38, - 0x53, 0xd9, 0x34, 0x67, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, - 0x6d, 0x75, 0xa4, 0xa6, 0xf2, 0x65, 0x72, 0x10, - ], - [ - 0x4b, 0x19, 0x22, 0x32, 0xec, 0xb9, 0xf0, 0xc0, 0x24, 0x11, 0xe5, 0x25, - 0x96, 0xbc, 0x5e, 0x90, 0x45, 0x7e, 0x74, 0x59, 0x39, 0xff, 0xed, 0xbd, - 0x12, 0x86, 0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11, - ], - ], - output: [ - 0xb0, 0x14, 0x47, 0x20, 0xf5, 0xf2, 0xa2, 0x5d, 0x49, 0x2a, 0x50, 0x4e, 0xc0, - 0x73, 0x7f, 0x09, 0x7e, 0xd8, 0x52, 0x17, 0x4f, 0x55, 0xf5, 0x86, 0x30, 0x91, - 0x30, 0x6c, 0x1a, 0xf2, 0x00, 0x35, - ], - }, - TestVector { - input: [ - [ - 0x7b, 0x41, 0x7a, 0xdb, 0x63, 0xb3, 0x71, 0x22, 0xa5, 0xbf, 0x62, 0xd2, - 0x6f, 0x1e, 0x7f, 0x26, 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, - 0x82, 0x85, 0x7d, 0xee, 0xcc, 0x40, 0xa9, 0x0d, - ], - [ - 0x5e, 0x29, 0x35, 0x39, 0x71, 0xb3, 0x49, 0x94, 0xb6, 0x21, 0xb0, 0xb2, - 0x61, 0xae, 0xb3, 0x78, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, - 0xb9, 0x27, 0xb7, 0xfa, 0xe2, 0xdb, 0x58, 0x31, - ], - ], - output: [ - 0xbb, 0xbe, 0xb7, 0x42, 0xd6, 0xe7, 0xc0, 0x1a, 0xdb, 0xf4, 0xd3, 0x85, 0x5e, - 0x35, 0xfe, 0xc4, 0x62, 0x04, 0x30, 0x89, 0xc1, 0x8b, 0xa8, 0x02, 0x90, 0x64, - 0x7b, 0xb0, 0xe5, 0x81, 0xad, 0x11, - ], - }, - ] - } -} - -pub(crate) mod fq { - use super::*; - - pub(crate) fn permute() -> Vec { - use PermuteTestVector as TestVector; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/orchard_poseidon/permute/fq.py - vec![ - TestVector { - initial_state: [ - [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - [ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - [ - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - ], - final_state: [ - [ - 0x59, 0xbe, 0xbe, 0x13, 0xa8, 0x8e, 0xb0, 0x0e, 0xc6, 0x36, 0xd3, 0x3d, - 0x97, 0xd1, 0x43, 0x4d, 0xf7, 0x2f, 0x8f, 0x2f, 0xf2, 0x74, 0xdd, 0xed, - 0x7c, 0x2f, 0x94, 0xdb, 0x4c, 0x1f, 0x5a, 0x31, - ], - [ - 0xf1, 0x65, 0xa1, 0x1e, 0xe6, 0x26, 0xf1, 0xf9, 0x98, 0x21, 0xbd, 0x7b, - 0xeb, 0xe0, 0x3e, 0x41, 0x48, 0xaa, 0x13, 0xdd, 0xe0, 0xde, 0x2a, 0x64, - 0xde, 0x2b, 0x64, 0xd7, 0xf2, 0x75, 0xe4, 0x3b, - ], - [ - 0xd9, 0xa0, 0x7b, 0x2a, 0x37, 0x42, 0xd5, 0x14, 0xa0, 0x3f, 0x42, 0xe0, - 0xd4, 0xbf, 0x19, 0x50, 0x60, 0xea, 0xd8, 0x20, 0x24, 0xdb, 0x7f, 0x11, - 0x68, 0x71, 0x53, 0xe9, 0xec, 0x8a, 0xab, 0x25, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x5c, 0x7a, 0x8f, 0x73, 0x79, 0x42, 0x57, 0x08, 0x7e, 0x63, 0x4c, 0x49, - 0xac, 0x6b, 0x57, 0x07, 0x4c, 0x4d, 0x6e, 0x66, 0xb1, 0x64, 0x93, 0x9d, - 0xaf, 0xfa, 0x2e, 0xf6, 0xee, 0x69, 0x21, 0x08, - ], - [ - 0x1a, 0xdd, 0x86, 0xb3, 0x8a, 0x6d, 0x8a, 0xc0, 0xa6, 0xfd, 0x9e, 0x0d, - 0x98, 0x2b, 0x77, 0xe6, 0xb0, 0xef, 0x9c, 0xa3, 0xf2, 0x49, 0x88, 0xc7, - 0xb3, 0x53, 0x42, 0x01, 0xcf, 0xb1, 0xcd, 0x0d, - ], - [ - 0xbd, 0x69, 0xb8, 0x25, 0xca, 0x41, 0x61, 0x29, 0x6e, 0xfa, 0x7f, 0x66, - 0x9b, 0xa9, 0xc7, 0x27, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, - 0xa5, 0xe2, 0x9d, 0x4e, 0x30, 0xa7, 0x35, 0x14, - ], - ], - final_state: [ - [ - 0xcd, 0x8f, 0x83, 0x92, 0xdf, 0xc7, 0x72, 0x8f, 0x5f, 0x6d, 0x85, 0x4c, - 0xc4, 0x60, 0x70, 0xa4, 0x0c, 0xba, 0x7a, 0x80, 0x33, 0x2d, 0xdc, 0x65, - 0xcb, 0xe2, 0x4a, 0xc3, 0xde, 0x23, 0x5e, 0x0e, - ], - [ - 0xc2, 0x53, 0xe5, 0x95, 0x3c, 0x83, 0xaa, 0x8a, 0x23, 0xd4, 0xd5, 0x58, - 0x7f, 0xbf, 0xc0, 0x7e, 0x78, 0x33, 0x1f, 0x7d, 0x46, 0xd1, 0xf5, 0xfa, - 0x54, 0x4d, 0x6a, 0xbd, 0xd4, 0x24, 0x1b, 0x27, - ], - [ - 0xb8, 0xc8, 0x33, 0x9b, 0xf9, 0x47, 0x2a, 0xd1, 0xc5, 0x27, 0xb7, 0x5e, - 0x99, 0x81, 0x2c, 0xa9, 0x1c, 0x5c, 0xbd, 0x7f, 0x4d, 0x46, 0x6f, 0x1a, - 0x13, 0x5a, 0x67, 0x50, 0x66, 0x76, 0x64, 0x34, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0xbc, 0x50, 0x98, 0x42, 0xb9, 0xa7, 0x62, 0xe5, 0x58, 0xea, 0x51, 0x47, - 0xed, 0x5a, 0xc0, 0x08, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, 0xbc, 0xb6, - 0x4b, 0x69, 0x68, 0x91, 0x2a, 0x63, 0x81, 0x0e, - ], - [ - 0x3d, 0xc1, 0x66, 0xd5, 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x55, 0x1d, - 0xb5, 0xfd, 0x93, 0x13, 0xe8, 0xc7, 0x20, 0x3d, 0x99, 0x6a, 0xf7, 0xd4, - 0x77, 0x08, 0x37, 0x56, 0xd5, 0x9a, 0xf8, 0x0d, - ], - [ - 0x05, 0xa7, 0x45, 0xf4, 0x29, 0xc5, 0xdc, 0xe8, 0x4e, 0x0c, 0x20, 0xfd, - 0xf0, 0xf0, 0x3e, 0xbf, 0x81, 0x30, 0xab, 0x33, 0x36, 0x26, 0x97, 0xb0, - 0xe4, 0xe4, 0xc7, 0x63, 0xcc, 0xb8, 0xf6, 0x36, - ], - ], - final_state: [ - [ - 0xa3, 0x5b, 0x56, 0x64, 0x62, 0x4a, 0x78, 0x49, 0x9e, 0xce, 0xe0, 0xfa, - 0x05, 0x18, 0x79, 0xa2, 0xad, 0x1c, 0xa4, 0x53, 0x9b, 0x5b, 0xd2, 0xa4, - 0x67, 0xe2, 0xea, 0x8d, 0x4e, 0x2d, 0x40, 0x08, - ], - [ - 0x36, 0xc2, 0x21, 0x7a, 0xe5, 0x75, 0xaa, 0xf8, 0xf2, 0x54, 0xd6, 0xe0, - 0x60, 0x10, 0x1c, 0xdc, 0x85, 0xaa, 0x39, 0x3c, 0x09, 0x54, 0x3b, 0xf0, - 0x48, 0x99, 0x7a, 0x7c, 0x5c, 0xb9, 0x27, 0x02, - ], - [ - 0x38, 0x12, 0x7e, 0xbe, 0xaf, 0x11, 0xae, 0x56, 0x64, 0x47, 0x14, 0x05, - 0x29, 0x3b, 0x60, 0x1c, 0x43, 0xf0, 0x3e, 0x8e, 0x40, 0x78, 0x11, 0x3a, - 0x63, 0x37, 0x10, 0x11, 0x9f, 0x9a, 0x1b, 0x1f, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, 0xfa, 0x3d, 0x5a, - 0x57, 0xef, 0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, 0xfb, - 0x1a, 0x38, 0xe0, 0x1d, 0x94, 0x90, 0x3d, 0x3c, - ], - [ - 0x3d, 0x0a, 0xd3, 0x36, 0xeb, 0x31, 0xf0, 0x83, 0xce, 0x29, 0x77, 0x0e, - 0x42, 0x98, 0x8d, 0x7d, 0x25, 0xc9, 0xa1, 0x38, 0xf4, 0x9b, 0x1a, 0x53, - 0x7e, 0xdc, 0xf0, 0x4b, 0xe3, 0x4a, 0x98, 0x11, - ], - [ - 0xa4, 0xaf, 0x9d, 0xb6, 0x36, 0x4d, 0x03, 0x99, 0x3d, 0x50, 0x35, 0x3d, - 0x88, 0x39, 0x5e, 0xd7, 0xa4, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, - 0xb9, 0xda, 0x94, 0x8d, 0x32, 0x0d, 0xad, 0x16, - ], - ], - final_state: [ - [ - 0x5c, 0x76, 0x63, 0x4f, 0xc7, 0x1a, 0x43, 0x7a, 0x3c, 0xc7, 0x89, 0x9d, - 0xb3, 0xb5, 0x1c, 0xea, 0xe6, 0x9a, 0xd0, 0x0b, 0x14, 0x96, 0xa6, 0x80, - 0x32, 0xd3, 0x83, 0x17, 0x37, 0x08, 0x79, 0x18, - ], - [ - 0xd3, 0xcc, 0x4e, 0xab, 0x45, 0x0a, 0xac, 0xc4, 0x5f, 0x9b, 0x32, 0x7e, - 0xbb, 0x9a, 0x50, 0xb8, 0x59, 0xca, 0x08, 0x0e, 0x10, 0x6b, 0x54, 0xc3, - 0x1c, 0x09, 0xc2, 0x1e, 0x1d, 0x79, 0xdf, 0x2a, - ], - [ - 0x09, 0x1e, 0x8f, 0x1e, 0xe9, 0xba, 0x00, 0xa3, 0xe3, 0xcf, 0x85, 0xd5, - 0xd6, 0x95, 0x3d, 0x25, 0xe0, 0x1e, 0x8b, 0xdb, 0x43, 0xde, 0x0f, 0xb7, - 0x30, 0x82, 0x4e, 0x6a, 0x8f, 0x69, 0x7e, 0x1c, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x4d, 0x54, 0x31, 0xe6, 0xdb, 0x08, 0xd8, 0x74, 0x69, 0x5c, 0x3e, 0xaf, - 0x34, 0x5b, 0x86, 0xc4, 0x12, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, - 0x42, 0x76, 0xd3, 0x8d, 0x47, 0xf1, 0xe1, 0x11, - ], - [ - 0xdd, 0x0c, 0x7a, 0x1d, 0xe5, 0xed, 0x2f, 0xc3, 0x8e, 0x5e, 0x60, 0x7a, - 0x3f, 0xde, 0xab, 0x3f, 0xb6, 0x79, 0xf3, 0xdc, 0x60, 0x1d, 0x00, 0x82, - 0x85, 0xed, 0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0x3c, - ], - [ - 0x19, 0xe4, 0xaa, 0xc0, 0xcd, 0x1b, 0xe4, 0x05, 0x02, 0x42, 0xf4, 0xd1, - 0x20, 0x53, 0xdb, 0x33, 0xf7, 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, - 0x37, 0x83, 0x65, 0xc8, 0xf7, 0x39, 0x3c, 0x14, - ], - ], - final_state: [ - [ - 0x00, 0xff, 0x3c, 0x20, 0xd5, 0xac, 0x28, 0x33, 0xe6, 0xd3, 0x84, 0x27, - 0xd0, 0x44, 0x06, 0x17, 0x9e, 0x31, 0xf3, 0xde, 0xd0, 0xe0, 0x33, 0xab, - 0x4f, 0x51, 0xfc, 0xb4, 0x28, 0xf8, 0x39, 0x1b, - ], - [ - 0x2a, 0x63, 0x7a, 0xa0, 0x4f, 0xb8, 0x0d, 0x9c, 0x50, 0xf3, 0x16, 0xb6, - 0x36, 0x7f, 0xa4, 0xf6, 0xed, 0x52, 0xd0, 0x7c, 0x99, 0xa1, 0x30, 0x29, - 0xd9, 0x3f, 0xae, 0xd3, 0xdd, 0x1e, 0xbc, 0x2f, - ], - [ - 0x12, 0x31, 0x54, 0xbb, 0x87, 0x60, 0x13, 0x94, 0x5f, 0x54, 0x69, 0x34, - 0x9d, 0x5f, 0xc3, 0xfc, 0xfc, 0xc9, 0xd2, 0xda, 0xb8, 0x06, 0x43, 0x0d, - 0x49, 0x69, 0x46, 0xf3, 0xbf, 0x2b, 0x61, 0x11, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, - 0x79, 0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, - 0x32, 0xb4, 0xf4, 0x73, 0xf4, 0x68, 0xa0, 0x08, - ], - [ - 0xe6, 0x23, 0x89, 0xfc, 0xe2, 0x9c, 0xc6, 0xeb, 0x2e, 0x07, 0xeb, 0xc5, - 0xae, 0x25, 0xf9, 0xf7, 0x83, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, 0x15, 0x3d, - 0x88, 0x2d, 0x2b, 0x21, 0x03, 0x59, 0x65, 0x15, - ], - [ - 0xeb, 0x94, 0x94, 0xc6, 0x6a, 0xb3, 0xae, 0x30, 0xb7, 0xe6, 0x09, 0xd9, - 0x91, 0xf4, 0x33, 0xbf, 0x94, 0x86, 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, - 0x73, 0x1e, 0x98, 0x5d, 0x99, 0x58, 0x9c, 0x0b, - ], - ], - final_state: [ - [ - 0xe7, 0x1e, 0xb4, 0x88, 0x51, 0xd7, 0x73, 0xb5, 0xa3, 0xb5, 0xd2, 0xb6, - 0xf6, 0xeb, 0x01, 0xc3, 0x79, 0x3f, 0x2f, 0xeb, 0xdf, 0xd1, 0xb9, 0x53, - 0xf0, 0x6f, 0xa9, 0x59, 0xc7, 0x26, 0xbc, 0x18, - ], - [ - 0x37, 0x71, 0xf8, 0x29, 0xfb, 0xf2, 0x74, 0x87, 0xf1, 0xdf, 0x2b, 0x5e, - 0xe9, 0x94, 0x97, 0x0b, 0x14, 0xd7, 0x13, 0xce, 0xae, 0x73, 0xa6, 0x33, - 0x95, 0x78, 0x4d, 0xcd, 0xf9, 0xaa, 0x30, 0x30, - ], - [ - 0x48, 0x06, 0xaf, 0xf7, 0x5e, 0xd3, 0xc6, 0xb9, 0x72, 0x1b, 0xc5, 0x23, - 0x0d, 0xd7, 0x76, 0xf9, 0x27, 0x44, 0x62, 0x90, 0x97, 0xcf, 0x5c, 0x2b, - 0x7f, 0x14, 0x2c, 0xf2, 0x74, 0xa5, 0x07, 0x37, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0xb7, 0x38, 0xe8, 0xaa, 0xd6, 0x5a, 0x0c, 0xb2, 0xfb, 0x3f, 0x1a, 0x31, - 0x20, 0x37, 0x2e, 0x83, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, - 0xeb, 0xbc, 0x86, 0x2d, 0xed, 0x42, 0x43, 0x1e, - ], - [ - 0x91, 0x47, 0x69, 0x30, 0xaf, 0x7e, 0x42, 0xe0, 0x21, 0x88, 0x56, 0x38, - 0x53, 0xd9, 0x34, 0x67, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, - 0x6d, 0x75, 0xa4, 0xa6, 0xf2, 0x65, 0x72, 0x10, - ], - [ - 0x4b, 0x19, 0x22, 0x32, 0xec, 0xb9, 0xf0, 0xc0, 0x24, 0x11, 0xe5, 0x25, - 0x96, 0xbc, 0x5e, 0x90, 0x45, 0x7e, 0x74, 0x59, 0x39, 0xff, 0xed, 0xbd, - 0x12, 0x86, 0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11, - ], - ], - final_state: [ - [ - 0x9d, 0x58, 0x16, 0x08, 0x94, 0x8a, 0xd0, 0x15, 0xf5, 0x38, 0x82, 0xc0, - 0x2d, 0x22, 0x40, 0x2f, 0x71, 0xbd, 0x52, 0x7a, 0xb6, 0xb0, 0xbd, 0xab, - 0x5e, 0xaf, 0xef, 0x0c, 0xd9, 0x41, 0xe8, 0x33, - ], - [ - 0xf4, 0x69, 0xd9, 0x80, 0x6d, 0x0b, 0x9d, 0x92, 0x46, 0x6b, 0xbd, 0xe4, - 0x90, 0x4b, 0x88, 0x2d, 0x29, 0xcc, 0x45, 0x6d, 0xef, 0xa4, 0x77, 0x3f, - 0x5d, 0x9a, 0x92, 0x79, 0x6c, 0x60, 0xed, 0x1d, - ], - [ - 0x3c, 0xf1, 0xa7, 0x38, 0x35, 0xf9, 0x42, 0x5d, 0x46, 0x87, 0xa0, 0x9b, - 0xea, 0xcf, 0x48, 0x9a, 0xa6, 0x0e, 0xcb, 0xfc, 0xae, 0xa0, 0x61, 0xc9, - 0x7e, 0xd3, 0x72, 0x86, 0x1c, 0x08, 0x0a, 0x3d, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x7b, 0x41, 0x7a, 0xdb, 0xfb, 0x3e, 0x3e, 0x3c, 0x21, 0x60, 0xd3, 0xd1, - 0x6f, 0x1e, 0x7f, 0x26, 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, - 0x82, 0x85, 0x7d, 0xee, 0xcc, 0x40, 0xa9, 0x0d, - ], - [ - 0x5e, 0x29, 0x35, 0x39, 0x3d, 0xf9, 0x2f, 0xa1, 0xf4, 0x71, 0x68, 0xb2, - 0x61, 0xae, 0xb3, 0x78, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, - 0xb9, 0x27, 0xb7, 0xfa, 0xe2, 0xdb, 0x58, 0x31, - ], - [ - 0x05, 0x41, 0x5d, 0x46, 0x42, 0x78, 0x9d, 0x38, 0xf5, 0x0b, 0x8d, 0xbc, - 0xc1, 0x29, 0xca, 0xb3, 0xd1, 0x7d, 0x19, 0xf3, 0x35, 0x5b, 0xcf, 0x73, - 0xce, 0xcb, 0x8c, 0xb8, 0xa5, 0xda, 0x01, 0x30, - ], - ], - final_state: [ - [ - 0x73, 0x2c, 0x01, 0x83, 0x41, 0x7f, 0xdf, 0x33, 0x43, 0xc1, 0xef, 0x69, - 0xfd, 0xf6, 0xb3, 0xe7, 0xfd, 0x52, 0x9e, 0xe8, 0x44, 0x63, 0x48, 0xf2, - 0x78, 0x50, 0x74, 0xaf, 0xe2, 0x97, 0xe5, 0x39, - ], - [ - 0xc0, 0x33, 0xd0, 0x1c, 0xb2, 0x29, 0x7f, 0x14, 0xdc, 0xcf, 0x8a, 0x37, - 0xc8, 0x90, 0x02, 0x09, 0x46, 0x5c, 0xc7, 0x41, 0x24, 0x50, 0xe0, 0xb0, - 0x82, 0x84, 0xf9, 0xaa, 0xa1, 0x18, 0xde, 0x34, - ], - [ - 0x17, 0xf9, 0xa6, 0x65, 0x38, 0x93, 0xea, 0x76, 0xbe, 0x60, 0x00, 0x20, - 0xb8, 0xff, 0xbf, 0xd9, 0x53, 0xae, 0x4a, 0x94, 0xad, 0x00, 0x10, 0x43, - 0x37, 0xb9, 0xf7, 0xde, 0x69, 0x88, 0x60, 0x31, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x71, 0x52, 0xf1, 0x39, 0x36, 0xa2, 0x70, 0x57, 0x26, 0x70, 0xdc, 0x82, - 0xd3, 0x90, 0x26, 0xc6, 0xcb, 0x4c, 0xd4, 0xb0, 0xf7, 0xf5, 0xaa, 0x2a, - 0x4f, 0x5a, 0x53, 0x41, 0xec, 0x5d, 0xd7, 0x15, - ], - [ - 0x40, 0x6f, 0x2f, 0xdd, 0x2a, 0xfa, 0x73, 0x3f, 0x5f, 0x64, 0x1c, 0x8c, - 0x21, 0x86, 0x2a, 0x1b, 0xaf, 0xce, 0x26, 0x09, 0xd9, 0xee, 0xcf, 0xa1, - 0x58, 0xcf, 0xb5, 0xcd, 0x79, 0xf8, 0x80, 0x08, - ], - [ - 0xe2, 0x15, 0xdc, 0x7d, 0x62, 0x9d, 0xa0, 0xe0, 0x39, 0xd9, 0x68, 0x1e, - 0x99, 0x38, 0x44, 0x54, 0x36, 0x24, 0xc2, 0x5f, 0xa9, 0x59, 0xcc, 0x97, - 0x48, 0x9c, 0xe7, 0x57, 0x45, 0x82, 0x4b, 0x37, - ], - ], - final_state: [ - [ - 0x16, 0x0a, 0x24, 0x98, 0x48, 0x62, 0xea, 0xe0, 0xa3, 0x33, 0x50, 0x7b, - 0x36, 0x11, 0x93, 0x13, 0x71, 0xc6, 0x1d, 0x8e, 0x65, 0x71, 0x38, 0xcf, - 0xb2, 0xfa, 0x3b, 0x0f, 0x4d, 0xe5, 0xed, 0x3b, - ], - [ - 0xc5, 0xbd, 0x5a, 0x00, 0x44, 0xb6, 0xdb, 0xfe, 0x88, 0xb6, 0x97, 0xf7, - 0x1e, 0xa0, 0x55, 0xb4, 0xe2, 0x32, 0x42, 0x66, 0x6b, 0xf4, 0xe1, 0xb0, - 0x27, 0x52, 0xee, 0xce, 0x08, 0xfb, 0xe8, 0x05, - ], - [ - 0x30, 0x34, 0xdc, 0x8e, 0x8d, 0x4f, 0x6e, 0x33, 0x53, 0x83, 0xb9, 0x01, - 0x35, 0x8a, 0xe4, 0xb7, 0x5f, 0xcc, 0xc7, 0x22, 0x69, 0xdb, 0x83, 0x37, - 0x89, 0xce, 0xd4, 0xc0, 0xad, 0x83, 0x25, 0x1e, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x86, 0x8c, 0x53, 0x23, 0x9c, 0xfb, 0xdf, 0x73, 0xca, 0xec, 0x65, 0x60, - 0x40, 0x37, 0x31, 0x4f, 0xaa, 0xce, 0xb5, 0x62, 0x18, 0xc6, 0xbd, 0x30, - 0xf8, 0x37, 0x4a, 0xc1, 0x33, 0x86, 0x79, 0x3f, - ], - [ - 0x21, 0xa9, 0xfb, 0x80, 0xad, 0x03, 0xbc, 0x0c, 0xda, 0x4a, 0x44, 0x94, - 0x6c, 0x00, 0xe1, 0xb1, 0xa1, 0xdf, 0x0e, 0x5b, 0x87, 0xb5, 0xbe, 0xce, - 0x47, 0x7a, 0x70, 0x96, 0x49, 0xe9, 0x50, 0x06, - ], - [ - 0x04, 0x91, 0x39, 0x48, 0xf1, 0xa9, 0xd7, 0x92, 0x05, 0xe1, 0xc6, 0x82, - 0xc7, 0x38, 0x07, 0x0a, 0xf6, 0x55, 0x6d, 0xf6, 0xed, 0x4b, 0x4d, 0xdd, - 0x3d, 0x9a, 0x69, 0xf5, 0x33, 0x57, 0xd7, 0x36, - ], - ], - final_state: [ - [ - 0x63, 0xe6, 0x3f, 0x14, 0xcc, 0x49, 0xec, 0x8f, 0x59, 0x93, 0x33, 0xae, - 0x04, 0x2c, 0xb4, 0x0c, 0x6f, 0xa8, 0x5f, 0x2d, 0x67, 0x64, 0xde, 0xad, - 0x13, 0x16, 0x44, 0x04, 0x97, 0x8b, 0x12, 0x03, - ], - [ - 0xc5, 0x61, 0xf3, 0x87, 0xb4, 0xaa, 0x32, 0x60, 0x09, 0x0f, 0x01, 0x73, - 0x88, 0x01, 0xb5, 0x34, 0xbe, 0x39, 0x6a, 0x13, 0xee, 0x11, 0x6b, 0x21, - 0xdb, 0x76, 0x10, 0x69, 0x59, 0x3d, 0xb6, 0x2f, - ], - [ - 0x10, 0x1a, 0x4b, 0xfd, 0x56, 0x89, 0xd5, 0x5a, 0xa7, 0x0e, 0xcf, 0x44, - 0x6d, 0xc3, 0x1a, 0x89, 0xbc, 0x62, 0xde, 0xb7, 0xed, 0x36, 0xf5, 0x49, - 0x19, 0x9c, 0xe1, 0x7b, 0xac, 0xe7, 0x32, 0x1b, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x7d, 0x4f, 0x5c, 0xcb, 0x99, 0xef, 0x08, 0x4b, 0x57, 0x25, 0xcf, 0xeb, - 0xd5, 0xd6, 0x3d, 0xc1, 0x6a, 0x95, 0xe3, 0x02, 0x5b, 0x97, 0x92, 0xff, - 0xf7, 0xf2, 0x44, 0xfc, 0x71, 0x62, 0x69, 0x39, - ], - [ - 0x26, 0xd6, 0x2e, 0x95, 0x96, 0xfa, 0x82, 0x5c, 0x6b, 0xf2, 0x1a, 0xff, - 0x9e, 0x68, 0x62, 0x5a, 0x19, 0x24, 0x40, 0xea, 0x06, 0x82, 0x81, 0x23, - 0xd9, 0x78, 0x84, 0x80, 0x6f, 0x15, 0xfa, 0x08, - ], - [ - 0xd9, 0x52, 0x75, 0x4a, 0xef, 0xa9, 0x9c, 0x73, 0x3d, 0x14, 0xc8, 0xda, - 0x01, 0x47, 0x86, 0xda, 0x3a, 0x61, 0x28, 0xae, 0xf7, 0x84, 0xa6, 0x46, - 0x10, 0xa8, 0x9d, 0x1a, 0x70, 0x99, 0x21, 0x2d, - ], - ], - final_state: [ - [ - 0x45, 0xed, 0x54, 0x17, 0x40, 0x7b, 0xfd, 0xb7, 0x97, 0xbc, 0xfe, 0x70, - 0x74, 0xdf, 0xf8, 0x0e, 0x32, 0xa5, 0x62, 0xed, 0x88, 0x73, 0x78, 0x1d, - 0xbc, 0xf4, 0xf6, 0x7e, 0x06, 0xbe, 0x0c, 0x23, - ], - [ - 0x13, 0x2f, 0x3f, 0x55, 0xd8, 0xfb, 0xfd, 0x46, 0x7b, 0x2a, 0xe2, 0x2b, - 0x8c, 0x64, 0x93, 0x43, 0x64, 0xcf, 0x9c, 0x4a, 0x0b, 0x07, 0xed, 0xb4, - 0x02, 0x87, 0xc3, 0x92, 0xc9, 0xc1, 0x45, 0x12, - ], - [ - 0xd0, 0x51, 0xc3, 0x7f, 0xf6, 0x4c, 0xad, 0xa2, 0xb4, 0x82, 0xf1, 0x1f, - 0x85, 0x64, 0x39, 0x6b, 0x75, 0xe3, 0xf8, 0x1b, 0x35, 0x52, 0xd8, 0x9a, - 0xf4, 0x92, 0xcf, 0x00, 0x52, 0x3c, 0x04, 0x15, - ], - ], - }, - ] - } - - pub(crate) fn hash() -> Vec { - use HashTestVector as TestVector; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/orchard_poseidon/hash/fq.py - vec![ - TestVector { - input: [ - [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - [ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - ], - output: [ - 0x4e, 0x68, 0xf6, 0x85, 0x70, 0x29, 0x57, 0xf3, 0xbf, 0x54, 0x6b, 0x7a, 0x09, - 0x01, 0x31, 0x4e, 0x51, 0x4f, 0x19, 0x5e, 0xe3, 0xb1, 0x64, 0x46, 0x22, 0x77, - 0x9d, 0x93, 0xdf, 0x96, 0xba, 0x15, - ], - }, - TestVector { - input: [ - [ - 0x5c, 0x7a, 0x8f, 0x73, 0x79, 0x42, 0x57, 0x08, 0x7e, 0x63, 0x4c, 0x49, - 0xac, 0x6b, 0x57, 0x07, 0x4c, 0x4d, 0x6e, 0x66, 0xb1, 0x64, 0x93, 0x9d, - 0xaf, 0xfa, 0x2e, 0xf6, 0xee, 0x69, 0x21, 0x08, - ], - [ - 0x1a, 0xdd, 0x86, 0xb3, 0x8a, 0x6d, 0x8a, 0xc0, 0xa6, 0xfd, 0x9e, 0x0d, - 0x98, 0x2b, 0x77, 0xe6, 0xb0, 0xef, 0x9c, 0xa3, 0xf2, 0x49, 0x88, 0xc7, - 0xb3, 0x53, 0x42, 0x01, 0xcf, 0xb1, 0xcd, 0x0d, - ], - ], - output: [ - 0x0c, 0x0a, 0xd9, 0x0a, 0x2e, 0x0c, 0xba, 0x0e, 0xe6, 0xa5, 0x5a, 0xc5, 0x38, - 0xa4, 0x35, 0xc9, 0x39, 0x04, 0x98, 0xae, 0xb5, 0x30, 0x3e, 0x3d, 0xad, 0x70, - 0x3a, 0xd1, 0xdc, 0xdb, 0x43, 0x2b, - ], - }, - TestVector { - input: [ - [ - 0xbd, 0x69, 0xb8, 0x25, 0xca, 0x41, 0x61, 0x29, 0x6e, 0xfa, 0x7f, 0x66, - 0x9b, 0xa9, 0xc7, 0x27, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, - 0xa5, 0xe2, 0x9d, 0x4e, 0x30, 0xa7, 0x35, 0x14, - ], - [ - 0xbc, 0x50, 0x98, 0x42, 0xb9, 0xa7, 0x62, 0xe5, 0x58, 0xea, 0x51, 0x47, - 0xed, 0x5a, 0xc0, 0x08, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, 0xbc, 0xb6, - 0x4b, 0x69, 0x68, 0x91, 0x2a, 0x63, 0x81, 0x0e, - ], - ], - output: [ - 0xa6, 0x0c, 0xc8, 0xb8, 0x53, 0xaf, 0xce, 0xdb, 0xa1, 0x44, 0x65, 0xd5, 0x31, - 0xc7, 0x3c, 0xbc, 0xe1, 0x9e, 0x46, 0x0b, 0xa8, 0x04, 0x62, 0x2d, 0xf5, 0x21, - 0x23, 0x1d, 0xa1, 0x21, 0xc6, 0x08, - ], - }, - TestVector { - input: [ - [ - 0x3d, 0xc1, 0x66, 0xd5, 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x55, 0x1d, - 0xb5, 0xfd, 0x93, 0x13, 0xe8, 0xc7, 0x20, 0x3d, 0x99, 0x6a, 0xf7, 0xd4, - 0x77, 0x08, 0x37, 0x56, 0xd5, 0x9a, 0xf8, 0x0d, - ], - [ - 0x05, 0xa7, 0x45, 0xf4, 0x29, 0xc5, 0xdc, 0xe8, 0x4e, 0x0c, 0x20, 0xfd, - 0xf0, 0xf0, 0x3e, 0xbf, 0x81, 0x30, 0xab, 0x33, 0x36, 0x26, 0x97, 0xb0, - 0xe4, 0xe4, 0xc7, 0x63, 0xcc, 0xb8, 0xf6, 0x36, - ], - ], - output: [ - 0xad, 0xa8, 0xca, 0xe4, 0x6a, 0x04, 0x2d, 0x00, 0xb0, 0x2e, 0x33, 0xc3, 0x6e, - 0x65, 0x8c, 0x22, 0x13, 0xfe, 0x81, 0x34, 0x53, 0x8b, 0x56, 0x03, 0x19, 0xe9, - 0x99, 0xf3, 0xf5, 0x82, 0x90, 0x00, - ], - }, - TestVector { - input: [ - [ - 0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, 0xfa, 0x3d, 0x5a, - 0x57, 0xef, 0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, 0xfb, - 0x1a, 0x38, 0xe0, 0x1d, 0x94, 0x90, 0x3d, 0x3c, - ], - [ - 0x3d, 0x0a, 0xd3, 0x36, 0xeb, 0x31, 0xf0, 0x83, 0xce, 0x29, 0x77, 0x0e, - 0x42, 0x98, 0x8d, 0x7d, 0x25, 0xc9, 0xa1, 0x38, 0xf4, 0x9b, 0x1a, 0x53, - 0x7e, 0xdc, 0xf0, 0x4b, 0xe3, 0x4a, 0x98, 0x11, - ], - ], - output: [ - 0x19, 0x94, 0x9f, 0xc7, 0x74, 0x04, 0x99, 0x37, 0x00, 0x58, 0x12, 0x7d, 0x04, - 0x0f, 0x11, 0x24, 0x5e, 0xba, 0x6c, 0x37, 0x80, 0xe9, 0x3e, 0x26, 0x16, 0xf4, - 0xc1, 0x77, 0x56, 0x30, 0x78, 0x2d, - ], - }, - TestVector { - input: [ - [ - 0xa4, 0xaf, 0x9d, 0xb6, 0x36, 0x4d, 0x03, 0x99, 0x3d, 0x50, 0x35, 0x3d, - 0x88, 0x39, 0x5e, 0xd7, 0xa4, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, - 0xb9, 0xda, 0x94, 0x8d, 0x32, 0x0d, 0xad, 0x16, - ], - [ - 0x4d, 0x54, 0x31, 0xe6, 0xdb, 0x08, 0xd8, 0x74, 0x69, 0x5c, 0x3e, 0xaf, - 0x34, 0x5b, 0x86, 0xc4, 0x12, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, - 0x42, 0x76, 0xd3, 0x8d, 0x47, 0xf1, 0xe1, 0x11, - ], - ], - output: [ - 0x29, 0x6e, 0xba, 0xb4, 0xb4, 0x5a, 0xb9, 0x20, 0x97, 0xa7, 0xe6, 0xe7, 0xcc, - 0x6d, 0xd7, 0xd4, 0x7a, 0x12, 0x3e, 0x85, 0x50, 0xa3, 0x3d, 0xf1, 0x20, 0xcc, - 0xa5, 0x38, 0x90, 0x67, 0x1b, 0x21, - ], - }, - TestVector { - input: [ - [ - 0xdd, 0x0c, 0x7a, 0x1d, 0xe5, 0xed, 0x2f, 0xc3, 0x8e, 0x5e, 0x60, 0x7a, - 0x3f, 0xde, 0xab, 0x3f, 0xb6, 0x79, 0xf3, 0xdc, 0x60, 0x1d, 0x00, 0x82, - 0x85, 0xed, 0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0x3c, - ], - [ - 0x19, 0xe4, 0xaa, 0xc0, 0xcd, 0x1b, 0xe4, 0x05, 0x02, 0x42, 0xf4, 0xd1, - 0x20, 0x53, 0xdb, 0x33, 0xf7, 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, - 0x37, 0x83, 0x65, 0xc8, 0xf7, 0x39, 0x3c, 0x14, - ], - ], - output: [ - 0xa8, 0x87, 0x6e, 0x8d, 0x2f, 0x30, 0x0a, 0x62, 0x05, 0x4b, 0x49, 0x4c, 0x8f, - 0x21, 0xc1, 0xd0, 0xad, 0xbd, 0xac, 0x89, 0xbf, 0x2a, 0xad, 0x9f, 0x3c, 0x1b, - 0x10, 0xc4, 0x78, 0x8c, 0x2d, 0x3d, - ], - }, - TestVector { - input: [ - [ - 0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, - 0x79, 0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, - 0x32, 0xb4, 0xf4, 0x73, 0xf4, 0x68, 0xa0, 0x08, - ], - [ - 0xe6, 0x23, 0x89, 0xfc, 0xe2, 0x9c, 0xc6, 0xeb, 0x2e, 0x07, 0xeb, 0xc5, - 0xae, 0x25, 0xf9, 0xf7, 0x83, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, 0x15, 0x3d, - 0x88, 0x2d, 0x2b, 0x21, 0x03, 0x59, 0x65, 0x15, - ], - ], - output: [ - 0xc2, 0xda, 0xcb, 0x1e, 0xea, 0xed, 0x88, 0x0b, 0x87, 0xd0, 0x4d, 0xd9, 0x61, - 0x95, 0x73, 0x0e, 0x98, 0xbd, 0x0f, 0x14, 0x77, 0x7b, 0x3e, 0xf0, 0xda, 0x40, - 0xe4, 0xc0, 0x87, 0xb1, 0x9d, 0x28, - ], - }, - TestVector { - input: [ - [ - 0xeb, 0x94, 0x94, 0xc6, 0x6a, 0xb3, 0xae, 0x30, 0xb7, 0xe6, 0x09, 0xd9, - 0x91, 0xf4, 0x33, 0xbf, 0x94, 0x86, 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, - 0x73, 0x1e, 0x98, 0x5d, 0x99, 0x58, 0x9c, 0x0b, - ], - [ - 0xb7, 0x38, 0xe8, 0xaa, 0xd6, 0x5a, 0x0c, 0xb2, 0xfb, 0x3f, 0x1a, 0x31, - 0x20, 0x37, 0x2e, 0x83, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, - 0xeb, 0xbc, 0x86, 0x2d, 0xed, 0x42, 0x43, 0x1e, - ], - ], - output: [ - 0x5a, 0x55, 0xe3, 0x08, 0x2e, 0x55, 0xa5, 0x66, 0xb9, 0xca, 0xb1, 0xca, 0xf4, - 0x48, 0xf7, 0x0f, 0x8c, 0x9a, 0x53, 0xa1, 0xc9, 0xf6, 0x9e, 0x2a, 0x80, 0xdd, - 0xb8, 0x58, 0x3f, 0x99, 0x01, 0x26, - ], - }, - TestVector { - input: [ - [ - 0x91, 0x47, 0x69, 0x30, 0xaf, 0x7e, 0x42, 0xe0, 0x21, 0x88, 0x56, 0x38, - 0x53, 0xd9, 0x34, 0x67, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, - 0x6d, 0x75, 0xa4, 0xa6, 0xf2, 0x65, 0x72, 0x10, - ], - [ - 0x4b, 0x19, 0x22, 0x32, 0xec, 0xb9, 0xf0, 0xc0, 0x24, 0x11, 0xe5, 0x25, - 0x96, 0xbc, 0x5e, 0x90, 0x45, 0x7e, 0x74, 0x59, 0x39, 0xff, 0xed, 0xbd, - 0x12, 0x86, 0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11, - ], - ], - output: [ - 0xca, 0xc6, 0x68, 0x8a, 0x3d, 0x2a, 0x7d, 0xca, 0xe1, 0xd4, 0x60, 0x1f, 0x9b, - 0xf0, 0x6d, 0x58, 0x00, 0x8f, 0x24, 0x85, 0x6a, 0xe6, 0x00, 0xf0, 0xe0, 0x90, - 0x07, 0x23, 0xaf, 0xa1, 0x20, 0x03, - ], - }, - TestVector { - input: [ - [ - 0x7b, 0x41, 0x7a, 0xdb, 0xfb, 0x3e, 0x3e, 0x3c, 0x21, 0x60, 0xd3, 0xd1, - 0x6f, 0x1e, 0x7f, 0x26, 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, - 0x82, 0x85, 0x7d, 0xee, 0xcc, 0x40, 0xa9, 0x0d, - ], - [ - 0x5e, 0x29, 0x35, 0x39, 0x3d, 0xf9, 0x2f, 0xa1, 0xf4, 0x71, 0x68, 0xb2, - 0x61, 0xae, 0xb3, 0x78, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, - 0xb9, 0x27, 0xb7, 0xfa, 0xe2, 0xdb, 0x58, 0x31, - ], - ], - output: [ - 0xd7, 0xe7, 0x83, 0x91, 0x97, 0x83, 0xb0, 0x8b, 0x5f, 0xad, 0x08, 0x9d, 0x57, - 0x1e, 0xc1, 0x8f, 0xb4, 0x63, 0x28, 0x53, 0x99, 0x3f, 0x35, 0xe3, 0xee, 0x54, - 0x3d, 0x4e, 0xed, 0xf6, 0x5f, 0x38, - ], - }, - ] - } -} diff --git a/halo2_gadgets/src/sha256.rs b/halo2_gadgets/src/sha256.rs deleted file mode 100644 index 391020a3d3..0000000000 --- a/halo2_gadgets/src/sha256.rs +++ /dev/null @@ -1,166 +0,0 @@ -//! The [SHA-256] hash function. -//! -//! [SHA-256]: https://tools.ietf.org/html/rfc6234 - -use std::cmp::min; -use std::convert::TryInto; -use std::fmt; - -use halo2_proofs::{ - arithmetic::Field, - circuit::{Chip, Layouter}, - plonk::Error, -}; - -mod table16; - -pub use table16::{BlockWord, Table16Chip, Table16Config}; - -/// The size of a SHA-256 block, in 32-bit words. -pub const BLOCK_SIZE: usize = 16; -/// The size of a SHA-256 digest, in 32-bit words. -const DIGEST_SIZE: usize = 8; - -/// The set of circuit instructions required to use the [`Sha256`] gadget. -pub trait Sha256Instructions: Chip { - /// Variable representing the SHA-256 internal state. - type State: Clone + fmt::Debug; - /// Variable representing a 32-bit word of the input block to the SHA-256 compression - /// function. - type BlockWord: Copy + fmt::Debug + Default; - - /// Places the SHA-256 IV in the circuit, returning the initial state variable. - fn initialization_vector(&self, layouter: &mut impl Layouter) -> Result; - - /// Creates an initial state from the output state of a previous block - fn initialization( - &self, - layouter: &mut impl Layouter, - init_state: &Self::State, - ) -> Result; - - /// Starting from the given initialized state, processes a block of input and returns the - /// final state. - fn compress( - &self, - layouter: &mut impl Layouter, - initialized_state: &Self::State, - input: [Self::BlockWord; BLOCK_SIZE], - ) -> Result; - - /// Converts the given state into a message digest. - fn digest( - &self, - layouter: &mut impl Layouter, - state: &Self::State, - ) -> Result<[Self::BlockWord; DIGEST_SIZE], Error>; -} - -/// The output of a SHA-256 circuit invocation. -#[derive(Debug)] -pub struct Sha256Digest([BlockWord; DIGEST_SIZE]); - -/// A gadget that constrains a SHA-256 invocation. It supports input at a granularity of -/// 32 bits. -#[derive(Debug)] -pub struct Sha256> { - chip: CS, - state: CS::State, - cur_block: Vec, - length: usize, -} - -impl> Sha256 { - /// Create a new hasher instance. - pub fn new(chip: Sha256Chip, mut layouter: impl Layouter) -> Result { - let state = chip.initialization_vector(&mut layouter)?; - Ok(Sha256 { - chip, - state, - cur_block: Vec::with_capacity(BLOCK_SIZE), - length: 0, - }) - } - - /// Digest data, updating the internal state. - pub fn update( - &mut self, - mut layouter: impl Layouter, - mut data: &[Sha256Chip::BlockWord], - ) -> Result<(), Error> { - self.length += data.len() * 32; - - // Fill the current block, if possible. - let remaining = BLOCK_SIZE - self.cur_block.len(); - let (l, r) = data.split_at(min(remaining, data.len())); - self.cur_block.extend_from_slice(l); - data = r; - - // If we still don't have a full block, we are done. - if self.cur_block.len() < BLOCK_SIZE { - return Ok(()); - } - - // Process the now-full current block. - self.state = self.chip.compress( - &mut layouter, - &self.state, - self.cur_block[..] - .try_into() - .expect("cur_block.len() == BLOCK_SIZE"), - )?; - self.cur_block.clear(); - - // Process any additional full blocks. - let mut chunks_iter = data.chunks_exact(BLOCK_SIZE); - for chunk in &mut chunks_iter { - self.state = self.chip.initialization(&mut layouter, &self.state)?; - self.state = self.chip.compress( - &mut layouter, - &self.state, - chunk.try_into().expect("chunk.len() == BLOCK_SIZE"), - )?; - } - - // Cache the remaining partial block, if any. - let rem = chunks_iter.remainder(); - self.cur_block.extend_from_slice(rem); - - Ok(()) - } - - /// Retrieve result and consume hasher instance. - pub fn finalize( - mut self, - mut layouter: impl Layouter, - ) -> Result, Error> { - // Pad the remaining block - if !self.cur_block.is_empty() { - let padding = vec![Sha256Chip::BlockWord::default(); BLOCK_SIZE - self.cur_block.len()]; - self.cur_block.extend_from_slice(&padding); - self.state = self.chip.initialization(&mut layouter, &self.state)?; - self.state = self.chip.compress( - &mut layouter, - &self.state, - self.cur_block[..] - .try_into() - .expect("cur_block.len() == BLOCK_SIZE"), - )?; - } - self.chip - .digest(&mut layouter, &self.state) - .map(Sha256Digest) - } - - /// Convenience function to compute hash of the data. It will handle hasher creation, - /// data feeding and finalization. - pub fn digest( - chip: Sha256Chip, - mut layouter: impl Layouter, - data: &[Sha256Chip::BlockWord], - ) -> Result, Error> { - let mut hasher = Self::new(chip, layouter.namespace(|| "init"))?; - hasher.update(layouter.namespace(|| "update"), data)?; - hasher.finalize(layouter.namespace(|| "finalize")) - } -} diff --git a/halo2_gadgets/src/sha256/table16.rs b/halo2_gadgets/src/sha256/table16.rs deleted file mode 100644 index 4781d82f64..0000000000 --- a/halo2_gadgets/src/sha256/table16.rs +++ /dev/null @@ -1,517 +0,0 @@ -use std::convert::TryInto; -use std::marker::PhantomData; - -use super::Sha256Instructions; -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter, Region, Value}, - plonk::{Advice, Any, Assigned, Column, ConstraintSystem, Error}, -}; -use halo2curves::pasta::pallas; - -mod compression; -mod gates; -mod message_schedule; -mod spread_table; -mod util; - -use compression::*; -use gates::*; -use message_schedule::*; -use spread_table::*; -use util::*; - -const ROUNDS: usize = 64; -const STATE: usize = 8; - -#[allow(clippy::unreadable_literal)] -pub(crate) const ROUND_CONSTANTS: [u32; ROUNDS] = [ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, -]; - -const IV: [u32; STATE] = [ - 0x6a09_e667, - 0xbb67_ae85, - 0x3c6e_f372, - 0xa54f_f53a, - 0x510e_527f, - 0x9b05_688c, - 0x1f83_d9ab, - 0x5be0_cd19, -]; - -#[derive(Clone, Copy, Debug, Default)] -/// A word in a `Table16` message block. -// TODO: Make the internals of this struct private. -pub struct BlockWord(pub Value); - -#[derive(Clone, Debug)] -/// Little-endian bits (up to 64 bits) -pub struct Bits([bool; LEN]); - -impl Bits { - fn spread(&self) -> [bool; SPREAD] { - spread_bits(self.0) - } -} - -impl std::ops::Deref for Bits { - type Target = [bool; LEN]; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl From<[bool; LEN]> for Bits { - fn from(bits: [bool; LEN]) -> Self { - Self(bits) - } -} - -impl From<&Bits> for [bool; LEN] { - fn from(bits: &Bits) -> Self { - bits.0 - } -} - -impl From<&Bits> for Assigned { - fn from(bits: &Bits) -> Assigned { - assert!(LEN <= 64); - pallas::Base::from(lebs2ip(&bits.0)).into() - } -} - -impl From<&Bits<16>> for u16 { - fn from(bits: &Bits<16>) -> u16 { - lebs2ip(&bits.0) as u16 - } -} - -impl From for Bits<16> { - fn from(int: u16) -> Bits<16> { - Bits(i2lebsp::<16>(int.into())) - } -} - -impl From<&Bits<32>> for u32 { - fn from(bits: &Bits<32>) -> u32 { - lebs2ip(&bits.0) as u32 - } -} - -impl From for Bits<32> { - fn from(int: u32) -> Bits<32> { - Bits(i2lebsp::<32>(int.into())) - } -} - -#[derive(Clone, Debug)] -pub struct AssignedBits(AssignedCell, pallas::Base>); - -impl std::ops::Deref for AssignedBits { - type Target = AssignedCell, pallas::Base>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl AssignedBits { - fn assign_bits + std::fmt::Debug + Clone>( - region: &mut Region<'_, pallas::Base>, - annotation: A, - column: impl Into>, - offset: usize, - value: Value, - ) -> Result - where - A: Fn() -> AR, - AR: Into, - >::Error: std::fmt::Debug, - { - let value: Value<[bool; LEN]> = value.map(|v| v.try_into().unwrap()); - let value: Value> = value.map(|v| v.into()); - - let column: Column = column.into(); - match column.column_type() { - Any::Advice(_) => { - region.assign_advice(annotation, column.try_into().unwrap(), offset, || { - value.clone() - }) - } - Any::Fixed => { - region.assign_fixed(annotation, column.try_into().unwrap(), offset, || { - value.clone() - }) - } - _ => panic!("Cannot assign to instance column"), - } - .map(AssignedBits) - } -} - -impl AssignedBits<16> { - fn value_u16(&self) -> Value { - self.value().map(|v| v.into()) - } - - fn assign( - region: &mut Region<'_, pallas::Base>, - annotation: A, - column: impl Into>, - offset: usize, - value: Value, - ) -> Result - where - A: Fn() -> AR, - AR: Into, - { - let column: Column = column.into(); - let value: Value> = value.map(|v| v.into()); - match column.column_type() { - Any::Advice(_) => { - region.assign_advice(annotation, column.try_into().unwrap(), offset, || { - value.clone() - }) - } - Any::Fixed => { - region.assign_fixed(annotation, column.try_into().unwrap(), offset, || { - value.clone() - }) - } - _ => panic!("Cannot assign to instance column"), - } - .map(AssignedBits) - } -} - -impl AssignedBits<32> { - fn value_u32(&self) -> Value { - self.value().map(|v| v.into()) - } - - fn assign( - region: &mut Region<'_, pallas::Base>, - annotation: A, - column: impl Into>, - offset: usize, - value: Value, - ) -> Result - where - A: Fn() -> AR, - AR: Into, - { - let column: Column = column.into(); - let value: Value> = value.map(|v| v.into()); - match column.column_type() { - Any::Advice(_) => { - region.assign_advice(annotation, column.try_into().unwrap(), offset, || { - value.clone() - }) - } - Any::Fixed => { - region.assign_fixed(annotation, column.try_into().unwrap(), offset, || { - value.clone() - }) - } - _ => panic!("Cannot assign to instance column"), - } - .map(AssignedBits) - } -} - -/// Configuration for a [`Table16Chip`]. -#[derive(Clone, Debug)] -pub struct Table16Config { - lookup: SpreadTableConfig, - message_schedule: MessageScheduleConfig, - compression: CompressionConfig, -} - -/// A chip that implements SHA-256 with a maximum lookup table size of $2^16$. -#[derive(Clone, Debug)] -pub struct Table16Chip { - config: Table16Config, - _marker: PhantomData, -} - -impl Chip for Table16Chip { - type Config = Table16Config; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -impl Table16Chip { - /// Reconstructs this chip from the given config. - pub fn construct(config: >::Config) -> Self { - Self { - config, - _marker: PhantomData, - } - } - - /// Configures a circuit to include this chip. - pub fn configure( - meta: &mut ConstraintSystem, - ) -> >::Config { - // Columns required by this chip: - let message_schedule = meta.advice_column(); - let extras = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - - // - Three advice columns to interact with the lookup table. - let input_tag = meta.advice_column(); - let input_dense = meta.advice_column(); - let input_spread = meta.advice_column(); - - let lookup = SpreadTableChip::configure(meta, input_tag, input_dense, input_spread); - let lookup_inputs = lookup.input.clone(); - - // Rename these here for ease of matching the gates to the specification. - let _a_0 = lookup_inputs.tag; - let a_1 = lookup_inputs.dense; - let a_2 = lookup_inputs.spread; - let a_3 = extras[0]; - let a_4 = extras[1]; - let a_5 = message_schedule; - let a_6 = extras[2]; - let a_7 = extras[3]; - let a_8 = extras[4]; - let _a_9 = extras[5]; - - // Add all advice columns to permutation - for column in [a_1, a_2, a_3, a_4, a_5, a_6, a_7, a_8].iter() { - meta.enable_equality(*column); - } - - let compression = - CompressionConfig::configure(meta, lookup_inputs.clone(), message_schedule, extras); - - let message_schedule = - MessageScheduleConfig::configure(meta, lookup_inputs, message_schedule, extras); - - Table16Config { - lookup, - message_schedule, - compression, - } - } - - /// Loads the lookup table required by this chip into the circuit. - pub fn load( - config: Table16Config, - layouter: &mut impl Layouter, - ) -> Result<(), Error> { - SpreadTableChip::load(config.lookup, layouter) - } -} - -impl Sha256Instructions for Table16Chip { - type State = State; - type BlockWord = BlockWord; - - fn initialization_vector( - &self, - layouter: &mut impl Layouter, - ) -> Result { - self.config().compression.initialize_with_iv(layouter, IV) - } - - fn initialization( - &self, - layouter: &mut impl Layouter, - init_state: &Self::State, - ) -> Result { - self.config() - .compression - .initialize_with_state(layouter, init_state.clone()) - } - - // Given an initialized state and an input message block, compress the - // message block and return the final state. - fn compress( - &self, - layouter: &mut impl Layouter, - initialized_state: &Self::State, - input: [Self::BlockWord; super::BLOCK_SIZE], - ) -> Result { - let config = self.config(); - let (_, w_halves) = config.message_schedule.process(layouter, input)?; - config - .compression - .compress(layouter, initialized_state.clone(), w_halves) - } - - fn digest( - &self, - layouter: &mut impl Layouter, - state: &Self::State, - ) -> Result<[Self::BlockWord; super::DIGEST_SIZE], Error> { - // Copy the dense forms of the state variable chunks down to this gate. - // Reconstruct the 32-bit dense words. - self.config().compression.digest(layouter, state.clone()) - } -} - -/// Common assignment patterns used by Table16 regions. -trait Table16Assignment { - /// Assign cells for general spread computation used in sigma, ch, ch_neg, maj gates - #[allow(clippy::too_many_arguments)] - #[allow(clippy::type_complexity)] - fn assign_spread_outputs( - &self, - region: &mut Region<'_, pallas::Base>, - lookup: &SpreadInputs, - a_3: Column, - row: usize, - r_0_even: Value<[bool; 16]>, - r_0_odd: Value<[bool; 16]>, - r_1_even: Value<[bool; 16]>, - r_1_odd: Value<[bool; 16]>, - ) -> Result< - ( - (AssignedBits<16>, AssignedBits<16>), - (AssignedBits<16>, AssignedBits<16>), - ), - Error, - > { - // Lookup R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - let r_0_even = SpreadVar::with_lookup( - region, - lookup, - row - 1, - r_0_even.map(SpreadWord::<16, 32>::new), - )?; - let r_0_odd = - SpreadVar::with_lookup(region, lookup, row, r_0_odd.map(SpreadWord::<16, 32>::new))?; - let r_1_even = SpreadVar::with_lookup( - region, - lookup, - row + 1, - r_1_even.map(SpreadWord::<16, 32>::new), - )?; - let r_1_odd = SpreadVar::with_lookup( - region, - lookup, - row + 2, - r_1_odd.map(SpreadWord::<16, 32>::new), - )?; - - // Assign and copy R_1^{odd} - r_1_odd - .spread - .copy_advice(|| "Assign and copy R_1^{odd}", region, a_3, row)?; - - Ok(( - (r_0_even.dense, r_1_even.dense), - (r_0_odd.dense, r_1_odd.dense), - )) - } - - /// Assign outputs of sigma gates - #[allow(clippy::too_many_arguments)] - fn assign_sigma_outputs( - &self, - region: &mut Region<'_, pallas::Base>, - lookup: &SpreadInputs, - a_3: Column, - row: usize, - r_0_even: Value<[bool; 16]>, - r_0_odd: Value<[bool; 16]>, - r_1_even: Value<[bool; 16]>, - r_1_odd: Value<[bool; 16]>, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let (even, _odd) = self.assign_spread_outputs( - region, lookup, a_3, row, r_0_even, r_0_odd, r_1_even, r_1_odd, - )?; - - Ok(even) - } -} - -#[cfg(test)] -#[cfg(feature = "test-dev-graph")] -mod tests { - use super::super::{Sha256, BLOCK_SIZE}; - use super::{message_schedule::msg_schedule_test_input, Table16Chip, Table16Config}; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use halo2curves::pasta::pallas; - - #[test] - fn print_sha256_circuit() { - use plotters::prelude::*; - struct MyCircuit {} - - impl Circuit for MyCircuit { - type Config = Table16Config; - type FloorPlanner = SimpleFloorPlanner; - #[cfg(feature = "circuit-params")] - type Params = (); - - fn without_witnesses(&self) -> Self { - MyCircuit {} - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - Table16Chip::configure(meta) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let table16_chip = Table16Chip::construct(config.clone()); - Table16Chip::load(config, &mut layouter)?; - - // Test vector: "abc" - let test_input = msg_schedule_test_input(); - - // Create a message of length 31 blocks - let mut input = Vec::with_capacity(31 * BLOCK_SIZE); - for _ in 0..31 { - input.extend_from_slice(&test_input); - } - - Sha256::digest(table16_chip, layouter.namespace(|| "'abc' * 31"), &input)?; - - Ok(()) - } - } - - let root = - BitMapBackend::new("sha-256-table16-chip-layout.png", (1024, 3480)).into_drawing_area(); - root.fill(&WHITE).unwrap(); - let root = root - .titled("16-bit Table SHA-256 Chip", ("sans-serif", 60)) - .unwrap(); - - let circuit = MyCircuit {}; - halo2_proofs::dev::CircuitLayout::default() - .render::(17, &circuit, &root) - .unwrap(); - } -} diff --git a/halo2_gadgets/src/sha256/table16/compression.rs b/halo2_gadgets/src/sha256/table16/compression.rs deleted file mode 100644 index 874452a418..0000000000 --- a/halo2_gadgets/src/sha256/table16/compression.rs +++ /dev/null @@ -1,1007 +0,0 @@ -use super::{ - super::DIGEST_SIZE, - util::{i2lebsp, lebs2ip}, - AssignedBits, BlockWord, SpreadInputs, SpreadVar, Table16Assignment, ROUNDS, STATE, -}; -use halo2_proofs::{ - circuit::{Layouter, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, Selector}, - poly::Rotation, -}; -use halo2curves::pasta::pallas; -use std::convert::TryInto; -use std::ops::Range; - -mod compression_gates; -mod compression_util; -mod subregion_digest; -mod subregion_initial; -mod subregion_main; - -use compression_gates::CompressionGate; - -pub trait UpperSigmaVar< - const A_LEN: usize, - const B_LEN: usize, - const C_LEN: usize, - const D_LEN: usize, -> -{ - fn spread_a(&self) -> Value<[bool; A_LEN]>; - fn spread_b(&self) -> Value<[bool; B_LEN]>; - fn spread_c(&self) -> Value<[bool; C_LEN]>; - fn spread_d(&self) -> Value<[bool; D_LEN]>; - - fn xor_upper_sigma(&self) -> Value<[bool; 64]> { - self.spread_a() - .zip(self.spread_b()) - .zip(self.spread_c()) - .zip(self.spread_d()) - .map(|(((a, b), c), d)| { - let xor_0 = b - .iter() - .chain(c.iter()) - .chain(d.iter()) - .chain(a.iter()) - .copied() - .collect::>(); - let xor_1 = c - .iter() - .chain(d.iter()) - .chain(a.iter()) - .chain(b.iter()) - .copied() - .collect::>(); - let xor_2 = d - .iter() - .chain(a.iter()) - .chain(b.iter()) - .chain(c.iter()) - .copied() - .collect::>(); - - let xor_0 = lebs2ip::<64>(&xor_0.try_into().unwrap()); - let xor_1 = lebs2ip::<64>(&xor_1.try_into().unwrap()); - let xor_2 = lebs2ip::<64>(&xor_2.try_into().unwrap()); - - i2lebsp(xor_0 + xor_1 + xor_2) - }) - } -} - -/// A variable that represents the `[A,B,C,D]` words of the SHA-256 internal state. -/// -/// The structure of this variable is influenced by the following factors: -/// - In `Σ_0(A)` we need `A` to be split into pieces `(a,b,c,d)` of lengths `(2,11,9,10)` -/// bits respectively (counting from the little end), as well as their spread forms. -/// - `Maj(A,B,C)` requires having the bits of each input in spread form. For `A` we can -/// reuse the pieces from `Σ_0(A)`. Since `B` and `C` are assigned from `A` and `B` -/// respectively in each round, we therefore also have the same pieces in earlier rows. -/// We align the columns to make it efficient to copy-constrain these forms where they -/// are needed. -#[derive(Clone, Debug)] -pub struct AbcdVar { - a: SpreadVar<2, 4>, - b: SpreadVar<11, 22>, - c_lo: SpreadVar<3, 6>, - c_mid: SpreadVar<3, 6>, - c_hi: SpreadVar<3, 6>, - d: SpreadVar<10, 20>, -} - -impl AbcdVar { - fn a_range() -> Range { - 0..2 - } - - fn b_range() -> Range { - 2..13 - } - - fn c_lo_range() -> Range { - 13..16 - } - - fn c_mid_range() -> Range { - 16..19 - } - - fn c_hi_range() -> Range { - 19..22 - } - - fn d_range() -> Range { - 22..32 - } - - fn pieces(val: u32) -> Vec> { - let val: [bool; 32] = i2lebsp(val.into()); - vec![ - val[Self::a_range()].to_vec(), - val[Self::b_range()].to_vec(), - val[Self::c_lo_range()].to_vec(), - val[Self::c_mid_range()].to_vec(), - val[Self::c_hi_range()].to_vec(), - val[Self::d_range()].to_vec(), - ] - } -} - -impl UpperSigmaVar<4, 22, 18, 20> for AbcdVar { - fn spread_a(&self) -> Value<[bool; 4]> { - self.a.spread.value().map(|v| v.0) - } - - fn spread_b(&self) -> Value<[bool; 22]> { - self.b.spread.value().map(|v| v.0) - } - - fn spread_c(&self) -> Value<[bool; 18]> { - self.c_lo - .spread - .value() - .zip(self.c_mid.spread.value()) - .zip(self.c_hi.spread.value()) - .map(|((c_lo, c_mid), c_hi)| { - c_lo.iter() - .chain(c_mid.iter()) - .chain(c_hi.iter()) - .copied() - .collect::>() - .try_into() - .unwrap() - }) - } - - fn spread_d(&self) -> Value<[bool; 20]> { - self.d.spread.value().map(|v| v.0) - } -} - -/// A variable that represents the `[E,F,G,H]` words of the SHA-256 internal state. -/// -/// The structure of this variable is influenced by the following factors: -/// - In `Σ_1(E)` we need `E` to be split into pieces `(a,b,c,d)` of lengths `(6,5,14,7)` -/// bits respectively (counting from the little end), as well as their spread forms. -/// - `Ch(E,F,G)` requires having the bits of each input in spread form. For `E` we can -/// reuse the pieces from `Σ_1(E)`. Since `F` and `G` are assigned from `E` and `F` -/// respectively in each round, we therefore also have the same pieces in earlier rows. -/// We align the columns to make it efficient to copy-constrain these forms where they -/// are needed. -#[derive(Clone, Debug)] -pub struct EfghVar { - a_lo: SpreadVar<3, 6>, - a_hi: SpreadVar<3, 6>, - b_lo: SpreadVar<2, 4>, - b_hi: SpreadVar<3, 6>, - c: SpreadVar<14, 28>, - d: SpreadVar<7, 14>, -} - -impl EfghVar { - fn a_lo_range() -> Range { - 0..3 - } - - fn a_hi_range() -> Range { - 3..6 - } - - fn b_lo_range() -> Range { - 6..8 - } - - fn b_hi_range() -> Range { - 8..11 - } - - fn c_range() -> Range { - 11..25 - } - - fn d_range() -> Range { - 25..32 - } - - fn pieces(val: u32) -> Vec> { - let val: [bool; 32] = i2lebsp(val.into()); - vec![ - val[Self::a_lo_range()].to_vec(), - val[Self::a_hi_range()].to_vec(), - val[Self::b_lo_range()].to_vec(), - val[Self::b_hi_range()].to_vec(), - val[Self::c_range()].to_vec(), - val[Self::d_range()].to_vec(), - ] - } -} - -impl UpperSigmaVar<12, 10, 28, 14> for EfghVar { - fn spread_a(&self) -> Value<[bool; 12]> { - self.a_lo - .spread - .value() - .zip(self.a_hi.spread.value()) - .map(|(a_lo, a_hi)| { - a_lo.iter() - .chain(a_hi.iter()) - .copied() - .collect::>() - .try_into() - .unwrap() - }) - } - - fn spread_b(&self) -> Value<[bool; 10]> { - self.b_lo - .spread - .value() - .zip(self.b_hi.spread.value()) - .map(|(b_lo, b_hi)| { - b_lo.iter() - .chain(b_hi.iter()) - .copied() - .collect::>() - .try_into() - .unwrap() - }) - } - - fn spread_c(&self) -> Value<[bool; 28]> { - self.c.spread.value().map(|v| v.0) - } - - fn spread_d(&self) -> Value<[bool; 14]> { - self.d.spread.value().map(|v| v.0) - } -} - -#[derive(Clone, Debug)] -pub struct RoundWordDense(AssignedBits<16>, AssignedBits<16>); - -impl From<(AssignedBits<16>, AssignedBits<16>)> for RoundWordDense { - fn from(halves: (AssignedBits<16>, AssignedBits<16>)) -> Self { - Self(halves.0, halves.1) - } -} - -impl RoundWordDense { - pub fn value(&self) -> Value { - self.0 - .value_u16() - .zip(self.1.value_u16()) - .map(|(lo, hi)| lo as u32 + (1 << 16) * hi as u32) - } -} - -#[derive(Clone, Debug)] -pub struct RoundWordSpread(AssignedBits<32>, AssignedBits<32>); - -impl From<(AssignedBits<32>, AssignedBits<32>)> for RoundWordSpread { - fn from(halves: (AssignedBits<32>, AssignedBits<32>)) -> Self { - Self(halves.0, halves.1) - } -} - -impl RoundWordSpread { - pub fn value(&self) -> Value { - self.0 - .value_u32() - .zip(self.1.value_u32()) - .map(|(lo, hi)| lo as u64 + (1 << 32) * hi as u64) - } -} - -#[derive(Clone, Debug)] -pub struct RoundWordA { - pieces: Option, - dense_halves: RoundWordDense, - spread_halves: Option, -} - -impl RoundWordA { - pub fn new( - pieces: AbcdVar, - dense_halves: RoundWordDense, - spread_halves: RoundWordSpread, - ) -> Self { - RoundWordA { - pieces: Some(pieces), - dense_halves, - spread_halves: Some(spread_halves), - } - } - - pub fn new_dense(dense_halves: RoundWordDense) -> Self { - RoundWordA { - pieces: None, - dense_halves, - spread_halves: None, - } - } -} - -#[derive(Clone, Debug)] -pub struct RoundWordE { - pieces: Option, - dense_halves: RoundWordDense, - spread_halves: Option, -} - -impl RoundWordE { - pub fn new( - pieces: EfghVar, - dense_halves: RoundWordDense, - spread_halves: RoundWordSpread, - ) -> Self { - RoundWordE { - pieces: Some(pieces), - dense_halves, - spread_halves: Some(spread_halves), - } - } - - pub fn new_dense(dense_halves: RoundWordDense) -> Self { - RoundWordE { - pieces: None, - dense_halves, - spread_halves: None, - } - } -} - -#[derive(Clone, Debug)] -pub struct RoundWord { - dense_halves: RoundWordDense, - spread_halves: RoundWordSpread, -} - -impl RoundWord { - pub fn new(dense_halves: RoundWordDense, spread_halves: RoundWordSpread) -> Self { - RoundWord { - dense_halves, - spread_halves, - } - } -} - -/// The internal state for SHA-256. -#[derive(Clone, Debug)] -pub struct State { - a: Option, - b: Option, - c: Option, - d: Option, - e: Option, - f: Option, - g: Option, - h: Option, -} - -impl State { - #[allow(clippy::many_single_char_names)] - #[allow(clippy::too_many_arguments)] - pub fn new( - a: StateWord, - b: StateWord, - c: StateWord, - d: StateWord, - e: StateWord, - f: StateWord, - g: StateWord, - h: StateWord, - ) -> Self { - State { - a: Some(a), - b: Some(b), - c: Some(c), - d: Some(d), - e: Some(e), - f: Some(f), - g: Some(g), - h: Some(h), - } - } - - pub fn empty_state() -> Self { - State { - a: None, - b: None, - c: None, - d: None, - e: None, - f: None, - g: None, - h: None, - } - } -} - -#[derive(Clone, Debug)] -pub enum StateWord { - A(RoundWordA), - B(RoundWord), - C(RoundWord), - D(RoundWordDense), - E(RoundWordE), - F(RoundWord), - G(RoundWord), - H(RoundWordDense), -} - -#[derive(Clone, Debug)] -pub(super) struct CompressionConfig { - lookup: SpreadInputs, - message_schedule: Column, - extras: [Column; 6], - - s_ch: Selector, - s_ch_neg: Selector, - s_maj: Selector, - s_h_prime: Selector, - s_a_new: Selector, - s_e_new: Selector, - - s_upper_sigma_0: Selector, - s_upper_sigma_1: Selector, - - // Decomposition gate for AbcdVar - s_decompose_abcd: Selector, - // Decomposition gate for EfghVar - s_decompose_efgh: Selector, - - s_digest: Selector, -} - -impl Table16Assignment for CompressionConfig {} - -impl CompressionConfig { - pub(super) fn configure( - meta: &mut ConstraintSystem, - lookup: SpreadInputs, - message_schedule: Column, - extras: [Column; 6], - ) -> Self { - let s_ch = meta.selector(); - let s_ch_neg = meta.selector(); - let s_maj = meta.selector(); - let s_h_prime = meta.selector(); - let s_a_new = meta.selector(); - let s_e_new = meta.selector(); - - let s_upper_sigma_0 = meta.selector(); - let s_upper_sigma_1 = meta.selector(); - - // Decomposition gate for AbcdVar - let s_decompose_abcd = meta.selector(); - // Decomposition gate for EfghVar - let s_decompose_efgh = meta.selector(); - - let s_digest = meta.selector(); - - // Rename these here for ease of matching the gates to the specification. - let a_0 = lookup.tag; - let a_1 = lookup.dense; - let a_2 = lookup.spread; - let a_3 = extras[0]; - let a_4 = extras[1]; - let a_5 = message_schedule; - let a_6 = extras[2]; - let a_7 = extras[3]; - let a_8 = extras[4]; - let a_9 = extras[5]; - - // Decompose `A,B,C,D` words into (2, 11, 9, 10)-bit chunks. - // `c` is split into (3, 3, 3)-bit c_lo, c_mid, c_hi. - meta.create_gate("decompose ABCD", |meta| { - let s_decompose_abcd = meta.query_selector(s_decompose_abcd); - let a = meta.query_advice(a_3, Rotation::next()); // 2-bit chunk - let spread_a = meta.query_advice(a_4, Rotation::next()); - let b = meta.query_advice(a_1, Rotation::cur()); // 11-bit chunk - let spread_b = meta.query_advice(a_2, Rotation::cur()); - let tag_b = meta.query_advice(a_0, Rotation::cur()); - let c_lo = meta.query_advice(a_3, Rotation::cur()); // 3-bit chunk - let spread_c_lo = meta.query_advice(a_4, Rotation::cur()); - let c_mid = meta.query_advice(a_5, Rotation::cur()); // 3-bit chunk - let spread_c_mid = meta.query_advice(a_6, Rotation::cur()); - let c_hi = meta.query_advice(a_5, Rotation::next()); // 3-bit chunk - let spread_c_hi = meta.query_advice(a_6, Rotation::next()); - let d = meta.query_advice(a_1, Rotation::next()); // 7-bit chunk - let spread_d = meta.query_advice(a_2, Rotation::next()); - let tag_d = meta.query_advice(a_0, Rotation::next()); - let word_lo = meta.query_advice(a_7, Rotation::cur()); - let spread_word_lo = meta.query_advice(a_8, Rotation::cur()); - let word_hi = meta.query_advice(a_7, Rotation::next()); - let spread_word_hi = meta.query_advice(a_8, Rotation::next()); - - CompressionGate::s_decompose_abcd( - s_decompose_abcd, - a, - spread_a, - b, - spread_b, - tag_b, - c_lo, - spread_c_lo, - c_mid, - spread_c_mid, - c_hi, - spread_c_hi, - d, - spread_d, - tag_d, - word_lo, - spread_word_lo, - word_hi, - spread_word_hi, - ) - }); - - // Decompose `E,F,G,H` words into (6, 5, 14, 7)-bit chunks. - // `a` is split into (3, 3)-bit a_lo, a_hi - // `b` is split into (2, 3)-bit b_lo, b_hi - meta.create_gate("Decompose EFGH", |meta| { - let s_decompose_efgh = meta.query_selector(s_decompose_efgh); - let a_lo = meta.query_advice(a_3, Rotation::next()); // 3-bit chunk - let spread_a_lo = meta.query_advice(a_4, Rotation::next()); - let a_hi = meta.query_advice(a_5, Rotation::next()); // 3-bit chunk - let spread_a_hi = meta.query_advice(a_6, Rotation::next()); - let b_lo = meta.query_advice(a_3, Rotation::cur()); // 2-bit chunk - let spread_b_lo = meta.query_advice(a_4, Rotation::cur()); - let b_hi = meta.query_advice(a_5, Rotation::cur()); // 3-bit chunk - let spread_b_hi = meta.query_advice(a_6, Rotation::cur()); - let c = meta.query_advice(a_1, Rotation::next()); // 14-bit chunk - let spread_c = meta.query_advice(a_2, Rotation::next()); - let tag_c = meta.query_advice(a_0, Rotation::next()); - let d = meta.query_advice(a_1, Rotation::cur()); // 7-bit chunk - let spread_d = meta.query_advice(a_2, Rotation::cur()); - let tag_d = meta.query_advice(a_0, Rotation::cur()); - let word_lo = meta.query_advice(a_7, Rotation::cur()); - let spread_word_lo = meta.query_advice(a_8, Rotation::cur()); - let word_hi = meta.query_advice(a_7, Rotation::next()); - let spread_word_hi = meta.query_advice(a_8, Rotation::next()); - - CompressionGate::s_decompose_efgh( - s_decompose_efgh, - a_lo, - spread_a_lo, - a_hi, - spread_a_hi, - b_lo, - spread_b_lo, - b_hi, - spread_b_hi, - c, - spread_c, - tag_c, - d, - spread_d, - tag_d, - word_lo, - spread_word_lo, - word_hi, - spread_word_hi, - ) - }); - - // s_upper_sigma_0 on abcd words - // (2, 11, 9, 10)-bit chunks - meta.create_gate("s_upper_sigma_0", |meta| { - let s_upper_sigma_0 = meta.query_selector(s_upper_sigma_0); - let spread_r0_even = meta.query_advice(a_2, Rotation::prev()); - let spread_r0_odd = meta.query_advice(a_2, Rotation::cur()); - let spread_r1_even = meta.query_advice(a_2, Rotation::next()); - let spread_r1_odd = meta.query_advice(a_3, Rotation::cur()); - - let spread_a = meta.query_advice(a_3, Rotation::next()); - let spread_b = meta.query_advice(a_5, Rotation::cur()); - let spread_c_lo = meta.query_advice(a_3, Rotation::prev()); - let spread_c_mid = meta.query_advice(a_4, Rotation::prev()); - let spread_c_hi = meta.query_advice(a_4, Rotation::next()); - let spread_d = meta.query_advice(a_4, Rotation::cur()); - - CompressionGate::s_upper_sigma_0( - s_upper_sigma_0, - spread_r0_even, - spread_r0_odd, - spread_r1_even, - spread_r1_odd, - spread_a, - spread_b, - spread_c_lo, - spread_c_mid, - spread_c_hi, - spread_d, - ) - }); - - // s_upper_sigma_1 on efgh words - // (6, 5, 14, 7)-bit chunks - meta.create_gate("s_upper_sigma_1", |meta| { - let s_upper_sigma_1 = meta.query_selector(s_upper_sigma_1); - let spread_r0_even = meta.query_advice(a_2, Rotation::prev()); - let spread_r0_odd = meta.query_advice(a_2, Rotation::cur()); - let spread_r1_even = meta.query_advice(a_2, Rotation::next()); - let spread_r1_odd = meta.query_advice(a_3, Rotation::cur()); - let spread_a_lo = meta.query_advice(a_3, Rotation::next()); - let spread_a_hi = meta.query_advice(a_4, Rotation::next()); - let spread_b_lo = meta.query_advice(a_3, Rotation::prev()); - let spread_b_hi = meta.query_advice(a_4, Rotation::prev()); - let spread_c = meta.query_advice(a_5, Rotation::cur()); - let spread_d = meta.query_advice(a_4, Rotation::cur()); - - CompressionGate::s_upper_sigma_1( - s_upper_sigma_1, - spread_r0_even, - spread_r0_odd, - spread_r1_even, - spread_r1_odd, - spread_a_lo, - spread_a_hi, - spread_b_lo, - spread_b_hi, - spread_c, - spread_d, - ) - }); - - // s_ch on efgh words - // First part of choice gate on (E, F, G), E ∧ F - meta.create_gate("s_ch", |meta| { - let s_ch = meta.query_selector(s_ch); - let spread_p0_even = meta.query_advice(a_2, Rotation::prev()); - let spread_p0_odd = meta.query_advice(a_2, Rotation::cur()); - let spread_p1_even = meta.query_advice(a_2, Rotation::next()); - let spread_p1_odd = meta.query_advice(a_3, Rotation::cur()); - let spread_e_lo = meta.query_advice(a_3, Rotation::prev()); - let spread_e_hi = meta.query_advice(a_4, Rotation::prev()); - let spread_f_lo = meta.query_advice(a_3, Rotation::next()); - let spread_f_hi = meta.query_advice(a_4, Rotation::next()); - - CompressionGate::s_ch( - s_ch, - spread_p0_even, - spread_p0_odd, - spread_p1_even, - spread_p1_odd, - spread_e_lo, - spread_e_hi, - spread_f_lo, - spread_f_hi, - ) - }); - - // s_ch_neg on efgh words - // Second part of Choice gate on (E, F, G), ¬E ∧ G - meta.create_gate("s_ch_neg", |meta| { - let s_ch_neg = meta.query_selector(s_ch_neg); - let spread_q0_even = meta.query_advice(a_2, Rotation::prev()); - let spread_q0_odd = meta.query_advice(a_2, Rotation::cur()); - let spread_q1_even = meta.query_advice(a_2, Rotation::next()); - let spread_q1_odd = meta.query_advice(a_3, Rotation::cur()); - let spread_e_lo = meta.query_advice(a_5, Rotation::prev()); - let spread_e_hi = meta.query_advice(a_5, Rotation::cur()); - let spread_e_neg_lo = meta.query_advice(a_3, Rotation::prev()); - let spread_e_neg_hi = meta.query_advice(a_4, Rotation::prev()); - let spread_g_lo = meta.query_advice(a_3, Rotation::next()); - let spread_g_hi = meta.query_advice(a_4, Rotation::next()); - - CompressionGate::s_ch_neg( - s_ch_neg, - spread_q0_even, - spread_q0_odd, - spread_q1_even, - spread_q1_odd, - spread_e_lo, - spread_e_hi, - spread_e_neg_lo, - spread_e_neg_hi, - spread_g_lo, - spread_g_hi, - ) - }); - - // s_maj on abcd words - meta.create_gate("s_maj", |meta| { - let s_maj = meta.query_selector(s_maj); - let spread_m0_even = meta.query_advice(a_2, Rotation::prev()); - let spread_m0_odd = meta.query_advice(a_2, Rotation::cur()); - let spread_m1_even = meta.query_advice(a_2, Rotation::next()); - let spread_m1_odd = meta.query_advice(a_3, Rotation::cur()); - let spread_a_lo = meta.query_advice(a_4, Rotation::prev()); - let spread_a_hi = meta.query_advice(a_5, Rotation::prev()); - let spread_b_lo = meta.query_advice(a_4, Rotation::cur()); - let spread_b_hi = meta.query_advice(a_5, Rotation::cur()); - let spread_c_lo = meta.query_advice(a_4, Rotation::next()); - let spread_c_hi = meta.query_advice(a_5, Rotation::next()); - - CompressionGate::s_maj( - s_maj, - spread_m0_even, - spread_m0_odd, - spread_m1_even, - spread_m1_odd, - spread_a_lo, - spread_a_hi, - spread_b_lo, - spread_b_hi, - spread_c_lo, - spread_c_hi, - ) - }); - - // s_h_prime to compute H' = H + Ch(E, F, G) + s_upper_sigma_1(E) + K + W - meta.create_gate("s_h_prime", |meta| { - let s_h_prime = meta.query_selector(s_h_prime); - let h_prime_lo = meta.query_advice(a_7, Rotation::next()); - let h_prime_hi = meta.query_advice(a_8, Rotation::next()); - let h_prime_carry = meta.query_advice(a_9, Rotation::next()); - let sigma_e_lo = meta.query_advice(a_4, Rotation::cur()); - let sigma_e_hi = meta.query_advice(a_5, Rotation::cur()); - let ch_lo = meta.query_advice(a_1, Rotation::cur()); - let ch_hi = meta.query_advice(a_6, Rotation::next()); - let ch_neg_lo = meta.query_advice(a_5, Rotation::prev()); - let ch_neg_hi = meta.query_advice(a_5, Rotation::next()); - let h_lo = meta.query_advice(a_7, Rotation::prev()); - let h_hi = meta.query_advice(a_7, Rotation::cur()); - let k_lo = meta.query_advice(a_6, Rotation::prev()); - let k_hi = meta.query_advice(a_6, Rotation::cur()); - let w_lo = meta.query_advice(a_8, Rotation::prev()); - let w_hi = meta.query_advice(a_8, Rotation::cur()); - - CompressionGate::s_h_prime( - s_h_prime, - h_prime_lo, - h_prime_hi, - h_prime_carry, - sigma_e_lo, - sigma_e_hi, - ch_lo, - ch_hi, - ch_neg_lo, - ch_neg_hi, - h_lo, - h_hi, - k_lo, - k_hi, - w_lo, - w_hi, - ) - }); - - // s_a_new - meta.create_gate("s_a_new", |meta| { - let s_a_new = meta.query_selector(s_a_new); - let a_new_lo = meta.query_advice(a_8, Rotation::cur()); - let a_new_hi = meta.query_advice(a_8, Rotation::next()); - let a_new_carry = meta.query_advice(a_9, Rotation::cur()); - let sigma_a_lo = meta.query_advice(a_6, Rotation::cur()); - let sigma_a_hi = meta.query_advice(a_6, Rotation::next()); - let maj_abc_lo = meta.query_advice(a_1, Rotation::cur()); - let maj_abc_hi = meta.query_advice(a_3, Rotation::prev()); - let h_prime_lo = meta.query_advice(a_7, Rotation::prev()); - let h_prime_hi = meta.query_advice(a_8, Rotation::prev()); - - CompressionGate::s_a_new( - s_a_new, - a_new_lo, - a_new_hi, - a_new_carry, - sigma_a_lo, - sigma_a_hi, - maj_abc_lo, - maj_abc_hi, - h_prime_lo, - h_prime_hi, - ) - }); - - // s_e_new - meta.create_gate("s_e_new", |meta| { - let s_e_new = meta.query_selector(s_e_new); - let e_new_lo = meta.query_advice(a_8, Rotation::cur()); - let e_new_hi = meta.query_advice(a_8, Rotation::next()); - let e_new_carry = meta.query_advice(a_9, Rotation::next()); - let d_lo = meta.query_advice(a_7, Rotation::cur()); - let d_hi = meta.query_advice(a_7, Rotation::next()); - let h_prime_lo = meta.query_advice(a_7, Rotation::prev()); - let h_prime_hi = meta.query_advice(a_8, Rotation::prev()); - - CompressionGate::s_e_new( - s_e_new, - e_new_lo, - e_new_hi, - e_new_carry, - d_lo, - d_hi, - h_prime_lo, - h_prime_hi, - ) - }); - - // s_digest for final round - meta.create_gate("s_digest", |meta| { - let s_digest = meta.query_selector(s_digest); - let lo_0 = meta.query_advice(a_3, Rotation::cur()); - let hi_0 = meta.query_advice(a_4, Rotation::cur()); - let word_0 = meta.query_advice(a_5, Rotation::cur()); - let lo_1 = meta.query_advice(a_6, Rotation::cur()); - let hi_1 = meta.query_advice(a_7, Rotation::cur()); - let word_1 = meta.query_advice(a_8, Rotation::cur()); - let lo_2 = meta.query_advice(a_3, Rotation::next()); - let hi_2 = meta.query_advice(a_4, Rotation::next()); - let word_2 = meta.query_advice(a_5, Rotation::next()); - let lo_3 = meta.query_advice(a_6, Rotation::next()); - let hi_3 = meta.query_advice(a_7, Rotation::next()); - let word_3 = meta.query_advice(a_8, Rotation::next()); - - CompressionGate::s_digest( - s_digest, lo_0, hi_0, word_0, lo_1, hi_1, word_1, lo_2, hi_2, word_2, lo_3, hi_3, - word_3, - ) - }); - - CompressionConfig { - lookup, - message_schedule, - extras, - s_ch, - s_ch_neg, - s_maj, - s_h_prime, - s_a_new, - s_e_new, - s_upper_sigma_0, - s_upper_sigma_1, - s_decompose_abcd, - s_decompose_efgh, - s_digest, - } - } - - /// Initialize compression with a constant Initialization Vector of 32-byte words. - /// Returns an initialized state. - pub(super) fn initialize_with_iv( - &self, - layouter: &mut impl Layouter, - init_state: [u32; STATE], - ) -> Result { - let mut new_state = State::empty_state(); - layouter.assign_region( - || "initialize_with_iv", - |mut region| { - new_state = self.initialize_iv(&mut region, init_state)?; - Ok(()) - }, - )?; - Ok(new_state) - } - - /// Initialize compression with some initialized state. This could be a state - /// output from a previous compression round. - pub(super) fn initialize_with_state( - &self, - layouter: &mut impl Layouter, - init_state: State, - ) -> Result { - let mut new_state = State::empty_state(); - layouter.assign_region( - || "initialize_with_state", - |mut region| { - new_state = self.initialize_state(&mut region, init_state.clone())?; - Ok(()) - }, - )?; - Ok(new_state) - } - - /// Given an initialized state and a message schedule, perform 64 compression rounds. - pub(super) fn compress( - &self, - layouter: &mut impl Layouter, - initialized_state: State, - w_halves: [(AssignedBits<16>, AssignedBits<16>); ROUNDS], - ) -> Result { - let mut state = State::empty_state(); - layouter.assign_region( - || "compress", - |mut region| { - state = initialized_state.clone(); - for (idx, w_halves) in w_halves.iter().enumerate() { - state = self.assign_round(&mut region, idx.into(), state.clone(), w_halves)?; - } - Ok(()) - }, - )?; - Ok(state) - } - - /// After the final round, convert the state into the final digest. - pub(super) fn digest( - &self, - layouter: &mut impl Layouter, - state: State, - ) -> Result<[BlockWord; DIGEST_SIZE], Error> { - let mut digest = [BlockWord(Value::known(0)); DIGEST_SIZE]; - layouter.assign_region( - || "digest", - |mut region| { - digest = self.assign_digest(&mut region, state.clone())?; - - Ok(()) - }, - )?; - Ok(digest) - } -} - -#[cfg(test)] -mod tests { - use super::super::{ - super::BLOCK_SIZE, msg_schedule_test_input, BlockWord, Table16Chip, Table16Config, IV, - }; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use halo2curves::pasta::pallas; - - #[test] - fn compress() { - struct MyCircuit {} - - impl Circuit for MyCircuit { - type Config = Table16Config; - type FloorPlanner = SimpleFloorPlanner; - #[cfg(feature = "circuit-params")] - type Params = (); - - fn without_witnesses(&self) -> Self { - MyCircuit {} - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - Table16Chip::configure(meta) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - Table16Chip::load(config.clone(), &mut layouter)?; - - // Test vector: "abc" - let input: [BlockWord; BLOCK_SIZE] = msg_schedule_test_input(); - - let (_, w_halves) = config.message_schedule.process(&mut layouter, input)?; - - let compression = config.compression.clone(); - let initial_state = compression.initialize_with_iv(&mut layouter, IV)?; - - let state = config - .compression - .compress(&mut layouter, initial_state, w_halves)?; - - let digest = config.compression.digest(&mut layouter, state)?; - for (idx, digest_word) in digest.iter().enumerate() { - digest_word.0.assert_if_known(|digest_word| { - (*digest_word as u64 + IV[idx] as u64) as u32 - == super::compression_util::COMPRESSION_OUTPUT[idx] - }); - } - - Ok(()) - } - } - - let circuit: MyCircuit = MyCircuit {}; - - let prover = match MockProver::::run(17, &circuit, vec![]) { - Ok(prover) => prover, - Err(e) => panic!("{:?}", e), - }; - assert_eq!(prover.verify(), Ok(())); - } -} diff --git a/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs b/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs deleted file mode 100644 index 1cf6a605d7..0000000000 --- a/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs +++ /dev/null @@ -1,442 +0,0 @@ -use super::super::{util::*, Gate}; -use ff::PrimeField; -use halo2_proofs::plonk::{Constraint, Constraints, Expression}; -use std::marker::PhantomData; - -pub struct CompressionGate(PhantomData); - -impl CompressionGate { - fn ones() -> Expression { - Expression::Constant(F::ONE) - } - - // Decompose `A,B,C,D` words - // (2, 11, 9, 10)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_decompose_abcd( - s_decompose_abcd: Expression, - a: Expression, - spread_a: Expression, - b: Expression, - spread_b: Expression, - tag_b: Expression, - c_lo: Expression, - spread_c_lo: Expression, - c_mid: Expression, - spread_c_mid: Expression, - c_hi: Expression, - spread_c_hi: Expression, - d: Expression, - spread_d: Expression, - tag_d: Expression, - word_lo: Expression, - spread_word_lo: Expression, - word_hi: Expression, - spread_word_hi: Expression, - ) -> Constraints< - F, - (&'static str, Expression), - impl Iterator)>, - > { - let check_spread_and_range = - Gate::three_bit_spread_and_range(c_lo.clone(), spread_c_lo.clone()) - .chain(Gate::three_bit_spread_and_range( - c_mid.clone(), - spread_c_mid.clone(), - )) - .chain(Gate::three_bit_spread_and_range( - c_hi.clone(), - spread_c_hi.clone(), - )) - .chain(Gate::two_bit_spread_and_range(a.clone(), spread_a.clone())); - let range_check_tag_b = Gate::range_check(tag_b, 0, 2); - let range_check_tag_d = Gate::range_check(tag_d, 0, 1); - let dense_check = a - + b * F::from(1 << 2) - + c_lo * F::from(1 << 13) - + c_mid * F::from(1 << 16) - + c_hi * F::from(1 << 19) - + d * F::from(1 << 22) - + word_lo * (-F::ONE) - + word_hi * F::from(1 << 16) * (-F::ONE); - let spread_check = spread_a - + spread_b * F::from(1 << 4) - + spread_c_lo * F::from(1 << 26) - + spread_c_mid * F::from(1 << 32) - + spread_c_hi * F::from(1 << 38) - + spread_d * F::from(1 << 44) - + spread_word_lo * (-F::ONE) - + spread_word_hi * F::from(1 << 32) * (-F::ONE); - - Constraints::with_selector( - s_decompose_abcd, - check_spread_and_range - .chain(Some(("range_check_tag_b", range_check_tag_b))) - .chain(Some(("range_check_tag_d", range_check_tag_d))) - .chain(Some(("dense_check", dense_check))) - .chain(Some(("spread_check", spread_check))), - ) - } - - // Decompose `E,F,G,H` words - // (6, 5, 14, 7)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_decompose_efgh( - s_decompose_efgh: Expression, - a_lo: Expression, - spread_a_lo: Expression, - a_hi: Expression, - spread_a_hi: Expression, - b_lo: Expression, - spread_b_lo: Expression, - b_hi: Expression, - spread_b_hi: Expression, - c: Expression, - spread_c: Expression, - tag_c: Expression, - d: Expression, - spread_d: Expression, - tag_d: Expression, - word_lo: Expression, - spread_word_lo: Expression, - word_hi: Expression, - spread_word_hi: Expression, - ) -> Constraints< - F, - (&'static str, Expression), - impl Iterator)>, - > { - let check_spread_and_range = - Gate::three_bit_spread_and_range(a_lo.clone(), spread_a_lo.clone()) - .chain(Gate::three_bit_spread_and_range( - a_hi.clone(), - spread_a_hi.clone(), - )) - .chain(Gate::three_bit_spread_and_range( - b_hi.clone(), - spread_b_hi.clone(), - )) - .chain(Gate::two_bit_spread_and_range( - b_lo.clone(), - spread_b_lo.clone(), - )); - let range_check_tag_c = Gate::range_check(tag_c, 0, 4); - let range_check_tag_d = Gate::range_check(tag_d, 0, 0); - let dense_check = a_lo - + a_hi * F::from(1 << 3) - + b_lo * F::from(1 << 6) - + b_hi * F::from(1 << 8) - + c * F::from(1 << 11) - + d * F::from(1 << 25) - + word_lo * (-F::ONE) - + word_hi * F::from(1 << 16) * (-F::ONE); - let spread_check = spread_a_lo - + spread_a_hi * F::from(1 << 6) - + spread_b_lo * F::from(1 << 12) - + spread_b_hi * F::from(1 << 16) - + spread_c * F::from(1 << 22) - + spread_d * F::from(1 << 50) - + spread_word_lo * (-F::ONE) - + spread_word_hi * F::from(1 << 32) * (-F::ONE); - - Constraints::with_selector( - s_decompose_efgh, - check_spread_and_range - .chain(Some(("range_check_tag_c", range_check_tag_c))) - .chain(Some(("range_check_tag_d", range_check_tag_d))) - .chain(Some(("dense_check", dense_check))) - .chain(Some(("spread_check", spread_check))), - ) - } - - // s_upper_sigma_0 on abcd words - // (2, 11, 9, 10)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_upper_sigma_0( - s_upper_sigma_0: Expression, - spread_r0_even: Expression, - spread_r0_odd: Expression, - spread_r1_even: Expression, - spread_r1_odd: Expression, - spread_a: Expression, - spread_b: Expression, - spread_c_lo: Expression, - spread_c_mid: Expression, - spread_c_hi: Expression, - spread_d: Expression, - ) -> Option<(&'static str, Expression)> { - let spread_witness = spread_r0_even - + spread_r0_odd * F::from(2) - + (spread_r1_even + spread_r1_odd * F::from(2)) * F::from(1 << 32); - let xor_0 = spread_b.clone() - + spread_c_lo.clone() * F::from(1 << 22) - + spread_c_mid.clone() * F::from(1 << 28) - + spread_c_hi.clone() * F::from(1 << 34) - + spread_d.clone() * F::from(1 << 40) - + spread_a.clone() * F::from(1 << 60); - let xor_1 = spread_c_lo.clone() - + spread_c_mid.clone() * F::from(1 << 6) - + spread_c_hi.clone() * F::from(1 << 12) - + spread_d.clone() * F::from(1 << 18) - + spread_a.clone() * F::from(1 << 38) - + spread_b.clone() * F::from(1 << 42); - let xor_2 = spread_d - + spread_a * F::from(1 << 20) - + spread_b * F::from(1 << 24) - + spread_c_lo * F::from(1 << 46) - + spread_c_mid * F::from(1 << 52) - + spread_c_hi * F::from(1 << 58); - let xor = xor_0 + xor_1 + xor_2; - let check = spread_witness + (xor * -F::ONE); - - Some(("s_upper_sigma_0", s_upper_sigma_0 * check)) - } - - // s_upper_sigma_1 on efgh words - // (6, 5, 14, 7)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_upper_sigma_1( - s_upper_sigma_1: Expression, - spread_r0_even: Expression, - spread_r0_odd: Expression, - spread_r1_even: Expression, - spread_r1_odd: Expression, - spread_a_lo: Expression, - spread_a_hi: Expression, - spread_b_lo: Expression, - spread_b_hi: Expression, - spread_c: Expression, - spread_d: Expression, - ) -> Option<(&'static str, Expression)> { - let spread_witness = spread_r0_even - + spread_r0_odd * F::from(2) - + (spread_r1_even + spread_r1_odd * F::from(2)) * F::from(1 << 32); - - let xor_0 = spread_b_lo.clone() - + spread_b_hi.clone() * F::from(1 << 4) - + spread_c.clone() * F::from(1 << 10) - + spread_d.clone() * F::from(1 << 38) - + spread_a_lo.clone() * F::from(1 << 52) - + spread_a_hi.clone() * F::from(1 << 58); - let xor_1 = spread_c.clone() - + spread_d.clone() * F::from(1 << 28) - + spread_a_lo.clone() * F::from(1 << 42) - + spread_a_hi.clone() * F::from(1 << 48) - + spread_b_lo.clone() * F::from(1 << 54) - + spread_b_hi.clone() * F::from(1 << 58); - let xor_2 = spread_d - + spread_a_lo * F::from(1 << 14) - + spread_a_hi * F::from(1 << 20) - + spread_b_lo * F::from(1 << 26) - + spread_b_hi * F::from(1 << 30) - + spread_c * F::from(1 << 36); - let xor = xor_0 + xor_1 + xor_2; - let check = spread_witness + (xor * -F::ONE); - - Some(("s_upper_sigma_1", s_upper_sigma_1 * check)) - } - - // First part of choice gate on (E, F, G), E ∧ F - #[allow(clippy::too_many_arguments)] - pub fn s_ch( - s_ch: Expression, - spread_p0_even: Expression, - spread_p0_odd: Expression, - spread_p1_even: Expression, - spread_p1_odd: Expression, - spread_e_lo: Expression, - spread_e_hi: Expression, - spread_f_lo: Expression, - spread_f_hi: Expression, - ) -> Option<(&'static str, Expression)> { - let lhs_lo = spread_e_lo + spread_f_lo; - let lhs_hi = spread_e_hi + spread_f_hi; - let lhs = lhs_lo + lhs_hi * F::from(1 << 32); - - let rhs_even = spread_p0_even + spread_p1_even * F::from(1 << 32); - let rhs_odd = spread_p0_odd + spread_p1_odd * F::from(1 << 32); - let rhs = rhs_even + rhs_odd * F::from(2); - - let check = lhs + rhs * -F::ONE; - - Some(("s_ch", s_ch * check)) - } - - // Second part of Choice gate on (E, F, G), ¬E ∧ G - #[allow(clippy::too_many_arguments)] - pub fn s_ch_neg( - s_ch_neg: Expression, - spread_q0_even: Expression, - spread_q0_odd: Expression, - spread_q1_even: Expression, - spread_q1_odd: Expression, - spread_e_lo: Expression, - spread_e_hi: Expression, - spread_e_neg_lo: Expression, - spread_e_neg_hi: Expression, - spread_g_lo: Expression, - spread_g_hi: Expression, - ) -> Constraints< - F, - (&'static str, Expression), - impl Iterator)>, - > { - let neg_check = { - let evens = Self::ones() * F::from(MASK_EVEN_32 as u64); - // evens - spread_e_lo = spread_e_neg_lo - let lo_check = spread_e_neg_lo.clone() + spread_e_lo + (evens.clone() * (-F::ONE)); - // evens - spread_e_hi = spread_e_neg_hi - let hi_check = spread_e_neg_hi.clone() + spread_e_hi + (evens * (-F::ONE)); - - std::iter::empty() - .chain(Some(("lo_check", lo_check))) - .chain(Some(("hi_check", hi_check))) - }; - - let lhs_lo = spread_e_neg_lo + spread_g_lo; - let lhs_hi = spread_e_neg_hi + spread_g_hi; - let lhs = lhs_lo + lhs_hi * F::from(1 << 32); - - let rhs_even = spread_q0_even + spread_q1_even * F::from(1 << 32); - let rhs_odd = spread_q0_odd + spread_q1_odd * F::from(1 << 32); - let rhs = rhs_even + rhs_odd * F::from(2); - - Constraints::with_selector(s_ch_neg, neg_check.chain(Some(("s_ch_neg", lhs - rhs)))) - } - - // Majority gate on (A, B, C) - #[allow(clippy::too_many_arguments)] - pub fn s_maj( - s_maj: Expression, - spread_m_0_even: Expression, - spread_m_0_odd: Expression, - spread_m_1_even: Expression, - spread_m_1_odd: Expression, - spread_a_lo: Expression, - spread_a_hi: Expression, - spread_b_lo: Expression, - spread_b_hi: Expression, - spread_c_lo: Expression, - spread_c_hi: Expression, - ) -> Option<(&'static str, Expression)> { - let maj_even = spread_m_0_even + spread_m_1_even * F::from(1 << 32); - let maj_odd = spread_m_0_odd + spread_m_1_odd * F::from(1 << 32); - let maj = maj_even + maj_odd * F::from(2); - - let a = spread_a_lo + spread_a_hi * F::from(1 << 32); - let b = spread_b_lo + spread_b_hi * F::from(1 << 32); - let c = spread_c_lo + spread_c_hi * F::from(1 << 32); - let sum = a + b + c; - - Some(("maj", s_maj * (sum - maj))) - } - - // s_h_prime to get H' = H + Ch(E, F, G) + s_upper_sigma_1(E) + K + W - #[allow(clippy::too_many_arguments)] - pub fn s_h_prime( - s_h_prime: Expression, - h_prime_lo: Expression, - h_prime_hi: Expression, - h_prime_carry: Expression, - sigma_e_lo: Expression, - sigma_e_hi: Expression, - ch_lo: Expression, - ch_hi: Expression, - ch_neg_lo: Expression, - ch_neg_hi: Expression, - h_lo: Expression, - h_hi: Expression, - k_lo: Expression, - k_hi: Expression, - w_lo: Expression, - w_hi: Expression, - ) -> Option<(&'static str, Expression)> { - let lo = h_lo + ch_lo + ch_neg_lo + sigma_e_lo + k_lo + w_lo; - let hi = h_hi + ch_hi + ch_neg_hi + sigma_e_hi + k_hi + w_hi; - - let sum = lo + hi * F::from(1 << 16); - let h_prime = h_prime_lo + h_prime_hi * F::from(1 << 16); - - let check = sum - (h_prime_carry * F::from(1 << 32)) - h_prime; - - Some(("s_h_prime", s_h_prime * check)) - } - - // s_a_new to get A_new = H' + Maj(A, B, C) + s_upper_sigma_0(A) - #[allow(clippy::too_many_arguments)] - pub fn s_a_new( - s_a_new: Expression, - a_new_lo: Expression, - a_new_hi: Expression, - a_new_carry: Expression, - sigma_a_lo: Expression, - sigma_a_hi: Expression, - maj_abc_lo: Expression, - maj_abc_hi: Expression, - h_prime_lo: Expression, - h_prime_hi: Expression, - ) -> Option<(&'static str, Expression)> { - let lo = sigma_a_lo + maj_abc_lo + h_prime_lo; - let hi = sigma_a_hi + maj_abc_hi + h_prime_hi; - let sum = lo + hi * F::from(1 << 16); - let a_new = a_new_lo + a_new_hi * F::from(1 << 16); - - let check = sum - (a_new_carry * F::from(1 << 32)) - a_new; - - Some(("s_a_new", s_a_new * check)) - } - - // s_e_new to get E_new = H' + D - #[allow(clippy::too_many_arguments)] - pub fn s_e_new( - s_e_new: Expression, - e_new_lo: Expression, - e_new_hi: Expression, - e_new_carry: Expression, - d_lo: Expression, - d_hi: Expression, - h_prime_lo: Expression, - h_prime_hi: Expression, - ) -> Option<(&'static str, Expression)> { - let lo = h_prime_lo + d_lo; - let hi = h_prime_hi + d_hi; - let sum = lo + hi * F::from(1 << 16); - let e_new = e_new_lo + e_new_hi * F::from(1 << 16); - - let check = sum - (e_new_carry * F::from(1 << 32)) - e_new; - - Some(("s_e_new", s_e_new * check)) - } - - // s_digest on final round - #[allow(clippy::too_many_arguments)] - pub fn s_digest( - s_digest: Expression, - lo_0: Expression, - hi_0: Expression, - word_0: Expression, - lo_1: Expression, - hi_1: Expression, - word_1: Expression, - lo_2: Expression, - hi_2: Expression, - word_2: Expression, - lo_3: Expression, - hi_3: Expression, - word_3: Expression, - ) -> impl IntoIterator> { - let check_lo_hi = |lo: Expression, hi: Expression, word: Expression| { - lo + hi * F::from(1 << 16) - word - }; - - Constraints::with_selector( - s_digest, - [ - ("check_lo_hi_0", check_lo_hi(lo_0, hi_0, word_0)), - ("check_lo_hi_1", check_lo_hi(lo_1, hi_1, word_1)), - ("check_lo_hi_2", check_lo_hi(lo_2, hi_2, word_2)), - ("check_lo_hi_3", check_lo_hi(lo_3, hi_3, word_3)), - ], - ) - } -} diff --git a/halo2_gadgets/src/sha256/table16/compression/compression_util.rs b/halo2_gadgets/src/sha256/table16/compression/compression_util.rs deleted file mode 100644 index 99706023df..0000000000 --- a/halo2_gadgets/src/sha256/table16/compression/compression_util.rs +++ /dev/null @@ -1,991 +0,0 @@ -use super::{ - AbcdVar, CompressionConfig, EfghVar, RoundWord, RoundWordA, RoundWordDense, RoundWordE, - RoundWordSpread, State, UpperSigmaVar, -}; -use crate::sha256::table16::{ - util::*, AssignedBits, SpreadVar, SpreadWord, StateWord, Table16Assignment, -}; -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::{Advice, Column, Error}, -}; -use halo2curves::pasta::pallas; -use std::convert::TryInto; - -// Test vector 'abc' -#[cfg(test)] -pub const COMPRESSION_OUTPUT: [u32; 8] = [ - 0b10111010011110000001011010111111, - 0b10001111000000011100111111101010, - 0b01000001010000010100000011011110, - 0b01011101101011100010001000100011, - 0b10110000000000110110000110100011, - 0b10010110000101110111101010011100, - 0b10110100000100001111111101100001, - 0b11110010000000000001010110101101, -]; - -// Rows needed for each gate -pub const SIGMA_0_ROWS: usize = 4; -pub const SIGMA_1_ROWS: usize = 4; -pub const CH_ROWS: usize = 8; -pub const MAJ_ROWS: usize = 4; -pub const DECOMPOSE_ABCD: usize = 2; -pub const DECOMPOSE_EFGH: usize = 2; - -// Rows needed for main subregion -pub const SUBREGION_MAIN_LEN: usize = 64; -pub const SUBREGION_MAIN_WORD: usize = - DECOMPOSE_ABCD + SIGMA_0_ROWS + DECOMPOSE_EFGH + SIGMA_1_ROWS + CH_ROWS + MAJ_ROWS; -pub const SUBREGION_MAIN_ROWS: usize = SUBREGION_MAIN_LEN * SUBREGION_MAIN_WORD; - -/// The initial round. -pub struct InitialRound; - -/// A main round index. -#[derive(Debug, Copy, Clone)] -pub struct MainRoundIdx(usize); - -/// Round index. -#[derive(Debug, Copy, Clone)] -pub enum RoundIdx { - Init, - Main(MainRoundIdx), -} - -impl From for RoundIdx { - fn from(_: InitialRound) -> Self { - RoundIdx::Init - } -} - -impl From for RoundIdx { - fn from(idx: MainRoundIdx) -> Self { - RoundIdx::Main(idx) - } -} - -impl MainRoundIdx { - pub(crate) fn as_usize(&self) -> usize { - self.0 - } -} - -impl From for MainRoundIdx { - fn from(idx: usize) -> Self { - MainRoundIdx(idx) - } -} - -impl std::ops::Add for MainRoundIdx { - type Output = Self; - - fn add(self, rhs: usize) -> Self::Output { - MainRoundIdx(self.0 + rhs) - } -} - -impl Ord for MainRoundIdx { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.0.cmp(&other.0) - } -} - -impl PartialOrd for MainRoundIdx { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl PartialEq for MainRoundIdx { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} - -impl Eq for MainRoundIdx {} - -/// Returns starting row number of a compression round -pub fn get_round_row(round_idx: RoundIdx) -> usize { - match round_idx { - RoundIdx::Init => 0, - RoundIdx::Main(MainRoundIdx(idx)) => { - assert!(idx < 64); - idx * SUBREGION_MAIN_WORD - } - } -} - -pub fn get_decompose_e_row(round_idx: RoundIdx) -> usize { - get_round_row(round_idx) -} - -pub fn get_decompose_f_row(round_idx: InitialRound) -> usize { - get_decompose_e_row(round_idx.into()) + DECOMPOSE_EFGH -} - -pub fn get_decompose_g_row(round_idx: InitialRound) -> usize { - get_decompose_f_row(round_idx) + DECOMPOSE_EFGH -} - -pub fn get_upper_sigma_1_row(round_idx: MainRoundIdx) -> usize { - get_decompose_e_row(round_idx.into()) + DECOMPOSE_EFGH + 1 -} - -pub fn get_ch_row(round_idx: MainRoundIdx) -> usize { - get_decompose_e_row(round_idx.into()) + DECOMPOSE_EFGH + SIGMA_1_ROWS + 1 -} - -pub fn get_ch_neg_row(round_idx: MainRoundIdx) -> usize { - get_ch_row(round_idx) + CH_ROWS / 2 -} - -pub fn get_decompose_a_row(round_idx: RoundIdx) -> usize { - match round_idx { - RoundIdx::Init => get_h_row(round_idx) + DECOMPOSE_EFGH, - RoundIdx::Main(mri) => get_ch_neg_row(mri) - 1 + CH_ROWS / 2, - } -} - -pub fn get_upper_sigma_0_row(round_idx: MainRoundIdx) -> usize { - get_decompose_a_row(round_idx.into()) + DECOMPOSE_ABCD + 1 -} - -pub fn get_decompose_b_row(round_idx: InitialRound) -> usize { - get_decompose_a_row(round_idx.into()) + DECOMPOSE_ABCD -} - -pub fn get_decompose_c_row(round_idx: InitialRound) -> usize { - get_decompose_b_row(round_idx) + DECOMPOSE_ABCD -} - -pub fn get_maj_row(round_idx: MainRoundIdx) -> usize { - get_upper_sigma_0_row(round_idx) + SIGMA_0_ROWS -} - -// Get state word rows -pub fn get_h_row(round_idx: RoundIdx) -> usize { - match round_idx { - RoundIdx::Init => get_decompose_g_row(InitialRound) + DECOMPOSE_EFGH, - RoundIdx::Main(mri) => get_ch_row(mri) - 1, - } -} - -pub fn get_h_prime_row(round_idx: MainRoundIdx) -> usize { - get_ch_row(round_idx) -} - -pub fn get_d_row(round_idx: RoundIdx) -> usize { - match round_idx { - RoundIdx::Init => get_decompose_c_row(InitialRound) + DECOMPOSE_ABCD, - RoundIdx::Main(mri) => get_ch_row(mri) + 2, - } -} - -pub fn get_e_new_row(round_idx: MainRoundIdx) -> usize { - get_d_row(round_idx.into()) -} - -pub fn get_a_new_row(round_idx: MainRoundIdx) -> usize { - get_maj_row(round_idx) -} - -pub fn get_digest_abcd_row() -> usize { - SUBREGION_MAIN_ROWS -} - -pub fn get_digest_efgh_row() -> usize { - get_digest_abcd_row() + 2 -} - -impl CompressionConfig { - pub(super) fn decompose_abcd( - &self, - region: &mut Region<'_, pallas::Base>, - row: usize, - val: Value, - ) -> Result { - self.s_decompose_abcd.enable(region, row)?; - - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - - let spread_pieces = val.map(AbcdVar::pieces); - let spread_pieces = spread_pieces.transpose_vec(6); - - let a = SpreadVar::without_lookup( - region, - a_3, - row + 1, - a_4, - row + 1, - spread_pieces[0].clone().map(SpreadWord::<2, 4>::try_new), - )?; - let b = SpreadVar::with_lookup( - region, - &self.lookup, - row, - spread_pieces[1].clone().map(SpreadWord::<11, 22>::try_new), - )?; - let c_lo = SpreadVar::without_lookup( - region, - a_3, - row, - a_4, - row, - spread_pieces[2].clone().map(SpreadWord::<3, 6>::try_new), - )?; - let c_mid = SpreadVar::without_lookup( - region, - a_5, - row, - a_6, - row, - spread_pieces[3].clone().map(SpreadWord::<3, 6>::try_new), - )?; - let c_hi = SpreadVar::without_lookup( - region, - a_5, - row + 1, - a_6, - row + 1, - spread_pieces[4].clone().map(SpreadWord::<3, 6>::try_new), - )?; - let d = SpreadVar::with_lookup( - region, - &self.lookup, - row + 1, - spread_pieces[5].clone().map(SpreadWord::<10, 20>::try_new), - )?; - - Ok(AbcdVar { - a, - b, - c_lo, - c_mid, - c_hi, - d, - }) - } - - pub(super) fn decompose_efgh( - &self, - region: &mut Region<'_, pallas::Base>, - row: usize, - val: Value, - ) -> Result { - self.s_decompose_efgh.enable(region, row)?; - - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - - let spread_pieces = val.map(EfghVar::pieces); - let spread_pieces = spread_pieces.transpose_vec(6); - - let a_lo = SpreadVar::without_lookup( - region, - a_3, - row + 1, - a_4, - row + 1, - spread_pieces[0].clone().map(SpreadWord::try_new), - )?; - let a_hi = SpreadVar::without_lookup( - region, - a_5, - row + 1, - a_6, - row + 1, - spread_pieces[1].clone().map(SpreadWord::try_new), - )?; - let b_lo = SpreadVar::without_lookup( - region, - a_3, - row, - a_4, - row, - spread_pieces[2].clone().map(SpreadWord::try_new), - )?; - let b_hi = SpreadVar::without_lookup( - region, - a_5, - row, - a_6, - row, - spread_pieces[3].clone().map(SpreadWord::try_new), - )?; - let c = SpreadVar::with_lookup( - region, - &self.lookup, - row + 1, - spread_pieces[4].clone().map(SpreadWord::try_new), - )?; - let d = SpreadVar::with_lookup( - region, - &self.lookup, - row, - spread_pieces[5].clone().map(SpreadWord::try_new), - )?; - - Ok(EfghVar { - a_lo, - a_hi, - b_lo, - b_hi, - c, - d, - }) - } - - pub(super) fn decompose_a( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: RoundIdx, - a_val: Value, - ) -> Result { - let row = get_decompose_a_row(round_idx); - - let (dense_halves, spread_halves) = self.assign_word_halves(region, row, a_val)?; - let a_pieces = self.decompose_abcd(region, row, a_val)?; - Ok(RoundWordA::new(a_pieces, dense_halves, spread_halves)) - } - - pub(super) fn decompose_e( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: RoundIdx, - e_val: Value, - ) -> Result { - let row = get_decompose_e_row(round_idx); - - let (dense_halves, spread_halves) = self.assign_word_halves(region, row, e_val)?; - let e_pieces = self.decompose_efgh(region, row, e_val)?; - Ok(RoundWordE::new(e_pieces, dense_halves, spread_halves)) - } - - pub(super) fn assign_upper_sigma_0( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - word: AbcdVar, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - // Rename these here for ease of matching the gates to the specification. - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - - let row = get_upper_sigma_0_row(round_idx); - - self.s_upper_sigma_0.enable(region, row)?; - - // Assign `spread_a` and copy constraint - word.a - .spread - .copy_advice(|| "spread_a", region, a_3, row + 1)?; - // Assign `spread_b` and copy constraint - word.b.spread.copy_advice(|| "spread_b", region, a_5, row)?; - // Assign `spread_c_lo` and copy constraint - word.c_lo - .spread - .copy_advice(|| "spread_c_lo", region, a_3, row - 1)?; - // Assign `spread_c_mid` and copy constraint - word.c_mid - .spread - .copy_advice(|| "spread_c_mid", region, a_4, row - 1)?; - // Assign `spread_c_hi` and copy constraint - word.c_hi - .spread - .copy_advice(|| "spread_c_hi", region, a_4, row + 1)?; - // Assign `spread_d` and copy constraint - word.d.spread.copy_advice(|| "spread_d", region, a_4, row)?; - - // Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - let r = word.xor_upper_sigma(); - let r_0: Value<[bool; 32]> = r.map(|r| r[..32].try_into().unwrap()); - let r_0_even = r_0.map(even_bits); - let r_0_odd = r_0.map(odd_bits); - - let r_1: Value<[bool; 32]> = r.map(|r| r[32..].try_into().unwrap()); - let r_1_even = r_1.map(even_bits); - let r_1_odd = r_1.map(odd_bits); - - self.assign_sigma_outputs( - region, - &self.lookup, - a_3, - row, - r_0_even, - r_0_odd, - r_1_even, - r_1_odd, - ) - } - - pub(super) fn assign_upper_sigma_1( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - word: EfghVar, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - // Rename these here for ease of matching the gates to the specification. - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - - let row = get_upper_sigma_1_row(round_idx); - - self.s_upper_sigma_1.enable(region, row)?; - - // Assign `spread_a_lo` and copy constraint - word.a_lo - .spread - .copy_advice(|| "spread_a_lo", region, a_3, row + 1)?; - // Assign `spread_a_hi` and copy constraint - word.a_hi - .spread - .copy_advice(|| "spread_a_hi", region, a_4, row + 1)?; - // Assign `spread_b_lo` and copy constraint - word.b_lo - .spread - .copy_advice(|| "spread_b_lo", region, a_3, row - 1)?; - // Assign `spread_b_hi` and copy constraint - word.b_hi - .spread - .copy_advice(|| "spread_b_hi", region, a_4, row - 1)?; - // Assign `spread_c` and copy constraint - word.c.spread.copy_advice(|| "spread_c", region, a_5, row)?; - // Assign `spread_d` and copy constraint - word.d.spread.copy_advice(|| "spread_d", region, a_4, row)?; - - // Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - // Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - let r = word.xor_upper_sigma(); - let r_0: Value<[bool; 32]> = r.map(|r| r[..32].try_into().unwrap()); - let r_0_even = r_0.map(even_bits); - let r_0_odd = r_0.map(odd_bits); - - let r_1: Value<[bool; 32]> = r.map(|r| r[32..].try_into().unwrap()); - let r_1_even = r_1.map(even_bits); - let r_1_odd = r_1.map(odd_bits); - - self.assign_sigma_outputs( - region, - &self.lookup, - a_3, - row, - r_0_even, - r_0_odd, - r_1_even, - r_1_odd, - ) - } - - fn assign_ch_outputs( - &self, - region: &mut Region<'_, pallas::Base>, - row: usize, - r_0_even: Value<[bool; 16]>, - r_0_odd: Value<[bool; 16]>, - r_1_even: Value<[bool; 16]>, - r_1_odd: Value<[bool; 16]>, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let a_3 = self.extras[0]; - - let (_even, odd) = self.assign_spread_outputs( - region, - &self.lookup, - a_3, - row, - r_0_even, - r_0_odd, - r_1_even, - r_1_odd, - )?; - - Ok(odd) - } - - pub(super) fn assign_ch( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - spread_halves_e: RoundWordSpread, - spread_halves_f: RoundWordSpread, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - - let row = get_ch_row(round_idx); - - self.s_ch.enable(region, row)?; - - // Assign and copy spread_e_lo, spread_e_hi - spread_halves_e - .0 - .copy_advice(|| "spread_e_lo", region, a_3, row - 1)?; - spread_halves_e - .1 - .copy_advice(|| "spread_e_hi", region, a_4, row - 1)?; - - // Assign and copy spread_f_lo, spread_f_hi - spread_halves_f - .0 - .copy_advice(|| "spread_f_lo", region, a_3, row + 1)?; - spread_halves_f - .1 - .copy_advice(|| "spread_f_hi", region, a_4, row + 1)?; - - let p: Value<[bool; 64]> = spread_halves_e - .value() - .zip(spread_halves_f.value()) - .map(|(e, f)| i2lebsp(e + f)); - - let p_0: Value<[bool; 32]> = p.map(|p| p[..32].try_into().unwrap()); - let p_0_even = p_0.map(even_bits); - let p_0_odd = p_0.map(odd_bits); - - let p_1: Value<[bool; 32]> = p.map(|p| p[32..].try_into().unwrap()); - let p_1_even = p_1.map(even_bits); - let p_1_odd = p_1.map(odd_bits); - - self.assign_ch_outputs(region, row, p_0_even, p_0_odd, p_1_even, p_1_odd) - } - - pub(super) fn assign_ch_neg( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - spread_halves_e: RoundWordSpread, - spread_halves_g: RoundWordSpread, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let row = get_ch_neg_row(round_idx); - - self.s_ch_neg.enable(region, row)?; - - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - - // Assign and copy spread_e_lo, spread_e_hi - spread_halves_e - .0 - .copy_advice(|| "spread_e_lo", region, a_5, row - 1)?; - spread_halves_e - .1 - .copy_advice(|| "spread_e_hi", region, a_5, row)?; - - // Assign and copy spread_g_lo, spread_g_hi - spread_halves_g - .0 - .copy_advice(|| "spread_g_lo", region, a_3, row + 1)?; - spread_halves_g - .1 - .copy_advice(|| "spread_g_hi", region, a_4, row + 1)?; - - // Calculate neg_e_lo - let spread_neg_e_lo = spread_halves_e - .0 - .value() - .map(|spread_e_lo| negate_spread(spread_e_lo.0)); - // Assign spread_neg_e_lo - AssignedBits::<32>::assign_bits( - region, - || "spread_neg_e_lo", - a_3, - row - 1, - spread_neg_e_lo, - )?; - - // Calculate neg_e_hi - let spread_neg_e_hi = spread_halves_e - .1 - .value() - .map(|spread_e_hi| negate_spread(spread_e_hi.0)); - // Assign spread_neg_e_hi - AssignedBits::<32>::assign_bits( - region, - || "spread_neg_e_hi", - a_4, - row - 1, - spread_neg_e_hi, - )?; - - let p: Value<[bool; 64]> = { - let spread_neg_e = spread_neg_e_lo - .zip(spread_neg_e_hi) - .map(|(lo, hi)| lebs2ip(&lo) + (1 << 32) * lebs2ip(&hi)); - spread_neg_e - .zip(spread_halves_g.value()) - .map(|(neg_e, g)| i2lebsp(neg_e + g)) - }; - - let p_0: Value<[bool; 32]> = p.map(|p| p[..32].try_into().unwrap()); - let p_0_even = p_0.map(even_bits); - let p_0_odd = p_0.map(odd_bits); - - let p_1: Value<[bool; 32]> = p.map(|p| p[32..].try_into().unwrap()); - let p_1_even = p_1.map(even_bits); - let p_1_odd = p_1.map(odd_bits); - - self.assign_ch_outputs(region, row, p_0_even, p_0_odd, p_1_even, p_1_odd) - } - - fn assign_maj_outputs( - &self, - region: &mut Region<'_, pallas::Base>, - row: usize, - r_0_even: Value<[bool; 16]>, - r_0_odd: Value<[bool; 16]>, - r_1_even: Value<[bool; 16]>, - r_1_odd: Value<[bool; 16]>, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let a_3 = self.extras[0]; - let (_even, odd) = self.assign_spread_outputs( - region, - &self.lookup, - a_3, - row, - r_0_even, - r_0_odd, - r_1_even, - r_1_odd, - )?; - - Ok(odd) - } - - pub(super) fn assign_maj( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - spread_halves_a: RoundWordSpread, - spread_halves_b: RoundWordSpread, - spread_halves_c: RoundWordSpread, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - - let row = get_maj_row(round_idx); - - self.s_maj.enable(region, row)?; - - // Assign and copy spread_a_lo, spread_a_hi - spread_halves_a - .0 - .copy_advice(|| "spread_a_lo", region, a_4, row - 1)?; - spread_halves_a - .1 - .copy_advice(|| "spread_a_hi", region, a_5, row - 1)?; - - // Assign and copy spread_b_lo, spread_b_hi - spread_halves_b - .0 - .copy_advice(|| "spread_b_lo", region, a_4, row)?; - spread_halves_b - .1 - .copy_advice(|| "spread_b_hi", region, a_5, row)?; - - // Assign and copy spread_c_lo, spread_c_hi - spread_halves_c - .0 - .copy_advice(|| "spread_c_lo", region, a_4, row + 1)?; - spread_halves_c - .1 - .copy_advice(|| "spread_c_hi", region, a_5, row + 1)?; - - let m: Value<[bool; 64]> = spread_halves_a - .value() - .zip(spread_halves_b.value()) - .zip(spread_halves_c.value()) - .map(|((a, b), c)| i2lebsp(a + b + c)); - - let m_0: Value<[bool; 32]> = m.map(|m| m[..32].try_into().unwrap()); - let m_0_even = m_0.map(even_bits); - let m_0_odd = m_0.map(odd_bits); - - let m_1: Value<[bool; 32]> = m.map(|m| m[32..].try_into().unwrap()); - let m_1_even = m_1.map(even_bits); - let m_1_odd = m_1.map(odd_bits); - - self.assign_maj_outputs(region, row, m_0_even, m_0_odd, m_1_even, m_1_odd) - } - - // s_h_prime to get H' = H + Ch(E, F, G) + s_upper_sigma_1(E) + K + W - #[allow(clippy::too_many_arguments)] - pub(super) fn assign_h_prime( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - h: RoundWordDense, - ch: (AssignedBits<16>, AssignedBits<16>), - ch_neg: (AssignedBits<16>, AssignedBits<16>), - sigma_1: (AssignedBits<16>, AssignedBits<16>), - k: u32, - w: &(AssignedBits<16>, AssignedBits<16>), - ) -> Result { - let row = get_h_prime_row(round_idx); - self.s_h_prime.enable(region, row)?; - - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - let a_7 = self.extras[3]; - let a_8 = self.extras[4]; - let a_9 = self.extras[5]; - - // Assign and copy h - h.0.copy_advice(|| "h_lo", region, a_7, row - 1)?; - h.1.copy_advice(|| "h_hi", region, a_7, row)?; - - // Assign and copy sigma_1 - sigma_1.0.copy_advice(|| "sigma_1_lo", region, a_4, row)?; - sigma_1.1.copy_advice(|| "sigma_1_hi", region, a_5, row)?; - - // Assign k - let k: [bool; 32] = i2lebsp(k.into()); - let k_lo: [bool; 16] = k[..16].try_into().unwrap(); - let k_hi: [bool; 16] = k[16..].try_into().unwrap(); - { - AssignedBits::<16>::assign_bits(region, || "k_lo", a_6, row - 1, Value::known(k_lo))?; - AssignedBits::<16>::assign_bits(region, || "k_hi", a_6, row, Value::known(k_hi))?; - } - - // Assign and copy w - w.0.copy_advice(|| "w_lo", region, a_8, row - 1)?; - w.1.copy_advice(|| "w_hi", region, a_8, row)?; - - // Assign and copy ch - ch.1.copy_advice(|| "ch_neg_hi", region, a_6, row + 1)?; - - // Assign and copy ch_neg - ch_neg.0.copy_advice(|| "ch_neg_lo", region, a_5, row - 1)?; - ch_neg.1.copy_advice(|| "ch_neg_hi", region, a_5, row + 1)?; - - // Assign h_prime_lo, h_prime_hi, h_prime_carry - { - let (h_prime, h_prime_carry) = sum_with_carry(vec![ - (h.0.value_u16(), h.1.value_u16()), - (ch.0.value_u16(), ch.1.value_u16()), - (ch_neg.0.value_u16(), ch_neg.1.value_u16()), - (sigma_1.0.value_u16(), sigma_1.1.value_u16()), - ( - Value::known(lebs2ip(&k_lo) as u16), - Value::known(lebs2ip(&k_hi) as u16), - ), - (w.0.value_u16(), w.1.value_u16()), - ]); - - region.assign_advice( - || "h_prime_carry", - a_9, - row + 1, - || h_prime_carry.map(pallas::Base::from), - )?; - - let h_prime: Value<[bool; 32]> = h_prime.map(|w| i2lebsp(w.into())); - let h_prime_lo: Value<[bool; 16]> = h_prime.map(|w| w[..16].try_into().unwrap()); - let h_prime_hi: Value<[bool; 16]> = h_prime.map(|w| w[16..].try_into().unwrap()); - - let h_prime_lo = - AssignedBits::<16>::assign_bits(region, || "h_prime_lo", a_7, row + 1, h_prime_lo)?; - let h_prime_hi = - AssignedBits::<16>::assign_bits(region, || "h_prime_hi", a_8, row + 1, h_prime_hi)?; - - Ok((h_prime_lo, h_prime_hi).into()) - } - } - - // s_e_new to get E_new = H' + D - pub(super) fn assign_e_new( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - d: &RoundWordDense, - h_prime: &RoundWordDense, - ) -> Result { - let row = get_e_new_row(round_idx); - - self.s_e_new.enable(region, row)?; - - let a_7 = self.extras[3]; - let a_8 = self.extras[4]; - let a_9 = self.extras[5]; - - // Assign and copy d_lo, d_hi - d.0.copy_advice(|| "d_lo", region, a_7, row)?; - d.1.copy_advice(|| "d_hi", region, a_7, row + 1)?; - - // Assign e_new, e_new_carry - let (e_new, e_new_carry) = sum_with_carry(vec![ - (h_prime.0.value_u16(), h_prime.1.value_u16()), - (d.0.value_u16(), d.1.value_u16()), - ]); - - let e_new_dense = self.assign_word_halves_dense(region, row, a_8, row + 1, a_8, e_new)?; - region.assign_advice( - || "e_new_carry", - a_9, - row + 1, - || e_new_carry.map(pallas::Base::from), - )?; - - Ok(e_new_dense) - } - - // s_a_new to get A_new = H' + Maj(A, B, C) + s_upper_sigma_0(A) - pub(super) fn assign_a_new( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - maj: (AssignedBits<16>, AssignedBits<16>), - sigma_0: (AssignedBits<16>, AssignedBits<16>), - h_prime: RoundWordDense, - ) -> Result { - let row = get_a_new_row(round_idx); - - self.s_a_new.enable(region, row)?; - - let a_3 = self.extras[0]; - let a_6 = self.extras[2]; - let a_7 = self.extras[3]; - let a_8 = self.extras[4]; - let a_9 = self.extras[5]; - - // Assign and copy maj_1 - maj.1.copy_advice(|| "maj_1_hi", region, a_3, row - 1)?; - - // Assign and copy sigma_0 - sigma_0.0.copy_advice(|| "sigma_0_lo", region, a_6, row)?; - sigma_0 - .1 - .copy_advice(|| "sigma_0_hi", region, a_6, row + 1)?; - - // Assign and copy h_prime - h_prime - .0 - .copy_advice(|| "h_prime_lo", region, a_7, row - 1)?; - h_prime - .1 - .copy_advice(|| "h_prime_hi", region, a_8, row - 1)?; - - // Assign a_new, a_new_carry - let (a_new, a_new_carry) = sum_with_carry(vec![ - (h_prime.0.value_u16(), h_prime.1.value_u16()), - (sigma_0.0.value_u16(), sigma_0.1.value_u16()), - (maj.0.value_u16(), maj.1.value_u16()), - ]); - - let a_new_dense = self.assign_word_halves_dense(region, row, a_8, row + 1, a_8, a_new)?; - region.assign_advice( - || "a_new_carry", - a_9, - row, - || a_new_carry.map(pallas::Base::from), - )?; - - Ok(a_new_dense) - } - - pub fn assign_word_halves_dense( - &self, - region: &mut Region<'_, pallas::Base>, - lo_row: usize, - lo_col: Column, - hi_row: usize, - hi_col: Column, - word: Value, - ) -> Result { - let word: Value<[bool; 32]> = word.map(|w| i2lebsp(w.into())); - - let lo = { - let lo: Value<[bool; 16]> = word.map(|w| w[..16].try_into().unwrap()); - AssignedBits::<16>::assign_bits(region, || "lo", lo_col, lo_row, lo)? - }; - - let hi = { - let hi: Value<[bool; 16]> = word.map(|w| w[16..].try_into().unwrap()); - AssignedBits::<16>::assign_bits(region, || "hi", hi_col, hi_row, hi)? - }; - - Ok((lo, hi).into()) - } - - // Assign hi and lo halves for both dense and spread versions of a word - #[allow(clippy::type_complexity)] - pub fn assign_word_halves( - &self, - region: &mut Region<'_, pallas::Base>, - row: usize, - word: Value, - ) -> Result<(RoundWordDense, RoundWordSpread), Error> { - // Rename these here for ease of matching the gates to the specification. - let a_7 = self.extras[3]; - let a_8 = self.extras[4]; - - let word: Value<[bool; 32]> = word.map(|w| i2lebsp(w.into())); - let lo: Value<[bool; 16]> = word.map(|w| w[..16].try_into().unwrap()); - let hi: Value<[bool; 16]> = word.map(|w| w[16..].try_into().unwrap()); - - let w_lo = SpreadVar::without_lookup(region, a_7, row, a_8, row, lo.map(SpreadWord::new))?; - let w_hi = - SpreadVar::without_lookup(region, a_7, row + 1, a_8, row + 1, hi.map(SpreadWord::new))?; - - Ok(( - (w_lo.dense, w_hi.dense).into(), - (w_lo.spread, w_hi.spread).into(), - )) - } -} - -#[allow(clippy::many_single_char_names)] -pub fn match_state( - state: State, -) -> ( - RoundWordA, - RoundWord, - RoundWord, - RoundWordDense, - RoundWordE, - RoundWord, - RoundWord, - RoundWordDense, -) { - let a = match state.a { - Some(StateWord::A(a)) => a, - _ => unreachable!(), - }; - let b = match state.b { - Some(StateWord::B(b)) => b, - _ => unreachable!(), - }; - let c = match state.c { - Some(StateWord::C(c)) => c, - _ => unreachable!(), - }; - let d = match state.d { - Some(StateWord::D(d)) => d, - _ => unreachable!(), - }; - let e = match state.e { - Some(StateWord::E(e)) => e, - _ => unreachable!(), - }; - let f = match state.f { - Some(StateWord::F(f)) => f, - _ => unreachable!(), - }; - let g = match state.g { - Some(StateWord::G(g)) => g, - _ => unreachable!(), - }; - let h = match state.h { - Some(StateWord::H(h)) => h, - _ => unreachable!(), - }; - - (a, b, c, d, e, f, g, h) -} diff --git a/halo2_gadgets/src/sha256/table16/compression/subregion_digest.rs b/halo2_gadgets/src/sha256/table16/compression/subregion_digest.rs deleted file mode 100644 index aa30f80af7..0000000000 --- a/halo2_gadgets/src/sha256/table16/compression/subregion_digest.rs +++ /dev/null @@ -1,102 +0,0 @@ -use super::super::{super::DIGEST_SIZE, BlockWord, RoundWordDense}; -use super::{compression_util::*, CompressionConfig, State}; -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::{Advice, Column, Error}, -}; -use halo2curves::pasta::pallas; - -impl CompressionConfig { - #[allow(clippy::many_single_char_names)] - pub fn assign_digest( - &self, - region: &mut Region<'_, pallas::Base>, - state: State, - ) -> Result<[BlockWord; DIGEST_SIZE], Error> { - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - let a_7 = self.extras[3]; - let a_8 = self.extras[4]; - - let (a, b, c, d, e, f, g, h) = match_state(state); - - let abcd_row = 0; - self.s_digest.enable(region, abcd_row)?; - let efgh_row = abcd_row + 2; - self.s_digest.enable(region, efgh_row)?; - - // Assign digest for A, B, C, D - a.dense_halves - .0 - .copy_advice(|| "a_lo", region, a_3, abcd_row)?; - a.dense_halves - .1 - .copy_advice(|| "a_hi", region, a_4, abcd_row)?; - let a = a.dense_halves.value(); - region.assign_advice( - || "a", - a_5, - abcd_row, - || a.map(|a| pallas::Base::from(a as u64)), - )?; - - let b = self.assign_digest_word(region, abcd_row, a_6, a_7, a_8, b.dense_halves)?; - let c = self.assign_digest_word(region, abcd_row + 1, a_3, a_4, a_5, c.dense_halves)?; - let d = self.assign_digest_word(region, abcd_row + 1, a_6, a_7, a_8, d)?; - - // Assign digest for E, F, G, H - e.dense_halves - .0 - .copy_advice(|| "e_lo", region, a_3, efgh_row)?; - e.dense_halves - .1 - .copy_advice(|| "e_hi", region, a_4, efgh_row)?; - let e = e.dense_halves.value(); - region.assign_advice( - || "e", - a_5, - efgh_row, - || e.map(|e| pallas::Base::from(e as u64)), - )?; - - let f = self.assign_digest_word(region, efgh_row, a_6, a_7, a_8, f.dense_halves)?; - let g = self.assign_digest_word(region, efgh_row + 1, a_3, a_4, a_5, g.dense_halves)?; - let h = self.assign_digest_word(region, efgh_row + 1, a_6, a_7, a_8, h)?; - - Ok([ - BlockWord(a), - BlockWord(b), - BlockWord(c), - BlockWord(d), - BlockWord(e), - BlockWord(f), - BlockWord(g), - BlockWord(h), - ]) - } - - fn assign_digest_word( - &self, - region: &mut Region<'_, pallas::Base>, - row: usize, - lo_col: Column, - hi_col: Column, - word_col: Column, - dense_halves: RoundWordDense, - ) -> Result, Error> { - dense_halves.0.copy_advice(|| "lo", region, lo_col, row)?; - dense_halves.1.copy_advice(|| "hi", region, hi_col, row)?; - - let val = dense_halves.value(); - region.assign_advice( - || "word", - word_col, - row, - || val.map(|val| pallas::Base::from(val as u64)), - )?; - - Ok(val) - } -} diff --git a/halo2_gadgets/src/sha256/table16/compression/subregion_initial.rs b/halo2_gadgets/src/sha256/table16/compression/subregion_initial.rs deleted file mode 100644 index a487dc0c87..0000000000 --- a/halo2_gadgets/src/sha256/table16/compression/subregion_initial.rs +++ /dev/null @@ -1,157 +0,0 @@ -use super::super::{RoundWord, StateWord, STATE}; -use super::{compression_util::*, CompressionConfig, State}; - -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::Error, -}; -use halo2curves::pasta::pallas; - -impl CompressionConfig { - #[allow(clippy::many_single_char_names)] - pub fn initialize_iv( - &self, - region: &mut Region<'_, pallas::Base>, - iv: [u32; STATE], - ) -> Result { - let a_7 = self.extras[3]; - - // Decompose E into (6, 5, 14, 7)-bit chunks - let e = self.decompose_e(region, RoundIdx::Init, Value::known(iv[4]))?; - - // Decompose F, G - let f = self.decompose_f(region, InitialRound, Value::known(iv[5]))?; - let g = self.decompose_g(region, InitialRound, Value::known(iv[6]))?; - - // Assign H - let h_row = get_h_row(RoundIdx::Init); - let h = - self.assign_word_halves_dense(region, h_row, a_7, h_row + 1, a_7, Value::known(iv[7]))?; - - // Decompose A into (2, 11, 9, 10)-bit chunks - let a = self.decompose_a(region, RoundIdx::Init, Value::known(iv[0]))?; - - // Decompose B, C - let b = self.decompose_b(region, InitialRound, Value::known(iv[1]))?; - let c = self.decompose_c(region, InitialRound, Value::known(iv[2]))?; - - // Assign D - let d_row = get_d_row(RoundIdx::Init); - let d = - self.assign_word_halves_dense(region, d_row, a_7, d_row + 1, a_7, Value::known(iv[3]))?; - - Ok(State::new( - StateWord::A(a), - StateWord::B(b), - StateWord::C(c), - StateWord::D(d), - StateWord::E(e), - StateWord::F(f), - StateWord::G(g), - StateWord::H(h), - )) - } - - #[allow(clippy::many_single_char_names)] - pub fn initialize_state( - &self, - region: &mut Region<'_, pallas::Base>, - state: State, - ) -> Result { - let a_7 = self.extras[3]; - let (a, b, c, d, e, f, g, h) = match_state(state); - - // Decompose E into (6, 5, 14, 7)-bit chunks - let e = e.dense_halves.value(); - let e = self.decompose_e(region, RoundIdx::Init, e)?; - - // Decompose F, G - let f = f.dense_halves.value(); - let f = self.decompose_f(region, InitialRound, f)?; - let g = g.dense_halves.value(); - let g = self.decompose_g(region, InitialRound, g)?; - - // Assign H - let h = h.value(); - let h_row = get_h_row(RoundIdx::Init); - let h = self.assign_word_halves_dense(region, h_row, a_7, h_row + 1, a_7, h)?; - - // Decompose A into (2, 11, 9, 10)-bit chunks - let a = a.dense_halves.value(); - let a = self.decompose_a(region, RoundIdx::Init, a)?; - - // Decompose B, C - let b = b.dense_halves.value(); - let b = self.decompose_b(region, InitialRound, b)?; - let c = c.dense_halves.value(); - let c = self.decompose_c(region, InitialRound, c)?; - - // Assign D - let d = d.value(); - let d_row = get_d_row(RoundIdx::Init); - let d = self.assign_word_halves_dense(region, d_row, a_7, d_row + 1, a_7, d)?; - - Ok(State::new( - StateWord::A(a), - StateWord::B(b), - StateWord::C(c), - StateWord::D(d), - StateWord::E(e), - StateWord::F(f), - StateWord::G(g), - StateWord::H(h), - )) - } - - fn decompose_b( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: InitialRound, - b_val: Value, - ) -> Result { - let row = get_decompose_b_row(round_idx); - - let (dense_halves, spread_halves) = self.assign_word_halves(region, row, b_val)?; - self.decompose_abcd(region, row, b_val)?; - Ok(RoundWord::new(dense_halves, spread_halves)) - } - - fn decompose_c( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: InitialRound, - c_val: Value, - ) -> Result { - let row = get_decompose_c_row(round_idx); - - let (dense_halves, spread_halves) = self.assign_word_halves(region, row, c_val)?; - self.decompose_abcd(region, row, c_val)?; - Ok(RoundWord::new(dense_halves, spread_halves)) - } - - fn decompose_f( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: InitialRound, - f_val: Value, - ) -> Result { - let row = get_decompose_f_row(round_idx); - - let (dense_halves, spread_halves) = self.assign_word_halves(region, row, f_val)?; - self.decompose_efgh(region, row, f_val)?; - Ok(RoundWord::new(dense_halves, spread_halves)) - } - - fn decompose_g( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: InitialRound, - g_val: Value, - ) -> Result { - let row = get_decompose_g_row(round_idx); - - let (dense_halves, spread_halves) = self.assign_word_halves(region, row, g_val)?; - self.decompose_efgh(region, row, g_val)?; - Ok(RoundWord::new(dense_halves, spread_halves)) - } -} diff --git a/halo2_gadgets/src/sha256/table16/compression/subregion_main.rs b/halo2_gadgets/src/sha256/table16/compression/subregion_main.rs deleted file mode 100644 index bda188a866..0000000000 --- a/halo2_gadgets/src/sha256/table16/compression/subregion_main.rs +++ /dev/null @@ -1,127 +0,0 @@ -use super::super::{AssignedBits, RoundWord, RoundWordA, RoundWordE, StateWord, ROUND_CONSTANTS}; -use super::{compression_util::*, CompressionConfig, State}; -use halo2_proofs::{circuit::Region, plonk::Error}; -use halo2curves::pasta::pallas; - -impl CompressionConfig { - #[allow(clippy::many_single_char_names)] - pub fn assign_round( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - state: State, - schedule_word: &(AssignedBits<16>, AssignedBits<16>), - ) -> Result { - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_7 = self.extras[3]; - - let (a, b, c, d, e, f, g, h) = match_state(state); - - // s_upper_sigma_1(E) - let sigma_1 = self.assign_upper_sigma_1(region, round_idx, e.pieces.clone().unwrap())?; - - // Ch(E, F, G) - let ch = self.assign_ch( - region, - round_idx, - e.spread_halves.clone().unwrap(), - f.spread_halves.clone(), - )?; - let ch_neg = self.assign_ch_neg( - region, - round_idx, - e.spread_halves.clone().unwrap(), - g.spread_halves.clone(), - )?; - - // s_upper_sigma_0(A) - let sigma_0 = self.assign_upper_sigma_0(region, round_idx, a.pieces.clone().unwrap())?; - - // Maj(A, B, C) - let maj = self.assign_maj( - region, - round_idx, - a.spread_halves.clone().unwrap(), - b.spread_halves.clone(), - c.spread_halves.clone(), - )?; - - // H' = H + Ch(E, F, G) + s_upper_sigma_1(E) + K + W - let h_prime = self.assign_h_prime( - region, - round_idx, - h, - ch, - ch_neg, - sigma_1, - ROUND_CONSTANTS[round_idx.as_usize()], - schedule_word, - )?; - - // E_new = H' + D - let e_new_dense = self.assign_e_new(region, round_idx, &d, &h_prime)?; - let e_new_val = e_new_dense.value(); - - // A_new = H' + Maj(A, B, C) + sigma_0(A) - let a_new_dense = self.assign_a_new(region, round_idx, maj, sigma_0, h_prime)?; - let a_new_val = a_new_dense.value(); - - if round_idx < 63.into() { - // Assign and copy A_new - let a_new_row = get_decompose_a_row((round_idx + 1).into()); - a_new_dense - .0 - .copy_advice(|| "a_new_lo", region, a_7, a_new_row)?; - a_new_dense - .1 - .copy_advice(|| "a_new_hi", region, a_7, a_new_row + 1)?; - - // Assign and copy E_new - let e_new_row = get_decompose_e_row((round_idx + 1).into()); - e_new_dense - .0 - .copy_advice(|| "e_new_lo", region, a_7, e_new_row)?; - e_new_dense - .1 - .copy_advice(|| "e_new_hi", region, a_7, e_new_row + 1)?; - - // Decompose A into (2, 11, 9, 10)-bit chunks - let a_new = self.decompose_a(region, (round_idx + 1).into(), a_new_val)?; - - // Decompose E into (6, 5, 14, 7)-bit chunks - let e_new = self.decompose_e(region, (round_idx + 1).into(), e_new_val)?; - - Ok(State::new( - StateWord::A(a_new), - StateWord::B(RoundWord::new(a.dense_halves, a.spread_halves.unwrap())), - StateWord::C(b), - StateWord::D(c.dense_halves), - StateWord::E(e_new), - StateWord::F(RoundWord::new(e.dense_halves, e.spread_halves.unwrap())), - StateWord::G(f), - StateWord::H(g.dense_halves), - )) - } else { - let abcd_row = get_digest_abcd_row(); - let efgh_row = get_digest_efgh_row(); - - let a_final = - self.assign_word_halves_dense(region, abcd_row, a_3, abcd_row, a_4, a_new_val)?; - - let e_final = - self.assign_word_halves_dense(region, efgh_row, a_3, efgh_row, a_4, e_new_val)?; - - Ok(State::new( - StateWord::A(RoundWordA::new_dense(a_final)), - StateWord::B(RoundWord::new(a.dense_halves, a.spread_halves.unwrap())), - StateWord::C(b), - StateWord::D(c.dense_halves), - StateWord::E(RoundWordE::new_dense(e_final)), - StateWord::F(RoundWord::new(e.dense_halves, e.spread_halves.unwrap())), - StateWord::G(f), - StateWord::H(g.dense_halves), - )) - } - } -} diff --git a/halo2_gadgets/src/sha256/table16/gates.rs b/halo2_gadgets/src/sha256/table16/gates.rs deleted file mode 100644 index d5f3840a57..0000000000 --- a/halo2_gadgets/src/sha256/table16/gates.rs +++ /dev/null @@ -1,125 +0,0 @@ -use ff::PrimeField; -use halo2_proofs::{arithmetic::Field, plonk::Expression}; - -pub struct Gate(pub Expression); - -impl Gate { - fn ones() -> Expression { - Expression::Constant(F::ONE) - } - - // Helper gates - fn lagrange_interpolate( - var: Expression, - points: Vec, - evals: Vec, - ) -> (F, Expression) { - assert_eq!(points.len(), evals.len()); - let deg = points.len(); - - fn factorial(n: u64) -> u64 { - if n < 2 { - 1 - } else { - n * factorial(n - 1) - } - } - - // Scale the whole expression by factor to avoid divisions - let factor = factorial((deg - 1) as u64); - - let numerator = |var: Expression, eval: u32, idx: u64| { - let mut expr = Self::ones(); - for i in 0..deg { - let i = i as u64; - if i != idx { - expr = expr * (Self::ones() * (-F::ONE) * F::from(i) + var.clone()); - } - } - expr * F::from(u64::from(eval)) - }; - let denominator = |idx: i32| { - let mut denom: i32 = 1; - for i in 0..deg { - let i = i as i32; - if i != idx { - denom *= idx - i - } - } - if denom < 0 { - -F::ONE * F::from(factor / (-denom as u64)) - } else { - F::from(factor / (denom as u64)) - } - }; - - let mut expr = Self::ones() * F::ZERO; - for ((idx, _), eval) in points.iter().enumerate().zip(evals.iter()) { - expr = expr + numerator(var.clone(), *eval, idx as u64) * denominator(idx as i32) - } - - (F::from(factor), expr) - } - - pub fn range_check(value: Expression, lower_range: u64, upper_range: u64) -> Expression { - let mut expr = Self::ones(); - for i in lower_range..(upper_range + 1) { - expr = expr * (Self::ones() * (-F::ONE) * F::from(i) + value.clone()) - } - expr - } - - /// Spread and range check on 2-bit word - pub fn two_bit_spread_and_range( - dense: Expression, - spread: Expression, - ) -> impl Iterator)> { - let two_bit_spread = |dense: Expression, spread: Expression| { - let (factor, lagrange_poly) = Self::lagrange_interpolate( - dense, - vec![0b00, 0b01, 0b10, 0b11], - vec![0b0000, 0b0001, 0b0100, 0b0101], - ); - - lagrange_poly - spread * factor - }; - - std::iter::empty() - .chain(Some(( - "two_bit_range_check", - Self::range_check(dense.clone(), 0, (1 << 2) - 1), - ))) - .chain(Some(( - "two_bit_spread_check", - two_bit_spread(dense, spread), - ))) - } - - /// Spread and range check on 3-bit word - pub fn three_bit_spread_and_range( - dense: Expression, - spread: Expression, - ) -> impl Iterator)> { - let three_bit_spread = |dense: Expression, spread: Expression| { - let (factor, lagrange_poly) = Self::lagrange_interpolate( - dense, - vec![0b000, 0b001, 0b010, 0b011, 0b100, 0b101, 0b110, 0b111], - vec![ - 0b000000, 0b000001, 0b000100, 0b000101, 0b010000, 0b010001, 0b010100, 0b010101, - ], - ); - - lagrange_poly - spread * factor - }; - - std::iter::empty() - .chain(Some(( - "three_bit_range_check", - Self::range_check(dense.clone(), 0, (1 << 3) - 1), - ))) - .chain(Some(( - "three_bit_spread_check", - three_bit_spread(dense, spread), - ))) - } -} diff --git a/halo2_gadgets/src/sha256/table16/message_schedule.rs b/halo2_gadgets/src/sha256/table16/message_schedule.rs deleted file mode 100644 index 3da70c0add..0000000000 --- a/halo2_gadgets/src/sha256/table16/message_schedule.rs +++ /dev/null @@ -1,457 +0,0 @@ -use std::convert::TryInto; - -use super::{super::BLOCK_SIZE, AssignedBits, BlockWord, SpreadInputs, Table16Assignment, ROUNDS}; -use halo2_proofs::{ - circuit::Layouter, - plonk::{Advice, Column, ConstraintSystem, Error, Selector}, - poly::Rotation, -}; -use halo2curves::pasta::pallas; - -mod schedule_gates; -mod schedule_util; -mod subregion1; -mod subregion2; -mod subregion3; - -use schedule_gates::ScheduleGate; -use schedule_util::*; - -#[cfg(test)] -pub use schedule_util::msg_schedule_test_input; - -#[derive(Clone, Debug)] -pub(super) struct MessageWord(AssignedBits<32>); - -impl std::ops::Deref for MessageWord { - type Target = AssignedBits<32>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Clone, Debug)] -pub(super) struct MessageScheduleConfig { - lookup: SpreadInputs, - message_schedule: Column, - extras: [Column; 6], - - /// Construct a word using reduce_4. - s_word: Selector, - /// Decomposition gate for W_0, W_62, W_63. - s_decompose_0: Selector, - /// Decomposition gate for W_[1..14] - s_decompose_1: Selector, - /// Decomposition gate for W_[14..49] - s_decompose_2: Selector, - /// Decomposition gate for W_[49..62] - s_decompose_3: Selector, - /// sigma_0 gate for W_[1..14] - s_lower_sigma_0: Selector, - /// sigma_1 gate for W_[49..62] - s_lower_sigma_1: Selector, - /// sigma_0_v2 gate for W_[14..49] - s_lower_sigma_0_v2: Selector, - /// sigma_1_v2 gate for W_[14..49] - s_lower_sigma_1_v2: Selector, -} - -impl Table16Assignment for MessageScheduleConfig {} - -impl MessageScheduleConfig { - /// Configures the message schedule. - /// - /// `message_schedule` is the column into which the message schedule will be placed. - /// The caller must create appropriate permutations in order to load schedule words - /// into the compression rounds. - /// - /// `extras` contains columns that the message schedule will only use for internal - /// gates, and will not place any constraints on (such as lookup constraints) outside - /// itself. - #[allow(clippy::many_single_char_names)] - pub(super) fn configure( - meta: &mut ConstraintSystem, - lookup: SpreadInputs, - message_schedule: Column, - extras: [Column; 6], - ) -> Self { - // Create fixed columns for the selectors we will require. - let s_word = meta.selector(); - let s_decompose_0 = meta.selector(); - let s_decompose_1 = meta.selector(); - let s_decompose_2 = meta.selector(); - let s_decompose_3 = meta.selector(); - let s_lower_sigma_0 = meta.selector(); - let s_lower_sigma_1 = meta.selector(); - let s_lower_sigma_0_v2 = meta.selector(); - let s_lower_sigma_1_v2 = meta.selector(); - - // Rename these here for ease of matching the gates to the specification. - let a_0 = lookup.tag; - let a_1 = lookup.dense; - let a_2 = lookup.spread; - let a_3 = extras[0]; - let a_4 = extras[1]; - let a_5 = message_schedule; - let a_6 = extras[2]; - let a_7 = extras[3]; - let a_8 = extras[4]; - let a_9 = extras[5]; - - // s_word for W_[16..64] - meta.create_gate("s_word for W_[16..64]", |meta| { - let s_word = meta.query_selector(s_word); - - let sigma_0_lo = meta.query_advice(a_6, Rotation::prev()); - let sigma_0_hi = meta.query_advice(a_6, Rotation::cur()); - - let sigma_1_lo = meta.query_advice(a_7, Rotation::prev()); - let sigma_1_hi = meta.query_advice(a_7, Rotation::cur()); - - let w_minus_9_lo = meta.query_advice(a_8, Rotation::prev()); - let w_minus_9_hi = meta.query_advice(a_8, Rotation::cur()); - - let w_minus_16_lo = meta.query_advice(a_3, Rotation::prev()); - let w_minus_16_hi = meta.query_advice(a_4, Rotation::prev()); - - let word = meta.query_advice(a_5, Rotation::cur()); - let carry = meta.query_advice(a_9, Rotation::cur()); - - ScheduleGate::s_word( - s_word, - sigma_0_lo, - sigma_0_hi, - sigma_1_lo, - sigma_1_hi, - w_minus_9_lo, - w_minus_9_hi, - w_minus_16_lo, - w_minus_16_hi, - word, - carry, - ) - }); - - // s_decompose_0 for all words - meta.create_gate("s_decompose_0", |meta| { - let s_decompose_0 = meta.query_selector(s_decompose_0); - let lo = meta.query_advice(a_3, Rotation::cur()); - let hi = meta.query_advice(a_4, Rotation::cur()); - let word = meta.query_advice(a_5, Rotation::cur()); - - ScheduleGate::s_decompose_0(s_decompose_0, lo, hi, word) - }); - - // s_decompose_1 for W_[1..14] - // (3, 4, 11, 14)-bit chunks - meta.create_gate("s_decompose_1", |meta| { - let s_decompose_1 = meta.query_selector(s_decompose_1); - let a = meta.query_advice(a_3, Rotation::next()); // 3-bit chunk - let b = meta.query_advice(a_4, Rotation::next()); // 4-bit chunk - let c = meta.query_advice(a_1, Rotation::next()); // 11-bit chunk - let tag_c = meta.query_advice(a_0, Rotation::next()); - let d = meta.query_advice(a_1, Rotation::cur()); // 14-bit chunk - let tag_d = meta.query_advice(a_0, Rotation::cur()); - let word = meta.query_advice(a_5, Rotation::cur()); - - ScheduleGate::s_decompose_1(s_decompose_1, a, b, c, tag_c, d, tag_d, word) - }); - - // s_decompose_2 for W_[14..49] - // (3, 4, 3, 7, 1, 1, 13)-bit chunks - meta.create_gate("s_decompose_2", |meta| { - let s_decompose_2 = meta.query_selector(s_decompose_2); - let a = meta.query_advice(a_3, Rotation::prev()); // 3-bit chunk - let b = meta.query_advice(a_1, Rotation::next()); // 4-bit chunk - let c = meta.query_advice(a_4, Rotation::prev()); // 3-bit chunk - let d = meta.query_advice(a_1, Rotation::cur()); // 7-bit chunk - let tag_d = meta.query_advice(a_0, Rotation::cur()); - let e = meta.query_advice(a_3, Rotation::next()); // 1-bit chunk - let f = meta.query_advice(a_4, Rotation::next()); // 1-bit chunk - let g = meta.query_advice(a_1, Rotation::prev()); // 13-bit chunk - let tag_g = meta.query_advice(a_0, Rotation::prev()); - let word = meta.query_advice(a_5, Rotation::cur()); - - ScheduleGate::s_decompose_2(s_decompose_2, a, b, c, d, tag_d, e, f, g, tag_g, word) - }); - - // s_decompose_3 for W_49 to W_61 - // (10, 7, 2, 13)-bit chunks - meta.create_gate("s_decompose_3", |meta| { - let s_decompose_3 = meta.query_selector(s_decompose_3); - let a = meta.query_advice(a_1, Rotation::next()); // 10-bit chunk - let tag_a = meta.query_advice(a_0, Rotation::next()); - let b = meta.query_advice(a_4, Rotation::next()); // 7-bit chunk - let c = meta.query_advice(a_3, Rotation::next()); // 2-bit chunk - let d = meta.query_advice(a_1, Rotation::cur()); // 13-bit chunk - let tag_d = meta.query_advice(a_0, Rotation::cur()); - let word = meta.query_advice(a_5, Rotation::cur()); - - ScheduleGate::s_decompose_3(s_decompose_3, a, tag_a, b, c, d, tag_d, word) - }); - - // sigma_0 v1 on W_[1..14] - // (3, 4, 11, 14)-bit chunks - meta.create_gate("sigma_0 v1", |meta| { - ScheduleGate::s_lower_sigma_0( - meta.query_selector(s_lower_sigma_0), - meta.query_advice(a_2, Rotation::prev()), // spread_r0_even - meta.query_advice(a_2, Rotation::cur()), // spread_r0_odd - meta.query_advice(a_2, Rotation::next()), // spread_r1_even - meta.query_advice(a_3, Rotation::cur()), // spread_r1_odd - meta.query_advice(a_5, Rotation::next()), // a - meta.query_advice(a_6, Rotation::next()), // spread_a - meta.query_advice(a_6, Rotation::cur()), // b - meta.query_advice(a_3, Rotation::prev()), // b_lo - meta.query_advice(a_4, Rotation::prev()), // spread_b_lo - meta.query_advice(a_5, Rotation::prev()), // b_hi - meta.query_advice(a_6, Rotation::prev()), // spread_b_hi - meta.query_advice(a_4, Rotation::cur()), // spread_c - meta.query_advice(a_5, Rotation::cur()), // spread_d - ) - }); - - // sigma_0 v2 on W_[14..49] - // (3, 4, 3, 7, 1, 1, 13)-bit chunks - meta.create_gate("sigma_0 v2", |meta| { - ScheduleGate::s_lower_sigma_0_v2( - meta.query_selector(s_lower_sigma_0_v2), - meta.query_advice(a_2, Rotation::prev()), // spread_r0_even - meta.query_advice(a_2, Rotation::cur()), // spread_r0_odd - meta.query_advice(a_2, Rotation::next()), // spread_r1_even - meta.query_advice(a_3, Rotation::cur()), // spread_r1_odd - meta.query_advice(a_3, Rotation::next()), // a - meta.query_advice(a_4, Rotation::next()), // spread_a - meta.query_advice(a_6, Rotation::cur()), // b - meta.query_advice(a_3, Rotation::prev()), // b_lo - meta.query_advice(a_4, Rotation::prev()), // spread_b_lo - meta.query_advice(a_5, Rotation::prev()), // b_hi - meta.query_advice(a_6, Rotation::prev()), // spread_b_hi - meta.query_advice(a_5, Rotation::next()), // c - meta.query_advice(a_6, Rotation::next()), // spread_c - meta.query_advice(a_4, Rotation::cur()), // spread_d - meta.query_advice(a_7, Rotation::cur()), // spread_e - meta.query_advice(a_7, Rotation::next()), // spread_f - meta.query_advice(a_5, Rotation::cur()), // spread_g - ) - }); - - // sigma_1 v2 on W_14 to W_48 - // (3, 4, 3, 7, 1, 1, 13)-bit chunks - meta.create_gate("sigma_1 v2", |meta| { - ScheduleGate::s_lower_sigma_1_v2( - meta.query_selector(s_lower_sigma_1_v2), - meta.query_advice(a_2, Rotation::prev()), // spread_r0_even - meta.query_advice(a_2, Rotation::cur()), // spread_r0_odd - meta.query_advice(a_2, Rotation::next()), // spread_r1_even - meta.query_advice(a_3, Rotation::cur()), // spread_r1_odd - meta.query_advice(a_3, Rotation::next()), // a - meta.query_advice(a_4, Rotation::next()), // spread_a - meta.query_advice(a_6, Rotation::cur()), // b - meta.query_advice(a_3, Rotation::prev()), // b_lo - meta.query_advice(a_4, Rotation::prev()), // spread_b_lo - meta.query_advice(a_5, Rotation::prev()), // b_hi - meta.query_advice(a_6, Rotation::prev()), // spread_b_hi - meta.query_advice(a_5, Rotation::next()), // c - meta.query_advice(a_6, Rotation::next()), // spread_c - meta.query_advice(a_4, Rotation::cur()), // spread_d - meta.query_advice(a_7, Rotation::cur()), // spread_e - meta.query_advice(a_7, Rotation::next()), // spread_f - meta.query_advice(a_5, Rotation::cur()), // spread_g - ) - }); - - // sigma_1 v1 on W_49 to W_61 - // (10, 7, 2, 13)-bit chunks - meta.create_gate("sigma_1 v1", |meta| { - ScheduleGate::s_lower_sigma_1( - meta.query_selector(s_lower_sigma_1), - meta.query_advice(a_2, Rotation::prev()), // spread_r0_even - meta.query_advice(a_2, Rotation::cur()), // spread_r0_odd - meta.query_advice(a_2, Rotation::next()), // spread_r1_even - meta.query_advice(a_3, Rotation::cur()), // spread_r1_odd - meta.query_advice(a_4, Rotation::cur()), // spread_a - meta.query_advice(a_6, Rotation::cur()), // b - meta.query_advice(a_3, Rotation::prev()), // b_lo - meta.query_advice(a_4, Rotation::prev()), // spread_b_lo - meta.query_advice(a_5, Rotation::prev()), // b_mid - meta.query_advice(a_6, Rotation::prev()), // spread_b_mid - meta.query_advice(a_5, Rotation::next()), // b_hi - meta.query_advice(a_6, Rotation::next()), // spread_b_hi - meta.query_advice(a_3, Rotation::next()), // c - meta.query_advice(a_4, Rotation::next()), // spread_c - meta.query_advice(a_5, Rotation::cur()), // spread_d - ) - }); - - MessageScheduleConfig { - lookup, - message_schedule, - extras, - s_word, - s_decompose_0, - s_decompose_1, - s_decompose_2, - s_decompose_3, - s_lower_sigma_0, - s_lower_sigma_1, - s_lower_sigma_0_v2, - s_lower_sigma_1_v2, - } - } - - #[allow(clippy::type_complexity)] - pub(super) fn process( - &self, - layouter: &mut impl Layouter, - input: [BlockWord; BLOCK_SIZE], - ) -> Result< - ( - [MessageWord; ROUNDS], - [(AssignedBits<16>, AssignedBits<16>); ROUNDS], - ), - Error, - > { - let mut w = Vec::::with_capacity(ROUNDS); - let mut w_halves = Vec::<(AssignedBits<16>, AssignedBits<16>)>::with_capacity(ROUNDS); - - layouter.assign_region( - || "process message block", - |mut region| { - w = Vec::::with_capacity(ROUNDS); - w_halves = Vec::<(AssignedBits<16>, AssignedBits<16>)>::with_capacity(ROUNDS); - - // Assign all fixed columns - for index in 1..14 { - let row = get_word_row(index); - self.s_decompose_1.enable(&mut region, row)?; - self.s_lower_sigma_0.enable(&mut region, row + 3)?; - } - - for index in 14..49 { - let row = get_word_row(index); - self.s_decompose_2.enable(&mut region, row)?; - self.s_lower_sigma_0_v2.enable(&mut region, row + 3)?; - self.s_lower_sigma_1_v2 - .enable(&mut region, row + SIGMA_0_V2_ROWS + 3)?; - - let new_word_idx = index + 2; - self.s_word - .enable(&mut region, get_word_row(new_word_idx - 16) + 1)?; - } - - for index in 49..62 { - let row = get_word_row(index); - self.s_decompose_3.enable(&mut region, row)?; - self.s_lower_sigma_1.enable(&mut region, row + 3)?; - - let new_word_idx = index + 2; - self.s_word - .enable(&mut region, get_word_row(new_word_idx - 16) + 1)?; - } - - for index in 0..64 { - let row = get_word_row(index); - self.s_decompose_0.enable(&mut region, row)?; - } - - // Assign W[0..16] - for (i, word) in input.iter().enumerate() { - let (word, halves) = self.assign_word_and_halves(&mut region, word.0, i)?; - w.push(MessageWord(word)); - w_halves.push(halves); - } - - // Returns the output of sigma_0 on W_[1..14] - let lower_sigma_0_output = self.assign_subregion1(&mut region, &input[1..14])?; - - // sigma_0_v2 and sigma_1_v2 on W_[14..49] - // Returns the output of sigma_0_v2 on W_[36..49], to be used in subregion3 - let lower_sigma_0_v2_output = self.assign_subregion2( - &mut region, - lower_sigma_0_output, - &mut w, - &mut w_halves, - )?; - - // sigma_1 v1 on W[49..62] - self.assign_subregion3( - &mut region, - lower_sigma_0_v2_output, - &mut w, - &mut w_halves, - )?; - - Ok(()) - }, - )?; - - Ok((w.try_into().unwrap(), w_halves.try_into().unwrap())) - } -} - -#[cfg(test)] -mod tests { - use super::super::{ - super::BLOCK_SIZE, util::lebs2ip, BlockWord, SpreadTableChip, Table16Chip, Table16Config, - }; - use super::schedule_util::*; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use halo2curves::pasta::pallas; - - #[test] - fn message_schedule() { - struct MyCircuit {} - - impl Circuit for MyCircuit { - type Config = Table16Config; - type FloorPlanner = SimpleFloorPlanner; - #[cfg(feature = "circuit-params")] - type Params = (); - - fn without_witnesses(&self) -> Self { - MyCircuit {} - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - Table16Chip::configure(meta) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Load lookup table - SpreadTableChip::load(config.lookup.clone(), &mut layouter)?; - - // Provide input - // Test vector: "abc" - let inputs: [BlockWord; BLOCK_SIZE] = msg_schedule_test_input(); - - // Run message_scheduler to get W_[0..64] - let (w, _) = config.message_schedule.process(&mut layouter, inputs)?; - for (word, test_word) in w.iter().zip(MSG_SCHEDULE_TEST_OUTPUT.iter()) { - word.value().assert_if_known(|bits| { - let word: u32 = lebs2ip(bits) as u32; - word == *test_word - }); - } - Ok(()) - } - } - - let circuit: MyCircuit = MyCircuit {}; - - let prover = match MockProver::::run(17, &circuit, vec![]) { - Ok(prover) => prover, - Err(e) => panic!("{:?}", e), - }; - assert_eq!(prover.verify(), Ok(())); - } -} diff --git a/halo2_gadgets/src/sha256/table16/message_schedule/schedule_gates.rs b/halo2_gadgets/src/sha256/table16/message_schedule/schedule_gates.rs deleted file mode 100644 index cf6a917261..0000000000 --- a/halo2_gadgets/src/sha256/table16/message_schedule/schedule_gates.rs +++ /dev/null @@ -1,394 +0,0 @@ -use super::super::Gate; -use ff::PrimeField; -use halo2_proofs::plonk::Expression; -use std::marker::PhantomData; - -pub struct ScheduleGate(PhantomData); - -impl ScheduleGate { - /// s_word for W_16 to W_63 - #[allow(clippy::too_many_arguments)] - pub fn s_word( - s_word: Expression, - sigma_0_lo: Expression, - sigma_0_hi: Expression, - sigma_1_lo: Expression, - sigma_1_hi: Expression, - w_minus_9_lo: Expression, - w_minus_9_hi: Expression, - w_minus_16_lo: Expression, - w_minus_16_hi: Expression, - word: Expression, - carry: Expression, - ) -> impl Iterator)> { - let lo = sigma_0_lo + sigma_1_lo + w_minus_9_lo + w_minus_16_lo; - let hi = sigma_0_hi + sigma_1_hi + w_minus_9_hi + w_minus_16_hi; - - let word_check = lo - + hi * F::from(1 << 16) - + (carry.clone() * F::from(1 << 32) * (-F::ONE)) - + (word * (-F::ONE)); - let carry_check = Gate::range_check(carry, 0, 3); - - [("word_check", word_check), ("carry_check", carry_check)] - .into_iter() - .map(move |(name, poly)| (name, s_word.clone() * poly)) - } - - /// s_decompose_0 for all words - pub fn s_decompose_0( - s_decompose_0: Expression, - lo: Expression, - hi: Expression, - word: Expression, - ) -> Option<(&'static str, Expression)> { - let check = lo + hi * F::from(1 << 16) - word; - Some(("s_decompose_0", s_decompose_0 * check)) - } - - /// s_decompose_1 for W_1 to W_13 - /// (3, 4, 11, 14)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_decompose_1( - s_decompose_1: Expression, - a: Expression, - b: Expression, - c: Expression, - tag_c: Expression, - d: Expression, - tag_d: Expression, - word: Expression, - ) -> impl Iterator)> { - let decompose_check = - a + b * F::from(1 << 3) + c * F::from(1 << 7) + d * F::from(1 << 18) + word * (-F::ONE); - let range_check_tag_c = Gate::range_check(tag_c, 0, 2); - let range_check_tag_d = Gate::range_check(tag_d, 0, 4); - - [ - ("decompose_check", decompose_check), - ("range_check_tag_c", range_check_tag_c), - ("range_check_tag_d", range_check_tag_d), - ] - .into_iter() - .map(move |(name, poly)| (name, s_decompose_1.clone() * poly)) - } - - /// s_decompose_2 for W_14 to W_48 - /// (3, 4, 3, 7, 1, 1, 13)-bit chunks - #[allow(clippy::many_single_char_names)] - #[allow(clippy::too_many_arguments)] - pub fn s_decompose_2( - s_decompose_2: Expression, - a: Expression, - b: Expression, - c: Expression, - d: Expression, - tag_d: Expression, - e: Expression, - f: Expression, - g: Expression, - tag_g: Expression, - word: Expression, - ) -> impl Iterator)> { - let decompose_check = a - + b * F::from(1 << 3) - + c * F::from(1 << 7) - + d * F::from(1 << 10) - + e * F::from(1 << 17) - + f * F::from(1 << 18) - + g * F::from(1 << 19) - + word * (-F::ONE); - let range_check_tag_d = Gate::range_check(tag_d, 0, 0); - let range_check_tag_g = Gate::range_check(tag_g, 0, 3); - - [ - ("decompose_check", decompose_check), - ("range_check_tag_g", range_check_tag_g), - ("range_check_tag_d", range_check_tag_d), - ] - .into_iter() - .map(move |(name, poly)| (name, s_decompose_2.clone() * poly)) - } - - /// s_decompose_3 for W_49 to W_61 - /// (10, 7, 2, 13)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_decompose_3( - s_decompose_3: Expression, - a: Expression, - tag_a: Expression, - b: Expression, - c: Expression, - d: Expression, - tag_d: Expression, - word: Expression, - ) -> impl Iterator)> { - let decompose_check = a - + b * F::from(1 << 10) - + c * F::from(1 << 17) - + d * F::from(1 << 19) - + word * (-F::ONE); - let range_check_tag_a = Gate::range_check(tag_a, 0, 1); - let range_check_tag_d = Gate::range_check(tag_d, 0, 3); - - [ - ("decompose_check", decompose_check), - ("range_check_tag_a", range_check_tag_a), - ("range_check_tag_d", range_check_tag_d), - ] - .into_iter() - .map(move |(name, poly)| (name, s_decompose_3.clone() * poly)) - } - - /// b_lo + 2^2 * b_mid = b, on W_[1..49] - fn check_b(b: Expression, b_lo: Expression, b_hi: Expression) -> Expression { - let expected_b = b_lo + b_hi * F::from(1 << 2); - expected_b - b - } - - /// sigma_0 v1 on W_1 to W_13 - /// (3, 4, 11, 14)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_lower_sigma_0( - s_lower_sigma_0: Expression, - spread_r0_even: Expression, - spread_r0_odd: Expression, - spread_r1_even: Expression, - spread_r1_odd: Expression, - a: Expression, - spread_a: Expression, - b: Expression, - b_lo: Expression, - spread_b_lo: Expression, - b_hi: Expression, - spread_b_hi: Expression, - spread_c: Expression, - spread_d: Expression, - ) -> impl Iterator)> { - let check_spread_and_range = - Gate::two_bit_spread_and_range(b_lo.clone(), spread_b_lo.clone()) - .chain(Gate::two_bit_spread_and_range( - b_hi.clone(), - spread_b_hi.clone(), - )) - .chain(Gate::three_bit_spread_and_range(a, spread_a.clone())); - let check_b = Self::check_b(b, b_lo, b_hi); - let spread_witness = spread_r0_even - + spread_r0_odd * F::from(2) - + (spread_r1_even + spread_r1_odd * F::from(2)) * F::from(1 << 32); - let xor_0 = spread_b_lo.clone() - + spread_b_hi.clone() * F::from(1 << 4) - + spread_c.clone() * F::from(1 << 8) - + spread_d.clone() * F::from(1 << 30); - let xor_1 = spread_c.clone() - + spread_d.clone() * F::from(1 << 22) - + spread_a.clone() * F::from(1 << 50) - + spread_b_lo.clone() * F::from(1 << 56) - + spread_b_hi.clone() * F::from(1 << 60); - let xor_2 = spread_d - + spread_a * F::from(1 << 28) - + spread_b_lo * F::from(1 << 34) - + spread_b_hi * F::from(1 << 38) - + spread_c * F::from(1 << 42); - let xor = xor_0 + xor_1 + xor_2; - - check_spread_and_range - .chain(Some(("check_b", check_b))) - .chain(Some(("lower_sigma_0", spread_witness - xor))) - .map(move |(name, poly)| (name, s_lower_sigma_0.clone() * poly)) - } - - /// sigma_1 v1 on W_49 to W_61 - /// (10, 7, 2, 13)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_lower_sigma_1( - s_lower_sigma_1: Expression, - spread_r0_even: Expression, - spread_r0_odd: Expression, - spread_r1_even: Expression, - spread_r1_odd: Expression, - spread_a: Expression, - b: Expression, - b_lo: Expression, - spread_b_lo: Expression, - b_mid: Expression, - spread_b_mid: Expression, - b_hi: Expression, - spread_b_hi: Expression, - c: Expression, - spread_c: Expression, - spread_d: Expression, - ) -> impl Iterator)> { - let check_spread_and_range = - Gate::two_bit_spread_and_range(b_lo.clone(), spread_b_lo.clone()) - .chain(Gate::two_bit_spread_and_range( - b_mid.clone(), - spread_b_mid.clone(), - )) - .chain(Gate::two_bit_spread_and_range(c, spread_c.clone())) - .chain(Gate::three_bit_spread_and_range( - b_hi.clone(), - spread_b_hi.clone(), - )); - // b_lo + 2^2 * b_mid + 2^4 * b_hi = b, on W_[49..62] - let check_b1 = { - let expected_b = b_lo + b_mid * F::from(1 << 2) + b_hi * F::from(1 << 4); - expected_b - b - }; - let spread_witness = spread_r0_even - + spread_r0_odd * F::from(2) - + (spread_r1_even + spread_r1_odd * F::from(2)) * F::from(1 << 32); - let xor_0 = spread_b_lo.clone() - + spread_b_mid.clone() * F::from(1 << 4) - + spread_b_hi.clone() * F::from(1 << 8) - + spread_c.clone() * F::from(1 << 14) - + spread_d.clone() * F::from(1 << 18); - let xor_1 = spread_c.clone() - + spread_d.clone() * F::from(1 << 4) - + spread_a.clone() * F::from(1 << 30) - + spread_b_lo.clone() * F::from(1 << 50) - + spread_b_mid.clone() * F::from(1 << 54) - + spread_b_hi.clone() * F::from(1 << 58); - let xor_2 = spread_d - + spread_a * F::from(1 << 26) - + spread_b_lo * F::from(1 << 46) - + spread_b_mid * F::from(1 << 50) - + spread_b_hi * F::from(1 << 54) - + spread_c * F::from(1 << 60); - let xor = xor_0 + xor_1 + xor_2; - - check_spread_and_range - .chain(Some(("check_b1", check_b1))) - .chain(Some(("lower_sigma_1", spread_witness - xor))) - .map(move |(name, poly)| (name, s_lower_sigma_1.clone() * poly)) - } - - /// sigma_0 v2 on W_14 to W_48 - /// (3, 4, 3, 7, 1, 1, 13)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_lower_sigma_0_v2( - s_lower_sigma_0_v2: Expression, - spread_r0_even: Expression, - spread_r0_odd: Expression, - spread_r1_even: Expression, - spread_r1_odd: Expression, - a: Expression, - spread_a: Expression, - b: Expression, - b_lo: Expression, - spread_b_lo: Expression, - b_hi: Expression, - spread_b_hi: Expression, - c: Expression, - spread_c: Expression, - spread_d: Expression, - spread_e: Expression, - spread_f: Expression, - spread_g: Expression, - ) -> impl Iterator)> { - let check_spread_and_range = - Gate::two_bit_spread_and_range(b_lo.clone(), spread_b_lo.clone()) - .chain(Gate::two_bit_spread_and_range( - b_hi.clone(), - spread_b_hi.clone(), - )) - .chain(Gate::three_bit_spread_and_range(a, spread_a.clone())) - .chain(Gate::three_bit_spread_and_range(c, spread_c.clone())); - let check_b = Self::check_b(b, b_lo, b_hi); - let spread_witness = spread_r0_even - + spread_r0_odd * F::from(2) - + (spread_r1_even + spread_r1_odd * F::from(2)) * F::from(1 << 32); - let xor_0 = spread_b_lo.clone() - + spread_b_hi.clone() * F::from(1 << 4) - + spread_c.clone() * F::from(1 << 8) - + spread_d.clone() * F::from(1 << 14) - + spread_e.clone() * F::from(1 << 28) - + spread_f.clone() * F::from(1 << 30) - + spread_g.clone() * F::from(1 << 32); - let xor_1 = spread_c.clone() - + spread_d.clone() * F::from(1 << 6) - + spread_e.clone() * F::from(1 << 20) - + spread_f.clone() * F::from(1 << 22) - + spread_g.clone() * F::from(1 << 24) - + spread_a.clone() * F::from(1 << 50) - + spread_b_lo.clone() * F::from(1 << 56) - + spread_b_hi.clone() * F::from(1 << 60); - let xor_2 = spread_f - + spread_g * F::from(1 << 2) - + spread_a * F::from(1 << 28) - + spread_b_lo * F::from(1 << 34) - + spread_b_hi * F::from(1 << 38) - + spread_c * F::from(1 << 42) - + spread_d * F::from(1 << 48) - + spread_e * F::from(1 << 62); - let xor = xor_0 + xor_1 + xor_2; - - check_spread_and_range - .chain(Some(("check_b", check_b))) - .chain(Some(("lower_sigma_0_v2", spread_witness - xor))) - .map(move |(name, poly)| (name, s_lower_sigma_0_v2.clone() * poly)) - } - - /// sigma_1 v2 on W_14 to W_48 - /// (3, 4, 3, 7, 1, 1, 13)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_lower_sigma_1_v2( - s_lower_sigma_1_v2: Expression, - spread_r0_even: Expression, - spread_r0_odd: Expression, - spread_r1_even: Expression, - spread_r1_odd: Expression, - a: Expression, - spread_a: Expression, - b: Expression, - b_lo: Expression, - spread_b_lo: Expression, - b_hi: Expression, - spread_b_hi: Expression, - c: Expression, - spread_c: Expression, - spread_d: Expression, - spread_e: Expression, - spread_f: Expression, - spread_g: Expression, - ) -> impl Iterator)> { - let check_spread_and_range = - Gate::two_bit_spread_and_range(b_lo.clone(), spread_b_lo.clone()) - .chain(Gate::two_bit_spread_and_range( - b_hi.clone(), - spread_b_hi.clone(), - )) - .chain(Gate::three_bit_spread_and_range(a, spread_a.clone())) - .chain(Gate::three_bit_spread_and_range(c, spread_c.clone())); - let check_b = Self::check_b(b, b_lo, b_hi); - let spread_witness = spread_r0_even - + spread_r0_odd * F::from(2) - + (spread_r1_even + spread_r1_odd * F::from(2)) * F::from(1 << 32); - let xor_0 = spread_d.clone() - + spread_e.clone() * F::from(1 << 14) - + spread_f.clone() * F::from(1 << 16) - + spread_g.clone() * F::from(1 << 18); - let xor_1 = spread_e.clone() - + spread_f.clone() * F::from(1 << 2) - + spread_g.clone() * F::from(1 << 4) - + spread_a.clone() * F::from(1 << 30) - + spread_b_lo.clone() * F::from(1 << 36) - + spread_b_hi.clone() * F::from(1 << 40) - + spread_c.clone() * F::from(1 << 44) - + spread_d.clone() * F::from(1 << 50); - let xor_2 = spread_g - + spread_a * F::from(1 << 26) - + spread_b_lo * F::from(1 << 32) - + spread_b_hi * F::from(1 << 36) - + spread_c * F::from(1 << 40) - + spread_d * F::from(1 << 46) - + spread_e * F::from(1 << 60) - + spread_f * F::from(1 << 62); - let xor = xor_0 + xor_1 + xor_2; - - check_spread_and_range - .chain(Some(("check_b", check_b))) - .chain(Some(("lower_sigma_1_v2", spread_witness - xor))) - .map(move |(name, poly)| (name, s_lower_sigma_1_v2.clone() * poly)) - } -} diff --git a/halo2_gadgets/src/sha256/table16/message_schedule/schedule_util.rs b/halo2_gadgets/src/sha256/table16/message_schedule/schedule_util.rs deleted file mode 100644 index 42ed58a835..0000000000 --- a/halo2_gadgets/src/sha256/table16/message_schedule/schedule_util.rs +++ /dev/null @@ -1,181 +0,0 @@ -use super::super::AssignedBits; -use super::MessageScheduleConfig; -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::Error, -}; -use halo2curves::pasta::pallas; - -#[cfg(test)] -use super::super::{super::BLOCK_SIZE, BlockWord, ROUNDS}; - -// Rows needed for each gate -pub const DECOMPOSE_0_ROWS: usize = 2; -pub const DECOMPOSE_1_ROWS: usize = 2; -pub const DECOMPOSE_2_ROWS: usize = 3; -pub const DECOMPOSE_3_ROWS: usize = 2; -pub const SIGMA_0_V1_ROWS: usize = 4; -pub const SIGMA_0_V2_ROWS: usize = 4; -pub const SIGMA_1_V1_ROWS: usize = 4; -pub const SIGMA_1_V2_ROWS: usize = 4; - -// Rows needed for each subregion -pub const SUBREGION_0_LEN: usize = 1; // W_0 -pub const SUBREGION_0_ROWS: usize = SUBREGION_0_LEN * DECOMPOSE_0_ROWS; -pub const SUBREGION_1_WORD: usize = DECOMPOSE_1_ROWS + SIGMA_0_V1_ROWS; -pub const SUBREGION_1_LEN: usize = 13; // W_[1..14] -pub const SUBREGION_1_ROWS: usize = SUBREGION_1_LEN * SUBREGION_1_WORD; -pub const SUBREGION_2_WORD: usize = DECOMPOSE_2_ROWS + SIGMA_0_V2_ROWS + SIGMA_1_V2_ROWS; -pub const SUBREGION_2_LEN: usize = 35; // W_[14..49] -pub const SUBREGION_2_ROWS: usize = SUBREGION_2_LEN * SUBREGION_2_WORD; -pub const SUBREGION_3_WORD: usize = DECOMPOSE_3_ROWS + SIGMA_1_V1_ROWS; -pub const SUBREGION_3_LEN: usize = 13; // W[49..62] -pub const SUBREGION_3_ROWS: usize = SUBREGION_3_LEN * SUBREGION_3_WORD; -// pub const SUBREGION_4_LEN: usize = 2; // W_[62..64] -// pub const SUBREGION_4_ROWS: usize = SUBREGION_4_LEN * DECOMPOSE_0_ROWS; - -/// Returns row number of a word -pub fn get_word_row(word_idx: usize) -> usize { - assert!(word_idx <= 63); - if word_idx == 0 { - 0 - } else if (1..=13).contains(&word_idx) { - SUBREGION_0_ROWS + SUBREGION_1_WORD * (word_idx - 1) - } else if (14..=48).contains(&word_idx) { - SUBREGION_0_ROWS + SUBREGION_1_ROWS + SUBREGION_2_WORD * (word_idx - 14) + 1 - } else if (49..=61).contains(&word_idx) { - SUBREGION_0_ROWS + SUBREGION_1_ROWS + SUBREGION_2_ROWS + SUBREGION_3_WORD * (word_idx - 49) - } else { - SUBREGION_0_ROWS - + SUBREGION_1_ROWS - + SUBREGION_2_ROWS - + SUBREGION_3_ROWS - + DECOMPOSE_0_ROWS * (word_idx - 62) - } -} - -/// Test vector: "abc" -#[cfg(test)] -pub fn msg_schedule_test_input() -> [BlockWord; BLOCK_SIZE] { - [ - BlockWord(Value::known(0b01100001011000100110001110000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000011000)), - ] -} - -#[cfg(test)] -pub const MSG_SCHEDULE_TEST_OUTPUT: [u32; ROUNDS] = [ - 0b01100001011000100110001110000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000011000, - 0b01100001011000100110001110000000, - 0b00000000000011110000000000000000, - 0b01111101101010000110010000000101, - 0b01100000000000000000001111000110, - 0b00111110100111010111101101111000, - 0b00000001100000111111110000000000, - 0b00010010110111001011111111011011, - 0b11100010111000101100001110001110, - 0b11001000001000010101110000011010, - 0b10110111001101100111100110100010, - 0b11100101101111000011100100001001, - 0b00110010011001100011110001011011, - 0b10011101001000001001110101100111, - 0b11101100100001110010011011001011, - 0b01110000001000010011100010100100, - 0b11010011101101111001011100111011, - 0b10010011111101011001100101111111, - 0b00111011011010001011101001110011, - 0b10101111111101001111111111000001, - 0b11110001000010100101110001100010, - 0b00001010100010110011100110010110, - 0b01110010101011111000001100001010, - 0b10010100000010011110001100111110, - 0b00100100011001000001010100100010, - 0b10011111010001111011111110010100, - 0b11110000101001100100111101011010, - 0b00111110001001000110101001111001, - 0b00100111001100110011101110100011, - 0b00001100010001110110001111110010, - 0b10000100000010101011111100100111, - 0b01111010001010010000110101011101, - 0b00000110010111000100001111011010, - 0b11111011001111101000100111001011, - 0b11001100011101100001011111011011, - 0b10111001111001100110110000110100, - 0b10101001100110010011011001100111, - 0b10000100101110101101111011011101, - 0b11000010000101000110001010111100, - 0b00010100100001110100011100101100, - 0b10110010000011110111101010011001, - 0b11101111010101111011100111001101, - 0b11101011111001101011001000111000, - 0b10011111111000110000100101011110, - 0b01111000101111001000110101001011, - 0b10100100001111111100111100010101, - 0b01100110100010110010111111111000, - 0b11101110101010111010001011001100, - 0b00010010101100011110110111101011, -]; - -impl MessageScheduleConfig { - // Assign a word and its hi and lo halves - pub fn assign_word_and_halves( - &self, - region: &mut Region<'_, pallas::Base>, - word: Value, - word_idx: usize, - ) -> Result<(AssignedBits<32>, (AssignedBits<16>, AssignedBits<16>)), Error> { - // Rename these here for ease of matching the gates to the specification. - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - - let row = get_word_row(word_idx); - - let w_lo = { - let w_lo_val = word.map(|word| word as u16); - AssignedBits::<16>::assign(region, || format!("W_{}_lo", word_idx), a_3, row, w_lo_val)? - }; - let w_hi = { - let w_hi_val = word.map(|word| (word >> 16) as u16); - AssignedBits::<16>::assign(region, || format!("W_{}_hi", word_idx), a_4, row, w_hi_val)? - }; - - let word = AssignedBits::<32>::assign( - region, - || format!("W_{}", word_idx), - self.message_schedule, - row, - word, - )?; - - Ok((word, (w_lo, w_hi))) - } -} diff --git a/halo2_gadgets/src/sha256/table16/message_schedule/subregion1.rs b/halo2_gadgets/src/sha256/table16/message_schedule/subregion1.rs deleted file mode 100644 index 947c9dda2a..0000000000 --- a/halo2_gadgets/src/sha256/table16/message_schedule/subregion1.rs +++ /dev/null @@ -1,223 +0,0 @@ -use super::super::{util::*, AssignedBits, BlockWord, SpreadVar, SpreadWord, Table16Assignment}; -use super::{schedule_util::*, MessageScheduleConfig}; -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::Error, -}; -use halo2curves::pasta::pallas; -use std::convert::TryInto; - -// A word in subregion 1 -// (3, 4, 11, 14)-bit chunks -#[derive(Debug)] -pub struct Subregion1Word { - index: usize, - a: AssignedBits<3>, - b: AssignedBits<4>, - c: AssignedBits<11>, - d: AssignedBits<14>, - spread_c: AssignedBits<22>, - spread_d: AssignedBits<28>, -} - -impl Subregion1Word { - fn spread_a(&self) -> Value<[bool; 6]> { - self.a.value().map(|v| v.spread()) - } - - fn spread_b(&self) -> Value<[bool; 8]> { - self.b.value().map(|v| v.spread()) - } - - fn spread_c(&self) -> Value<[bool; 22]> { - self.spread_c.value().map(|v| v.0) - } - - fn spread_d(&self) -> Value<[bool; 28]> { - self.spread_d.value().map(|v| v.0) - } - - fn xor_lower_sigma_0(&self) -> Value<[bool; 64]> { - self.spread_a() - .zip(self.spread_b()) - .zip(self.spread_c()) - .zip(self.spread_d()) - .map(|(((a, b), c), d)| { - let xor_0 = b - .iter() - .chain(c.iter()) - .chain(d.iter()) - .chain(std::iter::repeat(&false).take(6)) - .copied() - .collect::>(); - let xor_1 = c - .iter() - .chain(d.iter()) - .chain(a.iter()) - .chain(b.iter()) - .copied() - .collect::>(); - let xor_2 = d - .iter() - .chain(a.iter()) - .chain(b.iter()) - .chain(c.iter()) - .copied() - .collect::>(); - - let xor_0 = lebs2ip::<64>(&xor_0.try_into().unwrap()); - let xor_1 = lebs2ip::<64>(&xor_1.try_into().unwrap()); - let xor_2 = lebs2ip::<64>(&xor_2.try_into().unwrap()); - - i2lebsp(xor_0 + xor_1 + xor_2) - }) - } -} - -impl MessageScheduleConfig { - pub fn assign_subregion1( - &self, - region: &mut Region<'_, pallas::Base>, - input: &[BlockWord], - ) -> Result, AssignedBits<16>)>, Error> { - assert_eq!(input.len(), SUBREGION_1_LEN); - Ok(input - .iter() - .enumerate() - .map(|(idx, word)| { - // s_decompose_1 on W_[1..14] - let subregion1_word = self - .decompose_subregion1_word( - region, - word.0.map(|word| i2lebsp(word.into())), - idx + 1, - ) - .unwrap(); - - // lower_sigma_0 on W_[1..14] - self.lower_sigma_0(region, subregion1_word).unwrap() - }) - .collect::>()) - } - - /// Pieces of length [3, 4, 11, 14] - fn decompose_subregion1_word( - &self, - region: &mut Region<'_, pallas::Base>, - word: Value<[bool; 32]>, - index: usize, - ) -> Result { - let row = get_word_row(index); - - // Rename these here for ease of matching the gates to the specification. - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - - let pieces = word.map(|word| { - vec![ - word[0..3].to_vec(), - word[3..7].to_vec(), - word[7..18].to_vec(), - word[18..32].to_vec(), - ] - }); - let pieces = pieces.transpose_vec(4); - - // Assign `a` (3-bit piece) - let a = - AssignedBits::<3>::assign_bits(region, || "word_a", a_3, row + 1, pieces[0].clone())?; - // Assign `b` (4-bit piece) - let b = - AssignedBits::<4>::assign_bits(region, || "word_b", a_4, row + 1, pieces[1].clone())?; - - // Assign `c` (11-bit piece) lookup - let spread_c = pieces[2].clone().map(SpreadWord::try_new); - let spread_c = SpreadVar::with_lookup(region, &self.lookup, row + 1, spread_c)?; - - // Assign `d` (14-bit piece) lookup - let spread_d = pieces[3].clone().map(SpreadWord::try_new); - let spread_d = SpreadVar::with_lookup(region, &self.lookup, row, spread_d)?; - - Ok(Subregion1Word { - index, - a, - b, - c: spread_c.dense, - d: spread_d.dense, - spread_c: spread_c.spread, - spread_d: spread_d.spread, - }) - } - - // sigma_0 v1 on a word in W_1 to W_13 - // (3, 4, 11, 14)-bit chunks - fn lower_sigma_0( - &self, - region: &mut Region<'_, pallas::Base>, - word: Subregion1Word, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - - let row = get_word_row(word.index) + 3; - - // Assign `a` and copy constraint - word.a.copy_advice(|| "a", region, a_5, row + 1)?; - - // Witness `spread_a` - let spread_a = word.a.value().map(|bits| spread_bits(bits.0)); - AssignedBits::<6>::assign_bits(region, || "spread_a", a_6, row + 1, spread_a)?; - - // Split `b` (4-bit chunk) into `b_hi` and `b_lo` - // Assign `b_lo`, `spread_b_lo` - let b_lo: Value<[bool; 2]> = word.b.value().map(|b| b.0[..2].try_into().unwrap()); - let spread_b_lo = b_lo.map(spread_bits); - { - AssignedBits::<2>::assign_bits(region, || "b_lo", a_3, row - 1, b_lo)?; - - AssignedBits::<4>::assign_bits(region, || "spread_b_lo", a_4, row - 1, spread_b_lo)?; - }; - - // Split `b` (2-bit chunk) into `b_hi` and `b_lo` - // Assign `b_hi`, `spread_b_hi` - let b_hi: Value<[bool; 2]> = word.b.value().map(|b| b.0[2..].try_into().unwrap()); - let spread_b_hi = b_hi.map(spread_bits); - { - AssignedBits::<2>::assign_bits(region, || "b_hi", a_5, row - 1, b_hi)?; - - AssignedBits::<4>::assign_bits(region, || "spread_b_hi", a_6, row - 1, spread_b_hi)?; - }; - - // Assign `b` and copy constraint - word.b.copy_advice(|| "b", region, a_6, row)?; - - // Assign `spread_c` and copy constraint - word.spread_c.copy_advice(|| "spread_c", region, a_4, row)?; - - // Assign `spread_d` and copy constraint - word.spread_d.copy_advice(|| "spread_d", region, a_5, row)?; - - // Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - let r = word.xor_lower_sigma_0(); - let r_0: Value<[bool; 32]> = r.map(|r| r[..32].try_into().unwrap()); - let r_0_even = r_0.map(even_bits); - let r_0_odd = r_0.map(odd_bits); - - let r_1: Value<[bool; 32]> = r.map(|r| r[32..].try_into().unwrap()); - let r_1_even = r_1.map(even_bits); - let r_1_odd = r_1.map(odd_bits); - - self.assign_sigma_outputs( - region, - &self.lookup, - a_3, - row, - r_0_even, - r_0_odd, - r_1_even, - r_1_odd, - ) - } -} diff --git a/halo2_gadgets/src/sha256/table16/message_schedule/subregion2.rs b/halo2_gadgets/src/sha256/table16/message_schedule/subregion2.rs deleted file mode 100644 index 9733b46039..0000000000 --- a/halo2_gadgets/src/sha256/table16/message_schedule/subregion2.rs +++ /dev/null @@ -1,487 +0,0 @@ -use super::super::{util::*, AssignedBits, Bits, SpreadVar, SpreadWord, Table16Assignment}; -use super::{schedule_util::*, MessageScheduleConfig, MessageWord}; -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::Error, -}; -use halo2curves::pasta::pallas; -use std::convert::TryInto; - -/// A word in subregion 2 -/// (3, 4, 3, 7, 1, 1, 13)-bit chunks -#[derive(Clone, Debug)] -pub struct Subregion2Word { - index: usize, - a: AssignedBits<3>, - b: AssignedBits<4>, - c: AssignedBits<3>, - d: AssignedBits<7>, - e: AssignedBits<1>, - f: AssignedBits<1>, - g: AssignedBits<13>, - spread_d: AssignedBits<14>, - spread_g: AssignedBits<26>, -} - -impl Subregion2Word { - fn spread_a(&self) -> Value<[bool; 6]> { - self.a.value().map(|v| v.spread()) - } - - fn spread_b(&self) -> Value<[bool; 8]> { - self.b.value().map(|v| v.spread()) - } - - fn spread_c(&self) -> Value<[bool; 6]> { - self.c.value().map(|v| v.spread()) - } - - fn spread_d(&self) -> Value<[bool; 14]> { - self.spread_d.value().map(|v| v.0) - } - - fn spread_e(&self) -> Value<[bool; 2]> { - self.e.value().map(|v| v.spread()) - } - - fn spread_f(&self) -> Value<[bool; 2]> { - self.f.value().map(|v| v.spread()) - } - - fn spread_g(&self) -> Value<[bool; 26]> { - self.spread_g.value().map(|v| v.0) - } - - fn xor_sigma_0(&self) -> Value<[bool; 64]> { - self.spread_a() - .zip(self.spread_b()) - .zip(self.spread_c()) - .zip(self.spread_d()) - .zip(self.spread_e()) - .zip(self.spread_f()) - .zip(self.spread_g()) - .map(|((((((a, b), c), d), e), f), g)| { - let xor_0 = b - .iter() - .chain(c.iter()) - .chain(d.iter()) - .chain(e.iter()) - .chain(f.iter()) - .chain(g.iter()) - .chain(std::iter::repeat(&false).take(6)) - .copied() - .collect::>(); - - let xor_1 = c - .iter() - .chain(d.iter()) - .chain(e.iter()) - .chain(f.iter()) - .chain(g.iter()) - .chain(a.iter()) - .chain(b.iter()) - .copied() - .collect::>(); - - let xor_2 = f - .iter() - .chain(g.iter()) - .chain(a.iter()) - .chain(b.iter()) - .chain(c.iter()) - .chain(d.iter()) - .chain(e.iter()) - .copied() - .collect::>(); - - let xor_0 = lebs2ip::<64>(&xor_0.try_into().unwrap()); - let xor_1 = lebs2ip::<64>(&xor_1.try_into().unwrap()); - let xor_2 = lebs2ip::<64>(&xor_2.try_into().unwrap()); - - i2lebsp(xor_0 + xor_1 + xor_2) - }) - } - - fn xor_sigma_1(&self) -> Value<[bool; 64]> { - self.spread_a() - .zip(self.spread_b()) - .zip(self.spread_c()) - .zip(self.spread_d()) - .zip(self.spread_e()) - .zip(self.spread_f()) - .zip(self.spread_g()) - .map(|((((((a, b), c), d), e), f), g)| { - let xor_0 = d - .iter() - .chain(e.iter()) - .chain(f.iter()) - .chain(g.iter()) - .chain(std::iter::repeat(&false).take(20)) - .copied() - .collect::>(); - - let xor_1 = e - .iter() - .chain(f.iter()) - .chain(g.iter()) - .chain(a.iter()) - .chain(b.iter()) - .chain(c.iter()) - .chain(d.iter()) - .copied() - .collect::>(); - - let xor_2 = g - .iter() - .chain(a.iter()) - .chain(b.iter()) - .chain(c.iter()) - .chain(d.iter()) - .chain(e.iter()) - .chain(f.iter()) - .copied() - .collect::>(); - - let xor_0 = lebs2ip::<64>(&xor_0.try_into().unwrap()); - let xor_1 = lebs2ip::<64>(&xor_1.try_into().unwrap()); - let xor_2 = lebs2ip::<64>(&xor_2.try_into().unwrap()); - - i2lebsp(xor_0 + xor_1 + xor_2) - }) - } -} - -impl MessageScheduleConfig { - // W_[14..49] - pub fn assign_subregion2( - &self, - region: &mut Region<'_, pallas::Base>, - lower_sigma_0_output: Vec<(AssignedBits<16>, AssignedBits<16>)>, - w: &mut Vec, - w_halves: &mut Vec<(AssignedBits<16>, AssignedBits<16>)>, - ) -> Result, AssignedBits<16>)>, Error> { - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - let a_7 = self.extras[3]; - let a_8 = self.extras[4]; - let a_9 = self.extras[5]; - - let mut lower_sigma_0_v2_results = - Vec::<(AssignedBits<16>, AssignedBits<16>)>::with_capacity(SUBREGION_2_LEN); - let mut lower_sigma_1_v2_results = - Vec::<(AssignedBits<16>, AssignedBits<16>)>::with_capacity(SUBREGION_2_LEN); - - // Closure to compose new word - // W_i = sigma_1(W_{i - 2}) + W_{i - 7} + sigma_0(W_{i - 15}) + W_{i - 16} - // e.g. W_16 = sigma_1(W_14) + W_9 + sigma_0(W_1) + W_0 - - // sigma_0(W_[1..14]) will be used to get the new W_[16..29] - // sigma_0_v2(W_[14..36]) will be used to get the new W_[29..51] - // sigma_1_v2(W_[14..49]) will be used to get the W_[16..51] - // The lowest-index words involved will be W_[0..13] - let mut new_word = |idx: usize, - sigma_0_output: &(AssignedBits<16>, AssignedBits<16>)| - -> Result, AssignedBits<16>)>, Error> { - // Decompose word into (3, 4, 3, 7, 1, 1, 13)-bit chunks - let word = self.decompose_word(region, w[idx].value(), idx)?; - - // sigma_0 v2 and sigma_1 v2 on word - lower_sigma_0_v2_results.push(self.lower_sigma_0_v2(region, word.clone())?); - lower_sigma_1_v2_results.push(self.lower_sigma_1_v2(region, word)?); - - let new_word_idx = idx + 2; - - // Copy sigma_0(W_{i - 15}) output from Subregion 1 - sigma_0_output.0.copy_advice( - || format!("sigma_0(W_{})_lo", new_word_idx - 15), - region, - a_6, - get_word_row(new_word_idx - 16), - )?; - sigma_0_output.1.copy_advice( - || format!("sigma_0(W_{})_hi", new_word_idx - 15), - region, - a_6, - get_word_row(new_word_idx - 16) + 1, - )?; - - // Copy sigma_1(W_{i - 2}) - lower_sigma_1_v2_results[new_word_idx - 16].0.copy_advice( - || format!("sigma_1(W_{})_lo", new_word_idx - 2), - region, - a_7, - get_word_row(new_word_idx - 16), - )?; - lower_sigma_1_v2_results[new_word_idx - 16].1.copy_advice( - || format!("sigma_1(W_{})_hi", new_word_idx - 2), - region, - a_7, - get_word_row(new_word_idx - 16) + 1, - )?; - - // Copy W_{i - 7} - w_halves[new_word_idx - 7].0.copy_advice( - || format!("W_{}_lo", new_word_idx - 7), - region, - a_8, - get_word_row(new_word_idx - 16), - )?; - w_halves[new_word_idx - 7].1.copy_advice( - || format!("W_{}_hi", new_word_idx - 7), - region, - a_8, - get_word_row(new_word_idx - 16) + 1, - )?; - - // Calculate W_i, carry_i - let (word, carry) = sum_with_carry(vec![ - ( - lower_sigma_1_v2_results[new_word_idx - 16].0.value_u16(), - lower_sigma_1_v2_results[new_word_idx - 16].1.value_u16(), - ), - ( - w_halves[new_word_idx - 7].0.value_u16(), - w_halves[new_word_idx - 7].1.value_u16(), - ), - (sigma_0_output.0.value_u16(), sigma_0_output.1.value_u16()), - ( - w_halves[new_word_idx - 16].0.value_u16(), - w_halves[new_word_idx - 16].1.value_u16(), - ), - ]); - - // Assign W_i, carry_i - region.assign_advice( - || format!("W_{}", new_word_idx), - a_5, - get_word_row(new_word_idx - 16) + 1, - || word.map(|word| pallas::Base::from(word as u64)), - )?; - region.assign_advice( - || format!("carry_{}", new_word_idx), - a_9, - get_word_row(new_word_idx - 16) + 1, - || carry.map(pallas::Base::from), - )?; - let (word, halves) = self.assign_word_and_halves(region, word, new_word_idx)?; - w.push(MessageWord(word)); - w_halves.push(halves); - - Ok(lower_sigma_0_v2_results.clone()) - }; - - let mut tmp_lower_sigma_0_v2_results: Vec<(AssignedBits<16>, AssignedBits<16>)> = - Vec::with_capacity(SUBREGION_2_LEN); - - // Use up all the output from Subregion 1 lower_sigma_0 - for i in 14..27 { - tmp_lower_sigma_0_v2_results = new_word(i, &lower_sigma_0_output[i - 14])?; - } - - for i in 27..49 { - tmp_lower_sigma_0_v2_results = - new_word(i, &tmp_lower_sigma_0_v2_results[i + 2 - 15 - 14])?; - } - - // Return lower_sigma_0_v2 output for W_[36..49] - Ok(lower_sigma_0_v2_results.split_off(36 - 14)) - } - - /// Pieces of length [3, 4, 3, 7, 1, 1, 13] - fn decompose_word( - &self, - region: &mut Region<'_, pallas::Base>, - word: Value<&Bits<32>>, - index: usize, - ) -> Result { - let row = get_word_row(index); - - let pieces = word.map(|word| { - vec![ - word[0..3].to_vec(), - word[3..7].to_vec(), - word[7..10].to_vec(), - word[10..17].to_vec(), - vec![word[17]], - vec![word[18]], - word[19..32].to_vec(), - ] - }); - let pieces = pieces.transpose_vec(7); - - // Rename these here for ease of matching the gates to the specification. - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - - // Assign `a` (3-bit piece) - let a = AssignedBits::<3>::assign_bits(region, || "a", a_3, row - 1, pieces[0].clone())?; - - // Assign `b` (4-bit piece) lookup - let spread_b: Value> = pieces[1].clone().map(SpreadWord::try_new); - let spread_b = SpreadVar::with_lookup(region, &self.lookup, row + 1, spread_b)?; - - // Assign `c` (3-bit piece) - let c = AssignedBits::<3>::assign_bits(region, || "c", a_4, row - 1, pieces[2].clone())?; - - // Assign `d` (7-bit piece) lookup - let spread_d: Value> = pieces[3].clone().map(SpreadWord::try_new); - let spread_d = SpreadVar::with_lookup(region, &self.lookup, row, spread_d)?; - - // Assign `e` (1-bit piece) - let e = AssignedBits::<1>::assign_bits(region, || "e", a_3, row + 1, pieces[4].clone())?; - - // Assign `f` (1-bit piece) - let f = AssignedBits::<1>::assign_bits(region, || "f", a_4, row + 1, pieces[5].clone())?; - - // Assign `g` (13-bit piece) lookup - let spread_g = pieces[6].clone().map(SpreadWord::try_new); - let spread_g = SpreadVar::with_lookup(region, &self.lookup, row - 1, spread_g)?; - - Ok(Subregion2Word { - index, - a, - b: spread_b.dense, - c, - d: spread_d.dense, - e, - f, - g: spread_g.dense, - spread_d: spread_d.spread, - spread_g: spread_g.spread, - }) - } - - /// A word in subregion 2 - /// (3, 4, 3, 7, 1, 1, 13)-bit chunks - #[allow(clippy::type_complexity)] - fn assign_lower_sigma_v2_pieces( - &self, - region: &mut Region<'_, pallas::Base>, - row: usize, - word: &Subregion2Word, - ) -> Result<(), Error> { - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - let a_7 = self.extras[3]; - - // Assign `a` and copy constraint - word.a.copy_advice(|| "a", region, a_3, row + 1)?; - - // Witness `spread_a` - AssignedBits::<6>::assign_bits(region, || "spread_a", a_4, row + 1, word.spread_a())?; - - // Split `b` (4-bit chunk) into `b_hi` and `b_lo` - // Assign `b_lo`, `spread_b_lo` - - let b_lo: Value<[bool; 2]> = word.b.value().map(|b| b.0[..2].try_into().unwrap()); - let spread_b_lo = b_lo.map(spread_bits); - { - AssignedBits::<2>::assign_bits(region, || "b_lo", a_3, row - 1, b_lo)?; - - AssignedBits::<4>::assign_bits(region, || "spread_b_lo", a_4, row - 1, spread_b_lo)?; - }; - - // Split `b` (2-bit chunk) into `b_hi` and `b_lo` - // Assign `b_hi`, `spread_b_hi` - let b_hi: Value<[bool; 2]> = word.b.value().map(|b| b.0[2..].try_into().unwrap()); - let spread_b_hi = b_hi.map(spread_bits); - { - AssignedBits::<2>::assign_bits(region, || "b_hi", a_5, row - 1, b_hi)?; - - AssignedBits::<4>::assign_bits(region, || "spread_b_hi", a_6, row - 1, spread_b_hi)?; - }; - - // Assign `b` and copy constraint - word.b.copy_advice(|| "b", region, a_6, row)?; - - // Assign `c` and copy constraint - word.c.copy_advice(|| "c", region, a_5, row + 1)?; - - // Witness `spread_c` - AssignedBits::<6>::assign_bits(region, || "spread_c", a_6, row + 1, word.spread_c())?; - - // Assign `spread_d` and copy constraint - word.spread_d.copy_advice(|| "spread_d", region, a_4, row)?; - - // Assign `e` and copy constraint - word.e.copy_advice(|| "e", region, a_7, row)?; - - // Assign `f` and copy constraint - word.f.copy_advice(|| "f", region, a_7, row + 1)?; - - // Assign `spread_g` and copy constraint - word.spread_g.copy_advice(|| "spread_g", region, a_5, row)?; - - Ok(()) - } - - fn lower_sigma_0_v2( - &self, - region: &mut Region<'_, pallas::Base>, - word: Subregion2Word, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let a_3 = self.extras[0]; - let row = get_word_row(word.index) + 3; - - // Assign lower sigma_v2 pieces - self.assign_lower_sigma_v2_pieces(region, row, &word)?; - - // Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - let r = word.xor_sigma_0(); - let r_0: Value<[bool; 32]> = r.map(|r| r[..32].try_into().unwrap()); - let r_0_even = r_0.map(even_bits); - let r_0_odd = r_0.map(odd_bits); - - let r_1: Value<[bool; 32]> = r.map(|r| r[32..].try_into().unwrap()); - let r_1_even = r_1.map(even_bits); - let r_1_odd = r_1.map(odd_bits); - - self.assign_sigma_outputs( - region, - &self.lookup, - a_3, - row, - r_0_even, - r_0_odd, - r_1_even, - r_1_odd, - ) - } - - fn lower_sigma_1_v2( - &self, - region: &mut Region<'_, pallas::Base>, - word: Subregion2Word, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let a_3 = self.extras[0]; - let row = get_word_row(word.index) + SIGMA_0_V2_ROWS + 3; - - // Assign lower sigma_v2 pieces - self.assign_lower_sigma_v2_pieces(region, row, &word)?; - - // (3, 4, 3, 7, 1, 1, 13) - // Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - // Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - let r = word.xor_sigma_1(); - let r_0: Value<[bool; 32]> = r.map(|r| r[..32].try_into().unwrap()); - let r_0_even = r_0.map(even_bits); - let r_0_odd = r_0.map(odd_bits); - - let r_1: Value<[bool; 32]> = r.map(|r| r[32..].try_into().unwrap()); - let r_1_even = r_1.map(even_bits); - let r_1_odd = r_1.map(odd_bits); - - self.assign_sigma_outputs( - region, - &self.lookup, - a_3, - row, - r_0_even, - r_0_odd, - r_1_even, - r_1_odd, - ) - } -} diff --git a/halo2_gadgets/src/sha256/table16/message_schedule/subregion3.rs b/halo2_gadgets/src/sha256/table16/message_schedule/subregion3.rs deleted file mode 100644 index aebe1945d9..0000000000 --- a/halo2_gadgets/src/sha256/table16/message_schedule/subregion3.rs +++ /dev/null @@ -1,320 +0,0 @@ -use super::super::{util::*, AssignedBits, Bits, SpreadVar, SpreadWord, Table16Assignment}; -use super::{schedule_util::*, MessageScheduleConfig, MessageWord}; -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::Error, -}; -use halo2curves::pasta::pallas; -use std::convert::TryInto; - -// A word in subregion 3 -// (10, 7, 2, 13)-bit chunks -pub struct Subregion3Word { - index: usize, - #[allow(dead_code)] - a: AssignedBits<10>, - b: AssignedBits<7>, - c: AssignedBits<2>, - #[allow(dead_code)] - d: AssignedBits<13>, - spread_a: AssignedBits<20>, - spread_d: AssignedBits<26>, -} - -impl Subregion3Word { - fn spread_a(&self) -> Value<[bool; 20]> { - self.spread_a.value().map(|v| v.0) - } - - fn spread_b(&self) -> Value<[bool; 14]> { - self.b.value().map(|v| v.spread()) - } - - fn spread_c(&self) -> Value<[bool; 4]> { - self.c.value().map(|v| v.spread()) - } - - fn spread_d(&self) -> Value<[bool; 26]> { - self.spread_d.value().map(|v| v.0) - } - - fn xor_lower_sigma_1(&self) -> Value<[bool; 64]> { - self.spread_a() - .zip(self.spread_b()) - .zip(self.spread_c()) - .zip(self.spread_d()) - .map(|(((a, b), c), d)| { - let xor_0 = b - .iter() - .chain(c.iter()) - .chain(d.iter()) - .chain(std::iter::repeat(&false).take(20)) - .copied() - .collect::>(); - - let xor_1 = c - .iter() - .chain(d.iter()) - .chain(a.iter()) - .chain(b.iter()) - .copied() - .collect::>(); - let xor_2 = d - .iter() - .chain(a.iter()) - .chain(b.iter()) - .chain(c.iter()) - .copied() - .collect::>(); - - let xor_0 = lebs2ip::<64>(&xor_0.try_into().unwrap()); - let xor_1 = lebs2ip::<64>(&xor_1.try_into().unwrap()); - let xor_2 = lebs2ip::<64>(&xor_2.try_into().unwrap()); - - i2lebsp(xor_0 + xor_1 + xor_2) - }) - } -} - -impl MessageScheduleConfig { - // W_[49..62] - pub fn assign_subregion3( - &self, - region: &mut Region<'_, pallas::Base>, - lower_sigma_0_v2_output: Vec<(AssignedBits<16>, AssignedBits<16>)>, - w: &mut Vec, - w_halves: &mut Vec<(AssignedBits<16>, AssignedBits<16>)>, - ) -> Result<(), Error> { - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - let a_7 = self.extras[3]; - let a_8 = self.extras[4]; - let a_9 = self.extras[5]; - - // Closure to compose new word - // W_i = sigma_1(W_{i - 2}) + W_{i - 7} + sigma_0(W_{i - 15}) + W_{i - 16} - // e.g. W_51 = sigma_1(W_49) + W_44 + sigma_0(W_36) + W_35 - - // sigma_0_v2(W_[36..49]) will be used to get the new W_[51..64] - // sigma_1(W_[49..62]) will also be used to get the W_[51..64] - // The lowest-index words involved will be W_[35..58] - let mut new_word = |idx: usize| -> Result<(), Error> { - // Decompose word into (10, 7, 2, 13)-bit chunks - let subregion3_word = self.decompose_subregion3_word(region, w[idx].value(), idx)?; - - // sigma_1 on subregion3_word - let (r_0_even, r_1_even) = self.lower_sigma_1(region, subregion3_word)?; - - let new_word_idx = idx + 2; - - // Copy sigma_0_v2(W_{i - 15}) output from Subregion 2 - lower_sigma_0_v2_output[idx - 49].0.copy_advice( - || format!("sigma_0(W_{})_lo", new_word_idx - 15), - region, - a_6, - get_word_row(new_word_idx - 16), - )?; - lower_sigma_0_v2_output[idx - 49].1.copy_advice( - || format!("sigma_0(W_{})_hi", new_word_idx - 15), - region, - a_6, - get_word_row(new_word_idx - 16) + 1, - )?; - - // Copy sigma_1(W_{i - 2}) - r_0_even.copy_advice( - || format!("sigma_1(W_{})_lo", new_word_idx - 2), - region, - a_7, - get_word_row(new_word_idx - 16), - )?; - r_1_even.copy_advice( - || format!("sigma_1(W_{})_hi", new_word_idx - 2), - region, - a_7, - get_word_row(new_word_idx - 16) + 1, - )?; - - // Copy W_{i - 7} - w_halves[new_word_idx - 7].0.copy_advice( - || format!("W_{}_lo", new_word_idx - 7), - region, - a_8, - get_word_row(new_word_idx - 16), - )?; - w_halves[new_word_idx - 7].1.copy_advice( - || format!("W_{}_hi", new_word_idx - 7), - region, - a_8, - get_word_row(new_word_idx - 16) + 1, - )?; - - // Calculate W_i, carry_i - let (word, carry) = sum_with_carry(vec![ - (r_0_even.value_u16(), r_1_even.value_u16()), - ( - w_halves[new_word_idx - 7].0.value_u16(), - w_halves[new_word_idx - 7].1.value_u16(), - ), - ( - lower_sigma_0_v2_output[idx - 49].0.value_u16(), - lower_sigma_0_v2_output[idx - 49].1.value_u16(), - ), - ( - w_halves[new_word_idx - 16].0.value_u16(), - w_halves[new_word_idx - 16].1.value_u16(), - ), - ]); - - // Assign W_i, carry_i - region.assign_advice( - || format!("W_{}", new_word_idx), - a_5, - get_word_row(new_word_idx - 16) + 1, - || word.map(|word| pallas::Base::from(word as u64)), - )?; - region.assign_advice( - || format!("carry_{}", new_word_idx), - a_9, - get_word_row(new_word_idx - 16) + 1, - || carry.map(pallas::Base::from), - )?; - let (word, halves) = self.assign_word_and_halves(region, word, new_word_idx)?; - w.push(MessageWord(word)); - w_halves.push(halves); - - Ok(()) - }; - - for i in 49..62 { - new_word(i)?; - } - - Ok(()) - } - - /// Pieces of length [10, 7, 2, 13] - fn decompose_subregion3_word( - &self, - region: &mut Region<'_, pallas::Base>, - word: Value<&Bits<32>>, - index: usize, - ) -> Result { - let row = get_word_row(index); - - // Rename these here for ease of matching the gates to the specification. - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - - let pieces = word.map(|word| { - vec![ - word[0..10].to_vec(), - word[10..17].to_vec(), - word[17..19].to_vec(), - word[19..32].to_vec(), - ] - }); - let pieces = pieces.transpose_vec(4); - - // Assign `a` (10-bit piece) - let spread_a = pieces[0].clone().map(SpreadWord::try_new); - let spread_a = SpreadVar::with_lookup(region, &self.lookup, row + 1, spread_a)?; - - // Assign `b` (7-bit piece) - let b = AssignedBits::<7>::assign_bits(region, || "b", a_4, row + 1, pieces[1].clone())?; - - // Assign `c` (2-bit piece) - let c = AssignedBits::<2>::assign_bits(region, || "c", a_3, row + 1, pieces[2].clone())?; - - // Assign `d` (13-bit piece) lookup - let spread_d = pieces[3].clone().map(SpreadWord::try_new); - let spread_d = SpreadVar::with_lookup(region, &self.lookup, row, spread_d)?; - - Ok(Subregion3Word { - index, - a: spread_a.dense, - b, - c, - d: spread_d.dense, - spread_a: spread_a.spread, - spread_d: spread_d.spread, - }) - } - - fn lower_sigma_1( - &self, - region: &mut Region<'_, pallas::Base>, - word: Subregion3Word, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - - let row = get_word_row(word.index) + 3; - - // Assign `spread_a` and copy constraint - word.spread_a.copy_advice(|| "spread_a", region, a_4, row)?; - - // Split `b` (7-bit chunk) into (2, 2, 3)-bit `b_lo`, `b_mid` and `b_hi`. - // Assign `b_lo`, `spread_b_lo`, `b_mid`, `spread_b_mid`, `b_hi`, `spread_b_hi`. - - // b_lo (2-bit chunk) - { - let b_lo: Value<[bool; 2]> = word.b.value().map(|v| v[0..2].try_into().unwrap()); - let b_lo = b_lo.map(SpreadWord::<2, 4>::new); - SpreadVar::without_lookup(region, a_3, row - 1, a_4, row - 1, b_lo)?; - } - - // b_mid (2-bit chunk) - { - let b_mid: Value<[bool; 2]> = word.b.value().map(|v| v[2..4].try_into().unwrap()); - let b_mid = b_mid.map(SpreadWord::<2, 4>::new); - SpreadVar::without_lookup(region, a_5, row - 1, a_6, row - 1, b_mid)?; - } - - // b_hi (3-bit chunk) - { - let b_hi: Value<[bool; 3]> = word.b.value().map(|v| v[4..7].try_into().unwrap()); - let b_hi = b_hi.map(SpreadWord::<3, 6>::new); - SpreadVar::without_lookup(region, a_5, row + 1, a_6, row + 1, b_hi)?; - } - - // Assign `b` and copy constraint - word.b.copy_advice(|| "b", region, a_6, row)?; - - // Assign `c` and copy constraint - word.c.copy_advice(|| "c", region, a_3, row + 1)?; - - // Witness `spread_c` - { - let spread_c = word.c.value().map(spread_bits); - AssignedBits::<4>::assign_bits(region, || "spread_c", a_4, row + 1, spread_c)?; - } - - // Assign `spread_d` and copy constraint - word.spread_d.copy_advice(|| "spread_d", region, a_5, row)?; - - // (10, 7, 2, 13) - // Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - let r = word.xor_lower_sigma_1(); - let r_0: Value<[bool; 32]> = r.map(|r| r[..32].try_into().unwrap()); - let r_0_even = r_0.map(even_bits); - let r_0_odd = r_0.map(odd_bits); - - let r_1: Value<[bool; 32]> = r.map(|r| r[32..].try_into().unwrap()); - let r_1_even = r_1.map(even_bits); - let r_1_odd = r_1.map(odd_bits); - - self.assign_sigma_outputs( - region, - &self.lookup, - a_3, - row, - r_0_even, - r_0_odd, - r_1_even, - r_1_odd, - ) - } -} diff --git a/halo2_gadgets/src/sha256/table16/spread_table.rs b/halo2_gadgets/src/sha256/table16/spread_table.rs deleted file mode 100644 index 9b8a313cc2..0000000000 --- a/halo2_gadgets/src/sha256/table16/spread_table.rs +++ /dev/null @@ -1,448 +0,0 @@ -use super::{util::*, AssignedBits}; -use ff::PrimeField; -use halo2_proofs::{ - arithmetic::Field, - circuit::{Chip, Layouter, Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, TableColumn}, - poly::Rotation, -}; -use halo2curves::pasta::pallas; -use std::convert::TryInto; -use std::marker::PhantomData; - -const BITS_7: usize = 1 << 7; -const BITS_10: usize = 1 << 10; -const BITS_11: usize = 1 << 11; -const BITS_13: usize = 1 << 13; -const BITS_14: usize = 1 << 14; - -/// An input word into a lookup, containing (tag, dense, spread) -#[derive(Copy, Clone, Debug)] -pub(super) struct SpreadWord { - pub tag: u8, - pub dense: [bool; DENSE], - pub spread: [bool; SPREAD], -} - -/// Helper function that returns tag of 16-bit input -pub fn get_tag(input: u16) -> u8 { - let input = input as usize; - if input < BITS_7 { - 0 - } else if input < BITS_10 { - 1 - } else if input < BITS_11 { - 2 - } else if input < BITS_13 { - 3 - } else if input < BITS_14 { - 4 - } else { - 5 - } -} - -impl SpreadWord { - pub(super) fn new(dense: [bool; DENSE]) -> Self { - assert!(DENSE <= 16); - SpreadWord { - tag: get_tag(lebs2ip(&dense) as u16), - dense, - spread: spread_bits(dense), - } - } - - pub(super) fn try_new + std::fmt::Debug>(dense: T) -> Self - where - >::Error: std::fmt::Debug, - { - assert!(DENSE <= 16); - let dense: [bool; DENSE] = dense.try_into().unwrap(); - SpreadWord { - tag: get_tag(lebs2ip(&dense) as u16), - dense, - spread: spread_bits(dense), - } - } -} - -/// A variable stored in advice columns corresponding to a row of [`SpreadTableConfig`]. -#[derive(Clone, Debug)] -pub(super) struct SpreadVar { - pub tag: Value, - pub dense: AssignedBits, - pub spread: AssignedBits, -} - -impl SpreadVar { - pub(super) fn with_lookup( - region: &mut Region<'_, pallas::Base>, - cols: &SpreadInputs, - row: usize, - word: Value>, - ) -> Result { - let tag = word.map(|word| word.tag); - let dense_val = word.map(|word| word.dense); - let spread_val = word.map(|word| word.spread); - - region.assign_advice( - || "tag", - cols.tag, - row, - || tag.map(|tag| pallas::Base::from(tag as u64)), - )?; - - let dense = - AssignedBits::::assign_bits(region, || "dense", cols.dense, row, dense_val)?; - - let spread = - AssignedBits::::assign_bits(region, || "spread", cols.spread, row, spread_val)?; - - Ok(SpreadVar { tag, dense, spread }) - } - - pub(super) fn without_lookup( - region: &mut Region<'_, pallas::Base>, - dense_col: Column, - dense_row: usize, - spread_col: Column, - spread_row: usize, - word: Value>, - ) -> Result { - let tag = word.map(|word| word.tag); - let dense_val = word.map(|word| word.dense); - let spread_val = word.map(|word| word.spread); - - let dense = AssignedBits::::assign_bits( - region, - || "dense", - dense_col, - dense_row, - dense_val, - )?; - - let spread = AssignedBits::::assign_bits( - region, - || "spread", - spread_col, - spread_row, - spread_val, - )?; - - Ok(SpreadVar { tag, dense, spread }) - } -} - -#[derive(Clone, Debug)] -pub(super) struct SpreadInputs { - pub(super) tag: Column, - pub(super) dense: Column, - pub(super) spread: Column, -} - -#[derive(Clone, Debug)] -pub(super) struct SpreadTable { - pub(super) tag: TableColumn, - pub(super) dense: TableColumn, - pub(super) spread: TableColumn, -} - -#[derive(Clone, Debug)] -pub(super) struct SpreadTableConfig { - pub input: SpreadInputs, - pub table: SpreadTable, -} - -#[derive(Clone, Debug)] -pub(super) struct SpreadTableChip { - config: SpreadTableConfig, - _marker: PhantomData, -} - -impl Chip for SpreadTableChip { - type Config = SpreadTableConfig; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -impl SpreadTableChip { - pub fn configure( - meta: &mut ConstraintSystem, - input_tag: Column, - input_dense: Column, - input_spread: Column, - ) -> >::Config { - let table_tag = meta.lookup_table_column(); - let table_dense = meta.lookup_table_column(); - let table_spread = meta.lookup_table_column(); - - meta.lookup("lookup", |meta| { - let tag_cur = meta.query_advice(input_tag, Rotation::cur()); - let dense_cur = meta.query_advice(input_dense, Rotation::cur()); - let spread_cur = meta.query_advice(input_spread, Rotation::cur()); - - vec![ - (tag_cur, table_tag), - (dense_cur, table_dense), - (spread_cur, table_spread), - ] - }); - - SpreadTableConfig { - input: SpreadInputs { - tag: input_tag, - dense: input_dense, - spread: input_spread, - }, - table: SpreadTable { - tag: table_tag, - dense: table_dense, - spread: table_spread, - }, - } - } - - pub fn load( - config: SpreadTableConfig, - layouter: &mut impl Layouter, - ) -> Result<>::Loaded, Error> { - layouter.assign_table( - || "spread table", - |mut table| { - // We generate the row values lazily (we only need them during keygen). - let mut rows = SpreadTableConfig::generate::(); - - for index in 0..(1 << 16) { - let mut row = None; - table.assign_cell( - || "tag", - config.table.tag, - index, - || { - row = rows.next(); - Value::known(row.map(|(tag, _, _)| tag).unwrap()) - }, - )?; - table.assign_cell( - || "dense", - config.table.dense, - index, - || Value::known(row.map(|(_, dense, _)| dense).unwrap()), - )?; - table.assign_cell( - || "spread", - config.table.spread, - index, - || Value::known(row.map(|(_, _, spread)| spread).unwrap()), - )?; - } - - Ok(()) - }, - ) - } -} - -impl SpreadTableConfig { - fn generate() -> impl Iterator { - (1..=(1 << 16)).scan((F::ZERO, F::ZERO, F::ZERO), |(tag, dense, spread), i| { - // We computed this table row in the previous iteration. - let res = (*tag, *dense, *spread); - - // i holds the zero-indexed row number for the next table row. - match i { - BITS_7 | BITS_10 | BITS_11 | BITS_13 | BITS_14 => *tag += F::ONE, - _ => (), - } - *dense += F::ONE; - if i & 1 == 0 { - // On even-numbered rows we recompute the spread. - *spread = F::ZERO; - for b in 0..16 { - if (i >> b) & 1 != 0 { - *spread += F::from(1 << (2 * b)); - } - } - } else { - // On odd-numbered rows we add one. - *spread += F::ONE; - } - - Some(res) - }) - } -} - -#[cfg(test)] -mod tests { - use super::{get_tag, SpreadTableChip, SpreadTableConfig}; - use ff::PrimeField; - use rand::Rng; - - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Advice, Circuit, Column, ConstraintSystem, Error}, - }; - use halo2curves::pasta::Fp; - - #[test] - fn lookup_table() { - /// This represents an advice column at a certain row in the ConstraintSystem - #[derive(Copy, Clone, Debug)] - pub struct Variable(Column, usize); - - struct MyCircuit {} - - impl Circuit for MyCircuit { - type Config = SpreadTableConfig; - type FloorPlanner = SimpleFloorPlanner; - #[cfg(feature = "circuit-params")] - type Params = (); - - fn without_witnesses(&self) -> Self { - MyCircuit {} - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let input_tag = meta.advice_column(); - let input_dense = meta.advice_column(); - let input_spread = meta.advice_column(); - - SpreadTableChip::configure(meta, input_tag, input_dense, input_spread) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - SpreadTableChip::load(config.clone(), &mut layouter)?; - - layouter.assign_region( - || "spread_test", - |mut gate| { - let mut row = 0; - let mut add_row = |tag, dense, spread| -> Result<(), Error> { - gate.assign_advice( - || "tag", - config.input.tag, - row, - || Value::known(tag), - )?; - gate.assign_advice( - || "dense", - config.input.dense, - row, - || Value::known(dense), - )?; - gate.assign_advice( - || "spread", - config.input.spread, - row, - || Value::known(spread), - )?; - row += 1; - Ok(()) - }; - - // Test the first few small values. - add_row(F::ZERO, F::from(0b000), F::from(0b000000))?; - add_row(F::ZERO, F::from(0b001), F::from(0b000001))?; - add_row(F::ZERO, F::from(0b010), F::from(0b000100))?; - add_row(F::ZERO, F::from(0b011), F::from(0b000101))?; - add_row(F::ZERO, F::from(0b100), F::from(0b010000))?; - add_row(F::ZERO, F::from(0b101), F::from(0b010001))?; - - // Test the tag boundaries: - // 7-bit - add_row(F::ZERO, F::from(0b1111111), F::from(0b01010101010101))?; - add_row(F::ONE, F::from(0b10000000), F::from(0b0100000000000000))?; - // - 10-bit - add_row( - F::ONE, - F::from(0b1111111111), - F::from(0b01010101010101010101), - )?; - add_row( - F::from(2), - F::from(0b10000000000), - F::from(0b0100000000000000000000), - )?; - // - 11-bit - add_row( - F::from(2), - F::from(0b11111111111), - F::from(0b0101010101010101010101), - )?; - add_row( - F::from(3), - F::from(0b100000000000), - F::from(0b010000000000000000000000), - )?; - // - 13-bit - add_row( - F::from(3), - F::from(0b1111111111111), - F::from(0b01010101010101010101010101), - )?; - add_row( - F::from(4), - F::from(0b10000000000000), - F::from(0b0100000000000000000000000000), - )?; - // - 14-bit - add_row( - F::from(4), - F::from(0b11111111111111), - F::from(0b0101010101010101010101010101), - )?; - add_row( - F::from(5), - F::from(0b100000000000000), - F::from(0b010000000000000000000000000000), - )?; - - // Test random lookup values - let mut rng = rand::thread_rng(); - - fn interleave_u16_with_zeros(word: u16) -> u32 { - let mut word: u32 = word.into(); - word = (word ^ (word << 8)) & 0x00ff00ff; - word = (word ^ (word << 4)) & 0x0f0f0f0f; - word = (word ^ (word << 2)) & 0x33333333; - word = (word ^ (word << 1)) & 0x55555555; - word - } - - for _ in 0..10 { - let word: u16 = rng.gen(); - add_row( - F::from(u64::from(get_tag(word))), - F::from(u64::from(word)), - F::from(u64::from(interleave_u16_with_zeros(word))), - )?; - } - - Ok(()) - }, - ) - } - } - - let circuit: MyCircuit = MyCircuit {}; - - let prover = match MockProver::::run(17, &circuit, vec![]) { - Ok(prover) => prover, - Err(e) => panic!("{:?}", e), - }; - assert_eq!(prover.verify(), Ok(())); - } -} diff --git a/halo2_gadgets/src/sha256/table16/util.rs b/halo2_gadgets/src/sha256/table16/util.rs deleted file mode 100644 index d3da5317ca..0000000000 --- a/halo2_gadgets/src/sha256/table16/util.rs +++ /dev/null @@ -1,117 +0,0 @@ -use halo2_proofs::circuit::Value; - -pub const MASK_EVEN_32: u32 = 0x55555555; - -/// The sequence of bits representing a u64 in little-endian order. -/// -/// # Panics -/// -/// Panics if the expected length of the sequence `NUM_BITS` exceeds -/// 64. -pub fn i2lebsp(int: u64) -> [bool; NUM_BITS] { - /// Takes in an FnMut closure and returns a constant-length array with elements of - /// type `Output`. - fn gen_const_array( - closure: impl FnMut(usize) -> Output, - ) -> [Output; LEN] { - gen_const_array_with_default(Default::default(), closure) - } - - fn gen_const_array_with_default( - default_value: Output, - closure: impl FnMut(usize) -> Output, - ) -> [Output; LEN] { - let mut ret: [Output; LEN] = [default_value; LEN]; - for (bit, val) in ret.iter_mut().zip((0..LEN).map(closure)) { - *bit = val; - } - ret - } - - assert!(NUM_BITS <= 64); - gen_const_array(|mask: usize| (int & (1 << mask)) != 0) -} - -/// Returns the integer representation of a little-endian bit-array. -/// Panics if the number of bits exceeds 64. -pub fn lebs2ip(bits: &[bool; K]) -> u64 { - assert!(K <= 64); - bits.iter() - .enumerate() - .fold(0u64, |acc, (i, b)| acc + if *b { 1 << i } else { 0 }) -} - -/// Helper function that interleaves a little-endian bit-array with zeros -/// in the odd indices. That is, it takes the array -/// [b_0, b_1, ..., b_n] -/// to -/// [b_0, 0, b_1, 0, ..., b_n, 0]. -/// Panics if bit-array is longer than 16 bits. -pub fn spread_bits( - bits: impl Into<[bool; DENSE]>, -) -> [bool; SPREAD] { - assert_eq!(DENSE * 2, SPREAD); - assert!(DENSE <= 16); - - let bits: [bool; DENSE] = bits.into(); - let mut spread = [false; SPREAD]; - - for (idx, bit) in bits.iter().enumerate() { - spread[idx * 2] = *bit; - } - - spread -} - -/// Negates the even bits in a spread bit-array. -pub fn negate_spread(arr: [bool; LEN]) -> [bool; LEN] { - assert_eq!(LEN % 2, 0); - - let mut neg = arr; - for even_idx in (0..LEN).step_by(2) { - let odd_idx = even_idx + 1; - assert!(!arr[odd_idx]); - - neg[even_idx] = !arr[even_idx]; - } - - neg -} - -/// Returns even bits in a bit-array -pub fn even_bits(bits: [bool; LEN]) -> [bool; HALF] { - assert_eq!(LEN % 2, 0); - let mut even_bits = [false; HALF]; - for idx in 0..HALF { - even_bits[idx] = bits[idx * 2] - } - even_bits -} - -/// Returns odd bits in a bit-array -pub fn odd_bits(bits: [bool; LEN]) -> [bool; HALF] { - assert_eq!(LEN % 2, 0); - let mut odd_bits = [false; HALF]; - for idx in 0..HALF { - odd_bits[idx] = bits[idx * 2 + 1] - } - odd_bits -} - -/// Given a vector of words as vec![(lo: u16, hi: u16)], returns their sum: u32, along -/// with a carry bit. -pub fn sum_with_carry(words: Vec<(Value, Value)>) -> (Value, Value) { - let words_lo: Value> = words.iter().map(|(lo, _)| lo.map(|lo| lo as u64)).collect(); - let words_hi: Value> = words.iter().map(|(_, hi)| hi.map(|hi| hi as u64)).collect(); - - let sum: Value = { - let sum_lo: Value = words_lo.map(|vec| vec.iter().sum()); - let sum_hi: Value = words_hi.map(|vec| vec.iter().sum()); - sum_lo.zip(sum_hi).map(|(lo, hi)| lo + (1 << 16) * hi) - }; - - let carry = sum.map(|sum| (sum >> 32)); - let sum = sum.map(|sum| sum as u32); - - (sum, carry) -} diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs deleted file mode 100644 index 4a20ce4830..0000000000 --- a/halo2_gadgets/src/sinsemilla.rs +++ /dev/null @@ -1,754 +0,0 @@ -//! The [Sinsemilla] hash function. -//! -//! [Sinsemilla]: https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash -use crate::{ - ecc::{self, EccInstructions, FixedPoints}, - utilities::{FieldValue, RangeConstrained, Var}, -}; -use group::ff::{Field, PrimeField}; -use halo2_proofs::{ - circuit::{Layouter, Value}, - plonk::Error, -}; -use halo2curves::CurveAffine; -use std::fmt::Debug; - -pub mod chip; -pub mod merkle; -mod message; -pub mod primitives; - -/// The set of circuit instructions required to use the [`Sinsemilla`](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html) gadget. -/// This trait is bounded on two constant parameters: `K`, the number of bits -/// in each word accepted by the Sinsemilla hash, and `MAX_WORDS`, the maximum -/// number of words that a single hash instance can process. -pub trait SinsemillaInstructions { - /// A variable in the circuit. - type CellValue: Var; - - /// A message composed of [`Self::MessagePiece`]s. - type Message: From>; - - /// A piece in a message containing a number of `K`-bit words. - /// A [`Self::MessagePiece`] fits in a single base field element, - /// which means it can only contain up to `N` words, where - /// `N*K <= C::Base::CAPACITY`. - /// - /// For example, in the case `K = 10`, `CAPACITY = 254`, we can fit - /// up to `N = 25` words in a single base field element. - type MessagePiece: Clone + Debug; - - /// A cumulative sum `z` is used to decompose a Sinsemilla message. It - /// produces intermediate values for each word in the message, such - /// that `z_next` = (`z_cur` - `word_next`) / `2^K`. - /// - /// These intermediate values are useful for range checks on subsets - /// of the Sinsemilla message. Sinsemilla messages in the Orchard - /// protocol are composed of field elements, and we need to check - /// the canonicity of the field element encodings in certain cases. - type RunningSum; - - /// The x-coordinate of a point output of [`Self::hash_to_point`]. - type X; - /// A point output of [`Self::hash_to_point`]. - type NonIdentityPoint: Clone + Debug; - /// A type enumerating the fixed points used in `CommitDomains`. - type FixedPoints: FixedPoints; - - /// HashDomains used in this instruction. - type HashDomains: HashDomains; - /// CommitDomains used in this instruction. - type CommitDomains: CommitDomains; - - /// Witness a message piece given a field element. Returns a [`Self::MessagePiece`] - /// encoding the given message. - /// - /// # Panics - /// - /// Panics if `num_words` exceed the maximum number of `K`-bit words that - /// can fit into a single base field element. - fn witness_message_piece( - &self, - layouter: impl Layouter, - value: Value, - num_words: usize, - ) -> Result; - - /// Hashes a message to an ECC curve point. - /// This returns both the resulting point, as well as the message - /// decomposition in the form of intermediate values in a cumulative - /// sum. - /// - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - fn hash_to_point( - &self, - layouter: impl Layouter, - Q: C, - message: Self::Message, - ) -> Result<(Self::NonIdentityPoint, Vec), Error>; - - /// Extracts the x-coordinate of the output of a Sinsemilla hash. - fn extract(point: &Self::NonIdentityPoint) -> Self::X; -} - -/// A message to be hashed. -/// -/// Composed of [`MessagePiece`]s with bitlength some multiple of `K`. -/// -/// [`MessagePiece`]: SinsemillaInstructions::MessagePiece -#[derive(Clone, Debug)] -pub struct Message -where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, -{ - chip: SinsemillaChip, - inner: SinsemillaChip::Message, -} - -impl - Message -where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, -{ - fn from_bitstring( - chip: SinsemillaChip, - mut layouter: impl Layouter, - bitstring: Vec>, - ) -> Result { - // Message must be composed of `K`-bit words. - assert_eq!(bitstring.len() % K, 0); - - // Message must have at most `MAX_WORDS` words. - assert!(bitstring.len() / K <= MAX_WORDS); - - // Each message piece must have at most `floor(C::CAPACITY / K)` words. - let piece_num_words = C::Base::CAPACITY as usize / K; - let pieces: Result, _> = bitstring - .chunks(piece_num_words * K) - .enumerate() - .map( - |(i, piece)| -> Result, Error> { - MessagePiece::from_bitstring( - chip.clone(), - layouter.namespace(|| format!("message piece {}", i)), - piece, - ) - }, - ) - .collect(); - - pieces.map(|pieces| Self::from_pieces(chip, pieces)) - } - - /// Constructs a message from a vector of [`MessagePiece`]s. - /// - /// [`MessagePiece`]: SinsemillaInstructions::MessagePiece - pub fn from_pieces( - chip: SinsemillaChip, - pieces: Vec>, - ) -> Self { - Self { - chip, - inner: pieces - .into_iter() - .map(|piece| piece.inner) - .collect::>() - .into(), - } - } -} - -/// A message piece with a bitlength of some multiple of `K`. -#[derive(Copy, Clone, Debug)] -pub struct MessagePiece -where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, -{ - chip: SinsemillaChip, - inner: SinsemillaChip::MessagePiece, -} - -impl - MessagePiece -where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, -{ - /// Returns the inner MessagePiece contained in this gadget. - pub fn inner(&self) -> SinsemillaChip::MessagePiece { - self.inner.clone() - } -} - -impl - MessagePiece -where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, -{ - fn from_bitstring( - chip: SinsemillaChip, - layouter: impl Layouter, - bitstring: &[Value], - ) -> Result { - // Message must be composed of `K`-bit words. - assert_eq!(bitstring.len() % K, 0); - let num_words = bitstring.len() / K; - - // Each message piece must have at most `floor(C::Base::CAPACITY / K)` words. - // This ensures that the all-ones bitstring is canonical in the field. - let piece_max_num_words = C::Base::CAPACITY as usize / K; - assert!(num_words <= piece_max_num_words); - - // Closure to parse a bitstring (little-endian) into a base field element. - let to_base_field = |bits: &[Value]| -> Value { - let bits: Value> = bits.iter().cloned().collect(); - bits.map(|bits| { - bits.into_iter().rev().fold(C::Base::ZERO, |acc, bit| { - if bit { - acc.double() + C::Base::ONE - } else { - acc.double() - } - }) - }) - }; - - let piece_value = to_base_field(bitstring); - Self::from_field_elem(chip, layouter, piece_value, num_words) - } - - /// Constructs a MessagePiece from a field element. - pub fn from_field_elem( - chip: SinsemillaChip, - layouter: impl Layouter, - field_elem: Value, - num_words: usize, - ) -> Result { - let inner = chip.witness_message_piece(layouter, field_elem, num_words)?; - Ok(Self { chip, inner }) - } - - /// Constructs a `MessagePiece` by concatenating a sequence of [`RangeConstrained`] - /// subpiece values. - /// - /// The `MessagePiece` is assigned to the circuit, but not constrained in any way. - /// - /// # Panics - /// - /// Panics if the total number of bits across the subpieces is not a multiple of the - /// word size, or if the required bitshift for any subpiece is greater than 63 bits. - pub fn from_subpieces( - chip: SinsemillaChip, - layouter: impl Layouter, - subpieces: impl IntoIterator>>, - ) -> Result { - let (field_elem, total_bits) = subpieces.into_iter().fold( - (Value::known(C::Base::ZERO), 0), - |(acc, bits), subpiece| { - assert!(bits < 64); - let subpiece_shifted = subpiece - .inner() - .value() - .map(|v| C::Base::from(1 << bits) * v); - (acc + subpiece_shifted, bits + subpiece.num_bits()) - }, - ); - - // Message must be composed of `K`-bit words. - assert_eq!(total_bits % K, 0); - let num_words = total_bits / K; - - Self::from_field_elem(chip, layouter, field_elem, num_words) - } -} - -/// A domain in which $\mathsf{SinsemillaHashToPoint}$ and $\mathsf{SinsemillaHash}$ can -/// be used. -#[derive(Debug)] -#[allow(non_snake_case)] -pub struct HashDomain< - C: CurveAffine, - SinsemillaChip, - EccChip, - const K: usize, - const MAX_WORDS: usize, -> where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, - EccChip: EccInstructions< - C, - NonIdentityPoint = >::NonIdentityPoint, - FixedPoints = >::FixedPoints, - > + Clone - + Debug - + Eq, -{ - sinsemilla_chip: SinsemillaChip, - ecc_chip: EccChip, - Q: C, -} - -impl - HashDomain -where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, - EccChip: EccInstructions< - C, - NonIdentityPoint = >::NonIdentityPoint, - FixedPoints = >::FixedPoints, - > + Clone - + Debug - + Eq, -{ - #[allow(non_snake_case)] - /// Constructs a new `HashDomain` for the given domain. - pub fn new( - sinsemilla_chip: SinsemillaChip, - ecc_chip: EccChip, - domain: &SinsemillaChip::HashDomains, - ) -> Self { - HashDomain { - sinsemilla_chip, - ecc_chip, - Q: domain.Q(), - } - } - - #[allow(clippy::type_complexity)] - /// $\mathsf{SinsemillaHashToPoint}$ from [§ 5.4.1.9][concretesinsemillahash]. - /// - /// [concretesinsemillahash]: https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash - pub fn hash_to_point( - &self, - layouter: impl Layouter, - message: Message, - ) -> Result<(ecc::NonIdentityPoint, Vec), Error> { - assert_eq!(self.sinsemilla_chip, message.chip); - self.sinsemilla_chip - .hash_to_point(layouter, self.Q, message.inner) - .map(|(point, zs)| (ecc::NonIdentityPoint::from_inner(self.ecc_chip.clone(), point), zs)) - } - - /// $\mathsf{SinsemillaHash}$ from [§ 5.4.1.9][concretesinsemillahash]. - /// - /// [concretesinsemillahash]: https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash - #[allow(clippy::type_complexity)] - pub fn hash( - &self, - layouter: impl Layouter, - message: Message, - ) -> Result<(ecc::X, Vec), Error> { - assert_eq!(self.sinsemilla_chip, message.chip); - let (p, zs) = self.hash_to_point(layouter, message)?; - Ok((p.extract_p(), zs)) - } -} - -/// Trait allowing circuit's Sinsemilla CommitDomains to be enumerated. -pub trait CommitDomains, H: HashDomains>: - Clone + Debug -{ - /// Returns the fixed point corresponding to the R constant used for - /// randomization in this CommitDomain. - fn r(&self) -> F::FullScalar; - - /// Returns the HashDomain contained in this CommitDomain - fn hash_domain(&self) -> H; -} - -/// Trait allowing circuit's Sinsemilla HashDomains to be enumerated. -#[allow(non_snake_case)] -pub trait HashDomains: Clone + Debug { - /// Returns the `Q` constant for this domain. - fn Q(&self) -> C; -} - -/// Gadget representing a domain in which $\mathsf{SinsemillaCommit}$ and -/// $\mathsf{SinsemillaShortCommit}$ can be used. -#[derive(Debug)] -#[allow(non_snake_case)] -pub struct CommitDomain< - C: CurveAffine, - SinsemillaChip, - EccChip, - const K: usize, - const MAX_WORDS: usize, -> where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, - EccChip: EccInstructions< - C, - NonIdentityPoint = >::NonIdentityPoint, - FixedPoints = >::FixedPoints, - > + Clone - + Debug - + Eq, -{ - M: HashDomain, - R: ecc::FixedPoint, -} - -impl - CommitDomain -where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, - EccChip: EccInstructions< - C, - NonIdentityPoint = >::NonIdentityPoint, - FixedPoints = >::FixedPoints, - > + Clone - + Debug - + Eq, -{ - /// Constructs a new `CommitDomain` for the given domain. - pub fn new( - sinsemilla_chip: SinsemillaChip, - ecc_chip: EccChip, - // TODO: Instead of using SinsemilllaChip::CommitDomains, just use something that implements a CommitDomains trait - domain: &SinsemillaChip::CommitDomains, - ) -> Self { - CommitDomain { - M: HashDomain::new(sinsemilla_chip, ecc_chip.clone(), &domain.hash_domain()), - R: ecc::FixedPoint::from_inner(ecc_chip, domain.r()), - } - } - - #[allow(clippy::type_complexity)] - /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. - /// - /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit - pub fn commit( - &self, - mut layouter: impl Layouter, - message: Message, - r: ecc::ScalarFixed, - ) -> Result< - ( - ecc::Point, - Vec, - ), - Error, - > { - assert_eq!(self.M.sinsemilla_chip, message.chip); - let (blind, _) = self.R.mul(layouter.namespace(|| "[r] R"), r)?; - let (p, zs) = self.M.hash_to_point(layouter.namespace(|| "M"), message)?; - let commitment = p.add(layouter.namespace(|| "M + [r] R"), &blind)?; - Ok((commitment, zs)) - } - - #[allow(clippy::type_complexity)] - /// $\mathsf{SinsemillaShortCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. - /// - /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit - pub fn short_commit( - &self, - mut layouter: impl Layouter, - message: Message, - r: ecc::ScalarFixed, - ) -> Result<(ecc::X, Vec), Error> { - assert_eq!(self.M.sinsemilla_chip, message.chip); - let (p, zs) = self.commit(layouter.namespace(|| "commit"), message, r)?; - Ok((p.extract_p(), zs)) - } -} - -#[cfg(test)] -pub(crate) mod tests { - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use rand::rngs::OsRng; - - use super::{ - chip::{SinsemillaChip, SinsemillaConfig}, - CommitDomain, CommitDomains, HashDomain, HashDomains, Message, MessagePiece, - }; - - use crate::{ - ecc::ScalarFixed, - sinsemilla::primitives::{self as sinsemilla, K}, - { - ecc::{ - chip::{find_zs_and_us, EccChip, EccConfig, H, NUM_WINDOWS}, - tests::{FullWidth, TestFixedBases}, - NonIdentityPoint, - }, - utilities::lookup_range_check::LookupRangeCheckConfig, - }, - }; - - use group::{ff::Field, Curve}; - use halo2curves::pasta::pallas; - use lazy_static::lazy_static; - - use std::convert::TryInto; - - pub(crate) const PERSONALIZATION: &str = "MerkleCRH"; - - lazy_static! { - static ref COMMIT_DOMAIN: sinsemilla::CommitDomain = - sinsemilla::CommitDomain::new(PERSONALIZATION); - static ref Q: pallas::Affine = COMMIT_DOMAIN.Q().to_affine(); - static ref R: pallas::Affine = COMMIT_DOMAIN.R().to_affine(); - static ref R_ZS_AND_US: Vec<(u64, [pallas::Base; H])> = - find_zs_and_us(*R, NUM_WINDOWS).unwrap(); - } - - #[derive(Debug, Clone, Eq, PartialEq)] - pub(crate) struct TestHashDomain; - #[allow(non_snake_case)] - impl HashDomains for TestHashDomain { - fn Q(&self) -> pallas::Affine { - *Q - } - } - - // This test does not make use of the CommitDomain. - #[derive(Debug, Clone, Eq, PartialEq)] - pub(crate) struct TestCommitDomain; - impl CommitDomains for TestCommitDomain { - fn r(&self) -> FullWidth { - FullWidth::from_parts(*R, &R_ZS_AND_US) - } - - fn hash_domain(&self) -> TestHashDomain { - TestHashDomain - } - } - - struct MyCircuit {} - - impl Circuit for MyCircuit { - #[allow(clippy::type_complexity)] - type Config = ( - EccConfig, - SinsemillaConfig, - SinsemillaConfig, - ); - type FloorPlanner = SimpleFloorPlanner; - #[cfg(feature = "circuit-params")] - type Params = (); - - fn without_witnesses(&self) -> Self { - MyCircuit {} - } - - #[allow(non_snake_case)] - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let advices = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - - // Shared fixed column for loading constants - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - let table_idx = meta.lookup_table_column(); - let lagrange_coeffs = [ - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - ]; - - // Fixed columns for the Sinsemilla generator lookup table - let lookup = ( - table_idx, - meta.lookup_table_column(), - meta.lookup_table_column(), - ); - - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx); - - let ecc_config = - EccChip::::configure(meta, advices, lagrange_coeffs, range_check); - - let config1 = SinsemillaChip::configure( - meta, - advices[..5].try_into().unwrap(), - advices[2], - lagrange_coeffs[0], - lookup, - range_check, - ); - let config2 = SinsemillaChip::configure( - meta, - advices[5..].try_into().unwrap(), - advices[7], - lagrange_coeffs[1], - lookup, - range_check, - ); - (ecc_config, config1, config2) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let rng = OsRng; - - let ecc_chip = EccChip::construct(config.0); - - // The two `SinsemillaChip`s share the same lookup table. - SinsemillaChip::::load( - config.1.clone(), - &mut layouter, - )?; - - // This MerkleCRH example is purely for illustrative purposes. - // It is not an implementation of the Orchard protocol spec. - { - let chip1 = SinsemillaChip::construct(config.1); - - let merkle_crh = HashDomain::new(chip1.clone(), ecc_chip.clone(), &TestHashDomain); - - // Layer 31, l = MERKLE_DEPTH - 1 - layer = 0 - let l_bitstring = vec![Value::known(false); K]; - let l = MessagePiece::from_bitstring( - chip1.clone(), - layouter.namespace(|| "l"), - &l_bitstring, - )?; - - // Left leaf - let left_bitstring: Vec> = (0..250) - .map(|_| Value::known(rand::random::())) - .collect(); - let left = MessagePiece::from_bitstring( - chip1.clone(), - layouter.namespace(|| "left"), - &left_bitstring, - )?; - - // Right leaf - let right_bitstring: Vec> = (0..250) - .map(|_| Value::known(rand::random::())) - .collect(); - let right = MessagePiece::from_bitstring( - chip1.clone(), - layouter.namespace(|| "right"), - &right_bitstring, - )?; - - let l_bitstring: Value> = l_bitstring.into_iter().collect(); - let left_bitstring: Value> = left_bitstring.into_iter().collect(); - let right_bitstring: Value> = right_bitstring.into_iter().collect(); - - // Witness expected parent - let expected_parent = { - let expected_parent = l_bitstring.zip(left_bitstring.zip(right_bitstring)).map( - |(l, (left, right))| { - let merkle_crh = sinsemilla::HashDomain::from_Q((*Q).into()); - let point = merkle_crh - .hash_to_point(l.into_iter().chain(left).chain(right)) - .unwrap(); - point.to_affine() - }, - ); - - NonIdentityPoint::new( - ecc_chip.clone(), - layouter.namespace(|| "Witness expected parent"), - expected_parent, - )? - }; - - // Parent - let (parent, _) = { - let message = Message::from_pieces(chip1, vec![l, left, right]); - merkle_crh.hash_to_point(layouter.namespace(|| "parent"), message)? - }; - - parent.constrain_equal( - layouter.namespace(|| "parent == expected parent"), - &expected_parent, - )?; - } - - { - let chip2 = SinsemillaChip::construct(config.2); - - let test_commit = - CommitDomain::new(chip2.clone(), ecc_chip.clone(), &TestCommitDomain); - let r_val = pallas::Scalar::random(rng); - let message: Vec> = (0..500) - .map(|_| Value::known(rand::random::())) - .collect(); - - let (result, _) = { - let r = ScalarFixed::new( - ecc_chip.clone(), - layouter.namespace(|| "r"), - Value::known(r_val), - )?; - let message = Message::from_bitstring( - chip2, - layouter.namespace(|| "witness message"), - message.clone(), - )?; - test_commit.commit(layouter.namespace(|| "commit"), message, r)? - }; - - // Witness expected result. - let expected_result = { - let message: Value> = message.into_iter().collect(); - let expected_result = message.map(|message| { - let domain = sinsemilla::CommitDomain::new(PERSONALIZATION); - let point = domain.commit(message.into_iter(), &r_val).unwrap(); - point.to_affine() - }); - - NonIdentityPoint::new( - ecc_chip, - layouter.namespace(|| "Witness expected result"), - expected_result, - )? - }; - - result.constrain_equal( - layouter.namespace(|| "result == expected result"), - &expected_result, - ) - } - } - } - - #[test] - fn sinsemilla_chip() { - let k = 11; - let circuit = MyCircuit {}; - let prover = MockProver::run(k, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())) - } - - #[cfg(feature = "test-dev-graph")] - #[test] - fn print_sinsemilla_chip() { - use plotters::prelude::*; - - let root = - BitMapBackend::new("sinsemilla-hash-layout.png", (1024, 7680)).into_drawing_area(); - root.fill(&WHITE).unwrap(); - let root = root.titled("SinsemillaHash", ("sans-serif", 60)).unwrap(); - - let circuit = MyCircuit {}; - halo2_proofs::dev::CircuitLayout::default() - .render(11, &circuit, &root) - .unwrap(); - } -} diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs deleted file mode 100644 index a6788e55e1..0000000000 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ /dev/null @@ -1,327 +0,0 @@ -//! Chip implementations for the Sinsemilla gadgets. - -use super::{ - message::{Message, MessagePiece}, - primitives as sinsemilla, CommitDomains, HashDomains, SinsemillaInstructions, -}; -use crate::{ - ecc::{ - chip::{DoubleAndAdd, NonIdentityEccPoint}, - FixedPoints, - }, - utilities::lookup_range_check::LookupRangeCheckConfig, -}; -use std::marker::PhantomData; - -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{ - Advice, Column, ConstraintSystem, Constraints, Error, Expression, Fixed, Selector, - TableColumn, VirtualCells, - }, - poly::Rotation, -}; -use halo2curves::pasta::pallas; - -mod generator_table; -use generator_table::GeneratorTableConfig; - -mod hash_to_point; - -/// Configuration for the Sinsemilla hash chip -#[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaConfig -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - /// Binary selector used in lookup argument and in the body of the Sinsemilla hash. - q_sinsemilla1: Selector, - /// Non-binary selector used in lookup argument and in the body of the Sinsemilla hash. - q_sinsemilla2: Column, - /// q_sinsemilla2 is used to define a synthetic selector, - /// q_sinsemilla3 = (q_sinsemilla2) ⋅ (q_sinsemilla2 - 1) - /// Simple selector used to constrain hash initialization to be consistent with - /// the y-coordinate of the domain $Q$. - q_sinsemilla4: Selector, - /// Fixed column used to load the y-coordinate of the domain $Q$. - fixed_y_q: Column, - /// Logic specific to merged double-and-add. - double_and_add: DoubleAndAdd, - /// Advice column used to load the message. - bits: Column, - /// Advice column used to witness message pieces. This may or may not be the same - /// column as `bits`. - witness_pieces: Column, - /// The lookup table where $(\mathsf{idx}, x_p, y_p)$ are loaded for the $2^K$ - /// generators of the Sinsemilla hash. - pub(super) generator_table: GeneratorTableConfig, - /// An advice column configured to perform lookup range checks. - lookup_config: LookupRangeCheckConfig, - _marker: PhantomData<(Hash, Commit, F)>, -} - -impl SinsemillaConfig -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - /// Returns an array of all advice columns in this config, in arbitrary order. - pub(super) fn advices(&self) -> [Column; 5] { - [ - self.double_and_add.x_a, - self.double_and_add.x_p, - self.bits, - self.double_and_add.lambda_1, - self.double_and_add.lambda_2, - ] - } - - /// Returns the lookup range check config used in this config. - pub fn lookup_config(&self) -> LookupRangeCheckConfig { - self.lookup_config - } - - /// Derives the expression `q_s3 = (q_s2) * (q_s2 - 1)`. - fn q_s3(&self, meta: &mut VirtualCells) -> Expression { - let one = Expression::Constant(pallas::Base::one()); - let q_s2 = meta.query_fixed(self.q_sinsemilla2, Rotation::cur()); - q_s2.clone() * (q_s2 - one) - } -} - -/// A chip that implements 10-bit Sinsemilla using a lookup table and 5 advice columns. -/// -/// [Chip description](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html#plonk--halo-2-constraints). -#[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaChip -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, -{ - config: SinsemillaConfig, -} - -impl Chip for SinsemillaChip -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, -{ - type Config = SinsemillaConfig; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -impl SinsemillaChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - /// Reconstructs this chip from the given config. - pub fn construct(config: >::Config) -> Self { - Self { config } - } - - /// Loads the lookup table required by this chip into the circuit. - pub fn load( - config: SinsemillaConfig, - layouter: &mut impl Layouter, - ) -> Result<>::Loaded, Error> { - // Load the lookup table. - config.generator_table.load(layouter) - } - - /// # Side-effects - /// - /// All columns in `advices` and will be equality-enabled. - #[allow(clippy::too_many_arguments)] - #[allow(non_snake_case)] - pub fn configure( - meta: &mut ConstraintSystem, - advices: [Column; 5], - witness_pieces: Column, - fixed_y_q: Column, - lookup: (TableColumn, TableColumn, TableColumn), - range_check: LookupRangeCheckConfig, - ) -> >::Config { - // Enable equality on all advice columns - for advice in advices.iter() { - meta.enable_equality(*advice); - } - - let config = SinsemillaConfig:: { - q_sinsemilla1: meta.complex_selector(), - q_sinsemilla2: meta.fixed_column(), - q_sinsemilla4: meta.selector(), - fixed_y_q, - double_and_add: DoubleAndAdd { - x_a: advices[0], - x_p: advices[1], - lambda_1: advices[3], - lambda_2: advices[4], - }, - bits: advices[2], - witness_pieces, - generator_table: GeneratorTableConfig { - table_idx: lookup.0, - table_x: lookup.1, - table_y: lookup.2, - }, - lookup_config: range_check, - _marker: PhantomData, - }; - - // Set up lookup argument - GeneratorTableConfig::configure(meta, config.clone()); - - let two = pallas::Base::from(2); - - // Closures for expressions that are derived multiple times - // x_r = lambda_1^2 - x_a - x_p - let x_r = |meta: &mut VirtualCells, rotation| { - config.double_and_add.x_r(meta, rotation) - }; - - // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) - let Y_A = |meta: &mut VirtualCells, rotation| { - config.double_and_add.Y_A(meta, rotation) - }; - - // Check that the initial x_A, x_P, lambda_1, lambda_2 are consistent with y_Q. - // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial - meta.create_gate("Initial y_Q", |meta| { - let q_s4 = meta.query_selector(config.q_sinsemilla4); - let y_q = meta.query_fixed(config.fixed_y_q, Rotation::cur()); - - // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) - let Y_A_cur = Y_A(meta, Rotation::cur()); - - // 2 * y_q - Y_{A,0} = 0 - let init_y_q_check = y_q * two - Y_A_cur; - - Constraints::with_selector(q_s4, Some(("init_y_q_check", init_y_q_check))) - }); - - // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial - meta.create_gate("Sinsemilla gate", |meta| { - let q_s1 = meta.query_selector(config.q_sinsemilla1); - let q_s3 = config.q_s3(meta); - - let lambda_1_next = meta.query_advice(config.double_and_add.lambda_1, Rotation::next()); - let lambda_2_cur = meta.query_advice(config.double_and_add.lambda_2, Rotation::cur()); - let x_a_cur = meta.query_advice(config.double_and_add.x_a, Rotation::cur()); - let x_a_next = meta.query_advice(config.double_and_add.x_a, Rotation::next()); - - // x_r = lambda_1^2 - x_a_cur - x_p - let x_r = x_r(meta, Rotation::cur()); - - // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) - let Y_A_cur = Y_A(meta, Rotation::cur()); - - // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) - let Y_A_next = Y_A(meta, Rotation::next()); - - // lambda2^2 - (x_a_next + x_r + x_a_cur) = 0 - let secant_line = - lambda_2_cur.clone().square() - (x_a_next.clone() + x_r + x_a_cur.clone()); - - // lhs - rhs = 0, where - // - lhs = 4 * lambda_2_cur * (x_a_cur - x_a_next) - // - rhs = (2 * Y_A_cur + (2 - q_s3) * Y_A_next + 2 * q_s3 * y_a_final) - let y_check = { - // lhs = 4 * lambda_2_cur * (x_a_cur - x_a_next) - let lhs = lambda_2_cur * pallas::Base::from(4) * (x_a_cur - x_a_next); - - // rhs = 2 * Y_A_cur + (2 - q_s3) * Y_A_next + 2 * q_s3 * y_a_final - let rhs = { - // y_a_final is assigned to the lambda1 column on the next offset. - let y_a_final = lambda_1_next; - - Y_A_cur * two - + (Expression::Constant(two) - q_s3.clone()) * Y_A_next - + q_s3 * two * y_a_final - }; - lhs - rhs - }; - - Constraints::with_selector(q_s1, [("Secant line", secant_line), ("y check", y_check)]) - }); - - config - } -} - -// Implement `SinsemillaInstructions` for `SinsemillaChip` -impl SinsemillaInstructions - for SinsemillaChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - type CellValue = AssignedCell; - - type Message = Message; - type MessagePiece = MessagePiece; - - type RunningSum = Vec; - - type X = AssignedCell; - type NonIdentityPoint = NonIdentityEccPoint; - type FixedPoints = F; - - type HashDomains = Hash; - type CommitDomains = Commit; - - fn witness_message_piece( - &self, - mut layouter: impl Layouter, - field_elem: Value, - num_words: usize, - ) -> Result { - let config = self.config().clone(); - - let cell = layouter.assign_region( - || "witness message piece", - |mut region| { - region.assign_advice( - || "witness message piece", - config.witness_pieces, - 0, - || field_elem, - ) - }, - )?; - Ok(MessagePiece::new(cell, num_words)) - } - - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - fn hash_to_point( - &self, - mut layouter: impl Layouter, - Q: pallas::Affine, - message: Self::Message, - ) -> Result<(Self::NonIdentityPoint, Vec), Error> { - layouter.assign_region( - || "hash_to_point", - |mut region| self.hash_message(&mut region, Q, &message), - ) - } - - fn extract(point: &Self::NonIdentityPoint) -> Self::X { - point.x() - } -} diff --git a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs deleted file mode 100644 index a50a687e88..0000000000 --- a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs +++ /dev/null @@ -1,98 +0,0 @@ -use halo2_proofs::{ - circuit::{Layouter, Value}, - plonk::{ConstraintSystem, Error, Expression, TableColumn}, - poly::Rotation, -}; - -use super::{CommitDomains, FixedPoints, HashDomains}; -use crate::sinsemilla::primitives::{self as sinsemilla, SINSEMILLA_S}; -use ff::PrimeField; -use halo2curves::pasta::pallas; - -/// Table containing independent generators S[0..2^k] -#[derive(Eq, PartialEq, Copy, Clone, Debug)] -pub struct GeneratorTableConfig { - pub table_idx: TableColumn, - pub table_x: TableColumn, - pub table_y: TableColumn, -} - -impl GeneratorTableConfig { - #[allow(clippy::too_many_arguments)] - #[allow(non_snake_case)] - /// Even though the lookup table can be used in other parts of the circuit, - /// this specific configuration sets up Sinsemilla-specific constraints - /// controlled by `q_sinsemilla`, and would likely not apply to other chips. - pub fn configure( - meta: &mut ConstraintSystem, - config: super::SinsemillaConfig, - ) where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, - { - let (table_idx, table_x, table_y) = ( - config.generator_table.table_idx, - config.generator_table.table_x, - config.generator_table.table_y, - ); - - // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial - meta.lookup("lookup", |meta| { - let q_s1 = meta.query_selector(config.q_sinsemilla1); - let q_s2 = meta.query_fixed(config.q_sinsemilla2, Rotation::cur()); - let q_s3 = config.q_s3(meta); - let q_run = q_s2 - q_s3; - - // m_{i+1} = z_{i} - 2^K * q_{run,i} * z_{i + 1} - // Note that the message words m_i's are 1-indexed while the - // running sum z_i's are 0-indexed. - let word = { - let z_cur = meta.query_advice(config.bits, Rotation::cur()); - let z_next = meta.query_advice(config.bits, Rotation::next()); - z_cur - (q_run * z_next * pallas::Base::from(1 << sinsemilla::K)) - }; - - let x_p = meta.query_advice(config.double_and_add.x_p, Rotation::cur()); - - // y_{p,i} = (Y_{A,i} / 2) - lambda1 * (x_{A,i} - x_{P,i}) - let y_p = { - let lambda1 = meta.query_advice(config.double_and_add.lambda_1, Rotation::cur()); - let x_a = meta.query_advice(config.double_and_add.x_a, Rotation::cur()); - let Y_A = config.double_and_add.Y_A(meta, Rotation::cur()); - - (Y_A * pallas::Base::TWO_INV) - (lambda1 * (x_a - x_p.clone())) - }; - - // Lookup expressions default to the first entry when `q_s1` - // is not enabled. - let (init_x, init_y) = SINSEMILLA_S[0]; - let not_q_s1 = Expression::Constant(pallas::Base::one()) - q_s1.clone(); - - let m = q_s1.clone() * word; // The first table index is 0. - let x_p = q_s1.clone() * x_p + not_q_s1.clone() * init_x; - let y_p = q_s1 * y_p + not_q_s1 * init_y; - - vec![(m, table_idx), (x_p, table_x), (y_p, table_y)] - }); - } - - pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_table( - || "generator_table", - |mut table| { - for (index, (x, y)) in SINSEMILLA_S.iter().enumerate() { - table.assign_cell( - || "table_idx", - self.table_idx, - index, - || Value::known(pallas::Base::from(index as u64)), - )?; - table.assign_cell(|| "table_x", self.table_x, index, || Value::known(*x))?; - table.assign_cell(|| "table_y", self.table_y, index, || Value::known(*y))?; - } - Ok(()) - }, - ) - } -} diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs deleted file mode 100644 index 9c15dd111a..0000000000 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ /dev/null @@ -1,414 +0,0 @@ -use super::super::{CommitDomains, HashDomains, SinsemillaInstructions}; -use super::{NonIdentityEccPoint, SinsemillaChip}; -use crate::{ - ecc::FixedPoints, - sinsemilla::primitives::{self as sinsemilla, lebs2ip_k, INV_TWO_POW_K, SINSEMILLA_S}, -}; - -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Region, Value}, - plonk::{Assigned, Error}, -}; - -use group::ff::{Field, PrimeField, PrimeFieldBits}; -use halo2curves::{pasta::pallas, CurveAffine}; - -use std::ops::Deref; - -impl SinsemillaChip -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, -{ - /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - pub(super) fn hash_message( - &self, - region: &mut Region<'_, pallas::Base>, - Q: pallas::Affine, - message: &>::Message, - ) -> Result< - ( - NonIdentityEccPoint, - Vec>>, - ), - Error, - > { - let config = self.config().clone(); - let mut offset = 0; - - // Get the `x`- and `y`-coordinates of the starting `Q` base. - let x_q = *Q.coordinates().unwrap().x(); - let y_q = *Q.coordinates().unwrap().y(); - - // Constrain the initial x_a, lambda_1, lambda_2, x_p using the q_sinsemilla4 - // selector. - let mut y_a: Y = { - // Enable `q_sinsemilla4` on the first row. - config.q_sinsemilla4.enable(region, offset)?; - region.assign_fixed( - || "fixed y_q", - config.fixed_y_q, - offset, - || Value::known(y_q), - )?; - - Value::known(y_q.into()).into() - }; - - // Constrain the initial x_q to equal the x-coordinate of the domain's `Q`. - let mut x_a: X = { - let x_a = region.assign_advice_from_constant( - || "fixed x_q", - config.double_and_add.x_a, - offset, - x_q.into(), - )?; - - x_a.into() - }; - - let mut zs_sum: Vec>> = Vec::new(); - - // Hash each piece in the message. - for (idx, piece) in message.iter().enumerate() { - let final_piece = idx == message.len() - 1; - - // The value of the accumulator after this piece is processed. - let (x, y, zs) = self.hash_piece(region, offset, piece, x_a, y_a, final_piece)?; - - // Since each message word takes one row to process, we increase - // the offset by `piece.num_words` on each iteration. - offset += piece.num_words(); - - // Update the accumulator to the latest value. - x_a = x; - y_a = y; - zs_sum.push(zs); - } - - // Assign the final y_a. - let y_a = { - // Assign the final y_a. - let y_a_cell = - region.assign_advice(|| "y_a", config.double_and_add.lambda_1, offset, || y_a.0)?; - - // Assign lambda_2 and x_p zero values since they are queried - // in the gate. (The actual values do not matter since they are - // multiplied by zero.) - { - region.assign_advice( - || "dummy lambda2", - config.double_and_add.lambda_2, - offset, - || Value::known(pallas::Base::zero()), - )?; - region.assign_advice( - || "dummy x_p", - config.double_and_add.x_p, - offset, - || Value::known(pallas::Base::zero()), - )?; - } - - y_a_cell - }; - - #[cfg(test)] - #[allow(non_snake_case)] - // Check equivalence to result from primitives::sinsemilla::hash_to_point - { - use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; - - use group::{prime::PrimeCurveAffine, Curve}; - use halo2curves::CurveExt; - - let field_elems: Value> = message - .iter() - .map(|piece| piece.field_elem().map(|elem| (elem, piece.num_words()))) - .collect(); - - field_elems - .zip(x_a.value().zip(y_a.value())) - .assert_if_known(|(field_elems, (x_a, y_a))| { - // Get message as a bitstring. - let bitstring: Vec = field_elems - .iter() - .flat_map(|(elem, num_words)| { - elem.to_le_bits().into_iter().take(K * num_words) - }) - .collect(); - - let hasher_S = pallas::Point::hash_to_curve(S_PERSONALIZATION); - let S = |chunk: &[bool]| hasher_S(&lebs2ip_k(chunk).to_le_bytes()); - - // We can use complete addition here because it differs from - // incomplete addition with negligible probability. - let expected_point = bitstring - .chunks(K) - .fold(Q.to_curve(), |acc, chunk| (acc + S(chunk)) + acc); - let actual_point = - pallas::Affine::from_xy(x_a.evaluate(), y_a.evaluate()).unwrap(); - expected_point.to_affine() == actual_point - }); - } - - x_a.value() - .zip(y_a.value()) - .error_if_known_and(|(x_a, y_a)| x_a.is_zero_vartime() || y_a.is_zero_vartime())?; - Ok(( - NonIdentityEccPoint::from_coordinates_unchecked(x_a.0, y_a), - zs_sum, - )) - } - - #[allow(clippy::type_complexity)] - /// Hashes a message piece containing `piece.length` number of `K`-bit words. - /// - /// To avoid a duplicate assignment, the accumulator x-coordinate provided - /// by the caller is not copied. This only works because `hash_piece()` is - /// an internal API. Before this call to `hash_piece()`, x_a MUST have been - /// already assigned within this region at the correct offset. - fn hash_piece( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - piece: &>::MessagePiece, - mut x_a: X, - mut y_a: Y, - final_piece: bool, - ) -> Result< - ( - X, - Y, - Vec>, - ), - Error, - > { - let config = self.config().clone(); - - // Selector assignments - { - // Enable `q_sinsemilla1` selector on every row. - for row in 0..piece.num_words() { - config.q_sinsemilla1.enable(region, offset + row)?; - } - - // Set `q_sinsemilla2` fixed column to 1 on every row but the last. - for row in 0..(piece.num_words() - 1) { - region.assign_fixed( - || "q_s2 = 1", - config.q_sinsemilla2, - offset + row, - || Value::known(pallas::Base::one()), - )?; - } - - // Set `q_sinsemilla2` fixed column to 0 on the last row if this is - // not the final piece, or to 2 on the last row of the final piece. - region.assign_fixed( - || { - if final_piece { - "q_s2 for final piece" - } else { - "q_s2 between pieces" - } - }, - config.q_sinsemilla2, - offset + piece.num_words() - 1, - || { - Value::known(if final_piece { - pallas::Base::from(2) - } else { - pallas::Base::zero() - }) - }, - )?; - } - - // Message piece as K * piece.length bitstring - let bitstring: Value> = piece.field_elem().map(|value| { - value - .to_le_bits() - .into_iter() - .take(sinsemilla::K * piece.num_words()) - .collect() - }); - - let words: Value> = bitstring.map(|bitstring| { - bitstring - .chunks_exact(sinsemilla::K) - .map(lebs2ip_k) - .collect() - }); - - // Get (x_p, y_p) for each word. - let generators: Value> = words.clone().map(|words| { - words - .iter() - .map(|word| SINSEMILLA_S[*word as usize]) - .collect() - }); - - // Convert `words` from `Value>` to `Vec>` - let words = words.transpose_vec(piece.num_words()); - - // Decompose message piece into `K`-bit pieces with a running sum `z`. - let zs = { - let mut zs = Vec::with_capacity(piece.num_words() + 1); - - // Copy message and initialize running sum `z` to decompose message in-circuit - let initial_z = piece.cell_value().copy_advice( - || "z_0 (copy of message piece)", - region, - config.bits, - offset, - )?; - zs.push(initial_z); - - // Assign cumulative sum such that for 0 <= i < n, - // z_i = 2^K * z_{i + 1} + m_{i + 1} - // => z_{i + 1} = (z_i - m_{i + 1}) / 2^K - // - // For a message piece m = m_1 + 2^K m_2 + ... + 2^{K(n-1)} m_n}, initialize z_0 = m. - // We end up with z_n = 0. (z_n is not directly encoded as a cell value; - // it is implicitly taken as 0 by adjusting the definition of m_{i+1}.) - let mut z = piece.field_elem(); - let inv_2_k = Value::known(pallas::Base::from_repr(INV_TWO_POW_K).unwrap()); - - // We do not assign the final z_n as it is constrained to be zero. - for (idx, word) in words[0..(words.len() - 1)].iter().enumerate() { - let word = word.map(|word| pallas::Base::from(word as u64)); - // z_{i + 1} = (z_i - m_{i + 1}) / 2^K - z = (z - word) * inv_2_k; - let cell = region.assign_advice( - || format!("z_{:?}", idx + 1), - config.bits, - offset + idx + 1, - || z, - )?; - zs.push(cell) - } - - zs - }; - - // The accumulator x-coordinate provided by the caller MUST have been assigned - // within this region. - - let generators = generators.transpose_vec(piece.num_words()); - - for (row, gen) in generators.iter().enumerate() { - let x_p = gen.map(|gen| gen.0); - let y_p = gen.map(|gen| gen.1); - - // Assign `x_p` - region.assign_advice(|| "x_p", config.double_and_add.x_p, offset + row, || x_p)?; - - // Compute and assign `lambda_1` - let lambda_1 = { - let lambda_1 = (y_a.0 - y_p) * (x_a.value() - x_p).invert(); - - // Assign lambda_1 - region.assign_advice( - || "lambda_1", - config.double_and_add.lambda_1, - offset + row, - || lambda_1, - )?; - - lambda_1 - }; - - // Compute `x_r` - let x_r = lambda_1.square() - x_a.value() - x_p; - - // Compute and assign `lambda_2` - let lambda_2 = { - let lambda_2 = - y_a.0 * pallas::Base::from(2) * (x_a.value() - x_r).invert() - lambda_1; - - region.assign_advice( - || "lambda_2", - config.double_and_add.lambda_2, - offset + row, - || lambda_2, - )?; - - lambda_2 - }; - - // Compute and assign `x_a` for the next row. - let x_a_new: X = { - let x_a_new = lambda_2.square() - x_a.value() - x_r; - - let x_a_cell = region.assign_advice( - || "x_a", - config.double_and_add.x_a, - offset + row + 1, - || x_a_new, - )?; - - x_a_cell.into() - }; - - // Compute y_a for the next row. - let y_a_new: Y = - (lambda_2 * (x_a.value() - x_a_new.value()) - y_a.0).into(); - - // Update the mutable `x_a`, `y_a` variables. - x_a = x_a_new; - y_a = y_a_new; - } - - Ok((x_a, y_a, zs)) - } -} - -/// The x-coordinate of the accumulator in a Sinsemilla hash instance. -struct X(AssignedCell, F>); - -impl From, F>> for X { - fn from(cell_value: AssignedCell, F>) -> Self { - X(cell_value) - } -} - -impl Deref for X { - type Target = AssignedCell, F>; - - fn deref(&self) -> &AssignedCell, F> { - &self.0 - } -} - -/// The y-coordinate of the accumulator in a Sinsemilla hash instance. -/// -/// This is never actually witnessed until the last round, since it -/// can be derived from other variables. Thus it only exists as a field -/// element, not a `CellValue`. -struct Y(Value>); - -impl From>> for Y { - fn from(value: Value>) -> Self { - Y(value) - } -} - -impl Deref for Y { - type Target = Value>; - - fn deref(&self) -> &Value> { - &self.0 - } -} diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs deleted file mode 100644 index 47e5c953e3..0000000000 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ /dev/null @@ -1,400 +0,0 @@ -//! Gadgets for implementing a Merkle tree with Sinsemilla. - -use halo2_proofs::{ - circuit::{Chip, Layouter, Value}, - plonk::Error, -}; -use halo2curves::CurveAffine; - -use super::{HashDomains, SinsemillaInstructions}; - -use crate::utilities::{cond_swap::CondSwapInstructions, i2lebsp, UtilitiesInstructions}; - -pub mod chip; - -/// SWU hash-to-curve personalization for the Merkle CRH generator -pub const MERKLE_CRH_PERSONALIZATION: &str = "z.cash:Orchard-MerkleCRH"; - -/// Instructions to check the validity of a Merkle path of a given `PATH_LENGTH`. -/// The hash function used is a Sinsemilla instance with `K`-bit words. -/// The hash function can process `MAX_WORDS` words. -pub trait MerkleInstructions< - C: CurveAffine, - const PATH_LENGTH: usize, - const K: usize, - const MAX_WORDS: usize, ->: - SinsemillaInstructions - + CondSwapInstructions - + UtilitiesInstructions - + Chip -{ - /// Compute MerkleCRH for a given `layer`. The hash that computes the root - /// is at layer 0, and the hashes that are applied to two leaves are at - /// layer `MERKLE_DEPTH - 1` = layer 31. - #[allow(non_snake_case)] - fn hash_layer( - &self, - layouter: impl Layouter, - Q: C, - l: usize, - left: Self::Var, - right: Self::Var, - ) -> Result; -} - -/// Gadget representing a Merkle path that proves a leaf exists in a Merkle tree at a -/// specific position. -#[derive(Clone, Debug)] -pub struct MerklePath< - C: CurveAffine, - MerkleChip, - const PATH_LENGTH: usize, - const K: usize, - const MAX_WORDS: usize, - const PAR: usize, -> where - MerkleChip: MerkleInstructions + Clone, -{ - chips: [MerkleChip; PAR], - domain: MerkleChip::HashDomains, - leaf_pos: Value, - // The Merkle path is ordered from leaves to root. - path: Value<[C::Base; PATH_LENGTH]>, -} - -impl< - C: CurveAffine, - MerkleChip, - const PATH_LENGTH: usize, - const K: usize, - const MAX_WORDS: usize, - const PAR: usize, - > MerklePath -where - MerkleChip: MerkleInstructions + Clone, -{ - /// Constructs a [`MerklePath`]. - /// - /// A circuit may have many more columns available than are required by a single - /// `MerkleChip`. To make better use of the available circuit area, the `MerklePath` - /// gadget will distribute its path hashing across each `MerkleChip` in `chips`, such - /// that each chip processes `ceil(PATH_LENGTH / PAR)` layers (with the last chip - /// processing fewer layers if the division is inexact). - pub fn construct( - chips: [MerkleChip; PAR], - domain: MerkleChip::HashDomains, - leaf_pos: Value, - path: Value<[C::Base; PATH_LENGTH]>, - ) -> Self { - assert_ne!(PAR, 0); - Self { - chips, - domain, - leaf_pos, - path, - } - } -} - -#[allow(non_snake_case)] -impl< - C: CurveAffine, - MerkleChip, - const PATH_LENGTH: usize, - const K: usize, - const MAX_WORDS: usize, - const PAR: usize, - > MerklePath -where - MerkleChip: MerkleInstructions + Clone, -{ - /// Calculates the root of the tree containing the given leaf at this Merkle path. - /// - /// Implements [Zcash Protocol Specification Section 4.9: Merkle Path Validity][merklepath]. - /// - /// [merklepath]: https://zips.z.cash/protocol/protocol.pdf#merklepath - pub fn calculate_root( - &self, - mut layouter: impl Layouter, - leaf: MerkleChip::Var, - ) -> Result { - // Each chip processes `ceil(PATH_LENGTH / PAR)` layers. - let layers_per_chip = (PATH_LENGTH + PAR - 1) / PAR; - - // Assign each layer to a chip. - let chips = (0..PATH_LENGTH).map(|i| self.chips[i / layers_per_chip].clone()); - - // The Merkle path is ordered from leaves to root, which is consistent with the - // little-endian representation of `pos` below. - let path = self.path.transpose_array(); - - // Get position as a PATH_LENGTH-bit bitstring (little-endian bit order). - let pos: [Value; PATH_LENGTH] = { - let pos: Value<[bool; PATH_LENGTH]> = self.leaf_pos.map(|pos| i2lebsp(pos as u64)); - pos.transpose_array() - }; - - let Q = self.domain.Q(); - - let mut node = leaf; - for (l, ((sibling, pos), chip)) in path.iter().zip(pos.iter()).zip(chips).enumerate() { - // `l` = MERKLE_DEPTH - layer - 1, which is the index obtained from - // enumerating this Merkle path (going from leaf to root). - // For example, when `layer = 31` (the first sibling on the Merkle path), - // we have `l` = 32 - 31 - 1 = 0. - // On the other hand, when `layer = 0` (the final sibling on the Merkle path), - // we have `l` = 32 - 0 - 1 = 31. - - // Constrain which of (node, sibling) is (left, right) with a conditional swap - // tied to the current bit of the position. - let pair = { - let pair = (node, *sibling); - - // Swap node and sibling if needed - chip.swap(layouter.namespace(|| "node position"), pair, *pos)? - }; - - // Compute the node in layer l from its children: - // M^l_i = MerkleCRH(l, M^{l+1}_{2i}, M^{l+1}_{2i+1}) - node = chip.hash_layer( - layouter.namespace(|| format!("MerkleCRH({}, left, right)", l)), - Q, - l, - pair.0, - pair.1, - )?; - } - - Ok(node) - } -} - -#[cfg(test)] -pub mod tests { - use super::{ - chip::{MerkleChip, MerkleConfig}, - MerklePath, - }; - - use crate::{ - ecc::tests::TestFixedBases, - sinsemilla::{ - chip::SinsemillaChip, - tests::{TestCommitDomain, TestHashDomain}, - HashDomains, - }, - utilities::{i2lebsp, lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, - }; - - use group::ff::{Field, PrimeField, PrimeFieldBits}; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use halo2curves::pasta::pallas; - - use rand::{rngs::OsRng, RngCore}; - use std::{convert::TryInto, iter}; - - const MERKLE_DEPTH: usize = 32; - - #[derive(Default)] - struct MyCircuit { - leaf: Value, - leaf_pos: Value, - merkle_path: Value<[pallas::Base; MERKLE_DEPTH]>, - } - - impl Circuit for MyCircuit { - type Config = ( - MerkleConfig, - MerkleConfig, - ); - type FloorPlanner = SimpleFloorPlanner; - #[cfg(feature = "circuit-params")] - type Params = (); - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let advices = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - - // Shared fixed column for loading constants - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - // NB: In the actual Action circuit, these fixed columns will be reused - // by other chips. For this test, we are creating new fixed columns. - let fixed_y_q_1 = meta.fixed_column(); - let fixed_y_q_2 = meta.fixed_column(); - - // Fixed columns for the Sinsemilla generator lookup table - let lookup = ( - meta.lookup_table_column(), - meta.lookup_table_column(), - meta.lookup_table_column(), - ); - - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup.0); - - let sinsemilla_config_1 = SinsemillaChip::configure( - meta, - advices[5..].try_into().unwrap(), - advices[7], - fixed_y_q_1, - lookup, - range_check, - ); - let config1 = MerkleChip::configure(meta, sinsemilla_config_1); - - let sinsemilla_config_2 = SinsemillaChip::configure( - meta, - advices[..5].try_into().unwrap(), - advices[2], - fixed_y_q_2, - lookup, - range_check, - ); - let config2 = MerkleChip::configure(meta, sinsemilla_config_2); - - (config1, config2) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Load generator table (shared across both configs) - SinsemillaChip::::load( - config.0.sinsemilla_config.clone(), - &mut layouter, - )?; - - // Construct Merkle chips which will be placed side-by-side in the circuit. - let chip_1 = MerkleChip::construct(config.0.clone()); - let chip_2 = MerkleChip::construct(config.1.clone()); - - let leaf = chip_1.load_private( - layouter.namespace(|| ""), - config.0.cond_swap_config.a(), - self.leaf, - )?; - - let path = MerklePath { - chips: [chip_1, chip_2], - domain: TestHashDomain, - leaf_pos: self.leaf_pos, - path: self.merkle_path, - }; - - let computed_final_root = - path.calculate_root(layouter.namespace(|| "calculate root"), leaf)?; - - self.leaf - .zip(self.leaf_pos) - .zip(self.merkle_path) - .zip(computed_final_root.value()) - .assert_if_known(|(((leaf, leaf_pos), merkle_path), computed_final_root)| { - // The expected final root - let final_root = - merkle_path - .iter() - .enumerate() - .fold(*leaf, |node, (l, sibling)| { - let l = l as u8; - let (left, right) = if leaf_pos & (1 << l) == 0 { - (&node, sibling) - } else { - (sibling, &node) - }; - - use crate::sinsemilla::primitives as sinsemilla; - let merkle_crh = - sinsemilla::HashDomain::from_Q(TestHashDomain.Q().into()); - - merkle_crh - .hash( - iter::empty() - .chain(i2lebsp::<10>(l as u64).iter().copied()) - .chain( - left.to_le_bits() - .iter() - .by_vals() - .take(pallas::Base::NUM_BITS as usize), - ) - .chain( - right - .to_le_bits() - .iter() - .by_vals() - .take(pallas::Base::NUM_BITS as usize), - ), - ) - .unwrap_or(pallas::Base::zero()) - }); - - // Check the computed final root against the expected final root. - computed_final_root == &&final_root - }); - - Ok(()) - } - } - - #[test] - fn merkle_chip() { - let mut rng = OsRng; - - // Choose a random leaf and position - let leaf = pallas::Base::random(rng); - let pos = rng.next_u32(); - - // Choose a path of random inner nodes - let path: Vec<_> = (0..(MERKLE_DEPTH)) - .map(|_| pallas::Base::random(rng)) - .collect(); - - // The root is provided as a public input in the Orchard circuit. - - let circuit = MyCircuit { - leaf: Value::known(leaf), - leaf_pos: Value::known(pos), - merkle_path: Value::known(path.try_into().unwrap()), - }; - - let prover = MockProver::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())) - } - - #[cfg(feature = "test-dev-graph")] - #[test] - fn print_merkle_chip() { - use plotters::prelude::*; - - let root = BitMapBackend::new("merkle-path-layout.png", (1024, 7680)).into_drawing_area(); - root.fill(&WHITE).unwrap(); - let root = root.titled("MerkleCRH Path", ("sans-serif", 60)).unwrap(); - - let circuit = MyCircuit::default(); - halo2_proofs::dev::CircuitLayout::default() - .show_labels(false) - .render(11, &circuit, &root) - .unwrap(); - } -} diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs deleted file mode 100644 index bb042a5aee..0000000000 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ /dev/null @@ -1,529 +0,0 @@ -//! Chip implementing a Merkle hash using Sinsemilla as the hash function. - -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Selector}, - poly::Rotation, -}; -use halo2curves::pasta::pallas; - -use super::MerkleInstructions; - -use crate::{ - sinsemilla::{primitives as sinsemilla, MessagePiece}, - utilities::RangeConstrained, - { - ecc::FixedPoints, - sinsemilla::{ - chip::{SinsemillaChip, SinsemillaConfig}, - CommitDomains, HashDomains, SinsemillaInstructions, - }, - utilities::{ - cond_swap::{CondSwapChip, CondSwapConfig, CondSwapInstructions}, - UtilitiesInstructions, - }, - }, -}; -use group::ff::PrimeField; - -/// Configuration for the `MerkleChip` implementation. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleConfig -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, -{ - advices: [Column; 5], - q_decompose: Selector, - pub(super) cond_swap_config: CondSwapConfig, - pub(super) sinsemilla_config: SinsemillaConfig, -} - -/// Chip implementing `MerkleInstructions`. -/// -/// This chip specifically implements `MerkleInstructions::hash_layer` as the `MerkleCRH` -/// function `hash = SinsemillaHash(Q, 𝑙⋆ || left⋆ || right⋆)`, where: -/// - `𝑙⋆ = I2LEBSP_10(l)` -/// - `left⋆ = I2LEBSP_255(left)` -/// - `right⋆ = I2LEBSP_255(right)` -/// -/// This chip does **NOT** constrain `left⋆` and `right⋆` to be canonical encodings of -/// `left` and `right`. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleChip -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, -{ - config: MerkleConfig, -} - -impl Chip for MerkleChip -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, -{ - type Config = MerkleConfig; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -impl MerkleChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - /// Configures the [`MerkleChip`]. - pub fn configure( - meta: &mut ConstraintSystem, - sinsemilla_config: SinsemillaConfig, - ) -> MerkleConfig { - // All five advice columns are equality-enabled by SinsemillaConfig. - let advices = sinsemilla_config.advices(); - let cond_swap_config = CondSwapChip::configure(meta, advices); - - // This selector enables the decomposition gate. - let q_decompose = meta.selector(); - - // Check that pieces have been decomposed correctly for Sinsemilla hash. - // - // - // a = a_0||a_1 = l || (bits 0..=239 of left) - // b = b_0||b_1||b_2 - // = (bits 240..=249 of left) || (bits 250..=254 of left) || (bits 0..=4 of right) - // c = bits 5..=254 of right - // - // The message pieces `a`, `b`, `c` are constrained by Sinsemilla to be - // 250 bits, 20 bits, and 250 bits respectively. - // - // The pieces and subpieces are arranged in the following configuration: - // | A_0 | A_1 | A_2 | A_3 | A_4 | q_decompose | - // ------------------------------------------------------- - // | a | b | c | left | right | 1 | - // | z1_a | z1_b | b_1 | b_2 | l | 0 | - meta.create_gate("Decomposition check", |meta| { - let q_decompose = meta.query_selector(q_decompose); - let l_whole = meta.query_advice(advices[4], Rotation::next()); - - let two_pow_5 = pallas::Base::from(1 << 5); - let two_pow_10 = two_pow_5.square(); - - // a_whole is constrained by Sinsemilla to be 250 bits. - let a_whole = meta.query_advice(advices[0], Rotation::cur()); - // b_whole is constrained by Sinsemilla to be 20 bits. - let b_whole = meta.query_advice(advices[1], Rotation::cur()); - // c_whole is constrained by Sinsemilla to be 250 bits. - let c_whole = meta.query_advice(advices[2], Rotation::cur()); - let left_node = meta.query_advice(advices[3], Rotation::cur()); - let right_node = meta.query_advice(advices[4], Rotation::cur()); - - // a = a_0||a_1 = l || (bits 0..=239 of left) - // - // z_1 of SinsemillaHash(a) = a_1 - // => a_0 = a - (a_1 * 2^10) - let z1_a = meta.query_advice(advices[0], Rotation::next()); - let a_1 = z1_a; - // Derive a_0 (constrained by SinsemillaHash to be 10 bits) - let a_0 = a_whole - a_1.clone() * two_pow_10; - - // b = b_0||b_1||b_2 - // = (bits 240..=249 of left) || (bits 250..=254 of left) || (bits 0..=4 of right) - // The Orchard specification allows this representation to be non-canonical. - // - // - // z_1 of SinsemillaHash(b) = b_1 + 2^5 b_2 - // => b_0 = b - (z1_b * 2^10) - let z1_b = meta.query_advice(advices[1], Rotation::next()); - // b_1 has been constrained to be 5 bits outside this gate. - let b_1 = meta.query_advice(advices[2], Rotation::next()); - // b_2 has been constrained to be 5 bits outside this gate. - let b_2 = meta.query_advice(advices[3], Rotation::next()); - // Constrain b_1 + 2^5 b_2 = z1_b - // https://p.z.cash/halo2-0.1:sinsemilla-merkle-crh-bit-lengths?partial - let b1_b2_check = z1_b.clone() - (b_1.clone() + b_2.clone() * two_pow_5); - // Derive b_0 (constrained by SinsemillaHash to be 10 bits) - let b_0 = b_whole - (z1_b * two_pow_10); - - // Check that left = a_1 (240 bits) || b_0 (10 bits) || b_1 (5 bits) - // https://p.z.cash/halo2-0.1:sinsemilla-merkle-crh-decomposition?partial - let left_check = { - let reconstructed = { - let two_pow_240 = pallas::Base::from_u128(1 << 120).square(); - a_1 + (b_0 + b_1 * two_pow_10) * two_pow_240 - }; - reconstructed - left_node - }; - - // Check that right = b_2 (5 bits) || c (250 bits) - // The Orchard specification allows this representation to be non-canonical. - // - // https://p.z.cash/halo2-0.1:sinsemilla-merkle-crh-decomposition?partial - let right_check = b_2 + c_whole * two_pow_5 - right_node; - - Constraints::with_selector( - q_decompose, - [ - ("l_check", a_0 - l_whole), - ("left_check", left_check), - ("right_check", right_check), - ("b1_b2_check", b1_b2_check), - ], - ) - }); - - MerkleConfig { - advices, - q_decompose, - cond_swap_config, - sinsemilla_config, - } - } - - /// Constructs a [`MerkleChip`] given a [`MerkleConfig`]. - pub fn construct(config: MerkleConfig) -> Self { - MerkleChip { config } - } -} - -impl - MerkleInstructions - for MerkleChip -where - Hash: HashDomains + Eq, - F: FixedPoints, - Commit: CommitDomains + Eq, -{ - #[allow(non_snake_case)] - fn hash_layer( - &self, - mut layouter: impl Layouter, - Q: pallas::Affine, - // l = MERKLE_DEPTH - layer - 1 - l: usize, - left: Self::Var, - right: Self::Var, - ) -> Result { - let config = self.config().clone(); - - // We need to hash `l || left || right`, where `l` is a 10-bit value. - // We allow `left` and `right` to be non-canonical 255-bit encodings. - // - // a = a_0||a_1 = l || (bits 0..=239 of left) - // b = b_0||b_1||b_2 - // = (bits 240..=249 of left) || (bits 250..=254 of left) || (bits 0..=4 of right) - // c = bits 5..=254 of right - // - // We start by witnessing all of the individual pieces, and range-constraining the - // short pieces b_1 and b_2. - // - // https://p.z.cash/halo2-0.1:sinsemilla-merkle-crh-bit-lengths?partial - - // `a = a_0||a_1` = `l` || (bits 0..=239 of `left`) - let a = MessagePiece::from_subpieces( - self.clone(), - layouter.namespace(|| "Witness a = a_0 || a_1"), - [ - RangeConstrained::bitrange_of(Value::known(&pallas::Base::from(l as u64)), 0..10), - RangeConstrained::bitrange_of(left.value(), 0..240), - ], - )?; - - // b = b_0 || b_1 || b_2 - // = (bits 240..=249 of left) || (bits 250..=254 of left) || (bits 0..=4 of right) - let (b_1, b_2, b) = { - // b_0 = (bits 240..=249 of `left`) - let b_0 = RangeConstrained::bitrange_of(left.value(), 240..250); - - // b_1 = (bits 250..=254 of `left`) - // Constrain b_1 to 5 bits. - let b_1 = RangeConstrained::witness_short( - &config.sinsemilla_config.lookup_config(), - layouter.namespace(|| "b_1"), - left.value(), - 250..(pallas::Base::NUM_BITS as usize), - )?; - - // b_2 = (bits 0..=4 of `right`) - // Constrain b_2 to 5 bits. - let b_2 = RangeConstrained::witness_short( - &config.sinsemilla_config.lookup_config(), - layouter.namespace(|| "b_2"), - right.value(), - 0..5, - )?; - - let b = MessagePiece::from_subpieces( - self.clone(), - layouter.namespace(|| "Witness b = b_0 || b_1 || b_2"), - [b_0, b_1.value(), b_2.value()], - )?; - - (b_1, b_2, b) - }; - - // c = bits 5..=254 of `right` - let c = MessagePiece::from_subpieces( - self.clone(), - layouter.namespace(|| "Witness c"), - [RangeConstrained::bitrange_of( - right.value(), - 5..(pallas::Base::NUM_BITS as usize), - )], - )?; - - // hash = SinsemillaHash(Q, 𝑙⋆ || left⋆ || right⋆) - // - // `hash = ⊥` is handled internally to `SinsemillaChip::hash_to_point`: incomplete - // addition constraints allows ⊥ to occur, and then during synthesis it detects - // these edge cases and raises an error (aborting proof creation). - // - // Note that MerkleCRH as-defined maps ⊥ to 0. This is for completeness outside - // the circuit (so that the ⊥ does not propagate into the type system). The chip - // explicitly doesn't map ⊥ to 0; in fact it cannot, as doing so would require - // constraints that amount to using complete addition. The rationale for excluding - // this map is the same as why Sinsemilla uses incomplete addition: this situation - // yields a nontrivial discrete log relation, and by assumption it is hard to find - // these. - // - // https://p.z.cash/proto:merkle-crh-orchard - let (point, zs) = self.hash_to_point( - layouter.namespace(|| format!("hash at l = {}", l)), - Q, - vec![a.inner(), b.inner(), c.inner()].into(), - )?; - let hash = Self::extract(&point); - - // `SinsemillaChip::hash_to_point` returns the running sum for each `MessagePiece`. - // Grab the outputs we need for the decomposition constraints. - let z1_a = zs[0][1].clone(); - let z1_b = zs[1][1].clone(); - - // Check that the pieces have been decomposed properly. - // - // The pieces and subpieces are arranged in the following configuration: - // | A_0 | A_1 | A_2 | A_3 | A_4 | q_decompose | - // ------------------------------------------------------- - // | a | b | c | left | right | 1 | - // | z1_a | z1_b | b_1 | b_2 | l | 0 | - { - layouter.assign_region( - || "Check piece decomposition", - |mut region| { - // Set the fixed column `l` to the current l. - // Recall that l = MERKLE_DEPTH - layer - 1. - // The layer with 2^n nodes is called "layer n". - config.q_decompose.enable(&mut region, 0)?; - region.assign_advice_from_constant( - || format!("l {}", l), - config.advices[4], - 1, - pallas::Base::from(l as u64), - )?; - - // Offset 0 - // Copy and assign `a` at the correct position. - a.inner().cell_value().copy_advice( - || "copy a", - &mut region, - config.advices[0], - 0, - )?; - // Copy and assign `b` at the correct position. - b.inner().cell_value().copy_advice( - || "copy b", - &mut region, - config.advices[1], - 0, - )?; - // Copy and assign `c` at the correct position. - c.inner().cell_value().copy_advice( - || "copy c", - &mut region, - config.advices[2], - 0, - )?; - // Copy and assign the left node at the correct position. - left.copy_advice(|| "left", &mut region, config.advices[3], 0)?; - // Copy and assign the right node at the correct position. - right.copy_advice(|| "right", &mut region, config.advices[4], 0)?; - - // Offset 1 - // Copy and assign z_1 of SinsemillaHash(a) = a_1 - z1_a.copy_advice(|| "z1_a", &mut region, config.advices[0], 1)?; - // Copy and assign z_1 of SinsemillaHash(b) = b_1 - z1_b.copy_advice(|| "z1_b", &mut region, config.advices[1], 1)?; - // Copy `b_1`, which has been constrained to be a 5-bit value - b_1.inner() - .copy_advice(|| "b_1", &mut region, config.advices[2], 1)?; - // Copy `b_2`, which has been constrained to be a 5-bit value - b_2.inner() - .copy_advice(|| "b_2", &mut region, config.advices[3], 1)?; - - Ok(()) - }, - )?; - } - - // Check layer hash output against Sinsemilla primitives hash - #[cfg(test)] - { - use crate::{sinsemilla::primitives::HashDomain, utilities::i2lebsp}; - - use group::ff::PrimeFieldBits; - - left.value() - .zip(right.value()) - .zip(hash.value()) - .assert_if_known(|((left, right), hash)| { - let l = i2lebsp::<10>(l as u64); - let left: Vec<_> = left - .to_le_bits() - .iter() - .by_vals() - .take(pallas::Base::NUM_BITS as usize) - .collect(); - let right: Vec<_> = right - .to_le_bits() - .iter() - .by_vals() - .take(pallas::Base::NUM_BITS as usize) - .collect(); - let merkle_crh = HashDomain::from_Q(Q.into()); - - let mut message = l.to_vec(); - message.extend_from_slice(&left); - message.extend_from_slice(&right); - - let expected = merkle_crh.hash(message.into_iter()).unwrap(); - - expected.to_repr() == hash.to_repr() - }); - } - - Ok(hash) - } -} - -impl UtilitiesInstructions for MerkleChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - type Var = AssignedCell; -} - -impl CondSwapInstructions for MerkleChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - #[allow(clippy::type_complexity)] - fn swap( - &self, - layouter: impl Layouter, - pair: (Self::Var, Value), - swap: Value, - ) -> Result<(Self::Var, Self::Var), Error> { - let config = self.config().cond_swap_config.clone(); - let chip = CondSwapChip::::construct(config); - chip.swap(layouter, pair, swap) - } -} - -impl SinsemillaInstructions - for MerkleChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - type CellValue = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::CellValue; - - type Message = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::Message; - type MessagePiece = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::MessagePiece; - type RunningSum = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::RunningSum; - - type X = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::X; - type NonIdentityPoint = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::NonIdentityPoint; - type FixedPoints = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::FixedPoints; - - type HashDomains = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::HashDomains; - type CommitDomains = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::CommitDomains; - - fn witness_message_piece( - &self, - layouter: impl Layouter, - value: Value, - num_words: usize, - ) -> Result { - let config = self.config().sinsemilla_config.clone(); - let chip = SinsemillaChip::::construct(config); - chip.witness_message_piece(layouter, value, num_words) - } - - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - fn hash_to_point( - &self, - layouter: impl Layouter, - Q: pallas::Affine, - message: Self::Message, - ) -> Result<(Self::NonIdentityPoint, Vec>), Error> { - let config = self.config().sinsemilla_config.clone(); - let chip = SinsemillaChip::::construct(config); - chip.hash_to_point(layouter, Q, message) - } - - fn extract(point: &Self::NonIdentityPoint) -> Self::X { - SinsemillaChip::::extract(point) - } -} diff --git a/halo2_gadgets/src/sinsemilla/message.rs b/halo2_gadgets/src/sinsemilla/message.rs deleted file mode 100644 index 62696834ab..0000000000 --- a/halo2_gadgets/src/sinsemilla/message.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Gadget and chips for the Sinsemilla hash function. -use ff::PrimeFieldBits; -use halo2_proofs::{ - arithmetic::Field, - circuit::{AssignedCell, Cell, Value}, -}; -use std::fmt::Debug; - -/// A [`Message`] composed of several [`MessagePiece`]s. -#[derive(Clone, Debug)] -pub struct Message(Vec>); - -impl From>> - for Message -{ - fn from(pieces: Vec>) -> Self { - // A message cannot contain more than `MAX_WORDS` words. - assert!(pieces.iter().map(|piece| piece.num_words()).sum::() < MAX_WORDS); - Message(pieces) - } -} - -impl std::ops::Deref - for Message -{ - type Target = [MessagePiece]; - - fn deref(&self) -> &[MessagePiece] { - &self.0 - } -} - -/// A [`MessagePiece`] of some bitlength. -/// -/// The piece must fit within a base field element, which means its length -/// cannot exceed the base field's `NUM_BITS`. -#[derive(Clone, Debug)] -pub struct MessagePiece { - cell_value: AssignedCell, - /// The number of K-bit words in this message piece. - num_words: usize, -} - -impl MessagePiece { - pub fn new(cell_value: AssignedCell, num_words: usize) -> Self { - assert!(num_words * K < F::NUM_BITS as usize); - Self { - cell_value, - num_words, - } - } - - pub fn num_words(&self) -> usize { - self.num_words - } - - pub fn cell(&self) -> Cell { - self.cell_value.cell() - } - - pub fn field_elem(&self) -> Value { - self.cell_value.value().cloned() - } - - pub fn cell_value(&self) -> AssignedCell { - self.cell_value.clone() - } -} diff --git a/halo2_gadgets/src/sinsemilla/primitives.rs b/halo2_gadgets/src/sinsemilla/primitives.rs deleted file mode 100644 index fd2e4aea72..0000000000 --- a/halo2_gadgets/src/sinsemilla/primitives.rs +++ /dev/null @@ -1,308 +0,0 @@ -//! Implementation of Sinsemilla outside the circuit. - -use group::{Curve, Wnaf}; -use halo2_proofs::arithmetic::{CurveAffine, CurveExt}; -use halo2curves::pasta::pallas; -use subtle::CtOption; - -mod addition; -use self::addition::IncompletePoint; -mod sinsemilla_s; -pub use sinsemilla_s::SINSEMILLA_S; - -/// Number of bits of each message piece in $\mathsf{SinsemillaHashToPoint}$ -pub const K: usize = 10; - -/// $\frac{1}{2^K}$ -pub const INV_TWO_POW_K: [u8; 32] = [ - 1, 0, 192, 196, 160, 229, 70, 82, 221, 165, 74, 202, 85, 7, 62, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 240, 63, -]; - -/// The largest integer such that $2^c \leq (r_P - 1) / 2$, where $r_P$ is the order -/// of Pallas. -pub const C: usize = 253; - -// Sinsemilla Q generators - -/// SWU hash-to-curve personalization for Sinsemilla $Q$ generators. -pub const Q_PERSONALIZATION: &str = "z.cash:SinsemillaQ"; - -// Sinsemilla S generators - -/// SWU hash-to-curve personalization for Sinsemilla $S$ generators. -pub const S_PERSONALIZATION: &str = "z.cash:SinsemillaS"; - -pub(crate) fn lebs2ip_k(bits: &[bool]) -> u32 { - assert!(bits.len() == K); - bits.iter() - .enumerate() - .fold(0u32, |acc, (i, b)| acc + if *b { 1 << i } else { 0 }) -} - -/// Coordinate extractor for Pallas. -/// -/// Defined in [Zcash Protocol Spec § 5.4.9.7: Coordinate Extractor for Pallas][concreteextractorpallas]. -/// -/// [concreteextractorpallas]: https://zips.z.cash/protocol/nu5.pdf#concreteextractorpallas -fn extract_p_bottom(point: CtOption) -> CtOption { - point.map(|p| { - p.to_affine() - .coordinates() - .map(|c| *c.x()) - .unwrap_or_else(pallas::Base::zero) - }) -} - -/// Pads the given iterator (which MUST have length $\leq K * C$) with zero-bits to a -/// multiple of $K$ bits. -struct Pad> { - /// The iterator we are padding. - inner: I, - /// The measured length of the inner iterator. - /// - /// This starts as a lower bound, and will be accurate once `padding_left.is_some()`. - len: usize, - /// The amount of padding that remains to be emitted. - padding_left: Option, -} - -impl> Pad { - fn new(inner: I) -> Self { - Pad { - inner, - len: 0, - padding_left: None, - } - } -} - -impl> Iterator for Pad { - type Item = bool; - - fn next(&mut self) -> Option { - loop { - // If we have identified the required padding, the inner iterator has ended, - // and we will never poll it again. - if let Some(n) = self.padding_left.as_mut() { - if *n == 0 { - // Either we already emitted all necessary padding, or there was no - // padding required. - break None; - } else { - // Emit the next padding bit. - *n -= 1; - break Some(false); - } - } else if let Some(ret) = self.inner.next() { - // We haven't reached the end of the inner iterator yet. - self.len += 1; - assert!(self.len <= K * C); - break Some(ret); - } else { - // Inner iterator just ended, so we now know its length. - let rem = self.len % K; - if rem > 0 { - // The inner iterator requires padding in the range [1,K). - self.padding_left = Some(K - rem); - } else { - // No padding required. - self.padding_left = Some(0); - } - } - } - } -} - -/// A domain in which $\mathsf{SinsemillaHashToPoint}$ and $\mathsf{SinsemillaHash}$ can -/// be used. -#[derive(Debug, Clone)] -#[allow(non_snake_case)] -pub struct HashDomain { - Q: pallas::Point, -} - -impl HashDomain { - /// Constructs a new `HashDomain` with a specific prefix string. - pub fn new(domain: &str) -> Self { - HashDomain { - Q: pallas::Point::hash_to_curve(Q_PERSONALIZATION)(domain.as_bytes()), - } - } - - /// $\mathsf{SinsemillaHashToPoint}$ from [§ 5.4.1.9][concretesinsemillahash]. - /// - /// [concretesinsemillahash]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillahash - pub fn hash_to_point(&self, msg: impl Iterator) -> CtOption { - self.hash_to_point_inner(msg).into() - } - - #[allow(non_snake_case)] - fn hash_to_point_inner(&self, msg: impl Iterator) -> IncompletePoint { - let padded: Vec<_> = Pad::new(msg).collect(); - - padded - .chunks(K) - .fold(IncompletePoint::from(self.Q), |acc, chunk| { - let (S_x, S_y) = SINSEMILLA_S[lebs2ip_k(chunk) as usize]; - let S_chunk = pallas::Affine::from_xy(S_x, S_y).unwrap(); - (acc + S_chunk) + acc - }) - } - - /// $\mathsf{SinsemillaHash}$ from [§ 5.4.1.9][concretesinsemillahash]. - /// - /// [concretesinsemillahash]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillahash - /// - /// # Panics - /// - /// This panics if the message length is greater than [`K`] * [`C`] - pub fn hash(&self, msg: impl Iterator) -> CtOption { - extract_p_bottom(self.hash_to_point(msg)) - } - - /// Constructs a new `HashDomain` from a given `Q`. - /// - /// This is only for testing use. - #[cfg(test)] - #[allow(non_snake_case)] - pub(crate) fn from_Q(Q: pallas::Point) -> Self { - HashDomain { Q } - } - - /// Returns the Sinsemilla $Q$ constant for this domain. - #[cfg(any(test, feature = "test-dependencies"))] - #[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] - #[allow(non_snake_case)] - pub fn Q(&self) -> pallas::Point { - self.Q - } -} - -/// A domain in which $\mathsf{SinsemillaCommit}$ and $\mathsf{SinsemillaShortCommit}$ can -/// be used. -#[derive(Debug)] -#[allow(non_snake_case)] -pub struct CommitDomain { - M: HashDomain, - R: pallas::Point, -} - -impl CommitDomain { - /// Constructs a new `CommitDomain` with a specific prefix string. - pub fn new(domain: &str) -> Self { - let m_prefix = format!("{}-M", domain); - let r_prefix = format!("{}-r", domain); - let hasher_r = pallas::Point::hash_to_curve(&r_prefix); - CommitDomain { - M: HashDomain::new(&m_prefix), - R: hasher_r(&[]), - } - } - - /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. - /// - /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit - #[allow(non_snake_case)] - pub fn commit( - &self, - msg: impl Iterator, - r: &pallas::Scalar, - ) -> CtOption { - // We use complete addition for the blinding factor. - CtOption::::from(self.M.hash_to_point_inner(msg)) - .map(|p| p + Wnaf::new().scalar(r).base(self.R)) - } - - /// $\mathsf{SinsemillaShortCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. - /// - /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit - pub fn short_commit( - &self, - msg: impl Iterator, - r: &pallas::Scalar, - ) -> CtOption { - extract_p_bottom(self.commit(msg, r)) - } - - /// Returns the Sinsemilla $R$ constant for this domain. - #[cfg(any(test, feature = "test-dependencies"))] - #[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] - #[allow(non_snake_case)] - pub fn R(&self) -> pallas::Point { - self.R - } - - /// Returns the Sinsemilla $Q$ constant for this domain. - #[cfg(any(test, feature = "test-dependencies"))] - #[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] - #[allow(non_snake_case)] - pub fn Q(&self) -> pallas::Point { - self.M.Q - } -} - -#[cfg(test)] -mod tests { - use super::{Pad, K}; - use halo2curves::{pasta::pallas, CurveExt}; - - #[test] - fn pad() { - assert_eq!( - Pad::new([].iter().cloned()).collect::>(), - vec![false; 0] - ); - assert_eq!( - Pad::new([true].iter().cloned()).collect::>(), - vec![true, false, false, false, false, false, false, false, false, false] - ); - assert_eq!( - Pad::new([true, true].iter().cloned()).collect::>(), - vec![true, true, false, false, false, false, false, false, false, false] - ); - assert_eq!( - Pad::new([true, true, true].iter().cloned()).collect::>(), - vec![true, true, true, false, false, false, false, false, false, false] - ); - assert_eq!( - Pad::new( - [true, true, false, true, false, true, false, true, false, true] - .iter() - .cloned() - ) - .collect::>(), - vec![true, true, false, true, false, true, false, true, false, true] - ); - assert_eq!( - Pad::new( - [true, true, false, true, false, true, false, true, false, true, true] - .iter() - .cloned() - ) - .collect::>(), - vec![ - true, true, false, true, false, true, false, true, false, true, true, false, false, - false, false, false, false, false, false, false - ] - ); - } - - #[test] - fn sinsemilla_s() { - use super::sinsemilla_s::SINSEMILLA_S; - use group::Curve; - use halo2curves::CurveAffine; - - let hasher = pallas::Point::hash_to_curve(super::S_PERSONALIZATION); - - for j in 0..(1u32 << K) { - let computed = { - let point = hasher(&j.to_le_bytes()).to_affine().coordinates().unwrap(); - (*point.x(), *point.y()) - }; - let actual = SINSEMILLA_S[j as usize]; - assert_eq!(computed, actual); - } - } -} diff --git a/halo2_gadgets/src/sinsemilla/primitives/addition.rs b/halo2_gadgets/src/sinsemilla/primitives/addition.rs deleted file mode 100644 index 9d4574dca1..0000000000 --- a/halo2_gadgets/src/sinsemilla/primitives/addition.rs +++ /dev/null @@ -1,73 +0,0 @@ -use std::ops::Add; - -use group::{cofactor::CofactorCurveAffine, Group}; -use halo2curves::pasta::pallas; -use subtle::{ConstantTimeEq, CtOption}; - -/// P ∪ {⊥} -/// -/// Simulated incomplete addition built over complete addition. -#[derive(Clone, Copy, Debug)] -pub(super) struct IncompletePoint(CtOption); - -impl From for IncompletePoint { - fn from(p: pallas::Point) -> Self { - IncompletePoint(CtOption::new(p, 1.into())) - } -} - -impl From for CtOption { - fn from(p: IncompletePoint) -> Self { - p.0 - } -} - -impl Add for IncompletePoint { - type Output = IncompletePoint; - - #[allow(clippy::suspicious_arithmetic_impl)] - fn add(self, rhs: Self) -> Self::Output { - // ⊥ ⸭ ⊥ = ⊥ - // ⊥ ⸭ P = ⊥ - IncompletePoint(self.0.and_then(|p| { - // P ⸭ ⊥ = ⊥ - rhs.0.and_then(|q| { - // 0 ⸭ 0 = ⊥ - // 0 ⸭ P = ⊥ - // P ⸭ 0 = ⊥ - // (x, y) ⸭ (x', y') = ⊥ if x == x' - // (x, y) ⸭ (x', y') = (x, y) + (x', y') if x != x' - CtOption::new( - p + q, - !(p.is_identity() | q.is_identity() | p.ct_eq(&q) | p.ct_eq(&-q)), - ) - }) - })) - } -} - -impl Add for IncompletePoint { - type Output = IncompletePoint; - - /// Specialisation of incomplete addition for mixed addition. - #[allow(clippy::suspicious_arithmetic_impl)] - fn add(self, rhs: pallas::Affine) -> Self::Output { - // ⊥ ⸭ ⊥ = ⊥ - // ⊥ ⸭ P = ⊥ - IncompletePoint(self.0.and_then(|p| { - // P ⸭ ⊥ = ⊥ is satisfied by definition. - let q = rhs.to_curve(); - - // 0 ⸭ 0 = ⊥ - // 0 ⸭ P = ⊥ - // P ⸭ 0 = ⊥ - // (x, y) ⸭ (x', y') = ⊥ if x == x' - // (x, y) ⸭ (x', y') = (x, y) + (x', y') if x != x' - CtOption::new( - // Use mixed addition for efficiency. - p + rhs, - !(p.is_identity() | q.is_identity() | p.ct_eq(&q) | p.ct_eq(&-q)), - ) - })) - } -} diff --git a/halo2_gadgets/src/sinsemilla/primitives/sinsemilla_s.rs b/halo2_gadgets/src/sinsemilla/primitives/sinsemilla_s.rs deleted file mode 100644 index c72fe5841f..0000000000 --- a/halo2_gadgets/src/sinsemilla/primitives/sinsemilla_s.rs +++ /dev/null @@ -1,14344 +0,0 @@ -use super::K; -use halo2curves::pasta::pallas; - -/// The precomputed bases for the [Sinsemilla hash function][concretesinsemillahash]. -/// -/// [concretesinsemillahash]: https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash -pub const SINSEMILLA_S: [(pallas::Base, pallas::Base); 1 << K] = [ - ( - pallas::Base::from_raw([ - 0x5a91_eb91_2044_ea5f, - 0x29a0_5baf_bede_62b5, - 0x1431_d4ea_7d4a_fc7b, - 0x0db5_218b_e688_1f0f, - ]), - pallas::Base::from_raw([ - 0x17c2_4f76_bf8e_6483, - 0x944a_041c_2e65_ba01, - 0x9caf_6629_8493_d5d0, - 0x2f0f_40c2_f152_a01c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xce4a_e33e_a108_af91, - 0xe677_00ca_2464_9b8f, - 0xc8fd_33eb_3917_5404, - 0x2111_12b4_b3e1_9518, - ]), - pallas::Base::from_raw([ - 0x1d83_c293_f810_c5ee, - 0xb43c_744a_670e_19bc, - 0xa38a_3e79_cd5a_35fe, - 0x06c5_9939_93ad_b03b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x22e0_c475_a18f_6d24, - 0xf40c_b333_4b54_11c0, - 0x4661_a4e2_355b_9b33, - 0x25b3_2ccd_49f9_25a3, - ]), - pallas::Base::from_raw([ - 0xa67d_6b8d_b8fd_9757, - 0x4be1_ebb9_f945_ccd2, - 0x7d53_d0f3_23b4_4711, - 0x140f_f2ba_70d0_692c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa5fa_ef0f_0419_dabc, - 0x6539_ca12_938b_1826, - 0x60ff_465c_d02c_701f, - 0x1421_5a48_e118_32c9, - ]), - pallas::Base::from_raw([ - 0x011d_5d36_25ca_36dc, - 0x97b6_3b4b_53e2_ad56, - 0xc711_a0b9_0b58_03bd, - 0x1066_6957_becb_884d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xcd48_cef6_4bed_0936, - 0x0e94_8b52_f738_61ce, - 0x9ab9_b595_d23f_059f, - 0x315c_f93b_9e63_151c, - ]), - pallas::Base::from_raw([ - 0xe257_7684_a31c_721a, - 0x81ef_1386_c070_a51d, - 0x2afb_9a52_d043_78ca, - 0x2c54_c0b3_8dfb_ad40, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1e62_9662_aa5a_3fdf, - 0x94fb_57dc_9d31_389b, - 0x63c5_542e_be6c_3ab7, - 0x1d74_51a5_7e92_5ec5, - ]), - pallas::Base::from_raw([ - 0x934c_1dc8_aaca_454b, - 0xc086_048c_4eef_c0dd, - 0xc49c_1472_164b_6fbc, - 0x0a4b_5139_9347_7ec7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7e7c_cebd_ac44_118f, - 0xe055_272f_8429_ff1c, - 0x3c80_b5f8_24a7_5f24, - 0x0d3d_3c74_10d4_4668, - ]), - pallas::Base::from_raw([ - 0x79ea_b21b_b522_55cc, - 0x1268_61c0_de4f_0982, - 0xa02e_3186_23a5_5ae9, - 0x2b94_e712_9758_334f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0e77_383e_d712_9d2f, - 0x6283_df71_4b0f_9b18, - 0x0864_617c_d666_062c, - 0x197e_faba_7491_0b57, - ]), - pallas::Base::from_raw([ - 0x85b8_e2cb_12fd_c127, - 0x7a88_75b5_de27_45cd, - 0x8df5_6a97_ed99_d31b, - 0x34d9_5547_d6e9_56a9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd21c_d292_6b24_b055, - 0xa416_7a07_7246_418e, - 0x3e29_11ab_ef54_9b47, - 0x305a_d0e8_b11c_ee66, - ]), - pallas::Base::from_raw([ - 0x9b39_73cf_a5bf_b938, - 0x12a2_0ca5_d138_80d6, - 0x8207_1242_c3b7_34a4, - 0x3e25_9102_6dbb_bfd8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf6bc_e362_6b48_56be, - 0xdf5e_e6f1_5b66_3484, - 0xbc37_bdf1_4766_3e61, - 0x2a80_ed20_aecc_771f, - ]), - pallas::Base::from_raw([ - 0xaeaf_58cd_40d9_d753, - 0x6776_81a1_39a9_44eb, - 0xdb78_4220_d080_d1ae, - 0x3bed_9f53_2f89_c873, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa96d_351c_69e7_3b34, - 0xe5df_e62c_bb74_b432, - 0x3e0b_f886_c563_3909, - 0x1169_679d_516b_0f52, - ]), - pallas::Base::from_raw([ - 0x447f_2648_3a56_52ee, - 0x77d8_03b3_afe8_3912, - 0xbe1e_a779_988f_4fd3, - 0x24dc_58d8_46ef_f85d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x851d_c62e_bc87_5030, - 0x1957_510c_703c_5765, - 0xd439_8de8_3aae_c992, - 0x0a64_5164_e0e0_d1cb, - ]), - pallas::Base::from_raw([ - 0xd768_494c_1aa6_936d, - 0x0c89_d7ee_a548_c2a4, - 0x7e1f_87b7_9978_76b1, - 0x153f_b63d_3879_f182, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc565_0619_42a8_3439, - 0x7716_f57c_193a_3df2, - 0x1325_b0e1_8d7a_ea0a, - 0x05a9_1753_a68b_7601, - ]), - pallas::Base::from_raw([ - 0x2443_2316_26bd_d43c, - 0x959f_e764_a3f2_575f, - 0xd709_6a40_9799_144e, - 0x1c29_c630_347e_9508, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe843_6f46_1411_e72a, - 0x2c1a_4034_7249_2a59, - 0x1347_0a8d_938a_b691, - 0x25e3_34b5_cec9_3544, - ]), - pallas::Base::from_raw([ - 0xcec5_d233_9cad_4b3d, - 0xa40d_0761_a4cc_45ab, - 0x194c_d250_2d80_84b2, - 0x0160_64db_6159_2474, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe2f0_65b5_2537_5cc9, - 0x2528_5987_8c88_25ab, - 0x9252_31c1_bc9d_6a66, - 0x379c_2bd0_c190_9c7e, - ]), - pallas::Base::from_raw([ - 0xa0fb_efa7_6375_9430, - 0x430e_1e41_7b73_83f0, - 0xddea_123a_66f3_6e40, - 0x11a9_c254_99d5_9f1b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0b5a_9e1e_862e_edaa, - 0xc0a3_4382_61ff_61c6, - 0x4b41_f6dc_4801_f3a1, - 0x0c6f_c7b2_d365_6f82, - ]), - pallas::Base::from_raw([ - 0xf30d_50e8_3e60_3bb5, - 0x589f_b478_7d54_8e5f, - 0x06d5_b032_d1ea_0eeb, - 0x2492_a76d_96dc_fe8e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0719_4d69_3a4f_e5d9, - 0xc3f4_ced6_5ced_7022, - 0x1965_c5c3_f9ee_e6b7, - 0x0c17_5d45_3bb5_0e04, - ]), - pallas::Base::from_raw([ - 0x6e28_e65c_02a8_979a, - 0x9155_bdb2_213a_1ec2, - 0xa592_5dd2_ac1b_a08a, - 0x106e_3d4f_2d01_2990, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2af5_5769_718f_6d0a, - 0x0acc_0135_db3d_9c80, - 0x31f8_9d95_9313_5e05, - 0x26e5_eae3_20ed_b155, - ]), - pallas::Base::from_raw([ - 0xd75b_fdee_b95f_d1c9, - 0x1e63_a80a_818c_5374, - 0x4bb1_c3e6_0f0b_c040, - 0x1d05_882a_cd14_4b0c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7ec3_90f2_5e39_5b94, - 0x4230_0755_c68f_a549, - 0x9210_9733_af81_0407, - 0x310d_60d7_14eb_00d9, - ]), - pallas::Base::from_raw([ - 0xce04_43cb_4410_650a, - 0xb1c0_4053_f900_ef43, - 0x4087_e7a3_9312_1fdd, - 0x3ee2_559e_cdce_ec5c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa2a0_b2bb_c709_eb43, - 0x8ade_17ea_bf18_0624, - 0xbe3d_cee5_1eac_8187, - 0x1719_0481_09ec_ac8d, - ]), - pallas::Base::from_raw([ - 0x2abc_973a_cc15_a05b, - 0x50a8_df0b_570a_193a, - 0x87f1_e098_4f0e_1d44, - 0x1267_3ac5_b9fe_f8c5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb461_d0fe_6d58_3369, - 0xccbc_110f_c982_9287, - 0x0263_da47_2626_a5f0, - 0x1289_d222_9c37_19c6, - ]), - pallas::Base::from_raw([ - 0x7f84_d109_f869_6212, - 0xe7b6_8435_60c9_f37e, - 0xc9ab_26a3_a8a3_b9aa, - 0x08a7_e5e9_d4ad_1e44, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd657_d70e_67a6_cffb, - 0x1bc2_8f7a_f5d8_d663, - 0x176c_cb97_5e2e_acdd, - 0x08dc_48f1_a91c_222a, - ]), - pallas::Base::from_raw([ - 0xc6aa_0ceb_40b6_128c, - 0x94a1_9ee5_c270_a217, - 0x9f79_f114_a1f4_083a, - 0x21f4_0941_aa55_b3d0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x84c6_e703_7113_c2c1, - 0x9549_5a9a_5e2c_f521, - 0xae9d_c0a2_1bc8_b85e, - 0x2bde_7809_257f_2d02, - ]), - pallas::Base::from_raw([ - 0xa114_c0a6_314e_d2f9, - 0x9be7_e608_3d7e_876f, - 0xc105_6823_d929_fd2a, - 0x15ac_6d2a_83e2_50bd, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb0fe_9fd5_a421_340b, - 0x48e4_f171_3c9e_cd26, - 0xe4f4_ac71_3d4a_95bc, - 0x312b_6128_1ab5_d033, - ]), - pallas::Base::from_raw([ - 0x405b_d400_afdb_5d9c, - 0xaaeb_8090_ef6b_9390, - 0x7469_c0b3_e23c_53dd, - 0x2e4f_21bf_b05d_4559, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa0bf_d82b_7612_2e84, - 0x6c78_ca0a_b548_2d27, - 0x75ae_5653_62af_eb1d, - 0x089b_3b7f_8bd4_ea08, - ]), - pallas::Base::from_raw([ - 0x7fca_3834_c670_2579, - 0xa062_31d2_085d_6258, - 0xb32f_6836_d782_eb34, - 0x3708_e831_35ae_10c4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9f6d_c014_6c05_c7fe, - 0x1119_b3b5_d67c_a65f, - 0x45bf_6d2e_f7e6_fe54, - 0x0141_08ac_9ab6_3e4f, - ]), - pallas::Base::from_raw([ - 0x57f9_36e7_a514_d173, - 0x3d4e_a9b8_283e_a3f2, - 0x0b45_9bbe_bf56_d8df, - 0x0096_be83_6417_c3ce, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbf84_7e6e_a60a_1e10, - 0x007d_0da9_59a1_8af7, - 0x9b66_6f39_805d_f26e, - 0x2dda_a8b1_c70d_4798, - ]), - pallas::Base::from_raw([ - 0x8afa_e4a1_2104_3215, - 0xfc45_281d_665c_435f, - 0xcf42_5d23_97a4_d0d6, - 0x203b_d5e4_3544_e416, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6355_a342_c769_b991, - 0xaf94_3561_7ca8_fba5, - 0x9bc6_1953_1bc6_867c, - 0x35c6_b4b2_7ce9_8c84, - ]), - pallas::Base::from_raw([ - 0x358b_52f2_aa05_d0e2, - 0x1e36_f404_1069_11a7, - 0xdfb1_775d_f512_925e, - 0x2f0e_4cff_2885_5660, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9bc6_45aa_659d_394f, - 0x63fb_f9d5_aff5_52c2, - 0x2a81_a1f9_157d_0ddf, - 0x0840_8d6d_792b_1bdd, - ]), - pallas::Base::from_raw([ - 0x6214_c9e0_a442_6fed, - 0x580c_2dc1_b2dc_4db0, - 0xdf6e_7ce6_7c07_8b91, - 0x149b_86c7_aa0a_5807, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2366_fb20_016a_d15d, - 0x7e11_a509_32be_92a2, - 0xdf46_3c90_d34d_85db, - 0x3b7d_3524_37fb_ddae, - ]), - pallas::Base::from_raw([ - 0xd701_78a2_e2e7_3b2c, - 0xeb76_7a60_49bb_fd17, - 0xa081_0c5a_7118_8504, - 0x30e1_da14_7a31_ac8a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x996c_1cc3_79a3_05e2, - 0x61d9_35a7_da7f_f9df, - 0xe77e_3c50_0e84_d1fe, - 0x119d_6098_c1df_c009, - ]), - pallas::Base::from_raw([ - 0xe83c_68f6_0bac_ad89, - 0xe3e4_5f6b_7f33_8aea, - 0xcb02_edb7_2703_0a11, - 0x0dfe_fcd8_c7a0_37d2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0249_e1ef_c0c1_2e3f, - 0xfd35_f750_fc1b_140e, - 0x34cc_fd25_ee0a_24a4, - 0x2d85_ea37_1450_e936, - ]), - pallas::Base::from_raw([ - 0xea03_7e87_7076_c6a6, - 0x1e86_054a_7181_9a98, - 0xc8b2_0a67_de55_ffdd, - 0x2fa0_f1dc_c560_6ead, - ]), - ), - ( - pallas::Base::from_raw([ - 0x149d_4058_8269_142a, - 0xc47e_8699_87cd_0c7e, - 0x9083_84e4_4ce8_c260, - 0x0d65_ccec_99ef_3d51, - ]), - pallas::Base::from_raw([ - 0x3d9f_bece_1b95_bb5c, - 0x7369_87ea_5b12_60ce, - 0x69c5_cc43_e099_3c2c, - 0x1296_2805_bcb2_5e3d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfd0f_79ac_f857_70f6, - 0x2cad_5ad0_3b87_58f2, - 0xd79d_4eba_953a_f087, - 0x0074_778c_62d8_0363, - ]), - pallas::Base::from_raw([ - 0x4d53_43bd_75b7_04b2, - 0xfb69_64df_389f_bd6c, - 0x0999_4f51_36f1_c414, - 0x0776_f4ae_c6cb_4e85, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2207_b16e_8cac_9dc4, - 0x6fcc_2464_92c3_0265, - 0x1f05_e00a_14f4_b845, - 0x01a9_d4be_c204_e872, - ]), - pallas::Base::from_raw([ - 0xf783_69ae_24fb_81a8, - 0xf741_a8a2_38ae_9967, - 0x4408_0885_faae_b30d, - 0x03f7_7f1f_49b9_18e6, - ]), - ), - ( - pallas::Base::from_raw([ - 0xad73_e083_fd4b_c101, - 0xb299_c606_ca3b_197f, - 0x61c8_0000_0ba8_6506, - 0x1691_35f3_c4b5_4f76, - ]), - pallas::Base::from_raw([ - 0x8760_58ce_eb92_e28c, - 0x34f0_16e0_f86c_0e2d, - 0x86b0_495e_c47b_3f50, - 0x03f1_c42b_c4c5_85ff, - ]), - ), - ( - pallas::Base::from_raw([ - 0x017d_94b7_2cab_798c, - 0x8d6d_cb5b_18aa_f523, - 0x8e08_8b5d_8994_c20b, - 0x19ba_e178_e635_fe13, - ]), - pallas::Base::from_raw([ - 0xab27_84b4_994a_0119, - 0x9da4_fe0e_635c_7e33, - 0x1143_8112_caa2_afc4, - 0x3acf_da94_ded9_c4e7, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbbce_cb08_317a_55bc, - 0x36aa_ddcd_3238_f0e6, - 0xdf00_05b6_e6ab_d61e, - 0x2527_c64e_053d_087c, - ]), - pallas::Base::from_raw([ - 0x6be8_48ee_033a_68ef, - 0x55a3_f9ac_d4f4_cee1, - 0xf6dd_57ce_d465_28bf, - 0x1e27_ea7d_b509_cc96, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe5bc_12d9_9516_4280, - 0x2a00_0dc2_5125_5df6, - 0xa936_924b_164c_d882, - 0x34a9_358a_32a8_ce49, - ]), - pallas::Base::from_raw([ - 0x60e8_77e4_dfcb_aca2, - 0x0aa5_3e88_25f8_a521, - 0xe325_6cc5_83dd_f098, - 0x3bdb_fc5c_5aa3_cdb8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6d95_f7ea_ea3d_16d8, - 0x03c0_4e9a_6bd6_5383, - 0xec05_bb17_c4fe_b283, - 0x289e_03a5_ed1f_3b07, - ]), - pallas::Base::from_raw([ - 0x2b6a_c52f_feb1_7686, - 0xbcb7_da92_4e49_8948, - 0xa995_cd81_d04d_dbd3, - 0x0c46_6c57_1159_224a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6093_9be7_a4d2_9f0c, - 0x1518_62a2_b799_0aa2, - 0x44a3_e62c_1ce7_8cc2, - 0x201e_25ea_427d_e5f3, - ]), - pallas::Base::from_raw([ - 0x5853_5ee9_27ff_6b4f, - 0xa9ba_b5b3_9592_7126, - 0x2c60_0708_e61e_5681, - 0x31d4_68f6_37a7_026d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x97ec_2bda_32f9_27b3, - 0x7e79_9f38_c361_ed87, - 0x588f_ac0b_d601_fa88, - 0x275f_7736_734d_27fe, - ]), - pallas::Base::from_raw([ - 0x6426_8a27_c545_d9b9, - 0x46a0_a23d_c423_01eb, - 0xac7d_e04c_dccf_c81c, - 0x3030_4778_8312_b499, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9491_a146_3215_8028, - 0xee63_c9c2_6401_e1ab, - 0xe68f_139c_e3e6_847b, - 0x0ce9_e803_9aca_842f, - ]), - pallas::Base::from_raw([ - 0xe09d_04d1_25c7_4609, - 0x3770_bbd0_c05e_f8ad, - 0xdd8b_8c88_a169_9567, - 0x2d99_3912_f127_a6e4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe531_5459_6f63_dd08, - 0xf7a0_13fe_10a1_9fc0, - 0xd7b4_76dc_ac74_a040, - 0x08a0_75bf_2f3f_783f, - ]), - pallas::Base::from_raw([ - 0x1962_3209_80d2_b200, - 0x3da6_e1b6_5f7f_1977, - 0x6168_4dbf_f2db_9c35, - 0x3c21_4bf5_b381_9204, - ]), - ), - ( - pallas::Base::from_raw([ - 0x46fc_698d_e305_8e9d, - 0xed82_7429_e58b_0e53, - 0xff3b_2ab5_65d8_30e8, - 0x2ee6_898e_6f25_1e50, - ]), - pallas::Base::from_raw([ - 0x2fea_1665_b778_7f9e, - 0xa84c_eb52_339e_9083, - 0xfc32_2809_6906_9bf6, - 0x22a0_7570_d244_95a4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8b2e_1430_028d_9350, - 0xa9ad_41fb_bf86_26c0, - 0xecff_6798_0a63_b4a7, - 0x38ec_640b_0d84_abd2, - ]), - pallas::Base::from_raw([ - 0xda17_249d_9fd9_ddc4, - 0x3862_5d42_a318_2c13, - 0x74b0_4c68_5377_a262, - 0x1e61_c8ab_ab50_80ed, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9263_3bf4_9d92_db8c, - 0x5b42_7e02_12d6_fcc3, - 0xd20c_2b5b_3c99_9c68, - 0x34a7_46a8_736d_3635, - ]), - pallas::Base::from_raw([ - 0x484c_9af1_9fc0_7320, - 0x2362_4c04_4eb0_ddc2, - 0x27e8_3514_854d_3b73, - 0x3064_16e8_7ca7_c73b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x32d4_110d_cc45_356b, - 0x48f4_7f5e_fc03_07ae, - 0x7853_0e2b_f3ff_9683, - 0x36d6_91ab_da05_2e5f, - ]), - pallas::Base::from_raw([ - 0xbedb_da77_5302_ff2e, - 0x4a4c_5917_f279_7024, - 0x0a89_7f1c_02e3_d7f5, - 0x01ac_b0f3_614f_a0e4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4ed3_24c0_f046_d8ff, - 0xd81f_1aca_41bc_54b4, - 0x633d_70fd_3193_5850, - 0x2f15_eb03_9398_a90e, - ]), - pallas::Base::from_raw([ - 0xe7be_4499_5af7_37c9, - 0x073c_911b_0333_2ce7, - 0x6ea6_25ed_f5ff_2dda, - 0x0290_63f6_092d_d3df, - ]), - ), - ( - pallas::Base::from_raw([ - 0x15f2_260b_7092_c6c1, - 0x00fd_36e3_678b_2424, - 0x1463_36d5_403d_3290, - 0x26cc_d620_a8dd_a6be, - ]), - pallas::Base::from_raw([ - 0x24d6_05f8_d93c_5bf6, - 0xbe50_1490_75ca_0894, - 0x70ea_d543_4183_1118, - 0x197e_4293_be61_e514, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9b50_3271_5c73_4456, - 0x2aff_79cf_b329_881f, - 0x20ad_27f7_8677_2305, - 0x1fb2_df9c_0084_6254, - ]), - pallas::Base::from_raw([ - 0xd726_501c_633c_d28f, - 0xee75_e9bd_87c7_1d7e, - 0xe5a0_ffd1_3d7a_a3dc, - 0x3501_2a18_8aab_9aed, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa5e3_3bb7_1725_a038, - 0x1a6f_44fa_d126_caec, - 0xc682_0c7b_8b6b_3c11, - 0x1e69_1a87_f24b_4f92, - ]), - pallas::Base::from_raw([ - 0xef4b_cf4f_cd8d_ce42, - 0x9ed4_61f9_5a17_0c8a, - 0x885b_451a_cc3e_7b33, - 0x17e0_4dc9_ffb0_95b4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe134_a4de_1af0_e032, - 0x6055_abca_fd65_aa29, - 0x8109_bd0f_7563_29f6, - 0x3d92_2e0c_6fcd_9ba6, - ]), - pallas::Base::from_raw([ - 0xa51d_b5ff_c901_49ed, - 0x8886_223c_be3a_44da, - 0x9cf3_0d83_8bc7_63f1, - 0x23d6_dc61_5576_d09a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x79e2_836e_2b2a_990c, - 0x982d_0f03_434f_7eb9, - 0x8bd2_b47f_e76c_d5ab, - 0x1560_a3d5_02ce_9002, - ]), - pallas::Base::from_raw([ - 0x38ca_701d_79f6_f538, - 0x0e6a_15a2_265a_5ca7, - 0x6941_bbbd_ce8a_3cdb, - 0x22ed_bcbd_725d_71c2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xeb62_42b4_9b2b_17cc, - 0xdc45_c0bf_cfb3_b708, - 0x1ae9_71ab_fd1a_3f3e, - 0x3850_926a_6116_f9d5, - ]), - pallas::Base::from_raw([ - 0xdb46_22f9_99d5_1a3a, - 0xddcd_2618_7398_1ef3, - 0x3bb5_8508_b3d1_3894, - 0x2001_6ee8_a7ee_6a67, - ]), - ), - ( - pallas::Base::from_raw([ - 0x40e7_fdbf_ba4d_a620, - 0xf056_b930_22e3_f9ce, - 0x02b8_ee49_e734_7325, - 0x1d6f_f561_e1bc_8de3, - ]), - pallas::Base::from_raw([ - 0xb84e_027a_8189_369d, - 0x22f2_75da_0766_031d, - 0x4fe5_1687_c170_f2ec, - 0x3b2a_c069_39e1_17d1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6207_1eeb_79ef_b20c, - 0x0e39_0101_9c6f_6b1a, - 0xad9a_b2d4_0863_083d, - 0x24bb_0da6_d98e_430c, - ]), - pallas::Base::from_raw([ - 0xdc8e_7552_5328_2784, - 0x97f0_d36b_389a_5e23, - 0xdf59_27ec_4ddf_9bb4, - 0x205f_0b78_f827_4d40, - ]), - ), - ( - pallas::Base::from_raw([ - 0x01cd_96f6_680d_43ce, - 0xead1_e981_b589_56ef, - 0x7c6c_198f_61d3_59b6, - 0x2f8e_652c_a28e_caab, - ]), - pallas::Base::from_raw([ - 0xf893_e5c8_f34a_0ff0, - 0xc70a_cb32_4520_0e27, - 0xf8c6_36ea_ae29_6dc6, - 0x2328_82c1_1d67_4489, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd48e_2c48_68be_2a7f, - 0xfd76_3124_e97c_3785, - 0x2494_17a0_2862_5a76, - 0x1adb_8e39_5814_6bb6, - ]), - pallas::Base::from_raw([ - 0xc5b2_a933_33d8_2271, - 0xc234_101f_038d_cceb, - 0x14f3_b690_9f60_efab, - 0x27ba_de97_ba05_a771, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3781_a814_a454_5341, - 0xa839_4f11_8db0_db87, - 0x5f89_9340_4408_04e2, - 0x32c2_7af2_a581_5018, - ]), - pallas::Base::from_raw([ - 0x5072_470a_53d8_4521, - 0xf3ca_f426_f878_4d19, - 0x59c7_fc07_0d03_a314, - 0x05c9_4781_d82a_2a15, - ]), - ), - ( - pallas::Base::from_raw([ - 0x80d1_8205_7021_0e5c, - 0xc3c1_9d74_bb05_c3fd, - 0xb4d7_0972_795d_dc32, - 0x1703_d858_90b0_1ff2, - ]), - pallas::Base::from_raw([ - 0x48a1_ba30_d95b_8f1c, - 0xd8f0_0c72_cf1d_2306, - 0x13ac_ce4c_3128_9a52, - 0x3e18_5f4b_f046_df12, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6fe5_75df_15be_5ace, - 0x2c1f_ad80_7746_0b25, - 0x1fb9_8d91_95ff_e580, - 0x25d2_f86b_25f6_0374, - ]), - pallas::Base::from_raw([ - 0xe56d_dd9b_adaa_a04d, - 0x443a_5452_103d_3d0c, - 0x268f_e354_2b01_c30f, - 0x360a_d0af_c036_b6ec, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd5be_3219_7358_df23, - 0x36cd_6c6c_65c0_9b4d, - 0x2886_ca9d_7d3a_f212, - 0x0ad0_c100_2c7f_f83f, - ]), - pallas::Base::from_raw([ - 0x965c_3680_c268_ea30, - 0x90c2_1c88_c78f_7abd, - 0xadbd_7dfd_d32e_b481, - 0x3e32_3f87_fe7e_9cc8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa927_c4f7_bcbc_65c9, - 0xb16b_54b4_356c_da95, - 0x467d_21ce_c0a1_946a, - 0x3a94_7a7a_8ba8_fcf3, - ]), - pallas::Base::from_raw([ - 0x6ad5_c82f_2e6b_802b, - 0x2134_5b22_9afa_da8c, - 0xfc8f_90bb_fa9c_a1d5, - 0x1760_5d23_3ef4_1cfb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x745b_4736_84f8_b6ff, - 0x2fa7_72e6_7d28_f226, - 0x7f5c_281c_0a58_3d12, - 0x2101_b974_3906_2e3a, - ]), - pallas::Base::from_raw([ - 0xe616_1109_cf4e_3a62, - 0x250e_baad_119d_1842, - 0xfbd4_356a_24bc_0f49, - 0x197f_86a7_7da6_fbe4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5078_ccf0_65b4_a022, - 0xcadd_f679_760c_cec1, - 0x57f9_1931_9550_a0f2, - 0x1999_0351_202f_4b81, - ]), - pallas::Base::from_raw([ - 0xba4c_1093_d57d_9f32, - 0xa80a_f145_0a0f_e90f, - 0x640a_4328_7313_6af7, - 0x1965_465f_d2eb_c138, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4d75_75df_d86d_6ffc, - 0x8c7b_72c0_1499_bab5, - 0x8354_9fe9_4386_40f6, - 0x01a5_1723_6d7d_92c7, - ]), - pallas::Base::from_raw([ - 0x850e_9adf_152d_9d66, - 0xb87b_f256_43ee_366e, - 0x39dd_1caf_086d_f29c, - 0x2b2e_cbfa_0c18_5cfa, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2ff4_d2c3_2c0c_fb5e, - 0x5b66_20fb_1e78_2e48, - 0x164e_048f_a6a6_a139, - 0x1177_de98_7417_d289, - ]), - pallas::Base::from_raw([ - 0x4473_f63c_8b63_96f8, - 0x8813_7018_e47c_7668, - 0x6e54_658a_9365_58d6, - 0x1565_f32e_c124_4d16, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd3f8_b046_ad64_54ca, - 0x0783_8e28_f074_59fb, - 0x2c26_6e07_3920_1035, - 0x1ade_ae43_961e_58b4, - ]), - pallas::Base::from_raw([ - 0xcbac_9225_97cc_0885, - 0x0297_41f2_ecb8_bb41, - 0x52f7_8881_bca8_0ffe, - 0x2626_3bd7_d9ea_3997, - ]), - ), - ( - pallas::Base::from_raw([ - 0x239b_b01c_10ba_15ee, - 0xe0de_2e2f_e883_21d9, - 0x249e_a03d_0db2_8458, - 0x02a1_1010_c364_a8ea, - ]), - pallas::Base::from_raw([ - 0xbd63_66bd_80d3_bf55, - 0xb968_3e0e_df85_70d0, - 0xf00a_642f_04ed_e36b, - 0x37ff_d622_b30b_a504, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc31a_07a7_d2f5_79be, - 0x93e0_4a16_dd86_733b, - 0xbec9_12d1_386f_ac07, - 0x1991_25d9_b76c_e739, - ]), - pallas::Base::from_raw([ - 0x976a_9a8c_0d17_a731, - 0xaf6f_c9c4_4420_7256, - 0x7e5b_0ef8_957e_bf8d, - 0x1afe_401a_7512_9532, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3be4_fa65_6613_b0fa, - 0x3a1f_be61_2e26_94e4, - 0x0091_a6fc_3b5e_dd57, - 0x39fd_5dda_cf6b_ead4, - ]), - pallas::Base::from_raw([ - 0xf61e_8e10_a02d_938d, - 0x303d_5afb_e1b1_5c24, - 0x4f3b_c283_f1c5_9415, - 0x19ea_636b_25ee_6d68, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2f71_d6ff_1108_c379, - 0x3338_649b_c8f8_2416, - 0x29cb_7fba_0970_1000, - 0x3206_be8d_debb_c71c, - ]), - pallas::Base::from_raw([ - 0x4797_990c_97ff_3dc0, - 0xb0f3_243c_bc1b_97bc, - 0x8017_28af_4cf3_8a59, - 0x3f56_eb32_53df_1196, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5b66_3474_6e09_2e1f, - 0xc2e2_87f5_f9ef_0a82, - 0x2442_95dd_210c_66ca, - 0x1d88_ea2d_bc4c_95ae, - ]), - pallas::Base::from_raw([ - 0xe19d_8eb8_f861_3356, - 0x4b53_10d6_7f10_e971, - 0x1ae6_394e_2861_00bf, - 0x0bc9_988e_3ea3_35e3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc3be_adb7_c20e_f2de, - 0xe8ca_eb5c_5b32_9708, - 0x7c0b_c8f5_a91d_631b, - 0x357d_7b0d_bb96_a87f, - ]), - pallas::Base::from_raw([ - 0xad73_6f6d_e6f6_ed85, - 0xa176_6fea_071e_6309, - 0x73ff_1119_546e_4400, - 0x37b5_a0a3_1732_6eb9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x71fb_d7b6_ec81_457b, - 0xa3db_880b_8ebd_e2f8, - 0x6fae_9d5e_77f7_7282, - 0x3922_33fe_aae5_f4d8, - ]), - pallas::Base::from_raw([ - 0x10db_938c_736f_6d80, - 0x343d_e723_56d1_9731, - 0x78b3_c37a_9d5d_a468, - 0x1617_300e_9160_0a2b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x424a_8877_5bac_1aa3, - 0xa8c8_36e8_7e8c_c0e5, - 0xc371_2374_03fe_9264, - 0x26f1_c98a_7a66_a30e, - ]), - pallas::Base::from_raw([ - 0x51a3_b36e_0db2_44d9, - 0x3eea_1d88_887d_e035, - 0x25cb_a902_d51f_f3da, - 0x36e7_0b90_4548_6468, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2728_fdb5_0b61_d1c1, - 0xcb71_a070_6ed1_1521, - 0x0509_29be_1d07_ab6f, - 0x21d2_7b62_2b7e_c84c, - ]), - pallas::Base::from_raw([ - 0xe13a_1cfe_7ee0_cf80, - 0xae30_8c36_a8e1_6416, - 0xed99_fb9e_9ce0_6d84, - 0x34a7_cab8_9803_1842, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfdbb_35ef_3aeb_c28f, - 0x834b_2806_1e44_0e87, - 0xbd65_25e3_6607_150d, - 0x183c_3d98_886a_d987, - ]), - pallas::Base::from_raw([ - 0xefb2_e06e_bf3d_5ba9, - 0x8d2e_e783_371a_b957, - 0xca32_80bd_b0c7_07f8, - 0x1de1_6b88_08f5_68f0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x786d_bdc0_924e_ec5b, - 0xe210_6c1c_189c_4147, - 0x7a4b_a8ab_bb17_0ad5, - 0x27d2_5cca_176a_5ec8, - ]), - pallas::Base::from_raw([ - 0xbccc_549c_6a1a_38e3, - 0xffe7_d383_bcd5_f8c1, - 0x1e45_0633_f24b_c870, - 0x346e_0709_ab95_21c1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5e73_f44f_3cca_5a3e, - 0xa965_c7a3_dd6c_7e35, - 0x3ec6_eee4_1149_89dc, - 0x1083_dfea_d4be_6b07, - ]), - pallas::Base::from_raw([ - 0x294d_4b25_9ddb_cf9c, - 0x7ace_974e_8045_61c6, - 0x507e_843f_4d68_c0cd, - 0x0a2d_8f78_fec0_e925, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf05e_c78b_2d6d_b205, - 0x74ed_d93b_8da6_3fc5, - 0x2d14_ee3d_c962_e1b5, - 0x3d96_e779_a206_75e2, - ]), - pallas::Base::from_raw([ - 0x74b0_20fc_2442_53df, - 0x5e67_731c_8a84_c1e5, - 0x76b9_572f_ee83_9cca, - 0x20ec_4fc7_e584_793d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x618d_3a50_bf2f_9c6c, - 0x2c9e_12ad_d09d_53c9, - 0xc40e_e12a_9971_a79c, - 0x2193_5e49_8cdb_4af2, - ]), - pallas::Base::from_raw([ - 0x526d_a471_4847_0d71, - 0x91b6_ada6_7e06_44fd, - 0x0ed3_0fc8_f6f1_8eb0, - 0x3339_a9d2_a7ce_d503, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5083_6ba9_ebe2_c4d2, - 0x1a97_6e48_cf4e_b89f, - 0x8704_3936_d76c_17ad, - 0x29af_2213_94b4_1751, - ]), - pallas::Base::from_raw([ - 0xf644_cd10_7f09_50c3, - 0x8884_71c3_01ea_94bc, - 0x8937_b2cf_3be6_5258, - 0x2647_20f5_e202_98cb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x95c7_2972_4e5a_6bdd, - 0xcc55_a697_2f1e_750b, - 0xb9b7_90c3_f913_c375, - 0x1ddf_0c2a_bcd6_126c, - ]), - pallas::Base::from_raw([ - 0xb261_7fe7_e51f_68c2, - 0xaf6a_f700_27e2_8cd1, - 0x22e8_5bb5_4a2c_2e77, - 0x04af_6cfe_6abe_1c31, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8ea6_8c4e_c05f_e2f3, - 0x0155_d4ad_ba7b_31ef, - 0xa5ea_74df_1d84_ead9, - 0x2523_0890_0a38_e897, - ]), - pallas::Base::from_raw([ - 0xa64a_883e_1163_2151, - 0xd107_d743_2477_f8ff, - 0x0daf_49f8_7158_36fc, - 0x3e81_0b63_687a_6435, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb8e8_f1d3_9d83_1327, - 0xeefd_129a_2f23_fb16, - 0x5ce7_95e9_417c_4b58, - 0x3579_508c_8c75_a170, - ]), - pallas::Base::from_raw([ - 0xe1b9_574c_e4b2_5e71, - 0xa37c_b44d_e87e_b515, - 0xf492_24b9_9d55_8ab8, - 0x09c4_997f_9e5b_f623, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5010_3905_13ee_f907, - 0x4719_6aaa_d39a_a899, - 0x54de_851b_e709_1a02, - 0x2784_a297_4957_e70e, - ]), - pallas::Base::from_raw([ - 0x24ee_caef_9885_dfab, - 0xd189_3009_5f27_f678, - 0x1fd3_6af4_15d9_091f, - 0x084b_ec81_b437_8e44, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb19f_74b4_e493_4f13, - 0xe3a0_e81b_f084_e23c, - 0xafb2_ef1f_aea3_231b, - 0x0281_e846_acc0_87ee, - ]), - pallas::Base::from_raw([ - 0xd975_d00f_7393_542f, - 0xf8ae_f91e_ec9e_59d0, - 0xd285_8c11_b9c5_280c, - 0x3b00_5d52_5add_f883, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7b66_98ea_e221_f3ec, - 0xaa52_8c99_81e3_ef9d, - 0x8594_5e1a_bb14_af22, - 0x005a_5676_d642_01e0, - ]), - pallas::Base::from_raw([ - 0xf403_21aa_0a31_021b, - 0x4b9d_4172_43e9_01ce, - 0xdcef_30a1_fffd_6fe4, - 0x115c_5d90_17e7_5c6b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb50b_a31a_29ee_735f, - 0xe087_4244_55be_9f05, - 0x4b3d_5356_7f34_bb41, - 0x3592_dfa2_ef73_8fd5, - ]), - pallas::Base::from_raw([ - 0x5eea_a2b4_5eaa_ac7f, - 0xba64_a158_5df4_da51, - 0x64f2_1e18_e2a1_a18b, - 0x2744_472c_60b3_f4f4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1ab7_7d4c_5a3a_d076, - 0xecef_342e_138f_55a9, - 0xe581_d4cf_1cbd_f93b, - 0x0ea1_f359_9f7d_3d5c, - ]), - pallas::Base::from_raw([ - 0xfc25_aea5_9fe3_c15f, - 0xc8eb_d71a_f44f_64e0, - 0xaa6b_2e54_38b5_a5ed, - 0x1cd7_d950_1f7e_fb20, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb92c_cc75_d2f6_7ef9, - 0x7c8c_7050_bb4b_c76c, - 0xae06_dd71_3e7c_b705, - 0x12e7_b66e_0a99_9a6f, - ]), - pallas::Base::from_raw([ - 0xce73_174c_46de_1a90, - 0xf233_8c5c_dce6_3624, - 0x7311_d0f1_6107_caba, - 0x07c5_3cd8_2f6e_3bc1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x679f_68cb_0663_880c, - 0x22eb_3ab9_b8f2_c733, - 0x8c9a_cbf2_ee17_7ad5, - 0x0215_4cc2_96b2_c905, - ]), - pallas::Base::from_raw([ - 0xf9f8_7298_bb53_de4c, - 0xdf36_8c20_1ec4_1690, - 0x4964_d682_c5ab_2e0e, - 0x1c40_fd23_1fb7_cd69, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2119_8bfc_8956_b75d, - 0x991d_620b_35a4_b565, - 0x71ea_c445_814e_d86d, - 0x28c7_9db6_4739_3f32, - ]), - pallas::Base::from_raw([ - 0x14ce_2060_ae17_f113, - 0xbe45_fdc5_1246_fc50, - 0x8e1c_4319_10ac_be73, - 0x1312_53c6_1783_912e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x026d_767e_1005_dd37, - 0x0759_23a2_1a64_428a, - 0xeeae_4507_b79d_6a0e, - 0x37d5_760d_8173_256b, - ]), - pallas::Base::from_raw([ - 0x5214_d99e_936f_56c0, - 0x26a0_b50e_6731_2f58, - 0x3dfa_7029_6ec1_d238, - 0x170c_0df2_5f28_1a90, - ]), - ), - ( - pallas::Base::from_raw([ - 0x397a_3bcb_ba4d_bd68, - 0xf577_2816_06d1_1af5, - 0x0814_30b5_220c_1e6e, - 0x04ee_cac4_45e3_73c9, - ]), - pallas::Base::from_raw([ - 0x3de6_619d_1a4f_65d1, - 0x680e_a92b_eb54_6b7a, - 0x01d4_31ba_19fc_51bf, - 0x070c_35d1_13a7_0730, - ]), - ), - ( - pallas::Base::from_raw([ - 0x327a_43da_e34b_c50b, - 0x9227_b80c_f9ef_6317, - 0x207b_c331_727a_65f5, - 0x2f5b_368e_9519_0487, - ]), - pallas::Base::from_raw([ - 0x59da_f9c7_044b_8bc1, - 0x1ab3_944a_4c78_5084, - 0xb716_6a13_ed9f_a130, - 0x2165_91e0_c300_e0b9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5fa9_1288_f21f_b95f, - 0xbbd2_13a8_837b_4744, - 0x0a4a_3270_6938_5d8c, - 0x2db9_f193_d5c5_c9c1, - ]), - pallas::Base::from_raw([ - 0x7bbd_9898_1a1a_9bff, - 0x4ad2_4d15_ef54_060e, - 0x8824_c7a3_915e_035e, - 0x04ea_a03b_8152_e316, - ]), - ), - ( - pallas::Base::from_raw([ - 0x718e_5117_e211_d00c, - 0x6820_04a7_e806_2c61, - 0xe14d_1252_02ee_8806, - 0x35d6_bbce_17ad_d8be, - ]), - pallas::Base::from_raw([ - 0x6d50_9095_573e_853e, - 0x9be9_bb45_bd5d_ff54, - 0xd142_d615_c2b2_e50a, - 0x0d21_45dc_b049_831c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8fe4_32aa_3577_54fb, - 0x4766_8513_94d3_898b, - 0x776f_85d0_c89d_75c4, - 0x1144_091e_1eb0_8134, - ]), - pallas::Base::from_raw([ - 0x398f_9036_dcb4_9364, - 0xaaa7_1f19_dd46_1c3e, - 0xda24_0bf3_7b5d_659e, - 0x1c09_8238_7bf2_3870, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6570_c993_e75f_d9fd, - 0x5595_d3ee_e187_37f9, - 0x0629_32a7_cec7_4b58, - 0x0202_816c_bc84_b4fa, - ]), - pallas::Base::from_raw([ - 0x1df0_9e9c_5fb9_da74, - 0xb847_f271_42f4_50ee, - 0xf499_343b_da75_dca6, - 0x1781_323b_7425_6726, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5aff_0d37_7f88_51d2, - 0x7353_2959_e87d_bfb3, - 0x634c_476c_fbb7_1c96, - 0x11df_8818_cefd_7683, - ]), - pallas::Base::from_raw([ - 0x35ac_fac4_4577_543d, - 0x5c8f_db44_1658_61fc, - 0x4b19_0f39_cf3c_fb30, - 0x27dc_c868_42a3_d6b8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x706f_36b5_bce1_6334, - 0xed63_bc8e_d67e_8f0d, - 0x5389_8211_d9a1_148b, - 0x084e_1a66_ed1d_9f9a, - ]), - pallas::Base::from_raw([ - 0xa9e0_e924_9383_6ee5, - 0x54c4_d664_8f95_0861, - 0xe2de_beff_8d23_4306, - 0x2038_1989_0b48_2b10, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3afe_f81c_330c_8ad7, - 0x8f31_b38b_3cb7_7f46, - 0x0be8_a9e3_b4bc_f237, - 0x09ce_729b_7917_ae58, - ]), - pallas::Base::from_raw([ - 0xd199_ef86_4732_8de0, - 0x7b03_6744_a3f5_8144, - 0xa545_b8ef_580a_7994, - 0x1074_1c11_9769_07ab, - ]), - ), - ( - pallas::Base::from_raw([ - 0xcc3d_d69a_86da_b9af, - 0xd4e7_5a09_d52b_0b3e, - 0xe8ad_091d_8b10_7f75, - 0x2b43_cc2e_f8d8_f01e, - ]), - pallas::Base::from_raw([ - 0xbd14_0c51_b03d_0f63, - 0x1006_923c_4bcf_285d, - 0x7221_7a99_120c_7911, - 0x012f_2b79_8f53_056f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0beb_949f_a313_486c, - 0x0d5c_e4d6_059d_abf8, - 0x4991_4b41_76f5_2b16, - 0x1a14_5dc7_97b5_eb4c, - ]), - pallas::Base::from_raw([ - 0x9b0a_fb2b_b5fb_dc02, - 0xb72e_d001_8b32_e67e, - 0x8dc1_f4ac_e7f6_40a1, - 0x0a03_99e6_e2c1_35e8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x24e5_3cfc_0a85_3bd6, - 0xc691_a440_5284_538a, - 0x285f_8587_a2ca_3f67, - 0x0049_29ba_589a_b1ac, - ]), - pallas::Base::from_raw([ - 0x47d0_0f51_b59e_11b5, - 0x034c_e6c5_4f24_d018, - 0xcdfa_fdf5_9352_2277, - 0x1740_01a4_cd80_e459, - ]), - ), - ( - pallas::Base::from_raw([ - 0x05f2_fba6_88e4_64cd, - 0xcc07_4f11_8393_de4e, - 0x8cd3_84d1_2d3a_f616, - 0x082e_c561_65bd_c5db, - ]), - pallas::Base::from_raw([ - 0x0ff4_d463_cdf6_1438, - 0xb9d4_8513_1297_820b, - 0x577a_ab49_6011_7b6f, - 0x189f_caa5_6f47_de49, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6a66_f234_459d_9c05, - 0x52b3_b4e7_046a_0ca2, - 0x5f0c_f5c7_ac0b_8673, - 0x2d4d_378b_8ab7_0f4d, - ]), - pallas::Base::from_raw([ - 0x25e8_c3f3_463b_7de3, - 0x1db7_6493_b323_dd0c, - 0x96a6_cbc7_69f8_7c7f, - 0x0433_09e4_d57b_65e1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xcf05_4d04_c520_e0a0, - 0xd540_edc7_1ca1_3af1, - 0x4993_044b_77dd_0400, - 0x1b0e_a9cd_b77e_ff99, - ]), - pallas::Base::from_raw([ - 0x6928_0ea8_321c_cd3b, - 0x72ab_b895_a1a8_f03d, - 0xf3d3_938f_2c87_7734, - 0x1270_1769_ae73_6bcf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3e52_a2f0_ad5f_a12d, - 0x4418_5ba6_38bc_b064, - 0xef8b_d3ef_5bf1_6622, - 0x3ef5_5ec2_16b2_28bf, - ]), - pallas::Base::from_raw([ - 0xb82b_cb14_f2f4_9c05, - 0x1ecb_aee5_356e_0958, - 0xd850_681c_85cd_d83a, - 0x1328_7a30_a3cd_c18a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x76c9_1531_675b_e4d2, - 0xbff3_efc0_f5e7_a3d5, - 0xbf16_1feb_c704_2e5a, - 0x0033_a85c_5e3e_212d, - ]), - pallas::Base::from_raw([ - 0xb3fe_295f_735b_1607, - 0x4c07_169f_2f85_8811, - 0x53af_cd3d_e314_e24b, - 0x33dd_2f1a_9d46_44fc, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8e41_0696_97e7_8171, - 0x26ff_1208_32bf_c795, - 0x0bd7_0aa4_1196_808a, - 0x3ae0_f344_40d2_99f5, - ]), - pallas::Base::from_raw([ - 0x2474_b70b_2dad_669a, - 0x4603_66a7_e898_713f, - 0xb369_5b24_0bd9_aeba, - 0x3c74_bb6d_465e_e2ea, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6e89_42a3_91dd_c2ea, - 0xc38a_28e1_fcf3_fba9, - 0xeb31_2651_5a79_f178, - 0x341f_5e3d_2d3a_415b, - ]), - pallas::Base::from_raw([ - 0x7449_ce64_375e_4ca8, - 0x0602_745a_0fb3_6d33, - 0x2958_f891_d370_9055, - 0x09b2_2212_2dc8_e043, - ]), - ), - ( - pallas::Base::from_raw([ - 0x06b4_c662_7f86_1a17, - 0x6892_8a55_09f7_1a30, - 0x0f16_7e0c_216f_c514, - 0x3d3a_af95_d02a_5c26, - ]), - pallas::Base::from_raw([ - 0xf1df_9dff_4331_9bc6, - 0x3728_ab5b_c9a6_f755, - 0x8c73_0235_2ed7_3f95, - 0x3f65_6e0c_c790_2ba0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9f45_5904_d062_3f0a, - 0x7823_029e_72a6_7bb6, - 0x99fb_f22c_510a_2be4, - 0x2e85_df2d_4723_8ae7, - ]), - pallas::Base::from_raw([ - 0x327d_317b_e878_66e3, - 0xa45e_75ef_95df_3e94, - 0x7b1a_c76d_c402_0f49, - 0x3a60_fbcd_a37c_815e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x17df_a08e_e2a4_a5c2, - 0x0d37_fdbf_7f39_3cc8, - 0x5f65_0aee_69a3_3aab, - 0x21cc_cd3f_512f_6fef, - ]), - pallas::Base::from_raw([ - 0x5501_f47b_1934_3bbb, - 0xc629_25da_839b_5703, - 0xe869_5dff_4ac7_98db, - 0x2616_31c0_e0e8_b1b3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x11b8_7af9_9e00_27df, - 0xafd7_bf48_d6fc_a4f1, - 0xd540_1aff_42f4_c233, - 0x158d_6245_8d40_37b2, - ]), - pallas::Base::from_raw([ - 0x8b6f_fd47_6243_eb36, - 0x6c6d_2aa6_425d_192e, - 0x9148_af15_de60_624c, - 0x3e87_9938_3886_00a0, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfe07_2c77_e4e1_e7c2, - 0x93d8_3c8c_e662_68de, - 0x619f_5102_29bc_739b, - 0x3a66_5f24_c02b_af59, - ]), - pallas::Base::from_raw([ - 0xc557_f198_58c8_a876, - 0x7731_9895_7381_1af9, - 0x6b7d_918d_995d_93e6, - 0x307f_067d_c98e_9636, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa436_5475_6a68_c675, - 0x88f2_f299_794f_3553, - 0x7f11_45b8_74ae_62c7, - 0x0dee_f81a_0f27_b481, - ]), - pallas::Base::from_raw([ - 0x993e_47cf_7f5e_cf8c, - 0xe810_5d2c_1b5e_0447, - 0xcaad_b923_1a1d_ac82, - 0x147a_8969_4b2b_e230, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4723_e366_ae1e_6184, - 0xee04_327f_d719_ea9b, - 0x24db_be73_e152_f27d, - 0x2100_9976_6171_438d, - ]), - pallas::Base::from_raw([ - 0xefe4_8e4e_9b94_1267, - 0xacb1_8986_fab0_a084, - 0x7b10_5663_ae11_ea5e, - 0x274f_221d_771c_400c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5cb8_1790_8657_3d1e, - 0xdd05_63de_2edd_ddc4, - 0x78ba_e557_b388_ffeb, - 0x1a84_b9f1_4ad0_365d, - ]), - pallas::Base::from_raw([ - 0xd1da_bfb8_e966_236a, - 0x57d3_fa91_cbd6_0cc8, - 0xdc92_8096_0248_333a, - 0x376c_21b4_5247_997f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x13f0_c07a_dc21_f7b1, - 0x2a5c_69e9_05fe_854b, - 0x0573_d14d_1d7d_da4f, - 0x193e_e5da_b674_a49d, - ]), - pallas::Base::from_raw([ - 0x7fa1_74ca_714a_4b90, - 0xfe21_aa2e_52a5_a793, - 0x69dc_b536_0f5b_c791, - 0x1b16_b237_03d7_e26c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xeaf6_6865_27d4_b8e6, - 0x1aa0_aab4_2666_1fcf, - 0x1aa7_9baf_a2a0_5e73, - 0x3589_722c_8ec2_4085, - ]), - pallas::Base::from_raw([ - 0x4142_0491_d747_fb8f, - 0xc20b_63f7_728a_bf57, - 0xf61d_1974_ab2a_d20b, - 0x3a16_a2b3_28cd_a978, - ]), - ), - ( - pallas::Base::from_raw([ - 0x479a_9ac8_e884_e011, - 0x504e_93b0_cd03_ae26, - 0xc711_9e1f_1319_e977, - 0x3793_11e7_db77_15e7, - ]), - pallas::Base::from_raw([ - 0xf05b_ef48_6578_ec58, - 0x05b9_b52f_deca_50dd, - 0x6c92_c4fe_9bf6_95a2, - 0x2ae6_65e4_8ad7_556d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9418_f007_3a11_5039, - 0x84ba_f7e6_293c_aa1d, - 0x4be5_7bb5_6c37_e8e8, - 0x2e01_0c6c_ba9d_2f9e, - ]), - pallas::Base::from_raw([ - 0xb30c_63c5_793a_1373, - 0xc2a7_a868_e4da_a692, - 0x789f_e67b_b71f_b6dd, - 0x2812_c192_3126_8e2a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8a3e_8b6d_d6fb_bcb6, - 0xfab6_9586_3583_cbe2, - 0x3d2e_3c47_a4bf_b5a1, - 0x1715_0e76_b351_e99d, - ]), - pallas::Base::from_raw([ - 0x2ea8_22fa_65a4_7757, - 0x1f2f_e64a_c655_741c, - 0xd1aa_205a_f5ac_9570, - 0x27cf_dd88_0836_c8e9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7d30_5f29_822a_7979, - 0x8082_4fc1_a364_96e2, - 0xf73d_1cf4_c77a_0f4d, - 0x1c9c_be3c_6a19_26be, - ]), - pallas::Base::from_raw([ - 0xaa17_af8c_1c76_1823, - 0x09d0_a290_baf6_e926, - 0xf61c_06f8_b5d6_c22b, - 0x172f_1a6d_fc32_d9cd, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5ad3_8743_b520_2fb9, - 0x083a_2695_50be_40d2, - 0xb911_1803_3f67_cde3, - 0x2846_f462_30cf_b810, - ]), - pallas::Base::from_raw([ - 0xe223_b5e7_e937_c54c, - 0xf2c5_77fd_b08b_3f21, - 0xb6c1_652b_7505_a7d3, - 0x2c8f_a498_2e60_e130, - ]), - ), - ( - pallas::Base::from_raw([ - 0x56bb_e185_4175_95f3, - 0xecc1_0053_9407_c202, - 0x90a5_c415_7630_fd2e, - 0x1f33_8ef2_6410_ce20, - ]), - pallas::Base::from_raw([ - 0x1a3b_5459_1a56_b7d4, - 0x2711_c42b_cfc8_bd25, - 0xb313_42d6_a462_1965, - 0x1e04_5727_6c6a_be28, - ]), - ), - ( - pallas::Base::from_raw([ - 0x33f0_122d_1fc2_e9d6, - 0xbbaf_07e2_6d0d_b5f4, - 0xada4_e1db_90f2_0928, - 0x320d_78d3_7e1f_9b51, - ]), - pallas::Base::from_raw([ - 0x6d4f_fe2f_b80e_79f9, - 0x1697_46f5_0160_9c4d, - 0x9c94_aa69_371f_e117, - 0x08ff_a47d_8297_7661, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0eed_415f_7d55_1715, - 0xf420_3b98_aa11_457b, - 0x9053_f3d5_4476_0afb, - 0x02c2_03ba_dea2_76a1, - ]), - pallas::Base::from_raw([ - 0x55d7_024a_e842_a5af, - 0xb58c_03ba_9deb_cd2f, - 0x0c6b_c8b6_ceaa_42b5, - 0x3b4e_7fab_6e35_5c3e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xea9d_81f8_6a0d_dbe9, - 0xce0f_2809_3257_e6f1, - 0x0039_3b64_fd52_ff04, - 0x2942_5821_8d23_ef24, - ]), - pallas::Base::from_raw([ - 0xbb7f_710f_9517_dc5b, - 0xb9db_1453_43ab_48ca, - 0x94cd_60e3_1fe8_3451, - 0x2be1_7ce0_f798_be8b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd971_ee8b_071f_3aa2, - 0x6542_046f_2f21_6648, - 0x7011_a0b4_c4c5_2feb, - 0x176a_75e4_305d_c7cb, - ]), - pallas::Base::from_raw([ - 0xb8fe_680b_ce75_ae24, - 0x8549_cbf6_c3d2_7b44, - 0xa8ee_92a7_6a40_c587, - 0x09e6_b0ba_013d_f131, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb80b_9e97_64fd_da65, - 0xb0c0_b411_0bc5_8a2d, - 0xac1b_b1a0_c6e1_5c55, - 0x36a4_4d41_d37a_70e8, - ]), - pallas::Base::from_raw([ - 0x6a77_efb2_81aa_e72f, - 0xc578_8686_9b58_faa7, - 0xab74_33bd_7e33_68dc, - 0x1792_ad2e_7f54_a000, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8792_f6ef_0395_a9a7, - 0xd375_7f3d_66c2_7229, - 0x6949_e876_d5c7_9010, - 0x176c_f116_0c7f_8ba7, - ]), - pallas::Base::from_raw([ - 0xf0f5_d8f0_a98d_c2bf, - 0x4118_e09e_ac6c_d9e9, - 0x4ed1_51e4_5f97_f657, - 0x13e7_3756_26b8_54e4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbccd_3257_f3c2_06d0, - 0x3139_8eae_f991_a342, - 0x5a2d_4414_2fa3_5a6c, - 0x3cef_bcc7_13f6_3152, - ]), - pallas::Base::from_raw([ - 0xc806_3b97_017e_00ab, - 0x5e20_fdd5_44b5_acc3, - 0x6cce_c0f6_ef8f_18cd, - 0x14ee_4b77_ec6a_bfeb, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc096_2238_58db_eab3, - 0x5c0e_61b0_db10_ef29, - 0x6c9a_f1ed_8acb_1da4, - 0x3f76_fe73_c425_d939, - ]), - pallas::Base::from_raw([ - 0xdad4_82e8_b280_556f, - 0xc3f4_06de_7fdc_c54e, - 0x37ca_88b8_1d36_54b9, - 0x0261_f776_7244_a4d3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7e1c_ca9a_a12a_8efe, - 0x948b_62a8_c522_ec9b, - 0x9dbb_049b_218c_3df8, - 0x1efd_3a6c_d255_af78, - ]), - pallas::Base::from_raw([ - 0xa4b5_0f75_4d65_0a1f, - 0x25b7_6c86_a75e_2c13, - 0xfd6c_6887_ef4d_1d53, - 0x0a59_0bd3_71bc_51f0, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdcee_cea8_b8d0_d650, - 0x4f2d_8b8d_6a29_f2d4, - 0x43d0_528f_eaf9_11eb, - 0x2404_4c52_546c_2b52, - ]), - pallas::Base::from_raw([ - 0x96c3_facd_1cf0_d9f6, - 0xca63_6712_9f50_6ad8, - 0x2f85_d005_fa5f_9b5b, - 0x069e_153f_9896_c130, - ]), - ), - ( - pallas::Base::from_raw([ - 0x686e_8212_4c61_d957, - 0xc7aa_9bde_a486_649e, - 0xd3c2_91e0_d4a3_7a8d, - 0x0107_e2e3_2c5f_28f3, - ]), - pallas::Base::from_raw([ - 0xab0b_45df_c3d7_591b, - 0xf7b5_854a_710b_f63d, - 0x544d_c8f1_2e0c_26f3, - 0x2d9b_95a7_30cc_ea85, - ]), - ), - ( - pallas::Base::from_raw([ - 0x513d_33c2_95ce_56f0, - 0xbd2b_2fdd_7fd7_7031, - 0x5d4f_47fe_09e2_e031, - 0x2f94_4842_7b80_54b4, - ]), - pallas::Base::from_raw([ - 0xdf6f_d665_d36a_7467, - 0x5dc9_191f_2fea_6b07, - 0xeca2_ef63_7140_6422, - 0x0171_50c0_96da_f72c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x367a_1d4f_87ce_2858, - 0x9d54_5c07_8137_cd19, - 0xdf1a_2072_738f_3bfd, - 0x114e_4120_52f0_25d4, - ]), - pallas::Base::from_raw([ - 0x18fd_28df_bf66_d5ea, - 0x8bbd_77f0_f949_9a75, - 0x6362_4f99_f3e8_453b, - 0x2780_edfe_8a38_8449, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7402_3082_0ea9_5ad4, - 0x63b2_7be5_3550_2ffd, - 0x91dc_cb3e_fbe2_60b6, - 0x25e2_bfb1_0f32_3477, - ]), - pallas::Base::from_raw([ - 0xadc0_3a71_39b4_094f, - 0xedf8_c60f_b4d1_c2bb, - 0x6911_0947_b702_9fcb, - 0x01f4_2fe0_a850_8065, - ]), - ), - ( - pallas::Base::from_raw([ - 0xff2d_cd62_e596_b4d0, - 0xc7d3_1ad4_5af5_0fc8, - 0xa0bf_73fa_b1a6_63fd, - 0x01c5_4695_7e3e_a005, - ]), - pallas::Base::from_raw([ - 0xefeb_aacf_938f_6779, - 0x6986_3f6e_07de_7291, - 0xc06e_8e67_ade6_e796, - 0x164b_abe7_7966_9ae9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1c33_6e51_b527_8fe0, - 0x830f_0267_88b0_060b, - 0xe589_fe8a_6136_cdf4, - 0x04e2_bb36_ec30_315b, - ]), - pallas::Base::from_raw([ - 0xcde6_5cb5_9334_5bfb, - 0x10a1_fb83_4287_f5f4, - 0x37c7_a20c_4619_28c1, - 0x2adc_5a85_4126_6b62, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3932_ba35_42e2_61ba, - 0x3a1e_399e_82de_4dcd, - 0x3a5f_6dff_03ac_3c73, - 0x2cbd_15f4_53d9_16a9, - ]), - pallas::Base::from_raw([ - 0x2425_a35f_a98d_8937, - 0x0a66_a2d3_5d9f_588c, - 0xf832_8c5a_3951_852b, - 0x0848_6f66_b4a2_dd55, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa4c3_8380_3a4d_9564, - 0x109a_bd0c_31eb_54f2, - 0xa83d_57b4_b012_a211, - 0x3949_c80c_4cfd_3f85, - ]), - pallas::Base::from_raw([ - 0xfdcd_3f0d_1ef1_9e40, - 0x47f8_5477_4692_b481, - 0x60fc_0e1d_252f_8607, - 0x1547_2a08_45c3_dc19, - ]), - ), - ( - pallas::Base::from_raw([ - 0x042e_596d_48e5_7baf, - 0xd9d7_3041_cb15_f628, - 0x65ec_a378_4e88_0916, - 0x059f_7f0d_27e9_01da, - ]), - pallas::Base::from_raw([ - 0xd37d_77d4_4cf8_b443, - 0xbfa1_72a6_7d41_76ec, - 0xd8c8_b761_2524_7b4e, - 0x079b_6488_5c2d_24f5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd29f_0703_a4b5_6dbe, - 0x75e2_6aa8_956b_46fc, - 0x84a4_49e7_02e2_2806, - 0x38bb_f1d6_ceac_121c, - ]), - pallas::Base::from_raw([ - 0xc772_1a73_3066_b6d1, - 0x1737_55f3_b53b_ec06, - 0x3c2a_bd62_3e1e_2c21, - 0x088d_d43b_6366_0116, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa116_6f77_055a_8bb6, - 0x6385_2d8c_5889_8da4, - 0x34b4_f4cd_754b_7717, - 0x1526_aa2d_f3e7_515f, - ]), - pallas::Base::from_raw([ - 0x4085_c51a_2657_e4b8, - 0x9679_5ea4_4624_8645, - 0xc804_03a1_e3d6_3998, - 0x199c_c2b0_2132_4b08, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa52a_db5d_d168_77c2, - 0x6b03_f922_0b52_af2e, - 0x7fc8_01e8_b4ef_22bd, - 0x12e5_67c2_ec81_2f1d, - ]), - pallas::Base::from_raw([ - 0x0309_4014_a4e8_c20b, - 0xe7bf_0cd6_a200_a8cc, - 0xc608_65fe_fb5b_94ea, - 0x0993_1445_3f68_41ac, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbfd7_fd57_8b6f_75d8, - 0xf07e_f86e_d33d_296a, - 0x5054_c978_d48e_ee12, - 0x0b3d_76cb_4f6f_c43a, - ]), - pallas::Base::from_raw([ - 0xbef7_625a_4eed_90eb, - 0x1f8d_bade_22fe_73f7, - 0xc960_ab94_3ae5_1bfe, - 0x0858_b2d8_865c_973e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe2e4_3c37_843a_04dd, - 0x28e9_8a1e_6966_e7c0, - 0x6ac4_304f_d629_f5a1, - 0x2dfc_f1e1_ec0c_32fb, - ]), - pallas::Base::from_raw([ - 0xbd67_15f8_99d0_7f6e, - 0xcb85_5a99_89cc_47ff, - 0xdd2d_2426_6872_35c4, - 0x1968_0ec6_a3a3_fcb8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa5ab_b96e_1f94_1076, - 0x51b5_b451_b97a_0268, - 0xd7e0_dc4f_58ed_e375, - 0x2bee_18a5_f76d_7e63, - ]), - pallas::Base::from_raw([ - 0xed7d_80be_441d_d7b4, - 0xa4c2_d30a_3c19_cf3b, - 0xac4f_739b_2e1f_91ed, - 0x3562_48da_e389_3d81, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7c79_fc8c_4dcb_a1c0, - 0x8162_1c35_b958_c1a1, - 0x0a41_6e19_3265_f04d, - 0x009e_4848_45e1_7f41, - ]), - pallas::Base::from_raw([ - 0x712d_9394_ab35_ebd1, - 0x6312_e11e_d8e1_49fb, - 0x84af_9933_77e5_1ade, - 0x3f42_3c6c_cd36_1dc9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf371_6e56_7f23_b1e1, - 0x538f_3c4d_6a0d_4994, - 0xaf2a_6e2a_b089_32ec, - 0x2f3e_49c7_37a2_98af, - ]), - pallas::Base::from_raw([ - 0xc5eb_afba_dcc3_18cc, - 0x64f2_6b4c_6339_fd3d, - 0x5ef0_9554_fa27_b6cc, - 0x21dd_5ec1_51e4_e135, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc382_c4ea_f9e5_4b3c, - 0x47ea_f27a_b13e_c143, - 0x2a6c_3775_caaf_400f, - 0x08d1_cba6_65ee_26df, - ]), - pallas::Base::from_raw([ - 0xfdf2_f10d_f382_cd25, - 0x812b_4d72_4045_d2f3, - 0xc1c3_32e2_6422_084b, - 0x26a4_9ea4_f176_8cd3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe132_91ea_94e5_9353, - 0x7d69_5680_fc7b_82e5, - 0xada6_bc9f_fcd7_fe02, - 0x2ad4_e94f_ac41_1335, - ]), - pallas::Base::from_raw([ - 0xf166_8557_d845_98ef, - 0xb6f8_78df_9c3a_5c6a, - 0x0993_e2b9_0073_8ccf, - 0x09b0_6867_4885_ae31, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4161_dea7_2c51_a176, - 0x147b_e228_82c1_8e17, - 0xf47c_b827_d4af_8bcd, - 0x30a0_5ec4_90a9_aa33, - ]), - pallas::Base::from_raw([ - 0x3209_f6db_3ea8_a841, - 0x1d9c_06c6_ea2d_6905, - 0x6afe_34c8_ac39_628f, - 0x35f8_03ed_ac2f_acde, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbe8d_dfdb_83eb_b5ed, - 0x185a_8a55_57ab_07c3, - 0x109c_99b1_64d5_ebb0, - 0x0243_40be_c0e7_c4f7, - ]), - pallas::Base::from_raw([ - 0x6b51_37b6_6b10_0439, - 0x6f2e_00fe_1a1d_1ecd, - 0xe2af_ff62_7ab4_5f97, - 0x31d1_3ebc_0bad_4368, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe52c_00c2_77e0_805b, - 0x289a_6cfc_00e4_613e, - 0xba6d_64e6_b80e_af43, - 0x028d_bb3a_a2eb_10e1, - ]), - pallas::Base::from_raw([ - 0xb5e0_5d84_b2c2_af71, - 0x8ca8_19c8_ed2d_d4b4, - 0xbf23_1285_894e_181d, - 0x13dd_55ec_af42_2820, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7cd5_9e64_f479_5578, - 0xb2e4_8301_4dad_1d12, - 0x69bc_3333_f3ae_7a7b, - 0x1d8b_bee3_8e56_ce73, - ]), - pallas::Base::from_raw([ - 0x62ed_e032_93f3_6d8e, - 0xe0ff_b670_42fd_4d90, - 0x28e5_b97c_3c9d_1811, - 0x1a6e_4ed7_56c2_b230, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0828_358e_7ca1_8645, - 0x4e14_04d0_c831_fc41, - 0xa2d9_42ef_1ded_82b9, - 0x2fb8_9978_33e6_41c9, - ]), - pallas::Base::from_raw([ - 0x1fa1_883b_1222_e351, - 0x8a92_e672_a65c_2998, - 0x2c95_70ae_0ce3_66ac, - 0x2182_c430_2f94_8f79, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7137_1420_909c_4455, - 0x79a8_72fa_e5ff_4895, - 0x64c5_8a11_259d_2d60, - 0x1b4a_243f_2c40_9d0b, - ]), - pallas::Base::from_raw([ - 0x24b7_097b_3e5c_77cf, - 0x103c_bbe4_8a2c_d3c1, - 0xfb53_ff35_bd2b_0ac1, - 0x3520_075c_da2f_93c3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf70f_d61e_7311_192b, - 0x663f_6658_1f78_66bb, - 0xb223_dcf3_6099_76c2, - 0x22c3_ced3_c628_b166, - ]), - pallas::Base::from_raw([ - 0xc390_e15b_4656_71ea, - 0x839c_7a74_12c7_d85b, - 0x9eab_c165_478d_f2c2, - 0x0426_245e_279f_b951, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf32e_587b_08ac_a16a, - 0xef0f_0954_a0d1_18d6, - 0x663a_0d0e_0f93_711b, - 0x3ba9_d989_09c2_1586, - ]), - pallas::Base::from_raw([ - 0x67b0_fe69_78fa_f39b, - 0x4365_7c97_5d17_8817, - 0x3634_3954_9a26_d391, - 0x2912_61a5_3c05_d61d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb213_f8dc_16d9_4935, - 0x6c08_5bb9_8b3f_b3d8, - 0x3c8e_7712_a323_61cb, - 0x1186_5328_9691_8dbf, - ]), - pallas::Base::from_raw([ - 0xdd0f_6a6f_c395_0461, - 0x402e_cdec_f30a_8b9a, - 0x63c0_5442_4a3d_9c82, - 0x1e3b_87b0_e601_4734, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd2bf_fe22_3f25_f8aa, - 0x3d13_dad2_88e3_899a, - 0xe40c_042b_1047_1796, - 0x20ef_355f_b2b9_b7a4, - ]), - pallas::Base::from_raw([ - 0x2584_fc90_05a4_4eb7, - 0xc73d_0faa_e860_285e, - 0xa3a9_e4b5_9dce_93f6, - 0x1002_4764_5a67_73fa, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb44d_d4ef_f05f_ee9d, - 0xd311_e35e_57c3_af04, - 0x6afa_e748_df35_ace0, - 0x2852_47bf_ed5c_af05, - ]), - pallas::Base::from_raw([ - 0x67e1_bbc4_0409_5959, - 0x1064_023c_f1ce_c606, - 0x12ea_7b93_7755_8d2c, - 0x14e6_9d5a_a6ca_0da4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3dad_64a1_41cc_bf58, - 0xcd45_cc95_e1bb_6d96, - 0x4f71_1071_c168_9f44, - 0x0f42_27ce_35ad_602c, - ]), - pallas::Base::from_raw([ - 0x54ef_0524_e72a_f65c, - 0x7baf_4d83_432e_dfbc, - 0x3479_4bfb_b7eb_9917, - 0x1bad_5ff2_bc75_3f5e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x17df_6323_6eb4_e4a0, - 0xec9a_1e58_c280_b973, - 0x5a8d_46ad_12ab_e217, - 0x0222_2ecc_4b1f_79a4, - ]), - pallas::Base::from_raw([ - 0x8dc6_c26b_627e_cfc3, - 0xcad4_3492_8c57_feac, - 0x4c7e_c57f_f201_761e, - 0x1a7a_19c9_ebec_a09f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfbdd_d33a_def4_3e8f, - 0xd650_1c5d_0b0f_e30a, - 0x6fd5_fd34_c4c8_ef1b, - 0x337e_4fbe_c8b3_3a4e, - ]), - pallas::Base::from_raw([ - 0xfe9a_5311_7c98_6fb1, - 0x90fe_d9ee_d112_899c, - 0xa935_19db_c171_8814, - 0x1a32_d859_2e42_f132, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbd1f_570e_d595_ab4c, - 0x2e11_069e_dc17_bceb, - 0x5c63_4ef5_02d2_93e8, - 0x3be4_949d_9d7b_53c5, - ]), - pallas::Base::from_raw([ - 0xf087_456a_6cc0_0eac, - 0xb68e_6724_73b7_edeb, - 0x9548_e552_8391_9a99, - 0x0107_0f1f_04ae_b5d6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x493a_9aea_3262_6e17, - 0x7b8e_4c15_74b2_e969, - 0x8053_61b6_b5f2_ca98, - 0x39d7_c501_1792_79a3, - ]), - pallas::Base::from_raw([ - 0x53d3_5c19_43dc_f2e9, - 0xba13_604f_47bf_3260, - 0x8324_b8e7_4d46_596a, - 0x1882_9bdb_b7d8_45eb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0d27_0a51_f183_e9e8, - 0xd276_a7f9_3066_8f03, - 0xd48d_97b5_9e5d_88e9, - 0x0e8a_ee90_45a1_44e1, - ]), - pallas::Base::from_raw([ - 0x2818_4a9f_3fa0_bb40, - 0x710f_acd0_0450_af64, - 0x900f_4bdf_1974_6e9f, - 0x27a4_2da3_2115_76d4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb689_cf40_37dc_668d, - 0x9377_0a01_142d_c428, - 0x3134_eac4_c878_08fd, - 0x3afc_9061_8065_68ed, - ]), - pallas::Base::from_raw([ - 0x60c7_7d3d_3fad_57b6, - 0x59f4_9ebc_34aa_59b3, - 0x9d63_d009_0c0a_7384, - 0x2559_c358_bc86_61ce, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5c09_5692_145c_79b4, - 0xda8b_bb5f_49bd_b0b4, - 0x4135_2c94_9dbf_9dd7, - 0x0453_dc79_9e74_8178, - ]), - pallas::Base::from_raw([ - 0xda01_9f05_07c7_9539, - 0xe639_45d5_2aef_6d32, - 0x4119_4ec6_4943_39e2, - 0x2ea2_ef55_be81_fd44, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf49f_4fa9_04be_f892, - 0x62dc_978b_3700_3ffb, - 0x6702_e625_4263_44a6, - 0x3b3b_e12c_dc8e_7efc, - ]), - pallas::Base::from_raw([ - 0x10bd_e67f_93e4_1090, - 0x8ccc_a11e_ecb0_991e, - 0x50dd_72f0_eb8a_e400, - 0x3f3c_db56_a787_8aad, - ]), - ), - ( - pallas::Base::from_raw([ - 0xff0a_53a6_55f4_b430, - 0x0fbe_41a2_841c_8e6b, - 0xe44a_6249_5534_24da, - 0x3d16_d183_cfd9_e4f3, - ]), - pallas::Base::from_raw([ - 0xf173_7a47_4a12_010d, - 0x3386_2a20_5ae3_010c, - 0x9475_ac8c_7cc9_6eb2, - 0x2d5e_edba_92e3_787e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xec32_bdcc_3ab6_8bc8, - 0x5ef1_c68d_8205_6ba8, - 0x2a79_c6b1_760f_230a, - 0x0269_c007_4842_ac02, - ]), - pallas::Base::from_raw([ - 0xdea5_6a73_acf7_0dd7, - 0xefae_24fd_d605_d32c, - 0x7644_0179_5a72_8a8f, - 0x29bf_5935_ee3b_cf0d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xafec_fca4_d928_57e0, - 0xa2ef_4a25_2d8d_462a, - 0x3f9c_1cd2_7b1f_8c08, - 0x3f06_e865_ae86_e74e, - ]), - pallas::Base::from_raw([ - 0x2bca_60c6_542a_5cce, - 0x2017_a0ca_ddf9_1f45, - 0x9ee1_6a4f_f103_b9cf, - 0x3795_5bec_4580_dd2a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8691_e4b4_c1cf_edc6, - 0xb4f6_468c_8120_fd13, - 0x05b1_7517_b826_dc89, - 0x0c61_3568_3cef_710c, - ]), - pallas::Base::from_raw([ - 0xb119_025f_6be2_1c59, - 0xe60e_c8d4_cc1a_34da, - 0x61ba_a8f8_bd7a_34ff, - 0x1c27_2a98_a433_d3ba, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc775_8f6e_229b_53c4, - 0x8187_14e3_1fd4_834f, - 0x9b72_1c14_5292_b1f4, - 0x2ad0_635e_fd85_69a0, - ]), - pallas::Base::from_raw([ - 0x359a_b6e7_a119_d83e, - 0x598f_fc63_1f64_1ef0, - 0x444e_4b2b_7792_20fd, - 0x03df_5258_e7c9_9279, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9134_5261_be30_5e2e, - 0xe6d4_a11d_a37a_2874, - 0xba1c_281f_b344_e7ec, - 0x160d_d9d7_58da_88b5, - ]), - pallas::Base::from_raw([ - 0xdade_8f8f_bbfe_566a, - 0x2000_6526_5423_f35f, - 0x0f19_01f2_71a6_22a5, - 0x32a0_503a_fecb_2320, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0683_5997_1217_55ba, - 0x2a57_c9d0_8730_2e1b, - 0x8f07_c57b_3fdc_d076, - 0x0849_b2af_ec11_13b5, - ]), - pallas::Base::from_raw([ - 0x13d6_5361_9c27_882d, - 0x84d9_028a_a60f_5d93, - 0xf1ee_437b_33fa_62f2, - 0x0c6f_0de4_3fdb_971d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6e23_4404_9793_ef67, - 0x7cd5_90e5_4c92_3c41, - 0x27dc_0ed1_1611_45fe, - 0x1ce0_4ef4_cfb4_c9b1, - ]), - pallas::Base::from_raw([ - 0xfd5b_9f8f_ddcf_d367, - 0x6a5d_c6bd_9379_c9c2, - 0xc297_9ece_527b_63b8, - 0x323d_873d_580f_2a72, - ]), - ), - ( - pallas::Base::from_raw([ - 0x44f9_82c7_c31d_7a89, - 0x9846_e859_178d_60b5, - 0xa50a_5197_85d6_70ac, - 0x0777_8711_9138_56b7, - ]), - pallas::Base::from_raw([ - 0x8fa1_5093_7040_054c, - 0xe0af_8de4_84a8_b394, - 0x6ed9_fa7f_468f_261d, - 0x26e0_8f4c_2f70_048a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1610_366a_bf41_9b15, - 0x5495_33a5_f504_49cf, - 0xff03_7486_34b9_7494, - 0x2ccd_de83_e509_6a23, - ]), - pallas::Base::from_raw([ - 0x9724_c725_1ffe_d7b2, - 0x014a_a2d1_b3b7_bba7, - 0xed28_d6ab_01bd_03b9, - 0x04d8_9a55_3cc8_37fd, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5053_2dc7_a8cb_ce3d, - 0x9332_681a_8979_6c93, - 0x1b1c_f355_e7aa_959f, - 0x0b04_c461_9897_ec8b, - ]), - pallas::Base::from_raw([ - 0x91c0_9815_eac2_6003, - 0xdf44_c95a_8b52_8f05, - 0xfb9d_53b9_32a2_96c5, - 0x05f7_a7c0_514d_9481, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe9e8_2ebd_f36a_c3aa, - 0xd63c_3aba_dde3_84c6, - 0xa065_4794_bbd5_57d2, - 0x2af1_74e3_b8eb_6bb4, - ]), - pallas::Base::from_raw([ - 0xc1b7_ec28_b61c_bc1c, - 0xa6df_1fd9_3b44_ada5, - 0x41b4_1fbd_54b7_40e1, - 0x07b6_b7b5_6200_d6ae, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf809_14b1_c60c_7c25, - 0xc96e_9d7a_d9d2_0bbb, - 0x9bf1_14b6_065a_6090, - 0x07f3_c075_3999_631c, - ]), - pallas::Base::from_raw([ - 0x6d84_a970_41fb_fe71, - 0x7367_f8cc_4832_6aed, - 0x9fa4_b09a_b998_980d, - 0x10b5_51f4_4081_9d9b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x13b2_211f_8488_06eb, - 0x8761_a8e5_68bd_a93f, - 0xfe79_18b0_b2c7_bedb, - 0x0eb8_9428_e7fa_66e6, - ]), - pallas::Base::from_raw([ - 0xa4ae_5cd1_74dd_020f, - 0x0a36_7483_d7bc_ebd5, - 0x02ee_e479_a589_b49f, - 0x381f_443f_f703_3d02, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbfe9_7299_65ea_ab6c, - 0x91d7_c643_d196_223e, - 0xc1c4_1ee0_2fba_0ee2, - 0x0391_a582_eed5_9211, - ]), - pallas::Base::from_raw([ - 0xf6f5_ac50_5fbe_870a, - 0x4532_ce4f_a3a9_10b7, - 0x2e04_95dc_076f_edfc, - 0x2566_6899_b070_c78e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x59d3_31f8_f73a_4699, - 0xb89e_a133_6b3e_ec84, - 0x67bb_8592_e68f_95da, - 0x0917_436e_03ed_fafc, - ]), - pallas::Base::from_raw([ - 0x2728_c13f_7768_6f7e, - 0x2615_d6e8_f42a_f8eb, - 0x5cc5_df77_1ffb_5726, - 0x00a0_eb9f_912d_b497, - ]), - ), - ( - pallas::Base::from_raw([ - 0x45a5_12f7_5fc1_61de, - 0x0fc6_e344_3c96_5554, - 0x4fea_37c5_2155_ebd0, - 0x07c2_cfac_599f_e891, - ]), - pallas::Base::from_raw([ - 0xd32a_935d_3c0c_02bb, - 0x6263_1e68_432b_5e9c, - 0x072c_bed2_1f3d_b393, - 0x28ed_e749_83dc_4b16, - ]), - ), - ( - pallas::Base::from_raw([ - 0x06de_4839_8da8_baee, - 0x68cc_20a7_0293_f4e0, - 0xde3f_a9e2_2477_7654, - 0x3fd6_fa54_176a_beb5, - ]), - pallas::Base::from_raw([ - 0x5353_f59f_e5a7_9799, - 0x1782_1d05_f83b_d46d, - 0x426d_078d_a05e_5fc3, - 0x278e_e806_7443_d6e7, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc062_01cb_8329_3f63, - 0x2612_bb03_e6c3_5ca8, - 0x6cf4_e8c9_485f_b2b2, - 0x1df7_2e99_3570_d89e, - ]), - pallas::Base::from_raw([ - 0x78a4_d3c2_1b6d_70a7, - 0x14d8_c82f_b0c1_2f69, - 0xf678_2daa_4988_4ae3, - 0x35d2_eef4_df12_fd4f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb4ae_fdcc_23b0_19ed, - 0xac89_a1b7_c189_9999, - 0x3c5b_8165_4f7a_0a2d, - 0x0ab3_7d69_1765_1d3f, - ]), - pallas::Base::from_raw([ - 0xa130_f549_d03d_7b10, - 0xfe3e_fba5_af76_b8c7, - 0x479c_b292_d515_4d68, - 0x08ed_b127_7cd1_5737, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7250_3581_4ad1_9e66, - 0x9fad_6a01_94a2_09c1, - 0xea98_3f3f_0138_1a13, - 0x17b3_e97c_781f_885b, - ]), - pallas::Base::from_raw([ - 0x871a_12ed_525d_b6df, - 0xadc2_9db0_5909_a3d7, - 0x9807_df73_70cc_dace, - 0x31cc_cbe8_16e8_1804, - ]), - ), - ( - pallas::Base::from_raw([ - 0x42b6_c7a3_8516_301a, - 0x6485_544d_58aa_3fec, - 0xe105_5ca4_0c25_2a01, - 0x3ced_acc5_ade8_6885, - ]), - pallas::Base::from_raw([ - 0x4de5_edcc_e563_c20c, - 0x0879_53b7_6a36_36ea, - 0x1eda_cf9c_e6ca_a3a3, - 0x3f82_b415_4198_b3b1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2781_6103_15f5_7658, - 0xfcc0_b779_a51d_a582, - 0x99df_bff3_92f2_e1d7, - 0x1e09_2f1e_a84d_ae01, - ]), - pallas::Base::from_raw([ - 0x1e6f_2bc5_8ea2_2080, - 0x8ed9_b15d_0399_5f75, - 0x727a_eba9_910e_20af, - 0x38c6_dc55_925a_cbb1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x91fc_bc05_db22_2747, - 0x25bc_36c1_336b_0c2c, - 0x4df4_c949_dcfe_5263, - 0x2eec_785b_ec90_be5a, - ]), - pallas::Base::from_raw([ - 0x4d7e_fc93_c1b1_5b65, - 0x2def_facc_0fdc_986b, - 0x1250_98ef_caa3_a74d, - 0x0624_77fe_5983_41c1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb63d_7e66_55d5_e3ea, - 0xfb16_b4cb_6165_cc87, - 0x36d2_6c4d_6ae2_1690, - 0x166a_c76c_81f8_449d, - ]), - pallas::Base::from_raw([ - 0x82e2_3968_9388_5c2b, - 0x1b87_9d98_85df_6a30, - 0x5407_156d_69ad_ce04, - 0x0906_bd2d_e5cc_fafa, - ]), - ), - ( - pallas::Base::from_raw([ - 0x737c_cc41_9796_7823, - 0x1007_28e0_1f6f_ec97, - 0xfc9b_08d3_ba9e_2d24, - 0x06f5_aae5_2940_c965, - ]), - pallas::Base::from_raw([ - 0x28f1_62cd_2885_43be, - 0x3f9e_680d_fcad_3865, - 0x8661_0321_76b3_13ce, - 0x14bd_d4cd_abb9_372f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6c25_b3d7_e74e_4edf, - 0x67fb_ae65_2ead_0439, - 0xc182_0837_bf0b_8a51, - 0x3bc9_ce19_4df3_7d84, - ]), - pallas::Base::from_raw([ - 0x6a05_2e74_98de_40b8, - 0xca78_a073_4c6d_7fc7, - 0x5a0a_a126_7469_ec62, - 0x2f17_851c_850f_c7ed, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3317_c03a_fd91_fc0d, - 0x380d_9ecf_fea8_a93c, - 0x7ecd_e1bc_3a9f_b86e, - 0x1770_3f7b_98a4_afe3, - ]), - pallas::Base::from_raw([ - 0xc54b_5020_c9a0_f2c7, - 0xc66b_05c3_adef_c98c, - 0xf38d_a7ae_8e47_7d10, - 0x3784_0c9a_9c1b_eff5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5093_7efe_a739_821e, - 0x7ff8_6ca2_faa1_106e, - 0x252a_974b_7e9d_2cf1, - 0x1b69_d19c_d62b_b010, - ]), - pallas::Base::from_raw([ - 0xc16f_5a7f_12a2_844e, - 0xae53_d0bb_8ead_5714, - 0xa3c7_0af5_6666_4f67, - 0x3ecb_b98a_9351_1276, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbdc5_4853_e848_f0e9, - 0x1b28_67be_1e77_2485, - 0xe0f5_1554_daca_9e94, - 0x1186_da13_89c4_b670, - ]), - pallas::Base::from_raw([ - 0x1651_3d05_c776_2b00, - 0x20b2_e3a4_b95f_872b, - 0xbf7c_eb39_15fc_1332, - 0x0423_5acc_ac90_496a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x01b0_7e5d_d856_259f, - 0x7f43_208f_a155_b0c1, - 0x8928_e815_2193_8b73, - 0x178d_9714_a538_7eac, - ]), - pallas::Base::from_raw([ - 0xfcb4_658a_4c20_46bb, - 0x6bc7_e482_a235_c77f, - 0x44e8_f7b0_3fb7_88ff, - 0x3ce7_7772_6e04_3742, - ]), - ), - ( - pallas::Base::from_raw([ - 0x55ee_eaa0_d43e_91da, - 0xc90e_6024_78ca_5f27, - 0x6c2a_ec40_cbb6_e051, - 0x0bff_365c_4a48_be7c, - ]), - pallas::Base::from_raw([ - 0x145a_ef04_d8ea_8dc9, - 0x2d56_9b48_e5c8_414d, - 0x781c_943a_068f_fe73, - 0x3361_9f38_967a_b97b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xacbe_71a5_7996_2bd4, - 0x3a08_766b_9cb9_e72b, - 0x1588_d82c_533d_b065, - 0x30d6_c1d1_7767_c3e6, - ]), - pallas::Base::from_raw([ - 0x5d52_0dac_efe4_6e17, - 0xd87a_651f_6eab_7d3f, - 0x6a75_591f_324e_b6db, - 0x1a5d_9a98_7774_d8e4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0225_72e9_ae01_ff6b, - 0xce5a_1ad2_ef36_212b, - 0x14c1_0f42_da3d_b3ad, - 0x2267_625e_16a9_0f0e, - ]), - pallas::Base::from_raw([ - 0x7bf4_5dd3_d6d6_71ec, - 0x01bb_0a02_1198_ccac, - 0x15d0_34ca_24fa_48fa, - 0x19a8_8c5b_dd76_c0e2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfdd9_7cc1_34fa_1e2d, - 0x3714_b775_9ccf_8134, - 0xb76b_7ae3_d982_6b77, - 0x1ecb_f631_e1bd_91a2, - ]), - pallas::Base::from_raw([ - 0xb611_00ce_ead1_4ede, - 0x9f64_dc5c_9bf7_633c, - 0x315e_4d26_f06e_c2e6, - 0x024a_535a_5088_6f26, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9c75_4f1e_74b6_2341, - 0xc229_dbf2_cfa3_2ca1, - 0x8012_a006_e1b9_9678, - 0x289a_7df4_9f8e_2205, - ]), - pallas::Base::from_raw([ - 0xa292_86b7_14cc_854c, - 0x63c0_5a80_bab8_b239, - 0x77bc_a95b_3393_16df, - 0x0aa1_78e8_67c4_6e06, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6983_e305_abeb_b0fc, - 0x4047_8611_cde4_c624, - 0xcdee_dbfe_557f_b7ed, - 0x04e8_1c14_8e02_18d1, - ]), - pallas::Base::from_raw([ - 0xe556_8d33_21a8_0629, - 0x97f8_66e9_f2bb_ae53, - 0xcea5_b64e_5002_2bbb, - 0x1a34_52e0_acea_f51a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3405_d717_8cc7_2c52, - 0x28a7_a504_399a_1e1b, - 0xf170_e239_f7e9_c844, - 0x1cd3_6395_bb69_dc88, - ]), - pallas::Base::from_raw([ - 0x675b_0b51_04e6_8e2d, - 0x187f_6ecc_1ded_2163, - 0x1a53_421e_85e3_7079, - 0x158a_e3c7_752b_7751, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5500_883e_12a9_cfd7, - 0x9cd8_0402_12bd_4753, - 0x1f75_8954_f62b_dad5, - 0x0bbb_fa9c_c2fe_d2d0, - ]), - pallas::Base::from_raw([ - 0x19e6_d909_4824_a28d, - 0x8cd6_c4c0_9883_3e51, - 0xb646_194f_becc_6f59, - 0x3420_e2ec_d734_13e5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x80a9_e5e3_1610_f69e, - 0xdd9c_4a92_1056_8e20, - 0xf86c_aeb6_c85c_4356, - 0x31ad_dfcc_5e4b_700d, - ]), - pallas::Base::from_raw([ - 0xe9ab_d914_79e1_df04, - 0xb7f0_23f3_36f6_74dc, - 0xa9d2_3371_7f13_8bb6, - 0x1f15_2617_cb34_976f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x960d_00a3_fb22_5078, - 0x9988_7156_0e61_3f5f, - 0xb2ba_af97_cca6_a3eb, - 0x2e7f_19e7_c704_b5fd, - ]), - pallas::Base::from_raw([ - 0x57bb_469f_0dd9_b209, - 0x9c40_8186_c84a_bd26, - 0x5413_30b7_2445_9760, - 0x3ea7_3777_ee4f_b850, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6241_5e2d_be88_0053, - 0xe65d_815b_0595_5f7a, - 0x6b5b_e7ed_43e0_5474, - 0x29f9_ef3c_013d_20ff, - ]), - pallas::Base::from_raw([ - 0x645c_e074_cff0_711a, - 0x9b08_6e5e_0ae6_30dc, - 0x1765_5ee6_7ff2_68df, - 0x2830_190f_e6ea_62a9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf9a6_568b_9c61_4281, - 0x4bf3_f37b_d546_d5ce, - 0x47fc_7710_3474_7b14, - 0x3a46_2aa4_f76a_f9ef, - ]), - pallas::Base::from_raw([ - 0x480d_19d7_aeef_4c79, - 0xab60_e175_aefb_931d, - 0x4d55_85d0_c71f_a5b4, - 0x0a96_8e62_97d5_9535, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe436_903f_24ac_9df9, - 0x9300_ddf0_1da8_17a6, - 0x123e_6839_b4bc_932a, - 0x2718_8488_35fd_d77f, - ]), - pallas::Base::from_raw([ - 0x52e4_7abd_9b09_46bc, - 0xc085_3ece_0feb_e4a5, - 0xf3f8_35c8_347e_995d, - 0x19de_e913_2cc0_a224, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa453_83a9_b4e6_a758, - 0x9015_00b5_23c1_e447, - 0xe85e_c0c8_8626_5736, - 0x1461_a8e6_40c8_f85a, - ]), - pallas::Base::from_raw([ - 0x501d_08ea_fd72_b2c8, - 0xeb63_ec79_4f6d_f403, - 0xf1e3_f250_1c53_0d19, - 0x062e_d759_693d_19d8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa2c4_a38d_b249_fc75, - 0x8ae4_0721_77c7_8590, - 0x03dc_4b04_8d5b_9ea5, - 0x0d89_0d38_e803_317d, - ]), - pallas::Base::from_raw([ - 0x3e10_ee60_9358_ada7, - 0x3509_48eb_0862_d70e, - 0x75aa_80df_185a_8c1c, - 0x37e7_c380_d027_a877, - ]), - ), - ( - pallas::Base::from_raw([ - 0xaafd_a565_f09a_06cf, - 0x91e9_f0c0_b668_00eb, - 0xba89_4a61_9a9a_5deb, - 0x35ab_6c2f_a72a_67a5, - ]), - pallas::Base::from_raw([ - 0xdd34_5830_bbc1_a26f, - 0xc3d2_140c_6fc3_9747, - 0x6580_4aaa_a4a3_f62c, - 0x2c8a_da2b_1b04_9e5f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x641e_246a_98ad_630f, - 0x72ab_91de_19b3_2e2c, - 0x5c92_774b_2169_b661, - 0x1e1a_c543_70ce_61cd, - ]), - pallas::Base::from_raw([ - 0x9cb2_3ff5_285b_8448, - 0x9bb4_a42b_f331_6727, - 0x62dd_a513_c86e_4720, - 0x2138_a0f0_4fd0_ae85, - ]), - ), - ( - pallas::Base::from_raw([ - 0x05ff_8a30_31c8_c2c0, - 0x320c_4e8a_b37d_13af, - 0x5fe1_6192_7de0_0a62, - 0x3239_6eec_c899_df01, - ]), - pallas::Base::from_raw([ - 0xf86a_5aa7_254c_db0b, - 0xfff8_6343_7c50_4001, - 0x907e_ce31_13c4_2834, - 0x0083_9120_fef6_4f04, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0da3_5615_e80b_7105, - 0xcd0d_35c7_83f5_ea68, - 0x1956_8f17_fd14_c784, - 0x3844_169d_8e21_5b80, - ]), - pallas::Base::from_raw([ - 0x1fcc_6ff4_1c9b_ed51, - 0x34e5_9481_5dd7_ec6b, - 0x0ba0_d316_7cad_7c5d, - 0x3ec0_c83c_398a_638e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x30e3_dd2a_caa8_9e23, - 0xca56_24c7_a921_34aa, - 0x569a_4c5d_be62_0c0a, - 0x0bb5_f435_f064_07e1, - ]), - pallas::Base::from_raw([ - 0xdfe8_e197_5e22_f53b, - 0x8dfa_bec5_7137_b1fb, - 0x01e1_9f98_b685_ae1a, - 0x28c1_1490_0528_c2c1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3dcc_f7ce_0ad8_e4f8, - 0x588e_312e_199e_763b, - 0x8c6a_a52f_0325_558d, - 0x29c4_ba69_c672_f4f3, - ]), - pallas::Base::from_raw([ - 0x19ec_f218_7171_52d7, - 0x06ee_7a55_fa38_ba4e, - 0xd8f0_a4f2_6c3c_fd95, - 0x3ef7_61af_4dbb_7f0c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1f0f_baad_04bb_5f75, - 0x4aef_02b6_56f4_e2f0, - 0x4c89_9bff_b8a0_8ea4, - 0x3f4e_7e2c_a1c7_708d, - ]), - pallas::Base::from_raw([ - 0x02f6_7a10_1c9c_9bbf, - 0x05f3_0cdb_8ba2_8ad6, - 0xc13a_c49a_1560_a8e2, - 0x1534_bedb_9435_5918, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfa87_6dff_b810_be23, - 0x72c7_0ce1_e075_2041, - 0x07c8_bf38_511f_3cef, - 0x1a6c_5f3e_ed1b_e25b, - ]), - pallas::Base::from_raw([ - 0x51dd_c0ae_85fa_65b0, - 0x835b_4dca_4cc3_3f47, - 0x1bd6_02bd_221a_6807, - 0x32c2_3d1a_8a90_ae9f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0eed_532c_a114_960d, - 0x6983_2d07_9745_030d, - 0x0cb8_8c0e_c597_8792, - 0x3ed4_46f3_babd_8fbc, - ]), - pallas::Base::from_raw([ - 0x2fa7_9562_7ce7_6ebb, - 0x7e21_5019_7c86_5e0b, - 0x6d0e_6986_0b16_2609, - 0x17ed_a803_03d2_9dbd, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5add_f07f_2875_4f6e, - 0xded2_1019_ce38_6e69, - 0xba11_5d0e_d146_4546, - 0x1cb8_adf5_6bf7_d57b, - ]), - pallas::Base::from_raw([ - 0x74b3_43e7_3067_5c9f, - 0xaabe_1a6c_c038_250c, - 0x8ef9_5802_7c5c_eb68, - 0x26f7_2308_b634_cbf3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe697_9cd0_2e2a_09a3, - 0xbfb4_1ab4_b141_08b6, - 0x290d_dd81_2cb0_5761, - 0x2a6c_642d_8d10_e582, - ]), - pallas::Base::from_raw([ - 0x8536_8a2a_e13e_84a4, - 0x9ece_6cb2_499e_86d2, - 0xa6d1_0304_1f4e_6811, - 0x1749_3586_294f_c00b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd000_f933_b288_c9ec, - 0x0008_fa27_b1fc_f86c, - 0x77b8_dc36_5ede_0af6, - 0x289d_ea2d_59eb_3f26, - ]), - pallas::Base::from_raw([ - 0x6ee9_9aad_2b6e_4dfc, - 0xa357_f9fb_63b5_5c8d, - 0xb99d_03c4_98a8_d710, - 0x2cfd_b980_9dc3_4f19, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4a3f_f24b_fabd_5cdf, - 0x7415_5bb3_3633_20e8, - 0xf605_add9_99a6_a3b6, - 0x0365_39f1_3da5_3f58, - ]), - pallas::Base::from_raw([ - 0x4aa5_e910_0459_c408, - 0xe4df_d4e4_dbfc_3099, - 0xece4_6d1e_47e1_8bae, - 0x2571_fbf8_3aaf_0f52, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc08b_755a_6fa6_56f0, - 0xac17_cbd2_3558_19a6, - 0x0e1d_63a9_76de_d59f, - 0x0f0d_bacc_068f_cd71, - ]), - pallas::Base::from_raw([ - 0x9ab6_8817_d366_c236, - 0x7ada_4276_3f88_5fd7, - 0x083d_de4f_9fe3_44ec, - 0x33de_e193_caf7_4d09, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3595_8bfd_2887_b46e, - 0x5f38_9101_f1be_4e28, - 0xf9d1_acba_99ed_08d5, - 0x34ae_a666_fa73_373e, - ]), - pallas::Base::from_raw([ - 0x8550_386d_b269_6cc2, - 0xace0_f26f_8504_9ec0, - 0x8e1e_d46d_9d3d_5454, - 0x0978_82d8_5b44_aeee, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1337_19a0_5435_a760, - 0xeb59_3ab7_0fce_fad0, - 0x066b_89a8_bf0d_853a, - 0x1a05_df20_1bf7_016e, - ]), - pallas::Base::from_raw([ - 0x69f0_568a_7e88_6ac6, - 0x90d1_fb1a_ccb8_880d, - 0x81f3_cb9b_0f87_03f4, - 0x28e5_0389_a936_6ecf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x50bb_3f29_64dd_d715, - 0xd5aa_f9a6_dc3f_7706, - 0x6e6d_1433_c49c_3c3d, - 0x1a87_0e90_b006_4440, - ]), - pallas::Base::from_raw([ - 0x8f4a_8f0d_9ffe_2a67, - 0x3df7_ff37_8b3d_e8b2, - 0xe200_ac50_b2e5_224a, - 0x2ea8_be75_625f_19d6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9352_f3ae_79df_84a6, - 0xd821_c76a_b91e_7cd2, - 0x1516_8b7d_afe5_369b, - 0x39b2_d1b3_ed5f_2801, - ]), - pallas::Base::from_raw([ - 0xe3c1_c8d3_4ac0_cded, - 0x2467_48bb_7fb8_12b2, - 0xf18d_46f6_9a23_e9ca, - 0x12b1_73bf_3cbd_5773, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0d92_cb07_476a_c74d, - 0x9179_b82a_91e5_9ea2, - 0xd5fc_3ab3_d692_f5e0, - 0x3dee_efd0_00c3_3a50, - ]), - pallas::Base::from_raw([ - 0xce37_7044_fa32_43cd, - 0x23ea_04ca_a975_a183, - 0x3aa3_b02e_ec62_b871, - 0x04a9_2111_c558_8ef0, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdc97_a102_7da5_665f, - 0xa1bb_5b5d_cefd_5818, - 0x7b4e_1a76_62cd_3571, - 0x3aa3_d99b_5276_2d70, - ]), - pallas::Base::from_raw([ - 0x94bd_7936_fec3_7759, - 0x7216_4b55_232e_5a3c, - 0x756b_e2a2_52bd_b271, - 0x33f2_bb74_d656_6f3b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc8fd_7256_d6dc_d9b9, - 0xca03_c9d8_7f65_7f5e, - 0xfd39_43fa_2bf6_46db, - 0x22c1_594f_6399_a591, - ]), - pallas::Base::from_raw([ - 0xa3d3_1b89_58be_066c, - 0x3776_df4c_4371_d751, - 0x6b4f_1dcd_0000_7a87, - 0x3a6d_83e9_a433_e219, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2bac_92ca_749d_8ca1, - 0xcdff_b76a_d983_64c1, - 0x4a71_9e43_074b_e266, - 0x211d_199f_4af1_3d31, - ]), - pallas::Base::from_raw([ - 0x615c_f375_7d8a_3f72, - 0xe271_0a4e_2b25_e0cf, - 0xe07e_62f8_a9e1_180f, - 0x3668_5169_d28f_4663, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5026_b92b_a025_7211, - 0x0f61_be9a_2a03_558b, - 0x6eb5_4fce_c558_57ce, - 0x3193_20a0_380e_6bd7, - ]), - pallas::Base::from_raw([ - 0x6fe5_1d43_554a_f6a8, - 0x6ff0_48c0_b9c9_f972, - 0xb6f3_7bca_07a3_0477, - 0x01b4_080c_f397_6ea1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0c85_14b2_21c5_bf83, - 0x6a65_f7f8_f786_f1e3, - 0x3c45_3a2c_865b_f046, - 0x18e2_8c3f_fbc1_e707, - ]), - pallas::Base::from_raw([ - 0xb311_7e90_19e0_60bd, - 0x682c_b029_85d5_f279, - 0x2d07_1839_acf3_3c80, - 0x24fb_be5a_09e4_252a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3f38_1349_fd30_13dd, - 0x50a3_3f2c_64f9_acc4, - 0xbdfc_c29a_eaae_4852, - 0x08cd_e7f1_737e_4d1f, - ]), - pallas::Base::from_raw([ - 0xc9eb_95f1_0d2e_cff9, - 0x2e16_091e_e8fa_7cb8, - 0x2338_d545_b2b1_87df, - 0x2f9c_01cd_934a_39a5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2f4f_2486_fa98_dd32, - 0x5ab3_50b9_9429_ab02, - 0x4d00_5b08_67f9_fb09, - 0x3779_1b28_6244_fb4c, - ]), - pallas::Base::from_raw([ - 0xf37a_1b41_ad70_19ed, - 0x3d58_6291_0404_eff3, - 0x3710_9d64_690b_7131, - 0x323d_fe2b_648a_0a01, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2c99_1b63_424c_90ac, - 0xcde0_e148_9201_19b1, - 0x6b0a_cdcd_a94e_23dd, - 0x0a83_ec85_5467_a25b, - ]), - pallas::Base::from_raw([ - 0xe2ae_b456_e029_5ff5, - 0xbbf2_157e_95d4_0f9e, - 0xfcf3_8385_5286_2123, - 0x09d4_c6b8_6321_1860, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5a98_269b_b68a_dd6a, - 0x1efe_b941_4639_b22a, - 0x3571_1c04_46ae_622b, - 0x0724_0c4e_61e2_c404, - ]), - pallas::Base::from_raw([ - 0x4ef2_32c5_b9e0_bf79, - 0x2849_2c6d_82b9_4679, - 0x6dc9_c162_d595_5ace, - 0x23a1_46c9_cb46_7e4b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0ea6_e467_1688_5744, - 0xd73a_c7a9_3c06_0f51, - 0x1b46_3eef_0911_0ff0, - 0x25f5_1a1b_8b2b_15b0, - ]), - pallas::Base::from_raw([ - 0x0e94_24d7_d847_cff0, - 0x9eca_1c26_c8d3_4d22, - 0x3e7c_44f4_a071_358a, - 0x02e0_3e55_9e85_2acc, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfaf6_e963_4f72_548c, - 0x75ba_6678_06cb_3018, - 0xdd5c_4dc1_f6a6_1ed0, - 0x358a_aa4a_969c_7d11, - ]), - pallas::Base::from_raw([ - 0x7192_b88c_0b41_26f7, - 0xdcbf_5faa_5173_d672, - 0x2844_3f7b_d7c5_386b, - 0x0326_622d_0d54_8882, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf31d_8620_1649_f08d, - 0x1fc2_50c9_c62e_1cdb, - 0x3fa2_7d7f_c12a_308b, - 0x087a_7698_3f2b_40d6, - ]), - pallas::Base::from_raw([ - 0x1dfe_55f8_f11a_cf1f, - 0xee33_c9fd_9995_34ef, - 0xc306_776a_68aa_2318, - 0x2ac3_5afb_37f0_64ac, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3ade_cfe8_e5e3_3497, - 0x6c41_930f_374a_cbed, - 0x12b0_f864_c7a8_8ad8, - 0x370f_dfb0_97f4_2558, - ]), - pallas::Base::from_raw([ - 0x7220_b1e4_1ab5_cf99, - 0x1632_92de_779c_623c, - 0xb034_0022_4b4a_86e7, - 0x309b_afa2_6ef2_925b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3406_5012_f9c0_5127, - 0xc828_f419_9900_4b75, - 0xf6d7_a11d_f480_e3f3, - 0x2d33_2d46_fc42_f207, - ]), - pallas::Base::from_raw([ - 0x2e46_6250_9e68_6ee3, - 0xabfd_de7c_df9e_5e25, - 0xfd57_0e95_4b02_75d5, - 0x2477_ef02_28ea_9a13, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbc3e_e22f_76ca_58be, - 0x3ea8_77d8_d59b_c50b, - 0xa88b_9b65_778b_d746, - 0x3ac6_7681_a682_1563, - ]), - pallas::Base::from_raw([ - 0x012d_26a1_75a2_a60c, - 0xd293_1675_5b9e_520e, - 0x7bb3_81b2_f90a_0804, - 0x33a1_bb0d_70de_7a89, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb0ca_c9ca_8444_ee90, - 0x968e_19ad_ff27_1d61, - 0x3f26_3e09_835a_f66b, - 0x05bd_71f7_da1c_0c64, - ]), - pallas::Base::from_raw([ - 0x61e9_dece_6f85_2582, - 0xe5d1_17ee_5df5_c9f5, - 0xa3d6_5b5f_bc5d_8147, - 0x3b58_829c_1b3c_754e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x39e8_9116_b59c_ef80, - 0xe8ee_3f15_868d_9a99, - 0x4b32_6add_a5d5_8444, - 0x14fe_9402_9ff7_9f66, - ]), - pallas::Base::from_raw([ - 0x8f66_4020_0012_b5cb, - 0x6fcc_c979_1537_fa13, - 0xd19e_3ecc_386a_8282, - 0x162c_c785_6d5c_74dd, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdcc0_2e8e_07fe_88af, - 0xbd3b_2a17_ffae_f834, - 0x0c6f_3298_640b_78d5, - 0x34a4_a683_e010_cf56, - ]), - pallas::Base::from_raw([ - 0x63f3_abee_7273_ea33, - 0x0537_702e_040b_92a5, - 0x547d_6ec3_8dd6_3bc9, - 0x0064_5b12_758a_1545, - ]), - ), - ( - pallas::Base::from_raw([ - 0xee8e_7e91_b30f_5175, - 0x9118_328b_98b1_2a4f, - 0x0c6b_7d43_ce19_2ef5, - 0x2683_6545_f707_77c2, - ]), - pallas::Base::from_raw([ - 0xd798_780b_8fd5_f829, - 0xc468_a05e_0278_eba4, - 0xb7fa_f13c_0064_7ac1, - 0x322a_6aee_3ba4_d176, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1e3b_4dd6_6189_13dd, - 0x248b_f2dd_da95_8f94, - 0x8216_4826_97e1_1826, - 0x21ac_9398_a5e7_dcec, - ]), - pallas::Base::from_raw([ - 0x772d_8d75_5b4c_3ff4, - 0x7677_d0f9_ffdf_bce3, - 0x10a3_b808_a28e_401f, - 0x3f6e_5b46_b349_c86e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5585_d887_f1be_367c, - 0xaf07_cc5a_a53a_b659, - 0x923e_92e1_35a8_1746, - 0x3bf2_268c_f24d_f183, - ]), - pallas::Base::from_raw([ - 0x6fe6_0473_5e78_a74d, - 0x39a1_9091_b746_8447, - 0xa594_c45e_b7ed_cbeb, - 0x0bc9_13da_4cca_ecc3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1dd4_2c2c_c537_4903, - 0xa6cd_7de7_d439_ae61, - 0x15db_897f_3b7a_4b07, - 0x385c_81f8_ce51_3dd7, - ]), - pallas::Base::from_raw([ - 0x0ed8_0b1c_199e_8dc9, - 0x79e2_6722_5b1d_39ed, - 0x8b04_7941_6c0b_072f, - 0x1507_a637_5325_d934, - ]), - ), - ( - pallas::Base::from_raw([ - 0xaf31_86eb_84ad_4635, - 0xa779_6331_ccd3_0336, - 0xf128_6ce2_c67c_671f, - 0x00c1_b469_5cb2_7c0a, - ]), - pallas::Base::from_raw([ - 0x7c4f_be0e_1cae_a3da, - 0xc17b_1bad_0248_be18, - 0xbddd_f903_c50f_6c61, - 0x2f3f_845e_eaa9_03e7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7338_6610_264b_147f, - 0xe78a_eae6_e018_7005, - 0x909e_4f4d_6e92_b8fc, - 0x20ec_33c4_98b4_3f28, - ]), - pallas::Base::from_raw([ - 0x29a8_eaa1_5507_3eea, - 0x729d_227c_2a31_1b0f, - 0xb154_9c99_6dee_651b, - 0x3060_2ac3_8a24_17f5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3fa1_0f32_fc38_d1e7, - 0x1130_716c_d00c_2e12, - 0x8b7b_e7ee_bb9c_cf07, - 0x03dc_0d4e_7c25_b4c8, - ]), - pallas::Base::from_raw([ - 0xcc37_2d2f_1cf0_494e, - 0xf281_1971_693f_a7cb, - 0x71c8_5723_0112_d789, - 0x0b3a_4062_de68_d35a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2e57_965d_8fe6_3cf5, - 0x1e7d_0375_96cf_b42f, - 0xe4eb_acfa_e071_f221, - 0x18c8_30aa_25a9_b96b, - ]), - pallas::Base::from_raw([ - 0x1e35_c955_b145_dba5, - 0x38bf_a239_4c66_8c55, - 0x2b79_b6c0_0ae1_44e5, - 0x3306_70f2_2a1a_de18, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0337_c17d_8089_522c, - 0x8cf3_b7f9_e509_1e93, - 0x30c2_0095_5bf9_2882, - 0x1803_6e94_3474_308f, - ]), - pallas::Base::from_raw([ - 0x83ac_e960_14ab_f3bb, - 0x39e9_4c89_6758_a248, - 0x3b82_4eaf_babb_2278, - 0x05fc_dc8a_770e_abbe, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4d15_af9f_a6dc_11ec, - 0x9688_b4f7_fa83_b756, - 0xa900_9592_c556_2c12, - 0x3131_f9b2_c23e_76a9, - ]), - pallas::Base::from_raw([ - 0x6377_bc0b_418d_17d1, - 0xbdc7_c62f_a1a8_205e, - 0xb808_e58c_dc75_27e1, - 0x3ce3_9a6a_42ea_0aa0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x919c_3661_1b95_aae0, - 0x21c0_adf5_8570_1f29, - 0x15d8_a824_0a43_7e95, - 0x2487_0e7f_975b_e250, - ]), - pallas::Base::from_raw([ - 0x2b8a_f942_d325_4f8f, - 0xb8bf_f293_9d0e_2803, - 0x2b36_1401_fde5_3611, - 0x095f_973d_1e25_6fe0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x25b5_ca69_afd7_aff7, - 0x5731_761b_b667_965f, - 0xf0db_8000_e078_d5f6, - 0x105f_d651_9a6f_486c, - ]), - pallas::Base::from_raw([ - 0xf6ed_7c18_4edf_3a25, - 0xf716_d2fc_b54c_26c1, - 0x8303_3072_def8_c70a, - 0x3c72_43cc_c6f9_d8a8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd29a_f540_a1af_2913, - 0x86f8_1775_ed00_f09a, - 0xc978_728d_7996_fcb6, - 0x15aa_c4cf_5c52_2bcf, - ]), - pallas::Base::from_raw([ - 0xccad_8b65_5bf6_65a2, - 0x197e_4429_fe3d_8a0a, - 0xbc26_5a82_cbc8_f7ef, - 0x0963_7be9_0c33_cc7a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x75dc_37ce_9ca5_f163, - 0x3ce4_4f1c_f801_0d67, - 0x1933_916f_d304_ae70, - 0x09c9_2882_3da7_3ed0, - ]), - pallas::Base::from_raw([ - 0x141a_785b_eb35_8d29, - 0x10a1_7521_6bb8_ca36, - 0xcd51_d77e_9964_8226, - 0x1d96_15b1_2538_b56c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7c71_c1bd_6f57_54d3, - 0xc9a0_533d_95df_b16c, - 0xc945_1160_48eb_86c6, - 0x05a8_f8f3_8c44_0d2e, - ]), - pallas::Base::from_raw([ - 0x11d8_5995_cf88_f460, - 0x44eb_7f8a_f7bb_3f42, - 0xbe8c_bb43_79ee_ea5b, - 0x02dc_b98f_ed50_2f86, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4aa2_aebe_4d5d_a915, - 0x3425_6cb2_b933_62ec, - 0xd229_ad1e_6a44_6607, - 0x35fd_e2b2_e65f_cbf8, - ]), - pallas::Base::from_raw([ - 0x9a36_e5cc_e10a_7cc0, - 0x7d41_adbf_6442_8e9e, - 0xc64a_aab0_e77d_ddc3, - 0x28b6_ce44_dd17_b086, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1729_f03e_c757_de09, - 0x8714_d598_3cae_ddd6, - 0x46bc_981b_76f8_5cbe, - 0x1b7c_7a5d_98d4_34b6, - ]), - pallas::Base::from_raw([ - 0xfb61_8881_0f97_fafc, - 0x769e_1253_4744_7d00, - 0xe166_94e5_6b37_ac66, - 0x0e0d_592c_aaa4_40d6, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb477_691c_7b9a_4e74, - 0x1c61_eaa0_b273_998a, - 0x9295_2b04_a869_8738, - 0x18ae_d1c7_f94d_31cb, - ]), - pallas::Base::from_raw([ - 0x63b4_a102_91a0_3aa0, - 0x8456_6a59_cd00_e2e8, - 0xd9ac_8f76_f4fb_99ea, - 0x249a_c33c_1f19_006c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa611_c5c5_9dd9_c129, - 0xb449_431e_460c_3b9a, - 0x8aca_28de_50ac_6407, - 0x2be1_f2a6_a7a7_ef47, - ]), - pallas::Base::from_raw([ - 0xa14c_46c9_87ca_1f52, - 0x40fd_f4bb_a4f9_9362, - 0x99f2_8ce2_fff0_5d47, - 0x2339_e672_20fd_6223, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb07e_39ee_d553_19df, - 0x2e2e_a2b6_cd63_7b9e, - 0xb230_1c5c_5876_4d85, - 0x3101_8876_853f_6e11, - ]), - pallas::Base::from_raw([ - 0x6d1c_01bb_fd88_f740, - 0xac45_ec78_810e_f0f9, - 0x9178_89e7_5ed9_7c53, - 0x2e02_e772_12fb_a864, - ]), - ), - ( - pallas::Base::from_raw([ - 0x482b_ce95_a904_fbd8, - 0x099f_45ef_d9d4_df4e, - 0x6e70_1656_036c_32a5, - 0x0a38_cfd7_47d5_12df, - ]), - pallas::Base::from_raw([ - 0x570e_1101_ac76_4879, - 0x99d6_ff14_205e_e41a, - 0xc0cb_4ce1_8364_ca7d, - 0x3f21_3a0f_2127_88ab, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd491_d705_998e_3189, - 0x7bbe_badc_663c_142a, - 0x1d71_9890_63cb_18bf, - 0x24f8_a1c5_2bcc_e57b, - ]), - pallas::Base::from_raw([ - 0x1052_3fab_b946_6f52, - 0x4621_6150_6b1b_7617, - 0xe22b_b133_5f66_15bb, - 0x00f7_be2e_c34c_d4e3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9b7c_bac0_1918_11a9, - 0xe14a_1c33_bf27_13cd, - 0x9c34_676f_4ed5_0771, - 0x3bc3_b8f9_e4c7_cbdf, - ]), - pallas::Base::from_raw([ - 0xc0c3_e7a5_3a19_2bbe, - 0x9697_bec0_d8a8_605b, - 0xf832_dc8b_d08d_48b0, - 0x0ad3_7d64_7a36_db47, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1a49_dcca_d569_77a0, - 0x2769_7440_2b48_e461, - 0x7635_b7b2_f6c1_424a, - 0x2be6_10f4_a289_b89f, - ]), - pallas::Base::from_raw([ - 0x3e61_c167_3ef3_fc04, - 0x704f_268b_ce47_f0ed, - 0x1445_3f5f_d2de_d836, - 0x2cc9_d834_4ecd_1dd8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x11be_a2a7_7c43_e243, - 0xaecc_1a58_bb49_1e6a, - 0xad18_3b6c_844b_4f3e, - 0x3af2_29a8_1e78_8c01, - ]), - pallas::Base::from_raw([ - 0xe5c9_8811_3857_46dd, - 0x18a2_37a6_3f4b_065b, - 0x95eb_77a3_8a4f_506e, - 0x0f19_e7b4_bb81_9e9f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4289_8695_120d_ccc9, - 0x7c47_76b5_b28f_500d, - 0x7387_a0f6_6257_0e43, - 0x3e0a_1a75_0403_726f, - ]), - pallas::Base::from_raw([ - 0xa4b8_617f_f5a5_e2d0, - 0xbf01_7517_8dc0_be8f, - 0x3e12_8a0f_5763_aace, - 0x1019_05b6_1b1b_c5f2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6a1c_6336_c37a_69b0, - 0xab01_b8f5_4c9c_c938, - 0x4b70_77c2_8858_0ff1, - 0x219d_9462_2657_9313, - ]), - pallas::Base::from_raw([ - 0xf0ca_ec54_481d_b8b4, - 0x9caa_706e_8ced_f819, - 0x892e_4cf8_342d_d927, - 0x241c_1980_c2a8_9519, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2257_583e_eb36_4cc3, - 0x2729_3e7e_d528_5088, - 0x7eca_1457_60f9_6fcd, - 0x366d_41fd_d540_9bb6, - ]), - pallas::Base::from_raw([ - 0x8bfe_2959_1e82_19f9, - 0xbbcf_1722_efec_e216, - 0x9560_fd43_03ee_a5fe, - 0x01a2_ccf4_056f_faa8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf4b5_ad0b_5218_a94c, - 0x3a24_9090_dd6d_9354, - 0x98dc_0f69_de87_c57c, - 0x3dda_357c_5ff1_403e, - ]), - pallas::Base::from_raw([ - 0x5119_459b_c85d_b13a, - 0x2bfc_720c_90b0_7f40, - 0x8537_0f1d_f88b_d581, - 0x37db_226e_c00e_a298, - ]), - ), - ( - pallas::Base::from_raw([ - 0x63b3_23a9_39a1_77d2, - 0xe62f_9748_713d_01cc, - 0x2508_9050_a0a1_59bf, - 0x3d7c_7c78_e9b8_851d, - ]), - pallas::Base::from_raw([ - 0x3984_54cb_b4b2_6fce, - 0xc06e_f1b1_b11f_d4b9, - 0x4456_781c_e7d7_a297, - 0x04cd_8194_f1b8_f453, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1848_83cb_b617_7af4, - 0x2d57_546c_a4fe_c3d5, - 0x984d_e3a8_9232_dc0a, - 0x0fe5_7d7a_b313_f576, - ]), - pallas::Base::from_raw([ - 0x675f_4ab1_700e_2db7, - 0xb044_6bdd_3a0d_7127, - 0x8d66_c6a3_c174_8080, - 0x339e_ae89_0552_92fb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x28c6_46e7_5497_b6ce, - 0xa3fa_753a_0908_d101, - 0x1f09_d0f5_065d_2adc, - 0x178a_d1dd_216e_1573, - ]), - pallas::Base::from_raw([ - 0x030e_a306_b041_1e57, - 0x762a_03ec_df28_bda9, - 0xa2c1_f35a_ecc9_b51c, - 0x037f_7114_803f_e131, - ]), - ), - ( - pallas::Base::from_raw([ - 0x59ea_b5bb_9453_8366, - 0x5fd1_07f8_c2f0_3024, - 0x491f_9e0a_77a0_85f2, - 0x1948_5bba_5ad6_3346, - ]), - pallas::Base::from_raw([ - 0xe07d_8570_5ff6_f740, - 0xa7eb_9f4b_f78f_ebfb, - 0x4ec7_d8d5_ba74_87e2, - 0x152f_bf0c_1ad3_a448, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8951_a4b7_b88a_e304, - 0xfbba_f494_63d6_2de5, - 0x52dc_f4cf_46fb_b604, - 0x3867_61af_f0a2_8253, - ]), - pallas::Base::from_raw([ - 0xa79e_a333_0c3d_f255, - 0x98c0_1806_eff3_7bfa, - 0xce04_7c7b_36b8_bcd6, - 0x3c8b_a7f4_c363_edea, - ]), - ), - ( - pallas::Base::from_raw([ - 0xaf3d_f661_71ab_0aef, - 0xf42a_df27_feb7_ccb0, - 0xf652_096a_95e0_714e, - 0x12d2_2f2e_bb9f_dc00, - ]), - pallas::Base::from_raw([ - 0x2bd3_e13b_745c_7e1a, - 0x30d5_8bed_1c3b_4731, - 0x4fe9_de60_156d_0e6c, - 0x1e75_82ca_046c_a5e1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4b26_3b3a_2d30_be4e, - 0xa303_e1b5_ef9e_9c4e, - 0x1a0c_d3c7_1f78_d34d, - 0x0bc6_cbe2_2b93_1a09, - ]), - pallas::Base::from_raw([ - 0x5ef8_540a_c950_78e6, - 0x5d90_b70b_8565_5e85, - 0xed53_c717_36e6_4c78, - 0x1686_468a_3079_9166, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0d0d_dd14_b731_9e48, - 0x712e_bc82_5391_3fdc, - 0x5fcf_dda4_b51e_08ba, - 0x2f3d_06eb_2d44_fe78, - ]), - pallas::Base::from_raw([ - 0xa569_8634_a0b3_f32d, - 0xc8a6_e6d0_0d30_9550, - 0x89e7_8274_9620_9f58, - 0x05b3_f104_5b90_6405, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6556_9fab_c93f_5ef1, - 0x8c77_fb45_e5b0_3ff0, - 0x1462_4404_a661_0d5d, - 0x1431_fd82_8c12_8ca9, - ]), - pallas::Base::from_raw([ - 0xe0f4_ffe0_7a81_532a, - 0x6254_e069_7645_e573, - 0x3642_fa4b_19fd_822a, - 0x2485_d135_0391_bb52, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5768_e306_b266_4925, - 0xd2ef_fda1_e729_f652, - 0x21c6_d47c_319c_a9c0, - 0x2401_0c36_e54d_b3ee, - ]), - pallas::Base::from_raw([ - 0x4951_90fc_eb1b_0b80, - 0xf0c2_c315_ee04_91f2, - 0x61bc_9d08_1307_b3d6, - 0x024a_b73e_3607_a264, - ]), - ), - ( - pallas::Base::from_raw([ - 0x107f_387e_54f4_ef3f, - 0x290a_32da_0a43_f56b, - 0x8b9f_8656_4e83_0909, - 0x277f_0f45_b6ae_6203, - ]), - pallas::Base::from_raw([ - 0x546b_2865_f5cc_4c0e, - 0x8270_55d6_07bf_0010, - 0x3f7e_68bd_fe61_0371, - 0x1687_eb45_0f4d_7235, - ]), - ), - ( - pallas::Base::from_raw([ - 0x78a6_4eac_316d_2648, - 0x753e_2521_a67f_50aa, - 0x6e78_79a5_f11f_46fd, - 0x05d9_18ff_b1da_6eb7, - ]), - pallas::Base::from_raw([ - 0xbab9_5863_9bc9_3ae9, - 0xc37b_3f46_04cf_5755, - 0x7de4_ae79_9f29_d2df, - 0x047b_e1a6_060c_00a3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x49c8_71c2_61df_7cb6, - 0x5380_ca6c_e9ea_0b1a, - 0xd05a_4403_41b8_fe0e, - 0x080c_d18c_035f_3d1c, - ]), - pallas::Base::from_raw([ - 0x5274_e1b3_a894_244a, - 0xdedc_74af_a21e_7fb2, - 0xefb1_5f0d_99ee_54b4, - 0x164c_3262_4eb6_dbf6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x720a_ab53_d588_6877, - 0xceaa_5cf8_1671_dfae, - 0x6d4b_9e16_5405_52e7, - 0x1c6c_47fa_233f_06be, - ]), - pallas::Base::from_raw([ - 0x61f5_3c0a_f4a4_aa3f, - 0x5258_2334_b4f0_389a, - 0xc8a1_db30_50aa_f8fe, - 0x26dc_db34_c46c_475c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3208_2970_3840_3e89, - 0x90a1_593b_19f1_4fe3, - 0x09f3_ee71_e6d7_1be4, - 0x0e1f_8f25_134a_535e, - ]), - pallas::Base::from_raw([ - 0xd519_b8f9_b1ac_7612, - 0x91f7_850e_9074_5846, - 0x8846_3611_08cf_2b28, - 0x13ea_a62b_73e0_0d4c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4f39_a353_445a_c66f, - 0xb59d_a767_e1ba_84b7, - 0x3717_9c04_0954_afa8, - 0x2fcf_f236_d66a_b6d8, - ]), - pallas::Base::from_raw([ - 0x681a_f295_0d6a_597b, - 0x5642_9cae_6025_720a, - 0x8a44_998d_765c_574d, - 0x12ee_e67e_1017_6ed2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa310_66f1_af04_bfee, - 0x2537_ea36_fb79_6590, - 0xb3a7_25f6_64e1_75b9, - 0x0788_937e_9e35_d05e, - ]), - pallas::Base::from_raw([ - 0xb54e_df7e_8f9f_a0a2, - 0xe362_2000_9b73_a921, - 0xf8db_8c46_cd4f_aefb, - 0x2519_43ee_b590_deda, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa88e_2b82_de18_77cb, - 0x8b94_f5d7_e46c_d059, - 0x87a7_0381_3254_1fda, - 0x22b7_728f_f5f3_2e91, - ]), - pallas::Base::from_raw([ - 0x673d_7869_fa50_f997, - 0x9719_2499_f4d2_51a3, - 0x1c21_1da8_cfc7_b1d3, - 0x2bcb_9b60_77ac_9937, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa685_8e35_0e91_aeb6, - 0x97a5_6a16_423e_dae8, - 0xf9d3_8da2_28a0_0e54, - 0x1e9b_88fb_12aa_573a, - ]), - pallas::Base::from_raw([ - 0x9be1_63b7_2d0c_c322, - 0x6650_4cd4_3970_8ced, - 0xd3b1_ffca_c43e_ab37, - 0x1146_b28a_9f97_60fe, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdada_d29e_a8b1_8934, - 0x1250_940f_3606_539b, - 0xde2b_b139_6cf1_8876, - 0x11e8_cf63_9f28_6365, - ]), - pallas::Base::from_raw([ - 0x5015_5f8c_2102_5aa6, - 0xa1a1_d888_4567_1dfb, - 0x4927_0835_d236_0fb2, - 0x2753_5582_b996_b87b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8cc5_e492_e0b4_ca8f, - 0xb28f_29f7_b0c6_3c48, - 0x7e38_ef10_32a2_771e, - 0x3313_c543_e637_32ad, - ]), - pallas::Base::from_raw([ - 0x7669_4d57_eb2c_730c, - 0x0574_9ec0_b3f7_fe08, - 0x20a7_2453_e449_f1a4, - 0x2070_c656_4f60_8012, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7ec2_1a43_236a_004c, - 0xa075_0e43_5d13_56db, - 0xf3fe_38de_a0d9_767d, - 0x0337_f093_b562_0110, - ]), - pallas::Base::from_raw([ - 0x62ce_7184_7406_5d24, - 0x6bbb_c9a5_81d5_55af, - 0xfa2d_4ee6_6018_beea, - 0x280b_c654_e7e7_dca0, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb0e1_913d_b0c2_44fb, - 0xaaa4_d9c4_218e_5938, - 0x3546_9b6b_5fd6_28c6, - 0x2395_9107_43d3_b222, - ]), - pallas::Base::from_raw([ - 0x5caa_129b_4b4c_e99e, - 0xef45_ecaa_5313_85ec, - 0x9c0f_a2cc_c8c2_fb2b, - 0x189c_8131_f518_b80a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x032c_426c_b013_a4dd, - 0xe11b_5e5a_3317_d9a0, - 0x1492_b9fd_830d_3b80, - 0x05f1_9d94_cf5c_55d4, - ]), - pallas::Base::from_raw([ - 0x2c4c_4704_673d_d003, - 0xc48e_29af_97d8_8d07, - 0xd127_dd3d_91d8_53df, - 0x0d94_c052_f2d8_6405, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0281_7bc9_d4b9_3609, - 0xfd46_6a0d_2dd4_a592, - 0xd7bf_d5ad_053c_c494, - 0x3e23_096d_c906_06f6, - ]), - pallas::Base::from_raw([ - 0xca1b_a2ad_cf48_d0bb, - 0x4888_2a9e_e612_5ebd, - 0xa857_f300_33cd_faaa, - 0x0c0d_d8b5_2910_9f77, - ]), - ), - ( - pallas::Base::from_raw([ - 0x63aa_2c76_cd16_571b, - 0x6708_27ee_f35d_9eee, - 0xf732_370c_ed30_8f28, - 0x2ce7_690f_9c45_b228, - ]), - pallas::Base::from_raw([ - 0xcf08_8fe5_d2da_2200, - 0x6b75_35a5_3b79_5a4a, - 0x6cdd_78c6_35eb_3d58, - 0x088b_da57_e794_bed4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4f92_90f2_3582_04fa, - 0xbc25_9bd5_ce7a_6e0f, - 0xe944_7dba_fd99_596a, - 0x2151_a369_bbea_a627, - ]), - pallas::Base::from_raw([ - 0xc11e_3f08_4d99_83d1, - 0x3a2d_880e_3a7b_619b, - 0xa9ce_df46_75f2_11fc, - 0x153b_e140_8a41_79a8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x16b4_ed0b_32aa_4e15, - 0x5d02_9826_e003_163e, - 0xa674_90a0_12f9_fec2, - 0x13b1_0df3_13d4_e0de, - ]), - pallas::Base::from_raw([ - 0xfac3_5814_0dbf_6fc9, - 0x8d97_dbe3_f3dd_64d8, - 0xf604_80c5_b973_198e, - 0x0e44_6ba1_c4c7_30fe, - ]), - ), - ( - pallas::Base::from_raw([ - 0x53e5_02ce_d667_b3fc, - 0xbd6f_f292_2d35_b631, - 0x511e_7681_0c78_b289, - 0x35d9_b968_f2eb_c3a6, - ]), - pallas::Base::from_raw([ - 0x4b3b_f3a7_1759_3f8d, - 0x4820_7638_9976_7ebf, - 0x1549_6703_964e_4f60, - 0x153d_81a1_43f0_33f0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x31ba_52fc_3de5_ff01, - 0x376a_2b41_b9d1_ece2, - 0x62fc_8331_dce8_2da0, - 0x118f_5744_f6ac_a780, - ]), - pallas::Base::from_raw([ - 0xb1e6_df68_1ea7_f7a0, - 0x40ad_d363_1deb_f495, - 0x41bc_dabb_085f_cb8b, - 0x364f_f020_42c1_2247, - ]), - ), - ( - pallas::Base::from_raw([ - 0x36b4_1638_0c9e_d00e, - 0x51e0_bfdc_10a4_d1db, - 0x913c_5835_4ab5_aeab, - 0x0fab_7d64_6a29_1389, - ]), - pallas::Base::from_raw([ - 0x3321_18a5_c438_99ab, - 0xaf16_ef69_ec9a_ffa2, - 0xc1b2_59aa_af0b_d100, - 0x0575_6607_ef7c_7347, - ]), - ), - ( - pallas::Base::from_raw([ - 0x74e0_0818_faa1_9834, - 0xfb98_2b7c_6bed_60fd, - 0xdde3_235a_2ebd_4674, - 0x215a_5274_fda3_f4b6, - ]), - pallas::Base::from_raw([ - 0x106c_9783_c54d_cdce, - 0xe128_7246_1a71_5454, - 0xd4f3_6b85_c93a_1dc3, - 0x0c6e_92c5_d9f9_4b70, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1b65_d726_c0c0_4615, - 0xbf8b_e863_197b_7eda, - 0xaad7_e0b1_2452_bfd1, - 0x3511_415c_a5d8_9c89, - ]), - pallas::Base::from_raw([ - 0xd833_0a78_4996_6f63, - 0x30e1_6447_4b6b_f6d4, - 0xcaff_7c50_1359_107c, - 0x0952_ff5e_91f1_5c61, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0d03_79de_a34a_e974, - 0xcc94_561f_8673_d71a, - 0x131a_c0e3_d11b_fdbf, - 0x25f8_c019_6ac7_41d8, - ]), - pallas::Base::from_raw([ - 0xc14d_3404_894d_304e, - 0x1683_69a9_6ab3_16e9, - 0x3735_bc70_cd9c_eda8, - 0x37b4_443a_f523_48a5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9956_1c6e_192e_7568, - 0x65e7_be87_d79a_44a8, - 0xc477_1369_88f7_cfa5, - 0x2e08_d2d1_1f6a_f91f, - ]), - pallas::Base::from_raw([ - 0x8a16_6878_cf4d_afeb, - 0xabb3_04d6_e705_de6c, - 0x0859_c814_89dc_15a7, - 0x274d_0775_a079_b46f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdb3d_11a8_4fa8_eb13, - 0xea3a_7ea8_9ad3_d6af, - 0x9981_af35_3af1_4cae, - 0x2b38_c01e_7ae8_dfd9, - ]), - pallas::Base::from_raw([ - 0x830d_dec0_3c06_8077, - 0x422d_fa90_51e2_eb38, - 0xb8f7_0d0d_d10c_76bc, - 0x059f_5d67_0e51_88ac, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd910_97f8_e2bd_e10e, - 0x2f49_4c52_8f28_53a0, - 0x18ce_d481_b3ab_923b, - 0x25d9_e3db_a718_8482, - ]), - pallas::Base::from_raw([ - 0xd5a7_8005_ba95_0986, - 0xcaff_2367_d76d_2556, - 0xfd49_0e15_d2f5_1094, - 0x04ec_51a9_732e_c101, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9f75_b055_2d08_c237, - 0x8f7b_40f6_b94b_551f, - 0xff0a_1d65_6512_02d4, - 0x3259_3507_44ad_2a0e, - ]), - pallas::Base::from_raw([ - 0xc3b0_007b_5635_87fc, - 0x67fe_664c_1556_008b, - 0x3933_d14e_7c90_a14b, - 0x08dc_b066_37f5_9ef5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x66d6_5691_d7f4_6f1e, - 0x5774_25e4_a039_ed7a, - 0xfe27_c3f5_c7dd_098b, - 0x1daf_b77a_22f1_a231, - ]), - pallas::Base::from_raw([ - 0xa3bf_e610_9f9d_ac9b, - 0xa538_e6f2_5314_865c, - 0xd48c_5619_13f2_6135, - 0x267d_66bd_ebc3_5567, - ]), - ), - ( - pallas::Base::from_raw([ - 0x22c0_55b7_005a_fd9a, - 0xfbe9_5fb4_544d_dfc1, - 0x48d5_2641_43d1_c6cc, - 0x37c3_a72a_ea7a_3c08, - ]), - pallas::Base::from_raw([ - 0x77e1_afd5_eb2f_d2a4, - 0xbfcf_76bf_248c_529c, - 0x8589_07aa_9ffa_a44a, - 0x288a_b3ad_a23d_9811, - ]), - ), - ( - pallas::Base::from_raw([ - 0x847f_2f2e_b09a_a283, - 0x2874_cbee_5fec_a088, - 0x34d9_fc8d_9af2_8672, - 0x3e01_114f_d579_ff35, - ]), - pallas::Base::from_raw([ - 0x5504_d237_2254_c60b, - 0x8f8f_14cd_6ba7_b727, - 0x7539_9f3f_1180_d507, - 0x1977_5697_8320_c24b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x21d8_677d_a4ef_3754, - 0x970f_79ca_c4fe_71cc, - 0x9202_5638_93e7_a2f0, - 0x276c_3165_597d_8172, - ]), - pallas::Base::from_raw([ - 0xcddb_83d9_a9a1_4fee, - 0x05fa_2b1e_95df_ce2c, - 0xd58c_11ef_e1b6_7c84, - 0x01c7_cbc6_23e0_fde1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5dc4_11b7_be41_9bf8, - 0x6102_61de_71fd_509e, - 0x93df_5fe5_4b6f_15c1, - 0x2b17_a62a_ef55_fc8c, - ]), - pallas::Base::from_raw([ - 0x13e9_27e7_5428_fe43, - 0x3d07_6e3a_5358_d948, - 0x321d_9085_07a0_7394, - 0x2648_17bc_3f85_f5f9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xda55_668c_c5c9_544a, - 0x7dd5_42c2_06f1_4ae9, - 0xb88a_afeb_3d1c_ee22, - 0x1a12_25c2_42a6_d6dc, - ]), - pallas::Base::from_raw([ - 0xd8d8_02d6_7061_f4e7, - 0x1a21_e3e6_ed3e_e0e2, - 0xcbe5_9238_89e5_856b, - 0x0390_44ab_2e17_bd89, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3ae8_41df_e3b7_290b, - 0xf13f_ecde_fd80_6170, - 0xac39_a24e_4ce5_3f97, - 0x26ce_75c5_b2d5_e122, - ]), - pallas::Base::from_raw([ - 0xe473_f056_dc79_115d, - 0x76e3_15a5_ad62_0dae, - 0xa313_6c1e_483c_9721, - 0x3e6d_83ea_86d5_d926, - ]), - ), - ( - pallas::Base::from_raw([ - 0xae2f_741a_d983_16f1, - 0x382d_5858_cf9d_44bd, - 0x384e_98ab_f72d_0fbe, - 0x30f3_d34b_406d_3804, - ]), - pallas::Base::from_raw([ - 0xc245_5362_2247_8063, - 0x3e17_2608_60b4_bb4b, - 0xb86d_dafc_c500_27d6, - 0x2fe8_4841_5f29_2c18, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7b6a_1128_3c3c_80fa, - 0x9ca2_b9c2_dff3_f3b4, - 0x340f_f261_7ed1_3780, - 0x3e0c_e5ac_ec7d_2bec, - ]), - pallas::Base::from_raw([ - 0xd741_2e2b_3d37_fb89, - 0x6247_866a_c8b1_fed8, - 0x6f6b_0239_2805_590c, - 0x0ced_382c_9268_f3f4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf517_dcec_62e9_e3ab, - 0xef0f_7eeb_1b0c_6735, - 0x8b97_f27c_70f9_37cf, - 0x3b8f_7d37_f83c_eefc, - ]), - pallas::Base::from_raw([ - 0xc89c_a8e6_7126_cae0, - 0xbb34_8af9_7905_e208, - 0x454a_e56d_15e2_6ff5, - 0x1e45_8d1f_2c82_bdf4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8f21_d255_acaa_5b90, - 0xe729_e5a0_0840_e7fb, - 0x56c6_9b75_0b63_eb5d, - 0x1eaa_c9b9_4cc3_82f7, - ]), - pallas::Base::from_raw([ - 0xa370_d467_d4f0_adf4, - 0x5ec1_c5cf_197c_0be2, - 0xc1cf_51f4_f03f_6d42, - 0x09fb_0444_4edc_27ff, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb12c_0d2f_205c_31fe, - 0xeea6_f71c_6bfb_1591, - 0x67af_0a9c_f750_03b2, - 0x0398_bc66_1d37_47e7, - ]), - pallas::Base::from_raw([ - 0xcfcb_c59b_a71c_e886, - 0x13c5_dcea_abed_f8e3, - 0x94cc_f92b_e337_137f, - 0x0684_13f8_7199_260e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf82d_26f7_308d_982b, - 0xa463_f795_5164_d737, - 0x943b_0cdb_2a01_2793, - 0x36dc_43c7_d977_77d2, - ]), - pallas::Base::from_raw([ - 0x28d0_729c_c900_9cd4, - 0x95ce_751e_83b7_6438, - 0x7f75_8d0c_1ee4_d82f, - 0x0484_975c_8703_23b2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x573b_6407_c295_bc03, - 0x3d81_4362_3653_b276, - 0x715a_5538_1619_6299, - 0x1a2d_544c_2924_13dd, - ]), - pallas::Base::from_raw([ - 0x35eb_0d37_a82a_ebb9, - 0xc43b_bf74_7668_ff2b, - 0xb086_e27f_cabe_e36f, - 0x2aa3_498b_0d5e_e868, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbdc2_bfad_362e_4e45, - 0xe6a5_1dc4_a99d_9290, - 0x7a7b_06f1_60f6_7d5d, - 0x19cd_8877_65a7_d9d8, - ]), - pallas::Base::from_raw([ - 0x8d51_6305_64ff_936f, - 0xfadb_c64d_5013_97ef, - 0xc69f_7c0f_10e4_e5bc, - 0x2d2a_dbea_d1b6_989d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x583a_b4b1_cd55_7263, - 0xaae4_f810_312f_8c56, - 0x2f23_2a1d_07d9_df4d, - 0x2fba_b5a3_c4c6_773a, - ]), - pallas::Base::from_raw([ - 0x73e5_4412_d35d_bef2, - 0x3ece_87a1_67ec_e5a8, - 0x9223_f63f_59e9_6781, - 0x0ee5_e010_f598_055d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2969_6dcf_d0f2_45a4, - 0x8277_fcbf_73c3_66a0, - 0x6841_c274_1f99_74cf, - 0x3709_2e4c_18e6_289b, - ]), - pallas::Base::from_raw([ - 0x838f_2b53_2d37_f282, - 0x81dd_5e60_c4b0_6016, - 0xfc7c_b034_4511_4e5d, - 0x32ff_9c63_4da9_341f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9ff0_ae31_0044_5d6d, - 0x7cd8_e22c_968c_f64e, - 0x6ec7_7099_fd3f_bc2d, - 0x03ed_d409_4ace_757a, - ]), - pallas::Base::from_raw([ - 0xb949_d0f4_aa7d_daab, - 0x9579_75a6_e421_ce51, - 0xe387_f7c9_68d4_199a, - 0x1076_83d8_acc2_378c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7c36_ca16_0d02_f992, - 0xb3c4_7744_bd2a_cf1b, - 0xd4fa_877a_2a8e_237d, - 0x1394_a3da_f7c5_819a, - ]), - pallas::Base::from_raw([ - 0xb613_5e52_1b63_455a, - 0x4bf9_1fa0_ac38_e15a, - 0x81d9_9f64_1be8_55b6, - 0x2224_1b8b_d75d_1421, - ]), - ), - ( - pallas::Base::from_raw([ - 0xceb4_5f69_b989_fe1b, - 0xb7e7_93ed_c797_8d45, - 0x3b07_5a63_4103_0c39, - 0x2d76_b68f_6c00_d2e6, - ]), - pallas::Base::from_raw([ - 0x3ac8_1f11_ce1f_0c3e, - 0x5065_af29_2ab5_050c, - 0x8ac1_305a_a9ba_43f1, - 0x1697_81ba_e7d9_3067, - ]), - ), - ( - pallas::Base::from_raw([ - 0x20fe_f089_d835_a48f, - 0xcb23_7766_d607_2a64, - 0x18ef_0b57_dd7c_3b7c, - 0x1a3d_5f57_8f57_a4a0, - ]), - pallas::Base::from_raw([ - 0x2574_2597_3e32_c989, - 0xde95_cb1a_38b5_9aee, - 0x5e69_c45a_328e_ae08, - 0x12fa_3870_5145_9017, - ]), - ), - ( - pallas::Base::from_raw([ - 0x54cc_b71d_b115_00f3, - 0xeae2_7b08_c955_4e07, - 0xd7ac_a091_6e33_815d, - 0x0924_e273_11dd_a853, - ]), - pallas::Base::from_raw([ - 0x6d61_f93c_cce9_942a, - 0x2d9e_5dd1_7e83_e833, - 0x8410_7aea_6d67_f750, - 0x3cbe_6e62_757c_a1a5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7496_11d0_b797_7376, - 0x91ee_1646_4ccd_ec34, - 0xa71a_ee11_a82a_121a, - 0x0b9f_4bbf_d185_de95, - ]), - pallas::Base::from_raw([ - 0xd157_72cc_ea7e_a26d, - 0xd171_58db_8708_6d27, - 0x6093_1fae_1eea_2b4d, - 0x34dc_4613_b828_dd99, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1fbd_03d8_1ee5_f96f, - 0x371c_9782_b691_077a, - 0xf52d_f5a7_19bf_5ce5, - 0x02d6_cab2_451d_9d53, - ]), - pallas::Base::from_raw([ - 0x19b8_5371_5e90_f9c3, - 0x6e1e_109e_62b7_e02b, - 0x4302_b72c_1d4a_5b35, - 0x10b0_be6d_e221_46f8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x24cf_34c7_81aa_7322, - 0x3247_bd2e_b1c4_5ee3, - 0xf9ae_4378_0413_ea39, - 0x0d16_dcb8_7865_78a6, - ]), - pallas::Base::from_raw([ - 0x9d41_e502_3ba7_b1c8, - 0xfe5e_2c86_fc66_1a81, - 0xe729_c0d6_427e_0fc3, - 0x05f3_05ca_4971_05cb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1afa_a868_252f_7b9d, - 0x9e19_617b_52e9_b42c, - 0xd5f4_449d_e9e3_f183, - 0x322a_0e11_63ce_20e8, - ]), - pallas::Base::from_raw([ - 0xb391_cb0a_6351_bf73, - 0x610b_1f7b_4f5a_6acd, - 0x3a76_9f31_cd20_aa26, - 0x3ce3_28a2_561b_bf67, - ]), - ), - ( - pallas::Base::from_raw([ - 0x30c7_9e39_fd40_3fb2, - 0x1d82_1256_916f_f504, - 0xfe73_efde_65d6_2b6b, - 0x2994_4742_c6a3_4de2, - ]), - pallas::Base::from_raw([ - 0xaa6e_9941_b2a5_4d17, - 0x50e2_4496_1b34_d4ca, - 0x6b06_42c4_a199_cb45, - 0x01f3_609d_eefd_a00c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4bab_06a5_e077_4a9e, - 0xa330_3b42_52bd_5399, - 0x4bb4_1f7b_e729_9520, - 0x3e21_edef_d0eb_fab4, - ]), - pallas::Base::from_raw([ - 0x464c_145f_cb64_99e5, - 0xdf35_61b7_1aca_4810, - 0x04bc_58fc_3756_5635, - 0x1c58_279a_6bbf_5750, - ]), - ), - ( - pallas::Base::from_raw([ - 0x99f4_f0fe_9dc0_ca44, - 0x02fb_d682_b042_1702, - 0x2efe_f131_2968_d890, - 0x15e2_222e_6db1_4410, - ]), - pallas::Base::from_raw([ - 0x67a0_83e2_c99a_0667, - 0x23ab_d14a_6bd2_87fb, - 0xabdd_eb1e_2a5d_fdb0, - 0x0b60_960a_be90_667e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc740_684e_ba5a_4faf, - 0x4c22_ce95_137c_c36c, - 0x281a_a42b_c45a_2b1a, - 0x376b_146b_97e0_9a59, - ]), - pallas::Base::from_raw([ - 0xc4ef_bdb0_982a_e289, - 0xf554_a7b6_564c_83fc, - 0x8a67_d20f_be31_f8df, - 0x2c37_9f03_4178_6df6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2ab6_2fa8_4b1f_8e4f, - 0x5604_7652_51e0_d7d4, - 0x861d_2eb4_6261_0b9b, - 0x31c4_e0bd_450e_6e50, - ]), - pallas::Base::from_raw([ - 0xd8d3_3e9e_f72a_be1e, - 0xb803_ee7b_7f4a_6cef, - 0x9a3c_b438_0c39_4da6, - 0x1228_8e27_13b3_b5f0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1d8c_119e_1fea_0f3e, - 0xcf48_8423_afc0_a753, - 0x0b6e_dc85_421d_1af4, - 0x261f_f1dd_ff1f_5d8e, - ]), - pallas::Base::from_raw([ - 0x0199_5750_d19e_6caa, - 0xad1d_82df_b749_8ed4, - 0x247b_d709_b691_31b7, - 0x2539_b879_15a5_f780, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7589_fb80_f8e8_939a, - 0x9ebd_0810_d45a_bccd, - 0xfdba_79ca_0ccc_9b44, - 0x1aa0_1aea_8f5d_c980, - ]), - pallas::Base::from_raw([ - 0xa555_fa27_6b83_e30b, - 0x578f_1dd3_8ca4_8a1b, - 0x1df7_d102_f86b_370d, - 0x394a_4663_4e33_5391, - ]), - ), - ( - pallas::Base::from_raw([ - 0x20a6_ffb4_b2a0_6005, - 0x92eb_8f71_fb24_c4e2, - 0xaa8d_0967_96f7_84f8, - 0x16e3_1607_8d0e_330d, - ]), - pallas::Base::from_raw([ - 0xdd44_1a60_d432_5070, - 0x4b11_771a_1b21_7b5b, - 0xcd9b_504e_26da_2f48, - 0x300a_ebe3_2a72_477e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x744f_4c87_d1d4_508c, - 0xb3ec_6058_d948_a573, - 0xc4cc_b479_43b9_9fea, - 0x292e_928f_7ceb_3ff2, - ]), - pallas::Base::from_raw([ - 0x87ce_4476_03d0_27ad, - 0x9bb9_90ca_e688_0b20, - 0xc92d_41da_e465_745a, - 0x0223_81f5_2d29_279c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0762_3807_30d6_1de3, - 0x1edd_e3f3_3771_cc05, - 0x1b7f_051c_c2b6_4ab3, - 0x0453_ef02_8a0a_0e93, - ]), - pallas::Base::from_raw([ - 0x4af4_208c_5106_b83f, - 0xa12f_0bb8_1911_e9b2, - 0x8d23_55e3_13ca_6284, - 0x199a_c626_77dd_e42d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa5d5_078b_65a5_31cb, - 0xd6d4_d396_40a8_dead, - 0x7395_10a3_2e84_194a, - 0x0746_7e7f_2d24_b2da, - ]), - pallas::Base::from_raw([ - 0x2aca_d55d_1851_65e5, - 0x0fb2_146a_77c9_c7ad, - 0x4a21_f9c7_5a25_793d, - 0x051f_b653_7e5c_669a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5c77_2c3e_2739_e3fc, - 0xfef3_5127_c5dc_20fd, - 0x93d1_092b_43f0_b004, - 0x3610_1ab4_3a30_2e81, - ]), - pallas::Base::from_raw([ - 0xa206_2c8a_6927_2961, - 0x95ae_1eda_33fe_553c, - 0x0c55_8ed6_13c3_1d9f, - 0x2679_b3ad_0bb1_f518, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4c99_4a2d_9356_6587, - 0xdeeb_0d82_95d1_2d60, - 0xe1c2_2593_45ec_8dc4, - 0x2a35_d2f2_3772_88eb, - ]), - pallas::Base::from_raw([ - 0xdd98_203f_af9d_ee4d, - 0x5c66_2c8c_c521_19b8, - 0xa63e_cdcb_8480_514e, - 0x18da_f4d5_332a_1baa, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd84c_d0ad_ccfa_70c3, - 0x007c_d209_cc31_09a0, - 0x78ed_585e_3225_fa0f, - 0x039e_aa43_428a_bea0, - ]), - pallas::Base::from_raw([ - 0xb8f7_04f9_aa61_c65c, - 0xb502_1eee_d781_1fd1, - 0x5e3a_d1e1_0641_c3b6, - 0x286d_2d99_97fb_09c8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2f16_78b3_f543_9c73, - 0x9f1b_1cdd_d30a_111b, - 0x1601_479f_9b32_834d, - 0x17c1_c1b6_9420_721b, - ]), - pallas::Base::from_raw([ - 0x5b68_0b72_90c2_201a, - 0xf9f9_cb4d_b01a_bc23, - 0x1d4e_6bd4_f26a_e504, - 0x389d_e069_5988_822f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb1cc_a546_a26c_bd86, - 0xd581_36f0_8d48_7530, - 0xc022_5c61_93c4_2f07, - 0x3900_59d2_1cdc_6bd4, - ]), - pallas::Base::from_raw([ - 0x6b0c_72de_318e_22d4, - 0xc25b_9e3a_542f_b6b6, - 0xa7a8_06e6_da9f_7440, - 0x3c2a_71ce_4326_8d4d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x50e1_11a2_0489_f122, - 0x07db_1ada_fd5f_8ecb, - 0xf6a6_51ee_1f90_02b9, - 0x25dc_8f85_41ca_57ca, - ]), - pallas::Base::from_raw([ - 0x8241_e6e0_c4ed_eedc, - 0xe1db_5a05_57a0_5392, - 0x4b07_d4a1_6ee5_32a3, - 0x1d1a_0c97_70ed_f432, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb26b_68f6_0086_71f4, - 0x75db_a00b_0b9e_4307, - 0xd9a7_65b7_c82f_711f, - 0x2765_f4c0_27cb_e853, - ]), - pallas::Base::from_raw([ - 0xb2a7_d024_e97a_b65b, - 0x1df5_ee26_7727_2a6d, - 0x6c0e_4551_c789_273d, - 0x27a1_7d99_2875_639d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdb10_fcfe_4260_d68d, - 0x7154_7c95_a7be_2663, - 0x1258_286a_d0ce_a1a3, - 0x27df_52ac_88e9_47ea, - ]), - pallas::Base::from_raw([ - 0x3d4e_5b53_00c3_0fb7, - 0x93f6_bee4_3688_6e32, - 0xbce4_cf1c_bdd9_555d, - 0x2046_32cf_c355_10e2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8b7c_28f8_d7ec_c2a6, - 0x3484_bab7_04d2_2a17, - 0x68eb_5538_e6d8_bfcd, - 0x0408_8d25_0509_fd2f, - ]), - pallas::Base::from_raw([ - 0x57f8_018e_752e_b908, - 0xc709_94e2_3360_b3e9, - 0x31b5_e0c5_969a_1364, - 0x241d_3b9c_b64c_1c51, - ]), - ), - ( - pallas::Base::from_raw([ - 0x070f_a907_6332_8b37, - 0x80b7_7fc9_f7d1_454e, - 0xa851_ba95_b01c_9b9f, - 0x104f_1754_7220_df3c, - ]), - pallas::Base::from_raw([ - 0x7dc8_7e53_05e7_19fb, - 0x338f_f6d5_fbd5_8b87, - 0xf8c5_e720_14f7_325f, - 0x0309_fefc_0c51_fe88, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb33e_8147_9cf8_1580, - 0x3d43_f778_431a_39d8, - 0xca34_2567_f8af_16d1, - 0x3113_430a_214b_0cdb, - ]), - pallas::Base::from_raw([ - 0x13c9_5973_0b4f_4399, - 0xe534_1a6e_c65c_a2b0, - 0xcb52_a623_3314_e4d3, - 0x2ced_c552_f9fc_da21, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe2f2_d321_bc0b_2ca7, - 0xb252_6d8b_b9f2_415b, - 0xbf60_2a8f_52fe_1001, - 0x3d68_f289_95eb_8ebc, - ]), - pallas::Base::from_raw([ - 0x15bc_988c_f260_e0ae, - 0xd3fe_7253_a715_73b4, - 0x5d6e_a086_5a30_55b9, - 0x08ef_9afd_ec67_40fe, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4fa6_d6c3_91be_c514, - 0xb5a8_3229_b864_ecb8, - 0x3559_3f27_4198_2167, - 0x1402_abd3_64b4_91e4, - ]), - pallas::Base::from_raw([ - 0xad4f_91b5_5f82_9cbf, - 0x6078_24ce_bd17_46c1, - 0x8941_5aad_ad35_5caf, - 0x1e1d_54b1_8e31_aa02, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf268_ffe3_ff17_92f0, - 0xd30d_826d_c124_7ab7, - 0xd835_dea8_0451_546a, - 0x07f3_787f_5b1b_6728, - ]), - pallas::Base::from_raw([ - 0x06be_7c30_22da_5b48, - 0x6119_b0af_e57e_eece, - 0xffb2_ef93_3bd0_ebed, - 0x0169_f72c_db1b_2fcb, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe456_2834_294b_888d, - 0xbcfd_513b_64f2_5684, - 0xf08e_b8fb_c4ab_d423, - 0x0fb6_00e3_c86b_b49f, - ]), - pallas::Base::from_raw([ - 0xe7bc_fc0e_3b3f_f8de, - 0xbea6_5eea_f9ae_d71e, - 0x70df_ec85_cd8a_1b58, - 0x19f6_5367_896c_d8a6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x34fa_bfcf_3c22_1b33, - 0x044b_883c_d5c6_097b, - 0xbfb0_715a_00cc_0c7c, - 0x0679_54d0_2044_c9f5, - ]), - pallas::Base::from_raw([ - 0xd919_1bda_61df_8d07, - 0x6d2a_a446_a685_4475, - 0x92bc_bfbb_a58a_db13, - 0x065a_ecfb_ba1c_4f39, - ]), - ), - ( - pallas::Base::from_raw([ - 0x86c3_eb48_7c88_bd57, - 0xdb8b_d4d0_11d2_f88e, - 0xfad8_69ea_a7e4_4dcf, - 0x3022_30ed_6e9c_6e28, - ]), - pallas::Base::from_raw([ - 0x0fbe_eda5_bba2_91f6, - 0x92ea_6a64_ab91_359a, - 0x2e65_7270_4b8b_8373, - 0x30fd_7673_e584_02f4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xea84_2eab_a955_bf3a, - 0xa20d_8ca2_651d_19b9, - 0xab2e_3150_8ceb_fb7a, - 0x3aca_f491_8373_e853, - ]), - pallas::Base::from_raw([ - 0x44ca_a4f6_92ec_ca97, - 0x2b2e_4b9a_22ac_d3d3, - 0xbc30_279e_ff7b_e6aa, - 0x3b91_6c71_845b_1715, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1202_b03b_21d1_d047, - 0x03ae_5752_aa54_b5be, - 0xc925_4108_2eaf_2a3c, - 0x13ad_e51c_5d29_0b7a, - ]), - pallas::Base::from_raw([ - 0x8041_8cdc_5c36_974c, - 0xd604_0473_1a81_c29f, - 0x23a2_ba06_9389_1b6d, - 0x266f_9adc_4b16_36a1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9afd_aa5e_40ca_0c02, - 0xa358_984d_a414_8a51, - 0xacd4_cc7c_9942_0f78, - 0x2187_c185_232c_318b, - ]), - pallas::Base::from_raw([ - 0x8a81_3d5d_499f_4580, - 0xa513_113e_dfa2_d826, - 0xeb8d_fef7_f22d_f466, - 0x2031_fd3b_4359_99d0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x038e_6561_3318_309a, - 0xfbbc_cc98_6867_1618, - 0xc078_f45f_0b90_87ed, - 0x30f2_e8ef_849c_bdbb, - ]), - pallas::Base::from_raw([ - 0xa36b_5a01_49ef_da91, - 0x7a95_de96_1b20_9374, - 0xecca_06aa_0f3b_5ab8, - 0x31dd_63b8_64cb_de15, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4796_b297_f98e_93b3, - 0xf493_b341_1ed9_021e, - 0x1959_49f0_5a11_c922, - 0x35c5_a032_4cc5_8786, - ]), - pallas::Base::from_raw([ - 0xfe71_cea7_2663_1804, - 0x3b35_545d_e5bb_07ed, - 0x1e0c_8c02_6408_9be0, - 0x24b2_4b27_139e_827e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf33d_521e_4818_701b, - 0x0ed0_6b9b_4fb1_12eb, - 0xd38d_f6b1_d568_5738, - 0x2f83_54a3_e364_1f2d, - ]), - pallas::Base::from_raw([ - 0x2f57_b58b_8e5d_489c, - 0x88b1_ab17_4dc3_61c5, - 0xfffe_6160_1707_a091, - 0x0797_75d9_3fd9_4026, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7d09_4b08_9f06_34e0, - 0x3260_4273_2097_b4f3, - 0x2d95_5d56_8f05_4ae3, - 0x2094_83e1_a0b0_a837, - ]), - pallas::Base::from_raw([ - 0x7432_cb32_c68b_2165, - 0x7bd9_2165_7fb0_2d3f, - 0x0f8e_cd9e_6143_ed8a, - 0x1e80_5fa9_b94a_ec49, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5113_896c_8344_ca04, - 0x3ef8_8140_14dc_b062, - 0x4412_402a_64e3_8636, - 0x2ca2_c0ca_7fdf_3aab, - ]), - pallas::Base::from_raw([ - 0xaed4_11b6_dd39_334e, - 0xacbf_64e8_3c88_59f5, - 0xc68a_900f_bbf1_8b0f, - 0x35c2_a197_59b7_ad1c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3d3e_18af_68d8_62fa, - 0xe3d5_0649_7f05_6b13, - 0x4e45_faad_be7b_7fd3, - 0x1859_da3e_20cd_e957, - ]), - pallas::Base::from_raw([ - 0x645d_a090_f36a_e749, - 0xd41d_b3b2_a046_2af1, - 0xa96d_2c5e_6597_3c58, - 0x141e_1418_8f51_e0d0, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdabb_00be_7a67_fef0, - 0x5c7b_cf1c_6ad7_edda, - 0x936c_f456_316c_55a1, - 0x0d3a_6bba_e167_7f06, - ]), - pallas::Base::from_raw([ - 0xd39b_8075_0060_baa3, - 0xe8e3_40fa_3051_61af, - 0x195d_c44b_0585_652d, - 0x00d3_796b_0ba9_07d1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0f72_b95e_c033_1d81, - 0xc509_70b4_8e36_3af0, - 0x8d67_3023_a716_fcc4, - 0x012d_485d_fb24_6814, - ]), - pallas::Base::from_raw([ - 0xed91_6bb8_2624_17de, - 0x426d_028d_0170_49d3, - 0x398f_1550_b9e3_0d8c, - 0x0918_c246_acb5_fdee, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1293_b9c9_0725_4044, - 0x4088_0cdf_1a2f_acdc, - 0x4de3_cd80_f405_03be, - 0x21c9_dc8c_e021_5c1d, - ]), - pallas::Base::from_raw([ - 0x2a0b_32e0_23d9_a3bb, - 0x8dfd_3300_2c4d_a85d, - 0x90fa_fa54_eadc_032c, - 0x2b22_e6b4_d976_bb94, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7f67_fb22_3643_6df5, - 0x8cb7_a940_6905_bff4, - 0x0700_85c6_481f_f20a, - 0x2c67_6bf1_c4b8_6158, - ]), - pallas::Base::from_raw([ - 0x7cf1_8c00_4a9c_1a9e, - 0xf931_e68f_a15f_b06c, - 0x4b5a_0021_677e_9587, - 0x2fb0_f64a_a35e_6c60, - ]), - ), - ( - pallas::Base::from_raw([ - 0x980c_1135_0270_595f, - 0xda07_a0c2_5480_8a60, - 0xb0aa_67e1_dd15_8881, - 0x2075_e446_9ffc_c6fb, - ]), - pallas::Base::from_raw([ - 0x44d0_d6f6_aa0a_1932, - 0x862b_52b6_f304_e01b, - 0x690d_6e48_b517_135e, - 0x22e5_932c_6392_e33f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf261_d24d_d55e_fa46, - 0xe3a2_8ce1_2ece_2d1d, - 0xb6c3_ed0f_5de4_1a3c, - 0x1cb0_da91_1a87_cfa0, - ]), - pallas::Base::from_raw([ - 0x5442_5655_5336_1f42, - 0x089b_c245_a048_38f5, - 0x8dcc_4e66_7941_5a9e, - 0x34c6_80fb_1dd7_661b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2d65_9072_d56e_5b18, - 0x7987_24b4_22bd_dbf3, - 0xa346_5bd1_1778_6f23, - 0x3961_400e_4b13_e385, - ]), - pallas::Base::from_raw([ - 0xfd5e_6292_aed2_5d3c, - 0x4875_16bc_b3cb_783f, - 0x8e9f_fe18_293c_5856, - 0x257e_cda9_99c3_d0cf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8313_e47e_aa56_0f12, - 0xa288_d1ce_19d0_c1ce, - 0x0de7_47c8_24b5_d9ce, - 0x1ef9_17f6_6050_f9b8, - ]), - pallas::Base::from_raw([ - 0x51b3_c417_aae3_d512, - 0x308c_26cb_3ef9_b520, - 0x9e24_fee2_0510_c124, - 0x10c4_5920_4a45_09fa, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5354_70f6_26b1_1d0b, - 0x366e_2b98_c3f8_51b4, - 0xc02a_1aef_b019_705e, - 0x0ef2_f878_dec4_3a29, - ]), - pallas::Base::from_raw([ - 0xbbe1_eafd_c8f8_d6fb, - 0xba82_354a_c062_0fc1, - 0x4984_289a_d39b_917c, - 0x32b0_046e_bbd5_1e14, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe5af_e709_3216_cf73, - 0xce7c_ea62_2592_e580, - 0x073b_be3d_9d7b_463d, - 0x0205_976f_e9c1_b9d7, - ]), - pallas::Base::from_raw([ - 0x1eef_2946_b9ab_16dc, - 0x5513_ea0e_5cab_a5c4, - 0x0174_f38f_88f9_1425, - 0x16b7_f6c6_6548_4de9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x07cb_2e9c_7762_5c85, - 0x33f6_d324_7351_1aec, - 0xf7f0_ac0e_f1f1_e7ae, - 0x3e3f_c594_4e97_90ef, - ]), - pallas::Base::from_raw([ - 0xf286_21ff_e28c_23ad, - 0x44e4_45d2_2eb5_fae6, - 0xddc6_91ad_5bdf_57f0, - 0x36bf_156f_395d_dca9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd524_a165_4426_7d9a, - 0x1f66_2e96_84b2_aeab, - 0x2c89_6845_13b1_47ef, - 0x38c9_c6de_31d0_54f1, - ]), - pallas::Base::from_raw([ - 0x05ac_032b_5a68_e21d, - 0x13bb_ddc0_606c_20ab, - 0x3026_8ada_227c_8b3a, - 0x2d5b_3fbe_7b71_ff46, - ]), - ), - ( - pallas::Base::from_raw([ - 0x11b6_85e3_842e_c92b, - 0x9944_f4db_a624_498b, - 0x9fc0_d641_b040_6a97, - 0x1647_4f51_124c_377f, - ]), - pallas::Base::from_raw([ - 0x1168_60f3_af34_2dae, - 0x7805_c248_f3c3_fcc5, - 0x4813_d152_d1d3_098a, - 0x208f_c6df_823b_e5f9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc169_7a99_835e_be3e, - 0x5ef1_b7bb_3199_1aca, - 0x423b_d93b_fab8_c937, - 0x2967_35a3_0418_0bdd, - ]), - pallas::Base::from_raw([ - 0xbdb7_c009_07a2_d1da, - 0x368c_8c5b_b543_e0a1, - 0xc213_9520_868c_748e, - 0x0f8a_171f_46c2_fe7c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6adb_fb16_aac0_e0c1, - 0xe670_9f7f_a329_f25c, - 0x0345_3350_36cd_ada1, - 0x067c_220e_1a5d_efb7, - ]), - pallas::Base::from_raw([ - 0xeffb_7a08_1fd4_52ca, - 0x91c5_539e_3995_fa41, - 0x949f_e270_b209_2bc2, - 0x0c94_eb80_956c_63f5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x76ce_f08f_c4b9_3ce9, - 0xcd65_00bb_d889_d19b, - 0xcb76_bc91_e514_c0ba, - 0x2676_b3ed_f17f_cc35, - ]), - pallas::Base::from_raw([ - 0xa6ee_7cfc_440d_3bb1, - 0xf9f0_fa37_559f_b568, - 0x5c75_9922_987b_e0fd, - 0x18ba_9b25_9fb9_1ecc, - ]), - ), - ( - pallas::Base::from_raw([ - 0x88aa_9070_b7aa_f1e5, - 0xed19_124a_2b33_bb67, - 0xe56e_e569_c5d2_f813, - 0x3c6d_3d48_689c_6545, - ]), - pallas::Base::from_raw([ - 0x2dd3_3c98_6d92_2737, - 0x4a38_67c9_cc68_d3c5, - 0x0dd8_104b_2350_8489, - 0x1220_a703_5129_d555, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf34f_b7dc_c29e_e3f6, - 0x68ff_419f_787f_d6b4, - 0xe113_6044_b650_fd24, - 0x0f07_bb4e_3f0a_06bb, - ]), - pallas::Base::from_raw([ - 0xaf2f_3c9b_30d6_4868, - 0xb876_d0bd_eebc_8d41, - 0xd5e1_cfea_a531_971d, - 0x049f_733f_9545_e7b0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0730_f7ca_1dba_2634, - 0x229c_c86c_ac49_a95d, - 0x299f_5487_67f0_5bff, - 0x1ff0_6c6f_bbc9_7265, - ]), - pallas::Base::from_raw([ - 0x42d4_85b3_c343_fb9e, - 0xa6a0_b509_d7f4_32ed, - 0xea60_7525_3e54_c341, - 0x2c00_143d_8e9b_261e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8fda_58ae_2efc_f247, - 0xee35_0022_54f7_e10e, - 0x736e_f067_a1d8_6854, - 0x171b_73f6_f381_7bdb, - ]), - pallas::Base::from_raw([ - 0xc34f_b482_2878_1165, - 0xf1a5_16af_a161_fc8f, - 0x98c7_8cbd_6d9f_f721, - 0x3b38_7dd3_b99f_11c1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf52c_8ddc_ff5b_01c2, - 0x523d_70df_bd93_ca28, - 0x9c29_d3a5_c4c1_3774, - 0x31cd_fecb_38de_73c3, - ]), - pallas::Base::from_raw([ - 0xc68c_3f28_26b1_9cb8, - 0xfa8b_7593_0610_fe60, - 0xdef2_d495_2f51_9984, - 0x2221_6cb6_ddad_b185, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6bed_8edf_f3c0_d24e, - 0x99ef_37b9_cdba_a0d4, - 0xaf57_7449_65fd_54db, - 0x2704_ec4e_2419_ca44, - ]), - pallas::Base::from_raw([ - 0x8cdf_2bd0_b67e_b1c2, - 0x58f8_a33d_b426_e86b, - 0x653b_af62_fe66_967f, - 0x2326_7f58_4dce_4708, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6312_f284_adb7_2234, - 0x774f_0aa2_fa1c_ab96, - 0x7b2f_4ce7_137c_5695, - 0x0864_b203_83da_e0d2, - ]), - pallas::Base::from_raw([ - 0x731d_3ed1_53fe_b76c, - 0xcaf0_32bc_d5c9_4c3e, - 0xc4b6_0b28_83b2_aac6, - 0x2125_d63c_b9cf_c0b5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x53e9_3f17_a1d9_9759, - 0x5bbd_c73e_e01b_a020, - 0xacf7_bba6_f9d3_2f75, - 0x1952_c1c8_1635_6a75, - ]), - pallas::Base::from_raw([ - 0x66ec_f0b6_1af3_d4e0, - 0x571c_0924_ed6e_1a90, - 0x7705_b5de_1fc0_14c0, - 0x1fd7_5a22_f673_ea80, - ]), - ), - ( - pallas::Base::from_raw([ - 0x51e1_ea40_8c91_aad6, - 0x9db3_dc4a_6dd7_5da3, - 0x565d_5a06_e81f_9a96, - 0x0b2a_fb0f_ed99_5390, - ]), - pallas::Base::from_raw([ - 0xcb85_e6f7_24eb_eaa3, - 0x0ae7_3db8_9527_b9dc, - 0xcbe3_28e1_951c_7a68, - 0x2e2f_ae1a_239e_1571, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf958_eaa2_64c1_89d5, - 0xfd66_b7d1_121c_4ff7, - 0x34b3_6c0c_e96d_541b, - 0x0e73_8609_6c3b_0025, - ]), - pallas::Base::from_raw([ - 0x2cbd_19de_7f3b_b8ec, - 0x049d_9874_0dc9_177f, - 0xdc76_e494_dc8b_6c50, - 0x3c16_ea6c_a968_ab1a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x915a_adcc_89b7_daf3, - 0x2909_ff1c_0e1f_9785, - 0xd5bd_a128_019a_7ef2, - 0x3d37_fb8f_9eea_8d51, - ]), - pallas::Base::from_raw([ - 0x09be_e328_a080_f138, - 0xe673_5890_07fe_2120, - 0x2113_15e1_5d7c_9110, - 0x190f_69f4_eefd_5477, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9887_d028_c814_459b, - 0x0bfe_9714_c977_9a7d, - 0x09bc_a123_a070_2c37, - 0x2ab5_d63f_55f9_33ef, - ]), - pallas::Base::from_raw([ - 0x7704_3175_669a_cbaa, - 0xd2d9_3256_279c_aaaf, - 0x163b_f414_992e_0d03, - 0x2dd3_ad25_0723_378a, - ]), - ), - ( - pallas::Base::from_raw([ - 0xaa70_af4d_2c62_1ee1, - 0x82bf_76f9_a44f_e16a, - 0xd823_dfb3_28e9_1bf4, - 0x0e2e_86a7_8fef_50ce, - ]), - pallas::Base::from_raw([ - 0x96df_97dd_95e6_9e90, - 0xa340_7d75_e959_bcd6, - 0x8806_08c5_d89f_9255, - 0x2de3_b3e1_6dc1_2b33, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0c96_2934_58ec_b2cb, - 0x0d7d_864d_7d1e_560e, - 0xec28_d3a6_3cdd_c555, - 0x0de0_eb00_0263_741a, - ]), - pallas::Base::from_raw([ - 0x1cc8_207d_937b_6f0e, - 0x9797_e7ee_dc7e_c8c6, - 0x2286_088a_e441_e77a, - 0x242f_4811_c54f_c5a4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x02e6_08b8_b421_3091, - 0x04f9_d82c_26af_83fb, - 0x4d9c_e544_ba2f_2525, - 0x3f8e_e248_4851_a53b, - ]), - pallas::Base::from_raw([ - 0x9dac_0a3c_f93d_2ab4, - 0x7ed7_5569_f31b_ed67, - 0xb530_b73f_14e7_8731, - 0x320a_6858_c7ef_b1d8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf1c7_9c73_c18c_5bef, - 0xb4dc_fb27_be5d_af33, - 0x00fb_3437_a413_9ab8, - 0x27a9_6926_feb8_4658, - ]), - pallas::Base::from_raw([ - 0xf94f_9504_a805_5901, - 0xd816_70b5_5f8c_c186, - 0xd80a_41c9_3fca_d44c, - 0x35fb_6dfa_6996_faf9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbad4_1cc8_8afd_dd08, - 0x49d2_bda3_3181_eb27, - 0x6bd9_a42e_e764_f287, - 0x1bf9_7fbc_aad6_3dd3, - ]), - pallas::Base::from_raw([ - 0x9e70_14b6_b93f_3479, - 0x2ecd_3acc_85d9_0a8e, - 0x9adc_da24_387e_73bf, - 0x1e46_208e_ee13_e6a1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbefc_4b37_32e2_12e7, - 0x7994_0a4e_1943_82c7, - 0x31b5_2141_ba54_76cb, - 0x0dd7_b8d9_11c6_097e, - ]), - pallas::Base::from_raw([ - 0x878f_37be_45a6_24f7, - 0x9e03_f710_b58d_290e, - 0x9deb_aec0_79ca_08f8, - 0x00c9_3eac_1500_b8bd, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd808_eb89_0309_42fb, - 0xbcff_47e4_811f_e691, - 0x48a7_d2b6_7422_9156, - 0x228e_a752_e00e_fdbf, - ]), - pallas::Base::from_raw([ - 0xf199_ca0a_c24c_d4ca, - 0x6b0f_07a7_0752_8621, - 0x8d45_6536_032d_db36, - 0x0288_3b48_40b1_3378, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe693_43b4_9f9e_5b1b, - 0x89d5_ce6a_32fd_13c7, - 0x9ed7_6f5c_5aa1_9a97, - 0x2ec4_33c9_00e1_bbd1, - ]), - pallas::Base::from_raw([ - 0xeac3_ed86_403e_abe1, - 0xf6fe_9a5e_dfb8_8a4e, - 0x8f6a_6351_97b0_db20, - 0x1e2c_043d_0511_cfa2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9ab7_f215_baa3_94d4, - 0x1d8f_3e16_e38f_a26f, - 0x4159_fc19_7738_7456, - 0x00ab_08a1_f3c0_25db, - ]), - pallas::Base::from_raw([ - 0x7127_4247_2253_84aa, - 0xbb16_d239_fc1e_a68b, - 0x0e3b_b7c2_0be4_3570, - 0x100e_d9d7_3b76_9c8e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x42c3_aec9_48e9_24ff, - 0x9b63_1a8f_ca4b_f414, - 0x9ef2_f7fe_060e_a416, - 0x25b4_8d9f_f095_81d1, - ]), - pallas::Base::from_raw([ - 0x8ae4_2d3a_35a0_766e, - 0x104d_f6d8_e9cd_72d6, - 0x71df_5cb2_0423_2963, - 0x0899_58d7_7854_6236, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa5dc_0bad_a65b_67bf, - 0xf29f_e8a2_2244_b057, - 0x5511_3eee_8db8_b190, - 0x1210_c119_2f7b_d485, - ]), - pallas::Base::from_raw([ - 0x4b62_e8e5_60e9_df23, - 0xe625_32a0_2269_5edb, - 0x4afe_a317_bfa2_f9e4, - 0x0134_67f6_1d26_4b88, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd1d5_3c8c_9f78_209d, - 0x9713_2e54_9dc7_f6d1, - 0x9999_feb6_19e2_ce8f, - 0x1827_19c1_45b2_ad83, - ]), - pallas::Base::from_raw([ - 0x6440_07e8_0d1b_ebca, - 0xb59a_b45a_21c2_c8aa, - 0x37cd_166a_131b_bde9, - 0x3e88_79f1_0539_11ae, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2128_47a7_80b3_afd1, - 0xd62d_98a3_729d_147b, - 0xac76_cd5b_7780_e455, - 0x1371_d855_6493_7957, - ]), - pallas::Base::from_raw([ - 0x03c5_35ac_7821_d861, - 0x1897_7fb8_d4d3_21ff, - 0x57ec_5e9d_09d2_d94c, - 0x2933_8896_3d25_c33d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4c64_9009_4f5b_b733, - 0x2f25_149e_b638_123d, - 0x583b_d5e6_3c07_fe56, - 0x38d0_e3be_cf9a_d8fc, - ]), - pallas::Base::from_raw([ - 0x9482_7610_0282_f357, - 0x9035_4a5d_fd55_d474, - 0xdf90_065f_46d7_3461, - 0x1ee2_e8e9_a7f7_1162, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc2cf_20da_8325_f9f6, - 0x4158_322b_3ab5_e06c, - 0x55ea_0370_e75f_deaf, - 0x0491_5155_2307_b345, - ]), - pallas::Base::from_raw([ - 0x3a6c_b7c7_58d2_1156, - 0x3ee5_aca9_420a_c8d4, - 0x824e_78fc_93b0_042b, - 0x2300_ec5f_8679_d667, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4534_4de7_cd4a_1286, - 0x7000_9fbe_d545_bd95, - 0x56f3_45dc_329c_fe4d, - 0x1b11_0f10_4c22_8670, - ]), - pallas::Base::from_raw([ - 0x587e_67ee_4d03_0b13, - 0x26d6_4ee0_cfa1_e3fd, - 0x31a4_3dbc_e45b_3166, - 0x384c_1a74_cf99_7d87, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa739_b815_03af_5bde, - 0xfe73_4fc3_5916_3751, - 0x87ae_e2ab_a571_0f68, - 0x2880_7f09_fbdb_6069, - ]), - pallas::Base::from_raw([ - 0x959a_ef52_08c3_91fe, - 0x9283_4894_b296_c35c, - 0x4a5c_c47f_99f0_5f73, - 0x04a5_23d4_9550_e5f2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbbaa_a155_8473_a2f0, - 0x848d_48dd_594a_7097, - 0xe3dc_ec5c_faee_ddc1, - 0x3a8c_2c5a_d7c4_d92e, - ]), - pallas::Base::from_raw([ - 0x3bbc_7750_d4fe_2be1, - 0x70ba_0c48_e53b_baff, - 0xa804_5683_c10d_6804, - 0x1094_6631_c67f_0dfe, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3602_21c5_3677_ccd7, - 0x9de8_46d9_609e_11b3, - 0xc600_0f59_0fc5_e51e, - 0x12e5_6f18_ba2a_83f3, - ]), - pallas::Base::from_raw([ - 0xb472_c933_636e_7cfd, - 0x747b_505e_b1f1_252b, - 0x944f_8b8b_0fbe_9e69, - 0x081b_05b2_cc35_1fcd, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf69f_2736_a2e6_02cc, - 0x40b6_25b7_d5c4_621f, - 0x09ba_e2a7_4bc9_bc80, - 0x19b0_3942_3298_a1b4, - ]), - pallas::Base::from_raw([ - 0xab25_9c06_92dd_6ddd, - 0x8930_0e85_715a_2677, - 0x1518_4d35_6d96_7b91, - 0x1afc_017e_c025_f777, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbd9c_a11d_c9d1_47c4, - 0xa729_70e7_74ea_f665, - 0x4ab2_7f51_e350_8d9b, - 0x1b80_855f_52e2_65f1, - ]), - pallas::Base::from_raw([ - 0x47cd_3ef3_25be_4c31, - 0xe4c1_3895_f52a_ad9b, - 0x3533_9da3_9399_7f27, - 0x2388_7e28_f45a_cf6f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0863_f044_e1a6_11e2, - 0x79e4_5575_8e7a_78f8, - 0xc8fc_9c15_0f54_30d6, - 0x3a7a_8e36_84de_274d, - ]), - pallas::Base::from_raw([ - 0x03a3_2fb5_bab3_3a4d, - 0x0bd2_34a6_5c64_7867, - 0x972b_19ad_d013_d7c1, - 0x1612_2c94_e22e_f260, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdf78_184d_c553_f8fb, - 0x95e8_ea38_3755_2814, - 0x1603_092f_6d39_db38, - 0x2769_e6ea_c901_bb9f, - ]), - pallas::Base::from_raw([ - 0x6aae_1ad2_22b6_2d45, - 0x8341_704f_980d_1ea9, - 0x7317_b503_da60_23a6, - 0x16b1_5baa_a77c_92e6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x35ad_694f_d3f3_93e5, - 0xb977_6bab_ecc1_635d, - 0x673e_2552_a80f_847f, - 0x282a_562e_6ffd_6c2d, - ]), - pallas::Base::from_raw([ - 0xcd61_300f_af9b_7633, - 0x5f78_7bdd_6fb9_767a, - 0xf8e6_3e0b_a3cb_a82e, - 0x3c29_8b6c_70f6_5826, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf978_920b_4033_85f0, - 0x4741_dfed_87e7_f4ed, - 0x9af7_9a50_a097_b040, - 0x09f2_0401_7a7f_3d55, - ]), - pallas::Base::from_raw([ - 0x484c_a7c7_1e1d_cfde, - 0x435e_fe17_c8a5_cbc1, - 0xe981_12aa_7104_5057, - 0x1d2c_9905_b8c5_8026, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8a4e_ddc1_e2a4_e687, - 0x5bff_5ce2_018e_858f, - 0xc6e5_662f_83a1_e56a, - 0x02a2_000d_679b_2dba, - ]), - pallas::Base::from_raw([ - 0x2f6a_f6ea_7c76_b2a0, - 0xb8c7_4bfa_9b69_4056, - 0xfb79_16ad_496d_1e14, - 0x1df4_ca05_f14d_04e2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6088_f6ef_e336_ea5c, - 0x7497_110a_3ab5_54c8, - 0xbb4a_8a7e_90ab_1b70, - 0x16ca_05a8_a644_e307, - ]), - pallas::Base::from_raw([ - 0xbc6b_4bf6_eee0_03cf, - 0x9497_c239_5d17_314c, - 0xa528_8c4e_96df_57eb, - 0x05ec_2cd2_70b2_c32f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1d4b_5aba_2d51_6844, - 0x0ebb_e763_14ac_cff0, - 0xcae2_52c3_1950_5947, - 0x106f_7769_986b_58ec, - ]), - pallas::Base::from_raw([ - 0xec32_de24_bd53_2691, - 0xaf82_b179_9fba_b8aa, - 0xadf7_592d_33f3_4d51, - 0x1dd7_ab82_5380_22db, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7701_5dcc_356c_94f9, - 0xe75b_8f5f_f89f_73ab, - 0x934a_7c89_81e2_4737, - 0x0952_ea05_e704_9ee3, - ]), - pallas::Base::from_raw([ - 0x7bdb_c92d_9d50_75f7, - 0x9985_21f0_5f28_9ed4, - 0x920d_4ffe_7a28_6fb2, - 0x19b4_edf6_4b69_3292, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2d93_48b7_18f9_b3ac, - 0x1ee6_c3d8_07e9_cb72, - 0x27f7_47e3_bd7b_0b59, - 0x3344_264e_0e0f_39af, - ]), - pallas::Base::from_raw([ - 0x5392_14e5_9f27_7f85, - 0xbab5_f15c_75c7_fa84, - 0x5e92_a501_1bcb_a88a, - 0x39be_7bc4_6e98_ebef, - ]), - ), - ( - pallas::Base::from_raw([ - 0xeffc_5cb8_5798_7d36, - 0x4231_e383_e08a_1c06, - 0x83f4_c3e7_99b4_5fe5, - 0x1bc4_4ad9_628d_b324, - ]), - pallas::Base::from_raw([ - 0xb051_73ed_1a60_83bc, - 0x5d3f_b49d_377c_550f, - 0x9ec4_1f7e_c634_c956, - 0x2ea2_a4bd_7949_e352, - ]), - ), - ( - pallas::Base::from_raw([ - 0xce11_b86d_18ab_15c5, - 0xfdfd_58bb_e7cf_ebbd, - 0x011a_1665_1ade_a741, - 0x1867_7683_03fc_dcbe, - ]), - pallas::Base::from_raw([ - 0x8c65_a7b3_7436_63a6, - 0x0895_f62c_82b4_bcca, - 0x697f_2648_19e5_bf42, - 0x1c9e_8a89_693a_c155, - ]), - ), - ( - pallas::Base::from_raw([ - 0x20f1_50c1_b583_d962, - 0x5b7c_4fdd_6bf3_33a4, - 0x6616_f214_6b56_0695, - 0x3c09_152a_ae39_f9d7, - ]), - pallas::Base::from_raw([ - 0x8d4c_d15c_11e4_5f76, - 0x3ee6_fba2_a365_7a95, - 0x57df_944d_2990_ae68, - 0x3e40_9606_dd7f_fcfd, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0f1d_cbaa_c64e_207f, - 0x24ce_0096_04e8_74af, - 0x8206_a341_4f16_3b2b, - 0x1841_ffa5_9560_5383, - ]), - pallas::Base::from_raw([ - 0x7445_4a84_172d_dfb7, - 0x4e61_663d_e974_8c87, - 0x49ac_c46f_7652_ae10, - 0x35f9_eb31_2da0_3d40, - ]), - ), - ( - pallas::Base::from_raw([ - 0x71b2_cf29_e621_7cd2, - 0x85fb_6de4_0cdc_c772, - 0xfcb0_2d60_0a46_877a, - 0x0dcd_cba8_2583_6234, - ]), - pallas::Base::from_raw([ - 0xa5e7_e058_d611_327b, - 0x1f29_dadc_d446_02dd, - 0x50d2_0616_22aa_60e5, - 0x1bc1_4ad7_6911_5d28, - ]), - ), - ( - pallas::Base::from_raw([ - 0x76ad_98d4_ab3b_419f, - 0xffad_8c50_6e25_97ff, - 0x3a06_bbb6_43ea_1ebd, - 0x3da3_b0f3_6ffb_c5f7, - ]), - pallas::Base::from_raw([ - 0xf747_ed0e_6bf0_296d, - 0x08b5_9863_d358_93b0, - 0xfec9_a301_a77f_064e, - 0x18e9_b59e_d7dc_0386, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1965_7b9b_65a0_684f, - 0x2138_8c2d_19c4_1b69, - 0xae4f_210b_d783_87fa, - 0x2e4a_f156_17f9_aa1b, - ]), - pallas::Base::from_raw([ - 0x7e5a_da88_7dbb_23ac, - 0x076a_81da_aa1a_cea5, - 0x46f5_2c4a_4629_12c7, - 0x377c_3c47_a79a_cd00, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd9e6_9b4f_775a_8960, - 0x3cf8_686d_3a8c_2253, - 0x007c_16e7_38dd_f650, - 0x275c_d87f_d1a9_affb, - ]), - pallas::Base::from_raw([ - 0x2eac_fae8_83be_39dc, - 0xa147_cb90_545e_9792, - 0xb894_660b_0ca5_2156, - 0x102c_7bd5_54e6_2a1f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3d50_5225_818a_d743, - 0x7610_a4da_2296_4451, - 0x4ac1_dba3_15cd_e138, - 0x2a63_e9ea_93b4_8b68, - ]), - pallas::Base::from_raw([ - 0x602f_7b8a_987c_a0ae, - 0xf26d_d9ff_d12b_9ca2, - 0x7434_3696_6cde_5174, - 0x1d77_2b01_598d_98f6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9ee6_79fa_2503_f12d, - 0xe3a0_67a8_ab7c_c1a7, - 0x4a04_cfd6_a900_5d0d, - 0x20b6_e71f_03ce_350e, - ]), - pallas::Base::from_raw([ - 0xff99_352e_01d9_e9c0, - 0x1cff_eb28_f38b_918a, - 0x3f5a_211d_6b2f_6a4b, - 0x35fc_1ac5_b933_3f78, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfd29_ac30_0d2e_c13b, - 0x6d86_8828_a090_269d, - 0x617b_b4e3_df1d_6e3f, - 0x1062_44bd_2099_3d22, - ]), - pallas::Base::from_raw([ - 0xba4b_6207_7d83_b053, - 0x752b_22b3_0554_a5b4, - 0x9399_8320_f3a0_12c4, - 0x3e32_1295_f9a7_53f3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x21b0_2a13_67da_2df6, - 0xd95e_f536_2abb_71e5, - 0xc466_cf97_819a_bb8d, - 0x0ac1_d2f5_a9ef_d18d, - ]), - pallas::Base::from_raw([ - 0x652c_72da_e56f_053d, - 0x3e16_df3c_dd09_25f8, - 0x4486_dc64_f0ae_ae8e, - 0x1083_d1d6_afcc_3d28, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd66d_903f_1504_cb22, - 0x7d74_1d95_24fd_f1a2, - 0x0420_1142_5b05_701d, - 0x2581_a1db_a4a6_28f9, - ]), - pallas::Base::from_raw([ - 0x31f5_3161_9435_04e8, - 0x56b5_086a_e923_27ee, - 0x0470_dba6_f453_d40b, - 0x37b7_3cbb_6a46_8bc3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5a64_fae6_2a62_095a, - 0x1a5d_b99a_a3cc_09e1, - 0x5c87_bf4d_b4f1_d4cf, - 0x3554_e145_5ac7_ce25, - ]), - pallas::Base::from_raw([ - 0x62fb_29aa_b259_653c, - 0x1079_e028_f669_bf99, - 0xc7b5_e1a2_b66a_56d3, - 0x1da9_6c27_0679_663d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa38a_7597_05e4_c595, - 0x93b5_16bf_3679_9104, - 0xdcf3_617c_06b7_eca9, - 0x1c04_9649_6246_d90a, - ]), - pallas::Base::from_raw([ - 0xcb9b_62de_2098_b010, - 0x0b11_bddc_e6c4_3c5b, - 0x0e06_9619_2171_a4b5, - 0x0ca0_f9bd_545e_b563, - ]), - ), - ( - pallas::Base::from_raw([ - 0xabcc_ccbb_5ce1_d68c, - 0x6f7c_af47_e50d_a282, - 0xf36a_135e_abaa_806f, - 0x0c6e_bade_1095_aae8, - ]), - pallas::Base::from_raw([ - 0x759c_cc9e_69e6_b3e2, - 0xf9dd_54df_05a2_63bf, - 0x89da_d73c_cf47_946b, - 0x0312_d8af_2b83_bc52, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3d63_f419_3209_4084, - 0xa82e_0939_a10d_d3bd, - 0x09a4_2d48_e016_ca24, - 0x22d5_2560_48fb_a5d6, - ]), - pallas::Base::from_raw([ - 0x205f_917b_e385_f08e, - 0xe8ba_59ea_1582_96c5, - 0x07db_5f05_1202_61f4, - 0x1b27_fe10_cf0d_2d81, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc3c5_2026_c4c0_cdbc, - 0xe5c9_a075_9804_c4f1, - 0x333d_a34f_899b_6d01, - 0x0893_9b6f_69ee_9ff1, - ]), - pallas::Base::from_raw([ - 0x5738_5c90_a60b_6a29, - 0xcbfe_0af0_9889_9ee3, - 0xe56c_4f49_ed05_94c2, - 0x1a8c_87df_a7e4_fed0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9bcc_8617_524a_7052, - 0x9ed1_bc3e_a53b_8039, - 0xe83b_0a28_98c1_b3ae, - 0x2156_b879_f378_005f, - ]), - pallas::Base::from_raw([ - 0xe445_4fd6_1a4c_0c03, - 0xfd2d_77ee_9e45_d137, - 0x364c_d7d1_beca_462e, - 0x0454_61a0_6d06_0224, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa6dc_e40b_7742_c8df, - 0x77f6_fb9f_2f5e_4cbb, - 0x8971_a6f2_c8a1_01f6, - 0x06f6_891d_e68d_557e, - ]), - pallas::Base::from_raw([ - 0xe136_eb32_f32c_9360, - 0x43cc_807a_1583_94e3, - 0xb883_68d8_bd3f_0e85, - 0x39c7_f743_a3ff_d99b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4d92_8024_dec5_a188, - 0xc6fc_a92b_d386_353e, - 0x5812_c85d_f51b_7666, - 0x3622_96ae_b985_ad75, - ]), - pallas::Base::from_raw([ - 0xaf74_4347_0ebc_cc5b, - 0x8664_df03_bd4f_e04e, - 0xbb7c_dfe1_90ed_a6e1, - 0x04b7_49f0_6ac1_8d6d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x47cb_7e3a_61e6_5d64, - 0x2668_8f4b_611d_168b, - 0x851e_b1c6_f081_270a, - 0x0bcd_6577_07d9_c4d3, - ]), - pallas::Base::from_raw([ - 0xb8a7_9c1d_0164_6e59, - 0xaca0_0a81_3cbe_8d14, - 0x9be3_d622_a4d4_2261, - 0x228f_44ec_ff21_0aaf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x01e8_32eb_32fc_77d8, - 0xa37b_d49f_cf1e_6d1d, - 0x4ade_7626_003a_6902, - 0x2810_18ba_6873_285b, - ]), - pallas::Base::from_raw([ - 0x3b22_bd8c_3f6a_e0f7, - 0x647a_d4e9_cc9e_9df9, - 0x599f_264e_e5e2_861a, - 0x1bc7_4dbb_c711_e11b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xea31_502c_f1b8_0e15, - 0xc33d_5160_cd48_b428, - 0xcc23_c910_de17_adec, - 0x07de_f9ce_1aa5_9c47, - ]), - pallas::Base::from_raw([ - 0xa4ae_eeba_b464_5932, - 0xb123_1450_1087_4d65, - 0xd74f_2873_e2b3_fbd6, - 0x37f7_28e5_56e4_462f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7e30_9f95_bb4b_c5b4, - 0x6062_f47d_7261_c580, - 0x8e3d_4f2a_6d15_8590, - 0x01d5_e294_1638_a398, - ]), - pallas::Base::from_raw([ - 0x2d94_25e0_5176_6252, - 0x661f_3a26_6d6d_2f2b, - 0xe226_6037_2ff4_b8dd, - 0x1217_12c3_778e_e4a5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8089_bc3e_77ce_6f7c, - 0xa6b2_22eb_d80f_7fc0, - 0xe9b8_b790_943e_8250, - 0x1095_0660_66b4_15b1, - ]), - pallas::Base::from_raw([ - 0xecaf_5823_aa30_216c, - 0x1bd3_7176_ae8c_c867, - 0x6646_5d17_3a00_4c92, - 0x1708_b8da_bbac_5fa2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0f5a_b3f4_1ed5_0406, - 0x3ed6_b824_6b8e_8193, - 0xefc8_17a7_c166_72ef, - 0x03d9_e65c_55e0_6fed, - ]), - pallas::Base::from_raw([ - 0xd266_0a0a_3a15_efd9, - 0x3158_3160_0238_603a, - 0xd08a_576e_ef04_0407, - 0x12b5_fc79_3386_02ad, - ]), - ), - ( - pallas::Base::from_raw([ - 0xafb4_5038_861a_b261, - 0x3336_2512_0ea2_ddef, - 0xd0d2_1e8a_bde9_c3f0, - 0x3142_5607_0f44_6667, - ]), - pallas::Base::from_raw([ - 0xd47d_2bf6_b0cd_9526, - 0xdfb6_5162_03ea_5997, - 0x6bc8_e93a_d9f1_3d86, - 0x36e3_7b1e_879f_a3fe, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9641_b725_3871_63f8, - 0x2f14_e213_977d_fb89, - 0x872e_0f0f_818e_2401, - 0x2705_4742_9401_5255, - ]), - pallas::Base::from_raw([ - 0xe914_98e9_e277_bf3e, - 0xbc1c_1336_46cc_0de8, - 0x810d_265f_9dbb_24c2, - 0x073c_4fa7_0c22_d417, - ]), - ), - ( - pallas::Base::from_raw([ - 0x72e0_8476_4f57_cbdb, - 0xaade_43be_ed5a_ec74, - 0x6b7a_19e7_38aa_efa8, - 0x3fe1_03e4_b203_9c38, - ]), - pallas::Base::from_raw([ - 0xf7b0_a409_9047_5ffc, - 0xf227_8b45_596c_d47f, - 0x8e89_3c33_0061_9b20, - 0x1e9a_0a12_9951_b344, - ]), - ), - ( - pallas::Base::from_raw([ - 0x273e_1d1d_25f4_def7, - 0x2003_845a_3171_beb1, - 0x6d17_8165_5f29_f2d4, - 0x0870_5e7f_5d5b_29c0, - ]), - pallas::Base::from_raw([ - 0x5593_5829_fa5d_7cff, - 0xf32a_41cd_f789_5d7e, - 0x1bf2_ea43_d1a2_e73d, - 0x020f_bf08_0453_d654, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc7cc_99c7_2db8_9a13, - 0xe869_f872_1a3e_457f, - 0xf8d5_9b75_f9e9_5e27, - 0x2a3c_dfb9_b0ec_7221, - ]), - pallas::Base::from_raw([ - 0xda92_9b87_c8b3_43ae, - 0xb33c_22e3_1aca_23f0, - 0x7ef6_c020_43d5_029b, - 0x0f16_75e5_fb1b_6016, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdaa7_c49c_581e_a8f5, - 0x5e24_60df_0bf6_68a4, - 0x04e2_ec29_9caf_6146, - 0x2438_e7ee_c6b6_6289, - ]), - pallas::Base::from_raw([ - 0xd94c_c550_0990_5ce3, - 0x9149_39c9_7c98_acbb, - 0x90d6_a0d5_e69d_004f, - 0x0e30_9799_430a_005e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x16d2_ba71_df3d_ba37, - 0xf987_3a39_9072_46f3, - 0x7309_0fc7_2e2c_8978, - 0x3e6a_ca9f_7693_dbd8, - ]), - pallas::Base::from_raw([ - 0x14bb_c667_e12f_8242, - 0xb8ab_dadf_64c7_ce8e, - 0x1a94_5bc1_7bb2_ea2a, - 0x012d_bbf6_af71_3aec, - ]), - ), - ( - pallas::Base::from_raw([ - 0x240d_00da_c9d7_36ac, - 0x5e01_5424_1ed5_6054, - 0xb77b_8e76_3e42_9cfb, - 0x1443_95ec_38cd_baef, - ]), - pallas::Base::from_raw([ - 0xa1d5_463f_18ef_f4f8, - 0xac13_6a2b_6eec_e912, - 0x175b_2f1a_655b_abb6, - 0x11f8_e577_8862_dc12, - ]), - ), - ( - pallas::Base::from_raw([ - 0x917d_91a5_1b8e_9f26, - 0x96a7_d4b3_e2db_2ef9, - 0x6467_2893_ebec_80a5, - 0x0415_c72c_6add_a7ad, - ]), - pallas::Base::from_raw([ - 0x31fe_78e5_541c_b69d, - 0x6fd0_a42e_a164_a907, - 0x779b_fe38_59e7_a99d, - 0x1502_f313_f9ea_cc53, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6299_68d0_f509_962c, - 0x0fd8_546c_a5b9_a1e8, - 0x4f71_7137_88ee_864d, - 0x21be_39d7_bb78_98ff, - ]), - pallas::Base::from_raw([ - 0x2e30_597c_56a1_b4fa, - 0x1a02_ad53_8381_07e1, - 0x4d02_2a9e_1cfd_6d33, - 0x1f3c_e37d_51aa_b4c1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd2e8_277a_9787_ad9b, - 0x06b8_ef87_3d81_def3, - 0xcb3f_a058_0cdc_9294, - 0x3e0e_b866_b610_dad5, - ]), - pallas::Base::from_raw([ - 0x416f_988d_290b_fce1, - 0xe99d_9c46_9eea_a7fc, - 0xe826_d37c_968c_f31a, - 0x303a_5065_2996_bc3e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x970d_c43d_b7f9_6596, - 0x8bbe_a004_7bbe_b37a, - 0xffbf_c07c_4f86_ff20, - 0x2eb0_e870_2a5b_817b, - ]), - pallas::Base::from_raw([ - 0xcdec_df92_c73a_cf15, - 0xa349_b8f4_4bc1_1a4b, - 0x4ca2_5c82_1a35_0486, - 0x0c35_a8ee_8f63_ce4e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3330_feff_82c5_909d, - 0xa037_ccf5_1576_8f65, - 0x04b4_e5bf_d165_ab7e, - 0x3d8f_d30d_2e98_701f, - ]), - pallas::Base::from_raw([ - 0x76cf_354c_613f_6916, - 0xb3ac_8cfc_ef68_b8e4, - 0x121e_23ec_fb6d_3348, - 0x049c_4676_6965_007e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd28b_5af8_208a_ad16, - 0x85cc_0c01_2522_9ec1, - 0x0010_00b7_fcba_b744, - 0x2f16_3cb5_e159_50da, - ]), - pallas::Base::from_raw([ - 0x8204_a5a6_854c_8f0c, - 0xaec2_50ed_9f9c_1bf3, - 0xa678_973b_4ca8_cfba, - 0x2060_78c2_1062_adf6, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb572_bfa2_ae44_bae7, - 0x4739_7be5_ed58_65d9, - 0x12d8_2660_d7d5_cd9d, - 0x3802_91b0_d0fb_11f4, - ]), - pallas::Base::from_raw([ - 0xda9e_f004_e34f_00ed, - 0xd1c7_c9c5_f145_719e, - 0x5d07_b071_e032_9c77, - 0x111f_1bf3_5aca_cc6c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9d4e_fee9_dbec_f74b, - 0x54b6_6b98_6ed1_1c40, - 0xc69d_e967_1f2a_9277, - 0x381e_f7c2_0901_6f19, - ]), - pallas::Base::from_raw([ - 0x78cd_6291_4c3d_4870, - 0x969d_b03f_4366_a7c9, - 0xc63f_edfc_ad98_8cca, - 0x0871_c3f1_196c_ed39, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbf95_5ae0_cd25_88e4, - 0x1a5d_be45_5bc1_85c6, - 0x800f_fb1f_93e7_1b70, - 0x0499_6852_1fa4_93b8, - ]), - pallas::Base::from_raw([ - 0x0888_a02b_46a4_447f, - 0xbf4f_428f_9cb9_8c28, - 0x8137_0703_14ff_9de2, - 0x1387_9076_4310_b410, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd12e_b4c0_0f6b_07df, - 0x4867_9cb7_f377_39f4, - 0xd28d_9c85_b17d_4400, - 0x0bd9_47e1_a875_e349, - ]), - pallas::Base::from_raw([ - 0xda62_8d27_e56c_e1ba, - 0x3fb9_f8d5_96b8_9fd8, - 0x5de3_b929_f658_6237, - 0x1535_62a4_2638_2eb6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x36af_3b03_bde6_af5c, - 0x4fa4_3315_d7f6_0dc6, - 0x7067_a020_a491_9197, - 0x1c32_47f1_b306_ddee, - ]), - pallas::Base::from_raw([ - 0xc652_bb5a_650f_f696, - 0xf53e_890c_d2fe_64e1, - 0x9dbd_c120_670e_ac51, - 0x0786_cce0_4423_b08a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9b52_5a04_5c02_abe2, - 0xab88_03cd_3c69_fc10, - 0x4f5c_04e7_4967_f822, - 0x3d7c_ba8b_8d24_c973, - ]), - pallas::Base::from_raw([ - 0xc36f_6da9_c20e_8ca7, - 0x3ab8_0cd3_18c7_054d, - 0xea00_c48b_f1fb_88d8, - 0x2a85_cd4f_78e9_75d5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xac5b_f95e_d4b6_11a2, - 0x136d_4d81_80c7_2c43, - 0x1fb6_df88_d28c_8d4e, - 0x246a_fe1b_17d5_6011, - ]), - pallas::Base::from_raw([ - 0x3668_7b33_4756_4972, - 0x1467_dd2d_360d_bc64, - 0x410c_df5f_93a9_6258, - 0x3588_8b68_24c6_e8a0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5dc2_2a72_4a62_d492, - 0x2660_9b2b_a750_8d8c, - 0x5059_5ae6_1b53_8471, - 0x266a_34b1_9765_cdff, - ]), - pallas::Base::from_raw([ - 0x7fbe_5bdb_d358_a2cb, - 0x40a4_f7fd_1ca8_a76a, - 0x491d_3273_a50e_004a, - 0x3568_0e4a_dc4f_62ad, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbfdb_990c_f977_fd4e, - 0x6437_369d_ca6d_cc9e, - 0xc7b5_d048_b550_51ee, - 0x250b_73ec_71d5_4645, - ]), - pallas::Base::from_raw([ - 0x41ae_e46b_4412_b381, - 0x9e9e_e500_6ddc_61fb, - 0xec2f_6df5_bbce_cf94, - 0x1793_e215_0b16_603d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6f88_6d79_770c_6247, - 0x1500_0374_0fa1_e182, - 0xf376_03b2_1769_2f82, - 0x3d1f_7368_0af5_b7ec, - ]), - pallas::Base::from_raw([ - 0x81b6_a75a_e4f9_729e, - 0xe735_aeaa_341f_ae17, - 0x4eff_b7c5_e1aa_bb0a, - 0x0223_c1d4_4c5d_c34a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x419d_f14d_7945_7532, - 0xd780_283f_4e02_c512, - 0xf0fc_47a1_756c_c536, - 0x1ce3_0702_a06b_ed82, - ]), - pallas::Base::from_raw([ - 0xaa20_9753_1479_6860, - 0xb77b_9671_d950_53a0, - 0x804e_e63e_09dd_84ba, - 0x09e1_711b_96dd_a806, - ]), - ), - ( - pallas::Base::from_raw([ - 0x607f_ba34_a589_c019, - 0x79bd_bab6_5d82_5998, - 0xcaca_a4bd_7fbb_d938, - 0x3694_ca85_2cf8_e54d, - ]), - pallas::Base::from_raw([ - 0xf555_28c0_3fb3_7e54, - 0x4a49_b781_11bb_66e4, - 0x94e4_77e7_59c5_515b, - 0x369b_a0f2_0b09_fe48, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa903_4843_3c41_e761, - 0x334f_6c0e_07da_b2ae, - 0xfa76_35b1_0775_e8e1, - 0x1fdd_43d1_901d_1921, - ]), - pallas::Base::from_raw([ - 0xb042_af7e_11f5_e1a3, - 0x72dc_c343_0584_0ada, - 0xec1f_22f3_40a0_7a4a, - 0x3d4d_cd14_0c46_afa7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6516_53a1_ad5a_b863, - 0x3109_c5a4_3f3a_7299, - 0x4a26_89fe_ac51_8cd9, - 0x32cb_28e5_306f_4b25, - ]), - pallas::Base::from_raw([ - 0xce22_41f1_7770_0732, - 0xe9c2_68bf_1477_f81a, - 0xb643_c5f5_bed9_f57c, - 0x1ab3_8e0c_8fed_3eaf, - ]), - ), - ( - pallas::Base::from_raw([ - 0xad37_f47d_cf5b_c929, - 0xfec4_68cb_3ca6_b620, - 0x388c_5260_e2cd_625d, - 0x3e14_2094_bf47_b461, - ]), - pallas::Base::from_raw([ - 0xe191_3bcc_b9c4_dbd6, - 0xf56b_018e_cbd3_94fe, - 0x7a84_d88b_b2d8_d148, - 0x1095_d08b_31d1_571a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4c24_da73_a43b_18a4, - 0x192f_ad49_886d_4f1c, - 0xb9ca_2200_29b0_fd9e, - 0x23c3_cd8e_910e_3f61, - ]), - pallas::Base::from_raw([ - 0x446a_7b2c_0c53_995b, - 0xf640_9e82_f746_d6c6, - 0xd49a_f1a5_d660_f046, - 0x289f_6688_c8f7_a7da, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9322_2f89_f469_19ea, - 0x23ca_ce6d_d52f_41af, - 0x7b9f_0036_a0b5_b7ec, - 0x36a9_0ecc_3af7_1bf8, - ]), - pallas::Base::from_raw([ - 0xac78_4d5a_2fed_e96e, - 0x83c7_0ec2_e5cc_48a1, - 0x623c_7acd_dabe_6588, - 0x262e_4d3c_689f_55c2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc48b_b03e_d3dd_130e, - 0xc8da_668d_e3e8_c4c0, - 0x8496_8dfb_620e_4d78, - 0x21d2_8b83_ef14_3a07, - ]), - pallas::Base::from_raw([ - 0xa607_41ba_7c9f_512b, - 0xe9af_6b59_b23f_048f, - 0xb49b_ffe3_9a97_dd6b, - 0x073c_ef7a_eab5_e67c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbb8c_2ebd_02ef_5c02, - 0x9f3e_fb6b_a8a3_d5e7, - 0xdd5e_afd6_8224_7afd, - 0x0a4d_0696_34c2_1d49, - ]), - pallas::Base::from_raw([ - 0xde8b_2693_7445_2117, - 0x8827_3e13_9ac8_9175, - 0xaf4d_3f11_60fa_ce22, - 0x372e_f7de_420c_f5b0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x007a_3171_e694_ad4f, - 0x0b63_7d43_b499_6483, - 0x3f41_d9a4_71d9_e31e, - 0x2304_4159_f767_5fe2, - ]), - pallas::Base::from_raw([ - 0xc689_d9d9_98f0_22c3, - 0x3843_04a4_96ef_f3ea, - 0xcdf7_07fb_a786_9698, - 0x00ff_aa52_52f3_1075, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc7ed_5950_3bbd_ae0c, - 0x0771_0a4e_f363_a8cf, - 0xb854_a41d_2524_2222, - 0x361c_d998_8c71_f7d1, - ]), - pallas::Base::from_raw([ - 0xd1c3_f5a8_e31d_e85e, - 0x61f9_1fe1_a2ed_72f5, - 0xd02a_3047_b442_7a6b, - 0x28a9_2ac8_140a_7f61, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe69b_8ff5_68db_09ef, - 0xa955_a884_45b6_1b1d, - 0x0181_0ff8_0bc0_0a37, - 0x3f77_7487_2da1_b634, - ]), - pallas::Base::from_raw([ - 0xbafc_6197_5f58_119e, - 0x8ec8_6817_94cf_4a02, - 0xf79d_b4f7_ef61_586b, - 0x1ecb_0eff_dee9_b332, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2e7c_1b51_5d9a_6b02, - 0x6db8_5ed9_bc41_5b63, - 0x9e61_c761_f278_31e1, - 0x1d63_7f07_1de7_68c5, - ]), - pallas::Base::from_raw([ - 0xb695_013b_a88a_e8fc, - 0x6087_861a_5652_9bf5, - 0x37e4_54e2_449e_c3d0, - 0x32f1_ac34_a889_a6b1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x45c6_e979_95c8_8f9d, - 0x9177_13bd_364f_3511, - 0x18b5_d48a_f737_4cec, - 0x1acb_50aa_82bc_21f3, - ]), - pallas::Base::from_raw([ - 0xa0b5_ac1e_0e73_137c, - 0xe9cc_3b69_7c2a_33dd, - 0x3843_fbd6_837f_46b9, - 0x3af2_c307_dabd_f022, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf320_517d_b185_80af, - 0x4ee4_765d_dab8_aefa, - 0x6b87_9ec8_cb2c_34ec, - 0x1804_0e61_d02c_9aa7, - ]), - pallas::Base::from_raw([ - 0x7799_9a31_ca66_44d5, - 0x5c57_40bb_df52_8c37, - 0x3c6f_fa5b_9973_5cc2, - 0x2d42_7fcb_2de3_02b2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb702_1f4e_248b_d314, - 0x45a6_d47d_1e77_fc6f, - 0x71de_177e_9447_c0b3, - 0x2c36_6f8e_fc81_8295, - ]), - pallas::Base::from_raw([ - 0xd417_641c_3ef7_59be, - 0x46f0_a493_376d_27ea, - 0xcc58_89f3_a398_3e94, - 0x24ca_8204_9524_6a0c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4d41_08a1_fdf9_022d, - 0x445b_c1f6_ff38_ab2a, - 0x2c34_468f_08c5_67cd, - 0x27c9_224e_b005_f2fb, - ]), - pallas::Base::from_raw([ - 0xb67f_e386_3ad8_5858, - 0x35e7_89c1_3270_0ae0, - 0xaf43_ea8e_be9c_72c2, - 0x35ff_b97b_a593_0142, - ]), - ), - ( - pallas::Base::from_raw([ - 0x679c_9c77_fa3e_adea, - 0x050c_617e_c159_e9dd, - 0xe4d0_ad0b_279e_5d53, - 0x1c13_85a7_acca_d2d0, - ]), - pallas::Base::from_raw([ - 0xa605_758c_76d8_f99e, - 0x245c_09b6_233e_c109, - 0x9951_123f_fade_c94f, - 0x0e06_cb32_e11a_db9e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdda6_c646_97fa_e3a1, - 0x57f4_3e80_51b9_d2bc, - 0x05ac_1626_2bfa_455d, - 0x27e6_b214_c46d_b4ea, - ]), - pallas::Base::from_raw([ - 0xe0df_3924_7265_cae4, - 0x09c0_1eb2_c3d4_7a5b, - 0x4b07_d6dd_a718_dc3c, - 0x046e_e6b1_16a4_d680, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8827_884a_0d84_93fb, - 0xb641_d4be_17e5_2a25, - 0xd1bb_d65e_ca13_f1e5, - 0x14e6_8375_9dbd_f9b7, - ]), - pallas::Base::from_raw([ - 0xc5bc_27f2_043e_09d6, - 0x4383_1bd8_740d_18bc, - 0x4d28_b951_db51_646c, - 0x2ff2_925c_ae35_4106, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd2ab_b8ea_a809_c065, - 0xa526_4c4f_d558_42f7, - 0x36bd_6833_52ed_686a, - 0x3e03_a120_a2d9_028e, - ]), - pallas::Base::from_raw([ - 0xadcd_15a2_2b64_bcff, - 0x8b41_fbcf_fa41_1d4e, - 0x6275_e729_aac4_1718, - 0x05f4_d1dd_a528_76ca, - ]), - ), - ( - pallas::Base::from_raw([ - 0x259f_45df_db18_4292, - 0x85a3_9f21_bd27_88a2, - 0x7741_d050_9d2b_a469, - 0x3628_e48a_fad3_7caf, - ]), - pallas::Base::from_raw([ - 0xf38c_a509_52c2_edd4, - 0xdbc8_3dce_fa5d_964f, - 0x67e5_1358_704a_dc0d, - 0x2dd7_037f_7772_b72a, - ]), - ), - ( - pallas::Base::from_raw([ - 0xde93_38bd_92bb_3d57, - 0x944b_7238_c860_9441, - 0xe03d_5bc0_6ceb_4255, - 0x2889_0bf6_1603_be43, - ]), - pallas::Base::from_raw([ - 0x598d_dfbe_ff5b_91c4, - 0x9017_7d24_b040_66d8, - 0x29fe_24aa_ca62_9592, - 0x0e1b_b56d_d00f_ee5d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x80f2_b1d9_cd31_a2c3, - 0xfeca_8134_5364_e82b, - 0x667e_8405_4786_7826, - 0x196a_2aa5_dfcc_2404, - ]), - pallas::Base::from_raw([ - 0x44f2_ea4e_50cb_7b22, - 0xa203_aca9_842b_2587, - 0x9c3f_525e_e03f_487d, - 0x1dbb_0fc6_d624_36c8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd9f8_f81d_1726_2ea7, - 0x48c2_218d_3eba_8bbc, - 0x6a31_acc9_902a_abeb, - 0x1086_be57_c6c6_9382, - ]), - pallas::Base::from_raw([ - 0x9b21_c4ee_4438_3fb0, - 0xffbb_187c_d2c6_7113, - 0xbbdf_86a0_0d9c_9df9, - 0x1900_0dbd_6915_ef39, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb87e_e6a1_7150_f083, - 0x1dd3_172a_c7ca_bb4c, - 0x450d_6085_7553_2aa7, - 0x0e87_4af5_a4ea_bea9, - ]), - pallas::Base::from_raw([ - 0x27d9_3005_6a39_bdf0, - 0xaffc_ea8f_faac_2475, - 0x27ce_f92b_ac1e_26d1, - 0x1dce_ecf2_93f2_e855, - ]), - ), - ( - pallas::Base::from_raw([ - 0xec32_f124_f67c_b6a6, - 0xe76f_c0a9_bb04_6fc7, - 0x08c9_2fb9_a869_9d4b, - 0x0aa4_f0ca_3613_1f19, - ]), - pallas::Base::from_raw([ - 0xc77a_383a_f5f9_298c, - 0x6c2a_0c57_8f61_7a6a, - 0xa8fb_83f4_8769_5723, - 0x0dac_9338_2fb1_7d74, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa4ae_ed26_9bd7_f7af, - 0xcf45_5590_be79_8165, - 0xbb66_a5c2_ca07_ba02, - 0x2f71_97fb_33e0_2f3b, - ]), - pallas::Base::from_raw([ - 0xc6f5_fa79_26dc_55ff, - 0xb1d7_1d00_792c_b875, - 0x4300_1b82_b34b_fc81, - 0x2585_89f9_249d_35ff, - ]), - ), - ( - pallas::Base::from_raw([ - 0xca86_6954_84ea_c326, - 0x64d8_b454_7605_528f, - 0x47a1_1398_f1c8_6914, - 0x0626_f333_6694_8b96, - ]), - pallas::Base::from_raw([ - 0xcb9a_c695_8cdf_ac1a, - 0x51a2_395d_f28c_5a56, - 0x2982_997a_0143_8762, - 0x20a0_3634_e587_cdea, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4a22_3815_ad6a_af87, - 0xb23d_c239_fe51_f114, - 0xe744_6fbc_1d76_71f9, - 0x008f_b3c4_f277_6241, - ]), - pallas::Base::from_raw([ - 0xef35_ffbc_38cf_2be1, - 0x6406_1067_6e4b_152a, - 0xcd39_1b65_f743_55ca, - 0x33a9_ac54_8faa_2dc4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb43e_6160_16b7_ac1a, - 0x2d17_45fa_33dd_dbbe, - 0xfcf2_c7dc_158c_b996, - 0x222d_d6b4_22f5_41da, - ]), - pallas::Base::from_raw([ - 0xd15f_8eb6_6b9a_1971, - 0x735e_b437_8b76_de8c, - 0x7a9e_fd09_e21c_cb2f, - 0x2605_6891_36d0_47e3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa728_670e_b27d_0c27, - 0x0ffa_859b_d86e_09f4, - 0xfc12_1ddd_5bca_1d3e, - 0x3ed5_f5ac_9270_3915, - ]), - pallas::Base::from_raw([ - 0x2d66_ad9c_f3b0_9eb5, - 0x0f76_4a1b_3975_493f, - 0x311c_7d39_de6c_80e4, - 0x10c5_a910_538e_2161, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd8ef_2e55_08fe_449e, - 0x9795_f0b4_9b38_21dc, - 0x436d_3359_1956_ff92, - 0x2ef0_c2a1_ff67_562f, - ]), - pallas::Base::from_raw([ - 0xea61_5ac0_2396_252c, - 0xd3c3_e572_248f_f4ec, - 0x0891_5193_35ef_15f8, - 0x0e0b_7ddf_c509_d053, - ]), - ), - ( - pallas::Base::from_raw([ - 0x595f_7475_529b_3ad1, - 0xc202_93a2_e114_ef1a, - 0xa318_7931_4b87_03f2, - 0x25b5_defe_56df_8131, - ]), - pallas::Base::from_raw([ - 0x3207_683d_ce75_c89a, - 0x0aa3_95cc_ee66_6a3e, - 0x1d75_0d4b_db70_3a63, - 0x21a8_8c14_6d5d_50f2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf1a0_a157_fe44_54d0, - 0xe58f_ea83_b9a1_8e48, - 0xe75f_1ebe_b321_bd75, - 0x2ff0_cde1_263d_eb99, - ]), - pallas::Base::from_raw([ - 0x78ad_13cb_3871_d58b, - 0xd70b_f90a_dedf_4a15, - 0xce59_469b_4a86_1855, - 0x07d0_b9f2_d8b0_f8b3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1186_5fc8_3d94_8160, - 0xef33_cdf6_7d9d_f8ac, - 0x77fe_c81f_1b87_0816, - 0x33e4_5c8e_81bc_f208, - ]), - pallas::Base::from_raw([ - 0xa79c_f57d_5f8f_8039, - 0x46bd_dbab_182f_1e8d, - 0x121e_1e62_c3e6_2d1b, - 0x2aab_8626_7a08_126b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7309_5f4e_9257_4e26, - 0x800a_92c5_65c6_d0ab, - 0x959b_7396_8c33_df3e, - 0x1712_0abc_db9a_666e, - ]), - pallas::Base::from_raw([ - 0xa4ce_db71_dcbf_dda4, - 0x23a9_bb12_cc45_7125, - 0x4984_6598_5044_5012, - 0x15b9_a823_452d_151a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1881_58c9_d4f8_37b3, - 0x35e1_f53a_12ea_d4bf, - 0x43b0_1080_7105_9672, - 0x12a1_bb18_f6ae_aff4, - ]), - pallas::Base::from_raw([ - 0xd0c9_3a8c_6405_aeff, - 0x7c79_db4b_21ed_b868, - 0xfe64_ab4d_3285_580d, - 0x21f2_6e9b_4e96_4ad6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5ead_7427_d8bc_93be, - 0x1074_df9b_a240_dc10, - 0x5e02_f458_b883_e475, - 0x1658_9488_1a71_48ba, - ]), - pallas::Base::from_raw([ - 0xcf20_d6a3_30b6_e493, - 0xc050_fc5b_3e2a_b5ca, - 0xcad1_ca64_521c_4b4d, - 0x2d9b_99eb_4fa9_4da9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbf05_9e52_20ab_1fc0, - 0x8a7d_612b_8a1e_0e3a, - 0xeade_4244_f4cd_b38c, - 0x3331_7f8e_8124_54f2, - ]), - pallas::Base::from_raw([ - 0xc888_9b91_0593_4c5e, - 0xe569_c70e_0a7c_97f6, - 0x44d5_b9c8_f891_48f4, - 0x2312_5a5b_68f5_c72f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x94e4_bf9b_f2a6_1428, - 0xa590_5768_df89_f310, - 0x5f26_eac4_e6d7_bf48, - 0x1777_8461_3a31_42ef, - ]), - pallas::Base::from_raw([ - 0xd4c5_a93d_01a9_e944, - 0x00f3_0bb3_f382_1ab4, - 0x3e30_b05e_9001_115c, - 0x13aa_867d_0d62_d501, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0d77_6ee6_83d5_6884, - 0xc690_3133_0cb0_7fad, - 0x03f9_fa71_d83c_b6ac, - 0x385b_2c3f_69f2_2e4e, - ]), - pallas::Base::from_raw([ - 0xe52a_da77_f926_479c, - 0x4032_18dd_a3f9_f7d5, - 0x698a_ca67_0fe0_3b63, - 0x1be6_e46f_45a9_0d73, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb54f_2488_b34c_23f3, - 0x20f7_4d0f_dcf3_556c, - 0xb629_c46b_87ca_5183, - 0x3e05_1b07_97e5_4d7d, - ]), - pallas::Base::from_raw([ - 0x2845_df6b_a7f4_c4a9, - 0x01d8_7bb3_efc5_3212, - 0x7438_846f_f0c3_68eb, - 0x054c_4ccd_9568_783e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0e03_2b41_edf2_601e, - 0xca56_6380_2656_a1ab, - 0xa9c1_73f4_5b36_4aba, - 0x370b_f6a4_76fe_98c7, - ]), - pallas::Base::from_raw([ - 0xe83a_b9c8_7073_23c8, - 0x68cb_12fc_922c_e463, - 0x1d58_cba7_aae2_cd1d, - 0x1641_dcbe_d773_85ac, - ]), - ), - ( - pallas::Base::from_raw([ - 0x33d9_50b2_0786_8cb1, - 0x5546_4d24_79b0_1881, - 0xcef8_ae63_70b3_e7cf, - 0x1edd_0d6f_5654_df9f, - ]), - pallas::Base::from_raw([ - 0xca19_5fd2_3bf8_6d7d, - 0xd888_778b_481d_0c87, - 0x7718_4cb6_9a9c_a004, - 0x18cd_8422_c539_1785, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd3d0_061d_3c40_38a9, - 0x35d2_ba6f_b33a_337d, - 0x2b5a_ccd0_a048_8c8c, - 0x3177_51f9_70f0_55c8, - ]), - pallas::Base::from_raw([ - 0x7da0_2d46_e5dc_cf44, - 0x1948_7204_00fd_ac87, - 0xd35d_2f05_7952_09ed, - 0x067b_66e4_8fd4_40ae, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbe67_f5c1_c53b_6219, - 0x0c4d_d3eb_49dc_5141, - 0x1985_6e06_c83d_dc72, - 0x0580_4e34_6c60_f39d, - ]), - pallas::Base::from_raw([ - 0xd970_b5f8_e84e_2eca, - 0x8dee_bae7_6faa_0b0a, - 0xce36_460d_4c75_cfdd, - 0x0c0b_30a8_4eb6_c2ff, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd211_b3b4_85da_f337, - 0x7caf_c1c9_d176_8b9b, - 0x4f29_6d08_6aa0_6691, - 0x1469_1756_396e_e450, - ]), - pallas::Base::from_raw([ - 0x908c_5ebe_6cb7_9318, - 0x485e_123c_8a7a_1993, - 0xba9c_8297_dc30_544d, - 0x0b1b_b3c8_67ad_579f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfdbb_126a_9c89_8e38, - 0xeeb0_b9e3_24c7_e16a, - 0x2a63_649b_a4bd_3976, - 0x2cbe_8ae3_38cf_2e67, - ]), - pallas::Base::from_raw([ - 0x02c8_e297_4287_df10, - 0xfd4b_303a_ffcb_5e36, - 0xfe24_5d64_99c2_2680, - 0x2ad4_f003_ac6a_0942, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6366_45e4_5cf2_472e, - 0x581b_fa20_8c70_06f3, - 0x7f42_fc2f_a68c_53b6, - 0x3e5f_5c59_a596_3e85, - ]), - pallas::Base::from_raw([ - 0x3fae_7cd7_1795_7498, - 0x1897_f70d_330f_17cd, - 0x08bc_c4a8_93be_9624, - 0x16b6_5a70_880a_1196, - ]), - ), - ( - pallas::Base::from_raw([ - 0xecb8_a34e_6cfa_6400, - 0x872b_a68d_1737_b069, - 0x692b_8b56_4d30_00d6, - 0x1ac8_6b32_c2bd_28f7, - ]), - pallas::Base::from_raw([ - 0xcd15_73d7_4ab8_ecb6, - 0x10d8_d456_d06f_8959, - 0xc4d7_94db_40b8_a6a6, - 0x0fc4_1405_f622_01e8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb13c_4e21_fb86_cc29, - 0x6dd4_2256_220b_a841, - 0x485d_d357_9109_44f6, - 0x13e6_37f3_e85c_6236, - ]), - pallas::Base::from_raw([ - 0x393e_d2d6_d195_2520, - 0x8714_20e0_7d4d_41d9, - 0x4f97_e4c9_1b4d_d5a0, - 0x0ee1_6e26_9356_7999, - ]), - ), - ( - pallas::Base::from_raw([ - 0x18f0_e818_b67f_78c4, - 0xc78e_8276_5cfe_52d7, - 0x1029_108e_3372_5249, - 0x1ce7_779f_3e32_15bb, - ]), - pallas::Base::from_raw([ - 0x0a3c_2c79_69f4_7def, - 0x924a_5bd3_c10a_b277, - 0xa684_5102_3fda_00de, - 0x2848_c67f_8b86_351e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x785a_0070_6ef4_0a19, - 0xfc9e_e16d_1e79_450c, - 0x21b0_be13_8f13_ee31, - 0x205a_6e79_eb30_e515, - ]), - pallas::Base::from_raw([ - 0x109b_7b36_54cd_ff92, - 0xe219_fd76_bb44_d664, - 0x26dc_47f5_a4c6_cfd4, - 0x1396_0022_9638_8e73, - ]), - ), - ( - pallas::Base::from_raw([ - 0x284f_eee3_dedb_7e0a, - 0xeba3_d6d6_ab74_8634, - 0x206d_133e_7387_88b3, - 0x06e2_9444_0819_67d2, - ]), - pallas::Base::from_raw([ - 0x32f2_7745_dd5d_fa26, - 0x61b9_ff69_431d_6c7e, - 0x7b5e_c381_d868_ecdd, - 0x396d_b442_1b1f_998e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf09f_2925_09b3_435a, - 0x5dd8_7f72_700e_6289, - 0x428f_036b_3027_e4e7, - 0x3ba1_38ab_852a_c4c2, - ]), - pallas::Base::from_raw([ - 0x31eb_6ef7_e3a6_63c9, - 0x66fb_a519_222a_5eef, - 0xf056_ea85_d9a5_5f2d, - 0x0f9d_1a6e_42c7_af7b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2ed8_b60f_5a7d_5c4d, - 0x3c41_ec81_bb2b_0bd4, - 0x5162_51c1_cfd3_cc57, - 0x1628_f847_8492_257a, - ]), - pallas::Base::from_raw([ - 0x1028_dea0_df49_3ad2, - 0x9f64_8ee0_54ba_1f5d, - 0xa5c3_00a6_334b_5071, - 0x22ec_d647_4c9d_8dcb, - ]), - ), - ( - pallas::Base::from_raw([ - 0xba78_884f_a618_b4c9, - 0x2490_cfbd_ef1c_b8de, - 0x6262_4555_49b8_a7cf, - 0x22de_6c00_52d8_822e, - ]), - pallas::Base::from_raw([ - 0xb574_d8b6_4eb4_f13b, - 0x3ae5_7da8_c6fd_7491, - 0xd951_849a_c56a_d2eb, - 0x3d95_2743_8af5_bb67, - ]), - ), - ( - pallas::Base::from_raw([ - 0x423b_21c9_a9ae_e502, - 0xb560_584f_a159_372a, - 0xbde3_a652_e154_27f3, - 0x13e9_25ee_106a_6648, - ]), - pallas::Base::from_raw([ - 0x21c0_83c5_f051_3cd4, - 0x1aa4_9c06_bbfb_670f, - 0x003e_2620_a935_dec4, - 0x06d0_2c9b_fefc_d300, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1bac_349a_3968_df9d, - 0x4f7a_9588_dd94_8cf4, - 0x9c25_b2b9_425b_41da, - 0x34bc_c380_6706_0422, - ]), - pallas::Base::from_raw([ - 0x2e43_e508_767d_ab6a, - 0x8f2e_1357_30de_d522, - 0x1e5d_425e_7b9c_b97b, - 0x3b61_c068_3a4c_a1d1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2f22_1515_dc8d_33b3, - 0x8744_45d2_f4cf_5744, - 0xd439_9e9c_7a24_704b, - 0x0a48_d0cd_b7aa_cb6d, - ]), - pallas::Base::from_raw([ - 0x3265_a994_76ed_b4f8, - 0xad35_4f4c_83db_34fb, - 0x8c76_979a_0183_f56b, - 0x24c0_3c4a_383c_f34b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0264_48de_6bde_8f36, - 0x47df_c98c_065b_94cc, - 0x1bae_0086_8f7b_65d4, - 0x3725_ede4_49fa_fc27, - ]), - pallas::Base::from_raw([ - 0x0784_2c74_c2a0_abad, - 0x98b0_6931_a1fa_c65c, - 0xa0a2_f3f5_c5a0_d649, - 0x34e4_0ab4_f07a_f6aa, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc04a_82a5_985a_802d, - 0xf0dc_11c2_0ff2_f8e3, - 0xf99c_8842_c343_ab5b, - 0x1efe_d560_4943_bc1e, - ]), - pallas::Base::from_raw([ - 0x2b73_38af_72b1_7c87, - 0x7a76_3e90_131f_458a, - 0xf558_1a8c_ede7_797e, - 0x2160_887f_54e5_5248, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa806_7929_bd78_8219, - 0x4502_b7c2_0868_4ba6, - 0x1824_a713_12fa_8662, - 0x1d5f_eb68_ec9c_82c0, - ]), - pallas::Base::from_raw([ - 0xb50c_6fd8_a0ff_197e, - 0x1ecb_67c8_1a98_17ef, - 0x3802_668e_c3e2_e9ad, - 0x171f_bfe8_b8ea_bdc5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3804_32cb_1aa3_0b20, - 0x7206_9e76_128a_dbf5, - 0xfe30_6281_13f9_413e, - 0x3d95_faf6_a3c0_a23d, - ]), - pallas::Base::from_raw([ - 0x5c91_686d_7b70_5f0c, - 0xa432_25ab_ab76_f79a, - 0x1534_bae8_b052_0e10, - 0x1351_24f7_7d93_8a2d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd8a5_d43e_0733_a49a, - 0x59fc_166c_4df8_685b, - 0x6b2c_730b_481e_d580, - 0x0b74_b4c9_b3a5_8739, - ]), - pallas::Base::from_raw([ - 0xf7c3_af4c_034b_e968, - 0x280b_4dd1_da46_b742, - 0x817c_6343_92a5_2bf1, - 0x20c6_7219_0fa4_fd21, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9b9a_5d85_cc8c_cea9, - 0x8a3a_db6c_635f_69e0, - 0xd9e9_bb8c_1560_1184, - 0x1dcc_4260_292a_b5ee, - ]), - pallas::Base::from_raw([ - 0x1291_c646_f66d_6966, - 0xd0b2_d860_6baf_fadc, - 0x5fe4_42f8_21f2_398e, - 0x1b97_d042_35eb_620c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9111_47ed_8621_b0cb, - 0x15d9_a0c5_9075_13d4, - 0x55b6_8241_f6b5_5714, - 0x388f_21cd_bdba_18a8, - ]), - pallas::Base::from_raw([ - 0xd7f4_b6ed_57dd_0be9, - 0xc659_dca1_c72f_718f, - 0x673b_b001_0480_c230, - 0x089f_3734_b014_2b1d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3fef_e211_66f0_64d3, - 0xab1e_a692_2b23_fe74, - 0xabcc_16b8_5b13_edd3, - 0x2f1e_5892_5bfd_9702, - ]), - pallas::Base::from_raw([ - 0xe111_5ff5_cd6b_6e0c, - 0x3b8e_6060_6a62_c9d3, - 0x2a71_2c0a_2329_962a, - 0x398a_1f1d_e5c2_a3b5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb1f7_5faf_516c_5527, - 0x1834_e411_a954_5d74, - 0x5a3d_8f22_5192_48e5, - 0x0c9b_5c3b_99e5_e2e4, - ]), - pallas::Base::from_raw([ - 0xc519_1b97_cd4c_9178, - 0x3d1f_2cfd_ec1d_9f37, - 0x77ea_1ab5_a674_9b12, - 0x1c54_7537_1a50_9219, - ]), - ), - ( - pallas::Base::from_raw([ - 0xeb48_bb7c_bdf0_eca3, - 0x3818_af8f_3f8a_23f9, - 0x1225_2bc6_8251_52c2, - 0x20f2_231c_6b91_756b, - ]), - pallas::Base::from_raw([ - 0xe56c_b770_41bc_64df, - 0x6507_3efb_ec7c_88eb, - 0x4db8_fc10_e0e3_e9a3, - 0x25f5_aa8d_7ed0_e37a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x989d_1174_c5b5_1592, - 0xbc22_de23_d318_4f3d, - 0x0d74_e3e1_c30c_9216, - 0x3c9f_46e6_9974_ef0e, - ]), - pallas::Base::from_raw([ - 0xca71_bc9f_274e_a68f, - 0xda0a_f4d4_b787_77b0, - 0xe011_197f_5425_5452, - 0x02bc_1f24_5fad_07ce, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf66e_e106_a081_b017, - 0xbda0_9fb9_141a_ed66, - 0x8d9b_85d3_a5b2_218f, - 0x3368_44df_9aa0_5205, - ]), - pallas::Base::from_raw([ - 0x21cb_9ec2_7a50_283e, - 0x6526_eb8d_8a98_355e, - 0x4625_6651_5a5b_5bd2, - 0x0dcc_cfa2_eabb_31aa, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdf01_ebdc_d5d5_1078, - 0xdce7_4ffe_4597_40a9, - 0xec30_c721_88d4_926f, - 0x25f4_e3ba_66d0_0bd2, - ]), - pallas::Base::from_raw([ - 0x1aa4_cf28_305d_bd48, - 0xf1ac_ed41_29c5_2fce, - 0x6a79_ae99_419d_2023, - 0x287a_ccc2_aba7_dda2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf6c9_67b1_61e4_3701, - 0xba59_4171_cf75_314a, - 0x2366_fd0c_9845_d326, - 0x07ea_75ef_2e55_1043, - ]), - pallas::Base::from_raw([ - 0x5f6a_b363_1d50_02b3, - 0x42a7_f1d3_8df7_1886, - 0xb175_5fda_e244_41b1, - 0x06d8_b881_47e9_e884, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7760_0ee1_2469_f797, - 0x9d28_9411_63cf_2100, - 0x94f5_d9bc_1e38_d7ac, - 0x0d9d_a8ed_2348_f1d8, - ]), - pallas::Base::from_raw([ - 0x9dcb_1045_7ef9_4381, - 0xf26f_888e_41de_250d, - 0x4db4_569e_a5be_98ff, - 0x2c6e_26fe_e783_b1b6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8252_2117_8b68_e77e, - 0x62b6_4c04_daaf_0edb, - 0x56fc_ef6a_c5ce_9b21, - 0x0060_2183_26a9_b20f, - ]), - pallas::Base::from_raw([ - 0x9381_f756_c758_57be, - 0x2c64_8722_e9b2_aad0, - 0xd21d_fa97_22b7_899f, - 0x37b3_34ab_36d1_3b97, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1dca_d2a7_c9ac_257e, - 0xf481_bd41_dfde_561e, - 0x7fb9_5d59_e14f_9ba1, - 0x164f_e5ae_3a75_5ff1, - ]), - pallas::Base::from_raw([ - 0xd85d_2380_04ed_04b9, - 0xf0a2_f4ca_240b_67be, - 0x328d_6539_b137_e8c0, - 0x1f91_7ad2_3c72_2938, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7c1a_1f69_511d_ddc8, - 0xafef_22d0_8a93_c6bb, - 0x6b7d_de6e_5dfb_8e86, - 0x0418_14fb_9b1b_1fdf, - ]), - pallas::Base::from_raw([ - 0xc232_8d8d_5ade_ee19, - 0xfccd_233e_1faa_328c, - 0xb74a_eb62_bfd2_085d, - 0x349b_497a_e2da_b674, - ]), - ), - ( - pallas::Base::from_raw([ - 0xee76_492e_de05_8c40, - 0x9667_cea9_6321_0dfd, - 0x9ffb_dfe7_bbaf_4d78, - 0x024a_7f47_bbf2_edfb, - ]), - pallas::Base::from_raw([ - 0x2798_9453_54c0_b6a6, - 0x0258_04f1_e97c_9306, - 0xa589_745b_f70f_31f8, - 0x2980_753e_d2a0_1bd5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc217_79ea_fb8d_cf1f, - 0xc7d4_3d68_74e8_1a99, - 0xdf4e_e87a_3da7_0225, - 0x2674_6664_7ec0_66ec, - ]), - pallas::Base::from_raw([ - 0x9a08_438d_3e66_71ff, - 0x2597_f5fd_7ef0_e033, - 0x3490_d2b3_16e4_336b, - 0x0af1_68b8_2ce5_50d0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9ee7_3ace_ad81_d7b9, - 0x7f7d_4d51_c420_2287, - 0x7ea4_8cda_f72c_21d5, - 0x3ba5_ab89_7c05_9262, - ]), - pallas::Base::from_raw([ - 0x65a7_2df6_e7af_1f62, - 0x5018_7079_ed87_6e01, - 0xdd49_7bac_b2f8_f533, - 0x2305_b1e1_10ca_8348, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7bb8_856e_6f81_0866, - 0x2910_87a6_3558_342c, - 0x0197_f6a1_a5ec_2aee, - 0x2e3f_0e84_be82_a936, - ]), - pallas::Base::from_raw([ - 0x24d2_4f23_defe_d26e, - 0xa6a3_fdcb_e123_531f, - 0xf554_544f_9059_9b7a, - 0x1b2b_2c74_2c05_d788, - ]), - ), - ( - pallas::Base::from_raw([ - 0x77aa_8cc5_e75f_61b7, - 0x7ab0_d22c_2c7a_225d, - 0x261a_0bae_d904_6233, - 0x23ca_5427_dfe6_fe96, - ]), - pallas::Base::from_raw([ - 0x3965_f126_8be5_f4f1, - 0xfbbc_f05d_19e0_4468, - 0xcf20_7a1a_dda3_da90, - 0x2dc1_38b3_e758_ae9f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe4cd_d4bb_51f1_3a97, - 0x0ae0_b307_d947_f166, - 0x95c1_0d80_9554_61dd, - 0x2663_0dcd_f58c_a26b, - ]), - pallas::Base::from_raw([ - 0xec69_76ce_7f25_e7fb, - 0x21f1_ef67_603e_b2b9, - 0xb538_45ae_65dc_d7ef, - 0x006b_e5d2_3475_d4f0, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd937_daf5_c74d_37b5, - 0x7b6f_ad60_d7b0_78d4, - 0xeaa2_48f9_cc19_2e8e, - 0x1bff_9849_3f9c_61f3, - ]), - pallas::Base::from_raw([ - 0x1eb4_de71_6993_79b8, - 0x1631_ada7_84b0_c628, - 0x00af_5200_06fa_74cc, - 0x1497_0f48_9ac5_2a83, - ]), - ), - ( - pallas::Base::from_raw([ - 0x585d_8ca2_b07b_c36c, - 0x6a0e_125b_b3fb_3153, - 0x1656_99d8_a31c_48e5, - 0x0c90_2843_2d3d_2ecd, - ]), - pallas::Base::from_raw([ - 0x37b6_c3aa_0a9f_0553, - 0xe75f_7c83_3b31_0906, - 0x0b28_1359_fedd_80f0, - 0x2aea_f21d_78e4_2ae7, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf905_b492_f098_abbb, - 0x91e7_32ad_153d_fbb9, - 0x23b7_9b3d_c26f_956e, - 0x30a8_6999_b4de_0802, - ]), - pallas::Base::from_raw([ - 0xab98_1e4a_ef1a_ce80, - 0x3e6a_1ab7_cc7f_76f7, - 0xfcfc_ac90_b0a9_24bd, - 0x290c_7b1a_b364_d9f0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x89d2_5903_1495_2310, - 0xb8f6_4793_e3fe_9b02, - 0x1298_314c_1048_dded, - 0x35f6_6aef_3f87_5f47, - ]), - pallas::Base::from_raw([ - 0x7f09_c9ec_4e0b_9a00, - 0x02e5_58a8_8b63_c5e8, - 0xdff2_a2ab_eb34_d24d, - 0x182a_04c6_61a5_3ea5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7749_9a48_5a8d_c3c0, - 0x7301_8bb7_d60b_54a8, - 0xbd74_5aec_e134_f4d3, - 0x0ce6_4340_9896_9f25, - ]), - pallas::Base::from_raw([ - 0xb214_a94a_a5e8_5ac9, - 0x3a7b_00db_2c5b_71bf, - 0x1f1f_97e9_4a95_3ea7, - 0x0fdc_1f13_90f2_bdc3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfd7b_3712_3634_9249, - 0xb29c_31f6_a23e_e901, - 0x428c_09b7_ab6a_19b0, - 0x3edb_6eac_7f4a_7fc3, - ]), - pallas::Base::from_raw([ - 0x41ae_5f62_33d0_39fe, - 0x351b_2fad_6a83_3fae, - 0xb027_de87_dc3c_abd6, - 0x1c3c_6b89_8ff4_fbe6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8579_eab4_36d7_7379, - 0x6976_f60e_a7ad_6a4f, - 0x4d44_0486_bd7f_82e0, - 0x33df_087b_d169_6b33, - ]), - pallas::Base::from_raw([ - 0xd8ae_253e_7704_e1b1, - 0x6c80_3c98_5ca9_cb72, - 0x4f76_0a94_7173_e72a, - 0x1749_3c2a_a576_b53e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0d8d_9ce3_bee5_d2a8, - 0x3b11_1e32_1416_7ec7, - 0x866a_5644_f7bc_2429, - 0x2f53_e65c_d670_6b69, - ]), - pallas::Base::from_raw([ - 0xc9bc_a98d_5327_54b9, - 0x1c20_0a22_3360_ac52, - 0x8fd1_441f_3249_5f67, - 0x0891_e7a6_7b7a_a04c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x33ac_b0c2_3336_e65e, - 0xe9bd_f7b7_365f_b280, - 0x3fdb_301c_b124_359c, - 0x225c_f8a4_48fb_0bfc, - ]), - pallas::Base::from_raw([ - 0x7bd0_525c_7c01_37f5, - 0x25cc_2e9e_5ef5_3cac, - 0x0abf_86e7_33f6_5865, - 0x25ec_f837_9bd5_34fd, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1959_74df_433a_0d39, - 0xf92a_d555_fe66_45c1, - 0xde22_fe69_6b67_05a3, - 0x30c6_33cd_5289_cf7f, - ]), - pallas::Base::from_raw([ - 0x2de2_06ae_215b_cdb9, - 0x1dba_733a_5d1c_f06f, - 0x7795_0562_7c29_07b6, - 0x2e05_a443_58f8_295f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8c8d_3e5a_0e9e_27e2, - 0x33a7_ac34_3383_9ad5, - 0x813a_ef88_67ca_27f2, - 0x0351_82c5_aa57_93ea, - ]), - pallas::Base::from_raw([ - 0xe37a_d328_0519_9e75, - 0x9492_ecb8_7225_4d8f, - 0xe440_0d58_32d9_3b4f, - 0x23d7_f634_31de_0e04, - ]), - ), - ( - pallas::Base::from_raw([ - 0xed93_fc4d_8b7c_d2c7, - 0x2ff9_e82a_2813_1039, - 0x9b41_402f_8edd_7482, - 0x2de8_408a_e87c_5526, - ]), - pallas::Base::from_raw([ - 0x8482_7aee_9078_6f5b, - 0xfca5_1acc_7aa9_8a6f, - 0x3b26_c0d8_1fb1_7641, - 0x1e97_cfa5_3430_ce4f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x28d8_3f6f_dd30_2e4b, - 0x8b33_1616_df48_b162, - 0xeb66_7f0b_abbe_d5c6, - 0x1bb4_9f7d_2f00_992d, - ]), - pallas::Base::from_raw([ - 0x8f1b_2585_5975_5b8f, - 0x992a_5645_ac44_49a4, - 0xc7f8_a778_378a_878e, - 0x2388_d495_aa9a_2f14, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb3ee_832b_cca6_e15c, - 0x302e_0976_d09c_f5b0, - 0x3b73_c911_07ca_0590, - 0x1033_729d_e32a_20e5, - ]), - pallas::Base::from_raw([ - 0x824d_03c9_62ab_fb97, - 0x3376_05c3_fca4_da48, - 0xd938_5b92_c1b1_eb7b, - 0x04e9_d53b_9dd7_0353, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2a31_ceea_2bfe_1b89, - 0x459c_7864_3eed_fab2, - 0x8015_ebda_9a08_21f7, - 0x3176_5d48_ed2e_8f38, - ]), - pallas::Base::from_raw([ - 0xbbd2_e12e_2200_a567, - 0xee7e_8b8e_60c9_3161, - 0x4450_13a8_b51e_a17f, - 0x3fb3_ea3d_413f_600f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5792_e1bb_65af_5499, - 0xf38e_ecce_d9d1_90db, - 0x782e_777f_aef9_a1ed, - 0x3275_1af6_d47e_89f4, - ]), - pallas::Base::from_raw([ - 0x0558_8657_d79c_9fac, - 0x4cfc_fa59_c797_3faa, - 0x46ec_529c_3e3a_e025, - 0x2e88_9fc7_1cfe_b590, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4f36_5a89_27df_98cf, - 0xdc4d_ad2a_e1df_90d4, - 0xe8c7_f8c9_f534_a3a6, - 0x1f53_db72_546f_88b1, - ]), - pallas::Base::from_raw([ - 0xc521_f710_64f3_458e, - 0x55f4_b813_b4eb_ca44, - 0x1fbe_fca1_69c2_c1f7, - 0x3270_72d0_0569_db08, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe51c_bf5e_4534_c30a, - 0x9f11_38fe_5b82_ac9b, - 0x31e5_618e_64c9_6740, - 0x1626_a008_8065_ae1f, - ]), - pallas::Base::from_raw([ - 0x4e4f_35ca_0362_3b2b, - 0x589e_4ec7_4b43_ca66, - 0xadfc_a852_9739_1779, - 0x3ec9_c8c2_307f_b4fc, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe558_1772_2b26_fcc5, - 0x8cd2_78c7_57d7_bc6b, - 0x216f_0ed7_5683_8c13, - 0x2bad_b214_0ca1_67ef, - ]), - pallas::Base::from_raw([ - 0x7b8e_54ac_bde4_5d74, - 0xf12b_ee08_f085_ef2b, - 0x59be_cb38_9bb3_7cba, - 0x10c2_e53a_d289_3205, - ]), - ), - ( - pallas::Base::from_raw([ - 0x05bf_6073_a2cc_922b, - 0xaa40_a1b1_c161_a6f5, - 0xe7aa_a199_d7b3_f2be, - 0x2ec8_895a_ff5b_5376, - ]), - pallas::Base::from_raw([ - 0x21a9_2a6f_5c37_ad34, - 0x9ed0_8f7e_4c30_d354, - 0x0c92_ae6b_73d0_ddf0, - 0x02af_e3c9_f6d8_8524, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa364_1c63_2ef7_445f, - 0x1601_4441_ab17_06e9, - 0x5e0c_e5dd_d268_6d5c, - 0x2962_bd56_585a_49b2, - ]), - pallas::Base::from_raw([ - 0x8f33_3912_6908_c490, - 0xb337_01a1_f6fb_f2c6, - 0x5b5d_ed95_d5a1_587e, - 0x175a_30c9_9d0b_dcfa, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf982_0b5c_aa89_84ec, - 0x8cd5_6f8a_04f7_0000, - 0x45bf_1e43_42e6_c668, - 0x2b33_5ef2_cfc8_0c83, - ]), - pallas::Base::from_raw([ - 0xd28e_8c9a_a973_eb4c, - 0xfc8d_633c_c565_5eb8, - 0x49f8_808f_b1f8_2460, - 0x26df_2492_c732_e56c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xcc02_e14a_ed10_15df, - 0x7ab2_e6da_6148_1b32, - 0xf1b8_ccf5_7959_7c1f, - 0x1f39_1c76_d2a5_87d4, - ]), - pallas::Base::from_raw([ - 0x6161_8e3c_c900_c078, - 0x8051_d2da_5db8_ca06, - 0xf00c_bba6_4a81_7e59, - 0x0212_f279_9961_28a4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xba12_bea4_1ed1_352d, - 0xc72a_1238_3074_4e06, - 0x774b_4680_7bce_521e, - 0x1b55_f307_4483_1944, - ]), - pallas::Base::from_raw([ - 0x4339_05b5_7199_f756, - 0x5018_a2d2_8374_18cd, - 0xc369_3735_482c_e33f, - 0x06d1_33c4_e935_ed22, - ]), - ), - ( - pallas::Base::from_raw([ - 0x17d2_e055_42f8_9a6b, - 0x63c4_572c_834a_9911, - 0x7c98_197d_30e9_06b9, - 0x1bb8_0e9c_7b1c_a773, - ]), - pallas::Base::from_raw([ - 0x757f_5677_f5dd_82dd, - 0x6030_5392_57bb_182b, - 0x22e8_e711_493b_46f2, - 0x2462_9d6c_1107_6339, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc227_0007_0d48_67fa, - 0x5a14_a6ed_8e5a_164c, - 0xf31b_979b_e4fa_a4dc, - 0x2260_9c32_ae8a_2fe1, - ]), - pallas::Base::from_raw([ - 0xcbbe_cd59_36ba_6c7a, - 0x768f_7786_ddb9_39e0, - 0x8ee0_8603_e206_e123, - 0x14f1_bb3e_19ad_9852, - ]), - ), - ( - pallas::Base::from_raw([ - 0x36cc_d0fe_865e_1f8a, - 0xd12a_6df1_2f9b_0183, - 0x8fc1_7986_8075_3758, - 0x230a_a792_feb2_5fa6, - ]), - pallas::Base::from_raw([ - 0x2489_a5cd_0cc0_bae0, - 0x6f0d_c5d3_924f_4676, - 0xea2a_6502_9734_9b71, - 0x2596_75b5_6bcd_40ed, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc111_adf6_14ce_6cb0, - 0x4aba_0e21_bab9_0092, - 0x99e9_d9dc_1d39_ead0, - 0x1d84_4ec6_9215_ea84, - ]), - pallas::Base::from_raw([ - 0x665f_32ce_34d6_3a28, - 0x166d_7faf_b4f3_51da, - 0x71f2_1dc9_4a3a_0837, - 0x1cbd_dd75_d802_7a07, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbb16_0c4f_b407_3444, - 0x4f4f_3c61_ac00_a4f7, - 0x3c3a_271a_012b_988b, - 0x1b4d_4160_2bd3_ae10, - ]), - pallas::Base::from_raw([ - 0x61f2_9112_22f7_b25b, - 0xd2e6_eee7_d3df_2364, - 0x156e_24e6_a1ef_9b96, - 0x2cc4_b4f6_2b98_9419, - ]), - ), - ( - pallas::Base::from_raw([ - 0x90ad_379e_cf99_5052, - 0xfdd3_5b06_452e_f10f, - 0x3231_9fe1_ccd6_5847, - 0x37d6_0e5c_6f9b_157d, - ]), - pallas::Base::from_raw([ - 0xef5e_4b6d_8a11_3611, - 0xfff2_8aed_9719_e68f, - 0x0022_f704_2bc5_4b86, - 0x24d1_1739_87a0_150f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x67b6_a004_5b76_df29, - 0xd780_7758_5dd1_72c5, - 0xfd94_bada_1b47_6147, - 0x055a_ef12_3bb1_7975, - ]), - pallas::Base::from_raw([ - 0xc40d_7914_b6fd_0059, - 0xcd4b_03e5_9621_c0cf, - 0x5804_3959_aa1b_5cb4, - 0x399e_7d93_333c_9f5c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe987_36b6_6ff3_a8f3, - 0xb633_6b7c_e2d0_1c29, - 0x72b5_e138_e871_8594, - 0x39e3_1af0_f759_2d94, - ]), - pallas::Base::from_raw([ - 0x2584_aad2_a9e9_6991, - 0x4d67_c9b6_57a0_00f8, - 0x1fef_7c39_245d_f66b, - 0x39a5_61f5_b60e_13ce, - ]), - ), - ( - pallas::Base::from_raw([ - 0x12a8_2bb3_679d_2e7d, - 0x7923_949d_cf92_266e, - 0xb997_e0d1_8eda_a746, - 0x2722_d4bf_937a_919d, - ]), - pallas::Base::from_raw([ - 0xdcc8_3afd_5c79_7391, - 0x25a7_833d_a733_98ac, - 0xd82e_903f_c00f_3f8b, - 0x20b2_7ae6_263f_b41a, - ]), - ), - ( - pallas::Base::from_raw([ - 0xef97_ec2a_52ec_aaab, - 0x6456_0e73_b84c_0532, - 0xf42e_0f1e_2164_9dbc, - 0x362d_769b_3e3b_429b, - ]), - pallas::Base::from_raw([ - 0xa849_45d4_8229_07c7, - 0x8319_319a_9dfd_eb24, - 0x1b53_33bd_832f_9d47, - 0x1a8d_4605_440e_14eb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2cfe_f055_520e_c484, - 0xd39b_1ad9_5e10_8589, - 0x1aaf_3ba7_8102_4b08, - 0x39c3_c628_22fe_6009, - ]), - pallas::Base::from_raw([ - 0x45f8_894e_2232_67ac, - 0x4296_0ed4_94f2_d879, - 0x91c3_5975_0a2e_a628, - 0x0055_3f58_2ea2_b9d8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9dd7_97f4_738d_a24c, - 0x2759_7dca_3390_3158, - 0x2569_cf2d_55e1_3988, - 0x3a35_4403_855a_ecc7, - ]), - pallas::Base::from_raw([ - 0x8cd4_53df_2421_8d58, - 0x3eb8_606a_39df_7bba, - 0xe1b6_b3cd_016d_2c04, - 0x2ac0_1e01_122f_2859, - ]), - ), - ( - pallas::Base::from_raw([ - 0x05ee_bec3_ee74_bbef, - 0x9235_beb6_d261_7620, - 0xbe1b_e89b_c34f_92fd, - 0x3e52_f01c_752c_b88b, - ]), - pallas::Base::from_raw([ - 0xf3a9_51ca_cd8a_af53, - 0xc74a_97e4_097e_c343, - 0x092e_9e05_bffc_9a22, - 0x3d5a_5fc8_11e3_ba39, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0ce5_3d2c_d538_3a58, - 0x3ef1_eb32_6ca3_e72f, - 0x3c78_7688_7698_fc9b, - 0x3e74_cad7_49d2_c6c6, - ]), - pallas::Base::from_raw([ - 0x1f1c_faed_0c97_13d5, - 0x3c44_cdd9_d43b_1878, - 0xa99e_49e2_45a6_8dbe, - 0x3d13_8bac_6757_2e90, - ]), - ), - ( - pallas::Base::from_raw([ - 0x83f7_da35_d76e_c72f, - 0x5d1b_36e6_359e_06e5, - 0x4467_a198_0e08_1507, - 0x3416_e9d4_12cf_fc58, - ]), - pallas::Base::from_raw([ - 0x2730_0907_8ed4_7765, - 0xb022_0ab4_912b_7d90, - 0xb416_bc2b_6319_e9c9, - 0x10fa_d4cc_a19a_342c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa6ce_2794_9121_884f, - 0x92a8_a18f_02e8_8e44, - 0xcadf_04d1_3995_43e9, - 0x35f2_987c_a27e_1776, - ]), - pallas::Base::from_raw([ - 0x4f73_1ea3_e5d8_f863, - 0xbefa_b1c9_dacb_8028, - 0x91bd_d4ef_ab4e_02d4, - 0x39ea_3c5e_6cb8_47ec, - ]), - ), - ( - pallas::Base::from_raw([ - 0xba0e_d638_9040_a526, - 0xade3_6a2d_1046_ce2f, - 0x07c4_031f_7d63_bfda, - 0x3705_7fe5_eff1_6d4b, - ]), - pallas::Base::from_raw([ - 0xcb3d_da9a_230f_7d4f, - 0x3ec2_fac7_acc4_e22c, - 0x09bc_83c8_6022_52ca, - 0x01d7_c169_7b90_1850, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0316_2275_7062_aa8b, - 0x06e7_bf78_c301_eb68, - 0x5a45_ea8c_518d_e8fe, - 0x1a8b_f176_fdd8_5a16, - ]), - pallas::Base::from_raw([ - 0x1de4_ed97_6261_3da9, - 0x7c2d_265b_75a5_c58e, - 0xdecf_84e1_13a6_493c, - 0x1853_c9ac_fc18_1ad9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x18f8_f690_da5c_857a, - 0x8baf_5e54_f47a_4c66, - 0xc596_5adb_9056_e487, - 0x0b41_5e4f_c50b_4723, - ]), - pallas::Base::from_raw([ - 0xf758_8e8b_d1c1_5233, - 0x3bb8_512d_7b1e_a04e, - 0x3782_0e10_b3da_73da, - 0x2c2a_1026_015a_e0af, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc491_0da2_ab40_38fa, - 0x8919_0bf6_2117_4bb0, - 0x11b6_3346_fe70_1c31, - 0x01e3_fd81_583f_9350, - ]), - pallas::Base::from_raw([ - 0xdc61_17c0_98c1_601e, - 0x1ab5_a27b_e45e_f81e, - 0x52a2_3f16_f37e_1612, - 0x0b0a_7f80_97e2_e6cf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x520b_062f_e78a_e7a4, - 0x3cfd_2ac9_15c5_e15e, - 0x6f6f_0d82_41c1_d542, - 0x3d45_bbb4_6013_9f32, - ]), - pallas::Base::from_raw([ - 0xb1ac_5c97_c97a_3879, - 0xef0c_c0f2_56ab_5321, - 0x622a_376f_e184_60c6, - 0x0529_7efd_374c_32b5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc226_4973_4c5f_c60a, - 0xda93_2f28_b15a_50e6, - 0xcce7_e413_9c75_ced4, - 0x2a0a_7edf_84f3_ca0c, - ]), - pallas::Base::from_raw([ - 0x97e9_ae4d_cf51_e9c6, - 0x7763_6a76_34f8_eb62, - 0xc1db_731f_15d6_84d7, - 0x28ae_45a0_2811_2280, - ]), - ), - ( - pallas::Base::from_raw([ - 0x48e1_7904_526f_f906, - 0xd5fd_96af_3118_d25d, - 0x16f2_1379_295a_3e85, - 0x056e_6682_1209_f065, - ]), - pallas::Base::from_raw([ - 0x4d09_3b0c_18f0_4853, - 0xf28c_aecf_c757_36ed, - 0x0124_3cba_966f_a69b, - 0x2bf0_69d1_a8f4_e195, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa2ab_2ca3_3f7a_8c18, - 0x5fbf_9a9e_292c_3fee, - 0x42d2_fb9b_62d4_bf6f, - 0x1513_87c4_5019_b2a8, - ]), - pallas::Base::from_raw([ - 0x45de_0a99_709d_8f92, - 0x013b_c62b_f18c_2d51, - 0xdc17_e477_e451_a5b5, - 0x189b_e9b3_2748_ccfa, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb1d2_10c0_c338_3697, - 0xdde9_1ff0_0a98_9f1e, - 0x57b1_5511_fac4_ae0b, - 0x3415_5509_eda9_fb3a, - ]), - pallas::Base::from_raw([ - 0x0336_a0e4_4d04_f2a0, - 0x0c38_8030_f51d_1168, - 0xdb88_0218_359b_52b6, - 0x1669_7954_3729_1904, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf754_4d39_2e15_d646, - 0x042c_85b5_e75c_bffe, - 0xe38b_c7e1_c3a3_371e, - 0x1f78_4954_3955_3ffd, - ]), - pallas::Base::from_raw([ - 0xb3b0_03ef_ce95_fe55, - 0x3447_f020_3e43_a221, - 0xd3ec_5b00_f101_a4a7, - 0x1daf_fb55_fdca_e9bb, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd022_b2e4_3b43_5771, - 0x1f98_8073_0dae_5fa9, - 0xa19c_1dae_ee9d_2279, - 0x2d7c_10f1_1f8a_fbe2, - ]), - pallas::Base::from_raw([ - 0xe53e_4dc4_e5c6_9e51, - 0x2af4_1c7b_e73c_bfc3, - 0xf0e0_1136_6a8b_7018, - 0x0b77_44c8_8c77_fcbf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9ed7_be62_3b40_bcb9, - 0x3e31_f660_58df_eb96, - 0x0158_90c1_6331_430d, - 0x21ad_7eae_f186_64a9, - ]), - pallas::Base::from_raw([ - 0x4997_85d6_de57_f60b, - 0x3a83_9c1d_c46b_2861, - 0xaea4_ad0e_e1cd_df9a, - 0x2472_290e_1d0b_53b2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa73e_3284_1eb0_d3cf, - 0x5dd2_c1b8_16cb_cd57, - 0xac16_7859_a9c2_66b6, - 0x39d0_2f80_ee2f_5fdc, - ]), - pallas::Base::from_raw([ - 0xf33d_b523_81f4_08e5, - 0xa267_d464_ddb6_94ce, - 0xde0d_2c54_83af_3f7a, - 0x3105_d9d7_4eb0_8afc, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0f06_d3f2_ae51_741c, - 0xb747_9d5c_a4b9_5a80, - 0x7839_36ab_4715_89b0, - 0x17e1_7cf7_cf73_abce, - ]), - pallas::Base::from_raw([ - 0x228e_32f0_7e39_0ca6, - 0x92fe_35e7_744d_16a8, - 0x235f_5e1c_a1d9_dfa7, - 0x2adb_4c5b_3bd6_6726, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5819_6066_3266_3841, - 0x24da_b91e_6b28_9f04, - 0xb79a_cf49_63a4_4105, - 0x21da_e5c6_0cb6_7703, - ]), - pallas::Base::from_raw([ - 0xa223_487e_6406_576e, - 0x86b6_9d9e_7467_7eb2, - 0x7e2e_531d_048b_6ae2, - 0x1796_bb64_46b9_0567, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6b90_eb45_561d_04dc, - 0xe743_9460_131c_ae9a, - 0x2735_4e72_d3b1_3274, - 0x181b_8996_1ce6_dbf2, - ]), - pallas::Base::from_raw([ - 0x4393_a574_6e7d_ebcb, - 0x17b9_57b0_374b_7321, - 0xf48f_1499_0aeb_f4ff, - 0x2af0_a0cc_80d8_ad59, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8a86_d29c_9a81_c5a9, - 0x2393_6d2f_411a_1f97, - 0x50f6_242a_40fa_9525, - 0x05b0_faf1_c315_0a4b, - ]), - pallas::Base::from_raw([ - 0xc70c_9a93_ab83_1c95, - 0x6ed2_9ae9_ceea_efb1, - 0xc7fe_68b2_22e1_cf03, - 0x381d_cfd0_1918_44b4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7d5a_3127_5dbe_b7d9, - 0x79e0_3de5_25ce_dab6, - 0x935a_02dc_9fdc_eab4, - 0x2b4d_4719_7811_4448, - ]), - pallas::Base::from_raw([ - 0x7673_78df_e2fe_1eb2, - 0xbe91_9301_c9aa_5f18, - 0x60ee_48c0_4796_a28e, - 0x2f24_3e8c_7b7f_4693, - ]), - ), - ( - pallas::Base::from_raw([ - 0x58ac_fcec_3b6a_6302, - 0x778c_ceb2_8a49_ffb4, - 0x8c28_f55d_2771_8a04, - 0x3c4e_cb86_6f24_7db3, - ]), - pallas::Base::from_raw([ - 0x7fbe_d4df_7b3f_fc86, - 0x8540_6cc9_d470_f2ed, - 0x0bef_5e3d_830e_0220, - 0x2c60_c874_457a_d78e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2fb1_b9b7_f918_5676, - 0x3b9c_0985_f979_e385, - 0x3c64_e299_b19e_df3f, - 0x38c6_03c7_f4c2_e21a, - ]), - pallas::Base::from_raw([ - 0xb328_4e4b_3bc3_34f9, - 0x1a14_4a9d_9ca6_9b21, - 0x8d0c_c279_4992_b9b6, - 0x0ce6_19ca_d57c_1085, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9555_d1a8_a695_617a, - 0x9f38_43fe_8064_4c5e, - 0xa495_35cb_8d85_c2e7, - 0x2d01_2113_eb7c_976f, - ]), - pallas::Base::from_raw([ - 0xb4b7_72bd_6491_50b5, - 0x45dd_d92f_bdeb_1fd5, - 0xedaa_6443_41d8_1b41, - 0x2966_c1c6_12e0_0292, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6095_00b2_ffd5_9f23, - 0xc0c2_61ef_b258_de48, - 0xcbcd_b97b_51c2_00ac, - 0x0bef_2f3a_5b4a_70a6, - ]), - pallas::Base::from_raw([ - 0x69f9_ffcf_df73_c226, - 0x3c86_f51d_5b51_5ddf, - 0x0826_406c_ef5e_e020, - 0x05f0_31fe_225f_e8c9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x314d_d52e_0919_736c, - 0xf554_b5ea_55e9_39ff, - 0x7775_a5d8_d07f_9f27, - 0x18b9_43fb_57be_afd4, - ]), - pallas::Base::from_raw([ - 0xf563_1374_8745_63e7, - 0xbd1c_a9d6_622e_8cd2, - 0xd060_6006_611b_cc4e, - 0x360d_025e_38f6_02a0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x399e_2e74_4e2d_d3b9, - 0x43e3_74f8_8b83_0cba, - 0x4289_a1c4_48cd_f4e0, - 0x196d_f315_b594_9716, - ]), - pallas::Base::from_raw([ - 0xc288_6cd6_673f_4deb, - 0x21f2_2728_b89f_4ed3, - 0x3439_6d66_d9a9_48fe, - 0x1089_5fb4_40fe_bb75, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4316_a351_fc82_dd4a, - 0xc959_7950_4cfc_ed50, - 0x7273_943a_84cf_d15e, - 0x15aa_aa6c_c1b9_6ac1, - ]), - pallas::Base::from_raw([ - 0x1b99_d676_512b_796d, - 0xce39_dff1_cba5_dbbb, - 0x421d_4fa7_1462_6d44, - 0x34ad_9d2a_dfaf_5b69, - ]), - ), - ( - pallas::Base::from_raw([ - 0x49ad_a6d1_104a_6eef, - 0xcf8b_024f_cfb5_b7cf, - 0x840c_cc9d_3a3b_cc91, - 0x29b9_5744_64e1_ddfc, - ]), - pallas::Base::from_raw([ - 0x0b87_716a_708c_c280, - 0xf93d_800f_6f21_4435, - 0x1d51_3c67_2d6a_83ff, - 0x0ae6_d491_c1bd_f3bc, - ]), - ), - ( - pallas::Base::from_raw([ - 0x475e_41b0_f1fc_c172, - 0x09b7_1408_69c4_0bb0, - 0xc7ed_2eaa_6b58_0c14, - 0x1d5a_ddce_4556_7eae, - ]), - pallas::Base::from_raw([ - 0xb805_a989_ed0a_19a9, - 0x18f0_a092_4a48_ce6a, - 0x377c_c390_6667_48ba, - 0x0101_7bec_5e9b_8784, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc424_869d_df4a_4fd1, - 0xcb89_e9c6_1506_8e77, - 0x6573_5f9d_0d64_ad1e, - 0x1a16_1910_f3ef_d2a8, - ]), - pallas::Base::from_raw([ - 0x1c2a_ec44_2e96_e2b9, - 0xe5e2_6cbb_e793_3cd1, - 0x4152_f5a5_afcf_0b33, - 0x18bd_33f6_2cd7_afc2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6cef_2ed4_0f12_62a3, - 0x629f_be6a_9a08_13b6, - 0xe188_e97a_fd70_5e9a, - 0x1c81_abae_085e_bbdd, - ]), - pallas::Base::from_raw([ - 0x6b64_e32d_d83d_14cc, - 0x051c_e812_b7d3_8e72, - 0x7c9c_e5ff_9dab_955d, - 0x2c11_dcb2_7ed5_553a, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa486_1053_6543_7c5c, - 0xbaef_3528_5949_99b5, - 0x6ebc_2d21_8bd5_7856, - 0x1194_f3a8_8f8d_20d8, - ]), - pallas::Base::from_raw([ - 0xc583_16cf_02c6_0b44, - 0xbae8_db73_6695_4f2c, - 0x1321_fe4b_4bc8_ff74, - 0x1f90_ec5d_5cdb_66c9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3e78_8bbc_500b_061b, - 0xa39f_04d5_7d40_d1b4, - 0x1075_ff0a_e695_322e, - 0x29e8_f7f2_17eb_d76f, - ]), - pallas::Base::from_raw([ - 0xbf38_0b79_6b13_1fc9, - 0x6464_a70d_f53b_4597, - 0x7026_66e6_dd97_4644, - 0x12fe_b0d1_9689_e650, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfd13_2e00_4e5d_4971, - 0xc505_01d2_b5ea_6072, - 0x9202_b952_2e65_9ed7, - 0x3ab2_84aa_1043_7b11, - ]), - pallas::Base::from_raw([ - 0x4de0_8d20_70f7_f5e1, - 0x550f_b47d_5648_c508, - 0xf74a_5a30_6073_9c33, - 0x3b52_c98c_59db_48ec, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb565_72c3_4d9d_f266, - 0xd4cb_8d31_2f6e_e625, - 0xcd7e_2193_6f0a_a501, - 0x3173_b0b5_e1b9_bcb7, - ]), - pallas::Base::from_raw([ - 0x7bb7_0367_d936_382b, - 0x90d5_03e0_1a24_9fa0, - 0x1d1a_fceb_21eb_295a, - 0x2a42_5586_0ab7_f2de, - ]), - ), - ( - pallas::Base::from_raw([ - 0xea5b_ff65_c9da_428a, - 0xa4cb_a520_eadb_5354, - 0xd80d_5043_0b03_7bdb, - 0x30f5_493e_17bf_d471, - ]), - pallas::Base::from_raw([ - 0xa752_0e7f_dd99_dba5, - 0x5d12_6ed0_d9a3_2a25, - 0xf835_77c5_523e_9c66, - 0x3096_0d36_5f12_d42a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6698_5d13_ac44_6aa6, - 0xb773_2f26_9677_6e12, - 0x1fb7_b640_8501_50b1, - 0x335c_045c_e3ac_a829, - ]), - pallas::Base::from_raw([ - 0x1134_b8f8_bddf_ae01, - 0xfc14_9622_110b_9e4d, - 0x292a_9dfe_fed2_495a, - 0x2d23_4774_78d6_9f8c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe697_a384_bfe0_e7b9, - 0x9600_e548_7eec_8f61, - 0x5cf6_d911_d00d_4080, - 0x2f72_9fef_7fb4_9c3d, - ]), - pallas::Base::from_raw([ - 0x6f27_44cd_0eb3_ccea, - 0x20a3_f582_850f_75ee, - 0x0a5d_de13_44a9_f626, - 0x35ce_7274_5aba_1199, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7745_e733_21ad_a466, - 0x7e96_b0af_9e4e_eac1, - 0x9076_89d2_d2fe_4108, - 0x0ad7_74ec_279a_de59, - ]), - pallas::Base::from_raw([ - 0xeb87_26d2_fa30_f945, - 0xf59f_fb36_952a_758e, - 0xf46c_d397_277b_f15b, - 0x0e42_e600_a788_4e1e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x42d7_c6e8_1a54_7d39, - 0xb171_695f_50a8_bd62, - 0xfe87_5f93_5739_16ba, - 0x2b7b_81a1_9e1a_f147, - ]), - pallas::Base::from_raw([ - 0x5479_f6bc_eb58_7cf0, - 0x55a1_827c_f39e_06ab, - 0x2a9c_0fc4_d3e9_aaae, - 0x1934_b567_9c19_e682, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe18f_eb78_018f_21fb, - 0xcfa5_4075_0fa5_0007, - 0x05e3_f7d5_9d0f_5e8b, - 0x2cc9_4cc1_fe1a_3754, - ]), - pallas::Base::from_raw([ - 0xc2d2_f324_8b4c_ae1c, - 0x447f_7745_c5a9_dedd, - 0x3c21_26cb_32f6_9c68, - 0x08d2_cff6_fba5_5d5b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb5d8_5390_444c_c212, - 0xe08f_cf9d_bef6_3c10, - 0xe6cc_866a_fb3c_80e3, - 0x1973_ffe7_d02f_0fa4, - ]), - pallas::Base::from_raw([ - 0x433d_1974_b639_e380, - 0x10e3_a8f5_d79c_3bb2, - 0xc48b_7633_c798_f597, - 0x2b49_6a88_af43_e434, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6be3_5a9e_4646_9b0a, - 0x21fe_d657_d107_f630, - 0x99d3_0abd_ab7b_8d62, - 0x3509_1866_4a0e_e32f, - ]), - pallas::Base::from_raw([ - 0x0454_ba7b_2b38_8723, - 0x994c_fd44_0535_add3, - 0x5c3e_e7d5_a694_1082, - 0x3e6b_3a1f_16bb_57e2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xffb6_e87a_f4f9_273d, - 0xa3b4_9290_844f_d1f0, - 0xd9d9_9177_ac41_03a2, - 0x1ba6_f2f8_98ad_5de0, - ]), - pallas::Base::from_raw([ - 0x2199_f2d0_0e0a_20d2, - 0x47bf_5d92_1c69_7f48, - 0xb50d_409d_b342_4e95, - 0x0fc8_6805_b969_8fa4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x36ee_72e6_26d6_16f4, - 0xa85c_131e_8f2e_e5d1, - 0x544d_49b6_d5fe_bc77, - 0x0900_2d79_10df_23fd, - ]), - pallas::Base::from_raw([ - 0x768f_c641_47a7_920b, - 0xafed_4d26_3791_7ef3, - 0x25ef_bc62_b972_a83c, - 0x0a20_b646_a0fe_e655, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb83e_09de_6703_6a2c, - 0xc6e4_2d86_9a1c_8a6f, - 0x26cf_9928_a140_3757, - 0x2ea1_20a4_bb61_d62b, - ]), - pallas::Base::from_raw([ - 0xc7aa_5256_b121_eafd, - 0x37a9_d899_91a1_fb45, - 0x0c6b_29a8_5134_4bbd, - 0x0047_cc6a_f224_fb19, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9c0e_5b82_9469_8c2f, - 0x246a_ab8d_57f7_eb14, - 0x6acc_27f8_d28b_015c, - 0x14bc_c3c2_2e2e_b6bb, - ]), - pallas::Base::from_raw([ - 0xbcfd_9f65_9803_ac84, - 0x9065_8c67_7b1a_f1a8, - 0x779e_13d7_fbca_9d34, - 0x0cde_f9bd_324e_1df5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2fb5_5ddd_b490_61f1, - 0xe18d_c4f6_f48c_ff60, - 0x209e_1749_1f95_8e22, - 0x0651_e474_e0d8_11c6, - ]), - pallas::Base::from_raw([ - 0xadb6_45c2_ec3c_cbbb, - 0x35a0_eac6_b2d3_0210, - 0x4ad9_2ead_3d43_a194, - 0x2e39_0f7a_bc18_85b6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x23ca_ecf8_4a99_8786, - 0x48da_db27_2bd6_3318, - 0x9d89_40f9_b2d3_7799, - 0x17fa_61d6_05a5_8987, - ]), - pallas::Base::from_raw([ - 0xc88f_47e1_1d26_8daf, - 0xfb0d_a012_55ff_62bc, - 0xac10_cf88_df83_2cca, - 0x32f1_0c77_19eb_ab29, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3195_102f_c327_9b31, - 0xacfe_b6c5_89a5_d878, - 0x9367_2ab2_d8e8_a423, - 0x14ac_50c6_6669_ba07, - ]), - pallas::Base::from_raw([ - 0x8454_fc70_093a_e70e, - 0x83cf_e218_71ea_9716, - 0x8f87_513a_2560_8897, - 0x3042_845c_65f3_82fd, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe3bd_44e1_cf62_b948, - 0xaca4_8396_f097_f8f9, - 0xaae7_28f2_e533_dd59, - 0x205a_0002_d292_790e, - ]), - pallas::Base::from_raw([ - 0x3747_573a_6340_da58, - 0xc462_be08_e666_c34c, - 0x932b_a9bd_22ef_0dd1, - 0x3c05_7dd9_7523_55c2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x21bc_7af6_3b01_c7e9, - 0x6252_732a_b6ba_dc77, - 0x8936_7ad2_a6da_3eaf, - 0x3423_225a_a8b2_648c, - ]), - pallas::Base::from_raw([ - 0xbf9f_96b4_d37e_cdbd, - 0x9788_5731_a6b5_c21e, - 0x8e53_deb0_53bd_d03f, - 0x0267_f659_8e41_9d57, - ]), - ), - ( - pallas::Base::from_raw([ - 0x16ce_c525_99d8_4e32, - 0x0be9_87cf_f76b_791a, - 0x64e9_f724_3ded_90cb, - 0x3f4b_7c45_f7fd_0a5b, - ]), - pallas::Base::from_raw([ - 0x504d_f52d_0a5e_6f9b, - 0x0ffd_7f14_c471_c25e, - 0x05f5_f6a6_f4e4_3235, - 0x03ed_4df6_1b9b_8e2f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4d55_7ecd_d9bc_b076, - 0x5408_529b_d207_78e4, - 0x58de_ce33_83ef_9bd5, - 0x08e2_3b7f_80c4_f1ce, - ]), - pallas::Base::from_raw([ - 0x2439_550a_1d3f_5fe7, - 0x6f35_49ba_c229_e7de, - 0x4ff1_8163_5458_c34c, - 0x18b0_1033_f86c_5b2d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7932_981f_1490_acb6, - 0xae32_d1c6_69f1_ba87, - 0x487d_3e38_98de_ad2f, - 0x3360_9d96_1cb9_e4bb, - ]), - pallas::Base::from_raw([ - 0x2df5_c107_9de0_42d9, - 0x3a5e_e2d8_4f95_338e, - 0x0f61_1e54_8e5d_6071, - 0x314a_f599_b686_4f6a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x12ec_74da_fb34_4c9c, - 0x86e7_c394_398c_b2b0, - 0xb350_5e55_0f41_55b3, - 0x3882_c274_d10f_9604, - ]), - pallas::Base::from_raw([ - 0x0475_5416_a740_3cc8, - 0x7bc7_5c57_18be_8417, - 0x7225_cf87_5def_f0bb, - 0x354b_a5af_e4b7_8ab5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb928_8c66_ae60_cf6b, - 0x8a01_3bed_8367_6133, - 0xf9d3_d4e7_a269_61af, - 0x1590_bf3d_b717_8a0f, - ]), - pallas::Base::from_raw([ - 0x2988_6de5_e09d_b63b, - 0xffee_8de1_593f_5931, - 0x6c10_c99c_784a_4ab0, - 0x08b8_0c40_7a4e_c18f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x07ef_5d82_7684_6a64, - 0xf266_7542_3316_83e4, - 0x63e8_e5b2_b6e0_98a8, - 0x115d_36de_a116_3915, - ]), - pallas::Base::from_raw([ - 0xf5cb_ccd4_6981_b817, - 0x739c_6e08_5a3a_acc1, - 0x43c3_a2dc_0dc8_4a1b, - 0x3061_050b_bec9_728c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa784_97ba_84c4_9897, - 0x0bdf_4a54_6f11_477b, - 0x78d4_5bc7_61b4_4fc4, - 0x009c_265a_01e4_bd27, - ]), - pallas::Base::from_raw([ - 0x83d6_88e2_3124_442f, - 0xdaf5_4110_7337_7228, - 0x0476_e74e_a35f_a96c, - 0x1cbc_b10c_31c5_a6ce, - ]), - ), - ( - pallas::Base::from_raw([ - 0x815f_09ef_7425_c941, - 0xddea_5b91_af1f_b16e, - 0x44c4_8ec0_6e4c_4d5b, - 0x3eb2_6944_09dd_347a, - ]), - pallas::Base::from_raw([ - 0x5075_853b_087d_36e1, - 0xa637_4ced_4fb9_8cd2, - 0x8f41_0471_fa56_764d, - 0x2a49_2949_e50a_5431, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2a44_94c5_80ca_c7b1, - 0x5c80_bc62_be0c_4c20, - 0x3e9b_c8a6_76ee_a29d, - 0x31e9_f489_5373_0252, - ]), - pallas::Base::from_raw([ - 0x0cc5_99cc_2d44_795f, - 0x5f34_2d7a_6dbb_d769, - 0x1e03_83ac_5bb1_3b70, - 0x3576_b8fa_eecc_5390, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0d73_8802_f12c_9a24, - 0x574b_d31a_7a88_fc47, - 0xfc84_3f6a_5d93_3592, - 0x1386_f0fb_f8be_9c27, - ]), - pallas::Base::from_raw([ - 0x5a23_540a_296c_f044, - 0x6192_3af4_1508_7a98, - 0x5995_b4cf_15cc_2810, - 0x1706_3276_50a0_f036, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2653_f155_85de_a90b, - 0xd63d_94d0_8aa1_482f, - 0x6a82_4715_8027_d155, - 0x1df5_02c5_50b8_da4c, - ]), - pallas::Base::from_raw([ - 0x1c94_bebe_da62_eb37, - 0x0d7d_52bc_04b8_1267, - 0x8c2f_be33_eb00_04e4, - 0x0440_0a84_ea35_612f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5c1b_8f52_5659_4536, - 0x9b79_4d4d_2397_825f, - 0xbbde_a8df_0f7d_ba1c, - 0x3d29_b2f0_082a_5564, - ]), - pallas::Base::from_raw([ - 0x997a_e0be_a8e8_c381, - 0xd8fb_2e89_3946_7e27, - 0x23e9_4e6b_32ae_749c, - 0x37be_d4a7_96d3_6ef1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2b55_fd72_49a0_af15, - 0x84b6_ef86_00bf_2219, - 0xa742_27da_4188_25e1, - 0x2de3_dd50_d348_4b87, - ]), - pallas::Base::from_raw([ - 0x7c51_9935_0187_19af, - 0xe12b_c342_f5ad_3380, - 0x4771_3997_d6b6_6fdb, - 0x2781_cf1a_f080_88bd, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd6b5_8567_e42e_6228, - 0xba55_c9ee_caab_1684, - 0xb098_b03e_c0e2_bfa9, - 0x1658_92f6_2d6c_ab72, - ]), - pallas::Base::from_raw([ - 0x7cce_f3c2_7004_750a, - 0x6764_b8ec_87af_0fbd, - 0x954a_3e23_b88f_10da, - 0x016b_7c55_ed75_6eb4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1572_3792_f441_6a81, - 0xf995_d329_4d87_564f, - 0xb0d2_1f0e_cc5c_2ee8, - 0x27d0_c30b_d4bd_22ba, - ]), - pallas::Base::from_raw([ - 0xdb2c_fdc7_ab47_0473, - 0x6cf3_d13d_2256_03b9, - 0x2032_3b49_b053_23ca, - 0x3874_12f6_3a24_2a92, - ]), - ), - ( - pallas::Base::from_raw([ - 0x996a_0c38_d044_b83c, - 0xde09_0618_5b92_cda5, - 0x4643_0a67_d500_a255, - 0x27f5_9685_eb77_ac7e, - ]), - pallas::Base::from_raw([ - 0x059a_236e_dfd1_5edf, - 0xe561_315f_eae6_1f63, - 0xbb05_a594_85a4_b33a, - 0x3285_ddba_14ac_1ed8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe549_c0d0_0ceb_9dc3, - 0xd273_7cf6_b421_aa39, - 0x97d6_32a0_5a8f_3a2b, - 0x3c24_5f47_8e0c_a36c, - ]), - pallas::Base::from_raw([ - 0xf20b_8a37_aa4a_7d8b, - 0x8189_e00c_5620_23da, - 0x5aff_d154_2f27_8147, - 0x03a2_d69b_1690_1c15, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1db8_ec71_2a43_63b8, - 0x8920_3a49_6826_c060, - 0xab52_38e8_da30_0add, - 0x1fba_c064_05f9_fd83, - ]), - pallas::Base::from_raw([ - 0x35ca_286a_fd3e_c748, - 0x4d74_e271_dbd4_2a3a, - 0x1af7_48ff_e310_304b, - 0x38e5_4864_6bbe_709c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9c3f_6480_c417_46a5, - 0x7455_11cb_9655_ec10, - 0x0b30_d995_92df_c3ba, - 0x04b5_d208_aa2d_5695, - ]), - pallas::Base::from_raw([ - 0xe3fa_148a_db80_2f0b, - 0x692a_dedb_cc21_f27b, - 0xe5bd_3253_815e_0161, - 0x06ae_836a_74b7_d7b3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x23a6_7fe7_633a_8233, - 0xfb9a_4eca_7e71_4fac, - 0x950d_ef5f_a5bd_24cd, - 0x187a_4853_68dd_e36c, - ]), - pallas::Base::from_raw([ - 0x4ad9_6376_9666_3e54, - 0x935b_6072_4744_7eab, - 0x40d0_ef01_0cf4_ba17, - 0x2bd6_8f8f_e07b_ef4e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe269_82a7_147b_8c18, - 0x607b_e6c4_b9b9_be5d, - 0xe32d_307b_b3db_e0ef, - 0x3a76_010b_80d3_c8b0, - ]), - pallas::Base::from_raw([ - 0x06a9_146c_a674_8492, - 0xce4b_2d6b_49aa_731b, - 0x795b_873d_4a5a_95bb, - 0x19e5_778d_9876_7a46, - ]), - ), - ( - pallas::Base::from_raw([ - 0x02c9_e528_8369_fdca, - 0x546f_8eed_d946_62ec, - 0xa4c4_8b26_12bd_a088, - 0x3551_abbc_cb49_2c53, - ]), - pallas::Base::from_raw([ - 0xdfbe_b704_29a1_b4f7, - 0x6943_7350_0ca9_1961, - 0x4cf2_bc5d_2dd1_5705, - 0x2341_167f_494d_0476, - ]), - ), - ( - pallas::Base::from_raw([ - 0xaec8_67d5_8bab_356f, - 0x5a07_3489_e797_2666, - 0xe593_e00b_8588_5887, - 0x3298_8eb7_8bd8_1bcc, - ]), - pallas::Base::from_raw([ - 0xca3c_443b_d127_bdbe, - 0x53f6_db87_cbf9_232f, - 0x925e_3c81_1375_408d, - 0x362f_d3bb_da48_9c11, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6010_85d0_794c_e3ac, - 0x162b_7969_422e_ff0a, - 0xfa12_7c4b_9718_324d, - 0x05eb_74ba_ac18_6eb0, - ]), - pallas::Base::from_raw([ - 0xfa9c_6176_37ad_dbd4, - 0xd77b_985f_9626_c949, - 0x53e4_deb7_34a6_4e7a, - 0x1133_2731_91bb_93cf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x96c9_fb17_08b4_1634, - 0xa9a6_bc5e_2d24_cb92, - 0x834c_a22b_fd16_3870, - 0x3e56_ae12_1141_fc99, - ]), - pallas::Base::from_raw([ - 0x50bb_4dbc_163f_9f93, - 0x1e25_6f15_ff60_3b93, - 0x3e61_aa6f_b66c_8a6b, - 0x00e2_da21_06b8_e3c0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x42dd_8b79_23b6_b513, - 0xea85_bf04_b59a_779d, - 0xb0a9_fa50_a01a_72dd, - 0x08a0_0b38_4174_1ff4, - ]), - pallas::Base::from_raw([ - 0x64cb_e014_3f1e_ff9b, - 0xa145_12f2_67e7_15b9, - 0xd5fc_3acc_8d1b_3611, - 0x2717_cf1f_7f6d_ee6b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x11e3_925e_0cdb_c33d, - 0xbc8e_d434_51c3_4778, - 0x7304_853c_9743_9b31, - 0x1ada_7ad3_956c_621d, - ]), - pallas::Base::from_raw([ - 0x550f_ed05_7f72_917b, - 0x2345_cf15_73cd_6078, - 0xc00f_bede_8499_f921, - 0x3935_21fc_eb2e_3365, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0adc_cc3c_16a3_f235, - 0x2676_dcb3_8d85_ac03, - 0xb7c2_fa06_3232_3f54, - 0x1b00_c04e_8168_266c, - ]), - pallas::Base::from_raw([ - 0x22b8_f975_c6b2_6381, - 0x64a0_f521_877f_6589, - 0x0de4_3934_6246_b2b2, - 0x10ab_0d63_c867_c968, - ]), - ), - ( - pallas::Base::from_raw([ - 0x72ff_4d9f_054e_cb10, - 0x28cc_c6c5_1071_3c53, - 0x4144_3ca1_3640_7bcf, - 0x3ca1_8a54_8248_dce3, - ]), - pallas::Base::from_raw([ - 0x74b5_8607_c4f6_23a9, - 0x52cf_86ce_4024_b4e8, - 0x0c1f_22de_8fa9_9eb8, - 0x06d1_9d7c_2817_2812, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3429_9ecb_1a25_b41a, - 0x4c20_e2cd_430f_4f53, - 0xd3ac_8de7_5dfa_6385, - 0x315d_549f_290d_49aa, - ]), - pallas::Base::from_raw([ - 0x950a_7a7a_7391_01da, - 0xd06e_4417_2b59_15c5, - 0x8872_d56b_c32c_8a5b, - 0x1f28_a45d_64f9_644c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xec62_b82b_3f9c_dd5a, - 0x53e4_68e0_ba89_260f, - 0xbf71_b840_6644_8a63, - 0x1a7d_2578_300e_a6ca, - ]), - pallas::Base::from_raw([ - 0xdfd2_eae1_7952_3443, - 0xe753_284b_9058_3e43, - 0x3850_e370_e03e_b2ec, - 0x24f2_1e42_10b5_41ca, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3960_69f3_d739_056b, - 0x2f84_257d_240a_a99b, - 0xcbbc_6a3e_1d2e_3e47, - 0x32f2_11fd_60f5_6c88, - ]), - pallas::Base::from_raw([ - 0x8993_dc0a_f3e7_01d6, - 0x3c49_7f08_3d5f_1ffb, - 0x7c69_98c3_762e_4080, - 0x25ff_cd09_47d8_4962, - ]), - ), - ( - pallas::Base::from_raw([ - 0x00eb_df7a_a05e_0505, - 0x32d7_73fe_8a8d_769a, - 0xa0d7_4ae0_ba94_c75d, - 0x028f_6828_bf19_6ab8, - ]), - pallas::Base::from_raw([ - 0x1240_0761_dba1_cb3f, - 0xf439_7e09_5aee_c121, - 0x9a39_26be_cdaf_c085, - 0x11d1_6e6d_2222_d955, - ]), - ), - ( - pallas::Base::from_raw([ - 0xeb43_eac8_a45e_50fe, - 0x76e1_3155_9fb9_e4ca, - 0x8f66_7104_3f1b_0d78, - 0x0dc9_64a3_6226_3ba5, - ]), - pallas::Base::from_raw([ - 0x2443_a280_98f7_d9ea, - 0x7873_9d11_13fc_182d, - 0xd62c_6c84_30df_277e, - 0x3981_79f2_29f0_77ad, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3f3b_83e1_e18b_41a6, - 0xe879_b7d0_d499_1f0e, - 0x3a14_5291_dc57_a3a4, - 0x1106_64a3_a51b_428d, - ]), - pallas::Base::from_raw([ - 0x9acb_835d_d793_fc7e, - 0x695e_bbbc_7b1d_69ac, - 0x418d_bfef_2441_77eb, - 0x0e03_0d59_8861_c631, - ]), - ), - ( - pallas::Base::from_raw([ - 0x676c_1bbb_3d79_4a17, - 0x86f7_40b1_a30b_1824, - 0x0414_8138_2c6e_d6cd, - 0x2460_267a_aca9_b888, - ]), - pallas::Base::from_raw([ - 0x4b8e_28e4_c2de_91a3, - 0x0eb9_23e6_bb90_72e7, - 0x84a5_c9a1_9518_d64b, - 0x2028_854f_c7fe_f563, - ]), - ), - ( - pallas::Base::from_raw([ - 0xec55_0b1b_b4b3_5edc, - 0x9bd6_e713_a2a0_44f1, - 0x1bb7_d52f_e215_849b, - 0x2a3b_4a5a_60a8_e589, - ]), - pallas::Base::from_raw([ - 0x37db_8209_47f9_907b, - 0x9606_a95f_fed0_ec37, - 0xa4a5_f491_06db_2a91, - 0x2dc3_8e45_8a44_967b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xac40_3499_d9f9_eb6c, - 0x026d_a7c4_f3a1_2e88, - 0x7dfa_04ff_1867_a66b, - 0x0980_4e29_e424_13a9, - ]), - pallas::Base::from_raw([ - 0x51b5_218c_3a0a_055f, - 0x5ddc_c1fd_7461_34bb, - 0x3696_cdf0_cf53_c400, - 0x3594_1364_798f_0c20, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe6a7_7cfc_25cb_3242, - 0x2c31_d7f5_8837_2988, - 0x562e_9094_a407_ac85, - 0x3ab1_effb_2622_e180, - ]), - pallas::Base::from_raw([ - 0xb424_bdcf_597c_6557, - 0xeda3_48f9_ba67_2219, - 0x8c1a_e37b_63f2_d3cd, - 0x26f7_ed5a_5a2f_099a, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd297_863e_dded_7212, - 0xf91b_2b7e_3e36_bebc, - 0xaeff_d446_04bf_08b9, - 0x2467_95dd_ab7c_c74e, - ]), - pallas::Base::from_raw([ - 0xc713_53de_e975_f704, - 0xb276_043d_644d_0408, - 0x5878_7fed_3075_dead, - 0x2771_e939_209b_ae7a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x06dd_9ad7_373d_99f9, - 0x8a73_6054_b608_fa6a, - 0x3411_7ed3_2293_33b5, - 0x2e33_7d8a_2021_02de, - ]), - pallas::Base::from_raw([ - 0xc3ee_16d0_a73b_d633, - 0xd25f_08e9_2b65_b288, - 0xc26a_08ce_301a_28b9, - 0x3935_358f_146f_39be, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3f5b_b50c_f6ef_ce5b, - 0xb76d_32e4_5f67_4c5d, - 0xcaa1_7ff1_2bd7_bb4b, - 0x1b8d_cefd_b94d_06b2, - ]), - pallas::Base::from_raw([ - 0xa469_b014_2c83_2078, - 0x4d17_ae69_2a58_478f, - 0xcc08_c0ee_6947_386b, - 0x1428_6ba3_312d_4851, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2f3d_b3e9_a41a_0337, - 0x03a4_7f23_3f67_a26d, - 0x28c2_fecf_bfc3_355b, - 0x2bbc_960a_bd2e_f481, - ]), - pallas::Base::from_raw([ - 0xc311_0952_b121_2186, - 0x2e87_5201_48d5_fc53, - 0x875c_9ff6_a96a_da2c, - 0x0223_4935_d415_a5e5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x36f0_8415_22e2_56fe, - 0x6d55_4c96_1cb1_f126, - 0xefbe_e6c5_dceb_0fd6, - 0x3de2_b1ec_d97a_180c, - ]), - pallas::Base::from_raw([ - 0x5304_ab95_aae6_9b66, - 0x60ed_3893_0c80_7993, - 0xd9b4_3e8d_6ff5_4a3e, - 0x18fc_8e36_16ba_3090, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0822_d885_4dfe_69f0, - 0x505e_1f45_ccf1_dc38, - 0x628a_640a_7eec_8b84, - 0x0127_23d3_14c8_9c01, - ]), - pallas::Base::from_raw([ - 0x7e4e_f3cb_d5d4_7736, - 0x850b_2fbd_d6e5_5bac, - 0x6c2f_3bc2_18f3_9602, - 0x2535_1370_28dc_f11f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa134_90eb_3ad2_a6fe, - 0x0b67_1163_084d_310a, - 0x86df_15cb_08ca_1613, - 0x2186_0967_8d1c_6167, - ]), - pallas::Base::from_raw([ - 0x58de_954b_613d_9043, - 0x4cdf_a072_9d4a_5cde, - 0xd2a4_f058_b900_7509, - 0x2660_6d63_e85e_94fb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1bee_c383_512e_3059, - 0x75e4_6def_af35_b531, - 0x25cb_866c_89fa_7469, - 0x2300_a9c8_709c_c635, - ]), - pallas::Base::from_raw([ - 0x30fe_ba0a_d8b6_dd3a, - 0xfe7b_289a_3c6c_a17b, - 0x7a6a_763f_4f92_0595, - 0x0669_e3fe_787d_f81c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2317_af7e_2bc1_fb5a, - 0x4fa0_a83c_0f76_c57a, - 0xad4d_1850_e918_2af4, - 0x3095_294e_9909_a724, - ]), - pallas::Base::from_raw([ - 0xb04c_712b_c022_15ee, - 0xf118_0f20_c588_375d, - 0xaabd_ded2_9f7d_bf93, - 0x170b_a10e_7ff6_dc04, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4614_ca37_6411_165d, - 0xfe5e_19ff_1cf2_d2ea, - 0xfd57_702b_75b7_f29b, - 0x2d1b_3d96_4eb5_321a, - ]), - pallas::Base::from_raw([ - 0x03b0_6fb1_8c52_94d7, - 0xd282_d2a7_a658_83af, - 0x136d_b5bc_b3ef_254e, - 0x2e8c_5ef8_61fe_9aeb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x79cc_d5aa_18d7_fe0f, - 0x21fb_e42a_7f84_9fc5, - 0x6a28_f36b_52a4_f91c, - 0x011d_e672_2dda_0469, - ]), - pallas::Base::from_raw([ - 0x4f07_9730_2c53_dc9c, - 0x6c9d_a709_b02b_cf85, - 0x6bf0_cda1_2708_3753, - 0x02ad_a1fa_4596_eb60, - ]), - ), - ( - pallas::Base::from_raw([ - 0x74f1_d926_d45e_11b7, - 0x1c48_974b_0e37_87a2, - 0x574f_54b1_2560_ee08, - 0x1a17_a6cd_ff9b_fa8b, - ]), - pallas::Base::from_raw([ - 0x65bd_430a_18c2_6fdd, - 0x06a7_f226_5fff_44b4, - 0x600f_2717_320e_d4a6, - 0x0c3b_4e95_ac95_a06b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb18b_afc6_26e6_2669, - 0x34de_90c8_407d_290b, - 0x47c9_8071_fe58_680e, - 0x1274_01e0_c920_4b16, - ]), - pallas::Base::from_raw([ - 0x332d_e7a5_2f92_fc45, - 0xc917_cdc6_686b_1a9d, - 0xb86c_76fe_72e0_8b68, - 0x0b4f_39ca_545a_b70f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc417_3670_bcb9_cc4a, - 0xbd5c_f1b8_0b64_2192, - 0x1897_6a02_8e09_c2fb, - 0x187e_651a_79a4_8732, - ]), - pallas::Base::from_raw([ - 0xae69_5d7d_5294_c1af, - 0x1934_654c_e813_bf54, - 0x642c_b26f_293d_c2dd, - 0x092c_e031_517b_da63, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7662_8a07_ecc9_bc79, - 0x8cb2_1f86_aaa6_5bb3, - 0xbb09_cf23_8a56_d226, - 0x1c1a_5d7b_19a6_351a, - ]), - pallas::Base::from_raw([ - 0xfe9f_8731_fe5c_71af, - 0xdd8d_8082_7660_c6cf, - 0xa2fb_bb46_607d_b4f6, - 0x066c_dec4_29fa_02f4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfeba_3899_4dcd_fab9, - 0x0185_bee0_53a8_b2e9, - 0x2d18_4ae3_6719_da6c, - 0x38de_de43_97fc_4e8c, - ]), - pallas::Base::from_raw([ - 0xaf8c_1a56_9749_5a96, - 0x1eaf_43ef_5661_3ff8, - 0xfe65_2cce_44c4_fced, - 0x24ca_f69b_2d91_f2f4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x050e_2315_3fe8_888a, - 0x5cd6_7594_d7fb_eada, - 0x5890_89ac_5ffa_169e, - 0x2c7a_db4e_0279_0a77, - ]), - pallas::Base::from_raw([ - 0xace5_6f4c_4889_310b, - 0x36cb_a3e6_49a8_2d97, - 0x0a3f_5f71_4d72_02ef, - 0x34e9_12c6_ec66_b3d8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8d2d_8ca6_933c_4438, - 0xd7f0_b609_54f3_3f61, - 0xe93b_e7cc_13ed_f94c, - 0x114a_be4c_6b55_af86, - ]), - pallas::Base::from_raw([ - 0x1837_62f1_7010_22b7, - 0x4811_6b3d_d2a2_a698, - 0xea41_857f_a3f3_188e, - 0x1fb5_1838_65ba_7743, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa082_8c60_d8a3_f578, - 0x0a25_684f_653f_6c8f, - 0x2b4d_9dc4_dc66_7726, - 0x36c8_2048_d681_651d, - ]), - pallas::Base::from_raw([ - 0xe26c_9196_230a_c29c, - 0x08fb_0378_bc18_071b, - 0x75a0_8f44_c578_a727, - 0x15ee_7196_24dc_9c10, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfeaa_76bf_d7f3_cc18, - 0x7d70_d0be_ff2b_e9a5, - 0xbfb7_ade3_819f_e899, - 0x0a80_597f_8201_89a2, - ]), - pallas::Base::from_raw([ - 0x7c0c_7cf8_5e73_abcb, - 0xefb0_3940_c106_04ee, - 0x85e4_c588_3d14_ef43, - 0x27fe_fbb2_9d0a_97b7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x47c6_a888_684f_bdbe, - 0x5427_2144_0e19_5279, - 0xf6b3_7923_849c_acea, - 0x34f3_4173_3333_34f1, - ]), - pallas::Base::from_raw([ - 0x0a04_1869_d2aa_dad4, - 0x34a7_9c4d_f7a6_b66f, - 0x7b7b_e1e9_121b_6d3a, - 0x2421_7f52_b1bb_09bc, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfe01_fde7_3ddc_40c0, - 0x6731_87df_9de0_27de, - 0x2150_0dc8_2124_84f9, - 0x1764_90fe_4fbf_05d1, - ]), - pallas::Base::from_raw([ - 0x3e96_ffcc_83de_2760, - 0xffd3_6ccc_6e69_1191, - 0xe3ce_955b_54a6_1af7, - 0x091d_70c1_c2a0_1886, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdf0c_1b18_d13e_6075, - 0x3660_d9cd_6d7c_a28c, - 0xc8db_742a_5e85_5a70, - 0x0856_63df_fcde_b718, - ]), - pallas::Base::from_raw([ - 0xdfc6_3b44_bfcb_4ba9, - 0xe1ab_077a_c6da_e5a3, - 0x2b4a_31f8_1d0a_106f, - 0x26e9_9d38_3c41_ba1a, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa55b_b719_22c8_8eb6, - 0x2ba9_93d9_f776_01fd, - 0xef9d_38c3_4590_b955, - 0x393c_90d8_8ab2_8885, - ]), - pallas::Base::from_raw([ - 0x2367_9c6c_8698_dc18, - 0xc375_1a89_e204_ed77, - 0xa2cc_f60a_2cc0_42c5, - 0x3b1a_7e64_31f5_efc9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x01aa_2003_93d8_1228, - 0xd565_deb4_6165_426a, - 0x1359_c8b2_23c3_a219, - 0x1741_223b_656d_fbea, - ]), - pallas::Base::from_raw([ - 0x68a2_aa8d_99d2_6617, - 0x3248_d5e3_8e95_e05c, - 0x4347_e264_3653_a95c, - 0x3b6a_ab30_009e_2a40, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc401_caf5_b80b_d7b7, - 0xd475_062f_bbbc_8de4, - 0xf888_a322_55a9_d44e, - 0x1a01_8bfb_3b21_464d, - ]), - pallas::Base::from_raw([ - 0x5d8f_724e_1cd2_4386, - 0x78a3_535f_8640_efd4, - 0x47ce_290a_4905_53a1, - 0x2a91_7aea_3b73_4a4c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x034e_89dd_99f2_6e09, - 0x45b5_bd00_e4da_62a9, - 0xebf3_dbff_ba88_271e, - 0x02c8_2b9c_ea98_af0f, - ]), - pallas::Base::from_raw([ - 0x3aca_a2de_6568_bd4f, - 0x5544_cffc_3aed_6643, - 0x52f8_d105_2659_131d, - 0x011f_4744_f248_a534, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe504_9c54_5183_a68e, - 0xb2d8_76d0_fd04_ddfd, - 0xe266_0cda_4417_fa06, - 0x2bc0_f5d1_292f_66ad, - ]), - pallas::Base::from_raw([ - 0x98fa_34c1_c7e4_4d04, - 0x86f0_df5a_c92c_6a54, - 0x458a_25bc_e1c6_6a86, - 0x36c6_ddb7_9a5f_7421, - ]), - ), - ( - pallas::Base::from_raw([ - 0x309b_b8ce_eaf9_5df5, - 0x0149_4b0f_a4ba_ea01, - 0xa124_4665_cce6_d172, - 0x3412_acee_8559_e4cd, - ]), - pallas::Base::from_raw([ - 0xa00c_8037_9921_039c, - 0x26ec_3ff0_2626_f929, - 0x7f42_5184_1ec7_6115, - 0x0d32_4da9_5111_de3f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0623_4914_8426_c348, - 0x923b_758a_75fb_c2ae, - 0x8563_479a_8a1c_3a18, - 0x0222_f189_6b30_9026, - ]), - pallas::Base::from_raw([ - 0x6383_b87a_3a58_9f66, - 0x5d68_22db_c04c_0804, - 0x3cd5_300d_b8c8_5e26, - 0x1ed6_87af_f5a9_7f81, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4976_a9d9_23f4_e05a, - 0x89a9_d356_80f3_5037, - 0xfcce_d80b_20ff_a679, - 0x2eaa_c96a_e572_8c2e, - ]), - pallas::Base::from_raw([ - 0xe326_9ec8_35b1_a894, - 0xe334_6c5d_38d5_f584, - 0x58d6_995b_9eb6_1568, - 0x3b13_1337_181e_2cab, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd626_3c8c_8fab_225e, - 0x6111_af8a_c249_0cd6, - 0xf2ef_6c29_147c_86d6, - 0x27f5_4f89_3962_c0ad, - ]), - pallas::Base::from_raw([ - 0xa842_3c35_185c_5986, - 0x70ae_f850_779c_bfa3, - 0xf628_f488_1fc8_b76e, - 0x0a9c_f292_fe41_9dfa, - ]), - ), - ( - pallas::Base::from_raw([ - 0x537c_08e1_3a1c_f53f, - 0x78df_4265_7b2b_fc61, - 0x2500_a58a_eac6_35c6, - 0x0fcf_c9c2_bc99_f123, - ]), - pallas::Base::from_raw([ - 0x3147_0e47_8fbe_1b4a, - 0x991e_e318_b485_e3b9, - 0x633d_47dd_3042_bb0e, - 0x3360_8103_99b0_a527, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd7a2_1d17_f989_6972, - 0x5e8b_6e6b_30d7_aa2b, - 0x8454_73ae_ee97_a305, - 0x3116_2156_7cc1_18e5, - ]), - pallas::Base::from_raw([ - 0xfccf_5d9f_b11e_df81, - 0x2e12_7758_c03e_b200, - 0x5f04_7db9_eeaa_1921, - 0x3a86_fc45_77b3_f524, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9e93_1cc8_c148_8493, - 0x900f_cf13_2569_e392, - 0x765e_58e9_48b5_d022, - 0x2ede_c32e_ef69_64c0, - ]), - pallas::Base::from_raw([ - 0x5695_ebac_bfeb_ebd4, - 0x98cc_74a8_fd64_21ff, - 0x27d8_5ecb_1931_3238, - 0x1053_65b5_5423_da3c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf222_9818_2d70_d3ed, - 0xdf8e_0ddb_b98b_fbeb, - 0x44ec_a0c2_57ef_550b, - 0x12e2_838e_4f99_a03a, - ]), - pallas::Base::from_raw([ - 0x6655_b07c_8d8e_d971, - 0x9d54_b9e8_f799_c635, - 0xd3ac_f7ab_31b0_0ae0, - 0x3db7_b034_049d_ceb4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x10ba_763a_c8c6_f730, - 0xae79_86b4_9150_c67a, - 0x82ed_80f2_e411_a974, - 0x04e0_22d6_0b2c_6589, - ]), - pallas::Base::from_raw([ - 0x088c_79a2_e8ad_c3e4, - 0xa2b1_bfb2_60e1_d64f, - 0x2153_eadf_50f5_03a8, - 0x0471_d795_1f45_c106, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa0af_6834_540a_1d2a, - 0xbc22_530b_a609_337d, - 0xb27e_7401_ff92_1206, - 0x0f66_0b47_5fce_7a48, - ]), - pallas::Base::from_raw([ - 0x0d2d_0ce4_5d34_1e91, - 0x5ed6_ed9b_6248_73e5, - 0xdb0d_b388_856f_04a8, - 0x3909_13e5_6b4d_ecad, - ]), - ), - ( - pallas::Base::from_raw([ - 0x931f_ebf4_3432_8d85, - 0xb4ac_dfb4_13f3_778f, - 0x2198_10f0_065a_4746, - 0x274b_25e6_d0ee_28ac, - ]), - pallas::Base::from_raw([ - 0x85ff_5dcf_2af8_0d1e, - 0x4fcf_da75_73d5_6aaa, - 0xfebf_10d6_f655_de17, - 0x0fc4_ed1e_e2fb_3daa, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2c88_682b_0807_fb47, - 0xe572_e261_762a_9833, - 0x92a5_94b7_dd97_e2d6, - 0x290c_0f08_ae67_92f1, - ]), - pallas::Base::from_raw([ - 0x9f3e_a22a_9fbd_e2f2, - 0x7828_c11a_b548_3f9d, - 0x889f_be4d_6071_fc49, - 0x2127_232a_a434_31ff, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdf50_276a_cd2f_7fd2, - 0x6221_308a_0532_4c09, - 0x1c28_3f54_3fb6_99e4, - 0x2691_bf94_093a_d903, - ]), - pallas::Base::from_raw([ - 0x6af0_82ff_ff8c_9733, - 0x5ff9_faf0_e36e_d8c0, - 0xce94_f44a_1788_600f, - 0x1318_d65d_1c35_c49b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9163_559a_be89_bb1c, - 0x5251_bfcf_7749_01a7, - 0x3efb_6de2_8193_cf1e, - 0x1942_18c3_fe5b_6949, - ]), - pallas::Base::from_raw([ - 0x7174_f4c0_cc3b_ede0, - 0x735b_e3c2_887f_4687, - 0x93ab_3df4_5697_0520, - 0x0d9d_d803_f612_8651, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7f74_e033_1fc3_eca4, - 0xd55f_7848_5f07_c856, - 0x4a3f_5542_4f34_fd79, - 0x0a48_7764_e6bb_64fc, - ]), - pallas::Base::from_raw([ - 0x7746_ae1b_b07c_53a9, - 0x0cd8_26a8_b54e_f182, - 0x64d2_d590_c7a7_2ef5, - 0x34e7_9a7c_db19_a72f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9ee7_822c_9974_c6fe, - 0x6d79_96e6_ecf8_df62, - 0x3263_2b2e_f5df_4af0, - 0x10f9_be27_b481_30e5, - ]), - pallas::Base::from_raw([ - 0x1272_0f17_8ab2_623a, - 0xa050_ea3b_6f25_0848, - 0x01f1_8495_9947_e6d4, - 0x3e25_d531_e842_b508, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1c20_5dac_8ff2_38cb, - 0x4c0e_7a71_7346_0cd7, - 0x5cb8_b1a1_4c49_19e7, - 0x1017_cc43_7f6c_a31c, - ]), - pallas::Base::from_raw([ - 0xc7a7_9329_b0d7_cfab, - 0xf910_054e_b22e_57ef, - 0xa27e_9be2_3ef3_e39a, - 0x221a_8fd3_dea3_471c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8da5_c8aa_c156_511d, - 0x3df5_2950_01ad_9519, - 0x654e_3cc1_fefe_95d2, - 0x1826_50e8_f7f3_c594, - ]), - pallas::Base::from_raw([ - 0x6a14_5790_4fe2_27cc, - 0xdbdc_600a_387f_90de, - 0xb47f_a736_8906_d3bd, - 0x2919_7af4_2853_5c8b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0e60_4790_c292_a15b, - 0x568d_bf3d_b502_70c0, - 0x54ae_c935_bb45_d7de, - 0x30eb_56d9_3c62_e58a, - ]), - pallas::Base::from_raw([ - 0x940f_2e00_ced7_14f4, - 0xf3d0_1a90_5dd8_c6bb, - 0x2188_66b3_369c_ec8f, - 0x16ad_3c60_929e_f022, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0c17_e5c3_6446_c41f, - 0xbc36_aeb7_6459_3101, - 0xe6b3_222b_f89f_1cbb, - 0x0a55_07f7_2694_65a6, - ]), - pallas::Base::from_raw([ - 0x5d8e_9202_13b0_c07c, - 0x0c75_2080_6653_ef25, - 0x0a8a_c99c_9e71_ec48, - 0x0cea_69fc_1248_9c7a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6bf7_aa25_2e67_bfe4, - 0xf638_dd62_3264_efb2, - 0xc5d9_d3dd_7ab8_95eb, - 0x19cc_6f41_d5ea_400f, - ]), - pallas::Base::from_raw([ - 0xb5f9_31ac_c93d_a424, - 0x0669_28e6_f068_ab0b, - 0xaa97_d1f0_2516_8563, - 0x12c9_2e45_f41a_027e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb5cd_03f6_546f_2d8c, - 0x008b_ed8d_5fb4_d8cc, - 0xfbcb_8613_de82_5e34, - 0x321d_9574_27a1_bf27, - ]), - pallas::Base::from_raw([ - 0xf46e_ef71_5d5a_f67e, - 0x0718_6aa5_d7df_a969, - 0xcdd8_6543_720a_6554, - 0x0109_0738_2d21_8149, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3b0a_d014_2f1d_6af2, - 0x99d7_56da_d234_fc14, - 0x45a8_b1c4_454c_5dfb, - 0x1ee7_4f77_ad27_f629, - ]), - pallas::Base::from_raw([ - 0xf38f_1264_df92_5a0f, - 0x198a_81c9_05ac_18d7, - 0xcc50_1caf_24f4_ed42, - 0x399e_531d_d4d1_3840, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb529_b39a_b8c8_6bbf, - 0x7d8f_ebda_e02d_678e, - 0x7fae_d795_ca8e_8302, - 0x31ed_a441_e002_ac2c, - ]), - pallas::Base::from_raw([ - 0x619d_1ef8_6855_6cbb, - 0xd88c_2fed_a381_abd6, - 0x6845_42a1_1e1f_ddd0, - 0x0771_38ca_a39c_2293, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8e3c_040a_f2be_9c63, - 0x0cfc_acc4_41b0_e1e2, - 0xf752_2875_1f06_363f, - 0x0032_71bd_2b81_e3cc, - ]), - pallas::Base::from_raw([ - 0xc3ad_aedb_26dc_6180, - 0x2ad6_7b13_2e77_7986, - 0x2dc6_e063_027b_de54, - 0x0af4_dae5_6e28_04a4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5075_53c9_94d0_dc2e, - 0x940f_4012_649a_26a7, - 0x9162_6f3d_cb07_7bdb, - 0x3c6c_9061_ba99_8e97, - ]), - pallas::Base::from_raw([ - 0x2178_ff4b_0732_3f45, - 0xc7bd_6c17_b4a7_3748, - 0x567e_30af_d336_1f3f, - 0x0fe0_0d2e_dc98_92d2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x923e_5ef9_fc71_838b, - 0x7d0f_0335_d240_a72f, - 0x1995_4895_1bc7_bb3e, - 0x21ab_30c3_8b38_7741, - ]), - pallas::Base::from_raw([ - 0x28a5_52b8_4d1c_2cb2, - 0x7879_b66b_db7d_c6f9, - 0x66cb_e4a2_b207_c3c3, - 0x1c5e_324e_ce7e_1fc2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0bea_8b37_7a6e_5de3, - 0xe8ad_fcbe_7b8f_c888, - 0x6443_7dff_eb54_1544, - 0x17e3_7101_e098_d708, - ]), - pallas::Base::from_raw([ - 0x5e3c_16ee_ea18_7549, - 0xcebc_d07b_5dda_4fdc, - 0xcaef_d061_c365_1317, - 0x08ba_afac_c8b0_f579, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0c45_64d3_dfdc_c360, - 0x3c34_d6db_627a_b743, - 0x19d6_66ef_aece_e57d, - 0x202c_137c_d1b6_7cb8, - ]), - pallas::Base::from_raw([ - 0x0dee_c67f_c432_1abc, - 0xc5cb_4568_bc4a_8783, - 0x86b1_1451_ecca_550c, - 0x0ff0_09f7_4820_2e77, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf299_ebe2_a905_3c8b, - 0x424d_1301_89df_a29d, - 0xea28_f364_490d_4a4b, - 0x2508_a2a0_337f_d881, - ]), - pallas::Base::from_raw([ - 0xd25c_bf8b_16a9_bc33, - 0x11a1_c1ed_a972_d5f0, - 0x9cef_8ada_9d7d_314e, - 0x00a8_b4df_bad1_2ed3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x23be_9beb_9a9d_1973, - 0x08cb_a79c_d6be_891a, - 0xfe6b_6d74_0d9e_ca76, - 0x1cf9_8a3d_7cad_c772, - ]), - pallas::Base::from_raw([ - 0x37b5_48a9_8ca6_1367, - 0x7717_856a_a9b5_f7e9, - 0xbbc3_ed77_a685_e338, - 0x3721_1cad_a67a_824f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xec8f_2eff_5163_90b6, - 0x502b_81eb_7035_b6aa, - 0xc6f2_0df9_5dfa_4d3e, - 0x0a19_842b_c197_5949, - ]), - pallas::Base::from_raw([ - 0x760b_a317_8fbe_610d, - 0x0370_d562_6abd_b305, - 0xb005_aebf_6e18_2d4c, - 0x0bfb_19da_eb56_6427, - ]), - ), - ( - pallas::Base::from_raw([ - 0x577e_5c79_60fc_0750, - 0xef55_42ac_ca0d_7327, - 0x1f01_e126_ce1b_85b2, - 0x2a4a_42d0_4ff1_a83e, - ]), - pallas::Base::from_raw([ - 0x89fb_594d_05da_15b6, - 0x409f_a8a7_c292_6e67, - 0xf51d_1898_aad8_d7bc, - 0x11a2_2949_d51d_cca1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa13a_ce54_6c54_ddfd, - 0x4f2f_05d0_3b6b_c624, - 0x24d8_342b_6f1b_bed6, - 0x10f6_dcfd_3058_49b0, - ]), - pallas::Base::from_raw([ - 0x45e4_776c_b11e_2c8b, - 0x21dd_7840_7331_9fb1, - 0x9b3d_9a29_2c94_f391, - 0x2476_66c1_6beb_0949, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6942_a75b_0f86_97d1, - 0x1e65_3555_73de_ffb9, - 0xcaa7_5277_14cc_174f, - 0x0bd5_3c52_fdd8_9e3f, - ]), - pallas::Base::from_raw([ - 0xefbd_85ab_0779_2a56, - 0x94ee_6dd3_5be0_b609, - 0xe2e2_ebf4_4c60_80ad, - 0x37e7_f6b5_6da4_f564, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa785_938c_daf0_a82c, - 0x0ff1_052c_6b0f_e01a, - 0xa3a3_4892_9645_d506, - 0x35fc_4d9f_25e4_ee0c, - ]), - pallas::Base::from_raw([ - 0x1bd8_1387_35d5_eed0, - 0x2031_6e2b_4402_2210, - 0x1de4_87e5_3382_18c8, - 0x2639_15ef_7bb7_ac86, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7270_5394_9d68_af25, - 0x31ec_3a68_bc55_8512, - 0x6224_b2b9_4190_4745, - 0x2bae_d2fb_bfa0_7f92, - ]), - pallas::Base::from_raw([ - 0x1585_ad6e_c39d_17e7, - 0xb3f4_5d31_7909_30e0, - 0x10f2_cf93_6dce_27ab, - 0x3ac7_25dc_a3cc_5a5b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x16d5_99fd_795e_e6d3, - 0xa832_7e0c_535a_268d, - 0x66f3_59f1_a2d0_c9a0, - 0x0b43_b8cf_c755_ef13, - ]), - pallas::Base::from_raw([ - 0x771e_bb8c_9993_734f, - 0xe22b_9efa_7f0e_8978, - 0xf847_286e_a0aa_95f5, - 0x3cab_00dc_f0cb_4e65, - ]), - ), - ( - pallas::Base::from_raw([ - 0x940e_5b99_9381_5ed6, - 0xe458_f932_4ac9_8472, - 0x7277_a9b2_a4c6_6b96, - 0x2a9b_1dbb_3571_6aff, - ]), - pallas::Base::from_raw([ - 0x1d1e_8561_7c5f_74fa, - 0x04e0_d957_2d5e_bdec, - 0x697f_9f0f_730e_36dd, - 0x3196_6863_7d6b_29ae, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf4ec_666a_be5d_ceba, - 0x4e55_7554_6220_3670, - 0xc2c0_90b4_a237_cb56, - 0x32ae_228d_d97a_e433, - ]), - pallas::Base::from_raw([ - 0xad96_69b3_e76e_a998, - 0x91e7_879f_ed57_7b7c, - 0x1e41_9d83_9e6c_94d7, - 0x048d_94ba_a0e3_0800, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6c90_7b9f_576a_7619, - 0x7bb1_599f_1d1c_9120, - 0x3b2f_e84d_d429_e90c, - 0x33d9_fbea_8acc_5ae9, - ]), - pallas::Base::from_raw([ - 0x549a_ec50_44ca_17ec, - 0x645d_16ee_dbae_2cd2, - 0x0ab1_6a27_9c8b_feef, - 0x3ce8_42b9_6fec_08f2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x66fe_abea_b49c_bc29, - 0x831b_43fd_4f80_1ad0, - 0x8963_b81f_a95b_9f77, - 0x3fff_5b9f_33a9_c8da, - ]), - pallas::Base::from_raw([ - 0xb846_fdb3_3ece_c0f6, - 0x028f_eede_2d86_2dc1, - 0xb6fe_b8a0_d783_8453, - 0x1ebf_fb3e_ea47_f184, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdbd3_28a6_187e_d102, - 0x4d92_bae1_fab1_c408, - 0x5036_8ca9_4dc4_3f5c, - 0x03e9_6590_9135_7f5e, - ]), - pallas::Base::from_raw([ - 0x6929_1025_5164_3cbe, - 0xa488_9bf3_bc56_9b53, - 0xf020_bfe6_2ccd_f413, - 0x0128_5e40_0aa2_8746, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8a24_35af_b4a2_12b6, - 0x5132_1588_3ffa_9384, - 0xba59_b535_c741_b302, - 0x024f_79e6_c546_5014, - ]), - pallas::Base::from_raw([ - 0x708d_0744_747d_b6bd, - 0x4ba0_0f9c_9956_4ab8, - 0xa6a1_8626_802b_0d85, - 0x1180_93b3_83be_9f5f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4e81_e880_ac86_3341, - 0xb199_dda5_ee5c_d052, - 0x4bfb_9edb_2b9e_40bf, - 0x31f3_ccf9_bc82_4e71, - ]), - pallas::Base::from_raw([ - 0xc77e_ac27_414c_a39a, - 0x75e7_9a0b_3e2d_8063, - 0x0622_1629_392c_7383, - 0x003f_f9a6_01db_549a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x19a3_fe6e_8919_9977, - 0xcaae_dcab_3a2a_1fdc, - 0x5d08_6ffb_b871_b05d, - 0x1009_d4da_10a2_540b, - ]), - pallas::Base::from_raw([ - 0x3e52_b60b_e56e_d8d2, - 0xa1d1_62c0_5220_5502, - 0xdf1e_4b5f_9eff_40e2, - 0x3983_0483_a475_7d5e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8a0e_979e_fd3e_fc28, - 0x4949_282d_94e0_8968, - 0xf2b2_9f4b_9c13_6beb, - 0x10ff_7bf3_f711_ca78, - ]), - pallas::Base::from_raw([ - 0xf3ac_a739_fe6f_9a2b, - 0x24a4_32dd_3b09_89e1, - 0x2f22_37ec_e69c_8858, - 0x2d7e_82a5_6448_019f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0dd9_25b4_b2b2_2f7c, - 0x5f56_b22a_a5b3_3623, - 0x57d5_9fe0_f291_a84c, - 0x0d09_972b_30f1_be14, - ]), - pallas::Base::from_raw([ - 0x3374_d4c2_52f8_d6b4, - 0xc076_3cb4_bdd1_d03b, - 0x0075_cad7_fa9b_c762, - 0x3231_c543_5a25_3b5f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd27e_395d_361b_5ec6, - 0xbf65_b40b_5fa3_aa57, - 0x6ebe_d47a_734c_d047, - 0x1c72_49cb_9959_520b, - ]), - pallas::Base::from_raw([ - 0xdaa7_b8e5_921f_ef38, - 0x96ef_2a6d_ad05_ee3f, - 0xc6f1_76e2_fc0b_18a4, - 0x389f_6781_7075_8a4d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb719_cae7_9e3e_eee7, - 0x7195_0578_1db1_15a0, - 0x4bf3_df1d_89d4_101a, - 0x1180_028a_0688_b2fe, - ]), - pallas::Base::from_raw([ - 0xead4_6a5b_c181_84fa, - 0x752e_4ef1_9ed1_d259, - 0x6987_464e_4442_6e0f, - 0x0e76_4f02_842d_9e51, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4fc8_561b_e0e3_7afb, - 0x4e22_7ecd_b7af_8143, - 0x18e5_adcc_3d30_4460, - 0x1c1d_1e61_5c90_5b8a, - ]), - pallas::Base::from_raw([ - 0xe84b_9fc9_fa1a_3202, - 0x64d2_8a73_dea5_979f, - 0xa1b7_2a78_52c4_ace3, - 0x3176_462e_9090_e088, - ]), - ), - ( - pallas::Base::from_raw([ - 0x073d_58c4_427d_406e, - 0xeaae_a64c_9da4_b973, - 0xdb2b_606a_ce9c_98fd, - 0x320d_ab61_0606_cff0, - ]), - pallas::Base::from_raw([ - 0xf6f5_6017_e567_b738, - 0xad8b_2fa4_c80d_6dcf, - 0xef76_6787_acc5_eec6, - 0x2046_af02_0cc2_8cfd, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdfe0_be8c_ea45_93e2, - 0xbf25_71e6_2c01_a757, - 0x5646_bd2a_721f_cde4, - 0x2e56_8465_0c5e_df5a, - ]), - pallas::Base::from_raw([ - 0xc367_119b_e723_3de0, - 0xa859_64d3_8319_d7e2, - 0xbf56_4106_7772_44b3, - 0x05a7_a0a3_f91c_3fe3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa157_1fb9_7ebd_b1cf, - 0xad70_58d4_9484_4afb, - 0x22ff_383e_fdf9_34da, - 0x03a8_f536_628d_a555, - ]), - pallas::Base::from_raw([ - 0x89a6_b560_8b35_83df, - 0x93d8_765b_4bb6_3abe, - 0x6607_c289_c75e_39ce, - 0x0846_7ac7_d613_3c93, - ]), - ), - ( - pallas::Base::from_raw([ - 0x09bb_0aa5_c0f7_596d, - 0xc0b7_9d5e_0a31_3f09, - 0x25c7_ae48_63c8_df2d, - 0x340f_7178_57c8_c4f5, - ]), - pallas::Base::from_raw([ - 0x58d6_0999_e9bd_175c, - 0x413c_51e3_6936_3dcc, - 0x44bf_08fb_a5bd_cc5f, - 0x09d9_43ab_4210_7233, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7660_e2b2_190b_69a3, - 0xa675_e6bd_1268_5aba, - 0x70c3_464c_345f_61a3, - 0x0c06_a269_203a_835c, - ]), - pallas::Base::from_raw([ - 0x5ea9_81b8_2f7f_4ab8, - 0x270c_896c_5e02_6b95, - 0x410a_6beb_1116_7954, - 0x25cc_f45d_51f9_413f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x83b6_8e9a_1a6a_c28f, - 0x252f_9079_e85e_8c2b, - 0x3dd5_a334_3f27_7d23, - 0x1f00_6677_bdfe_d386, - ]), - pallas::Base::from_raw([ - 0x21c2_597c_a01e_4b39, - 0x1195_b279_cab6_3aa8, - 0x5947_c45d_89d5_371c, - 0x0bfd_bc05_76f2_f69a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x56aa_cca5_f6d6_aeae, - 0x00de_b6ed_5b56_175d, - 0xe99e_0920_f6e3_ac48, - 0x1970_6df9_fa50_7068, - ]), - pallas::Base::from_raw([ - 0x68d1_0152_dcd8_93fb, - 0x05ce_c81d_e5b3_7f47, - 0x7f83_e062_2c1f_9c14, - 0x31cb_805d_ed05_7b35, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf740_8933_84f5_3c01, - 0xa65d_85ad_4b70_3a91, - 0xe988_f151_9c16_9eb4, - 0x39b7_6368_9c50_4537, - ]), - pallas::Base::from_raw([ - 0x8fcc_2881_8f89_9d3c, - 0x9a09_7667_344e_b7ed, - 0xc77a_ff9a_1099_b9ac, - 0x3c20_f228_e53f_9a40, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3e5f_02b6_0499_512f, - 0xc6aa_35d0_b5fc_7e3e, - 0x310d_1554_993b_9077, - 0x3b2e_af1c_97a7_e598, - ]), - pallas::Base::from_raw([ - 0xc7eb_cb64_9b4c_42bf, - 0x2bf3_2b91_10f2_ce19, - 0xd0eb_b868_6884_a28e, - 0x025e_43d6_95a4_e968, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe521_3aed_05e9_77a3, - 0xfe91_23c6_366e_6089, - 0xff9d_b1bf_4bbd_55c7, - 0x2806_f809_7feb_4387, - ]), - pallas::Base::from_raw([ - 0xf2cd_f9d7_d0fc_3fa3, - 0x277e_e79b_e9e8_6ab7, - 0x37c9_96f8_8238_9c4e, - 0x37d0_9ecf_faad_6231, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6d97_b12d_3d3a_a165, - 0x3ca0_bd33_97db_0743, - 0xc6eb_cdf5_27ec_2a4c, - 0x377f_7772_587b_c8e2, - ]), - pallas::Base::from_raw([ - 0x2563_f930_3ffd_2e65, - 0x54e7_472c_ef1a_9b21, - 0xfdf1_b209_a4ba_4952, - 0x285e_bf94_09ad_7630, - ]), - ), - ( - pallas::Base::from_raw([ - 0x300d_9e13_f84f_0abb, - 0xd16d_7740_9c8d_c8d6, - 0x88b4_6edb_02c4_9705, - 0x05c4_e9fb_bada_d36d, - ]), - pallas::Base::from_raw([ - 0xf151_5ce8_bead_7602, - 0x3928_bb28_9b22_02ae, - 0x11dd_8076_58b5_38d9, - 0x0bef_8f47_2c87_7974, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9182_5076_acdb_4b23, - 0x5e1d_aab6_2b52_5e01, - 0xd348_f694_cf00_7eab, - 0x0fcc_10bf_2527_b056, - ]), - pallas::Base::from_raw([ - 0x80f6_acc9_9258_cb51, - 0xc15d_6f31_1e48_7046, - 0x3042_b48e_8bab_078a, - 0x3cf4_7fcf_48ab_5d1b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6c13_9e12_49ce_58fd, - 0x04b0_81f9_23c7_d9e8, - 0x8f7a_9239_88e5_0d43, - 0x1fca_3b8d_b325_a3be, - ]), - pallas::Base::from_raw([ - 0x692f_f292_5bc7_efe1, - 0x375d_358d_b102_d895, - 0x7377_f146_2112_ee7e, - 0x22b9_ca2a_74d3_accf, - ]), - ), - ( - pallas::Base::from_raw([ - 0xda8d_d358_9491_7794, - 0xe067_e06d_8977_054b, - 0x68e7_65cf_e835_3e99, - 0x2c7b_ae76_7c60_05c6, - ]), - pallas::Base::from_raw([ - 0xbf71_5d06_4e5e_e34f, - 0x9c99_a7e1_8746_abeb, - 0x7615_e9eb_5e16_ccc4, - 0x328e_84b7_73ab_f7fa, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfe57_fcce_7fa3_b8ee, - 0xc9c2_448c_f7c2_687a, - 0x6fd2_be38_efd3_c2d4, - 0x0288_6502_ad64_3ca2, - ]), - pallas::Base::from_raw([ - 0x4bc1_9841_b03f_4d5c, - 0x460b_ea82_dcb0_7401, - 0x95b2_4a5e_6c57_84b4, - 0x2bfb_f8ee_7da6_9c92, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd39f_ac30_c415_232c, - 0x76dd_a79e_3bac_418d, - 0x146a_5061_cc03_a8bd, - 0x33d1_e61b_23b0_45c8, - ]), - pallas::Base::from_raw([ - 0x0a86_1d38_a0c1_6167, - 0x3403_d750_3625_fd76, - 0x5c14_43d8_4dfc_5111, - 0x11c4_166d_43ca_34b8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x59d0_4901_73f3_dc32, - 0xba05_8d5b_fec4_3964, - 0xe934_dd16_6639_b95a, - 0x2bbb_c6ea_bb03_cde0, - ]), - pallas::Base::from_raw([ - 0xee85_cf18_4523_3d07, - 0xee68_4cb6_e0a9_3cf3, - 0x256b_3bba_79ee_21d0, - 0x1922_24ec_0f7f_7bb9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5e0d_4224_2670_e7ae, - 0x1625_3e15_14a1_7a12, - 0xdc19_7727_5d06_feee, - 0x1945_e2c3_3e05_75dd, - ]), - pallas::Base::from_raw([ - 0xd13a_150f_7299_7634, - 0xfb54_5fc0_aeb3_d878, - 0x30f3_976d_4f5b_fab9, - 0x39e2_8dd6_964e_57c2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6338_94e3_1def_1331, - 0x178a_dcd2_9172_17f0, - 0x661d_3878_6be1_3883, - 0x3408_a710_6fc8_2ce2, - ]), - pallas::Base::from_raw([ - 0x342c_2e44_c71b_ed3f, - 0x96de_42e1_09ee_70d6, - 0x8589_6891_dd66_820f, - 0x0741_8793_5d70_7bcf, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc10b_7e08_f2dc_891d, - 0x5d68_913c_d9e6_d01e, - 0xdd5d_234c_090b_3903, - 0x15f0_5b8d_a216_b34d, - ]), - pallas::Base::from_raw([ - 0x7962_faa0_cf7a_f257, - 0xaeb0_181c_1252_a47d, - 0x1261_6f4b_f1ca_e2a5, - 0x2322_da04_1fbd_9122, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6a1f_d4d7_4910_b554, - 0xe38f_1107_a34e_2dfb, - 0x68c6_f5cb_806b_3ea4, - 0x2b4a_4711_8c56_07da, - ]), - pallas::Base::from_raw([ - 0xc783_e3cb_01aa_1026, - 0x5c61_2654_288f_5199, - 0x6308_5aa7_4c7a_1afd, - 0x2be0_c52c_6093_c62c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xcfd8_887f_b984_673a, - 0x7d45_4af5_572d_847a, - 0xb8cc_5e6b_e457_cafa, - 0x05f0_5b4a_1514_6b31, - ]), - pallas::Base::from_raw([ - 0x9b83_b107_3366_b9df, - 0x7e64_4e6e_6208_ad83, - 0xe7f1_ff6b_4f7f_ecbe, - 0x315c_4707_e207_5aa1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x937f_a439_75f4_9b60, - 0x302b_b808_40e5_8700, - 0xb139_c191_3f5d_2668, - 0x37d0_f747_3f38_8e55, - ]), - pallas::Base::from_raw([ - 0x85c8_de85_e1bb_51af, - 0x248e_5ca6_6754_a3fe, - 0xfcd6_2e4a_d4f9_c873, - 0x33ff_0368_6ba7_d5c7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5e5b_adbc_d5fb_0443, - 0x78c4_d68d_9535_6613, - 0xfc3a_f91d_e825_cef9, - 0x0da7_ce87_e12d_4f1c, - ]), - pallas::Base::from_raw([ - 0x7ef0_5e88_6074_d377, - 0x4a7f_af08_52b5_609c, - 0x0b09_33a2_2f81_8986, - 0x0d6f_bbc5_de55_8690, - ]), - ), - ( - pallas::Base::from_raw([ - 0xaa91_03bf_b5ec_e132, - 0x1104_aaeb_126c_9c14, - 0x03d5_39c6_576f_6608, - 0x2297_a2d2_c5b4_e323, - ]), - pallas::Base::from_raw([ - 0x60d6_c848_219c_e7be, - 0xb05a_10e1_00cd_63b0, - 0x429b_ea17_7b3f_4b88, - 0x0c1d_c916_f323_e7ba, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7e91_af55_41b0_8bf4, - 0x7eb7_87f3_ce5f_d6b1, - 0x716d_a388_45f1_2b56, - 0x0b63_6e98_ac64_6f4d, - ]), - pallas::Base::from_raw([ - 0x4ab7_12d1_a43e_13db, - 0xe60a_52eb_e24b_27bf, - 0x056c_fba5_2b55_7f09, - 0x1fac_62f4_32cd_f236, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2dfa_15b7_ebbd_e631, - 0xb320_f94d_a9c0_63af, - 0x1b77_601c_50e8_6a37, - 0x3d4c_2ff5_d00a_3876, - ]), - pallas::Base::from_raw([ - 0x272a_3417_43de_26bc, - 0xaea5_4b59_4992_3c71, - 0x0c4d_e807_c535_b183, - 0x2765_c806_aec7_71a7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x55ec_8f25_7b63_e13a, - 0xd5fc_34d5_66ec_9ee8, - 0x56c2_e320_91d0_8278, - 0x1691_2185_0e3d_dc23, - ]), - pallas::Base::from_raw([ - 0xa148_4983_bee5_638d, - 0x8a79_eb1b_c492_8b71, - 0xd6df_d4fc_d029_984b, - 0x2cbd_3698_162f_9ae9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7a1b_05bc_e3c4_7320, - 0x32a7_6039_297e_8409, - 0x732f_44e5_5380_a997, - 0x202a_a34a_e870_a44e, - ]), - pallas::Base::from_raw([ - 0x4868_6f6e_4f31_74e7, - 0x36ff_575c_ae12_a1e3, - 0xe09a_f42d_581b_50a7, - 0x2114_4937_0a1c_f825, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdb42_2a77_b183_1102, - 0x7bf8_c21d_1049_98b1, - 0xce43_b79c_9ad6_75f9, - 0x349d_78c6_a718_8921, - ]), - pallas::Base::from_raw([ - 0x3070_ba0f_699f_080f, - 0xd134_f6e0_36b8_c18a, - 0xda34_d0a7_2cd2_aa3f, - 0x2945_7a3e_37c3_b020, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6fa1_6666_d21b_774e, - 0xb91f_c4b1_0e6f_767c, - 0x12af_8401_416c_df0b, - 0x220f_43a3_4cc1_d1a0, - ]), - pallas::Base::from_raw([ - 0xab2b_060c_b26e_f892, - 0xe580_8ab1_a538_10e2, - 0xf36f_e472_3313_570c, - 0x36f1_3b73_3934_59b1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4e49_ebb2_947d_b488, - 0x242c_04d3_d97d_c253, - 0x9f41_d8d8_d7fd_b017, - 0x013c_52dc_adff_81e0, - ]), - pallas::Base::from_raw([ - 0x0a29_7aca_54ca_ebd9, - 0x63b0_abde_e434_9e09, - 0x51d0_948c_c749_f20b, - 0x069a_8db0_9a55_b0f4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x406f_b28a_71f7_8032, - 0x969e_b429_82fe_4929, - 0xb1af_24a1_53c8_2095, - 0x052a_3255_a165_23a7, - ]), - pallas::Base::from_raw([ - 0x98f1_82b9_5ac3_dcd2, - 0xb088_ed0c_bf43_f3a8, - 0xf950_fe2d_c059_db22, - 0x1440_06da_cd6f_d539, - ]), - ), - ( - pallas::Base::from_raw([ - 0xda59_fedf_ac9d_3f1e, - 0x226a_cb4a_3e98_29b1, - 0x3a73_3388_a504_88dc, - 0x3891_f70a_133b_a457, - ]), - pallas::Base::from_raw([ - 0x25c4_6ed8_4bf2_d71f, - 0xbff1_2fe2_1b00_e737, - 0xaedc_6377_1e3f_8787, - 0x0ed1_b27c_c7ef_d5ac, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc0d0_516d_40d3_cc81, - 0xa649_0816_1677_43c9, - 0xca42_f4c4_4243_c1d5, - 0x23b3_8f5b_b23d_8b5e, - ]), - pallas::Base::from_raw([ - 0xed2a_a32c_dcc3_fa23, - 0x8cda_3463_fef1_02c3, - 0x6b5a_f006_e433_ce3c, - 0x1225_df05_7f84_56b2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8291_0d73_56a0_e04c, - 0x64b6_73ac_c38f_66f0, - 0xdd23_f657_9d03_0932, - 0x2e91_cf8d_0328_73cd, - ]), - pallas::Base::from_raw([ - 0x6c94_8550_64c0_d6b3, - 0x7a29_80d2_5e0a_beb0, - 0xb651_e0fb_26b8_1656, - 0x3b5a_8440_9640_1532, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbadb_8627_9571_bbfb, - 0x124b_4809_a75e_8835, - 0xc9e7_00a7_4761_1c17, - 0x0920_b057_f207_5bcd, - ]), - pallas::Base::from_raw([ - 0xedf4_28d2_7f57_6e69, - 0x81db_b861_29e9_b438, - 0xfa8e_eed3_1e15_ec93, - 0x1126_9fbe_894e_0bed, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb1f4_fe1d_7c44_7f1f, - 0x83c4_259d_9758_51fc, - 0x117c_2cb5_bf1e_601b, - 0x22d9_4c09_d954_00dd, - ]), - pallas::Base::from_raw([ - 0xd683_7d9f_b5d2_4924, - 0x313b_2636_f504_0619, - 0x2b63_fc49_08e0_48d6, - 0x1144_ded2_0553_ac9c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x387c_b408_a242_5394, - 0xd079_369b_b24c_53d9, - 0x8f15_d008_d9e9_d4c3, - 0x3150_c6bf_e2c6_f49d, - ]), - pallas::Base::from_raw([ - 0x0404_728f_c1f7_729d, - 0x7867_a4bd_2454_fc8c, - 0x41ce_532d_3e8a_12e2, - 0x1ba3_02a9_468e_f35f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3db3_09bf_c9b3_4ec5, - 0x5033_0f96_20ca_8bcc, - 0xa8ba_c058_76aa_2be0, - 0x1448_b16c_5253_7aeb, - ]), - pallas::Base::from_raw([ - 0xc139_ae90_00d8_2a6f, - 0xe882_76a0_e243_47b5, - 0x3ddd_9c6e_1e82_af5b, - 0x36f6_2912_c020_70b8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1402_2b05_d861_fd8f, - 0x41d7_89f5_50b6_a9e6, - 0x87d2_6c5d_6fc8_2332, - 0x02f8_35e2_95b6_562e, - ]), - pallas::Base::from_raw([ - 0xbeb9_3c06_52f7_4ad8, - 0xe619_72c1_05e4_cd9d, - 0x884a_8d7f_678f_75dd, - 0x2874_6006_1cc8_886f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x69f1_75ca_c3b9_58f2, - 0x6747_f1ef_abb5_3998, - 0x46ec_4c53_0949_f44c, - 0x07ba_e7f2_46e1_1e0e, - ]), - pallas::Base::from_raw([ - 0x1021_d25b_0c19_dc41, - 0xea7a_36bd_9497_28f4, - 0xa859_e7cd_2cea_c8a7, - 0x0efc_9a8c_f825_3990, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5dea_1fb9_0da5_a77b, - 0xc0e1_3bb8_134a_bcc6, - 0x9938_d35c_c9ea_b2d4, - 0x2283_5512_a16b_cd1f, - ]), - pallas::Base::from_raw([ - 0x9be9_eaf3_1b0f_ad7e, - 0x3491_2b52_0ca1_71f9, - 0x0721_8f00_31b9_ac7e, - 0x0e74_f8e8_90c4_692f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6b4a_0ce4_26ac_5fb9, - 0x13cf_2331_e171_707e, - 0x8539_192e_4fcd_6ea1, - 0x128c_aa53_6e03_01ab, - ]), - pallas::Base::from_raw([ - 0x6e6b_8cb3_43a7_fcba, - 0xb4b2_353a_6472_323d, - 0x4867_0871_a8fd_61a2, - 0x11c8_bcf8_bdca_1c4d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8f8f_bb6f_6f0c_7693, - 0xa8cd_2c9f_9f6f_9eda, - 0xf8f7_1e1d_01ab_dafa, - 0x301a_41e0_0512_a1dc, - ]), - pallas::Base::from_raw([ - 0xcb70_6c7b_9d80_868f, - 0xf2a6_d279_5c03_64f4, - 0xbf2a_e148_ec6b_7343, - 0x303f_3b4b_74c4_59b8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4c67_a5c8_e007_8e3b, - 0x5a11_f487_f259_6bcb, - 0x52d4_26c8_e498_b8aa, - 0x1bf9_81ee_4546_e1d6, - ]), - pallas::Base::from_raw([ - 0xb25b_9eda_f3c4_0ace, - 0x4cd8_57e5_5ff9_a68e, - 0x4c57_4295_a50b_e5aa, - 0x1457_bcd8_9f13_ef72, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6e49_8196_9af9_5023, - 0xa9f4_ad41_da85_fd4d, - 0xf643_d9f0_fcdb_da79, - 0x1077_61df_2dd6_6275, - ]), - pallas::Base::from_raw([ - 0xfa32_bd06_b1af_c76e, - 0xe61c_2fa4_1da2_cb0e, - 0x4c70_289c_043c_e9ed, - 0x2056_dd5d_ddfb_d391, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe6f7_b311_a5eb_8af4, - 0xbbcb_dea1_4f28_c13d, - 0x832a_fc2a_c06b_48c0, - 0x1884_c484_9a23_39d1, - ]), - pallas::Base::from_raw([ - 0xae85_ea27_cf05_147e, - 0xa661_d654_5ad7_8770, - 0x8cff_b5bd_23cd_1e02, - 0x0c4a_a17a_3d59_87b0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0903_2b71_20d2_c6d6, - 0x631f_355d_d06d_ccc6, - 0xf87c_c78c_ef4a_6b96, - 0x3ef8_d7d1_dc6f_9f9d, - ]), - pallas::Base::from_raw([ - 0x43ce_ad49_48dd_c9d2, - 0x2dc3_7407_7cca_9ffc, - 0xac61_ddbd_67db_3e8d, - 0x0297_f7b8_d03f_dedc, - ]), - ), - ( - pallas::Base::from_raw([ - 0x361c_0eb5_afba_a00d, - 0x8051_789c_48c8_8225, - 0x9887_1616_2649_2d22, - 0x3d51_6690_501f_18a2, - ]), - pallas::Base::from_raw([ - 0x3a63_1bfb_843d_d126, - 0x4a8c_64d0_c4eb_0522, - 0x9124_952e_3015_76f3, - 0x1a00_2583_79af_10c8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd1b3_d060_1eee_6e43, - 0xc4c5_f777_afcb_3d7c, - 0x5890_cf65_cdee_4f41, - 0x3bac_6dcd_6ca7_0869, - ]), - pallas::Base::from_raw([ - 0xddf9_20c5_9c7d_0fc6, - 0x0586_3a0c_6afe_2d3d, - 0x14d2_e276_9317_f416, - 0x1b0a_6eba_dac7_b097, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1396_4ab6_46aa_aa39, - 0x63ab_087a_ae54_f31b, - 0x6d98_908d_b903_5320, - 0x38d0_a593_6ed6_9ee0, - ]), - pallas::Base::from_raw([ - 0x63ad_df45_aee3_572a, - 0xce8b_2242_3aa8_96fe, - 0xddc1_4261_c724_5d07, - 0x3535_1cd4_d4f9_1ba2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb5ca_a06f_a744_e9dd, - 0x38e3_7f58_5670_d457, - 0xb4df_a467_546f_0bbb, - 0x01c3_1821_87e9_c394, - ]), - pallas::Base::from_raw([ - 0x735c_1df3_1c86_a46f, - 0xc35a_47e7_9530_8784, - 0x0b2d_cd84_17ad_d715, - 0x106c_dfe8_b63a_2baa, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1a6e_026d_0c07_0abb, - 0xaca9_b562_15b5_32b2, - 0xd41e_5c95_365c_f30a, - 0x288d_ca02_8dc0_36dc, - ]), - pallas::Base::from_raw([ - 0x662c_4ded_8523_98ed, - 0xb2d7_be0a_1d12_423d, - 0x3ec6_e3b5_de20_815c, - 0x291f_f461_d024_af8f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb09f_fa66_d16c_27ec, - 0xa1da_22b0_8593_d72a, - 0xe632_9240_dc54_eb20, - 0x1a76_7954_e044_678d, - ]), - pallas::Base::from_raw([ - 0xe6fa_cd09_85a5_0427, - 0xd348_8598_eddd_f7b2, - 0xd7a2_306f_08c8_bcc4, - 0x14f0_fcd5_0316_e459, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8f32_c8f3_5b64_6f4e, - 0x21aa_08fc_88eb_4def, - 0x2801_597f_de58_9a34, - 0x3a30_a417_2ad6_0466, - ]), - pallas::Base::from_raw([ - 0x7d06_9540_e011_19ee, - 0xc967_557c_731b_7356, - 0xda5a_4c02_83a4_2f1d, - 0x3d3a_57fb_c972_c1e0, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd3c1_f6cc_c3e0_2a53, - 0x0547_5fdc_7ec7_1268, - 0xf000_9637_f19f_5b9d, - 0x30ff_defd_ca48_bd81, - ]), - pallas::Base::from_raw([ - 0x91ae_9409_8215_c29a, - 0x6132_5ed0_20eb_03f6, - 0x7902_c795_04be_18dc, - 0x2fd2_0d09_cb6b_ffe2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1a31_a60b_d542_73dc, - 0xdb7f_1cc7_04b6_b150, - 0x1861_c054_0121_d013, - 0x206c_c173_9153_a5a3, - ]), - pallas::Base::from_raw([ - 0xe0e9_cb82_5775_fbd5, - 0x4376_49cc_7524_f7df, - 0x7bd2_080e_2134_cd15, - 0x31f0_de88_e2da_7e71, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfc72_8173_780b_d7a5, - 0x7aef_d664_bcbf_065b, - 0xb00b_a3b7_0b2c_e355, - 0x3699_84a7_28c9_f5db, - ]), - pallas::Base::from_raw([ - 0xce09_1005_839f_4217, - 0x3295_dcc5_fe7c_58a3, - 0x5aa3_0609_bda0_b60a, - 0x0241_cf89_cdbb_b0f2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1b00_1931_9eba_29b1, - 0x7216_7d55_26f9_8da3, - 0xe7cf_f705_a799_754f, - 0x2990_fd50_70f8_dc2b, - ]), - pallas::Base::from_raw([ - 0x1eed_c7c4_49c6_3e99, - 0xbbf4_2638_ef85_5544, - 0xf755_cb96_23f0_a42e, - 0x01ee_b0e0_5fe3_1d97, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe37e_1f9e_40b1_54a3, - 0x652d_23f0_cc13_026d, - 0x8e86_4190_1d49_7ee8, - 0x0664_9f66_0725_b3b9, - ]), - pallas::Base::from_raw([ - 0xf17e_dcbc_83c0_56f4, - 0xbb63_cec3_3dc1_383f, - 0x8e3f_6121_894f_a536, - 0x3c11_2d8a_1c60_b07c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1a3e_7d79_56bb_fe12, - 0xa7a9_ca39_4c1d_37be, - 0x9740_4aaf_c9c4_a82e, - 0x38aa_35a0_3d7c_378a, - ]), - pallas::Base::from_raw([ - 0xb631_7d5e_8de0_bb5d, - 0xdc67_9917_adbc_69d0, - 0x68b9_71fe_c7f3_8566, - 0x1989_cd89_9970_7a95, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb220_5013_ba92_96bb, - 0x2058_da75_36fa_a776, - 0x0436_5be3_f84a_c088, - 0x1af4_7a2f_3b0f_a032, - ]), - pallas::Base::from_raw([ - 0x2abf_4796_3d43_d58f, - 0xb235_0d75_403d_f0f1, - 0xa021_f706_77fe_3e5a, - 0x322f_cdad_4c07_7b90, - ]), - ), - ( - pallas::Base::from_raw([ - 0x06a9_ae6c_cbe5_d5d4, - 0xaa6b_45d7_03a5_e6f6, - 0x4614_a78b_bebe_0932, - 0x18cc_6bd2_2c90_ec21, - ]), - pallas::Base::from_raw([ - 0x967c_718d_fed8_a0b8, - 0x95a7_bc7f_31b3_4247, - 0x5a19_1faf_19e0_da2c, - 0x115b_c841_1338_488f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1d51_ca19_915e_a485, - 0x0b43_77f8_251d_b7af, - 0x0825_fb37_e0ea_5a48, - 0x1548_072e_3b8c_9cbf, - ]), - pallas::Base::from_raw([ - 0x48eb_6bb8_ab54_4b29, - 0xae66_f29c_ec75_ea3a, - 0x3195_4ba2_167a_b49c, - 0x3d57_aaaa_db93_5f7b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0c46_3390_d414_4397, - 0xb683_52dc_4bf0_80f6, - 0xa6a1_5861_0737_0e45, - 0x2400_81aa_ffbc_d341, - ]), - pallas::Base::from_raw([ - 0xbbef_dfca_46b3_a803, - 0xc3dd_0e85_0c04_6877, - 0x71e3_e8e2_2feb_ec64, - 0x08a9_eaf7_b5a5_39fc, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5e06_c2b1_b31b_93b4, - 0xc313_a37c_4320_dc75, - 0x7efc_a295_2612_6f7b, - 0x0aff_f83d_40bf_1741, - ]), - pallas::Base::from_raw([ - 0xc7cb_8f4c_fdc8_1d4b, - 0x5a50_fd94_f40c_8457, - 0x71d6_4791_1e74_f12b, - 0x1541_6661_ee80_7c70, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2802_c3f2_89e9_5d61, - 0xf33c_77fb_6c07_ea84, - 0xbbc9_320f_0df4_143a, - 0x356c_a3df_9cc0_4f80, - ]), - pallas::Base::from_raw([ - 0x4f45_fa2b_9fd8_1daa, - 0x7f47_5e59_7199_616e, - 0x7d3b_df29_ce4e_dfb5, - 0x1dae_8d6b_f927_1f87, - ]), - ), - ( - pallas::Base::from_raw([ - 0x473f_87de_7e94_192f, - 0xd393_9d88_1211_44b0, - 0x963b_e798_1010_c5ea, - 0x17ef_3597_df23_de2e, - ]), - pallas::Base::from_raw([ - 0x1e95_8dac_55e3_db76, - 0x12d2_c681_d82e_ed9c, - 0xd3d5_1684_1d5e_e0cf, - 0x0ac9_26dd_9cea_3447, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6858_89c4_1505_8b08, - 0x6db7_b0e4_db13_97af, - 0x5b80_1548_f65c_a777, - 0x0bc7_e844_145e_084b, - ]), - pallas::Base::from_raw([ - 0xe538_4d8c_3f79_208a, - 0x151f_22e1_29fd_3354, - 0x7a90_a95c_27ac_21db, - 0x19ed_e445_2202_a655, - ]), - ), - ( - pallas::Base::from_raw([ - 0xded8_57fc_ee32_3789, - 0x0bfe_aa0f_301d_6f33, - 0xf39c_96d3_5d9b_bf6d, - 0x2a9d_8309_fabf_976f, - ]), - pallas::Base::from_raw([ - 0x528c_0f45_53ee_3161, - 0x6dca_d2cc_ef93_aa93, - 0xe704_f08a_2ec9_996c, - 0x1bfd_16da_cc0d_2d3f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x188b_8471_e40c_3640, - 0xa201_8659_0697_76d0, - 0xd08d_57e0_209d_0571, - 0x1a90_63bb_e154_64ae, - ]), - pallas::Base::from_raw([ - 0x568d_9049_e597_c096, - 0xdd50_78d0_87aa_87c5, - 0x3c15_73d9_7187_5ef2, - 0x388e_691e_ea9e_23f4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x40ab_3fc1_9370_1560, - 0x29ce_a290_2ec8_40f5, - 0xd75d_0b95_a9f7_f97b, - 0x0af0_7979_abd8_c613, - ]), - pallas::Base::from_raw([ - 0x5c15_cad2_0553_9ced, - 0xc602_0943_036b_091b, - 0x4c2c_78ce_e591_7f5e, - 0x1959_acff_f5a3_4bf9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfa8d_876d_7cc0_0fb8, - 0x5a9c_4a97_786d_19a1, - 0x12be_8115_3b9b_aee9, - 0x1a0f_2978_8594_d43f, - ]), - pallas::Base::from_raw([ - 0xed97_14bc_d4e8_8df7, - 0xe734_c0d3_0dd8_9ea3, - 0xec5d_2259_c86d_e1f5, - 0x1322_03f3_5788_8faf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x93b5_3b69_0484_8f93, - 0x1339_8c0d_df8c_cf22, - 0xf46d_112e_a566_4f42, - 0x0041_e2f5_f2d6_8640, - ]), - pallas::Base::from_raw([ - 0xb605_0c79_bc10_7760, - 0xee50_15ea_4b49_adac, - 0x65e3_2182_22f4_2268, - 0x31cc_6994_41a9_c0ad, - ]), - ), - ( - pallas::Base::from_raw([ - 0x94ae_ab7c_eb62_81ab, - 0x5228_ca94_d8f1_56ab, - 0x475a_af93_16b9_884e, - 0x1986_0f4a_6c3e_b16d, - ]), - pallas::Base::from_raw([ - 0xebdc_e98f_ed8c_6d40, - 0x0540_8297_454e_307f, - 0xd024_3225_3f4a_6703, - 0x1af1_a0e4_f57d_5be3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfa36_a92e_b85b_e634, - 0xb44a_ed3d_eab7_8850, - 0xbe32_58d6_6770_c14b, - 0x35ff_5141_816d_634f, - ]), - pallas::Base::from_raw([ - 0x500c_0c1b_ceaa_bd2c, - 0xf0d6_669b_f68a_ef2e, - 0xbd8d_f904_9439_9c72, - 0x2db1_ef2c_35ad_69d3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc0b4_8b5d_58ff_c10c, - 0xe5ca_70be_a28e_8cd2, - 0xf439_95af_87ab_fbbd, - 0x0730_82f6_d583_d377, - ]), - pallas::Base::from_raw([ - 0x1062_30a0_d505_0d13, - 0x4b6a_3c80_f34b_c350, - 0xc6fe_8327_3096_a319, - 0x2230_637f_0cc2_89f0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x25e8_9191_c18b_b009, - 0x82f9_29c5_b2a1_8aad, - 0x3f85_1520_6a2a_9706, - 0x25fe_4261_1ed7_737c, - ]), - pallas::Base::from_raw([ - 0x8337_c552_d63e_02f6, - 0x73cc_77a9_0b10_5fb4, - 0x94db_e561_3bad_7a8c, - 0x26e7_36b7_a39f_c440, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0946_b650_b1c0_8743, - 0x9db9_c020_11b8_8c65, - 0xfa3c_4dca_cbf8_ff13, - 0x06e5_c844_eb13_24bc, - ]), - pallas::Base::from_raw([ - 0x3c8f_57f9_a8a3_70a1, - 0x37c5_8b38_e0fc_1baf, - 0x6b33_3515_afc8_813b, - 0x1a82_f5f2_799f_573a, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbea1_5e63_420a_279b, - 0x8e07_282b_8912_351d, - 0x408f_f799_d86a_fd7d, - 0x078f_7b8e_ce6e_22e4, - ]), - pallas::Base::from_raw([ - 0x88bc_d999_cef1_ecdf, - 0x333d_9c44_d4e7_0bec, - 0x8035_febd_691a_b18e, - 0x1407_a098_70a5_1148, - ]), - ), - ( - pallas::Base::from_raw([ - 0x454c_97de_2584_aa5f, - 0xeec7_9406_7a27_a899, - 0x0955_d427_80d3_4702, - 0x1d35_9759_c143_d6ff, - ]), - pallas::Base::from_raw([ - 0xa816_af30_15f6_605c, - 0x0710_71d6_689b_a943, - 0xdb02_148a_c73c_a8e1, - 0x05dd_3dec_b765_a777, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdb80_38eb_d76a_fb2f, - 0x0dc9_0a9f_1c88_325d, - 0xcf8c_c81e_1622_6cf5, - 0x2a99_7c7b_a771_a172, - ]), - pallas::Base::from_raw([ - 0xe8c2_d9bd_2155_e22f, - 0x8a70_25a0_bd8f_e9a9, - 0x5be9_c192_1d28_e841, - 0x12ea_8763_5c8a_9c3b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4e5c_2298_84b8_933c, - 0x4677_86a0_b2a8_994c, - 0x1325_900b_c323_5b30, - 0x2a1e_4623_a4ae_cc18, - ]), - pallas::Base::from_raw([ - 0x566c_512b_6e4b_d49b, - 0xa74e_0f1c_1e2f_0b5d, - 0xcb43_553c_5583_6e1d, - 0x13a4_a175_6930_a346, - ]), - ), - ( - pallas::Base::from_raw([ - 0x503c_48f0_8921_2210, - 0xed91_7232_785d_86d0, - 0xc0c2_ad95_b9fd_35fa, - 0x0b03_ca6a_1e38_17f6, - ]), - pallas::Base::from_raw([ - 0x4c85_4c2e_f43b_beb6, - 0x3325_8fe3_0797_c712, - 0x7b2b_65b2_71d7_d17f, - 0x2608_45d2_59cb_fed7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5143_9665_16ca_1642, - 0xfaa0_77c5_094f_ad4d, - 0xcbc1_d869_aa7d_14eb, - 0x2cf2_0f0a_34c2_1025, - ]), - pallas::Base::from_raw([ - 0xad36_eea9_9921_cdc6, - 0x2e1d_370d_297f_0a41, - 0xc957_086f_0915_9341, - 0x22cc_cf10_e21e_1daf, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfb44_e614_c314_ad4c, - 0x8b24_db0b_dfd8_617d, - 0xd17d_196f_3f6a_9e26, - 0x27c8_ffd6_32df_7764, - ]), - pallas::Base::from_raw([ - 0xa5ca_43b4_390c_42dc, - 0xd7a2_791f_6a1b_568b, - 0x98a7_1f22_9c63_b251, - 0x31a3_0d03_e7a9_779d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf4b4_4ce9_8722_550d, - 0xdd93_8b22_0139_0ac8, - 0xfe86_f423_5227_eeaa, - 0x31d2_8dfe_adb7_adcb, - ]), - pallas::Base::from_raw([ - 0x5adb_7f33_74bc_7bdc, - 0xc10f_d1b1_2bb8_8630, - 0xae28_7ce5_935b_f41c, - 0x2a20_9773_8054_a39f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3be7_413e_3d67_146b, - 0xad57_cda9_2e17_75bd, - 0x2c5f_f9c4_e371_aee9, - 0x1b81_7a0e_2f33_4e49, - ]), - pallas::Base::from_raw([ - 0xa15d_8dfb_cd6d_2737, - 0x2a49_ce19_5f43_8fcb, - 0x4d38_1b52_1b1a_cfd1, - 0x0e93_ce94_5828_a23c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1f51_ce5d_d476_cea2, - 0xdd2f_92cf_2184_73d4, - 0x666a_9231_c766_0b6b, - 0x2b1a_a9ae_9756_b3fb, - ]), - pallas::Base::from_raw([ - 0x46a9_9cce_8c15_cca3, - 0xbf85_bbce_c460_d9aa, - 0x4e8a_a7b8_4aa4_1021, - 0x1780_a81a_6a2a_e54c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe17a_6b50_9568_c08a, - 0x259f_ae60_9e4e_fd82, - 0xaf7f_d128_3ec4_4bdc, - 0x1c09_ded3_74a6_91ad, - ]), - pallas::Base::from_raw([ - 0x70df_b9a3_3551_a4d5, - 0xfe2e_eecc_1187_c582, - 0x8586_f426_db21_1456, - 0x26a6_2ba8_9350_0fca, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5ec3_cd23_5624_6658, - 0x0bab_696b_14fe_b07f, - 0xf70e_9a72_5b80_1b25, - 0x22ff_987b_a1c6_cd80, - ]), - pallas::Base::from_raw([ - 0x7808_0fb5_8b7c_ee41, - 0xce4d_d83d_b956_929b, - 0xeac8_39ce_a74d_ddc4, - 0x2317_33ea_2b06_a86d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xaec8_6746_685d_fe1f, - 0xc218_0c0a_b71e_5168, - 0x8d76_6976_1a70_70fa, - 0x0008_c8a2_7bfc_9cdb, - ]), - pallas::Base::from_raw([ - 0xaa4f_3a36_9871_ca77, - 0x7b4c_0ea1_c1ad_696f, - 0x4ed8_5210_fab0_f980, - 0x3e6c_bd12_b49c_1bdb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8f6a_0cea_47e1_7bc8, - 0x2864_1feb_0791_af26, - 0x60a3_c179_c72a_2b89, - 0x10ee_4430_7ce0_cbf3, - ]), - pallas::Base::from_raw([ - 0x66aa_db97_f4c0_a463, - 0xe302_d7db_78d5_576d, - 0x482d_9194_87cb_1e2f, - 0x0e9a_4a4a_36ad_1881, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4c34_5c29_f898_6470, - 0xdff4_47e0_e1f7_6080, - 0xf9db_c0ba_062c_1970, - 0x06cd_6193_ac7c_e277, - ]), - pallas::Base::from_raw([ - 0x6104_a761_347d_3597, - 0x8280_faa1_48a1_e104, - 0xa011_5d0a_2f37_3747, - 0x0c73_50b8_829e_b73b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7a98_41a0_1d18_03f0, - 0x9dcd_a639_ea9d_d030, - 0xd91c_8c1f_f2fc_d414, - 0x22b1_7e59_75fc_4d7f, - ]), - pallas::Base::from_raw([ - 0xcaea_f461_5474_dd21, - 0x973b_49e9_4e35_150e, - 0x1a20_3ee4_03cb_bc49, - 0x2012_40e4_943d_2c2c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x75f1_33d9_1456_5351, - 0x1896_214f_0087_2854, - 0x0cd4_7ce7_26fe_ea9d, - 0x2663_26f8_7005_286e, - ]), - pallas::Base::from_raw([ - 0x1737_3826_4271_f35f, - 0xc7d8_f940_6e0a_7c1f, - 0x5924_d283_767f_9d5c, - 0x0eb5_0f0e_3127_577d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x68e2_0f5e_bd39_c14c, - 0x477b_6956_a99f_77cb, - 0x313a_9885_a170_99ce, - 0x1a86_5d1d_04a2_df73, - ]), - pallas::Base::from_raw([ - 0x0623_0fc4_c152_65bb, - 0x52dd_72d4_2781_e376, - 0xa418_49f5_864e_6635, - 0x10fa_c29d_eb03_270d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa57d_3895_4a64_fb15, - 0xca09_c64e_7421_cae2, - 0xf017_5c2b_ec60_fe7f, - 0x0195_07a1_b05a_ac7e, - ]), - pallas::Base::from_raw([ - 0x6075_dd27_63ab_77ac, - 0x1aa0_6090_7bb7_8a07, - 0xef6a_bddb_8c68_635f, - 0x1b09_b5e0_1b7a_f882, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7849_72ec_1ae0_37c3, - 0x5a42_69be_4726_d8bd, - 0x56a7_19a2_e165_6dc7, - 0x1418_9c78_50da_d383, - ]), - pallas::Base::from_raw([ - 0x815b_cd2b_ca53_eb95, - 0x556c_78b4_7751_dbf6, - 0xf053_fd13_1a20_08c1, - 0x2881_c78c_feab_68d2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf306_1913_4ae0_7a9e, - 0xd306_6f26_bd6b_4a10, - 0xd230_d8ea_c29a_51fc, - 0x0e6c_d0f8_d1ea_c0f0, - ]), - pallas::Base::from_raw([ - 0x9fa4_27be_acec_9bb8, - 0x2a2b_c250_80aa_697f, - 0xdbf7_9c2f_db4d_bd95, - 0x0028_bb6a_8622_43f5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf013_8449_cc96_1899, - 0x379d_ac9d_9ebf_876a, - 0xeb7f_99d0_31cd_e93d, - 0x130b_5b85_19be_08fd, - ]), - pallas::Base::from_raw([ - 0xa4ed_7e43_422c_baeb, - 0x15bd_a565_cfd0_99f1, - 0x75e7_3fae_ef12_8208, - 0x1196_b027_3cf1_1fbc, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc311_f99e_5530_bae5, - 0x5e96_2191_2f98_67c0, - 0x0ec4_6179_0832_791f, - 0x3ab8_8c62_791f_cabc, - ]), - pallas::Base::from_raw([ - 0xe30c_dbb2_d1a3_46f3, - 0x300d_881b_2157_d573, - 0xe362_292b_af62_b032, - 0x02c4_23ea_26f4_a3a1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7244_fb82_f14a_5b15, - 0x1716_dbf8_c880_c5a0, - 0x134b_bb0d_fa04_d130, - 0x2c80_0943_ac16_971f, - ]), - pallas::Base::from_raw([ - 0x978a_d2ca_089a_5c31, - 0xe1e6_1bbd_0163_3f49, - 0x3330_aaf3_b642_cbd0, - 0x09a1_c6d2_ba6b_3d2c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x28a5_4ff3_bc33_d5be, - 0x3bf6_b12e_cf48_395c, - 0x222d_c71b_557c_9043, - 0x2440_8b65_1f74_a85b, - ]), - pallas::Base::from_raw([ - 0x9066_0895_04af_52c0, - 0x35e4_e8f7_66c0_15d1, - 0xa386_9229_659f_2484, - 0x207d_3198_11df_6bc7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x15d9_722b_d97c_c054, - 0xc0a4_0440_6239_45f9, - 0xb46b_37e5_73fd_989c, - 0x2b58_6ce7_ac3a_9166, - ]), - pallas::Base::from_raw([ - 0xb9d6_2d9d_3f31_dbef, - 0x7275_cd16_b7e6_a7a5, - 0x8d85_c044_6dd5_7a4d, - 0x0d86_a9fc_da53_0505, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6cc3_c1bc_2016_e727, - 0x617b_0dd8_180a_164b, - 0x4fd6_39de_9f61_971e, - 0x3d4a_6fd8_19ba_27f0, - ]), - pallas::Base::from_raw([ - 0x3413_e80e_aa57_8bd4, - 0x7b16_485e_63bb_769f, - 0x62bb_5921_8c4c_4aa2, - 0x1098_9857_f8af_586f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4d33_b7d2_2e3a_e53d, - 0xe888_af7e_b724_5aa1, - 0x78e6_f0f3_0b76_b896, - 0x15f9_f0ca_f850_8e61, - ]), - pallas::Base::from_raw([ - 0xbece_4f0d_e233_cb6a, - 0xeb3f_a9df_d0c3_9b89, - 0xb351_ff58_43cb_cac6, - 0x372a_a61b_e920_3f30, - ]), - ), - ( - pallas::Base::from_raw([ - 0x74f7_4a0c_a5d5_f226, - 0x3751_b852_e703_7cb6, - 0x9ad1_c8fa_759a_1891, - 0x10fd_b6b7_2434_8442, - ]), - pallas::Base::from_raw([ - 0xfcd7_aa2c_6716_e475, - 0x4f9c_2246_cede_c392, - 0x06aa_a436_01b9_97e3, - 0x0a26_804b_d57e_c010, - ]), - ), - ( - pallas::Base::from_raw([ - 0x539f_f781_f164_4836, - 0xd1dc_dc87_3d99_a0c6, - 0x2de4_7396_8ef1_0b89, - 0x0ff1_67a9_82ba_334c, - ]), - pallas::Base::from_raw([ - 0xb50d_ab91_5188_8e47, - 0xc1e0_55fa_97df_88cb, - 0x3547_e3a1_e0dd_755d, - 0x2d28_735e_9afb_ed0a, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa278_8a09_c089_d696, - 0xf529_cbd9_0600_711e, - 0xcb66_bb7a_1ef8_523e, - 0x29b9_17aa_34eb_2bac, - ]), - pallas::Base::from_raw([ - 0xed7f_a639_85a4_bf96, - 0xbc46_b5a4_cea4_8664, - 0x2c0b_8691_1652_3fde, - 0x3d30_43c2_7ddc_7417, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3c6e_e712_6545_c6fc, - 0x361e_60a3_9a64_72b5, - 0xa4fa_2bc5_6f5a_3772, - 0x206b_0968_ab5d_844a, - ]), - pallas::Base::from_raw([ - 0x7cc3_6e87_ba43_ad08, - 0xf915_23eb_eca6_b1dc, - 0x2fa9_d1da_381f_945a, - 0x25ff_57c6_8a6c_aa43, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7726_42a3_c1c2_2be0, - 0x5061_8408_7ab7_daae, - 0x67ee_d982_89e3_c3e4, - 0x1c40_7832_12e1_7379, - ]), - pallas::Base::from_raw([ - 0xaa43_becb_fcb9_ce01, - 0xe538_4afd_eab9_4a52, - 0x3e9c_4b32_8d24_33ff, - 0x0057_5aff_a2e5_24a2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xea0e_ce17_54e1_854f, - 0x4459_6094_9fc0_86c4, - 0x835e_6759_c23d_e766, - 0x0be3_ab41_eeec_484d, - ]), - pallas::Base::from_raw([ - 0x48f9_a609_6201_6be1, - 0x1909_3863_efb7_d549, - 0x2b59_8ff2_accf_39ce, - 0x389d_847e_e5a1_b1e9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x936a_c037_696b_6537, - 0x3560_e5b4_a313_28a8, - 0x1f47_fea4_cfcb_2890, - 0x0c6b_bc4d_4957_3c28, - ]), - pallas::Base::from_raw([ - 0x2ac6_7e2f_fba6_8746, - 0x80e1_d8ee_95b1_e538, - 0x0ff9_37f0_4793_a319, - 0x1094_a38b_a671_2718, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8ec7_df2c_b2b8_fae3, - 0xeb40_cbe1_652c_ef89, - 0xa02d_a353_aadf_1885, - 0x2c64_885e_84cb_e485, - ]), - pallas::Base::from_raw([ - 0xccf9_06a7_d926_e277, - 0x5d7e_8f08_57f5_5c3e, - 0xdf71_1b47_1772_d5f2, - 0x0ca8_260c_f185_b333, - ]), - ), - ( - pallas::Base::from_raw([ - 0xefba_501d_d999_2307, - 0xcbce_e2bf_bc0a_86da, - 0x7ba9_c366_8cca_0e58, - 0x10e0_7bda_6733_fc28, - ]), - pallas::Base::from_raw([ - 0x0a72_e66f_df7d_ebc3, - 0xf16a_67d6_2aa2_75b9, - 0x03d2_5e00_aa84_2a6f, - 0x26c7_55bc_dfdb_ce70, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1853_7664_9aef_2dff, - 0x7f94_4c4f_10a4_9717, - 0xe235_80ff_b9f5_ac99, - 0x1d38_7fb6_5f7f_4a52, - ]), - pallas::Base::from_raw([ - 0xb59f_6906_b41f_c19e, - 0x6ae3_f226_ba4b_d26b, - 0x5171_2aca_d3e3_cb0c, - 0x3019_b3ab_9250_0e25, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7405_db8c_8d13_97ec, - 0x3a1f_5c63_44b8_b4b2, - 0x3b16_175b_df99_eacb, - 0x0e5c_3936_5a61_4966, - ]), - pallas::Base::from_raw([ - 0x3c2a_824f_2a3b_26ee, - 0x0cb5_c814_2e77_4dc9, - 0xe648_7df6_e45f_90f6, - 0x3a37_71c5_e20a_e479, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0f51_40a8_9629_08a9, - 0xab28_d099_4637_c6c5, - 0x8d40_0c2d_dfbb_597d, - 0x359a_fe63_b4f2_9823, - ]), - pallas::Base::from_raw([ - 0x1fc4_f014_db42_75cc, - 0x136d_5fd6_5404_503c, - 0x0844_9c43_ce86_523a, - 0x0677_006e_034e_098f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7cb5_4bb7_ecfc_0a93, - 0x64fc_3b54_53ba_a1af, - 0xc453_e619_2e6a_86d5, - 0x2838_035c_ac98_9917, - ]), - pallas::Base::from_raw([ - 0x0f6e_5839_dff8_8640, - 0x1290_4182_7ebc_73df, - 0x4735_3b6f_4a1f_7e8a, - 0x31aa_a1ad_ca93_7f4c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9f43_37c3_6d2b_534d, - 0x3bc4_bb39_ede7_0bc3, - 0x2f38_79ae_104b_8a55, - 0x13b0_c171_d97a_4fc8, - ]), - pallas::Base::from_raw([ - 0x0d46_d1fa_370c_5421, - 0x8397_7f28_65be_b753, - 0x63f4_7e7d_e49e_dfd8, - 0x118c_46bf_17f3_a19f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb4eb_a0ce_8969_48bf, - 0xad2a_98d9_656d_0cf3, - 0xc651_741d_4d5c_668a, - 0x039e_bf84_e942_4d6f, - ]), - pallas::Base::from_raw([ - 0xe095_c878_476c_81a2, - 0xedc7_bc68_679d_680e, - 0xf763_852b_4eed_2af1, - 0x15e9_98b1_e98e_6e1b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8566_9a18_2b28_8d21, - 0x9344_357f_0a1f_da13, - 0x3772_d744_a179_b8ed, - 0x1b03_8534_4ec0_b55a, - ]), - pallas::Base::from_raw([ - 0x4661_8dac_39b6_0421, - 0x4ef5_5d88_b13c_01b6, - 0x5315_7c47_50c6_9734, - 0x2a3a_6e07_2174_0395, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1e17_b775_4399_3b91, - 0x2837_ecac_c403_6f3d, - 0x56b4_0a0a_664d_8fb4, - 0x2f04_0f71_e7e4_d554, - ]), - pallas::Base::from_raw([ - 0xcbf0_51de_b98f_c269, - 0x5c6a_a704_7588_9496, - 0x42fa_c5f8_299f_bcfe, - 0x1247_eccd_7849_645b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x163e_3aad_4d5f_7140, - 0xb692_8158_7410_67a5, - 0x26b5_6868_509f_8ba2, - 0x05b1_5c3d_6a3f_a4ff, - ]), - pallas::Base::from_raw([ - 0x7cab_64a8_a8d0_1dc7, - 0x5b3b_f269_2d68_3607, - 0x2a15_8448_6787_3934, - 0x259a_0f62_1c04_39a1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5bda_eacf_bdfb_6df5, - 0xff6e_56d7_32b9_a43d, - 0x4557_5d7b_eff9_afc9, - 0x115f_3e25_b370_bb60, - ]), - pallas::Base::from_raw([ - 0xfa75_dfbd_dac8_8daa, - 0x2f30_93f7_6e39_fdb3, - 0xc8c1_e227_7dc5_95ff, - 0x3ea1_7ec5_148c_679d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2447_5f8c_9993_6ad1, - 0x51ee_6362_1f78_87c0, - 0x475e_d1d0_ab29_f628, - 0x0303_ffaa_2430_a0b7, - ]), - pallas::Base::from_raw([ - 0x1dd2_a952_d5a5_189d, - 0x22cc_a0bf_5041_4271, - 0x49b2_3458_622c_c627, - 0x0130_c236_40f8_7f89, - ]), - ), - ( - pallas::Base::from_raw([ - 0xaaf1_9c5a_cad7_1c28, - 0x8bb1_2918_8b7a_7858, - 0x23e7_ce2d_92dc_d66a, - 0x1942_3751_8e3a_2f23, - ]), - pallas::Base::from_raw([ - 0xa32c_eb66_4b3e_d4d9, - 0xeb2b_683e_f2b0_6773, - 0xa6f3_5519_396e_3a07, - 0x1d2b_b94d_b61e_c34c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4d21_de83_ed0b_0ed9, - 0xbddf_daab_a5f2_5e3b, - 0x0bbc_a486_495e_59d5, - 0x1685_4768_9da6_e3ad, - ]), - pallas::Base::from_raw([ - 0x8704_6afb_e059_6e25, - 0xbf4f_ef21_6f4a_5988, - 0x336a_e9d0_5d21_7097, - 0x0a21_13b0_758e_02e5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1b2a_4f19_90f6_4ec2, - 0x56ab_849f_5d02_0569, - 0x2814_07aa_f7bf_a9ed, - 0x0601_c91a_2106_8b41, - ]), - pallas::Base::from_raw([ - 0xcb15_a0dd_808e_bc3d, - 0x07de_f385_c064_d556, - 0x2d6e_5a28_1e93_64d8, - 0x1039_dc0a_cb9e_a154, - ]), - ), - ( - pallas::Base::from_raw([ - 0xed0a_e905_2f8f_ec82, - 0xc113_bd2c_e530_54b2, - 0x0c7a_a4fc_f303_779b, - 0x0874_2829_cd8c_a708, - ]), - pallas::Base::from_raw([ - 0x6882_2f87_7899_c3f0, - 0x1896_a6ab_5b9e_67b3, - 0xcd49_5299_356c_6330, - 0x28a6_ee29_3adc_b613, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4b5e_4d5b_3583_5cb1, - 0x7c02_2a85_aaa9_48e4, - 0x8e1f_4a9b_8d4b_d320, - 0x3a17_94db_a7a9_3fc6, - ]), - pallas::Base::from_raw([ - 0xdd55_72e9_e0fe_59d3, - 0x7b10_d3c9_524a_5acb, - 0xfdfd_2d82_7b63_647c, - 0x0f9a_11b5_efe5_01ac, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8a46_db66_f88a_dfda, - 0x231a_f130_d914_9161, - 0x9afc_b0b8_a037_044d, - 0x2f80_ba78_43d6_0676, - ]), - pallas::Base::from_raw([ - 0x7b8b_4486_b3b0_f9ac, - 0xe9b8_0152_03ff_232a, - 0x3152_b63f_bf6b_2e27, - 0x2c41_0add_3b9a_25cd, - ]), - ), - ( - pallas::Base::from_raw([ - 0x346c_dbf0_be76_95e5, - 0x67e3_f66a_ed16_d76a, - 0x0461_f1a2_8763_60a3, - 0x0a18_29ce_9f91_a1d5, - ]), - pallas::Base::from_raw([ - 0xf17b_9a2b_6fc8_8392, - 0x2c4e_a7a2_bc5d_fd52, - 0xf512_092f_5365_a2ac, - 0x2c5f_2e6d_efce_5696, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa5c1_e1f8_460d_9bd0, - 0xb139_cee1_fbb6_2242, - 0xf5e6_14a0_2785_2538, - 0x133b_ce23_0971_df91, - ]), - pallas::Base::from_raw([ - 0x189c_cd97_00f7_da52, - 0x0ebf_79f0_cb47_65ce, - 0x749c_44ef_1e7d_1d11, - 0x312f_ad99_bbe7_c204, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe752_8bbc_917a_6be2, - 0x0bc2_ab1e_2504_cf52, - 0x3a48_1726_09ca_4031, - 0x2ce5_37e1_0a7c_529a, - ]), - pallas::Base::from_raw([ - 0x64f7_9aef_f4c4_2d79, - 0x9fd8_db65_8592_ed64, - 0xf842_04da_8886_9faf, - 0x377a_985c_3a1b_860c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5d3e_bfc6_25d2_05fa, - 0x10fa_dab3_20e6_ff3f, - 0x1784_f663_e29a_30ca, - 0x2a69_96bb_3ac5_9673, - ]), - pallas::Base::from_raw([ - 0x3fb6_a9c2_e6d6_0488, - 0x90b5_9221_a401_79bf, - 0xdc88_a94b_7528_facb, - 0x2c29_eed6_7fbd_9a89, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfea6_2c82_74a6_af4c, - 0x388c_7bcf_228c_73fe, - 0xc0c7_ea19_e955_ddd7, - 0x1e46_4602_7b2b_c1ca, - ]), - pallas::Base::from_raw([ - 0xca09_e0e1_e39c_3c01, - 0x701a_20ec_477e_affc, - 0x0fa5_db8e_79e9_4367, - 0x3cfc_3c48_e73a_04d1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd84c_ccf5_eb33_4179, - 0xce23_1898_15de_f8c7, - 0xe76c_8dea_7db5_8e1f, - 0x3aca_479f_f6b4_9d8a, - ]), - pallas::Base::from_raw([ - 0x17f1_246d_f123_7a60, - 0x2e17_9d8f_8d2f_2fa6, - 0x32d0_e613_423e_f64f, - 0x067c_293d_8b6e_c1ae, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8ecd_0c0a_17a7_8a19, - 0x7136_7ba6_7f60_b188, - 0xff5a_bf2c_d1aa_d63a, - 0x3656_099b_d15e_edb5, - ]), - pallas::Base::from_raw([ - 0xc0df_1063_d1e2_9ebc, - 0x9aec_45eb_3df3_5ab5, - 0x6e71_3f49_7b86_cba1, - 0x2e44_9f1d_b523_59ca, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa56e_440e_afba_0e69, - 0x10fb_4ac0_433e_be1a, - 0xd95f_392c_8d71_ee6d, - 0x34ef_089e_8af4_75db, - ]), - pallas::Base::from_raw([ - 0x9cde_8968_4faf_ee29, - 0xd390_7c2b_4645_4693, - 0xf858_c045_9eb2_6def, - 0x2a59_6136_fc96_199e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd341_83b8_68a0_094b, - 0x46c5_6330_1224_b24f, - 0x939f_ac11_dc0b_394b, - 0x1198_5ddc_b45f_ed85, - ]), - pallas::Base::from_raw([ - 0x4503_5252_8c23_bdac, - 0x818c_e278_0479_31a8, - 0x4d8b_05af_33be_0a68, - 0x2854_b240_01fe_2947, - ]), - ), - ( - pallas::Base::from_raw([ - 0x21ea_923b_9dba_2757, - 0x102d_32ee_7267_baa4, - 0xe07e_8d17_ff5b_d96d, - 0x0539_fe92_593b_cb44, - ]), - pallas::Base::from_raw([ - 0x89a6_e78c_a798_2cda, - 0x776a_98ae_c6c1_fc45, - 0xa4c1_cc4e_5efb_20c5, - 0x2f15_1e00_8953_fe2c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1023_5041_83b9_1d97, - 0x81fe_bc2a_8877_ca60, - 0x1924_5c49_fe3f_bb4c, - 0x0d38_a13f_e3f3_74f3, - ]), - pallas::Base::from_raw([ - 0xd643_1731_44a1_45de, - 0xcd95_d78b_7357_5f87, - 0x6ed2_6c3f_d329_09e3, - 0x0960_8380_e85f_342a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4291_8cdb_be2f_c05e, - 0x9acf_4a57_b166_d495, - 0xca99_c923_f45e_49ab, - 0x3fa1_33ab_04b7_a1e9, - ]), - pallas::Base::from_raw([ - 0xd731_a982_524d_4da0, - 0x55ec_878d_0321_1172, - 0x48d5_eaed_e324_92cd, - 0x0cff_b957_d167_7198, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf528_ad8a_c429_a4c2, - 0xd99b_85cd_8bcb_927e, - 0x853a_6c3f_3ecd_f11d, - 0x3fb4_d9e9_0d91_ecb0, - ]), - pallas::Base::from_raw([ - 0x9137_5cbd_7088_a770, - 0xbc73_46bd_4063_fc5d, - 0x52ee_b5a0_1934_a31c, - 0x3597_389b_0dc1_1334, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdb04_e2bd_c6a3_3802, - 0x4896_61c3_cebe_0978, - 0x21f9_61cc_a49e_f597, - 0x0fc8_c0b7_b394_2242, - ]), - pallas::Base::from_raw([ - 0x8f85_9b56_948a_bed6, - 0x72b1_52a1_bb7c_2347, - 0xfcda_82d5_34b4_88d3, - 0x3e4d_040b_c1bf_dcf7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x24a9_d7d9_f5f8_fb4c, - 0xa84b_e92f_da7a_6564, - 0x7c10_a2c0_1bac_9ff6, - 0x343d_ecbb_2e70_9ef9, - ]), - pallas::Base::from_raw([ - 0xf538_642e_d7fd_e654, - 0x6d30_faa6_432e_584b, - 0x18f2_02ad_2856_2bcc, - 0x1a0c_7166_2352_d21d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x08e8_9011_14d3_3f6a, - 0x0d82_62ea_f48c_28a2, - 0x89fe_087b_2750_6546, - 0x0895_2f7a_efaa_e8e6, - ]), - pallas::Base::from_raw([ - 0xca63_280f_9555_84ad, - 0xc7be_a103_e8a5_d522, - 0xb795_d913_5441_e491, - 0x3aa2_13ad_62ab_a032, - ]), - ), - ( - pallas::Base::from_raw([ - 0x154d_e3e2_a46d_afa1, - 0xef1b_cb7e_af7c_9641, - 0xc4cc_1e3f_0b9c_48b7, - 0x227b_14a3_1a99_2a2e, - ]), - pallas::Base::from_raw([ - 0xe7e2_e290_71fb_4a61, - 0x28f4_a7fe_9e2c_3b73, - 0x2fc8_8036_1925_c86a, - 0x2cde_373d_3d92_f96a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6c19_1842_a7d6_f4c8, - 0xa31d_ba99_3039_3d70, - 0x3514_6c26_3e06_7076, - 0x3803_9a47_4646_486b, - ]), - pallas::Base::from_raw([ - 0x27af_d249_5982_96c5, - 0xfcf6_b6aa_f5b2_d252, - 0x5c22_b91e_7495_dfec, - 0x2d57_9b70_dfa4_6507, - ]), - ), - ( - pallas::Base::from_raw([ - 0x50af_b111_4376_64df, - 0x1a85_72f4_fe6f_5325, - 0x1388_bf8b_eacf_630e, - 0x386b_3799_e109_7613, - ]), - pallas::Base::from_raw([ - 0x1d70_2f5b_9143_e12a, - 0xaac6_af7e_c5f3_428d, - 0x17dc_6b11_551f_52f2, - 0x0f7c_38b0_e835_e793, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc6e1_bd75_9bd4_3e46, - 0xb4a0_cc52_41e1_0baf, - 0x9b77_ed75_c46e_f6ab, - 0x0c02_f929_5248_ff03, - ]), - pallas::Base::from_raw([ - 0xc445_5024_0956_6825, - 0x0996_b65c_b2e1_7918, - 0xec22_9f0f_1eb1_49a6, - 0x0c64_8828_4462_5887, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc412_8bbd_2797_ba18, - 0xbd47_1f04_69d3_5b08, - 0x021a_0ae6_846c_2364, - 0x1e0d_3b1e_f4ea_6379, - ]), - pallas::Base::from_raw([ - 0xd0bd_8eb2_1cab_9f78, - 0x1bfb_e611_fe72_74e3, - 0xf844_8815_10e3_d7de, - 0x150b_00bb_a5ac_9396, - ]), - ), - ( - pallas::Base::from_raw([ - 0x752e_2b2b_9169_c0de, - 0xf2e4_7feb_5a2b_1656, - 0x61f7_7831_314b_7912, - 0x29d5_36bf_1530_146c, - ]), - pallas::Base::from_raw([ - 0xc890_bb54_9aff_0c72, - 0x197d_a4e0_76db_b42a, - 0x746f_0142_3821_5206, - 0x2512_c57e_4c5a_951e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe7e6_6a45_c1aa_686c, - 0x8c98_b474_bd46_1267, - 0x8ae1_d414_4cc1_4cdf, - 0x1b9f_33fa_945c_8c67, - ]), - pallas::Base::from_raw([ - 0x9802_7495_ad6d_6b21, - 0xccc8_ed29_cecc_1b1b, - 0x74c8_0f51_6930_7044, - 0x334b_d2ec_3b06_2238, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe2e3_e34a_e48a_4542, - 0x77a7_9d9d_ee72_233a, - 0x9290_2fcd_5d97_3f99, - 0x0e28_df80_537b_d86b, - ]), - pallas::Base::from_raw([ - 0xb257_f5b7_a198_5b9a, - 0xaddd_7e70_cbc2_8f19, - 0xc35b_17df_11d3_bb77, - 0x28f4_8a76_e85b_984c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc1d2_64b9_7aa5_7f83, - 0xc8a7_697d_1031_d3ba, - 0x1e54_33c8_d6c1_c1ba, - 0x1a28_4362_7c85_7a95, - ]), - pallas::Base::from_raw([ - 0x5c00_7005_f638_803b, - 0x153c_6810_33d1_3436, - 0x39ca_84fa_65ec_c4cf, - 0x36a5_7369_ebe3_2da1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xcb3b_fab7_1ed6_88d1, - 0x959d_75b1_c3da_4470, - 0xff6b_cf88_212e_3d2b, - 0x1ab4_0ee5_990b_6b99, - ]), - pallas::Base::from_raw([ - 0x18fc_cc71_d6e5_8e43, - 0x52fa_e1cf_1c00_0d21, - 0xfe55_97c1_42a4_a225, - 0x0a8a_53ab_72a3_13ba, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf4ce_3a37_5416_8e4b, - 0x61c7_546a_ec52_434a, - 0x7d70_ac66_6893_57e8, - 0x1c12_4475_9a7d_efc8, - ]), - pallas::Base::from_raw([ - 0x3b5f_2cb6_a96e_db5a, - 0xef71_e886_2359_5d4f, - 0xe5a2_7436_5afd_c9e0, - 0x110a_f91f_2774_3efe, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6895_e22a_e677_de95, - 0x9fbb_9b3d_937b_3dc3, - 0x0bc1_f4d9_d4d5_bd66, - 0x27f2_b67f_1fec_e78a, - ]), - pallas::Base::from_raw([ - 0x7234_9411_50bc_efc4, - 0xac8e_5753_a8f5_0362, - 0xf7e3_8c41_e428_466c, - 0x315e_645b_5d4d_cf13, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5494_bb94_e808_6993, - 0x909a_795b_c421_efe8, - 0x038b_cb01_6b45_f433, - 0x2fc4_4636_cbb6_d6dd, - ]), - pallas::Base::from_raw([ - 0xa37f_6fe0_0cbd_bb87, - 0x0aae_cb06_be08_0506, - 0xdd80_a12f_e84d_f36f, - 0x1dc8_84e0_7af9_e250, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdaa4_1d05_a56d_0e0b, - 0x6fed_5c75_13eb_443c, - 0x7a8b_0e4c_65b1_cd50, - 0x214f_7c8e_ed8b_b0ef, - ]), - pallas::Base::from_raw([ - 0xfe49_d9d5_1881_ea16, - 0x2353_dd64_ed34_1337, - 0x56b2_0c8e_d9f1_26d9, - 0x2c22_92b4_4c2b_0de8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa74d_964e_9b7c_04bb, - 0x335c_bb5b_4ec0_2dec, - 0x8a84_7bec_6994_329f, - 0x1aa7_1c22_0de7_c5d4, - ]), - pallas::Base::from_raw([ - 0xc3b8_82a6_d6f9_f593, - 0x9ba7_9e1b_259f_8ae6, - 0x8ab6_b763_bd79_cc26, - 0x2183_61af_34fa_b740, - ]), - ), - ( - pallas::Base::from_raw([ - 0x97b6_5e79_5bd5_3661, - 0x560b_b24b_f4dc_8b38, - 0x16ce_dcc1_c055_12da, - 0x1571_6cae_b4f2_105b, - ]), - pallas::Base::from_raw([ - 0x3f1a_b4a4_ab91_7f25, - 0x4597_f16e_4e48_2ec7, - 0x43c4_b3e2_9f78_544b, - 0x0abf_eec2_26bf_1c59, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9beb_a739_41b6_91d7, - 0xcf15_e49b_9d08_eba3, - 0xd443_2465_4f9b_bb6e, - 0x2542_f10c_5975_b4f6, - ]), - pallas::Base::from_raw([ - 0x410d_c2a6_f3c7_221c, - 0x9e64_ef82_f138_821d, - 0x3607_68e2_df2a_cb50, - 0x2af0_280c_a2a1_a946, - ]), - ), - ( - pallas::Base::from_raw([ - 0x40aa_4da4_2525_32cc, - 0xa047_25f5_6850_6918, - 0xd096_8644_fefc_e14a, - 0x0591_ae22_96a9_a185, - ]), - pallas::Base::from_raw([ - 0xc59d_ea56_2de9_c223, - 0x1548_1b85_8a62_94f1, - 0x0aac_a08d_c1b6_25a2, - 0x0f05_cf9a_21ce_dda1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd14b_b7d1_5076_72cc, - 0x6330_7f6f_52ce_3ad5, - 0x7ce5_1e25_ad24_3072, - 0x07dc_2bac_dd7c_6ea0, - ]), - pallas::Base::from_raw([ - 0x5836_c3d5_7c40_ffae, - 0x46f5_819e_44b7_ae09, - 0xb796_fb55_e09c_9785, - 0x2d95_737b_55d5_5dd1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x86dd_a9bf_0115_82af, - 0x40d9_e41e_3690_6b44, - 0x5787_20aa_8983_bfa2, - 0x2f1a_1706_18f1_8afb, - ]), - pallas::Base::from_raw([ - 0x09f8_9309_75e4_a8c6, - 0xef85_967d_be1c_9f79, - 0x4a38_18ba_32b7_bcd4, - 0x0a8f_1295_63b5_5cb7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x64e5_850f_a84e_2a38, - 0x67a1_f9d2_a1cb_2892, - 0x34b6_e8a9_6a3d_1adc, - 0x2e6f_30e3_86d6_a0c0, - ]), - pallas::Base::from_raw([ - 0xb9d1_3f17_8e65_ff6a, - 0x4ffb_0b20_e25a_7848, - 0x6c2f_dcd2_e668_e2d3, - 0x1e93_9c54_a6fa_239c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3316_8467_79ce_e7f6, - 0xfb6e_d07b_5560_c360, - 0x4a8f_2f59_55ff_6357, - 0x28fb_77fc_9375_6d8d, - ]), - pallas::Base::from_raw([ - 0xe3e2_1b78_b2cf_5612, - 0xc8d4_70e2_cb22_7688, - 0x731b_0c6e_e1d4_f24b, - 0x30cd_02ff_4619_55c2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8e9c_4a02_e5ea_9126, - 0x6fb9_f18e_4e5e_96dd, - 0x494c_3274_6849_1131, - 0x18b5_fe24_35aa_0912, - ]), - pallas::Base::from_raw([ - 0x4956_0a92_8dfc_8d75, - 0xc948_7b69_3b11_267e, - 0x315e_da1d_1b42_789f, - 0x35d4_3503_9f73_bf9a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0010_6821_9f96_2f62, - 0x3931_2d4d_6b30_e2e7, - 0x94be_b29a_ad36_c2c6, - 0x36f4_5328_c007_73d2, - ]), - pallas::Base::from_raw([ - 0xe4f3_0b41_1e5d_d8b5, - 0x65e5_1f6f_4823_cbd8, - 0xf47f_3fd3_d0b6_f299, - 0x1427_8ff8_e951_56be, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe14f_d0ad_d91e_2015, - 0xa2bc_ccd9_60a9_fdab, - 0x715f_aab5_f71c_b572, - 0x1960_ed3b_e23f_8c8c, - ]), - pallas::Base::from_raw([ - 0x6d4d_e792_32d9_75b0, - 0xa0e0_d86f_f79c_4490, - 0x947e_ec8e_5f3c_08d9, - 0x162a_f9d0_f176_eeb6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x77be_2a89_644f_4e4f, - 0xdac2_fd2f_f979_19f8, - 0x482d_415e_0aa4_336e, - 0x12b4_8f67_c25d_ddea, - ]), - pallas::Base::from_raw([ - 0x1447_b356_5495_fdc2, - 0xfa86_152d_2046_a6bd, - 0x0e48_3cee_96b6_3430, - 0x310a_f969_9f04_356b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x49d9_568f_4b49_90b2, - 0xff1d_52e9_6c43_0eed, - 0x9dab_c67e_0ab6_7fbc, - 0x15b8_acf0_dafc_6bd0, - ]), - pallas::Base::from_raw([ - 0x04db_2abc_c8af_ebe1, - 0x858a_4302_b8ed_aede, - 0x857e_f9df_9683_371a, - 0x0ed5_6792_c5bc_56a9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8fc8_c4bb_97be_29b8, - 0x723f_ec3a_c6fd_9388, - 0xcc18_5b44_14ce_3800, - 0x1903_31a9_ed7c_af8c, - ]), - pallas::Base::from_raw([ - 0x6e48_8eb0_820c_1768, - 0x7fcb_5d2c_98f1_ca49, - 0x32c6_8966_238e_4125, - 0x06ca_d05e_b165_eacc, - ]), - ), - ( - pallas::Base::from_raw([ - 0x05d6_73c0_9942_4c38, - 0x9b1c_e944_65d8_d36c, - 0x4192_c0f4_f365_0b99, - 0x3383_b385_084d_b871, - ]), - pallas::Base::from_raw([ - 0x41a3_b162_abb4_42dc, - 0x017f_86b0_2583_46ed, - 0x458e_9783_e3ed_a2b5, - 0x083e_e1cb_29d3_6b81, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe476_9543_7977_767d, - 0xed9c_7b2a_f66c_175f, - 0xb833_a588_5741_cd5e, - 0x363d_b7fb_cd58_d72c, - ]), - pallas::Base::from_raw([ - 0xf313_93cb_d9f8_02e3, - 0xe6eb_366c_2b43_078b, - 0xbca3_b4dc_3212_594e, - 0x08b1_1978_df11_1b34, - ]), - ), - ( - pallas::Base::from_raw([ - 0x77ce_a705_9e6f_006c, - 0xa35b_db7d_dc08_66ab, - 0x715a_f92e_56f1_97ea, - 0x3664_9345_05c4_d86e, - ]), - pallas::Base::from_raw([ - 0x9c53_e468_a11d_cffc, - 0x1c3e_0f67_68dd_602c, - 0x1ba5_77b8_d65c_4577, - 0x1d42_09b8_67f6_9ae6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x260a_5380_a10f_5880, - 0x7a1b_b8cc_b65a_04e5, - 0x27a8_f9ff_d28b_2308, - 0x3a32_fb37_acbe_f3c3, - ]), - pallas::Base::from_raw([ - 0x914a_9b46_a374_9954, - 0xfed9_b9fc_0c61_8135, - 0xfe45_3ec9_a172_f21e, - 0x1c9f_90fd_5778_ec0f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9910_a461_c209_3108, - 0x2c2e_d023_b39e_9004, - 0x2c03_9b33_a27f_913b, - 0x0a0e_6954_9577_4dec, - ]), - pallas::Base::from_raw([ - 0xe6b9_b73d_4549_90d8, - 0x47ba_dd67_2352_1eed, - 0x40be_e046_81a5_cc00, - 0x36b5_ea1f_1eff_932d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd2e0_0398_4661_f7a3, - 0xca79_c17c_09e6_51e1, - 0x7836_47d3_410b_a538, - 0x217c_55a4_8acb_9a5d, - ]), - pallas::Base::from_raw([ - 0x1bd2_0b6c_04fd_e263, - 0x02c7_b694_dc6d_a359, - 0x3a71_9cfc_8a1b_9a1c, - 0x3fff_5323_5b48_9bbe, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe25b_d2f6_66fc_16d2, - 0xf999_b1a1_db9c_75c2, - 0xd0f6_f6cf_794f_162d, - 0x3366_32de_5352_5f98, - ]), - pallas::Base::from_raw([ - 0x1c68_3a79_9230_e098, - 0x807c_7b25_a72c_04ed, - 0x534e_0c05_0c08_e762, - 0x2bc6_1d1f_88b2_bab0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6ee1_ad02_6d11_3806, - 0xc402_cf86_0c69_c2f8, - 0x1b43_0a98_7ad4_7948, - 0x3123_cab0_04e7_4073, - ]), - pallas::Base::from_raw([ - 0x28ac_c01e_af74_1193, - 0x3d35_2c06_3e65_b2b5, - 0x5da6_8188_3d2a_52ab, - 0x38f2_4ab3_5569_517a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6baf_341c_2702_9a80, - 0x31d7_cf3d_2326_22c1, - 0xb56b_e361_456f_7da3, - 0x22d9_07c2_5b47_0494, - ]), - pallas::Base::from_raw([ - 0x8110_08ea_9321_b2e1, - 0x9e15_c19c_8b04_0ec1, - 0xc7b4_860c_a4fd_0f1a, - 0x3fb3_5b5c_9ff2_ce92, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3eb4_cbe9_57c3_215d, - 0xe3bb_1c30_aa5a_2018, - 0x6829_f364_04df_ce6a, - 0x1e4c_9bb8_5e77_3502, - ]), - pallas::Base::from_raw([ - 0xf927_5406_c35a_b692, - 0xedb3_cacf_43f8_d2eb, - 0x5b04_6f41_e82f_fa8d, - 0x16c2_b490_1be1_772e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x91f2_5bb0_0df3_b325, - 0x9fa2_042e_bf14_310e, - 0x440d_8c06_8bb1_5a05, - 0x000a_e05a_1117_51b6, - ]), - pallas::Base::from_raw([ - 0x71a9_f252_e8dc_96fc, - 0x93e9_0e94_a948_47fc, - 0x35bd_756d_82e4_6522, - 0x0dd4_182d_0922_90ad, - ]), - ), - ( - pallas::Base::from_raw([ - 0xac7d_898a_152e_395a, - 0x893e_8851_1ab3_33da, - 0xf069_82b1_791e_1812, - 0x1fb6_f3c4_cf65_d002, - ]), - pallas::Base::from_raw([ - 0x65c5_e104_bca2_bc38, - 0xcd1b_883c_113f_a262, - 0x96bc_af49_58ae_d45e, - 0x3c4c_e7d2_6eb9_a372, - ]), - ), - ( - pallas::Base::from_raw([ - 0x867f_b40f_ed90_02ea, - 0x40a5_041b_7cba_a776, - 0xc206_37a4_c7c4_ac98, - 0x2570_9da2_0e46_8fbe, - ]), - pallas::Base::from_raw([ - 0x651a_689f_4ec0_fd53, - 0x4a1e_3008_41ea_e098, - 0x9e4d_ec05_ca83_49d2, - 0x2fcb_ed31_57c6_0795, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa5b5_1c60_e817_6fd1, - 0x2e8f_21e3_bfb9_750f, - 0xf45c_e53c_8b74_a941, - 0x04fd_1a36_e04a_7b99, - ]), - pallas::Base::from_raw([ - 0x5ca7_72c9_9b5a_d4f9, - 0xea3c_aa3d_8393_caee, - 0x3508_ad20_2818_0ba6, - 0x1b7d_cd69_c52c_070f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf076_4e26_b3f1_d20e, - 0x18c7_142e_8625_e9c8, - 0x51f7_7d4f_7dde_dce2, - 0x2373_bf50_232b_3f22, - ]), - pallas::Base::from_raw([ - 0x47b8_d63d_328c_c660, - 0xdafe_f5c4_0e05_ae5d, - 0x98b5_a965_47c9_1289, - 0x01ad_0491_0905_0a6c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1144_a189_947f_94df, - 0xe428_df16_cd10_22ba, - 0x7565_d9ea_3476_c4a8, - 0x2070_a6e3_1265_c3dc, - ]), - pallas::Base::from_raw([ - 0x91df_7f7d_dec9_e146, - 0x9135_871c_349e_dbe7, - 0x7edb_dcb4_d0e8_bb0a, - 0x0c90_c909_0575_8d15, - ]), - ), - ( - pallas::Base::from_raw([ - 0x497e_9d18_b31f_1ea6, - 0x087a_5e39_1bec_b0e3, - 0xe8de_4d9c_6a44_8c64, - 0x141d_4aad_df85_22b8, - ]), - pallas::Base::from_raw([ - 0xff15_6277_b7ae_3c64, - 0x3455_b096_0f5b_a73c, - 0x2051_cfe3_04f9_e861, - 0x19f8_6f8b_52e2_d6d7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9eb2_3cac_ee0c_46a4, - 0xe61a_c293_cba7_7cd6, - 0xc50e_6571_9c07_30af, - 0x2225_2c4f_0dc9_d926, - ]), - pallas::Base::from_raw([ - 0x99ee_8f10_2d20_4335, - 0x09d9_c154_3bf6_02d3, - 0x61d7_e3d0_9e64_c519, - 0x1b3f_b8bc_c227_b8f3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6b9e_a4ea_df65_cb3f, - 0xc1fe_f822_6717_eb27, - 0xfb69_b82e_a0f3_4f2c, - 0x2594_f3af_922c_6c4c, - ]), - pallas::Base::from_raw([ - 0xc431_a2b7_6a21_a9ae, - 0xba4f_fa4e_a749_4caa, - 0x354d_e308_ab36_c4f9, - 0x244b_96c7_5d78_711b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4768_edc3_6542_5192, - 0x6635_8e8a_a347_fefe, - 0xb5f4_dfd5_e5b9_73ce, - 0x1a59_51c5_25bf_f454, - ]), - pallas::Base::from_raw([ - 0x7e01_049a_8df5_fd8a, - 0x6b01_2890_41d2_19dd, - 0x3844_3e89_e500_e012, - 0x2be0_f234_4af5_6d77, - ]), - ), - ( - pallas::Base::from_raw([ - 0xae1e_74fc_1860_213a, - 0x3fe4_3c3a_2886_f22c, - 0xdefa_9b1e_edbe_c1e1, - 0x31bc_5ab6_4e9f_5faf, - ]), - pallas::Base::from_raw([ - 0xbd19_b196_572a_8513, - 0x4272_e09b_f426_f2c9, - 0x9925_f875_ae11_ddf7, - 0x1fb9_5b9e_53fb_0d63, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb236_a763_08e8_7326, - 0x8974_b02e_45e8_dca3, - 0x0575_b904_ff33_10d8, - 0x0347_ed41_4f04_efca, - ]), - pallas::Base::from_raw([ - 0x18eb_fd89_32b5_0ad8, - 0x82a2_5574_4ed0_515d, - 0xb135_d6bf_0377_152a, - 0x3419_a1db_bc9a_9880, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8c84_0714_8c42_e400, - 0xee8a_bd72_6199_8367, - 0xfe4e_c3e9_5c51_4cd9, - 0x2b7d_7f9a_0bc8_cf07, - ]), - pallas::Base::from_raw([ - 0xe58f_7f61_3068_dfd4, - 0x31c9_d482_7192_7dd4, - 0xa09f_1e90_db5e_fe74, - 0x2e12_f957_7e54_b546, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3d25_c1f3_eb56_14c1, - 0x78b0_2ff0_db91_5adc, - 0x52e4_595a_4745_1abb, - 0x20c0_812b_5d28_2662, - ]), - pallas::Base::from_raw([ - 0xc166_e032_a3ff_9774, - 0xbf21_613f_887f_5cc1, - 0x6666_23cc_e45a_acb3, - 0x1f8a_670a_47ae_5415, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0e32_ea98_b294_1bb3, - 0x0040_f5f6_d5d0_174b, - 0x137c_87e7_3271_65a4, - 0x0614_8c65_f99b_da0a, - ]), - pallas::Base::from_raw([ - 0x6348_5e06_f44d_7edc, - 0x3b2b_37a4_b180_07ab, - 0xfe96_302e_4023_3b6d, - 0x0c86_9dda_efca_80d1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x74e3_303e_17d4_1cf1, - 0xb9b5_5056_8945_d1c1, - 0xf5ca_f3d6_bab0_c8ee, - 0x20aa_c0ce_dcdc_1816, - ]), - pallas::Base::from_raw([ - 0x465b_2a4b_f80c_a876, - 0x7f65_deed_eb30_4907, - 0xcf39_c880_9f38_77e2, - 0x0286_a346_71e5_743b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfb50_a168_127f_b04b, - 0x40f8_01e3_04f5_df03, - 0xb4e1_c034_c959_50eb, - 0x1126_9317_caf7_5d07, - ]), - pallas::Base::from_raw([ - 0x42c5_97bd_71be_93ad, - 0xe220_1b27_f87d_2e4b, - 0x11f2_a2f5_a81c_6934, - 0x25a7_0d53_1d5b_addf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x86c3_b612_1d8d_3fa4, - 0x4914_c783_0ca4_f15f, - 0x04ea_4fe6_f986_a7ec, - 0x2026_f468_4a50_7b0c, - ]), - pallas::Base::from_raw([ - 0x435e_50f3_7974_66eb, - 0x8b5c_73b6_b70e_0033, - 0x7ed9_4ab6_144a_18bf, - 0x2b10_91f0_ffa9_d775, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7335_a5d6_15f2_85a5, - 0x65e3_ce55_379a_4653, - 0xc59c_ed4a_cc76_2af0, - 0x0429_7a2c_6046_7f76, - ]), - pallas::Base::from_raw([ - 0x38f3_ec3f_0286_6257, - 0x1e13_f010_a49e_a5c0, - 0xdaf1_e8bb_06ca_2eec, - 0x329d_3ddb_9b5a_922d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x400a_e7f0_113b_1b88, - 0x6505_dd5a_729f_0ed9, - 0xf46d_81a6_8261_b4c8, - 0x2450_8490_e887_3820, - ]), - pallas::Base::from_raw([ - 0x35b8_1e5b_7fea_8621, - 0x9ab1_93bd_5e06_6a86, - 0x8692_12f1_d266_8fc3, - 0x15ea_d070_2b54_0d1e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x958c_8b6a_f42e_66da, - 0xdfcd_951f_1c14_d6f5, - 0xb5bc_07dc_6f54_f30a, - 0x1d82_d649_7016_56da, - ]), - pallas::Base::from_raw([ - 0x05be_a7e3_a36e_01f9, - 0x77ab_d96c_4618_47be, - 0xa7b5_16d3_9767_5ff3, - 0x1785_5e76_cc3c_e4be, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfd0a_310a_b4fb_5f5a, - 0xd05f_e1c2_4618_bb6f, - 0x5741_e067_013d_e384, - 0x2373_0ed6_879c_4bf1, - ]), - pallas::Base::from_raw([ - 0x7e9f_f7bc_b94c_5d16, - 0xd75e_56b3_9f76_fd96, - 0x5562_35b1_256d_ea0f, - 0x3ecd_11be_4f08_056d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3d04_4438_d2b7_8ca6, - 0xa679_db14_51f3_dcb0, - 0x922b_166c_a2b2_bb15, - 0x1107_3835_6e3d_778a, - ]), - pallas::Base::from_raw([ - 0x95ce_a45d_d63e_b7e2, - 0x2af0_c617_e626_d526, - 0x9d55_3537_9131_d95d, - 0x0d84_161a_6b99_3a77, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4df8_74c2_f161_5191, - 0xd297_0d9a_0843_1ff4, - 0x66c1_4b9b_525d_f889, - 0x3b83_8a77_8a22_ed9a, - ]), - pallas::Base::from_raw([ - 0x6786_9621_06cb_caae, - 0x83f2_0b98_433f_f62b, - 0xff05_c2a9_4d11_970e, - 0x32db_3f0c_596c_894c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x18d2_6b17_c5b7_95b4, - 0x5097_014c_31df_3d6b, - 0xc1bc_54b7_a9a3_6f47, - 0x003f_0149_4252_2ca4, - ]), - pallas::Base::from_raw([ - 0xe704_1773_6871_2b5d, - 0x012a_3a17_1425_6ed0, - 0x750f_6ae1_dac8_4dba, - 0x39fa_e6ac_0da9_dcec, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0022_fc4f_c196_3017, - 0x6e6d_a891_b75a_a6f2, - 0x8e65_aa60_d9c7_8441, - 0x2ff0_f181_181a_9fa8, - ]), - pallas::Base::from_raw([ - 0x08ea_646a_eaa0_74f3, - 0xe893_09ca_01bb_be00, - 0x0021_c936_55f7_2464, - 0x2e6f_5fdc_b38c_af4f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x99bf_57d6_5784_c501, - 0x7017_bd72_7c8e_b52c, - 0xe919_d31c_2d32_8f5d, - 0x0bcd_43af_aaf5_2fb7, - ]), - pallas::Base::from_raw([ - 0x60d0_5ba3_c3d4_e2a8, - 0x03a1_39f0_df52_02d2, - 0xe5c8_8a6e_21e1_9481, - 0x384a_d0a4_1d52_9ba5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xac1f_1153_693b_c3fb, - 0x95cb_3d54_26f8_0864, - 0xacc9_531f_91c2_17a7, - 0x37a0_65ab_2b62_bad6, - ]), - pallas::Base::from_raw([ - 0x2556_2833_d728_cc98, - 0x157a_5fe3_6bdc_7a86, - 0x45a9_fabe_1703_6e96, - 0x15a6_2e9a_3e84_6efb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x84eb_0966_60b5_7d7e, - 0xbcb3_c183_689f_69b6, - 0xc179_6b0c_1aa2_7a8d, - 0x1f47_12b0_6b77_73e3, - ]), - pallas::Base::from_raw([ - 0x2e00_a10a_f3c4_6f66, - 0xd4d2_d9a4_4958_e31e, - 0xaae5_c9f9_9f8c_6e6a, - 0x0ffb_5c9c_6c4a_c3aa, - ]), - ), - ( - pallas::Base::from_raw([ - 0xebdf_427c_e6aa_6032, - 0x2284_d8b0_888f_cc3a, - 0x3f9c_8166_83f2_fe8d, - 0x3be0_c3d2_1862_d2b0, - ]), - pallas::Base::from_raw([ - 0xd068_4fe3_7825_0382, - 0x29a3_85cf_563b_538f, - 0xb401_2ac9_07b0_9161, - 0x3fe4_fabe_5f26_0616, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0bc2_86a7_8d4d_c29a, - 0xa808_bac0_57cb_7c72, - 0x1e71_e213_e7ad_d6cd, - 0x3d6b_987c_9596_0b11, - ]), - pallas::Base::from_raw([ - 0xe4ac_cdd3_7e1d_475a, - 0xe6b1_afb2_8e9a_e97c, - 0xb43c_7942_dc38_771b, - 0x0a9f_622c_5b76_581d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x346d_1c37_d315_d20d, - 0x2f90_33b6_9759_2232, - 0x19fa_9995_c446_fd03, - 0x0e97_a5fa_b367_fc42, - ]), - pallas::Base::from_raw([ - 0xa4f9_7858_7b47_3a80, - 0x5c3a_72cf_5848_9bcc, - 0x812b_72e4_2421_a299, - 0x2b11_99ab_416d_bef7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5e07_f1b3_b73a_4e48, - 0x19b0_925f_6f8f_6b83, - 0xcf98_c5cc_7f9a_9cb2, - 0x0f1a_0d41_9b39_1617, - ]), - pallas::Base::from_raw([ - 0x632f_c83e_f090_fdec, - 0x2f3c_0e5b_a18e_d660, - 0xce90_d880_46e7_cabf, - 0x0cad_fd0b_a42e_ea59, - ]), - ), - ( - pallas::Base::from_raw([ - 0x238c_cf74_76ab_5023, - 0x074a_888a_fb1b_0035, - 0x3763_56e8_efeb_ecee, - 0x203e_1e97_4451_db54, - ]), - pallas::Base::from_raw([ - 0x205f_a8cc_d857_d1b7, - 0xa271_379b_274f_7284, - 0x3d47_8f66_532f_d8fc, - 0x1366_88be_56b9_e771, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2b08_b53d_bb1c_746f, - 0xded6_6332_130e_59f9, - 0xec3e_7d70_890f_11b3, - 0x070b_8394_0557_a571, - ]), - pallas::Base::from_raw([ - 0x9320_2c85_006c_febc, - 0x679f_3693_3fc6_5b4d, - 0xea12_f030_0d2a_06e1, - 0x2e11_4723_802f_792c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x356f_e85c_2e67_e247, - 0x1d0d_775e_a300_5f6d, - 0x80f8_64c6_bbd0_c16c, - 0x317a_eda0_114e_e9f0, - ]), - pallas::Base::from_raw([ - 0xcda6_4589_4bfc_0455, - 0xf9fc_3a76_ac88_3c1f, - 0x61f6_a208_798d_28ec, - 0x2c02_1be9_a8c2_9b49, - ]), - ), - ( - pallas::Base::from_raw([ - 0x717a_a137_f5c5_be89, - 0x9028_5359_3102_985b, - 0x4ffc_0b33_2c5a_0750, - 0x2494_2c9c_ed84_3a53, - ]), - pallas::Base::from_raw([ - 0xfbdb_198d_0cae_4fa7, - 0x301e_d666_339f_ae29, - 0xe8db_271b_351f_54c1, - 0x1ec6_b81d_e40c_48da, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1fad_ffb9_7149_61e3, - 0xa176_3927_04e4_6feb, - 0x335d_89f8_2091_038d, - 0x0556_0da5_b68a_034a, - ]), - pallas::Base::from_raw([ - 0x7cbc_a061_15ef_3129, - 0x8e19_e08d_db9c_008d, - 0xa745_abb6_b7a1_36fb, - 0x2ccc_b707_6bde_5545, - ]), - ), - ( - pallas::Base::from_raw([ - 0x66ba_c59c_6f88_1b40, - 0xae9b_1f86_51c5_f96c, - 0x688e_7e00_9bdc_52e1, - 0x27e4_380e_842e_d733, - ]), - pallas::Base::from_raw([ - 0x1be8_47f3_618d_78db, - 0xcbf1_c63d_6c8b_f57f, - 0x62cb_3b48_a39f_91dc, - 0x0ced_7d2b_0b84_8552, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2bc3_ed47_d3b1_9dae, - 0x7929_235c_2bdf_6880, - 0x4ec8_7166_4d23_deae, - 0x026a_bf29_d792_9647, - ]), - pallas::Base::from_raw([ - 0x8951_204b_5262_6b96, - 0x15ba_29c7_c672_fad2, - 0x0d49_9ba7_a480_134c, - 0x397c_dfb1_4d54_65ce, - ]), - ), -]; diff --git a/halo2_gadgets/src/utilities.rs b/halo2_gadgets/src/utilities.rs deleted file mode 100644 index 50d939b055..0000000000 --- a/halo2_gadgets/src/utilities.rs +++ /dev/null @@ -1,497 +0,0 @@ -//! Utility gadgets. - -use ff::{Field, PrimeField, PrimeFieldBits}; -use halo2_proofs::{ - circuit::{AssignedCell, Cell, Layouter, Value}, - plonk::{Advice, Column, Error, Expression}, -}; -use std::marker::PhantomData; -use std::ops::Range; - -pub mod cond_swap; -pub mod decompose_running_sum; -pub mod lookup_range_check; - -/// A type that has a value at either keygen or proving time. -pub trait FieldValue { - /// Returns the value of this type. - fn value(&self) -> Value<&F>; -} - -impl FieldValue for Value { - fn value(&self) -> Value<&F> { - self.as_ref() - } -} - -impl FieldValue for AssignedCell { - fn value(&self) -> Value<&F> { - self.value() - } -} - -/// Trait for a variable in the circuit. -pub trait Var: Clone + std::fmt::Debug + From> { - /// The cell at which this variable was allocated. - fn cell(&self) -> Cell; - - /// The value allocated to this variable. - fn value(&self) -> Value; -} - -impl Var for AssignedCell { - fn cell(&self) -> Cell { - self.cell() - } - - fn value(&self) -> Value { - self.value().cloned() - } -} - -/// Trait for utilities used across circuits. -pub trait UtilitiesInstructions { - /// Variable in the circuit. - type Var: Var; - - /// Load a variable. - fn load_private( - &self, - mut layouter: impl Layouter, - column: Column, - value: Value, - ) -> Result { - layouter.assign_region( - || "load private", - |mut region| { - region - .assign_advice(|| "load private", column, 0, || value) - .map(Self::Var::from) - }, - ) - } -} - -/// A type representing a range-constrained field element. -#[derive(Clone, Copy, Debug)] -pub struct RangeConstrained> { - inner: T, - num_bits: usize, - _phantom: PhantomData, -} - -impl> RangeConstrained { - /// Returns the range-constrained inner type. - pub fn inner(&self) -> &T { - &self.inner - } - - /// Returns the number of bits to which this cell is constrained. - pub fn num_bits(&self) -> usize { - self.num_bits - } -} - -impl RangeConstrained> { - /// Constructs a `RangeConstrained>` as a bitrange of the given value. - pub fn bitrange_of(value: Value<&F>, bitrange: Range) -> Self { - let num_bits = bitrange.len(); - Self { - inner: value.map(|value| bitrange_subset(value, bitrange)), - num_bits, - _phantom: PhantomData, - } - } -} - -impl RangeConstrained> { - /// Constructs a `RangeConstrained>` without verifying that the - /// cell is correctly range constrained. - /// - /// This API only exists to ease with integrating this type into existing circuits, - /// and will likely be removed in future. - pub fn unsound_unchecked(cell: AssignedCell, num_bits: usize) -> Self { - Self { - inner: cell, - num_bits, - _phantom: PhantomData, - } - } - - /// Extracts the range-constrained value from this range-constrained cell. - pub fn value(&self) -> RangeConstrained> { - RangeConstrained { - inner: self.inner.value().copied(), - num_bits: self.num_bits, - _phantom: PhantomData, - } - } -} - -/// Checks that an expression is either 1 or 0. -pub fn bool_check(value: Expression) -> Expression { - range_check(value, 2) -} - -/// If `a` then `b`, else `c`. Returns (a * b) + (1 - a) * c. -/// -/// `a` must be a boolean-constrained expression. -pub fn ternary(a: Expression, b: Expression, c: Expression) -> Expression { - let one_minus_a = Expression::Constant(F::ONE) - a.clone(); - a * b + one_minus_a * c -} - -/// Takes a specified subsequence of the little-endian bit representation of a field element. -/// The bits are numbered from 0 for the LSB. -pub fn bitrange_subset(field_elem: &F, bitrange: Range) -> F { - // We can allow a subsequence of length NUM_BITS, because - // field_elem.to_le_bits() returns canonical bitstrings. - assert!(bitrange.end <= F::NUM_BITS as usize); - - field_elem - .to_le_bits() - .iter() - .by_vals() - .skip(bitrange.start) - .take(bitrange.end - bitrange.start) - .rev() - .fold(F::ZERO, |acc, bit| { - if bit { - acc.double() + F::ONE - } else { - acc.double() - } - }) -} - -/// Check that an expression is in the small range [0..range), -/// i.e. 0 ≤ word < range. -pub fn range_check(word: Expression, range: usize) -> Expression { - (1..range).fold(word.clone(), |acc, i| { - acc * (Expression::Constant(F::from(i as u64)) - word.clone()) - }) -} - -/// Decompose a word `alpha` into `window_num_bits` bits (little-endian) -/// For a window size of `w`, this returns [k_0, ..., k_n] where each `k_i` -/// is a `w`-bit value, and `scalar = k_0 + k_1 * w + k_n * w^n`. -/// -/// # Panics -/// -/// We are returning a `Vec` which means the window size is limited to -/// <= 8 bits. -pub fn decompose_word( - word: &F, - word_num_bits: usize, - window_num_bits: usize, -) -> Vec { - assert!(window_num_bits <= 8); - - // Pad bits to multiple of window_num_bits - let padding = (window_num_bits - (word_num_bits % window_num_bits)) % window_num_bits; - let bits: Vec = word - .to_le_bits() - .into_iter() - .take(word_num_bits) - .chain(std::iter::repeat(false).take(padding)) - .collect(); - assert_eq!(bits.len(), word_num_bits + padding); - - bits.chunks_exact(window_num_bits) - .map(|chunk| chunk.iter().rev().fold(0, |acc, b| (acc << 1) + (*b as u8))) - .collect() -} - -/// The u64 integer represented by an L-bit little-endian bitstring. -/// -/// # Panics -/// -/// Panics if the bitstring is longer than 64 bits. -pub fn lebs2ip(bits: &[bool; L]) -> u64 { - assert!(L <= 64); - bits.iter() - .enumerate() - .fold(0u64, |acc, (i, b)| acc + if *b { 1 << i } else { 0 }) -} - -/// The sequence of bits representing a u64 in little-endian order. -/// -/// # Panics -/// -/// Panics if the expected length of the sequence `NUM_BITS` exceeds -/// 64. -pub fn i2lebsp(int: u64) -> [bool; NUM_BITS] { - /// Takes in an FnMut closure and returns a constant-length array with elements of - /// type `Output`. - fn gen_const_array( - closure: impl FnMut(usize) -> Output, - ) -> [Output; LEN] { - let mut ret: [Output; LEN] = [Default::default(); LEN]; - for (bit, val) in ret.iter_mut().zip((0..LEN).map(closure)) { - *bit = val; - } - ret - } - assert!(NUM_BITS <= 64); - gen_const_array(|mask: usize| (int & (1 << mask)) != 0) -} - -#[cfg(test)] -mod tests { - use super::*; - use ff::FromUniformBytes; - use group::ff::{Field, PrimeField}; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::{FailureLocation, MockProver, VerifyFailure}, - plonk::{Any, Circuit, ConstraintSystem, Constraints, Error, Selector}, - poly::Rotation, - }; - use halo2curves::pasta::pallas; - use proptest::prelude::*; - use rand::rngs::OsRng; - use std::convert::TryInto; - use std::iter; - use uint::construct_uint; - - #[test] - fn test_range_check() { - struct MyCircuit(u8); - - impl UtilitiesInstructions for MyCircuit { - type Var = AssignedCell; - } - - #[derive(Clone)] - struct Config { - selector: Selector, - advice: Column, - } - - impl Circuit for MyCircuit { - type Config = Config; - type FloorPlanner = SimpleFloorPlanner; - #[cfg(feature = "circuit-params")] - type Params = (); - - fn without_witnesses(&self) -> Self { - MyCircuit(self.0) - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let selector = meta.selector(); - let advice = meta.advice_column(); - - meta.create_gate("range check", |meta| { - let selector = meta.query_selector(selector); - let advice = meta.query_advice(advice, Rotation::cur()); - - Constraints::with_selector(selector, Some(range_check(advice, RANGE))) - }); - - Config { selector, advice } - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - layouter.assign_region( - || "range constrain", - |mut region| { - config.selector.enable(&mut region, 0)?; - region.assign_advice( - || format!("witness {}", self.0), - config.advice, - 0, - || Value::known(pallas::Base::from(self.0 as u64)), - )?; - - Ok(()) - }, - ) - } - } - - for i in 0..8 { - let circuit: MyCircuit<8> = MyCircuit(i); - let prover = MockProver::::run(3, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - { - let circuit: MyCircuit<8> = MyCircuit(8); - let prover = MockProver::::run(3, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![VerifyFailure::ConstraintNotSatisfied { - constraint: ((0, "range check").into(), 0, "").into(), - location: FailureLocation::InRegion { - region: (0, "range constrain").into(), - offset: 0, - }, - cell_values: vec![(((Any::advice(), 0).into(), 0).into(), "0x8".to_string())], - }]) - ); - } - } - - #[allow(clippy::assign_op_pattern)] - #[allow(clippy::ptr_offset_with_cast)] - #[test] - fn test_bitrange_subset() { - let rng = OsRng; - - construct_uint! { - struct U256(4); - } - - // Subset full range. - { - let field_elem = pallas::Base::random(rng); - let bitrange = 0..(pallas::Base::NUM_BITS as usize); - let subset = bitrange_subset(&field_elem, bitrange); - assert_eq!(field_elem, subset); - } - - // Subset zero bits - { - let field_elem = pallas::Base::random(rng); - let bitrange = 0..0; - let subset = bitrange_subset(&field_elem, bitrange); - assert_eq!(pallas::Base::zero(), subset); - } - - // Closure to decompose field element into pieces using consecutive ranges, - // and check that we recover the original. - let decompose = |field_elem: pallas::Base, ranges: &[Range]| { - assert_eq!( - ranges.iter().map(|range| range.len()).sum::(), - pallas::Base::NUM_BITS as usize - ); - assert_eq!(ranges[0].start, 0); - assert_eq!(ranges.last().unwrap().end, pallas::Base::NUM_BITS as usize); - - // Check ranges are contiguous - #[allow(unused_assignments)] - { - let mut ranges = ranges.iter(); - let mut range = ranges.next().unwrap(); - if let Some(next_range) = ranges.next() { - assert_eq!(range.end, next_range.start); - range = next_range; - } - } - - let subsets = ranges - .iter() - .map(|range| bitrange_subset(&field_elem, range.clone())) - .collect::>(); - - let mut sum = subsets[0]; - let mut num_bits = 0; - for (idx, subset) in subsets.iter().skip(1).enumerate() { - // 2^num_bits - let range_shift: [u8; 32] = { - num_bits += ranges[idx].len(); - let mut range_shift = [0u8; 32]; - U256([2, 0, 0, 0]) - .pow(U256([num_bits as u64, 0, 0, 0])) - .to_little_endian(&mut range_shift); - range_shift - }; - sum += subset * pallas::Base::from_repr(range_shift).unwrap(); - } - assert_eq!(field_elem, sum); - }; - decompose(pallas::Base::random(rng), &[0..255]); - decompose(pallas::Base::random(rng), &[0..1, 1..255]); - decompose(pallas::Base::random(rng), &[0..254, 254..255]); - decompose(pallas::Base::random(rng), &[0..127, 127..255]); - decompose(pallas::Base::random(rng), &[0..128, 128..255]); - decompose( - pallas::Base::random(rng), - &[0..50, 50..100, 100..150, 150..200, 200..255], - ); - } - - prop_compose! { - fn arb_scalar()(bytes in prop::array::uniform32(0u8..)) -> pallas::Scalar { - // Instead of rejecting out-of-range bytes, let's reduce them. - let mut buf = [0; 64]; - buf[..32].copy_from_slice(&bytes); - pallas::Scalar::from_uniform_bytes(&buf) - } - } - - proptest! { - #[test] - fn test_decompose_word( - scalar in arb_scalar(), - window_num_bits in 1u8..9 - ) { - // Get decomposition into `window_num_bits` bits - let decomposed = decompose_word(&scalar, pallas::Scalar::NUM_BITS as usize, window_num_bits as usize); - - // Flatten bits - let bits = decomposed - .iter() - .flat_map(|window| (0..window_num_bits).map(move |mask| (window & (1 << mask)) != 0)); - - // Ensure this decomposition contains 256 or fewer set bits. - assert!(!bits.clone().skip(32*8).any(|b| b)); - - // Pad or truncate bits to 32 bytes - let bits: Vec = bits.chain(iter::repeat(false)).take(32*8).collect(); - - let bytes: Vec = bits.chunks_exact(8).map(|chunk| chunk.iter().rev().fold(0, |acc, b| (acc << 1) + (*b as u8))).collect(); - - // Check that original scalar is recovered from decomposition - assert_eq!(scalar, pallas::Scalar::from_repr(bytes.try_into().unwrap()).unwrap()); - } - } - - #[test] - fn lebs2ip_round_trip() { - use rand::rngs::OsRng; - - let mut rng = OsRng; - { - let int = rng.next_u64(); - assert_eq!(lebs2ip::<64>(&i2lebsp(int)), int); - } - - assert_eq!(lebs2ip::<64>(&i2lebsp(0)), 0); - assert_eq!( - lebs2ip::<64>(&i2lebsp(0xFFFFFFFFFFFFFFFF)), - 0xFFFFFFFFFFFFFFFF - ); - } - - #[test] - fn i2lebsp_round_trip() { - { - let bitstring = (0..64).map(|_| rand::random()).collect::>(); - assert_eq!( - i2lebsp::<64>(lebs2ip::<64>(&bitstring.clone().try_into().unwrap())).to_vec(), - bitstring - ); - } - - { - let bitstring = [false; 64]; - assert_eq!(i2lebsp(lebs2ip(&bitstring)), bitstring); - } - - { - let bitstring = [true; 64]; - assert_eq!(i2lebsp(lebs2ip(&bitstring)), bitstring); - } - - { - let bitstring = []; - assert_eq!(i2lebsp(lebs2ip(&bitstring)), bitstring); - } - } -} diff --git a/halo2_gadgets/src/utilities/cond_swap.rs b/halo2_gadgets/src/utilities/cond_swap.rs deleted file mode 100644 index d71b2599a7..0000000000 --- a/halo2_gadgets/src/utilities/cond_swap.rs +++ /dev/null @@ -1,296 +0,0 @@ -//! Gadget and chip for a conditional swap utility. - -use super::{bool_check, ternary, UtilitiesInstructions}; -use ff::{Field, PrimeField}; -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Selector}, - poly::Rotation, -}; -use std::marker::PhantomData; - -/// Instructions for a conditional swap gadget. -pub trait CondSwapInstructions: UtilitiesInstructions { - #[allow(clippy::type_complexity)] - /// Given an input pair (a,b) and a `swap` boolean flag, returns - /// (b,a) if `swap` is set, else (a,b) if `swap` is not set. - /// - /// The second element of the pair is required to be a witnessed - /// value, not a variable that already exists in the circuit. - fn swap( - &self, - layouter: impl Layouter, - pair: (Self::Var, Value), - swap: Value, - ) -> Result<(Self::Var, Self::Var), Error>; -} - -/// A chip implementing a conditional swap. -#[derive(Clone, Debug)] -pub struct CondSwapChip { - config: CondSwapConfig, - _marker: PhantomData, -} - -impl Chip for CondSwapChip { - type Config = CondSwapConfig; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -/// Configuration for the [`CondSwapChip`]. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CondSwapConfig { - q_swap: Selector, - a: Column, - b: Column, - a_swapped: Column, - b_swapped: Column, - swap: Column, -} - -#[cfg(test)] -impl CondSwapConfig { - pub(crate) fn a(&self) -> Column { - self.a - } -} - -impl UtilitiesInstructions for CondSwapChip { - type Var = AssignedCell; -} - -impl CondSwapInstructions for CondSwapChip { - #[allow(clippy::type_complexity)] - fn swap( - &self, - mut layouter: impl Layouter, - pair: (Self::Var, Value), - swap: Value, - ) -> Result<(Self::Var, Self::Var), Error> { - let config = self.config(); - - layouter.assign_region( - || "swap", - |mut region| { - // Enable `q_swap` selector - config.q_swap.enable(&mut region, 0)?; - - // Copy in `a` value - let a = pair.0.copy_advice(|| "copy a", &mut region, config.a, 0)?; - - // Witness `b` value - let b = region.assign_advice(|| "witness b", config.b, 0, || pair.1)?; - - // Witness `swap` value - let swap_val = swap.map(|swap| F::from(swap as u64)); - region.assign_advice(|| "swap", config.swap, 0, || swap_val)?; - - // Conditionally swap a - let a_swapped = { - let a_swapped = a - .value() - .zip(b.value()) - .zip(swap) - .map(|((a, b), swap)| if swap { b } else { a }) - .cloned(); - region.assign_advice(|| "a_swapped", config.a_swapped, 0, || a_swapped)? - }; - - // Conditionally swap b - let b_swapped = { - let b_swapped = a - .value() - .zip(b.value()) - .zip(swap) - .map(|((a, b), swap)| if swap { a } else { b }) - .cloned(); - region.assign_advice(|| "b_swapped", config.b_swapped, 0, || b_swapped)? - }; - - // Return swapped pair - Ok((a_swapped, b_swapped)) - }, - ) - } -} - -impl CondSwapChip { - /// Configures this chip for use in a circuit. - /// - /// # Side-effects - /// - /// `advices[0]` will be equality-enabled. - pub fn configure( - meta: &mut ConstraintSystem, - advices: [Column; 5], - ) -> CondSwapConfig { - let a = advices[0]; - // Only column a is used in an equality constraint directly by this chip. - meta.enable_equality(a); - - let q_swap = meta.selector(); - - let config = CondSwapConfig { - q_swap, - a, - b: advices[1], - a_swapped: advices[2], - b_swapped: advices[3], - swap: advices[4], - }; - - // TODO: optimise shape of gate for Merkle path validation - - meta.create_gate("a' = b ⋅ swap + a ⋅ (1-swap)", |meta| { - let q_swap = meta.query_selector(q_swap); - - let a = meta.query_advice(config.a, Rotation::cur()); - let b = meta.query_advice(config.b, Rotation::cur()); - let a_swapped = meta.query_advice(config.a_swapped, Rotation::cur()); - let b_swapped = meta.query_advice(config.b_swapped, Rotation::cur()); - let swap = meta.query_advice(config.swap, Rotation::cur()); - - // This checks that `a_swapped` is equal to `b` when `swap` is set, - // but remains as `a` when `swap` is not set. - let a_check = a_swapped - ternary(swap.clone(), b.clone(), a.clone()); - - // This checks that `b_swapped` is equal to `a` when `swap` is set, - // but remains as `b` when `swap` is not set. - let b_check = b_swapped - ternary(swap.clone(), a, b); - - // Check `swap` is boolean. - let bool_check = bool_check(swap); - - Constraints::with_selector( - q_swap, - [ - ("a check", a_check), - ("b check", b_check), - ("swap is bool", bool_check), - ], - ) - }); - - config - } - - /// Constructs a [`CondSwapChip`] given a [`CondSwapConfig`]. - pub fn construct(config: CondSwapConfig) -> Self { - CondSwapChip { - config, - _marker: PhantomData, - } - } -} - -#[cfg(test)] -mod tests { - use super::super::UtilitiesInstructions; - use super::{CondSwapChip, CondSwapConfig, CondSwapInstructions}; - use ff::PrimeField; - use group::ff::Field; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use halo2curves::pasta::pallas::Base; - use rand::rngs::OsRng; - - #[test] - fn cond_swap() { - #[derive(Default)] - struct MyCircuit { - a: Value, - b: Value, - swap: Value, - } - - impl Circuit for MyCircuit { - type Config = CondSwapConfig; - type FloorPlanner = SimpleFloorPlanner; - #[cfg(feature = "circuit-params")] - type Params = (); - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let advices = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - - CondSwapChip::::configure(meta, advices) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let chip = CondSwapChip::::construct(config.clone()); - - // Load the pair and the swap flag into the circuit. - let a = chip.load_private(layouter.namespace(|| "a"), config.a, self.a)?; - // Return the swapped pair. - let swapped_pair = chip.swap( - layouter.namespace(|| "swap"), - (a.clone(), self.b), - self.swap, - )?; - - self.swap - .zip(a.value().zip(self.b.as_ref())) - .zip(swapped_pair.0.value().zip(swapped_pair.1.value())) - .assert_if_known(|((swap, (a, b)), (a_swapped, b_swapped))| { - if *swap { - // Check that `a` and `b` have been swapped - (a_swapped == b) && (b_swapped == a) - } else { - // Check that `a` and `b` have not been swapped - (a_swapped == a) && (b_swapped == b) - } - }); - - Ok(()) - } - } - - let rng = OsRng; - - // Test swap case - { - let circuit: MyCircuit = MyCircuit { - a: Value::known(Base::random(rng)), - b: Value::known(Base::random(rng)), - swap: Value::known(true), - }; - let prover = MockProver::::run(3, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // Test non-swap case - { - let circuit: MyCircuit = MyCircuit { - a: Value::known(Base::random(rng)), - b: Value::known(Base::random(rng)), - swap: Value::known(false), - }; - let prover = MockProver::::run(3, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - } -} diff --git a/halo2_gadgets/src/utilities/decompose_running_sum.rs b/halo2_gadgets/src/utilities/decompose_running_sum.rs deleted file mode 100644 index 041044ffcb..0000000000 --- a/halo2_gadgets/src/utilities/decompose_running_sum.rs +++ /dev/null @@ -1,390 +0,0 @@ -//! Decomposes an $n$-bit field element $\alpha$ into $W$ windows, each window -//! being a $K$-bit word, using a running sum $z$. -//! We constrain $K \leq 3$ for this helper. -//! $$\alpha = k_0 + (2^K) k_1 + (2^{2K}) k_2 + ... + (2^{(W-1)K}) k_{W-1}$$ -//! -//! $z_0$ is initialized as $\alpha$. Each successive $z_{i+1}$ is computed as -//! $$z_{i+1} = (z_{i} - k_i) / (2^K).$$ -//! $z_W$ is constrained to be zero. -//! The difference between each interstitial running sum output is constrained -//! to be $K$ bits, i.e. -//! `range_check`($k_i$, $2^K$), -//! where -//! ```text -//! range_check(word, range) -//! = word * (1 - word) * (2 - word) * ... * ((range - 1) - word) -//! ``` -//! -//! Given that the `range_check` constraint will be toggled by a selector, in -//! practice we will have a `selector * range_check(word, range)` expression -//! of degree `range + 1`. -//! -//! This means that $2^K$ has to be at most `degree_bound - 1` in order for -//! the range check constraint to stay within the degree bound. - -use ff::PrimeFieldBits; -use halo2_proofs::{ - circuit::{AssignedCell, Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Selector}, - poly::Rotation, -}; - -use super::range_check; -use std::marker::PhantomData; - -/// The running sum $[z_0, ..., z_W]$. If created in strict mode, $z_W = 0$. -#[derive(Debug)] -pub struct RunningSum(Vec>); -impl std::ops::Deref for RunningSum { - type Target = Vec>; - - fn deref(&self) -> &Vec> { - &self.0 - } -} - -/// Configuration that provides methods for running sum decomposition. -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub struct RunningSumConfig { - q_range_check: Selector, - z: Column, - _marker: PhantomData, -} - -impl RunningSumConfig { - /// Returns the q_range_check selector of this [`RunningSumConfig`]. - pub(crate) fn q_range_check(&self) -> Selector { - self.q_range_check - } - - /// `perm` MUST include the advice column `z`. - /// - /// # Panics - /// - /// Panics if WINDOW_NUM_BITS > 3. - /// - /// # Side-effects - /// - /// `z` will be equality-enabled. - pub fn configure( - meta: &mut ConstraintSystem, - q_range_check: Selector, - z: Column, - ) -> Self { - assert!(WINDOW_NUM_BITS <= 3); - - meta.enable_equality(z); - - let config = Self { - q_range_check, - z, - _marker: PhantomData, - }; - - // https://p.z.cash/halo2-0.1:decompose-short-range - meta.create_gate("range check", |meta| { - let q_range_check = meta.query_selector(config.q_range_check); - let z_cur = meta.query_advice(config.z, Rotation::cur()); - let z_next = meta.query_advice(config.z, Rotation::next()); - // z_i = 2^{K}⋅z_{i + 1} + k_i - // => k_i = z_i - 2^{K}⋅z_{i + 1} - let word = z_cur - z_next * F::from(1 << WINDOW_NUM_BITS); - - Constraints::with_selector(q_range_check, Some(range_check(word, 1 << WINDOW_NUM_BITS))) - }); - - config - } - - /// Decompose a field element alpha that is witnessed in this helper. - /// - /// `strict` = true constrains the final running sum to be zero, i.e. - /// constrains alpha to be within WINDOW_NUM_BITS * num_windows bits. - pub fn witness_decompose( - &self, - region: &mut Region<'_, F>, - offset: usize, - alpha: Value, - strict: bool, - word_num_bits: usize, - num_windows: usize, - ) -> Result, Error> { - let z_0 = region.assign_advice(|| "z_0 = alpha", self.z, offset, || alpha)?; - self.decompose(region, offset, z_0, strict, word_num_bits, num_windows) - } - - /// Decompose an existing variable alpha that is copied into this helper. - /// - /// `strict` = true constrains the final running sum to be zero, i.e. - /// constrains alpha to be within WINDOW_NUM_BITS * num_windows bits. - pub fn copy_decompose( - &self, - region: &mut Region<'_, F>, - offset: usize, - alpha: AssignedCell, - strict: bool, - word_num_bits: usize, - num_windows: usize, - ) -> Result, Error> { - let z_0 = alpha.copy_advice(|| "copy z_0 = alpha", region, self.z, offset)?; - self.decompose(region, offset, z_0, strict, word_num_bits, num_windows) - } - - /// `z_0` must be the cell at `(self.z, offset)` in `region`. - /// - /// # Panics - /// - /// Panics if there are too many windows for the given word size. - fn decompose( - &self, - region: &mut Region<'_, F>, - offset: usize, - z_0: AssignedCell, - strict: bool, - word_num_bits: usize, - num_windows: usize, - ) -> Result, Error> { - // Make sure that we do not have more windows than required for the number - // of bits in the word. In other words, every window must contain at least - // one bit of the word (no empty windows). - // - // For example, let: - // - word_num_bits = 64 - // - WINDOW_NUM_BITS = 3 - // In this case, the maximum allowed num_windows is 22: - // 3 * 22 < 64 + 3 - // - assert!(WINDOW_NUM_BITS * num_windows < word_num_bits + WINDOW_NUM_BITS); - - // Enable selectors - for idx in 0..num_windows { - self.q_range_check.enable(region, offset + idx)?; - } - - // Decompose base field element into K-bit words. - let words = z_0 - .value() - .map(|word| super::decompose_word::(word, word_num_bits, WINDOW_NUM_BITS)) - .transpose_vec(num_windows); - - // Initialize empty vector to store running sum values [z_0, ..., z_W]. - let mut zs: Vec> = vec![z_0.clone()]; - let mut z = z_0; - - // Assign running sum `z_{i+1}` = (z_i - k_i) / (2^K) for i = 0..=n-1. - // Outside of this helper, z_0 = alpha must have already been loaded into the - // `z` column at `offset`. - let two_pow_k_inv = Value::known(F::from(1 << WINDOW_NUM_BITS as u64).invert().unwrap()); - for (i, word) in words.iter().enumerate() { - // z_next = (z_cur - word) / (2^K) - let z_next = { - let z_cur_val = z.value().copied(); - let word = word.map(|word| F::from(word as u64)); - let z_next_val = (z_cur_val - word) * two_pow_k_inv; - region.assign_advice( - || format!("z_{:?}", i + 1), - self.z, - offset + i + 1, - || z_next_val, - )? - }; - - // Update `z`. - z = z_next; - zs.push(z.clone()); - } - assert_eq!(zs.len(), num_windows + 1); - - if strict { - // Constrain the final running sum output to be zero. - region.constrain_constant(zs.last().unwrap().cell(), F::ZERO)?; - } - - Ok(RunningSum(zs)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use group::ff::{Field, PrimeField}; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::{FailureLocation, MockProver, VerifyFailure}, - plonk::{Any, Circuit, ConstraintSystem, Error}, - }; - use halo2curves::pasta::pallas; - use rand::rngs::OsRng; - - use crate::ecc::chip::{ - FIXED_BASE_WINDOW_SIZE, L_SCALAR_SHORT as L_SHORT, NUM_WINDOWS, NUM_WINDOWS_SHORT, - }; - - const L_BASE: usize = pallas::Base::NUM_BITS as usize; - - #[test] - fn test_running_sum() { - struct MyCircuit< - F: PrimeFieldBits, - const WORD_NUM_BITS: usize, - const WINDOW_NUM_BITS: usize, - const NUM_WINDOWS: usize, - > { - alpha: Value, - strict: bool, - } - - impl< - F: PrimeFieldBits, - const WORD_NUM_BITS: usize, - const WINDOW_NUM_BITS: usize, - const NUM_WINDOWS: usize, - > Circuit for MyCircuit - { - type Config = RunningSumConfig; - type FloorPlanner = SimpleFloorPlanner; - #[cfg(feature = "circuit-params")] - type Params = (); - - fn without_witnesses(&self) -> Self { - Self { - alpha: Value::unknown(), - strict: self.strict, - } - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let z = meta.advice_column(); - let q_range_check = meta.selector(); - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - RunningSumConfig::::configure(meta, q_range_check, z) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - layouter.assign_region( - || "decompose", - |mut region| { - let offset = 0; - let zs = config.witness_decompose( - &mut region, - offset, - self.alpha, - self.strict, - WORD_NUM_BITS, - NUM_WINDOWS, - )?; - let alpha = zs[0].clone(); - - let offset = offset + NUM_WINDOWS + 1; - - config.copy_decompose( - &mut region, - offset, - alpha, - self.strict, - WORD_NUM_BITS, - NUM_WINDOWS, - )?; - - Ok(()) - }, - ) - } - } - - // Random base field element - { - let alpha = pallas::Base::random(OsRng); - - // Strict full decomposition should pass. - let circuit: MyCircuit = - MyCircuit { - alpha: Value::known(alpha), - strict: true, - }; - let prover = MockProver::::run(8, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // Random 64-bit word - { - let alpha = pallas::Base::from(rand::random::()); - - // Strict full decomposition should pass. - let circuit: MyCircuit< - pallas::Base, - L_SHORT, - FIXED_BASE_WINDOW_SIZE, - { NUM_WINDOWS_SHORT }, - > = MyCircuit { - alpha: Value::known(alpha), - strict: true, - }; - let prover = MockProver::::run(8, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // 2^66 - { - let alpha = pallas::Base::from_u128(1 << 66); - - // Strict partial decomposition should fail. - let circuit: MyCircuit< - pallas::Base, - L_SHORT, - FIXED_BASE_WINDOW_SIZE, - { NUM_WINDOWS_SHORT }, - > = MyCircuit { - alpha: Value::known(alpha), - strict: true, - }; - let prover = MockProver::::run(8, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![ - VerifyFailure::Permutation { - column: (Any::Fixed, 0).into(), - location: FailureLocation::OutsideRegion { row: 0 }, - }, - VerifyFailure::Permutation { - column: (Any::Fixed, 0).into(), - location: FailureLocation::OutsideRegion { row: 1 }, - }, - VerifyFailure::Permutation { - column: (Any::advice(), 0).into(), - location: FailureLocation::InRegion { - region: (0, "decompose").into(), - offset: 22, - }, - }, - VerifyFailure::Permutation { - column: (Any::advice(), 0).into(), - location: FailureLocation::InRegion { - region: (0, "decompose").into(), - offset: 45, - }, - }, - ]) - ); - - // Non-strict partial decomposition should pass. - let circuit: MyCircuit< - pallas::Base, - { L_SHORT }, - FIXED_BASE_WINDOW_SIZE, - { NUM_WINDOWS_SHORT }, - > = MyCircuit { - alpha: Value::known(alpha), - strict: false, - }; - let prover = MockProver::::run(8, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - } -} diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs deleted file mode 100644 index 0679e202de..0000000000 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ /dev/null @@ -1,658 +0,0 @@ -//! Make use of a K-bit lookup table to decompose a field element into K-bit -//! words. - -use halo2_proofs::{ - circuit::{AssignedCell, Layouter, Region}, - plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Selector, TableColumn}, - poly::Rotation, -}; -use std::{convert::TryInto, marker::PhantomData}; - -use ff::PrimeFieldBits; - -use super::*; - -/// The running sum $[z_0, ..., z_W]$. If created in strict mode, $z_W = 0$. -#[derive(Debug)] -pub struct RunningSum(Vec>); -impl std::ops::Deref for RunningSum { - type Target = Vec>; - - fn deref(&self) -> &Vec> { - &self.0 - } -} - -impl RangeConstrained> { - /// Witnesses a subset of the bits in `value` and constrains them to be the correct - /// number of bits. - /// - /// # Panics - /// - /// Panics if `bitrange.len() >= K`. - pub fn witness_short( - lookup_config: &LookupRangeCheckConfig, - layouter: impl Layouter, - value: Value<&F>, - bitrange: Range, - ) -> Result { - let num_bits = bitrange.len(); - assert!(num_bits < K); - - // Witness the subset and constrain it to be the correct number of bits. - lookup_config - .witness_short_check( - layouter, - value.map(|value| bitrange_subset(value, bitrange)), - num_bits, - ) - .map(|inner| Self { - inner, - num_bits, - _phantom: PhantomData, - }) - } -} - -/// Configuration that provides methods for a lookup range check. -#[derive(Eq, PartialEq, Debug, Clone, Copy)] -pub struct LookupRangeCheckConfig { - q_lookup: Selector, - q_running: Selector, - q_bitshift: Selector, - running_sum: Column, - table_idx: TableColumn, - _marker: PhantomData, -} - -impl LookupRangeCheckConfig { - /// The `running_sum` advice column breaks the field element into `K`-bit - /// words. It is used to construct the input expression to the lookup - /// argument. - /// - /// The `table_idx` fixed column contains values from [0..2^K). Looking up - /// a value in `table_idx` constrains it to be within this range. The table - /// can be loaded outside this helper. - /// - /// # Side-effects - /// - /// Both the `running_sum` and `constants` columns will be equality-enabled. - pub fn configure( - meta: &mut ConstraintSystem, - running_sum: Column, - table_idx: TableColumn, - ) -> Self { - meta.enable_equality(running_sum); - - let q_lookup = meta.complex_selector(); - let q_running = meta.complex_selector(); - let q_bitshift = meta.selector(); - let config = LookupRangeCheckConfig { - q_lookup, - q_running, - q_bitshift, - running_sum, - table_idx, - _marker: PhantomData, - }; - - // https://p.z.cash/halo2-0.1:decompose-combined-lookup - meta.lookup("lookup", |meta| { - let q_lookup = meta.query_selector(config.q_lookup); - let q_running = meta.query_selector(config.q_running); - let z_cur = meta.query_advice(config.running_sum, Rotation::cur()); - - // In the case of a running sum decomposition, we recover the word from - // the difference of the running sums: - // z_i = 2^{K}⋅z_{i + 1} + a_i - // => a_i = z_i - 2^{K}⋅z_{i + 1} - let running_sum_lookup = { - let running_sum_word = { - let z_next = meta.query_advice(config.running_sum, Rotation::next()); - z_cur.clone() - z_next * F::from(1 << K) - }; - - q_running.clone() * running_sum_word - }; - - // In the short range check, the word is directly witnessed. - let short_lookup = { - let short_word = z_cur; - let q_short = Expression::Constant(F::ONE) - q_running; - - q_short * short_word - }; - - // Combine the running sum and short lookups: - vec![( - q_lookup * (running_sum_lookup + short_lookup), - config.table_idx, - )] - }); - - // For short lookups, check that the word has been shifted by the correct number of bits. - // https://p.z.cash/halo2-0.1:decompose-short-lookup - meta.create_gate("Short lookup bitshift", |meta| { - let q_bitshift = meta.query_selector(config.q_bitshift); - let word = meta.query_advice(config.running_sum, Rotation::prev()); - let shifted_word = meta.query_advice(config.running_sum, Rotation::cur()); - let inv_two_pow_s = meta.query_advice(config.running_sum, Rotation::next()); - - let two_pow_k = F::from(1 << K); - - // shifted_word = word * 2^{K-s} - // = word * 2^K * inv_two_pow_s - Constraints::with_selector( - q_bitshift, - Some(word * two_pow_k * inv_two_pow_s - shifted_word), - ) - }); - - config - } - - #[cfg(test)] - // Loads the values [0..2^K) into `table_idx`. This is only used in testing - // for now, since the Sinsemilla chip provides a pre-loaded table in the - // Orchard context. - pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_table( - || "table_idx", - |mut table| { - // We generate the row values lazily (we only need them during keygen). - for index in 0..(1 << K) { - table.assign_cell( - || "table_idx", - self.table_idx, - index, - || Value::known(F::from(index as u64)), - )?; - } - Ok(()) - }, - ) - } - - /// Range check on an existing cell that is copied into this helper. - /// - /// Returns an error if `element` is not in a column that was passed to - /// [`ConstraintSystem::enable_equality`] during circuit configuration. - pub fn copy_check( - &self, - mut layouter: impl Layouter, - element: AssignedCell, - num_words: usize, - strict: bool, - ) -> Result, Error> { - layouter.assign_region( - || format!("{:?} words range check", num_words), - |mut region| { - // Copy `element` and initialize running sum `z_0 = element` to decompose it. - let z_0 = element.copy_advice(|| "z_0", &mut region, self.running_sum, 0)?; - self.range_check(&mut region, z_0, num_words, strict) - }, - ) - } - - /// Range check on a value that is witnessed in this helper. - pub fn witness_check( - &self, - mut layouter: impl Layouter, - value: Value, - num_words: usize, - strict: bool, - ) -> Result, Error> { - layouter.assign_region( - || "Witness element", - |mut region| { - let z_0 = - region.assign_advice(|| "Witness element", self.running_sum, 0, || value)?; - self.range_check(&mut region, z_0, num_words, strict) - }, - ) - } - - /// If `strict` is set to "true", the field element must fit into - /// `num_words * K` bits. In other words, the final cumulative sum `z_{num_words}` - /// must be zero. - /// - /// If `strict` is set to "false", the final `z_{num_words}` is not constrained. - /// - /// `element` must have been assigned to `self.running_sum` at offset 0. - fn range_check( - &self, - region: &mut Region<'_, F>, - element: AssignedCell, - num_words: usize, - strict: bool, - ) -> Result, Error> { - // `num_words` must fit into a single field element. - assert!(num_words * K <= F::CAPACITY as usize); - let num_bits = num_words * K; - - // Chunk the first num_bits bits into K-bit words. - let words = { - // Take first num_bits bits of `element`. - let bits = element.value().map(|element| { - element - .to_le_bits() - .into_iter() - .take(num_bits) - .collect::>() - }); - - bits.map(|bits| { - bits.chunks_exact(K) - .map(|word| F::from(lebs2ip::(&(word.try_into().unwrap())))) - .collect::>() - }) - .transpose_vec(num_words) - }; - - let mut zs = vec![element.clone()]; - - // Assign cumulative sum such that - // z_i = 2^{K}⋅z_{i + 1} + a_i - // => z_{i + 1} = (z_i - a_i) / (2^K) - // - // For `element` = a_0 + 2^10 a_1 + ... + 2^{120} a_{12}}, initialize z_0 = `element`. - // If `element` fits in 130 bits, we end up with z_{13} = 0. - let mut z = element; - let inv_two_pow_k = F::from(1u64 << K).invert().unwrap(); - for (idx, word) in words.iter().enumerate() { - // Enable q_lookup on this row - self.q_lookup.enable(region, idx)?; - // Enable q_running on this row - self.q_running.enable(region, idx)?; - - // z_next = (z_cur - m_cur) / 2^K - z = { - let z_val = z - .value() - .zip(*word) - .map(|(z, word)| (*z - word) * inv_two_pow_k); - - // Assign z_next - region.assign_advice( - || format!("z_{:?}", idx + 1), - self.running_sum, - idx + 1, - || z_val, - )? - }; - zs.push(z.clone()); - } - - if strict { - // Constrain the final `z` to be zero. - region.constrain_constant(zs.last().unwrap().cell(), F::ZERO)?; - } - - Ok(RunningSum(zs)) - } - - /// Short range check on an existing cell that is copied into this helper. - /// - /// # Panics - /// - /// Panics if NUM_BITS is equal to or larger than K. - pub fn copy_short_check( - &self, - mut layouter: impl Layouter, - element: AssignedCell, - num_bits: usize, - ) -> Result<(), Error> { - assert!(num_bits < K); - layouter.assign_region( - || format!("Range check {:?} bits", num_bits), - |mut region| { - // Copy `element` to use in the k-bit lookup. - let element = - element.copy_advice(|| "element", &mut region, self.running_sum, 0)?; - - self.short_range_check(&mut region, element, num_bits) - }, - ) - } - - /// Short range check on value that is witnessed in this helper. - /// - /// # Panics - /// - /// Panics if num_bits is larger than K. - pub fn witness_short_check( - &self, - mut layouter: impl Layouter, - element: Value, - num_bits: usize, - ) -> Result, Error> { - assert!(num_bits <= K); - layouter.assign_region( - || format!("Range check {:?} bits", num_bits), - |mut region| { - // Witness `element` to use in the k-bit lookup. - let element = - region.assign_advice(|| "Witness element", self.running_sum, 0, || element)?; - - self.short_range_check(&mut region, element.clone(), num_bits)?; - - Ok(element) - }, - ) - } - - /// Constrain `x` to be a NUM_BITS word. - /// - /// `element` must have been assigned to `self.running_sum` at offset 0. - fn short_range_check( - &self, - region: &mut Region<'_, F>, - element: AssignedCell, - num_bits: usize, - ) -> Result<(), Error> { - // Enable lookup for `element`, to constrain it to 10 bits. - self.q_lookup.enable(region, 0)?; - - // Enable lookup for shifted element, to constrain it to 10 bits. - self.q_lookup.enable(region, 1)?; - - // Check element has been shifted by the correct number of bits. - self.q_bitshift.enable(region, 1)?; - - // Assign shifted `element * 2^{K - num_bits}` - let shifted = element.value().into_field() * F::from(1 << (K - num_bits)); - - region.assign_advice( - || format!("element * 2^({}-{})", K, num_bits), - self.running_sum, - 1, - || shifted, - )?; - - // Assign 2^{-num_bits} from a fixed column. - let inv_two_pow_s = F::from(1 << num_bits).invert().unwrap(); - region.assign_advice_from_constant( - || format!("2^(-{})", num_bits), - self.running_sum, - 2, - inv_two_pow_s, - )?; - - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::LookupRangeCheckConfig; - - use super::super::lebs2ip; - use crate::sinsemilla::primitives::K; - - use ff::{Field, PrimeFieldBits}; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::{FailureLocation, MockProver, VerifyFailure}, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use halo2curves::pasta::pallas; - - use std::{convert::TryInto, marker::PhantomData}; - - #[test] - fn lookup_range_check() { - #[derive(Clone, Copy)] - struct MyCircuit { - num_words: usize, - _marker: PhantomData, - } - - impl Circuit for MyCircuit { - type Config = LookupRangeCheckConfig; - type FloorPlanner = SimpleFloorPlanner; - #[cfg(feature = "circuit-params")] - type Params = (); - - fn without_witnesses(&self) -> Self { - *self - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let running_sum = meta.advice_column(); - let table_idx = meta.lookup_table_column(); - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - LookupRangeCheckConfig::::configure(meta, running_sum, table_idx) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Load table_idx - config.load(&mut layouter)?; - - // Lookup constraining element to be no longer than num_words * K bits. - let elements_and_expected_final_zs = [ - (F::from((1 << (self.num_words * K)) - 1), F::ZERO, true), // a word that is within self.num_words * K bits long - (F::from(1 << (self.num_words * K)), F::ONE, false), // a word that is just over self.num_words * K bits long - ]; - - fn expected_zs( - element: F, - num_words: usize, - ) -> Vec { - let chunks = { - element - .to_le_bits() - .iter() - .by_vals() - .take(num_words * K) - .collect::>() - .chunks_exact(K) - .map(|chunk| F::from(lebs2ip::(chunk.try_into().unwrap()))) - .collect::>() - }; - let expected_zs = { - let inv_two_pow_k = F::from(1 << K).invert().unwrap(); - chunks.iter().fold(vec![element], |mut zs, a_i| { - // z_{i + 1} = (z_i - a_i) / 2^{K} - let z = (zs[zs.len() - 1] - a_i) * inv_two_pow_k; - zs.push(z); - zs - }) - }; - expected_zs - } - - for (element, expected_final_z, strict) in elements_and_expected_final_zs.iter() { - let expected_zs = expected_zs::(*element, self.num_words); - - let zs = config.witness_check( - layouter.namespace(|| format!("Lookup {:?}", self.num_words)), - Value::known(*element), - self.num_words, - *strict, - )?; - - assert_eq!(*expected_zs.last().unwrap(), *expected_final_z); - - for (expected_z, z) in expected_zs.into_iter().zip(zs.iter()) { - z.value().assert_if_known(|z| &&expected_z == z); - } - } - Ok(()) - } - } - - { - let circuit: MyCircuit = MyCircuit { - num_words: 6, - _marker: PhantomData, - }; - - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - } - - #[test] - fn short_range_check() { - struct MyCircuit { - element: Value, - num_bits: usize, - } - - impl Circuit for MyCircuit { - type Config = LookupRangeCheckConfig; - type FloorPlanner = SimpleFloorPlanner; - #[cfg(feature = "circuit-params")] - type Params = (); - - fn without_witnesses(&self) -> Self { - MyCircuit { - element: Value::unknown(), - num_bits: self.num_bits, - } - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let running_sum = meta.advice_column(); - let table_idx = meta.lookup_table_column(); - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - LookupRangeCheckConfig::::configure(meta, running_sum, table_idx) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Load table_idx - config.load(&mut layouter)?; - - // Lookup constraining element to be no longer than num_bits. - config.witness_short_check( - layouter.namespace(|| format!("Lookup {:?} bits", self.num_bits)), - self.element, - self.num_bits, - )?; - - Ok(()) - } - } - - // Edge case: zero bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::zero()), - num_bits: 0, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // Edge case: K bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from((1 << K) - 1)), - num_bits: K, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // Element within `num_bits` - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from((1 << 6) - 1)), - num_bits: 6, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // Element larger than `num_bits` but within K bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from(1 << 6)), - num_bits: 6, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![VerifyFailure::Lookup { - name: "lookup".to_string(), - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 1, - }, - }]), - ); - } - - // Element larger than K bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from(1 << K)), - num_bits: 6, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![ - VerifyFailure::Lookup { - name: "lookup".to_string(), - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 0, - }, - }, - VerifyFailure::Lookup { - name: "lookup".to_string(), - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 1, - }, - }, - ]) - ); - } - - // Element which is not within `num_bits`, but which has a shifted value within - // num_bits - { - let num_bits = 6; - let shifted = pallas::Base::from((1 << num_bits) - 1); - // Recall that shifted = element * 2^{K-s} - // => element = shifted * 2^{s-K} - let element = shifted - * pallas::Base::from(1 << (K as u64 - num_bits)) - .invert() - .unwrap(); - let circuit: MyCircuit = MyCircuit { - element: Value::known(element), - num_bits: num_bits as usize, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![VerifyFailure::Lookup { - name: "lookup".to_string(), - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 0, - }, - }]) - ); - } - } -}