From 19dcb542d0c46e79aa8c197396d48d7a1ceff8bb Mon Sep 17 00:00:00 2001 From: Alex Kuzmin <6849426+alxkzmn@users.noreply.github.com> Date: Wed, 8 Nov 2023 21:45:05 +0800 Subject: [PATCH] Refactor the contract according to V1 consolidation spec (#178) * chore: add audit comments (#168) * Refactor backend by following internal audit comments (#173) * feat: create bash script for updating verifier interface files in backend * fix: error propagation with try operator; remove unnecessaries * refactor: changed data type in 'MstInclusionProof' * fix: generate solvency verifier contract * chore: remove left over * chore: update README * fix: remove left over; assert term * fix: update README; small fixes * feat: Signer accepts address or file path for init * Refactor contract according to V1 consolidation spec (#169) * Refactor smart contract * Update smart contract module readme --------- Co-authored-by: JinHwan --- backend/.gitignore | 1 + backend/README.md | 53 +- backend/examples/summa_solvency_flow.rs | 91 +- backend/scripts/update_verifier_contracts.sh | 26 + backend/src/apis/address_ownership.rs | 10 +- backend/src/apis/round.rs | 32 +- backend/src/contracts/deployments.json | 2 +- backend/src/contracts/mod.rs | 2 +- backend/src/contracts/signer.rs | 40 +- backend/src/tests.rs | 138 +- backend/summa_verifier_interface.png | Bin 0 -> 199820 bytes contracts/README.md | 31 +- contracts/scripts/deploy.ts | 7 - contracts/src/SolvencyVerifier.sol | 11 - contracts/src/SolvencyVerifier.yul | 1418 ----------------- contracts/src/Summa.sol | 117 +- contracts/test/Summa.ts | 210 ++- zk_prover/README.md | 2 +- zk_prover/examples/gen_solvency_verifier.rs | 4 +- .../utils/generate_leaf_hash.rs | 8 +- 20 files changed, 406 insertions(+), 1797 deletions(-) create mode 100644 backend/scripts/update_verifier_contracts.sh create mode 100644 backend/summa_verifier_interface.png delete mode 100644 contracts/src/SolvencyVerifier.sol delete mode 100644 contracts/src/SolvencyVerifier.yul diff --git a/backend/.gitignore b/backend/.gitignore index b55c6369..5e48149c 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -2,3 +2,4 @@ # will have compiled files and executables /target .env +*_proof.json diff --git a/backend/README.md b/backend/README.md index 5168e2b4..3f04ef51 100644 --- a/backend/README.md +++ b/backend/README.md @@ -46,22 +46,22 @@ SIGNATURE_VERIFICATION_MESSAGE="Summa proof of solvency for CryptoExchange" carg ## Important Notices -### Generating Verifiers for Backend +### Generating and updating verifier contracts for Backend -The following steps are optional and are only required if you need to update the verifier contracts for the backend: +The verifier contracts in the backend were generated using a predefined set of parameters: `N_ASSETS = 2` and `N_BYTES=14`, as indicated [here](https://github.com/summa-dev/summa-solvency/blob/master/zk_prover/examples/gen_solvency_verifier.rs#L21-L22). +If you intend to work with different parameters, you'll need to adjust these hard-coded values and then generate new verifier contracts. + +The process described below assists in both generating the verifiers and updating the Summa contract, which integrates the new verifiers as constructors. -1. **Build the Verifier Contracts**: - - Move to the `zk_prover` directory. - - Run the [`gen_solvency_verifier`](https://github.com/summa-dev/summa-solvency/blob/master/zk_prover/examples/gen_solvency_verifier.rs) and [`gen_inclusion_verifier`](https://github.com/summa-dev/summa-solvency/blob/master/zk_prover/examples/gen_inclusion_verifier.rs) located within the `zk_prover/examples`. - - For detailed instructions [building a solvency verifier contract](https://github.com/summa-dev/summa-solvency/tree/master/zk_prover#build-a-solvency-verifier-contract) and [building an inclusion verifier contract.](https://github.com/summa-dev/summa-solvency/tree/master/zk_prover#build-an-inclusion-verifier-contract) -2. **Deploy Contracts to Local Environment**: - - Navigate to the `contracts` directory - - Deploy the contracts to a Hardhat environment. This step will refresh the ABI files(`src/contracts/abi/*.json`) in the backend. -3. **Generate Rust Interface Files**: - - Move to the `backend` directory. - - Execute the build script in the backend. This will produce the Rust interface files: `inclusion_verifier.rs`, `solvency_verifier.rs`, and `summa_contract.rs`. +#### Using the Bash Script -By completing these steps, the backend will be primed with the essential verifiers for its tasks. +We have provided a bash script to automate the process of updating the verifier contracts and the Summa contract. To use the script: + +Ensure you have the necessary permissions to execute the script. + +``` +backend $ chmod +x scripts/update_verifier_contracts.sh +``` ## Summa solvency flow example @@ -83,9 +83,6 @@ Key points: - The `dispatch_proof_of_address_ownership` function sends a transaction to the Summa contract to register CEX-owned addresses. -- After dispatching the transaction, the example computes the hashed addresses (address_hashes) to verify they've been correctly registered in the Summa contract - - Note: This demonstration takes place in a test environment. In real-world production, always ensure that the Summa contract is correctly deployed on the target chain. If executed successfully, you'll see: @@ -97,12 +94,16 @@ If executed successfully, you'll see: ### 2. Submit Proof of Solvency -This step is crucial for two primary reasons: first, to validate the root hash of the Merkle Sum Tree (`mst_root`); and second, to ensure that the assets held by the CEX exceed their liabilities, as confirmed through the proof verification on the Summa contract. -The CEX must submit this proof of solvency to the Summa contract. Currently, it's a mandatory requirement to provide this proof before generating the inclusion proof for each user in the current round. +This step is also crucial for two primary reasons: + + first, to validate the root hash of the Merkle Sum Tree (`mst_root`); and second, to ensure that the assets held by the CEX exceed their liabilities, as confirmed through the proof verification on the Summa contract. +The CEX must submit this proof of solvency to the Summa contract. + + Currently, it's a mandatory requirement to provide this proof before generating the inclusion proof for each user in the current round. Without this verification, It seems the user may not trust to the inclusion proof for the round. becuase the `mst_root` is not published on contract. More specifically, it means that the `mst_root` is not correctly verified on the Summa contract. -In this step, we'll guide you through the process of submitting a solvency proof using the Round to the Summa contract. +In here, we'll introduce you through the process of submitting a solvency proof using the `Round` to the Summa contract. The Round serves as the core of the backend in Summa, and we have briefly described it in the Components section. To initialize the `Round` instance, you'll need paths to specific CSV files (`assets.csv` and `entry_16.csv`) and the `ptau/hermez-raw-11` file. Here's what each file does: @@ -147,3 +148,17 @@ The result will display as: ``` 4. Verifying the proof on contract verifier for User #0: true ``` + +### 4. Verify Proof of Inclusion + +This is the final step in the Summa process and the only part that occurs on the user side. Users receive the proof for a specific round and use methods available on the deployed Summa contract. Importantly, the Summa contract verifier function is a view function, meaning it doesn't consume gas or change the blockchain's state. + +In this step, you'll see: +- Retrieve the `mst_root` from the Summa contract and match it with the `root_hash` in the proof. +- Ensure the `leaf_hash` aligns with the hash based on the `username` and `balances` provided by the CEX. +- Use the `verify_inclusion_proof` method on the Summa contract to validate the proof. +The result will display as: + +**Note:** In a production environment, users can independently verify their proof using public interfaces, such as Etherscan, as shown below: +![Summa contract interface on Etherscan](summa_verifier_interface.png) +This offers an added layer of transparency and trust. diff --git a/backend/examples/summa_solvency_flow.rs b/backend/examples/summa_solvency_flow.rs index 76a0861d..172ccb74 100644 --- a/backend/examples/summa_solvency_flow.rs +++ b/backend/examples/summa_solvency_flow.rs @@ -1,11 +1,7 @@ #![feature(generic_const_exprs)] use std::{error::Error, fs::File, io::BufReader, io::Write}; -use ethers::{ - abi::{encode, Token}, - types::{Bytes, U256}, - utils::keccak256, -}; +use ethers::types::U256; use serde_json::{from_reader, to_string_pretty}; use summa_backend::{ @@ -13,6 +9,7 @@ use summa_backend::{ address_ownership::AddressOwnership, round::{MstInclusionProof, Round}, }, + contracts::signer::AddressInput, tests::initialize_test_env, }; use summa_solvency::merkle_sum_tree::utils::generate_leaf_hash; @@ -29,52 +26,25 @@ async fn main() -> Result<(), Box> { // // Each CEX prepares its own `signature` CSV file. let signature_csv_path = "src/apis/csv/signatures.csv"; + + // Using AddressInput::Address to directly provide the summa_contract's address. + // For deployed contracts, if the address is stored in a config file, + // you can alternatively use AddressInput::Path to specify the file's path. let mut address_ownership_client = AddressOwnership::new( "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", anvil.chain_id(), anvil.endpoint().as_str(), - summa_contract.address(), + AddressInput::Address(summa_contract.address()), signature_csv_path, ) .unwrap(); - // Retrieve hashed addresses using the `keccak256` method. - let address_hashes = address_ownership_client - .get_ownership_proofs() - .iter() - .map(|x| keccak256(encode(&[Token::String(x.cex_address.clone())]))) - .collect::>(); - // Dispatch the proof of address ownership. // the `dispatch_proof_of_address_ownership` function sends a transaction to the Summa contract. address_ownership_client .dispatch_proof_of_address_ownership() - .await - .unwrap(); + .await?; - // If the `addressHash` isn't found in the `addressOwnershipProofs` mapping of the Summa contract, - // it will return 0; otherwise, it will return a non-zero value. - // - // You can find unregistered address with null bytes as follows: - // - // let unregistered = summa_contract - // .ownership_proof_by_address([0u8; 32]) - // .call() - // .await - // .unwrap(); - // - // assert_eq!(unregistered, 0); - - // Verify whether the addresses have been registered within the Summa contract. - for address_hash in address_hashes.iter() { - let registered = summa_contract - .ownership_proof_by_address(*address_hash) - .call() - .await - .unwrap(); - - assert_ne!(registered, U256::from(0)); - } println!("1. Ownership proofs are submitted successfully!"); // 2. Submit solvency proof @@ -89,7 +59,7 @@ async fn main() -> Result<(), Box> { "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", // anvil account [0] anvil.chain_id(), anvil.endpoint().as_str(), - summa_contract.address(), + AddressInput::Address(summa_contract.address()), entry_csv, asset_csv, params_path, @@ -98,21 +68,13 @@ async fn main() -> Result<(), Box> { .unwrap(); // Sends the solvency proof, which should ideally complete without errors. - assert_eq!(round.dispatch_solvency_proof().await.unwrap(), ()); - - // You can also use the `solvency_proof_submitted_filter` method to check if the solvency proof is submitted. - // println!("{:?}", summa_contract - // .solvency_proof_submitted_filter() - // .query() - // .await - // .unwrap();); + round.dispatch_solvency_proof().await?; println!("2. Solvency proof is submitted successfully!"); // 3. Generate Inclusion Proof // - // In a production setup, the CEX should first dispatch the solvency proof to update the Merkle sum tree's root before generating any inclusion proofs. - // Otherwise, users might distrust the provided `root_hash` in the inclusion proof, as it hasn't been published on-chain. + // Generate and export the inclusion proof for the specified user to a JSON file. let inclusion_proof = round.get_proof_of_inclusion(USER_INDEX).unwrap(); let filename = format!("user_{}_proof.json", USER_INDEX); @@ -142,49 +104,34 @@ async fn main() -> Result<(), Box> { // Verify the `leaf_hash` from the proof file. // It's assumed that both `user_name` and `balances` are provided by the CEX. + // The `balances` represent the user's balances on the CEX at `snapshot_time`. let user_name = "dxGaEAii".to_string(); let balances = vec![11888, 41163]; - let leaf_hash = public_inputs[0][0]; + let leaf_hash = public_inputs[0]; assert_eq!( leaf_hash, generate_leaf_hash::(user_name.clone(), balances.clone()) ); - // Before verifying `root_hath`, convert type of `proof` and `public_inputs` to the type of `Bytes` and `Vec`. - let proof: Bytes = Bytes::from(inclusion_proof.get_proof().clone()); - let public_inputs: Vec = inclusion_proof - .get_public_inputs() - .iter() - .flat_map(|input_set| { - input_set.iter().map(|input| { - let mut bytes = input.to_bytes(); - bytes.reverse(); - U256::from_big_endian(&bytes) - }) - }) - .collect(); - // Get `mst_root` from contract. the `mst_root` is disptached by CEX with specific time `snapshot_time`. - let mst_root = summa_contract - .mst_roots(snapshot_time) - .call() - .await - .unwrap(); + let mst_root = summa_contract.mst_roots(snapshot_time).call().await?; // Match the `mst_root` with the `root_hash` derived from the proof. assert_eq!(mst_root, public_inputs[1]); // Validate the inclusion proof using the contract verifier. + let proof = inclusion_proof.get_proof(); let verification_result = summa_contract - .verify_inclusion_proof(proof, public_inputs, snapshot_time) - .await - .unwrap(); + .verify_inclusion_proof(proof.clone(), public_inputs.clone(), snapshot_time) + .await?; println!( "4. Verifying the proof on contract veirifer for User #{}: {}", USER_INDEX, verification_result ); + // Wrapping up + drop(anvil); Ok(()) } diff --git a/backend/scripts/update_verifier_contracts.sh b/backend/scripts/update_verifier_contracts.sh new file mode 100644 index 00000000..4e5c8eec --- /dev/null +++ b/backend/scripts/update_verifier_contracts.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -e + +# Build the verifier contracts +echo "1. Building verifier contracts" +cd ../zk_prover +cargo run --release --example gen_inclusion_verifier +cargo run --release --example gen_solvency_verifier + +# Deploy contracts to local environment +echo "2. Deploying contracts to local environment" +cd ../contracts +npm install +npx hardhat node & +HARDHAT_PID=$! +sleep 5 +npx hardhat run scripts/deploy.ts --network localhost + +# Generate interface files for Backend +echo "3. Generating interface files for Backend" +cd ../backend +cargo build + +# Wrap up +echo "Terminate hardhat node" +kill $HARDHAT_PID diff --git a/backend/src/apis/address_ownership.rs b/backend/src/apis/address_ownership.rs index 7b56348b..54233e86 100644 --- a/backend/src/apis/address_ownership.rs +++ b/backend/src/apis/address_ownership.rs @@ -1,5 +1,7 @@ -use crate::contracts::{generated::summa_contract::AddressOwnershipProof, signer::SummaSigner}; -use ethers::types::Address; +use crate::contracts::{ + generated::summa_contract::AddressOwnershipProof, + signer::{AddressInput, SummaSigner}, +}; use std::{error::Error, result::Result}; use super::csv_parser::parse_signature_csv; @@ -14,14 +16,14 @@ impl AddressOwnership { signer_key: &str, chain_id: u64, rpc_url: &str, - summa_sc_address: Address, + summa_address_input: AddressInput, signature_csv_path: &str, ) -> Result> { let address_ownership_proofs = parse_signature_csv(signature_csv_path)?; Ok(AddressOwnership { address_ownership_proofs, - signer: SummaSigner::new(signer_key, chain_id, rpc_url, summa_sc_address), + signer: SummaSigner::new(signer_key, chain_id, rpc_url, summa_address_input), }) } diff --git a/backend/src/apis/round.rs b/backend/src/apis/round.rs index c1f47b45..eba011d3 100644 --- a/backend/src/apis/round.rs +++ b/backend/src/apis/round.rs @@ -1,18 +1,17 @@ -use ethers::{ - abi::Address, - types::{Bytes, U256}, -}; +use ethers::types::{Bytes, U256}; use halo2_proofs::{ halo2curves::bn256::{Bn256, Fr as Fp, G1Affine}, plonk::{ProvingKey, VerifyingKey}, poly::kzg::commitment::ParamsKZG, }; use serde::{Deserialize, Serialize}; -use snark_verifier_sdk::{evm::gen_evm_proof_shplonk, CircuitExt}; use std::error::Error; use super::csv_parser::parse_asset_csv; -use crate::contracts::{generated::summa_contract::summa::Asset, signer::SummaSigner}; +use crate::contracts::{ + generated::summa_contract::summa::Asset, + signer::{AddressInput, SummaSigner}, +}; use summa_solvency::{ circuits::{ merkle_sum_tree::MstInclusionCircuit, @@ -46,17 +45,17 @@ impl SolvencyProof { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MstInclusionProof { - public_inputs: Vec>, - proof: Vec, + public_inputs: Vec, + proof_calldata: Bytes, } impl MstInclusionProof { - pub fn get_public_inputs(&self) -> &Vec> { + pub fn get_public_inputs(&self) -> &Vec { &self.public_inputs } - pub fn get_proof(&self) -> &Vec { - &self.proof + pub fn get_proof(&self) -> &Bytes { + &self.proof_calldata } } @@ -82,7 +81,7 @@ where signer_key: &str, chain_id: u64, rpc_url: &str, - summa_sc_address: Address, + summa_address_input: AddressInput, entry_csv_path: &str, asset_csv_path: &str, params_path: &str, @@ -96,7 +95,7 @@ where params_path, ) .unwrap(), - signer: SummaSigner::new(signer_key, chain_id, rpc_url, summa_sc_address), + signer: SummaSigner::new(signer_key, chain_id, rpc_url, summa_address_input), }) } @@ -203,16 +202,15 @@ where MstInclusionCircuit::::init(self.mst.clone(), user_index); // Currently, default manner of generating a inclusion proof for solidity-verifier. - let proof = gen_evm_proof_shplonk( + let calldata = gen_proof_solidity_calldata( &self.trusted_setup[0].0, &self.trusted_setup[0].1, circuit.clone(), - circuit.instances(), ); Ok(MstInclusionProof { - public_inputs: circuit.instances(), - proof, + proof_calldata: calldata.0, + public_inputs: calldata.1, }) } } diff --git a/backend/src/contracts/deployments.json b/backend/src/contracts/deployments.json index 0dadb21b..a945ae8f 100644 --- a/backend/src/contracts/deployments.json +++ b/backend/src/contracts/deployments.json @@ -1 +1 @@ -{"31337":{"address":"0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0"}} \ No newline at end of file +{"31337":{"address":"0xdc64a140aa3e981100a9beca4e685f962f0cf6c9"}} diff --git a/backend/src/contracts/mod.rs b/backend/src/contracts/mod.rs index a6499aca..55333bf2 100644 --- a/backend/src/contracts/mod.rs +++ b/backend/src/contracts/mod.rs @@ -1,3 +1,3 @@ pub mod generated; pub mod mock; -pub(crate) mod signer; +pub mod signer; diff --git a/backend/src/contracts/signer.rs b/backend/src/contracts/signer.rs index 5b4f3ccc..633b2ed6 100644 --- a/backend/src/contracts/signer.rs +++ b/backend/src/contracts/signer.rs @@ -1,4 +1,3 @@ -use crate::contracts::generated::summa_contract::Summa; use ethers::{ prelude::SignerMiddleware, providers::{Http, Provider}, @@ -11,6 +10,12 @@ use std::{ }; use super::generated::summa_contract::{AddressOwnershipProof, Asset}; +use crate::contracts::generated::summa_contract::Summa; + +pub enum AddressInput { + Address(Address), + Path(String), +} #[derive(Debug)] pub struct SummaSigner { @@ -23,8 +28,13 @@ impl SummaSigner { /// * `signer_key` - The private key of wallet that will interact with the chain on behalf of the exchange /// * `chain_id` - The chain id of the network /// * `rpc_url` - The RPC URL of the network - /// * `address` - The address of the Summa contract - pub fn new(signer_key: &str, chain_id: u64, rpc_url: &str, address: Address) -> Self { + /// * `address_input` - Either the contract's direct address or a path to its config file. + pub fn new( + signer_key: &str, + chain_id: u64, + rpc_url: &str, + address_input: AddressInput, + ) -> Self { let wallet: LocalWallet = LocalWallet::from_str(signer_key).unwrap(); let provider = Provider::::try_from(rpc_url) @@ -35,13 +45,25 @@ impl SummaSigner { wallet.with_chain_id(chain_id), )); + let address = match address_input { + AddressInput::Address(address) => address, + AddressInput::Path(path) => { + let address = Self::get_deployment_address(path, chain_id).unwrap(); + address + } + }; + let contract = Summa::new(address, client); Self { summa_contract: contract, } } - pub fn get_deployment_address>( + pub fn get_summa_address(&self) -> Address { + self.summa_contract.address() + } + + fn get_deployment_address>( path: P, chain_id: u64, ) -> Result> { @@ -72,9 +94,10 @@ impl SummaSigner { let submit_proof_of_address_ownership = &self .summa_contract .submit_proof_of_address_ownership(address_ownership_proofs); - let tx = submit_proof_of_address_ownership.send().await.unwrap(); + let tx = submit_proof_of_address_ownership.send().await?; - tx.await.unwrap(); + // Wait for the pending transaction to be mined + tx.await?; Ok(()) } @@ -89,9 +112,10 @@ impl SummaSigner { let submit_proof_of_solvency_call = &self .summa_contract .submit_proof_of_solvency(mst_root, assets, proof, timestamp); - let tx = submit_proof_of_solvency_call.send().await.unwrap(); + let tx = submit_proof_of_solvency_call.send().await?; - tx.await.unwrap(); + // Wait for the pending transaction to be mined + tx.await?; Ok(()) } diff --git a/backend/src/tests.rs b/backend/src/tests.rs index faf41cee..7098c8e6 100644 --- a/backend/src/tests.rs +++ b/backend/src/tests.rs @@ -102,64 +102,82 @@ pub async fn initialize_test_env() -> ( #[cfg(test)] mod test { - use ethers::{ - abi::AbiEncode, - types::{Bytes, U256}, - utils::to_checksum, - }; + use ethers::{abi::AbiEncode, types::U256, utils::to_checksum}; + use std::error::Error; use crate::apis::{address_ownership::AddressOwnership, round::Round}; - use crate::contracts::generated::summa_contract::{ - AddressOwnershipProof, AddressOwnershipProofSubmittedFilter, Asset, - SolvencyProofSubmittedFilter, + use crate::contracts::{ + generated::summa_contract::{ + AddressOwnershipProof, AddressOwnershipProofSubmittedFilter, Asset, + SolvencyProofSubmittedFilter, + }, + signer::{AddressInput, SummaSigner}, }; use crate::tests::initialize_test_env; #[tokio::test] - async fn test_round_features() { + async fn test_deployed_address() -> Result<(), Box> { + let (anvil, _, _, _, summa_contract) = initialize_test_env().await; + + // Hardhat development environment, usually updates the address of a deployed contract in the `artifacts` directory. + // However, in our custom deployment script, `contracts/scripts/deploy.ts`, + // the address gets updated in `backend/src/contracts/deployments.json`. + let contract_address = summa_contract.address(); + + let summa_signer = SummaSigner::new( + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + anvil.chain_id(), + anvil.endpoint().as_str(), + AddressInput::Path("./src/contracts/deployments.json".into()), // the file contains the address of the deployed contract + ); + + assert_eq!(contract_address, summa_signer.get_summa_address()); + + Ok(()) + } + + #[tokio::test] + async fn test_round_features() -> Result<(), Box> { let (anvil, cex_addr_1, cex_addr_2, _, summa_contract) = initialize_test_env().await; let mut address_ownership_client = AddressOwnership::new( "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", anvil.chain_id(), anvil.endpoint().as_str(), - summa_contract.address(), + AddressInput::Address(summa_contract.address()), "src/apis/csv/signatures.csv", ) .unwrap(); - let ownership_submitted_result = address_ownership_client + address_ownership_client .dispatch_proof_of_address_ownership() - .await; + .await?; - assert_eq!(ownership_submitted_result.is_ok(), true); - - let logs = summa_contract + let ownership_proof_logs = summa_contract .address_ownership_proof_submitted_filter() .query() - .await - .unwrap(); + .await?; - assert_eq!(logs.len(), 1); + assert_eq!(ownership_proof_logs.len(), 1); assert_eq!( - logs[0], - AddressOwnershipProofSubmittedFilter { - address_ownership_proofs: vec![AddressOwnershipProof { - chain: "ETH".to_string(), - cex_address: to_checksum(&cex_addr_1, None), - signature: - ("0x089b32327d332c295dc3b8873c205b72153211de6dc1c51235782b091cefb9d06d6df2661b86a7d441cd322f125b84901486b150e684221a7b7636eb8182af551b").parse().unwrap(), - message: "Summa proof of solvency for CryptoExchange".encode().into(), - },AddressOwnershipProof { - chain: "ETH".to_string(), - cex_address:to_checksum(&cex_addr_2, None), - signature: - ("0xb17a9e25265d3b88de7bfad81e7accad6e3d5612308ff83cc0fef76a34152b0444309e8fc3dea5139e49b6fc83a8553071a7af3d0cfd3fb8c1aea2a4c171729c1c").parse().unwrap(), - message: "Summa proof of solvency for CryptoExchange".encode().into(), - }, - ], - } - ); + ownership_proof_logs[0], + AddressOwnershipProofSubmittedFilter { + address_ownership_proofs: vec![AddressOwnershipProof { + chain: "ETH".to_string(), + cex_address: to_checksum(&cex_addr_1, None), + signature: + ("0x089b32327d332c295dc3b8873c205b72153211de6dc1c51235782b091cefb9d06d6df2661b86a7d441cd322f125b84901486b150e684221a7b7636eb8182af551b").parse().unwrap(), + message: "Summa proof of solvency for CryptoExchange".encode().into(), + },AddressOwnershipProof { + chain: "ETH".to_string(), + cex_address:to_checksum(&cex_addr_2, None), + signature: + ("0xb17a9e25265d3b88de7bfad81e7accad6e3d5612308ff83cc0fef76a34152b0444309e8fc3dea5139e49b6fc83a8553071a7af3d0cfd3fb8c1aea2a4c171729c1c").parse().unwrap(), + message: "Summa proof of solvency for CryptoExchange".encode().into(), + }, + ], + } + ); // Initialize round let asset_csv = "src/apis/csv/assets.csv"; @@ -170,7 +188,7 @@ mod test { "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", // anvil account [0] anvil.chain_id(), anvil.endpoint().as_str(), - summa_contract.address(), + AddressInput::Address(summa_contract.address()), entry_csv, asset_csv, params_path, @@ -179,12 +197,12 @@ mod test { .unwrap(); // Verify solvency proof - let mut logs = summa_contract + let mut solvency_proof_logs = summa_contract .solvency_proof_submitted_filter() .query() - .await - .unwrap(); - assert_eq!(logs.len(), 0); + .await?; + + assert_eq!(solvency_proof_logs.len(), 0); // Dispatch solvency proof let assets = [ @@ -200,20 +218,18 @@ mod test { }, ]; - assert_eq!(round.dispatch_solvency_proof().await.unwrap(), ()); + // Send sovlecy proof to contract + round.dispatch_solvency_proof().await?; // After sending transaction of proof of solvency, logs should be updated - logs = summa_contract + solvency_proof_logs = summa_contract .solvency_proof_submitted_filter() .query() - .await - .unwrap(); - - assert_eq!(logs.len(), 1); + .await?; - assert_eq!(logs.len(), 1); + assert_eq!(solvency_proof_logs.len(), 1); assert_eq!( - logs[0], + solvency_proof_logs[0], SolvencyProofSubmittedFilter { timestamp: U256::from(1), mst_root: "0x2E021D9BF99C5BD7267488B6A7A5CF5F7D00222A41B6A9B971899C44089E0C5" @@ -225,27 +241,19 @@ mod test { // Test inclusion proof let inclusion_proof = round.get_proof_of_inclusion(0).unwrap(); - let proof = Bytes::from(inclusion_proof.get_proof().clone()); - let public_inputs: Vec = inclusion_proof - .get_public_inputs() - .iter() - .flat_map(|input_set| { - input_set.iter().map(|input| { - let mut bytes = input.to_bytes(); - bytes.reverse(); - U256::from_big_endian(&bytes) - }) - }) - .collect(); // Verify inclusion proof with onchain function let verified = summa_contract - .verify_inclusion_proof(proof, public_inputs, U256::from(1)) - .await - .unwrap(); + .verify_inclusion_proof( + inclusion_proof.get_proof().clone(), + inclusion_proof.get_public_inputs().clone(), + U256::from(1), + ) + .await?; - assert_eq!(verified, true); + assert!(verified); drop(anvil); + Ok(()) } } diff --git a/backend/summa_verifier_interface.png b/backend/summa_verifier_interface.png new file mode 100644 index 0000000000000000000000000000000000000000..3d5447727cca1f1381afef26d4f745016cccd1b7 GIT binary patch literal 199820 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 literal 0 HcmV?d00001 diff --git a/contracts/README.md b/contracts/README.md index ac63c987..f0a061b7 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -1,22 +1,43 @@ -# Summa Smart contract +# Summa Smart Contract -Install dependencies: +The [Summa smart contract](src/Summa.sol) acts as a registrar for Centralized Exchanges (CEXs) to commit to their liabilities by submitting a Merkle sum tree (MST) root of all the CEX user asset balances. Users can then verify their inclusion into the liabilities commitment, and the public can compare the committed total sums with the assets owned by the CEX onchain. + +## Features + +- **Address Ownership Proofs**: CEXs should submit the proof of address ownership for all addresses that hold the assets included into the commitment by using `submitProofOfAddressOwnership` function. The proofs are accepted optimistically and subject to off-chain verification. + +- **Liabilities Commitments**: CEXs can submit commitments to its liabilities in the form of MST roots and the corresponding total sums that represent the snapshots of the liabilities at a given timestamp by using `submitCommitment` function. + +- **Inclusion Verification**: Users are able to verify the zero-knowledge proof of inclusion of their balances into the MST using `verifyInclusionProof` function. The function is calling the underlying smart contract [Verifier](src/InclusionVerifier.sol). The verifier is generated from the [zk_prover](./../zk_prover/) module (see module's [readme](./../zk_prover/README.md)). + +## Installation + +Ensure you have Node.js installed on your machine before proceeding. The smart contract is written in Solidity and uses the Hardhat environment for testing and deployment. + +To set up the project environment, install the necessary dependencies: ```shell npm install ``` -Testing: +## Testing ```shell npx hardhat node REPORT_GAS=true npx hardhat test ``` -Deploying: +### Test Coverage + +```shell +npx hardhat coverage +``` + +## Deploying ```shell npx hardhat run scripts/deploy.ts --network localhost ``` -The deployment script will copy the contract ABIs from the ./artifacts/src/ to the [backend subproject](./../backend/src/contracts/abi/). The backend buildscript will then be able to generate the updated contract interfaces (see the [backend readme](./../backend/README.md)). +The deployment script writes the latest deployment address for the chain to the [deployments](./../backend/src/contracts/deployments.json) file in the backend project. This data can later be used by the backend module to connect to the deployed contract. +The deployment script will copy the contract ABIs from the ./artifacts/src/ to the [backend](./../backend/src/contracts/abi/) module. The backend buildscript will then be able to generate the updated contract interfaces (see the backend [readme](./../backend/README.md)). diff --git a/contracts/scripts/deploy.ts b/contracts/scripts/deploy.ts index 4425c4dc..5329c0d3 100644 --- a/contracts/scripts/deploy.ts +++ b/contracts/scripts/deploy.ts @@ -10,18 +10,12 @@ type Deployments = { }; async function main() { - const solvencyVerifier = await ethers.deployContract( - "src/SolvencyVerifier.sol:Verifier" - ); - await solvencyVerifier.deployed(); - const inclusionVerifier = await ethers.deployContract( "src/InclusionVerifier.sol:Verifier" ); await inclusionVerifier.deployed(); const summa = await ethers.deployContract("Summa", [ - solvencyVerifier.address, inclusionVerifier.address, ]); @@ -61,7 +55,6 @@ async function main() { //Copy the ABIs from `artifacts/src/*` to `backend/src/contracts/*` copyAbi(fs, "Summa", "Summa"); - copyAbi(fs, "SolvencyVerifier", "Verifier"); copyAbi(fs, "InclusionVerifier", "Verifier"); } diff --git a/contracts/src/SolvencyVerifier.sol b/contracts/src/SolvencyVerifier.sol deleted file mode 100644 index d1e940a9..00000000 --- a/contracts/src/SolvencyVerifier.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT - pragma solidity ^0.8.17; - - contract Verifier { - function verify( - uint256[] memory pubInputs, - bytes memory proof - ) public view returns (bool) { - bool success = true; - bytes32[846] memory transcript; - assembly { let f_p := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 let f_q := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 function validate_ec_point(x, y) -> valid { { let x_lt_p := lt(x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) let y_lt_p := lt(y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) valid := and(x_lt_p, y_lt_p) } { let y_square := mulmod(y, y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) let x_square := mulmod(x, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) let x_cube := mulmod(x_square, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) let x_cube_plus_3 := addmod(x_cube, 3, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) let is_affine := eq(x_cube_plus_3, y_square) valid := and(valid, is_affine) } } mstore(add(transcript, 0x20), mod(mload(add(pubInputs, 0x20)), f_q))mstore(add(transcript, 0x40), mod(mload(add(pubInputs, 0x40)), f_q))mstore(add(transcript, 0x60), mod(mload(add(pubInputs, 0x60)), f_q))mstore(add(transcript, 0x0), 308492134225063399814226381520525808113815168934209933683689315739401114858) { let x := mload(add(proof, 0x20)) mstore(add(transcript, 0x80), x) let y := mload(add(proof, 0x40)) mstore(add(transcript, 0xa0), y) success := and(validate_ec_point(x, y), success) } { let x := mload(add(proof, 0x60)) mstore(add(transcript, 0xc0), x) let y := mload(add(proof, 0x80)) mstore(add(transcript, 0xe0), y) success := and(validate_ec_point(x, y), success) } { let x := mload(add(proof, 0xa0)) mstore(add(transcript, 0x100), x) let y := mload(add(proof, 0xc0)) mstore(add(transcript, 0x120), y) success := and(validate_ec_point(x, y), success) }mstore(add(transcript, 0x140), keccak256(add(transcript, 0x0), 320)){ let hash := mload(add(transcript, 0x140)) mstore(add(transcript, 0x160), mod(hash, f_q)) mstore(add(transcript, 0x180), hash) } { let x := mload(add(proof, 0xe0)) mstore(add(transcript, 0x1a0), x) let y := mload(add(proof, 0x100)) mstore(add(transcript, 0x1c0), y) success := and(validate_ec_point(x, y), success) } { let x := mload(add(proof, 0x120)) mstore(add(transcript, 0x1e0), x) let y := mload(add(proof, 0x140)) mstore(add(transcript, 0x200), y) success := and(validate_ec_point(x, y), success) }mstore(add(transcript, 0x220), keccak256(add(transcript, 0x180), 160)){ let hash := mload(add(transcript, 0x220)) mstore(add(transcript, 0x240), mod(hash, f_q)) mstore(add(transcript, 0x260), hash) }mstore8(add(transcript, 0x280), 1)mstore(add(transcript, 0x280), keccak256(add(transcript, 0x260), 33)){ let hash := mload(add(transcript, 0x280)) mstore(add(transcript, 0x2a0), mod(hash, f_q)) mstore(add(transcript, 0x2c0), hash) } { let x := mload(add(proof, 0x160)) mstore(add(transcript, 0x2e0), x) let y := mload(add(proof, 0x180)) mstore(add(transcript, 0x300), y) success := and(validate_ec_point(x, y), success) } { let x := mload(add(proof, 0x1a0)) mstore(add(transcript, 0x320), x) let y := mload(add(proof, 0x1c0)) mstore(add(transcript, 0x340), y) success := and(validate_ec_point(x, y), success) } { let x := mload(add(proof, 0x1e0)) mstore(add(transcript, 0x360), x) let y := mload(add(proof, 0x200)) mstore(add(transcript, 0x380), y) success := and(validate_ec_point(x, y), success) } { let x := mload(add(proof, 0x220)) mstore(add(transcript, 0x3a0), x) let y := mload(add(proof, 0x240)) mstore(add(transcript, 0x3c0), y) success := and(validate_ec_point(x, y), success) }mstore(add(transcript, 0x3e0), keccak256(add(transcript, 0x2c0), 288)){ let hash := mload(add(transcript, 0x3e0)) mstore(add(transcript, 0x400), mod(hash, f_q)) mstore(add(transcript, 0x420), hash) } { let x := mload(add(proof, 0x260)) mstore(add(transcript, 0x440), x) let y := mload(add(proof, 0x280)) mstore(add(transcript, 0x460), y) success := and(validate_ec_point(x, y), success) } { let x := mload(add(proof, 0x2a0)) mstore(add(transcript, 0x480), x) let y := mload(add(proof, 0x2c0)) mstore(add(transcript, 0x4a0), y) success := and(validate_ec_point(x, y), success) } { let x := mload(add(proof, 0x2e0)) mstore(add(transcript, 0x4c0), x) let y := mload(add(proof, 0x300)) mstore(add(transcript, 0x4e0), y) success := and(validate_ec_point(x, y), success) } { let x := mload(add(proof, 0x320)) mstore(add(transcript, 0x500), x) let y := mload(add(proof, 0x340)) mstore(add(transcript, 0x520), y) success := and(validate_ec_point(x, y), success) } { let x := mload(add(proof, 0x360)) mstore(add(transcript, 0x540), x) let y := mload(add(proof, 0x380)) mstore(add(transcript, 0x560), y) success := and(validate_ec_point(x, y), success) }mstore(add(transcript, 0x580), keccak256(add(transcript, 0x420), 352)){ let hash := mload(add(transcript, 0x580)) mstore(add(transcript, 0x5a0), mod(hash, f_q)) mstore(add(transcript, 0x5c0), hash) }mstore(add(transcript, 0x5e0), mod(mload(add(proof, 0x3a0)), f_q))mstore(add(transcript, 0x600), mod(mload(add(proof, 0x3c0)), f_q))mstore(add(transcript, 0x620), mod(mload(add(proof, 0x3e0)), f_q))mstore(add(transcript, 0x640), mod(mload(add(proof, 0x400)), f_q))mstore(add(transcript, 0x660), mod(mload(add(proof, 0x420)), f_q))mstore(add(transcript, 0x680), mod(mload(add(proof, 0x440)), f_q))mstore(add(transcript, 0x6a0), mod(mload(add(proof, 0x460)), f_q))mstore(add(transcript, 0x6c0), mod(mload(add(proof, 0x480)), f_q))mstore(add(transcript, 0x6e0), mod(mload(add(proof, 0x4a0)), f_q))mstore(add(transcript, 0x700), mod(mload(add(proof, 0x4c0)), f_q))mstore(add(transcript, 0x720), mod(mload(add(proof, 0x4e0)), f_q))mstore(add(transcript, 0x740), mod(mload(add(proof, 0x500)), f_q))mstore(add(transcript, 0x760), mod(mload(add(proof, 0x520)), f_q))mstore(add(transcript, 0x780), mod(mload(add(proof, 0x540)), f_q))mstore(add(transcript, 0x7a0), mod(mload(add(proof, 0x560)), f_q))mstore(add(transcript, 0x7c0), mod(mload(add(proof, 0x580)), f_q))mstore(add(transcript, 0x7e0), mod(mload(add(proof, 0x5a0)), f_q))mstore(add(transcript, 0x800), mod(mload(add(proof, 0x5c0)), f_q))mstore(add(transcript, 0x820), mod(mload(add(proof, 0x5e0)), f_q))mstore(add(transcript, 0x840), mod(mload(add(proof, 0x600)), f_q))mstore(add(transcript, 0x860), mod(mload(add(proof, 0x620)), f_q))mstore(add(transcript, 0x880), mod(mload(add(proof, 0x640)), f_q))mstore(add(transcript, 0x8a0), mod(mload(add(proof, 0x660)), f_q))mstore(add(transcript, 0x8c0), mod(mload(add(proof, 0x680)), f_q))mstore(add(transcript, 0x8e0), mod(mload(add(proof, 0x6a0)), f_q))mstore(add(transcript, 0x900), mod(mload(add(proof, 0x6c0)), f_q))mstore(add(transcript, 0x920), mod(mload(add(proof, 0x6e0)), f_q))mstore(add(transcript, 0x940), mod(mload(add(proof, 0x700)), f_q))mstore(add(transcript, 0x960), mod(mload(add(proof, 0x720)), f_q))mstore(add(transcript, 0x980), mod(mload(add(proof, 0x740)), f_q))mstore(add(transcript, 0x9a0), mod(mload(add(proof, 0x760)), f_q))mstore(add(transcript, 0x9c0), mod(mload(add(proof, 0x780)), f_q))mstore(add(transcript, 0x9e0), mod(mload(add(proof, 0x7a0)), f_q))mstore(add(transcript, 0xa00), keccak256(add(transcript, 0x5c0), 1088)){ let hash := mload(add(transcript, 0xa00)) mstore(add(transcript, 0xa20), mod(hash, f_q)) mstore(add(transcript, 0xa40), hash) }mstore8(add(transcript, 0xa60), 1)mstore(add(transcript, 0xa60), keccak256(add(transcript, 0xa40), 33)){ let hash := mload(add(transcript, 0xa60)) mstore(add(transcript, 0xa80), mod(hash, f_q)) mstore(add(transcript, 0xaa0), hash) } { let x := mload(add(proof, 0x7c0)) mstore(add(transcript, 0xac0), x) let y := mload(add(proof, 0x7e0)) mstore(add(transcript, 0xae0), y) success := and(validate_ec_point(x, y), success) }mstore(add(transcript, 0xb00), keccak256(add(transcript, 0xaa0), 96)){ let hash := mload(add(transcript, 0xb00)) mstore(add(transcript, 0xb20), mod(hash, f_q)) mstore(add(transcript, 0xb40), hash) } { let x := mload(add(proof, 0x800)) mstore(add(transcript, 0xb60), x) let y := mload(add(proof, 0x820)) mstore(add(transcript, 0xb80), y) success := and(validate_ec_point(x, y), success) }mstore(add(transcript, 0xba0), mulmod(mload(add(transcript, 0x5a0)), mload(add(transcript, 0x5a0)), f_q))mstore(add(transcript, 0xbc0), mulmod(mload(add(transcript, 0xba0)), mload(add(transcript, 0xba0)), f_q))mstore(add(transcript, 0xbe0), mulmod(mload(add(transcript, 0xbc0)), mload(add(transcript, 0xbc0)), f_q))mstore(add(transcript, 0xc00), mulmod(mload(add(transcript, 0xbe0)), mload(add(transcript, 0xbe0)), f_q))mstore(add(transcript, 0xc20), mulmod(mload(add(transcript, 0xc00)), mload(add(transcript, 0xc00)), f_q))mstore(add(transcript, 0xc40), mulmod(mload(add(transcript, 0xc20)), mload(add(transcript, 0xc20)), f_q))mstore(add(transcript, 0xc60), mulmod(mload(add(transcript, 0xc40)), mload(add(transcript, 0xc40)), f_q))mstore(add(transcript, 0xc80), mulmod(mload(add(transcript, 0xc60)), mload(add(transcript, 0xc60)), f_q))mstore(add(transcript, 0xca0), mulmod(mload(add(transcript, 0xc80)), mload(add(transcript, 0xc80)), f_q))mstore(add(transcript, 0xcc0), mulmod(mload(add(transcript, 0xca0)), mload(add(transcript, 0xca0)), f_q))mstore(add(transcript, 0xce0), addmod(mload(add(transcript, 0xcc0)), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q))mstore(add(transcript, 0xd00), mulmod(mload(add(transcript, 0xce0)), 21866867634659744680037180739646672280844703888306253060159436409049855557633, f_q))mstore(add(transcript, 0xd20), mulmod(mload(add(transcript, 0xd00)), 9936069627611189518829255670237324269287146421271524553312532036927871056678, f_q))mstore(add(transcript, 0xd40), addmod(mload(add(transcript, 0x5a0)), 11952173244228085703417150075019950819261217979144509790385672149647937438939, f_q))mstore(add(transcript, 0xd60), mulmod(mload(add(transcript, 0xd00)), 1680739780407307830605919050682431078078760076686599579086116998224280619988, f_q))mstore(add(transcript, 0xd80), addmod(mload(add(transcript, 0x5a0)), 20207503091431967391640486694574844010469604323729434764612087188351527875629, f_q))mstore(add(transcript, 0xda0), mulmod(mload(add(transcript, 0xd00)), 14158528901797138466244491986759313854666262535363044392173788062030301470987, f_q))mstore(add(transcript, 0xdc0), addmod(mload(add(transcript, 0x5a0)), 7729713970042136756001913758497961233882101865052989951524416124545507024630, f_q))mstore(add(transcript, 0xde0), mulmod(mload(add(transcript, 0xd00)), 15699029810934084314820646074566828280617789951162923449200398535581206172418, f_q))mstore(add(transcript, 0xe00), addmod(mload(add(transcript, 0x5a0)), 6189213060905190907425759670690446807930574449253110894497805650994602323199, f_q))mstore(add(transcript, 0xe20), mulmod(mload(add(transcript, 0xd00)), 4260969412351770314333984243767775737437927068151180798236715529158398853173, f_q))mstore(add(transcript, 0xe40), addmod(mload(add(transcript, 0x5a0)), 17627273459487504907912421501489499351110437332264853545461488657417409642444, f_q))mstore(add(transcript, 0xe60), mulmod(mload(add(transcript, 0xd00)), 4925592601992654644734291590386747644864797672605745962807370354577123815907, f_q))mstore(add(transcript, 0xe80), addmod(mload(add(transcript, 0x5a0)), 16962650269846620577512114154870527443683566727810288380890833831998684679710, f_q))mstore(add(transcript, 0xea0), mulmod(mload(add(transcript, 0xd00)), 1, f_q))mstore(add(transcript, 0xec0), addmod(mload(add(transcript, 0x5a0)), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q))mstore(add(transcript, 0xee0), mulmod(mload(add(transcript, 0xd00)), 19380560087801265747114831706136320509424814679569278834391540198888293317501, f_q))mstore(add(transcript, 0xf00), addmod(mload(add(transcript, 0x5a0)), 2507682784038009475131574039120954579123549720846755509306663987687515178116, f_q))mstore(add(transcript, 0xf20), mulmod(mload(add(transcript, 0xd00)), 6252951856119339508807713076978770803512896272623217303779254502899773638908, f_q))mstore(add(transcript, 0xf40), addmod(mload(add(transcript, 0x5a0)), 15635291015719935713438692668278504285035468127792817039918949683676034856709, f_q)){ let prod := mload(add(transcript, 0xd40)) prod := mulmod(mload(add(transcript, 0xd80)), prod, f_q) mstore(add(transcript, 0xf60), prod) prod := mulmod(mload(add(transcript, 0xdc0)), prod, f_q) mstore(add(transcript, 0xf80), prod) prod := mulmod(mload(add(transcript, 0xe00)), prod, f_q) mstore(add(transcript, 0xfa0), prod) prod := mulmod(mload(add(transcript, 0xe40)), prod, f_q) mstore(add(transcript, 0xfc0), prod) prod := mulmod(mload(add(transcript, 0xe80)), prod, f_q) mstore(add(transcript, 0xfe0), prod) prod := mulmod(mload(add(transcript, 0xec0)), prod, f_q) mstore(add(transcript, 0x1000), prod) prod := mulmod(mload(add(transcript, 0xf00)), prod, f_q) mstore(add(transcript, 0x1020), prod) prod := mulmod(mload(add(transcript, 0xf40)), prod, f_q) mstore(add(transcript, 0x1040), prod) prod := mulmod(mload(add(transcript, 0xce0)), prod, f_q) mstore(add(transcript, 0x1060), prod) }mstore(add(transcript, 0x10a0), 32)mstore(add(transcript, 0x10c0), 32)mstore(add(transcript, 0x10e0), 32)mstore(add(transcript, 0x1100), mload(add(transcript, 0x1060)))mstore(add(transcript, 0x1120), 21888242871839275222246405745257275088548364400416034343698204186575808495615)mstore(add(transcript, 0x1140), 21888242871839275222246405745257275088548364400416034343698204186575808495617)success := and(eq(staticcall(gas(), 0x5, add(transcript, 0x10a0), 0xc0, add(transcript, 0x1080), 0x20), 1), success){ let inv := mload(add(transcript, 0x1080)) let v v := mload(add(transcript, 0xce0)) mstore(add(transcript, 0xce0), mulmod(mload(add(transcript, 0x1040)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0xf40)) mstore(add(transcript, 0xf40), mulmod(mload(add(transcript, 0x1020)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0xf00)) mstore(add(transcript, 0xf00), mulmod(mload(add(transcript, 0x1000)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0xec0)) mstore(add(transcript, 0xec0), mulmod(mload(add(transcript, 0xfe0)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0xe80)) mstore(add(transcript, 0xe80), mulmod(mload(add(transcript, 0xfc0)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0xe40)) mstore(add(transcript, 0xe40), mulmod(mload(add(transcript, 0xfa0)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0xe00)) mstore(add(transcript, 0xe00), mulmod(mload(add(transcript, 0xf80)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0xdc0)) mstore(add(transcript, 0xdc0), mulmod(mload(add(transcript, 0xf60)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0xd80)) mstore(add(transcript, 0xd80), mulmod(mload(add(transcript, 0xd40)), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(add(transcript, 0xd40), inv) }mstore(add(transcript, 0x1160), mulmod(mload(add(transcript, 0xd20)), mload(add(transcript, 0xd40)), f_q))mstore(add(transcript, 0x1180), mulmod(mload(add(transcript, 0xd60)), mload(add(transcript, 0xd80)), f_q))mstore(add(transcript, 0x11a0), mulmod(mload(add(transcript, 0xda0)), mload(add(transcript, 0xdc0)), f_q))mstore(add(transcript, 0x11c0), mulmod(mload(add(transcript, 0xde0)), mload(add(transcript, 0xe00)), f_q))mstore(add(transcript, 0x11e0), mulmod(mload(add(transcript, 0xe20)), mload(add(transcript, 0xe40)), f_q))mstore(add(transcript, 0x1200), mulmod(mload(add(transcript, 0xe60)), mload(add(transcript, 0xe80)), f_q))mstore(add(transcript, 0x1220), mulmod(mload(add(transcript, 0xea0)), mload(add(transcript, 0xec0)), f_q))mstore(add(transcript, 0x1240), mulmod(mload(add(transcript, 0xee0)), mload(add(transcript, 0xf00)), f_q))mstore(add(transcript, 0x1260), mulmod(mload(add(transcript, 0xf20)), mload(add(transcript, 0xf40)), f_q)){ let result := mulmod(mload(add(transcript, 0x1220)), mload(add(transcript, 0x20)), f_q)result := addmod(mulmod(mload(add(transcript, 0x1240)), mload(add(transcript, 0x40)), f_q), result, f_q)result := addmod(mulmod(mload(add(transcript, 0x1260)), mload(add(transcript, 0x60)), f_q), result, f_q)mstore(add(transcript, 0x1280), result) }mstore(add(transcript, 0x12a0), addmod(mload(add(transcript, 0x5e0)), mload(add(transcript, 0x720)), f_q))mstore(add(transcript, 0x12c0), mulmod(mload(add(transcript, 0x12a0)), mload(add(transcript, 0x12a0)), f_q))mstore(add(transcript, 0x12e0), mulmod(mload(add(transcript, 0x12c0)), mload(add(transcript, 0x12c0)), f_q))mstore(add(transcript, 0x1300), mulmod(mload(add(transcript, 0x12a0)), mload(add(transcript, 0x12e0)), f_q))mstore(add(transcript, 0x1320), mulmod(mload(add(transcript, 0x1300)), 2910766817845651019878574839501801340070030115151021261302834310722729507541, f_q))mstore(add(transcript, 0x1340), addmod(mload(add(transcript, 0x600)), mload(add(transcript, 0x740)), f_q))mstore(add(transcript, 0x1360), mulmod(mload(add(transcript, 0x1340)), mload(add(transcript, 0x1340)), f_q))mstore(add(transcript, 0x1380), mulmod(mload(add(transcript, 0x1360)), mload(add(transcript, 0x1360)), f_q))mstore(add(transcript, 0x13a0), mulmod(mload(add(transcript, 0x1340)), mload(add(transcript, 0x1380)), f_q))mstore(add(transcript, 0x13c0), mulmod(mload(add(transcript, 0x13a0)), 19727366863391167538122140361473584127147630672623100827934084310230022599144, f_q))mstore(add(transcript, 0x13e0), addmod(mload(add(transcript, 0x1320)), mload(add(transcript, 0x13c0)), f_q))mstore(add(transcript, 0x1400), addmod(mload(add(transcript, 0x13e0)), sub(f_q, mload(add(transcript, 0x620))), f_q))mstore(add(transcript, 0x1420), mulmod(mload(add(transcript, 0x1400)), mload(add(transcript, 0x7a0)), f_q))mstore(add(transcript, 0x1440), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x1420)), f_q))mstore(add(transcript, 0x1460), mulmod(mload(add(transcript, 0x1300)), 5776684794125549462448597414050232243778680302179439492664047328281728356345, f_q))mstore(add(transcript, 0x1480), mulmod(mload(add(transcript, 0x13a0)), 8348174920934122550483593999453880006756108121341067172388445916328941978568, f_q))mstore(add(transcript, 0x14a0), addmod(mload(add(transcript, 0x1460)), mload(add(transcript, 0x1480)), f_q))mstore(add(transcript, 0x14c0), addmod(mload(add(transcript, 0x14a0)), sub(f_q, mload(add(transcript, 0x640))), f_q))mstore(add(transcript, 0x14e0), mulmod(mload(add(transcript, 0x14c0)), mload(add(transcript, 0x7a0)), f_q))mstore(add(transcript, 0x1500), addmod(mload(add(transcript, 0x1440)), mload(add(transcript, 0x14e0)), f_q))mstore(add(transcript, 0x1520), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x1500)), f_q))mstore(add(transcript, 0x1540), addmod(mload(add(transcript, 0x1300)), sub(f_q, mload(add(transcript, 0x660))), f_q))mstore(add(transcript, 0x1560), mulmod(mload(add(transcript, 0x1540)), mload(add(transcript, 0x7c0)), f_q))mstore(add(transcript, 0x1580), addmod(mload(add(transcript, 0x1520)), mload(add(transcript, 0x1560)), f_q))mstore(add(transcript, 0x15a0), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x1580)), f_q))mstore(add(transcript, 0x15c0), mulmod(mload(add(transcript, 0x660)), 2910766817845651019878574839501801340070030115151021261302834310722729507541, f_q))mstore(add(transcript, 0x15e0), mulmod(mload(add(transcript, 0x1340)), 19727366863391167538122140361473584127147630672623100827934084310230022599144, f_q))mstore(add(transcript, 0x1600), addmod(mload(add(transcript, 0x15c0)), mload(add(transcript, 0x15e0)), f_q))mstore(add(transcript, 0x1620), addmod(mload(add(transcript, 0x1600)), mload(add(transcript, 0x6e0)), f_q))mstore(add(transcript, 0x1640), mulmod(mload(add(transcript, 0x1620)), mload(add(transcript, 0x1620)), f_q))mstore(add(transcript, 0x1660), mulmod(mload(add(transcript, 0x1640)), mload(add(transcript, 0x1640)), f_q))mstore(add(transcript, 0x1680), mulmod(mload(add(transcript, 0x1620)), mload(add(transcript, 0x1660)), f_q))mstore(add(transcript, 0x16a0), mulmod(mload(add(transcript, 0x620)), 8897705321156975119607866206188469715432233408805434913352778521345836531302, f_q))mstore(add(transcript, 0x16c0), mulmod(mload(add(transcript, 0x640)), 13897810991298242824030978581179475767377101082166056046492926701399149797630, f_q))mstore(add(transcript, 0x16e0), addmod(mload(add(transcript, 0x16a0)), mload(add(transcript, 0x16c0)), f_q))mstore(add(transcript, 0x1700), addmod(mload(add(transcript, 0x1680)), sub(f_q, mload(add(transcript, 0x16e0))), f_q))mstore(add(transcript, 0x1720), mulmod(mload(add(transcript, 0x1700)), mload(add(transcript, 0x7c0)), f_q))mstore(add(transcript, 0x1740), addmod(mload(add(transcript, 0x15a0)), mload(add(transcript, 0x1720)), f_q))mstore(add(transcript, 0x1760), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x1740)), f_q))mstore(add(transcript, 0x1780), mulmod(mload(add(transcript, 0x660)), 5776684794125549462448597414050232243778680302179439492664047328281728356345, f_q))mstore(add(transcript, 0x17a0), mulmod(mload(add(transcript, 0x1340)), 8348174920934122550483593999453880006756108121341067172388445916328941978568, f_q))mstore(add(transcript, 0x17c0), addmod(mload(add(transcript, 0x1780)), mload(add(transcript, 0x17a0)), f_q))mstore(add(transcript, 0x17e0), addmod(mload(add(transcript, 0x17c0)), mload(add(transcript, 0x700)), f_q))mstore(add(transcript, 0x1800), mulmod(mload(add(transcript, 0x620)), 7127083008168878795310303301757642617203533252990949589494537404444738046722, f_q))mstore(add(transcript, 0x1820), mulmod(mload(add(transcript, 0x640)), 10251091711782631878897995303436082826711938358699127319815611151510940403902, f_q))mstore(add(transcript, 0x1840), addmod(mload(add(transcript, 0x1800)), mload(add(transcript, 0x1820)), f_q))mstore(add(transcript, 0x1860), addmod(mload(add(transcript, 0x17e0)), sub(f_q, mload(add(transcript, 0x1840))), f_q))mstore(add(transcript, 0x1880), mulmod(mload(add(transcript, 0x1860)), mload(add(transcript, 0x7c0)), f_q))mstore(add(transcript, 0x18a0), addmod(mload(add(transcript, 0x1760)), mload(add(transcript, 0x1880)), f_q))mstore(add(transcript, 0x18c0), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x18a0)), f_q))mstore(add(transcript, 0x18e0), addmod(1, sub(f_q, mload(add(transcript, 0x780))), f_q))mstore(add(transcript, 0x1900), mulmod(mload(add(transcript, 0x18e0)), mload(add(transcript, 0x780)), f_q))mstore(add(transcript, 0x1920), addmod(2, sub(f_q, mload(add(transcript, 0x780))), f_q))mstore(add(transcript, 0x1940), mulmod(mload(add(transcript, 0x1920)), mload(add(transcript, 0x1900)), f_q))mstore(add(transcript, 0x1960), addmod(3, sub(f_q, mload(add(transcript, 0x780))), f_q))mstore(add(transcript, 0x1980), mulmod(mload(add(transcript, 0x1960)), mload(add(transcript, 0x1940)), f_q))mstore(add(transcript, 0x19a0), addmod(mload(add(transcript, 0x6a0)), mload(add(transcript, 0x5e0)), f_q))mstore(add(transcript, 0x19c0), addmod(mload(add(transcript, 0x19a0)), sub(f_q, mload(add(transcript, 0x620))), f_q))mstore(add(transcript, 0x19e0), mulmod(mload(add(transcript, 0x19c0)), mload(add(transcript, 0x1980)), f_q))mstore(add(transcript, 0x1a00), addmod(mload(add(transcript, 0x18c0)), mload(add(transcript, 0x19e0)), f_q))mstore(add(transcript, 0x1a20), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x1a00)), f_q))mstore(add(transcript, 0x1a40), addmod(mload(add(transcript, 0x680)), sub(f_q, mload(add(transcript, 0x640))), f_q))mstore(add(transcript, 0x1a60), mulmod(mload(add(transcript, 0x1a40)), mload(add(transcript, 0x1980)), f_q))mstore(add(transcript, 0x1a80), addmod(mload(add(transcript, 0x1a20)), mload(add(transcript, 0x1a60)), f_q))mstore(add(transcript, 0x1aa0), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x1a80)), f_q))mstore(add(transcript, 0x1ac0), mulmod(mload(add(transcript, 0x1920)), mload(add(transcript, 0x780)), f_q))mstore(add(transcript, 0x1ae0), mulmod(mload(add(transcript, 0x1960)), mload(add(transcript, 0x1ac0)), f_q))mstore(add(transcript, 0x1b00), addmod(4, sub(f_q, mload(add(transcript, 0x780))), f_q))mstore(add(transcript, 0x1b20), mulmod(mload(add(transcript, 0x1b00)), mload(add(transcript, 0x1ae0)), f_q))mstore(add(transcript, 0x1b40), mulmod(mload(add(transcript, 0x660)), mload(add(transcript, 0x1b20)), f_q))mstore(add(transcript, 0x1b60), addmod(1, sub(f_q, mload(add(transcript, 0x660))), f_q))mstore(add(transcript, 0x1b80), mulmod(mload(add(transcript, 0x1b60)), mload(add(transcript, 0x1b40)), f_q))mstore(add(transcript, 0x1ba0), addmod(mload(add(transcript, 0x1aa0)), mload(add(transcript, 0x1b80)), f_q))mstore(add(transcript, 0x1bc0), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x1ba0)), f_q))mstore(add(transcript, 0x1be0), mulmod(2, mload(add(transcript, 0x660)), f_q))mstore(add(transcript, 0x1c00), addmod(mload(add(transcript, 0x600)), sub(f_q, mload(add(transcript, 0x5e0))), f_q))mstore(add(transcript, 0x1c20), mulmod(mload(add(transcript, 0x1c00)), mload(add(transcript, 0x1be0)), f_q))mstore(add(transcript, 0x1c40), addmod(mload(add(transcript, 0x620)), sub(f_q, mload(add(transcript, 0x5e0))), f_q))mstore(add(transcript, 0x1c60), addmod(mload(add(transcript, 0x1c20)), sub(f_q, mload(add(transcript, 0x1c40))), f_q))mstore(add(transcript, 0x1c80), addmod(mload(add(transcript, 0x600)), sub(f_q, mload(add(transcript, 0x640))), f_q))mstore(add(transcript, 0x1ca0), addmod(mload(add(transcript, 0x1c60)), sub(f_q, mload(add(transcript, 0x1c80))), f_q))mstore(add(transcript, 0x1cc0), mulmod(mload(add(transcript, 0x1ca0)), mload(add(transcript, 0x1b20)), f_q))mstore(add(transcript, 0x1ce0), addmod(mload(add(transcript, 0x1bc0)), mload(add(transcript, 0x1cc0)), f_q))mstore(add(transcript, 0x1d00), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x1ce0)), f_q))mstore(add(transcript, 0x1d20), mulmod(mload(add(transcript, 0x1960)), mload(add(transcript, 0x1900)), f_q))mstore(add(transcript, 0x1d40), mulmod(mload(add(transcript, 0x1b00)), mload(add(transcript, 0x1d20)), f_q))mstore(add(transcript, 0x1d60), addmod(mload(add(transcript, 0x5e0)), mload(add(transcript, 0x600)), f_q))mstore(add(transcript, 0x1d80), addmod(mload(add(transcript, 0x1d60)), sub(f_q, mload(add(transcript, 0x660))), f_q))mstore(add(transcript, 0x1da0), mulmod(mload(add(transcript, 0x1d80)), mload(add(transcript, 0x1d40)), f_q))mstore(add(transcript, 0x1dc0), addmod(mload(add(transcript, 0x1d00)), mload(add(transcript, 0x1da0)), f_q))mstore(add(transcript, 0x1de0), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x1dc0)), f_q))mstore(add(transcript, 0x1e00), addmod(mload(add(transcript, 0x1de0)), mload(add(transcript, 0x1da0)), f_q))mstore(add(transcript, 0x1e20), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x1e00)), f_q))mstore(add(transcript, 0x1e40), mulmod(mload(add(transcript, 0x1b00)), mload(add(transcript, 0x1940)), f_q))mstore(add(transcript, 0x1e60), addmod(mload(add(transcript, 0x5e0)), sub(f_q, mload(add(transcript, 0x600))), f_q))mstore(add(transcript, 0x1e80), addmod(mload(add(transcript, 0x1e60)), 5192296858534827628530496329220096, f_q))mstore(add(transcript, 0x1ea0), addmod(mload(add(transcript, 0x1e80)), sub(f_q, mload(add(transcript, 0x660))), f_q))mstore(add(transcript, 0x1ec0), mulmod(mload(add(transcript, 0x1ea0)), mload(add(transcript, 0x1e40)), f_q))mstore(add(transcript, 0x1ee0), addmod(mload(add(transcript, 0x1e20)), mload(add(transcript, 0x1ec0)), f_q))mstore(add(transcript, 0x1f00), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x1ee0)), f_q))mstore(add(transcript, 0x1f20), addmod(1, sub(f_q, mload(add(transcript, 0x8c0))), f_q))mstore(add(transcript, 0x1f40), mulmod(mload(add(transcript, 0x1f20)), mload(add(transcript, 0x1220)), f_q))mstore(add(transcript, 0x1f60), addmod(mload(add(transcript, 0x1f00)), mload(add(transcript, 0x1f40)), f_q))mstore(add(transcript, 0x1f80), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x1f60)), f_q))mstore(add(transcript, 0x1fa0), mulmod(mload(add(transcript, 0x920)), mload(add(transcript, 0x920)), f_q))mstore(add(transcript, 0x1fc0), addmod(mload(add(transcript, 0x1fa0)), sub(f_q, mload(add(transcript, 0x920))), f_q))mstore(add(transcript, 0x1fe0), mulmod(mload(add(transcript, 0x1fc0)), mload(add(transcript, 0x1160)), f_q))mstore(add(transcript, 0x2000), addmod(mload(add(transcript, 0x1f80)), mload(add(transcript, 0x1fe0)), f_q))mstore(add(transcript, 0x2020), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x2000)), f_q))mstore(add(transcript, 0x2040), addmod(mload(add(transcript, 0x920)), sub(f_q, mload(add(transcript, 0x900))), f_q))mstore(add(transcript, 0x2060), mulmod(mload(add(transcript, 0x2040)), mload(add(transcript, 0x1220)), f_q))mstore(add(transcript, 0x2080), addmod(mload(add(transcript, 0x2020)), mload(add(transcript, 0x2060)), f_q))mstore(add(transcript, 0x20a0), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x2080)), f_q))mstore(add(transcript, 0x20c0), addmod(1, sub(f_q, mload(add(transcript, 0x1160))), f_q))mstore(add(transcript, 0x20e0), addmod(mload(add(transcript, 0x1180)), mload(add(transcript, 0x11a0)), f_q))mstore(add(transcript, 0x2100), addmod(mload(add(transcript, 0x20e0)), mload(add(transcript, 0x11c0)), f_q))mstore(add(transcript, 0x2120), addmod(mload(add(transcript, 0x2100)), mload(add(transcript, 0x11e0)), f_q))mstore(add(transcript, 0x2140), addmod(mload(add(transcript, 0x2120)), mload(add(transcript, 0x1200)), f_q))mstore(add(transcript, 0x2160), addmod(mload(add(transcript, 0x20c0)), sub(f_q, mload(add(transcript, 0x2140))), f_q))mstore(add(transcript, 0x2180), mulmod(mload(add(transcript, 0x800)), mload(add(transcript, 0x240)), f_q))mstore(add(transcript, 0x21a0), addmod(mload(add(transcript, 0x6e0)), mload(add(transcript, 0x2180)), f_q))mstore(add(transcript, 0x21c0), addmod(mload(add(transcript, 0x21a0)), mload(add(transcript, 0x2a0)), f_q))mstore(add(transcript, 0x21e0), mulmod(mload(add(transcript, 0x820)), mload(add(transcript, 0x240)), f_q))mstore(add(transcript, 0x2200), addmod(mload(add(transcript, 0x5e0)), mload(add(transcript, 0x21e0)), f_q))mstore(add(transcript, 0x2220), addmod(mload(add(transcript, 0x2200)), mload(add(transcript, 0x2a0)), f_q))mstore(add(transcript, 0x2240), mulmod(mload(add(transcript, 0x2220)), mload(add(transcript, 0x21c0)), f_q))mstore(add(transcript, 0x2260), mulmod(mload(add(transcript, 0x840)), mload(add(transcript, 0x240)), f_q))mstore(add(transcript, 0x2280), addmod(mload(add(transcript, 0x600)), mload(add(transcript, 0x2260)), f_q))mstore(add(transcript, 0x22a0), addmod(mload(add(transcript, 0x2280)), mload(add(transcript, 0x2a0)), f_q))mstore(add(transcript, 0x22c0), mulmod(mload(add(transcript, 0x22a0)), mload(add(transcript, 0x2240)), f_q))mstore(add(transcript, 0x22e0), mulmod(mload(add(transcript, 0x860)), mload(add(transcript, 0x240)), f_q))mstore(add(transcript, 0x2300), addmod(mload(add(transcript, 0x700)), mload(add(transcript, 0x22e0)), f_q))mstore(add(transcript, 0x2320), addmod(mload(add(transcript, 0x2300)), mload(add(transcript, 0x2a0)), f_q))mstore(add(transcript, 0x2340), mulmod(mload(add(transcript, 0x2320)), mload(add(transcript, 0x22c0)), f_q))mstore(add(transcript, 0x2360), mulmod(mload(add(transcript, 0x2340)), mload(add(transcript, 0x8e0)), f_q))mstore(add(transcript, 0x2380), mulmod(1, mload(add(transcript, 0x240)), f_q))mstore(add(transcript, 0x23a0), mulmod(mload(add(transcript, 0x5a0)), mload(add(transcript, 0x2380)), f_q))mstore(add(transcript, 0x23c0), addmod(mload(add(transcript, 0x6e0)), mload(add(transcript, 0x23a0)), f_q))mstore(add(transcript, 0x23e0), addmod(mload(add(transcript, 0x23c0)), mload(add(transcript, 0x2a0)), f_q))mstore(add(transcript, 0x2400), mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(add(transcript, 0x240)), f_q))mstore(add(transcript, 0x2420), mulmod(mload(add(transcript, 0x5a0)), mload(add(transcript, 0x2400)), f_q))mstore(add(transcript, 0x2440), addmod(mload(add(transcript, 0x5e0)), mload(add(transcript, 0x2420)), f_q))mstore(add(transcript, 0x2460), addmod(mload(add(transcript, 0x2440)), mload(add(transcript, 0x2a0)), f_q))mstore(add(transcript, 0x2480), mulmod(mload(add(transcript, 0x2460)), mload(add(transcript, 0x23e0)), f_q))mstore(add(transcript, 0x24a0), mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(add(transcript, 0x240)), f_q))mstore(add(transcript, 0x24c0), mulmod(mload(add(transcript, 0x5a0)), mload(add(transcript, 0x24a0)), f_q))mstore(add(transcript, 0x24e0), addmod(mload(add(transcript, 0x600)), mload(add(transcript, 0x24c0)), f_q))mstore(add(transcript, 0x2500), addmod(mload(add(transcript, 0x24e0)), mload(add(transcript, 0x2a0)), f_q))mstore(add(transcript, 0x2520), mulmod(mload(add(transcript, 0x2500)), mload(add(transcript, 0x2480)), f_q))mstore(add(transcript, 0x2540), mulmod(11166246659983828508719468090013646171463329086121580628794302409516816350802, mload(add(transcript, 0x240)), f_q))mstore(add(transcript, 0x2560), mulmod(mload(add(transcript, 0x5a0)), mload(add(transcript, 0x2540)), f_q))mstore(add(transcript, 0x2580), addmod(mload(add(transcript, 0x700)), mload(add(transcript, 0x2560)), f_q))mstore(add(transcript, 0x25a0), addmod(mload(add(transcript, 0x2580)), mload(add(transcript, 0x2a0)), f_q))mstore(add(transcript, 0x25c0), mulmod(mload(add(transcript, 0x25a0)), mload(add(transcript, 0x2520)), f_q))mstore(add(transcript, 0x25e0), mulmod(mload(add(transcript, 0x25c0)), mload(add(transcript, 0x8c0)), f_q))mstore(add(transcript, 0x2600), addmod(mload(add(transcript, 0x2360)), sub(f_q, mload(add(transcript, 0x25e0))), f_q))mstore(add(transcript, 0x2620), mulmod(mload(add(transcript, 0x2600)), mload(add(transcript, 0x2160)), f_q))mstore(add(transcript, 0x2640), addmod(mload(add(transcript, 0x20a0)), mload(add(transcript, 0x2620)), f_q))mstore(add(transcript, 0x2660), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x2640)), f_q))mstore(add(transcript, 0x2680), mulmod(mload(add(transcript, 0x880)), mload(add(transcript, 0x240)), f_q))mstore(add(transcript, 0x26a0), addmod(mload(add(transcript, 0x660)), mload(add(transcript, 0x2680)), f_q))mstore(add(transcript, 0x26c0), addmod(mload(add(transcript, 0x26a0)), mload(add(transcript, 0x2a0)), f_q))mstore(add(transcript, 0x26e0), mulmod(mload(add(transcript, 0x8a0)), mload(add(transcript, 0x240)), f_q))mstore(add(transcript, 0x2700), addmod(mload(add(transcript, 0x1280)), mload(add(transcript, 0x26e0)), f_q))mstore(add(transcript, 0x2720), addmod(mload(add(transcript, 0x2700)), mload(add(transcript, 0x2a0)), f_q))mstore(add(transcript, 0x2740), mulmod(mload(add(transcript, 0x2720)), mload(add(transcript, 0x26c0)), f_q))mstore(add(transcript, 0x2760), mulmod(mload(add(transcript, 0x2740)), mload(add(transcript, 0x940)), f_q))mstore(add(transcript, 0x2780), mulmod(284840088355319032285349970403338060113257071685626700086398481893096618818, mload(add(transcript, 0x240)), f_q))mstore(add(transcript, 0x27a0), mulmod(mload(add(transcript, 0x5a0)), mload(add(transcript, 0x2780)), f_q))mstore(add(transcript, 0x27c0), addmod(mload(add(transcript, 0x660)), mload(add(transcript, 0x27a0)), f_q))mstore(add(transcript, 0x27e0), addmod(mload(add(transcript, 0x27c0)), mload(add(transcript, 0x2a0)), f_q))mstore(add(transcript, 0x2800), mulmod(21134065618345176623193549882539580312263652408302468683943992798037078993309, mload(add(transcript, 0x240)), f_q))mstore(add(transcript, 0x2820), mulmod(mload(add(transcript, 0x5a0)), mload(add(transcript, 0x2800)), f_q))mstore(add(transcript, 0x2840), addmod(mload(add(transcript, 0x1280)), mload(add(transcript, 0x2820)), f_q))mstore(add(transcript, 0x2860), addmod(mload(add(transcript, 0x2840)), mload(add(transcript, 0x2a0)), f_q))mstore(add(transcript, 0x2880), mulmod(mload(add(transcript, 0x2860)), mload(add(transcript, 0x27e0)), f_q))mstore(add(transcript, 0x28a0), mulmod(mload(add(transcript, 0x2880)), mload(add(transcript, 0x920)), f_q))mstore(add(transcript, 0x28c0), addmod(mload(add(transcript, 0x2760)), sub(f_q, mload(add(transcript, 0x28a0))), f_q))mstore(add(transcript, 0x28e0), mulmod(mload(add(transcript, 0x28c0)), mload(add(transcript, 0x2160)), f_q))mstore(add(transcript, 0x2900), addmod(mload(add(transcript, 0x2660)), mload(add(transcript, 0x28e0)), f_q))mstore(add(transcript, 0x2920), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x2900)), f_q))mstore(add(transcript, 0x2940), addmod(1, sub(f_q, mload(add(transcript, 0x960))), f_q))mstore(add(transcript, 0x2960), mulmod(mload(add(transcript, 0x2940)), mload(add(transcript, 0x1220)), f_q))mstore(add(transcript, 0x2980), addmod(mload(add(transcript, 0x2920)), mload(add(transcript, 0x2960)), f_q))mstore(add(transcript, 0x29a0), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x2980)), f_q))mstore(add(transcript, 0x29c0), mulmod(mload(add(transcript, 0x960)), mload(add(transcript, 0x960)), f_q))mstore(add(transcript, 0x29e0), addmod(mload(add(transcript, 0x29c0)), sub(f_q, mload(add(transcript, 0x960))), f_q))mstore(add(transcript, 0x2a00), mulmod(mload(add(transcript, 0x29e0)), mload(add(transcript, 0x1160)), f_q))mstore(add(transcript, 0x2a20), addmod(mload(add(transcript, 0x29a0)), mload(add(transcript, 0x2a00)), f_q))mstore(add(transcript, 0x2a40), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x2a20)), f_q))mstore(add(transcript, 0x2a60), addmod(mload(add(transcript, 0x9a0)), mload(add(transcript, 0x240)), f_q))mstore(add(transcript, 0x2a80), mulmod(mload(add(transcript, 0x2a60)), mload(add(transcript, 0x980)), f_q))mstore(add(transcript, 0x2aa0), addmod(mload(add(transcript, 0x9e0)), mload(add(transcript, 0x2a0)), f_q))mstore(add(transcript, 0x2ac0), mulmod(mload(add(transcript, 0x2aa0)), mload(add(transcript, 0x2a80)), f_q))mstore(add(transcript, 0x2ae0), mulmod(256, mload(add(transcript, 0x6c0)), f_q))mstore(add(transcript, 0x2b00), addmod(mload(add(transcript, 0x660)), sub(f_q, mload(add(transcript, 0x2ae0))), f_q))mstore(add(transcript, 0x2b20), mulmod(mload(add(transcript, 0x2b00)), mload(add(transcript, 0x760)), f_q))mstore(add(transcript, 0x2b40), addmod(mload(add(transcript, 0x2b20)), mload(add(transcript, 0x240)), f_q))mstore(add(transcript, 0x2b60), mulmod(mload(add(transcript, 0x2b40)), mload(add(transcript, 0x960)), f_q))mstore(add(transcript, 0x2b80), addmod(mload(add(transcript, 0x720)), mload(add(transcript, 0x2a0)), f_q))mstore(add(transcript, 0x2ba0), mulmod(mload(add(transcript, 0x2b80)), mload(add(transcript, 0x2b60)), f_q))mstore(add(transcript, 0x2bc0), addmod(mload(add(transcript, 0x2ac0)), sub(f_q, mload(add(transcript, 0x2ba0))), f_q))mstore(add(transcript, 0x2be0), mulmod(mload(add(transcript, 0x2bc0)), mload(add(transcript, 0x2160)), f_q))mstore(add(transcript, 0x2c00), addmod(mload(add(transcript, 0x2a40)), mload(add(transcript, 0x2be0)), f_q))mstore(add(transcript, 0x2c20), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x2c00)), f_q))mstore(add(transcript, 0x2c40), addmod(mload(add(transcript, 0x9a0)), sub(f_q, mload(add(transcript, 0x9e0))), f_q))mstore(add(transcript, 0x2c60), mulmod(mload(add(transcript, 0x2c40)), mload(add(transcript, 0x1220)), f_q))mstore(add(transcript, 0x2c80), addmod(mload(add(transcript, 0x2c20)), mload(add(transcript, 0x2c60)), f_q))mstore(add(transcript, 0x2ca0), mulmod(mload(add(transcript, 0x400)), mload(add(transcript, 0x2c80)), f_q))mstore(add(transcript, 0x2cc0), mulmod(mload(add(transcript, 0x2c40)), mload(add(transcript, 0x2160)), f_q))mstore(add(transcript, 0x2ce0), addmod(mload(add(transcript, 0x9a0)), sub(f_q, mload(add(transcript, 0x9c0))), f_q))mstore(add(transcript, 0x2d00), mulmod(mload(add(transcript, 0x2ce0)), mload(add(transcript, 0x2cc0)), f_q))mstore(add(transcript, 0x2d20), addmod(mload(add(transcript, 0x2ca0)), mload(add(transcript, 0x2d00)), f_q))mstore(add(transcript, 0x2d40), mulmod(mload(add(transcript, 0xcc0)), mload(add(transcript, 0xcc0)), f_q))mstore(add(transcript, 0x2d60), mulmod(mload(add(transcript, 0x2d40)), mload(add(transcript, 0xcc0)), f_q))mstore(add(transcript, 0x2d80), mulmod(mload(add(transcript, 0x2d60)), mload(add(transcript, 0xcc0)), f_q))mstore(add(transcript, 0x2da0), mulmod(mload(add(transcript, 0x2d80)), mload(add(transcript, 0xcc0)), f_q))mstore(add(transcript, 0x2dc0), mulmod(1, mload(add(transcript, 0xcc0)), f_q))mstore(add(transcript, 0x2de0), mulmod(1, mload(add(transcript, 0x2d40)), f_q))mstore(add(transcript, 0x2e00), mulmod(1, mload(add(transcript, 0x2d60)), f_q))mstore(add(transcript, 0x2e20), mulmod(1, mload(add(transcript, 0x2d80)), f_q))mstore(add(transcript, 0x2e40), mulmod(mload(add(transcript, 0x2d20)), mload(add(transcript, 0xce0)), f_q))mstore(add(transcript, 0x2e60), mulmod(mload(add(transcript, 0xba0)), mload(add(transcript, 0x5a0)), f_q))mstore(add(transcript, 0x2e80), mulmod(mload(add(transcript, 0x5a0)), 1, f_q))mstore(add(transcript, 0x2ea0), addmod(mload(add(transcript, 0xb20)), sub(f_q, mload(add(transcript, 0x2e80))), f_q))mstore(add(transcript, 0x2ec0), mulmod(mload(add(transcript, 0x5a0)), 4925592601992654644734291590386747644864797672605745962807370354577123815907, f_q))mstore(add(transcript, 0x2ee0), addmod(mload(add(transcript, 0xb20)), sub(f_q, mload(add(transcript, 0x2ec0))), f_q))mstore(add(transcript, 0x2f00), mulmod(mload(add(transcript, 0x5a0)), 9936069627611189518829255670237324269287146421271524553312532036927871056678, f_q))mstore(add(transcript, 0x2f20), addmod(mload(add(transcript, 0xb20)), sub(f_q, mload(add(transcript, 0x2f00))), f_q))mstore(add(transcript, 0x2f40), mulmod(mload(add(transcript, 0x5a0)), 19380560087801265747114831706136320509424814679569278834391540198888293317501, f_q))mstore(add(transcript, 0x2f60), addmod(mload(add(transcript, 0xb20)), sub(f_q, mload(add(transcript, 0x2f40))), f_q)){ let result := mulmod(mload(add(transcript, 0xb20)), mulmod(mload(add(transcript, 0xba0)), 19470333053884630052643688193991482022807116448657043890197497819686199857828, f_q), f_q)result := addmod(mulmod(mload(add(transcript, 0x5a0)), mulmod(mload(add(transcript, 0xba0)), 2417909817954645169602717551265793065741247951758990453500706366889608637789, f_q), f_q), result, f_q)mstore(add(transcript, 0x2f80), result) }{ let result := mulmod(mload(add(transcript, 0xb20)), mulmod(mload(add(transcript, 0xba0)), 13686227242150003628673578706486473027501243666075718775893288845164412632930, f_q), f_q)result := addmod(mulmod(mload(add(transcript, 0x5a0)), mulmod(mload(add(transcript, 0xba0)), 10079503758141076467065204586507257535549232608832327988764044976944819876346, f_q), f_q), result, f_q)mstore(add(transcript, 0x2fa0), result) }{ let result := mulmod(mload(add(transcript, 0xb20)), mulmod(mload(add(transcript, 0xba0)), 18715936898160381416714524359517348601997944075114713669820885373469568354766, f_q), f_q)result := addmod(mulmod(mload(add(transcript, 0x5a0)), mulmod(mload(add(transcript, 0xba0)), 15375775075249615866494035504844970190233299190010037655541891534730124992278, f_q), f_q), result, f_q)mstore(add(transcript, 0x2fc0), result) }mstore(add(transcript, 0x2fe0), mulmod(1, mload(add(transcript, 0x2ea0)), f_q))mstore(add(transcript, 0x3000), mulmod(mload(add(transcript, 0x2fe0)), mload(add(transcript, 0x2f60)), f_q))mstore(add(transcript, 0x3020), mulmod(mload(add(transcript, 0x3000)), mload(add(transcript, 0x2ee0)), f_q)){ let result := mulmod(mload(add(transcript, 0xb20)), mulmod(mload(add(transcript, 0x5a0)), 2507682784038009475131574039120954579123549720846755509306663987687515178117, f_q), f_q)result := addmod(mulmod(mload(add(transcript, 0x5a0)), mulmod(mload(add(transcript, 0x5a0)), 19380560087801265747114831706136320509424814679569278834391540198888293317500, f_q), f_q), result, f_q)mstore(add(transcript, 0x3040), result) }{ let result := mulmod(mload(add(transcript, 0xb20)), mulmod(mload(add(transcript, 0x5a0)), 19380560087801265747114831706136320509424814679569278834391540198888293317500, f_q), f_q)result := addmod(mulmod(mload(add(transcript, 0x5a0)), mulmod(mload(add(transcript, 0x5a0)), 13127608231681926238307118629157549705911918406946061530612285695988519678593, f_q), f_q), result, f_q)mstore(add(transcript, 0x3060), result) }{ let result := mulmod(mload(add(transcript, 0xb20)), mulmod(mload(add(transcript, 0xba0)), 16140595808673403009154643164823336476463527776677864878778453135559733237044, f_q), f_q)result := addmod(mulmod(mload(add(transcript, 0x5a0)), mulmod(mload(add(transcript, 0xba0)), 5747647063165872213091762580433938612084836623738169464919751051016075258573, f_q), f_q), result, f_q)mstore(add(transcript, 0x3080), result) }{ let result := mulmod(mload(add(transcript, 0xb20)), mulmod(mload(add(transcript, 0xba0)), 17015964487361230672162623735654618573844832338054897787312333529290879253714, f_q), f_q)result := addmod(mulmod(mload(add(transcript, 0x5a0)), mulmod(mload(add(transcript, 0xba0)), 3176732791729641355588945816447819802711920387939493967460175841862547409845, f_q), f_q), result, f_q)mstore(add(transcript, 0x30a0), result) }{ let result := mulmod(mload(add(transcript, 0xb20)), mulmod(mload(add(transcript, 0xba0)), 19187508498431587163140984396833674282302409422288044257471288693049179355069, f_q), f_q)result := addmod(mulmod(mload(add(transcript, 0x5a0)), mulmod(mload(add(transcript, 0xba0)), 17472297497993506786357772047295541913219081564856233764575529621311665103799, f_q), f_q), result, f_q)mstore(add(transcript, 0x30c0), result) }mstore(add(transcript, 0x30e0), mulmod(mload(add(transcript, 0x3000)), mload(add(transcript, 0x2f20)), f_q)){ let result := mulmod(mload(add(transcript, 0xb20)), mulmod(mload(add(transcript, 0x5a0)), 16962650269846620577512114154870527443683566727810288380890833831998684679711, f_q), f_q)result := addmod(mulmod(mload(add(transcript, 0x5a0)), mulmod(mload(add(transcript, 0x5a0)), 4925592601992654644734291590386747644864797672605745962807370354577123815906, f_q), f_q), result, f_q)mstore(add(transcript, 0x3100), result) }{ let result := mulmod(mload(add(transcript, 0xb20)), mulmod(mload(add(transcript, 0x5a0)), 4925592601992654644734291590386747644864797672605745962807370354577123815906, f_q), f_q)result := addmod(mulmod(mload(add(transcript, 0x5a0)), mulmod(mload(add(transcript, 0x5a0)), 664623189640884330400307346618971907426870604454565164570654825418724962734, f_q), f_q), result, f_q)mstore(add(transcript, 0x3120), result) }mstore(add(transcript, 0x3140), mulmod(mload(add(transcript, 0x2fe0)), mload(add(transcript, 0x2ee0)), f_q)){ let result := mulmod(mload(add(transcript, 0xb20)), 1, f_q)result := addmod(mulmod(mload(add(transcript, 0x5a0)), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q), result, f_q)mstore(add(transcript, 0x3160), result) }{ let prod := mload(add(transcript, 0x2f80)) prod := mulmod(mload(add(transcript, 0x2fa0)), prod, f_q) mstore(add(transcript, 0x3180), prod) prod := mulmod(mload(add(transcript, 0x2fc0)), prod, f_q) mstore(add(transcript, 0x31a0), prod) prod := mulmod(mload(add(transcript, 0x3040)), prod, f_q) mstore(add(transcript, 0x31c0), prod) prod := mulmod(mload(add(transcript, 0x3060)), prod, f_q) mstore(add(transcript, 0x31e0), prod) prod := mulmod(mload(add(transcript, 0x3000)), prod, f_q) mstore(add(transcript, 0x3200), prod) prod := mulmod(mload(add(transcript, 0x3080)), prod, f_q) mstore(add(transcript, 0x3220), prod) prod := mulmod(mload(add(transcript, 0x30a0)), prod, f_q) mstore(add(transcript, 0x3240), prod) prod := mulmod(mload(add(transcript, 0x30c0)), prod, f_q) mstore(add(transcript, 0x3260), prod) prod := mulmod(mload(add(transcript, 0x30e0)), prod, f_q) mstore(add(transcript, 0x3280), prod) prod := mulmod(mload(add(transcript, 0x3100)), prod, f_q) mstore(add(transcript, 0x32a0), prod) prod := mulmod(mload(add(transcript, 0x3120)), prod, f_q) mstore(add(transcript, 0x32c0), prod) prod := mulmod(mload(add(transcript, 0x3140)), prod, f_q) mstore(add(transcript, 0x32e0), prod) prod := mulmod(mload(add(transcript, 0x3160)), prod, f_q) mstore(add(transcript, 0x3300), prod) prod := mulmod(mload(add(transcript, 0x2fe0)), prod, f_q) mstore(add(transcript, 0x3320), prod) }mstore(add(transcript, 0x3360), 32)mstore(add(transcript, 0x3380), 32)mstore(add(transcript, 0x33a0), 32)mstore(add(transcript, 0x33c0), mload(add(transcript, 0x3320)))mstore(add(transcript, 0x33e0), 21888242871839275222246405745257275088548364400416034343698204186575808495615)mstore(add(transcript, 0x3400), 21888242871839275222246405745257275088548364400416034343698204186575808495617)success := and(eq(staticcall(gas(), 0x5, add(transcript, 0x3360), 0xc0, add(transcript, 0x3340), 0x20), 1), success){ let inv := mload(add(transcript, 0x3340)) let v v := mload(add(transcript, 0x2fe0)) mstore(add(transcript, 0x2fe0), mulmod(mload(add(transcript, 0x3300)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0x3160)) mstore(add(transcript, 0x3160), mulmod(mload(add(transcript, 0x32e0)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0x3140)) mstore(add(transcript, 0x3140), mulmod(mload(add(transcript, 0x32c0)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0x3120)) mstore(add(transcript, 0x3120), mulmod(mload(add(transcript, 0x32a0)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0x3100)) mstore(add(transcript, 0x3100), mulmod(mload(add(transcript, 0x3280)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0x30e0)) mstore(add(transcript, 0x30e0), mulmod(mload(add(transcript, 0x3260)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0x30c0)) mstore(add(transcript, 0x30c0), mulmod(mload(add(transcript, 0x3240)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0x30a0)) mstore(add(transcript, 0x30a0), mulmod(mload(add(transcript, 0x3220)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0x3080)) mstore(add(transcript, 0x3080), mulmod(mload(add(transcript, 0x3200)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0x3000)) mstore(add(transcript, 0x3000), mulmod(mload(add(transcript, 0x31e0)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0x3060)) mstore(add(transcript, 0x3060), mulmod(mload(add(transcript, 0x31c0)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0x3040)) mstore(add(transcript, 0x3040), mulmod(mload(add(transcript, 0x31a0)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0x2fc0)) mstore(add(transcript, 0x2fc0), mulmod(mload(add(transcript, 0x3180)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0x2fa0)) mstore(add(transcript, 0x2fa0), mulmod(mload(add(transcript, 0x2f80)), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(add(transcript, 0x2f80), inv) }{ let result := mload(add(transcript, 0x2f80))result := addmod(mload(add(transcript, 0x2fa0)), result, f_q)result := addmod(mload(add(transcript, 0x2fc0)), result, f_q)mstore(add(transcript, 0x3420), result) }mstore(add(transcript, 0x3440), mulmod(mload(add(transcript, 0x3020)), mload(add(transcript, 0x3000)), f_q)){ let result := mload(add(transcript, 0x3040))result := addmod(mload(add(transcript, 0x3060)), result, f_q)mstore(add(transcript, 0x3460), result) }mstore(add(transcript, 0x3480), mulmod(mload(add(transcript, 0x3020)), mload(add(transcript, 0x30e0)), f_q)){ let result := mload(add(transcript, 0x3080))result := addmod(mload(add(transcript, 0x30a0)), result, f_q)result := addmod(mload(add(transcript, 0x30c0)), result, f_q)mstore(add(transcript, 0x34a0), result) }mstore(add(transcript, 0x34c0), mulmod(mload(add(transcript, 0x3020)), mload(add(transcript, 0x3140)), f_q)){ let result := mload(add(transcript, 0x3100))result := addmod(mload(add(transcript, 0x3120)), result, f_q)mstore(add(transcript, 0x34e0), result) }mstore(add(transcript, 0x3500), mulmod(mload(add(transcript, 0x3020)), mload(add(transcript, 0x2fe0)), f_q)){ let result := mload(add(transcript, 0x3160))mstore(add(transcript, 0x3520), result) }{ let prod := mload(add(transcript, 0x3420)) prod := mulmod(mload(add(transcript, 0x3460)), prod, f_q) mstore(add(transcript, 0x3540), prod) prod := mulmod(mload(add(transcript, 0x34a0)), prod, f_q) mstore(add(transcript, 0x3560), prod) prod := mulmod(mload(add(transcript, 0x34e0)), prod, f_q) mstore(add(transcript, 0x3580), prod) prod := mulmod(mload(add(transcript, 0x3520)), prod, f_q) mstore(add(transcript, 0x35a0), prod) }mstore(add(transcript, 0x35e0), 32)mstore(add(transcript, 0x3600), 32)mstore(add(transcript, 0x3620), 32)mstore(add(transcript, 0x3640), mload(add(transcript, 0x35a0)))mstore(add(transcript, 0x3660), 21888242871839275222246405745257275088548364400416034343698204186575808495615)mstore(add(transcript, 0x3680), 21888242871839275222246405745257275088548364400416034343698204186575808495617)success := and(eq(staticcall(gas(), 0x5, add(transcript, 0x35e0), 0xc0, add(transcript, 0x35c0), 0x20), 1), success){ let inv := mload(add(transcript, 0x35c0)) let v v := mload(add(transcript, 0x3520)) mstore(add(transcript, 0x3520), mulmod(mload(add(transcript, 0x3580)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0x34e0)) mstore(add(transcript, 0x34e0), mulmod(mload(add(transcript, 0x3560)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0x34a0)) mstore(add(transcript, 0x34a0), mulmod(mload(add(transcript, 0x3540)), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(add(transcript, 0x3460)) mstore(add(transcript, 0x3460), mulmod(mload(add(transcript, 0x3420)), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(add(transcript, 0x3420), inv) }mstore(add(transcript, 0x36a0), mulmod(mload(add(transcript, 0x3440)), mload(add(transcript, 0x3460)), f_q))mstore(add(transcript, 0x36c0), mulmod(mload(add(transcript, 0x3480)), mload(add(transcript, 0x34a0)), f_q))mstore(add(transcript, 0x36e0), mulmod(mload(add(transcript, 0x34c0)), mload(add(transcript, 0x34e0)), f_q))mstore(add(transcript, 0x3700), mulmod(mload(add(transcript, 0x3500)), mload(add(transcript, 0x3520)), f_q))mstore(add(transcript, 0x3720), mulmod(mload(add(transcript, 0xa20)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x3740), mulmod(mload(add(transcript, 0x3720)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x3760), mulmod(mload(add(transcript, 0x3740)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x3780), mulmod(mload(add(transcript, 0x3760)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x37a0), mulmod(mload(add(transcript, 0x3780)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x37c0), mulmod(mload(add(transcript, 0x37a0)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x37e0), mulmod(mload(add(transcript, 0x37c0)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x3800), mulmod(mload(add(transcript, 0x37e0)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x3820), mulmod(mload(add(transcript, 0x3800)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x3840), mulmod(mload(add(transcript, 0x3820)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x3860), mulmod(mload(add(transcript, 0x3840)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x3880), mulmod(mload(add(transcript, 0x3860)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x38a0), mulmod(mload(add(transcript, 0x3880)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x38c0), mulmod(mload(add(transcript, 0x38a0)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x38e0), mulmod(mload(add(transcript, 0x38c0)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x3900), mulmod(mload(add(transcript, 0x38e0)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x3920), mulmod(mload(add(transcript, 0xa80)), mload(add(transcript, 0xa80)), f_q))mstore(add(transcript, 0x3940), mulmod(mload(add(transcript, 0x3920)), mload(add(transcript, 0xa80)), f_q))mstore(add(transcript, 0x3960), mulmod(mload(add(transcript, 0x3940)), mload(add(transcript, 0xa80)), f_q))mstore(add(transcript, 0x3980), mulmod(mload(add(transcript, 0x3960)), mload(add(transcript, 0xa80)), f_q)){ let result := mulmod(mload(add(transcript, 0x5e0)), mload(add(transcript, 0x2f80)), f_q)result := addmod(mulmod(mload(add(transcript, 0x620)), mload(add(transcript, 0x2fa0)), f_q), result, f_q)result := addmod(mulmod(mload(add(transcript, 0x6a0)), mload(add(transcript, 0x2fc0)), f_q), result, f_q)mstore(add(transcript, 0x39a0), result) }mstore(add(transcript, 0x39c0), mulmod(mload(add(transcript, 0x39a0)), mload(add(transcript, 0x3420)), f_q))mstore(add(transcript, 0x39e0), mulmod(sub(f_q, mload(add(transcript, 0x39c0))), 1, f_q)){ let result := mulmod(mload(add(transcript, 0x600)), mload(add(transcript, 0x2f80)), f_q)result := addmod(mulmod(mload(add(transcript, 0x640)), mload(add(transcript, 0x2fa0)), f_q), result, f_q)result := addmod(mulmod(mload(add(transcript, 0x680)), mload(add(transcript, 0x2fc0)), f_q), result, f_q)mstore(add(transcript, 0x3a00), result) }mstore(add(transcript, 0x3a20), mulmod(mload(add(transcript, 0x3a00)), mload(add(transcript, 0x3420)), f_q))mstore(add(transcript, 0x3a40), mulmod(sub(f_q, mload(add(transcript, 0x3a20))), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x3a60), mulmod(1, mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x3a80), addmod(mload(add(transcript, 0x39e0)), mload(add(transcript, 0x3a40)), f_q))mstore(add(transcript, 0x3aa0), mulmod(mload(add(transcript, 0x3a80)), 1, f_q))mstore(add(transcript, 0x3ac0), mulmod(mload(add(transcript, 0x3a60)), 1, f_q))mstore(add(transcript, 0x3ae0), mulmod(1, mload(add(transcript, 0x3440)), f_q)){ let result := mulmod(mload(add(transcript, 0x660)), mload(add(transcript, 0x3040)), f_q)result := addmod(mulmod(mload(add(transcript, 0x6c0)), mload(add(transcript, 0x3060)), f_q), result, f_q)mstore(add(transcript, 0x3b00), result) }mstore(add(transcript, 0x3b20), mulmod(mload(add(transcript, 0x3b00)), mload(add(transcript, 0x36a0)), f_q))mstore(add(transcript, 0x3b40), mulmod(sub(f_q, mload(add(transcript, 0x3b20))), 1, f_q))mstore(add(transcript, 0x3b60), mulmod(mload(add(transcript, 0x3ae0)), 1, f_q)){ let result := mulmod(mload(add(transcript, 0x920)), mload(add(transcript, 0x3040)), f_q)result := addmod(mulmod(mload(add(transcript, 0x940)), mload(add(transcript, 0x3060)), f_q), result, f_q)mstore(add(transcript, 0x3b80), result) }mstore(add(transcript, 0x3ba0), mulmod(mload(add(transcript, 0x3b80)), mload(add(transcript, 0x36a0)), f_q))mstore(add(transcript, 0x3bc0), mulmod(sub(f_q, mload(add(transcript, 0x3ba0))), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x3be0), mulmod(mload(add(transcript, 0x3ae0)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x3c00), addmod(mload(add(transcript, 0x3b40)), mload(add(transcript, 0x3bc0)), f_q)){ let result := mulmod(mload(add(transcript, 0x960)), mload(add(transcript, 0x3040)), f_q)result := addmod(mulmod(mload(add(transcript, 0x980)), mload(add(transcript, 0x3060)), f_q), result, f_q)mstore(add(transcript, 0x3c20), result) }mstore(add(transcript, 0x3c40), mulmod(mload(add(transcript, 0x3c20)), mload(add(transcript, 0x36a0)), f_q))mstore(add(transcript, 0x3c60), mulmod(sub(f_q, mload(add(transcript, 0x3c40))), mload(add(transcript, 0x3720)), f_q))mstore(add(transcript, 0x3c80), mulmod(mload(add(transcript, 0x3ae0)), mload(add(transcript, 0x3720)), f_q))mstore(add(transcript, 0x3ca0), addmod(mload(add(transcript, 0x3c00)), mload(add(transcript, 0x3c60)), f_q))mstore(add(transcript, 0x3cc0), mulmod(mload(add(transcript, 0x3ca0)), mload(add(transcript, 0xa80)), f_q))mstore(add(transcript, 0x3ce0), mulmod(mload(add(transcript, 0x3b60)), mload(add(transcript, 0xa80)), f_q))mstore(add(transcript, 0x3d00), mulmod(mload(add(transcript, 0x3be0)), mload(add(transcript, 0xa80)), f_q))mstore(add(transcript, 0x3d20), mulmod(mload(add(transcript, 0x3c80)), mload(add(transcript, 0xa80)), f_q))mstore(add(transcript, 0x3d40), addmod(mload(add(transcript, 0x3aa0)), mload(add(transcript, 0x3cc0)), f_q))mstore(add(transcript, 0x3d60), mulmod(1, mload(add(transcript, 0x3480)), f_q)){ let result := mulmod(mload(add(transcript, 0x8c0)), mload(add(transcript, 0x3080)), f_q)result := addmod(mulmod(mload(add(transcript, 0x8e0)), mload(add(transcript, 0x30a0)), f_q), result, f_q)result := addmod(mulmod(mload(add(transcript, 0x900)), mload(add(transcript, 0x30c0)), f_q), result, f_q)mstore(add(transcript, 0x3d80), result) }mstore(add(transcript, 0x3da0), mulmod(mload(add(transcript, 0x3d80)), mload(add(transcript, 0x36c0)), f_q))mstore(add(transcript, 0x3dc0), mulmod(sub(f_q, mload(add(transcript, 0x3da0))), 1, f_q))mstore(add(transcript, 0x3de0), mulmod(mload(add(transcript, 0x3d60)), 1, f_q))mstore(add(transcript, 0x3e00), mulmod(mload(add(transcript, 0x3dc0)), mload(add(transcript, 0x3920)), f_q))mstore(add(transcript, 0x3e20), mulmod(mload(add(transcript, 0x3de0)), mload(add(transcript, 0x3920)), f_q))mstore(add(transcript, 0x3e40), addmod(mload(add(transcript, 0x3d40)), mload(add(transcript, 0x3e00)), f_q))mstore(add(transcript, 0x3e60), mulmod(1, mload(add(transcript, 0x34c0)), f_q)){ let result := mulmod(mload(add(transcript, 0x9a0)), mload(add(transcript, 0x3100)), f_q)result := addmod(mulmod(mload(add(transcript, 0x9c0)), mload(add(transcript, 0x3120)), f_q), result, f_q)mstore(add(transcript, 0x3e80), result) }mstore(add(transcript, 0x3ea0), mulmod(mload(add(transcript, 0x3e80)), mload(add(transcript, 0x36e0)), f_q))mstore(add(transcript, 0x3ec0), mulmod(sub(f_q, mload(add(transcript, 0x3ea0))), 1, f_q))mstore(add(transcript, 0x3ee0), mulmod(mload(add(transcript, 0x3e60)), 1, f_q))mstore(add(transcript, 0x3f00), mulmod(mload(add(transcript, 0x3ec0)), mload(add(transcript, 0x3940)), f_q))mstore(add(transcript, 0x3f20), mulmod(mload(add(transcript, 0x3ee0)), mload(add(transcript, 0x3940)), f_q))mstore(add(transcript, 0x3f40), addmod(mload(add(transcript, 0x3e40)), mload(add(transcript, 0x3f00)), f_q))mstore(add(transcript, 0x3f60), mulmod(1, mload(add(transcript, 0x3500)), f_q)){ let result := mulmod(mload(add(transcript, 0x9e0)), mload(add(transcript, 0x3160)), f_q)mstore(add(transcript, 0x3f80), result) }mstore(add(transcript, 0x3fa0), mulmod(mload(add(transcript, 0x3f80)), mload(add(transcript, 0x3700)), f_q))mstore(add(transcript, 0x3fc0), mulmod(sub(f_q, mload(add(transcript, 0x3fa0))), 1, f_q))mstore(add(transcript, 0x3fe0), mulmod(mload(add(transcript, 0x3f60)), 1, f_q)){ let result := mulmod(mload(add(transcript, 0x6e0)), mload(add(transcript, 0x3160)), f_q)mstore(add(transcript, 0x4000), result) }mstore(add(transcript, 0x4020), mulmod(mload(add(transcript, 0x4000)), mload(add(transcript, 0x3700)), f_q))mstore(add(transcript, 0x4040), mulmod(sub(f_q, mload(add(transcript, 0x4020))), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x4060), mulmod(mload(add(transcript, 0x3f60)), mload(add(transcript, 0xa20)), f_q))mstore(add(transcript, 0x4080), addmod(mload(add(transcript, 0x3fc0)), mload(add(transcript, 0x4040)), f_q)){ let result := mulmod(mload(add(transcript, 0x700)), mload(add(transcript, 0x3160)), f_q)mstore(add(transcript, 0x40a0), result) }mstore(add(transcript, 0x40c0), mulmod(mload(add(transcript, 0x40a0)), mload(add(transcript, 0x3700)), f_q))mstore(add(transcript, 0x40e0), mulmod(sub(f_q, mload(add(transcript, 0x40c0))), mload(add(transcript, 0x3720)), f_q))mstore(add(transcript, 0x4100), mulmod(mload(add(transcript, 0x3f60)), mload(add(transcript, 0x3720)), f_q))mstore(add(transcript, 0x4120), addmod(mload(add(transcript, 0x4080)), mload(add(transcript, 0x40e0)), f_q)){ let result := mulmod(mload(add(transcript, 0x720)), mload(add(transcript, 0x3160)), f_q)mstore(add(transcript, 0x4140), result) }mstore(add(transcript, 0x4160), mulmod(mload(add(transcript, 0x4140)), mload(add(transcript, 0x3700)), f_q))mstore(add(transcript, 0x4180), mulmod(sub(f_q, mload(add(transcript, 0x4160))), mload(add(transcript, 0x3740)), f_q))mstore(add(transcript, 0x41a0), mulmod(mload(add(transcript, 0x3f60)), mload(add(transcript, 0x3740)), f_q))mstore(add(transcript, 0x41c0), addmod(mload(add(transcript, 0x4120)), mload(add(transcript, 0x4180)), f_q)){ let result := mulmod(mload(add(transcript, 0x740)), mload(add(transcript, 0x3160)), f_q)mstore(add(transcript, 0x41e0), result) }mstore(add(transcript, 0x4200), mulmod(mload(add(transcript, 0x41e0)), mload(add(transcript, 0x3700)), f_q))mstore(add(transcript, 0x4220), mulmod(sub(f_q, mload(add(transcript, 0x4200))), mload(add(transcript, 0x3760)), f_q))mstore(add(transcript, 0x4240), mulmod(mload(add(transcript, 0x3f60)), mload(add(transcript, 0x3760)), f_q))mstore(add(transcript, 0x4260), addmod(mload(add(transcript, 0x41c0)), mload(add(transcript, 0x4220)), f_q)){ let result := mulmod(mload(add(transcript, 0x760)), mload(add(transcript, 0x3160)), f_q)mstore(add(transcript, 0x4280), result) }mstore(add(transcript, 0x42a0), mulmod(mload(add(transcript, 0x4280)), mload(add(transcript, 0x3700)), f_q))mstore(add(transcript, 0x42c0), mulmod(sub(f_q, mload(add(transcript, 0x42a0))), mload(add(transcript, 0x3780)), f_q))mstore(add(transcript, 0x42e0), mulmod(mload(add(transcript, 0x3f60)), mload(add(transcript, 0x3780)), f_q))mstore(add(transcript, 0x4300), addmod(mload(add(transcript, 0x4260)), mload(add(transcript, 0x42c0)), f_q)){ let result := mulmod(mload(add(transcript, 0x780)), mload(add(transcript, 0x3160)), f_q)mstore(add(transcript, 0x4320), result) }mstore(add(transcript, 0x4340), mulmod(mload(add(transcript, 0x4320)), mload(add(transcript, 0x3700)), f_q))mstore(add(transcript, 0x4360), mulmod(sub(f_q, mload(add(transcript, 0x4340))), mload(add(transcript, 0x37a0)), f_q))mstore(add(transcript, 0x4380), mulmod(mload(add(transcript, 0x3f60)), mload(add(transcript, 0x37a0)), f_q))mstore(add(transcript, 0x43a0), addmod(mload(add(transcript, 0x4300)), mload(add(transcript, 0x4360)), f_q)){ let result := mulmod(mload(add(transcript, 0x7a0)), mload(add(transcript, 0x3160)), f_q)mstore(add(transcript, 0x43c0), result) }mstore(add(transcript, 0x43e0), mulmod(mload(add(transcript, 0x43c0)), mload(add(transcript, 0x3700)), f_q))mstore(add(transcript, 0x4400), mulmod(sub(f_q, mload(add(transcript, 0x43e0))), mload(add(transcript, 0x37c0)), f_q))mstore(add(transcript, 0x4420), mulmod(mload(add(transcript, 0x3f60)), mload(add(transcript, 0x37c0)), f_q))mstore(add(transcript, 0x4440), addmod(mload(add(transcript, 0x43a0)), mload(add(transcript, 0x4400)), f_q)){ let result := mulmod(mload(add(transcript, 0x7c0)), mload(add(transcript, 0x3160)), f_q)mstore(add(transcript, 0x4460), result) }mstore(add(transcript, 0x4480), mulmod(mload(add(transcript, 0x4460)), mload(add(transcript, 0x3700)), f_q))mstore(add(transcript, 0x44a0), mulmod(sub(f_q, mload(add(transcript, 0x4480))), mload(add(transcript, 0x37e0)), f_q))mstore(add(transcript, 0x44c0), mulmod(mload(add(transcript, 0x3f60)), mload(add(transcript, 0x37e0)), f_q))mstore(add(transcript, 0x44e0), addmod(mload(add(transcript, 0x4440)), mload(add(transcript, 0x44a0)), f_q)){ let result := mulmod(mload(add(transcript, 0x800)), mload(add(transcript, 0x3160)), f_q)mstore(add(transcript, 0x4500), result) }mstore(add(transcript, 0x4520), mulmod(mload(add(transcript, 0x4500)), mload(add(transcript, 0x3700)), f_q))mstore(add(transcript, 0x4540), mulmod(sub(f_q, mload(add(transcript, 0x4520))), mload(add(transcript, 0x3800)), f_q))mstore(add(transcript, 0x4560), mulmod(mload(add(transcript, 0x3f60)), mload(add(transcript, 0x3800)), f_q))mstore(add(transcript, 0x4580), addmod(mload(add(transcript, 0x44e0)), mload(add(transcript, 0x4540)), f_q)){ let result := mulmod(mload(add(transcript, 0x820)), mload(add(transcript, 0x3160)), f_q)mstore(add(transcript, 0x45a0), result) }mstore(add(transcript, 0x45c0), mulmod(mload(add(transcript, 0x45a0)), mload(add(transcript, 0x3700)), f_q))mstore(add(transcript, 0x45e0), mulmod(sub(f_q, mload(add(transcript, 0x45c0))), mload(add(transcript, 0x3820)), f_q))mstore(add(transcript, 0x4600), mulmod(mload(add(transcript, 0x3f60)), mload(add(transcript, 0x3820)), f_q))mstore(add(transcript, 0x4620), addmod(mload(add(transcript, 0x4580)), mload(add(transcript, 0x45e0)), f_q)){ let result := mulmod(mload(add(transcript, 0x840)), mload(add(transcript, 0x3160)), f_q)mstore(add(transcript, 0x4640), result) }mstore(add(transcript, 0x4660), mulmod(mload(add(transcript, 0x4640)), mload(add(transcript, 0x3700)), f_q))mstore(add(transcript, 0x4680), mulmod(sub(f_q, mload(add(transcript, 0x4660))), mload(add(transcript, 0x3840)), f_q))mstore(add(transcript, 0x46a0), mulmod(mload(add(transcript, 0x3f60)), mload(add(transcript, 0x3840)), f_q))mstore(add(transcript, 0x46c0), addmod(mload(add(transcript, 0x4620)), mload(add(transcript, 0x4680)), f_q)){ let result := mulmod(mload(add(transcript, 0x860)), mload(add(transcript, 0x3160)), f_q)mstore(add(transcript, 0x46e0), result) }mstore(add(transcript, 0x4700), mulmod(mload(add(transcript, 0x46e0)), mload(add(transcript, 0x3700)), f_q))mstore(add(transcript, 0x4720), mulmod(sub(f_q, mload(add(transcript, 0x4700))), mload(add(transcript, 0x3860)), f_q))mstore(add(transcript, 0x4740), mulmod(mload(add(transcript, 0x3f60)), mload(add(transcript, 0x3860)), f_q))mstore(add(transcript, 0x4760), addmod(mload(add(transcript, 0x46c0)), mload(add(transcript, 0x4720)), f_q)){ let result := mulmod(mload(add(transcript, 0x880)), mload(add(transcript, 0x3160)), f_q)mstore(add(transcript, 0x4780), result) }mstore(add(transcript, 0x47a0), mulmod(mload(add(transcript, 0x4780)), mload(add(transcript, 0x3700)), f_q))mstore(add(transcript, 0x47c0), mulmod(sub(f_q, mload(add(transcript, 0x47a0))), mload(add(transcript, 0x3880)), f_q))mstore(add(transcript, 0x47e0), mulmod(mload(add(transcript, 0x3f60)), mload(add(transcript, 0x3880)), f_q))mstore(add(transcript, 0x4800), addmod(mload(add(transcript, 0x4760)), mload(add(transcript, 0x47c0)), f_q)){ let result := mulmod(mload(add(transcript, 0x8a0)), mload(add(transcript, 0x3160)), f_q)mstore(add(transcript, 0x4820), result) }mstore(add(transcript, 0x4840), mulmod(mload(add(transcript, 0x4820)), mload(add(transcript, 0x3700)), f_q))mstore(add(transcript, 0x4860), mulmod(sub(f_q, mload(add(transcript, 0x4840))), mload(add(transcript, 0x38a0)), f_q))mstore(add(transcript, 0x4880), mulmod(mload(add(transcript, 0x3f60)), mload(add(transcript, 0x38a0)), f_q))mstore(add(transcript, 0x48a0), addmod(mload(add(transcript, 0x4800)), mload(add(transcript, 0x4860)), f_q))mstore(add(transcript, 0x48c0), mulmod(mload(add(transcript, 0x2dc0)), mload(add(transcript, 0x3500)), f_q))mstore(add(transcript, 0x48e0), mulmod(mload(add(transcript, 0x2de0)), mload(add(transcript, 0x3500)), f_q))mstore(add(transcript, 0x4900), mulmod(mload(add(transcript, 0x2e00)), mload(add(transcript, 0x3500)), f_q))mstore(add(transcript, 0x4920), mulmod(mload(add(transcript, 0x2e20)), mload(add(transcript, 0x3500)), f_q)){ let result := mulmod(mload(add(transcript, 0x2e40)), mload(add(transcript, 0x3160)), f_q)mstore(add(transcript, 0x4940), result) }mstore(add(transcript, 0x4960), mulmod(mload(add(transcript, 0x4940)), mload(add(transcript, 0x3700)), f_q))mstore(add(transcript, 0x4980), mulmod(sub(f_q, mload(add(transcript, 0x4960))), mload(add(transcript, 0x38c0)), f_q))mstore(add(transcript, 0x49a0), mulmod(mload(add(transcript, 0x3f60)), mload(add(transcript, 0x38c0)), f_q))mstore(add(transcript, 0x49c0), mulmod(mload(add(transcript, 0x48c0)), mload(add(transcript, 0x38c0)), f_q))mstore(add(transcript, 0x49e0), mulmod(mload(add(transcript, 0x48e0)), mload(add(transcript, 0x38c0)), f_q))mstore(add(transcript, 0x4a00), mulmod(mload(add(transcript, 0x4900)), mload(add(transcript, 0x38c0)), f_q))mstore(add(transcript, 0x4a20), mulmod(mload(add(transcript, 0x4920)), mload(add(transcript, 0x38c0)), f_q))mstore(add(transcript, 0x4a40), addmod(mload(add(transcript, 0x48a0)), mload(add(transcript, 0x4980)), f_q)){ let result := mulmod(mload(add(transcript, 0x7e0)), mload(add(transcript, 0x3160)), f_q)mstore(add(transcript, 0x4a60), result) }mstore(add(transcript, 0x4a80), mulmod(mload(add(transcript, 0x4a60)), mload(add(transcript, 0x3700)), f_q))mstore(add(transcript, 0x4aa0), mulmod(sub(f_q, mload(add(transcript, 0x4a80))), mload(add(transcript, 0x38e0)), f_q))mstore(add(transcript, 0x4ac0), mulmod(mload(add(transcript, 0x3f60)), mload(add(transcript, 0x38e0)), f_q))mstore(add(transcript, 0x4ae0), addmod(mload(add(transcript, 0x4a40)), mload(add(transcript, 0x4aa0)), f_q))mstore(add(transcript, 0x4b00), mulmod(mload(add(transcript, 0x4ae0)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4b20), mulmod(mload(add(transcript, 0x3fe0)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4b40), mulmod(mload(add(transcript, 0x4060)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4b60), mulmod(mload(add(transcript, 0x4100)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4b80), mulmod(mload(add(transcript, 0x41a0)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4ba0), mulmod(mload(add(transcript, 0x4240)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4bc0), mulmod(mload(add(transcript, 0x42e0)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4be0), mulmod(mload(add(transcript, 0x4380)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4c00), mulmod(mload(add(transcript, 0x4420)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4c20), mulmod(mload(add(transcript, 0x44c0)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4c40), mulmod(mload(add(transcript, 0x4560)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4c60), mulmod(mload(add(transcript, 0x4600)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4c80), mulmod(mload(add(transcript, 0x46a0)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4ca0), mulmod(mload(add(transcript, 0x4740)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4cc0), mulmod(mload(add(transcript, 0x47e0)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4ce0), mulmod(mload(add(transcript, 0x4880)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4d00), mulmod(mload(add(transcript, 0x49a0)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4d20), mulmod(mload(add(transcript, 0x49c0)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4d40), mulmod(mload(add(transcript, 0x49e0)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4d60), mulmod(mload(add(transcript, 0x4a00)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4d80), mulmod(mload(add(transcript, 0x4a20)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4da0), mulmod(mload(add(transcript, 0x4ac0)), mload(add(transcript, 0x3960)), f_q))mstore(add(transcript, 0x4dc0), addmod(mload(add(transcript, 0x3f40)), mload(add(transcript, 0x4b00)), f_q))mstore(add(transcript, 0x4de0), mulmod(1, mload(add(transcript, 0x3020)), f_q))mstore(add(transcript, 0x4e00), mulmod(1, mload(add(transcript, 0xb20)), f_q))mstore(add(transcript, 0x4e20), 0x0000000000000000000000000000000000000000000000000000000000000001) mstore(add(transcript, 0x4e40), 0x0000000000000000000000000000000000000000000000000000000000000002)mstore(add(transcript, 0x4e60), mload(add(transcript, 0x4dc0)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x4e20), 0x60, add(transcript, 0x4e20), 0x40), 1), success)mstore(add(transcript, 0x4e80), mload(add(transcript, 0x4e20))) mstore(add(transcript, 0x4ea0), mload(add(transcript, 0x4e40)))mstore(add(transcript, 0x4ec0), mload(add(transcript, 0x80))) mstore(add(transcript, 0x4ee0), mload(add(transcript, 0xa0)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x4e80), 0x80, add(transcript, 0x4e80), 0x40), 1), success)mstore(add(transcript, 0x4f00), mload(add(transcript, 0xc0))) mstore(add(transcript, 0x4f20), mload(add(transcript, 0xe0)))mstore(add(transcript, 0x4f40), mload(add(transcript, 0x3ac0)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x4f00), 0x60, add(transcript, 0x4f00), 0x40), 1), success)mstore(add(transcript, 0x4f60), mload(add(transcript, 0x4e80))) mstore(add(transcript, 0x4f80), mload(add(transcript, 0x4ea0)))mstore(add(transcript, 0x4fa0), mload(add(transcript, 0x4f00))) mstore(add(transcript, 0x4fc0), mload(add(transcript, 0x4f20)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x4f60), 0x80, add(transcript, 0x4f60), 0x40), 1), success)mstore(add(transcript, 0x4fe0), mload(add(transcript, 0x100))) mstore(add(transcript, 0x5000), mload(add(transcript, 0x120)))mstore(add(transcript, 0x5020), mload(add(transcript, 0x3ce0)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x4fe0), 0x60, add(transcript, 0x4fe0), 0x40), 1), success)mstore(add(transcript, 0x5040), mload(add(transcript, 0x4f60))) mstore(add(transcript, 0x5060), mload(add(transcript, 0x4f80)))mstore(add(transcript, 0x5080), mload(add(transcript, 0x4fe0))) mstore(add(transcript, 0x50a0), mload(add(transcript, 0x5000)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x5040), 0x80, add(transcript, 0x5040), 0x40), 1), success)mstore(add(transcript, 0x50c0), mload(add(transcript, 0x320))) mstore(add(transcript, 0x50e0), mload(add(transcript, 0x340)))mstore(add(transcript, 0x5100), mload(add(transcript, 0x3d00)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x50c0), 0x60, add(transcript, 0x50c0), 0x40), 1), success)mstore(add(transcript, 0x5120), mload(add(transcript, 0x5040))) mstore(add(transcript, 0x5140), mload(add(transcript, 0x5060)))mstore(add(transcript, 0x5160), mload(add(transcript, 0x50c0))) mstore(add(transcript, 0x5180), mload(add(transcript, 0x50e0)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x5120), 0x80, add(transcript, 0x5120), 0x40), 1), success)mstore(add(transcript, 0x51a0), mload(add(transcript, 0x360))) mstore(add(transcript, 0x51c0), mload(add(transcript, 0x380)))mstore(add(transcript, 0x51e0), mload(add(transcript, 0x3d20)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x51a0), 0x60, add(transcript, 0x51a0), 0x40), 1), success)mstore(add(transcript, 0x5200), mload(add(transcript, 0x5120))) mstore(add(transcript, 0x5220), mload(add(transcript, 0x5140)))mstore(add(transcript, 0x5240), mload(add(transcript, 0x51a0))) mstore(add(transcript, 0x5260), mload(add(transcript, 0x51c0)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x5200), 0x80, add(transcript, 0x5200), 0x40), 1), success)mstore(add(transcript, 0x5280), mload(add(transcript, 0x2e0))) mstore(add(transcript, 0x52a0), mload(add(transcript, 0x300)))mstore(add(transcript, 0x52c0), mload(add(transcript, 0x3e20)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x5280), 0x60, add(transcript, 0x5280), 0x40), 1), success)mstore(add(transcript, 0x52e0), mload(add(transcript, 0x5200))) mstore(add(transcript, 0x5300), mload(add(transcript, 0x5220)))mstore(add(transcript, 0x5320), mload(add(transcript, 0x5280))) mstore(add(transcript, 0x5340), mload(add(transcript, 0x52a0)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x52e0), 0x80, add(transcript, 0x52e0), 0x40), 1), success)mstore(add(transcript, 0x5360), mload(add(transcript, 0x1a0))) mstore(add(transcript, 0x5380), mload(add(transcript, 0x1c0)))mstore(add(transcript, 0x53a0), mload(add(transcript, 0x3f20)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x5360), 0x60, add(transcript, 0x5360), 0x40), 1), success)mstore(add(transcript, 0x53c0), mload(add(transcript, 0x52e0))) mstore(add(transcript, 0x53e0), mload(add(transcript, 0x5300)))mstore(add(transcript, 0x5400), mload(add(transcript, 0x5360))) mstore(add(transcript, 0x5420), mload(add(transcript, 0x5380)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x53c0), 0x80, add(transcript, 0x53c0), 0x40), 1), success)mstore(add(transcript, 0x5440), mload(add(transcript, 0x1e0))) mstore(add(transcript, 0x5460), mload(add(transcript, 0x200)))mstore(add(transcript, 0x5480), mload(add(transcript, 0x4b20)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x5440), 0x60, add(transcript, 0x5440), 0x40), 1), success)mstore(add(transcript, 0x54a0), mload(add(transcript, 0x53c0))) mstore(add(transcript, 0x54c0), mload(add(transcript, 0x53e0)))mstore(add(transcript, 0x54e0), mload(add(transcript, 0x5440))) mstore(add(transcript, 0x5500), mload(add(transcript, 0x5460)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x54a0), 0x80, add(transcript, 0x54a0), 0x40), 1), success)mstore(add(transcript, 0x5520), 0x0655d62979dc062dc1e8c15334bf17cf5c7e6352219c0bd0b0cc039598d9a669) mstore(add(transcript, 0x5540), 0x019589d3002f6a0ded46a69053f0c05e7a7ca45339b3d2bae85d00f26ac0f33e)mstore(add(transcript, 0x5560), mload(add(transcript, 0x4b40)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x5520), 0x60, add(transcript, 0x5520), 0x40), 1), success)mstore(add(transcript, 0x5580), mload(add(transcript, 0x54a0))) mstore(add(transcript, 0x55a0), mload(add(transcript, 0x54c0)))mstore(add(transcript, 0x55c0), mload(add(transcript, 0x5520))) mstore(add(transcript, 0x55e0), mload(add(transcript, 0x5540)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x5580), 0x80, add(transcript, 0x5580), 0x40), 1), success)mstore(add(transcript, 0x5600), 0x1eab999592385208b42a12dcc047763ee5cf12052eb4b0d9a7a286e043f3df9f) mstore(add(transcript, 0x5620), 0x18887eb3c646ffd4961226c91bac9661004798b1fc6a39c43f9a6d1d03767194)mstore(add(transcript, 0x5640), mload(add(transcript, 0x4b60)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x5600), 0x60, add(transcript, 0x5600), 0x40), 1), success)mstore(add(transcript, 0x5660), mload(add(transcript, 0x5580))) mstore(add(transcript, 0x5680), mload(add(transcript, 0x55a0)))mstore(add(transcript, 0x56a0), mload(add(transcript, 0x5600))) mstore(add(transcript, 0x56c0), mload(add(transcript, 0x5620)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x5660), 0x80, add(transcript, 0x5660), 0x40), 1), success)mstore(add(transcript, 0x56e0), 0x076806058b02e1b5e99b2f2e8eee613194f8df73481659f5938baacd64e4d7b8) mstore(add(transcript, 0x5700), 0x05ae81644b244dceea5350a84a79cbf0a199bbd6c1fad9887423f8c8048e6039)mstore(add(transcript, 0x5720), mload(add(transcript, 0x4b80)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x56e0), 0x60, add(transcript, 0x56e0), 0x40), 1), success)mstore(add(transcript, 0x5740), mload(add(transcript, 0x5660))) mstore(add(transcript, 0x5760), mload(add(transcript, 0x5680)))mstore(add(transcript, 0x5780), mload(add(transcript, 0x56e0))) mstore(add(transcript, 0x57a0), mload(add(transcript, 0x5700)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x5740), 0x80, add(transcript, 0x5740), 0x40), 1), success)mstore(add(transcript, 0x57c0), 0x0438873fc00231ae527efcf74d9092f5059dfa05275cbe7381e948fe3b7b61d8) mstore(add(transcript, 0x57e0), 0x03c0f314c93403792ba86ec3841b3080f2f7cd092c6bcb632cdbc2122a13cdef)mstore(add(transcript, 0x5800), mload(add(transcript, 0x4ba0)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x57c0), 0x60, add(transcript, 0x57c0), 0x40), 1), success)mstore(add(transcript, 0x5820), mload(add(transcript, 0x5740))) mstore(add(transcript, 0x5840), mload(add(transcript, 0x5760)))mstore(add(transcript, 0x5860), mload(add(transcript, 0x57c0))) mstore(add(transcript, 0x5880), mload(add(transcript, 0x57e0)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x5820), 0x80, add(transcript, 0x5820), 0x40), 1), success)mstore(add(transcript, 0x58a0), 0x2b12b132a6261ad60249147599cae0d5b3547e510deabba65526d130f04f2402) mstore(add(transcript, 0x58c0), 0x13e3c02ce00f6b7e00d5b099eda5f1155956ae83899a2d59cefcb00dad66a7f6)mstore(add(transcript, 0x58e0), mload(add(transcript, 0x4bc0)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x58a0), 0x60, add(transcript, 0x58a0), 0x40), 1), success)mstore(add(transcript, 0x5900), mload(add(transcript, 0x5820))) mstore(add(transcript, 0x5920), mload(add(transcript, 0x5840)))mstore(add(transcript, 0x5940), mload(add(transcript, 0x58a0))) mstore(add(transcript, 0x5960), mload(add(transcript, 0x58c0)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x5900), 0x80, add(transcript, 0x5900), 0x40), 1), success)mstore(add(transcript, 0x5980), 0x0ed83370277e0fd35e8258dd5630ce0ce3491fdf7e166d293745635b0cc4eba5) mstore(add(transcript, 0x59a0), 0x03994e7e77ad58072b78757700ab0b79247f2e462b0cf6a5a18b607414c095db)mstore(add(transcript, 0x59c0), mload(add(transcript, 0x4be0)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x5980), 0x60, add(transcript, 0x5980), 0x40), 1), success)mstore(add(transcript, 0x59e0), mload(add(transcript, 0x5900))) mstore(add(transcript, 0x5a00), mload(add(transcript, 0x5920)))mstore(add(transcript, 0x5a20), mload(add(transcript, 0x5980))) mstore(add(transcript, 0x5a40), mload(add(transcript, 0x59a0)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x59e0), 0x80, add(transcript, 0x59e0), 0x40), 1), success)mstore(add(transcript, 0x5a60), 0x23ba4bc49baab563e9d5bf07da231a4496d35b6bc782dbbd76135fe44c31cbcf) mstore(add(transcript, 0x5a80), 0x28b88097e7edf1b2904f6c25c1e30ca0e38c74a52125b2995c4cf0a750683854)mstore(add(transcript, 0x5aa0), mload(add(transcript, 0x4c00)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x5a60), 0x60, add(transcript, 0x5a60), 0x40), 1), success)mstore(add(transcript, 0x5ac0), mload(add(transcript, 0x59e0))) mstore(add(transcript, 0x5ae0), mload(add(transcript, 0x5a00)))mstore(add(transcript, 0x5b00), mload(add(transcript, 0x5a60))) mstore(add(transcript, 0x5b20), mload(add(transcript, 0x5a80)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x5ac0), 0x80, add(transcript, 0x5ac0), 0x40), 1), success)mstore(add(transcript, 0x5b40), 0x17dcbba0bbe2d24566de620998f62ff54ea5302ada6aeb18028b61b4dc19bbd3) mstore(add(transcript, 0x5b60), 0x0e1f908007a5c2cc934426c26de7206c53fa10c79d63ef52ee91bfb568c72fbd)mstore(add(transcript, 0x5b80), mload(add(transcript, 0x4c20)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x5b40), 0x60, add(transcript, 0x5b40), 0x40), 1), success)mstore(add(transcript, 0x5ba0), mload(add(transcript, 0x5ac0))) mstore(add(transcript, 0x5bc0), mload(add(transcript, 0x5ae0)))mstore(add(transcript, 0x5be0), mload(add(transcript, 0x5b40))) mstore(add(transcript, 0x5c00), mload(add(transcript, 0x5b60)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x5ba0), 0x80, add(transcript, 0x5ba0), 0x40), 1), success)mstore(add(transcript, 0x5c20), 0x2c7823f99cb2adb716becb960914ffa1d6e2f257875fdd03c2bee52ef571d41e) mstore(add(transcript, 0x5c40), 0x09ab83ebc6803e65b2e6831c8706d9a134f6b1cf6f6ec5c2697afee095320ee1)mstore(add(transcript, 0x5c60), mload(add(transcript, 0x4c40)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x5c20), 0x60, add(transcript, 0x5c20), 0x40), 1), success)mstore(add(transcript, 0x5c80), mload(add(transcript, 0x5ba0))) mstore(add(transcript, 0x5ca0), mload(add(transcript, 0x5bc0)))mstore(add(transcript, 0x5cc0), mload(add(transcript, 0x5c20))) mstore(add(transcript, 0x5ce0), mload(add(transcript, 0x5c40)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x5c80), 0x80, add(transcript, 0x5c80), 0x40), 1), success)mstore(add(transcript, 0x5d00), 0x2dc12c205152bfacc354c838225571172c215e01a64de6a2ca6665c70937ac58) mstore(add(transcript, 0x5d20), 0x0449eb529f0038a2bd2f6c0b6213a70488b69b479d90a953579e4c9d45621b85)mstore(add(transcript, 0x5d40), mload(add(transcript, 0x4c60)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x5d00), 0x60, add(transcript, 0x5d00), 0x40), 1), success)mstore(add(transcript, 0x5d60), mload(add(transcript, 0x5c80))) mstore(add(transcript, 0x5d80), mload(add(transcript, 0x5ca0)))mstore(add(transcript, 0x5da0), mload(add(transcript, 0x5d00))) mstore(add(transcript, 0x5dc0), mload(add(transcript, 0x5d20)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x5d60), 0x80, add(transcript, 0x5d60), 0x40), 1), success)mstore(add(transcript, 0x5de0), 0x09a2ab3913a4770fd50f6ba9ec4ce0b3178b54d7bfca5b42fe7e8e1ce5cf60a9) mstore(add(transcript, 0x5e00), 0x13ec31f94026569c4bb76e2c4ceaa3e6525438ffb4a7a69cde61f6d77b93bad7)mstore(add(transcript, 0x5e20), mload(add(transcript, 0x4c80)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x5de0), 0x60, add(transcript, 0x5de0), 0x40), 1), success)mstore(add(transcript, 0x5e40), mload(add(transcript, 0x5d60))) mstore(add(transcript, 0x5e60), mload(add(transcript, 0x5d80)))mstore(add(transcript, 0x5e80), mload(add(transcript, 0x5de0))) mstore(add(transcript, 0x5ea0), mload(add(transcript, 0x5e00)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x5e40), 0x80, add(transcript, 0x5e40), 0x40), 1), success)mstore(add(transcript, 0x5ec0), 0x0743ea40f14084db2673217283aa053f986896ee7c181f52118442e99c452974) mstore(add(transcript, 0x5ee0), 0x0203e3493a2594ece57d22cc75dd081ac68271ec7c758153cfd2152bfb5c19e3)mstore(add(transcript, 0x5f00), mload(add(transcript, 0x4ca0)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x5ec0), 0x60, add(transcript, 0x5ec0), 0x40), 1), success)mstore(add(transcript, 0x5f20), mload(add(transcript, 0x5e40))) mstore(add(transcript, 0x5f40), mload(add(transcript, 0x5e60)))mstore(add(transcript, 0x5f60), mload(add(transcript, 0x5ec0))) mstore(add(transcript, 0x5f80), mload(add(transcript, 0x5ee0)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x5f20), 0x80, add(transcript, 0x5f20), 0x40), 1), success)mstore(add(transcript, 0x5fa0), 0x02a9a77d8e6f6fd89f33ba56fe45f6f5c907e50ba28cdd4198acfb562eb21103) mstore(add(transcript, 0x5fc0), 0x23abee68d83c2d6632576e5e95ca01a61e5e3e6d9438c2ac6428c8b6edfe2aba)mstore(add(transcript, 0x5fe0), mload(add(transcript, 0x4cc0)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x5fa0), 0x60, add(transcript, 0x5fa0), 0x40), 1), success)mstore(add(transcript, 0x6000), mload(add(transcript, 0x5f20))) mstore(add(transcript, 0x6020), mload(add(transcript, 0x5f40)))mstore(add(transcript, 0x6040), mload(add(transcript, 0x5fa0))) mstore(add(transcript, 0x6060), mload(add(transcript, 0x5fc0)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x6000), 0x80, add(transcript, 0x6000), 0x40), 1), success)mstore(add(transcript, 0x6080), 0x2cf36d36bfacbe1a8d8c626aefa75ac0feb46b725989a8e6fabed074bf9f6af7) mstore(add(transcript, 0x60a0), 0x060fded3ed5ec56d9e0064d73c472245a4c4b6ec371e9808692bf7f259d3b730)mstore(add(transcript, 0x60c0), mload(add(transcript, 0x4ce0)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x6080), 0x60, add(transcript, 0x6080), 0x40), 1), success)mstore(add(transcript, 0x60e0), mload(add(transcript, 0x6000))) mstore(add(transcript, 0x6100), mload(add(transcript, 0x6020)))mstore(add(transcript, 0x6120), mload(add(transcript, 0x6080))) mstore(add(transcript, 0x6140), mload(add(transcript, 0x60a0)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x60e0), 0x80, add(transcript, 0x60e0), 0x40), 1), success)mstore(add(transcript, 0x6160), mload(add(transcript, 0x440))) mstore(add(transcript, 0x6180), mload(add(transcript, 0x460)))mstore(add(transcript, 0x61a0), mload(add(transcript, 0x4d00)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x6160), 0x60, add(transcript, 0x6160), 0x40), 1), success)mstore(add(transcript, 0x61c0), mload(add(transcript, 0x60e0))) mstore(add(transcript, 0x61e0), mload(add(transcript, 0x6100)))mstore(add(transcript, 0x6200), mload(add(transcript, 0x6160))) mstore(add(transcript, 0x6220), mload(add(transcript, 0x6180)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x61c0), 0x80, add(transcript, 0x61c0), 0x40), 1), success)mstore(add(transcript, 0x6240), mload(add(transcript, 0x480))) mstore(add(transcript, 0x6260), mload(add(transcript, 0x4a0)))mstore(add(transcript, 0x6280), mload(add(transcript, 0x4d20)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x6240), 0x60, add(transcript, 0x6240), 0x40), 1), success)mstore(add(transcript, 0x62a0), mload(add(transcript, 0x61c0))) mstore(add(transcript, 0x62c0), mload(add(transcript, 0x61e0)))mstore(add(transcript, 0x62e0), mload(add(transcript, 0x6240))) mstore(add(transcript, 0x6300), mload(add(transcript, 0x6260)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x62a0), 0x80, add(transcript, 0x62a0), 0x40), 1), success)mstore(add(transcript, 0x6320), mload(add(transcript, 0x4c0))) mstore(add(transcript, 0x6340), mload(add(transcript, 0x4e0)))mstore(add(transcript, 0x6360), mload(add(transcript, 0x4d40)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x6320), 0x60, add(transcript, 0x6320), 0x40), 1), success)mstore(add(transcript, 0x6380), mload(add(transcript, 0x62a0))) mstore(add(transcript, 0x63a0), mload(add(transcript, 0x62c0)))mstore(add(transcript, 0x63c0), mload(add(transcript, 0x6320))) mstore(add(transcript, 0x63e0), mload(add(transcript, 0x6340)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x6380), 0x80, add(transcript, 0x6380), 0x40), 1), success)mstore(add(transcript, 0x6400), mload(add(transcript, 0x500))) mstore(add(transcript, 0x6420), mload(add(transcript, 0x520)))mstore(add(transcript, 0x6440), mload(add(transcript, 0x4d60)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x6400), 0x60, add(transcript, 0x6400), 0x40), 1), success)mstore(add(transcript, 0x6460), mload(add(transcript, 0x6380))) mstore(add(transcript, 0x6480), mload(add(transcript, 0x63a0)))mstore(add(transcript, 0x64a0), mload(add(transcript, 0x6400))) mstore(add(transcript, 0x64c0), mload(add(transcript, 0x6420)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x6460), 0x80, add(transcript, 0x6460), 0x40), 1), success)mstore(add(transcript, 0x64e0), mload(add(transcript, 0x540))) mstore(add(transcript, 0x6500), mload(add(transcript, 0x560)))mstore(add(transcript, 0x6520), mload(add(transcript, 0x4d80)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x64e0), 0x60, add(transcript, 0x64e0), 0x40), 1), success)mstore(add(transcript, 0x6540), mload(add(transcript, 0x6460))) mstore(add(transcript, 0x6560), mload(add(transcript, 0x6480)))mstore(add(transcript, 0x6580), mload(add(transcript, 0x64e0))) mstore(add(transcript, 0x65a0), mload(add(transcript, 0x6500)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x6540), 0x80, add(transcript, 0x6540), 0x40), 1), success)mstore(add(transcript, 0x65c0), mload(add(transcript, 0x3a0))) mstore(add(transcript, 0x65e0), mload(add(transcript, 0x3c0)))mstore(add(transcript, 0x6600), mload(add(transcript, 0x4da0)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x65c0), 0x60, add(transcript, 0x65c0), 0x40), 1), success)mstore(add(transcript, 0x6620), mload(add(transcript, 0x6540))) mstore(add(transcript, 0x6640), mload(add(transcript, 0x6560)))mstore(add(transcript, 0x6660), mload(add(transcript, 0x65c0))) mstore(add(transcript, 0x6680), mload(add(transcript, 0x65e0)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x6620), 0x80, add(transcript, 0x6620), 0x40), 1), success)mstore(add(transcript, 0x66a0), mload(add(transcript, 0xac0))) mstore(add(transcript, 0x66c0), mload(add(transcript, 0xae0)))mstore(add(transcript, 0x66e0), sub(f_q, mload(add(transcript, 0x4de0))))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x66a0), 0x60, add(transcript, 0x66a0), 0x40), 1), success)mstore(add(transcript, 0x6700), mload(add(transcript, 0x6620))) mstore(add(transcript, 0x6720), mload(add(transcript, 0x6640)))mstore(add(transcript, 0x6740), mload(add(transcript, 0x66a0))) mstore(add(transcript, 0x6760), mload(add(transcript, 0x66c0)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x6700), 0x80, add(transcript, 0x6700), 0x40), 1), success)mstore(add(transcript, 0x6780), mload(add(transcript, 0xb60))) mstore(add(transcript, 0x67a0), mload(add(transcript, 0xb80)))mstore(add(transcript, 0x67c0), mload(add(transcript, 0x4e00)))success := and(eq(staticcall(gas(), 0x7, add(transcript, 0x6780), 0x60, add(transcript, 0x6780), 0x40), 1), success)mstore(add(transcript, 0x67e0), mload(add(transcript, 0x6700))) mstore(add(transcript, 0x6800), mload(add(transcript, 0x6720)))mstore(add(transcript, 0x6820), mload(add(transcript, 0x6780))) mstore(add(transcript, 0x6840), mload(add(transcript, 0x67a0)))success := and(eq(staticcall(gas(), 0x6, add(transcript, 0x67e0), 0x80, add(transcript, 0x67e0), 0x40), 1), success)mstore(add(transcript, 0x6860), mload(add(transcript, 0x67e0))) mstore(add(transcript, 0x6880), mload(add(transcript, 0x6800)))mstore(add(transcript, 0x68a0), 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) mstore(add(transcript, 0x68c0), 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) mstore(add(transcript, 0x68e0), 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) mstore(add(transcript, 0x6900), 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa)mstore(add(transcript, 0x6920), mload(add(transcript, 0xb60))) mstore(add(transcript, 0x6940), mload(add(transcript, 0xb80)))mstore(add(transcript, 0x6960), 0x26186a2d65ee4d2f9c9a5b91f86597d35f192cd120caf7e935d8443d1938e23d) mstore(add(transcript, 0x6980), 0x30441fd1b5d3370482c42152a8899027716989a6996c2535bc9f7fee8aaef79e) mstore(add(transcript, 0x69a0), 0x16f363f103c80d7bbc8ad3c6867e0822bbc6000be91a4689755c7df40221c145) mstore(add(transcript, 0x69c0), 0x2b1cbb3e521edf5a622d82762a44a5e63f1e50b332d71154a4a7958d6011deff)success := and(eq(staticcall(gas(), 0x8, add(transcript, 0x6860), 0x180, add(transcript, 0x6860), 0x20), 1), success)success := and(eq(mload(add(transcript, 0x6860)), 1), success)} return success; } } diff --git a/contracts/src/SolvencyVerifier.yul b/contracts/src/SolvencyVerifier.yul deleted file mode 100644 index d72d7d0e..00000000 --- a/contracts/src/SolvencyVerifier.yul +++ /dev/null @@ -1,1418 +0,0 @@ - - object "plonk_verifier" { - code { - function allocate(size) -> ptr { - ptr := mload(0x40) - if eq(ptr, 0) { ptr := 0x60 } - mstore(0x40, add(ptr, size)) - } - let size := datasize("Runtime") - let offset := allocate(size) - datacopy(offset, dataoffset("Runtime"), size) - return(offset, size) - } - object "Runtime" { - code { - let success:bool := true - let f_p := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 - let f_q := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 - function validate_ec_point(x, y) -> valid:bool { - { - let x_lt_p:bool := lt(x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - let y_lt_p:bool := lt(y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - valid := and(x_lt_p, y_lt_p) - } - { - let y_square := mulmod(y, y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - let x_square := mulmod(x, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - let x_cube := mulmod(x_square, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - let x_cube_plus_3 := addmod(x_cube, 3, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - let is_affine:bool := eq(x_cube_plus_3, y_square) - valid := and(valid, is_affine) - } - } - mstore(0x20, mod(calldataload(0x0), f_q)) -mstore(0x40, mod(calldataload(0x20), f_q)) -mstore(0x60, mod(calldataload(0x40), f_q)) -mstore(0x0, 308492134225063399814226381520525808113815168934209933683689315739401114858) - - { - let x := calldataload(0x60) - mstore(0x80, x) - let y := calldataload(0x80) - mstore(0xa0, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0xa0) - mstore(0xc0, x) - let y := calldataload(0xc0) - mstore(0xe0, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0xe0) - mstore(0x100, x) - let y := calldataload(0x100) - mstore(0x120, y) - success := and(validate_ec_point(x, y), success) - } -mstore(0x140, keccak256(0x0, 320)) -{ - let hash := mload(0x140) - mstore(0x160, mod(hash, f_q)) - mstore(0x180, hash) - } - - { - let x := calldataload(0x120) - mstore(0x1a0, x) - let y := calldataload(0x140) - mstore(0x1c0, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0x160) - mstore(0x1e0, x) - let y := calldataload(0x180) - mstore(0x200, y) - success := and(validate_ec_point(x, y), success) - } -mstore(0x220, keccak256(0x180, 160)) -{ - let hash := mload(0x220) - mstore(0x240, mod(hash, f_q)) - mstore(0x260, hash) - } -mstore8(640, 1) -mstore(0x280, keccak256(0x260, 33)) -{ - let hash := mload(0x280) - mstore(0x2a0, mod(hash, f_q)) - mstore(0x2c0, hash) - } - - { - let x := calldataload(0x1a0) - mstore(0x2e0, x) - let y := calldataload(0x1c0) - mstore(0x300, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0x1e0) - mstore(0x320, x) - let y := calldataload(0x200) - mstore(0x340, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0x220) - mstore(0x360, x) - let y := calldataload(0x240) - mstore(0x380, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0x260) - mstore(0x3a0, x) - let y := calldataload(0x280) - mstore(0x3c0, y) - success := and(validate_ec_point(x, y), success) - } -mstore(0x3e0, keccak256(0x2c0, 288)) -{ - let hash := mload(0x3e0) - mstore(0x400, mod(hash, f_q)) - mstore(0x420, hash) - } - - { - let x := calldataload(0x2a0) - mstore(0x440, x) - let y := calldataload(0x2c0) - mstore(0x460, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0x2e0) - mstore(0x480, x) - let y := calldataload(0x300) - mstore(0x4a0, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0x320) - mstore(0x4c0, x) - let y := calldataload(0x340) - mstore(0x4e0, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0x360) - mstore(0x500, x) - let y := calldataload(0x380) - mstore(0x520, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0x3a0) - mstore(0x540, x) - let y := calldataload(0x3c0) - mstore(0x560, y) - success := and(validate_ec_point(x, y), success) - } -mstore(0x580, keccak256(0x420, 352)) -{ - let hash := mload(0x580) - mstore(0x5a0, mod(hash, f_q)) - mstore(0x5c0, hash) - } -mstore(0x5e0, mod(calldataload(0x3e0), f_q)) -mstore(0x600, mod(calldataload(0x400), f_q)) -mstore(0x620, mod(calldataload(0x420), f_q)) -mstore(0x640, mod(calldataload(0x440), f_q)) -mstore(0x660, mod(calldataload(0x460), f_q)) -mstore(0x680, mod(calldataload(0x480), f_q)) -mstore(0x6a0, mod(calldataload(0x4a0), f_q)) -mstore(0x6c0, mod(calldataload(0x4c0), f_q)) -mstore(0x6e0, mod(calldataload(0x4e0), f_q)) -mstore(0x700, mod(calldataload(0x500), f_q)) -mstore(0x720, mod(calldataload(0x520), f_q)) -mstore(0x740, mod(calldataload(0x540), f_q)) -mstore(0x760, mod(calldataload(0x560), f_q)) -mstore(0x780, mod(calldataload(0x580), f_q)) -mstore(0x7a0, mod(calldataload(0x5a0), f_q)) -mstore(0x7c0, mod(calldataload(0x5c0), f_q)) -mstore(0x7e0, mod(calldataload(0x5e0), f_q)) -mstore(0x800, mod(calldataload(0x600), f_q)) -mstore(0x820, mod(calldataload(0x620), f_q)) -mstore(0x840, mod(calldataload(0x640), f_q)) -mstore(0x860, mod(calldataload(0x660), f_q)) -mstore(0x880, mod(calldataload(0x680), f_q)) -mstore(0x8a0, mod(calldataload(0x6a0), f_q)) -mstore(0x8c0, mod(calldataload(0x6c0), f_q)) -mstore(0x8e0, mod(calldataload(0x6e0), f_q)) -mstore(0x900, mod(calldataload(0x700), f_q)) -mstore(0x920, mod(calldataload(0x720), f_q)) -mstore(0x940, mod(calldataload(0x740), f_q)) -mstore(0x960, mod(calldataload(0x760), f_q)) -mstore(0x980, mod(calldataload(0x780), f_q)) -mstore(0x9a0, mod(calldataload(0x7a0), f_q)) -mstore(0x9c0, mod(calldataload(0x7c0), f_q)) -mstore(0x9e0, mod(calldataload(0x7e0), f_q)) -mstore(0xa00, keccak256(0x5c0, 1088)) -{ - let hash := mload(0xa00) - mstore(0xa20, mod(hash, f_q)) - mstore(0xa40, hash) - } -mstore8(2656, 1) -mstore(0xa60, keccak256(0xa40, 33)) -{ - let hash := mload(0xa60) - mstore(0xa80, mod(hash, f_q)) - mstore(0xaa0, hash) - } - - { - let x := calldataload(0x800) - mstore(0xac0, x) - let y := calldataload(0x820) - mstore(0xae0, y) - success := and(validate_ec_point(x, y), success) - } -mstore(0xb00, keccak256(0xaa0, 96)) -{ - let hash := mload(0xb00) - mstore(0xb20, mod(hash, f_q)) - mstore(0xb40, hash) - } - - { - let x := calldataload(0x840) - mstore(0xb60, x) - let y := calldataload(0x860) - mstore(0xb80, y) - success := and(validate_ec_point(x, y), success) - } -mstore(0xba0, mulmod(mload(0x5a0), mload(0x5a0), f_q)) -mstore(0xbc0, mulmod(mload(0xba0), mload(0xba0), f_q)) -mstore(0xbe0, mulmod(mload(0xbc0), mload(0xbc0), f_q)) -mstore(0xc00, mulmod(mload(0xbe0), mload(0xbe0), f_q)) -mstore(0xc20, mulmod(mload(0xc00), mload(0xc00), f_q)) -mstore(0xc40, mulmod(mload(0xc20), mload(0xc20), f_q)) -mstore(0xc60, mulmod(mload(0xc40), mload(0xc40), f_q)) -mstore(0xc80, mulmod(mload(0xc60), mload(0xc60), f_q)) -mstore(0xca0, mulmod(mload(0xc80), mload(0xc80), f_q)) -mstore(0xcc0, mulmod(mload(0xca0), mload(0xca0), f_q)) -mstore(0xce0, addmod(mload(0xcc0), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) -mstore(0xd00, mulmod(mload(0xce0), 21866867634659744680037180739646672280844703888306253060159436409049855557633, f_q)) -mstore(0xd20, mulmod(mload(0xd00), 9936069627611189518829255670237324269287146421271524553312532036927871056678, f_q)) -mstore(0xd40, addmod(mload(0x5a0), 11952173244228085703417150075019950819261217979144509790385672149647937438939, f_q)) -mstore(0xd60, mulmod(mload(0xd00), 1680739780407307830605919050682431078078760076686599579086116998224280619988, f_q)) -mstore(0xd80, addmod(mload(0x5a0), 20207503091431967391640486694574844010469604323729434764612087188351527875629, f_q)) -mstore(0xda0, mulmod(mload(0xd00), 14158528901797138466244491986759313854666262535363044392173788062030301470987, f_q)) -mstore(0xdc0, addmod(mload(0x5a0), 7729713970042136756001913758497961233882101865052989951524416124545507024630, f_q)) -mstore(0xde0, mulmod(mload(0xd00), 15699029810934084314820646074566828280617789951162923449200398535581206172418, f_q)) -mstore(0xe00, addmod(mload(0x5a0), 6189213060905190907425759670690446807930574449253110894497805650994602323199, f_q)) -mstore(0xe20, mulmod(mload(0xd00), 4260969412351770314333984243767775737437927068151180798236715529158398853173, f_q)) -mstore(0xe40, addmod(mload(0x5a0), 17627273459487504907912421501489499351110437332264853545461488657417409642444, f_q)) -mstore(0xe60, mulmod(mload(0xd00), 4925592601992654644734291590386747644864797672605745962807370354577123815907, f_q)) -mstore(0xe80, addmod(mload(0x5a0), 16962650269846620577512114154870527443683566727810288380890833831998684679710, f_q)) -mstore(0xea0, mulmod(mload(0xd00), 1, f_q)) -mstore(0xec0, addmod(mload(0x5a0), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) -mstore(0xee0, mulmod(mload(0xd00), 19380560087801265747114831706136320509424814679569278834391540198888293317501, f_q)) -mstore(0xf00, addmod(mload(0x5a0), 2507682784038009475131574039120954579123549720846755509306663987687515178116, f_q)) -mstore(0xf20, mulmod(mload(0xd00), 6252951856119339508807713076978770803512896272623217303779254502899773638908, f_q)) -mstore(0xf40, addmod(mload(0x5a0), 15635291015719935713438692668278504285035468127792817039918949683676034856709, f_q)) -{ - let prod := mload(0xd40) - - prod := mulmod(mload(0xd80), prod, f_q) - mstore(0xf60, prod) - - prod := mulmod(mload(0xdc0), prod, f_q) - mstore(0xf80, prod) - - prod := mulmod(mload(0xe00), prod, f_q) - mstore(0xfa0, prod) - - prod := mulmod(mload(0xe40), prod, f_q) - mstore(0xfc0, prod) - - prod := mulmod(mload(0xe80), prod, f_q) - mstore(0xfe0, prod) - - prod := mulmod(mload(0xec0), prod, f_q) - mstore(0x1000, prod) - - prod := mulmod(mload(0xf00), prod, f_q) - mstore(0x1020, prod) - - prod := mulmod(mload(0xf40), prod, f_q) - mstore(0x1040, prod) - - prod := mulmod(mload(0xce0), prod, f_q) - mstore(0x1060, prod) - - } -mstore(0x10a0, 32) -mstore(0x10c0, 32) -mstore(0x10e0, 32) -mstore(0x1100, mload(0x1060)) -mstore(0x1120, 21888242871839275222246405745257275088548364400416034343698204186575808495615) -mstore(0x1140, 21888242871839275222246405745257275088548364400416034343698204186575808495617) -success := and(eq(staticcall(gas(), 0x5, 0x10a0, 0xc0, 0x1080, 0x20), 1), success) -{ - - let inv := mload(0x1080) - let v - - v := mload(0xce0) - mstore(3296, mulmod(mload(0x1040), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0xf40) - mstore(3904, mulmod(mload(0x1020), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0xf00) - mstore(3840, mulmod(mload(0x1000), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0xec0) - mstore(3776, mulmod(mload(0xfe0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0xe80) - mstore(3712, mulmod(mload(0xfc0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0xe40) - mstore(3648, mulmod(mload(0xfa0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0xe00) - mstore(3584, mulmod(mload(0xf80), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0xdc0) - mstore(3520, mulmod(mload(0xf60), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0xd80) - mstore(3456, mulmod(mload(0xd40), inv, f_q)) - inv := mulmod(v, inv, f_q) - mstore(0xd40, inv) - - } -mstore(0x1160, mulmod(mload(0xd20), mload(0xd40), f_q)) -mstore(0x1180, mulmod(mload(0xd60), mload(0xd80), f_q)) -mstore(0x11a0, mulmod(mload(0xda0), mload(0xdc0), f_q)) -mstore(0x11c0, mulmod(mload(0xde0), mload(0xe00), f_q)) -mstore(0x11e0, mulmod(mload(0xe20), mload(0xe40), f_q)) -mstore(0x1200, mulmod(mload(0xe60), mload(0xe80), f_q)) -mstore(0x1220, mulmod(mload(0xea0), mload(0xec0), f_q)) -mstore(0x1240, mulmod(mload(0xee0), mload(0xf00), f_q)) -mstore(0x1260, mulmod(mload(0xf20), mload(0xf40), f_q)) -{ - let result := mulmod(mload(0x1220), mload(0x20), f_q) -result := addmod(mulmod(mload(0x1240), mload(0x40), f_q), result, f_q) -result := addmod(mulmod(mload(0x1260), mload(0x60), f_q), result, f_q) -mstore(4736, result) - } -mstore(0x12a0, addmod(mload(0x5e0), mload(0x720), f_q)) -mstore(0x12c0, mulmod(mload(0x12a0), mload(0x12a0), f_q)) -mstore(0x12e0, mulmod(mload(0x12c0), mload(0x12c0), f_q)) -mstore(0x1300, mulmod(mload(0x12a0), mload(0x12e0), f_q)) -mstore(0x1320, mulmod(mload(0x1300), 2910766817845651019878574839501801340070030115151021261302834310722729507541, f_q)) -mstore(0x1340, addmod(mload(0x600), mload(0x740), f_q)) -mstore(0x1360, mulmod(mload(0x1340), mload(0x1340), f_q)) -mstore(0x1380, mulmod(mload(0x1360), mload(0x1360), f_q)) -mstore(0x13a0, mulmod(mload(0x1340), mload(0x1380), f_q)) -mstore(0x13c0, mulmod(mload(0x13a0), 19727366863391167538122140361473584127147630672623100827934084310230022599144, f_q)) -mstore(0x13e0, addmod(mload(0x1320), mload(0x13c0), f_q)) -mstore(0x1400, addmod(mload(0x13e0), sub(f_q, mload(0x620)), f_q)) -mstore(0x1420, mulmod(mload(0x1400), mload(0x7a0), f_q)) -mstore(0x1440, mulmod(mload(0x400), mload(0x1420), f_q)) -mstore(0x1460, mulmod(mload(0x1300), 5776684794125549462448597414050232243778680302179439492664047328281728356345, f_q)) -mstore(0x1480, mulmod(mload(0x13a0), 8348174920934122550483593999453880006756108121341067172388445916328941978568, f_q)) -mstore(0x14a0, addmod(mload(0x1460), mload(0x1480), f_q)) -mstore(0x14c0, addmod(mload(0x14a0), sub(f_q, mload(0x640)), f_q)) -mstore(0x14e0, mulmod(mload(0x14c0), mload(0x7a0), f_q)) -mstore(0x1500, addmod(mload(0x1440), mload(0x14e0), f_q)) -mstore(0x1520, mulmod(mload(0x400), mload(0x1500), f_q)) -mstore(0x1540, addmod(mload(0x1300), sub(f_q, mload(0x660)), f_q)) -mstore(0x1560, mulmod(mload(0x1540), mload(0x7c0), f_q)) -mstore(0x1580, addmod(mload(0x1520), mload(0x1560), f_q)) -mstore(0x15a0, mulmod(mload(0x400), mload(0x1580), f_q)) -mstore(0x15c0, mulmod(mload(0x660), 2910766817845651019878574839501801340070030115151021261302834310722729507541, f_q)) -mstore(0x15e0, mulmod(mload(0x1340), 19727366863391167538122140361473584127147630672623100827934084310230022599144, f_q)) -mstore(0x1600, addmod(mload(0x15c0), mload(0x15e0), f_q)) -mstore(0x1620, addmod(mload(0x1600), mload(0x6e0), f_q)) -mstore(0x1640, mulmod(mload(0x1620), mload(0x1620), f_q)) -mstore(0x1660, mulmod(mload(0x1640), mload(0x1640), f_q)) -mstore(0x1680, mulmod(mload(0x1620), mload(0x1660), f_q)) -mstore(0x16a0, mulmod(mload(0x620), 8897705321156975119607866206188469715432233408805434913352778521345836531302, f_q)) -mstore(0x16c0, mulmod(mload(0x640), 13897810991298242824030978581179475767377101082166056046492926701399149797630, f_q)) -mstore(0x16e0, addmod(mload(0x16a0), mload(0x16c0), f_q)) -mstore(0x1700, addmod(mload(0x1680), sub(f_q, mload(0x16e0)), f_q)) -mstore(0x1720, mulmod(mload(0x1700), mload(0x7c0), f_q)) -mstore(0x1740, addmod(mload(0x15a0), mload(0x1720), f_q)) -mstore(0x1760, mulmod(mload(0x400), mload(0x1740), f_q)) -mstore(0x1780, mulmod(mload(0x660), 5776684794125549462448597414050232243778680302179439492664047328281728356345, f_q)) -mstore(0x17a0, mulmod(mload(0x1340), 8348174920934122550483593999453880006756108121341067172388445916328941978568, f_q)) -mstore(0x17c0, addmod(mload(0x1780), mload(0x17a0), f_q)) -mstore(0x17e0, addmod(mload(0x17c0), mload(0x700), f_q)) -mstore(0x1800, mulmod(mload(0x620), 7127083008168878795310303301757642617203533252990949589494537404444738046722, f_q)) -mstore(0x1820, mulmod(mload(0x640), 10251091711782631878897995303436082826711938358699127319815611151510940403902, f_q)) -mstore(0x1840, addmod(mload(0x1800), mload(0x1820), f_q)) -mstore(0x1860, addmod(mload(0x17e0), sub(f_q, mload(0x1840)), f_q)) -mstore(0x1880, mulmod(mload(0x1860), mload(0x7c0), f_q)) -mstore(0x18a0, addmod(mload(0x1760), mload(0x1880), f_q)) -mstore(0x18c0, mulmod(mload(0x400), mload(0x18a0), f_q)) -mstore(0x18e0, addmod(1, sub(f_q, mload(0x780)), f_q)) -mstore(0x1900, mulmod(mload(0x18e0), mload(0x780), f_q)) -mstore(0x1920, addmod(2, sub(f_q, mload(0x780)), f_q)) -mstore(0x1940, mulmod(mload(0x1920), mload(0x1900), f_q)) -mstore(0x1960, addmod(3, sub(f_q, mload(0x780)), f_q)) -mstore(0x1980, mulmod(mload(0x1960), mload(0x1940), f_q)) -mstore(0x19a0, addmod(mload(0x6a0), mload(0x5e0), f_q)) -mstore(0x19c0, addmod(mload(0x19a0), sub(f_q, mload(0x620)), f_q)) -mstore(0x19e0, mulmod(mload(0x19c0), mload(0x1980), f_q)) -mstore(0x1a00, addmod(mload(0x18c0), mload(0x19e0), f_q)) -mstore(0x1a20, mulmod(mload(0x400), mload(0x1a00), f_q)) -mstore(0x1a40, addmod(mload(0x680), sub(f_q, mload(0x640)), f_q)) -mstore(0x1a60, mulmod(mload(0x1a40), mload(0x1980), f_q)) -mstore(0x1a80, addmod(mload(0x1a20), mload(0x1a60), f_q)) -mstore(0x1aa0, mulmod(mload(0x400), mload(0x1a80), f_q)) -mstore(0x1ac0, mulmod(mload(0x1920), mload(0x780), f_q)) -mstore(0x1ae0, mulmod(mload(0x1960), mload(0x1ac0), f_q)) -mstore(0x1b00, addmod(4, sub(f_q, mload(0x780)), f_q)) -mstore(0x1b20, mulmod(mload(0x1b00), mload(0x1ae0), f_q)) -mstore(0x1b40, mulmod(mload(0x660), mload(0x1b20), f_q)) -mstore(0x1b60, addmod(1, sub(f_q, mload(0x660)), f_q)) -mstore(0x1b80, mulmod(mload(0x1b60), mload(0x1b40), f_q)) -mstore(0x1ba0, addmod(mload(0x1aa0), mload(0x1b80), f_q)) -mstore(0x1bc0, mulmod(mload(0x400), mload(0x1ba0), f_q)) -mstore(0x1be0, mulmod(2, mload(0x660), f_q)) -mstore(0x1c00, addmod(mload(0x600), sub(f_q, mload(0x5e0)), f_q)) -mstore(0x1c20, mulmod(mload(0x1c00), mload(0x1be0), f_q)) -mstore(0x1c40, addmod(mload(0x620), sub(f_q, mload(0x5e0)), f_q)) -mstore(0x1c60, addmod(mload(0x1c20), sub(f_q, mload(0x1c40)), f_q)) -mstore(0x1c80, addmod(mload(0x600), sub(f_q, mload(0x640)), f_q)) -mstore(0x1ca0, addmod(mload(0x1c60), sub(f_q, mload(0x1c80)), f_q)) -mstore(0x1cc0, mulmod(mload(0x1ca0), mload(0x1b20), f_q)) -mstore(0x1ce0, addmod(mload(0x1bc0), mload(0x1cc0), f_q)) -mstore(0x1d00, mulmod(mload(0x400), mload(0x1ce0), f_q)) -mstore(0x1d20, mulmod(mload(0x1960), mload(0x1900), f_q)) -mstore(0x1d40, mulmod(mload(0x1b00), mload(0x1d20), f_q)) -mstore(0x1d60, addmod(mload(0x5e0), mload(0x600), f_q)) -mstore(0x1d80, addmod(mload(0x1d60), sub(f_q, mload(0x660)), f_q)) -mstore(0x1da0, mulmod(mload(0x1d80), mload(0x1d40), f_q)) -mstore(0x1dc0, addmod(mload(0x1d00), mload(0x1da0), f_q)) -mstore(0x1de0, mulmod(mload(0x400), mload(0x1dc0), f_q)) -mstore(0x1e00, addmod(mload(0x1de0), mload(0x1da0), f_q)) -mstore(0x1e20, mulmod(mload(0x400), mload(0x1e00), f_q)) -mstore(0x1e40, mulmod(mload(0x1b00), mload(0x1940), f_q)) -mstore(0x1e60, addmod(mload(0x5e0), sub(f_q, mload(0x600)), f_q)) -mstore(0x1e80, addmod(mload(0x1e60), 5192296858534827628530496329220096, f_q)) -mstore(0x1ea0, addmod(mload(0x1e80), sub(f_q, mload(0x660)), f_q)) -mstore(0x1ec0, mulmod(mload(0x1ea0), mload(0x1e40), f_q)) -mstore(0x1ee0, addmod(mload(0x1e20), mload(0x1ec0), f_q)) -mstore(0x1f00, mulmod(mload(0x400), mload(0x1ee0), f_q)) -mstore(0x1f20, addmod(1, sub(f_q, mload(0x8c0)), f_q)) -mstore(0x1f40, mulmod(mload(0x1f20), mload(0x1220), f_q)) -mstore(0x1f60, addmod(mload(0x1f00), mload(0x1f40), f_q)) -mstore(0x1f80, mulmod(mload(0x400), mload(0x1f60), f_q)) -mstore(0x1fa0, mulmod(mload(0x920), mload(0x920), f_q)) -mstore(0x1fc0, addmod(mload(0x1fa0), sub(f_q, mload(0x920)), f_q)) -mstore(0x1fe0, mulmod(mload(0x1fc0), mload(0x1160), f_q)) -mstore(0x2000, addmod(mload(0x1f80), mload(0x1fe0), f_q)) -mstore(0x2020, mulmod(mload(0x400), mload(0x2000), f_q)) -mstore(0x2040, addmod(mload(0x920), sub(f_q, mload(0x900)), f_q)) -mstore(0x2060, mulmod(mload(0x2040), mload(0x1220), f_q)) -mstore(0x2080, addmod(mload(0x2020), mload(0x2060), f_q)) -mstore(0x20a0, mulmod(mload(0x400), mload(0x2080), f_q)) -mstore(0x20c0, addmod(1, sub(f_q, mload(0x1160)), f_q)) -mstore(0x20e0, addmod(mload(0x1180), mload(0x11a0), f_q)) -mstore(0x2100, addmod(mload(0x20e0), mload(0x11c0), f_q)) -mstore(0x2120, addmod(mload(0x2100), mload(0x11e0), f_q)) -mstore(0x2140, addmod(mload(0x2120), mload(0x1200), f_q)) -mstore(0x2160, addmod(mload(0x20c0), sub(f_q, mload(0x2140)), f_q)) -mstore(0x2180, mulmod(mload(0x800), mload(0x240), f_q)) -mstore(0x21a0, addmod(mload(0x6e0), mload(0x2180), f_q)) -mstore(0x21c0, addmod(mload(0x21a0), mload(0x2a0), f_q)) -mstore(0x21e0, mulmod(mload(0x820), mload(0x240), f_q)) -mstore(0x2200, addmod(mload(0x5e0), mload(0x21e0), f_q)) -mstore(0x2220, addmod(mload(0x2200), mload(0x2a0), f_q)) -mstore(0x2240, mulmod(mload(0x2220), mload(0x21c0), f_q)) -mstore(0x2260, mulmod(mload(0x840), mload(0x240), f_q)) -mstore(0x2280, addmod(mload(0x600), mload(0x2260), f_q)) -mstore(0x22a0, addmod(mload(0x2280), mload(0x2a0), f_q)) -mstore(0x22c0, mulmod(mload(0x22a0), mload(0x2240), f_q)) -mstore(0x22e0, mulmod(mload(0x860), mload(0x240), f_q)) -mstore(0x2300, addmod(mload(0x700), mload(0x22e0), f_q)) -mstore(0x2320, addmod(mload(0x2300), mload(0x2a0), f_q)) -mstore(0x2340, mulmod(mload(0x2320), mload(0x22c0), f_q)) -mstore(0x2360, mulmod(mload(0x2340), mload(0x8e0), f_q)) -mstore(0x2380, mulmod(1, mload(0x240), f_q)) -mstore(0x23a0, mulmod(mload(0x5a0), mload(0x2380), f_q)) -mstore(0x23c0, addmod(mload(0x6e0), mload(0x23a0), f_q)) -mstore(0x23e0, addmod(mload(0x23c0), mload(0x2a0), f_q)) -mstore(0x2400, mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(0x240), f_q)) -mstore(0x2420, mulmod(mload(0x5a0), mload(0x2400), f_q)) -mstore(0x2440, addmod(mload(0x5e0), mload(0x2420), f_q)) -mstore(0x2460, addmod(mload(0x2440), mload(0x2a0), f_q)) -mstore(0x2480, mulmod(mload(0x2460), mload(0x23e0), f_q)) -mstore(0x24a0, mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(0x240), f_q)) -mstore(0x24c0, mulmod(mload(0x5a0), mload(0x24a0), f_q)) -mstore(0x24e0, addmod(mload(0x600), mload(0x24c0), f_q)) -mstore(0x2500, addmod(mload(0x24e0), mload(0x2a0), f_q)) -mstore(0x2520, mulmod(mload(0x2500), mload(0x2480), f_q)) -mstore(0x2540, mulmod(11166246659983828508719468090013646171463329086121580628794302409516816350802, mload(0x240), f_q)) -mstore(0x2560, mulmod(mload(0x5a0), mload(0x2540), f_q)) -mstore(0x2580, addmod(mload(0x700), mload(0x2560), f_q)) -mstore(0x25a0, addmod(mload(0x2580), mload(0x2a0), f_q)) -mstore(0x25c0, mulmod(mload(0x25a0), mload(0x2520), f_q)) -mstore(0x25e0, mulmod(mload(0x25c0), mload(0x8c0), f_q)) -mstore(0x2600, addmod(mload(0x2360), sub(f_q, mload(0x25e0)), f_q)) -mstore(0x2620, mulmod(mload(0x2600), mload(0x2160), f_q)) -mstore(0x2640, addmod(mload(0x20a0), mload(0x2620), f_q)) -mstore(0x2660, mulmod(mload(0x400), mload(0x2640), f_q)) -mstore(0x2680, mulmod(mload(0x880), mload(0x240), f_q)) -mstore(0x26a0, addmod(mload(0x660), mload(0x2680), f_q)) -mstore(0x26c0, addmod(mload(0x26a0), mload(0x2a0), f_q)) -mstore(0x26e0, mulmod(mload(0x8a0), mload(0x240), f_q)) -mstore(0x2700, addmod(mload(0x1280), mload(0x26e0), f_q)) -mstore(0x2720, addmod(mload(0x2700), mload(0x2a0), f_q)) -mstore(0x2740, mulmod(mload(0x2720), mload(0x26c0), f_q)) -mstore(0x2760, mulmod(mload(0x2740), mload(0x940), f_q)) -mstore(0x2780, mulmod(284840088355319032285349970403338060113257071685626700086398481893096618818, mload(0x240), f_q)) -mstore(0x27a0, mulmod(mload(0x5a0), mload(0x2780), f_q)) -mstore(0x27c0, addmod(mload(0x660), mload(0x27a0), f_q)) -mstore(0x27e0, addmod(mload(0x27c0), mload(0x2a0), f_q)) -mstore(0x2800, mulmod(21134065618345176623193549882539580312263652408302468683943992798037078993309, mload(0x240), f_q)) -mstore(0x2820, mulmod(mload(0x5a0), mload(0x2800), f_q)) -mstore(0x2840, addmod(mload(0x1280), mload(0x2820), f_q)) -mstore(0x2860, addmod(mload(0x2840), mload(0x2a0), f_q)) -mstore(0x2880, mulmod(mload(0x2860), mload(0x27e0), f_q)) -mstore(0x28a0, mulmod(mload(0x2880), mload(0x920), f_q)) -mstore(0x28c0, addmod(mload(0x2760), sub(f_q, mload(0x28a0)), f_q)) -mstore(0x28e0, mulmod(mload(0x28c0), mload(0x2160), f_q)) -mstore(0x2900, addmod(mload(0x2660), mload(0x28e0), f_q)) -mstore(0x2920, mulmod(mload(0x400), mload(0x2900), f_q)) -mstore(0x2940, addmod(1, sub(f_q, mload(0x960)), f_q)) -mstore(0x2960, mulmod(mload(0x2940), mload(0x1220), f_q)) -mstore(0x2980, addmod(mload(0x2920), mload(0x2960), f_q)) -mstore(0x29a0, mulmod(mload(0x400), mload(0x2980), f_q)) -mstore(0x29c0, mulmod(mload(0x960), mload(0x960), f_q)) -mstore(0x29e0, addmod(mload(0x29c0), sub(f_q, mload(0x960)), f_q)) -mstore(0x2a00, mulmod(mload(0x29e0), mload(0x1160), f_q)) -mstore(0x2a20, addmod(mload(0x29a0), mload(0x2a00), f_q)) -mstore(0x2a40, mulmod(mload(0x400), mload(0x2a20), f_q)) -mstore(0x2a60, addmod(mload(0x9a0), mload(0x240), f_q)) -mstore(0x2a80, mulmod(mload(0x2a60), mload(0x980), f_q)) -mstore(0x2aa0, addmod(mload(0x9e0), mload(0x2a0), f_q)) -mstore(0x2ac0, mulmod(mload(0x2aa0), mload(0x2a80), f_q)) -mstore(0x2ae0, mulmod(256, mload(0x6c0), f_q)) -mstore(0x2b00, addmod(mload(0x660), sub(f_q, mload(0x2ae0)), f_q)) -mstore(0x2b20, mulmod(mload(0x2b00), mload(0x760), f_q)) -mstore(0x2b40, addmod(mload(0x2b20), mload(0x240), f_q)) -mstore(0x2b60, mulmod(mload(0x2b40), mload(0x960), f_q)) -mstore(0x2b80, addmod(mload(0x720), mload(0x2a0), f_q)) -mstore(0x2ba0, mulmod(mload(0x2b80), mload(0x2b60), f_q)) -mstore(0x2bc0, addmod(mload(0x2ac0), sub(f_q, mload(0x2ba0)), f_q)) -mstore(0x2be0, mulmod(mload(0x2bc0), mload(0x2160), f_q)) -mstore(0x2c00, addmod(mload(0x2a40), mload(0x2be0), f_q)) -mstore(0x2c20, mulmod(mload(0x400), mload(0x2c00), f_q)) -mstore(0x2c40, addmod(mload(0x9a0), sub(f_q, mload(0x9e0)), f_q)) -mstore(0x2c60, mulmod(mload(0x2c40), mload(0x1220), f_q)) -mstore(0x2c80, addmod(mload(0x2c20), mload(0x2c60), f_q)) -mstore(0x2ca0, mulmod(mload(0x400), mload(0x2c80), f_q)) -mstore(0x2cc0, mulmod(mload(0x2c40), mload(0x2160), f_q)) -mstore(0x2ce0, addmod(mload(0x9a0), sub(f_q, mload(0x9c0)), f_q)) -mstore(0x2d00, mulmod(mload(0x2ce0), mload(0x2cc0), f_q)) -mstore(0x2d20, addmod(mload(0x2ca0), mload(0x2d00), f_q)) -mstore(0x2d40, mulmod(mload(0xcc0), mload(0xcc0), f_q)) -mstore(0x2d60, mulmod(mload(0x2d40), mload(0xcc0), f_q)) -mstore(0x2d80, mulmod(mload(0x2d60), mload(0xcc0), f_q)) -mstore(0x2da0, mulmod(mload(0x2d80), mload(0xcc0), f_q)) -mstore(0x2dc0, mulmod(1, mload(0xcc0), f_q)) -mstore(0x2de0, mulmod(1, mload(0x2d40), f_q)) -mstore(0x2e00, mulmod(1, mload(0x2d60), f_q)) -mstore(0x2e20, mulmod(1, mload(0x2d80), f_q)) -mstore(0x2e40, mulmod(mload(0x2d20), mload(0xce0), f_q)) -mstore(0x2e60, mulmod(mload(0xba0), mload(0x5a0), f_q)) -mstore(0x2e80, mulmod(mload(0x5a0), 1, f_q)) -mstore(0x2ea0, addmod(mload(0xb20), sub(f_q, mload(0x2e80)), f_q)) -mstore(0x2ec0, mulmod(mload(0x5a0), 4925592601992654644734291590386747644864797672605745962807370354577123815907, f_q)) -mstore(0x2ee0, addmod(mload(0xb20), sub(f_q, mload(0x2ec0)), f_q)) -mstore(0x2f00, mulmod(mload(0x5a0), 9936069627611189518829255670237324269287146421271524553312532036927871056678, f_q)) -mstore(0x2f20, addmod(mload(0xb20), sub(f_q, mload(0x2f00)), f_q)) -mstore(0x2f40, mulmod(mload(0x5a0), 19380560087801265747114831706136320509424814679569278834391540198888293317501, f_q)) -mstore(0x2f60, addmod(mload(0xb20), sub(f_q, mload(0x2f40)), f_q)) -{ - let result := mulmod(mload(0xb20), mulmod(mload(0xba0), 19470333053884630052643688193991482022807116448657043890197497819686199857828, f_q), f_q) -result := addmod(mulmod(mload(0x5a0), mulmod(mload(0xba0), 2417909817954645169602717551265793065741247951758990453500706366889608637789, f_q), f_q), result, f_q) -mstore(12160, result) - } -{ - let result := mulmod(mload(0xb20), mulmod(mload(0xba0), 13686227242150003628673578706486473027501243666075718775893288845164412632930, f_q), f_q) -result := addmod(mulmod(mload(0x5a0), mulmod(mload(0xba0), 10079503758141076467065204586507257535549232608832327988764044976944819876346, f_q), f_q), result, f_q) -mstore(12192, result) - } -{ - let result := mulmod(mload(0xb20), mulmod(mload(0xba0), 18715936898160381416714524359517348601997944075114713669820885373469568354766, f_q), f_q) -result := addmod(mulmod(mload(0x5a0), mulmod(mload(0xba0), 15375775075249615866494035504844970190233299190010037655541891534730124992278, f_q), f_q), result, f_q) -mstore(12224, result) - } -mstore(0x2fe0, mulmod(1, mload(0x2ea0), f_q)) -mstore(0x3000, mulmod(mload(0x2fe0), mload(0x2f60), f_q)) -mstore(0x3020, mulmod(mload(0x3000), mload(0x2ee0), f_q)) -{ - let result := mulmod(mload(0xb20), mulmod(mload(0x5a0), 2507682784038009475131574039120954579123549720846755509306663987687515178117, f_q), f_q) -result := addmod(mulmod(mload(0x5a0), mulmod(mload(0x5a0), 19380560087801265747114831706136320509424814679569278834391540198888293317500, f_q), f_q), result, f_q) -mstore(12352, result) - } -{ - let result := mulmod(mload(0xb20), mulmod(mload(0x5a0), 19380560087801265747114831706136320509424814679569278834391540198888293317500, f_q), f_q) -result := addmod(mulmod(mload(0x5a0), mulmod(mload(0x5a0), 13127608231681926238307118629157549705911918406946061530612285695988519678593, f_q), f_q), result, f_q) -mstore(12384, result) - } -{ - let result := mulmod(mload(0xb20), mulmod(mload(0xba0), 16140595808673403009154643164823336476463527776677864878778453135559733237044, f_q), f_q) -result := addmod(mulmod(mload(0x5a0), mulmod(mload(0xba0), 5747647063165872213091762580433938612084836623738169464919751051016075258573, f_q), f_q), result, f_q) -mstore(12416, result) - } -{ - let result := mulmod(mload(0xb20), mulmod(mload(0xba0), 17015964487361230672162623735654618573844832338054897787312333529290879253714, f_q), f_q) -result := addmod(mulmod(mload(0x5a0), mulmod(mload(0xba0), 3176732791729641355588945816447819802711920387939493967460175841862547409845, f_q), f_q), result, f_q) -mstore(12448, result) - } -{ - let result := mulmod(mload(0xb20), mulmod(mload(0xba0), 19187508498431587163140984396833674282302409422288044257471288693049179355069, f_q), f_q) -result := addmod(mulmod(mload(0x5a0), mulmod(mload(0xba0), 17472297497993506786357772047295541913219081564856233764575529621311665103799, f_q), f_q), result, f_q) -mstore(12480, result) - } -mstore(0x30e0, mulmod(mload(0x3000), mload(0x2f20), f_q)) -{ - let result := mulmod(mload(0xb20), mulmod(mload(0x5a0), 16962650269846620577512114154870527443683566727810288380890833831998684679711, f_q), f_q) -result := addmod(mulmod(mload(0x5a0), mulmod(mload(0x5a0), 4925592601992654644734291590386747644864797672605745962807370354577123815906, f_q), f_q), result, f_q) -mstore(12544, result) - } -{ - let result := mulmod(mload(0xb20), mulmod(mload(0x5a0), 4925592601992654644734291590386747644864797672605745962807370354577123815906, f_q), f_q) -result := addmod(mulmod(mload(0x5a0), mulmod(mload(0x5a0), 664623189640884330400307346618971907426870604454565164570654825418724962734, f_q), f_q), result, f_q) -mstore(12576, result) - } -mstore(0x3140, mulmod(mload(0x2fe0), mload(0x2ee0), f_q)) -{ - let result := mulmod(mload(0xb20), 1, f_q) -result := addmod(mulmod(mload(0x5a0), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q), result, f_q) -mstore(12640, result) - } -{ - let prod := mload(0x2f80) - - prod := mulmod(mload(0x2fa0), prod, f_q) - mstore(0x3180, prod) - - prod := mulmod(mload(0x2fc0), prod, f_q) - mstore(0x31a0, prod) - - prod := mulmod(mload(0x3040), prod, f_q) - mstore(0x31c0, prod) - - prod := mulmod(mload(0x3060), prod, f_q) - mstore(0x31e0, prod) - - prod := mulmod(mload(0x3000), prod, f_q) - mstore(0x3200, prod) - - prod := mulmod(mload(0x3080), prod, f_q) - mstore(0x3220, prod) - - prod := mulmod(mload(0x30a0), prod, f_q) - mstore(0x3240, prod) - - prod := mulmod(mload(0x30c0), prod, f_q) - mstore(0x3260, prod) - - prod := mulmod(mload(0x30e0), prod, f_q) - mstore(0x3280, prod) - - prod := mulmod(mload(0x3100), prod, f_q) - mstore(0x32a0, prod) - - prod := mulmod(mload(0x3120), prod, f_q) - mstore(0x32c0, prod) - - prod := mulmod(mload(0x3140), prod, f_q) - mstore(0x32e0, prod) - - prod := mulmod(mload(0x3160), prod, f_q) - mstore(0x3300, prod) - - prod := mulmod(mload(0x2fe0), prod, f_q) - mstore(0x3320, prod) - - } -mstore(0x3360, 32) -mstore(0x3380, 32) -mstore(0x33a0, 32) -mstore(0x33c0, mload(0x3320)) -mstore(0x33e0, 21888242871839275222246405745257275088548364400416034343698204186575808495615) -mstore(0x3400, 21888242871839275222246405745257275088548364400416034343698204186575808495617) -success := and(eq(staticcall(gas(), 0x5, 0x3360, 0xc0, 0x3340, 0x20), 1), success) -{ - - let inv := mload(0x3340) - let v - - v := mload(0x2fe0) - mstore(12256, mulmod(mload(0x3300), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3160) - mstore(12640, mulmod(mload(0x32e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3140) - mstore(12608, mulmod(mload(0x32c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3120) - mstore(12576, mulmod(mload(0x32a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3100) - mstore(12544, mulmod(mload(0x3280), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x30e0) - mstore(12512, mulmod(mload(0x3260), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x30c0) - mstore(12480, mulmod(mload(0x3240), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x30a0) - mstore(12448, mulmod(mload(0x3220), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3080) - mstore(12416, mulmod(mload(0x3200), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3000) - mstore(12288, mulmod(mload(0x31e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3060) - mstore(12384, mulmod(mload(0x31c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3040) - mstore(12352, mulmod(mload(0x31a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2fc0) - mstore(12224, mulmod(mload(0x3180), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2fa0) - mstore(12192, mulmod(mload(0x2f80), inv, f_q)) - inv := mulmod(v, inv, f_q) - mstore(0x2f80, inv) - - } -{ - let result := mload(0x2f80) -result := addmod(mload(0x2fa0), result, f_q) -result := addmod(mload(0x2fc0), result, f_q) -mstore(13344, result) - } -mstore(0x3440, mulmod(mload(0x3020), mload(0x3000), f_q)) -{ - let result := mload(0x3040) -result := addmod(mload(0x3060), result, f_q) -mstore(13408, result) - } -mstore(0x3480, mulmod(mload(0x3020), mload(0x30e0), f_q)) -{ - let result := mload(0x3080) -result := addmod(mload(0x30a0), result, f_q) -result := addmod(mload(0x30c0), result, f_q) -mstore(13472, result) - } -mstore(0x34c0, mulmod(mload(0x3020), mload(0x3140), f_q)) -{ - let result := mload(0x3100) -result := addmod(mload(0x3120), result, f_q) -mstore(13536, result) - } -mstore(0x3500, mulmod(mload(0x3020), mload(0x2fe0), f_q)) -{ - let result := mload(0x3160) -mstore(13600, result) - } -{ - let prod := mload(0x3420) - - prod := mulmod(mload(0x3460), prod, f_q) - mstore(0x3540, prod) - - prod := mulmod(mload(0x34a0), prod, f_q) - mstore(0x3560, prod) - - prod := mulmod(mload(0x34e0), prod, f_q) - mstore(0x3580, prod) - - prod := mulmod(mload(0x3520), prod, f_q) - mstore(0x35a0, prod) - - } -mstore(0x35e0, 32) -mstore(0x3600, 32) -mstore(0x3620, 32) -mstore(0x3640, mload(0x35a0)) -mstore(0x3660, 21888242871839275222246405745257275088548364400416034343698204186575808495615) -mstore(0x3680, 21888242871839275222246405745257275088548364400416034343698204186575808495617) -success := and(eq(staticcall(gas(), 0x5, 0x35e0, 0xc0, 0x35c0, 0x20), 1), success) -{ - - let inv := mload(0x35c0) - let v - - v := mload(0x3520) - mstore(13600, mulmod(mload(0x3580), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x34e0) - mstore(13536, mulmod(mload(0x3560), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x34a0) - mstore(13472, mulmod(mload(0x3540), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3460) - mstore(13408, mulmod(mload(0x3420), inv, f_q)) - inv := mulmod(v, inv, f_q) - mstore(0x3420, inv) - - } -mstore(0x36a0, mulmod(mload(0x3440), mload(0x3460), f_q)) -mstore(0x36c0, mulmod(mload(0x3480), mload(0x34a0), f_q)) -mstore(0x36e0, mulmod(mload(0x34c0), mload(0x34e0), f_q)) -mstore(0x3700, mulmod(mload(0x3500), mload(0x3520), f_q)) -mstore(0x3720, mulmod(mload(0xa20), mload(0xa20), f_q)) -mstore(0x3740, mulmod(mload(0x3720), mload(0xa20), f_q)) -mstore(0x3760, mulmod(mload(0x3740), mload(0xa20), f_q)) -mstore(0x3780, mulmod(mload(0x3760), mload(0xa20), f_q)) -mstore(0x37a0, mulmod(mload(0x3780), mload(0xa20), f_q)) -mstore(0x37c0, mulmod(mload(0x37a0), mload(0xa20), f_q)) -mstore(0x37e0, mulmod(mload(0x37c0), mload(0xa20), f_q)) -mstore(0x3800, mulmod(mload(0x37e0), mload(0xa20), f_q)) -mstore(0x3820, mulmod(mload(0x3800), mload(0xa20), f_q)) -mstore(0x3840, mulmod(mload(0x3820), mload(0xa20), f_q)) -mstore(0x3860, mulmod(mload(0x3840), mload(0xa20), f_q)) -mstore(0x3880, mulmod(mload(0x3860), mload(0xa20), f_q)) -mstore(0x38a0, mulmod(mload(0x3880), mload(0xa20), f_q)) -mstore(0x38c0, mulmod(mload(0x38a0), mload(0xa20), f_q)) -mstore(0x38e0, mulmod(mload(0x38c0), mload(0xa20), f_q)) -mstore(0x3900, mulmod(mload(0x38e0), mload(0xa20), f_q)) -mstore(0x3920, mulmod(mload(0xa80), mload(0xa80), f_q)) -mstore(0x3940, mulmod(mload(0x3920), mload(0xa80), f_q)) -mstore(0x3960, mulmod(mload(0x3940), mload(0xa80), f_q)) -mstore(0x3980, mulmod(mload(0x3960), mload(0xa80), f_q)) -{ - let result := mulmod(mload(0x5e0), mload(0x2f80), f_q) -result := addmod(mulmod(mload(0x620), mload(0x2fa0), f_q), result, f_q) -result := addmod(mulmod(mload(0x6a0), mload(0x2fc0), f_q), result, f_q) -mstore(14752, result) - } -mstore(0x39c0, mulmod(mload(0x39a0), mload(0x3420), f_q)) -mstore(0x39e0, mulmod(sub(f_q, mload(0x39c0)), 1, f_q)) -{ - let result := mulmod(mload(0x600), mload(0x2f80), f_q) -result := addmod(mulmod(mload(0x640), mload(0x2fa0), f_q), result, f_q) -result := addmod(mulmod(mload(0x680), mload(0x2fc0), f_q), result, f_q) -mstore(14848, result) - } -mstore(0x3a20, mulmod(mload(0x3a00), mload(0x3420), f_q)) -mstore(0x3a40, mulmod(sub(f_q, mload(0x3a20)), mload(0xa20), f_q)) -mstore(0x3a60, mulmod(1, mload(0xa20), f_q)) -mstore(0x3a80, addmod(mload(0x39e0), mload(0x3a40), f_q)) -mstore(0x3aa0, mulmod(mload(0x3a80), 1, f_q)) -mstore(0x3ac0, mulmod(mload(0x3a60), 1, f_q)) -mstore(0x3ae0, mulmod(1, mload(0x3440), f_q)) -{ - let result := mulmod(mload(0x660), mload(0x3040), f_q) -result := addmod(mulmod(mload(0x6c0), mload(0x3060), f_q), result, f_q) -mstore(15104, result) - } -mstore(0x3b20, mulmod(mload(0x3b00), mload(0x36a0), f_q)) -mstore(0x3b40, mulmod(sub(f_q, mload(0x3b20)), 1, f_q)) -mstore(0x3b60, mulmod(mload(0x3ae0), 1, f_q)) -{ - let result := mulmod(mload(0x920), mload(0x3040), f_q) -result := addmod(mulmod(mload(0x940), mload(0x3060), f_q), result, f_q) -mstore(15232, result) - } -mstore(0x3ba0, mulmod(mload(0x3b80), mload(0x36a0), f_q)) -mstore(0x3bc0, mulmod(sub(f_q, mload(0x3ba0)), mload(0xa20), f_q)) -mstore(0x3be0, mulmod(mload(0x3ae0), mload(0xa20), f_q)) -mstore(0x3c00, addmod(mload(0x3b40), mload(0x3bc0), f_q)) -{ - let result := mulmod(mload(0x960), mload(0x3040), f_q) -result := addmod(mulmod(mload(0x980), mload(0x3060), f_q), result, f_q) -mstore(15392, result) - } -mstore(0x3c40, mulmod(mload(0x3c20), mload(0x36a0), f_q)) -mstore(0x3c60, mulmod(sub(f_q, mload(0x3c40)), mload(0x3720), f_q)) -mstore(0x3c80, mulmod(mload(0x3ae0), mload(0x3720), f_q)) -mstore(0x3ca0, addmod(mload(0x3c00), mload(0x3c60), f_q)) -mstore(0x3cc0, mulmod(mload(0x3ca0), mload(0xa80), f_q)) -mstore(0x3ce0, mulmod(mload(0x3b60), mload(0xa80), f_q)) -mstore(0x3d00, mulmod(mload(0x3be0), mload(0xa80), f_q)) -mstore(0x3d20, mulmod(mload(0x3c80), mload(0xa80), f_q)) -mstore(0x3d40, addmod(mload(0x3aa0), mload(0x3cc0), f_q)) -mstore(0x3d60, mulmod(1, mload(0x3480), f_q)) -{ - let result := mulmod(mload(0x8c0), mload(0x3080), f_q) -result := addmod(mulmod(mload(0x8e0), mload(0x30a0), f_q), result, f_q) -result := addmod(mulmod(mload(0x900), mload(0x30c0), f_q), result, f_q) -mstore(15744, result) - } -mstore(0x3da0, mulmod(mload(0x3d80), mload(0x36c0), f_q)) -mstore(0x3dc0, mulmod(sub(f_q, mload(0x3da0)), 1, f_q)) -mstore(0x3de0, mulmod(mload(0x3d60), 1, f_q)) -mstore(0x3e00, mulmod(mload(0x3dc0), mload(0x3920), f_q)) -mstore(0x3e20, mulmod(mload(0x3de0), mload(0x3920), f_q)) -mstore(0x3e40, addmod(mload(0x3d40), mload(0x3e00), f_q)) -mstore(0x3e60, mulmod(1, mload(0x34c0), f_q)) -{ - let result := mulmod(mload(0x9a0), mload(0x3100), f_q) -result := addmod(mulmod(mload(0x9c0), mload(0x3120), f_q), result, f_q) -mstore(16000, result) - } -mstore(0x3ea0, mulmod(mload(0x3e80), mload(0x36e0), f_q)) -mstore(0x3ec0, mulmod(sub(f_q, mload(0x3ea0)), 1, f_q)) -mstore(0x3ee0, mulmod(mload(0x3e60), 1, f_q)) -mstore(0x3f00, mulmod(mload(0x3ec0), mload(0x3940), f_q)) -mstore(0x3f20, mulmod(mload(0x3ee0), mload(0x3940), f_q)) -mstore(0x3f40, addmod(mload(0x3e40), mload(0x3f00), f_q)) -mstore(0x3f60, mulmod(1, mload(0x3500), f_q)) -{ - let result := mulmod(mload(0x9e0), mload(0x3160), f_q) -mstore(16256, result) - } -mstore(0x3fa0, mulmod(mload(0x3f80), mload(0x3700), f_q)) -mstore(0x3fc0, mulmod(sub(f_q, mload(0x3fa0)), 1, f_q)) -mstore(0x3fe0, mulmod(mload(0x3f60), 1, f_q)) -{ - let result := mulmod(mload(0x6e0), mload(0x3160), f_q) -mstore(16384, result) - } -mstore(0x4020, mulmod(mload(0x4000), mload(0x3700), f_q)) -mstore(0x4040, mulmod(sub(f_q, mload(0x4020)), mload(0xa20), f_q)) -mstore(0x4060, mulmod(mload(0x3f60), mload(0xa20), f_q)) -mstore(0x4080, addmod(mload(0x3fc0), mload(0x4040), f_q)) -{ - let result := mulmod(mload(0x700), mload(0x3160), f_q) -mstore(16544, result) - } -mstore(0x40c0, mulmod(mload(0x40a0), mload(0x3700), f_q)) -mstore(0x40e0, mulmod(sub(f_q, mload(0x40c0)), mload(0x3720), f_q)) -mstore(0x4100, mulmod(mload(0x3f60), mload(0x3720), f_q)) -mstore(0x4120, addmod(mload(0x4080), mload(0x40e0), f_q)) -{ - let result := mulmod(mload(0x720), mload(0x3160), f_q) -mstore(16704, result) - } -mstore(0x4160, mulmod(mload(0x4140), mload(0x3700), f_q)) -mstore(0x4180, mulmod(sub(f_q, mload(0x4160)), mload(0x3740), f_q)) -mstore(0x41a0, mulmod(mload(0x3f60), mload(0x3740), f_q)) -mstore(0x41c0, addmod(mload(0x4120), mload(0x4180), f_q)) -{ - let result := mulmod(mload(0x740), mload(0x3160), f_q) -mstore(16864, result) - } -mstore(0x4200, mulmod(mload(0x41e0), mload(0x3700), f_q)) -mstore(0x4220, mulmod(sub(f_q, mload(0x4200)), mload(0x3760), f_q)) -mstore(0x4240, mulmod(mload(0x3f60), mload(0x3760), f_q)) -mstore(0x4260, addmod(mload(0x41c0), mload(0x4220), f_q)) -{ - let result := mulmod(mload(0x760), mload(0x3160), f_q) -mstore(17024, result) - } -mstore(0x42a0, mulmod(mload(0x4280), mload(0x3700), f_q)) -mstore(0x42c0, mulmod(sub(f_q, mload(0x42a0)), mload(0x3780), f_q)) -mstore(0x42e0, mulmod(mload(0x3f60), mload(0x3780), f_q)) -mstore(0x4300, addmod(mload(0x4260), mload(0x42c0), f_q)) -{ - let result := mulmod(mload(0x780), mload(0x3160), f_q) -mstore(17184, result) - } -mstore(0x4340, mulmod(mload(0x4320), mload(0x3700), f_q)) -mstore(0x4360, mulmod(sub(f_q, mload(0x4340)), mload(0x37a0), f_q)) -mstore(0x4380, mulmod(mload(0x3f60), mload(0x37a0), f_q)) -mstore(0x43a0, addmod(mload(0x4300), mload(0x4360), f_q)) -{ - let result := mulmod(mload(0x7a0), mload(0x3160), f_q) -mstore(17344, result) - } -mstore(0x43e0, mulmod(mload(0x43c0), mload(0x3700), f_q)) -mstore(0x4400, mulmod(sub(f_q, mload(0x43e0)), mload(0x37c0), f_q)) -mstore(0x4420, mulmod(mload(0x3f60), mload(0x37c0), f_q)) -mstore(0x4440, addmod(mload(0x43a0), mload(0x4400), f_q)) -{ - let result := mulmod(mload(0x7c0), mload(0x3160), f_q) -mstore(17504, result) - } -mstore(0x4480, mulmod(mload(0x4460), mload(0x3700), f_q)) -mstore(0x44a0, mulmod(sub(f_q, mload(0x4480)), mload(0x37e0), f_q)) -mstore(0x44c0, mulmod(mload(0x3f60), mload(0x37e0), f_q)) -mstore(0x44e0, addmod(mload(0x4440), mload(0x44a0), f_q)) -{ - let result := mulmod(mload(0x800), mload(0x3160), f_q) -mstore(17664, result) - } -mstore(0x4520, mulmod(mload(0x4500), mload(0x3700), f_q)) -mstore(0x4540, mulmod(sub(f_q, mload(0x4520)), mload(0x3800), f_q)) -mstore(0x4560, mulmod(mload(0x3f60), mload(0x3800), f_q)) -mstore(0x4580, addmod(mload(0x44e0), mload(0x4540), f_q)) -{ - let result := mulmod(mload(0x820), mload(0x3160), f_q) -mstore(17824, result) - } -mstore(0x45c0, mulmod(mload(0x45a0), mload(0x3700), f_q)) -mstore(0x45e0, mulmod(sub(f_q, mload(0x45c0)), mload(0x3820), f_q)) -mstore(0x4600, mulmod(mload(0x3f60), mload(0x3820), f_q)) -mstore(0x4620, addmod(mload(0x4580), mload(0x45e0), f_q)) -{ - let result := mulmod(mload(0x840), mload(0x3160), f_q) -mstore(17984, result) - } -mstore(0x4660, mulmod(mload(0x4640), mload(0x3700), f_q)) -mstore(0x4680, mulmod(sub(f_q, mload(0x4660)), mload(0x3840), f_q)) -mstore(0x46a0, mulmod(mload(0x3f60), mload(0x3840), f_q)) -mstore(0x46c0, addmod(mload(0x4620), mload(0x4680), f_q)) -{ - let result := mulmod(mload(0x860), mload(0x3160), f_q) -mstore(18144, result) - } -mstore(0x4700, mulmod(mload(0x46e0), mload(0x3700), f_q)) -mstore(0x4720, mulmod(sub(f_q, mload(0x4700)), mload(0x3860), f_q)) -mstore(0x4740, mulmod(mload(0x3f60), mload(0x3860), f_q)) -mstore(0x4760, addmod(mload(0x46c0), mload(0x4720), f_q)) -{ - let result := mulmod(mload(0x880), mload(0x3160), f_q) -mstore(18304, result) - } -mstore(0x47a0, mulmod(mload(0x4780), mload(0x3700), f_q)) -mstore(0x47c0, mulmod(sub(f_q, mload(0x47a0)), mload(0x3880), f_q)) -mstore(0x47e0, mulmod(mload(0x3f60), mload(0x3880), f_q)) -mstore(0x4800, addmod(mload(0x4760), mload(0x47c0), f_q)) -{ - let result := mulmod(mload(0x8a0), mload(0x3160), f_q) -mstore(18464, result) - } -mstore(0x4840, mulmod(mload(0x4820), mload(0x3700), f_q)) -mstore(0x4860, mulmod(sub(f_q, mload(0x4840)), mload(0x38a0), f_q)) -mstore(0x4880, mulmod(mload(0x3f60), mload(0x38a0), f_q)) -mstore(0x48a0, addmod(mload(0x4800), mload(0x4860), f_q)) -mstore(0x48c0, mulmod(mload(0x2dc0), mload(0x3500), f_q)) -mstore(0x48e0, mulmod(mload(0x2de0), mload(0x3500), f_q)) -mstore(0x4900, mulmod(mload(0x2e00), mload(0x3500), f_q)) -mstore(0x4920, mulmod(mload(0x2e20), mload(0x3500), f_q)) -{ - let result := mulmod(mload(0x2e40), mload(0x3160), f_q) -mstore(18752, result) - } -mstore(0x4960, mulmod(mload(0x4940), mload(0x3700), f_q)) -mstore(0x4980, mulmod(sub(f_q, mload(0x4960)), mload(0x38c0), f_q)) -mstore(0x49a0, mulmod(mload(0x3f60), mload(0x38c0), f_q)) -mstore(0x49c0, mulmod(mload(0x48c0), mload(0x38c0), f_q)) -mstore(0x49e0, mulmod(mload(0x48e0), mload(0x38c0), f_q)) -mstore(0x4a00, mulmod(mload(0x4900), mload(0x38c0), f_q)) -mstore(0x4a20, mulmod(mload(0x4920), mload(0x38c0), f_q)) -mstore(0x4a40, addmod(mload(0x48a0), mload(0x4980), f_q)) -{ - let result := mulmod(mload(0x7e0), mload(0x3160), f_q) -mstore(19040, result) - } -mstore(0x4a80, mulmod(mload(0x4a60), mload(0x3700), f_q)) -mstore(0x4aa0, mulmod(sub(f_q, mload(0x4a80)), mload(0x38e0), f_q)) -mstore(0x4ac0, mulmod(mload(0x3f60), mload(0x38e0), f_q)) -mstore(0x4ae0, addmod(mload(0x4a40), mload(0x4aa0), f_q)) -mstore(0x4b00, mulmod(mload(0x4ae0), mload(0x3960), f_q)) -mstore(0x4b20, mulmod(mload(0x3fe0), mload(0x3960), f_q)) -mstore(0x4b40, mulmod(mload(0x4060), mload(0x3960), f_q)) -mstore(0x4b60, mulmod(mload(0x4100), mload(0x3960), f_q)) -mstore(0x4b80, mulmod(mload(0x41a0), mload(0x3960), f_q)) -mstore(0x4ba0, mulmod(mload(0x4240), mload(0x3960), f_q)) -mstore(0x4bc0, mulmod(mload(0x42e0), mload(0x3960), f_q)) -mstore(0x4be0, mulmod(mload(0x4380), mload(0x3960), f_q)) -mstore(0x4c00, mulmod(mload(0x4420), mload(0x3960), f_q)) -mstore(0x4c20, mulmod(mload(0x44c0), mload(0x3960), f_q)) -mstore(0x4c40, mulmod(mload(0x4560), mload(0x3960), f_q)) -mstore(0x4c60, mulmod(mload(0x4600), mload(0x3960), f_q)) -mstore(0x4c80, mulmod(mload(0x46a0), mload(0x3960), f_q)) -mstore(0x4ca0, mulmod(mload(0x4740), mload(0x3960), f_q)) -mstore(0x4cc0, mulmod(mload(0x47e0), mload(0x3960), f_q)) -mstore(0x4ce0, mulmod(mload(0x4880), mload(0x3960), f_q)) -mstore(0x4d00, mulmod(mload(0x49a0), mload(0x3960), f_q)) -mstore(0x4d20, mulmod(mload(0x49c0), mload(0x3960), f_q)) -mstore(0x4d40, mulmod(mload(0x49e0), mload(0x3960), f_q)) -mstore(0x4d60, mulmod(mload(0x4a00), mload(0x3960), f_q)) -mstore(0x4d80, mulmod(mload(0x4a20), mload(0x3960), f_q)) -mstore(0x4da0, mulmod(mload(0x4ac0), mload(0x3960), f_q)) -mstore(0x4dc0, addmod(mload(0x3f40), mload(0x4b00), f_q)) -mstore(0x4de0, mulmod(1, mload(0x3020), f_q)) -mstore(0x4e00, mulmod(1, mload(0xb20), f_q)) -mstore(0x4e20, 0x0000000000000000000000000000000000000000000000000000000000000001) - mstore(0x4e40, 0x0000000000000000000000000000000000000000000000000000000000000002) -mstore(0x4e60, mload(0x4dc0)) -success := and(eq(staticcall(gas(), 0x7, 0x4e20, 0x60, 0x4e20, 0x40), 1), success) -mstore(0x4e80, mload(0x4e20)) - mstore(0x4ea0, mload(0x4e40)) -mstore(0x4ec0, mload(0x80)) - mstore(0x4ee0, mload(0xa0)) -success := and(eq(staticcall(gas(), 0x6, 0x4e80, 0x80, 0x4e80, 0x40), 1), success) -mstore(0x4f00, mload(0xc0)) - mstore(0x4f20, mload(0xe0)) -mstore(0x4f40, mload(0x3ac0)) -success := and(eq(staticcall(gas(), 0x7, 0x4f00, 0x60, 0x4f00, 0x40), 1), success) -mstore(0x4f60, mload(0x4e80)) - mstore(0x4f80, mload(0x4ea0)) -mstore(0x4fa0, mload(0x4f00)) - mstore(0x4fc0, mload(0x4f20)) -success := and(eq(staticcall(gas(), 0x6, 0x4f60, 0x80, 0x4f60, 0x40), 1), success) -mstore(0x4fe0, mload(0x100)) - mstore(0x5000, mload(0x120)) -mstore(0x5020, mload(0x3ce0)) -success := and(eq(staticcall(gas(), 0x7, 0x4fe0, 0x60, 0x4fe0, 0x40), 1), success) -mstore(0x5040, mload(0x4f60)) - mstore(0x5060, mload(0x4f80)) -mstore(0x5080, mload(0x4fe0)) - mstore(0x50a0, mload(0x5000)) -success := and(eq(staticcall(gas(), 0x6, 0x5040, 0x80, 0x5040, 0x40), 1), success) -mstore(0x50c0, mload(0x320)) - mstore(0x50e0, mload(0x340)) -mstore(0x5100, mload(0x3d00)) -success := and(eq(staticcall(gas(), 0x7, 0x50c0, 0x60, 0x50c0, 0x40), 1), success) -mstore(0x5120, mload(0x5040)) - mstore(0x5140, mload(0x5060)) -mstore(0x5160, mload(0x50c0)) - mstore(0x5180, mload(0x50e0)) -success := and(eq(staticcall(gas(), 0x6, 0x5120, 0x80, 0x5120, 0x40), 1), success) -mstore(0x51a0, mload(0x360)) - mstore(0x51c0, mload(0x380)) -mstore(0x51e0, mload(0x3d20)) -success := and(eq(staticcall(gas(), 0x7, 0x51a0, 0x60, 0x51a0, 0x40), 1), success) -mstore(0x5200, mload(0x5120)) - mstore(0x5220, mload(0x5140)) -mstore(0x5240, mload(0x51a0)) - mstore(0x5260, mload(0x51c0)) -success := and(eq(staticcall(gas(), 0x6, 0x5200, 0x80, 0x5200, 0x40), 1), success) -mstore(0x5280, mload(0x2e0)) - mstore(0x52a0, mload(0x300)) -mstore(0x52c0, mload(0x3e20)) -success := and(eq(staticcall(gas(), 0x7, 0x5280, 0x60, 0x5280, 0x40), 1), success) -mstore(0x52e0, mload(0x5200)) - mstore(0x5300, mload(0x5220)) -mstore(0x5320, mload(0x5280)) - mstore(0x5340, mload(0x52a0)) -success := and(eq(staticcall(gas(), 0x6, 0x52e0, 0x80, 0x52e0, 0x40), 1), success) -mstore(0x5360, mload(0x1a0)) - mstore(0x5380, mload(0x1c0)) -mstore(0x53a0, mload(0x3f20)) -success := and(eq(staticcall(gas(), 0x7, 0x5360, 0x60, 0x5360, 0x40), 1), success) -mstore(0x53c0, mload(0x52e0)) - mstore(0x53e0, mload(0x5300)) -mstore(0x5400, mload(0x5360)) - mstore(0x5420, mload(0x5380)) -success := and(eq(staticcall(gas(), 0x6, 0x53c0, 0x80, 0x53c0, 0x40), 1), success) -mstore(0x5440, mload(0x1e0)) - mstore(0x5460, mload(0x200)) -mstore(0x5480, mload(0x4b20)) -success := and(eq(staticcall(gas(), 0x7, 0x5440, 0x60, 0x5440, 0x40), 1), success) -mstore(0x54a0, mload(0x53c0)) - mstore(0x54c0, mload(0x53e0)) -mstore(0x54e0, mload(0x5440)) - mstore(0x5500, mload(0x5460)) -success := and(eq(staticcall(gas(), 0x6, 0x54a0, 0x80, 0x54a0, 0x40), 1), success) -mstore(0x5520, 0x0655d62979dc062dc1e8c15334bf17cf5c7e6352219c0bd0b0cc039598d9a669) - mstore(0x5540, 0x019589d3002f6a0ded46a69053f0c05e7a7ca45339b3d2bae85d00f26ac0f33e) -mstore(0x5560, mload(0x4b40)) -success := and(eq(staticcall(gas(), 0x7, 0x5520, 0x60, 0x5520, 0x40), 1), success) -mstore(0x5580, mload(0x54a0)) - mstore(0x55a0, mload(0x54c0)) -mstore(0x55c0, mload(0x5520)) - mstore(0x55e0, mload(0x5540)) -success := and(eq(staticcall(gas(), 0x6, 0x5580, 0x80, 0x5580, 0x40), 1), success) -mstore(0x5600, 0x1eab999592385208b42a12dcc047763ee5cf12052eb4b0d9a7a286e043f3df9f) - mstore(0x5620, 0x18887eb3c646ffd4961226c91bac9661004798b1fc6a39c43f9a6d1d03767194) -mstore(0x5640, mload(0x4b60)) -success := and(eq(staticcall(gas(), 0x7, 0x5600, 0x60, 0x5600, 0x40), 1), success) -mstore(0x5660, mload(0x5580)) - mstore(0x5680, mload(0x55a0)) -mstore(0x56a0, mload(0x5600)) - mstore(0x56c0, mload(0x5620)) -success := and(eq(staticcall(gas(), 0x6, 0x5660, 0x80, 0x5660, 0x40), 1), success) -mstore(0x56e0, 0x076806058b02e1b5e99b2f2e8eee613194f8df73481659f5938baacd64e4d7b8) - mstore(0x5700, 0x05ae81644b244dceea5350a84a79cbf0a199bbd6c1fad9887423f8c8048e6039) -mstore(0x5720, mload(0x4b80)) -success := and(eq(staticcall(gas(), 0x7, 0x56e0, 0x60, 0x56e0, 0x40), 1), success) -mstore(0x5740, mload(0x5660)) - mstore(0x5760, mload(0x5680)) -mstore(0x5780, mload(0x56e0)) - mstore(0x57a0, mload(0x5700)) -success := and(eq(staticcall(gas(), 0x6, 0x5740, 0x80, 0x5740, 0x40), 1), success) -mstore(0x57c0, 0x0438873fc00231ae527efcf74d9092f5059dfa05275cbe7381e948fe3b7b61d8) - mstore(0x57e0, 0x03c0f314c93403792ba86ec3841b3080f2f7cd092c6bcb632cdbc2122a13cdef) -mstore(0x5800, mload(0x4ba0)) -success := and(eq(staticcall(gas(), 0x7, 0x57c0, 0x60, 0x57c0, 0x40), 1), success) -mstore(0x5820, mload(0x5740)) - mstore(0x5840, mload(0x5760)) -mstore(0x5860, mload(0x57c0)) - mstore(0x5880, mload(0x57e0)) -success := and(eq(staticcall(gas(), 0x6, 0x5820, 0x80, 0x5820, 0x40), 1), success) -mstore(0x58a0, 0x2b12b132a6261ad60249147599cae0d5b3547e510deabba65526d130f04f2402) - mstore(0x58c0, 0x13e3c02ce00f6b7e00d5b099eda5f1155956ae83899a2d59cefcb00dad66a7f6) -mstore(0x58e0, mload(0x4bc0)) -success := and(eq(staticcall(gas(), 0x7, 0x58a0, 0x60, 0x58a0, 0x40), 1), success) -mstore(0x5900, mload(0x5820)) - mstore(0x5920, mload(0x5840)) -mstore(0x5940, mload(0x58a0)) - mstore(0x5960, mload(0x58c0)) -success := and(eq(staticcall(gas(), 0x6, 0x5900, 0x80, 0x5900, 0x40), 1), success) -mstore(0x5980, 0x0ed83370277e0fd35e8258dd5630ce0ce3491fdf7e166d293745635b0cc4eba5) - mstore(0x59a0, 0x03994e7e77ad58072b78757700ab0b79247f2e462b0cf6a5a18b607414c095db) -mstore(0x59c0, mload(0x4be0)) -success := and(eq(staticcall(gas(), 0x7, 0x5980, 0x60, 0x5980, 0x40), 1), success) -mstore(0x59e0, mload(0x5900)) - mstore(0x5a00, mload(0x5920)) -mstore(0x5a20, mload(0x5980)) - mstore(0x5a40, mload(0x59a0)) -success := and(eq(staticcall(gas(), 0x6, 0x59e0, 0x80, 0x59e0, 0x40), 1), success) -mstore(0x5a60, 0x23ba4bc49baab563e9d5bf07da231a4496d35b6bc782dbbd76135fe44c31cbcf) - mstore(0x5a80, 0x28b88097e7edf1b2904f6c25c1e30ca0e38c74a52125b2995c4cf0a750683854) -mstore(0x5aa0, mload(0x4c00)) -success := and(eq(staticcall(gas(), 0x7, 0x5a60, 0x60, 0x5a60, 0x40), 1), success) -mstore(0x5ac0, mload(0x59e0)) - mstore(0x5ae0, mload(0x5a00)) -mstore(0x5b00, mload(0x5a60)) - mstore(0x5b20, mload(0x5a80)) -success := and(eq(staticcall(gas(), 0x6, 0x5ac0, 0x80, 0x5ac0, 0x40), 1), success) -mstore(0x5b40, 0x17dcbba0bbe2d24566de620998f62ff54ea5302ada6aeb18028b61b4dc19bbd3) - mstore(0x5b60, 0x0e1f908007a5c2cc934426c26de7206c53fa10c79d63ef52ee91bfb568c72fbd) -mstore(0x5b80, mload(0x4c20)) -success := and(eq(staticcall(gas(), 0x7, 0x5b40, 0x60, 0x5b40, 0x40), 1), success) -mstore(0x5ba0, mload(0x5ac0)) - mstore(0x5bc0, mload(0x5ae0)) -mstore(0x5be0, mload(0x5b40)) - mstore(0x5c00, mload(0x5b60)) -success := and(eq(staticcall(gas(), 0x6, 0x5ba0, 0x80, 0x5ba0, 0x40), 1), success) -mstore(0x5c20, 0x2c7823f99cb2adb716becb960914ffa1d6e2f257875fdd03c2bee52ef571d41e) - mstore(0x5c40, 0x09ab83ebc6803e65b2e6831c8706d9a134f6b1cf6f6ec5c2697afee095320ee1) -mstore(0x5c60, mload(0x4c40)) -success := and(eq(staticcall(gas(), 0x7, 0x5c20, 0x60, 0x5c20, 0x40), 1), success) -mstore(0x5c80, mload(0x5ba0)) - mstore(0x5ca0, mload(0x5bc0)) -mstore(0x5cc0, mload(0x5c20)) - mstore(0x5ce0, mload(0x5c40)) -success := and(eq(staticcall(gas(), 0x6, 0x5c80, 0x80, 0x5c80, 0x40), 1), success) -mstore(0x5d00, 0x2dc12c205152bfacc354c838225571172c215e01a64de6a2ca6665c70937ac58) - mstore(0x5d20, 0x0449eb529f0038a2bd2f6c0b6213a70488b69b479d90a953579e4c9d45621b85) -mstore(0x5d40, mload(0x4c60)) -success := and(eq(staticcall(gas(), 0x7, 0x5d00, 0x60, 0x5d00, 0x40), 1), success) -mstore(0x5d60, mload(0x5c80)) - mstore(0x5d80, mload(0x5ca0)) -mstore(0x5da0, mload(0x5d00)) - mstore(0x5dc0, mload(0x5d20)) -success := and(eq(staticcall(gas(), 0x6, 0x5d60, 0x80, 0x5d60, 0x40), 1), success) -mstore(0x5de0, 0x09a2ab3913a4770fd50f6ba9ec4ce0b3178b54d7bfca5b42fe7e8e1ce5cf60a9) - mstore(0x5e00, 0x13ec31f94026569c4bb76e2c4ceaa3e6525438ffb4a7a69cde61f6d77b93bad7) -mstore(0x5e20, mload(0x4c80)) -success := and(eq(staticcall(gas(), 0x7, 0x5de0, 0x60, 0x5de0, 0x40), 1), success) -mstore(0x5e40, mload(0x5d60)) - mstore(0x5e60, mload(0x5d80)) -mstore(0x5e80, mload(0x5de0)) - mstore(0x5ea0, mload(0x5e00)) -success := and(eq(staticcall(gas(), 0x6, 0x5e40, 0x80, 0x5e40, 0x40), 1), success) -mstore(0x5ec0, 0x0743ea40f14084db2673217283aa053f986896ee7c181f52118442e99c452974) - mstore(0x5ee0, 0x0203e3493a2594ece57d22cc75dd081ac68271ec7c758153cfd2152bfb5c19e3) -mstore(0x5f00, mload(0x4ca0)) -success := and(eq(staticcall(gas(), 0x7, 0x5ec0, 0x60, 0x5ec0, 0x40), 1), success) -mstore(0x5f20, mload(0x5e40)) - mstore(0x5f40, mload(0x5e60)) -mstore(0x5f60, mload(0x5ec0)) - mstore(0x5f80, mload(0x5ee0)) -success := and(eq(staticcall(gas(), 0x6, 0x5f20, 0x80, 0x5f20, 0x40), 1), success) -mstore(0x5fa0, 0x02a9a77d8e6f6fd89f33ba56fe45f6f5c907e50ba28cdd4198acfb562eb21103) - mstore(0x5fc0, 0x23abee68d83c2d6632576e5e95ca01a61e5e3e6d9438c2ac6428c8b6edfe2aba) -mstore(0x5fe0, mload(0x4cc0)) -success := and(eq(staticcall(gas(), 0x7, 0x5fa0, 0x60, 0x5fa0, 0x40), 1), success) -mstore(0x6000, mload(0x5f20)) - mstore(0x6020, mload(0x5f40)) -mstore(0x6040, mload(0x5fa0)) - mstore(0x6060, mload(0x5fc0)) -success := and(eq(staticcall(gas(), 0x6, 0x6000, 0x80, 0x6000, 0x40), 1), success) -mstore(0x6080, 0x2cf36d36bfacbe1a8d8c626aefa75ac0feb46b725989a8e6fabed074bf9f6af7) - mstore(0x60a0, 0x060fded3ed5ec56d9e0064d73c472245a4c4b6ec371e9808692bf7f259d3b730) -mstore(0x60c0, mload(0x4ce0)) -success := and(eq(staticcall(gas(), 0x7, 0x6080, 0x60, 0x6080, 0x40), 1), success) -mstore(0x60e0, mload(0x6000)) - mstore(0x6100, mload(0x6020)) -mstore(0x6120, mload(0x6080)) - mstore(0x6140, mload(0x60a0)) -success := and(eq(staticcall(gas(), 0x6, 0x60e0, 0x80, 0x60e0, 0x40), 1), success) -mstore(0x6160, mload(0x440)) - mstore(0x6180, mload(0x460)) -mstore(0x61a0, mload(0x4d00)) -success := and(eq(staticcall(gas(), 0x7, 0x6160, 0x60, 0x6160, 0x40), 1), success) -mstore(0x61c0, mload(0x60e0)) - mstore(0x61e0, mload(0x6100)) -mstore(0x6200, mload(0x6160)) - mstore(0x6220, mload(0x6180)) -success := and(eq(staticcall(gas(), 0x6, 0x61c0, 0x80, 0x61c0, 0x40), 1), success) -mstore(0x6240, mload(0x480)) - mstore(0x6260, mload(0x4a0)) -mstore(0x6280, mload(0x4d20)) -success := and(eq(staticcall(gas(), 0x7, 0x6240, 0x60, 0x6240, 0x40), 1), success) -mstore(0x62a0, mload(0x61c0)) - mstore(0x62c0, mload(0x61e0)) -mstore(0x62e0, mload(0x6240)) - mstore(0x6300, mload(0x6260)) -success := and(eq(staticcall(gas(), 0x6, 0x62a0, 0x80, 0x62a0, 0x40), 1), success) -mstore(0x6320, mload(0x4c0)) - mstore(0x6340, mload(0x4e0)) -mstore(0x6360, mload(0x4d40)) -success := and(eq(staticcall(gas(), 0x7, 0x6320, 0x60, 0x6320, 0x40), 1), success) -mstore(0x6380, mload(0x62a0)) - mstore(0x63a0, mload(0x62c0)) -mstore(0x63c0, mload(0x6320)) - mstore(0x63e0, mload(0x6340)) -success := and(eq(staticcall(gas(), 0x6, 0x6380, 0x80, 0x6380, 0x40), 1), success) -mstore(0x6400, mload(0x500)) - mstore(0x6420, mload(0x520)) -mstore(0x6440, mload(0x4d60)) -success := and(eq(staticcall(gas(), 0x7, 0x6400, 0x60, 0x6400, 0x40), 1), success) -mstore(0x6460, mload(0x6380)) - mstore(0x6480, mload(0x63a0)) -mstore(0x64a0, mload(0x6400)) - mstore(0x64c0, mload(0x6420)) -success := and(eq(staticcall(gas(), 0x6, 0x6460, 0x80, 0x6460, 0x40), 1), success) -mstore(0x64e0, mload(0x540)) - mstore(0x6500, mload(0x560)) -mstore(0x6520, mload(0x4d80)) -success := and(eq(staticcall(gas(), 0x7, 0x64e0, 0x60, 0x64e0, 0x40), 1), success) -mstore(0x6540, mload(0x6460)) - mstore(0x6560, mload(0x6480)) -mstore(0x6580, mload(0x64e0)) - mstore(0x65a0, mload(0x6500)) -success := and(eq(staticcall(gas(), 0x6, 0x6540, 0x80, 0x6540, 0x40), 1), success) -mstore(0x65c0, mload(0x3a0)) - mstore(0x65e0, mload(0x3c0)) -mstore(0x6600, mload(0x4da0)) -success := and(eq(staticcall(gas(), 0x7, 0x65c0, 0x60, 0x65c0, 0x40), 1), success) -mstore(0x6620, mload(0x6540)) - mstore(0x6640, mload(0x6560)) -mstore(0x6660, mload(0x65c0)) - mstore(0x6680, mload(0x65e0)) -success := and(eq(staticcall(gas(), 0x6, 0x6620, 0x80, 0x6620, 0x40), 1), success) -mstore(0x66a0, mload(0xac0)) - mstore(0x66c0, mload(0xae0)) -mstore(0x66e0, sub(f_q, mload(0x4de0))) -success := and(eq(staticcall(gas(), 0x7, 0x66a0, 0x60, 0x66a0, 0x40), 1), success) -mstore(0x6700, mload(0x6620)) - mstore(0x6720, mload(0x6640)) -mstore(0x6740, mload(0x66a0)) - mstore(0x6760, mload(0x66c0)) -success := and(eq(staticcall(gas(), 0x6, 0x6700, 0x80, 0x6700, 0x40), 1), success) -mstore(0x6780, mload(0xb60)) - mstore(0x67a0, mload(0xb80)) -mstore(0x67c0, mload(0x4e00)) -success := and(eq(staticcall(gas(), 0x7, 0x6780, 0x60, 0x6780, 0x40), 1), success) -mstore(0x67e0, mload(0x6700)) - mstore(0x6800, mload(0x6720)) -mstore(0x6820, mload(0x6780)) - mstore(0x6840, mload(0x67a0)) -success := and(eq(staticcall(gas(), 0x6, 0x67e0, 0x80, 0x67e0, 0x40), 1), success) -mstore(0x6860, mload(0x67e0)) - mstore(0x6880, mload(0x6800)) -mstore(0x68a0, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) - mstore(0x68c0, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) - mstore(0x68e0, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) - mstore(0x6900, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) -mstore(0x6920, mload(0xb60)) - mstore(0x6940, mload(0xb80)) -mstore(0x6960, 0x26186a2d65ee4d2f9c9a5b91f86597d35f192cd120caf7e935d8443d1938e23d) - mstore(0x6980, 0x30441fd1b5d3370482c42152a8899027716989a6996c2535bc9f7fee8aaef79e) - mstore(0x69a0, 0x16f363f103c80d7bbc8ad3c6867e0822bbc6000be91a4689755c7df40221c145) - mstore(0x69c0, 0x2b1cbb3e521edf5a622d82762a44a5e63f1e50b332d71154a4a7958d6011deff) -success := and(eq(staticcall(gas(), 0x8, 0x6860, 0x180, 0x6860, 0x20), 1), success) -success := and(eq(mload(0x6860), 1), success) - - if not(success) { revert(0, 0) } - return(0, 0) - - } - } - } diff --git a/contracts/src/Summa.sol b/contracts/src/Summa.sol index 2134c4f0..cff887d3 100644 --- a/contracts/src/Summa.sol +++ b/contracts/src/Summa.sol @@ -4,9 +4,7 @@ pragma solidity ^0.8.18; // Uncomment this line to use console.log //import "hardhat/console.sol"; -import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./interfaces/IVerifier.sol"; @@ -29,43 +27,66 @@ contract Summa is Ownable { * @dev Struct representing an asset owned by the CEX * @param assetName The name of the asset * @param chain The name of the chain name where the asset lives (e.g., ETH, BTC) - * @param amount The total amount of the asset that the CEX holds on a given chain */ struct Asset { string assetName; string chain; - uint256 amount; } - //Verifier contracts - IVerifier private immutable solvencyVerifier; + /** + * @dev Struct representing a commitment submitted by the CEX. + * @param mstRoot Merkle sum tree root of the CEX's liabilities + * @param rootSums The total sums of the assets included in the tree + * @param assetChains The chains where the CEX holds the assets included into the tree + * @param assetNames The names of the assets included into the tree + */ + struct Commitment { + uint256 mstRoot; + uint256[] rootSums; + string[] assetNames; + string[] assetChains; + } + + // User inclusion proof verifier IVerifier private immutable inclusionVerifier; - //All address ownership proofs submitted by the CEX + // List of all address ownership proofs submitted by the CEX AddressOwnershipProof[] public addressOwnershipProofs; - //Convenience mapping to check if an address has already been verified - mapping(bytes32 => uint256) public ownershipProofByAddress; + function getAddressOwnershipProof( + bytes32 addressHash + ) public view returns (AddressOwnershipProof memory) { + require( + _ownershipProofByAddress[addressHash] > 0, + "Address not verified" + ); + // -1 comes from the fact that 0 is reserved to distinguish the case when the proof has not yet been submitted + return + addressOwnershipProofs[_ownershipProofByAddress[addressHash] - 1]; + } + + // Convenience mapping to check if an address has already been verified + mapping(bytes32 => uint256) private _ownershipProofByAddress; - // MST roots corresponding to successfully verified solvency proofs by timestamp - mapping(uint256 => uint256) public mstRoots; + // Solvency commitments by timestamp submitted by the CEX + mapping(uint256 => Commitment) public commitments; event AddressOwnershipProofSubmitted( AddressOwnershipProof[] addressOwnershipProofs ); - event SolvencyProofSubmitted( + event LiabilitiesCommitmentSubmitted( uint256 indexed timestamp, uint256 mstRoot, + uint256[] rootSums, Asset[] assets ); - constructor(IVerifier _solvencyVerifier, IVerifier _inclusionVerifier) { - solvencyVerifier = _solvencyVerifier; + constructor(IVerifier _inclusionVerifier) { inclusionVerifier = _inclusionVerifier; } /** - * @dev Submit an optimistic proof of address ownership for a CEX. The proof is subject to an off-chain verification as it's not feasible to verify the signatures of non-EVM chains in an Ethereum smart contract. + * @dev Submit an optimistic proof of multiple address ownership for a CEX. The proof is subject to an off-chain verification as it's not feasible to verify the signatures of non-EVM chains in an Ethereum smart contract. * @param _addressOwnershipProofs The list of address ownership proofs */ function submitProofOfAddressOwnership( @@ -73,12 +94,14 @@ contract Summa is Ownable { ) public onlyOwner { for (uint i = 0; i < _addressOwnershipProofs.length; i++) { bytes32 addressHash = keccak256( - abi.encode(_addressOwnershipProofs[i].cexAddress) + abi.encodePacked(_addressOwnershipProofs[i].cexAddress) ); - uint256 index = ownershipProofByAddress[addressHash]; - require(index == 0, "Address already verified"); - ownershipProofByAddress[addressHash] = i + 1; + uint256 proofIndex = _ownershipProofByAddress[addressHash]; + require(proofIndex == 0, "Address already verified"); + addressOwnershipProofs.push(_addressOwnershipProofs[i]); + _ownershipProofByAddress[addressHash] = addressOwnershipProofs + .length; require( bytes(_addressOwnershipProofs[i].cexAddress).length != 0 && bytes(_addressOwnershipProofs[i].chain).length != 0 && @@ -94,47 +117,50 @@ contract Summa is Ownable { /** * @dev Submit proof of solvency for a CEX * @param mstRoot Merkle sum tree root of the CEX's liabilities - * @param assets The list of assets owned by the CEX - * @param proof The ZK proof + * @param rootSums The total sums of the assets included into the Merkle sum tree + * @param assets The assets included into the Merkle sum tree * @param timestamp The timestamp at which the CEX took the snapshot of its assets and liabilities */ - function submitProofOfSolvency( + function submitCommitment( uint256 mstRoot, + uint256[] memory rootSums, Asset[] memory assets, - bytes memory proof, uint256 timestamp ) public onlyOwner { + require(mstRoot != 0, "Invalid MST root"); require( - addressOwnershipProofs.length != 0, - "The CEX has not submitted any address ownership proofs" + rootSums.length == assets.length, + "Root asset sums and asset number mismatch" ); - uint256[] memory inputs = new uint256[](assets.length + 1); - inputs[0] = mstRoot; + string[] memory assetNames = new string[](assets.length); + string[] memory assetChains = new string[](assets.length); for (uint i = 0; i < assets.length; i++) { require( bytes(assets[i].chain).length != 0 && bytes(assets[i].assetName).length != 0, "Invalid asset" ); - inputs[i + 1] = assets[i].amount; + require( + rootSums[i] != 0, + "All root sums should be greater than zero" + ); + assetNames[i] = assets[i].assetName; + assetChains[i] = assets[i].chain; } - require(verifySolvencyProof(proof, inputs), "Invalid ZK proof"); - mstRoots[timestamp] = mstRoot; - - emit SolvencyProofSubmitted(timestamp, inputs[0], assets); - } + commitments[timestamp] = Commitment( + mstRoot, + rootSums, + assetNames, + assetChains + ); - /** - * Verify the proof of CEX solvency - * @param proof ZK proof - * @param publicInputs proof inputs - */ - function verifySolvencyProof( - bytes memory proof, - uint256[] memory publicInputs - ) public view returns (bool) { - return solvencyVerifier.verify(publicInputs, proof); + emit LiabilitiesCommitmentSubmitted( + timestamp, + mstRoot, + rootSums, + assets + ); } /** @@ -147,7 +173,10 @@ contract Summa is Ownable { uint256[] memory publicInputs, uint256 timestamp ) public view returns (bool) { - require(mstRoots[timestamp] == publicInputs[1], "Invalid MST root"); + require( + commitments[timestamp].mstRoot == publicInputs[1], + "Invalid MST root" + ); return inclusionVerifier.verify(publicInputs, proof); } } diff --git a/contracts/test/Summa.ts b/contracts/test/Summa.ts index 2ab793f1..d8d6da15 100644 --- a/contracts/test/Summa.ts +++ b/contracts/test/Summa.ts @@ -9,27 +9,21 @@ import * as fs from "fs"; import * as path from "path"; describe("Summa Contract", () => { - function submitProofOfSolvency( + function submitCommitment( summa: Summa, mstRoot: BigNumber, - proof: string, + rootSums: BigNumber[], assets = [ { chain: "ETH", assetName: "ETH", - amount: BigNumber.from(556863), - }, - { - chain: "ETH", - assetName: "USDT", - amount: BigNumber.from(556863), }, ] ): any { - return summa.submitProofOfSolvency( + return summa.submitCommitment( mstRoot, + rootSums, assets, - proof, BigNumber.from(1693559255) ); } @@ -52,18 +46,12 @@ describe("Summa Contract", () => { const [owner, addr1, addr2, addr3]: SignerWithAddress[] = await ethers.getSigners(); - const solvencyVerifier = await ethers.deployContract( - "src/SolvencyVerifier.sol:Verifier" - ); - await solvencyVerifier.deployed(); - const inclusionVerifier = await ethers.deployContract( "src/InclusionVerifier.sol:Verifier" ); await inclusionVerifier.deployed(); const summa = await ethers.deployContract("Summa", [ - solvencyVerifier.address, inclusionVerifier.address, ]); await summa.deployed(); @@ -112,14 +100,14 @@ describe("Summa Contract", () => { ownedAddresses = [ { chain: "ETH", - cexAddress: defaultAbiCoder.encode(["address"], [account1.address]), + cexAddress: account1.address.toString(), signature: "0x089b32327d332c295dc3b8873c205b72153211de6dc1c51235782b091cefb9d06d6df2661b86a7d441cd322f125b84901486b150e684221a7b7636eb8182af551b", message: message, }, { chain: "ETH", - cexAddress: defaultAbiCoder.encode(["address"], [account2.address]), + cexAddress: account2.address.toString(), signature: "0xb17a9e25265d3b88de7bfad81e7accad6e3d5612308ff83cc0fef76a34152b0444309e8fc3dea5139e49b6fc83a8553071a7af3d0cfd3fb8c1aea2a4c171729c1c", message: message, @@ -133,38 +121,44 @@ describe("Summa Contract", () => { .withArgs((ownedAddresses: any) => { return ( ownedAddresses[0].chain == "ETH" && - ownedAddresses[0].cexAddress == - defaultAbiCoder.encode(["address"], [account1.address]) && + ownedAddresses[0].cexAddress == account1.address && ownedAddresses[0].signature == "0x089b32327d332c295dc3b8873c205b72153211de6dc1c51235782b091cefb9d06d6df2661b86a7d441cd322f125b84901486b150e684221a7b7636eb8182af551b" && ownedAddresses[0].message == message && ownedAddresses[1].chain == "ETH" && - ownedAddresses[1].cexAddress == - defaultAbiCoder.encode(["address"], [account2.address]) && + ownedAddresses[1].cexAddress == account2.address && ownedAddresses[1].signature == "0xb17a9e25265d3b88de7bfad81e7accad6e3d5612308ff83cc0fef76a34152b0444309e8fc3dea5139e49b6fc83a8553071a7af3d0cfd3fb8c1aea2a4c171729c1c" && ownedAddresses[1].message == message ); }); - let proofOfAddressOwnership0 = await summa.addressOwnershipProofs(0); - expect(proofOfAddressOwnership0.chain).to.be.equal("ETH"); - expect(proofOfAddressOwnership0.cexAddress).to.be.equal( - defaultAbiCoder.encode(["address"], [account1.address]) + const addr1Hash = ethers.utils.solidityKeccak256( + ["string"], + [account1.address] ); - expect(proofOfAddressOwnership0.signature).to.be.equal( - "0x089b32327d332c295dc3b8873c205b72153211de6dc1c51235782b091cefb9d06d6df2661b86a7d441cd322f125b84901486b150e684221a7b7636eb8182af551b" + let proofOfAddressOwnership1 = await summa.getAddressOwnershipProof( + addr1Hash ); - expect(proofOfAddressOwnership0.message).to.be.equal(message); - let proofOfAddressOwnership1 = await summa.addressOwnershipProofs(1); expect(proofOfAddressOwnership1.chain).to.be.equal("ETH"); - expect(proofOfAddressOwnership1.cexAddress).to.be.equal( - defaultAbiCoder.encode(["address"], [account2.address]) - ); + expect(proofOfAddressOwnership1.cexAddress).to.be.equal(account1.address); expect(proofOfAddressOwnership1.signature).to.be.equal( - "0xb17a9e25265d3b88de7bfad81e7accad6e3d5612308ff83cc0fef76a34152b0444309e8fc3dea5139e49b6fc83a8553071a7af3d0cfd3fb8c1aea2a4c171729c1c" + "0x089b32327d332c295dc3b8873c205b72153211de6dc1c51235782b091cefb9d06d6df2661b86a7d441cd322f125b84901486b150e684221a7b7636eb8182af551b" ); expect(proofOfAddressOwnership1.message).to.be.equal(message); + const addr2Hash = ethers.utils.solidityKeccak256( + ["string"], + [account2.address] + ); + let proofOfAddressOwnership2 = await summa.getAddressOwnershipProof( + addr2Hash + ); + expect(proofOfAddressOwnership2.chain).to.be.equal("ETH"); + expect(proofOfAddressOwnership2.cexAddress).to.be.equal(account2.address); + expect(proofOfAddressOwnership2.signature).to.be.equal( + "0xb17a9e25265d3b88de7bfad81e7accad6e3d5612308ff83cc0fef76a34152b0444309e8fc3dea5139e49b6fc83a8553071a7af3d0cfd3fb8c1aea2a4c171729c1c" + ); + expect(proofOfAddressOwnership2.message).to.be.equal(message); }); it("should revert if the caller is not the owner", async () => { @@ -207,14 +201,24 @@ describe("Summa Contract", () => { summa.submitProofOfAddressOwnership(ownedAddresses) ).to.be.revertedWith("Invalid proof of address ownership"); }); + + it("should revert if requesting proof for unverified address", async () => { + const addr1Hash = ethers.utils.solidityKeccak256( + ["string"], + [account1.address] + ); + await expect( + summa.getAddressOwnershipProof(addr1Hash) + ).to.be.revertedWith("Address not verified"); + }); }); describe("verify proof of solvency", () => { let mstRoot: BigNumber; + let rootSum: BigNumber; let summa: Summa; let account1: SignerWithAddress; let account2: SignerWithAddress; - let proof: string; //let ethAccount3; let ownedAddresses: Summa.AddressOwnershipProofStruct[]; const message = ethers.utils.defaultAbiCoder.encode( @@ -231,143 +235,120 @@ describe("Summa Contract", () => { ownedAddresses = [ { chain: "ETH", - cexAddress: defaultAbiCoder.encode(["address"], [account1.address]), + cexAddress: account1.address.toString(), signature: "0x089b32327d332c295dc3b8873c205b72153211de6dc1c51235782b091cefb9d06d6df2661b86a7d441cd322f125b84901486b150e684221a7b7636eb8182af551b", message: message, }, { chain: "ETH", - cexAddress: defaultAbiCoder.encode(["address"], [account2.address]), + cexAddress: account2.address.toString(), signature: "0xb17a9e25265d3b88de7bfad81e7accad6e3d5612308ff83cc0fef76a34152b0444309e8fc3dea5139e49b6fc83a8553071a7af3d0cfd3fb8c1aea2a4c171729c1c", message: message, }, ]; - const jsonData = fs.readFileSync( - path.resolve( - __dirname, - "../../zk_prover/examples/solvency_proof_solidity_calldata.json" - ), - "utf-8" + mstRoot = BigNumber.from( + "0x2e021d9bf99c5bd7267488b6a7a5cf5f7d00222a41b6a9b971899c44089e0c5" ); - const calldata: any = JSON.parse(jsonData); - - mstRoot = calldata.public_inputs[0]; - proof = calldata.proof; + rootSum = BigNumber.from(10000000); }); it("should verify the proof of solvency for the given public input", async () => { await summa.submitProofOfAddressOwnership(ownedAddresses); - await expect(submitProofOfSolvency(summa, mstRoot, proof)) - .to.emit(summa, "SolvencyProofSubmitted") + await expect(submitCommitment(summa, mstRoot, [rootSum])) + .to.emit(summa, "LiabilitiesCommitmentSubmitted") .withArgs( BigNumber.from(1693559255), mstRoot, - (assets: Summa.AssetStruct[]) => { - return ( - assets[0].chain == "ETH" && - assets[0].assetName == "ETH" && - BigNumber.from(556863).eq(assets[0].amount as BigNumber) && - assets[1].chain == "ETH" && - assets[1].assetName == "USDT" && - BigNumber.from(556863).eq(assets[1].amount as BigNumber) - ); + [rootSum], + (assets: [Summa.AssetStruct]) => { + return assets[0].chain == "ETH" && assets[0].assetName == "ETH"; } ); }); it("should revert if the caller is not the owner", async () => { await expect( - summa.connect(account2).submitProofOfSolvency( + summa.connect(account2).submitCommitment( mstRoot, + [BigNumber.from(1000000000)], [ { chain: "ETH", assetName: "ETH", - amount: BigNumber.from(556863), - }, - { - chain: "ETH", - assetName: "USDT", - amount: BigNumber.from(556863), }, ], - proof, BigNumber.from(1693559255) ) ).to.be.revertedWith("Ownable: caller is not the owner"); }); - it("should not verify the proof of solvency if the CEX hasn't proven the address ownership", async () => { - await expect( - submitProofOfSolvency(summa, mstRoot, proof) - ).to.be.revertedWith( - "The CEX has not submitted any address ownership proofs" - ); - }); - - it("should revert with invalid MST root", async () => { - mstRoot = BigNumber.from(0); + it("should revert with invalid root sum", async () => { + rootSum = BigNumber.from(0); await summa.submitProofOfAddressOwnership(ownedAddresses); await expect( - submitProofOfSolvency(summa, mstRoot, proof) - ).to.be.revertedWith("Invalid ZK proof"); + submitCommitment(summa, mstRoot, [rootSum]) + ).to.be.revertedWith("All root sums should be greater than zero"); }); it("should revert with invalid assets", async () => { await summa.submitProofOfAddressOwnership(ownedAddresses); await expect( - submitProofOfSolvency(summa, mstRoot, proof, [ - { - chain: "", - assetName: "ETH", - amount: BigNumber.from(556863), - }, - ]) + submitCommitment( + summa, + mstRoot, + [rootSum], + [ + { + chain: "", + assetName: "ETH", + }, + ] + ) ).to.be.revertedWith("Invalid asset"); await expect( - submitProofOfSolvency(summa, mstRoot, proof, [ - { - chain: "ETH", - assetName: "", - amount: BigNumber.from(556863), - }, - ]) + submitCommitment( + summa, + mstRoot, + [rootSum], + [ + { + chain: "ETH", + assetName: "", + }, + ] + ) ).to.be.revertedWith("Invalid asset"); }); - it("should revert with invalid proof", async () => { - await summa.submitProofOfAddressOwnership(ownedAddresses); - - proof = proof.replace("1", "2"); - + it("should not submit invalid root", async () => { await expect( - submitProofOfSolvency(summa, mstRoot, proof) - ).to.be.revertedWith("Invalid ZK proof"); - - proof = "0x000000"; + submitCommitment(summa, BigNumber.from(0), [rootSum]) + ).to.be.revertedWith("Invalid MST root"); + }); + it("should revert if asset and sum count don't match", async () => { await expect( - submitProofOfSolvency(summa, mstRoot, proof) - ).to.be.revertedWithoutReason(); + submitCommitment(summa, mstRoot, [rootSum, rootSum]) + ).to.be.revertedWith("Root asset sums and asset number mismatch"); }); }); describe("verify proof of inclusion", () => { let mstRoot: BigNumber; + let rootSum: BigNumber; let leafHash: BigNumber; let summa: Summa; let account1: SignerWithAddress; let account2: SignerWithAddress; let inclusionProof: string; - let solvencyProof: string; let ownedAddresses: Summa.AddressOwnershipProofStruct[]; const message = ethers.utils.defaultAbiCoder.encode( ["string"], @@ -397,18 +378,6 @@ describe("Summa Contract", () => { }, ]; - const solvencyJson = fs.readFileSync( - path.resolve( - __dirname, - "../../zk_prover/examples/solvency_proof_solidity_calldata.json" - ), - "utf-8" - ); - const solvencyCalldata: any = JSON.parse(solvencyJson); - - mstRoot = solvencyCalldata.public_inputs[0]; - solvencyProof = solvencyCalldata.proof; - const inclusionJson = fs.readFileSync( path.resolve( __dirname, @@ -421,11 +390,12 @@ describe("Summa Contract", () => { leafHash = inclusionCalldata.public_inputs[0]; mstRoot = inclusionCalldata.public_inputs[1]; inclusionProof = inclusionCalldata.proof; + rootSum = BigNumber.from(10000000); }); it("should verify the proof of inclusion for the given public input", async () => { await summa.submitProofOfAddressOwnership(ownedAddresses); - await submitProofOfSolvency(summa, mstRoot, solvencyProof); + await submitCommitment(summa, mstRoot, [rootSum]); expect( await verifyInclusionProof(summa, inclusionProof, leafHash, mstRoot) ).to.be.equal(true); @@ -433,7 +403,7 @@ describe("Summa Contract", () => { it("should not verify with invalid MST root", async () => { await summa.submitProofOfAddressOwnership(ownedAddresses); - await submitProofOfSolvency(summa, mstRoot, solvencyProof); + await submitCommitment(summa, mstRoot, [rootSum]); mstRoot = BigNumber.from(0); await expect( verifyInclusionProof(summa, inclusionProof, leafHash, mstRoot) @@ -451,7 +421,7 @@ describe("Summa Contract", () => { leafHash = BigNumber.from(0); await summa.submitProofOfAddressOwnership(ownedAddresses); - await submitProofOfSolvency(summa, mstRoot, solvencyProof); + await submitCommitment(summa, mstRoot, [rootSum]); expect( await verifyInclusionProof(summa, inclusionProof, leafHash, mstRoot) ).to.be.equal(false); @@ -461,7 +431,7 @@ describe("Summa Contract", () => { inclusionProof = inclusionProof.replace("1", "2"); await summa.submitProofOfAddressOwnership(ownedAddresses); - await submitProofOfSolvency(summa, mstRoot, solvencyProof); + await submitCommitment(summa, mstRoot, [rootSum]); expect( await verifyInclusionProof(summa, inclusionProof, leafHash, mstRoot) ).to.be.equal(false); diff --git a/zk_prover/README.md b/zk_prover/README.md index 704b5866..af77f651 100644 --- a/zk_prover/README.md +++ b/zk_prover/README.md @@ -38,7 +38,7 @@ The script will generate a new `SolvencyVerifier.sol` and `SolvencyVerifier.yul` Note that the generic parameters of the circuits `N_ASSETS` and `N_BYTES` are set to `2` and `14`. This means that the circuit is tuned to verify the proof of solvency for an exchange with 2 assets and a balances in a range of 14 bytes. These parameters can be changed in the script. -Furthermore, the verifier are generated based on an unsafe setup. For a production ready verifier, the setup should be generated by providing a `ptau` file generated after a trusted setup ceremony to `generate_setup_artifacts` function. +Furthermore, the verifier is generated based on a specified `ptau` file, `hermez-raw-11`, for the generic parameters (`N_ASSETS`, `N_BYTES`), using the `generate_setup_artifacts` function. If you try to use different generic parameters, you may have to choose a different `ptau` file for that. On top of that the script will also generate a `solvency_proof_solidity_calldata.json` file that contains some testing calldata to be used within `contracts` and `backend` to test the verifier. Again, in the example, the proof is generated based on the `src/merkle_sum_tree/csv/entry_16.csv` file. If you want to generate a proof for a different file, you can change the path in the script. diff --git a/zk_prover/examples/gen_solvency_verifier.rs b/zk_prover/examples/gen_solvency_verifier.rs index 5bfc9430..2680fdd8 100644 --- a/zk_prover/examples/gen_solvency_verifier.rs +++ b/zk_prover/examples/gen_solvency_verifier.rs @@ -26,7 +26,9 @@ fn main() { let circuit = SolvencyCircuit::::init_empty(); // generate a universal trusted setup for testing, along with the verification key (vk) and the proving key (pk). - let (params, pk, _) = generate_setup_artifacts(10, None, circuit.clone()).unwrap(); + let (params, pk, _) = + generate_setup_artifacts(10, Some("../backend/ptau/hermez-raw-11"), circuit.clone()) + .unwrap(); let num_instances = circuit.num_instance(); diff --git a/zk_prover/src/merkle_sum_tree/utils/generate_leaf_hash.rs b/zk_prover/src/merkle_sum_tree/utils/generate_leaf_hash.rs index 8effd32a..13b264ba 100644 --- a/zk_prover/src/merkle_sum_tree/utils/generate_leaf_hash.rs +++ b/zk_prover/src/merkle_sum_tree/utils/generate_leaf_hash.rs @@ -1,9 +1,9 @@ -use halo2_proofs::halo2curves::bn256::Fr as Fp; +use ethers::types::U256; use num_bigint::BigUint; use crate::merkle_sum_tree::Entry; -pub fn generate_leaf_hash(user_name: String, balances: Vec) -> Fp +pub fn generate_leaf_hash(user_name: String, balances: Vec) -> U256 where [usize; N_ASSETS + 1]: Sized, { @@ -13,5 +13,7 @@ where let entry: Entry = Entry::new(user_name, balances_big_uint.try_into().unwrap()).unwrap(); - entry.compute_leaf().hash + // Convert Fp to U256 + let hash_str = format!("{:?}", entry.compute_leaf().hash); + U256::from_str_radix(&hash_str, 16).unwrap() }