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