diff --git a/apps/interface/package.json b/apps/interface/package.json index 344f7e6..e0309d6 100644 --- a/apps/interface/package.json +++ b/apps/interface/package.json @@ -29,6 +29,7 @@ "lucide-svelte": "^0.441.0", "ms": "^2.1.3", "ts-essentials": "^10.0.2", + "webauthn-p256": "^0.0.10", "viem": "^2.21.54", "zod": "^3.23.8" }, diff --git a/apps/interface/src/app.html b/apps/interface/src/app.html index d467537..e257e45 100644 --- a/apps/interface/src/app.html +++ b/apps/interface/src/app.html @@ -4,7 +4,7 @@ - zkLogin on Base + zkLogin with EIP-7702 %sveltekit.head% diff --git a/apps/interface/src/lib/SendEthCard.svelte b/apps/interface/src/lib/SendEthCard.svelte index 35be1ec..26092ad 100644 --- a/apps/interface/src/lib/SendEthCard.svelte +++ b/apps/interface/src/lib/SendEthCard.svelte @@ -1,42 +1,18 @@ @@ -44,35 +20,26 @@ Send ETH -
- Balance: - {#snippet success(data)} - {data} - {/snippet} - -
- { - assert(jwt, "no session"); - const bundlerClient = getBundlerClient( - await ethersSignerToWalletClient(signer), - ); - const account = await lib.jwtAccount.getAccount(jwt, signer); - const tx = await bundlerClient.sendUserOperation({ - account, - calls: [ - { - to: data.recipient as Address, - value: ethers.parseEther(data.amount), - }, - ], + const cred = await lib.webAuthn.getCredential(); + assert(cred, "no credential"); + const tx = await lib.eip7702.executeTx({ + credentialId: cred.id, + address, + to: data.recipient, + value: ethers.parseEther(data.amount), }); console.log("tx", tx); + lib.queries.invalidateAll(); Ui.toast.success("Transaction sent successfully"); }} > @@ -95,9 +62,7 @@ - - {disabled ? "Create a session first" : "Send"} - + Send {/snippet}
diff --git a/apps/interface/src/lib/chain.ts b/apps/interface/src/lib/chain.ts index 3e29c6a..e16e26d 100644 --- a/apps/interface/src/lib/chain.ts +++ b/apps/interface/src/lib/chain.ts @@ -5,11 +5,16 @@ import type { z } from "zod"; import { zUnionFromArray } from "./utils"; /** @deprecated use {@link ChainService} */ -export const chain = baseSepolia; +export const chain = odysseyTestnet; -const RPC_URL = "https://sepolia.base.org"; +const RPC_URL = "https://odyssey.ithaca.xyz"; /** @deprecated migrate to viem */ export const provider = new ethers.JsonRpcProvider(RPC_URL); +/** @deprecated migrate to viem */ +export const relayer = new ethers.Wallet( + "0x4e560d1db4456119f9256bb65b4321ad54b860882c46b5ecb6ba92ca4d725dad", + provider, +); const chains = [baseSepolia, odysseyTestnet] as const; diff --git a/apps/interface/src/lib/index.ts b/apps/interface/src/lib/index.ts index 0b6c1bb..bc2859d 100644 --- a/apps/interface/src/lib/index.ts +++ b/apps/interface/src/lib/index.ts @@ -2,9 +2,10 @@ import { browser } from "$app/environment"; import { PUBLIC_AUTH_GOOGLE_ID } from "$env/static/public"; import { zklogin } from "@shield-labs/zklogin"; import { QueryClient } from "@tanstack/svelte-query"; -import { ChainService, provider } from "./chain.js"; -import { JwtAccountService } from "./services/JwtAccountService.js"; +import { ChainService } from "./chain.js"; +import { Eip7702Service } from "./services/Eip7702Service.js"; import { QueriesService } from "./services/QueriesService.svelte.js"; +import { WebAuthnService } from "./services/WebAuthnService.js"; import { publicClient } from "./viemClients.js"; export * from "./viemClients.js"; @@ -18,9 +19,10 @@ const queryClient = new QueryClient({ }); const chain = new ChainService(); +const webAuthn = new WebAuthnService(); const zkLogin = new zklogin.ZkLogin(new zklogin.PublicKeyRegistry("")); const authProvider = new zklogin.GoogleProvider(PUBLIC_AUTH_GOOGLE_ID); -const jwtAccount = new JwtAccountService(publicClient, provider, zkLogin); +const eip7702 = new Eip7702Service(zkLogin, publicClient, authProvider); const queries = new QueriesService(authProvider, queryClient); const APP_NAME = "zkLogin"; @@ -29,6 +31,7 @@ export const lib = { queries, chain, zkLogin, + eip7702, authProvider, - jwtAccount, + webAuthn, }; diff --git a/apps/interface/src/lib/services/Eip7702Service.ts b/apps/interface/src/lib/services/Eip7702Service.ts new file mode 100644 index 0000000..ff9021f --- /dev/null +++ b/apps/interface/src/lib/services/Eip7702Service.ts @@ -0,0 +1,210 @@ +import { chain, provider, relayer } from "$lib/chain"; +import { Ui } from "@repo/ui"; +import { utils } from "@shield-labs/utils"; +import { zklogin } from "@shield-labs/zklogin"; +import deployments from "@shield-labs/zklogin-contracts/deployments.json"; +import { EoaAccount__factory } from "@shield-labs/zklogin-contracts/typechain-types"; +import { ethers } from "ethers"; +import { assert } from "ts-essentials"; +import { + createWalletClient, + http, + slice, + type Account, + type Chain, + type Client, + type Hex, +} from "viem"; +import { signAuthorization } from "viem/experimental"; +import { parsePublicKey, sign } from "webauthn-p256"; + +export class Eip7702Service { + constructor( + private zkLogin: zklogin.ZkLogin, + private client: Client & { chain: Chain }, + private authProvider: zklogin.GoogleProvider, + ) {} + + async requestJwt({ webAuthnPublicKey }: { webAuthnPublicKey: Hex }) { + const nonce = this.#toNonce(webAuthnPublicKey).slice("0x".length); + await this.authProvider.signInWithRedirect({ nonce }); + } + + async authorize({ + account, + jwt, + webAuthnPublicKey, + }: { + account: Account; + jwt: string; + webAuthnPublicKey: Hex; + }) { + if (!(await this.#requestJwtIfInvalid({ jwt, webAuthnPublicKey }))) { + throw new Error("jwt invalid"); + } + + const contractAddress = deployments[chain.id].contracts + .EoaAccount as `0x${string}`; + const auth = await signAuthorization(this.client, { + account, + contractAddress, + }); + + const accountClient = createWalletClient({ + account: account, + chain: this.client.chain, + transport: http(), + }); + + const accountData = await this.zkLogin.getAccountDataFromJwt( + jwt, + this.client.chain.id, + ); + const hash = await accountClient.writeContract({ + abi: EoaAccount__factory.abi, + address: account.address, + functionName: "setAccountId", + args: [parsePublicKey(webAuthnPublicKey), accountData], + authorizationList: [auth], + account: account, + chain: this.client.chain, + }); + + return hash; + } + + async recover({ + address, + jwt, + webAuthnPublicKey, + }: { + address: string; + jwt: string; + webAuthnPublicKey: Hex; + }) { + if (!(await this.#requestJwtIfInvalid({ jwt, webAuthnPublicKey }))) { + throw new Error("jwt invalid"); + } + + await this.zkLogin.publicKeyRegistry.requestPublicKeysUpdate( + this.client.chain.id, + ); + + const result = await this.zkLogin.proveJwt( + jwt, + this.#toNonce(webAuthnPublicKey).slice("0x".length), + ); + assert(result, "jwt invalid"); + const { input, proof } = result; + + const accContract = this.#toAccountContract(address); + const tx = await accContract.connect(relayer).recover( + { + proof: ethers.hexlify(proof), + jwtIat: input.jwt_iat, + jwtNonce: this.#toNonce(webAuthnPublicKey), + publicKeyHash: input.public_key_hash, + }, + parsePublicKey(webAuthnPublicKey), + ); + return tx.hash; + } + + async executeTx({ + credentialId, + address, + to, + value, + }: { + to: string; + value: bigint; + credentialId: string; + address: string; + }) { + const accContract = this.#toAccountContract(address); + const nonce = await accContract.nonce(); + const data = "0x"; + const digest = ethers.AbiCoder.defaultAbiCoder().encode( + ["uint256", "address", "bytes", "uint256"], + [nonce, to, data, value], + ); + const digestHash = ethers.keccak256(digest) as `0x${string}`; + + const signature = await sign({ hash: digestHash, credentialId }); + const r = slice(signature.signature, 0, 32); + const s = slice(signature.signature, 32, 64); + + console.log( + "balance before", + ethers.formatEther(await provider.provider.getBalance(accContract)), + ); + + const tx = await accContract + .connect(relayer) + .execute(to, data, value, { r, s }, signature.webauthn); + console.log("tx", tx.hash); + await tx.wait(); + console.log( + "balance after", + ethers.formatEther(await provider.provider.getBalance(accContract)), + ); + return tx.hash; + } + + async #requestJwtIfInvalid({ + jwt, + webAuthnPublicKey, + }: { + jwt: string; + webAuthnPublicKey: Hex; + }): Promise { + const isValid: boolean = await this.zkLogin.checkJwt( + jwt, + this.#toNonce(webAuthnPublicKey).slice("0x".length), + ); + if (isValid) { + return true; + } + Ui.toast.log( + "Sign in again please to link your wallet to your Google account", + ); + await utils.sleep("2 sec"); + await this.requestJwt({ + webAuthnPublicKey, + }); + return false; + } + + async isWebAuthnPublicKeyCorrect({ + address, + + webAuthnPublicKey, + }: { + address: string; + webAuthnPublicKey: Hex; + }) { + const accContract = this.#toAccountContract(address); + const publicKeyOnChain = await accContract.webauthnPublicKey(); + return ( + ethers.concat([ + ethers.zeroPadValue(ethers.toBeArray(publicKeyOnChain.x), 32), + ethers.zeroPadValue(ethers.toBeArray(publicKeyOnChain.y), 32), + ]) === webAuthnPublicKey + ); + } + + #toNonce(webAuthnPublicKey: Hex) { + const parsed = parsePublicKey(webAuthnPublicKey); + const hex = ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( + ["uint256", "uint256"], + [parsed.x, parsed.y], + ), + ); + return hex; + } + + #toAccountContract(address: string) { + return EoaAccount__factory.connect(address, provider.provider); + } +} diff --git a/apps/interface/src/lib/services/WebAuthnService.ts b/apps/interface/src/lib/services/WebAuthnService.ts new file mode 100644 index 0000000..a18e388 --- /dev/null +++ b/apps/interface/src/lib/services/WebAuthnService.ts @@ -0,0 +1,44 @@ +import { LocalStore } from "$lib/localStorage.svelte"; +import { + createCredential, + type CreateCredentialReturnType, +} from "webauthn-p256"; + +export class WebAuthnService { + #cred = new LocalStore( + "credential", + undefined, + ); + + async getOrCreateCredential({ name }: { name: string }) { + if (!this.#cred.value) { + this.#cred.value = await this.#createCredential({ name }); + } + return this.#cred.value; + } + + async getCredential() { + return this.#cred.value; + } + + async #createCredential({ + name, + }: { + name: string; + }): Promise { + const cred = await createCredential({ + user: { + name, + }, + }); + return { + id: cred.id, + publicKey: cred.publicKey, + }; + } +} + +export type SerializedCredential = Pick< + CreateCredentialReturnType, + "id" | "publicKey" +>; diff --git a/apps/interface/src/routes/+page.svelte b/apps/interface/src/routes/+page.svelte index a975f26..ba2f63b 100644 --- a/apps/interface/src/routes/+page.svelte +++ b/apps/interface/src/routes/+page.svelte @@ -1,52 +1,74 @@ @@ -133,82 +150,154 @@ Google account - {#if !jwt} + {#if acc} +
+ Address: {utils.shortAddress(acc.address)} + +
+ +
+ Passkeys and Google connected: + + {#snippet success(data)} + {data} + {/snippet} + +
+
+ Balance: + {#snippet success(data)} + {ethers.formatEther(data)} ETH + {/snippet} + + + {#if $balanceQuery.data === 0n} + { + const tx = await relayer.sendTransaction({ + to: acc.address, + value: ethers.parseEther("0.001"), + }); + await tx.wait(); + }} + > + Top up + + {/if} +
+
Network: {chain.name}
+ + {#if !jwt} + { + const cred = await lib.webAuthn.getOrCreateCredential({ + name: "me", + }); + await lib.eip7702.requestJwt({ + webAuthnPublicKey: cred.publicKey, + }); + }} + > + Create passkeys and sign in with Google + + {:else if $codeConnectedQuery.data === false} + + Connect Passkeys and Google + {#if $balanceQuery.data === 0n} + + Top up your balance first + + {/if} + + {:else if $credentialIsCorrectQuery.data === false} + + Recover + + {#if extendSessionStart} + {@const estimatedDuration = ms("1.5 min")} +
+ Remaining time: {formatDuration( + intervalToDuration({ + start: now.value, + end: extendSessionStart + estimatedDuration, + }), + )} + +
+ {/if} + {/if} + How it works +
+ {:else} + signIn(signer)} + onclick={async () => { + const privateKey = generatePrivateKey(); + accStore.value = { + type: "privateKey", + privateKey, + address: privateKeyToAddress(privateKey), + }; + }} > - Sign in with Google + Create account - How it works + + + { + const address = prompt("Enter the address you want to recover"); + if (address == null) { + return; + } + assert(isAddress(address), `Invalid address: ${address}`); + accStore.value = { + type: "address", + address, + }; + }} + > + Recover + + - {:else} - - {#snippet pending()} -
Loading...
- {/snippet} - {#snippet success(data)} - {#if data} - -
-
- Address: {utils.shortAddress(data.address)} - -
-
Network: {publicClient.chain.name}
-
- {#if data.ownerInfo == null} - No session - {:else if data.ownerInfo === "expired"} - Session expired - {:else} - Session expiration: in {formatDistance( - data.ownerInfo.expirationTimestamp * 1000, - now.value, - )} - {/if} -
-
- - {data.ownerInfo == null ? "Create" : "Extend"} session - - {#if extendSessionStart} - {@const estimatedDuration = ms("1.5 min")} - Remaining time: {formatDuration( - intervalToDuration({ - start: now.value, - end: extendSessionStart + estimatedDuration, - }), - )} - - {/if} -
- {/if} - {/snippet} -
{/if}
- + {#if acc && $codeConnectedQuery.data === true} + + {/if} + + {#if acc} + { + const result: boolean = await Ui.toast.confirm({ + confirmText: "Are you sure you want to forget this account?", + }); + if (!result) { + return; + } + accStore.value = undefined; + }} + > + Forget account + + {/if} diff --git a/packages/contracts/contracts/EoaAccount.sol b/packages/contracts/contracts/EoaAccount.sol new file mode 100644 index 0000000..254c018 --- /dev/null +++ b/packages/contracts/contracts/EoaAccount.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: SEE LICENSE IN LICENSE +pragma solidity ^0.8.27; + +import {ZkLogin} from "./ZkLogin.sol"; +import {IPublicKeyRegistry} from "./infra/IPublicKeyRegistry.sol"; +import {UltraVerifier} from "../noir/target/jwt_account.sol"; +import {WebAuthnP256} from "./utils/WebAuthnP256.sol"; +import {ECDSA} from "./utils/ECDSA.sol"; + +contract EoaAccount { + ZkLogin.AccountData public accountData; + + uint256 public nonce; + + ECDSA.PublicKey public webauthnPublicKey; + + function setAccountId( + ECDSA.PublicKey calldata webauthnPublicKey_, + ZkLogin.AccountData memory accountData_ + ) external { + require(msg.sender == address(this), "not self"); + + webauthnPublicKey = webauthnPublicKey_; + + accountData = accountData_; + } + + function recover( + ZkLogin.VerificationData calldata verificationData, + ECDSA.PublicKey calldata newP256PublicKey + ) external { + require( + keccak256(abi.encode(newP256PublicKey)) == + verificationData.jwtNonce, + "invalid WebAuthn public key" + ); + + require( + ZkLogin.verifyProof(accountData, verificationData), + "invalid proof" + ); + + webauthnPublicKey = newP256PublicKey; + } + + function execute( + address to, + bytes calldata data, + uint256 value, + ECDSA.Signature calldata signature, + WebAuthnP256.Metadata calldata metadata + ) public { + bytes32 challenge = keccak256(abi.encode(nonce++, to, data, value)); + require( + WebAuthnP256.verify( + challenge, + metadata, + signature, + webauthnPublicKey + ) + ); + + (bool success, ) = to.call{value: value}(data); + require(success, "call failed"); + } + + function getWebAuthnPublicKey() + external + view + returns (ECDSA.PublicKey memory) + { + return webauthnPublicKey; + } + + receive() external payable {} +} diff --git a/packages/contracts/contracts/utils/ECDSA.sol b/packages/contracts/contracts/utils/ECDSA.sol new file mode 100644 index 0000000..063e0a6 --- /dev/null +++ b/packages/contracts/contracts/utils/ECDSA.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +library ECDSA { + struct PublicKey { + uint256 x; + uint256 y; + } + + struct Signature { + uint256 r; + uint256 s; + } + + struct RecoveredSignature { + uint256 r; + uint256 s; + uint8 yParity; + } +} diff --git a/packages/contracts/contracts/utils/P256.sol b/packages/contracts/contracts/utils/P256.sol new file mode 100644 index 0000000..e311b3a --- /dev/null +++ b/packages/contracts/contracts/utils/P256.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import "./ECDSA.sol"; + +//( @title P256 +/// @author klkvr +/// @author jxom +/// @notice Wrapper function to abstract low level details of call to the P256 +/// signature verification precompile as defined in EIP-7212, see +/// . +library P256 { + /// @notice P256VERIFY operation + /// @param digest 32 bytes of the signed data hash + /// @param signature Signature of the signer + /// @param publicKey Public key of the signer + /// @return success Represents if the operation was successful + function verify( + bytes32 digest, + ECDSA.Signature memory signature, + ECDSA.PublicKey memory publicKey + ) internal view returns (bool) { + // P256VERIFY address is 0x14 from + (bool success, bytes memory output) = address(0x14).staticcall( + abi.encode( + digest, + signature.r, + signature.s, + publicKey.x, + publicKey.y + ) + ); + success = success && output.length == 32 && output[31] == 0x01; + + return success; + } +} diff --git a/packages/contracts/contracts/utils/WebAuthnP256.sol b/packages/contracts/contracts/utils/WebAuthnP256.sol new file mode 100644 index 0000000..3376745 --- /dev/null +++ b/packages/contracts/contracts/utils/WebAuthnP256.sol @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.23; + +import {Base64} from "solady/src/utils/Base64.sol"; +import "./ECDSA.sol"; +import "./P256.sol"; + +/// @title WebAuthnP256 +/// @author jxom +/// @notice Helper library for external contracts to verify WebAuthn signatures. +/// @dev Adapted from https://github.com/daimo-eth/p256-verifier/blob/master/src/WebAuthn.sol +library WebAuthnP256 { + struct Metadata { + bytes authenticatorData; + string clientDataJSON; + uint16 challengeIndex; + uint16 typeIndex; + bool userVerificationRequired; + } + + /// Checks whether substr occurs in str starting at a given byte offset. + function contains( + string memory substr, + string memory str, + uint256 location + ) internal pure returns (bool) { + bytes memory substrBytes = bytes(substr); + bytes memory strBytes = bytes(str); + + uint256 substrLen = substrBytes.length; + uint256 strLen = strBytes.length; + + for (uint256 i = 0; i < substrLen; i++) { + if (location + i >= strLen) { + return false; + } + + if (substrBytes[i] != strBytes[location + i]) { + return false; + } + } + + return true; + } + + bytes1 constant AUTH_DATA_FLAGS_UP = 0x01; // Bit 0 + bytes1 constant AUTH_DATA_FLAGS_UV = 0x04; // Bit 2 + bytes1 constant AUTH_DATA_FLAGS_BE = 0x08; // Bit 3 + bytes1 constant AUTH_DATA_FLAGS_BS = 0x10; // Bit 4 + + /// Verifies the authFlags in authenticatorData. Numbers in inline comment + /// correspond to the same numbered bullets in + /// https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion. + function checkAuthFlags( + bytes1 flags, + bool requireUserVerification + ) internal pure returns (bool) { + // 17. Verify that the UP bit of the flags in authData is set. + if (flags & AUTH_DATA_FLAGS_UP != AUTH_DATA_FLAGS_UP) { + return false; + } + + // 18. If user verification was determined to be required, verify that + // the UV bit of the flags in authData is set. Otherwise, ignore the + // value of the UV flag. + if ( + requireUserVerification && + (flags & AUTH_DATA_FLAGS_UV) != AUTH_DATA_FLAGS_UV + ) { + return false; + } + + // 19. If the BE bit of the flags in authData is not set, verify that + // the BS bit is not set. + if (flags & AUTH_DATA_FLAGS_BE != AUTH_DATA_FLAGS_BE) { + if (flags & AUTH_DATA_FLAGS_BS == AUTH_DATA_FLAGS_BS) { + return false; + } + } + + return true; + } + + /** + * Verifies a Webauthn P256 signature (Authentication Assertion) as described + * in https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion. We do not + * verify all the steps as described in the specification, only ones relevant + * to our context. Please carefully read through this list before usage. + * Specifically, we do verify the following: + * - Verify that authenticatorData (which comes from the authenticator, + * such as iCloud Keychain) indicates a well-formed assertion. If + * requireUserVerification is set, checks that the authenticator enforced + * user verification. User verification should be required if, + * and only if, options.userVerification is set to required in the request + * - Verifies that the client JSON is of type "webauthn.get", i.e. the client + * was responding to a request to assert authentication. + * - Verifies that the client JSON contains the requested challenge. + * - Finally, verifies that (r, s) constitute a valid signature over both + * the authenicatorData and client JSON, for public key (x, y). + * + * We make some assumptions about the particular use case of this verifier, + * so we do NOT verify the following: + * - Does NOT verify that the origin in the clientDataJSON matches the + * Relying Party's origin: It is considered the authenticator's + * responsibility to ensure that the user is interacting with the correct + * RP. This is enforced by most high quality authenticators properly, + * particularly the iCloud Keychain and Google Password Manager were + * tested. + * - Does NOT verify That c.topOrigin is well-formed: We assume c.topOrigin + * would never be present, i.e. the credentials are never used in a + * cross-origin/iframe context. The website/app set up should disallow + * cross-origin usage of the credentials. This is the default behaviour for + * created credentials in common settings. + * - Does NOT verify that the rpIdHash in authData is the SHA-256 hash of an + * RP ID expected by the Relying Party: This means that we rely on the + * authenticator to properly enforce credentials to be used only by the + * correct RP. This is generally enforced with features like Apple App Site + * Association and Google Asset Links. To protect from edge cases in which + * a previously-linked RP ID is removed from the authorised RP IDs, + * we recommend that messages signed by the authenticator include some + * expiry mechanism. + * - Does NOT verify the credential backup state: This assumes the credential + * backup state is NOT used as part of Relying Party business logic or + * policy. + * - Does NOT verify the values of the client extension outputs: This assumes + * that the Relying Party does not use client extension outputs. + * - Does NOT verify the signature counter: Signature counters are intended + * to enable risk scoring for the Relying Party. This assumes risk scoring + * is not used as part of Relying Party business logic or policy. + * - Does NOT verify the attestation object: This assumes that + * response.attestationObject is NOT present in the response, i.e. the + * RP does not intend to verify an attestation. + */ + function verify( + bytes32 challenge, + Metadata memory metadata, + ECDSA.Signature memory signature, + ECDSA.PublicKey memory publicKey + ) internal view returns (bool) { + // Check that authenticatorData has good flags + if ( + metadata.authenticatorData.length < 37 || + !checkAuthFlags( + metadata.authenticatorData[32], + metadata.userVerificationRequired + ) + ) { + return false; + } + + // Check that response is for an authentication assertion + string memory responseType = '"type":"webauthn.get"'; + if ( + !contains(responseType, metadata.clientDataJSON, metadata.typeIndex) + ) { + return false; + } + + // Check that challenge is in the clientDataJSON + string memory challengeB64url = Base64.encode( + abi.encodePacked(challenge), + true, + true + ); + string memory challengeProperty = string.concat( + '"challenge":"', + challengeB64url, + '"' + ); + + if ( + !contains( + challengeProperty, + metadata.clientDataJSON, + metadata.challengeIndex + ) + ) { + return false; + } + + // Check that the public key signed sha256(authenticatorData || sha256(clientDataJSON)) + bytes32 clientDataJSONHash = sha256(bytes(metadata.clientDataJSON)); + bytes32 messageHash = sha256( + abi.encodePacked(metadata.authenticatorData, clientDataJSONHash) + ); + + return P256.verify(messageHash, signature, publicKey); + } +} diff --git a/packages/contracts/deploy/00_deploy.ts b/packages/contracts/deploy/00_deploy.ts index 94fa19e..2119263 100644 --- a/packages/contracts/deploy/00_deploy.ts +++ b/packages/contracts/deploy/00_deploy.ts @@ -5,6 +5,7 @@ declare module "hardhat/types/runtime" { PublicKeyRegistry: "PublicKeyRegistry"; SimpleAccountFactory: "SimpleAccountFactory"; UltraVerifier: "UltraVerifier"; + EoaAccount: "EoaAccount"; } } @@ -24,6 +25,11 @@ const deploy: DeployFunction = async ({ log: true, }); + await typedDeployments.deploy("EoaAccount", { + from: deployer, + log: true, + }); + const entryPoint = "0x0000000071727De22E5E9d8BAf0edAc6f37da032"; // 0.7.0 await typedDeployments.deploy("SimpleAccountFactory", { from: deployer, diff --git a/packages/contracts/deployments.json b/packages/contracts/deployments.json index 1b0df15..8267abd 100644 --- a/packages/contracts/deployments.json +++ b/packages/contracts/deployments.json @@ -11,6 +11,7 @@ "911867": { "chainId": "911867", "contracts": { + "EoaAccount": "0xaAEeF3AC9807EBBAE0829b869FCF1913fA0e13a8", "PublicKeyRegistry": "0x4aCE3c45Ce0395c178eA70D61d78326c11546e03", "SimpleAccountFactory": "0xe86f848F0BFa31DdaA5455E95cD8aF5f696ddc0e", "UltraVerifier": "0xc500504b6b2F64D3CaE0FB92C22ef582e07Ecf5A" diff --git a/packages/contracts/deployments/odysseyTestnet/EoaAccount.json b/packages/contracts/deployments/odysseyTestnet/EoaAccount.json new file mode 100644 index 0000000..e894e4c --- /dev/null +++ b/packages/contracts/deployments/odysseyTestnet/EoaAccount.json @@ -0,0 +1,431 @@ +{ + "address": "0xaAEeF3AC9807EBBAE0829b869FCF1913fA0e13a8", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "StringsInsufficientHexLength", + "type": "error" + }, + { + "inputs": [], + "name": "accountData", + "outputs": [ + { + "internalType": "bytes32", + "name": "accountId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "authProviderId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "publicKeyRegistry", + "type": "address" + }, + { + "internalType": "address", + "name": "proofVerifier", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "r", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "s", + "type": "uint256" + } + ], + "internalType": "struct ECDSA.Signature", + "name": "signature", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes", + "name": "authenticatorData", + "type": "bytes" + }, + { + "internalType": "string", + "name": "clientDataJSON", + "type": "string" + }, + { + "internalType": "uint16", + "name": "challengeIndex", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "typeIndex", + "type": "uint16" + }, + { + "internalType": "bool", + "name": "userVerificationRequired", + "type": "bool" + } + ], + "internalType": "struct WebAuthnP256.Metadata", + "name": "metadata", + "type": "tuple" + } + ], + "name": "execute", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getWebAuthnPublicKey", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "internalType": "struct ECDSA.PublicKey", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "proof", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "jwtIat", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "jwtNonce", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "publicKeyHash", + "type": "bytes32" + } + ], + "internalType": "struct ZkLogin.VerificationData", + "name": "verificationData", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "internalType": "struct ECDSA.PublicKey", + "name": "newP256PublicKey", + "type": "tuple" + } + ], + "name": "recover", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "internalType": "struct ECDSA.PublicKey", + "name": "webauthnPublicKey_", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "accountId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "authProviderId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "publicKeyRegistry", + "type": "address" + }, + { + "internalType": "address", + "name": "proofVerifier", + "type": "address" + } + ], + "internalType": "struct ZkLogin.AccountData", + "name": "accountData_", + "type": "tuple" + } + ], + "name": "setAccountId", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "webauthnPublicKey", + "outputs": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "y", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "transactionHash": "0x304b02678a1ad63ab8e177e20cc7183fbcf4bbb3082c86f83792f17c18581677", + "receipt": { + "to": null, + "from": "0xEE0A4782efd390120A29F050A76B297D078e1df9", + "contractAddress": "0xaAEeF3AC9807EBBAE0829b869FCF1913fA0e13a8", + "transactionIndex": 1, + "gasUsed": "1416798", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x48b67cbc4559797589ce273c802d2d9ae857b0f6364f1c91de18771bb23b022a", + "transactionHash": "0x304b02678a1ad63ab8e177e20cc7183fbcf4bbb3082c86f83792f17c18581677", + "logs": [], + "blockNumber": 5132601, + "cumulativeGasUsed": "1460640", + "status": 1, + "byzantium": true + }, + "args": [], + "numDeployments": 2, + "solcInputHash": "e2c7304a6ecf567a5c4c24c2eee90283", + "metadata": "{\"compiler\":{\"version\":\"0.8.27+commit.40a35a09\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"length\",\"type\":\"uint256\"}],\"name\":\"StringsInsufficientHexLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"accountData\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"accountId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"authProviderId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"publicKeyRegistry\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"proofVerifier\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"r\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"s\",\"type\":\"uint256\"}],\"internalType\":\"struct ECDSA.Signature\",\"name\":\"signature\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"authenticatorData\",\"type\":\"bytes\"},{\"internalType\":\"string\",\"name\":\"clientDataJSON\",\"type\":\"string\"},{\"internalType\":\"uint16\",\"name\":\"challengeIndex\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"typeIndex\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"userVerificationRequired\",\"type\":\"bool\"}],\"internalType\":\"struct WebAuthnP256.Metadata\",\"name\":\"metadata\",\"type\":\"tuple\"}],\"name\":\"execute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWebAuthnPublicKey\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct ECDSA.PublicKey\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"jwtIat\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"jwtNonce\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"publicKeyHash\",\"type\":\"bytes32\"}],\"internalType\":\"struct ZkLogin.VerificationData\",\"name\":\"verificationData\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct ECDSA.PublicKey\",\"name\":\"newP256PublicKey\",\"type\":\"tuple\"}],\"name\":\"recover\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"internalType\":\"struct ECDSA.PublicKey\",\"name\":\"webauthnPublicKey_\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"accountId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"authProviderId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"publicKeyRegistry\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"proofVerifier\",\"type\":\"address\"}],\"internalType\":\"struct ZkLogin.AccountData\",\"name\":\"accountData_\",\"type\":\"tuple\"}],\"name\":\"setAccountId\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"webauthnPublicKey\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"y\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"errors\":{\"StringsInsufficientHexLength(uint256,uint256)\":[{\"details\":\"The `value` string doesn't fit in the specified `length`.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/EoaAccount.sol\":\"EoaAccount\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100000000},\"remappings\":[]},\"sources\":{\"contracts/EoaAccount.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity ^0.8.27;\\n\\nimport {ZkLogin} from \\\"./ZkLogin.sol\\\";\\nimport {IPublicKeyRegistry} from \\\"./infra/IPublicKeyRegistry.sol\\\";\\nimport {UltraVerifier} from \\\"../noir/target/jwt_account.sol\\\";\\nimport {WebAuthnP256} from \\\"./utils/WebAuthnP256.sol\\\";\\nimport {ECDSA} from \\\"./utils/ECDSA.sol\\\";\\n\\ncontract EoaAccount {\\n ZkLogin.AccountData public accountData;\\n\\n uint256 public nonce;\\n\\n ECDSA.PublicKey public webauthnPublicKey;\\n\\n function setAccountId(\\n ECDSA.PublicKey calldata webauthnPublicKey_,\\n ZkLogin.AccountData memory accountData_\\n ) external {\\n require(msg.sender == address(this), \\\"not self\\\");\\n\\n webauthnPublicKey = webauthnPublicKey_;\\n\\n accountData = accountData_;\\n }\\n\\n function recover(\\n ZkLogin.VerificationData calldata verificationData,\\n ECDSA.PublicKey calldata newP256PublicKey\\n ) external {\\n require(\\n keccak256(abi.encode(newP256PublicKey)) ==\\n verificationData.jwtNonce,\\n \\\"invalid WebAuthn public key\\\"\\n );\\n\\n require(\\n ZkLogin.verifyProof(accountData, verificationData),\\n \\\"invalid proof\\\"\\n );\\n\\n webauthnPublicKey = newP256PublicKey;\\n }\\n\\n function execute(\\n address to,\\n bytes calldata data,\\n uint256 value,\\n ECDSA.Signature calldata signature,\\n WebAuthnP256.Metadata calldata metadata\\n ) public {\\n bytes32 challenge = keccak256(abi.encode(nonce++, to, data, value));\\n require(\\n WebAuthnP256.verify(\\n challenge,\\n metadata,\\n signature,\\n webauthnPublicKey\\n )\\n );\\n\\n (bool success, ) = to.call{value: value}(data);\\n require(success, \\\"call failed\\\");\\n }\\n\\n function getWebAuthnPublicKey()\\n external\\n view\\n returns (ECDSA.PublicKey memory)\\n {\\n return webauthnPublicKey;\\n }\\n\\n receive() external payable {}\\n}\\n\",\"keccak256\":\"0xb0311badd77e8fb263250eba377e735fab83e05fe37f88a41fc93066b7be6752\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/IProofVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity ^0.8.27;\\n\\ninterface IProofVerifier {\\n function verify(\\n bytes calldata proof,\\n bytes32[] calldata publicInputs\\n ) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x1021dfaf4da24ec23fd0208918af784529ab02e5b0fe9c90f3650977fe81876e\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/ZkLogin.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity ^0.8.27;\\n\\nimport {IProofVerifier} from \\\"./IProofVerifier.sol\\\";\\nimport {Strings} from \\\"./utils/Strings.sol\\\";\\nimport {IPublicKeyRegistry} from \\\"./infra/IPublicKeyRegistry.sol\\\";\\n\\nlibrary ZkLogin {\\n struct AccountData {\\n bytes32 accountId;\\n bytes32 authProviderId;\\n address publicKeyRegistry;\\n address proofVerifier;\\n }\\n\\n struct VerificationData {\\n bytes proof;\\n uint256 jwtIat;\\n bytes32 jwtNonce;\\n bytes32 publicKeyHash;\\n }\\n\\n function verifyProof(\\n AccountData memory accountData,\\n VerificationData memory verificationData\\n ) internal view returns (bool) {\\n require(\\n IPublicKeyRegistry(accountData.publicKeyRegistry).checkPublicKey(\\n accountData.authProviderId,\\n verificationData.publicKeyHash\\n ),\\n \\\"public key hash mismatch\\\"\\n );\\n\\n bytes memory jwtNonce = bytes(\\n Strings.toHexStringWithoutPrefix(verificationData.jwtNonce)\\n );\\n\\n uint256 staticInputLength = 3;\\n bytes32[] memory publicInputs = new bytes32[](\\n staticInputLength + jwtNonce.length\\n );\\n uint256 j = 0;\\n publicInputs[j++] = accountData.accountId;\\n publicInputs[j++] = bytes32(verificationData.jwtIat);\\n publicInputs[j++] = verificationData.publicKeyHash;\\n\\n for (uint256 i = 0; i < jwtNonce.length; i++) {\\n publicInputs[j++] = bytes32(uint256(uint8(jwtNonce[i])));\\n }\\n assert(j == publicInputs.length);\\n\\n return\\n IProofVerifier(accountData.proofVerifier).verify(\\n verificationData.proof,\\n publicInputs\\n );\\n }\\n}\\n\",\"keccak256\":\"0xb0f7545d9b2fe516c8a3eeff3bcb8abf307900fe788dac712914fd221e667b8b\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/infra/IPublicKeyRegistry.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity ^0.8.27;\\n\\ninterface IPublicKeyRegistry {\\n function checkPublicKey(\\n bytes32 providerId,\\n bytes32 publicKeyHash\\n ) external view returns (bool);\\n}\\n\",\"keccak256\":\"0xae7fd8c2a171137840a2ba7353c60cff4368fd764285db0f6b3321f5c2ab0883\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/utils/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.23;\\n\\nlibrary ECDSA {\\n struct PublicKey {\\n uint256 x;\\n uint256 y;\\n }\\n\\n struct Signature {\\n uint256 r;\\n uint256 s;\\n }\\n\\n struct RecoveredSignature {\\n uint256 r;\\n uint256 s;\\n uint8 yParity;\\n }\\n}\\n\",\"keccak256\":\"0x14a31e9a4efb985d00c8f4d1f0d4d9a99eef64e88addcf563b0e93a0ddc525fa\",\"license\":\"MIT\"},\"contracts/utils/P256.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.23;\\n\\nimport \\\"./ECDSA.sol\\\";\\n\\n//( @title P256\\n/// @author klkvr \\n/// @author jxom \\n/// @notice Wrapper function to abstract low level details of call to the P256\\n/// signature verification precompile as defined in EIP-7212, see\\n/// .\\nlibrary P256 {\\n /// @notice P256VERIFY operation\\n /// @param digest 32 bytes of the signed data hash\\n /// @param signature Signature of the signer\\n /// @param publicKey Public key of the signer\\n /// @return success Represents if the operation was successful\\n function verify(\\n bytes32 digest,\\n ECDSA.Signature memory signature,\\n ECDSA.PublicKey memory publicKey\\n ) internal view returns (bool) {\\n // P256VERIFY address is 0x14 from \\n (bool success, bytes memory output) = address(0x14).staticcall(\\n abi.encode(\\n digest,\\n signature.r,\\n signature.s,\\n publicKey.x,\\n publicKey.y\\n )\\n );\\n success = success && output.length == 32 && output[31] == 0x01;\\n\\n return success;\\n }\\n}\\n\",\"keccak256\":\"0xf39582cf83b9983fc80aca532199c73f3033f7e471205c04364cb89d46a9b2ed\",\"license\":\"MIT\"},\"contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: SEE LICENSE IN LICENSE\\npragma solidity ^0.8.27;\\n\\nlibrary Strings {\\n bytes16 private constant HEX_DIGITS = \\\"0123456789abcdef\\\";\\n\\n /**\\n * @dev The `value` string doesn't fit in the specified `length`.\\n */\\n error StringsInsufficientHexLength(uint256 value, uint256 length);\\n\\n function toHexStringWithoutPrefix(\\n uint256 value,\\n uint256 length\\n ) internal pure returns (string memory) {\\n uint256 localValue = value;\\n bytes memory buffer = new bytes(2 * length);\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i - 2] = HEX_DIGITS[localValue & 0xf];\\n localValue >>= 4;\\n }\\n if (localValue != 0) {\\n revert StringsInsufficientHexLength(value, length);\\n }\\n return string(buffer);\\n }\\n\\n function toHexStringWithoutPrefix(\\n bytes32 value\\n ) internal pure returns (string memory) {\\n return toHexStringWithoutPrefix(uint256(value), 32);\\n }\\n}\\n\",\"keccak256\":\"0x71f8f11a2e7a84881a5ceb1cc52313d3e4e09b2e7ff6a09a0afb6dd7bc05651c\",\"license\":\"SEE LICENSE IN LICENSE\"},\"contracts/utils/WebAuthnP256.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.23;\\n\\nimport {Base64} from \\\"solady/src/utils/Base64.sol\\\";\\nimport \\\"./ECDSA.sol\\\";\\nimport \\\"./P256.sol\\\";\\n\\n/// @title WebAuthnP256\\n/// @author jxom \\n/// @notice Helper library for external contracts to verify WebAuthn signatures.\\n/// @dev Adapted from https://github.com/daimo-eth/p256-verifier/blob/master/src/WebAuthn.sol\\nlibrary WebAuthnP256 {\\n struct Metadata {\\n bytes authenticatorData;\\n string clientDataJSON;\\n uint16 challengeIndex;\\n uint16 typeIndex;\\n bool userVerificationRequired;\\n }\\n\\n /// Checks whether substr occurs in str starting at a given byte offset.\\n function contains(\\n string memory substr,\\n string memory str,\\n uint256 location\\n ) internal pure returns (bool) {\\n bytes memory substrBytes = bytes(substr);\\n bytes memory strBytes = bytes(str);\\n\\n uint256 substrLen = substrBytes.length;\\n uint256 strLen = strBytes.length;\\n\\n for (uint256 i = 0; i < substrLen; i++) {\\n if (location + i >= strLen) {\\n return false;\\n }\\n\\n if (substrBytes[i] != strBytes[location + i]) {\\n return false;\\n }\\n }\\n\\n return true;\\n }\\n\\n bytes1 constant AUTH_DATA_FLAGS_UP = 0x01; // Bit 0\\n bytes1 constant AUTH_DATA_FLAGS_UV = 0x04; // Bit 2\\n bytes1 constant AUTH_DATA_FLAGS_BE = 0x08; // Bit 3\\n bytes1 constant AUTH_DATA_FLAGS_BS = 0x10; // Bit 4\\n\\n /// Verifies the authFlags in authenticatorData. Numbers in inline comment\\n /// correspond to the same numbered bullets in\\n /// https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion.\\n function checkAuthFlags(\\n bytes1 flags,\\n bool requireUserVerification\\n ) internal pure returns (bool) {\\n // 17. Verify that the UP bit of the flags in authData is set.\\n if (flags & AUTH_DATA_FLAGS_UP != AUTH_DATA_FLAGS_UP) {\\n return false;\\n }\\n\\n // 18. If user verification was determined to be required, verify that\\n // the UV bit of the flags in authData is set. Otherwise, ignore the\\n // value of the UV flag.\\n if (\\n requireUserVerification &&\\n (flags & AUTH_DATA_FLAGS_UV) != AUTH_DATA_FLAGS_UV\\n ) {\\n return false;\\n }\\n\\n // 19. If the BE bit of the flags in authData is not set, verify that\\n // the BS bit is not set.\\n if (flags & AUTH_DATA_FLAGS_BE != AUTH_DATA_FLAGS_BE) {\\n if (flags & AUTH_DATA_FLAGS_BS == AUTH_DATA_FLAGS_BS) {\\n return false;\\n }\\n }\\n\\n return true;\\n }\\n\\n /**\\n * Verifies a Webauthn P256 signature (Authentication Assertion) as described\\n * in https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion. We do not\\n * verify all the steps as described in the specification, only ones relevant\\n * to our context. Please carefully read through this list before usage.\\n * Specifically, we do verify the following:\\n * - Verify that authenticatorData (which comes from the authenticator,\\n * such as iCloud Keychain) indicates a well-formed assertion. If\\n * requireUserVerification is set, checks that the authenticator enforced\\n * user verification. User verification should be required if,\\n * and only if, options.userVerification is set to required in the request\\n * - Verifies that the client JSON is of type \\\"webauthn.get\\\", i.e. the client\\n * was responding to a request to assert authentication.\\n * - Verifies that the client JSON contains the requested challenge.\\n * - Finally, verifies that (r, s) constitute a valid signature over both\\n * the authenicatorData and client JSON, for public key (x, y).\\n *\\n * We make some assumptions about the particular use case of this verifier,\\n * so we do NOT verify the following:\\n * - Does NOT verify that the origin in the clientDataJSON matches the\\n * Relying Party's origin: It is considered the authenticator's\\n * responsibility to ensure that the user is interacting with the correct\\n * RP. This is enforced by most high quality authenticators properly,\\n * particularly the iCloud Keychain and Google Password Manager were\\n * tested.\\n * - Does NOT verify That c.topOrigin is well-formed: We assume c.topOrigin\\n * would never be present, i.e. the credentials are never used in a\\n * cross-origin/iframe context. The website/app set up should disallow\\n * cross-origin usage of the credentials. This is the default behaviour for\\n * created credentials in common settings.\\n * - Does NOT verify that the rpIdHash in authData is the SHA-256 hash of an\\n * RP ID expected by the Relying Party: This means that we rely on the\\n * authenticator to properly enforce credentials to be used only by the\\n * correct RP. This is generally enforced with features like Apple App Site\\n * Association and Google Asset Links. To protect from edge cases in which\\n * a previously-linked RP ID is removed from the authorised RP IDs,\\n * we recommend that messages signed by the authenticator include some\\n * expiry mechanism.\\n * - Does NOT verify the credential backup state: This assumes the credential\\n * backup state is NOT used as part of Relying Party business logic or\\n * policy.\\n * - Does NOT verify the values of the client extension outputs: This assumes\\n * that the Relying Party does not use client extension outputs.\\n * - Does NOT verify the signature counter: Signature counters are intended\\n * to enable risk scoring for the Relying Party. This assumes risk scoring\\n * is not used as part of Relying Party business logic or policy.\\n * - Does NOT verify the attestation object: This assumes that\\n * response.attestationObject is NOT present in the response, i.e. the\\n * RP does not intend to verify an attestation.\\n */\\n function verify(\\n bytes32 challenge,\\n Metadata memory metadata,\\n ECDSA.Signature memory signature,\\n ECDSA.PublicKey memory publicKey\\n ) internal view returns (bool) {\\n // Check that authenticatorData has good flags\\n if (\\n metadata.authenticatorData.length < 37 ||\\n !checkAuthFlags(\\n metadata.authenticatorData[32],\\n metadata.userVerificationRequired\\n )\\n ) {\\n return false;\\n }\\n\\n // Check that response is for an authentication assertion\\n string memory responseType = '\\\"type\\\":\\\"webauthn.get\\\"';\\n if (\\n !contains(responseType, metadata.clientDataJSON, metadata.typeIndex)\\n ) {\\n return false;\\n }\\n\\n // Check that challenge is in the clientDataJSON\\n string memory challengeB64url = Base64.encode(\\n abi.encodePacked(challenge),\\n true,\\n true\\n );\\n string memory challengeProperty = string.concat(\\n '\\\"challenge\\\":\\\"',\\n challengeB64url,\\n '\\\"'\\n );\\n\\n if (\\n !contains(\\n challengeProperty,\\n metadata.clientDataJSON,\\n metadata.challengeIndex\\n )\\n ) {\\n return false;\\n }\\n\\n // Check that the public key signed sha256(authenticatorData || sha256(clientDataJSON))\\n bytes32 clientDataJSONHash = sha256(bytes(metadata.clientDataJSON));\\n bytes32 messageHash = sha256(\\n abi.encodePacked(metadata.authenticatorData, clientDataJSONHash)\\n );\\n\\n return P256.verify(messageHash, signature, publicKey);\\n }\\n}\\n\",\"keccak256\":\"0x22854d394e59d6656de1a8e05dbb58a7154b352a064f924264b9a8bad15ccdb7\",\"license\":\"MIT\"},\"noir/target/jwt_account.sol\":{\"content\":\"// Verification Key Hash: df17b68894fbe76ada8e2859abb6925eb52b99f2516db87bc9720ed3f22c9625\\n// SPDX-License-Identifier: Apache-2.0\\n// Copyright 2022 Aztec\\npragma solidity >=0.8.4;\\n\\nlibrary UltraVerificationKey {\\n function verificationKeyHash() internal pure returns(bytes32) {\\n return 0xdf17b68894fbe76ada8e2859abb6925eb52b99f2516db87bc9720ed3f22c9625;\\n }\\n\\n function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure {\\n assembly {\\n mstore(add(_vk, 0x00), 0x0000000000000000000000000000000000000000000000000000000000040000) // vk.circuit_size\\n mstore(add(_vk, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000043) // vk.num_inputs\\n mstore(add(_vk, 0x40), 0x19ddbcaf3a8d46c15c0176fbb5b95e4dc57088ff13f4d1bd84c6bfa57dcdc0e0) // vk.work_root\\n mstore(add(_vk, 0x60), 0x30644259cd94e7dd5045d7a27013b7fcd21c9e3b7fa75222e7bda49b729b0401) // vk.domain_inverse\\n mstore(add(_vk, 0x80), 0x1f71d28f11460f73331294dcf27294a19ed4b299e9017ae496055943f52e24e2) // vk.Q1.x\\n mstore(add(_vk, 0xa0), 0x271a3a71a32f091c6798366f7973de1d977acfaf7724ff5058e7cba7cdd23b80) // vk.Q1.y\\n mstore(add(_vk, 0xc0), 0x2b1cb88996c8731ebf20516498954b9a032de3b05df44d5e7d26e6363f3d60e1) // vk.Q2.x\\n mstore(add(_vk, 0xe0), 0x196fadb6d06f205cc5ebae7284263b042d5b9fa18199256d3cc7781e3711af5d) // vk.Q2.y\\n mstore(add(_vk, 0x100), 0x08c5d310e66efae284aa2e844dec1675291c7991f45b4cdaa46ba9b8e537b9be) // vk.Q3.x\\n mstore(add(_vk, 0x120), 0x19d75133597f5a7faa14851b95187f35ef8f1fa1f414d3f4089cc07f1b9865e4) // vk.Q3.y\\n mstore(add(_vk, 0x140), 0x1b8337f6394b77c6fd4fb9f6d6a92a6edc860e19c3653088a95edc825af4b540) // vk.Q4.x\\n mstore(add(_vk, 0x160), 0x0780e2515f54a5f9c172e47e47021b475bc28d46a5507d71ca963ea8bcf76082) // vk.Q4.y\\n mstore(add(_vk, 0x180), 0x2e0f0594e85394a51b61896fe2c840722a2fb8b47b0085fa8402689a9e69db78) // vk.Q_M.x\\n mstore(add(_vk, 0x1a0), 0x12d1e049b46895986669c27c85bc03c732e1f8588e8a7692f89574875472b207) // vk.Q_M.y\\n mstore(add(_vk, 0x1c0), 0x2386abedd596e6ae42de8b18c2c2482a0f132fed2010b5701c7e5e84e6abf202) // vk.Q_C.x\\n mstore(add(_vk, 0x1e0), 0x25844948d313c3863f20e125e45f6812f96c4474a9a391a79b70da7b79ff14f9) // vk.Q_C.y\\n mstore(add(_vk, 0x200), 0x281abbca08b2d727b5f127242dc71d78d7d133ce160cfeb8f11438f69f8ae5ef) // vk.Q_ARITHMETIC.x\\n mstore(add(_vk, 0x220), 0x151febc070ee5a29f29e66c7dfdc46d31d53781b12a5092e7fcc32cb8e5f1ef9) // vk.Q_ARITHMETIC.y\\n mstore(add(_vk, 0x240), 0x1107a754c3f11021248c43d10abd2ed46eafd9e293ee620b50cdb47e65123bc7) // vk.QSORT.x\\n mstore(add(_vk, 0x260), 0x150544048502e4a6252dc819526c72cf6e605c841af7b06028e7f722819893a7) // vk.QSORT.y\\n mstore(add(_vk, 0x280), 0x22f2a3213af13776e6bd38362a5885cbf923d5630eda38ba032a42faeb1ea61c) // vk.Q_ELLIPTIC.x\\n mstore(add(_vk, 0x2a0), 0x177d8d1ed4c4b9e2c3f232b25de8638139e795bd40689a9765750ebaca55f48f) // vk.Q_ELLIPTIC.y\\n mstore(add(_vk, 0x2c0), 0x0383b7f12114cc47c75eb683abb079fdb0cddcade14107819bb917209c0ae05a) // vk.Q_AUX.x\\n mstore(add(_vk, 0x2e0), 0x0ac0be98b2a66afb7df02cf9bcb702ab54e4d48fb08eef1f8c60a957603617cd) // vk.Q_AUX.y\\n mstore(add(_vk, 0x300), 0x199abd2d188bed224ba145f82d16e61939a31b6fb98fd6620e1b0242cf78bb0f) // vk.SIGMA1.x\\n mstore(add(_vk, 0x320), 0x1199f428a1af935ac6e0fd709b7fd8393bdce95e95f017257583153a99befb44) // vk.SIGMA1.y\\n mstore(add(_vk, 0x340), 0x1fb4c449e6bd67bc3dd0ec09e740bd5895b1952f2c42a54c0eb8d59ffa4f81e4) // vk.SIGMA2.x\\n mstore(add(_vk, 0x360), 0x15914e6eac131c6c3e51703646e5524a0be256a25f0a29ac12aca19352c9bff6) // vk.SIGMA2.y\\n mstore(add(_vk, 0x380), 0x2ea86576148d8d46e4b782c77af341f15b7d0d68f661b3445f6476dd54a7a558) // vk.SIGMA3.x\\n mstore(add(_vk, 0x3a0), 0x1e1bee942b8d63fb9e4a324d07f538d69a0b9d895a0e765e8116df0dd41350b3) // vk.SIGMA3.y\\n mstore(add(_vk, 0x3c0), 0x1a97a02b48f748c9fe2dcc9c3f829b2ea194f120c1110a43080112108eacad9e) // vk.SIGMA4.x\\n mstore(add(_vk, 0x3e0), 0x1dcab1530e972eb87903764308228f9c6eb1e0a8ece757616146eb9ac92f41a0) // vk.SIGMA4.y\\n mstore(add(_vk, 0x400), 0x12037992a0868b71fd31e8afdd2eadb65703eb9b066f46619795addc76c4c040) // vk.TABLE1.x\\n mstore(add(_vk, 0x420), 0x03087c87f8e680e93787d0b1ee1e7b03a361953026880f136896be768c398a52) // vk.TABLE1.y\\n mstore(add(_vk, 0x440), 0x20333b8a625e44316eb415594db2fb1418360858b9bbd871eb602d1e2d99aec3) // vk.TABLE2.x\\n mstore(add(_vk, 0x460), 0x071cff58e911f0bfbb01a49556356929c0d32d3a343fb91c62728b5f40ef9c2e) // vk.TABLE2.y\\n mstore(add(_vk, 0x480), 0x05ea76ef86cb4a6516241f0ffd1cb4a3d08911ed1785b2c2e5d21d03160af911) // vk.TABLE3.x\\n mstore(add(_vk, 0x4a0), 0x04bf914031bd405440af705425e95109b8ccb07be5f521baf78522a47f808aef) // vk.TABLE3.y\\n mstore(add(_vk, 0x4c0), 0x17841405ffd5b7391dfc4c67df8b83b829c04c6c39fa304c63ba85efc356cb6b) // vk.TABLE4.x\\n mstore(add(_vk, 0x4e0), 0x071662508f56a08c39f23e3b574939b610830931daaf5f8c7da09d8341423e72) // vk.TABLE4.y\\n mstore(add(_vk, 0x500), 0x2cd0adb4efab7c1f2f3ce467113f6b5a60ab824b86852c995d83e87af264bd71) // vk.TABLE_TYPE.x\\n mstore(add(_vk, 0x520), 0x0c6a58624d7220202551ec32fe8abdd14f9830dc08578941185a66282cb04948) // vk.TABLE_TYPE.y\\n mstore(add(_vk, 0x540), 0x13f7aa6c469715e6cd1f38bf20c9b09078403df8217f9d30df97aae41d460f40) // vk.ID1.x\\n mstore(add(_vk, 0x560), 0x02944c0148d257c53e52d2ea61b6fcfedf6dc6861d4833893f5b2f367e68232f) // vk.ID1.y\\n mstore(add(_vk, 0x580), 0x0737ea2401dff83ecc5d6258aec1533b305e85a418c2a8c2fbec7bf6fbc39599) // vk.ID2.x\\n mstore(add(_vk, 0x5a0), 0x108fb619aec96784857cd68447c8455790602ef51e7e6e4c7cdc416831a9ab50) // vk.ID2.y\\n mstore(add(_vk, 0x5c0), 0x1064d92338c133f3c77d13a7d4d688f94216dca3143f8ff96aa5b9530295cc97) // vk.ID3.x\\n mstore(add(_vk, 0x5e0), 0x2336336f949cb51eab3edeb98bbeeb7aecd353fda918c1ee5aea9d01f1e2b446) // vk.ID3.y\\n mstore(add(_vk, 0x600), 0x1beb44efe9150760b8b668dd41a5229e21258845fb446004f5b5501ba4a6495c) // vk.ID4.x\\n mstore(add(_vk, 0x620), 0x1c7187e828b8c1ef699c55a031ca21baeea080a8f70a7e41b41ea35eff4ffeb0) // vk.ID4.y\\n mstore(add(_vk, 0x640), 0x00) // vk.contains_pairing_point_accumulator\\n mstore(add(_vk, 0x660), 0) // vk.pairing_point_accumulator_public_input_indices\\n mstore(add(_vk, 0x680), 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1) // vk.g2_x.X.c1 \\n mstore(add(_vk, 0x6a0), 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0) // vk.g2_x.X.c0 \\n mstore(add(_vk, 0x6c0), 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4) // vk.g2_x.Y.c1 \\n mstore(add(_vk, 0x6e0), 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55) // vk.g2_x.Y.c0 \\n mstore(_omegaInverseLoc, 0x036853f083780e87f8d7c71d111119c57dbe118c22d5ad707a82317466c5174c) // vk.work_root_inverse\\n }\\n }\\n}\\n\\n/**\\n * @title Ultra Plonk proof verification contract\\n * @dev Top level Plonk proof verification contract, which allows Plonk proof to be verified\\n */\\nabstract contract BaseUltraVerifier {\\n // VERIFICATION KEY MEMORY LOCATIONS\\n uint256 internal constant N_LOC = 0x380;\\n uint256 internal constant NUM_INPUTS_LOC = 0x3a0;\\n uint256 internal constant OMEGA_LOC = 0x3c0;\\n uint256 internal constant DOMAIN_INVERSE_LOC = 0x3e0;\\n uint256 internal constant Q1_X_LOC = 0x400;\\n uint256 internal constant Q1_Y_LOC = 0x420;\\n uint256 internal constant Q2_X_LOC = 0x440;\\n uint256 internal constant Q2_Y_LOC = 0x460;\\n uint256 internal constant Q3_X_LOC = 0x480;\\n uint256 internal constant Q3_Y_LOC = 0x4a0;\\n uint256 internal constant Q4_X_LOC = 0x4c0;\\n uint256 internal constant Q4_Y_LOC = 0x4e0;\\n uint256 internal constant QM_X_LOC = 0x500;\\n uint256 internal constant QM_Y_LOC = 0x520;\\n uint256 internal constant QC_X_LOC = 0x540;\\n uint256 internal constant QC_Y_LOC = 0x560;\\n uint256 internal constant QARITH_X_LOC = 0x580;\\n uint256 internal constant QARITH_Y_LOC = 0x5a0;\\n uint256 internal constant QSORT_X_LOC = 0x5c0;\\n uint256 internal constant QSORT_Y_LOC = 0x5e0;\\n uint256 internal constant QELLIPTIC_X_LOC = 0x600;\\n uint256 internal constant QELLIPTIC_Y_LOC = 0x620;\\n uint256 internal constant QAUX_X_LOC = 0x640;\\n uint256 internal constant QAUX_Y_LOC = 0x660;\\n uint256 internal constant SIGMA1_X_LOC = 0x680;\\n uint256 internal constant SIGMA1_Y_LOC = 0x6a0;\\n uint256 internal constant SIGMA2_X_LOC = 0x6c0;\\n uint256 internal constant SIGMA2_Y_LOC = 0x6e0;\\n uint256 internal constant SIGMA3_X_LOC = 0x700;\\n uint256 internal constant SIGMA3_Y_LOC = 0x720;\\n uint256 internal constant SIGMA4_X_LOC = 0x740;\\n uint256 internal constant SIGMA4_Y_LOC = 0x760;\\n uint256 internal constant TABLE1_X_LOC = 0x780;\\n uint256 internal constant TABLE1_Y_LOC = 0x7a0;\\n uint256 internal constant TABLE2_X_LOC = 0x7c0;\\n uint256 internal constant TABLE2_Y_LOC = 0x7e0;\\n uint256 internal constant TABLE3_X_LOC = 0x800;\\n uint256 internal constant TABLE3_Y_LOC = 0x820;\\n uint256 internal constant TABLE4_X_LOC = 0x840;\\n uint256 internal constant TABLE4_Y_LOC = 0x860;\\n uint256 internal constant TABLE_TYPE_X_LOC = 0x880;\\n uint256 internal constant TABLE_TYPE_Y_LOC = 0x8a0;\\n uint256 internal constant ID1_X_LOC = 0x8c0;\\n uint256 internal constant ID1_Y_LOC = 0x8e0;\\n uint256 internal constant ID2_X_LOC = 0x900;\\n uint256 internal constant ID2_Y_LOC = 0x920;\\n uint256 internal constant ID3_X_LOC = 0x940;\\n uint256 internal constant ID3_Y_LOC = 0x960;\\n uint256 internal constant ID4_X_LOC = 0x980;\\n uint256 internal constant ID4_Y_LOC = 0x9a0;\\n uint256 internal constant CONTAINS_RECURSIVE_PROOF_LOC = 0x9c0;\\n uint256 internal constant RECURSIVE_PROOF_PUBLIC_INPUT_INDICES_LOC = 0x9e0;\\n uint256 internal constant G2X_X0_LOC = 0xa00;\\n uint256 internal constant G2X_X1_LOC = 0xa20;\\n uint256 internal constant G2X_Y0_LOC = 0xa40;\\n uint256 internal constant G2X_Y1_LOC = 0xa60;\\n\\n // ### PROOF DATA MEMORY LOCATIONS\\n uint256 internal constant W1_X_LOC = 0x1200;\\n uint256 internal constant W1_Y_LOC = 0x1220;\\n uint256 internal constant W2_X_LOC = 0x1240;\\n uint256 internal constant W2_Y_LOC = 0x1260;\\n uint256 internal constant W3_X_LOC = 0x1280;\\n uint256 internal constant W3_Y_LOC = 0x12a0;\\n uint256 internal constant W4_X_LOC = 0x12c0;\\n uint256 internal constant W4_Y_LOC = 0x12e0;\\n uint256 internal constant S_X_LOC = 0x1300;\\n uint256 internal constant S_Y_LOC = 0x1320;\\n uint256 internal constant Z_X_LOC = 0x1340;\\n uint256 internal constant Z_Y_LOC = 0x1360;\\n uint256 internal constant Z_LOOKUP_X_LOC = 0x1380;\\n uint256 internal constant Z_LOOKUP_Y_LOC = 0x13a0;\\n uint256 internal constant T1_X_LOC = 0x13c0;\\n uint256 internal constant T1_Y_LOC = 0x13e0;\\n uint256 internal constant T2_X_LOC = 0x1400;\\n uint256 internal constant T2_Y_LOC = 0x1420;\\n uint256 internal constant T3_X_LOC = 0x1440;\\n uint256 internal constant T3_Y_LOC = 0x1460;\\n uint256 internal constant T4_X_LOC = 0x1480;\\n uint256 internal constant T4_Y_LOC = 0x14a0;\\n\\n uint256 internal constant W1_EVAL_LOC = 0x1600;\\n uint256 internal constant W2_EVAL_LOC = 0x1620;\\n uint256 internal constant W3_EVAL_LOC = 0x1640;\\n uint256 internal constant W4_EVAL_LOC = 0x1660;\\n uint256 internal constant S_EVAL_LOC = 0x1680;\\n uint256 internal constant Z_EVAL_LOC = 0x16a0;\\n uint256 internal constant Z_LOOKUP_EVAL_LOC = 0x16c0;\\n uint256 internal constant Q1_EVAL_LOC = 0x16e0;\\n uint256 internal constant Q2_EVAL_LOC = 0x1700;\\n uint256 internal constant Q3_EVAL_LOC = 0x1720;\\n uint256 internal constant Q4_EVAL_LOC = 0x1740;\\n uint256 internal constant QM_EVAL_LOC = 0x1760;\\n uint256 internal constant QC_EVAL_LOC = 0x1780;\\n uint256 internal constant QARITH_EVAL_LOC = 0x17a0;\\n uint256 internal constant QSORT_EVAL_LOC = 0x17c0;\\n uint256 internal constant QELLIPTIC_EVAL_LOC = 0x17e0;\\n uint256 internal constant QAUX_EVAL_LOC = 0x1800;\\n uint256 internal constant TABLE1_EVAL_LOC = 0x1840;\\n uint256 internal constant TABLE2_EVAL_LOC = 0x1860;\\n uint256 internal constant TABLE3_EVAL_LOC = 0x1880;\\n uint256 internal constant TABLE4_EVAL_LOC = 0x18a0;\\n uint256 internal constant TABLE_TYPE_EVAL_LOC = 0x18c0;\\n uint256 internal constant ID1_EVAL_LOC = 0x18e0;\\n uint256 internal constant ID2_EVAL_LOC = 0x1900;\\n uint256 internal constant ID3_EVAL_LOC = 0x1920;\\n uint256 internal constant ID4_EVAL_LOC = 0x1940;\\n uint256 internal constant SIGMA1_EVAL_LOC = 0x1960;\\n uint256 internal constant SIGMA2_EVAL_LOC = 0x1980;\\n uint256 internal constant SIGMA3_EVAL_LOC = 0x19a0;\\n uint256 internal constant SIGMA4_EVAL_LOC = 0x19c0;\\n uint256 internal constant W1_OMEGA_EVAL_LOC = 0x19e0;\\n uint256 internal constant W2_OMEGA_EVAL_LOC = 0x2000;\\n uint256 internal constant W3_OMEGA_EVAL_LOC = 0x2020;\\n uint256 internal constant W4_OMEGA_EVAL_LOC = 0x2040;\\n uint256 internal constant S_OMEGA_EVAL_LOC = 0x2060;\\n uint256 internal constant Z_OMEGA_EVAL_LOC = 0x2080;\\n uint256 internal constant Z_LOOKUP_OMEGA_EVAL_LOC = 0x20a0;\\n uint256 internal constant TABLE1_OMEGA_EVAL_LOC = 0x20c0;\\n uint256 internal constant TABLE2_OMEGA_EVAL_LOC = 0x20e0;\\n uint256 internal constant TABLE3_OMEGA_EVAL_LOC = 0x2100;\\n uint256 internal constant TABLE4_OMEGA_EVAL_LOC = 0x2120;\\n\\n uint256 internal constant PI_Z_X_LOC = 0x2300;\\n uint256 internal constant PI_Z_Y_LOC = 0x2320;\\n uint256 internal constant PI_Z_OMEGA_X_LOC = 0x2340;\\n uint256 internal constant PI_Z_OMEGA_Y_LOC = 0x2360;\\n\\n // Used for elliptic widget. These are alias names for wire + shifted wire evaluations\\n uint256 internal constant X1_EVAL_LOC = W2_EVAL_LOC;\\n uint256 internal constant X2_EVAL_LOC = W1_OMEGA_EVAL_LOC;\\n uint256 internal constant X3_EVAL_LOC = W2_OMEGA_EVAL_LOC;\\n uint256 internal constant Y1_EVAL_LOC = W3_EVAL_LOC;\\n uint256 internal constant Y2_EVAL_LOC = W4_OMEGA_EVAL_LOC;\\n uint256 internal constant Y3_EVAL_LOC = W3_OMEGA_EVAL_LOC;\\n uint256 internal constant QBETA_LOC = Q3_EVAL_LOC;\\n uint256 internal constant QBETA_SQR_LOC = Q4_EVAL_LOC;\\n uint256 internal constant QSIGN_LOC = Q1_EVAL_LOC;\\n\\n // ### CHALLENGES MEMORY OFFSETS\\n\\n uint256 internal constant C_BETA_LOC = 0x2600;\\n uint256 internal constant C_GAMMA_LOC = 0x2620;\\n uint256 internal constant C_ALPHA_LOC = 0x2640;\\n uint256 internal constant C_ETA_LOC = 0x2660;\\n uint256 internal constant C_ETA_SQR_LOC = 0x2680;\\n uint256 internal constant C_ETA_CUBE_LOC = 0x26a0;\\n\\n uint256 internal constant C_ZETA_LOC = 0x26c0;\\n uint256 internal constant C_CURRENT_LOC = 0x26e0;\\n uint256 internal constant C_V0_LOC = 0x2700;\\n uint256 internal constant C_V1_LOC = 0x2720;\\n uint256 internal constant C_V2_LOC = 0x2740;\\n uint256 internal constant C_V3_LOC = 0x2760;\\n uint256 internal constant C_V4_LOC = 0x2780;\\n uint256 internal constant C_V5_LOC = 0x27a0;\\n uint256 internal constant C_V6_LOC = 0x27c0;\\n uint256 internal constant C_V7_LOC = 0x27e0;\\n uint256 internal constant C_V8_LOC = 0x2800;\\n uint256 internal constant C_V9_LOC = 0x2820;\\n uint256 internal constant C_V10_LOC = 0x2840;\\n uint256 internal constant C_V11_LOC = 0x2860;\\n uint256 internal constant C_V12_LOC = 0x2880;\\n uint256 internal constant C_V13_LOC = 0x28a0;\\n uint256 internal constant C_V14_LOC = 0x28c0;\\n uint256 internal constant C_V15_LOC = 0x28e0;\\n uint256 internal constant C_V16_LOC = 0x2900;\\n uint256 internal constant C_V17_LOC = 0x2920;\\n uint256 internal constant C_V18_LOC = 0x2940;\\n uint256 internal constant C_V19_LOC = 0x2960;\\n uint256 internal constant C_V20_LOC = 0x2980;\\n uint256 internal constant C_V21_LOC = 0x29a0;\\n uint256 internal constant C_V22_LOC = 0x29c0;\\n uint256 internal constant C_V23_LOC = 0x29e0;\\n uint256 internal constant C_V24_LOC = 0x2a00;\\n uint256 internal constant C_V25_LOC = 0x2a20;\\n uint256 internal constant C_V26_LOC = 0x2a40;\\n uint256 internal constant C_V27_LOC = 0x2a60;\\n uint256 internal constant C_V28_LOC = 0x2a80;\\n uint256 internal constant C_V29_LOC = 0x2aa0;\\n uint256 internal constant C_V30_LOC = 0x2ac0;\\n\\n uint256 internal constant C_U_LOC = 0x2b00;\\n\\n // ### LOCAL VARIABLES MEMORY OFFSETS\\n uint256 internal constant DELTA_NUMERATOR_LOC = 0x3000;\\n uint256 internal constant DELTA_DENOMINATOR_LOC = 0x3020;\\n uint256 internal constant ZETA_POW_N_LOC = 0x3040;\\n uint256 internal constant PUBLIC_INPUT_DELTA_LOC = 0x3060;\\n uint256 internal constant ZERO_POLY_LOC = 0x3080;\\n uint256 internal constant L_START_LOC = 0x30a0;\\n uint256 internal constant L_END_LOC = 0x30c0;\\n uint256 internal constant R_ZERO_EVAL_LOC = 0x30e0;\\n\\n uint256 internal constant PLOOKUP_DELTA_NUMERATOR_LOC = 0x3100;\\n uint256 internal constant PLOOKUP_DELTA_DENOMINATOR_LOC = 0x3120;\\n uint256 internal constant PLOOKUP_DELTA_LOC = 0x3140;\\n\\n uint256 internal constant ACCUMULATOR_X_LOC = 0x3160;\\n uint256 internal constant ACCUMULATOR_Y_LOC = 0x3180;\\n uint256 internal constant ACCUMULATOR2_X_LOC = 0x31a0;\\n uint256 internal constant ACCUMULATOR2_Y_LOC = 0x31c0;\\n uint256 internal constant PAIRING_LHS_X_LOC = 0x31e0;\\n uint256 internal constant PAIRING_LHS_Y_LOC = 0x3200;\\n uint256 internal constant PAIRING_RHS_X_LOC = 0x3220;\\n uint256 internal constant PAIRING_RHS_Y_LOC = 0x3240;\\n\\n // misc stuff\\n uint256 internal constant OMEGA_INVERSE_LOC = 0x3300;\\n uint256 internal constant C_ALPHA_SQR_LOC = 0x3320;\\n uint256 internal constant C_ALPHA_CUBE_LOC = 0x3340;\\n uint256 internal constant C_ALPHA_QUAD_LOC = 0x3360;\\n uint256 internal constant C_ALPHA_BASE_LOC = 0x3380;\\n\\n // ### RECURSION VARIABLE MEMORY LOCATIONS\\n uint256 internal constant RECURSIVE_P1_X_LOC = 0x3400;\\n uint256 internal constant RECURSIVE_P1_Y_LOC = 0x3420;\\n uint256 internal constant RECURSIVE_P2_X_LOC = 0x3440;\\n uint256 internal constant RECURSIVE_P2_Y_LOC = 0x3460;\\n uint256 internal constant PUBLIC_INPUTS_HASH_LOCATION = 0x3480;\\n\\n // sub-identity storage\\n uint256 internal constant PERMUTATION_IDENTITY = 0x3500;\\n uint256 internal constant PLOOKUP_IDENTITY = 0x3520;\\n uint256 internal constant ARITHMETIC_IDENTITY = 0x3540;\\n uint256 internal constant SORT_IDENTITY = 0x3560;\\n uint256 internal constant ELLIPTIC_IDENTITY = 0x3580;\\n uint256 internal constant AUX_IDENTITY = 0x35a0;\\n uint256 internal constant AUX_NON_NATIVE_FIELD_EVALUATION = 0x35c0;\\n uint256 internal constant AUX_LIMB_ACCUMULATOR_EVALUATION = 0x35e0;\\n uint256 internal constant AUX_RAM_CONSISTENCY_EVALUATION = 0x3600;\\n uint256 internal constant AUX_ROM_CONSISTENCY_EVALUATION = 0x3620;\\n uint256 internal constant AUX_MEMORY_EVALUATION = 0x3640;\\n\\n uint256 internal constant QUOTIENT_EVAL_LOC = 0x3660;\\n uint256 internal constant ZERO_POLY_INVERSE_LOC = 0x3680;\\n\\n // when hashing public inputs we use memory at NU_CHALLENGE_INPUT_LOC_A, as the hash input size is unknown at compile time\\n uint256 internal constant NU_CHALLENGE_INPUT_LOC_A = 0x36a0;\\n uint256 internal constant NU_CHALLENGE_INPUT_LOC_B = 0x36c0;\\n uint256 internal constant NU_CHALLENGE_INPUT_LOC_C = 0x36e0;\\n\\n bytes4 internal constant INVALID_VERIFICATION_KEY_SELECTOR = 0x7e5769bf;\\n bytes4 internal constant POINT_NOT_ON_CURVE_SELECTOR = 0xa3dad654;\\n bytes4 internal constant PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR = 0xeba9f4a6;\\n bytes4 internal constant PUBLIC_INPUT_GE_P_SELECTOR = 0x374a972f;\\n bytes4 internal constant MOD_EXP_FAILURE_SELECTOR = 0xf894a7bc;\\n bytes4 internal constant PAIRING_PREAMBLE_FAILED_SELECTOR = 0x01882d81;\\n bytes4 internal constant OPENING_COMMITMENT_FAILED_SELECTOR = 0x4e719763;\\n bytes4 internal constant PAIRING_FAILED_SELECTOR = 0xd71fd263;\\n\\n uint256 internal constant ETA_INPUT_LENGTH = 0xc0; // W1, W2, W3 = 6 * 0x20 bytes\\n\\n // We need to hash 41 field elements when generating the NU challenge\\n // w1, w2, w3, w4, s, z, z_lookup, q1, q2, q3, q4, qm, qc, qarith (14)\\n // qsort, qelliptic, qaux, sigma1, sigma2, sigma, sigma4, (7)\\n // table1, table2, table3, table4, tabletype, id1, id2, id3, id4, (9)\\n // w1_omega, w2_omega, w3_omega, w4_omega, s_omega, z_omega, z_lookup_omega, (7)\\n // table1_omega, table2_omega, table3_omega, table4_omega (4)\\n uint256 internal constant NU_INPUT_LENGTH = 0x520; // 0x520 = 41 * 0x20\\n\\n // There are ELEVEN G1 group elements added into the transcript in the `beta` round, that we need to skip over\\n // W1, W2, W3, W4, S, Z, Z_LOOKUP, T1, T2, T3, T4\\n uint256 internal constant NU_CALLDATA_SKIP_LENGTH = 0x2c0; // 11 * 0x40 = 0x2c0\\n\\n uint256 internal constant NEGATIVE_INVERSE_OF_2_MODULO_P =\\n 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000;\\n uint256 internal constant LIMB_SIZE = 0x100000000000000000; // 2<<68\\n uint256 internal constant SUBLIMB_SHIFT = 0x4000; // 2<<14\\n\\n // y^2 = x^3 + ax + b\\n // for Grumpkin, a = 0 and b = -17. We use b in a custom gate relation that evaluates elliptic curve arithmetic\\n uint256 internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = 17;\\n\\n error INVALID_VERIFICATION_KEY();\\n error POINT_NOT_ON_CURVE();\\n error PUBLIC_INPUT_COUNT_INVALID(uint256 expected, uint256 actual);\\n error PUBLIC_INPUT_INVALID_BN128_G1_POINT();\\n error PUBLIC_INPUT_GE_P();\\n error MOD_EXP_FAILURE();\\n error PAIRING_PREAMBLE_FAILED();\\n error OPENING_COMMITMENT_FAILED();\\n error PAIRING_FAILED();\\n\\n function getVerificationKeyHash() public pure virtual returns (bytes32);\\n\\n /**\\n * @dev We assume that the verification key loaded by this function is constant as we only verify it on deployment\\n */\\n function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure virtual;\\n\\n constructor() { \\n loadVerificationKey(N_LOC, OMEGA_INVERSE_LOC);\\n\\n // We verify that all of the EC points in the verification key lie on the bn128 curve. \\n assembly {\\n let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // EC group order\\n\\n let success := 1\\n\\n // VALIDATE Q1\\n {\\n let x := mload(Q1_X_LOC)\\n let y := mload(Q1_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n // VALIDATE Q2\\n {\\n let x := mload(Q2_X_LOC)\\n let y := mload(Q2_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n // VALIDATE Q3\\n {\\n let x := mload(Q3_X_LOC)\\n let y := mload(Q3_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n // VALIDATE Q4\\n {\\n let x := mload(Q4_X_LOC)\\n let y := mload(Q4_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n mstore(0x00, x)\\n mstore(0x20, y)\\n }\\n // VALIDATE QM\\n {\\n let x := mload(QM_X_LOC)\\n let y := mload(QM_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n // VALIDATE QC\\n {\\n let x := mload(QC_X_LOC)\\n let y := mload(QC_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n // VALIDATE QARITH\\n {\\n let x := mload(QARITH_X_LOC)\\n let y := mload(QARITH_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n // VALIDATE QSORT\\n {\\n let x := mload(QSORT_X_LOC)\\n let y := mload(QSORT_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n // VALIDATE QELLIPTIC\\n {\\n let x := mload(QELLIPTIC_X_LOC)\\n let y := mload(QELLIPTIC_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n // VALIDATE QAUX\\n {\\n let x := mload(QAUX_X_LOC)\\n let y := mload(QAUX_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n // VALIDATE SIGMA1\\n {\\n let x := mload(SIGMA1_X_LOC)\\n let y := mload(SIGMA1_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n // VALIDATE SIGMA2\\n {\\n let x := mload(SIGMA2_X_LOC)\\n let y := mload(SIGMA2_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n // VALIDATE SIGMA3\\n {\\n let x := mload(SIGMA3_X_LOC)\\n let y := mload(SIGMA3_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n // VALIDATE SIGMA4\\n {\\n let x := mload(SIGMA4_X_LOC)\\n let y := mload(SIGMA4_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n // VALIDATE TABLE1\\n {\\n let x := mload(TABLE1_X_LOC)\\n let y := mload(TABLE1_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n } \\n // VALIDATE TABLE2\\n {\\n let x := mload(TABLE2_X_LOC)\\n let y := mload(TABLE2_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n } \\n // VALIDATE TABLE3\\n {\\n let x := mload(TABLE3_X_LOC)\\n let y := mload(TABLE3_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n } \\n // VALIDATE TABLE4\\n {\\n let x := mload(TABLE4_X_LOC)\\n let y := mload(TABLE4_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n } \\n // VALIDATE TABLE_TYPE\\n {\\n let x := mload(TABLE_TYPE_X_LOC)\\n let y := mload(TABLE_TYPE_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n // VALIDATE ID1\\n {\\n let x := mload(ID1_X_LOC)\\n let y := mload(ID1_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n // VALIDATE ID2\\n {\\n let x := mload(ID2_X_LOC)\\n let y := mload(ID2_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n // VALIDATE ID3\\n {\\n let x := mload(ID3_X_LOC)\\n let y := mload(ID3_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n // VALIDATE ID4\\n {\\n let x := mload(ID4_X_LOC)\\n let y := mload(ID4_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\\n }\\n\\n if iszero(success) {\\n mstore(0x0, INVALID_VERIFICATION_KEY_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n }\\n }\\n\\n /**\\n * @notice Verify a Ultra Plonk proof\\n * @param _proof - The serialized proof\\n * @param _publicInputs - An array of the public inputs\\n * @return True if proof is valid, reverts otherwise\\n */\\n function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) {\\n loadVerificationKey(N_LOC, OMEGA_INVERSE_LOC);\\n\\n uint256 requiredPublicInputCount;\\n assembly {\\n requiredPublicInputCount := mload(NUM_INPUTS_LOC)\\n }\\n if (requiredPublicInputCount != _publicInputs.length) {\\n revert PUBLIC_INPUT_COUNT_INVALID(requiredPublicInputCount, _publicInputs.length);\\n }\\n\\n assembly {\\n let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // EC group order\\n let p := 21888242871839275222246405745257275088548364400416034343698204186575808495617 // Prime field order\\n\\n /**\\n * LOAD PROOF FROM CALLDATA\\n */\\n {\\n let data_ptr := add(calldataload(0x04), 0x24)\\n\\n mstore(W1_Y_LOC, mod(calldataload(data_ptr), q))\\n mstore(W1_X_LOC, mod(calldataload(add(data_ptr, 0x20)), q))\\n\\n mstore(W2_Y_LOC, mod(calldataload(add(data_ptr, 0x40)), q))\\n mstore(W2_X_LOC, mod(calldataload(add(data_ptr, 0x60)), q))\\n\\n mstore(W3_Y_LOC, mod(calldataload(add(data_ptr, 0x80)), q))\\n mstore(W3_X_LOC, mod(calldataload(add(data_ptr, 0xa0)), q))\\n\\n mstore(W4_Y_LOC, mod(calldataload(add(data_ptr, 0xc0)), q))\\n mstore(W4_X_LOC, mod(calldataload(add(data_ptr, 0xe0)), q))\\n\\n mstore(S_Y_LOC, mod(calldataload(add(data_ptr, 0x100)), q))\\n mstore(S_X_LOC, mod(calldataload(add(data_ptr, 0x120)), q))\\n mstore(Z_Y_LOC, mod(calldataload(add(data_ptr, 0x140)), q))\\n mstore(Z_X_LOC, mod(calldataload(add(data_ptr, 0x160)), q))\\n mstore(Z_LOOKUP_Y_LOC, mod(calldataload(add(data_ptr, 0x180)), q))\\n mstore(Z_LOOKUP_X_LOC, mod(calldataload(add(data_ptr, 0x1a0)), q))\\n mstore(T1_Y_LOC, mod(calldataload(add(data_ptr, 0x1c0)), q))\\n mstore(T1_X_LOC, mod(calldataload(add(data_ptr, 0x1e0)), q))\\n\\n mstore(T2_Y_LOC, mod(calldataload(add(data_ptr, 0x200)), q))\\n mstore(T2_X_LOC, mod(calldataload(add(data_ptr, 0x220)), q))\\n\\n mstore(T3_Y_LOC, mod(calldataload(add(data_ptr, 0x240)), q))\\n mstore(T3_X_LOC, mod(calldataload(add(data_ptr, 0x260)), q))\\n\\n mstore(T4_Y_LOC, mod(calldataload(add(data_ptr, 0x280)), q))\\n mstore(T4_X_LOC, mod(calldataload(add(data_ptr, 0x2a0)), q))\\n\\n mstore(W1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x2c0)), p))\\n mstore(W2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x2e0)), p))\\n mstore(W3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x300)), p))\\n mstore(W4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x320)), p))\\n mstore(S_EVAL_LOC, mod(calldataload(add(data_ptr, 0x340)), p))\\n mstore(Z_EVAL_LOC, mod(calldataload(add(data_ptr, 0x360)), p))\\n mstore(Z_LOOKUP_EVAL_LOC, mod(calldataload(add(data_ptr, 0x380)), p))\\n mstore(Q1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3a0)), p))\\n mstore(Q2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3c0)), p))\\n mstore(Q3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3e0)), p))\\n mstore(Q4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x400)), p))\\n mstore(QM_EVAL_LOC, mod(calldataload(add(data_ptr, 0x420)), p))\\n mstore(QC_EVAL_LOC, mod(calldataload(add(data_ptr, 0x440)), p))\\n mstore(QARITH_EVAL_LOC, mod(calldataload(add(data_ptr, 0x460)), p))\\n mstore(QSORT_EVAL_LOC, mod(calldataload(add(data_ptr, 0x480)), p))\\n mstore(QELLIPTIC_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4a0)), p))\\n mstore(QAUX_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4c0)), p))\\n\\n mstore(SIGMA1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4e0)), p))\\n mstore(SIGMA2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x500)), p))\\n\\n mstore(SIGMA3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x520)), p))\\n mstore(SIGMA4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x540)), p))\\n\\n mstore(TABLE1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x560)), p))\\n mstore(TABLE2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x580)), p))\\n mstore(TABLE3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5a0)), p))\\n mstore(TABLE4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5c0)), p))\\n mstore(TABLE_TYPE_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5e0)), p))\\n\\n mstore(ID1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x600)), p))\\n mstore(ID2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x620)), p))\\n mstore(ID3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x640)), p))\\n mstore(ID4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x660)), p))\\n\\n mstore(W1_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x680)), p))\\n mstore(W2_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6a0)), p))\\n mstore(W3_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6c0)), p))\\n mstore(W4_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6e0)), p))\\n mstore(S_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x700)), p))\\n\\n mstore(Z_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x720)), p))\\n\\n mstore(Z_LOOKUP_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x740)), p))\\n mstore(TABLE1_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x760)), p))\\n mstore(TABLE2_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x780)), p))\\n mstore(TABLE3_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x7a0)), p))\\n mstore(TABLE4_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x7c0)), p))\\n\\n mstore(PI_Z_Y_LOC, mod(calldataload(add(data_ptr, 0x7e0)), q))\\n mstore(PI_Z_X_LOC, mod(calldataload(add(data_ptr, 0x800)), q))\\n\\n mstore(PI_Z_OMEGA_Y_LOC, mod(calldataload(add(data_ptr, 0x820)), q))\\n mstore(PI_Z_OMEGA_X_LOC, mod(calldataload(add(data_ptr, 0x840)), q))\\n }\\n\\n /**\\n * LOAD RECURSIVE PROOF INTO MEMORY\\n */\\n {\\n if mload(CONTAINS_RECURSIVE_PROOF_LOC) {\\n let public_inputs_ptr := add(calldataload(0x24), 0x24)\\n let index_counter := add(shl(5, mload(RECURSIVE_PROOF_PUBLIC_INPUT_INDICES_LOC)), public_inputs_ptr)\\n\\n let x0 := calldataload(index_counter)\\n x0 := add(x0, shl(68, calldataload(add(index_counter, 0x20))))\\n x0 := add(x0, shl(136, calldataload(add(index_counter, 0x40))))\\n x0 := add(x0, shl(204, calldataload(add(index_counter, 0x60))))\\n let y0 := calldataload(add(index_counter, 0x80))\\n y0 := add(y0, shl(68, calldataload(add(index_counter, 0xa0))))\\n y0 := add(y0, shl(136, calldataload(add(index_counter, 0xc0))))\\n y0 := add(y0, shl(204, calldataload(add(index_counter, 0xe0))))\\n let x1 := calldataload(add(index_counter, 0x100))\\n x1 := add(x1, shl(68, calldataload(add(index_counter, 0x120))))\\n x1 := add(x1, shl(136, calldataload(add(index_counter, 0x140))))\\n x1 := add(x1, shl(204, calldataload(add(index_counter, 0x160))))\\n let y1 := calldataload(add(index_counter, 0x180))\\n y1 := add(y1, shl(68, calldataload(add(index_counter, 0x1a0))))\\n y1 := add(y1, shl(136, calldataload(add(index_counter, 0x1c0))))\\n y1 := add(y1, shl(204, calldataload(add(index_counter, 0x1e0))))\\n mstore(RECURSIVE_P1_X_LOC, x0)\\n mstore(RECURSIVE_P1_Y_LOC, y0)\\n mstore(RECURSIVE_P2_X_LOC, x1)\\n mstore(RECURSIVE_P2_Y_LOC, y1)\\n\\n // validate these are valid bn128 G1 points\\n if iszero(and(and(lt(x0, q), lt(x1, q)), and(lt(y0, q), lt(y1, q)))) {\\n mstore(0x00, PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n }\\n }\\n\\n {\\n /**\\n * Generate initial challenge\\n */\\n mstore(0x00, shl(224, mload(N_LOC)))\\n mstore(0x04, shl(224, mload(NUM_INPUTS_LOC)))\\n let challenge := keccak256(0x00, 0x08)\\n\\n /**\\n * Generate eta challenge\\n */\\n mstore(PUBLIC_INPUTS_HASH_LOCATION, challenge)\\n // The public input location is stored at 0x24, we then add 0x24 to skip selector and the length of public inputs\\n let public_inputs_start := add(calldataload(0x24), 0x24)\\n // copy the public inputs over\\n let public_input_size := mul(mload(NUM_INPUTS_LOC), 0x20)\\n calldatacopy(add(PUBLIC_INPUTS_HASH_LOCATION, 0x20), public_inputs_start, public_input_size)\\n\\n // copy W1, W2, W3 into challenge. Each point is 0x40 bytes, so load 0xc0 = 3 * 0x40 bytes (ETA input length)\\n let w_start := add(calldataload(0x04), 0x24)\\n calldatacopy(add(add(PUBLIC_INPUTS_HASH_LOCATION, 0x20), public_input_size), w_start, ETA_INPUT_LENGTH)\\n\\n // Challenge is the old challenge + public inputs + W1, W2, W3 (0x20 + public_input_size + 0xc0)\\n let challenge_bytes_size := add(0x20, add(public_input_size, ETA_INPUT_LENGTH))\\n\\n challenge := keccak256(PUBLIC_INPUTS_HASH_LOCATION, challenge_bytes_size)\\n {\\n let eta := mod(challenge, p)\\n mstore(C_ETA_LOC, eta)\\n mstore(C_ETA_SQR_LOC, mulmod(eta, eta, p))\\n mstore(C_ETA_CUBE_LOC, mulmod(mload(C_ETA_SQR_LOC), eta, p))\\n }\\n\\n /**\\n * Generate beta challenge\\n */\\n mstore(0x00, challenge)\\n mstore(0x20, mload(W4_Y_LOC))\\n mstore(0x40, mload(W4_X_LOC))\\n mstore(0x60, mload(S_Y_LOC))\\n mstore(0x80, mload(S_X_LOC))\\n challenge := keccak256(0x00, 0xa0)\\n mstore(C_BETA_LOC, mod(challenge, p))\\n\\n /**\\n * Generate gamma challenge\\n */\\n mstore(0x00, challenge)\\n mstore8(0x20, 0x01)\\n challenge := keccak256(0x00, 0x21)\\n mstore(C_GAMMA_LOC, mod(challenge, p))\\n\\n /**\\n * Generate alpha challenge\\n */\\n mstore(0x00, challenge)\\n mstore(0x20, mload(Z_Y_LOC))\\n mstore(0x40, mload(Z_X_LOC))\\n mstore(0x60, mload(Z_LOOKUP_Y_LOC))\\n mstore(0x80, mload(Z_LOOKUP_X_LOC))\\n challenge := keccak256(0x00, 0xa0)\\n mstore(C_ALPHA_LOC, mod(challenge, p))\\n\\n /**\\n * Compute and store some powers of alpha for future computations\\n */\\n let alpha := mload(C_ALPHA_LOC)\\n mstore(C_ALPHA_SQR_LOC, mulmod(alpha, alpha, p))\\n mstore(C_ALPHA_CUBE_LOC, mulmod(mload(C_ALPHA_SQR_LOC), alpha, p))\\n mstore(C_ALPHA_QUAD_LOC, mulmod(mload(C_ALPHA_CUBE_LOC), alpha, p))\\n mstore(C_ALPHA_BASE_LOC, alpha)\\n\\n /**\\n * Generate zeta challenge\\n */\\n mstore(0x00, challenge)\\n mstore(0x20, mload(T1_Y_LOC))\\n mstore(0x40, mload(T1_X_LOC))\\n mstore(0x60, mload(T2_Y_LOC))\\n mstore(0x80, mload(T2_X_LOC))\\n mstore(0xa0, mload(T3_Y_LOC))\\n mstore(0xc0, mload(T3_X_LOC))\\n mstore(0xe0, mload(T4_Y_LOC))\\n mstore(0x100, mload(T4_X_LOC))\\n\\n challenge := keccak256(0x00, 0x120)\\n\\n mstore(C_ZETA_LOC, mod(challenge, p))\\n mstore(C_CURRENT_LOC, challenge)\\n }\\n\\n /**\\n * EVALUATE FIELD OPERATIONS\\n */\\n\\n /**\\n * COMPUTE PUBLIC INPUT DELTA\\n * \\u0394PI = \\u220f\\u1d62\\u2208\\u2113(w\\u1d62 + \\u03b2 \\u03c3(i) + \\u03b3) / \\u220f\\u1d62\\u2208\\u2113(w\\u1d62 + \\u03b2 \\u03c3'(i) + \\u03b3)\\n */\\n {\\n let beta := mload(C_BETA_LOC) // \\u03b2\\n let gamma := mload(C_GAMMA_LOC) // \\u03b3\\n let work_root := mload(OMEGA_LOC) // \\u03c9\\n let numerator_value := 1\\n let denominator_value := 1\\n\\n let p_clone := p // move p to the front of the stack\\n let valid_inputs := true\\n\\n // Load the starting point of the public inputs (jump over the selector and the length of public inputs [0x24])\\n let public_inputs_ptr := add(calldataload(0x24), 0x24)\\n\\n // endpoint_ptr = public_inputs_ptr + num_inputs * 0x20. // every public input is 0x20 bytes\\n let endpoint_ptr := add(public_inputs_ptr, mul(mload(NUM_INPUTS_LOC), 0x20))\\n\\n // root_1 = \\u03b2 * 0x05\\n let root_1 := mulmod(beta, 0x05, p_clone) // k1.\\u03b2\\n // root_2 = \\u03b2 * 0x0c\\n let root_2 := mulmod(beta, 0x0c, p_clone)\\n // @note 0x05 + 0x07 == 0x0c == external coset generator\\n\\n for {} lt(public_inputs_ptr, endpoint_ptr) { public_inputs_ptr := add(public_inputs_ptr, 0x20) } {\\n /**\\n * input = public_input[i]\\n * valid_inputs &= input < p\\n * temp = input + gamma\\n * numerator_value *= (\\u03b2.\\u03c3(i) + w\\u1d62 + \\u03b3) // \\u03c3(i) = 0x05.\\u03c9\\u2071\\n * denominator_value *= (\\u03b2.\\u03c3'(i) + w\\u1d62 + \\u03b3) // \\u03c3'(i) = 0x0c.\\u03c9\\u2071\\n * root_1 *= \\u03c9\\n * root_2 *= \\u03c9\\n */\\n\\n let input := calldataload(public_inputs_ptr)\\n valid_inputs := and(valid_inputs, lt(input, p_clone))\\n let temp := addmod(input, gamma, p_clone)\\n\\n numerator_value := mulmod(numerator_value, add(root_1, temp), p_clone)\\n denominator_value := mulmod(denominator_value, add(root_2, temp), p_clone)\\n\\n root_1 := mulmod(root_1, work_root, p_clone)\\n root_2 := mulmod(root_2, work_root, p_clone)\\n }\\n\\n // Revert if not all public inputs are field elements (i.e. < p)\\n if iszero(valid_inputs) {\\n mstore(0x00, PUBLIC_INPUT_GE_P_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n\\n mstore(DELTA_NUMERATOR_LOC, numerator_value)\\n mstore(DELTA_DENOMINATOR_LOC, denominator_value)\\n }\\n\\n /**\\n * Compute Plookup delta factor [\\u03b3(1 + \\u03b2)]^{n-k}\\n * k = num roots cut out of Z_H = 4\\n */\\n {\\n let delta_base := mulmod(mload(C_GAMMA_LOC), addmod(mload(C_BETA_LOC), 1, p), p)\\n let delta_numerator := delta_base\\n {\\n let exponent := mload(N_LOC)\\n let count := 1\\n for {} lt(count, exponent) { count := add(count, count) } {\\n delta_numerator := mulmod(delta_numerator, delta_numerator, p)\\n }\\n }\\n mstore(PLOOKUP_DELTA_NUMERATOR_LOC, delta_numerator)\\n\\n let delta_denominator := mulmod(delta_base, delta_base, p)\\n delta_denominator := mulmod(delta_denominator, delta_denominator, p)\\n mstore(PLOOKUP_DELTA_DENOMINATOR_LOC, delta_denominator)\\n }\\n /**\\n * Compute lagrange poly and vanishing poly fractions\\n */\\n {\\n /**\\n * vanishing_numerator = zeta\\n * ZETA_POW_N = zeta^n\\n * vanishing_numerator -= 1\\n * accumulating_root = omega_inverse\\n * work_root = p - accumulating_root\\n * domain_inverse = domain_inverse\\n * vanishing_denominator = zeta + work_root\\n * work_root *= accumulating_root\\n * vanishing_denominator *= (zeta + work_root)\\n * work_root *= accumulating_root\\n * vanishing_denominator *= (zeta + work_root)\\n * vanishing_denominator *= (zeta + (zeta + accumulating_root))\\n * work_root = omega\\n * lagrange_numerator = vanishing_numerator * domain_inverse\\n * l_start_denominator = zeta - 1\\n * accumulating_root = work_root^2\\n * l_end_denominator = accumulating_root^2 * work_root * zeta - 1\\n * Note: l_end_denominator term contains a term \\\\omega^5 to cut out 5 roots of unity from vanishing poly\\n */\\n\\n let zeta := mload(C_ZETA_LOC)\\n\\n // compute zeta^n, where n is a power of 2\\n let vanishing_numerator := zeta\\n {\\n // pow_small\\n let exponent := mload(N_LOC)\\n let count := 1\\n for {} lt(count, exponent) { count := add(count, count) } {\\n vanishing_numerator := mulmod(vanishing_numerator, vanishing_numerator, p)\\n }\\n }\\n mstore(ZETA_POW_N_LOC, vanishing_numerator)\\n vanishing_numerator := addmod(vanishing_numerator, sub(p, 1), p)\\n\\n let accumulating_root := mload(OMEGA_INVERSE_LOC)\\n let work_root := sub(p, accumulating_root)\\n let domain_inverse := mload(DOMAIN_INVERSE_LOC)\\n\\n let vanishing_denominator := addmod(zeta, work_root, p)\\n work_root := mulmod(work_root, accumulating_root, p)\\n vanishing_denominator := mulmod(vanishing_denominator, addmod(zeta, work_root, p), p)\\n work_root := mulmod(work_root, accumulating_root, p)\\n vanishing_denominator := mulmod(vanishing_denominator, addmod(zeta, work_root, p), p)\\n vanishing_denominator :=\\n mulmod(vanishing_denominator, addmod(zeta, mulmod(work_root, accumulating_root, p), p), p)\\n\\n work_root := mload(OMEGA_LOC)\\n\\n let lagrange_numerator := mulmod(vanishing_numerator, domain_inverse, p)\\n let l_start_denominator := addmod(zeta, sub(p, 1), p)\\n\\n accumulating_root := mulmod(work_root, work_root, p)\\n\\n let l_end_denominator :=\\n addmod(\\n mulmod(mulmod(mulmod(accumulating_root, accumulating_root, p), work_root, p), zeta, p), sub(p, 1), p\\n )\\n\\n /**\\n * Compute inversions using Montgomery's batch inversion trick\\n */\\n let accumulator := mload(DELTA_DENOMINATOR_LOC)\\n let t0 := accumulator\\n accumulator := mulmod(accumulator, vanishing_denominator, p)\\n let t1 := accumulator\\n accumulator := mulmod(accumulator, vanishing_numerator, p)\\n let t2 := accumulator\\n accumulator := mulmod(accumulator, l_start_denominator, p)\\n let t3 := accumulator\\n accumulator := mulmod(accumulator, mload(PLOOKUP_DELTA_DENOMINATOR_LOC), p)\\n let t4 := accumulator\\n {\\n mstore(0, 0x20)\\n mstore(0x20, 0x20)\\n mstore(0x40, 0x20)\\n mstore(0x60, mulmod(accumulator, l_end_denominator, p))\\n mstore(0x80, sub(p, 2))\\n mstore(0xa0, p)\\n if iszero(staticcall(gas(), 0x05, 0x00, 0xc0, 0x00, 0x20)) {\\n mstore(0x0, MOD_EXP_FAILURE_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n accumulator := mload(0x00)\\n }\\n\\n t4 := mulmod(accumulator, t4, p)\\n accumulator := mulmod(accumulator, l_end_denominator, p)\\n\\n t3 := mulmod(accumulator, t3, p)\\n accumulator := mulmod(accumulator, mload(PLOOKUP_DELTA_DENOMINATOR_LOC), p)\\n\\n t2 := mulmod(accumulator, t2, p)\\n accumulator := mulmod(accumulator, l_start_denominator, p)\\n\\n t1 := mulmod(accumulator, t1, p)\\n accumulator := mulmod(accumulator, vanishing_numerator, p)\\n\\n t0 := mulmod(accumulator, t0, p)\\n accumulator := mulmod(accumulator, vanishing_denominator, p)\\n\\n accumulator := mulmod(mulmod(accumulator, accumulator, p), mload(DELTA_DENOMINATOR_LOC), p)\\n\\n mstore(PUBLIC_INPUT_DELTA_LOC, mulmod(mload(DELTA_NUMERATOR_LOC), accumulator, p))\\n mstore(ZERO_POLY_LOC, mulmod(vanishing_numerator, t0, p))\\n mstore(ZERO_POLY_INVERSE_LOC, mulmod(vanishing_denominator, t1, p))\\n mstore(L_START_LOC, mulmod(lagrange_numerator, t2, p))\\n mstore(PLOOKUP_DELTA_LOC, mulmod(mload(PLOOKUP_DELTA_NUMERATOR_LOC), t3, p))\\n mstore(L_END_LOC, mulmod(lagrange_numerator, t4, p))\\n }\\n\\n /**\\n * UltraPlonk Widget Ordering:\\n *\\n * 1. Permutation widget\\n * 2. Plookup widget\\n * 3. Arithmetic widget\\n * 4. Fixed base widget (?)\\n * 5. GenPermSort widget\\n * 6. Elliptic widget\\n * 7. Auxiliary widget\\n */\\n\\n /**\\n * COMPUTE PERMUTATION WIDGET EVALUATION\\n */\\n {\\n let alpha := mload(C_ALPHA_LOC)\\n let beta := mload(C_BETA_LOC)\\n let gamma := mload(C_GAMMA_LOC)\\n\\n /**\\n * t1 = (W1 + gamma + beta * ID1) * (W2 + gamma + beta * ID2)\\n * t2 = (W3 + gamma + beta * ID3) * (W4 + gamma + beta * ID4)\\n * result = alpha_base * z_eval * t1 * t2\\n * t1 = (W1 + gamma + beta * sigma_1_eval) * (W2 + gamma + beta * sigma_2_eval)\\n * t2 = (W2 + gamma + beta * sigma_3_eval) * (W3 + gamma + beta * sigma_4_eval)\\n * result -= (alpha_base * z_omega_eval * t1 * t2)\\n */\\n let t1 :=\\n mulmod(\\n add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(ID1_EVAL_LOC), p)),\\n add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(ID2_EVAL_LOC), p)),\\n p\\n )\\n let t2 :=\\n mulmod(\\n add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(ID3_EVAL_LOC), p)),\\n add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(ID4_EVAL_LOC), p)),\\n p\\n )\\n let result := mulmod(mload(C_ALPHA_BASE_LOC), mulmod(mload(Z_EVAL_LOC), mulmod(t1, t2, p), p), p)\\n t1 :=\\n mulmod(\\n add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA1_EVAL_LOC), p)),\\n add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA2_EVAL_LOC), p)),\\n p\\n )\\n t2 :=\\n mulmod(\\n add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA3_EVAL_LOC), p)),\\n add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA4_EVAL_LOC), p)),\\n p\\n )\\n result :=\\n addmod(\\n result,\\n sub(p, mulmod(mload(C_ALPHA_BASE_LOC), mulmod(mload(Z_OMEGA_EVAL_LOC), mulmod(t1, t2, p), p), p)),\\n p\\n )\\n\\n /**\\n * alpha_base *= alpha\\n * result += alpha_base . (L_{n-k}(\\u0293) . (z(\\u0293.\\u03c9) - \\u2206_{PI}))\\n * alpha_base *= alpha\\n * result += alpha_base . (L_1(\\u0293)(Z(\\u0293) - 1))\\n * alpha_Base *= alpha\\n */\\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p))\\n result :=\\n addmod(\\n result,\\n mulmod(\\n mload(C_ALPHA_BASE_LOC),\\n mulmod(\\n mload(L_END_LOC),\\n addmod(mload(Z_OMEGA_EVAL_LOC), sub(p, mload(PUBLIC_INPUT_DELTA_LOC)), p),\\n p\\n ),\\n p\\n ),\\n p\\n )\\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p))\\n mstore(\\n PERMUTATION_IDENTITY,\\n addmod(\\n result,\\n mulmod(\\n mload(C_ALPHA_BASE_LOC),\\n mulmod(mload(L_START_LOC), addmod(mload(Z_EVAL_LOC), sub(p, 1), p), p),\\n p\\n ),\\n p\\n )\\n )\\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p))\\n }\\n\\n /**\\n * COMPUTE PLOOKUP WIDGET EVALUATION\\n */\\n {\\n /**\\n * Goal: f = (w1(z) + q2.w1(z\\u03c9)) + \\u03b7(w2(z) + qm.w2(z\\u03c9)) + \\u03b7\\u00b2(w3(z) + qc.w_3(z\\u03c9)) + q3(z).\\u03b7\\u00b3\\n * f = \\u03b7.q3(z)\\n * f += (w3(z) + qc.w_3(z\\u03c9))\\n * f *= \\u03b7\\n * f += (w2(z) + qm.w2(z\\u03c9))\\n * f *= \\u03b7\\n * f += (w1(z) + q2.w1(z\\u03c9))\\n */\\n let f := mulmod(mload(C_ETA_LOC), mload(Q3_EVAL_LOC), p)\\n f :=\\n addmod(f, addmod(mload(W3_EVAL_LOC), mulmod(mload(QC_EVAL_LOC), mload(W3_OMEGA_EVAL_LOC), p), p), p)\\n f := mulmod(f, mload(C_ETA_LOC), p)\\n f :=\\n addmod(f, addmod(mload(W2_EVAL_LOC), mulmod(mload(QM_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), p), p)\\n f := mulmod(f, mload(C_ETA_LOC), p)\\n f :=\\n addmod(f, addmod(mload(W1_EVAL_LOC), mulmod(mload(Q2_EVAL_LOC), mload(W1_OMEGA_EVAL_LOC), p), p), p)\\n\\n // t(z) = table4(z).\\u03b7\\u00b3 + table3(z).\\u03b7\\u00b2 + table2(z).\\u03b7 + table1(z)\\n let t :=\\n addmod(\\n addmod(\\n addmod(\\n mulmod(mload(TABLE4_EVAL_LOC), mload(C_ETA_CUBE_LOC), p),\\n mulmod(mload(TABLE3_EVAL_LOC), mload(C_ETA_SQR_LOC), p),\\n p\\n ),\\n mulmod(mload(TABLE2_EVAL_LOC), mload(C_ETA_LOC), p),\\n p\\n ),\\n mload(TABLE1_EVAL_LOC),\\n p\\n )\\n\\n // t(zw) = table4(zw).\\u03b7\\u00b3 + table3(zw).\\u03b7\\u00b2 + table2(zw).\\u03b7 + table1(zw)\\n let t_omega :=\\n addmod(\\n addmod(\\n addmod(\\n mulmod(mload(TABLE4_OMEGA_EVAL_LOC), mload(C_ETA_CUBE_LOC), p),\\n mulmod(mload(TABLE3_OMEGA_EVAL_LOC), mload(C_ETA_SQR_LOC), p),\\n p\\n ),\\n mulmod(mload(TABLE2_OMEGA_EVAL_LOC), mload(C_ETA_LOC), p),\\n p\\n ),\\n mload(TABLE1_OMEGA_EVAL_LOC),\\n p\\n )\\n\\n /**\\n * Goal: numerator = (TABLE_TYPE_EVAL * f(z) + \\u03b3) * (t(z) + \\u03b2t(z\\u03c9) + \\u03b3(\\u03b2 + 1)) * (\\u03b2 + 1)\\n * gamma_beta_constant = \\u03b3(\\u03b2 + 1)\\n * numerator = f * TABLE_TYPE_EVAL + gamma\\n * temp0 = t(z) + t(z\\u03c9) * \\u03b2 + gamma_beta_constant\\n * numerator *= temp0\\n * numerator *= (\\u03b2 + 1)\\n * temp0 = alpha * l_1\\n * numerator += temp0\\n * numerator *= z_lookup(z)\\n * numerator -= temp0\\n */\\n let gamma_beta_constant := mulmod(mload(C_GAMMA_LOC), addmod(mload(C_BETA_LOC), 1, p), p)\\n let numerator := addmod(mulmod(f, mload(TABLE_TYPE_EVAL_LOC), p), mload(C_GAMMA_LOC), p)\\n let temp0 := addmod(addmod(t, mulmod(t_omega, mload(C_BETA_LOC), p), p), gamma_beta_constant, p)\\n numerator := mulmod(numerator, temp0, p)\\n numerator := mulmod(numerator, addmod(mload(C_BETA_LOC), 1, p), p)\\n temp0 := mulmod(mload(C_ALPHA_LOC), mload(L_START_LOC), p)\\n numerator := addmod(numerator, temp0, p)\\n numerator := mulmod(numerator, mload(Z_LOOKUP_EVAL_LOC), p)\\n numerator := addmod(numerator, sub(p, temp0), p)\\n\\n /**\\n * Goal: denominator = z_lookup(z\\u03c9)*[s(z) + \\u03b2s(z\\u03c9) + \\u03b3(1 + \\u03b2)] - [z_lookup(z\\u03c9) - [\\u03b3(1 + \\u03b2)]^{n-k}]*\\u03b1\\u00b2L_end(z)\\n * note: delta_factor = [\\u03b3(1 + \\u03b2)]^{n-k}\\n * denominator = s(z) + \\u03b2s(z\\u03c9) + \\u03b3(\\u03b2 + 1)\\n * temp1 = \\u03b1\\u00b2L_end(z)\\n * denominator -= temp1\\n * denominator *= z_lookup(z\\u03c9)\\n * denominator += temp1 * delta_factor\\n * PLOOKUP_IDENTITY = (numerator - denominator).alpha_base\\n * alpha_base *= alpha^3\\n */\\n let denominator :=\\n addmod(\\n addmod(mload(S_EVAL_LOC), mulmod(mload(S_OMEGA_EVAL_LOC), mload(C_BETA_LOC), p), p),\\n gamma_beta_constant,\\n p\\n )\\n let temp1 := mulmod(mload(C_ALPHA_SQR_LOC), mload(L_END_LOC), p)\\n denominator := addmod(denominator, sub(p, temp1), p)\\n denominator := mulmod(denominator, mload(Z_LOOKUP_OMEGA_EVAL_LOC), p)\\n denominator := addmod(denominator, mulmod(temp1, mload(PLOOKUP_DELTA_LOC), p), p)\\n\\n mstore(PLOOKUP_IDENTITY, mulmod(addmod(numerator, sub(p, denominator), p), mload(C_ALPHA_BASE_LOC), p))\\n\\n // update alpha\\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p))\\n }\\n\\n /**\\n * COMPUTE ARITHMETIC WIDGET EVALUATION\\n */\\n {\\n /**\\n * The basic arithmetic gate identity in standard plonk is as follows.\\n * (w_1 . w_2 . q_m) + (w_1 . q_1) + (w_2 . q_2) + (w_3 . q_3) + (w_4 . q_4) + q_c = 0\\n * However, for Ultraplonk, we extend this to support \\\"passing\\\" wires between rows (shown without alpha scaling below):\\n * q_arith * ( ( (-1/2) * (q_arith - 3) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c ) +\\n * (q_arith - 1)*( \\u03b1 * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m) + w_4_omega) ) = 0\\n *\\n * This formula results in several cases depending on q_arith:\\n * 1. q_arith == 0: Arithmetic gate is completely disabled\\n *\\n * 2. q_arith == 1: Everything in the minigate on the right is disabled. The equation is just a standard plonk equation\\n * with extra wires: q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c = 0\\n *\\n * 3. q_arith == 2: The (w_1 + w_4 - ...) term is disabled. THe equation is:\\n * (1/2) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + w_4_omega = 0\\n * It allows defining w_4 at next index (w_4_omega) in terms of current wire values\\n *\\n * 4. q_arith == 3: The product of w_1 and w_2 is disabled, but a mini addition gate is enabled. \\u03b1 allows us to split\\n * the equation into two:\\n *\\n * q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + 2 * w_4_omega = 0\\n * and\\n * w_1 + w_4 - w_1_omega + q_m = 0 (we are reusing q_m here)\\n *\\n * 5. q_arith > 3: The product of w_1 and w_2 is scaled by (q_arith - 3), while the w_4_omega term is scaled by (q_arith - 1).\\n * The equation can be split into two:\\n *\\n * (q_arith - 3)* q_m * w_1 * w_ 2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + (q_arith - 1) * w_4_omega = 0\\n * and\\n * w_1 + w_4 - w_1_omega + q_m = 0\\n *\\n * The problem that q_m is used both in both equations can be dealt with by appropriately changing selector values at\\n * the next gate. Then we can treat (q_arith - 1) as a simulated q_6 selector and scale q_m to handle (q_arith - 3) at\\n * product.\\n */\\n\\n let w1q1 := mulmod(mload(W1_EVAL_LOC), mload(Q1_EVAL_LOC), p)\\n let w2q2 := mulmod(mload(W2_EVAL_LOC), mload(Q2_EVAL_LOC), p)\\n let w3q3 := mulmod(mload(W3_EVAL_LOC), mload(Q3_EVAL_LOC), p)\\n let w4q3 := mulmod(mload(W4_EVAL_LOC), mload(Q4_EVAL_LOC), p)\\n\\n // @todo - Add a explicit test that hits QARITH == 3\\n // w1w2qm := (w_1 . w_2 . q_m . (QARITH_EVAL_LOC - 3)) / 2\\n let w1w2qm :=\\n mulmod(\\n mulmod(\\n mulmod(mulmod(mload(W1_EVAL_LOC), mload(W2_EVAL_LOC), p), mload(QM_EVAL_LOC), p),\\n addmod(mload(QARITH_EVAL_LOC), sub(p, 3), p),\\n p\\n ),\\n NEGATIVE_INVERSE_OF_2_MODULO_P,\\n p\\n )\\n\\n // (w_1 . w_2 . q_m . (q_arith - 3)) / -2) + (w_1 . q_1) + (w_2 . q_2) + (w_3 . q_3) + (w_4 . q_4) + q_c\\n let identity :=\\n addmod(\\n mload(QC_EVAL_LOC), addmod(w4q3, addmod(w3q3, addmod(w2q2, addmod(w1q1, w1w2qm, p), p), p), p), p\\n )\\n\\n // if q_arith == 3 we evaluate an additional mini addition gate (on top of the regular one), where:\\n // w_1 + w_4 - w_1_omega + q_m = 0\\n // we use this gate to save an addition gate when adding or subtracting non-native field elements\\n // \\u03b1 * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m)\\n let extra_small_addition_gate_identity :=\\n mulmod(\\n mload(C_ALPHA_LOC),\\n mulmod(\\n addmod(mload(QARITH_EVAL_LOC), sub(p, 2), p),\\n addmod(\\n mload(QM_EVAL_LOC),\\n addmod(\\n sub(p, mload(W1_OMEGA_EVAL_LOC)), addmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p), p\\n ),\\n p\\n ),\\n p\\n ),\\n p\\n )\\n\\n // if q_arith == 2 OR q_arith == 3 we add the 4th wire of the NEXT gate into the arithmetic identity\\n // N.B. if q_arith > 2, this wire value will be scaled by (q_arith - 1) relative to the other gate wires!\\n // alpha_base * q_arith * (identity + (q_arith - 1) * (w_4_omega + extra_small_addition_gate_identity))\\n mstore(\\n ARITHMETIC_IDENTITY,\\n mulmod(\\n mload(C_ALPHA_BASE_LOC),\\n mulmod(\\n mload(QARITH_EVAL_LOC),\\n addmod(\\n identity,\\n mulmod(\\n addmod(mload(QARITH_EVAL_LOC), sub(p, 1), p),\\n addmod(mload(W4_OMEGA_EVAL_LOC), extra_small_addition_gate_identity, p),\\n p\\n ),\\n p\\n ),\\n p\\n ),\\n p\\n )\\n )\\n\\n // update alpha\\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_SQR_LOC), p))\\n }\\n\\n /**\\n * COMPUTE GENPERMSORT WIDGET EVALUATION\\n */\\n {\\n /**\\n * D1 = (w2 - w1)\\n * D2 = (w3 - w2)\\n * D3 = (w4 - w3)\\n * D4 = (w1_omega - w4)\\n *\\n * \\u03b1_a = alpha_base\\n * \\u03b1_b = alpha_base * \\u03b1\\n * \\u03b1_c = alpha_base * \\u03b1^2\\n * \\u03b1_d = alpha_base * \\u03b1^3\\n *\\n * range_accumulator = (\\n * D1(D1 - 1)(D1 - 2)(D1 - 3).\\u03b1_a +\\n * D2(D2 - 1)(D2 - 2)(D2 - 3).\\u03b1_b +\\n * D3(D3 - 1)(D3 - 2)(D3 - 3).\\u03b1_c +\\n * D4(D4 - 1)(D4 - 2)(D4 - 3).\\u03b1_d +\\n * ) . q_sort\\n */\\n let minus_two := sub(p, 2)\\n let minus_three := sub(p, 3)\\n let d1 := addmod(mload(W2_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p)\\n let d2 := addmod(mload(W3_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p)\\n let d3 := addmod(mload(W4_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p)\\n let d4 := addmod(mload(W1_OMEGA_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p)\\n\\n let range_accumulator :=\\n mulmod(\\n mulmod(\\n mulmod(addmod(mulmod(d1, d1, p), sub(p, d1), p), addmod(d1, minus_two, p), p),\\n addmod(d1, minus_three, p),\\n p\\n ),\\n mload(C_ALPHA_BASE_LOC),\\n p\\n )\\n range_accumulator :=\\n addmod(\\n range_accumulator,\\n mulmod(\\n mulmod(\\n mulmod(addmod(mulmod(d2, d2, p), sub(p, d2), p), addmod(d2, minus_two, p), p),\\n addmod(d2, minus_three, p),\\n p\\n ),\\n mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p),\\n p\\n ),\\n p\\n )\\n range_accumulator :=\\n addmod(\\n range_accumulator,\\n mulmod(\\n mulmod(\\n mulmod(addmod(mulmod(d3, d3, p), sub(p, d3), p), addmod(d3, minus_two, p), p),\\n addmod(d3, minus_three, p),\\n p\\n ),\\n mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_SQR_LOC), p),\\n p\\n ),\\n p\\n )\\n range_accumulator :=\\n addmod(\\n range_accumulator,\\n mulmod(\\n mulmod(\\n mulmod(addmod(mulmod(d4, d4, p), sub(p, d4), p), addmod(d4, minus_two, p), p),\\n addmod(d4, minus_three, p),\\n p\\n ),\\n mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p),\\n p\\n ),\\n p\\n )\\n range_accumulator := mulmod(range_accumulator, mload(QSORT_EVAL_LOC), p)\\n\\n mstore(SORT_IDENTITY, range_accumulator)\\n\\n // update alpha\\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_QUAD_LOC), p))\\n }\\n\\n /**\\n * COMPUTE ELLIPTIC WIDGET EVALUATION\\n */\\n {\\n /**\\n * endo_term = (-x_2) * x_1 * (x_3 * 2 + x_1) * q_beta\\n * endo_sqr_term = x_2^2\\n * endo_sqr_term *= (x_3 - x_1)\\n * endo_sqr_term *= q_beta^2\\n * leftovers = x_2^2\\n * leftovers *= x_2\\n * leftovers += x_1^2 * (x_3 + x_1) @follow-up Invalid comment in BB widget\\n * leftovers -= (y_2^2 + y_1^2)\\n * sign_term = y_2 * y_1\\n * sign_term += sign_term\\n * sign_term *= q_sign\\n */\\n // q_elliptic * (x3 + x2 + x1)(x2 - x1)(x2 - x1) - y2^2 - y1^2 + 2(y2y1)*q_sign = 0\\n let x_diff := addmod(mload(X2_EVAL_LOC), sub(p, mload(X1_EVAL_LOC)), p)\\n let y2_sqr := mulmod(mload(Y2_EVAL_LOC), mload(Y2_EVAL_LOC), p)\\n let y1_sqr := mulmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p)\\n let y1y2 := mulmod(mulmod(mload(Y1_EVAL_LOC), mload(Y2_EVAL_LOC), p), mload(QSIGN_LOC), p)\\n\\n let x_add_identity :=\\n addmod(\\n mulmod(\\n addmod(mload(X3_EVAL_LOC), addmod(mload(X2_EVAL_LOC), mload(X1_EVAL_LOC), p), p),\\n mulmod(x_diff, x_diff, p),\\n p\\n ),\\n addmod(\\n sub(\\n p,\\n addmod(y2_sqr, y1_sqr, p)\\n ),\\n addmod(y1y2, y1y2, p),\\n p\\n ),\\n p\\n )\\n x_add_identity :=\\n mulmod(\\n mulmod(\\n x_add_identity,\\n addmod(\\n 1,\\n sub(p, mload(QM_EVAL_LOC)),\\n p\\n ),\\n p\\n ),\\n mload(C_ALPHA_BASE_LOC),\\n p\\n )\\n\\n // q_elliptic * (x3 + x2 + x1)(x2 - x1)(x2 - x1) - y2^2 - y1^2 + 2(y2y1)*q_sign = 0\\n let y1_plus_y3 := addmod(\\n mload(Y1_EVAL_LOC),\\n mload(Y3_EVAL_LOC),\\n p\\n )\\n let y_diff := addmod(mulmod(mload(Y2_EVAL_LOC), mload(QSIGN_LOC), p), sub(p, mload(Y1_EVAL_LOC)), p)\\n let y_add_identity :=\\n addmod(\\n mulmod(y1_plus_y3, x_diff, p),\\n mulmod(addmod(mload(X3_EVAL_LOC), sub(p, mload(X1_EVAL_LOC)), p), y_diff, p),\\n p\\n )\\n y_add_identity :=\\n mulmod(\\n mulmod(y_add_identity, addmod(1, sub(p, mload(QM_EVAL_LOC)), p), p),\\n mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p),\\n p\\n )\\n\\n // ELLIPTIC_IDENTITY = (x_identity + y_identity) * Q_ELLIPTIC_EVAL\\n mstore(\\n ELLIPTIC_IDENTITY, mulmod(addmod(x_add_identity, y_add_identity, p), mload(QELLIPTIC_EVAL_LOC), p)\\n )\\n }\\n {\\n /**\\n * x_pow_4 = (y_1_sqr - curve_b) * x_1;\\n * y_1_sqr_mul_4 = y_1_sqr + y_1_sqr;\\n * y_1_sqr_mul_4 += y_1_sqr_mul_4;\\n * x_1_pow_4_mul_9 = x_pow_4;\\n * x_1_pow_4_mul_9 += x_1_pow_4_mul_9;\\n * x_1_pow_4_mul_9 += x_1_pow_4_mul_9;\\n * x_1_pow_4_mul_9 += x_1_pow_4_mul_9;\\n * x_1_pow_4_mul_9 += x_pow_4;\\n * x_1_sqr_mul_3 = x_1_sqr + x_1_sqr + x_1_sqr;\\n * x_double_identity = (x_3 + x_1 + x_1) * y_1_sqr_mul_4 - x_1_pow_4_mul_9;\\n * y_double_identity = x_1_sqr_mul_3 * (x_1 - x_3) - (y_1 + y_1) * (y_1 + y_3);\\n */\\n // (x3 + x1 + x1) (4y1*y1) - 9 * x1 * x1 * x1 * x1 = 0\\n let x1_sqr := mulmod(mload(X1_EVAL_LOC), mload(X1_EVAL_LOC), p)\\n let y1_sqr := mulmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p)\\n let x_pow_4 := mulmod(addmod(y1_sqr, GRUMPKIN_CURVE_B_PARAMETER_NEGATED, p), mload(X1_EVAL_LOC), p)\\n let y1_sqr_mul_4 := mulmod(y1_sqr, 4, p)\\n let x1_pow_4_mul_9 := mulmod(x_pow_4, 9, p)\\n let x1_sqr_mul_3 := mulmod(x1_sqr, 3, p)\\n let x_double_identity :=\\n addmod(\\n mulmod(\\n addmod(mload(X3_EVAL_LOC), addmod(mload(X1_EVAL_LOC), mload(X1_EVAL_LOC), p), p),\\n y1_sqr_mul_4,\\n p\\n ),\\n sub(p, x1_pow_4_mul_9),\\n p\\n )\\n // (y1 + y1) (2y1) - (3 * x1 * x1)(x1 - x3) = 0\\n let y_double_identity :=\\n addmod(\\n mulmod(x1_sqr_mul_3, addmod(mload(X1_EVAL_LOC), sub(p, mload(X3_EVAL_LOC)), p), p),\\n sub(\\n p,\\n mulmod(\\n addmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p),\\n addmod(mload(Y1_EVAL_LOC), mload(Y3_EVAL_LOC), p),\\n p\\n )\\n ),\\n p\\n )\\n x_double_identity := mulmod(x_double_identity, mload(C_ALPHA_BASE_LOC), p)\\n y_double_identity :=\\n mulmod(y_double_identity, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p), p)\\n x_double_identity := mulmod(x_double_identity, mload(QM_EVAL_LOC), p)\\n y_double_identity := mulmod(y_double_identity, mload(QM_EVAL_LOC), p)\\n // ELLIPTIC_IDENTITY += (x_double_identity + y_double_identity) * Q_DOUBLE_EVAL\\n mstore(\\n ELLIPTIC_IDENTITY,\\n addmod(\\n mload(ELLIPTIC_IDENTITY),\\n mulmod(addmod(x_double_identity, y_double_identity, p), mload(QELLIPTIC_EVAL_LOC), p),\\n p\\n )\\n )\\n\\n // update alpha\\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_QUAD_LOC), p))\\n }\\n\\n /**\\n * COMPUTE AUXILIARY WIDGET EVALUATION\\n */\\n {\\n {\\n /**\\n * Non native field arithmetic gate 2\\n * _ _\\n * / _ _ _ 14 \\\\\\n * q_2 . q_4 | (w_1 . w_2) + (w_1 . w_2) + (w_1 . w_4 + w_2 . w_3 - w_3) . 2 - w_3 - w_4 |\\n * \\\\_ _/\\n *\\n * limb_subproduct = w_1 . w_2_omega + w_1_omega . w_2\\n * non_native_field_gate_2 = w_1 * w_4 + w_4 * w_3 - w_3_omega\\n * non_native_field_gate_2 = non_native_field_gate_2 * limb_size\\n * non_native_field_gate_2 -= w_4_omega\\n * non_native_field_gate_2 += limb_subproduct\\n * non_native_field_gate_2 *= q_4\\n * limb_subproduct *= limb_size\\n * limb_subproduct += w_1_omega * w_2_omega\\n * non_native_field_gate_1 = (limb_subproduct + w_3 + w_4) * q_3\\n * non_native_field_gate_3 = (limb_subproduct + w_4 - (w_3_omega + w_4_omega)) * q_m\\n * non_native_field_identity = (non_native_field_gate_1 + non_native_field_gate_2 + non_native_field_gate_3) * q_2\\n */\\n\\n let limb_subproduct :=\\n addmod(\\n mulmod(mload(W1_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p),\\n mulmod(mload(W1_OMEGA_EVAL_LOC), mload(W2_EVAL_LOC), p),\\n p\\n )\\n\\n let non_native_field_gate_2 :=\\n addmod(\\n addmod(\\n mulmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p),\\n mulmod(mload(W2_EVAL_LOC), mload(W3_EVAL_LOC), p),\\n p\\n ),\\n sub(p, mload(W3_OMEGA_EVAL_LOC)),\\n p\\n )\\n non_native_field_gate_2 := mulmod(non_native_field_gate_2, LIMB_SIZE, p)\\n non_native_field_gate_2 := addmod(non_native_field_gate_2, sub(p, mload(W4_OMEGA_EVAL_LOC)), p)\\n non_native_field_gate_2 := addmod(non_native_field_gate_2, limb_subproduct, p)\\n non_native_field_gate_2 := mulmod(non_native_field_gate_2, mload(Q4_EVAL_LOC), p)\\n limb_subproduct := mulmod(limb_subproduct, LIMB_SIZE, p)\\n limb_subproduct :=\\n addmod(limb_subproduct, mulmod(mload(W1_OMEGA_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), p)\\n let non_native_field_gate_1 :=\\n mulmod(\\n addmod(limb_subproduct, sub(p, addmod(mload(W3_EVAL_LOC), mload(W4_EVAL_LOC), p)), p),\\n mload(Q3_EVAL_LOC),\\n p\\n )\\n let non_native_field_gate_3 :=\\n mulmod(\\n addmod(\\n addmod(limb_subproduct, mload(W4_EVAL_LOC), p),\\n sub(p, addmod(mload(W3_OMEGA_EVAL_LOC), mload(W4_OMEGA_EVAL_LOC), p)),\\n p\\n ),\\n mload(QM_EVAL_LOC),\\n p\\n )\\n let non_native_field_identity :=\\n mulmod(\\n addmod(addmod(non_native_field_gate_1, non_native_field_gate_2, p), non_native_field_gate_3, p),\\n mload(Q2_EVAL_LOC),\\n p\\n )\\n\\n mstore(AUX_NON_NATIVE_FIELD_EVALUATION, non_native_field_identity)\\n }\\n\\n {\\n /**\\n * limb_accumulator_1 = w_2_omega;\\n * limb_accumulator_1 *= SUBLIMB_SHIFT;\\n * limb_accumulator_1 += w_1_omega;\\n * limb_accumulator_1 *= SUBLIMB_SHIFT;\\n * limb_accumulator_1 += w_3;\\n * limb_accumulator_1 *= SUBLIMB_SHIFT;\\n * limb_accumulator_1 += w_2;\\n * limb_accumulator_1 *= SUBLIMB_SHIFT;\\n * limb_accumulator_1 += w_1;\\n * limb_accumulator_1 -= w_4;\\n * limb_accumulator_1 *= q_4;\\n */\\n let limb_accumulator_1 := mulmod(mload(W2_OMEGA_EVAL_LOC), SUBLIMB_SHIFT, p)\\n limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_OMEGA_EVAL_LOC), p)\\n limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)\\n limb_accumulator_1 := addmod(limb_accumulator_1, mload(W3_EVAL_LOC), p)\\n limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)\\n limb_accumulator_1 := addmod(limb_accumulator_1, mload(W2_EVAL_LOC), p)\\n limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)\\n limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_EVAL_LOC), p)\\n limb_accumulator_1 := addmod(limb_accumulator_1, sub(p, mload(W4_EVAL_LOC)), p)\\n limb_accumulator_1 := mulmod(limb_accumulator_1, mload(Q4_EVAL_LOC), p)\\n\\n /**\\n * limb_accumulator_2 = w_3_omega;\\n * limb_accumulator_2 *= SUBLIMB_SHIFT;\\n * limb_accumulator_2 += w_2_omega;\\n * limb_accumulator_2 *= SUBLIMB_SHIFT;\\n * limb_accumulator_2 += w_1_omega;\\n * limb_accumulator_2 *= SUBLIMB_SHIFT;\\n * limb_accumulator_2 += w_4;\\n * limb_accumulator_2 *= SUBLIMB_SHIFT;\\n * limb_accumulator_2 += w_3;\\n * limb_accumulator_2 -= w_4_omega;\\n * limb_accumulator_2 *= q_m;\\n */\\n let limb_accumulator_2 := mulmod(mload(W3_OMEGA_EVAL_LOC), SUBLIMB_SHIFT, p)\\n limb_accumulator_2 := addmod(limb_accumulator_2, mload(W2_OMEGA_EVAL_LOC), p)\\n limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)\\n limb_accumulator_2 := addmod(limb_accumulator_2, mload(W1_OMEGA_EVAL_LOC), p)\\n limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)\\n limb_accumulator_2 := addmod(limb_accumulator_2, mload(W4_EVAL_LOC), p)\\n limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)\\n limb_accumulator_2 := addmod(limb_accumulator_2, mload(W3_EVAL_LOC), p)\\n limb_accumulator_2 := addmod(limb_accumulator_2, sub(p, mload(W4_OMEGA_EVAL_LOC)), p)\\n limb_accumulator_2 := mulmod(limb_accumulator_2, mload(QM_EVAL_LOC), p)\\n\\n mstore(\\n AUX_LIMB_ACCUMULATOR_EVALUATION,\\n mulmod(addmod(limb_accumulator_1, limb_accumulator_2, p), mload(Q3_EVAL_LOC), p)\\n )\\n }\\n\\n {\\n /**\\n * memory_record_check = w_3;\\n * memory_record_check *= eta;\\n * memory_record_check += w_2;\\n * memory_record_check *= eta;\\n * memory_record_check += w_1;\\n * memory_record_check *= eta;\\n * memory_record_check += q_c;\\n *\\n * partial_record_check = memory_record_check;\\n *\\n * memory_record_check -= w_4;\\n */\\n\\n let memory_record_check := mulmod(mload(W3_EVAL_LOC), mload(C_ETA_LOC), p)\\n memory_record_check := addmod(memory_record_check, mload(W2_EVAL_LOC), p)\\n memory_record_check := mulmod(memory_record_check, mload(C_ETA_LOC), p)\\n memory_record_check := addmod(memory_record_check, mload(W1_EVAL_LOC), p)\\n memory_record_check := mulmod(memory_record_check, mload(C_ETA_LOC), p)\\n memory_record_check := addmod(memory_record_check, mload(QC_EVAL_LOC), p)\\n\\n let partial_record_check := memory_record_check\\n memory_record_check := addmod(memory_record_check, sub(p, mload(W4_EVAL_LOC)), p)\\n\\n mstore(AUX_MEMORY_EVALUATION, memory_record_check)\\n\\n // index_delta = w_1_omega - w_1\\n let index_delta := addmod(mload(W1_OMEGA_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p)\\n // record_delta = w_4_omega - w_4\\n let record_delta := addmod(mload(W4_OMEGA_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p)\\n // index_is_monotonically_increasing = index_delta * (index_delta - 1)\\n let index_is_monotonically_increasing := mulmod(index_delta, addmod(index_delta, sub(p, 1), p), p)\\n\\n // adjacent_values_match_if_adjacent_indices_match = record_delta * (1 - index_delta)\\n let adjacent_values_match_if_adjacent_indices_match :=\\n mulmod(record_delta, addmod(1, sub(p, index_delta), p), p)\\n\\n // AUX_ROM_CONSISTENCY_EVALUATION = ((adjacent_values_match_if_adjacent_indices_match * alpha) + index_is_monotonically_increasing) * alpha + partial_record_check\\n mstore(\\n AUX_ROM_CONSISTENCY_EVALUATION,\\n addmod(\\n mulmod(\\n addmod(\\n mulmod(adjacent_values_match_if_adjacent_indices_match, mload(C_ALPHA_LOC), p),\\n index_is_monotonically_increasing,\\n p\\n ),\\n mload(C_ALPHA_LOC),\\n p\\n ),\\n memory_record_check,\\n p\\n )\\n )\\n\\n {\\n /**\\n * next_gate_access_type = w_3_omega;\\n * next_gate_access_type *= eta;\\n * next_gate_access_type += w_2_omega;\\n * next_gate_access_type *= eta;\\n * next_gate_access_type += w_1_omega;\\n * next_gate_access_type *= eta;\\n * next_gate_access_type = w_4_omega - next_gate_access_type;\\n */\\n let next_gate_access_type := mulmod(mload(W3_OMEGA_EVAL_LOC), mload(C_ETA_LOC), p)\\n next_gate_access_type := addmod(next_gate_access_type, mload(W2_OMEGA_EVAL_LOC), p)\\n next_gate_access_type := mulmod(next_gate_access_type, mload(C_ETA_LOC), p)\\n next_gate_access_type := addmod(next_gate_access_type, mload(W1_OMEGA_EVAL_LOC), p)\\n next_gate_access_type := mulmod(next_gate_access_type, mload(C_ETA_LOC), p)\\n next_gate_access_type := addmod(mload(W4_OMEGA_EVAL_LOC), sub(p, next_gate_access_type), p)\\n\\n // value_delta = w_3_omega - w_3\\n let value_delta := addmod(mload(W3_OMEGA_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p)\\n // adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = (1 - index_delta) * value_delta * (1 - next_gate_access_type);\\n\\n let adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation :=\\n mulmod(\\n addmod(1, sub(p, index_delta), p),\\n mulmod(value_delta, addmod(1, sub(p, next_gate_access_type), p), p),\\n p\\n )\\n\\n // AUX_RAM_CONSISTENCY_EVALUATION\\n\\n /**\\n * access_type = w_4 - partial_record_check\\n * access_check = access_type^2 - access_type\\n * next_gate_access_type_is_boolean = next_gate_access_type^2 - next_gate_access_type\\n * RAM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation;\\n * RAM_consistency_check_identity *= alpha;\\n * RAM_consistency_check_identity += index_is_monotonically_increasing;\\n * RAM_consistency_check_identity *= alpha;\\n * RAM_consistency_check_identity += next_gate_access_type_is_boolean;\\n * RAM_consistency_check_identity *= alpha;\\n * RAM_consistency_check_identity += access_check;\\n */\\n\\n let access_type := addmod(mload(W4_EVAL_LOC), sub(p, partial_record_check), p)\\n let access_check := mulmod(access_type, addmod(access_type, sub(p, 1), p), p)\\n let next_gate_access_type_is_boolean :=\\n mulmod(next_gate_access_type, addmod(next_gate_access_type, sub(p, 1), p), p)\\n let RAM_cci :=\\n mulmod(\\n adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation,\\n mload(C_ALPHA_LOC),\\n p\\n )\\n RAM_cci := addmod(RAM_cci, index_is_monotonically_increasing, p)\\n RAM_cci := mulmod(RAM_cci, mload(C_ALPHA_LOC), p)\\n RAM_cci := addmod(RAM_cci, next_gate_access_type_is_boolean, p)\\n RAM_cci := mulmod(RAM_cci, mload(C_ALPHA_LOC), p)\\n RAM_cci := addmod(RAM_cci, access_check, p)\\n\\n mstore(AUX_RAM_CONSISTENCY_EVALUATION, RAM_cci)\\n }\\n\\n {\\n // timestamp_delta = w_2_omega - w_2\\n let timestamp_delta := addmod(mload(W2_OMEGA_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p)\\n\\n // RAM_timestamp_check_identity = (1 - index_delta) * timestamp_delta - w_3\\n let RAM_timestamp_check_identity :=\\n addmod(\\n mulmod(timestamp_delta, addmod(1, sub(p, index_delta), p), p), sub(p, mload(W3_EVAL_LOC)), p\\n )\\n\\n /**\\n * memory_identity = ROM_consistency_check_identity * q_2;\\n * memory_identity += RAM_timestamp_check_identity * q_4;\\n * memory_identity += memory_record_check * q_m;\\n * memory_identity *= q_1;\\n * memory_identity += (RAM_consistency_check_identity * q_arith);\\n *\\n * auxiliary_identity = memory_identity + non_native_field_identity + limb_accumulator_identity;\\n * auxiliary_identity *= q_aux;\\n * auxiliary_identity *= alpha_base;\\n */\\n let memory_identity := mulmod(mload(AUX_ROM_CONSISTENCY_EVALUATION), mload(Q2_EVAL_LOC), p)\\n memory_identity :=\\n addmod(memory_identity, mulmod(RAM_timestamp_check_identity, mload(Q4_EVAL_LOC), p), p)\\n memory_identity :=\\n addmod(memory_identity, mulmod(mload(AUX_MEMORY_EVALUATION), mload(QM_EVAL_LOC), p), p)\\n memory_identity := mulmod(memory_identity, mload(Q1_EVAL_LOC), p)\\n memory_identity :=\\n addmod(\\n memory_identity, mulmod(mload(AUX_RAM_CONSISTENCY_EVALUATION), mload(QARITH_EVAL_LOC), p), p\\n )\\n\\n let auxiliary_identity := addmod(memory_identity, mload(AUX_NON_NATIVE_FIELD_EVALUATION), p)\\n auxiliary_identity := addmod(auxiliary_identity, mload(AUX_LIMB_ACCUMULATOR_EVALUATION), p)\\n auxiliary_identity := mulmod(auxiliary_identity, mload(QAUX_EVAL_LOC), p)\\n auxiliary_identity := mulmod(auxiliary_identity, mload(C_ALPHA_BASE_LOC), p)\\n\\n mstore(AUX_IDENTITY, auxiliary_identity)\\n\\n // update alpha\\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p))\\n }\\n }\\n }\\n\\n {\\n /**\\n * quotient = ARITHMETIC_IDENTITY\\n * quotient += PERMUTATION_IDENTITY\\n * quotient += PLOOKUP_IDENTITY\\n * quotient += SORT_IDENTITY\\n * quotient += ELLIPTIC_IDENTITY\\n * quotient += AUX_IDENTITY\\n * quotient *= ZERO_POLY_INVERSE\\n */\\n mstore(\\n QUOTIENT_EVAL_LOC,\\n mulmod(\\n addmod(\\n addmod(\\n addmod(\\n addmod(\\n addmod(mload(PERMUTATION_IDENTITY), mload(PLOOKUP_IDENTITY), p),\\n mload(ARITHMETIC_IDENTITY),\\n p\\n ),\\n mload(SORT_IDENTITY),\\n p\\n ),\\n mload(ELLIPTIC_IDENTITY),\\n p\\n ),\\n mload(AUX_IDENTITY),\\n p\\n ),\\n mload(ZERO_POLY_INVERSE_LOC),\\n p\\n )\\n )\\n }\\n\\n /**\\n * GENERATE NU AND SEPARATOR CHALLENGES\\n */\\n {\\n let current_challenge := mload(C_CURRENT_LOC)\\n // get a calldata pointer that points to the start of the data we want to copy\\n let calldata_ptr := add(calldataload(0x04), 0x24)\\n\\n calldata_ptr := add(calldata_ptr, NU_CALLDATA_SKIP_LENGTH)\\n\\n mstore(NU_CHALLENGE_INPUT_LOC_A, current_challenge)\\n mstore(NU_CHALLENGE_INPUT_LOC_B, mload(QUOTIENT_EVAL_LOC))\\n calldatacopy(NU_CHALLENGE_INPUT_LOC_C, calldata_ptr, NU_INPUT_LENGTH)\\n\\n // hash length = (0x20 + num field elements), we include the previous challenge in the hash\\n let challenge := keccak256(NU_CHALLENGE_INPUT_LOC_A, add(NU_INPUT_LENGTH, 0x40))\\n\\n mstore(C_V0_LOC, mod(challenge, p))\\n // We need THIRTY-ONE independent nu challenges!\\n mstore(0x00, challenge)\\n mstore8(0x20, 0x01)\\n mstore(C_V1_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x02)\\n mstore(C_V2_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x03)\\n mstore(C_V3_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x04)\\n mstore(C_V4_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x05)\\n mstore(C_V5_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x06)\\n mstore(C_V6_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x07)\\n mstore(C_V7_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x08)\\n mstore(C_V8_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x09)\\n mstore(C_V9_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x0a)\\n mstore(C_V10_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x0b)\\n mstore(C_V11_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x0c)\\n mstore(C_V12_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x0d)\\n mstore(C_V13_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x0e)\\n mstore(C_V14_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x0f)\\n mstore(C_V15_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x10)\\n mstore(C_V16_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x11)\\n mstore(C_V17_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x12)\\n mstore(C_V18_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x13)\\n mstore(C_V19_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x14)\\n mstore(C_V20_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x15)\\n mstore(C_V21_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x16)\\n mstore(C_V22_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x17)\\n mstore(C_V23_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x18)\\n mstore(C_V24_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x19)\\n mstore(C_V25_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x1a)\\n mstore(C_V26_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x1b)\\n mstore(C_V27_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x1c)\\n mstore(C_V28_LOC, mod(keccak256(0x00, 0x21), p))\\n mstore8(0x20, 0x1d)\\n mstore(C_V29_LOC, mod(keccak256(0x00, 0x21), p))\\n\\n // @follow-up - Why are both v29 and v30 using appending 0x1d to the prior challenge and hashing, should it not change?\\n mstore8(0x20, 0x1d)\\n challenge := keccak256(0x00, 0x21)\\n mstore(C_V30_LOC, mod(challenge, p))\\n\\n // separator\\n mstore(0x00, challenge)\\n mstore(0x20, mload(PI_Z_Y_LOC))\\n mstore(0x40, mload(PI_Z_X_LOC))\\n mstore(0x60, mload(PI_Z_OMEGA_Y_LOC))\\n mstore(0x80, mload(PI_Z_OMEGA_X_LOC))\\n\\n mstore(C_U_LOC, mod(keccak256(0x00, 0xa0), p))\\n }\\n\\n let success := 0\\n // VALIDATE T1\\n {\\n let x := mload(T1_X_LOC)\\n let y := mload(T1_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n mstore(ACCUMULATOR_X_LOC, x)\\n mstore(add(ACCUMULATOR_X_LOC, 0x20), y)\\n }\\n // VALIDATE T2\\n {\\n let x := mload(T2_X_LOC) // 0x1400\\n let y := mload(T2_Y_LOC) // 0x1420\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n mstore(0x00, x)\\n mstore(0x20, y)\\n }\\n mstore(0x40, mload(ZETA_POW_N_LOC))\\n // accumulator_2 = [T2].zeta^n\\n success := staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)\\n // accumulator = [T1] + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // VALIDATE T3\\n {\\n let x := mload(T3_X_LOC)\\n let y := mload(T3_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n mstore(0x00, x)\\n mstore(0x20, y)\\n }\\n mstore(0x40, mulmod(mload(ZETA_POW_N_LOC), mload(ZETA_POW_N_LOC), p))\\n // accumulator_2 = [T3].zeta^{2n}\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // VALIDATE T4\\n {\\n let x := mload(T4_X_LOC)\\n let y := mload(T4_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n mstore(0x00, x)\\n mstore(0x20, y)\\n }\\n mstore(0x40, mulmod(mulmod(mload(ZETA_POW_N_LOC), mload(ZETA_POW_N_LOC), p), mload(ZETA_POW_N_LOC), p))\\n // accumulator_2 = [T4].zeta^{3n}\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // VALIDATE W1\\n {\\n let x := mload(W1_X_LOC)\\n let y := mload(W1_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n mstore(0x00, x)\\n mstore(0x20, y)\\n }\\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V0_LOC), p))\\n // accumulator_2 = v0.(u + 1).[W1]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // VALIDATE W2\\n {\\n let x := mload(W2_X_LOC)\\n let y := mload(W2_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n mstore(0x00, x)\\n mstore(0x20, y)\\n }\\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V1_LOC), p))\\n // accumulator_2 = v1.(u + 1).[W2]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // VALIDATE W3\\n {\\n let x := mload(W3_X_LOC)\\n let y := mload(W3_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n mstore(0x00, x)\\n mstore(0x20, y)\\n }\\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V2_LOC), p))\\n // accumulator_2 = v2.(u + 1).[W3]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // VALIDATE W4\\n {\\n let x := mload(W4_X_LOC)\\n let y := mload(W4_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n mstore(0x00, x)\\n mstore(0x20, y)\\n }\\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V3_LOC), p))\\n // accumulator_2 = v3.(u + 1).[W4]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // VALIDATE S\\n {\\n let x := mload(S_X_LOC)\\n let y := mload(S_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n mstore(0x00, x)\\n mstore(0x20, y)\\n }\\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V4_LOC), p))\\n // accumulator_2 = v4.(u + 1).[S]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // VALIDATE Z\\n {\\n let x := mload(Z_X_LOC)\\n let y := mload(Z_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n mstore(0x00, x)\\n mstore(0x20, y)\\n }\\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V5_LOC), p))\\n // accumulator_2 = v5.(u + 1).[Z]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // VALIDATE Z_LOOKUP\\n {\\n let x := mload(Z_LOOKUP_X_LOC)\\n let y := mload(Z_LOOKUP_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n mstore(0x00, x)\\n mstore(0x20, y)\\n }\\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V6_LOC), p))\\n // accumulator_2 = v6.(u + 1).[Z_LOOKUP]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE Q1\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(Q1_X_LOC))\\n mstore(0x20, mload(Q1_Y_LOC))\\n mstore(0x40, mload(C_V7_LOC))\\n // accumulator_2 = v7.[Q1]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE Q2\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(Q2_X_LOC))\\n mstore(0x20, mload(Q2_Y_LOC))\\n mstore(0x40, mload(C_V8_LOC))\\n // accumulator_2 = v8.[Q2]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE Q3\\n \\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(Q3_X_LOC))\\n mstore(0x20, mload(Q3_Y_LOC))\\n mstore(0x40, mload(C_V9_LOC))\\n // accumulator_2 = v9.[Q3]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE Q4\\n \\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(Q4_X_LOC))\\n mstore(0x20, mload(Q4_Y_LOC))\\n mstore(0x40, mload(C_V10_LOC))\\n // accumulator_2 = v10.[Q4]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE QM\\n \\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(QM_X_LOC))\\n mstore(0x20, mload(QM_Y_LOC))\\n mstore(0x40, mload(C_V11_LOC))\\n // accumulator_2 = v11.[Q;]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE QC\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(QC_X_LOC))\\n mstore(0x20, mload(QC_Y_LOC))\\n mstore(0x40, mload(C_V12_LOC))\\n // accumulator_2 = v12.[QC]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE QARITH\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(QARITH_X_LOC))\\n mstore(0x20, mload(QARITH_Y_LOC))\\n mstore(0x40, mload(C_V13_LOC))\\n // accumulator_2 = v13.[QARITH]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE QSORT\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(QSORT_X_LOC))\\n mstore(0x20, mload(QSORT_Y_LOC))\\n mstore(0x40, mload(C_V14_LOC))\\n // accumulator_2 = v14.[QSORT]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE QELLIPTIC\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(QELLIPTIC_X_LOC))\\n mstore(0x20, mload(QELLIPTIC_Y_LOC))\\n mstore(0x40, mload(C_V15_LOC))\\n // accumulator_2 = v15.[QELLIPTIC]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE QAUX\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(QAUX_X_LOC))\\n mstore(0x20, mload(QAUX_Y_LOC))\\n mstore(0x40, mload(C_V16_LOC))\\n // accumulator_2 = v15.[Q_AUX]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE SIGMA1\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(SIGMA1_X_LOC))\\n mstore(0x20, mload(SIGMA1_Y_LOC))\\n mstore(0x40, mload(C_V17_LOC))\\n // accumulator_2 = v17.[sigma1]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE SIGMA2\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(SIGMA2_X_LOC))\\n mstore(0x20, mload(SIGMA2_Y_LOC))\\n mstore(0x40, mload(C_V18_LOC))\\n // accumulator_2 = v18.[sigma2]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE SIGMA3\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(SIGMA3_X_LOC))\\n mstore(0x20, mload(SIGMA3_Y_LOC))\\n mstore(0x40, mload(C_V19_LOC))\\n // accumulator_2 = v19.[sigma3]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE SIGMA4\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(SIGMA4_X_LOC))\\n mstore(0x20, mload(SIGMA4_Y_LOC))\\n mstore(0x40, mload(C_V20_LOC))\\n // accumulator_2 = v20.[sigma4]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE TABLE1\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(TABLE1_X_LOC))\\n mstore(0x20, mload(TABLE1_Y_LOC))\\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V21_LOC), p))\\n // accumulator_2 = u.[table1]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE TABLE2\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(TABLE2_X_LOC))\\n mstore(0x20, mload(TABLE2_Y_LOC))\\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V22_LOC), p))\\n // accumulator_2 = u.[table2]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE TABLE3\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(TABLE3_X_LOC))\\n mstore(0x20, mload(TABLE3_Y_LOC))\\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V23_LOC), p))\\n // accumulator_2 = u.[table3]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE TABLE4\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(TABLE4_X_LOC))\\n mstore(0x20, mload(TABLE4_Y_LOC))\\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V24_LOC), p))\\n // accumulator_2 = u.[table4]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE TABLE_TYPE\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(TABLE_TYPE_X_LOC))\\n mstore(0x20, mload(TABLE_TYPE_Y_LOC))\\n mstore(0x40, mload(C_V25_LOC))\\n // accumulator_2 = v25.[TableType]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE ID1\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(ID1_X_LOC))\\n mstore(0x20, mload(ID1_Y_LOC))\\n mstore(0x40, mload(C_V26_LOC))\\n // accumulator_2 = v26.[ID1]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE ID2\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(ID2_X_LOC))\\n mstore(0x20, mload(ID2_Y_LOC))\\n mstore(0x40, mload(C_V27_LOC))\\n // accumulator_2 = v27.[ID2]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE ID3\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(ID3_X_LOC))\\n mstore(0x20, mload(ID3_Y_LOC))\\n mstore(0x40, mload(C_V28_LOC))\\n // accumulator_2 = v28.[ID3]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // ACCUMULATE ID4\\n\\n // Verification key fields verified to be on curve at contract deployment\\n mstore(0x00, mload(ID4_X_LOC))\\n mstore(0x20, mload(ID4_Y_LOC))\\n mstore(0x40, mload(C_V29_LOC))\\n // accumulator_2 = v29.[ID4]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n /**\\n * COMPUTE BATCH EVALUATION SCALAR MULTIPLIER\\n */\\n {\\n /**\\n * batch_evaluation = v0 * (w_1_omega * u + w_1_eval)\\n * batch_evaluation += v1 * (w_2_omega * u + w_2_eval)\\n * batch_evaluation += v2 * (w_3_omega * u + w_3_eval)\\n * batch_evaluation += v3 * (w_4_omega * u + w_4_eval)\\n * batch_evaluation += v4 * (s_omega_eval * u + s_eval)\\n * batch_evaluation += v5 * (z_omega_eval * u + z_eval)\\n * batch_evaluation += v6 * (z_lookup_omega_eval * u + z_lookup_eval)\\n */\\n let batch_evaluation :=\\n mulmod(\\n mload(C_V0_LOC),\\n addmod(mulmod(mload(W1_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W1_EVAL_LOC), p),\\n p\\n )\\n batch_evaluation :=\\n addmod(\\n batch_evaluation,\\n mulmod(\\n mload(C_V1_LOC),\\n addmod(mulmod(mload(W2_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W2_EVAL_LOC), p),\\n p\\n ),\\n p\\n )\\n batch_evaluation :=\\n addmod(\\n batch_evaluation,\\n mulmod(\\n mload(C_V2_LOC),\\n addmod(mulmod(mload(W3_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W3_EVAL_LOC), p),\\n p\\n ),\\n p\\n )\\n batch_evaluation :=\\n addmod(\\n batch_evaluation,\\n mulmod(\\n mload(C_V3_LOC),\\n addmod(mulmod(mload(W4_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W4_EVAL_LOC), p),\\n p\\n ),\\n p\\n )\\n batch_evaluation :=\\n addmod(\\n batch_evaluation,\\n mulmod(\\n mload(C_V4_LOC),\\n addmod(mulmod(mload(S_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(S_EVAL_LOC), p),\\n p\\n ),\\n p\\n )\\n batch_evaluation :=\\n addmod(\\n batch_evaluation,\\n mulmod(\\n mload(C_V5_LOC),\\n addmod(mulmod(mload(Z_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(Z_EVAL_LOC), p),\\n p\\n ),\\n p\\n )\\n batch_evaluation :=\\n addmod(\\n batch_evaluation,\\n mulmod(\\n mload(C_V6_LOC),\\n addmod(mulmod(mload(Z_LOOKUP_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(Z_LOOKUP_EVAL_LOC), p),\\n p\\n ),\\n p\\n )\\n\\n /**\\n * batch_evaluation += v7 * Q1_EVAL\\n * batch_evaluation += v8 * Q2_EVAL\\n * batch_evaluation += v9 * Q3_EVAL\\n * batch_evaluation += v10 * Q4_EVAL\\n * batch_evaluation += v11 * QM_EVAL\\n * batch_evaluation += v12 * QC_EVAL\\n * batch_evaluation += v13 * QARITH_EVAL\\n * batch_evaluation += v14 * QSORT_EVAL_LOC\\n * batch_evaluation += v15 * QELLIPTIC_EVAL_LOC\\n * batch_evaluation += v16 * QAUX_EVAL_LOC\\n * batch_evaluation += v17 * SIGMA1_EVAL_LOC\\n * batch_evaluation += v18 * SIGMA2_EVAL_LOC\\n * batch_evaluation += v19 * SIGMA3_EVAL_LOC\\n * batch_evaluation += v20 * SIGMA4_EVAL_LOC\\n */\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V7_LOC), mload(Q1_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V8_LOC), mload(Q2_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V9_LOC), mload(Q3_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V10_LOC), mload(Q4_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V11_LOC), mload(QM_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V12_LOC), mload(QC_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V13_LOC), mload(QARITH_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V14_LOC), mload(QSORT_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V15_LOC), mload(QELLIPTIC_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V16_LOC), mload(QAUX_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V17_LOC), mload(SIGMA1_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V18_LOC), mload(SIGMA2_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V19_LOC), mload(SIGMA3_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V20_LOC), mload(SIGMA4_EVAL_LOC), p), p)\\n\\n /**\\n * batch_evaluation += v21 * (table1(zw) * u + table1(z))\\n * batch_evaluation += v22 * (table2(zw) * u + table2(z))\\n * batch_evaluation += v23 * (table3(zw) * u + table3(z))\\n * batch_evaluation += v24 * (table4(zw) * u + table4(z))\\n * batch_evaluation += v25 * table_type_eval\\n * batch_evaluation += v26 * id1_eval\\n * batch_evaluation += v27 * id2_eval\\n * batch_evaluation += v28 * id3_eval\\n * batch_evaluation += v29 * id4_eval\\n * batch_evaluation += quotient_eval\\n */\\n batch_evaluation :=\\n addmod(\\n batch_evaluation,\\n mulmod(\\n mload(C_V21_LOC),\\n addmod(mulmod(mload(TABLE1_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE1_EVAL_LOC), p),\\n p\\n ),\\n p\\n )\\n batch_evaluation :=\\n addmod(\\n batch_evaluation,\\n mulmod(\\n mload(C_V22_LOC),\\n addmod(mulmod(mload(TABLE2_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE2_EVAL_LOC), p),\\n p\\n ),\\n p\\n )\\n batch_evaluation :=\\n addmod(\\n batch_evaluation,\\n mulmod(\\n mload(C_V23_LOC),\\n addmod(mulmod(mload(TABLE3_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE3_EVAL_LOC), p),\\n p\\n ),\\n p\\n )\\n batch_evaluation :=\\n addmod(\\n batch_evaluation,\\n mulmod(\\n mload(C_V24_LOC),\\n addmod(mulmod(mload(TABLE4_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE4_EVAL_LOC), p),\\n p\\n ),\\n p\\n )\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V25_LOC), mload(TABLE_TYPE_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V26_LOC), mload(ID1_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V27_LOC), mload(ID2_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V28_LOC), mload(ID3_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V29_LOC), mload(ID4_EVAL_LOC), p), p)\\n batch_evaluation := addmod(batch_evaluation, mload(QUOTIENT_EVAL_LOC), p)\\n\\n mstore(0x00, 0x01) // [1].x\\n mstore(0x20, 0x02) // [1].y\\n mstore(0x40, sub(p, batch_evaluation))\\n // accumulator_2 = -[1].(batch_evaluation)\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n if iszero(success) {\\n mstore(0x0, OPENING_COMMITMENT_FAILED_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n }\\n\\n /**\\n * PERFORM PAIRING PREAMBLE\\n */\\n {\\n let u := mload(C_U_LOC)\\n let zeta := mload(C_ZETA_LOC)\\n // VALIDATE PI_Z\\n {\\n let x := mload(PI_Z_X_LOC)\\n let y := mload(PI_Z_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n mstore(0x00, x)\\n mstore(0x20, y)\\n }\\n // compute zeta.[PI_Z] and add into accumulator\\n mstore(0x40, zeta)\\n success := staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)\\n // accumulator = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\\n\\n // VALIDATE PI_Z_OMEGA\\n {\\n let x := mload(PI_Z_OMEGA_X_LOC)\\n let y := mload(PI_Z_OMEGA_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n mstore(0x00, x)\\n mstore(0x20, y)\\n }\\n mstore(0x40, mulmod(mulmod(u, zeta, p), mload(OMEGA_LOC), p))\\n // accumulator_2 = u.zeta.omega.[PI_Z_OMEGA]\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\\n // PAIRING_RHS = accumulator + accumulator_2\\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, PAIRING_RHS_X_LOC, 0x40))\\n\\n mstore(0x00, mload(PI_Z_X_LOC))\\n mstore(0x20, mload(PI_Z_Y_LOC))\\n mstore(0x40, mload(PI_Z_OMEGA_X_LOC))\\n mstore(0x60, mload(PI_Z_OMEGA_Y_LOC))\\n mstore(0x80, u)\\n success := and(success, staticcall(gas(), 7, 0x40, 0x60, 0x40, 0x40))\\n // PAIRING_LHS = [PI_Z] + [PI_Z_OMEGA] * u\\n success := and(success, staticcall(gas(), 6, 0x00, 0x80, PAIRING_LHS_X_LOC, 0x40))\\n // negate lhs y-coordinate\\n mstore(PAIRING_LHS_Y_LOC, sub(q, mload(PAIRING_LHS_Y_LOC)))\\n\\n if mload(CONTAINS_RECURSIVE_PROOF_LOC) {\\n // VALIDATE RECURSIVE P1\\n {\\n let x := mload(RECURSIVE_P1_X_LOC)\\n let y := mload(RECURSIVE_P1_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n mstore(0x00, x)\\n mstore(0x20, y)\\n }\\n\\n // compute u.u.[recursive_p1] and write into 0x60\\n mstore(0x40, mulmod(u, u, p))\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, 0x60, 0x40))\\n // VALIDATE RECURSIVE P2\\n {\\n let x := mload(RECURSIVE_P2_X_LOC)\\n let y := mload(RECURSIVE_P2_Y_LOC)\\n let xx := mulmod(x, x, q)\\n // validate on curve\\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n mstore(0x00, x)\\n mstore(0x20, y)\\n }\\n // compute u.u.[recursive_p2] and write into 0x00\\n // 0x40 still contains u*u\\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, 0x00, 0x40))\\n\\n // compute u.u.[recursiveP1] + rhs and write into rhs\\n mstore(0xa0, mload(PAIRING_RHS_X_LOC))\\n mstore(0xc0, mload(PAIRING_RHS_Y_LOC))\\n success := and(success, staticcall(gas(), 6, 0x60, 0x80, PAIRING_RHS_X_LOC, 0x40))\\n\\n // compute u.u.[recursiveP2] + lhs and write into lhs\\n mstore(0x40, mload(PAIRING_LHS_X_LOC))\\n mstore(0x60, mload(PAIRING_LHS_Y_LOC))\\n success := and(success, staticcall(gas(), 6, 0x00, 0x80, PAIRING_LHS_X_LOC, 0x40))\\n }\\n\\n if iszero(success) {\\n mstore(0x0, PAIRING_PREAMBLE_FAILED_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n }\\n\\n /**\\n * PERFORM PAIRING\\n */\\n {\\n // rhs paired with [1]_2\\n // lhs paired with [x]_2\\n\\n mstore(0x00, mload(PAIRING_RHS_X_LOC))\\n mstore(0x20, mload(PAIRING_RHS_Y_LOC))\\n mstore(0x40, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) // this is [1]_2\\n mstore(0x60, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed)\\n mstore(0x80, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b)\\n mstore(0xa0, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa)\\n\\n mstore(0xc0, mload(PAIRING_LHS_X_LOC))\\n mstore(0xe0, mload(PAIRING_LHS_Y_LOC))\\n mstore(0x100, mload(G2X_X0_LOC))\\n mstore(0x120, mload(G2X_X1_LOC))\\n mstore(0x140, mload(G2X_Y0_LOC))\\n mstore(0x160, mload(G2X_Y1_LOC))\\n\\n success := staticcall(gas(), 8, 0x00, 0x180, 0x00, 0x20)\\n if iszero(and(success, mload(0x00))) {\\n mstore(0x0, PAIRING_FAILED_SELECTOR)\\n revert(0x00, 0x04)\\n }\\n }\\n\\n {\\n mstore(0x00, 0x01)\\n return(0x00, 0x20) // Proof succeeded!\\n }\\n }\\n }\\n}\\n\\ncontract UltraVerifier is BaseUltraVerifier {\\n function getVerificationKeyHash() public pure override(BaseUltraVerifier) returns (bytes32) {\\n return UltraVerificationKey.verificationKeyHash();\\n }\\n\\n function loadVerificationKey(uint256 vk, uint256 _omegaInverseLoc) internal pure virtual override(BaseUltraVerifier) {\\n UltraVerificationKey.loadVerificationKey(vk, _omegaInverseLoc);\\n }\\n}\\n\",\"keccak256\":\"0x9ba7ac5c50cddbdf58b0f03b195df323d9f81981e6c9c043b2aa54b537133f06\",\"license\":\"Apache-2.0\"},\"solady/src/utils/Base64.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\n/// @notice Library to encode strings in Base64.\\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol)\\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol)\\n/// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - .\\nlibrary Base64 {\\n /// @dev Encodes `data` using the base64 encoding described in RFC 4648.\\n /// See: https://datatracker.ietf.org/doc/html/rfc4648\\n /// @param fileSafe Whether to replace '+' with '-' and '/' with '_'.\\n /// @param noPadding Whether to strip away the padding.\\n function encode(bytes memory data, bool fileSafe, bool noPadding)\\n internal\\n pure\\n returns (string memory result)\\n {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let dataLength := mload(data)\\n\\n if dataLength {\\n // Multiply by 4/3 rounded up.\\n // The `shl(2, ...)` is equivalent to multiplying by 4.\\n let encodedLength := shl(2, div(add(dataLength, 2), 3))\\n\\n // Set `result` to point to the start of the free memory.\\n result := mload(0x40)\\n\\n // Store the table into the scratch space.\\n // Offsetted by -1 byte so that the `mload` will load the character.\\n // We will rewrite the free memory pointer at `0x40` later with\\n // the allocated size.\\n // The magic constant 0x0670 will turn \\\"-_\\\" into \\\"+/\\\".\\n mstore(0x1f, \\\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef\\\")\\n mstore(0x3f, xor(\\\"ghijklmnopqrstuvwxyz0123456789-_\\\", mul(iszero(fileSafe), 0x0670)))\\n\\n // Skip the first slot, which stores the length.\\n let ptr := add(result, 0x20)\\n let end := add(ptr, encodedLength)\\n\\n let dataEnd := add(add(0x20, data), dataLength)\\n let dataEndValue := mload(dataEnd) // Cache the value at the `dataEnd` slot.\\n mstore(dataEnd, 0x00) // Zeroize the `dataEnd` slot to clear dirty bits.\\n\\n // Run over the input, 3 bytes at a time.\\n for {} 1 {} {\\n data := add(data, 3) // Advance 3 bytes.\\n let input := mload(data)\\n\\n // Write 4 bytes. Optimized for fewer stack operations.\\n mstore8(0, mload(and(shr(18, input), 0x3F)))\\n mstore8(1, mload(and(shr(12, input), 0x3F)))\\n mstore8(2, mload(and(shr(6, input), 0x3F)))\\n mstore8(3, mload(and(input, 0x3F)))\\n mstore(ptr, mload(0x00))\\n\\n ptr := add(ptr, 4) // Advance 4 bytes.\\n if iszero(lt(ptr, end)) { break }\\n }\\n mstore(dataEnd, dataEndValue) // Restore the cached value at `dataEnd`.\\n mstore(0x40, add(end, 0x20)) // Allocate the memory.\\n // Equivalent to `o = [0, 2, 1][dataLength % 3]`.\\n let o := div(2, mod(dataLength, 3))\\n // Offset `ptr` and pad with '='. We can simply write over the end.\\n mstore(sub(ptr, o), shl(240, 0x3d3d))\\n // Set `o` to zero if there is padding.\\n o := mul(iszero(iszero(noPadding)), o)\\n mstore(sub(ptr, o), 0) // Zeroize the slot after the string.\\n mstore(result, sub(encodedLength, o)) // Store the length.\\n }\\n }\\n }\\n\\n /// @dev Encodes `data` using the base64 encoding described in RFC 4648.\\n /// Equivalent to `encode(data, false, false)`.\\n function encode(bytes memory data) internal pure returns (string memory result) {\\n result = encode(data, false, false);\\n }\\n\\n /// @dev Encodes `data` using the base64 encoding described in RFC 4648.\\n /// Equivalent to `encode(data, fileSafe, false)`.\\n function encode(bytes memory data, bool fileSafe)\\n internal\\n pure\\n returns (string memory result)\\n {\\n result = encode(data, fileSafe, false);\\n }\\n\\n /// @dev Decodes base64 encoded `data`.\\n ///\\n /// Supports:\\n /// - RFC 4648 (both standard and file-safe mode).\\n /// - RFC 3501 (63: ',').\\n ///\\n /// Does not support:\\n /// - Line breaks.\\n ///\\n /// Note: For performance reasons,\\n /// this function will NOT revert on invalid `data` inputs.\\n /// Outputs for invalid inputs will simply be undefined behaviour.\\n /// It is the user's responsibility to ensure that the `data`\\n /// is a valid base64 encoded string.\\n function decode(string memory data) internal pure returns (bytes memory result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let dataLength := mload(data)\\n\\n if dataLength {\\n let decodedLength := mul(shr(2, dataLength), 3)\\n\\n for {} 1 {} {\\n // If padded.\\n if iszero(and(dataLength, 3)) {\\n let t := xor(mload(add(data, dataLength)), 0x3d3d)\\n // forgefmt: disable-next-item\\n decodedLength := sub(\\n decodedLength,\\n add(iszero(byte(30, t)), iszero(byte(31, t)))\\n )\\n break\\n }\\n // If non-padded.\\n decodedLength := add(decodedLength, sub(and(dataLength, 3), 1))\\n break\\n }\\n result := mload(0x40)\\n\\n // Write the length of the bytes.\\n mstore(result, decodedLength)\\n\\n // Skip the first slot, which stores the length.\\n let ptr := add(result, 0x20)\\n let end := add(ptr, decodedLength)\\n\\n // Load the table into the scratch space.\\n // Constants are optimized for smaller bytecode with zero gas overhead.\\n // `m` also doubles as the mask of the upper 6 bits.\\n let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc\\n mstore(0x5b, m)\\n mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064)\\n mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4)\\n\\n for {} 1 {} {\\n // Read 4 bytes.\\n data := add(data, 4)\\n let input := mload(data)\\n\\n // Write 3 bytes.\\n // forgefmt: disable-next-item\\n mstore(ptr, or(\\n and(m, mload(byte(28, input))),\\n shr(6, or(\\n and(m, mload(byte(29, input))),\\n shr(6, or(\\n and(m, mload(byte(30, input))),\\n shr(6, mload(byte(31, input)))\\n ))\\n ))\\n ))\\n ptr := add(ptr, 3)\\n if iszero(lt(ptr, end)) { break }\\n }\\n mstore(0x40, add(end, 0x20)) // Allocate the memory.\\n mstore(end, 0) // Zeroize the slot after the bytes.\\n mstore(0x60, 0) // Restore the zero slot.\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x07dcf983a86bc961e4cc0b57a2cfc3e46b20a50fed9b2092c7497e5fe3715a93\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x6080604052348015600f57600080fd5b506118d28061001f6000396000f3fe6080604052600436106100745760003560e01c8063affed0e01161004e578063affed0e01461014f578063bb3da92d14610173578063c389ca27146101be578063ff07203e146101de57600080fd5b8063041c9ae6146100805780637a28f8bc146100a25780637dc0872e1461011f57600080fd5b3661007b57005b600080fd5b34801561008c57600080fd5b506100a061009b36600461107b565b6101fe565b005b3480156100ae57600080fd5b506000546001546002546003546100de93929173ffffffffffffffffffffffffffffffffffffffff908116911684565b60408051948552602085019390935273ffffffffffffffffffffffffffffffffffffffff918216928401929092521660608201526080015b60405180910390f35b34801561012b57600080fd5b5060055460065461013a919082565b60408051928352602083019190915201610116565b34801561015b57600080fd5b5061016560045481565b604051908152602001610116565b34801561017f57600080fd5b50604080518082018252600080825260209182015281518083018352600554808252600654918301918252835190815290519181019190915201610116565b3480156101ca57600080fd5b506100a06101d936600461110a565b610369565b3480156101ea57600080fd5b506100a06101f9366004611250565b6104d1565b604080518235602080830191909152830135818301529083013590606001604051602081830303815290604052805190602001201461029e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c696420576562417574686e207075626c6963206b6579000000000060448201526064015b60405180910390fd5b604080516080810182526000548152600154602082015260025473ffffffffffffffffffffffffffffffffffffffff9081169282019290925260035490911660608201526102f4906102ef8461139f565b6105b1565b61035a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f696e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610295565b80356005556020013560065550565b600480546000918261037a83611433565b919050558787878760405160200161039695949392919061146b565b6040516020818303038152906040528051906020012090506103e781836103bc90611514565b6103cb368790038701876115cd565b60408051808201909152600554815260065460208201526108af565b6103f057600080fd5b60008773ffffffffffffffffffffffffffffffffffffffff1685888860405161041a92919061161e565b60006040518083038185875af1925050503d8060008114610457576040519150601f19603f3d011682016040523d82523d6000602084013e61045c565b606091505b50509050806104c7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f63616c6c206661696c65640000000000000000000000000000000000000000006044820152606401610295565b5050505050505050565b33301461053a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f6e6f742073656c660000000000000000000000000000000000000000000000006044820152606401610295565b81356005556020918201356006558051600055908101516001556040810151600280547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff93841617909155606090920151600380549093169116179055565b6000826040015173ffffffffffffffffffffffffffffffffffffffff16635879142a846020015184606001516040518363ffffffff1660e01b8152600401610603929190918252602082015260400190565b602060405180830381865afa158015610620573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610644919061162e565b6106aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f7075626c6963206b65792068617368206d69736d6174636800000000000000006044820152606401610295565b60006106b98360400151610ae1565b80519091506003906000906106ce908361164b565b67ffffffffffffffff8111156106e6576106e66111d5565b60405190808252806020026020018201604052801561070f578160200160208202803683370190505b508651909150600090828261072381611433565b9350815181106107355761073561165e565b602002602001018181525050856020015160001b82828061075590611433565b9350815181106107675761076761165e565b60209081029190910101526060860151828261078281611433565b9350815181106107945761079461165e565b60200260200101818152505060005b84518110156107f6578481815181106107be576107be61165e565b016020015160f81c83836107d181611433565b9450815181106107e3576107e361165e565b60209081029190910101526001016107a3565b50815181146108075761080761168d565b606087015186516040517fea50d0e400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9092169163ea50d0e4916108619186906004016116e0565b602060405180830381865afa15801561087e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a2919061162e565b9450505050505b92915050565b6000602584600001515110806108f157506108ef84600001516020815181106108da576108da61165e565b602001015160f81c60f81b8560800151610aee565b155b156108fe57506000610ad9565b60006040518060400160405280601581526020017f2274797065223a22776562617574686e2e676574220000000000000000000000815250905061094f818660200151876060015161ffff16610be0565b61095d576000915050610ad9565b600061098c8760405160200161097591815260200190565b604051602081830303815290604052600180610cc1565b90506000816040516020016109a1919061177a565b60405160208183030381529060405290506109c9818860200151896040015161ffff16610be0565b6109d95760009350505050610ad9565b6000600288602001516040516109ef91906117e6565b602060405180830381855afa158015610a0c573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610a2f9190611802565b905060006002896000015183604051602001610a4c92919061181b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610a84916117e6565b602060405180830381855afa158015610aa1573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610ac49190611802565b9050610ad1818989610dd2565b955050505050505b949350505050565b60606108a9826020610f0c565b60007f010000000000000000000000000000000000000000000000000000000000000083811614610b21575060006108a9565b818015610b5057507f040000000000000000000000000000000000000000000000000000000000000083811614155b15610b5d575060006108a9565b7f080000000000000000000000000000000000000000000000000000000000000083811614610bd7577ff0000000000000000000000000000000000000000000000000000000000000007f1000000000000000000000000000000000000000000000000000000000000000841601610bd7575060006108a9565b50600192915050565b825182516000918591859190845b82811015610cb05781610c01828961164b565b10610c1457600095505050505050610cba565b83610c1f828961164b565b81518110610c2f57610c2f61165e565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916858281518110610c6e57610c6e61165e565b01602001517fff000000000000000000000000000000000000000000000000000000000000001614610ca857600095505050505050610cba565b600101610bee565b5060019450505050505b9392505050565b606083518015610dca576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106708515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f52602083018181018388602001018051600082525b60038a0199508951603f8160121c1651600053603f81600c1c1651600153603f8160061c1651600253603f811651600353506000518452600484019350828410610d3d5790526020016040527f3d3d000000000000000000000000000000000000000000000000000000000000600384066002048083039190915260008615159091029182900352900382525b509392505050565b8151602080840151835184830151604080519485018990528401949094526060830191909152608082015260a08101919091526000908190819060149060c001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610e4a916117e6565b600060405180830381855afa9150503d8060008114610e85576040519150601f19603f3d011682016040523d82523d6000602084013e610e8a565b606091505b5091509150818015610e9d575080516020145b8015610f02575080601f81518110610eb757610eb761165e565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167f0100000000000000000000000000000000000000000000000000000000000000145b9695505050505050565b6060826000610f1c84600261183d565b67ffffffffffffffff811115610f3457610f346111d5565b6040519080825280601f01601f191660200182016040528015610f5e576020820181803683370190505b5090506000610f6e85600261183d565b610f7990600161164b565b90505b6001811115611020577f303132333435363738396162636465660000000000000000000000000000000083600f1660108110610fba57610fba61165e565b1a60f81b82610fca600284611854565b81518110610fda57610fda61165e565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049290921c9161101981611867565b9050610f7c565b508115610ad9576040517fe22e27eb0000000000000000000000000000000000000000000000000000000081526004810186905260248101859052604401610295565b60006040828403121561107557600080fd5b50919050565b6000806060838503121561108e57600080fd5b823567ffffffffffffffff8111156110a557600080fd5b8301608081860312156110b757600080fd5b91506110c68460208501611063565b90509250929050565b803573ffffffffffffffffffffffffffffffffffffffff811681146110f357600080fd5b919050565b600060a0828403121561107557600080fd5b60008060008060008060c0878903121561112357600080fd5b61112c876110cf565b9550602087013567ffffffffffffffff81111561114857600080fd5b8701601f8101891361115957600080fd5b803567ffffffffffffffff81111561117057600080fd5b89602082840101111561118257600080fd5b60209190910195509350604087013592506111a08860608901611063565b915060a087013567ffffffffffffffff8111156111bc57600080fd5b6111c889828a016110f8565b9150509295509295509295565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715611227576112276111d5565b60405290565b60405160a0810167ffffffffffffffff81118282101715611227576112276111d5565b60008082840360c081121561126457600080fd5b61126e8585611063565b925060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0820112156112a057600080fd5b506112a9611204565b60408401358152606084013560208201526112c6608085016110cf565b60408201526112d760a085016110cf565b6060820152809150509250929050565b60008067ffffffffffffffff841115611302576113026111d5565b506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85018116603f0116810181811067ffffffffffffffff8211171561134f5761134f6111d5565b60405283815290508082840185101561136757600080fd5b83836020830137600060208583010152509392505050565b600082601f83011261139057600080fd5b610cba838335602085016112e7565b6000608082360312156113b157600080fd5b6113b9611204565b823567ffffffffffffffff8111156113d057600080fd5b6113dc3682860161137f565b8252506020838101359082015260408084013590820152606092830135928101929092525090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361146457611464611404565b5060010190565b85815273ffffffffffffffffffffffffffffffffffffffff8516602082015260806040820152826080820152828460a0830137600060a08483010152600060a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b803561ffff811681146110f357600080fd5b801515811461150657600080fd5b50565b80356110f3816114f8565b600060a0823603121561152657600080fd5b61152e61122d565b823567ffffffffffffffff81111561154557600080fd5b6115513682860161137f565b825250602083013567ffffffffffffffff81111561156e57600080fd5b830136601f82011261157f57600080fd5b61158e368235602084016112e7565b6020830152506115a0604084016114e6565b60408201526115b1606084016114e6565b60608201526115c260808401611509565b608082015292915050565b600060408284031280156115e057600080fd5b506040805190810167ffffffffffffffff81118282101715611604576116046111d5565b604052823581526020928301359281019290925250919050565b8183823760009101908152919050565b60006020828403121561164057600080fd5b8151610cba816114f8565b808201808211156108a9576108a9611404565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b60005b838110156116d75781810151838201526020016116bf565b50506000910152565b60408152600083518060408401526116ff8160608501602088016116bc565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201828103606090810160208086019190915285519183018290528501916000916080909101905b8083101561176f578351825260208201915060208401935060018301925061174c565b509695505050505050565b7f226368616c6c656e6765223a22000000000000000000000000000000000000008152600082516117b281600d8501602087016116bc565b7f2200000000000000000000000000000000000000000000000000000000000000600d939091019283015250600e01919050565b600082516117f88184602087016116bc565b9190910192915050565b60006020828403121561181457600080fd5b5051919050565b6000835161182d8184602088016116bc565b9190910191825250602001919050565b80820281158282048414176108a9576108a9611404565b818103818111156108a9576108a9611404565b60008161187657611876611404565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea26469706673582212200f13d9d851d2190cfbe947e89c27b152eef4ae0ea84ce51cb3027758d574341a64736f6c634300081b0033", + "deployedBytecode": "0x6080604052600436106100745760003560e01c8063affed0e01161004e578063affed0e01461014f578063bb3da92d14610173578063c389ca27146101be578063ff07203e146101de57600080fd5b8063041c9ae6146100805780637a28f8bc146100a25780637dc0872e1461011f57600080fd5b3661007b57005b600080fd5b34801561008c57600080fd5b506100a061009b36600461107b565b6101fe565b005b3480156100ae57600080fd5b506000546001546002546003546100de93929173ffffffffffffffffffffffffffffffffffffffff908116911684565b60408051948552602085019390935273ffffffffffffffffffffffffffffffffffffffff918216928401929092521660608201526080015b60405180910390f35b34801561012b57600080fd5b5060055460065461013a919082565b60408051928352602083019190915201610116565b34801561015b57600080fd5b5061016560045481565b604051908152602001610116565b34801561017f57600080fd5b50604080518082018252600080825260209182015281518083018352600554808252600654918301918252835190815290519181019190915201610116565b3480156101ca57600080fd5b506100a06101d936600461110a565b610369565b3480156101ea57600080fd5b506100a06101f9366004611250565b6104d1565b604080518235602080830191909152830135818301529083013590606001604051602081830303815290604052805190602001201461029e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c696420576562417574686e207075626c6963206b6579000000000060448201526064015b60405180910390fd5b604080516080810182526000548152600154602082015260025473ffffffffffffffffffffffffffffffffffffffff9081169282019290925260035490911660608201526102f4906102ef8461139f565b6105b1565b61035a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f696e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610295565b80356005556020013560065550565b600480546000918261037a83611433565b919050558787878760405160200161039695949392919061146b565b6040516020818303038152906040528051906020012090506103e781836103bc90611514565b6103cb368790038701876115cd565b60408051808201909152600554815260065460208201526108af565b6103f057600080fd5b60008773ffffffffffffffffffffffffffffffffffffffff1685888860405161041a92919061161e565b60006040518083038185875af1925050503d8060008114610457576040519150601f19603f3d011682016040523d82523d6000602084013e61045c565b606091505b50509050806104c7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f63616c6c206661696c65640000000000000000000000000000000000000000006044820152606401610295565b5050505050505050565b33301461053a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f6e6f742073656c660000000000000000000000000000000000000000000000006044820152606401610295565b81356005556020918201356006558051600055908101516001556040810151600280547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff93841617909155606090920151600380549093169116179055565b6000826040015173ffffffffffffffffffffffffffffffffffffffff16635879142a846020015184606001516040518363ffffffff1660e01b8152600401610603929190918252602082015260400190565b602060405180830381865afa158015610620573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610644919061162e565b6106aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f7075626c6963206b65792068617368206d69736d6174636800000000000000006044820152606401610295565b60006106b98360400151610ae1565b80519091506003906000906106ce908361164b565b67ffffffffffffffff8111156106e6576106e66111d5565b60405190808252806020026020018201604052801561070f578160200160208202803683370190505b508651909150600090828261072381611433565b9350815181106107355761073561165e565b602002602001018181525050856020015160001b82828061075590611433565b9350815181106107675761076761165e565b60209081029190910101526060860151828261078281611433565b9350815181106107945761079461165e565b60200260200101818152505060005b84518110156107f6578481815181106107be576107be61165e565b016020015160f81c83836107d181611433565b9450815181106107e3576107e361165e565b60209081029190910101526001016107a3565b50815181146108075761080761168d565b606087015186516040517fea50d0e400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9092169163ea50d0e4916108619186906004016116e0565b602060405180830381865afa15801561087e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a2919061162e565b9450505050505b92915050565b6000602584600001515110806108f157506108ef84600001516020815181106108da576108da61165e565b602001015160f81c60f81b8560800151610aee565b155b156108fe57506000610ad9565b60006040518060400160405280601581526020017f2274797065223a22776562617574686e2e676574220000000000000000000000815250905061094f818660200151876060015161ffff16610be0565b61095d576000915050610ad9565b600061098c8760405160200161097591815260200190565b604051602081830303815290604052600180610cc1565b90506000816040516020016109a1919061177a565b60405160208183030381529060405290506109c9818860200151896040015161ffff16610be0565b6109d95760009350505050610ad9565b6000600288602001516040516109ef91906117e6565b602060405180830381855afa158015610a0c573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610a2f9190611802565b905060006002896000015183604051602001610a4c92919061181b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610a84916117e6565b602060405180830381855afa158015610aa1573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610ac49190611802565b9050610ad1818989610dd2565b955050505050505b949350505050565b60606108a9826020610f0c565b60007f010000000000000000000000000000000000000000000000000000000000000083811614610b21575060006108a9565b818015610b5057507f040000000000000000000000000000000000000000000000000000000000000083811614155b15610b5d575060006108a9565b7f080000000000000000000000000000000000000000000000000000000000000083811614610bd7577ff0000000000000000000000000000000000000000000000000000000000000007f1000000000000000000000000000000000000000000000000000000000000000841601610bd7575060006108a9565b50600192915050565b825182516000918591859190845b82811015610cb05781610c01828961164b565b10610c1457600095505050505050610cba565b83610c1f828961164b565b81518110610c2f57610c2f61165e565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916858281518110610c6e57610c6e61165e565b01602001517fff000000000000000000000000000000000000000000000000000000000000001614610ca857600095505050505050610cba565b600101610bee565b5060019450505050505b9392505050565b606083518015610dca576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106708515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f52602083018181018388602001018051600082525b60038a0199508951603f8160121c1651600053603f81600c1c1651600153603f8160061c1651600253603f811651600353506000518452600484019350828410610d3d5790526020016040527f3d3d000000000000000000000000000000000000000000000000000000000000600384066002048083039190915260008615159091029182900352900382525b509392505050565b8151602080840151835184830151604080519485018990528401949094526060830191909152608082015260a08101919091526000908190819060149060c001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610e4a916117e6565b600060405180830381855afa9150503d8060008114610e85576040519150601f19603f3d011682016040523d82523d6000602084013e610e8a565b606091505b5091509150818015610e9d575080516020145b8015610f02575080601f81518110610eb757610eb761165e565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167f0100000000000000000000000000000000000000000000000000000000000000145b9695505050505050565b6060826000610f1c84600261183d565b67ffffffffffffffff811115610f3457610f346111d5565b6040519080825280601f01601f191660200182016040528015610f5e576020820181803683370190505b5090506000610f6e85600261183d565b610f7990600161164b565b90505b6001811115611020577f303132333435363738396162636465660000000000000000000000000000000083600f1660108110610fba57610fba61165e565b1a60f81b82610fca600284611854565b81518110610fda57610fda61165e565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049290921c9161101981611867565b9050610f7c565b508115610ad9576040517fe22e27eb0000000000000000000000000000000000000000000000000000000081526004810186905260248101859052604401610295565b60006040828403121561107557600080fd5b50919050565b6000806060838503121561108e57600080fd5b823567ffffffffffffffff8111156110a557600080fd5b8301608081860312156110b757600080fd5b91506110c68460208501611063565b90509250929050565b803573ffffffffffffffffffffffffffffffffffffffff811681146110f357600080fd5b919050565b600060a0828403121561107557600080fd5b60008060008060008060c0878903121561112357600080fd5b61112c876110cf565b9550602087013567ffffffffffffffff81111561114857600080fd5b8701601f8101891361115957600080fd5b803567ffffffffffffffff81111561117057600080fd5b89602082840101111561118257600080fd5b60209190910195509350604087013592506111a08860608901611063565b915060a087013567ffffffffffffffff8111156111bc57600080fd5b6111c889828a016110f8565b9150509295509295509295565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715611227576112276111d5565b60405290565b60405160a0810167ffffffffffffffff81118282101715611227576112276111d5565b60008082840360c081121561126457600080fd5b61126e8585611063565b925060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0820112156112a057600080fd5b506112a9611204565b60408401358152606084013560208201526112c6608085016110cf565b60408201526112d760a085016110cf565b6060820152809150509250929050565b60008067ffffffffffffffff841115611302576113026111d5565b506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85018116603f0116810181811067ffffffffffffffff8211171561134f5761134f6111d5565b60405283815290508082840185101561136757600080fd5b83836020830137600060208583010152509392505050565b600082601f83011261139057600080fd5b610cba838335602085016112e7565b6000608082360312156113b157600080fd5b6113b9611204565b823567ffffffffffffffff8111156113d057600080fd5b6113dc3682860161137f565b8252506020838101359082015260408084013590820152606092830135928101929092525090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361146457611464611404565b5060010190565b85815273ffffffffffffffffffffffffffffffffffffffff8516602082015260806040820152826080820152828460a0830137600060a08483010152600060a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b803561ffff811681146110f357600080fd5b801515811461150657600080fd5b50565b80356110f3816114f8565b600060a0823603121561152657600080fd5b61152e61122d565b823567ffffffffffffffff81111561154557600080fd5b6115513682860161137f565b825250602083013567ffffffffffffffff81111561156e57600080fd5b830136601f82011261157f57600080fd5b61158e368235602084016112e7565b6020830152506115a0604084016114e6565b60408201526115b1606084016114e6565b60608201526115c260808401611509565b608082015292915050565b600060408284031280156115e057600080fd5b506040805190810167ffffffffffffffff81118282101715611604576116046111d5565b604052823581526020928301359281019290925250919050565b8183823760009101908152919050565b60006020828403121561164057600080fd5b8151610cba816114f8565b808201808211156108a9576108a9611404565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b60005b838110156116d75781810151838201526020016116bf565b50506000910152565b60408152600083518060408401526116ff8160608501602088016116bc565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201828103606090810160208086019190915285519183018290528501916000916080909101905b8083101561176f578351825260208201915060208401935060018301925061174c565b509695505050505050565b7f226368616c6c656e6765223a22000000000000000000000000000000000000008152600082516117b281600d8501602087016116bc565b7f2200000000000000000000000000000000000000000000000000000000000000600d939091019283015250600e01919050565b600082516117f88184602087016116bc565b9190910192915050565b60006020828403121561181457600080fd5b5051919050565b6000835161182d8184602088016116bc565b9190910191825250602001919050565b80820281158282048414176108a9576108a9611404565b818103818111156108a9576108a9611404565b60008161187657611876611404565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea26469706673582212200f13d9d851d2190cfbe947e89c27b152eef4ae0ea84ce51cb3027758d574341a64736f6c634300081b0033", + "devdoc": { + "errors": { + "StringsInsufficientHexLength(uint256,uint256)": [ + { + "details": "The `value` string doesn't fit in the specified `length`." + } + ] + }, + "kind": "dev", + "methods": {}, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 14, + "contract": "contracts/EoaAccount.sol:EoaAccount", + "label": "accountData", + "offset": 0, + "slot": "0", + "type": "t_struct(AccountData)181_storage" + }, + { + "astId": 16, + "contract": "contracts/EoaAccount.sol:EoaAccount", + "label": "nonce", + "offset": 0, + "slot": "4", + "type": "t_uint256" + }, + { + "astId": 19, + "contract": "contracts/EoaAccount.sol:EoaAccount", + "label": "webauthnPublicKey", + "offset": 0, + "slot": "5", + "type": "t_struct(PublicKey)344_storage" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bytes32": { + "encoding": "inplace", + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_struct(AccountData)181_storage": { + "encoding": "inplace", + "label": "struct ZkLogin.AccountData", + "members": [ + { + "astId": 174, + "contract": "contracts/EoaAccount.sol:EoaAccount", + "label": "accountId", + "offset": 0, + "slot": "0", + "type": "t_bytes32" + }, + { + "astId": 176, + "contract": "contracts/EoaAccount.sol:EoaAccount", + "label": "authProviderId", + "offset": 0, + "slot": "1", + "type": "t_bytes32" + }, + { + "astId": 178, + "contract": "contracts/EoaAccount.sol:EoaAccount", + "label": "publicKeyRegistry", + "offset": 0, + "slot": "2", + "type": "t_address" + }, + { + "astId": 180, + "contract": "contracts/EoaAccount.sol:EoaAccount", + "label": "proofVerifier", + "offset": 0, + "slot": "3", + "type": "t_address" + } + ], + "numberOfBytes": "128" + }, + "t_struct(PublicKey)344_storage": { + "encoding": "inplace", + "label": "struct ECDSA.PublicKey", + "members": [ + { + "astId": 341, + "contract": "contracts/EoaAccount.sol:EoaAccount", + "label": "x", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 343, + "contract": "contracts/EoaAccount.sol:EoaAccount", + "label": "y", + "offset": 0, + "slot": "1", + "type": "t_uint256" + } + ], + "numberOfBytes": "64" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} \ No newline at end of file diff --git a/packages/contracts/deployments/odysseyTestnet/solcInputs/bba85c7f434c9beec0a49080c39fcff7.json b/packages/contracts/deployments/odysseyTestnet/solcInputs/bba85c7f434c9beec0a49080c39fcff7.json new file mode 100644 index 0000000..07c91c6 --- /dev/null +++ b/packages/contracts/deployments/odysseyTestnet/solcInputs/bba85c7f434c9beec0a49080c39fcff7.json @@ -0,0 +1,66 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n /**\n * @dev The caller account is not authorized to perform an operation.\n */\n error OwnableUnauthorizedAccount(address account);\n\n /**\n * @dev The owner is not a valid owner account. (eg. `address(0)`)\n */\n error OwnableInvalidOwner(address owner);\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n */\n constructor(address initialOwner) {\n if (initialOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(initialOwner);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n if (owner() != _msgSender()) {\n revert OwnableUnauthorizedAccount(_msgSender());\n }\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby disabling any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n if (newOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n" + }, + "contracts/ECDSA.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\nlibrary ECDSA {\n struct PublicKey {\n uint256 x;\n uint256 y;\n }\n\n struct Signature {\n uint256 r;\n uint256 s;\n }\n\n struct RecoveredSignature {\n uint256 r;\n uint256 s;\n uint8 yParity;\n }\n}\n" + }, + "contracts/EoaAccount.sol": { + "content": "// SPDX-License-Identifier: SEE LICENSE IN LICENSE\npragma solidity ^0.8.27;\n\nimport {ZkLogin} from \"./ZkLogin.sol\";\nimport {PublicKeyRegistry} from \"./PublicKeyRegistry.sol\";\nimport {UltraVerifier} from \"../noir/target/jwt_account.sol\";\nimport {WebAuthnP256} from \"./WebAuthnP256.sol\";\nimport {ECDSA} from \"./ECDSA.sol\";\n\ncontract EoaAccount {\n ZkLogin.AccountData public accountData;\n\n uint256 public nonce;\n\n ECDSA.PublicKey public webauthnPublicKey;\n\n function setAccountId(\n ECDSA.PublicKey calldata webauthnPublicKey_,\n ZkLogin.AccountData memory accountData_\n ) external {\n require(msg.sender == address(this), \"not self\");\n\n webauthnPublicKey = webauthnPublicKey_;\n\n accountData = accountData_;\n }\n\n function recover(\n ZkLogin.VerificationData calldata verificationData,\n ECDSA.PublicKey calldata newP256PublicKey\n ) external {\n require(\n keccak256(abi.encode(newP256PublicKey)) ==\n verificationData.jwtNonce,\n \"invalid WebAuthn public key\"\n );\n\n require(\n ZkLogin.verifyProof(accountData, verificationData),\n \"invalid proof\"\n );\n\n webauthnPublicKey = newP256PublicKey;\n }\n\n function execute(\n address to,\n bytes calldata data,\n uint256 value,\n ECDSA.Signature calldata signature,\n WebAuthnP256.Metadata calldata metadata\n ) public {\n bytes32 challenge = keccak256(abi.encode(nonce++, to, data, value));\n require(\n WebAuthnP256.verify(\n challenge,\n metadata,\n signature,\n webauthnPublicKey\n )\n );\n\n (bool success, ) = to.call{value: value}(data);\n require(success, \"call failed\");\n }\n\n function getWebAuthnPublicKey()\n external\n view\n returns (ECDSA.PublicKey memory)\n {\n return webauthnPublicKey;\n }\n\n receive() external payable {}\n}\n" + }, + "contracts/P256.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\nimport \"./ECDSA.sol\";\n\n//( @title P256\n/// @author klkvr \n/// @author jxom \n/// @notice Wrapper function to abstract low level details of call to the P256\n/// signature verification precompile as defined in EIP-7212, see\n/// .\nlibrary P256 {\n /// @notice P256VERIFY operation\n /// @param digest 32 bytes of the signed data hash\n /// @param signature Signature of the signer\n /// @param publicKey Public key of the signer\n /// @return success Represents if the operation was successful\n function verify(\n bytes32 digest,\n ECDSA.Signature memory signature,\n ECDSA.PublicKey memory publicKey\n ) internal view returns (bool) {\n // P256VERIFY address is 0x14 from \n (bool success, bytes memory output) = address(0x14).staticcall(\n abi.encode(\n digest,\n signature.r,\n signature.s,\n publicKey.x,\n publicKey.y\n )\n );\n success = success && output.length == 32 && output[31] == 0x01;\n\n return success;\n }\n}\n" + }, + "contracts/PublicKeyRegistry.sol": { + "content": "// SPDX-License-Identifier: SEE LICENSE IN LICENSE\npragma solidity ^0.8.27;\n\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\n\ncontract PublicKeyRegistry is Ownable(msg.sender) {\n /// providerId => publicKeyHash => isValid\n mapping(bytes32 => mapping(bytes32 => bool)) public isPublicKeyHashValid;\n\n function setPublicKeyValid(\n bytes32 providerId,\n bytes32 publicKeyHash,\n bool valid\n ) external onlyOwner {\n isPublicKeyHashValid[providerId][publicKeyHash] = valid;\n }\n\n struct PublicKeyValidity {\n bytes32 providerId;\n bytes32 publicKeyHash;\n bool valid;\n }\n\n function setPublicKeysValid(\n PublicKeyValidity[] calldata validity\n ) external onlyOwner {\n for (uint256 i = 0; i < validity.length; i++) {\n PublicKeyValidity calldata v = validity[i];\n isPublicKeyHashValid[v.providerId][v.publicKeyHash] = v.valid;\n }\n }\n\n function checkPublicKey(\n bytes32 providerId,\n bytes32 publicKeyHash\n ) external view returns (bool) {\n return isPublicKeyHashValid[providerId][publicKeyHash];\n }\n}\n" + }, + "contracts/Strings.sol": { + "content": "// SPDX-License-Identifier: SEE LICENSE IN LICENSE\npragma solidity ^0.8.27;\n\nlibrary Strings {\n bytes16 private constant HEX_DIGITS = \"0123456789abcdef\";\n\n /**\n * @dev The `value` string doesn't fit in the specified `length`.\n */\n error StringsInsufficientHexLength(uint256 value, uint256 length);\n\n function toHexStringWithoutPrefix(\n uint256 value,\n uint256 length\n ) internal pure returns (string memory) {\n uint256 localValue = value;\n bytes memory buffer = new bytes(2 * length);\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i - 2] = HEX_DIGITS[localValue & 0xf];\n localValue >>= 4;\n }\n if (localValue != 0) {\n revert StringsInsufficientHexLength(value, length);\n }\n return string(buffer);\n }\n\n function toHexStringWithoutPrefix(\n bytes32 value\n ) internal pure returns (string memory) {\n return toHexStringWithoutPrefix(uint256(value), 32);\n }\n}\n" + }, + "contracts/WebAuthnP256.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\nimport {Base64} from \"solady/src/utils/Base64.sol\";\nimport \"./ECDSA.sol\";\nimport \"./P256.sol\";\n\n/// @title WebAuthnP256\n/// @author jxom \n/// @notice Helper library for external contracts to verify WebAuthn signatures.\n/// @dev Adapted from https://github.com/daimo-eth/p256-verifier/blob/master/src/WebAuthn.sol\nlibrary WebAuthnP256 {\n struct Metadata {\n bytes authenticatorData;\n string clientDataJSON;\n uint16 challengeIndex;\n uint16 typeIndex;\n bool userVerificationRequired;\n }\n\n /// Checks whether substr occurs in str starting at a given byte offset.\n function contains(\n string memory substr,\n string memory str,\n uint256 location\n ) internal pure returns (bool) {\n bytes memory substrBytes = bytes(substr);\n bytes memory strBytes = bytes(str);\n\n uint256 substrLen = substrBytes.length;\n uint256 strLen = strBytes.length;\n\n for (uint256 i = 0; i < substrLen; i++) {\n if (location + i >= strLen) {\n return false;\n }\n\n if (substrBytes[i] != strBytes[location + i]) {\n return false;\n }\n }\n\n return true;\n }\n\n bytes1 constant AUTH_DATA_FLAGS_UP = 0x01; // Bit 0\n bytes1 constant AUTH_DATA_FLAGS_UV = 0x04; // Bit 2\n bytes1 constant AUTH_DATA_FLAGS_BE = 0x08; // Bit 3\n bytes1 constant AUTH_DATA_FLAGS_BS = 0x10; // Bit 4\n\n /// Verifies the authFlags in authenticatorData. Numbers in inline comment\n /// correspond to the same numbered bullets in\n /// https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion.\n function checkAuthFlags(\n bytes1 flags,\n bool requireUserVerification\n ) internal pure returns (bool) {\n // 17. Verify that the UP bit of the flags in authData is set.\n if (flags & AUTH_DATA_FLAGS_UP != AUTH_DATA_FLAGS_UP) {\n return false;\n }\n\n // 18. If user verification was determined to be required, verify that\n // the UV bit of the flags in authData is set. Otherwise, ignore the\n // value of the UV flag.\n if (\n requireUserVerification &&\n (flags & AUTH_DATA_FLAGS_UV) != AUTH_DATA_FLAGS_UV\n ) {\n return false;\n }\n\n // 19. If the BE bit of the flags in authData is not set, verify that\n // the BS bit is not set.\n if (flags & AUTH_DATA_FLAGS_BE != AUTH_DATA_FLAGS_BE) {\n if (flags & AUTH_DATA_FLAGS_BS == AUTH_DATA_FLAGS_BS) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Verifies a Webauthn P256 signature (Authentication Assertion) as described\n * in https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion. We do not\n * verify all the steps as described in the specification, only ones relevant\n * to our context. Please carefully read through this list before usage.\n * Specifically, we do verify the following:\n * - Verify that authenticatorData (which comes from the authenticator,\n * such as iCloud Keychain) indicates a well-formed assertion. If\n * requireUserVerification is set, checks that the authenticator enforced\n * user verification. User verification should be required if,\n * and only if, options.userVerification is set to required in the request\n * - Verifies that the client JSON is of type \"webauthn.get\", i.e. the client\n * was responding to a request to assert authentication.\n * - Verifies that the client JSON contains the requested challenge.\n * - Finally, verifies that (r, s) constitute a valid signature over both\n * the authenicatorData and client JSON, for public key (x, y).\n *\n * We make some assumptions about the particular use case of this verifier,\n * so we do NOT verify the following:\n * - Does NOT verify that the origin in the clientDataJSON matches the\n * Relying Party's origin: It is considered the authenticator's\n * responsibility to ensure that the user is interacting with the correct\n * RP. This is enforced by most high quality authenticators properly,\n * particularly the iCloud Keychain and Google Password Manager were\n * tested.\n * - Does NOT verify That c.topOrigin is well-formed: We assume c.topOrigin\n * would never be present, i.e. the credentials are never used in a\n * cross-origin/iframe context. The website/app set up should disallow\n * cross-origin usage of the credentials. This is the default behaviour for\n * created credentials in common settings.\n * - Does NOT verify that the rpIdHash in authData is the SHA-256 hash of an\n * RP ID expected by the Relying Party: This means that we rely on the\n * authenticator to properly enforce credentials to be used only by the\n * correct RP. This is generally enforced with features like Apple App Site\n * Association and Google Asset Links. To protect from edge cases in which\n * a previously-linked RP ID is removed from the authorised RP IDs,\n * we recommend that messages signed by the authenticator include some\n * expiry mechanism.\n * - Does NOT verify the credential backup state: This assumes the credential\n * backup state is NOT used as part of Relying Party business logic or\n * policy.\n * - Does NOT verify the values of the client extension outputs: This assumes\n * that the Relying Party does not use client extension outputs.\n * - Does NOT verify the signature counter: Signature counters are intended\n * to enable risk scoring for the Relying Party. This assumes risk scoring\n * is not used as part of Relying Party business logic or policy.\n * - Does NOT verify the attestation object: This assumes that\n * response.attestationObject is NOT present in the response, i.e. the\n * RP does not intend to verify an attestation.\n */\n function verify(\n bytes32 challenge,\n Metadata memory metadata,\n ECDSA.Signature memory signature,\n ECDSA.PublicKey memory publicKey\n ) internal view returns (bool) {\n // Check that authenticatorData has good flags\n if (\n metadata.authenticatorData.length < 37 ||\n !checkAuthFlags(\n metadata.authenticatorData[32],\n metadata.userVerificationRequired\n )\n ) {\n return false;\n }\n\n // Check that response is for an authentication assertion\n string memory responseType = '\"type\":\"webauthn.get\"';\n if (\n !contains(responseType, metadata.clientDataJSON, metadata.typeIndex)\n ) {\n return false;\n }\n\n // Check that challenge is in the clientDataJSON\n string memory challengeB64url = Base64.encode(\n abi.encodePacked(challenge),\n true,\n true\n );\n string memory challengeProperty = string.concat(\n '\"challenge\":\"',\n challengeB64url,\n '\"'\n );\n\n if (\n !contains(\n challengeProperty,\n metadata.clientDataJSON,\n metadata.challengeIndex\n )\n ) {\n return false;\n }\n\n // Check that the public key signed sha256(authenticatorData || sha256(clientDataJSON))\n bytes32 clientDataJSONHash = sha256(bytes(metadata.clientDataJSON));\n bytes32 messageHash = sha256(\n abi.encodePacked(metadata.authenticatorData, clientDataJSONHash)\n );\n\n return P256.verify(messageHash, signature, publicKey);\n }\n}\n" + }, + "contracts/ZkLogin.sol": { + "content": "// SPDX-License-Identifier: SEE LICENSE IN LICENSE\npragma solidity ^0.8.27;\n\nimport {UltraVerifier} from \"../noir/target/jwt_account.sol\";\nimport {Strings} from \"./Strings.sol\";\nimport {PublicKeyRegistry} from \"./PublicKeyRegistry.sol\";\n\nlibrary ZkLogin {\n struct AccountData {\n bytes32 accountId;\n bytes32 authProviderId;\n PublicKeyRegistry publicKeyRegistry;\n UltraVerifier proofVerifier;\n }\n\n struct VerificationData {\n bytes proof;\n uint256 jwtIat;\n bytes32 jwtNonce;\n bytes32 publicKeyHash;\n }\n\n function verifyProof(\n AccountData memory accountData,\n VerificationData memory verificationData\n ) internal view returns (bool) {\n require(\n accountData.publicKeyRegistry.checkPublicKey(\n accountData.authProviderId,\n verificationData.publicKeyHash\n ),\n \"public key hash mismatch\"\n );\n\n bytes memory jwtNonce = bytes(\n Strings.toHexStringWithoutPrefix(verificationData.jwtNonce)\n );\n\n uint256 staticInputLength = 3;\n bytes32[] memory publicInputs = new bytes32[](\n staticInputLength + jwtNonce.length\n );\n uint256 j = 0;\n publicInputs[j++] = accountData.accountId;\n publicInputs[j++] = bytes32(verificationData.jwtIat);\n publicInputs[j++] = verificationData.publicKeyHash;\n\n for (uint256 i = 0; i < jwtNonce.length; i++) {\n publicInputs[j++] = bytes32(uint256(uint8(jwtNonce[i])));\n }\n\n return\n accountData.proofVerifier.verify(\n verificationData.proof,\n publicInputs\n );\n }\n}\n" + }, + "noir/target/jwt_account.sol": { + "content": "// Verification Key Hash: 5bca26b0c155cf304f99a1e9e73c1ab8a3b80fa001c15a5b003c87f4584ced4c\n// SPDX-License-Identifier: Apache-2.0\n// Copyright 2022 Aztec\npragma solidity >=0.8.4;\n\nlibrary UltraVerificationKey {\n function verificationKeyHash() internal pure returns(bytes32) {\n return 0x5bca26b0c155cf304f99a1e9e73c1ab8a3b80fa001c15a5b003c87f4584ced4c;\n }\n\n function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure {\n assembly {\n mstore(add(_vk, 0x00), 0x0000000000000000000000000000000000000000000000000000000000040000) // vk.circuit_size\n mstore(add(_vk, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000043) // vk.num_inputs\n mstore(add(_vk, 0x40), 0x19ddbcaf3a8d46c15c0176fbb5b95e4dc57088ff13f4d1bd84c6bfa57dcdc0e0) // vk.work_root\n mstore(add(_vk, 0x60), 0x30644259cd94e7dd5045d7a27013b7fcd21c9e3b7fa75222e7bda49b729b0401) // vk.domain_inverse\n mstore(add(_vk, 0x80), 0x0a5931a9b3c37db04548c933e4a9b0f9487757a9f801aa01e7d275a40d39497c) // vk.Q1.x\n mstore(add(_vk, 0xa0), 0x12cea158643389d8711b24540c1c4e4c8cf13611f3798ba2358e167a912844f3) // vk.Q1.y\n mstore(add(_vk, 0xc0), 0x0ebc1e32f831aba49fe31bc239d5a0561adaf404f155b9d6bb08e4c3815f2f32) // vk.Q2.x\n mstore(add(_vk, 0xe0), 0x2131da70b7e64e99b4f24039af9603654f76a03bbfabb597527349660bc9da08) // vk.Q2.y\n mstore(add(_vk, 0x100), 0x223884f4d210a8b3ad2f585b49c054daa4d33c9e28043f0f78871ca23732234f) // vk.Q3.x\n mstore(add(_vk, 0x120), 0x1061015802740d854aaa354775d778347f1221d8872eef9c89d2a203202bc7da) // vk.Q3.y\n mstore(add(_vk, 0x140), 0x2eabe443fda536437a613f8d783072d53e0046db141b1e33d7c3c121212a3c06) // vk.Q4.x\n mstore(add(_vk, 0x160), 0x2f07e36491c8308b6f245cbf6948ff696be6e17c8631a7a379d53aa833784022) // vk.Q4.y\n mstore(add(_vk, 0x180), 0x08f38e48c240322d5150c343eb6cf0a6a11484702d6db43a9143ff08bf7be7ef) // vk.Q_M.x\n mstore(add(_vk, 0x1a0), 0x28abf6c5b8d14c614e5e4575ee40226d3d6c7f5466abb5c5be2e71a897671bd5) // vk.Q_M.y\n mstore(add(_vk, 0x1c0), 0x03683dca601ea287423f7aa77934c3f112c180c0b9093b87a3dee5eb90c141a8) // vk.Q_C.x\n mstore(add(_vk, 0x1e0), 0x1b4cb37ecbf1e89f8f5cdec73df94eaeb001af346e54edf1bdea1d1ad95327fe) // vk.Q_C.y\n mstore(add(_vk, 0x200), 0x28d2fe928614e9222624eec22092cc08c468da49fdd46600d22ed6070b04689b) // vk.Q_ARITHMETIC.x\n mstore(add(_vk, 0x220), 0x2c1fab639b86dddf22ce0a88e81600183ef90511cb0033928cdb225af699a022) // vk.Q_ARITHMETIC.y\n mstore(add(_vk, 0x240), 0x0a4ef796d6d31a644c8c005f91540bdf015259b0ef571c832f8fe6d970ebeacc) // vk.QSORT.x\n mstore(add(_vk, 0x260), 0x09d812db52384fb2302afca48cc5c4a4e7732fdfb2d617afeb0848e8e1d68918) // vk.QSORT.y\n mstore(add(_vk, 0x280), 0x28002136441f499cb67dbe131036e36477668eb2240b22cf01a0e08c51db6d19) // vk.Q_ELLIPTIC.x\n mstore(add(_vk, 0x2a0), 0x18f6eb64de1535001bb91205993e1ec99f31b5fdbf562048474f850d32127cbf) // vk.Q_ELLIPTIC.y\n mstore(add(_vk, 0x2c0), 0x0d66d7745f53cf8e3cd02024e91de1aa5d365f13e7f2febb4ca1d5dc4a082384) // vk.Q_AUX.x\n mstore(add(_vk, 0x2e0), 0x1ae49dbb3c823d4fc5083077f5ae521b89793192810892a0bba7daf7fd2cf957) // vk.Q_AUX.y\n mstore(add(_vk, 0x300), 0x0f2fbe4580f9491850c96072d8e8adea39f118dd6e52d4f03a2ed1569869bc9d) // vk.SIGMA1.x\n mstore(add(_vk, 0x320), 0x0def278a1c8071b88aef1dc4e901661b00702522ae7474b8211560348726ae4f) // vk.SIGMA1.y\n mstore(add(_vk, 0x340), 0x2e981032d6afd0918d10b2ff080643f3927510ab98ef24234a30a5e9a7001262) // vk.SIGMA2.x\n mstore(add(_vk, 0x360), 0x194a07affc2b36d4507054f4561b804bdf2c56a28b22a030ecd2215ea0fbcf5b) // vk.SIGMA2.y\n mstore(add(_vk, 0x380), 0x1c6e41c7f0d0d6ac3582af9aa5e2487ae103c541496db4eee80f855663bc16e7) // vk.SIGMA3.x\n mstore(add(_vk, 0x3a0), 0x2727b6fec65a3a3f08ddc326b4124bb3821ed4d6ae26ef6e732e258d45373f8a) // vk.SIGMA3.y\n mstore(add(_vk, 0x3c0), 0x13715b20f765d6bf2b2dae455edaf3c866620c31a561a3c45cff21ef3e5889dd) // vk.SIGMA4.x\n mstore(add(_vk, 0x3e0), 0x22266b85afe166c89985108dbc7893ca86be396cfcdb6e264a48d1f24ba8fcbe) // vk.SIGMA4.y\n mstore(add(_vk, 0x400), 0x12037992a0868b71fd31e8afdd2eadb65703eb9b066f46619795addc76c4c040) // vk.TABLE1.x\n mstore(add(_vk, 0x420), 0x03087c87f8e680e93787d0b1ee1e7b03a361953026880f136896be768c398a52) // vk.TABLE1.y\n mstore(add(_vk, 0x440), 0x20333b8a625e44316eb415594db2fb1418360858b9bbd871eb602d1e2d99aec3) // vk.TABLE2.x\n mstore(add(_vk, 0x460), 0x071cff58e911f0bfbb01a49556356929c0d32d3a343fb91c62728b5f40ef9c2e) // vk.TABLE2.y\n mstore(add(_vk, 0x480), 0x05ea76ef86cb4a6516241f0ffd1cb4a3d08911ed1785b2c2e5d21d03160af911) // vk.TABLE3.x\n mstore(add(_vk, 0x4a0), 0x04bf914031bd405440af705425e95109b8ccb07be5f521baf78522a47f808aef) // vk.TABLE3.y\n mstore(add(_vk, 0x4c0), 0x17841405ffd5b7391dfc4c67df8b83b829c04c6c39fa304c63ba85efc356cb6b) // vk.TABLE4.x\n mstore(add(_vk, 0x4e0), 0x071662508f56a08c39f23e3b574939b610830931daaf5f8c7da09d8341423e72) // vk.TABLE4.y\n mstore(add(_vk, 0x500), 0x0787ef43895e3cf0f2e5c42b6f9024004a3338842a5eb1d1fd32b49a99fff17d) // vk.TABLE_TYPE.x\n mstore(add(_vk, 0x520), 0x1192394643e84b8499150f637aeb1ebba43d626d633f7a83ae69515ad95a4b5a) // vk.TABLE_TYPE.y\n mstore(add(_vk, 0x540), 0x2e0d8fde926249765f452043300afdd3bbb0f9e13baccb0a47a68b9eb7d7c79f) // vk.ID1.x\n mstore(add(_vk, 0x560), 0x211c0ba67378e8446ba9a4e5138dc5de4373c7adfd5cc83ac7d433d386a0ecfd) // vk.ID1.y\n mstore(add(_vk, 0x580), 0x143e7be3d5d1580d5110b3a67c380cf9caeb4770427e90b388f2270fb0f83d91) // vk.ID2.x\n mstore(add(_vk, 0x5a0), 0x195e2f7e65ac5a6840e93423f82c16f30c3790de59116b9f9e14f407ad0d4d6a) // vk.ID2.y\n mstore(add(_vk, 0x5c0), 0x2804b12fdbd501ff15264b01e561e3bd270c4b05f7c5c5bcf24ef2fc0071b9ad) // vk.ID3.x\n mstore(add(_vk, 0x5e0), 0x2e1649b3d5a35df625d980c66b04edc019ca28aab93348da450f0dfb5e0e465b) // vk.ID3.y\n mstore(add(_vk, 0x600), 0x1fbbe654114caad3397b07f36243f5e9fbbb9a7faf44b0babfb6f16d325ab965) // vk.ID4.x\n mstore(add(_vk, 0x620), 0x2aef8f62c5552883a6275e470906ca2959d76a59b5db7e223a4663fcdced4a93) // vk.ID4.y\n mstore(add(_vk, 0x640), 0x00) // vk.contains_recursive_proof\n mstore(add(_vk, 0x660), 0) // vk.recursive_proof_public_input_indices\n mstore(add(_vk, 0x680), 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1) // vk.g2_x.X.c1 \n mstore(add(_vk, 0x6a0), 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0) // vk.g2_x.X.c0 \n mstore(add(_vk, 0x6c0), 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4) // vk.g2_x.Y.c1 \n mstore(add(_vk, 0x6e0), 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55) // vk.g2_x.Y.c0 \n mstore(_omegaInverseLoc, 0x036853f083780e87f8d7c71d111119c57dbe118c22d5ad707a82317466c5174c) // vk.work_root_inverse\n }\n }\n}\n\n/**\n * @title Ultra Plonk proof verification contract\n * @dev Top level Plonk proof verification contract, which allows Plonk proof to be verified\n */\nabstract contract BaseUltraVerifier {\n // VERIFICATION KEY MEMORY LOCATIONS\n uint256 internal constant N_LOC = 0x380;\n uint256 internal constant NUM_INPUTS_LOC = 0x3a0;\n uint256 internal constant OMEGA_LOC = 0x3c0;\n uint256 internal constant DOMAIN_INVERSE_LOC = 0x3e0;\n uint256 internal constant Q1_X_LOC = 0x400;\n uint256 internal constant Q1_Y_LOC = 0x420;\n uint256 internal constant Q2_X_LOC = 0x440;\n uint256 internal constant Q2_Y_LOC = 0x460;\n uint256 internal constant Q3_X_LOC = 0x480;\n uint256 internal constant Q3_Y_LOC = 0x4a0;\n uint256 internal constant Q4_X_LOC = 0x4c0;\n uint256 internal constant Q4_Y_LOC = 0x4e0;\n uint256 internal constant QM_X_LOC = 0x500;\n uint256 internal constant QM_Y_LOC = 0x520;\n uint256 internal constant QC_X_LOC = 0x540;\n uint256 internal constant QC_Y_LOC = 0x560;\n uint256 internal constant QARITH_X_LOC = 0x580;\n uint256 internal constant QARITH_Y_LOC = 0x5a0;\n uint256 internal constant QSORT_X_LOC = 0x5c0;\n uint256 internal constant QSORT_Y_LOC = 0x5e0;\n uint256 internal constant QELLIPTIC_X_LOC = 0x600;\n uint256 internal constant QELLIPTIC_Y_LOC = 0x620;\n uint256 internal constant QAUX_X_LOC = 0x640;\n uint256 internal constant QAUX_Y_LOC = 0x660;\n uint256 internal constant SIGMA1_X_LOC = 0x680;\n uint256 internal constant SIGMA1_Y_LOC = 0x6a0;\n uint256 internal constant SIGMA2_X_LOC = 0x6c0;\n uint256 internal constant SIGMA2_Y_LOC = 0x6e0;\n uint256 internal constant SIGMA3_X_LOC = 0x700;\n uint256 internal constant SIGMA3_Y_LOC = 0x720;\n uint256 internal constant SIGMA4_X_LOC = 0x740;\n uint256 internal constant SIGMA4_Y_LOC = 0x760;\n uint256 internal constant TABLE1_X_LOC = 0x780;\n uint256 internal constant TABLE1_Y_LOC = 0x7a0;\n uint256 internal constant TABLE2_X_LOC = 0x7c0;\n uint256 internal constant TABLE2_Y_LOC = 0x7e0;\n uint256 internal constant TABLE3_X_LOC = 0x800;\n uint256 internal constant TABLE3_Y_LOC = 0x820;\n uint256 internal constant TABLE4_X_LOC = 0x840;\n uint256 internal constant TABLE4_Y_LOC = 0x860;\n uint256 internal constant TABLE_TYPE_X_LOC = 0x880;\n uint256 internal constant TABLE_TYPE_Y_LOC = 0x8a0;\n uint256 internal constant ID1_X_LOC = 0x8c0;\n uint256 internal constant ID1_Y_LOC = 0x8e0;\n uint256 internal constant ID2_X_LOC = 0x900;\n uint256 internal constant ID2_Y_LOC = 0x920;\n uint256 internal constant ID3_X_LOC = 0x940;\n uint256 internal constant ID3_Y_LOC = 0x960;\n uint256 internal constant ID4_X_LOC = 0x980;\n uint256 internal constant ID4_Y_LOC = 0x9a0;\n uint256 internal constant CONTAINS_RECURSIVE_PROOF_LOC = 0x9c0;\n uint256 internal constant RECURSIVE_PROOF_PUBLIC_INPUT_INDICES_LOC = 0x9e0;\n uint256 internal constant G2X_X0_LOC = 0xa00;\n uint256 internal constant G2X_X1_LOC = 0xa20;\n uint256 internal constant G2X_Y0_LOC = 0xa40;\n uint256 internal constant G2X_Y1_LOC = 0xa60;\n\n // ### PROOF DATA MEMORY LOCATIONS\n uint256 internal constant W1_X_LOC = 0x1200;\n uint256 internal constant W1_Y_LOC = 0x1220;\n uint256 internal constant W2_X_LOC = 0x1240;\n uint256 internal constant W2_Y_LOC = 0x1260;\n uint256 internal constant W3_X_LOC = 0x1280;\n uint256 internal constant W3_Y_LOC = 0x12a0;\n uint256 internal constant W4_X_LOC = 0x12c0;\n uint256 internal constant W4_Y_LOC = 0x12e0;\n uint256 internal constant S_X_LOC = 0x1300;\n uint256 internal constant S_Y_LOC = 0x1320;\n uint256 internal constant Z_X_LOC = 0x1340;\n uint256 internal constant Z_Y_LOC = 0x1360;\n uint256 internal constant Z_LOOKUP_X_LOC = 0x1380;\n uint256 internal constant Z_LOOKUP_Y_LOC = 0x13a0;\n uint256 internal constant T1_X_LOC = 0x13c0;\n uint256 internal constant T1_Y_LOC = 0x13e0;\n uint256 internal constant T2_X_LOC = 0x1400;\n uint256 internal constant T2_Y_LOC = 0x1420;\n uint256 internal constant T3_X_LOC = 0x1440;\n uint256 internal constant T3_Y_LOC = 0x1460;\n uint256 internal constant T4_X_LOC = 0x1480;\n uint256 internal constant T4_Y_LOC = 0x14a0;\n\n uint256 internal constant W1_EVAL_LOC = 0x1600;\n uint256 internal constant W2_EVAL_LOC = 0x1620;\n uint256 internal constant W3_EVAL_LOC = 0x1640;\n uint256 internal constant W4_EVAL_LOC = 0x1660;\n uint256 internal constant S_EVAL_LOC = 0x1680;\n uint256 internal constant Z_EVAL_LOC = 0x16a0;\n uint256 internal constant Z_LOOKUP_EVAL_LOC = 0x16c0;\n uint256 internal constant Q1_EVAL_LOC = 0x16e0;\n uint256 internal constant Q2_EVAL_LOC = 0x1700;\n uint256 internal constant Q3_EVAL_LOC = 0x1720;\n uint256 internal constant Q4_EVAL_LOC = 0x1740;\n uint256 internal constant QM_EVAL_LOC = 0x1760;\n uint256 internal constant QC_EVAL_LOC = 0x1780;\n uint256 internal constant QARITH_EVAL_LOC = 0x17a0;\n uint256 internal constant QSORT_EVAL_LOC = 0x17c0;\n uint256 internal constant QELLIPTIC_EVAL_LOC = 0x17e0;\n uint256 internal constant QAUX_EVAL_LOC = 0x1800;\n uint256 internal constant TABLE1_EVAL_LOC = 0x1840;\n uint256 internal constant TABLE2_EVAL_LOC = 0x1860;\n uint256 internal constant TABLE3_EVAL_LOC = 0x1880;\n uint256 internal constant TABLE4_EVAL_LOC = 0x18a0;\n uint256 internal constant TABLE_TYPE_EVAL_LOC = 0x18c0;\n uint256 internal constant ID1_EVAL_LOC = 0x18e0;\n uint256 internal constant ID2_EVAL_LOC = 0x1900;\n uint256 internal constant ID3_EVAL_LOC = 0x1920;\n uint256 internal constant ID4_EVAL_LOC = 0x1940;\n uint256 internal constant SIGMA1_EVAL_LOC = 0x1960;\n uint256 internal constant SIGMA2_EVAL_LOC = 0x1980;\n uint256 internal constant SIGMA3_EVAL_LOC = 0x19a0;\n uint256 internal constant SIGMA4_EVAL_LOC = 0x19c0;\n uint256 internal constant W1_OMEGA_EVAL_LOC = 0x19e0;\n uint256 internal constant W2_OMEGA_EVAL_LOC = 0x2000;\n uint256 internal constant W3_OMEGA_EVAL_LOC = 0x2020;\n uint256 internal constant W4_OMEGA_EVAL_LOC = 0x2040;\n uint256 internal constant S_OMEGA_EVAL_LOC = 0x2060;\n uint256 internal constant Z_OMEGA_EVAL_LOC = 0x2080;\n uint256 internal constant Z_LOOKUP_OMEGA_EVAL_LOC = 0x20a0;\n uint256 internal constant TABLE1_OMEGA_EVAL_LOC = 0x20c0;\n uint256 internal constant TABLE2_OMEGA_EVAL_LOC = 0x20e0;\n uint256 internal constant TABLE3_OMEGA_EVAL_LOC = 0x2100;\n uint256 internal constant TABLE4_OMEGA_EVAL_LOC = 0x2120;\n\n uint256 internal constant PI_Z_X_LOC = 0x2300;\n uint256 internal constant PI_Z_Y_LOC = 0x2320;\n uint256 internal constant PI_Z_OMEGA_X_LOC = 0x2340;\n uint256 internal constant PI_Z_OMEGA_Y_LOC = 0x2360;\n\n // Used for elliptic widget. These are alias names for wire + shifted wire evaluations\n uint256 internal constant X1_EVAL_LOC = W2_EVAL_LOC;\n uint256 internal constant X2_EVAL_LOC = W1_OMEGA_EVAL_LOC;\n uint256 internal constant X3_EVAL_LOC = W2_OMEGA_EVAL_LOC;\n uint256 internal constant Y1_EVAL_LOC = W3_EVAL_LOC;\n uint256 internal constant Y2_EVAL_LOC = W4_OMEGA_EVAL_LOC;\n uint256 internal constant Y3_EVAL_LOC = W3_OMEGA_EVAL_LOC;\n uint256 internal constant QBETA_LOC = Q3_EVAL_LOC;\n uint256 internal constant QBETA_SQR_LOC = Q4_EVAL_LOC;\n uint256 internal constant QSIGN_LOC = Q1_EVAL_LOC;\n\n // ### CHALLENGES MEMORY OFFSETS\n\n uint256 internal constant C_BETA_LOC = 0x2600;\n uint256 internal constant C_GAMMA_LOC = 0x2620;\n uint256 internal constant C_ALPHA_LOC = 0x2640;\n uint256 internal constant C_ETA_LOC = 0x2660;\n uint256 internal constant C_ETA_SQR_LOC = 0x2680;\n uint256 internal constant C_ETA_CUBE_LOC = 0x26a0;\n\n uint256 internal constant C_ZETA_LOC = 0x26c0;\n uint256 internal constant C_CURRENT_LOC = 0x26e0;\n uint256 internal constant C_V0_LOC = 0x2700;\n uint256 internal constant C_V1_LOC = 0x2720;\n uint256 internal constant C_V2_LOC = 0x2740;\n uint256 internal constant C_V3_LOC = 0x2760;\n uint256 internal constant C_V4_LOC = 0x2780;\n uint256 internal constant C_V5_LOC = 0x27a0;\n uint256 internal constant C_V6_LOC = 0x27c0;\n uint256 internal constant C_V7_LOC = 0x27e0;\n uint256 internal constant C_V8_LOC = 0x2800;\n uint256 internal constant C_V9_LOC = 0x2820;\n uint256 internal constant C_V10_LOC = 0x2840;\n uint256 internal constant C_V11_LOC = 0x2860;\n uint256 internal constant C_V12_LOC = 0x2880;\n uint256 internal constant C_V13_LOC = 0x28a0;\n uint256 internal constant C_V14_LOC = 0x28c0;\n uint256 internal constant C_V15_LOC = 0x28e0;\n uint256 internal constant C_V16_LOC = 0x2900;\n uint256 internal constant C_V17_LOC = 0x2920;\n uint256 internal constant C_V18_LOC = 0x2940;\n uint256 internal constant C_V19_LOC = 0x2960;\n uint256 internal constant C_V20_LOC = 0x2980;\n uint256 internal constant C_V21_LOC = 0x29a0;\n uint256 internal constant C_V22_LOC = 0x29c0;\n uint256 internal constant C_V23_LOC = 0x29e0;\n uint256 internal constant C_V24_LOC = 0x2a00;\n uint256 internal constant C_V25_LOC = 0x2a20;\n uint256 internal constant C_V26_LOC = 0x2a40;\n uint256 internal constant C_V27_LOC = 0x2a60;\n uint256 internal constant C_V28_LOC = 0x2a80;\n uint256 internal constant C_V29_LOC = 0x2aa0;\n uint256 internal constant C_V30_LOC = 0x2ac0;\n\n uint256 internal constant C_U_LOC = 0x2b00;\n\n // ### LOCAL VARIABLES MEMORY OFFSETS\n uint256 internal constant DELTA_NUMERATOR_LOC = 0x3000;\n uint256 internal constant DELTA_DENOMINATOR_LOC = 0x3020;\n uint256 internal constant ZETA_POW_N_LOC = 0x3040;\n uint256 internal constant PUBLIC_INPUT_DELTA_LOC = 0x3060;\n uint256 internal constant ZERO_POLY_LOC = 0x3080;\n uint256 internal constant L_START_LOC = 0x30a0;\n uint256 internal constant L_END_LOC = 0x30c0;\n uint256 internal constant R_ZERO_EVAL_LOC = 0x30e0;\n\n uint256 internal constant PLOOKUP_DELTA_NUMERATOR_LOC = 0x3100;\n uint256 internal constant PLOOKUP_DELTA_DENOMINATOR_LOC = 0x3120;\n uint256 internal constant PLOOKUP_DELTA_LOC = 0x3140;\n\n uint256 internal constant ACCUMULATOR_X_LOC = 0x3160;\n uint256 internal constant ACCUMULATOR_Y_LOC = 0x3180;\n uint256 internal constant ACCUMULATOR2_X_LOC = 0x31a0;\n uint256 internal constant ACCUMULATOR2_Y_LOC = 0x31c0;\n uint256 internal constant PAIRING_LHS_X_LOC = 0x31e0;\n uint256 internal constant PAIRING_LHS_Y_LOC = 0x3200;\n uint256 internal constant PAIRING_RHS_X_LOC = 0x3220;\n uint256 internal constant PAIRING_RHS_Y_LOC = 0x3240;\n\n // misc stuff\n uint256 internal constant OMEGA_INVERSE_LOC = 0x3300;\n uint256 internal constant C_ALPHA_SQR_LOC = 0x3320;\n uint256 internal constant C_ALPHA_CUBE_LOC = 0x3340;\n uint256 internal constant C_ALPHA_QUAD_LOC = 0x3360;\n uint256 internal constant C_ALPHA_BASE_LOC = 0x3380;\n\n // ### RECURSION VARIABLE MEMORY LOCATIONS\n uint256 internal constant RECURSIVE_P1_X_LOC = 0x3400;\n uint256 internal constant RECURSIVE_P1_Y_LOC = 0x3420;\n uint256 internal constant RECURSIVE_P2_X_LOC = 0x3440;\n uint256 internal constant RECURSIVE_P2_Y_LOC = 0x3460;\n uint256 internal constant PUBLIC_INPUTS_HASH_LOCATION = 0x3480;\n\n // sub-identity storage\n uint256 internal constant PERMUTATION_IDENTITY = 0x3500;\n uint256 internal constant PLOOKUP_IDENTITY = 0x3520;\n uint256 internal constant ARITHMETIC_IDENTITY = 0x3540;\n uint256 internal constant SORT_IDENTITY = 0x3560;\n uint256 internal constant ELLIPTIC_IDENTITY = 0x3580;\n uint256 internal constant AUX_IDENTITY = 0x35a0;\n uint256 internal constant AUX_NON_NATIVE_FIELD_EVALUATION = 0x35c0;\n uint256 internal constant AUX_LIMB_ACCUMULATOR_EVALUATION = 0x35e0;\n uint256 internal constant AUX_RAM_CONSISTENCY_EVALUATION = 0x3600;\n uint256 internal constant AUX_ROM_CONSISTENCY_EVALUATION = 0x3620;\n uint256 internal constant AUX_MEMORY_EVALUATION = 0x3640;\n\n uint256 internal constant QUOTIENT_EVAL_LOC = 0x3660;\n uint256 internal constant ZERO_POLY_INVERSE_LOC = 0x3680;\n\n // when hashing public inputs we use memory at NU_CHALLENGE_INPUT_LOC_A, as the hash input size is unknown at compile time\n uint256 internal constant NU_CHALLENGE_INPUT_LOC_A = 0x36a0;\n uint256 internal constant NU_CHALLENGE_INPUT_LOC_B = 0x36c0;\n uint256 internal constant NU_CHALLENGE_INPUT_LOC_C = 0x36e0;\n\n bytes4 internal constant INVALID_VERIFICATION_KEY_SELECTOR = 0x7e5769bf;\n bytes4 internal constant POINT_NOT_ON_CURVE_SELECTOR = 0xa3dad654;\n bytes4 internal constant PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR = 0xeba9f4a6;\n bytes4 internal constant PUBLIC_INPUT_GE_P_SELECTOR = 0x374a972f;\n bytes4 internal constant MOD_EXP_FAILURE_SELECTOR = 0xf894a7bc;\n bytes4 internal constant PAIRING_PREAMBLE_FAILED_SELECTOR = 0x01882d81;\n bytes4 internal constant OPENING_COMMITMENT_FAILED_SELECTOR = 0x4e719763;\n bytes4 internal constant PAIRING_FAILED_SELECTOR = 0xd71fd263;\n\n uint256 internal constant ETA_INPUT_LENGTH = 0xc0; // W1, W2, W3 = 6 * 0x20 bytes\n\n // We need to hash 41 field elements when generating the NU challenge\n // w1, w2, w3, w4, s, z, z_lookup, q1, q2, q3, q4, qm, qc, qarith (14)\n // qsort, qelliptic, qaux, sigma1, sigma2, sigma, sigma4, (7)\n // table1, table2, table3, table4, tabletype, id1, id2, id3, id4, (9)\n // w1_omega, w2_omega, w3_omega, w4_omega, s_omega, z_omega, z_lookup_omega, (7)\n // table1_omega, table2_omega, table3_omega, table4_omega (4)\n uint256 internal constant NU_INPUT_LENGTH = 0x520; // 0x520 = 41 * 0x20\n\n // There are ELEVEN G1 group elements added into the transcript in the `beta` round, that we need to skip over\n // W1, W2, W3, W4, S, Z, Z_LOOKUP, T1, T2, T3, T4\n uint256 internal constant NU_CALLDATA_SKIP_LENGTH = 0x2c0; // 11 * 0x40 = 0x2c0\n\n uint256 internal constant NEGATIVE_INVERSE_OF_2_MODULO_P =\n 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000;\n uint256 internal constant LIMB_SIZE = 0x100000000000000000; // 2<<68\n uint256 internal constant SUBLIMB_SHIFT = 0x4000; // 2<<14\n\n // y^2 = x^3 + ax + b\n // for Grumpkin, a = 0 and b = -17. We use b in a custom gate relation that evaluates elliptic curve arithmetic\n uint256 internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = 17;\n\n error INVALID_VERIFICATION_KEY();\n error POINT_NOT_ON_CURVE();\n error PUBLIC_INPUT_COUNT_INVALID(uint256 expected, uint256 actual);\n error PUBLIC_INPUT_INVALID_BN128_G1_POINT();\n error PUBLIC_INPUT_GE_P();\n error MOD_EXP_FAILURE();\n error PAIRING_PREAMBLE_FAILED();\n error OPENING_COMMITMENT_FAILED();\n error PAIRING_FAILED();\n\n function getVerificationKeyHash() public pure virtual returns (bytes32);\n\n /**\n * @dev We assume that the verification key loaded by this function is constant as we only verify it on deployment\n */\n function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure virtual;\n\n constructor() { \n loadVerificationKey(N_LOC, OMEGA_INVERSE_LOC);\n\n // We verify that all of the EC points in the verification key lie on the bn128 curve. \n assembly {\n let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // EC group order\n\n let success := 1\n\n // VALIDATE Q1\n {\n let x := mload(Q1_X_LOC)\n let y := mload(Q1_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE Q2\n {\n let x := mload(Q2_X_LOC)\n let y := mload(Q2_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE Q3\n {\n let x := mload(Q3_X_LOC)\n let y := mload(Q3_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE Q4\n {\n let x := mload(Q4_X_LOC)\n let y := mload(Q4_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n mstore(0x00, x)\n mstore(0x20, y)\n }\n // VALIDATE QM\n {\n let x := mload(QM_X_LOC)\n let y := mload(QM_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE QC\n {\n let x := mload(QC_X_LOC)\n let y := mload(QC_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE QARITH\n {\n let x := mload(QARITH_X_LOC)\n let y := mload(QARITH_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE QSORT\n {\n let x := mload(QSORT_X_LOC)\n let y := mload(QSORT_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE QELLIPTIC\n {\n let x := mload(QELLIPTIC_X_LOC)\n let y := mload(QELLIPTIC_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE QAUX\n {\n let x := mload(QAUX_X_LOC)\n let y := mload(QAUX_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE SIGMA1\n {\n let x := mload(SIGMA1_X_LOC)\n let y := mload(SIGMA1_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE SIGMA2\n {\n let x := mload(SIGMA2_X_LOC)\n let y := mload(SIGMA2_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE SIGMA3\n {\n let x := mload(SIGMA3_X_LOC)\n let y := mload(SIGMA3_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE SIGMA4\n {\n let x := mload(SIGMA4_X_LOC)\n let y := mload(SIGMA4_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE TABLE1\n {\n let x := mload(TABLE1_X_LOC)\n let y := mload(TABLE1_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n } \n // VALIDATE TABLE2\n {\n let x := mload(TABLE2_X_LOC)\n let y := mload(TABLE2_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n } \n // VALIDATE TABLE3\n {\n let x := mload(TABLE3_X_LOC)\n let y := mload(TABLE3_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n } \n // VALIDATE TABLE4\n {\n let x := mload(TABLE4_X_LOC)\n let y := mload(TABLE4_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n } \n // VALIDATE TABLE_TYPE\n {\n let x := mload(TABLE_TYPE_X_LOC)\n let y := mload(TABLE_TYPE_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE ID1\n {\n let x := mload(ID1_X_LOC)\n let y := mload(ID1_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE ID2\n {\n let x := mload(ID2_X_LOC)\n let y := mload(ID2_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE ID3\n {\n let x := mload(ID3_X_LOC)\n let y := mload(ID3_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE ID4\n {\n let x := mload(ID4_X_LOC)\n let y := mload(ID4_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n\n if iszero(success) {\n mstore(0x0, INVALID_VERIFICATION_KEY_SELECTOR)\n revert(0x00, 0x04)\n }\n }\n }\n\n /**\n * @notice Verify a Ultra Plonk proof\n * @param _proof - The serialized proof\n * @param _publicInputs - An array of the public inputs\n * @return True if proof is valid, reverts otherwise\n */\n function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) {\n loadVerificationKey(N_LOC, OMEGA_INVERSE_LOC);\n\n uint256 requiredPublicInputCount;\n assembly {\n requiredPublicInputCount := mload(NUM_INPUTS_LOC)\n }\n if (requiredPublicInputCount != _publicInputs.length) {\n revert PUBLIC_INPUT_COUNT_INVALID(requiredPublicInputCount, _publicInputs.length);\n }\n\n assembly {\n let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // EC group order\n let p := 21888242871839275222246405745257275088548364400416034343698204186575808495617 // Prime field order\n\n /**\n * LOAD PROOF FROM CALLDATA\n */\n {\n let data_ptr := add(calldataload(0x04), 0x24)\n\n mstore(W1_Y_LOC, mod(calldataload(data_ptr), q))\n mstore(W1_X_LOC, mod(calldataload(add(data_ptr, 0x20)), q))\n\n mstore(W2_Y_LOC, mod(calldataload(add(data_ptr, 0x40)), q))\n mstore(W2_X_LOC, mod(calldataload(add(data_ptr, 0x60)), q))\n\n mstore(W3_Y_LOC, mod(calldataload(add(data_ptr, 0x80)), q))\n mstore(W3_X_LOC, mod(calldataload(add(data_ptr, 0xa0)), q))\n\n mstore(W4_Y_LOC, mod(calldataload(add(data_ptr, 0xc0)), q))\n mstore(W4_X_LOC, mod(calldataload(add(data_ptr, 0xe0)), q))\n\n mstore(S_Y_LOC, mod(calldataload(add(data_ptr, 0x100)), q))\n mstore(S_X_LOC, mod(calldataload(add(data_ptr, 0x120)), q))\n mstore(Z_Y_LOC, mod(calldataload(add(data_ptr, 0x140)), q))\n mstore(Z_X_LOC, mod(calldataload(add(data_ptr, 0x160)), q))\n mstore(Z_LOOKUP_Y_LOC, mod(calldataload(add(data_ptr, 0x180)), q))\n mstore(Z_LOOKUP_X_LOC, mod(calldataload(add(data_ptr, 0x1a0)), q))\n mstore(T1_Y_LOC, mod(calldataload(add(data_ptr, 0x1c0)), q))\n mstore(T1_X_LOC, mod(calldataload(add(data_ptr, 0x1e0)), q))\n\n mstore(T2_Y_LOC, mod(calldataload(add(data_ptr, 0x200)), q))\n mstore(T2_X_LOC, mod(calldataload(add(data_ptr, 0x220)), q))\n\n mstore(T3_Y_LOC, mod(calldataload(add(data_ptr, 0x240)), q))\n mstore(T3_X_LOC, mod(calldataload(add(data_ptr, 0x260)), q))\n\n mstore(T4_Y_LOC, mod(calldataload(add(data_ptr, 0x280)), q))\n mstore(T4_X_LOC, mod(calldataload(add(data_ptr, 0x2a0)), q))\n\n mstore(W1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x2c0)), p))\n mstore(W2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x2e0)), p))\n mstore(W3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x300)), p))\n mstore(W4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x320)), p))\n mstore(S_EVAL_LOC, mod(calldataload(add(data_ptr, 0x340)), p))\n mstore(Z_EVAL_LOC, mod(calldataload(add(data_ptr, 0x360)), p))\n mstore(Z_LOOKUP_EVAL_LOC, mod(calldataload(add(data_ptr, 0x380)), p))\n mstore(Q1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3a0)), p))\n mstore(Q2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3c0)), p))\n mstore(Q3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3e0)), p))\n mstore(Q4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x400)), p))\n mstore(QM_EVAL_LOC, mod(calldataload(add(data_ptr, 0x420)), p))\n mstore(QC_EVAL_LOC, mod(calldataload(add(data_ptr, 0x440)), p))\n mstore(QARITH_EVAL_LOC, mod(calldataload(add(data_ptr, 0x460)), p))\n mstore(QSORT_EVAL_LOC, mod(calldataload(add(data_ptr, 0x480)), p))\n mstore(QELLIPTIC_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4a0)), p))\n mstore(QAUX_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4c0)), p))\n\n mstore(SIGMA1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4e0)), p))\n mstore(SIGMA2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x500)), p))\n\n mstore(SIGMA3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x520)), p))\n mstore(SIGMA4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x540)), p))\n\n mstore(TABLE1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x560)), p))\n mstore(TABLE2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x580)), p))\n mstore(TABLE3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5a0)), p))\n mstore(TABLE4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5c0)), p))\n mstore(TABLE_TYPE_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5e0)), p))\n\n mstore(ID1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x600)), p))\n mstore(ID2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x620)), p))\n mstore(ID3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x640)), p))\n mstore(ID4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x660)), p))\n\n mstore(W1_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x680)), p))\n mstore(W2_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6a0)), p))\n mstore(W3_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6c0)), p))\n mstore(W4_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6e0)), p))\n mstore(S_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x700)), p))\n\n mstore(Z_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x720)), p))\n\n mstore(Z_LOOKUP_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x740)), p))\n mstore(TABLE1_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x760)), p))\n mstore(TABLE2_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x780)), p))\n mstore(TABLE3_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x7a0)), p))\n mstore(TABLE4_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x7c0)), p))\n\n mstore(PI_Z_Y_LOC, mod(calldataload(add(data_ptr, 0x7e0)), q))\n mstore(PI_Z_X_LOC, mod(calldataload(add(data_ptr, 0x800)), q))\n\n mstore(PI_Z_OMEGA_Y_LOC, mod(calldataload(add(data_ptr, 0x820)), q))\n mstore(PI_Z_OMEGA_X_LOC, mod(calldataload(add(data_ptr, 0x840)), q))\n }\n\n /**\n * LOAD RECURSIVE PROOF INTO MEMORY\n */\n {\n if mload(CONTAINS_RECURSIVE_PROOF_LOC) {\n let public_inputs_ptr := add(calldataload(0x24), 0x24)\n let index_counter := add(shl(5, mload(RECURSIVE_PROOF_PUBLIC_INPUT_INDICES_LOC)), public_inputs_ptr)\n\n let x0 := calldataload(index_counter)\n x0 := add(x0, shl(68, calldataload(add(index_counter, 0x20))))\n x0 := add(x0, shl(136, calldataload(add(index_counter, 0x40))))\n x0 := add(x0, shl(204, calldataload(add(index_counter, 0x60))))\n let y0 := calldataload(add(index_counter, 0x80))\n y0 := add(y0, shl(68, calldataload(add(index_counter, 0xa0))))\n y0 := add(y0, shl(136, calldataload(add(index_counter, 0xc0))))\n y0 := add(y0, shl(204, calldataload(add(index_counter, 0xe0))))\n let x1 := calldataload(add(index_counter, 0x100))\n x1 := add(x1, shl(68, calldataload(add(index_counter, 0x120))))\n x1 := add(x1, shl(136, calldataload(add(index_counter, 0x140))))\n x1 := add(x1, shl(204, calldataload(add(index_counter, 0x160))))\n let y1 := calldataload(add(index_counter, 0x180))\n y1 := add(y1, shl(68, calldataload(add(index_counter, 0x1a0))))\n y1 := add(y1, shl(136, calldataload(add(index_counter, 0x1c0))))\n y1 := add(y1, shl(204, calldataload(add(index_counter, 0x1e0))))\n mstore(RECURSIVE_P1_X_LOC, x0)\n mstore(RECURSIVE_P1_Y_LOC, y0)\n mstore(RECURSIVE_P2_X_LOC, x1)\n mstore(RECURSIVE_P2_Y_LOC, y1)\n\n // validate these are valid bn128 G1 points\n if iszero(and(and(lt(x0, q), lt(x1, q)), and(lt(y0, q), lt(y1, q)))) {\n mstore(0x00, PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR)\n revert(0x00, 0x04)\n }\n }\n }\n\n {\n /**\n * Generate initial challenge\n */\n mstore(0x00, shl(224, mload(N_LOC)))\n mstore(0x04, shl(224, mload(NUM_INPUTS_LOC)))\n let challenge := keccak256(0x00, 0x08)\n\n /**\n * Generate eta challenge\n */\n mstore(PUBLIC_INPUTS_HASH_LOCATION, challenge)\n // The public input location is stored at 0x24, we then add 0x24 to skip selector and the length of public inputs\n let public_inputs_start := add(calldataload(0x24), 0x24)\n // copy the public inputs over\n let public_input_size := mul(mload(NUM_INPUTS_LOC), 0x20)\n calldatacopy(add(PUBLIC_INPUTS_HASH_LOCATION, 0x20), public_inputs_start, public_input_size)\n\n // copy W1, W2, W3 into challenge. Each point is 0x40 bytes, so load 0xc0 = 3 * 0x40 bytes (ETA input length)\n let w_start := add(calldataload(0x04), 0x24)\n calldatacopy(add(add(PUBLIC_INPUTS_HASH_LOCATION, 0x20), public_input_size), w_start, ETA_INPUT_LENGTH)\n\n // Challenge is the old challenge + public inputs + W1, W2, W3 (0x20 + public_input_size + 0xc0)\n let challenge_bytes_size := add(0x20, add(public_input_size, ETA_INPUT_LENGTH))\n\n challenge := keccak256(PUBLIC_INPUTS_HASH_LOCATION, challenge_bytes_size)\n {\n let eta := mod(challenge, p)\n mstore(C_ETA_LOC, eta)\n mstore(C_ETA_SQR_LOC, mulmod(eta, eta, p))\n mstore(C_ETA_CUBE_LOC, mulmod(mload(C_ETA_SQR_LOC), eta, p))\n }\n\n /**\n * Generate beta challenge\n */\n mstore(0x00, challenge)\n mstore(0x20, mload(W4_Y_LOC))\n mstore(0x40, mload(W4_X_LOC))\n mstore(0x60, mload(S_Y_LOC))\n mstore(0x80, mload(S_X_LOC))\n challenge := keccak256(0x00, 0xa0)\n mstore(C_BETA_LOC, mod(challenge, p))\n\n /**\n * Generate gamma challenge\n */\n mstore(0x00, challenge)\n mstore8(0x20, 0x01)\n challenge := keccak256(0x00, 0x21)\n mstore(C_GAMMA_LOC, mod(challenge, p))\n\n /**\n * Generate alpha challenge\n */\n mstore(0x00, challenge)\n mstore(0x20, mload(Z_Y_LOC))\n mstore(0x40, mload(Z_X_LOC))\n mstore(0x60, mload(Z_LOOKUP_Y_LOC))\n mstore(0x80, mload(Z_LOOKUP_X_LOC))\n challenge := keccak256(0x00, 0xa0)\n mstore(C_ALPHA_LOC, mod(challenge, p))\n\n /**\n * Compute and store some powers of alpha for future computations\n */\n let alpha := mload(C_ALPHA_LOC)\n mstore(C_ALPHA_SQR_LOC, mulmod(alpha, alpha, p))\n mstore(C_ALPHA_CUBE_LOC, mulmod(mload(C_ALPHA_SQR_LOC), alpha, p))\n mstore(C_ALPHA_QUAD_LOC, mulmod(mload(C_ALPHA_CUBE_LOC), alpha, p))\n mstore(C_ALPHA_BASE_LOC, alpha)\n\n /**\n * Generate zeta challenge\n */\n mstore(0x00, challenge)\n mstore(0x20, mload(T1_Y_LOC))\n mstore(0x40, mload(T1_X_LOC))\n mstore(0x60, mload(T2_Y_LOC))\n mstore(0x80, mload(T2_X_LOC))\n mstore(0xa0, mload(T3_Y_LOC))\n mstore(0xc0, mload(T3_X_LOC))\n mstore(0xe0, mload(T4_Y_LOC))\n mstore(0x100, mload(T4_X_LOC))\n\n challenge := keccak256(0x00, 0x120)\n\n mstore(C_ZETA_LOC, mod(challenge, p))\n mstore(C_CURRENT_LOC, challenge)\n }\n\n /**\n * EVALUATE FIELD OPERATIONS\n */\n\n /**\n * COMPUTE PUBLIC INPUT DELTA\n * ΔPI = ∏ᵢ∈ℓ(wᵢ + β σ(i) + γ) / ∏ᵢ∈ℓ(wᵢ + β σ'(i) + γ)\n */\n {\n let beta := mload(C_BETA_LOC) // β\n let gamma := mload(C_GAMMA_LOC) // γ\n let work_root := mload(OMEGA_LOC) // ω\n let numerator_value := 1\n let denominator_value := 1\n\n let p_clone := p // move p to the front of the stack\n let valid_inputs := true\n\n // Load the starting point of the public inputs (jump over the selector and the length of public inputs [0x24])\n let public_inputs_ptr := add(calldataload(0x24), 0x24)\n\n // endpoint_ptr = public_inputs_ptr + num_inputs * 0x20. // every public input is 0x20 bytes\n let endpoint_ptr := add(public_inputs_ptr, mul(mload(NUM_INPUTS_LOC), 0x20))\n\n // root_1 = β * 0x05\n let root_1 := mulmod(beta, 0x05, p_clone) // k1.β\n // root_2 = β * 0x0c\n let root_2 := mulmod(beta, 0x0c, p_clone)\n // @note 0x05 + 0x07 == 0x0c == external coset generator\n\n for {} lt(public_inputs_ptr, endpoint_ptr) { public_inputs_ptr := add(public_inputs_ptr, 0x20) } {\n /**\n * input = public_input[i]\n * valid_inputs &= input < p\n * temp = input + gamma\n * numerator_value *= (β.σ(i) + wᵢ + γ) // σ(i) = 0x05.ωⁱ\n * denominator_value *= (β.σ'(i) + wᵢ + γ) // σ'(i) = 0x0c.ωⁱ\n * root_1 *= ω\n * root_2 *= ω\n */\n\n let input := calldataload(public_inputs_ptr)\n valid_inputs := and(valid_inputs, lt(input, p_clone))\n let temp := addmod(input, gamma, p_clone)\n\n numerator_value := mulmod(numerator_value, add(root_1, temp), p_clone)\n denominator_value := mulmod(denominator_value, add(root_2, temp), p_clone)\n\n root_1 := mulmod(root_1, work_root, p_clone)\n root_2 := mulmod(root_2, work_root, p_clone)\n }\n\n // Revert if not all public inputs are field elements (i.e. < p)\n if iszero(valid_inputs) {\n mstore(0x00, PUBLIC_INPUT_GE_P_SELECTOR)\n revert(0x00, 0x04)\n }\n\n mstore(DELTA_NUMERATOR_LOC, numerator_value)\n mstore(DELTA_DENOMINATOR_LOC, denominator_value)\n }\n\n /**\n * Compute Plookup delta factor [γ(1 + β)]^{n-k}\n * k = num roots cut out of Z_H = 4\n */\n {\n let delta_base := mulmod(mload(C_GAMMA_LOC), addmod(mload(C_BETA_LOC), 1, p), p)\n let delta_numerator := delta_base\n {\n let exponent := mload(N_LOC)\n let count := 1\n for {} lt(count, exponent) { count := add(count, count) } {\n delta_numerator := mulmod(delta_numerator, delta_numerator, p)\n }\n }\n mstore(PLOOKUP_DELTA_NUMERATOR_LOC, delta_numerator)\n\n let delta_denominator := mulmod(delta_base, delta_base, p)\n delta_denominator := mulmod(delta_denominator, delta_denominator, p)\n mstore(PLOOKUP_DELTA_DENOMINATOR_LOC, delta_denominator)\n }\n /**\n * Compute lagrange poly and vanishing poly fractions\n */\n {\n /**\n * vanishing_numerator = zeta\n * ZETA_POW_N = zeta^n\n * vanishing_numerator -= 1\n * accumulating_root = omega_inverse\n * work_root = p - accumulating_root\n * domain_inverse = domain_inverse\n * vanishing_denominator = zeta + work_root\n * work_root *= accumulating_root\n * vanishing_denominator *= (zeta + work_root)\n * work_root *= accumulating_root\n * vanishing_denominator *= (zeta + work_root)\n * vanishing_denominator *= (zeta + (zeta + accumulating_root))\n * work_root = omega\n * lagrange_numerator = vanishing_numerator * domain_inverse\n * l_start_denominator = zeta - 1\n * accumulating_root = work_root^2\n * l_end_denominator = accumulating_root^2 * work_root * zeta - 1\n * Note: l_end_denominator term contains a term \\omega^5 to cut out 5 roots of unity from vanishing poly\n */\n\n let zeta := mload(C_ZETA_LOC)\n\n // compute zeta^n, where n is a power of 2\n let vanishing_numerator := zeta\n {\n // pow_small\n let exponent := mload(N_LOC)\n let count := 1\n for {} lt(count, exponent) { count := add(count, count) } {\n vanishing_numerator := mulmod(vanishing_numerator, vanishing_numerator, p)\n }\n }\n mstore(ZETA_POW_N_LOC, vanishing_numerator)\n vanishing_numerator := addmod(vanishing_numerator, sub(p, 1), p)\n\n let accumulating_root := mload(OMEGA_INVERSE_LOC)\n let work_root := sub(p, accumulating_root)\n let domain_inverse := mload(DOMAIN_INVERSE_LOC)\n\n let vanishing_denominator := addmod(zeta, work_root, p)\n work_root := mulmod(work_root, accumulating_root, p)\n vanishing_denominator := mulmod(vanishing_denominator, addmod(zeta, work_root, p), p)\n work_root := mulmod(work_root, accumulating_root, p)\n vanishing_denominator := mulmod(vanishing_denominator, addmod(zeta, work_root, p), p)\n vanishing_denominator :=\n mulmod(vanishing_denominator, addmod(zeta, mulmod(work_root, accumulating_root, p), p), p)\n\n work_root := mload(OMEGA_LOC)\n\n let lagrange_numerator := mulmod(vanishing_numerator, domain_inverse, p)\n let l_start_denominator := addmod(zeta, sub(p, 1), p)\n\n accumulating_root := mulmod(work_root, work_root, p)\n\n let l_end_denominator :=\n addmod(\n mulmod(mulmod(mulmod(accumulating_root, accumulating_root, p), work_root, p), zeta, p), sub(p, 1), p\n )\n\n /**\n * Compute inversions using Montgomery's batch inversion trick\n */\n let accumulator := mload(DELTA_DENOMINATOR_LOC)\n let t0 := accumulator\n accumulator := mulmod(accumulator, vanishing_denominator, p)\n let t1 := accumulator\n accumulator := mulmod(accumulator, vanishing_numerator, p)\n let t2 := accumulator\n accumulator := mulmod(accumulator, l_start_denominator, p)\n let t3 := accumulator\n accumulator := mulmod(accumulator, mload(PLOOKUP_DELTA_DENOMINATOR_LOC), p)\n let t4 := accumulator\n {\n mstore(0, 0x20)\n mstore(0x20, 0x20)\n mstore(0x40, 0x20)\n mstore(0x60, mulmod(accumulator, l_end_denominator, p))\n mstore(0x80, sub(p, 2))\n mstore(0xa0, p)\n if iszero(staticcall(gas(), 0x05, 0x00, 0xc0, 0x00, 0x20)) {\n mstore(0x0, MOD_EXP_FAILURE_SELECTOR)\n revert(0x00, 0x04)\n }\n accumulator := mload(0x00)\n }\n\n t4 := mulmod(accumulator, t4, p)\n accumulator := mulmod(accumulator, l_end_denominator, p)\n\n t3 := mulmod(accumulator, t3, p)\n accumulator := mulmod(accumulator, mload(PLOOKUP_DELTA_DENOMINATOR_LOC), p)\n\n t2 := mulmod(accumulator, t2, p)\n accumulator := mulmod(accumulator, l_start_denominator, p)\n\n t1 := mulmod(accumulator, t1, p)\n accumulator := mulmod(accumulator, vanishing_numerator, p)\n\n t0 := mulmod(accumulator, t0, p)\n accumulator := mulmod(accumulator, vanishing_denominator, p)\n\n accumulator := mulmod(mulmod(accumulator, accumulator, p), mload(DELTA_DENOMINATOR_LOC), p)\n\n mstore(PUBLIC_INPUT_DELTA_LOC, mulmod(mload(DELTA_NUMERATOR_LOC), accumulator, p))\n mstore(ZERO_POLY_LOC, mulmod(vanishing_numerator, t0, p))\n mstore(ZERO_POLY_INVERSE_LOC, mulmod(vanishing_denominator, t1, p))\n mstore(L_START_LOC, mulmod(lagrange_numerator, t2, p))\n mstore(PLOOKUP_DELTA_LOC, mulmod(mload(PLOOKUP_DELTA_NUMERATOR_LOC), t3, p))\n mstore(L_END_LOC, mulmod(lagrange_numerator, t4, p))\n }\n\n /**\n * UltraPlonk Widget Ordering:\n *\n * 1. Permutation widget\n * 2. Plookup widget\n * 3. Arithmetic widget\n * 4. Fixed base widget (?)\n * 5. GenPermSort widget\n * 6. Elliptic widget\n * 7. Auxiliary widget\n */\n\n /**\n * COMPUTE PERMUTATION WIDGET EVALUATION\n */\n {\n let alpha := mload(C_ALPHA_LOC)\n let beta := mload(C_BETA_LOC)\n let gamma := mload(C_GAMMA_LOC)\n\n /**\n * t1 = (W1 + gamma + beta * ID1) * (W2 + gamma + beta * ID2)\n * t2 = (W3 + gamma + beta * ID3) * (W4 + gamma + beta * ID4)\n * result = alpha_base * z_eval * t1 * t2\n * t1 = (W1 + gamma + beta * sigma_1_eval) * (W2 + gamma + beta * sigma_2_eval)\n * t2 = (W2 + gamma + beta * sigma_3_eval) * (W3 + gamma + beta * sigma_4_eval)\n * result -= (alpha_base * z_omega_eval * t1 * t2)\n */\n let t1 :=\n mulmod(\n add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(ID1_EVAL_LOC), p)),\n add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(ID2_EVAL_LOC), p)),\n p\n )\n let t2 :=\n mulmod(\n add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(ID3_EVAL_LOC), p)),\n add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(ID4_EVAL_LOC), p)),\n p\n )\n let result := mulmod(mload(C_ALPHA_BASE_LOC), mulmod(mload(Z_EVAL_LOC), mulmod(t1, t2, p), p), p)\n t1 :=\n mulmod(\n add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA1_EVAL_LOC), p)),\n add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA2_EVAL_LOC), p)),\n p\n )\n t2 :=\n mulmod(\n add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA3_EVAL_LOC), p)),\n add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA4_EVAL_LOC), p)),\n p\n )\n result :=\n addmod(\n result,\n sub(p, mulmod(mload(C_ALPHA_BASE_LOC), mulmod(mload(Z_OMEGA_EVAL_LOC), mulmod(t1, t2, p), p), p)),\n p\n )\n\n /**\n * alpha_base *= alpha\n * result += alpha_base . (L_{n-k}(ʓ) . (z(ʓ.ω) - ∆_{PI}))\n * alpha_base *= alpha\n * result += alpha_base . (L_1(ʓ)(Z(ʓ) - 1))\n * alpha_Base *= alpha\n */\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p))\n result :=\n addmod(\n result,\n mulmod(\n mload(C_ALPHA_BASE_LOC),\n mulmod(\n mload(L_END_LOC),\n addmod(mload(Z_OMEGA_EVAL_LOC), sub(p, mload(PUBLIC_INPUT_DELTA_LOC)), p),\n p\n ),\n p\n ),\n p\n )\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p))\n mstore(\n PERMUTATION_IDENTITY,\n addmod(\n result,\n mulmod(\n mload(C_ALPHA_BASE_LOC),\n mulmod(mload(L_START_LOC), addmod(mload(Z_EVAL_LOC), sub(p, 1), p), p),\n p\n ),\n p\n )\n )\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p))\n }\n\n /**\n * COMPUTE PLOOKUP WIDGET EVALUATION\n */\n {\n /**\n * Goal: f = (w1(z) + q2.w1(zω)) + η(w2(z) + qm.w2(zω)) + η²(w3(z) + qc.w_3(zω)) + q3(z).η³\n * f = η.q3(z)\n * f += (w3(z) + qc.w_3(zω))\n * f *= η\n * f += (w2(z) + qm.w2(zω))\n * f *= η\n * f += (w1(z) + q2.w1(zω))\n */\n let f := mulmod(mload(C_ETA_LOC), mload(Q3_EVAL_LOC), p)\n f :=\n addmod(f, addmod(mload(W3_EVAL_LOC), mulmod(mload(QC_EVAL_LOC), mload(W3_OMEGA_EVAL_LOC), p), p), p)\n f := mulmod(f, mload(C_ETA_LOC), p)\n f :=\n addmod(f, addmod(mload(W2_EVAL_LOC), mulmod(mload(QM_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), p), p)\n f := mulmod(f, mload(C_ETA_LOC), p)\n f :=\n addmod(f, addmod(mload(W1_EVAL_LOC), mulmod(mload(Q2_EVAL_LOC), mload(W1_OMEGA_EVAL_LOC), p), p), p)\n\n // t(z) = table4(z).η³ + table3(z).η² + table2(z).η + table1(z)\n let t :=\n addmod(\n addmod(\n addmod(\n mulmod(mload(TABLE4_EVAL_LOC), mload(C_ETA_CUBE_LOC), p),\n mulmod(mload(TABLE3_EVAL_LOC), mload(C_ETA_SQR_LOC), p),\n p\n ),\n mulmod(mload(TABLE2_EVAL_LOC), mload(C_ETA_LOC), p),\n p\n ),\n mload(TABLE1_EVAL_LOC),\n p\n )\n\n // t(zw) = table4(zw).η³ + table3(zw).η² + table2(zw).η + table1(zw)\n let t_omega :=\n addmod(\n addmod(\n addmod(\n mulmod(mload(TABLE4_OMEGA_EVAL_LOC), mload(C_ETA_CUBE_LOC), p),\n mulmod(mload(TABLE3_OMEGA_EVAL_LOC), mload(C_ETA_SQR_LOC), p),\n p\n ),\n mulmod(mload(TABLE2_OMEGA_EVAL_LOC), mload(C_ETA_LOC), p),\n p\n ),\n mload(TABLE1_OMEGA_EVAL_LOC),\n p\n )\n\n /**\n * Goal: numerator = (TABLE_TYPE_EVAL * f(z) + γ) * (t(z) + βt(zω) + γ(β + 1)) * (β + 1)\n * gamma_beta_constant = γ(β + 1)\n * numerator = f * TABLE_TYPE_EVAL + gamma\n * temp0 = t(z) + t(zω) * β + gamma_beta_constant\n * numerator *= temp0\n * numerator *= (β + 1)\n * temp0 = alpha * l_1\n * numerator += temp0\n * numerator *= z_lookup(z)\n * numerator -= temp0\n */\n let gamma_beta_constant := mulmod(mload(C_GAMMA_LOC), addmod(mload(C_BETA_LOC), 1, p), p)\n let numerator := addmod(mulmod(f, mload(TABLE_TYPE_EVAL_LOC), p), mload(C_GAMMA_LOC), p)\n let temp0 := addmod(addmod(t, mulmod(t_omega, mload(C_BETA_LOC), p), p), gamma_beta_constant, p)\n numerator := mulmod(numerator, temp0, p)\n numerator := mulmod(numerator, addmod(mload(C_BETA_LOC), 1, p), p)\n temp0 := mulmod(mload(C_ALPHA_LOC), mload(L_START_LOC), p)\n numerator := addmod(numerator, temp0, p)\n numerator := mulmod(numerator, mload(Z_LOOKUP_EVAL_LOC), p)\n numerator := addmod(numerator, sub(p, temp0), p)\n\n /**\n * Goal: denominator = z_lookup(zω)*[s(z) + βs(zω) + γ(1 + β)] - [z_lookup(zω) - [γ(1 + β)]^{n-k}]*α²L_end(z)\n * note: delta_factor = [γ(1 + β)]^{n-k}\n * denominator = s(z) + βs(zω) + γ(β + 1)\n * temp1 = α²L_end(z)\n * denominator -= temp1\n * denominator *= z_lookup(zω)\n * denominator += temp1 * delta_factor\n * PLOOKUP_IDENTITY = (numerator - denominator).alpha_base\n * alpha_base *= alpha^3\n */\n let denominator :=\n addmod(\n addmod(mload(S_EVAL_LOC), mulmod(mload(S_OMEGA_EVAL_LOC), mload(C_BETA_LOC), p), p),\n gamma_beta_constant,\n p\n )\n let temp1 := mulmod(mload(C_ALPHA_SQR_LOC), mload(L_END_LOC), p)\n denominator := addmod(denominator, sub(p, temp1), p)\n denominator := mulmod(denominator, mload(Z_LOOKUP_OMEGA_EVAL_LOC), p)\n denominator := addmod(denominator, mulmod(temp1, mload(PLOOKUP_DELTA_LOC), p), p)\n\n mstore(PLOOKUP_IDENTITY, mulmod(addmod(numerator, sub(p, denominator), p), mload(C_ALPHA_BASE_LOC), p))\n\n // update alpha\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p))\n }\n\n /**\n * COMPUTE ARITHMETIC WIDGET EVALUATION\n */\n {\n /**\n * The basic arithmetic gate identity in standard plonk is as follows.\n * (w_1 . w_2 . q_m) + (w_1 . q_1) + (w_2 . q_2) + (w_3 . q_3) + (w_4 . q_4) + q_c = 0\n * However, for Ultraplonk, we extend this to support \"passing\" wires between rows (shown without alpha scaling below):\n * q_arith * ( ( (-1/2) * (q_arith - 3) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c ) +\n * (q_arith - 1)*( α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m) + w_4_omega) ) = 0\n *\n * This formula results in several cases depending on q_arith:\n * 1. q_arith == 0: Arithmetic gate is completely disabled\n *\n * 2. q_arith == 1: Everything in the minigate on the right is disabled. The equation is just a standard plonk equation\n * with extra wires: q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c = 0\n *\n * 3. q_arith == 2: The (w_1 + w_4 - ...) term is disabled. THe equation is:\n * (1/2) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + w_4_omega = 0\n * It allows defining w_4 at next index (w_4_omega) in terms of current wire values\n *\n * 4. q_arith == 3: The product of w_1 and w_2 is disabled, but a mini addition gate is enabled. α allows us to split\n * the equation into two:\n *\n * q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + 2 * w_4_omega = 0\n * and\n * w_1 + w_4 - w_1_omega + q_m = 0 (we are reusing q_m here)\n *\n * 5. q_arith > 3: The product of w_1 and w_2 is scaled by (q_arith - 3), while the w_4_omega term is scaled by (q_arith - 1).\n * The equation can be split into two:\n *\n * (q_arith - 3)* q_m * w_1 * w_ 2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + (q_arith - 1) * w_4_omega = 0\n * and\n * w_1 + w_4 - w_1_omega + q_m = 0\n *\n * The problem that q_m is used both in both equations can be dealt with by appropriately changing selector values at\n * the next gate. Then we can treat (q_arith - 1) as a simulated q_6 selector and scale q_m to handle (q_arith - 3) at\n * product.\n */\n\n let w1q1 := mulmod(mload(W1_EVAL_LOC), mload(Q1_EVAL_LOC), p)\n let w2q2 := mulmod(mload(W2_EVAL_LOC), mload(Q2_EVAL_LOC), p)\n let w3q3 := mulmod(mload(W3_EVAL_LOC), mload(Q3_EVAL_LOC), p)\n let w4q3 := mulmod(mload(W4_EVAL_LOC), mload(Q4_EVAL_LOC), p)\n\n // @todo - Add a explicit test that hits QARITH == 3\n // w1w2qm := (w_1 . w_2 . q_m . (QARITH_EVAL_LOC - 3)) / 2\n let w1w2qm :=\n mulmod(\n mulmod(\n mulmod(mulmod(mload(W1_EVAL_LOC), mload(W2_EVAL_LOC), p), mload(QM_EVAL_LOC), p),\n addmod(mload(QARITH_EVAL_LOC), sub(p, 3), p),\n p\n ),\n NEGATIVE_INVERSE_OF_2_MODULO_P,\n p\n )\n\n // (w_1 . w_2 . q_m . (q_arith - 3)) / -2) + (w_1 . q_1) + (w_2 . q_2) + (w_3 . q_3) + (w_4 . q_4) + q_c\n let identity :=\n addmod(\n mload(QC_EVAL_LOC), addmod(w4q3, addmod(w3q3, addmod(w2q2, addmod(w1q1, w1w2qm, p), p), p), p), p\n )\n\n // if q_arith == 3 we evaluate an additional mini addition gate (on top of the regular one), where:\n // w_1 + w_4 - w_1_omega + q_m = 0\n // we use this gate to save an addition gate when adding or subtracting non-native field elements\n // α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m)\n let extra_small_addition_gate_identity :=\n mulmod(\n mload(C_ALPHA_LOC),\n mulmod(\n addmod(mload(QARITH_EVAL_LOC), sub(p, 2), p),\n addmod(\n mload(QM_EVAL_LOC),\n addmod(\n sub(p, mload(W1_OMEGA_EVAL_LOC)), addmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p), p\n ),\n p\n ),\n p\n ),\n p\n )\n\n // if q_arith == 2 OR q_arith == 3 we add the 4th wire of the NEXT gate into the arithmetic identity\n // N.B. if q_arith > 2, this wire value will be scaled by (q_arith - 1) relative to the other gate wires!\n // alpha_base * q_arith * (identity + (q_arith - 1) * (w_4_omega + extra_small_addition_gate_identity))\n mstore(\n ARITHMETIC_IDENTITY,\n mulmod(\n mload(C_ALPHA_BASE_LOC),\n mulmod(\n mload(QARITH_EVAL_LOC),\n addmod(\n identity,\n mulmod(\n addmod(mload(QARITH_EVAL_LOC), sub(p, 1), p),\n addmod(mload(W4_OMEGA_EVAL_LOC), extra_small_addition_gate_identity, p),\n p\n ),\n p\n ),\n p\n ),\n p\n )\n )\n\n // update alpha\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_SQR_LOC), p))\n }\n\n /**\n * COMPUTE GENPERMSORT WIDGET EVALUATION\n */\n {\n /**\n * D1 = (w2 - w1)\n * D2 = (w3 - w2)\n * D3 = (w4 - w3)\n * D4 = (w1_omega - w4)\n *\n * α_a = alpha_base\n * α_b = alpha_base * α\n * α_c = alpha_base * α^2\n * α_d = alpha_base * α^3\n *\n * range_accumulator = (\n * D1(D1 - 1)(D1 - 2)(D1 - 3).α_a +\n * D2(D2 - 1)(D2 - 2)(D2 - 3).α_b +\n * D3(D3 - 1)(D3 - 2)(D3 - 3).α_c +\n * D4(D4 - 1)(D4 - 2)(D4 - 3).α_d +\n * ) . q_sort\n */\n let minus_two := sub(p, 2)\n let minus_three := sub(p, 3)\n let d1 := addmod(mload(W2_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p)\n let d2 := addmod(mload(W3_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p)\n let d3 := addmod(mload(W4_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p)\n let d4 := addmod(mload(W1_OMEGA_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p)\n\n let range_accumulator :=\n mulmod(\n mulmod(\n mulmod(addmod(mulmod(d1, d1, p), sub(p, d1), p), addmod(d1, minus_two, p), p),\n addmod(d1, minus_three, p),\n p\n ),\n mload(C_ALPHA_BASE_LOC),\n p\n )\n range_accumulator :=\n addmod(\n range_accumulator,\n mulmod(\n mulmod(\n mulmod(addmod(mulmod(d2, d2, p), sub(p, d2), p), addmod(d2, minus_two, p), p),\n addmod(d2, minus_three, p),\n p\n ),\n mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p),\n p\n ),\n p\n )\n range_accumulator :=\n addmod(\n range_accumulator,\n mulmod(\n mulmod(\n mulmod(addmod(mulmod(d3, d3, p), sub(p, d3), p), addmod(d3, minus_two, p), p),\n addmod(d3, minus_three, p),\n p\n ),\n mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_SQR_LOC), p),\n p\n ),\n p\n )\n range_accumulator :=\n addmod(\n range_accumulator,\n mulmod(\n mulmod(\n mulmod(addmod(mulmod(d4, d4, p), sub(p, d4), p), addmod(d4, minus_two, p), p),\n addmod(d4, minus_three, p),\n p\n ),\n mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p),\n p\n ),\n p\n )\n range_accumulator := mulmod(range_accumulator, mload(QSORT_EVAL_LOC), p)\n\n mstore(SORT_IDENTITY, range_accumulator)\n\n // update alpha\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_QUAD_LOC), p))\n }\n\n /**\n * COMPUTE ELLIPTIC WIDGET EVALUATION\n */\n {\n /**\n * endo_term = (-x_2) * x_1 * (x_3 * 2 + x_1) * q_beta\n * endo_sqr_term = x_2^2\n * endo_sqr_term *= (x_3 - x_1)\n * endo_sqr_term *= q_beta^2\n * leftovers = x_2^2\n * leftovers *= x_2\n * leftovers += x_1^2 * (x_3 + x_1) @follow-up Invalid comment in BB widget\n * leftovers -= (y_2^2 + y_1^2)\n * sign_term = y_2 * y_1\n * sign_term += sign_term\n * sign_term *= q_sign\n */\n // q_elliptic * (x3 + x2 + x1)(x2 - x1)(x2 - x1) - y2^2 - y1^2 + 2(y2y1)*q_sign = 0\n let x_diff := addmod(mload(X2_EVAL_LOC), sub(p, mload(X1_EVAL_LOC)), p)\n let y2_sqr := mulmod(mload(Y2_EVAL_LOC), mload(Y2_EVAL_LOC), p)\n let y1_sqr := mulmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p)\n let y1y2 := mulmod(mulmod(mload(Y1_EVAL_LOC), mload(Y2_EVAL_LOC), p), mload(QSIGN_LOC), p)\n\n let x_add_identity :=\n addmod(\n mulmod(\n addmod(mload(X3_EVAL_LOC), addmod(mload(X2_EVAL_LOC), mload(X1_EVAL_LOC), p), p),\n mulmod(x_diff, x_diff, p),\n p\n ),\n addmod(\n sub(\n p,\n addmod(y2_sqr, y1_sqr, p)\n ),\n addmod(y1y2, y1y2, p),\n p\n ),\n p\n )\n x_add_identity :=\n mulmod(\n mulmod(\n x_add_identity,\n addmod(\n 1,\n sub(p, mload(QM_EVAL_LOC)),\n p\n ),\n p\n ),\n mload(C_ALPHA_BASE_LOC),\n p\n )\n\n // q_elliptic * (x3 + x2 + x1)(x2 - x1)(x2 - x1) - y2^2 - y1^2 + 2(y2y1)*q_sign = 0\n let y1_plus_y3 := addmod(\n mload(Y1_EVAL_LOC),\n mload(Y3_EVAL_LOC),\n p\n )\n let y_diff := addmod(mulmod(mload(Y2_EVAL_LOC), mload(QSIGN_LOC), p), sub(p, mload(Y1_EVAL_LOC)), p)\n let y_add_identity :=\n addmod(\n mulmod(y1_plus_y3, x_diff, p),\n mulmod(addmod(mload(X3_EVAL_LOC), sub(p, mload(X1_EVAL_LOC)), p), y_diff, p),\n p\n )\n y_add_identity :=\n mulmod(\n mulmod(y_add_identity, addmod(1, sub(p, mload(QM_EVAL_LOC)), p), p),\n mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p),\n p\n )\n\n // ELLIPTIC_IDENTITY = (x_identity + y_identity) * Q_ELLIPTIC_EVAL\n mstore(\n ELLIPTIC_IDENTITY, mulmod(addmod(x_add_identity, y_add_identity, p), mload(QELLIPTIC_EVAL_LOC), p)\n )\n }\n {\n /**\n * x_pow_4 = (y_1_sqr - curve_b) * x_1;\n * y_1_sqr_mul_4 = y_1_sqr + y_1_sqr;\n * y_1_sqr_mul_4 += y_1_sqr_mul_4;\n * x_1_pow_4_mul_9 = x_pow_4;\n * x_1_pow_4_mul_9 += x_1_pow_4_mul_9;\n * x_1_pow_4_mul_9 += x_1_pow_4_mul_9;\n * x_1_pow_4_mul_9 += x_1_pow_4_mul_9;\n * x_1_pow_4_mul_9 += x_pow_4;\n * x_1_sqr_mul_3 = x_1_sqr + x_1_sqr + x_1_sqr;\n * x_double_identity = (x_3 + x_1 + x_1) * y_1_sqr_mul_4 - x_1_pow_4_mul_9;\n * y_double_identity = x_1_sqr_mul_3 * (x_1 - x_3) - (y_1 + y_1) * (y_1 + y_3);\n */\n // (x3 + x1 + x1) (4y1*y1) - 9 * x1 * x1 * x1 * x1 = 0\n let x1_sqr := mulmod(mload(X1_EVAL_LOC), mload(X1_EVAL_LOC), p)\n let y1_sqr := mulmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p)\n let x_pow_4 := mulmod(addmod(y1_sqr, GRUMPKIN_CURVE_B_PARAMETER_NEGATED, p), mload(X1_EVAL_LOC), p)\n let y1_sqr_mul_4 := mulmod(y1_sqr, 4, p)\n let x1_pow_4_mul_9 := mulmod(x_pow_4, 9, p)\n let x1_sqr_mul_3 := mulmod(x1_sqr, 3, p)\n let x_double_identity :=\n addmod(\n mulmod(\n addmod(mload(X3_EVAL_LOC), addmod(mload(X1_EVAL_LOC), mload(X1_EVAL_LOC), p), p),\n y1_sqr_mul_4,\n p\n ),\n sub(p, x1_pow_4_mul_9),\n p\n )\n // (y1 + y1) (2y1) - (3 * x1 * x1)(x1 - x3) = 0\n let y_double_identity :=\n addmod(\n mulmod(x1_sqr_mul_3, addmod(mload(X1_EVAL_LOC), sub(p, mload(X3_EVAL_LOC)), p), p),\n sub(\n p,\n mulmod(\n addmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p),\n addmod(mload(Y1_EVAL_LOC), mload(Y3_EVAL_LOC), p),\n p\n )\n ),\n p\n )\n x_double_identity := mulmod(x_double_identity, mload(C_ALPHA_BASE_LOC), p)\n y_double_identity :=\n mulmod(y_double_identity, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p), p)\n x_double_identity := mulmod(x_double_identity, mload(QM_EVAL_LOC), p)\n y_double_identity := mulmod(y_double_identity, mload(QM_EVAL_LOC), p)\n // ELLIPTIC_IDENTITY += (x_double_identity + y_double_identity) * Q_DOUBLE_EVAL\n mstore(\n ELLIPTIC_IDENTITY,\n addmod(\n mload(ELLIPTIC_IDENTITY),\n mulmod(addmod(x_double_identity, y_double_identity, p), mload(QELLIPTIC_EVAL_LOC), p),\n p\n )\n )\n\n // update alpha\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_QUAD_LOC), p))\n }\n\n /**\n * COMPUTE AUXILIARY WIDGET EVALUATION\n */\n {\n {\n /**\n * Non native field arithmetic gate 2\n * _ _\n * / _ _ _ 14 \\\n * q_2 . q_4 | (w_1 . w_2) + (w_1 . w_2) + (w_1 . w_4 + w_2 . w_3 - w_3) . 2 - w_3 - w_4 |\n * \\_ _/\n *\n * limb_subproduct = w_1 . w_2_omega + w_1_omega . w_2\n * non_native_field_gate_2 = w_1 * w_4 + w_4 * w_3 - w_3_omega\n * non_native_field_gate_2 = non_native_field_gate_2 * limb_size\n * non_native_field_gate_2 -= w_4_omega\n * non_native_field_gate_2 += limb_subproduct\n * non_native_field_gate_2 *= q_4\n * limb_subproduct *= limb_size\n * limb_subproduct += w_1_omega * w_2_omega\n * non_native_field_gate_1 = (limb_subproduct + w_3 + w_4) * q_3\n * non_native_field_gate_3 = (limb_subproduct + w_4 - (w_3_omega + w_4_omega)) * q_m\n * non_native_field_identity = (non_native_field_gate_1 + non_native_field_gate_2 + non_native_field_gate_3) * q_2\n */\n\n let limb_subproduct :=\n addmod(\n mulmod(mload(W1_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p),\n mulmod(mload(W1_OMEGA_EVAL_LOC), mload(W2_EVAL_LOC), p),\n p\n )\n\n let non_native_field_gate_2 :=\n addmod(\n addmod(\n mulmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p),\n mulmod(mload(W2_EVAL_LOC), mload(W3_EVAL_LOC), p),\n p\n ),\n sub(p, mload(W3_OMEGA_EVAL_LOC)),\n p\n )\n non_native_field_gate_2 := mulmod(non_native_field_gate_2, LIMB_SIZE, p)\n non_native_field_gate_2 := addmod(non_native_field_gate_2, sub(p, mload(W4_OMEGA_EVAL_LOC)), p)\n non_native_field_gate_2 := addmod(non_native_field_gate_2, limb_subproduct, p)\n non_native_field_gate_2 := mulmod(non_native_field_gate_2, mload(Q4_EVAL_LOC), p)\n limb_subproduct := mulmod(limb_subproduct, LIMB_SIZE, p)\n limb_subproduct :=\n addmod(limb_subproduct, mulmod(mload(W1_OMEGA_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), p)\n let non_native_field_gate_1 :=\n mulmod(\n addmod(limb_subproduct, sub(p, addmod(mload(W3_EVAL_LOC), mload(W4_EVAL_LOC), p)), p),\n mload(Q3_EVAL_LOC),\n p\n )\n let non_native_field_gate_3 :=\n mulmod(\n addmod(\n addmod(limb_subproduct, mload(W4_EVAL_LOC), p),\n sub(p, addmod(mload(W3_OMEGA_EVAL_LOC), mload(W4_OMEGA_EVAL_LOC), p)),\n p\n ),\n mload(QM_EVAL_LOC),\n p\n )\n let non_native_field_identity :=\n mulmod(\n addmod(addmod(non_native_field_gate_1, non_native_field_gate_2, p), non_native_field_gate_3, p),\n mload(Q2_EVAL_LOC),\n p\n )\n\n mstore(AUX_NON_NATIVE_FIELD_EVALUATION, non_native_field_identity)\n }\n\n {\n /**\n * limb_accumulator_1 = w_2_omega;\n * limb_accumulator_1 *= SUBLIMB_SHIFT;\n * limb_accumulator_1 += w_1_omega;\n * limb_accumulator_1 *= SUBLIMB_SHIFT;\n * limb_accumulator_1 += w_3;\n * limb_accumulator_1 *= SUBLIMB_SHIFT;\n * limb_accumulator_1 += w_2;\n * limb_accumulator_1 *= SUBLIMB_SHIFT;\n * limb_accumulator_1 += w_1;\n * limb_accumulator_1 -= w_4;\n * limb_accumulator_1 *= q_4;\n */\n let limb_accumulator_1 := mulmod(mload(W2_OMEGA_EVAL_LOC), SUBLIMB_SHIFT, p)\n limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_OMEGA_EVAL_LOC), p)\n limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)\n limb_accumulator_1 := addmod(limb_accumulator_1, mload(W3_EVAL_LOC), p)\n limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)\n limb_accumulator_1 := addmod(limb_accumulator_1, mload(W2_EVAL_LOC), p)\n limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)\n limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_EVAL_LOC), p)\n limb_accumulator_1 := addmod(limb_accumulator_1, sub(p, mload(W4_EVAL_LOC)), p)\n limb_accumulator_1 := mulmod(limb_accumulator_1, mload(Q4_EVAL_LOC), p)\n\n /**\n * limb_accumulator_2 = w_3_omega;\n * limb_accumulator_2 *= SUBLIMB_SHIFT;\n * limb_accumulator_2 += w_2_omega;\n * limb_accumulator_2 *= SUBLIMB_SHIFT;\n * limb_accumulator_2 += w_1_omega;\n * limb_accumulator_2 *= SUBLIMB_SHIFT;\n * limb_accumulator_2 += w_4;\n * limb_accumulator_2 *= SUBLIMB_SHIFT;\n * limb_accumulator_2 += w_3;\n * limb_accumulator_2 -= w_4_omega;\n * limb_accumulator_2 *= q_m;\n */\n let limb_accumulator_2 := mulmod(mload(W3_OMEGA_EVAL_LOC), SUBLIMB_SHIFT, p)\n limb_accumulator_2 := addmod(limb_accumulator_2, mload(W2_OMEGA_EVAL_LOC), p)\n limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)\n limb_accumulator_2 := addmod(limb_accumulator_2, mload(W1_OMEGA_EVAL_LOC), p)\n limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)\n limb_accumulator_2 := addmod(limb_accumulator_2, mload(W4_EVAL_LOC), p)\n limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)\n limb_accumulator_2 := addmod(limb_accumulator_2, mload(W3_EVAL_LOC), p)\n limb_accumulator_2 := addmod(limb_accumulator_2, sub(p, mload(W4_OMEGA_EVAL_LOC)), p)\n limb_accumulator_2 := mulmod(limb_accumulator_2, mload(QM_EVAL_LOC), p)\n\n mstore(\n AUX_LIMB_ACCUMULATOR_EVALUATION,\n mulmod(addmod(limb_accumulator_1, limb_accumulator_2, p), mload(Q3_EVAL_LOC), p)\n )\n }\n\n {\n /**\n * memory_record_check = w_3;\n * memory_record_check *= eta;\n * memory_record_check += w_2;\n * memory_record_check *= eta;\n * memory_record_check += w_1;\n * memory_record_check *= eta;\n * memory_record_check += q_c;\n *\n * partial_record_check = memory_record_check;\n *\n * memory_record_check -= w_4;\n */\n\n let memory_record_check := mulmod(mload(W3_EVAL_LOC), mload(C_ETA_LOC), p)\n memory_record_check := addmod(memory_record_check, mload(W2_EVAL_LOC), p)\n memory_record_check := mulmod(memory_record_check, mload(C_ETA_LOC), p)\n memory_record_check := addmod(memory_record_check, mload(W1_EVAL_LOC), p)\n memory_record_check := mulmod(memory_record_check, mload(C_ETA_LOC), p)\n memory_record_check := addmod(memory_record_check, mload(QC_EVAL_LOC), p)\n\n let partial_record_check := memory_record_check\n memory_record_check := addmod(memory_record_check, sub(p, mload(W4_EVAL_LOC)), p)\n\n mstore(AUX_MEMORY_EVALUATION, memory_record_check)\n\n // index_delta = w_1_omega - w_1\n let index_delta := addmod(mload(W1_OMEGA_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p)\n // record_delta = w_4_omega - w_4\n let record_delta := addmod(mload(W4_OMEGA_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p)\n // index_is_monotonically_increasing = index_delta * (index_delta - 1)\n let index_is_monotonically_increasing := mulmod(index_delta, addmod(index_delta, sub(p, 1), p), p)\n\n // adjacent_values_match_if_adjacent_indices_match = record_delta * (1 - index_delta)\n let adjacent_values_match_if_adjacent_indices_match :=\n mulmod(record_delta, addmod(1, sub(p, index_delta), p), p)\n\n // AUX_ROM_CONSISTENCY_EVALUATION = ((adjacent_values_match_if_adjacent_indices_match * alpha) + index_is_monotonically_increasing) * alpha + partial_record_check\n mstore(\n AUX_ROM_CONSISTENCY_EVALUATION,\n addmod(\n mulmod(\n addmod(\n mulmod(adjacent_values_match_if_adjacent_indices_match, mload(C_ALPHA_LOC), p),\n index_is_monotonically_increasing,\n p\n ),\n mload(C_ALPHA_LOC),\n p\n ),\n memory_record_check,\n p\n )\n )\n\n {\n /**\n * next_gate_access_type = w_3_omega;\n * next_gate_access_type *= eta;\n * next_gate_access_type += w_2_omega;\n * next_gate_access_type *= eta;\n * next_gate_access_type += w_1_omega;\n * next_gate_access_type *= eta;\n * next_gate_access_type = w_4_omega - next_gate_access_type;\n */\n let next_gate_access_type := mulmod(mload(W3_OMEGA_EVAL_LOC), mload(C_ETA_LOC), p)\n next_gate_access_type := addmod(next_gate_access_type, mload(W2_OMEGA_EVAL_LOC), p)\n next_gate_access_type := mulmod(next_gate_access_type, mload(C_ETA_LOC), p)\n next_gate_access_type := addmod(next_gate_access_type, mload(W1_OMEGA_EVAL_LOC), p)\n next_gate_access_type := mulmod(next_gate_access_type, mload(C_ETA_LOC), p)\n next_gate_access_type := addmod(mload(W4_OMEGA_EVAL_LOC), sub(p, next_gate_access_type), p)\n\n // value_delta = w_3_omega - w_3\n let value_delta := addmod(mload(W3_OMEGA_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p)\n // adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = (1 - index_delta) * value_delta * (1 - next_gate_access_type);\n\n let adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation :=\n mulmod(\n addmod(1, sub(p, index_delta), p),\n mulmod(value_delta, addmod(1, sub(p, next_gate_access_type), p), p),\n p\n )\n\n // AUX_RAM_CONSISTENCY_EVALUATION\n\n /**\n * access_type = w_4 - partial_record_check\n * access_check = access_type^2 - access_type\n * next_gate_access_type_is_boolean = next_gate_access_type^2 - next_gate_access_type\n * RAM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation;\n * RAM_consistency_check_identity *= alpha;\n * RAM_consistency_check_identity += index_is_monotonically_increasing;\n * RAM_consistency_check_identity *= alpha;\n * RAM_consistency_check_identity += next_gate_access_type_is_boolean;\n * RAM_consistency_check_identity *= alpha;\n * RAM_consistency_check_identity += access_check;\n */\n\n let access_type := addmod(mload(W4_EVAL_LOC), sub(p, partial_record_check), p)\n let access_check := mulmod(access_type, addmod(access_type, sub(p, 1), p), p)\n let next_gate_access_type_is_boolean :=\n mulmod(next_gate_access_type, addmod(next_gate_access_type, sub(p, 1), p), p)\n let RAM_cci :=\n mulmod(\n adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation,\n mload(C_ALPHA_LOC),\n p\n )\n RAM_cci := addmod(RAM_cci, index_is_monotonically_increasing, p)\n RAM_cci := mulmod(RAM_cci, mload(C_ALPHA_LOC), p)\n RAM_cci := addmod(RAM_cci, next_gate_access_type_is_boolean, p)\n RAM_cci := mulmod(RAM_cci, mload(C_ALPHA_LOC), p)\n RAM_cci := addmod(RAM_cci, access_check, p)\n\n mstore(AUX_RAM_CONSISTENCY_EVALUATION, RAM_cci)\n }\n\n {\n // timestamp_delta = w_2_omega - w_2\n let timestamp_delta := addmod(mload(W2_OMEGA_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p)\n\n // RAM_timestamp_check_identity = (1 - index_delta) * timestamp_delta - w_3\n let RAM_timestamp_check_identity :=\n addmod(\n mulmod(timestamp_delta, addmod(1, sub(p, index_delta), p), p), sub(p, mload(W3_EVAL_LOC)), p\n )\n\n /**\n * memory_identity = ROM_consistency_check_identity * q_2;\n * memory_identity += RAM_timestamp_check_identity * q_4;\n * memory_identity += memory_record_check * q_m;\n * memory_identity *= q_1;\n * memory_identity += (RAM_consistency_check_identity * q_arith);\n *\n * auxiliary_identity = memory_identity + non_native_field_identity + limb_accumulator_identity;\n * auxiliary_identity *= q_aux;\n * auxiliary_identity *= alpha_base;\n */\n let memory_identity := mulmod(mload(AUX_ROM_CONSISTENCY_EVALUATION), mload(Q2_EVAL_LOC), p)\n memory_identity :=\n addmod(memory_identity, mulmod(RAM_timestamp_check_identity, mload(Q4_EVAL_LOC), p), p)\n memory_identity :=\n addmod(memory_identity, mulmod(mload(AUX_MEMORY_EVALUATION), mload(QM_EVAL_LOC), p), p)\n memory_identity := mulmod(memory_identity, mload(Q1_EVAL_LOC), p)\n memory_identity :=\n addmod(\n memory_identity, mulmod(mload(AUX_RAM_CONSISTENCY_EVALUATION), mload(QARITH_EVAL_LOC), p), p\n )\n\n let auxiliary_identity := addmod(memory_identity, mload(AUX_NON_NATIVE_FIELD_EVALUATION), p)\n auxiliary_identity := addmod(auxiliary_identity, mload(AUX_LIMB_ACCUMULATOR_EVALUATION), p)\n auxiliary_identity := mulmod(auxiliary_identity, mload(QAUX_EVAL_LOC), p)\n auxiliary_identity := mulmod(auxiliary_identity, mload(C_ALPHA_BASE_LOC), p)\n\n mstore(AUX_IDENTITY, auxiliary_identity)\n\n // update alpha\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p))\n }\n }\n }\n\n {\n /**\n * quotient = ARITHMETIC_IDENTITY\n * quotient += PERMUTATION_IDENTITY\n * quotient += PLOOKUP_IDENTITY\n * quotient += SORT_IDENTITY\n * quotient += ELLIPTIC_IDENTITY\n * quotient += AUX_IDENTITY\n * quotient *= ZERO_POLY_INVERSE\n */\n mstore(\n QUOTIENT_EVAL_LOC,\n mulmod(\n addmod(\n addmod(\n addmod(\n addmod(\n addmod(mload(PERMUTATION_IDENTITY), mload(PLOOKUP_IDENTITY), p),\n mload(ARITHMETIC_IDENTITY),\n p\n ),\n mload(SORT_IDENTITY),\n p\n ),\n mload(ELLIPTIC_IDENTITY),\n p\n ),\n mload(AUX_IDENTITY),\n p\n ),\n mload(ZERO_POLY_INVERSE_LOC),\n p\n )\n )\n }\n\n /**\n * GENERATE NU AND SEPARATOR CHALLENGES\n */\n {\n let current_challenge := mload(C_CURRENT_LOC)\n // get a calldata pointer that points to the start of the data we want to copy\n let calldata_ptr := add(calldataload(0x04), 0x24)\n\n calldata_ptr := add(calldata_ptr, NU_CALLDATA_SKIP_LENGTH)\n\n mstore(NU_CHALLENGE_INPUT_LOC_A, current_challenge)\n mstore(NU_CHALLENGE_INPUT_LOC_B, mload(QUOTIENT_EVAL_LOC))\n calldatacopy(NU_CHALLENGE_INPUT_LOC_C, calldata_ptr, NU_INPUT_LENGTH)\n\n // hash length = (0x20 + num field elements), we include the previous challenge in the hash\n let challenge := keccak256(NU_CHALLENGE_INPUT_LOC_A, add(NU_INPUT_LENGTH, 0x40))\n\n mstore(C_V0_LOC, mod(challenge, p))\n // We need THIRTY-ONE independent nu challenges!\n mstore(0x00, challenge)\n mstore8(0x20, 0x01)\n mstore(C_V1_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x02)\n mstore(C_V2_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x03)\n mstore(C_V3_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x04)\n mstore(C_V4_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x05)\n mstore(C_V5_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x06)\n mstore(C_V6_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x07)\n mstore(C_V7_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x08)\n mstore(C_V8_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x09)\n mstore(C_V9_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x0a)\n mstore(C_V10_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x0b)\n mstore(C_V11_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x0c)\n mstore(C_V12_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x0d)\n mstore(C_V13_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x0e)\n mstore(C_V14_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x0f)\n mstore(C_V15_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x10)\n mstore(C_V16_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x11)\n mstore(C_V17_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x12)\n mstore(C_V18_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x13)\n mstore(C_V19_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x14)\n mstore(C_V20_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x15)\n mstore(C_V21_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x16)\n mstore(C_V22_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x17)\n mstore(C_V23_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x18)\n mstore(C_V24_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x19)\n mstore(C_V25_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x1a)\n mstore(C_V26_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x1b)\n mstore(C_V27_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x1c)\n mstore(C_V28_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x1d)\n mstore(C_V29_LOC, mod(keccak256(0x00, 0x21), p))\n\n // @follow-up - Why are both v29 and v30 using appending 0x1d to the prior challenge and hashing, should it not change?\n mstore8(0x20, 0x1d)\n challenge := keccak256(0x00, 0x21)\n mstore(C_V30_LOC, mod(challenge, p))\n\n // separator\n mstore(0x00, challenge)\n mstore(0x20, mload(PI_Z_Y_LOC))\n mstore(0x40, mload(PI_Z_X_LOC))\n mstore(0x60, mload(PI_Z_OMEGA_Y_LOC))\n mstore(0x80, mload(PI_Z_OMEGA_X_LOC))\n\n mstore(C_U_LOC, mod(keccak256(0x00, 0xa0), p))\n }\n\n let success := 0\n // VALIDATE T1\n {\n let x := mload(T1_X_LOC)\n let y := mload(T1_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(ACCUMULATOR_X_LOC, x)\n mstore(add(ACCUMULATOR_X_LOC, 0x20), y)\n }\n // VALIDATE T2\n {\n let x := mload(T2_X_LOC) // 0x1400\n let y := mload(T2_Y_LOC) // 0x1420\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mload(ZETA_POW_N_LOC))\n // accumulator_2 = [T2].zeta^n\n success := staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)\n // accumulator = [T1] + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE T3\n {\n let x := mload(T3_X_LOC)\n let y := mload(T3_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(mload(ZETA_POW_N_LOC), mload(ZETA_POW_N_LOC), p))\n // accumulator_2 = [T3].zeta^{2n}\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE T4\n {\n let x := mload(T4_X_LOC)\n let y := mload(T4_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(mulmod(mload(ZETA_POW_N_LOC), mload(ZETA_POW_N_LOC), p), mload(ZETA_POW_N_LOC), p))\n // accumulator_2 = [T4].zeta^{3n}\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE W1\n {\n let x := mload(W1_X_LOC)\n let y := mload(W1_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V0_LOC), p))\n // accumulator_2 = v0.(u + 1).[W1]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE W2\n {\n let x := mload(W2_X_LOC)\n let y := mload(W2_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V1_LOC), p))\n // accumulator_2 = v1.(u + 1).[W2]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE W3\n {\n let x := mload(W3_X_LOC)\n let y := mload(W3_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V2_LOC), p))\n // accumulator_2 = v2.(u + 1).[W3]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE W4\n {\n let x := mload(W4_X_LOC)\n let y := mload(W4_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V3_LOC), p))\n // accumulator_2 = v3.(u + 1).[W4]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE S\n {\n let x := mload(S_X_LOC)\n let y := mload(S_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V4_LOC), p))\n // accumulator_2 = v4.(u + 1).[S]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE Z\n {\n let x := mload(Z_X_LOC)\n let y := mload(Z_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V5_LOC), p))\n // accumulator_2 = v5.(u + 1).[Z]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE Z_LOOKUP\n {\n let x := mload(Z_LOOKUP_X_LOC)\n let y := mload(Z_LOOKUP_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V6_LOC), p))\n // accumulator_2 = v6.(u + 1).[Z_LOOKUP]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE Q1\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(Q1_X_LOC))\n mstore(0x20, mload(Q1_Y_LOC))\n mstore(0x40, mload(C_V7_LOC))\n // accumulator_2 = v7.[Q1]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE Q2\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(Q2_X_LOC))\n mstore(0x20, mload(Q2_Y_LOC))\n mstore(0x40, mload(C_V8_LOC))\n // accumulator_2 = v8.[Q2]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE Q3\n \n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(Q3_X_LOC))\n mstore(0x20, mload(Q3_Y_LOC))\n mstore(0x40, mload(C_V9_LOC))\n // accumulator_2 = v9.[Q3]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE Q4\n \n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(Q4_X_LOC))\n mstore(0x20, mload(Q4_Y_LOC))\n mstore(0x40, mload(C_V10_LOC))\n // accumulator_2 = v10.[Q4]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE QM\n \n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(QM_X_LOC))\n mstore(0x20, mload(QM_Y_LOC))\n mstore(0x40, mload(C_V11_LOC))\n // accumulator_2 = v11.[Q;]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE QC\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(QC_X_LOC))\n mstore(0x20, mload(QC_Y_LOC))\n mstore(0x40, mload(C_V12_LOC))\n // accumulator_2 = v12.[QC]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE QARITH\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(QARITH_X_LOC))\n mstore(0x20, mload(QARITH_Y_LOC))\n mstore(0x40, mload(C_V13_LOC))\n // accumulator_2 = v13.[QARITH]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE QSORT\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(QSORT_X_LOC))\n mstore(0x20, mload(QSORT_Y_LOC))\n mstore(0x40, mload(C_V14_LOC))\n // accumulator_2 = v14.[QSORT]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE QELLIPTIC\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(QELLIPTIC_X_LOC))\n mstore(0x20, mload(QELLIPTIC_Y_LOC))\n mstore(0x40, mload(C_V15_LOC))\n // accumulator_2 = v15.[QELLIPTIC]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE QAUX\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(QAUX_X_LOC))\n mstore(0x20, mload(QAUX_Y_LOC))\n mstore(0x40, mload(C_V16_LOC))\n // accumulator_2 = v15.[Q_AUX]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE SIGMA1\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(SIGMA1_X_LOC))\n mstore(0x20, mload(SIGMA1_Y_LOC))\n mstore(0x40, mload(C_V17_LOC))\n // accumulator_2 = v17.[sigma1]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE SIGMA2\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(SIGMA2_X_LOC))\n mstore(0x20, mload(SIGMA2_Y_LOC))\n mstore(0x40, mload(C_V18_LOC))\n // accumulator_2 = v18.[sigma2]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE SIGMA3\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(SIGMA3_X_LOC))\n mstore(0x20, mload(SIGMA3_Y_LOC))\n mstore(0x40, mload(C_V19_LOC))\n // accumulator_2 = v19.[sigma3]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE SIGMA4\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(SIGMA4_X_LOC))\n mstore(0x20, mload(SIGMA4_Y_LOC))\n mstore(0x40, mload(C_V20_LOC))\n // accumulator_2 = v20.[sigma4]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE TABLE1\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(TABLE1_X_LOC))\n mstore(0x20, mload(TABLE1_Y_LOC))\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V21_LOC), p))\n // accumulator_2 = u.[table1]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE TABLE2\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(TABLE2_X_LOC))\n mstore(0x20, mload(TABLE2_Y_LOC))\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V22_LOC), p))\n // accumulator_2 = u.[table2]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE TABLE3\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(TABLE3_X_LOC))\n mstore(0x20, mload(TABLE3_Y_LOC))\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V23_LOC), p))\n // accumulator_2 = u.[table3]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE TABLE4\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(TABLE4_X_LOC))\n mstore(0x20, mload(TABLE4_Y_LOC))\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V24_LOC), p))\n // accumulator_2 = u.[table4]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE TABLE_TYPE\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(TABLE_TYPE_X_LOC))\n mstore(0x20, mload(TABLE_TYPE_Y_LOC))\n mstore(0x40, mload(C_V25_LOC))\n // accumulator_2 = v25.[TableType]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE ID1\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(ID1_X_LOC))\n mstore(0x20, mload(ID1_Y_LOC))\n mstore(0x40, mload(C_V26_LOC))\n // accumulator_2 = v26.[ID1]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE ID2\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(ID2_X_LOC))\n mstore(0x20, mload(ID2_Y_LOC))\n mstore(0x40, mload(C_V27_LOC))\n // accumulator_2 = v27.[ID2]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE ID3\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(ID3_X_LOC))\n mstore(0x20, mload(ID3_Y_LOC))\n mstore(0x40, mload(C_V28_LOC))\n // accumulator_2 = v28.[ID3]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE ID4\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(ID4_X_LOC))\n mstore(0x20, mload(ID4_Y_LOC))\n mstore(0x40, mload(C_V29_LOC))\n // accumulator_2 = v29.[ID4]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n /**\n * COMPUTE BATCH EVALUATION SCALAR MULTIPLIER\n */\n {\n /**\n * batch_evaluation = v0 * (w_1_omega * u + w_1_eval)\n * batch_evaluation += v1 * (w_2_omega * u + w_2_eval)\n * batch_evaluation += v2 * (w_3_omega * u + w_3_eval)\n * batch_evaluation += v3 * (w_4_omega * u + w_4_eval)\n * batch_evaluation += v4 * (s_omega_eval * u + s_eval)\n * batch_evaluation += v5 * (z_omega_eval * u + z_eval)\n * batch_evaluation += v6 * (z_lookup_omega_eval * u + z_lookup_eval)\n */\n let batch_evaluation :=\n mulmod(\n mload(C_V0_LOC),\n addmod(mulmod(mload(W1_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W1_EVAL_LOC), p),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V1_LOC),\n addmod(mulmod(mload(W2_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W2_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V2_LOC),\n addmod(mulmod(mload(W3_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W3_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V3_LOC),\n addmod(mulmod(mload(W4_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W4_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V4_LOC),\n addmod(mulmod(mload(S_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(S_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V5_LOC),\n addmod(mulmod(mload(Z_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(Z_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V6_LOC),\n addmod(mulmod(mload(Z_LOOKUP_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(Z_LOOKUP_EVAL_LOC), p),\n p\n ),\n p\n )\n\n /**\n * batch_evaluation += v7 * Q1_EVAL\n * batch_evaluation += v8 * Q2_EVAL\n * batch_evaluation += v9 * Q3_EVAL\n * batch_evaluation += v10 * Q4_EVAL\n * batch_evaluation += v11 * QM_EVAL\n * batch_evaluation += v12 * QC_EVAL\n * batch_evaluation += v13 * QARITH_EVAL\n * batch_evaluation += v14 * QSORT_EVAL_LOC\n * batch_evaluation += v15 * QELLIPTIC_EVAL_LOC\n * batch_evaluation += v16 * QAUX_EVAL_LOC\n * batch_evaluation += v17 * SIGMA1_EVAL_LOC\n * batch_evaluation += v18 * SIGMA2_EVAL_LOC\n * batch_evaluation += v19 * SIGMA3_EVAL_LOC\n * batch_evaluation += v20 * SIGMA4_EVAL_LOC\n */\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V7_LOC), mload(Q1_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V8_LOC), mload(Q2_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V9_LOC), mload(Q3_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V10_LOC), mload(Q4_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V11_LOC), mload(QM_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V12_LOC), mload(QC_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V13_LOC), mload(QARITH_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V14_LOC), mload(QSORT_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V15_LOC), mload(QELLIPTIC_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V16_LOC), mload(QAUX_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V17_LOC), mload(SIGMA1_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V18_LOC), mload(SIGMA2_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V19_LOC), mload(SIGMA3_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V20_LOC), mload(SIGMA4_EVAL_LOC), p), p)\n\n /**\n * batch_evaluation += v21 * (table1(zw) * u + table1(z))\n * batch_evaluation += v22 * (table2(zw) * u + table2(z))\n * batch_evaluation += v23 * (table3(zw) * u + table3(z))\n * batch_evaluation += v24 * (table4(zw) * u + table4(z))\n * batch_evaluation += v25 * table_type_eval\n * batch_evaluation += v26 * id1_eval\n * batch_evaluation += v27 * id2_eval\n * batch_evaluation += v28 * id3_eval\n * batch_evaluation += v29 * id4_eval\n * batch_evaluation += quotient_eval\n */\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V21_LOC),\n addmod(mulmod(mload(TABLE1_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE1_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V22_LOC),\n addmod(mulmod(mload(TABLE2_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE2_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V23_LOC),\n addmod(mulmod(mload(TABLE3_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE3_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V24_LOC),\n addmod(mulmod(mload(TABLE4_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE4_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V25_LOC), mload(TABLE_TYPE_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V26_LOC), mload(ID1_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V27_LOC), mload(ID2_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V28_LOC), mload(ID3_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V29_LOC), mload(ID4_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mload(QUOTIENT_EVAL_LOC), p)\n\n mstore(0x00, 0x01) // [1].x\n mstore(0x20, 0x02) // [1].y\n mstore(0x40, sub(p, batch_evaluation))\n // accumulator_2 = -[1].(batch_evaluation)\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n if iszero(success) {\n mstore(0x0, OPENING_COMMITMENT_FAILED_SELECTOR)\n revert(0x00, 0x04)\n }\n }\n\n /**\n * PERFORM PAIRING PREAMBLE\n */\n {\n let u := mload(C_U_LOC)\n let zeta := mload(C_ZETA_LOC)\n // VALIDATE PI_Z\n {\n let x := mload(PI_Z_X_LOC)\n let y := mload(PI_Z_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n // compute zeta.[PI_Z] and add into accumulator\n mstore(0x40, zeta)\n success := staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE PI_Z_OMEGA\n {\n let x := mload(PI_Z_OMEGA_X_LOC)\n let y := mload(PI_Z_OMEGA_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(mulmod(u, zeta, p), mload(OMEGA_LOC), p))\n // accumulator_2 = u.zeta.omega.[PI_Z_OMEGA]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // PAIRING_RHS = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, PAIRING_RHS_X_LOC, 0x40))\n\n mstore(0x00, mload(PI_Z_X_LOC))\n mstore(0x20, mload(PI_Z_Y_LOC))\n mstore(0x40, mload(PI_Z_OMEGA_X_LOC))\n mstore(0x60, mload(PI_Z_OMEGA_Y_LOC))\n mstore(0x80, u)\n success := and(success, staticcall(gas(), 7, 0x40, 0x60, 0x40, 0x40))\n // PAIRING_LHS = [PI_Z] + [PI_Z_OMEGA] * u\n success := and(success, staticcall(gas(), 6, 0x00, 0x80, PAIRING_LHS_X_LOC, 0x40))\n // negate lhs y-coordinate\n mstore(PAIRING_LHS_Y_LOC, sub(q, mload(PAIRING_LHS_Y_LOC)))\n\n if mload(CONTAINS_RECURSIVE_PROOF_LOC) {\n // VALIDATE RECURSIVE P1\n {\n let x := mload(RECURSIVE_P1_X_LOC)\n let y := mload(RECURSIVE_P1_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n\n // compute u.u.[recursive_p1] and write into 0x60\n mstore(0x40, mulmod(u, u, p))\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, 0x60, 0x40))\n // VALIDATE RECURSIVE P2\n {\n let x := mload(RECURSIVE_P2_X_LOC)\n let y := mload(RECURSIVE_P2_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n // compute u.u.[recursive_p2] and write into 0x00\n // 0x40 still contains u*u\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, 0x00, 0x40))\n\n // compute u.u.[recursiveP1] + rhs and write into rhs\n mstore(0xa0, mload(PAIRING_RHS_X_LOC))\n mstore(0xc0, mload(PAIRING_RHS_Y_LOC))\n success := and(success, staticcall(gas(), 6, 0x60, 0x80, PAIRING_RHS_X_LOC, 0x40))\n\n // compute u.u.[recursiveP2] + lhs and write into lhs\n mstore(0x40, mload(PAIRING_LHS_X_LOC))\n mstore(0x60, mload(PAIRING_LHS_Y_LOC))\n success := and(success, staticcall(gas(), 6, 0x00, 0x80, PAIRING_LHS_X_LOC, 0x40))\n }\n\n if iszero(success) {\n mstore(0x0, PAIRING_PREAMBLE_FAILED_SELECTOR)\n revert(0x00, 0x04)\n }\n }\n\n /**\n * PERFORM PAIRING\n */\n {\n // rhs paired with [1]_2\n // lhs paired with [x]_2\n\n mstore(0x00, mload(PAIRING_RHS_X_LOC))\n mstore(0x20, mload(PAIRING_RHS_Y_LOC))\n mstore(0x40, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) // this is [1]_2\n mstore(0x60, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed)\n mstore(0x80, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b)\n mstore(0xa0, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa)\n\n mstore(0xc0, mload(PAIRING_LHS_X_LOC))\n mstore(0xe0, mload(PAIRING_LHS_Y_LOC))\n mstore(0x100, mload(G2X_X0_LOC))\n mstore(0x120, mload(G2X_X1_LOC))\n mstore(0x140, mload(G2X_Y0_LOC))\n mstore(0x160, mload(G2X_Y1_LOC))\n\n success := staticcall(gas(), 8, 0x00, 0x180, 0x00, 0x20)\n if iszero(and(success, mload(0x00))) {\n mstore(0x0, PAIRING_FAILED_SELECTOR)\n revert(0x00, 0x04)\n }\n }\n\n {\n mstore(0x00, 0x01)\n return(0x00, 0x20) // Proof succeeded!\n }\n }\n }\n}\n\ncontract UltraVerifier is BaseUltraVerifier {\n function getVerificationKeyHash() public pure override(BaseUltraVerifier) returns (bytes32) {\n return UltraVerificationKey.verificationKeyHash();\n }\n\n function loadVerificationKey(uint256 vk, uint256 _omegaInverseLoc) internal pure virtual override(BaseUltraVerifier) {\n UltraVerificationKey.loadVerificationKey(vk, _omegaInverseLoc);\n }\n}\n" + }, + "solady/src/utils/Base64.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library to encode strings in Base64.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol)\n/// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - .\nlibrary Base64 {\n /// @dev Encodes `data` using the base64 encoding described in RFC 4648.\n /// See: https://datatracker.ietf.org/doc/html/rfc4648\n /// @param fileSafe Whether to replace '+' with '-' and '/' with '_'.\n /// @param noPadding Whether to strip away the padding.\n function encode(bytes memory data, bool fileSafe, bool noPadding)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let dataLength := mload(data)\n\n if dataLength {\n // Multiply by 4/3 rounded up.\n // The `shl(2, ...)` is equivalent to multiplying by 4.\n let encodedLength := shl(2, div(add(dataLength, 2), 3))\n\n // Set `result` to point to the start of the free memory.\n result := mload(0x40)\n\n // Store the table into the scratch space.\n // Offsetted by -1 byte so that the `mload` will load the character.\n // We will rewrite the free memory pointer at `0x40` later with\n // the allocated size.\n // The magic constant 0x0670 will turn \"-_\" into \"+/\".\n mstore(0x1f, \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef\")\n mstore(0x3f, xor(\"ghijklmnopqrstuvwxyz0123456789-_\", mul(iszero(fileSafe), 0x0670)))\n\n // Skip the first slot, which stores the length.\n let ptr := add(result, 0x20)\n let end := add(ptr, encodedLength)\n\n let dataEnd := add(add(0x20, data), dataLength)\n let dataEndValue := mload(dataEnd) // Cache the value at the `dataEnd` slot.\n mstore(dataEnd, 0x00) // Zeroize the `dataEnd` slot to clear dirty bits.\n\n // Run over the input, 3 bytes at a time.\n for {} 1 {} {\n data := add(data, 3) // Advance 3 bytes.\n let input := mload(data)\n\n // Write 4 bytes. Optimized for fewer stack operations.\n mstore8(0, mload(and(shr(18, input), 0x3F)))\n mstore8(1, mload(and(shr(12, input), 0x3F)))\n mstore8(2, mload(and(shr(6, input), 0x3F)))\n mstore8(3, mload(and(input, 0x3F)))\n mstore(ptr, mload(0x00))\n\n ptr := add(ptr, 4) // Advance 4 bytes.\n if iszero(lt(ptr, end)) { break }\n }\n mstore(dataEnd, dataEndValue) // Restore the cached value at `dataEnd`.\n mstore(0x40, add(end, 0x20)) // Allocate the memory.\n // Equivalent to `o = [0, 2, 1][dataLength % 3]`.\n let o := div(2, mod(dataLength, 3))\n // Offset `ptr` and pad with '='. We can simply write over the end.\n mstore(sub(ptr, o), shl(240, 0x3d3d))\n // Set `o` to zero if there is padding.\n o := mul(iszero(iszero(noPadding)), o)\n mstore(sub(ptr, o), 0) // Zeroize the slot after the string.\n mstore(result, sub(encodedLength, o)) // Store the length.\n }\n }\n }\n\n /// @dev Encodes `data` using the base64 encoding described in RFC 4648.\n /// Equivalent to `encode(data, false, false)`.\n function encode(bytes memory data) internal pure returns (string memory result) {\n result = encode(data, false, false);\n }\n\n /// @dev Encodes `data` using the base64 encoding described in RFC 4648.\n /// Equivalent to `encode(data, fileSafe, false)`.\n function encode(bytes memory data, bool fileSafe)\n internal\n pure\n returns (string memory result)\n {\n result = encode(data, fileSafe, false);\n }\n\n /// @dev Decodes base64 encoded `data`.\n ///\n /// Supports:\n /// - RFC 4648 (both standard and file-safe mode).\n /// - RFC 3501 (63: ',').\n ///\n /// Does not support:\n /// - Line breaks.\n ///\n /// Note: For performance reasons,\n /// this function will NOT revert on invalid `data` inputs.\n /// Outputs for invalid inputs will simply be undefined behaviour.\n /// It is the user's responsibility to ensure that the `data`\n /// is a valid base64 encoded string.\n function decode(string memory data) internal pure returns (bytes memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n let dataLength := mload(data)\n\n if dataLength {\n let decodedLength := mul(shr(2, dataLength), 3)\n\n for {} 1 {} {\n // If padded.\n if iszero(and(dataLength, 3)) {\n let t := xor(mload(add(data, dataLength)), 0x3d3d)\n // forgefmt: disable-next-item\n decodedLength := sub(\n decodedLength,\n add(iszero(byte(30, t)), iszero(byte(31, t)))\n )\n break\n }\n // If non-padded.\n decodedLength := add(decodedLength, sub(and(dataLength, 3), 1))\n break\n }\n result := mload(0x40)\n\n // Write the length of the bytes.\n mstore(result, decodedLength)\n\n // Skip the first slot, which stores the length.\n let ptr := add(result, 0x20)\n let end := add(ptr, decodedLength)\n\n // Load the table into the scratch space.\n // Constants are optimized for smaller bytecode with zero gas overhead.\n // `m` also doubles as the mask of the upper 6 bits.\n let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc\n mstore(0x5b, m)\n mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064)\n mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4)\n\n for {} 1 {} {\n // Read 4 bytes.\n data := add(data, 4)\n let input := mload(data)\n\n // Write 3 bytes.\n // forgefmt: disable-next-item\n mstore(ptr, or(\n and(m, mload(byte(28, input))),\n shr(6, or(\n and(m, mload(byte(29, input))),\n shr(6, or(\n and(m, mload(byte(30, input))),\n shr(6, mload(byte(31, input)))\n ))\n ))\n ))\n ptr := add(ptr, 3)\n if iszero(lt(ptr, end)) { break }\n }\n mstore(0x40, add(end, 0x20)) // Allocate the memory.\n mstore(end, 0) // Zeroize the slot after the bytes.\n mstore(0x60, 0) // Restore the zero slot.\n }\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 100000000 + }, + "evmVersion": "paris", + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/packages/contracts/deployments/odysseyTestnet/solcInputs/e2c7304a6ecf567a5c4c24c2eee90283.json b/packages/contracts/deployments/odysseyTestnet/solcInputs/e2c7304a6ecf567a5c4c24c2eee90283.json new file mode 100644 index 0000000..335ecb9 --- /dev/null +++ b/packages/contracts/deployments/odysseyTestnet/solcInputs/e2c7304a6ecf567a5c4c24c2eee90283.json @@ -0,0 +1,63 @@ +{ + "language": "Solidity", + "sources": { + "contracts/EoaAccount.sol": { + "content": "// SPDX-License-Identifier: SEE LICENSE IN LICENSE\npragma solidity ^0.8.27;\n\nimport {ZkLogin} from \"./ZkLogin.sol\";\nimport {IPublicKeyRegistry} from \"./infra/IPublicKeyRegistry.sol\";\nimport {UltraVerifier} from \"../noir/target/jwt_account.sol\";\nimport {WebAuthnP256} from \"./utils/WebAuthnP256.sol\";\nimport {ECDSA} from \"./utils/ECDSA.sol\";\n\ncontract EoaAccount {\n ZkLogin.AccountData public accountData;\n\n uint256 public nonce;\n\n ECDSA.PublicKey public webauthnPublicKey;\n\n function setAccountId(\n ECDSA.PublicKey calldata webauthnPublicKey_,\n ZkLogin.AccountData memory accountData_\n ) external {\n require(msg.sender == address(this), \"not self\");\n\n webauthnPublicKey = webauthnPublicKey_;\n\n accountData = accountData_;\n }\n\n function recover(\n ZkLogin.VerificationData calldata verificationData,\n ECDSA.PublicKey calldata newP256PublicKey\n ) external {\n require(\n keccak256(abi.encode(newP256PublicKey)) ==\n verificationData.jwtNonce,\n \"invalid WebAuthn public key\"\n );\n\n require(\n ZkLogin.verifyProof(accountData, verificationData),\n \"invalid proof\"\n );\n\n webauthnPublicKey = newP256PublicKey;\n }\n\n function execute(\n address to,\n bytes calldata data,\n uint256 value,\n ECDSA.Signature calldata signature,\n WebAuthnP256.Metadata calldata metadata\n ) public {\n bytes32 challenge = keccak256(abi.encode(nonce++, to, data, value));\n require(\n WebAuthnP256.verify(\n challenge,\n metadata,\n signature,\n webauthnPublicKey\n )\n );\n\n (bool success, ) = to.call{value: value}(data);\n require(success, \"call failed\");\n }\n\n function getWebAuthnPublicKey()\n external\n view\n returns (ECDSA.PublicKey memory)\n {\n return webauthnPublicKey;\n }\n\n receive() external payable {}\n}\n" + }, + "contracts/infra/IPublicKeyRegistry.sol": { + "content": "// SPDX-License-Identifier: SEE LICENSE IN LICENSE\npragma solidity ^0.8.27;\n\ninterface IPublicKeyRegistry {\n function checkPublicKey(\n bytes32 providerId,\n bytes32 publicKeyHash\n ) external view returns (bool);\n}\n" + }, + "contracts/IProofVerifier.sol": { + "content": "// SPDX-License-Identifier: SEE LICENSE IN LICENSE\npragma solidity ^0.8.27;\n\ninterface IProofVerifier {\n function verify(\n bytes calldata proof,\n bytes32[] calldata publicInputs\n ) external view returns (bool);\n}\n" + }, + "contracts/utils/ECDSA.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\nlibrary ECDSA {\n struct PublicKey {\n uint256 x;\n uint256 y;\n }\n\n struct Signature {\n uint256 r;\n uint256 s;\n }\n\n struct RecoveredSignature {\n uint256 r;\n uint256 s;\n uint8 yParity;\n }\n}\n" + }, + "contracts/utils/P256.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\nimport \"./ECDSA.sol\";\n\n//( @title P256\n/// @author klkvr \n/// @author jxom \n/// @notice Wrapper function to abstract low level details of call to the P256\n/// signature verification precompile as defined in EIP-7212, see\n/// .\nlibrary P256 {\n /// @notice P256VERIFY operation\n /// @param digest 32 bytes of the signed data hash\n /// @param signature Signature of the signer\n /// @param publicKey Public key of the signer\n /// @return success Represents if the operation was successful\n function verify(\n bytes32 digest,\n ECDSA.Signature memory signature,\n ECDSA.PublicKey memory publicKey\n ) internal view returns (bool) {\n // P256VERIFY address is 0x14 from \n (bool success, bytes memory output) = address(0x14).staticcall(\n abi.encode(\n digest,\n signature.r,\n signature.s,\n publicKey.x,\n publicKey.y\n )\n );\n success = success && output.length == 32 && output[31] == 0x01;\n\n return success;\n }\n}\n" + }, + "contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: SEE LICENSE IN LICENSE\npragma solidity ^0.8.27;\n\nlibrary Strings {\n bytes16 private constant HEX_DIGITS = \"0123456789abcdef\";\n\n /**\n * @dev The `value` string doesn't fit in the specified `length`.\n */\n error StringsInsufficientHexLength(uint256 value, uint256 length);\n\n function toHexStringWithoutPrefix(\n uint256 value,\n uint256 length\n ) internal pure returns (string memory) {\n uint256 localValue = value;\n bytes memory buffer = new bytes(2 * length);\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i - 2] = HEX_DIGITS[localValue & 0xf];\n localValue >>= 4;\n }\n if (localValue != 0) {\n revert StringsInsufficientHexLength(value, length);\n }\n return string(buffer);\n }\n\n function toHexStringWithoutPrefix(\n bytes32 value\n ) internal pure returns (string memory) {\n return toHexStringWithoutPrefix(uint256(value), 32);\n }\n}\n" + }, + "contracts/utils/WebAuthnP256.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\nimport {Base64} from \"solady/src/utils/Base64.sol\";\nimport \"./ECDSA.sol\";\nimport \"./P256.sol\";\n\n/// @title WebAuthnP256\n/// @author jxom \n/// @notice Helper library for external contracts to verify WebAuthn signatures.\n/// @dev Adapted from https://github.com/daimo-eth/p256-verifier/blob/master/src/WebAuthn.sol\nlibrary WebAuthnP256 {\n struct Metadata {\n bytes authenticatorData;\n string clientDataJSON;\n uint16 challengeIndex;\n uint16 typeIndex;\n bool userVerificationRequired;\n }\n\n /// Checks whether substr occurs in str starting at a given byte offset.\n function contains(\n string memory substr,\n string memory str,\n uint256 location\n ) internal pure returns (bool) {\n bytes memory substrBytes = bytes(substr);\n bytes memory strBytes = bytes(str);\n\n uint256 substrLen = substrBytes.length;\n uint256 strLen = strBytes.length;\n\n for (uint256 i = 0; i < substrLen; i++) {\n if (location + i >= strLen) {\n return false;\n }\n\n if (substrBytes[i] != strBytes[location + i]) {\n return false;\n }\n }\n\n return true;\n }\n\n bytes1 constant AUTH_DATA_FLAGS_UP = 0x01; // Bit 0\n bytes1 constant AUTH_DATA_FLAGS_UV = 0x04; // Bit 2\n bytes1 constant AUTH_DATA_FLAGS_BE = 0x08; // Bit 3\n bytes1 constant AUTH_DATA_FLAGS_BS = 0x10; // Bit 4\n\n /// Verifies the authFlags in authenticatorData. Numbers in inline comment\n /// correspond to the same numbered bullets in\n /// https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion.\n function checkAuthFlags(\n bytes1 flags,\n bool requireUserVerification\n ) internal pure returns (bool) {\n // 17. Verify that the UP bit of the flags in authData is set.\n if (flags & AUTH_DATA_FLAGS_UP != AUTH_DATA_FLAGS_UP) {\n return false;\n }\n\n // 18. If user verification was determined to be required, verify that\n // the UV bit of the flags in authData is set. Otherwise, ignore the\n // value of the UV flag.\n if (\n requireUserVerification &&\n (flags & AUTH_DATA_FLAGS_UV) != AUTH_DATA_FLAGS_UV\n ) {\n return false;\n }\n\n // 19. If the BE bit of the flags in authData is not set, verify that\n // the BS bit is not set.\n if (flags & AUTH_DATA_FLAGS_BE != AUTH_DATA_FLAGS_BE) {\n if (flags & AUTH_DATA_FLAGS_BS == AUTH_DATA_FLAGS_BS) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Verifies a Webauthn P256 signature (Authentication Assertion) as described\n * in https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion. We do not\n * verify all the steps as described in the specification, only ones relevant\n * to our context. Please carefully read through this list before usage.\n * Specifically, we do verify the following:\n * - Verify that authenticatorData (which comes from the authenticator,\n * such as iCloud Keychain) indicates a well-formed assertion. If\n * requireUserVerification is set, checks that the authenticator enforced\n * user verification. User verification should be required if,\n * and only if, options.userVerification is set to required in the request\n * - Verifies that the client JSON is of type \"webauthn.get\", i.e. the client\n * was responding to a request to assert authentication.\n * - Verifies that the client JSON contains the requested challenge.\n * - Finally, verifies that (r, s) constitute a valid signature over both\n * the authenicatorData and client JSON, for public key (x, y).\n *\n * We make some assumptions about the particular use case of this verifier,\n * so we do NOT verify the following:\n * - Does NOT verify that the origin in the clientDataJSON matches the\n * Relying Party's origin: It is considered the authenticator's\n * responsibility to ensure that the user is interacting with the correct\n * RP. This is enforced by most high quality authenticators properly,\n * particularly the iCloud Keychain and Google Password Manager were\n * tested.\n * - Does NOT verify That c.topOrigin is well-formed: We assume c.topOrigin\n * would never be present, i.e. the credentials are never used in a\n * cross-origin/iframe context. The website/app set up should disallow\n * cross-origin usage of the credentials. This is the default behaviour for\n * created credentials in common settings.\n * - Does NOT verify that the rpIdHash in authData is the SHA-256 hash of an\n * RP ID expected by the Relying Party: This means that we rely on the\n * authenticator to properly enforce credentials to be used only by the\n * correct RP. This is generally enforced with features like Apple App Site\n * Association and Google Asset Links. To protect from edge cases in which\n * a previously-linked RP ID is removed from the authorised RP IDs,\n * we recommend that messages signed by the authenticator include some\n * expiry mechanism.\n * - Does NOT verify the credential backup state: This assumes the credential\n * backup state is NOT used as part of Relying Party business logic or\n * policy.\n * - Does NOT verify the values of the client extension outputs: This assumes\n * that the Relying Party does not use client extension outputs.\n * - Does NOT verify the signature counter: Signature counters are intended\n * to enable risk scoring for the Relying Party. This assumes risk scoring\n * is not used as part of Relying Party business logic or policy.\n * - Does NOT verify the attestation object: This assumes that\n * response.attestationObject is NOT present in the response, i.e. the\n * RP does not intend to verify an attestation.\n */\n function verify(\n bytes32 challenge,\n Metadata memory metadata,\n ECDSA.Signature memory signature,\n ECDSA.PublicKey memory publicKey\n ) internal view returns (bool) {\n // Check that authenticatorData has good flags\n if (\n metadata.authenticatorData.length < 37 ||\n !checkAuthFlags(\n metadata.authenticatorData[32],\n metadata.userVerificationRequired\n )\n ) {\n return false;\n }\n\n // Check that response is for an authentication assertion\n string memory responseType = '\"type\":\"webauthn.get\"';\n if (\n !contains(responseType, metadata.clientDataJSON, metadata.typeIndex)\n ) {\n return false;\n }\n\n // Check that challenge is in the clientDataJSON\n string memory challengeB64url = Base64.encode(\n abi.encodePacked(challenge),\n true,\n true\n );\n string memory challengeProperty = string.concat(\n '\"challenge\":\"',\n challengeB64url,\n '\"'\n );\n\n if (\n !contains(\n challengeProperty,\n metadata.clientDataJSON,\n metadata.challengeIndex\n )\n ) {\n return false;\n }\n\n // Check that the public key signed sha256(authenticatorData || sha256(clientDataJSON))\n bytes32 clientDataJSONHash = sha256(bytes(metadata.clientDataJSON));\n bytes32 messageHash = sha256(\n abi.encodePacked(metadata.authenticatorData, clientDataJSONHash)\n );\n\n return P256.verify(messageHash, signature, publicKey);\n }\n}\n" + }, + "contracts/ZkLogin.sol": { + "content": "// SPDX-License-Identifier: SEE LICENSE IN LICENSE\npragma solidity ^0.8.27;\n\nimport {IProofVerifier} from \"./IProofVerifier.sol\";\nimport {Strings} from \"./utils/Strings.sol\";\nimport {IPublicKeyRegistry} from \"./infra/IPublicKeyRegistry.sol\";\n\nlibrary ZkLogin {\n struct AccountData {\n bytes32 accountId;\n bytes32 authProviderId;\n address publicKeyRegistry;\n address proofVerifier;\n }\n\n struct VerificationData {\n bytes proof;\n uint256 jwtIat;\n bytes32 jwtNonce;\n bytes32 publicKeyHash;\n }\n\n function verifyProof(\n AccountData memory accountData,\n VerificationData memory verificationData\n ) internal view returns (bool) {\n require(\n IPublicKeyRegistry(accountData.publicKeyRegistry).checkPublicKey(\n accountData.authProviderId,\n verificationData.publicKeyHash\n ),\n \"public key hash mismatch\"\n );\n\n bytes memory jwtNonce = bytes(\n Strings.toHexStringWithoutPrefix(verificationData.jwtNonce)\n );\n\n uint256 staticInputLength = 3;\n bytes32[] memory publicInputs = new bytes32[](\n staticInputLength + jwtNonce.length\n );\n uint256 j = 0;\n publicInputs[j++] = accountData.accountId;\n publicInputs[j++] = bytes32(verificationData.jwtIat);\n publicInputs[j++] = verificationData.publicKeyHash;\n\n for (uint256 i = 0; i < jwtNonce.length; i++) {\n publicInputs[j++] = bytes32(uint256(uint8(jwtNonce[i])));\n }\n assert(j == publicInputs.length);\n\n return\n IProofVerifier(accountData.proofVerifier).verify(\n verificationData.proof,\n publicInputs\n );\n }\n}\n" + }, + "noir/target/jwt_account.sol": { + "content": "// Verification Key Hash: df17b68894fbe76ada8e2859abb6925eb52b99f2516db87bc9720ed3f22c9625\n// SPDX-License-Identifier: Apache-2.0\n// Copyright 2022 Aztec\npragma solidity >=0.8.4;\n\nlibrary UltraVerificationKey {\n function verificationKeyHash() internal pure returns(bytes32) {\n return 0xdf17b68894fbe76ada8e2859abb6925eb52b99f2516db87bc9720ed3f22c9625;\n }\n\n function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure {\n assembly {\n mstore(add(_vk, 0x00), 0x0000000000000000000000000000000000000000000000000000000000040000) // vk.circuit_size\n mstore(add(_vk, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000043) // vk.num_inputs\n mstore(add(_vk, 0x40), 0x19ddbcaf3a8d46c15c0176fbb5b95e4dc57088ff13f4d1bd84c6bfa57dcdc0e0) // vk.work_root\n mstore(add(_vk, 0x60), 0x30644259cd94e7dd5045d7a27013b7fcd21c9e3b7fa75222e7bda49b729b0401) // vk.domain_inverse\n mstore(add(_vk, 0x80), 0x1f71d28f11460f73331294dcf27294a19ed4b299e9017ae496055943f52e24e2) // vk.Q1.x\n mstore(add(_vk, 0xa0), 0x271a3a71a32f091c6798366f7973de1d977acfaf7724ff5058e7cba7cdd23b80) // vk.Q1.y\n mstore(add(_vk, 0xc0), 0x2b1cb88996c8731ebf20516498954b9a032de3b05df44d5e7d26e6363f3d60e1) // vk.Q2.x\n mstore(add(_vk, 0xe0), 0x196fadb6d06f205cc5ebae7284263b042d5b9fa18199256d3cc7781e3711af5d) // vk.Q2.y\n mstore(add(_vk, 0x100), 0x08c5d310e66efae284aa2e844dec1675291c7991f45b4cdaa46ba9b8e537b9be) // vk.Q3.x\n mstore(add(_vk, 0x120), 0x19d75133597f5a7faa14851b95187f35ef8f1fa1f414d3f4089cc07f1b9865e4) // vk.Q3.y\n mstore(add(_vk, 0x140), 0x1b8337f6394b77c6fd4fb9f6d6a92a6edc860e19c3653088a95edc825af4b540) // vk.Q4.x\n mstore(add(_vk, 0x160), 0x0780e2515f54a5f9c172e47e47021b475bc28d46a5507d71ca963ea8bcf76082) // vk.Q4.y\n mstore(add(_vk, 0x180), 0x2e0f0594e85394a51b61896fe2c840722a2fb8b47b0085fa8402689a9e69db78) // vk.Q_M.x\n mstore(add(_vk, 0x1a0), 0x12d1e049b46895986669c27c85bc03c732e1f8588e8a7692f89574875472b207) // vk.Q_M.y\n mstore(add(_vk, 0x1c0), 0x2386abedd596e6ae42de8b18c2c2482a0f132fed2010b5701c7e5e84e6abf202) // vk.Q_C.x\n mstore(add(_vk, 0x1e0), 0x25844948d313c3863f20e125e45f6812f96c4474a9a391a79b70da7b79ff14f9) // vk.Q_C.y\n mstore(add(_vk, 0x200), 0x281abbca08b2d727b5f127242dc71d78d7d133ce160cfeb8f11438f69f8ae5ef) // vk.Q_ARITHMETIC.x\n mstore(add(_vk, 0x220), 0x151febc070ee5a29f29e66c7dfdc46d31d53781b12a5092e7fcc32cb8e5f1ef9) // vk.Q_ARITHMETIC.y\n mstore(add(_vk, 0x240), 0x1107a754c3f11021248c43d10abd2ed46eafd9e293ee620b50cdb47e65123bc7) // vk.QSORT.x\n mstore(add(_vk, 0x260), 0x150544048502e4a6252dc819526c72cf6e605c841af7b06028e7f722819893a7) // vk.QSORT.y\n mstore(add(_vk, 0x280), 0x22f2a3213af13776e6bd38362a5885cbf923d5630eda38ba032a42faeb1ea61c) // vk.Q_ELLIPTIC.x\n mstore(add(_vk, 0x2a0), 0x177d8d1ed4c4b9e2c3f232b25de8638139e795bd40689a9765750ebaca55f48f) // vk.Q_ELLIPTIC.y\n mstore(add(_vk, 0x2c0), 0x0383b7f12114cc47c75eb683abb079fdb0cddcade14107819bb917209c0ae05a) // vk.Q_AUX.x\n mstore(add(_vk, 0x2e0), 0x0ac0be98b2a66afb7df02cf9bcb702ab54e4d48fb08eef1f8c60a957603617cd) // vk.Q_AUX.y\n mstore(add(_vk, 0x300), 0x199abd2d188bed224ba145f82d16e61939a31b6fb98fd6620e1b0242cf78bb0f) // vk.SIGMA1.x\n mstore(add(_vk, 0x320), 0x1199f428a1af935ac6e0fd709b7fd8393bdce95e95f017257583153a99befb44) // vk.SIGMA1.y\n mstore(add(_vk, 0x340), 0x1fb4c449e6bd67bc3dd0ec09e740bd5895b1952f2c42a54c0eb8d59ffa4f81e4) // vk.SIGMA2.x\n mstore(add(_vk, 0x360), 0x15914e6eac131c6c3e51703646e5524a0be256a25f0a29ac12aca19352c9bff6) // vk.SIGMA2.y\n mstore(add(_vk, 0x380), 0x2ea86576148d8d46e4b782c77af341f15b7d0d68f661b3445f6476dd54a7a558) // vk.SIGMA3.x\n mstore(add(_vk, 0x3a0), 0x1e1bee942b8d63fb9e4a324d07f538d69a0b9d895a0e765e8116df0dd41350b3) // vk.SIGMA3.y\n mstore(add(_vk, 0x3c0), 0x1a97a02b48f748c9fe2dcc9c3f829b2ea194f120c1110a43080112108eacad9e) // vk.SIGMA4.x\n mstore(add(_vk, 0x3e0), 0x1dcab1530e972eb87903764308228f9c6eb1e0a8ece757616146eb9ac92f41a0) // vk.SIGMA4.y\n mstore(add(_vk, 0x400), 0x12037992a0868b71fd31e8afdd2eadb65703eb9b066f46619795addc76c4c040) // vk.TABLE1.x\n mstore(add(_vk, 0x420), 0x03087c87f8e680e93787d0b1ee1e7b03a361953026880f136896be768c398a52) // vk.TABLE1.y\n mstore(add(_vk, 0x440), 0x20333b8a625e44316eb415594db2fb1418360858b9bbd871eb602d1e2d99aec3) // vk.TABLE2.x\n mstore(add(_vk, 0x460), 0x071cff58e911f0bfbb01a49556356929c0d32d3a343fb91c62728b5f40ef9c2e) // vk.TABLE2.y\n mstore(add(_vk, 0x480), 0x05ea76ef86cb4a6516241f0ffd1cb4a3d08911ed1785b2c2e5d21d03160af911) // vk.TABLE3.x\n mstore(add(_vk, 0x4a0), 0x04bf914031bd405440af705425e95109b8ccb07be5f521baf78522a47f808aef) // vk.TABLE3.y\n mstore(add(_vk, 0x4c0), 0x17841405ffd5b7391dfc4c67df8b83b829c04c6c39fa304c63ba85efc356cb6b) // vk.TABLE4.x\n mstore(add(_vk, 0x4e0), 0x071662508f56a08c39f23e3b574939b610830931daaf5f8c7da09d8341423e72) // vk.TABLE4.y\n mstore(add(_vk, 0x500), 0x2cd0adb4efab7c1f2f3ce467113f6b5a60ab824b86852c995d83e87af264bd71) // vk.TABLE_TYPE.x\n mstore(add(_vk, 0x520), 0x0c6a58624d7220202551ec32fe8abdd14f9830dc08578941185a66282cb04948) // vk.TABLE_TYPE.y\n mstore(add(_vk, 0x540), 0x13f7aa6c469715e6cd1f38bf20c9b09078403df8217f9d30df97aae41d460f40) // vk.ID1.x\n mstore(add(_vk, 0x560), 0x02944c0148d257c53e52d2ea61b6fcfedf6dc6861d4833893f5b2f367e68232f) // vk.ID1.y\n mstore(add(_vk, 0x580), 0x0737ea2401dff83ecc5d6258aec1533b305e85a418c2a8c2fbec7bf6fbc39599) // vk.ID2.x\n mstore(add(_vk, 0x5a0), 0x108fb619aec96784857cd68447c8455790602ef51e7e6e4c7cdc416831a9ab50) // vk.ID2.y\n mstore(add(_vk, 0x5c0), 0x1064d92338c133f3c77d13a7d4d688f94216dca3143f8ff96aa5b9530295cc97) // vk.ID3.x\n mstore(add(_vk, 0x5e0), 0x2336336f949cb51eab3edeb98bbeeb7aecd353fda918c1ee5aea9d01f1e2b446) // vk.ID3.y\n mstore(add(_vk, 0x600), 0x1beb44efe9150760b8b668dd41a5229e21258845fb446004f5b5501ba4a6495c) // vk.ID4.x\n mstore(add(_vk, 0x620), 0x1c7187e828b8c1ef699c55a031ca21baeea080a8f70a7e41b41ea35eff4ffeb0) // vk.ID4.y\n mstore(add(_vk, 0x640), 0x00) // vk.contains_pairing_point_accumulator\n mstore(add(_vk, 0x660), 0) // vk.pairing_point_accumulator_public_input_indices\n mstore(add(_vk, 0x680), 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1) // vk.g2_x.X.c1 \n mstore(add(_vk, 0x6a0), 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0) // vk.g2_x.X.c0 \n mstore(add(_vk, 0x6c0), 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4) // vk.g2_x.Y.c1 \n mstore(add(_vk, 0x6e0), 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55) // vk.g2_x.Y.c0 \n mstore(_omegaInverseLoc, 0x036853f083780e87f8d7c71d111119c57dbe118c22d5ad707a82317466c5174c) // vk.work_root_inverse\n }\n }\n}\n\n/**\n * @title Ultra Plonk proof verification contract\n * @dev Top level Plonk proof verification contract, which allows Plonk proof to be verified\n */\nabstract contract BaseUltraVerifier {\n // VERIFICATION KEY MEMORY LOCATIONS\n uint256 internal constant N_LOC = 0x380;\n uint256 internal constant NUM_INPUTS_LOC = 0x3a0;\n uint256 internal constant OMEGA_LOC = 0x3c0;\n uint256 internal constant DOMAIN_INVERSE_LOC = 0x3e0;\n uint256 internal constant Q1_X_LOC = 0x400;\n uint256 internal constant Q1_Y_LOC = 0x420;\n uint256 internal constant Q2_X_LOC = 0x440;\n uint256 internal constant Q2_Y_LOC = 0x460;\n uint256 internal constant Q3_X_LOC = 0x480;\n uint256 internal constant Q3_Y_LOC = 0x4a0;\n uint256 internal constant Q4_X_LOC = 0x4c0;\n uint256 internal constant Q4_Y_LOC = 0x4e0;\n uint256 internal constant QM_X_LOC = 0x500;\n uint256 internal constant QM_Y_LOC = 0x520;\n uint256 internal constant QC_X_LOC = 0x540;\n uint256 internal constant QC_Y_LOC = 0x560;\n uint256 internal constant QARITH_X_LOC = 0x580;\n uint256 internal constant QARITH_Y_LOC = 0x5a0;\n uint256 internal constant QSORT_X_LOC = 0x5c0;\n uint256 internal constant QSORT_Y_LOC = 0x5e0;\n uint256 internal constant QELLIPTIC_X_LOC = 0x600;\n uint256 internal constant QELLIPTIC_Y_LOC = 0x620;\n uint256 internal constant QAUX_X_LOC = 0x640;\n uint256 internal constant QAUX_Y_LOC = 0x660;\n uint256 internal constant SIGMA1_X_LOC = 0x680;\n uint256 internal constant SIGMA1_Y_LOC = 0x6a0;\n uint256 internal constant SIGMA2_X_LOC = 0x6c0;\n uint256 internal constant SIGMA2_Y_LOC = 0x6e0;\n uint256 internal constant SIGMA3_X_LOC = 0x700;\n uint256 internal constant SIGMA3_Y_LOC = 0x720;\n uint256 internal constant SIGMA4_X_LOC = 0x740;\n uint256 internal constant SIGMA4_Y_LOC = 0x760;\n uint256 internal constant TABLE1_X_LOC = 0x780;\n uint256 internal constant TABLE1_Y_LOC = 0x7a0;\n uint256 internal constant TABLE2_X_LOC = 0x7c0;\n uint256 internal constant TABLE2_Y_LOC = 0x7e0;\n uint256 internal constant TABLE3_X_LOC = 0x800;\n uint256 internal constant TABLE3_Y_LOC = 0x820;\n uint256 internal constant TABLE4_X_LOC = 0x840;\n uint256 internal constant TABLE4_Y_LOC = 0x860;\n uint256 internal constant TABLE_TYPE_X_LOC = 0x880;\n uint256 internal constant TABLE_TYPE_Y_LOC = 0x8a0;\n uint256 internal constant ID1_X_LOC = 0x8c0;\n uint256 internal constant ID1_Y_LOC = 0x8e0;\n uint256 internal constant ID2_X_LOC = 0x900;\n uint256 internal constant ID2_Y_LOC = 0x920;\n uint256 internal constant ID3_X_LOC = 0x940;\n uint256 internal constant ID3_Y_LOC = 0x960;\n uint256 internal constant ID4_X_LOC = 0x980;\n uint256 internal constant ID4_Y_LOC = 0x9a0;\n uint256 internal constant CONTAINS_RECURSIVE_PROOF_LOC = 0x9c0;\n uint256 internal constant RECURSIVE_PROOF_PUBLIC_INPUT_INDICES_LOC = 0x9e0;\n uint256 internal constant G2X_X0_LOC = 0xa00;\n uint256 internal constant G2X_X1_LOC = 0xa20;\n uint256 internal constant G2X_Y0_LOC = 0xa40;\n uint256 internal constant G2X_Y1_LOC = 0xa60;\n\n // ### PROOF DATA MEMORY LOCATIONS\n uint256 internal constant W1_X_LOC = 0x1200;\n uint256 internal constant W1_Y_LOC = 0x1220;\n uint256 internal constant W2_X_LOC = 0x1240;\n uint256 internal constant W2_Y_LOC = 0x1260;\n uint256 internal constant W3_X_LOC = 0x1280;\n uint256 internal constant W3_Y_LOC = 0x12a0;\n uint256 internal constant W4_X_LOC = 0x12c0;\n uint256 internal constant W4_Y_LOC = 0x12e0;\n uint256 internal constant S_X_LOC = 0x1300;\n uint256 internal constant S_Y_LOC = 0x1320;\n uint256 internal constant Z_X_LOC = 0x1340;\n uint256 internal constant Z_Y_LOC = 0x1360;\n uint256 internal constant Z_LOOKUP_X_LOC = 0x1380;\n uint256 internal constant Z_LOOKUP_Y_LOC = 0x13a0;\n uint256 internal constant T1_X_LOC = 0x13c0;\n uint256 internal constant T1_Y_LOC = 0x13e0;\n uint256 internal constant T2_X_LOC = 0x1400;\n uint256 internal constant T2_Y_LOC = 0x1420;\n uint256 internal constant T3_X_LOC = 0x1440;\n uint256 internal constant T3_Y_LOC = 0x1460;\n uint256 internal constant T4_X_LOC = 0x1480;\n uint256 internal constant T4_Y_LOC = 0x14a0;\n\n uint256 internal constant W1_EVAL_LOC = 0x1600;\n uint256 internal constant W2_EVAL_LOC = 0x1620;\n uint256 internal constant W3_EVAL_LOC = 0x1640;\n uint256 internal constant W4_EVAL_LOC = 0x1660;\n uint256 internal constant S_EVAL_LOC = 0x1680;\n uint256 internal constant Z_EVAL_LOC = 0x16a0;\n uint256 internal constant Z_LOOKUP_EVAL_LOC = 0x16c0;\n uint256 internal constant Q1_EVAL_LOC = 0x16e0;\n uint256 internal constant Q2_EVAL_LOC = 0x1700;\n uint256 internal constant Q3_EVAL_LOC = 0x1720;\n uint256 internal constant Q4_EVAL_LOC = 0x1740;\n uint256 internal constant QM_EVAL_LOC = 0x1760;\n uint256 internal constant QC_EVAL_LOC = 0x1780;\n uint256 internal constant QARITH_EVAL_LOC = 0x17a0;\n uint256 internal constant QSORT_EVAL_LOC = 0x17c0;\n uint256 internal constant QELLIPTIC_EVAL_LOC = 0x17e0;\n uint256 internal constant QAUX_EVAL_LOC = 0x1800;\n uint256 internal constant TABLE1_EVAL_LOC = 0x1840;\n uint256 internal constant TABLE2_EVAL_LOC = 0x1860;\n uint256 internal constant TABLE3_EVAL_LOC = 0x1880;\n uint256 internal constant TABLE4_EVAL_LOC = 0x18a0;\n uint256 internal constant TABLE_TYPE_EVAL_LOC = 0x18c0;\n uint256 internal constant ID1_EVAL_LOC = 0x18e0;\n uint256 internal constant ID2_EVAL_LOC = 0x1900;\n uint256 internal constant ID3_EVAL_LOC = 0x1920;\n uint256 internal constant ID4_EVAL_LOC = 0x1940;\n uint256 internal constant SIGMA1_EVAL_LOC = 0x1960;\n uint256 internal constant SIGMA2_EVAL_LOC = 0x1980;\n uint256 internal constant SIGMA3_EVAL_LOC = 0x19a0;\n uint256 internal constant SIGMA4_EVAL_LOC = 0x19c0;\n uint256 internal constant W1_OMEGA_EVAL_LOC = 0x19e0;\n uint256 internal constant W2_OMEGA_EVAL_LOC = 0x2000;\n uint256 internal constant W3_OMEGA_EVAL_LOC = 0x2020;\n uint256 internal constant W4_OMEGA_EVAL_LOC = 0x2040;\n uint256 internal constant S_OMEGA_EVAL_LOC = 0x2060;\n uint256 internal constant Z_OMEGA_EVAL_LOC = 0x2080;\n uint256 internal constant Z_LOOKUP_OMEGA_EVAL_LOC = 0x20a0;\n uint256 internal constant TABLE1_OMEGA_EVAL_LOC = 0x20c0;\n uint256 internal constant TABLE2_OMEGA_EVAL_LOC = 0x20e0;\n uint256 internal constant TABLE3_OMEGA_EVAL_LOC = 0x2100;\n uint256 internal constant TABLE4_OMEGA_EVAL_LOC = 0x2120;\n\n uint256 internal constant PI_Z_X_LOC = 0x2300;\n uint256 internal constant PI_Z_Y_LOC = 0x2320;\n uint256 internal constant PI_Z_OMEGA_X_LOC = 0x2340;\n uint256 internal constant PI_Z_OMEGA_Y_LOC = 0x2360;\n\n // Used for elliptic widget. These are alias names for wire + shifted wire evaluations\n uint256 internal constant X1_EVAL_LOC = W2_EVAL_LOC;\n uint256 internal constant X2_EVAL_LOC = W1_OMEGA_EVAL_LOC;\n uint256 internal constant X3_EVAL_LOC = W2_OMEGA_EVAL_LOC;\n uint256 internal constant Y1_EVAL_LOC = W3_EVAL_LOC;\n uint256 internal constant Y2_EVAL_LOC = W4_OMEGA_EVAL_LOC;\n uint256 internal constant Y3_EVAL_LOC = W3_OMEGA_EVAL_LOC;\n uint256 internal constant QBETA_LOC = Q3_EVAL_LOC;\n uint256 internal constant QBETA_SQR_LOC = Q4_EVAL_LOC;\n uint256 internal constant QSIGN_LOC = Q1_EVAL_LOC;\n\n // ### CHALLENGES MEMORY OFFSETS\n\n uint256 internal constant C_BETA_LOC = 0x2600;\n uint256 internal constant C_GAMMA_LOC = 0x2620;\n uint256 internal constant C_ALPHA_LOC = 0x2640;\n uint256 internal constant C_ETA_LOC = 0x2660;\n uint256 internal constant C_ETA_SQR_LOC = 0x2680;\n uint256 internal constant C_ETA_CUBE_LOC = 0x26a0;\n\n uint256 internal constant C_ZETA_LOC = 0x26c0;\n uint256 internal constant C_CURRENT_LOC = 0x26e0;\n uint256 internal constant C_V0_LOC = 0x2700;\n uint256 internal constant C_V1_LOC = 0x2720;\n uint256 internal constant C_V2_LOC = 0x2740;\n uint256 internal constant C_V3_LOC = 0x2760;\n uint256 internal constant C_V4_LOC = 0x2780;\n uint256 internal constant C_V5_LOC = 0x27a0;\n uint256 internal constant C_V6_LOC = 0x27c0;\n uint256 internal constant C_V7_LOC = 0x27e0;\n uint256 internal constant C_V8_LOC = 0x2800;\n uint256 internal constant C_V9_LOC = 0x2820;\n uint256 internal constant C_V10_LOC = 0x2840;\n uint256 internal constant C_V11_LOC = 0x2860;\n uint256 internal constant C_V12_LOC = 0x2880;\n uint256 internal constant C_V13_LOC = 0x28a0;\n uint256 internal constant C_V14_LOC = 0x28c0;\n uint256 internal constant C_V15_LOC = 0x28e0;\n uint256 internal constant C_V16_LOC = 0x2900;\n uint256 internal constant C_V17_LOC = 0x2920;\n uint256 internal constant C_V18_LOC = 0x2940;\n uint256 internal constant C_V19_LOC = 0x2960;\n uint256 internal constant C_V20_LOC = 0x2980;\n uint256 internal constant C_V21_LOC = 0x29a0;\n uint256 internal constant C_V22_LOC = 0x29c0;\n uint256 internal constant C_V23_LOC = 0x29e0;\n uint256 internal constant C_V24_LOC = 0x2a00;\n uint256 internal constant C_V25_LOC = 0x2a20;\n uint256 internal constant C_V26_LOC = 0x2a40;\n uint256 internal constant C_V27_LOC = 0x2a60;\n uint256 internal constant C_V28_LOC = 0x2a80;\n uint256 internal constant C_V29_LOC = 0x2aa0;\n uint256 internal constant C_V30_LOC = 0x2ac0;\n\n uint256 internal constant C_U_LOC = 0x2b00;\n\n // ### LOCAL VARIABLES MEMORY OFFSETS\n uint256 internal constant DELTA_NUMERATOR_LOC = 0x3000;\n uint256 internal constant DELTA_DENOMINATOR_LOC = 0x3020;\n uint256 internal constant ZETA_POW_N_LOC = 0x3040;\n uint256 internal constant PUBLIC_INPUT_DELTA_LOC = 0x3060;\n uint256 internal constant ZERO_POLY_LOC = 0x3080;\n uint256 internal constant L_START_LOC = 0x30a0;\n uint256 internal constant L_END_LOC = 0x30c0;\n uint256 internal constant R_ZERO_EVAL_LOC = 0x30e0;\n\n uint256 internal constant PLOOKUP_DELTA_NUMERATOR_LOC = 0x3100;\n uint256 internal constant PLOOKUP_DELTA_DENOMINATOR_LOC = 0x3120;\n uint256 internal constant PLOOKUP_DELTA_LOC = 0x3140;\n\n uint256 internal constant ACCUMULATOR_X_LOC = 0x3160;\n uint256 internal constant ACCUMULATOR_Y_LOC = 0x3180;\n uint256 internal constant ACCUMULATOR2_X_LOC = 0x31a0;\n uint256 internal constant ACCUMULATOR2_Y_LOC = 0x31c0;\n uint256 internal constant PAIRING_LHS_X_LOC = 0x31e0;\n uint256 internal constant PAIRING_LHS_Y_LOC = 0x3200;\n uint256 internal constant PAIRING_RHS_X_LOC = 0x3220;\n uint256 internal constant PAIRING_RHS_Y_LOC = 0x3240;\n\n // misc stuff\n uint256 internal constant OMEGA_INVERSE_LOC = 0x3300;\n uint256 internal constant C_ALPHA_SQR_LOC = 0x3320;\n uint256 internal constant C_ALPHA_CUBE_LOC = 0x3340;\n uint256 internal constant C_ALPHA_QUAD_LOC = 0x3360;\n uint256 internal constant C_ALPHA_BASE_LOC = 0x3380;\n\n // ### RECURSION VARIABLE MEMORY LOCATIONS\n uint256 internal constant RECURSIVE_P1_X_LOC = 0x3400;\n uint256 internal constant RECURSIVE_P1_Y_LOC = 0x3420;\n uint256 internal constant RECURSIVE_P2_X_LOC = 0x3440;\n uint256 internal constant RECURSIVE_P2_Y_LOC = 0x3460;\n uint256 internal constant PUBLIC_INPUTS_HASH_LOCATION = 0x3480;\n\n // sub-identity storage\n uint256 internal constant PERMUTATION_IDENTITY = 0x3500;\n uint256 internal constant PLOOKUP_IDENTITY = 0x3520;\n uint256 internal constant ARITHMETIC_IDENTITY = 0x3540;\n uint256 internal constant SORT_IDENTITY = 0x3560;\n uint256 internal constant ELLIPTIC_IDENTITY = 0x3580;\n uint256 internal constant AUX_IDENTITY = 0x35a0;\n uint256 internal constant AUX_NON_NATIVE_FIELD_EVALUATION = 0x35c0;\n uint256 internal constant AUX_LIMB_ACCUMULATOR_EVALUATION = 0x35e0;\n uint256 internal constant AUX_RAM_CONSISTENCY_EVALUATION = 0x3600;\n uint256 internal constant AUX_ROM_CONSISTENCY_EVALUATION = 0x3620;\n uint256 internal constant AUX_MEMORY_EVALUATION = 0x3640;\n\n uint256 internal constant QUOTIENT_EVAL_LOC = 0x3660;\n uint256 internal constant ZERO_POLY_INVERSE_LOC = 0x3680;\n\n // when hashing public inputs we use memory at NU_CHALLENGE_INPUT_LOC_A, as the hash input size is unknown at compile time\n uint256 internal constant NU_CHALLENGE_INPUT_LOC_A = 0x36a0;\n uint256 internal constant NU_CHALLENGE_INPUT_LOC_B = 0x36c0;\n uint256 internal constant NU_CHALLENGE_INPUT_LOC_C = 0x36e0;\n\n bytes4 internal constant INVALID_VERIFICATION_KEY_SELECTOR = 0x7e5769bf;\n bytes4 internal constant POINT_NOT_ON_CURVE_SELECTOR = 0xa3dad654;\n bytes4 internal constant PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR = 0xeba9f4a6;\n bytes4 internal constant PUBLIC_INPUT_GE_P_SELECTOR = 0x374a972f;\n bytes4 internal constant MOD_EXP_FAILURE_SELECTOR = 0xf894a7bc;\n bytes4 internal constant PAIRING_PREAMBLE_FAILED_SELECTOR = 0x01882d81;\n bytes4 internal constant OPENING_COMMITMENT_FAILED_SELECTOR = 0x4e719763;\n bytes4 internal constant PAIRING_FAILED_SELECTOR = 0xd71fd263;\n\n uint256 internal constant ETA_INPUT_LENGTH = 0xc0; // W1, W2, W3 = 6 * 0x20 bytes\n\n // We need to hash 41 field elements when generating the NU challenge\n // w1, w2, w3, w4, s, z, z_lookup, q1, q2, q3, q4, qm, qc, qarith (14)\n // qsort, qelliptic, qaux, sigma1, sigma2, sigma, sigma4, (7)\n // table1, table2, table3, table4, tabletype, id1, id2, id3, id4, (9)\n // w1_omega, w2_omega, w3_omega, w4_omega, s_omega, z_omega, z_lookup_omega, (7)\n // table1_omega, table2_omega, table3_omega, table4_omega (4)\n uint256 internal constant NU_INPUT_LENGTH = 0x520; // 0x520 = 41 * 0x20\n\n // There are ELEVEN G1 group elements added into the transcript in the `beta` round, that we need to skip over\n // W1, W2, W3, W4, S, Z, Z_LOOKUP, T1, T2, T3, T4\n uint256 internal constant NU_CALLDATA_SKIP_LENGTH = 0x2c0; // 11 * 0x40 = 0x2c0\n\n uint256 internal constant NEGATIVE_INVERSE_OF_2_MODULO_P =\n 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000;\n uint256 internal constant LIMB_SIZE = 0x100000000000000000; // 2<<68\n uint256 internal constant SUBLIMB_SHIFT = 0x4000; // 2<<14\n\n // y^2 = x^3 + ax + b\n // for Grumpkin, a = 0 and b = -17. We use b in a custom gate relation that evaluates elliptic curve arithmetic\n uint256 internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = 17;\n\n error INVALID_VERIFICATION_KEY();\n error POINT_NOT_ON_CURVE();\n error PUBLIC_INPUT_COUNT_INVALID(uint256 expected, uint256 actual);\n error PUBLIC_INPUT_INVALID_BN128_G1_POINT();\n error PUBLIC_INPUT_GE_P();\n error MOD_EXP_FAILURE();\n error PAIRING_PREAMBLE_FAILED();\n error OPENING_COMMITMENT_FAILED();\n error PAIRING_FAILED();\n\n function getVerificationKeyHash() public pure virtual returns (bytes32);\n\n /**\n * @dev We assume that the verification key loaded by this function is constant as we only verify it on deployment\n */\n function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure virtual;\n\n constructor() { \n loadVerificationKey(N_LOC, OMEGA_INVERSE_LOC);\n\n // We verify that all of the EC points in the verification key lie on the bn128 curve. \n assembly {\n let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // EC group order\n\n let success := 1\n\n // VALIDATE Q1\n {\n let x := mload(Q1_X_LOC)\n let y := mload(Q1_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE Q2\n {\n let x := mload(Q2_X_LOC)\n let y := mload(Q2_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE Q3\n {\n let x := mload(Q3_X_LOC)\n let y := mload(Q3_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE Q4\n {\n let x := mload(Q4_X_LOC)\n let y := mload(Q4_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n mstore(0x00, x)\n mstore(0x20, y)\n }\n // VALIDATE QM\n {\n let x := mload(QM_X_LOC)\n let y := mload(QM_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE QC\n {\n let x := mload(QC_X_LOC)\n let y := mload(QC_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE QARITH\n {\n let x := mload(QARITH_X_LOC)\n let y := mload(QARITH_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE QSORT\n {\n let x := mload(QSORT_X_LOC)\n let y := mload(QSORT_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE QELLIPTIC\n {\n let x := mload(QELLIPTIC_X_LOC)\n let y := mload(QELLIPTIC_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE QAUX\n {\n let x := mload(QAUX_X_LOC)\n let y := mload(QAUX_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE SIGMA1\n {\n let x := mload(SIGMA1_X_LOC)\n let y := mload(SIGMA1_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE SIGMA2\n {\n let x := mload(SIGMA2_X_LOC)\n let y := mload(SIGMA2_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE SIGMA3\n {\n let x := mload(SIGMA3_X_LOC)\n let y := mload(SIGMA3_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE SIGMA4\n {\n let x := mload(SIGMA4_X_LOC)\n let y := mload(SIGMA4_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE TABLE1\n {\n let x := mload(TABLE1_X_LOC)\n let y := mload(TABLE1_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n } \n // VALIDATE TABLE2\n {\n let x := mload(TABLE2_X_LOC)\n let y := mload(TABLE2_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n } \n // VALIDATE TABLE3\n {\n let x := mload(TABLE3_X_LOC)\n let y := mload(TABLE3_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n } \n // VALIDATE TABLE4\n {\n let x := mload(TABLE4_X_LOC)\n let y := mload(TABLE4_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n } \n // VALIDATE TABLE_TYPE\n {\n let x := mload(TABLE_TYPE_X_LOC)\n let y := mload(TABLE_TYPE_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE ID1\n {\n let x := mload(ID1_X_LOC)\n let y := mload(ID1_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE ID2\n {\n let x := mload(ID2_X_LOC)\n let y := mload(ID2_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE ID3\n {\n let x := mload(ID3_X_LOC)\n let y := mload(ID3_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n // VALIDATE ID4\n {\n let x := mload(ID4_X_LOC)\n let y := mload(ID4_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))\n }\n\n if iszero(success) {\n mstore(0x0, INVALID_VERIFICATION_KEY_SELECTOR)\n revert(0x00, 0x04)\n }\n }\n }\n\n /**\n * @notice Verify a Ultra Plonk proof\n * @param _proof - The serialized proof\n * @param _publicInputs - An array of the public inputs\n * @return True if proof is valid, reverts otherwise\n */\n function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) {\n loadVerificationKey(N_LOC, OMEGA_INVERSE_LOC);\n\n uint256 requiredPublicInputCount;\n assembly {\n requiredPublicInputCount := mload(NUM_INPUTS_LOC)\n }\n if (requiredPublicInputCount != _publicInputs.length) {\n revert PUBLIC_INPUT_COUNT_INVALID(requiredPublicInputCount, _publicInputs.length);\n }\n\n assembly {\n let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // EC group order\n let p := 21888242871839275222246405745257275088548364400416034343698204186575808495617 // Prime field order\n\n /**\n * LOAD PROOF FROM CALLDATA\n */\n {\n let data_ptr := add(calldataload(0x04), 0x24)\n\n mstore(W1_Y_LOC, mod(calldataload(data_ptr), q))\n mstore(W1_X_LOC, mod(calldataload(add(data_ptr, 0x20)), q))\n\n mstore(W2_Y_LOC, mod(calldataload(add(data_ptr, 0x40)), q))\n mstore(W2_X_LOC, mod(calldataload(add(data_ptr, 0x60)), q))\n\n mstore(W3_Y_LOC, mod(calldataload(add(data_ptr, 0x80)), q))\n mstore(W3_X_LOC, mod(calldataload(add(data_ptr, 0xa0)), q))\n\n mstore(W4_Y_LOC, mod(calldataload(add(data_ptr, 0xc0)), q))\n mstore(W4_X_LOC, mod(calldataload(add(data_ptr, 0xe0)), q))\n\n mstore(S_Y_LOC, mod(calldataload(add(data_ptr, 0x100)), q))\n mstore(S_X_LOC, mod(calldataload(add(data_ptr, 0x120)), q))\n mstore(Z_Y_LOC, mod(calldataload(add(data_ptr, 0x140)), q))\n mstore(Z_X_LOC, mod(calldataload(add(data_ptr, 0x160)), q))\n mstore(Z_LOOKUP_Y_LOC, mod(calldataload(add(data_ptr, 0x180)), q))\n mstore(Z_LOOKUP_X_LOC, mod(calldataload(add(data_ptr, 0x1a0)), q))\n mstore(T1_Y_LOC, mod(calldataload(add(data_ptr, 0x1c0)), q))\n mstore(T1_X_LOC, mod(calldataload(add(data_ptr, 0x1e0)), q))\n\n mstore(T2_Y_LOC, mod(calldataload(add(data_ptr, 0x200)), q))\n mstore(T2_X_LOC, mod(calldataload(add(data_ptr, 0x220)), q))\n\n mstore(T3_Y_LOC, mod(calldataload(add(data_ptr, 0x240)), q))\n mstore(T3_X_LOC, mod(calldataload(add(data_ptr, 0x260)), q))\n\n mstore(T4_Y_LOC, mod(calldataload(add(data_ptr, 0x280)), q))\n mstore(T4_X_LOC, mod(calldataload(add(data_ptr, 0x2a0)), q))\n\n mstore(W1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x2c0)), p))\n mstore(W2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x2e0)), p))\n mstore(W3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x300)), p))\n mstore(W4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x320)), p))\n mstore(S_EVAL_LOC, mod(calldataload(add(data_ptr, 0x340)), p))\n mstore(Z_EVAL_LOC, mod(calldataload(add(data_ptr, 0x360)), p))\n mstore(Z_LOOKUP_EVAL_LOC, mod(calldataload(add(data_ptr, 0x380)), p))\n mstore(Q1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3a0)), p))\n mstore(Q2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3c0)), p))\n mstore(Q3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3e0)), p))\n mstore(Q4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x400)), p))\n mstore(QM_EVAL_LOC, mod(calldataload(add(data_ptr, 0x420)), p))\n mstore(QC_EVAL_LOC, mod(calldataload(add(data_ptr, 0x440)), p))\n mstore(QARITH_EVAL_LOC, mod(calldataload(add(data_ptr, 0x460)), p))\n mstore(QSORT_EVAL_LOC, mod(calldataload(add(data_ptr, 0x480)), p))\n mstore(QELLIPTIC_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4a0)), p))\n mstore(QAUX_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4c0)), p))\n\n mstore(SIGMA1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4e0)), p))\n mstore(SIGMA2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x500)), p))\n\n mstore(SIGMA3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x520)), p))\n mstore(SIGMA4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x540)), p))\n\n mstore(TABLE1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x560)), p))\n mstore(TABLE2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x580)), p))\n mstore(TABLE3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5a0)), p))\n mstore(TABLE4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5c0)), p))\n mstore(TABLE_TYPE_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5e0)), p))\n\n mstore(ID1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x600)), p))\n mstore(ID2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x620)), p))\n mstore(ID3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x640)), p))\n mstore(ID4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x660)), p))\n\n mstore(W1_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x680)), p))\n mstore(W2_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6a0)), p))\n mstore(W3_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6c0)), p))\n mstore(W4_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6e0)), p))\n mstore(S_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x700)), p))\n\n mstore(Z_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x720)), p))\n\n mstore(Z_LOOKUP_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x740)), p))\n mstore(TABLE1_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x760)), p))\n mstore(TABLE2_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x780)), p))\n mstore(TABLE3_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x7a0)), p))\n mstore(TABLE4_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x7c0)), p))\n\n mstore(PI_Z_Y_LOC, mod(calldataload(add(data_ptr, 0x7e0)), q))\n mstore(PI_Z_X_LOC, mod(calldataload(add(data_ptr, 0x800)), q))\n\n mstore(PI_Z_OMEGA_Y_LOC, mod(calldataload(add(data_ptr, 0x820)), q))\n mstore(PI_Z_OMEGA_X_LOC, mod(calldataload(add(data_ptr, 0x840)), q))\n }\n\n /**\n * LOAD RECURSIVE PROOF INTO MEMORY\n */\n {\n if mload(CONTAINS_RECURSIVE_PROOF_LOC) {\n let public_inputs_ptr := add(calldataload(0x24), 0x24)\n let index_counter := add(shl(5, mload(RECURSIVE_PROOF_PUBLIC_INPUT_INDICES_LOC)), public_inputs_ptr)\n\n let x0 := calldataload(index_counter)\n x0 := add(x0, shl(68, calldataload(add(index_counter, 0x20))))\n x0 := add(x0, shl(136, calldataload(add(index_counter, 0x40))))\n x0 := add(x0, shl(204, calldataload(add(index_counter, 0x60))))\n let y0 := calldataload(add(index_counter, 0x80))\n y0 := add(y0, shl(68, calldataload(add(index_counter, 0xa0))))\n y0 := add(y0, shl(136, calldataload(add(index_counter, 0xc0))))\n y0 := add(y0, shl(204, calldataload(add(index_counter, 0xe0))))\n let x1 := calldataload(add(index_counter, 0x100))\n x1 := add(x1, shl(68, calldataload(add(index_counter, 0x120))))\n x1 := add(x1, shl(136, calldataload(add(index_counter, 0x140))))\n x1 := add(x1, shl(204, calldataload(add(index_counter, 0x160))))\n let y1 := calldataload(add(index_counter, 0x180))\n y1 := add(y1, shl(68, calldataload(add(index_counter, 0x1a0))))\n y1 := add(y1, shl(136, calldataload(add(index_counter, 0x1c0))))\n y1 := add(y1, shl(204, calldataload(add(index_counter, 0x1e0))))\n mstore(RECURSIVE_P1_X_LOC, x0)\n mstore(RECURSIVE_P1_Y_LOC, y0)\n mstore(RECURSIVE_P2_X_LOC, x1)\n mstore(RECURSIVE_P2_Y_LOC, y1)\n\n // validate these are valid bn128 G1 points\n if iszero(and(and(lt(x0, q), lt(x1, q)), and(lt(y0, q), lt(y1, q)))) {\n mstore(0x00, PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR)\n revert(0x00, 0x04)\n }\n }\n }\n\n {\n /**\n * Generate initial challenge\n */\n mstore(0x00, shl(224, mload(N_LOC)))\n mstore(0x04, shl(224, mload(NUM_INPUTS_LOC)))\n let challenge := keccak256(0x00, 0x08)\n\n /**\n * Generate eta challenge\n */\n mstore(PUBLIC_INPUTS_HASH_LOCATION, challenge)\n // The public input location is stored at 0x24, we then add 0x24 to skip selector and the length of public inputs\n let public_inputs_start := add(calldataload(0x24), 0x24)\n // copy the public inputs over\n let public_input_size := mul(mload(NUM_INPUTS_LOC), 0x20)\n calldatacopy(add(PUBLIC_INPUTS_HASH_LOCATION, 0x20), public_inputs_start, public_input_size)\n\n // copy W1, W2, W3 into challenge. Each point is 0x40 bytes, so load 0xc0 = 3 * 0x40 bytes (ETA input length)\n let w_start := add(calldataload(0x04), 0x24)\n calldatacopy(add(add(PUBLIC_INPUTS_HASH_LOCATION, 0x20), public_input_size), w_start, ETA_INPUT_LENGTH)\n\n // Challenge is the old challenge + public inputs + W1, W2, W3 (0x20 + public_input_size + 0xc0)\n let challenge_bytes_size := add(0x20, add(public_input_size, ETA_INPUT_LENGTH))\n\n challenge := keccak256(PUBLIC_INPUTS_HASH_LOCATION, challenge_bytes_size)\n {\n let eta := mod(challenge, p)\n mstore(C_ETA_LOC, eta)\n mstore(C_ETA_SQR_LOC, mulmod(eta, eta, p))\n mstore(C_ETA_CUBE_LOC, mulmod(mload(C_ETA_SQR_LOC), eta, p))\n }\n\n /**\n * Generate beta challenge\n */\n mstore(0x00, challenge)\n mstore(0x20, mload(W4_Y_LOC))\n mstore(0x40, mload(W4_X_LOC))\n mstore(0x60, mload(S_Y_LOC))\n mstore(0x80, mload(S_X_LOC))\n challenge := keccak256(0x00, 0xa0)\n mstore(C_BETA_LOC, mod(challenge, p))\n\n /**\n * Generate gamma challenge\n */\n mstore(0x00, challenge)\n mstore8(0x20, 0x01)\n challenge := keccak256(0x00, 0x21)\n mstore(C_GAMMA_LOC, mod(challenge, p))\n\n /**\n * Generate alpha challenge\n */\n mstore(0x00, challenge)\n mstore(0x20, mload(Z_Y_LOC))\n mstore(0x40, mload(Z_X_LOC))\n mstore(0x60, mload(Z_LOOKUP_Y_LOC))\n mstore(0x80, mload(Z_LOOKUP_X_LOC))\n challenge := keccak256(0x00, 0xa0)\n mstore(C_ALPHA_LOC, mod(challenge, p))\n\n /**\n * Compute and store some powers of alpha for future computations\n */\n let alpha := mload(C_ALPHA_LOC)\n mstore(C_ALPHA_SQR_LOC, mulmod(alpha, alpha, p))\n mstore(C_ALPHA_CUBE_LOC, mulmod(mload(C_ALPHA_SQR_LOC), alpha, p))\n mstore(C_ALPHA_QUAD_LOC, mulmod(mload(C_ALPHA_CUBE_LOC), alpha, p))\n mstore(C_ALPHA_BASE_LOC, alpha)\n\n /**\n * Generate zeta challenge\n */\n mstore(0x00, challenge)\n mstore(0x20, mload(T1_Y_LOC))\n mstore(0x40, mload(T1_X_LOC))\n mstore(0x60, mload(T2_Y_LOC))\n mstore(0x80, mload(T2_X_LOC))\n mstore(0xa0, mload(T3_Y_LOC))\n mstore(0xc0, mload(T3_X_LOC))\n mstore(0xe0, mload(T4_Y_LOC))\n mstore(0x100, mload(T4_X_LOC))\n\n challenge := keccak256(0x00, 0x120)\n\n mstore(C_ZETA_LOC, mod(challenge, p))\n mstore(C_CURRENT_LOC, challenge)\n }\n\n /**\n * EVALUATE FIELD OPERATIONS\n */\n\n /**\n * COMPUTE PUBLIC INPUT DELTA\n * ΔPI = ∏ᵢ∈ℓ(wᵢ + β σ(i) + γ) / ∏ᵢ∈ℓ(wᵢ + β σ'(i) + γ)\n */\n {\n let beta := mload(C_BETA_LOC) // β\n let gamma := mload(C_GAMMA_LOC) // γ\n let work_root := mload(OMEGA_LOC) // ω\n let numerator_value := 1\n let denominator_value := 1\n\n let p_clone := p // move p to the front of the stack\n let valid_inputs := true\n\n // Load the starting point of the public inputs (jump over the selector and the length of public inputs [0x24])\n let public_inputs_ptr := add(calldataload(0x24), 0x24)\n\n // endpoint_ptr = public_inputs_ptr + num_inputs * 0x20. // every public input is 0x20 bytes\n let endpoint_ptr := add(public_inputs_ptr, mul(mload(NUM_INPUTS_LOC), 0x20))\n\n // root_1 = β * 0x05\n let root_1 := mulmod(beta, 0x05, p_clone) // k1.β\n // root_2 = β * 0x0c\n let root_2 := mulmod(beta, 0x0c, p_clone)\n // @note 0x05 + 0x07 == 0x0c == external coset generator\n\n for {} lt(public_inputs_ptr, endpoint_ptr) { public_inputs_ptr := add(public_inputs_ptr, 0x20) } {\n /**\n * input = public_input[i]\n * valid_inputs &= input < p\n * temp = input + gamma\n * numerator_value *= (β.σ(i) + wᵢ + γ) // σ(i) = 0x05.ωⁱ\n * denominator_value *= (β.σ'(i) + wᵢ + γ) // σ'(i) = 0x0c.ωⁱ\n * root_1 *= ω\n * root_2 *= ω\n */\n\n let input := calldataload(public_inputs_ptr)\n valid_inputs := and(valid_inputs, lt(input, p_clone))\n let temp := addmod(input, gamma, p_clone)\n\n numerator_value := mulmod(numerator_value, add(root_1, temp), p_clone)\n denominator_value := mulmod(denominator_value, add(root_2, temp), p_clone)\n\n root_1 := mulmod(root_1, work_root, p_clone)\n root_2 := mulmod(root_2, work_root, p_clone)\n }\n\n // Revert if not all public inputs are field elements (i.e. < p)\n if iszero(valid_inputs) {\n mstore(0x00, PUBLIC_INPUT_GE_P_SELECTOR)\n revert(0x00, 0x04)\n }\n\n mstore(DELTA_NUMERATOR_LOC, numerator_value)\n mstore(DELTA_DENOMINATOR_LOC, denominator_value)\n }\n\n /**\n * Compute Plookup delta factor [γ(1 + β)]^{n-k}\n * k = num roots cut out of Z_H = 4\n */\n {\n let delta_base := mulmod(mload(C_GAMMA_LOC), addmod(mload(C_BETA_LOC), 1, p), p)\n let delta_numerator := delta_base\n {\n let exponent := mload(N_LOC)\n let count := 1\n for {} lt(count, exponent) { count := add(count, count) } {\n delta_numerator := mulmod(delta_numerator, delta_numerator, p)\n }\n }\n mstore(PLOOKUP_DELTA_NUMERATOR_LOC, delta_numerator)\n\n let delta_denominator := mulmod(delta_base, delta_base, p)\n delta_denominator := mulmod(delta_denominator, delta_denominator, p)\n mstore(PLOOKUP_DELTA_DENOMINATOR_LOC, delta_denominator)\n }\n /**\n * Compute lagrange poly and vanishing poly fractions\n */\n {\n /**\n * vanishing_numerator = zeta\n * ZETA_POW_N = zeta^n\n * vanishing_numerator -= 1\n * accumulating_root = omega_inverse\n * work_root = p - accumulating_root\n * domain_inverse = domain_inverse\n * vanishing_denominator = zeta + work_root\n * work_root *= accumulating_root\n * vanishing_denominator *= (zeta + work_root)\n * work_root *= accumulating_root\n * vanishing_denominator *= (zeta + work_root)\n * vanishing_denominator *= (zeta + (zeta + accumulating_root))\n * work_root = omega\n * lagrange_numerator = vanishing_numerator * domain_inverse\n * l_start_denominator = zeta - 1\n * accumulating_root = work_root^2\n * l_end_denominator = accumulating_root^2 * work_root * zeta - 1\n * Note: l_end_denominator term contains a term \\omega^5 to cut out 5 roots of unity from vanishing poly\n */\n\n let zeta := mload(C_ZETA_LOC)\n\n // compute zeta^n, where n is a power of 2\n let vanishing_numerator := zeta\n {\n // pow_small\n let exponent := mload(N_LOC)\n let count := 1\n for {} lt(count, exponent) { count := add(count, count) } {\n vanishing_numerator := mulmod(vanishing_numerator, vanishing_numerator, p)\n }\n }\n mstore(ZETA_POW_N_LOC, vanishing_numerator)\n vanishing_numerator := addmod(vanishing_numerator, sub(p, 1), p)\n\n let accumulating_root := mload(OMEGA_INVERSE_LOC)\n let work_root := sub(p, accumulating_root)\n let domain_inverse := mload(DOMAIN_INVERSE_LOC)\n\n let vanishing_denominator := addmod(zeta, work_root, p)\n work_root := mulmod(work_root, accumulating_root, p)\n vanishing_denominator := mulmod(vanishing_denominator, addmod(zeta, work_root, p), p)\n work_root := mulmod(work_root, accumulating_root, p)\n vanishing_denominator := mulmod(vanishing_denominator, addmod(zeta, work_root, p), p)\n vanishing_denominator :=\n mulmod(vanishing_denominator, addmod(zeta, mulmod(work_root, accumulating_root, p), p), p)\n\n work_root := mload(OMEGA_LOC)\n\n let lagrange_numerator := mulmod(vanishing_numerator, domain_inverse, p)\n let l_start_denominator := addmod(zeta, sub(p, 1), p)\n\n accumulating_root := mulmod(work_root, work_root, p)\n\n let l_end_denominator :=\n addmod(\n mulmod(mulmod(mulmod(accumulating_root, accumulating_root, p), work_root, p), zeta, p), sub(p, 1), p\n )\n\n /**\n * Compute inversions using Montgomery's batch inversion trick\n */\n let accumulator := mload(DELTA_DENOMINATOR_LOC)\n let t0 := accumulator\n accumulator := mulmod(accumulator, vanishing_denominator, p)\n let t1 := accumulator\n accumulator := mulmod(accumulator, vanishing_numerator, p)\n let t2 := accumulator\n accumulator := mulmod(accumulator, l_start_denominator, p)\n let t3 := accumulator\n accumulator := mulmod(accumulator, mload(PLOOKUP_DELTA_DENOMINATOR_LOC), p)\n let t4 := accumulator\n {\n mstore(0, 0x20)\n mstore(0x20, 0x20)\n mstore(0x40, 0x20)\n mstore(0x60, mulmod(accumulator, l_end_denominator, p))\n mstore(0x80, sub(p, 2))\n mstore(0xa0, p)\n if iszero(staticcall(gas(), 0x05, 0x00, 0xc0, 0x00, 0x20)) {\n mstore(0x0, MOD_EXP_FAILURE_SELECTOR)\n revert(0x00, 0x04)\n }\n accumulator := mload(0x00)\n }\n\n t4 := mulmod(accumulator, t4, p)\n accumulator := mulmod(accumulator, l_end_denominator, p)\n\n t3 := mulmod(accumulator, t3, p)\n accumulator := mulmod(accumulator, mload(PLOOKUP_DELTA_DENOMINATOR_LOC), p)\n\n t2 := mulmod(accumulator, t2, p)\n accumulator := mulmod(accumulator, l_start_denominator, p)\n\n t1 := mulmod(accumulator, t1, p)\n accumulator := mulmod(accumulator, vanishing_numerator, p)\n\n t0 := mulmod(accumulator, t0, p)\n accumulator := mulmod(accumulator, vanishing_denominator, p)\n\n accumulator := mulmod(mulmod(accumulator, accumulator, p), mload(DELTA_DENOMINATOR_LOC), p)\n\n mstore(PUBLIC_INPUT_DELTA_LOC, mulmod(mload(DELTA_NUMERATOR_LOC), accumulator, p))\n mstore(ZERO_POLY_LOC, mulmod(vanishing_numerator, t0, p))\n mstore(ZERO_POLY_INVERSE_LOC, mulmod(vanishing_denominator, t1, p))\n mstore(L_START_LOC, mulmod(lagrange_numerator, t2, p))\n mstore(PLOOKUP_DELTA_LOC, mulmod(mload(PLOOKUP_DELTA_NUMERATOR_LOC), t3, p))\n mstore(L_END_LOC, mulmod(lagrange_numerator, t4, p))\n }\n\n /**\n * UltraPlonk Widget Ordering:\n *\n * 1. Permutation widget\n * 2. Plookup widget\n * 3. Arithmetic widget\n * 4. Fixed base widget (?)\n * 5. GenPermSort widget\n * 6. Elliptic widget\n * 7. Auxiliary widget\n */\n\n /**\n * COMPUTE PERMUTATION WIDGET EVALUATION\n */\n {\n let alpha := mload(C_ALPHA_LOC)\n let beta := mload(C_BETA_LOC)\n let gamma := mload(C_GAMMA_LOC)\n\n /**\n * t1 = (W1 + gamma + beta * ID1) * (W2 + gamma + beta * ID2)\n * t2 = (W3 + gamma + beta * ID3) * (W4 + gamma + beta * ID4)\n * result = alpha_base * z_eval * t1 * t2\n * t1 = (W1 + gamma + beta * sigma_1_eval) * (W2 + gamma + beta * sigma_2_eval)\n * t2 = (W2 + gamma + beta * sigma_3_eval) * (W3 + gamma + beta * sigma_4_eval)\n * result -= (alpha_base * z_omega_eval * t1 * t2)\n */\n let t1 :=\n mulmod(\n add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(ID1_EVAL_LOC), p)),\n add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(ID2_EVAL_LOC), p)),\n p\n )\n let t2 :=\n mulmod(\n add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(ID3_EVAL_LOC), p)),\n add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(ID4_EVAL_LOC), p)),\n p\n )\n let result := mulmod(mload(C_ALPHA_BASE_LOC), mulmod(mload(Z_EVAL_LOC), mulmod(t1, t2, p), p), p)\n t1 :=\n mulmod(\n add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA1_EVAL_LOC), p)),\n add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA2_EVAL_LOC), p)),\n p\n )\n t2 :=\n mulmod(\n add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA3_EVAL_LOC), p)),\n add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA4_EVAL_LOC), p)),\n p\n )\n result :=\n addmod(\n result,\n sub(p, mulmod(mload(C_ALPHA_BASE_LOC), mulmod(mload(Z_OMEGA_EVAL_LOC), mulmod(t1, t2, p), p), p)),\n p\n )\n\n /**\n * alpha_base *= alpha\n * result += alpha_base . (L_{n-k}(ʓ) . (z(ʓ.ω) - ∆_{PI}))\n * alpha_base *= alpha\n * result += alpha_base . (L_1(ʓ)(Z(ʓ) - 1))\n * alpha_Base *= alpha\n */\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p))\n result :=\n addmod(\n result,\n mulmod(\n mload(C_ALPHA_BASE_LOC),\n mulmod(\n mload(L_END_LOC),\n addmod(mload(Z_OMEGA_EVAL_LOC), sub(p, mload(PUBLIC_INPUT_DELTA_LOC)), p),\n p\n ),\n p\n ),\n p\n )\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p))\n mstore(\n PERMUTATION_IDENTITY,\n addmod(\n result,\n mulmod(\n mload(C_ALPHA_BASE_LOC),\n mulmod(mload(L_START_LOC), addmod(mload(Z_EVAL_LOC), sub(p, 1), p), p),\n p\n ),\n p\n )\n )\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p))\n }\n\n /**\n * COMPUTE PLOOKUP WIDGET EVALUATION\n */\n {\n /**\n * Goal: f = (w1(z) + q2.w1(zω)) + η(w2(z) + qm.w2(zω)) + η²(w3(z) + qc.w_3(zω)) + q3(z).η³\n * f = η.q3(z)\n * f += (w3(z) + qc.w_3(zω))\n * f *= η\n * f += (w2(z) + qm.w2(zω))\n * f *= η\n * f += (w1(z) + q2.w1(zω))\n */\n let f := mulmod(mload(C_ETA_LOC), mload(Q3_EVAL_LOC), p)\n f :=\n addmod(f, addmod(mload(W3_EVAL_LOC), mulmod(mload(QC_EVAL_LOC), mload(W3_OMEGA_EVAL_LOC), p), p), p)\n f := mulmod(f, mload(C_ETA_LOC), p)\n f :=\n addmod(f, addmod(mload(W2_EVAL_LOC), mulmod(mload(QM_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), p), p)\n f := mulmod(f, mload(C_ETA_LOC), p)\n f :=\n addmod(f, addmod(mload(W1_EVAL_LOC), mulmod(mload(Q2_EVAL_LOC), mload(W1_OMEGA_EVAL_LOC), p), p), p)\n\n // t(z) = table4(z).η³ + table3(z).η² + table2(z).η + table1(z)\n let t :=\n addmod(\n addmod(\n addmod(\n mulmod(mload(TABLE4_EVAL_LOC), mload(C_ETA_CUBE_LOC), p),\n mulmod(mload(TABLE3_EVAL_LOC), mload(C_ETA_SQR_LOC), p),\n p\n ),\n mulmod(mload(TABLE2_EVAL_LOC), mload(C_ETA_LOC), p),\n p\n ),\n mload(TABLE1_EVAL_LOC),\n p\n )\n\n // t(zw) = table4(zw).η³ + table3(zw).η² + table2(zw).η + table1(zw)\n let t_omega :=\n addmod(\n addmod(\n addmod(\n mulmod(mload(TABLE4_OMEGA_EVAL_LOC), mload(C_ETA_CUBE_LOC), p),\n mulmod(mload(TABLE3_OMEGA_EVAL_LOC), mload(C_ETA_SQR_LOC), p),\n p\n ),\n mulmod(mload(TABLE2_OMEGA_EVAL_LOC), mload(C_ETA_LOC), p),\n p\n ),\n mload(TABLE1_OMEGA_EVAL_LOC),\n p\n )\n\n /**\n * Goal: numerator = (TABLE_TYPE_EVAL * f(z) + γ) * (t(z) + βt(zω) + γ(β + 1)) * (β + 1)\n * gamma_beta_constant = γ(β + 1)\n * numerator = f * TABLE_TYPE_EVAL + gamma\n * temp0 = t(z) + t(zω) * β + gamma_beta_constant\n * numerator *= temp0\n * numerator *= (β + 1)\n * temp0 = alpha * l_1\n * numerator += temp0\n * numerator *= z_lookup(z)\n * numerator -= temp0\n */\n let gamma_beta_constant := mulmod(mload(C_GAMMA_LOC), addmod(mload(C_BETA_LOC), 1, p), p)\n let numerator := addmod(mulmod(f, mload(TABLE_TYPE_EVAL_LOC), p), mload(C_GAMMA_LOC), p)\n let temp0 := addmod(addmod(t, mulmod(t_omega, mload(C_BETA_LOC), p), p), gamma_beta_constant, p)\n numerator := mulmod(numerator, temp0, p)\n numerator := mulmod(numerator, addmod(mload(C_BETA_LOC), 1, p), p)\n temp0 := mulmod(mload(C_ALPHA_LOC), mload(L_START_LOC), p)\n numerator := addmod(numerator, temp0, p)\n numerator := mulmod(numerator, mload(Z_LOOKUP_EVAL_LOC), p)\n numerator := addmod(numerator, sub(p, temp0), p)\n\n /**\n * Goal: denominator = z_lookup(zω)*[s(z) + βs(zω) + γ(1 + β)] - [z_lookup(zω) - [γ(1 + β)]^{n-k}]*α²L_end(z)\n * note: delta_factor = [γ(1 + β)]^{n-k}\n * denominator = s(z) + βs(zω) + γ(β + 1)\n * temp1 = α²L_end(z)\n * denominator -= temp1\n * denominator *= z_lookup(zω)\n * denominator += temp1 * delta_factor\n * PLOOKUP_IDENTITY = (numerator - denominator).alpha_base\n * alpha_base *= alpha^3\n */\n let denominator :=\n addmod(\n addmod(mload(S_EVAL_LOC), mulmod(mload(S_OMEGA_EVAL_LOC), mload(C_BETA_LOC), p), p),\n gamma_beta_constant,\n p\n )\n let temp1 := mulmod(mload(C_ALPHA_SQR_LOC), mload(L_END_LOC), p)\n denominator := addmod(denominator, sub(p, temp1), p)\n denominator := mulmod(denominator, mload(Z_LOOKUP_OMEGA_EVAL_LOC), p)\n denominator := addmod(denominator, mulmod(temp1, mload(PLOOKUP_DELTA_LOC), p), p)\n\n mstore(PLOOKUP_IDENTITY, mulmod(addmod(numerator, sub(p, denominator), p), mload(C_ALPHA_BASE_LOC), p))\n\n // update alpha\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p))\n }\n\n /**\n * COMPUTE ARITHMETIC WIDGET EVALUATION\n */\n {\n /**\n * The basic arithmetic gate identity in standard plonk is as follows.\n * (w_1 . w_2 . q_m) + (w_1 . q_1) + (w_2 . q_2) + (w_3 . q_3) + (w_4 . q_4) + q_c = 0\n * However, for Ultraplonk, we extend this to support \"passing\" wires between rows (shown without alpha scaling below):\n * q_arith * ( ( (-1/2) * (q_arith - 3) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c ) +\n * (q_arith - 1)*( α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m) + w_4_omega) ) = 0\n *\n * This formula results in several cases depending on q_arith:\n * 1. q_arith == 0: Arithmetic gate is completely disabled\n *\n * 2. q_arith == 1: Everything in the minigate on the right is disabled. The equation is just a standard plonk equation\n * with extra wires: q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c = 0\n *\n * 3. q_arith == 2: The (w_1 + w_4 - ...) term is disabled. THe equation is:\n * (1/2) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + w_4_omega = 0\n * It allows defining w_4 at next index (w_4_omega) in terms of current wire values\n *\n * 4. q_arith == 3: The product of w_1 and w_2 is disabled, but a mini addition gate is enabled. α allows us to split\n * the equation into two:\n *\n * q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + 2 * w_4_omega = 0\n * and\n * w_1 + w_4 - w_1_omega + q_m = 0 (we are reusing q_m here)\n *\n * 5. q_arith > 3: The product of w_1 and w_2 is scaled by (q_arith - 3), while the w_4_omega term is scaled by (q_arith - 1).\n * The equation can be split into two:\n *\n * (q_arith - 3)* q_m * w_1 * w_ 2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + (q_arith - 1) * w_4_omega = 0\n * and\n * w_1 + w_4 - w_1_omega + q_m = 0\n *\n * The problem that q_m is used both in both equations can be dealt with by appropriately changing selector values at\n * the next gate. Then we can treat (q_arith - 1) as a simulated q_6 selector and scale q_m to handle (q_arith - 3) at\n * product.\n */\n\n let w1q1 := mulmod(mload(W1_EVAL_LOC), mload(Q1_EVAL_LOC), p)\n let w2q2 := mulmod(mload(W2_EVAL_LOC), mload(Q2_EVAL_LOC), p)\n let w3q3 := mulmod(mload(W3_EVAL_LOC), mload(Q3_EVAL_LOC), p)\n let w4q3 := mulmod(mload(W4_EVAL_LOC), mload(Q4_EVAL_LOC), p)\n\n // @todo - Add a explicit test that hits QARITH == 3\n // w1w2qm := (w_1 . w_2 . q_m . (QARITH_EVAL_LOC - 3)) / 2\n let w1w2qm :=\n mulmod(\n mulmod(\n mulmod(mulmod(mload(W1_EVAL_LOC), mload(W2_EVAL_LOC), p), mload(QM_EVAL_LOC), p),\n addmod(mload(QARITH_EVAL_LOC), sub(p, 3), p),\n p\n ),\n NEGATIVE_INVERSE_OF_2_MODULO_P,\n p\n )\n\n // (w_1 . w_2 . q_m . (q_arith - 3)) / -2) + (w_1 . q_1) + (w_2 . q_2) + (w_3 . q_3) + (w_4 . q_4) + q_c\n let identity :=\n addmod(\n mload(QC_EVAL_LOC), addmod(w4q3, addmod(w3q3, addmod(w2q2, addmod(w1q1, w1w2qm, p), p), p), p), p\n )\n\n // if q_arith == 3 we evaluate an additional mini addition gate (on top of the regular one), where:\n // w_1 + w_4 - w_1_omega + q_m = 0\n // we use this gate to save an addition gate when adding or subtracting non-native field elements\n // α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m)\n let extra_small_addition_gate_identity :=\n mulmod(\n mload(C_ALPHA_LOC),\n mulmod(\n addmod(mload(QARITH_EVAL_LOC), sub(p, 2), p),\n addmod(\n mload(QM_EVAL_LOC),\n addmod(\n sub(p, mload(W1_OMEGA_EVAL_LOC)), addmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p), p\n ),\n p\n ),\n p\n ),\n p\n )\n\n // if q_arith == 2 OR q_arith == 3 we add the 4th wire of the NEXT gate into the arithmetic identity\n // N.B. if q_arith > 2, this wire value will be scaled by (q_arith - 1) relative to the other gate wires!\n // alpha_base * q_arith * (identity + (q_arith - 1) * (w_4_omega + extra_small_addition_gate_identity))\n mstore(\n ARITHMETIC_IDENTITY,\n mulmod(\n mload(C_ALPHA_BASE_LOC),\n mulmod(\n mload(QARITH_EVAL_LOC),\n addmod(\n identity,\n mulmod(\n addmod(mload(QARITH_EVAL_LOC), sub(p, 1), p),\n addmod(mload(W4_OMEGA_EVAL_LOC), extra_small_addition_gate_identity, p),\n p\n ),\n p\n ),\n p\n ),\n p\n )\n )\n\n // update alpha\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_SQR_LOC), p))\n }\n\n /**\n * COMPUTE GENPERMSORT WIDGET EVALUATION\n */\n {\n /**\n * D1 = (w2 - w1)\n * D2 = (w3 - w2)\n * D3 = (w4 - w3)\n * D4 = (w1_omega - w4)\n *\n * α_a = alpha_base\n * α_b = alpha_base * α\n * α_c = alpha_base * α^2\n * α_d = alpha_base * α^3\n *\n * range_accumulator = (\n * D1(D1 - 1)(D1 - 2)(D1 - 3).α_a +\n * D2(D2 - 1)(D2 - 2)(D2 - 3).α_b +\n * D3(D3 - 1)(D3 - 2)(D3 - 3).α_c +\n * D4(D4 - 1)(D4 - 2)(D4 - 3).α_d +\n * ) . q_sort\n */\n let minus_two := sub(p, 2)\n let minus_three := sub(p, 3)\n let d1 := addmod(mload(W2_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p)\n let d2 := addmod(mload(W3_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p)\n let d3 := addmod(mload(W4_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p)\n let d4 := addmod(mload(W1_OMEGA_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p)\n\n let range_accumulator :=\n mulmod(\n mulmod(\n mulmod(addmod(mulmod(d1, d1, p), sub(p, d1), p), addmod(d1, minus_two, p), p),\n addmod(d1, minus_three, p),\n p\n ),\n mload(C_ALPHA_BASE_LOC),\n p\n )\n range_accumulator :=\n addmod(\n range_accumulator,\n mulmod(\n mulmod(\n mulmod(addmod(mulmod(d2, d2, p), sub(p, d2), p), addmod(d2, minus_two, p), p),\n addmod(d2, minus_three, p),\n p\n ),\n mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p),\n p\n ),\n p\n )\n range_accumulator :=\n addmod(\n range_accumulator,\n mulmod(\n mulmod(\n mulmod(addmod(mulmod(d3, d3, p), sub(p, d3), p), addmod(d3, minus_two, p), p),\n addmod(d3, minus_three, p),\n p\n ),\n mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_SQR_LOC), p),\n p\n ),\n p\n )\n range_accumulator :=\n addmod(\n range_accumulator,\n mulmod(\n mulmod(\n mulmod(addmod(mulmod(d4, d4, p), sub(p, d4), p), addmod(d4, minus_two, p), p),\n addmod(d4, minus_three, p),\n p\n ),\n mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p),\n p\n ),\n p\n )\n range_accumulator := mulmod(range_accumulator, mload(QSORT_EVAL_LOC), p)\n\n mstore(SORT_IDENTITY, range_accumulator)\n\n // update alpha\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_QUAD_LOC), p))\n }\n\n /**\n * COMPUTE ELLIPTIC WIDGET EVALUATION\n */\n {\n /**\n * endo_term = (-x_2) * x_1 * (x_3 * 2 + x_1) * q_beta\n * endo_sqr_term = x_2^2\n * endo_sqr_term *= (x_3 - x_1)\n * endo_sqr_term *= q_beta^2\n * leftovers = x_2^2\n * leftovers *= x_2\n * leftovers += x_1^2 * (x_3 + x_1) @follow-up Invalid comment in BB widget\n * leftovers -= (y_2^2 + y_1^2)\n * sign_term = y_2 * y_1\n * sign_term += sign_term\n * sign_term *= q_sign\n */\n // q_elliptic * (x3 + x2 + x1)(x2 - x1)(x2 - x1) - y2^2 - y1^2 + 2(y2y1)*q_sign = 0\n let x_diff := addmod(mload(X2_EVAL_LOC), sub(p, mload(X1_EVAL_LOC)), p)\n let y2_sqr := mulmod(mload(Y2_EVAL_LOC), mload(Y2_EVAL_LOC), p)\n let y1_sqr := mulmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p)\n let y1y2 := mulmod(mulmod(mload(Y1_EVAL_LOC), mload(Y2_EVAL_LOC), p), mload(QSIGN_LOC), p)\n\n let x_add_identity :=\n addmod(\n mulmod(\n addmod(mload(X3_EVAL_LOC), addmod(mload(X2_EVAL_LOC), mload(X1_EVAL_LOC), p), p),\n mulmod(x_diff, x_diff, p),\n p\n ),\n addmod(\n sub(\n p,\n addmod(y2_sqr, y1_sqr, p)\n ),\n addmod(y1y2, y1y2, p),\n p\n ),\n p\n )\n x_add_identity :=\n mulmod(\n mulmod(\n x_add_identity,\n addmod(\n 1,\n sub(p, mload(QM_EVAL_LOC)),\n p\n ),\n p\n ),\n mload(C_ALPHA_BASE_LOC),\n p\n )\n\n // q_elliptic * (x3 + x2 + x1)(x2 - x1)(x2 - x1) - y2^2 - y1^2 + 2(y2y1)*q_sign = 0\n let y1_plus_y3 := addmod(\n mload(Y1_EVAL_LOC),\n mload(Y3_EVAL_LOC),\n p\n )\n let y_diff := addmod(mulmod(mload(Y2_EVAL_LOC), mload(QSIGN_LOC), p), sub(p, mload(Y1_EVAL_LOC)), p)\n let y_add_identity :=\n addmod(\n mulmod(y1_plus_y3, x_diff, p),\n mulmod(addmod(mload(X3_EVAL_LOC), sub(p, mload(X1_EVAL_LOC)), p), y_diff, p),\n p\n )\n y_add_identity :=\n mulmod(\n mulmod(y_add_identity, addmod(1, sub(p, mload(QM_EVAL_LOC)), p), p),\n mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p),\n p\n )\n\n // ELLIPTIC_IDENTITY = (x_identity + y_identity) * Q_ELLIPTIC_EVAL\n mstore(\n ELLIPTIC_IDENTITY, mulmod(addmod(x_add_identity, y_add_identity, p), mload(QELLIPTIC_EVAL_LOC), p)\n )\n }\n {\n /**\n * x_pow_4 = (y_1_sqr - curve_b) * x_1;\n * y_1_sqr_mul_4 = y_1_sqr + y_1_sqr;\n * y_1_sqr_mul_4 += y_1_sqr_mul_4;\n * x_1_pow_4_mul_9 = x_pow_4;\n * x_1_pow_4_mul_9 += x_1_pow_4_mul_9;\n * x_1_pow_4_mul_9 += x_1_pow_4_mul_9;\n * x_1_pow_4_mul_9 += x_1_pow_4_mul_9;\n * x_1_pow_4_mul_9 += x_pow_4;\n * x_1_sqr_mul_3 = x_1_sqr + x_1_sqr + x_1_sqr;\n * x_double_identity = (x_3 + x_1 + x_1) * y_1_sqr_mul_4 - x_1_pow_4_mul_9;\n * y_double_identity = x_1_sqr_mul_3 * (x_1 - x_3) - (y_1 + y_1) * (y_1 + y_3);\n */\n // (x3 + x1 + x1) (4y1*y1) - 9 * x1 * x1 * x1 * x1 = 0\n let x1_sqr := mulmod(mload(X1_EVAL_LOC), mload(X1_EVAL_LOC), p)\n let y1_sqr := mulmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p)\n let x_pow_4 := mulmod(addmod(y1_sqr, GRUMPKIN_CURVE_B_PARAMETER_NEGATED, p), mload(X1_EVAL_LOC), p)\n let y1_sqr_mul_4 := mulmod(y1_sqr, 4, p)\n let x1_pow_4_mul_9 := mulmod(x_pow_4, 9, p)\n let x1_sqr_mul_3 := mulmod(x1_sqr, 3, p)\n let x_double_identity :=\n addmod(\n mulmod(\n addmod(mload(X3_EVAL_LOC), addmod(mload(X1_EVAL_LOC), mload(X1_EVAL_LOC), p), p),\n y1_sqr_mul_4,\n p\n ),\n sub(p, x1_pow_4_mul_9),\n p\n )\n // (y1 + y1) (2y1) - (3 * x1 * x1)(x1 - x3) = 0\n let y_double_identity :=\n addmod(\n mulmod(x1_sqr_mul_3, addmod(mload(X1_EVAL_LOC), sub(p, mload(X3_EVAL_LOC)), p), p),\n sub(\n p,\n mulmod(\n addmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p),\n addmod(mload(Y1_EVAL_LOC), mload(Y3_EVAL_LOC), p),\n p\n )\n ),\n p\n )\n x_double_identity := mulmod(x_double_identity, mload(C_ALPHA_BASE_LOC), p)\n y_double_identity :=\n mulmod(y_double_identity, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p), p)\n x_double_identity := mulmod(x_double_identity, mload(QM_EVAL_LOC), p)\n y_double_identity := mulmod(y_double_identity, mload(QM_EVAL_LOC), p)\n // ELLIPTIC_IDENTITY += (x_double_identity + y_double_identity) * Q_DOUBLE_EVAL\n mstore(\n ELLIPTIC_IDENTITY,\n addmod(\n mload(ELLIPTIC_IDENTITY),\n mulmod(addmod(x_double_identity, y_double_identity, p), mload(QELLIPTIC_EVAL_LOC), p),\n p\n )\n )\n\n // update alpha\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_QUAD_LOC), p))\n }\n\n /**\n * COMPUTE AUXILIARY WIDGET EVALUATION\n */\n {\n {\n /**\n * Non native field arithmetic gate 2\n * _ _\n * / _ _ _ 14 \\\n * q_2 . q_4 | (w_1 . w_2) + (w_1 . w_2) + (w_1 . w_4 + w_2 . w_3 - w_3) . 2 - w_3 - w_4 |\n * \\_ _/\n *\n * limb_subproduct = w_1 . w_2_omega + w_1_omega . w_2\n * non_native_field_gate_2 = w_1 * w_4 + w_4 * w_3 - w_3_omega\n * non_native_field_gate_2 = non_native_field_gate_2 * limb_size\n * non_native_field_gate_2 -= w_4_omega\n * non_native_field_gate_2 += limb_subproduct\n * non_native_field_gate_2 *= q_4\n * limb_subproduct *= limb_size\n * limb_subproduct += w_1_omega * w_2_omega\n * non_native_field_gate_1 = (limb_subproduct + w_3 + w_4) * q_3\n * non_native_field_gate_3 = (limb_subproduct + w_4 - (w_3_omega + w_4_omega)) * q_m\n * non_native_field_identity = (non_native_field_gate_1 + non_native_field_gate_2 + non_native_field_gate_3) * q_2\n */\n\n let limb_subproduct :=\n addmod(\n mulmod(mload(W1_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p),\n mulmod(mload(W1_OMEGA_EVAL_LOC), mload(W2_EVAL_LOC), p),\n p\n )\n\n let non_native_field_gate_2 :=\n addmod(\n addmod(\n mulmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p),\n mulmod(mload(W2_EVAL_LOC), mload(W3_EVAL_LOC), p),\n p\n ),\n sub(p, mload(W3_OMEGA_EVAL_LOC)),\n p\n )\n non_native_field_gate_2 := mulmod(non_native_field_gate_2, LIMB_SIZE, p)\n non_native_field_gate_2 := addmod(non_native_field_gate_2, sub(p, mload(W4_OMEGA_EVAL_LOC)), p)\n non_native_field_gate_2 := addmod(non_native_field_gate_2, limb_subproduct, p)\n non_native_field_gate_2 := mulmod(non_native_field_gate_2, mload(Q4_EVAL_LOC), p)\n limb_subproduct := mulmod(limb_subproduct, LIMB_SIZE, p)\n limb_subproduct :=\n addmod(limb_subproduct, mulmod(mload(W1_OMEGA_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), p)\n let non_native_field_gate_1 :=\n mulmod(\n addmod(limb_subproduct, sub(p, addmod(mload(W3_EVAL_LOC), mload(W4_EVAL_LOC), p)), p),\n mload(Q3_EVAL_LOC),\n p\n )\n let non_native_field_gate_3 :=\n mulmod(\n addmod(\n addmod(limb_subproduct, mload(W4_EVAL_LOC), p),\n sub(p, addmod(mload(W3_OMEGA_EVAL_LOC), mload(W4_OMEGA_EVAL_LOC), p)),\n p\n ),\n mload(QM_EVAL_LOC),\n p\n )\n let non_native_field_identity :=\n mulmod(\n addmod(addmod(non_native_field_gate_1, non_native_field_gate_2, p), non_native_field_gate_3, p),\n mload(Q2_EVAL_LOC),\n p\n )\n\n mstore(AUX_NON_NATIVE_FIELD_EVALUATION, non_native_field_identity)\n }\n\n {\n /**\n * limb_accumulator_1 = w_2_omega;\n * limb_accumulator_1 *= SUBLIMB_SHIFT;\n * limb_accumulator_1 += w_1_omega;\n * limb_accumulator_1 *= SUBLIMB_SHIFT;\n * limb_accumulator_1 += w_3;\n * limb_accumulator_1 *= SUBLIMB_SHIFT;\n * limb_accumulator_1 += w_2;\n * limb_accumulator_1 *= SUBLIMB_SHIFT;\n * limb_accumulator_1 += w_1;\n * limb_accumulator_1 -= w_4;\n * limb_accumulator_1 *= q_4;\n */\n let limb_accumulator_1 := mulmod(mload(W2_OMEGA_EVAL_LOC), SUBLIMB_SHIFT, p)\n limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_OMEGA_EVAL_LOC), p)\n limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)\n limb_accumulator_1 := addmod(limb_accumulator_1, mload(W3_EVAL_LOC), p)\n limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)\n limb_accumulator_1 := addmod(limb_accumulator_1, mload(W2_EVAL_LOC), p)\n limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)\n limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_EVAL_LOC), p)\n limb_accumulator_1 := addmod(limb_accumulator_1, sub(p, mload(W4_EVAL_LOC)), p)\n limb_accumulator_1 := mulmod(limb_accumulator_1, mload(Q4_EVAL_LOC), p)\n\n /**\n * limb_accumulator_2 = w_3_omega;\n * limb_accumulator_2 *= SUBLIMB_SHIFT;\n * limb_accumulator_2 += w_2_omega;\n * limb_accumulator_2 *= SUBLIMB_SHIFT;\n * limb_accumulator_2 += w_1_omega;\n * limb_accumulator_2 *= SUBLIMB_SHIFT;\n * limb_accumulator_2 += w_4;\n * limb_accumulator_2 *= SUBLIMB_SHIFT;\n * limb_accumulator_2 += w_3;\n * limb_accumulator_2 -= w_4_omega;\n * limb_accumulator_2 *= q_m;\n */\n let limb_accumulator_2 := mulmod(mload(W3_OMEGA_EVAL_LOC), SUBLIMB_SHIFT, p)\n limb_accumulator_2 := addmod(limb_accumulator_2, mload(W2_OMEGA_EVAL_LOC), p)\n limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)\n limb_accumulator_2 := addmod(limb_accumulator_2, mload(W1_OMEGA_EVAL_LOC), p)\n limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)\n limb_accumulator_2 := addmod(limb_accumulator_2, mload(W4_EVAL_LOC), p)\n limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)\n limb_accumulator_2 := addmod(limb_accumulator_2, mload(W3_EVAL_LOC), p)\n limb_accumulator_2 := addmod(limb_accumulator_2, sub(p, mload(W4_OMEGA_EVAL_LOC)), p)\n limb_accumulator_2 := mulmod(limb_accumulator_2, mload(QM_EVAL_LOC), p)\n\n mstore(\n AUX_LIMB_ACCUMULATOR_EVALUATION,\n mulmod(addmod(limb_accumulator_1, limb_accumulator_2, p), mload(Q3_EVAL_LOC), p)\n )\n }\n\n {\n /**\n * memory_record_check = w_3;\n * memory_record_check *= eta;\n * memory_record_check += w_2;\n * memory_record_check *= eta;\n * memory_record_check += w_1;\n * memory_record_check *= eta;\n * memory_record_check += q_c;\n *\n * partial_record_check = memory_record_check;\n *\n * memory_record_check -= w_4;\n */\n\n let memory_record_check := mulmod(mload(W3_EVAL_LOC), mload(C_ETA_LOC), p)\n memory_record_check := addmod(memory_record_check, mload(W2_EVAL_LOC), p)\n memory_record_check := mulmod(memory_record_check, mload(C_ETA_LOC), p)\n memory_record_check := addmod(memory_record_check, mload(W1_EVAL_LOC), p)\n memory_record_check := mulmod(memory_record_check, mload(C_ETA_LOC), p)\n memory_record_check := addmod(memory_record_check, mload(QC_EVAL_LOC), p)\n\n let partial_record_check := memory_record_check\n memory_record_check := addmod(memory_record_check, sub(p, mload(W4_EVAL_LOC)), p)\n\n mstore(AUX_MEMORY_EVALUATION, memory_record_check)\n\n // index_delta = w_1_omega - w_1\n let index_delta := addmod(mload(W1_OMEGA_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p)\n // record_delta = w_4_omega - w_4\n let record_delta := addmod(mload(W4_OMEGA_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p)\n // index_is_monotonically_increasing = index_delta * (index_delta - 1)\n let index_is_monotonically_increasing := mulmod(index_delta, addmod(index_delta, sub(p, 1), p), p)\n\n // adjacent_values_match_if_adjacent_indices_match = record_delta * (1 - index_delta)\n let adjacent_values_match_if_adjacent_indices_match :=\n mulmod(record_delta, addmod(1, sub(p, index_delta), p), p)\n\n // AUX_ROM_CONSISTENCY_EVALUATION = ((adjacent_values_match_if_adjacent_indices_match * alpha) + index_is_monotonically_increasing) * alpha + partial_record_check\n mstore(\n AUX_ROM_CONSISTENCY_EVALUATION,\n addmod(\n mulmod(\n addmod(\n mulmod(adjacent_values_match_if_adjacent_indices_match, mload(C_ALPHA_LOC), p),\n index_is_monotonically_increasing,\n p\n ),\n mload(C_ALPHA_LOC),\n p\n ),\n memory_record_check,\n p\n )\n )\n\n {\n /**\n * next_gate_access_type = w_3_omega;\n * next_gate_access_type *= eta;\n * next_gate_access_type += w_2_omega;\n * next_gate_access_type *= eta;\n * next_gate_access_type += w_1_omega;\n * next_gate_access_type *= eta;\n * next_gate_access_type = w_4_omega - next_gate_access_type;\n */\n let next_gate_access_type := mulmod(mload(W3_OMEGA_EVAL_LOC), mload(C_ETA_LOC), p)\n next_gate_access_type := addmod(next_gate_access_type, mload(W2_OMEGA_EVAL_LOC), p)\n next_gate_access_type := mulmod(next_gate_access_type, mload(C_ETA_LOC), p)\n next_gate_access_type := addmod(next_gate_access_type, mload(W1_OMEGA_EVAL_LOC), p)\n next_gate_access_type := mulmod(next_gate_access_type, mload(C_ETA_LOC), p)\n next_gate_access_type := addmod(mload(W4_OMEGA_EVAL_LOC), sub(p, next_gate_access_type), p)\n\n // value_delta = w_3_omega - w_3\n let value_delta := addmod(mload(W3_OMEGA_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p)\n // adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = (1 - index_delta) * value_delta * (1 - next_gate_access_type);\n\n let adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation :=\n mulmod(\n addmod(1, sub(p, index_delta), p),\n mulmod(value_delta, addmod(1, sub(p, next_gate_access_type), p), p),\n p\n )\n\n // AUX_RAM_CONSISTENCY_EVALUATION\n\n /**\n * access_type = w_4 - partial_record_check\n * access_check = access_type^2 - access_type\n * next_gate_access_type_is_boolean = next_gate_access_type^2 - next_gate_access_type\n * RAM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation;\n * RAM_consistency_check_identity *= alpha;\n * RAM_consistency_check_identity += index_is_monotonically_increasing;\n * RAM_consistency_check_identity *= alpha;\n * RAM_consistency_check_identity += next_gate_access_type_is_boolean;\n * RAM_consistency_check_identity *= alpha;\n * RAM_consistency_check_identity += access_check;\n */\n\n let access_type := addmod(mload(W4_EVAL_LOC), sub(p, partial_record_check), p)\n let access_check := mulmod(access_type, addmod(access_type, sub(p, 1), p), p)\n let next_gate_access_type_is_boolean :=\n mulmod(next_gate_access_type, addmod(next_gate_access_type, sub(p, 1), p), p)\n let RAM_cci :=\n mulmod(\n adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation,\n mload(C_ALPHA_LOC),\n p\n )\n RAM_cci := addmod(RAM_cci, index_is_monotonically_increasing, p)\n RAM_cci := mulmod(RAM_cci, mload(C_ALPHA_LOC), p)\n RAM_cci := addmod(RAM_cci, next_gate_access_type_is_boolean, p)\n RAM_cci := mulmod(RAM_cci, mload(C_ALPHA_LOC), p)\n RAM_cci := addmod(RAM_cci, access_check, p)\n\n mstore(AUX_RAM_CONSISTENCY_EVALUATION, RAM_cci)\n }\n\n {\n // timestamp_delta = w_2_omega - w_2\n let timestamp_delta := addmod(mload(W2_OMEGA_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p)\n\n // RAM_timestamp_check_identity = (1 - index_delta) * timestamp_delta - w_3\n let RAM_timestamp_check_identity :=\n addmod(\n mulmod(timestamp_delta, addmod(1, sub(p, index_delta), p), p), sub(p, mload(W3_EVAL_LOC)), p\n )\n\n /**\n * memory_identity = ROM_consistency_check_identity * q_2;\n * memory_identity += RAM_timestamp_check_identity * q_4;\n * memory_identity += memory_record_check * q_m;\n * memory_identity *= q_1;\n * memory_identity += (RAM_consistency_check_identity * q_arith);\n *\n * auxiliary_identity = memory_identity + non_native_field_identity + limb_accumulator_identity;\n * auxiliary_identity *= q_aux;\n * auxiliary_identity *= alpha_base;\n */\n let memory_identity := mulmod(mload(AUX_ROM_CONSISTENCY_EVALUATION), mload(Q2_EVAL_LOC), p)\n memory_identity :=\n addmod(memory_identity, mulmod(RAM_timestamp_check_identity, mload(Q4_EVAL_LOC), p), p)\n memory_identity :=\n addmod(memory_identity, mulmod(mload(AUX_MEMORY_EVALUATION), mload(QM_EVAL_LOC), p), p)\n memory_identity := mulmod(memory_identity, mload(Q1_EVAL_LOC), p)\n memory_identity :=\n addmod(\n memory_identity, mulmod(mload(AUX_RAM_CONSISTENCY_EVALUATION), mload(QARITH_EVAL_LOC), p), p\n )\n\n let auxiliary_identity := addmod(memory_identity, mload(AUX_NON_NATIVE_FIELD_EVALUATION), p)\n auxiliary_identity := addmod(auxiliary_identity, mload(AUX_LIMB_ACCUMULATOR_EVALUATION), p)\n auxiliary_identity := mulmod(auxiliary_identity, mload(QAUX_EVAL_LOC), p)\n auxiliary_identity := mulmod(auxiliary_identity, mload(C_ALPHA_BASE_LOC), p)\n\n mstore(AUX_IDENTITY, auxiliary_identity)\n\n // update alpha\n mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p))\n }\n }\n }\n\n {\n /**\n * quotient = ARITHMETIC_IDENTITY\n * quotient += PERMUTATION_IDENTITY\n * quotient += PLOOKUP_IDENTITY\n * quotient += SORT_IDENTITY\n * quotient += ELLIPTIC_IDENTITY\n * quotient += AUX_IDENTITY\n * quotient *= ZERO_POLY_INVERSE\n */\n mstore(\n QUOTIENT_EVAL_LOC,\n mulmod(\n addmod(\n addmod(\n addmod(\n addmod(\n addmod(mload(PERMUTATION_IDENTITY), mload(PLOOKUP_IDENTITY), p),\n mload(ARITHMETIC_IDENTITY),\n p\n ),\n mload(SORT_IDENTITY),\n p\n ),\n mload(ELLIPTIC_IDENTITY),\n p\n ),\n mload(AUX_IDENTITY),\n p\n ),\n mload(ZERO_POLY_INVERSE_LOC),\n p\n )\n )\n }\n\n /**\n * GENERATE NU AND SEPARATOR CHALLENGES\n */\n {\n let current_challenge := mload(C_CURRENT_LOC)\n // get a calldata pointer that points to the start of the data we want to copy\n let calldata_ptr := add(calldataload(0x04), 0x24)\n\n calldata_ptr := add(calldata_ptr, NU_CALLDATA_SKIP_LENGTH)\n\n mstore(NU_CHALLENGE_INPUT_LOC_A, current_challenge)\n mstore(NU_CHALLENGE_INPUT_LOC_B, mload(QUOTIENT_EVAL_LOC))\n calldatacopy(NU_CHALLENGE_INPUT_LOC_C, calldata_ptr, NU_INPUT_LENGTH)\n\n // hash length = (0x20 + num field elements), we include the previous challenge in the hash\n let challenge := keccak256(NU_CHALLENGE_INPUT_LOC_A, add(NU_INPUT_LENGTH, 0x40))\n\n mstore(C_V0_LOC, mod(challenge, p))\n // We need THIRTY-ONE independent nu challenges!\n mstore(0x00, challenge)\n mstore8(0x20, 0x01)\n mstore(C_V1_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x02)\n mstore(C_V2_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x03)\n mstore(C_V3_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x04)\n mstore(C_V4_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x05)\n mstore(C_V5_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x06)\n mstore(C_V6_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x07)\n mstore(C_V7_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x08)\n mstore(C_V8_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x09)\n mstore(C_V9_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x0a)\n mstore(C_V10_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x0b)\n mstore(C_V11_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x0c)\n mstore(C_V12_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x0d)\n mstore(C_V13_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x0e)\n mstore(C_V14_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x0f)\n mstore(C_V15_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x10)\n mstore(C_V16_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x11)\n mstore(C_V17_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x12)\n mstore(C_V18_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x13)\n mstore(C_V19_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x14)\n mstore(C_V20_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x15)\n mstore(C_V21_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x16)\n mstore(C_V22_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x17)\n mstore(C_V23_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x18)\n mstore(C_V24_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x19)\n mstore(C_V25_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x1a)\n mstore(C_V26_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x1b)\n mstore(C_V27_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x1c)\n mstore(C_V28_LOC, mod(keccak256(0x00, 0x21), p))\n mstore8(0x20, 0x1d)\n mstore(C_V29_LOC, mod(keccak256(0x00, 0x21), p))\n\n // @follow-up - Why are both v29 and v30 using appending 0x1d to the prior challenge and hashing, should it not change?\n mstore8(0x20, 0x1d)\n challenge := keccak256(0x00, 0x21)\n mstore(C_V30_LOC, mod(challenge, p))\n\n // separator\n mstore(0x00, challenge)\n mstore(0x20, mload(PI_Z_Y_LOC))\n mstore(0x40, mload(PI_Z_X_LOC))\n mstore(0x60, mload(PI_Z_OMEGA_Y_LOC))\n mstore(0x80, mload(PI_Z_OMEGA_X_LOC))\n\n mstore(C_U_LOC, mod(keccak256(0x00, 0xa0), p))\n }\n\n let success := 0\n // VALIDATE T1\n {\n let x := mload(T1_X_LOC)\n let y := mload(T1_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(ACCUMULATOR_X_LOC, x)\n mstore(add(ACCUMULATOR_X_LOC, 0x20), y)\n }\n // VALIDATE T2\n {\n let x := mload(T2_X_LOC) // 0x1400\n let y := mload(T2_Y_LOC) // 0x1420\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mload(ZETA_POW_N_LOC))\n // accumulator_2 = [T2].zeta^n\n success := staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)\n // accumulator = [T1] + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE T3\n {\n let x := mload(T3_X_LOC)\n let y := mload(T3_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(mload(ZETA_POW_N_LOC), mload(ZETA_POW_N_LOC), p))\n // accumulator_2 = [T3].zeta^{2n}\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE T4\n {\n let x := mload(T4_X_LOC)\n let y := mload(T4_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(mulmod(mload(ZETA_POW_N_LOC), mload(ZETA_POW_N_LOC), p), mload(ZETA_POW_N_LOC), p))\n // accumulator_2 = [T4].zeta^{3n}\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE W1\n {\n let x := mload(W1_X_LOC)\n let y := mload(W1_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V0_LOC), p))\n // accumulator_2 = v0.(u + 1).[W1]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE W2\n {\n let x := mload(W2_X_LOC)\n let y := mload(W2_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V1_LOC), p))\n // accumulator_2 = v1.(u + 1).[W2]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE W3\n {\n let x := mload(W3_X_LOC)\n let y := mload(W3_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V2_LOC), p))\n // accumulator_2 = v2.(u + 1).[W3]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE W4\n {\n let x := mload(W4_X_LOC)\n let y := mload(W4_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V3_LOC), p))\n // accumulator_2 = v3.(u + 1).[W4]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE S\n {\n let x := mload(S_X_LOC)\n let y := mload(S_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V4_LOC), p))\n // accumulator_2 = v4.(u + 1).[S]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE Z\n {\n let x := mload(Z_X_LOC)\n let y := mload(Z_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V5_LOC), p))\n // accumulator_2 = v5.(u + 1).[Z]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE Z_LOOKUP\n {\n let x := mload(Z_LOOKUP_X_LOC)\n let y := mload(Z_LOOKUP_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V6_LOC), p))\n // accumulator_2 = v6.(u + 1).[Z_LOOKUP]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE Q1\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(Q1_X_LOC))\n mstore(0x20, mload(Q1_Y_LOC))\n mstore(0x40, mload(C_V7_LOC))\n // accumulator_2 = v7.[Q1]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE Q2\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(Q2_X_LOC))\n mstore(0x20, mload(Q2_Y_LOC))\n mstore(0x40, mload(C_V8_LOC))\n // accumulator_2 = v8.[Q2]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE Q3\n \n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(Q3_X_LOC))\n mstore(0x20, mload(Q3_Y_LOC))\n mstore(0x40, mload(C_V9_LOC))\n // accumulator_2 = v9.[Q3]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE Q4\n \n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(Q4_X_LOC))\n mstore(0x20, mload(Q4_Y_LOC))\n mstore(0x40, mload(C_V10_LOC))\n // accumulator_2 = v10.[Q4]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE QM\n \n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(QM_X_LOC))\n mstore(0x20, mload(QM_Y_LOC))\n mstore(0x40, mload(C_V11_LOC))\n // accumulator_2 = v11.[Q;]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE QC\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(QC_X_LOC))\n mstore(0x20, mload(QC_Y_LOC))\n mstore(0x40, mload(C_V12_LOC))\n // accumulator_2 = v12.[QC]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE QARITH\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(QARITH_X_LOC))\n mstore(0x20, mload(QARITH_Y_LOC))\n mstore(0x40, mload(C_V13_LOC))\n // accumulator_2 = v13.[QARITH]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE QSORT\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(QSORT_X_LOC))\n mstore(0x20, mload(QSORT_Y_LOC))\n mstore(0x40, mload(C_V14_LOC))\n // accumulator_2 = v14.[QSORT]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE QELLIPTIC\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(QELLIPTIC_X_LOC))\n mstore(0x20, mload(QELLIPTIC_Y_LOC))\n mstore(0x40, mload(C_V15_LOC))\n // accumulator_2 = v15.[QELLIPTIC]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE QAUX\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(QAUX_X_LOC))\n mstore(0x20, mload(QAUX_Y_LOC))\n mstore(0x40, mload(C_V16_LOC))\n // accumulator_2 = v15.[Q_AUX]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE SIGMA1\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(SIGMA1_X_LOC))\n mstore(0x20, mload(SIGMA1_Y_LOC))\n mstore(0x40, mload(C_V17_LOC))\n // accumulator_2 = v17.[sigma1]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE SIGMA2\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(SIGMA2_X_LOC))\n mstore(0x20, mload(SIGMA2_Y_LOC))\n mstore(0x40, mload(C_V18_LOC))\n // accumulator_2 = v18.[sigma2]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE SIGMA3\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(SIGMA3_X_LOC))\n mstore(0x20, mload(SIGMA3_Y_LOC))\n mstore(0x40, mload(C_V19_LOC))\n // accumulator_2 = v19.[sigma3]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE SIGMA4\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(SIGMA4_X_LOC))\n mstore(0x20, mload(SIGMA4_Y_LOC))\n mstore(0x40, mload(C_V20_LOC))\n // accumulator_2 = v20.[sigma4]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE TABLE1\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(TABLE1_X_LOC))\n mstore(0x20, mload(TABLE1_Y_LOC))\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V21_LOC), p))\n // accumulator_2 = u.[table1]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE TABLE2\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(TABLE2_X_LOC))\n mstore(0x20, mload(TABLE2_Y_LOC))\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V22_LOC), p))\n // accumulator_2 = u.[table2]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE TABLE3\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(TABLE3_X_LOC))\n mstore(0x20, mload(TABLE3_Y_LOC))\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V23_LOC), p))\n // accumulator_2 = u.[table3]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE TABLE4\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(TABLE4_X_LOC))\n mstore(0x20, mload(TABLE4_Y_LOC))\n mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V24_LOC), p))\n // accumulator_2 = u.[table4]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE TABLE_TYPE\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(TABLE_TYPE_X_LOC))\n mstore(0x20, mload(TABLE_TYPE_Y_LOC))\n mstore(0x40, mload(C_V25_LOC))\n // accumulator_2 = v25.[TableType]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE ID1\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(ID1_X_LOC))\n mstore(0x20, mload(ID1_Y_LOC))\n mstore(0x40, mload(C_V26_LOC))\n // accumulator_2 = v26.[ID1]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE ID2\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(ID2_X_LOC))\n mstore(0x20, mload(ID2_Y_LOC))\n mstore(0x40, mload(C_V27_LOC))\n // accumulator_2 = v27.[ID2]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE ID3\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(ID3_X_LOC))\n mstore(0x20, mload(ID3_Y_LOC))\n mstore(0x40, mload(C_V28_LOC))\n // accumulator_2 = v28.[ID3]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // ACCUMULATE ID4\n\n // Verification key fields verified to be on curve at contract deployment\n mstore(0x00, mload(ID4_X_LOC))\n mstore(0x20, mload(ID4_Y_LOC))\n mstore(0x40, mload(C_V29_LOC))\n // accumulator_2 = v29.[ID4]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n /**\n * COMPUTE BATCH EVALUATION SCALAR MULTIPLIER\n */\n {\n /**\n * batch_evaluation = v0 * (w_1_omega * u + w_1_eval)\n * batch_evaluation += v1 * (w_2_omega * u + w_2_eval)\n * batch_evaluation += v2 * (w_3_omega * u + w_3_eval)\n * batch_evaluation += v3 * (w_4_omega * u + w_4_eval)\n * batch_evaluation += v4 * (s_omega_eval * u + s_eval)\n * batch_evaluation += v5 * (z_omega_eval * u + z_eval)\n * batch_evaluation += v6 * (z_lookup_omega_eval * u + z_lookup_eval)\n */\n let batch_evaluation :=\n mulmod(\n mload(C_V0_LOC),\n addmod(mulmod(mload(W1_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W1_EVAL_LOC), p),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V1_LOC),\n addmod(mulmod(mload(W2_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W2_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V2_LOC),\n addmod(mulmod(mload(W3_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W3_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V3_LOC),\n addmod(mulmod(mload(W4_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W4_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V4_LOC),\n addmod(mulmod(mload(S_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(S_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V5_LOC),\n addmod(mulmod(mload(Z_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(Z_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V6_LOC),\n addmod(mulmod(mload(Z_LOOKUP_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(Z_LOOKUP_EVAL_LOC), p),\n p\n ),\n p\n )\n\n /**\n * batch_evaluation += v7 * Q1_EVAL\n * batch_evaluation += v8 * Q2_EVAL\n * batch_evaluation += v9 * Q3_EVAL\n * batch_evaluation += v10 * Q4_EVAL\n * batch_evaluation += v11 * QM_EVAL\n * batch_evaluation += v12 * QC_EVAL\n * batch_evaluation += v13 * QARITH_EVAL\n * batch_evaluation += v14 * QSORT_EVAL_LOC\n * batch_evaluation += v15 * QELLIPTIC_EVAL_LOC\n * batch_evaluation += v16 * QAUX_EVAL_LOC\n * batch_evaluation += v17 * SIGMA1_EVAL_LOC\n * batch_evaluation += v18 * SIGMA2_EVAL_LOC\n * batch_evaluation += v19 * SIGMA3_EVAL_LOC\n * batch_evaluation += v20 * SIGMA4_EVAL_LOC\n */\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V7_LOC), mload(Q1_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V8_LOC), mload(Q2_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V9_LOC), mload(Q3_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V10_LOC), mload(Q4_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V11_LOC), mload(QM_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V12_LOC), mload(QC_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V13_LOC), mload(QARITH_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V14_LOC), mload(QSORT_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V15_LOC), mload(QELLIPTIC_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V16_LOC), mload(QAUX_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V17_LOC), mload(SIGMA1_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V18_LOC), mload(SIGMA2_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V19_LOC), mload(SIGMA3_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V20_LOC), mload(SIGMA4_EVAL_LOC), p), p)\n\n /**\n * batch_evaluation += v21 * (table1(zw) * u + table1(z))\n * batch_evaluation += v22 * (table2(zw) * u + table2(z))\n * batch_evaluation += v23 * (table3(zw) * u + table3(z))\n * batch_evaluation += v24 * (table4(zw) * u + table4(z))\n * batch_evaluation += v25 * table_type_eval\n * batch_evaluation += v26 * id1_eval\n * batch_evaluation += v27 * id2_eval\n * batch_evaluation += v28 * id3_eval\n * batch_evaluation += v29 * id4_eval\n * batch_evaluation += quotient_eval\n */\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V21_LOC),\n addmod(mulmod(mload(TABLE1_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE1_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V22_LOC),\n addmod(mulmod(mload(TABLE2_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE2_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V23_LOC),\n addmod(mulmod(mload(TABLE3_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE3_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation :=\n addmod(\n batch_evaluation,\n mulmod(\n mload(C_V24_LOC),\n addmod(mulmod(mload(TABLE4_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE4_EVAL_LOC), p),\n p\n ),\n p\n )\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V25_LOC), mload(TABLE_TYPE_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V26_LOC), mload(ID1_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V27_LOC), mload(ID2_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V28_LOC), mload(ID3_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V29_LOC), mload(ID4_EVAL_LOC), p), p)\n batch_evaluation := addmod(batch_evaluation, mload(QUOTIENT_EVAL_LOC), p)\n\n mstore(0x00, 0x01) // [1].x\n mstore(0x20, 0x02) // [1].y\n mstore(0x40, sub(p, batch_evaluation))\n // accumulator_2 = -[1].(batch_evaluation)\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n if iszero(success) {\n mstore(0x0, OPENING_COMMITMENT_FAILED_SELECTOR)\n revert(0x00, 0x04)\n }\n }\n\n /**\n * PERFORM PAIRING PREAMBLE\n */\n {\n let u := mload(C_U_LOC)\n let zeta := mload(C_ZETA_LOC)\n // VALIDATE PI_Z\n {\n let x := mload(PI_Z_X_LOC)\n let y := mload(PI_Z_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n // compute zeta.[PI_Z] and add into accumulator\n mstore(0x40, zeta)\n success := staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)\n // accumulator = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))\n\n // VALIDATE PI_Z_OMEGA\n {\n let x := mload(PI_Z_OMEGA_X_LOC)\n let y := mload(PI_Z_OMEGA_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n mstore(0x40, mulmod(mulmod(u, zeta, p), mload(OMEGA_LOC), p))\n // accumulator_2 = u.zeta.omega.[PI_Z_OMEGA]\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))\n // PAIRING_RHS = accumulator + accumulator_2\n success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, PAIRING_RHS_X_LOC, 0x40))\n\n mstore(0x00, mload(PI_Z_X_LOC))\n mstore(0x20, mload(PI_Z_Y_LOC))\n mstore(0x40, mload(PI_Z_OMEGA_X_LOC))\n mstore(0x60, mload(PI_Z_OMEGA_Y_LOC))\n mstore(0x80, u)\n success := and(success, staticcall(gas(), 7, 0x40, 0x60, 0x40, 0x40))\n // PAIRING_LHS = [PI_Z] + [PI_Z_OMEGA] * u\n success := and(success, staticcall(gas(), 6, 0x00, 0x80, PAIRING_LHS_X_LOC, 0x40))\n // negate lhs y-coordinate\n mstore(PAIRING_LHS_Y_LOC, sub(q, mload(PAIRING_LHS_Y_LOC)))\n\n if mload(CONTAINS_RECURSIVE_PROOF_LOC) {\n // VALIDATE RECURSIVE P1\n {\n let x := mload(RECURSIVE_P1_X_LOC)\n let y := mload(RECURSIVE_P1_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n\n // compute u.u.[recursive_p1] and write into 0x60\n mstore(0x40, mulmod(u, u, p))\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, 0x60, 0x40))\n // VALIDATE RECURSIVE P2\n {\n let x := mload(RECURSIVE_P2_X_LOC)\n let y := mload(RECURSIVE_P2_Y_LOC)\n let xx := mulmod(x, x, q)\n // validate on curve\n if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) {\n mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR)\n revert(0x00, 0x04)\n }\n mstore(0x00, x)\n mstore(0x20, y)\n }\n // compute u.u.[recursive_p2] and write into 0x00\n // 0x40 still contains u*u\n success := and(success, staticcall(gas(), 7, 0x00, 0x60, 0x00, 0x40))\n\n // compute u.u.[recursiveP1] + rhs and write into rhs\n mstore(0xa0, mload(PAIRING_RHS_X_LOC))\n mstore(0xc0, mload(PAIRING_RHS_Y_LOC))\n success := and(success, staticcall(gas(), 6, 0x60, 0x80, PAIRING_RHS_X_LOC, 0x40))\n\n // compute u.u.[recursiveP2] + lhs and write into lhs\n mstore(0x40, mload(PAIRING_LHS_X_LOC))\n mstore(0x60, mload(PAIRING_LHS_Y_LOC))\n success := and(success, staticcall(gas(), 6, 0x00, 0x80, PAIRING_LHS_X_LOC, 0x40))\n }\n\n if iszero(success) {\n mstore(0x0, PAIRING_PREAMBLE_FAILED_SELECTOR)\n revert(0x00, 0x04)\n }\n }\n\n /**\n * PERFORM PAIRING\n */\n {\n // rhs paired with [1]_2\n // lhs paired with [x]_2\n\n mstore(0x00, mload(PAIRING_RHS_X_LOC))\n mstore(0x20, mload(PAIRING_RHS_Y_LOC))\n mstore(0x40, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) // this is [1]_2\n mstore(0x60, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed)\n mstore(0x80, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b)\n mstore(0xa0, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa)\n\n mstore(0xc0, mload(PAIRING_LHS_X_LOC))\n mstore(0xe0, mload(PAIRING_LHS_Y_LOC))\n mstore(0x100, mload(G2X_X0_LOC))\n mstore(0x120, mload(G2X_X1_LOC))\n mstore(0x140, mload(G2X_Y0_LOC))\n mstore(0x160, mload(G2X_Y1_LOC))\n\n success := staticcall(gas(), 8, 0x00, 0x180, 0x00, 0x20)\n if iszero(and(success, mload(0x00))) {\n mstore(0x0, PAIRING_FAILED_SELECTOR)\n revert(0x00, 0x04)\n }\n }\n\n {\n mstore(0x00, 0x01)\n return(0x00, 0x20) // Proof succeeded!\n }\n }\n }\n}\n\ncontract UltraVerifier is BaseUltraVerifier {\n function getVerificationKeyHash() public pure override(BaseUltraVerifier) returns (bytes32) {\n return UltraVerificationKey.verificationKeyHash();\n }\n\n function loadVerificationKey(uint256 vk, uint256 _omegaInverseLoc) internal pure virtual override(BaseUltraVerifier) {\n UltraVerificationKey.loadVerificationKey(vk, _omegaInverseLoc);\n }\n}\n" + }, + "solady/src/utils/Base64.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library to encode strings in Base64.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol)\n/// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - .\nlibrary Base64 {\n /// @dev Encodes `data` using the base64 encoding described in RFC 4648.\n /// See: https://datatracker.ietf.org/doc/html/rfc4648\n /// @param fileSafe Whether to replace '+' with '-' and '/' with '_'.\n /// @param noPadding Whether to strip away the padding.\n function encode(bytes memory data, bool fileSafe, bool noPadding)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let dataLength := mload(data)\n\n if dataLength {\n // Multiply by 4/3 rounded up.\n // The `shl(2, ...)` is equivalent to multiplying by 4.\n let encodedLength := shl(2, div(add(dataLength, 2), 3))\n\n // Set `result` to point to the start of the free memory.\n result := mload(0x40)\n\n // Store the table into the scratch space.\n // Offsetted by -1 byte so that the `mload` will load the character.\n // We will rewrite the free memory pointer at `0x40` later with\n // the allocated size.\n // The magic constant 0x0670 will turn \"-_\" into \"+/\".\n mstore(0x1f, \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef\")\n mstore(0x3f, xor(\"ghijklmnopqrstuvwxyz0123456789-_\", mul(iszero(fileSafe), 0x0670)))\n\n // Skip the first slot, which stores the length.\n let ptr := add(result, 0x20)\n let end := add(ptr, encodedLength)\n\n let dataEnd := add(add(0x20, data), dataLength)\n let dataEndValue := mload(dataEnd) // Cache the value at the `dataEnd` slot.\n mstore(dataEnd, 0x00) // Zeroize the `dataEnd` slot to clear dirty bits.\n\n // Run over the input, 3 bytes at a time.\n for {} 1 {} {\n data := add(data, 3) // Advance 3 bytes.\n let input := mload(data)\n\n // Write 4 bytes. Optimized for fewer stack operations.\n mstore8(0, mload(and(shr(18, input), 0x3F)))\n mstore8(1, mload(and(shr(12, input), 0x3F)))\n mstore8(2, mload(and(shr(6, input), 0x3F)))\n mstore8(3, mload(and(input, 0x3F)))\n mstore(ptr, mload(0x00))\n\n ptr := add(ptr, 4) // Advance 4 bytes.\n if iszero(lt(ptr, end)) { break }\n }\n mstore(dataEnd, dataEndValue) // Restore the cached value at `dataEnd`.\n mstore(0x40, add(end, 0x20)) // Allocate the memory.\n // Equivalent to `o = [0, 2, 1][dataLength % 3]`.\n let o := div(2, mod(dataLength, 3))\n // Offset `ptr` and pad with '='. We can simply write over the end.\n mstore(sub(ptr, o), shl(240, 0x3d3d))\n // Set `o` to zero if there is padding.\n o := mul(iszero(iszero(noPadding)), o)\n mstore(sub(ptr, o), 0) // Zeroize the slot after the string.\n mstore(result, sub(encodedLength, o)) // Store the length.\n }\n }\n }\n\n /// @dev Encodes `data` using the base64 encoding described in RFC 4648.\n /// Equivalent to `encode(data, false, false)`.\n function encode(bytes memory data) internal pure returns (string memory result) {\n result = encode(data, false, false);\n }\n\n /// @dev Encodes `data` using the base64 encoding described in RFC 4648.\n /// Equivalent to `encode(data, fileSafe, false)`.\n function encode(bytes memory data, bool fileSafe)\n internal\n pure\n returns (string memory result)\n {\n result = encode(data, fileSafe, false);\n }\n\n /// @dev Decodes base64 encoded `data`.\n ///\n /// Supports:\n /// - RFC 4648 (both standard and file-safe mode).\n /// - RFC 3501 (63: ',').\n ///\n /// Does not support:\n /// - Line breaks.\n ///\n /// Note: For performance reasons,\n /// this function will NOT revert on invalid `data` inputs.\n /// Outputs for invalid inputs will simply be undefined behaviour.\n /// It is the user's responsibility to ensure that the `data`\n /// is a valid base64 encoded string.\n function decode(string memory data) internal pure returns (bytes memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n let dataLength := mload(data)\n\n if dataLength {\n let decodedLength := mul(shr(2, dataLength), 3)\n\n for {} 1 {} {\n // If padded.\n if iszero(and(dataLength, 3)) {\n let t := xor(mload(add(data, dataLength)), 0x3d3d)\n // forgefmt: disable-next-item\n decodedLength := sub(\n decodedLength,\n add(iszero(byte(30, t)), iszero(byte(31, t)))\n )\n break\n }\n // If non-padded.\n decodedLength := add(decodedLength, sub(and(dataLength, 3), 1))\n break\n }\n result := mload(0x40)\n\n // Write the length of the bytes.\n mstore(result, decodedLength)\n\n // Skip the first slot, which stores the length.\n let ptr := add(result, 0x20)\n let end := add(ptr, decodedLength)\n\n // Load the table into the scratch space.\n // Constants are optimized for smaller bytecode with zero gas overhead.\n // `m` also doubles as the mask of the upper 6 bits.\n let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc\n mstore(0x5b, m)\n mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064)\n mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4)\n\n for {} 1 {} {\n // Read 4 bytes.\n data := add(data, 4)\n let input := mload(data)\n\n // Write 3 bytes.\n // forgefmt: disable-next-item\n mstore(ptr, or(\n and(m, mload(byte(28, input))),\n shr(6, or(\n and(m, mload(byte(29, input))),\n shr(6, or(\n and(m, mload(byte(30, input))),\n shr(6, mload(byte(31, input)))\n ))\n ))\n ))\n ptr := add(ptr, 3)\n if iszero(lt(ptr, end)) { break }\n }\n mstore(0x40, add(end, 0x20)) // Allocate the memory.\n mstore(end, 0) // Zeroize the slot after the bytes.\n mstore(0x60, 0) // Restore the zero slot.\n }\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 100000000 + }, + "evmVersion": "paris", + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/packages/contracts/hardhat.config.ts b/packages/contracts/hardhat.config.ts index d393ab3..a62bfa0 100644 --- a/packages/contracts/hardhat.config.ts +++ b/packages/contracts/hardhat.config.ts @@ -1,4 +1,5 @@ import "@nomicfoundation/hardhat-toolbox"; +import "@nomicfoundation/hardhat-viem"; import "hardhat-deploy"; import "hardhat-plugin-noir"; import { HardhatUserConfig } from "hardhat/config"; @@ -19,6 +20,7 @@ const config: HardhatUserConfig = { version: "1.0.0-beta.0", bbVersion: "0.65.2", }, + defaultNetwork: "localhost", networks: { baseSepolia: { url: "https://sepolia.base.org", diff --git a/packages/contracts/package.json b/packages/contracts/package.json index d11a344..3e19e27 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -9,6 +9,7 @@ "test": "hardhat test --typecheck", "test:no-typecheck": "hardhat test", "deploy": "hardhat deploy-and-export --tags all", + "deploy:clean": "rm -rf deployments/localhost && pnpm run deploy", "prepublishOnly": "pnpm compile" }, "devDependencies": { @@ -18,6 +19,7 @@ "@nomicfoundation/hardhat-network-helpers": "^1.0.10", "@nomicfoundation/hardhat-toolbox": "^4.0.0", "@nomicfoundation/hardhat-verify": "^2.0.4", + "@nomicfoundation/hardhat-viem": "^2.0.5", "@openzeppelin/contracts": "5.1.0", "@typechain/ethers-v6": "^0.5.1", "@typechain/hardhat": "^9.1.0", @@ -39,11 +41,13 @@ "prettier": "^3.2.5", "prettier-plugin-organize-imports": "^3.2.4", "prettier-plugin-solidity": "^1.3.1", + "solady": "0.0.267", "solidity-coverage": "^0.8.7", "ts-essentials": "^9.4.1", "ts-node": "^10.9.1", "typechain": "^8.3.2", "typescript": "^5.3.3", + "viem": "^2.21.28", "zod": "^3.22.4" } } diff --git a/packages/contracts/test/EoaAccount.test.ts b/packages/contracts/test/EoaAccount.test.ts new file mode 100644 index 0000000..61744b7 --- /dev/null +++ b/packages/contracts/test/EoaAccount.test.ts @@ -0,0 +1,84 @@ +import { type SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; +import hre, { ethers, safeGetNamedAccounts, typedDeployments } from "hardhat"; +import { describe } from "mocha"; +import { Account, Client, createWalletClient, http } from "viem"; +import { privateKeyToAccount } from "viem/accounts"; +import { readContract } from "viem/actions"; +import { signAuthorization } from "viem/experimental"; +import { snapshottedBeforeEach } from "../shared/utils"; +import { + EoaAccount__factory, + PublicKeyRegistry, + PublicKeyRegistry__factory, +} from "../typechain-types"; + +describe("EoaAccount", () => { + let alice: SignerWithAddress; + let deployer: SignerWithAddress; + let publicKeyRegistry: PublicKeyRegistry; + const authProviderId = ethers.id("google"); // TODO: think about the structure + + snapshottedBeforeEach(async () => { + deployer = await ethers.getSigner( + (await safeGetNamedAccounts({ deployer: true })).deployer, + ); + await ethers.provider.send("hardhat_setBalance", [ + deployer.address, + ethers.toQuantity(ethers.parseEther("100")), + ]); + await typedDeployments.fixture(); + + [alice] = await ethers.getSigners(); + + publicKeyRegistry = PublicKeyRegistry__factory.connect( + (await typedDeployments.get("PublicKeyRegistry")).address, + deployer, + ); + }); + + it("works", async () => { + const publicClient = await hre.viem.getPublicClient(); + const service = new Eip7702Service(publicClient); + const account = privateKeyToAccount( + "0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6", + ); + const result = await service.authorize({ account }); + }); +}); + +class Eip7702Service { + constructor(private client: Client) {} + + async authorize({ account }: { account: Account }) { + const contractAddress = (await typedDeployments.get("EoaAccount")) + .address as `0x${string}`; + const auth = await signAuthorization(this.client, { + account, + contractAddress, + }); + + const accountClient = createWalletClient({ + account: account, + chain: this.client.chain, + transport: http(), + }); + + await accountClient.writeContract({ + abi: EoaAccount__factory.abi, + address: account.address, + functionName: "dummy", + args: [], + authorizationList: [auth], + account: account, + chain: this.client.chain, + }); + + const result = await readContract(this.client, { + address: account.address, + abi: EoaAccount__factory.abi, + functionName: "hello", + args: [], + }); + console.log("result", result); + } +} diff --git a/packages/contracts/test/JwtAccount.test.ts b/packages/contracts/test/JwtAccount.test.ts index f837a2d..2fed4c3 100644 --- a/packages/contracts/test/JwtAccount.test.ts +++ b/packages/contracts/test/JwtAccount.test.ts @@ -10,7 +10,7 @@ import { UltraVerifier__factory, } from "../typechain-types"; -describe("JwtAccount", () => { +describe.skip("JwtAccount", () => { let alice: SignerWithAddress; let deployer: SignerWithAddress; let publicKeyRegistry: PublicKeyRegistry; diff --git a/packages/contracts/typechain-types/contracts/EoaAccount.ts b/packages/contracts/typechain-types/contracts/EoaAccount.ts new file mode 100644 index 0000000..4ef7462 --- /dev/null +++ b/packages/contracts/typechain-types/contracts/EoaAccount.ts @@ -0,0 +1,335 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { + BaseContract, + BigNumberish, + BytesLike, + FunctionFragment, + Result, + Interface, + AddressLike, + ContractRunner, + ContractMethod, + Listener, +} from "ethers"; +import type { + TypedContractEvent, + TypedDeferredTopicFilter, + TypedEventLog, + TypedListener, + TypedContractMethod, +} from "../common"; + +export declare namespace ECDSA { + export type SignatureStruct = { r: BigNumberish; s: BigNumberish }; + + export type SignatureStructOutput = [r: bigint, s: bigint] & { + r: bigint; + s: bigint; + }; + + export type PublicKeyStruct = { x: BigNumberish; y: BigNumberish }; + + export type PublicKeyStructOutput = [x: bigint, y: bigint] & { + x: bigint; + y: bigint; + }; +} + +export declare namespace WebAuthnP256 { + export type MetadataStruct = { + authenticatorData: BytesLike; + clientDataJSON: string; + challengeIndex: BigNumberish; + typeIndex: BigNumberish; + userVerificationRequired: boolean; + }; + + export type MetadataStructOutput = [ + authenticatorData: string, + clientDataJSON: string, + challengeIndex: bigint, + typeIndex: bigint, + userVerificationRequired: boolean + ] & { + authenticatorData: string; + clientDataJSON: string; + challengeIndex: bigint; + typeIndex: bigint; + userVerificationRequired: boolean; + }; +} + +export declare namespace ZkLogin { + export type VerificationDataStruct = { + proof: BytesLike; + jwtIat: BigNumberish; + jwtNonce: BytesLike; + publicKeyHash: BytesLike; + }; + + export type VerificationDataStructOutput = [ + proof: string, + jwtIat: bigint, + jwtNonce: string, + publicKeyHash: string + ] & { + proof: string; + jwtIat: bigint; + jwtNonce: string; + publicKeyHash: string; + }; + + export type AccountDataStruct = { + accountId: BytesLike; + authProviderId: BytesLike; + publicKeyRegistry: AddressLike; + proofVerifier: AddressLike; + }; + + export type AccountDataStructOutput = [ + accountId: string, + authProviderId: string, + publicKeyRegistry: string, + proofVerifier: string + ] & { + accountId: string; + authProviderId: string; + publicKeyRegistry: string; + proofVerifier: string; + }; +} + +export interface EoaAccountInterface extends Interface { + getFunction( + nameOrSignature: + | "accountData" + | "execute" + | "getWebAuthnPublicKey" + | "nonce" + | "recover" + | "setAccountId" + | "webauthnPublicKey" + ): FunctionFragment; + + encodeFunctionData( + functionFragment: "accountData", + values?: undefined + ): string; + encodeFunctionData( + functionFragment: "execute", + values: [ + AddressLike, + BytesLike, + BigNumberish, + ECDSA.SignatureStruct, + WebAuthnP256.MetadataStruct + ] + ): string; + encodeFunctionData( + functionFragment: "getWebAuthnPublicKey", + values?: undefined + ): string; + encodeFunctionData(functionFragment: "nonce", values?: undefined): string; + encodeFunctionData( + functionFragment: "recover", + values: [ZkLogin.VerificationDataStruct, ECDSA.PublicKeyStruct] + ): string; + encodeFunctionData( + functionFragment: "setAccountId", + values: [ECDSA.PublicKeyStruct, ZkLogin.AccountDataStruct] + ): string; + encodeFunctionData( + functionFragment: "webauthnPublicKey", + values?: undefined + ): string; + + decodeFunctionResult( + functionFragment: "accountData", + data: BytesLike + ): Result; + decodeFunctionResult(functionFragment: "execute", data: BytesLike): Result; + decodeFunctionResult( + functionFragment: "getWebAuthnPublicKey", + data: BytesLike + ): Result; + decodeFunctionResult(functionFragment: "nonce", data: BytesLike): Result; + decodeFunctionResult(functionFragment: "recover", data: BytesLike): Result; + decodeFunctionResult( + functionFragment: "setAccountId", + data: BytesLike + ): Result; + decodeFunctionResult( + functionFragment: "webauthnPublicKey", + data: BytesLike + ): Result; +} + +export interface EoaAccount extends BaseContract { + connect(runner?: ContractRunner | null): EoaAccount; + waitForDeployment(): Promise; + + interface: EoaAccountInterface; + + queryFilter( + event: TCEvent, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>>; + queryFilter( + filter: TypedDeferredTopicFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>>; + + on( + event: TCEvent, + listener: TypedListener + ): Promise; + on( + filter: TypedDeferredTopicFilter, + listener: TypedListener + ): Promise; + + once( + event: TCEvent, + listener: TypedListener + ): Promise; + once( + filter: TypedDeferredTopicFilter, + listener: TypedListener + ): Promise; + + listeners( + event: TCEvent + ): Promise>>; + listeners(eventName?: string): Promise>; + removeAllListeners( + event?: TCEvent + ): Promise; + + accountData: TypedContractMethod< + [], + [ + [string, string, string, string] & { + accountId: string; + authProviderId: string; + publicKeyRegistry: string; + proofVerifier: string; + } + ], + "view" + >; + + execute: TypedContractMethod< + [ + to: AddressLike, + data: BytesLike, + value: BigNumberish, + signature: ECDSA.SignatureStruct, + metadata: WebAuthnP256.MetadataStruct + ], + [void], + "nonpayable" + >; + + getWebAuthnPublicKey: TypedContractMethod< + [], + [ECDSA.PublicKeyStructOutput], + "view" + >; + + nonce: TypedContractMethod<[], [bigint], "view">; + + recover: TypedContractMethod< + [ + verificationData: ZkLogin.VerificationDataStruct, + newP256PublicKey: ECDSA.PublicKeyStruct + ], + [void], + "nonpayable" + >; + + setAccountId: TypedContractMethod< + [ + webauthnPublicKey_: ECDSA.PublicKeyStruct, + accountData_: ZkLogin.AccountDataStruct + ], + [void], + "nonpayable" + >; + + webauthnPublicKey: TypedContractMethod< + [], + [[bigint, bigint] & { x: bigint; y: bigint }], + "view" + >; + + getFunction( + key: string | FunctionFragment + ): T; + + getFunction( + nameOrSignature: "accountData" + ): TypedContractMethod< + [], + [ + [string, string, string, string] & { + accountId: string; + authProviderId: string; + publicKeyRegistry: string; + proofVerifier: string; + } + ], + "view" + >; + getFunction( + nameOrSignature: "execute" + ): TypedContractMethod< + [ + to: AddressLike, + data: BytesLike, + value: BigNumberish, + signature: ECDSA.SignatureStruct, + metadata: WebAuthnP256.MetadataStruct + ], + [void], + "nonpayable" + >; + getFunction( + nameOrSignature: "getWebAuthnPublicKey" + ): TypedContractMethod<[], [ECDSA.PublicKeyStructOutput], "view">; + getFunction( + nameOrSignature: "nonce" + ): TypedContractMethod<[], [bigint], "view">; + getFunction( + nameOrSignature: "recover" + ): TypedContractMethod< + [ + verificationData: ZkLogin.VerificationDataStruct, + newP256PublicKey: ECDSA.PublicKeyStruct + ], + [void], + "nonpayable" + >; + getFunction( + nameOrSignature: "setAccountId" + ): TypedContractMethod< + [ + webauthnPublicKey_: ECDSA.PublicKeyStruct, + accountData_: ZkLogin.AccountDataStruct + ], + [void], + "nonpayable" + >; + getFunction( + nameOrSignature: "webauthnPublicKey" + ): TypedContractMethod< + [], + [[bigint, bigint] & { x: bigint; y: bigint }], + "view" + >; + + filters: {}; +} diff --git a/packages/contracts/typechain-types/contracts/index.ts b/packages/contracts/typechain-types/contracts/index.ts index e942b19..a815fa7 100644 --- a/packages/contracts/typechain-types/contracts/index.ts +++ b/packages/contracts/typechain-types/contracts/index.ts @@ -9,4 +9,5 @@ import type * as product from "./product"; export type { product }; import type * as utils from "./utils"; export type { utils }; +export type { EoaAccount } from "./EoaAccount"; export type { IProofVerifier } from "./IProofVerifier"; diff --git a/packages/contracts/typechain-types/factories/contracts/EoaAccount__factory.ts b/packages/contracts/typechain-types/factories/contracts/EoaAccount__factory.ts new file mode 100644 index 0000000..09b4d8f --- /dev/null +++ b/packages/contracts/typechain-types/factories/contracts/EoaAccount__factory.ts @@ -0,0 +1,344 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import { + Contract, + ContractFactory, + ContractTransactionResponse, + Interface, +} from "ethers"; +import type { Signer, ContractDeployTransaction, ContractRunner } from "ethers"; +import type { NonPayableOverrides } from "../../common"; +import type { + EoaAccount, + EoaAccountInterface, +} from "../../contracts/EoaAccount"; + +const _abi = [ + { + inputs: [ + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + { + internalType: "uint256", + name: "length", + type: "uint256", + }, + ], + name: "StringsInsufficientHexLength", + type: "error", + }, + { + inputs: [], + name: "accountData", + outputs: [ + { + internalType: "bytes32", + name: "accountId", + type: "bytes32", + }, + { + internalType: "bytes32", + name: "authProviderId", + type: "bytes32", + }, + { + internalType: "address", + name: "publicKeyRegistry", + type: "address", + }, + { + internalType: "address", + name: "proofVerifier", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "to", + type: "address", + }, + { + internalType: "bytes", + name: "data", + type: "bytes", + }, + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + { + components: [ + { + internalType: "uint256", + name: "r", + type: "uint256", + }, + { + internalType: "uint256", + name: "s", + type: "uint256", + }, + ], + internalType: "struct ECDSA.Signature", + name: "signature", + type: "tuple", + }, + { + components: [ + { + internalType: "bytes", + name: "authenticatorData", + type: "bytes", + }, + { + internalType: "string", + name: "clientDataJSON", + type: "string", + }, + { + internalType: "uint16", + name: "challengeIndex", + type: "uint16", + }, + { + internalType: "uint16", + name: "typeIndex", + type: "uint16", + }, + { + internalType: "bool", + name: "userVerificationRequired", + type: "bool", + }, + ], + internalType: "struct WebAuthnP256.Metadata", + name: "metadata", + type: "tuple", + }, + ], + name: "execute", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "getWebAuthnPublicKey", + outputs: [ + { + components: [ + { + internalType: "uint256", + name: "x", + type: "uint256", + }, + { + internalType: "uint256", + name: "y", + type: "uint256", + }, + ], + internalType: "struct ECDSA.PublicKey", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "nonce", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + components: [ + { + internalType: "bytes", + name: "proof", + type: "bytes", + }, + { + internalType: "uint256", + name: "jwtIat", + type: "uint256", + }, + { + internalType: "bytes32", + name: "jwtNonce", + type: "bytes32", + }, + { + internalType: "bytes32", + name: "publicKeyHash", + type: "bytes32", + }, + ], + internalType: "struct ZkLogin.VerificationData", + name: "verificationData", + type: "tuple", + }, + { + components: [ + { + internalType: "uint256", + name: "x", + type: "uint256", + }, + { + internalType: "uint256", + name: "y", + type: "uint256", + }, + ], + internalType: "struct ECDSA.PublicKey", + name: "newP256PublicKey", + type: "tuple", + }, + ], + name: "recover", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + internalType: "uint256", + name: "x", + type: "uint256", + }, + { + internalType: "uint256", + name: "y", + type: "uint256", + }, + ], + internalType: "struct ECDSA.PublicKey", + name: "webauthnPublicKey_", + type: "tuple", + }, + { + components: [ + { + internalType: "bytes32", + name: "accountId", + type: "bytes32", + }, + { + internalType: "bytes32", + name: "authProviderId", + type: "bytes32", + }, + { + internalType: "address", + name: "publicKeyRegistry", + type: "address", + }, + { + internalType: "address", + name: "proofVerifier", + type: "address", + }, + ], + internalType: "struct ZkLogin.AccountData", + name: "accountData_", + type: "tuple", + }, + ], + name: "setAccountId", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "webauthnPublicKey", + outputs: [ + { + internalType: "uint256", + name: "x", + type: "uint256", + }, + { + internalType: "uint256", + name: "y", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + stateMutability: "payable", + type: "receive", + }, +] as const; + +const _bytecode = + "0x6080604052348015600f57600080fd5b506118d28061001f6000396000f3fe6080604052600436106100745760003560e01c8063affed0e01161004e578063affed0e01461014f578063bb3da92d14610173578063c389ca27146101be578063ff07203e146101de57600080fd5b8063041c9ae6146100805780637a28f8bc146100a25780637dc0872e1461011f57600080fd5b3661007b57005b600080fd5b34801561008c57600080fd5b506100a061009b36600461107b565b6101fe565b005b3480156100ae57600080fd5b506000546001546002546003546100de93929173ffffffffffffffffffffffffffffffffffffffff908116911684565b60408051948552602085019390935273ffffffffffffffffffffffffffffffffffffffff918216928401929092521660608201526080015b60405180910390f35b34801561012b57600080fd5b5060055460065461013a919082565b60408051928352602083019190915201610116565b34801561015b57600080fd5b5061016560045481565b604051908152602001610116565b34801561017f57600080fd5b50604080518082018252600080825260209182015281518083018352600554808252600654918301918252835190815290519181019190915201610116565b3480156101ca57600080fd5b506100a06101d936600461110a565b610369565b3480156101ea57600080fd5b506100a06101f9366004611250565b6104d1565b604080518235602080830191909152830135818301529083013590606001604051602081830303815290604052805190602001201461029e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c696420576562417574686e207075626c6963206b6579000000000060448201526064015b60405180910390fd5b604080516080810182526000548152600154602082015260025473ffffffffffffffffffffffffffffffffffffffff9081169282019290925260035490911660608201526102f4906102ef8461139f565b6105b1565b61035a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f696e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610295565b80356005556020013560065550565b600480546000918261037a83611433565b919050558787878760405160200161039695949392919061146b565b6040516020818303038152906040528051906020012090506103e781836103bc90611514565b6103cb368790038701876115cd565b60408051808201909152600554815260065460208201526108af565b6103f057600080fd5b60008773ffffffffffffffffffffffffffffffffffffffff1685888860405161041a92919061161e565b60006040518083038185875af1925050503d8060008114610457576040519150601f19603f3d011682016040523d82523d6000602084013e61045c565b606091505b50509050806104c7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f63616c6c206661696c65640000000000000000000000000000000000000000006044820152606401610295565b5050505050505050565b33301461053a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f6e6f742073656c660000000000000000000000000000000000000000000000006044820152606401610295565b81356005556020918201356006558051600055908101516001556040810151600280547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff93841617909155606090920151600380549093169116179055565b6000826040015173ffffffffffffffffffffffffffffffffffffffff16635879142a846020015184606001516040518363ffffffff1660e01b8152600401610603929190918252602082015260400190565b602060405180830381865afa158015610620573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610644919061162e565b6106aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f7075626c6963206b65792068617368206d69736d6174636800000000000000006044820152606401610295565b60006106b98360400151610ae1565b80519091506003906000906106ce908361164b565b67ffffffffffffffff8111156106e6576106e66111d5565b60405190808252806020026020018201604052801561070f578160200160208202803683370190505b508651909150600090828261072381611433565b9350815181106107355761073561165e565b602002602001018181525050856020015160001b82828061075590611433565b9350815181106107675761076761165e565b60209081029190910101526060860151828261078281611433565b9350815181106107945761079461165e565b60200260200101818152505060005b84518110156107f6578481815181106107be576107be61165e565b016020015160f81c83836107d181611433565b9450815181106107e3576107e361165e565b60209081029190910101526001016107a3565b50815181146108075761080761168d565b606087015186516040517fea50d0e400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9092169163ea50d0e4916108619186906004016116e0565b602060405180830381865afa15801561087e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a2919061162e565b9450505050505b92915050565b6000602584600001515110806108f157506108ef84600001516020815181106108da576108da61165e565b602001015160f81c60f81b8560800151610aee565b155b156108fe57506000610ad9565b60006040518060400160405280601581526020017f2274797065223a22776562617574686e2e676574220000000000000000000000815250905061094f818660200151876060015161ffff16610be0565b61095d576000915050610ad9565b600061098c8760405160200161097591815260200190565b604051602081830303815290604052600180610cc1565b90506000816040516020016109a1919061177a565b60405160208183030381529060405290506109c9818860200151896040015161ffff16610be0565b6109d95760009350505050610ad9565b6000600288602001516040516109ef91906117e6565b602060405180830381855afa158015610a0c573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610a2f9190611802565b905060006002896000015183604051602001610a4c92919061181b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610a84916117e6565b602060405180830381855afa158015610aa1573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610ac49190611802565b9050610ad1818989610dd2565b955050505050505b949350505050565b60606108a9826020610f0c565b60007f010000000000000000000000000000000000000000000000000000000000000083811614610b21575060006108a9565b818015610b5057507f040000000000000000000000000000000000000000000000000000000000000083811614155b15610b5d575060006108a9565b7f080000000000000000000000000000000000000000000000000000000000000083811614610bd7577ff0000000000000000000000000000000000000000000000000000000000000007f1000000000000000000000000000000000000000000000000000000000000000841601610bd7575060006108a9565b50600192915050565b825182516000918591859190845b82811015610cb05781610c01828961164b565b10610c1457600095505050505050610cba565b83610c1f828961164b565b81518110610c2f57610c2f61165e565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916858281518110610c6e57610c6e61165e565b01602001517fff000000000000000000000000000000000000000000000000000000000000001614610ca857600095505050505050610cba565b600101610bee565b5060019450505050505b9392505050565b606083518015610dca576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106708515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f52602083018181018388602001018051600082525b60038a0199508951603f8160121c1651600053603f81600c1c1651600153603f8160061c1651600253603f811651600353506000518452600484019350828410610d3d5790526020016040527f3d3d000000000000000000000000000000000000000000000000000000000000600384066002048083039190915260008615159091029182900352900382525b509392505050565b8151602080840151835184830151604080519485018990528401949094526060830191909152608082015260a08101919091526000908190819060149060c001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610e4a916117e6565b600060405180830381855afa9150503d8060008114610e85576040519150601f19603f3d011682016040523d82523d6000602084013e610e8a565b606091505b5091509150818015610e9d575080516020145b8015610f02575080601f81518110610eb757610eb761165e565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167f0100000000000000000000000000000000000000000000000000000000000000145b9695505050505050565b6060826000610f1c84600261183d565b67ffffffffffffffff811115610f3457610f346111d5565b6040519080825280601f01601f191660200182016040528015610f5e576020820181803683370190505b5090506000610f6e85600261183d565b610f7990600161164b565b90505b6001811115611020577f303132333435363738396162636465660000000000000000000000000000000083600f1660108110610fba57610fba61165e565b1a60f81b82610fca600284611854565b81518110610fda57610fda61165e565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049290921c9161101981611867565b9050610f7c565b508115610ad9576040517fe22e27eb0000000000000000000000000000000000000000000000000000000081526004810186905260248101859052604401610295565b60006040828403121561107557600080fd5b50919050565b6000806060838503121561108e57600080fd5b823567ffffffffffffffff8111156110a557600080fd5b8301608081860312156110b757600080fd5b91506110c68460208501611063565b90509250929050565b803573ffffffffffffffffffffffffffffffffffffffff811681146110f357600080fd5b919050565b600060a0828403121561107557600080fd5b60008060008060008060c0878903121561112357600080fd5b61112c876110cf565b9550602087013567ffffffffffffffff81111561114857600080fd5b8701601f8101891361115957600080fd5b803567ffffffffffffffff81111561117057600080fd5b89602082840101111561118257600080fd5b60209190910195509350604087013592506111a08860608901611063565b915060a087013567ffffffffffffffff8111156111bc57600080fd5b6111c889828a016110f8565b9150509295509295509295565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715611227576112276111d5565b60405290565b60405160a0810167ffffffffffffffff81118282101715611227576112276111d5565b60008082840360c081121561126457600080fd5b61126e8585611063565b925060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0820112156112a057600080fd5b506112a9611204565b60408401358152606084013560208201526112c6608085016110cf565b60408201526112d760a085016110cf565b6060820152809150509250929050565b60008067ffffffffffffffff841115611302576113026111d5565b506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85018116603f0116810181811067ffffffffffffffff8211171561134f5761134f6111d5565b60405283815290508082840185101561136757600080fd5b83836020830137600060208583010152509392505050565b600082601f83011261139057600080fd5b610cba838335602085016112e7565b6000608082360312156113b157600080fd5b6113b9611204565b823567ffffffffffffffff8111156113d057600080fd5b6113dc3682860161137f565b8252506020838101359082015260408084013590820152606092830135928101929092525090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361146457611464611404565b5060010190565b85815273ffffffffffffffffffffffffffffffffffffffff8516602082015260806040820152826080820152828460a0830137600060a08483010152600060a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190508260608301529695505050505050565b803561ffff811681146110f357600080fd5b801515811461150657600080fd5b50565b80356110f3816114f8565b600060a0823603121561152657600080fd5b61152e61122d565b823567ffffffffffffffff81111561154557600080fd5b6115513682860161137f565b825250602083013567ffffffffffffffff81111561156e57600080fd5b830136601f82011261157f57600080fd5b61158e368235602084016112e7565b6020830152506115a0604084016114e6565b60408201526115b1606084016114e6565b60608201526115c260808401611509565b608082015292915050565b600060408284031280156115e057600080fd5b506040805190810167ffffffffffffffff81118282101715611604576116046111d5565b604052823581526020928301359281019290925250919050565b8183823760009101908152919050565b60006020828403121561164057600080fd5b8151610cba816114f8565b808201808211156108a9576108a9611404565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b60005b838110156116d75781810151838201526020016116bf565b50506000910152565b60408152600083518060408401526116ff8160608501602088016116bc565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201828103606090810160208086019190915285519183018290528501916000916080909101905b8083101561176f578351825260208201915060208401935060018301925061174c565b509695505050505050565b7f226368616c6c656e6765223a22000000000000000000000000000000000000008152600082516117b281600d8501602087016116bc565b7f2200000000000000000000000000000000000000000000000000000000000000600d939091019283015250600e01919050565b600082516117f88184602087016116bc565b9190910192915050565b60006020828403121561181457600080fd5b5051919050565b6000835161182d8184602088016116bc565b9190910191825250602001919050565b80820281158282048414176108a9576108a9611404565b818103818111156108a9576108a9611404565b60008161187657611876611404565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea26469706673582212200f13d9d851d2190cfbe947e89c27b152eef4ae0ea84ce51cb3027758d574341a64736f6c634300081b0033"; + +type EoaAccountConstructorParams = + | [signer?: Signer] + | ConstructorParameters; + +const isSuperArgs = ( + xs: EoaAccountConstructorParams +): xs is ConstructorParameters => xs.length > 1; + +export class EoaAccount__factory extends ContractFactory { + constructor(...args: EoaAccountConstructorParams) { + if (isSuperArgs(args)) { + super(...args); + } else { + super(_abi, _bytecode, args[0]); + } + } + + override getDeployTransaction( + overrides?: NonPayableOverrides & { from?: string } + ): Promise { + return super.getDeployTransaction(overrides || {}); + } + override deploy(overrides?: NonPayableOverrides & { from?: string }) { + return super.deploy(overrides || {}) as Promise< + EoaAccount & { + deploymentTransaction(): ContractTransactionResponse; + } + >; + } + override connect(runner: ContractRunner | null): EoaAccount__factory { + return super.connect(runner) as EoaAccount__factory; + } + + static readonly bytecode = _bytecode; + static readonly abi = _abi; + static createInterface(): EoaAccountInterface { + return new Interface(_abi) as EoaAccountInterface; + } + static connect(address: string, runner?: ContractRunner | null): EoaAccount { + return new Contract(address, _abi, runner) as unknown as EoaAccount; + } +} diff --git a/packages/contracts/typechain-types/factories/contracts/index.ts b/packages/contracts/typechain-types/factories/contracts/index.ts index 6caa444..63d53d0 100644 --- a/packages/contracts/typechain-types/factories/contracts/index.ts +++ b/packages/contracts/typechain-types/factories/contracts/index.ts @@ -5,4 +5,5 @@ export * as mock from "./_mock"; export * as infra from "./infra"; export * as product from "./product"; export * as utils from "./utils"; +export { EoaAccount__factory } from "./EoaAccount__factory"; export { IProofVerifier__factory } from "./IProofVerifier__factory"; diff --git a/packages/contracts/typechain-types/hardhat.d.ts b/packages/contracts/typechain-types/hardhat.d.ts index 1e2c1bc..e4f4943 100644 --- a/packages/contracts/typechain-types/hardhat.d.ts +++ b/packages/contracts/typechain-types/hardhat.d.ts @@ -121,6 +121,10 @@ declare module "hardhat/types/runtime" { name: "TestJwtAccount", signerOrOptions?: ethers.Signer | FactoryOptions ): Promise; + getContractFactory( + name: "EoaAccount", + signerOrOptions?: ethers.Signer | FactoryOptions + ): Promise; getContractFactory( name: "IPublicKeyRegistry", signerOrOptions?: ethers.Signer | FactoryOptions @@ -289,6 +293,11 @@ declare module "hardhat/types/runtime" { address: string | ethers.Addressable, signer?: ethers.Signer ): Promise; + getContractAt( + name: "EoaAccount", + address: string | ethers.Addressable, + signer?: ethers.Signer + ): Promise; getContractAt( name: "IPublicKeyRegistry", address: string | ethers.Addressable, @@ -438,6 +447,10 @@ declare module "hardhat/types/runtime" { name: "TestJwtAccount", signerOrOptions?: ethers.Signer | DeployContractOptions ): Promise; + deployContract( + name: "EoaAccount", + signerOrOptions?: ethers.Signer | DeployContractOptions + ): Promise; deployContract( name: "IPublicKeyRegistry", signerOrOptions?: ethers.Signer | DeployContractOptions @@ -606,6 +619,11 @@ declare module "hardhat/types/runtime" { args: any[], signerOrOptions?: ethers.Signer | DeployContractOptions ): Promise; + deployContract( + name: "EoaAccount", + args: any[], + signerOrOptions?: ethers.Signer | DeployContractOptions + ): Promise; deployContract( name: "IPublicKeyRegistry", args: any[], diff --git a/packages/contracts/typechain-types/index.ts b/packages/contracts/typechain-types/index.ts index 7499d1f..71e3224 100644 --- a/packages/contracts/typechain-types/index.ts +++ b/packages/contracts/typechain-types/index.ts @@ -64,6 +64,8 @@ export type { Strings } from "./@openzeppelin/contracts/utils/Strings"; export { Strings__factory } from "./factories/@openzeppelin/contracts/utils/Strings__factory"; export type { TestJwtAccount } from "./contracts/_mock/TestJwtAccount"; export { TestJwtAccount__factory } from "./factories/contracts/_mock/TestJwtAccount__factory"; +export type { EoaAccount } from "./contracts/EoaAccount"; +export { EoaAccount__factory } from "./factories/contracts/EoaAccount__factory"; export type { IPublicKeyRegistry } from "./contracts/infra/IPublicKeyRegistry"; export { IPublicKeyRegistry__factory } from "./factories/contracts/infra/IPublicKeyRegistry__factory"; export type { PublicKeyRegistry } from "./contracts/infra/PublicKeyRegistry"; diff --git a/packages/ui/src/lib/components/form/Form.svelte b/packages/ui/src/lib/components/form/Form.svelte index 7403adb..ef15fa5 100644 --- a/packages/ui/src/lib/components/form/Form.svelte +++ b/packages/ui/src/lib/components/form/Form.svelte @@ -10,10 +10,12 @@ let { schema, + initialValues = {}, onsubmit, children, }: { schema: T; + initialValues?: Partial>; onsubmit: (data: z.infer) => Promise; children: ( form: ReturnType>>, @@ -22,24 +24,29 @@ } = $props(); let formElement: HTMLFormElement | undefined = $state(); - const form = superForm(defaults(zod(schema)), { - validators: zodClient(schema), - SPA: true, - async onSubmit(input) { - try { - const result = await superValidate(input.formData, zod(schema)); - if (!result.valid) { - throw new Error("Invalid form data"); + const form = superForm( + defaults(zod(schema), { + defaults: initialValues, + } as any), + { + validators: zodClient(schema), + SPA: true, + async onSubmit(input) { + try { + const result = await superValidate(input.formData, zod(schema)); + if (!result.valid) { + throw new Error("Invalid form data"); + } + const data = result.data; + await onsubmit(data); + // formElement?.reset(); + } catch (e) { + toast.error(e); + throw e; } - const data = result.data; - await onsubmit(data); - // formElement?.reset(); - } catch (e) { - toast.error(e); - throw e; - } + }, }, - }); + ); const { form: formDataStore, enhance } = form; let formData = toRuneObject(formDataStore); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b3d18f2..deca4e4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -76,6 +76,9 @@ importers: viem: specifier: ^2.21.54 version: 2.21.54(typescript@5.6.3)(zod@3.23.8) + webauthn-p256: + specifier: ^0.0.10 + version: 0.0.10 zod: specifier: ^3.23.8 version: 3.23.8 @@ -146,6 +149,9 @@ importers: '@nomicfoundation/hardhat-verify': specifier: ^2.0.4 version: 2.0.11(hardhat@2.22.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3))(typescript@5.6.3)) + '@nomicfoundation/hardhat-viem': + specifier: ^2.0.5 + version: 2.0.5(hardhat@2.22.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3))(typescript@5.6.3))(typescript@5.6.3)(viem@2.21.45(typescript@5.6.3)(zod@3.23.8))(zod@3.23.8) '@openzeppelin/contracts': specifier: 5.1.0 version: 5.1.0 @@ -209,6 +215,9 @@ importers: prettier-plugin-solidity: specifier: ^1.3.1 version: 1.4.1(prettier@3.3.3) + solady: + specifier: 0.0.267 + version: 0.0.267 solidity-coverage: specifier: ^0.8.7 version: 0.8.13(hardhat@2.22.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3))(typescript@5.6.3)) @@ -224,6 +233,9 @@ importers: typescript: specifier: ^5.3.3 version: 5.6.3 + viem: + specifier: ^2.21.28 + version: 2.21.45(typescript@5.6.3)(zod@3.23.8) zod: specifier: ^3.22.4 version: 3.23.8 @@ -1244,6 +1256,13 @@ packages: peerDependencies: hardhat: ^2.0.4 + '@nomicfoundation/hardhat-viem@2.0.5': + resolution: {integrity: sha512-T3xqRzPwhKawqjKvqUT1fZUD85JxFhHjb/nAiJiuYQzaR6NyDPEJVwcc3CU5uwB79BwgQlSHDGOKjSNYmQP+VA==} + peerDependencies: + hardhat: ^2.17.0 + typescript: ~5.0.0 + viem: ^2.7.6 + '@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2': resolution: {integrity: sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw==} engines: {node: '>= 12'} @@ -1723,6 +1742,17 @@ packages: abbrev@1.0.9: resolution: {integrity: sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==} + abitype@0.9.10: + resolution: {integrity: sha512-FIS7U4n7qwAT58KibwYig5iFG4K61rbhAqaQh/UWj8v1Y8mjX3F8TC9gd8cz9yT1TYel9f8nS5NO5kZp2RW0jQ==} + peerDependencies: + typescript: '>=5.0.4' + zod: ^3 >=3.22.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + abitype@1.0.6: resolution: {integrity: sha512-MMSqYh4+C/aVqI2RQaWqbvI4Kxo5cQV40WQ4QFtDnNzCkqChm8MuENhElmynZlO0qUy/ObkEUaXtKqYnx1Kp3A==} peerDependencies: @@ -3026,6 +3056,9 @@ packages: lodash.isplainobject@4.0.6: resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -3798,6 +3831,9 @@ packages: resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} engines: {node: '>=10'} + solady@0.0.267: + resolution: {integrity: sha512-Jjl5odGoXARF2TOGJMLtKy5Z+qsu1Bfq+al0uNVnBQjHH8Rw/oOMb7Em1igxxx4UQcjcKEpQiAYtsawK+B3TKg==} + solc@0.8.26: resolution: {integrity: sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g==} engines: {node: '>=10.0.0'} @@ -4231,6 +4267,14 @@ packages: resolution: {integrity: sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==} engines: {node: '>= 0.10'} + viem@2.21.45: + resolution: {integrity: sha512-I+On/IiaObQdhDKWU5Rurh6nf3G7reVkAODG5ECIfjsrGQ3EPJnxirUPT4FNV6bWER5iphoG62/TidwuTSOA1A==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + viem@2.21.54: resolution: {integrity: sha512-G9mmtbua3UtnVY9BqAtWdNp+3AO+oWhD0B9KaEsZb6gcrOWgmA4rz02yqEMg+qW9m6KgKGie7q3zcHqJIw6AqA==} peerDependencies: @@ -5419,6 +5463,16 @@ snapshots: transitivePeerDependencies: - supports-color + '@nomicfoundation/hardhat-viem@2.0.5(hardhat@2.22.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3))(typescript@5.6.3))(typescript@5.6.3)(viem@2.21.45(typescript@5.6.3)(zod@3.23.8))(zod@3.23.8)': + dependencies: + abitype: 0.9.10(typescript@5.6.3)(zod@3.23.8) + hardhat: 2.22.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3))(typescript@5.6.3) + lodash.memoize: 4.1.2 + typescript: 5.6.3 + viem: 2.21.45(typescript@5.6.3)(zod@3.23.8) + transitivePeerDependencies: + - zod + '@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2': optional: true @@ -5982,6 +6036,11 @@ snapshots: abbrev@1.0.9: {} + abitype@0.9.10(typescript@5.6.3)(zod@3.23.8): + optionalDependencies: + typescript: 5.6.3 + zod: 3.23.8 + abitype@1.0.6(typescript@5.6.3)(zod@3.23.8): optionalDependencies: typescript: 5.6.3 @@ -7498,6 +7557,8 @@ snapshots: lodash.isplainobject@4.0.6: {} + lodash.memoize@4.1.2: {} + lodash.merge@4.6.2: {} lodash.startcase@4.4.0: {} @@ -8195,6 +8256,8 @@ snapshots: astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 + solady@0.0.267: {} + solc@0.8.26(debug@4.3.7): dependencies: command-exists: 1.2.9 @@ -8678,6 +8741,24 @@ snapshots: validator@13.12.0: optional: true + viem@2.21.45(typescript@5.6.3)(zod@3.23.8): + dependencies: + '@noble/curves': 1.6.0 + '@noble/hashes': 1.5.0 + '@scure/bip32': 1.5.0 + '@scure/bip39': 1.4.0 + abitype: 1.0.6(typescript@5.6.3)(zod@3.23.8) + isows: 1.0.6(ws@8.18.0) + ox: 0.1.2(typescript@5.6.3)(zod@3.23.8) + webauthn-p256: 0.0.10 + ws: 8.18.0 + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + viem@2.21.54(typescript@5.6.3)(zod@3.23.8): dependencies: '@noble/curves': 1.7.0