From 3eb78b775df640e9e6ad40940263d07adde75629 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Tue, 24 Oct 2023 17:29:02 +0800 Subject: [PATCH 01/38] move over PlonkVerifier and fix solhint --- .solhint.json | 2 - contract-bindings/src/i_plonk_verifier.rs | 314 +++++++ contract-bindings/src/lib.rs | 4 + contract-bindings/src/plonk_verifier.rs | 515 ++++++++++++ contract-bindings/src/polynomial_eval.rs | 140 ++++ contract-bindings/src/shared_types.rs | 69 ++ contract-bindings/src/transcript.rs | 119 +++ contracts/src/interfaces/IPlonkVerifier.sol | 100 +++ contracts/src/libraries/PlonkVerifier.sol | 856 ++++++++++++++++++++ contracts/src/libraries/PolynomialEval.sol | 249 ++++++ contracts/src/libraries/Transcript.sol | 153 ++++ flake.nix | 28 +- justfile | 5 + 13 files changed, 2539 insertions(+), 15 deletions(-) create mode 100644 contract-bindings/src/i_plonk_verifier.rs create mode 100644 contract-bindings/src/plonk_verifier.rs create mode 100644 contract-bindings/src/polynomial_eval.rs create mode 100644 contract-bindings/src/transcript.rs create mode 100644 contracts/src/interfaces/IPlonkVerifier.sol create mode 100644 contracts/src/libraries/PlonkVerifier.sol create mode 100644 contracts/src/libraries/PolynomialEval.sol create mode 100644 contracts/src/libraries/Transcript.sol diff --git a/.solhint.json b/.solhint.json index 2df82c58da..5edeab529d 100644 --- a/.solhint.json +++ b/.solhint.json @@ -10,14 +10,12 @@ , "func-param-name-mixedcase": "error" , "func-visibility": ["error", { "ignoreConstructors": true }] , "imports-on-top": "error" - , "max-line-length": ["error", 100] , "modifier-name-mixedcase": "error" , "named-parameters-mapping": "error" , "no-console": "error" , "no-empty-blocks": "error" , "no-unused-vars": "error" , "no-global-import": "off" - , "private-vars-leading-underscore": ["error", { "strict": true }] , "var-name-mixedcase": "error" } } diff --git a/contract-bindings/src/i_plonk_verifier.rs b/contract-bindings/src/i_plonk_verifier.rs new file mode 100644 index 0000000000..60680d648a --- /dev/null +++ b/contract-bindings/src/i_plonk_verifier.rs @@ -0,0 +1,314 @@ +pub use i_plonk_verifier::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod i_plonk_verifier { + pub use super::super::shared_types::*; + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([( + ::std::borrow::ToOwned::to_owned("batchVerify"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("batchVerify"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("verifyingKeys"), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ],), + ), + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned( + "struct IPlonkVerifier.VerifyingKey[]", + ), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("publicInputs"), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ), + ), + ), + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256[][]"), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("proofs"), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ), + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned( + "struct IPlonkVerifier.PlonkProof[]", + ), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("extraTranscriptInitMsgs",), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Bytes, + ), + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bytes[]"), + ), + }, + ], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + )]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static IPLONKVERIFIER_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = + ::ethers::contract::Lazy::new(__abi); + pub struct IPlonkVerifier(::ethers::contract::Contract); + impl ::core::clone::Clone for IPlonkVerifier { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for IPlonkVerifier { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for IPlonkVerifier { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for IPlonkVerifier { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(IPlonkVerifier)) + .field(&self.address()) + .finish() + } + } + impl IPlonkVerifier { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + IPLONKVERIFIER_ABI.clone(), + client, + )) + } + ///Calls the contract's `batchVerify` (0x830affd6) function + pub fn batch_verify( + &self, + verifying_keys: ::std::vec::Vec, + public_inputs: ::std::vec::Vec<::std::vec::Vec<::ethers::core::types::U256>>, + proofs: ::std::vec::Vec, + extra_transcript_init_msgs: ::std::vec::Vec<::ethers::core::types::Bytes>, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash( + [131, 10, 255, 214], + ( + verifying_keys, + public_inputs, + proofs, + extra_transcript_init_msgs, + ), + ) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for IPlonkVerifier + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `batchVerify` function with signature `batchVerify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256))[],uint256[][],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)[],bytes[])` and selector `0x830affd6` + #[derive(Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay)] + #[ethcall( + name = "batchVerify", + abi = "batchVerify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256))[],uint256[][],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)[],bytes[])" + )] + pub struct BatchVerifyCall { + pub verifying_keys: ::std::vec::Vec, + pub public_inputs: ::std::vec::Vec<::std::vec::Vec<::ethers::core::types::U256>>, + pub proofs: ::std::vec::Vec, + pub extra_transcript_init_msgs: ::std::vec::Vec<::ethers::core::types::Bytes>, + } + ///Container type for all return fields from the `batchVerify` function with signature `batchVerify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256))[],uint256[][],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)[],bytes[])` and selector `0x830affd6` + #[derive(Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec)] + pub struct BatchVerifyReturn(pub bool); +} diff --git a/contract-bindings/src/lib.rs b/contract-bindings/src/lib.rs index 0c69010afd..ac6c59a71e 100644 --- a/contract-bindings/src/lib.rs +++ b/contract-bindings/src/lib.rs @@ -10,6 +10,10 @@ pub mod bn256g2; pub mod bytes_lib; pub mod deploy_hot_shot; pub mod hot_shot; +pub mod i_plonk_verifier; +pub mod plonk_verifier; +pub mod polynomial_eval; pub mod shared_types; pub mod std_invariant; +pub mod transcript; pub mod utils; diff --git a/contract-bindings/src/plonk_verifier.rs b/contract-bindings/src/plonk_verifier.rs new file mode 100644 index 0000000000..367d512daa --- /dev/null +++ b/contract-bindings/src/plonk_verifier.rs @@ -0,0 +1,515 @@ +pub use plonk_verifier::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod plonk_verifier { + pub use super::super::shared_types::*; + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([( + ::std::borrow::ToOwned::to_owned("batchVerify"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("batchVerify"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("verifyingKeys"), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ],), + ), + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned( + "struct IPlonkVerifier.VerifyingKey[]", + ), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("publicInputs"), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ), + ), + ), + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256[][]"), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("proofs"), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ), + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned( + "struct IPlonkVerifier.PlonkProof[]", + ), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("extraTranscriptInitMsgs",), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Bytes, + ), + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bytes[]"), + ), + }, + ], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + )]), + events: ::std::collections::BTreeMap::new(), + errors: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("InvalidPlonkArgs"), + ::std::vec![::ethers::core::abi::ethabi::AbiError { + name: ::std::borrow::ToOwned::to_owned("InvalidPlonkArgs"), + inputs: ::std::vec![], + },], + ), + ( + ::std::borrow::ToOwned::to_owned("UnsupportedDegree"), + ::std::vec![::ethers::core::abi::ethabi::AbiError { + name: ::std::borrow::ToOwned::to_owned("UnsupportedDegree"), + inputs: ::std::vec![], + },], + ), + ( + ::std::borrow::ToOwned::to_owned("WrongPlonkVK"), + ::std::vec![::ethers::core::abi::ethabi::AbiError { + name: ::std::borrow::ToOwned::to_owned("WrongPlonkVK"), + inputs: ::std::vec![], + },], + ), + ]), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static PLONKVERIFIER_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = + ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"a94a\0:`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14a\0-WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\x046\x10a\x005W`\x005`\xE0\x1C\x80c6\xD8\xD6\xEB\x14a\0:W[`\0\x80\xFD[a\0Ma\0H6`\x04a5\x1DV[a\0aV[`@Q\x90\x15\x15\x81R` \x01`@Q\x80\x91\x03\x90\xF3[`\0\x82Q\x85Q\x14\x15\x80a\0vWP\x82Q\x84Q\x14\x15[\x80a\0\x83WP\x82Q\x82Q\x14\x15[\x80a\0\x8DWP\x82Q\x15[\x15a\0\xABW`@Qc\xFD\x9A-\x1B`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0\x83Q`\x01`\x01`@\x1B\x03\x81\x11\x15a\0\xC6Wa\0\xC6a0XV[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\0\xFFW\x81` \x01[a\0\xECa/jV[\x81R` \x01\x90`\x01\x90\x03\x90\x81a\0\xE4W\x90P[P\x90P`\0[\x84Q\x81\x10\x15a\x02CWa\x010\x85\x82\x81Q\x81\x10a\x01#Wa\x01#a7\x9FV[` \x02` \x01\x01Qa\x02YV[`\0[\x86\x82\x81Q\x81\x10a\x01EWa\x01Ea7\x9FV[` \x02` \x01\x01QQ\x81\x10\x15a\x01\xA2Wa\x01\x90\x87\x83\x81Q\x81\x10a\x01jWa\x01ja7\x9FV[` \x02` \x01\x01Q\x82\x81Q\x81\x10a\x01\x83Wa\x01\x83a7\x9FV[` \x02` \x01\x01Qa\x03\x86V[\x80a\x01\x9A\x81a7\xCBV[\x91PPa\x013V[Pa\x02\x13\x87\x82\x81Q\x81\x10a\x01\xB8Wa\x01\xB8a7\x9FV[` \x02` \x01\x01Q\x87\x83\x81Q\x81\x10a\x01\xD2Wa\x01\xD2a7\x9FV[` \x02` \x01\x01Q\x87\x84\x81Q\x81\x10a\x01\xECWa\x01\xECa7\x9FV[` \x02` \x01\x01Q\x87\x85\x81Q\x81\x10a\x02\x06Wa\x02\x06a7\x9FV[` \x02` \x01\x01Qa\x03\xEDV[\x82\x82\x81Q\x81\x10a\x02%Wa\x02%a7\x9FV[` \x02` \x01\x01\x81\x90RP\x80\x80a\x02;\x90a7\xCBV[\x91PPa\x01\x05V[Pa\x02M\x81a\x05EV[\x91PP[\x94\x93PPPPV[\x80Qa\x02d\x90a\x0C\xE8V[a\x02q\x81` \x01Qa\x0C\xE8V[a\x02~\x81`@\x01Qa\x0C\xE8V[a\x02\x8B\x81``\x01Qa\x0C\xE8V[a\x02\x98\x81`\x80\x01Qa\x0C\xE8V[a\x02\xA5\x81`\xA0\x01Qa\x0C\xE8V[a\x02\xB2\x81`\xC0\x01Qa\x0C\xE8V[a\x02\xBF\x81`\xE0\x01Qa\x0C\xE8V[a\x02\xCD\x81a\x01\0\x01Qa\x0C\xE8V[a\x02\xDB\x81a\x01 \x01Qa\x0C\xE8V[a\x02\xE9\x81a\x01@\x01Qa\x0C\xE8V[a\x02\xF7\x81a\x01`\x01Qa\x0C\xE8V[a\x03\x05\x81a\x01\xA0\x01Qa\x03\x86V[a\x03\x13\x81a\x01\xC0\x01Qa\x03\x86V[a\x03!\x81a\x01\xE0\x01Qa\x03\x86V[a\x03/\x81a\x02\0\x01Qa\x03\x86V[a\x03=\x81a\x02 \x01Qa\x03\x86V[a\x03K\x81a\x02@\x01Qa\x03\x86V[a\x03Y\x81a\x02`\x01Qa\x03\x86V[a\x03g\x81a\x02\x80\x01Qa\x03\x86V[a\x03u\x81a\x02\xA0\x01Qa\x03\x86V[a\x03\x83\x81a\x02\xC0\x01Qa\x03\x86V[PV[`\0\x80Q` a8\xDF\x839\x81Q\x91R\x81\x10\x80a\x03\xE9W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FBn254: invalid scalar field\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[PPV[a\x03\xF5a/jV[\x84` \x01Q\x84Q\x14a\x04\x1AW`@Qc \xFA\x9D\x89`\xE1\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0a\x04(\x86\x86\x86\x86a\rwV[\x90P`\0a\x049\x87`\0\x01Qa\x0FEV[\x90P`\0a\x04L\x82\x84`\xA0\x01Q\x89a\x11\xE1V[`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x91\x92P`\0\x91\x90` \x82\x01a\x03\xC0\x806\x837PP`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x92\x93P`\0\x92\x91P` \x82\x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x04\x8FW\x90PP\x90P`\0a\x04\xC8\x8B\x85\x8B\x89\x87\x87a\x12AV[`\xA0\x87\x01Q``\x87\x01Q\x91\x92P\x90`\0\x80Q` a8\xDF\x839\x81Q\x91R`\0\x81\x83\x85\t`@\x80Qa\x01\0\x81\x01\x82R`\xE0\x9C\x8D\x01Q\x81R` \x81\x01\x96\x90\x96R\x85\x01RPPP``\x81\x01\x91\x90\x91R`\x80\x81\x01\x92\x90\x92R`\xA0\x82\x01Ra\x01`\x87\x01Q`\xC0\x82\x01Ra\x01\x80\x90\x96\x01Q\x92\x86\x01\x92\x90\x92RP\x92\x95\x94PPPPPV[\x80Q`\0\x90`\0\x80Q` a8\xDF\x839\x81Q\x91R`\x01\x80\x83\x11\x15a\x05\xC6Wa\x05ka/\xE4V[`\0[\x84\x81\x10\x15a\x05\xB8Wa\x05\xA6\x87\x82\x81Q\x81\x10a\x05\x8BWa\x05\x8Ba7\x9FV[` \x02` \x01\x01Q`\0\x01Q\x83a\x12j\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x80a\x05\xB0\x81a7\xCBV[\x91PPa\x05nV[Pa\x05\xC2\x81a\x12tV[\x91PP[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`\0a\x05\xFB\x86`\x02a7\xE4V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06\x12Wa\x06\x12a0XV[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06;W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P`\0a\x06K\x87`\x02a7\xE4V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06bWa\x06ba0XV[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06\xA7W\x81` \x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x06\x80W\x90P[P\x90P`\x01`\0[\x88\x81\x10\x15a\x07\xF0W\x81\x84a\x06\xC4\x83`\x02a7\xE4V[\x81Q\x81\x10a\x06\xD4Wa\x06\xD4a7\x9FV[` \x02` \x01\x01\x81\x81RPP\x8A\x81\x81Q\x81\x10a\x06\xF2Wa\x06\xF2a7\x9FV[` \x02` \x01\x01Q`\xC0\x01Q\x83\x82`\x02a\x07\x0C\x91\x90a7\xE4V[\x81Q\x81\x10a\x07\x1CWa\x07\x1Ca7\x9FV[` \x02` \x01\x01\x81\x90RP`\0\x80\x8C\x83\x81Q\x81\x10a\x07\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x05`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\x0F\x84\x84a\x1ANV[\x80\x82Ra\x12\x1F\x90\x85\x90\x85\x90a\x1A\xA2V[` \x82\x01R\x80Qa\x125\x90\x85\x90\x84\x90\x86\x90a\x1B\x08V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12O\x85\x87\x89a\x1C^V[\x90Pa\x12_\x88\x86\x89\x89\x88\x88a\x1DJV[a\x0C\xDC\x81\x87\x86a VV[a\x03\xE9\x82\x82a \xA6V[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x12\x9C\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a8>V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x12\xCDWa\x12\xCDa7\x9FV[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x12\xE9Wa\x12\xE9a7\x9FV[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x08\x94\x93\x92\x91\x90a8>V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x138Wa\x138a7\x9FV[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13YWa\x13Ya7\x9FV[` \x02\x01\x81\x81RPPa\x02Qa\x13\x9C\x83\x83`@Q` \x01a\x13\x84\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a \xD9V[a!\xE6V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14D\x83`\0\x81Q\x81\x10a\x14\x1CWa\x14\x1Ca7\x9FV[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x147Wa\x147a7\x9FV[` \x02` \x01\x01Qa\"fV[\x90P`\x01[\x82Q\x81\x10\x15a\x14\x9EWa\x14\x8A\x82a\x14\x85\x86\x84\x81Q\x81\x10a\x14kWa\x14ka7\x9FV[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x147Wa\x147a7\x9FV[a#\nV[\x91P\x80a\x14\x96\x81a7\xCBV[\x91PPa\x14IV[P\x92\x91PPV[`\0a\x14\xBF`\0\x80Q` a8\xDF\x839\x81Q\x91R\x83a8tV[a\x14\xD7\x90`\0\x80Q` a8\xDF\x839\x81Q\x91Ra8\x96V[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x05WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a8\xBF\x839\x81Q\x91R\x84` \x01Qa\x158\x91\x90a8tV[a\x15P\x90`\0\x80Q` a8\xBF\x839\x81Q\x91Ra8\x96V[\x90R\x92\x91PPV[a\x15\x83`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x16\xFFW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\x1F\x91\x90\x83\x90` \x01a8\xA9V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x17v\x84a\x17qa\x17G\x84a#\xB1V[`@Q` \x01a\x17Y\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a \xD9V[a\x17\x0BV[a\x17\x8A\x84a\x17qa\x17G\x86`\0\x01Qa#\xB1V[a\x17\x9E\x84a\x17qa\x17G\x86` \x01Qa#\xB1V[a\x17\xA9\x84`\x01a \xA6V[a\x17\xD3\x84\x7F/\x8D\xD1\xF1\xA7X\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x05`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\x0F\x84\x84a\x1ANV[\x80\x82Ra\x12\x1F\x90\x85\x90\x85\x90a\x1A\xA2V[` \x82\x01R\x80Qa\x125\x90\x85\x90\x84\x90\x86\x90a\x1B\x08V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12O\x85\x87\x89a\x1C^V[\x90Pa\x12_\x88\x86\x89\x89\x88\x88a\x1DJV[a\x0C\xDC\x81\x87\x86a VV[a\x03\xE9\x82\x82a \xA6V[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x12\x9C\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a8>V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x12\xCDWa\x12\xCDa7\x9FV[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x12\xE9Wa\x12\xE9a7\x9FV[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x08\x94\x93\x92\x91\x90a8>V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x138Wa\x138a7\x9FV[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13YWa\x13Ya7\x9FV[` \x02\x01\x81\x81RPPa\x02Qa\x13\x9C\x83\x83`@Q` \x01a\x13\x84\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a \xD9V[a!\xE6V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14D\x83`\0\x81Q\x81\x10a\x14\x1CWa\x14\x1Ca7\x9FV[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x147Wa\x147a7\x9FV[` \x02` \x01\x01Qa\"fV[\x90P`\x01[\x82Q\x81\x10\x15a\x14\x9EWa\x14\x8A\x82a\x14\x85\x86\x84\x81Q\x81\x10a\x14kWa\x14ka7\x9FV[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x147Wa\x147a7\x9FV[a#\nV[\x91P\x80a\x14\x96\x81a7\xCBV[\x91PPa\x14IV[P\x92\x91PPV[`\0a\x14\xBF`\0\x80Q` a8\xDF\x839\x81Q\x91R\x83a8tV[a\x14\xD7\x90`\0\x80Q` a8\xDF\x839\x81Q\x91Ra8\x96V[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x05WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a8\xBF\x839\x81Q\x91R\x84` \x01Qa\x158\x91\x90a8tV[a\x15P\x90`\0\x80Q` a8\xBF\x839\x81Q\x91Ra8\x96V[\x90R\x92\x91PPV[a\x15\x83`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x16\xFFW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\x1F\x91\x90\x83\x90` \x01a8\xA9V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x17v\x84a\x17qa\x17G\x84a#\xB1V[`@Q` \x01a\x17Y\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a \xD9V[a\x17\x0BV[a\x17\x8A\x84a\x17qa\x17G\x86`\0\x01Qa#\xB1V[a\x17\x9E\x84a\x17qa\x17G\x86` \x01Qa#\xB1V[a\x17\xA9\x84`\x01a \xA6V[a\x17\xD3\x84\x7F/\x8D\xD1\xF1\xA7X(::ethers::contract::Contract); + impl ::core::clone::Clone for PlonkVerifier { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for PlonkVerifier { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for PlonkVerifier { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for PlonkVerifier { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(PlonkVerifier)) + .field(&self.address()) + .finish() + } + } + impl PlonkVerifier { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + PLONKVERIFIER_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. + /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + PLONKVERIFIER_ABI.clone(), + PLONKVERIFIER_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `batchVerify` (0x830affd6) function + pub fn batch_verify( + &self, + verifying_keys: ::std::vec::Vec, + public_inputs: ::std::vec::Vec<::std::vec::Vec<::ethers::core::types::U256>>, + proofs: ::std::vec::Vec, + extra_transcript_init_msgs: ::std::vec::Vec<::ethers::core::types::Bytes>, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash( + [131, 10, 255, 214], + ( + verifying_keys, + public_inputs, + proofs, + extra_transcript_init_msgs, + ), + ) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for PlonkVerifier + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Custom Error type `InvalidPlonkArgs` with signature `InvalidPlonkArgs()` and selector `0xfd9a2d1b` + #[derive( + Clone, + ::ethers::contract::EthError, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[etherror(name = "InvalidPlonkArgs", abi = "InvalidPlonkArgs()")] + pub struct InvalidPlonkArgs; + ///Custom Error type `UnsupportedDegree` with signature `UnsupportedDegree()` and selector `0xe2ef09e5` + #[derive( + Clone, + ::ethers::contract::EthError, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[etherror(name = "UnsupportedDegree", abi = "UnsupportedDegree()")] + pub struct UnsupportedDegree; + ///Custom Error type `WrongPlonkVK` with signature `WrongPlonkVK()` and selector `0x41f53b12` + #[derive( + Clone, + ::ethers::contract::EthError, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[etherror(name = "WrongPlonkVK", abi = "WrongPlonkVK()")] + pub struct WrongPlonkVK; + ///Container type for all of the contract's custom errors + #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + pub enum PlonkVerifierErrors { + InvalidPlonkArgs(InvalidPlonkArgs), + UnsupportedDegree(UnsupportedDegree), + WrongPlonkVK(WrongPlonkVK), + /// The standard solidity revert string, with selector + /// Error(string) -- 0x08c379a0 + RevertString(::std::string::String), + } + impl ::ethers::core::abi::AbiDecode for PlonkVerifierErrors { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) = + <::std::string::String as ::ethers::core::abi::AbiDecode>::decode(data) + { + return Ok(Self::RevertString(decoded)); + } + if let Ok(decoded) = ::decode(data) + { + return Ok(Self::InvalidPlonkArgs(decoded)); + } + if let Ok(decoded) = ::decode(data) + { + return Ok(Self::UnsupportedDegree(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::WrongPlonkVK(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for PlonkVerifierErrors { + fn encode(self) -> ::std::vec::Vec { + match self { + Self::InvalidPlonkArgs(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::UnsupportedDegree(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::WrongPlonkVK(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::RevertString(s) => ::ethers::core::abi::AbiEncode::encode(s), + } + } + } + impl ::ethers::contract::ContractRevert for PlonkVerifierErrors { + fn valid_selector(selector: [u8; 4]) -> bool { + match selector { + [0x08, 0xc3, 0x79, 0xa0] => true, + _ if selector == ::selector() => { + true + } + _ if selector + == ::selector() => + { + true + } + _ if selector == ::selector() => true, + _ => false, + } + } + } + impl ::core::fmt::Display for PlonkVerifierErrors { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::InvalidPlonkArgs(element) => ::core::fmt::Display::fmt(element, f), + Self::UnsupportedDegree(element) => ::core::fmt::Display::fmt(element, f), + Self::WrongPlonkVK(element) => ::core::fmt::Display::fmt(element, f), + Self::RevertString(s) => ::core::fmt::Display::fmt(s, f), + } + } + } + impl ::core::convert::From<::std::string::String> for PlonkVerifierErrors { + fn from(value: String) -> Self { + Self::RevertString(value) + } + } + impl ::core::convert::From for PlonkVerifierErrors { + fn from(value: InvalidPlonkArgs) -> Self { + Self::InvalidPlonkArgs(value) + } + } + impl ::core::convert::From for PlonkVerifierErrors { + fn from(value: UnsupportedDegree) -> Self { + Self::UnsupportedDegree(value) + } + } + impl ::core::convert::From for PlonkVerifierErrors { + fn from(value: WrongPlonkVK) -> Self { + Self::WrongPlonkVK(value) + } + } + ///Container type for all input parameters for the `batchVerify` function with signature `batchVerify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256))[],uint256[][],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)[],bytes[])` and selector `0x830affd6` + #[derive(Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay)] + #[ethcall( + name = "batchVerify", + abi = "batchVerify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256))[],uint256[][],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)[],bytes[])" + )] + pub struct BatchVerifyCall { + pub verifying_keys: ::std::vec::Vec, + pub public_inputs: ::std::vec::Vec<::std::vec::Vec<::ethers::core::types::U256>>, + pub proofs: ::std::vec::Vec, + pub extra_transcript_init_msgs: ::std::vec::Vec<::ethers::core::types::Bytes>, + } + ///Container type for all return fields from the `batchVerify` function with signature `batchVerify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256))[],uint256[][],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)[],bytes[])` and selector `0x830affd6` + #[derive(Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec)] + pub struct BatchVerifyReturn(pub bool); +} diff --git a/contract-bindings/src/polynomial_eval.rs b/contract-bindings/src/polynomial_eval.rs new file mode 100644 index 0000000000..85bf245fa9 --- /dev/null +++ b/contract-bindings/src/polynomial_eval.rs @@ -0,0 +1,140 @@ +pub use polynomial_eval::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod polynomial_eval { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::std::collections::BTreeMap::new(), + events: ::std::collections::BTreeMap::new(), + errors: ::core::convert::From::from([( + ::std::borrow::ToOwned::to_owned("UnsupportedDegree"), + ::std::vec![::ethers::core::abi::ethabi::AbiError { + name: ::std::borrow::ToOwned::to_owned("UnsupportedDegree"), + inputs: ::std::vec![], + },], + )]), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static POLYNOMIALEVAL_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = + ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`V`7`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14`*WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 b\xC6\n\xF4m\x8F\x9CZ\xA2\x97A\x81\x81#X\")\x9F\xB5\xA0\xB5\x07\xD1\xD1\xDB\x1C,\x14\x07\xBB\xC2ldsolcC\0\x08\x14\x003"; + /// The bytecode of the contract. + pub static POLYNOMIALEVAL_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__BYTECODE); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 b\xC6\n\xF4m\x8F\x9CZ\xA2\x97A\x81\x81#X\")\x9F\xB5\xA0\xB5\x07\xD1\xD1\xDB\x1C,\x14\x07\xBB\xC2ldsolcC\0\x08\x14\x003"; + /// The deployed bytecode of the contract. + pub static POLYNOMIALEVAL_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); + pub struct PolynomialEval(::ethers::contract::Contract); + impl ::core::clone::Clone for PolynomialEval { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for PolynomialEval { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for PolynomialEval { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for PolynomialEval { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(PolynomialEval)) + .field(&self.address()) + .finish() + } + } + impl PolynomialEval { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + POLYNOMIALEVAL_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. + /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + POLYNOMIALEVAL_ABI.clone(), + POLYNOMIALEVAL_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + } + impl From<::ethers::contract::Contract> + for PolynomialEval + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Custom Error type `UnsupportedDegree` with signature `UnsupportedDegree()` and selector `0xe2ef09e5` + #[derive( + Clone, + ::ethers::contract::EthError, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[etherror(name = "UnsupportedDegree", abi = "UnsupportedDegree()")] + pub struct UnsupportedDegree; +} diff --git a/contract-bindings/src/shared_types.rs b/contract-bindings/src/shared_types.rs index 1d71824186..c59894e9e1 100644 --- a/contract-bindings/src/shared_types.rs +++ b/contract-bindings/src/shared_types.rs @@ -30,3 +30,72 @@ pub struct G2Point { pub y_0: ::ethers::core::types::U256, pub y_1: ::ethers::core::types::U256, } +///`PlonkProof((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)` +#[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash, +)] +pub struct PlonkProof { + pub wire_0: G1Point, + pub wire_1: G1Point, + pub wire_2: G1Point, + pub wire_3: G1Point, + pub wire_4: G1Point, + pub prod_perm: G1Point, + pub split_0: G1Point, + pub split_1: G1Point, + pub split_2: G1Point, + pub split_3: G1Point, + pub split_4: G1Point, + pub zeta: G1Point, + pub zeta_omega: G1Point, + pub wire_eval_0: ::ethers::core::types::U256, + pub wire_eval_1: ::ethers::core::types::U256, + pub wire_eval_2: ::ethers::core::types::U256, + pub wire_eval_3: ::ethers::core::types::U256, + pub wire_eval_4: ::ethers::core::types::U256, + pub sigma_eval_0: ::ethers::core::types::U256, + pub sigma_eval_1: ::ethers::core::types::U256, + pub sigma_eval_2: ::ethers::core::types::U256, + pub sigma_eval_3: ::ethers::core::types::U256, + pub prod_perm_zeta_omega_eval: ::ethers::core::types::U256, +} +///`VerifyingKey(uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256))` +#[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + Default, + Debug, + PartialEq, + Eq, + Hash, +)] +pub struct VerifyingKey { + pub domain_size: ::ethers::core::types::U256, + pub num_inputs: ::ethers::core::types::U256, + pub sigma_0: G1Point, + pub sigma_1: G1Point, + pub sigma_2: G1Point, + pub sigma_3: G1Point, + pub sigma_4: G1Point, + pub q_1: G1Point, + pub q_2: G1Point, + pub q_3: G1Point, + pub q_4: G1Point, + pub q_m12: G1Point, + pub q_m34: G1Point, + pub q_o: G1Point, + pub q_c: G1Point, + pub q_h1: G1Point, + pub q_h2: G1Point, + pub q_h3: G1Point, + pub q_h4: G1Point, + pub q_ecc: G1Point, +} diff --git a/contract-bindings/src/transcript.rs b/contract-bindings/src/transcript.rs new file mode 100644 index 0000000000..af3bf6518a --- /dev/null +++ b/contract-bindings/src/transcript.rs @@ -0,0 +1,119 @@ +pub use transcript::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod transcript { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::std::collections::BTreeMap::new(), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static TRANSCRIPT_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = + ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`V`7`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14`*WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \0\x9E4\xCD\xBA\xED_D\xBC\x91\xCB\x1F\xE6,~'\x93\xECp\x8C\xDD'\xD5\xE4\xFAE\xDF\xA8\xE4\x82\xCBVdsolcC\0\x08\x14\x003"; + /// The bytecode of the contract. + pub static TRANSCRIPT_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__BYTECODE); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \0\x9E4\xCD\xBA\xED_D\xBC\x91\xCB\x1F\xE6,~'\x93\xECp\x8C\xDD'\xD5\xE4\xFAE\xDF\xA8\xE4\x82\xCBVdsolcC\0\x08\x14\x003"; + /// The deployed bytecode of the contract. + pub static TRANSCRIPT_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); + pub struct Transcript(::ethers::contract::Contract); + impl ::core::clone::Clone for Transcript { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for Transcript { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for Transcript { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for Transcript { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(Transcript)) + .field(&self.address()) + .finish() + } + } + impl Transcript { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + TRANSCRIPT_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. + /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + TRANSCRIPT_ABI.clone(), + TRANSCRIPT_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + } + impl From<::ethers::contract::Contract> for Transcript { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } +} diff --git a/contracts/src/interfaces/IPlonkVerifier.sol b/contracts/src/interfaces/IPlonkVerifier.sol new file mode 100644 index 0000000000..b5a7aa3692 --- /dev/null +++ b/contracts/src/interfaces/IPlonkVerifier.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: Unlicensed + +pragma solidity ^0.8.0; + +import { BN254 } from "bn254/BN254.sol"; + +/// @title The structs and interfaces for a specific flavor of TurboPlonk verifier. +interface IPlonkVerifier { + // Flatten out TurboPlonk proof + struct PlonkProof { + // the first 5 are 4 inputs and 1 output wire poly commmitments + // i.e., batch_proof.wires_poly_comms_vec.iter() + // wire0 is 32 bytes which is a pointer to BN254.G1Point + BN254.G1Point wire0; // 0x00 + BN254.G1Point wire1; // 0x20 + BN254.G1Point wire2; // 0x40 + BN254.G1Point wire3; // 0x60 + BN254.G1Point wire4; // 0x80 + // the next one is the product permutation poly commitment + // i.e., batch_proof.prod_perm_poly_comms_vec.iter() + BN254.G1Point prodPerm; // 0xA0 + // the next 5 are split quotient poly commmitments + // i.e., batch_proof.split_quot_poly_comms + BN254.G1Point split0; // 0xC0 + BN254.G1Point split1; // 0xE0 + BN254.G1Point split2; // 0x100 + BN254.G1Point split3; // 0x120 + BN254.G1Point split4; // 0x140 + // witness poly com for aggregated opening at `zeta` + // i.e., batch_proof.opening_proof + BN254.G1Point zeta; // 0x160 + // witness poly com for shifted opening at `zeta * \omega` + // i.e., batch_proof.shifted_opening_proof + BN254.G1Point zetaOmega; // 0x180 + // wire poly eval at `zeta` + uint256 wireEval0; // 0x1A0 + uint256 wireEval1; // 0x1C0 + uint256 wireEval2; // 0x1E0 + uint256 wireEval3; // 0x200 + uint256 wireEval4; // 0x220 + // extended permutation (sigma) poly eval at `zeta` + // last (sigmaEval4) is saved by Maller Optimization + uint256 sigmaEval0; // 0x240 + uint256 sigmaEval1; // 0x260 + uint256 sigmaEval2; // 0x280 + uint256 sigmaEval3; // 0x2A0 + // product permutation poly eval at `zeta * \omega` + uint256 prodPermZetaOmegaEval; // 0x2C0 + } + + // The verifying key for Plonk proofs. + struct VerifyingKey { + uint256 domainSize; // 0x00 + uint256 numInputs; // 0x20 + // commitment to extended perm (sigma) poly + BN254.G1Point sigma0; // 0x40 + BN254.G1Point sigma1; // 0x60 + BN254.G1Point sigma2; // 0x80 + BN254.G1Point sigma3; // 0xA0 + BN254.G1Point sigma4; // 0xC0 + // commitment to selector poly + // first 4 are linear combination selector + BN254.G1Point q1; // 0xE0 + BN254.G1Point q2; // 0x100 + BN254.G1Point q3; // 0x120 + BN254.G1Point q4; // 0x140 + // multiplication selector for 1st, 2nd wire + BN254.G1Point qM12; // 0x160 + // multiplication selector for 3rd, 4th wire + BN254.G1Point qM34; // 0x180 + // output selector + BN254.G1Point qO; // 0x1A0 + // constant term selector + BN254.G1Point qC; // 0x1C0 + // rescue selector qH1 * w_ai^5 + BN254.G1Point qH1; // 0x1E0 + // rescue selector qH2 * w_bi^5 + BN254.G1Point qH2; // 0x200 + // rescue selector qH3 * w_ci^5 + BN254.G1Point qH3; // 0x220 + // rescue selector qH4 * w_di^5 + BN254.G1Point qH4; // 0x240 + // elliptic curve selector + BN254.G1Point qEcc; // 0x260 + } + + /// @dev Batch verify multiple TurboPlonk proofs. + /// @param verifyingKeys An array of verifying keys + /// @param publicInputs A two-dimensional array of public inputs. + /// @param proofs An array of Plonk proofs + /// @param extraTranscriptInitMsgs An array of bytes from + /// transcript initialization messages + /// @return _ A boolean that is true for successful verification, false otherwise + function batchVerify( + VerifyingKey[] memory verifyingKeys, + uint256[][] memory publicInputs, + PlonkProof[] memory proofs, + bytes[] memory extraTranscriptInitMsgs + ) external view returns (bool); +} diff --git a/contracts/src/libraries/PlonkVerifier.sol b/contracts/src/libraries/PlonkVerifier.sol new file mode 100644 index 0000000000..367c6d334e --- /dev/null +++ b/contracts/src/libraries/PlonkVerifier.sol @@ -0,0 +1,856 @@ +// SPDX-License-Identifier: Unlicensed + +pragma solidity ^0.8.0; + +import { BN254 } from "bn254/BN254.sol"; +import { PolynomialEval as Poly } from "./PolynomialEval.sol"; +import { IPlonkVerifier } from "../interfaces/IPlonkVerifier.sol"; +import { Transcript } from "./Transcript.sol"; + +/* solhint-disable no-inline-assembly */ + +/// @dev The TurboPlonk formla is: +/// qo * wo = pub_input + q_c + +/// q_mul0 * w0 * w1 + q_mul1 * w2 * w3 + +/// q_lc0 * w0 + q_lc1 * w1 + q_lc2 * w2 + q_lc3 * w3 + +/// q_hash0 * w0 + q_hash1 * w1 + q_hash2 * w2 + q_hash3 * w3 + +/// q_ecc * w0 * w1 * w2 * w3 * wo +library PlonkVerifier { + /// Plonk: invalid inputs, either mismatching lengths among input arguments + /// or empty input. + error InvalidPlonkArgs(); + /// Plonk: wrong verification key used. + error WrongPlonkVK(); + + using Transcript for Transcript.TranscriptData; + + // _COSET_K0 = 1, has no effect during multiplication, thus avoid declaring it here. + uint256 private constant COSET_K1 = + 0x2f8dd1f1a7583c42c4e12a44e110404c73ca6c94813f85835da4fb7bb1301d4a; + uint256 private constant COSET_K2 = + 0x1ee678a0470a75a6eaa8fe837060498ba828a3703b311d0f77f010424afeb025; + uint256 private constant COSET_K3 = + 0x2042a587a90c187b0a087c03e29c968b950b1db26d5c82d666905a6895790c0a; + uint256 private constant COSET_K4 = + 0x2e2b91456103698adf57b799969dea1c8f739da5d8d40dd3eb9222db7c81e881; + + // Parsed from Aztec's Ignition CRS, + // `beta_h` \in G2 where \beta is the trapdoor, h is G2 generator `BN254.P2()` + // See parsing code: https://github.com/alxiong/crs + // @dev since library cannot have constant value of custom type, we break it + // into individual field values. + uint256 private constant BETA_H_X0 = + 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1; + uint256 private constant BETA_H_X1 = + 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0; + uint256 private constant BETA_H_Y0 = + 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4; + uint256 private constant BETA_H_Y1 = + 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55; + + /// The number of wire types of the circuit, TurboPlonk has 5. + uint256 private constant NUM_WIRE_TYPES = 5; + + /// @dev polynomial commitment evaluation info. + struct PcsInfo { + // a random combiner that was used to combine evaluations at point + uint256 u; // 0x00 + // the point to be evaluated at + uint256 evalPoint; // 0x20 + // the shifted point to be evaluated at + uint256 nextEvalPoint; // 0x40 + // the polynomial evaluation value + uint256 eval; // 0x60 + // scalars of poly comm for MSM + uint256[] commScalars; // 0x80 + // bases of poly comm for MSM + BN254.G1Point[] commBases; // 0xa0 + // proof of evaluations at point `eval_point` + BN254.G1Point openingProof; // 0xc0 + // proof of evaluations at point `next_eval_point` + BN254.G1Point shiftedOpeningProof; // 0xe0 + } + + /// @dev Plonk IOP verifier challenges. + struct Challenges { + uint256 alpha; // 0x00 + uint256 alpha2; // 0x20 + uint256 alpha3; // 0x40 + uint256 beta; // 0x60 + uint256 gamma; // 0x80 + uint256 zeta; // 0xA0 + uint256 v; // 0xC0 + uint256 u; // 0xE0 + } + + /// @dev Batch verify multiple TurboPlonk proofs. + /// @param verifyingKeys An array of verifier keys + /// @param publicInputs A two-dimensional array of public inputs. + /// @param proofs An array of Plonk proofs + /// @param extraTranscriptInitMsgs An array of bytes from + /// transcript initialization messages + function batchVerify( + IPlonkVerifier.VerifyingKey[] memory verifyingKeys, + uint256[][] memory publicInputs, + IPlonkVerifier.PlonkProof[] memory proofs, + bytes[] memory extraTranscriptInitMsgs + ) external view returns (bool) { + if ( + verifyingKeys.length != proofs.length || publicInputs.length != proofs.length + || extraTranscriptInitMsgs.length != proofs.length || proofs.length == 0 + ) { + revert InvalidPlonkArgs(); + } + + PcsInfo[] memory pcsInfos = new PcsInfo[](proofs.length); + for (uint256 i = 0; i < proofs.length; i++) { + // validate proofs are proper group/field elements + _validateProof(proofs[i]); + // validate public input are all proper scalar fields + for (uint256 j = 0; j < publicInputs[i].length; j++) { + BN254.validateScalarField(publicInputs[i][j]); + } + // prepare pcs info + pcsInfos[i] = _preparePcsInfo( + verifyingKeys[i], publicInputs[i], proofs[i], extraTranscriptInitMsgs[i] + ); + } + + return _batchVerifyOpeningProofs(pcsInfos); + } + + /// @dev Validate all group points and scalar fields. Revert if + /// any are invalid. + /// @param proof A Plonk proof + function _validateProof(IPlonkVerifier.PlonkProof memory proof) internal pure { + BN254.validateG1Point(proof.wire0); + BN254.validateG1Point(proof.wire1); + BN254.validateG1Point(proof.wire2); + BN254.validateG1Point(proof.wire3); + BN254.validateG1Point(proof.wire4); + BN254.validateG1Point(proof.prodPerm); + BN254.validateG1Point(proof.split0); + BN254.validateG1Point(proof.split1); + BN254.validateG1Point(proof.split2); + BN254.validateG1Point(proof.split3); + BN254.validateG1Point(proof.split4); + BN254.validateG1Point(proof.zeta); + BN254.validateScalarField(proof.wireEval0); + BN254.validateScalarField(proof.wireEval1); + BN254.validateScalarField(proof.wireEval2); + BN254.validateScalarField(proof.wireEval3); + BN254.validateScalarField(proof.wireEval4); + BN254.validateScalarField(proof.sigmaEval0); + BN254.validateScalarField(proof.sigmaEval1); + BN254.validateScalarField(proof.sigmaEval2); + BN254.validateScalarField(proof.sigmaEval3); + BN254.validateScalarField(proof.prodPermZetaOmegaEval); + } + + function _preparePcsInfo( + IPlonkVerifier.VerifyingKey memory verifyingKey, + uint256[] memory publicInput, + IPlonkVerifier.PlonkProof memory proof, + bytes memory extraTranscriptInitMsg + ) internal view returns (PcsInfo memory res) { + if (publicInput.length != verifyingKey.numInputs) revert WrongPlonkVK(); + + Challenges memory chal = + _computeChallenges(verifyingKey, publicInput, proof, extraTranscriptInitMsg); + + Poly.EvalDomain memory domain = Poly.newEvalDomain(verifyingKey.domainSize); + // pre-compute evaluation data + Poly.EvalData memory evalData = Poly.evalDataGen(domain, chal.zeta, publicInput); + + // compute opening proof in poly comm. + uint256[] memory commScalars = new uint256[](30); + BN254.G1Point[] memory commBases = new BN254.G1Point[](30); + + uint256 eval = + _prepareOpeningProof(verifyingKey, evalData, proof, chal, commScalars, commBases); + + uint256 zeta = chal.zeta; + uint256 omega = domain.groupGen; + uint256 p = BN254.R_MOD; + uint256 zetaOmega; + assembly { + zetaOmega := mulmod(zeta, omega, p) + } + + res = PcsInfo( + chal.u, zeta, zetaOmega, eval, commScalars, commBases, proof.zeta, proof.zetaOmega + ); + } + + function _computeChallenges( + IPlonkVerifier.VerifyingKey memory verifyingKey, + uint256[] memory publicInput, + IPlonkVerifier.PlonkProof memory proof, + bytes memory extraTranscriptInitMsg + ) internal pure returns (Challenges memory res) { + Transcript.TranscriptData memory transcript; + uint256 p = BN254.R_MOD; + + transcript.appendMessage(extraTranscriptInitMsg); + transcript.appendVkAndPubInput(verifyingKey, publicInput); + transcript.appendGroupElement(proof.wire0); + transcript.appendGroupElement(proof.wire1); + transcript.appendGroupElement(proof.wire2); + transcript.appendGroupElement(proof.wire3); + transcript.appendGroupElement(proof.wire4); + + // have to compute tau, but not really used anywhere + // slither-disable-next-line unused-return + transcript.getAndAppendChallenge(); + res.beta = transcript.getAndAppendChallenge(); + res.gamma = transcript.getAndAppendChallenge(); + + transcript.appendGroupElement(proof.prodPerm); + + res.alpha = transcript.getAndAppendChallenge(); + + transcript.appendGroupElement(proof.split0); + transcript.appendGroupElement(proof.split1); + transcript.appendGroupElement(proof.split2); + transcript.appendGroupElement(proof.split3); + transcript.appendGroupElement(proof.split4); + + res.zeta = transcript.getAndAppendChallenge(); + + transcript.appendProofEvaluations(proof); + res.v = transcript.getAndAppendChallenge(); + + transcript.appendGroupElement(proof.zeta); + transcript.appendGroupElement(proof.zetaOmega); + res.u = transcript.getAndAppendChallenge(); + + assembly { + let alpha := mload(res) + let alpha2 := mulmod(alpha, alpha, p) + let alpha3 := mulmod(alpha2, alpha, p) + mstore(add(res, 0x20), alpha2) + mstore(add(res, 0x40), alpha3) + } + } + + /// @dev Compute the constant term of the linearization polynomial. + /// ``` + /// r_plonk = PI - L1(x) * alpha^2 - alpha * \prod_i=1..m-1 (w_i + beta * sigma_i + gamma) * + /// (w_m + gamma) * z(xw) + /// ``` + /// where m is the number of wire types. + function _computeLinPolyConstantTerm( + Challenges memory chal, + IPlonkVerifier.PlonkProof memory proof, + Poly.EvalData memory evalData + ) internal pure returns (uint256 res) { + uint256 p = BN254.R_MOD; + uint256 lagrangeOneEval = evalData.lagrangeOne; + uint256 piEval = evalData.piEval; + uint256 perm = 1; + + assembly { + let beta := mload(add(chal, 0x60)) + let gamma := mload(add(chal, 0x80)) + + // \prod_i=1..m-1 (w_i + beta * sigma_i + gamma) + { + let w0 := mload(add(proof, 0x1a0)) + let sigma0 := mload(add(proof, 0x240)) + perm := mulmod(perm, addmod(add(w0, gamma), mulmod(beta, sigma0, p), p), p) + } + { + let w1 := mload(add(proof, 0x1c0)) + let sigma1 := mload(add(proof, 0x260)) + perm := mulmod(perm, addmod(add(w1, gamma), mulmod(beta, sigma1, p), p), p) + } + { + let w2 := mload(add(proof, 0x1e0)) + let sigma2 := mload(add(proof, 0x280)) + perm := mulmod(perm, addmod(add(w2, gamma), mulmod(beta, sigma2, p), p), p) + } + { + let w3 := mload(add(proof, 0x200)) + let sigma3 := mload(add(proof, 0x2a0)) + perm := mulmod(perm, addmod(add(w3, gamma), mulmod(beta, sigma3, p), p), p) + } + + // \prod_i=1..m-1 (w_i + beta * sigma_i + gamma) * (w_m + gamma) * z(xw) + { + let w4 := mload(add(proof, 0x220)) + let permNextEval := mload(add(proof, 0x2c0)) + perm := mulmod(perm, mulmod(addmod(w4, gamma, p), permNextEval, p), p) + } + + let alpha := mload(chal) + let alpha2 := mload(add(chal, 0x20)) + // PI - L1(x) * alpha^2 - alpha * \prod_i=1..m-1 (w_i + beta * sigma_i + gamma) * (w_m + + // gamma) * z(xw) + res := addmod(piEval, sub(p, mulmod(alpha2, lagrangeOneEval, p)), p) + res := addmod(res, sub(p, mulmod(alpha, perm, p)), p) + } + } + + /// @dev Compute components in [E]1 and [F]1 used for PolyComm opening verification + /// equivalent of JF's + /// https://github.com/EspressoSystems/jellyfish/blob/main/plonk/src/proof_system/verifier.rs#L154-L170 + /// caller allocates the memory fr commScalars and commBases + /// requires Arrays of size 30. + /// @param verifyingKey A verifier key + /// @param evalData A polynomial evaluation + /// @param proof A Plonk proof + /// @param chal A set of challenges + /// @param commScalars Common scalars + /// @param commBases Common bases + // The returned commitment is a generalization of + // `[F]1` described in Sec 8.4, step 10 of https://eprint.iacr.org/2019/953.pdf + // Returned evaluation is the scalar in `[E]1` described in Sec 8.4, step 11 of + // https://eprint.iacr.org/2019/953.pdf + function _prepareOpeningProof( + IPlonkVerifier.VerifyingKey memory verifyingKey, + Poly.EvalData memory evalData, + IPlonkVerifier.PlonkProof memory proof, + Challenges memory chal, + uint256[] memory commScalars, + BN254.G1Point[] memory commBases + ) internal pure returns (uint256 eval) { + // compute the constant term of the linearization polynomial + uint256 linPolyConstant = _computeLinPolyConstantTerm(chal, proof, evalData); + + _preparePolyCommitments(verifyingKey, chal, evalData, proof, commScalars, commBases); + + eval = _prepareEvaluations(linPolyConstant, proof, commScalars); + } + + /// @dev Similar to `aggregate_poly_commitments()` in Jellyfish, but we are not aggregating + /// multiple, + /// but rather preparing for `[F]1` from a single proof. + /// The caller allocates the memory fr commScalars and commBases. + /// Requires Arrays of size 30. + function _preparePolyCommitments( + IPlonkVerifier.VerifyingKey memory verifyingKey, + Challenges memory chal, + Poly.EvalData memory evalData, + IPlonkVerifier.PlonkProof memory proof, + uint256[] memory commScalars, + BN254.G1Point[] memory commBases + ) internal pure { + _linearizationScalarsAndBases(verifyingKey, chal, evalData, proof, commBases, commScalars); + + uint256 p = BN254.R_MOD; + uint256 v = chal.v; + uint256 vBase = v; + + // Add wire witness polynomial commitments. + commScalars[20] = vBase; + commBases[20] = proof.wire0; + assembly { + vBase := mulmod(vBase, v, p) + } + + commScalars[21] = vBase; + commBases[21] = proof.wire1; + assembly { + vBase := mulmod(vBase, v, p) + } + + commScalars[22] = vBase; + commBases[22] = proof.wire2; + assembly { + vBase := mulmod(vBase, v, p) + } + + commScalars[23] = vBase; + commBases[23] = proof.wire3; + assembly { + vBase := mulmod(vBase, v, p) + } + + commScalars[24] = vBase; + commBases[24] = proof.wire4; + assembly { + vBase := mulmod(vBase, v, p) + } + + // Add wire sigma polynomial commitments. The last sigma commitment is excluded. + commScalars[25] = vBase; + commBases[25] = verifyingKey.sigma0; + assembly { + vBase := mulmod(vBase, v, p) + } + + commScalars[26] = vBase; + commBases[26] = verifyingKey.sigma1; + assembly { + vBase := mulmod(vBase, v, p) + } + + commScalars[27] = vBase; + commBases[27] = verifyingKey.sigma2; + assembly { + vBase := mulmod(vBase, v, p) + } + + commScalars[28] = vBase; + commBases[28] = verifyingKey.sigma3; + assembly { + vBase := mulmod(vBase, v, p) + } + + // Add poly commitments to be evaluated at point `zeta * g`. + commScalars[29] = chal.u; + commBases[29] = proof.prodPerm; + } + + /// @dev `aggregate_evaluations()` in Jellyfish, but since we are not aggregating multiple, but + /// rather preparing `[E]1` from a single proof. + /// @dev caller allocates the memory fr commScalars + /// requires Arrays of size 30. + /// @param linPolyConstant A linear polynomial constant + /// @param proof A Plonk proof + /// @param commScalars An array of common scalars + /// The returned value is the scalar in `[E]1` described in Sec 8.4, step 11 of + /// https://eprint.iacr.org/2019/953.pdf + function _prepareEvaluations( + uint256 linPolyConstant, + IPlonkVerifier.PlonkProof memory proof, + uint256[] memory commScalars + ) internal pure returns (uint256 eval) { + uint256 p = BN254.R_MOD; + assembly { + eval := sub(p, linPolyConstant) + for { let i := 0 } lt(i, 10) { i := add(i, 1) } { + // the first u256 stores the length of this array; + // the next 20 elements are used to store the linearization of the scalars + // the first free space starts from 21 + let combiner := mload(add(commScalars, mul(add(i, 21), 0x20))) + let termEval := mload(add(proof, add(0x1a0, mul(i, 0x20)))) + eval := addmod(eval, mulmod(combiner, termEval, p), p) + } + } + } + + /// @dev Batchly verify multiple PCS opening proofs. + /// `open_key` has been assembled from BN254.P1(), BN254.P2() and contract variable _betaH + /// @param pcsInfos An array of PcsInfo + /// @dev Returns true if the entire batch verifiies and false otherwise. + function _batchVerifyOpeningProofs(PcsInfo[] memory pcsInfos) internal view returns (bool) { + uint256 pcsLen = pcsInfos.length; + uint256 p = BN254.R_MOD; + // Compute a pseudorandom challenge from the instances + uint256 r = 1; // for a single proof, no need to use `r` (`r=1` has no effect) + if (pcsLen > 1) { + Transcript.TranscriptData memory transcript; + for (uint256 i = 0; i < pcsLen; i++) { + transcript.appendChallenge(pcsInfos[i].u); + } + r = transcript.getAndAppendChallenge(); + } + + BN254.G1Point memory a1; + BN254.G1Point memory b1; + + // Compute A := A0 + r * A1 + ... + r^{m-1} * Am + { + uint256[] memory scalars = new uint256[](2 * pcsLen); + BN254.G1Point[] memory bases = new BN254.G1Point[](2 * pcsLen); + uint256 rBase = 1; + for (uint256 i = 0; i < pcsLen; i++) { + scalars[2 * i] = rBase; + bases[2 * i] = pcsInfos[i].openingProof; + + { + // slither-disable-next-line write-after-write + uint256 tmp; + uint256 u = pcsInfos[i].u; + assembly { + tmp := mulmod(rBase, u, p) + } + scalars[2 * i + 1] = tmp; + } + bases[2 * i + 1] = pcsInfos[i].shiftedOpeningProof; + + assembly { + rBase := mulmod(rBase, r, p) + } + } + a1 = BN254.multiScalarMul(bases, scalars); + } + + // Compute B := B0 + r * B1 + ... + r^{m-1} * Bm + { + uint256[] memory scalars; + BN254.G1Point[] memory bases; + { + // variable scoping to avoid "Stack too deep" + uint256 scalarsLenPerInfo = pcsInfos[0].commScalars.length; + uint256 totalScalarsLen = (2 + scalarsLenPerInfo) * pcsInfos.length + 1; + scalars = new uint256[](totalScalarsLen); + bases = new BN254.G1Point[](totalScalarsLen); + } + uint256 sumEvals = 0; + uint256 idx = 0; + uint256 rBase = 1; + for (uint256 i = 0; i < pcsInfos.length; i++) { + for (uint256 j = 0; j < pcsInfos[0].commScalars.length; j++) { + { + // scalars[idx] = (rBase * pcsInfos[i].commScalars[j]) % BN254.R_MOD; + uint256 s = pcsInfos[i].commScalars[j]; + uint256 tmp; + assembly { + // slither-disable-next-line variable-scope + tmp := mulmod(rBase, s, p) + } + scalars[idx] = tmp; + } + bases[idx] = pcsInfos[i].commBases[j]; + idx += 1; + } + + { + // scalars[idx] = (rBase * pcsInfos[i].evalPoint) % BN254.R_MOD; + uint256 evalPoint = pcsInfos[i].evalPoint; + uint256 tmp; + assembly { + // slither-disable-next-line variable-scope + tmp := mulmod(rBase, evalPoint, p) + } + scalars[idx] = tmp; + } + bases[idx] = pcsInfos[i].openingProof; + idx += 1; + + { + // scalars[idx] = (rBase * pcsInfos[i].u * pcsInfos[i].nextEvalPoint) % + // BN254.R_MOD; + uint256 u = pcsInfos[i].u; + uint256 nextEvalPoint = pcsInfos[i].nextEvalPoint; + uint256 tmp; + assembly { + // slither-disable-next-line variable-scope + tmp := mulmod(rBase, mulmod(u, nextEvalPoint, p), p) + } + scalars[idx] = tmp; + } + bases[idx] = pcsInfos[i].shiftedOpeningProof; + idx += 1; + + { + // sumEvals = (sumEvals + rBase * pcsInfos[i].eval) % BN254.R_MOD; + // rBase = (rBase * r) % BN254.R_MOD; + uint256 eval = pcsInfos[i].eval; + assembly { + sumEvals := addmod(sumEvals, mulmod(rBase, eval, p), p) + rBase := mulmod(rBase, r, p) + } + } + } + scalars[idx] = BN254.negate(sumEvals); + bases[idx] = BN254.P1(); + b1 = BN254.negate(BN254.multiScalarMul(bases, scalars)); + } + + // Check e(A, [x]2) ?= e(B, [1]2) + BN254.G2Point memory betaH = + BN254.G2Point({ x0: BETA_H_X0, x1: BETA_H_X1, y0: BETA_H_Y0, y1: BETA_H_Y1 }); + + return BN254.pairingProd2(a1, betaH, b1, BN254.P2()); + } + + /// @dev Compute the linearization of the scalars and bases. + /// The caller allocates the memory from commScalars and commBases. + /// Requires arrays of size 30. + /// @param verifyingKey The verifying key + /// @param challenge A set of challenges + /// @param evalData Polynomial evaluation data + /// @param proof A Plonk proof + /// @param bases An array of BN254 G1 points + /// @param scalars An array of scalars + function _linearizationScalarsAndBases( + IPlonkVerifier.VerifyingKey memory verifyingKey, + Challenges memory challenge, + Poly.EvalData memory evalData, + IPlonkVerifier.PlonkProof memory proof, + BN254.G1Point[] memory bases, + uint256[] memory scalars + ) internal pure { + uint256 firstScalar; + uint256 secondScalar; + uint256 rhs; + uint256 tmp; + uint256 tmp2; + uint256 p = BN254.R_MOD; + + // ============================================ + // Compute coefficient for the permutation product polynomial commitment. + // firstScalar = + // L1(zeta) * alpha^2 + // + alpha + // * (beta * zeta + wireEval0 + gamma) + // * (beta * k1 * zeta + wireEval1 + gamma) + // * (beta * k2 * zeta + wireEval2 + gamma) + // * ... + // where wireEval0, wireEval1, wireEval2, ... are in w_evals + // ============================================ + // first base and scala: + // - proof.prodPerm + // - firstScalar + assembly { + // firstScalar = alpha^2 * L1(zeta) + firstScalar := mulmod(mload(add(challenge, 0x20)), mload(add(evalData, 0x20)), p) + + // rhs = alpha + rhs := mload(challenge) + + // tmp = beta * zeta + tmp := mulmod(mload(add(challenge, 0x60)), mload(add(challenge, 0xA0)), p) + + // ================================= + // k0 (which is 1) component + // (beta * zeta + wireEval0 + gamma) + // ================================= + tmp2 := addmod(tmp, mload(add(proof, 0x1A0)), p) + tmp2 := addmod(tmp2, mload(add(challenge, 0x80)), p) + + rhs := mulmod(tmp2, rhs, p) + + // ================================= + // k1 component + // (beta * zeta * k1 + wireEval1 + gamma) + // ================================= + tmp2 := mulmod(tmp, COSET_K1, p) + tmp2 := addmod(tmp2, mload(add(proof, 0x1C0)), p) + tmp2 := addmod(tmp2, mload(add(challenge, 0x80)), p) + + rhs := mulmod(tmp2, rhs, p) + + // ================================= + // k2 component + // (beta * zeta * k2 + wireEval2 + gamma) + // ================================= + tmp2 := mulmod(tmp, COSET_K2, p) + tmp2 := addmod(tmp2, mload(add(proof, 0x1E0)), p) + tmp2 := addmod(tmp2, mload(add(challenge, 0x80)), p) + rhs := mulmod(tmp2, rhs, p) + + // ================================= + // k3 component + // (beta * zeta * k3 + wireEval3 + gamma) + // ================================= + tmp2 := mulmod(tmp, COSET_K3, p) + tmp2 := addmod(tmp2, mload(add(proof, 0x200)), p) + tmp2 := addmod(tmp2, mload(add(challenge, 0x80)), p) + rhs := mulmod(tmp2, rhs, p) + + // ================================= + // k4 component + // (beta * zeta * k4 + wireEval4 + gamma) + // ================================= + tmp2 := mulmod(tmp, COSET_K4, p) + tmp2 := addmod(tmp2, mload(add(proof, 0x220)), p) + tmp2 := addmod(tmp2, mload(add(challenge, 0x80)), p) + rhs := mulmod(tmp2, rhs, p) + + firstScalar := addmod(firstScalar, rhs, p) + } + bases[0] = proof.prodPerm; + scalars[0] = firstScalar; + + // ============================================ + // Compute coefficient for the last wire sigma polynomial commitment. + // secondScalar = alpha * beta * z_w * [s_sigma_3]_1 + // * (wireEval0 + gamma + beta * sigmaEval0) + // * (wireEval1 + gamma + beta * sigmaEval1) + // * ... + // ============================================ + // second base and scala: + // - verifyingKey.sigma4 + // - secondScalar + assembly { + // secondScalar = alpha * beta * z_w + secondScalar := mulmod(mload(challenge), mload(add(challenge, 0x60)), p) + secondScalar := mulmod(secondScalar, mload(add(proof, 0x2C0)), p) + + // (wireEval0 + gamma + beta * sigmaEval0) + tmp := mulmod(mload(add(challenge, 0x60)), mload(add(proof, 0x240)), p) + tmp := addmod(tmp, mload(add(proof, 0x1A0)), p) + tmp := addmod(tmp, mload(add(challenge, 0x80)), p) + + secondScalar := mulmod(secondScalar, tmp, p) + + // (wireEval1 + gamma + beta * sigmaEval1) + tmp := mulmod(mload(add(challenge, 0x60)), mload(add(proof, 0x260)), p) + tmp := addmod(tmp, mload(add(proof, 0x1C0)), p) + tmp := addmod(tmp, mload(add(challenge, 0x80)), p) + + secondScalar := mulmod(secondScalar, tmp, p) + + // (wireEval2 + gamma + beta * sigmaEval2) + tmp := mulmod(mload(add(challenge, 0x60)), mload(add(proof, 0x280)), p) + tmp := addmod(tmp, mload(add(proof, 0x1E0)), p) + tmp := addmod(tmp, mload(add(challenge, 0x80)), p) + + secondScalar := mulmod(secondScalar, tmp, p) + + // (wireEval3 + gamma + beta * sigmaEval3) + tmp := mulmod(mload(add(challenge, 0x60)), mload(add(proof, 0x2A0)), p) + tmp := addmod(tmp, mload(add(proof, 0x200)), p) + tmp := addmod(tmp, mload(add(challenge, 0x80)), p) + + secondScalar := mulmod(secondScalar, tmp, p) + } + bases[1] = verifyingKey.sigma4; + scalars[1] = p - secondScalar; + + // ============================================ + // next 13 are for selectors: + // + // the selectors are organized as + // - q_lc + // - q_mul + // - q_hash + // - q_o + // - q_c + // - q_ecc + // ============================================ + + // ============ + // q_lc + // ============ + // q_1...q_4 + scalars[2] = proof.wireEval0; + scalars[3] = proof.wireEval1; + scalars[4] = proof.wireEval2; + scalars[5] = proof.wireEval3; + bases[2] = verifyingKey.q1; + bases[3] = verifyingKey.q2; + bases[4] = verifyingKey.q3; + bases[5] = verifyingKey.q4; + + // ============ + // q_M + // ============ + // q_M12 and q_M34 + // q_M12 = w_evals[0] * w_evals[1]; + assembly { + tmp := mulmod(mload(add(proof, 0x1A0)), mload(add(proof, 0x1C0)), p) + } + scalars[6] = tmp; + bases[6] = verifyingKey.qM12; + + assembly { + tmp := mulmod(mload(add(proof, 0x1E0)), mload(add(proof, 0x200)), p) + } + scalars[7] = tmp; + bases[7] = verifyingKey.qM34; + + // ============ + // q_H + // ============ + // w_evals[0].pow([5]); + assembly { + tmp := mload(add(proof, 0x1A0)) + tmp2 := mulmod(tmp, tmp, p) + tmp2 := mulmod(tmp2, tmp2, p) + tmp := mulmod(tmp, tmp2, p) + } + scalars[8] = tmp; + bases[8] = verifyingKey.qH1; + + // w_evals[1].pow([5]); + assembly { + tmp := mload(add(proof, 0x1C0)) + tmp2 := mulmod(tmp, tmp, p) + tmp2 := mulmod(tmp2, tmp2, p) + tmp := mulmod(tmp, tmp2, p) + } + scalars[9] = tmp; + bases[9] = verifyingKey.qH2; + + // w_evals[2].pow([5]); + assembly { + tmp := mload(add(proof, 0x1E0)) + tmp2 := mulmod(tmp, tmp, p) + tmp2 := mulmod(tmp2, tmp2, p) + tmp := mulmod(tmp, tmp2, p) + } + scalars[10] = tmp; + bases[10] = verifyingKey.qH3; + + // w_evals[3].pow([5]); + assembly { + tmp := mload(add(proof, 0x200)) + tmp2 := mulmod(tmp, tmp, p) + tmp2 := mulmod(tmp2, tmp2, p) + tmp := mulmod(tmp, tmp2, p) + } + scalars[11] = tmp; + bases[11] = verifyingKey.qH4; + + // ============ + // q_o and q_c + // ============ + // q_o + scalars[12] = p - proof.wireEval4; + bases[12] = verifyingKey.qO; + // q_c + scalars[13] = 1; + bases[13] = verifyingKey.qC; + + // ============ + // q_Ecc + // ============ + // q_Ecc = w_evals[0] * w_evals[1] * w_evals[2] * w_evals[3] * w_evals[4]; + assembly { + tmp := mulmod(mload(add(proof, 0x1A0)), mload(add(proof, 0x1C0)), p) + tmp := mulmod(tmp, mload(add(proof, 0x1E0)), p) + tmp := mulmod(tmp, mload(add(proof, 0x200)), p) + tmp := mulmod(tmp, mload(add(proof, 0x220)), p) + } + scalars[14] = tmp; + bases[14] = verifyingKey.qEcc; + + // ============================================ + // the last 5 are for splitting quotient commitments + // ============================================ + + // first one is 1-zeta^n + scalars[15] = p - evalData.vanishEval; + bases[15] = proof.split0; + assembly { + // tmp = zeta^{n+2} + tmp := addmod(mload(evalData), 1, p) + // todo: use pre-computed zeta^2 + tmp2 := mulmod(mload(add(challenge, 0xA0)), mload(add(challenge, 0xA0)), p) + tmp := mulmod(tmp, tmp2, p) + } + + // second one is (1-zeta^n) zeta^(n+2) + assembly { + tmp2 := mulmod(mload(add(scalars, mul(16, 0x20))), tmp, p) + } + scalars[16] = tmp2; + bases[16] = proof.split1; + + // third one is (1-zeta^n) zeta^2(n+2) + assembly { + tmp2 := mulmod(mload(add(scalars, mul(17, 0x20))), tmp, p) + } + scalars[17] = tmp2; + bases[17] = proof.split2; + + // forth one is (1-zeta^n) zeta^3(n+2) + assembly { + tmp2 := mulmod(mload(add(scalars, mul(18, 0x20))), tmp, p) + } + scalars[18] = tmp2; + bases[18] = proof.split3; + + // fifth one is (1-zeta^n) zeta^4(n+2) + assembly { + tmp2 := mulmod(mload(add(scalars, mul(19, 0x20))), tmp, p) + } + scalars[19] = tmp2; + bases[19] = proof.split4; + } +} diff --git a/contracts/src/libraries/PolynomialEval.sol b/contracts/src/libraries/PolynomialEval.sol new file mode 100644 index 0000000000..18b06d8f71 --- /dev/null +++ b/contracts/src/libraries/PolynomialEval.sol @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: Unlicensed + +pragma solidity ^0.8.0; + +import { BN254 } from "bn254/BN254.sol"; + +/* solhint-disable no-inline-assembly */ + +library PolynomialEval { + /// Unsupported polynomial degree, currently size must in 2^{14~17}. + error UnsupportedDegree(); + + /// @dev a Radix 2 Evaluation Domain + struct EvalDomain { + uint256 logSize; // log_2(self.size) + uint256 size; // Size of the domain as a field element + uint256 sizeInv; // Inverse of the size in the field + uint256 groupGen; // A generator of the subgroup + uint256 groupGenInv; // Inverse of the generator of the subgroup + } + + /// @dev stores vanishing poly, lagrange at 1, and Public input poly + struct EvalData { + uint256 vanishEval; + uint256 lagrangeOne; + uint256 piEval; + } + + /// @dev compute the EvalData for a given domain and a challenge zeta + function evalDataGen(EvalDomain memory self, uint256 zeta, uint256[] memory publicInput) + internal + view + returns (EvalData memory evalData) + { + evalData.vanishEval = evaluateVanishingPoly(self, zeta); + evalData.lagrangeOne = evaluateLagrangeOne(self, zeta, evalData.vanishEval); + evalData.piEval = evaluatePiPoly(self, publicInput, zeta, evalData.vanishEval); + } + + /// @dev Create a new Radix2EvalDomain with `domainSize` which should be power of 2. + /// @dev Will revert if domainSize is not among {2^14, 2^15, 2^16, 2^17} + function newEvalDomain(uint256 domainSize) internal pure returns (EvalDomain memory) { + if (domainSize == 16384) { + return EvalDomain( + 14, + domainSize, + 0x30638CE1A7661B6337A964756AA75257C6BF4778D89789AB819CE60C19B04001, + 0x2D965651CDD9E4811F4E51B80DDCA8A8B4A93EE17420AAE6ADAA01C2617C6E85, + 0x281C036F06E7E9E911680D42558E6E8CF40976B0677771C0F8EEE934641C8410 + ); + } else if (domainSize == 32768) { + return EvalDomain( + 15, + domainSize, + 0x3063edaa444bddc677fcd515f614555a777997e0a9287d1e62bf6dd004d82001, + 0x2d1ba66f5941dc91017171fa69ec2bd0022a2a2d4115a009a93458fd4e26ecfb, + 0x05d33766e4590b3722701b6f2fa43d0dc3f028424d384e68c92a742fb2dbc0b4 + ); + } else if (domainSize == 65536) { + return EvalDomain( + 16, + domainSize, + 0x30641e0e92bebef818268d663bcad6dbcfd6c0149170f6d7d350b1b1fa6c1001, + 0x00eeb2cb5981ed45649abebde081dcff16c8601de4347e7dd1628ba2daac43b7, + 0x0b5d56b77fe704e8e92338c0082f37e091126414c830e4c6922d5ac802d842d4 + ); + } else if (domainSize == 131072) { + return EvalDomain( + 17, + domainSize, + 0x30643640b9f82f90e83b698e5ea6179c7c05542e859533b48b9953a2f5360801, + 0x1bf82deba7d74902c3708cc6e70e61f30512eca95655210e276e5858ce8f58e5, + 0x244cf010c43ca87237d8b00bf9dd50c4c01c7f086bd4e8c920e75251d96f0d22 + ); + } else { + revert UnsupportedDegree(); + } + } + + // This evaluates the vanishing polynomial for this domain at zeta. + // For multiplicative subgroups, this polynomial is + // `z(X) = X^self.size - 1`. + function evaluateVanishingPoly(EvalDomain memory self, uint256 zeta) + internal + pure + returns (uint256 res) + { + uint256 p = BN254.R_MOD; + uint256 logSize = self.logSize; + + assembly { + switch zeta + case 0 { res := sub(p, 1) } + default { + res := zeta + for { let i := 0 } lt(i, logSize) { i := add(i, 1) } { res := mulmod(res, res, p) } + // since zeta != 0 we know that res is not 0 + // so we can safely do a subtraction + res := sub(res, 1) + } + } + } + + /// @dev Evaluate the lagrange polynomial at point `zeta` given the vanishing polynomial + /// evaluation `vanish_eval`. + function evaluateLagrangeOne(EvalDomain memory self, uint256 zeta, uint256 vanishEval) + internal + view + returns (uint256 res) + { + if (vanishEval == 0) { + return 0; + } + + uint256 p = BN254.R_MOD; + uint256 divisor; + uint256 vanishEvalMulSizeInv = self.sizeInv; + + // ========================= + // lagrange_1_eval = vanish_eval / self.size / (zeta - 1) + // ========================= + assembly { + vanishEvalMulSizeInv := mulmod(vanishEval, vanishEvalMulSizeInv, p) + + switch zeta + case 0 { divisor := sub(p, 1) } + default { divisor := sub(zeta, 1) } + } + divisor = BN254.invert(divisor); + assembly { + res := mulmod(vanishEvalMulSizeInv, divisor, p) + } + } + + /// @dev Evaluate public input polynomial at point `zeta`. + function evaluatePiPoly( + EvalDomain memory self, + uint256[] memory pi, + uint256 zeta, + uint256 vanishEval + ) internal view returns (uint256 res) { + if (vanishEval == 0) { + return 0; + } + + uint256 p = BN254.R_MOD; + uint256 length = pi.length; + uint256 ithLagrange; + uint256 ithDivisor; + uint256 tmp; + uint256 vanishEvalDivN = self.sizeInv; + uint256 divisorProd; + uint256[] memory localDomainElements = domainElements(self, length); + uint256[] memory divisors = new uint256[](length); + + assembly { + // vanish_eval_div_n = (zeta^n-1)/n + vanishEvalDivN := mulmod(vanishEvalDivN, vanishEval, p) + + // Now we need to compute + // \sum_{i=0..l} L_{i,H}(zeta) * pub_input[i] + // where + // - L_{i,H}(zeta) + // = Z_H(zeta) * v_i / (zeta - g^i) + // = vanish_eval_div_n * g^i / (zeta - g^i) + // - v_i = g^i / n + // + // we want to use batch inversion method where we compute + // + // divisorProd = 1 / \prod (zeta - g^i) + // + // and then each 1 / (zeta - g^i) can be computed via (length - 1) + // multiplications: + // + // 1 / (zeta - g^i) = divisorProd * \prod_{j!=i} (zeta - g^j) + // + // In total this takes n(n-1) multiplications and 1 inversion, + // instead of doing n inversions. + divisorProd := 1 + + for { let i := 0 } lt(i, length) { i := add(i, 1) } { + // tmp points to g^i + // first 32 bytes of reference is the length of an array + tmp := mload(add(add(localDomainElements, 0x20), mul(i, 0x20))) + // compute (zeta - g^i) + ithDivisor := addmod(sub(p, tmp), zeta, p) + // accumulate (zeta - g^i) to the divisorProd + divisorProd := mulmod(divisorProd, ithDivisor, p) + // store ithDivisor in the array + mstore(add(add(divisors, 0x20), mul(i, 0x20)), ithDivisor) + } + } + + // compute 1 / \prod_{i=0}^length (zeta - g^i) + divisorProd = BN254.invert(divisorProd); + + assembly { + for { let i := 0 } lt(i, length) { i := add(i, 1) } { + // tmp points to g^i + // first 32 bytes of reference is the length of an array + tmp := mload(add(add(localDomainElements, 0x20), mul(i, 0x20))) + // vanish_eval_div_n * g^i + ithLagrange := mulmod(vanishEvalDivN, tmp, p) + + // now we compute vanish_eval_div_n * g^i / (zeta - g^i) via + // vanish_eval_div_n * g^i * divisorProd * \prod_{j!=i} (zeta - g^j) + ithLagrange := mulmod(ithLagrange, divisorProd, p) + for { let j := 0 } lt(j, length) { j := add(j, 1) } { + if iszero(eq(i, j)) { + ithDivisor := mload(add(add(divisors, 0x20), mul(j, 0x20))) + ithLagrange := mulmod(ithLagrange, ithDivisor, p) + } + } + + // multiply by pub_input[i] and update res + // tmp points to public input + tmp := mload(add(add(pi, 0x20), mul(i, 0x20))) + ithLagrange := mulmod(ithLagrange, tmp, p) + res := addmod(res, ithLagrange, p) + } + } + } + + /// @dev Generate the domain elements for indexes 0..length + /// which are essentially g^0, g^1, ..., g^{length-1} + function domainElements(EvalDomain memory self, uint256 length) + internal + pure + returns (uint256[] memory elements) + { + uint256 groupGen = self.groupGen; + uint256 tmp = 1; + uint256 p = BN254.R_MOD; + elements = new uint256[](length); + assembly { + if not(iszero(length)) { + let ptr := add(elements, 0x20) + let end := add(ptr, mul(0x20, length)) + mstore(ptr, 1) + ptr := add(ptr, 0x20) + // for (; ptr < end; ptr += 32) loop through the memory of `elements` + for { } lt(ptr, end) { ptr := add(ptr, 0x20) } { + tmp := mulmod(tmp, groupGen, p) + mstore(ptr, tmp) + } + } + } + } +} diff --git a/contracts/src/libraries/Transcript.sol b/contracts/src/libraries/Transcript.sol new file mode 100644 index 0000000000..5fdbb7c9fd --- /dev/null +++ b/contracts/src/libraries/Transcript.sol @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: Unlicensed + +pragma solidity ^0.8.0; + +import { BN254, Utils } from "bn254/BN254.sol"; +import { BytesLib } from "solidity-bytes-utils/BytesLib.sol"; +import { IPlonkVerifier } from "../interfaces/IPlonkVerifier.sol"; + +library Transcript { + struct TranscriptData { + bytes transcript; + bytes32[2] state; + } + + // ================================ + // Primitive functions + // ================================ + function appendMessage(TranscriptData memory self, bytes memory message) internal pure { + self.transcript = abi.encodePacked(self.transcript, message); + } + + function appendFieldElement(TranscriptData memory self, uint256 fieldElement) internal pure { + appendMessage(self, abi.encodePacked(Utils.reverseEndianness(fieldElement))); + } + + function appendGroupElement(TranscriptData memory self, BN254.G1Point memory comm) + internal + pure + { + bytes memory commBytes = BN254.g1Serialize(comm); + appendMessage(self, commBytes); + } + + // ================================ + // Transcript APIs + // ================================ + function appendChallenge(TranscriptData memory self, uint256 challenge) internal pure { + appendFieldElement(self, challenge); + } + + function appendCommitments(TranscriptData memory self, BN254.G1Point[] memory comms) + internal + pure + { + for (uint256 i = 0; i < comms.length; i++) { + appendCommitment(self, comms[i]); + } + } + + function appendCommitment(TranscriptData memory self, BN254.G1Point memory comm) + internal + pure + { + appendGroupElement(self, comm); + } + + function getAndAppendChallenge(TranscriptData memory self) internal pure returns (uint256) { + bytes32 h1 = + keccak256(abi.encodePacked(self.state[0], self.state[1], self.transcript, uint8(0))); + bytes32 h2 = + keccak256(abi.encodePacked(self.state[0], self.state[1], self.transcript, uint8(1))); + + self.state[0] = h1; + self.state[1] = h2; + + return BN254.fromLeBytesModOrder(BytesLib.slice(abi.encodePacked(h1, h2), 0, 48)); + } + + /// @dev Append the verifying key and the public inputs to the transcript. + /// @param verifyingKey verifiying key + /// @param publicInput a list of field elements + function appendVkAndPubInput( + TranscriptData memory self, + IPlonkVerifier.VerifyingKey memory verifyingKey, + uint256[] memory publicInput + ) internal pure { + uint64 sizeInBits = 254; + + // Fr field size in bits + appendMessage( + self, BytesLib.slice(abi.encodePacked(Utils.reverseEndianness(sizeInBits)), 0, 8) + ); + + // domain size + appendMessage( + self, + BytesLib.slice(abi.encodePacked(Utils.reverseEndianness(verifyingKey.domainSize)), 0, 8) + ); + + // number of inputs + appendMessage( + self, + BytesLib.slice(abi.encodePacked(Utils.reverseEndianness(verifyingKey.numInputs)), 0, 8) + ); + + // ===================== + // k: coset representatives + // ===================== + // Currently, K is hardcoded, and there are 5 of them since + // # wire types == 5 + appendFieldElement(self, 0x1); // k0 = 1 + appendFieldElement(self, 0x2f8dd1f1a7583c42c4e12a44e110404c73ca6c94813f85835da4fb7bb1301d4a); // k1 + appendFieldElement(self, 0x1ee678a0470a75a6eaa8fe837060498ba828a3703b311d0f77f010424afeb025); // k2 + appendFieldElement(self, 0x2042a587a90c187b0a087c03e29c968b950b1db26d5c82d666905a6895790c0a); // k3 + appendFieldElement(self, 0x2e2b91456103698adf57b799969dea1c8f739da5d8d40dd3eb9222db7c81e881); // k4 + + // selectors + appendGroupElement(self, verifyingKey.q1); + appendGroupElement(self, verifyingKey.q2); + appendGroupElement(self, verifyingKey.q3); + appendGroupElement(self, verifyingKey.q4); + appendGroupElement(self, verifyingKey.qM12); + appendGroupElement(self, verifyingKey.qM34); + appendGroupElement(self, verifyingKey.qH1); + appendGroupElement(self, verifyingKey.qH2); + appendGroupElement(self, verifyingKey.qH3); + appendGroupElement(self, verifyingKey.qH4); + appendGroupElement(self, verifyingKey.qO); + appendGroupElement(self, verifyingKey.qC); + appendGroupElement(self, verifyingKey.qEcc); + + // sigmas + appendGroupElement(self, verifyingKey.sigma0); + appendGroupElement(self, verifyingKey.sigma1); + appendGroupElement(self, verifyingKey.sigma2); + appendGroupElement(self, verifyingKey.sigma3); + appendGroupElement(self, verifyingKey.sigma4); + + // public inputs + for (uint256 i = 0; i < publicInput.length; i++) { + appendFieldElement(self, publicInput[i]); + } + } + + /// @dev Append the proof to the transcript. + function appendProofEvaluations( + TranscriptData memory self, + IPlonkVerifier.PlonkProof memory proof + ) internal pure { + appendFieldElement(self, proof.wireEval0); + appendFieldElement(self, proof.wireEval1); + appendFieldElement(self, proof.wireEval2); + appendFieldElement(self, proof.wireEval3); + appendFieldElement(self, proof.wireEval4); + + appendFieldElement(self, proof.sigmaEval0); + appendFieldElement(self, proof.sigmaEval1); + appendFieldElement(self, proof.sigmaEval2); + appendFieldElement(self, proof.sigmaEval3); + + appendFieldElement(self, proof.prodPermZetaOmegaEval); + } +} diff --git a/flake.nix b/flake.nix index bc45b00297..6899a1b8cc 100644 --- a/flake.nix +++ b/flake.nix @@ -40,20 +40,22 @@ # node=error: disable noisy anvil output RUST_LOG = "info,libp2p=off,isahc=error,surf=error,node=error"; RUST_BACKTRACE = 1; - RUSTFLAGS = " --cfg async_executor_impl=\"async-std\" --cfg async_channel_impl=\"async-std\""; - - solhintPkg = { buildNpmPackage, fetchFromGitHub }: buildNpmPackage rec { - pname = "solhint"; - version = "3.4.1"; - src = fetchFromGitHub { - owner = "protofire"; - repo = pname; - rev = "v${version}"; - hash = "sha256-cOZgphyNbTBWnnomOoQj9Ferss6/109EGkzVZY1eqrg="; + RUSTFLAGS = + " --cfg async_executor_impl=\"async-std\" --cfg async_channel_impl=\"async-std\""; + + solhintPkg = { buildNpmPackage, fetchFromGitHub }: + buildNpmPackage rec { + pname = "solhint"; + version = "3.6.2"; + src = fetchFromGitHub { + owner = "protofire"; + repo = pname; + rev = "v${version}"; + hash = "sha256-i2W+2My4DixRY+uOGi1iSdLLNLsdzdGRrPibQTPxtr8="; + }; + npmDepsHash = "sha256-4icK1K8o9OfFWs4fnQGOgGt6tI4By0EWPQ3YerUDYU8="; + dontNpmBuild = true; }; - npmDepsHash = "sha256-s037N+fma4aLTrEhRb64UGr7uItP7v0s1gQ9X7fra00="; - dontNpmBuild = true; - }; overlays = [ (import rust-overlay) diff --git a/justfile b/justfile index fc48cad965..d6b600f1b2 100644 --- a/justfile +++ b/justfile @@ -61,3 +61,8 @@ gen-bindings: mv ./contracts/out/bindings ./contract-bindings cargo fmt --all cargo sort -g -w + +# Lint solidity files +sol-lint: + forge fmt + solhint --fix 'contracts/{script,src,test}/**/*.sol' From 66966f28dbf45dfcc6a768be0aa5b821fa822e94 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 27 Oct 2023 00:18:53 +0800 Subject: [PATCH 02/38] fix: flake.nix for solhint dep --- flake.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index 6899a1b8cc..29d4c53484 100644 --- a/flake.nix +++ b/flake.nix @@ -50,10 +50,10 @@ src = fetchFromGitHub { owner = "protofire"; repo = pname; - rev = "v${version}"; - hash = "sha256-i2W+2My4DixRY+uOGi1iSdLLNLsdzdGRrPibQTPxtr8="; + rev = "refs/tags/${version}"; + hash = "sha256-VI6J2iSgimcT9TWPlPD6aIDfRFmlQafCc/J4dwF9rMs="; }; - npmDepsHash = "sha256-4icK1K8o9OfFWs4fnQGOgGt6tI4By0EWPQ3YerUDYU8="; + npmDepsHash = "sha256-lSe3Rt3I2yFy9Je3SLD2QJA/608ppvbLWmwDt6vkDIk="; dontNpmBuild = true; }; From 1e09fb3a2c7136ccbb900a7ecff7bc86082cb19d Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 27 Oct 2023 23:20:24 +0800 Subject: [PATCH 03/38] add ffi & fuzz test example for polyeval --- Cargo.lock | 2 ++ contracts/rust/Cargo.toml | 10 ++++-- contracts/rust/src/bin/diff_test.rs | 54 +++++++++++++++++++++++++++++ contracts/test/PolynomialEval.t.sol | 46 ++++++++++++++++++++++++ foundry.toml | 1 + 5 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 contracts/rust/src/bin/diff_test.rs create mode 100644 contracts/test/PolynomialEval.t.sol diff --git a/Cargo.lock b/Cargo.lock index cdbe9fb20a..c5e11b7972 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3729,10 +3729,12 @@ dependencies = [ "ark-bn254", "ark-ec 0.4.2", "ark-ff 0.4.2", + "ark-poly", "ark-serialize 0.4.2", "ark-std 0.4.0", "async-compatibility-layer", "async-std", + "clap", "contract-bindings", "digest 0.10.7", "ethers", diff --git a/contracts/rust/Cargo.toml b/contracts/rust/Cargo.toml index 548f8ed961..ceccbe213e 100644 --- a/contracts/rust/Cargo.toml +++ b/contracts/rust/Cargo.toml @@ -8,17 +8,19 @@ edition = "2021" [dependencies] anyhow = "1.0.71" ark-bn254 = "0.4.0" -ark-ec = { version = "0.4.2" } +ark-ec = "0.4.2" ark-ff = "0.4.2" +ark-poly = "0.4.2" ark-serialize = "0.4.2" ark-std = { version = "0.4.0", default-features = false } async-compatibility-layer = { git = "https://github.com/EspressoSystems/async-compatibility-layer", tag = "1.4.1", features = [ "logging-utils", ] } async-std = "1.12.0" +clap = { version = "^4.4", features = ["derive"] } contract-bindings = { path = "../../contract-bindings" } digest = { version = "0.10", default-features = false, features = ["alloc"] } -ethers = { version = "2.0.4", features = ["abigen"] } +ethers = { version = "2.0.4" } ethers-providers = "2.0.4" ethers-solc = "2.0.4" hex = "0.4.3" @@ -32,3 +34,7 @@ jf-primitives = { git = "https://github.com/EspressoSystems/jellyfish", features jf-utils = { git = "https://github.com/EspressoSystems/jellyfish", rev = "483fb97324d42724720f9155f200973a3b83a7b4" } sequencer-utils = { path = "../../utils" } sha3 = { version = "0.10.8", default-features = false } + +[[bin]] +name = "diff-test" +path = "src/bin/diff_test.rs" diff --git a/contracts/rust/src/bin/diff_test.rs b/contracts/rust/src/bin/diff_test.rs new file mode 100644 index 0000000000..d52b89f4ff --- /dev/null +++ b/contracts/rust/src/bin/diff_test.rs @@ -0,0 +1,54 @@ +use anyhow::{anyhow, Result}; +use ark_bn254::Fr; +use ark_ff::{BigInteger, PrimeField}; +use ark_poly::domain::radix2::Radix2EvaluationDomain; +use ark_poly::EvaluationDomain; +use clap::{Parser, ValueEnum}; +use ethers::{abi::AbiEncode, types::U256}; + +#[derive(Parser)] +#[command(author, version, about, long_about=None)] +struct Cli { + /// Identifier for the functions to invoke in Jellyfish + #[arg(value_enum)] + action: Action, + /// Optional 1st argument for the `action` + arg1: Option, + /// Optional 2nd argument for the `action` + arg2: Option, +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] +enum Action { + /// Getting ark_poly::Radix2EvaluationDomain::new() + NewPolyEvalDomain, +} + +fn main() -> Result<()> { + let cli = Cli::parse(); + + match cli.action { + Action::NewPolyEvalDomain => { + if let Some(arg1) = cli.arg1.as_ref() { + let log_size = arg1.parse::()?; + let domain = + Radix2EvaluationDomain::::new(2u32.pow(log_size) as usize).unwrap(); + let res = ( + field_to_u256(domain.size_inv)?, + field_to_u256(domain.group_gen)?, + field_to_u256(domain.group_gen_inv)?, + ); + println!("{}", res.encode_hex()); + } + } + }; + + Ok(()) +} + +fn field_to_u256(f: F) -> Result { + if F::MODULUS_BIT_SIZE > 256 { + return Err(anyhow!("Shouldn't convert a > 256-bit field to U256")); + } + Ok(U256::from_little_endian(&f.into_bigint().to_bytes_le())) +} diff --git a/contracts/test/PolynomialEval.t.sol b/contracts/test/PolynomialEval.t.sol new file mode 100644 index 0000000000..c49a10b2c8 --- /dev/null +++ b/contracts/test/PolynomialEval.t.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: Unlicensed + +/* solhint-disable contract-name-camelcase, func-name-mixedcase */ + +pragma solidity ^0.8.0; + +// Libraries +import "forge-std/Test.sol"; + +// Target contract +import { PolynomialEval as Poly } from "../src/libraries/PolynomialEval.sol"; + +contract PolynomialEval_newEvalDomain_Test is Test { + /// @dev diff-test with Rust when `domainSize` is in {2^14, 2^15, 2^16, 2^17} + function test_supportedDomainSize_matches() external { + for (uint256 logSize = 14; logSize < 18; logSize++) { + string[] memory cmds = new string[](6); + cmds[0] = "cargo"; + cmds[1] = "run"; + cmds[2] = "--bin"; + cmds[3] = "diff-test"; + cmds[4] = "new-poly-eval-domain"; + cmds[5] = vm.toString(logSize); + + bytes memory result = vm.ffi(cmds); + (uint256 sizeInv, uint256 groupGen, uint256 groupGenInv) = + abi.decode(result, (uint256, uint256, uint256)); + + Poly.EvalDomain memory domain = Poly.newEvalDomain(2 ** logSize); + assertEq(sizeInv, domain.sizeInv); + assertEq(groupGen, domain.groupGen); + assertEq(groupGenInv, domain.groupGenInv); + } + } + + /// @dev Test revert if domainSize is not among {2^14, 2^15, 2^16, 2^17} + function testFuzz_unsupportedDomainSize_reverts(uint256 domainSize) external { + vm.assume( + domainSize != 2 ** 14 && domainSize != 2 ** 15 && domainSize != 2 ** 16 + && domainSize != 2 ** 17 + ); + + vm.expectRevert(Poly.UnsupportedDegree.selector); + Poly.newEvalDomain(domainSize); + } +} diff --git a/foundry.toml b/foundry.toml index 20690cb1e2..80c75555c9 100644 --- a/foundry.toml +++ b/foundry.toml @@ -12,6 +12,7 @@ cache_path = "contracts/cache" # Version should match the solc installed via flake, otherwise the contract # artifacts may differ slightly. solc = "0.8.20" +ffi = true # See more config options https://github.com/foundry-rs/foundry/tree/master/config From 45464366eb1878ec68501602bcfef6b8624da211 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Tue, 31 Oct 2023 11:28:47 +0800 Subject: [PATCH 04/38] wip: test evalDataGen --- contract-bindings/src/plonk_verifier.rs | 44 +++++++- contract-bindings/src/polynomial_eval.rs | 124 +++++++++++++++++++-- contracts/rust/src/bin/diff_test.rs | 80 +++++++++---- contracts/src/libraries/PolynomialEval.sol | 25 +++-- contracts/test/PolynomialEval.t.sol | 62 +++++++++++ 5 files changed, 293 insertions(+), 42 deletions(-) diff --git a/contract-bindings/src/plonk_verifier.rs b/contract-bindings/src/plonk_verifier.rs index 367d512daa..4ab0ab6cd9 100644 --- a/contract-bindings/src/plonk_verifier.rs +++ b/contract-bindings/src/plonk_verifier.rs @@ -231,6 +231,13 @@ pub mod plonk_verifier { inputs: ::std::vec![], },], ), + ( + ::std::borrow::ToOwned::to_owned("InvalidPolyEvalArgs"), + ::std::vec![::ethers::core::abi::ethabi::AbiError { + name: ::std::borrow::ToOwned::to_owned("InvalidPolyEvalArgs",), + inputs: ::std::vec![], + },], + ), ( ::std::borrow::ToOwned::to_owned("UnsupportedDegree"), ::std::vec![::ethers::core::abi::ethabi::AbiError { @@ -254,12 +261,12 @@ pub mod plonk_verifier { pub static PLONKVERIFIER_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); #[rustfmt::skip] - const __BYTECODE: &[u8] = b"a94a\0:`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14a\0-WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\x046\x10a\x005W`\x005`\xE0\x1C\x80c6\xD8\xD6\xEB\x14a\0:W[`\0\x80\xFD[a\0Ma\0H6`\x04a5\x1DV[a\0aV[`@Q\x90\x15\x15\x81R` \x01`@Q\x80\x91\x03\x90\xF3[`\0\x82Q\x85Q\x14\x15\x80a\0vWP\x82Q\x84Q\x14\x15[\x80a\0\x83WP\x82Q\x82Q\x14\x15[\x80a\0\x8DWP\x82Q\x15[\x15a\0\xABW`@Qc\xFD\x9A-\x1B`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0\x83Q`\x01`\x01`@\x1B\x03\x81\x11\x15a\0\xC6Wa\0\xC6a0XV[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\0\xFFW\x81` \x01[a\0\xECa/jV[\x81R` \x01\x90`\x01\x90\x03\x90\x81a\0\xE4W\x90P[P\x90P`\0[\x84Q\x81\x10\x15a\x02CWa\x010\x85\x82\x81Q\x81\x10a\x01#Wa\x01#a7\x9FV[` \x02` \x01\x01Qa\x02YV[`\0[\x86\x82\x81Q\x81\x10a\x01EWa\x01Ea7\x9FV[` \x02` \x01\x01QQ\x81\x10\x15a\x01\xA2Wa\x01\x90\x87\x83\x81Q\x81\x10a\x01jWa\x01ja7\x9FV[` \x02` \x01\x01Q\x82\x81Q\x81\x10a\x01\x83Wa\x01\x83a7\x9FV[` \x02` \x01\x01Qa\x03\x86V[\x80a\x01\x9A\x81a7\xCBV[\x91PPa\x013V[Pa\x02\x13\x87\x82\x81Q\x81\x10a\x01\xB8Wa\x01\xB8a7\x9FV[` \x02` \x01\x01Q\x87\x83\x81Q\x81\x10a\x01\xD2Wa\x01\xD2a7\x9FV[` \x02` \x01\x01Q\x87\x84\x81Q\x81\x10a\x01\xECWa\x01\xECa7\x9FV[` \x02` \x01\x01Q\x87\x85\x81Q\x81\x10a\x02\x06Wa\x02\x06a7\x9FV[` \x02` \x01\x01Qa\x03\xEDV[\x82\x82\x81Q\x81\x10a\x02%Wa\x02%a7\x9FV[` \x02` \x01\x01\x81\x90RP\x80\x80a\x02;\x90a7\xCBV[\x91PPa\x01\x05V[Pa\x02M\x81a\x05EV[\x91PP[\x94\x93PPPPV[\x80Qa\x02d\x90a\x0C\xE8V[a\x02q\x81` \x01Qa\x0C\xE8V[a\x02~\x81`@\x01Qa\x0C\xE8V[a\x02\x8B\x81``\x01Qa\x0C\xE8V[a\x02\x98\x81`\x80\x01Qa\x0C\xE8V[a\x02\xA5\x81`\xA0\x01Qa\x0C\xE8V[a\x02\xB2\x81`\xC0\x01Qa\x0C\xE8V[a\x02\xBF\x81`\xE0\x01Qa\x0C\xE8V[a\x02\xCD\x81a\x01\0\x01Qa\x0C\xE8V[a\x02\xDB\x81a\x01 \x01Qa\x0C\xE8V[a\x02\xE9\x81a\x01@\x01Qa\x0C\xE8V[a\x02\xF7\x81a\x01`\x01Qa\x0C\xE8V[a\x03\x05\x81a\x01\xA0\x01Qa\x03\x86V[a\x03\x13\x81a\x01\xC0\x01Qa\x03\x86V[a\x03!\x81a\x01\xE0\x01Qa\x03\x86V[a\x03/\x81a\x02\0\x01Qa\x03\x86V[a\x03=\x81a\x02 \x01Qa\x03\x86V[a\x03K\x81a\x02@\x01Qa\x03\x86V[a\x03Y\x81a\x02`\x01Qa\x03\x86V[a\x03g\x81a\x02\x80\x01Qa\x03\x86V[a\x03u\x81a\x02\xA0\x01Qa\x03\x86V[a\x03\x83\x81a\x02\xC0\x01Qa\x03\x86V[PV[`\0\x80Q` a8\xDF\x839\x81Q\x91R\x81\x10\x80a\x03\xE9W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FBn254: invalid scalar field\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[PPV[a\x03\xF5a/jV[\x84` \x01Q\x84Q\x14a\x04\x1AW`@Qc \xFA\x9D\x89`\xE1\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0a\x04(\x86\x86\x86\x86a\rwV[\x90P`\0a\x049\x87`\0\x01Qa\x0FEV[\x90P`\0a\x04L\x82\x84`\xA0\x01Q\x89a\x11\xE1V[`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x91\x92P`\0\x91\x90` \x82\x01a\x03\xC0\x806\x837PP`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x92\x93P`\0\x92\x91P` \x82\x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x04\x8FW\x90PP\x90P`\0a\x04\xC8\x8B\x85\x8B\x89\x87\x87a\x12AV[`\xA0\x87\x01Q``\x87\x01Q\x91\x92P\x90`\0\x80Q` a8\xDF\x839\x81Q\x91R`\0\x81\x83\x85\t`@\x80Qa\x01\0\x81\x01\x82R`\xE0\x9C\x8D\x01Q\x81R` \x81\x01\x96\x90\x96R\x85\x01RPPP``\x81\x01\x91\x90\x91R`\x80\x81\x01\x92\x90\x92R`\xA0\x82\x01Ra\x01`\x87\x01Q`\xC0\x82\x01Ra\x01\x80\x90\x96\x01Q\x92\x86\x01\x92\x90\x92RP\x92\x95\x94PPPPPV[\x80Q`\0\x90`\0\x80Q` a8\xDF\x839\x81Q\x91R`\x01\x80\x83\x11\x15a\x05\xC6Wa\x05ka/\xE4V[`\0[\x84\x81\x10\x15a\x05\xB8Wa\x05\xA6\x87\x82\x81Q\x81\x10a\x05\x8BWa\x05\x8Ba7\x9FV[` \x02` \x01\x01Q`\0\x01Q\x83a\x12j\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x80a\x05\xB0\x81a7\xCBV[\x91PPa\x05nV[Pa\x05\xC2\x81a\x12tV[\x91PP[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`\0a\x05\xFB\x86`\x02a7\xE4V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06\x12Wa\x06\x12a0XV[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06;W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P`\0a\x06K\x87`\x02a7\xE4V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06bWa\x06ba0XV[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06\xA7W\x81` \x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x06\x80W\x90P[P\x90P`\x01`\0[\x88\x81\x10\x15a\x07\xF0W\x81\x84a\x06\xC4\x83`\x02a7\xE4V[\x81Q\x81\x10a\x06\xD4Wa\x06\xD4a7\x9FV[` \x02` \x01\x01\x81\x81RPP\x8A\x81\x81Q\x81\x10a\x06\xF2Wa\x06\xF2a7\x9FV[` \x02` \x01\x01Q`\xC0\x01Q\x83\x82`\x02a\x07\x0C\x91\x90a7\xE4V[\x81Q\x81\x10a\x07\x1CWa\x07\x1Ca7\x9FV[` \x02` \x01\x01\x81\x90RP`\0\x80\x8C\x83\x81Q\x81\x10a\x07\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x05`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\x0F\x84\x84a\x1ANV[\x80\x82Ra\x12\x1F\x90\x85\x90\x85\x90a\x1A\xA2V[` \x82\x01R\x80Qa\x125\x90\x85\x90\x84\x90\x86\x90a\x1B\x08V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12O\x85\x87\x89a\x1C^V[\x90Pa\x12_\x88\x86\x89\x89\x88\x88a\x1DJV[a\x0C\xDC\x81\x87\x86a VV[a\x03\xE9\x82\x82a \xA6V[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x12\x9C\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a8>V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x12\xCDWa\x12\xCDa7\x9FV[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x12\xE9Wa\x12\xE9a7\x9FV[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x08\x94\x93\x92\x91\x90a8>V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x138Wa\x138a7\x9FV[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13YWa\x13Ya7\x9FV[` \x02\x01\x81\x81RPPa\x02Qa\x13\x9C\x83\x83`@Q` \x01a\x13\x84\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a \xD9V[a!\xE6V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14D\x83`\0\x81Q\x81\x10a\x14\x1CWa\x14\x1Ca7\x9FV[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x147Wa\x147a7\x9FV[` \x02` \x01\x01Qa\"fV[\x90P`\x01[\x82Q\x81\x10\x15a\x14\x9EWa\x14\x8A\x82a\x14\x85\x86\x84\x81Q\x81\x10a\x14kWa\x14ka7\x9FV[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x147Wa\x147a7\x9FV[a#\nV[\x91P\x80a\x14\x96\x81a7\xCBV[\x91PPa\x14IV[P\x92\x91PPV[`\0a\x14\xBF`\0\x80Q` a8\xDF\x839\x81Q\x91R\x83a8tV[a\x14\xD7\x90`\0\x80Q` a8\xDF\x839\x81Q\x91Ra8\x96V[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x05WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a8\xBF\x839\x81Q\x91R\x84` \x01Qa\x158\x91\x90a8tV[a\x15P\x90`\0\x80Q` a8\xBF\x839\x81Q\x91Ra8\x96V[\x90R\x92\x91PPV[a\x15\x83`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x16\xFFW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\x1F\x91\x90\x83\x90` \x01a8\xA9V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x17v\x84a\x17qa\x17G\x84a#\xB1V[`@Q` \x01a\x17Y\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a \xD9V[a\x17\x0BV[a\x17\x8A\x84a\x17qa\x17G\x86`\0\x01Qa#\xB1V[a\x17\x9E\x84a\x17qa\x17G\x86` \x01Qa#\xB1V[a\x17\xA9\x84`\x01a \xA6V[a\x17\xD3\x84\x7F/\x8D\xD1\xF1\xA7X\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x05`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\x0F\x84\x84a\x1ANV[\x80\x82Ra\x12\x1F\x90\x85\x90\x85\x90a\x1A\xA2V[` \x82\x01R\x80Qa\x125\x90\x85\x90\x84\x90\x86\x90a\x1B\x08V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12O\x85\x87\x89a\x1C^V[\x90Pa\x12_\x88\x86\x89\x89\x88\x88a\x1DJV[a\x0C\xDC\x81\x87\x86a VV[a\x03\xE9\x82\x82a \xA6V[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x12\x9C\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a8mV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x12\xCDWa\x12\xCDa7\xCEV[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x12\xE9Wa\x12\xE9a7\xCEV[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x08\x94\x93\x92\x91\x90a8mV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x138Wa\x138a7\xCEV[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13YWa\x13Ya7\xCEV[` \x02\x01\x81\x81RPPa\x02Qa\x13\x9C\x83\x83`@Q` \x01a\x13\x84\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a \xD9V[a!\xE6V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14D\x83`\0\x81Q\x81\x10a\x14\x1CWa\x14\x1Ca7\xCEV[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x147Wa\x147a7\xCEV[` \x02` \x01\x01Qa\"fV[\x90P`\x01[\x82Q\x81\x10\x15a\x14\x9EWa\x14\x8A\x82a\x14\x85\x86\x84\x81Q\x81\x10a\x14kWa\x14ka7\xCEV[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x147Wa\x147a7\xCEV[a#\nV[\x91P\x80a\x14\x96\x81a7\xFAV[\x91PPa\x14IV[P\x92\x91PPV[`\0a\x14\xBF`\0\x80Q` a9\x0E\x839\x81Q\x91R\x83a8\xA3V[a\x14\xD7\x90`\0\x80Q` a9\x0E\x839\x81Q\x91Ra8\xC5V[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x05WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a8\xEE\x839\x81Q\x91R\x84` \x01Qa\x158\x91\x90a8\xA3V[a\x15P\x90`\0\x80Q` a8\xEE\x839\x81Q\x91Ra8\xC5V[\x90R\x92\x91PPV[a\x15\x83`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x16\xFFW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\x1F\x91\x90\x83\x90` \x01a8\xD8V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x17v\x84a\x17qa\x17G\x84a#\xB1V[`@Q` \x01a\x17Y\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a \xD9V[a\x17\x0BV[a\x17\x8A\x84a\x17qa\x17G\x86`\0\x01Qa#\xB1V[a\x17\x9E\x84a\x17qa\x17G\x86` \x01Qa#\xB1V[a\x17\xA9\x84`\x01a \xA6V[a\x17\xD3\x84\x7F/\x8D\xD1\xF1\xA7X\"\x9E\xF0\xFE\xD6\xC9\xE1\xE0j\x7FD\0r\xA4\x82dsolcC\0\x08\x14\x003"; /// The bytecode of the contract. pub static PLONKVERIFIER_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static(__BYTECODE); #[rustfmt::skip] - const __DEPLOYED_BYTECODE: &[u8] = b"s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\x046\x10a\x005W`\x005`\xE0\x1C\x80c6\xD8\xD6\xEB\x14a\0:W[`\0\x80\xFD[a\0Ma\0H6`\x04a5\x1DV[a\0aV[`@Q\x90\x15\x15\x81R` \x01`@Q\x80\x91\x03\x90\xF3[`\0\x82Q\x85Q\x14\x15\x80a\0vWP\x82Q\x84Q\x14\x15[\x80a\0\x83WP\x82Q\x82Q\x14\x15[\x80a\0\x8DWP\x82Q\x15[\x15a\0\xABW`@Qc\xFD\x9A-\x1B`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0\x83Q`\x01`\x01`@\x1B\x03\x81\x11\x15a\0\xC6Wa\0\xC6a0XV[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\0\xFFW\x81` \x01[a\0\xECa/jV[\x81R` \x01\x90`\x01\x90\x03\x90\x81a\0\xE4W\x90P[P\x90P`\0[\x84Q\x81\x10\x15a\x02CWa\x010\x85\x82\x81Q\x81\x10a\x01#Wa\x01#a7\x9FV[` \x02` \x01\x01Qa\x02YV[`\0[\x86\x82\x81Q\x81\x10a\x01EWa\x01Ea7\x9FV[` \x02` \x01\x01QQ\x81\x10\x15a\x01\xA2Wa\x01\x90\x87\x83\x81Q\x81\x10a\x01jWa\x01ja7\x9FV[` \x02` \x01\x01Q\x82\x81Q\x81\x10a\x01\x83Wa\x01\x83a7\x9FV[` \x02` \x01\x01Qa\x03\x86V[\x80a\x01\x9A\x81a7\xCBV[\x91PPa\x013V[Pa\x02\x13\x87\x82\x81Q\x81\x10a\x01\xB8Wa\x01\xB8a7\x9FV[` \x02` \x01\x01Q\x87\x83\x81Q\x81\x10a\x01\xD2Wa\x01\xD2a7\x9FV[` \x02` \x01\x01Q\x87\x84\x81Q\x81\x10a\x01\xECWa\x01\xECa7\x9FV[` \x02` \x01\x01Q\x87\x85\x81Q\x81\x10a\x02\x06Wa\x02\x06a7\x9FV[` \x02` \x01\x01Qa\x03\xEDV[\x82\x82\x81Q\x81\x10a\x02%Wa\x02%a7\x9FV[` \x02` \x01\x01\x81\x90RP\x80\x80a\x02;\x90a7\xCBV[\x91PPa\x01\x05V[Pa\x02M\x81a\x05EV[\x91PP[\x94\x93PPPPV[\x80Qa\x02d\x90a\x0C\xE8V[a\x02q\x81` \x01Qa\x0C\xE8V[a\x02~\x81`@\x01Qa\x0C\xE8V[a\x02\x8B\x81``\x01Qa\x0C\xE8V[a\x02\x98\x81`\x80\x01Qa\x0C\xE8V[a\x02\xA5\x81`\xA0\x01Qa\x0C\xE8V[a\x02\xB2\x81`\xC0\x01Qa\x0C\xE8V[a\x02\xBF\x81`\xE0\x01Qa\x0C\xE8V[a\x02\xCD\x81a\x01\0\x01Qa\x0C\xE8V[a\x02\xDB\x81a\x01 \x01Qa\x0C\xE8V[a\x02\xE9\x81a\x01@\x01Qa\x0C\xE8V[a\x02\xF7\x81a\x01`\x01Qa\x0C\xE8V[a\x03\x05\x81a\x01\xA0\x01Qa\x03\x86V[a\x03\x13\x81a\x01\xC0\x01Qa\x03\x86V[a\x03!\x81a\x01\xE0\x01Qa\x03\x86V[a\x03/\x81a\x02\0\x01Qa\x03\x86V[a\x03=\x81a\x02 \x01Qa\x03\x86V[a\x03K\x81a\x02@\x01Qa\x03\x86V[a\x03Y\x81a\x02`\x01Qa\x03\x86V[a\x03g\x81a\x02\x80\x01Qa\x03\x86V[a\x03u\x81a\x02\xA0\x01Qa\x03\x86V[a\x03\x83\x81a\x02\xC0\x01Qa\x03\x86V[PV[`\0\x80Q` a8\xDF\x839\x81Q\x91R\x81\x10\x80a\x03\xE9W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FBn254: invalid scalar field\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[PPV[a\x03\xF5a/jV[\x84` \x01Q\x84Q\x14a\x04\x1AW`@Qc \xFA\x9D\x89`\xE1\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0a\x04(\x86\x86\x86\x86a\rwV[\x90P`\0a\x049\x87`\0\x01Qa\x0FEV[\x90P`\0a\x04L\x82\x84`\xA0\x01Q\x89a\x11\xE1V[`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x91\x92P`\0\x91\x90` \x82\x01a\x03\xC0\x806\x837PP`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x92\x93P`\0\x92\x91P` \x82\x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x04\x8FW\x90PP\x90P`\0a\x04\xC8\x8B\x85\x8B\x89\x87\x87a\x12AV[`\xA0\x87\x01Q``\x87\x01Q\x91\x92P\x90`\0\x80Q` a8\xDF\x839\x81Q\x91R`\0\x81\x83\x85\t`@\x80Qa\x01\0\x81\x01\x82R`\xE0\x9C\x8D\x01Q\x81R` \x81\x01\x96\x90\x96R\x85\x01RPPP``\x81\x01\x91\x90\x91R`\x80\x81\x01\x92\x90\x92R`\xA0\x82\x01Ra\x01`\x87\x01Q`\xC0\x82\x01Ra\x01\x80\x90\x96\x01Q\x92\x86\x01\x92\x90\x92RP\x92\x95\x94PPPPPV[\x80Q`\0\x90`\0\x80Q` a8\xDF\x839\x81Q\x91R`\x01\x80\x83\x11\x15a\x05\xC6Wa\x05ka/\xE4V[`\0[\x84\x81\x10\x15a\x05\xB8Wa\x05\xA6\x87\x82\x81Q\x81\x10a\x05\x8BWa\x05\x8Ba7\x9FV[` \x02` \x01\x01Q`\0\x01Q\x83a\x12j\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x80a\x05\xB0\x81a7\xCBV[\x91PPa\x05nV[Pa\x05\xC2\x81a\x12tV[\x91PP[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`\0a\x05\xFB\x86`\x02a7\xE4V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06\x12Wa\x06\x12a0XV[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06;W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P`\0a\x06K\x87`\x02a7\xE4V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06bWa\x06ba0XV[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06\xA7W\x81` \x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x06\x80W\x90P[P\x90P`\x01`\0[\x88\x81\x10\x15a\x07\xF0W\x81\x84a\x06\xC4\x83`\x02a7\xE4V[\x81Q\x81\x10a\x06\xD4Wa\x06\xD4a7\x9FV[` \x02` \x01\x01\x81\x81RPP\x8A\x81\x81Q\x81\x10a\x06\xF2Wa\x06\xF2a7\x9FV[` \x02` \x01\x01Q`\xC0\x01Q\x83\x82`\x02a\x07\x0C\x91\x90a7\xE4V[\x81Q\x81\x10a\x07\x1CWa\x07\x1Ca7\x9FV[` \x02` \x01\x01\x81\x90RP`\0\x80\x8C\x83\x81Q\x81\x10a\x07\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x05`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\x0F\x84\x84a\x1ANV[\x80\x82Ra\x12\x1F\x90\x85\x90\x85\x90a\x1A\xA2V[` \x82\x01R\x80Qa\x125\x90\x85\x90\x84\x90\x86\x90a\x1B\x08V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12O\x85\x87\x89a\x1C^V[\x90Pa\x12_\x88\x86\x89\x89\x88\x88a\x1DJV[a\x0C\xDC\x81\x87\x86a VV[a\x03\xE9\x82\x82a \xA6V[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x12\x9C\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a8>V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x12\xCDWa\x12\xCDa7\x9FV[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x12\xE9Wa\x12\xE9a7\x9FV[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x08\x94\x93\x92\x91\x90a8>V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x138Wa\x138a7\x9FV[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13YWa\x13Ya7\x9FV[` \x02\x01\x81\x81RPPa\x02Qa\x13\x9C\x83\x83`@Q` \x01a\x13\x84\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a \xD9V[a!\xE6V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14D\x83`\0\x81Q\x81\x10a\x14\x1CWa\x14\x1Ca7\x9FV[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x147Wa\x147a7\x9FV[` \x02` \x01\x01Qa\"fV[\x90P`\x01[\x82Q\x81\x10\x15a\x14\x9EWa\x14\x8A\x82a\x14\x85\x86\x84\x81Q\x81\x10a\x14kWa\x14ka7\x9FV[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x147Wa\x147a7\x9FV[a#\nV[\x91P\x80a\x14\x96\x81a7\xCBV[\x91PPa\x14IV[P\x92\x91PPV[`\0a\x14\xBF`\0\x80Q` a8\xDF\x839\x81Q\x91R\x83a8tV[a\x14\xD7\x90`\0\x80Q` a8\xDF\x839\x81Q\x91Ra8\x96V[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x05WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a8\xBF\x839\x81Q\x91R\x84` \x01Qa\x158\x91\x90a8tV[a\x15P\x90`\0\x80Q` a8\xBF\x839\x81Q\x91Ra8\x96V[\x90R\x92\x91PPV[a\x15\x83`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x16\xFFW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\x1F\x91\x90\x83\x90` \x01a8\xA9V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x17v\x84a\x17qa\x17G\x84a#\xB1V[`@Q` \x01a\x17Y\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a \xD9V[a\x17\x0BV[a\x17\x8A\x84a\x17qa\x17G\x86`\0\x01Qa#\xB1V[a\x17\x9E\x84a\x17qa\x17G\x86` \x01Qa#\xB1V[a\x17\xA9\x84`\x01a \xA6V[a\x17\xD3\x84\x7F/\x8D\xD1\xF1\xA7X\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x05`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\x0F\x84\x84a\x1ANV[\x80\x82Ra\x12\x1F\x90\x85\x90\x85\x90a\x1A\xA2V[` \x82\x01R\x80Qa\x125\x90\x85\x90\x84\x90\x86\x90a\x1B\x08V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12O\x85\x87\x89a\x1C^V[\x90Pa\x12_\x88\x86\x89\x89\x88\x88a\x1DJV[a\x0C\xDC\x81\x87\x86a VV[a\x03\xE9\x82\x82a \xA6V[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x12\x9C\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a8mV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x12\xCDWa\x12\xCDa7\xCEV[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x12\xE9Wa\x12\xE9a7\xCEV[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x08\x94\x93\x92\x91\x90a8mV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x138Wa\x138a7\xCEV[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13YWa\x13Ya7\xCEV[` \x02\x01\x81\x81RPPa\x02Qa\x13\x9C\x83\x83`@Q` \x01a\x13\x84\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a \xD9V[a!\xE6V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14D\x83`\0\x81Q\x81\x10a\x14\x1CWa\x14\x1Ca7\xCEV[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x147Wa\x147a7\xCEV[` \x02` \x01\x01Qa\"fV[\x90P`\x01[\x82Q\x81\x10\x15a\x14\x9EWa\x14\x8A\x82a\x14\x85\x86\x84\x81Q\x81\x10a\x14kWa\x14ka7\xCEV[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x147Wa\x147a7\xCEV[a#\nV[\x91P\x80a\x14\x96\x81a7\xFAV[\x91PPa\x14IV[P\x92\x91PPV[`\0a\x14\xBF`\0\x80Q` a9\x0E\x839\x81Q\x91R\x83a8\xA3V[a\x14\xD7\x90`\0\x80Q` a9\x0E\x839\x81Q\x91Ra8\xC5V[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x05WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a8\xEE\x839\x81Q\x91R\x84` \x01Qa\x158\x91\x90a8\xA3V[a\x15P\x90`\0\x80Q` a8\xEE\x839\x81Q\x91Ra8\xC5V[\x90R\x92\x91PPV[a\x15\x83`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x16\xFFW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\x1F\x91\x90\x83\x90` \x01a8\xD8V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x17v\x84a\x17qa\x17G\x84a#\xB1V[`@Q` \x01a\x17Y\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a \xD9V[a\x17\x0BV[a\x17\x8A\x84a\x17qa\x17G\x86`\0\x01Qa#\xB1V[a\x17\x9E\x84a\x17qa\x17G\x86` \x01Qa#\xB1V[a\x17\xA9\x84`\x01a \xA6V[a\x17\xD3\x84\x7F/\x8D\xD1\xF1\xA7X\"\x9E\xF0\xFE\xD6\xC9\xE1\xE0j\x7FD\0r\xA4\x82dsolcC\0\x08\x14\x003"; /// The deployed bytecode of the contract. pub static PLONKVERIFIER_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); @@ -380,6 +387,19 @@ pub mod plonk_verifier { )] #[etherror(name = "InvalidPlonkArgs", abi = "InvalidPlonkArgs()")] pub struct InvalidPlonkArgs; + ///Custom Error type `InvalidPolyEvalArgs` with signature `InvalidPolyEvalArgs()` and selector `0x8c5e11f1` + #[derive( + Clone, + ::ethers::contract::EthError, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[etherror(name = "InvalidPolyEvalArgs", abi = "InvalidPolyEvalArgs()")] + pub struct InvalidPolyEvalArgs; ///Custom Error type `UnsupportedDegree` with signature `UnsupportedDegree()` and selector `0xe2ef09e5` #[derive( Clone, @@ -410,6 +430,7 @@ pub mod plonk_verifier { #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum PlonkVerifierErrors { InvalidPlonkArgs(InvalidPlonkArgs), + InvalidPolyEvalArgs(InvalidPolyEvalArgs), UnsupportedDegree(UnsupportedDegree), WrongPlonkVK(WrongPlonkVK), /// The standard solidity revert string, with selector @@ -430,6 +451,11 @@ pub mod plonk_verifier { { return Ok(Self::InvalidPlonkArgs(decoded)); } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::InvalidPolyEvalArgs(decoded)); + } if let Ok(decoded) = ::decode(data) { return Ok(Self::UnsupportedDegree(decoded)); @@ -444,6 +470,9 @@ pub mod plonk_verifier { fn encode(self) -> ::std::vec::Vec { match self { Self::InvalidPlonkArgs(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::InvalidPolyEvalArgs(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } Self::UnsupportedDegree(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::WrongPlonkVK(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::RevertString(s) => ::ethers::core::abi::AbiEncode::encode(s), @@ -457,6 +486,11 @@ pub mod plonk_verifier { _ if selector == ::selector() => { true } + _ if selector + == ::selector() => + { + true + } _ if selector == ::selector() => { @@ -471,6 +505,7 @@ pub mod plonk_verifier { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { match self { Self::InvalidPlonkArgs(element) => ::core::fmt::Display::fmt(element, f), + Self::InvalidPolyEvalArgs(element) => ::core::fmt::Display::fmt(element, f), Self::UnsupportedDegree(element) => ::core::fmt::Display::fmt(element, f), Self::WrongPlonkVK(element) => ::core::fmt::Display::fmt(element, f), Self::RevertString(s) => ::core::fmt::Display::fmt(s, f), @@ -487,6 +522,11 @@ pub mod plonk_verifier { Self::InvalidPlonkArgs(value) } } + impl ::core::convert::From for PlonkVerifierErrors { + fn from(value: InvalidPolyEvalArgs) -> Self { + Self::InvalidPolyEvalArgs(value) + } + } impl ::core::convert::From for PlonkVerifierErrors { fn from(value: UnsupportedDegree) -> Self { Self::UnsupportedDegree(value) diff --git a/contract-bindings/src/polynomial_eval.rs b/contract-bindings/src/polynomial_eval.rs index 85bf245fa9..c4b45347df 100644 --- a/contract-bindings/src/polynomial_eval.rs +++ b/contract-bindings/src/polynomial_eval.rs @@ -16,13 +16,22 @@ pub mod polynomial_eval { constructor: ::core::option::Option::None, functions: ::std::collections::BTreeMap::new(), events: ::std::collections::BTreeMap::new(), - errors: ::core::convert::From::from([( - ::std::borrow::ToOwned::to_owned("UnsupportedDegree"), - ::std::vec![::ethers::core::abi::ethabi::AbiError { - name: ::std::borrow::ToOwned::to_owned("UnsupportedDegree"), - inputs: ::std::vec![], - },], - )]), + errors: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("InvalidPolyEvalArgs"), + ::std::vec![::ethers::core::abi::ethabi::AbiError { + name: ::std::borrow::ToOwned::to_owned("InvalidPolyEvalArgs",), + inputs: ::std::vec![], + },], + ), + ( + ::std::borrow::ToOwned::to_owned("UnsupportedDegree"), + ::std::vec![::ethers::core::abi::ethabi::AbiError { + name: ::std::borrow::ToOwned::to_owned("UnsupportedDegree"), + inputs: ::std::vec![], + },], + ), + ]), receive: false, fallback: false, } @@ -31,12 +40,12 @@ pub mod polynomial_eval { pub static POLYNOMIALEVAL_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); #[rustfmt::skip] - const __BYTECODE: &[u8] = b"`V`7`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14`*WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 b\xC6\n\xF4m\x8F\x9CZ\xA2\x97A\x81\x81#X\")\x9F\xB5\xA0\xB5\x07\xD1\xD1\xDB\x1C,\x14\x07\xBB\xC2ldsolcC\0\x08\x14\x003"; + const __BYTECODE: &[u8] = b"`V`7`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14`*WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \x03$F\x84\xF2N\xCBk\x12\xC0]\xD3\x04\0\xD1dvM\x94@\xA8\xD7d)\xEE~\x96\x91\x0B\x12L\xFBdsolcC\0\x08\x14\x003"; /// The bytecode of the contract. pub static POLYNOMIALEVAL_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static(__BYTECODE); #[rustfmt::skip] - const __DEPLOYED_BYTECODE: &[u8] = b"s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 b\xC6\n\xF4m\x8F\x9CZ\xA2\x97A\x81\x81#X\")\x9F\xB5\xA0\xB5\x07\xD1\xD1\xDB\x1C,\x14\x07\xBB\xC2ldsolcC\0\x08\x14\x003"; + const __DEPLOYED_BYTECODE: &[u8] = b"s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \x03$F\x84\xF2N\xCBk\x12\xC0]\xD3\x04\0\xD1dvM\x94@\xA8\xD7d)\xEE~\x96\x91\x0B\x12L\xFBdsolcC\0\x08\x14\x003"; /// The deployed bytecode of the contract. pub static POLYNOMIALEVAL_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); @@ -124,6 +133,19 @@ pub mod polynomial_eval { Self::new(contract.address(), contract.client()) } } + ///Custom Error type `InvalidPolyEvalArgs` with signature `InvalidPolyEvalArgs()` and selector `0x8c5e11f1` + #[derive( + Clone, + ::ethers::contract::EthError, + ::ethers::contract::EthDisplay, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[etherror(name = "InvalidPolyEvalArgs", abi = "InvalidPolyEvalArgs()")] + pub struct InvalidPolyEvalArgs; ///Custom Error type `UnsupportedDegree` with signature `UnsupportedDegree()` and selector `0xe2ef09e5` #[derive( Clone, @@ -137,4 +159,88 @@ pub mod polynomial_eval { )] #[etherror(name = "UnsupportedDegree", abi = "UnsupportedDegree()")] pub struct UnsupportedDegree; + ///Container type for all of the contract's custom errors + #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + pub enum PolynomialEvalErrors { + InvalidPolyEvalArgs(InvalidPolyEvalArgs), + UnsupportedDegree(UnsupportedDegree), + /// The standard solidity revert string, with selector + /// Error(string) -- 0x08c379a0 + RevertString(::std::string::String), + } + impl ::ethers::core::abi::AbiDecode for PolynomialEvalErrors { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) = + <::std::string::String as ::ethers::core::abi::AbiDecode>::decode(data) + { + return Ok(Self::RevertString(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::InvalidPolyEvalArgs(decoded)); + } + if let Ok(decoded) = ::decode(data) + { + return Ok(Self::UnsupportedDegree(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for PolynomialEvalErrors { + fn encode(self) -> ::std::vec::Vec { + match self { + Self::InvalidPolyEvalArgs(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::UnsupportedDegree(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::RevertString(s) => ::ethers::core::abi::AbiEncode::encode(s), + } + } + } + impl ::ethers::contract::ContractRevert for PolynomialEvalErrors { + fn valid_selector(selector: [u8; 4]) -> bool { + match selector { + [0x08, 0xc3, 0x79, 0xa0] => true, + _ if selector + == ::selector() => + { + true + } + _ if selector + == ::selector() => + { + true + } + _ => false, + } + } + } + impl ::core::fmt::Display for PolynomialEvalErrors { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::InvalidPolyEvalArgs(element) => ::core::fmt::Display::fmt(element, f), + Self::UnsupportedDegree(element) => ::core::fmt::Display::fmt(element, f), + Self::RevertString(s) => ::core::fmt::Display::fmt(s, f), + } + } + } + impl ::core::convert::From<::std::string::String> for PolynomialEvalErrors { + fn from(value: String) -> Self { + Self::RevertString(value) + } + } + impl ::core::convert::From for PolynomialEvalErrors { + fn from(value: InvalidPolyEvalArgs) -> Self { + Self::InvalidPolyEvalArgs(value) + } + } + impl ::core::convert::From for PolynomialEvalErrors { + fn from(value: UnsupportedDegree) -> Self { + Self::UnsupportedDegree(value) + } + } } diff --git a/contracts/rust/src/bin/diff_test.rs b/contracts/rust/src/bin/diff_test.rs index d52b89f4ff..18afa4a81a 100644 --- a/contracts/rust/src/bin/diff_test.rs +++ b/contracts/rust/src/bin/diff_test.rs @@ -1,10 +1,12 @@ -use anyhow::{anyhow, Result}; use ark_bn254::Fr; use ark_ff::{BigInteger, PrimeField}; use ark_poly::domain::radix2::Radix2EvaluationDomain; use ark_poly::EvaluationDomain; use clap::{Parser, ValueEnum}; -use ethers::{abi::AbiEncode, types::U256}; +use ethers::{ + abi::{AbiDecode, AbiEncode}, + types::U256, +}; #[derive(Parser)] #[command(author, version, about, long_about=None)] @@ -16,39 +18,77 @@ struct Cli { arg1: Option, /// Optional 2nd argument for the `action` arg2: Option, + /// Optional 3rd argument for the `action` + arg3: Option, } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] enum Action { - /// Getting ark_poly::Radix2EvaluationDomain::new() + /// Get ark_poly::Radix2EvaluationDomain::new() NewPolyEvalDomain, + /// Get ark_poly::Radix2EvaluationDomain::elements() + EvalDomainElements, + /// Get some poly evals during jf_plonk::prepare_pcs_info() + EvalDataGen, + /// Test only logic + TestOnly, } -fn main() -> Result<()> { +fn main() { let cli = Cli::parse(); match cli.action { Action::NewPolyEvalDomain => { - if let Some(arg1) = cli.arg1.as_ref() { - let log_size = arg1.parse::()?; - let domain = - Radix2EvaluationDomain::::new(2u32.pow(log_size) as usize).unwrap(); - let res = ( - field_to_u256(domain.size_inv)?, - field_to_u256(domain.group_gen)?, - field_to_u256(domain.group_gen_inv)?, - ); - println!("{}", res.encode_hex()); - } + let arg1 = cli.arg1.as_ref().expect("Should provide arg1=logSize"); + let log_size = arg1.parse::().unwrap(); + + let domain = Radix2EvaluationDomain::::new(2u32.pow(log_size) as usize).unwrap(); + let res = ( + field_to_u256(domain.size_inv), + field_to_u256(domain.group_gen), + field_to_u256(domain.group_gen_inv), + ); + println!("{}", res.encode_hex()); } - }; + Action::EvalDomainElements => { + let arg1 = cli.arg1.as_ref().expect("Should provide arg1=logSize"); + let arg2 = cli.arg2.as_ref().expect("Should provide arg2=length"); + let log_size = arg1.parse::().unwrap(); + let length = arg2.parse::().unwrap(); - Ok(()) + let domain = Radix2EvaluationDomain::::new(2u32.pow(log_size) as usize).unwrap(); + let res = domain + .elements() + .take(length) + .map(field_to_u256) + .collect::>(); + println!("{}", res.encode_hex()); + } + Action::EvalDataGen => { + let arg1 = cli.arg1.as_ref().expect("Should provide arg1=logSize"); + let arg2 = cli.arg2.as_ref().expect("Should provide arg2=zeta"); + let arg3 = cli.arg2.as_ref().expect("Should provide arg3=publicInput"); + let log_size = arg1.parse::().unwrap(); + let zeta = u256_to_field::(arg2.parse::().unwrap()); + // let pi = + } + Action::TestOnly => { + let arg1 = cli.arg1.as_ref().expect("Should provide arg1=array"); + let array: Vec = AbiDecode::decode_hex(arg1).unwrap(); + println!("rust side: {:?}", array); + } + }; } -fn field_to_u256(f: F) -> Result { +fn field_to_u256(f: F) -> U256 { if F::MODULUS_BIT_SIZE > 256 { - return Err(anyhow!("Shouldn't convert a > 256-bit field to U256")); + panic!("Shouldn't convert a >256-bit field to U256"); } - Ok(U256::from_little_endian(&f.into_bigint().to_bytes_le())) + U256::from_little_endian(&f.into_bigint().to_bytes_le()) +} + +fn u256_to_field(x: U256) -> F { + let mut bytes = [0u8; 32]; + x.to_little_endian(&mut bytes); + F::from_le_bytes_mod_order(&bytes) } diff --git a/contracts/src/libraries/PolynomialEval.sol b/contracts/src/libraries/PolynomialEval.sol index 18b06d8f71..c7b19ffab1 100644 --- a/contracts/src/libraries/PolynomialEval.sol +++ b/contracts/src/libraries/PolynomialEval.sol @@ -9,6 +9,8 @@ import { BN254 } from "bn254/BN254.sol"; library PolynomialEval { /// Unsupported polynomial degree, currently size must in 2^{14~17}. error UnsupportedDegree(); + /// Unexpected input arguments, some precondition assumptions violated. + error InvalidPolyEvalArgs(); /// @dev a Radix 2 Evaluation Domain struct EvalDomain { @@ -26,17 +28,6 @@ library PolynomialEval { uint256 piEval; } - /// @dev compute the EvalData for a given domain and a challenge zeta - function evalDataGen(EvalDomain memory self, uint256 zeta, uint256[] memory publicInput) - internal - view - returns (EvalData memory evalData) - { - evalData.vanishEval = evaluateVanishingPoly(self, zeta); - evalData.lagrangeOne = evaluateLagrangeOne(self, zeta, evalData.vanishEval); - evalData.piEval = evaluatePiPoly(self, publicInput, zeta, evalData.vanishEval); - } - /// @dev Create a new Radix2EvalDomain with `domainSize` which should be power of 2. /// @dev Will revert if domainSize is not among {2^14, 2^15, 2^16, 2^17} function newEvalDomain(uint256 domainSize) internal pure returns (EvalDomain memory) { @@ -228,6 +219,7 @@ library PolynomialEval { pure returns (uint256[] memory elements) { + if (length > self.size || length == 0) revert InvalidPolyEvalArgs(); uint256 groupGen = self.groupGen; uint256 tmp = 1; uint256 p = BN254.R_MOD; @@ -246,4 +238,15 @@ library PolynomialEval { } } } + + /// @dev compute the EvalData for a given domain and a challenge zeta + function evalDataGen(EvalDomain memory self, uint256 zeta, uint256[] memory publicInput) + internal + view + returns (EvalData memory evalData) + { + evalData.vanishEval = evaluateVanishingPoly(self, zeta); + evalData.lagrangeOne = evaluateLagrangeOne(self, zeta, evalData.vanishEval); + evalData.piEval = evaluatePiPoly(self, publicInput, zeta, evalData.vanishEval); + } } diff --git a/contracts/test/PolynomialEval.t.sol b/contracts/test/PolynomialEval.t.sol index c49a10b2c8..2e49158900 100644 --- a/contracts/test/PolynomialEval.t.sol +++ b/contracts/test/PolynomialEval.t.sol @@ -44,3 +44,65 @@ contract PolynomialEval_newEvalDomain_Test is Test { Poly.newEvalDomain(domainSize); } } + +contract PolynomialEval_domainElements_Test is Test { + /// @dev Test if the domain elements are generated correctly + /// forge-config: default.fuzz.runs = 25 + function testFuzz_domainElements_matches(uint8 logSize, uint256 length) external { + vm.assume(14 <= logSize && logSize <= 17); + Poly.EvalDomain memory domain = Poly.newEvalDomain(2 ** logSize); + + if (length > domain.size || length == 0) { + vm.expectRevert(Poly.InvalidPolyEvalArgs.selector); + Poly.domainElements(domain, length); + } else { + string[] memory cmds = new string[](7); + cmds[0] = "cargo"; + cmds[1] = "run"; + cmds[2] = "--bin"; + cmds[3] = "diff-test"; + cmds[4] = "eval-domain-elements"; + cmds[5] = vm.toString(logSize); + cmds[6] = vm.toString(length); + + bytes memory result = vm.ffi(cmds); + (uint256[] memory elems) = abi.decode(result, (uint256[])); + + assertEq(elems, Poly.domainElements(domain, length)); + } + } +} + +contract PolynomialEval_evalDataGen_Test is Test { + /// @dev Test if evaluations on the vanishing poly, the lagrange one poly, and the public input + /// poly are correct. + function testFuzz_evalDataGen_matches(uint8 logSize, uint256 zeta, uint256[] memory publicInput) + external + { + vm.assume(14 <= logSize && logSize <= 17); + Poly.EvalDomain memory domain = Poly.newEvalDomain(2 ** logSize); + + // TODO: + return; + } +} + +contract WhateverTest is Test { + function test_whatever() external { + uint256[] memory array = new uint256[](3); + array[0] = 1; + array[1] = 10; + array[2] = 100; + console.logBytes(abi.encode(array)); + + string[] memory cmds = new string[](6); + cmds[0] = "cargo"; + cmds[1] = "run"; + cmds[2] = "--bin"; + cmds[3] = "diff-test"; + cmds[4] = "test-only"; + cmds[5] = string(abi.encode(array)); + + bytes memory result = vm.ffi(cmds); + } +} From 271d0194de3f3747ee821fa84e1497d6841a39f3 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Tue, 31 Oct 2023 21:38:46 +0800 Subject: [PATCH 05/38] wip: put aside evalDataEval failed test --- Cargo.lock | 148 +++++++++++++++++++++++++--- contracts/rust/Cargo.toml | 1 + contracts/rust/src/bin/diff_test.rs | 20 +++- contracts/test/PolynomialEval.t.sol | 41 ++++---- 4 files changed, 174 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c5e11b7972..6918d56dea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3500,9 +3500,9 @@ dependencies = [ "ethereum-types", "generic-array", "hotshot-types", - "jf-primitives", - "jf-relation", - "jf-utils 0.4.0-pre.0", + "jf-primitives 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish)", + "jf-relation 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish)", + "jf-utils 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish)", "serde", "typenum", ] @@ -3550,7 +3550,7 @@ dependencies = [ "hotshot-qc", "hotshot-types", "hotshot-utils", - "jf-primitives", + "jf-primitives 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish)", "rand 0.8.5", "rand_chacha 0.3.1", "serde", @@ -3597,7 +3597,7 @@ dependencies = [ "hotshot-task", "hotshot-types", "hotshot-utils", - "jf-primitives", + "jf-primitives 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish)", "nll", "pin-project", "rand_chacha 0.3.1", @@ -3628,7 +3628,7 @@ dependencies = [ "hotshot-task-impls", "hotshot-types", "hotshot-utils", - "jf-primitives", + "jf-primitives 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish)", "nll", "rand 0.8.5", "rand_chacha 0.3.1", @@ -3668,7 +3668,7 @@ dependencies = [ "hex_fmt", "hotshot-task", "hotshot-utils", - "jf-primitives", + "jf-primitives 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish)", "libp2p-networking", "nll", "rand 0.8.5", @@ -3705,7 +3705,7 @@ dependencies = [ "futures", "hotshot-types", "hotshot-utils", - "jf-primitives", + "jf-primitives 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish)", "libp2p-core", "nll", "portpicker", @@ -3741,7 +3741,8 @@ dependencies = [ "ethers-providers", "ethers-solc", "hex", - "jf-primitives", + "jf-plonk", + "jf-primitives 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish)", "jf-utils 0.3.0", "sequencer-utils", "sha3", @@ -4173,10 +4174,83 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "jf-plonk" +version = "0.4.0-pre.0" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#fc7a1e19383acb2a770d08c1ed7ffaa06eb27491" +dependencies = [ + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-poly", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "displaydoc", + "downcast-rs", + "dyn-clone", + "espresso-systems-common 0.4.0", + "hashbrown 0.13.2", + "itertools 0.10.5", + "jf-primitives 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", + "jf-relation 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", + "jf-utils 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", + "merlin", + "num-bigint", + "rand_chacha 0.3.1", + "rayon", + "serde", + "sha3", + "tagged-base64 0.3.3", +] + +[[package]] +name = "jf-primitives" +version = "0.4.0-pre.0" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#fc7a1e19383acb2a770d08c1ed7ffaa06eb27491" +dependencies = [ + "anyhow", + "ark-bls12-377", + "ark-bls12-381 0.4.0", + "ark-bn254", + "ark-bw6-761", + "ark-crypto-primitives", + "ark-ec 0.4.2", + "ark-ed-on-bls12-377", + "ark-ed-on-bls12-381", + "ark-ed-on-bn254", + "ark-ff 0.4.2", + "ark-pallas", + "ark-poly", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "blst", + "chacha20poly1305 0.10.1", + "crypto_kx", + "derivative", + "digest 0.10.7", + "displaydoc", + "espresso-systems-common 0.4.0", + "hashbrown 0.13.2", + "itertools 0.10.5", + "jf-relation 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", + "jf-utils 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", + "merlin", + "num-bigint", + "num-traits", + "rand_chacha 0.3.1", + "rayon", + "serde", + "sha2 0.10.8", + "sha3", + "tagged-base64 0.3.3", + "typenum", + "zeroize", +] + [[package]] name = "jf-primitives" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish#c0b88424ac1c362c2066971d0da5c43e8832ed5f" +source = "git+https://github.com/EspressoSystems/jellyfish#5c74b9a0a3cd6909fe9d10cbff61057ff705fb6d" dependencies = [ "anyhow", "ark-bls12-377", @@ -4202,8 +4276,8 @@ dependencies = [ "espresso-systems-common 0.4.0", "hashbrown 0.13.2", "itertools 0.10.5", - "jf-relation", - "jf-utils 0.4.0-pre.0", + "jf-relation 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish)", + "jf-utils 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish)", "merlin", "num-bigint", "num-traits", @@ -4220,7 +4294,33 @@ dependencies = [ [[package]] name = "jf-relation" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish#c0b88424ac1c362c2066971d0da5c43e8832ed5f" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#fc7a1e19383acb2a770d08c1ed7ffaa06eb27491" +dependencies = [ + "ark-bls12-377", + "ark-bls12-381 0.4.0", + "ark-bn254", + "ark-bw6-761", + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-poly", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "displaydoc", + "downcast-rs", + "dyn-clone", + "hashbrown 0.13.2", + "itertools 0.10.5", + "jf-utils 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", + "num-bigint", + "rand_chacha 0.3.1", + "rayon", +] + +[[package]] +name = "jf-relation" +version = "0.4.0-pre.0" +source = "git+https://github.com/EspressoSystems/jellyfish#5c74b9a0a3cd6909fe9d10cbff61057ff705fb6d" dependencies = [ "ark-bls12-377", "ark-bls12-381 0.4.0", @@ -4237,7 +4337,7 @@ dependencies = [ "dyn-clone", "hashbrown 0.13.2", "itertools 0.10.5", - "jf-utils 0.4.0-pre.0", + "jf-utils 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish)", "num-bigint", "rand_chacha 0.3.1", "rayon", @@ -4261,7 +4361,23 @@ dependencies = [ [[package]] name = "jf-utils" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish#c0b88424ac1c362c2066971d0da5c43e8832ed5f" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#fc7a1e19383acb2a770d08c1ed7ffaa06eb27491" +dependencies = [ + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "digest 0.10.7", + "rayon", + "serde", + "sha2 0.10.8", + "tagged-base64 0.3.3", +] + +[[package]] +name = "jf-utils" +version = "0.4.0-pre.0" +source = "git+https://github.com/EspressoSystems/jellyfish#5c74b9a0a3cd6909fe9d10cbff61057ff705fb6d" dependencies = [ "ark-ec 0.4.2", "ark-ff 0.4.2", @@ -6959,7 +7075,7 @@ dependencies = [ "hotshot-testing", "hotshot-types", "hotshot-web-server", - "jf-primitives", + "jf-primitives 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish)", "lazy_static", "nll", "portpicker", diff --git a/contracts/rust/Cargo.toml b/contracts/rust/Cargo.toml index ceccbe213e..85d997f9eb 100644 --- a/contracts/rust/Cargo.toml +++ b/contracts/rust/Cargo.toml @@ -28,6 +28,7 @@ hex = "0.4.3" # This crate requires a newer version than 0.1.2-patch.1 that's used elsewhere # in this workspace. However not pinning any revision currently breaks # dependency resolution. +jf-plonk = { git = "https://github.com/EspressoSystems/jellyfish", features = ["test_apis"], branch = "more-test-apis" } jf-primitives = { git = "https://github.com/EspressoSystems/jellyfish", features = [ "std", ] } diff --git a/contracts/rust/src/bin/diff_test.rs b/contracts/rust/src/bin/diff_test.rs index 18afa4a81a..ab7d4eade6 100644 --- a/contracts/rust/src/bin/diff_test.rs +++ b/contracts/rust/src/bin/diff_test.rs @@ -1,4 +1,4 @@ -use ark_bn254::Fr; +use ark_bn254::{Bn254, Fr}; use ark_ff::{BigInteger, PrimeField}; use ark_poly::domain::radix2::Radix2EvaluationDomain; use ark_poly::EvaluationDomain; @@ -7,6 +7,7 @@ use ethers::{ abi::{AbiDecode, AbiEncode}, types::U256, }; +use jf_plonk::testing_apis::Verifier; #[derive(Parser)] #[command(author, version, about, long_about=None)] @@ -67,10 +68,23 @@ fn main() { Action::EvalDataGen => { let arg1 = cli.arg1.as_ref().expect("Should provide arg1=logSize"); let arg2 = cli.arg2.as_ref().expect("Should provide arg2=zeta"); - let arg3 = cli.arg2.as_ref().expect("Should provide arg3=publicInput"); + let arg3 = cli.arg3.as_ref().expect("Should provide arg3=publicInput"); + let log_size = arg1.parse::().unwrap(); let zeta = u256_to_field::(arg2.parse::().unwrap()); - // let pi = + let pi_u256: Vec = AbiDecode::decode_hex(arg3).unwrap(); + let pi: Vec = pi_u256.into_iter().map(u256_to_field).collect(); + + let verifier = Verifier::::new(2u32.pow(log_size) as usize).unwrap(); + let (vanish_eval, lagrange_one, pi_eval) = verifier + .compute_poly_evals_for_pcs_info(&zeta, &pi) + .unwrap(); + let res = ( + field_to_u256(vanish_eval), + field_to_u256(lagrange_one), + field_to_u256(pi_eval), + ); + println!("{}", res.encode_hex()); } Action::TestOnly => { let arg1 = cli.arg1.as_ref().expect("Should provide arg1=array"); diff --git a/contracts/test/PolynomialEval.t.sol b/contracts/test/PolynomialEval.t.sol index 2e49158900..9a2bfb63b9 100644 --- a/contracts/test/PolynomialEval.t.sol +++ b/contracts/test/PolynomialEval.t.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: Unlicensed -/* solhint-disable contract-name-camelcase, func-name-mixedcase */ +/* solhint-disable contract-name-camelcase, func-name-mixedcase, one-contract-per-file */ pragma solidity ^0.8.0; // Libraries import "forge-std/Test.sol"; +import { BN254 } from "bn254/BN254.sol"; // Target contract import { PolynomialEval as Poly } from "../src/libraries/PolynomialEval.sol"; @@ -74,35 +75,41 @@ contract PolynomialEval_domainElements_Test is Test { } contract PolynomialEval_evalDataGen_Test is Test { + // FIXME: (alex) this test is failing /// @dev Test if evaluations on the vanishing poly, the lagrange one poly, and the public input /// poly are correct. + /// forge-config: default.fuzz.runs = 1 function testFuzz_evalDataGen_matches(uint8 logSize, uint256 zeta, uint256[] memory publicInput) external { vm.assume(14 <= logSize && logSize <= 17); - Poly.EvalDomain memory domain = Poly.newEvalDomain(2 ** logSize); - - // TODO: - return; - } -} + vm.assume(zeta < BN254.R_MOD); + vm.assume(publicInput.length > 0); + // Since these user-provided `publicInputs` were checked outside before passing in via + // `BN254.validateScalarField()`, it suffices to assume they are proper for our test here. + for (uint256 i = 0; i < publicInput.length; i++) { + vm.assume(publicInput[i] < BN254.R_MOD); + } -contract WhateverTest is Test { - function test_whatever() external { - uint256[] memory array = new uint256[](3); - array[0] = 1; - array[1] = 10; - array[2] = 100; - console.logBytes(abi.encode(array)); + Poly.EvalDomain memory domain = Poly.newEvalDomain(2 ** logSize); - string[] memory cmds = new string[](6); + string[] memory cmds = new string[](8); cmds[0] = "cargo"; cmds[1] = "run"; cmds[2] = "--bin"; cmds[3] = "diff-test"; - cmds[4] = "test-only"; - cmds[5] = string(abi.encode(array)); + cmds[4] = "eval-data-gen"; + cmds[5] = vm.toString(logSize); + cmds[6] = vm.toString(zeta); + cmds[7] = vm.toString(abi.encode(publicInput)); bytes memory result = vm.ffi(cmds); + (uint256 vanishEval, uint256 lagrangeOne, uint256 piEval) = + abi.decode(result, (uint256, uint256, uint256)); + + Poly.EvalData memory evalData = Poly.evalDataGen(domain, zeta, publicInput); + assertEq(vanishEval, evalData.vanishEval); + assertEq(lagrangeOne, evalData.lagrangeOne); + assertEq(piEval, evalData.piEval); } } From 296af4e5ea5dd303960311b6bed8864ff0a00fec Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Wed, 1 Nov 2023 23:41:08 +0800 Subject: [PATCH 06/38] pass Transcript's appendMessage fuzz test --- Cargo.lock | 8 +-- contracts/rust/src/bin/diff_test.rs | 66 ++++++++++++++++++++-- contracts/test/Transcript.t.sol | 86 +++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+), 9 deletions(-) create mode 100644 contracts/test/Transcript.t.sol diff --git a/Cargo.lock b/Cargo.lock index 6918d56dea..b1602846f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4177,7 +4177,7 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jf-plonk" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#fc7a1e19383acb2a770d08c1ed7ffaa06eb27491" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#e099c5a7dee1b89fc7665cb7ce878c4cae1cb317" dependencies = [ "ark-ec 0.4.2", "ark-ff 0.4.2", @@ -4206,7 +4206,7 @@ dependencies = [ [[package]] name = "jf-primitives" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#fc7a1e19383acb2a770d08c1ed7ffaa06eb27491" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#e099c5a7dee1b89fc7665cb7ce878c4cae1cb317" dependencies = [ "anyhow", "ark-bls12-377", @@ -4294,7 +4294,7 @@ dependencies = [ [[package]] name = "jf-relation" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#fc7a1e19383acb2a770d08c1ed7ffaa06eb27491" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#e099c5a7dee1b89fc7665cb7ce878c4cae1cb317" dependencies = [ "ark-bls12-377", "ark-bls12-381 0.4.0", @@ -4361,7 +4361,7 @@ dependencies = [ [[package]] name = "jf-utils" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#fc7a1e19383acb2a770d08c1ed7ffaa06eb27491" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#e099c5a7dee1b89fc7665cb7ce878c4cae1cb317" dependencies = [ "ark-ec 0.4.2", "ark-ff 0.4.2", diff --git a/contracts/rust/src/bin/diff_test.rs b/contracts/rust/src/bin/diff_test.rs index ab7d4eade6..1fcd7ff8e2 100644 --- a/contracts/rust/src/bin/diff_test.rs +++ b/contracts/rust/src/bin/diff_test.rs @@ -5,9 +5,14 @@ use ark_poly::EvaluationDomain; use clap::{Parser, ValueEnum}; use ethers::{ abi::{AbiDecode, AbiEncode}, - types::U256, + prelude::{EthAbiCodec, EthAbiType}, + types::{Bytes, H256, U256}, +}; +use jf_plonk::{ + constants::KECCAK256_STATE_SIZE, + testing_apis::Verifier, + transcript::{PlonkTranscript, SolidityTranscript}, }; -use jf_plonk::testing_apis::Verifier; #[derive(Parser)] #[command(author, version, about, long_about=None)] @@ -31,6 +36,8 @@ enum Action { EvalDomainElements, /// Get some poly evals during jf_plonk::prepare_pcs_info() EvalDataGen, + /// Get jf_plonk::Transcript::append_message() + TranscriptAppendMsg, /// Test only logic TestOnly, } @@ -86,10 +93,30 @@ fn main() { ); println!("{}", res.encode_hex()); } + Action::TranscriptAppendMsg => { + let arg1 = cli.arg1.as_ref().expect("Should provide arg1=transcript"); + let arg2 = cli.arg2.as_ref().expect("Should provide arg2=message"); + let t_parsed = { + let parsed: (ParsedTranscript,) = AbiDecode::decode_hex(arg1).unwrap(); + parsed.0 + }; + let msg = { + let parsed: Bytes = AbiDecode::decode_hex(arg2).unwrap(); + parsed.0.to_vec() + }; + + let mut t: SolidityTranscript = t_parsed.into(); + >::append_message(&mut t, &[], &msg).unwrap(); + let res: ParsedTranscript = t.into(); + println!("{}", (res,).encode_hex()); + } Action::TestOnly => { - let arg1 = cli.arg1.as_ref().expect("Should provide arg1=array"); - let array: Vec = AbiDecode::decode_hex(arg1).unwrap(); - println!("rust side: {:?}", array); + let arg1 = cli.arg1.as_ref().expect("Should provide arg1=transcript"); + let t_parsed = { + let parsed: (ParsedTranscript,) = AbiDecode::decode_hex(arg1).unwrap(); + parsed.0 + }; + println!("{}", (t_parsed,).encode_hex()); } }; } @@ -106,3 +133,32 @@ fn u256_to_field(x: U256) -> F { x.to_little_endian(&mut bytes); F::from_le_bytes_mod_order(&bytes) } + +/// an intermediate representation of the transcript parsed from abi.encode(transcript) from Solidity. +#[derive(Clone, EthAbiType, EthAbiCodec)] +struct ParsedTranscript { + pub(crate) transcript: Bytes, + pub(crate) state: [H256; 2], +} + +impl From for ParsedTranscript { + fn from(t: SolidityTranscript) -> Self { + let (transcript, state) = t.internal(); + Self { + transcript: transcript.into(), + state: [ + H256::from_slice(&state[..32]), + H256::from_slice(&state[32..]), + ], + } + } +} + +impl From for SolidityTranscript { + fn from(t: ParsedTranscript) -> Self { + let mut state = [0u8; KECCAK256_STATE_SIZE]; + state[..32].copy_from_slice(&t.state[0].to_fixed_bytes()); + state[32..].copy_from_slice(&t.state[1].to_fixed_bytes()); + Self::from_internal(t.transcript.to_vec(), state) + } +} diff --git a/contracts/test/Transcript.t.sol b/contracts/test/Transcript.t.sol new file mode 100644 index 0000000000..c97f220571 --- /dev/null +++ b/contracts/test/Transcript.t.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: Unlicensed + +/* solhint-disable contract-name-camelcase, func-name-mixedcase, one-contract-per-file */ + +pragma solidity ^0.8.0; + +// Libraries +import "forge-std/Test.sol"; +import { BN254 } from "bn254/BN254.sol"; +import { IPlonkVerifier } from "../src/interfaces/IPlonkVerifier.sol"; + +// Target contract +import { Transcript as T } from "../src/libraries/Transcript.sol"; + +contract Transcript_appendMessage_Test is Test { + using T for T.TranscriptData; + + /// forge-config: default.fuzz.runs = 10 + /// @dev Test if `appendMessage` matches that of the Jellyfish's code + function testFuzz_appendMessage_matches( + T.TranscriptData memory transcript, + bytes memory message + ) external { + string[] memory cmds = new string[](7); + cmds[0] = "cargo"; + cmds[1] = "run"; + cmds[2] = "--bin"; + cmds[3] = "diff-test"; + cmds[4] = "transcript-append-msg"; + cmds[5] = vm.toString(abi.encode(transcript)); + cmds[6] = vm.toString(abi.encode(message)); + + bytes memory result = vm.ffi(cmds); + (T.TranscriptData memory updated) = abi.decode(result, (T.TranscriptData)); + + transcript.appendMessage(message); + assertEq(updated.transcript, transcript.transcript); + assertEq(updated.state[0], transcript.state[0]); + assertEq(updated.state[1], transcript.state[1]); + } +} + +// contract Transcript_appendFieldElement_Test is Test { +// // TODO: +// } + +// contract Transcript_appendGroupElement_Test is Test { +// // TODO: +// } + +// contract Transcript_getAndAppendChallenge_Test is Test { +// // TODO: +// } + +// contract Transcript_appendVkAndPubInput_Test is Test { +// // TODO: +// } + +// contract Transcript_appendProofEvaluations_Test is Test { +// // TODO: +// } + +contract WhateverTest is Test { + function test_whatever() external { + T.TranscriptData memory transcript; + transcript.transcript = "\x03\x04"; + transcript.state[0] = "a"; + transcript.state[1] = "b"; + + // bytes memory message = "hi"; + + string[] memory cmds = new string[](6); + // string[] memory cmds = new string[](7); + cmds[0] = "cargo"; + cmds[1] = "run"; + cmds[2] = "--bin"; + cmds[3] = "diff-test"; + cmds[4] = "test-only"; + cmds[5] = vm.toString(abi.encode(transcript)); + // cmds[6] = vm.toString(message); + + bytes memory result = vm.ffi(cmds); + (T.TranscriptData memory recv) = abi.decode(result, (T.TranscriptData)); + assertEq(recv.transcript, transcript.transcript); + } +} From 71dce986a16d5197b4fa8975a10fbb766947d89f Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 3 Nov 2023 00:54:48 +0800 Subject: [PATCH 07/38] more tests, and fix prior failure --- Cargo.lock | 42 +---------- contracts/rust/Cargo.toml | 6 +- contracts/rust/src/bin/diff_test.rs | 104 ++++++++++++++++++++++++++-- contracts/test/PolynomialEval.t.sol | 5 +- contracts/test/Transcript.t.sol | 96 ++++++++++++++++++++++--- 5 files changed, 191 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b1602846f3..84bef6eb97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3742,8 +3742,8 @@ dependencies = [ "ethers-solc", "hex", "jf-plonk", - "jf-primitives 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish)", - "jf-utils 0.3.0", + "jf-primitives 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", + "jf-utils 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", "sequencer-utils", "sha3", ] @@ -4343,21 +4343,6 @@ dependencies = [ "rayon", ] -[[package]] -name = "jf-utils" -version = "0.3.0" -source = "git+https://github.com/EspressoSystems/jellyfish?rev=483fb97324d42724720f9155f200973a3b83a7b4#483fb97324d42724720f9155f200973a3b83a7b4" -dependencies = [ - "ark-ec 0.4.2", - "ark-ff 0.4.2", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "digest 0.10.7", - "serde", - "sha2 0.10.8", - "tagged-base64 0.3.0", -] - [[package]] name = "jf-utils" version = "0.4.0-pre.0" @@ -7947,20 +7932,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "tagged-base64" -version = "0.3.0" -source = "git+https://github.com/espressosystems/tagged-base64?tag=0.3.0#19381b3f14b1f94269c8c783288a63694b6dd12a" -dependencies = [ - "ark-serialize 0.4.2", - "base64 0.13.1", - "crc-any", - "serde", - "snafu", - "tagged-base64-macros 0.3.0", - "wasm-bindgen", -] - [[package]] name = "tagged-base64" version = "0.3.3" @@ -7987,15 +7958,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "tagged-base64-macros" -version = "0.3.0" -source = "git+https://github.com/espressosystems/tagged-base64?tag=0.3.0#19381b3f14b1f94269c8c783288a63694b6dd12a" -dependencies = [ - "quote", - "syn 1.0.109", -] - [[package]] name = "tagged-base64-macros" version = "0.3.3" diff --git a/contracts/rust/Cargo.toml b/contracts/rust/Cargo.toml index 85d997f9eb..1af0347e52 100644 --- a/contracts/rust/Cargo.toml +++ b/contracts/rust/Cargo.toml @@ -29,10 +29,8 @@ hex = "0.4.3" # in this workspace. However not pinning any revision currently breaks # dependency resolution. jf-plonk = { git = "https://github.com/EspressoSystems/jellyfish", features = ["test_apis"], branch = "more-test-apis" } -jf-primitives = { git = "https://github.com/EspressoSystems/jellyfish", features = [ - "std", -] } -jf-utils = { git = "https://github.com/EspressoSystems/jellyfish", rev = "483fb97324d42724720f9155f200973a3b83a7b4" } +jf-primitives = { git = "https://github.com/EspressoSystems/jellyfish", features = ["std"], branch = "more-test-apis" } +jf-utils = { git = "https://github.com/EspressoSystems/jellyfish", branch = "more-test-apis" } sequencer-utils = { path = "../../utils" } sha3 = { version = "0.10.8", default-features = false } diff --git a/contracts/rust/src/bin/diff_test.rs b/contracts/rust/src/bin/diff_test.rs index 1fcd7ff8e2..3a42f1bb36 100644 --- a/contracts/rust/src/bin/diff_test.rs +++ b/contracts/rust/src/bin/diff_test.rs @@ -1,11 +1,15 @@ -use ark_bn254::{Bn254, Fr}; +use std::str::FromStr; + +use ark_bn254::{Bn254, Fr, G1Affine}; +use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; +use ark_ec::AffineRepr; use ark_ff::{BigInteger, PrimeField}; use ark_poly::domain::radix2::Radix2EvaluationDomain; use ark_poly::EvaluationDomain; use clap::{Parser, ValueEnum}; use ethers::{ abi::{AbiDecode, AbiEncode}, - prelude::{EthAbiCodec, EthAbiType}, + prelude::{AbiError, EthAbiCodec, EthAbiType}, types::{Bytes, H256, U256}, }; use jf_plonk::{ @@ -13,6 +17,7 @@ use jf_plonk::{ testing_apis::Verifier, transcript::{PlonkTranscript, SolidityTranscript}, }; +use jf_primitives::pcs::prelude::Commitment; #[derive(Parser)] #[command(author, version, about, long_about=None)] @@ -38,6 +43,12 @@ enum Action { EvalDataGen, /// Get jf_plonk::Transcript::append_message() TranscriptAppendMsg, + /// Get jf_plonk::Transcript::append_challenge() + TranscriptAppendField, + /// Get jf_plonk::Transcript::append_commitment() + TranscriptAppendGroup, + /// Get jf_plonk::Transcript::get_and_append_challenge() + TranscriptGetChal, /// Test only logic TestOnly, } @@ -96,10 +107,7 @@ fn main() { Action::TranscriptAppendMsg => { let arg1 = cli.arg1.as_ref().expect("Should provide arg1=transcript"); let arg2 = cli.arg2.as_ref().expect("Should provide arg2=message"); - let t_parsed = { - let parsed: (ParsedTranscript,) = AbiDecode::decode_hex(arg1).unwrap(); - parsed.0 - }; + let t_parsed = arg1.parse::().unwrap(); let msg = { let parsed: Bytes = AbiDecode::decode_hex(arg2).unwrap(); parsed.0.to_vec() @@ -110,6 +118,40 @@ fn main() { let res: ParsedTranscript = t.into(); println!("{}", (res,).encode_hex()); } + Action::TranscriptAppendField => { + let arg1 = cli.arg1.as_ref().expect("Should provide arg1=transcript"); + let arg2 = cli.arg2.as_ref().expect("Should provide arg2=fieldElement"); + let t_parsed = arg1.parse::().unwrap(); + let field = u256_to_field::(arg2.parse::().unwrap()); + + let mut t: SolidityTranscript = t_parsed.into(); + t.append_challenge::(&[], &field).unwrap(); + let res: ParsedTranscript = t.into(); + println!("{}", (res,).encode_hex()); + } + Action::TranscriptAppendGroup => { + let arg1 = cli.arg1.as_ref().expect("Should provide arg1=transcript"); + let arg2 = cli.arg2.as_ref().expect("Should provide arg2=groupElement"); + let t_parsed = arg1.parse::().unwrap(); + let point: G1Affine = arg2.parse::().unwrap().into(); + + let mut t: SolidityTranscript = t_parsed.into(); + t.append_commitment::(&[], &Commitment::from(point)) + .unwrap(); + let res: ParsedTranscript = t.into(); + println!("{}", (res,).encode_hex()); + } + Action::TranscriptGetChal => { + let arg1 = cli.arg1.as_ref().expect("Should provide arg1=transcript"); + let t_parsed = arg1.parse::().unwrap(); + + let mut t: SolidityTranscript = t_parsed.into(); + let chal = t.get_and_append_challenge::(&[]).unwrap(); + + let updated_t: ParsedTranscript = t.into(); + let res = (updated_t, field_to_u256(chal)); + println!("{}", res.encode_hex()); + } Action::TestOnly => { let arg1 = cli.arg1.as_ref().expect("Should provide arg1=transcript"); let t_parsed = { @@ -121,6 +163,9 @@ fn main() { }; } +// ------- Helper functions and structs -------- +// --------------------------------------------- + fn field_to_u256(f: F) -> U256 { if F::MODULUS_BIT_SIZE > 256 { panic!("Shouldn't convert a >256-bit field to U256"); @@ -141,6 +186,14 @@ struct ParsedTranscript { pub(crate) state: [H256; 2], } +impl FromStr for ParsedTranscript { + type Err = AbiError; + fn from_str(s: &str) -> Result { + let parsed: (ParsedTranscript,) = AbiDecode::decode_hex(s)?; + Ok(parsed.0) + } +} + impl From for ParsedTranscript { fn from(t: SolidityTranscript) -> Self { let (transcript, state) = t.internal(); @@ -162,3 +215,42 @@ impl From for SolidityTranscript { Self::from_internal(t.transcript.to_vec(), state) } } + +/// an intermediate representation of `BN254.G1Point` in solidity. +#[derive(Clone, Debug, EthAbiType, EthAbiCodec)] +struct ParsedG1Point { + x: U256, + y: U256, +} + +impl FromStr for ParsedG1Point { + type Err = AbiError; + fn from_str(s: &str) -> Result { + let parsed: (Self,) = AbiDecode::decode_hex(s)?; + Ok(parsed.0) + } +} + +impl From> for ParsedG1Point +where + P::BaseField: PrimeField, +{ + fn from(p: Affine

) -> Self { + Self { + x: field_to_u256::(*p.x().unwrap()), + y: field_to_u256::(*p.y().unwrap()), + } + } +} + +impl From for Affine

+where + P::BaseField: PrimeField, +{ + fn from(p: ParsedG1Point) -> Self { + Self::new( + u256_to_field::(p.x), + u256_to_field::(p.y), + ) + } +} diff --git a/contracts/test/PolynomialEval.t.sol b/contracts/test/PolynomialEval.t.sol index 9a2bfb63b9..305a5d8368 100644 --- a/contracts/test/PolynomialEval.t.sol +++ b/contracts/test/PolynomialEval.t.sol @@ -75,10 +75,9 @@ contract PolynomialEval_domainElements_Test is Test { } contract PolynomialEval_evalDataGen_Test is Test { - // FIXME: (alex) this test is failing /// @dev Test if evaluations on the vanishing poly, the lagrange one poly, and the public input /// poly are correct. - /// forge-config: default.fuzz.runs = 1 + /// forge-config: default.fuzz.runs = 10 function testFuzz_evalDataGen_matches(uint8 logSize, uint256 zeta, uint256[] memory publicInput) external { @@ -100,7 +99,7 @@ contract PolynomialEval_evalDataGen_Test is Test { cmds[3] = "diff-test"; cmds[4] = "eval-data-gen"; cmds[5] = vm.toString(logSize); - cmds[6] = vm.toString(zeta); + cmds[6] = vm.toString(bytes32(zeta)); cmds[7] = vm.toString(abi.encode(publicInput)); bytes memory result = vm.ffi(cmds); diff --git a/contracts/test/Transcript.t.sol b/contracts/test/Transcript.t.sol index c97f220571..92e08c4609 100644 --- a/contracts/test/Transcript.t.sol +++ b/contracts/test/Transcript.t.sol @@ -40,17 +40,95 @@ contract Transcript_appendMessage_Test is Test { } } -// contract Transcript_appendFieldElement_Test is Test { -// // TODO: -// } +contract Transcript_appendFieldElement_Test is Test { + using T for T.TranscriptData; -// contract Transcript_appendGroupElement_Test is Test { -// // TODO: -// } + /// forge-config: default.fuzz.runs = 10 + /// @dev Test if `appendFieldElement` matches that of Jellyfish + function testFuzz_appendFieldElement_matches( + T.TranscriptData memory transcript, + uint256 fieldElement + ) external { + fieldElement = bound(fieldElement, 0, BN254.R_MOD - 1); + BN254.validateScalarField(fieldElement); -// contract Transcript_getAndAppendChallenge_Test is Test { -// // TODO: -// } + string[] memory cmds = new string[](7); + cmds[0] = "cargo"; + cmds[1] = "run"; + cmds[2] = "--bin"; + cmds[3] = "diff-test"; + cmds[4] = "transcript-append-field"; + cmds[5] = vm.toString(abi.encode(transcript)); + cmds[6] = vm.toString(bytes32(fieldElement)); + + bytes memory result = vm.ffi(cmds); + (T.TranscriptData memory updated) = abi.decode(result, (T.TranscriptData)); + + transcript.appendFieldElement(fieldElement); + assertEq(updated.transcript, transcript.transcript); + assertEq(updated.state[0], transcript.state[0]); + assertEq(updated.state[1], transcript.state[1]); + } +} + +contract Transcript_appendGroupElement_Test is Test { + using T for T.TranscriptData; + + /// forge-config: default.fuzz.runs = 10 + /// @dev Test if `appendGroupElement` matches that of Jellyfish + function testFuzz_appendGroupElement_matches( + T.TranscriptData memory transcript, + uint256 randScalar + ) external { + randScalar = bound(randScalar, 0, BN254.R_MOD - 1); + BN254.validateScalarField(randScalar); + BN254.G1Point memory randPoint = BN254.scalarMul(BN254.P1(), randScalar); + + string[] memory cmds = new string[](7); + cmds[0] = "cargo"; + cmds[1] = "run"; + cmds[2] = "--bin"; + cmds[3] = "diff-test"; + cmds[4] = "transcript-append-group"; + cmds[5] = vm.toString(abi.encode(transcript)); + cmds[6] = vm.toString(abi.encode(randPoint)); + + bytes memory result = vm.ffi(cmds); + (T.TranscriptData memory updated) = abi.decode(result, (T.TranscriptData)); + + transcript.appendGroupElement(randPoint); + assertEq(updated.transcript, transcript.transcript); + assertEq(updated.state[0], transcript.state[0]); + assertEq(updated.state[1], transcript.state[1]); + } +} + +contract Transcript_getAndAppendChallenge_Test is Test { + using T for T.TranscriptData; + + /// forge-config: default.fuzz.runs = 10 + /// @dev Test if `getAndAppendChallenge` matches that of Jellyfish + function testFuzz_getAndAppendChallenge_matches(T.TranscriptData memory transcript) external { + string[] memory cmds = new string[](6); + cmds[0] = "cargo"; + cmds[1] = "run"; + cmds[2] = "--bin"; + cmds[3] = "diff-test"; + cmds[4] = "transcript-get-chal"; + cmds[5] = vm.toString(abi.encode(transcript)); + + bytes memory result = vm.ffi(cmds); + (T.TranscriptData memory updated, uint256 chal) = + abi.decode(result, (T.TranscriptData, uint256)); + + uint256 challenge = transcript.getAndAppendChallenge(); + + assertEq(updated.transcript, transcript.transcript); + assertEq(updated.state[0], transcript.state[0]); + assertEq(updated.state[1], transcript.state[1]); + assertEq(chal, challenge); + } +} // contract Transcript_appendVkAndPubInput_Test is Test { // // TODO: From 69079d9cf0fea19882fe742de3fde4f9b5c44471 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 3 Nov 2023 20:02:29 +0800 Subject: [PATCH 08/38] bugfix: fix type inconsistency leading to diff transcript --- Cargo.lock | 16 +- contract-bindings/src/plonk_verifier.rs | 4 +- contract-bindings/src/transcript.rs | 4 +- contracts/rust/Cargo.toml | 6 +- contracts/rust/src/bin/diff_test.rs | 255 +++++++++++++++++- contracts/src/libraries/Transcript.sol | 4 +- contracts/test/Transcript.t.sol | 56 ++-- .../test/stubs/Transfer1In2Out24DepthVk.sol | 196 ++++++++++++++ 8 files changed, 496 insertions(+), 45 deletions(-) create mode 100644 contracts/test/stubs/Transfer1In2Out24DepthVk.sol diff --git a/Cargo.lock b/Cargo.lock index 84bef6eb97..3d1fcd9257 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3744,6 +3744,8 @@ dependencies = [ "jf-plonk", "jf-primitives 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", "jf-utils 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", + "num-bigint", + "num-traits", "sequencer-utils", "sha3", ] @@ -4177,7 +4179,7 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jf-plonk" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#e099c5a7dee1b89fc7665cb7ce878c4cae1cb317" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#92bb74afeb894473116eb484ca12118e528365ec" dependencies = [ "ark-ec 0.4.2", "ark-ff 0.4.2", @@ -4206,7 +4208,7 @@ dependencies = [ [[package]] name = "jf-primitives" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#e099c5a7dee1b89fc7665cb7ce878c4cae1cb317" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#92bb74afeb894473116eb484ca12118e528365ec" dependencies = [ "anyhow", "ark-bls12-377", @@ -4250,7 +4252,7 @@ dependencies = [ [[package]] name = "jf-primitives" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish#5c74b9a0a3cd6909fe9d10cbff61057ff705fb6d" +source = "git+https://github.com/EspressoSystems/jellyfish#d99c22da6b733131c665b8bf8edcc33258d4f41d" dependencies = [ "anyhow", "ark-bls12-377", @@ -4294,7 +4296,7 @@ dependencies = [ [[package]] name = "jf-relation" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#e099c5a7dee1b89fc7665cb7ce878c4cae1cb317" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#92bb74afeb894473116eb484ca12118e528365ec" dependencies = [ "ark-bls12-377", "ark-bls12-381 0.4.0", @@ -4320,7 +4322,7 @@ dependencies = [ [[package]] name = "jf-relation" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish#5c74b9a0a3cd6909fe9d10cbff61057ff705fb6d" +source = "git+https://github.com/EspressoSystems/jellyfish#d99c22da6b733131c665b8bf8edcc33258d4f41d" dependencies = [ "ark-bls12-377", "ark-bls12-381 0.4.0", @@ -4346,7 +4348,7 @@ dependencies = [ [[package]] name = "jf-utils" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#e099c5a7dee1b89fc7665cb7ce878c4cae1cb317" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#92bb74afeb894473116eb484ca12118e528365ec" dependencies = [ "ark-ec 0.4.2", "ark-ff 0.4.2", @@ -4362,7 +4364,7 @@ dependencies = [ [[package]] name = "jf-utils" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish#5c74b9a0a3cd6909fe9d10cbff61057ff705fb6d" +source = "git+https://github.com/EspressoSystems/jellyfish#d99c22da6b733131c665b8bf8edcc33258d4f41d" dependencies = [ "ark-ec 0.4.2", "ark-ff 0.4.2", diff --git a/contract-bindings/src/plonk_verifier.rs b/contract-bindings/src/plonk_verifier.rs index 4ab0ab6cd9..5f3b870b7f 100644 --- a/contract-bindings/src/plonk_verifier.rs +++ b/contract-bindings/src/plonk_verifier.rs @@ -261,12 +261,12 @@ pub mod plonk_verifier { pub static PLONKVERIFIER_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); #[rustfmt::skip] - const __BYTECODE: &[u8] = b"a9ca\0:`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14a\0-WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\x046\x10a\x005W`\x005`\xE0\x1C\x80c6\xD8\xD6\xEB\x14a\0:W[`\0\x80\xFD[a\0Ma\0H6`\x04a5LV[a\0aV[`@Q\x90\x15\x15\x81R` \x01`@Q\x80\x91\x03\x90\xF3[`\0\x82Q\x85Q\x14\x15\x80a\0vWP\x82Q\x84Q\x14\x15[\x80a\0\x83WP\x82Q\x82Q\x14\x15[\x80a\0\x8DWP\x82Q\x15[\x15a\0\xABW`@Qc\xFD\x9A-\x1B`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0\x83Q`\x01`\x01`@\x1B\x03\x81\x11\x15a\0\xC6Wa\0\xC6a0\x87V[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\0\xFFW\x81` \x01[a\0\xECa/\x99V[\x81R` \x01\x90`\x01\x90\x03\x90\x81a\0\xE4W\x90P[P\x90P`\0[\x84Q\x81\x10\x15a\x02CWa\x010\x85\x82\x81Q\x81\x10a\x01#Wa\x01#a7\xCEV[` \x02` \x01\x01Qa\x02YV[`\0[\x86\x82\x81Q\x81\x10a\x01EWa\x01Ea7\xCEV[` \x02` \x01\x01QQ\x81\x10\x15a\x01\xA2Wa\x01\x90\x87\x83\x81Q\x81\x10a\x01jWa\x01ja7\xCEV[` \x02` \x01\x01Q\x82\x81Q\x81\x10a\x01\x83Wa\x01\x83a7\xCEV[` \x02` \x01\x01Qa\x03\x86V[\x80a\x01\x9A\x81a7\xFAV[\x91PPa\x013V[Pa\x02\x13\x87\x82\x81Q\x81\x10a\x01\xB8Wa\x01\xB8a7\xCEV[` \x02` \x01\x01Q\x87\x83\x81Q\x81\x10a\x01\xD2Wa\x01\xD2a7\xCEV[` \x02` \x01\x01Q\x87\x84\x81Q\x81\x10a\x01\xECWa\x01\xECa7\xCEV[` \x02` \x01\x01Q\x87\x85\x81Q\x81\x10a\x02\x06Wa\x02\x06a7\xCEV[` \x02` \x01\x01Qa\x03\xEDV[\x82\x82\x81Q\x81\x10a\x02%Wa\x02%a7\xCEV[` \x02` \x01\x01\x81\x90RP\x80\x80a\x02;\x90a7\xFAV[\x91PPa\x01\x05V[Pa\x02M\x81a\x05EV[\x91PP[\x94\x93PPPPV[\x80Qa\x02d\x90a\x0C\xE8V[a\x02q\x81` \x01Qa\x0C\xE8V[a\x02~\x81`@\x01Qa\x0C\xE8V[a\x02\x8B\x81``\x01Qa\x0C\xE8V[a\x02\x98\x81`\x80\x01Qa\x0C\xE8V[a\x02\xA5\x81`\xA0\x01Qa\x0C\xE8V[a\x02\xB2\x81`\xC0\x01Qa\x0C\xE8V[a\x02\xBF\x81`\xE0\x01Qa\x0C\xE8V[a\x02\xCD\x81a\x01\0\x01Qa\x0C\xE8V[a\x02\xDB\x81a\x01 \x01Qa\x0C\xE8V[a\x02\xE9\x81a\x01@\x01Qa\x0C\xE8V[a\x02\xF7\x81a\x01`\x01Qa\x0C\xE8V[a\x03\x05\x81a\x01\xA0\x01Qa\x03\x86V[a\x03\x13\x81a\x01\xC0\x01Qa\x03\x86V[a\x03!\x81a\x01\xE0\x01Qa\x03\x86V[a\x03/\x81a\x02\0\x01Qa\x03\x86V[a\x03=\x81a\x02 \x01Qa\x03\x86V[a\x03K\x81a\x02@\x01Qa\x03\x86V[a\x03Y\x81a\x02`\x01Qa\x03\x86V[a\x03g\x81a\x02\x80\x01Qa\x03\x86V[a\x03u\x81a\x02\xA0\x01Qa\x03\x86V[a\x03\x83\x81a\x02\xC0\x01Qa\x03\x86V[PV[`\0\x80Q` a9\x0E\x839\x81Q\x91R\x81\x10\x80a\x03\xE9W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FBn254: invalid scalar field\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[PPV[a\x03\xF5a/\x99V[\x84` \x01Q\x84Q\x14a\x04\x1AW`@Qc \xFA\x9D\x89`\xE1\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0a\x04(\x86\x86\x86\x86a\rwV[\x90P`\0a\x049\x87`\0\x01Qa\x0FEV[\x90P`\0a\x04L\x82\x84`\xA0\x01Q\x89a\x11\xE1V[`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x91\x92P`\0\x91\x90` \x82\x01a\x03\xC0\x806\x837PP`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x92\x93P`\0\x92\x91P` \x82\x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x04\x8FW\x90PP\x90P`\0a\x04\xC8\x8B\x85\x8B\x89\x87\x87a\x12AV[`\xA0\x87\x01Q``\x87\x01Q\x91\x92P\x90`\0\x80Q` a9\x0E\x839\x81Q\x91R`\0\x81\x83\x85\t`@\x80Qa\x01\0\x81\x01\x82R`\xE0\x9C\x8D\x01Q\x81R` \x81\x01\x96\x90\x96R\x85\x01RPPP``\x81\x01\x91\x90\x91R`\x80\x81\x01\x92\x90\x92R`\xA0\x82\x01Ra\x01`\x87\x01Q`\xC0\x82\x01Ra\x01\x80\x90\x96\x01Q\x92\x86\x01\x92\x90\x92RP\x92\x95\x94PPPPPV[\x80Q`\0\x90`\0\x80Q` a9\x0E\x839\x81Q\x91R`\x01\x80\x83\x11\x15a\x05\xC6Wa\x05ka0\x13V[`\0[\x84\x81\x10\x15a\x05\xB8Wa\x05\xA6\x87\x82\x81Q\x81\x10a\x05\x8BWa\x05\x8Ba7\xCEV[` \x02` \x01\x01Q`\0\x01Q\x83a\x12j\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x80a\x05\xB0\x81a7\xFAV[\x91PPa\x05nV[Pa\x05\xC2\x81a\x12tV[\x91PP[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`\0a\x05\xFB\x86`\x02a8\x13V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06\x12Wa\x06\x12a0\x87V[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06;W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P`\0a\x06K\x87`\x02a8\x13V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06bWa\x06ba0\x87V[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06\xA7W\x81` \x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x06\x80W\x90P[P\x90P`\x01`\0[\x88\x81\x10\x15a\x07\xF0W\x81\x84a\x06\xC4\x83`\x02a8\x13V[\x81Q\x81\x10a\x06\xD4Wa\x06\xD4a7\xCEV[` \x02` \x01\x01\x81\x81RPP\x8A\x81\x81Q\x81\x10a\x06\xF2Wa\x06\xF2a7\xCEV[` \x02` \x01\x01Q`\xC0\x01Q\x83\x82`\x02a\x07\x0C\x91\x90a8\x13V[\x81Q\x81\x10a\x07\x1CWa\x07\x1Ca7\xCEV[` \x02` \x01\x01\x81\x90RP`\0\x80\x8C\x83\x81Q\x81\x10a\x07\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x05`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\x0F\x84\x84a\x1ANV[\x80\x82Ra\x12\x1F\x90\x85\x90\x85\x90a\x1A\xA2V[` \x82\x01R\x80Qa\x125\x90\x85\x90\x84\x90\x86\x90a\x1B\x08V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12O\x85\x87\x89a\x1C^V[\x90Pa\x12_\x88\x86\x89\x89\x88\x88a\x1DJV[a\x0C\xDC\x81\x87\x86a VV[a\x03\xE9\x82\x82a \xA6V[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x12\x9C\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a8mV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x12\xCDWa\x12\xCDa7\xCEV[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x12\xE9Wa\x12\xE9a7\xCEV[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x08\x94\x93\x92\x91\x90a8mV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x138Wa\x138a7\xCEV[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13YWa\x13Ya7\xCEV[` \x02\x01\x81\x81RPPa\x02Qa\x13\x9C\x83\x83`@Q` \x01a\x13\x84\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a \xD9V[a!\xE6V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14D\x83`\0\x81Q\x81\x10a\x14\x1CWa\x14\x1Ca7\xCEV[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x147Wa\x147a7\xCEV[` \x02` \x01\x01Qa\"fV[\x90P`\x01[\x82Q\x81\x10\x15a\x14\x9EWa\x14\x8A\x82a\x14\x85\x86\x84\x81Q\x81\x10a\x14kWa\x14ka7\xCEV[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x147Wa\x147a7\xCEV[a#\nV[\x91P\x80a\x14\x96\x81a7\xFAV[\x91PPa\x14IV[P\x92\x91PPV[`\0a\x14\xBF`\0\x80Q` a9\x0E\x839\x81Q\x91R\x83a8\xA3V[a\x14\xD7\x90`\0\x80Q` a9\x0E\x839\x81Q\x91Ra8\xC5V[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x05WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a8\xEE\x839\x81Q\x91R\x84` \x01Qa\x158\x91\x90a8\xA3V[a\x15P\x90`\0\x80Q` a8\xEE\x839\x81Q\x91Ra8\xC5V[\x90R\x92\x91PPV[a\x15\x83`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x16\xFFW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\x1F\x91\x90\x83\x90` \x01a8\xD8V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x17v\x84a\x17qa\x17G\x84a#\xB1V[`@Q` \x01a\x17Y\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a \xD9V[a\x17\x0BV[a\x17\x8A\x84a\x17qa\x17G\x86`\0\x01Qa#\xB1V[a\x17\x9E\x84a\x17qa\x17G\x86` \x01Qa#\xB1V[a\x17\xA9\x84`\x01a \xA6V[a\x17\xD3\x84\x7F/\x8D\xD1\xF1\xA7X\"\x9E\xF0\xFE\xD6\xC9\xE1\xE0j\x7FD\0r\xA4\x82dsolcC\0\x08\x14\x003"; + const __BYTECODE: &[u8] = b"a9\x8Da\0:`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14a\0-WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\x046\x10a\x005W`\x005`\xE0\x1C\x80c6\xD8\xD6\xEB\x14a\0:W[`\0\x80\xFD[a\0Ma\0H6`\x04a5vV[a\0aV[`@Q\x90\x15\x15\x81R` \x01`@Q\x80\x91\x03\x90\xF3[`\0\x82Q\x85Q\x14\x15\x80a\0vWP\x82Q\x84Q\x14\x15[\x80a\0\x83WP\x82Q\x82Q\x14\x15[\x80a\0\x8DWP\x82Q\x15[\x15a\0\xABW`@Qc\xFD\x9A-\x1B`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0\x83Q`\x01`\x01`@\x1B\x03\x81\x11\x15a\0\xC6Wa\0\xC6a0\xB1V[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\0\xFFW\x81` \x01[a\0\xECa/\xC3V[\x81R` \x01\x90`\x01\x90\x03\x90\x81a\0\xE4W\x90P[P\x90P`\0[\x84Q\x81\x10\x15a\x02CWa\x010\x85\x82\x81Q\x81\x10a\x01#Wa\x01#a7\xF8V[` \x02` \x01\x01Qa\x02YV[`\0[\x86\x82\x81Q\x81\x10a\x01EWa\x01Ea7\xF8V[` \x02` \x01\x01QQ\x81\x10\x15a\x01\xA2Wa\x01\x90\x87\x83\x81Q\x81\x10a\x01jWa\x01ja7\xF8V[` \x02` \x01\x01Q\x82\x81Q\x81\x10a\x01\x83Wa\x01\x83a7\xF8V[` \x02` \x01\x01Qa\x03\x86V[\x80a\x01\x9A\x81a8$V[\x91PPa\x013V[Pa\x02\x13\x87\x82\x81Q\x81\x10a\x01\xB8Wa\x01\xB8a7\xF8V[` \x02` \x01\x01Q\x87\x83\x81Q\x81\x10a\x01\xD2Wa\x01\xD2a7\xF8V[` \x02` \x01\x01Q\x87\x84\x81Q\x81\x10a\x01\xECWa\x01\xECa7\xF8V[` \x02` \x01\x01Q\x87\x85\x81Q\x81\x10a\x02\x06Wa\x02\x06a7\xF8V[` \x02` \x01\x01Qa\x03\xEDV[\x82\x82\x81Q\x81\x10a\x02%Wa\x02%a7\xF8V[` \x02` \x01\x01\x81\x90RP\x80\x80a\x02;\x90a8$V[\x91PPa\x01\x05V[Pa\x02M\x81a\x05EV[\x91PP[\x94\x93PPPPV[\x80Qa\x02d\x90a\x0C\xE8V[a\x02q\x81` \x01Qa\x0C\xE8V[a\x02~\x81`@\x01Qa\x0C\xE8V[a\x02\x8B\x81``\x01Qa\x0C\xE8V[a\x02\x98\x81`\x80\x01Qa\x0C\xE8V[a\x02\xA5\x81`\xA0\x01Qa\x0C\xE8V[a\x02\xB2\x81`\xC0\x01Qa\x0C\xE8V[a\x02\xBF\x81`\xE0\x01Qa\x0C\xE8V[a\x02\xCD\x81a\x01\0\x01Qa\x0C\xE8V[a\x02\xDB\x81a\x01 \x01Qa\x0C\xE8V[a\x02\xE9\x81a\x01@\x01Qa\x0C\xE8V[a\x02\xF7\x81a\x01`\x01Qa\x0C\xE8V[a\x03\x05\x81a\x01\xA0\x01Qa\x03\x86V[a\x03\x13\x81a\x01\xC0\x01Qa\x03\x86V[a\x03!\x81a\x01\xE0\x01Qa\x03\x86V[a\x03/\x81a\x02\0\x01Qa\x03\x86V[a\x03=\x81a\x02 \x01Qa\x03\x86V[a\x03K\x81a\x02@\x01Qa\x03\x86V[a\x03Y\x81a\x02`\x01Qa\x03\x86V[a\x03g\x81a\x02\x80\x01Qa\x03\x86V[a\x03u\x81a\x02\xA0\x01Qa\x03\x86V[a\x03\x83\x81a\x02\xC0\x01Qa\x03\x86V[PV[`\0\x80Q` a98\x839\x81Q\x91R\x81\x10\x80a\x03\xE9W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FBn254: invalid scalar field\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[PPV[a\x03\xF5a/\xC3V[\x84` \x01Q\x84Q\x14a\x04\x1AW`@Qc \xFA\x9D\x89`\xE1\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0a\x04(\x86\x86\x86\x86a\rwV[\x90P`\0a\x049\x87`\0\x01Qa\x0FEV[\x90P`\0a\x04L\x82\x84`\xA0\x01Q\x89a\x11\xE1V[`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x91\x92P`\0\x91\x90` \x82\x01a\x03\xC0\x806\x837PP`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x92\x93P`\0\x92\x91P` \x82\x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x04\x8FW\x90PP\x90P`\0a\x04\xC8\x8B\x85\x8B\x89\x87\x87a\x12AV[`\xA0\x87\x01Q``\x87\x01Q\x91\x92P\x90`\0\x80Q` a98\x839\x81Q\x91R`\0\x81\x83\x85\t`@\x80Qa\x01\0\x81\x01\x82R`\xE0\x9C\x8D\x01Q\x81R` \x81\x01\x96\x90\x96R\x85\x01RPPP``\x81\x01\x91\x90\x91R`\x80\x81\x01\x92\x90\x92R`\xA0\x82\x01Ra\x01`\x87\x01Q`\xC0\x82\x01Ra\x01\x80\x90\x96\x01Q\x92\x86\x01\x92\x90\x92RP\x92\x95\x94PPPPPV[\x80Q`\0\x90`\0\x80Q` a98\x839\x81Q\x91R`\x01\x80\x83\x11\x15a\x05\xC6Wa\x05ka0=V[`\0[\x84\x81\x10\x15a\x05\xB8Wa\x05\xA6\x87\x82\x81Q\x81\x10a\x05\x8BWa\x05\x8Ba7\xF8V[` \x02` \x01\x01Q`\0\x01Q\x83a\x12j\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x80a\x05\xB0\x81a8$V[\x91PPa\x05nV[Pa\x05\xC2\x81a\x12tV[\x91PP[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`\0a\x05\xFB\x86`\x02a8=V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06\x12Wa\x06\x12a0\xB1V[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06;W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P`\0a\x06K\x87`\x02a8=V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06bWa\x06ba0\xB1V[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06\xA7W\x81` \x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x06\x80W\x90P[P\x90P`\x01`\0[\x88\x81\x10\x15a\x07\xF0W\x81\x84a\x06\xC4\x83`\x02a8=V[\x81Q\x81\x10a\x06\xD4Wa\x06\xD4a7\xF8V[` \x02` \x01\x01\x81\x81RPP\x8A\x81\x81Q\x81\x10a\x06\xF2Wa\x06\xF2a7\xF8V[` \x02` \x01\x01Q`\xC0\x01Q\x83\x82`\x02a\x07\x0C\x91\x90a8=V[\x81Q\x81\x10a\x07\x1CWa\x07\x1Ca7\xF8V[` \x02` \x01\x01\x81\x90RP`\0\x80\x8C\x83\x81Q\x81\x10a\x07\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x05`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\x0F\x84\x84a\x1AxV[\x80\x82Ra\x12\x1F\x90\x85\x90\x85\x90a\x1A\xCCV[` \x82\x01R\x80Qa\x125\x90\x85\x90\x84\x90\x86\x90a\x1B2V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12O\x85\x87\x89a\x1C\x88V[\x90Pa\x12_\x88\x86\x89\x89\x88\x88a\x1DtV[a\x0C\xDC\x81\x87\x86a \x80V[a\x03\xE9\x82\x82a \xD0V[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x12\x9C\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a8\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x12\xCDWa\x12\xCDa7\xF8V[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x12\xE9Wa\x12\xE9a7\xF8V[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x08\x94\x93\x92\x91\x90a8\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x138Wa\x138a7\xF8V[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13YWa\x13Ya7\xF8V[` \x02\x01\x81\x81RPPa\x02Qa\x13\x9C\x83\x83`@Q` \x01a\x13\x84\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a!\x03V[a\"\x10V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14D\x83`\0\x81Q\x81\x10a\x14\x1CWa\x14\x1Ca7\xF8V[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x147Wa\x147a7\xF8V[` \x02` \x01\x01Qa\"\x90V[\x90P`\x01[\x82Q\x81\x10\x15a\x14\x9EWa\x14\x8A\x82a\x14\x85\x86\x84\x81Q\x81\x10a\x14kWa\x14ka7\xF8V[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x147Wa\x147a7\xF8V[a#4V[\x91P\x80a\x14\x96\x81a8$V[\x91PPa\x14IV[P\x92\x91PPV[`\0a\x14\xBF`\0\x80Q` a98\x839\x81Q\x91R\x83a8\xCDV[a\x14\xD7\x90`\0\x80Q` a98\x839\x81Q\x91Ra8\xEFV[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x05WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a9\x18\x839\x81Q\x91R\x84` \x01Qa\x158\x91\x90a8\xCDV[a\x15P\x90`\0\x80Q` a9\x18\x839\x81Q\x91Ra8\xEFV[\x90R\x92\x91PPV[a\x15\x83`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x16\xFFW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\x1F\x91\x90\x83\x90` \x01a9\x02V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x17v\x84a\x17qa\x17G\x84a#\xDBV[`@Q` \x01a\x17Y\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x04a!\x03V[a\x17\x0BV[a\x17\xB4\x84a\x17qa\x17\x8A\x86`\0\x01Qa#\xDBV[`@Q` \x01a\x17\x9C\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a!\x03V[a\x17\xC8\x84a\x17qa\x17\x8A\x86` \x01Qa#\xDBV[a\x17\xD3\x84`\x01a \xD0V[a\x17\xFD\x84\x7F/\x8D\xD1\xF1\xA7X\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x05`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\x0F\x84\x84a\x1ANV[\x80\x82Ra\x12\x1F\x90\x85\x90\x85\x90a\x1A\xA2V[` \x82\x01R\x80Qa\x125\x90\x85\x90\x84\x90\x86\x90a\x1B\x08V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12O\x85\x87\x89a\x1C^V[\x90Pa\x12_\x88\x86\x89\x89\x88\x88a\x1DJV[a\x0C\xDC\x81\x87\x86a VV[a\x03\xE9\x82\x82a \xA6V[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x12\x9C\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a8mV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x12\xCDWa\x12\xCDa7\xCEV[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x12\xE9Wa\x12\xE9a7\xCEV[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x08\x94\x93\x92\x91\x90a8mV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x138Wa\x138a7\xCEV[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13YWa\x13Ya7\xCEV[` \x02\x01\x81\x81RPPa\x02Qa\x13\x9C\x83\x83`@Q` \x01a\x13\x84\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a \xD9V[a!\xE6V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14D\x83`\0\x81Q\x81\x10a\x14\x1CWa\x14\x1Ca7\xCEV[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x147Wa\x147a7\xCEV[` \x02` \x01\x01Qa\"fV[\x90P`\x01[\x82Q\x81\x10\x15a\x14\x9EWa\x14\x8A\x82a\x14\x85\x86\x84\x81Q\x81\x10a\x14kWa\x14ka7\xCEV[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x147Wa\x147a7\xCEV[a#\nV[\x91P\x80a\x14\x96\x81a7\xFAV[\x91PPa\x14IV[P\x92\x91PPV[`\0a\x14\xBF`\0\x80Q` a9\x0E\x839\x81Q\x91R\x83a8\xA3V[a\x14\xD7\x90`\0\x80Q` a9\x0E\x839\x81Q\x91Ra8\xC5V[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x05WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a8\xEE\x839\x81Q\x91R\x84` \x01Qa\x158\x91\x90a8\xA3V[a\x15P\x90`\0\x80Q` a8\xEE\x839\x81Q\x91Ra8\xC5V[\x90R\x92\x91PPV[a\x15\x83`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x16\xFFW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\x1F\x91\x90\x83\x90` \x01a8\xD8V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x17v\x84a\x17qa\x17G\x84a#\xB1V[`@Q` \x01a\x17Y\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a \xD9V[a\x17\x0BV[a\x17\x8A\x84a\x17qa\x17G\x86`\0\x01Qa#\xB1V[a\x17\x9E\x84a\x17qa\x17G\x86` \x01Qa#\xB1V[a\x17\xA9\x84`\x01a \xA6V[a\x17\xD3\x84\x7F/\x8D\xD1\xF1\xA7X\"\x9E\xF0\xFE\xD6\xC9\xE1\xE0j\x7FD\0r\xA4\x82dsolcC\0\x08\x14\x003"; + const __DEPLOYED_BYTECODE: &[u8] = b"s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\x046\x10a\x005W`\x005`\xE0\x1C\x80c6\xD8\xD6\xEB\x14a\0:W[`\0\x80\xFD[a\0Ma\0H6`\x04a5vV[a\0aV[`@Q\x90\x15\x15\x81R` \x01`@Q\x80\x91\x03\x90\xF3[`\0\x82Q\x85Q\x14\x15\x80a\0vWP\x82Q\x84Q\x14\x15[\x80a\0\x83WP\x82Q\x82Q\x14\x15[\x80a\0\x8DWP\x82Q\x15[\x15a\0\xABW`@Qc\xFD\x9A-\x1B`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0\x83Q`\x01`\x01`@\x1B\x03\x81\x11\x15a\0\xC6Wa\0\xC6a0\xB1V[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\0\xFFW\x81` \x01[a\0\xECa/\xC3V[\x81R` \x01\x90`\x01\x90\x03\x90\x81a\0\xE4W\x90P[P\x90P`\0[\x84Q\x81\x10\x15a\x02CWa\x010\x85\x82\x81Q\x81\x10a\x01#Wa\x01#a7\xF8V[` \x02` \x01\x01Qa\x02YV[`\0[\x86\x82\x81Q\x81\x10a\x01EWa\x01Ea7\xF8V[` \x02` \x01\x01QQ\x81\x10\x15a\x01\xA2Wa\x01\x90\x87\x83\x81Q\x81\x10a\x01jWa\x01ja7\xF8V[` \x02` \x01\x01Q\x82\x81Q\x81\x10a\x01\x83Wa\x01\x83a7\xF8V[` \x02` \x01\x01Qa\x03\x86V[\x80a\x01\x9A\x81a8$V[\x91PPa\x013V[Pa\x02\x13\x87\x82\x81Q\x81\x10a\x01\xB8Wa\x01\xB8a7\xF8V[` \x02` \x01\x01Q\x87\x83\x81Q\x81\x10a\x01\xD2Wa\x01\xD2a7\xF8V[` \x02` \x01\x01Q\x87\x84\x81Q\x81\x10a\x01\xECWa\x01\xECa7\xF8V[` \x02` \x01\x01Q\x87\x85\x81Q\x81\x10a\x02\x06Wa\x02\x06a7\xF8V[` \x02` \x01\x01Qa\x03\xEDV[\x82\x82\x81Q\x81\x10a\x02%Wa\x02%a7\xF8V[` \x02` \x01\x01\x81\x90RP\x80\x80a\x02;\x90a8$V[\x91PPa\x01\x05V[Pa\x02M\x81a\x05EV[\x91PP[\x94\x93PPPPV[\x80Qa\x02d\x90a\x0C\xE8V[a\x02q\x81` \x01Qa\x0C\xE8V[a\x02~\x81`@\x01Qa\x0C\xE8V[a\x02\x8B\x81``\x01Qa\x0C\xE8V[a\x02\x98\x81`\x80\x01Qa\x0C\xE8V[a\x02\xA5\x81`\xA0\x01Qa\x0C\xE8V[a\x02\xB2\x81`\xC0\x01Qa\x0C\xE8V[a\x02\xBF\x81`\xE0\x01Qa\x0C\xE8V[a\x02\xCD\x81a\x01\0\x01Qa\x0C\xE8V[a\x02\xDB\x81a\x01 \x01Qa\x0C\xE8V[a\x02\xE9\x81a\x01@\x01Qa\x0C\xE8V[a\x02\xF7\x81a\x01`\x01Qa\x0C\xE8V[a\x03\x05\x81a\x01\xA0\x01Qa\x03\x86V[a\x03\x13\x81a\x01\xC0\x01Qa\x03\x86V[a\x03!\x81a\x01\xE0\x01Qa\x03\x86V[a\x03/\x81a\x02\0\x01Qa\x03\x86V[a\x03=\x81a\x02 \x01Qa\x03\x86V[a\x03K\x81a\x02@\x01Qa\x03\x86V[a\x03Y\x81a\x02`\x01Qa\x03\x86V[a\x03g\x81a\x02\x80\x01Qa\x03\x86V[a\x03u\x81a\x02\xA0\x01Qa\x03\x86V[a\x03\x83\x81a\x02\xC0\x01Qa\x03\x86V[PV[`\0\x80Q` a98\x839\x81Q\x91R\x81\x10\x80a\x03\xE9W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FBn254: invalid scalar field\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[PPV[a\x03\xF5a/\xC3V[\x84` \x01Q\x84Q\x14a\x04\x1AW`@Qc \xFA\x9D\x89`\xE1\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0a\x04(\x86\x86\x86\x86a\rwV[\x90P`\0a\x049\x87`\0\x01Qa\x0FEV[\x90P`\0a\x04L\x82\x84`\xA0\x01Q\x89a\x11\xE1V[`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x91\x92P`\0\x91\x90` \x82\x01a\x03\xC0\x806\x837PP`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x92\x93P`\0\x92\x91P` \x82\x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x04\x8FW\x90PP\x90P`\0a\x04\xC8\x8B\x85\x8B\x89\x87\x87a\x12AV[`\xA0\x87\x01Q``\x87\x01Q\x91\x92P\x90`\0\x80Q` a98\x839\x81Q\x91R`\0\x81\x83\x85\t`@\x80Qa\x01\0\x81\x01\x82R`\xE0\x9C\x8D\x01Q\x81R` \x81\x01\x96\x90\x96R\x85\x01RPPP``\x81\x01\x91\x90\x91R`\x80\x81\x01\x92\x90\x92R`\xA0\x82\x01Ra\x01`\x87\x01Q`\xC0\x82\x01Ra\x01\x80\x90\x96\x01Q\x92\x86\x01\x92\x90\x92RP\x92\x95\x94PPPPPV[\x80Q`\0\x90`\0\x80Q` a98\x839\x81Q\x91R`\x01\x80\x83\x11\x15a\x05\xC6Wa\x05ka0=V[`\0[\x84\x81\x10\x15a\x05\xB8Wa\x05\xA6\x87\x82\x81Q\x81\x10a\x05\x8BWa\x05\x8Ba7\xF8V[` \x02` \x01\x01Q`\0\x01Q\x83a\x12j\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x80a\x05\xB0\x81a8$V[\x91PPa\x05nV[Pa\x05\xC2\x81a\x12tV[\x91PP[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`\0a\x05\xFB\x86`\x02a8=V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06\x12Wa\x06\x12a0\xB1V[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06;W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P`\0a\x06K\x87`\x02a8=V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06bWa\x06ba0\xB1V[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06\xA7W\x81` \x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x06\x80W\x90P[P\x90P`\x01`\0[\x88\x81\x10\x15a\x07\xF0W\x81\x84a\x06\xC4\x83`\x02a8=V[\x81Q\x81\x10a\x06\xD4Wa\x06\xD4a7\xF8V[` \x02` \x01\x01\x81\x81RPP\x8A\x81\x81Q\x81\x10a\x06\xF2Wa\x06\xF2a7\xF8V[` \x02` \x01\x01Q`\xC0\x01Q\x83\x82`\x02a\x07\x0C\x91\x90a8=V[\x81Q\x81\x10a\x07\x1CWa\x07\x1Ca7\xF8V[` \x02` \x01\x01\x81\x90RP`\0\x80\x8C\x83\x81Q\x81\x10a\x07\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x05`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\x0F\x84\x84a\x1AxV[\x80\x82Ra\x12\x1F\x90\x85\x90\x85\x90a\x1A\xCCV[` \x82\x01R\x80Qa\x125\x90\x85\x90\x84\x90\x86\x90a\x1B2V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12O\x85\x87\x89a\x1C\x88V[\x90Pa\x12_\x88\x86\x89\x89\x88\x88a\x1DtV[a\x0C\xDC\x81\x87\x86a \x80V[a\x03\xE9\x82\x82a \xD0V[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x12\x9C\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a8\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x12\xCDWa\x12\xCDa7\xF8V[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x12\xE9Wa\x12\xE9a7\xF8V[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x08\x94\x93\x92\x91\x90a8\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x138Wa\x138a7\xF8V[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13YWa\x13Ya7\xF8V[` \x02\x01\x81\x81RPPa\x02Qa\x13\x9C\x83\x83`@Q` \x01a\x13\x84\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a!\x03V[a\"\x10V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14D\x83`\0\x81Q\x81\x10a\x14\x1CWa\x14\x1Ca7\xF8V[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x147Wa\x147a7\xF8V[` \x02` \x01\x01Qa\"\x90V[\x90P`\x01[\x82Q\x81\x10\x15a\x14\x9EWa\x14\x8A\x82a\x14\x85\x86\x84\x81Q\x81\x10a\x14kWa\x14ka7\xF8V[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x147Wa\x147a7\xF8V[a#4V[\x91P\x80a\x14\x96\x81a8$V[\x91PPa\x14IV[P\x92\x91PPV[`\0a\x14\xBF`\0\x80Q` a98\x839\x81Q\x91R\x83a8\xCDV[a\x14\xD7\x90`\0\x80Q` a98\x839\x81Q\x91Ra8\xEFV[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x05WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a9\x18\x839\x81Q\x91R\x84` \x01Qa\x158\x91\x90a8\xCDV[a\x15P\x90`\0\x80Q` a9\x18\x839\x81Q\x91Ra8\xEFV[\x90R\x92\x91PPV[a\x15\x83`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x16\xFFW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\x1F\x91\x90\x83\x90` \x01a9\x02V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x17v\x84a\x17qa\x17G\x84a#\xDBV[`@Q` \x01a\x17Y\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x04a!\x03V[a\x17\x0BV[a\x17\xB4\x84a\x17qa\x17\x8A\x86`\0\x01Qa#\xDBV[`@Q` \x01a\x17\x9C\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a!\x03V[a\x17\xC8\x84a\x17qa\x17\x8A\x86` \x01Qa#\xDBV[a\x17\xD3\x84`\x01a \xD0V[a\x17\xFD\x84\x7F/\x8D\xD1\xF1\xA7X = ::ethers::contract::Lazy::new(__abi); #[rustfmt::skip] - const __BYTECODE: &[u8] = b"`V`7`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14`*WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \0\x9E4\xCD\xBA\xED_D\xBC\x91\xCB\x1F\xE6,~'\x93\xECp\x8C\xDD'\xD5\xE4\xFAE\xDF\xA8\xE4\x82\xCBVdsolcC\0\x08\x14\x003"; + const __BYTECODE: &[u8] = b"`V`7`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14`*WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 7M\xD0\xFBmIw\xD0+\x0E\xD1g\x06\xE5\x15i\x1B|\xE6]\x8C\x90\x1B@ >\xFD2\"\xBA\x1B\x1FdsolcC\0\x08\x14\x003"; /// The bytecode of the contract. pub static TRANSCRIPT_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static(__BYTECODE); #[rustfmt::skip] - const __DEPLOYED_BYTECODE: &[u8] = b"s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \0\x9E4\xCD\xBA\xED_D\xBC\x91\xCB\x1F\xE6,~'\x93\xECp\x8C\xDD'\xD5\xE4\xFAE\xDF\xA8\xE4\x82\xCBVdsolcC\0\x08\x14\x003"; + const __DEPLOYED_BYTECODE: &[u8] = b"s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 7M\xD0\xFBmIw\xD0+\x0E\xD1g\x06\xE5\x15i\x1B|\xE6]\x8C\x90\x1B@ >\xFD2\"\xBA\x1B\x1FdsolcC\0\x08\x14\x003"; /// The deployed bytecode of the contract. pub static TRANSCRIPT_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); diff --git a/contracts/rust/Cargo.toml b/contracts/rust/Cargo.toml index 1af0347e52..6e3cc94e83 100644 --- a/contracts/rust/Cargo.toml +++ b/contracts/rust/Cargo.toml @@ -24,13 +24,11 @@ ethers = { version = "2.0.4" } ethers-providers = "2.0.4" ethers-solc = "2.0.4" hex = "0.4.3" - -# This crate requires a newer version than 0.1.2-patch.1 that's used elsewhere -# in this workspace. However not pinning any revision currently breaks -# dependency resolution. jf-plonk = { git = "https://github.com/EspressoSystems/jellyfish", features = ["test_apis"], branch = "more-test-apis" } jf-primitives = { git = "https://github.com/EspressoSystems/jellyfish", features = ["std"], branch = "more-test-apis" } jf-utils = { git = "https://github.com/EspressoSystems/jellyfish", branch = "more-test-apis" } +num-bigint = { version = "0.4", default-features = false } +num-traits = { version = "0.2", default-features = false } sequencer-utils = { path = "../../utils" } sha3 = { version = "0.10.8", default-features = false } diff --git a/contracts/rust/src/bin/diff_test.rs b/contracts/rust/src/bin/diff_test.rs index 3a42f1bb36..755c068bda 100644 --- a/contracts/rust/src/bin/diff_test.rs +++ b/contracts/rust/src/bin/diff_test.rs @@ -1,9 +1,9 @@ use std::str::FromStr; -use ark_bn254::{Bn254, Fr, G1Affine}; +use ark_bn254::{Bn254, Fq, Fr, G1Affine, G2Affine}; use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ec::AffineRepr; -use ark_ff::{BigInteger, PrimeField}; +use ark_ff::{BigInteger, Fp2, MontFp, PrimeField}; use ark_poly::domain::radix2::Radix2EvaluationDomain; use ark_poly::EvaluationDomain; use clap::{Parser, ValueEnum}; @@ -12,12 +12,15 @@ use ethers::{ prelude::{AbiError, EthAbiCodec, EthAbiType}, types::{Bytes, H256, U256}, }; +use jf_plonk::proof_system::structs::{OpenKey, VerifyingKey}; use jf_plonk::{ constants::KECCAK256_STATE_SIZE, testing_apis::Verifier, transcript::{PlonkTranscript, SolidityTranscript}, }; use jf_primitives::pcs::prelude::Commitment; +use num_bigint::BigUint; +use num_traits::Num; #[derive(Parser)] #[command(author, version, about, long_about=None)] @@ -49,6 +52,10 @@ enum Action { TranscriptAppendGroup, /// Get jf_plonk::Transcript::get_and_append_challenge() TranscriptGetChal, + /// Get jf_plonk::Transcript::append_vk_and_pub_input() + TranscriptAppendVkAndPi, + /// Return the Plonk Verifier related constants + PlonkConstants, /// Test only logic TestOnly, } @@ -152,13 +159,34 @@ fn main() { let res = (updated_t, field_to_u256(chal)); println!("{}", res.encode_hex()); } + Action::TranscriptAppendVkAndPi => { + let arg1 = cli.arg1.as_ref().expect("Should provide arg1=transcript"); + let arg2 = cli.arg2.as_ref().expect("Should provide arg2=verifyingKey"); + let arg3 = cli.arg3.as_ref().expect("Should provide arg3=publicInput"); + + let t_parsed = arg1.parse::().unwrap(); + let vk_parsed = arg2.parse::().unwrap(); + let pi_u256: Vec = AbiDecode::decode_hex(arg3).unwrap(); + let pi: Vec = pi_u256.into_iter().map(u256_to_field).collect(); + + let mut t: SolidityTranscript = t_parsed.into(); + let vk: VerifyingKey = vk_parsed.into(); + t.append_vk_and_pub_input(&vk, &pi).unwrap(); + + let res: ParsedTranscript = t.into(); + println!("{}", (res,).encode_hex()); + } + Action::PlonkConstants => { + unimplemented!() + } Action::TestOnly => { let arg1 = cli.arg1.as_ref().expect("Should provide arg1=transcript"); - let t_parsed = { - let parsed: (ParsedTranscript,) = AbiDecode::decode_hex(arg1).unwrap(); - parsed.0 - }; - println!("{}", (t_parsed,).encode_hex()); + let vk_parsed = arg1.parse::().unwrap(); + + let vk: VerifyingKey = vk_parsed.into(); + + let res: ParsedVerifyingKey = vk.into(); + println!("{}", (res,).encode_hex()); } }; } @@ -166,6 +194,120 @@ fn main() { // ------- Helper functions and structs -------- // --------------------------------------------- +// constant in hex string copied from hardcoded constants from solidity contracts + +// TODO: (alex) change to simply using `MontFp!("0x..")` after +// is on a tag release +// Return cosets coefficients for circuits over BN254. +fn coset_k() -> Vec { + vec![ + Fr::from(BigUint::from_str_radix("1", 16).unwrap()), + Fr::from( + BigUint::from_str_radix( + "2f8dd1f1a7583c42c4e12a44e110404c73ca6c94813f85835da4fb7bb1301d4a", + 16, + ) + .unwrap(), + ), + Fr::from( + BigUint::from_str_radix( + "1ee678a0470a75a6eaa8fe837060498ba828a3703b311d0f77f010424afeb025", + 16, + ) + .unwrap(), + ), + Fr::from( + BigUint::from_str_radix( + "2042a587a90c187b0a087c03e29c968b950b1db26d5c82d666905a6895790c0a", + 16, + ) + .unwrap(), + ), + Fr::from( + BigUint::from_str_radix( + "2e2b91456103698adf57b799969dea1c8f739da5d8d40dd3eb9222db7c81e881", + 16, + ) + .unwrap(), + ), + ] +} + +/// Returns `OpenKeys` for KZG10 over BN254 curve from Aztec's SRS +fn open_key() -> OpenKey { + let g = G1Affine::new_unchecked(MontFp!("1"), MontFp!("2")); + let h = G2Affine::new_unchecked( + Fp2::new( + Fq::from( + BigUint::from_str_radix( + "198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2", + 16, + ) + .unwrap(), + ), + Fq::from( + BigUint::from_str_radix( + "1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed", + 16, + ) + .unwrap(), + ), + ), + Fp2::new( + Fq::from( + BigUint::from_str_radix( + "090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b", + 16, + ) + .unwrap(), + ), + Fq::from( + BigUint::from_str_radix( + "12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + 16, + ) + .unwrap(), + ), + ), + ); + let beta_h = G2Affine::new_unchecked( + Fp2::new( + Fq::from( + BigUint::from_str_radix( + "260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1", + 16, + ) + .unwrap(), + ), + Fq::from( + BigUint::from_str_radix( + "0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0", + 16, + ) + .unwrap(), + ), + ), + Fp2::new( + Fq::from( + BigUint::from_str_radix( + "04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4", + 16, + ) + .unwrap(), + ), + Fq::from( + BigUint::from_str_radix( + "22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55", + 16, + ) + .unwrap(), + ), + ), + ); + + OpenKey { g, h, beta_h } +} + fn field_to_u256(f: F) -> U256 { if F::MODULUS_BIT_SIZE > 256 { panic!("Shouldn't convert a >256-bit field to U256"); @@ -254,3 +396,102 @@ where ) } } + +/// intermediate representation of `VerifyingKey` in solidity. +#[derive(Clone, Debug, EthAbiType, EthAbiCodec)] +struct ParsedVerifyingKey { + domain_size: U256, + num_inputs: U256, + sigma_0: ParsedG1Point, + sigma_1: ParsedG1Point, + sigma_2: ParsedG1Point, + sigma_3: ParsedG1Point, + sigma_4: ParsedG1Point, + q_1: ParsedG1Point, + q_2: ParsedG1Point, + q_3: ParsedG1Point, + q_4: ParsedG1Point, + q_m_12: ParsedG1Point, + q_m_34: ParsedG1Point, + q_o: ParsedG1Point, + q_c: ParsedG1Point, + q_h_1: ParsedG1Point, + q_h_2: ParsedG1Point, + q_h_3: ParsedG1Point, + q_h_4: ParsedG1Point, + q_ecc: ParsedG1Point, +} + +impl FromStr for ParsedVerifyingKey { + type Err = AbiError; + fn from_str(s: &str) -> Result { + let parsed: (Self,) = AbiDecode::decode_hex(s)?; + Ok(parsed.0) + } +} + +impl From> for ParsedVerifyingKey { + fn from(vk: VerifyingKey) -> Self { + Self { + domain_size: U256::from(vk.domain_size), + num_inputs: U256::from(vk.num_inputs), + sigma_0: vk.sigma_comms[0].0.into(), + sigma_1: vk.sigma_comms[1].0.into(), + sigma_2: vk.sigma_comms[2].0.into(), + sigma_3: vk.sigma_comms[3].0.into(), + sigma_4: vk.sigma_comms[4].0.into(), + q_1: vk.selector_comms[0].0.into(), + q_2: vk.selector_comms[1].0.into(), + q_3: vk.selector_comms[2].0.into(), + q_4: vk.selector_comms[3].0.into(), + q_m_12: vk.selector_comms[4].0.into(), + q_m_34: vk.selector_comms[5].0.into(), + q_h_1: vk.selector_comms[6].0.into(), + q_h_2: vk.selector_comms[7].0.into(), + q_h_3: vk.selector_comms[8].0.into(), + q_h_4: vk.selector_comms[9].0.into(), + q_o: vk.selector_comms[10].0.into(), + q_c: vk.selector_comms[11].0.into(), + q_ecc: vk.selector_comms[12].0.into(), + } + } +} + +impl From for VerifyingKey { + fn from(vk: ParsedVerifyingKey) -> Self { + let sigma_comms = vec![ + Commitment::from(>::into(vk.sigma_0)), + Commitment::from(>::into(vk.sigma_1)), + Commitment::from(>::into(vk.sigma_2)), + Commitment::from(>::into(vk.sigma_3)), + Commitment::from(>::into(vk.sigma_4)), + ]; + + let selector_comms = vec![ + Commitment::from(>::into(vk.q_1)), + Commitment::from(>::into(vk.q_2)), + Commitment::from(>::into(vk.q_3)), + Commitment::from(>::into(vk.q_4)), + Commitment::from(>::into(vk.q_m_12)), + Commitment::from(>::into(vk.q_m_34)), + Commitment::from(>::into(vk.q_h_1)), + Commitment::from(>::into(vk.q_h_2)), + Commitment::from(>::into(vk.q_h_3)), + Commitment::from(>::into(vk.q_h_4)), + Commitment::from(>::into(vk.q_o)), + Commitment::from(>::into(vk.q_c)), + Commitment::from(>::into(vk.q_ecc)), + ]; + + Self { + domain_size: vk.domain_size.as_usize(), + num_inputs: vk.num_inputs.as_usize(), + sigma_comms, + selector_comms, + k: coset_k(), + open_key: open_key(), + is_merged: false, + plookup_vk: None, + } + } +} diff --git a/contracts/src/libraries/Transcript.sol b/contracts/src/libraries/Transcript.sol index 5fdbb7c9fd..e5d6a1f771 100644 --- a/contracts/src/libraries/Transcript.sol +++ b/contracts/src/libraries/Transcript.sol @@ -74,11 +74,11 @@ library Transcript { IPlonkVerifier.VerifyingKey memory verifyingKey, uint256[] memory publicInput ) internal pure { - uint64 sizeInBits = 254; + uint32 sizeInBits = 254; // Fr field size in bits appendMessage( - self, BytesLib.slice(abi.encodePacked(Utils.reverseEndianness(sizeInBits)), 0, 8) + self, BytesLib.slice(abi.encodePacked(Utils.reverseEndianness(sizeInBits)), 0, 4) ); // domain size diff --git a/contracts/test/Transcript.t.sol b/contracts/test/Transcript.t.sol index 92e08c4609..21272e753d 100644 --- a/contracts/test/Transcript.t.sol +++ b/contracts/test/Transcript.t.sol @@ -8,6 +8,7 @@ pragma solidity ^0.8.0; import "forge-std/Test.sol"; import { BN254 } from "bn254/BN254.sol"; import { IPlonkVerifier } from "../src/interfaces/IPlonkVerifier.sol"; +import { VkTest } from "./stubs/Transfer1In2Out24DepthVk.sol"; // Target contract import { Transcript as T } from "../src/libraries/Transcript.sol"; @@ -130,35 +131,48 @@ contract Transcript_getAndAppendChallenge_Test is Test { } } -// contract Transcript_appendVkAndPubInput_Test is Test { -// // TODO: -// } - -// contract Transcript_appendProofEvaluations_Test is Test { -// // TODO: -// } - -contract WhateverTest is Test { - function test_whatever() external { - T.TranscriptData memory transcript; - transcript.transcript = "\x03\x04"; - transcript.state[0] = "a"; - transcript.state[1] = "b"; +contract Transcript_appendVkAndPubInput_Test is Test { + using T for T.TranscriptData; - // bytes memory message = "hi"; + /// forge-config: default.fuzz.runs = 5 + /// @dev Test if `appendVkAndPubInput` matches that of Jellyfish + function testFuzz_appendVkAndPubInput_matches( + T.TranscriptData memory transcript, + uint256[] memory publicInput + ) external { + for (uint256 i = 0; i < publicInput.length; i++) { + publicInput[i] = bound(publicInput[i], 0, BN254.R_MOD - 1); + BN254.validateScalarField(publicInput[i]); + } + IPlonkVerifier.VerifyingKey memory vk = VkTest.getVk(); - string[] memory cmds = new string[](6); - // string[] memory cmds = new string[](7); + string[] memory cmds = new string[](8); cmds[0] = "cargo"; cmds[1] = "run"; cmds[2] = "--bin"; cmds[3] = "diff-test"; - cmds[4] = "test-only"; + cmds[4] = "transcript-append-vk-and-pi"; cmds[5] = vm.toString(abi.encode(transcript)); - // cmds[6] = vm.toString(message); + cmds[6] = vm.toString(abi.encode(vk)); + cmds[7] = vm.toString(abi.encode(publicInput)); bytes memory result = vm.ffi(cmds); - (T.TranscriptData memory recv) = abi.decode(result, (T.TranscriptData)); - assertEq(recv.transcript, transcript.transcript); + (T.TranscriptData memory updated) = abi.decode(result, (T.TranscriptData)); + + transcript.appendVkAndPubInput(vk, publicInput); + + assertEq(updated.transcript, transcript.transcript, "transcript field mismatch"); + assertEq(updated.state[0], transcript.state[0], "state[0] field mismatch"); + assertEq(updated.state[1], transcript.state[1], "state[1] field mismatch"); } } + +// contract Transcript_appendProofEvaluations_Test is Test { +// // TODO: +// } + +// contract WhateverTest is Test { +// function test_whatever() external { +// return; +// } +// } diff --git a/contracts/test/stubs/Transfer1In2Out24DepthVk.sol b/contracts/test/stubs/Transfer1In2Out24DepthVk.sol new file mode 100644 index 0000000000..cbd4f4bb0e --- /dev/null +++ b/contracts/test/stubs/Transfer1In2Out24DepthVk.sol @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// +// Copyright (c) 2022 Espresso Systems (espressosys.com) +// This file is part of the Configurable Asset Privacy for Ethereum (CAPE) library. +// +// This program is free software: you can redistribute it and/or modify it under the terms of the +// GNU General Public License as published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +// even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// You should have received a copy of the GNU General Public License along with this program. If +// not, see . + +// NOTE: DO NOT MODIFY! GENERATED BY SCRIPT VIA `cargo run --bin gen-vk-libraries --release`. +pragma solidity ^0.8.0; + +import { BN254 } from "bn254/BN254.sol"; +import { IPlonkVerifier } from "../../src/interfaces/IPlonkVerifier.sol"; + +library VkTest { + function getVk() internal pure returns (IPlonkVerifier.VerifyingKey memory vk) { + assembly { + // domain size + mstore(vk, 32768) + // num of public inputs + mstore(add(vk, 0x20), 14) + + // sigma0 + mstore( + mload(add(vk, 0x40)), + 6451930258054036397165544866644311272180786776693649154889113517935138989324 + ) + mstore( + add(mload(add(vk, 0x40)), 0x20), + 15824498031290932840309269587075035510403426361110328301862825820425402064333 + ) + // sigma1 + mstore( + mload(add(vk, 0x60)), + 16567945706248183214406921539823721483157024902030706018155219832331943151521 + ) + mstore( + add(mload(add(vk, 0x60)), 0x20), + 14506648136467119081958160505454685757895812203258866143116417397069305366174 + ) + // sigma2 + mstore( + mload(add(vk, 0x80)), + 16908805137848644970538829805684573945187052776129406508429516788865993229946 + ) + mstore( + add(mload(add(vk, 0x80)), 0x20), + 13370902069114408370627021011309095482019563080650295231694581484651030202227 + ) + // sigma3 + mstore( + mload(add(vk, 0xa0)), + 11385428061273012554614867838291301202096376350855764984558871671579621291507 + ) + mstore( + add(mload(add(vk, 0xa0)), 0x20), + 18938480909096008246537758317235530495583632544865390355616243879170108311037 + ) + // sigma4 + mstore( + mload(add(vk, 0xc0)), + 7250836052061444170671162428779548720754588271620290284029438087321333136859 + ) + mstore( + add(mload(add(vk, 0xc0)), 0x20), + 9774478170511284714380468511107372909275276960243638784016266344709965751507 + ) + + // q1 + mstore( + mload(add(vk, 0xe0)), + 2164661706057106993702119971892524764909406587180616475316536801798272746351 + ) + mstore( + add(mload(add(vk, 0xe0)), 0x20), + 7993083931046493938644389635874939373576598203553188654440768055247347522377 + ) + // q2 + mstore( + mload(add(vk, 0x100)), + 17875027092910639802264620931724329796279457509298747494670931666396434012177 + ) + mstore( + add(mload(add(vk, 0x100)), 0x20), + 12276180841132702377773827582398158204508221552359644390751974783173207949116 + ) + // q3 + mstore( + mload(add(vk, 0x120)), + 6923045257159434019788850173231395134054684072354814328515094196682490129996 + ) + mstore( + add(mload(add(vk, 0x120)), 0x20), + 10297389981574891432841377306749459633586002482842974197875786670892058142179 + ) + // q4 + mstore( + mload(add(vk, 0x140)), + 13566140293342467207563198706820126266175769850278450464476746689910443370750 + ) + mstore( + add(mload(add(vk, 0x140)), 0x20), + 4337013617009771491102950113766314929630396941539697665107262932887431611820 + ) + + // qM12 + mstore( + mload(add(vk, 0x160)), + 19545356440018631139549838928930231615194677294299230322568967706100221743452 + ) + mstore( + add(mload(add(vk, 0x160)), 0x20), + 3905268653568739552774781017975590296651581349403516285498718251384231803637 + ) + // qM34 + mstore( + mload(add(vk, 0x180)), + 3633513776458243190609011598510312470369153119749343878250857605063953894824 + ) + mstore( + add(mload(add(vk, 0x180)), 0x20), + 10348854780537633653024803962077925757963724802390956695225993897601858375068 + ) + + // qO + mstore( + mload(add(vk, 0x1a0)), + 10515123958235902109894586452633863486298290064878690665500349352367945576213 + ) + mstore( + add(mload(add(vk, 0x1a0)), 0x20), + 20835963785046732330293306231553834880816750576829504030205004088050809531737 + ) + // qC + mstore( + mload(add(vk, 0x1c0)), + 10349250837084111252673833558497412287345352572732754388450385078539897036072 + ) + mstore( + add(mload(add(vk, 0x1c0)), 0x20), + 1295954576893766564415821998145161393110346678014886452040838119568563355556 + ) + // qH1 + mstore( + mload(add(vk, 0x1e0)), + 18595738613642013642528283665640490180800278502934355301953048187579782737773 + ) + mstore( + add(mload(add(vk, 0x1e0)), 0x20), + 5708601727819525671780050950771464619626673626810479676243974296923430650735 + ) + // qH2 + mstore( + mload(add(vk, 0x200)), + 8105844768413379370590866345497514518639783589779028631263566798017351944465 + ) + mstore( + add(mload(add(vk, 0x200)), 0x20), + 13767799708582015119198203890136804463714948257729839866946279972890684141171 + ) + // qH3 + mstore( + mload(add(vk, 0x220)), + 13976995316216184532948677497270469464100744949177652840098916826286666391978 + ) + mstore( + add(mload(add(vk, 0x220)), 0x20), + 8782060747227562892357029272916715317651514559557103332761644499318601665300 + ) + // qH4 + mstore( + mload(add(vk, 0x240)), + 10423258206189675762927713311069351374538317153673220039972782365668263479097 + ) + mstore( + add(mload(add(vk, 0x240)), 0x20), + 12712089727236847935392559371166622501626155101609755726562266635070650647609 + ) + // qEcc + mstore( + mload(add(vk, 0x260)), + 3447947975392962233948092031223758925923495365282112464857270024948603045088 + ) + mstore( + add(mload(add(vk, 0x260)), 0x20), + 4655198050073279486560411245172865913095816956325221266986314415391129730949 + ) + } + } +} From 2887bba95beff577c2bf52b2d7e5cf818f309293 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Sat, 4 Nov 2023 01:31:26 +0800 Subject: [PATCH 09/38] finish tests for Transcript.sol --- Cargo.lock | 8 +- contracts/rust/src/bin/diff_test.rs | 181 +++++++++++++++++++++++++++- contracts/test/Transcript.t.sol | 34 ++++-- 3 files changed, 204 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d1fcd9257..6b9a81ae68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4179,7 +4179,7 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jf-plonk" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#92bb74afeb894473116eb484ca12118e528365ec" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#f32b1160e71dc5d5c4e0d92de46b688d68a6c385" dependencies = [ "ark-ec 0.4.2", "ark-ff 0.4.2", @@ -4208,7 +4208,7 @@ dependencies = [ [[package]] name = "jf-primitives" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#92bb74afeb894473116eb484ca12118e528365ec" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#f32b1160e71dc5d5c4e0d92de46b688d68a6c385" dependencies = [ "anyhow", "ark-bls12-377", @@ -4296,7 +4296,7 @@ dependencies = [ [[package]] name = "jf-relation" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#92bb74afeb894473116eb484ca12118e528365ec" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#f32b1160e71dc5d5c4e0d92de46b688d68a6c385" dependencies = [ "ark-bls12-377", "ark-bls12-381 0.4.0", @@ -4348,7 +4348,7 @@ dependencies = [ [[package]] name = "jf-utils" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#92bb74afeb894473116eb484ca12118e528365ec" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#f32b1160e71dc5d5c4e0d92de46b688d68a6c385" dependencies = [ "ark-ec 0.4.2", "ark-ff 0.4.2", diff --git a/contracts/rust/src/bin/diff_test.rs b/contracts/rust/src/bin/diff_test.rs index 755c068bda..a393b97a3c 100644 --- a/contracts/rust/src/bin/diff_test.rs +++ b/contracts/rust/src/bin/diff_test.rs @@ -1,18 +1,19 @@ use std::str::FromStr; -use ark_bn254::{Bn254, Fq, Fr, G1Affine, G2Affine}; +use ark_bn254::{g1, Bn254, Fq, Fr, G1Affine, G2Affine}; use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ec::AffineRepr; use ark_ff::{BigInteger, Fp2, MontFp, PrimeField}; use ark_poly::domain::radix2::Radix2EvaluationDomain; use ark_poly::EvaluationDomain; +use ark_std::{rand::Rng, UniformRand}; use clap::{Parser, ValueEnum}; use ethers::{ abi::{AbiDecode, AbiEncode}, prelude::{AbiError, EthAbiCodec, EthAbiType}, types::{Bytes, H256, U256}, }; -use jf_plonk::proof_system::structs::{OpenKey, VerifyingKey}; +use jf_plonk::proof_system::structs::{OpenKey, Proof, ProofEvaluations, VerifyingKey}; use jf_plonk::{ constants::KECCAK256_STATE_SIZE, testing_apis::Verifier, @@ -54,6 +55,8 @@ enum Action { TranscriptGetChal, /// Get jf_plonk::Transcript::append_vk_and_pub_input() TranscriptAppendVkAndPi, + /// Get jf_plonk::Transcript::append_proof_evaluations() + TranscriptAppendProofEvals, /// Return the Plonk Verifier related constants PlonkConstants, /// Test only logic @@ -176,16 +179,35 @@ fn main() { let res: ParsedTranscript = t.into(); println!("{}", (res,).encode_hex()); } + Action::TranscriptAppendProofEvals => { + let mut rng = jf_utils::test_rng(); + + let arg1 = cli.arg1.as_ref().expect("Should provide arg1=transcript"); + let t_parsed = arg1.parse::().unwrap(); + let proof_parsed = ParsedPlonkProof::dummy_with_rand_proof_evals(&mut rng); + let proof: Proof = proof_parsed.clone().into(); + + let mut t: SolidityTranscript = t_parsed.into(); + >::append_proof_evaluations::( + &mut t, + &proof.poly_evals, + ) + .unwrap(); + + let t_updated: ParsedTranscript = t.into(); + let res = (t_updated, proof_parsed); + println!("{}", res.encode_hex()); + } Action::PlonkConstants => { unimplemented!() } Action::TestOnly => { - let arg1 = cli.arg1.as_ref().expect("Should provide arg1=transcript"); - let vk_parsed = arg1.parse::().unwrap(); + let arg1 = cli.arg1.as_ref().expect("Should provide arg1=proof"); + let proof_parsed = arg1.parse::().unwrap(); - let vk: VerifyingKey = vk_parsed.into(); + let proof: Proof = proof_parsed.into(); - let res: ParsedVerifyingKey = vk.into(); + let res: ParsedPlonkProof = proof.into(); println!("{}", (res,).encode_hex()); } }; @@ -365,6 +387,13 @@ struct ParsedG1Point { y: U256, } +impl Default for ParsedG1Point { + fn default() -> Self { + let point = Affine::::new_unchecked(MontFp!("1"), MontFp!("2")); + point.into() + } +} + impl FromStr for ParsedG1Point { type Err = AbiError; fn from_str(s: &str) -> Result { @@ -495,3 +524,143 @@ impl From for VerifyingKey { } } } + +/// intermediate representation of `PlonkProof` in solidity +#[derive(Clone, Debug, Default, EthAbiType, EthAbiCodec)] +struct ParsedPlonkProof { + // commitments + wire_0: ParsedG1Point, + wire_1: ParsedG1Point, + wire_2: ParsedG1Point, + wire_3: ParsedG1Point, + wire_4: ParsedG1Point, + prod_perm: ParsedG1Point, + split_0: ParsedG1Point, + split_1: ParsedG1Point, + split_2: ParsedG1Point, + split_3: ParsedG1Point, + split_4: ParsedG1Point, + zeta: ParsedG1Point, + zeta_omega: ParsedG1Point, + // proof evals + wire_eval_0: U256, + wire_eval_1: U256, + wire_eval_2: U256, + wire_eval_3: U256, + wire_eval_4: U256, + sigma_eval_0: U256, + sigma_eval_1: U256, + sigma_eval_2: U256, + sigma_eval_3: U256, + prod_perm_zeta_omega_eval: U256, +} + +impl FromStr for ParsedPlonkProof { + type Err = AbiError; + fn from_str(s: &str) -> Result { + let parsed: (Self,) = AbiDecode::decode_hex(s)?; + Ok(parsed.0) + } +} + +impl From> for ParsedPlonkProof { + fn from(proof: Proof) -> Self { + Self { + wire_0: proof.wires_poly_comms[0].0.into(), + wire_1: proof.wires_poly_comms[1].0.into(), + wire_2: proof.wires_poly_comms[2].0.into(), + wire_3: proof.wires_poly_comms[3].0.into(), + wire_4: proof.wires_poly_comms[4].0.into(), + prod_perm: proof.prod_perm_poly_comm.0.into(), + split_0: proof.split_quot_poly_comms[0].0.into(), + split_1: proof.split_quot_poly_comms[1].0.into(), + split_2: proof.split_quot_poly_comms[2].0.into(), + split_3: proof.split_quot_poly_comms[3].0.into(), + split_4: proof.split_quot_poly_comms[4].0.into(), + zeta: proof.opening_proof.0.into(), + zeta_omega: proof.shifted_opening_proof.0.into(), + wire_eval_0: field_to_u256(proof.poly_evals.wires_evals[0]), + wire_eval_1: field_to_u256(proof.poly_evals.wires_evals[1]), + wire_eval_2: field_to_u256(proof.poly_evals.wires_evals[2]), + wire_eval_3: field_to_u256(proof.poly_evals.wires_evals[3]), + wire_eval_4: field_to_u256(proof.poly_evals.wires_evals[4]), + sigma_eval_0: field_to_u256(proof.poly_evals.wire_sigma_evals[0]), + sigma_eval_1: field_to_u256(proof.poly_evals.wire_sigma_evals[1]), + sigma_eval_2: field_to_u256(proof.poly_evals.wire_sigma_evals[2]), + sigma_eval_3: field_to_u256(proof.poly_evals.wire_sigma_evals[3]), + prod_perm_zeta_omega_eval: field_to_u256(proof.poly_evals.perm_next_eval), + } + } +} + +impl From for Proof { + fn from(proof: ParsedPlonkProof) -> Self { + let wires_poly_comms = vec![ + Commitment::from(>::into(proof.wire_0)), + Commitment::from(>::into(proof.wire_1)), + Commitment::from(>::into(proof.wire_2)), + Commitment::from(>::into(proof.wire_3)), + Commitment::from(>::into(proof.wire_4)), + ]; + let split_quot_poly_comms = vec![ + Commitment::from(>::into(proof.split_0)), + Commitment::from(>::into(proof.split_1)), + Commitment::from(>::into(proof.split_2)), + Commitment::from(>::into(proof.split_3)), + Commitment::from(>::into(proof.split_4)), + ]; + let prod_perm_poly_comm = + Commitment::from(>::into(proof.prod_perm)); + let opening_proof = Commitment::from(>::into(proof.zeta)); + let shifted_opening_proof = + Commitment::from(>::into(proof.zeta_omega)); + + let wires_evals = vec![ + u256_to_field(proof.wire_eval_0), + u256_to_field(proof.wire_eval_1), + u256_to_field(proof.wire_eval_2), + u256_to_field(proof.wire_eval_3), + u256_to_field(proof.wire_eval_4), + ]; + let wire_sigma_evals = vec![ + u256_to_field(proof.sigma_eval_0), + u256_to_field(proof.sigma_eval_1), + u256_to_field(proof.sigma_eval_2), + u256_to_field(proof.sigma_eval_3), + ]; + let perm_next_eval = u256_to_field(proof.prod_perm_zeta_omega_eval); + + Self { + wires_poly_comms, + prod_perm_poly_comm, + split_quot_poly_comms, + opening_proof, + shifted_opening_proof, + poly_evals: ProofEvaluations { + wires_evals, + wire_sigma_evals, + perm_next_eval, + }, + plookup_proof: None, + } + } +} + +impl ParsedPlonkProof { + // return a dummy proof instance with random ProofEvaluations fields. + fn dummy_with_rand_proof_evals(rng: &mut R) -> Self { + Self { + wire_eval_0: field_to_u256(Fr::rand(rng)), + wire_eval_1: field_to_u256(Fr::rand(rng)), + wire_eval_2: field_to_u256(Fr::rand(rng)), + wire_eval_3: field_to_u256(Fr::rand(rng)), + wire_eval_4: field_to_u256(Fr::rand(rng)), + sigma_eval_0: field_to_u256(Fr::rand(rng)), + sigma_eval_1: field_to_u256(Fr::rand(rng)), + sigma_eval_2: field_to_u256(Fr::rand(rng)), + sigma_eval_3: field_to_u256(Fr::rand(rng)), + prod_perm_zeta_omega_eval: field_to_u256(Fr::rand(rng)), + ..Default::default() + } + } +} diff --git a/contracts/test/Transcript.t.sol b/contracts/test/Transcript.t.sol index 21272e753d..527d3c7b5f 100644 --- a/contracts/test/Transcript.t.sol +++ b/contracts/test/Transcript.t.sol @@ -167,12 +167,28 @@ contract Transcript_appendVkAndPubInput_Test is Test { } } -// contract Transcript_appendProofEvaluations_Test is Test { -// // TODO: -// } - -// contract WhateverTest is Test { -// function test_whatever() external { -// return; -// } -// } +contract Transcript_appendProofEvaluations_Test is Test { + using T for T.TranscriptData; + + /// forge-config: default.fuzz.runs = 5 + /// @dev Test if `appendProofEvaluations` matches that of Jellyfish + function testFuzz_appendProofEvaluations_matches(T.TranscriptData memory transcript) external { + string[] memory cmds = new string[](6); + cmds[0] = "cargo"; + cmds[1] = "run"; + cmds[2] = "--bin"; + cmds[3] = "diff-test"; + cmds[4] = "transcript-append-proof-evals"; + cmds[5] = vm.toString(abi.encode(transcript)); + + bytes memory result = vm.ffi(cmds); + (T.TranscriptData memory updated, IPlonkVerifier.PlonkProof memory proof) = + abi.decode(result, (T.TranscriptData, IPlonkVerifier.PlonkProof)); + + transcript.appendProofEvaluations(proof); + + assertEq(updated.transcript, transcript.transcript, "transcript field mismatch"); + assertEq(updated.state[0], transcript.state[0], "state[0] field mismatch"); + assertEq(updated.state[1], transcript.state[1], "state[1] field mismatch"); + } +} From 6807ac8cf5a68ced48b8ccee67e6827bc02caedd Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Sat, 4 Nov 2023 01:37:15 +0800 Subject: [PATCH 10/38] vm.assume -> bound when possible --- contracts/test/PolynomialEval.t.sol | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/contracts/test/PolynomialEval.t.sol b/contracts/test/PolynomialEval.t.sol index 305a5d8368..cf256de6b1 100644 --- a/contracts/test/PolynomialEval.t.sol +++ b/contracts/test/PolynomialEval.t.sol @@ -34,6 +34,7 @@ contract PolynomialEval_newEvalDomain_Test is Test { } } + /// forge-config: default.fuzz.runs = 20 /// @dev Test revert if domainSize is not among {2^14, 2^15, 2^16, 2^17} function testFuzz_unsupportedDomainSize_reverts(uint256 domainSize) external { vm.assume( @@ -49,8 +50,8 @@ contract PolynomialEval_newEvalDomain_Test is Test { contract PolynomialEval_domainElements_Test is Test { /// @dev Test if the domain elements are generated correctly /// forge-config: default.fuzz.runs = 25 - function testFuzz_domainElements_matches(uint8 logSize, uint256 length) external { - vm.assume(14 <= logSize && logSize <= 17); + function testFuzz_domainElements_matches(uint256 logSize, uint256 length) external { + logSize = bound(logSize, 14, 17); Poly.EvalDomain memory domain = Poly.newEvalDomain(2 ** logSize); if (length > domain.size || length == 0) { @@ -78,16 +79,20 @@ contract PolynomialEval_evalDataGen_Test is Test { /// @dev Test if evaluations on the vanishing poly, the lagrange one poly, and the public input /// poly are correct. /// forge-config: default.fuzz.runs = 10 - function testFuzz_evalDataGen_matches(uint8 logSize, uint256 zeta, uint256[] memory publicInput) - external - { - vm.assume(14 <= logSize && logSize <= 17); - vm.assume(zeta < BN254.R_MOD); + function testFuzz_evalDataGen_matches( + uint256 logSize, + uint256 zeta, + uint256[] memory publicInput + ) external { + logSize = bound(logSize, 14, 17); + zeta = bound(zeta, 0, BN254.R_MOD - 1); + BN254.validateScalarField(zeta); vm.assume(publicInput.length > 0); // Since these user-provided `publicInputs` were checked outside before passing in via // `BN254.validateScalarField()`, it suffices to assume they are proper for our test here. for (uint256 i = 0; i < publicInput.length; i++) { - vm.assume(publicInput[i] < BN254.R_MOD); + publicInput[i] = bound(publicInput[i], 0, BN254.R_MOD - 1); + BN254.validateScalarField(publicInput[i]); } Poly.EvalDomain memory domain = Poly.newEvalDomain(2 ** logSize); From e0a3e31bcd1e01a01be938da769d3aeb82ebfc2c Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Sat, 4 Nov 2023 11:11:13 +0800 Subject: [PATCH 11/38] add extra fuzzy input constraint on zeta value --- contracts/test/PolynomialEval.t.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/test/PolynomialEval.t.sol b/contracts/test/PolynomialEval.t.sol index cf256de6b1..57871cfb42 100644 --- a/contracts/test/PolynomialEval.t.sol +++ b/contracts/test/PolynomialEval.t.sol @@ -86,6 +86,7 @@ contract PolynomialEval_evalDataGen_Test is Test { ) external { logSize = bound(logSize, 14, 17); zeta = bound(zeta, 0, BN254.R_MOD - 1); + vm.assume(zeta != 0); // otherwise divisor of lagrange_one_poly would be zero BN254.validateScalarField(zeta); vm.assume(publicInput.length > 0); // Since these user-provided `publicInputs` were checked outside before passing in via From 6bc9d0b154dd8f9c8b65c117c2942c2f21a00403 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Mon, 6 Nov 2023 19:01:39 +0800 Subject: [PATCH 12/38] wip: two more plonkverifier test --- contract-bindings/src/plonk_verifier.rs | 4 +- contracts/rust/src/bin/diff_test.rs | 136 ++++++++++++- contracts/src/libraries/PlonkVerifier.sol | 80 ++++---- contracts/test/PlonkVerifier.t.sol | 182 ++++++++++++++++++ .../test/stubs/Transfer1In2Out24DepthVk.sol | 3 +- 5 files changed, 360 insertions(+), 45 deletions(-) create mode 100644 contracts/test/PlonkVerifier.t.sol diff --git a/contract-bindings/src/plonk_verifier.rs b/contract-bindings/src/plonk_verifier.rs index 5f3b870b7f..df02021f19 100644 --- a/contract-bindings/src/plonk_verifier.rs +++ b/contract-bindings/src/plonk_verifier.rs @@ -261,12 +261,12 @@ pub mod plonk_verifier { pub static PLONKVERIFIER_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); #[rustfmt::skip] - const __BYTECODE: &[u8] = b"a9\x8Da\0:`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14a\0-WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\x046\x10a\x005W`\x005`\xE0\x1C\x80c6\xD8\xD6\xEB\x14a\0:W[`\0\x80\xFD[a\0Ma\0H6`\x04a5vV[a\0aV[`@Q\x90\x15\x15\x81R` \x01`@Q\x80\x91\x03\x90\xF3[`\0\x82Q\x85Q\x14\x15\x80a\0vWP\x82Q\x84Q\x14\x15[\x80a\0\x83WP\x82Q\x82Q\x14\x15[\x80a\0\x8DWP\x82Q\x15[\x15a\0\xABW`@Qc\xFD\x9A-\x1B`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0\x83Q`\x01`\x01`@\x1B\x03\x81\x11\x15a\0\xC6Wa\0\xC6a0\xB1V[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\0\xFFW\x81` \x01[a\0\xECa/\xC3V[\x81R` \x01\x90`\x01\x90\x03\x90\x81a\0\xE4W\x90P[P\x90P`\0[\x84Q\x81\x10\x15a\x02CWa\x010\x85\x82\x81Q\x81\x10a\x01#Wa\x01#a7\xF8V[` \x02` \x01\x01Qa\x02YV[`\0[\x86\x82\x81Q\x81\x10a\x01EWa\x01Ea7\xF8V[` \x02` \x01\x01QQ\x81\x10\x15a\x01\xA2Wa\x01\x90\x87\x83\x81Q\x81\x10a\x01jWa\x01ja7\xF8V[` \x02` \x01\x01Q\x82\x81Q\x81\x10a\x01\x83Wa\x01\x83a7\xF8V[` \x02` \x01\x01Qa\x03\x86V[\x80a\x01\x9A\x81a8$V[\x91PPa\x013V[Pa\x02\x13\x87\x82\x81Q\x81\x10a\x01\xB8Wa\x01\xB8a7\xF8V[` \x02` \x01\x01Q\x87\x83\x81Q\x81\x10a\x01\xD2Wa\x01\xD2a7\xF8V[` \x02` \x01\x01Q\x87\x84\x81Q\x81\x10a\x01\xECWa\x01\xECa7\xF8V[` \x02` \x01\x01Q\x87\x85\x81Q\x81\x10a\x02\x06Wa\x02\x06a7\xF8V[` \x02` \x01\x01Qa\x03\xEDV[\x82\x82\x81Q\x81\x10a\x02%Wa\x02%a7\xF8V[` \x02` \x01\x01\x81\x90RP\x80\x80a\x02;\x90a8$V[\x91PPa\x01\x05V[Pa\x02M\x81a\x05EV[\x91PP[\x94\x93PPPPV[\x80Qa\x02d\x90a\x0C\xE8V[a\x02q\x81` \x01Qa\x0C\xE8V[a\x02~\x81`@\x01Qa\x0C\xE8V[a\x02\x8B\x81``\x01Qa\x0C\xE8V[a\x02\x98\x81`\x80\x01Qa\x0C\xE8V[a\x02\xA5\x81`\xA0\x01Qa\x0C\xE8V[a\x02\xB2\x81`\xC0\x01Qa\x0C\xE8V[a\x02\xBF\x81`\xE0\x01Qa\x0C\xE8V[a\x02\xCD\x81a\x01\0\x01Qa\x0C\xE8V[a\x02\xDB\x81a\x01 \x01Qa\x0C\xE8V[a\x02\xE9\x81a\x01@\x01Qa\x0C\xE8V[a\x02\xF7\x81a\x01`\x01Qa\x0C\xE8V[a\x03\x05\x81a\x01\xA0\x01Qa\x03\x86V[a\x03\x13\x81a\x01\xC0\x01Qa\x03\x86V[a\x03!\x81a\x01\xE0\x01Qa\x03\x86V[a\x03/\x81a\x02\0\x01Qa\x03\x86V[a\x03=\x81a\x02 \x01Qa\x03\x86V[a\x03K\x81a\x02@\x01Qa\x03\x86V[a\x03Y\x81a\x02`\x01Qa\x03\x86V[a\x03g\x81a\x02\x80\x01Qa\x03\x86V[a\x03u\x81a\x02\xA0\x01Qa\x03\x86V[a\x03\x83\x81a\x02\xC0\x01Qa\x03\x86V[PV[`\0\x80Q` a98\x839\x81Q\x91R\x81\x10\x80a\x03\xE9W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FBn254: invalid scalar field\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[PPV[a\x03\xF5a/\xC3V[\x84` \x01Q\x84Q\x14a\x04\x1AW`@Qc \xFA\x9D\x89`\xE1\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0a\x04(\x86\x86\x86\x86a\rwV[\x90P`\0a\x049\x87`\0\x01Qa\x0FEV[\x90P`\0a\x04L\x82\x84`\xA0\x01Q\x89a\x11\xE1V[`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x91\x92P`\0\x91\x90` \x82\x01a\x03\xC0\x806\x837PP`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x92\x93P`\0\x92\x91P` \x82\x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x04\x8FW\x90PP\x90P`\0a\x04\xC8\x8B\x85\x8B\x89\x87\x87a\x12AV[`\xA0\x87\x01Q``\x87\x01Q\x91\x92P\x90`\0\x80Q` a98\x839\x81Q\x91R`\0\x81\x83\x85\t`@\x80Qa\x01\0\x81\x01\x82R`\xE0\x9C\x8D\x01Q\x81R` \x81\x01\x96\x90\x96R\x85\x01RPPP``\x81\x01\x91\x90\x91R`\x80\x81\x01\x92\x90\x92R`\xA0\x82\x01Ra\x01`\x87\x01Q`\xC0\x82\x01Ra\x01\x80\x90\x96\x01Q\x92\x86\x01\x92\x90\x92RP\x92\x95\x94PPPPPV[\x80Q`\0\x90`\0\x80Q` a98\x839\x81Q\x91R`\x01\x80\x83\x11\x15a\x05\xC6Wa\x05ka0=V[`\0[\x84\x81\x10\x15a\x05\xB8Wa\x05\xA6\x87\x82\x81Q\x81\x10a\x05\x8BWa\x05\x8Ba7\xF8V[` \x02` \x01\x01Q`\0\x01Q\x83a\x12j\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x80a\x05\xB0\x81a8$V[\x91PPa\x05nV[Pa\x05\xC2\x81a\x12tV[\x91PP[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`\0a\x05\xFB\x86`\x02a8=V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06\x12Wa\x06\x12a0\xB1V[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06;W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P`\0a\x06K\x87`\x02a8=V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06bWa\x06ba0\xB1V[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06\xA7W\x81` \x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x06\x80W\x90P[P\x90P`\x01`\0[\x88\x81\x10\x15a\x07\xF0W\x81\x84a\x06\xC4\x83`\x02a8=V[\x81Q\x81\x10a\x06\xD4Wa\x06\xD4a7\xF8V[` \x02` \x01\x01\x81\x81RPP\x8A\x81\x81Q\x81\x10a\x06\xF2Wa\x06\xF2a7\xF8V[` \x02` \x01\x01Q`\xC0\x01Q\x83\x82`\x02a\x07\x0C\x91\x90a8=V[\x81Q\x81\x10a\x07\x1CWa\x07\x1Ca7\xF8V[` \x02` \x01\x01\x81\x90RP`\0\x80\x8C\x83\x81Q\x81\x10a\x07\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x05`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\x0F\x84\x84a\x1AxV[\x80\x82Ra\x12\x1F\x90\x85\x90\x85\x90a\x1A\xCCV[` \x82\x01R\x80Qa\x125\x90\x85\x90\x84\x90\x86\x90a\x1B2V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12O\x85\x87\x89a\x1C\x88V[\x90Pa\x12_\x88\x86\x89\x89\x88\x88a\x1DtV[a\x0C\xDC\x81\x87\x86a \x80V[a\x03\xE9\x82\x82a \xD0V[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x12\x9C\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a8\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x12\xCDWa\x12\xCDa7\xF8V[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x12\xE9Wa\x12\xE9a7\xF8V[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x08\x94\x93\x92\x91\x90a8\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x138Wa\x138a7\xF8V[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13YWa\x13Ya7\xF8V[` \x02\x01\x81\x81RPPa\x02Qa\x13\x9C\x83\x83`@Q` \x01a\x13\x84\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a!\x03V[a\"\x10V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14D\x83`\0\x81Q\x81\x10a\x14\x1CWa\x14\x1Ca7\xF8V[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x147Wa\x147a7\xF8V[` \x02` \x01\x01Qa\"\x90V[\x90P`\x01[\x82Q\x81\x10\x15a\x14\x9EWa\x14\x8A\x82a\x14\x85\x86\x84\x81Q\x81\x10a\x14kWa\x14ka7\xF8V[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x147Wa\x147a7\xF8V[a#4V[\x91P\x80a\x14\x96\x81a8$V[\x91PPa\x14IV[P\x92\x91PPV[`\0a\x14\xBF`\0\x80Q` a98\x839\x81Q\x91R\x83a8\xCDV[a\x14\xD7\x90`\0\x80Q` a98\x839\x81Q\x91Ra8\xEFV[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x05WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a9\x18\x839\x81Q\x91R\x84` \x01Qa\x158\x91\x90a8\xCDV[a\x15P\x90`\0\x80Q` a9\x18\x839\x81Q\x91Ra8\xEFV[\x90R\x92\x91PPV[a\x15\x83`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x16\xFFW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\x1F\x91\x90\x83\x90` \x01a9\x02V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x17v\x84a\x17qa\x17G\x84a#\xDBV[`@Q` \x01a\x17Y\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x04a!\x03V[a\x17\x0BV[a\x17\xB4\x84a\x17qa\x17\x8A\x86`\0\x01Qa#\xDBV[`@Q` \x01a\x17\x9C\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a!\x03V[a\x17\xC8\x84a\x17qa\x17\x8A\x86` \x01Qa#\xDBV[a\x17\xD3\x84`\x01a \xD0V[a\x17\xFD\x84\x7F/\x8D\xD1\xF1\xA7X\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x05`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\x0F\x84\x84a\x1AxV[\x80\x82Ra\x12\x1F\x90\x85\x90\x85\x90a\x1A\xCCV[` \x82\x01R\x80Qa\x125\x90\x85\x90\x84\x90\x86\x90a\x1B2V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12O\x85\x87\x89a\x1C\x88V[\x90Pa\x12_\x88\x86\x89\x89\x88\x88a\x1DtV[a\x0C\xDC\x81\x87\x86a \x80V[a\x03\xE9\x82\x82a \xD0V[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x12\x9C\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a8\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x12\xCDWa\x12\xCDa7\xF8V[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x12\xE9Wa\x12\xE9a7\xF8V[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x08\x94\x93\x92\x91\x90a8\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x138Wa\x138a7\xF8V[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13YWa\x13Ya7\xF8V[` \x02\x01\x81\x81RPPa\x02Qa\x13\x9C\x83\x83`@Q` \x01a\x13\x84\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a!\x03V[a\"\x10V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14D\x83`\0\x81Q\x81\x10a\x14\x1CWa\x14\x1Ca7\xF8V[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x147Wa\x147a7\xF8V[` \x02` \x01\x01Qa\"\x90V[\x90P`\x01[\x82Q\x81\x10\x15a\x14\x9EWa\x14\x8A\x82a\x14\x85\x86\x84\x81Q\x81\x10a\x14kWa\x14ka7\xF8V[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x147Wa\x147a7\xF8V[a#4V[\x91P\x80a\x14\x96\x81a8$V[\x91PPa\x14IV[P\x92\x91PPV[`\0a\x14\xBF`\0\x80Q` a98\x839\x81Q\x91R\x83a8\xCDV[a\x14\xD7\x90`\0\x80Q` a98\x839\x81Q\x91Ra8\xEFV[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x05WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a9\x18\x839\x81Q\x91R\x84` \x01Qa\x158\x91\x90a8\xCDV[a\x15P\x90`\0\x80Q` a9\x18\x839\x81Q\x91Ra8\xEFV[\x90R\x92\x91PPV[a\x15\x83`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x16\xFFW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\x1F\x91\x90\x83\x90` \x01a9\x02V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x17v\x84a\x17qa\x17G\x84a#\xDBV[`@Q` \x01a\x17Y\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x04a!\x03V[a\x17\x0BV[a\x17\xB4\x84a\x17qa\x17\x8A\x86`\0\x01Qa#\xDBV[`@Q` \x01a\x17\x9C\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a!\x03V[a\x17\xC8\x84a\x17qa\x17\x8A\x86` \x01Qa#\xDBV[a\x17\xD3\x84`\x01a \xD0V[a\x17\xFD\x84\x7F/\x8D\xD1\xF1\xA7X\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x05`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\x0F\x84\x84a\x1AxV[\x80\x82Ra\x12\x1F\x90\x85\x90\x85\x90a\x1A\xCCV[` \x82\x01R\x80Qa\x125\x90\x85\x90\x84\x90\x86\x90a\x1B2V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12O\x85\x87\x89a\x1C\x88V[\x90Pa\x12_\x88\x86\x89\x89\x88\x88a\x1DtV[a\x0C\xDC\x81\x87\x86a \x80V[a\x03\xE9\x82\x82a \xD0V[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x12\x9C\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a8\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x12\xCDWa\x12\xCDa7\xF8V[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x12\xE9Wa\x12\xE9a7\xF8V[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x08\x94\x93\x92\x91\x90a8\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x138Wa\x138a7\xF8V[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13YWa\x13Ya7\xF8V[` \x02\x01\x81\x81RPPa\x02Qa\x13\x9C\x83\x83`@Q` \x01a\x13\x84\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a!\x03V[a\"\x10V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14D\x83`\0\x81Q\x81\x10a\x14\x1CWa\x14\x1Ca7\xF8V[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x147Wa\x147a7\xF8V[` \x02` \x01\x01Qa\"\x90V[\x90P`\x01[\x82Q\x81\x10\x15a\x14\x9EWa\x14\x8A\x82a\x14\x85\x86\x84\x81Q\x81\x10a\x14kWa\x14ka7\xF8V[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x147Wa\x147a7\xF8V[a#4V[\x91P\x80a\x14\x96\x81a8$V[\x91PPa\x14IV[P\x92\x91PPV[`\0a\x14\xBF`\0\x80Q` a98\x839\x81Q\x91R\x83a8\xCDV[a\x14\xD7\x90`\0\x80Q` a98\x839\x81Q\x91Ra8\xEFV[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x05WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a9\x18\x839\x81Q\x91R\x84` \x01Qa\x158\x91\x90a8\xCDV[a\x15P\x90`\0\x80Q` a9\x18\x839\x81Q\x91Ra8\xEFV[\x90R\x92\x91PPV[a\x15\x83`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x16\xFFW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\x1F\x91\x90\x83\x90` \x01a9\x02V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x17v\x84a\x17qa\x17G\x84a#\xDBV[`@Q` \x01a\x17Y\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x04a!\x03V[a\x17\x0BV[a\x17\xB4\x84a\x17qa\x17\x8A\x86`\0\x01Qa#\xDBV[`@Q` \x01a\x17\x9C\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a!\x03V[a\x17\xC8\x84a\x17qa\x17\x8A\x86` \x01Qa#\xDBV[a\x17\xD3\x84`\x01a \xD0V[a\x17\xFD\x84\x7F/\x8D\xD1\xF1\xA7X\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x05`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\x0F\x84\x84a\x1AxV[\x80\x82Ra\x12\x1F\x90\x85\x90\x85\x90a\x1A\xCCV[` \x82\x01R\x80Qa\x125\x90\x85\x90\x84\x90\x86\x90a\x1B2V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12O\x85\x87\x89a\x1C\x88V[\x90Pa\x12_\x88\x86\x89\x89\x88\x88a\x1DtV[a\x0C\xDC\x81\x87\x86a \x80V[a\x03\xE9\x82\x82a \xD0V[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x12\x9C\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a8\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x12\xCDWa\x12\xCDa7\xF8V[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x12\xE9Wa\x12\xE9a7\xF8V[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x08\x94\x93\x92\x91\x90a8\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x138Wa\x138a7\xF8V[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13YWa\x13Ya7\xF8V[` \x02\x01\x81\x81RPPa\x02Qa\x13\x9C\x83\x83`@Q` \x01a\x13\x84\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a!\x03V[a\"\x10V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14D\x83`\0\x81Q\x81\x10a\x14\x1CWa\x14\x1Ca7\xF8V[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x147Wa\x147a7\xF8V[` \x02` \x01\x01Qa\"\x90V[\x90P`\x01[\x82Q\x81\x10\x15a\x14\x9EWa\x14\x8A\x82a\x14\x85\x86\x84\x81Q\x81\x10a\x14kWa\x14ka7\xF8V[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x147Wa\x147a7\xF8V[a#4V[\x91P\x80a\x14\x96\x81a8$V[\x91PPa\x14IV[P\x92\x91PPV[`\0a\x14\xBF`\0\x80Q` a98\x839\x81Q\x91R\x83a8\xCDV[a\x14\xD7\x90`\0\x80Q` a98\x839\x81Q\x91Ra8\xEFV[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x05WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a9\x18\x839\x81Q\x91R\x84` \x01Qa\x158\x91\x90a8\xCDV[a\x15P\x90`\0\x80Q` a9\x18\x839\x81Q\x91Ra8\xEFV[\x90R\x92\x91PPV[a\x15\x83`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x16\xFFW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\x1F\x91\x90\x83\x90` \x01a9\x02V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x17v\x84a\x17qa\x17G\x84a#\xDBV[`@Q` \x01a\x17Y\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x04a!\x03V[a\x17\x0BV[a\x17\xB4\x84a\x17qa\x17\x8A\x86`\0\x01Qa#\xDBV[`@Q` \x01a\x17\x9C\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a!\x03V[a\x17\xC8\x84a\x17qa\x17\x8A\x86` \x01Qa#\xDBV[a\x17\xD3\x84`\x01a \xD0V[a\x17\xFD\x84\x7F/\x8D\xD1\xF1\xA7X, /// Optional 3rd argument for the `action` arg3: Option, + /// Optional 4th argument for the `action` + arg4: Option, } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] @@ -59,6 +64,10 @@ enum Action { TranscriptAppendProofEvals, /// Return the Plonk Verifier related constants PlonkConstants, + /// Get jf_plonk::Verifier::compute_challenges() + PlonkComputeChal, + /// Get a random, dummy proof with correct format + DummyProof, /// Test only logic TestOnly, } @@ -199,7 +208,59 @@ fn main() { println!("{}", res.encode_hex()); } Action::PlonkConstants => { - unimplemented!() + let coset_k = coset_k(); + let open_key = open_key(); + + let res = ( + field_to_u256::(coset_k[1]), + field_to_u256::(coset_k[2]), + field_to_u256::(coset_k[3]), + field_to_u256::(coset_k[4]), + field_to_u256::(open_key.beta_h.x().unwrap().c0), + field_to_u256::(open_key.beta_h.x().unwrap().c1), + field_to_u256::(open_key.beta_h.y().unwrap().c0), + field_to_u256::(open_key.beta_h.y().unwrap().c1), + ); + println!("{}", res.encode_hex()); + } + Action::PlonkComputeChal => { + let arg1 = cli.arg1.as_ref().expect("Should provide arg1=verifyingKey"); + let arg2 = cli.arg2.as_ref().expect("Should provide arg2=publicInput"); + let arg3 = cli.arg3.as_ref().expect("Should provide arg3=proof"); + let arg4 = cli + .arg4 + .as_ref() + .expect("Should provide arg3=extraTranscriptInitMsg"); + + let vk = arg1.parse::().unwrap().into(); + let pi_u256: Vec = AbiDecode::decode_hex(arg2).unwrap(); + let pi: Vec = pi_u256.into_iter().map(u256_to_field).collect(); + let proof: Proof = arg3.parse::().unwrap().into(); + let msg = { + let parsed: Bytes = AbiDecode::decode_hex(arg4).unwrap(); + parsed.0.to_vec() + }; + + let chal: ParsedChallenges = + Verifier::::compute_challenges::( + &[&vk], + &[&pi], + &proof.into(), + &Some(msg), + ) + .unwrap() + .into(); + println!("{}", (chal,).encode_hex()); + } + Action::DummyProof => { + let mut rng = jf_utils::test_rng(); + if let Some(arg1) = cli.arg1.as_ref() { + let seed = arg1.parse::().unwrap(); + rng = StdRng::seed_from_u64(seed); + } + + let proof = ParsedPlonkProof::dummy(&mut rng); + println!("{}", (proof,).encode_hex()); } Action::TestOnly => { let arg1 = cli.arg1.as_ref().expect("Should provide arg1=proof"); @@ -218,6 +279,7 @@ fn main() { // constant in hex string copied from hardcoded constants from solidity contracts +// TODO: (alex) further test these with output from Jellyfish directly! // TODO: (alex) change to simply using `MontFp!("0x..")` after // is on a tag release // Return cosets coefficients for circuits over BN254. @@ -663,4 +725,74 @@ impl ParsedPlonkProof { ..Default::default() } } + + /// return a dummy proof instance with all random fields + fn dummy(rng: &mut R) -> Self { + let mut proof = Self::dummy_with_rand_proof_evals(rng); + proof.wire_0 = G1Affine::rand(rng).into(); + proof.wire_1 = G1Affine::rand(rng).into(); + proof.wire_2 = G1Affine::rand(rng).into(); + proof.wire_3 = G1Affine::rand(rng).into(); + proof.wire_4 = G1Affine::rand(rng).into(); + proof.prod_perm = G1Affine::rand(rng).into(); + proof.split_0 = G1Affine::rand(rng).into(); + proof.split_1 = G1Affine::rand(rng).into(); + proof.split_2 = G1Affine::rand(rng).into(); + proof.split_3 = G1Affine::rand(rng).into(); + proof.split_4 = G1Affine::rand(rng).into(); + proof.zeta = G1Affine::rand(rng).into(); + proof.zeta_omega = G1Affine::rand(rng).into(); + proof + } +} + +/// intermediate representation of `Challenges` in solidity +#[derive(Clone, Debug, Default, EthAbiType, EthAbiCodec)] +struct ParsedChallenges { + alpha: U256, + alpha_2: U256, + alpha_3: U256, + beta: U256, + gamma: U256, + zeta: U256, + v: U256, + u: U256, +} + +impl FromStr for ParsedChallenges { + type Err = AbiError; + fn from_str(s: &str) -> Result { + let parsed: (Self,) = AbiDecode::decode_hex(s)?; + Ok(parsed.0) + } +} + +impl From> for ParsedChallenges { + fn from(c: Challenges) -> Self { + let alpha_2 = c.alpha.double(); + Self { + alpha: field_to_u256::(c.alpha), + alpha_2: field_to_u256::(alpha_2), + alpha_3: field_to_u256::(c.alpha * alpha_2), + beta: field_to_u256::(c.beta), + gamma: field_to_u256::(c.gamma), + zeta: field_to_u256::(c.zeta), + v: field_to_u256::(c.v), + u: field_to_u256::(c.u), + } + } +} + +impl From for Challenges { + fn from(c: ParsedChallenges) -> Self { + Self { + tau: Fr::from(0u32), + alpha: u256_to_field(c.alpha), + beta: u256_to_field(c.beta), + gamma: u256_to_field(c.gamma), + zeta: u256_to_field(c.zeta), + v: u256_to_field(c.v), + u: u256_to_field(c.u), + } + } } diff --git a/contracts/src/libraries/PlonkVerifier.sol b/contracts/src/libraries/PlonkVerifier.sol index 367c6d334e..0942cb6565 100644 --- a/contracts/src/libraries/PlonkVerifier.sol +++ b/contracts/src/libraries/PlonkVerifier.sol @@ -25,13 +25,13 @@ library PlonkVerifier { using Transcript for Transcript.TranscriptData; // _COSET_K0 = 1, has no effect during multiplication, thus avoid declaring it here. - uint256 private constant COSET_K1 = + uint256 internal constant COSET_K1 = 0x2f8dd1f1a7583c42c4e12a44e110404c73ca6c94813f85835da4fb7bb1301d4a; - uint256 private constant COSET_K2 = + uint256 internal constant COSET_K2 = 0x1ee678a0470a75a6eaa8fe837060498ba828a3703b311d0f77f010424afeb025; - uint256 private constant COSET_K3 = + uint256 internal constant COSET_K3 = 0x2042a587a90c187b0a087c03e29c968b950b1db26d5c82d666905a6895790c0a; - uint256 private constant COSET_K4 = + uint256 internal constant COSET_K4 = 0x2e2b91456103698adf57b799969dea1c8f739da5d8d40dd3eb9222db7c81e881; // Parsed from Aztec's Ignition CRS, @@ -39,17 +39,17 @@ library PlonkVerifier { // See parsing code: https://github.com/alxiong/crs // @dev since library cannot have constant value of custom type, we break it // into individual field values. - uint256 private constant BETA_H_X0 = + uint256 internal constant BETA_H_X0 = 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1; - uint256 private constant BETA_H_X1 = + uint256 internal constant BETA_H_X1 = 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0; - uint256 private constant BETA_H_Y0 = + uint256 internal constant BETA_H_Y0 = 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4; - uint256 private constant BETA_H_Y1 = + uint256 internal constant BETA_H_Y1 = 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55; /// The number of wire types of the circuit, TurboPlonk has 5. - uint256 private constant NUM_WIRE_TYPES = 5; + uint256 internal constant NUM_WIRE_TYPES = 5; /// @dev polynomial commitment evaluation info. struct PcsInfo { @@ -233,6 +233,37 @@ library PlonkVerifier { } } + /// @dev Compute components in [E]1 and [F]1 used for PolyComm opening verification + /// equivalent of JF's + /// https://github.com/EspressoSystems/jellyfish/blob/main/plonk/src/proof_system/verifier.rs#L154-L170 + /// caller allocates the memory fr commScalars and commBases + /// requires Arrays of size 30. + /// @param verifyingKey A verifier key + /// @param evalData A polynomial evaluation + /// @param proof A Plonk proof + /// @param chal A set of challenges + /// @param commScalars Common scalars + /// @param commBases Common bases + // The returned commitment is a generalization of + // `[F]1` described in Sec 8.4, step 10 of https://eprint.iacr.org/2019/953.pdf + // Returned evaluation is the scalar in `[E]1` described in Sec 8.4, step 11 of + // https://eprint.iacr.org/2019/953.pdf + function _prepareOpeningProof( + IPlonkVerifier.VerifyingKey memory verifyingKey, + Poly.EvalData memory evalData, + IPlonkVerifier.PlonkProof memory proof, + Challenges memory chal, + uint256[] memory commScalars, + BN254.G1Point[] memory commBases + ) internal pure returns (uint256 eval) { + // compute the constant term of the linearization polynomial + uint256 linPolyConstant = _computeLinPolyConstantTerm(chal, proof, evalData); + + _preparePolyCommitments(verifyingKey, chal, evalData, proof, commScalars, commBases); + + eval = _prepareEvaluations(linPolyConstant, proof, commScalars); + } + /// @dev Compute the constant term of the linearization polynomial. /// ``` /// r_plonk = PI - L1(x) * alpha^2 - alpha * \prod_i=1..m-1 (w_i + beta * sigma_i + gamma) * @@ -291,37 +322,6 @@ library PlonkVerifier { } } - /// @dev Compute components in [E]1 and [F]1 used for PolyComm opening verification - /// equivalent of JF's - /// https://github.com/EspressoSystems/jellyfish/blob/main/plonk/src/proof_system/verifier.rs#L154-L170 - /// caller allocates the memory fr commScalars and commBases - /// requires Arrays of size 30. - /// @param verifyingKey A verifier key - /// @param evalData A polynomial evaluation - /// @param proof A Plonk proof - /// @param chal A set of challenges - /// @param commScalars Common scalars - /// @param commBases Common bases - // The returned commitment is a generalization of - // `[F]1` described in Sec 8.4, step 10 of https://eprint.iacr.org/2019/953.pdf - // Returned evaluation is the scalar in `[E]1` described in Sec 8.4, step 11 of - // https://eprint.iacr.org/2019/953.pdf - function _prepareOpeningProof( - IPlonkVerifier.VerifyingKey memory verifyingKey, - Poly.EvalData memory evalData, - IPlonkVerifier.PlonkProof memory proof, - Challenges memory chal, - uint256[] memory commScalars, - BN254.G1Point[] memory commBases - ) internal pure returns (uint256 eval) { - // compute the constant term of the linearization polynomial - uint256 linPolyConstant = _computeLinPolyConstantTerm(chal, proof, evalData); - - _preparePolyCommitments(verifyingKey, chal, evalData, proof, commScalars, commBases); - - eval = _prepareEvaluations(linPolyConstant, proof, commScalars); - } - /// @dev Similar to `aggregate_poly_commitments()` in Jellyfish, but we are not aggregating /// multiple, /// but rather preparing for `[F]1` from a single proof. diff --git a/contracts/test/PlonkVerifier.t.sol b/contracts/test/PlonkVerifier.t.sol new file mode 100644 index 0000000000..60c22248d5 --- /dev/null +++ b/contracts/test/PlonkVerifier.t.sol @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: Unlicensed + +/* solhint-disable contract-name-camelcase, func-name-mixedcase, one-contract-per-file */ + +pragma solidity ^0.8.0; + +// Libraries +import "forge-std/Test.sol"; +import { BN254 } from "bn254/BN254.sol"; +import { IPlonkVerifier } from "../src/interfaces/IPlonkVerifier.sol"; +import { VkTest } from "./stubs/Transfer1In2Out24DepthVk.sol"; + +// Target contract +import { PlonkVerifier as V } from "../src/libraries/PlonkVerifier.sol"; + +/// @dev Common helpers/utils for PlonkVerifier tests +contract PlonkVerifierCommonTest is Test { + /// @dev Sanitize all values in `a` to be valid scalar fields Bn254::Fr. + /// This is helpful to sanitize fuzzer-generated random `uint[]` values. + function sanitizeScalarFields(uint256[] memory a) public returns (uint256[] memory) { + for (uint256 i = 0; i < a.length; i++) { + a[i] = bound(a[i], 0, BN254.R_MOD - 1); + BN254.validateScalarField(a[i]); + } + return a; + } + + /// @dev Generate a random valid (format-wise) proof from a random seed + function dummyProof(uint64 seed) public returns (IPlonkVerifier.PlonkProof memory) { + string[] memory cmds = new string[](6); + cmds[0] = "cargo"; + cmds[1] = "run"; + cmds[2] = "--bin"; + cmds[3] = "diff-test"; + cmds[4] = "dummy-proof"; + cmds[5] = vm.toString(seed); + + bytes memory result = vm.ffi(cmds); + (IPlonkVerifier.PlonkProof memory proof) = abi.decode(result, (IPlonkVerifier.PlonkProof)); + return proof; + } +} + +contract PlonkVerifier_constants_Test is Test { + /// @dev Test constants declared matches that from Jellyfish + function test_correctConstants() external { + string[] memory cmds = new string[](7); + cmds[0] = "cargo"; + cmds[1] = "run"; + cmds[2] = "--bin"; + cmds[3] = "diff-test"; + cmds[4] = "plonk-constants"; + + bytes memory result = vm.ffi(cmds); + ( + uint256 k1, + uint256 k2, + uint256 k3, + uint256 k4, + uint256 betaHX0, + uint256 betaHX1, + uint256 betaHY0, + uint256 betaHY1 + ) = abi.decode( + result, (uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256) + ); + + assertEq(k1, V.COSET_K1); + assertEq(k2, V.COSET_K2); + assertEq(k3, V.COSET_K3); + assertEq(k4, V.COSET_K4); + assertEq(betaHX0, V.BETA_H_X0); + assertEq(betaHX1, V.BETA_H_X1); + assertEq(betaHY0, V.BETA_H_Y0); + assertEq(betaHY1, V.BETA_H_Y1); + } +} + +contract PlonkVerifier_batchVerify_Test is Test { + /// @dev Test if some of the user inputs are invalid + function testFuzz_revertWhenInvalidArgs() external { + // TODO: break down into more possible reasons of malformed inputs. + return; + } + + /// @dev Test happy path for `batchVerify` + function test_correctProof_succeeds() external { + return; + } + + /// @dev Test bad path for `batchVerify`: valid bur wrong proof should return false + function testFuzz_wrongProof_fails() external { + return; + } +} + +contract PlonkVerifier_validateProof_Test is Test { + /// @dev Test `_validateProof` correct catches invalidly form proof + function testFuzz_validateProof_succeeds() external { + return; + } +} + +contract PlonkVerifier_preparePcsInfo_Test is Test { + /// @dev Test `preparePcsInfo` matches that of Jellyfish + function testFuzz_preparePcsInfo_matches() external { + return; + } +} + +contract PlonkVerifier_computeChallenges_Test is PlonkVerifierCommonTest { + /// forge-config: default.fuzz.runs = 5 + /// @dev Test `computeChallenges` matches that of Jellyfish + function testFuzz_computeChallenges_matches( + uint64 seed, + uint256[] memory publicInput, + bytes memory extraTranscriptInitMsg + ) external { + IPlonkVerifier.VerifyingKey memory vk = VkTest.getVk(); + IPlonkVerifier.PlonkProof memory proof = dummyProof(seed); + publicInput = sanitizeScalarFields(publicInput); + string[] memory cmds = new string[](9); + cmds[0] = "cargo"; + cmds[1] = "run"; + cmds[2] = "--bin"; + cmds[3] = "diff-test"; + cmds[4] = "plonk-compute-chal"; + cmds[5] = vm.toString(abi.encode(vk)); + cmds[6] = vm.toString(abi.encode(publicInput)); + cmds[7] = vm.toString(abi.encode(proof)); + cmds[8] = vm.toString(abi.encode(extraTranscriptInitMsg)); + + bytes memory result = vm.ffi(cmds); + (V.Challenges memory chal) = abi.decode(result, (V.Challenges)); + + V.Challenges memory c = V._computeChallenges(vk, publicInput, proof, extraTranscriptInitMsg); + assertEq(chal.alpha, c.alpha); + assertEq(chal.alpha2, c.alpha2); + assertEq(chal.alpha3, c.alpha3); + assertEq(chal.beta, c.beta); + assertEq(chal.gamma, c.gamma); + assertEq(chal.zeta, c.zeta); + assertEq(chal.v, c.v); + assertEq(chal.u, c.u); + } +} + +contract PlonkVerifier_prepareOpeningProof_Test is Test { + function testFuzz_prepareOpeningProof_matches() external { + return; + } +} + +contract PlonkVerifier_computeLinPolyConstantTerm_Test is Test { + function testFuzz_computeLinPolyConstantTerm_matches() external { + return; + } +} + +contract PlonkVerifier_preparePolyCommitments_Test is Test { + function testFuzz_preparePolyCommitments_matches() external { + return; + } +} + +contract PlonkVerifier_prepareEvaluations_Test is Test { + function testFuzz_prepareEvaluations_matches() external { + return; + } +} + +contract PlonkVerifier_batchVerifyOpeningProofs_Test is Test { + function testFuzz_batchVerifyOpeningProofs_matches() external { + return; + } +} + +contract PlonkVerifier_linearizationScalarsAndBases_Test is Test { + function testFuzz_linearizationScalarsAndBases_matches() external { + return; + } +} diff --git a/contracts/test/stubs/Transfer1In2Out24DepthVk.sol b/contracts/test/stubs/Transfer1In2Out24DepthVk.sol index cbd4f4bb0e..15f15db6c1 100644 --- a/contracts/test/stubs/Transfer1In2Out24DepthVk.sol +++ b/contracts/test/stubs/Transfer1In2Out24DepthVk.sol @@ -15,9 +15,10 @@ // NOTE: DO NOT MODIFY! GENERATED BY SCRIPT VIA `cargo run --bin gen-vk-libraries --release`. pragma solidity ^0.8.0; -import { BN254 } from "bn254/BN254.sol"; import { IPlonkVerifier } from "../../src/interfaces/IPlonkVerifier.sol"; +/* solhint-disable no-inline-assembly */ + library VkTest { function getVk() internal pure returns (IPlonkVerifier.VerifyingKey memory vk) { assembly { From 566ee05032d4ef2eac0643adf459009418de4b04 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Thu, 9 Nov 2023 01:17:23 +0800 Subject: [PATCH 13/38] wip: add most verifier tests --- Cargo.lock | 10 +- contracts/rust/Cargo.toml | 4 +- contracts/rust/src/bin/diff_test.rs | 271 ++++++++++++++++++++- contracts/test/PlonkVerifier.t.sol | 359 ++++++++++++++++++++++++---- 4 files changed, 585 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6b9a81ae68..fef7d01011 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3741,8 +3741,10 @@ dependencies = [ "ethers-providers", "ethers-solc", "hex", + "itertools 0.10.5", "jf-plonk", "jf-primitives 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", + "jf-relation 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", "jf-utils 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", "num-bigint", "num-traits", @@ -4179,7 +4181,7 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jf-plonk" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#f32b1160e71dc5d5c4e0d92de46b688d68a6c385" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#ac5b068f506575406d210491e87fb0eb8c8f32d4" dependencies = [ "ark-ec 0.4.2", "ark-ff 0.4.2", @@ -4208,7 +4210,7 @@ dependencies = [ [[package]] name = "jf-primitives" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#f32b1160e71dc5d5c4e0d92de46b688d68a6c385" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#ac5b068f506575406d210491e87fb0eb8c8f32d4" dependencies = [ "anyhow", "ark-bls12-377", @@ -4296,7 +4298,7 @@ dependencies = [ [[package]] name = "jf-relation" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#f32b1160e71dc5d5c4e0d92de46b688d68a6c385" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#ac5b068f506575406d210491e87fb0eb8c8f32d4" dependencies = [ "ark-bls12-377", "ark-bls12-381 0.4.0", @@ -4348,7 +4350,7 @@ dependencies = [ [[package]] name = "jf-utils" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#f32b1160e71dc5d5c4e0d92de46b688d68a6c385" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#ac5b068f506575406d210491e87fb0eb8c8f32d4" dependencies = [ "ark-ec 0.4.2", "ark-ff 0.4.2", diff --git a/contracts/rust/Cargo.toml b/contracts/rust/Cargo.toml index 6e3cc94e83..b48d317e0d 100644 --- a/contracts/rust/Cargo.toml +++ b/contracts/rust/Cargo.toml @@ -24,8 +24,10 @@ ethers = { version = "2.0.4" } ethers-providers = "2.0.4" ethers-solc = "2.0.4" hex = "0.4.3" -jf-plonk = { git = "https://github.com/EspressoSystems/jellyfish", features = ["test_apis"], branch = "more-test-apis" } +itertools = "0.10.3" +jf-plonk = { git = "https://github.com/EspressoSystems/jellyfish", features = ["test-apis", "test-srs"], branch = "more-test-apis" } jf-primitives = { git = "https://github.com/EspressoSystems/jellyfish", features = ["std"], branch = "more-test-apis" } +jf-relation = { git = "https://github.com/EspressoSystems/jellyfish", features = ["std"], branch = "more-test-apis" } jf-utils = { git = "https://github.com/EspressoSystems/jellyfish", branch = "more-test-apis" } num-bigint = { version = "0.4", default-features = false } num-traits = { version = "0.2", default-features = false } diff --git a/contracts/rust/src/bin/diff_test.rs b/contracts/rust/src/bin/diff_test.rs index 3e7765633f..d4fb850464 100644 --- a/contracts/rust/src/bin/diff_test.rs +++ b/contracts/rust/src/bin/diff_test.rs @@ -1,21 +1,25 @@ use std::str::FromStr; +use anyhow::Result; use ark_bn254::{g1, Bn254, Fq, Fr, G1Affine, G2Affine}; use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; -use ark_ec::AffineRepr; +use ark_ec::{AffineRepr, CurveGroup}; use ark_ff::{BigInteger, Field, Fp2, MontFp, PrimeField}; use ark_poly::domain::radix2::Radix2EvaluationDomain; use ark_poly::EvaluationDomain; -use ark_std::rand::rngs::StdRng; -use ark_std::rand::SeedableRng; -use ark_std::{rand::Rng, UniformRand}; +use ark_std::{ + rand::{rngs::StdRng, Rng, SeedableRng}, + UniformRand, +}; use clap::{Parser, ValueEnum}; use ethers::{ abi::{AbiDecode, AbiEncode}, prelude::{AbiError, EthAbiCodec, EthAbiType}, types::{Bytes, H256, U256}, }; +use itertools::{izip, multiunzip}; use jf_plonk::proof_system::structs::{OpenKey, Proof, ProofEvaluations, VerifyingKey}; +use jf_plonk::proof_system::{PlonkKzgSnark, UniversalSNARK}; use jf_plonk::testing_apis::Challenges; use jf_plonk::{ constants::KECCAK256_STATE_SIZE, @@ -23,6 +27,7 @@ use jf_plonk::{ transcript::{PlonkTranscript, SolidityTranscript}, }; use jf_primitives::pcs::prelude::Commitment; +use jf_relation::{Arithmetization, Circuit, PlonkCircuit}; use num_bigint::BigUint; use num_traits::Num; @@ -66,12 +71,19 @@ enum Action { PlonkConstants, /// Get jf_plonk::Verifier::compute_challenges() PlonkComputeChal, + /// Get jf_plonk::Verifier::aggregate_evaluations() + PlonkPrepareEval, + /// Get jf_plonk::Verifier::prepare_pcs_info() + PlonkPreparePcsInfo, + /// Get jf_plonk::Verifier::batch_verify() + PlonkBatchVerify, /// Get a random, dummy proof with correct format DummyProof, /// Test only logic TestOnly, } +#[allow(clippy::type_complexity)] fn main() { let cli = Cli::parse(); @@ -113,7 +125,7 @@ fn main() { let pi: Vec = pi_u256.into_iter().map(u256_to_field).collect(); let verifier = Verifier::::new(2u32.pow(log_size) as usize).unwrap(); - let (vanish_eval, lagrange_one, pi_eval) = verifier + let (vanish_eval, lagrange_one, _, pi_eval) = verifier .compute_poly_evals_for_pcs_info(&zeta, &pi) .unwrap(); let res = ( @@ -252,6 +264,115 @@ fn main() { .into(); println!("{}", (chal,).encode_hex()); } + Action::PlonkPrepareEval => { + let arg1 = cli.arg1.as_ref().expect("Should provide arg1=proof"); + let arg2 = cli + .arg2 + .as_ref() + .expect("Should provide arg2=linPolyConstant"); + let arg3 = cli.arg3.as_ref().expect("Should provide arg3=commScalars"); + + let proof: Proof = arg1.parse::().unwrap().into(); + let lin_poly_constant = u256_to_field::(arg2.parse::().unwrap()); + let comm_scalars_u256: Vec = AbiDecode::decode_hex(arg3).unwrap(); + // NOTE: only take the last 10 scalars, the first 20 are linearization scalars + let comm_scalars: Vec = comm_scalars_u256 + .into_iter() + .skip(20) + .map(u256_to_field) + .collect(); + + let eval = Verifier::::aggregate_evaluations( + &lin_poly_constant, + &[proof.poly_evals], + &[None], + &comm_scalars, + ) + .unwrap(); + let res = field_to_u256(eval); + println!("{}", (res,).encode_hex()); + } + Action::PlonkPreparePcsInfo => { + let arg1 = cli.arg1.as_ref().expect("Should provide arg1=verifyingKey"); + let arg2 = cli.arg2.as_ref().expect("Should provide arg2=publicInput"); + let arg3 = cli.arg3.as_ref().expect("Should provide arg3=proof"); + let arg4 = cli + .arg4 + .as_ref() + .expect("Should provide arg3=extraTranscriptInitMsg"); + + let vk: VerifyingKey = arg1.parse::().unwrap().into(); + let pi_u256: Vec = AbiDecode::decode_hex(arg2).unwrap(); + let pi: Vec = pi_u256.into_iter().map(u256_to_field).collect(); + let proof: Proof = arg3.parse::().unwrap().into(); + let msg = { + let parsed: Bytes = AbiDecode::decode_hex(arg4).unwrap(); + parsed.0.to_vec() + }; + + let verifier = Verifier::::new(vk.domain_size).unwrap(); + let pcs_info = verifier + .prepare_pcs_info::(&[&vk], &[&pi], &proof.into(), &Some(msg)) + .unwrap(); + + let scalars_and_bases_prod: ParsedG1Point = pcs_info + .comm_scalars_and_bases + .multi_scalar_mul() + .into_affine() + .into(); + let opening_proof: ParsedG1Point = pcs_info.opening_proof.0.into(); + let shifted_opening_proof: ParsedG1Point = pcs_info.shifted_opening_proof.0.into(); + let res = ( + field_to_u256(pcs_info.u), + field_to_u256(pcs_info.eval_point), + field_to_u256(pcs_info.next_eval_point), + field_to_u256(pcs_info.eval), + scalars_and_bases_prod, + opening_proof, + shifted_opening_proof, + ); + println!("{}", res.encode_hex()); + } + Action::PlonkBatchVerify => { + let arg1 = cli.arg1.as_ref().expect("Should provide arg1=numProof"); + let num_proof = arg1.parse::().unwrap(); + let (proofs, vks, public_inputs, extra_msgs, _): ( + Vec>, + Vec>, + Vec>, + Vec>>, + Vec, + ) = multiunzip(gen_plonk_proof_for_test(num_proof as usize).unwrap()); + + // ensure they are correct params + let proofs_refs: Vec<&Proof> = proofs.iter().collect(); + let vks_refs: Vec<&VerifyingKey> = vks.iter().collect(); + let pi_refs: Vec<&[Fr]> = public_inputs + .iter() + .map(|pub_input| &pub_input[..]) + .collect(); + assert!(PlonkKzgSnark::batch_verify::( + &vks_refs, + &pi_refs, + &proofs_refs, + &extra_msgs + ) + .is_ok()); + + let vks_parsed: Vec = vks.into_iter().map(Into::into).collect(); + let pis_parsed: Vec> = public_inputs + .into_iter() + .map(|pi| pi.into_iter().map(field_to_u256).collect()) + .collect(); + let proofs_parsed: Vec = proofs.into_iter().map(Into::into).collect(); + let msgs_parsed: Vec = extra_msgs + .into_iter() + .map(|msg| msg.unwrap().into()) + .collect(); + + let res = (vks_parsed, pis_parsed, proofs_parsed, msgs_parsed); + println!("{}", res.encode_hex()); + } Action::DummyProof => { let mut rng = jf_utils::test_rng(); if let Some(arg1) = cli.arg1.as_ref() { @@ -469,9 +590,17 @@ where P::BaseField: PrimeField, { fn from(p: Affine

) -> Self { - Self { - x: field_to_u256::(*p.x().unwrap()), - y: field_to_u256::(*p.y().unwrap()), + if p.is_zero() { + // this convention is from the BN precompile + Self { + x: U256::from(0), + y: U256::from(0), + } + } else { + Self { + x: field_to_u256::(*p.x().unwrap()), + y: field_to_u256::(*p.y().unwrap()), + } } } } @@ -759,6 +888,25 @@ struct ParsedChallenges { u: U256, } +impl ParsedChallenges { + #[allow(dead_code)] + fn dummy(rng: &mut R) -> Self { + let alpha = Fr::rand(rng); + let alpha_2 = alpha * alpha; + let alpha_3 = alpha * alpha_2; + Self { + alpha: field_to_u256(alpha), + alpha_2: field_to_u256(alpha_2), + alpha_3: field_to_u256(alpha_3), + beta: field_to_u256(Fr::rand(rng)), + gamma: field_to_u256(Fr::rand(rng)), + zeta: field_to_u256(Fr::rand(rng)), + v: field_to_u256(Fr::rand(rng)), + u: field_to_u256(Fr::rand(rng)), + } + } +} + impl FromStr for ParsedChallenges { type Err = AbiError; fn from_str(s: &str) -> Result { @@ -796,3 +944,110 @@ impl From for Challenges { } } } + +// modify from +/// return list of (proof, ver_key, public_input, extra_msg, domain_size) +#[allow(clippy::type_complexity)] +fn gen_plonk_proof_for_test( + num_proof: usize, +) -> Result< + Vec<( + Proof, + VerifyingKey, + Vec, + Option>, + usize, + )>, +> { + // 1. Simulate universal setup + let rng = &mut jf_utils::test_rng(); + let srs = PlonkKzgSnark::::universal_setup_for_testing(2u64.pow(17) as usize, rng)?; + + // 2. Create circuits + let circuits = (0..num_proof) + .map(|i| { + let m = 2 + i / 3; + let a0 = 1 + i % 3; + gen_circuit_for_test::(m, a0) + }) + .collect::>>()?; + let domain_sizes: Vec = circuits + .iter() + .map(|c| c.eval_domain_size().unwrap()) + .collect(); + + // 3. Preprocessing + let mut prove_keys = vec![]; + let mut ver_keys = vec![]; + for c in circuits.iter() { + let (pk, vk) = PlonkKzgSnark::::preprocess(&srs, c)?; + prove_keys.push(pk); + ver_keys.push(vk); + } + + // 4. Proving + let mut proofs = vec![]; + let mut extra_msgs = vec![]; + + circuits + .iter() + .zip(prove_keys.iter()) + .enumerate() + .for_each(|(i, (cs, pk))| { + let extra_msg = Some(format!("extra message: {}", i).into_bytes()); + proofs.push( + PlonkKzgSnark::::prove::<_, _, SolidityTranscript>( + rng, + cs, + pk, + extra_msg.clone(), + ) + .unwrap(), + ); + extra_msgs.push(extra_msg); + }); + + let public_inputs: Vec> = circuits + .iter() + .map(|cs| cs.public_input().unwrap()) + .collect(); + + Ok(izip!(proofs, ver_keys, public_inputs, extra_msgs, domain_sizes).collect()) +} + +// Different `m`s lead to different circuits. +// Different `a0`s lead to different witness values. +// TODO: (alex) change this circuit for easier size counting +fn gen_circuit_for_test(m: usize, a0: usize) -> Result> { + let mut cs: PlonkCircuit = PlonkCircuit::new_turbo_plonk(); + // Create variables + let mut a = vec![]; + for i in a0..(a0 + 4 * m) { + a.push(cs.create_variable(F::from(i as u64))?); + } + let b = [ + cs.create_public_variable(F::from(m as u64 * 2))?, + cs.create_public_variable(F::from(a0 as u64 * 2 + m as u64 * 4 - 1))?, + ]; + let c = cs.create_public_variable( + (cs.witness(b[1])? + cs.witness(a[0])?) * (cs.witness(b[1])? - cs.witness(a[0])?), + )?; + + // Create gates: + // 1. a0 + ... + a_{4*m-1} = b0 * b1 + // 2. (b1 + a0) * (b1 - a0) = c + // 3. b0 = 2 * m + let mut acc = cs.zero(); + a.iter().for_each(|&elem| acc = cs.add(acc, elem).unwrap()); + let b_mul = cs.mul(b[0], b[1])?; + cs.enforce_equal(acc, b_mul)?; + let b1_plus_a0 = cs.add(b[1], a[0])?; + let b1_minus_a0 = cs.sub(b[1], a[0])?; + cs.mul_gate(b1_plus_a0, b1_minus_a0, c)?; + cs.enforce_constant(b[0], F::from(m as u64 * 2))?; + + // Finalize the circuit. + cs.finalize_for_arithmetization()?; + + Ok(cs) +} diff --git a/contracts/test/PlonkVerifier.t.sol b/contracts/test/PlonkVerifier.t.sol index 60c22248d5..e06aa516f0 100644 --- a/contracts/test/PlonkVerifier.t.sol +++ b/contracts/test/PlonkVerifier.t.sol @@ -2,6 +2,14 @@ /* solhint-disable contract-name-camelcase, func-name-mixedcase, one-contract-per-file */ +// NOTE: For developers and auditors: we mainly test the consistency between the outputs between +// Solidity and Jellyfish library, with the help of fuzzer-generated inputs from Forge Testing. +// Inside the logic of `batchVerify()`, variables values only need to be consistent and valid +// (i.e. valid group or field elements) and don't need to be from a correct proof/public input. +// Only the last step `_batchVerifyOpeningProof` will test *correctness* of these parameters. +// Therefore, we employ more randomly generated dummy inputs for most tests for robustness, +// and only relie on Rust-code to generate correct inputs for the `_batchVerifyOpeningProof`. + pragma solidity ^0.8.0; // Libraries @@ -9,15 +17,23 @@ import "forge-std/Test.sol"; import { BN254 } from "bn254/BN254.sol"; import { IPlonkVerifier } from "../src/interfaces/IPlonkVerifier.sol"; import { VkTest } from "./stubs/Transfer1In2Out24DepthVk.sol"; +import { PolynomialEval as Poly } from "../src/libraries/PolynomialEval.sol"; // Target contract import { PlonkVerifier as V } from "../src/libraries/PlonkVerifier.sol"; /// @dev Common helpers/utils for PlonkVerifier tests contract PlonkVerifierCommonTest is Test { + /// @dev Sanitize a single value to be valid scalar field Bn254::Fr. + function sanitizeScalarField(uint256 a) public view returns (uint256) { + a = bound(a, 0, BN254.R_MOD - 1); + BN254.validateScalarField(a); + return a; + } + /// @dev Sanitize all values in `a` to be valid scalar fields Bn254::Fr. /// This is helpful to sanitize fuzzer-generated random `uint[]` values. - function sanitizeScalarFields(uint256[] memory a) public returns (uint256[] memory) { + function sanitizeScalarFields(uint256[] memory a) public view returns (uint256[] memory) { for (uint256 i = 0; i < a.length; i++) { a[i] = bound(a[i], 0, BN254.R_MOD - 1); BN254.validateScalarField(a[i]); @@ -25,6 +41,27 @@ contract PlonkVerifierCommonTest is Test { return a; } + /// @dev Sanitize dummy verifyingKey such that it matches with the length of publicInput, + /// This is only used for fuzz-generated-dummy-valued tests. + function sanitizeVk(IPlonkVerifier.VerifyingKey memory vk, uint256 piLength) + public + pure + returns (IPlonkVerifier.VerifyingKey memory) + { + vk.numInputs = piLength; + return vk; + } + + /// @dev copy a fixed array into a dynamic array, mostly used for converting fuzzer generated + /// array into another accepted by most APIs. + function copyCommScalars(uint256[30] memory a) public pure returns (uint256[] memory) { + uint256[] memory b = new uint256[](a.length); + for (uint256 i = 0; i < a.length; i++) { + b[i] = a[i]; + } + return b; + } + /// @dev Generate a random valid (format-wise) proof from a random seed function dummyProof(uint64 seed) public returns (IPlonkVerifier.PlonkProof memory) { string[] memory cmds = new string[](6); @@ -39,6 +76,40 @@ contract PlonkVerifierCommonTest is Test { (IPlonkVerifier.PlonkProof memory proof) = abi.decode(result, (IPlonkVerifier.PlonkProof)); return proof; } + + /// @dev helper function to generate some dummy but format-valid arguments for + /// `prepareOpeningProof` step. The verifyingKey should be fixed/loaded from library, + /// proof should be generated via `dummyProof()`, other inputs are from fuzzers. + function dummyArgsForOpeningProof( + uint64 seed, + uint256[] memory publicInput, + bytes memory extraTranscriptInitMsg + ) + public + returns ( + IPlonkVerifier.VerifyingKey memory, + IPlonkVerifier.PlonkProof memory, + V.Challenges memory, + Poly.EvalData memory + ) + { + IPlonkVerifier.VerifyingKey memory vk = sanitizeVk(VkTest.getVk(), publicInput.length); + IPlonkVerifier.PlonkProof memory proof = dummyProof(seed); + V.Challenges memory chal = + V._computeChallenges(vk, publicInput, proof, extraTranscriptInitMsg); + + Poly.EvalDomain memory domain = Poly.newEvalDomain(vk.domainSize); + // pre-compute evaluation data + Poly.EvalData memory evalData = Poly.evalDataGen(domain, chal.zeta, publicInput); + + return (vk, proof, chal, evalData); + } + + /// Thin wrapper to ensure two G1 points are the same + function assertEqG1Point(BN254.G1Point memory a, BN254.G1Point memory b) public { + assertEq(a.x, b.x); + assertEq(a.y, b.y); + } } contract PlonkVerifier_constants_Test is Test { @@ -77,34 +148,231 @@ contract PlonkVerifier_constants_Test is Test { } contract PlonkVerifier_batchVerify_Test is Test { + /// forge-config: default.fuzz.runs = 30 /// @dev Test if some of the user inputs are invalid - function testFuzz_revertWhenInvalidArgs() external { - // TODO: break down into more possible reasons of malformed inputs. - return; + function testFuzz_revertWhenInvalidArgs( + IPlonkVerifier.VerifyingKey[] memory verifyingKeys, + uint256[][] memory publicInputs, + IPlonkVerifier.PlonkProof[] memory proofs, + bytes[] memory extraTranscriptInitMsgs + ) external { + vm.assume( + verifyingKeys.length != proofs.length || publicInputs.length != proofs.length + || extraTranscriptInitMsgs.length != proofs.length || proofs.length == 0 + ); + vm.expectRevert(V.InvalidPlonkArgs.selector); + V.batchVerify(verifyingKeys, publicInputs, proofs, extraTranscriptInitMsgs); } - /// @dev Test happy path for `batchVerify` - function test_correctProof_succeeds() external { - return; - } + /// @dev Test happy and unhappy path of `batchVerify`. + function test_batchVerify_succeeds() external { + for (uint32 i = 1; i < 2; i++) { + string[] memory cmds = new string[](6); + cmds[0] = "cargo"; + cmds[1] = "run"; + cmds[2] = "--bin"; + cmds[3] = "diff-test"; + cmds[4] = "plonk-batch-verify"; + cmds[5] = vm.toString(i); + + bytes memory result = vm.ffi(cmds); + ( + IPlonkVerifier.VerifyingKey[] memory verifyingKeys, + uint256[][] memory publicInputs, + IPlonkVerifier.PlonkProof[] memory proofs, + bytes[] memory extraTranscriptInitMsgs + ) = abi.decode( + result, + (IPlonkVerifier.VerifyingKey[], uint256[][], IPlonkVerifier.PlonkProof[], bytes[]) + ); + + // happy path + assert(V.batchVerify(verifyingKeys, publicInputs, proofs, extraTranscriptInitMsgs)); - /// @dev Test bad path for `batchVerify`: valid bur wrong proof should return false - function testFuzz_wrongProof_fails() external { - return; + // unhappy path + // TODO: (alex) + } } } -contract PlonkVerifier_validateProof_Test is Test { +contract PlonkVerifier_validateProof_Test is PlonkVerifierCommonTest { + /// forge-config: default.fuzz.runs = 5 /// @dev Test `_validateProof` correct catches invalidly form proof - function testFuzz_validateProof_succeeds() external { - return; + function testFuzz_validateProof_succeeds(IPlonkVerifier.PlonkProof memory proof) external { + // w.o.p. this fuzzer-generated input proof is invalid, either one of the G1Points + // or one of the scalar fields is invalid. + vm.expectRevert(); + V._validateProof(proof); + + // happy path + proof = dummyProof(42); // give any seed + V._validateProof(proof); // valid proof should pass without any assertion + + // unhappy path + BN254.G1Point memory invalidPoint = BN254.G1Point(2, 3); + uint256 invalidScalar = BN254.R_MOD; + + proof.wire0 = invalidPoint; + vm.expectRevert(); + V._validateProof(proof); + proof.wire0 = BN254.P1(); // restore to a valid point + + proof.wire1 = invalidPoint; + vm.expectRevert(); + V._validateProof(proof); + proof.wire1 = BN254.P1(); // restore to a valid point + + proof.wire2 = invalidPoint; + vm.expectRevert(); + V._validateProof(proof); + proof.wire2 = BN254.P1(); // restore to a valid point + + proof.wire3 = invalidPoint; + vm.expectRevert(); + V._validateProof(proof); + proof.wire3 = BN254.P1(); // restore to a valid point + + proof.wire4 = invalidPoint; + vm.expectRevert(); + V._validateProof(proof); + proof.wire4 = BN254.P1(); // restore to a valid point + + proof.prodPerm = invalidPoint; + vm.expectRevert(); + V._validateProof(proof); + proof.prodPerm = BN254.P1(); // restore to a valid point + + proof.split0 = invalidPoint; + vm.expectRevert(); + V._validateProof(proof); + proof.split0 = BN254.P1(); // restore to a valid point + + proof.split1 = invalidPoint; + vm.expectRevert(); + V._validateProof(proof); + proof.split1 = BN254.P1(); // restore to a valid point + + proof.split2 = invalidPoint; + vm.expectRevert(); + V._validateProof(proof); + proof.split2 = BN254.P1(); // restore to a valid point + + proof.split3 = invalidPoint; + vm.expectRevert(); + V._validateProof(proof); + proof.split3 = BN254.P1(); // restore to a valid point + + proof.split4 = invalidPoint; + vm.expectRevert(); + V._validateProof(proof); + proof.split4 = BN254.P1(); // restore to a valid point + + proof.zeta = invalidPoint; + vm.expectRevert(); + V._validateProof(proof); + proof.zeta = BN254.P1(); // restore to a valid point + + proof.wireEval0 = invalidScalar; + vm.expectRevert(); + V._validateProof(proof); + proof.wireEval0 = 1; // restore to a valid scalar + + proof.wireEval1 = invalidScalar; + vm.expectRevert(); + V._validateProof(proof); + proof.wireEval1 = 1; // restore to a valid scalar + + proof.wireEval2 = invalidScalar; + vm.expectRevert(); + V._validateProof(proof); + proof.wireEval2 = 1; // restore to a valid scalar + + proof.wireEval3 = invalidScalar; + vm.expectRevert(); + V._validateProof(proof); + proof.wireEval3 = 1; // restore to a valid scalar + + proof.wireEval4 = invalidScalar; + vm.expectRevert(); + V._validateProof(proof); + proof.wireEval4 = 1; // restore to a valid scalar + + proof.sigmaEval0 = invalidScalar; + vm.expectRevert(); + V._validateProof(proof); + proof.sigmaEval0 = 1; // restore to a valid scalar + + proof.sigmaEval1 = invalidScalar; + vm.expectRevert(); + V._validateProof(proof); + proof.sigmaEval1 = 1; // restore to a valid scalar + + proof.sigmaEval2 = invalidScalar; + vm.expectRevert(); + V._validateProof(proof); + proof.sigmaEval2 = 1; // restore to a valid scalar + + proof.sigmaEval3 = invalidScalar; + vm.expectRevert(); + V._validateProof(proof); + proof.sigmaEval3 = 1; // restore to a valid scalar + + proof.prodPermZetaOmegaEval = invalidScalar; + vm.expectRevert(); + V._validateProof(proof); + proof.prodPermZetaOmegaEval = 1; // restore to a valid scalar + + V._validateProof(proof); } } -contract PlonkVerifier_preparePcsInfo_Test is Test { +contract PlonkVerifier_preparePcsInfo_Test is PlonkVerifierCommonTest { + /// forge-config: default.fuzz.runs = 5 /// @dev Test `preparePcsInfo` matches that of Jellyfish - function testFuzz_preparePcsInfo_matches() external { - return; + function testFuzz_preparePcsInfo_matches( + uint64 seed, + uint256[] memory publicInput, + bytes memory extraTranscriptInitMsg + ) external { + publicInput = sanitizeScalarFields(publicInput); + IPlonkVerifier.VerifyingKey memory vk = sanitizeVk(VkTest.getVk(), publicInput.length); + IPlonkVerifier.PlonkProof memory proof = dummyProof(seed); + + V.PcsInfo memory info = V._preparePcsInfo(vk, publicInput, proof, extraTranscriptInitMsg); + + string[] memory cmds = new string[](9); + cmds[0] = "cargo"; + cmds[1] = "run"; + cmds[2] = "--bin"; + cmds[3] = "diff-test"; + cmds[4] = "plonk-prepare-pcs-info"; + cmds[5] = vm.toString(abi.encode(vk)); + cmds[6] = vm.toString(abi.encode(publicInput)); + cmds[7] = vm.toString(abi.encode(proof)); + cmds[8] = vm.toString(abi.encode(extraTranscriptInitMsg)); + + bytes memory result = vm.ffi(cmds); + ( + uint256 u, + uint256 evalPoint, + uint256 nextEvalPoint, + uint256 eval, + BN254.G1Point memory scalarsAndBasesProd, + BN254.G1Point memory openingProof, + BN254.G1Point memory shiftedOpeningProof + ) = abi.decode( + result, + (uint256, uint256, uint256, uint256, BN254.G1Point, BN254.G1Point, BN254.G1Point) + ); + + assertEq(info.u, u); + assertEq(info.evalPoint, evalPoint); + assertEq(info.nextEvalPoint, nextEvalPoint); + assertEq(info.eval, eval); + // NOTE: since we cannot directly compare `struct ScalarsAndBases`, we compare their MSM + assertEqG1Point(BN254.multiScalarMul(info.commBases, info.commScalars), scalarsAndBasesProd); + assertEqG1Point(info.openingProof, openingProof); + assertEqG1Point(info.shiftedOpeningProof, shiftedOpeningProof); } } @@ -119,6 +387,7 @@ contract PlonkVerifier_computeChallenges_Test is PlonkVerifierCommonTest { IPlonkVerifier.VerifyingKey memory vk = VkTest.getVk(); IPlonkVerifier.PlonkProof memory proof = dummyProof(seed); publicInput = sanitizeScalarFields(publicInput); + string[] memory cmds = new string[](9); cmds[0] = "cargo"; cmds[1] = "run"; @@ -145,38 +414,36 @@ contract PlonkVerifier_computeChallenges_Test is PlonkVerifierCommonTest { } } -contract PlonkVerifier_prepareOpeningProof_Test is Test { - function testFuzz_prepareOpeningProof_matches() external { - return; - } -} - -contract PlonkVerifier_computeLinPolyConstantTerm_Test is Test { - function testFuzz_computeLinPolyConstantTerm_matches() external { - return; - } -} +contract PlonkVerifier_prepareEvaluations_Test is PlonkVerifierCommonTest { + /// forge-config: default.fuzz.runs = 5 + /// @dev Test if combinng the polynomial evaluations into a single evaluation is done correctly + /// is done correctly + function testFuzz_prepareEvaluations_matches( + uint64 seed, + uint256 linPolyConstant, + uint256[30] memory scalars + ) external { + IPlonkVerifier.PlonkProof memory proof = dummyProof(seed); + linPolyConstant = sanitizeScalarField(linPolyConstant); + uint256[] memory commScalars = sanitizeScalarFields(copyCommScalars(scalars)); -contract PlonkVerifier_preparePolyCommitments_Test is Test { - function testFuzz_preparePolyCommitments_matches() external { - return; - } -} + string[] memory cmds = new string[](8); + cmds[0] = "cargo"; + cmds[1] = "run"; + cmds[2] = "--bin"; + cmds[3] = "diff-test"; + cmds[4] = "plonk-prepare-eval"; + cmds[5] = vm.toString(abi.encode(proof)); + cmds[6] = vm.toString(bytes32(linPolyConstant)); + cmds[7] = vm.toString(abi.encode(commScalars)); -contract PlonkVerifier_prepareEvaluations_Test is Test { - function testFuzz_prepareEvaluations_matches() external { - return; - } -} + bytes memory result = vm.ffi(cmds); + (uint256 eval) = abi.decode(result, (uint256)); -contract PlonkVerifier_batchVerifyOpeningProofs_Test is Test { - function testFuzz_batchVerifyOpeningProofs_matches() external { - return; + assertEq(eval, V._prepareEvaluations(linPolyConstant, proof, commScalars)); } } -contract PlonkVerifier_linearizationScalarsAndBases_Test is Test { - function testFuzz_linearizationScalarsAndBases_matches() external { - return; - } -} +// NOTE: it's troublesome to convert `ScalarsAndBases` field of a proper `PcsInfo` from Jellyfish to +// Solidity due to the different data structure (vector v.s. map). Thus, we skip diff-test for +// `batchVerifyOpeningProofs()` for now, and only test the outer `batchVerify()` directly From f5d1b37d66a6ca945f5c99e3b5ee8952b4eedd90 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Thu, 9 Nov 2023 14:55:21 +0800 Subject: [PATCH 14/38] add eval domain support for size=32 for testing --- contract-bindings/src/plonk_verifier.rs | 4 ++-- contract-bindings/src/polynomial_eval.rs | 4 ++-- contracts/rust/src/bin/diff_test.rs | 2 +- contracts/src/libraries/PolynomialEval.sol | 9 +++++++++ contracts/test/PlonkVerifier.t.sol | 23 +++++++++++++++++++++- contracts/test/PolynomialEval.t.sol | 13 ++++++------ 6 files changed, 43 insertions(+), 12 deletions(-) diff --git a/contract-bindings/src/plonk_verifier.rs b/contract-bindings/src/plonk_verifier.rs index df02021f19..a91171c235 100644 --- a/contract-bindings/src/plonk_verifier.rs +++ b/contract-bindings/src/plonk_verifier.rs @@ -261,12 +261,12 @@ pub mod plonk_verifier { pub static PLONKVERIFIER_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); #[rustfmt::skip] - const __BYTECODE: &[u8] = b"a9\x8Da\0:`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14a\0-WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\x046\x10a\x005W`\x005`\xE0\x1C\x80c6\xD8\xD6\xEB\x14a\0:W[`\0\x80\xFD[a\0Ma\0H6`\x04a5vV[a\0aV[`@Q\x90\x15\x15\x81R` \x01`@Q\x80\x91\x03\x90\xF3[`\0\x82Q\x85Q\x14\x15\x80a\0vWP\x82Q\x84Q\x14\x15[\x80a\0\x83WP\x82Q\x82Q\x14\x15[\x80a\0\x8DWP\x82Q\x15[\x15a\0\xABW`@Qc\xFD\x9A-\x1B`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0\x83Q`\x01`\x01`@\x1B\x03\x81\x11\x15a\0\xC6Wa\0\xC6a0\xB1V[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\0\xFFW\x81` \x01[a\0\xECa/\xC3V[\x81R` \x01\x90`\x01\x90\x03\x90\x81a\0\xE4W\x90P[P\x90P`\0[\x84Q\x81\x10\x15a\x02CWa\x010\x85\x82\x81Q\x81\x10a\x01#Wa\x01#a7\xF8V[` \x02` \x01\x01Qa\x02YV[`\0[\x86\x82\x81Q\x81\x10a\x01EWa\x01Ea7\xF8V[` \x02` \x01\x01QQ\x81\x10\x15a\x01\xA2Wa\x01\x90\x87\x83\x81Q\x81\x10a\x01jWa\x01ja7\xF8V[` \x02` \x01\x01Q\x82\x81Q\x81\x10a\x01\x83Wa\x01\x83a7\xF8V[` \x02` \x01\x01Qa\x03\x86V[\x80a\x01\x9A\x81a8$V[\x91PPa\x013V[Pa\x02\x13\x87\x82\x81Q\x81\x10a\x01\xB8Wa\x01\xB8a7\xF8V[` \x02` \x01\x01Q\x87\x83\x81Q\x81\x10a\x01\xD2Wa\x01\xD2a7\xF8V[` \x02` \x01\x01Q\x87\x84\x81Q\x81\x10a\x01\xECWa\x01\xECa7\xF8V[` \x02` \x01\x01Q\x87\x85\x81Q\x81\x10a\x02\x06Wa\x02\x06a7\xF8V[` \x02` \x01\x01Qa\x03\xEDV[\x82\x82\x81Q\x81\x10a\x02%Wa\x02%a7\xF8V[` \x02` \x01\x01\x81\x90RP\x80\x80a\x02;\x90a8$V[\x91PPa\x01\x05V[Pa\x02M\x81a\x05EV[\x91PP[\x94\x93PPPPV[\x80Qa\x02d\x90a\x0C\xE8V[a\x02q\x81` \x01Qa\x0C\xE8V[a\x02~\x81`@\x01Qa\x0C\xE8V[a\x02\x8B\x81``\x01Qa\x0C\xE8V[a\x02\x98\x81`\x80\x01Qa\x0C\xE8V[a\x02\xA5\x81`\xA0\x01Qa\x0C\xE8V[a\x02\xB2\x81`\xC0\x01Qa\x0C\xE8V[a\x02\xBF\x81`\xE0\x01Qa\x0C\xE8V[a\x02\xCD\x81a\x01\0\x01Qa\x0C\xE8V[a\x02\xDB\x81a\x01 \x01Qa\x0C\xE8V[a\x02\xE9\x81a\x01@\x01Qa\x0C\xE8V[a\x02\xF7\x81a\x01`\x01Qa\x0C\xE8V[a\x03\x05\x81a\x01\xA0\x01Qa\x03\x86V[a\x03\x13\x81a\x01\xC0\x01Qa\x03\x86V[a\x03!\x81a\x01\xE0\x01Qa\x03\x86V[a\x03/\x81a\x02\0\x01Qa\x03\x86V[a\x03=\x81a\x02 \x01Qa\x03\x86V[a\x03K\x81a\x02@\x01Qa\x03\x86V[a\x03Y\x81a\x02`\x01Qa\x03\x86V[a\x03g\x81a\x02\x80\x01Qa\x03\x86V[a\x03u\x81a\x02\xA0\x01Qa\x03\x86V[a\x03\x83\x81a\x02\xC0\x01Qa\x03\x86V[PV[`\0\x80Q` a98\x839\x81Q\x91R\x81\x10\x80a\x03\xE9W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FBn254: invalid scalar field\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[PPV[a\x03\xF5a/\xC3V[\x84` \x01Q\x84Q\x14a\x04\x1AW`@Qc \xFA\x9D\x89`\xE1\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0a\x04(\x86\x86\x86\x86a\rwV[\x90P`\0a\x049\x87`\0\x01Qa\x0FEV[\x90P`\0a\x04L\x82\x84`\xA0\x01Q\x89a\x11\xE1V[`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x91\x92P`\0\x91\x90` \x82\x01a\x03\xC0\x806\x837PP`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x92\x93P`\0\x92\x91P` \x82\x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x04\x8FW\x90PP\x90P`\0a\x04\xC8\x8B\x85\x8B\x89\x87\x87a\x12AV[`\xA0\x87\x01Q``\x87\x01Q\x91\x92P\x90`\0\x80Q` a98\x839\x81Q\x91R`\0\x81\x83\x85\t`@\x80Qa\x01\0\x81\x01\x82R`\xE0\x9C\x8D\x01Q\x81R` \x81\x01\x96\x90\x96R\x85\x01RPPP``\x81\x01\x91\x90\x91R`\x80\x81\x01\x92\x90\x92R`\xA0\x82\x01Ra\x01`\x87\x01Q`\xC0\x82\x01Ra\x01\x80\x90\x96\x01Q\x92\x86\x01\x92\x90\x92RP\x92\x95\x94PPPPPV[\x80Q`\0\x90`\0\x80Q` a98\x839\x81Q\x91R`\x01\x80\x83\x11\x15a\x05\xC6Wa\x05ka0=V[`\0[\x84\x81\x10\x15a\x05\xB8Wa\x05\xA6\x87\x82\x81Q\x81\x10a\x05\x8BWa\x05\x8Ba7\xF8V[` \x02` \x01\x01Q`\0\x01Q\x83a\x12j\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x80a\x05\xB0\x81a8$V[\x91PPa\x05nV[Pa\x05\xC2\x81a\x12tV[\x91PP[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`\0a\x05\xFB\x86`\x02a8=V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06\x12Wa\x06\x12a0\xB1V[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06;W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P`\0a\x06K\x87`\x02a8=V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06bWa\x06ba0\xB1V[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06\xA7W\x81` \x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x06\x80W\x90P[P\x90P`\x01`\0[\x88\x81\x10\x15a\x07\xF0W\x81\x84a\x06\xC4\x83`\x02a8=V[\x81Q\x81\x10a\x06\xD4Wa\x06\xD4a7\xF8V[` \x02` \x01\x01\x81\x81RPP\x8A\x81\x81Q\x81\x10a\x06\xF2Wa\x06\xF2a7\xF8V[` \x02` \x01\x01Q`\xC0\x01Q\x83\x82`\x02a\x07\x0C\x91\x90a8=V[\x81Q\x81\x10a\x07\x1CWa\x07\x1Ca7\xF8V[` \x02` \x01\x01\x81\x90RP`\0\x80\x8C\x83\x81Q\x81\x10a\x07\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x05`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\x0F\x84\x84a\x1AxV[\x80\x82Ra\x12\x1F\x90\x85\x90\x85\x90a\x1A\xCCV[` \x82\x01R\x80Qa\x125\x90\x85\x90\x84\x90\x86\x90a\x1B2V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12O\x85\x87\x89a\x1C\x88V[\x90Pa\x12_\x88\x86\x89\x89\x88\x88a\x1DtV[a\x0C\xDC\x81\x87\x86a \x80V[a\x03\xE9\x82\x82a \xD0V[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x12\x9C\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a8\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x12\xCDWa\x12\xCDa7\xF8V[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x12\xE9Wa\x12\xE9a7\xF8V[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x08\x94\x93\x92\x91\x90a8\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x138Wa\x138a7\xF8V[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13YWa\x13Ya7\xF8V[` \x02\x01\x81\x81RPPa\x02Qa\x13\x9C\x83\x83`@Q` \x01a\x13\x84\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a!\x03V[a\"\x10V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14D\x83`\0\x81Q\x81\x10a\x14\x1CWa\x14\x1Ca7\xF8V[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x147Wa\x147a7\xF8V[` \x02` \x01\x01Qa\"\x90V[\x90P`\x01[\x82Q\x81\x10\x15a\x14\x9EWa\x14\x8A\x82a\x14\x85\x86\x84\x81Q\x81\x10a\x14kWa\x14ka7\xF8V[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x147Wa\x147a7\xF8V[a#4V[\x91P\x80a\x14\x96\x81a8$V[\x91PPa\x14IV[P\x92\x91PPV[`\0a\x14\xBF`\0\x80Q` a98\x839\x81Q\x91R\x83a8\xCDV[a\x14\xD7\x90`\0\x80Q` a98\x839\x81Q\x91Ra8\xEFV[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x05WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a9\x18\x839\x81Q\x91R\x84` \x01Qa\x158\x91\x90a8\xCDV[a\x15P\x90`\0\x80Q` a9\x18\x839\x81Q\x91Ra8\xEFV[\x90R\x92\x91PPV[a\x15\x83`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x16\xFFW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\x1F\x91\x90\x83\x90` \x01a9\x02V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x17v\x84a\x17qa\x17G\x84a#\xDBV[`@Q` \x01a\x17Y\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x04a!\x03V[a\x17\x0BV[a\x17\xB4\x84a\x17qa\x17\x8A\x86`\0\x01Qa#\xDBV[`@Q` \x01a\x17\x9C\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a!\x03V[a\x17\xC8\x84a\x17qa\x17\x8A\x86` \x01Qa#\xDBV[a\x17\xD3\x84`\x01a \xD0V[a\x17\xFD\x84\x7F/\x8D\xD1\xF1\xA7X\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[\x81` \x03a\x12[WP`@\x80Q`\xA0\x81\x01\x82R`\x05\x81R` \x81\x01\x92\x90\x92R\x7F.\xE1+\xFFJ(\x13(j\x8D\xC3\x88\xCDuM\x9A>\xF2I\x065\xEB\xA5\x0C\xB9\xC2\xE5\xE7P\x80\0\x01\x90\x82\x01R\x7F\t\xC52\xC60k\x93\xD2\x96x \rG\xC0\xB2\xA9\x9C\x18\xD5\x1B\x83\x8E\xEB\x1D>\xEDLS;\xB5\x12\xD0``\x82\x01R\x7F'$q6\x03\xBF\xBDy\n\xEA\xF3\xE7\xDF%\xD8\xE7\xEF\x8F1\x134\x90[M\x8C\x99\x98\x0C\xF2\x10\x97\x9D`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x98`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\xA2\x84\x84a\x1B\x0BV[\x80\x82Ra\x12\xB2\x90\x85\x90\x85\x90a\x1B_V[` \x82\x01R\x80Qa\x12\xC8\x90\x85\x90\x84\x90\x86\x90a\x1B\xC5V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12\xE2\x85\x87\x89a\x1D\x1BV[\x90Pa\x12\xF2\x88\x86\x89\x89\x88\x88a\x1E\x07V[a\x0C\xDC\x81\x87\x86a!\x13V[a\x03\xE9\x82\x82a!cV[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x13/\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a9*V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x13`Wa\x13`a8\x8BV[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x13|Wa\x13|a8\x8BV[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x9B\x94\x93\x92\x91\x90a9*V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x13\xCBWa\x13\xCBa8\x8BV[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13\xECWa\x13\xECa8\x8BV[` \x02\x01\x81\x81RPPa\x02Qa\x14/\x83\x83`@Q` \x01a\x14\x17\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a!\x96V[a\"\xA3V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x99W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14\xD7\x83`\0\x81Q\x81\x10a\x14\xAFWa\x14\xAFa8\x8BV[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x14\xCAWa\x14\xCAa8\x8BV[` \x02` \x01\x01Qa##V[\x90P`\x01[\x82Q\x81\x10\x15a\x151Wa\x15\x1D\x82a\x15\x18\x86\x84\x81Q\x81\x10a\x14\xFEWa\x14\xFEa8\x8BV[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x14\xCAWa\x14\xCAa8\x8BV[a#\xC7V[\x91P\x80a\x15)\x81a8\xB7V[\x91PPa\x14\xDCV[P\x92\x91PPV[`\0a\x15R`\0\x80Q` a9\xCB\x839\x81Q\x91R\x83a9`V[a\x15j\x90`\0\x80Q` a9\xCB\x839\x81Q\x91Ra9\x82V[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x98WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a9\xAB\x839\x81Q\x91R\x84` \x01Qa\x15\xCB\x91\x90a9`V[a\x15\xE3\x90`\0\x80Q` a9\xAB\x839\x81Q\x91Ra9\x82V[\x90R\x92\x91PPV[a\x16\x16`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x17\x92W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\xB2\x91\x90\x83\x90` \x01a9\x95V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x18\t\x84a\x18\x04a\x17\xDA\x84a$nV[`@Q` \x01a\x17\xEC\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x04a!\x96V[a\x17\x9EV[a\x18G\x84a\x18\x04a\x18\x1D\x86`\0\x01Qa$nV[`@Q` \x01a\x18/\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a!\x96V[a\x18[\x84a\x18\x04a\x18\x1D\x86` \x01Qa$nV[a\x18f\x84`\x01a!cV[a\x18\x90\x84\x7F/\x8D\xD1\xF1\xA7X\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x05`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\x0F\x84\x84a\x1AxV[\x80\x82Ra\x12\x1F\x90\x85\x90\x85\x90a\x1A\xCCV[` \x82\x01R\x80Qa\x125\x90\x85\x90\x84\x90\x86\x90a\x1B2V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12O\x85\x87\x89a\x1C\x88V[\x90Pa\x12_\x88\x86\x89\x89\x88\x88a\x1DtV[a\x0C\xDC\x81\x87\x86a \x80V[a\x03\xE9\x82\x82a \xD0V[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x12\x9C\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a8\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x12\xCDWa\x12\xCDa7\xF8V[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x12\xE9Wa\x12\xE9a7\xF8V[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x08\x94\x93\x92\x91\x90a8\x97V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x138Wa\x138a7\xF8V[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13YWa\x13Ya7\xF8V[` \x02\x01\x81\x81RPPa\x02Qa\x13\x9C\x83\x83`@Q` \x01a\x13\x84\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a!\x03V[a\"\x10V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x06W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14D\x83`\0\x81Q\x81\x10a\x14\x1CWa\x14\x1Ca7\xF8V[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x147Wa\x147a7\xF8V[` \x02` \x01\x01Qa\"\x90V[\x90P`\x01[\x82Q\x81\x10\x15a\x14\x9EWa\x14\x8A\x82a\x14\x85\x86\x84\x81Q\x81\x10a\x14kWa\x14ka7\xF8V[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x147Wa\x147a7\xF8V[a#4V[\x91P\x80a\x14\x96\x81a8$V[\x91PPa\x14IV[P\x92\x91PPV[`\0a\x14\xBF`\0\x80Q` a98\x839\x81Q\x91R\x83a8\xCDV[a\x14\xD7\x90`\0\x80Q` a98\x839\x81Q\x91Ra8\xEFV[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x05WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a9\x18\x839\x81Q\x91R\x84` \x01Qa\x158\x91\x90a8\xCDV[a\x15P\x90`\0\x80Q` a9\x18\x839\x81Q\x91Ra8\xEFV[\x90R\x92\x91PPV[a\x15\x83`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x16\xFFW`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\x1F\x91\x90\x83\x90` \x01a9\x02V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x17v\x84a\x17qa\x17G\x84a#\xDBV[`@Q` \x01a\x17Y\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x04a!\x03V[a\x17\x0BV[a\x17\xB4\x84a\x17qa\x17\x8A\x86`\0\x01Qa#\xDBV[`@Q` \x01a\x17\x9C\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a!\x03V[a\x17\xC8\x84a\x17qa\x17\x8A\x86` \x01Qa#\xDBV[a\x17\xD3\x84`\x01a \xD0V[a\x17\xFD\x84\x7F/\x8D\xD1\xF1\xA7X\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[\x81` \x03a\x12[WP`@\x80Q`\xA0\x81\x01\x82R`\x05\x81R` \x81\x01\x92\x90\x92R\x7F.\xE1+\xFFJ(\x13(j\x8D\xC3\x88\xCDuM\x9A>\xF2I\x065\xEB\xA5\x0C\xB9\xC2\xE5\xE7P\x80\0\x01\x90\x82\x01R\x7F\t\xC52\xC60k\x93\xD2\x96x \rG\xC0\xB2\xA9\x9C\x18\xD5\x1B\x83\x8E\xEB\x1D>\xEDLS;\xB5\x12\xD0``\x82\x01R\x7F'$q6\x03\xBF\xBDy\n\xEA\xF3\xE7\xDF%\xD8\xE7\xEF\x8F1\x134\x90[M\x8C\x99\x98\x0C\xF2\x10\x97\x9D`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x98`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\xA2\x84\x84a\x1B\x0BV[\x80\x82Ra\x12\xB2\x90\x85\x90\x85\x90a\x1B_V[` \x82\x01R\x80Qa\x12\xC8\x90\x85\x90\x84\x90\x86\x90a\x1B\xC5V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12\xE2\x85\x87\x89a\x1D\x1BV[\x90Pa\x12\xF2\x88\x86\x89\x89\x88\x88a\x1E\x07V[a\x0C\xDC\x81\x87\x86a!\x13V[a\x03\xE9\x82\x82a!cV[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x13/\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a9*V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x13`Wa\x13`a8\x8BV[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x13|Wa\x13|a8\x8BV[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x9B\x94\x93\x92\x91\x90a9*V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x13\xCBWa\x13\xCBa8\x8BV[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13\xECWa\x13\xECa8\x8BV[` \x02\x01\x81\x81RPPa\x02Qa\x14/\x83\x83`@Q` \x01a\x14\x17\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a!\x96V[a\"\xA3V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x99W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14\xD7\x83`\0\x81Q\x81\x10a\x14\xAFWa\x14\xAFa8\x8BV[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x14\xCAWa\x14\xCAa8\x8BV[` \x02` \x01\x01Qa##V[\x90P`\x01[\x82Q\x81\x10\x15a\x151Wa\x15\x1D\x82a\x15\x18\x86\x84\x81Q\x81\x10a\x14\xFEWa\x14\xFEa8\x8BV[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x14\xCAWa\x14\xCAa8\x8BV[a#\xC7V[\x91P\x80a\x15)\x81a8\xB7V[\x91PPa\x14\xDCV[P\x92\x91PPV[`\0a\x15R`\0\x80Q` a9\xCB\x839\x81Q\x91R\x83a9`V[a\x15j\x90`\0\x80Q` a9\xCB\x839\x81Q\x91Ra9\x82V[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x98WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a9\xAB\x839\x81Q\x91R\x84` \x01Qa\x15\xCB\x91\x90a9`V[a\x15\xE3\x90`\0\x80Q` a9\xAB\x839\x81Q\x91Ra9\x82V[\x90R\x92\x91PPV[a\x16\x16`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x17\x92W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\xB2\x91\x90\x83\x90` \x01a9\x95V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x18\t\x84a\x18\x04a\x17\xDA\x84a$nV[`@Q` \x01a\x17\xEC\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x04a!\x96V[a\x17\x9EV[a\x18G\x84a\x18\x04a\x18\x1D\x86`\0\x01Qa$nV[`@Q` \x01a\x18/\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a!\x96V[a\x18[\x84a\x18\x04a\x18\x1D\x86` \x01Qa$nV[a\x18f\x84`\x01a!cV[a\x18\x90\x84\x7F/\x8D\xD1\xF1\xA7X = ::ethers::contract::Lazy::new(__abi); #[rustfmt::skip] - const __BYTECODE: &[u8] = b"`V`7`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14`*WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \x03$F\x84\xF2N\xCBk\x12\xC0]\xD3\x04\0\xD1dvM\x94@\xA8\xD7d)\xEE~\x96\x91\x0B\x12L\xFBdsolcC\0\x08\x14\x003"; + const __BYTECODE: &[u8] = b"`V`7`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14`*WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \x80\xE6\x9E+\xBD\xD9\xE1jP\xCA\x0F\xD5GPd9m\x91cG\x92A\x12\xF82\x97\xF1\x18Sz\xB5odsolcC\0\x08\x14\x003"; /// The bytecode of the contract. pub static POLYNOMIALEVAL_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static(__BYTECODE); #[rustfmt::skip] - const __DEPLOYED_BYTECODE: &[u8] = b"s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \x03$F\x84\xF2N\xCBk\x12\xC0]\xD3\x04\0\xD1dvM\x94@\xA8\xD7d)\xEE~\x96\x91\x0B\x12L\xFBdsolcC\0\x08\x14\x003"; + const __DEPLOYED_BYTECODE: &[u8] = b"s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \x80\xE6\x9E+\xBD\xD9\xE1jP\xCA\x0F\xD5GPd9m\x91cG\x92A\x12\xF82\x97\xF1\x18Sz\xB5odsolcC\0\x08\x14\x003"; /// The deployed bytecode of the contract. pub static POLYNOMIALEVAL_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); diff --git a/contracts/rust/src/bin/diff_test.rs b/contracts/rust/src/bin/diff_test.rs index d4fb850464..9ae549113a 100644 --- a/contracts/rust/src/bin/diff_test.rs +++ b/contracts/rust/src/bin/diff_test.rs @@ -961,6 +961,7 @@ fn gen_plonk_proof_for_test( > { // 1. Simulate universal setup let rng = &mut jf_utils::test_rng(); + // FIXME: (alex) fix SRS to use Aztec's instead let srs = PlonkKzgSnark::::universal_setup_for_testing(2u64.pow(17) as usize, rng)?; // 2. Create circuits @@ -1017,7 +1018,6 @@ fn gen_plonk_proof_for_test( // Different `m`s lead to different circuits. // Different `a0`s lead to different witness values. -// TODO: (alex) change this circuit for easier size counting fn gen_circuit_for_test(m: usize, a0: usize) -> Result> { let mut cs: PlonkCircuit = PlonkCircuit::new_turbo_plonk(); // Create variables diff --git a/contracts/src/libraries/PolynomialEval.sol b/contracts/src/libraries/PolynomialEval.sol index c7b19ffab1..39ee1e7199 100644 --- a/contracts/src/libraries/PolynomialEval.sol +++ b/contracts/src/libraries/PolynomialEval.sol @@ -63,6 +63,15 @@ library PolynomialEval { 0x1bf82deba7d74902c3708cc6e70e61f30512eca95655210e276e5858ce8f58e5, 0x244cf010c43ca87237d8b00bf9dd50c4c01c7f086bd4e8c920e75251d96f0d22 ); + } else if (domainSize == 32) { + // useful for small-size test, in practice unlikely to be used. + return EvalDomain( + 5, + domainSize, + 0x2ee12bff4a2813286a8dc388cd754d9a3ef2490635eba50cb9c2e5e750800001, + 0x9c532c6306b93d29678200d47c0b2a99c18d51b838eeb1d3eed4c533bb512d0, + 0x2724713603bfbd790aeaf3e7df25d8e7ef8f311334905b4d8c99980cf210979d + ); } else { revert UnsupportedDegree(); } diff --git a/contracts/test/PlonkVerifier.t.sol b/contracts/test/PlonkVerifier.t.sol index e06aa516f0..cb512ea792 100644 --- a/contracts/test/PlonkVerifier.t.sol +++ b/contracts/test/PlonkVerifier.t.sol @@ -166,6 +166,7 @@ contract PlonkVerifier_batchVerify_Test is Test { /// @dev Test happy and unhappy path of `batchVerify`. function test_batchVerify_succeeds() external { + // TODO: change to i<6 for (uint32 i = 1; i < 2; i++) { string[] memory cmds = new string[](6); cmds[0] = "cargo"; @@ -190,7 +191,27 @@ contract PlonkVerifier_batchVerify_Test is Test { assert(V.batchVerify(verifyingKeys, publicInputs, proofs, extraTranscriptInitMsgs)); // unhappy path - // TODO: (alex) + // wrong vk + IPlonkVerifier.VerifyingKey[] memory badVks = verifyingKeys; + badVks[0].q1 = BN254.negate(verifyingKeys[0].q1); + badVks[0].qEcc = BN254.negate(verifyingKeys[0].qEcc); + assert(!V.batchVerify(badVks, publicInputs, proofs, extraTranscriptInitMsgs)); + + // wrong public inputs + uint256[][] memory badPis = publicInputs; + badPis[0][0] = 0x1234; + assert(!V.batchVerify(verifyingKeys, badPis, proofs, extraTranscriptInitMsgs)); + + // wrong proofs + IPlonkVerifier.PlonkProof[] memory badProofs; + badProofs[0].wireEval0 = 0x12; + badProofs[0].sigmaEval0 = 0x34; + assert(!V.batchVerify(verifyingKeys, publicInputs, badProofs, extraTranscriptInitMsgs)); + + // wrong extraMsgs + bytes[] memory badMsgs = extraTranscriptInitMsgs; + badMsgs[0] = bytes("hi"); + assert(!V.batchVerify(verifyingKeys, publicInputs, proofs, badMsgs)); } } } diff --git a/contracts/test/PolynomialEval.t.sol b/contracts/test/PolynomialEval.t.sol index 57871cfb42..80b1666fe2 100644 --- a/contracts/test/PolynomialEval.t.sol +++ b/contracts/test/PolynomialEval.t.sol @@ -12,22 +12,23 @@ import { BN254 } from "bn254/BN254.sol"; import { PolynomialEval as Poly } from "../src/libraries/PolynomialEval.sol"; contract PolynomialEval_newEvalDomain_Test is Test { - /// @dev diff-test with Rust when `domainSize` is in {2^14, 2^15, 2^16, 2^17} + /// @dev diff-test with Rust when `domainSize` is in {2^14, 2^15, 2^16, 2^17, 2^5} function test_supportedDomainSize_matches() external { - for (uint256 logSize = 14; logSize < 18; logSize++) { + uint256[5] memory logSizes = [uint256(5), 14, 15, 16, 17]; + for (uint256 i = 0; i < 5; i++) { string[] memory cmds = new string[](6); cmds[0] = "cargo"; cmds[1] = "run"; cmds[2] = "--bin"; cmds[3] = "diff-test"; cmds[4] = "new-poly-eval-domain"; - cmds[5] = vm.toString(logSize); + cmds[5] = vm.toString(logSizes[i]); bytes memory result = vm.ffi(cmds); (uint256 sizeInv, uint256 groupGen, uint256 groupGenInv) = abi.decode(result, (uint256, uint256, uint256)); - Poly.EvalDomain memory domain = Poly.newEvalDomain(2 ** logSize); + Poly.EvalDomain memory domain = Poly.newEvalDomain(2 ** logSizes[i]); assertEq(sizeInv, domain.sizeInv); assertEq(groupGen, domain.groupGen); assertEq(groupGenInv, domain.groupGenInv); @@ -35,11 +36,11 @@ contract PolynomialEval_newEvalDomain_Test is Test { } /// forge-config: default.fuzz.runs = 20 - /// @dev Test revert if domainSize is not among {2^14, 2^15, 2^16, 2^17} + /// @dev Test revert if domainSize is not among {2^14, 2^15, 2^16, 2^17, 2^5} function testFuzz_unsupportedDomainSize_reverts(uint256 domainSize) external { vm.assume( domainSize != 2 ** 14 && domainSize != 2 ** 15 && domainSize != 2 ** 16 - && domainSize != 2 ** 17 + && domainSize != 2 ** 17 && domainSize != 2 ** 5 ); vm.expectRevert(Poly.UnsupportedDegree.selector); From 388ddd18e45d635128ecaf70d140da2be9080fe3 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Thu, 9 Nov 2023 21:56:47 +0800 Subject: [PATCH 15/38] test: finish all tests --- Cargo.lock | 33 +++++++++++++++++++++ contracts/rust/Cargo.toml | 1 + contracts/rust/src/bin/diff_test.rs | 43 ++++++++++++++++++---------- contracts/test/PlonkVerifier.t.sol | 2 +- data/kzg10-bn254-aztec-srs-1024.bin | Bin 0 -> 65880 bytes 5 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 data/kzg10-bn254-aztec-srs-1024.bin diff --git a/Cargo.lock b/Cargo.lock index fef7d01011..73ab46dea6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -498,6 +498,24 @@ dependencies = [ "rayon", ] +[[package]] +name = "ark-poly-commit" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a741492629ffcd228337676dc223a28551aa6792eedb8a2a22c767f00df6c89" +dependencies = [ + "ark-crypto-primitives", + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-poly", + "ark-relations", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "rayon", +] + [[package]] name = "ark-relations" version = "0.4.0" @@ -1813,6 +1831,20 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crs" +version = "0.1.0" +source = "git+https://github.com/alxiong/crs#5d1142432e4045c3c0847b6481c89afddf6bb2c2" +dependencies = [ + "anyhow", + "ark-bn254", + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-poly-commit", + "ark-serialize 0.4.2", + "ark-std 0.4.0", +] + [[package]] name = "crunchy" version = "0.2.2" @@ -3736,6 +3768,7 @@ dependencies = [ "async-std", "clap", "contract-bindings", + "crs", "digest 0.10.7", "ethers", "ethers-providers", diff --git a/contracts/rust/Cargo.toml b/contracts/rust/Cargo.toml index b48d317e0d..41ec1e930d 100644 --- a/contracts/rust/Cargo.toml +++ b/contracts/rust/Cargo.toml @@ -19,6 +19,7 @@ async-compatibility-layer = { git = "https://github.com/EspressoSystems/async-co async-std = "1.12.0" clap = { version = "^4.4", features = ["derive"] } contract-bindings = { path = "../../contract-bindings" } +crs = { git = "https://github.com/alxiong/crs" } digest = { version = "0.10", default-features = false, features = ["alloc"] } ethers = { version = "2.0.4" } ethers-providers = "2.0.4" diff --git a/contracts/rust/src/bin/diff_test.rs b/contracts/rust/src/bin/diff_test.rs index 9ae549113a..af582d3188 100644 --- a/contracts/rust/src/bin/diff_test.rs +++ b/contracts/rust/src/bin/diff_test.rs @@ -26,7 +26,7 @@ use jf_plonk::{ testing_apis::Verifier, transcript::{PlonkTranscript, SolidityTranscript}, }; -use jf_primitives::pcs::prelude::Commitment; +use jf_primitives::pcs::prelude::{Commitment, UnivariateUniversalParams}; use jf_relation::{Arithmetization, Circuit, PlonkCircuit}; use num_bigint::BigUint; use num_traits::Num; @@ -228,10 +228,12 @@ fn main() { field_to_u256::(coset_k[2]), field_to_u256::(coset_k[3]), field_to_u256::(coset_k[4]), - field_to_u256::(open_key.beta_h.x().unwrap().c0), + // NOTE: be EXTRA careful here!! Solidity's BN254.G2Point: Fp2 = x0 * u + x1 + // whereas in rust: Fp2 = x0 + x1 * u field_to_u256::(open_key.beta_h.x().unwrap().c1), - field_to_u256::(open_key.beta_h.y().unwrap().c0), + field_to_u256::(open_key.beta_h.x().unwrap().c0), field_to_u256::(open_key.beta_h.y().unwrap().c1), + field_to_u256::(open_key.beta_h.y().unwrap().c0), ); println!("{}", res.encode_hex()); } @@ -441,18 +443,18 @@ fn coset_k() -> Vec { /// Returns `OpenKeys` for KZG10 over BN254 curve from Aztec's SRS fn open_key() -> OpenKey { let g = G1Affine::new_unchecked(MontFp!("1"), MontFp!("2")); - let h = G2Affine::new_unchecked( + let h = G2Affine::new( Fp2::new( Fq::from( BigUint::from_str_radix( - "198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2", + "1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed", 16, ) .unwrap(), ), Fq::from( BigUint::from_str_radix( - "1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed", + "198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2", 16, ) .unwrap(), @@ -461,32 +463,32 @@ fn open_key() -> OpenKey { Fp2::new( Fq::from( BigUint::from_str_radix( - "090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b", + "12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", 16, ) .unwrap(), ), Fq::from( BigUint::from_str_radix( - "12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b", 16, ) .unwrap(), ), ), ); - let beta_h = G2Affine::new_unchecked( + let beta_h = G2Affine::new( Fp2::new( Fq::from( BigUint::from_str_radix( - "260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1", + "0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0", 16, ) .unwrap(), ), Fq::from( BigUint::from_str_radix( - "0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0", + "260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1", 16, ) .unwrap(), @@ -495,14 +497,14 @@ fn open_key() -> OpenKey { Fp2::new( Fq::from( BigUint::from_str_radix( - "04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4", + "22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55", 16, ) .unwrap(), ), Fq::from( BigUint::from_str_radix( - "22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55", + "04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4", 16, ) .unwrap(), @@ -961,8 +963,19 @@ fn gen_plonk_proof_for_test( > { // 1. Simulate universal setup let rng = &mut jf_utils::test_rng(); - // FIXME: (alex) fix SRS to use Aztec's instead - let srs = PlonkKzgSnark::::universal_setup_for_testing(2u64.pow(17) as usize, rng)?; + let srs = { + let aztec_srs = crs::aztec20::kzg10_setup(1024)?; + + UnivariateUniversalParams { + powers_of_g: aztec_srs.powers_of_g, + h: aztec_srs.h, + beta_h: aztec_srs.beta_h, + } + }; + let open_key = open_key(); + assert_eq!(srs.h, open_key.h); + assert_eq!(srs.beta_h, open_key.beta_h); + assert_eq!(srs.powers_of_g[0], open_key.g); // 2. Create circuits let circuits = (0..num_proof) diff --git a/contracts/test/PlonkVerifier.t.sol b/contracts/test/PlonkVerifier.t.sol index cb512ea792..69c433c8b0 100644 --- a/contracts/test/PlonkVerifier.t.sol +++ b/contracts/test/PlonkVerifier.t.sol @@ -203,7 +203,7 @@ contract PlonkVerifier_batchVerify_Test is Test { assert(!V.batchVerify(verifyingKeys, badPis, proofs, extraTranscriptInitMsgs)); // wrong proofs - IPlonkVerifier.PlonkProof[] memory badProofs; + IPlonkVerifier.PlonkProof[] memory badProofs = proofs; badProofs[0].wireEval0 = 0x12; badProofs[0].sigmaEval0 = 0x34; assert(!V.batchVerify(verifyingKeys, publicInputs, badProofs, extraTranscriptInitMsgs)); diff --git a/data/kzg10-bn254-aztec-srs-1024.bin b/data/kzg10-bn254-aztec-srs-1024.bin new file mode 100644 index 0000000000000000000000000000000000000000..ffe616fecfa7afaf97e0d993e045414859f18aeb GIT binary patch literal 65880 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

AbSPFM(>G~jd27k+xoOA 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 Date: Fri, 10 Nov 2023 01:48:00 +0800 Subject: [PATCH 16/38] bugfix: add missing check, improving test to catch similar mistakes --- contract-bindings/src/plonk_verifier.rs | 4 +- contracts/src/libraries/PlonkVerifier.sol | 1 + contracts/test/PlonkVerifier.t.sol | 161 ++++++---------------- 3 files changed, 47 insertions(+), 119 deletions(-) diff --git a/contract-bindings/src/plonk_verifier.rs b/contract-bindings/src/plonk_verifier.rs index a91171c235..8e8a5e4c3f 100644 --- a/contract-bindings/src/plonk_verifier.rs +++ b/contract-bindings/src/plonk_verifier.rs @@ -261,12 +261,12 @@ pub mod plonk_verifier { pub static PLONKVERIFIER_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); #[rustfmt::skip] - const __BYTECODE: &[u8] = b"a: a\0:`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14a\0-WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\x046\x10a\x005W`\x005`\xE0\x1C\x80c6\xD8\xD6\xEB\x14a\0:W[`\0\x80\xFD[a\0Ma\0H6`\x04a6\tV[a\0aV[`@Q\x90\x15\x15\x81R` \x01`@Q\x80\x91\x03\x90\xF3[`\0\x82Q\x85Q\x14\x15\x80a\0vWP\x82Q\x84Q\x14\x15[\x80a\0\x83WP\x82Q\x82Q\x14\x15[\x80a\0\x8DWP\x82Q\x15[\x15a\0\xABW`@Qc\xFD\x9A-\x1B`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0\x83Q`\x01`\x01`@\x1B\x03\x81\x11\x15a\0\xC6Wa\0\xC6a1DV[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\0\xFFW\x81` \x01[a\0\xECa0VV[\x81R` \x01\x90`\x01\x90\x03\x90\x81a\0\xE4W\x90P[P\x90P`\0[\x84Q\x81\x10\x15a\x02CWa\x010\x85\x82\x81Q\x81\x10a\x01#Wa\x01#a8\x8BV[` \x02` \x01\x01Qa\x02YV[`\0[\x86\x82\x81Q\x81\x10a\x01EWa\x01Ea8\x8BV[` \x02` \x01\x01QQ\x81\x10\x15a\x01\xA2Wa\x01\x90\x87\x83\x81Q\x81\x10a\x01jWa\x01ja8\x8BV[` \x02` \x01\x01Q\x82\x81Q\x81\x10a\x01\x83Wa\x01\x83a8\x8BV[` \x02` \x01\x01Qa\x03\x86V[\x80a\x01\x9A\x81a8\xB7V[\x91PPa\x013V[Pa\x02\x13\x87\x82\x81Q\x81\x10a\x01\xB8Wa\x01\xB8a8\x8BV[` \x02` \x01\x01Q\x87\x83\x81Q\x81\x10a\x01\xD2Wa\x01\xD2a8\x8BV[` \x02` \x01\x01Q\x87\x84\x81Q\x81\x10a\x01\xECWa\x01\xECa8\x8BV[` \x02` \x01\x01Q\x87\x85\x81Q\x81\x10a\x02\x06Wa\x02\x06a8\x8BV[` \x02` \x01\x01Qa\x03\xEDV[\x82\x82\x81Q\x81\x10a\x02%Wa\x02%a8\x8BV[` \x02` \x01\x01\x81\x90RP\x80\x80a\x02;\x90a8\xB7V[\x91PPa\x01\x05V[Pa\x02M\x81a\x05EV[\x91PP[\x94\x93PPPPV[\x80Qa\x02d\x90a\x0C\xE8V[a\x02q\x81` \x01Qa\x0C\xE8V[a\x02~\x81`@\x01Qa\x0C\xE8V[a\x02\x8B\x81``\x01Qa\x0C\xE8V[a\x02\x98\x81`\x80\x01Qa\x0C\xE8V[a\x02\xA5\x81`\xA0\x01Qa\x0C\xE8V[a\x02\xB2\x81`\xC0\x01Qa\x0C\xE8V[a\x02\xBF\x81`\xE0\x01Qa\x0C\xE8V[a\x02\xCD\x81a\x01\0\x01Qa\x0C\xE8V[a\x02\xDB\x81a\x01 \x01Qa\x0C\xE8V[a\x02\xE9\x81a\x01@\x01Qa\x0C\xE8V[a\x02\xF7\x81a\x01`\x01Qa\x0C\xE8V[a\x03\x05\x81a\x01\xA0\x01Qa\x03\x86V[a\x03\x13\x81a\x01\xC0\x01Qa\x03\x86V[a\x03!\x81a\x01\xE0\x01Qa\x03\x86V[a\x03/\x81a\x02\0\x01Qa\x03\x86V[a\x03=\x81a\x02 \x01Qa\x03\x86V[a\x03K\x81a\x02@\x01Qa\x03\x86V[a\x03Y\x81a\x02`\x01Qa\x03\x86V[a\x03g\x81a\x02\x80\x01Qa\x03\x86V[a\x03u\x81a\x02\xA0\x01Qa\x03\x86V[a\x03\x83\x81a\x02\xC0\x01Qa\x03\x86V[PV[`\0\x80Q` a9\xCB\x839\x81Q\x91R\x81\x10\x80a\x03\xE9W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FBn254: invalid scalar field\0\0\0\0\0`D\x82\x01R`d\x01[`@Q\x80\x91\x03\x90\xFD[PPV[a\x03\xF5a0VV[\x84` \x01Q\x84Q\x14a\x04\x1AW`@Qc \xFA\x9D\x89`\xE1\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[`\0a\x04(\x86\x86\x86\x86a\rwV[\x90P`\0a\x049\x87`\0\x01Qa\x0FEV[\x90P`\0a\x04L\x82\x84`\xA0\x01Q\x89a\x12tV[`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x91\x92P`\0\x91\x90` \x82\x01a\x03\xC0\x806\x837PP`@\x80Q`\x1E\x80\x82Ra\x03\xE0\x82\x01\x90\x92R\x92\x93P`\0\x92\x91P` \x82\x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x04\x8FW\x90PP\x90P`\0a\x04\xC8\x8B\x85\x8B\x89\x87\x87a\x12\xD4V[`\xA0\x87\x01Q``\x87\x01Q\x91\x92P\x90`\0\x80Q` a9\xCB\x839\x81Q\x91R`\0\x81\x83\x85\t`@\x80Qa\x01\0\x81\x01\x82R`\xE0\x9C\x8D\x01Q\x81R` \x81\x01\x96\x90\x96R\x85\x01RPPP``\x81\x01\x91\x90\x91R`\x80\x81\x01\x92\x90\x92R`\xA0\x82\x01Ra\x01`\x87\x01Q`\xC0\x82\x01Ra\x01\x80\x90\x96\x01Q\x92\x86\x01\x92\x90\x92RP\x92\x95\x94PPPPPV[\x80Q`\0\x90`\0\x80Q` a9\xCB\x839\x81Q\x91R`\x01\x80\x83\x11\x15a\x05\xC6Wa\x05ka0\xD0V[`\0[\x84\x81\x10\x15a\x05\xB8Wa\x05\xA6\x87\x82\x81Q\x81\x10a\x05\x8BWa\x05\x8Ba8\x8BV[` \x02` \x01\x01Q`\0\x01Q\x83a\x12\xFD\x90\x91\x90c\xFF\xFF\xFF\xFF\x16V[\x80a\x05\xB0\x81a8\xB7V[\x91PPa\x05nV[Pa\x05\xC2\x81a\x13\x07V[\x91PP[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R`\0a\x05\xFB\x86`\x02a8\xD0V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06\x12Wa\x06\x12a1DV[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06;W\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x90P`\0a\x06K\x87`\x02a8\xD0V[`\x01`\x01`@\x1B\x03\x81\x11\x15a\x06bWa\x06ba1DV[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a\x06\xA7W\x81` \x01[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81R` \x01\x90`\x01\x90\x03\x90\x81a\x06\x80W\x90P[P\x90P`\x01`\0[\x88\x81\x10\x15a\x07\xF0W\x81\x84a\x06\xC4\x83`\x02a8\xD0V[\x81Q\x81\x10a\x06\xD4Wa\x06\xD4a8\x8BV[` \x02` \x01\x01\x81\x81RPP\x8A\x81\x81Q\x81\x10a\x06\xF2Wa\x06\xF2a8\x8BV[` \x02` \x01\x01Q`\xC0\x01Q\x83\x82`\x02a\x07\x0C\x91\x90a8\xD0V[\x81Q\x81\x10a\x07\x1CWa\x07\x1Ca8\x8BV[` \x02` \x01\x01\x81\x90RP`\0\x80\x8C\x83\x81Q\x81\x10a\x07\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[\x81` \x03a\x12[WP`@\x80Q`\xA0\x81\x01\x82R`\x05\x81R` \x81\x01\x92\x90\x92R\x7F.\xE1+\xFFJ(\x13(j\x8D\xC3\x88\xCDuM\x9A>\xF2I\x065\xEB\xA5\x0C\xB9\xC2\xE5\xE7P\x80\0\x01\x90\x82\x01R\x7F\t\xC52\xC60k\x93\xD2\x96x \rG\xC0\xB2\xA9\x9C\x18\xD5\x1B\x83\x8E\xEB\x1D>\xEDLS;\xB5\x12\xD0``\x82\x01R\x7F'$q6\x03\xBF\xBDy\n\xEA\xF3\xE7\xDF%\xD8\xE7\xEF\x8F1\x134\x90[M\x8C\x99\x98\x0C\xF2\x10\x97\x9D`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x98`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\xA2\x84\x84a\x1B\x0BV[\x80\x82Ra\x12\xB2\x90\x85\x90\x85\x90a\x1B_V[` \x82\x01R\x80Qa\x12\xC8\x90\x85\x90\x84\x90\x86\x90a\x1B\xC5V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12\xE2\x85\x87\x89a\x1D\x1BV[\x90Pa\x12\xF2\x88\x86\x89\x89\x88\x88a\x1E\x07V[a\x0C\xDC\x81\x87\x86a!\x13V[a\x03\xE9\x82\x82a!cV[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x13/\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a9*V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x13`Wa\x13`a8\x8BV[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x13|Wa\x13|a8\x8BV[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x9B\x94\x93\x92\x91\x90a9*V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x13\xCBWa\x13\xCBa8\x8BV[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13\xECWa\x13\xECa8\x8BV[` \x02\x01\x81\x81RPPa\x02Qa\x14/\x83\x83`@Q` \x01a\x14\x17\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a!\x96V[a\"\xA3V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x99W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14\xD7\x83`\0\x81Q\x81\x10a\x14\xAFWa\x14\xAFa8\x8BV[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x14\xCAWa\x14\xCAa8\x8BV[` \x02` \x01\x01Qa##V[\x90P`\x01[\x82Q\x81\x10\x15a\x151Wa\x15\x1D\x82a\x15\x18\x86\x84\x81Q\x81\x10a\x14\xFEWa\x14\xFEa8\x8BV[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x14\xCAWa\x14\xCAa8\x8BV[a#\xC7V[\x91P\x80a\x15)\x81a8\xB7V[\x91PPa\x14\xDCV[P\x92\x91PPV[`\0a\x15R`\0\x80Q` a9\xCB\x839\x81Q\x91R\x83a9`V[a\x15j\x90`\0\x80Q` a9\xCB\x839\x81Q\x91Ra9\x82V[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x98WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a9\xAB\x839\x81Q\x91R\x84` \x01Qa\x15\xCB\x91\x90a9`V[a\x15\xE3\x90`\0\x80Q` a9\xAB\x839\x81Q\x91Ra9\x82V[\x90R\x92\x91PPV[a\x16\x16`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x17\x92W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\xB2\x91\x90\x83\x90` \x01a9\x95V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x18\t\x84a\x18\x04a\x17\xDA\x84a$nV[`@Q` \x01a\x17\xEC\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x04a!\x96V[a\x17\x9EV[a\x18G\x84a\x18\x04a\x18\x1D\x86`\0\x01Qa$nV[`@Q` \x01a\x18/\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a!\x96V[a\x18[\x84a\x18\x04a\x18\x1D\x86` \x01Qa$nV[a\x18f\x84`\x01a!cV[a\x18\x90\x84\x7F/\x8D\xD1\xF1\xA7X\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\xADWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x11AWP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xD6WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[\x81` \x03a\x12iWP`@\x80Q`\xA0\x81\x01\x82R`\x05\x81R` \x81\x01\x92\x90\x92R\x7F.\xE1+\xFFJ(\x13(j\x8D\xC3\x88\xCDuM\x9A>\xF2I\x065\xEB\xA5\x0C\xB9\xC2\xE5\xE7P\x80\0\x01\x90\x82\x01R\x7F\t\xC52\xC60k\x93\xD2\x96x \rG\xC0\xB2\xA9\x9C\x18\xD5\x1B\x83\x8E\xEB\x1D>\xEDLS;\xB5\x12\xD0``\x82\x01R\x7F'$q6\x03\xBF\xBDy\n\xEA\xF3\xE7\xDF%\xD8\xE7\xEF\x8F1\x134\x90[M\x8C\x99\x98\x0C\xF2\x10\x97\x9D`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\xA6`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\xB0\x84\x84a\x1B\x19V[\x80\x82Ra\x12\xC0\x90\x85\x90\x85\x90a\x1BmV[` \x82\x01R\x80Qa\x12\xD6\x90\x85\x90\x84\x90\x86\x90a\x1B\xD3V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12\xF0\x85\x87\x89a\x1D)V[\x90Pa\x13\0\x88\x86\x89\x89\x88\x88a\x1E\x15V[a\x0C\xEA\x81\x87\x86a!!V[a\x03\xF7\x82\x82a!qV[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x13=\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a98V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x13nWa\x13na8\x99V[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x13\x8AWa\x13\x8Aa8\x99V[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\xA9\x94\x93\x92\x91\x90a98V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x13\xD9Wa\x13\xD9a8\x99V[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13\xFAWa\x13\xFAa8\x99V[` \x02\x01\x81\x81RPPa\x02Qa\x14=\x83\x83`@Q` \x01a\x14%\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a!\xA4V[a\"\xB1V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\xA7W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xEEV[a\x14\xE5\x83`\0\x81Q\x81\x10a\x14\xBDWa\x14\xBDa8\x99V[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x14\xD8Wa\x14\xD8a8\x99V[` \x02` \x01\x01Qa#1V[\x90P`\x01[\x82Q\x81\x10\x15a\x15?Wa\x15+\x82a\x15&\x86\x84\x81Q\x81\x10a\x15\x0CWa\x15\x0Ca8\x99V[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x14\xD8Wa\x14\xD8a8\x99V[a#\xD5V[\x91P\x80a\x157\x81a8\xC5V[\x91PPa\x14\xEAV[P\x92\x91PPV[`\0a\x15``\0\x80Q` a9\xD9\x839\x81Q\x91R\x83a9nV[a\x15x\x90`\0\x80Q` a9\xD9\x839\x81Q\x91Ra9\x90V[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\xA6WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a9\xB9\x839\x81Q\x91R\x84` \x01Qa\x15\xD9\x91\x90a9nV[a\x15\xF1\x90`\0\x80Q` a9\xB9\x839\x81Q\x91Ra9\x90V[\x90R\x92\x91PPV[a\x16$`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x17\xA0W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xEEV[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\xC0\x91\x90\x83\x90` \x01a9\xA3V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x18\x17\x84a\x18\x12a\x17\xE8\x84a$|V[`@Q` \x01a\x17\xFA\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x04a!\xA4V[a\x17\xACV[a\x18U\x84a\x18\x12a\x18+\x86`\0\x01Qa$|V[`@Q` \x01a\x18=\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a!\xA4V[a\x18i\x84a\x18\x12a\x18+\x86` \x01Qa$|V[a\x18t\x84`\x01a!qV[a\x18\x9E\x84\x7F/\x8D\xD1\xF1\xA7XWa'>a1RV[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a'gW\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x93P\x84\x15\x19\x15a\x1BdW` \x84\x01\x85` \x02\x81\x01`\x01\x82R` \x82\x01\x91P[\x80\x82\x10\x15a'\xA3W\x82\x85\x85\t\x93P\x83\x82R` \x82\x01\x91Pa'\x87V[PPPPP\x92\x91PPV[`\0\x80`\0\x80`\0\x80`\0\x80Q` a9\xD9\x839\x81Q\x91R\x90P\x80` \x8B\x01Q` \x8D\x01Q\t\x95P\x8AQ\x93P\x80`\xA0\x8C\x01Q``\x8D\x01Q\t\x92P\x80a\x01\xA0\x8A\x01Q\x84\x08\x91P\x80`\x80\x8C\x01Q\x83\x08\x91P\x80\x84\x83\t\x93P\x80\x7F/\x8D\xD1\xF1\xA7X\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\x9FWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x113WP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xC8WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[\x81` \x03a\x12[WP`@\x80Q`\xA0\x81\x01\x82R`\x05\x81R` \x81\x01\x92\x90\x92R\x7F.\xE1+\xFFJ(\x13(j\x8D\xC3\x88\xCDuM\x9A>\xF2I\x065\xEB\xA5\x0C\xB9\xC2\xE5\xE7P\x80\0\x01\x90\x82\x01R\x7F\t\xC52\xC60k\x93\xD2\x96x \rG\xC0\xB2\xA9\x9C\x18\xD5\x1B\x83\x8E\xEB\x1D>\xEDLS;\xB5\x12\xD0``\x82\x01R\x7F'$q6\x03\xBF\xBDy\n\xEA\xF3\xE7\xDF%\xD8\xE7\xEF\x8F1\x134\x90[M\x8C\x99\x98\x0C\xF2\x10\x97\x9D`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\x98`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\xA2\x84\x84a\x1B\x0BV[\x80\x82Ra\x12\xB2\x90\x85\x90\x85\x90a\x1B_V[` \x82\x01R\x80Qa\x12\xC8\x90\x85\x90\x84\x90\x86\x90a\x1B\xC5V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12\xE2\x85\x87\x89a\x1D\x1BV[\x90Pa\x12\xF2\x88\x86\x89\x89\x88\x88a\x1E\x07V[a\x0C\xDC\x81\x87\x86a!\x13V[a\x03\xE9\x82\x82a!cV[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x13/\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a9*V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x13`Wa\x13`a8\x8BV[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x13|Wa\x13|a8\x8BV[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\x9B\x94\x93\x92\x91\x90a9*V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x13\xCBWa\x13\xCBa8\x8BV[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13\xECWa\x13\xECa8\x8BV[` \x02\x01\x81\x81RPPa\x02Qa\x14/\x83\x83`@Q` \x01a\x14\x17\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a!\x96V[a\"\xA3V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\x99W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xE0V[a\x14\xD7\x83`\0\x81Q\x81\x10a\x14\xAFWa\x14\xAFa8\x8BV[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x14\xCAWa\x14\xCAa8\x8BV[` \x02` \x01\x01Qa##V[\x90P`\x01[\x82Q\x81\x10\x15a\x151Wa\x15\x1D\x82a\x15\x18\x86\x84\x81Q\x81\x10a\x14\xFEWa\x14\xFEa8\x8BV[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x14\xCAWa\x14\xCAa8\x8BV[a#\xC7V[\x91P\x80a\x15)\x81a8\xB7V[\x91PPa\x14\xDCV[P\x92\x91PPV[`\0a\x15R`\0\x80Q` a9\xCB\x839\x81Q\x91R\x83a9`V[a\x15j\x90`\0\x80Q` a9\xCB\x839\x81Q\x91Ra9\x82V[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\x98WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a9\xAB\x839\x81Q\x91R\x84` \x01Qa\x15\xCB\x91\x90a9`V[a\x15\xE3\x90`\0\x80Q` a9\xAB\x839\x81Q\x91Ra9\x82V[\x90R\x92\x91PPV[a\x16\x16`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x17\x92W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xE0V[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\xB2\x91\x90\x83\x90` \x01a9\x95V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x18\t\x84a\x18\x04a\x17\xDA\x84a$nV[`@Q` \x01a\x17\xEC\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x04a!\x96V[a\x17\x9EV[a\x18G\x84a\x18\x04a\x18\x1D\x86`\0\x01Qa$nV[`@Q` \x01a\x18/\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a!\x96V[a\x18[\x84a\x18\x04a\x18\x1D\x86` \x01Qa$nV[a\x18f\x84`\x01a!cV[a\x18\x90\x84\x7F/\x8D\xD1\xF1\xA7X\xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85``\x82\x01R\x7F(\x1C\x03o\x06\xE7\xE9\xE9\x11h\rBU\x8En\x8C\xF4\tv\xB0gwq\xC0\xF8\xEE\xE94d\x1C\x84\x10`\x80\x82\x01R\x90V[\x81a\x80\0\x03a\x10\xADWP`@\x80Q`\xA0\x81\x01\x82R`\x0F\x81R` \x81\x01\x92\x90\x92R\x7F0c\xED\xAADK\xDD\xC6w\xFC\xD5\x15\xF6\x14UZwy\x97\xE0\xA9(}\x1Eb\xBFm\xD0\x04\xD8 \x01\x90\x82\x01R\x7F-\x1B\xA6oYA\xDC\x91\x01qq\xFAi\xEC+\xD0\x02**-A\x15\xA0\t\xA94X\xFDN&\xEC\xFB``\x82\x01R\x7F\x05\xD37f\xE4Y\x0B7\"p\x1Bo/\xA4=\r\xC3\xF0(BM8Nh\xC9*t/\xB2\xDB\xC0\xB4`\x80\x82\x01R\x90V[\x81b\x01\0\0\x03a\x11AWP`@\x80Q`\xA0\x81\x01\x82R`\x10\x81R` \x81\x01\x92\x90\x92R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01\x90\x82\x01R~\xEE\xB2\xCBY\x81\xEDEd\x9A\xBE\xBD\xE0\x81\xDC\xFF\x16\xC8`\x1D\xE44~}\xD1b\x8B\xA2\xDA\xACC\xB7``\x82\x01R\x7F\x0B]V\xB7\x7F\xE7\x04\xE8\xE9#8\xC0\x08/7\xE0\x91\x12d\x14\xC80\xE4\xC6\x92-Z\xC8\x02\xD8B\xD4`\x80\x82\x01R\x90V[\x81b\x02\0\0\x03a\x11\xD6WP`@\x80Q`\xA0\x81\x01\x82R`\x11\x81R` \x81\x01\x92\x90\x92R\x7F0d6@\xB9\xF8/\x90\xE8;i\x8E^\xA6\x17\x9C|\x05T.\x85\x953\xB4\x8B\x99S\xA2\xF56\x08\x01\x90\x82\x01R\x7F\x1B\xF8-\xEB\xA7\xD7I\x02\xC3p\x8C\xC6\xE7\x0Ea\xF3\x05\x12\xEC\xA9VU!\x0E'nXX\xCE\x8FX\xE5``\x82\x01R\x7F$L\xF0\x10\xC4<\xA8r7\xD8\xB0\x0B\xF9\xDDP\xC4\xC0\x1C\x7F\x08k\xD4\xE8\xC9 \xE7RQ\xD9o\r\"`\x80\x82\x01R\x90V[\x81` \x03a\x12iWP`@\x80Q`\xA0\x81\x01\x82R`\x05\x81R` \x81\x01\x92\x90\x92R\x7F.\xE1+\xFFJ(\x13(j\x8D\xC3\x88\xCDuM\x9A>\xF2I\x065\xEB\xA5\x0C\xB9\xC2\xE5\xE7P\x80\0\x01\x90\x82\x01R\x7F\t\xC52\xC60k\x93\xD2\x96x \rG\xC0\xB2\xA9\x9C\x18\xD5\x1B\x83\x8E\xEB\x1D>\xEDLS;\xB5\x12\xD0``\x82\x01R\x7F'$q6\x03\xBF\xBDy\n\xEA\xF3\xE7\xDF%\xD8\xE7\xEF\x8F1\x134\x90[M\x8C\x99\x98\x0C\xF2\x10\x97\x9D`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x01`@Q\x80\x91\x03\x90\xFD[a\x12\xA6`@Q\x80``\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[a\x12\xB0\x84\x84a\x1B\x19V[\x80\x82Ra\x12\xC0\x90\x85\x90\x85\x90a\x1BmV[` \x82\x01R\x80Qa\x12\xD6\x90\x85\x90\x84\x90\x86\x90a\x1B\xD3V[`@\x82\x01R\x93\x92PPPV[`\0\x80a\x12\xF0\x85\x87\x89a\x1D)V[\x90Pa\x13\0\x88\x86\x89\x89\x88\x88a\x1E\x15V[a\x0C\xEA\x81\x87\x86a!!V[a\x03\xF7\x82\x82a!qV[` \x81\x81\x01Q\x80Q\x90\x82\x01Q\x83Q`@Q`\0\x94\x85\x94a\x13=\x94\x90\x93\x90\x92\x90\x91\x86\x91\x01a98V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P`\0\x83` \x01Q`\0`\x02\x81\x10a\x13nWa\x13na8\x99V[` \x02\x01Q\x84` \x01Q`\x01`\x02\x81\x10a\x13\x8AWa\x13\x8Aa8\x99V[` \x02\x01Q\x85`\0\x01Q`\x01`@Q` \x01a\x13\xA9\x94\x93\x92\x91\x90a98V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x81\x84` \x01Q`\0`\x02\x81\x10a\x13\xD9Wa\x13\xD9a8\x99V[` \x02\x01\x81\x81RPP\x80\x84` \x01Q`\x01`\x02\x81\x10a\x13\xFAWa\x13\xFAa8\x99V[` \x02\x01\x81\x81RPPa\x02Qa\x14=\x83\x83`@Q` \x01a\x14%\x92\x91\x90\x91\x82R` \x82\x01R`@\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`0a!\xA4V[a\"\xB1V[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x82Q\x82Q\x14a\x14\xA7W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01\x81\x90R`$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R`d\x01a\x03\xEEV[a\x14\xE5\x83`\0\x81Q\x81\x10a\x14\xBDWa\x14\xBDa8\x99V[` \x02` \x01\x01Q\x83`\0\x81Q\x81\x10a\x14\xD8Wa\x14\xD8a8\x99V[` \x02` \x01\x01Qa#1V[\x90P`\x01[\x82Q\x81\x10\x15a\x15?Wa\x15+\x82a\x15&\x86\x84\x81Q\x81\x10a\x15\x0CWa\x15\x0Ca8\x99V[` \x02` \x01\x01Q\x86\x85\x81Q\x81\x10a\x14\xD8Wa\x14\xD8a8\x99V[a#\xD5V[\x91P\x80a\x157\x81a8\xC5V[\x91PPa\x14\xEAV[P\x92\x91PPV[`\0a\x15``\0\x80Q` a9\xD9\x839\x81Q\x91R\x83a9nV[a\x15x\x90`\0\x80Q` a9\xD9\x839\x81Q\x91Ra9\x90V[\x92\x91PPV[`@\x80Q\x80\x82\x01\x90\x91R`\0\x80\x82R` \x82\x01R\x81Q` \x83\x01Q\x15\x90\x15\x16\x15a\x15\xA6WP\x90V[`@Q\x80`@\x01`@R\x80\x83`\0\x01Q\x81R` \x01`\0\x80Q` a9\xB9\x839\x81Q\x91R\x84` \x01Qa\x15\xD9\x91\x90a9nV[a\x15\xF1\x90`\0\x80Q` a9\xB9\x839\x81Q\x91Ra9\x90V[\x90R\x92\x91PPV[a\x16$`@Q\x80`\x80\x01`@R\x80`\0\x81R` \x01`\0\x81R` \x01`\0\x81R` \x01`\0\x81RP\x90V[`@Q\x80`\x80\x01`@R\x80\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2\x81R` \x01\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R` \x01\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[\x81R` \x01\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA\x81RP\x90P\x90V[`\0\x80`\0`@Q\x87Q\x81R` \x88\x01Q` \x82\x01R\x86Q`@\x82\x01R` \x87\x01Q``\x82\x01R`@\x87\x01Q`\x80\x82\x01R``\x87\x01Q`\xA0\x82\x01R\x85Q`\xC0\x82\x01R` \x86\x01Q`\xE0\x82\x01R\x84Qa\x01\0\x82\x01R` \x85\x01Qa\x01 \x82\x01R`@\x85\x01Qa\x01@\x82\x01R``\x85\x01Qa\x01`\x82\x01R` `\0a\x01\x80\x83`\x08Z\xFA\x91PP`\0Q\x91P\x80a\x17\xA0W`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x01a\x03\xEEV[P\x15\x15\x95\x94PPPPPV[\x81Q`@Qa\x17\xC0\x91\x90\x83\x90` \x01a9\xA3V[`@\x80Q`\x1F\x19\x81\x84\x03\x01\x81R\x91\x90R\x90\x91RPV[`\xFEa\x18\x17\x84a\x18\x12a\x17\xE8\x84a$|V[`@Q` \x01a\x17\xFA\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x04a!\xA4V[a\x17\xACV[a\x18U\x84a\x18\x12a\x18+\x86`\0\x01Qa$|V[`@Q` \x01a\x18=\x91\x81R` \x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`\0`\x08a!\xA4V[a\x18i\x84a\x18\x12a\x18+\x86` \x01Qa$|V[a\x18t\x84`\x01a!qV[a\x18\x9E\x84\x7F/\x8D\xD1\xF1\xA7XWa'>a1RV[`@Q\x90\x80\x82R\x80` \x02` \x01\x82\x01`@R\x80\x15a'gW\x81` \x01` \x82\x02\x806\x837\x01\x90P[P\x93P\x84\x15\x19\x15a\x1BdW` \x84\x01\x85` \x02\x81\x01`\x01\x82R` \x82\x01\x91P[\x80\x82\x10\x15a'\xA3W\x82\x85\x85\t\x93P\x83\x82R` \x82\x01\x91Pa'\x87V[PPPPP\x92\x91PPV[`\0\x80`\0\x80`\0\x80`\0\x80Q` a9\xD9\x839\x81Q\x91R\x90P\x80` \x8B\x01Q` \x8D\x01Q\t\x95P\x8AQ\x93P\x80`\xA0\x8C\x01Q``\x8D\x01Q\t\x92P\x80a\x01\xA0\x8A\x01Q\x84\x08\x91P\x80`\x80\x8C\x01Q\x83\x08\x91P\x80\x84\x83\t\x93P\x80\x7F/\x8D\xD1\xF1\xA7X Date: Fri, 10 Nov 2023 14:49:41 +0800 Subject: [PATCH 17/38] fortify the precondition of genEvalData test --- contracts/test/PolynomialEval.t.sol | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contracts/test/PolynomialEval.t.sol b/contracts/test/PolynomialEval.t.sol index 80b1666fe2..170e545c76 100644 --- a/contracts/test/PolynomialEval.t.sol +++ b/contracts/test/PolynomialEval.t.sol @@ -87,7 +87,6 @@ contract PolynomialEval_evalDataGen_Test is Test { ) external { logSize = bound(logSize, 14, 17); zeta = bound(zeta, 0, BN254.R_MOD - 1); - vm.assume(zeta != 0); // otherwise divisor of lagrange_one_poly would be zero BN254.validateScalarField(zeta); vm.assume(publicInput.length > 0); // Since these user-provided `publicInputs` were checked outside before passing in via @@ -98,6 +97,10 @@ contract PolynomialEval_evalDataGen_Test is Test { } Poly.EvalDomain memory domain = Poly.newEvalDomain(2 ** logSize); + // NOTE: since zeta comes from CRH via `computeChallenges`, we can assume it's hard to + // be specifically preimage attacked, or accidentially collide with these values. + vm.assume(zeta != 1); // otherwise divisor of lagrange_1_poly would be zero + vm.assume(zeta != domain.groupGenInv); // otherwise divisor of lagrange_n_poly would be zero string[] memory cmds = new string[](8); cmds[0] = "cargo"; From af7266c6b8bca80d4be59103cbe40187092c798f Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 10 Nov 2023 15:17:25 +0800 Subject: [PATCH 18/38] fix inf point conversion and alpha_2 comp --- Cargo.lock | 26 +++++++++++++------------- contracts/rust/Cargo.toml | 8 ++++---- contracts/rust/src/bin/diff_test.rs | 27 +++++++++++++++++---------- contracts/test/Transcript.t.sol | 24 ++++++++++++++++++++++++ foundry.toml | 3 +++ 5 files changed, 61 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 73ab46dea6..3bb5f5fb0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3776,9 +3776,9 @@ dependencies = [ "hex", "itertools 0.10.5", "jf-plonk", - "jf-primitives 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", - "jf-relation 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", - "jf-utils 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", + "jf-primitives 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?rev=8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb)", + "jf-relation 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?rev=8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb)", + "jf-utils 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?rev=8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb)", "num-bigint", "num-traits", "sequencer-utils", @@ -4214,7 +4214,7 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jf-plonk" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#ac5b068f506575406d210491e87fb0eb8c8f32d4" +source = "git+https://github.com/EspressoSystems/jellyfish?rev=8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb#8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb" dependencies = [ "ark-ec 0.4.2", "ark-ff 0.4.2", @@ -4228,9 +4228,9 @@ dependencies = [ "espresso-systems-common 0.4.0", "hashbrown 0.13.2", "itertools 0.10.5", - "jf-primitives 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", - "jf-relation 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", - "jf-utils 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", + "jf-primitives 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?rev=8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb)", + "jf-relation 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?rev=8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb)", + "jf-utils 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?rev=8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb)", "merlin", "num-bigint", "rand_chacha 0.3.1", @@ -4243,7 +4243,7 @@ dependencies = [ [[package]] name = "jf-primitives" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#ac5b068f506575406d210491e87fb0eb8c8f32d4" +source = "git+https://github.com/EspressoSystems/jellyfish?rev=8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb#8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb" dependencies = [ "anyhow", "ark-bls12-377", @@ -4269,8 +4269,8 @@ dependencies = [ "espresso-systems-common 0.4.0", "hashbrown 0.13.2", "itertools 0.10.5", - "jf-relation 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", - "jf-utils 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", + "jf-relation 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?rev=8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb)", + "jf-utils 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?rev=8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb)", "merlin", "num-bigint", "num-traits", @@ -4331,7 +4331,7 @@ dependencies = [ [[package]] name = "jf-relation" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#ac5b068f506575406d210491e87fb0eb8c8f32d4" +source = "git+https://github.com/EspressoSystems/jellyfish?rev=8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb#8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb" dependencies = [ "ark-bls12-377", "ark-bls12-381 0.4.0", @@ -4348,7 +4348,7 @@ dependencies = [ "dyn-clone", "hashbrown 0.13.2", "itertools 0.10.5", - "jf-utils 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis)", + "jf-utils 0.4.0-pre.0 (git+https://github.com/EspressoSystems/jellyfish?rev=8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb)", "num-bigint", "rand_chacha 0.3.1", "rayon", @@ -4383,7 +4383,7 @@ dependencies = [ [[package]] name = "jf-utils" version = "0.4.0-pre.0" -source = "git+https://github.com/EspressoSystems/jellyfish?branch=more-test-apis#ac5b068f506575406d210491e87fb0eb8c8f32d4" +source = "git+https://github.com/EspressoSystems/jellyfish?rev=8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb#8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb" dependencies = [ "ark-ec 0.4.2", "ark-ff 0.4.2", diff --git a/contracts/rust/Cargo.toml b/contracts/rust/Cargo.toml index 41ec1e930d..e265b79ce1 100644 --- a/contracts/rust/Cargo.toml +++ b/contracts/rust/Cargo.toml @@ -26,10 +26,10 @@ ethers-providers = "2.0.4" ethers-solc = "2.0.4" hex = "0.4.3" itertools = "0.10.3" -jf-plonk = { git = "https://github.com/EspressoSystems/jellyfish", features = ["test-apis", "test-srs"], branch = "more-test-apis" } -jf-primitives = { git = "https://github.com/EspressoSystems/jellyfish", features = ["std"], branch = "more-test-apis" } -jf-relation = { git = "https://github.com/EspressoSystems/jellyfish", features = ["std"], branch = "more-test-apis" } -jf-utils = { git = "https://github.com/EspressoSystems/jellyfish", branch = "more-test-apis" } +jf-plonk = { git = "https://github.com/EspressoSystems/jellyfish", features = ["test-apis", "test-srs"], rev = "8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb" } +jf-primitives = { git = "https://github.com/EspressoSystems/jellyfish", features = ["std"], rev = "8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb" } +jf-relation = { git = "https://github.com/EspressoSystems/jellyfish", features = ["std"], rev = "8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb" } +jf-utils = { git = "https://github.com/EspressoSystems/jellyfish", rev = "8c66b70c5dae00ceb4d1c32fc3a0ab603d1681cb" } num-bigint = { version = "0.4", default-features = false } num-traits = { version = "0.2", default-features = false } sequencer-utils = { path = "../../utils" } diff --git a/contracts/rust/src/bin/diff_test.rs b/contracts/rust/src/bin/diff_test.rs index af582d3188..e3a3f0438a 100644 --- a/contracts/rust/src/bin/diff_test.rs +++ b/contracts/rust/src/bin/diff_test.rs @@ -1,10 +1,10 @@ use std::str::FromStr; use anyhow::Result; -use ark_bn254::{g1, Bn254, Fq, Fr, G1Affine, G2Affine}; +use ark_bn254::{Bn254, Fq, Fr, G1Affine, G2Affine}; use ark_ec::short_weierstrass::{Affine, SWCurveConfig}; use ark_ec::{AffineRepr, CurveGroup}; -use ark_ff::{BigInteger, Field, Fp2, MontFp, PrimeField}; +use ark_ff::{BigInteger, Fp2, MontFp, PrimeField}; use ark_poly::domain::radix2::Radix2EvaluationDomain; use ark_poly::EvaluationDomain; use ark_std::{ @@ -566,16 +566,19 @@ impl From for SolidityTranscript { } /// an intermediate representation of `BN254.G1Point` in solidity. -#[derive(Clone, Debug, EthAbiType, EthAbiCodec)] +#[derive(Clone, PartialEq, Eq, Debug, EthAbiType, EthAbiCodec)] struct ParsedG1Point { x: U256, y: U256, } +// this is convention from BN256 precompile impl Default for ParsedG1Point { fn default() -> Self { - let point = Affine::::new_unchecked(MontFp!("1"), MontFp!("2")); - point.into() + Self { + x: U256::from(0), + y: U256::from(0), + } } } @@ -612,10 +615,14 @@ where P::BaseField: PrimeField, { fn from(p: ParsedG1Point) -> Self { - Self::new( - u256_to_field::(p.x), - u256_to_field::(p.y), - ) + if p == ParsedG1Point::default() { + Self::default() + } else { + Self::new( + u256_to_field::(p.x), + u256_to_field::(p.y), + ) + } } } @@ -919,7 +926,7 @@ impl FromStr for ParsedChallenges { impl From> for ParsedChallenges { fn from(c: Challenges) -> Self { - let alpha_2 = c.alpha.double(); + let alpha_2 = c.alpha * c.alpha; Self { alpha: field_to_u256::(c.alpha), alpha_2: field_to_u256::(alpha_2), diff --git a/contracts/test/Transcript.t.sol b/contracts/test/Transcript.t.sol index 527d3c7b5f..03fdc09022 100644 --- a/contracts/test/Transcript.t.sol +++ b/contracts/test/Transcript.t.sol @@ -102,6 +102,30 @@ contract Transcript_appendGroupElement_Test is Test { assertEq(updated.state[0], transcript.state[0]); assertEq(updated.state[1], transcript.state[1]); } + + /// forge-config: default.fuzz.runs = 5 + /// @dev Test special case where the identity point (or infinity) is appended. + function test_appendInfinityPoint_succeeds(T.TranscriptData memory transcript) external { + BN254.G1Point memory infinity = BN254.G1Point(0, 0); + assert(BN254.isInfinity(infinity)); + + string[] memory cmds = new string[](7); + cmds[0] = "cargo"; + cmds[1] = "run"; + cmds[2] = "--bin"; + cmds[3] = "diff-test"; + cmds[4] = "transcript-append-group"; + cmds[5] = vm.toString(abi.encode(transcript)); + cmds[6] = vm.toString(abi.encode(infinity)); + + bytes memory result = vm.ffi(cmds); + (T.TranscriptData memory updated) = abi.decode(result, (T.TranscriptData)); + + transcript.appendGroupElement(infinity); + assertEq(updated.transcript, transcript.transcript); + assertEq(updated.state[0], transcript.state[0]); + assertEq(updated.state[1], transcript.state[1]); + } } contract Transcript_getAndAppendChallenge_Test is Test { diff --git a/foundry.toml b/foundry.toml index 80c75555c9..edafc6dd28 100644 --- a/foundry.toml +++ b/foundry.toml @@ -27,3 +27,6 @@ sepolia = { key = "${ETHERSCAN_API_KEY}" } line_length=100 bracket_spacing=true wrap_comments=true + +[profile.ci] +fuzz = { run = 50 } From 79f7c0f5d04812d86fbeb9fab2cab1561c612f66 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 10 Nov 2023 16:02:46 +0800 Subject: [PATCH 19/38] directly use diff-test binary --- Cargo.lock | 1 + contract-bindings/Cargo.toml | 1 + contract-bindings/src/bls_helper.rs | 23 +- contract-bindings/src/bls_sig.rs | 2 + contract-bindings/src/bn254.rs | 19 +- contract-bindings/src/deploy_hot_shot.rs | 17 +- contract-bindings/src/hot_shot.rs | 73 ++- contract-bindings/src/i_plonk_verifier.rs | 16 +- contract-bindings/src/lib.rs | 1 - contract-bindings/src/plonk_verifier.rs | 35 +- contract-bindings/src/polynomial_eval.rs | 15 +- contract-bindings/src/shared_types.rs | 8 + contract-bindings/src/std_invariant.rs | 740 ---------------------- contracts/test/PlonkVerifier.t.sol | 80 +-- contracts/test/PolynomialEval.t.sol | 39 +- contracts/test/Transcript.t.sol | 89 +-- flake.nix | 2 + 17 files changed, 280 insertions(+), 881 deletions(-) delete mode 100644 contract-bindings/src/std_invariant.rs diff --git a/Cargo.lock b/Cargo.lock index 3bb5f5fb0b..b6516d1508 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1708,6 +1708,7 @@ name = "contract-bindings" version = "0.1.0" dependencies = [ "ethers", + "serde", ] [[package]] diff --git a/contract-bindings/Cargo.toml b/contract-bindings/Cargo.toml index 1294487a79..6dd081af3c 100644 --- a/contract-bindings/Cargo.toml +++ b/contract-bindings/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" [dependencies] ethers = { version = "2", default-features = false, features = ["abigen"] } +serde = "1" diff --git a/contract-bindings/src/bls_helper.rs b/contract-bindings/src/bls_helper.rs index 7bb5e55c2d..640492812e 100644 --- a/contract-bindings/src/bls_helper.rs +++ b/contract-bindings/src/bls_helper.rs @@ -254,6 +254,8 @@ pub mod bls_helper { Clone, ::ethers::contract::EthError, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -267,6 +269,8 @@ pub mod bls_helper { Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -282,6 +286,8 @@ pub mod bls_helper { Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -297,6 +303,8 @@ pub mod bls_helper { Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -313,7 +321,16 @@ pub mod bls_helper { pub pk: G2Point, } ///Container type for all of the contract's call - #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] pub enum BLSHelperCalls { HashToCurve(HashToCurveCall), HashToField(HashToFieldCall), @@ -375,6 +392,8 @@ pub mod bls_helper { Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -390,6 +409,8 @@ pub mod bls_helper { Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, diff --git a/contract-bindings/src/bls_sig.rs b/contract-bindings/src/bls_sig.rs index 5021a64efc..9275a2b100 100644 --- a/contract-bindings/src/bls_sig.rs +++ b/contract-bindings/src/bls_sig.rs @@ -127,6 +127,8 @@ pub mod bls_sig { Clone, ::ethers::contract::EthError, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, diff --git a/contract-bindings/src/bn254.rs b/contract-bindings/src/bn254.rs index 0d770d538c..a99816ab49 100644 --- a/contract-bindings/src/bn254.rs +++ b/contract-bindings/src/bn254.rs @@ -170,6 +170,8 @@ pub mod bn254 { Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -183,6 +185,8 @@ pub mod bn254 { Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -192,7 +196,16 @@ pub mod bn254 { #[ethcall(name = "R_MOD", abi = "R_MOD()")] pub struct RModCall; ///Container type for all of the contract's call - #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] pub enum BN254Calls { PMod(PModCall), RMod(RModCall), @@ -242,6 +255,8 @@ pub mod bn254 { Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -254,6 +269,8 @@ pub mod bn254 { Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, diff --git a/contract-bindings/src/deploy_hot_shot.rs b/contract-bindings/src/deploy_hot_shot.rs index a4e395e6ab..ea038ca6f2 100644 --- a/contract-bindings/src/deploy_hot_shot.rs +++ b/contract-bindings/src/deploy_hot_shot.rs @@ -162,6 +162,8 @@ pub mod deploy_hot_shot { Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -175,6 +177,8 @@ pub mod deploy_hot_shot { Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -184,7 +188,16 @@ pub mod deploy_hot_shot { #[ethcall(name = "run", abi = "run()")] pub struct RunCall; ///Container type for all of the contract's call - #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] pub enum DeployHotShotCalls { IsScript(IsScriptCall), Run(RunCall), @@ -234,6 +247,8 @@ pub mod deploy_hot_shot { Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, diff --git a/contract-bindings/src/hot_shot.rs b/contract-bindings/src/hot_shot.rs index d45d1dfd10..38c33abcc6 100644 --- a/contract-bindings/src/hot_shot.rs +++ b/contract-bindings/src/hot_shot.rs @@ -522,6 +522,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthError, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -535,6 +537,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthError, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -554,6 +558,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthError, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -569,6 +575,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthError, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -582,6 +590,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthError, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -595,6 +605,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthError, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -606,7 +618,16 @@ pub mod hot_shot { pub num_blocks: ::ethers::core::types::U256, } ///Container type for all of the contract's custom errors - #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] pub enum HotShotErrors { BLSSigVerificationFailed(BLSSigVerificationFailed), IncorrectBlockNumber(IncorrectBlockNumber), @@ -750,6 +771,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthEvent, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -765,6 +788,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthEvent, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -781,7 +806,16 @@ pub mod hot_shot { pub index: ::ethers::core::types::U256, } ///Container type for all of the contract's events - #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] pub enum HotShotEvents { NewBlocksFilter(NewBlocksFilter), NewStakingKeyFilter(NewStakingKeyFilter), @@ -822,6 +856,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -835,6 +871,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -854,6 +892,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -867,6 +907,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -882,6 +924,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -897,6 +941,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -915,6 +961,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -932,7 +980,16 @@ pub mod hot_shot { pub min_stake_threshold: ::ethers::core::types::U256, } ///Container type for all of the contract's call - #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] pub enum HotShotCalls { MaxBlocks(MaxBlocksCall), AddNewStakingKey(AddNewStakingKeyCall), @@ -1041,6 +1098,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -1053,6 +1112,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -1065,6 +1126,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -1079,6 +1142,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -1091,6 +1156,8 @@ pub mod hot_shot { Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, diff --git a/contract-bindings/src/i_plonk_verifier.rs b/contract-bindings/src/i_plonk_verifier.rs index 60680d648a..9bbab802b6 100644 --- a/contract-bindings/src/i_plonk_verifier.rs +++ b/contract-bindings/src/i_plonk_verifier.rs @@ -297,7 +297,13 @@ pub mod i_plonk_verifier { } } ///Container type for all input parameters for the `batchVerify` function with signature `batchVerify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256))[],uint256[][],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)[],bytes[])` and selector `0x830affd6` - #[derive(Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay)] + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + )] #[ethcall( name = "batchVerify", abi = "batchVerify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256))[],uint256[][],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)[],bytes[])" @@ -309,6 +315,12 @@ pub mod i_plonk_verifier { pub extra_transcript_init_msgs: ::std::vec::Vec<::ethers::core::types::Bytes>, } ///Container type for all return fields from the `batchVerify` function with signature `batchVerify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256))[],uint256[][],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)[],bytes[])` and selector `0x830affd6` - #[derive(Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec)] + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + )] pub struct BatchVerifyReturn(pub bool); } diff --git a/contract-bindings/src/lib.rs b/contract-bindings/src/lib.rs index ac6c59a71e..d06782d5f6 100644 --- a/contract-bindings/src/lib.rs +++ b/contract-bindings/src/lib.rs @@ -14,6 +14,5 @@ pub mod i_plonk_verifier; pub mod plonk_verifier; pub mod polynomial_eval; pub mod shared_types; -pub mod std_invariant; pub mod transcript; pub mod utils; diff --git a/contract-bindings/src/plonk_verifier.rs b/contract-bindings/src/plonk_verifier.rs index 8e8a5e4c3f..37bfc33ebf 100644 --- a/contract-bindings/src/plonk_verifier.rs +++ b/contract-bindings/src/plonk_verifier.rs @@ -379,6 +379,8 @@ pub mod plonk_verifier { Clone, ::ethers::contract::EthError, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -392,6 +394,8 @@ pub mod plonk_verifier { Clone, ::ethers::contract::EthError, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -405,6 +409,8 @@ pub mod plonk_verifier { Clone, ::ethers::contract::EthError, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -418,6 +424,8 @@ pub mod plonk_verifier { Clone, ::ethers::contract::EthError, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -427,7 +435,16 @@ pub mod plonk_verifier { #[etherror(name = "WrongPlonkVK", abi = "WrongPlonkVK()")] pub struct WrongPlonkVK; ///Container type for all of the contract's custom errors - #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] pub enum PlonkVerifierErrors { InvalidPlonkArgs(InvalidPlonkArgs), InvalidPolyEvalArgs(InvalidPolyEvalArgs), @@ -538,7 +555,13 @@ pub mod plonk_verifier { } } ///Container type for all input parameters for the `batchVerify` function with signature `batchVerify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256))[],uint256[][],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)[],bytes[])` and selector `0x830affd6` - #[derive(Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay)] + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + )] #[ethcall( name = "batchVerify", abi = "batchVerify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256))[],uint256[][],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)[],bytes[])" @@ -550,6 +573,12 @@ pub mod plonk_verifier { pub extra_transcript_init_msgs: ::std::vec::Vec<::ethers::core::types::Bytes>, } ///Container type for all return fields from the `batchVerify` function with signature `batchVerify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256))[],uint256[][],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)[],bytes[])` and selector `0x830affd6` - #[derive(Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec)] + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + )] pub struct BatchVerifyReturn(pub bool); } diff --git a/contract-bindings/src/polynomial_eval.rs b/contract-bindings/src/polynomial_eval.rs index 520b1f66ba..fc221f90eb 100644 --- a/contract-bindings/src/polynomial_eval.rs +++ b/contract-bindings/src/polynomial_eval.rs @@ -138,6 +138,8 @@ pub mod polynomial_eval { Clone, ::ethers::contract::EthError, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -151,6 +153,8 @@ pub mod polynomial_eval { Clone, ::ethers::contract::EthError, ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -160,7 +164,16 @@ pub mod polynomial_eval { #[etherror(name = "UnsupportedDegree", abi = "UnsupportedDegree()")] pub struct UnsupportedDegree; ///Container type for all of the contract's custom errors - #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] pub enum PolynomialEvalErrors { InvalidPolyEvalArgs(InvalidPolyEvalArgs), UnsupportedDegree(UnsupportedDegree), diff --git a/contract-bindings/src/shared_types.rs b/contract-bindings/src/shared_types.rs index c59894e9e1..e620e45093 100644 --- a/contract-bindings/src/shared_types.rs +++ b/contract-bindings/src/shared_types.rs @@ -3,6 +3,8 @@ Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -18,6 +20,8 @@ pub struct G1Point { Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -35,6 +39,8 @@ pub struct G2Point { Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, @@ -71,6 +77,8 @@ pub struct PlonkProof { Clone, ::ethers::contract::EthAbiType, ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, Default, Debug, PartialEq, diff --git a/contract-bindings/src/std_invariant.rs b/contract-bindings/src/std_invariant.rs deleted file mode 100644 index 2e1923d51a..0000000000 --- a/contract-bindings/src/std_invariant.rs +++ /dev/null @@ -1,740 +0,0 @@ -pub use std_invariant::*; -/// This module was auto-generated with ethers-rs Abigen. -/// More information at: -#[allow( - clippy::enum_variant_names, - clippy::too_many_arguments, - clippy::upper_case_acronyms, - clippy::type_complexity, - dead_code, - non_camel_case_types -)] -pub mod std_invariant { - #[allow(deprecated)] - fn __abi() -> ::ethers::core::abi::Abi { - ::ethers::core::abi::ethabi::Contract { - constructor: ::core::option::Option::None, - functions: ::core::convert::From::from([ - ( - ::std::borrow::ToOwned::to_owned("excludeArtifacts"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("excludeArtifacts"), - inputs: ::std::vec![], - outputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("excludedArtifacts_",), - kind: ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::String, - ), - ), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("string[]"), - ), - },], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, - },], - ), - ( - ::std::borrow::ToOwned::to_owned("excludeContracts"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("excludeContracts"), - inputs: ::std::vec![], - outputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("excludedContracts_",), - kind: ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::Address, - ), - ), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("address[]"), - ), - },], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, - },], - ), - ( - ::std::borrow::ToOwned::to_owned("excludeSenders"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("excludeSenders"), - inputs: ::std::vec![], - outputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("excludedSenders_"), - kind: ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::Address, - ), - ), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("address[]"), - ), - },], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, - },], - ), - ( - ::std::borrow::ToOwned::to_owned("targetArtifactSelectors"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("targetArtifactSelectors",), - inputs: ::std::vec![], - outputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("targetedArtifactSelectors_",), - kind: ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Address, - ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::FixedBytes( - 4usize - ), - ), - ), - ],), - ), - ), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned( - "struct StdInvariant.FuzzSelector[]", - ), - ), - },], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, - },], - ), - ( - ::std::borrow::ToOwned::to_owned("targetArtifacts"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("targetArtifacts"), - inputs: ::std::vec![], - outputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("targetedArtifacts_",), - kind: ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::String, - ), - ), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("string[]"), - ), - },], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, - },], - ), - ( - ::std::borrow::ToOwned::to_owned("targetContracts"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("targetContracts"), - inputs: ::std::vec![], - outputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("targetedContracts_",), - kind: ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::Address, - ), - ), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("address[]"), - ), - },], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, - },], - ), - ( - ::std::borrow::ToOwned::to_owned("targetSelectors"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("targetSelectors"), - inputs: ::std::vec![], - outputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("targetedSelectors_",), - kind: ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Address, - ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::FixedBytes( - 4usize - ), - ), - ), - ],), - ), - ), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned( - "struct StdInvariant.FuzzSelector[]", - ), - ), - },], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, - },], - ), - ( - ::std::borrow::ToOwned::to_owned("targetSenders"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("targetSenders"), - inputs: ::std::vec![], - outputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("targetedSenders_"), - kind: ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::Address, - ), - ), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("address[]"), - ), - },], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, - },], - ), - ]), - events: ::std::collections::BTreeMap::new(), - errors: ::std::collections::BTreeMap::new(), - receive: false, - fallback: false, - } - } - ///The parsed JSON ABI of the contract. - pub static STDINVARIANT_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = - ::ethers::contract::Lazy::new(__abi); - #[rustfmt::skip] - const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[Pa\x07\xF6\x80a\0 `\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0\x88W`\x005`\xE0\x1C\x80c\x85\"l\x81\x11a\0[W\x80c\x85\"l\x81\x14a\0\xD0W\x80c\x91j\x17\xC6\x14a\0\xE5W\x80c\xB5P\x8A\xA9\x14a\0\xEDW\x80c\xE2\x0C\x9Fq\x14a\0\xF5W`\0\x80\xFD[\x80c\x1E\xD7\x83\x1C\x14a\0\x8DW\x80c>^<#\x14a\0\xABW\x80c?r\x86\xF4\x14a\0\xB3W\x80cf\xD9\xA9\xA0\x14a\0\xBBW[`\0\x80\xFD[a\0\x95a\0\xFDV[`@Qa\0\xA2\x91\x90a\x05\xF4V[`@Q\x80\x91\x03\x90\xF3[a\0\x95a\x01_V[a\0\x95a\x01\xBFV[a\0\xC3a\x02\x1FV[`@Qa\0\xA2\x91\x90a\x06AV[a\0\xD8a\x03\x0EV[`@Qa\0\xA2\x91\x90a\x06\xF4V[a\0\xC3a\x03\xDEV[a\0\xD8a\x04\xC4V[a\0\x95a\x05\x94V[```\x01\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80T\x80\x15a\x01UW` \x02\x82\x01\x91\x90`\0R` `\0 \x90[\x81T`\x01`\x01`\xA0\x1B\x03\x16\x81R`\x01\x90\x91\x01\x90` \x01\x80\x83\x11a\x017W[PPPPP\x90P\x90V[```\x03\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80T\x80\x15a\x01UW` \x02\x82\x01\x91\x90`\0R` `\0 \x90\x81T`\x01`\x01`\xA0\x1B\x03\x16\x81R`\x01\x90\x91\x01\x90` \x01\x80\x83\x11a\x017WPPPPP\x90P\x90V[```\x02\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80T\x80\x15a\x01UW` \x02\x82\x01\x91\x90`\0R` `\0 \x90\x81T`\x01`\x01`\xA0\x1B\x03\x16\x81R`\x01\x90\x91\x01\x90` \x01\x80\x83\x11a\x017WPPPPP\x90P\x90V[```\x06\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01`\0\x90[\x82\x82\x10\x15a\x03\x05W`\0\x84\x81R` \x90\x81\x90 `@\x80Q\x80\x82\x01\x82R`\x02\x86\x02\x90\x92\x01\x80T`\x01`\x01`\xA0\x1B\x03\x16\x83R`\x01\x81\x01\x80T\x83Q\x81\x87\x02\x81\x01\x87\x01\x90\x94R\x80\x84R\x93\x94\x91\x93\x85\x83\x01\x93\x92\x83\x01\x82\x82\x80\x15a\x02\xEDW` \x02\x82\x01\x91\x90`\0R` `\0 \x90`\0\x90[\x82\x82\x90T\x90a\x01\0\n\x90\x04`\xE0\x1B`\x01`\x01`\xE0\x1B\x03\x19\x16\x81R` \x01\x90`\x04\x01\x90` \x82`\x03\x01\x04\x92\x83\x01\x92`\x01\x03\x82\x02\x91P\x80\x84\x11a\x02\xAFW\x90P[PPPPP\x81RPP\x81R` \x01\x90`\x01\x01\x90a\x02CV[PPPP\x90P\x90V[```\x05\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01`\0\x90[\x82\x82\x10\x15a\x03\x05W\x83\x82\x90`\0R` `\0 \x01\x80Ta\x03Q\x90a\x07\x86V[\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80Ta\x03}\x90a\x07\x86V[\x80\x15a\x03\xCAW\x80`\x1F\x10a\x03\x9FWa\x01\0\x80\x83T\x04\x02\x83R\x91` \x01\x91a\x03\xCAV[\x82\x01\x91\x90`\0R` `\0 \x90[\x81T\x81R\x90`\x01\x01\x90` \x01\x80\x83\x11a\x03\xADW\x82\x90\x03`\x1F\x16\x82\x01\x91[PPPPP\x81R` \x01\x90`\x01\x01\x90a\x032V[```\x07\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01`\0\x90[\x82\x82\x10\x15a\x03\x05W`\0\x84\x81R` \x90\x81\x90 `@\x80Q\x80\x82\x01\x82R`\x02\x86\x02\x90\x92\x01\x80T`\x01`\x01`\xA0\x1B\x03\x16\x83R`\x01\x81\x01\x80T\x83Q\x81\x87\x02\x81\x01\x87\x01\x90\x94R\x80\x84R\x93\x94\x91\x93\x85\x83\x01\x93\x92\x83\x01\x82\x82\x80\x15a\x04\xACW` \x02\x82\x01\x91\x90`\0R` `\0 \x90`\0\x90[\x82\x82\x90T\x90a\x01\0\n\x90\x04`\xE0\x1B`\x01`\x01`\xE0\x1B\x03\x19\x16\x81R` \x01\x90`\x04\x01\x90` \x82`\x03\x01\x04\x92\x83\x01\x92`\x01\x03\x82\x02\x91P\x80\x84\x11a\x04nW\x90P[PPPPP\x81RPP\x81R` \x01\x90`\x01\x01\x90a\x04\x02V[```\x04\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01`\0\x90[\x82\x82\x10\x15a\x03\x05W\x83\x82\x90`\0R` `\0 \x01\x80Ta\x05\x07\x90a\x07\x86V[\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80Ta\x053\x90a\x07\x86V[\x80\x15a\x05\x80W\x80`\x1F\x10a\x05UWa\x01\0\x80\x83T\x04\x02\x83R\x91` \x01\x91a\x05\x80V[\x82\x01\x91\x90`\0R` `\0 \x90[\x81T\x81R\x90`\x01\x01\x90` \x01\x80\x83\x11a\x05cW\x82\x90\x03`\x1F\x16\x82\x01\x91[PPPPP\x81R` \x01\x90`\x01\x01\x90a\x04\xE8V[```\0\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80T\x80\x15a\x01UW` \x02\x82\x01\x91\x90`\0R` `\0 \x90\x81T`\x01`\x01`\xA0\x1B\x03\x16\x81R`\x01\x90\x91\x01\x90` \x01\x80\x83\x11a\x017WPPPPP\x90P\x90V[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90\x84\x82\x01\x90`@\x85\x01\x90\x84[\x81\x81\x10\x15a\x065W\x83Q`\x01`\x01`\xA0\x1B\x03\x16\x83R\x92\x84\x01\x92\x91\x84\x01\x91`\x01\x01a\x06\x10V[P\x90\x96\x95PPPPPPV[`\0` \x80\x83\x01\x81\x84R\x80\x85Q\x80\x83R`@\x92P\x82\x86\x01\x91P\x82\x81`\x05\x1B\x87\x01\x01\x84\x88\x01`\0\x80[\x84\x81\x10\x15a\x06\xE5W\x89\x84\x03`?\x19\x01\x86R\x82Q\x80Q`\x01`\x01`\xA0\x1B\x03\x16\x85R\x88\x01Q\x88\x85\x01\x88\x90R\x80Q\x88\x86\x01\x81\x90R\x90\x89\x01\x90\x83\x90``\x87\x01\x90[\x80\x83\x10\x15a\x06\xD0W\x83Q`\x01`\x01`\xE0\x1B\x03\x19\x16\x82R\x92\x8B\x01\x92`\x01\x92\x90\x92\x01\x91\x90\x8B\x01\x90a\x06\xA6V[P\x97\x8A\x01\x97\x95PPP\x91\x87\x01\x91`\x01\x01a\x06iV[P\x91\x99\x98PPPPPPPPPV[`\0` \x80\x83\x01\x81\x84R\x80\x85Q\x80\x83R`@\x86\x01\x91P`@\x81`\x05\x1B\x87\x01\x01\x92P\x83\x87\x01`\0\x80[\x83\x81\x10\x15a\x07xW\x88\x86\x03`?\x19\x01\x85R\x82Q\x80Q\x80\x88R\x83[\x81\x81\x10\x15a\x07QW\x82\x81\x01\x8A\x01Q\x89\x82\x01\x8B\x01R\x89\x01a\x076V[P\x87\x81\x01\x89\x01\x84\x90R`\x1F\x01`\x1F\x19\x16\x90\x96\x01\x87\x01\x95P\x93\x86\x01\x93\x91\x86\x01\x91`\x01\x01a\x07\x1CV[P\x93\x98\x97PPPPPPPPV[`\x01\x81\x81\x1C\x90\x82\x16\x80a\x07\x9AW`\x7F\x82\x16\x91P[` \x82\x10\x81\x03a\x07\xBAWcNH{q`\xE0\x1B`\0R`\"`\x04R`$`\0\xFD[P\x91\x90PV\xFE\xA2dipfsX\"\x12 \xB6\x13\xF9\xAA\xC7g\xE6qU\xE2\xD4\xEA\x0B\xFE\xAA<\x0C*\x01*\x14g\xA4\x1B\xC1\xE0m\xAE\x95^p>dsolcC\0\x08\x14\x003"; - /// The bytecode of the contract. - pub static STDINVARIANT_BYTECODE: ::ethers::core::types::Bytes = - ::ethers::core::types::Bytes::from_static(__BYTECODE); - #[rustfmt::skip] - const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0\x88W`\x005`\xE0\x1C\x80c\x85\"l\x81\x11a\0[W\x80c\x85\"l\x81\x14a\0\xD0W\x80c\x91j\x17\xC6\x14a\0\xE5W\x80c\xB5P\x8A\xA9\x14a\0\xEDW\x80c\xE2\x0C\x9Fq\x14a\0\xF5W`\0\x80\xFD[\x80c\x1E\xD7\x83\x1C\x14a\0\x8DW\x80c>^<#\x14a\0\xABW\x80c?r\x86\xF4\x14a\0\xB3W\x80cf\xD9\xA9\xA0\x14a\0\xBBW[`\0\x80\xFD[a\0\x95a\0\xFDV[`@Qa\0\xA2\x91\x90a\x05\xF4V[`@Q\x80\x91\x03\x90\xF3[a\0\x95a\x01_V[a\0\x95a\x01\xBFV[a\0\xC3a\x02\x1FV[`@Qa\0\xA2\x91\x90a\x06AV[a\0\xD8a\x03\x0EV[`@Qa\0\xA2\x91\x90a\x06\xF4V[a\0\xC3a\x03\xDEV[a\0\xD8a\x04\xC4V[a\0\x95a\x05\x94V[```\x01\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80T\x80\x15a\x01UW` \x02\x82\x01\x91\x90`\0R` `\0 \x90[\x81T`\x01`\x01`\xA0\x1B\x03\x16\x81R`\x01\x90\x91\x01\x90` \x01\x80\x83\x11a\x017W[PPPPP\x90P\x90V[```\x03\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80T\x80\x15a\x01UW` \x02\x82\x01\x91\x90`\0R` `\0 \x90\x81T`\x01`\x01`\xA0\x1B\x03\x16\x81R`\x01\x90\x91\x01\x90` \x01\x80\x83\x11a\x017WPPPPP\x90P\x90V[```\x02\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80T\x80\x15a\x01UW` \x02\x82\x01\x91\x90`\0R` `\0 \x90\x81T`\x01`\x01`\xA0\x1B\x03\x16\x81R`\x01\x90\x91\x01\x90` \x01\x80\x83\x11a\x017WPPPPP\x90P\x90V[```\x06\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01`\0\x90[\x82\x82\x10\x15a\x03\x05W`\0\x84\x81R` \x90\x81\x90 `@\x80Q\x80\x82\x01\x82R`\x02\x86\x02\x90\x92\x01\x80T`\x01`\x01`\xA0\x1B\x03\x16\x83R`\x01\x81\x01\x80T\x83Q\x81\x87\x02\x81\x01\x87\x01\x90\x94R\x80\x84R\x93\x94\x91\x93\x85\x83\x01\x93\x92\x83\x01\x82\x82\x80\x15a\x02\xEDW` \x02\x82\x01\x91\x90`\0R` `\0 \x90`\0\x90[\x82\x82\x90T\x90a\x01\0\n\x90\x04`\xE0\x1B`\x01`\x01`\xE0\x1B\x03\x19\x16\x81R` \x01\x90`\x04\x01\x90` \x82`\x03\x01\x04\x92\x83\x01\x92`\x01\x03\x82\x02\x91P\x80\x84\x11a\x02\xAFW\x90P[PPPPP\x81RPP\x81R` \x01\x90`\x01\x01\x90a\x02CV[PPPP\x90P\x90V[```\x05\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01`\0\x90[\x82\x82\x10\x15a\x03\x05W\x83\x82\x90`\0R` `\0 \x01\x80Ta\x03Q\x90a\x07\x86V[\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80Ta\x03}\x90a\x07\x86V[\x80\x15a\x03\xCAW\x80`\x1F\x10a\x03\x9FWa\x01\0\x80\x83T\x04\x02\x83R\x91` \x01\x91a\x03\xCAV[\x82\x01\x91\x90`\0R` `\0 \x90[\x81T\x81R\x90`\x01\x01\x90` \x01\x80\x83\x11a\x03\xADW\x82\x90\x03`\x1F\x16\x82\x01\x91[PPPPP\x81R` \x01\x90`\x01\x01\x90a\x032V[```\x07\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01`\0\x90[\x82\x82\x10\x15a\x03\x05W`\0\x84\x81R` \x90\x81\x90 `@\x80Q\x80\x82\x01\x82R`\x02\x86\x02\x90\x92\x01\x80T`\x01`\x01`\xA0\x1B\x03\x16\x83R`\x01\x81\x01\x80T\x83Q\x81\x87\x02\x81\x01\x87\x01\x90\x94R\x80\x84R\x93\x94\x91\x93\x85\x83\x01\x93\x92\x83\x01\x82\x82\x80\x15a\x04\xACW` \x02\x82\x01\x91\x90`\0R` `\0 \x90`\0\x90[\x82\x82\x90T\x90a\x01\0\n\x90\x04`\xE0\x1B`\x01`\x01`\xE0\x1B\x03\x19\x16\x81R` \x01\x90`\x04\x01\x90` \x82`\x03\x01\x04\x92\x83\x01\x92`\x01\x03\x82\x02\x91P\x80\x84\x11a\x04nW\x90P[PPPPP\x81RPP\x81R` \x01\x90`\x01\x01\x90a\x04\x02V[```\x04\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01`\0\x90[\x82\x82\x10\x15a\x03\x05W\x83\x82\x90`\0R` `\0 \x01\x80Ta\x05\x07\x90a\x07\x86V[\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80Ta\x053\x90a\x07\x86V[\x80\x15a\x05\x80W\x80`\x1F\x10a\x05UWa\x01\0\x80\x83T\x04\x02\x83R\x91` \x01\x91a\x05\x80V[\x82\x01\x91\x90`\0R` `\0 \x90[\x81T\x81R\x90`\x01\x01\x90` \x01\x80\x83\x11a\x05cW\x82\x90\x03`\x1F\x16\x82\x01\x91[PPPPP\x81R` \x01\x90`\x01\x01\x90a\x04\xE8V[```\0\x80T\x80` \x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80T\x80\x15a\x01UW` \x02\x82\x01\x91\x90`\0R` `\0 \x90\x81T`\x01`\x01`\xA0\x1B\x03\x16\x81R`\x01\x90\x91\x01\x90` \x01\x80\x83\x11a\x017WPPPPP\x90P\x90V[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90\x84\x82\x01\x90`@\x85\x01\x90\x84[\x81\x81\x10\x15a\x065W\x83Q`\x01`\x01`\xA0\x1B\x03\x16\x83R\x92\x84\x01\x92\x91\x84\x01\x91`\x01\x01a\x06\x10V[P\x90\x96\x95PPPPPPV[`\0` \x80\x83\x01\x81\x84R\x80\x85Q\x80\x83R`@\x92P\x82\x86\x01\x91P\x82\x81`\x05\x1B\x87\x01\x01\x84\x88\x01`\0\x80[\x84\x81\x10\x15a\x06\xE5W\x89\x84\x03`?\x19\x01\x86R\x82Q\x80Q`\x01`\x01`\xA0\x1B\x03\x16\x85R\x88\x01Q\x88\x85\x01\x88\x90R\x80Q\x88\x86\x01\x81\x90R\x90\x89\x01\x90\x83\x90``\x87\x01\x90[\x80\x83\x10\x15a\x06\xD0W\x83Q`\x01`\x01`\xE0\x1B\x03\x19\x16\x82R\x92\x8B\x01\x92`\x01\x92\x90\x92\x01\x91\x90\x8B\x01\x90a\x06\xA6V[P\x97\x8A\x01\x97\x95PPP\x91\x87\x01\x91`\x01\x01a\x06iV[P\x91\x99\x98PPPPPPPPPV[`\0` \x80\x83\x01\x81\x84R\x80\x85Q\x80\x83R`@\x86\x01\x91P`@\x81`\x05\x1B\x87\x01\x01\x92P\x83\x87\x01`\0\x80[\x83\x81\x10\x15a\x07xW\x88\x86\x03`?\x19\x01\x85R\x82Q\x80Q\x80\x88R\x83[\x81\x81\x10\x15a\x07QW\x82\x81\x01\x8A\x01Q\x89\x82\x01\x8B\x01R\x89\x01a\x076V[P\x87\x81\x01\x89\x01\x84\x90R`\x1F\x01`\x1F\x19\x16\x90\x96\x01\x87\x01\x95P\x93\x86\x01\x93\x91\x86\x01\x91`\x01\x01a\x07\x1CV[P\x93\x98\x97PPPPPPPPV[`\x01\x81\x81\x1C\x90\x82\x16\x80a\x07\x9AW`\x7F\x82\x16\x91P[` \x82\x10\x81\x03a\x07\xBAWcNH{q`\xE0\x1B`\0R`\"`\x04R`$`\0\xFD[P\x91\x90PV\xFE\xA2dipfsX\"\x12 \xB6\x13\xF9\xAA\xC7g\xE6qU\xE2\xD4\xEA\x0B\xFE\xAA<\x0C*\x01*\x14g\xA4\x1B\xC1\xE0m\xAE\x95^p>dsolcC\0\x08\x14\x003"; - /// The deployed bytecode of the contract. - pub static STDINVARIANT_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = - ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); - pub struct StdInvariant(::ethers::contract::Contract); - impl ::core::clone::Clone for StdInvariant { - fn clone(&self) -> Self { - Self(::core::clone::Clone::clone(&self.0)) - } - } - impl ::core::ops::Deref for StdInvariant { - type Target = ::ethers::contract::Contract; - fn deref(&self) -> &Self::Target { - &self.0 - } - } - impl ::core::ops::DerefMut for StdInvariant { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } - } - impl ::core::fmt::Debug for StdInvariant { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - f.debug_tuple(::core::stringify!(StdInvariant)) - .field(&self.address()) - .finish() - } - } - impl StdInvariant { - /// Creates a new contract instance with the specified `ethers` client at - /// `address`. The contract derefs to a `ethers::Contract` object. - pub fn new>( - address: T, - client: ::std::sync::Arc, - ) -> Self { - Self(::ethers::contract::Contract::new( - address.into(), - STDINVARIANT_ABI.clone(), - client, - )) - } - /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. - /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction - /// - /// Notes: - /// - If there are no constructor arguments, you should pass `()` as the argument. - /// - The default poll duration is 7 seconds. - /// - The default number of confirmations is 1 block. - /// - /// - /// # Example - /// - /// Generate contract bindings with `abigen!` and deploy a new contract instance. - /// - /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. - /// - /// ```ignore - /// # async fn deploy(client: ::std::sync::Arc) { - /// abigen!(Greeter, "../greeter.json"); - /// - /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); - /// let msg = greeter_contract.greet().call().await.unwrap(); - /// # } - /// ``` - pub fn deploy( - client: ::std::sync::Arc, - constructor_args: T, - ) -> ::core::result::Result< - ::ethers::contract::builders::ContractDeployer, - ::ethers::contract::ContractError, - > { - let factory = ::ethers::contract::ContractFactory::new( - STDINVARIANT_ABI.clone(), - STDINVARIANT_BYTECODE.clone().into(), - client, - ); - let deployer = factory.deploy(constructor_args)?; - let deployer = ::ethers::contract::ContractDeployer::new(deployer); - Ok(deployer) - } - ///Calls the contract's `excludeArtifacts` (0xb5508aa9) function - pub fn exclude_artifacts( - &self, - ) -> ::ethers::contract::builders::ContractCall> - { - self.0 - .method_hash([181, 80, 138, 169], ()) - .expect("method not found (this should never happen)") - } - ///Calls the contract's `excludeContracts` (0xe20c9f71) function - pub fn exclude_contracts( - &self, - ) -> ::ethers::contract::builders::ContractCall< - M, - ::std::vec::Vec<::ethers::core::types::Address>, - > { - self.0 - .method_hash([226, 12, 159, 113], ()) - .expect("method not found (this should never happen)") - } - ///Calls the contract's `excludeSenders` (0x1ed7831c) function - pub fn exclude_senders( - &self, - ) -> ::ethers::contract::builders::ContractCall< - M, - ::std::vec::Vec<::ethers::core::types::Address>, - > { - self.0 - .method_hash([30, 215, 131, 28], ()) - .expect("method not found (this should never happen)") - } - ///Calls the contract's `targetArtifactSelectors` (0x66d9a9a0) function - pub fn target_artifact_selectors( - &self, - ) -> ::ethers::contract::builders::ContractCall> { - self.0 - .method_hash([102, 217, 169, 160], ()) - .expect("method not found (this should never happen)") - } - ///Calls the contract's `targetArtifacts` (0x85226c81) function - pub fn target_artifacts( - &self, - ) -> ::ethers::contract::builders::ContractCall> - { - self.0 - .method_hash([133, 34, 108, 129], ()) - .expect("method not found (this should never happen)") - } - ///Calls the contract's `targetContracts` (0x3f7286f4) function - pub fn target_contracts( - &self, - ) -> ::ethers::contract::builders::ContractCall< - M, - ::std::vec::Vec<::ethers::core::types::Address>, - > { - self.0 - .method_hash([63, 114, 134, 244], ()) - .expect("method not found (this should never happen)") - } - ///Calls the contract's `targetSelectors` (0x916a17c6) function - pub fn target_selectors( - &self, - ) -> ::ethers::contract::builders::ContractCall> { - self.0 - .method_hash([145, 106, 23, 198], ()) - .expect("method not found (this should never happen)") - } - ///Calls the contract's `targetSenders` (0x3e5e3c23) function - pub fn target_senders( - &self, - ) -> ::ethers::contract::builders::ContractCall< - M, - ::std::vec::Vec<::ethers::core::types::Address>, - > { - self.0 - .method_hash([62, 94, 60, 35], ()) - .expect("method not found (this should never happen)") - } - } - impl From<::ethers::contract::Contract> for StdInvariant { - fn from(contract: ::ethers::contract::Contract) -> Self { - Self::new(contract.address(), contract.client()) - } - } - ///Container type for all input parameters for the `excludeArtifacts` function with signature `excludeArtifacts()` and selector `0xb5508aa9` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall(name = "excludeArtifacts", abi = "excludeArtifacts()")] - pub struct ExcludeArtifactsCall; - ///Container type for all input parameters for the `excludeContracts` function with signature `excludeContracts()` and selector `0xe20c9f71` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall(name = "excludeContracts", abi = "excludeContracts()")] - pub struct ExcludeContractsCall; - ///Container type for all input parameters for the `excludeSenders` function with signature `excludeSenders()` and selector `0x1ed7831c` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall(name = "excludeSenders", abi = "excludeSenders()")] - pub struct ExcludeSendersCall; - ///Container type for all input parameters for the `targetArtifactSelectors` function with signature `targetArtifactSelectors()` and selector `0x66d9a9a0` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall(name = "targetArtifactSelectors", abi = "targetArtifactSelectors()")] - pub struct TargetArtifactSelectorsCall; - ///Container type for all input parameters for the `targetArtifacts` function with signature `targetArtifacts()` and selector `0x85226c81` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall(name = "targetArtifacts", abi = "targetArtifacts()")] - pub struct TargetArtifactsCall; - ///Container type for all input parameters for the `targetContracts` function with signature `targetContracts()` and selector `0x3f7286f4` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall(name = "targetContracts", abi = "targetContracts()")] - pub struct TargetContractsCall; - ///Container type for all input parameters for the `targetSelectors` function with signature `targetSelectors()` and selector `0x916a17c6` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall(name = "targetSelectors", abi = "targetSelectors()")] - pub struct TargetSelectorsCall; - ///Container type for all input parameters for the `targetSenders` function with signature `targetSenders()` and selector `0x3e5e3c23` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall(name = "targetSenders", abi = "targetSenders()")] - pub struct TargetSendersCall; - ///Container type for all of the contract's call - #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] - pub enum StdInvariantCalls { - ExcludeArtifacts(ExcludeArtifactsCall), - ExcludeContracts(ExcludeContractsCall), - ExcludeSenders(ExcludeSendersCall), - TargetArtifactSelectors(TargetArtifactSelectorsCall), - TargetArtifacts(TargetArtifactsCall), - TargetContracts(TargetContractsCall), - TargetSelectors(TargetSelectorsCall), - TargetSenders(TargetSendersCall), - } - impl ::ethers::core::abi::AbiDecode for StdInvariantCalls { - fn decode( - data: impl AsRef<[u8]>, - ) -> ::core::result::Result { - let data = data.as_ref(); - if let Ok(decoded) = - ::decode(data) - { - return Ok(Self::ExcludeArtifacts(decoded)); - } - if let Ok(decoded) = - ::decode(data) - { - return Ok(Self::ExcludeContracts(decoded)); - } - if let Ok(decoded) = - ::decode(data) - { - return Ok(Self::ExcludeSenders(decoded)); - } - if let Ok(decoded) = - ::decode(data) - { - return Ok(Self::TargetArtifactSelectors(decoded)); - } - if let Ok(decoded) = - ::decode(data) - { - return Ok(Self::TargetArtifacts(decoded)); - } - if let Ok(decoded) = - ::decode(data) - { - return Ok(Self::TargetContracts(decoded)); - } - if let Ok(decoded) = - ::decode(data) - { - return Ok(Self::TargetSelectors(decoded)); - } - if let Ok(decoded) = ::decode(data) - { - return Ok(Self::TargetSenders(decoded)); - } - Err(::ethers::core::abi::Error::InvalidData.into()) - } - } - impl ::ethers::core::abi::AbiEncode for StdInvariantCalls { - fn encode(self) -> Vec { - match self { - Self::ExcludeArtifacts(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::ExcludeContracts(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::ExcludeSenders(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::TargetArtifactSelectors(element) => { - ::ethers::core::abi::AbiEncode::encode(element) - } - Self::TargetArtifacts(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::TargetContracts(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::TargetSelectors(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::TargetSenders(element) => ::ethers::core::abi::AbiEncode::encode(element), - } - } - } - impl ::core::fmt::Display for StdInvariantCalls { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - match self { - Self::ExcludeArtifacts(element) => ::core::fmt::Display::fmt(element, f), - Self::ExcludeContracts(element) => ::core::fmt::Display::fmt(element, f), - Self::ExcludeSenders(element) => ::core::fmt::Display::fmt(element, f), - Self::TargetArtifactSelectors(element) => ::core::fmt::Display::fmt(element, f), - Self::TargetArtifacts(element) => ::core::fmt::Display::fmt(element, f), - Self::TargetContracts(element) => ::core::fmt::Display::fmt(element, f), - Self::TargetSelectors(element) => ::core::fmt::Display::fmt(element, f), - Self::TargetSenders(element) => ::core::fmt::Display::fmt(element, f), - } - } - } - impl ::core::convert::From for StdInvariantCalls { - fn from(value: ExcludeArtifactsCall) -> Self { - Self::ExcludeArtifacts(value) - } - } - impl ::core::convert::From for StdInvariantCalls { - fn from(value: ExcludeContractsCall) -> Self { - Self::ExcludeContracts(value) - } - } - impl ::core::convert::From for StdInvariantCalls { - fn from(value: ExcludeSendersCall) -> Self { - Self::ExcludeSenders(value) - } - } - impl ::core::convert::From for StdInvariantCalls { - fn from(value: TargetArtifactSelectorsCall) -> Self { - Self::TargetArtifactSelectors(value) - } - } - impl ::core::convert::From for StdInvariantCalls { - fn from(value: TargetArtifactsCall) -> Self { - Self::TargetArtifacts(value) - } - } - impl ::core::convert::From for StdInvariantCalls { - fn from(value: TargetContractsCall) -> Self { - Self::TargetContracts(value) - } - } - impl ::core::convert::From for StdInvariantCalls { - fn from(value: TargetSelectorsCall) -> Self { - Self::TargetSelectors(value) - } - } - impl ::core::convert::From for StdInvariantCalls { - fn from(value: TargetSendersCall) -> Self { - Self::TargetSenders(value) - } - } - ///Container type for all return fields from the `excludeArtifacts` function with signature `excludeArtifacts()` and selector `0xb5508aa9` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct ExcludeArtifactsReturn { - pub excluded_artifacts: ::std::vec::Vec<::std::string::String>, - } - ///Container type for all return fields from the `excludeContracts` function with signature `excludeContracts()` and selector `0xe20c9f71` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct ExcludeContractsReturn { - pub excluded_contracts: ::std::vec::Vec<::ethers::core::types::Address>, - } - ///Container type for all return fields from the `excludeSenders` function with signature `excludeSenders()` and selector `0x1ed7831c` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct ExcludeSendersReturn { - pub excluded_senders: ::std::vec::Vec<::ethers::core::types::Address>, - } - ///Container type for all return fields from the `targetArtifactSelectors` function with signature `targetArtifactSelectors()` and selector `0x66d9a9a0` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct TargetArtifactSelectorsReturn { - pub targeted_artifact_selectors: ::std::vec::Vec, - } - ///Container type for all return fields from the `targetArtifacts` function with signature `targetArtifacts()` and selector `0x85226c81` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct TargetArtifactsReturn { - pub targeted_artifacts: ::std::vec::Vec<::std::string::String>, - } - ///Container type for all return fields from the `targetContracts` function with signature `targetContracts()` and selector `0x3f7286f4` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct TargetContractsReturn { - pub targeted_contracts: ::std::vec::Vec<::ethers::core::types::Address>, - } - ///Container type for all return fields from the `targetSelectors` function with signature `targetSelectors()` and selector `0x916a17c6` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct TargetSelectorsReturn { - pub targeted_selectors: ::std::vec::Vec, - } - ///Container type for all return fields from the `targetSenders` function with signature `targetSenders()` and selector `0x3e5e3c23` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct TargetSendersReturn { - pub targeted_senders: ::std::vec::Vec<::ethers::core::types::Address>, - } - ///`FuzzSelector(address,bytes4[])` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct FuzzSelector { - pub addr: ::ethers::core::types::Address, - pub selectors: ::std::vec::Vec<[u8; 4]>, - } -} diff --git a/contracts/test/PlonkVerifier.t.sol b/contracts/test/PlonkVerifier.t.sol index 301f177e28..e110bc2fdb 100644 --- a/contracts/test/PlonkVerifier.t.sol +++ b/contracts/test/PlonkVerifier.t.sol @@ -65,13 +65,10 @@ contract PlonkVerifierCommonTest is Test { /// @dev Generate a random valid (format-wise) proof from a random seed function dummyProof(uint64 seed) public returns (IPlonkVerifier.PlonkProof memory) { - string[] memory cmds = new string[](6); - cmds[0] = "cargo"; - cmds[1] = "run"; - cmds[2] = "--bin"; - cmds[3] = "diff-test"; - cmds[4] = "dummy-proof"; - cmds[5] = vm.toString(seed); + string[] memory cmds = new string[](3); + cmds[0] = "diff-test"; + cmds[1] = "dummy-proof"; + cmds[2] = vm.toString(seed); bytes memory result = vm.ffi(cmds); (IPlonkVerifier.PlonkProof memory proof) = abi.decode(result, (IPlonkVerifier.PlonkProof)); @@ -116,12 +113,9 @@ contract PlonkVerifierCommonTest is Test { contract PlonkVerifier_constants_Test is Test { /// @dev Test constants declared matches that from Jellyfish function test_correctConstants() external { - string[] memory cmds = new string[](7); - cmds[0] = "cargo"; - cmds[1] = "run"; - cmds[2] = "--bin"; - cmds[3] = "diff-test"; - cmds[4] = "plonk-constants"; + string[] memory cmds = new string[](3); + cmds[0] = "diff-test"; + cmds[1] = "plonk-constants"; bytes memory result = vm.ffi(cmds); ( @@ -169,13 +163,10 @@ contract PlonkVerifier_batchVerify_Test is Test { function test_batchVerify_succeeds() external { // TODO: change to i<6 for (uint32 i = 1; i < 2; i++) { - string[] memory cmds = new string[](6); - cmds[0] = "cargo"; - cmds[1] = "run"; - cmds[2] = "--bin"; - cmds[3] = "diff-test"; - cmds[4] = "plonk-batch-verify"; - cmds[5] = vm.toString(i); + string[] memory cmds = new string[](3); + cmds[0] = "diff-test"; + cmds[1] = "plonk-batch-verify"; + cmds[2] = vm.toString(i); bytes memory result = vm.ffi(cmds); ( @@ -288,16 +279,13 @@ contract PlonkVerifier_preparePcsInfo_Test is PlonkVerifierCommonTest { V.PcsInfo memory info = V._preparePcsInfo(vk, publicInput, proof, extraTranscriptInitMsg); - string[] memory cmds = new string[](9); - cmds[0] = "cargo"; - cmds[1] = "run"; - cmds[2] = "--bin"; - cmds[3] = "diff-test"; - cmds[4] = "plonk-prepare-pcs-info"; - cmds[5] = vm.toString(abi.encode(vk)); - cmds[6] = vm.toString(abi.encode(publicInput)); - cmds[7] = vm.toString(abi.encode(proof)); - cmds[8] = vm.toString(abi.encode(extraTranscriptInitMsg)); + string[] memory cmds = new string[](6); + cmds[0] = "diff-test"; + cmds[1] = "plonk-prepare-pcs-info"; + cmds[2] = vm.toString(abi.encode(vk)); + cmds[3] = vm.toString(abi.encode(publicInput)); + cmds[4] = vm.toString(abi.encode(proof)); + cmds[5] = vm.toString(abi.encode(extraTranscriptInitMsg)); bytes memory result = vm.ffi(cmds); ( @@ -336,16 +324,13 @@ contract PlonkVerifier_computeChallenges_Test is PlonkVerifierCommonTest { IPlonkVerifier.PlonkProof memory proof = dummyProof(seed); publicInput = sanitizeScalarFields(publicInput); - string[] memory cmds = new string[](9); - cmds[0] = "cargo"; - cmds[1] = "run"; - cmds[2] = "--bin"; - cmds[3] = "diff-test"; - cmds[4] = "plonk-compute-chal"; - cmds[5] = vm.toString(abi.encode(vk)); - cmds[6] = vm.toString(abi.encode(publicInput)); - cmds[7] = vm.toString(abi.encode(proof)); - cmds[8] = vm.toString(abi.encode(extraTranscriptInitMsg)); + string[] memory cmds = new string[](6); + cmds[0] = "diff-test"; + cmds[1] = "plonk-compute-chal"; + cmds[2] = vm.toString(abi.encode(vk)); + cmds[3] = vm.toString(abi.encode(publicInput)); + cmds[4] = vm.toString(abi.encode(proof)); + cmds[5] = vm.toString(abi.encode(extraTranscriptInitMsg)); bytes memory result = vm.ffi(cmds); (V.Challenges memory chal) = abi.decode(result, (V.Challenges)); @@ -375,15 +360,12 @@ contract PlonkVerifier_prepareEvaluations_Test is PlonkVerifierCommonTest { linPolyConstant = sanitizeScalarField(linPolyConstant); uint256[] memory commScalars = sanitizeScalarFields(copyCommScalars(scalars)); - string[] memory cmds = new string[](8); - cmds[0] = "cargo"; - cmds[1] = "run"; - cmds[2] = "--bin"; - cmds[3] = "diff-test"; - cmds[4] = "plonk-prepare-eval"; - cmds[5] = vm.toString(abi.encode(proof)); - cmds[6] = vm.toString(bytes32(linPolyConstant)); - cmds[7] = vm.toString(abi.encode(commScalars)); + string[] memory cmds = new string[](5); + cmds[0] = "diff-test"; + cmds[1] = "plonk-prepare-eval"; + cmds[2] = vm.toString(abi.encode(proof)); + cmds[3] = vm.toString(bytes32(linPolyConstant)); + cmds[4] = vm.toString(abi.encode(commScalars)); bytes memory result = vm.ffi(cmds); (uint256 eval) = abi.decode(result, (uint256)); diff --git a/contracts/test/PolynomialEval.t.sol b/contracts/test/PolynomialEval.t.sol index 170e545c76..07ab68aea3 100644 --- a/contracts/test/PolynomialEval.t.sol +++ b/contracts/test/PolynomialEval.t.sol @@ -16,13 +16,10 @@ contract PolynomialEval_newEvalDomain_Test is Test { function test_supportedDomainSize_matches() external { uint256[5] memory logSizes = [uint256(5), 14, 15, 16, 17]; for (uint256 i = 0; i < 5; i++) { - string[] memory cmds = new string[](6); - cmds[0] = "cargo"; - cmds[1] = "run"; - cmds[2] = "--bin"; - cmds[3] = "diff-test"; - cmds[4] = "new-poly-eval-domain"; - cmds[5] = vm.toString(logSizes[i]); + string[] memory cmds = new string[](3); + cmds[0] = "diff-test"; + cmds[1] = "new-poly-eval-domain"; + cmds[2] = vm.toString(logSizes[i]); bytes memory result = vm.ffi(cmds); (uint256 sizeInv, uint256 groupGen, uint256 groupGenInv) = @@ -59,14 +56,11 @@ contract PolynomialEval_domainElements_Test is Test { vm.expectRevert(Poly.InvalidPolyEvalArgs.selector); Poly.domainElements(domain, length); } else { - string[] memory cmds = new string[](7); - cmds[0] = "cargo"; - cmds[1] = "run"; - cmds[2] = "--bin"; - cmds[3] = "diff-test"; - cmds[4] = "eval-domain-elements"; - cmds[5] = vm.toString(logSize); - cmds[6] = vm.toString(length); + string[] memory cmds = new string[](4); + cmds[0] = "diff-test"; + cmds[1] = "eval-domain-elements"; + cmds[2] = vm.toString(logSize); + cmds[3] = vm.toString(length); bytes memory result = vm.ffi(cmds); (uint256[] memory elems) = abi.decode(result, (uint256[])); @@ -102,15 +96,12 @@ contract PolynomialEval_evalDataGen_Test is Test { vm.assume(zeta != 1); // otherwise divisor of lagrange_1_poly would be zero vm.assume(zeta != domain.groupGenInv); // otherwise divisor of lagrange_n_poly would be zero - string[] memory cmds = new string[](8); - cmds[0] = "cargo"; - cmds[1] = "run"; - cmds[2] = "--bin"; - cmds[3] = "diff-test"; - cmds[4] = "eval-data-gen"; - cmds[5] = vm.toString(logSize); - cmds[6] = vm.toString(bytes32(zeta)); - cmds[7] = vm.toString(abi.encode(publicInput)); + string[] memory cmds = new string[](5); + cmds[0] = "diff-test"; + cmds[1] = "eval-data-gen"; + cmds[2] = vm.toString(logSize); + cmds[3] = vm.toString(bytes32(zeta)); + cmds[4] = vm.toString(abi.encode(publicInput)); bytes memory result = vm.ffi(cmds); (uint256 vanishEval, uint256 lagrangeOne, uint256 piEval) = diff --git a/contracts/test/Transcript.t.sol b/contracts/test/Transcript.t.sol index 03fdc09022..3bf4f12d66 100644 --- a/contracts/test/Transcript.t.sol +++ b/contracts/test/Transcript.t.sol @@ -22,14 +22,11 @@ contract Transcript_appendMessage_Test is Test { T.TranscriptData memory transcript, bytes memory message ) external { - string[] memory cmds = new string[](7); - cmds[0] = "cargo"; - cmds[1] = "run"; - cmds[2] = "--bin"; - cmds[3] = "diff-test"; - cmds[4] = "transcript-append-msg"; - cmds[5] = vm.toString(abi.encode(transcript)); - cmds[6] = vm.toString(abi.encode(message)); + string[] memory cmds = new string[](4); + cmds[0] = "diff-test"; + cmds[1] = "transcript-append-msg"; + cmds[2] = vm.toString(abi.encode(transcript)); + cmds[3] = vm.toString(abi.encode(message)); bytes memory result = vm.ffi(cmds); (T.TranscriptData memory updated) = abi.decode(result, (T.TranscriptData)); @@ -53,14 +50,11 @@ contract Transcript_appendFieldElement_Test is Test { fieldElement = bound(fieldElement, 0, BN254.R_MOD - 1); BN254.validateScalarField(fieldElement); - string[] memory cmds = new string[](7); - cmds[0] = "cargo"; - cmds[1] = "run"; - cmds[2] = "--bin"; - cmds[3] = "diff-test"; - cmds[4] = "transcript-append-field"; - cmds[5] = vm.toString(abi.encode(transcript)); - cmds[6] = vm.toString(bytes32(fieldElement)); + string[] memory cmds = new string[](4); + cmds[0] = "diff-test"; + cmds[1] = "transcript-append-field"; + cmds[2] = vm.toString(abi.encode(transcript)); + cmds[3] = vm.toString(bytes32(fieldElement)); bytes memory result = vm.ffi(cmds); (T.TranscriptData memory updated) = abi.decode(result, (T.TranscriptData)); @@ -85,14 +79,11 @@ contract Transcript_appendGroupElement_Test is Test { BN254.validateScalarField(randScalar); BN254.G1Point memory randPoint = BN254.scalarMul(BN254.P1(), randScalar); - string[] memory cmds = new string[](7); - cmds[0] = "cargo"; - cmds[1] = "run"; - cmds[2] = "--bin"; - cmds[3] = "diff-test"; - cmds[4] = "transcript-append-group"; - cmds[5] = vm.toString(abi.encode(transcript)); - cmds[6] = vm.toString(abi.encode(randPoint)); + string[] memory cmds = new string[](4); + cmds[0] = "diff-test"; + cmds[1] = "transcript-append-group"; + cmds[2] = vm.toString(abi.encode(transcript)); + cmds[3] = vm.toString(abi.encode(randPoint)); bytes memory result = vm.ffi(cmds); (T.TranscriptData memory updated) = abi.decode(result, (T.TranscriptData)); @@ -109,14 +100,11 @@ contract Transcript_appendGroupElement_Test is Test { BN254.G1Point memory infinity = BN254.G1Point(0, 0); assert(BN254.isInfinity(infinity)); - string[] memory cmds = new string[](7); - cmds[0] = "cargo"; - cmds[1] = "run"; - cmds[2] = "--bin"; - cmds[3] = "diff-test"; - cmds[4] = "transcript-append-group"; - cmds[5] = vm.toString(abi.encode(transcript)); - cmds[6] = vm.toString(abi.encode(infinity)); + string[] memory cmds = new string[](4); + cmds[0] = "diff-test"; + cmds[1] = "transcript-append-group"; + cmds[2] = vm.toString(abi.encode(transcript)); + cmds[3] = vm.toString(abi.encode(infinity)); bytes memory result = vm.ffi(cmds); (T.TranscriptData memory updated) = abi.decode(result, (T.TranscriptData)); @@ -134,13 +122,10 @@ contract Transcript_getAndAppendChallenge_Test is Test { /// forge-config: default.fuzz.runs = 10 /// @dev Test if `getAndAppendChallenge` matches that of Jellyfish function testFuzz_getAndAppendChallenge_matches(T.TranscriptData memory transcript) external { - string[] memory cmds = new string[](6); - cmds[0] = "cargo"; - cmds[1] = "run"; - cmds[2] = "--bin"; - cmds[3] = "diff-test"; - cmds[4] = "transcript-get-chal"; - cmds[5] = vm.toString(abi.encode(transcript)); + string[] memory cmds = new string[](3); + cmds[0] = "diff-test"; + cmds[1] = "transcript-get-chal"; + cmds[2] = vm.toString(abi.encode(transcript)); bytes memory result = vm.ffi(cmds); (T.TranscriptData memory updated, uint256 chal) = @@ -170,15 +155,12 @@ contract Transcript_appendVkAndPubInput_Test is Test { } IPlonkVerifier.VerifyingKey memory vk = VkTest.getVk(); - string[] memory cmds = new string[](8); - cmds[0] = "cargo"; - cmds[1] = "run"; - cmds[2] = "--bin"; - cmds[3] = "diff-test"; - cmds[4] = "transcript-append-vk-and-pi"; - cmds[5] = vm.toString(abi.encode(transcript)); - cmds[6] = vm.toString(abi.encode(vk)); - cmds[7] = vm.toString(abi.encode(publicInput)); + string[] memory cmds = new string[](5); + cmds[0] = "diff-test"; + cmds[1] = "transcript-append-vk-and-pi"; + cmds[2] = vm.toString(abi.encode(transcript)); + cmds[3] = vm.toString(abi.encode(vk)); + cmds[4] = vm.toString(abi.encode(publicInput)); bytes memory result = vm.ffi(cmds); (T.TranscriptData memory updated) = abi.decode(result, (T.TranscriptData)); @@ -197,13 +179,10 @@ contract Transcript_appendProofEvaluations_Test is Test { /// forge-config: default.fuzz.runs = 5 /// @dev Test if `appendProofEvaluations` matches that of Jellyfish function testFuzz_appendProofEvaluations_matches(T.TranscriptData memory transcript) external { - string[] memory cmds = new string[](6); - cmds[0] = "cargo"; - cmds[1] = "run"; - cmds[2] = "--bin"; - cmds[3] = "diff-test"; - cmds[4] = "transcript-append-proof-evals"; - cmds[5] = vm.toString(abi.encode(transcript)); + string[] memory cmds = new string[](3); + cmds[0] = "diff-test"; + cmds[1] = "transcript-append-proof-evals"; + cmds[2] = vm.toString(abi.encode(transcript)); bytes memory result = vm.ffi(cmds); (T.TranscriptData memory updated, IPlonkVerifier.PlonkProof memory proof) = diff --git a/flake.nix b/flake.nix index 29d4c53484..667ff915b0 100644 --- a/flake.nix +++ b/flake.nix @@ -197,6 +197,8 @@ # Prevent cargo aliases from using programs in `~/.cargo` to avoid conflicts # with rustup installations. export CARGO_HOME=$HOME/.cargo-nix + export PATH="./target/release:$PATH" + cargo build --bin diff-test --release '' + self.checks.${system}.pre-commit-check.shellHook; RUST_SRC_PATH = "${stableToolchain}/lib/rustlib/src/rust/library"; FOUNDRY_SOLC = "${solc}/bin/solc"; From c226f877851e694033978d4daf625a4b47c476b4 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 10 Nov 2023 16:13:16 +0800 Subject: [PATCH 20/38] remove done TODO --- contracts/rust/src/bin/diff_test.rs | 1 - contracts/test/PlonkVerifier.t.sol | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/contracts/rust/src/bin/diff_test.rs b/contracts/rust/src/bin/diff_test.rs index e3a3f0438a..bdfa488518 100644 --- a/contracts/rust/src/bin/diff_test.rs +++ b/contracts/rust/src/bin/diff_test.rs @@ -402,7 +402,6 @@ fn main() { // constant in hex string copied from hardcoded constants from solidity contracts -// TODO: (alex) further test these with output from Jellyfish directly! // TODO: (alex) change to simply using `MontFp!("0x..")` after // is on a tag release // Return cosets coefficients for circuits over BN254. diff --git a/contracts/test/PlonkVerifier.t.sol b/contracts/test/PlonkVerifier.t.sol index e110bc2fdb..454f1453cb 100644 --- a/contracts/test/PlonkVerifier.t.sol +++ b/contracts/test/PlonkVerifier.t.sol @@ -161,8 +161,7 @@ contract PlonkVerifier_batchVerify_Test is Test { /// @dev Test happy and unhappy path of `batchVerify`. function test_batchVerify_succeeds() external { - // TODO: change to i<6 - for (uint32 i = 1; i < 2; i++) { + for (uint32 i = 1; i < 6; i++) { string[] memory cmds = new string[](3); cmds[0] = "diff-test"; cmds[1] = "plonk-batch-verify"; From 9775bd118bad05023b1688b55cf26b6aeeacf987 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 10 Nov 2023 16:39:07 +0800 Subject: [PATCH 21/38] avoid burden shellHook to build diff-test, use just command instead --- flake.nix | 1 - justfile | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index a13223f8f2..6a7edddae7 100644 --- a/flake.nix +++ b/flake.nix @@ -199,7 +199,6 @@ # with rustup installations. export CARGO_HOME=$HOME/.cargo-nix export PATH="./target/release:$PATH" - cargo build --bin diff-test --release '' + self.checks.${system}.pre-commit-check.shellHook; RUST_SRC_PATH = "${stableToolchain}/lib/rustlib/src/rust/library"; FOUNDRY_SOLC = "${solc}/bin/solc"; diff --git a/justfile b/justfile index ffb29813a7..c7716a91e4 100644 --- a/justfile +++ b/justfile @@ -61,3 +61,8 @@ gen-bindings: sol-lint: forge fmt solhint --fix 'contracts/{script,src,test}/**/*.sol' + +# Build diff-test binary and forge test +sol-test: + cargo build --bin diff-test --release + forge test From 1ba425af98383c6f1c69464e519ca5fe9237106e Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 10 Nov 2023 18:58:48 +0800 Subject: [PATCH 22/38] ci: fix ci error --- .github/workflows/contracts.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/contracts.yml b/.github/workflows/contracts.yml index 49e122780d..d89e016784 100644 --- a/.github/workflows/contracts.yml +++ b/.github/workflows/contracts.yml @@ -70,4 +70,6 @@ jobs: git diff - name: Run tests - run: nix develop --accept-flake-config -c forge test -vvv + run: | + nix develop --accept-flake-config -c cargo build --bin diff-test --release + nix develop --accept-flake-config -c forge test -vvv From 343b953c60959404cad2845048fa16e64af20d26 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 10 Nov 2023 22:43:06 +0800 Subject: [PATCH 23/38] address comments --- contracts/rust/src/bin/diff_test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/rust/src/bin/diff_test.rs b/contracts/rust/src/bin/diff_test.rs index bdfa488518..889e975081 100644 --- a/contracts/rust/src/bin/diff_test.rs +++ b/contracts/rust/src/bin/diff_test.rs @@ -301,7 +301,7 @@ fn main() { let arg4 = cli .arg4 .as_ref() - .expect("Should provide arg3=extraTranscriptInitMsg"); + .expect("Should provide arg4=extraTranscriptInitMsg"); let vk: VerifyingKey = arg1.parse::().unwrap().into(); let pi_u256: Vec = AbiDecode::decode_hex(arg2).unwrap(); From bdf18acddacaf8702c3c403bfb9346f1cd1c9056 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Mon, 13 Nov 2023 12:36:59 +0800 Subject: [PATCH 24/38] fix bad path test for batchVerify --- contracts/test/PlonkVerifier.t.sol | 104 ++++++++++++++++++++++------- 1 file changed, 79 insertions(+), 25 deletions(-) diff --git a/contracts/test/PlonkVerifier.t.sol b/contracts/test/PlonkVerifier.t.sol index 454f1453cb..591e761b30 100644 --- a/contracts/test/PlonkVerifier.t.sol +++ b/contracts/test/PlonkVerifier.t.sol @@ -142,7 +142,7 @@ contract PlonkVerifier_constants_Test is Test { } } -contract PlonkVerifier_batchVerify_Test is Test { +contract PlonkVerifier_batchVerify_Test is PlonkVerifierCommonTest { /// forge-config: default.fuzz.runs = 30 /// @dev Test if some of the user inputs are invalid function testFuzz_revertWhenInvalidArgs( @@ -178,33 +178,87 @@ contract PlonkVerifier_batchVerify_Test is Test { (IPlonkVerifier.VerifyingKey[], uint256[][], IPlonkVerifier.PlonkProof[], bytes[]) ); - // happy path assert(V.batchVerify(verifyingKeys, publicInputs, proofs, extraTranscriptInitMsgs)); - - // unhappy path - // wrong vk - IPlonkVerifier.VerifyingKey[] memory badVks = verifyingKeys; - badVks[0].q1 = BN254.negate(verifyingKeys[0].q1); - badVks[0].qEcc = BN254.negate(verifyingKeys[0].qEcc); - assert(!V.batchVerify(badVks, publicInputs, proofs, extraTranscriptInitMsgs)); - - // wrong public inputs - uint256[][] memory badPis = publicInputs; - badPis[0][0] = 0x1234; - assert(!V.batchVerify(verifyingKeys, badPis, proofs, extraTranscriptInitMsgs)); - - // wrong proofs - IPlonkVerifier.PlonkProof[] memory badProofs = proofs; - badProofs[0].wireEval0 = 0x12; - badProofs[0].sigmaEval0 = 0x34; - assert(!V.batchVerify(verifyingKeys, publicInputs, badProofs, extraTranscriptInitMsgs)); - - // wrong extraMsgs - bytes[] memory badMsgs = extraTranscriptInitMsgs; - badMsgs[0] = bytes("hi"); - assert(!V.batchVerify(verifyingKeys, publicInputs, proofs, badMsgs)); } } + + /// forge-config: default.fuzz.runs = 30 + /// @dev Test when bad public inputs are supplied, the verification should fail + /// We know our `gen_circuit_for_test` in `diff_test.rs` has only 3 public inputs + function testFuzz_badPublicInputs_fails(uint256[3] calldata randPublicInput) external { + uint256[] memory badPublicInput = new uint256[](3); + badPublicInput[0] = randPublicInput[0]; + badPublicInput[1] = randPublicInput[1]; + badPublicInput[2] = randPublicInput[2]; + badPublicInput = sanitizeScalarFields(badPublicInput); + + string[] memory cmds = new string[](3); + cmds[0] = "diff-test"; + cmds[1] = "plonk-batch-verify"; + cmds[2] = vm.toString(uint32(1)); + + bytes memory result = vm.ffi(cmds); + ( + IPlonkVerifier.VerifyingKey[] memory verifyingKeys, + uint256[][] memory publicInputs, + IPlonkVerifier.PlonkProof[] memory proofs, + bytes[] memory extraTranscriptInitMsgs + ) = abi.decode( + result, + (IPlonkVerifier.VerifyingKey[], uint256[][], IPlonkVerifier.PlonkProof[], bytes[]) + ); + + publicInputs[0] = badPublicInput; + assert(!V.batchVerify(verifyingKeys, publicInputs, proofs, extraTranscriptInitMsgs)); + } + + /// forge-config: default.fuzz.runs = 30 + /// @dev Test when bad proofs are supplied, the verification should fail + function testFuzz_badProofs_fails(uint64 seed) external { + IPlonkVerifier.PlonkProof memory badProof = dummyProof(seed); + + string[] memory cmds = new string[](3); + cmds[0] = "diff-test"; + cmds[1] = "plonk-batch-verify"; + cmds[2] = vm.toString(uint32(1)); + + bytes memory result = vm.ffi(cmds); + ( + IPlonkVerifier.VerifyingKey[] memory verifyingKeys, + uint256[][] memory publicInputs, + IPlonkVerifier.PlonkProof[] memory proofs, + bytes[] memory extraTranscriptInitMsgs + ) = abi.decode( + result, + (IPlonkVerifier.VerifyingKey[], uint256[][], IPlonkVerifier.PlonkProof[], bytes[]) + ); + + proofs[0] = badProof; + assert(!V.batchVerify(verifyingKeys, publicInputs, proofs, extraTranscriptInitMsgs)); + } + + /// forge-config: default.fuzz.runs = 30 + /// @dev Test when bad extraTranscriptInitMsgs are supplied, the verification should fail + function testFuzz_badExtraTranscriptInitMsgs_fails(bytes calldata badMsg) external { + string[] memory cmds = new string[](3); + cmds[0] = "diff-test"; + cmds[1] = "plonk-batch-verify"; + cmds[2] = vm.toString(uint32(1)); + + bytes memory result = vm.ffi(cmds); + ( + IPlonkVerifier.VerifyingKey[] memory verifyingKeys, + uint256[][] memory publicInputs, + IPlonkVerifier.PlonkProof[] memory proofs, + bytes[] memory extraTranscriptInitMsgs + ) = abi.decode( + result, + (IPlonkVerifier.VerifyingKey[], uint256[][], IPlonkVerifier.PlonkProof[], bytes[]) + ); + + extraTranscriptInitMsgs[0] = badMsg; + assert(!V.batchVerify(verifyingKeys, publicInputs, proofs, extraTranscriptInitMsgs)); + } } contract PlonkVerifier_validateProof_Test is PlonkVerifierCommonTest { From 103969016549e36f5ac5a8dadf1e6bad91efe5f7 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Sat, 11 Nov 2023 14:32:27 +0800 Subject: [PATCH 25/38] add stake table interfaces --- contracts/src/interfaces/IStakeTable.sol | 127 +++++++++++++++++++++++ contracts/src/libraries/EdOnBn254.sol | 39 +++++++ 2 files changed, 166 insertions(+) create mode 100644 contracts/src/interfaces/IStakeTable.sol create mode 100644 contracts/src/libraries/EdOnBn254.sol diff --git a/contracts/src/interfaces/IStakeTable.sol b/contracts/src/interfaces/IStakeTable.sol new file mode 100644 index 0000000000..85c7ca3a6f --- /dev/null +++ b/contracts/src/interfaces/IStakeTable.sol @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: Unlicensed + +pragma solidity ^0.8.0; + +import { BN254 } from "bn254/BN254.sol"; +import { EdOnBN254 } from "../libraries/EdOnBn254.sol"; + +/// @title Interface for stake table that keep track of validators' external key and staked amount. +/// @dev Stake delegation happens in a separate DelegationPool contract, and specific to +/// instantiation thus not part of this interface +interface IStakeTable { + /// @notice Supported stake type, either using native token or re-staked using ETH + enum StakeType { + Native, + Restake + } + + /// @dev (sadly, Solidity doesn't support type alias on non-primitive types) + // We avoid declaring another struct even if the type info helps with readability, + // extra layer of struct introduces overhead and more gas cost. + // + /// @dev BLS verification key (used for Consensus voting in HotShot) is `BN254.G1Point`. + // `type BlsVerKey is BN254.G1Point;` + // + /// @dev Verification key of a Schnorr signature is just a `EdOnBN254.EdOnBN254Point` + // `type SchnorrVerKey is EdOnBN254.EdOnBN254Point;` + + /// @notice Represents a HotShot validator node + /// In the dual-staking model, a HotShot validator could have multiple `Node` entries. + /// @param account The Ethereum account of the validator. + /// @param stakeType The type of token staked. + /// @param balance The amount of token staked. + /// @param registerEpoch The starting epoch for the validator. + /// @param exitEpoch The ending epoch for the validator. + struct Node { + address account; + StakeType stakeType; + uint64 balance; + uint64 registerEpoch; + uint64 exitEpoch; + } + + // === Table State & Stats === + + /// @notice Get the commitment of the stake table used in current voting (i.e. snapshot at + /// the start of last epoch) + function votingStakeTableCommitment() external view returns (bytes32); + /// @notice Get the commitment of the stake table frozen for change (i.g. snapshot at the start + /// of the current epoch) + function frozenStakeTableCommitment() external view returns (bytes32); + + /// @notice Get the total stake of the registered keys in the latest stake table (Head) + function totalStake() external view returns (uint256); + /// @notice Get the total number of stakers, uniquely identified by their `blsVK` + function totalKeys() external view returns (uint32); + /// @notice Get the total stake of the registered keys in the voting stake table + /// (LastEpochStart) + function totalVotingStake() external view returns (uint256); + + /// @notice Look up the balance of `blsVK` + function lookup(BN254.G1Point calldata blsVK) external view returns (uint64); + /// @notice Look up the full `Node` state associated with `blsVK` + function fullLookup(BN254.G1Point calldata blsVK) external view returns (Node memory); + + // === Queuing Stats === + + /// @notice Get the next available epoch for new registration + function nextRegisterationEpoch() external view returns (uint64); + /// @notice Get the number of pending registration requests in the waiting queue + function numPendingRegistrations() external view returns (uint64); + /// @notice Get the next available epoch for exit + function nextExitEpoch() external view returns (uint64); + /// @notice Get the number of pending exit requests in the waiting queue + function numPendingExit() external view returns (uint64); + + // === Write APIs === + + /// @notice Register a validator in the stake table, transfer of tokens incurred! + /// + /// @param blsVK The BLS verification key + /// @param schnorrVK The Schnorr verification key (as the auxiliary info) + /// @param amount The amount to register + /// @param stakeType The type of staking (native or restaking) + /// @param blsSig The BLS signature that authenticates the `blsVK` field + /// @param maxWait The maximum epoch the sender is waiting to wait to be included (cannot be + /// smaller than the current epoch) + /// + /// @return success status + /// + /// @dev No validity check on `schnorrVK`, as it's assumed to be sender's responsibility, + /// the contract only treat it as auxiliary info submitted by `blsVK`. + function register( + BN254.G1Point calldata blsVK, + EdOnBN254.EdOnBN254Point calldata schnorrVK, + uint64 amount, + StakeType stakeType, + bytes calldata blsSig, + uint64 maxWait + ) external returns (bool); + + /// @notice Deposit more stakes to registered keys + /// + /// @param blsVK The BLS verification key + /// @param amount The amount to deposit + /// @return (newBalance, effectiveEpoch) the new balance effective at a future epoch + function depoist(BN254.G1Point calldata blsVK, uint64 amount) + external + returns (uint64, uint64); + + /// @notice Request to exit from the stake table, not immediately withdrawable! + /// + /// @param blsVK The BLS verification key to exit + /// @return success status + function exit(BN254.G1Point calldata blsVK) external returns (bool); + + /// @notice Withdraw from the staking pool. Transfers occur! Only successfully exited keys can + /// withdraw past their `exitEpoch`. + /// + /// @param blsVK The BLS verification key to withdraw + /// @return The total amount withdrawn, equal to `Node.balance` associated with `blsVK` + function withdraw(BN254.G1Point calldata blsVK) external returns (uint64); + + /// @notice Advance to the next epoch, the new `votingStakeTableCommitment` will be + /// `frozenStakeTableCommitment` and the new `frozenStakeTableCommitment` will be + /// `curEpochComm`, + function advanceEpoch(bytes32 curEpochComm) external returns (bool); +} diff --git a/contracts/src/libraries/EdOnBn254.sol b/contracts/src/libraries/EdOnBn254.sol new file mode 100644 index 0000000000..c7cfe2b32b --- /dev/null +++ b/contracts/src/libraries/EdOnBn254.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.0; + +import { Utils } from "bn254/BN254.sol"; + +/// @notice Edward curve on BN254. +/// This library only implements a serialization function that is consistent with +/// Arkworks' format. It does not support any group operations. +library EdOnBN254 { + uint256 public constant P_MOD = + 21888242871839275222246405745257275088548364400416034343698204186575808495617; + + struct EdOnBN254Point { + uint256 x; + uint256 y; + } + + /// @dev Check if y-coordinate of G1 point is negative. + function isYNegative(EdOnBN254Point memory point) internal pure returns (bool) { + return (point.y << 1) < P_MOD; + } + + /// @dev Serialize a point into bytes + function serialize(EdOnBN254Point memory point) internal pure returns (bytes memory res) { + uint256 mask = 0; + // Edward curve does not have an infinity flag. + // Set the 255-th bit to 1 for positive Y + // See: + // https://github.com/arkworks-rs/algebra/blob/d6365c3a0724e5d71322fe19cbdb30f979b064c8/serialize/src/flags.rs#L148 + if (!EdOnBN254.isYNegative(point)) { + mask = 0x8000000000000000000000000000000000000000000000000000000000000000; + } + + return abi.encodePacked(Utils.reverseEndianness(point.x | mask)); + } + + // TODO: (alex) add `validatePoint` methods and tests +} From 90bf8d1c42a6613213ef9efe4711a57e3c803a89 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Tue, 14 Nov 2023 11:57:44 +0800 Subject: [PATCH 26/38] fix: allow empty public input, remove default.fuzz.runs, increase ci.fuzz.runs --- contracts/src/libraries/PolynomialEval.sol | 2 +- contracts/test/PlonkVerifier.t.sol | 9 --------- contracts/test/PolynomialEval.t.sol | 6 +----- contracts/test/Transcript.t.sol | 7 ------- foundry.toml | 2 +- 5 files changed, 3 insertions(+), 23 deletions(-) diff --git a/contracts/src/libraries/PolynomialEval.sol b/contracts/src/libraries/PolynomialEval.sol index 39ee1e7199..4dcc94562a 100644 --- a/contracts/src/libraries/PolynomialEval.sol +++ b/contracts/src/libraries/PolynomialEval.sol @@ -228,7 +228,7 @@ library PolynomialEval { pure returns (uint256[] memory elements) { - if (length > self.size || length == 0) revert InvalidPolyEvalArgs(); + if (length > self.size) revert InvalidPolyEvalArgs(); uint256 groupGen = self.groupGen; uint256 tmp = 1; uint256 p = BN254.R_MOD; diff --git a/contracts/test/PlonkVerifier.t.sol b/contracts/test/PlonkVerifier.t.sol index 591e761b30..476801e116 100644 --- a/contracts/test/PlonkVerifier.t.sol +++ b/contracts/test/PlonkVerifier.t.sol @@ -143,7 +143,6 @@ contract PlonkVerifier_constants_Test is Test { } contract PlonkVerifier_batchVerify_Test is PlonkVerifierCommonTest { - /// forge-config: default.fuzz.runs = 30 /// @dev Test if some of the user inputs are invalid function testFuzz_revertWhenInvalidArgs( IPlonkVerifier.VerifyingKey[] memory verifyingKeys, @@ -182,7 +181,6 @@ contract PlonkVerifier_batchVerify_Test is PlonkVerifierCommonTest { } } - /// forge-config: default.fuzz.runs = 30 /// @dev Test when bad public inputs are supplied, the verification should fail /// We know our `gen_circuit_for_test` in `diff_test.rs` has only 3 public inputs function testFuzz_badPublicInputs_fails(uint256[3] calldata randPublicInput) external { @@ -212,7 +210,6 @@ contract PlonkVerifier_batchVerify_Test is PlonkVerifierCommonTest { assert(!V.batchVerify(verifyingKeys, publicInputs, proofs, extraTranscriptInitMsgs)); } - /// forge-config: default.fuzz.runs = 30 /// @dev Test when bad proofs are supplied, the verification should fail function testFuzz_badProofs_fails(uint64 seed) external { IPlonkVerifier.PlonkProof memory badProof = dummyProof(seed); @@ -237,7 +234,6 @@ contract PlonkVerifier_batchVerify_Test is PlonkVerifierCommonTest { assert(!V.batchVerify(verifyingKeys, publicInputs, proofs, extraTranscriptInitMsgs)); } - /// forge-config: default.fuzz.runs = 30 /// @dev Test when bad extraTranscriptInitMsgs are supplied, the verification should fail function testFuzz_badExtraTranscriptInitMsgs_fails(bytes calldata badMsg) external { string[] memory cmds = new string[](3); @@ -270,7 +266,6 @@ contract PlonkVerifier_validateProof_Test is PlonkVerifierCommonTest { V._validateProof(proof); } - /// forge-config: default.fuzz.runs = 30 /// @dev Randomly pick a coordinate of a point among points in a proof /// mutate it to another value so that the point is no longer valid, /// test if our check will revert. @@ -296,7 +291,6 @@ contract PlonkVerifier_validateProof_Test is PlonkVerifierCommonTest { V._validateProof(proof); } - /// forge-config: default.fuzz.runs = 15 /// @dev Randomly pick field in a proof mutate it to invalid value /// test if our check will revert. function testFuzz_RevertIfProofContainsInvalidField(uint256 nthField) external { @@ -319,7 +313,6 @@ contract PlonkVerifier_validateProof_Test is PlonkVerifierCommonTest { } contract PlonkVerifier_preparePcsInfo_Test is PlonkVerifierCommonTest { - /// forge-config: default.fuzz.runs = 5 /// @dev Test `preparePcsInfo` matches that of Jellyfish function testFuzz_preparePcsInfo_matches( uint64 seed, @@ -366,7 +359,6 @@ contract PlonkVerifier_preparePcsInfo_Test is PlonkVerifierCommonTest { } contract PlonkVerifier_computeChallenges_Test is PlonkVerifierCommonTest { - /// forge-config: default.fuzz.runs = 5 /// @dev Test `computeChallenges` matches that of Jellyfish function testFuzz_computeChallenges_matches( uint64 seed, @@ -401,7 +393,6 @@ contract PlonkVerifier_computeChallenges_Test is PlonkVerifierCommonTest { } contract PlonkVerifier_prepareEvaluations_Test is PlonkVerifierCommonTest { - /// forge-config: default.fuzz.runs = 5 /// @dev Test if combinng the polynomial evaluations into a single evaluation is done correctly /// is done correctly function testFuzz_prepareEvaluations_matches( diff --git a/contracts/test/PolynomialEval.t.sol b/contracts/test/PolynomialEval.t.sol index 07ab68aea3..28d159e0bd 100644 --- a/contracts/test/PolynomialEval.t.sol +++ b/contracts/test/PolynomialEval.t.sol @@ -32,7 +32,6 @@ contract PolynomialEval_newEvalDomain_Test is Test { } } - /// forge-config: default.fuzz.runs = 20 /// @dev Test revert if domainSize is not among {2^14, 2^15, 2^16, 2^17, 2^5} function testFuzz_unsupportedDomainSize_reverts(uint256 domainSize) external { vm.assume( @@ -47,12 +46,11 @@ contract PolynomialEval_newEvalDomain_Test is Test { contract PolynomialEval_domainElements_Test is Test { /// @dev Test if the domain elements are generated correctly - /// forge-config: default.fuzz.runs = 25 function testFuzz_domainElements_matches(uint256 logSize, uint256 length) external { logSize = bound(logSize, 14, 17); Poly.EvalDomain memory domain = Poly.newEvalDomain(2 ** logSize); - if (length > domain.size || length == 0) { + if (length > domain.size) { vm.expectRevert(Poly.InvalidPolyEvalArgs.selector); Poly.domainElements(domain, length); } else { @@ -73,7 +71,6 @@ contract PolynomialEval_domainElements_Test is Test { contract PolynomialEval_evalDataGen_Test is Test { /// @dev Test if evaluations on the vanishing poly, the lagrange one poly, and the public input /// poly are correct. - /// forge-config: default.fuzz.runs = 10 function testFuzz_evalDataGen_matches( uint256 logSize, uint256 zeta, @@ -82,7 +79,6 @@ contract PolynomialEval_evalDataGen_Test is Test { logSize = bound(logSize, 14, 17); zeta = bound(zeta, 0, BN254.R_MOD - 1); BN254.validateScalarField(zeta); - vm.assume(publicInput.length > 0); // Since these user-provided `publicInputs` were checked outside before passing in via // `BN254.validateScalarField()`, it suffices to assume they are proper for our test here. for (uint256 i = 0; i < publicInput.length; i++) { diff --git a/contracts/test/Transcript.t.sol b/contracts/test/Transcript.t.sol index 3bf4f12d66..2c73622b9e 100644 --- a/contracts/test/Transcript.t.sol +++ b/contracts/test/Transcript.t.sol @@ -16,7 +16,6 @@ import { Transcript as T } from "../src/libraries/Transcript.sol"; contract Transcript_appendMessage_Test is Test { using T for T.TranscriptData; - /// forge-config: default.fuzz.runs = 10 /// @dev Test if `appendMessage` matches that of the Jellyfish's code function testFuzz_appendMessage_matches( T.TranscriptData memory transcript, @@ -41,7 +40,6 @@ contract Transcript_appendMessage_Test is Test { contract Transcript_appendFieldElement_Test is Test { using T for T.TranscriptData; - /// forge-config: default.fuzz.runs = 10 /// @dev Test if `appendFieldElement` matches that of Jellyfish function testFuzz_appendFieldElement_matches( T.TranscriptData memory transcript, @@ -69,7 +67,6 @@ contract Transcript_appendFieldElement_Test is Test { contract Transcript_appendGroupElement_Test is Test { using T for T.TranscriptData; - /// forge-config: default.fuzz.runs = 10 /// @dev Test if `appendGroupElement` matches that of Jellyfish function testFuzz_appendGroupElement_matches( T.TranscriptData memory transcript, @@ -94,7 +91,6 @@ contract Transcript_appendGroupElement_Test is Test { assertEq(updated.state[1], transcript.state[1]); } - /// forge-config: default.fuzz.runs = 5 /// @dev Test special case where the identity point (or infinity) is appended. function test_appendInfinityPoint_succeeds(T.TranscriptData memory transcript) external { BN254.G1Point memory infinity = BN254.G1Point(0, 0); @@ -119,7 +115,6 @@ contract Transcript_appendGroupElement_Test is Test { contract Transcript_getAndAppendChallenge_Test is Test { using T for T.TranscriptData; - /// forge-config: default.fuzz.runs = 10 /// @dev Test if `getAndAppendChallenge` matches that of Jellyfish function testFuzz_getAndAppendChallenge_matches(T.TranscriptData memory transcript) external { string[] memory cmds = new string[](3); @@ -143,7 +138,6 @@ contract Transcript_getAndAppendChallenge_Test is Test { contract Transcript_appendVkAndPubInput_Test is Test { using T for T.TranscriptData; - /// forge-config: default.fuzz.runs = 5 /// @dev Test if `appendVkAndPubInput` matches that of Jellyfish function testFuzz_appendVkAndPubInput_matches( T.TranscriptData memory transcript, @@ -176,7 +170,6 @@ contract Transcript_appendVkAndPubInput_Test is Test { contract Transcript_appendProofEvaluations_Test is Test { using T for T.TranscriptData; - /// forge-config: default.fuzz.runs = 5 /// @dev Test if `appendProofEvaluations` matches that of Jellyfish function testFuzz_appendProofEvaluations_matches(T.TranscriptData memory transcript) external { string[] memory cmds = new string[](3); diff --git a/foundry.toml b/foundry.toml index edafc6dd28..266d2df88c 100644 --- a/foundry.toml +++ b/foundry.toml @@ -29,4 +29,4 @@ bracket_spacing=true wrap_comments=true [profile.ci] -fuzz = { run = 50 } +fuzz = { runs = 1000 } From b914f7761975e341ddd7f49eea9125f8f72efbd6 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Tue, 14 Nov 2023 12:07:18 +0800 Subject: [PATCH 27/38] address comments --- contracts/test/PlonkVerifier.t.sol | 61 ++++++++++++++++++++++++++---- flake.nix | 2 +- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/contracts/test/PlonkVerifier.t.sol b/contracts/test/PlonkVerifier.t.sol index 476801e116..bdad0a9ee0 100644 --- a/contracts/test/PlonkVerifier.t.sol +++ b/contracts/test/PlonkVerifier.t.sol @@ -36,8 +36,7 @@ contract PlonkVerifierCommonTest is Test { /// This is helpful to sanitize fuzzer-generated random `uint[]` values. function sanitizeScalarFields(uint256[] memory a) public view returns (uint256[] memory) { for (uint256 i = 0; i < a.length; i++) { - a[i] = bound(a[i], 0, BN254.R_MOD - 1); - BN254.validateScalarField(a[i]); + a[i] = sanitizeScalarField(a[i]); } return a; } @@ -181,6 +180,49 @@ contract PlonkVerifier_batchVerify_Test is PlonkVerifierCommonTest { } } + /// @dev Test when bad verifying key are supplied, the verification should fail + function testFuzz_badVerifyingKey_fails(uint256 nthPoint) external { + string[] memory cmds = new string[](3); + cmds[0] = "diff-test"; + cmds[1] = "plonk-batch-verify"; + cmds[2] = vm.toString(uint32(1)); + + bytes memory result = vm.ffi(cmds); + ( + IPlonkVerifier.VerifyingKey[] memory verifyingKeys, + uint256[][] memory publicInputs, + IPlonkVerifier.PlonkProof[] memory proofs, + bytes[] memory extraTranscriptInitMsgs + ) = abi.decode( + result, + (IPlonkVerifier.VerifyingKey[], uint256[][], IPlonkVerifier.PlonkProof[], bytes[]) + ); + + // there are 18 points in verifying key + // randomly choose one to mutate + nthPoint = bound(nthPoint, 0, 17); + + BN254.G1Point memory badPoint; + assembly { + // the first 32 bytes is array length + let firstVkRef := add(verifyingKeys, 0x20) + // the first point offset is 0x40 + let badPointRef := add(mload(firstVkRef), add(mul(nthPoint, 0x20), 0x40)) + badPoint := mload(badPointRef) + } + + // modify the point to be invalid + badPoint = BN254.add(badPoint, BN254.P1()); + + assembly { + let firstVkRef := add(verifyingKeys, 0x20) + let badPointRef := add(mload(firstVkRef), add(mul(nthPoint, 0x20), 0x40)) + mstore(badPointRef, badPoint) + } + + assert(!V.batchVerify(verifyingKeys, publicInputs, proofs, extraTranscriptInitMsgs)); + } + /// @dev Test when bad public inputs are supplied, the verification should fail /// We know our `gen_circuit_for_test` in `diff_test.rs` has only 3 public inputs function testFuzz_badPublicInputs_fails(uint256[3] calldata randPublicInput) external { @@ -279,12 +321,15 @@ contract PlonkVerifier_validateProof_Test is PlonkVerifierCommonTest { nthPoint = bound(nthPoint, 0, 12); assembly { - if testX { - // muteate the x coordinate + switch testX + case true { + // mutate the x coordinate mstore(mload(add(proof, mul(0x20, nthPoint))), 0x1234) } - // else, mutate y coordinate - mstore(add(mload(add(proof, mul(0x20, nthPoint))), 0x20), 0x1234) + default { + // else, mutate y coordinate + mstore(add(mload(add(proof, mul(0x20, nthPoint))), 0x20), 0x1234) + } } vm.expectRevert(); @@ -299,7 +344,7 @@ contract PlonkVerifier_validateProof_Test is PlonkVerifierCommonTest { uint256 invalidField = BN254.R_MOD; // we are testing the `nthField` in the `proof`, - // There are 10 points in total (with 13 points in front) + // There are 10 field elements in total (with 13 points in front) nthField = bound(nthField, 0, 9); assembly { @@ -393,7 +438,7 @@ contract PlonkVerifier_computeChallenges_Test is PlonkVerifierCommonTest { } contract PlonkVerifier_prepareEvaluations_Test is PlonkVerifierCommonTest { - /// @dev Test if combinng the polynomial evaluations into a single evaluation is done correctly + /// @dev Test if combining the polynomial evaluations into a single evaluation is done correctly /// is done correctly function testFuzz_prepareEvaluations_matches( uint64 seed, diff --git a/flake.nix b/flake.nix index 6a7edddae7..35440b4dd5 100644 --- a/flake.nix +++ b/flake.nix @@ -198,7 +198,7 @@ # Prevent cargo aliases from using programs in `~/.cargo` to avoid conflicts # with rustup installations. export CARGO_HOME=$HOME/.cargo-nix - export PATH="./target/release:$PATH" + export PATH="$PWD/target/release:$PATH" '' + self.checks.${system}.pre-commit-check.shellHook; RUST_SRC_PATH = "${stableToolchain}/lib/rustlib/src/rust/library"; FOUNDRY_SOLC = "${solc}/bin/solc"; From fc1484eccc33744db412645d721146bdf553c0de Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Tue, 14 Nov 2023 15:56:45 +0800 Subject: [PATCH 28/38] improve diff-test --- contracts/rust/src/bin/diff_test.rs | 321 ++++++++++++---------------- 1 file changed, 134 insertions(+), 187 deletions(-) diff --git a/contracts/rust/src/bin/diff_test.rs b/contracts/rust/src/bin/diff_test.rs index 889e975081..0212f75c7b 100644 --- a/contracts/rust/src/bin/diff_test.rs +++ b/contracts/rust/src/bin/diff_test.rs @@ -37,14 +37,9 @@ struct Cli { /// Identifier for the functions to invoke in Jellyfish #[arg(value_enum)] action: Action, - /// Optional 1st argument for the `action` - arg1: Option, - /// Optional 2nd argument for the `action` - arg2: Option, - /// Optional 3rd argument for the `action` - arg3: Option, - /// Optional 4th argument for the `action` - arg4: Option, + /// Optional arguments for the `action` + #[arg(value_parser, num_args = 1.., value_delimiter = ' ')] + args: Vec, } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] @@ -89,8 +84,10 @@ fn main() { match cli.action { Action::NewPolyEvalDomain => { - let arg1 = cli.arg1.as_ref().expect("Should provide arg1=logSize"); - let log_size = arg1.parse::().unwrap(); + if cli.args.len() != 1 { + panic!("Should provide arg1=logSize"); + } + let log_size = cli.args[0].parse::().unwrap(); let domain = Radix2EvaluationDomain::::new(2u32.pow(log_size) as usize).unwrap(); let res = ( @@ -101,10 +98,11 @@ fn main() { println!("{}", res.encode_hex()); } Action::EvalDomainElements => { - let arg1 = cli.arg1.as_ref().expect("Should provide arg1=logSize"); - let arg2 = cli.arg2.as_ref().expect("Should provide arg2=length"); - let log_size = arg1.parse::().unwrap(); - let length = arg2.parse::().unwrap(); + if cli.args.len() != 2 { + panic!("Should provide arg1=logSize, arg2=length"); + } + let log_size = cli.args[0].parse::().unwrap(); + let length = cli.args[1].parse::().unwrap(); let domain = Radix2EvaluationDomain::::new(2u32.pow(log_size) as usize).unwrap(); let res = domain @@ -115,13 +113,13 @@ fn main() { println!("{}", res.encode_hex()); } Action::EvalDataGen => { - let arg1 = cli.arg1.as_ref().expect("Should provide arg1=logSize"); - let arg2 = cli.arg2.as_ref().expect("Should provide arg2=zeta"); - let arg3 = cli.arg3.as_ref().expect("Should provide arg3=publicInput"); + if cli.args.len() != 3 { + panic!("Should provide arg1=logSize, arg2=zeta, arg3=publicInput"); + } - let log_size = arg1.parse::().unwrap(); - let zeta = u256_to_field::(arg2.parse::().unwrap()); - let pi_u256: Vec = AbiDecode::decode_hex(arg3).unwrap(); + let log_size = cli.args[0].parse::().unwrap(); + let zeta = u256_to_field::(cli.args[1].parse::().unwrap()); + let pi_u256: Vec = AbiDecode::decode_hex(&cli.args[2]).unwrap(); let pi: Vec = pi_u256.into_iter().map(u256_to_field).collect(); let verifier = Verifier::::new(2u32.pow(log_size) as usize).unwrap(); @@ -136,11 +134,12 @@ fn main() { println!("{}", res.encode_hex()); } Action::TranscriptAppendMsg => { - let arg1 = cli.arg1.as_ref().expect("Should provide arg1=transcript"); - let arg2 = cli.arg2.as_ref().expect("Should provide arg2=message"); - let t_parsed = arg1.parse::().unwrap(); + if cli.args.len() != 2 { + panic!("Should provide arg1=transcript, arg2=message"); + } + let t_parsed = cli.args[0].parse::().unwrap(); let msg = { - let parsed: Bytes = AbiDecode::decode_hex(arg2).unwrap(); + let parsed: Bytes = AbiDecode::decode_hex(&cli.args[1]).unwrap(); parsed.0.to_vec() }; @@ -150,10 +149,11 @@ fn main() { println!("{}", (res,).encode_hex()); } Action::TranscriptAppendField => { - let arg1 = cli.arg1.as_ref().expect("Should provide arg1=transcript"); - let arg2 = cli.arg2.as_ref().expect("Should provide arg2=fieldElement"); - let t_parsed = arg1.parse::().unwrap(); - let field = u256_to_field::(arg2.parse::().unwrap()); + if cli.args.len() != 2 { + panic!("Should provide arg1=transcript, arg2=fieldElement"); + } + let t_parsed = cli.args[0].parse::().unwrap(); + let field = u256_to_field::(cli.args[1].parse::().unwrap()); let mut t: SolidityTranscript = t_parsed.into(); t.append_challenge::(&[], &field).unwrap(); @@ -161,10 +161,12 @@ fn main() { println!("{}", (res,).encode_hex()); } Action::TranscriptAppendGroup => { - let arg1 = cli.arg1.as_ref().expect("Should provide arg1=transcript"); - let arg2 = cli.arg2.as_ref().expect("Should provide arg2=groupElement"); - let t_parsed = arg1.parse::().unwrap(); - let point: G1Affine = arg2.parse::().unwrap().into(); + if cli.args.len() != 2 { + panic!("Should provide arg1=transcript, arg2=groupElement"); + } + + let t_parsed = cli.args[0].parse::().unwrap(); + let point: G1Affine = cli.args[1].parse::().unwrap().into(); let mut t: SolidityTranscript = t_parsed.into(); t.append_commitment::(&[], &Commitment::from(point)) @@ -173,8 +175,11 @@ fn main() { println!("{}", (res,).encode_hex()); } Action::TranscriptGetChal => { - let arg1 = cli.arg1.as_ref().expect("Should provide arg1=transcript"); - let t_parsed = arg1.parse::().unwrap(); + if cli.args.len() != 1 { + panic!("Should provide arg1=transcript"); + } + + let t_parsed = cli.args[0].parse::().unwrap(); let mut t: SolidityTranscript = t_parsed.into(); let chal = t.get_and_append_challenge::(&[]).unwrap(); @@ -184,13 +189,13 @@ fn main() { println!("{}", res.encode_hex()); } Action::TranscriptAppendVkAndPi => { - let arg1 = cli.arg1.as_ref().expect("Should provide arg1=transcript"); - let arg2 = cli.arg2.as_ref().expect("Should provide arg2=verifyingKey"); - let arg3 = cli.arg3.as_ref().expect("Should provide arg3=publicInput"); + if cli.args.len() != 3 { + panic!("Should provide arg1=transcript, arg2=verifyingKey, arg3=publicInput"); + } - let t_parsed = arg1.parse::().unwrap(); - let vk_parsed = arg2.parse::().unwrap(); - let pi_u256: Vec = AbiDecode::decode_hex(arg3).unwrap(); + let t_parsed = cli.args[0].parse::().unwrap(); + let vk_parsed = cli.args[1].parse::().unwrap(); + let pi_u256: Vec = AbiDecode::decode_hex(&cli.args[2]).unwrap(); let pi: Vec = pi_u256.into_iter().map(u256_to_field).collect(); let mut t: SolidityTranscript = t_parsed.into(); @@ -201,10 +206,13 @@ fn main() { println!("{}", (res,).encode_hex()); } Action::TranscriptAppendProofEvals => { + if cli.args.len() != 1 { + panic!("Should provide arg1=transcript"); + } + let mut rng = jf_utils::test_rng(); - let arg1 = cli.arg1.as_ref().expect("Should provide arg1=transcript"); - let t_parsed = arg1.parse::().unwrap(); + let t_parsed = cli.args[0].parse::().unwrap(); let proof_parsed = ParsedPlonkProof::dummy_with_rand_proof_evals(&mut rng); let proof: Proof = proof_parsed.clone().into(); @@ -238,20 +246,16 @@ fn main() { println!("{}", res.encode_hex()); } Action::PlonkComputeChal => { - let arg1 = cli.arg1.as_ref().expect("Should provide arg1=verifyingKey"); - let arg2 = cli.arg2.as_ref().expect("Should provide arg2=publicInput"); - let arg3 = cli.arg3.as_ref().expect("Should provide arg3=proof"); - let arg4 = cli - .arg4 - .as_ref() - .expect("Should provide arg3=extraTranscriptInitMsg"); - - let vk = arg1.parse::().unwrap().into(); - let pi_u256: Vec = AbiDecode::decode_hex(arg2).unwrap(); + if cli.args.len() != 4 { + panic!("Should provide arg1=verifyingKey, arg2=publicInput, arg3=proof, arg4=extraTranscriptInitMsg"); + } + + let vk = cli.args[0].parse::().unwrap().into(); + let pi_u256: Vec = AbiDecode::decode_hex(&cli.args[1]).unwrap(); let pi: Vec = pi_u256.into_iter().map(u256_to_field).collect(); - let proof: Proof = arg3.parse::().unwrap().into(); + let proof: Proof = cli.args[2].parse::().unwrap().into(); let msg = { - let parsed: Bytes = AbiDecode::decode_hex(arg4).unwrap(); + let parsed: Bytes = AbiDecode::decode_hex(&cli.args[3]).unwrap(); parsed.0.to_vec() }; @@ -267,16 +271,13 @@ fn main() { println!("{}", (chal,).encode_hex()); } Action::PlonkPrepareEval => { - let arg1 = cli.arg1.as_ref().expect("Should provide arg1=proof"); - let arg2 = cli - .arg2 - .as_ref() - .expect("Should provide arg2=linPolyConstant"); - let arg3 = cli.arg3.as_ref().expect("Should provide arg3=commScalars"); - - let proof: Proof = arg1.parse::().unwrap().into(); - let lin_poly_constant = u256_to_field::(arg2.parse::().unwrap()); - let comm_scalars_u256: Vec = AbiDecode::decode_hex(arg3).unwrap(); + if cli.args.len() != 3 { + panic!("Should provide arg1=proof, arg2=linPolyConstant, arg3=commScalars"); + } + + let proof: Proof = cli.args[0].parse::().unwrap().into(); + let lin_poly_constant = u256_to_field::(cli.args[1].parse::().unwrap()); + let comm_scalars_u256: Vec = AbiDecode::decode_hex(&cli.args[2]).unwrap(); // NOTE: only take the last 10 scalars, the first 20 are linearization scalars let comm_scalars: Vec = comm_scalars_u256 .into_iter() @@ -295,20 +296,16 @@ fn main() { println!("{}", (res,).encode_hex()); } Action::PlonkPreparePcsInfo => { - let arg1 = cli.arg1.as_ref().expect("Should provide arg1=verifyingKey"); - let arg2 = cli.arg2.as_ref().expect("Should provide arg2=publicInput"); - let arg3 = cli.arg3.as_ref().expect("Should provide arg3=proof"); - let arg4 = cli - .arg4 - .as_ref() - .expect("Should provide arg4=extraTranscriptInitMsg"); - - let vk: VerifyingKey = arg1.parse::().unwrap().into(); - let pi_u256: Vec = AbiDecode::decode_hex(arg2).unwrap(); + if cli.args.len() != 4 { + panic!("Should provide arg1=verifyingKey, arg2=publicInput, arg3=proof, arg4=extraTranscriptInitMsg"); + } + + let vk: VerifyingKey = cli.args[0].parse::().unwrap().into(); + let pi_u256: Vec = AbiDecode::decode_hex(&cli.args[1]).unwrap(); let pi: Vec = pi_u256.into_iter().map(u256_to_field).collect(); - let proof: Proof = arg3.parse::().unwrap().into(); + let proof: Proof = cli.args[2].parse::().unwrap().into(); let msg = { - let parsed: Bytes = AbiDecode::decode_hex(arg4).unwrap(); + let parsed: Bytes = AbiDecode::decode_hex(&cli.args[3]).unwrap(); parsed.0.to_vec() }; @@ -336,15 +333,18 @@ fn main() { println!("{}", res.encode_hex()); } Action::PlonkBatchVerify => { - let arg1 = cli.arg1.as_ref().expect("Should provide arg1=numProof"); - let num_proof = arg1.parse::().unwrap(); + if cli.args.len() != 1 { + panic!("Should provide arg1=numProof"); + } + + let num_proof = cli.args[0].parse::().unwrap(); let (proofs, vks, public_inputs, extra_msgs, _): ( Vec>, Vec>, Vec>, Vec>>, Vec, - ) = multiunzip(gen_plonk_proof_for_test(num_proof as usize).unwrap()); + ) = multiunzip(gen_plonk_proof_for_test(num_proof as usize)); // ensure they are correct params let proofs_refs: Vec<&Proof> = proofs.iter().collect(); @@ -377,22 +377,15 @@ fn main() { } Action::DummyProof => { let mut rng = jf_utils::test_rng(); - if let Some(arg1) = cli.arg1.as_ref() { - let seed = arg1.parse::().unwrap(); + if !cli.args.is_empty() { + let seed = cli.args[0].parse::().unwrap(); rng = StdRng::seed_from_u64(seed); } - let proof = ParsedPlonkProof::dummy(&mut rng); println!("{}", (proof,).encode_hex()); } Action::TestOnly => { - let arg1 = cli.arg1.as_ref().expect("Should provide arg1=proof"); - let proof_parsed = arg1.parse::().unwrap(); - - let proof: Proof = proof_parsed.into(); - - let res: ParsedPlonkProof = proof.into(); - println!("{}", (res,).encode_hex()); + println!("args: {:?}", cli.args); } }; } @@ -402,40 +395,42 @@ fn main() { // constant in hex string copied from hardcoded constants from solidity contracts +const COSET: [&str; 5] = [ + "1", + "2f8dd1f1a7583c42c4e12a44e110404c73ca6c94813f85835da4fb7bb1301d4a", + "1ee678a0470a75a6eaa8fe837060498ba828a3703b311d0f77f010424afeb025", + "2042a587a90c187b0a087c03e29c968b950b1db26d5c82d666905a6895790c0a", + "2e2b91456103698adf57b799969dea1c8f739da5d8d40dd3eb9222db7c81e881", +]; + +// H: G2Affine(x: Fp2, y:Fp2), x = x0 + u * x1, y = y0 + u * y1 +// NOTE: extra careful with discrepancy with current version of BN254.G2Point +// which assume Fp2 = x0 * u + x1 ! +const H: [&str; 4] = [ + "1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed", // x0 + "198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2", // x1 + "12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", // y0 + "090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b", // y1 +]; + +// See notes about `const H` above. +const BETA_H: [&str; 4] = [ + "0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0", + "260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1", + "22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55", + "04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4", +]; + // TODO: (alex) change to simply using `MontFp!("0x..")` after // is on a tag release // Return cosets coefficients for circuits over BN254. fn coset_k() -> Vec { vec![ - Fr::from(BigUint::from_str_radix("1", 16).unwrap()), - Fr::from( - BigUint::from_str_radix( - "2f8dd1f1a7583c42c4e12a44e110404c73ca6c94813f85835da4fb7bb1301d4a", - 16, - ) - .unwrap(), - ), - Fr::from( - BigUint::from_str_radix( - "1ee678a0470a75a6eaa8fe837060498ba828a3703b311d0f77f010424afeb025", - 16, - ) - .unwrap(), - ), - Fr::from( - BigUint::from_str_radix( - "2042a587a90c187b0a087c03e29c968b950b1db26d5c82d666905a6895790c0a", - 16, - ) - .unwrap(), - ), - Fr::from( - BigUint::from_str_radix( - "2e2b91456103698adf57b799969dea1c8f739da5d8d40dd3eb9222db7c81e881", - 16, - ) - .unwrap(), - ), + Fr::from(BigUint::from_str_radix(COSET[0], 16).unwrap()), + Fr::from(BigUint::from_str_radix(COSET[1], 16).unwrap()), + Fr::from(BigUint::from_str_radix(COSET[2], 16).unwrap()), + Fr::from(BigUint::from_str_radix(COSET[3], 16).unwrap()), + Fr::from(BigUint::from_str_radix(COSET[4], 16).unwrap()), ] } @@ -444,70 +439,22 @@ fn open_key() -> OpenKey { let g = G1Affine::new_unchecked(MontFp!("1"), MontFp!("2")); let h = G2Affine::new( Fp2::new( - Fq::from( - BigUint::from_str_radix( - "1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed", - 16, - ) - .unwrap(), - ), - Fq::from( - BigUint::from_str_radix( - "198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2", - 16, - ) - .unwrap(), - ), + Fq::from(BigUint::from_str_radix(H[0], 16).unwrap()), + Fq::from(BigUint::from_str_radix(H[1], 16).unwrap()), ), Fp2::new( - Fq::from( - BigUint::from_str_radix( - "12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", - 16, - ) - .unwrap(), - ), - Fq::from( - BigUint::from_str_radix( - "090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b", - 16, - ) - .unwrap(), - ), + Fq::from(BigUint::from_str_radix(H[2], 16).unwrap()), + Fq::from(BigUint::from_str_radix(H[3], 16).unwrap()), ), ); let beta_h = G2Affine::new( Fp2::new( - Fq::from( - BigUint::from_str_radix( - "0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0", - 16, - ) - .unwrap(), - ), - Fq::from( - BigUint::from_str_radix( - "260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1", - 16, - ) - .unwrap(), - ), + Fq::from(BigUint::from_str_radix(BETA_H[0], 16).unwrap()), + Fq::from(BigUint::from_str_radix(BETA_H[1], 16).unwrap()), ), Fp2::new( - Fq::from( - BigUint::from_str_radix( - "22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55", - 16, - ) - .unwrap(), - ), - Fq::from( - BigUint::from_str_radix( - "04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4", - 16, - ) - .unwrap(), - ), + Fq::from(BigUint::from_str_radix(BETA_H[2], 16).unwrap()), + Fq::from(BigUint::from_str_radix(BETA_H[3], 16).unwrap()), ), ); @@ -958,19 +905,17 @@ impl From for Challenges { #[allow(clippy::type_complexity)] fn gen_plonk_proof_for_test( num_proof: usize, -) -> Result< - Vec<( - Proof, - VerifyingKey, - Vec, - Option>, - usize, - )>, -> { +) -> Vec<( + Proof, + VerifyingKey, + Vec, + Option>, + usize, +)> { // 1. Simulate universal setup let rng = &mut jf_utils::test_rng(); let srs = { - let aztec_srs = crs::aztec20::kzg10_setup(1024)?; + let aztec_srs = crs::aztec20::kzg10_setup(1024).expect("Aztec SRS fail to load"); UnivariateUniversalParams { powers_of_g: aztec_srs.powers_of_g, @@ -990,7 +935,8 @@ fn gen_plonk_proof_for_test( let a0 = 1 + i % 3; gen_circuit_for_test::(m, a0) }) - .collect::>>()?; + .collect::>>() + .expect("Test circuits fail to create"); let domain_sizes: Vec = circuits .iter() .map(|c| c.eval_domain_size().unwrap()) @@ -1000,7 +946,8 @@ fn gen_plonk_proof_for_test( let mut prove_keys = vec![]; let mut ver_keys = vec![]; for c in circuits.iter() { - let (pk, vk) = PlonkKzgSnark::::preprocess(&srs, c)?; + let (pk, vk) = + PlonkKzgSnark::::preprocess(&srs, c).expect("Circuit preprocessing failed"); prove_keys.push(pk); ver_keys.push(vk); } @@ -1032,7 +979,7 @@ fn gen_plonk_proof_for_test( .map(|cs| cs.public_input().unwrap()) .collect(); - Ok(izip!(proofs, ver_keys, public_inputs, extra_msgs, domain_sizes).collect()) + izip!(proofs, ver_keys, public_inputs, extra_msgs, domain_sizes).collect() } // Different `m`s lead to different circuits. From 9268423180e4c5d421de4a6fa3f2ce51e0165be1 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Tue, 14 Nov 2023 16:21:04 +0800 Subject: [PATCH 29/38] Revert "add stake table interfaces" This reverts commit 103969016549e36f5ac5a8dadf1e6bad91efe5f7. --- contracts/src/interfaces/IStakeTable.sol | 127 ----------------------- contracts/src/libraries/EdOnBn254.sol | 39 ------- 2 files changed, 166 deletions(-) delete mode 100644 contracts/src/interfaces/IStakeTable.sol delete mode 100644 contracts/src/libraries/EdOnBn254.sol diff --git a/contracts/src/interfaces/IStakeTable.sol b/contracts/src/interfaces/IStakeTable.sol deleted file mode 100644 index 85c7ca3a6f..0000000000 --- a/contracts/src/interfaces/IStakeTable.sol +++ /dev/null @@ -1,127 +0,0 @@ -// SPDX-License-Identifier: Unlicensed - -pragma solidity ^0.8.0; - -import { BN254 } from "bn254/BN254.sol"; -import { EdOnBN254 } from "../libraries/EdOnBn254.sol"; - -/// @title Interface for stake table that keep track of validators' external key and staked amount. -/// @dev Stake delegation happens in a separate DelegationPool contract, and specific to -/// instantiation thus not part of this interface -interface IStakeTable { - /// @notice Supported stake type, either using native token or re-staked using ETH - enum StakeType { - Native, - Restake - } - - /// @dev (sadly, Solidity doesn't support type alias on non-primitive types) - // We avoid declaring another struct even if the type info helps with readability, - // extra layer of struct introduces overhead and more gas cost. - // - /// @dev BLS verification key (used for Consensus voting in HotShot) is `BN254.G1Point`. - // `type BlsVerKey is BN254.G1Point;` - // - /// @dev Verification key of a Schnorr signature is just a `EdOnBN254.EdOnBN254Point` - // `type SchnorrVerKey is EdOnBN254.EdOnBN254Point;` - - /// @notice Represents a HotShot validator node - /// In the dual-staking model, a HotShot validator could have multiple `Node` entries. - /// @param account The Ethereum account of the validator. - /// @param stakeType The type of token staked. - /// @param balance The amount of token staked. - /// @param registerEpoch The starting epoch for the validator. - /// @param exitEpoch The ending epoch for the validator. - struct Node { - address account; - StakeType stakeType; - uint64 balance; - uint64 registerEpoch; - uint64 exitEpoch; - } - - // === Table State & Stats === - - /// @notice Get the commitment of the stake table used in current voting (i.e. snapshot at - /// the start of last epoch) - function votingStakeTableCommitment() external view returns (bytes32); - /// @notice Get the commitment of the stake table frozen for change (i.g. snapshot at the start - /// of the current epoch) - function frozenStakeTableCommitment() external view returns (bytes32); - - /// @notice Get the total stake of the registered keys in the latest stake table (Head) - function totalStake() external view returns (uint256); - /// @notice Get the total number of stakers, uniquely identified by their `blsVK` - function totalKeys() external view returns (uint32); - /// @notice Get the total stake of the registered keys in the voting stake table - /// (LastEpochStart) - function totalVotingStake() external view returns (uint256); - - /// @notice Look up the balance of `blsVK` - function lookup(BN254.G1Point calldata blsVK) external view returns (uint64); - /// @notice Look up the full `Node` state associated with `blsVK` - function fullLookup(BN254.G1Point calldata blsVK) external view returns (Node memory); - - // === Queuing Stats === - - /// @notice Get the next available epoch for new registration - function nextRegisterationEpoch() external view returns (uint64); - /// @notice Get the number of pending registration requests in the waiting queue - function numPendingRegistrations() external view returns (uint64); - /// @notice Get the next available epoch for exit - function nextExitEpoch() external view returns (uint64); - /// @notice Get the number of pending exit requests in the waiting queue - function numPendingExit() external view returns (uint64); - - // === Write APIs === - - /// @notice Register a validator in the stake table, transfer of tokens incurred! - /// - /// @param blsVK The BLS verification key - /// @param schnorrVK The Schnorr verification key (as the auxiliary info) - /// @param amount The amount to register - /// @param stakeType The type of staking (native or restaking) - /// @param blsSig The BLS signature that authenticates the `blsVK` field - /// @param maxWait The maximum epoch the sender is waiting to wait to be included (cannot be - /// smaller than the current epoch) - /// - /// @return success status - /// - /// @dev No validity check on `schnorrVK`, as it's assumed to be sender's responsibility, - /// the contract only treat it as auxiliary info submitted by `blsVK`. - function register( - BN254.G1Point calldata blsVK, - EdOnBN254.EdOnBN254Point calldata schnorrVK, - uint64 amount, - StakeType stakeType, - bytes calldata blsSig, - uint64 maxWait - ) external returns (bool); - - /// @notice Deposit more stakes to registered keys - /// - /// @param blsVK The BLS verification key - /// @param amount The amount to deposit - /// @return (newBalance, effectiveEpoch) the new balance effective at a future epoch - function depoist(BN254.G1Point calldata blsVK, uint64 amount) - external - returns (uint64, uint64); - - /// @notice Request to exit from the stake table, not immediately withdrawable! - /// - /// @param blsVK The BLS verification key to exit - /// @return success status - function exit(BN254.G1Point calldata blsVK) external returns (bool); - - /// @notice Withdraw from the staking pool. Transfers occur! Only successfully exited keys can - /// withdraw past their `exitEpoch`. - /// - /// @param blsVK The BLS verification key to withdraw - /// @return The total amount withdrawn, equal to `Node.balance` associated with `blsVK` - function withdraw(BN254.G1Point calldata blsVK) external returns (uint64); - - /// @notice Advance to the next epoch, the new `votingStakeTableCommitment` will be - /// `frozenStakeTableCommitment` and the new `frozenStakeTableCommitment` will be - /// `curEpochComm`, - function advanceEpoch(bytes32 curEpochComm) external returns (bool); -} diff --git a/contracts/src/libraries/EdOnBn254.sol b/contracts/src/libraries/EdOnBn254.sol deleted file mode 100644 index c7cfe2b32b..0000000000 --- a/contracts/src/libraries/EdOnBn254.sol +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity ^0.8.0; - -import { Utils } from "bn254/BN254.sol"; - -/// @notice Edward curve on BN254. -/// This library only implements a serialization function that is consistent with -/// Arkworks' format. It does not support any group operations. -library EdOnBN254 { - uint256 public constant P_MOD = - 21888242871839275222246405745257275088548364400416034343698204186575808495617; - - struct EdOnBN254Point { - uint256 x; - uint256 y; - } - - /// @dev Check if y-coordinate of G1 point is negative. - function isYNegative(EdOnBN254Point memory point) internal pure returns (bool) { - return (point.y << 1) < P_MOD; - } - - /// @dev Serialize a point into bytes - function serialize(EdOnBN254Point memory point) internal pure returns (bytes memory res) { - uint256 mask = 0; - // Edward curve does not have an infinity flag. - // Set the 255-th bit to 1 for positive Y - // See: - // https://github.com/arkworks-rs/algebra/blob/d6365c3a0724e5d71322fe19cbdb30f979b064c8/serialize/src/flags.rs#L148 - if (!EdOnBN254.isYNegative(point)) { - mask = 0x8000000000000000000000000000000000000000000000000000000000000000; - } - - return abi.encodePacked(Utils.reverseEndianness(point.x | mask)); - } - - // TODO: (alex) add `validatePoint` methods and tests -} From 8bded3ec87748f4fe57083a4b8cfdbe4ac415981 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Sat, 11 Nov 2023 14:32:27 +0800 Subject: [PATCH 30/38] add stake table interfaces --- contracts/src/interfaces/IStakeTable.sol | 127 +++++++++++++++++++++++ contracts/src/libraries/EdOnBn254.sol | 39 +++++++ 2 files changed, 166 insertions(+) create mode 100644 contracts/src/interfaces/IStakeTable.sol create mode 100644 contracts/src/libraries/EdOnBn254.sol diff --git a/contracts/src/interfaces/IStakeTable.sol b/contracts/src/interfaces/IStakeTable.sol new file mode 100644 index 0000000000..85c7ca3a6f --- /dev/null +++ b/contracts/src/interfaces/IStakeTable.sol @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: Unlicensed + +pragma solidity ^0.8.0; + +import { BN254 } from "bn254/BN254.sol"; +import { EdOnBN254 } from "../libraries/EdOnBn254.sol"; + +/// @title Interface for stake table that keep track of validators' external key and staked amount. +/// @dev Stake delegation happens in a separate DelegationPool contract, and specific to +/// instantiation thus not part of this interface +interface IStakeTable { + /// @notice Supported stake type, either using native token or re-staked using ETH + enum StakeType { + Native, + Restake + } + + /// @dev (sadly, Solidity doesn't support type alias on non-primitive types) + // We avoid declaring another struct even if the type info helps with readability, + // extra layer of struct introduces overhead and more gas cost. + // + /// @dev BLS verification key (used for Consensus voting in HotShot) is `BN254.G1Point`. + // `type BlsVerKey is BN254.G1Point;` + // + /// @dev Verification key of a Schnorr signature is just a `EdOnBN254.EdOnBN254Point` + // `type SchnorrVerKey is EdOnBN254.EdOnBN254Point;` + + /// @notice Represents a HotShot validator node + /// In the dual-staking model, a HotShot validator could have multiple `Node` entries. + /// @param account The Ethereum account of the validator. + /// @param stakeType The type of token staked. + /// @param balance The amount of token staked. + /// @param registerEpoch The starting epoch for the validator. + /// @param exitEpoch The ending epoch for the validator. + struct Node { + address account; + StakeType stakeType; + uint64 balance; + uint64 registerEpoch; + uint64 exitEpoch; + } + + // === Table State & Stats === + + /// @notice Get the commitment of the stake table used in current voting (i.e. snapshot at + /// the start of last epoch) + function votingStakeTableCommitment() external view returns (bytes32); + /// @notice Get the commitment of the stake table frozen for change (i.g. snapshot at the start + /// of the current epoch) + function frozenStakeTableCommitment() external view returns (bytes32); + + /// @notice Get the total stake of the registered keys in the latest stake table (Head) + function totalStake() external view returns (uint256); + /// @notice Get the total number of stakers, uniquely identified by their `blsVK` + function totalKeys() external view returns (uint32); + /// @notice Get the total stake of the registered keys in the voting stake table + /// (LastEpochStart) + function totalVotingStake() external view returns (uint256); + + /// @notice Look up the balance of `blsVK` + function lookup(BN254.G1Point calldata blsVK) external view returns (uint64); + /// @notice Look up the full `Node` state associated with `blsVK` + function fullLookup(BN254.G1Point calldata blsVK) external view returns (Node memory); + + // === Queuing Stats === + + /// @notice Get the next available epoch for new registration + function nextRegisterationEpoch() external view returns (uint64); + /// @notice Get the number of pending registration requests in the waiting queue + function numPendingRegistrations() external view returns (uint64); + /// @notice Get the next available epoch for exit + function nextExitEpoch() external view returns (uint64); + /// @notice Get the number of pending exit requests in the waiting queue + function numPendingExit() external view returns (uint64); + + // === Write APIs === + + /// @notice Register a validator in the stake table, transfer of tokens incurred! + /// + /// @param blsVK The BLS verification key + /// @param schnorrVK The Schnorr verification key (as the auxiliary info) + /// @param amount The amount to register + /// @param stakeType The type of staking (native or restaking) + /// @param blsSig The BLS signature that authenticates the `blsVK` field + /// @param maxWait The maximum epoch the sender is waiting to wait to be included (cannot be + /// smaller than the current epoch) + /// + /// @return success status + /// + /// @dev No validity check on `schnorrVK`, as it's assumed to be sender's responsibility, + /// the contract only treat it as auxiliary info submitted by `blsVK`. + function register( + BN254.G1Point calldata blsVK, + EdOnBN254.EdOnBN254Point calldata schnorrVK, + uint64 amount, + StakeType stakeType, + bytes calldata blsSig, + uint64 maxWait + ) external returns (bool); + + /// @notice Deposit more stakes to registered keys + /// + /// @param blsVK The BLS verification key + /// @param amount The amount to deposit + /// @return (newBalance, effectiveEpoch) the new balance effective at a future epoch + function depoist(BN254.G1Point calldata blsVK, uint64 amount) + external + returns (uint64, uint64); + + /// @notice Request to exit from the stake table, not immediately withdrawable! + /// + /// @param blsVK The BLS verification key to exit + /// @return success status + function exit(BN254.G1Point calldata blsVK) external returns (bool); + + /// @notice Withdraw from the staking pool. Transfers occur! Only successfully exited keys can + /// withdraw past their `exitEpoch`. + /// + /// @param blsVK The BLS verification key to withdraw + /// @return The total amount withdrawn, equal to `Node.balance` associated with `blsVK` + function withdraw(BN254.G1Point calldata blsVK) external returns (uint64); + + /// @notice Advance to the next epoch, the new `votingStakeTableCommitment` will be + /// `frozenStakeTableCommitment` and the new `frozenStakeTableCommitment` will be + /// `curEpochComm`, + function advanceEpoch(bytes32 curEpochComm) external returns (bool); +} diff --git a/contracts/src/libraries/EdOnBn254.sol b/contracts/src/libraries/EdOnBn254.sol new file mode 100644 index 0000000000..c7cfe2b32b --- /dev/null +++ b/contracts/src/libraries/EdOnBn254.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.0; + +import { Utils } from "bn254/BN254.sol"; + +/// @notice Edward curve on BN254. +/// This library only implements a serialization function that is consistent with +/// Arkworks' format. It does not support any group operations. +library EdOnBN254 { + uint256 public constant P_MOD = + 21888242871839275222246405745257275088548364400416034343698204186575808495617; + + struct EdOnBN254Point { + uint256 x; + uint256 y; + } + + /// @dev Check if y-coordinate of G1 point is negative. + function isYNegative(EdOnBN254Point memory point) internal pure returns (bool) { + return (point.y << 1) < P_MOD; + } + + /// @dev Serialize a point into bytes + function serialize(EdOnBN254Point memory point) internal pure returns (bytes memory res) { + uint256 mask = 0; + // Edward curve does not have an infinity flag. + // Set the 255-th bit to 1 for positive Y + // See: + // https://github.com/arkworks-rs/algebra/blob/d6365c3a0724e5d71322fe19cbdb30f979b064c8/serialize/src/flags.rs#L148 + if (!EdOnBN254.isYNegative(point)) { + mask = 0x8000000000000000000000000000000000000000000000000000000000000000; + } + + return abi.encodePacked(Utils.reverseEndianness(point.x | mask)); + } + + // TODO: (alex) add `validatePoint` methods and tests +} From 47aa7813c38e8b4a5b46fb20931924d3f836524e Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Tue, 14 Nov 2023 16:56:32 +0800 Subject: [PATCH 31/38] address comments --- contracts/src/interfaces/IStakeTable.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/src/interfaces/IStakeTable.sol b/contracts/src/interfaces/IStakeTable.sol index 85c7ca3a6f..d48e49ab73 100644 --- a/contracts/src/interfaces/IStakeTable.sol +++ b/contracts/src/interfaces/IStakeTable.sol @@ -32,12 +32,14 @@ interface IStakeTable { /// @param balance The amount of token staked. /// @param registerEpoch The starting epoch for the validator. /// @param exitEpoch The ending epoch for the validator. + /// @param schnorrVK The Schnorr verification key associated. struct Node { address account; StakeType stakeType; uint64 balance; uint64 registerEpoch; uint64 exitEpoch; + EdOnBN254.EdOnBN254Point schnorrVK; } // === Table State & Stats === @@ -103,7 +105,7 @@ interface IStakeTable { /// @param blsVK The BLS verification key /// @param amount The amount to deposit /// @return (newBalance, effectiveEpoch) the new balance effective at a future epoch - function depoist(BN254.G1Point calldata blsVK, uint64 amount) + function deposit(BN254.G1Point calldata blsVK, uint64 amount) external returns (uint64, uint64); From 8e857eb9df7deb9d60b23eff43e51b06d325ebb4 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Wed, 15 Nov 2023 14:00:47 +0800 Subject: [PATCH 32/38] update totalStake() return types --- contracts/src/interfaces/IStakeTable.sol | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contracts/src/interfaces/IStakeTable.sol b/contracts/src/interfaces/IStakeTable.sol index d48e49ab73..05ea573247 100644 --- a/contracts/src/interfaces/IStakeTable.sol +++ b/contracts/src/interfaces/IStakeTable.sol @@ -51,8 +51,9 @@ interface IStakeTable { /// of the current epoch) function frozenStakeTableCommitment() external view returns (bytes32); - /// @notice Get the total stake of the registered keys in the latest stake table (Head) - function totalStake() external view returns (uint256); + /// @notice Get the total stakes of the registered keys in the latest stake table (Head). + /// @return The total stake for native token and restaked token respectively. + function totalStake() external view returns (uint256, uint256); /// @notice Get the total number of stakers, uniquely identified by their `blsVK` function totalKeys() external view returns (uint32); /// @notice Get the total stake of the registered keys in the voting stake table From 36fb30e1cd3967441551f5ea50ab58fa46fff460 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Thu, 16 Nov 2023 12:01:47 +0800 Subject: [PATCH 33/38] update contract-bindings --- contract-bindings/src/ed_on_bn254.rs | 171 +++ contract-bindings/src/i_stake_table.rs | 1370 ++++++++++++++++++++++++ contract-bindings/src/lib.rs | 2 + 3 files changed, 1543 insertions(+) create mode 100644 contract-bindings/src/ed_on_bn254.rs create mode 100644 contract-bindings/src/i_stake_table.rs diff --git a/contract-bindings/src/ed_on_bn254.rs b/contract-bindings/src/ed_on_bn254.rs new file mode 100644 index 0000000000..5c12e453d9 --- /dev/null +++ b/contract-bindings/src/ed_on_bn254.rs @@ -0,0 +1,171 @@ +pub use ed_on_bn254::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod ed_on_bn254 { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([( + ::std::borrow::ToOwned::to_owned("P_MOD"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("P_MOD"), + inputs: ::std::vec![], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(256usize,), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + )]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static EDONBN254_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = + ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\xA6a\08`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14`+WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\x046\x10`3W`\x005`\xE0\x1C\x80c\x1Dq.'\x14`8W[`\0\x80\xFD[`^\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\x01\x81V[`@Q\x90\x81R` \x01`@Q\x80\x91\x03\x90\xF3\xFE\xA2dipfsX\"\x12 \xCA\xEC>\x0F\xDD\xCC\x97\x7F\xE8\xF8\xD5hZ\x98\xCA\x8A#{1\xFA\xF2V\x98\xAB\xD5\xD1e\x16l\x83Y\xF3dsolcC\0\x08\x14\x003"; + /// The bytecode of the contract. + pub static EDONBN254_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__BYTECODE); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\x046\x10`3W`\x005`\xE0\x1C\x80c\x1Dq.'\x14`8W[`\0\x80\xFD[`^\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\x01\x81V[`@Q\x90\x81R` \x01`@Q\x80\x91\x03\x90\xF3\xFE\xA2dipfsX\"\x12 \xCA\xEC>\x0F\xDD\xCC\x97\x7F\xE8\xF8\xD5hZ\x98\xCA\x8A#{1\xFA\xF2V\x98\xAB\xD5\xD1e\x16l\x83Y\xF3dsolcC\0\x08\x14\x003"; + /// The deployed bytecode of the contract. + pub static EDONBN254_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); + pub struct EdOnBN254(::ethers::contract::Contract); + impl ::core::clone::Clone for EdOnBN254 { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for EdOnBN254 { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for EdOnBN254 { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for EdOnBN254 { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(EdOnBN254)) + .field(&self.address()) + .finish() + } + } + impl EdOnBN254 { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + EDONBN254_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. + /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + EDONBN254_ABI.clone(), + EDONBN254_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `P_MOD` (0x1d712e27) function + pub fn p_mod( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([29, 113, 46, 39], ()) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> for EdOnBN254 { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `P_MOD` function with signature `P_MOD()` and selector `0x1d712e27` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "P_MOD", abi = "P_MOD()")] + pub struct PModCall; + ///Container type for all return fields from the `P_MOD` function with signature `P_MOD()` and selector `0x1d712e27` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct PModReturn(pub ::ethers::core::types::U256); +} diff --git a/contract-bindings/src/i_stake_table.rs b/contract-bindings/src/i_stake_table.rs new file mode 100644 index 0000000000..35d4ac2278 --- /dev/null +++ b/contract-bindings/src/i_stake_table.rs @@ -0,0 +1,1370 @@ +pub use i_stake_table::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod i_stake_table { + pub use super::super::shared_types::*; + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("advanceEpoch"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("advanceEpoch"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("curEpochComm"), + kind: ::ethers::core::abi::ethabi::ParamType::FixedBytes(32usize,), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bytes32"), + ), + },], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("deposit"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("deposit"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("blsVK"), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct BN254.G1Point"), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("amount"), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(64usize), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint64"), + ), + }, + ], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(64usize), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint64"), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(64usize), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint64"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("exit"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("exit"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("blsVK"), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct BN254.G1Point"), + ), + },], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("frozenStakeTableCommitment"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("frozenStakeTableCommitment",), + inputs: ::std::vec![], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::FixedBytes(32usize,), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bytes32"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("fullLookup"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("fullLookup"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("blsVK"), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct BN254.G1Point"), + ), + },], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Address, + ::ethers::core::abi::ethabi::ParamType::Uint(8usize), + ::ethers::core::abi::ethabi::ParamType::Uint(64usize), + ::ethers::core::abi::ethabi::ParamType::Uint(64usize), + ::ethers::core::abi::ethabi::ParamType::Uint(64usize), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct IStakeTable.Node"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("lookup"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("lookup"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("blsVK"), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct BN254.G1Point"), + ), + },], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(64usize), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint64"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("nextExitEpoch"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("nextExitEpoch"), + inputs: ::std::vec![], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(64usize), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint64"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("nextRegisterationEpoch"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("nextRegisterationEpoch",), + inputs: ::std::vec![], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(64usize), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint64"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("numPendingExit"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("numPendingExit"), + inputs: ::std::vec![], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(64usize), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint64"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("numPendingRegistrations"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("numPendingRegistrations",), + inputs: ::std::vec![], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(64usize), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint64"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("register"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("register"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("blsVK"), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct BN254.G1Point"), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("schnorrVK"), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned( + "struct EdOnBN254.EdOnBN254Point", + ), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("amount"), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(64usize), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint64"), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("stakeType"), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(8usize), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("enum IStakeTable.StakeType",), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("blsSig"), + kind: ::ethers::core::abi::ethabi::ParamType::Bytes, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bytes"), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("maxWait"), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(64usize), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint64"), + ), + }, + ], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("totalKeys"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("totalKeys"), + inputs: ::std::vec![], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(32usize), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint32"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("totalStake"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("totalStake"), + inputs: ::std::vec![], + outputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(256usize,), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(256usize,), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + }, + ], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("totalVotingStake"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("totalVotingStake"), + inputs: ::std::vec![], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(256usize,), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("votingStakeTableCommitment"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("votingStakeTableCommitment",), + inputs: ::std::vec![], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::FixedBytes(32usize,), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bytes32"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("withdraw"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("withdraw"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("blsVK"), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct BN254.G1Point"), + ), + },], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(64usize), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint64"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::std::collections::BTreeMap::new(), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static ISTAKETABLE_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = + ::ethers::contract::Lazy::new(__abi); + pub struct IStakeTable(::ethers::contract::Contract); + impl ::core::clone::Clone for IStakeTable { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for IStakeTable { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for IStakeTable { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for IStakeTable { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(IStakeTable)) + .field(&self.address()) + .finish() + } + } + impl IStakeTable { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + ISTAKETABLE_ABI.clone(), + client, + )) + } + ///Calls the contract's `advanceEpoch` (0x3808f4df) function + pub fn advance_epoch( + &self, + cur_epoch_comm: [u8; 32], + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([56, 8, 244, 223], cur_epoch_comm) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `deposit` (0xf7bfb01c) function + pub fn deposit( + &self, + bls_vk: G1Point, + amount: u64, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([247, 191, 176, 28], (bls_vk, amount)) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `exit` (0xd1543893) function + pub fn exit(&self, bls_vk: G1Point) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([209, 84, 56, 147], (bls_vk,)) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `frozenStakeTableCommitment` (0x382b215a) function + pub fn frozen_stake_table_commitment( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([56, 43, 33, 90], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `fullLookup` (0x8d98af20) function + pub fn full_lookup( + &self, + bls_vk: G1Point, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([141, 152, 175, 32], (bls_vk,)) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `lookup` (0x28e25b51) function + pub fn lookup( + &self, + bls_vk: G1Point, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([40, 226, 91, 81], (bls_vk,)) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `nextExitEpoch` (0x3b09c267) function + pub fn next_exit_epoch(&self) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([59, 9, 194, 103], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `nextRegisterationEpoch` (0x4942a4e6) function + pub fn next_registeration_epoch( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([73, 66, 164, 230], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `numPendingExit` (0xbf8248dd) function + pub fn num_pending_exit(&self) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([191, 130, 72, 221], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `numPendingRegistrations` (0x16fefed7) function + pub fn num_pending_registrations( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([22, 254, 254, 215], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `register` (0x096fbae3) function + pub fn register( + &self, + bls_vk: G1Point, + schnorr_vk: EdOnBN254Point, + amount: u64, + stake_type: u8, + bls_sig: ::ethers::core::types::Bytes, + max_wait: u64, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash( + [9, 111, 186, 227], + (bls_vk, schnorr_vk, amount, stake_type, bls_sig, max_wait), + ) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `totalKeys` (0x488bdabc) function + pub fn total_keys(&self) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([72, 139, 218, 188], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `totalStake` (0x8b0e9f3f) function + pub fn total_stake( + &self, + ) -> ::ethers::contract::builders::ContractCall< + M, + (::ethers::core::types::U256, ::ethers::core::types::U256), + > { + self.0 + .method_hash([139, 14, 159, 63], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `totalVotingStake` (0x4317d00b) function + pub fn total_voting_stake( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([67, 23, 208, 11], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `votingStakeTableCommitment` (0x76b6b7cb) function + pub fn voting_stake_table_commitment( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([118, 182, 183, 203], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `withdraw` (0x0d075e27) function + pub fn withdraw( + &self, + bls_vk: G1Point, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([13, 7, 94, 39], (bls_vk,)) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> for IStakeTable { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Container type for all input parameters for the `advanceEpoch` function with signature `advanceEpoch(bytes32)` and selector `0x3808f4df` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "advanceEpoch", abi = "advanceEpoch(bytes32)")] + pub struct AdvanceEpochCall { + pub cur_epoch_comm: [u8; 32], + } + ///Container type for all input parameters for the `deposit` function with signature `deposit((uint256,uint256),uint64)` and selector `0xf7bfb01c` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "deposit", abi = "deposit((uint256,uint256),uint64)")] + pub struct DepositCall { + pub bls_vk: G1Point, + pub amount: u64, + } + ///Container type for all input parameters for the `exit` function with signature `exit((uint256,uint256))` and selector `0xd1543893` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "exit", abi = "exit((uint256,uint256))")] + pub struct ExitCall { + pub bls_vk: G1Point, + } + ///Container type for all input parameters for the `frozenStakeTableCommitment` function with signature `frozenStakeTableCommitment()` and selector `0x382b215a` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall( + name = "frozenStakeTableCommitment", + abi = "frozenStakeTableCommitment()" + )] + pub struct FrozenStakeTableCommitmentCall; + ///Container type for all input parameters for the `fullLookup` function with signature `fullLookup((uint256,uint256))` and selector `0x8d98af20` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "fullLookup", abi = "fullLookup((uint256,uint256))")] + pub struct FullLookupCall { + pub bls_vk: G1Point, + } + ///Container type for all input parameters for the `lookup` function with signature `lookup((uint256,uint256))` and selector `0x28e25b51` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "lookup", abi = "lookup((uint256,uint256))")] + pub struct LookupCall { + pub bls_vk: G1Point, + } + ///Container type for all input parameters for the `nextExitEpoch` function with signature `nextExitEpoch()` and selector `0x3b09c267` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "nextExitEpoch", abi = "nextExitEpoch()")] + pub struct NextExitEpochCall; + ///Container type for all input parameters for the `nextRegisterationEpoch` function with signature `nextRegisterationEpoch()` and selector `0x4942a4e6` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "nextRegisterationEpoch", abi = "nextRegisterationEpoch()")] + pub struct NextRegisterationEpochCall; + ///Container type for all input parameters for the `numPendingExit` function with signature `numPendingExit()` and selector `0xbf8248dd` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "numPendingExit", abi = "numPendingExit()")] + pub struct NumPendingExitCall; + ///Container type for all input parameters for the `numPendingRegistrations` function with signature `numPendingRegistrations()` and selector `0x16fefed7` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "numPendingRegistrations", abi = "numPendingRegistrations()")] + pub struct NumPendingRegistrationsCall; + ///Container type for all input parameters for the `register` function with signature `register((uint256,uint256),(uint256,uint256),uint64,uint8,bytes,uint64)` and selector `0x096fbae3` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall( + name = "register", + abi = "register((uint256,uint256),(uint256,uint256),uint64,uint8,bytes,uint64)" + )] + pub struct RegisterCall { + pub bls_vk: G1Point, + pub schnorr_vk: EdOnBN254Point, + pub amount: u64, + pub stake_type: u8, + pub bls_sig: ::ethers::core::types::Bytes, + pub max_wait: u64, + } + ///Container type for all input parameters for the `totalKeys` function with signature `totalKeys()` and selector `0x488bdabc` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "totalKeys", abi = "totalKeys()")] + pub struct TotalKeysCall; + ///Container type for all input parameters for the `totalStake` function with signature `totalStake()` and selector `0x8b0e9f3f` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "totalStake", abi = "totalStake()")] + pub struct TotalStakeCall; + ///Container type for all input parameters for the `totalVotingStake` function with signature `totalVotingStake()` and selector `0x4317d00b` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "totalVotingStake", abi = "totalVotingStake()")] + pub struct TotalVotingStakeCall; + ///Container type for all input parameters for the `votingStakeTableCommitment` function with signature `votingStakeTableCommitment()` and selector `0x76b6b7cb` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall( + name = "votingStakeTableCommitment", + abi = "votingStakeTableCommitment()" + )] + pub struct VotingStakeTableCommitmentCall; + ///Container type for all input parameters for the `withdraw` function with signature `withdraw((uint256,uint256))` and selector `0x0d075e27` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "withdraw", abi = "withdraw((uint256,uint256))")] + pub struct WithdrawCall { + pub bls_vk: G1Point, + } + ///Container type for all of the contract's call + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] + pub enum IStakeTableCalls { + AdvanceEpoch(AdvanceEpochCall), + Deposit(DepositCall), + Exit(ExitCall), + FrozenStakeTableCommitment(FrozenStakeTableCommitmentCall), + FullLookup(FullLookupCall), + Lookup(LookupCall), + NextExitEpoch(NextExitEpochCall), + NextRegisterationEpoch(NextRegisterationEpochCall), + NumPendingExit(NumPendingExitCall), + NumPendingRegistrations(NumPendingRegistrationsCall), + Register(RegisterCall), + TotalKeys(TotalKeysCall), + TotalStake(TotalStakeCall), + TotalVotingStake(TotalVotingStakeCall), + VotingStakeTableCommitment(VotingStakeTableCommitmentCall), + Withdraw(WithdrawCall), + } + impl ::ethers::core::abi::AbiDecode for IStakeTableCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) = ::decode(data) + { + return Ok(Self::AdvanceEpoch(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::Deposit(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::Exit(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::FrozenStakeTableCommitment(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::FullLookup(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::Lookup(decoded)); + } + if let Ok(decoded) = ::decode(data) + { + return Ok(Self::NextExitEpoch(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::NextRegisterationEpoch(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::NumPendingExit(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::NumPendingRegistrations(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::Register(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::TotalKeys(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::TotalStake(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::TotalVotingStake(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::VotingStakeTableCommitment(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::Withdraw(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for IStakeTableCalls { + fn encode(self) -> Vec { + match self { + Self::AdvanceEpoch(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Deposit(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Exit(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::FrozenStakeTableCommitment(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::FullLookup(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Lookup(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::NextExitEpoch(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::NextRegisterationEpoch(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::NumPendingExit(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::NumPendingRegistrations(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Register(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::TotalKeys(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::TotalStake(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::TotalVotingStake(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::VotingStakeTableCommitment(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::Withdraw(element) => ::ethers::core::abi::AbiEncode::encode(element), + } + } + } + impl ::core::fmt::Display for IStakeTableCalls { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::AdvanceEpoch(element) => ::core::fmt::Display::fmt(element, f), + Self::Deposit(element) => ::core::fmt::Display::fmt(element, f), + Self::Exit(element) => ::core::fmt::Display::fmt(element, f), + Self::FrozenStakeTableCommitment(element) => ::core::fmt::Display::fmt(element, f), + Self::FullLookup(element) => ::core::fmt::Display::fmt(element, f), + Self::Lookup(element) => ::core::fmt::Display::fmt(element, f), + Self::NextExitEpoch(element) => ::core::fmt::Display::fmt(element, f), + Self::NextRegisterationEpoch(element) => ::core::fmt::Display::fmt(element, f), + Self::NumPendingExit(element) => ::core::fmt::Display::fmt(element, f), + Self::NumPendingRegistrations(element) => ::core::fmt::Display::fmt(element, f), + Self::Register(element) => ::core::fmt::Display::fmt(element, f), + Self::TotalKeys(element) => ::core::fmt::Display::fmt(element, f), + Self::TotalStake(element) => ::core::fmt::Display::fmt(element, f), + Self::TotalVotingStake(element) => ::core::fmt::Display::fmt(element, f), + Self::VotingStakeTableCommitment(element) => ::core::fmt::Display::fmt(element, f), + Self::Withdraw(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for IStakeTableCalls { + fn from(value: AdvanceEpochCall) -> Self { + Self::AdvanceEpoch(value) + } + } + impl ::core::convert::From for IStakeTableCalls { + fn from(value: DepositCall) -> Self { + Self::Deposit(value) + } + } + impl ::core::convert::From for IStakeTableCalls { + fn from(value: ExitCall) -> Self { + Self::Exit(value) + } + } + impl ::core::convert::From for IStakeTableCalls { + fn from(value: FrozenStakeTableCommitmentCall) -> Self { + Self::FrozenStakeTableCommitment(value) + } + } + impl ::core::convert::From for IStakeTableCalls { + fn from(value: FullLookupCall) -> Self { + Self::FullLookup(value) + } + } + impl ::core::convert::From for IStakeTableCalls { + fn from(value: LookupCall) -> Self { + Self::Lookup(value) + } + } + impl ::core::convert::From for IStakeTableCalls { + fn from(value: NextExitEpochCall) -> Self { + Self::NextExitEpoch(value) + } + } + impl ::core::convert::From for IStakeTableCalls { + fn from(value: NextRegisterationEpochCall) -> Self { + Self::NextRegisterationEpoch(value) + } + } + impl ::core::convert::From for IStakeTableCalls { + fn from(value: NumPendingExitCall) -> Self { + Self::NumPendingExit(value) + } + } + impl ::core::convert::From for IStakeTableCalls { + fn from(value: NumPendingRegistrationsCall) -> Self { + Self::NumPendingRegistrations(value) + } + } + impl ::core::convert::From for IStakeTableCalls { + fn from(value: RegisterCall) -> Self { + Self::Register(value) + } + } + impl ::core::convert::From for IStakeTableCalls { + fn from(value: TotalKeysCall) -> Self { + Self::TotalKeys(value) + } + } + impl ::core::convert::From for IStakeTableCalls { + fn from(value: TotalStakeCall) -> Self { + Self::TotalStake(value) + } + } + impl ::core::convert::From for IStakeTableCalls { + fn from(value: TotalVotingStakeCall) -> Self { + Self::TotalVotingStake(value) + } + } + impl ::core::convert::From for IStakeTableCalls { + fn from(value: VotingStakeTableCommitmentCall) -> Self { + Self::VotingStakeTableCommitment(value) + } + } + impl ::core::convert::From for IStakeTableCalls { + fn from(value: WithdrawCall) -> Self { + Self::Withdraw(value) + } + } + ///Container type for all return fields from the `advanceEpoch` function with signature `advanceEpoch(bytes32)` and selector `0x3808f4df` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct AdvanceEpochReturn(pub bool); + ///Container type for all return fields from the `deposit` function with signature `deposit((uint256,uint256),uint64)` and selector `0xf7bfb01c` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct DepositReturn(pub u64, pub u64); + ///Container type for all return fields from the `exit` function with signature `exit((uint256,uint256))` and selector `0xd1543893` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct ExitReturn(pub bool); + ///Container type for all return fields from the `frozenStakeTableCommitment` function with signature `frozenStakeTableCommitment()` and selector `0x382b215a` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct FrozenStakeTableCommitmentReturn(pub [u8; 32]); + ///Container type for all return fields from the `fullLookup` function with signature `fullLookup((uint256,uint256))` and selector `0x8d98af20` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct FullLookupReturn(pub Node); + ///Container type for all return fields from the `lookup` function with signature `lookup((uint256,uint256))` and selector `0x28e25b51` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct LookupReturn(pub u64); + ///Container type for all return fields from the `nextExitEpoch` function with signature `nextExitEpoch()` and selector `0x3b09c267` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct NextExitEpochReturn(pub u64); + ///Container type for all return fields from the `nextRegisterationEpoch` function with signature `nextRegisterationEpoch()` and selector `0x4942a4e6` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct NextRegisterationEpochReturn(pub u64); + ///Container type for all return fields from the `numPendingExit` function with signature `numPendingExit()` and selector `0xbf8248dd` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct NumPendingExitReturn(pub u64); + ///Container type for all return fields from the `numPendingRegistrations` function with signature `numPendingRegistrations()` and selector `0x16fefed7` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct NumPendingRegistrationsReturn(pub u64); + ///Container type for all return fields from the `register` function with signature `register((uint256,uint256),(uint256,uint256),uint64,uint8,bytes,uint64)` and selector `0x096fbae3` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct RegisterReturn(pub bool); + ///Container type for all return fields from the `totalKeys` function with signature `totalKeys()` and selector `0x488bdabc` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct TotalKeysReturn(pub u32); + ///Container type for all return fields from the `totalStake` function with signature `totalStake()` and selector `0x8b0e9f3f` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct TotalStakeReturn( + pub ::ethers::core::types::U256, + pub ::ethers::core::types::U256, + ); + ///Container type for all return fields from the `totalVotingStake` function with signature `totalVotingStake()` and selector `0x4317d00b` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct TotalVotingStakeReturn(pub ::ethers::core::types::U256); + ///Container type for all return fields from the `votingStakeTableCommitment` function with signature `votingStakeTableCommitment()` and selector `0x76b6b7cb` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct VotingStakeTableCommitmentReturn(pub [u8; 32]); + ///Container type for all return fields from the `withdraw` function with signature `withdraw((uint256,uint256))` and selector `0x0d075e27` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct WithdrawReturn(pub u64); + ///`EdOnBN254Point(uint256,uint256)` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct EdOnBN254Point { + pub x: ::ethers::core::types::U256, + pub y: ::ethers::core::types::U256, + } + ///`Node(address,uint8,uint64,uint64,uint64,(uint256,uint256))` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct Node { + pub account: ::ethers::core::types::Address, + pub stake_type: u8, + pub balance: u64, + pub register_epoch: u64, + pub exit_epoch: u64, + pub schnorr_vk: EdOnBN254Point, + } +} diff --git a/contract-bindings/src/lib.rs b/contract-bindings/src/lib.rs index d06782d5f6..48d92fda28 100644 --- a/contract-bindings/src/lib.rs +++ b/contract-bindings/src/lib.rs @@ -9,8 +9,10 @@ pub mod bn254; pub mod bn256g2; pub mod bytes_lib; pub mod deploy_hot_shot; +pub mod ed_on_bn254; pub mod hot_shot; pub mod i_plonk_verifier; +pub mod i_stake_table; pub mod plonk_verifier; pub mod polynomial_eval; pub mod shared_types; From cfb6471affa62c697cf03066b17a62dfd20f816a Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Thu, 16 Nov 2023 13:20:24 +0800 Subject: [PATCH 34/38] address comments --- contract-bindings/src/i_stake_table.rs | 57 ++++++++++-------------- contracts/src/interfaces/IStakeTable.sol | 4 +- 2 files changed, 25 insertions(+), 36 deletions(-) diff --git a/contract-bindings/src/i_stake_table.rs b/contract-bindings/src/i_stake_table.rs index 35d4ac2278..0c91a16468 100644 --- a/contract-bindings/src/i_stake_table.rs +++ b/contract-bindings/src/i_stake_table.rs @@ -199,9 +199,9 @@ pub mod i_stake_table { },], ), ( - ::std::borrow::ToOwned::to_owned("nextRegisterationEpoch"), + ::std::borrow::ToOwned::to_owned("nextRegistrationEpoch"), ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("nextRegisterationEpoch",), + name: ::std::borrow::ToOwned::to_owned("nextRegistrationEpoch",), inputs: ::std::vec![], outputs: ::std::vec![::ethers::core::abi::ethabi::Param { name: ::std::string::String::new(), @@ -287,13 +287,6 @@ pub mod i_stake_table { ::std::borrow::ToOwned::to_owned("enum IStakeTable.StakeType",), ), }, - ::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("blsSig"), - kind: ::ethers::core::abi::ethabi::ParamType::Bytes, - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("bytes"), - ), - }, ::ethers::core::abi::ethabi::Param { name: ::std::borrow::ToOwned::to_owned("maxWait"), kind: ::ethers::core::abi::ethabi::ParamType::Uint(64usize), @@ -515,12 +508,12 @@ pub mod i_stake_table { .method_hash([59, 9, 194, 103], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `nextRegisterationEpoch` (0x4942a4e6) function - pub fn next_registeration_epoch( + ///Calls the contract's `nextRegistrationEpoch` (0x2c530584) function + pub fn next_registration_epoch( &self, ) -> ::ethers::contract::builders::ContractCall { self.0 - .method_hash([73, 66, 164, 230], ()) + .method_hash([44, 83, 5, 132], ()) .expect("method not found (this should never happen)") } ///Calls the contract's `numPendingExit` (0xbf8248dd) function @@ -537,20 +530,19 @@ pub mod i_stake_table { .method_hash([22, 254, 254, 215], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `register` (0x096fbae3) function + ///Calls the contract's `register` (0x7b04b626) function pub fn register( &self, bls_vk: G1Point, schnorr_vk: EdOnBN254Point, amount: u64, stake_type: u8, - bls_sig: ::ethers::core::types::Bytes, max_wait: u64, ) -> ::ethers::contract::builders::ContractCall { self.0 .method_hash( - [9, 111, 186, 227], - (bls_vk, schnorr_vk, amount, stake_type, bls_sig, max_wait), + [123, 4, 182, 38], + (bls_vk, schnorr_vk, amount, stake_type, max_wait), ) .expect("method not found (this should never happen)") } @@ -721,7 +713,7 @@ pub mod i_stake_table { )] #[ethcall(name = "nextExitEpoch", abi = "nextExitEpoch()")] pub struct NextExitEpochCall; - ///Container type for all input parameters for the `nextRegisterationEpoch` function with signature `nextRegisterationEpoch()` and selector `0x4942a4e6` + ///Container type for all input parameters for the `nextRegistrationEpoch` function with signature `nextRegistrationEpoch()` and selector `0x2c530584` #[derive( Clone, ::ethers::contract::EthCall, @@ -734,8 +726,8 @@ pub mod i_stake_table { Eq, Hash, )] - #[ethcall(name = "nextRegisterationEpoch", abi = "nextRegisterationEpoch()")] - pub struct NextRegisterationEpochCall; + #[ethcall(name = "nextRegistrationEpoch", abi = "nextRegistrationEpoch()")] + pub struct NextRegistrationEpochCall; ///Container type for all input parameters for the `numPendingExit` function with signature `numPendingExit()` and selector `0xbf8248dd` #[derive( Clone, @@ -766,7 +758,7 @@ pub mod i_stake_table { )] #[ethcall(name = "numPendingRegistrations", abi = "numPendingRegistrations()")] pub struct NumPendingRegistrationsCall; - ///Container type for all input parameters for the `register` function with signature `register((uint256,uint256),(uint256,uint256),uint64,uint8,bytes,uint64)` and selector `0x096fbae3` + ///Container type for all input parameters for the `register` function with signature `register((uint256,uint256),(uint256,uint256),uint64,uint8,uint64)` and selector `0x7b04b626` #[derive( Clone, ::ethers::contract::EthCall, @@ -781,14 +773,13 @@ pub mod i_stake_table { )] #[ethcall( name = "register", - abi = "register((uint256,uint256),(uint256,uint256),uint64,uint8,bytes,uint64)" + abi = "register((uint256,uint256),(uint256,uint256),uint64,uint8,uint64)" )] pub struct RegisterCall { pub bls_vk: G1Point, pub schnorr_vk: EdOnBN254Point, pub amount: u64, pub stake_type: u8, - pub bls_sig: ::ethers::core::types::Bytes, pub max_wait: u64, } ///Container type for all input parameters for the `totalKeys` function with signature `totalKeys()` and selector `0x488bdabc` @@ -890,7 +881,7 @@ pub mod i_stake_table { FullLookup(FullLookupCall), Lookup(LookupCall), NextExitEpoch(NextExitEpochCall), - NextRegisterationEpoch(NextRegisterationEpochCall), + NextRegistrationEpoch(NextRegistrationEpochCall), NumPendingExit(NumPendingExitCall), NumPendingRegistrations(NumPendingRegistrationsCall), Register(RegisterCall), @@ -931,9 +922,9 @@ pub mod i_stake_table { return Ok(Self::NextExitEpoch(decoded)); } if let Ok(decoded) = - ::decode(data) + ::decode(data) { - return Ok(Self::NextRegisterationEpoch(decoded)); + return Ok(Self::NextRegistrationEpoch(decoded)); } if let Ok(decoded) = ::decode(data) @@ -982,7 +973,7 @@ pub mod i_stake_table { Self::FullLookup(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::Lookup(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::NextExitEpoch(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::NextRegisterationEpoch(element) => { + Self::NextRegistrationEpoch(element) => { ::ethers::core::abi::AbiEncode::encode(element) } Self::NumPendingExit(element) => ::ethers::core::abi::AbiEncode::encode(element), @@ -1010,7 +1001,7 @@ pub mod i_stake_table { Self::FullLookup(element) => ::core::fmt::Display::fmt(element, f), Self::Lookup(element) => ::core::fmt::Display::fmt(element, f), Self::NextExitEpoch(element) => ::core::fmt::Display::fmt(element, f), - Self::NextRegisterationEpoch(element) => ::core::fmt::Display::fmt(element, f), + Self::NextRegistrationEpoch(element) => ::core::fmt::Display::fmt(element, f), Self::NumPendingExit(element) => ::core::fmt::Display::fmt(element, f), Self::NumPendingRegistrations(element) => ::core::fmt::Display::fmt(element, f), Self::Register(element) => ::core::fmt::Display::fmt(element, f), @@ -1057,9 +1048,9 @@ pub mod i_stake_table { Self::NextExitEpoch(value) } } - impl ::core::convert::From for IStakeTableCalls { - fn from(value: NextRegisterationEpochCall) -> Self { - Self::NextRegisterationEpoch(value) + impl ::core::convert::From for IStakeTableCalls { + fn from(value: NextRegistrationEpochCall) -> Self { + Self::NextRegistrationEpoch(value) } } impl ::core::convert::From for IStakeTableCalls { @@ -1200,7 +1191,7 @@ pub mod i_stake_table { Hash, )] pub struct NextExitEpochReturn(pub u64); - ///Container type for all return fields from the `nextRegisterationEpoch` function with signature `nextRegisterationEpoch()` and selector `0x4942a4e6` + ///Container type for all return fields from the `nextRegistrationEpoch` function with signature `nextRegistrationEpoch()` and selector `0x2c530584` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1213,7 +1204,7 @@ pub mod i_stake_table { Eq, Hash, )] - pub struct NextRegisterationEpochReturn(pub u64); + pub struct NextRegistrationEpochReturn(pub u64); ///Container type for all return fields from the `numPendingExit` function with signature `numPendingExit()` and selector `0xbf8248dd` #[derive( Clone, @@ -1242,7 +1233,7 @@ pub mod i_stake_table { Hash, )] pub struct NumPendingRegistrationsReturn(pub u64); - ///Container type for all return fields from the `register` function with signature `register((uint256,uint256),(uint256,uint256),uint64,uint8,bytes,uint64)` and selector `0x096fbae3` + ///Container type for all return fields from the `register` function with signature `register((uint256,uint256),(uint256,uint256),uint64,uint8,uint64)` and selector `0x7b04b626` #[derive( Clone, ::ethers::contract::EthAbiType, diff --git a/contracts/src/interfaces/IStakeTable.sol b/contracts/src/interfaces/IStakeTable.sol index 05ea573247..cf16a090d4 100644 --- a/contracts/src/interfaces/IStakeTable.sol +++ b/contracts/src/interfaces/IStakeTable.sol @@ -68,7 +68,7 @@ interface IStakeTable { // === Queuing Stats === /// @notice Get the next available epoch for new registration - function nextRegisterationEpoch() external view returns (uint64); + function nextRegistrationEpoch() external view returns (uint64); /// @notice Get the number of pending registration requests in the waiting queue function numPendingRegistrations() external view returns (uint64); /// @notice Get the next available epoch for exit @@ -84,7 +84,6 @@ interface IStakeTable { /// @param schnorrVK The Schnorr verification key (as the auxiliary info) /// @param amount The amount to register /// @param stakeType The type of staking (native or restaking) - /// @param blsSig The BLS signature that authenticates the `blsVK` field /// @param maxWait The maximum epoch the sender is waiting to wait to be included (cannot be /// smaller than the current epoch) /// @@ -97,7 +96,6 @@ interface IStakeTable { EdOnBN254.EdOnBN254Point calldata schnorrVK, uint64 amount, StakeType stakeType, - bytes calldata blsSig, uint64 maxWait ) external returns (bool); From 65a87d0b981f90a204a7ba399e1741653d9f1295 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 17 Nov 2023 20:44:43 +0800 Subject: [PATCH 35/38] more comments --- contract-bindings/src/i_stake_table.rs | 387 ++++++----------------- contracts/src/interfaces/IStakeTable.sol | 25 +- 2 files changed, 104 insertions(+), 308 deletions(-) diff --git a/contract-bindings/src/i_stake_table.rs b/contract-bindings/src/i_stake_table.rs index 0c91a16468..eb1d5fac30 100644 --- a/contract-bindings/src/i_stake_table.rs +++ b/contract-bindings/src/i_stake_table.rs @@ -16,28 +16,6 @@ pub mod i_stake_table { ::ethers::core::abi::ethabi::Contract { constructor: ::core::option::Option::None, functions: ::core::convert::From::from([ - ( - ::std::borrow::ToOwned::to_owned("advanceEpoch"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("advanceEpoch"), - inputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("curEpochComm"), - kind: ::ethers::core::abi::ethabi::ParamType::FixedBytes(32usize,), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("bytes32"), - ), - },], - outputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::string::String::new(), - kind: ::ethers::core::abi::ethabi::ParamType::Bool, - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("bool"), - ), - },], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, - },], - ), ( ::std::borrow::ToOwned::to_owned("deposit"), ::std::vec![::ethers::core::abi::ethabi::Function { @@ -81,47 +59,6 @@ pub mod i_stake_table { state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, },], ), - ( - ::std::borrow::ToOwned::to_owned("exit"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("exit"), - inputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("blsVK"), - kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("struct BN254.G1Point"), - ), - },], - outputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::string::String::new(), - kind: ::ethers::core::abi::ethabi::ParamType::Bool, - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("bool"), - ), - },], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, - },], - ), - ( - ::std::borrow::ToOwned::to_owned("frozenStakeTableCommitment"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("frozenStakeTableCommitment",), - inputs: ::std::vec![], - outputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::string::String::new(), - kind: ::ethers::core::abi::ethabi::ParamType::FixedBytes(32usize,), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("bytes32"), - ), - },], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, - },], - ), ( ::std::borrow::ToOwned::to_owned("fullLookup"), ::std::vec![::ethers::core::abi::ethabi::Function { @@ -288,7 +225,14 @@ pub mod i_stake_table { ), }, ::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("maxWait"), + name: ::std::borrow::ToOwned::to_owned("blsSig"), + kind: ::ethers::core::abi::ethabi::ParamType::Bytes, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bytes"), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("validUntilEpoch"), kind: ::ethers::core::abi::ethabi::ParamType::Uint(64usize), internal_type: ::core::option::Option::Some( ::std::borrow::ToOwned::to_owned("uint64"), @@ -306,6 +250,31 @@ pub mod i_stake_table { state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, },], ), + ( + ::std::borrow::ToOwned::to_owned("requestExit"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("requestExit"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("blsVK"), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct BN254.G1Point"), + ), + },], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + ), ( ::std::borrow::ToOwned::to_owned("totalKeys"), ::std::vec![::ethers::core::abi::ethabi::Function { @@ -363,22 +332,6 @@ pub mod i_stake_table { state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, },], ), - ( - ::std::borrow::ToOwned::to_owned("votingStakeTableCommitment"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("votingStakeTableCommitment",), - inputs: ::std::vec![], - outputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::string::String::new(), - kind: ::ethers::core::abi::ethabi::ParamType::FixedBytes(32usize,), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("bytes32"), - ), - },], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, - },], - ), ( ::std::borrow::ToOwned::to_owned("withdraw"), ::std::vec![::ethers::core::abi::ethabi::Function { @@ -451,15 +404,6 @@ pub mod i_stake_table { client, )) } - ///Calls the contract's `advanceEpoch` (0x3808f4df) function - pub fn advance_epoch( - &self, - cur_epoch_comm: [u8; 32], - ) -> ::ethers::contract::builders::ContractCall { - self.0 - .method_hash([56, 8, 244, 223], cur_epoch_comm) - .expect("method not found (this should never happen)") - } ///Calls the contract's `deposit` (0xf7bfb01c) function pub fn deposit( &self, @@ -470,20 +414,6 @@ pub mod i_stake_table { .method_hash([247, 191, 176, 28], (bls_vk, amount)) .expect("method not found (this should never happen)") } - ///Calls the contract's `exit` (0xd1543893) function - pub fn exit(&self, bls_vk: G1Point) -> ::ethers::contract::builders::ContractCall { - self.0 - .method_hash([209, 84, 56, 147], (bls_vk,)) - .expect("method not found (this should never happen)") - } - ///Calls the contract's `frozenStakeTableCommitment` (0x382b215a) function - pub fn frozen_stake_table_commitment( - &self, - ) -> ::ethers::contract::builders::ContractCall { - self.0 - .method_hash([56, 43, 33, 90], ()) - .expect("method not found (this should never happen)") - } ///Calls the contract's `fullLookup` (0x8d98af20) function pub fn full_lookup( &self, @@ -530,22 +460,39 @@ pub mod i_stake_table { .method_hash([22, 254, 254, 215], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `register` (0x7b04b626) function + ///Calls the contract's `register` (0x096fbae3) function pub fn register( &self, bls_vk: G1Point, schnorr_vk: EdOnBN254Point, amount: u64, stake_type: u8, - max_wait: u64, + bls_sig: ::ethers::core::types::Bytes, + valid_until_epoch: u64, ) -> ::ethers::contract::builders::ContractCall { self.0 .method_hash( - [123, 4, 182, 38], - (bls_vk, schnorr_vk, amount, stake_type, max_wait), + [9, 111, 186, 227], + ( + bls_vk, + schnorr_vk, + amount, + stake_type, + bls_sig, + valid_until_epoch, + ), ) .expect("method not found (this should never happen)") } + ///Calls the contract's `requestExit` (0xd4b83f45) function + pub fn request_exit( + &self, + bls_vk: G1Point, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([212, 184, 63, 69], (bls_vk,)) + .expect("method not found (this should never happen)") + } ///Calls the contract's `totalKeys` (0x488bdabc) function pub fn total_keys(&self) -> ::ethers::contract::builders::ContractCall { self.0 @@ -571,14 +518,6 @@ pub mod i_stake_table { .method_hash([67, 23, 208, 11], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `votingStakeTableCommitment` (0x76b6b7cb) function - pub fn voting_stake_table_commitment( - &self, - ) -> ::ethers::contract::builders::ContractCall { - self.0 - .method_hash([118, 182, 183, 203], ()) - .expect("method not found (this should never happen)") - } ///Calls the contract's `withdraw` (0x0d075e27) function pub fn withdraw( &self, @@ -594,23 +533,6 @@ pub mod i_stake_table { Self::new(contract.address(), contract.client()) } } - ///Container type for all input parameters for the `advanceEpoch` function with signature `advanceEpoch(bytes32)` and selector `0x3808f4df` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall(name = "advanceEpoch", abi = "advanceEpoch(bytes32)")] - pub struct AdvanceEpochCall { - pub cur_epoch_comm: [u8; 32], - } ///Container type for all input parameters for the `deposit` function with signature `deposit((uint256,uint256),uint64)` and selector `0xf7bfb01c` #[derive( Clone, @@ -629,41 +551,6 @@ pub mod i_stake_table { pub bls_vk: G1Point, pub amount: u64, } - ///Container type for all input parameters for the `exit` function with signature `exit((uint256,uint256))` and selector `0xd1543893` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall(name = "exit", abi = "exit((uint256,uint256))")] - pub struct ExitCall { - pub bls_vk: G1Point, - } - ///Container type for all input parameters for the `frozenStakeTableCommitment` function with signature `frozenStakeTableCommitment()` and selector `0x382b215a` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall( - name = "frozenStakeTableCommitment", - abi = "frozenStakeTableCommitment()" - )] - pub struct FrozenStakeTableCommitmentCall; ///Container type for all input parameters for the `fullLookup` function with signature `fullLookup((uint256,uint256))` and selector `0x8d98af20` #[derive( Clone, @@ -758,7 +645,7 @@ pub mod i_stake_table { )] #[ethcall(name = "numPendingRegistrations", abi = "numPendingRegistrations()")] pub struct NumPendingRegistrationsCall; - ///Container type for all input parameters for the `register` function with signature `register((uint256,uint256),(uint256,uint256),uint64,uint8,uint64)` and selector `0x7b04b626` + ///Container type for all input parameters for the `register` function with signature `register((uint256,uint256),(uint256,uint256),uint64,uint8,bytes,uint64)` and selector `0x096fbae3` #[derive( Clone, ::ethers::contract::EthCall, @@ -773,16 +660,17 @@ pub mod i_stake_table { )] #[ethcall( name = "register", - abi = "register((uint256,uint256),(uint256,uint256),uint64,uint8,uint64)" + abi = "register((uint256,uint256),(uint256,uint256),uint64,uint8,bytes,uint64)" )] pub struct RegisterCall { pub bls_vk: G1Point, pub schnorr_vk: EdOnBN254Point, pub amount: u64, pub stake_type: u8, - pub max_wait: u64, + pub bls_sig: ::ethers::core::types::Bytes, + pub valid_until_epoch: u64, } - ///Container type for all input parameters for the `totalKeys` function with signature `totalKeys()` and selector `0x488bdabc` + ///Container type for all input parameters for the `requestExit` function with signature `requestExit((uint256,uint256))` and selector `0xd4b83f45` #[derive( Clone, ::ethers::contract::EthCall, @@ -795,9 +683,11 @@ pub mod i_stake_table { Eq, Hash, )] - #[ethcall(name = "totalKeys", abi = "totalKeys()")] - pub struct TotalKeysCall; - ///Container type for all input parameters for the `totalStake` function with signature `totalStake()` and selector `0x8b0e9f3f` + #[ethcall(name = "requestExit", abi = "requestExit((uint256,uint256))")] + pub struct RequestExitCall { + pub bls_vk: G1Point, + } + ///Container type for all input parameters for the `totalKeys` function with signature `totalKeys()` and selector `0x488bdabc` #[derive( Clone, ::ethers::contract::EthCall, @@ -810,9 +700,9 @@ pub mod i_stake_table { Eq, Hash, )] - #[ethcall(name = "totalStake", abi = "totalStake()")] - pub struct TotalStakeCall; - ///Container type for all input parameters for the `totalVotingStake` function with signature `totalVotingStake()` and selector `0x4317d00b` + #[ethcall(name = "totalKeys", abi = "totalKeys()")] + pub struct TotalKeysCall; + ///Container type for all input parameters for the `totalStake` function with signature `totalStake()` and selector `0x8b0e9f3f` #[derive( Clone, ::ethers::contract::EthCall, @@ -825,9 +715,9 @@ pub mod i_stake_table { Eq, Hash, )] - #[ethcall(name = "totalVotingStake", abi = "totalVotingStake()")] - pub struct TotalVotingStakeCall; - ///Container type for all input parameters for the `votingStakeTableCommitment` function with signature `votingStakeTableCommitment()` and selector `0x76b6b7cb` + #[ethcall(name = "totalStake", abi = "totalStake()")] + pub struct TotalStakeCall; + ///Container type for all input parameters for the `totalVotingStake` function with signature `totalVotingStake()` and selector `0x4317d00b` #[derive( Clone, ::ethers::contract::EthCall, @@ -840,11 +730,8 @@ pub mod i_stake_table { Eq, Hash, )] - #[ethcall( - name = "votingStakeTableCommitment", - abi = "votingStakeTableCommitment()" - )] - pub struct VotingStakeTableCommitmentCall; + #[ethcall(name = "totalVotingStake", abi = "totalVotingStake()")] + pub struct TotalVotingStakeCall; ///Container type for all input parameters for the `withdraw` function with signature `withdraw((uint256,uint256))` and selector `0x0d075e27` #[derive( Clone, @@ -874,10 +761,7 @@ pub mod i_stake_table { Hash, )] pub enum IStakeTableCalls { - AdvanceEpoch(AdvanceEpochCall), Deposit(DepositCall), - Exit(ExitCall), - FrozenStakeTableCommitment(FrozenStakeTableCommitmentCall), FullLookup(FullLookupCall), Lookup(LookupCall), NextExitEpoch(NextExitEpochCall), @@ -885,10 +769,10 @@ pub mod i_stake_table { NumPendingExit(NumPendingExitCall), NumPendingRegistrations(NumPendingRegistrationsCall), Register(RegisterCall), + RequestExit(RequestExitCall), TotalKeys(TotalKeysCall), TotalStake(TotalStakeCall), TotalVotingStake(TotalVotingStakeCall), - VotingStakeTableCommitment(VotingStakeTableCommitmentCall), Withdraw(WithdrawCall), } impl ::ethers::core::abi::AbiDecode for IStakeTableCalls { @@ -896,21 +780,9 @@ pub mod i_stake_table { data: impl AsRef<[u8]>, ) -> ::core::result::Result { let data = data.as_ref(); - if let Ok(decoded) = ::decode(data) - { - return Ok(Self::AdvanceEpoch(decoded)); - } if let Ok(decoded) = ::decode(data) { return Ok(Self::Deposit(decoded)); } - if let Ok(decoded) = ::decode(data) { - return Ok(Self::Exit(decoded)); - } - if let Ok(decoded) = - ::decode(data) - { - return Ok(Self::FrozenStakeTableCommitment(decoded)); - } if let Ok(decoded) = ::decode(data) { return Ok(Self::FullLookup(decoded)); } @@ -939,6 +811,9 @@ pub mod i_stake_table { if let Ok(decoded) = ::decode(data) { return Ok(Self::Register(decoded)); } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::RequestExit(decoded)); + } if let Ok(decoded) = ::decode(data) { return Ok(Self::TotalKeys(decoded)); } @@ -950,11 +825,6 @@ pub mod i_stake_table { { return Ok(Self::TotalVotingStake(decoded)); } - if let Ok(decoded) = - ::decode(data) - { - return Ok(Self::VotingStakeTableCommitment(decoded)); - } if let Ok(decoded) = ::decode(data) { return Ok(Self::Withdraw(decoded)); } @@ -964,12 +834,7 @@ pub mod i_stake_table { impl ::ethers::core::abi::AbiEncode for IStakeTableCalls { fn encode(self) -> Vec { match self { - Self::AdvanceEpoch(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::Deposit(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::Exit(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::FrozenStakeTableCommitment(element) => { - ::ethers::core::abi::AbiEncode::encode(element) - } Self::FullLookup(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::Lookup(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::NextExitEpoch(element) => ::ethers::core::abi::AbiEncode::encode(element), @@ -981,12 +846,10 @@ pub mod i_stake_table { ::ethers::core::abi::AbiEncode::encode(element) } Self::Register(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::RequestExit(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::TotalKeys(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::TotalStake(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::TotalVotingStake(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::VotingStakeTableCommitment(element) => { - ::ethers::core::abi::AbiEncode::encode(element) - } Self::Withdraw(element) => ::ethers::core::abi::AbiEncode::encode(element), } } @@ -994,10 +857,7 @@ pub mod i_stake_table { impl ::core::fmt::Display for IStakeTableCalls { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { match self { - Self::AdvanceEpoch(element) => ::core::fmt::Display::fmt(element, f), Self::Deposit(element) => ::core::fmt::Display::fmt(element, f), - Self::Exit(element) => ::core::fmt::Display::fmt(element, f), - Self::FrozenStakeTableCommitment(element) => ::core::fmt::Display::fmt(element, f), Self::FullLookup(element) => ::core::fmt::Display::fmt(element, f), Self::Lookup(element) => ::core::fmt::Display::fmt(element, f), Self::NextExitEpoch(element) => ::core::fmt::Display::fmt(element, f), @@ -1005,34 +865,19 @@ pub mod i_stake_table { Self::NumPendingExit(element) => ::core::fmt::Display::fmt(element, f), Self::NumPendingRegistrations(element) => ::core::fmt::Display::fmt(element, f), Self::Register(element) => ::core::fmt::Display::fmt(element, f), + Self::RequestExit(element) => ::core::fmt::Display::fmt(element, f), Self::TotalKeys(element) => ::core::fmt::Display::fmt(element, f), Self::TotalStake(element) => ::core::fmt::Display::fmt(element, f), Self::TotalVotingStake(element) => ::core::fmt::Display::fmt(element, f), - Self::VotingStakeTableCommitment(element) => ::core::fmt::Display::fmt(element, f), Self::Withdraw(element) => ::core::fmt::Display::fmt(element, f), } } } - impl ::core::convert::From for IStakeTableCalls { - fn from(value: AdvanceEpochCall) -> Self { - Self::AdvanceEpoch(value) - } - } impl ::core::convert::From for IStakeTableCalls { fn from(value: DepositCall) -> Self { Self::Deposit(value) } } - impl ::core::convert::From for IStakeTableCalls { - fn from(value: ExitCall) -> Self { - Self::Exit(value) - } - } - impl ::core::convert::From for IStakeTableCalls { - fn from(value: FrozenStakeTableCommitmentCall) -> Self { - Self::FrozenStakeTableCommitment(value) - } - } impl ::core::convert::From for IStakeTableCalls { fn from(value: FullLookupCall) -> Self { Self::FullLookup(value) @@ -1068,6 +913,11 @@ pub mod i_stake_table { Self::Register(value) } } + impl ::core::convert::From for IStakeTableCalls { + fn from(value: RequestExitCall) -> Self { + Self::RequestExit(value) + } + } impl ::core::convert::From for IStakeTableCalls { fn from(value: TotalKeysCall) -> Self { Self::TotalKeys(value) @@ -1083,30 +933,11 @@ pub mod i_stake_table { Self::TotalVotingStake(value) } } - impl ::core::convert::From for IStakeTableCalls { - fn from(value: VotingStakeTableCommitmentCall) -> Self { - Self::VotingStakeTableCommitment(value) - } - } impl ::core::convert::From for IStakeTableCalls { fn from(value: WithdrawCall) -> Self { Self::Withdraw(value) } } - ///Container type for all return fields from the `advanceEpoch` function with signature `advanceEpoch(bytes32)` and selector `0x3808f4df` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct AdvanceEpochReturn(pub bool); ///Container type for all return fields from the `deposit` function with signature `deposit((uint256,uint256),uint64)` and selector `0xf7bfb01c` #[derive( Clone, @@ -1121,34 +952,6 @@ pub mod i_stake_table { Hash, )] pub struct DepositReturn(pub u64, pub u64); - ///Container type for all return fields from the `exit` function with signature `exit((uint256,uint256))` and selector `0xd1543893` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct ExitReturn(pub bool); - ///Container type for all return fields from the `frozenStakeTableCommitment` function with signature `frozenStakeTableCommitment()` and selector `0x382b215a` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct FrozenStakeTableCommitmentReturn(pub [u8; 32]); ///Container type for all return fields from the `fullLookup` function with signature `fullLookup((uint256,uint256))` and selector `0x8d98af20` #[derive( Clone, @@ -1233,7 +1036,7 @@ pub mod i_stake_table { Hash, )] pub struct NumPendingRegistrationsReturn(pub u64); - ///Container type for all return fields from the `register` function with signature `register((uint256,uint256),(uint256,uint256),uint64,uint8,uint64)` and selector `0x7b04b626` + ///Container type for all return fields from the `register` function with signature `register((uint256,uint256),(uint256,uint256),uint64,uint8,bytes,uint64)` and selector `0x096fbae3` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1247,7 +1050,7 @@ pub mod i_stake_table { Hash, )] pub struct RegisterReturn(pub bool); - ///Container type for all return fields from the `totalKeys` function with signature `totalKeys()` and selector `0x488bdabc` + ///Container type for all return fields from the `requestExit` function with signature `requestExit((uint256,uint256))` and selector `0xd4b83f45` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1260,8 +1063,8 @@ pub mod i_stake_table { Eq, Hash, )] - pub struct TotalKeysReturn(pub u32); - ///Container type for all return fields from the `totalStake` function with signature `totalStake()` and selector `0x8b0e9f3f` + pub struct RequestExitReturn(pub bool); + ///Container type for all return fields from the `totalKeys` function with signature `totalKeys()` and selector `0x488bdabc` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1274,11 +1077,8 @@ pub mod i_stake_table { Eq, Hash, )] - pub struct TotalStakeReturn( - pub ::ethers::core::types::U256, - pub ::ethers::core::types::U256, - ); - ///Container type for all return fields from the `totalVotingStake` function with signature `totalVotingStake()` and selector `0x4317d00b` + pub struct TotalKeysReturn(pub u32); + ///Container type for all return fields from the `totalStake` function with signature `totalStake()` and selector `0x8b0e9f3f` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1291,8 +1091,11 @@ pub mod i_stake_table { Eq, Hash, )] - pub struct TotalVotingStakeReturn(pub ::ethers::core::types::U256); - ///Container type for all return fields from the `votingStakeTableCommitment` function with signature `votingStakeTableCommitment()` and selector `0x76b6b7cb` + pub struct TotalStakeReturn( + pub ::ethers::core::types::U256, + pub ::ethers::core::types::U256, + ); + ///Container type for all return fields from the `totalVotingStake` function with signature `totalVotingStake()` and selector `0x4317d00b` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1305,7 +1108,7 @@ pub mod i_stake_table { Eq, Hash, )] - pub struct VotingStakeTableCommitmentReturn(pub [u8; 32]); + pub struct TotalVotingStakeReturn(pub ::ethers::core::types::U256); ///Container type for all return fields from the `withdraw` function with signature `withdraw((uint256,uint256))` and selector `0x0d075e27` #[derive( Clone, diff --git a/contracts/src/interfaces/IStakeTable.sol b/contracts/src/interfaces/IStakeTable.sol index cf16a090d4..521d2440df 100644 --- a/contracts/src/interfaces/IStakeTable.sol +++ b/contracts/src/interfaces/IStakeTable.sol @@ -8,6 +8,8 @@ import { EdOnBN254 } from "../libraries/EdOnBn254.sol"; /// @title Interface for stake table that keep track of validators' external key and staked amount. /// @dev Stake delegation happens in a separate DelegationPool contract, and specific to /// instantiation thus not part of this interface +/// @dev Stake table contract should store a reference to the `LightClient.sol` to query +/// "epoch-related" info interface IStakeTable { /// @notice Supported stake type, either using native token or re-staked using ETH enum StakeType { @@ -44,13 +46,6 @@ interface IStakeTable { // === Table State & Stats === - /// @notice Get the commitment of the stake table used in current voting (i.e. snapshot at - /// the start of last epoch) - function votingStakeTableCommitment() external view returns (bytes32); - /// @notice Get the commitment of the stake table frozen for change (i.g. snapshot at the start - /// of the current epoch) - function frozenStakeTableCommitment() external view returns (bytes32); - /// @notice Get the total stakes of the registered keys in the latest stake table (Head). /// @return The total stake for native token and restaked token respectively. function totalStake() external view returns (uint256, uint256); @@ -84,19 +79,22 @@ interface IStakeTable { /// @param schnorrVK The Schnorr verification key (as the auxiliary info) /// @param amount The amount to register /// @param stakeType The type of staking (native or restaking) - /// @param maxWait The maximum epoch the sender is waiting to wait to be included (cannot be - /// smaller than the current epoch) + /// @param blsSig The BLS signature that authenticates the `blsVK` field + /// @param validUntilEpoch The maximum epoch the sender is willing to wait to be included + /// (cannot be smaller than the current epoch) /// /// @return success status /// /// @dev No validity check on `schnorrVK`, as it's assumed to be sender's responsibility, /// the contract only treat it as auxiliary info submitted by `blsVK`. + /// @dev `blsSig` field is necessary to prevent "rogue public-key attack". function register( BN254.G1Point calldata blsVK, EdOnBN254.EdOnBN254Point calldata schnorrVK, uint64 amount, StakeType stakeType, - uint64 maxWait + bytes calldata blsSig, + uint64 validUntilEpoch ) external returns (bool); /// @notice Deposit more stakes to registered keys @@ -112,7 +110,7 @@ interface IStakeTable { /// /// @param blsVK The BLS verification key to exit /// @return success status - function exit(BN254.G1Point calldata blsVK) external returns (bool); + function requestExit(BN254.G1Point calldata blsVK) external returns (bool); /// @notice Withdraw from the staking pool. Transfers occur! Only successfully exited keys can /// withdraw past their `exitEpoch`. @@ -120,9 +118,4 @@ interface IStakeTable { /// @param blsVK The BLS verification key to withdraw /// @return The total amount withdrawn, equal to `Node.balance` associated with `blsVK` function withdraw(BN254.G1Point calldata blsVK) external returns (uint64); - - /// @notice Advance to the next epoch, the new `votingStakeTableCommitment` will be - /// `frozenStakeTableCommitment` and the new `frozenStakeTableCommitment` will be - /// `curEpochComm`, - function advanceEpoch(bytes32 curEpochComm) external returns (bool); } From 8ff8e8d77fb6eebd42fd313f36fab14add4b423d Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 17 Nov 2023 20:55:26 +0800 Subject: [PATCH 36/38] withdraw->withdrawFunds more explicit name --- contract-bindings/src/i_stake_table.rs | 37 ++++++++++++------------ contracts/src/interfaces/IStakeTable.sol | 2 +- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/contract-bindings/src/i_stake_table.rs b/contract-bindings/src/i_stake_table.rs index eb1d5fac30..d03f1f7fa5 100644 --- a/contract-bindings/src/i_stake_table.rs +++ b/contract-bindings/src/i_stake_table.rs @@ -333,9 +333,9 @@ pub mod i_stake_table { },], ), ( - ::std::borrow::ToOwned::to_owned("withdraw"), + ::std::borrow::ToOwned::to_owned("withdrawFunds"), ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("withdraw"), + name: ::std::borrow::ToOwned::to_owned("withdrawFunds"), inputs: ::std::vec![::ethers::core::abi::ethabi::Param { name: ::std::borrow::ToOwned::to_owned("blsVK"), kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ @@ -518,13 +518,13 @@ pub mod i_stake_table { .method_hash([67, 23, 208, 11], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `withdraw` (0x0d075e27) function - pub fn withdraw( + ///Calls the contract's `withdrawFunds` (0x162d4e7c) function + pub fn withdraw_funds( &self, bls_vk: G1Point, ) -> ::ethers::contract::builders::ContractCall { self.0 - .method_hash([13, 7, 94, 39], (bls_vk,)) + .method_hash([22, 45, 78, 124], (bls_vk,)) .expect("method not found (this should never happen)") } } @@ -732,7 +732,7 @@ pub mod i_stake_table { )] #[ethcall(name = "totalVotingStake", abi = "totalVotingStake()")] pub struct TotalVotingStakeCall; - ///Container type for all input parameters for the `withdraw` function with signature `withdraw((uint256,uint256))` and selector `0x0d075e27` + ///Container type for all input parameters for the `withdrawFunds` function with signature `withdrawFunds((uint256,uint256))` and selector `0x162d4e7c` #[derive( Clone, ::ethers::contract::EthCall, @@ -745,8 +745,8 @@ pub mod i_stake_table { Eq, Hash, )] - #[ethcall(name = "withdraw", abi = "withdraw((uint256,uint256))")] - pub struct WithdrawCall { + #[ethcall(name = "withdrawFunds", abi = "withdrawFunds((uint256,uint256))")] + pub struct WithdrawFundsCall { pub bls_vk: G1Point, } ///Container type for all of the contract's call @@ -773,7 +773,7 @@ pub mod i_stake_table { TotalKeys(TotalKeysCall), TotalStake(TotalStakeCall), TotalVotingStake(TotalVotingStakeCall), - Withdraw(WithdrawCall), + WithdrawFunds(WithdrawFundsCall), } impl ::ethers::core::abi::AbiDecode for IStakeTableCalls { fn decode( @@ -825,8 +825,9 @@ pub mod i_stake_table { { return Ok(Self::TotalVotingStake(decoded)); } - if let Ok(decoded) = ::decode(data) { - return Ok(Self::Withdraw(decoded)); + if let Ok(decoded) = ::decode(data) + { + return Ok(Self::WithdrawFunds(decoded)); } Err(::ethers::core::abi::Error::InvalidData.into()) } @@ -850,7 +851,7 @@ pub mod i_stake_table { Self::TotalKeys(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::TotalStake(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::TotalVotingStake(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::Withdraw(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::WithdrawFunds(element) => ::ethers::core::abi::AbiEncode::encode(element), } } } @@ -869,7 +870,7 @@ pub mod i_stake_table { Self::TotalKeys(element) => ::core::fmt::Display::fmt(element, f), Self::TotalStake(element) => ::core::fmt::Display::fmt(element, f), Self::TotalVotingStake(element) => ::core::fmt::Display::fmt(element, f), - Self::Withdraw(element) => ::core::fmt::Display::fmt(element, f), + Self::WithdrawFunds(element) => ::core::fmt::Display::fmt(element, f), } } } @@ -933,9 +934,9 @@ pub mod i_stake_table { Self::TotalVotingStake(value) } } - impl ::core::convert::From for IStakeTableCalls { - fn from(value: WithdrawCall) -> Self { - Self::Withdraw(value) + impl ::core::convert::From for IStakeTableCalls { + fn from(value: WithdrawFundsCall) -> Self { + Self::WithdrawFunds(value) } } ///Container type for all return fields from the `deposit` function with signature `deposit((uint256,uint256),uint64)` and selector `0xf7bfb01c` @@ -1109,7 +1110,7 @@ pub mod i_stake_table { Hash, )] pub struct TotalVotingStakeReturn(pub ::ethers::core::types::U256); - ///Container type for all return fields from the `withdraw` function with signature `withdraw((uint256,uint256))` and selector `0x0d075e27` + ///Container type for all return fields from the `withdrawFunds` function with signature `withdrawFunds((uint256,uint256))` and selector `0x162d4e7c` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1122,7 +1123,7 @@ pub mod i_stake_table { Eq, Hash, )] - pub struct WithdrawReturn(pub u64); + pub struct WithdrawFundsReturn(pub u64); ///`EdOnBN254Point(uint256,uint256)` #[derive( Clone, diff --git a/contracts/src/interfaces/IStakeTable.sol b/contracts/src/interfaces/IStakeTable.sol index 521d2440df..a0d2d37992 100644 --- a/contracts/src/interfaces/IStakeTable.sol +++ b/contracts/src/interfaces/IStakeTable.sol @@ -117,5 +117,5 @@ interface IStakeTable { /// /// @param blsVK The BLS verification key to withdraw /// @return The total amount withdrawn, equal to `Node.balance` associated with `blsVK` - function withdraw(BN254.G1Point calldata blsVK) external returns (uint64); + function withdrawFunds(BN254.G1Point calldata blsVK) external returns (uint64); } From c83ebbeb984d8d22fbe434d691c91b89e58d8a88 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 17 Nov 2023 21:19:45 +0800 Subject: [PATCH 37/38] revert flake.nix formatting --- flake.nix | 191 +++++++++++++++++++++++++++--------------------------- 1 file changed, 96 insertions(+), 95 deletions(-) diff --git a/flake.nix b/flake.nix index a6c4a81733..1602758c14 100644 --- a/flake.nix +++ b/flake.nix @@ -18,13 +18,11 @@ inputs.fenix.url = "github:nix-community/fenix"; inputs.fenix.inputs.nixpkgs.follows = "nixpkgs"; - inputs.nixpkgs-cross-overlay.url = - "github:alekseysidorov/nixpkgs-cross-overlay"; + inputs.nixpkgs-cross-overlay.url = "github:alekseysidorov/nixpkgs-cross-overlay"; inputs.flake-utils.url = "github:numtide/flake-utils"; - inputs.foundry.url = - "github:shazow/foundry.nix/monthly"; # Use monthly branch for permanent releases + inputs.foundry.url = "github:shazow/foundry.nix/monthly"; # Use monthly branch for permanent releases inputs.solc-bin.url = "github:EspressoSystems/nix-solc-bin"; inputs.flake-compat.url = "github:edolstra/flake-compat"; @@ -32,8 +30,8 @@ inputs.pre-commit-hooks.url = "github:cachix/pre-commit-hooks.nix"; - outputs = { self, nixpkgs, rust-overlay, nixpkgs-cross-overlay, flake-utils - , pre-commit-hooks, fenix, foundry, solc-bin, ... }: + + outputs = { self, nixpkgs, rust-overlay, nixpkgs-cross-overlay, flake-utils, pre-commit-hooks, fenix, foundry, solc-bin, ... }: flake-utils.lib.eachDefaultSystem (system: let # node=error: disable noisy anvil output @@ -63,27 +61,27 @@ foundry.overlay solc-bin.overlays.default (final: prev: { - solhint = - solhintPkg { inherit (prev) buildNpmPackage fetchFromGitHub; }; + solhint = solhintPkg { inherit (prev) buildNpmPackage fetchFromGitHub; }; }) ]; - pkgs = import nixpkgs { inherit system overlays; }; + pkgs = import nixpkgs { + inherit system overlays; + }; crossShell = { config }: let localSystem = system; - crossSystem = { - inherit config; - useLLVM = true; - isStatic = true; - }; + crossSystem = { inherit config; useLLVM = true; isStatic = true; }; pkgs = import "${nixpkgs-cross-overlay}/utils/nixpkgs.nix" { inherit overlays localSystem crossSystem; }; - in import ./cross-shell.nix { + in + import ./cross-shell.nix { inherit pkgs; inherit RUST_LOG RUST_BACKTRACE RUSTFLAGS CARGO_TARGET_DIR; }; - in with pkgs; { + in + with pkgs; + { checks = { pre-commit-check = pre-commit-hooks.lib.${system}.run { src = ./.; @@ -112,8 +110,7 @@ cargo-clippy = { enable = true; description = "Run clippy"; - entry = - "cargo clippy --workspace --all-features --all-targets -- -D warnings"; + entry = "cargo clippy --workspace --all-features --all-targets -- -D warnings"; types_or = [ "rust" "toml" ]; pass_filenames = false; }; @@ -149,81 +146,85 @@ }; }; }; - devShells.default = let - stableToolchain = pkgs.rust-bin.stable.latest.minimal.override { - extensions = [ "rustfmt" "clippy" "llvm-tools-preview" "rust-src" ]; - }; - # nixWithFlakes allows pre v2.4 nix installations to use - # flake commands (like `nix flake update`) - nixWithFlakes = pkgs.writeShellScriptBin "nix" '' - exec ${pkgs.nixFlakes}/bin/nix --experimental-features "nix-command flakes" "$@" - ''; - solc = pkgs.solc-bin.latest; - in mkShell { - buildInputs = [ - # Rust dependencies - pkg-config - openssl - curl - protobuf # to compile libp2p-autonat - stableToolchain - - # Rust tools - cargo-audit - cargo-edit - cargo-sort - just - fenix.packages.${system}.rust-analyzer - - # Tools - nixWithFlakes - nixpkgs-fmt - entr - - # Figures - graphviz - plantuml - coreutils - - # Ethereum contracts, solidity, ... - foundry-bin - solc - nodePackages.prettier - solhint - (python3.withPackages (ps: with ps; [ black ])) - - ] ++ lib.optionals stdenv.isDarwin - [ darwin.apple_sdk.frameworks.SystemConfiguration ] - ++ lib.optionals (!stdenv.isDarwin) [ cargo-watch ] # broken on OSX - ; - shellHook = '' - # Prevent cargo aliases from using programs in `~/.cargo` to avoid conflicts - # with rustup installations. - export CARGO_HOME=$HOME/.cargo-nix - export PATH="$PWD/$CARGO_TARGET_DIR/release:$PATH" - '' + self.checks.${system}.pre-commit-check.shellHook; - RUST_SRC_PATH = "${stableToolchain}/lib/rustlib/src/rust/library"; - FOUNDRY_SOLC = "${solc}/bin/solc"; - inherit RUST_LOG RUST_BACKTRACE RUSTFLAGS CARGO_TARGET_DIR; - }; - devShells.crossShell = - crossShell { config = "x86_64-unknown-linux-musl"; }; - devShells.armCrossShell = - crossShell { config = "aarch64-unknown-linux-musl"; }; - devShells.rustShell = let - stableToolchain = pkgs.rust-bin.stable.latest.minimal.override { - extensions = [ "rustfmt" "clippy" "llvm-tools-preview" "rust-src" ]; - }; - in mkShell { - buildInputs = [ - # Rust dependencies - pkg-config - openssl - curl - protobuf # to compile libp2p-autonat - stableToolchain - ]; - inherit RUST_LOG RUST_BACKTRACE RUSTFLAGS CARGO_TARGET_DIR; - }; - }); + devShells.default = + let + stableToolchain = pkgs.rust-bin.stable.latest.minimal.override { + extensions = [ "rustfmt" "clippy" "llvm-tools-preview" "rust-src" ]; + }; + # nixWithFlakes allows pre v2.4 nix installations to use + # flake commands (like `nix flake update`) + nixWithFlakes = pkgs.writeShellScriptBin "nix" '' + exec ${pkgs.nixFlakes}/bin/nix --experimental-features "nix-command flakes" "$@" + ''; + solc = pkgs.solc-bin.latest; + in + mkShell + { + buildInputs = [ + # Rust dependencies + pkg-config + openssl + curl + protobuf # to compile libp2p-autonat + stableToolchain + + # Rust tools + cargo-audit + cargo-edit + cargo-sort + just + fenix.packages.${system}.rust-analyzer + + # Tools + nixWithFlakes + nixpkgs-fmt + entr + + # Figures + graphviz + plantuml + coreutils + + # Ethereum contracts, solidity, ... + foundry-bin + solc + nodePackages.prettier + solhint + (python3.withPackages (ps: with ps; [ black ])) + + ] ++ lib.optionals stdenv.isDarwin [ darwin.apple_sdk.frameworks.SystemConfiguration ] + ++ lib.optionals (!stdenv.isDarwin) [ cargo-watch ] # broken on OSX + ; + shellHook = '' + # Prevent cargo aliases from using programs in `~/.cargo` to avoid conflicts + # with rustup installations. + export CARGO_HOME=$HOME/.cargo-nix + export PATH="$PWD/$CARGO_TARGET_DIR/release:$PATH" + '' + self.checks.${system}.pre-commit-check.shellHook; + RUST_SRC_PATH = "${stableToolchain}/lib/rustlib/src/rust/library"; + FOUNDRY_SOLC = "${solc}/bin/solc"; + inherit RUST_LOG RUST_BACKTRACE RUSTFLAGS CARGO_TARGET_DIR; + }; + devShells.crossShell = crossShell { config = "x86_64-unknown-linux-musl"; }; + devShells.armCrossShell = crossShell { config = "aarch64-unknown-linux-musl"; }; + devShells.rustShell = + let + stableToolchain = pkgs.rust-bin.stable.latest.minimal.override { + extensions = [ "rustfmt" "clippy" "llvm-tools-preview" "rust-src" ]; + }; + in + mkShell + { + buildInputs = [ + # Rust dependencies + pkg-config + openssl + curl + protobuf # to compile libp2p-autonat + stableToolchain + ]; + inherit RUST_LOG RUST_BACKTRACE RUSTFLAGS CARGO_TARGET_DIR; + }; + } + ); } From 612a5787aa1ab5d81c73765aa22de498c06a3f23 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 17 Nov 2023 22:25:18 +0800 Subject: [PATCH 38/38] more explict fn names --- contract-bindings/src/i_stake_table.rs | 72 ++++++++++++------------ contracts/src/interfaces/IStakeTable.sol | 4 +- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/contract-bindings/src/i_stake_table.rs b/contract-bindings/src/i_stake_table.rs index d03f1f7fa5..efdaeb4563 100644 --- a/contract-bindings/src/i_stake_table.rs +++ b/contract-bindings/src/i_stake_table.rs @@ -60,9 +60,9 @@ pub mod i_stake_table { },], ), ( - ::std::borrow::ToOwned::to_owned("fullLookup"), + ::std::borrow::ToOwned::to_owned("lookupNode"), ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("fullLookup"), + name: ::std::borrow::ToOwned::to_owned("lookupNode"), inputs: ::std::vec![::ethers::core::abi::ethabi::Param { name: ::std::borrow::ToOwned::to_owned("blsVK"), kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ @@ -95,9 +95,9 @@ pub mod i_stake_table { },], ), ( - ::std::borrow::ToOwned::to_owned("lookup"), + ::std::borrow::ToOwned::to_owned("lookupStake"), ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("lookup"), + name: ::std::borrow::ToOwned::to_owned("lookupStake"), inputs: ::std::vec![::ethers::core::abi::ethabi::Param { name: ::std::borrow::ToOwned::to_owned("blsVK"), kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ @@ -414,22 +414,22 @@ pub mod i_stake_table { .method_hash([247, 191, 176, 28], (bls_vk, amount)) .expect("method not found (this should never happen)") } - ///Calls the contract's `fullLookup` (0x8d98af20) function - pub fn full_lookup( + ///Calls the contract's `lookupNode` (0x52f92fc4) function + pub fn lookup_node( &self, bls_vk: G1Point, ) -> ::ethers::contract::builders::ContractCall { self.0 - .method_hash([141, 152, 175, 32], (bls_vk,)) + .method_hash([82, 249, 47, 196], (bls_vk,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `lookup` (0x28e25b51) function - pub fn lookup( + ///Calls the contract's `lookupStake` (0xcdf7788f) function + pub fn lookup_stake( &self, bls_vk: G1Point, ) -> ::ethers::contract::builders::ContractCall { self.0 - .method_hash([40, 226, 91, 81], (bls_vk,)) + .method_hash([205, 247, 120, 143], (bls_vk,)) .expect("method not found (this should never happen)") } ///Calls the contract's `nextExitEpoch` (0x3b09c267) function @@ -551,7 +551,7 @@ pub mod i_stake_table { pub bls_vk: G1Point, pub amount: u64, } - ///Container type for all input parameters for the `fullLookup` function with signature `fullLookup((uint256,uint256))` and selector `0x8d98af20` + ///Container type for all input parameters for the `lookupNode` function with signature `lookupNode((uint256,uint256))` and selector `0x52f92fc4` #[derive( Clone, ::ethers::contract::EthCall, @@ -564,11 +564,11 @@ pub mod i_stake_table { Eq, Hash, )] - #[ethcall(name = "fullLookup", abi = "fullLookup((uint256,uint256))")] - pub struct FullLookupCall { + #[ethcall(name = "lookupNode", abi = "lookupNode((uint256,uint256))")] + pub struct LookupNodeCall { pub bls_vk: G1Point, } - ///Container type for all input parameters for the `lookup` function with signature `lookup((uint256,uint256))` and selector `0x28e25b51` + ///Container type for all input parameters for the `lookupStake` function with signature `lookupStake((uint256,uint256))` and selector `0xcdf7788f` #[derive( Clone, ::ethers::contract::EthCall, @@ -581,8 +581,8 @@ pub mod i_stake_table { Eq, Hash, )] - #[ethcall(name = "lookup", abi = "lookup((uint256,uint256))")] - pub struct LookupCall { + #[ethcall(name = "lookupStake", abi = "lookupStake((uint256,uint256))")] + pub struct LookupStakeCall { pub bls_vk: G1Point, } ///Container type for all input parameters for the `nextExitEpoch` function with signature `nextExitEpoch()` and selector `0x3b09c267` @@ -762,8 +762,8 @@ pub mod i_stake_table { )] pub enum IStakeTableCalls { Deposit(DepositCall), - FullLookup(FullLookupCall), - Lookup(LookupCall), + LookupNode(LookupNodeCall), + LookupStake(LookupStakeCall), NextExitEpoch(NextExitEpochCall), NextRegistrationEpoch(NextRegistrationEpochCall), NumPendingExit(NumPendingExitCall), @@ -783,11 +783,11 @@ pub mod i_stake_table { if let Ok(decoded) = ::decode(data) { return Ok(Self::Deposit(decoded)); } - if let Ok(decoded) = ::decode(data) { - return Ok(Self::FullLookup(decoded)); + if let Ok(decoded) = ::decode(data) { + return Ok(Self::LookupNode(decoded)); } - if let Ok(decoded) = ::decode(data) { - return Ok(Self::Lookup(decoded)); + if let Ok(decoded) = ::decode(data) { + return Ok(Self::LookupStake(decoded)); } if let Ok(decoded) = ::decode(data) { @@ -836,8 +836,8 @@ pub mod i_stake_table { fn encode(self) -> Vec { match self { Self::Deposit(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::FullLookup(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::Lookup(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::LookupNode(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::LookupStake(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::NextExitEpoch(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::NextRegistrationEpoch(element) => { ::ethers::core::abi::AbiEncode::encode(element) @@ -859,8 +859,8 @@ pub mod i_stake_table { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { match self { Self::Deposit(element) => ::core::fmt::Display::fmt(element, f), - Self::FullLookup(element) => ::core::fmt::Display::fmt(element, f), - Self::Lookup(element) => ::core::fmt::Display::fmt(element, f), + Self::LookupNode(element) => ::core::fmt::Display::fmt(element, f), + Self::LookupStake(element) => ::core::fmt::Display::fmt(element, f), Self::NextExitEpoch(element) => ::core::fmt::Display::fmt(element, f), Self::NextRegistrationEpoch(element) => ::core::fmt::Display::fmt(element, f), Self::NumPendingExit(element) => ::core::fmt::Display::fmt(element, f), @@ -879,14 +879,14 @@ pub mod i_stake_table { Self::Deposit(value) } } - impl ::core::convert::From for IStakeTableCalls { - fn from(value: FullLookupCall) -> Self { - Self::FullLookup(value) + impl ::core::convert::From for IStakeTableCalls { + fn from(value: LookupNodeCall) -> Self { + Self::LookupNode(value) } } - impl ::core::convert::From for IStakeTableCalls { - fn from(value: LookupCall) -> Self { - Self::Lookup(value) + impl ::core::convert::From for IStakeTableCalls { + fn from(value: LookupStakeCall) -> Self { + Self::LookupStake(value) } } impl ::core::convert::From for IStakeTableCalls { @@ -953,7 +953,7 @@ pub mod i_stake_table { Hash, )] pub struct DepositReturn(pub u64, pub u64); - ///Container type for all return fields from the `fullLookup` function with signature `fullLookup((uint256,uint256))` and selector `0x8d98af20` + ///Container type for all return fields from the `lookupNode` function with signature `lookupNode((uint256,uint256))` and selector `0x52f92fc4` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -966,8 +966,8 @@ pub mod i_stake_table { Eq, Hash, )] - pub struct FullLookupReturn(pub Node); - ///Container type for all return fields from the `lookup` function with signature `lookup((uint256,uint256))` and selector `0x28e25b51` + pub struct LookupNodeReturn(pub Node); + ///Container type for all return fields from the `lookupStake` function with signature `lookupStake((uint256,uint256))` and selector `0xcdf7788f` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -980,7 +980,7 @@ pub mod i_stake_table { Eq, Hash, )] - pub struct LookupReturn(pub u64); + pub struct LookupStakeReturn(pub u64); ///Container type for all return fields from the `nextExitEpoch` function with signature `nextExitEpoch()` and selector `0x3b09c267` #[derive( Clone, diff --git a/contracts/src/interfaces/IStakeTable.sol b/contracts/src/interfaces/IStakeTable.sol index a0d2d37992..f6bf607ddf 100644 --- a/contracts/src/interfaces/IStakeTable.sol +++ b/contracts/src/interfaces/IStakeTable.sol @@ -56,9 +56,9 @@ interface IStakeTable { function totalVotingStake() external view returns (uint256); /// @notice Look up the balance of `blsVK` - function lookup(BN254.G1Point calldata blsVK) external view returns (uint64); + function lookupStake(BN254.G1Point calldata blsVK) external view returns (uint64); /// @notice Look up the full `Node` state associated with `blsVK` - function fullLookup(BN254.G1Point calldata blsVK) external view returns (Node memory); + function lookupNode(BN254.G1Point calldata blsVK) external view returns (Node memory); // === Queuing Stats ===