diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a0e962c42..2fa7d9bf2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,12 +44,25 @@ jobs: *.md !PULL_REQUEST_TEMPLATE.md + - name: Verify generated Falcon NTT sources + run: | + python3 scripts/falcon_512/generate_ntt.py --write + git diff --exit-code -- packages/account/src/falcon_512/ntt + - name: Cairo lint run: scarb fmt --check --workspace - name: Run tests run: snforge test --workspace --features fuzzing --fuzzer-runs 200 + - name: Run Falcon release-profile tests + run: | + snforge test -p openzeppelin_account --release --features falcon_fast_tests falcon_512 --max-n-steps 100000000 + snforge test -p openzeppelin_presets --release --features falcon_presets_tests falcon_512 --max-n-steps 100000000 + + - name: Build release-profile presets + run: scarb --release build -p openzeppelin_presets + - name: Run tests and generate coverage report run: snforge test --workspace --coverage diff --git a/CHANGELOG.md b/CHANGELOG.md index f7925ec18..4a29b97dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- `Falcon512AccountComponent`, SHAKE-256 hint and direct verifier strategies, + `Falcon512ShakeAccountUpgradeable` and `Falcon512ShakeDirectAccountUpgradeable` presets with SRC9 + and class upgrades, and felt-array deployment and public-key interfaces for Falcon-512 accounts + (#1730) - `SafeERC20DispatcherTrait` in `openzeppelin_token::erc20::utils` with `assert_transfer`, `assert_transfer_from`, `assert_increase_allowance`, and `assert_decrease_allowance` (#1683) ### Changed (Breaking) diff --git a/Scarb.lock b/Scarb.lock index ebba35f2c..cc3ff6a41 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -39,6 +39,7 @@ dependencies = [ name = "openzeppelin_account" version = "4.0.0-alpha.1" dependencies = [ + "openzeppelin_corelib_imports", "openzeppelin_interfaces", "openzeppelin_introspection", "openzeppelin_test_common", @@ -47,6 +48,10 @@ dependencies = [ "snforge_std", ] +[[package]] +name = "openzeppelin_corelib_imports" +version = "4.0.0-alpha.1" + [[package]] name = "openzeppelin_finance" version = "4.0.0-alpha.1" diff --git a/Scarb.toml b/Scarb.toml index 89c6376cc..1d0a86a5a 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -2,6 +2,7 @@ members = [ "packages/access", "packages/account", + "packages/corelib_imports", "packages/finance", "packages/interfaces", "packages/governance", diff --git a/packages/account/README.md b/packages/account/README.md index c7e1dfa09..eb80ba001 100644 --- a/packages/account/README.md +++ b/packages/account/README.md @@ -2,21 +2,71 @@ > **NOTE:** This document is better viewed at [https://docs.openzeppelin.com/contracts-cairo/api/account](https://docs.openzeppelin.com/contracts-cairo/3.x/api/account) -This crate provides components to implement account contracts that can be used for interacting with the network. +This crate provides components for building account contracts that interact with the network. -- `Account` validates transactions from signatures over the -[STARK Curve](https://docs.starknet.io/architecture-and-concepts/cryptography/#the_stark_curve). +- `AccountComponent` validates transactions from signatures over the + [STARK Curve](https://docs.starknet.io/architecture-and-concepts/cryptography/#the_stark_curve). -- `EthAccount` validates transactions from signatures over the -[Secp256k1 curve](https://en.bitcoin.it/wiki/Secp256k1). +- `EthAccountComponent` validates transactions from signatures over the + [Secp256k1 curve](https://en.bitcoin.it/wiki/Secp256k1). + +- `Falcon512AccountComponent` provides felt-array public-key management and account behavior for + canonical Falcon-512 public keys. It is generic over `Falcon512SignatureVerifier` and supports + two supplied SHAKE-256 strategies: + + - `Falcon512ShakeVerifier` validates a 60-felt signature containing a verifier-checked + polynomial-product hint to reduce on-chain execution cost. + + - `Falcon512ShakeDirectVerifier` validates a 31-felt signature and recomputes the polynomial + product on-chain. + +> **WARNING:** The supplied Falcon verifiers target the verification relation and SHAKE-256 +> hash-to-point from the FALCON submission selected by NIST. Their public-key and signature +> encodings are contract-specific, and they are not FN-DSA (FIPS 206) implementations. + +The Falcon component implements invoke, declare, and deploy-account validation, +signature validation, and owner-authorized felt-array public-key management. Contracts embed it +with `SRC5Component` and one of the supplied verifier strategies. Ready-to-deploy variants with +SRC9 outside execution and class upgrades are provided by the `openzeppelin_presets` package. + +Falcon accounts support owner-authorized key rotation by executing a self-call to +`set_public_key` or `setPublicKey`. As with the STARK-curve and Secp256k1 accounts, the +current key authorizes the outer account transaction and the new key signs a +domain-separated ownership-acceptance message. Rotation keeps the same account address. +Because the current key authorizes the outer transaction, rotating a lost or unavailable key +requires an independent recovery mechanism. The upgradeable presets can adopt verifier changes at +the same account address through a self-authorized class upgrade. + +### Build profile + +Build deployable Falcon preset artifacts from this repository with +`scarb --release build -p openzeppelin_presets`. The workspace dev profile produces Falcon Sierra +artifacts that cannot be lowered to CASM. Only the workspace's `target/release` Falcon preset +artifacts are suitable for declaration. A consuming project that embeds the component must +likewise use a declaration profile with inlining enabled. + +### Maintainer workflow: generated Falcon NTT sources + +The Falcon root tables, bit-reversal table, and unrolled production transform are derived and +checked by `scripts/falcon_512/generate_ntt.py`. Regenerate them from the repository root and verify +the checked-in output with: + +```sh +python3 scripts/falcon_512/generate_ntt.py --write +git diff --exit-code -- packages/account/src/falcon_512/ntt +``` ### Interfaces - [`ISRC6`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/account#ISRC6) +- [`IFeltArrayDeployable`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/account#IFeltArrayDeployable) +- [`IFeltArrayPublicKey`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/account#IFeltArrayPublicKey) +- [`IFeltArrayPublicKeyCamel`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/account#IFeltArrayPublicKeyCamel) - [`ISRC9_V2`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/account#ISRC9_V2) ### Components - [`AccountComponent`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/account#AccountComponent) - [`EthAccountComponent`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/account#EthAccountComponent) +- [`Falcon512AccountComponent`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/account#Falcon512AccountComponent) - [`SRC9Component`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/account#SRC9Component) diff --git a/packages/account/Scarb.toml b/packages/account/Scarb.toml index c0e826d07..de50c8916 100644 --- a/packages/account/Scarb.toml +++ b/packages/account/Scarb.toml @@ -24,6 +24,7 @@ scarb.workspace = true [dependencies] starknet.workspace = true +openzeppelin_corelib_imports = { path = "../corelib_imports" } openzeppelin_introspection = { path = "../introspection" } openzeppelin_interfaces = { path = "../interfaces" } openzeppelin_utils = { path = "../utils" } @@ -36,6 +37,8 @@ openzeppelin_test_common = { path = "../test_common" } [features] fuzzing = [] +# Enables tests for the generated production NTT path; requires the release compiler profile. +falcon_fast_tests = [] [lib] diff --git a/packages/account/src/falcon_512.cairo b/packages/account/src/falcon_512.cairo new file mode 100644 index 000000000..9bd950335 --- /dev/null +++ b/packages/account/src/falcon_512.cairo @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (account/src/falcon_512.cairo) + +//! Falcon-512 SHAKE account component and verifier strategies. +//! +//! `Falcon512ShakeVerifier` validates the FALCON submission relation with a verifier-checked +//! polynomial-product hint that reduces on-chain execution cost. `Falcon512ShakeDirectVerifier` +//! recomputes the product on-chain. Both strategies use SHAKE-256 hash-to-point and +//! contract-specific felt encodings; they are not FN-DSA (FIPS 206) implementations. +//! +//! `Falcon512AccountComponent` provides SRC6 account behavior and owner-authorized key rotation +//! for canonical packed Falcon-512 public keys. Ready-to-deploy compositions are provided by the +//! `openzeppelin_presets` package. + +pub mod account; +pub(crate) mod falcon; +pub(crate) mod hashing; +pub(crate) mod ntt; +pub(crate) mod packing; +pub mod verifier; +pub mod verifier_impls; +pub(crate) mod zq; + +pub use account::Falcon512AccountComponent; +pub use verifier::Falcon512SignatureVerifier; +pub use verifier_impls::{Falcon512ShakeDirectVerifier, Falcon512ShakeVerifier}; diff --git a/packages/account/src/falcon_512/account.cairo b/packages/account/src/falcon_512/account.cairo new file mode 100644 index 000000000..767bb8cc4 --- /dev/null +++ b/packages/account/src/falcon_512/account.cairo @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (account/src/falcon_512/account.cairo) + +use super::verifier::Falcon512SignatureVerifier; + +/// # Falcon512Account Component +/// +/// The Falcon512Account component enables contracts to behave as accounts using canonical +/// 29-felt NTT-domain Falcon-512 public keys. Embedding contracts select an implementation of +/// `Falcon512SignatureVerifier`. +#[starknet::component] +pub mod Falcon512AccountComponent { + use core::hash::{HashStateExTrait, HashStateTrait}; + use core::num::traits::Zero; + use core::poseidon::{PoseidonTrait, poseidon_hash_span}; + use openzeppelin_interfaces::accounts as interface; + use openzeppelin_introspection::src5::SRC5Component; + use openzeppelin_introspection::src5::SRC5Component::{ + InternalTrait as SRC5InternalTrait, SRC5Impl, + }; + use openzeppelin_utils::execution::execute_single_call; + use starknet::account::Call; + use starknet::storage::{ + MutableVecTrait, StoragePointerReadAccess, StoragePointerWriteAccess, Vec, VecTrait, + }; + use crate::utils::is_tx_version_valid; + use super::Falcon512SignatureVerifier; + + #[storage] + pub struct Storage { + pub Falcon512Account_public_key: Vec, + } + + #[event] + #[derive(Drop, Debug, PartialEq, starknet::Event)] + pub enum Event { + OwnerAdded: OwnerAdded, + OwnerRemoved: OwnerRemoved, + } + + #[derive(Drop, Debug, PartialEq, starknet::Event)] + pub struct OwnerAdded { + #[key] + pub new_owner_guid: felt252, + } + + #[derive(Drop, Debug, PartialEq, starknet::Event)] + pub struct OwnerRemoved { + #[key] + pub removed_owner_guid: felt252, + } + + pub mod Errors { + pub const INVALID_CALLER: felt252 = 'Falcon512: invalid caller'; + pub const INVALID_PUBLIC_KEY: felt252 = 'Falcon512: invalid public key'; + pub const INVALID_SIGNATURE: felt252 = 'Falcon512: invalid signature'; + pub const INVALID_TX_VERSION: felt252 = 'Falcon512: invalid tx version'; + pub const UNAUTHORIZED: felt252 = 'Falcon512: unauthorized'; + } + + // + // External + // + + #[embeddable_as(SRC6Impl)] + impl SRC6< + TContractState, + impl Verifier: Falcon512SignatureVerifier, + +HasComponent, + +SRC5Component::HasComponent, + +Drop, + > of interface::ISRC6> { + /// Executes a list of calls from the account. + /// + /// Requirements: + /// + /// - The transaction version must be greater than or equal to `MIN_TRANSACTION_VERSION`. + /// - If the transaction is a simulation (version >= `QUERY_OFFSET`), it must be + /// greater than or equal to `QUERY_OFFSET` + `MIN_TRANSACTION_VERSION`. + fn __execute__(self: @ComponentState, calls: Array) { + // Avoid calls from other contracts + // https://github.com/OpenZeppelin/cairo-contracts/issues/344 + let sender = starknet::get_caller_address(); + assert(sender.is_zero(), Errors::INVALID_CALLER); + assert(is_tx_version_valid(), Errors::INVALID_TX_VERSION); + + for call in calls.span() { + execute_single_call(call); + } + } + + /// Verifies the validity of the signature for the current transaction. + /// This function is used by the protocol to verify `invoke` transactions. + fn __validate__(self: @ComponentState, calls: Array) -> felt252 { + self.validate_transaction::() + } + + /// Verifies that the given signature is valid for the given hash. + fn is_valid_signature( + self: @ComponentState, hash: felt252, signature: Array, + ) -> felt252 { + if Verifier::verify(hash, self.read_public_key().span(), signature.span()) { + starknet::VALIDATED + } else { + 0 + } + } + } + + #[embeddable_as(DeclarerImpl)] + impl Declarer< + TContractState, + impl Verifier: Falcon512SignatureVerifier, + +HasComponent, + +SRC5Component::HasComponent, + +Drop, + > of interface::IDeclarer> { + /// Verifies the validity of the signature for the current transaction. + /// This function is used by the protocol to verify `declare` transactions. + fn __validate_declare__( + self: @ComponentState, class_hash: felt252, + ) -> felt252 { + self.validate_transaction::() + } + } + + #[embeddable_as(DeployableImpl)] + impl Deployable< + TContractState, + impl Verifier: Falcon512SignatureVerifier, + +HasComponent, + +SRC5Component::HasComponent, + +Drop, + > of interface::IFeltArrayDeployable> { + /// Verifies the validity of the signature for the current transaction. + /// This function is used by the protocol to verify `deploy_account` transactions. + fn __validate_deploy__( + self: @ComponentState, + class_hash: felt252, + contract_address_salt: felt252, + public_key: Array, + ) -> felt252 { + self.validate_transaction::() + } + } + + #[embeddable_as(PublicKeyImpl)] + impl PublicKey< + TContractState, + impl Verifier: Falcon512SignatureVerifier, + +HasComponent, + +SRC5Component::HasComponent, + +Drop, + > of interface::IFeltArrayPublicKey> { + /// Returns the current packed Falcon-512 public key. + fn get_public_key(self: @ComponentState) -> Array { + self.read_public_key() + } + + /// Sets the public key to a canonical packed Falcon-512 public key. + /// + /// Requirements: + /// + /// - The caller must be the contract itself. + /// - The new public key must use the canonical 29-felt encoding. + /// - The signature must prove acceptance by the new owner. + /// + /// Emits both an `OwnerRemoved` and an `OwnerAdded` event. + fn set_public_key( + ref self: ComponentState, + new_public_key: Array, + signature: Span, + ) { + self.assert_only_self(); + assert( + Verifier::is_valid_public_key(new_public_key.span()), Errors::INVALID_PUBLIC_KEY, + ); + + let current_public_key = self.read_public_key(); + let removed_owner_guid = poseidon_hash_span(current_public_key.span()); + let current_owner = current_public_key.span(); + let new_owner = new_public_key.span(); + self.assert_valid_new_owner::(current_owner, new_owner, signature); + + self.emit(OwnerRemoved { removed_owner_guid }); + self._set_public_key(new_public_key); + } + } + + /// Adds camelCase support for `ISRC6`. + #[embeddable_as(SRC6CamelOnlyImpl)] + impl SRC6CamelOnly< + TContractState, + impl Verifier: Falcon512SignatureVerifier, + +HasComponent, + +SRC5Component::HasComponent, + +Drop, + > of interface::ISRC6CamelOnly> { + fn isValidSignature( + self: @ComponentState, hash: felt252, signature: Array, + ) -> felt252 { + SRC6::is_valid_signature(self, hash, signature) + } + } + + /// Adds camelCase support for `IFeltArrayPublicKey`. + #[embeddable_as(PublicKeyCamelImpl)] + impl PublicKeyCamel< + TContractState, + impl Verifier: Falcon512SignatureVerifier, + +HasComponent, + +SRC5Component::HasComponent, + +Drop, + > of interface::IFeltArrayPublicKeyCamel> { + fn getPublicKey(self: @ComponentState) -> Array { + self.read_public_key() + } + + fn setPublicKey( + ref self: ComponentState, + newPublicKey: Array, + signature: Span, + ) { + PublicKey::set_public_key(ref self, newPublicKey, signature); + } + } + + #[embeddable_as(Falcon512AccountMixinImpl)] + impl Falcon512AccountMixin< + TContractState, + impl Verifier: Falcon512SignatureVerifier, + +HasComponent, + impl SRC5: SRC5Component::HasComponent, + +Drop, + > of interface::FeltArrayAccountABI> { + // ISRC6 + fn __execute__(self: @ComponentState, calls: Array) { + SRC6::__execute__(self, calls) + } + + fn __validate__(self: @ComponentState, calls: Array) -> felt252 { + SRC6::__validate__(self, calls) + } + + fn is_valid_signature( + self: @ComponentState, hash: felt252, signature: Array, + ) -> felt252 { + SRC6::is_valid_signature(self, hash, signature) + } + + // ISRC6CamelOnly + fn isValidSignature( + self: @ComponentState, hash: felt252, signature: Array, + ) -> felt252 { + SRC6CamelOnly::isValidSignature(self, hash, signature) + } + + // IDeclarer + fn __validate_declare__( + self: @ComponentState, class_hash: felt252, + ) -> felt252 { + Declarer::__validate_declare__(self, class_hash) + } + + // IFeltArrayDeployable + fn __validate_deploy__( + self: @ComponentState, + class_hash: felt252, + contract_address_salt: felt252, + public_key: Array, + ) -> felt252 { + Deployable::__validate_deploy__(self, class_hash, contract_address_salt, public_key) + } + + // IFeltArrayPublicKey + fn get_public_key(self: @ComponentState) -> Array { + PublicKey::get_public_key(self) + } + + fn set_public_key( + ref self: ComponentState, + new_public_key: Array, + signature: Span, + ) { + PublicKey::set_public_key(ref self, new_public_key, signature); + } + + // IFeltArrayPublicKeyCamel + fn getPublicKey(self: @ComponentState) -> Array { + PublicKeyCamel::getPublicKey(self) + } + + fn setPublicKey( + ref self: ComponentState, + newPublicKey: Array, + signature: Span, + ) { + PublicKeyCamel::setPublicKey(ref self, newPublicKey, signature); + } + + // ISRC5 + fn supports_interface( + self: @ComponentState, interface_id: felt252, + ) -> bool { + let src5 = get_dep_component!(self, SRC5); + src5.supports_interface(interface_id) + } + } + + // + // Internal + // + + #[generate_trait] + pub impl InternalImpl< + TContractState, + +HasComponent, + impl SRC5: SRC5Component::HasComponent, + +Drop, + > of InternalTrait { + /// Initializes the account with a canonical packed Falcon-512 public key and registers + /// the ISRC6 interface ID. + /// + /// Emits an `OwnerAdded` event. + fn initializer( + ref self: ComponentState, public_key: Array, + ) { + assert(Verifier::is_valid_public_key(public_key.span()), Errors::INVALID_PUBLIC_KEY); + + let mut src5_component = get_dep_component_mut!(ref self, SRC5); + src5_component.register_interface(interface::ISRC6_ID); + + self._set_public_key(public_key); + } + + /// Validates that the caller is the account itself. Otherwise it reverts. + fn assert_only_self(self: @ComponentState) { + let caller = starknet::get_caller_address(); + let self = starknet::get_contract_address(); + assert(self == caller, Errors::UNAUTHORIZED); + } + + /// Validates that `new_owner` accepted ownership of the account. + /// + /// WARNING: This function assumes that `current_owner` is the account's current owner + /// and does not validate this assumption. + /// + /// Requirements: + /// + /// - The signature must be valid for `new_owner`. + fn assert_valid_new_owner( + self: @ComponentState, + current_owner: Span, + new_owner: Span, + signature: Span, + ) { + let message_hash = PoseidonTrait::new() + .update_with('StarkNet Message') + .update_with('accept_ownership') + .update_with(starknet::get_contract_address()) + .update_with(poseidon_hash_span(current_owner)) + .finalize(); + + assert(Verifier::verify(message_hash, new_owner, signature), Errors::INVALID_SIGNATURE); + } + + /// Validates the signature for the current transaction. + /// Returns the short string `VALID` if valid, otherwise it reverts. + fn validate_transaction( + self: @ComponentState, + ) -> felt252 { + let tx_info = starknet::get_tx_info().unbox(); + assert( + Verifier::verify( + tx_info.transaction_hash, self.read_public_key().span(), tx_info.signature, + ), + Errors::INVALID_SIGNATURE, + ); + starknet::VALIDATED + } + + /// Stores `new_public_key` and emits an `OwnerAdded` event. + /// Once initialized, the stored key length is fixed; subsequent calls must provide a key + /// with the same number of felts. + /// Callers are responsible for enforcing the applicable encoding and authorization checks. + fn _set_public_key( + ref self: ComponentState, new_public_key: Array, + ) { + let new_owner_guid = poseidon_hash_span(new_public_key.span()); + let stored_len = self.Falcon512Account_public_key.len(); + + if stored_len == 0 { + for felt in new_public_key { + self.Falcon512Account_public_key.push(felt); + } + } else { + assert(stored_len == new_public_key.len().into(), Errors::INVALID_PUBLIC_KEY); + let mut index = 0; + for felt in new_public_key { + self.Falcon512Account_public_key.at(index).write(felt); + index += 1; + } + } + + self.emit(OwnerAdded { new_owner_guid }); + } + + /// Reads the stored public key into its 29-felt packed representation. + fn read_public_key(self: @ComponentState) -> Array { + let mut public_key = array![]; + let len = self.Falcon512Account_public_key.len(); + let mut index = 0; + while index != len { + public_key.append(self.Falcon512Account_public_key.at(index).read()); + index += 1; + } + public_key + } + } +} diff --git a/packages/account/src/falcon_512/falcon.cairo b/packages/account/src/falcon_512/falcon.cairo new file mode 100644 index 000000000..340846c1c --- /dev/null +++ b/packages/account/src/falcon_512/falcon.cairo @@ -0,0 +1,519 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (account/src/falcon_512/falcon.cairo) + +//! Falcon-512 signature verification. +//! +//! The hint variant accepts a signer-supplied product and verifies +//! `mul_hint = s1 * h` in `Z_q[x]/(x^512 + 1)` using two forward NTTs and a pointwise +//! equality check. It then accepts when +//! `||msg_point - mul_hint||^2 + ||s1||^2 <= SIG_BOUND_512` over centered representatives. +//! NTT bijectivity binds the accepted hint to the product determined by `s1` and `h`. +//! +//! The direct variant derives `s1 * h` on-chain as `INTT(NTT(s1) ∘ h_ntt)`. +//! +//! The verifier path decodes packed coefficients into canonical `u16` values and keeps +//! that representation through the generated NTT and norm calculation. + +use super::ntt::engine::intt; +#[cfg(test)] +#[cfg(not(feature: 'falcon_fast_tests'))] +use super::ntt::engine::ntt; +use super::ntt::falcon512::{PRODUCT_BITS, PRODUCT_BOUND_FELT, config}; +#[cfg(not(test))] +use super::ntt::falcon512_fast::ntt_falcon512_fast_u16_unchecked; +#[cfg(test)] +#[cfg(feature: 'falcon_fast_tests')] +use super::ntt::falcon512_fast::ntt_falcon512_fast_u16_unchecked; +use super::zq::{Q32, center_sq, centered_difference_sq}; + +/// Maximum squared-norm bound for the Falcon-512 submission algorithm. +pub const SIG_BOUND_512: u64 = 34034726; + +/// The Falcon modulus as a `u32` divisor. +const Q32_NZ: NonZero = 12289; + +#[cfg(not(test))] +#[inline(always)] +fn forward_ntt(values: Span) -> Array { + ntt_falcon512_fast_u16_unchecked(values) +} + +#[cfg(test)] +#[cfg(feature: 'falcon_fast_tests')] +#[inline(always)] +fn forward_ntt(values: Span) -> Array { + ntt_falcon512_fast_u16_unchecked(values) +} + +// The workspace dev profile disables inlining, and the universal Sierra compiler cannot lower +// the generated 512-value straight-line transform in that profile. Dev-profile tests use the +// equivalent generic engine; release-profile tests select the generated path with +// `falcon_fast_tests`. +#[cfg(test)] +#[cfg(not(feature: 'falcon_fast_tests'))] +fn forward_ntt(mut values: Span) -> Array { + let mut input = array![]; + while let Some(value) = values.pop_front() { + input.append((*value).into()); + } + let mut transformed = ntt(input.span(), @config()).span(); + let mut output = array![]; + while let Some(value) = transformed.pop_front() { + output.append((*value).try_into().unwrap()); + } + output +} + +#[inline(always)] +#[cfg(test)] +fn felts_to_u16(mut values: Span) -> Array { + let mut out: Array = array![]; + while let Some(value) = values.pop_front() { + out.append((*value).try_into().unwrap()); + } + out +} + +#[inline(always)] +fn product_difference(a: u16, b: u16, c: u16) -> u32 { + let a: u32 = a.into(); + let b: u32 = b.into(); + let c: u32 = c.into(); + a * b + Q32 - c +} + +#[inline(always)] +fn product_as_felt(a: u16, b: u16) -> felt252 { + let a: u32 = a.into(); + let b: u32 = b.into(); + (a * b).into() +} + +/// Verifies a signer-supplied product hint through the test-facing `felt252` wrapper. All spans +/// must have length 512 with coefficients in `[0, Q)`. +#[cfg(test)] +pub fn verify_512_with_hint( + s1: Span, h_ntt: Span, mul_hint: Span, msg_point: Span, +) -> bool { + assert(s1.len() == 512, 's1 must be 512 coeffs'); + assert(h_ntt.len() == 512, 'h_ntt must be 512 coeffs'); + assert(mul_hint.len() == 512, 'mul_hint must be 512 coeffs'); + assert(msg_point.len() == 512, 'msg_point must be 512 coeffs'); + + let s1 = felts_to_u16(s1); + let h_ntt = felts_to_u16(h_ntt); + let mul_hint = felts_to_u16(mul_hint); + verify_512_with_hint_u16(s1.span(), h_ntt.span(), mul_hint.span(), msg_point) +} + +/// Verifies the hint equation over canonical `u16` coefficients. Every span must contain exactly +/// 512 coefficients in `[0, Q)`. +pub(crate) fn verify_512_with_hint_u16( + s1: Span, h_ntt: Span, mul_hint: Span, msg_point: Span, +) -> bool { + assert(s1.len() == 512, 's1 must be 512 coeffs'); + assert(h_ntt.len() == 512, 'h_ntt must be 512 coeffs'); + assert(mul_hint.len() == 512, 'mul_hint must be 512 coeffs'); + assert(msg_point.len() == 512, 'msg_point must be 512 coeffs'); + + // Production inputs come from canonical base-Q unpacking; the test wrapper documents the same + // coefficient precondition. The generated unchecked NTT is sound for both call paths. + let s1_ntt = forward_ntt(s1); + let hint_ntt = forward_ntt(mul_hint); + + let mut s1_ntt_iter = s1_ntt.span(); + let mut hint_ntt_iter = hint_ntt.span(); + let mut h_iter = h_ntt; + let mut msg_iter = msg_point; + let mut hint_iter = mul_hint; + let mut s1_iter = s1; + + // Fused pass, 16-way unrolled (512 = 16 * 32, no remainder): hint check and + // centered-norm accumulation per coefficient. + // Max acc = 512 * 2 * 6144^2 < 2^36, so the felt252 accumulator cannot wrap + // and always fits u64. + let mut acc: felt252 = 0; + let mut ok = true; + while let Some(s1n_c) = s1_ntt_iter.multi_pop_front::<16>() { + let [ + s1n0, + s1n1, + s1n2, + s1n3, + s1n4, + s1n5, + s1n6, + s1n7, + s1n8, + s1n9, + s1n10, + s1n11, + s1n12, + s1n13, + s1n14, + s1n15, + ] = + (*s1n_c) + .unbox(); + let [hn0, hn1, hn2, hn3, hn4, hn5, hn6, hn7, hn8, hn9, hn10, hn11, hn12, hn13, hn14, hn15] = + (*hint_ntt_iter + .multi_pop_front::<16>() + .unwrap()) + .unbox(); + let [h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15] = (*h_iter + .multi_pop_front::<16>() + .unwrap()) + .unbox(); + // s1n*h + q - hn has zero remainder iff the two NTT coordinates agree mod q, + // which by bijectivity binds mul_hint to s1*h. + let (_, r0) = DivRem::div_rem(product_difference(s1n0, h0, hn0), Q32_NZ); + let (_, r1) = DivRem::div_rem(product_difference(s1n1, h1, hn1), Q32_NZ); + let (_, r2) = DivRem::div_rem(product_difference(s1n2, h2, hn2), Q32_NZ); + let (_, r3) = DivRem::div_rem(product_difference(s1n3, h3, hn3), Q32_NZ); + let (_, r4) = DivRem::div_rem(product_difference(s1n4, h4, hn4), Q32_NZ); + let (_, r5) = DivRem::div_rem(product_difference(s1n5, h5, hn5), Q32_NZ); + let (_, r6) = DivRem::div_rem(product_difference(s1n6, h6, hn6), Q32_NZ); + let (_, r7) = DivRem::div_rem(product_difference(s1n7, h7, hn7), Q32_NZ); + let (_, r8) = DivRem::div_rem(product_difference(s1n8, h8, hn8), Q32_NZ); + let (_, r9) = DivRem::div_rem(product_difference(s1n9, h9, hn9), Q32_NZ); + let (_, r10) = DivRem::div_rem(product_difference(s1n10, h10, hn10), Q32_NZ); + let (_, r11) = DivRem::div_rem(product_difference(s1n11, h11, hn11), Q32_NZ); + let (_, r12) = DivRem::div_rem(product_difference(s1n12, h12, hn12), Q32_NZ); + let (_, r13) = DivRem::div_rem(product_difference(s1n13, h13, hn13), Q32_NZ); + let (_, r14) = DivRem::div_rem(product_difference(s1n14, h14, hn14), Q32_NZ); + let (_, r15) = DivRem::div_rem(product_difference(s1n15, h15, hn15), Q32_NZ); + // Remainders are non-negative, so the sum is zero iff all sixteen are. + if r0 + + r1 + + r2 + + r3 + + r4 + + r5 + + r6 + + r7 + + r8 + + r9 + + r10 + + r11 + + r12 + + r13 + + r14 + + r15 != 0 { + ok = false; + break; + } + let [m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15] = (*msg_iter + .multi_pop_front::<16>() + .unwrap()) + .unbox(); + let [t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15] = (*hint_iter + .multi_pop_front::<16>() + .unwrap()) + .unbox(); + let [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15] = (*s1_iter + .multi_pop_front::<16>() + .unwrap()) + .unbox(); + acc += centered_difference_sq(m0, t0) + center_sq(v0); + acc += centered_difference_sq(m1, t1) + center_sq(v1); + acc += centered_difference_sq(m2, t2) + center_sq(v2); + acc += centered_difference_sq(m3, t3) + center_sq(v3); + acc += centered_difference_sq(m4, t4) + center_sq(v4); + acc += centered_difference_sq(m5, t5) + center_sq(v5); + acc += centered_difference_sq(m6, t6) + center_sq(v6); + acc += centered_difference_sq(m7, t7) + center_sq(v7); + acc += centered_difference_sq(m8, t8) + center_sq(v8); + acc += centered_difference_sq(m9, t9) + center_sq(v9); + acc += centered_difference_sq(m10, t10) + center_sq(v10); + acc += centered_difference_sq(m11, t11) + center_sq(v11); + acc += centered_difference_sq(m12, t12) + center_sq(v12); + acc += centered_difference_sq(m13, t13) + center_sq(v13); + acc += centered_difference_sq(m14, t14) + center_sq(v14); + acc += centered_difference_sq(m15, t15) + center_sq(v15); + } + if !ok { + return false; + } + let norm: u64 = acc.try_into().unwrap(); + norm <= SIG_BOUND_512 +} + +/// Verifies the direct variant by computing `s1 * h` on-chain as +/// `INTT(NTT(s1) ∘ h_ntt)`, then applying the Falcon squared-norm bound. Its signature omits the +/// 29-felt product hint and performs an inverse NTT on-chain. +#[cfg(test)] +pub fn verify_512_direct(s1: Span, h_ntt: Span, msg_point: Span) -> bool { + assert(s1.len() == 512, 's1 must be 512 coeffs'); + assert(h_ntt.len() == 512, 'h_ntt must be 512 coeffs'); + assert(msg_point.len() == 512, 'msg_point must be 512 coeffs'); + + let s1 = felts_to_u16(s1); + let h_ntt = felts_to_u16(h_ntt); + verify_512_direct_u16(s1.span(), h_ntt.span(), msg_point) +} + +/// Verifies the direct equation over canonical `u16` coefficients. +pub(crate) fn verify_512_direct_u16(s1: Span, h_ntt: Span, msg_point: Span) -> bool { + assert(s1.len() == 512, 's1 must be 512 coeffs'); + assert(h_ntt.len() == 512, 'h_ntt must be 512 coeffs'); + assert(msg_point.len() == 512, 'msg_point must be 512 coeffs'); + + let cfg = config(); + // `s1` is canonical under the verifier and test-wrapper preconditions. + let s1_ntt = forward_ntt(s1); + + // Pointwise products of two reduced inputs are below q^2. They feed the inverse + // engine unreduced under its exact product bound. + let mut prods: Array = array![]; + let mut s1n_iter = s1_ntt.span(); + let mut h_iter = h_ntt; + while let Some(s1n_c) = s1n_iter.multi_pop_front::<16>() { + let [ + s1n0, + s1n1, + s1n2, + s1n3, + s1n4, + s1n5, + s1n6, + s1n7, + s1n8, + s1n9, + s1n10, + s1n11, + s1n12, + s1n13, + s1n14, + s1n15, + ] = + (*s1n_c) + .unbox(); + let [h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15] = (*h_iter + .multi_pop_front::<16>() + .unwrap()) + .unbox(); + prods.append(product_as_felt(s1n0, h0)); + prods.append(product_as_felt(s1n1, h1)); + prods.append(product_as_felt(s1n2, h2)); + prods.append(product_as_felt(s1n3, h3)); + prods.append(product_as_felt(s1n4, h4)); + prods.append(product_as_felt(s1n5, h5)); + prods.append(product_as_felt(s1n6, h6)); + prods.append(product_as_felt(s1n7, h7)); + prods.append(product_as_felt(s1n8, h8)); + prods.append(product_as_felt(s1n9, h9)); + prods.append(product_as_felt(s1n10, h10)); + prods.append(product_as_felt(s1n11, h11)); + prods.append(product_as_felt(s1n12, h12)); + prods.append(product_as_felt(s1n13, h13)); + prods.append(product_as_felt(s1n14, h14)); + prods.append(product_as_felt(s1n15, h15)); + } + let s1h = intt(prods.span(), PRODUCT_BITS, PRODUCT_BOUND_FELT, @cfg); + + let mut s1h_iter = s1h.span(); + let mut msg_iter = msg_point; + let mut s1_iter = s1; + // Norm pass, 16-way unrolled (512 = 16 * 32, no remainder). + // Same accumulator bound argument as in `verify_512_with_hint`. + let mut acc: felt252 = 0; + while let Some(pc) = s1h_iter.multi_pop_front::<16>() { + let [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15] = (*pc).unbox(); + let [m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15] = (*msg_iter + .multi_pop_front::<16>() + .unwrap()) + .unbox(); + let [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15] = (*s1_iter + .multi_pop_front::<16>() + .unwrap()) + .unbox(); + // INTT outputs are reduced, so their u16 downcasts cannot fail. + acc += centered_difference_sq(m0, p0.try_into().unwrap()) + center_sq(v0); + acc += centered_difference_sq(m1, p1.try_into().unwrap()) + center_sq(v1); + acc += centered_difference_sq(m2, p2.try_into().unwrap()) + center_sq(v2); + acc += centered_difference_sq(m3, p3.try_into().unwrap()) + center_sq(v3); + acc += centered_difference_sq(m4, p4.try_into().unwrap()) + center_sq(v4); + acc += centered_difference_sq(m5, p5.try_into().unwrap()) + center_sq(v5); + acc += centered_difference_sq(m6, p6.try_into().unwrap()) + center_sq(v6); + acc += centered_difference_sq(m7, p7.try_into().unwrap()) + center_sq(v7); + acc += centered_difference_sq(m8, p8.try_into().unwrap()) + center_sq(v8); + acc += centered_difference_sq(m9, p9.try_into().unwrap()) + center_sq(v9); + acc += centered_difference_sq(m10, p10.try_into().unwrap()) + center_sq(v10); + acc += centered_difference_sq(m11, p11.try_into().unwrap()) + center_sq(v11); + acc += centered_difference_sq(m12, p12.try_into().unwrap()) + center_sq(v12); + acc += centered_difference_sq(m13, p13.try_into().unwrap()) + center_sq(v13); + acc += centered_difference_sq(m14, p14.try_into().unwrap()) + center_sq(v14); + acc += centered_difference_sq(m15, p15.try_into().unwrap()) + center_sq(v15); + } + let norm: u64 = acc.try_into().unwrap(); + norm <= SIG_BOUND_512 +} + +#[cfg(test)] +mod tests { + use super::super::ntt::engine::{intt, ntt}; + use super::super::ntt::falcon512::{PRODUCT_BITS, PRODUCT_BOUND_FELT, config}; + use super::super::zq::add_mod; + use super::{verify_512_direct, verify_512_with_hint}; + + fn to_u16(mut vals: Span) -> Array { + let mut out: Array = array![]; + while let Some(v) = vals.pop_front() { + out.append((*v).try_into().unwrap()); + } + out + } + + /// Negacyclic product in `Z_q[x]/(x^512 + 1)` (test helper). + fn mul_zq(f: Span, g: Span) -> Array { + let cfg = config(); + let f_ntt = ntt(f, @cfg); + let g_ntt = ntt(g, @cfg); + let mut prods: Array = array![]; + let mut fi = f_ntt.span(); + let mut gi = g_ntt.span(); + while let Some(a) = fi.pop_front() { + prods.append(*a * *gi.pop_front().unwrap()); + } + intt(prods.span(), PRODUCT_BITS, PRODUCT_BOUND_FELT, @cfg) + } + + fn pseudorandom_coeffs(seed: u64) -> Array { + let mut f: Array = array![]; + let mut state: u64 = seed; + for _ in 0_u32..512 { + state = (state * 1664525 + 1013904223) % 0x100000000; + f.append((state % 12289).into()); + } + f + } + + fn small_coeffs(seed: u64) -> Array { + // Centered coefficients in [-16, 16]: comfortably inside the norm bound. + let mut f: Array = array![]; + let mut state: u64 = seed; + for _ in 0_u32..512 { + state = (state * 1664525 + 1013904223) % 0x100000000; + let centered = state % 33; + if centered <= 16 { + f.append(centered.into()); + } else { + f.append((12289 - (centered - 16)).into()); + } + } + f + } + + /// `msg_point = s0 + prod` coefficient-wise, downcast to the norm side's `u16` form. + fn add_points(s0: Span, prod: Span) -> Array { + let mut out: Array = array![]; + let mut s0_iter = to_u16(s0).span(); + let mut prod_iter = to_u16(prod).span(); + while let Some(a) = s0_iter.pop_front() { + out.append(add_mod(*a, *prod_iter.pop_front().unwrap())); + } + out + } + + fn norm_vector(a: u16, b: u16, c: u16, d: u16) -> Array { + let mut values: Array = array![a.into(), b.into(), c.into(), d.into()]; + while values.len() != 512 { + values.append(0); + } + values + } + + // Synthetic instance built from the verification equation itself: pick small s1 and + // small s0, any h, set mul_hint = s1*h and msg_point = s0 + s1*h. A correct verifier + // must accept it, and reject once the hint or the norm side is broken. + #[test] + fn test_verify_synthetic_instance() { + let s1 = small_coeffs(1); + let s0 = small_coeffs(2); + let h = pseudorandom_coeffs(3); + let h_ntt = ntt(h.span(), @config()); + let mul_hint = mul_zq(s1.span(), h.span()); + let msg_point = add_points(s0.span(), mul_hint.span()); + assert!(verify_512_with_hint(s1.span(), h_ntt.span(), mul_hint.span(), msg_point.span())); + } + + #[test] + fn test_verify_rejects_bad_hint() { + let s1 = small_coeffs(1); + let h = pseudorandom_coeffs(3); + let h_ntt = ntt(h.span(), @config()); + let good_hint = mul_zq(s1.span(), h.span()); + // Flip one coefficient of the hint. + let mut hint_iter = good_hint.span(); + let first: u16 = (*hint_iter.pop_front().unwrap()).try_into().unwrap(); + let mut tampered: Array = array![((first + 1) % 12289).into()]; + while let Some(c) = hint_iter.pop_front() { + tampered.append(*c); + } + // msg_point = mul_hint would give norm ||s1||^2 only — accepted if hint passed. + let msg_point = to_u16(mul_zq(s1.span(), h.span()).span()); + assert!(!verify_512_with_hint(s1.span(), h_ntt.span(), tampered.span(), msg_point.span())); + } + + // The direct variant must agree with the hint variant on the same instances. + #[test] + fn test_verify_direct_synthetic_instance() { + let s1 = small_coeffs(1); + let s0 = small_coeffs(2); + let h = pseudorandom_coeffs(3); + let h_ntt = ntt(h.span(), @config()); + let prod = mul_zq(s1.span(), h.span()); + let msg_point = add_points(s0.span(), prod.span()); + assert!(verify_512_direct(s1.span(), h_ntt.span(), msg_point.span())); + // Perturb one msg_point coefficient far from the lattice point: norm blows up. + let mut bad_msg: Array = array![add_mod(*msg_point.span().at(0), 6144)]; + let mut rest = msg_point.span().slice(1, 511); + while let Some(c) = rest.pop_front() { + bad_msg.append(*c); + } + assert!(!verify_512_direct(s1.span(), h_ntt.span(), bad_msg.span())); + } + + #[test] + fn test_verify_direct_rejects_large_norm() { + let s1 = pseudorandom_coeffs(9); + let h = pseudorandom_coeffs(3); + let h_ntt = ntt(h.span(), @config()); + // msg_point = s1*h so s0 = 0; ||s1||^2 alone is far above the bound. + let msg_point = to_u16(mul_zq(s1.span(), h.span()).span()); + assert!(!verify_512_direct(s1.span(), h_ntt.span(), msg_point.span())); + } + + #[test] + fn test_verify_rejects_large_norm() { + // s1 uniformly random in [0, Q): astronomically above the centered-norm bound, + // with a consistent hint and msg_point = s1*h (so s0 = 0). + let s1 = pseudorandom_coeffs(9); + let h = pseudorandom_coeffs(3); + let h_ntt = ntt(h.span(), @config()); + let mul_hint = mul_zq(s1.span(), h.span()); + let msg_point = to_u16(mul_hint.span()); + assert!(!verify_512_with_hint(s1.span(), h_ntt.span(), mul_hint.span(), msg_point.span())); + } + + #[test] + fn test_verify_accepts_exact_norm_bound_and_rejects_next_value() { + // 34,034,726 = 5833² + 89² + 54². + let at_bound = norm_vector(5833, 89, 54, 0); + // 34,034,727 = 5833² + 103² + 15² + 2². + let over_bound = norm_vector(5833, 103, 15, 2); + let zeros = norm_vector(0, 0, 0, 0); + let message_point = to_u16(zeros.span()); + + assert!( + verify_512_with_hint(at_bound.span(), zeros.span(), zeros.span(), message_point.span()), + ); + assert!(verify_512_direct(at_bound.span(), zeros.span(), message_point.span())); + assert!( + !verify_512_with_hint( + over_bound.span(), zeros.span(), zeros.span(), message_point.span(), + ), + ); + assert!(!verify_512_direct(over_bound.span(), zeros.span(), message_point.span())); + } +} diff --git a/packages/account/src/falcon_512/hashing.cairo b/packages/account/src/falcon_512/hashing.cairo new file mode 100644 index 000000000..7c0e98c3f --- /dev/null +++ b/packages/account/src/falcon_512/hashing.cairo @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (account/src/falcon_512/hashing.cairo) + +//! SHAKE-256 primitives used to derive Falcon-512 message points. + +pub(crate) mod hash_to_point; +pub(crate) mod shake256; diff --git a/packages/account/src/falcon_512/hashing/hash_to_point.cairo b/packages/account/src/falcon_512/hashing/hash_to_point.cairo new file mode 100644 index 000000000..a772b89e5 --- /dev/null +++ b/packages/account/src/falcon_512/hashing/hash_to_point.cairo @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 +// (account/src/falcon_512/hashing/hash_to_point.cairo) + +//! SHAKE-256 hash-to-point for the Falcon-512 submission algorithm. +//! +//! The function absorbs a 40-byte salt followed by the message hash's 32-byte +//! little-endian representation. It reads the SHAKE-256 output as big-endian `u16` words +//! and rejection-samples each word into `Z_q` until it has 512 coefficients. + +use super::shake256::keccak_f1600; + +/// Rejection bound: the largest multiple of q = 12289 below 2^16. +const REJECT_BOUND: u32 = 61445; + +/// Exclusive upper bound for each 20-byte salt limb. +const TWO_POW_160: u256 = 0x10000000000000000000000000000000000000000; + +/// Hashes the 40-byte salt encoded by `(salt_a, salt_b)` and `message_hash` to +/// 512 coefficients in `[0, 12289)`. +/// +/// Returns `None` if either salt felt exceeds 20 bytes. +pub(crate) fn hash_to_point_shake_512( + message_hash: felt252, salt_a: felt252, salt_b: felt252, +) -> Option> { + let sa: u256 = salt_a.into(); + let sb: u256 = salt_b.into(); + if sa >= TWO_POW_160 || sb >= TWO_POW_160 { + return None; + } + let mh: u256 = message_hash.into(); + + // The 72-byte input fits one SHAKE-256 rate block. Bytes 0..40 hold the salt, + // bytes 40..72 hold the message hash, byte 72 is the SHAKE domain byte, and byte + // 135 is the pad10*1 terminator. + let two64: NonZero = 0x10000000000000000_u128.try_into().unwrap(); + let two32: NonZero = 0x100000000_u128.try_into().unwrap(); + let (a1, a0) = DivRem::div_rem(sa.low, two64); + let (sbq, sb0) = DivRem::div_rem(sb.low, two32); + let (sb12, l3) = DivRem::div_rem(sbq, two64); + let (m1, m0) = DivRem::div_rem(mh.low, two64); + let (m3, m2) = DivRem::div_rem(mh.high, two64); + let l2: u128 = (sa.high.into() + sb0.into() * 0x100000000).try_into().unwrap(); + let l4: u128 = (sb12.into() + sb.high.into() * 0x100000000).try_into().unwrap(); + + let mut state = keccak_f1600( + [ + a0, a1, l2, l3, l4, m0, m1, m2, m3, 0x1f, 0, 0, 0, 0, 0, 0, 0x8000000000000000, 0, 0, 0, + 0, 0, 0, 0, 0, + ], + ); + + let q32: NonZero = 12289_u32.try_into().unwrap(); + let two16: NonZero = 0x10000_u64.try_into().unwrap(); + let b256: NonZero = 0x100_u64.try_into().unwrap(); + let mut coeffs: Array = array![]; + loop { + let mut lanes = state.span().slice(0, 17); + while let Some(lane) = lanes.pop_front() { + push_lane_words(*lane, two16, b256, q32, ref coeffs); + } + if coeffs.len() == 512 { + break; + } + state = keccak_f1600(state); + } + Some(coeffs) +} + +/// Reads one squeezed lane as four big-endian `u16` candidate words. +#[inline(always)] +fn push_lane_words( + lane: u128, two16: NonZero, b256: NonZero, q32: NonZero, ref coeffs: Array, +) { + let lane64: u64 = lane.try_into().unwrap(); + let (rest, c0) = DivRem::div_rem(lane64, two16); + let (rest, c1) = DivRem::div_rem(rest, two16); + let (c3, c2) = DivRem::div_rem(rest, two16); + + let (b1, b0) = DivRem::div_rem(c0, b256); + push_candidate((b0 * 256 + b1).try_into().unwrap(), q32, ref coeffs); + let (b1, b0) = DivRem::div_rem(c1, b256); + push_candidate((b0 * 256 + b1).try_into().unwrap(), q32, ref coeffs); + let (b1, b0) = DivRem::div_rem(c2, b256); + push_candidate((b0 * 256 + b1).try_into().unwrap(), q32, ref coeffs); + let (b1, b0) = DivRem::div_rem(c3, b256); + push_candidate((b0 * 256 + b1).try_into().unwrap(), q32, ref coeffs); +} + +/// Appends `candidate mod q` when the word lies below the rejection bound and the +/// output is not complete. +#[inline(always)] +fn push_candidate(candidate: u32, q32: NonZero, ref coeffs: Array) { + if coeffs.len() != 512 && candidate < REJECT_BOUND { + let (_, remainder) = DivRem::div_rem(candidate, q32); + coeffs.append(remainder.try_into().unwrap()); + } +} + +#[cfg(test)] +mod tests { + use super::{REJECT_BOUND, TWO_POW_160, hash_to_point_shake_512, push_candidate}; + + #[test] + fn test_hash_to_point_reference_vector() { + // Independently generated with Python hashlib.shake_256 over + // salt_a[20 LE] || salt_b[20 LE] || message_hash[32 LE]. + let coefficients = hash_to_point_shake_512(3, 1, 2).unwrap(); + assert_eq!(coefficients.len(), 512); + assert_eq!( + coefficients.span().slice(0, 8), + [2750, 10132, 11472, 1877, 11061, 11208, 12103, 6446].span(), + ); + assert_eq!(coefficients.span().slice(254, 6), [937, 8133, 7551, 334, 4678, 4603].span()); + assert_eq!( + coefficients.span().slice(504, 8), + [5448, 3366, 6941, 8171, 6950, 4708, 3646, 5435].span(), + ); + } + + #[test] + fn test_hash_to_point_domain_separation() { + let base = hash_to_point_shake_512(3, 1, 2).unwrap(); + assert_ne!(base.span(), hash_to_point_shake_512(4, 1, 2).unwrap().span()); + assert_ne!(base.span(), hash_to_point_shake_512(3, 2, 1).unwrap().span()); + assert_ne!(base.span(), hash_to_point_shake_512(3, 1, 3).unwrap().span()); + } + + #[test] + fn test_hash_to_point_salt_bounds() { + let too_big: felt252 = TWO_POW_160.try_into().unwrap(); + assert!(hash_to_point_shake_512(3, too_big, 0).is_none()); + assert!(hash_to_point_shake_512(3, 0, too_big).is_none()); + assert!(hash_to_point_shake_512(3, too_big - 1, too_big - 1).is_some()); + } + + #[test] + fn test_push_candidate_accept_reject_and_complete_branches() { + let q32: NonZero = 12289_u32.try_into().unwrap(); + let mut coefficients: Array = array![]; + + push_candidate(12290, q32, ref coefficients); + assert_eq!(coefficients.span(), [1].span()); + + push_candidate(REJECT_BOUND, q32, ref coefficients); + assert_eq!(coefficients.len(), 1); + + while coefficients.len() != 512 { + coefficients.append(0); + } + push_candidate(1, q32, ref coefficients); + assert_eq!(coefficients.len(), 512); + } +} diff --git a/packages/account/src/falcon_512/hashing/shake256.cairo b/packages/account/src/falcon_512/hashing/shake256.cairo new file mode 100644 index 000000000..63cebfaf9 --- /dev/null +++ b/packages/account/src/falcon_512/hashing/shake256.cairo @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (account/src/falcon_512/hashing/shake256.cairo) + +//! Pure-Cairo SHAKE-256 extendable-output function from FIPS 202. +//! +//! This module implements the Keccak-f[1600] sponge with a 1088-bit rate, 512-bit capacity, +//! `0x1F` domain separation, and pad10*1 padding. Starknet's `keccak` syscall implements +//! Keccak-256 with `0x01` padding and a fixed 256-bit output, so this module supplies the +//! permutation required by SHAKE-256 directly. +//! +//! State: 25 lanes of 64 bits, `lane[x + 5y]`, bytes mapped little-endian per lane. +//! +//! The permutation dominates on-chain cost, so it is written flat: +//! - each round is a straight-line expression over 25 lane locals; θ is fused into the ρ+π +//! terms and ι into the first χ lane; +//! - lanes are carried as `u128`, the bitwise builtin's native operand width, so XOR/AND operate +//! directly on lane values. The `< 2^64` lane invariant is +//! maintained structurally: XOR/AND of 64-bit values is 64-bit, complements are +//! `MASK64 - b`, and rotations reassemble disjoint bit ranges below bit 64; +//! - rotations use baked-in powers of two, so a left-rotate is one `felt252` multiply and one +//! `u128` division by `2^64` via +//! `div_rem`. The wrapped high bits and the shifted low bits occupy disjoint positions, so +//! their sum is the rotation. +//! +//! `hash_to_point::hash_to_point_shake_512` uses [`keccak_f1600`] directly to consume candidates +//! from the sponge's rate lanes. A test-only byte-oriented XOF checks the permutation and sponge +//! construction against FIPS 202 known-answer vectors. + +const MASK64: u128 = 0xffffffffffffffff; +#[cfg(test)] +const RATE_LANES: u32 = 17; // 136 bytes / 8 +#[cfg(test)] +const RATE_BYTES: u32 = 136; + +/// Keccak-f[1600] round constants (FIPS 202, Table 1). +const ROUND_CONSTANTS: [u128; 24] = [ + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, + 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, + 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003, + 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a, + 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, +]; + +/// Rotates a 64-bit lane left, given `pow = 2^r` with `0 < r < 64`. The widened felt +/// product `x * 2^r < 2^127` splits at bit 64 into the bits that stay (`lo`) and the +/// bits that wrap to the bottom (`hi`); they occupy disjoint positions, so `lo + hi` +/// is the rotation. +#[inline(always)] +fn rotl(x: u128, pow: felt252, two64: NonZero) -> u128 { + let wide: u128 = (x.into() * pow).try_into().unwrap(); + let (hi, lo) = DivRem::div_rem(wide, two64); + lo + hi +} + +/// Keccak-f[1600]: 24 rounds of θ, ρ, π, χ, ι on the 25-lane state, fully unrolled +/// over lane locals. The ρ+π terms read `b[dst] = rotl(a[src] ^ d[src mod 5], ρ[dst])` +/// with the π source indices and ρ offsets from FIPS 202, precomposed per destination. +pub(crate) fn keccak_f1600(state: [u128; 25]) -> [u128; 25] { + let two64: NonZero = 0x10000000000000000_u128.try_into().unwrap(); + let mut s = state; + for rc in ROUND_CONSTANTS.span() { + let rc = *rc; + let [ + s00, + s01, + s02, + s03, + s04, + s05, + s06, + s07, + s08, + s09, + s10, + s11, + s12, + s13, + s14, + s15, + s16, + s17, + s18, + s19, + s20, + s21, + s22, + s23, + s24, + ] = + s; + + // θ: column parities and the per-column mixing term d[x] = c[x-1] ^ rotl(c[x+1], 1). + let c0 = s00 ^ s05 ^ s10 ^ s15 ^ s20; + let c1 = s01 ^ s06 ^ s11 ^ s16 ^ s21; + let c2 = s02 ^ s07 ^ s12 ^ s17 ^ s22; + let c3 = s03 ^ s08 ^ s13 ^ s18 ^ s23; + let c4 = s04 ^ s09 ^ s14 ^ s19 ^ s24; + let d0 = c4 ^ rotl(c1, 0x2, two64); + let d1 = c0 ^ rotl(c2, 0x2, two64); + let d2 = c1 ^ rotl(c3, 0x2, two64); + let d3 = c2 ^ rotl(c4, 0x2, two64); + let d4 = c3 ^ rotl(c0, 0x2, two64); + + // θ (fused) + ρ + π, straight into destination order. + let b00 = s00 ^ d0; + let b01 = rotl(s06 ^ d1, 0x100000000000, two64); + let b02 = rotl(s12 ^ d2, 0x80000000000, two64); + let b03 = rotl(s18 ^ d3, 0x200000, two64); + let b04 = rotl(s24 ^ d4, 0x4000, two64); + let b05 = rotl(s03 ^ d3, 0x10000000, two64); + let b06 = rotl(s09 ^ d4, 0x100000, two64); + let b07 = rotl(s10 ^ d0, 0x8, two64); + let b08 = rotl(s16 ^ d1, 0x200000000000, two64); + let b09 = rotl(s22 ^ d2, 0x2000000000000000, two64); + let b10 = rotl(s01 ^ d1, 0x2, two64); + let b11 = rotl(s07 ^ d2, 0x40, two64); + let b12 = rotl(s13 ^ d3, 0x2000000, two64); + let b13 = rotl(s19 ^ d4, 0x100, two64); + let b14 = rotl(s20 ^ d0, 0x40000, two64); + let b15 = rotl(s04 ^ d4, 0x8000000, two64); + let b16 = rotl(s05 ^ d0, 0x1000000000, two64); + let b17 = rotl(s11 ^ d1, 0x400, two64); + let b18 = rotl(s17 ^ d2, 0x8000, two64); + let b19 = rotl(s23 ^ d3, 0x100000000000000, two64); + let b20 = rotl(s02 ^ d2, 0x4000000000000000, two64); + let b21 = rotl(s08 ^ d3, 0x80000000000000, two64); + let b22 = rotl(s14 ^ d4, 0x8000000000, two64); + let b23 = rotl(s15 ^ d0, 0x20000000000, two64); + let b24 = rotl(s21 ^ d1, 0x4, two64); + + // χ (complement as MASK64 - b), with ι folded into lane 0. + s = + [ + b00 ^ ((MASK64 - b01) & b02) ^ rc, b01 ^ ((MASK64 - b02) & b03), + b02 ^ ((MASK64 - b03) & b04), b03 ^ ((MASK64 - b04) & b00), + b04 ^ ((MASK64 - b00) & b01), b05 ^ ((MASK64 - b06) & b07), + b06 ^ ((MASK64 - b07) & b08), b07 ^ ((MASK64 - b08) & b09), + b08 ^ ((MASK64 - b09) & b05), b09 ^ ((MASK64 - b05) & b06), + b10 ^ ((MASK64 - b11) & b12), b11 ^ ((MASK64 - b12) & b13), + b12 ^ ((MASK64 - b13) & b14), b13 ^ ((MASK64 - b14) & b10), + b14 ^ ((MASK64 - b10) & b11), b15 ^ ((MASK64 - b16) & b17), + b16 ^ ((MASK64 - b17) & b18), b17 ^ ((MASK64 - b18) & b19), + b18 ^ ((MASK64 - b19) & b15), b19 ^ ((MASK64 - b15) & b16), + b20 ^ ((MASK64 - b21) & b22), b21 ^ ((MASK64 - b22) & b23), + b22 ^ ((MASK64 - b23) & b24), b23 ^ ((MASK64 - b24) & b20), + b24 ^ ((MASK64 - b20) & b21), + ]; + } + s +} + +/// Absorbs `input` with SHAKE-256 and squeezes `out_bytes` bytes. +#[cfg(test)] +pub(crate) fn shake256(input: Array, out_bytes: u32) -> Array { + // Pad (pad10*1 with SHAKE domain 0x1F) to a multiple of the rate. + let mut padded = input; + let l = padded.len(); + let pad_len = RATE_BYTES - (l % RATE_BYTES); // in [1, RATE_BYTES] + padded.append(0x1f); + let mut z = 1; + while z != pad_len { + padded.append(0); + z += 1; + } + let last_idx = l + pad_len - 1; + let bytes = pad_ored_msb(padded, last_idx); + + // Absorb rate-sized blocks: XOR each block's 17 lanes into the state, permute. + let mut state = [0; 25]; + let n_blocks = (l + pad_len) / RATE_BYTES; + let mut blk = 0; + while blk != n_blocks { + let base = blk * RATE_BYTES; + let [ + s00, + s01, + s02, + s03, + s04, + s05, + s06, + s07, + s08, + s09, + s10, + s11, + s12, + s13, + s14, + s15, + s16, + s17, + s18, + s19, + s20, + s21, + s22, + s23, + s24, + ] = + state; + state = + keccak_f1600( + [ + s00 ^ load_lane_le(@bytes, base), s01 ^ load_lane_le(@bytes, base + 8), + s02 ^ load_lane_le(@bytes, base + 16), s03 ^ load_lane_le(@bytes, base + 24), + s04 ^ load_lane_le(@bytes, base + 32), s05 ^ load_lane_le(@bytes, base + 40), + s06 ^ load_lane_le(@bytes, base + 48), s07 ^ load_lane_le(@bytes, base + 56), + s08 ^ load_lane_le(@bytes, base + 64), s09 ^ load_lane_le(@bytes, base + 72), + s10 ^ load_lane_le(@bytes, base + 80), s11 ^ load_lane_le(@bytes, base + 88), + s12 ^ load_lane_le(@bytes, base + 96), s13 ^ load_lane_le(@bytes, base + 104), + s14 ^ load_lane_le(@bytes, base + 112), s15 ^ load_lane_le(@bytes, base + 120), + s16 ^ load_lane_le(@bytes, base + 128), s17, s18, s19, s20, s21, s22, s23, s24, + ], + ); + blk += 1; + } + + // Squeeze rate-sized blocks, permuting only when more output is needed. + let mut out: Array = array![]; + loop { + let mut lanes = state.span().slice(0, RATE_LANES); + while let Some(lane) = lanes.pop_front() { + emit_lane_le(*lane, ref out, out_bytes); + } + if out.len() == out_bytes { + break; + } + state = keccak_f1600(state); + } + out +} + +/// Appends up to 8 little-endian bytes of lane `v` (`v < 2^64`), stopping at `out_bytes`. +#[cfg(test)] +fn emit_lane_le(v: u128, ref out: Array, out_bytes: u32) { + let mut rem: u64 = v.try_into().unwrap(); + let mut k = 0; + while k != 8 && out.len() < out_bytes { + out.append((rem % 256).try_into().unwrap()); + rem = rem / 256; + k += 1; + } +} + +/// Rebuilds `bytes` with `bytes[idx] |= 0x80` (that byte is below `0x80`, so `+ 0x80`). +#[cfg(test)] +fn pad_ored_msb(bytes: Array, idx: u32) -> Array { + let mut out: Array = array![]; + let span = bytes.span(); + let mut i = 0; + while i != span.len() { + if i == idx { + out.append(*span[i] + 0x80); + } else { + out.append(*span[i]); + } + i += 1; + } + out +} + +/// Little-endian 64-bit lane from 8 bytes at `off`. +#[cfg(test)] +fn load_lane_le(bytes: @Array, off: u32) -> u128 { + let span = bytes.span(); + let mut acc: u128 = 0; + let mut k = 8; + while k != 0 { + k -= 1; + acc = acc * 256 + (*span[off + k]).into(); + } + acc +} + +#[cfg(test)] +mod tests { + use super::shake256; + + fn to_hex(bytes: Array) -> ByteArray { + let hexchars: ByteArray = "0123456789abcdef"; + let mut s: ByteArray = ""; + let mut span = bytes.span(); + while let Some(b) = span.pop_front() { + s.append_byte(hexchars.at((*b / 16).into()).unwrap()); + s.append_byte(hexchars.at((*b % 16).into()).unwrap()); + } + s + } + + // KAT vectors from Python `hashlib.shake_256` (FIPS 202). + #[test] + fn test_shake256_empty() { + let got = to_hex(shake256(array![], 32)); + assert!(got == "46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f"); + } + + #[test] + fn test_shake256_abc() { + let got = to_hex(shake256(array![0x61, 0x62, 0x63], 32)); + assert!(got == "483366601360a8771c6863080cc4114d8db44530f8f1e1ee4f94ea37e78b5739"); + } + + // 200 bytes of 0xA3: a 2-block absorb (input > 136-byte rate). NIST SHAKE-256 vector. + #[test] + fn test_shake256_multiblock() { + let mut input: Array = array![]; + let mut i = 0; + while i != 200 { + input.append(0xa3); + i += 1; + } + let got = to_hex(shake256(input, 32)); + assert!(got == "cd8a920ed141aa0407a22d59288652e9d9f1a7ee0c1e7c1ca699424da84a904d"); + } + + // Squeeze past one rate block (137 bytes > 136): exercises the squeeze-side + // permutation. Tail bytes from Python `hashlib.shake_256(b"abc").hexdigest(137)`. + #[test] + fn test_shake256_multiblock_squeeze() { + let out = shake256(array![0x61, 0x62, 0x63], 137); + assert_eq!(out.len(), 137); + // First bytes match the 32-byte KAT above. + assert_eq!(*out.at(0), 0x48); + assert_eq!(*out.at(1), 0x33); + // Bytes 128.. of the stream: e8 a2 d7 ec 71 a7 cc 29 cf (last is out[136]). + let tail: [u8; 9] = [0xe8, 0xa2, 0xd7, 0xec, 0x71, 0xa7, 0xcc, 0x29, 0xcf]; + let mut i: u32 = 128; + for expected in tail.span() { + assert_eq!(*out.at(i), *expected); + i += 1; + } + } +} diff --git a/packages/account/src/falcon_512/ntt.cairo b/packages/account/src/falcon_512/ntt.cairo new file mode 100644 index 000000000..688cf5258 --- /dev/null +++ b/packages/account/src/falcon_512/ntt.cairo @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (account/src/falcon_512/ntt.cairo) + +//! Number-theoretic transform implementation used by the Falcon-512 verifiers. + +pub(crate) mod bitrev; +pub(crate) mod engine; +pub(crate) mod falcon512; +pub(crate) mod falcon512_fast; +pub(crate) mod roots_felt; +pub(crate) mod roots_scaled; diff --git a/packages/account/src/falcon_512/ntt/bitrev.cairo b/packages/account/src/falcon_512/ntt/bitrev.cairo new file mode 100644 index 000000000..685ebcd84 --- /dev/null +++ b/packages/account/src/falcon_512/ntt/bitrev.cairo @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (account/src/falcon_512/ntt/bitrev.cairo) + +// Generated by scripts/falcon_512/generate_ntt.py; do not edit by hand. +// Self-inverse bit-reversal permutation for n = 512, used to map between +// natural coefficient order and the recursive transform's leaf order. +// Regenerate with: python3 scripts/falcon_512/generate_ntt.py --write + +//! Bit-reversal permutation table (generated). + +pub(crate) const BITREV_512: [u16; 512] = [ + 0, 256, 128, 384, 64, 320, 192, 448, 32, 288, 160, 416, 96, 352, 224, 480, 16, 272, 144, 400, + 80, 336, 208, 464, 48, 304, 176, 432, 112, 368, 240, 496, 8, 264, 136, 392, 72, 328, 200, 456, + 40, 296, 168, 424, 104, 360, 232, 488, 24, 280, 152, 408, 88, 344, 216, 472, 56, 312, 184, 440, + 120, 376, 248, 504, 4, 260, 132, 388, 68, 324, 196, 452, 36, 292, 164, 420, 100, 356, 228, 484, + 20, 276, 148, 404, 84, 340, 212, 468, 52, 308, 180, 436, 116, 372, 244, 500, 12, 268, 140, 396, + 76, 332, 204, 460, 44, 300, 172, 428, 108, 364, 236, 492, 28, 284, 156, 412, 92, 348, 220, 476, + 60, 316, 188, 444, 124, 380, 252, 508, 2, 258, 130, 386, 66, 322, 194, 450, 34, 290, 162, 418, + 98, 354, 226, 482, 18, 274, 146, 402, 82, 338, 210, 466, 50, 306, 178, 434, 114, 370, 242, 498, + 10, 266, 138, 394, 74, 330, 202, 458, 42, 298, 170, 426, 106, 362, 234, 490, 26, 282, 154, 410, + 90, 346, 218, 474, 58, 314, 186, 442, 122, 378, 250, 506, 6, 262, 134, 390, 70, 326, 198, 454, + 38, 294, 166, 422, 102, 358, 230, 486, 22, 278, 150, 406, 86, 342, 214, 470, 54, 310, 182, 438, + 118, 374, 246, 502, 14, 270, 142, 398, 78, 334, 206, 462, 46, 302, 174, 430, 110, 366, 238, 494, + 30, 286, 158, 414, 94, 350, 222, 478, 62, 318, 190, 446, 126, 382, 254, 510, 1, 257, 129, 385, + 65, 321, 193, 449, 33, 289, 161, 417, 97, 353, 225, 481, 17, 273, 145, 401, 81, 337, 209, 465, + 49, 305, 177, 433, 113, 369, 241, 497, 9, 265, 137, 393, 73, 329, 201, 457, 41, 297, 169, 425, + 105, 361, 233, 489, 25, 281, 153, 409, 89, 345, 217, 473, 57, 313, 185, 441, 121, 377, 249, 505, + 5, 261, 133, 389, 69, 325, 197, 453, 37, 293, 165, 421, 101, 357, 229, 485, 21, 277, 149, 405, + 85, 341, 213, 469, 53, 309, 181, 437, 117, 373, 245, 501, 13, 269, 141, 397, 77, 333, 205, 461, + 45, 301, 173, 429, 109, 365, 237, 493, 29, 285, 157, 413, 93, 349, 221, 477, 61, 317, 189, 445, + 125, 381, 253, 509, 3, 259, 131, 387, 67, 323, 195, 451, 35, 291, 163, 419, 99, 355, 227, 483, + 19, 275, 147, 403, 83, 339, 211, 467, 51, 307, 179, 435, 115, 371, 243, 499, 11, 267, 139, 395, + 75, 331, 203, 459, 43, 299, 171, 427, 107, 363, 235, 491, 27, 283, 155, 411, 91, 347, 219, 475, + 59, 315, 187, 443, 123, 379, 251, 507, 7, 263, 135, 391, 71, 327, 199, 455, 39, 295, 167, 423, + 103, 359, 231, 487, 23, 279, 151, 407, 87, 343, 215, 471, 55, 311, 183, 439, 119, 375, 247, 503, + 15, 271, 143, 399, 79, 335, 207, 463, 47, 303, 175, 431, 111, 367, 239, 495, 31, 287, 159, 415, + 95, 351, 223, 479, 63, 319, 191, 447, 127, 383, 255, 511, +]; + +/// The 512-entry bit-reversal permutation as a span. +pub fn bitrev_512() -> Span { + BITREV_512.span() +} diff --git a/packages/account/src/falcon_512/ntt/engine.cairo b/packages/account/src/falcon_512/ntt/engine.cairo new file mode 100644 index 000000000..068dbf00b --- /dev/null +++ b/packages/account/src/falcon_512/ntt/engine.cairo @@ -0,0 +1,358 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (account/src/falcon_512/ntt/engine.cairo) + +//! Iterative NTT engine with `felt252` lazy reduction. +//! +//! # Algorithm +//! +//! This engine computes the recursive split/merge transform used by the Falcon-512 verifier, +//! reformulated iteratively: +//! +//! - **Forward** ([`ntt`]): permute the input into recursion-leaf order (bit reversal), +//! then run merge levels bottom-up. The level merging blocks into size `2h` reads two +//! half-blocks `f0`, `f1` sequentially and appends `f0[i] ± w[i]·f1[i]` interleaved — +//! every read and write is sequential, matching Cairo's append-only arrays. The +//! permutation is fused into the first level (`h = 1`), which is also specialized: +//! its blocks are single butterflies sharing one root. +//! - **Inverse** ([`intt`]): the exact mirror — split levels top-down (reading +//! interleaved pairs, writing the two half-blocks), then one fused +//! permute-and-reduce pass back to natural order. The per-level `1/2` factor is +//! folded into the pre-scaled inverse root tables (`tinv[i] = 2^-1 · w[i]^-1 mod q`). +//! The last level (`h = 1`) writes adjacent outputs and needs no half-block buffer. +//! +//! Generic levels with `h >= 8` run 8-way unrolled over `multi_pop_front` chunks. +//! +//! # Lazy modular reduction +//! +//! Coefficients remain non-negative `felt252` integer representatives between scheduled modular +//! reduction passes. Subtractions add `off = bound · q`, a multiple of `q` that preserves each +//! residue. +//! +//! The engine tracks an exact exclusive `bound` on coefficient integers and a conservative bit +//! bound. Per forward level `bound *= q + 1`; per inverse level `bound *= 2q`. Before a level that +//! could push values to `2^126` or beyond, and once at the end, a reduction pass maps every +//! coefficient to `[0, q)` via `u128` divmod. All intermediates remain below `2^126`, well below +//! the Starknet field prime, and every reduction input fits `u128`. For the reduced and +//! pointwise-product bounds used by Falcon-512, a 512-point transform performs one intermediate +//! reduction pass and one final reduction pass. + +use core::traits::DivRem; + +/// Configuration for an NTT parameter set. `falcon512::config` returns the canonical Falcon-512 +/// configuration. +#[derive(Copy, Drop)] +pub struct NttConfig { + /// Transform size (a power of two). + pub n: u32, + /// log2(n): number of merge/split levels. + pub levels: u32, + /// The modulus, as a `u128` divisor for reduction passes. + pub q_nz: NonZero, + /// The modulus as a felt (offset construction). + pub q_felt: felt252, + /// 2^-1 mod q (even branch of the inverse split). + pub i2_felt: felt252, + /// Bit size of a reduced value: values in `[0, q)` fit `qbits` bits. + pub qbits: u32, + /// Per-forward-level bound growth, exact and in bits: `bound *= q + 1`. + pub fwd_growth_felt: felt252, + pub fwd_growth_bits: u32, + /// Per-inverse-level bound growth, exact and in bits: `bound *= 2q`. + pub inv_growth_felt: felt252, + pub inv_growth_bits: u32, + /// Leaf permutation (self-inverse bit reversal), entries < n. + pub perm: Span, + /// Merge root tables: index ℓ holds the size-2^(ℓ+1) table (length 2^ℓ). + pub merge_roots: Span>, + /// I2-prescaled inverse root tables, same indexing as `merge_roots`. + pub split_roots_scaled: Span>, +} + +/// Intermediates must stay below `2^126`, which is below the Starknet field prime, and reduction +/// inputs must fit `u128`. +const SAFE_BITS: u32 = 126; + +/// Reduces every coefficient to `[0, q)`. Inputs must be below `2^128`, as guaranteed by the +/// engine's bound schedule. The loop is 8-way unrolled. +fn reduce_pass(mut vals: Span, q_nz: NonZero) -> Array { + let mut out: Array = array![]; + while let Some(chunk) = vals.multi_pop_front::<8>() { + let [v0, v1, v2, v3, v4, v5, v6, v7] = (*chunk).unbox(); + let (_, r0) = DivRem::div_rem(TryInto::::try_into(v0).unwrap(), q_nz); + let (_, r1) = DivRem::div_rem(TryInto::::try_into(v1).unwrap(), q_nz); + let (_, r2) = DivRem::div_rem(TryInto::::try_into(v2).unwrap(), q_nz); + let (_, r3) = DivRem::div_rem(TryInto::::try_into(v3).unwrap(), q_nz); + let (_, r4) = DivRem::div_rem(TryInto::::try_into(v4).unwrap(), q_nz); + let (_, r5) = DivRem::div_rem(TryInto::::try_into(v5).unwrap(), q_nz); + let (_, r6) = DivRem::div_rem(TryInto::::try_into(v6).unwrap(), q_nz); + let (_, r7) = DivRem::div_rem(TryInto::::try_into(v7).unwrap(), q_nz); + out.append(r0.into()); + out.append(r1.into()); + out.append(r2.into()); + out.append(r3.into()); + out.append(r4.into()); + out.append(r5.into()); + out.append(r6.into()); + out.append(r7.into()); + } + while let Some(v) = vals.pop_front() { + let vu: u128 = (*v).try_into().unwrap(); + let (_, rem) = DivRem::div_rem(vu, q_nz); + out.append(rem.into()); + } + out +} + +/// One generic merge level: blocks of output size `2h`; `f0`/`f1` are each block's +/// half-spans, outputs interleave `f0[i] ± w[i]·f1[i]` (offset keeps them non-negative). +#[inline] +fn merge_level( + src: Span, roots: Span, n: u32, h: u32, off: felt252, +) -> Array { + let mut out: Array = array![]; + let mut b: u32 = 0; + if h >= 8 { + while b != n { + let mut f0 = src.slice(b, h); + let mut f1 = src.slice(b + h, h); + let mut r = roots; + while let Some(rc) = r.multi_pop_front::<8>() { + let [w0, w1, w2, w3, w4, w5, w6, w7] = (*rc).unbox(); + let [a0, a1, a2, a3, a4, a5, a6, a7] = (*f0.multi_pop_front::<8>().unwrap()) + .unbox(); + let [b0, b1, b2, b3, b4, b5, b6, b7] = (*f1.multi_pop_front::<8>().unwrap()) + .unbox(); + let t0 = w0 * b0; + out.append(a0 + t0); + out.append(a0 + off - t0); + let t1 = w1 * b1; + out.append(a1 + t1); + out.append(a1 + off - t1); + let t2 = w2 * b2; + out.append(a2 + t2); + out.append(a2 + off - t2); + let t3 = w3 * b3; + out.append(a3 + t3); + out.append(a3 + off - t3); + let t4 = w4 * b4; + out.append(a4 + t4); + out.append(a4 + off - t4); + let t5 = w5 * b5; + out.append(a5 + t5); + out.append(a5 + off - t5); + let t6 = w6 * b6; + out.append(a6 + t6); + out.append(a6 + off - t6); + let t7 = w7 * b7; + out.append(a7 + t7); + out.append(a7 + off - t7); + } + b += 2 * h; + } + } else { + while b != n { + let mut f0 = src.slice(b, h); + let mut f1 = src.slice(b + h, h); + let mut r = roots; + while let Some(w) = r.pop_front() { + let x0 = *f0.pop_front().unwrap(); + let x1 = *f1.pop_front().unwrap(); + let t = *w * x1; + out.append(x0 + t); + out.append(x0 + off - t); + } + b += 2 * h; + } + } + out +} + +/// Computes the forward NTT. `f` must hold `cfg.n` coefficients in `[0, q)`. Returns the +/// transform in the parameter set's evaluation order, reduced to `[0, q)`. +pub fn ntt(f: Span, cfg: @NttConfig) -> Array { + let (out, _, _) = ntt_core(f, cfg); + reduce_pass(out.span(), *cfg.q_nz) +} + +/// Executes the forward merge levels and returns the unreduced coefficients, their bit bound, and +/// their exclusive value bound. +#[inline(always)] +fn ntt_core(f: Span, cfg: @NttConfig) -> (Array, u32, felt252) { + let n = *cfg.n; + assert(f.len() == n, 'ntt: bad input length'); + let q_felt = *cfg.q_felt; + let q_nz = *cfg.q_nz; + let qbits = *cfg.qbits; + let growth_felt = *cfg.fwd_growth_felt; + let growth_bits = *cfg.fwd_growth_bits; + let merge_roots = *cfg.merge_roots; + + // Level h = 1, fused with the leaf permutation: block b is the single butterfly + // (f[perm[2b]], f[perm[2b+1]]), and every block shares the size-2 table's one root. + let r0 = *(*merge_roots.at(0)).at(0); + let off0 = q_felt * q_felt; // bound = q + let mut cur: Array = array![]; + let mut perm = *cfg.perm; + while let Some(pc) = perm.multi_pop_front::<2>() { + let [p0, p1] = (*pc).unbox(); + let x0 = *f.at(p0.into()); + let x1 = *f.at(p1.into()); + let t = r0 * x1; + cur.append(x0 + t); + cur.append(x0 + off0 - t); + } + let mut bits: u32 = qbits + growth_bits; + let mut bound: felt252 = q_felt * growth_felt; + + // Remaining merge levels. + let mut h: u32 = 2; + let mut level: u32 = 1; + while h != n { + if bits + growth_bits > SAFE_BITS { + cur = reduce_pass(cur.span(), q_nz); + bits = qbits; + bound = q_felt; + } + // off = bound·q: a multiple of q dominating any w·x1 (w < q, x1 < bound), so + // odd outputs stay non-negative with residues unchanged. + cur = merge_level(cur.span(), *merge_roots.at(level), n, h, bound * q_felt); + // Outputs < bound + q·bound = bound·(q+1). + bound = bound * growth_felt; + bits += growth_bits; + h = 2 * h; + level += 1; + } + (cur, bits, bound) +} + +/// One generic split level: read interleaved pairs per block of size `2h`, write the +/// even results followed by the buffered odd half-block. +#[inline] +fn split_level( + src: Span, tinv: Span, i2: felt252, n: u32, h: u32, off: felt252, +) -> Array { + let mut out: Array = array![]; + let mut b: u32 = 0; + if h >= 8 { + while b != n { + let mut pairs = src.slice(b, 2 * h); + let mut r = tinv; + let mut tmp: Array = array![]; + while let Some(rc) = r.multi_pop_front::<4>() { + let [w0, w1, w2, w3] = (*rc).unbox(); + let [x00, x01, x10, x11, x20, x21, x30, x31] = (*pairs + .multi_pop_front::<8>() + .unwrap()) + .unbox(); + out.append(i2 * (x00 + x01)); + tmp.append(w0 * x00 + off - w0 * x01); + out.append(i2 * (x10 + x11)); + tmp.append(w1 * x10 + off - w1 * x11); + out.append(i2 * (x20 + x21)); + tmp.append(w2 * x20 + off - w2 * x21); + out.append(i2 * (x30 + x31)); + tmp.append(w3 * x30 + off - w3 * x31); + } + let mut ts = tmp.span(); + while let Some(tc) = ts.multi_pop_front::<4>() { + let [t0, t1, t2, t3] = (*tc).unbox(); + out.append(t0); + out.append(t1); + out.append(t2); + out.append(t3); + } + b += 2 * h; + } + } else { + while b != n { + let mut pairs = src.slice(b, 2 * h); + let mut r = tinv; + let mut tmp: Array = array![]; + while let Some(w) = r.pop_front() { + let x0 = *pairs.pop_front().unwrap(); + let x1 = *pairs.pop_front().unwrap(); + out.append(i2 * (x0 + x1)); + tmp.append(*w * x0 + off - *w * x1); + } + let mut ts = tmp.span(); + while let Some(v) = ts.pop_front() { + out.append(*v); + } + b += 2 * h; + } + } + out +} + +/// Computes the inverse NTT. `f` must hold `cfg.n` values below `2^input_bits` (as integers), with +/// `input_bound` their exact exclusive bound: pass `(cfg.qbits, cfg.q_felt)` for +/// reduced inputs, or the product bound for unreduced pointwise products (the +/// lazy-product path: `intt(a_ntt ∘ b_ntt)` without reducing the products first). +/// Returns coefficients in natural order, reduced to `[0, q)`. +pub fn intt( + f: Span, input_bits: u32, input_bound: felt252, cfg: @NttConfig, +) -> Array { + let n = *cfg.n; + assert(f.len() == n, 'intt: bad input length'); + let q_felt = *cfg.q_felt; + let q_nz = *cfg.q_nz; + let qbits = *cfg.qbits; + let i2 = *cfg.i2_felt; + let growth_felt = *cfg.inv_growth_felt; + let growth_bits = *cfg.inv_growth_bits; + let split_roots = *cfg.split_roots_scaled; + assert(input_bits + growth_bits <= SAFE_BITS, 'intt: input too large'); + + // Split levels top-down (h = n/2 .. 2 generic; h = 1 specialized below). + let mut bits: u32 = input_bits; + let mut bound: felt252 = input_bound; + let mut cur: Array = array![]; + let mut src0 = f; + while let Some(v) = src0.pop_front() { + cur.append(*v); + } + let mut h: u32 = n / 2; + let mut level: u32 = *cfg.levels - 1; + while h != 1 { + if bits + growth_bits > SAFE_BITS { + cur = reduce_pass(cur.span(), q_nz); + bits = qbits; + bound = q_felt; + } + cur = split_level(cur.span(), *split_roots.at(level), i2, n, h, bound * q_felt); + // Both branches < 2q·bound. + bound = bound * growth_felt; + bits += growth_bits; + h = h / 2; + level -= 1; + } + + // Last level (h = 1): every block is one adjacent pair sharing the size-2 scaled + // root — outputs are adjacent too, so no half-block buffering. + if bits + growth_bits > SAFE_BITS { + cur = reduce_pass(cur.span(), q_nz); + bound = q_felt; + // No later growth decision reads `bits`; the final output is reduced unconditionally. + } + let t0 = *(*split_roots.at(0)).at(0); + let off = bound * q_felt; + let src = cur.span(); + let mut last: Array = array![]; + let mut pairs = src; + while let Some(pc) = pairs.multi_pop_front::<2>() { + let [x0, x1] = (*pc).unbox(); + last.append(i2 * (x0 + x1)); + last.append(t0 * x0 + off - t0 * x1); + } + + // Fused final pass: bit-reversal back to natural order + reduction. + let out_src = last.span(); + let mut out: Array = array![]; + let mut perm = *cfg.perm; + while let Some(p) = perm.pop_front() { + let vu: u128 = (*out_src.at((*p).into())).try_into().unwrap(); + let (_, rem) = DivRem::div_rem(vu, q_nz); + out.append(rem.into()); + } + out +} diff --git a/packages/account/src/falcon_512/ntt/falcon512.cairo b/packages/account/src/falcon_512/ntt/falcon512.cairo new file mode 100644 index 000000000..108761956 --- /dev/null +++ b/packages/account/src/falcon_512/ntt/falcon512.cairo @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (account/src/falcon_512/ntt/falcon512.cairo) + +//! Falcon parameter set for the NTT engine: `q = 12289` and negacyclic ring `(x^n + 1)`. +//! The generated root tables use the evaluation order expected by the accounts' packed +//! NTT-domain public keys. + +use super::bitrev::bitrev_512; +use super::engine::NttConfig; +use super::roots_felt::get_even_roots_felt; +use super::roots_scaled::get_scaled_inv_roots; + +/// The modulus as a non-zero `u128` divisor. +const Q_NZ: NonZero = 12289; +/// q as a felt. +pub const Q_FELT: felt252 = 12289; +/// 2^-1 mod q. +pub const I2_FELT: felt252 = 6145; +/// Reduced values are < q < 2^14. +pub const REDUCED_BITS: u32 = 14; +/// Unreduced pointwise products of two reduced values are < q^2 < 2^28. +pub const PRODUCT_BITS: u32 = 28; +/// Exclusive bound for unreduced products of two reduced values; each product fits +/// [`PRODUCT_BITS`] bits. +pub const PRODUCT_BOUND_FELT: felt252 = 151019521; + +/// Engine configuration for the production size n = 512 (table-driven permutation). +pub fn config() -> NttConfig { + config_with_perm(512, 9, bitrev_512()) +} + +/// Engine configuration for a supported power-of-two degree from 4 through 512, computing the +/// bit-reversal permutation programmatically. `levels` must equal `log2(n)`. Tests and auxiliary +/// tooling use this function; production callers use [`config`], which reads the pinned table. +pub fn config_for_degree(n: u32, levels: u32) -> NttConfig { + assert!(n >= 4 && n <= 512 && (n & (n - 1)) == 0, "config_for_degree: unsupported degree {n}"); + let mut perm: Array = array![]; + let mut i: u32 = 0; + while i != n { + let mut x = i; + let mut acc: u32 = 0; + let mut j: u32 = 0; + while j != levels { + acc = 2 * acc + (x % 2); + x = x / 2; + j += 1; + } + perm.append(acc.try_into().unwrap()); + i += 1; + } + config_with_perm(n, levels, perm.span()) +} + +fn config_with_perm(n: u32, levels: u32, perm: Span) -> NttConfig { + // Root-table spans, one per level: level ℓ merges into size 2^(ℓ+1). The tables + // are stored as felt252 constants (generated), so no per-call conversion runs. + let mut merge_roots: Array> = array![]; + let mut split_scaled: Array> = array![]; + let mut size: u32 = 2; + loop { + merge_roots.append(get_even_roots_felt(size)); + split_scaled.append(get_scaled_inv_roots(size)); + if size == n { + break; + } + size = 2 * size; + } + NttConfig { + n, + levels, + q_nz: Q_NZ, + q_felt: Q_FELT, + i2_felt: I2_FELT, + qbits: REDUCED_BITS, + fwd_growth_felt: 12290, // q + 1 + fwd_growth_bits: 14, + inv_growth_felt: 24578, // 2q + inv_growth_bits: 15, + perm, + merge_roots: merge_roots.span(), + split_roots_scaled: split_scaled.span(), + } +} diff --git a/packages/account/src/falcon_512/ntt/falcon512_fast.cairo b/packages/account/src/falcon_512/ntt/falcon512_fast.cairo new file mode 100644 index 000000000..ec0fcc16c --- /dev/null +++ b/packages/account/src/falcon_512/ntt/falcon512_fast.cairo @@ -0,0 +1,12792 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (account/src/falcon_512/ntt/falcon512_fast.cairo) + +// Generated by scripts/falcon_512/generate_ntt.py; do not edit by hand. +// Fully unrolled Falcon-512 forward NTT for n = 512 and q = 12289. +// The generator checks exact integer bounds and reduces each output once. +// Regenerate with: python3 scripts/falcon_512/generate_ntt.py --write + +//! Generated Falcon-512 forward NTT. +//! +//! Inputs are 512 coefficients in `[0, 12289)`. The unchecked entry points rely +//! on callers to enforce that precondition. Outputs are reduced to the same range. + +use openzeppelin_corelib_imports::bounded_int::{ + BoundedInt, DivRemHelper, UnitInt, bounded_int_div_rem, upcast, +}; +use openzeppelin_corelib_imports::integer::{U128sFromFelt252Result, u128s_from_felt252}; + +type Falcon512Zq = BoundedInt<0, 12288>; +type Falcon512Q = UnitInt<12289>; +type U128AsBounded = BoundedInt<0, 340282366920938463463374607431768211455>; + +const FALCON512_Q_NZ: NonZero = 12289; +const SHIFT: felt252 = 2305326338167692580222332728864932068; + +impl Falcon512FastDivRemImpl of DivRemHelper { + type DivT = BoundedInt<0, 27689996494502275487295516920153650>; + type RemT = Falcon512Zq; +} + +#[inline(always)] +fn felt252_as_u128(value: felt252) -> u128 { + // Exact generated bounds put canonical shifted outputs below 2^128. + match u128s_from_felt252(value) { + U128sFromFelt252Result::Narrow(low) => low, + U128sFromFelt252Result::Wide((_, low)) => low, + } +} + +#[inline(always)] +fn ntt_falcon512_fast_inner( + f0: felt252, + f1: felt252, + f2: felt252, + f3: felt252, + f4: felt252, + f5: felt252, + f6: felt252, + f7: felt252, + f8: felt252, + f9: felt252, + f10: felt252, + f11: felt252, + f12: felt252, + f13: felt252, + f14: felt252, + f15: felt252, + f16: felt252, + f17: felt252, + f18: felt252, + f19: felt252, + f20: felt252, + f21: felt252, + f22: felt252, + f23: felt252, + f24: felt252, + f25: felt252, + f26: felt252, + f27: felt252, + f28: felt252, + f29: felt252, + f30: felt252, + f31: felt252, + f32: felt252, + f33: felt252, + f34: felt252, + f35: felt252, + f36: felt252, + f37: felt252, + f38: felt252, + f39: felt252, + f40: felt252, + f41: felt252, + f42: felt252, + f43: felt252, + f44: felt252, + f45: felt252, + f46: felt252, + f47: felt252, + f48: felt252, + f49: felt252, + f50: felt252, + f51: felt252, + f52: felt252, + f53: felt252, + f54: felt252, + f55: felt252, + f56: felt252, + f57: felt252, + f58: felt252, + f59: felt252, + f60: felt252, + f61: felt252, + f62: felt252, + f63: felt252, + f64: felt252, + f65: felt252, + f66: felt252, + f67: felt252, + f68: felt252, + f69: felt252, + f70: felt252, + f71: felt252, + f72: felt252, + f73: felt252, + f74: felt252, + f75: felt252, + f76: felt252, + f77: felt252, + f78: felt252, + f79: felt252, + f80: felt252, + f81: felt252, + f82: felt252, + f83: felt252, + f84: felt252, + f85: felt252, + f86: felt252, + f87: felt252, + f88: felt252, + f89: felt252, + f90: felt252, + f91: felt252, + f92: felt252, + f93: felt252, + f94: felt252, + f95: felt252, + f96: felt252, + f97: felt252, + f98: felt252, + f99: felt252, + f100: felt252, + f101: felt252, + f102: felt252, + f103: felt252, + f104: felt252, + f105: felt252, + f106: felt252, + f107: felt252, + f108: felt252, + f109: felt252, + f110: felt252, + f111: felt252, + f112: felt252, + f113: felt252, + f114: felt252, + f115: felt252, + f116: felt252, + f117: felt252, + f118: felt252, + f119: felt252, + f120: felt252, + f121: felt252, + f122: felt252, + f123: felt252, + f124: felt252, + f125: felt252, + f126: felt252, + f127: felt252, + f128: felt252, + f129: felt252, + f130: felt252, + f131: felt252, + f132: felt252, + f133: felt252, + f134: felt252, + f135: felt252, + f136: felt252, + f137: felt252, + f138: felt252, + f139: felt252, + f140: felt252, + f141: felt252, + f142: felt252, + f143: felt252, + f144: felt252, + f145: felt252, + f146: felt252, + f147: felt252, + f148: felt252, + f149: felt252, + f150: felt252, + f151: felt252, + f152: felt252, + f153: felt252, + f154: felt252, + f155: felt252, + f156: felt252, + f157: felt252, + f158: felt252, + f159: felt252, + f160: felt252, + f161: felt252, + f162: felt252, + f163: felt252, + f164: felt252, + f165: felt252, + f166: felt252, + f167: felt252, + f168: felt252, + f169: felt252, + f170: felt252, + f171: felt252, + f172: felt252, + f173: felt252, + f174: felt252, + f175: felt252, + f176: felt252, + f177: felt252, + f178: felt252, + f179: felt252, + f180: felt252, + f181: felt252, + f182: felt252, + f183: felt252, + f184: felt252, + f185: felt252, + f186: felt252, + f187: felt252, + f188: felt252, + f189: felt252, + f190: felt252, + f191: felt252, + f192: felt252, + f193: felt252, + f194: felt252, + f195: felt252, + f196: felt252, + f197: felt252, + f198: felt252, + f199: felt252, + f200: felt252, + f201: felt252, + f202: felt252, + f203: felt252, + f204: felt252, + f205: felt252, + f206: felt252, + f207: felt252, + f208: felt252, + f209: felt252, + f210: felt252, + f211: felt252, + f212: felt252, + f213: felt252, + f214: felt252, + f215: felt252, + f216: felt252, + f217: felt252, + f218: felt252, + f219: felt252, + f220: felt252, + f221: felt252, + f222: felt252, + f223: felt252, + f224: felt252, + f225: felt252, + f226: felt252, + f227: felt252, + f228: felt252, + f229: felt252, + f230: felt252, + f231: felt252, + f232: felt252, + f233: felt252, + f234: felt252, + f235: felt252, + f236: felt252, + f237: felt252, + f238: felt252, + f239: felt252, + f240: felt252, + f241: felt252, + f242: felt252, + f243: felt252, + f244: felt252, + f245: felt252, + f246: felt252, + f247: felt252, + f248: felt252, + f249: felt252, + f250: felt252, + f251: felt252, + f252: felt252, + f253: felt252, + f254: felt252, + f255: felt252, + f256: felt252, + f257: felt252, + f258: felt252, + f259: felt252, + f260: felt252, + f261: felt252, + f262: felt252, + f263: felt252, + f264: felt252, + f265: felt252, + f266: felt252, + f267: felt252, + f268: felt252, + f269: felt252, + f270: felt252, + f271: felt252, + f272: felt252, + f273: felt252, + f274: felt252, + f275: felt252, + f276: felt252, + f277: felt252, + f278: felt252, + f279: felt252, + f280: felt252, + f281: felt252, + f282: felt252, + f283: felt252, + f284: felt252, + f285: felt252, + f286: felt252, + f287: felt252, + f288: felt252, + f289: felt252, + f290: felt252, + f291: felt252, + f292: felt252, + f293: felt252, + f294: felt252, + f295: felt252, + f296: felt252, + f297: felt252, + f298: felt252, + f299: felt252, + f300: felt252, + f301: felt252, + f302: felt252, + f303: felt252, + f304: felt252, + f305: felt252, + f306: felt252, + f307: felt252, + f308: felt252, + f309: felt252, + f310: felt252, + f311: felt252, + f312: felt252, + f313: felt252, + f314: felt252, + f315: felt252, + f316: felt252, + f317: felt252, + f318: felt252, + f319: felt252, + f320: felt252, + f321: felt252, + f322: felt252, + f323: felt252, + f324: felt252, + f325: felt252, + f326: felt252, + f327: felt252, + f328: felt252, + f329: felt252, + f330: felt252, + f331: felt252, + f332: felt252, + f333: felt252, + f334: felt252, + f335: felt252, + f336: felt252, + f337: felt252, + f338: felt252, + f339: felt252, + f340: felt252, + f341: felt252, + f342: felt252, + f343: felt252, + f344: felt252, + f345: felt252, + f346: felt252, + f347: felt252, + f348: felt252, + f349: felt252, + f350: felt252, + f351: felt252, + f352: felt252, + f353: felt252, + f354: felt252, + f355: felt252, + f356: felt252, + f357: felt252, + f358: felt252, + f359: felt252, + f360: felt252, + f361: felt252, + f362: felt252, + f363: felt252, + f364: felt252, + f365: felt252, + f366: felt252, + f367: felt252, + f368: felt252, + f369: felt252, + f370: felt252, + f371: felt252, + f372: felt252, + f373: felt252, + f374: felt252, + f375: felt252, + f376: felt252, + f377: felt252, + f378: felt252, + f379: felt252, + f380: felt252, + f381: felt252, + f382: felt252, + f383: felt252, + f384: felt252, + f385: felt252, + f386: felt252, + f387: felt252, + f388: felt252, + f389: felt252, + f390: felt252, + f391: felt252, + f392: felt252, + f393: felt252, + f394: felt252, + f395: felt252, + f396: felt252, + f397: felt252, + f398: felt252, + f399: felt252, + f400: felt252, + f401: felt252, + f402: felt252, + f403: felt252, + f404: felt252, + f405: felt252, + f406: felt252, + f407: felt252, + f408: felt252, + f409: felt252, + f410: felt252, + f411: felt252, + f412: felt252, + f413: felt252, + f414: felt252, + f415: felt252, + f416: felt252, + f417: felt252, + f418: felt252, + f419: felt252, + f420: felt252, + f421: felt252, + f422: felt252, + f423: felt252, + f424: felt252, + f425: felt252, + f426: felt252, + f427: felt252, + f428: felt252, + f429: felt252, + f430: felt252, + f431: felt252, + f432: felt252, + f433: felt252, + f434: felt252, + f435: felt252, + f436: felt252, + f437: felt252, + f438: felt252, + f439: felt252, + f440: felt252, + f441: felt252, + f442: felt252, + f443: felt252, + f444: felt252, + f445: felt252, + f446: felt252, + f447: felt252, + f448: felt252, + f449: felt252, + f450: felt252, + f451: felt252, + f452: felt252, + f453: felt252, + f454: felt252, + f455: felt252, + f456: felt252, + f457: felt252, + f458: felt252, + f459: felt252, + f460: felt252, + f461: felt252, + f462: felt252, + f463: felt252, + f464: felt252, + f465: felt252, + f466: felt252, + f467: felt252, + f468: felt252, + f469: felt252, + f470: felt252, + f471: felt252, + f472: felt252, + f473: felt252, + f474: felt252, + f475: felt252, + f476: felt252, + f477: felt252, + f478: felt252, + f479: felt252, + f480: felt252, + f481: felt252, + f482: felt252, + f483: felt252, + f484: felt252, + f485: felt252, + f486: felt252, + f487: felt252, + f488: felt252, + f489: felt252, + f490: felt252, + f491: felt252, + f492: felt252, + f493: felt252, + f494: felt252, + f495: felt252, + f496: felt252, + f497: felt252, + f498: felt252, + f499: felt252, + f500: felt252, + f501: felt252, + f502: felt252, + f503: felt252, + f504: felt252, + f505: felt252, + f506: felt252, + f507: felt252, + f508: felt252, + f509: felt252, + f510: felt252, + f511: felt252, +) -> ( + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, + Falcon512Zq, +) { + let v0 = f256 * 1479; + let v1 = f0 + v0; + let v2 = f0 - v0; + let v3 = f384 * 1479; + let v4 = f128 + v3; + let v5 = f128 - v3; + let v6 = v4 * 4043; + let v7 = v1 + v6; + let v8 = v1 - v6; + let v9 = v5 * 5146; + let v10 = v2 + v9; + let v11 = v2 - v9; + let v12 = f320 * 1479; + let v13 = f64 + v12; + let v14 = f64 - v12; + let v15 = f448 * 1479; + let v16 = f192 + v15; + let v17 = f192 - v15; + let v18 = v16 * 4043; + let v19 = v13 + v18; + let v20 = v13 - v18; + let v21 = v17 * 5146; + let v22 = v14 + v21; + let v23 = v14 - v21; + let v24 = v19 * 5736; + let v25 = v7 + v24; + let v26 = v7 - v24; + let v27 = v20 * 4134; + let v28 = v8 + v27; + let v29 = v8 - v27; + let v30 = v22 * 722; + let v31 = v10 + v30; + let v32 = v10 - v30; + let v33 = v23 * 1305; + let v34 = v11 + v33; + let v35 = v11 - v33; + let v36 = f288 * 1479; + let v37 = f32 + v36; + let v38 = f32 - v36; + let v39 = f416 * 1479; + let v40 = f160 + v39; + let v41 = f160 - v39; + let v42 = v40 * 4043; + let v43 = v37 + v42; + let v44 = v37 - v42; + let v45 = v41 * 5146; + let v46 = v38 + v45; + let v47 = v38 - v45; + let v48 = f352 * 1479; + let v49 = f96 + v48; + let v50 = f96 - v48; + let v51 = f480 * 1479; + let v52 = f224 + v51; + let v53 = f224 - v51; + let v54 = v52 * 4043; + let v55 = v49 + v54; + let v56 = v49 - v54; + let v57 = v53 * 5146; + let v58 = v50 + v57; + let v59 = v50 - v57; + let v60 = v55 * 5736; + let v61 = v43 + v60; + let v62 = v43 - v60; + let v63 = v56 * 4134; + let v64 = v44 + v63; + let v65 = v44 - v63; + let v66 = v58 * 722; + let v67 = v46 + v66; + let v68 = v46 - v66; + let v69 = v59 * 1305; + let v70 = v47 + v69; + let v71 = v47 - v69; + let v72 = v61 * 1646; + let v73 = v25 + v72; + let v74 = v25 - v72; + let v75 = v62 * 1212; + let v76 = v26 + v75; + let v77 = v26 - v75; + let v78 = v64 * 5860; + let v79 = v28 + v78; + let v80 = v28 - v78; + let v81 = v65 * 3195; + let v82 = v29 + v81; + let v83 = v29 - v81; + let v84 = v67 * 2545; + let v85 = v31 + v84; + let v86 = v31 - v84; + let v87 = v68 * 3621; + let v88 = v32 + v87; + let v89 = v32 - v87; + let v90 = v70 * 3504; + let v91 = v34 + v90; + let v92 = v34 - v90; + let v93 = v71 * 3542; + let v94 = v35 + v93; + let v95 = v35 - v93; + let v96 = f272 * 1479; + let v97 = f16 + v96; + let v98 = f16 - v96; + let v99 = f400 * 1479; + let v100 = f144 + v99; + let v101 = f144 - v99; + let v102 = v100 * 4043; + let v103 = v97 + v102; + let v104 = v97 - v102; + let v105 = v101 * 5146; + let v106 = v98 + v105; + let v107 = v98 - v105; + let v108 = f336 * 1479; + let v109 = f80 + v108; + let v110 = f80 - v108; + let v111 = f464 * 1479; + let v112 = f208 + v111; + let v113 = f208 - v111; + let v114 = v112 * 4043; + let v115 = v109 + v114; + let v116 = v109 - v114; + let v117 = v113 * 5146; + let v118 = v110 + v117; + let v119 = v110 - v117; + let v120 = v115 * 5736; + let v121 = v103 + v120; + let v122 = v103 - v120; + let v123 = v116 * 4134; + let v124 = v104 + v123; + let v125 = v104 - v123; + let v126 = v118 * 722; + let v127 = v106 + v126; + let v128 = v106 - v126; + let v129 = v119 * 1305; + let v130 = v107 + v129; + let v131 = v107 - v129; + let v132 = f304 * 1479; + let v133 = f48 + v132; + let v134 = f48 - v132; + let v135 = f432 * 1479; + let v136 = f176 + v135; + let v137 = f176 - v135; + let v138 = v136 * 4043; + let v139 = v133 + v138; + let v140 = v133 - v138; + let v141 = v137 * 5146; + let v142 = v134 + v141; + let v143 = v134 - v141; + let v144 = f368 * 1479; + let v145 = f112 + v144; + let v146 = f112 - v144; + let v147 = f496 * 1479; + let v148 = f240 + v147; + let v149 = f240 - v147; + let v150 = v148 * 4043; + let v151 = v145 + v150; + let v152 = v145 - v150; + let v153 = v149 * 5146; + let v154 = v146 + v153; + let v155 = v146 - v153; + let v156 = v151 * 5736; + let v157 = v139 + v156; + let v158 = v139 - v156; + let v159 = v152 * 4134; + let v160 = v140 + v159; + let v161 = v140 - v159; + let v162 = v154 * 722; + let v163 = v142 + v162; + let v164 = v142 - v162; + let v165 = v155 * 1305; + let v166 = v143 + v165; + let v167 = v143 - v165; + let v168 = v157 * 1646; + let v169 = v121 + v168; + let v170 = v121 - v168; + let v171 = v158 * 1212; + let v172 = v122 + v171; + let v173 = v122 - v171; + let v174 = v160 * 5860; + let v175 = v124 + v174; + let v176 = v124 - v174; + let v177 = v161 * 3195; + let v178 = v125 + v177; + let v179 = v125 - v177; + let v180 = v163 * 2545; + let v181 = v127 + v180; + let v182 = v127 - v180; + let v183 = v164 * 3621; + let v184 = v128 + v183; + let v185 = v128 - v183; + let v186 = v166 * 3504; + let v187 = v130 + v186; + let v188 = v130 - v186; + let v189 = v167 * 3542; + let v190 = v131 + v189; + let v191 = v131 - v189; + let v192 = v169 * 4591; + let v193 = v73 + v192; + let v194 = v73 - v192; + let v195 = v170 * 5728; + let v196 = v74 + v195; + let v197 = v74 - v195; + let v198 = v172 * 5023; + let v199 = v76 + v198; + let v200 = v76 - v198; + let v201 = v173 * 5828; + let v202 = v77 + v201; + let v203 = v77 - v201; + let v204 = v175 * 4978; + let v205 = v79 + v204; + let v206 = v79 - v204; + let v207 = v176 * 1351; + let v208 = v80 + v207; + let v209 = v80 - v207; + let v210 = v178 * 3328; + let v211 = v82 + v210; + let v212 = v82 - v210; + let v213 = v179 * 5777; + let v214 = v83 + v213; + let v215 = v83 - v213; + let v216 = v181 * 2975; + let v217 = v85 + v216; + let v218 = v85 - v216; + let v219 = v182 * 563; + let v220 = v86 + v219; + let v221 = v86 - v219; + let v222 = v184 * 3006; + let v223 = v88 + v222; + let v224 = v88 - v222; + let v225 = v185 * 2744; + let v226 = v89 + v225; + let v227 = v89 - v225; + let v228 = v187 * 949; + let v229 = v91 + v228; + let v230 = v91 - v228; + let v231 = v188 * 2625; + let v232 = v92 + v231; + let v233 = v92 - v231; + let v234 = v190 * 4821; + let v235 = v94 + v234; + let v236 = v94 - v234; + let v237 = v191 * 2639; + let v238 = v95 + v237; + let v239 = v95 - v237; + let v240 = f264 * 1479; + let v241 = f8 + v240; + let v242 = f8 - v240; + let v243 = f392 * 1479; + let v244 = f136 + v243; + let v245 = f136 - v243; + let v246 = v244 * 4043; + let v247 = v241 + v246; + let v248 = v241 - v246; + let v249 = v245 * 5146; + let v250 = v242 + v249; + let v251 = v242 - v249; + let v252 = f328 * 1479; + let v253 = f72 + v252; + let v254 = f72 - v252; + let v255 = f456 * 1479; + let v256 = f200 + v255; + let v257 = f200 - v255; + let v258 = v256 * 4043; + let v259 = v253 + v258; + let v260 = v253 - v258; + let v261 = v257 * 5146; + let v262 = v254 + v261; + let v263 = v254 - v261; + let v264 = v259 * 5736; + let v265 = v247 + v264; + let v266 = v247 - v264; + let v267 = v260 * 4134; + let v268 = v248 + v267; + let v269 = v248 - v267; + let v270 = v262 * 722; + let v271 = v250 + v270; + let v272 = v250 - v270; + let v273 = v263 * 1305; + let v274 = v251 + v273; + let v275 = v251 - v273; + let v276 = f296 * 1479; + let v277 = f40 + v276; + let v278 = f40 - v276; + let v279 = f424 * 1479; + let v280 = f168 + v279; + let v281 = f168 - v279; + let v282 = v280 * 4043; + let v283 = v277 + v282; + let v284 = v277 - v282; + let v285 = v281 * 5146; + let v286 = v278 + v285; + let v287 = v278 - v285; + let v288 = f360 * 1479; + let v289 = f104 + v288; + let v290 = f104 - v288; + let v291 = f488 * 1479; + let v292 = f232 + v291; + let v293 = f232 - v291; + let v294 = v292 * 4043; + let v295 = v289 + v294; + let v296 = v289 - v294; + let v297 = v293 * 5146; + let v298 = v290 + v297; + let v299 = v290 - v297; + let v300 = v295 * 5736; + let v301 = v283 + v300; + let v302 = v283 - v300; + let v303 = v296 * 4134; + let v304 = v284 + v303; + let v305 = v284 - v303; + let v306 = v298 * 722; + let v307 = v286 + v306; + let v308 = v286 - v306; + let v309 = v299 * 1305; + let v310 = v287 + v309; + let v311 = v287 - v309; + let v312 = v301 * 1646; + let v313 = v265 + v312; + let v314 = v265 - v312; + let v315 = v302 * 1212; + let v316 = v266 + v315; + let v317 = v266 - v315; + let v318 = v304 * 5860; + let v319 = v268 + v318; + let v320 = v268 - v318; + let v321 = v305 * 3195; + let v322 = v269 + v321; + let v323 = v269 - v321; + let v324 = v307 * 2545; + let v325 = v271 + v324; + let v326 = v271 - v324; + let v327 = v308 * 3621; + let v328 = v272 + v327; + let v329 = v272 - v327; + let v330 = v310 * 3504; + let v331 = v274 + v330; + let v332 = v274 - v330; + let v333 = v311 * 3542; + let v334 = v275 + v333; + let v335 = v275 - v333; + let v336 = f280 * 1479; + let v337 = f24 + v336; + let v338 = f24 - v336; + let v339 = f408 * 1479; + let v340 = f152 + v339; + let v341 = f152 - v339; + let v342 = v340 * 4043; + let v343 = v337 + v342; + let v344 = v337 - v342; + let v345 = v341 * 5146; + let v346 = v338 + v345; + let v347 = v338 - v345; + let v348 = f344 * 1479; + let v349 = f88 + v348; + let v350 = f88 - v348; + let v351 = f472 * 1479; + let v352 = f216 + v351; + let v353 = f216 - v351; + let v354 = v352 * 4043; + let v355 = v349 + v354; + let v356 = v349 - v354; + let v357 = v353 * 5146; + let v358 = v350 + v357; + let v359 = v350 - v357; + let v360 = v355 * 5736; + let v361 = v343 + v360; + let v362 = v343 - v360; + let v363 = v356 * 4134; + let v364 = v344 + v363; + let v365 = v344 - v363; + let v366 = v358 * 722; + let v367 = v346 + v366; + let v368 = v346 - v366; + let v369 = v359 * 1305; + let v370 = v347 + v369; + let v371 = v347 - v369; + let v372 = f312 * 1479; + let v373 = f56 + v372; + let v374 = f56 - v372; + let v375 = f440 * 1479; + let v376 = f184 + v375; + let v377 = f184 - v375; + let v378 = v376 * 4043; + let v379 = v373 + v378; + let v380 = v373 - v378; + let v381 = v377 * 5146; + let v382 = v374 + v381; + let v383 = v374 - v381; + let v384 = f376 * 1479; + let v385 = f120 + v384; + let v386 = f120 - v384; + let v387 = f504 * 1479; + let v388 = f248 + v387; + let v389 = f248 - v387; + let v390 = v388 * 4043; + let v391 = v385 + v390; + let v392 = v385 - v390; + let v393 = v389 * 5146; + let v394 = v386 + v393; + let v395 = v386 - v393; + let v396 = v391 * 5736; + let v397 = v379 + v396; + let v398 = v379 - v396; + let v399 = v392 * 4134; + let v400 = v380 + v399; + let v401 = v380 - v399; + let v402 = v394 * 722; + let v403 = v382 + v402; + let v404 = v382 - v402; + let v405 = v395 * 1305; + let v406 = v383 + v405; + let v407 = v383 - v405; + let v408 = v397 * 1646; + let v409 = v361 + v408; + let v410 = v361 - v408; + let v411 = v398 * 1212; + let v412 = v362 + v411; + let v413 = v362 - v411; + let v414 = v400 * 5860; + let v415 = v364 + v414; + let v416 = v364 - v414; + let v417 = v401 * 3195; + let v418 = v365 + v417; + let v419 = v365 - v417; + let v420 = v403 * 2545; + let v421 = v367 + v420; + let v422 = v367 - v420; + let v423 = v404 * 3621; + let v424 = v368 + v423; + let v425 = v368 - v423; + let v426 = v406 * 3504; + let v427 = v370 + v426; + let v428 = v370 - v426; + let v429 = v407 * 3542; + let v430 = v371 + v429; + let v431 = v371 - v429; + let v432 = v409 * 4591; + let v433 = v313 + v432; + let v434 = v313 - v432; + let v435 = v410 * 5728; + let v436 = v314 + v435; + let v437 = v314 - v435; + let v438 = v412 * 5023; + let v439 = v316 + v438; + let v440 = v316 - v438; + let v441 = v413 * 5828; + let v442 = v317 + v441; + let v443 = v317 - v441; + let v444 = v415 * 4978; + let v445 = v319 + v444; + let v446 = v319 - v444; + let v447 = v416 * 1351; + let v448 = v320 + v447; + let v449 = v320 - v447; + let v450 = v418 * 3328; + let v451 = v322 + v450; + let v452 = v322 - v450; + let v453 = v419 * 5777; + let v454 = v323 + v453; + let v455 = v323 - v453; + let v456 = v421 * 2975; + let v457 = v325 + v456; + let v458 = v325 - v456; + let v459 = v422 * 563; + let v460 = v326 + v459; + let v461 = v326 - v459; + let v462 = v424 * 3006; + let v463 = v328 + v462; + let v464 = v328 - v462; + let v465 = v425 * 2744; + let v466 = v329 + v465; + let v467 = v329 - v465; + let v468 = v427 * 949; + let v469 = v331 + v468; + let v470 = v331 - v468; + let v471 = v428 * 2625; + let v472 = v332 + v471; + let v473 = v332 - v471; + let v474 = v430 * 4821; + let v475 = v334 + v474; + let v476 = v334 - v474; + let v477 = v431 * 2639; + let v478 = v335 + v477; + let v479 = v335 - v477; + let v480 = v433 * 1000; + let v481 = v193 + v480; + let v482 = v193 - v480; + let v483 = v434 * 4320; + let v484 = v194 + v483; + let v485 = v194 - v483; + let v486 = v436 * 3091; + let v487 = v196 + v486; + let v488 = v196 - v486; + let v489 = v437 * 81; + let v490 = v197 + v489; + let v491 = v197 - v489; + let v492 = v439 * 2963; + let v493 = v199 + v492; + let v494 = v199 - v492; + let v495 = v440 * 4896; + let v496 = v200 + v495; + let v497 = v200 - v495; + let v498 = v442 * 3051; + let v499 = v202 + v498; + let v500 = v202 - v498; + let v501 = v443 * 2366; + let v502 = v203 + v501; + let v503 = v203 - v501; + let v504 = v445 * 1853; + let v505 = v205 + v504; + let v506 = v205 - v504; + let v507 = v446 * 140; + let v508 = v206 + v507; + let v509 = v206 - v507; + let v510 = v448 * 4611; + let v511 = v208 + v510; + let v512 = v208 - v510; + let v513 = v449 * 726; + let v514 = v209 + v513; + let v515 = v209 - v513; + let v516 = v451 * 4255; + let v517 = v211 + v516; + let v518 = v211 - v516; + let v519 = v452 * 1177; + let v520 = v212 + v519; + let v521 = v212 - v519; + let v522 = v454 * 2768; + let v523 = v214 + v522; + let v524 = v214 - v522; + let v525 = v455 * 1635; + let v526 = v215 + v525; + let v527 = v215 - v525; + let v528 = v457 * 3712; + let v529 = v217 + v528; + let v530 = v217 - v528; + let v531 = v458 * 3135; + let v532 = v218 + v531; + let v533 = v218 - v531; + let v534 = v460 * 2747; + let v535 = v220 + v534; + let v536 = v220 - v534; + let v537 = v461 * 4846; + let v538 = v221 + v537; + let v539 = v221 - v537; + let v540 = v463 * 3553; + let v541 = v223 + v540; + let v542 = v223 - v540; + let v543 = v464 * 4805; + let v544 = v224 + v543; + let v545 = v224 - v543; + let v546 = v466 * 2294; + let v547 = v226 + v546; + let v548 = v226 - v546; + let v549 = v467 * 1062; + let v550 = v227 + v549; + let v551 = v227 - v549; + let v552 = v469 * 1326; + let v553 = v229 + v552; + let v554 = v229 - v552; + let v555 = v470 * 5086; + let v556 = v230 + v555; + let v557 = v230 - v555; + let v558 = v472 * 3014; + let v559 = v232 + v558; + let v560 = v232 - v558; + let v561 = v473 * 3201; + let v562 = v233 + v561; + let v563 = v233 - v561; + let v564 = v475 * 1170; + let v565 = v235 + v564; + let v566 = v235 - v564; + let v567 = v476 * 2319; + let v568 = v236 + v567; + let v569 = v236 - v567; + let v570 = v478 * 955; + let v571 = v238 + v570; + let v572 = v238 - v570; + let v573 = v479 * 790; + let v574 = v239 + v573; + let v575 = v239 - v573; + let v576 = f260 * 1479; + let v577 = f4 + v576; + let v578 = f4 - v576; + let v579 = f388 * 1479; + let v580 = f132 + v579; + let v581 = f132 - v579; + let v582 = v580 * 4043; + let v583 = v577 + v582; + let v584 = v577 - v582; + let v585 = v581 * 5146; + let v586 = v578 + v585; + let v587 = v578 - v585; + let v588 = f324 * 1479; + let v589 = f68 + v588; + let v590 = f68 - v588; + let v591 = f452 * 1479; + let v592 = f196 + v591; + let v593 = f196 - v591; + let v594 = v592 * 4043; + let v595 = v589 + v594; + let v596 = v589 - v594; + let v597 = v593 * 5146; + let v598 = v590 + v597; + let v599 = v590 - v597; + let v600 = v595 * 5736; + let v601 = v583 + v600; + let v602 = v583 - v600; + let v603 = v596 * 4134; + let v604 = v584 + v603; + let v605 = v584 - v603; + let v606 = v598 * 722; + let v607 = v586 + v606; + let v608 = v586 - v606; + let v609 = v599 * 1305; + let v610 = v587 + v609; + let v611 = v587 - v609; + let v612 = f292 * 1479; + let v613 = f36 + v612; + let v614 = f36 - v612; + let v615 = f420 * 1479; + let v616 = f164 + v615; + let v617 = f164 - v615; + let v618 = v616 * 4043; + let v619 = v613 + v618; + let v620 = v613 - v618; + let v621 = v617 * 5146; + let v622 = v614 + v621; + let v623 = v614 - v621; + let v624 = f356 * 1479; + let v625 = f100 + v624; + let v626 = f100 - v624; + let v627 = f484 * 1479; + let v628 = f228 + v627; + let v629 = f228 - v627; + let v630 = v628 * 4043; + let v631 = v625 + v630; + let v632 = v625 - v630; + let v633 = v629 * 5146; + let v634 = v626 + v633; + let v635 = v626 - v633; + let v636 = v631 * 5736; + let v637 = v619 + v636; + let v638 = v619 - v636; + let v639 = v632 * 4134; + let v640 = v620 + v639; + let v641 = v620 - v639; + let v642 = v634 * 722; + let v643 = v622 + v642; + let v644 = v622 - v642; + let v645 = v635 * 1305; + let v646 = v623 + v645; + let v647 = v623 - v645; + let v648 = v637 * 1646; + let v649 = v601 + v648; + let v650 = v601 - v648; + let v651 = v638 * 1212; + let v652 = v602 + v651; + let v653 = v602 - v651; + let v654 = v640 * 5860; + let v655 = v604 + v654; + let v656 = v604 - v654; + let v657 = v641 * 3195; + let v658 = v605 + v657; + let v659 = v605 - v657; + let v660 = v643 * 2545; + let v661 = v607 + v660; + let v662 = v607 - v660; + let v663 = v644 * 3621; + let v664 = v608 + v663; + let v665 = v608 - v663; + let v666 = v646 * 3504; + let v667 = v610 + v666; + let v668 = v610 - v666; + let v669 = v647 * 3542; + let v670 = v611 + v669; + let v671 = v611 - v669; + let v672 = f276 * 1479; + let v673 = f20 + v672; + let v674 = f20 - v672; + let v675 = f404 * 1479; + let v676 = f148 + v675; + let v677 = f148 - v675; + let v678 = v676 * 4043; + let v679 = v673 + v678; + let v680 = v673 - v678; + let v681 = v677 * 5146; + let v682 = v674 + v681; + let v683 = v674 - v681; + let v684 = f340 * 1479; + let v685 = f84 + v684; + let v686 = f84 - v684; + let v687 = f468 * 1479; + let v688 = f212 + v687; + let v689 = f212 - v687; + let v690 = v688 * 4043; + let v691 = v685 + v690; + let v692 = v685 - v690; + let v693 = v689 * 5146; + let v694 = v686 + v693; + let v695 = v686 - v693; + let v696 = v691 * 5736; + let v697 = v679 + v696; + let v698 = v679 - v696; + let v699 = v692 * 4134; + let v700 = v680 + v699; + let v701 = v680 - v699; + let v702 = v694 * 722; + let v703 = v682 + v702; + let v704 = v682 - v702; + let v705 = v695 * 1305; + let v706 = v683 + v705; + let v707 = v683 - v705; + let v708 = f308 * 1479; + let v709 = f52 + v708; + let v710 = f52 - v708; + let v711 = f436 * 1479; + let v712 = f180 + v711; + let v713 = f180 - v711; + let v714 = v712 * 4043; + let v715 = v709 + v714; + let v716 = v709 - v714; + let v717 = v713 * 5146; + let v718 = v710 + v717; + let v719 = v710 - v717; + let v720 = f372 * 1479; + let v721 = f116 + v720; + let v722 = f116 - v720; + let v723 = f500 * 1479; + let v724 = f244 + v723; + let v725 = f244 - v723; + let v726 = v724 * 4043; + let v727 = v721 + v726; + let v728 = v721 - v726; + let v729 = v725 * 5146; + let v730 = v722 + v729; + let v731 = v722 - v729; + let v732 = v727 * 5736; + let v733 = v715 + v732; + let v734 = v715 - v732; + let v735 = v728 * 4134; + let v736 = v716 + v735; + let v737 = v716 - v735; + let v738 = v730 * 722; + let v739 = v718 + v738; + let v740 = v718 - v738; + let v741 = v731 * 1305; + let v742 = v719 + v741; + let v743 = v719 - v741; + let v744 = v733 * 1646; + let v745 = v697 + v744; + let v746 = v697 - v744; + let v747 = v734 * 1212; + let v748 = v698 + v747; + let v749 = v698 - v747; + let v750 = v736 * 5860; + let v751 = v700 + v750; + let v752 = v700 - v750; + let v753 = v737 * 3195; + let v754 = v701 + v753; + let v755 = v701 - v753; + let v756 = v739 * 2545; + let v757 = v703 + v756; + let v758 = v703 - v756; + let v759 = v740 * 3621; + let v760 = v704 + v759; + let v761 = v704 - v759; + let v762 = v742 * 3504; + let v763 = v706 + v762; + let v764 = v706 - v762; + let v765 = v743 * 3542; + let v766 = v707 + v765; + let v767 = v707 - v765; + let v768 = v745 * 4591; + let v769 = v649 + v768; + let v770 = v649 - v768; + let v771 = v746 * 5728; + let v772 = v650 + v771; + let v773 = v650 - v771; + let v774 = v748 * 5023; + let v775 = v652 + v774; + let v776 = v652 - v774; + let v777 = v749 * 5828; + let v778 = v653 + v777; + let v779 = v653 - v777; + let v780 = v751 * 4978; + let v781 = v655 + v780; + let v782 = v655 - v780; + let v783 = v752 * 1351; + let v784 = v656 + v783; + let v785 = v656 - v783; + let v786 = v754 * 3328; + let v787 = v658 + v786; + let v788 = v658 - v786; + let v789 = v755 * 5777; + let v790 = v659 + v789; + let v791 = v659 - v789; + let v792 = v757 * 2975; + let v793 = v661 + v792; + let v794 = v661 - v792; + let v795 = v758 * 563; + let v796 = v662 + v795; + let v797 = v662 - v795; + let v798 = v760 * 3006; + let v799 = v664 + v798; + let v800 = v664 - v798; + let v801 = v761 * 2744; + let v802 = v665 + v801; + let v803 = v665 - v801; + let v804 = v763 * 949; + let v805 = v667 + v804; + let v806 = v667 - v804; + let v807 = v764 * 2625; + let v808 = v668 + v807; + let v809 = v668 - v807; + let v810 = v766 * 4821; + let v811 = v670 + v810; + let v812 = v670 - v810; + let v813 = v767 * 2639; + let v814 = v671 + v813; + let v815 = v671 - v813; + let v816 = f268 * 1479; + let v817 = f12 + v816; + let v818 = f12 - v816; + let v819 = f396 * 1479; + let v820 = f140 + v819; + let v821 = f140 - v819; + let v822 = v820 * 4043; + let v823 = v817 + v822; + let v824 = v817 - v822; + let v825 = v821 * 5146; + let v826 = v818 + v825; + let v827 = v818 - v825; + let v828 = f332 * 1479; + let v829 = f76 + v828; + let v830 = f76 - v828; + let v831 = f460 * 1479; + let v832 = f204 + v831; + let v833 = f204 - v831; + let v834 = v832 * 4043; + let v835 = v829 + v834; + let v836 = v829 - v834; + let v837 = v833 * 5146; + let v838 = v830 + v837; + let v839 = v830 - v837; + let v840 = v835 * 5736; + let v841 = v823 + v840; + let v842 = v823 - v840; + let v843 = v836 * 4134; + let v844 = v824 + v843; + let v845 = v824 - v843; + let v846 = v838 * 722; + let v847 = v826 + v846; + let v848 = v826 - v846; + let v849 = v839 * 1305; + let v850 = v827 + v849; + let v851 = v827 - v849; + let v852 = f300 * 1479; + let v853 = f44 + v852; + let v854 = f44 - v852; + let v855 = f428 * 1479; + let v856 = f172 + v855; + let v857 = f172 - v855; + let v858 = v856 * 4043; + let v859 = v853 + v858; + let v860 = v853 - v858; + let v861 = v857 * 5146; + let v862 = v854 + v861; + let v863 = v854 - v861; + let v864 = f364 * 1479; + let v865 = f108 + v864; + let v866 = f108 - v864; + let v867 = f492 * 1479; + let v868 = f236 + v867; + let v869 = f236 - v867; + let v870 = v868 * 4043; + let v871 = v865 + v870; + let v872 = v865 - v870; + let v873 = v869 * 5146; + let v874 = v866 + v873; + let v875 = v866 - v873; + let v876 = v871 * 5736; + let v877 = v859 + v876; + let v878 = v859 - v876; + let v879 = v872 * 4134; + let v880 = v860 + v879; + let v881 = v860 - v879; + let v882 = v874 * 722; + let v883 = v862 + v882; + let v884 = v862 - v882; + let v885 = v875 * 1305; + let v886 = v863 + v885; + let v887 = v863 - v885; + let v888 = v877 * 1646; + let v889 = v841 + v888; + let v890 = v841 - v888; + let v891 = v878 * 1212; + let v892 = v842 + v891; + let v893 = v842 - v891; + let v894 = v880 * 5860; + let v895 = v844 + v894; + let v896 = v844 - v894; + let v897 = v881 * 3195; + let v898 = v845 + v897; + let v899 = v845 - v897; + let v900 = v883 * 2545; + let v901 = v847 + v900; + let v902 = v847 - v900; + let v903 = v884 * 3621; + let v904 = v848 + v903; + let v905 = v848 - v903; + let v906 = v886 * 3504; + let v907 = v850 + v906; + let v908 = v850 - v906; + let v909 = v887 * 3542; + let v910 = v851 + v909; + let v911 = v851 - v909; + let v912 = f284 * 1479; + let v913 = f28 + v912; + let v914 = f28 - v912; + let v915 = f412 * 1479; + let v916 = f156 + v915; + let v917 = f156 - v915; + let v918 = v916 * 4043; + let v919 = v913 + v918; + let v920 = v913 - v918; + let v921 = v917 * 5146; + let v922 = v914 + v921; + let v923 = v914 - v921; + let v924 = f348 * 1479; + let v925 = f92 + v924; + let v926 = f92 - v924; + let v927 = f476 * 1479; + let v928 = f220 + v927; + let v929 = f220 - v927; + let v930 = v928 * 4043; + let v931 = v925 + v930; + let v932 = v925 - v930; + let v933 = v929 * 5146; + let v934 = v926 + v933; + let v935 = v926 - v933; + let v936 = v931 * 5736; + let v937 = v919 + v936; + let v938 = v919 - v936; + let v939 = v932 * 4134; + let v940 = v920 + v939; + let v941 = v920 - v939; + let v942 = v934 * 722; + let v943 = v922 + v942; + let v944 = v922 - v942; + let v945 = v935 * 1305; + let v946 = v923 + v945; + let v947 = v923 - v945; + let v948 = f316 * 1479; + let v949 = f60 + v948; + let v950 = f60 - v948; + let v951 = f444 * 1479; + let v952 = f188 + v951; + let v953 = f188 - v951; + let v954 = v952 * 4043; + let v955 = v949 + v954; + let v956 = v949 - v954; + let v957 = v953 * 5146; + let v958 = v950 + v957; + let v959 = v950 - v957; + let v960 = f380 * 1479; + let v961 = f124 + v960; + let v962 = f124 - v960; + let v963 = f508 * 1479; + let v964 = f252 + v963; + let v965 = f252 - v963; + let v966 = v964 * 4043; + let v967 = v961 + v966; + let v968 = v961 - v966; + let v969 = v965 * 5146; + let v970 = v962 + v969; + let v971 = v962 - v969; + let v972 = v967 * 5736; + let v973 = v955 + v972; + let v974 = v955 - v972; + let v975 = v968 * 4134; + let v976 = v956 + v975; + let v977 = v956 - v975; + let v978 = v970 * 722; + let v979 = v958 + v978; + let v980 = v958 - v978; + let v981 = v971 * 1305; + let v982 = v959 + v981; + let v983 = v959 - v981; + let v984 = v973 * 1646; + let v985 = v937 + v984; + let v986 = v937 - v984; + let v987 = v974 * 1212; + let v988 = v938 + v987; + let v989 = v938 - v987; + let v990 = v976 * 5860; + let v991 = v940 + v990; + let v992 = v940 - v990; + let v993 = v977 * 3195; + let v994 = v941 + v993; + let v995 = v941 - v993; + let v996 = v979 * 2545; + let v997 = v943 + v996; + let v998 = v943 - v996; + let v999 = v980 * 3621; + let v1000 = v944 + v999; + let v1001 = v944 - v999; + let v1002 = v982 * 3504; + let v1003 = v946 + v1002; + let v1004 = v946 - v1002; + let v1005 = v983 * 3542; + let v1006 = v947 + v1005; + let v1007 = v947 - v1005; + let v1008 = v985 * 4591; + let v1009 = v889 + v1008; + let v1010 = v889 - v1008; + let v1011 = v986 * 5728; + let v1012 = v890 + v1011; + let v1013 = v890 - v1011; + let v1014 = v988 * 5023; + let v1015 = v892 + v1014; + let v1016 = v892 - v1014; + let v1017 = v989 * 5828; + let v1018 = v893 + v1017; + let v1019 = v893 - v1017; + let v1020 = v991 * 4978; + let v1021 = v895 + v1020; + let v1022 = v895 - v1020; + let v1023 = v992 * 1351; + let v1024 = v896 + v1023; + let v1025 = v896 - v1023; + let v1026 = v994 * 3328; + let v1027 = v898 + v1026; + let v1028 = v898 - v1026; + let v1029 = v995 * 5777; + let v1030 = v899 + v1029; + let v1031 = v899 - v1029; + let v1032 = v997 * 2975; + let v1033 = v901 + v1032; + let v1034 = v901 - v1032; + let v1035 = v998 * 563; + let v1036 = v902 + v1035; + let v1037 = v902 - v1035; + let v1038 = v1000 * 3006; + let v1039 = v904 + v1038; + let v1040 = v904 - v1038; + let v1041 = v1001 * 2744; + let v1042 = v905 + v1041; + let v1043 = v905 - v1041; + let v1044 = v1003 * 949; + let v1045 = v907 + v1044; + let v1046 = v907 - v1044; + let v1047 = v1004 * 2625; + let v1048 = v908 + v1047; + let v1049 = v908 - v1047; + let v1050 = v1006 * 4821; + let v1051 = v910 + v1050; + let v1052 = v910 - v1050; + let v1053 = v1007 * 2639; + let v1054 = v911 + v1053; + let v1055 = v911 - v1053; + let v1056 = v1009 * 1000; + let v1057 = v769 + v1056; + let v1058 = v769 - v1056; + let v1059 = v1010 * 4320; + let v1060 = v770 + v1059; + let v1061 = v770 - v1059; + let v1062 = v1012 * 3091; + let v1063 = v772 + v1062; + let v1064 = v772 - v1062; + let v1065 = v1013 * 81; + let v1066 = v773 + v1065; + let v1067 = v773 - v1065; + let v1068 = v1015 * 2963; + let v1069 = v775 + v1068; + let v1070 = v775 - v1068; + let v1071 = v1016 * 4896; + let v1072 = v776 + v1071; + let v1073 = v776 - v1071; + let v1074 = v1018 * 3051; + let v1075 = v778 + v1074; + let v1076 = v778 - v1074; + let v1077 = v1019 * 2366; + let v1078 = v779 + v1077; + let v1079 = v779 - v1077; + let v1080 = v1021 * 1853; + let v1081 = v781 + v1080; + let v1082 = v781 - v1080; + let v1083 = v1022 * 140; + let v1084 = v782 + v1083; + let v1085 = v782 - v1083; + let v1086 = v1024 * 4611; + let v1087 = v784 + v1086; + let v1088 = v784 - v1086; + let v1089 = v1025 * 726; + let v1090 = v785 + v1089; + let v1091 = v785 - v1089; + let v1092 = v1027 * 4255; + let v1093 = v787 + v1092; + let v1094 = v787 - v1092; + let v1095 = v1028 * 1177; + let v1096 = v788 + v1095; + let v1097 = v788 - v1095; + let v1098 = v1030 * 2768; + let v1099 = v790 + v1098; + let v1100 = v790 - v1098; + let v1101 = v1031 * 1635; + let v1102 = v791 + v1101; + let v1103 = v791 - v1101; + let v1104 = v1033 * 3712; + let v1105 = v793 + v1104; + let v1106 = v793 - v1104; + let v1107 = v1034 * 3135; + let v1108 = v794 + v1107; + let v1109 = v794 - v1107; + let v1110 = v1036 * 2747; + let v1111 = v796 + v1110; + let v1112 = v796 - v1110; + let v1113 = v1037 * 4846; + let v1114 = v797 + v1113; + let v1115 = v797 - v1113; + let v1116 = v1039 * 3553; + let v1117 = v799 + v1116; + let v1118 = v799 - v1116; + let v1119 = v1040 * 4805; + let v1120 = v800 + v1119; + let v1121 = v800 - v1119; + let v1122 = v1042 * 2294; + let v1123 = v802 + v1122; + let v1124 = v802 - v1122; + let v1125 = v1043 * 1062; + let v1126 = v803 + v1125; + let v1127 = v803 - v1125; + let v1128 = v1045 * 1326; + let v1129 = v805 + v1128; + let v1130 = v805 - v1128; + let v1131 = v1046 * 5086; + let v1132 = v806 + v1131; + let v1133 = v806 - v1131; + let v1134 = v1048 * 3014; + let v1135 = v808 + v1134; + let v1136 = v808 - v1134; + let v1137 = v1049 * 3201; + let v1138 = v809 + v1137; + let v1139 = v809 - v1137; + let v1140 = v1051 * 1170; + let v1141 = v811 + v1140; + let v1142 = v811 - v1140; + let v1143 = v1052 * 2319; + let v1144 = v812 + v1143; + let v1145 = v812 - v1143; + let v1146 = v1054 * 955; + let v1147 = v814 + v1146; + let v1148 = v814 - v1146; + let v1149 = v1055 * 790; + let v1150 = v815 + v1149; + let v1151 = v815 - v1149; + let v1152 = v1057 * 544; + let v1153 = v481 + v1152; + let v1154 = v481 - v1152; + let v1155 = v1058 * 5791; + let v1156 = v482 + v1155; + let v1157 = v482 - v1155; + let v1158 = v1060 * 339; + let v1159 = v484 + v1158; + let v1160 = v484 - v1158; + let v1161 = v1061 * 2468; + let v1162 = v485 + v1161; + let v1163 = v485 - v1161; + let v1164 = v1063 * 2842; + let v1165 = v487 + v1164; + let v1166 = v487 - v1164; + let v1167 = v1064 * 480; + let v1168 = v488 + v1167; + let v1169 = v488 - v1167; + let v1170 = v1066 * 9; + let v1171 = v490 + v1170; + let v1172 = v490 - v1170; + let v1173 = v1067 * 1022; + let v1174 = v491 + v1173; + let v1175 = v491 - v1173; + let v1176 = v1069 * 4278; + let v1177 = v493 + v1176; + let v1178 = v493 - v1176; + let v1179 = v1070 * 1673; + let v1180 = v494 + v1179; + let v1181 = v494 - v1179; + let v1182 = v1072 * 4989; + let v1183 = v496 + v1182; + let v1184 = v496 - v1182; + let v1185 = v1073 * 5331; + let v1186 = v497 + v1185; + let v1187 = v497 - v1185; + let v1188 = v1075 * 3584; + let v1189 = v499 + v1188; + let v1190 = v499 - v1188; + let v1191 = v1076 * 4177; + let v1192 = v500 + v1191; + let v1193 = v500 - v1191; + let v1194 = v1078 * 1381; + let v1195 = v502 + v1194; + let v1196 = v502 - v1194; + let v1197 = v1079 * 2525; + let v1198 = v503 + v1197; + let v1199 = v503 - v1197; + let v1200 = v1081 * 2396; + let v1201 = v505 + v1200; + let v1202 = v505 - v1200; + let v1203 = v1082 * 4452; + let v1204 = v506 + v1203; + let v1205 = v506 - v1203; + let v1206 = v1084 * 3296; + let v1207 = v508 + v1206; + let v1208 = v508 - v1206; + let v1209 = v1085 * 3949; + let v1210 = v509 + v1209; + let v1211 = v509 - v1209; + let v1212 = v1087 * 130; + let v1213 = v511 + v1212; + let v1214 = v511 - v1212; + let v1215 = v1088 * 4354; + let v1216 = v512 + v1215; + let v1217 = v512 - v1215; + let v1218 = v1090 * 5374; + let v1219 = v514 + v1218; + let v1220 = v514 - v1218; + let v1221 = v1091 * 2837; + let v1222 = v515 + v1221; + let v1223 = v515 - v1221; + let v1224 = v1093 * 5767; + let v1225 = v517 + v1224; + let v1226 = v517 - v1224; + let v1227 = v1094 * 827; + let v1228 = v518 + v1227; + let v1229 = v518 - v1227; + let v1230 = v1096 * 3748; + let v1231 = v520 + v1230; + let v1232 = v520 - v1230; + let v1233 = v1097 * 953; + let v1234 = v521 + v1233; + let v1235 = v521 - v1233; + let v1236 = v1099 * 5067; + let v1237 = v523 + v1236; + let v1238 = v523 - v1236; + let v1239 = v1100 * 2197; + let v1240 = v524 + v1239; + let v1241 = v524 - v1239; + let v1242 = v1102 * 118; + let v1243 = v526 + v1242; + let v1244 = v526 - v1242; + let v1245 = v1103 * 2476; + let v1246 = v527 + v1245; + let v1247 = v527 - v1245; + let v1248 = v1105 * 2548; + let v1249 = v529 + v1248; + let v1250 = v529 - v1248; + let v1251 = v1106 * 4231; + let v1252 = v530 + v1251; + let v1253 = v530 - v1251; + let v1254 = v1108 * 355; + let v1255 = v532 + v1254; + let v1256 = v532 - v1254; + let v1257 = v1109 * 3382; + let v1258 = v533 + v1257; + let v1259 = v533 - v1257; + let v1260 = v1111 * 3707; + let v1261 = v535 + v1260; + let v1262 = v535 - v1260; + let v1263 = v1112 * 1759; + let v1264 = v536 + v1263; + let v1265 = v536 - v1263; + let v1266 = v1114 * 3694; + let v1267 = v538 + v1266; + let v1268 = v538 - v1266; + let v1269 = v1115 * 5179; + let v1270 = v539 + v1269; + let v1271 = v539 - v1269; + let v1272 = v1117 * 5542; + let v1273 = v541 + v1272; + let v1274 = v541 - v1272; + let v1275 = v1118 * 145; + let v1276 = v542 + v1275; + let v1277 = v542 - v1275; + let v1278 = v1120 * 3637; + let v1279 = v544 + v1278; + let v1280 = v544 - v1278; + let v1281 = v1121 * 3459; + let v1282 = v545 + v1281; + let v1283 = v545 - v1281; + let v1284 = v1123 * 5911; + let v1285 = v547 + v1284; + let v1286 = v547 - v1284; + let v1287 = v1124 * 4890; + let v1288 = v548 + v1287; + let v1289 = v548 - v1287; + let v1290 = v1126 * 3932; + let v1291 = v550 + v1290; + let v1292 = v550 - v1290; + let v1293 = v1127 * 2731; + let v1294 = v551 + v1293; + let v1295 = v551 - v1293; + let v1296 = v1129 * 2089; + let v1297 = v553 + v1296; + let v1298 = v553 - v1296; + let v1299 = v1130 * 5092; + let v1300 = v554 + v1299; + let v1301 = v554 - v1299; + let v1302 = v1132 * 2881; + let v1303 = v556 + v1302; + let v1304 = v556 - v1302; + let v1305 = v1133 * 3284; + let v1306 = v557 + v1305; + let v1307 = v557 - v1305; + let v1308 = v1135 * 729; + let v1309 = v559 + v1308; + let v1310 = v559 - v1308; + let v1311 = v1136 * 3241; + let v1312 = v560 + v1311; + let v1313 = v560 - v1311; + let v1314 = v1138 * 3289; + let v1315 = v562 + v1314; + let v1316 = v562 - v1314; + let v1317 = v1139 * 2013; + let v1318 = v563 + v1317; + let v1319 = v563 - v1317; + let v1320 = v1141 * 5755; + let v1321 = v565 + v1320; + let v1322 = v565 - v1320; + let v1323 = v1142 * 4632; + let v1324 = v566 + v1323; + let v1325 = v566 - v1323; + let v1326 = v1144 * 1260; + let v1327 = v568 + v1326; + let v1328 = v568 - v1326; + let v1329 = v1145 * 4388; + let v1330 = v569 + v1329; + let v1331 = v569 - v1329; + let v1332 = v1147 * 334; + let v1333 = v571 + v1332; + let v1334 = v571 - v1332; + let v1335 = v1148 * 2426; + let v1336 = v572 + v1335; + let v1337 = v572 - v1335; + let v1338 = v1150 * 1696; + let v1339 = v574 + v1338; + let v1340 = v574 - v1338; + let v1341 = v1151 * 1428; + let v1342 = v575 + v1341; + let v1343 = v575 - v1341; + let v1344 = f258 * 1479; + let v1345 = f2 + v1344; + let v1346 = f2 - v1344; + let v1347 = f386 * 1479; + let v1348 = f130 + v1347; + let v1349 = f130 - v1347; + let v1350 = v1348 * 4043; + let v1351 = v1345 + v1350; + let v1352 = v1345 - v1350; + let v1353 = v1349 * 5146; + let v1354 = v1346 + v1353; + let v1355 = v1346 - v1353; + let v1356 = f322 * 1479; + let v1357 = f66 + v1356; + let v1358 = f66 - v1356; + let v1359 = f450 * 1479; + let v1360 = f194 + v1359; + let v1361 = f194 - v1359; + let v1362 = v1360 * 4043; + let v1363 = v1357 + v1362; + let v1364 = v1357 - v1362; + let v1365 = v1361 * 5146; + let v1366 = v1358 + v1365; + let v1367 = v1358 - v1365; + let v1368 = v1363 * 5736; + let v1369 = v1351 + v1368; + let v1370 = v1351 - v1368; + let v1371 = v1364 * 4134; + let v1372 = v1352 + v1371; + let v1373 = v1352 - v1371; + let v1374 = v1366 * 722; + let v1375 = v1354 + v1374; + let v1376 = v1354 - v1374; + let v1377 = v1367 * 1305; + let v1378 = v1355 + v1377; + let v1379 = v1355 - v1377; + let v1380 = f290 * 1479; + let v1381 = f34 + v1380; + let v1382 = f34 - v1380; + let v1383 = f418 * 1479; + let v1384 = f162 + v1383; + let v1385 = f162 - v1383; + let v1386 = v1384 * 4043; + let v1387 = v1381 + v1386; + let v1388 = v1381 - v1386; + let v1389 = v1385 * 5146; + let v1390 = v1382 + v1389; + let v1391 = v1382 - v1389; + let v1392 = f354 * 1479; + let v1393 = f98 + v1392; + let v1394 = f98 - v1392; + let v1395 = f482 * 1479; + let v1396 = f226 + v1395; + let v1397 = f226 - v1395; + let v1398 = v1396 * 4043; + let v1399 = v1393 + v1398; + let v1400 = v1393 - v1398; + let v1401 = v1397 * 5146; + let v1402 = v1394 + v1401; + let v1403 = v1394 - v1401; + let v1404 = v1399 * 5736; + let v1405 = v1387 + v1404; + let v1406 = v1387 - v1404; + let v1407 = v1400 * 4134; + let v1408 = v1388 + v1407; + let v1409 = v1388 - v1407; + let v1410 = v1402 * 722; + let v1411 = v1390 + v1410; + let v1412 = v1390 - v1410; + let v1413 = v1403 * 1305; + let v1414 = v1391 + v1413; + let v1415 = v1391 - v1413; + let v1416 = v1405 * 1646; + let v1417 = v1369 + v1416; + let v1418 = v1369 - v1416; + let v1419 = v1406 * 1212; + let v1420 = v1370 + v1419; + let v1421 = v1370 - v1419; + let v1422 = v1408 * 5860; + let v1423 = v1372 + v1422; + let v1424 = v1372 - v1422; + let v1425 = v1409 * 3195; + let v1426 = v1373 + v1425; + let v1427 = v1373 - v1425; + let v1428 = v1411 * 2545; + let v1429 = v1375 + v1428; + let v1430 = v1375 - v1428; + let v1431 = v1412 * 3621; + let v1432 = v1376 + v1431; + let v1433 = v1376 - v1431; + let v1434 = v1414 * 3504; + let v1435 = v1378 + v1434; + let v1436 = v1378 - v1434; + let v1437 = v1415 * 3542; + let v1438 = v1379 + v1437; + let v1439 = v1379 - v1437; + let v1440 = f274 * 1479; + let v1441 = f18 + v1440; + let v1442 = f18 - v1440; + let v1443 = f402 * 1479; + let v1444 = f146 + v1443; + let v1445 = f146 - v1443; + let v1446 = v1444 * 4043; + let v1447 = v1441 + v1446; + let v1448 = v1441 - v1446; + let v1449 = v1445 * 5146; + let v1450 = v1442 + v1449; + let v1451 = v1442 - v1449; + let v1452 = f338 * 1479; + let v1453 = f82 + v1452; + let v1454 = f82 - v1452; + let v1455 = f466 * 1479; + let v1456 = f210 + v1455; + let v1457 = f210 - v1455; + let v1458 = v1456 * 4043; + let v1459 = v1453 + v1458; + let v1460 = v1453 - v1458; + let v1461 = v1457 * 5146; + let v1462 = v1454 + v1461; + let v1463 = v1454 - v1461; + let v1464 = v1459 * 5736; + let v1465 = v1447 + v1464; + let v1466 = v1447 - v1464; + let v1467 = v1460 * 4134; + let v1468 = v1448 + v1467; + let v1469 = v1448 - v1467; + let v1470 = v1462 * 722; + let v1471 = v1450 + v1470; + let v1472 = v1450 - v1470; + let v1473 = v1463 * 1305; + let v1474 = v1451 + v1473; + let v1475 = v1451 - v1473; + let v1476 = f306 * 1479; + let v1477 = f50 + v1476; + let v1478 = f50 - v1476; + let v1479 = f434 * 1479; + let v1480 = f178 + v1479; + let v1481 = f178 - v1479; + let v1482 = v1480 * 4043; + let v1483 = v1477 + v1482; + let v1484 = v1477 - v1482; + let v1485 = v1481 * 5146; + let v1486 = v1478 + v1485; + let v1487 = v1478 - v1485; + let v1488 = f370 * 1479; + let v1489 = f114 + v1488; + let v1490 = f114 - v1488; + let v1491 = f498 * 1479; + let v1492 = f242 + v1491; + let v1493 = f242 - v1491; + let v1494 = v1492 * 4043; + let v1495 = v1489 + v1494; + let v1496 = v1489 - v1494; + let v1497 = v1493 * 5146; + let v1498 = v1490 + v1497; + let v1499 = v1490 - v1497; + let v1500 = v1495 * 5736; + let v1501 = v1483 + v1500; + let v1502 = v1483 - v1500; + let v1503 = v1496 * 4134; + let v1504 = v1484 + v1503; + let v1505 = v1484 - v1503; + let v1506 = v1498 * 722; + let v1507 = v1486 + v1506; + let v1508 = v1486 - v1506; + let v1509 = v1499 * 1305; + let v1510 = v1487 + v1509; + let v1511 = v1487 - v1509; + let v1512 = v1501 * 1646; + let v1513 = v1465 + v1512; + let v1514 = v1465 - v1512; + let v1515 = v1502 * 1212; + let v1516 = v1466 + v1515; + let v1517 = v1466 - v1515; + let v1518 = v1504 * 5860; + let v1519 = v1468 + v1518; + let v1520 = v1468 - v1518; + let v1521 = v1505 * 3195; + let v1522 = v1469 + v1521; + let v1523 = v1469 - v1521; + let v1524 = v1507 * 2545; + let v1525 = v1471 + v1524; + let v1526 = v1471 - v1524; + let v1527 = v1508 * 3621; + let v1528 = v1472 + v1527; + let v1529 = v1472 - v1527; + let v1530 = v1510 * 3504; + let v1531 = v1474 + v1530; + let v1532 = v1474 - v1530; + let v1533 = v1511 * 3542; + let v1534 = v1475 + v1533; + let v1535 = v1475 - v1533; + let v1536 = v1513 * 4591; + let v1537 = v1417 + v1536; + let v1538 = v1417 - v1536; + let v1539 = v1514 * 5728; + let v1540 = v1418 + v1539; + let v1541 = v1418 - v1539; + let v1542 = v1516 * 5023; + let v1543 = v1420 + v1542; + let v1544 = v1420 - v1542; + let v1545 = v1517 * 5828; + let v1546 = v1421 + v1545; + let v1547 = v1421 - v1545; + let v1548 = v1519 * 4978; + let v1549 = v1423 + v1548; + let v1550 = v1423 - v1548; + let v1551 = v1520 * 1351; + let v1552 = v1424 + v1551; + let v1553 = v1424 - v1551; + let v1554 = v1522 * 3328; + let v1555 = v1426 + v1554; + let v1556 = v1426 - v1554; + let v1557 = v1523 * 5777; + let v1558 = v1427 + v1557; + let v1559 = v1427 - v1557; + let v1560 = v1525 * 2975; + let v1561 = v1429 + v1560; + let v1562 = v1429 - v1560; + let v1563 = v1526 * 563; + let v1564 = v1430 + v1563; + let v1565 = v1430 - v1563; + let v1566 = v1528 * 3006; + let v1567 = v1432 + v1566; + let v1568 = v1432 - v1566; + let v1569 = v1529 * 2744; + let v1570 = v1433 + v1569; + let v1571 = v1433 - v1569; + let v1572 = v1531 * 949; + let v1573 = v1435 + v1572; + let v1574 = v1435 - v1572; + let v1575 = v1532 * 2625; + let v1576 = v1436 + v1575; + let v1577 = v1436 - v1575; + let v1578 = v1534 * 4821; + let v1579 = v1438 + v1578; + let v1580 = v1438 - v1578; + let v1581 = v1535 * 2639; + let v1582 = v1439 + v1581; + let v1583 = v1439 - v1581; + let v1584 = f266 * 1479; + let v1585 = f10 + v1584; + let v1586 = f10 - v1584; + let v1587 = f394 * 1479; + let v1588 = f138 + v1587; + let v1589 = f138 - v1587; + let v1590 = v1588 * 4043; + let v1591 = v1585 + v1590; + let v1592 = v1585 - v1590; + let v1593 = v1589 * 5146; + let v1594 = v1586 + v1593; + let v1595 = v1586 - v1593; + let v1596 = f330 * 1479; + let v1597 = f74 + v1596; + let v1598 = f74 - v1596; + let v1599 = f458 * 1479; + let v1600 = f202 + v1599; + let v1601 = f202 - v1599; + let v1602 = v1600 * 4043; + let v1603 = v1597 + v1602; + let v1604 = v1597 - v1602; + let v1605 = v1601 * 5146; + let v1606 = v1598 + v1605; + let v1607 = v1598 - v1605; + let v1608 = v1603 * 5736; + let v1609 = v1591 + v1608; + let v1610 = v1591 - v1608; + let v1611 = v1604 * 4134; + let v1612 = v1592 + v1611; + let v1613 = v1592 - v1611; + let v1614 = v1606 * 722; + let v1615 = v1594 + v1614; + let v1616 = v1594 - v1614; + let v1617 = v1607 * 1305; + let v1618 = v1595 + v1617; + let v1619 = v1595 - v1617; + let v1620 = f298 * 1479; + let v1621 = f42 + v1620; + let v1622 = f42 - v1620; + let v1623 = f426 * 1479; + let v1624 = f170 + v1623; + let v1625 = f170 - v1623; + let v1626 = v1624 * 4043; + let v1627 = v1621 + v1626; + let v1628 = v1621 - v1626; + let v1629 = v1625 * 5146; + let v1630 = v1622 + v1629; + let v1631 = v1622 - v1629; + let v1632 = f362 * 1479; + let v1633 = f106 + v1632; + let v1634 = f106 - v1632; + let v1635 = f490 * 1479; + let v1636 = f234 + v1635; + let v1637 = f234 - v1635; + let v1638 = v1636 * 4043; + let v1639 = v1633 + v1638; + let v1640 = v1633 - v1638; + let v1641 = v1637 * 5146; + let v1642 = v1634 + v1641; + let v1643 = v1634 - v1641; + let v1644 = v1639 * 5736; + let v1645 = v1627 + v1644; + let v1646 = v1627 - v1644; + let v1647 = v1640 * 4134; + let v1648 = v1628 + v1647; + let v1649 = v1628 - v1647; + let v1650 = v1642 * 722; + let v1651 = v1630 + v1650; + let v1652 = v1630 - v1650; + let v1653 = v1643 * 1305; + let v1654 = v1631 + v1653; + let v1655 = v1631 - v1653; + let v1656 = v1645 * 1646; + let v1657 = v1609 + v1656; + let v1658 = v1609 - v1656; + let v1659 = v1646 * 1212; + let v1660 = v1610 + v1659; + let v1661 = v1610 - v1659; + let v1662 = v1648 * 5860; + let v1663 = v1612 + v1662; + let v1664 = v1612 - v1662; + let v1665 = v1649 * 3195; + let v1666 = v1613 + v1665; + let v1667 = v1613 - v1665; + let v1668 = v1651 * 2545; + let v1669 = v1615 + v1668; + let v1670 = v1615 - v1668; + let v1671 = v1652 * 3621; + let v1672 = v1616 + v1671; + let v1673 = v1616 - v1671; + let v1674 = v1654 * 3504; + let v1675 = v1618 + v1674; + let v1676 = v1618 - v1674; + let v1677 = v1655 * 3542; + let v1678 = v1619 + v1677; + let v1679 = v1619 - v1677; + let v1680 = f282 * 1479; + let v1681 = f26 + v1680; + let v1682 = f26 - v1680; + let v1683 = f410 * 1479; + let v1684 = f154 + v1683; + let v1685 = f154 - v1683; + let v1686 = v1684 * 4043; + let v1687 = v1681 + v1686; + let v1688 = v1681 - v1686; + let v1689 = v1685 * 5146; + let v1690 = v1682 + v1689; + let v1691 = v1682 - v1689; + let v1692 = f346 * 1479; + let v1693 = f90 + v1692; + let v1694 = f90 - v1692; + let v1695 = f474 * 1479; + let v1696 = f218 + v1695; + let v1697 = f218 - v1695; + let v1698 = v1696 * 4043; + let v1699 = v1693 + v1698; + let v1700 = v1693 - v1698; + let v1701 = v1697 * 5146; + let v1702 = v1694 + v1701; + let v1703 = v1694 - v1701; + let v1704 = v1699 * 5736; + let v1705 = v1687 + v1704; + let v1706 = v1687 - v1704; + let v1707 = v1700 * 4134; + let v1708 = v1688 + v1707; + let v1709 = v1688 - v1707; + let v1710 = v1702 * 722; + let v1711 = v1690 + v1710; + let v1712 = v1690 - v1710; + let v1713 = v1703 * 1305; + let v1714 = v1691 + v1713; + let v1715 = v1691 - v1713; + let v1716 = f314 * 1479; + let v1717 = f58 + v1716; + let v1718 = f58 - v1716; + let v1719 = f442 * 1479; + let v1720 = f186 + v1719; + let v1721 = f186 - v1719; + let v1722 = v1720 * 4043; + let v1723 = v1717 + v1722; + let v1724 = v1717 - v1722; + let v1725 = v1721 * 5146; + let v1726 = v1718 + v1725; + let v1727 = v1718 - v1725; + let v1728 = f378 * 1479; + let v1729 = f122 + v1728; + let v1730 = f122 - v1728; + let v1731 = f506 * 1479; + let v1732 = f250 + v1731; + let v1733 = f250 - v1731; + let v1734 = v1732 * 4043; + let v1735 = v1729 + v1734; + let v1736 = v1729 - v1734; + let v1737 = v1733 * 5146; + let v1738 = v1730 + v1737; + let v1739 = v1730 - v1737; + let v1740 = v1735 * 5736; + let v1741 = v1723 + v1740; + let v1742 = v1723 - v1740; + let v1743 = v1736 * 4134; + let v1744 = v1724 + v1743; + let v1745 = v1724 - v1743; + let v1746 = v1738 * 722; + let v1747 = v1726 + v1746; + let v1748 = v1726 - v1746; + let v1749 = v1739 * 1305; + let v1750 = v1727 + v1749; + let v1751 = v1727 - v1749; + let v1752 = v1741 * 1646; + let v1753 = v1705 + v1752; + let v1754 = v1705 - v1752; + let v1755 = v1742 * 1212; + let v1756 = v1706 + v1755; + let v1757 = v1706 - v1755; + let v1758 = v1744 * 5860; + let v1759 = v1708 + v1758; + let v1760 = v1708 - v1758; + let v1761 = v1745 * 3195; + let v1762 = v1709 + v1761; + let v1763 = v1709 - v1761; + let v1764 = v1747 * 2545; + let v1765 = v1711 + v1764; + let v1766 = v1711 - v1764; + let v1767 = v1748 * 3621; + let v1768 = v1712 + v1767; + let v1769 = v1712 - v1767; + let v1770 = v1750 * 3504; + let v1771 = v1714 + v1770; + let v1772 = v1714 - v1770; + let v1773 = v1751 * 3542; + let v1774 = v1715 + v1773; + let v1775 = v1715 - v1773; + let v1776 = v1753 * 4591; + let v1777 = v1657 + v1776; + let v1778 = v1657 - v1776; + let v1779 = v1754 * 5728; + let v1780 = v1658 + v1779; + let v1781 = v1658 - v1779; + let v1782 = v1756 * 5023; + let v1783 = v1660 + v1782; + let v1784 = v1660 - v1782; + let v1785 = v1757 * 5828; + let v1786 = v1661 + v1785; + let v1787 = v1661 - v1785; + let v1788 = v1759 * 4978; + let v1789 = v1663 + v1788; + let v1790 = v1663 - v1788; + let v1791 = v1760 * 1351; + let v1792 = v1664 + v1791; + let v1793 = v1664 - v1791; + let v1794 = v1762 * 3328; + let v1795 = v1666 + v1794; + let v1796 = v1666 - v1794; + let v1797 = v1763 * 5777; + let v1798 = v1667 + v1797; + let v1799 = v1667 - v1797; + let v1800 = v1765 * 2975; + let v1801 = v1669 + v1800; + let v1802 = v1669 - v1800; + let v1803 = v1766 * 563; + let v1804 = v1670 + v1803; + let v1805 = v1670 - v1803; + let v1806 = v1768 * 3006; + let v1807 = v1672 + v1806; + let v1808 = v1672 - v1806; + let v1809 = v1769 * 2744; + let v1810 = v1673 + v1809; + let v1811 = v1673 - v1809; + let v1812 = v1771 * 949; + let v1813 = v1675 + v1812; + let v1814 = v1675 - v1812; + let v1815 = v1772 * 2625; + let v1816 = v1676 + v1815; + let v1817 = v1676 - v1815; + let v1818 = v1774 * 4821; + let v1819 = v1678 + v1818; + let v1820 = v1678 - v1818; + let v1821 = v1775 * 2639; + let v1822 = v1679 + v1821; + let v1823 = v1679 - v1821; + let v1824 = v1777 * 1000; + let v1825 = v1537 + v1824; + let v1826 = v1537 - v1824; + let v1827 = v1778 * 4320; + let v1828 = v1538 + v1827; + let v1829 = v1538 - v1827; + let v1830 = v1780 * 3091; + let v1831 = v1540 + v1830; + let v1832 = v1540 - v1830; + let v1833 = v1781 * 81; + let v1834 = v1541 + v1833; + let v1835 = v1541 - v1833; + let v1836 = v1783 * 2963; + let v1837 = v1543 + v1836; + let v1838 = v1543 - v1836; + let v1839 = v1784 * 4896; + let v1840 = v1544 + v1839; + let v1841 = v1544 - v1839; + let v1842 = v1786 * 3051; + let v1843 = v1546 + v1842; + let v1844 = v1546 - v1842; + let v1845 = v1787 * 2366; + let v1846 = v1547 + v1845; + let v1847 = v1547 - v1845; + let v1848 = v1789 * 1853; + let v1849 = v1549 + v1848; + let v1850 = v1549 - v1848; + let v1851 = v1790 * 140; + let v1852 = v1550 + v1851; + let v1853 = v1550 - v1851; + let v1854 = v1792 * 4611; + let v1855 = v1552 + v1854; + let v1856 = v1552 - v1854; + let v1857 = v1793 * 726; + let v1858 = v1553 + v1857; + let v1859 = v1553 - v1857; + let v1860 = v1795 * 4255; + let v1861 = v1555 + v1860; + let v1862 = v1555 - v1860; + let v1863 = v1796 * 1177; + let v1864 = v1556 + v1863; + let v1865 = v1556 - v1863; + let v1866 = v1798 * 2768; + let v1867 = v1558 + v1866; + let v1868 = v1558 - v1866; + let v1869 = v1799 * 1635; + let v1870 = v1559 + v1869; + let v1871 = v1559 - v1869; + let v1872 = v1801 * 3712; + let v1873 = v1561 + v1872; + let v1874 = v1561 - v1872; + let v1875 = v1802 * 3135; + let v1876 = v1562 + v1875; + let v1877 = v1562 - v1875; + let v1878 = v1804 * 2747; + let v1879 = v1564 + v1878; + let v1880 = v1564 - v1878; + let v1881 = v1805 * 4846; + let v1882 = v1565 + v1881; + let v1883 = v1565 - v1881; + let v1884 = v1807 * 3553; + let v1885 = v1567 + v1884; + let v1886 = v1567 - v1884; + let v1887 = v1808 * 4805; + let v1888 = v1568 + v1887; + let v1889 = v1568 - v1887; + let v1890 = v1810 * 2294; + let v1891 = v1570 + v1890; + let v1892 = v1570 - v1890; + let v1893 = v1811 * 1062; + let v1894 = v1571 + v1893; + let v1895 = v1571 - v1893; + let v1896 = v1813 * 1326; + let v1897 = v1573 + v1896; + let v1898 = v1573 - v1896; + let v1899 = v1814 * 5086; + let v1900 = v1574 + v1899; + let v1901 = v1574 - v1899; + let v1902 = v1816 * 3014; + let v1903 = v1576 + v1902; + let v1904 = v1576 - v1902; + let v1905 = v1817 * 3201; + let v1906 = v1577 + v1905; + let v1907 = v1577 - v1905; + let v1908 = v1819 * 1170; + let v1909 = v1579 + v1908; + let v1910 = v1579 - v1908; + let v1911 = v1820 * 2319; + let v1912 = v1580 + v1911; + let v1913 = v1580 - v1911; + let v1914 = v1822 * 955; + let v1915 = v1582 + v1914; + let v1916 = v1582 - v1914; + let v1917 = v1823 * 790; + let v1918 = v1583 + v1917; + let v1919 = v1583 - v1917; + let v1920 = f262 * 1479; + let v1921 = f6 + v1920; + let v1922 = f6 - v1920; + let v1923 = f390 * 1479; + let v1924 = f134 + v1923; + let v1925 = f134 - v1923; + let v1926 = v1924 * 4043; + let v1927 = v1921 + v1926; + let v1928 = v1921 - v1926; + let v1929 = v1925 * 5146; + let v1930 = v1922 + v1929; + let v1931 = v1922 - v1929; + let v1932 = f326 * 1479; + let v1933 = f70 + v1932; + let v1934 = f70 - v1932; + let v1935 = f454 * 1479; + let v1936 = f198 + v1935; + let v1937 = f198 - v1935; + let v1938 = v1936 * 4043; + let v1939 = v1933 + v1938; + let v1940 = v1933 - v1938; + let v1941 = v1937 * 5146; + let v1942 = v1934 + v1941; + let v1943 = v1934 - v1941; + let v1944 = v1939 * 5736; + let v1945 = v1927 + v1944; + let v1946 = v1927 - v1944; + let v1947 = v1940 * 4134; + let v1948 = v1928 + v1947; + let v1949 = v1928 - v1947; + let v1950 = v1942 * 722; + let v1951 = v1930 + v1950; + let v1952 = v1930 - v1950; + let v1953 = v1943 * 1305; + let v1954 = v1931 + v1953; + let v1955 = v1931 - v1953; + let v1956 = f294 * 1479; + let v1957 = f38 + v1956; + let v1958 = f38 - v1956; + let v1959 = f422 * 1479; + let v1960 = f166 + v1959; + let v1961 = f166 - v1959; + let v1962 = v1960 * 4043; + let v1963 = v1957 + v1962; + let v1964 = v1957 - v1962; + let v1965 = v1961 * 5146; + let v1966 = v1958 + v1965; + let v1967 = v1958 - v1965; + let v1968 = f358 * 1479; + let v1969 = f102 + v1968; + let v1970 = f102 - v1968; + let v1971 = f486 * 1479; + let v1972 = f230 + v1971; + let v1973 = f230 - v1971; + let v1974 = v1972 * 4043; + let v1975 = v1969 + v1974; + let v1976 = v1969 - v1974; + let v1977 = v1973 * 5146; + let v1978 = v1970 + v1977; + let v1979 = v1970 - v1977; + let v1980 = v1975 * 5736; + let v1981 = v1963 + v1980; + let v1982 = v1963 - v1980; + let v1983 = v1976 * 4134; + let v1984 = v1964 + v1983; + let v1985 = v1964 - v1983; + let v1986 = v1978 * 722; + let v1987 = v1966 + v1986; + let v1988 = v1966 - v1986; + let v1989 = v1979 * 1305; + let v1990 = v1967 + v1989; + let v1991 = v1967 - v1989; + let v1992 = v1981 * 1646; + let v1993 = v1945 + v1992; + let v1994 = v1945 - v1992; + let v1995 = v1982 * 1212; + let v1996 = v1946 + v1995; + let v1997 = v1946 - v1995; + let v1998 = v1984 * 5860; + let v1999 = v1948 + v1998; + let v2000 = v1948 - v1998; + let v2001 = v1985 * 3195; + let v2002 = v1949 + v2001; + let v2003 = v1949 - v2001; + let v2004 = v1987 * 2545; + let v2005 = v1951 + v2004; + let v2006 = v1951 - v2004; + let v2007 = v1988 * 3621; + let v2008 = v1952 + v2007; + let v2009 = v1952 - v2007; + let v2010 = v1990 * 3504; + let v2011 = v1954 + v2010; + let v2012 = v1954 - v2010; + let v2013 = v1991 * 3542; + let v2014 = v1955 + v2013; + let v2015 = v1955 - v2013; + let v2016 = f278 * 1479; + let v2017 = f22 + v2016; + let v2018 = f22 - v2016; + let v2019 = f406 * 1479; + let v2020 = f150 + v2019; + let v2021 = f150 - v2019; + let v2022 = v2020 * 4043; + let v2023 = v2017 + v2022; + let v2024 = v2017 - v2022; + let v2025 = v2021 * 5146; + let v2026 = v2018 + v2025; + let v2027 = v2018 - v2025; + let v2028 = f342 * 1479; + let v2029 = f86 + v2028; + let v2030 = f86 - v2028; + let v2031 = f470 * 1479; + let v2032 = f214 + v2031; + let v2033 = f214 - v2031; + let v2034 = v2032 * 4043; + let v2035 = v2029 + v2034; + let v2036 = v2029 - v2034; + let v2037 = v2033 * 5146; + let v2038 = v2030 + v2037; + let v2039 = v2030 - v2037; + let v2040 = v2035 * 5736; + let v2041 = v2023 + v2040; + let v2042 = v2023 - v2040; + let v2043 = v2036 * 4134; + let v2044 = v2024 + v2043; + let v2045 = v2024 - v2043; + let v2046 = v2038 * 722; + let v2047 = v2026 + v2046; + let v2048 = v2026 - v2046; + let v2049 = v2039 * 1305; + let v2050 = v2027 + v2049; + let v2051 = v2027 - v2049; + let v2052 = f310 * 1479; + let v2053 = f54 + v2052; + let v2054 = f54 - v2052; + let v2055 = f438 * 1479; + let v2056 = f182 + v2055; + let v2057 = f182 - v2055; + let v2058 = v2056 * 4043; + let v2059 = v2053 + v2058; + let v2060 = v2053 - v2058; + let v2061 = v2057 * 5146; + let v2062 = v2054 + v2061; + let v2063 = v2054 - v2061; + let v2064 = f374 * 1479; + let v2065 = f118 + v2064; + let v2066 = f118 - v2064; + let v2067 = f502 * 1479; + let v2068 = f246 + v2067; + let v2069 = f246 - v2067; + let v2070 = v2068 * 4043; + let v2071 = v2065 + v2070; + let v2072 = v2065 - v2070; + let v2073 = v2069 * 5146; + let v2074 = v2066 + v2073; + let v2075 = v2066 - v2073; + let v2076 = v2071 * 5736; + let v2077 = v2059 + v2076; + let v2078 = v2059 - v2076; + let v2079 = v2072 * 4134; + let v2080 = v2060 + v2079; + let v2081 = v2060 - v2079; + let v2082 = v2074 * 722; + let v2083 = v2062 + v2082; + let v2084 = v2062 - v2082; + let v2085 = v2075 * 1305; + let v2086 = v2063 + v2085; + let v2087 = v2063 - v2085; + let v2088 = v2077 * 1646; + let v2089 = v2041 + v2088; + let v2090 = v2041 - v2088; + let v2091 = v2078 * 1212; + let v2092 = v2042 + v2091; + let v2093 = v2042 - v2091; + let v2094 = v2080 * 5860; + let v2095 = v2044 + v2094; + let v2096 = v2044 - v2094; + let v2097 = v2081 * 3195; + let v2098 = v2045 + v2097; + let v2099 = v2045 - v2097; + let v2100 = v2083 * 2545; + let v2101 = v2047 + v2100; + let v2102 = v2047 - v2100; + let v2103 = v2084 * 3621; + let v2104 = v2048 + v2103; + let v2105 = v2048 - v2103; + let v2106 = v2086 * 3504; + let v2107 = v2050 + v2106; + let v2108 = v2050 - v2106; + let v2109 = v2087 * 3542; + let v2110 = v2051 + v2109; + let v2111 = v2051 - v2109; + let v2112 = v2089 * 4591; + let v2113 = v1993 + v2112; + let v2114 = v1993 - v2112; + let v2115 = v2090 * 5728; + let v2116 = v1994 + v2115; + let v2117 = v1994 - v2115; + let v2118 = v2092 * 5023; + let v2119 = v1996 + v2118; + let v2120 = v1996 - v2118; + let v2121 = v2093 * 5828; + let v2122 = v1997 + v2121; + let v2123 = v1997 - v2121; + let v2124 = v2095 * 4978; + let v2125 = v1999 + v2124; + let v2126 = v1999 - v2124; + let v2127 = v2096 * 1351; + let v2128 = v2000 + v2127; + let v2129 = v2000 - v2127; + let v2130 = v2098 * 3328; + let v2131 = v2002 + v2130; + let v2132 = v2002 - v2130; + let v2133 = v2099 * 5777; + let v2134 = v2003 + v2133; + let v2135 = v2003 - v2133; + let v2136 = v2101 * 2975; + let v2137 = v2005 + v2136; + let v2138 = v2005 - v2136; + let v2139 = v2102 * 563; + let v2140 = v2006 + v2139; + let v2141 = v2006 - v2139; + let v2142 = v2104 * 3006; + let v2143 = v2008 + v2142; + let v2144 = v2008 - v2142; + let v2145 = v2105 * 2744; + let v2146 = v2009 + v2145; + let v2147 = v2009 - v2145; + let v2148 = v2107 * 949; + let v2149 = v2011 + v2148; + let v2150 = v2011 - v2148; + let v2151 = v2108 * 2625; + let v2152 = v2012 + v2151; + let v2153 = v2012 - v2151; + let v2154 = v2110 * 4821; + let v2155 = v2014 + v2154; + let v2156 = v2014 - v2154; + let v2157 = v2111 * 2639; + let v2158 = v2015 + v2157; + let v2159 = v2015 - v2157; + let v2160 = f270 * 1479; + let v2161 = f14 + v2160; + let v2162 = f14 - v2160; + let v2163 = f398 * 1479; + let v2164 = f142 + v2163; + let v2165 = f142 - v2163; + let v2166 = v2164 * 4043; + let v2167 = v2161 + v2166; + let v2168 = v2161 - v2166; + let v2169 = v2165 * 5146; + let v2170 = v2162 + v2169; + let v2171 = v2162 - v2169; + let v2172 = f334 * 1479; + let v2173 = f78 + v2172; + let v2174 = f78 - v2172; + let v2175 = f462 * 1479; + let v2176 = f206 + v2175; + let v2177 = f206 - v2175; + let v2178 = v2176 * 4043; + let v2179 = v2173 + v2178; + let v2180 = v2173 - v2178; + let v2181 = v2177 * 5146; + let v2182 = v2174 + v2181; + let v2183 = v2174 - v2181; + let v2184 = v2179 * 5736; + let v2185 = v2167 + v2184; + let v2186 = v2167 - v2184; + let v2187 = v2180 * 4134; + let v2188 = v2168 + v2187; + let v2189 = v2168 - v2187; + let v2190 = v2182 * 722; + let v2191 = v2170 + v2190; + let v2192 = v2170 - v2190; + let v2193 = v2183 * 1305; + let v2194 = v2171 + v2193; + let v2195 = v2171 - v2193; + let v2196 = f302 * 1479; + let v2197 = f46 + v2196; + let v2198 = f46 - v2196; + let v2199 = f430 * 1479; + let v2200 = f174 + v2199; + let v2201 = f174 - v2199; + let v2202 = v2200 * 4043; + let v2203 = v2197 + v2202; + let v2204 = v2197 - v2202; + let v2205 = v2201 * 5146; + let v2206 = v2198 + v2205; + let v2207 = v2198 - v2205; + let v2208 = f366 * 1479; + let v2209 = f110 + v2208; + let v2210 = f110 - v2208; + let v2211 = f494 * 1479; + let v2212 = f238 + v2211; + let v2213 = f238 - v2211; + let v2214 = v2212 * 4043; + let v2215 = v2209 + v2214; + let v2216 = v2209 - v2214; + let v2217 = v2213 * 5146; + let v2218 = v2210 + v2217; + let v2219 = v2210 - v2217; + let v2220 = v2215 * 5736; + let v2221 = v2203 + v2220; + let v2222 = v2203 - v2220; + let v2223 = v2216 * 4134; + let v2224 = v2204 + v2223; + let v2225 = v2204 - v2223; + let v2226 = v2218 * 722; + let v2227 = v2206 + v2226; + let v2228 = v2206 - v2226; + let v2229 = v2219 * 1305; + let v2230 = v2207 + v2229; + let v2231 = v2207 - v2229; + let v2232 = v2221 * 1646; + let v2233 = v2185 + v2232; + let v2234 = v2185 - v2232; + let v2235 = v2222 * 1212; + let v2236 = v2186 + v2235; + let v2237 = v2186 - v2235; + let v2238 = v2224 * 5860; + let v2239 = v2188 + v2238; + let v2240 = v2188 - v2238; + let v2241 = v2225 * 3195; + let v2242 = v2189 + v2241; + let v2243 = v2189 - v2241; + let v2244 = v2227 * 2545; + let v2245 = v2191 + v2244; + let v2246 = v2191 - v2244; + let v2247 = v2228 * 3621; + let v2248 = v2192 + v2247; + let v2249 = v2192 - v2247; + let v2250 = v2230 * 3504; + let v2251 = v2194 + v2250; + let v2252 = v2194 - v2250; + let v2253 = v2231 * 3542; + let v2254 = v2195 + v2253; + let v2255 = v2195 - v2253; + let v2256 = f286 * 1479; + let v2257 = f30 + v2256; + let v2258 = f30 - v2256; + let v2259 = f414 * 1479; + let v2260 = f158 + v2259; + let v2261 = f158 - v2259; + let v2262 = v2260 * 4043; + let v2263 = v2257 + v2262; + let v2264 = v2257 - v2262; + let v2265 = v2261 * 5146; + let v2266 = v2258 + v2265; + let v2267 = v2258 - v2265; + let v2268 = f350 * 1479; + let v2269 = f94 + v2268; + let v2270 = f94 - v2268; + let v2271 = f478 * 1479; + let v2272 = f222 + v2271; + let v2273 = f222 - v2271; + let v2274 = v2272 * 4043; + let v2275 = v2269 + v2274; + let v2276 = v2269 - v2274; + let v2277 = v2273 * 5146; + let v2278 = v2270 + v2277; + let v2279 = v2270 - v2277; + let v2280 = v2275 * 5736; + let v2281 = v2263 + v2280; + let v2282 = v2263 - v2280; + let v2283 = v2276 * 4134; + let v2284 = v2264 + v2283; + let v2285 = v2264 - v2283; + let v2286 = v2278 * 722; + let v2287 = v2266 + v2286; + let v2288 = v2266 - v2286; + let v2289 = v2279 * 1305; + let v2290 = v2267 + v2289; + let v2291 = v2267 - v2289; + let v2292 = f318 * 1479; + let v2293 = f62 + v2292; + let v2294 = f62 - v2292; + let v2295 = f446 * 1479; + let v2296 = f190 + v2295; + let v2297 = f190 - v2295; + let v2298 = v2296 * 4043; + let v2299 = v2293 + v2298; + let v2300 = v2293 - v2298; + let v2301 = v2297 * 5146; + let v2302 = v2294 + v2301; + let v2303 = v2294 - v2301; + let v2304 = f382 * 1479; + let v2305 = f126 + v2304; + let v2306 = f126 - v2304; + let v2307 = f510 * 1479; + let v2308 = f254 + v2307; + let v2309 = f254 - v2307; + let v2310 = v2308 * 4043; + let v2311 = v2305 + v2310; + let v2312 = v2305 - v2310; + let v2313 = v2309 * 5146; + let v2314 = v2306 + v2313; + let v2315 = v2306 - v2313; + let v2316 = v2311 * 5736; + let v2317 = v2299 + v2316; + let v2318 = v2299 - v2316; + let v2319 = v2312 * 4134; + let v2320 = v2300 + v2319; + let v2321 = v2300 - v2319; + let v2322 = v2314 * 722; + let v2323 = v2302 + v2322; + let v2324 = v2302 - v2322; + let v2325 = v2315 * 1305; + let v2326 = v2303 + v2325; + let v2327 = v2303 - v2325; + let v2328 = v2317 * 1646; + let v2329 = v2281 + v2328; + let v2330 = v2281 - v2328; + let v2331 = v2318 * 1212; + let v2332 = v2282 + v2331; + let v2333 = v2282 - v2331; + let v2334 = v2320 * 5860; + let v2335 = v2284 + v2334; + let v2336 = v2284 - v2334; + let v2337 = v2321 * 3195; + let v2338 = v2285 + v2337; + let v2339 = v2285 - v2337; + let v2340 = v2323 * 2545; + let v2341 = v2287 + v2340; + let v2342 = v2287 - v2340; + let v2343 = v2324 * 3621; + let v2344 = v2288 + v2343; + let v2345 = v2288 - v2343; + let v2346 = v2326 * 3504; + let v2347 = v2290 + v2346; + let v2348 = v2290 - v2346; + let v2349 = v2327 * 3542; + let v2350 = v2291 + v2349; + let v2351 = v2291 - v2349; + let v2352 = v2329 * 4591; + let v2353 = v2233 + v2352; + let v2354 = v2233 - v2352; + let v2355 = v2330 * 5728; + let v2356 = v2234 + v2355; + let v2357 = v2234 - v2355; + let v2358 = v2332 * 5023; + let v2359 = v2236 + v2358; + let v2360 = v2236 - v2358; + let v2361 = v2333 * 5828; + let v2362 = v2237 + v2361; + let v2363 = v2237 - v2361; + let v2364 = v2335 * 4978; + let v2365 = v2239 + v2364; + let v2366 = v2239 - v2364; + let v2367 = v2336 * 1351; + let v2368 = v2240 + v2367; + let v2369 = v2240 - v2367; + let v2370 = v2338 * 3328; + let v2371 = v2242 + v2370; + let v2372 = v2242 - v2370; + let v2373 = v2339 * 5777; + let v2374 = v2243 + v2373; + let v2375 = v2243 - v2373; + let v2376 = v2341 * 2975; + let v2377 = v2245 + v2376; + let v2378 = v2245 - v2376; + let v2379 = v2342 * 563; + let v2380 = v2246 + v2379; + let v2381 = v2246 - v2379; + let v2382 = v2344 * 3006; + let v2383 = v2248 + v2382; + let v2384 = v2248 - v2382; + let v2385 = v2345 * 2744; + let v2386 = v2249 + v2385; + let v2387 = v2249 - v2385; + let v2388 = v2347 * 949; + let v2389 = v2251 + v2388; + let v2390 = v2251 - v2388; + let v2391 = v2348 * 2625; + let v2392 = v2252 + v2391; + let v2393 = v2252 - v2391; + let v2394 = v2350 * 4821; + let v2395 = v2254 + v2394; + let v2396 = v2254 - v2394; + let v2397 = v2351 * 2639; + let v2398 = v2255 + v2397; + let v2399 = v2255 - v2397; + let v2400 = v2353 * 1000; + let v2401 = v2113 + v2400; + let v2402 = v2113 - v2400; + let v2403 = v2354 * 4320; + let v2404 = v2114 + v2403; + let v2405 = v2114 - v2403; + let v2406 = v2356 * 3091; + let v2407 = v2116 + v2406; + let v2408 = v2116 - v2406; + let v2409 = v2357 * 81; + let v2410 = v2117 + v2409; + let v2411 = v2117 - v2409; + let v2412 = v2359 * 2963; + let v2413 = v2119 + v2412; + let v2414 = v2119 - v2412; + let v2415 = v2360 * 4896; + let v2416 = v2120 + v2415; + let v2417 = v2120 - v2415; + let v2418 = v2362 * 3051; + let v2419 = v2122 + v2418; + let v2420 = v2122 - v2418; + let v2421 = v2363 * 2366; + let v2422 = v2123 + v2421; + let v2423 = v2123 - v2421; + let v2424 = v2365 * 1853; + let v2425 = v2125 + v2424; + let v2426 = v2125 - v2424; + let v2427 = v2366 * 140; + let v2428 = v2126 + v2427; + let v2429 = v2126 - v2427; + let v2430 = v2368 * 4611; + let v2431 = v2128 + v2430; + let v2432 = v2128 - v2430; + let v2433 = v2369 * 726; + let v2434 = v2129 + v2433; + let v2435 = v2129 - v2433; + let v2436 = v2371 * 4255; + let v2437 = v2131 + v2436; + let v2438 = v2131 - v2436; + let v2439 = v2372 * 1177; + let v2440 = v2132 + v2439; + let v2441 = v2132 - v2439; + let v2442 = v2374 * 2768; + let v2443 = v2134 + v2442; + let v2444 = v2134 - v2442; + let v2445 = v2375 * 1635; + let v2446 = v2135 + v2445; + let v2447 = v2135 - v2445; + let v2448 = v2377 * 3712; + let v2449 = v2137 + v2448; + let v2450 = v2137 - v2448; + let v2451 = v2378 * 3135; + let v2452 = v2138 + v2451; + let v2453 = v2138 - v2451; + let v2454 = v2380 * 2747; + let v2455 = v2140 + v2454; + let v2456 = v2140 - v2454; + let v2457 = v2381 * 4846; + let v2458 = v2141 + v2457; + let v2459 = v2141 - v2457; + let v2460 = v2383 * 3553; + let v2461 = v2143 + v2460; + let v2462 = v2143 - v2460; + let v2463 = v2384 * 4805; + let v2464 = v2144 + v2463; + let v2465 = v2144 - v2463; + let v2466 = v2386 * 2294; + let v2467 = v2146 + v2466; + let v2468 = v2146 - v2466; + let v2469 = v2387 * 1062; + let v2470 = v2147 + v2469; + let v2471 = v2147 - v2469; + let v2472 = v2389 * 1326; + let v2473 = v2149 + v2472; + let v2474 = v2149 - v2472; + let v2475 = v2390 * 5086; + let v2476 = v2150 + v2475; + let v2477 = v2150 - v2475; + let v2478 = v2392 * 3014; + let v2479 = v2152 + v2478; + let v2480 = v2152 - v2478; + let v2481 = v2393 * 3201; + let v2482 = v2153 + v2481; + let v2483 = v2153 - v2481; + let v2484 = v2395 * 1170; + let v2485 = v2155 + v2484; + let v2486 = v2155 - v2484; + let v2487 = v2396 * 2319; + let v2488 = v2156 + v2487; + let v2489 = v2156 - v2487; + let v2490 = v2398 * 955; + let v2491 = v2158 + v2490; + let v2492 = v2158 - v2490; + let v2493 = v2399 * 790; + let v2494 = v2159 + v2493; + let v2495 = v2159 - v2493; + let v2496 = v2401 * 544; + let v2497 = v1825 + v2496; + let v2498 = v1825 - v2496; + let v2499 = v2402 * 5791; + let v2500 = v1826 + v2499; + let v2501 = v1826 - v2499; + let v2502 = v2404 * 339; + let v2503 = v1828 + v2502; + let v2504 = v1828 - v2502; + let v2505 = v2405 * 2468; + let v2506 = v1829 + v2505; + let v2507 = v1829 - v2505; + let v2508 = v2407 * 2842; + let v2509 = v1831 + v2508; + let v2510 = v1831 - v2508; + let v2511 = v2408 * 480; + let v2512 = v1832 + v2511; + let v2513 = v1832 - v2511; + let v2514 = v2410 * 9; + let v2515 = v1834 + v2514; + let v2516 = v1834 - v2514; + let v2517 = v2411 * 1022; + let v2518 = v1835 + v2517; + let v2519 = v1835 - v2517; + let v2520 = v2413 * 4278; + let v2521 = v1837 + v2520; + let v2522 = v1837 - v2520; + let v2523 = v2414 * 1673; + let v2524 = v1838 + v2523; + let v2525 = v1838 - v2523; + let v2526 = v2416 * 4989; + let v2527 = v1840 + v2526; + let v2528 = v1840 - v2526; + let v2529 = v2417 * 5331; + let v2530 = v1841 + v2529; + let v2531 = v1841 - v2529; + let v2532 = v2419 * 3584; + let v2533 = v1843 + v2532; + let v2534 = v1843 - v2532; + let v2535 = v2420 * 4177; + let v2536 = v1844 + v2535; + let v2537 = v1844 - v2535; + let v2538 = v2422 * 1381; + let v2539 = v1846 + v2538; + let v2540 = v1846 - v2538; + let v2541 = v2423 * 2525; + let v2542 = v1847 + v2541; + let v2543 = v1847 - v2541; + let v2544 = v2425 * 2396; + let v2545 = v1849 + v2544; + let v2546 = v1849 - v2544; + let v2547 = v2426 * 4452; + let v2548 = v1850 + v2547; + let v2549 = v1850 - v2547; + let v2550 = v2428 * 3296; + let v2551 = v1852 + v2550; + let v2552 = v1852 - v2550; + let v2553 = v2429 * 3949; + let v2554 = v1853 + v2553; + let v2555 = v1853 - v2553; + let v2556 = v2431 * 130; + let v2557 = v1855 + v2556; + let v2558 = v1855 - v2556; + let v2559 = v2432 * 4354; + let v2560 = v1856 + v2559; + let v2561 = v1856 - v2559; + let v2562 = v2434 * 5374; + let v2563 = v1858 + v2562; + let v2564 = v1858 - v2562; + let v2565 = v2435 * 2837; + let v2566 = v1859 + v2565; + let v2567 = v1859 - v2565; + let v2568 = v2437 * 5767; + let v2569 = v1861 + v2568; + let v2570 = v1861 - v2568; + let v2571 = v2438 * 827; + let v2572 = v1862 + v2571; + let v2573 = v1862 - v2571; + let v2574 = v2440 * 3748; + let v2575 = v1864 + v2574; + let v2576 = v1864 - v2574; + let v2577 = v2441 * 953; + let v2578 = v1865 + v2577; + let v2579 = v1865 - v2577; + let v2580 = v2443 * 5067; + let v2581 = v1867 + v2580; + let v2582 = v1867 - v2580; + let v2583 = v2444 * 2197; + let v2584 = v1868 + v2583; + let v2585 = v1868 - v2583; + let v2586 = v2446 * 118; + let v2587 = v1870 + v2586; + let v2588 = v1870 - v2586; + let v2589 = v2447 * 2476; + let v2590 = v1871 + v2589; + let v2591 = v1871 - v2589; + let v2592 = v2449 * 2548; + let v2593 = v1873 + v2592; + let v2594 = v1873 - v2592; + let v2595 = v2450 * 4231; + let v2596 = v1874 + v2595; + let v2597 = v1874 - v2595; + let v2598 = v2452 * 355; + let v2599 = v1876 + v2598; + let v2600 = v1876 - v2598; + let v2601 = v2453 * 3382; + let v2602 = v1877 + v2601; + let v2603 = v1877 - v2601; + let v2604 = v2455 * 3707; + let v2605 = v1879 + v2604; + let v2606 = v1879 - v2604; + let v2607 = v2456 * 1759; + let v2608 = v1880 + v2607; + let v2609 = v1880 - v2607; + let v2610 = v2458 * 3694; + let v2611 = v1882 + v2610; + let v2612 = v1882 - v2610; + let v2613 = v2459 * 5179; + let v2614 = v1883 + v2613; + let v2615 = v1883 - v2613; + let v2616 = v2461 * 5542; + let v2617 = v1885 + v2616; + let v2618 = v1885 - v2616; + let v2619 = v2462 * 145; + let v2620 = v1886 + v2619; + let v2621 = v1886 - v2619; + let v2622 = v2464 * 3637; + let v2623 = v1888 + v2622; + let v2624 = v1888 - v2622; + let v2625 = v2465 * 3459; + let v2626 = v1889 + v2625; + let v2627 = v1889 - v2625; + let v2628 = v2467 * 5911; + let v2629 = v1891 + v2628; + let v2630 = v1891 - v2628; + let v2631 = v2468 * 4890; + let v2632 = v1892 + v2631; + let v2633 = v1892 - v2631; + let v2634 = v2470 * 3932; + let v2635 = v1894 + v2634; + let v2636 = v1894 - v2634; + let v2637 = v2471 * 2731; + let v2638 = v1895 + v2637; + let v2639 = v1895 - v2637; + let v2640 = v2473 * 2089; + let v2641 = v1897 + v2640; + let v2642 = v1897 - v2640; + let v2643 = v2474 * 5092; + let v2644 = v1898 + v2643; + let v2645 = v1898 - v2643; + let v2646 = v2476 * 2881; + let v2647 = v1900 + v2646; + let v2648 = v1900 - v2646; + let v2649 = v2477 * 3284; + let v2650 = v1901 + v2649; + let v2651 = v1901 - v2649; + let v2652 = v2479 * 729; + let v2653 = v1903 + v2652; + let v2654 = v1903 - v2652; + let v2655 = v2480 * 3241; + let v2656 = v1904 + v2655; + let v2657 = v1904 - v2655; + let v2658 = v2482 * 3289; + let v2659 = v1906 + v2658; + let v2660 = v1906 - v2658; + let v2661 = v2483 * 2013; + let v2662 = v1907 + v2661; + let v2663 = v1907 - v2661; + let v2664 = v2485 * 5755; + let v2665 = v1909 + v2664; + let v2666 = v1909 - v2664; + let v2667 = v2486 * 4632; + let v2668 = v1910 + v2667; + let v2669 = v1910 - v2667; + let v2670 = v2488 * 1260; + let v2671 = v1912 + v2670; + let v2672 = v1912 - v2670; + let v2673 = v2489 * 4388; + let v2674 = v1913 + v2673; + let v2675 = v1913 - v2673; + let v2676 = v2491 * 334; + let v2677 = v1915 + v2676; + let v2678 = v1915 - v2676; + let v2679 = v2492 * 2426; + let v2680 = v1916 + v2679; + let v2681 = v1916 - v2679; + let v2682 = v2494 * 1696; + let v2683 = v1918 + v2682; + let v2684 = v1918 - v2682; + let v2685 = v2495 * 1428; + let v2686 = v1919 + v2685; + let v2687 = v1919 - v2685; + let v2688 = v2497 * 1663; + let v2689 = v1153 + v2688; + let v2690 = v1153 - v2688; + let v2691 = v2498 * 1777; + let v2692 = v1154 + v2691; + let v2693 = v1154 - v2691; + let v2694 = v2500 * 1426; + let v2695 = v1156 + v2694; + let v2696 = v1156 - v2694; + let v2697 = v2501 * 4654; + let v2698 = v1157 + v2697; + let v2699 = v1157 - v2697; + let v2700 = v2503 * 5291; + let v2701 = v1159 + v2700; + let v2702 = v1159 - v2700; + let v2703 = v2504 * 2704; + let v2704 = v1160 + v2703; + let v2705 = v1160 - v2703; + let v2706 = v2506 * 4938; + let v2707 = v1162 + v2706; + let v2708 = v1162 - v2706; + let v2709 = v2507 * 3636; + let v2710 = v1163 + v2709; + let v2711 = v1163 - v2709; + let v2712 = v2509 * 3915; + let v2713 = v1165 + v2712; + let v2714 = v1165 - v2712; + let v2715 = v2510 * 2166; + let v2716 = v1166 + v2715; + let v2717 = v1166 - v2715; + let v2718 = v2512 * 113; + let v2719 = v1168 + v2718; + let v2720 = v1168 - v2718; + let v2721 = v2513 * 4919; + let v2722 = v1169 + v2721; + let v2723 = v1169 - v2721; + let v2724 = v2515 * 3; + let v2725 = v1171 + v2724; + let v2726 = v1171 - v2724; + let v2727 = v2516 * 4437; + let v2728 = v1172 + v2727; + let v2729 = v1172 - v2727; + let v2730 = v2518 * 160; + let v2731 = v1174 + v2730; + let v2732 = v1174 - v2730; + let v2733 = v2519 * 3149; + let v2734 = v1175 + v2733; + let v2735 = v1175 - v2733; + let v2736 = v2521 * 4057; + let v2737 = v1177 + v2736; + let v2738 = v1177 - v2736; + let v2739 = v2522 * 3271; + let v2740 = v1178 + v2739; + let v2741 = v1178 - v2739; + let v2742 = v2524 * 1689; + let v2743 = v1180 + v2742; + let v2744 = v1180 - v2742; + let v2745 = v2525 * 3364; + let v2746 = v1181 + v2745; + let v2747 = v1181 - v2745; + let v2748 = v2527 * 4372; + let v2749 = v1183 + v2748; + let v2750 = v1183 - v2748; + let v2751 = v2528 * 2174; + let v2752 = v1184 + v2751; + let v2753 = v1184 - v2751; + let v2754 = v2530 * 4414; + let v2755 = v1186 + v2754; + let v2756 = v1186 - v2754; + let v2757 = v2531 * 2847; + let v2758 = v1187 + v2757; + let v2759 = v1187 - v2757; + let v2760 = v2533 * 2645; + let v2761 = v1189 + v2760; + let v2762 = v1189 - v2760; + let v2763 = v2534 * 4053; + let v2764 = v1190 + v2763; + let v2765 = v1190 - v2763; + let v2766 = v2536 * 2305; + let v2767 = v1192 + v2766; + let v2768 = v1192 - v2766; + let v2769 = v2537 * 5042; + let v2770 = v1193 + v2769; + let v2771 = v1193 - v2769; + let v2772 = v2539 * 5195; + let v2773 = v1195 + v2772; + let v2774 = v1195 - v2772; + let v2775 = v2540 * 2780; + let v2776 = v1196 + v2775; + let v2777 = v1196 - v2775; + let v2778 = v2542 * 1484; + let v2779 = v1198 + v2778; + let v2780 = v1198 - v2778; + let v2781 = v2543 * 4895; + let v2782 = v1199 + v2781; + let v2783 = v1199 - v2781; + let v2784 = v2545 * 3016; + let v2785 = v1201 + v2784; + let v2786 = v1201 - v2784; + let v2787 = v2546 * 243; + let v2788 = v1202 + v2787; + let v2789 = v1202 - v2787; + let v2790 = v2548 * 3000; + let v2791 = v1204 + v2790; + let v2792 = v1204 - v2790; + let v2793 = v2549 * 671; + let v2794 = v1205 + v2793; + let v2795 = v1205 - v2793; + let v2796 = v2551 * 3136; + let v2797 = v1207 + v2796; + let v2798 = v1207 - v2796; + let v2799 = v2552 * 5191; + let v2800 = v1208 + v2799; + let v2801 = v1208 - v2799; + let v2802 = v2554 * 2399; + let v2803 = v1210 + v2802; + let v2804 = v1210 - v2802; + let v2805 = v2555 * 3400; + let v2806 = v1211 + v2805; + let v2807 = v1211 - v2805; + let v2808 = v2557 * 2178; + let v2809 = v1213 + v2808; + let v2810 = v1213 - v2808; + let v2811 = v2558 * 1544; + let v2812 = v1214 + v2811; + let v2813 = v1214 - v2811; + let v2814 = v2560 * 420; + let v2815 = v1216 + v2814; + let v2816 = v1216 - v2814; + let v2817 = v2561 * 5559; + let v2818 = v1217 + v2817; + let v2819 = v1217 - v2817; + let v2820 = v2563 * 476; + let v2821 = v1219 + v2820; + let v2822 = v1219 - v2820; + let v2823 = v2564 * 3531; + let v2824 = v1220 + v2823; + let v2825 = v1220 - v2823; + let v2826 = v2566 * 3985; + let v2827 = v1222 + v2826; + let v2828 = v1222 - v2826; + let v2829 = v2567 * 4905; + let v2830 = v1223 + v2829; + let v2831 = v1223 - v2829; + let v2832 = v2569 * 5332; + let v2833 = v1225 + v2832; + let v2834 = v1225 - v2832; + let v2835 = v2570 * 3510; + let v2836 = v1226 + v2835; + let v2837 = v1226 - v2835; + let v2838 = v2572 * 2370; + let v2839 = v1228 + v2838; + let v2840 = v1228 - v2838; + let v2841 = v2573 * 2865; + let v2842 = v1229 + v2841; + let v2843 = v1229 - v2841; + let v2844 = v2575 * 2969; + let v2845 = v1231 + v2844; + let v2846 = v1231 - v2844; + let v2847 = v2576 * 3978; + let v2848 = v1232 + v2847; + let v2849 = v1232 - v2847; + let v2850 = v2578 * 2686; + let v2851 = v1234 + v2850; + let v2852 = v1234 - v2850; + let v2853 = v2579 * 3247; + let v2854 = v1235 + v2853; + let v2855 = v1235 - v2853; + let v2856 = v2581 * 4048; + let v2857 = v1237 + v2856; + let v2858 = v1237 - v2856; + let v2859 = v2582 * 2249; + let v2860 = v1238 + v2859; + let v2861 = v1238 - v2859; + let v2862 = v2584 * 1153; + let v2863 = v1240 + v2862; + let v2864 = v1240 - v2862; + let v2865 = v2585 * 2884; + let v2866 = v1241 + v2865; + let v2867 = v1241 - v2865; + let v2868 = v2587 * 5407; + let v2869 = v1243 + v2868; + let v2870 = v1243 - v2868; + let v2871 = v2588 * 3186; + let v2872 = v1244 + v2871; + let v2873 = v1244 - v2871; + let v2874 = v2590 * 1630; + let v2875 = v1246 + v2874; + let v2876 = v1246 - v2874; + let v2877 = v2591 * 2126; + let v2878 = v1247 + v2877; + let v2879 = v1247 - v2877; + let v2880 = v2593 * 2187; + let v2881 = v1249 + v2880; + let v2882 = v1249 - v2880; + let v2883 = v2594 * 2566; + let v2884 = v1250 + v2883; + let v2885 = v1250 - v2883; + let v2886 = v2596 * 2422; + let v2887 = v1252 + v2886; + let v2888 = v1252 - v2886; + let v2889 = v2597 * 6039; + let v2890 = v1253 + v2889; + let v2891 = v1253 - v2889; + let v2892 = v2599 * 2987; + let v2893 = v1255 + v2892; + let v2894 = v1255 - v2892; + let v2895 = v2600 * 6022; + let v2896 = v1256 + v2895; + let v2897 = v1256 - v2895; + let v2898 = v2602 * 2437; + let v2899 = v1258 + v2898; + let v2900 = v1258 - v2898; + let v2901 = v2603 * 3646; + let v2902 = v1259 + v2901; + let v2903 = v1259 - v2901; + let v2904 = v2605 * 875; + let v2905 = v1261 + v2904; + let v2906 = v1261 - v2904; + let v2907 = v2606 * 3780; + let v2908 = v1262 + v2907; + let v2909 = v1262 - v2907; + let v2910 = v2608 * 1607; + let v2911 = v1264 + v2910; + let v2912 = v1264 - v2910; + let v2913 = v2609 * 4976; + let v2914 = v1265 + v2913; + let v2915 = v1265 - v2913; + let v2916 = v2611 * 5011; + let v2917 = v1267 + v2916; + let v2918 = v1267 - v2916; + let v2919 = v2612 * 1002; + let v2920 = v1268 + v2919; + let v2921 = v1268 - v2919; + let v2922 = v2614 * 4284; + let v2923 = v1270 + v2922; + let v2924 = v1270 - v2922; + let v2925 = v2615 * 5088; + let v2926 = v1271 + v2925; + let v2927 = v1271 - v2925; + let v2928 = v2617 * 3248; + let v2929 = v1273 + v2928; + let v2930 = v1273 - v2928; + let v2931 = v2618 * 1207; + let v2932 = v1274 + v2931; + let v2933 = v1274 - v2931; + let v2934 = v2620 * 1168; + let v2935 = v1276 + v2934; + let v2936 = v1276 - v2934; + let v2937 = v2621 * 5277; + let v2938 = v1277 + v2937; + let v2939 = v1277 - v2937; + let v2940 = v2623 * 1065; + let v2941 = v1279 + v2940; + let v2942 = v1279 - v2940; + let v2943 = v2624 * 2143; + let v2944 = v1280 + v2943; + let v2945 = v1280 - v2943; + let v2946 = v2626 * 404; + let v2947 = v1282 + v2946; + let v2948 = v1282 - v2946; + let v2949 = v2627 * 4645; + let v2950 = v1283 + v2949; + let v2951 = v1283 - v2949; + let v2952 = v2629 * 1912; + let v2953 = v1285 + v2952; + let v2954 = v1285 - v2952; + let v2955 = v2630 * 1378; + let v2956 = v1286 + v2955; + let v2957 = v1286 - v2955; + let v2958 = v2632 * 435; + let v2959 = v1288 + v2958; + let v2960 = v1288 - v2958; + let v2961 = v2633 * 4337; + let v2962 = v1289 + v2961; + let v2963 = v1289 - v2961; + let v2964 = v2635 * 2381; + let v2965 = v1291 + v2964; + let v2966 = v1291 - v2964; + let v2967 = v2636 * 5444; + let v2968 = v1292 + v2967; + let v2969 = v1292 - v2967; + let v2970 = v2638 * 4096; + let v2971 = v1294 + v2970; + let v2972 = v1294 - v2970; + let v2973 = v2639 * 493; + let v2974 = v1295 + v2973; + let v2975 = v1295 - v2973; + let v2976 = v2641 * 545; + let v2977 = v1297 + v2976; + let v2978 = v1297 - v2976; + let v2979 = v2642 * 5019; + let v2980 = v1298 + v2979; + let v2981 = v1298 - v2979; + let v2982 = v2644 * 3704; + let v2983 = v1300 + v2982; + let v2984 = v1300 - v2982; + let v2985 = v2645 * 2678; + let v2986 = v1301 + v2985; + let v2987 = v1301 - v2985; + let v2988 = v2647 * 1537; + let v2989 = v1303 + v2988; + let v2990 = v1303 - v2988; + let v2991 = v2648 * 242; + let v2992 = v1304 + v2991; + let v2993 = v1304 - v2991; + let v2994 = v2650 * 4714; + let v2995 = v1306 + v2994; + let v2996 = v1306 - v2994; + let v2997 = v2651 * 4143; + let v2998 = v1307 + v2997; + let v2999 = v1307 - v2997; + let v3000 = v2653 * 27; + let v3001 = v1309 + v3000; + let v3002 = v1309 - v3000; + let v3003 = v2654 * 3066; + let v3004 = v1310 + v3003; + let v3005 = v1310 - v3003; + let v3006 = v2656 * 3763; + let v3007 = v1312 + v3006; + let v3008 = v1312 - v3006; + let v3009 = v2657 * 1440; + let v3010 = v1313 + v3009; + let v3011 = v1313 - v3009; + let v3012 = v2659 * 5084; + let v3013 = v1315 + v3012; + let v3014 = v1315 - v3012; + let v3015 = v2660 * 1632; + let v3016 = v1316 + v3015; + let v3017 = v1316 - v3015; + let v3018 = v2662 * 1017; + let v3019 = v1318 + v3018; + let v3020 = v1318 - v3018; + let v3021 = v2663 * 4885; + let v3022 = v1319 + v3021; + let v3023 = v1319 - v3021; + let v3024 = v2665 * 3778; + let v3025 = v1321 + v3024; + let v3026 = v1321 - v3024; + let v3027 = v2666 * 3833; + let v3028 = v1322 + v3027; + let v3029 = v1322 - v3027; + let v3030 = v2668 * 390; + let v3031 = v1324 + v3030; + let v3032 = v1324 - v3030; + let v3033 = v2669 * 773; + let v3034 = v1325 + v3033; + let v3035 = v1325 - v3033; + let v3036 = v2671 * 2401; + let v3037 = v1327 + v3036; + let v3038 = v1327 - v3036; + let v3039 = v2672 * 442; + let v3040 = v1328 + v3039; + let v3041 = v1328 - v3039; + let v3042 = v2674 * 5101; + let v3043 = v1330 + v3042; + let v3044 = v1330 - v3042; + let v3045 = v2675 * 1067; + let v3046 = v1331 + v3045; + let v3047 = v1331 - v3045; + let v3048 = v2677 * 2912; + let v3049 = v1333 + v3048; + let v3050 = v1333 - v3048; + let v3051 = v2678 * 5698; + let v3052 = v1334 + v3051; + let v3053 = v1334 - v3051; + let v3054 = v2680 * 354; + let v3055 = v1336 + v3054; + let v3056 = v1336 - v3054; + let v3057 = v2681 * 4861; + let v3058 = v1337 + v3057; + let v3059 = v1337 - v3057; + let v3060 = v2683 * 2859; + let v3061 = v1339 + v3060; + let v3062 = v1339 - v3060; + let v3063 = v2684 * 1045; + let v3064 = v1340 + v3063; + let v3065 = v1340 - v3063; + let v3066 = v2686 * 5012; + let v3067 = v1342 + v3066; + let v3068 = v1342 - v3066; + let v3069 = v2687 * 2481; + let v3070 = v1343 + v3069; + let v3071 = v1343 - v3069; + let v3072 = f257 * 1479; + let v3073 = f1 + v3072; + let v3074 = f1 - v3072; + let v3075 = f385 * 1479; + let v3076 = f129 + v3075; + let v3077 = f129 - v3075; + let v3078 = v3076 * 4043; + let v3079 = v3073 + v3078; + let v3080 = v3073 - v3078; + let v3081 = v3077 * 5146; + let v3082 = v3074 + v3081; + let v3083 = v3074 - v3081; + let v3084 = f321 * 1479; + let v3085 = f65 + v3084; + let v3086 = f65 - v3084; + let v3087 = f449 * 1479; + let v3088 = f193 + v3087; + let v3089 = f193 - v3087; + let v3090 = v3088 * 4043; + let v3091 = v3085 + v3090; + let v3092 = v3085 - v3090; + let v3093 = v3089 * 5146; + let v3094 = v3086 + v3093; + let v3095 = v3086 - v3093; + let v3096 = v3091 * 5736; + let v3097 = v3079 + v3096; + let v3098 = v3079 - v3096; + let v3099 = v3092 * 4134; + let v3100 = v3080 + v3099; + let v3101 = v3080 - v3099; + let v3102 = v3094 * 722; + let v3103 = v3082 + v3102; + let v3104 = v3082 - v3102; + let v3105 = v3095 * 1305; + let v3106 = v3083 + v3105; + let v3107 = v3083 - v3105; + let v3108 = f289 * 1479; + let v3109 = f33 + v3108; + let v3110 = f33 - v3108; + let v3111 = f417 * 1479; + let v3112 = f161 + v3111; + let v3113 = f161 - v3111; + let v3114 = v3112 * 4043; + let v3115 = v3109 + v3114; + let v3116 = v3109 - v3114; + let v3117 = v3113 * 5146; + let v3118 = v3110 + v3117; + let v3119 = v3110 - v3117; + let v3120 = f353 * 1479; + let v3121 = f97 + v3120; + let v3122 = f97 - v3120; + let v3123 = f481 * 1479; + let v3124 = f225 + v3123; + let v3125 = f225 - v3123; + let v3126 = v3124 * 4043; + let v3127 = v3121 + v3126; + let v3128 = v3121 - v3126; + let v3129 = v3125 * 5146; + let v3130 = v3122 + v3129; + let v3131 = v3122 - v3129; + let v3132 = v3127 * 5736; + let v3133 = v3115 + v3132; + let v3134 = v3115 - v3132; + let v3135 = v3128 * 4134; + let v3136 = v3116 + v3135; + let v3137 = v3116 - v3135; + let v3138 = v3130 * 722; + let v3139 = v3118 + v3138; + let v3140 = v3118 - v3138; + let v3141 = v3131 * 1305; + let v3142 = v3119 + v3141; + let v3143 = v3119 - v3141; + let v3144 = v3133 * 1646; + let v3145 = v3097 + v3144; + let v3146 = v3097 - v3144; + let v3147 = v3134 * 1212; + let v3148 = v3098 + v3147; + let v3149 = v3098 - v3147; + let v3150 = v3136 * 5860; + let v3151 = v3100 + v3150; + let v3152 = v3100 - v3150; + let v3153 = v3137 * 3195; + let v3154 = v3101 + v3153; + let v3155 = v3101 - v3153; + let v3156 = v3139 * 2545; + let v3157 = v3103 + v3156; + let v3158 = v3103 - v3156; + let v3159 = v3140 * 3621; + let v3160 = v3104 + v3159; + let v3161 = v3104 - v3159; + let v3162 = v3142 * 3504; + let v3163 = v3106 + v3162; + let v3164 = v3106 - v3162; + let v3165 = v3143 * 3542; + let v3166 = v3107 + v3165; + let v3167 = v3107 - v3165; + let v3168 = f273 * 1479; + let v3169 = f17 + v3168; + let v3170 = f17 - v3168; + let v3171 = f401 * 1479; + let v3172 = f145 + v3171; + let v3173 = f145 - v3171; + let v3174 = v3172 * 4043; + let v3175 = v3169 + v3174; + let v3176 = v3169 - v3174; + let v3177 = v3173 * 5146; + let v3178 = v3170 + v3177; + let v3179 = v3170 - v3177; + let v3180 = f337 * 1479; + let v3181 = f81 + v3180; + let v3182 = f81 - v3180; + let v3183 = f465 * 1479; + let v3184 = f209 + v3183; + let v3185 = f209 - v3183; + let v3186 = v3184 * 4043; + let v3187 = v3181 + v3186; + let v3188 = v3181 - v3186; + let v3189 = v3185 * 5146; + let v3190 = v3182 + v3189; + let v3191 = v3182 - v3189; + let v3192 = v3187 * 5736; + let v3193 = v3175 + v3192; + let v3194 = v3175 - v3192; + let v3195 = v3188 * 4134; + let v3196 = v3176 + v3195; + let v3197 = v3176 - v3195; + let v3198 = v3190 * 722; + let v3199 = v3178 + v3198; + let v3200 = v3178 - v3198; + let v3201 = v3191 * 1305; + let v3202 = v3179 + v3201; + let v3203 = v3179 - v3201; + let v3204 = f305 * 1479; + let v3205 = f49 + v3204; + let v3206 = f49 - v3204; + let v3207 = f433 * 1479; + let v3208 = f177 + v3207; + let v3209 = f177 - v3207; + let v3210 = v3208 * 4043; + let v3211 = v3205 + v3210; + let v3212 = v3205 - v3210; + let v3213 = v3209 * 5146; + let v3214 = v3206 + v3213; + let v3215 = v3206 - v3213; + let v3216 = f369 * 1479; + let v3217 = f113 + v3216; + let v3218 = f113 - v3216; + let v3219 = f497 * 1479; + let v3220 = f241 + v3219; + let v3221 = f241 - v3219; + let v3222 = v3220 * 4043; + let v3223 = v3217 + v3222; + let v3224 = v3217 - v3222; + let v3225 = v3221 * 5146; + let v3226 = v3218 + v3225; + let v3227 = v3218 - v3225; + let v3228 = v3223 * 5736; + let v3229 = v3211 + v3228; + let v3230 = v3211 - v3228; + let v3231 = v3224 * 4134; + let v3232 = v3212 + v3231; + let v3233 = v3212 - v3231; + let v3234 = v3226 * 722; + let v3235 = v3214 + v3234; + let v3236 = v3214 - v3234; + let v3237 = v3227 * 1305; + let v3238 = v3215 + v3237; + let v3239 = v3215 - v3237; + let v3240 = v3229 * 1646; + let v3241 = v3193 + v3240; + let v3242 = v3193 - v3240; + let v3243 = v3230 * 1212; + let v3244 = v3194 + v3243; + let v3245 = v3194 - v3243; + let v3246 = v3232 * 5860; + let v3247 = v3196 + v3246; + let v3248 = v3196 - v3246; + let v3249 = v3233 * 3195; + let v3250 = v3197 + v3249; + let v3251 = v3197 - v3249; + let v3252 = v3235 * 2545; + let v3253 = v3199 + v3252; + let v3254 = v3199 - v3252; + let v3255 = v3236 * 3621; + let v3256 = v3200 + v3255; + let v3257 = v3200 - v3255; + let v3258 = v3238 * 3504; + let v3259 = v3202 + v3258; + let v3260 = v3202 - v3258; + let v3261 = v3239 * 3542; + let v3262 = v3203 + v3261; + let v3263 = v3203 - v3261; + let v3264 = v3241 * 4591; + let v3265 = v3145 + v3264; + let v3266 = v3145 - v3264; + let v3267 = v3242 * 5728; + let v3268 = v3146 + v3267; + let v3269 = v3146 - v3267; + let v3270 = v3244 * 5023; + let v3271 = v3148 + v3270; + let v3272 = v3148 - v3270; + let v3273 = v3245 * 5828; + let v3274 = v3149 + v3273; + let v3275 = v3149 - v3273; + let v3276 = v3247 * 4978; + let v3277 = v3151 + v3276; + let v3278 = v3151 - v3276; + let v3279 = v3248 * 1351; + let v3280 = v3152 + v3279; + let v3281 = v3152 - v3279; + let v3282 = v3250 * 3328; + let v3283 = v3154 + v3282; + let v3284 = v3154 - v3282; + let v3285 = v3251 * 5777; + let v3286 = v3155 + v3285; + let v3287 = v3155 - v3285; + let v3288 = v3253 * 2975; + let v3289 = v3157 + v3288; + let v3290 = v3157 - v3288; + let v3291 = v3254 * 563; + let v3292 = v3158 + v3291; + let v3293 = v3158 - v3291; + let v3294 = v3256 * 3006; + let v3295 = v3160 + v3294; + let v3296 = v3160 - v3294; + let v3297 = v3257 * 2744; + let v3298 = v3161 + v3297; + let v3299 = v3161 - v3297; + let v3300 = v3259 * 949; + let v3301 = v3163 + v3300; + let v3302 = v3163 - v3300; + let v3303 = v3260 * 2625; + let v3304 = v3164 + v3303; + let v3305 = v3164 - v3303; + let v3306 = v3262 * 4821; + let v3307 = v3166 + v3306; + let v3308 = v3166 - v3306; + let v3309 = v3263 * 2639; + let v3310 = v3167 + v3309; + let v3311 = v3167 - v3309; + let v3312 = f265 * 1479; + let v3313 = f9 + v3312; + let v3314 = f9 - v3312; + let v3315 = f393 * 1479; + let v3316 = f137 + v3315; + let v3317 = f137 - v3315; + let v3318 = v3316 * 4043; + let v3319 = v3313 + v3318; + let v3320 = v3313 - v3318; + let v3321 = v3317 * 5146; + let v3322 = v3314 + v3321; + let v3323 = v3314 - v3321; + let v3324 = f329 * 1479; + let v3325 = f73 + v3324; + let v3326 = f73 - v3324; + let v3327 = f457 * 1479; + let v3328 = f201 + v3327; + let v3329 = f201 - v3327; + let v3330 = v3328 * 4043; + let v3331 = v3325 + v3330; + let v3332 = v3325 - v3330; + let v3333 = v3329 * 5146; + let v3334 = v3326 + v3333; + let v3335 = v3326 - v3333; + let v3336 = v3331 * 5736; + let v3337 = v3319 + v3336; + let v3338 = v3319 - v3336; + let v3339 = v3332 * 4134; + let v3340 = v3320 + v3339; + let v3341 = v3320 - v3339; + let v3342 = v3334 * 722; + let v3343 = v3322 + v3342; + let v3344 = v3322 - v3342; + let v3345 = v3335 * 1305; + let v3346 = v3323 + v3345; + let v3347 = v3323 - v3345; + let v3348 = f297 * 1479; + let v3349 = f41 + v3348; + let v3350 = f41 - v3348; + let v3351 = f425 * 1479; + let v3352 = f169 + v3351; + let v3353 = f169 - v3351; + let v3354 = v3352 * 4043; + let v3355 = v3349 + v3354; + let v3356 = v3349 - v3354; + let v3357 = v3353 * 5146; + let v3358 = v3350 + v3357; + let v3359 = v3350 - v3357; + let v3360 = f361 * 1479; + let v3361 = f105 + v3360; + let v3362 = f105 - v3360; + let v3363 = f489 * 1479; + let v3364 = f233 + v3363; + let v3365 = f233 - v3363; + let v3366 = v3364 * 4043; + let v3367 = v3361 + v3366; + let v3368 = v3361 - v3366; + let v3369 = v3365 * 5146; + let v3370 = v3362 + v3369; + let v3371 = v3362 - v3369; + let v3372 = v3367 * 5736; + let v3373 = v3355 + v3372; + let v3374 = v3355 - v3372; + let v3375 = v3368 * 4134; + let v3376 = v3356 + v3375; + let v3377 = v3356 - v3375; + let v3378 = v3370 * 722; + let v3379 = v3358 + v3378; + let v3380 = v3358 - v3378; + let v3381 = v3371 * 1305; + let v3382 = v3359 + v3381; + let v3383 = v3359 - v3381; + let v3384 = v3373 * 1646; + let v3385 = v3337 + v3384; + let v3386 = v3337 - v3384; + let v3387 = v3374 * 1212; + let v3388 = v3338 + v3387; + let v3389 = v3338 - v3387; + let v3390 = v3376 * 5860; + let v3391 = v3340 + v3390; + let v3392 = v3340 - v3390; + let v3393 = v3377 * 3195; + let v3394 = v3341 + v3393; + let v3395 = v3341 - v3393; + let v3396 = v3379 * 2545; + let v3397 = v3343 + v3396; + let v3398 = v3343 - v3396; + let v3399 = v3380 * 3621; + let v3400 = v3344 + v3399; + let v3401 = v3344 - v3399; + let v3402 = v3382 * 3504; + let v3403 = v3346 + v3402; + let v3404 = v3346 - v3402; + let v3405 = v3383 * 3542; + let v3406 = v3347 + v3405; + let v3407 = v3347 - v3405; + let v3408 = f281 * 1479; + let v3409 = f25 + v3408; + let v3410 = f25 - v3408; + let v3411 = f409 * 1479; + let v3412 = f153 + v3411; + let v3413 = f153 - v3411; + let v3414 = v3412 * 4043; + let v3415 = v3409 + v3414; + let v3416 = v3409 - v3414; + let v3417 = v3413 * 5146; + let v3418 = v3410 + v3417; + let v3419 = v3410 - v3417; + let v3420 = f345 * 1479; + let v3421 = f89 + v3420; + let v3422 = f89 - v3420; + let v3423 = f473 * 1479; + let v3424 = f217 + v3423; + let v3425 = f217 - v3423; + let v3426 = v3424 * 4043; + let v3427 = v3421 + v3426; + let v3428 = v3421 - v3426; + let v3429 = v3425 * 5146; + let v3430 = v3422 + v3429; + let v3431 = v3422 - v3429; + let v3432 = v3427 * 5736; + let v3433 = v3415 + v3432; + let v3434 = v3415 - v3432; + let v3435 = v3428 * 4134; + let v3436 = v3416 + v3435; + let v3437 = v3416 - v3435; + let v3438 = v3430 * 722; + let v3439 = v3418 + v3438; + let v3440 = v3418 - v3438; + let v3441 = v3431 * 1305; + let v3442 = v3419 + v3441; + let v3443 = v3419 - v3441; + let v3444 = f313 * 1479; + let v3445 = f57 + v3444; + let v3446 = f57 - v3444; + let v3447 = f441 * 1479; + let v3448 = f185 + v3447; + let v3449 = f185 - v3447; + let v3450 = v3448 * 4043; + let v3451 = v3445 + v3450; + let v3452 = v3445 - v3450; + let v3453 = v3449 * 5146; + let v3454 = v3446 + v3453; + let v3455 = v3446 - v3453; + let v3456 = f377 * 1479; + let v3457 = f121 + v3456; + let v3458 = f121 - v3456; + let v3459 = f505 * 1479; + let v3460 = f249 + v3459; + let v3461 = f249 - v3459; + let v3462 = v3460 * 4043; + let v3463 = v3457 + v3462; + let v3464 = v3457 - v3462; + let v3465 = v3461 * 5146; + let v3466 = v3458 + v3465; + let v3467 = v3458 - v3465; + let v3468 = v3463 * 5736; + let v3469 = v3451 + v3468; + let v3470 = v3451 - v3468; + let v3471 = v3464 * 4134; + let v3472 = v3452 + v3471; + let v3473 = v3452 - v3471; + let v3474 = v3466 * 722; + let v3475 = v3454 + v3474; + let v3476 = v3454 - v3474; + let v3477 = v3467 * 1305; + let v3478 = v3455 + v3477; + let v3479 = v3455 - v3477; + let v3480 = v3469 * 1646; + let v3481 = v3433 + v3480; + let v3482 = v3433 - v3480; + let v3483 = v3470 * 1212; + let v3484 = v3434 + v3483; + let v3485 = v3434 - v3483; + let v3486 = v3472 * 5860; + let v3487 = v3436 + v3486; + let v3488 = v3436 - v3486; + let v3489 = v3473 * 3195; + let v3490 = v3437 + v3489; + let v3491 = v3437 - v3489; + let v3492 = v3475 * 2545; + let v3493 = v3439 + v3492; + let v3494 = v3439 - v3492; + let v3495 = v3476 * 3621; + let v3496 = v3440 + v3495; + let v3497 = v3440 - v3495; + let v3498 = v3478 * 3504; + let v3499 = v3442 + v3498; + let v3500 = v3442 - v3498; + let v3501 = v3479 * 3542; + let v3502 = v3443 + v3501; + let v3503 = v3443 - v3501; + let v3504 = v3481 * 4591; + let v3505 = v3385 + v3504; + let v3506 = v3385 - v3504; + let v3507 = v3482 * 5728; + let v3508 = v3386 + v3507; + let v3509 = v3386 - v3507; + let v3510 = v3484 * 5023; + let v3511 = v3388 + v3510; + let v3512 = v3388 - v3510; + let v3513 = v3485 * 5828; + let v3514 = v3389 + v3513; + let v3515 = v3389 - v3513; + let v3516 = v3487 * 4978; + let v3517 = v3391 + v3516; + let v3518 = v3391 - v3516; + let v3519 = v3488 * 1351; + let v3520 = v3392 + v3519; + let v3521 = v3392 - v3519; + let v3522 = v3490 * 3328; + let v3523 = v3394 + v3522; + let v3524 = v3394 - v3522; + let v3525 = v3491 * 5777; + let v3526 = v3395 + v3525; + let v3527 = v3395 - v3525; + let v3528 = v3493 * 2975; + let v3529 = v3397 + v3528; + let v3530 = v3397 - v3528; + let v3531 = v3494 * 563; + let v3532 = v3398 + v3531; + let v3533 = v3398 - v3531; + let v3534 = v3496 * 3006; + let v3535 = v3400 + v3534; + let v3536 = v3400 - v3534; + let v3537 = v3497 * 2744; + let v3538 = v3401 + v3537; + let v3539 = v3401 - v3537; + let v3540 = v3499 * 949; + let v3541 = v3403 + v3540; + let v3542 = v3403 - v3540; + let v3543 = v3500 * 2625; + let v3544 = v3404 + v3543; + let v3545 = v3404 - v3543; + let v3546 = v3502 * 4821; + let v3547 = v3406 + v3546; + let v3548 = v3406 - v3546; + let v3549 = v3503 * 2639; + let v3550 = v3407 + v3549; + let v3551 = v3407 - v3549; + let v3552 = v3505 * 1000; + let v3553 = v3265 + v3552; + let v3554 = v3265 - v3552; + let v3555 = v3506 * 4320; + let v3556 = v3266 + v3555; + let v3557 = v3266 - v3555; + let v3558 = v3508 * 3091; + let v3559 = v3268 + v3558; + let v3560 = v3268 - v3558; + let v3561 = v3509 * 81; + let v3562 = v3269 + v3561; + let v3563 = v3269 - v3561; + let v3564 = v3511 * 2963; + let v3565 = v3271 + v3564; + let v3566 = v3271 - v3564; + let v3567 = v3512 * 4896; + let v3568 = v3272 + v3567; + let v3569 = v3272 - v3567; + let v3570 = v3514 * 3051; + let v3571 = v3274 + v3570; + let v3572 = v3274 - v3570; + let v3573 = v3515 * 2366; + let v3574 = v3275 + v3573; + let v3575 = v3275 - v3573; + let v3576 = v3517 * 1853; + let v3577 = v3277 + v3576; + let v3578 = v3277 - v3576; + let v3579 = v3518 * 140; + let v3580 = v3278 + v3579; + let v3581 = v3278 - v3579; + let v3582 = v3520 * 4611; + let v3583 = v3280 + v3582; + let v3584 = v3280 - v3582; + let v3585 = v3521 * 726; + let v3586 = v3281 + v3585; + let v3587 = v3281 - v3585; + let v3588 = v3523 * 4255; + let v3589 = v3283 + v3588; + let v3590 = v3283 - v3588; + let v3591 = v3524 * 1177; + let v3592 = v3284 + v3591; + let v3593 = v3284 - v3591; + let v3594 = v3526 * 2768; + let v3595 = v3286 + v3594; + let v3596 = v3286 - v3594; + let v3597 = v3527 * 1635; + let v3598 = v3287 + v3597; + let v3599 = v3287 - v3597; + let v3600 = v3529 * 3712; + let v3601 = v3289 + v3600; + let v3602 = v3289 - v3600; + let v3603 = v3530 * 3135; + let v3604 = v3290 + v3603; + let v3605 = v3290 - v3603; + let v3606 = v3532 * 2747; + let v3607 = v3292 + v3606; + let v3608 = v3292 - v3606; + let v3609 = v3533 * 4846; + let v3610 = v3293 + v3609; + let v3611 = v3293 - v3609; + let v3612 = v3535 * 3553; + let v3613 = v3295 + v3612; + let v3614 = v3295 - v3612; + let v3615 = v3536 * 4805; + let v3616 = v3296 + v3615; + let v3617 = v3296 - v3615; + let v3618 = v3538 * 2294; + let v3619 = v3298 + v3618; + let v3620 = v3298 - v3618; + let v3621 = v3539 * 1062; + let v3622 = v3299 + v3621; + let v3623 = v3299 - v3621; + let v3624 = v3541 * 1326; + let v3625 = v3301 + v3624; + let v3626 = v3301 - v3624; + let v3627 = v3542 * 5086; + let v3628 = v3302 + v3627; + let v3629 = v3302 - v3627; + let v3630 = v3544 * 3014; + let v3631 = v3304 + v3630; + let v3632 = v3304 - v3630; + let v3633 = v3545 * 3201; + let v3634 = v3305 + v3633; + let v3635 = v3305 - v3633; + let v3636 = v3547 * 1170; + let v3637 = v3307 + v3636; + let v3638 = v3307 - v3636; + let v3639 = v3548 * 2319; + let v3640 = v3308 + v3639; + let v3641 = v3308 - v3639; + let v3642 = v3550 * 955; + let v3643 = v3310 + v3642; + let v3644 = v3310 - v3642; + let v3645 = v3551 * 790; + let v3646 = v3311 + v3645; + let v3647 = v3311 - v3645; + let v3648 = f261 * 1479; + let v3649 = f5 + v3648; + let v3650 = f5 - v3648; + let v3651 = f389 * 1479; + let v3652 = f133 + v3651; + let v3653 = f133 - v3651; + let v3654 = v3652 * 4043; + let v3655 = v3649 + v3654; + let v3656 = v3649 - v3654; + let v3657 = v3653 * 5146; + let v3658 = v3650 + v3657; + let v3659 = v3650 - v3657; + let v3660 = f325 * 1479; + let v3661 = f69 + v3660; + let v3662 = f69 - v3660; + let v3663 = f453 * 1479; + let v3664 = f197 + v3663; + let v3665 = f197 - v3663; + let v3666 = v3664 * 4043; + let v3667 = v3661 + v3666; + let v3668 = v3661 - v3666; + let v3669 = v3665 * 5146; + let v3670 = v3662 + v3669; + let v3671 = v3662 - v3669; + let v3672 = v3667 * 5736; + let v3673 = v3655 + v3672; + let v3674 = v3655 - v3672; + let v3675 = v3668 * 4134; + let v3676 = v3656 + v3675; + let v3677 = v3656 - v3675; + let v3678 = v3670 * 722; + let v3679 = v3658 + v3678; + let v3680 = v3658 - v3678; + let v3681 = v3671 * 1305; + let v3682 = v3659 + v3681; + let v3683 = v3659 - v3681; + let v3684 = f293 * 1479; + let v3685 = f37 + v3684; + let v3686 = f37 - v3684; + let v3687 = f421 * 1479; + let v3688 = f165 + v3687; + let v3689 = f165 - v3687; + let v3690 = v3688 * 4043; + let v3691 = v3685 + v3690; + let v3692 = v3685 - v3690; + let v3693 = v3689 * 5146; + let v3694 = v3686 + v3693; + let v3695 = v3686 - v3693; + let v3696 = f357 * 1479; + let v3697 = f101 + v3696; + let v3698 = f101 - v3696; + let v3699 = f485 * 1479; + let v3700 = f229 + v3699; + let v3701 = f229 - v3699; + let v3702 = v3700 * 4043; + let v3703 = v3697 + v3702; + let v3704 = v3697 - v3702; + let v3705 = v3701 * 5146; + let v3706 = v3698 + v3705; + let v3707 = v3698 - v3705; + let v3708 = v3703 * 5736; + let v3709 = v3691 + v3708; + let v3710 = v3691 - v3708; + let v3711 = v3704 * 4134; + let v3712 = v3692 + v3711; + let v3713 = v3692 - v3711; + let v3714 = v3706 * 722; + let v3715 = v3694 + v3714; + let v3716 = v3694 - v3714; + let v3717 = v3707 * 1305; + let v3718 = v3695 + v3717; + let v3719 = v3695 - v3717; + let v3720 = v3709 * 1646; + let v3721 = v3673 + v3720; + let v3722 = v3673 - v3720; + let v3723 = v3710 * 1212; + let v3724 = v3674 + v3723; + let v3725 = v3674 - v3723; + let v3726 = v3712 * 5860; + let v3727 = v3676 + v3726; + let v3728 = v3676 - v3726; + let v3729 = v3713 * 3195; + let v3730 = v3677 + v3729; + let v3731 = v3677 - v3729; + let v3732 = v3715 * 2545; + let v3733 = v3679 + v3732; + let v3734 = v3679 - v3732; + let v3735 = v3716 * 3621; + let v3736 = v3680 + v3735; + let v3737 = v3680 - v3735; + let v3738 = v3718 * 3504; + let v3739 = v3682 + v3738; + let v3740 = v3682 - v3738; + let v3741 = v3719 * 3542; + let v3742 = v3683 + v3741; + let v3743 = v3683 - v3741; + let v3744 = f277 * 1479; + let v3745 = f21 + v3744; + let v3746 = f21 - v3744; + let v3747 = f405 * 1479; + let v3748 = f149 + v3747; + let v3749 = f149 - v3747; + let v3750 = v3748 * 4043; + let v3751 = v3745 + v3750; + let v3752 = v3745 - v3750; + let v3753 = v3749 * 5146; + let v3754 = v3746 + v3753; + let v3755 = v3746 - v3753; + let v3756 = f341 * 1479; + let v3757 = f85 + v3756; + let v3758 = f85 - v3756; + let v3759 = f469 * 1479; + let v3760 = f213 + v3759; + let v3761 = f213 - v3759; + let v3762 = v3760 * 4043; + let v3763 = v3757 + v3762; + let v3764 = v3757 - v3762; + let v3765 = v3761 * 5146; + let v3766 = v3758 + v3765; + let v3767 = v3758 - v3765; + let v3768 = v3763 * 5736; + let v3769 = v3751 + v3768; + let v3770 = v3751 - v3768; + let v3771 = v3764 * 4134; + let v3772 = v3752 + v3771; + let v3773 = v3752 - v3771; + let v3774 = v3766 * 722; + let v3775 = v3754 + v3774; + let v3776 = v3754 - v3774; + let v3777 = v3767 * 1305; + let v3778 = v3755 + v3777; + let v3779 = v3755 - v3777; + let v3780 = f309 * 1479; + let v3781 = f53 + v3780; + let v3782 = f53 - v3780; + let v3783 = f437 * 1479; + let v3784 = f181 + v3783; + let v3785 = f181 - v3783; + let v3786 = v3784 * 4043; + let v3787 = v3781 + v3786; + let v3788 = v3781 - v3786; + let v3789 = v3785 * 5146; + let v3790 = v3782 + v3789; + let v3791 = v3782 - v3789; + let v3792 = f373 * 1479; + let v3793 = f117 + v3792; + let v3794 = f117 - v3792; + let v3795 = f501 * 1479; + let v3796 = f245 + v3795; + let v3797 = f245 - v3795; + let v3798 = v3796 * 4043; + let v3799 = v3793 + v3798; + let v3800 = v3793 - v3798; + let v3801 = v3797 * 5146; + let v3802 = v3794 + v3801; + let v3803 = v3794 - v3801; + let v3804 = v3799 * 5736; + let v3805 = v3787 + v3804; + let v3806 = v3787 - v3804; + let v3807 = v3800 * 4134; + let v3808 = v3788 + v3807; + let v3809 = v3788 - v3807; + let v3810 = v3802 * 722; + let v3811 = v3790 + v3810; + let v3812 = v3790 - v3810; + let v3813 = v3803 * 1305; + let v3814 = v3791 + v3813; + let v3815 = v3791 - v3813; + let v3816 = v3805 * 1646; + let v3817 = v3769 + v3816; + let v3818 = v3769 - v3816; + let v3819 = v3806 * 1212; + let v3820 = v3770 + v3819; + let v3821 = v3770 - v3819; + let v3822 = v3808 * 5860; + let v3823 = v3772 + v3822; + let v3824 = v3772 - v3822; + let v3825 = v3809 * 3195; + let v3826 = v3773 + v3825; + let v3827 = v3773 - v3825; + let v3828 = v3811 * 2545; + let v3829 = v3775 + v3828; + let v3830 = v3775 - v3828; + let v3831 = v3812 * 3621; + let v3832 = v3776 + v3831; + let v3833 = v3776 - v3831; + let v3834 = v3814 * 3504; + let v3835 = v3778 + v3834; + let v3836 = v3778 - v3834; + let v3837 = v3815 * 3542; + let v3838 = v3779 + v3837; + let v3839 = v3779 - v3837; + let v3840 = v3817 * 4591; + let v3841 = v3721 + v3840; + let v3842 = v3721 - v3840; + let v3843 = v3818 * 5728; + let v3844 = v3722 + v3843; + let v3845 = v3722 - v3843; + let v3846 = v3820 * 5023; + let v3847 = v3724 + v3846; + let v3848 = v3724 - v3846; + let v3849 = v3821 * 5828; + let v3850 = v3725 + v3849; + let v3851 = v3725 - v3849; + let v3852 = v3823 * 4978; + let v3853 = v3727 + v3852; + let v3854 = v3727 - v3852; + let v3855 = v3824 * 1351; + let v3856 = v3728 + v3855; + let v3857 = v3728 - v3855; + let v3858 = v3826 * 3328; + let v3859 = v3730 + v3858; + let v3860 = v3730 - v3858; + let v3861 = v3827 * 5777; + let v3862 = v3731 + v3861; + let v3863 = v3731 - v3861; + let v3864 = v3829 * 2975; + let v3865 = v3733 + v3864; + let v3866 = v3733 - v3864; + let v3867 = v3830 * 563; + let v3868 = v3734 + v3867; + let v3869 = v3734 - v3867; + let v3870 = v3832 * 3006; + let v3871 = v3736 + v3870; + let v3872 = v3736 - v3870; + let v3873 = v3833 * 2744; + let v3874 = v3737 + v3873; + let v3875 = v3737 - v3873; + let v3876 = v3835 * 949; + let v3877 = v3739 + v3876; + let v3878 = v3739 - v3876; + let v3879 = v3836 * 2625; + let v3880 = v3740 + v3879; + let v3881 = v3740 - v3879; + let v3882 = v3838 * 4821; + let v3883 = v3742 + v3882; + let v3884 = v3742 - v3882; + let v3885 = v3839 * 2639; + let v3886 = v3743 + v3885; + let v3887 = v3743 - v3885; + let v3888 = f269 * 1479; + let v3889 = f13 + v3888; + let v3890 = f13 - v3888; + let v3891 = f397 * 1479; + let v3892 = f141 + v3891; + let v3893 = f141 - v3891; + let v3894 = v3892 * 4043; + let v3895 = v3889 + v3894; + let v3896 = v3889 - v3894; + let v3897 = v3893 * 5146; + let v3898 = v3890 + v3897; + let v3899 = v3890 - v3897; + let v3900 = f333 * 1479; + let v3901 = f77 + v3900; + let v3902 = f77 - v3900; + let v3903 = f461 * 1479; + let v3904 = f205 + v3903; + let v3905 = f205 - v3903; + let v3906 = v3904 * 4043; + let v3907 = v3901 + v3906; + let v3908 = v3901 - v3906; + let v3909 = v3905 * 5146; + let v3910 = v3902 + v3909; + let v3911 = v3902 - v3909; + let v3912 = v3907 * 5736; + let v3913 = v3895 + v3912; + let v3914 = v3895 - v3912; + let v3915 = v3908 * 4134; + let v3916 = v3896 + v3915; + let v3917 = v3896 - v3915; + let v3918 = v3910 * 722; + let v3919 = v3898 + v3918; + let v3920 = v3898 - v3918; + let v3921 = v3911 * 1305; + let v3922 = v3899 + v3921; + let v3923 = v3899 - v3921; + let v3924 = f301 * 1479; + let v3925 = f45 + v3924; + let v3926 = f45 - v3924; + let v3927 = f429 * 1479; + let v3928 = f173 + v3927; + let v3929 = f173 - v3927; + let v3930 = v3928 * 4043; + let v3931 = v3925 + v3930; + let v3932 = v3925 - v3930; + let v3933 = v3929 * 5146; + let v3934 = v3926 + v3933; + let v3935 = v3926 - v3933; + let v3936 = f365 * 1479; + let v3937 = f109 + v3936; + let v3938 = f109 - v3936; + let v3939 = f493 * 1479; + let v3940 = f237 + v3939; + let v3941 = f237 - v3939; + let v3942 = v3940 * 4043; + let v3943 = v3937 + v3942; + let v3944 = v3937 - v3942; + let v3945 = v3941 * 5146; + let v3946 = v3938 + v3945; + let v3947 = v3938 - v3945; + let v3948 = v3943 * 5736; + let v3949 = v3931 + v3948; + let v3950 = v3931 - v3948; + let v3951 = v3944 * 4134; + let v3952 = v3932 + v3951; + let v3953 = v3932 - v3951; + let v3954 = v3946 * 722; + let v3955 = v3934 + v3954; + let v3956 = v3934 - v3954; + let v3957 = v3947 * 1305; + let v3958 = v3935 + v3957; + let v3959 = v3935 - v3957; + let v3960 = v3949 * 1646; + let v3961 = v3913 + v3960; + let v3962 = v3913 - v3960; + let v3963 = v3950 * 1212; + let v3964 = v3914 + v3963; + let v3965 = v3914 - v3963; + let v3966 = v3952 * 5860; + let v3967 = v3916 + v3966; + let v3968 = v3916 - v3966; + let v3969 = v3953 * 3195; + let v3970 = v3917 + v3969; + let v3971 = v3917 - v3969; + let v3972 = v3955 * 2545; + let v3973 = v3919 + v3972; + let v3974 = v3919 - v3972; + let v3975 = v3956 * 3621; + let v3976 = v3920 + v3975; + let v3977 = v3920 - v3975; + let v3978 = v3958 * 3504; + let v3979 = v3922 + v3978; + let v3980 = v3922 - v3978; + let v3981 = v3959 * 3542; + let v3982 = v3923 + v3981; + let v3983 = v3923 - v3981; + let v3984 = f285 * 1479; + let v3985 = f29 + v3984; + let v3986 = f29 - v3984; + let v3987 = f413 * 1479; + let v3988 = f157 + v3987; + let v3989 = f157 - v3987; + let v3990 = v3988 * 4043; + let v3991 = v3985 + v3990; + let v3992 = v3985 - v3990; + let v3993 = v3989 * 5146; + let v3994 = v3986 + v3993; + let v3995 = v3986 - v3993; + let v3996 = f349 * 1479; + let v3997 = f93 + v3996; + let v3998 = f93 - v3996; + let v3999 = f477 * 1479; + let v4000 = f221 + v3999; + let v4001 = f221 - v3999; + let v4002 = v4000 * 4043; + let v4003 = v3997 + v4002; + let v4004 = v3997 - v4002; + let v4005 = v4001 * 5146; + let v4006 = v3998 + v4005; + let v4007 = v3998 - v4005; + let v4008 = v4003 * 5736; + let v4009 = v3991 + v4008; + let v4010 = v3991 - v4008; + let v4011 = v4004 * 4134; + let v4012 = v3992 + v4011; + let v4013 = v3992 - v4011; + let v4014 = v4006 * 722; + let v4015 = v3994 + v4014; + let v4016 = v3994 - v4014; + let v4017 = v4007 * 1305; + let v4018 = v3995 + v4017; + let v4019 = v3995 - v4017; + let v4020 = f317 * 1479; + let v4021 = f61 + v4020; + let v4022 = f61 - v4020; + let v4023 = f445 * 1479; + let v4024 = f189 + v4023; + let v4025 = f189 - v4023; + let v4026 = v4024 * 4043; + let v4027 = v4021 + v4026; + let v4028 = v4021 - v4026; + let v4029 = v4025 * 5146; + let v4030 = v4022 + v4029; + let v4031 = v4022 - v4029; + let v4032 = f381 * 1479; + let v4033 = f125 + v4032; + let v4034 = f125 - v4032; + let v4035 = f509 * 1479; + let v4036 = f253 + v4035; + let v4037 = f253 - v4035; + let v4038 = v4036 * 4043; + let v4039 = v4033 + v4038; + let v4040 = v4033 - v4038; + let v4041 = v4037 * 5146; + let v4042 = v4034 + v4041; + let v4043 = v4034 - v4041; + let v4044 = v4039 * 5736; + let v4045 = v4027 + v4044; + let v4046 = v4027 - v4044; + let v4047 = v4040 * 4134; + let v4048 = v4028 + v4047; + let v4049 = v4028 - v4047; + let v4050 = v4042 * 722; + let v4051 = v4030 + v4050; + let v4052 = v4030 - v4050; + let v4053 = v4043 * 1305; + let v4054 = v4031 + v4053; + let v4055 = v4031 - v4053; + let v4056 = v4045 * 1646; + let v4057 = v4009 + v4056; + let v4058 = v4009 - v4056; + let v4059 = v4046 * 1212; + let v4060 = v4010 + v4059; + let v4061 = v4010 - v4059; + let v4062 = v4048 * 5860; + let v4063 = v4012 + v4062; + let v4064 = v4012 - v4062; + let v4065 = v4049 * 3195; + let v4066 = v4013 + v4065; + let v4067 = v4013 - v4065; + let v4068 = v4051 * 2545; + let v4069 = v4015 + v4068; + let v4070 = v4015 - v4068; + let v4071 = v4052 * 3621; + let v4072 = v4016 + v4071; + let v4073 = v4016 - v4071; + let v4074 = v4054 * 3504; + let v4075 = v4018 + v4074; + let v4076 = v4018 - v4074; + let v4077 = v4055 * 3542; + let v4078 = v4019 + v4077; + let v4079 = v4019 - v4077; + let v4080 = v4057 * 4591; + let v4081 = v3961 + v4080; + let v4082 = v3961 - v4080; + let v4083 = v4058 * 5728; + let v4084 = v3962 + v4083; + let v4085 = v3962 - v4083; + let v4086 = v4060 * 5023; + let v4087 = v3964 + v4086; + let v4088 = v3964 - v4086; + let v4089 = v4061 * 5828; + let v4090 = v3965 + v4089; + let v4091 = v3965 - v4089; + let v4092 = v4063 * 4978; + let v4093 = v3967 + v4092; + let v4094 = v3967 - v4092; + let v4095 = v4064 * 1351; + let v4096 = v3968 + v4095; + let v4097 = v3968 - v4095; + let v4098 = v4066 * 3328; + let v4099 = v3970 + v4098; + let v4100 = v3970 - v4098; + let v4101 = v4067 * 5777; + let v4102 = v3971 + v4101; + let v4103 = v3971 - v4101; + let v4104 = v4069 * 2975; + let v4105 = v3973 + v4104; + let v4106 = v3973 - v4104; + let v4107 = v4070 * 563; + let v4108 = v3974 + v4107; + let v4109 = v3974 - v4107; + let v4110 = v4072 * 3006; + let v4111 = v3976 + v4110; + let v4112 = v3976 - v4110; + let v4113 = v4073 * 2744; + let v4114 = v3977 + v4113; + let v4115 = v3977 - v4113; + let v4116 = v4075 * 949; + let v4117 = v3979 + v4116; + let v4118 = v3979 - v4116; + let v4119 = v4076 * 2625; + let v4120 = v3980 + v4119; + let v4121 = v3980 - v4119; + let v4122 = v4078 * 4821; + let v4123 = v3982 + v4122; + let v4124 = v3982 - v4122; + let v4125 = v4079 * 2639; + let v4126 = v3983 + v4125; + let v4127 = v3983 - v4125; + let v4128 = v4081 * 1000; + let v4129 = v3841 + v4128; + let v4130 = v3841 - v4128; + let v4131 = v4082 * 4320; + let v4132 = v3842 + v4131; + let v4133 = v3842 - v4131; + let v4134 = v4084 * 3091; + let v4135 = v3844 + v4134; + let v4136 = v3844 - v4134; + let v4137 = v4085 * 81; + let v4138 = v3845 + v4137; + let v4139 = v3845 - v4137; + let v4140 = v4087 * 2963; + let v4141 = v3847 + v4140; + let v4142 = v3847 - v4140; + let v4143 = v4088 * 4896; + let v4144 = v3848 + v4143; + let v4145 = v3848 - v4143; + let v4146 = v4090 * 3051; + let v4147 = v3850 + v4146; + let v4148 = v3850 - v4146; + let v4149 = v4091 * 2366; + let v4150 = v3851 + v4149; + let v4151 = v3851 - v4149; + let v4152 = v4093 * 1853; + let v4153 = v3853 + v4152; + let v4154 = v3853 - v4152; + let v4155 = v4094 * 140; + let v4156 = v3854 + v4155; + let v4157 = v3854 - v4155; + let v4158 = v4096 * 4611; + let v4159 = v3856 + v4158; + let v4160 = v3856 - v4158; + let v4161 = v4097 * 726; + let v4162 = v3857 + v4161; + let v4163 = v3857 - v4161; + let v4164 = v4099 * 4255; + let v4165 = v3859 + v4164; + let v4166 = v3859 - v4164; + let v4167 = v4100 * 1177; + let v4168 = v3860 + v4167; + let v4169 = v3860 - v4167; + let v4170 = v4102 * 2768; + let v4171 = v3862 + v4170; + let v4172 = v3862 - v4170; + let v4173 = v4103 * 1635; + let v4174 = v3863 + v4173; + let v4175 = v3863 - v4173; + let v4176 = v4105 * 3712; + let v4177 = v3865 + v4176; + let v4178 = v3865 - v4176; + let v4179 = v4106 * 3135; + let v4180 = v3866 + v4179; + let v4181 = v3866 - v4179; + let v4182 = v4108 * 2747; + let v4183 = v3868 + v4182; + let v4184 = v3868 - v4182; + let v4185 = v4109 * 4846; + let v4186 = v3869 + v4185; + let v4187 = v3869 - v4185; + let v4188 = v4111 * 3553; + let v4189 = v3871 + v4188; + let v4190 = v3871 - v4188; + let v4191 = v4112 * 4805; + let v4192 = v3872 + v4191; + let v4193 = v3872 - v4191; + let v4194 = v4114 * 2294; + let v4195 = v3874 + v4194; + let v4196 = v3874 - v4194; + let v4197 = v4115 * 1062; + let v4198 = v3875 + v4197; + let v4199 = v3875 - v4197; + let v4200 = v4117 * 1326; + let v4201 = v3877 + v4200; + let v4202 = v3877 - v4200; + let v4203 = v4118 * 5086; + let v4204 = v3878 + v4203; + let v4205 = v3878 - v4203; + let v4206 = v4120 * 3014; + let v4207 = v3880 + v4206; + let v4208 = v3880 - v4206; + let v4209 = v4121 * 3201; + let v4210 = v3881 + v4209; + let v4211 = v3881 - v4209; + let v4212 = v4123 * 1170; + let v4213 = v3883 + v4212; + let v4214 = v3883 - v4212; + let v4215 = v4124 * 2319; + let v4216 = v3884 + v4215; + let v4217 = v3884 - v4215; + let v4218 = v4126 * 955; + let v4219 = v3886 + v4218; + let v4220 = v3886 - v4218; + let v4221 = v4127 * 790; + let v4222 = v3887 + v4221; + let v4223 = v3887 - v4221; + let v4224 = v4129 * 544; + let v4225 = v3553 + v4224; + let v4226 = v3553 - v4224; + let v4227 = v4130 * 5791; + let v4228 = v3554 + v4227; + let v4229 = v3554 - v4227; + let v4230 = v4132 * 339; + let v4231 = v3556 + v4230; + let v4232 = v3556 - v4230; + let v4233 = v4133 * 2468; + let v4234 = v3557 + v4233; + let v4235 = v3557 - v4233; + let v4236 = v4135 * 2842; + let v4237 = v3559 + v4236; + let v4238 = v3559 - v4236; + let v4239 = v4136 * 480; + let v4240 = v3560 + v4239; + let v4241 = v3560 - v4239; + let v4242 = v4138 * 9; + let v4243 = v3562 + v4242; + let v4244 = v3562 - v4242; + let v4245 = v4139 * 1022; + let v4246 = v3563 + v4245; + let v4247 = v3563 - v4245; + let v4248 = v4141 * 4278; + let v4249 = v3565 + v4248; + let v4250 = v3565 - v4248; + let v4251 = v4142 * 1673; + let v4252 = v3566 + v4251; + let v4253 = v3566 - v4251; + let v4254 = v4144 * 4989; + let v4255 = v3568 + v4254; + let v4256 = v3568 - v4254; + let v4257 = v4145 * 5331; + let v4258 = v3569 + v4257; + let v4259 = v3569 - v4257; + let v4260 = v4147 * 3584; + let v4261 = v3571 + v4260; + let v4262 = v3571 - v4260; + let v4263 = v4148 * 4177; + let v4264 = v3572 + v4263; + let v4265 = v3572 - v4263; + let v4266 = v4150 * 1381; + let v4267 = v3574 + v4266; + let v4268 = v3574 - v4266; + let v4269 = v4151 * 2525; + let v4270 = v3575 + v4269; + let v4271 = v3575 - v4269; + let v4272 = v4153 * 2396; + let v4273 = v3577 + v4272; + let v4274 = v3577 - v4272; + let v4275 = v4154 * 4452; + let v4276 = v3578 + v4275; + let v4277 = v3578 - v4275; + let v4278 = v4156 * 3296; + let v4279 = v3580 + v4278; + let v4280 = v3580 - v4278; + let v4281 = v4157 * 3949; + let v4282 = v3581 + v4281; + let v4283 = v3581 - v4281; + let v4284 = v4159 * 130; + let v4285 = v3583 + v4284; + let v4286 = v3583 - v4284; + let v4287 = v4160 * 4354; + let v4288 = v3584 + v4287; + let v4289 = v3584 - v4287; + let v4290 = v4162 * 5374; + let v4291 = v3586 + v4290; + let v4292 = v3586 - v4290; + let v4293 = v4163 * 2837; + let v4294 = v3587 + v4293; + let v4295 = v3587 - v4293; + let v4296 = v4165 * 5767; + let v4297 = v3589 + v4296; + let v4298 = v3589 - v4296; + let v4299 = v4166 * 827; + let v4300 = v3590 + v4299; + let v4301 = v3590 - v4299; + let v4302 = v4168 * 3748; + let v4303 = v3592 + v4302; + let v4304 = v3592 - v4302; + let v4305 = v4169 * 953; + let v4306 = v3593 + v4305; + let v4307 = v3593 - v4305; + let v4308 = v4171 * 5067; + let v4309 = v3595 + v4308; + let v4310 = v3595 - v4308; + let v4311 = v4172 * 2197; + let v4312 = v3596 + v4311; + let v4313 = v3596 - v4311; + let v4314 = v4174 * 118; + let v4315 = v3598 + v4314; + let v4316 = v3598 - v4314; + let v4317 = v4175 * 2476; + let v4318 = v3599 + v4317; + let v4319 = v3599 - v4317; + let v4320 = v4177 * 2548; + let v4321 = v3601 + v4320; + let v4322 = v3601 - v4320; + let v4323 = v4178 * 4231; + let v4324 = v3602 + v4323; + let v4325 = v3602 - v4323; + let v4326 = v4180 * 355; + let v4327 = v3604 + v4326; + let v4328 = v3604 - v4326; + let v4329 = v4181 * 3382; + let v4330 = v3605 + v4329; + let v4331 = v3605 - v4329; + let v4332 = v4183 * 3707; + let v4333 = v3607 + v4332; + let v4334 = v3607 - v4332; + let v4335 = v4184 * 1759; + let v4336 = v3608 + v4335; + let v4337 = v3608 - v4335; + let v4338 = v4186 * 3694; + let v4339 = v3610 + v4338; + let v4340 = v3610 - v4338; + let v4341 = v4187 * 5179; + let v4342 = v3611 + v4341; + let v4343 = v3611 - v4341; + let v4344 = v4189 * 5542; + let v4345 = v3613 + v4344; + let v4346 = v3613 - v4344; + let v4347 = v4190 * 145; + let v4348 = v3614 + v4347; + let v4349 = v3614 - v4347; + let v4350 = v4192 * 3637; + let v4351 = v3616 + v4350; + let v4352 = v3616 - v4350; + let v4353 = v4193 * 3459; + let v4354 = v3617 + v4353; + let v4355 = v3617 - v4353; + let v4356 = v4195 * 5911; + let v4357 = v3619 + v4356; + let v4358 = v3619 - v4356; + let v4359 = v4196 * 4890; + let v4360 = v3620 + v4359; + let v4361 = v3620 - v4359; + let v4362 = v4198 * 3932; + let v4363 = v3622 + v4362; + let v4364 = v3622 - v4362; + let v4365 = v4199 * 2731; + let v4366 = v3623 + v4365; + let v4367 = v3623 - v4365; + let v4368 = v4201 * 2089; + let v4369 = v3625 + v4368; + let v4370 = v3625 - v4368; + let v4371 = v4202 * 5092; + let v4372 = v3626 + v4371; + let v4373 = v3626 - v4371; + let v4374 = v4204 * 2881; + let v4375 = v3628 + v4374; + let v4376 = v3628 - v4374; + let v4377 = v4205 * 3284; + let v4378 = v3629 + v4377; + let v4379 = v3629 - v4377; + let v4380 = v4207 * 729; + let v4381 = v3631 + v4380; + let v4382 = v3631 - v4380; + let v4383 = v4208 * 3241; + let v4384 = v3632 + v4383; + let v4385 = v3632 - v4383; + let v4386 = v4210 * 3289; + let v4387 = v3634 + v4386; + let v4388 = v3634 - v4386; + let v4389 = v4211 * 2013; + let v4390 = v3635 + v4389; + let v4391 = v3635 - v4389; + let v4392 = v4213 * 5755; + let v4393 = v3637 + v4392; + let v4394 = v3637 - v4392; + let v4395 = v4214 * 4632; + let v4396 = v3638 + v4395; + let v4397 = v3638 - v4395; + let v4398 = v4216 * 1260; + let v4399 = v3640 + v4398; + let v4400 = v3640 - v4398; + let v4401 = v4217 * 4388; + let v4402 = v3641 + v4401; + let v4403 = v3641 - v4401; + let v4404 = v4219 * 334; + let v4405 = v3643 + v4404; + let v4406 = v3643 - v4404; + let v4407 = v4220 * 2426; + let v4408 = v3644 + v4407; + let v4409 = v3644 - v4407; + let v4410 = v4222 * 1696; + let v4411 = v3646 + v4410; + let v4412 = v3646 - v4410; + let v4413 = v4223 * 1428; + let v4414 = v3647 + v4413; + let v4415 = v3647 - v4413; + let v4416 = f259 * 1479; + let v4417 = f3 + v4416; + let v4418 = f3 - v4416; + let v4419 = f387 * 1479; + let v4420 = f131 + v4419; + let v4421 = f131 - v4419; + let v4422 = v4420 * 4043; + let v4423 = v4417 + v4422; + let v4424 = v4417 - v4422; + let v4425 = v4421 * 5146; + let v4426 = v4418 + v4425; + let v4427 = v4418 - v4425; + let v4428 = f323 * 1479; + let v4429 = f67 + v4428; + let v4430 = f67 - v4428; + let v4431 = f451 * 1479; + let v4432 = f195 + v4431; + let v4433 = f195 - v4431; + let v4434 = v4432 * 4043; + let v4435 = v4429 + v4434; + let v4436 = v4429 - v4434; + let v4437 = v4433 * 5146; + let v4438 = v4430 + v4437; + let v4439 = v4430 - v4437; + let v4440 = v4435 * 5736; + let v4441 = v4423 + v4440; + let v4442 = v4423 - v4440; + let v4443 = v4436 * 4134; + let v4444 = v4424 + v4443; + let v4445 = v4424 - v4443; + let v4446 = v4438 * 722; + let v4447 = v4426 + v4446; + let v4448 = v4426 - v4446; + let v4449 = v4439 * 1305; + let v4450 = v4427 + v4449; + let v4451 = v4427 - v4449; + let v4452 = f291 * 1479; + let v4453 = f35 + v4452; + let v4454 = f35 - v4452; + let v4455 = f419 * 1479; + let v4456 = f163 + v4455; + let v4457 = f163 - v4455; + let v4458 = v4456 * 4043; + let v4459 = v4453 + v4458; + let v4460 = v4453 - v4458; + let v4461 = v4457 * 5146; + let v4462 = v4454 + v4461; + let v4463 = v4454 - v4461; + let v4464 = f355 * 1479; + let v4465 = f99 + v4464; + let v4466 = f99 - v4464; + let v4467 = f483 * 1479; + let v4468 = f227 + v4467; + let v4469 = f227 - v4467; + let v4470 = v4468 * 4043; + let v4471 = v4465 + v4470; + let v4472 = v4465 - v4470; + let v4473 = v4469 * 5146; + let v4474 = v4466 + v4473; + let v4475 = v4466 - v4473; + let v4476 = v4471 * 5736; + let v4477 = v4459 + v4476; + let v4478 = v4459 - v4476; + let v4479 = v4472 * 4134; + let v4480 = v4460 + v4479; + let v4481 = v4460 - v4479; + let v4482 = v4474 * 722; + let v4483 = v4462 + v4482; + let v4484 = v4462 - v4482; + let v4485 = v4475 * 1305; + let v4486 = v4463 + v4485; + let v4487 = v4463 - v4485; + let v4488 = v4477 * 1646; + let v4489 = v4441 + v4488; + let v4490 = v4441 - v4488; + let v4491 = v4478 * 1212; + let v4492 = v4442 + v4491; + let v4493 = v4442 - v4491; + let v4494 = v4480 * 5860; + let v4495 = v4444 + v4494; + let v4496 = v4444 - v4494; + let v4497 = v4481 * 3195; + let v4498 = v4445 + v4497; + let v4499 = v4445 - v4497; + let v4500 = v4483 * 2545; + let v4501 = v4447 + v4500; + let v4502 = v4447 - v4500; + let v4503 = v4484 * 3621; + let v4504 = v4448 + v4503; + let v4505 = v4448 - v4503; + let v4506 = v4486 * 3504; + let v4507 = v4450 + v4506; + let v4508 = v4450 - v4506; + let v4509 = v4487 * 3542; + let v4510 = v4451 + v4509; + let v4511 = v4451 - v4509; + let v4512 = f275 * 1479; + let v4513 = f19 + v4512; + let v4514 = f19 - v4512; + let v4515 = f403 * 1479; + let v4516 = f147 + v4515; + let v4517 = f147 - v4515; + let v4518 = v4516 * 4043; + let v4519 = v4513 + v4518; + let v4520 = v4513 - v4518; + let v4521 = v4517 * 5146; + let v4522 = v4514 + v4521; + let v4523 = v4514 - v4521; + let v4524 = f339 * 1479; + let v4525 = f83 + v4524; + let v4526 = f83 - v4524; + let v4527 = f467 * 1479; + let v4528 = f211 + v4527; + let v4529 = f211 - v4527; + let v4530 = v4528 * 4043; + let v4531 = v4525 + v4530; + let v4532 = v4525 - v4530; + let v4533 = v4529 * 5146; + let v4534 = v4526 + v4533; + let v4535 = v4526 - v4533; + let v4536 = v4531 * 5736; + let v4537 = v4519 + v4536; + let v4538 = v4519 - v4536; + let v4539 = v4532 * 4134; + let v4540 = v4520 + v4539; + let v4541 = v4520 - v4539; + let v4542 = v4534 * 722; + let v4543 = v4522 + v4542; + let v4544 = v4522 - v4542; + let v4545 = v4535 * 1305; + let v4546 = v4523 + v4545; + let v4547 = v4523 - v4545; + let v4548 = f307 * 1479; + let v4549 = f51 + v4548; + let v4550 = f51 - v4548; + let v4551 = f435 * 1479; + let v4552 = f179 + v4551; + let v4553 = f179 - v4551; + let v4554 = v4552 * 4043; + let v4555 = v4549 + v4554; + let v4556 = v4549 - v4554; + let v4557 = v4553 * 5146; + let v4558 = v4550 + v4557; + let v4559 = v4550 - v4557; + let v4560 = f371 * 1479; + let v4561 = f115 + v4560; + let v4562 = f115 - v4560; + let v4563 = f499 * 1479; + let v4564 = f243 + v4563; + let v4565 = f243 - v4563; + let v4566 = v4564 * 4043; + let v4567 = v4561 + v4566; + let v4568 = v4561 - v4566; + let v4569 = v4565 * 5146; + let v4570 = v4562 + v4569; + let v4571 = v4562 - v4569; + let v4572 = v4567 * 5736; + let v4573 = v4555 + v4572; + let v4574 = v4555 - v4572; + let v4575 = v4568 * 4134; + let v4576 = v4556 + v4575; + let v4577 = v4556 - v4575; + let v4578 = v4570 * 722; + let v4579 = v4558 + v4578; + let v4580 = v4558 - v4578; + let v4581 = v4571 * 1305; + let v4582 = v4559 + v4581; + let v4583 = v4559 - v4581; + let v4584 = v4573 * 1646; + let v4585 = v4537 + v4584; + let v4586 = v4537 - v4584; + let v4587 = v4574 * 1212; + let v4588 = v4538 + v4587; + let v4589 = v4538 - v4587; + let v4590 = v4576 * 5860; + let v4591 = v4540 + v4590; + let v4592 = v4540 - v4590; + let v4593 = v4577 * 3195; + let v4594 = v4541 + v4593; + let v4595 = v4541 - v4593; + let v4596 = v4579 * 2545; + let v4597 = v4543 + v4596; + let v4598 = v4543 - v4596; + let v4599 = v4580 * 3621; + let v4600 = v4544 + v4599; + let v4601 = v4544 - v4599; + let v4602 = v4582 * 3504; + let v4603 = v4546 + v4602; + let v4604 = v4546 - v4602; + let v4605 = v4583 * 3542; + let v4606 = v4547 + v4605; + let v4607 = v4547 - v4605; + let v4608 = v4585 * 4591; + let v4609 = v4489 + v4608; + let v4610 = v4489 - v4608; + let v4611 = v4586 * 5728; + let v4612 = v4490 + v4611; + let v4613 = v4490 - v4611; + let v4614 = v4588 * 5023; + let v4615 = v4492 + v4614; + let v4616 = v4492 - v4614; + let v4617 = v4589 * 5828; + let v4618 = v4493 + v4617; + let v4619 = v4493 - v4617; + let v4620 = v4591 * 4978; + let v4621 = v4495 + v4620; + let v4622 = v4495 - v4620; + let v4623 = v4592 * 1351; + let v4624 = v4496 + v4623; + let v4625 = v4496 - v4623; + let v4626 = v4594 * 3328; + let v4627 = v4498 + v4626; + let v4628 = v4498 - v4626; + let v4629 = v4595 * 5777; + let v4630 = v4499 + v4629; + let v4631 = v4499 - v4629; + let v4632 = v4597 * 2975; + let v4633 = v4501 + v4632; + let v4634 = v4501 - v4632; + let v4635 = v4598 * 563; + let v4636 = v4502 + v4635; + let v4637 = v4502 - v4635; + let v4638 = v4600 * 3006; + let v4639 = v4504 + v4638; + let v4640 = v4504 - v4638; + let v4641 = v4601 * 2744; + let v4642 = v4505 + v4641; + let v4643 = v4505 - v4641; + let v4644 = v4603 * 949; + let v4645 = v4507 + v4644; + let v4646 = v4507 - v4644; + let v4647 = v4604 * 2625; + let v4648 = v4508 + v4647; + let v4649 = v4508 - v4647; + let v4650 = v4606 * 4821; + let v4651 = v4510 + v4650; + let v4652 = v4510 - v4650; + let v4653 = v4607 * 2639; + let v4654 = v4511 + v4653; + let v4655 = v4511 - v4653; + let v4656 = f267 * 1479; + let v4657 = f11 + v4656; + let v4658 = f11 - v4656; + let v4659 = f395 * 1479; + let v4660 = f139 + v4659; + let v4661 = f139 - v4659; + let v4662 = v4660 * 4043; + let v4663 = v4657 + v4662; + let v4664 = v4657 - v4662; + let v4665 = v4661 * 5146; + let v4666 = v4658 + v4665; + let v4667 = v4658 - v4665; + let v4668 = f331 * 1479; + let v4669 = f75 + v4668; + let v4670 = f75 - v4668; + let v4671 = f459 * 1479; + let v4672 = f203 + v4671; + let v4673 = f203 - v4671; + let v4674 = v4672 * 4043; + let v4675 = v4669 + v4674; + let v4676 = v4669 - v4674; + let v4677 = v4673 * 5146; + let v4678 = v4670 + v4677; + let v4679 = v4670 - v4677; + let v4680 = v4675 * 5736; + let v4681 = v4663 + v4680; + let v4682 = v4663 - v4680; + let v4683 = v4676 * 4134; + let v4684 = v4664 + v4683; + let v4685 = v4664 - v4683; + let v4686 = v4678 * 722; + let v4687 = v4666 + v4686; + let v4688 = v4666 - v4686; + let v4689 = v4679 * 1305; + let v4690 = v4667 + v4689; + let v4691 = v4667 - v4689; + let v4692 = f299 * 1479; + let v4693 = f43 + v4692; + let v4694 = f43 - v4692; + let v4695 = f427 * 1479; + let v4696 = f171 + v4695; + let v4697 = f171 - v4695; + let v4698 = v4696 * 4043; + let v4699 = v4693 + v4698; + let v4700 = v4693 - v4698; + let v4701 = v4697 * 5146; + let v4702 = v4694 + v4701; + let v4703 = v4694 - v4701; + let v4704 = f363 * 1479; + let v4705 = f107 + v4704; + let v4706 = f107 - v4704; + let v4707 = f491 * 1479; + let v4708 = f235 + v4707; + let v4709 = f235 - v4707; + let v4710 = v4708 * 4043; + let v4711 = v4705 + v4710; + let v4712 = v4705 - v4710; + let v4713 = v4709 * 5146; + let v4714 = v4706 + v4713; + let v4715 = v4706 - v4713; + let v4716 = v4711 * 5736; + let v4717 = v4699 + v4716; + let v4718 = v4699 - v4716; + let v4719 = v4712 * 4134; + let v4720 = v4700 + v4719; + let v4721 = v4700 - v4719; + let v4722 = v4714 * 722; + let v4723 = v4702 + v4722; + let v4724 = v4702 - v4722; + let v4725 = v4715 * 1305; + let v4726 = v4703 + v4725; + let v4727 = v4703 - v4725; + let v4728 = v4717 * 1646; + let v4729 = v4681 + v4728; + let v4730 = v4681 - v4728; + let v4731 = v4718 * 1212; + let v4732 = v4682 + v4731; + let v4733 = v4682 - v4731; + let v4734 = v4720 * 5860; + let v4735 = v4684 + v4734; + let v4736 = v4684 - v4734; + let v4737 = v4721 * 3195; + let v4738 = v4685 + v4737; + let v4739 = v4685 - v4737; + let v4740 = v4723 * 2545; + let v4741 = v4687 + v4740; + let v4742 = v4687 - v4740; + let v4743 = v4724 * 3621; + let v4744 = v4688 + v4743; + let v4745 = v4688 - v4743; + let v4746 = v4726 * 3504; + let v4747 = v4690 + v4746; + let v4748 = v4690 - v4746; + let v4749 = v4727 * 3542; + let v4750 = v4691 + v4749; + let v4751 = v4691 - v4749; + let v4752 = f283 * 1479; + let v4753 = f27 + v4752; + let v4754 = f27 - v4752; + let v4755 = f411 * 1479; + let v4756 = f155 + v4755; + let v4757 = f155 - v4755; + let v4758 = v4756 * 4043; + let v4759 = v4753 + v4758; + let v4760 = v4753 - v4758; + let v4761 = v4757 * 5146; + let v4762 = v4754 + v4761; + let v4763 = v4754 - v4761; + let v4764 = f347 * 1479; + let v4765 = f91 + v4764; + let v4766 = f91 - v4764; + let v4767 = f475 * 1479; + let v4768 = f219 + v4767; + let v4769 = f219 - v4767; + let v4770 = v4768 * 4043; + let v4771 = v4765 + v4770; + let v4772 = v4765 - v4770; + let v4773 = v4769 * 5146; + let v4774 = v4766 + v4773; + let v4775 = v4766 - v4773; + let v4776 = v4771 * 5736; + let v4777 = v4759 + v4776; + let v4778 = v4759 - v4776; + let v4779 = v4772 * 4134; + let v4780 = v4760 + v4779; + let v4781 = v4760 - v4779; + let v4782 = v4774 * 722; + let v4783 = v4762 + v4782; + let v4784 = v4762 - v4782; + let v4785 = v4775 * 1305; + let v4786 = v4763 + v4785; + let v4787 = v4763 - v4785; + let v4788 = f315 * 1479; + let v4789 = f59 + v4788; + let v4790 = f59 - v4788; + let v4791 = f443 * 1479; + let v4792 = f187 + v4791; + let v4793 = f187 - v4791; + let v4794 = v4792 * 4043; + let v4795 = v4789 + v4794; + let v4796 = v4789 - v4794; + let v4797 = v4793 * 5146; + let v4798 = v4790 + v4797; + let v4799 = v4790 - v4797; + let v4800 = f379 * 1479; + let v4801 = f123 + v4800; + let v4802 = f123 - v4800; + let v4803 = f507 * 1479; + let v4804 = f251 + v4803; + let v4805 = f251 - v4803; + let v4806 = v4804 * 4043; + let v4807 = v4801 + v4806; + let v4808 = v4801 - v4806; + let v4809 = v4805 * 5146; + let v4810 = v4802 + v4809; + let v4811 = v4802 - v4809; + let v4812 = v4807 * 5736; + let v4813 = v4795 + v4812; + let v4814 = v4795 - v4812; + let v4815 = v4808 * 4134; + let v4816 = v4796 + v4815; + let v4817 = v4796 - v4815; + let v4818 = v4810 * 722; + let v4819 = v4798 + v4818; + let v4820 = v4798 - v4818; + let v4821 = v4811 * 1305; + let v4822 = v4799 + v4821; + let v4823 = v4799 - v4821; + let v4824 = v4813 * 1646; + let v4825 = v4777 + v4824; + let v4826 = v4777 - v4824; + let v4827 = v4814 * 1212; + let v4828 = v4778 + v4827; + let v4829 = v4778 - v4827; + let v4830 = v4816 * 5860; + let v4831 = v4780 + v4830; + let v4832 = v4780 - v4830; + let v4833 = v4817 * 3195; + let v4834 = v4781 + v4833; + let v4835 = v4781 - v4833; + let v4836 = v4819 * 2545; + let v4837 = v4783 + v4836; + let v4838 = v4783 - v4836; + let v4839 = v4820 * 3621; + let v4840 = v4784 + v4839; + let v4841 = v4784 - v4839; + let v4842 = v4822 * 3504; + let v4843 = v4786 + v4842; + let v4844 = v4786 - v4842; + let v4845 = v4823 * 3542; + let v4846 = v4787 + v4845; + let v4847 = v4787 - v4845; + let v4848 = v4825 * 4591; + let v4849 = v4729 + v4848; + let v4850 = v4729 - v4848; + let v4851 = v4826 * 5728; + let v4852 = v4730 + v4851; + let v4853 = v4730 - v4851; + let v4854 = v4828 * 5023; + let v4855 = v4732 + v4854; + let v4856 = v4732 - v4854; + let v4857 = v4829 * 5828; + let v4858 = v4733 + v4857; + let v4859 = v4733 - v4857; + let v4860 = v4831 * 4978; + let v4861 = v4735 + v4860; + let v4862 = v4735 - v4860; + let v4863 = v4832 * 1351; + let v4864 = v4736 + v4863; + let v4865 = v4736 - v4863; + let v4866 = v4834 * 3328; + let v4867 = v4738 + v4866; + let v4868 = v4738 - v4866; + let v4869 = v4835 * 5777; + let v4870 = v4739 + v4869; + let v4871 = v4739 - v4869; + let v4872 = v4837 * 2975; + let v4873 = v4741 + v4872; + let v4874 = v4741 - v4872; + let v4875 = v4838 * 563; + let v4876 = v4742 + v4875; + let v4877 = v4742 - v4875; + let v4878 = v4840 * 3006; + let v4879 = v4744 + v4878; + let v4880 = v4744 - v4878; + let v4881 = v4841 * 2744; + let v4882 = v4745 + v4881; + let v4883 = v4745 - v4881; + let v4884 = v4843 * 949; + let v4885 = v4747 + v4884; + let v4886 = v4747 - v4884; + let v4887 = v4844 * 2625; + let v4888 = v4748 + v4887; + let v4889 = v4748 - v4887; + let v4890 = v4846 * 4821; + let v4891 = v4750 + v4890; + let v4892 = v4750 - v4890; + let v4893 = v4847 * 2639; + let v4894 = v4751 + v4893; + let v4895 = v4751 - v4893; + let v4896 = v4849 * 1000; + let v4897 = v4609 + v4896; + let v4898 = v4609 - v4896; + let v4899 = v4850 * 4320; + let v4900 = v4610 + v4899; + let v4901 = v4610 - v4899; + let v4902 = v4852 * 3091; + let v4903 = v4612 + v4902; + let v4904 = v4612 - v4902; + let v4905 = v4853 * 81; + let v4906 = v4613 + v4905; + let v4907 = v4613 - v4905; + let v4908 = v4855 * 2963; + let v4909 = v4615 + v4908; + let v4910 = v4615 - v4908; + let v4911 = v4856 * 4896; + let v4912 = v4616 + v4911; + let v4913 = v4616 - v4911; + let v4914 = v4858 * 3051; + let v4915 = v4618 + v4914; + let v4916 = v4618 - v4914; + let v4917 = v4859 * 2366; + let v4918 = v4619 + v4917; + let v4919 = v4619 - v4917; + let v4920 = v4861 * 1853; + let v4921 = v4621 + v4920; + let v4922 = v4621 - v4920; + let v4923 = v4862 * 140; + let v4924 = v4622 + v4923; + let v4925 = v4622 - v4923; + let v4926 = v4864 * 4611; + let v4927 = v4624 + v4926; + let v4928 = v4624 - v4926; + let v4929 = v4865 * 726; + let v4930 = v4625 + v4929; + let v4931 = v4625 - v4929; + let v4932 = v4867 * 4255; + let v4933 = v4627 + v4932; + let v4934 = v4627 - v4932; + let v4935 = v4868 * 1177; + let v4936 = v4628 + v4935; + let v4937 = v4628 - v4935; + let v4938 = v4870 * 2768; + let v4939 = v4630 + v4938; + let v4940 = v4630 - v4938; + let v4941 = v4871 * 1635; + let v4942 = v4631 + v4941; + let v4943 = v4631 - v4941; + let v4944 = v4873 * 3712; + let v4945 = v4633 + v4944; + let v4946 = v4633 - v4944; + let v4947 = v4874 * 3135; + let v4948 = v4634 + v4947; + let v4949 = v4634 - v4947; + let v4950 = v4876 * 2747; + let v4951 = v4636 + v4950; + let v4952 = v4636 - v4950; + let v4953 = v4877 * 4846; + let v4954 = v4637 + v4953; + let v4955 = v4637 - v4953; + let v4956 = v4879 * 3553; + let v4957 = v4639 + v4956; + let v4958 = v4639 - v4956; + let v4959 = v4880 * 4805; + let v4960 = v4640 + v4959; + let v4961 = v4640 - v4959; + let v4962 = v4882 * 2294; + let v4963 = v4642 + v4962; + let v4964 = v4642 - v4962; + let v4965 = v4883 * 1062; + let v4966 = v4643 + v4965; + let v4967 = v4643 - v4965; + let v4968 = v4885 * 1326; + let v4969 = v4645 + v4968; + let v4970 = v4645 - v4968; + let v4971 = v4886 * 5086; + let v4972 = v4646 + v4971; + let v4973 = v4646 - v4971; + let v4974 = v4888 * 3014; + let v4975 = v4648 + v4974; + let v4976 = v4648 - v4974; + let v4977 = v4889 * 3201; + let v4978 = v4649 + v4977; + let v4979 = v4649 - v4977; + let v4980 = v4891 * 1170; + let v4981 = v4651 + v4980; + let v4982 = v4651 - v4980; + let v4983 = v4892 * 2319; + let v4984 = v4652 + v4983; + let v4985 = v4652 - v4983; + let v4986 = v4894 * 955; + let v4987 = v4654 + v4986; + let v4988 = v4654 - v4986; + let v4989 = v4895 * 790; + let v4990 = v4655 + v4989; + let v4991 = v4655 - v4989; + let v4992 = f263 * 1479; + let v4993 = f7 + v4992; + let v4994 = f7 - v4992; + let v4995 = f391 * 1479; + let v4996 = f135 + v4995; + let v4997 = f135 - v4995; + let v4998 = v4996 * 4043; + let v4999 = v4993 + v4998; + let v5000 = v4993 - v4998; + let v5001 = v4997 * 5146; + let v5002 = v4994 + v5001; + let v5003 = v4994 - v5001; + let v5004 = f327 * 1479; + let v5005 = f71 + v5004; + let v5006 = f71 - v5004; + let v5007 = f455 * 1479; + let v5008 = f199 + v5007; + let v5009 = f199 - v5007; + let v5010 = v5008 * 4043; + let v5011 = v5005 + v5010; + let v5012 = v5005 - v5010; + let v5013 = v5009 * 5146; + let v5014 = v5006 + v5013; + let v5015 = v5006 - v5013; + let v5016 = v5011 * 5736; + let v5017 = v4999 + v5016; + let v5018 = v4999 - v5016; + let v5019 = v5012 * 4134; + let v5020 = v5000 + v5019; + let v5021 = v5000 - v5019; + let v5022 = v5014 * 722; + let v5023 = v5002 + v5022; + let v5024 = v5002 - v5022; + let v5025 = v5015 * 1305; + let v5026 = v5003 + v5025; + let v5027 = v5003 - v5025; + let v5028 = f295 * 1479; + let v5029 = f39 + v5028; + let v5030 = f39 - v5028; + let v5031 = f423 * 1479; + let v5032 = f167 + v5031; + let v5033 = f167 - v5031; + let v5034 = v5032 * 4043; + let v5035 = v5029 + v5034; + let v5036 = v5029 - v5034; + let v5037 = v5033 * 5146; + let v5038 = v5030 + v5037; + let v5039 = v5030 - v5037; + let v5040 = f359 * 1479; + let v5041 = f103 + v5040; + let v5042 = f103 - v5040; + let v5043 = f487 * 1479; + let v5044 = f231 + v5043; + let v5045 = f231 - v5043; + let v5046 = v5044 * 4043; + let v5047 = v5041 + v5046; + let v5048 = v5041 - v5046; + let v5049 = v5045 * 5146; + let v5050 = v5042 + v5049; + let v5051 = v5042 - v5049; + let v5052 = v5047 * 5736; + let v5053 = v5035 + v5052; + let v5054 = v5035 - v5052; + let v5055 = v5048 * 4134; + let v5056 = v5036 + v5055; + let v5057 = v5036 - v5055; + let v5058 = v5050 * 722; + let v5059 = v5038 + v5058; + let v5060 = v5038 - v5058; + let v5061 = v5051 * 1305; + let v5062 = v5039 + v5061; + let v5063 = v5039 - v5061; + let v5064 = v5053 * 1646; + let v5065 = v5017 + v5064; + let v5066 = v5017 - v5064; + let v5067 = v5054 * 1212; + let v5068 = v5018 + v5067; + let v5069 = v5018 - v5067; + let v5070 = v5056 * 5860; + let v5071 = v5020 + v5070; + let v5072 = v5020 - v5070; + let v5073 = v5057 * 3195; + let v5074 = v5021 + v5073; + let v5075 = v5021 - v5073; + let v5076 = v5059 * 2545; + let v5077 = v5023 + v5076; + let v5078 = v5023 - v5076; + let v5079 = v5060 * 3621; + let v5080 = v5024 + v5079; + let v5081 = v5024 - v5079; + let v5082 = v5062 * 3504; + let v5083 = v5026 + v5082; + let v5084 = v5026 - v5082; + let v5085 = v5063 * 3542; + let v5086 = v5027 + v5085; + let v5087 = v5027 - v5085; + let v5088 = f279 * 1479; + let v5089 = f23 + v5088; + let v5090 = f23 - v5088; + let v5091 = f407 * 1479; + let v5092 = f151 + v5091; + let v5093 = f151 - v5091; + let v5094 = v5092 * 4043; + let v5095 = v5089 + v5094; + let v5096 = v5089 - v5094; + let v5097 = v5093 * 5146; + let v5098 = v5090 + v5097; + let v5099 = v5090 - v5097; + let v5100 = f343 * 1479; + let v5101 = f87 + v5100; + let v5102 = f87 - v5100; + let v5103 = f471 * 1479; + let v5104 = f215 + v5103; + let v5105 = f215 - v5103; + let v5106 = v5104 * 4043; + let v5107 = v5101 + v5106; + let v5108 = v5101 - v5106; + let v5109 = v5105 * 5146; + let v5110 = v5102 + v5109; + let v5111 = v5102 - v5109; + let v5112 = v5107 * 5736; + let v5113 = v5095 + v5112; + let v5114 = v5095 - v5112; + let v5115 = v5108 * 4134; + let v5116 = v5096 + v5115; + let v5117 = v5096 - v5115; + let v5118 = v5110 * 722; + let v5119 = v5098 + v5118; + let v5120 = v5098 - v5118; + let v5121 = v5111 * 1305; + let v5122 = v5099 + v5121; + let v5123 = v5099 - v5121; + let v5124 = f311 * 1479; + let v5125 = f55 + v5124; + let v5126 = f55 - v5124; + let v5127 = f439 * 1479; + let v5128 = f183 + v5127; + let v5129 = f183 - v5127; + let v5130 = v5128 * 4043; + let v5131 = v5125 + v5130; + let v5132 = v5125 - v5130; + let v5133 = v5129 * 5146; + let v5134 = v5126 + v5133; + let v5135 = v5126 - v5133; + let v5136 = f375 * 1479; + let v5137 = f119 + v5136; + let v5138 = f119 - v5136; + let v5139 = f503 * 1479; + let v5140 = f247 + v5139; + let v5141 = f247 - v5139; + let v5142 = v5140 * 4043; + let v5143 = v5137 + v5142; + let v5144 = v5137 - v5142; + let v5145 = v5141 * 5146; + let v5146 = v5138 + v5145; + let v5147 = v5138 - v5145; + let v5148 = v5143 * 5736; + let v5149 = v5131 + v5148; + let v5150 = v5131 - v5148; + let v5151 = v5144 * 4134; + let v5152 = v5132 + v5151; + let v5153 = v5132 - v5151; + let v5154 = v5146 * 722; + let v5155 = v5134 + v5154; + let v5156 = v5134 - v5154; + let v5157 = v5147 * 1305; + let v5158 = v5135 + v5157; + let v5159 = v5135 - v5157; + let v5160 = v5149 * 1646; + let v5161 = v5113 + v5160; + let v5162 = v5113 - v5160; + let v5163 = v5150 * 1212; + let v5164 = v5114 + v5163; + let v5165 = v5114 - v5163; + let v5166 = v5152 * 5860; + let v5167 = v5116 + v5166; + let v5168 = v5116 - v5166; + let v5169 = v5153 * 3195; + let v5170 = v5117 + v5169; + let v5171 = v5117 - v5169; + let v5172 = v5155 * 2545; + let v5173 = v5119 + v5172; + let v5174 = v5119 - v5172; + let v5175 = v5156 * 3621; + let v5176 = v5120 + v5175; + let v5177 = v5120 - v5175; + let v5178 = v5158 * 3504; + let v5179 = v5122 + v5178; + let v5180 = v5122 - v5178; + let v5181 = v5159 * 3542; + let v5182 = v5123 + v5181; + let v5183 = v5123 - v5181; + let v5184 = v5161 * 4591; + let v5185 = v5065 + v5184; + let v5186 = v5065 - v5184; + let v5187 = v5162 * 5728; + let v5188 = v5066 + v5187; + let v5189 = v5066 - v5187; + let v5190 = v5164 * 5023; + let v5191 = v5068 + v5190; + let v5192 = v5068 - v5190; + let v5193 = v5165 * 5828; + let v5194 = v5069 + v5193; + let v5195 = v5069 - v5193; + let v5196 = v5167 * 4978; + let v5197 = v5071 + v5196; + let v5198 = v5071 - v5196; + let v5199 = v5168 * 1351; + let v5200 = v5072 + v5199; + let v5201 = v5072 - v5199; + let v5202 = v5170 * 3328; + let v5203 = v5074 + v5202; + let v5204 = v5074 - v5202; + let v5205 = v5171 * 5777; + let v5206 = v5075 + v5205; + let v5207 = v5075 - v5205; + let v5208 = v5173 * 2975; + let v5209 = v5077 + v5208; + let v5210 = v5077 - v5208; + let v5211 = v5174 * 563; + let v5212 = v5078 + v5211; + let v5213 = v5078 - v5211; + let v5214 = v5176 * 3006; + let v5215 = v5080 + v5214; + let v5216 = v5080 - v5214; + let v5217 = v5177 * 2744; + let v5218 = v5081 + v5217; + let v5219 = v5081 - v5217; + let v5220 = v5179 * 949; + let v5221 = v5083 + v5220; + let v5222 = v5083 - v5220; + let v5223 = v5180 * 2625; + let v5224 = v5084 + v5223; + let v5225 = v5084 - v5223; + let v5226 = v5182 * 4821; + let v5227 = v5086 + v5226; + let v5228 = v5086 - v5226; + let v5229 = v5183 * 2639; + let v5230 = v5087 + v5229; + let v5231 = v5087 - v5229; + let v5232 = f271 * 1479; + let v5233 = f15 + v5232; + let v5234 = f15 - v5232; + let v5235 = f399 * 1479; + let v5236 = f143 + v5235; + let v5237 = f143 - v5235; + let v5238 = v5236 * 4043; + let v5239 = v5233 + v5238; + let v5240 = v5233 - v5238; + let v5241 = v5237 * 5146; + let v5242 = v5234 + v5241; + let v5243 = v5234 - v5241; + let v5244 = f335 * 1479; + let v5245 = f79 + v5244; + let v5246 = f79 - v5244; + let v5247 = f463 * 1479; + let v5248 = f207 + v5247; + let v5249 = f207 - v5247; + let v5250 = v5248 * 4043; + let v5251 = v5245 + v5250; + let v5252 = v5245 - v5250; + let v5253 = v5249 * 5146; + let v5254 = v5246 + v5253; + let v5255 = v5246 - v5253; + let v5256 = v5251 * 5736; + let v5257 = v5239 + v5256; + let v5258 = v5239 - v5256; + let v5259 = v5252 * 4134; + let v5260 = v5240 + v5259; + let v5261 = v5240 - v5259; + let v5262 = v5254 * 722; + let v5263 = v5242 + v5262; + let v5264 = v5242 - v5262; + let v5265 = v5255 * 1305; + let v5266 = v5243 + v5265; + let v5267 = v5243 - v5265; + let v5268 = f303 * 1479; + let v5269 = f47 + v5268; + let v5270 = f47 - v5268; + let v5271 = f431 * 1479; + let v5272 = f175 + v5271; + let v5273 = f175 - v5271; + let v5274 = v5272 * 4043; + let v5275 = v5269 + v5274; + let v5276 = v5269 - v5274; + let v5277 = v5273 * 5146; + let v5278 = v5270 + v5277; + let v5279 = v5270 - v5277; + let v5280 = f367 * 1479; + let v5281 = f111 + v5280; + let v5282 = f111 - v5280; + let v5283 = f495 * 1479; + let v5284 = f239 + v5283; + let v5285 = f239 - v5283; + let v5286 = v5284 * 4043; + let v5287 = v5281 + v5286; + let v5288 = v5281 - v5286; + let v5289 = v5285 * 5146; + let v5290 = v5282 + v5289; + let v5291 = v5282 - v5289; + let v5292 = v5287 * 5736; + let v5293 = v5275 + v5292; + let v5294 = v5275 - v5292; + let v5295 = v5288 * 4134; + let v5296 = v5276 + v5295; + let v5297 = v5276 - v5295; + let v5298 = v5290 * 722; + let v5299 = v5278 + v5298; + let v5300 = v5278 - v5298; + let v5301 = v5291 * 1305; + let v5302 = v5279 + v5301; + let v5303 = v5279 - v5301; + let v5304 = v5293 * 1646; + let v5305 = v5257 + v5304; + let v5306 = v5257 - v5304; + let v5307 = v5294 * 1212; + let v5308 = v5258 + v5307; + let v5309 = v5258 - v5307; + let v5310 = v5296 * 5860; + let v5311 = v5260 + v5310; + let v5312 = v5260 - v5310; + let v5313 = v5297 * 3195; + let v5314 = v5261 + v5313; + let v5315 = v5261 - v5313; + let v5316 = v5299 * 2545; + let v5317 = v5263 + v5316; + let v5318 = v5263 - v5316; + let v5319 = v5300 * 3621; + let v5320 = v5264 + v5319; + let v5321 = v5264 - v5319; + let v5322 = v5302 * 3504; + let v5323 = v5266 + v5322; + let v5324 = v5266 - v5322; + let v5325 = v5303 * 3542; + let v5326 = v5267 + v5325; + let v5327 = v5267 - v5325; + let v5328 = f287 * 1479; + let v5329 = f31 + v5328; + let v5330 = f31 - v5328; + let v5331 = f415 * 1479; + let v5332 = f159 + v5331; + let v5333 = f159 - v5331; + let v5334 = v5332 * 4043; + let v5335 = v5329 + v5334; + let v5336 = v5329 - v5334; + let v5337 = v5333 * 5146; + let v5338 = v5330 + v5337; + let v5339 = v5330 - v5337; + let v5340 = f351 * 1479; + let v5341 = f95 + v5340; + let v5342 = f95 - v5340; + let v5343 = f479 * 1479; + let v5344 = f223 + v5343; + let v5345 = f223 - v5343; + let v5346 = v5344 * 4043; + let v5347 = v5341 + v5346; + let v5348 = v5341 - v5346; + let v5349 = v5345 * 5146; + let v5350 = v5342 + v5349; + let v5351 = v5342 - v5349; + let v5352 = v5347 * 5736; + let v5353 = v5335 + v5352; + let v5354 = v5335 - v5352; + let v5355 = v5348 * 4134; + let v5356 = v5336 + v5355; + let v5357 = v5336 - v5355; + let v5358 = v5350 * 722; + let v5359 = v5338 + v5358; + let v5360 = v5338 - v5358; + let v5361 = v5351 * 1305; + let v5362 = v5339 + v5361; + let v5363 = v5339 - v5361; + let v5364 = f319 * 1479; + let v5365 = f63 + v5364; + let v5366 = f63 - v5364; + let v5367 = f447 * 1479; + let v5368 = f191 + v5367; + let v5369 = f191 - v5367; + let v5370 = v5368 * 4043; + let v5371 = v5365 + v5370; + let v5372 = v5365 - v5370; + let v5373 = v5369 * 5146; + let v5374 = v5366 + v5373; + let v5375 = v5366 - v5373; + let v5376 = f383 * 1479; + let v5377 = f127 + v5376; + let v5378 = f127 - v5376; + let v5379 = f511 * 1479; + let v5380 = f255 + v5379; + let v5381 = f255 - v5379; + let v5382 = v5380 * 4043; + let v5383 = v5377 + v5382; + let v5384 = v5377 - v5382; + let v5385 = v5381 * 5146; + let v5386 = v5378 + v5385; + let v5387 = v5378 - v5385; + let v5388 = v5383 * 5736; + let v5389 = v5371 + v5388; + let v5390 = v5371 - v5388; + let v5391 = v5384 * 4134; + let v5392 = v5372 + v5391; + let v5393 = v5372 - v5391; + let v5394 = v5386 * 722; + let v5395 = v5374 + v5394; + let v5396 = v5374 - v5394; + let v5397 = v5387 * 1305; + let v5398 = v5375 + v5397; + let v5399 = v5375 - v5397; + let v5400 = v5389 * 1646; + let v5401 = v5353 + v5400; + let v5402 = v5353 - v5400; + let v5403 = v5390 * 1212; + let v5404 = v5354 + v5403; + let v5405 = v5354 - v5403; + let v5406 = v5392 * 5860; + let v5407 = v5356 + v5406; + let v5408 = v5356 - v5406; + let v5409 = v5393 * 3195; + let v5410 = v5357 + v5409; + let v5411 = v5357 - v5409; + let v5412 = v5395 * 2545; + let v5413 = v5359 + v5412; + let v5414 = v5359 - v5412; + let v5415 = v5396 * 3621; + let v5416 = v5360 + v5415; + let v5417 = v5360 - v5415; + let v5418 = v5398 * 3504; + let v5419 = v5362 + v5418; + let v5420 = v5362 - v5418; + let v5421 = v5399 * 3542; + let v5422 = v5363 + v5421; + let v5423 = v5363 - v5421; + let v5424 = v5401 * 4591; + let v5425 = v5305 + v5424; + let v5426 = v5305 - v5424; + let v5427 = v5402 * 5728; + let v5428 = v5306 + v5427; + let v5429 = v5306 - v5427; + let v5430 = v5404 * 5023; + let v5431 = v5308 + v5430; + let v5432 = v5308 - v5430; + let v5433 = v5405 * 5828; + let v5434 = v5309 + v5433; + let v5435 = v5309 - v5433; + let v5436 = v5407 * 4978; + let v5437 = v5311 + v5436; + let v5438 = v5311 - v5436; + let v5439 = v5408 * 1351; + let v5440 = v5312 + v5439; + let v5441 = v5312 - v5439; + let v5442 = v5410 * 3328; + let v5443 = v5314 + v5442; + let v5444 = v5314 - v5442; + let v5445 = v5411 * 5777; + let v5446 = v5315 + v5445; + let v5447 = v5315 - v5445; + let v5448 = v5413 * 2975; + let v5449 = v5317 + v5448; + let v5450 = v5317 - v5448; + let v5451 = v5414 * 563; + let v5452 = v5318 + v5451; + let v5453 = v5318 - v5451; + let v5454 = v5416 * 3006; + let v5455 = v5320 + v5454; + let v5456 = v5320 - v5454; + let v5457 = v5417 * 2744; + let v5458 = v5321 + v5457; + let v5459 = v5321 - v5457; + let v5460 = v5419 * 949; + let v5461 = v5323 + v5460; + let v5462 = v5323 - v5460; + let v5463 = v5420 * 2625; + let v5464 = v5324 + v5463; + let v5465 = v5324 - v5463; + let v5466 = v5422 * 4821; + let v5467 = v5326 + v5466; + let v5468 = v5326 - v5466; + let v5469 = v5423 * 2639; + let v5470 = v5327 + v5469; + let v5471 = v5327 - v5469; + let v5472 = v5425 * 1000; + let v5473 = v5185 + v5472; + let v5474 = v5185 - v5472; + let v5475 = v5426 * 4320; + let v5476 = v5186 + v5475; + let v5477 = v5186 - v5475; + let v5478 = v5428 * 3091; + let v5479 = v5188 + v5478; + let v5480 = v5188 - v5478; + let v5481 = v5429 * 81; + let v5482 = v5189 + v5481; + let v5483 = v5189 - v5481; + let v5484 = v5431 * 2963; + let v5485 = v5191 + v5484; + let v5486 = v5191 - v5484; + let v5487 = v5432 * 4896; + let v5488 = v5192 + v5487; + let v5489 = v5192 - v5487; + let v5490 = v5434 * 3051; + let v5491 = v5194 + v5490; + let v5492 = v5194 - v5490; + let v5493 = v5435 * 2366; + let v5494 = v5195 + v5493; + let v5495 = v5195 - v5493; + let v5496 = v5437 * 1853; + let v5497 = v5197 + v5496; + let v5498 = v5197 - v5496; + let v5499 = v5438 * 140; + let v5500 = v5198 + v5499; + let v5501 = v5198 - v5499; + let v5502 = v5440 * 4611; + let v5503 = v5200 + v5502; + let v5504 = v5200 - v5502; + let v5505 = v5441 * 726; + let v5506 = v5201 + v5505; + let v5507 = v5201 - v5505; + let v5508 = v5443 * 4255; + let v5509 = v5203 + v5508; + let v5510 = v5203 - v5508; + let v5511 = v5444 * 1177; + let v5512 = v5204 + v5511; + let v5513 = v5204 - v5511; + let v5514 = v5446 * 2768; + let v5515 = v5206 + v5514; + let v5516 = v5206 - v5514; + let v5517 = v5447 * 1635; + let v5518 = v5207 + v5517; + let v5519 = v5207 - v5517; + let v5520 = v5449 * 3712; + let v5521 = v5209 + v5520; + let v5522 = v5209 - v5520; + let v5523 = v5450 * 3135; + let v5524 = v5210 + v5523; + let v5525 = v5210 - v5523; + let v5526 = v5452 * 2747; + let v5527 = v5212 + v5526; + let v5528 = v5212 - v5526; + let v5529 = v5453 * 4846; + let v5530 = v5213 + v5529; + let v5531 = v5213 - v5529; + let v5532 = v5455 * 3553; + let v5533 = v5215 + v5532; + let v5534 = v5215 - v5532; + let v5535 = v5456 * 4805; + let v5536 = v5216 + v5535; + let v5537 = v5216 - v5535; + let v5538 = v5458 * 2294; + let v5539 = v5218 + v5538; + let v5540 = v5218 - v5538; + let v5541 = v5459 * 1062; + let v5542 = v5219 + v5541; + let v5543 = v5219 - v5541; + let v5544 = v5461 * 1326; + let v5545 = v5221 + v5544; + let v5546 = v5221 - v5544; + let v5547 = v5462 * 5086; + let v5548 = v5222 + v5547; + let v5549 = v5222 - v5547; + let v5550 = v5464 * 3014; + let v5551 = v5224 + v5550; + let v5552 = v5224 - v5550; + let v5553 = v5465 * 3201; + let v5554 = v5225 + v5553; + let v5555 = v5225 - v5553; + let v5556 = v5467 * 1170; + let v5557 = v5227 + v5556; + let v5558 = v5227 - v5556; + let v5559 = v5468 * 2319; + let v5560 = v5228 + v5559; + let v5561 = v5228 - v5559; + let v5562 = v5470 * 955; + let v5563 = v5230 + v5562; + let v5564 = v5230 - v5562; + let v5565 = v5471 * 790; + let v5566 = v5231 + v5565; + let v5567 = v5231 - v5565; + let v5568 = v5473 * 544; + let v5569 = v4897 + v5568; + let v5570 = v4897 - v5568; + let v5571 = v5474 * 5791; + let v5572 = v4898 + v5571; + let v5573 = v4898 - v5571; + let v5574 = v5476 * 339; + let v5575 = v4900 + v5574; + let v5576 = v4900 - v5574; + let v5577 = v5477 * 2468; + let v5578 = v4901 + v5577; + let v5579 = v4901 - v5577; + let v5580 = v5479 * 2842; + let v5581 = v4903 + v5580; + let v5582 = v4903 - v5580; + let v5583 = v5480 * 480; + let v5584 = v4904 + v5583; + let v5585 = v4904 - v5583; + let v5586 = v5482 * 9; + let v5587 = v4906 + v5586; + let v5588 = v4906 - v5586; + let v5589 = v5483 * 1022; + let v5590 = v4907 + v5589; + let v5591 = v4907 - v5589; + let v5592 = v5485 * 4278; + let v5593 = v4909 + v5592; + let v5594 = v4909 - v5592; + let v5595 = v5486 * 1673; + let v5596 = v4910 + v5595; + let v5597 = v4910 - v5595; + let v5598 = v5488 * 4989; + let v5599 = v4912 + v5598; + let v5600 = v4912 - v5598; + let v5601 = v5489 * 5331; + let v5602 = v4913 + v5601; + let v5603 = v4913 - v5601; + let v5604 = v5491 * 3584; + let v5605 = v4915 + v5604; + let v5606 = v4915 - v5604; + let v5607 = v5492 * 4177; + let v5608 = v4916 + v5607; + let v5609 = v4916 - v5607; + let v5610 = v5494 * 1381; + let v5611 = v4918 + v5610; + let v5612 = v4918 - v5610; + let v5613 = v5495 * 2525; + let v5614 = v4919 + v5613; + let v5615 = v4919 - v5613; + let v5616 = v5497 * 2396; + let v5617 = v4921 + v5616; + let v5618 = v4921 - v5616; + let v5619 = v5498 * 4452; + let v5620 = v4922 + v5619; + let v5621 = v4922 - v5619; + let v5622 = v5500 * 3296; + let v5623 = v4924 + v5622; + let v5624 = v4924 - v5622; + let v5625 = v5501 * 3949; + let v5626 = v4925 + v5625; + let v5627 = v4925 - v5625; + let v5628 = v5503 * 130; + let v5629 = v4927 + v5628; + let v5630 = v4927 - v5628; + let v5631 = v5504 * 4354; + let v5632 = v4928 + v5631; + let v5633 = v4928 - v5631; + let v5634 = v5506 * 5374; + let v5635 = v4930 + v5634; + let v5636 = v4930 - v5634; + let v5637 = v5507 * 2837; + let v5638 = v4931 + v5637; + let v5639 = v4931 - v5637; + let v5640 = v5509 * 5767; + let v5641 = v4933 + v5640; + let v5642 = v4933 - v5640; + let v5643 = v5510 * 827; + let v5644 = v4934 + v5643; + let v5645 = v4934 - v5643; + let v5646 = v5512 * 3748; + let v5647 = v4936 + v5646; + let v5648 = v4936 - v5646; + let v5649 = v5513 * 953; + let v5650 = v4937 + v5649; + let v5651 = v4937 - v5649; + let v5652 = v5515 * 5067; + let v5653 = v4939 + v5652; + let v5654 = v4939 - v5652; + let v5655 = v5516 * 2197; + let v5656 = v4940 + v5655; + let v5657 = v4940 - v5655; + let v5658 = v5518 * 118; + let v5659 = v4942 + v5658; + let v5660 = v4942 - v5658; + let v5661 = v5519 * 2476; + let v5662 = v4943 + v5661; + let v5663 = v4943 - v5661; + let v5664 = v5521 * 2548; + let v5665 = v4945 + v5664; + let v5666 = v4945 - v5664; + let v5667 = v5522 * 4231; + let v5668 = v4946 + v5667; + let v5669 = v4946 - v5667; + let v5670 = v5524 * 355; + let v5671 = v4948 + v5670; + let v5672 = v4948 - v5670; + let v5673 = v5525 * 3382; + let v5674 = v4949 + v5673; + let v5675 = v4949 - v5673; + let v5676 = v5527 * 3707; + let v5677 = v4951 + v5676; + let v5678 = v4951 - v5676; + let v5679 = v5528 * 1759; + let v5680 = v4952 + v5679; + let v5681 = v4952 - v5679; + let v5682 = v5530 * 3694; + let v5683 = v4954 + v5682; + let v5684 = v4954 - v5682; + let v5685 = v5531 * 5179; + let v5686 = v4955 + v5685; + let v5687 = v4955 - v5685; + let v5688 = v5533 * 5542; + let v5689 = v4957 + v5688; + let v5690 = v4957 - v5688; + let v5691 = v5534 * 145; + let v5692 = v4958 + v5691; + let v5693 = v4958 - v5691; + let v5694 = v5536 * 3637; + let v5695 = v4960 + v5694; + let v5696 = v4960 - v5694; + let v5697 = v5537 * 3459; + let v5698 = v4961 + v5697; + let v5699 = v4961 - v5697; + let v5700 = v5539 * 5911; + let v5701 = v4963 + v5700; + let v5702 = v4963 - v5700; + let v5703 = v5540 * 4890; + let v5704 = v4964 + v5703; + let v5705 = v4964 - v5703; + let v5706 = v5542 * 3932; + let v5707 = v4966 + v5706; + let v5708 = v4966 - v5706; + let v5709 = v5543 * 2731; + let v5710 = v4967 + v5709; + let v5711 = v4967 - v5709; + let v5712 = v5545 * 2089; + let v5713 = v4969 + v5712; + let v5714 = v4969 - v5712; + let v5715 = v5546 * 5092; + let v5716 = v4970 + v5715; + let v5717 = v4970 - v5715; + let v5718 = v5548 * 2881; + let v5719 = v4972 + v5718; + let v5720 = v4972 - v5718; + let v5721 = v5549 * 3284; + let v5722 = v4973 + v5721; + let v5723 = v4973 - v5721; + let v5724 = v5551 * 729; + let v5725 = v4975 + v5724; + let v5726 = v4975 - v5724; + let v5727 = v5552 * 3241; + let v5728 = v4976 + v5727; + let v5729 = v4976 - v5727; + let v5730 = v5554 * 3289; + let v5731 = v4978 + v5730; + let v5732 = v4978 - v5730; + let v5733 = v5555 * 2013; + let v5734 = v4979 + v5733; + let v5735 = v4979 - v5733; + let v5736 = v5557 * 5755; + let v5737 = v4981 + v5736; + let v5738 = v4981 - v5736; + let v5739 = v5558 * 4632; + let v5740 = v4982 + v5739; + let v5741 = v4982 - v5739; + let v5742 = v5560 * 1260; + let v5743 = v4984 + v5742; + let v5744 = v4984 - v5742; + let v5745 = v5561 * 4388; + let v5746 = v4985 + v5745; + let v5747 = v4985 - v5745; + let v5748 = v5563 * 334; + let v5749 = v4987 + v5748; + let v5750 = v4987 - v5748; + let v5751 = v5564 * 2426; + let v5752 = v4988 + v5751; + let v5753 = v4988 - v5751; + let v5754 = v5566 * 1696; + let v5755 = v4990 + v5754; + let v5756 = v4990 - v5754; + let v5757 = v5567 * 1428; + let v5758 = v4991 + v5757; + let v5759 = v4991 - v5757; + let v5760 = v5569 * 1663; + let v5761 = v4225 + v5760; + let v5762 = v4225 - v5760; + let v5763 = v5570 * 1777; + let v5764 = v4226 + v5763; + let v5765 = v4226 - v5763; + let v5766 = v5572 * 1426; + let v5767 = v4228 + v5766; + let v5768 = v4228 - v5766; + let v5769 = v5573 * 4654; + let v5770 = v4229 + v5769; + let v5771 = v4229 - v5769; + let v5772 = v5575 * 5291; + let v5773 = v4231 + v5772; + let v5774 = v4231 - v5772; + let v5775 = v5576 * 2704; + let v5776 = v4232 + v5775; + let v5777 = v4232 - v5775; + let v5778 = v5578 * 4938; + let v5779 = v4234 + v5778; + let v5780 = v4234 - v5778; + let v5781 = v5579 * 3636; + let v5782 = v4235 + v5781; + let v5783 = v4235 - v5781; + let v5784 = v5581 * 3915; + let v5785 = v4237 + v5784; + let v5786 = v4237 - v5784; + let v5787 = v5582 * 2166; + let v5788 = v4238 + v5787; + let v5789 = v4238 - v5787; + let v5790 = v5584 * 113; + let v5791 = v4240 + v5790; + let v5792 = v4240 - v5790; + let v5793 = v5585 * 4919; + let v5794 = v4241 + v5793; + let v5795 = v4241 - v5793; + let v5796 = v5587 * 3; + let v5797 = v4243 + v5796; + let v5798 = v4243 - v5796; + let v5799 = v5588 * 4437; + let v5800 = v4244 + v5799; + let v5801 = v4244 - v5799; + let v5802 = v5590 * 160; + let v5803 = v4246 + v5802; + let v5804 = v4246 - v5802; + let v5805 = v5591 * 3149; + let v5806 = v4247 + v5805; + let v5807 = v4247 - v5805; + let v5808 = v5593 * 4057; + let v5809 = v4249 + v5808; + let v5810 = v4249 - v5808; + let v5811 = v5594 * 3271; + let v5812 = v4250 + v5811; + let v5813 = v4250 - v5811; + let v5814 = v5596 * 1689; + let v5815 = v4252 + v5814; + let v5816 = v4252 - v5814; + let v5817 = v5597 * 3364; + let v5818 = v4253 + v5817; + let v5819 = v4253 - v5817; + let v5820 = v5599 * 4372; + let v5821 = v4255 + v5820; + let v5822 = v4255 - v5820; + let v5823 = v5600 * 2174; + let v5824 = v4256 + v5823; + let v5825 = v4256 - v5823; + let v5826 = v5602 * 4414; + let v5827 = v4258 + v5826; + let v5828 = v4258 - v5826; + let v5829 = v5603 * 2847; + let v5830 = v4259 + v5829; + let v5831 = v4259 - v5829; + let v5832 = v5605 * 2645; + let v5833 = v4261 + v5832; + let v5834 = v4261 - v5832; + let v5835 = v5606 * 4053; + let v5836 = v4262 + v5835; + let v5837 = v4262 - v5835; + let v5838 = v5608 * 2305; + let v5839 = v4264 + v5838; + let v5840 = v4264 - v5838; + let v5841 = v5609 * 5042; + let v5842 = v4265 + v5841; + let v5843 = v4265 - v5841; + let v5844 = v5611 * 5195; + let v5845 = v4267 + v5844; + let v5846 = v4267 - v5844; + let v5847 = v5612 * 2780; + let v5848 = v4268 + v5847; + let v5849 = v4268 - v5847; + let v5850 = v5614 * 1484; + let v5851 = v4270 + v5850; + let v5852 = v4270 - v5850; + let v5853 = v5615 * 4895; + let v5854 = v4271 + v5853; + let v5855 = v4271 - v5853; + let v5856 = v5617 * 3016; + let v5857 = v4273 + v5856; + let v5858 = v4273 - v5856; + let v5859 = v5618 * 243; + let v5860 = v4274 + v5859; + let v5861 = v4274 - v5859; + let v5862 = v5620 * 3000; + let v5863 = v4276 + v5862; + let v5864 = v4276 - v5862; + let v5865 = v5621 * 671; + let v5866 = v4277 + v5865; + let v5867 = v4277 - v5865; + let v5868 = v5623 * 3136; + let v5869 = v4279 + v5868; + let v5870 = v4279 - v5868; + let v5871 = v5624 * 5191; + let v5872 = v4280 + v5871; + let v5873 = v4280 - v5871; + let v5874 = v5626 * 2399; + let v5875 = v4282 + v5874; + let v5876 = v4282 - v5874; + let v5877 = v5627 * 3400; + let v5878 = v4283 + v5877; + let v5879 = v4283 - v5877; + let v5880 = v5629 * 2178; + let v5881 = v4285 + v5880; + let v5882 = v4285 - v5880; + let v5883 = v5630 * 1544; + let v5884 = v4286 + v5883; + let v5885 = v4286 - v5883; + let v5886 = v5632 * 420; + let v5887 = v4288 + v5886; + let v5888 = v4288 - v5886; + let v5889 = v5633 * 5559; + let v5890 = v4289 + v5889; + let v5891 = v4289 - v5889; + let v5892 = v5635 * 476; + let v5893 = v4291 + v5892; + let v5894 = v4291 - v5892; + let v5895 = v5636 * 3531; + let v5896 = v4292 + v5895; + let v5897 = v4292 - v5895; + let v5898 = v5638 * 3985; + let v5899 = v4294 + v5898; + let v5900 = v4294 - v5898; + let v5901 = v5639 * 4905; + let v5902 = v4295 + v5901; + let v5903 = v4295 - v5901; + let v5904 = v5641 * 5332; + let v5905 = v4297 + v5904; + let v5906 = v4297 - v5904; + let v5907 = v5642 * 3510; + let v5908 = v4298 + v5907; + let v5909 = v4298 - v5907; + let v5910 = v5644 * 2370; + let v5911 = v4300 + v5910; + let v5912 = v4300 - v5910; + let v5913 = v5645 * 2865; + let v5914 = v4301 + v5913; + let v5915 = v4301 - v5913; + let v5916 = v5647 * 2969; + let v5917 = v4303 + v5916; + let v5918 = v4303 - v5916; + let v5919 = v5648 * 3978; + let v5920 = v4304 + v5919; + let v5921 = v4304 - v5919; + let v5922 = v5650 * 2686; + let v5923 = v4306 + v5922; + let v5924 = v4306 - v5922; + let v5925 = v5651 * 3247; + let v5926 = v4307 + v5925; + let v5927 = v4307 - v5925; + let v5928 = v5653 * 4048; + let v5929 = v4309 + v5928; + let v5930 = v4309 - v5928; + let v5931 = v5654 * 2249; + let v5932 = v4310 + v5931; + let v5933 = v4310 - v5931; + let v5934 = v5656 * 1153; + let v5935 = v4312 + v5934; + let v5936 = v4312 - v5934; + let v5937 = v5657 * 2884; + let v5938 = v4313 + v5937; + let v5939 = v4313 - v5937; + let v5940 = v5659 * 5407; + let v5941 = v4315 + v5940; + let v5942 = v4315 - v5940; + let v5943 = v5660 * 3186; + let v5944 = v4316 + v5943; + let v5945 = v4316 - v5943; + let v5946 = v5662 * 1630; + let v5947 = v4318 + v5946; + let v5948 = v4318 - v5946; + let v5949 = v5663 * 2126; + let v5950 = v4319 + v5949; + let v5951 = v4319 - v5949; + let v5952 = v5665 * 2187; + let v5953 = v4321 + v5952; + let v5954 = v4321 - v5952; + let v5955 = v5666 * 2566; + let v5956 = v4322 + v5955; + let v5957 = v4322 - v5955; + let v5958 = v5668 * 2422; + let v5959 = v4324 + v5958; + let v5960 = v4324 - v5958; + let v5961 = v5669 * 6039; + let v5962 = v4325 + v5961; + let v5963 = v4325 - v5961; + let v5964 = v5671 * 2987; + let v5965 = v4327 + v5964; + let v5966 = v4327 - v5964; + let v5967 = v5672 * 6022; + let v5968 = v4328 + v5967; + let v5969 = v4328 - v5967; + let v5970 = v5674 * 2437; + let v5971 = v4330 + v5970; + let v5972 = v4330 - v5970; + let v5973 = v5675 * 3646; + let v5974 = v4331 + v5973; + let v5975 = v4331 - v5973; + let v5976 = v5677 * 875; + let v5977 = v4333 + v5976; + let v5978 = v4333 - v5976; + let v5979 = v5678 * 3780; + let v5980 = v4334 + v5979; + let v5981 = v4334 - v5979; + let v5982 = v5680 * 1607; + let v5983 = v4336 + v5982; + let v5984 = v4336 - v5982; + let v5985 = v5681 * 4976; + let v5986 = v4337 + v5985; + let v5987 = v4337 - v5985; + let v5988 = v5683 * 5011; + let v5989 = v4339 + v5988; + let v5990 = v4339 - v5988; + let v5991 = v5684 * 1002; + let v5992 = v4340 + v5991; + let v5993 = v4340 - v5991; + let v5994 = v5686 * 4284; + let v5995 = v4342 + v5994; + let v5996 = v4342 - v5994; + let v5997 = v5687 * 5088; + let v5998 = v4343 + v5997; + let v5999 = v4343 - v5997; + let v6000 = v5689 * 3248; + let v6001 = v4345 + v6000; + let v6002 = v4345 - v6000; + let v6003 = v5690 * 1207; + let v6004 = v4346 + v6003; + let v6005 = v4346 - v6003; + let v6006 = v5692 * 1168; + let v6007 = v4348 + v6006; + let v6008 = v4348 - v6006; + let v6009 = v5693 * 5277; + let v6010 = v4349 + v6009; + let v6011 = v4349 - v6009; + let v6012 = v5695 * 1065; + let v6013 = v4351 + v6012; + let v6014 = v4351 - v6012; + let v6015 = v5696 * 2143; + let v6016 = v4352 + v6015; + let v6017 = v4352 - v6015; + let v6018 = v5698 * 404; + let v6019 = v4354 + v6018; + let v6020 = v4354 - v6018; + let v6021 = v5699 * 4645; + let v6022 = v4355 + v6021; + let v6023 = v4355 - v6021; + let v6024 = v5701 * 1912; + let v6025 = v4357 + v6024; + let v6026 = v4357 - v6024; + let v6027 = v5702 * 1378; + let v6028 = v4358 + v6027; + let v6029 = v4358 - v6027; + let v6030 = v5704 * 435; + let v6031 = v4360 + v6030; + let v6032 = v4360 - v6030; + let v6033 = v5705 * 4337; + let v6034 = v4361 + v6033; + let v6035 = v4361 - v6033; + let v6036 = v5707 * 2381; + let v6037 = v4363 + v6036; + let v6038 = v4363 - v6036; + let v6039 = v5708 * 5444; + let v6040 = v4364 + v6039; + let v6041 = v4364 - v6039; + let v6042 = v5710 * 4096; + let v6043 = v4366 + v6042; + let v6044 = v4366 - v6042; + let v6045 = v5711 * 493; + let v6046 = v4367 + v6045; + let v6047 = v4367 - v6045; + let v6048 = v5713 * 545; + let v6049 = v4369 + v6048; + let v6050 = v4369 - v6048; + let v6051 = v5714 * 5019; + let v6052 = v4370 + v6051; + let v6053 = v4370 - v6051; + let v6054 = v5716 * 3704; + let v6055 = v4372 + v6054; + let v6056 = v4372 - v6054; + let v6057 = v5717 * 2678; + let v6058 = v4373 + v6057; + let v6059 = v4373 - v6057; + let v6060 = v5719 * 1537; + let v6061 = v4375 + v6060; + let v6062 = v4375 - v6060; + let v6063 = v5720 * 242; + let v6064 = v4376 + v6063; + let v6065 = v4376 - v6063; + let v6066 = v5722 * 4714; + let v6067 = v4378 + v6066; + let v6068 = v4378 - v6066; + let v6069 = v5723 * 4143; + let v6070 = v4379 + v6069; + let v6071 = v4379 - v6069; + let v6072 = v5725 * 27; + let v6073 = v4381 + v6072; + let v6074 = v4381 - v6072; + let v6075 = v5726 * 3066; + let v6076 = v4382 + v6075; + let v6077 = v4382 - v6075; + let v6078 = v5728 * 3763; + let v6079 = v4384 + v6078; + let v6080 = v4384 - v6078; + let v6081 = v5729 * 1440; + let v6082 = v4385 + v6081; + let v6083 = v4385 - v6081; + let v6084 = v5731 * 5084; + let v6085 = v4387 + v6084; + let v6086 = v4387 - v6084; + let v6087 = v5732 * 1632; + let v6088 = v4388 + v6087; + let v6089 = v4388 - v6087; + let v6090 = v5734 * 1017; + let v6091 = v4390 + v6090; + let v6092 = v4390 - v6090; + let v6093 = v5735 * 4885; + let v6094 = v4391 + v6093; + let v6095 = v4391 - v6093; + let v6096 = v5737 * 3778; + let v6097 = v4393 + v6096; + let v6098 = v4393 - v6096; + let v6099 = v5738 * 3833; + let v6100 = v4394 + v6099; + let v6101 = v4394 - v6099; + let v6102 = v5740 * 390; + let v6103 = v4396 + v6102; + let v6104 = v4396 - v6102; + let v6105 = v5741 * 773; + let v6106 = v4397 + v6105; + let v6107 = v4397 - v6105; + let v6108 = v5743 * 2401; + let v6109 = v4399 + v6108; + let v6110 = v4399 - v6108; + let v6111 = v5744 * 442; + let v6112 = v4400 + v6111; + let v6113 = v4400 - v6111; + let v6114 = v5746 * 5101; + let v6115 = v4402 + v6114; + let v6116 = v4402 - v6114; + let v6117 = v5747 * 1067; + let v6118 = v4403 + v6117; + let v6119 = v4403 - v6117; + let v6120 = v5749 * 2912; + let v6121 = v4405 + v6120; + let v6122 = v4405 - v6120; + let v6123 = v5750 * 5698; + let v6124 = v4406 + v6123; + let v6125 = v4406 - v6123; + let v6126 = v5752 * 354; + let v6127 = v4408 + v6126; + let v6128 = v4408 - v6126; + let v6129 = v5753 * 4861; + let v6130 = v4409 + v6129; + let v6131 = v4409 - v6129; + let v6132 = v5755 * 2859; + let v6133 = v4411 + v6132; + let v6134 = v4411 - v6132; + let v6135 = v5756 * 1045; + let v6136 = v4412 + v6135; + let v6137 = v4412 - v6135; + let v6138 = v5758 * 5012; + let v6139 = v4414 + v6138; + let v6140 = v4414 - v6138; + let v6141 = v5759 * 2481; + let v6142 = v4415 + v6141; + let v6143 = v4415 - v6141; + let v6144 = v5761 * 3957; + let v6145 = v2689 + v6144; + let v6146 = v2689 - v6144; + let v6147 = v5762 * 2839; + let v6148 = v2690 + v6147; + let v6149 = v2690 - v6147; + let v6150 = v5764 * 2127; + let v6151 = v2692 + v6150; + let v6152 = v2692 - v6150; + let v6153 = v5765 * 151; + let v6154 = v2693 + v6153; + let v6155 = v2693 - v6153; + let v6156 = v5767 * 431; + let v6157 = v2695 + v6156; + let v6158 = v2695 - v6156; + let v6159 = v5768 * 1579; + let v6160 = v2696 + v6159; + let v6161 = v2696 - v6159; + let v6162 = v5770 * 5906; + let v6163 = v2698 + v6162; + let v6164 = v2698 - v6162; + let v6165 = v5771 * 2505; + let v6166 = v2699 + v6165; + let v6167 = v2699 - v6165; + let v6168 = v5773 * 1323; + let v6169 = v2701 + v6168; + let v6170 = v2701 - v6168; + let v6171 = v5774 * 2766; + let v6172 = v2702 + v6171; + let v6173 = v2702 - v6171; + let v6174 = v5776 * 52; + let v6175 = v2704 + v6174; + let v6176 = v2704 - v6174; + let v6177 = v5777 * 3174; + let v6178 = v2705 + v6177; + let v6179 = v2705 - v6177; + let v6180 = v5779 * 6055; + let v6181 = v2707 + v6180; + let v6182 = v2707 - v6180; + let v6183 = v5780 * 3336; + let v6184 = v2708 + v6183; + let v6185 = v2708 - v6183; + let v6186 = v5782 * 677; + let v6187 = v2710 + v6186; + let v6188 = v2710 - v6186; + let v6189 = v5783 * 5874; + let v6190 = v2711 + v6189; + let v6191 = v2711 - v6189; + let v6192 = v5785 * 4169; + let v6193 = v2713 + v6192; + let v6194 = v2713 - v6192; + let v6195 = v5786 * 3127; + let v6196 = v2714 + v6195; + let v6197 = v2714 - v6195; + let v6198 = v5788 * 5241; + let v6199 = v2716 + v6198; + let v6200 = v2716 - v6198; + let v6201 = v5789 * 2920; + let v6202 = v2717 + v6201; + let v6203 = v2717 - v6201; + let v6204 = v5791 * 1010; + let v6205 = v2719 + v6204; + let v6206 = v2719 - v6204; + let v6207 = v5792 * 5468; + let v6208 = v2720 + v6207; + let v6209 = v2720 - v6207; + let v6210 = v5794 * 787; + let v6211 = v2722 + v6210; + let v6212 = v2722 - v6210; + let v6213 = v5795 * 3482; + let v6214 = v2723 + v6213; + let v6215 = v2723 - v6213; + let v6216 = v5797 * 1321; + let v6217 = v2725 + v6216; + let v6218 = v2725 - v6216; + let v6219 = v5798 * 192; + let v6220 = v2726 + v6219; + let v6221 = v2726 - v6219; + let v6222 = v5800 * 4912; + let v6223 = v2728 + v6222; + let v6224 = v2728 - v6222; + let v6225 = v5801 * 2049; + let v6226 = v2729 + v6225; + let v6227 = v2729 - v6225; + let v6228 = v5803 * 4698; + let v6229 = v2731 + v6228; + let v6230 = v2731 - v6228; + let v6231 = v5804 * 5057; + let v6232 = v2732 + v6231; + let v6233 = v2732 - v6231; + let v6234 = v5806 * 4780; + let v6235 = v2734 + v6234; + let v6236 = v2734 - v6234; + let v6237 = v5807 * 3445; + let v6238 = v2735 + v6237; + let v6239 = v2735 - v6237; + let v6240 = v5809 * 1956; + let v6241 = v2737 + v6240; + let v6242 = v2737 - v6240; + let v6243 = v5810 * 5009; + let v6244 = v2738 + v6243; + let v6245 = v2738 - v6243; + let v6246 = v5812 * 6008; + let v6247 = v2740 + v6246; + let v6248 = v2740 - v6246; + let v6249 = v5813 * 885; + let v6250 = v2741 + v6249; + let v6251 = v2741 - v6249; + let v6252 = v5815 * 3532; + let v6253 = v2743 + v6252; + let v6254 = v2743 - v6252; + let v6255 = v5816 * 1003; + let v6256 = v2744 + v6255; + let v6257 = v2744 - v6255; + let v6258 = v5818 * 58; + let v6259 = v2746 + v6258; + let v6260 = v2746 - v6258; + let v6261 = v5819 * 241; + let v6262 = v2747 + v6261; + let v6263 = v2747 - v6261; + let v6264 = v5821 * 975; + let v6265 = v2749 + v6264; + let v6266 = v2749 - v6264; + let v6267 = v5822 * 4212; + let v6268 = v2750 + v6267; + let v6269 = v2750 - v6267; + let v6270 = v5824 * 2844; + let v6271 = v2752 + v6270; + let v6272 = v2752 - v6270; + let v6273 = v5825 * 3438; + let v6274 = v2753 + v6273; + let v6275 = v2753 - v6273; + let v6276 = v5827 * 1105; + let v6277 = v2755 + v6276; + let v6278 = v2755 - v6276; + let v6279 = v5828 * 142; + let v6280 = v2756 + v6279; + let v6281 = v2756 - v6279; + let v6282 = v5830 * 5681; + let v6283 = v2758 + v6282; + let v6284 = v2758 - v6282; + let v6285 = v5831 * 3477; + let v6286 = v2759 + v6285; + let v6287 = v2759 - v6285; + let v6288 = v5833 * 2302; + let v6289 = v2761 + v6288; + let v6290 = v2761 - v6288; + let v6291 = v5834 * 605; + let v6292 = v2762 + v6291; + let v6293 = v2762 - v6291; + let v6294 = v5836 * 4213; + let v6295 = v2764 + v6294; + let v6296 = v2764 - v6294; + let v6297 = v5837 * 504; + let v6298 = v2765 + v6297; + let v6299 = v2765 - v6297; + let v6300 = v5839 * 5886; + let v6301 = v2767 + v6300; + let v6302 = v2767 - v6300; + let v6303 = v5840 * 4782; + let v6304 = v2768 + v6303; + let v6305 = v2768 - v6303; + let v6306 = v5842 * 5594; + let v6307 = v2770 + v6306; + let v6308 = v2770 - v6306; + let v6309 = v5843 * 3029; + let v6310 = v2771 + v6309; + let v6311 = v2771 - v6309; + let v6312 = v5845 * 421; + let v6313 = v2773 + v6312; + let v6314 = v2773 - v6312; + let v6315 = v5846 * 4080; + let v6316 = v2774 + v6315; + let v6317 = v2774 - v6315; + let v6318 = v5848 * 6068; + let v6319 = v2776 + v6318; + let v6320 = v2776 - v6318; + let v6321 = v5849 * 3602; + let v6322 = v2777 + v6321; + let v6323 = v2777 - v6321; + let v6324 = v5851 * 6077; + let v6325 = v2779 + v6324; + let v6326 = v2779 - v6324; + let v6327 = v5852 * 4624; + let v6328 = v2780 + v6327; + let v6329 = v2780 - v6327; + let v6330 = v5854 * 3263; + let v6331 = v2782 + v6330; + let v6332 = v2782 - v6330; + let v6333 = v5855 * 3600; + let v6334 = v2783 + v6333; + let v6335 = v2783 - v6333; + let v6336 = v5857 * 4948; + let v6337 = v2785 + v6336; + let v6338 = v2785 - v6336; + let v6339 = v5858 * 6137; + let v6340 = v2786 + v6339; + let v6341 = v2786 - v6339; + let v6342 = v5860 * 400; + let v6343 = v2788 + v6342; + let v6344 = v2788 - v6342; + let v6345 = v5861 * 1728; + let v6346 = v2789 + v6345; + let v6347 = v2789 - v6345; + let v6348 = v5863 * 5862; + let v6349 = v2791 + v6348; + let v6350 = v2791 - v6348; + let v6351 = v5864 * 6136; + let v6352 = v2792 + v6351; + let v6353 = v2792 - v6351; + let v6354 = v5866 * 5415; + let v6355 = v2794 + v6354; + let v6356 = v2794 - v6354; + let v6357 = v5867 * 3643; + let v6358 = v2795 + v6357; + let v6359 = v2795 - v6357; + let v6360 = v5869 * 56; + let v6361 = v2797 + v6360; + let v6362 = v2797 - v6360; + let v6363 = v5870 * 3199; + let v6364 = v2798 + v6363; + let v6365 = v2798 - v6363; + let v6366 = v5872 * 5206; + let v6367 = v2800 + v6366; + let v6368 = v2800 - v6366; + let v6369 = v5873 * 5529; + let v6370 = v2801 + v6369; + let v6371 = v2801 - v6369; + let v6372 = v5875 * 3565; + let v6373 = v2803 + v6372; + let v6374 = v2803 - v6372; + let v6375 = v5876 * 654; + let v6376 = v2804 + v6375; + let v6377 = v2804 - v6375; + let v6378 = v5878 * 1987; + let v6379 = v2806 + v6378; + let v6380 = v2806 - v6378; + let v6381 = v5879 * 1702; + let v6382 = v2807 + v6381; + let v6383 = v2807 - v6381; + let v6384 = v5881 * 3988; + let v6385 = v2809 + v6384; + let v6386 = v2809 - v6384; + let v6387 = v5882 * 468; + let v6388 = v2810 + v6387; + let v6389 = v2810 - v6387; + let v6390 = v5884 * 316; + let v6391 = v2812 + v6390; + let v6392 = v2812 - v6390; + let v6393 = v5885 * 382; + let v6394 = v2813 + v6393; + let v6395 = v2813 - v6393; + let v6396 = v5887 * 3710; + let v6397 = v2815 + v6396; + let v6398 = v2815 - v6396; + let v6399 = v5888 * 6093; + let v6400 = v2816 + v6399; + let v6401 = v2816 - v6399; + let v6402 = v5890 * 5446; + let v6403 = v2818 + v6402; + let v6404 = v2818 - v6402; + let v6405 = v5891 * 5339; + let v6406 = v2819 + v6405; + let v6407 = v2819 - v6405; + let v6408 = v5893 * 973; + let v6409 = v2821 + v6408; + let v6410 = v2821 - v6408; + let v6411 = v5894 * 1254; + let v6412 = v2822 + v6411; + let v6413 = v2822 - v6411; + let v6414 = v5896 * 1359; + let v6415 = v2824 + v6414; + let v6416 = v2824 - v6414; + let v6417 = v5897 * 5435; + let v6418 = v2825 + v6417; + let v6419 = v2825 - v6417; + let v6420 = v5899 * 2033; + let v6421 = v2827 + v6420; + let v6422 = v2827 - v6420; + let v6423 = v5900 * 3998; + let v6424 = v2828 + v6423; + let v6425 = v2828 - v6423; + let v6426 = v5902 * 3879; + let v6427 = v2830 + v6426; + let v6428 = v2830 - v6426; + let v6429 = v5903 * 1922; + let v6430 = v2831 + v6429; + let v6431 = v2831 - v6429; + let v6432 = v5905 * 3860; + let v6433 = v2833 + v6432; + let v6434 = v2833 - v6432; + let v6435 = v5906 * 5445; + let v6436 = v2834 + v6435; + let v6437 = v2834 - v6435; + let v6438 = v5908 * 4536; + let v6439 = v2836 + v6438; + let v6440 = v2836 - v6438; + let v6441 = v5909 * 1050; + let v6442 = v2837 + v6441; + let v6443 = v2837 - v6441; + let v6444 = v5911 * 3818; + let v6445 = v2839 + v6444; + let v6446 = v2839 - v6444; + let v6447 = v5912 * 6118; + let v6448 = v2840 + v6447; + let v6449 = v2840 - v6447; + let v6450 = v5914 * 1190; + let v6451 = v2842 + v6450; + let v6452 = v2842 - v6450; + let v6453 = v5915 * 2683; + let v6454 = v2843 + v6453; + let v6455 = v2843 - v6453; + let v6456 = v5917 * 3789; + let v6457 = v2845 + v6456; + let v6458 = v2845 - v6456; + let v6459 = v5918 * 147; + let v6460 = v2846 + v6459; + let v6461 = v2846 - v6459; + let v6462 = v5920 * 5456; + let v6463 = v2848 + v6462; + let v6464 = v2848 - v6462; + let v6465 = v5921 * 4449; + let v6466 = v2849 + v6465; + let v6467 = v2849 - v6465; + let v6468 = v5923 * 4749; + let v6469 = v2851 + v6468; + let v6470 = v2851 - v6468; + let v6471 = v5924 * 5537; + let v6472 = v2852 + v6471; + let v6473 = v2852 - v6471; + let v6474 = v5926 * 4789; + let v6475 = v2854 + v6474; + let v6476 = v2854 - v6474; + let v6477 = v5927 * 4467; + let v6478 = v2855 + v6477; + let v6479 = v2855 - v6477; + let v6480 = v5929 * 1018; + let v6481 = v2857 + v6480; + let v6482 = v2857 - v6480; + let v6483 = v5930 * 5925; + let v6484 = v2858 + v6483; + let v6485 = v2858 - v6483; + let v6486 = v5932 * 1041; + let v6487 = v2860 + v6486; + let v6488 = v2860 - v6486; + let v6489 = v5933 * 3514; + let v6490 = v2861 + v6489; + let v6491 = v2861 - v6489; + let v6492 = v5935 * 2344; + let v6493 = v2863 + v6492; + let v6494 = v2863 - v6492; + let v6495 = v5936 * 1278; + let v6496 = v2864 + v6495; + let v6497 = v2864 - v6495; + let v6498 = v5938 * 5574; + let v6499 = v2866 + v6498; + let v6500 = v2866 - v6498; + let v6501 = v5939 * 1973; + let v6502 = v2867 + v6501; + let v6503 = v2867 - v6501; + let v6504 = v5941 * 4324; + let v6505 = v2869 + v6504; + let v6506 = v2869 - v6504; + let v6507 = v5942 * 4916; + let v6508 = v2870 + v6507; + let v6509 = v2870 - v6507; + let v6510 = v5944 * 4075; + let v6511 = v2872 + v6510; + let v6512 = v2872 - v6510; + let v6513 = v5945 * 5315; + let v6514 = v2873 + v6513; + let v6515 = v2873 - v6513; + let v6516 = v5947 * 5079; + let v6517 = v2875 + v6516; + let v6518 = v2875 - v6516; + let v6519 = v5948 * 3262; + let v6520 = v2876 + v6519; + let v6521 = v2876 - v6519; + let v6522 = v5950 * 522; + let v6523 = v2878 + v6522; + let v6524 = v2878 - v6522; + let v6525 = v5951 * 2169; + let v6526 = v2879 + v6525; + let v6527 = v2879 - v6525; + let v6528 = v5953 * 1200; + let v6529 = v2881 + v6528; + let v6530 = v2881 - v6528; + let v6531 = v5954 * 5184; + let v6532 = v2882 + v6531; + let v6533 = v2882 - v6531; + let v6534 = v5956 * 2555; + let v6535 = v2884 + v6534; + let v6536 = v2884 - v6534; + let v6537 = v5957 * 6122; + let v6538 = v2885 + v6537; + let v6539 = v2885 - v6537; + let v6540 = v5959 * 5297; + let v6541 = v2887 + v6540; + let v6542 = v2887 - v6540; + let v6543 = v5960 * 6119; + let v6544 = v2888 + v6543; + let v6545 = v2888 - v6543; + let v6546 = v5962 * 3956; + let v6547 = v2890 + v6546; + let v6548 = v2890 - v6546; + let v6549 = v5963 * 1360; + let v6550 = v2891 + v6549; + let v6551 = v2891 - v6549; + let v6552 = v5965 * 1962; + let v6553 = v2893 + v6552; + let v6554 = v2893 - v6552; + let v6555 = v5966 * 1594; + let v6556 = v2894 + v6555; + let v6557 = v2894 - v6555; + let v6558 = v5968 * 5961; + let v6559 = v2896 + v6558; + let v6560 = v2896 - v6558; + let v6561 = v5969 * 5106; + let v6562 = v2897 + v6561; + let v6563 = v2897 - v6561; + let v6564 = v5971 * 4298; + let v6565 = v2899 + v6564; + let v6566 = v2899 - v6564; + let v6567 = v5972 * 3329; + let v6568 = v2900 + v6567; + let v6569 = v2900 - v6567; + let v6570 = v5974 * 168; + let v6571 = v2902 + v6570; + let v6572 = v2902 - v6570; + let v6573 = v5975 * 2692; + let v6574 = v2903 + v6573; + let v6575 = v2903 - v6573; + let v6576 = v5977 * 4049; + let v6577 = v2905 + v6576; + let v6578 = v2905 - v6576; + let v6579 = v5978 * 3728; + let v6580 = v2906 + v6579; + let v6581 = v2906 - v6579; + let v6582 = v5980 * 1159; + let v6583 = v2908 + v6582; + let v6584 = v2908 - v6582; + let v6585 = v5981 * 5990; + let v6586 = v2909 + v6585; + let v6587 = v2909 - v6585; + let v6588 = v5983 * 948; + let v6589 = v2911 + v6588; + let v6590 = v2911 - v6588; + let v6591 = v5984 * 1146; + let v6592 = v2912 + v6591; + let v6593 = v2912 - v6591; + let v6594 = v5986 * 1404; + let v6595 = v2914 + v6594; + let v6596 = v2914 - v6594; + let v6597 = v5987 * 325; + let v6598 = v2915 + v6597; + let v6599 = v2915 - v6597; + let v6600 = v5989 * 5766; + let v6601 = v2917 + v6600; + let v6602 = v2917 - v6600; + let v6603 = v5990 * 652; + let v6604 = v2918 + v6603; + let v6605 = v2918 - v6603; + let v6606 = v5992 * 295; + let v6607 = v2920 + v6606; + let v6608 = v2920 - v6606; + let v6609 = v5993 * 6099; + let v6610 = v2921 + v6609; + let v6611 = v2921 - v6609; + let v6612 = v5995 * 2919; + let v6613 = v2923 + v6612; + let v6614 = v2923 - v6612; + let v6615 = v5996 * 3762; + let v6616 = v2924 + v6615; + let v6617 = v2924 - v6615; + let v6618 = v5998 * 4016; + let v6619 = v2926 + v6618; + let v6620 = v2926 - v6618; + let v6621 = v5999 * 4077; + let v6622 = v2927 + v6621; + let v6623 = v2927 - v6621; + let v6624 = v6001 * 6065; + let v6625 = v2929 + v6624; + let v6626 = v2929 - v6624; + let v6627 = v6002 * 835; + let v6628 = v2930 + v6627; + let v6629 = v2930 - v6627; + let v6630 = v6004 * 3570; + let v6631 = v2932 + v6630; + let v6632 = v2932 - v6630; + let v6633 = v6005 * 4240; + let v6634 = v2933 + v6633; + let v6635 = v2933 - v6633; + let v6636 = v6007 * 4046; + let v6637 = v2935 + v6636; + let v6638 = v2935 - v6636; + let v6639 = v6008 * 709; + let v6640 = v2936 + v6639; + let v6641 = v2936 - v6639; + let v6642 = v6010 * 3150; + let v6643 = v2938 + v6642; + let v6644 = v2938 - v6642; + let v6645 = v6011 * 1319; + let v6646 = v2939 + v6645; + let v6647 = v2939 - v6645; + let v6648 = v6013 * 1058; + let v6649 = v2941 + v6648; + let v6650 = v2941 - v6648; + let v6651 = v6014 * 4079; + let v6652 = v2942 + v6651; + let v6653 = v2942 - v6651; + let v6654 = v6016 * 922; + let v6655 = v2944 + v6654; + let v6656 = v2944 - v6654; + let v6657 = v6017 * 441; + let v6658 = v2945 + v6657; + let v6659 = v2945 - v6657; + let v6660 = v6019 * 4322; + let v6661 = v2947 + v6660; + let v6662 = v2947 - v6660; + let v6663 = v6020 * 1958; + let v6664 = v2948 + v6663; + let v6665 = v2948 - v6663; + let v6666 = v6022 * 2078; + let v6667 = v2950 + v6666; + let v6668 = v2950 - v6666; + let v6669 = v6023 * 1112; + let v6670 = v2951 + v6669; + let v6671 = v2951 - v6669; + let v6672 = v6025 * 3834; + let v6673 = v2953 + v6672; + let v6674 = v2953 - v6672; + let v6675 = v6026 * 5257; + let v6676 = v2954 + v6675; + let v6677 = v2954 - v6675; + let v6678 = v6028 * 4433; + let v6679 = v2956 + v6678; + let v6680 = v2956 - v6678; + let v6681 = v6029 * 5919; + let v6682 = v2957 + v6681; + let v6683 = v2957 - v6681; + let v6684 = v6031 * 5486; + let v6685 = v2959 + v6684; + let v6686 = v2959 - v6684; + let v6687 = v6032 * 3054; + let v6688 = v2960 + v6687; + let v6689 = v2960 - v6687; + let v6690 = v6034 * 1747; + let v6691 = v2962 + v6690; + let v6692 = v2962 - v6690; + let v6693 = v6035 * 3123; + let v6694 = v2963 + v6693; + let v6695 = v2963 - v6693; + let v6696 = v6037 * 2948; + let v6697 = v2965 + v6696; + let v6698 = v2965 - v6696; + let v6699 = v6038 * 2503; + let v6700 = v2966 + v6699; + let v6701 = v2966 - v6699; + let v6702 = v6040 * 5782; + let v6703 = v2968 + v6702; + let v6704 = v2968 - v6702; + let v6705 = v6041 * 1566; + let v6706 = v2969 + v6705; + let v6707 = v2969 - v6705; + let v6708 = v6043 * 64; + let v6709 = v2971 + v6708; + let v6710 = v2971 - v6708; + let v6711 = v6044 * 3656; + let v6712 = v2972 + v6711; + let v6713 = v2972 - v6711; + let v6714 = v6046 * 2459; + let v6715 = v2974 + v6714; + let v6716 = v2974 - v6714; + let v6717 = v6047 * 683; + let v6718 = v2975 + v6717; + let v6719 = v2975 - v6717; + let v6720 = v6049 * 1293; + let v6721 = v2977 + v6720; + let v6722 = v2977 - v6720; + let v6723 = v6050 * 4737; + let v6724 = v2978 + v6723; + let v6725 = v2978 - v6723; + let v6726 = v6052 * 5429; + let v6727 = v2980 + v6726; + let v6728 = v2980 - v6726; + let v6729 = v6053 * 4774; + let v6730 = v2981 + v6729; + let v6731 = v2981 - v6729; + let v6732 = v6055 * 5908; + let v6733 = v2983 + v6732; + let v6734 = v2983 - v6732; + let v6735 = v6056 * 453; + let v6736 = v2984 + v6735; + let v6737 = v2984 - v6735; + let v6738 = v6058 * 418; + let v6739 = v2986 + v6738; + let v6740 = v2986 - v6738; + let v6741 = v6059 * 3772; + let v6742 = v2987 + v6741; + let v6743 = v2987 - v6741; + let v6744 = v6061 * 3991; + let v6745 = v2989 + v6744; + let v6746 = v2989 - v6744; + let v6747 = v6062 * 3969; + let v6748 = v2990 + v6747; + let v6749 = v2990 - v6747; + let v6750 = v6064 * 2767; + let v6751 = v2992 + v6750; + let v6752 = v2992 - v6750; + let v6753 = v6065 * 156; + let v6754 = v2993 + v6753; + let v6755 = v2993 - v6753; + let v6756 = v6067 * 2281; + let v6757 = v2995 + v6756; + let v6758 = v2995 - v6756; + let v6759 = v6068 * 5876; + let v6760 = v2996 + v6759; + let v6761 = v2996 - v6759; + let v6762 = v6070 * 5333; + let v6763 = v2998 + v6762; + let v6764 = v2998 - v6762; + let v6765 = v6071 * 2031; + let v6766 = v2999 + v6765; + let v6767 = v2999 - v6765; + let v6768 = v6073 * 3963; + let v6769 = v3001 + v6768; + let v6770 = v3001 - v6768; + let v6771 = v6074 * 576; + let v6772 = v3002 + v6771; + let v6773 = v3002 - v6771; + let v6774 = v6076 * 2447; + let v6775 = v3004 + v6774; + let v6776 = v3004 - v6774; + let v6777 = v6077 * 6142; + let v6778 = v3005 + v6777; + let v6779 = v3005 - v6777; + let v6780 = v6079 * 2051; + let v6781 = v3007 + v6780; + let v6782 = v3007 - v6780; + let v6783 = v6080 * 1954; + let v6784 = v3008 + v6783; + let v6785 = v3008 - v6783; + let v6786 = v6082 * 1805; + let v6787 = v3010 + v6786; + let v6788 = v3010 - v6786; + let v6789 = v6083 * 2882; + let v6790 = v3011 + v6789; + let v6791 = v3011 - v6789; + let v6792 = v6085 * 3529; + let v6793 = v3013 + v6792; + let v6794 = v3013 - v6792; + let v6795 = v6086 * 3434; + let v6796 = v3014 + v6795; + let v6797 = v3014 - v6795; + let v6798 = v6088 * 2908; + let v6799 = v3016 + v6798; + let v6800 = v3016 - v6798; + let v6801 = v6089 * 218; + let v6802 = v3017 + v6801; + let v6803 = v3017 - v6801; + let v6804 = v6091 * 3030; + let v6805 = v3019 + v6804; + let v6806 = v3019 - v6804; + let v6807 = v6092 * 4115; + let v6808 = v3020 + v6807; + let v6809 = v3020 - v6807; + let v6810 = v6094 * 1843; + let v6811 = v3022 + v6810; + let v6812 = v3022 - v6810; + let v6813 = v6095 * 2361; + let v6814 = v3023 + v6813; + let v6815 = v3023 - v6813; + let v6816 = v6097 * 3202; + let v6817 = v3025 + v6816; + let v6818 = v3025 - v6816; + let v6819 = v6098 * 4493; + let v6820 = v3026 + v6819; + let v6821 = v3026 - v6819; + let v6822 = v6100 * 2057; + let v6823 = v3028 + v6822; + let v6824 = v3028 - v6822; + let v6825 = v6101 * 5369; + let v6826 = v3029 + v6825; + let v6827 = v3029 - v6825; + let v6828 = v6103 * 1512; + let v6829 = v3031 + v6828; + let v6830 = v3031 - v6828; + let v6831 = v6104 * 350; + let v6832 = v3032 + v6831; + let v6833 = v3032 - v6831; + let v6834 = v6106 * 1815; + let v6835 = v3034 + v6834; + let v6836 = v3034 - v6834; + let v6837 = v6107 * 5383; + let v6838 = v3035 + v6837; + let v6839 = v3035 - v6837; + let v6840 = v6109 * 49; + let v6841 = v3037 + v6840; + let v6842 = v3037 - v6840; + let v6843 = v6110 * 1263; + let v6844 = v3038 + v6843; + let v6845 = v3038 - v6843; + let v6846 = v6112 * 5915; + let v6847 = v3040 + v6846; + let v6848 = v3040 - v6846; + let v6849 = v6113 * 1483; + let v6850 = v3041 + v6849; + let v6851 = v3041 - v6849; + let v6852 = v6115 * 1489; + let v6853 = v3043 + v6852; + let v6854 = v3043 - v6852; + let v6855 = v6116 * 2500; + let v6856 = v3044 + v6855; + let v6857 = v3044 - v6855; + let v6858 = v6118 * 5942; + let v6859 = v3046 + v6858; + let v6860 = v3046 - v6858; + let v6861 = v6119 * 1583; + let v6862 = v3047 + v6861; + let v6863 = v3047 - v6861; + let v6864 = v6121 * 1693; + let v6865 = v3049 + v6864; + let v6866 = v3049 - v6864; + let v6867 = v6122 * 3009; + let v6868 = v3050 + v6867; + let v6869 = v3050 - v6867; + let v6870 = v6124 * 174; + let v6871 = v3052 + v6870; + let v6872 = v3052 - v6870; + let v6873 = v6125 * 723; + let v6874 = v3053 + v6873; + let v6875 = v3053 - v6873; + let v6876 = v6127 * 2738; + let v6877 = v3055 + v6876; + let v6878 = v3055 - v6876; + let v6879 = v6128 * 5868; + let v6880 = v3056 + v6879; + let v6881 = v3056 - v6879; + let v6882 = v6130 * 5735; + let v6883 = v3058 + v6882; + let v6884 = v3058 - v6882; + let v6885 = v6131 * 2655; + let v6886 = v3059 + v6885; + let v6887 = v3059 - v6885; + let v6888 = v6133 * 3315; + let v6889 = v3061 + v6888; + let v6890 = v3061 - v6888; + let v6891 = v6134 * 426; + let v6892 = v3062 + v6891; + let v6893 = v3062 - v6891; + let v6894 = v6136 * 4754; + let v6895 = v3064 + v6894; + let v6896 = v3064 - v6894; + let v6897 = v6137 * 1858; + let v6898 = v3065 + v6897; + let v6899 = v3065 - v6897; + let v6900 = v6139 * 1975; + let v6901 = v3067 + v6900; + let v6902 = v3067 - v6900; + let v6903 = v6140 * 3757; + let v6904 = v3068 + v6903; + let v6905 = v3068 - v6903; + let v6906 = v6142 * 2925; + let v6907 = v3070 + v6906; + let v6908 = v3070 - v6906; + let v6909 = v6143 * 347; + let v6910 = v3071 + v6909; + let v6911 = v3071 - v6909; + let r0_bounded: U128AsBounded = upcast(felt252_as_u128(v6145 + SHIFT)); + let (_, r0) = bounded_int_div_rem(r0_bounded, FALCON512_Q_NZ); + let r1_bounded: U128AsBounded = upcast(felt252_as_u128(v6146 + SHIFT)); + let (_, r1) = bounded_int_div_rem(r1_bounded, FALCON512_Q_NZ); + let r2_bounded: U128AsBounded = upcast(felt252_as_u128(v6148 + SHIFT)); + let (_, r2) = bounded_int_div_rem(r2_bounded, FALCON512_Q_NZ); + let r3_bounded: U128AsBounded = upcast(felt252_as_u128(v6149 + SHIFT)); + let (_, r3) = bounded_int_div_rem(r3_bounded, FALCON512_Q_NZ); + let r4_bounded: U128AsBounded = upcast(felt252_as_u128(v6151 + SHIFT)); + let (_, r4) = bounded_int_div_rem(r4_bounded, FALCON512_Q_NZ); + let r5_bounded: U128AsBounded = upcast(felt252_as_u128(v6152 + SHIFT)); + let (_, r5) = bounded_int_div_rem(r5_bounded, FALCON512_Q_NZ); + let r6_bounded: U128AsBounded = upcast(felt252_as_u128(v6154 + SHIFT)); + let (_, r6) = bounded_int_div_rem(r6_bounded, FALCON512_Q_NZ); + let r7_bounded: U128AsBounded = upcast(felt252_as_u128(v6155 + SHIFT)); + let (_, r7) = bounded_int_div_rem(r7_bounded, FALCON512_Q_NZ); + let r8_bounded: U128AsBounded = upcast(felt252_as_u128(v6157 + SHIFT)); + let (_, r8) = bounded_int_div_rem(r8_bounded, FALCON512_Q_NZ); + let r9_bounded: U128AsBounded = upcast(felt252_as_u128(v6158 + SHIFT)); + let (_, r9) = bounded_int_div_rem(r9_bounded, FALCON512_Q_NZ); + let r10_bounded: U128AsBounded = upcast(felt252_as_u128(v6160 + SHIFT)); + let (_, r10) = bounded_int_div_rem(r10_bounded, FALCON512_Q_NZ); + let r11_bounded: U128AsBounded = upcast(felt252_as_u128(v6161 + SHIFT)); + let (_, r11) = bounded_int_div_rem(r11_bounded, FALCON512_Q_NZ); + let r12_bounded: U128AsBounded = upcast(felt252_as_u128(v6163 + SHIFT)); + let (_, r12) = bounded_int_div_rem(r12_bounded, FALCON512_Q_NZ); + let r13_bounded: U128AsBounded = upcast(felt252_as_u128(v6164 + SHIFT)); + let (_, r13) = bounded_int_div_rem(r13_bounded, FALCON512_Q_NZ); + let r14_bounded: U128AsBounded = upcast(felt252_as_u128(v6166 + SHIFT)); + let (_, r14) = bounded_int_div_rem(r14_bounded, FALCON512_Q_NZ); + let r15_bounded: U128AsBounded = upcast(felt252_as_u128(v6167 + SHIFT)); + let (_, r15) = bounded_int_div_rem(r15_bounded, FALCON512_Q_NZ); + let r16_bounded: U128AsBounded = upcast(felt252_as_u128(v6169 + SHIFT)); + let (_, r16) = bounded_int_div_rem(r16_bounded, FALCON512_Q_NZ); + let r17_bounded: U128AsBounded = upcast(felt252_as_u128(v6170 + SHIFT)); + let (_, r17) = bounded_int_div_rem(r17_bounded, FALCON512_Q_NZ); + let r18_bounded: U128AsBounded = upcast(felt252_as_u128(v6172 + SHIFT)); + let (_, r18) = bounded_int_div_rem(r18_bounded, FALCON512_Q_NZ); + let r19_bounded: U128AsBounded = upcast(felt252_as_u128(v6173 + SHIFT)); + let (_, r19) = bounded_int_div_rem(r19_bounded, FALCON512_Q_NZ); + let r20_bounded: U128AsBounded = upcast(felt252_as_u128(v6175 + SHIFT)); + let (_, r20) = bounded_int_div_rem(r20_bounded, FALCON512_Q_NZ); + let r21_bounded: U128AsBounded = upcast(felt252_as_u128(v6176 + SHIFT)); + let (_, r21) = bounded_int_div_rem(r21_bounded, FALCON512_Q_NZ); + let r22_bounded: U128AsBounded = upcast(felt252_as_u128(v6178 + SHIFT)); + let (_, r22) = bounded_int_div_rem(r22_bounded, FALCON512_Q_NZ); + let r23_bounded: U128AsBounded = upcast(felt252_as_u128(v6179 + SHIFT)); + let (_, r23) = bounded_int_div_rem(r23_bounded, FALCON512_Q_NZ); + let r24_bounded: U128AsBounded = upcast(felt252_as_u128(v6181 + SHIFT)); + let (_, r24) = bounded_int_div_rem(r24_bounded, FALCON512_Q_NZ); + let r25_bounded: U128AsBounded = upcast(felt252_as_u128(v6182 + SHIFT)); + let (_, r25) = bounded_int_div_rem(r25_bounded, FALCON512_Q_NZ); + let r26_bounded: U128AsBounded = upcast(felt252_as_u128(v6184 + SHIFT)); + let (_, r26) = bounded_int_div_rem(r26_bounded, FALCON512_Q_NZ); + let r27_bounded: U128AsBounded = upcast(felt252_as_u128(v6185 + SHIFT)); + let (_, r27) = bounded_int_div_rem(r27_bounded, FALCON512_Q_NZ); + let r28_bounded: U128AsBounded = upcast(felt252_as_u128(v6187 + SHIFT)); + let (_, r28) = bounded_int_div_rem(r28_bounded, FALCON512_Q_NZ); + let r29_bounded: U128AsBounded = upcast(felt252_as_u128(v6188 + SHIFT)); + let (_, r29) = bounded_int_div_rem(r29_bounded, FALCON512_Q_NZ); + let r30_bounded: U128AsBounded = upcast(felt252_as_u128(v6190 + SHIFT)); + let (_, r30) = bounded_int_div_rem(r30_bounded, FALCON512_Q_NZ); + let r31_bounded: U128AsBounded = upcast(felt252_as_u128(v6191 + SHIFT)); + let (_, r31) = bounded_int_div_rem(r31_bounded, FALCON512_Q_NZ); + let r32_bounded: U128AsBounded = upcast(felt252_as_u128(v6193 + SHIFT)); + let (_, r32) = bounded_int_div_rem(r32_bounded, FALCON512_Q_NZ); + let r33_bounded: U128AsBounded = upcast(felt252_as_u128(v6194 + SHIFT)); + let (_, r33) = bounded_int_div_rem(r33_bounded, FALCON512_Q_NZ); + let r34_bounded: U128AsBounded = upcast(felt252_as_u128(v6196 + SHIFT)); + let (_, r34) = bounded_int_div_rem(r34_bounded, FALCON512_Q_NZ); + let r35_bounded: U128AsBounded = upcast(felt252_as_u128(v6197 + SHIFT)); + let (_, r35) = bounded_int_div_rem(r35_bounded, FALCON512_Q_NZ); + let r36_bounded: U128AsBounded = upcast(felt252_as_u128(v6199 + SHIFT)); + let (_, r36) = bounded_int_div_rem(r36_bounded, FALCON512_Q_NZ); + let r37_bounded: U128AsBounded = upcast(felt252_as_u128(v6200 + SHIFT)); + let (_, r37) = bounded_int_div_rem(r37_bounded, FALCON512_Q_NZ); + let r38_bounded: U128AsBounded = upcast(felt252_as_u128(v6202 + SHIFT)); + let (_, r38) = bounded_int_div_rem(r38_bounded, FALCON512_Q_NZ); + let r39_bounded: U128AsBounded = upcast(felt252_as_u128(v6203 + SHIFT)); + let (_, r39) = bounded_int_div_rem(r39_bounded, FALCON512_Q_NZ); + let r40_bounded: U128AsBounded = upcast(felt252_as_u128(v6205 + SHIFT)); + let (_, r40) = bounded_int_div_rem(r40_bounded, FALCON512_Q_NZ); + let r41_bounded: U128AsBounded = upcast(felt252_as_u128(v6206 + SHIFT)); + let (_, r41) = bounded_int_div_rem(r41_bounded, FALCON512_Q_NZ); + let r42_bounded: U128AsBounded = upcast(felt252_as_u128(v6208 + SHIFT)); + let (_, r42) = bounded_int_div_rem(r42_bounded, FALCON512_Q_NZ); + let r43_bounded: U128AsBounded = upcast(felt252_as_u128(v6209 + SHIFT)); + let (_, r43) = bounded_int_div_rem(r43_bounded, FALCON512_Q_NZ); + let r44_bounded: U128AsBounded = upcast(felt252_as_u128(v6211 + SHIFT)); + let (_, r44) = bounded_int_div_rem(r44_bounded, FALCON512_Q_NZ); + let r45_bounded: U128AsBounded = upcast(felt252_as_u128(v6212 + SHIFT)); + let (_, r45) = bounded_int_div_rem(r45_bounded, FALCON512_Q_NZ); + let r46_bounded: U128AsBounded = upcast(felt252_as_u128(v6214 + SHIFT)); + let (_, r46) = bounded_int_div_rem(r46_bounded, FALCON512_Q_NZ); + let r47_bounded: U128AsBounded = upcast(felt252_as_u128(v6215 + SHIFT)); + let (_, r47) = bounded_int_div_rem(r47_bounded, FALCON512_Q_NZ); + let r48_bounded: U128AsBounded = upcast(felt252_as_u128(v6217 + SHIFT)); + let (_, r48) = bounded_int_div_rem(r48_bounded, FALCON512_Q_NZ); + let r49_bounded: U128AsBounded = upcast(felt252_as_u128(v6218 + SHIFT)); + let (_, r49) = bounded_int_div_rem(r49_bounded, FALCON512_Q_NZ); + let r50_bounded: U128AsBounded = upcast(felt252_as_u128(v6220 + SHIFT)); + let (_, r50) = bounded_int_div_rem(r50_bounded, FALCON512_Q_NZ); + let r51_bounded: U128AsBounded = upcast(felt252_as_u128(v6221 + SHIFT)); + let (_, r51) = bounded_int_div_rem(r51_bounded, FALCON512_Q_NZ); + let r52_bounded: U128AsBounded = upcast(felt252_as_u128(v6223 + SHIFT)); + let (_, r52) = bounded_int_div_rem(r52_bounded, FALCON512_Q_NZ); + let r53_bounded: U128AsBounded = upcast(felt252_as_u128(v6224 + SHIFT)); + let (_, r53) = bounded_int_div_rem(r53_bounded, FALCON512_Q_NZ); + let r54_bounded: U128AsBounded = upcast(felt252_as_u128(v6226 + SHIFT)); + let (_, r54) = bounded_int_div_rem(r54_bounded, FALCON512_Q_NZ); + let r55_bounded: U128AsBounded = upcast(felt252_as_u128(v6227 + SHIFT)); + let (_, r55) = bounded_int_div_rem(r55_bounded, FALCON512_Q_NZ); + let r56_bounded: U128AsBounded = upcast(felt252_as_u128(v6229 + SHIFT)); + let (_, r56) = bounded_int_div_rem(r56_bounded, FALCON512_Q_NZ); + let r57_bounded: U128AsBounded = upcast(felt252_as_u128(v6230 + SHIFT)); + let (_, r57) = bounded_int_div_rem(r57_bounded, FALCON512_Q_NZ); + let r58_bounded: U128AsBounded = upcast(felt252_as_u128(v6232 + SHIFT)); + let (_, r58) = bounded_int_div_rem(r58_bounded, FALCON512_Q_NZ); + let r59_bounded: U128AsBounded = upcast(felt252_as_u128(v6233 + SHIFT)); + let (_, r59) = bounded_int_div_rem(r59_bounded, FALCON512_Q_NZ); + let r60_bounded: U128AsBounded = upcast(felt252_as_u128(v6235 + SHIFT)); + let (_, r60) = bounded_int_div_rem(r60_bounded, FALCON512_Q_NZ); + let r61_bounded: U128AsBounded = upcast(felt252_as_u128(v6236 + SHIFT)); + let (_, r61) = bounded_int_div_rem(r61_bounded, FALCON512_Q_NZ); + let r62_bounded: U128AsBounded = upcast(felt252_as_u128(v6238 + SHIFT)); + let (_, r62) = bounded_int_div_rem(r62_bounded, FALCON512_Q_NZ); + let r63_bounded: U128AsBounded = upcast(felt252_as_u128(v6239 + SHIFT)); + let (_, r63) = bounded_int_div_rem(r63_bounded, FALCON512_Q_NZ); + let r64_bounded: U128AsBounded = upcast(felt252_as_u128(v6241 + SHIFT)); + let (_, r64) = bounded_int_div_rem(r64_bounded, FALCON512_Q_NZ); + let r65_bounded: U128AsBounded = upcast(felt252_as_u128(v6242 + SHIFT)); + let (_, r65) = bounded_int_div_rem(r65_bounded, FALCON512_Q_NZ); + let r66_bounded: U128AsBounded = upcast(felt252_as_u128(v6244 + SHIFT)); + let (_, r66) = bounded_int_div_rem(r66_bounded, FALCON512_Q_NZ); + let r67_bounded: U128AsBounded = upcast(felt252_as_u128(v6245 + SHIFT)); + let (_, r67) = bounded_int_div_rem(r67_bounded, FALCON512_Q_NZ); + let r68_bounded: U128AsBounded = upcast(felt252_as_u128(v6247 + SHIFT)); + let (_, r68) = bounded_int_div_rem(r68_bounded, FALCON512_Q_NZ); + let r69_bounded: U128AsBounded = upcast(felt252_as_u128(v6248 + SHIFT)); + let (_, r69) = bounded_int_div_rem(r69_bounded, FALCON512_Q_NZ); + let r70_bounded: U128AsBounded = upcast(felt252_as_u128(v6250 + SHIFT)); + let (_, r70) = bounded_int_div_rem(r70_bounded, FALCON512_Q_NZ); + let r71_bounded: U128AsBounded = upcast(felt252_as_u128(v6251 + SHIFT)); + let (_, r71) = bounded_int_div_rem(r71_bounded, FALCON512_Q_NZ); + let r72_bounded: U128AsBounded = upcast(felt252_as_u128(v6253 + SHIFT)); + let (_, r72) = bounded_int_div_rem(r72_bounded, FALCON512_Q_NZ); + let r73_bounded: U128AsBounded = upcast(felt252_as_u128(v6254 + SHIFT)); + let (_, r73) = bounded_int_div_rem(r73_bounded, FALCON512_Q_NZ); + let r74_bounded: U128AsBounded = upcast(felt252_as_u128(v6256 + SHIFT)); + let (_, r74) = bounded_int_div_rem(r74_bounded, FALCON512_Q_NZ); + let r75_bounded: U128AsBounded = upcast(felt252_as_u128(v6257 + SHIFT)); + let (_, r75) = bounded_int_div_rem(r75_bounded, FALCON512_Q_NZ); + let r76_bounded: U128AsBounded = upcast(felt252_as_u128(v6259 + SHIFT)); + let (_, r76) = bounded_int_div_rem(r76_bounded, FALCON512_Q_NZ); + let r77_bounded: U128AsBounded = upcast(felt252_as_u128(v6260 + SHIFT)); + let (_, r77) = bounded_int_div_rem(r77_bounded, FALCON512_Q_NZ); + let r78_bounded: U128AsBounded = upcast(felt252_as_u128(v6262 + SHIFT)); + let (_, r78) = bounded_int_div_rem(r78_bounded, FALCON512_Q_NZ); + let r79_bounded: U128AsBounded = upcast(felt252_as_u128(v6263 + SHIFT)); + let (_, r79) = bounded_int_div_rem(r79_bounded, FALCON512_Q_NZ); + let r80_bounded: U128AsBounded = upcast(felt252_as_u128(v6265 + SHIFT)); + let (_, r80) = bounded_int_div_rem(r80_bounded, FALCON512_Q_NZ); + let r81_bounded: U128AsBounded = upcast(felt252_as_u128(v6266 + SHIFT)); + let (_, r81) = bounded_int_div_rem(r81_bounded, FALCON512_Q_NZ); + let r82_bounded: U128AsBounded = upcast(felt252_as_u128(v6268 + SHIFT)); + let (_, r82) = bounded_int_div_rem(r82_bounded, FALCON512_Q_NZ); + let r83_bounded: U128AsBounded = upcast(felt252_as_u128(v6269 + SHIFT)); + let (_, r83) = bounded_int_div_rem(r83_bounded, FALCON512_Q_NZ); + let r84_bounded: U128AsBounded = upcast(felt252_as_u128(v6271 + SHIFT)); + let (_, r84) = bounded_int_div_rem(r84_bounded, FALCON512_Q_NZ); + let r85_bounded: U128AsBounded = upcast(felt252_as_u128(v6272 + SHIFT)); + let (_, r85) = bounded_int_div_rem(r85_bounded, FALCON512_Q_NZ); + let r86_bounded: U128AsBounded = upcast(felt252_as_u128(v6274 + SHIFT)); + let (_, r86) = bounded_int_div_rem(r86_bounded, FALCON512_Q_NZ); + let r87_bounded: U128AsBounded = upcast(felt252_as_u128(v6275 + SHIFT)); + let (_, r87) = bounded_int_div_rem(r87_bounded, FALCON512_Q_NZ); + let r88_bounded: U128AsBounded = upcast(felt252_as_u128(v6277 + SHIFT)); + let (_, r88) = bounded_int_div_rem(r88_bounded, FALCON512_Q_NZ); + let r89_bounded: U128AsBounded = upcast(felt252_as_u128(v6278 + SHIFT)); + let (_, r89) = bounded_int_div_rem(r89_bounded, FALCON512_Q_NZ); + let r90_bounded: U128AsBounded = upcast(felt252_as_u128(v6280 + SHIFT)); + let (_, r90) = bounded_int_div_rem(r90_bounded, FALCON512_Q_NZ); + let r91_bounded: U128AsBounded = upcast(felt252_as_u128(v6281 + SHIFT)); + let (_, r91) = bounded_int_div_rem(r91_bounded, FALCON512_Q_NZ); + let r92_bounded: U128AsBounded = upcast(felt252_as_u128(v6283 + SHIFT)); + let (_, r92) = bounded_int_div_rem(r92_bounded, FALCON512_Q_NZ); + let r93_bounded: U128AsBounded = upcast(felt252_as_u128(v6284 + SHIFT)); + let (_, r93) = bounded_int_div_rem(r93_bounded, FALCON512_Q_NZ); + let r94_bounded: U128AsBounded = upcast(felt252_as_u128(v6286 + SHIFT)); + let (_, r94) = bounded_int_div_rem(r94_bounded, FALCON512_Q_NZ); + let r95_bounded: U128AsBounded = upcast(felt252_as_u128(v6287 + SHIFT)); + let (_, r95) = bounded_int_div_rem(r95_bounded, FALCON512_Q_NZ); + let r96_bounded: U128AsBounded = upcast(felt252_as_u128(v6289 + SHIFT)); + let (_, r96) = bounded_int_div_rem(r96_bounded, FALCON512_Q_NZ); + let r97_bounded: U128AsBounded = upcast(felt252_as_u128(v6290 + SHIFT)); + let (_, r97) = bounded_int_div_rem(r97_bounded, FALCON512_Q_NZ); + let r98_bounded: U128AsBounded = upcast(felt252_as_u128(v6292 + SHIFT)); + let (_, r98) = bounded_int_div_rem(r98_bounded, FALCON512_Q_NZ); + let r99_bounded: U128AsBounded = upcast(felt252_as_u128(v6293 + SHIFT)); + let (_, r99) = bounded_int_div_rem(r99_bounded, FALCON512_Q_NZ); + let r100_bounded: U128AsBounded = upcast(felt252_as_u128(v6295 + SHIFT)); + let (_, r100) = bounded_int_div_rem(r100_bounded, FALCON512_Q_NZ); + let r101_bounded: U128AsBounded = upcast(felt252_as_u128(v6296 + SHIFT)); + let (_, r101) = bounded_int_div_rem(r101_bounded, FALCON512_Q_NZ); + let r102_bounded: U128AsBounded = upcast(felt252_as_u128(v6298 + SHIFT)); + let (_, r102) = bounded_int_div_rem(r102_bounded, FALCON512_Q_NZ); + let r103_bounded: U128AsBounded = upcast(felt252_as_u128(v6299 + SHIFT)); + let (_, r103) = bounded_int_div_rem(r103_bounded, FALCON512_Q_NZ); + let r104_bounded: U128AsBounded = upcast(felt252_as_u128(v6301 + SHIFT)); + let (_, r104) = bounded_int_div_rem(r104_bounded, FALCON512_Q_NZ); + let r105_bounded: U128AsBounded = upcast(felt252_as_u128(v6302 + SHIFT)); + let (_, r105) = bounded_int_div_rem(r105_bounded, FALCON512_Q_NZ); + let r106_bounded: U128AsBounded = upcast(felt252_as_u128(v6304 + SHIFT)); + let (_, r106) = bounded_int_div_rem(r106_bounded, FALCON512_Q_NZ); + let r107_bounded: U128AsBounded = upcast(felt252_as_u128(v6305 + SHIFT)); + let (_, r107) = bounded_int_div_rem(r107_bounded, FALCON512_Q_NZ); + let r108_bounded: U128AsBounded = upcast(felt252_as_u128(v6307 + SHIFT)); + let (_, r108) = bounded_int_div_rem(r108_bounded, FALCON512_Q_NZ); + let r109_bounded: U128AsBounded = upcast(felt252_as_u128(v6308 + SHIFT)); + let (_, r109) = bounded_int_div_rem(r109_bounded, FALCON512_Q_NZ); + let r110_bounded: U128AsBounded = upcast(felt252_as_u128(v6310 + SHIFT)); + let (_, r110) = bounded_int_div_rem(r110_bounded, FALCON512_Q_NZ); + let r111_bounded: U128AsBounded = upcast(felt252_as_u128(v6311 + SHIFT)); + let (_, r111) = bounded_int_div_rem(r111_bounded, FALCON512_Q_NZ); + let r112_bounded: U128AsBounded = upcast(felt252_as_u128(v6313 + SHIFT)); + let (_, r112) = bounded_int_div_rem(r112_bounded, FALCON512_Q_NZ); + let r113_bounded: U128AsBounded = upcast(felt252_as_u128(v6314 + SHIFT)); + let (_, r113) = bounded_int_div_rem(r113_bounded, FALCON512_Q_NZ); + let r114_bounded: U128AsBounded = upcast(felt252_as_u128(v6316 + SHIFT)); + let (_, r114) = bounded_int_div_rem(r114_bounded, FALCON512_Q_NZ); + let r115_bounded: U128AsBounded = upcast(felt252_as_u128(v6317 + SHIFT)); + let (_, r115) = bounded_int_div_rem(r115_bounded, FALCON512_Q_NZ); + let r116_bounded: U128AsBounded = upcast(felt252_as_u128(v6319 + SHIFT)); + let (_, r116) = bounded_int_div_rem(r116_bounded, FALCON512_Q_NZ); + let r117_bounded: U128AsBounded = upcast(felt252_as_u128(v6320 + SHIFT)); + let (_, r117) = bounded_int_div_rem(r117_bounded, FALCON512_Q_NZ); + let r118_bounded: U128AsBounded = upcast(felt252_as_u128(v6322 + SHIFT)); + let (_, r118) = bounded_int_div_rem(r118_bounded, FALCON512_Q_NZ); + let r119_bounded: U128AsBounded = upcast(felt252_as_u128(v6323 + SHIFT)); + let (_, r119) = bounded_int_div_rem(r119_bounded, FALCON512_Q_NZ); + let r120_bounded: U128AsBounded = upcast(felt252_as_u128(v6325 + SHIFT)); + let (_, r120) = bounded_int_div_rem(r120_bounded, FALCON512_Q_NZ); + let r121_bounded: U128AsBounded = upcast(felt252_as_u128(v6326 + SHIFT)); + let (_, r121) = bounded_int_div_rem(r121_bounded, FALCON512_Q_NZ); + let r122_bounded: U128AsBounded = upcast(felt252_as_u128(v6328 + SHIFT)); + let (_, r122) = bounded_int_div_rem(r122_bounded, FALCON512_Q_NZ); + let r123_bounded: U128AsBounded = upcast(felt252_as_u128(v6329 + SHIFT)); + let (_, r123) = bounded_int_div_rem(r123_bounded, FALCON512_Q_NZ); + let r124_bounded: U128AsBounded = upcast(felt252_as_u128(v6331 + SHIFT)); + let (_, r124) = bounded_int_div_rem(r124_bounded, FALCON512_Q_NZ); + let r125_bounded: U128AsBounded = upcast(felt252_as_u128(v6332 + SHIFT)); + let (_, r125) = bounded_int_div_rem(r125_bounded, FALCON512_Q_NZ); + let r126_bounded: U128AsBounded = upcast(felt252_as_u128(v6334 + SHIFT)); + let (_, r126) = bounded_int_div_rem(r126_bounded, FALCON512_Q_NZ); + let r127_bounded: U128AsBounded = upcast(felt252_as_u128(v6335 + SHIFT)); + let (_, r127) = bounded_int_div_rem(r127_bounded, FALCON512_Q_NZ); + let r128_bounded: U128AsBounded = upcast(felt252_as_u128(v6337 + SHIFT)); + let (_, r128) = bounded_int_div_rem(r128_bounded, FALCON512_Q_NZ); + let r129_bounded: U128AsBounded = upcast(felt252_as_u128(v6338 + SHIFT)); + let (_, r129) = bounded_int_div_rem(r129_bounded, FALCON512_Q_NZ); + let r130_bounded: U128AsBounded = upcast(felt252_as_u128(v6340 + SHIFT)); + let (_, r130) = bounded_int_div_rem(r130_bounded, FALCON512_Q_NZ); + let r131_bounded: U128AsBounded = upcast(felt252_as_u128(v6341 + SHIFT)); + let (_, r131) = bounded_int_div_rem(r131_bounded, FALCON512_Q_NZ); + let r132_bounded: U128AsBounded = upcast(felt252_as_u128(v6343 + SHIFT)); + let (_, r132) = bounded_int_div_rem(r132_bounded, FALCON512_Q_NZ); + let r133_bounded: U128AsBounded = upcast(felt252_as_u128(v6344 + SHIFT)); + let (_, r133) = bounded_int_div_rem(r133_bounded, FALCON512_Q_NZ); + let r134_bounded: U128AsBounded = upcast(felt252_as_u128(v6346 + SHIFT)); + let (_, r134) = bounded_int_div_rem(r134_bounded, FALCON512_Q_NZ); + let r135_bounded: U128AsBounded = upcast(felt252_as_u128(v6347 + SHIFT)); + let (_, r135) = bounded_int_div_rem(r135_bounded, FALCON512_Q_NZ); + let r136_bounded: U128AsBounded = upcast(felt252_as_u128(v6349 + SHIFT)); + let (_, r136) = bounded_int_div_rem(r136_bounded, FALCON512_Q_NZ); + let r137_bounded: U128AsBounded = upcast(felt252_as_u128(v6350 + SHIFT)); + let (_, r137) = bounded_int_div_rem(r137_bounded, FALCON512_Q_NZ); + let r138_bounded: U128AsBounded = upcast(felt252_as_u128(v6352 + SHIFT)); + let (_, r138) = bounded_int_div_rem(r138_bounded, FALCON512_Q_NZ); + let r139_bounded: U128AsBounded = upcast(felt252_as_u128(v6353 + SHIFT)); + let (_, r139) = bounded_int_div_rem(r139_bounded, FALCON512_Q_NZ); + let r140_bounded: U128AsBounded = upcast(felt252_as_u128(v6355 + SHIFT)); + let (_, r140) = bounded_int_div_rem(r140_bounded, FALCON512_Q_NZ); + let r141_bounded: U128AsBounded = upcast(felt252_as_u128(v6356 + SHIFT)); + let (_, r141) = bounded_int_div_rem(r141_bounded, FALCON512_Q_NZ); + let r142_bounded: U128AsBounded = upcast(felt252_as_u128(v6358 + SHIFT)); + let (_, r142) = bounded_int_div_rem(r142_bounded, FALCON512_Q_NZ); + let r143_bounded: U128AsBounded = upcast(felt252_as_u128(v6359 + SHIFT)); + let (_, r143) = bounded_int_div_rem(r143_bounded, FALCON512_Q_NZ); + let r144_bounded: U128AsBounded = upcast(felt252_as_u128(v6361 + SHIFT)); + let (_, r144) = bounded_int_div_rem(r144_bounded, FALCON512_Q_NZ); + let r145_bounded: U128AsBounded = upcast(felt252_as_u128(v6362 + SHIFT)); + let (_, r145) = bounded_int_div_rem(r145_bounded, FALCON512_Q_NZ); + let r146_bounded: U128AsBounded = upcast(felt252_as_u128(v6364 + SHIFT)); + let (_, r146) = bounded_int_div_rem(r146_bounded, FALCON512_Q_NZ); + let r147_bounded: U128AsBounded = upcast(felt252_as_u128(v6365 + SHIFT)); + let (_, r147) = bounded_int_div_rem(r147_bounded, FALCON512_Q_NZ); + let r148_bounded: U128AsBounded = upcast(felt252_as_u128(v6367 + SHIFT)); + let (_, r148) = bounded_int_div_rem(r148_bounded, FALCON512_Q_NZ); + let r149_bounded: U128AsBounded = upcast(felt252_as_u128(v6368 + SHIFT)); + let (_, r149) = bounded_int_div_rem(r149_bounded, FALCON512_Q_NZ); + let r150_bounded: U128AsBounded = upcast(felt252_as_u128(v6370 + SHIFT)); + let (_, r150) = bounded_int_div_rem(r150_bounded, FALCON512_Q_NZ); + let r151_bounded: U128AsBounded = upcast(felt252_as_u128(v6371 + SHIFT)); + let (_, r151) = bounded_int_div_rem(r151_bounded, FALCON512_Q_NZ); + let r152_bounded: U128AsBounded = upcast(felt252_as_u128(v6373 + SHIFT)); + let (_, r152) = bounded_int_div_rem(r152_bounded, FALCON512_Q_NZ); + let r153_bounded: U128AsBounded = upcast(felt252_as_u128(v6374 + SHIFT)); + let (_, r153) = bounded_int_div_rem(r153_bounded, FALCON512_Q_NZ); + let r154_bounded: U128AsBounded = upcast(felt252_as_u128(v6376 + SHIFT)); + let (_, r154) = bounded_int_div_rem(r154_bounded, FALCON512_Q_NZ); + let r155_bounded: U128AsBounded = upcast(felt252_as_u128(v6377 + SHIFT)); + let (_, r155) = bounded_int_div_rem(r155_bounded, FALCON512_Q_NZ); + let r156_bounded: U128AsBounded = upcast(felt252_as_u128(v6379 + SHIFT)); + let (_, r156) = bounded_int_div_rem(r156_bounded, FALCON512_Q_NZ); + let r157_bounded: U128AsBounded = upcast(felt252_as_u128(v6380 + SHIFT)); + let (_, r157) = bounded_int_div_rem(r157_bounded, FALCON512_Q_NZ); + let r158_bounded: U128AsBounded = upcast(felt252_as_u128(v6382 + SHIFT)); + let (_, r158) = bounded_int_div_rem(r158_bounded, FALCON512_Q_NZ); + let r159_bounded: U128AsBounded = upcast(felt252_as_u128(v6383 + SHIFT)); + let (_, r159) = bounded_int_div_rem(r159_bounded, FALCON512_Q_NZ); + let r160_bounded: U128AsBounded = upcast(felt252_as_u128(v6385 + SHIFT)); + let (_, r160) = bounded_int_div_rem(r160_bounded, FALCON512_Q_NZ); + let r161_bounded: U128AsBounded = upcast(felt252_as_u128(v6386 + SHIFT)); + let (_, r161) = bounded_int_div_rem(r161_bounded, FALCON512_Q_NZ); + let r162_bounded: U128AsBounded = upcast(felt252_as_u128(v6388 + SHIFT)); + let (_, r162) = bounded_int_div_rem(r162_bounded, FALCON512_Q_NZ); + let r163_bounded: U128AsBounded = upcast(felt252_as_u128(v6389 + SHIFT)); + let (_, r163) = bounded_int_div_rem(r163_bounded, FALCON512_Q_NZ); + let r164_bounded: U128AsBounded = upcast(felt252_as_u128(v6391 + SHIFT)); + let (_, r164) = bounded_int_div_rem(r164_bounded, FALCON512_Q_NZ); + let r165_bounded: U128AsBounded = upcast(felt252_as_u128(v6392 + SHIFT)); + let (_, r165) = bounded_int_div_rem(r165_bounded, FALCON512_Q_NZ); + let r166_bounded: U128AsBounded = upcast(felt252_as_u128(v6394 + SHIFT)); + let (_, r166) = bounded_int_div_rem(r166_bounded, FALCON512_Q_NZ); + let r167_bounded: U128AsBounded = upcast(felt252_as_u128(v6395 + SHIFT)); + let (_, r167) = bounded_int_div_rem(r167_bounded, FALCON512_Q_NZ); + let r168_bounded: U128AsBounded = upcast(felt252_as_u128(v6397 + SHIFT)); + let (_, r168) = bounded_int_div_rem(r168_bounded, FALCON512_Q_NZ); + let r169_bounded: U128AsBounded = upcast(felt252_as_u128(v6398 + SHIFT)); + let (_, r169) = bounded_int_div_rem(r169_bounded, FALCON512_Q_NZ); + let r170_bounded: U128AsBounded = upcast(felt252_as_u128(v6400 + SHIFT)); + let (_, r170) = bounded_int_div_rem(r170_bounded, FALCON512_Q_NZ); + let r171_bounded: U128AsBounded = upcast(felt252_as_u128(v6401 + SHIFT)); + let (_, r171) = bounded_int_div_rem(r171_bounded, FALCON512_Q_NZ); + let r172_bounded: U128AsBounded = upcast(felt252_as_u128(v6403 + SHIFT)); + let (_, r172) = bounded_int_div_rem(r172_bounded, FALCON512_Q_NZ); + let r173_bounded: U128AsBounded = upcast(felt252_as_u128(v6404 + SHIFT)); + let (_, r173) = bounded_int_div_rem(r173_bounded, FALCON512_Q_NZ); + let r174_bounded: U128AsBounded = upcast(felt252_as_u128(v6406 + SHIFT)); + let (_, r174) = bounded_int_div_rem(r174_bounded, FALCON512_Q_NZ); + let r175_bounded: U128AsBounded = upcast(felt252_as_u128(v6407 + SHIFT)); + let (_, r175) = bounded_int_div_rem(r175_bounded, FALCON512_Q_NZ); + let r176_bounded: U128AsBounded = upcast(felt252_as_u128(v6409 + SHIFT)); + let (_, r176) = bounded_int_div_rem(r176_bounded, FALCON512_Q_NZ); + let r177_bounded: U128AsBounded = upcast(felt252_as_u128(v6410 + SHIFT)); + let (_, r177) = bounded_int_div_rem(r177_bounded, FALCON512_Q_NZ); + let r178_bounded: U128AsBounded = upcast(felt252_as_u128(v6412 + SHIFT)); + let (_, r178) = bounded_int_div_rem(r178_bounded, FALCON512_Q_NZ); + let r179_bounded: U128AsBounded = upcast(felt252_as_u128(v6413 + SHIFT)); + let (_, r179) = bounded_int_div_rem(r179_bounded, FALCON512_Q_NZ); + let r180_bounded: U128AsBounded = upcast(felt252_as_u128(v6415 + SHIFT)); + let (_, r180) = bounded_int_div_rem(r180_bounded, FALCON512_Q_NZ); + let r181_bounded: U128AsBounded = upcast(felt252_as_u128(v6416 + SHIFT)); + let (_, r181) = bounded_int_div_rem(r181_bounded, FALCON512_Q_NZ); + let r182_bounded: U128AsBounded = upcast(felt252_as_u128(v6418 + SHIFT)); + let (_, r182) = bounded_int_div_rem(r182_bounded, FALCON512_Q_NZ); + let r183_bounded: U128AsBounded = upcast(felt252_as_u128(v6419 + SHIFT)); + let (_, r183) = bounded_int_div_rem(r183_bounded, FALCON512_Q_NZ); + let r184_bounded: U128AsBounded = upcast(felt252_as_u128(v6421 + SHIFT)); + let (_, r184) = bounded_int_div_rem(r184_bounded, FALCON512_Q_NZ); + let r185_bounded: U128AsBounded = upcast(felt252_as_u128(v6422 + SHIFT)); + let (_, r185) = bounded_int_div_rem(r185_bounded, FALCON512_Q_NZ); + let r186_bounded: U128AsBounded = upcast(felt252_as_u128(v6424 + SHIFT)); + let (_, r186) = bounded_int_div_rem(r186_bounded, FALCON512_Q_NZ); + let r187_bounded: U128AsBounded = upcast(felt252_as_u128(v6425 + SHIFT)); + let (_, r187) = bounded_int_div_rem(r187_bounded, FALCON512_Q_NZ); + let r188_bounded: U128AsBounded = upcast(felt252_as_u128(v6427 + SHIFT)); + let (_, r188) = bounded_int_div_rem(r188_bounded, FALCON512_Q_NZ); + let r189_bounded: U128AsBounded = upcast(felt252_as_u128(v6428 + SHIFT)); + let (_, r189) = bounded_int_div_rem(r189_bounded, FALCON512_Q_NZ); + let r190_bounded: U128AsBounded = upcast(felt252_as_u128(v6430 + SHIFT)); + let (_, r190) = bounded_int_div_rem(r190_bounded, FALCON512_Q_NZ); + let r191_bounded: U128AsBounded = upcast(felt252_as_u128(v6431 + SHIFT)); + let (_, r191) = bounded_int_div_rem(r191_bounded, FALCON512_Q_NZ); + let r192_bounded: U128AsBounded = upcast(felt252_as_u128(v6433 + SHIFT)); + let (_, r192) = bounded_int_div_rem(r192_bounded, FALCON512_Q_NZ); + let r193_bounded: U128AsBounded = upcast(felt252_as_u128(v6434 + SHIFT)); + let (_, r193) = bounded_int_div_rem(r193_bounded, FALCON512_Q_NZ); + let r194_bounded: U128AsBounded = upcast(felt252_as_u128(v6436 + SHIFT)); + let (_, r194) = bounded_int_div_rem(r194_bounded, FALCON512_Q_NZ); + let r195_bounded: U128AsBounded = upcast(felt252_as_u128(v6437 + SHIFT)); + let (_, r195) = bounded_int_div_rem(r195_bounded, FALCON512_Q_NZ); + let r196_bounded: U128AsBounded = upcast(felt252_as_u128(v6439 + SHIFT)); + let (_, r196) = bounded_int_div_rem(r196_bounded, FALCON512_Q_NZ); + let r197_bounded: U128AsBounded = upcast(felt252_as_u128(v6440 + SHIFT)); + let (_, r197) = bounded_int_div_rem(r197_bounded, FALCON512_Q_NZ); + let r198_bounded: U128AsBounded = upcast(felt252_as_u128(v6442 + SHIFT)); + let (_, r198) = bounded_int_div_rem(r198_bounded, FALCON512_Q_NZ); + let r199_bounded: U128AsBounded = upcast(felt252_as_u128(v6443 + SHIFT)); + let (_, r199) = bounded_int_div_rem(r199_bounded, FALCON512_Q_NZ); + let r200_bounded: U128AsBounded = upcast(felt252_as_u128(v6445 + SHIFT)); + let (_, r200) = bounded_int_div_rem(r200_bounded, FALCON512_Q_NZ); + let r201_bounded: U128AsBounded = upcast(felt252_as_u128(v6446 + SHIFT)); + let (_, r201) = bounded_int_div_rem(r201_bounded, FALCON512_Q_NZ); + let r202_bounded: U128AsBounded = upcast(felt252_as_u128(v6448 + SHIFT)); + let (_, r202) = bounded_int_div_rem(r202_bounded, FALCON512_Q_NZ); + let r203_bounded: U128AsBounded = upcast(felt252_as_u128(v6449 + SHIFT)); + let (_, r203) = bounded_int_div_rem(r203_bounded, FALCON512_Q_NZ); + let r204_bounded: U128AsBounded = upcast(felt252_as_u128(v6451 + SHIFT)); + let (_, r204) = bounded_int_div_rem(r204_bounded, FALCON512_Q_NZ); + let r205_bounded: U128AsBounded = upcast(felt252_as_u128(v6452 + SHIFT)); + let (_, r205) = bounded_int_div_rem(r205_bounded, FALCON512_Q_NZ); + let r206_bounded: U128AsBounded = upcast(felt252_as_u128(v6454 + SHIFT)); + let (_, r206) = bounded_int_div_rem(r206_bounded, FALCON512_Q_NZ); + let r207_bounded: U128AsBounded = upcast(felt252_as_u128(v6455 + SHIFT)); + let (_, r207) = bounded_int_div_rem(r207_bounded, FALCON512_Q_NZ); + let r208_bounded: U128AsBounded = upcast(felt252_as_u128(v6457 + SHIFT)); + let (_, r208) = bounded_int_div_rem(r208_bounded, FALCON512_Q_NZ); + let r209_bounded: U128AsBounded = upcast(felt252_as_u128(v6458 + SHIFT)); + let (_, r209) = bounded_int_div_rem(r209_bounded, FALCON512_Q_NZ); + let r210_bounded: U128AsBounded = upcast(felt252_as_u128(v6460 + SHIFT)); + let (_, r210) = bounded_int_div_rem(r210_bounded, FALCON512_Q_NZ); + let r211_bounded: U128AsBounded = upcast(felt252_as_u128(v6461 + SHIFT)); + let (_, r211) = bounded_int_div_rem(r211_bounded, FALCON512_Q_NZ); + let r212_bounded: U128AsBounded = upcast(felt252_as_u128(v6463 + SHIFT)); + let (_, r212) = bounded_int_div_rem(r212_bounded, FALCON512_Q_NZ); + let r213_bounded: U128AsBounded = upcast(felt252_as_u128(v6464 + SHIFT)); + let (_, r213) = bounded_int_div_rem(r213_bounded, FALCON512_Q_NZ); + let r214_bounded: U128AsBounded = upcast(felt252_as_u128(v6466 + SHIFT)); + let (_, r214) = bounded_int_div_rem(r214_bounded, FALCON512_Q_NZ); + let r215_bounded: U128AsBounded = upcast(felt252_as_u128(v6467 + SHIFT)); + let (_, r215) = bounded_int_div_rem(r215_bounded, FALCON512_Q_NZ); + let r216_bounded: U128AsBounded = upcast(felt252_as_u128(v6469 + SHIFT)); + let (_, r216) = bounded_int_div_rem(r216_bounded, FALCON512_Q_NZ); + let r217_bounded: U128AsBounded = upcast(felt252_as_u128(v6470 + SHIFT)); + let (_, r217) = bounded_int_div_rem(r217_bounded, FALCON512_Q_NZ); + let r218_bounded: U128AsBounded = upcast(felt252_as_u128(v6472 + SHIFT)); + let (_, r218) = bounded_int_div_rem(r218_bounded, FALCON512_Q_NZ); + let r219_bounded: U128AsBounded = upcast(felt252_as_u128(v6473 + SHIFT)); + let (_, r219) = bounded_int_div_rem(r219_bounded, FALCON512_Q_NZ); + let r220_bounded: U128AsBounded = upcast(felt252_as_u128(v6475 + SHIFT)); + let (_, r220) = bounded_int_div_rem(r220_bounded, FALCON512_Q_NZ); + let r221_bounded: U128AsBounded = upcast(felt252_as_u128(v6476 + SHIFT)); + let (_, r221) = bounded_int_div_rem(r221_bounded, FALCON512_Q_NZ); + let r222_bounded: U128AsBounded = upcast(felt252_as_u128(v6478 + SHIFT)); + let (_, r222) = bounded_int_div_rem(r222_bounded, FALCON512_Q_NZ); + let r223_bounded: U128AsBounded = upcast(felt252_as_u128(v6479 + SHIFT)); + let (_, r223) = bounded_int_div_rem(r223_bounded, FALCON512_Q_NZ); + let r224_bounded: U128AsBounded = upcast(felt252_as_u128(v6481 + SHIFT)); + let (_, r224) = bounded_int_div_rem(r224_bounded, FALCON512_Q_NZ); + let r225_bounded: U128AsBounded = upcast(felt252_as_u128(v6482 + SHIFT)); + let (_, r225) = bounded_int_div_rem(r225_bounded, FALCON512_Q_NZ); + let r226_bounded: U128AsBounded = upcast(felt252_as_u128(v6484 + SHIFT)); + let (_, r226) = bounded_int_div_rem(r226_bounded, FALCON512_Q_NZ); + let r227_bounded: U128AsBounded = upcast(felt252_as_u128(v6485 + SHIFT)); + let (_, r227) = bounded_int_div_rem(r227_bounded, FALCON512_Q_NZ); + let r228_bounded: U128AsBounded = upcast(felt252_as_u128(v6487 + SHIFT)); + let (_, r228) = bounded_int_div_rem(r228_bounded, FALCON512_Q_NZ); + let r229_bounded: U128AsBounded = upcast(felt252_as_u128(v6488 + SHIFT)); + let (_, r229) = bounded_int_div_rem(r229_bounded, FALCON512_Q_NZ); + let r230_bounded: U128AsBounded = upcast(felt252_as_u128(v6490 + SHIFT)); + let (_, r230) = bounded_int_div_rem(r230_bounded, FALCON512_Q_NZ); + let r231_bounded: U128AsBounded = upcast(felt252_as_u128(v6491 + SHIFT)); + let (_, r231) = bounded_int_div_rem(r231_bounded, FALCON512_Q_NZ); + let r232_bounded: U128AsBounded = upcast(felt252_as_u128(v6493 + SHIFT)); + let (_, r232) = bounded_int_div_rem(r232_bounded, FALCON512_Q_NZ); + let r233_bounded: U128AsBounded = upcast(felt252_as_u128(v6494 + SHIFT)); + let (_, r233) = bounded_int_div_rem(r233_bounded, FALCON512_Q_NZ); + let r234_bounded: U128AsBounded = upcast(felt252_as_u128(v6496 + SHIFT)); + let (_, r234) = bounded_int_div_rem(r234_bounded, FALCON512_Q_NZ); + let r235_bounded: U128AsBounded = upcast(felt252_as_u128(v6497 + SHIFT)); + let (_, r235) = bounded_int_div_rem(r235_bounded, FALCON512_Q_NZ); + let r236_bounded: U128AsBounded = upcast(felt252_as_u128(v6499 + SHIFT)); + let (_, r236) = bounded_int_div_rem(r236_bounded, FALCON512_Q_NZ); + let r237_bounded: U128AsBounded = upcast(felt252_as_u128(v6500 + SHIFT)); + let (_, r237) = bounded_int_div_rem(r237_bounded, FALCON512_Q_NZ); + let r238_bounded: U128AsBounded = upcast(felt252_as_u128(v6502 + SHIFT)); + let (_, r238) = bounded_int_div_rem(r238_bounded, FALCON512_Q_NZ); + let r239_bounded: U128AsBounded = upcast(felt252_as_u128(v6503 + SHIFT)); + let (_, r239) = bounded_int_div_rem(r239_bounded, FALCON512_Q_NZ); + let r240_bounded: U128AsBounded = upcast(felt252_as_u128(v6505 + SHIFT)); + let (_, r240) = bounded_int_div_rem(r240_bounded, FALCON512_Q_NZ); + let r241_bounded: U128AsBounded = upcast(felt252_as_u128(v6506 + SHIFT)); + let (_, r241) = bounded_int_div_rem(r241_bounded, FALCON512_Q_NZ); + let r242_bounded: U128AsBounded = upcast(felt252_as_u128(v6508 + SHIFT)); + let (_, r242) = bounded_int_div_rem(r242_bounded, FALCON512_Q_NZ); + let r243_bounded: U128AsBounded = upcast(felt252_as_u128(v6509 + SHIFT)); + let (_, r243) = bounded_int_div_rem(r243_bounded, FALCON512_Q_NZ); + let r244_bounded: U128AsBounded = upcast(felt252_as_u128(v6511 + SHIFT)); + let (_, r244) = bounded_int_div_rem(r244_bounded, FALCON512_Q_NZ); + let r245_bounded: U128AsBounded = upcast(felt252_as_u128(v6512 + SHIFT)); + let (_, r245) = bounded_int_div_rem(r245_bounded, FALCON512_Q_NZ); + let r246_bounded: U128AsBounded = upcast(felt252_as_u128(v6514 + SHIFT)); + let (_, r246) = bounded_int_div_rem(r246_bounded, FALCON512_Q_NZ); + let r247_bounded: U128AsBounded = upcast(felt252_as_u128(v6515 + SHIFT)); + let (_, r247) = bounded_int_div_rem(r247_bounded, FALCON512_Q_NZ); + let r248_bounded: U128AsBounded = upcast(felt252_as_u128(v6517 + SHIFT)); + let (_, r248) = bounded_int_div_rem(r248_bounded, FALCON512_Q_NZ); + let r249_bounded: U128AsBounded = upcast(felt252_as_u128(v6518 + SHIFT)); + let (_, r249) = bounded_int_div_rem(r249_bounded, FALCON512_Q_NZ); + let r250_bounded: U128AsBounded = upcast(felt252_as_u128(v6520 + SHIFT)); + let (_, r250) = bounded_int_div_rem(r250_bounded, FALCON512_Q_NZ); + let r251_bounded: U128AsBounded = upcast(felt252_as_u128(v6521 + SHIFT)); + let (_, r251) = bounded_int_div_rem(r251_bounded, FALCON512_Q_NZ); + let r252_bounded: U128AsBounded = upcast(felt252_as_u128(v6523 + SHIFT)); + let (_, r252) = bounded_int_div_rem(r252_bounded, FALCON512_Q_NZ); + let r253_bounded: U128AsBounded = upcast(felt252_as_u128(v6524 + SHIFT)); + let (_, r253) = bounded_int_div_rem(r253_bounded, FALCON512_Q_NZ); + let r254_bounded: U128AsBounded = upcast(felt252_as_u128(v6526 + SHIFT)); + let (_, r254) = bounded_int_div_rem(r254_bounded, FALCON512_Q_NZ); + let r255_bounded: U128AsBounded = upcast(felt252_as_u128(v6527 + SHIFT)); + let (_, r255) = bounded_int_div_rem(r255_bounded, FALCON512_Q_NZ); + let r256_bounded: U128AsBounded = upcast(felt252_as_u128(v6529 + SHIFT)); + let (_, r256) = bounded_int_div_rem(r256_bounded, FALCON512_Q_NZ); + let r257_bounded: U128AsBounded = upcast(felt252_as_u128(v6530 + SHIFT)); + let (_, r257) = bounded_int_div_rem(r257_bounded, FALCON512_Q_NZ); + let r258_bounded: U128AsBounded = upcast(felt252_as_u128(v6532 + SHIFT)); + let (_, r258) = bounded_int_div_rem(r258_bounded, FALCON512_Q_NZ); + let r259_bounded: U128AsBounded = upcast(felt252_as_u128(v6533 + SHIFT)); + let (_, r259) = bounded_int_div_rem(r259_bounded, FALCON512_Q_NZ); + let r260_bounded: U128AsBounded = upcast(felt252_as_u128(v6535 + SHIFT)); + let (_, r260) = bounded_int_div_rem(r260_bounded, FALCON512_Q_NZ); + let r261_bounded: U128AsBounded = upcast(felt252_as_u128(v6536 + SHIFT)); + let (_, r261) = bounded_int_div_rem(r261_bounded, FALCON512_Q_NZ); + let r262_bounded: U128AsBounded = upcast(felt252_as_u128(v6538 + SHIFT)); + let (_, r262) = bounded_int_div_rem(r262_bounded, FALCON512_Q_NZ); + let r263_bounded: U128AsBounded = upcast(felt252_as_u128(v6539 + SHIFT)); + let (_, r263) = bounded_int_div_rem(r263_bounded, FALCON512_Q_NZ); + let r264_bounded: U128AsBounded = upcast(felt252_as_u128(v6541 + SHIFT)); + let (_, r264) = bounded_int_div_rem(r264_bounded, FALCON512_Q_NZ); + let r265_bounded: U128AsBounded = upcast(felt252_as_u128(v6542 + SHIFT)); + let (_, r265) = bounded_int_div_rem(r265_bounded, FALCON512_Q_NZ); + let r266_bounded: U128AsBounded = upcast(felt252_as_u128(v6544 + SHIFT)); + let (_, r266) = bounded_int_div_rem(r266_bounded, FALCON512_Q_NZ); + let r267_bounded: U128AsBounded = upcast(felt252_as_u128(v6545 + SHIFT)); + let (_, r267) = bounded_int_div_rem(r267_bounded, FALCON512_Q_NZ); + let r268_bounded: U128AsBounded = upcast(felt252_as_u128(v6547 + SHIFT)); + let (_, r268) = bounded_int_div_rem(r268_bounded, FALCON512_Q_NZ); + let r269_bounded: U128AsBounded = upcast(felt252_as_u128(v6548 + SHIFT)); + let (_, r269) = bounded_int_div_rem(r269_bounded, FALCON512_Q_NZ); + let r270_bounded: U128AsBounded = upcast(felt252_as_u128(v6550 + SHIFT)); + let (_, r270) = bounded_int_div_rem(r270_bounded, FALCON512_Q_NZ); + let r271_bounded: U128AsBounded = upcast(felt252_as_u128(v6551 + SHIFT)); + let (_, r271) = bounded_int_div_rem(r271_bounded, FALCON512_Q_NZ); + let r272_bounded: U128AsBounded = upcast(felt252_as_u128(v6553 + SHIFT)); + let (_, r272) = bounded_int_div_rem(r272_bounded, FALCON512_Q_NZ); + let r273_bounded: U128AsBounded = upcast(felt252_as_u128(v6554 + SHIFT)); + let (_, r273) = bounded_int_div_rem(r273_bounded, FALCON512_Q_NZ); + let r274_bounded: U128AsBounded = upcast(felt252_as_u128(v6556 + SHIFT)); + let (_, r274) = bounded_int_div_rem(r274_bounded, FALCON512_Q_NZ); + let r275_bounded: U128AsBounded = upcast(felt252_as_u128(v6557 + SHIFT)); + let (_, r275) = bounded_int_div_rem(r275_bounded, FALCON512_Q_NZ); + let r276_bounded: U128AsBounded = upcast(felt252_as_u128(v6559 + SHIFT)); + let (_, r276) = bounded_int_div_rem(r276_bounded, FALCON512_Q_NZ); + let r277_bounded: U128AsBounded = upcast(felt252_as_u128(v6560 + SHIFT)); + let (_, r277) = bounded_int_div_rem(r277_bounded, FALCON512_Q_NZ); + let r278_bounded: U128AsBounded = upcast(felt252_as_u128(v6562 + SHIFT)); + let (_, r278) = bounded_int_div_rem(r278_bounded, FALCON512_Q_NZ); + let r279_bounded: U128AsBounded = upcast(felt252_as_u128(v6563 + SHIFT)); + let (_, r279) = bounded_int_div_rem(r279_bounded, FALCON512_Q_NZ); + let r280_bounded: U128AsBounded = upcast(felt252_as_u128(v6565 + SHIFT)); + let (_, r280) = bounded_int_div_rem(r280_bounded, FALCON512_Q_NZ); + let r281_bounded: U128AsBounded = upcast(felt252_as_u128(v6566 + SHIFT)); + let (_, r281) = bounded_int_div_rem(r281_bounded, FALCON512_Q_NZ); + let r282_bounded: U128AsBounded = upcast(felt252_as_u128(v6568 + SHIFT)); + let (_, r282) = bounded_int_div_rem(r282_bounded, FALCON512_Q_NZ); + let r283_bounded: U128AsBounded = upcast(felt252_as_u128(v6569 + SHIFT)); + let (_, r283) = bounded_int_div_rem(r283_bounded, FALCON512_Q_NZ); + let r284_bounded: U128AsBounded = upcast(felt252_as_u128(v6571 + SHIFT)); + let (_, r284) = bounded_int_div_rem(r284_bounded, FALCON512_Q_NZ); + let r285_bounded: U128AsBounded = upcast(felt252_as_u128(v6572 + SHIFT)); + let (_, r285) = bounded_int_div_rem(r285_bounded, FALCON512_Q_NZ); + let r286_bounded: U128AsBounded = upcast(felt252_as_u128(v6574 + SHIFT)); + let (_, r286) = bounded_int_div_rem(r286_bounded, FALCON512_Q_NZ); + let r287_bounded: U128AsBounded = upcast(felt252_as_u128(v6575 + SHIFT)); + let (_, r287) = bounded_int_div_rem(r287_bounded, FALCON512_Q_NZ); + let r288_bounded: U128AsBounded = upcast(felt252_as_u128(v6577 + SHIFT)); + let (_, r288) = bounded_int_div_rem(r288_bounded, FALCON512_Q_NZ); + let r289_bounded: U128AsBounded = upcast(felt252_as_u128(v6578 + SHIFT)); + let (_, r289) = bounded_int_div_rem(r289_bounded, FALCON512_Q_NZ); + let r290_bounded: U128AsBounded = upcast(felt252_as_u128(v6580 + SHIFT)); + let (_, r290) = bounded_int_div_rem(r290_bounded, FALCON512_Q_NZ); + let r291_bounded: U128AsBounded = upcast(felt252_as_u128(v6581 + SHIFT)); + let (_, r291) = bounded_int_div_rem(r291_bounded, FALCON512_Q_NZ); + let r292_bounded: U128AsBounded = upcast(felt252_as_u128(v6583 + SHIFT)); + let (_, r292) = bounded_int_div_rem(r292_bounded, FALCON512_Q_NZ); + let r293_bounded: U128AsBounded = upcast(felt252_as_u128(v6584 + SHIFT)); + let (_, r293) = bounded_int_div_rem(r293_bounded, FALCON512_Q_NZ); + let r294_bounded: U128AsBounded = upcast(felt252_as_u128(v6586 + SHIFT)); + let (_, r294) = bounded_int_div_rem(r294_bounded, FALCON512_Q_NZ); + let r295_bounded: U128AsBounded = upcast(felt252_as_u128(v6587 + SHIFT)); + let (_, r295) = bounded_int_div_rem(r295_bounded, FALCON512_Q_NZ); + let r296_bounded: U128AsBounded = upcast(felt252_as_u128(v6589 + SHIFT)); + let (_, r296) = bounded_int_div_rem(r296_bounded, FALCON512_Q_NZ); + let r297_bounded: U128AsBounded = upcast(felt252_as_u128(v6590 + SHIFT)); + let (_, r297) = bounded_int_div_rem(r297_bounded, FALCON512_Q_NZ); + let r298_bounded: U128AsBounded = upcast(felt252_as_u128(v6592 + SHIFT)); + let (_, r298) = bounded_int_div_rem(r298_bounded, FALCON512_Q_NZ); + let r299_bounded: U128AsBounded = upcast(felt252_as_u128(v6593 + SHIFT)); + let (_, r299) = bounded_int_div_rem(r299_bounded, FALCON512_Q_NZ); + let r300_bounded: U128AsBounded = upcast(felt252_as_u128(v6595 + SHIFT)); + let (_, r300) = bounded_int_div_rem(r300_bounded, FALCON512_Q_NZ); + let r301_bounded: U128AsBounded = upcast(felt252_as_u128(v6596 + SHIFT)); + let (_, r301) = bounded_int_div_rem(r301_bounded, FALCON512_Q_NZ); + let r302_bounded: U128AsBounded = upcast(felt252_as_u128(v6598 + SHIFT)); + let (_, r302) = bounded_int_div_rem(r302_bounded, FALCON512_Q_NZ); + let r303_bounded: U128AsBounded = upcast(felt252_as_u128(v6599 + SHIFT)); + let (_, r303) = bounded_int_div_rem(r303_bounded, FALCON512_Q_NZ); + let r304_bounded: U128AsBounded = upcast(felt252_as_u128(v6601 + SHIFT)); + let (_, r304) = bounded_int_div_rem(r304_bounded, FALCON512_Q_NZ); + let r305_bounded: U128AsBounded = upcast(felt252_as_u128(v6602 + SHIFT)); + let (_, r305) = bounded_int_div_rem(r305_bounded, FALCON512_Q_NZ); + let r306_bounded: U128AsBounded = upcast(felt252_as_u128(v6604 + SHIFT)); + let (_, r306) = bounded_int_div_rem(r306_bounded, FALCON512_Q_NZ); + let r307_bounded: U128AsBounded = upcast(felt252_as_u128(v6605 + SHIFT)); + let (_, r307) = bounded_int_div_rem(r307_bounded, FALCON512_Q_NZ); + let r308_bounded: U128AsBounded = upcast(felt252_as_u128(v6607 + SHIFT)); + let (_, r308) = bounded_int_div_rem(r308_bounded, FALCON512_Q_NZ); + let r309_bounded: U128AsBounded = upcast(felt252_as_u128(v6608 + SHIFT)); + let (_, r309) = bounded_int_div_rem(r309_bounded, FALCON512_Q_NZ); + let r310_bounded: U128AsBounded = upcast(felt252_as_u128(v6610 + SHIFT)); + let (_, r310) = bounded_int_div_rem(r310_bounded, FALCON512_Q_NZ); + let r311_bounded: U128AsBounded = upcast(felt252_as_u128(v6611 + SHIFT)); + let (_, r311) = bounded_int_div_rem(r311_bounded, FALCON512_Q_NZ); + let r312_bounded: U128AsBounded = upcast(felt252_as_u128(v6613 + SHIFT)); + let (_, r312) = bounded_int_div_rem(r312_bounded, FALCON512_Q_NZ); + let r313_bounded: U128AsBounded = upcast(felt252_as_u128(v6614 + SHIFT)); + let (_, r313) = bounded_int_div_rem(r313_bounded, FALCON512_Q_NZ); + let r314_bounded: U128AsBounded = upcast(felt252_as_u128(v6616 + SHIFT)); + let (_, r314) = bounded_int_div_rem(r314_bounded, FALCON512_Q_NZ); + let r315_bounded: U128AsBounded = upcast(felt252_as_u128(v6617 + SHIFT)); + let (_, r315) = bounded_int_div_rem(r315_bounded, FALCON512_Q_NZ); + let r316_bounded: U128AsBounded = upcast(felt252_as_u128(v6619 + SHIFT)); + let (_, r316) = bounded_int_div_rem(r316_bounded, FALCON512_Q_NZ); + let r317_bounded: U128AsBounded = upcast(felt252_as_u128(v6620 + SHIFT)); + let (_, r317) = bounded_int_div_rem(r317_bounded, FALCON512_Q_NZ); + let r318_bounded: U128AsBounded = upcast(felt252_as_u128(v6622 + SHIFT)); + let (_, r318) = bounded_int_div_rem(r318_bounded, FALCON512_Q_NZ); + let r319_bounded: U128AsBounded = upcast(felt252_as_u128(v6623 + SHIFT)); + let (_, r319) = bounded_int_div_rem(r319_bounded, FALCON512_Q_NZ); + let r320_bounded: U128AsBounded = upcast(felt252_as_u128(v6625 + SHIFT)); + let (_, r320) = bounded_int_div_rem(r320_bounded, FALCON512_Q_NZ); + let r321_bounded: U128AsBounded = upcast(felt252_as_u128(v6626 + SHIFT)); + let (_, r321) = bounded_int_div_rem(r321_bounded, FALCON512_Q_NZ); + let r322_bounded: U128AsBounded = upcast(felt252_as_u128(v6628 + SHIFT)); + let (_, r322) = bounded_int_div_rem(r322_bounded, FALCON512_Q_NZ); + let r323_bounded: U128AsBounded = upcast(felt252_as_u128(v6629 + SHIFT)); + let (_, r323) = bounded_int_div_rem(r323_bounded, FALCON512_Q_NZ); + let r324_bounded: U128AsBounded = upcast(felt252_as_u128(v6631 + SHIFT)); + let (_, r324) = bounded_int_div_rem(r324_bounded, FALCON512_Q_NZ); + let r325_bounded: U128AsBounded = upcast(felt252_as_u128(v6632 + SHIFT)); + let (_, r325) = bounded_int_div_rem(r325_bounded, FALCON512_Q_NZ); + let r326_bounded: U128AsBounded = upcast(felt252_as_u128(v6634 + SHIFT)); + let (_, r326) = bounded_int_div_rem(r326_bounded, FALCON512_Q_NZ); + let r327_bounded: U128AsBounded = upcast(felt252_as_u128(v6635 + SHIFT)); + let (_, r327) = bounded_int_div_rem(r327_bounded, FALCON512_Q_NZ); + let r328_bounded: U128AsBounded = upcast(felt252_as_u128(v6637 + SHIFT)); + let (_, r328) = bounded_int_div_rem(r328_bounded, FALCON512_Q_NZ); + let r329_bounded: U128AsBounded = upcast(felt252_as_u128(v6638 + SHIFT)); + let (_, r329) = bounded_int_div_rem(r329_bounded, FALCON512_Q_NZ); + let r330_bounded: U128AsBounded = upcast(felt252_as_u128(v6640 + SHIFT)); + let (_, r330) = bounded_int_div_rem(r330_bounded, FALCON512_Q_NZ); + let r331_bounded: U128AsBounded = upcast(felt252_as_u128(v6641 + SHIFT)); + let (_, r331) = bounded_int_div_rem(r331_bounded, FALCON512_Q_NZ); + let r332_bounded: U128AsBounded = upcast(felt252_as_u128(v6643 + SHIFT)); + let (_, r332) = bounded_int_div_rem(r332_bounded, FALCON512_Q_NZ); + let r333_bounded: U128AsBounded = upcast(felt252_as_u128(v6644 + SHIFT)); + let (_, r333) = bounded_int_div_rem(r333_bounded, FALCON512_Q_NZ); + let r334_bounded: U128AsBounded = upcast(felt252_as_u128(v6646 + SHIFT)); + let (_, r334) = bounded_int_div_rem(r334_bounded, FALCON512_Q_NZ); + let r335_bounded: U128AsBounded = upcast(felt252_as_u128(v6647 + SHIFT)); + let (_, r335) = bounded_int_div_rem(r335_bounded, FALCON512_Q_NZ); + let r336_bounded: U128AsBounded = upcast(felt252_as_u128(v6649 + SHIFT)); + let (_, r336) = bounded_int_div_rem(r336_bounded, FALCON512_Q_NZ); + let r337_bounded: U128AsBounded = upcast(felt252_as_u128(v6650 + SHIFT)); + let (_, r337) = bounded_int_div_rem(r337_bounded, FALCON512_Q_NZ); + let r338_bounded: U128AsBounded = upcast(felt252_as_u128(v6652 + SHIFT)); + let (_, r338) = bounded_int_div_rem(r338_bounded, FALCON512_Q_NZ); + let r339_bounded: U128AsBounded = upcast(felt252_as_u128(v6653 + SHIFT)); + let (_, r339) = bounded_int_div_rem(r339_bounded, FALCON512_Q_NZ); + let r340_bounded: U128AsBounded = upcast(felt252_as_u128(v6655 + SHIFT)); + let (_, r340) = bounded_int_div_rem(r340_bounded, FALCON512_Q_NZ); + let r341_bounded: U128AsBounded = upcast(felt252_as_u128(v6656 + SHIFT)); + let (_, r341) = bounded_int_div_rem(r341_bounded, FALCON512_Q_NZ); + let r342_bounded: U128AsBounded = upcast(felt252_as_u128(v6658 + SHIFT)); + let (_, r342) = bounded_int_div_rem(r342_bounded, FALCON512_Q_NZ); + let r343_bounded: U128AsBounded = upcast(felt252_as_u128(v6659 + SHIFT)); + let (_, r343) = bounded_int_div_rem(r343_bounded, FALCON512_Q_NZ); + let r344_bounded: U128AsBounded = upcast(felt252_as_u128(v6661 + SHIFT)); + let (_, r344) = bounded_int_div_rem(r344_bounded, FALCON512_Q_NZ); + let r345_bounded: U128AsBounded = upcast(felt252_as_u128(v6662 + SHIFT)); + let (_, r345) = bounded_int_div_rem(r345_bounded, FALCON512_Q_NZ); + let r346_bounded: U128AsBounded = upcast(felt252_as_u128(v6664 + SHIFT)); + let (_, r346) = bounded_int_div_rem(r346_bounded, FALCON512_Q_NZ); + let r347_bounded: U128AsBounded = upcast(felt252_as_u128(v6665 + SHIFT)); + let (_, r347) = bounded_int_div_rem(r347_bounded, FALCON512_Q_NZ); + let r348_bounded: U128AsBounded = upcast(felt252_as_u128(v6667 + SHIFT)); + let (_, r348) = bounded_int_div_rem(r348_bounded, FALCON512_Q_NZ); + let r349_bounded: U128AsBounded = upcast(felt252_as_u128(v6668 + SHIFT)); + let (_, r349) = bounded_int_div_rem(r349_bounded, FALCON512_Q_NZ); + let r350_bounded: U128AsBounded = upcast(felt252_as_u128(v6670 + SHIFT)); + let (_, r350) = bounded_int_div_rem(r350_bounded, FALCON512_Q_NZ); + let r351_bounded: U128AsBounded = upcast(felt252_as_u128(v6671 + SHIFT)); + let (_, r351) = bounded_int_div_rem(r351_bounded, FALCON512_Q_NZ); + let r352_bounded: U128AsBounded = upcast(felt252_as_u128(v6673 + SHIFT)); + let (_, r352) = bounded_int_div_rem(r352_bounded, FALCON512_Q_NZ); + let r353_bounded: U128AsBounded = upcast(felt252_as_u128(v6674 + SHIFT)); + let (_, r353) = bounded_int_div_rem(r353_bounded, FALCON512_Q_NZ); + let r354_bounded: U128AsBounded = upcast(felt252_as_u128(v6676 + SHIFT)); + let (_, r354) = bounded_int_div_rem(r354_bounded, FALCON512_Q_NZ); + let r355_bounded: U128AsBounded = upcast(felt252_as_u128(v6677 + SHIFT)); + let (_, r355) = bounded_int_div_rem(r355_bounded, FALCON512_Q_NZ); + let r356_bounded: U128AsBounded = upcast(felt252_as_u128(v6679 + SHIFT)); + let (_, r356) = bounded_int_div_rem(r356_bounded, FALCON512_Q_NZ); + let r357_bounded: U128AsBounded = upcast(felt252_as_u128(v6680 + SHIFT)); + let (_, r357) = bounded_int_div_rem(r357_bounded, FALCON512_Q_NZ); + let r358_bounded: U128AsBounded = upcast(felt252_as_u128(v6682 + SHIFT)); + let (_, r358) = bounded_int_div_rem(r358_bounded, FALCON512_Q_NZ); + let r359_bounded: U128AsBounded = upcast(felt252_as_u128(v6683 + SHIFT)); + let (_, r359) = bounded_int_div_rem(r359_bounded, FALCON512_Q_NZ); + let r360_bounded: U128AsBounded = upcast(felt252_as_u128(v6685 + SHIFT)); + let (_, r360) = bounded_int_div_rem(r360_bounded, FALCON512_Q_NZ); + let r361_bounded: U128AsBounded = upcast(felt252_as_u128(v6686 + SHIFT)); + let (_, r361) = bounded_int_div_rem(r361_bounded, FALCON512_Q_NZ); + let r362_bounded: U128AsBounded = upcast(felt252_as_u128(v6688 + SHIFT)); + let (_, r362) = bounded_int_div_rem(r362_bounded, FALCON512_Q_NZ); + let r363_bounded: U128AsBounded = upcast(felt252_as_u128(v6689 + SHIFT)); + let (_, r363) = bounded_int_div_rem(r363_bounded, FALCON512_Q_NZ); + let r364_bounded: U128AsBounded = upcast(felt252_as_u128(v6691 + SHIFT)); + let (_, r364) = bounded_int_div_rem(r364_bounded, FALCON512_Q_NZ); + let r365_bounded: U128AsBounded = upcast(felt252_as_u128(v6692 + SHIFT)); + let (_, r365) = bounded_int_div_rem(r365_bounded, FALCON512_Q_NZ); + let r366_bounded: U128AsBounded = upcast(felt252_as_u128(v6694 + SHIFT)); + let (_, r366) = bounded_int_div_rem(r366_bounded, FALCON512_Q_NZ); + let r367_bounded: U128AsBounded = upcast(felt252_as_u128(v6695 + SHIFT)); + let (_, r367) = bounded_int_div_rem(r367_bounded, FALCON512_Q_NZ); + let r368_bounded: U128AsBounded = upcast(felt252_as_u128(v6697 + SHIFT)); + let (_, r368) = bounded_int_div_rem(r368_bounded, FALCON512_Q_NZ); + let r369_bounded: U128AsBounded = upcast(felt252_as_u128(v6698 + SHIFT)); + let (_, r369) = bounded_int_div_rem(r369_bounded, FALCON512_Q_NZ); + let r370_bounded: U128AsBounded = upcast(felt252_as_u128(v6700 + SHIFT)); + let (_, r370) = bounded_int_div_rem(r370_bounded, FALCON512_Q_NZ); + let r371_bounded: U128AsBounded = upcast(felt252_as_u128(v6701 + SHIFT)); + let (_, r371) = bounded_int_div_rem(r371_bounded, FALCON512_Q_NZ); + let r372_bounded: U128AsBounded = upcast(felt252_as_u128(v6703 + SHIFT)); + let (_, r372) = bounded_int_div_rem(r372_bounded, FALCON512_Q_NZ); + let r373_bounded: U128AsBounded = upcast(felt252_as_u128(v6704 + SHIFT)); + let (_, r373) = bounded_int_div_rem(r373_bounded, FALCON512_Q_NZ); + let r374_bounded: U128AsBounded = upcast(felt252_as_u128(v6706 + SHIFT)); + let (_, r374) = bounded_int_div_rem(r374_bounded, FALCON512_Q_NZ); + let r375_bounded: U128AsBounded = upcast(felt252_as_u128(v6707 + SHIFT)); + let (_, r375) = bounded_int_div_rem(r375_bounded, FALCON512_Q_NZ); + let r376_bounded: U128AsBounded = upcast(felt252_as_u128(v6709 + SHIFT)); + let (_, r376) = bounded_int_div_rem(r376_bounded, FALCON512_Q_NZ); + let r377_bounded: U128AsBounded = upcast(felt252_as_u128(v6710 + SHIFT)); + let (_, r377) = bounded_int_div_rem(r377_bounded, FALCON512_Q_NZ); + let r378_bounded: U128AsBounded = upcast(felt252_as_u128(v6712 + SHIFT)); + let (_, r378) = bounded_int_div_rem(r378_bounded, FALCON512_Q_NZ); + let r379_bounded: U128AsBounded = upcast(felt252_as_u128(v6713 + SHIFT)); + let (_, r379) = bounded_int_div_rem(r379_bounded, FALCON512_Q_NZ); + let r380_bounded: U128AsBounded = upcast(felt252_as_u128(v6715 + SHIFT)); + let (_, r380) = bounded_int_div_rem(r380_bounded, FALCON512_Q_NZ); + let r381_bounded: U128AsBounded = upcast(felt252_as_u128(v6716 + SHIFT)); + let (_, r381) = bounded_int_div_rem(r381_bounded, FALCON512_Q_NZ); + let r382_bounded: U128AsBounded = upcast(felt252_as_u128(v6718 + SHIFT)); + let (_, r382) = bounded_int_div_rem(r382_bounded, FALCON512_Q_NZ); + let r383_bounded: U128AsBounded = upcast(felt252_as_u128(v6719 + SHIFT)); + let (_, r383) = bounded_int_div_rem(r383_bounded, FALCON512_Q_NZ); + let r384_bounded: U128AsBounded = upcast(felt252_as_u128(v6721 + SHIFT)); + let (_, r384) = bounded_int_div_rem(r384_bounded, FALCON512_Q_NZ); + let r385_bounded: U128AsBounded = upcast(felt252_as_u128(v6722 + SHIFT)); + let (_, r385) = bounded_int_div_rem(r385_bounded, FALCON512_Q_NZ); + let r386_bounded: U128AsBounded = upcast(felt252_as_u128(v6724 + SHIFT)); + let (_, r386) = bounded_int_div_rem(r386_bounded, FALCON512_Q_NZ); + let r387_bounded: U128AsBounded = upcast(felt252_as_u128(v6725 + SHIFT)); + let (_, r387) = bounded_int_div_rem(r387_bounded, FALCON512_Q_NZ); + let r388_bounded: U128AsBounded = upcast(felt252_as_u128(v6727 + SHIFT)); + let (_, r388) = bounded_int_div_rem(r388_bounded, FALCON512_Q_NZ); + let r389_bounded: U128AsBounded = upcast(felt252_as_u128(v6728 + SHIFT)); + let (_, r389) = bounded_int_div_rem(r389_bounded, FALCON512_Q_NZ); + let r390_bounded: U128AsBounded = upcast(felt252_as_u128(v6730 + SHIFT)); + let (_, r390) = bounded_int_div_rem(r390_bounded, FALCON512_Q_NZ); + let r391_bounded: U128AsBounded = upcast(felt252_as_u128(v6731 + SHIFT)); + let (_, r391) = bounded_int_div_rem(r391_bounded, FALCON512_Q_NZ); + let r392_bounded: U128AsBounded = upcast(felt252_as_u128(v6733 + SHIFT)); + let (_, r392) = bounded_int_div_rem(r392_bounded, FALCON512_Q_NZ); + let r393_bounded: U128AsBounded = upcast(felt252_as_u128(v6734 + SHIFT)); + let (_, r393) = bounded_int_div_rem(r393_bounded, FALCON512_Q_NZ); + let r394_bounded: U128AsBounded = upcast(felt252_as_u128(v6736 + SHIFT)); + let (_, r394) = bounded_int_div_rem(r394_bounded, FALCON512_Q_NZ); + let r395_bounded: U128AsBounded = upcast(felt252_as_u128(v6737 + SHIFT)); + let (_, r395) = bounded_int_div_rem(r395_bounded, FALCON512_Q_NZ); + let r396_bounded: U128AsBounded = upcast(felt252_as_u128(v6739 + SHIFT)); + let (_, r396) = bounded_int_div_rem(r396_bounded, FALCON512_Q_NZ); + let r397_bounded: U128AsBounded = upcast(felt252_as_u128(v6740 + SHIFT)); + let (_, r397) = bounded_int_div_rem(r397_bounded, FALCON512_Q_NZ); + let r398_bounded: U128AsBounded = upcast(felt252_as_u128(v6742 + SHIFT)); + let (_, r398) = bounded_int_div_rem(r398_bounded, FALCON512_Q_NZ); + let r399_bounded: U128AsBounded = upcast(felt252_as_u128(v6743 + SHIFT)); + let (_, r399) = bounded_int_div_rem(r399_bounded, FALCON512_Q_NZ); + let r400_bounded: U128AsBounded = upcast(felt252_as_u128(v6745 + SHIFT)); + let (_, r400) = bounded_int_div_rem(r400_bounded, FALCON512_Q_NZ); + let r401_bounded: U128AsBounded = upcast(felt252_as_u128(v6746 + SHIFT)); + let (_, r401) = bounded_int_div_rem(r401_bounded, FALCON512_Q_NZ); + let r402_bounded: U128AsBounded = upcast(felt252_as_u128(v6748 + SHIFT)); + let (_, r402) = bounded_int_div_rem(r402_bounded, FALCON512_Q_NZ); + let r403_bounded: U128AsBounded = upcast(felt252_as_u128(v6749 + SHIFT)); + let (_, r403) = bounded_int_div_rem(r403_bounded, FALCON512_Q_NZ); + let r404_bounded: U128AsBounded = upcast(felt252_as_u128(v6751 + SHIFT)); + let (_, r404) = bounded_int_div_rem(r404_bounded, FALCON512_Q_NZ); + let r405_bounded: U128AsBounded = upcast(felt252_as_u128(v6752 + SHIFT)); + let (_, r405) = bounded_int_div_rem(r405_bounded, FALCON512_Q_NZ); + let r406_bounded: U128AsBounded = upcast(felt252_as_u128(v6754 + SHIFT)); + let (_, r406) = bounded_int_div_rem(r406_bounded, FALCON512_Q_NZ); + let r407_bounded: U128AsBounded = upcast(felt252_as_u128(v6755 + SHIFT)); + let (_, r407) = bounded_int_div_rem(r407_bounded, FALCON512_Q_NZ); + let r408_bounded: U128AsBounded = upcast(felt252_as_u128(v6757 + SHIFT)); + let (_, r408) = bounded_int_div_rem(r408_bounded, FALCON512_Q_NZ); + let r409_bounded: U128AsBounded = upcast(felt252_as_u128(v6758 + SHIFT)); + let (_, r409) = bounded_int_div_rem(r409_bounded, FALCON512_Q_NZ); + let r410_bounded: U128AsBounded = upcast(felt252_as_u128(v6760 + SHIFT)); + let (_, r410) = bounded_int_div_rem(r410_bounded, FALCON512_Q_NZ); + let r411_bounded: U128AsBounded = upcast(felt252_as_u128(v6761 + SHIFT)); + let (_, r411) = bounded_int_div_rem(r411_bounded, FALCON512_Q_NZ); + let r412_bounded: U128AsBounded = upcast(felt252_as_u128(v6763 + SHIFT)); + let (_, r412) = bounded_int_div_rem(r412_bounded, FALCON512_Q_NZ); + let r413_bounded: U128AsBounded = upcast(felt252_as_u128(v6764 + SHIFT)); + let (_, r413) = bounded_int_div_rem(r413_bounded, FALCON512_Q_NZ); + let r414_bounded: U128AsBounded = upcast(felt252_as_u128(v6766 + SHIFT)); + let (_, r414) = bounded_int_div_rem(r414_bounded, FALCON512_Q_NZ); + let r415_bounded: U128AsBounded = upcast(felt252_as_u128(v6767 + SHIFT)); + let (_, r415) = bounded_int_div_rem(r415_bounded, FALCON512_Q_NZ); + let r416_bounded: U128AsBounded = upcast(felt252_as_u128(v6769 + SHIFT)); + let (_, r416) = bounded_int_div_rem(r416_bounded, FALCON512_Q_NZ); + let r417_bounded: U128AsBounded = upcast(felt252_as_u128(v6770 + SHIFT)); + let (_, r417) = bounded_int_div_rem(r417_bounded, FALCON512_Q_NZ); + let r418_bounded: U128AsBounded = upcast(felt252_as_u128(v6772 + SHIFT)); + let (_, r418) = bounded_int_div_rem(r418_bounded, FALCON512_Q_NZ); + let r419_bounded: U128AsBounded = upcast(felt252_as_u128(v6773 + SHIFT)); + let (_, r419) = bounded_int_div_rem(r419_bounded, FALCON512_Q_NZ); + let r420_bounded: U128AsBounded = upcast(felt252_as_u128(v6775 + SHIFT)); + let (_, r420) = bounded_int_div_rem(r420_bounded, FALCON512_Q_NZ); + let r421_bounded: U128AsBounded = upcast(felt252_as_u128(v6776 + SHIFT)); + let (_, r421) = bounded_int_div_rem(r421_bounded, FALCON512_Q_NZ); + let r422_bounded: U128AsBounded = upcast(felt252_as_u128(v6778 + SHIFT)); + let (_, r422) = bounded_int_div_rem(r422_bounded, FALCON512_Q_NZ); + let r423_bounded: U128AsBounded = upcast(felt252_as_u128(v6779 + SHIFT)); + let (_, r423) = bounded_int_div_rem(r423_bounded, FALCON512_Q_NZ); + let r424_bounded: U128AsBounded = upcast(felt252_as_u128(v6781 + SHIFT)); + let (_, r424) = bounded_int_div_rem(r424_bounded, FALCON512_Q_NZ); + let r425_bounded: U128AsBounded = upcast(felt252_as_u128(v6782 + SHIFT)); + let (_, r425) = bounded_int_div_rem(r425_bounded, FALCON512_Q_NZ); + let r426_bounded: U128AsBounded = upcast(felt252_as_u128(v6784 + SHIFT)); + let (_, r426) = bounded_int_div_rem(r426_bounded, FALCON512_Q_NZ); + let r427_bounded: U128AsBounded = upcast(felt252_as_u128(v6785 + SHIFT)); + let (_, r427) = bounded_int_div_rem(r427_bounded, FALCON512_Q_NZ); + let r428_bounded: U128AsBounded = upcast(felt252_as_u128(v6787 + SHIFT)); + let (_, r428) = bounded_int_div_rem(r428_bounded, FALCON512_Q_NZ); + let r429_bounded: U128AsBounded = upcast(felt252_as_u128(v6788 + SHIFT)); + let (_, r429) = bounded_int_div_rem(r429_bounded, FALCON512_Q_NZ); + let r430_bounded: U128AsBounded = upcast(felt252_as_u128(v6790 + SHIFT)); + let (_, r430) = bounded_int_div_rem(r430_bounded, FALCON512_Q_NZ); + let r431_bounded: U128AsBounded = upcast(felt252_as_u128(v6791 + SHIFT)); + let (_, r431) = bounded_int_div_rem(r431_bounded, FALCON512_Q_NZ); + let r432_bounded: U128AsBounded = upcast(felt252_as_u128(v6793 + SHIFT)); + let (_, r432) = bounded_int_div_rem(r432_bounded, FALCON512_Q_NZ); + let r433_bounded: U128AsBounded = upcast(felt252_as_u128(v6794 + SHIFT)); + let (_, r433) = bounded_int_div_rem(r433_bounded, FALCON512_Q_NZ); + let r434_bounded: U128AsBounded = upcast(felt252_as_u128(v6796 + SHIFT)); + let (_, r434) = bounded_int_div_rem(r434_bounded, FALCON512_Q_NZ); + let r435_bounded: U128AsBounded = upcast(felt252_as_u128(v6797 + SHIFT)); + let (_, r435) = bounded_int_div_rem(r435_bounded, FALCON512_Q_NZ); + let r436_bounded: U128AsBounded = upcast(felt252_as_u128(v6799 + SHIFT)); + let (_, r436) = bounded_int_div_rem(r436_bounded, FALCON512_Q_NZ); + let r437_bounded: U128AsBounded = upcast(felt252_as_u128(v6800 + SHIFT)); + let (_, r437) = bounded_int_div_rem(r437_bounded, FALCON512_Q_NZ); + let r438_bounded: U128AsBounded = upcast(felt252_as_u128(v6802 + SHIFT)); + let (_, r438) = bounded_int_div_rem(r438_bounded, FALCON512_Q_NZ); + let r439_bounded: U128AsBounded = upcast(felt252_as_u128(v6803 + SHIFT)); + let (_, r439) = bounded_int_div_rem(r439_bounded, FALCON512_Q_NZ); + let r440_bounded: U128AsBounded = upcast(felt252_as_u128(v6805 + SHIFT)); + let (_, r440) = bounded_int_div_rem(r440_bounded, FALCON512_Q_NZ); + let r441_bounded: U128AsBounded = upcast(felt252_as_u128(v6806 + SHIFT)); + let (_, r441) = bounded_int_div_rem(r441_bounded, FALCON512_Q_NZ); + let r442_bounded: U128AsBounded = upcast(felt252_as_u128(v6808 + SHIFT)); + let (_, r442) = bounded_int_div_rem(r442_bounded, FALCON512_Q_NZ); + let r443_bounded: U128AsBounded = upcast(felt252_as_u128(v6809 + SHIFT)); + let (_, r443) = bounded_int_div_rem(r443_bounded, FALCON512_Q_NZ); + let r444_bounded: U128AsBounded = upcast(felt252_as_u128(v6811 + SHIFT)); + let (_, r444) = bounded_int_div_rem(r444_bounded, FALCON512_Q_NZ); + let r445_bounded: U128AsBounded = upcast(felt252_as_u128(v6812 + SHIFT)); + let (_, r445) = bounded_int_div_rem(r445_bounded, FALCON512_Q_NZ); + let r446_bounded: U128AsBounded = upcast(felt252_as_u128(v6814 + SHIFT)); + let (_, r446) = bounded_int_div_rem(r446_bounded, FALCON512_Q_NZ); + let r447_bounded: U128AsBounded = upcast(felt252_as_u128(v6815 + SHIFT)); + let (_, r447) = bounded_int_div_rem(r447_bounded, FALCON512_Q_NZ); + let r448_bounded: U128AsBounded = upcast(felt252_as_u128(v6817 + SHIFT)); + let (_, r448) = bounded_int_div_rem(r448_bounded, FALCON512_Q_NZ); + let r449_bounded: U128AsBounded = upcast(felt252_as_u128(v6818 + SHIFT)); + let (_, r449) = bounded_int_div_rem(r449_bounded, FALCON512_Q_NZ); + let r450_bounded: U128AsBounded = upcast(felt252_as_u128(v6820 + SHIFT)); + let (_, r450) = bounded_int_div_rem(r450_bounded, FALCON512_Q_NZ); + let r451_bounded: U128AsBounded = upcast(felt252_as_u128(v6821 + SHIFT)); + let (_, r451) = bounded_int_div_rem(r451_bounded, FALCON512_Q_NZ); + let r452_bounded: U128AsBounded = upcast(felt252_as_u128(v6823 + SHIFT)); + let (_, r452) = bounded_int_div_rem(r452_bounded, FALCON512_Q_NZ); + let r453_bounded: U128AsBounded = upcast(felt252_as_u128(v6824 + SHIFT)); + let (_, r453) = bounded_int_div_rem(r453_bounded, FALCON512_Q_NZ); + let r454_bounded: U128AsBounded = upcast(felt252_as_u128(v6826 + SHIFT)); + let (_, r454) = bounded_int_div_rem(r454_bounded, FALCON512_Q_NZ); + let r455_bounded: U128AsBounded = upcast(felt252_as_u128(v6827 + SHIFT)); + let (_, r455) = bounded_int_div_rem(r455_bounded, FALCON512_Q_NZ); + let r456_bounded: U128AsBounded = upcast(felt252_as_u128(v6829 + SHIFT)); + let (_, r456) = bounded_int_div_rem(r456_bounded, FALCON512_Q_NZ); + let r457_bounded: U128AsBounded = upcast(felt252_as_u128(v6830 + SHIFT)); + let (_, r457) = bounded_int_div_rem(r457_bounded, FALCON512_Q_NZ); + let r458_bounded: U128AsBounded = upcast(felt252_as_u128(v6832 + SHIFT)); + let (_, r458) = bounded_int_div_rem(r458_bounded, FALCON512_Q_NZ); + let r459_bounded: U128AsBounded = upcast(felt252_as_u128(v6833 + SHIFT)); + let (_, r459) = bounded_int_div_rem(r459_bounded, FALCON512_Q_NZ); + let r460_bounded: U128AsBounded = upcast(felt252_as_u128(v6835 + SHIFT)); + let (_, r460) = bounded_int_div_rem(r460_bounded, FALCON512_Q_NZ); + let r461_bounded: U128AsBounded = upcast(felt252_as_u128(v6836 + SHIFT)); + let (_, r461) = bounded_int_div_rem(r461_bounded, FALCON512_Q_NZ); + let r462_bounded: U128AsBounded = upcast(felt252_as_u128(v6838 + SHIFT)); + let (_, r462) = bounded_int_div_rem(r462_bounded, FALCON512_Q_NZ); + let r463_bounded: U128AsBounded = upcast(felt252_as_u128(v6839 + SHIFT)); + let (_, r463) = bounded_int_div_rem(r463_bounded, FALCON512_Q_NZ); + let r464_bounded: U128AsBounded = upcast(felt252_as_u128(v6841 + SHIFT)); + let (_, r464) = bounded_int_div_rem(r464_bounded, FALCON512_Q_NZ); + let r465_bounded: U128AsBounded = upcast(felt252_as_u128(v6842 + SHIFT)); + let (_, r465) = bounded_int_div_rem(r465_bounded, FALCON512_Q_NZ); + let r466_bounded: U128AsBounded = upcast(felt252_as_u128(v6844 + SHIFT)); + let (_, r466) = bounded_int_div_rem(r466_bounded, FALCON512_Q_NZ); + let r467_bounded: U128AsBounded = upcast(felt252_as_u128(v6845 + SHIFT)); + let (_, r467) = bounded_int_div_rem(r467_bounded, FALCON512_Q_NZ); + let r468_bounded: U128AsBounded = upcast(felt252_as_u128(v6847 + SHIFT)); + let (_, r468) = bounded_int_div_rem(r468_bounded, FALCON512_Q_NZ); + let r469_bounded: U128AsBounded = upcast(felt252_as_u128(v6848 + SHIFT)); + let (_, r469) = bounded_int_div_rem(r469_bounded, FALCON512_Q_NZ); + let r470_bounded: U128AsBounded = upcast(felt252_as_u128(v6850 + SHIFT)); + let (_, r470) = bounded_int_div_rem(r470_bounded, FALCON512_Q_NZ); + let r471_bounded: U128AsBounded = upcast(felt252_as_u128(v6851 + SHIFT)); + let (_, r471) = bounded_int_div_rem(r471_bounded, FALCON512_Q_NZ); + let r472_bounded: U128AsBounded = upcast(felt252_as_u128(v6853 + SHIFT)); + let (_, r472) = bounded_int_div_rem(r472_bounded, FALCON512_Q_NZ); + let r473_bounded: U128AsBounded = upcast(felt252_as_u128(v6854 + SHIFT)); + let (_, r473) = bounded_int_div_rem(r473_bounded, FALCON512_Q_NZ); + let r474_bounded: U128AsBounded = upcast(felt252_as_u128(v6856 + SHIFT)); + let (_, r474) = bounded_int_div_rem(r474_bounded, FALCON512_Q_NZ); + let r475_bounded: U128AsBounded = upcast(felt252_as_u128(v6857 + SHIFT)); + let (_, r475) = bounded_int_div_rem(r475_bounded, FALCON512_Q_NZ); + let r476_bounded: U128AsBounded = upcast(felt252_as_u128(v6859 + SHIFT)); + let (_, r476) = bounded_int_div_rem(r476_bounded, FALCON512_Q_NZ); + let r477_bounded: U128AsBounded = upcast(felt252_as_u128(v6860 + SHIFT)); + let (_, r477) = bounded_int_div_rem(r477_bounded, FALCON512_Q_NZ); + let r478_bounded: U128AsBounded = upcast(felt252_as_u128(v6862 + SHIFT)); + let (_, r478) = bounded_int_div_rem(r478_bounded, FALCON512_Q_NZ); + let r479_bounded: U128AsBounded = upcast(felt252_as_u128(v6863 + SHIFT)); + let (_, r479) = bounded_int_div_rem(r479_bounded, FALCON512_Q_NZ); + let r480_bounded: U128AsBounded = upcast(felt252_as_u128(v6865 + SHIFT)); + let (_, r480) = bounded_int_div_rem(r480_bounded, FALCON512_Q_NZ); + let r481_bounded: U128AsBounded = upcast(felt252_as_u128(v6866 + SHIFT)); + let (_, r481) = bounded_int_div_rem(r481_bounded, FALCON512_Q_NZ); + let r482_bounded: U128AsBounded = upcast(felt252_as_u128(v6868 + SHIFT)); + let (_, r482) = bounded_int_div_rem(r482_bounded, FALCON512_Q_NZ); + let r483_bounded: U128AsBounded = upcast(felt252_as_u128(v6869 + SHIFT)); + let (_, r483) = bounded_int_div_rem(r483_bounded, FALCON512_Q_NZ); + let r484_bounded: U128AsBounded = upcast(felt252_as_u128(v6871 + SHIFT)); + let (_, r484) = bounded_int_div_rem(r484_bounded, FALCON512_Q_NZ); + let r485_bounded: U128AsBounded = upcast(felt252_as_u128(v6872 + SHIFT)); + let (_, r485) = bounded_int_div_rem(r485_bounded, FALCON512_Q_NZ); + let r486_bounded: U128AsBounded = upcast(felt252_as_u128(v6874 + SHIFT)); + let (_, r486) = bounded_int_div_rem(r486_bounded, FALCON512_Q_NZ); + let r487_bounded: U128AsBounded = upcast(felt252_as_u128(v6875 + SHIFT)); + let (_, r487) = bounded_int_div_rem(r487_bounded, FALCON512_Q_NZ); + let r488_bounded: U128AsBounded = upcast(felt252_as_u128(v6877 + SHIFT)); + let (_, r488) = bounded_int_div_rem(r488_bounded, FALCON512_Q_NZ); + let r489_bounded: U128AsBounded = upcast(felt252_as_u128(v6878 + SHIFT)); + let (_, r489) = bounded_int_div_rem(r489_bounded, FALCON512_Q_NZ); + let r490_bounded: U128AsBounded = upcast(felt252_as_u128(v6880 + SHIFT)); + let (_, r490) = bounded_int_div_rem(r490_bounded, FALCON512_Q_NZ); + let r491_bounded: U128AsBounded = upcast(felt252_as_u128(v6881 + SHIFT)); + let (_, r491) = bounded_int_div_rem(r491_bounded, FALCON512_Q_NZ); + let r492_bounded: U128AsBounded = upcast(felt252_as_u128(v6883 + SHIFT)); + let (_, r492) = bounded_int_div_rem(r492_bounded, FALCON512_Q_NZ); + let r493_bounded: U128AsBounded = upcast(felt252_as_u128(v6884 + SHIFT)); + let (_, r493) = bounded_int_div_rem(r493_bounded, FALCON512_Q_NZ); + let r494_bounded: U128AsBounded = upcast(felt252_as_u128(v6886 + SHIFT)); + let (_, r494) = bounded_int_div_rem(r494_bounded, FALCON512_Q_NZ); + let r495_bounded: U128AsBounded = upcast(felt252_as_u128(v6887 + SHIFT)); + let (_, r495) = bounded_int_div_rem(r495_bounded, FALCON512_Q_NZ); + let r496_bounded: U128AsBounded = upcast(felt252_as_u128(v6889 + SHIFT)); + let (_, r496) = bounded_int_div_rem(r496_bounded, FALCON512_Q_NZ); + let r497_bounded: U128AsBounded = upcast(felt252_as_u128(v6890 + SHIFT)); + let (_, r497) = bounded_int_div_rem(r497_bounded, FALCON512_Q_NZ); + let r498_bounded: U128AsBounded = upcast(felt252_as_u128(v6892 + SHIFT)); + let (_, r498) = bounded_int_div_rem(r498_bounded, FALCON512_Q_NZ); + let r499_bounded: U128AsBounded = upcast(felt252_as_u128(v6893 + SHIFT)); + let (_, r499) = bounded_int_div_rem(r499_bounded, FALCON512_Q_NZ); + let r500_bounded: U128AsBounded = upcast(felt252_as_u128(v6895 + SHIFT)); + let (_, r500) = bounded_int_div_rem(r500_bounded, FALCON512_Q_NZ); + let r501_bounded: U128AsBounded = upcast(felt252_as_u128(v6896 + SHIFT)); + let (_, r501) = bounded_int_div_rem(r501_bounded, FALCON512_Q_NZ); + let r502_bounded: U128AsBounded = upcast(felt252_as_u128(v6898 + SHIFT)); + let (_, r502) = bounded_int_div_rem(r502_bounded, FALCON512_Q_NZ); + let r503_bounded: U128AsBounded = upcast(felt252_as_u128(v6899 + SHIFT)); + let (_, r503) = bounded_int_div_rem(r503_bounded, FALCON512_Q_NZ); + let r504_bounded: U128AsBounded = upcast(felt252_as_u128(v6901 + SHIFT)); + let (_, r504) = bounded_int_div_rem(r504_bounded, FALCON512_Q_NZ); + let r505_bounded: U128AsBounded = upcast(felt252_as_u128(v6902 + SHIFT)); + let (_, r505) = bounded_int_div_rem(r505_bounded, FALCON512_Q_NZ); + let r506_bounded: U128AsBounded = upcast(felt252_as_u128(v6904 + SHIFT)); + let (_, r506) = bounded_int_div_rem(r506_bounded, FALCON512_Q_NZ); + let r507_bounded: U128AsBounded = upcast(felt252_as_u128(v6905 + SHIFT)); + let (_, r507) = bounded_int_div_rem(r507_bounded, FALCON512_Q_NZ); + let r508_bounded: U128AsBounded = upcast(felt252_as_u128(v6907 + SHIFT)); + let (_, r508) = bounded_int_div_rem(r508_bounded, FALCON512_Q_NZ); + let r509_bounded: U128AsBounded = upcast(felt252_as_u128(v6908 + SHIFT)); + let (_, r509) = bounded_int_div_rem(r509_bounded, FALCON512_Q_NZ); + let r510_bounded: U128AsBounded = upcast(felt252_as_u128(v6910 + SHIFT)); + let (_, r510) = bounded_int_div_rem(r510_bounded, FALCON512_Q_NZ); + let r511_bounded: U128AsBounded = upcast(felt252_as_u128(v6911 + SHIFT)); + let (_, r511) = bounded_int_div_rem(r511_bounded, FALCON512_Q_NZ); + ( + r0, + r1, + r2, + r3, + r4, + r5, + r6, + r7, + r8, + r9, + r10, + r11, + r12, + r13, + r14, + r15, + r16, + r17, + r18, + r19, + r20, + r21, + r22, + r23, + r24, + r25, + r26, + r27, + r28, + r29, + r30, + r31, + r32, + r33, + r34, + r35, + r36, + r37, + r38, + r39, + r40, + r41, + r42, + r43, + r44, + r45, + r46, + r47, + r48, + r49, + r50, + r51, + r52, + r53, + r54, + r55, + r56, + r57, + r58, + r59, + r60, + r61, + r62, + r63, + r64, + r65, + r66, + r67, + r68, + r69, + r70, + r71, + r72, + r73, + r74, + r75, + r76, + r77, + r78, + r79, + r80, + r81, + r82, + r83, + r84, + r85, + r86, + r87, + r88, + r89, + r90, + r91, + r92, + r93, + r94, + r95, + r96, + r97, + r98, + r99, + r100, + r101, + r102, + r103, + r104, + r105, + r106, + r107, + r108, + r109, + r110, + r111, + r112, + r113, + r114, + r115, + r116, + r117, + r118, + r119, + r120, + r121, + r122, + r123, + r124, + r125, + r126, + r127, + r128, + r129, + r130, + r131, + r132, + r133, + r134, + r135, + r136, + r137, + r138, + r139, + r140, + r141, + r142, + r143, + r144, + r145, + r146, + r147, + r148, + r149, + r150, + r151, + r152, + r153, + r154, + r155, + r156, + r157, + r158, + r159, + r160, + r161, + r162, + r163, + r164, + r165, + r166, + r167, + r168, + r169, + r170, + r171, + r172, + r173, + r174, + r175, + r176, + r177, + r178, + r179, + r180, + r181, + r182, + r183, + r184, + r185, + r186, + r187, + r188, + r189, + r190, + r191, + r192, + r193, + r194, + r195, + r196, + r197, + r198, + r199, + r200, + r201, + r202, + r203, + r204, + r205, + r206, + r207, + r208, + r209, + r210, + r211, + r212, + r213, + r214, + r215, + r216, + r217, + r218, + r219, + r220, + r221, + r222, + r223, + r224, + r225, + r226, + r227, + r228, + r229, + r230, + r231, + r232, + r233, + r234, + r235, + r236, + r237, + r238, + r239, + r240, + r241, + r242, + r243, + r244, + r245, + r246, + r247, + r248, + r249, + r250, + r251, + r252, + r253, + r254, + r255, + r256, + r257, + r258, + r259, + r260, + r261, + r262, + r263, + r264, + r265, + r266, + r267, + r268, + r269, + r270, + r271, + r272, + r273, + r274, + r275, + r276, + r277, + r278, + r279, + r280, + r281, + r282, + r283, + r284, + r285, + r286, + r287, + r288, + r289, + r290, + r291, + r292, + r293, + r294, + r295, + r296, + r297, + r298, + r299, + r300, + r301, + r302, + r303, + r304, + r305, + r306, + r307, + r308, + r309, + r310, + r311, + r312, + r313, + r314, + r315, + r316, + r317, + r318, + r319, + r320, + r321, + r322, + r323, + r324, + r325, + r326, + r327, + r328, + r329, + r330, + r331, + r332, + r333, + r334, + r335, + r336, + r337, + r338, + r339, + r340, + r341, + r342, + r343, + r344, + r345, + r346, + r347, + r348, + r349, + r350, + r351, + r352, + r353, + r354, + r355, + r356, + r357, + r358, + r359, + r360, + r361, + r362, + r363, + r364, + r365, + r366, + r367, + r368, + r369, + r370, + r371, + r372, + r373, + r374, + r375, + r376, + r377, + r378, + r379, + r380, + r381, + r382, + r383, + r384, + r385, + r386, + r387, + r388, + r389, + r390, + r391, + r392, + r393, + r394, + r395, + r396, + r397, + r398, + r399, + r400, + r401, + r402, + r403, + r404, + r405, + r406, + r407, + r408, + r409, + r410, + r411, + r412, + r413, + r414, + r415, + r416, + r417, + r418, + r419, + r420, + r421, + r422, + r423, + r424, + r425, + r426, + r427, + r428, + r429, + r430, + r431, + r432, + r433, + r434, + r435, + r436, + r437, + r438, + r439, + r440, + r441, + r442, + r443, + r444, + r445, + r446, + r447, + r448, + r449, + r450, + r451, + r452, + r453, + r454, + r455, + r456, + r457, + r458, + r459, + r460, + r461, + r462, + r463, + r464, + r465, + r466, + r467, + r468, + r469, + r470, + r471, + r472, + r473, + r474, + r475, + r476, + r477, + r478, + r479, + r480, + r481, + r482, + r483, + r484, + r485, + r486, + r487, + r488, + r489, + r490, + r491, + r492, + r493, + r494, + r495, + r496, + r497, + r498, + r499, + r500, + r501, + r502, + r503, + r504, + r505, + r506, + r507, + r508, + r509, + r510, + r511, + ) +} + +/// Test-only felt wrapper for the generated Falcon-512 forward NTT. +#[cfg(test)] +pub fn ntt_falcon512_fast_unchecked(mut f: Span) -> Array { + assert(f.len() == 512, 'fast NTT: bad length'); + let boxed = f.multi_pop_front::<512>().unwrap(); + let [ + f0, + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + f14, + f15, + f16, + f17, + f18, + f19, + f20, + f21, + f22, + f23, + f24, + f25, + f26, + f27, + f28, + f29, + f30, + f31, + f32, + f33, + f34, + f35, + f36, + f37, + f38, + f39, + f40, + f41, + f42, + f43, + f44, + f45, + f46, + f47, + f48, + f49, + f50, + f51, + f52, + f53, + f54, + f55, + f56, + f57, + f58, + f59, + f60, + f61, + f62, + f63, + f64, + f65, + f66, + f67, + f68, + f69, + f70, + f71, + f72, + f73, + f74, + f75, + f76, + f77, + f78, + f79, + f80, + f81, + f82, + f83, + f84, + f85, + f86, + f87, + f88, + f89, + f90, + f91, + f92, + f93, + f94, + f95, + f96, + f97, + f98, + f99, + f100, + f101, + f102, + f103, + f104, + f105, + f106, + f107, + f108, + f109, + f110, + f111, + f112, + f113, + f114, + f115, + f116, + f117, + f118, + f119, + f120, + f121, + f122, + f123, + f124, + f125, + f126, + f127, + f128, + f129, + f130, + f131, + f132, + f133, + f134, + f135, + f136, + f137, + f138, + f139, + f140, + f141, + f142, + f143, + f144, + f145, + f146, + f147, + f148, + f149, + f150, + f151, + f152, + f153, + f154, + f155, + f156, + f157, + f158, + f159, + f160, + f161, + f162, + f163, + f164, + f165, + f166, + f167, + f168, + f169, + f170, + f171, + f172, + f173, + f174, + f175, + f176, + f177, + f178, + f179, + f180, + f181, + f182, + f183, + f184, + f185, + f186, + f187, + f188, + f189, + f190, + f191, + f192, + f193, + f194, + f195, + f196, + f197, + f198, + f199, + f200, + f201, + f202, + f203, + f204, + f205, + f206, + f207, + f208, + f209, + f210, + f211, + f212, + f213, + f214, + f215, + f216, + f217, + f218, + f219, + f220, + f221, + f222, + f223, + f224, + f225, + f226, + f227, + f228, + f229, + f230, + f231, + f232, + f233, + f234, + f235, + f236, + f237, + f238, + f239, + f240, + f241, + f242, + f243, + f244, + f245, + f246, + f247, + f248, + f249, + f250, + f251, + f252, + f253, + f254, + f255, + f256, + f257, + f258, + f259, + f260, + f261, + f262, + f263, + f264, + f265, + f266, + f267, + f268, + f269, + f270, + f271, + f272, + f273, + f274, + f275, + f276, + f277, + f278, + f279, + f280, + f281, + f282, + f283, + f284, + f285, + f286, + f287, + f288, + f289, + f290, + f291, + f292, + f293, + f294, + f295, + f296, + f297, + f298, + f299, + f300, + f301, + f302, + f303, + f304, + f305, + f306, + f307, + f308, + f309, + f310, + f311, + f312, + f313, + f314, + f315, + f316, + f317, + f318, + f319, + f320, + f321, + f322, + f323, + f324, + f325, + f326, + f327, + f328, + f329, + f330, + f331, + f332, + f333, + f334, + f335, + f336, + f337, + f338, + f339, + f340, + f341, + f342, + f343, + f344, + f345, + f346, + f347, + f348, + f349, + f350, + f351, + f352, + f353, + f354, + f355, + f356, + f357, + f358, + f359, + f360, + f361, + f362, + f363, + f364, + f365, + f366, + f367, + f368, + f369, + f370, + f371, + f372, + f373, + f374, + f375, + f376, + f377, + f378, + f379, + f380, + f381, + f382, + f383, + f384, + f385, + f386, + f387, + f388, + f389, + f390, + f391, + f392, + f393, + f394, + f395, + f396, + f397, + f398, + f399, + f400, + f401, + f402, + f403, + f404, + f405, + f406, + f407, + f408, + f409, + f410, + f411, + f412, + f413, + f414, + f415, + f416, + f417, + f418, + f419, + f420, + f421, + f422, + f423, + f424, + f425, + f426, + f427, + f428, + f429, + f430, + f431, + f432, + f433, + f434, + f435, + f436, + f437, + f438, + f439, + f440, + f441, + f442, + f443, + f444, + f445, + f446, + f447, + f448, + f449, + f450, + f451, + f452, + f453, + f454, + f455, + f456, + f457, + f458, + f459, + f460, + f461, + f462, + f463, + f464, + f465, + f466, + f467, + f468, + f469, + f470, + f471, + f472, + f473, + f474, + f475, + f476, + f477, + f478, + f479, + f480, + f481, + f482, + f483, + f484, + f485, + f486, + f487, + f488, + f489, + f490, + f491, + f492, + f493, + f494, + f495, + f496, + f497, + f498, + f499, + f500, + f501, + f502, + f503, + f504, + f505, + f506, + f507, + f508, + f509, + f510, + f511, + ] = + boxed + .unbox(); + let ( + r0, + r1, + r2, + r3, + r4, + r5, + r6, + r7, + r8, + r9, + r10, + r11, + r12, + r13, + r14, + r15, + r16, + r17, + r18, + r19, + r20, + r21, + r22, + r23, + r24, + r25, + r26, + r27, + r28, + r29, + r30, + r31, + r32, + r33, + r34, + r35, + r36, + r37, + r38, + r39, + r40, + r41, + r42, + r43, + r44, + r45, + r46, + r47, + r48, + r49, + r50, + r51, + r52, + r53, + r54, + r55, + r56, + r57, + r58, + r59, + r60, + r61, + r62, + r63, + r64, + r65, + r66, + r67, + r68, + r69, + r70, + r71, + r72, + r73, + r74, + r75, + r76, + r77, + r78, + r79, + r80, + r81, + r82, + r83, + r84, + r85, + r86, + r87, + r88, + r89, + r90, + r91, + r92, + r93, + r94, + r95, + r96, + r97, + r98, + r99, + r100, + r101, + r102, + r103, + r104, + r105, + r106, + r107, + r108, + r109, + r110, + r111, + r112, + r113, + r114, + r115, + r116, + r117, + r118, + r119, + r120, + r121, + r122, + r123, + r124, + r125, + r126, + r127, + r128, + r129, + r130, + r131, + r132, + r133, + r134, + r135, + r136, + r137, + r138, + r139, + r140, + r141, + r142, + r143, + r144, + r145, + r146, + r147, + r148, + r149, + r150, + r151, + r152, + r153, + r154, + r155, + r156, + r157, + r158, + r159, + r160, + r161, + r162, + r163, + r164, + r165, + r166, + r167, + r168, + r169, + r170, + r171, + r172, + r173, + r174, + r175, + r176, + r177, + r178, + r179, + r180, + r181, + r182, + r183, + r184, + r185, + r186, + r187, + r188, + r189, + r190, + r191, + r192, + r193, + r194, + r195, + r196, + r197, + r198, + r199, + r200, + r201, + r202, + r203, + r204, + r205, + r206, + r207, + r208, + r209, + r210, + r211, + r212, + r213, + r214, + r215, + r216, + r217, + r218, + r219, + r220, + r221, + r222, + r223, + r224, + r225, + r226, + r227, + r228, + r229, + r230, + r231, + r232, + r233, + r234, + r235, + r236, + r237, + r238, + r239, + r240, + r241, + r242, + r243, + r244, + r245, + r246, + r247, + r248, + r249, + r250, + r251, + r252, + r253, + r254, + r255, + r256, + r257, + r258, + r259, + r260, + r261, + r262, + r263, + r264, + r265, + r266, + r267, + r268, + r269, + r270, + r271, + r272, + r273, + r274, + r275, + r276, + r277, + r278, + r279, + r280, + r281, + r282, + r283, + r284, + r285, + r286, + r287, + r288, + r289, + r290, + r291, + r292, + r293, + r294, + r295, + r296, + r297, + r298, + r299, + r300, + r301, + r302, + r303, + r304, + r305, + r306, + r307, + r308, + r309, + r310, + r311, + r312, + r313, + r314, + r315, + r316, + r317, + r318, + r319, + r320, + r321, + r322, + r323, + r324, + r325, + r326, + r327, + r328, + r329, + r330, + r331, + r332, + r333, + r334, + r335, + r336, + r337, + r338, + r339, + r340, + r341, + r342, + r343, + r344, + r345, + r346, + r347, + r348, + r349, + r350, + r351, + r352, + r353, + r354, + r355, + r356, + r357, + r358, + r359, + r360, + r361, + r362, + r363, + r364, + r365, + r366, + r367, + r368, + r369, + r370, + r371, + r372, + r373, + r374, + r375, + r376, + r377, + r378, + r379, + r380, + r381, + r382, + r383, + r384, + r385, + r386, + r387, + r388, + r389, + r390, + r391, + r392, + r393, + r394, + r395, + r396, + r397, + r398, + r399, + r400, + r401, + r402, + r403, + r404, + r405, + r406, + r407, + r408, + r409, + r410, + r411, + r412, + r413, + r414, + r415, + r416, + r417, + r418, + r419, + r420, + r421, + r422, + r423, + r424, + r425, + r426, + r427, + r428, + r429, + r430, + r431, + r432, + r433, + r434, + r435, + r436, + r437, + r438, + r439, + r440, + r441, + r442, + r443, + r444, + r445, + r446, + r447, + r448, + r449, + r450, + r451, + r452, + r453, + r454, + r455, + r456, + r457, + r458, + r459, + r460, + r461, + r462, + r463, + r464, + r465, + r466, + r467, + r468, + r469, + r470, + r471, + r472, + r473, + r474, + r475, + r476, + r477, + r478, + r479, + r480, + r481, + r482, + r483, + r484, + r485, + r486, + r487, + r488, + r489, + r490, + r491, + r492, + r493, + r494, + r495, + r496, + r497, + r498, + r499, + r500, + r501, + r502, + r503, + r504, + r505, + r506, + r507, + r508, + r509, + r510, + r511, + ) = + ntt_falcon512_fast_inner( + f0, + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + f14, + f15, + f16, + f17, + f18, + f19, + f20, + f21, + f22, + f23, + f24, + f25, + f26, + f27, + f28, + f29, + f30, + f31, + f32, + f33, + f34, + f35, + f36, + f37, + f38, + f39, + f40, + f41, + f42, + f43, + f44, + f45, + f46, + f47, + f48, + f49, + f50, + f51, + f52, + f53, + f54, + f55, + f56, + f57, + f58, + f59, + f60, + f61, + f62, + f63, + f64, + f65, + f66, + f67, + f68, + f69, + f70, + f71, + f72, + f73, + f74, + f75, + f76, + f77, + f78, + f79, + f80, + f81, + f82, + f83, + f84, + f85, + f86, + f87, + f88, + f89, + f90, + f91, + f92, + f93, + f94, + f95, + f96, + f97, + f98, + f99, + f100, + f101, + f102, + f103, + f104, + f105, + f106, + f107, + f108, + f109, + f110, + f111, + f112, + f113, + f114, + f115, + f116, + f117, + f118, + f119, + f120, + f121, + f122, + f123, + f124, + f125, + f126, + f127, + f128, + f129, + f130, + f131, + f132, + f133, + f134, + f135, + f136, + f137, + f138, + f139, + f140, + f141, + f142, + f143, + f144, + f145, + f146, + f147, + f148, + f149, + f150, + f151, + f152, + f153, + f154, + f155, + f156, + f157, + f158, + f159, + f160, + f161, + f162, + f163, + f164, + f165, + f166, + f167, + f168, + f169, + f170, + f171, + f172, + f173, + f174, + f175, + f176, + f177, + f178, + f179, + f180, + f181, + f182, + f183, + f184, + f185, + f186, + f187, + f188, + f189, + f190, + f191, + f192, + f193, + f194, + f195, + f196, + f197, + f198, + f199, + f200, + f201, + f202, + f203, + f204, + f205, + f206, + f207, + f208, + f209, + f210, + f211, + f212, + f213, + f214, + f215, + f216, + f217, + f218, + f219, + f220, + f221, + f222, + f223, + f224, + f225, + f226, + f227, + f228, + f229, + f230, + f231, + f232, + f233, + f234, + f235, + f236, + f237, + f238, + f239, + f240, + f241, + f242, + f243, + f244, + f245, + f246, + f247, + f248, + f249, + f250, + f251, + f252, + f253, + f254, + f255, + f256, + f257, + f258, + f259, + f260, + f261, + f262, + f263, + f264, + f265, + f266, + f267, + f268, + f269, + f270, + f271, + f272, + f273, + f274, + f275, + f276, + f277, + f278, + f279, + f280, + f281, + f282, + f283, + f284, + f285, + f286, + f287, + f288, + f289, + f290, + f291, + f292, + f293, + f294, + f295, + f296, + f297, + f298, + f299, + f300, + f301, + f302, + f303, + f304, + f305, + f306, + f307, + f308, + f309, + f310, + f311, + f312, + f313, + f314, + f315, + f316, + f317, + f318, + f319, + f320, + f321, + f322, + f323, + f324, + f325, + f326, + f327, + f328, + f329, + f330, + f331, + f332, + f333, + f334, + f335, + f336, + f337, + f338, + f339, + f340, + f341, + f342, + f343, + f344, + f345, + f346, + f347, + f348, + f349, + f350, + f351, + f352, + f353, + f354, + f355, + f356, + f357, + f358, + f359, + f360, + f361, + f362, + f363, + f364, + f365, + f366, + f367, + f368, + f369, + f370, + f371, + f372, + f373, + f374, + f375, + f376, + f377, + f378, + f379, + f380, + f381, + f382, + f383, + f384, + f385, + f386, + f387, + f388, + f389, + f390, + f391, + f392, + f393, + f394, + f395, + f396, + f397, + f398, + f399, + f400, + f401, + f402, + f403, + f404, + f405, + f406, + f407, + f408, + f409, + f410, + f411, + f412, + f413, + f414, + f415, + f416, + f417, + f418, + f419, + f420, + f421, + f422, + f423, + f424, + f425, + f426, + f427, + f428, + f429, + f430, + f431, + f432, + f433, + f434, + f435, + f436, + f437, + f438, + f439, + f440, + f441, + f442, + f443, + f444, + f445, + f446, + f447, + f448, + f449, + f450, + f451, + f452, + f453, + f454, + f455, + f456, + f457, + f458, + f459, + f460, + f461, + f462, + f463, + f464, + f465, + f466, + f467, + f468, + f469, + f470, + f471, + f472, + f473, + f474, + f475, + f476, + f477, + f478, + f479, + f480, + f481, + f482, + f483, + f484, + f485, + f486, + f487, + f488, + f489, + f490, + f491, + f492, + f493, + f494, + f495, + f496, + f497, + f498, + f499, + f500, + f501, + f502, + f503, + f504, + f505, + f506, + f507, + f508, + f509, + f510, + f511, + ); + array![ + upcast(r0), upcast(r1), upcast(r2), upcast(r3), upcast(r4), upcast(r5), upcast(r6), + upcast(r7), upcast(r8), upcast(r9), upcast(r10), upcast(r11), upcast(r12), upcast(r13), + upcast(r14), upcast(r15), upcast(r16), upcast(r17), upcast(r18), upcast(r19), upcast(r20), + upcast(r21), upcast(r22), upcast(r23), upcast(r24), upcast(r25), upcast(r26), upcast(r27), + upcast(r28), upcast(r29), upcast(r30), upcast(r31), upcast(r32), upcast(r33), upcast(r34), + upcast(r35), upcast(r36), upcast(r37), upcast(r38), upcast(r39), upcast(r40), upcast(r41), + upcast(r42), upcast(r43), upcast(r44), upcast(r45), upcast(r46), upcast(r47), upcast(r48), + upcast(r49), upcast(r50), upcast(r51), upcast(r52), upcast(r53), upcast(r54), upcast(r55), + upcast(r56), upcast(r57), upcast(r58), upcast(r59), upcast(r60), upcast(r61), upcast(r62), + upcast(r63), upcast(r64), upcast(r65), upcast(r66), upcast(r67), upcast(r68), upcast(r69), + upcast(r70), upcast(r71), upcast(r72), upcast(r73), upcast(r74), upcast(r75), upcast(r76), + upcast(r77), upcast(r78), upcast(r79), upcast(r80), upcast(r81), upcast(r82), upcast(r83), + upcast(r84), upcast(r85), upcast(r86), upcast(r87), upcast(r88), upcast(r89), upcast(r90), + upcast(r91), upcast(r92), upcast(r93), upcast(r94), upcast(r95), upcast(r96), upcast(r97), + upcast(r98), upcast(r99), upcast(r100), upcast(r101), upcast(r102), upcast(r103), + upcast(r104), upcast(r105), upcast(r106), upcast(r107), upcast(r108), upcast(r109), + upcast(r110), upcast(r111), upcast(r112), upcast(r113), upcast(r114), upcast(r115), + upcast(r116), upcast(r117), upcast(r118), upcast(r119), upcast(r120), upcast(r121), + upcast(r122), upcast(r123), upcast(r124), upcast(r125), upcast(r126), upcast(r127), + upcast(r128), upcast(r129), upcast(r130), upcast(r131), upcast(r132), upcast(r133), + upcast(r134), upcast(r135), upcast(r136), upcast(r137), upcast(r138), upcast(r139), + upcast(r140), upcast(r141), upcast(r142), upcast(r143), upcast(r144), upcast(r145), + upcast(r146), upcast(r147), upcast(r148), upcast(r149), upcast(r150), upcast(r151), + upcast(r152), upcast(r153), upcast(r154), upcast(r155), upcast(r156), upcast(r157), + upcast(r158), upcast(r159), upcast(r160), upcast(r161), upcast(r162), upcast(r163), + upcast(r164), upcast(r165), upcast(r166), upcast(r167), upcast(r168), upcast(r169), + upcast(r170), upcast(r171), upcast(r172), upcast(r173), upcast(r174), upcast(r175), + upcast(r176), upcast(r177), upcast(r178), upcast(r179), upcast(r180), upcast(r181), + upcast(r182), upcast(r183), upcast(r184), upcast(r185), upcast(r186), upcast(r187), + upcast(r188), upcast(r189), upcast(r190), upcast(r191), upcast(r192), upcast(r193), + upcast(r194), upcast(r195), upcast(r196), upcast(r197), upcast(r198), upcast(r199), + upcast(r200), upcast(r201), upcast(r202), upcast(r203), upcast(r204), upcast(r205), + upcast(r206), upcast(r207), upcast(r208), upcast(r209), upcast(r210), upcast(r211), + upcast(r212), upcast(r213), upcast(r214), upcast(r215), upcast(r216), upcast(r217), + upcast(r218), upcast(r219), upcast(r220), upcast(r221), upcast(r222), upcast(r223), + upcast(r224), upcast(r225), upcast(r226), upcast(r227), upcast(r228), upcast(r229), + upcast(r230), upcast(r231), upcast(r232), upcast(r233), upcast(r234), upcast(r235), + upcast(r236), upcast(r237), upcast(r238), upcast(r239), upcast(r240), upcast(r241), + upcast(r242), upcast(r243), upcast(r244), upcast(r245), upcast(r246), upcast(r247), + upcast(r248), upcast(r249), upcast(r250), upcast(r251), upcast(r252), upcast(r253), + upcast(r254), upcast(r255), upcast(r256), upcast(r257), upcast(r258), upcast(r259), + upcast(r260), upcast(r261), upcast(r262), upcast(r263), upcast(r264), upcast(r265), + upcast(r266), upcast(r267), upcast(r268), upcast(r269), upcast(r270), upcast(r271), + upcast(r272), upcast(r273), upcast(r274), upcast(r275), upcast(r276), upcast(r277), + upcast(r278), upcast(r279), upcast(r280), upcast(r281), upcast(r282), upcast(r283), + upcast(r284), upcast(r285), upcast(r286), upcast(r287), upcast(r288), upcast(r289), + upcast(r290), upcast(r291), upcast(r292), upcast(r293), upcast(r294), upcast(r295), + upcast(r296), upcast(r297), upcast(r298), upcast(r299), upcast(r300), upcast(r301), + upcast(r302), upcast(r303), upcast(r304), upcast(r305), upcast(r306), upcast(r307), + upcast(r308), upcast(r309), upcast(r310), upcast(r311), upcast(r312), upcast(r313), + upcast(r314), upcast(r315), upcast(r316), upcast(r317), upcast(r318), upcast(r319), + upcast(r320), upcast(r321), upcast(r322), upcast(r323), upcast(r324), upcast(r325), + upcast(r326), upcast(r327), upcast(r328), upcast(r329), upcast(r330), upcast(r331), + upcast(r332), upcast(r333), upcast(r334), upcast(r335), upcast(r336), upcast(r337), + upcast(r338), upcast(r339), upcast(r340), upcast(r341), upcast(r342), upcast(r343), + upcast(r344), upcast(r345), upcast(r346), upcast(r347), upcast(r348), upcast(r349), + upcast(r350), upcast(r351), upcast(r352), upcast(r353), upcast(r354), upcast(r355), + upcast(r356), upcast(r357), upcast(r358), upcast(r359), upcast(r360), upcast(r361), + upcast(r362), upcast(r363), upcast(r364), upcast(r365), upcast(r366), upcast(r367), + upcast(r368), upcast(r369), upcast(r370), upcast(r371), upcast(r372), upcast(r373), + upcast(r374), upcast(r375), upcast(r376), upcast(r377), upcast(r378), upcast(r379), + upcast(r380), upcast(r381), upcast(r382), upcast(r383), upcast(r384), upcast(r385), + upcast(r386), upcast(r387), upcast(r388), upcast(r389), upcast(r390), upcast(r391), + upcast(r392), upcast(r393), upcast(r394), upcast(r395), upcast(r396), upcast(r397), + upcast(r398), upcast(r399), upcast(r400), upcast(r401), upcast(r402), upcast(r403), + upcast(r404), upcast(r405), upcast(r406), upcast(r407), upcast(r408), upcast(r409), + upcast(r410), upcast(r411), upcast(r412), upcast(r413), upcast(r414), upcast(r415), + upcast(r416), upcast(r417), upcast(r418), upcast(r419), upcast(r420), upcast(r421), + upcast(r422), upcast(r423), upcast(r424), upcast(r425), upcast(r426), upcast(r427), + upcast(r428), upcast(r429), upcast(r430), upcast(r431), upcast(r432), upcast(r433), + upcast(r434), upcast(r435), upcast(r436), upcast(r437), upcast(r438), upcast(r439), + upcast(r440), upcast(r441), upcast(r442), upcast(r443), upcast(r444), upcast(r445), + upcast(r446), upcast(r447), upcast(r448), upcast(r449), upcast(r450), upcast(r451), + upcast(r452), upcast(r453), upcast(r454), upcast(r455), upcast(r456), upcast(r457), + upcast(r458), upcast(r459), upcast(r460), upcast(r461), upcast(r462), upcast(r463), + upcast(r464), upcast(r465), upcast(r466), upcast(r467), upcast(r468), upcast(r469), + upcast(r470), upcast(r471), upcast(r472), upcast(r473), upcast(r474), upcast(r475), + upcast(r476), upcast(r477), upcast(r478), upcast(r479), upcast(r480), upcast(r481), + upcast(r482), upcast(r483), upcast(r484), upcast(r485), upcast(r486), upcast(r487), + upcast(r488), upcast(r489), upcast(r490), upcast(r491), upcast(r492), upcast(r493), + upcast(r494), upcast(r495), upcast(r496), upcast(r497), upcast(r498), upcast(r499), + upcast(r500), upcast(r501), upcast(r502), upcast(r503), upcast(r504), upcast(r505), + upcast(r506), upcast(r507), upcast(r508), upcast(r509), upcast(r510), upcast(r511), + ] +} + +/// Computes the Falcon-512 forward NTT from canonical `u16` coefficients. +/// +/// Inputs must be in `[0, 12289)`; violating that precondition may return an +/// invalid transform. Outputs are reduced to the same range. +pub fn ntt_falcon512_fast_u16_unchecked(mut f: Span) -> Array { + assert(f.len() == 512, 'fast NTT: bad length'); + let boxed = f.multi_pop_front::<512>().unwrap(); + let [ + f0, + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + f14, + f15, + f16, + f17, + f18, + f19, + f20, + f21, + f22, + f23, + f24, + f25, + f26, + f27, + f28, + f29, + f30, + f31, + f32, + f33, + f34, + f35, + f36, + f37, + f38, + f39, + f40, + f41, + f42, + f43, + f44, + f45, + f46, + f47, + f48, + f49, + f50, + f51, + f52, + f53, + f54, + f55, + f56, + f57, + f58, + f59, + f60, + f61, + f62, + f63, + f64, + f65, + f66, + f67, + f68, + f69, + f70, + f71, + f72, + f73, + f74, + f75, + f76, + f77, + f78, + f79, + f80, + f81, + f82, + f83, + f84, + f85, + f86, + f87, + f88, + f89, + f90, + f91, + f92, + f93, + f94, + f95, + f96, + f97, + f98, + f99, + f100, + f101, + f102, + f103, + f104, + f105, + f106, + f107, + f108, + f109, + f110, + f111, + f112, + f113, + f114, + f115, + f116, + f117, + f118, + f119, + f120, + f121, + f122, + f123, + f124, + f125, + f126, + f127, + f128, + f129, + f130, + f131, + f132, + f133, + f134, + f135, + f136, + f137, + f138, + f139, + f140, + f141, + f142, + f143, + f144, + f145, + f146, + f147, + f148, + f149, + f150, + f151, + f152, + f153, + f154, + f155, + f156, + f157, + f158, + f159, + f160, + f161, + f162, + f163, + f164, + f165, + f166, + f167, + f168, + f169, + f170, + f171, + f172, + f173, + f174, + f175, + f176, + f177, + f178, + f179, + f180, + f181, + f182, + f183, + f184, + f185, + f186, + f187, + f188, + f189, + f190, + f191, + f192, + f193, + f194, + f195, + f196, + f197, + f198, + f199, + f200, + f201, + f202, + f203, + f204, + f205, + f206, + f207, + f208, + f209, + f210, + f211, + f212, + f213, + f214, + f215, + f216, + f217, + f218, + f219, + f220, + f221, + f222, + f223, + f224, + f225, + f226, + f227, + f228, + f229, + f230, + f231, + f232, + f233, + f234, + f235, + f236, + f237, + f238, + f239, + f240, + f241, + f242, + f243, + f244, + f245, + f246, + f247, + f248, + f249, + f250, + f251, + f252, + f253, + f254, + f255, + f256, + f257, + f258, + f259, + f260, + f261, + f262, + f263, + f264, + f265, + f266, + f267, + f268, + f269, + f270, + f271, + f272, + f273, + f274, + f275, + f276, + f277, + f278, + f279, + f280, + f281, + f282, + f283, + f284, + f285, + f286, + f287, + f288, + f289, + f290, + f291, + f292, + f293, + f294, + f295, + f296, + f297, + f298, + f299, + f300, + f301, + f302, + f303, + f304, + f305, + f306, + f307, + f308, + f309, + f310, + f311, + f312, + f313, + f314, + f315, + f316, + f317, + f318, + f319, + f320, + f321, + f322, + f323, + f324, + f325, + f326, + f327, + f328, + f329, + f330, + f331, + f332, + f333, + f334, + f335, + f336, + f337, + f338, + f339, + f340, + f341, + f342, + f343, + f344, + f345, + f346, + f347, + f348, + f349, + f350, + f351, + f352, + f353, + f354, + f355, + f356, + f357, + f358, + f359, + f360, + f361, + f362, + f363, + f364, + f365, + f366, + f367, + f368, + f369, + f370, + f371, + f372, + f373, + f374, + f375, + f376, + f377, + f378, + f379, + f380, + f381, + f382, + f383, + f384, + f385, + f386, + f387, + f388, + f389, + f390, + f391, + f392, + f393, + f394, + f395, + f396, + f397, + f398, + f399, + f400, + f401, + f402, + f403, + f404, + f405, + f406, + f407, + f408, + f409, + f410, + f411, + f412, + f413, + f414, + f415, + f416, + f417, + f418, + f419, + f420, + f421, + f422, + f423, + f424, + f425, + f426, + f427, + f428, + f429, + f430, + f431, + f432, + f433, + f434, + f435, + f436, + f437, + f438, + f439, + f440, + f441, + f442, + f443, + f444, + f445, + f446, + f447, + f448, + f449, + f450, + f451, + f452, + f453, + f454, + f455, + f456, + f457, + f458, + f459, + f460, + f461, + f462, + f463, + f464, + f465, + f466, + f467, + f468, + f469, + f470, + f471, + f472, + f473, + f474, + f475, + f476, + f477, + f478, + f479, + f480, + f481, + f482, + f483, + f484, + f485, + f486, + f487, + f488, + f489, + f490, + f491, + f492, + f493, + f494, + f495, + f496, + f497, + f498, + f499, + f500, + f501, + f502, + f503, + f504, + f505, + f506, + f507, + f508, + f509, + f510, + f511, + ] = + boxed + .unbox(); + let ( + r0, + r1, + r2, + r3, + r4, + r5, + r6, + r7, + r8, + r9, + r10, + r11, + r12, + r13, + r14, + r15, + r16, + r17, + r18, + r19, + r20, + r21, + r22, + r23, + r24, + r25, + r26, + r27, + r28, + r29, + r30, + r31, + r32, + r33, + r34, + r35, + r36, + r37, + r38, + r39, + r40, + r41, + r42, + r43, + r44, + r45, + r46, + r47, + r48, + r49, + r50, + r51, + r52, + r53, + r54, + r55, + r56, + r57, + r58, + r59, + r60, + r61, + r62, + r63, + r64, + r65, + r66, + r67, + r68, + r69, + r70, + r71, + r72, + r73, + r74, + r75, + r76, + r77, + r78, + r79, + r80, + r81, + r82, + r83, + r84, + r85, + r86, + r87, + r88, + r89, + r90, + r91, + r92, + r93, + r94, + r95, + r96, + r97, + r98, + r99, + r100, + r101, + r102, + r103, + r104, + r105, + r106, + r107, + r108, + r109, + r110, + r111, + r112, + r113, + r114, + r115, + r116, + r117, + r118, + r119, + r120, + r121, + r122, + r123, + r124, + r125, + r126, + r127, + r128, + r129, + r130, + r131, + r132, + r133, + r134, + r135, + r136, + r137, + r138, + r139, + r140, + r141, + r142, + r143, + r144, + r145, + r146, + r147, + r148, + r149, + r150, + r151, + r152, + r153, + r154, + r155, + r156, + r157, + r158, + r159, + r160, + r161, + r162, + r163, + r164, + r165, + r166, + r167, + r168, + r169, + r170, + r171, + r172, + r173, + r174, + r175, + r176, + r177, + r178, + r179, + r180, + r181, + r182, + r183, + r184, + r185, + r186, + r187, + r188, + r189, + r190, + r191, + r192, + r193, + r194, + r195, + r196, + r197, + r198, + r199, + r200, + r201, + r202, + r203, + r204, + r205, + r206, + r207, + r208, + r209, + r210, + r211, + r212, + r213, + r214, + r215, + r216, + r217, + r218, + r219, + r220, + r221, + r222, + r223, + r224, + r225, + r226, + r227, + r228, + r229, + r230, + r231, + r232, + r233, + r234, + r235, + r236, + r237, + r238, + r239, + r240, + r241, + r242, + r243, + r244, + r245, + r246, + r247, + r248, + r249, + r250, + r251, + r252, + r253, + r254, + r255, + r256, + r257, + r258, + r259, + r260, + r261, + r262, + r263, + r264, + r265, + r266, + r267, + r268, + r269, + r270, + r271, + r272, + r273, + r274, + r275, + r276, + r277, + r278, + r279, + r280, + r281, + r282, + r283, + r284, + r285, + r286, + r287, + r288, + r289, + r290, + r291, + r292, + r293, + r294, + r295, + r296, + r297, + r298, + r299, + r300, + r301, + r302, + r303, + r304, + r305, + r306, + r307, + r308, + r309, + r310, + r311, + r312, + r313, + r314, + r315, + r316, + r317, + r318, + r319, + r320, + r321, + r322, + r323, + r324, + r325, + r326, + r327, + r328, + r329, + r330, + r331, + r332, + r333, + r334, + r335, + r336, + r337, + r338, + r339, + r340, + r341, + r342, + r343, + r344, + r345, + r346, + r347, + r348, + r349, + r350, + r351, + r352, + r353, + r354, + r355, + r356, + r357, + r358, + r359, + r360, + r361, + r362, + r363, + r364, + r365, + r366, + r367, + r368, + r369, + r370, + r371, + r372, + r373, + r374, + r375, + r376, + r377, + r378, + r379, + r380, + r381, + r382, + r383, + r384, + r385, + r386, + r387, + r388, + r389, + r390, + r391, + r392, + r393, + r394, + r395, + r396, + r397, + r398, + r399, + r400, + r401, + r402, + r403, + r404, + r405, + r406, + r407, + r408, + r409, + r410, + r411, + r412, + r413, + r414, + r415, + r416, + r417, + r418, + r419, + r420, + r421, + r422, + r423, + r424, + r425, + r426, + r427, + r428, + r429, + r430, + r431, + r432, + r433, + r434, + r435, + r436, + r437, + r438, + r439, + r440, + r441, + r442, + r443, + r444, + r445, + r446, + r447, + r448, + r449, + r450, + r451, + r452, + r453, + r454, + r455, + r456, + r457, + r458, + r459, + r460, + r461, + r462, + r463, + r464, + r465, + r466, + r467, + r468, + r469, + r470, + r471, + r472, + r473, + r474, + r475, + r476, + r477, + r478, + r479, + r480, + r481, + r482, + r483, + r484, + r485, + r486, + r487, + r488, + r489, + r490, + r491, + r492, + r493, + r494, + r495, + r496, + r497, + r498, + r499, + r500, + r501, + r502, + r503, + r504, + r505, + r506, + r507, + r508, + r509, + r510, + r511, + ) = + ntt_falcon512_fast_inner( + f0.into(), + f1.into(), + f2.into(), + f3.into(), + f4.into(), + f5.into(), + f6.into(), + f7.into(), + f8.into(), + f9.into(), + f10.into(), + f11.into(), + f12.into(), + f13.into(), + f14.into(), + f15.into(), + f16.into(), + f17.into(), + f18.into(), + f19.into(), + f20.into(), + f21.into(), + f22.into(), + f23.into(), + f24.into(), + f25.into(), + f26.into(), + f27.into(), + f28.into(), + f29.into(), + f30.into(), + f31.into(), + f32.into(), + f33.into(), + f34.into(), + f35.into(), + f36.into(), + f37.into(), + f38.into(), + f39.into(), + f40.into(), + f41.into(), + f42.into(), + f43.into(), + f44.into(), + f45.into(), + f46.into(), + f47.into(), + f48.into(), + f49.into(), + f50.into(), + f51.into(), + f52.into(), + f53.into(), + f54.into(), + f55.into(), + f56.into(), + f57.into(), + f58.into(), + f59.into(), + f60.into(), + f61.into(), + f62.into(), + f63.into(), + f64.into(), + f65.into(), + f66.into(), + f67.into(), + f68.into(), + f69.into(), + f70.into(), + f71.into(), + f72.into(), + f73.into(), + f74.into(), + f75.into(), + f76.into(), + f77.into(), + f78.into(), + f79.into(), + f80.into(), + f81.into(), + f82.into(), + f83.into(), + f84.into(), + f85.into(), + f86.into(), + f87.into(), + f88.into(), + f89.into(), + f90.into(), + f91.into(), + f92.into(), + f93.into(), + f94.into(), + f95.into(), + f96.into(), + f97.into(), + f98.into(), + f99.into(), + f100.into(), + f101.into(), + f102.into(), + f103.into(), + f104.into(), + f105.into(), + f106.into(), + f107.into(), + f108.into(), + f109.into(), + f110.into(), + f111.into(), + f112.into(), + f113.into(), + f114.into(), + f115.into(), + f116.into(), + f117.into(), + f118.into(), + f119.into(), + f120.into(), + f121.into(), + f122.into(), + f123.into(), + f124.into(), + f125.into(), + f126.into(), + f127.into(), + f128.into(), + f129.into(), + f130.into(), + f131.into(), + f132.into(), + f133.into(), + f134.into(), + f135.into(), + f136.into(), + f137.into(), + f138.into(), + f139.into(), + f140.into(), + f141.into(), + f142.into(), + f143.into(), + f144.into(), + f145.into(), + f146.into(), + f147.into(), + f148.into(), + f149.into(), + f150.into(), + f151.into(), + f152.into(), + f153.into(), + f154.into(), + f155.into(), + f156.into(), + f157.into(), + f158.into(), + f159.into(), + f160.into(), + f161.into(), + f162.into(), + f163.into(), + f164.into(), + f165.into(), + f166.into(), + f167.into(), + f168.into(), + f169.into(), + f170.into(), + f171.into(), + f172.into(), + f173.into(), + f174.into(), + f175.into(), + f176.into(), + f177.into(), + f178.into(), + f179.into(), + f180.into(), + f181.into(), + f182.into(), + f183.into(), + f184.into(), + f185.into(), + f186.into(), + f187.into(), + f188.into(), + f189.into(), + f190.into(), + f191.into(), + f192.into(), + f193.into(), + f194.into(), + f195.into(), + f196.into(), + f197.into(), + f198.into(), + f199.into(), + f200.into(), + f201.into(), + f202.into(), + f203.into(), + f204.into(), + f205.into(), + f206.into(), + f207.into(), + f208.into(), + f209.into(), + f210.into(), + f211.into(), + f212.into(), + f213.into(), + f214.into(), + f215.into(), + f216.into(), + f217.into(), + f218.into(), + f219.into(), + f220.into(), + f221.into(), + f222.into(), + f223.into(), + f224.into(), + f225.into(), + f226.into(), + f227.into(), + f228.into(), + f229.into(), + f230.into(), + f231.into(), + f232.into(), + f233.into(), + f234.into(), + f235.into(), + f236.into(), + f237.into(), + f238.into(), + f239.into(), + f240.into(), + f241.into(), + f242.into(), + f243.into(), + f244.into(), + f245.into(), + f246.into(), + f247.into(), + f248.into(), + f249.into(), + f250.into(), + f251.into(), + f252.into(), + f253.into(), + f254.into(), + f255.into(), + f256.into(), + f257.into(), + f258.into(), + f259.into(), + f260.into(), + f261.into(), + f262.into(), + f263.into(), + f264.into(), + f265.into(), + f266.into(), + f267.into(), + f268.into(), + f269.into(), + f270.into(), + f271.into(), + f272.into(), + f273.into(), + f274.into(), + f275.into(), + f276.into(), + f277.into(), + f278.into(), + f279.into(), + f280.into(), + f281.into(), + f282.into(), + f283.into(), + f284.into(), + f285.into(), + f286.into(), + f287.into(), + f288.into(), + f289.into(), + f290.into(), + f291.into(), + f292.into(), + f293.into(), + f294.into(), + f295.into(), + f296.into(), + f297.into(), + f298.into(), + f299.into(), + f300.into(), + f301.into(), + f302.into(), + f303.into(), + f304.into(), + f305.into(), + f306.into(), + f307.into(), + f308.into(), + f309.into(), + f310.into(), + f311.into(), + f312.into(), + f313.into(), + f314.into(), + f315.into(), + f316.into(), + f317.into(), + f318.into(), + f319.into(), + f320.into(), + f321.into(), + f322.into(), + f323.into(), + f324.into(), + f325.into(), + f326.into(), + f327.into(), + f328.into(), + f329.into(), + f330.into(), + f331.into(), + f332.into(), + f333.into(), + f334.into(), + f335.into(), + f336.into(), + f337.into(), + f338.into(), + f339.into(), + f340.into(), + f341.into(), + f342.into(), + f343.into(), + f344.into(), + f345.into(), + f346.into(), + f347.into(), + f348.into(), + f349.into(), + f350.into(), + f351.into(), + f352.into(), + f353.into(), + f354.into(), + f355.into(), + f356.into(), + f357.into(), + f358.into(), + f359.into(), + f360.into(), + f361.into(), + f362.into(), + f363.into(), + f364.into(), + f365.into(), + f366.into(), + f367.into(), + f368.into(), + f369.into(), + f370.into(), + f371.into(), + f372.into(), + f373.into(), + f374.into(), + f375.into(), + f376.into(), + f377.into(), + f378.into(), + f379.into(), + f380.into(), + f381.into(), + f382.into(), + f383.into(), + f384.into(), + f385.into(), + f386.into(), + f387.into(), + f388.into(), + f389.into(), + f390.into(), + f391.into(), + f392.into(), + f393.into(), + f394.into(), + f395.into(), + f396.into(), + f397.into(), + f398.into(), + f399.into(), + f400.into(), + f401.into(), + f402.into(), + f403.into(), + f404.into(), + f405.into(), + f406.into(), + f407.into(), + f408.into(), + f409.into(), + f410.into(), + f411.into(), + f412.into(), + f413.into(), + f414.into(), + f415.into(), + f416.into(), + f417.into(), + f418.into(), + f419.into(), + f420.into(), + f421.into(), + f422.into(), + f423.into(), + f424.into(), + f425.into(), + f426.into(), + f427.into(), + f428.into(), + f429.into(), + f430.into(), + f431.into(), + f432.into(), + f433.into(), + f434.into(), + f435.into(), + f436.into(), + f437.into(), + f438.into(), + f439.into(), + f440.into(), + f441.into(), + f442.into(), + f443.into(), + f444.into(), + f445.into(), + f446.into(), + f447.into(), + f448.into(), + f449.into(), + f450.into(), + f451.into(), + f452.into(), + f453.into(), + f454.into(), + f455.into(), + f456.into(), + f457.into(), + f458.into(), + f459.into(), + f460.into(), + f461.into(), + f462.into(), + f463.into(), + f464.into(), + f465.into(), + f466.into(), + f467.into(), + f468.into(), + f469.into(), + f470.into(), + f471.into(), + f472.into(), + f473.into(), + f474.into(), + f475.into(), + f476.into(), + f477.into(), + f478.into(), + f479.into(), + f480.into(), + f481.into(), + f482.into(), + f483.into(), + f484.into(), + f485.into(), + f486.into(), + f487.into(), + f488.into(), + f489.into(), + f490.into(), + f491.into(), + f492.into(), + f493.into(), + f494.into(), + f495.into(), + f496.into(), + f497.into(), + f498.into(), + f499.into(), + f500.into(), + f501.into(), + f502.into(), + f503.into(), + f504.into(), + f505.into(), + f506.into(), + f507.into(), + f508.into(), + f509.into(), + f510.into(), + f511.into(), + ); + array![ + upcast(r0), upcast(r1), upcast(r2), upcast(r3), upcast(r4), upcast(r5), upcast(r6), + upcast(r7), upcast(r8), upcast(r9), upcast(r10), upcast(r11), upcast(r12), upcast(r13), + upcast(r14), upcast(r15), upcast(r16), upcast(r17), upcast(r18), upcast(r19), upcast(r20), + upcast(r21), upcast(r22), upcast(r23), upcast(r24), upcast(r25), upcast(r26), upcast(r27), + upcast(r28), upcast(r29), upcast(r30), upcast(r31), upcast(r32), upcast(r33), upcast(r34), + upcast(r35), upcast(r36), upcast(r37), upcast(r38), upcast(r39), upcast(r40), upcast(r41), + upcast(r42), upcast(r43), upcast(r44), upcast(r45), upcast(r46), upcast(r47), upcast(r48), + upcast(r49), upcast(r50), upcast(r51), upcast(r52), upcast(r53), upcast(r54), upcast(r55), + upcast(r56), upcast(r57), upcast(r58), upcast(r59), upcast(r60), upcast(r61), upcast(r62), + upcast(r63), upcast(r64), upcast(r65), upcast(r66), upcast(r67), upcast(r68), upcast(r69), + upcast(r70), upcast(r71), upcast(r72), upcast(r73), upcast(r74), upcast(r75), upcast(r76), + upcast(r77), upcast(r78), upcast(r79), upcast(r80), upcast(r81), upcast(r82), upcast(r83), + upcast(r84), upcast(r85), upcast(r86), upcast(r87), upcast(r88), upcast(r89), upcast(r90), + upcast(r91), upcast(r92), upcast(r93), upcast(r94), upcast(r95), upcast(r96), upcast(r97), + upcast(r98), upcast(r99), upcast(r100), upcast(r101), upcast(r102), upcast(r103), + upcast(r104), upcast(r105), upcast(r106), upcast(r107), upcast(r108), upcast(r109), + upcast(r110), upcast(r111), upcast(r112), upcast(r113), upcast(r114), upcast(r115), + upcast(r116), upcast(r117), upcast(r118), upcast(r119), upcast(r120), upcast(r121), + upcast(r122), upcast(r123), upcast(r124), upcast(r125), upcast(r126), upcast(r127), + upcast(r128), upcast(r129), upcast(r130), upcast(r131), upcast(r132), upcast(r133), + upcast(r134), upcast(r135), upcast(r136), upcast(r137), upcast(r138), upcast(r139), + upcast(r140), upcast(r141), upcast(r142), upcast(r143), upcast(r144), upcast(r145), + upcast(r146), upcast(r147), upcast(r148), upcast(r149), upcast(r150), upcast(r151), + upcast(r152), upcast(r153), upcast(r154), upcast(r155), upcast(r156), upcast(r157), + upcast(r158), upcast(r159), upcast(r160), upcast(r161), upcast(r162), upcast(r163), + upcast(r164), upcast(r165), upcast(r166), upcast(r167), upcast(r168), upcast(r169), + upcast(r170), upcast(r171), upcast(r172), upcast(r173), upcast(r174), upcast(r175), + upcast(r176), upcast(r177), upcast(r178), upcast(r179), upcast(r180), upcast(r181), + upcast(r182), upcast(r183), upcast(r184), upcast(r185), upcast(r186), upcast(r187), + upcast(r188), upcast(r189), upcast(r190), upcast(r191), upcast(r192), upcast(r193), + upcast(r194), upcast(r195), upcast(r196), upcast(r197), upcast(r198), upcast(r199), + upcast(r200), upcast(r201), upcast(r202), upcast(r203), upcast(r204), upcast(r205), + upcast(r206), upcast(r207), upcast(r208), upcast(r209), upcast(r210), upcast(r211), + upcast(r212), upcast(r213), upcast(r214), upcast(r215), upcast(r216), upcast(r217), + upcast(r218), upcast(r219), upcast(r220), upcast(r221), upcast(r222), upcast(r223), + upcast(r224), upcast(r225), upcast(r226), upcast(r227), upcast(r228), upcast(r229), + upcast(r230), upcast(r231), upcast(r232), upcast(r233), upcast(r234), upcast(r235), + upcast(r236), upcast(r237), upcast(r238), upcast(r239), upcast(r240), upcast(r241), + upcast(r242), upcast(r243), upcast(r244), upcast(r245), upcast(r246), upcast(r247), + upcast(r248), upcast(r249), upcast(r250), upcast(r251), upcast(r252), upcast(r253), + upcast(r254), upcast(r255), upcast(r256), upcast(r257), upcast(r258), upcast(r259), + upcast(r260), upcast(r261), upcast(r262), upcast(r263), upcast(r264), upcast(r265), + upcast(r266), upcast(r267), upcast(r268), upcast(r269), upcast(r270), upcast(r271), + upcast(r272), upcast(r273), upcast(r274), upcast(r275), upcast(r276), upcast(r277), + upcast(r278), upcast(r279), upcast(r280), upcast(r281), upcast(r282), upcast(r283), + upcast(r284), upcast(r285), upcast(r286), upcast(r287), upcast(r288), upcast(r289), + upcast(r290), upcast(r291), upcast(r292), upcast(r293), upcast(r294), upcast(r295), + upcast(r296), upcast(r297), upcast(r298), upcast(r299), upcast(r300), upcast(r301), + upcast(r302), upcast(r303), upcast(r304), upcast(r305), upcast(r306), upcast(r307), + upcast(r308), upcast(r309), upcast(r310), upcast(r311), upcast(r312), upcast(r313), + upcast(r314), upcast(r315), upcast(r316), upcast(r317), upcast(r318), upcast(r319), + upcast(r320), upcast(r321), upcast(r322), upcast(r323), upcast(r324), upcast(r325), + upcast(r326), upcast(r327), upcast(r328), upcast(r329), upcast(r330), upcast(r331), + upcast(r332), upcast(r333), upcast(r334), upcast(r335), upcast(r336), upcast(r337), + upcast(r338), upcast(r339), upcast(r340), upcast(r341), upcast(r342), upcast(r343), + upcast(r344), upcast(r345), upcast(r346), upcast(r347), upcast(r348), upcast(r349), + upcast(r350), upcast(r351), upcast(r352), upcast(r353), upcast(r354), upcast(r355), + upcast(r356), upcast(r357), upcast(r358), upcast(r359), upcast(r360), upcast(r361), + upcast(r362), upcast(r363), upcast(r364), upcast(r365), upcast(r366), upcast(r367), + upcast(r368), upcast(r369), upcast(r370), upcast(r371), upcast(r372), upcast(r373), + upcast(r374), upcast(r375), upcast(r376), upcast(r377), upcast(r378), upcast(r379), + upcast(r380), upcast(r381), upcast(r382), upcast(r383), upcast(r384), upcast(r385), + upcast(r386), upcast(r387), upcast(r388), upcast(r389), upcast(r390), upcast(r391), + upcast(r392), upcast(r393), upcast(r394), upcast(r395), upcast(r396), upcast(r397), + upcast(r398), upcast(r399), upcast(r400), upcast(r401), upcast(r402), upcast(r403), + upcast(r404), upcast(r405), upcast(r406), upcast(r407), upcast(r408), upcast(r409), + upcast(r410), upcast(r411), upcast(r412), upcast(r413), upcast(r414), upcast(r415), + upcast(r416), upcast(r417), upcast(r418), upcast(r419), upcast(r420), upcast(r421), + upcast(r422), upcast(r423), upcast(r424), upcast(r425), upcast(r426), upcast(r427), + upcast(r428), upcast(r429), upcast(r430), upcast(r431), upcast(r432), upcast(r433), + upcast(r434), upcast(r435), upcast(r436), upcast(r437), upcast(r438), upcast(r439), + upcast(r440), upcast(r441), upcast(r442), upcast(r443), upcast(r444), upcast(r445), + upcast(r446), upcast(r447), upcast(r448), upcast(r449), upcast(r450), upcast(r451), + upcast(r452), upcast(r453), upcast(r454), upcast(r455), upcast(r456), upcast(r457), + upcast(r458), upcast(r459), upcast(r460), upcast(r461), upcast(r462), upcast(r463), + upcast(r464), upcast(r465), upcast(r466), upcast(r467), upcast(r468), upcast(r469), + upcast(r470), upcast(r471), upcast(r472), upcast(r473), upcast(r474), upcast(r475), + upcast(r476), upcast(r477), upcast(r478), upcast(r479), upcast(r480), upcast(r481), + upcast(r482), upcast(r483), upcast(r484), upcast(r485), upcast(r486), upcast(r487), + upcast(r488), upcast(r489), upcast(r490), upcast(r491), upcast(r492), upcast(r493), + upcast(r494), upcast(r495), upcast(r496), upcast(r497), upcast(r498), upcast(r499), + upcast(r500), upcast(r501), upcast(r502), upcast(r503), upcast(r504), upcast(r505), + upcast(r506), upcast(r507), upcast(r508), upcast(r509), upcast(r510), upcast(r511), + ] +} diff --git a/packages/account/src/falcon_512/ntt/roots_felt.cairo b/packages/account/src/falcon_512/ntt/roots_felt.cairo new file mode 100644 index 000000000..6c685cf2c --- /dev/null +++ b/packages/account/src/falcon_512/ntt/roots_felt.cairo @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (account/src/falcon_512/ntt/roots_felt.cairo) + +// Generated by scripts/falcon_512/generate_ntt.py; do not edit by hand. +// Forward merge roots derived recursively from q = 12289 and sqrt(-1) = 1479, +// choosing the smaller representative of each modular square-root pair. +// Regenerate with: python3 scripts/falcon_512/generate_ntt.py --write + +//! Forward NTT root tables as felts (generated). + +const phi4_roots_zq_felt: [felt252; 1] = [1479]; +const phi8_roots_zq_felt: [felt252; 2] = [4043, 5146]; +const phi16_roots_zq_felt: [felt252; 4] = [5736, 4134, 722, 1305]; +const phi32_roots_zq_felt: [felt252; 8] = [1646, 1212, 5860, 3195, 2545, 3621, 3504, 3542]; +const phi64_roots_zq_felt: [felt252; 16] = [ + 4591, 5728, 5023, 5828, 4978, 1351, 3328, 5777, 2975, 563, 3006, 2744, 949, 2625, 4821, 2639, +]; +const phi128_roots_zq_felt: [felt252; 32] = [ + 1000, 4320, 3091, 81, 2963, 4896, 3051, 2366, 1853, 140, 4611, 726, 4255, 1177, 2768, 1635, + 3712, 3135, 2747, 4846, 3553, 4805, 2294, 1062, 1326, 5086, 3014, 3201, 1170, 2319, 955, 790, +]; +const phi256_roots_zq_felt: [felt252; 64] = [ + 544, 5791, 339, 2468, 2842, 480, 9, 1022, 4278, 1673, 4989, 5331, 3584, 4177, 1381, 2525, 2396, + 4452, 3296, 3949, 130, 4354, 5374, 2837, 5767, 827, 3748, 953, 5067, 2197, 118, 2476, 2548, + 4231, 355, 3382, 3707, 1759, 3694, 5179, 5542, 145, 3637, 3459, 5911, 4890, 3932, 2731, 2089, + 5092, 2881, 3284, 729, 3241, 3289, 2013, 5755, 4632, 1260, 4388, 334, 2426, 1696, 1428, +]; +const phi512_roots_zq_felt: [felt252; 128] = [ + 1663, 1777, 1426, 4654, 5291, 2704, 4938, 3636, 3915, 2166, 113, 4919, 3, 4437, 160, 3149, 4057, + 3271, 1689, 3364, 4372, 2174, 4414, 2847, 2645, 4053, 2305, 5042, 5195, 2780, 1484, 4895, 3016, + 243, 3000, 671, 3136, 5191, 2399, 3400, 2178, 1544, 420, 5559, 476, 3531, 3985, 4905, 5332, + 3510, 2370, 2865, 2969, 3978, 2686, 3247, 4048, 2249, 1153, 2884, 5407, 3186, 1630, 2126, 2187, + 2566, 2422, 6039, 2987, 6022, 2437, 3646, 875, 3780, 1607, 4976, 5011, 1002, 4284, 5088, 3248, + 1207, 1168, 5277, 1065, 2143, 404, 4645, 1912, 1378, 435, 4337, 2381, 5444, 4096, 493, 545, + 5019, 3704, 2678, 1537, 242, 4714, 4143, 27, 3066, 3763, 1440, 5084, 1632, 1017, 4885, 3778, + 3833, 390, 773, 2401, 442, 5101, 1067, 2912, 5698, 354, 4861, 2859, 1045, 5012, 2481, +]; +const phi1024_roots_zq_felt: [felt252; 256] = [ + 3957, 2839, 2127, 151, 431, 1579, 5906, 2505, 1323, 2766, 52, 3174, 6055, 3336, 677, 5874, 4169, + 3127, 5241, 2920, 1010, 5468, 787, 3482, 1321, 192, 4912, 2049, 4698, 5057, 4780, 3445, 1956, + 5009, 6008, 885, 3532, 1003, 58, 241, 975, 4212, 2844, 3438, 1105, 142, 5681, 3477, 2302, 605, + 4213, 504, 5886, 4782, 5594, 3029, 421, 4080, 6068, 3602, 6077, 4624, 3263, 3600, 4948, 6137, + 400, 1728, 5862, 6136, 5415, 3643, 56, 3199, 5206, 5529, 3565, 654, 1987, 1702, 3988, 468, 316, + 382, 3710, 6093, 5446, 5339, 973, 1254, 1359, 5435, 2033, 3998, 3879, 1922, 3860, 5445, 4536, + 1050, 3818, 6118, 1190, 2683, 3789, 147, 5456, 4449, 4749, 5537, 4789, 4467, 1018, 5925, 1041, + 3514, 2344, 1278, 5574, 1973, 4324, 4916, 4075, 5315, 5079, 3262, 522, 2169, 1200, 5184, 2555, + 6122, 5297, 6119, 3956, 1360, 1962, 1594, 5961, 5106, 4298, 3329, 168, 2692, 4049, 3728, 1159, + 5990, 948, 1146, 1404, 325, 5766, 652, 295, 6099, 2919, 3762, 4016, 4077, 6065, 835, 3570, 4240, + 4046, 709, 3150, 1319, 1058, 4079, 922, 441, 4322, 1958, 2078, 1112, 3834, 5257, 4433, 5919, + 5486, 3054, 1747, 3123, 2948, 2503, 5782, 1566, 64, 3656, 2459, 683, 1293, 4737, 5429, 4774, + 5908, 453, 418, 3772, 3991, 3969, 2767, 156, 2281, 5876, 5333, 2031, 3963, 576, 2447, 6142, + 2051, 1954, 1805, 2882, 3529, 3434, 2908, 218, 3030, 4115, 1843, 2361, 3202, 4493, 2057, 5369, + 1512, 350, 1815, 5383, 49, 1263, 5915, 1483, 1489, 2500, 5942, 1583, 1693, 3009, 174, 723, 2738, + 5868, 5735, 2655, 3315, 426, 4754, 1858, 1975, 3757, 2925, 347, +]; + +/// Forward merge roots for a power-of-two transform degree from 2 through 512. +pub fn get_even_roots_felt(degree: u32) -> Span { + if degree == 2 { + phi4_roots_zq_felt.span() + } else if degree == 4 { + phi8_roots_zq_felt.span() + } else if degree == 8 { + phi16_roots_zq_felt.span() + } else if degree == 16 { + phi32_roots_zq_felt.span() + } else if degree == 32 { + phi64_roots_zq_felt.span() + } else if degree == 64 { + phi128_roots_zq_felt.span() + } else if degree == 128 { + phi256_roots_zq_felt.span() + } else if degree == 256 { + phi512_roots_zq_felt.span() + } else if degree == 512 { + phi1024_roots_zq_felt.span() + } else { + panic!("no root table for degree") + } +} diff --git a/packages/account/src/falcon_512/ntt/roots_scaled.cairo b/packages/account/src/falcon_512/ntt/roots_scaled.cairo new file mode 100644 index 000000000..cf4fa84c1 --- /dev/null +++ b/packages/account/src/falcon_512/ntt/roots_scaled.cairo @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (account/src/falcon_512/ntt/roots_scaled.cairo) + +// Generated by scripts/falcon_512/generate_ntt.py; do not edit by hand. +// Inverse roots derived from the deterministic forward roots and prescaled by +// I2 = 2^-1 mod q for the inverse transform's split butterflies. +// Regenerate with: python3 scripts/falcon_512/generate_ntt.py --write + +//! I2-scaled inverse NTT root tables (generated). + +const phi4_roots_zq_inv_scaled: [felt252; 1] = [5405]; +const phi8_roots_zq_inv_scaled: [felt252; 2] = [2573, 8166]; +const phi16_roots_zq_inv_scaled: [felt252; 4] = [11928, 5492, 9421, 10222]; +const phi32_roots_zq_inv_scaled: [felt252; 8] = [7955, 7417, 10518, 1752, 606, 823, 7742, 9359]; +const phi64_roots_zq_inv_scaled: [felt252; 16] = [ + 10786, 1372, 7632, 6426, 7464, 8555, 5670, 4832, 8656, 2914, 3849, 2864, 10625, 3256, 6820, + 2489, +]; +const phi128_roots_zq_inv_scaled: [felt252; 32] = [ + 8547, 4368, 1147, 11758, 1856, 4577, 4771, 9866, 5667, 11894, 11704, 7304, 2543, 11626, 4544, + 1507, 7626, 9841, 4619, 11106, 10129, 500, 7690, 6104, 5556, 8272, 6962, 10905, 3839, 363, 5218, + 12219, +]; +const phi256_roots_zq_inv_scaled: [felt252; 64] = [ + 4326, 4415, 6072, 9518, 3189, 2445, 7510, 1966, 1274, 4029, 1691, 5967, 5265, 4291, 8734, 10442, + 11076, 12122, 714, 11441, 9973, 3267, 630, 10095, 4704, 10647, 9743, 5100, 7151, 7789, 5780, + 4524, 2139, 5308, 3479, 8639, 4056, 10497, 4882, 6835, 11055, 5975, 12017, 3249, 10868, 240, + 511, 6149, 5668, 10415, 3261, 5731, 12230, 11051, 7243, 8678, 10112, 12224, 2687, 4726, 10063, + 11091, 4170, 1648, +]; +const phi512_roots_zq_inv_scaled: [felt252; 128] = [ + 5073, 5612, 3822, 12087, 3506, 11705, 6748, 10665, 11600, 11333, 5927, 3976, 10241, 5898, 7335, + 2722, 7238, 11006, 9164, 1211, 7363, 10466, 3011, 7638, 2488, 6948, 10399, 5707, 2142, 2544, + 11788, 8650, 3714, 12112, 2849, 1456, 2506, 4904, 5622, 7574, 6531, 12094, 8061, 1889, 4944, + 12068, 6678, 8695, 12168, 5376, 4073, 9932, 10950, 1852, 8654, 5872, 6653, 3702, 9747, 816, + 1533, 6131, 720, 4263, 8173, 4509, 1682, 6989, 7568, 2207, 2186, 11202, 9768, 4992, 8171, 7467, + 8592, 11547, 8742, 1390, 10471, 2469, 10937, 3499, 5256, 5313, 9962, 11576, 11206, 4187, 6088, + 3685, 80, 7719, 6143, 3926, 4521, 1343, 1989, 4660, 10534, 9623, 4712, 11104, 10696, 8848, + 11226, 815, 5568, 1442, 2024, 5020, 8924, 210, 11517, 1089, 12051, 4379, 8597, 8137, 6480, 1500, + 6023, 10781, 1700, 4945, 1568, 3549, +]; +const phi1024_roots_zq_inv_scaled: [felt252; 256] = [ + 5924, 461, 4105, 529, 556, 11250, 11310, 2161, 5485, 10714, 6499, 10266, 10504, 2120, 6562, + 3112, 3185, 3928, 3516, 1917, 1527, 9546, 7706, 5271, 10461, 12257, 5803, 7374, 1474, 7396, + 9398, 11506, 600, 9697, 9228, 4867, 10311, 680, 8793, 3085, 2149, 4480, 1346, 84, 9125, 2553, + 11308, 11492, 702, 6307, 11815, 573, 9294, 5565, 10425, 4120, 4685, 10408, 2008, 4106, 3095, + 6292, 9406, 326, 4817, 3277, 2934, 10920, 87, 5783, 6991, 4640, 5157, 8023, 5971, 7607, 11360, + 9912, 7802, 213, 5237, 3453, 12114, 756, 7173, 3460, 1601, 3898, 5513, 6169, 6886, 9102, 9318, + 5353, 6889, 1250, 12211, 7528, 4160, 8140, 5129, 3478, 9351, 7285, 1886, 209, 2954, 6371, 3430, + 9902, 3776, 6791, 1515, 4087, 7325, 5223, 1717, 4380, 1454, 12180, 4921, 9218, 288, 4163, 7047, + 10848, 977, 7170, 978, 3640, 5702, 9285, 29, 6024, 10523, 6646, 3304, 4406, 6697, 71, 6632, + 10183, 1719, 1422, 4630, 9492, 9898, 9346, 4038, 252, 1151, 6447, 4513, 1800, 2312, 3106, 5934, + 10249, 3034, 10488, 9352, 6483, 3117, 1668, 10702, 26, 10906, 5483, 6220, 5081, 7564, 4166, + 7397, 9336, 5355, 6360, 1460, 3524, 4581, 4060, 9555, 505, 10548, 6538, 2349, 8673, 9899, 4422, + 12193, 5484, 7169, 9833, 8378, 3750, 3770, 3376, 2728, 8369, 6218, 8039, 525, 10021, 8867, + 10359, 7486, 11694, 9230, 10380, 3487, 8182, 10127, 9831, 7229, 261, 8684, 10658, 11650, 1172, + 2787, 5158, 509, 3182, 10532, 6665, 2723, 3475, 1855, 3098, 191, 12131, 10295, 12055, 627, 5658, + 8862, 6824, 8084, 961, 5128, 10290, 8852, 4323, 2931, 9221, 11425, 200, 3076, 9815, 7138, 851, + 11962, 4362, 12261, 7744, 8909, 9686, +]; + +/// I2-prescaled inverse roots for a power-of-two transform degree from 2 through 512. +pub fn get_scaled_inv_roots(degree: u32) -> Span { + if degree == 2 { + phi4_roots_zq_inv_scaled.span() + } else if degree == 4 { + phi8_roots_zq_inv_scaled.span() + } else if degree == 8 { + phi16_roots_zq_inv_scaled.span() + } else if degree == 16 { + phi32_roots_zq_inv_scaled.span() + } else if degree == 32 { + phi64_roots_zq_inv_scaled.span() + } else if degree == 64 { + phi128_roots_zq_inv_scaled.span() + } else if degree == 128 { + phi256_roots_zq_inv_scaled.span() + } else if degree == 256 { + phi512_roots_zq_inv_scaled.span() + } else if degree == 512 { + phi1024_roots_zq_inv_scaled.span() + } else { + panic!("no root table for degree") + } +} diff --git a/packages/account/src/falcon_512/packing.cairo b/packages/account/src/falcon_512/packing.cairo new file mode 100644 index 000000000..6f8411df8 --- /dev/null +++ b/packages/account/src/falcon_512/packing.cairo @@ -0,0 +1,341 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (account/src/falcon_512/packing.cairo) + +//! Base-`Q` packing of 512 `Z_q` coefficients into 29 `felt252` slots. +//! +//! Each full slot carries two `u128` halves; each half Horner-packs 9 coefficients in base +//! `Q = 12289` (`Q^9 < 2^128`): `half = c0 + Q*(c1 + Q*(c2 + ...))`. 28 full slots +//! hold 18 coefficients each; the last slot holds the remaining 8 in its low half. +//! +//! Unpacking accepts exactly canonical encodings: each full half is downcast to `[0, Q^9)`, the +//! final low half to `[0, Q^8)`, and the final high half must be zero. The accepted felt vectors +//! are therefore in bijection with coefficient vectors in `[0, Q)^512`. + +use openzeppelin_corelib_imports::bounded_int::{ + BoundedInt, DivRemHelper, UnitInt, bounded_int_div_rem, downcast, upcast, +}; +#[cfg(test)] +use super::zq::Q; + +/// Coefficients per full `felt252` slot (two `u128` halves of 9). +#[cfg(test)] +pub const VALS_PER_FELT: u32 = 18; +/// `felt252` slots for 512 coefficients: 28 full slots + 1 slot with 8. +pub const PACKED_SLOTS: u32 = 29; +/// Coefficients in the last slot: 512 - 28*18. +#[cfg(test)] +const LAST_SLOT_VALS: u32 = 8; + +#[cfg(test)] +const TWO_POW_128: felt252 = 0x100000000000000000000000000000000; + +type PackingZq = BoundedInt<0, 12288>; +type PackingQ = UnitInt<12289>; +type Acc1 = BoundedInt<0, 151019520>; +type Acc2 = BoundedInt<0, 1855878893568>; +type Acc3 = BoundedInt<0, 22806895723069440>; +type Acc4 = BoundedInt<0, 280273941540800360448>; +type Acc5 = BoundedInt<0, 3444286467594895629557760>; +type Acc6 = BoundedInt<0, 42326836400273672391635324928>; +type Acc7 = BoundedInt<0, 520154492522963160020806508052480>; +type Acc8 = BoundedInt<0, 6392178558614694273495691177456939008>; + +const PACKING_Q_NZ: NonZero = 12289; + +impl PackingDivRemAcc1Impl of DivRemHelper { + type DivT = PackingZq; + type RemT = PackingZq; +} + +impl PackingDivRemAcc2Impl of DivRemHelper { + type DivT = Acc1; + type RemT = PackingZq; +} + +impl PackingDivRemAcc3Impl of DivRemHelper { + type DivT = Acc2; + type RemT = PackingZq; +} + +impl PackingDivRemAcc4Impl of DivRemHelper { + type DivT = Acc3; + type RemT = PackingZq; +} + +impl PackingDivRemAcc5Impl of DivRemHelper { + type DivT = Acc4; + type RemT = PackingZq; +} + +impl PackingDivRemAcc6Impl of DivRemHelper { + type DivT = Acc5; + type RemT = PackingZq; +} + +impl PackingDivRemAcc7Impl of DivRemHelper { + type DivT = Acc6; + type RemT = PackingZq; +} + +impl PackingDivRemAcc8Impl of DivRemHelper { + type DivT = Acc7; + type RemT = PackingZq; +} + +/// Unpacks 29 packed felts into 512 coefficients in `[0, Q)`, as felts (each is a +/// base-Q digit, so the range holds by construction). +/// Returns `None` on wrong length or any non-canonical slot encoding. +#[cfg(test)] +pub fn unpack_512(packed: Span) -> Option> { + let coeffs_u16 = match unpack_512_u16(packed) { + Some(v) => v, + None => { return None; }, + }; + let mut coeffs_u16 = coeffs_u16.span(); + let mut coeffs: Array = array![]; + while let Some(coeff) = coeffs_u16.pop_front() { + coeffs.append((*coeff).into()); + } + Some(coeffs) +} + +/// Unpacks the canonical 29-slot encoding directly into the verifier's `u16` form. +/// Returns `None` on wrong length or any non-canonical slot encoding. +pub(crate) fn unpack_512_u16(packed: Span) -> Option> { + if packed.len() != PACKED_SLOTS { + return None; + } + let mut coeffs: Array = array![]; + let mut full_slots = packed.slice(0, PACKED_SLOTS - 1); + while let Some(chunk) = full_slots.multi_pop_front::<7>() { + let [f0, f1, f2, f3, f4, f5, f6] = (*chunk).unbox(); + if !unpack_full_slot_u16(f0, ref coeffs) + || !unpack_full_slot_u16(f1, ref coeffs) + || !unpack_full_slot_u16(f2, ref coeffs) + || !unpack_full_slot_u16(f3, ref coeffs) + || !unpack_full_slot_u16(f4, ref coeffs) + || !unpack_full_slot_u16(f5, ref coeffs) + || !unpack_full_slot_u16(f6, ref coeffs) { + return None; + } + } + let last: u256 = (*packed.at(PACKED_SLOTS - 1)).into(); + if last.high != 0 || !unpack_half8_u16(last.low, ref coeffs) { + return None; + } + Some(coeffs) +} + +#[inline(always)] +fn unpack_full_slot_u16(felt: felt252, ref coeffs: Array) -> bool { + let value: u256 = felt.into(); + unpack_half9_u16(value.low, ref coeffs) && unpack_half9_u16(value.high, ref coeffs) +} + +/// Extracts nine base-Q digits from a `u128` half. Values below `Q^9` are canonical; +/// after eight divisions the remaining quotient is the ninth digit. +#[inline(always)] +fn unpack_half9_u16(value: u128, ref coeffs: Array) -> bool { + let value: Acc8 = match downcast(value) { + Some(v) => v, + None => { return false; }, + }; + let (rest, d0) = bounded_int_div_rem(value, PACKING_Q_NZ); + let (rest, d1) = bounded_int_div_rem(rest, PACKING_Q_NZ); + let (rest, d2) = bounded_int_div_rem(rest, PACKING_Q_NZ); + let (rest, d3) = bounded_int_div_rem(rest, PACKING_Q_NZ); + let (rest, d4) = bounded_int_div_rem(rest, PACKING_Q_NZ); + let (rest, d5) = bounded_int_div_rem(rest, PACKING_Q_NZ); + let (rest, d6) = bounded_int_div_rem(rest, PACKING_Q_NZ); + let (rest, d7) = bounded_int_div_rem(rest, PACKING_Q_NZ); + coeffs.append(upcast(d0)); + coeffs.append(upcast(d1)); + coeffs.append(upcast(d2)); + coeffs.append(upcast(d3)); + coeffs.append(upcast(d4)); + coeffs.append(upcast(d5)); + coeffs.append(upcast(d6)); + coeffs.append(upcast(d7)); + coeffs.append(upcast(rest)); + true +} + +/// Extracts the final slot's eight digits after checking the value is below `Q^8`. +#[inline(always)] +fn unpack_half8_u16(value: u128, ref coeffs: Array) -> bool { + let value: Acc7 = match downcast(value) { + Some(v) => v, + None => { return false; }, + }; + let (rest, d0) = bounded_int_div_rem(value, PACKING_Q_NZ); + let (rest, d1) = bounded_int_div_rem(rest, PACKING_Q_NZ); + let (rest, d2) = bounded_int_div_rem(rest, PACKING_Q_NZ); + let (rest, d3) = bounded_int_div_rem(rest, PACKING_Q_NZ); + let (rest, d4) = bounded_int_div_rem(rest, PACKING_Q_NZ); + let (rest, d5) = bounded_int_div_rem(rest, PACKING_Q_NZ); + let (rest, d6) = bounded_int_div_rem(rest, PACKING_Q_NZ); + coeffs.append(upcast(d0)); + coeffs.append(upcast(d1)); + coeffs.append(upcast(d2)); + coeffs.append(upcast(d3)); + coeffs.append(upcast(d4)); + coeffs.append(upcast(d5)); + coeffs.append(upcast(d6)); + coeffs.append(upcast(rest)); + true +} + +/// Packs 512 coefficients into 29 felts. Inverse of [`unpack_512`]; used by tests. +/// Panics unless `coeffs` contains exactly 512 coefficients in `[0, Q)`. +#[cfg(test)] +pub fn pack_512(coeffs: Span) -> Array { + assert(coeffs.len() == 512, 'pack: need 512 coeffs'); + let mut packed: Array = array![]; + let mut slot: u32 = 0; + while slot != PACKED_SLOTS - 1 { + let low = pack_half(coeffs.slice(slot * VALS_PER_FELT, 9)); + let high = pack_half(coeffs.slice(slot * VALS_PER_FELT + 9, 9)); + packed.append(low.into() + high.into() * TWO_POW_128); + slot += 1; + } + packed.append(pack_half(coeffs.slice(504, LAST_SLOT_VALS)).into()); + packed +} + +/// Horner-encodes up to 9 coefficients into a `u128`: c0 + Q*(c1 + Q*(c2 + ...)). +#[cfg(test)] +fn pack_half(coeffs: Span) -> u128 { + let mut acc: u128 = 0; + let mut i = coeffs.len(); + while i != 0 { + i -= 1; + let c = *coeffs.at(i); + assert(c < Q, 'pack: coeff >= Q'); + acc = acc * Q.into() + c.into(); + } + acc +} + +#[cfg(test)] +mod tests { + use super::{PACKED_SLOTS, pack_512, unpack_512, unpack_512_u16}; + + /// Q^9: the smallest non-canonical low-half value (all 9 digits zero, residue 1). + const Q_POW_9: felt252 = 6392178558614694273495691177456939009; + /// Q^8: the smallest non-canonical last-slot value. + const Q_POW_8: felt252 = 520154492522963160020806508052481; + const TWO_POW_128: felt252 = 0x100000000000000000000000000000000; + + fn pseudorandom_coeffs() -> Array { + let mut f: Array = array![]; + let mut state: u64 = 7; + for _ in 0_u32..512 { + state = (state * 1664525 + 1013904223) % 0x100000000; + f.append((state % 12289).try_into().unwrap()); + } + f + } + + fn as_felts(mut vals: Span) -> Array { + let mut out: Array = array![]; + while let Some(v) = vals.pop_front() { + out.append((*v).into()); + } + out + } + + #[test] + fn test_pack_unpack_roundtrip() { + let coeffs = pseudorandom_coeffs(); + let packed = pack_512(coeffs.span()); + assert_eq!(packed.len(), PACKED_SLOTS); + let unpacked = unpack_512(packed.span()).unwrap(); + assert_eq!(unpacked.span(), as_felts(coeffs.span()).span()); + assert_eq!(unpack_512_u16(packed.span()).unwrap().span(), coeffs.span()); + } + + #[test] + fn test_unpack_all_zero_and_max() { + let mut zeros: Array = array![]; + let mut maxed: Array = array![]; + for _ in 0_u32..512 { + zeros.append(0); + maxed.append(12288); + } + let z = unpack_512(pack_512(zeros.span()).span()).unwrap(); + assert_eq!(z.span(), as_felts(zeros.span()).span()); + let m = unpack_512(pack_512(maxed.span()).span()).unwrap(); + assert_eq!(m.span(), as_felts(maxed.span()).span()); + } + + #[test] + fn test_unpack_rejects_wrong_length() { + let coeffs = pseudorandom_coeffs(); + let packed = pack_512(coeffs.span()); + assert!(unpack_512(packed.span().slice(0, 28)).is_none()); + assert!(unpack_512(array![].span()).is_none()); + let mut too_long = packed; + too_long.append(0); + assert!(unpack_512(too_long.span()).is_none()); + } + + #[test] + fn test_unpack_rejects_noncanonical_slot_in_each_unrolled_position() { + let packed = pack_512(pseudorandom_coeffs().span()); + let mut bad_index = 0; + while bad_index != 7 { + let mut tampered: Array = array![]; + let mut index = 0; + while index != packed.len() { + if index == bad_index { + tampered.append(Q_POW_9); + } else { + tampered.append(*packed.at(index)); + } + index += 1; + } + assert!(unpack_512(tampered.span()).is_none()); + bad_index += 1; + } + } + + #[test] + fn test_unpack_rejects_noncanonical_half() { + // Q^9 in a low half: nine zero digits with a nonzero residue. + let mut packed = pack_512(pseudorandom_coeffs().span()); + let mut tampered: Array = array![Q_POW_9]; + let mut rest = packed.span().slice(1, 28); + while let Some(f) = rest.pop_front() { + tampered.append(*f); + } + assert!(unpack_512(tampered.span()).is_none()); + // Same overflow in a high half. + let mut tampered2: Array = array![Q_POW_9 * TWO_POW_128]; + let mut rest2 = packed.span().slice(1, 28); + while let Some(f) = rest2.pop_front() { + tampered2.append(*f); + } + assert!(unpack_512(tampered2.span()).is_none()); + } + + #[test] + fn test_unpack_rejects_noncanonical_last_slot() { + let packed = pack_512(pseudorandom_coeffs().span()); + // Non-zero high half in the last slot. + let mut tampered: Array = array![]; + let mut head = packed.span().slice(0, 28); + while let Some(f) = head.pop_front() { + tampered.append(*f); + } + tampered.append(TWO_POW_128); + assert!(unpack_512(tampered.span()).is_none()); + // Q^8 in the last slot: eight zero digits with a nonzero residue. + let mut tampered2: Array = array![]; + let mut head2 = packed.span().slice(0, 28); + while let Some(f) = head2.pop_front() { + tampered2.append(*f); + } + tampered2.append(Q_POW_8); + assert!(unpack_512(tampered2.span()).is_none()); + } +} diff --git a/packages/account/src/falcon_512/verifier.cairo b/packages/account/src/falcon_512/verifier.cairo new file mode 100644 index 000000000..4b4035742 --- /dev/null +++ b/packages/account/src/falcon_512/verifier.cairo @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (account/src/falcon_512/verifier.cairo) + +/// Verification strategy used by `Falcon512AccountComponent`. +pub trait Falcon512SignatureVerifier { + /// Returns whether `signature` authenticates `message_hash` under `public_key`. + fn verify(message_hash: felt252, public_key: Span, signature: Span) -> bool; + + /// Returns whether the packed public key has the required canonical encoding. + fn is_valid_public_key(public_key: Span) -> bool; +} diff --git a/packages/account/src/falcon_512/verifier_impls.cairo b/packages/account/src/falcon_512/verifier_impls.cairo new file mode 100644 index 000000000..493ace9b9 --- /dev/null +++ b/packages/account/src/falcon_512/verifier_impls.cairo @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (account/src/falcon_512/verifier_impls.cairo) + +use super::hashing::hash_to_point::hash_to_point_shake_512; +use super::verifier::Falcon512SignatureVerifier; +use super::{falcon, packing}; + +/// Number of felts containing the Falcon salt. +const SALT_FELTS: u32 = 2; + +/// Number of felts in a packed Falcon-512 public key. +pub(crate) const PUBLIC_KEY_FELTS: u32 = packing::PACKED_SLOTS; + +/// Number of felts in a direct Falcon-512 signature. +pub(crate) const DIRECT_SIGNATURE_FELTS: u32 = PUBLIC_KEY_FELTS + SALT_FELTS; + +/// Number of felts in a Falcon-512 signature carrying a product hint. +pub(crate) const SIGNATURE_FELTS: u32 = DIRECT_SIGNATURE_FELTS + PUBLIC_KEY_FELTS; + +/// Decodes the public key, signature polynomial, and salt shared by both layouts. +fn decode_common( + public_key: Span, signature: Span, +) -> Option<(Array, Array, felt252, felt252)> { + let h_ntt = match packing::unpack_512_u16(public_key) { + Some(value) => value, + None => { return None; }, + }; + let s1 = match packing::unpack_512_u16(signature.slice(0, PUBLIC_KEY_FELTS)) { + Some(value) => value, + None => { return None; }, + }; + let salt_a = *signature.at(PUBLIC_KEY_FELTS); + let salt_b = *signature.at(PUBLIC_KEY_FELTS + 1); + Some((h_ntt, s1, salt_a, salt_b)) +} + +/// Verifier for the 60-felt SHAKE-256 signature carrying a polynomial-product hint. +pub impl Falcon512ShakeVerifier of Falcon512SignatureVerifier { + fn verify(message_hash: felt252, public_key: Span, signature: Span) -> bool { + if public_key.len() != PUBLIC_KEY_FELTS || signature.len() != SIGNATURE_FELTS { + return false; + } + let (h_ntt, s1, salt_a, salt_b) = match decode_common(public_key, signature) { + Some(value) => value, + None => { return false; }, + }; + let mul_hint = + match packing::unpack_512_u16( + signature.slice(DIRECT_SIGNATURE_FELTS, PUBLIC_KEY_FELTS), + ) { + Some(value) => value, + None => { return false; }, + }; + let message_point = match hash_to_point_shake_512(message_hash, salt_a, salt_b) { + Some(value) => value, + None => { return false; }, + }; + falcon::verify_512_with_hint_u16( + s1.span(), h_ntt.span(), mul_hint.span(), message_point.span(), + ) + } + + fn is_valid_public_key(public_key: Span) -> bool { + if public_key.len() != PUBLIC_KEY_FELTS { + return false; + } + match packing::unpack_512_u16(public_key) { + Some(_) => true, + None => false, + } + } +} + +/// Verifier for the 31-felt SHAKE-256 signature that recomputes the product on-chain. +pub impl Falcon512ShakeDirectVerifier of Falcon512SignatureVerifier { + fn verify(message_hash: felt252, public_key: Span, signature: Span) -> bool { + if public_key.len() != PUBLIC_KEY_FELTS || signature.len() != DIRECT_SIGNATURE_FELTS { + return false; + } + let (h_ntt, s1, salt_a, salt_b) = match decode_common(public_key, signature) { + Some(value) => value, + None => { return false; }, + }; + let message_point = match hash_to_point_shake_512(message_hash, salt_a, salt_b) { + Some(value) => value, + None => { return false; }, + }; + falcon::verify_512_direct_u16(s1.span(), h_ntt.span(), message_point.span()) + } + + fn is_valid_public_key(public_key: Span) -> bool { + Falcon512ShakeVerifier::is_valid_public_key(public_key) + } +} diff --git a/packages/account/src/falcon_512/zq.cairo b/packages/account/src/falcon_512/zq.cairo new file mode 100644 index 000000000..e0901ab48 --- /dev/null +++ b/packages/account/src/falcon_512/zq.cairo @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (account/src/falcon_512/zq.cairo) + +//! Arithmetic helpers for `Z_q`, where `q = 12289`. +//! +//! Modular operands are canonical `u16` values in `[0, Q)`. The modular helpers return canonical +//! residues, while the norm helpers return squared centered representatives. All intermediate +//! values fit their declared types. + +/// The Falcon modulus `q = 12289 = 12 · 1024 + 1`. +pub const Q: u16 = 12289; +pub const Q32: u32 = 12289; + +/// Largest centered-low value: `(Q - 1) / 2`. Coefficients above this represent negatives. +pub const Q_HALF: u16 = 6144; + +/// Adds two values modulo `Q`. +#[cfg(test)] +#[inline(always)] +pub fn add_mod(a: u16, b: u16) -> u16 { + // a, b < Q so a + b <= 24576 < 2^16: the checked u16 add never overflows, and a + // single conditional subtraction reduces the sum. + let d = a + b; + if d >= Q { + d - Q + } else { + d + } +} + +/// Subtracts two values modulo `Q` via `a + Q - b` and one conditional subtraction. +#[cfg(test)] +#[inline(always)] +pub fn sub_mod(a: u16, b: u16) -> u16 { + // a < Q so a + Q <= 24577 < 2^16; a + Q - b is in [1, 2Q-1]. + let d = a + Q - b; + if d >= Q { + d - Q + } else { + d + } +} + +/// Multiplies two values modulo `Q`. +#[cfg(test)] +#[inline(always)] +pub fn mul_mod(a: u16, b: u16) -> u16 { + let a: u32 = a.into(); + let b: u32 = b.into(); + // a·b <= 12288² < 2^31. + let res = (a * b) % Q32; + res.try_into().unwrap() +} + +/// Squared centered representative of a coefficient as `felt252`: +/// x ∈ [0, 6144] → x²; x ∈ [6145, 12288] → (Q - x)². +#[inline(always)] +pub fn center_sq(coeff: u16) -> felt252 { + if coeff <= Q_HALF { + let x: felt252 = coeff.into(); + x * x + } else { + let x: felt252 = (Q - coeff).into(); + x * x + } +} + +/// Squared centered representative of `a - b` for canonical coefficients. +#[inline(always)] +pub(crate) fn centered_difference_sq(a: u16, b: u16) -> felt252 { + let difference = if a >= b { + a - b + } else { + b - a + }; + let centered = if difference <= Q_HALF { + difference + } else { + Q - difference + }; + let centered: felt252 = centered.into(); + centered * centered +} + +#[cfg(test)] +mod tests { + use super::{Q, add_mod, center_sq, centered_difference_sq, mul_mod, sub_mod}; + + #[test] + fn test_add_mod_wraps() { + assert_eq!(add_mod(12288, 1), 0); + assert_eq!(add_mod(12288, 12288), 12287); // (-1) + (-1) = -2 = q - 2 + assert_eq!(add_mod(0, 0), 0); + } + + #[test] + fn test_sub_mod_wraps() { + assert_eq!(sub_mod(0, 1), 12288); + assert_eq!(sub_mod(1, 1), 0); + assert_eq!(sub_mod(12288, 12287), 1); + } + + #[test] + fn test_mul_mod() { + assert_eq!(mul_mod(12288, 12288), 1); // (-1)² = 1 + assert_eq!(mul_mod(0, 12288), 0); + // SQR1 = 1479 is a square root of -1 mod q + assert_eq!(mul_mod(1479, 1479), Q - 1); + // 2 · 6145 = 12290 = 1 mod q (6145 = 2⁻¹) + assert_eq!(mul_mod(2, 6145), 1); + } + + #[test] + fn test_center_sq() { + assert_eq!(center_sq(0), 0); + assert_eq!(center_sq(1), 1); + assert_eq!(center_sq(6144), 6144 * 6144); // largest low-half value + assert_eq!(center_sq(6145), 6144 * 6144); // q - 6145 = 6144 + assert_eq!(center_sq(12288), 1); // -1 centered is ±1 + } + + #[test] + fn test_centered_difference_sq_boundaries_and_equivalence() { + assert_eq!(centered_difference_sq(0, 0), 0); + assert_eq!(centered_difference_sq(0, 1), 1); + assert_eq!(centered_difference_sq(1, 0), 1); + assert_eq!(centered_difference_sq(0, 6144), 6144 * 6144); + assert_eq!(centered_difference_sq(0, 6145), 6144 * 6144); + assert_eq!(centered_difference_sq(0, 12288), 1); + assert_eq!(centered_difference_sq(12288, 0), 1); + + let boundaries: [u16; 7] = [0, 1, 6143, 6144, 6145, 12287, 12288]; + for a in boundaries.span() { + for b in boundaries.span() { + assert_eq!(centered_difference_sq(*a, *b), center_sq(sub_mod(*a, *b))); + } + } + } +} diff --git a/packages/account/src/lib.cairo b/packages/account/src/lib.cairo index 93ec3545e..a89c840ac 100644 --- a/packages/account/src/lib.cairo +++ b/packages/account/src/lib.cairo @@ -1,6 +1,7 @@ pub mod account; pub mod eth_account; pub mod extensions; +pub mod falcon_512; #[cfg(test)] mod tests; @@ -8,3 +9,7 @@ pub mod utils; pub use account::AccountComponent; pub use eth_account::EthAccountComponent; +pub use falcon_512::{ + Falcon512AccountComponent, Falcon512ShakeDirectVerifier, Falcon512ShakeVerifier, + Falcon512SignatureVerifier, +}; diff --git a/packages/account/src/tests.cairo b/packages/account/src/tests.cairo index 1d84fc250..f39d455ad 100644 --- a/packages/account/src/tests.cairo +++ b/packages/account/src/tests.cairo @@ -1,6 +1,9 @@ mod extensions; +mod falcon_512_account_mocks; mod test_account; mod test_eth_account; +mod test_falcon_512; +mod test_falcon_512_ntt; mod test_secp256_point; mod test_signature; diff --git a/packages/account/src/tests/falcon_512_account_mocks.cairo b/packages/account/src/tests/falcon_512_account_mocks.cairo new file mode 100644 index 000000000..067c81e56 --- /dev/null +++ b/packages/account/src/tests/falcon_512_account_mocks.cairo @@ -0,0 +1,77 @@ +#[starknet::contract(account)] +pub mod Falcon512ShakeAccountMock { + use openzeppelin_introspection::src5::SRC5Component; + use crate::falcon_512::Falcon512ShakeVerifier; + use crate::falcon_512::account::Falcon512AccountComponent; + + component!(path: Falcon512AccountComponent, storage: account, event: AccountEvent); + component!(path: SRC5Component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl AccountMixinImpl = + Falcon512AccountComponent::Falcon512AccountMixinImpl; + + impl AccountInternalImpl = Falcon512AccountComponent::InternalImpl; + + #[storage] + pub struct Storage { + #[substorage(v0)] + pub account: Falcon512AccountComponent::Storage, + #[substorage(v0)] + pub src5: SRC5Component::Storage, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + AccountEvent: Falcon512AccountComponent::Event, + #[flat] + SRC5Event: SRC5Component::Event, + } + + #[constructor] + pub fn constructor(ref self: ContractState, public_key: Array) { + self.account.initializer::(public_key); + } +} + +#[starknet::contract(account)] +pub mod Falcon512ShakeDirectAccountMock { + use openzeppelin_introspection::src5::SRC5Component; + use crate::falcon_512::Falcon512ShakeDirectVerifier; + use crate::falcon_512::account::Falcon512AccountComponent; + + component!(path: Falcon512AccountComponent, storage: account, event: AccountEvent); + component!(path: SRC5Component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl AccountMixinImpl = + Falcon512AccountComponent::Falcon512AccountMixinImpl< + ContractState, Falcon512ShakeDirectVerifier, + >; + + impl AccountInternalImpl = Falcon512AccountComponent::InternalImpl; + + #[storage] + pub struct Storage { + #[substorage(v0)] + pub account: Falcon512AccountComponent::Storage, + #[substorage(v0)] + pub src5: SRC5Component::Storage, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + AccountEvent: Falcon512AccountComponent::Event, + #[flat] + SRC5Event: SRC5Component::Event, + } + + #[constructor] + pub fn constructor(ref self: ContractState, public_key: Array) { + self.account.initializer::(public_key); + } +} diff --git a/packages/account/src/tests/test_falcon_512.cairo b/packages/account/src/tests/test_falcon_512.cairo new file mode 100644 index 000000000..fa7ae2ac5 --- /dev/null +++ b/packages/account/src/tests/test_falcon_512.cairo @@ -0,0 +1,654 @@ +use core::num::traits::Zero; +use openzeppelin_interfaces::accounts::{ + FeltArrayAccountABIDispatcher, FeltArrayAccountABIDispatcherTrait, IDeclarerDispatcher, + IDeclarerDispatcherTrait, IFeltArrayDeployableDispatcher, IFeltArrayDeployableDispatcherTrait, + IFeltArrayPublicKeyDispatcher, IFeltArrayPublicKeyDispatcherTrait, ISRC6Dispatcher, + ISRC6DispatcherTrait, ISRC6_ID, +}; +use openzeppelin_interfaces::introspection::{ISRC5Dispatcher, ISRC5DispatcherTrait, ISRC5_ID}; +use openzeppelin_test_common::falcon_512::fixture::{msg, public_key, signature}; +use openzeppelin_test_common::falcon_512::rotation_fixture::{ + accept_ownership_hash, accept_ownership_signature, account_address, current_owner_guid, + new_owner_guid, new_public_key, second_accept_ownership_signature, +}; +use openzeppelin_test_common::mocks::simple::{ISimpleMockDispatcher, ISimpleMockDispatcherTrait}; +use openzeppelin_testing as utils; +use openzeppelin_testing::constants::{ + CALLER, MIN_TRANSACTION_VERSION, QUERY_OFFSET, QUERY_VERSION, SALT, ZERO, +}; +use openzeppelin_testing::{EventSpyExt, ExpectedEvent, spy_events}; +use snforge_std::{ + CheatSpan, ContractClassTrait, cheat_caller_address, start_cheat_caller_address, + start_cheat_signature_global, start_cheat_transaction_hash_global, + start_cheat_transaction_version_global, stop_cheat_caller_address, +}; +use starknet::ContractAddress; +use starknet::account::Call; +use crate::falcon_512::verifier_impls::{DIRECT_SIGNATURE_FELTS, PUBLIC_KEY_FELTS, SIGNATURE_FELTS}; +use crate::falcon_512::{Falcon512ShakeDirectVerifier, Falcon512ShakeVerifier}; + +const Q_POW_9: felt252 = 6392178558614694273495691177456939009; +const TWO_POW_160: felt252 = 0x10000000000000000000000000000000000000000; + +fn copy_prefix(mut values: Span, length: u32) -> Array { + let mut output = array![]; + let mut index = 0; + while index != length { + output.append(*values.pop_front().unwrap()); + index += 1; + } + output +} + +fn with_replaced(mut values: Span, target: u32, replacement: felt252) -> Array { + let mut output = array![]; + let mut index = 0; + while let Some(value) = values.pop_front() { + if index == target { + output.append(replacement); + } else { + output.append(*value); + } + index += 1; + } + output +} + +fn with_swapped(values: Span, first: u32, second: u32) -> Array { + let first_value = *values.at(first); + let second_value = *values.at(second); + with_replaced(with_replaced(values, first, second_value).span(), second, first_value) +} + +fn with_appended(mut values: Span, value: felt252) -> Array { + let mut output = array![]; + while let Some(current) = values.pop_front() { + output.append(*current); + } + output.append(value); + output +} + +fn direct_signature() -> Array { + copy_prefix(signature().span(), DIRECT_SIGNATURE_FELTS) +} + +fn direct_accept_ownership_signature() -> Array { + copy_prefix(accept_ownership_signature().span(), DIRECT_SIGNATURE_FELTS) +} + +fn deploy_account(contract_name: ByteArray) -> (ContractAddress, felt252) { + let contract_class = utils::declare_class(contract_name); + let mut calldata = array![]; + public_key().serialize(ref calldata); + let contract_address = utils::deploy(contract_class, calldata); + (contract_address, contract_class.class_hash.into()) +} + +fn deploy_account_at( + contract_name: ByteArray, contract_address: ContractAddress, +) -> FeltArrayAccountABIDispatcher { + let contract_class = utils::declare_class(contract_name); + let mut calldata = array![]; + public_key().serialize(ref calldata); + utils::deploy_at(contract_class, contract_address, calldata); + FeltArrayAccountABIDispatcher { contract_address } +} + +fn assert_deploy_rejects_public_key(contract_name: ByteArray, public_key: Array) { + let contract_class = utils::declare_class(contract_name); + let mut calldata = array![]; + public_key.serialize(ref calldata); + + match contract_class.deploy(@calldata) { + Result::Ok(_) => panic!("Expected invalid public key"), + Result::Err(panic_data) => { + assert_eq!(panic_data, array!['Falcon512: invalid public key']); + }, + } +} + +fn execute_key_rotation( + account: FeltArrayAccountABIDispatcher, + new_key: Array, + acceptance_signature: Array, + setter_selector: felt252, +) { + let mut calldata = array![]; + new_key.serialize(ref calldata); + acceptance_signature.serialize(ref calldata); + account + .__execute__( + array![ + Call { + to: account.contract_address, + selector: setter_selector, + calldata: calldata.span(), + }, + ], + ); +} + +fn setup_transaction( + contract_address: ContractAddress, + tx_hash: felt252, + tx_signature: Array, + version: felt252, +) { + start_cheat_signature_global(tx_signature.span()); + start_cheat_transaction_hash_global(tx_hash); + start_cheat_transaction_version_global(version); + start_cheat_caller_address(contract_address, ZERO); +} + +fn execute_increase( + account: ISRC6Dispatcher, target: ContractAddress, amount: felt252, version: felt252, +) { + start_cheat_transaction_version_global(version); + let calldata = array![amount]; + let call = Call { + to: target, selector: selector!("increase_balance"), calldata: calldata.span(), + }; + account.__execute__(array![call]); +} + +#[test] +fn test_verifiers_accept_reference_signature_and_reject_cross_layout() { + let key = public_key(); + let hint_signature = signature(); + let direct_signature = direct_signature(); + + assert!(Falcon512ShakeVerifier::verify(msg(), key.span(), hint_signature.span())); + assert!(Falcon512ShakeDirectVerifier::verify(msg(), key.span(), direct_signature.span())); + assert!(!Falcon512ShakeVerifier::verify(msg(), key.span(), direct_signature.span())); + assert!(!Falcon512ShakeDirectVerifier::verify(msg(), key.span(), hint_signature.span())); +} + +#[test] +fn test_hint_verifier_rejects_all_malformed_layout_branches() { + let key = public_key(); + let valid_signature = signature(); + + assert!( + !Falcon512ShakeVerifier::verify( + msg(), key.span().slice(0, PUBLIC_KEY_FELTS - 1), valid_signature.span(), + ), + ); + assert!( + !Falcon512ShakeVerifier::verify( + msg(), with_appended(key.span(), 0).span(), valid_signature.span(), + ), + ); + assert!( + !Falcon512ShakeVerifier::verify( + msg(), key.span(), valid_signature.span().slice(0, SIGNATURE_FELTS - 1), + ), + ); + assert!( + !Falcon512ShakeVerifier::verify( + msg(), key.span(), with_appended(valid_signature.span(), 0).span(), + ), + ); + assert!( + !Falcon512ShakeVerifier::verify( + msg(), with_replaced(key.span(), 0, Q_POW_9).span(), valid_signature.span(), + ), + ); + assert!( + !Falcon512ShakeVerifier::verify( + msg(), key.span(), with_replaced(valid_signature.span(), 0, Q_POW_9).span(), + ), + ); + assert!( + !Falcon512ShakeVerifier::verify( + msg(), key.span(), with_replaced(valid_signature.span(), 31, Q_POW_9).span(), + ), + ); + assert!( + !Falcon512ShakeVerifier::verify( + msg(), key.span(), with_replaced(valid_signature.span(), 29, TWO_POW_160).span(), + ), + ); + assert!( + !Falcon512ShakeVerifier::verify( + msg(), key.span(), with_replaced(valid_signature.span(), 30, TWO_POW_160).span(), + ), + ); +} + +#[test] +fn test_hint_verifier_rejects_tampering_in_each_authenticated_region() { + let key = public_key(); + let valid_signature = signature(); + + assert!(!Falcon512ShakeVerifier::verify(msg() + 1, key.span(), valid_signature.span())); + assert!( + !Falcon512ShakeVerifier::verify( + msg(), with_swapped(key.span(), 0, 1).span(), valid_signature.span(), + ), + ); + assert!( + !Falcon512ShakeVerifier::verify( + msg(), key.span(), with_swapped(valid_signature.span(), 0, 1).span(), + ), + ); + assert!( + !Falcon512ShakeVerifier::verify( + msg(), + key.span(), + with_replaced(valid_signature.span(), 29, *valid_signature.at(29) + 1).span(), + ), + ); + assert!( + !Falcon512ShakeVerifier::verify( + msg(), + key.span(), + with_replaced(valid_signature.span(), 31, *valid_signature.at(31) + 1).span(), + ), + ); +} + +#[test] +fn test_direct_verifier_rejects_all_malformed_layout_branches() { + let key = public_key(); + let valid_signature = direct_signature(); + + assert!( + !Falcon512ShakeDirectVerifier::verify( + msg(), key.span().slice(0, PUBLIC_KEY_FELTS - 1), valid_signature.span(), + ), + ); + assert!( + !Falcon512ShakeDirectVerifier::verify( + msg(), with_appended(key.span(), 0).span(), valid_signature.span(), + ), + ); + assert!( + !Falcon512ShakeDirectVerifier::verify( + msg(), key.span(), valid_signature.span().slice(0, DIRECT_SIGNATURE_FELTS - 1), + ), + ); + assert!( + !Falcon512ShakeDirectVerifier::verify( + msg(), key.span(), with_appended(valid_signature.span(), 0).span(), + ), + ); + assert!( + !Falcon512ShakeDirectVerifier::verify( + msg(), with_replaced(key.span(), 0, Q_POW_9).span(), valid_signature.span(), + ), + ); + assert!( + !Falcon512ShakeDirectVerifier::verify( + msg(), key.span(), with_replaced(valid_signature.span(), 0, Q_POW_9).span(), + ), + ); + assert!( + !Falcon512ShakeDirectVerifier::verify( + msg(), key.span(), with_replaced(valid_signature.span(), 29, TWO_POW_160).span(), + ), + ); + assert!( + !Falcon512ShakeDirectVerifier::verify( + msg(), key.span(), with_replaced(valid_signature.span(), 30, TWO_POW_160).span(), + ), + ); +} + +#[test] +fn test_direct_verifier_rejects_tampering_in_each_authenticated_region() { + let key = public_key(); + let valid_signature = direct_signature(); + + assert!(!Falcon512ShakeDirectVerifier::verify(msg() + 1, key.span(), valid_signature.span())); + assert!( + !Falcon512ShakeDirectVerifier::verify( + msg(), with_swapped(key.span(), 0, 1).span(), valid_signature.span(), + ), + ); + assert!( + !Falcon512ShakeDirectVerifier::verify( + msg(), key.span(), with_swapped(valid_signature.span(), 0, 1).span(), + ), + ); + assert!( + !Falcon512ShakeDirectVerifier::verify( + msg(), + key.span(), + with_replaced(valid_signature.span(), 29, *valid_signature.at(29) + 1).span(), + ), + ); +} + +#[test] +fn test_direct_signature_prefix_remains_valid_when_hint_suffix_is_tampered() { + let key = public_key(); + let valid_signature = signature(); + let tampered = with_replaced(valid_signature.span(), 31, *valid_signature.at(31) + 1); + + assert!(!Falcon512ShakeVerifier::verify(msg(), key.span(), tampered.span())); + assert!( + Falcon512ShakeDirectVerifier::verify( + msg(), key.span(), copy_prefix(tampered.span(), DIRECT_SIGNATURE_FELTS).span(), + ), + ); +} + +#[test] +fn test_accounts_expose_exact_public_key_and_interfaces() { + let (hint_address, _) = deploy_account("Falcon512ShakeAccountMock"); + let (direct_address, _) = deploy_account("Falcon512ShakeDirectAccountMock"); + + for address in [hint_address, direct_address].span() { + let key_dispatcher = IFeltArrayPublicKeyDispatcher { contract_address: *address }; + assert_eq!(key_dispatcher.get_public_key().span(), public_key().span()); + + let src5 = ISRC5Dispatcher { contract_address: *address }; + assert!(src5.supports_interface(ISRC5_ID)); + assert!(src5.supports_interface(ISRC6_ID)); + assert!(!src5.supports_interface(0x123456)); + } +} + +#[test] +fn test_accounts_follow_is_valid_signature_return_convention_and_reject_cross_layout() { + let (hint_address, _) = deploy_account("Falcon512ShakeAccountMock"); + let (direct_address, _) = deploy_account("Falcon512ShakeDirectAccountMock"); + let hint = ISRC6Dispatcher { contract_address: hint_address }; + let direct = ISRC6Dispatcher { contract_address: direct_address }; + + assert_eq!(hint.is_valid_signature(msg(), signature()), starknet::VALIDATED); + assert!(hint.is_valid_signature(msg() + 1, signature()).is_zero()); + assert!(hint.is_valid_signature(msg(), direct_signature()).is_zero()); + + assert_eq!(direct.is_valid_signature(msg(), direct_signature()), starknet::VALIDATED); + assert!(direct.is_valid_signature(msg() + 1, direct_signature()).is_zero()); + assert!(direct.is_valid_signature(msg(), signature()).is_zero()); +} + +#[test] +fn test_hint_account_rotates_key_via_authenticated_execute() { + let address = account_address(); + let account = deploy_account_at("Falcon512ShakeAccountMock", address); + setup_transaction(address, msg(), signature(), MIN_TRANSACTION_VERSION); + + // Protocol validation authenticates the outer invoke with the current owner. + assert_eq!(account.__validate__(array![]), starknet::VALIDATED); + stop_cheat_caller_address(address); + // Cheat only the outer entry point call. The nested self-call keeps its real caller. + cheat_caller_address(address, ZERO, CheatSpan::TargetCalls(1)); + + let mut spy = spy_events(); + execute_key_rotation( + account, new_public_key(), accept_ownership_signature(), selector!("set_public_key"), + ); + + spy + .assert_emitted_single( + address, ExpectedEvent::new().key(selector!("OwnerRemoved")).key(current_owner_guid()), + ); + spy + .assert_only_event( + address, ExpectedEvent::new().key(selector!("OwnerAdded")).key(new_owner_guid()), + ); + + let account = FeltArrayAccountABIDispatcher { contract_address: address }; + assert_eq!(account.get_public_key().span(), new_public_key().span()); + assert_eq!(account.getPublicKey().span(), new_public_key().span()); +} + +#[test] +fn test_hint_rotated_key_accepts_new_owner_and_rejects_old_owner() { + let address = account_address(); + let account = deploy_account_at("Falcon512ShakeAccountMock", address); + let acceptance_signature = accept_ownership_signature(); + start_cheat_caller_address(address, address); + account.set_public_key(new_public_key(), acceptance_signature.span()); + + assert_eq!( + account.is_valid_signature(accept_ownership_hash(), accept_ownership_signature()), + starknet::VALIDATED, + ); + assert!(account.is_valid_signature(msg(), signature()).is_zero()); +} + +#[test] +fn test_repeated_key_rotation_keeps_exact_storage_length() { + let address = account_address(); + let account = deploy_account_at("Falcon512ShakeAccountMock", address); + start_cheat_caller_address(address, address); + let first_signature = accept_ownership_signature(); + account.set_public_key(new_public_key(), first_signature.span()); + + // A second rotation keeps the stored key at its fixed 29-felt length. + let second_signature = second_accept_ownership_signature(); + account.set_public_key(new_public_key(), second_signature.span()); + assert_eq!(account.get_public_key().len(), PUBLIC_KEY_FELTS); +} + +#[test] +fn test_direct_account_rotates_key_through_camel_case_abi() { + let address = account_address(); + let account = deploy_account_at("Falcon512ShakeDirectAccountMock", address); + let acceptance_signature = direct_accept_ownership_signature(); + start_cheat_caller_address(address, address); + + let mut spy = spy_events(); + account.setPublicKey(new_public_key(), acceptance_signature.span()); + + spy + .assert_emitted_single( + address, ExpectedEvent::new().key(selector!("OwnerRemoved")).key(current_owner_guid()), + ); + spy + .assert_only_event( + address, ExpectedEvent::new().key(selector!("OwnerAdded")).key(new_owner_guid()), + ); + + assert_eq!(account.getPublicKey().span(), new_public_key().span()); + assert_eq!(account.get_public_key().span(), new_public_key().span()); +} + +#[test] +fn test_direct_account_camel_case_signature_alias() { + let address = account_address(); + let account = deploy_account_at("Falcon512ShakeDirectAccountMock", address); + + assert_eq!(account.isValidSignature(msg(), direct_signature()), starknet::VALIDATED); +} + +#[test] +fn test_constructor_emits_owner_added_guid() { + let address = account_address(); + let mut spy = spy_events(); + deploy_account_at("Falcon512ShakeAccountMock", address); + + spy + .assert_only_event( + address, ExpectedEvent::new().key(selector!("OwnerAdded")).key(current_owner_guid()), + ); +} + +#[test] +#[should_panic(expected: 'Falcon512: unauthorized')] +fn test_key_rotation_rejects_non_self_caller() { + let address = account_address(); + let account = deploy_account_at("Falcon512ShakeAccountMock", address); + start_cheat_caller_address(address, CALLER); + + account.set_public_key(new_public_key(), array![].span()); +} + +#[test] +#[should_panic(expected: 'Falcon512: invalid public key')] +fn test_key_rotation_rejects_malformed_public_key_before_signature() { + let address = account_address(); + let account = deploy_account_at("Falcon512ShakeDirectAccountMock", address); + start_cheat_caller_address(address, address); + + account + .set_public_key( + copy_prefix(new_public_key().span(), PUBLIC_KEY_FELTS - 1), array![].span(), + ); +} + +#[test] +#[should_panic(expected: 'Falcon512: invalid signature')] +fn test_key_rotation_rejects_invalid_new_owner_proof() { + let address = account_address(); + let account = deploy_account_at("Falcon512ShakeAccountMock", address); + start_cheat_caller_address(address, address); + let valid_signature = accept_ownership_signature(); + let invalid_signature = with_replaced(valid_signature.span(), 0, *valid_signature.at(0) + 1); + + account.set_public_key(new_public_key(), invalid_signature.span()); +} + +#[test] +#[should_panic(expected: 'Falcon512: invalid signature')] +fn test_key_rotation_proof_cannot_be_replayed_to_another_account() { + let address = CALLER; + let account = deploy_account_at("Falcon512ShakeDirectAccountMock", address); + start_cheat_caller_address(address, address); + let acceptance_signature = direct_accept_ownership_signature(); + + account.set_public_key(new_public_key(), acceptance_signature.span()); +} + +#[test] +#[should_panic(expected: 'Falcon512: invalid signature')] +fn test_key_rotation_proof_cannot_be_replayed_after_rotation() { + let address = account_address(); + let account = deploy_account_at("Falcon512ShakeDirectAccountMock", address); + start_cheat_caller_address(address, address); + let acceptance_signature = direct_accept_ownership_signature(); + + account.set_public_key(new_public_key(), acceptance_signature.span()); + // The current-owner GUID changed, so the first acceptance proof is no longer valid. + account.set_public_key(new_public_key(), acceptance_signature.span()); +} + +#[test] +fn test_all_validation_entrypoints_accept_hint_account_signature() { + let (address, class_hash) = deploy_account("Falcon512ShakeAccountMock"); + setup_transaction(address, msg(), signature(), MIN_TRANSACTION_VERSION); + + let src6 = ISRC6Dispatcher { contract_address: address }; + let declarer = IDeclarerDispatcher { contract_address: address }; + let deployable = IFeltArrayDeployableDispatcher { contract_address: address }; + assert_eq!(src6.__validate__(array![]), starknet::VALIDATED); + assert_eq!(declarer.__validate_declare__(class_hash), starknet::VALIDATED); + assert_eq!(deployable.__validate_deploy__(class_hash, SALT, public_key()), starknet::VALIDATED); +} + +#[test] +fn test_all_validation_entrypoints_accept_direct_account_signature() { + let (address, class_hash) = deploy_account("Falcon512ShakeDirectAccountMock"); + setup_transaction(address, msg(), direct_signature(), MIN_TRANSACTION_VERSION); + + let src6 = ISRC6Dispatcher { contract_address: address }; + let declarer = IDeclarerDispatcher { contract_address: address }; + let deployable = IFeltArrayDeployableDispatcher { contract_address: address }; + assert_eq!(src6.__validate__(array![]), starknet::VALIDATED); + assert_eq!(declarer.__validate_declare__(class_hash), starknet::VALIDATED); + assert_eq!(deployable.__validate_deploy__(class_hash, SALT, public_key()), starknet::VALIDATED); +} + +#[test] +#[should_panic(expected: 'Falcon512: invalid signature')] +fn test_hint_validate_rejects_invalid_signature() { + let (address, _) = deploy_account("Falcon512ShakeAccountMock"); + setup_transaction(address, msg() + 1, signature(), MIN_TRANSACTION_VERSION); + ISRC6Dispatcher { contract_address: address }.__validate__(array![]); +} + +#[test] +#[should_panic(expected: 'Falcon512: invalid signature')] +fn test_direct_validate_rejects_invalid_signature() { + let (address, _) = deploy_account("Falcon512ShakeDirectAccountMock"); + setup_transaction(address, msg() + 1, direct_signature(), MIN_TRANSACTION_VERSION); + ISRC6Dispatcher { contract_address: address }.__validate__(array![]); +} + +#[test] +#[should_panic(expected: 'Falcon512: invalid signature')] +fn test_validate_declare_rejects_invalid_signature() { + let (address, class_hash) = deploy_account("Falcon512ShakeAccountMock"); + setup_transaction(address, msg() + 1, signature(), MIN_TRANSACTION_VERSION); + IDeclarerDispatcher { contract_address: address }.__validate_declare__(class_hash); +} + +#[test] +#[should_panic(expected: 'Falcon512: invalid signature')] +fn test_validate_deploy_rejects_invalid_signature() { + let (address, class_hash) = deploy_account("Falcon512ShakeAccountMock"); + setup_transaction(address, msg() + 1, signature(), MIN_TRANSACTION_VERSION); + IFeltArrayDeployableDispatcher { contract_address: address } + .__validate_deploy__(class_hash, SALT, public_key()); +} + +#[test] +fn test_constructor_rejects_wrong_public_key_length() { + assert_deploy_rejects_public_key( + "Falcon512ShakeAccountMock", copy_prefix(public_key().span(), PUBLIC_KEY_FELTS - 1), + ); +} + +#[test] +fn test_constructor_rejects_noncanonical_public_key() { + assert_deploy_rejects_public_key( + "Falcon512ShakeDirectAccountMock", with_replaced(public_key().span(), 0, Q_POW_9), + ); +} + +#[test] +fn test_execute_empty_single_multicall_and_supported_versions() { + let (address, _) = deploy_account("Falcon512ShakeAccountMock"); + setup_transaction(address, msg(), signature(), MIN_TRANSACTION_VERSION); + let account = ISRC6Dispatcher { contract_address: address }; + account.__execute__(array![]); + + let target = utils::declare_and_deploy("SimpleMock", array![]); + let simple = ISimpleMockDispatcher { contract_address: target }; + execute_increase(account, target, 1, MIN_TRANSACTION_VERSION); + execute_increase(account, target, 2, MIN_TRANSACTION_VERSION + 1); + execute_increase(account, target, 4, QUERY_VERSION); + execute_increase(account, target, 8, QUERY_VERSION + 1); + + start_cheat_transaction_version_global(MIN_TRANSACTION_VERSION); + let calldata_a = array![16]; + let calldata_b = array![32]; + let call_a = Call { + to: target, selector: selector!("increase_balance"), calldata: calldata_a.span(), + }; + let call_b = Call { + to: target, selector: selector!("increase_balance"), calldata: calldata_b.span(), + }; + account.__execute__(array![call_a, call_b]); + assert_eq!(simple.get_balance(), 63); +} + +#[test] +#[should_panic(expected: 'Falcon512: invalid tx version')] +fn test_execute_rejects_zero_version() { + let (address, _) = deploy_account("Falcon512ShakeAccountMock"); + setup_transaction(address, msg(), signature(), MIN_TRANSACTION_VERSION - 1); + ISRC6Dispatcher { contract_address: address }.__execute__(array![]); +} + +#[test] +#[should_panic(expected: 'Falcon512: invalid tx version')] +fn test_execute_rejects_query_offset_without_version() { + let (address, _) = deploy_account("Falcon512ShakeAccountMock"); + setup_transaction(address, msg(), signature(), QUERY_OFFSET); + ISRC6Dispatcher { contract_address: address }.__execute__(array![]); +} + +#[test] +#[should_panic(expected: 'Falcon512: invalid caller')] +fn test_execute_rejects_contract_caller() { + let (address, _) = deploy_account("Falcon512ShakeAccountMock"); + setup_transaction(address, msg(), signature(), MIN_TRANSACTION_VERSION); + start_cheat_caller_address(address, CALLER); + ISRC6Dispatcher { contract_address: address }.__execute__(array![]); +} diff --git a/packages/account/src/tests/test_falcon_512_ntt.cairo b/packages/account/src/tests/test_falcon_512_ntt.cairo new file mode 100644 index 000000000..1e9554978 --- /dev/null +++ b/packages/account/src/tests/test_falcon_512_ntt.cairo @@ -0,0 +1,187 @@ +use crate::falcon_512::ntt::engine::{intt, ntt}; +#[cfg(feature: 'falcon_fast_tests')] +use crate::falcon_512::ntt::falcon512::PRODUCT_BITS; +use crate::falcon_512::ntt::falcon512::{ + PRODUCT_BOUND_FELT, REDUCED_BITS, config, config_for_degree, +}; +#[cfg(feature: 'falcon_fast_tests')] +use crate::falcon_512::ntt::falcon512_fast::{ + ntt_falcon512_fast_u16_unchecked, ntt_falcon512_fast_unchecked, +}; +use crate::falcon_512::ntt::roots_felt::get_even_roots_felt; +use crate::falcon_512::ntt::roots_scaled::get_scaled_inv_roots; + +fn as_felts(mut values: Span) -> Array { + let mut output = array![]; + while let Some(value) = values.pop_front() { + output.append((*value).into()); + } + output +} + +fn zeros() -> Array { + let mut values = array![]; + while values.len() != 512 { + values.append(0); + } + values +} + +fn max_values() -> Array { + let mut values = array![]; + while values.len() != 512 { + values.append(12288); + } + values +} + +fn basis(index: u32) -> Array { + let mut values = array![]; + let mut current = 0; + while current != 512 { + if current == index { + values.append(1); + } else { + values.append(0); + } + current += 1; + } + values +} + +fn pseudorandom_values(seed: u64) -> Array { + let mut values = array![]; + let mut state = seed; + while values.len() != 512 { + state = (state * 1664525 + 1013904223) % 0x100000000; + values.append((state % 12289).try_into().unwrap()); + } + values +} + +#[cfg(feature: 'falcon_fast_tests')] +fn assert_fast_matches_generic(values: Span) { + let input = as_felts(values); + let generic = ntt(input.span(), @config()); + let fast_u16 = ntt_falcon512_fast_u16_unchecked(values); + let fast_felt = ntt_falcon512_fast_unchecked(input.span()); + assert_eq!(generic.span(), as_felts(fast_u16.span()).span()); + assert_eq!(generic.span(), fast_felt.span()); +} + +#[cfg(feature: 'falcon_fast_tests')] +#[test] +fn test_fast_ntt_matches_generic_on_boundary_and_pseudorandom_inputs() { + assert_fast_matches_generic(zeros().span()); + assert_fast_matches_generic(max_values().span()); + assert_fast_matches_generic(basis(0).span()); + assert_fast_matches_generic(basis(511).span()); + assert_fast_matches_generic(pseudorandom_values(7).span()); +} + +#[cfg(feature: 'falcon_fast_tests')] +#[test] +fn test_fast_ntt_matches_generic_reference_for_every_basis_vector() { + let mut index = 0; + while index != 512 { + let values = basis(index); + let input = as_felts(values.span()); + let generic = ntt(input.span(), @config()); + let fast = ntt_falcon512_fast_u16_unchecked(values.span()); + assert_eq!(generic.span(), as_felts(fast.span()).span()); + index += 1; + } +} + +#[cfg(feature: 'falcon_fast_tests')] +#[test] +fn test_fast_ntt_inverse_roundtrip() { + let values = pseudorandom_values(19); + let transformed = ntt_falcon512_fast_u16_unchecked(values.span()); + let transformed = as_felts(transformed.span()); + let recovered = intt(transformed.span(), REDUCED_BITS, 12289, @config()); + assert_eq!(recovered.span(), as_felts(values.span()).span()); +} + +#[cfg(feature: 'falcon_fast_tests')] +#[test] +fn test_ntt_negacyclic_product() { + let left = ntt_falcon512_fast_u16_unchecked(basis(1).span()); + let right = ntt_falcon512_fast_u16_unchecked(basis(511).span()); + let mut products = array![]; + let mut left = left.span(); + let mut right = right.span(); + while let Some(a) = left.pop_front() { + let a: felt252 = (*a).into(); + let b: felt252 = (*right.pop_front().unwrap()).into(); + products.append(a * b); + } + + let product = intt(products.span(), PRODUCT_BITS, PRODUCT_BOUND_FELT, @config()); + let mut expected = array![12288]; + while expected.len() != 512 { + expected.append(0); + } + assert_eq!(product.span(), expected.span()); +} + +#[test] +#[should_panic(expected: 'intt: bad input length')] +fn test_intt_rejects_wrong_length() { + intt(array![].span(), REDUCED_BITS, 12289, @config()); +} + +#[test] +#[should_panic(expected: 'intt: input too large')] +fn test_intt_rejects_excessive_input_bits() { + let values = as_felts(zeros().span()); + intt(values.span(), 120, PRODUCT_BOUND_FELT, @config()); +} + +#[test] +fn test_degree_four_roundtrip_exercises_reduction_tail() { + let values = array![1, 2, 3, 4]; + let cfg = config_for_degree(4, 2); + let transformed = ntt(values.span(), @cfg); + let recovered = intt(transformed.span(), REDUCED_BITS, 12289, @cfg); + assert_eq!(recovered.span(), values.span()); +} + +#[test] +fn test_intt_reduces_before_last_level() { + let values = array![1, 2, 3, 4]; + let cfg = config_for_degree(4, 2); + let transformed = ntt(values.span(), @cfg); + let recovered = intt(transformed.span(), 111, 12289, @cfg); + assert_eq!(recovered.span(), values.span()); +} + +#[test] +#[should_panic(expected: "config_for_degree: unsupported degree 2")] +fn test_config_rejects_degree_below_range() { + config_for_degree(2, 1); +} + +#[test] +#[should_panic(expected: "config_for_degree: unsupported degree 6")] +fn test_config_rejects_non_power_of_two_degree() { + config_for_degree(6, 3); +} + +#[test] +#[should_panic(expected: "config_for_degree: unsupported degree 1024")] +fn test_config_rejects_degree_above_range() { + config_for_degree(1024, 10); +} + +#[test] +#[should_panic(expected: "no root table for degree")] +fn test_forward_roots_reject_unsupported_degree() { + get_even_roots_felt(3); +} + +#[test] +#[should_panic(expected: "no root table for degree")] +fn test_inverse_roots_reject_unsupported_degree() { + get_scaled_inv_roots(3); +} diff --git a/packages/corelib_imports/README.md b/packages/corelib_imports/README.md new file mode 100644 index 000000000..18f5395c8 --- /dev/null +++ b/packages/corelib_imports/README.md @@ -0,0 +1,8 @@ +## Corelib Imports + +Provides the gated Cairo corelib re-exports required by OpenZeppelin packages. The `2023_10` +edition exposes these APIs under Cairo 2.18.0; they are unavailable to a `2024_07` package in that +compiler version. + +This compiler-compatibility package contains only re-exports. Its API is internal to the workspace +and may change with Cairo compiler upgrades. diff --git a/packages/corelib_imports/Scarb.toml b/packages/corelib_imports/Scarb.toml new file mode 100644 index 000000000..66f9be8f2 --- /dev/null +++ b/packages/corelib_imports/Scarb.toml @@ -0,0 +1,24 @@ +[package] +name = "openzeppelin_corelib_imports" +readme = "README.md" +version.workspace = true +edition = "2023_10" +cairo-version.workspace = true +scarb-version.workspace = true +authors.workspace = true +description = "OpenZeppelin compatibility imports for gated Cairo corelib APIs" +documentation.workspace = true +repository.workspace = true +license-file.workspace = true +keywords = [ + "openzeppelin", + "cairo", + "corelib", + "internal" +] + +[tool] +fmt.workspace = true +scarb.workspace = true + +[lib] diff --git a/packages/corelib_imports/src/lib.cairo b/packages/corelib_imports/src/lib.cairo new file mode 100644 index 000000000..da2457510 --- /dev/null +++ b/packages/corelib_imports/src/lib.cairo @@ -0,0 +1,10 @@ +pub mod bounded_int { + #[feature("bounded-int-utils")] + pub use core::internal::bounded_int::{ + BoundedInt, DivRemHelper, UnitInt, bounded_int_div_rem, downcast, upcast, + }; +} + +pub mod integer { + pub use core::integer::{U128sFromFelt252Result, u128s_from_felt252}; +} diff --git a/packages/interfaces/README.md b/packages/interfaces/README.md index 024264ed5..b57e77364 100644 --- a/packages/interfaces/README.md +++ b/packages/interfaces/README.md @@ -1,8 +1,8 @@ ## Interfaces -List of standardized interfaces, ABI traits and dispatchers. +List of interfaces, ABI traits and dispatchers. -### Standardized Interfaces +### Interface Traits - [`IAccessControlDefaultAdminRules`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/access#IAccessControlDefaultAdminRules) - [`IAccessControl`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/access#IAccessControl) @@ -16,6 +16,9 @@ List of standardized interfaces, ABI traits and dispatchers. - `ISRC6CamelOnly` - `IDeclarer` - `IDeployable` +- `IFeltArrayDeployable` +- `IFeltArrayPublicKey` +- `IFeltArrayPublicKeyCamel` - `IPublicKey` - `IPublicKeyCamel` - `IEthDeployable` @@ -65,7 +68,6 @@ List of standardized interfaces, ABI traits and dispatchers. - [`IUpgradeable`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/upgrades#IUpgradeable) - [`IUpgradeAndCall`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/upgrades#IUpgradeAndCall) - ### ABI Traits - `AccessControlDefaultAdminRulesABI` @@ -73,6 +75,7 @@ List of standardized interfaces, ABI traits and dispatchers. - `OwnableABI` - `OwnableTwoStepABI` - `AccountABI` +- `FeltArrayAccountABI` - `EthAccountABI` - `TimelockABI` - `VotesABI` diff --git a/packages/interfaces/src/account/accounts.cairo b/packages/interfaces/src/account/accounts.cairo index d5d2cbc22..65fe19811 100644 --- a/packages/interfaces/src/account/accounts.cairo +++ b/packages/interfaces/src/account/accounts.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (interfaces/src/account/account.cairo) +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 (interfaces/src/account/accounts.cairo) use starknet::account::Call; @@ -49,6 +49,21 @@ pub trait IDeployable { ) -> felt252; } +/// Deployment validation for accounts whose public key is encoded as a felt array. +#[starknet::interface] +pub trait IFeltArrayDeployable { + /// Validates a deploy-account transaction before deployment. + /// This function is used by the protocol to verify `deploy_account` transactions. + /// + /// Returns the short string 'VALID' if valid, otherwise it reverts. + fn __validate_deploy__( + self: @TState, + class_hash: felt252, + contract_address_salt: felt252, + public_key: Array, + ) -> felt252; +} + #[starknet::interface] pub trait IPublicKey { /// Returns the current public key of the account. @@ -60,6 +75,18 @@ pub trait IPublicKey { fn set_public_key(ref self: TState, new_public_key: felt252, signature: Span); } +/// Access to a public key encoded as a felt array. +#[starknet::interface] +pub trait IFeltArrayPublicKey { + /// Returns the current public key of the account. + fn get_public_key(self: @TState) -> Array; + + /// Sets the public key of the account to `new_public_key`. + /// + /// Emits both an `OwnerRemoved` and an `OwnerAdded` event. + fn set_public_key(ref self: TState, new_public_key: Array, signature: Span); +} + /// Adds camelCase support for `ISRC6`. #[starknet::interface] pub trait ISRC6CamelOnly { @@ -73,6 +100,13 @@ pub trait IPublicKeyCamel { fn setPublicKey(ref self: TState, newPublicKey: felt252, signature: Span); } +/// Adds camelCase support for `IFeltArrayPublicKey`. +#[starknet::interface] +pub trait IFeltArrayPublicKeyCamel { + fn getPublicKey(self: @TState) -> Array; + fn setPublicKey(ref self: TState, newPublicKey: Array, signature: Span); +} + // // Account ABI // @@ -107,6 +141,43 @@ pub trait AccountABI { fn setPublicKey(ref self: TState, newPublicKey: felt252, signature: Span); } +// +// FeltArrayAccount ABI +// + +#[starknet::interface] +pub trait FeltArrayAccountABI { + // ISRC6 + fn __execute__(self: @TState, calls: Array); + fn __validate__(self: @TState, calls: Array) -> felt252; + fn is_valid_signature(self: @TState, hash: felt252, signature: Array) -> felt252; + + // ISRC5 + fn supports_interface(self: @TState, interface_id: felt252) -> bool; + + // IDeclarer + fn __validate_declare__(self: @TState, class_hash: felt252) -> felt252; + + // IFeltArrayDeployable + fn __validate_deploy__( + self: @TState, + class_hash: felt252, + contract_address_salt: felt252, + public_key: Array, + ) -> felt252; + + // IFeltArrayPublicKey + fn get_public_key(self: @TState) -> Array; + fn set_public_key(ref self: TState, new_public_key: Array, signature: Span); + + // ISRC6CamelOnly + fn isValidSignature(self: @TState, hash: felt252, signature: Array) -> felt252; + + // IFeltArrayPublicKeyCamel + fn getPublicKey(self: @TState) -> Array; + fn setPublicKey(ref self: TState, newPublicKey: Array, signature: Span); +} + // // EthAccount // diff --git a/packages/presets/README.md b/packages/presets/README.md index 9b8a4a78a..34cd68c95 100644 --- a/packages/presets/README.md +++ b/packages/presets/README.md @@ -8,6 +8,14 @@ generic as possible, there’s no support for custom or complex contracts such a For contract customization and combination of modules you can use [Wizard for Cairo](https://wizard.openzeppelin.com/cairo), our code-generation tool. +The Falcon-512 account presets support SRC9 outside execution, self-authorized class upgrades, and +owner-authorized key rotation. Build their deployable artifacts with +`scarb --release build -p openzeppelin_presets`; their Falcon verification paths require the +release compiler profile. + +> **WARNING:** The Falcon presets use contract-specific public-key and signature encodings for the +> FALCON submission verification relation. They are not FN-DSA (FIPS 206) implementations. + ### Presets - [`AccountUpgradeable`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/account#AccountUpgradeable) @@ -15,4 +23,6 @@ For contract customization and combination of modules you can use - [`ERC721Upgradeable`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/erc721#ERC721Upgradeable) - [`ERC1155Upgradeable`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/erc1155#ERC1155Upgradeable) - [`EthAccountUpgradeable`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/account#EthAccountUpgradeable) +- [`Falcon512ShakeAccountUpgradeable`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/account#Falcon512ShakeAccountUpgradeable) +- [`Falcon512ShakeDirectAccountUpgradeable`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/account#Falcon512ShakeDirectAccountUpgradeable) - [`UniversalDeployer`](https://docs.openzeppelin.com/contracts-cairo/3.x/api/udc#UniversalDeployer) diff --git a/packages/presets/Scarb.toml b/packages/presets/Scarb.toml index a040ea672..bfde777e0 100644 --- a/packages/presets/Scarb.toml +++ b/packages/presets/Scarb.toml @@ -38,6 +38,10 @@ snforge_std.workspace = true openzeppelin_testing = { path = "../testing" } openzeppelin_test_common = { path = "../test_common" } +[features] +# Enables the Falcon preset integration tests; requires the release compiler profile. +falcon_presets_tests = [] + [lib] [[target.starknet-contract]] diff --git a/packages/presets/src/falcon_512_shake_account.cairo b/packages/presets/src/falcon_512_shake_account.cairo new file mode 100644 index 000000000..cdb666ec2 --- /dev/null +++ b/packages/presets/src/falcon_512_shake_account.cairo @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 +// (presets/src/falcon_512_shake_account.cairo) + +/// # Falcon512ShakeAccount Preset +/// +/// OpenZeppelin's upgradeable Falcon-512 account using SHAKE-256 hash-to-point and a +/// verifier-checked polynomial-product hint. Supports outside execution by implementing SRC9. +/// Its public-key and signature formats are contract-specific encodings for the FALCON submission +/// verification relation, rather than FN-DSA (FIPS 206) encodings. +#[starknet::contract(account)] +pub mod Falcon512ShakeAccountUpgradeable { + use openzeppelin_account::extensions::SRC9Component; + use openzeppelin_account::{Falcon512AccountComponent, Falcon512ShakeVerifier}; + use openzeppelin_interfaces::upgrades::IUpgradeable; + use openzeppelin_introspection::src5::SRC5Component; + use openzeppelin_upgrades::UpgradeableComponent; + use starknet::ClassHash; + + component!(path: Falcon512AccountComponent, storage: account, event: AccountEvent); + component!(path: SRC5Component, storage: src5, event: SRC5Event); + component!(path: SRC9Component, storage: src9, event: SRC9Event); + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent); + + // Falcon512Account Mixin + #[abi(embed_v0)] + pub(crate) impl Falcon512AccountMixinImpl = + Falcon512AccountComponent::Falcon512AccountMixinImpl; + impl Falcon512AccountInternalImpl = Falcon512AccountComponent::InternalImpl; + + // SRC9 + #[abi(embed_v0)] + impl OutsideExecutionV2Impl = + SRC9Component::OutsideExecutionV2Impl; + impl OutsideExecutionInternalImpl = SRC9Component::InternalImpl; + + // Upgradeable + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl; + + #[storage] + pub struct Storage { + #[substorage(v0)] + pub account: Falcon512AccountComponent::Storage, + #[substorage(v0)] + pub src5: SRC5Component::Storage, + #[substorage(v0)] + pub src9: SRC9Component::Storage, + #[substorage(v0)] + pub upgradeable: UpgradeableComponent::Storage, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + AccountEvent: Falcon512AccountComponent::Event, + #[flat] + SRC5Event: SRC5Component::Event, + #[flat] + SRC9Event: SRC9Component::Event, + #[flat] + UpgradeableEvent: UpgradeableComponent::Event, + } + + #[constructor] + pub fn constructor(ref self: ContractState, public_key: Array) { + self.account.initializer::(public_key); + self.src9.initializer(); + } + + #[abi(embed_v0)] + impl UpgradeableImpl of IUpgradeable { + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) { + self.account.assert_only_self(); + self.upgradeable.upgrade(new_class_hash); + } + } +} diff --git a/packages/presets/src/falcon_512_shake_direct_account.cairo b/packages/presets/src/falcon_512_shake_direct_account.cairo new file mode 100644 index 000000000..b8958c813 --- /dev/null +++ b/packages/presets/src/falcon_512_shake_direct_account.cairo @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v4.0.0-alpha.1 +// (presets/src/falcon_512_shake_direct_account.cairo) + +/// # Falcon512ShakeDirectAccount Preset +/// +/// OpenZeppelin's upgradeable Falcon-512 account using SHAKE-256 hash-to-point and on-chain +/// polynomial-product recomputation. Supports outside execution by implementing SRC9. +/// Its public-key and signature formats are contract-specific encodings for the FALCON submission +/// verification relation, rather than FN-DSA (FIPS 206) encodings. +#[starknet::contract(account)] +pub mod Falcon512ShakeDirectAccountUpgradeable { + use openzeppelin_account::extensions::SRC9Component; + use openzeppelin_account::{Falcon512AccountComponent, Falcon512ShakeDirectVerifier}; + use openzeppelin_interfaces::upgrades::IUpgradeable; + use openzeppelin_introspection::src5::SRC5Component; + use openzeppelin_upgrades::UpgradeableComponent; + use starknet::ClassHash; + + component!(path: Falcon512AccountComponent, storage: account, event: AccountEvent); + component!(path: SRC5Component, storage: src5, event: SRC5Event); + component!(path: SRC9Component, storage: src9, event: SRC9Event); + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent); + + // Falcon512Account Mixin + #[abi(embed_v0)] + pub(crate) impl Falcon512AccountMixinImpl = + Falcon512AccountComponent::Falcon512AccountMixinImpl< + ContractState, Falcon512ShakeDirectVerifier, + >; + impl Falcon512AccountInternalImpl = Falcon512AccountComponent::InternalImpl; + + // SRC9 + #[abi(embed_v0)] + impl OutsideExecutionV2Impl = + SRC9Component::OutsideExecutionV2Impl; + impl OutsideExecutionInternalImpl = SRC9Component::InternalImpl; + + // Upgradeable + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl; + + #[storage] + pub struct Storage { + #[substorage(v0)] + pub account: Falcon512AccountComponent::Storage, + #[substorage(v0)] + pub src5: SRC5Component::Storage, + #[substorage(v0)] + pub src9: SRC9Component::Storage, + #[substorage(v0)] + pub upgradeable: UpgradeableComponent::Storage, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + AccountEvent: Falcon512AccountComponent::Event, + #[flat] + SRC5Event: SRC5Component::Event, + #[flat] + SRC9Event: SRC9Component::Event, + #[flat] + UpgradeableEvent: UpgradeableComponent::Event, + } + + #[constructor] + pub fn constructor(ref self: ContractState, public_key: Array) { + self.account.initializer::(public_key); + self.src9.initializer(); + } + + #[abi(embed_v0)] + impl UpgradeableImpl of IUpgradeable { + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) { + self.account.assert_only_self(); + self.upgradeable.upgrade(new_class_hash); + } + } +} diff --git a/packages/presets/src/interfaces.cairo b/packages/presets/src/interfaces.cairo index f0d3228f8..98f848b2d 100644 --- a/packages/presets/src/interfaces.cairo +++ b/packages/presets/src/interfaces.cairo @@ -3,6 +3,7 @@ pub mod erc1155; pub mod erc20; pub mod erc721; pub mod eth_account; +pub mod falcon_512_account; pub mod meta_tx_v0; pub mod vesting; @@ -21,6 +22,10 @@ pub use eth_account::{ EthAccountUpgradeableABI, EthAccountUpgradeableABIDispatcher, EthAccountUpgradeableABIDispatcherTrait, }; +pub use falcon_512_account::{ + Falcon512AccountUpgradeableABI, Falcon512AccountUpgradeableABIDispatcher, + Falcon512AccountUpgradeableABIDispatcherTrait, +}; pub use meta_tx_v0::{ MetaTransactionV0ABI, MetaTransactionV0ABIDispatcher, MetaTransactionV0ABIDispatcherTrait, }; diff --git a/packages/presets/src/interfaces/falcon_512_account.cairo b/packages/presets/src/interfaces/falcon_512_account.cairo new file mode 100644 index 000000000..d26de0650 --- /dev/null +++ b/packages/presets/src/interfaces/falcon_512_account.cairo @@ -0,0 +1,45 @@ +use openzeppelin_interfaces::src9::OutsideExecution; +use starknet::ClassHash; +use starknet::account::Call; + +#[starknet::interface] +pub trait Falcon512AccountUpgradeableABI { + // ISRC6 + fn __execute__(self: @TState, calls: Array); + fn __validate__(self: @TState, calls: Array) -> felt252; + fn is_valid_signature(self: @TState, hash: felt252, signature: Array) -> felt252; + + // ISRC5 + fn supports_interface(self: @TState, interface_id: felt252) -> bool; + + // ISRC9 + fn execute_from_outside_v2( + ref self: TState, outside_execution: OutsideExecution, signature: Span, + ) -> Array>; + fn is_valid_outside_execution_nonce(self: @TState, nonce: felt252) -> bool; + + // IDeclarer + fn __validate_declare__(self: @TState, class_hash: felt252) -> felt252; + + // IFeltArrayDeployable + fn __validate_deploy__( + self: @TState, + class_hash: felt252, + contract_address_salt: felt252, + public_key: Array, + ) -> felt252; + + // IFeltArrayPublicKey + fn get_public_key(self: @TState) -> Array; + fn set_public_key(ref self: TState, new_public_key: Array, signature: Span); + + // ISRC6CamelOnly + fn isValidSignature(self: @TState, hash: felt252, signature: Array) -> felt252; + + // IFeltArrayPublicKeyCamel + fn getPublicKey(self: @TState) -> Array; + fn setPublicKey(ref self: TState, newPublicKey: Array, signature: Span); + + // IUpgradeable + fn upgrade(ref self: TState, new_class_hash: ClassHash); +} diff --git a/packages/presets/src/lib.cairo b/packages/presets/src/lib.cairo index a06b38d28..0c36b9eb8 100644 --- a/packages/presets/src/lib.cairo +++ b/packages/presets/src/lib.cairo @@ -3,6 +3,16 @@ pub mod erc1155; pub mod erc20; pub mod erc721; pub mod eth_account; +#[cfg(not(test))] +pub mod falcon_512_shake_account; +#[cfg(test)] +#[cfg(feature: 'falcon_presets_tests')] +pub mod falcon_512_shake_account; +#[cfg(not(test))] +pub mod falcon_512_shake_direct_account; +#[cfg(test)] +#[cfg(feature: 'falcon_presets_tests')] +pub mod falcon_512_shake_direct_account; pub mod interfaces; pub mod meta_tx_v0; @@ -17,6 +27,16 @@ pub use erc1155::ERC1155Upgradeable; pub use erc20::ERC20Upgradeable; pub use erc721::ERC721Upgradeable; pub use eth_account::EthAccountUpgradeable; +#[cfg(not(test))] +pub use falcon_512_shake_account::Falcon512ShakeAccountUpgradeable; +#[cfg(test)] +#[cfg(feature: 'falcon_presets_tests')] +pub use falcon_512_shake_account::Falcon512ShakeAccountUpgradeable; +#[cfg(not(test))] +pub use falcon_512_shake_direct_account::Falcon512ShakeDirectAccountUpgradeable; +#[cfg(test)] +#[cfg(feature: 'falcon_presets_tests')] +pub use falcon_512_shake_direct_account::Falcon512ShakeDirectAccountUpgradeable; pub use meta_tx_v0::MetaTransactionV0; pub use universal_deployer::UniversalDeployer; pub use vesting::VestingWallet; diff --git a/packages/presets/src/tests.cairo b/packages/presets/src/tests.cairo index 726e1da2d..72d95c446 100644 --- a/packages/presets/src/tests.cairo +++ b/packages/presets/src/tests.cairo @@ -3,6 +3,8 @@ mod test_erc1155; mod test_erc20; mod test_erc721; mod test_eth_account; +#[cfg(feature: 'falcon_presets_tests')] +mod test_falcon_512_accounts; mod test_meta_tx_v0; mod test_universal_deployer; mod test_vesting; diff --git a/packages/presets/src/tests/test_falcon_512_accounts.cairo b/packages/presets/src/tests/test_falcon_512_accounts.cairo new file mode 100644 index 000000000..2146efa89 --- /dev/null +++ b/packages/presets/src/tests/test_falcon_512_accounts.cairo @@ -0,0 +1,213 @@ +use openzeppelin_account::extensions::SRC9Component::SNIP12MetadataImpl; +use openzeppelin_account::extensions::src9::snip12_utils::OutsideExecutionStructHash; +use openzeppelin_interfaces::accounts::{ + FeltArrayAccountABIDispatcher, FeltArrayAccountABIDispatcherTrait, ISRC6_ID, +}; +use openzeppelin_interfaces::introspection::{ISRC5Dispatcher, ISRC5DispatcherTrait, ISRC5_ID}; +use openzeppelin_interfaces::src9::{ + ISRC9_V2Dispatcher, ISRC9_V2DispatcherTrait, ISRC9_V2_ID, OutsideExecution, +}; +use openzeppelin_interfaces::upgrades::{IUpgradeableDispatcher, IUpgradeableDispatcherTrait}; +use openzeppelin_test_common::falcon_512::fixture::{msg, public_key, signature}; +use openzeppelin_test_common::falcon_512::rotation_fixture::{ + accept_ownership_hash, accept_ownership_signature, account_address, new_public_key, + outside_execution_hash, outside_execution_signature, +}; +use openzeppelin_testing as utils; +use openzeppelin_testing::constants::CLASS_HASH_ZERO; +use openzeppelin_utils::cryptography::snip12::OffchainMessageHash; +use snforge_std::{ + start_cheat_block_timestamp_global, start_cheat_caller_address, start_cheat_chain_id_global, +}; +use starknet::ContractAddress; + +const DIRECT_SIGNATURE_FELTS: u32 = 31; + +fn copy_prefix(mut values: Span, length: u32) -> Array { + let mut output = array![]; + let mut index = 0; + while index != length { + output.append(*values.pop_front().unwrap()); + index += 1; + } + output +} + +fn direct_signature() -> Array { + copy_prefix(signature().span(), DIRECT_SIGNATURE_FELTS) +} + +fn direct_accept_ownership_signature() -> Array { + copy_prefix(accept_ownership_signature().span(), DIRECT_SIGNATURE_FELTS) +} + +fn deploy(class_name: ByteArray) -> FeltArrayAccountABIDispatcher { + let mut calldata = array![]; + public_key().serialize(ref calldata); + let contract_address = utils::declare_and_deploy(class_name, calldata); + FeltArrayAccountABIDispatcher { contract_address } +} + +fn deploy_at( + class_name: ByteArray, contract_address: ContractAddress, +) -> FeltArrayAccountABIDispatcher { + let contract_class = utils::declare_class(class_name); + let mut calldata = array![]; + public_key().serialize(ref calldata); + utils::deploy_at(contract_class, contract_address, calldata); + FeltArrayAccountABIDispatcher { contract_address } +} + +fn deploy_with_new_key_at(class_name: ByteArray) -> FeltArrayAccountABIDispatcher { + let contract_class = utils::declare_class(class_name); + let mut calldata = array![]; + new_public_key().serialize(ref calldata); + let contract_address = account_address(); + utils::deploy_at(contract_class, contract_address, calldata); + FeltArrayAccountABIDispatcher { contract_address } +} + +fn assert_constructor_interfaces_and_signature( + class_name: ByteArray, valid_signature: Array, +) { + let account = deploy(class_name); + assert_eq!(account.get_public_key().span(), public_key().span()); + assert_eq!(account.is_valid_signature(msg(), valid_signature), starknet::VALIDATED); + + let src5 = ISRC5Dispatcher { contract_address: account.contract_address }; + assert!(src5.supports_interface(ISRC5_ID)); + assert!(src5.supports_interface(ISRC6_ID)); + assert!(src5.supports_interface(ISRC9_V2_ID)); +} + +#[test] +fn test_falcon_presets_initialize_interfaces_and_variant_verifiers() { + assert_constructor_interfaces_and_signature("Falcon512ShakeAccountUpgradeable", signature()); + assert_constructor_interfaces_and_signature( + "Falcon512ShakeDirectAccountUpgradeable", direct_signature(), + ); +} + +fn assert_src9_with_real_signature(class_name: ByteArray, valid_signature: Array) { + let account = deploy_with_new_key_at(class_name); + let src9 = ISRC9_V2Dispatcher { contract_address: account.contract_address }; + let nonce = 5; + let calls = array![]; + let outside_execution = OutsideExecution { + caller: 'ANY_CALLER'.try_into().unwrap(), + nonce, + execute_after: 10, + execute_before: 20, + calls: calls.span(), + }; + + start_cheat_chain_id_global('SN_SEPOLIA'); + assert_eq!( + outside_execution.get_message_hash(account.contract_address), outside_execution_hash(), + ); + start_cheat_block_timestamp_global(15); + + assert!(src9.is_valid_outside_execution_nonce(nonce)); + src9.execute_from_outside_v2(outside_execution, valid_signature.span()); + assert!(!src9.is_valid_outside_execution_nonce(nonce)); +} + +#[test] +fn test_falcon_shake_preset_executes_from_outside_with_real_signature() { + assert_src9_with_real_signature( + "Falcon512ShakeAccountUpgradeable", outside_execution_signature(), + ); +} + +#[test] +fn test_falcon_shake_direct_preset_executes_from_outside_with_real_signature() { + assert_src9_with_real_signature( + "Falcon512ShakeDirectAccountUpgradeable", + copy_prefix(outside_execution_signature().span(), DIRECT_SIGNATURE_FELTS), + ); +} + +fn execute_src9_with_invalid_signature(class_name: ByteArray) { + let account = deploy(class_name); + let src9 = ISRC9_V2Dispatcher { contract_address: account.contract_address }; + let outside_execution = OutsideExecution { + caller: 'ANY_CALLER'.try_into().unwrap(), + nonce: 5, + execute_after: 10, + execute_before: 20, + calls: array![].span(), + }; + + start_cheat_block_timestamp_global(15); + src9.execute_from_outside_v2(outside_execution, array![].span()); +} + +#[test] +#[should_panic(expected: 'SRC9: invalid signature')] +fn test_falcon_shake_preset_routes_src9_signature_validation() { + execute_src9_with_invalid_signature("Falcon512ShakeAccountUpgradeable"); +} + +#[test] +#[should_panic(expected: 'SRC9: invalid signature')] +fn test_falcon_shake_direct_preset_routes_src9_signature_validation() { + execute_src9_with_invalid_signature("Falcon512ShakeDirectAccountUpgradeable"); +} + +fn reject_unauthorized_upgrade(class_name: ByteArray) { + let account = deploy(class_name); + IUpgradeableDispatcher { contract_address: account.contract_address }.upgrade(CLASS_HASH_ZERO); +} + +#[test] +#[should_panic(expected: 'Falcon512: unauthorized')] +fn test_falcon_shake_preset_rejects_unauthorized_upgrade() { + reject_unauthorized_upgrade("Falcon512ShakeAccountUpgradeable"); +} + +#[test] +#[should_panic(expected: 'Falcon512: unauthorized')] +fn test_falcon_shake_direct_preset_rejects_unauthorized_upgrade() { + reject_unauthorized_upgrade("Falcon512ShakeDirectAccountUpgradeable"); +} + +fn assert_rotation_survives_cross_variant_upgrade( + source_class_name: ByteArray, + target_class_name: ByteArray, + rotation_signature: Array, + post_upgrade_signature: Array, +) { + let address = account_address(); + let account = deploy_at(source_class_name, address); + start_cheat_caller_address(address, address); + account.set_public_key(new_public_key(), rotation_signature.span()); + + let target_class_hash = utils::declare_class(target_class_name).class_hash; + IUpgradeableDispatcher { contract_address: address }.upgrade(target_class_hash); + + assert_eq!(account.get_public_key().span(), new_public_key().span()); + assert_eq!( + account.is_valid_signature(accept_ownership_hash(), post_upgrade_signature), + starknet::VALIDATED, + ); +} + +#[test] +fn test_falcon_shake_preset_storage_survives_upgrade_to_direct_variant() { + assert_rotation_survives_cross_variant_upgrade( + "Falcon512ShakeAccountUpgradeable", + "Falcon512ShakeDirectAccountUpgradeable", + accept_ownership_signature(), + direct_accept_ownership_signature(), + ); +} + +#[test] +fn test_falcon_shake_direct_preset_storage_survives_upgrade_to_hint_variant() { + assert_rotation_survives_cross_variant_upgrade( + "Falcon512ShakeDirectAccountUpgradeable", + "Falcon512ShakeAccountUpgradeable", + direct_accept_ownership_signature(), + accept_ownership_signature(), + ); +} diff --git a/packages/test_common/src/falcon_512.cairo b/packages/test_common/src/falcon_512.cairo new file mode 100644 index 000000000..36ad16180 --- /dev/null +++ b/packages/test_common/src/falcon_512.cairo @@ -0,0 +1,2 @@ +pub mod fixture; +pub mod rotation_fixture; diff --git a/packages/test_common/src/falcon_512/fixture.cairo b/packages/test_common/src/falcon_512/fixture.cairo new file mode 100644 index 000000000..1f478f1a8 --- /dev/null +++ b/packages/test_common/src/falcon_512/fixture.cairo @@ -0,0 +1,111 @@ +//! Fixed test vector for the Falcon-512 submission algorithm. +//! +//! The public key and signature were produced with the `tprest/falcon.py` Falcon-512 signer using +//! its SHAKE-256 hash-to-point over `msg()`, then packed with the accounts' Cairo-specific felt +//! encoding. This is not an FN-DSA (FIPS 206) conformance vector. +//! Salt: `0x4ad23197d576f705594ac172f4fca80e3338e991b8b55e269d421aa1522cd0aa2490034127651fc2`. + +/// Fixed reference message felt (`'BENCH_MSG'`) used by this fixture. +pub fn msg() -> felt252 { + 1222479111879746474823 +} + +/// Packed NTT-domain public key h (29 felts). +pub fn public_key() -> Array { + array![ + 0x4b5883f5c89b0d4556d3c04683f7773007c23e91e17fd81f7c07e44e1723b16, + 0x80828f753351be72b867969629e57f03c53eec73696ed2a42f46e0731ebd18, + 0xa3526ad70f16bd9a22c88f50b6827e0313e613847af64b94c907ee28fddfba, + 0x4c00d1147cd00b633e46aea6dd7b821029a674204e7684da2a46353e1bef622, + 0x38e739bf5c8e77dff055d5ca6fc46f30134a2f6761fcde7291a84b642cc8870, + 0x2f15c3f7c1440e382e190c38c1405090314d0f38571505dbd139c39f2b16f11, + 0x5f608e2270192abd47c2b841f226520173d949c07dec39370e3fde1d38f5bc, + 0x29e50592fdb70623642bc59db478bbc017345a2ef3c8aa24fcfb8fbdbad82d9, + 0x24d3c1f17b53784199b2ba981fa556a0119d898c9752789105fff98c1b9cd76, + 0x9f5217536d557a0554fa6981843049023a282890b2c50117e7b06f23aa46b6, + 0x14e85ff168a577fdcf4645c2737f54002181be04e75f31f37e647b665cd71e2, + 0x4ed6d9d92397dd450dade5c08473a401ade31eba36b0058303b60540e141d6, + 0x4962bdf39b526379cc6f943a8651f4a009eb2008a088bdf0c700cd8f8b707ff, + 0x1e5722f7a6b5849d2dba1482e1b6c9f0176383d44cec027385c9ee3b60adccf, + 0x32ddae92481958f566883e90d9db7c5040b7b5cfb4768a8f4fd03aa33151687, + 0x2a40da74f65c493097754208c90f4e1032412af5c4c07ecd5551108bd89e6d7, + 0x4445ae0aaaa0249d4de7e2fc77a49ba016ece2eae0297ad2e2e617b5f36ed8d, + 0x4323277a8e1ebd7cdfe0b0b291277cb03138b7e1aac1316213f3b8093bcf0ae, + 0x48db6dc62abdf00d5a4f00f67486fce040f0b092dbf4f512b975f7dd8e3867b, + 0x367deb3eeb11eefda6708f11dc0138004d0534582489f8fafb2f2fd47f371d, + 0x40752ed0116a666130d5b8cc3746a400287fab22f80a41057b56bf8a54db3a6, + 0x3843a1c0c723b9abd43c6fb84928f6a028232d1102eb631ce1e7de44c871599, + 0x303137e0620a78b84c0dfb2b44a322026c291b4f357c1beef235e802a5939a, + 0x3d8037ba551320cc9be7f4b14e1ebe1000c59f734b66e3fdd527d41a1200860, + 0x1fbd87f9480222de9609ebda655338b04353863afce87ee3ed6349e66389e15, + 0x2f08581081c3f60a0c58b7e4d70c45103c1ea9f33e76209c09340a06cf990d3, + 0x34f19aad64c761cc21f74cf4554f8a00611661c1596564c01ba296469d4c54, + 0x1627799a0710d18e5a2d46127da74f0040fdb0167400b5927ee792de206e8b9, + 0x168f7f69a1d0308fa7b6a298cea8, + ] +} + +/// Signature: packed s1 (29 felts) || salt (2 felts) || packed mul_hint (29 felts). +pub fn signature() -> Array { + array![ + 0xc3876e3982b541f962e4f77ff8382000c1f7eb26dc69208bab3afdc3dc1d0, + 0x4c12a028535570b1ba507ce01cc515304b2f01b9554ceec9023ab26b30f105e, + 0x7b7405cb5587555e7d99b9d65225b0005e8e09b2b645a4a11b3a3c5bc0fa2, + 0x4b90c64a108041f3dbce09cc6a91f1900279253640884bc8434a2fbf9c6c264, + 0x4cc2ec3bd4d44bd43cafa7ae0b83edf001b8c67cdce1653683c34850b9393db, + 0x59cb22d890fb18658c1d0d8ea206100178a97902b5adf97845649c0281f92, + 0x4ce48f8b68eff13a34c337d9e01acd700193e8ac7c158019b329e7a0917cfe4, + 0x4b5a55606078b3e0bc98ff6b219710c0006b716700749407bb9c7e45ec39499, + 0x5020f0241dc5f42b38ad5eff0310f0009d1a3470afdab515ace284180ff6d, + 0x81d4f61c65ececef5a64a1fbad2d000175733e7e7e1b3febff606bf0b2fcb, + 0x4b0d5b1b5547a96157ada24d1836da404cb9552b1834b1762c5be67eb82bd76, + 0xa389199f55f1e4bdda4285fcf933d04c0f66970291d36368569e1b3704f28, + 0x4c9618f6ec02f9b9bb8fdd066e6d4670007b69f057ec7e5d2271a362bc6ddd2, + 0xe6c9028315d81274dcf007bb761fb0014a35dcc154df026ee2da9cf6d4ef9, + 0x4c512ded713bd52e8ffcf4d829bb01504c6783ff3d7697f39e04296799dfa44, + 0x4cd7c362fcd15d9683f84d07627d2610009eb09842f9be47ce597b19758af46, + 0x2342c2f878bdfbbf4ddb714447317c0000b3106f585585761e9f927c055e00, + 0x12bb87c597fbe680e7f3be18d4513604cbae51d0ec49525ec7e1bf47d36005, + 0x4ce639a281d0ecab39e59b828bf3feb04cb14fc8dcd4037cbafd2218af7bf45, + 0x1c5997da66c46510de044b2039e07404bff62803296c615893c6de7628519d, + 0x34e51bc4d8704b0e55abaf32f804204c51240b70f81d7936168a5523dfeb2, + 0x4c4453721150ab5ffb65c9e75f2e08304bef585531b0898edd50c55d0019ffc, + 0x1c40344b02b6ba74a6c2e5792ad0c100058266388043d278b0d608094a3299, + 0x4ca7b1ac5802cb8c22a18dfbf2cf20804c4de9022dfb608b3974059dd5feed3, + 0x4c3de0cfec3b63c7468556d7ea4af24000280c43023a9756b0fba3cf730fda4, + 0xc060cb704a3a464022f951996321e000380a602e6ac8fd8ff9e30c28eefb7, + 0x188ac6d6736d1058c8cf45a1cfc0de04bac0cefe9a65354de0d9fdcdec215a, + 0x7509d6424f2debe0e4ca0e2e7e085000a05000229fbffa62948066e727277, + 0x199a938840456e14796bb66d9ebb, 0x91e938330ea8fcf472c14a5905f776d59731d24a, + 0xc21f652741039024aad02c52a11a429d265eb5b8, + 0x107be11221f9c4b7381cf0c3970444f03701fbcc120a592b8121062e5b59b9a, + 0x1e44009df2457c77dacad9b85613b650185cea7da868df396b735f790e36edb, + 0xb99d364347b55e7f73e01761fe10b301194ac214fbad5128efd03c4e56b82c, + 0x220473e38c276e61815e5384cb3612801250c05d9ebf0099d6da0a94885de10, + 0x1c58455b7629f447c77aa9773af7ffe02d094284c08cb92fdfe41cd0b098b50, + 0xaec193cb1033aa746adea102dd829a04c724ddad243a4d6ba745f9c6cccb78, + 0x34bd9bf4ff6a789a4208c1a4feb5c8a00b76706eda239e170496b046c555f4d, + 0x20dd278182b85864a1218708ae9a78003f80ee5d5aa23e76f865ebfae119d17, + 0x56516fef301e3a0f8f7b206b5bf53e01f42a57a26c2bf7ced9430a25c75617, + 0x4be6010beac3f16464bbc71723cdbb8029b329a07e2c9032d603e14048d5488, + 0x13eab76df94131e0fb4e903ca57caeb0423778dfb37815e87b5f70f622e6498, + 0x61317a493aad9b43e3e0c6bfb86b1b043cbe3e29d79a80f71887dc427a79c3, + 0x2e9667e027151b686f33ebbccc12e2b020b21c61b50ee07e71b3ae9b86290d4, + 0xc3a660592015363eabca73a1a3523f045d06263282512faf6c0ab10c6468a3, + 0x1faba087a7577afe1a5a21e51d7cdb0044d90ddfaa348b6a341dc26222576ae, + 0x34552f457ee4bc2e897521604c4ed63026eb0a14d1d9c18c9b069c7b14f78c9, + 0x786e4c34f2393cfb6c8bdfea0606a602e85c417aa840aaccc320f69eb64a60, + 0xf890af43edfa6cdbc89198d829749702914725c367eb262dd7141723152f51, + 0x49d602c25063dc3518ab42d7c9287ac00c41590eea487fea340a8d9eb66b1d3, + 0x1c8306b4665fa20daf5b8bd4deb5c34047bfabcfad5c16ee6a3e5987e0dc17d, + 0x43e929dbb8942b8b0947f95cd683da600684e1f86e95272f4710dad3ed04d0f, + 0x8617cd70a49f8bc9305336233784e101f2dda080df6c21f4a160b891828bdd, + 0x9056f9a67d7852ac619169ec80e8cb010080f040f169c7e84d213297708091, + 0x2687075c64f19db4f68fcc9612919d201d434101448db72e4300ecf097e0795, + 0x23122edeaeef1949ad8c7724d755485044272d01aa40fd080c80c15f4075a07, + 0x1edf55a60cd99472510ee283f06576f049cce7d601e6a0dab3c7ff637df457f, + 0x26a621693f4b69a4b92d89efdbf558f02ce0f378d7a885a1637c4dac8a341a6, + 0x2bbb2baf68ae0d7c9bd4f8b21e476ab019fc66a54b84c25e34f54146d62dc29, + 0x7706513a985e051d497fc9cb2a3, + ] +} diff --git a/packages/test_common/src/falcon_512/rotation_fixture.cairo b/packages/test_common/src/falcon_512/rotation_fixture.cairo new file mode 100644 index 000000000..315380e26 --- /dev/null +++ b/packages/test_common/src/falcon_512/rotation_fixture.cairo @@ -0,0 +1,269 @@ +//! Fixed Falcon-512 account integration test vectors. +//! +//! The vectors cover new-owner acceptance, same-key rotation, and SRC9 outside execution for +//! `account_address()`. Their keys and signatures were generated with the +//! `tprest/falcon.py`-based test signer and use the accounts' Cairo-specific felt encoding. This +//! test material must not be used in production. + +/// Fixed address used to domain-separate the ownership-acceptance fixture. +pub fn account_address() -> starknet::ContractAddress { + 'FALCON_ACCOUNT'.try_into().unwrap() +} + +/// Poseidon('StarkNet Message', 'accept_ownership', account, current-key GUID). +pub fn accept_ownership_hash() -> felt252 { + 0x4e62665f5de5d234888da2b01cedcd1c3ed0b70149a6697d6c881b38021c0a +} + +/// Poseidon hash of [`super::fixture::public_key()`]. +pub fn current_owner_guid() -> felt252 { + 0x1c017f6368c49d94e2fee2cebcac6def11fd9d75dd9042216f630dac0376c4 +} + +/// Poseidon hash of `new_public_key()`. +pub fn new_owner_guid() -> felt252 { + 0x17705763a1277b0c72cc319dc0015046911575a5f00c2c4b8cde3936383f329 +} + +/// Canonical packed NTT-domain public key for the prospective owner (29 felts). +pub fn new_public_key() -> Array { + array![ + 0x9b070736af5cc06617e666684c2c7a010403b7d0d19dcd9cfb81189549805a, + 0x3d105fa9ae5ebb1b395b209f52d2573037aaf140a400f46abd8dd88dd6bdf7a, + 0x2694f8a86e7b5f43eb110a59677216700618c8a3a24b3da4a136121a564d51f, + 0x4c5b14d67f4e0ae3284ffe2cf65677104377bac0d860555878e6ef1b5583b1d, + 0x29821d15055be2309a227e2cfe5fb85009a17b780fa8d28df54501b358df83f, + 0x3e89a91ad7b8c9eff39374bd52a35af04860b1e7c93b895d23a1d46691aa38e, + 0x3a0a0e611b4b5b5649299d1598ee6a700038a82c8b1ab80dc941940c3a9b2a2, + 0x10c18aa9ac68d713ef720a31f5da2ec0095ca428486417acb8c8e6167201c0d, + 0x15f41c81e8885ac8dc01893ca65f02f0012a1eb6c967961eb0c945ad748ff50, + 0x4618beaf0197e17ec3689c5d36748c60318ee55414b85514a60dfb56eeeb4fa, + 0x30b879e8c0410e99f348217c18e22ff02afa0e5dbbd08207a5ccfa79a3ba625, + 0xaf0fb6daf59003db42f43df88cc0c001f679d7b48f67daa7d356a4bf336496, + 0x304d57e2461c9696b912a8206b978e03259bc45470546e4dcb6a9ce8eae372, + 0x4c43cc880b89ce551b791d3ffe6c42f009226ebf2cda7e1589ddb048ef3e285, + 0xded1a3261b45f5cd48b998fb4bb7730039227a60c74e3642f6d804088059ad, + 0x24738b37ff4970f0ebb3413c2ba80aa007537f5375e541b5de331bd24b7964b, + 0x635f5e913d93fe5fe967be72cb5ffe00f597198816fe0e7bc6f593e8b2f289, + 0x3bc65b96f0e1895aec8212134d4df4e00e6c187e4e5662b17c5617ea2c879d8, + 0x31953229396e87504f366de96ff81aa049eb9685294b798510c9dc6f33f2ead, + 0x4ad02aa854a2437211d0d932218492a041509375f9aa07aa048bb1f026fcb47, + 0x228372a2c3a4aa5ad081c14e1e59c9401d9cf3b670a57b74fe0db6212101354, + 0x21c5182aae8a80ee8120ac5b28da11302462b1cfd8cb8d9bd365d91679746ed, + 0x9142b61620f1a9aa1559d64dc947080439cfc2ed631f67e0c6fb24c89f45c1, + 0x2aff191772041447ab79b5119d20dce032df5801359ae786d30a36a58720526, + 0x5c960381a0f084fd1ee7ce1857eb67033be15d10c22561eb8a64c5bfe11316, + 0x21cb99b175511bae8b10c81fb384a5c0200267514bd3e78f1994f2e84145fd7, + 0x954ba16dc3cac58842d592273f5b3c0475157535e4e9968a4871791acb7386, + 0xc01619ea6b19c34f0902ea4cc8b069038f4b28106b81377424a847f2085a17, + 0xde26e4af2b41471a826a610f23, + ] +} + +/// New-owner acceptance signature: packed s1 (29) || salt (2) || packed mul_hint (29). +pub fn accept_ownership_signature() -> Array { + array![ + 0x4bd8ec4b708072cf5362a321179003104c4c50f2f986221418a96705d433e21, + 0x682d1dd0c5881eafd35aad9c5a05004c3c4b52b7899b42010ff2db7a09ea7, + 0x4bcf491b89f52b5761724a3ed302d3c04a9d2a827e2d772b1dba258c109e061, + 0x4cb7b76eaed906a150d9823d31e401a000f0789e016141e0e61d630e037620c, + 0x4ca479be1a133af9811cf86a5c8419804cafb98fbc2fe39f3ffd0227ae0bfd5, + 0x8843b018a692af92a60d55ef6c0f404c45ebbcd7200c8fcde396048d60f7b, + 0x3684c7f6455c3ebedc50b87e6e3100002b4b459193d1fbe8018ce82d07205, + 0x15d6b684829414103090f0acfa244004c22a91f8cbfce474932d0b0c977d30, + 0x4bb8eb0f19aeab46b0ab070e25d9eee0018716d703d665410dd1b7e06b3e33d, + 0x20051b97b1f6401e7370a9a856f8c04bf8fb1e92fe2f3e34d6ebd0520410c, + 0x4c6f99cf11fa6e33d2dcd6af8f1ef680015096fff3b3843a2344bf73282e10a, + 0x4bff61f774e0dfb3f7ba80db4d45e0800024e47d9a97b6e5d5553418b900f3b, + 0x4cb2efb086aa5a742ef1c4b974c1f93000dd36a707a965312c194d0248201c3, + 0x1b58fecee0992b9f0186698ec08dda04cd961526e4dd80ffddc3efb6e4102f, + 0x670cc2ab87dbc109614e10c1216d000199ec2f99bb899210e0d8aa887dca, + 0x1121559d16b57083725a7c4450ff1d04b2efc2e37bef4ce4e025a4b5d3bdac, + 0x10d4b09495173bef015ace4c4742d100133c5597b3536d964f822a9ab5920e, + 0x14a2c0beb5f158385759e697b3007700031abd747c7673a628ab03204840d2, + 0x4d3c35bfc4f8715a7f410d1f7fb700190b9ca868f4293e5c45d6486952bc, + 0x4c32b8d5115b731c281a64faf771f41000581f4f296cf908ab2824d9994dd10, + 0x4cbc868e17e7b77d10c1b48c396fe0a0016a3ee08207552926538c060cc6edb, + 0x4c5c578270640554c6cb3ab47f89e2e0009d1a09de5d7c6bc748f92e382f280, + 0x148939e89bd4db9d0112f86248ef9d000bebd61ee851f36798bf21c546e024, + 0x1b8ca5c92eb2579225e1d8b97473b604c00fb06ee864994613ce35ea88fe38, + 0x4cd7ce67945ef3495c008b3a6f772d00000cc8c0900072370feea11b30c2e57, + 0x4cc15557cd85bfc94965eff5ff3702004b3a463771c9ca43dc9a1def3da301f, + 0x2349b1df9e95f8f4dc72c0f485e6f0002818f34ad3cba8aaf05594b569f55, + 0x2ceafa0c7661bbbce90a817b93f4004c1ddee8c80545132781b09382f909d, + 0x2ac0257769127e5984194dffa7, 0xbd04ce759c492d07b19bef74d71ee6fe2c6395c5, + 0x91d81fd4340aa00431b4cb75587540af14d8cd73, + 0x1051c709c87ed0445c766e7cb5ce8d102f5c042846f698e5fc38c5e857fd1fd, + 0x33a47a815b695b237c57076db0c52a200004480aaf9dcc50aa38773f164f4dc, + 0x4390c80587c953957fcefa0e96dcc850440e3d33c5583abb53202486512e0a4, + 0x3c8efd9742450d383641fd61b3d7a02049633f66b708801f9532f736f391f20, + 0x16107b9eb461c7ff459a0ad99e6ac220457638e26fd7e221362aa67342d9826, + 0x3f8260d83f17fd3b24a27aa8a6959910468a44bdffb5c5d64c9f931b7988be3, + 0x40dcb437664f302fad3f828a550872704a05df1259b31c4c233e4044c1356e6, + 0xde82db0bc2ed4ff11f929b77c2e7f200835825cfda5cf4f03898bb0019247f, + 0x412b08e780e1f7ce2e8d0a50ec37587029252efc28f902ec0fba7d47848e8a3, + 0x62c7a63f8b9a78fa9eb0492dac515c046c1f24110314f4077f6a6a9d77e25e, + 0x479886cb05345c99f609266a1d8569b01ca8ebc4be002168db76c630b929778, + 0x165f97ff7005bee86cbc640c08125da0116dee775768d8433a85bcca04f6e25, + 0x3707f6ac5cc25764e1f0757d62ef37d0031c625e8e57d997e71eac2dc20afce, + 0x455a010b4d551da4227f72a230bb870012fd860df39a89a1cac1237bffb3e1a, + 0x2fbb2ee1ee08124eb7084684d1c369a002c38bd7ccd46459727513fd77b15bb, + 0x21a74007a1dff2da04d072b76d1add20372e72f5ed1a02bda91535ade25edcd, + 0xc00f854df5ecd9dd59049957e61fde01b991a7eac5d5123fb99890eb3352d5, + 0x23b2f5f09b53b3a601ee8b403f163750195079f2d3e4270bd141c7d999ade24, + 0x198ddc376c9a5a0648588085f81c5600483d075e2a001f9974e300d587fcbc3, + 0x8ad58028cdd0578a90382530b80be20189a0a470f9e99d937b509012dd9d5c, + 0x5954442e51ac54bb521a781d4e792c00fffc93bc98ab740780e791e080101f, + 0x3189c3e2ef880bd48ebda2c66f4231e020f638f7dd8749cc6cf00aff4901fa5, + 0x1a75769c1e41cee70b2312b20b67258035a064e284fad5933762f822c7273b5, + 0xb5d36ab5affdbda6cffc2e601a645f0399e06eaabb0ad78e291a855104e00e, + 0x28a06c02fef981a16947d57bf3faaf4008b85a687096d718050986984c421cd, + 0xdb421cb4f9bdd7862d60e0fe301e57000932b740701f2c68bb4314ec7c9154, + 0x70d7172e53b99f0af6f88646f278cc0271114547953f07d1de373a5502741c, + 0x1dd222aacd445fdb26c808596ac28a701b9c25fc954b15c6794e9aa9ee1ee0f, + 0xcbd8a83727b237f7924603d6f19, + ] +} + +/// Ownership-acceptance hash after the first rotation, when `new_public_key()` is current. +pub fn second_accept_ownership_hash() -> felt252 { + 0x2ab9ca182c4cf47c5a03e1d9a614497b148d52814e8837f308fb0aa02355dc8 +} + +/// Acceptance signature for a same-key rotation while `new_public_key()` is current. +pub fn second_accept_ownership_signature() -> Array { + array![ + 0xf6d56a03695a92ffe10775fa7611a000a51ff4f283bb2847933b6b46f5eea, + 0x4c52c22e48128d903d26dc818aa4ff9001308679147aa1b50c818d6f7960081, + 0x1cda19343fb81d5c2a6054167effe04c2de6d6aebf21e18215c7bd14111fd, + 0x4ceb06a7628ff5c6409704547ceb22f04cdb083d3464003540961d43df3527e, + 0x4afbb4b4e2f119f4a8e971ddc3eaaf804bfa98275513f2cfd8375ffd6210e53, + 0x123b5f938153dd7902054277d0215a04cd62c9889dbdf0bc58f394bac6af46, + 0x14ddee0c94522c499966e1c2091ce00190bacb3802a97a92036e39040f0c5, + 0x123ba47f5485065bdff8eae8d26dce000435101956a0b4900a88390881c1e2, + 0x4cc7ca72d7fc275a8cb0ee4ce1850a60006e9a3d902c7d37295d0a3ed071f3a, + 0x4cc7bce46ff6df3ccfc83dab3a08f300000337f7035642fd85e7fb3fd3ecec5, + 0x4be8f7d4a0f93f61133f0441bdcab900013ef309b7f513071a7733cb7bdff2a, + 0x1d0defcd31553708a3f593dd830452000dec56dd02d514ba9a2b4c5e9e1149, + 0x4c0f6541464f2e84c82e2fd68b83eba0007ea1d620956d88167b99facaf8ef9, + 0x435413ba2c43207cfbf6bebaccf4e001cd9d5f6576b6401d33c64a98972e4, + 0x1a8b693f6eeabfa3d47182b4f28ecd00044e639ff42a16b8fb6958d5307d65, + 0x19bec6c21a4f0e20e689608003d1860007d0712b9f2b61fb972c2e1466c057, + 0x9046111643fbfe65be14273eaa1fb04bdc1d5030de30442f17fd79009df32, + 0x4bc41be307f769a3c05aeab5c4973e204ca2e5b932f65c33e953d8cd012e1c6, + 0x4c8adabefbdc970c0481de0e1cb9caa0001cdf3d790d63e620974f7aea32101, + 0x4bad994f2bc99764172ead9fcae9e1804cf168caf55b79f2af8d5c9c6b6def2, + 0x4c6dfaa37616f3124baaff11d0f3f4204c05c983c15209ae3911844ab541eba, + 0x4cd494f00a89cdf59d25c9c4db8be4004bb26fe0ba360f33d5462c90997ad99, + 0x21c2b6d53bd45d793420de8849105b04bda867d88bdd6dba4b6cf233ab707e, + 0x4c12a00ed61d48357079ee45b0bdf79000119eda7b00337f972f2d5b65b8f4d, + 0xf3a2ecf437af67a652d6c8b7fa2e000102156f4fde082d083625a15b0651d, + 0x4c1c340499152699b95a9ea8c14c04804bd752551c5c7635ed809c79309ae55, + 0x89d8e03437810f4f415d546c9910b04b98d058fc077f3f2be07e327a70d3d, + 0x4c779a6b3a8957a87a28b191b146f4004c6ac2791b07cee011241595bfec002, + 0x3bdf29415cc9d5cb3be966024, 0xd60ab6224f871c2728630186e556c5a368417228, + 0x2f1dc6f52c185b6fadb36c8b7ccbc2b4fb8768a4, + 0x2d434c43fa92349a139c616b7f836e202606f3858fb183df65884be39c9ec60, + 0x1905f098212a5f47a15a742176fcc7a0238f7d9f2864917b92643d27fc57485, + 0x268e77449f3f343b765f09d69ec5d24049d08677fad8a5dca0a42bf9ea34e5c, + 0x47cc402067f87b327b4769e5d8bd10e02f9cba4965f5ce37d20adb0a91389e4, + 0x3bb6230a52112dd5a9d9c28d7f364f802729533298307a4e01b00452c7a395d, + 0x42cb68d1a7bf40213dc9d3a3d8f4bea0016b6f4d7e2c114a836a513023cfc03, + 0x6545893784155df10281b3917ba2aa023832c31b682917bf38a9089a418531, + 0x4c28826494541bb9256069dc7cabf8700f9c08e290584cbfa7d63d196145b3b, + 0xedbca298596adff6b29858b9dabec20418f2e1bfcb2de3f1d51acf264e395c, + 0x96a610c80c21bade198c8067d27a1c025afdda83b9b9e589b73a68a0476eb0, + 0xd079e08398ba8dec496fd23107fb04cba3e3ec170207d2927e13500743ea, + 0x155e559c66e2e6c61ce66cb3024d57f034a0161959ee88aa2277d0369b5b9e7, + 0x238f54118a964f827bfbf5fc7c3102f04478f428498dd170fb970e7bd1cf581, + 0x1d719db1c7ee057e314ad8b7de1cece02896b5174f59aa612631e1e5fef0e0b, + 0x4fa2c0d8474e2fcc4b8915cbc9724002681edca710d94538af3a39f7988ccc, + 0x2f8416195d0eeee50f141ff5d8c33fc04b71b2e65d4ca630649f52bfe427f15, + 0x2f7a46a098ec70436533ce0ede3992503935467de00794c5bd62f7b6953b4b3, + 0x30a2d971f3604e1ddde683e990c984003478852047ba4a92fa2759e3266e0b4, + 0xd43ee472abffe62e92ba4f59da84e004c875f3ddebb93f5b5902b837d51b94, + 0x1fb55ca37e0372da3e8d6b825fc72d400476552effa9fc733cbf2a8cd1efdce, + 0x395a989d73d2749f3eee8c98b7955ca009c610e68ed1faecfce5bba311f9ed7, + 0x34fc98fc328e7ce0024752cdcbaa89d0002fd82676b3e32b1b5b130216fdf4f, + 0x32e1417294a818ad2925f44a03cb0f049d00eddff29e50ed00eb24e250b96c, + 0x19b1fa1777484a4605991448e8e627701565723c76e1596f688372d2501b092, + 0x3b59dca4e54aaa3cc995db1ee63146f02937aedf1a4c8fc3e0486e5a8e30165, + 0x1df8ca24fb6ec85eda1bbd1049413db03d95e67b49fd1f98247b16f32adde84, + 0x2c6c8582db3ab172621fc31949c694e014888d6dcaa3278230f90cd9a19910b, + 0x39678a33f5573e81e8aa9317e88624701b6c81616be373d7f5be12868926d92, + 0x141b32eb53245d40045054b63367, + ] +} + +/// SRC9 message hash for an empty outside execution addressed to `account_address()` with +/// `ANY_CALLER`, nonce 5, `execute_after` 10, and `execute_before` 20. Its SNIP-12 domain uses +/// name `Account.execute_from_outside`, version 2, chain ID `SN_SEPOLIA`, and revision 1. +pub fn outside_execution_hash() -> felt252 { + 0x6b92f58cb9070d5700b3dfbc62e82131a570bc1d2ca9133db3842f94eceeac4 +} + +/// SHAKE-256 hint signature over `outside_execution_hash()`, produced with the test private key +/// corresponding to `new_public_key()`. +pub fn outside_execution_signature() -> Array { + array![ + 0x4b4f151f45c3b0494a32916b674cdb2001f749ceb287d544d4eb1b423c612d5, + 0x669c2b57f4da0f10725003a59831704c7c74cb0c97465fd29ca1e7cfb402a, + 0x14bc9f29138bd2b5dd4955b8ba3fbe00004ca48190fc41d52930a646935f67, + 0x4b58b17f52f2ceb59b3c61c78d5100c000d056ba419eac52a06ea247229f1dc, + 0x19e784e2e4caa1e0ba283dca81f90011d4fb189e4ebce11970597abf6028, + 0x1e75077ddd44ba0b716b14ea2ff5604c1f74d4aa5074234290c8a2b36311b, + 0xd6bfb5f18d753edd248480e94ff5304cac84dead887afd07681a0517c11f9, + 0x4b9da03cfe36602cf75d985cc669f8804c1908d74e335bcdd37f45b7c241ee0, + 0x984043daabe592da7fc4e939f0053001bd8fe689974f62c4a9c8bbae5f008, + 0xab76b5c232aafc3429c166b7fefb2000903fdb022dd6bb5c491ae4aa30d03, + 0x4c2de4e714cf0c3bc91d71f101642830000b345550b0a64845ee5ada701fd04, + 0xa04f43ba95737f00106fb91a6015c04c5dfad25791a2c784b31b563c90f57, + 0x9eb444c7c0d1316c89d5acc49c285000f8628dd7b9bda83a35b4a959f3b8f, + 0x4c82d1fd95d2dcb0ec1a01fa7c0403d04ce3016739b647936d5e58df8bd30aa, + 0x4bff67c6cf029ed1d9543399390d06404cc152bd4f37628f3ac591c2c35d0d7, + 0x4bec22a3b29465fe1c3c7a5ebbd1f0900105422562575c128f10f7b1429c137, + 0x31ace09d8191e3824c24c682defd90000ffd1c96849f1479129c98943fdf7, + 0x14d53fc7239a11655b08b8d83cf9b04caae52163fa83d8f37f062d5e71dc5, + 0x4c45e9c4c151b8048e2b3a580af5f7f04c0dd22bd09e81b3f740f0b99acb261, + 0x44ef939b33c377045dc4b8809dade00115511f504c7a669f6cd0a9a1cd321, + 0x4c64505f931305097e6656b43dc910000034d80526b841d7a733b0aa2e87e04, + 0x4c9ade0086aa6a479ef11e7a8ecef680006e8ae19225179ec16434f5d239d8d, + 0x133a95f7e1f1a5e9ba02392266f7d04c8e122d8360fab80ce04b6893e6585, + 0x4bf5c25a4f6512d687f09043d70fe76001fa78db7dd9d5ecd2f84bf1c01d1d4, + 0x4c5123e95a855e6323e19a2d8a710ec04c9fae5c2333d3487add6f11b189e91, + 0x4c879d92c45dd6e62c5698fdade1e7e04b88b8b9612a15111c52e5cb61a3deb, + 0x4b58afe4be4ccce5be0a144ffed1c7800081d486817109a2fa988a0455edf0d, + 0x4b4f0bf92fd7940f8067e3c04b28dc504cc6251102450e734433651191d424a, + 0x1ab4cce57920b58f81e20b60db, 0xb80dead152bad04f674347ab1ab2316e0819c776, + 0xb10b59cd20ba7e6b932a53bb005a7c520a863dec, + 0x4b44c9a863df768c8359ec527d3c7490199a8e7920e4a78e24ddd509f7118a1, + 0x30a24369c757325e6f10fdba527c9450069d063f15798a3ac74907d2811f2a5, + 0x79694d4295f1990078644ca15c0f4303a871d9275157534407ddf2d7062bcf, + 0x3f7c4dd3711929129ac76e18d31e1b02185051a8ab79cbd6187cfd34724aab, + 0x2dd032e5419dcd93295c7c0c3a0107a008f09aafd5afd15ee3cc198c74f0165, + 0x16efbe27c5931f09de4f0afd81c2d1d014acf1e0b31a57c5e52cddc5d205912, + 0x34724daa7b50655841e43076be0653601ec0530a3ffba787e9627f7026b1c95, + 0x360a1d235d9da8dee21aae138bc935101ebe51741d2fb32b50046c3871aef9f, + 0x14a4b268d64bee657bfdaa57d16feb01a3af3aa0d5f729d4ab7d4ce2107c74, + 0x37c1924a346a648a07fd892877479ef04700ff9c31878fef065e5d1f9b19fb1, + 0x1cacc5fa22f1d916415a7a71c3132cd03be9dd39aee46d29d20d5c595767b5f, + 0x15fe178b816546d91e6f8ab2aa28cde04716fcff74bd578462ac0f2d1abd7c9, + 0x428055334432c3b4a0c68a8957f5459029a54fe83bc944df1ca0d078e50ae54, + 0x1d69ed931e5a94e384e07c2576fbeab03a39e3d2eb37ecd71f988bbebaf35f9, + 0x62edf675f00ec8a0cb8ee2b2120ebe0350bca5f7f14ecd7e12036d04d15052, + 0x15cf6f0b586cc06ac67945ef11576c0052ebaf911c2d525f0b17b5772d4ef8, + 0x20bb1217bc9d9bc929d8c3d650d98fd032b78dfd0f39a74fef9c564df3b6d6e, + 0x4306db5a13a7ec15fdb4ce63999fdd037590c842025460f903b70e208a92f5, + 0x4013552d954d5e2bbef1ed4d838d91804543e8c639e7b3f01fd7dbdf04345d2, + 0x4c6d90027346dd12b1e9bbf24ca59b3047b5778058b35edbab930d485fc662a, + 0x1eb6cabc8e08b00e90500dc103eb67301e72ad3aa33801e4231966a4ceb0484, + 0x443d6fa13abe7de7208a5ccde5b1e80042b5b027441297ede9a9aab33012d96, + 0x4198eea2930ce04241e14f446ee882a01563d42e6dae95f64bbc7b612011117, + 0xa136d1fdb5a1bbf4515709da15e0b200680ae20b27443a7bf0a485372f0fec, + 0x24150041bfbc26a21f6665ee16a042702091d6cc00cd2e924d2f23c1d6256e7, + 0x1885d40d392b1d6e838473a57ff705403488156122fb5faa95d10640e660f7b, + 0x45de57705f8580e6f94493d9a39de340442c117a13a255dc60e4f5b0018aacb, + 0x124081749e93c944284324c3e23b2b002a3186d4070e5863dc20aa85287e799, + 0x14355bbe3b117dc3152be52f77de, + ] +} diff --git a/packages/test_common/src/lib.cairo b/packages/test_common/src/lib.cairo index 56d8dac92..6adf07df4 100644 --- a/packages/test_common/src/lib.cairo +++ b/packages/test_common/src/lib.cairo @@ -5,6 +5,7 @@ pub mod erc20; pub mod erc6909; pub mod erc721; pub mod eth_account; +pub mod falcon_512; pub mod math; pub mod mocks; pub mod ownable; diff --git a/scripts/falcon_512/generate_ntt.py b/scripts/falcon_512/generate_ntt.py new file mode 100644 index 000000000..470f6f042 --- /dev/null +++ b/scripts/falcon_512/generate_ntt.py @@ -0,0 +1,583 @@ +#!/usr/bin/env python3 +"""Verify and generate the Falcon-512 NTT sources used by openzeppelin_account. + +The forward roots are derived from q = 12289 and sqrt(-1) = 1479. At each recursive +level, the canonical square root of every previous evaluation point is the smaller +representative of the pair ``r`` and ``q-r``. This fully determines the root order used +by the recursive Falcon transform. + +The executable checks cover the root construction, the iterative Cairo engine, inverse +and pointwise-product paths, and the fully unrolled production transform. The generated +operation graph is interval-checked to ensure that felt arithmetic does not wrap and that +every shifted output fits the u128 reduction path. + +Run without arguments to execute the checks. Pass ``--write`` to regenerate and format: + + packages/account/src/falcon_512/ntt/{bitrev,roots_felt,roots_scaled,falcon512_fast}.cairo +""" + +import argparse +import random +import subprocess +import tomllib +from dataclasses import dataclass +from pathlib import Path + + +Q = 12289 +SQR1 = 1479 +I2 = 6145 +STARK_PRIME = 2**251 + 17 * 2**192 + 1 +SIZES = [2, 4, 8, 16, 32, 64, 128, 256, 512] +QBITS = Q.bit_length() +FWD_GROWTH_BITS = (Q + 1).bit_length() +INV_GROWTH_BITS = (2 * Q).bit_length() +PRODUCT_BITS = 2 * QBITS +SAFE_BITS = 126 + +REPO_ROOT = Path(__file__).resolve().parents[2] +WORKSPACE_VERSION = tomllib.loads((REPO_ROOT / "Scarb.toml").read_text())["workspace"][ + "package" +]["version"] +NTT_DIR = REPO_ROOT / "packages/account/src/falcon_512/ntt" +BITREV_OUT = NTT_DIR / "bitrev.cairo" +ROOTS_FELT_OUT = NTT_DIR / "roots_felt.cairo" +ROOTS_SCALED_OUT = NTT_DIR / "roots_scaled.cairo" +FAST_OUT = NTT_DIR / "falcon512_fast.cairo" + + +def derive_forward_roots() -> dict[int, list[int]]: + """Derive the exact recursive merge-root tables for sizes 2 through 512.""" + canonical_sqrt = {x * x % Q: x for x in range((Q + 1) // 2)} + tables = {2: [SQR1]} + points = [SQR1, Q - SQR1] + for size in SIZES[1:]: + roots = [canonical_sqrt[point] for point in points] + tables[size] = roots + points = [value for root in roots for value in (root, Q - root)] + return tables + + +def derive_scaled_inverse_roots(tables: dict[int, list[int]]) -> dict[int, list[int]]: + return { + size: [I2 * pow(root, -1, Q) % Q for root in tables[size]] for size in SIZES + } + + +def evaluation_points(tables: dict[int, list[int]], size: int) -> list[int]: + return [value for root in tables[size] for value in (root, Q - root)] + + +def bitrev_perm(size: int) -> list[int]: + bits = size.bit_length() - 1 + return [int(f"{index:0{bits}b}"[::-1], 2) for index in range(size)] + + +def ntt_recursive(values: list[int], tables: dict[int, list[int]]) -> list[int]: + size = len(values) + if size == 2: + product = SQR1 * values[1] + return [(values[0] + product) % Q, (values[0] - product) % Q] + even = ntt_recursive(values[0::2], tables) + odd = ntt_recursive(values[1::2], tables) + output = [] + for left, right, root in zip(even, odd, tables[size]): + output.extend(((left + root * right) % Q, (left - root * right) % Q)) + return output + + +def intt_recursive(values: list[int], tables: dict[int, list[int]]) -> list[int]: + size = len(values) + if size == 2: + return [ + I2 * (values[0] + values[1]) % Q, + I2 * (values[0] - values[1]) * pow(SQR1, -1, Q) % Q, + ] + even = [] + odd = [] + for index, root in enumerate(tables[size]): + left, right = values[2 * index], values[2 * index + 1] + even.append(I2 * (left + right) % Q) + odd.append(I2 * (left - right) * pow(root, -1, Q) % Q) + even = intt_recursive(even, tables) + odd = intt_recursive(odd, tables) + return [coefficient for pair in zip(even, odd) for coefficient in pair] + + +class Stats: + def __init__(self) -> None: + self.max_value = 0 + + def see(self, values: list[int]) -> None: + self.max_value = max(self.max_value, max(values)) + + +def ntt_iterative(values: list[int], tables: dict[int, list[int]], stats: Stats) -> list[int]: + """Exact integer model of engine.cairo's forward transform and reduction schedule.""" + size = len(values) + current = [values[index] for index in bitrev_perm(size)] + bits = QBITS + bound = Q + half = 1 + level = 0 + while half != size: + if bits + FWD_GROWTH_BITS > SAFE_BITS: + current = [value % Q for value in current] + bits = QBITS + bound = Q + roots = tables[SIZES[level]] + offset = bound * Q + output = [] + for block in range(0, size, 2 * half): + left = current[block : block + half] + right = current[block + half : block + 2 * half] + for index, root in enumerate(roots): + product = root * right[index] + output.extend((left[index] + product, left[index] + offset - product)) + assert min(output) >= 0 + stats.see(output) + current = output + bits += FWD_GROWTH_BITS + bound *= Q + 1 + half *= 2 + level += 1 + return [value % Q for value in current] + + +def intt_iterative( + values: list[int], + tables: dict[int, list[int]], + stats: Stats, + input_bits: int = QBITS, + input_bound: int = Q, +) -> list[int]: + """Exact integer model of engine.cairo's inverse transform and reduction schedule.""" + size = len(values) + scaled = derive_scaled_inverse_roots(tables) + current = list(values) + bits = input_bits + bound = input_bound + half = size // 2 + level = size.bit_length() - 2 + while True: + if bits + INV_GROWTH_BITS > SAFE_BITS: + current = [value % Q for value in current] + bits = QBITS + bound = Q + roots = scaled[SIZES[level]] + offset = bound * Q + output = [] + for block in range(0, size, 2 * half): + odd = [] + for index, root in enumerate(roots): + left = current[block + 2 * index] + right = current[block + 2 * index + 1] + output.append(I2 * (left + right)) + odd.append(root * left + offset - root * right) + output.extend(odd) + assert min(output) >= 0 + stats.see(output) + current = output + bits += INV_GROWTH_BITS + bound *= 2 * Q + if half == 1: + break + half //= 2 + level -= 1 + return [current[index] % Q for index in bitrev_perm(size)] + + +class ConcreteOps: + @staticmethod + def mul_const(value: int, constant: int) -> int: + return value * constant + + @staticmethod + def add(left: int, right: int) -> int: + return left + right + + @staticmethod + def sub(left: int, right: int) -> int: + return left - right + + +@dataclass(frozen=True) +class CairoValue: + name: str + low: int + high: int + + +class CairoOps: + """Record straight-line Cairo operations together with exact inclusive intervals.""" + + def __init__(self) -> None: + self.lines: list[str] = [] + self.next_id = 0 + self.low = 0 + self.high = Q - 1 + + def record(self, expression: str, low: int, high: int) -> CairoValue: + name = f"v{self.next_id}" + self.next_id += 1 + self.lines.append(f" let {name} = {expression};") + self.low = min(self.low, low) + self.high = max(self.high, high) + return CairoValue(name, low, high) + + def mul_const(self, value: CairoValue, constant: int) -> CairoValue: + return self.record( + f"{value.name} * {constant}", value.low * constant, value.high * constant + ) + + def add(self, left: CairoValue, right: CairoValue) -> CairoValue: + return self.record( + f"{left.name} + {right.name}", left.low + right.low, left.high + right.high + ) + + def sub(self, left: CairoValue, right: CairoValue) -> CairoValue: + return self.record( + f"{left.name} - {right.name}", left.low - right.high, left.high - right.low + ) + + +def ntt_unrolled(values, tables: dict[int, list[int]], ops): + """Build the recursive NTT operation graph without intermediate modular reductions.""" + size = len(values) + if size == 2: + product = ops.mul_const(values[1], SQR1) + return [ops.add(values[0], product), ops.sub(values[0], product)] + even = ntt_unrolled(values[0::2], tables, ops) + odd = ntt_unrolled(values[1::2], tables, ops) + output = [] + for left, right, root in zip(even, odd, tables[size]): + product = ops.mul_const(right, root) + output.extend((ops.add(left, product), ops.sub(left, product))) + return output + + +def shift_for_bound(low: int) -> int: + return 0 if low >= 0 else ((-low + Q - 1) // Q) * Q + + +def sample_inputs(size: int, rng: random.Random) -> list[list[int]]: + return [ + [0] * size, + [Q - 1] * size, + [1] + [0] * (size - 1), + list(range(size)), + *[[rng.randrange(Q) for _ in range(size)] for _ in range(3)], + ] + + +def verify(tables: dict[int, list[int]]) -> tuple[CairoOps, list[CairoValue], int]: + assert SQR1 * SQR1 % Q == Q - 1 + assert I2 * 2 % Q == 1 + + for size in SIZES: + points = evaluation_points(tables, size) + assert len(points) == size + assert len(set(points)) == size + assert all(pow(point, size, Q) == Q - 1 for point in points) + + rng = random.Random(Q) + stats = Stats() + for size in SIZES[1:]: + for values in sample_inputs(size, rng): + expected = ntt_recursive(values, tables) + assert ntt_iterative(values, tables, stats) == expected + assert intt_recursive(expected, tables) == [value % Q for value in values] + assert intt_iterative(expected, tables, stats) == [value % Q for value in values] + + for _ in range(3): + left = [rng.randrange(Q) for _ in range(512)] + right = [rng.randrange(Q) for _ in range(512)] + left_ntt = ntt_recursive(left, tables) + right_ntt = ntt_recursive(right, tables) + products = [a * b for a, b in zip(left_ntt, right_ntt)] + expected = intt_recursive([value % Q for value in products], tables) + assert ( + intt_iterative( + products, + tables, + stats, + input_bits=PRODUCT_BITS, + input_bound=Q * Q, + ) + == expected + ) + + points = evaluation_points(tables, 512) + for basis_index in range(512): + basis = [0] * 512 + basis[basis_index] = 1 + expected = [pow(point, basis_index, Q) for point in points] + raw = ntt_unrolled(basis, tables, ConcreteOps()) + assert [value % Q for value in raw] == expected + + trace = CairoOps() + inputs = [CairoValue(f"f{index}", 0, Q - 1) for index in range(512)] + outputs = ntt_unrolled(inputs, tables, trace) + shift = shift_for_bound(trace.low) + assert shift % Q == 0 + assert min(output.low for output in outputs) + shift >= 0 + assert max(output.high for output in outputs) + shift < 2**128 + assert max(abs(trace.low), trace.high) < STARK_PRIME + assert stats.max_value < 2**SAFE_BITS + + print("verified deterministic roots and distinct negacyclic evaluation points") + print("verified iterative NTT, INTT, and unreduced product paths for sizes 4..512") + print("verified all 512 basis vectors through the generated fast operation graph") + print( + f"verified {trace.next_id} generated operations; shifted outputs fit " + f"{(max(output.high for output in outputs) + shift).bit_length()} bits" + ) + return trace, outputs, shift + + +def generated_header(path: Path, description: list[str]) -> str: + relative = path.relative_to(REPO_ROOT).as_posix() + lines = [ + "// SPDX-License-Identifier: MIT", + f"// OpenZeppelin Contracts for Cairo v{WORKSPACE_VERSION} " + f"({relative.removeprefix('packages/')})", + "", + "// Generated by scripts/falcon_512/generate_ntt.py; do not edit by hand.", + *[f"// {line}" for line in description], + "// Regenerate with: python3 scripts/falcon_512/generate_ntt.py --write", + "", + ] + return "\n".join(lines) + "\n" + + +def format_table(name: str, values: list[int], value_type: str) -> str: + body = ", ".join(str(value) for value in values) + return f"const {name}: [{value_type}; {len(values)}] = [{body}];\n" + + +def emit_dispatch(function_name: str, doc: str, names: dict[int, str]) -> str: + branches = [] + for size in SIZES: + branches.append(f" if degree == {size} {{\n {names[size]}.span()\n }}") + return ( + f"\n{doc}pub fn {function_name}(degree: u32) -> Span {{\n" + + " else ".join(branches) + + ' else {\n panic!("no root table for degree")\n }\n}\n' + ) + + +def render_roots_felt(tables: dict[int, list[int]]) -> str: + output = [ + generated_header( + ROOTS_FELT_OUT, + [ + "Forward merge roots derived recursively from q = 12289 and sqrt(-1) = 1479,", + "choosing the smaller representative of each modular square-root pair.", + ], + ), + "//! Forward NTT root tables as felts (generated).\n\n", + ] + names = {} + for size in SIZES: + name = f"phi{2 * size}_roots_zq_felt" + names[size] = name + output.append(format_table(name, tables[size], "felt252")) + output.append( + emit_dispatch( + "get_even_roots_felt", + "/// Forward merge roots for a power-of-two transform degree from 2 through 512.\n", + names, + ) + ) + return "".join(output) + + +def render_roots_scaled(tables: dict[int, list[int]]) -> str: + scaled = derive_scaled_inverse_roots(tables) + output = [ + generated_header( + ROOTS_SCALED_OUT, + [ + "Inverse roots derived from the deterministic forward roots and prescaled by", + "I2 = 2^-1 mod q for the inverse transform's split butterflies.", + ], + ), + "//! I2-scaled inverse NTT root tables (generated).\n\n", + ] + names = {} + for size in SIZES: + name = f"phi{2 * size}_roots_zq_inv_scaled" + names[size] = name + output.append(format_table(name, scaled[size], "felt252")) + output.append( + emit_dispatch( + "get_scaled_inv_roots", + "/// I2-prescaled inverse roots for a power-of-two transform degree from 2 through " + "512.\n", + names, + ) + ) + return "".join(output) + + +def render_bitrev() -> str: + return "".join( + [ + generated_header( + BITREV_OUT, + [ + "Self-inverse bit-reversal permutation for n = 512, used to map between", + "natural coefficient order and the recursive transform's leaf order.", + ], + ), + "//! Bit-reversal permutation table (generated).\n\n", + format_table("BITREV_512", bitrev_perm(512), "u16").replace( + "const", "pub(crate) const", 1 + ), + "\n/// The 512-entry bit-reversal permutation as a span.\n", + "pub fn bitrev_512() -> Span {\n BITREV_512.span()\n}\n", + ] + ) + + +def wrapped(items: list[str], indent: str = " ", width: int = 100) -> str: + lines = [] + current = indent + for item in items: + token = f"{item}," + if len(current) + len(token) + 1 > width and current.strip(): + lines.append(current.rstrip()) + current = indent + token + " " + else: + current += token + " " + if current.strip(): + lines.append(current.rstrip()) + return "\n".join(lines) + + +def render_fast( + trace: CairoOps, outputs: list[CairoValue], shift: int +) -> str: + input_params = [f"f{index}: felt252" for index in range(512)] + input_names = [f"f{index}" for index in range(512)] + reduced_names = [f"r{index}" for index in range(512)] + return_type = "(" + ", ".join("Falcon512Zq" for _ in outputs) + ")" + output = [ + generated_header( + FAST_OUT, + [ + "Fully unrolled Falcon-512 forward NTT for n = 512 and q = 12289.", + "The generator checks exact integer bounds and reduces each output once.", + ], + ), + "//! Generated Falcon-512 forward NTT.\n//!\n", + "//! Inputs are 512 coefficients in `[0, 12289)`. The unchecked entry points rely\n", + "//! on callers to enforce that precondition. Outputs are reduced to the same range.\n\n", + "use openzeppelin_corelib_imports::bounded_int::{\n", + " BoundedInt, DivRemHelper, UnitInt, bounded_int_div_rem, upcast,\n", + "};\n", + "use openzeppelin_corelib_imports::integer::{\n", + " U128sFromFelt252Result, u128s_from_felt252,\n", + "};\n\n", + "type Falcon512Zq = BoundedInt<0, 12288>;\n", + "type Falcon512Q = UnitInt<12289>;\n", + "type U128AsBounded = BoundedInt<0, 340282366920938463463374607431768211455>;\n\n", + "const FALCON512_Q_NZ: NonZero = 12289;\n", + f"const SHIFT: felt252 = {shift};\n\n", + "impl Falcon512FastDivRemImpl of DivRemHelper {\n", + " type DivT = BoundedInt<0, 27689996494502275487295516920153650>;\n", + " type RemT = Falcon512Zq;\n", + "}\n\n", + "#[inline(always)]\n", + "fn felt252_as_u128(value: felt252) -> u128 {\n", + " // Exact generated bounds put canonical shifted outputs below 2^128.\n", + " match u128s_from_felt252(value) {\n", + " U128sFromFelt252Result::Narrow(low) => low,\n", + " U128sFromFelt252Result::Wide((_, low)) => low,\n", + " }\n", + "}\n\n", + "#[inline(always)]\n", + "fn ntt_falcon512_fast_inner(\n", + wrapped(input_params), + f"\n) -> {return_type} {{\n", + "\n".join(trace.lines), + "\n", + ] + for value, name in zip(outputs, reduced_names): + output.extend( + [ + f" let {name}_bounded: U128AsBounded = ", + f"upcast(felt252_as_u128({value.name} + SHIFT));\n", + f" let (_, {name}) = bounded_int_div_rem({name}_bounded, FALCON512_Q_NZ);\n", + ] + ) + output.extend([" (\n", wrapped(reduced_names, " "), "\n )\n}\n\n"]) + output.extend( + [ + "/// Test-only felt wrapper for the generated Falcon-512 forward NTT.\n", + "#[cfg(test)]\n", + "pub fn ntt_falcon512_fast_unchecked(mut f: Span) -> Array {\n", + " assert(f.len() == 512, 'fast NTT: bad length');\n", + " let boxed = f.multi_pop_front::<512>().unwrap();\n", + " let [\n", + wrapped(input_names, " "), + "\n ] = boxed.unbox();\n", + " let (\n", + wrapped(reduced_names, " "), + "\n ) = ntt_falcon512_fast_inner(\n", + wrapped(input_names, " "), + "\n );\n", + " array![\n", + wrapped([f"upcast({name})" for name in reduced_names], " "), + "\n ]\n", + "}\n\n", + "/// Computes the Falcon-512 forward NTT from canonical `u16` coefficients.\n", + "///\n", + "/// Inputs must be in `[0, 12289)`; violating that precondition may return an\n", + "/// invalid transform. Outputs are reduced to the same range.\n", + "pub fn ntt_falcon512_fast_u16_unchecked(mut f: Span) -> Array {\n", + " assert(f.len() == 512, 'fast NTT: bad length');\n", + " let boxed = f.multi_pop_front::<512>().unwrap();\n", + " let [\n", + wrapped(input_names, " "), + "\n ] = boxed.unbox();\n", + " let (\n", + wrapped(reduced_names, " "), + "\n ) = ntt_falcon512_fast_inner(\n", + wrapped([f"{name}.into()" for name in input_names], " "), + "\n );\n", + " array![\n", + wrapped([f"upcast({name})" for name in reduced_names], " "), + "\n ]\n", + "}\n", + ] + ) + return "".join(output) + + +def write_generated(tables: dict[int, list[int]], trace, outputs, shift: int) -> None: + rendered = { + BITREV_OUT: render_bitrev(), + ROOTS_FELT_OUT: render_roots_felt(tables), + ROOTS_SCALED_OUT: render_roots_scaled(tables), + FAST_OUT: render_fast(trace, outputs, shift), + } + for path, source in rendered.items(): + path.write_text(source) + subprocess.run(["scarb", "fmt", str(path)], cwd=REPO_ROOT, check=True) + print(f"wrote {path.relative_to(REPO_ROOT)}") + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--write", action="store_true", help="regenerate the Cairo sources") + args = parser.parse_args() + + tables = derive_forward_roots() + trace, outputs, shift = verify(tables) + if args.write: + write_generated(tables, trace, outputs, shift) + + +if __name__ == "__main__": + main()