From 4eed58e5bacff4262f434cf69f0f589789fea0cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bence=20H=C3=A1romi?= <56651250+benceharomi@users.noreply.github.com> Date: Wed, 18 Feb 2026 16:03:38 +0000 Subject: [PATCH 01/11] feat: generic platform handling in command --- script/DeployLinkHandleVerifier.s.sol | 2 +- src/entrypoints/LinkHandleEntrypoint.sol | 8 +- src/entrypoints/LinkTextRecordEntrypoint.sol | 1 + src/verifiers/LinkEmailCommandVerifier.sol | 17 +++- src/verifiers/LinkHandleCommandVerifier.sol | 16 +++- test/fixtures/TestFixtures.sol | 1 + .../HandleCommandTestFixture.sol | 30 +------ .../RedditHandleCommandTestFixture.sol | 30 +------ .../LinkHandleEntrypoint.t.sol | 8 +- .../_LinkHandleEntrypointHelper.sol | 2 +- test/utils/TestStringUtils.sol | 89 +++++++++++++++++++ test/utils/TestStringUtils.t.sol | 48 ++++++++++ test/utils/_TestStringUtilsHelper.sol | 10 +++ 13 files changed, 196 insertions(+), 66 deletions(-) create mode 100644 test/utils/TestStringUtils.sol create mode 100644 test/utils/TestStringUtils.t.sol create mode 100644 test/utils/_TestStringUtilsHelper.sol diff --git a/script/DeployLinkHandleVerifier.s.sol b/script/DeployLinkHandleVerifier.s.sol index 5050a15..63faa3e 100644 --- a/script/DeployLinkHandleVerifier.s.sol +++ b/script/DeployLinkHandleVerifier.s.sol @@ -19,7 +19,7 @@ contract DeployLinkHandleEntrypointScript is Script { LinkHandleCommandVerifier commandVerifier = new LinkHandleCommandVerifier(address(new HonkVerifier()), DKIM_REGISTRY); - LinkHandleEntrypoint verifier = new LinkHandleEntrypoint(address(commandVerifier)); + LinkHandleEntrypoint verifier = new LinkHandleEntrypoint(address(commandVerifier), "com.twitter"); vm.stopBroadcast(); console.log("LINK_HANDLE_VERIFIER=", address(verifier)); diff --git a/src/entrypoints/LinkHandleEntrypoint.sol b/src/entrypoints/LinkHandleEntrypoint.sol index b3d6780..0cbb62f 100644 --- a/src/entrypoints/LinkHandleEntrypoint.sol +++ b/src/entrypoints/LinkHandleEntrypoint.sol @@ -10,7 +10,13 @@ import { LinkHandleCommand } from "../verifiers/HandleVerifier.sol"; * @dev The verifier can be updated via the entrypoint function. */ contract LinkHandleEntrypoint is LinkTextRecordEntrypoint { - constructor(address verifier) LinkTextRecordEntrypoint(verifier, "com.twitter") { } + /** + * @notice Constructor + * @param verifier The LinkHandleCommandVerifier contract address + * @param keyName The key name for the text record (e.g. "com.twitter") + * @dev The key name is used to identify the text record in the mapping + */ + constructor(address verifier, string memory keyName) LinkTextRecordEntrypoint(verifier, keyName) { } /** * @inheritdoc LinkTextRecordEntrypoint diff --git a/src/entrypoints/LinkTextRecordEntrypoint.sol b/src/entrypoints/LinkTextRecordEntrypoint.sol index e5100e8..2a93a32 100644 --- a/src/entrypoints/LinkTextRecordEntrypoint.sol +++ b/src/entrypoints/LinkTextRecordEntrypoint.sol @@ -7,6 +7,7 @@ import { IVerifier } from "../interfaces/IVerifier.sol"; import { EnsUtils } from "../utils/EnsUtils.sol"; struct TextRecord { + string platformName; string ensName; string value; bytes32 nullifier; diff --git a/src/verifiers/LinkEmailCommandVerifier.sol b/src/verifiers/LinkEmailCommandVerifier.sol index 4a2ae59..0e379e8 100644 --- a/src/verifiers/LinkEmailCommandVerifier.sol +++ b/src/verifiers/LinkEmailCommandVerifier.sol @@ -11,9 +11,11 @@ import { TextRecord } from "../entrypoints/LinkTextRecordEntrypoint.sol"; /** * @notice Enum representing the indices of command parameters in the command template * @dev Used to specify which parameter to extract from the command string - * @param ENS_NAME = 0 + * @param PLATFORM_NAME = 0 + * @param ENS_NAME = 1 */ enum CommandParamIndex { + PLATFORM_NAME, ENS_NAME } @@ -79,6 +81,11 @@ contract LinkEmailCommandVerifier is EmailAuthVerifier { PublicInputs memory publicInputs = _unpackPublicInputs(publicInputsFields); return LinkEmailCommand({ textRecord: TextRecord({ + platformName: string( + CommandUtils.extractCommandParamByIndex( + _getTemplate(), publicInputs.maskedCommand, uint256(CommandParamIndex.PLATFORM_NAME) + ) + ), // ensName is extracted from the command ensName: string( CommandUtils.extractCommandParamByIndex( @@ -95,8 +102,10 @@ contract LinkEmailCommandVerifier is EmailAuthVerifier { } function _getMaskedCommand(LinkEmailCommand memory command) private pure returns (string memory) { - bytes[] memory commandParams = new bytes[](1); - commandParams[0] = abi.encode(command.textRecord.ensName); + bytes[] memory commandParams = new bytes[](2); + commandParams[0] = abi.encode(command.textRecord.platformName); + commandParams[1] = abi.encode(command.textRecord.ensName); + return CommandUtils.computeExpectedCommand(commandParams, _getTemplate(), 0); } @@ -105,7 +114,7 @@ contract LinkEmailCommandVerifier is EmailAuthVerifier { template[0] = "Link"; template[1] = "my"; - template[2] = "email"; + template[2] = CommandUtils.STRING_MATCHER; template[3] = "to"; template[4] = CommandUtils.STRING_MATCHER; diff --git a/src/verifiers/LinkHandleCommandVerifier.sol b/src/verifiers/LinkHandleCommandVerifier.sol index fc62424..b4eaef9 100644 --- a/src/verifiers/LinkHandleCommandVerifier.sol +++ b/src/verifiers/LinkHandleCommandVerifier.sol @@ -10,9 +10,11 @@ import { HandleVerifier, LinkHandleCommand, PublicInputs, TextRecord } from "./H /** * @notice Enum representing the indices of command parameters in the command template * @dev Used to specify which parameter to extract from the command string - * @param ENS_NAME = 0 + * @param PLATFORM_NAME = 0 + * @param ENS_NAME = 1 */ enum CommandParamIndex { + PLATFORM_NAME, ENS_NAME } @@ -65,6 +67,11 @@ contract LinkHandleCommandVerifier is HandleVerifier { PublicInputs memory publicInputs = _unpackPublicInputs(publicInputsFields); return LinkHandleCommand({ textRecord: TextRecord({ + platformName: string( + CommandUtils.extractCommandParamByIndex( + _getTemplate(), publicInputs.command, uint256(CommandParamIndex.PLATFORM_NAME) + ) + ), // ensName is extracted from the command ensName: string( CommandUtils.extractCommandParamByIndex( @@ -81,8 +88,9 @@ contract LinkHandleCommandVerifier is HandleVerifier { } function _getCommand(LinkHandleCommand memory command) private pure returns (string memory) { - bytes[] memory commandParams = new bytes[](1); - commandParams[0] = abi.encode(command.textRecord.ensName); + bytes[] memory commandParams = new bytes[](2); + commandParams[0] = abi.encode(command.textRecord.platformName); + commandParams[1] = abi.encode(command.textRecord.ensName); return CommandUtils.computeExpectedCommand(commandParams, _getTemplate(), 0); } @@ -92,7 +100,7 @@ contract LinkHandleCommandVerifier is HandleVerifier { template[0] = "Link"; template[1] = "my"; - template[2] = "x"; + template[2] = CommandUtils.STRING_MATCHER; template[3] = "handle"; template[4] = "to"; template[5] = CommandUtils.STRING_MATCHER; diff --git a/test/fixtures/TestFixtures.sol b/test/fixtures/TestFixtures.sol index 9890204..0e3aae7 100644 --- a/test/fixtures/TestFixtures.sol +++ b/test/fixtures/TestFixtures.sol @@ -279,6 +279,7 @@ library TestFixtures { command = LinkEmailCommand({ textRecord: TextRecord({ + platformName: "email", ensName: "zkfriendly.eth", value: "thezdev1@gmail.com", nullifier: hex"0CEF36D2E53A61D038B0F46466F7C1E4E5D62636FC3ACAB471C8AC6A0558F705" diff --git a/test/fixtures/handleCommand/HandleCommandTestFixture.sol b/test/fixtures/handleCommand/HandleCommandTestFixture.sol index 9168564..cd725d9 100644 --- a/test/fixtures/handleCommand/HandleCommandTestFixture.sol +++ b/test/fixtures/handleCommand/HandleCommandTestFixture.sol @@ -5,6 +5,7 @@ import { Vm } from "forge-std/Vm.sol"; import { LinkHandleCommand, PublicInputs } from "../../../src/verifiers/HandleVerifier.sol"; import { ClaimHandleCommand } from "../../../src/verifiers/ClaimHandleCommandVerifier.sol"; import { TextRecord } from "../../../src/entrypoints/LinkTextRecordEntrypoint.sol"; +import { TestStringUtils } from "../../utils/TestStringUtils.sol"; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; address constant _VM_ADDR = address(uint160(uint256(keccak256("hevm cheat code")))); @@ -24,7 +25,7 @@ library HandleCommandTestFixture { _getExpectedPublicInputs(string.concat(path, "files/claimX/expected_public_inputs.json")); command = ClaimHandleCommand({ - target: Strings.parseAddress(_getLastWord(expectedPublicInputs.command)), + target: Strings.parseAddress(TestStringUtils.getNthWord(expectedPublicInputs.command, -1)), proof: abi.encodePacked(_getProofFieldsFromBinary(string.concat(path, "files/claimX/proof"))), publicInputs: expectedPublicInputs }); @@ -40,7 +41,8 @@ library HandleCommandTestFixture { command = LinkHandleCommand({ textRecord: TextRecord({ - ensName: _getLastWord(expectedPublicInputs.command), + platformName: TestStringUtils.getNthWord(expectedPublicInputs.command, 2), + ensName: TestStringUtils.getNthWord(expectedPublicInputs.command, -1), value: expectedPublicInputs.handle, nullifier: expectedPublicInputs.emailNullifier }), @@ -128,28 +130,4 @@ library HandleCommandTestFixture { } return publicInputs; } - - function _getLastWord(string memory input) private pure returns (string memory) { - bytes memory strBytes = bytes(input); - uint256 len = strBytes.length; - uint256 start = len; - - // Iterate backwards to find the last space character - for (uint256 i = len; i > 0; i--) { - if (strBytes[i - 1] == 0x20) { - // 0x20 is the ASCII for space - start = i; - break; - } - } - - // Copy the last word to a new bytes array - uint256 wordLen = len - start; - bytes memory lastWordBytes = new bytes(wordLen); - for (uint256 i = 0; i < wordLen; i++) { - lastWordBytes[i] = strBytes[start + i]; - } - - return string(lastWordBytes); - } } diff --git a/test/fixtures/redditHandleCommand/RedditHandleCommandTestFixture.sol b/test/fixtures/redditHandleCommand/RedditHandleCommandTestFixture.sol index 168fb6c..1b52975 100644 --- a/test/fixtures/redditHandleCommand/RedditHandleCommandTestFixture.sol +++ b/test/fixtures/redditHandleCommand/RedditHandleCommandTestFixture.sol @@ -5,6 +5,7 @@ import { Vm } from "forge-std/Vm.sol"; import { LinkHandleCommand, PublicInputs } from "../../../src/verifiers/HandleVerifier.sol"; import { ClaimHandleCommand } from "../../../src/verifiers/ClaimHandleCommandVerifier.sol"; import { TextRecord } from "../../../src/entrypoints/LinkTextRecordEntrypoint.sol"; +import { TestStringUtils } from "../../utils/TestStringUtils.sol"; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; address constant _VM_ADDR = address(uint160(uint256(keccak256("hevm cheat code")))); @@ -24,7 +25,7 @@ library RedditHandleCommandTestFixture { _getExpectedPublicInputs(string.concat(path, "files/claimReddit/expected_public_inputs.json")); command = ClaimHandleCommand({ - target: Strings.parseAddress(_getLastWord(expectedPublicInputs.command)), + target: Strings.parseAddress(TestStringUtils.getNthWord(expectedPublicInputs.command, -1)), proof: abi.encodePacked(_getProofFieldsFromBinary(string.concat(path, "files/claimReddit/proof"))), publicInputs: expectedPublicInputs }); @@ -44,7 +45,8 @@ library RedditHandleCommandTestFixture { command = LinkHandleCommand({ textRecord: TextRecord({ - ensName: _getLastWord(expectedPublicInputs.command), + platformName: TestStringUtils.getNthWord(expectedPublicInputs.command, 2), + ensName: TestStringUtils.getNthWord(expectedPublicInputs.command, -1), value: expectedPublicInputs.handle, nullifier: expectedPublicInputs.emailNullifier }), @@ -131,28 +133,4 @@ library RedditHandleCommandTestFixture { } return publicInputs; } - - function _getLastWord(string memory input) private pure returns (string memory) { - bytes memory strBytes = bytes(input); - uint256 len = strBytes.length; - uint256 start = len; - - // Iterate backwards to find the last space character - for (uint256 i = len; i > 0; i--) { - if (strBytes[i - 1] == 0x20) { - // 0x20 is the ASCII for space - start = i; - break; - } - } - - // Copy the last word to a new bytes array - uint256 wordLen = len - start; - bytes memory lastWordBytes = new bytes(wordLen); - for (uint256 i = 0; i < wordLen; i++) { - lastWordBytes[i] = strBytes[start + i]; - } - - return string(lastWordBytes); - } } diff --git a/test/src/entrypoints/LinkHandleEntrypoint/LinkHandleEntrypoint.t.sol b/test/src/entrypoints/LinkHandleEntrypoint/LinkHandleEntrypoint.t.sol index c375ef9..6251c03 100644 --- a/test/src/entrypoints/LinkHandleEntrypoint/LinkHandleEntrypoint.t.sol +++ b/test/src/entrypoints/LinkHandleEntrypoint/LinkHandleEntrypoint.t.sol @@ -14,6 +14,8 @@ import { IDKIMRegistry } from "@zk-email/contracts/interfaces/IERC7969.sol"; contract LinkHandleVerifierTest is Test { using EnsUtils for bytes; + string public constant KEY_NAME = "com.platform-domain"; + LinkHandleCommandVerifier public verifier; LinkHandleEntrypointHelper public linkHandle; @@ -30,7 +32,7 @@ contract LinkHandleVerifierTest is Test { abi.encode(true) ); verifier = new LinkHandleCommandVerifier(address(new HonkVerifier()), dkimRegistry); - linkHandle = new LinkHandleEntrypointHelper(address(verifier)); + linkHandle = new LinkHandleEntrypointHelper(address(verifier), KEY_NAME); } function test_entrypoint_correctlyEncodesAndValidatesCommand() public { @@ -59,7 +61,7 @@ contract LinkHandleVerifierTest is Test { bytes memory encodedCommand = linkHandle.encode(command.proof, expectedPublicInputs); linkHandle.entrypoint(encodedCommand); assertEq( - linkHandle.verifyTextRecord(bytes(command.textRecord.ensName).namehash(), "com.twitter", "incorrect"), false + linkHandle.verifyTextRecord(bytes(command.textRecord.ensName).namehash(), KEY_NAME, "incorrect"), false ); } @@ -70,7 +72,7 @@ contract LinkHandleVerifierTest is Test { linkHandle.entrypoint(encodedCommand); assertEq( linkHandle.verifyTextRecord( - bytes(command.textRecord.ensName).namehash(), "com.twitter", command.textRecord.value + bytes(command.textRecord.ensName).namehash(), KEY_NAME, command.textRecord.value ), true ); diff --git a/test/src/entrypoints/LinkHandleEntrypoint/_LinkHandleEntrypointHelper.sol b/test/src/entrypoints/LinkHandleEntrypoint/_LinkHandleEntrypointHelper.sol index 35f7435..ff95ae7 100644 --- a/test/src/entrypoints/LinkHandleEntrypoint/_LinkHandleEntrypointHelper.sol +++ b/test/src/entrypoints/LinkHandleEntrypoint/_LinkHandleEntrypointHelper.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.30; import { LinkHandleEntrypoint } from "../../../../src/entrypoints/LinkHandleEntrypoint.sol"; contract LinkHandleEntrypointHelper is LinkHandleEntrypoint { - constructor(address verifier) LinkHandleEntrypoint(verifier) { } + constructor(address verifier, string memory keyName) LinkHandleEntrypoint(verifier, keyName) { } function isUsed(bytes32 nullifier) public view returns (bool) { return _isUsed[nullifier]; diff --git a/test/utils/TestStringUtils.sol b/test/utils/TestStringUtils.sol new file mode 100644 index 0000000..d95f6ab --- /dev/null +++ b/test/utils/TestStringUtils.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +library TestStringUtils { + error WordIndexOutOfBounds(); + + /** + * @notice Reads the nth word from a string. A word is defined as a sequence of characters separated by spaces. + * @param input The input string + * @param n The index of the word to return (0-indexed). Negative values are supported, where -1 is the last word, + * -2 the second to last, etc. + * @return word The nth word + */ + function getNthWord(string memory input, int256 n) internal pure returns (string memory) { + bytes memory strBytes = bytes(input); + uint256 targetIndex = _resolveTargetIndex(strBytes, n); + return _extractWord(strBytes, targetIndex); + } + + function _countWords(bytes memory strBytes) private pure returns (uint256 wordCount) { + uint256 length = strBytes.length; + bool inWord = false; + + for (uint256 i = 0; i <= length; i++) { + if (i == length || strBytes[i] == 0x20) { + if (inWord) { + wordCount++; + inWord = false; + } + } else if (!inWord) { + inWord = true; + } + } + } + + function _resolveTargetIndex(bytes memory strBytes, int256 n) private pure returns (uint256) { + uint256 wordCount = _countWords(strBytes); + + if (wordCount == 0) { + revert WordIndexOutOfBounds(); + } + + int256 targetIndexSigned; + if (n >= 0) { + if (uint256(n) >= wordCount) { + revert WordIndexOutOfBounds(); + } + targetIndexSigned = n; + } else { + // Negative index: -1 is last word, -2 is second to last, etc. + targetIndexSigned = int256(wordCount) + n; + if (targetIndexSigned < 0 || uint256(targetIndexSigned) >= wordCount) { + revert WordIndexOutOfBounds(); + } + } + + return uint256(targetIndexSigned); + } + + function _extractWord(bytes memory strBytes, uint256 targetIndex) private pure returns (string memory) { + uint256 length = strBytes.length; + uint256 wordStart = 0; + uint256 currentIndex = 0; + bool inWord = false; + + for (uint256 i = 0; i <= length; i++) { + if (i == length || strBytes[i] == 0x20) { + if (inWord) { + if (currentIndex == targetIndex) { + uint256 wordLength = i - wordStart; + bytes memory wordBytes = new bytes(wordLength); + for (uint256 j = 0; j < wordLength; j++) { + wordBytes[j] = strBytes[wordStart + j]; + } + return string(wordBytes); + } + currentIndex++; + inWord = false; + } + } else if (!inWord) { + inWord = true; + wordStart = i; + } + } + + revert WordIndexOutOfBounds(); + } +} + diff --git a/test/utils/TestStringUtils.t.sol b/test/utils/TestStringUtils.t.sol new file mode 100644 index 0000000..0242647 --- /dev/null +++ b/test/utils/TestStringUtils.t.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import { Test } from "forge-std/Test.sol"; +import { TestStringUtils } from "./TestStringUtils.sol"; +import { TestStringUtilsHelper } from "./_TestStringUtilsHelper.sol"; + +contract TestStringUtilsTest is Test { + TestStringUtilsHelper internal _helper = new TestStringUtilsHelper(); + + function test_getNthWord_outOfBoundsPositive_reverts() public { + string memory input = "a b"; + + vm.expectRevert(TestStringUtils.WordIndexOutOfBounds.selector); + _helper.callGetNthWord(input, 2); + } + + function test_getNthWord_outOfBoundsNegative_reverts() public { + string memory input = "a b"; + + vm.expectRevert(TestStringUtils.WordIndexOutOfBounds.selector); + _helper.callGetNthWord(input, -3); + } + + function test_getNthWord_emptyString_reverts() public { + string memory input = ""; + + vm.expectRevert(TestStringUtils.WordIndexOutOfBounds.selector); + _helper.callGetNthWord(input, 0); + } + + function test_getNthWord_positiveIndices() public view { + string memory input = "a b c"; + + assertEq(_helper.callGetNthWord(input, 0), "a"); + assertEq(_helper.callGetNthWord(input, 1), "b"); + assertEq(_helper.callGetNthWord(input, 2), "c"); + } + + function test_getNthWord_negativeIndices() public view { + string memory input = "a b c"; + + assertEq(_helper.callGetNthWord(input, -1), "c"); + assertEq(_helper.callGetNthWord(input, -2), "b"); + assertEq(_helper.callGetNthWord(input, -3), "a"); + } +} + diff --git a/test/utils/_TestStringUtilsHelper.sol b/test/utils/_TestStringUtilsHelper.sol new file mode 100644 index 0000000..299cabf --- /dev/null +++ b/test/utils/_TestStringUtilsHelper.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import { TestStringUtils } from "./TestStringUtils.sol"; + +contract TestStringUtilsHelper { + function callGetNthWord(string memory input, int256 n) external pure returns (string memory) { + return TestStringUtils.getNthWord(input, n); + } +} From 53e82ec16df0ddb1beb0b09849983231a1d030d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bence=20H=C3=A1romi?= <56651250+benceharomi@users.noreply.github.com> Date: Wed, 18 Feb 2026 16:33:03 +0000 Subject: [PATCH 02/11] feat: generic deployment script for link handle entrypoint --- .../DeployLinkHandleEntrypointDiscord.s.sol | 20 +++++++ .../DeployLinkHandleEntrypointTwitter.s.sol | 20 +++++++ .../_DeployLinkHandleEntrypoint.s.sol | 57 +++++++++++++++++++ script/DeployLinkHandleVerifier.s.sol | 27 --------- 4 files changed, 97 insertions(+), 27 deletions(-) create mode 100644 script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointDiscord.s.sol create mode 100644 script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol create mode 100644 script/DeployLinkHandleEntrypoint/_DeployLinkHandleEntrypoint.s.sol delete mode 100644 script/DeployLinkHandleVerifier.s.sol diff --git a/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointDiscord.s.sol b/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointDiscord.s.sol new file mode 100644 index 0000000..cf86c33 --- /dev/null +++ b/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointDiscord.s.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import { DeployLinkHandleEntrypointScript } from "./_DeployLinkHandleEntrypoint.s.sol"; +import { HonkVerifier } from "../../test/fixtures/handleCommand/HonkVerifier.sol"; + +contract DeployLinkHandleEntrypointTwitterScript is DeployLinkHandleEntrypointScript { + function _deployHonkVerifier() internal override returns (address) { + return address(new HonkVerifier()); + } + + function _dkimRegistry() internal pure override returns (address) { + // sepolia always valid dkim registry + return 0xc4f628496b8c474096650C8f9023954643cC614F; + } + + function _keyName() internal pure override returns (string memory) { + return "com.twitter"; + } +} diff --git a/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol b/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol new file mode 100644 index 0000000..cf86c33 --- /dev/null +++ b/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import { DeployLinkHandleEntrypointScript } from "./_DeployLinkHandleEntrypoint.s.sol"; +import { HonkVerifier } from "../../test/fixtures/handleCommand/HonkVerifier.sol"; + +contract DeployLinkHandleEntrypointTwitterScript is DeployLinkHandleEntrypointScript { + function _deployHonkVerifier() internal override returns (address) { + return address(new HonkVerifier()); + } + + function _dkimRegistry() internal pure override returns (address) { + // sepolia always valid dkim registry + return 0xc4f628496b8c474096650C8f9023954643cC614F; + } + + function _keyName() internal pure override returns (string memory) { + return "com.twitter"; + } +} diff --git a/script/DeployLinkHandleEntrypoint/_DeployLinkHandleEntrypoint.s.sol b/script/DeployLinkHandleEntrypoint/_DeployLinkHandleEntrypoint.s.sol new file mode 100644 index 0000000..0b309ff --- /dev/null +++ b/script/DeployLinkHandleEntrypoint/_DeployLinkHandleEntrypoint.s.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import { Script, console } from "forge-std/Script.sol"; +import { LinkHandleEntrypoint } from "../../src/entrypoints/LinkHandleEntrypoint.sol"; +import { LinkHandleCommandVerifier } from "../../src/verifiers/LinkHandleCommandVerifier.sol"; + +abstract contract DeployLinkHandleEntrypointScript is Script { + function run() external { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + vm.startBroadcast(deployerPrivateKey); + + console.log("\n=== Step 1: Deploy HonkVerifier ==="); + + address honkVerifier = _deployHonkVerifier(); + console.log("HonkVerifier deployed at:", address(honkVerifier)); + + console.log("\n=== Step 2: Deploy LinkHandleCommandVerifier ==="); + LinkHandleCommandVerifier commandVerifier = new LinkHandleCommandVerifier(honkVerifier, _dkimRegistry()); + console.log("LinkHandleCommandVerifier deployed at:", address(commandVerifier)); + + console.log("\n=== Step 3: Deploy LinkHandleEntrypoint ==="); + LinkHandleEntrypoint verifier = new LinkHandleEntrypoint(address(commandVerifier), _keyName()); + console.log("LinkHandleEntrypoint deployed at:", address(verifier)); + + vm.stopBroadcast(); + + console.log("\n=== Deployment Complete ==="); + console.log("HONK_VERIFIER=", address(honkVerifier)); + console.log("KEY_NAME=", _keyName()); + console.log("LINK_HANDLE_VERIFIER=", address(verifier)); + } + + /** + * @notice Deploys the HonkVerifier. This is needed because each platform has its own HonkVerifier generated from + * the circuit. + * @dev Example: return address(new HonkVerifier()); + * @return The address of the HonkVerifier + */ + function _deployHonkVerifier() internal virtual returns (address); + + /** + * @notice The DKIM registry address. + * @dev Example (sepolia): return 0xe24c24Ab94c93D5754De1cbE61b777e47cc57723; + * Example (sepolia always valid): return 0xc4f628496b8c474096650C8f9023954643cC614F; + * @return The address of the DKIM registry + */ + function _dkimRegistry() internal pure virtual returns (address); + + /** + * @notice The key name for the text record. + * @dev Example: return "com.twitter"; + * @return The key name for the text record + */ + function _keyName() internal pure virtual returns (string memory); +} diff --git a/script/DeployLinkHandleVerifier.s.sol b/script/DeployLinkHandleVerifier.s.sol deleted file mode 100644 index 63faa3e..0000000 --- a/script/DeployLinkHandleVerifier.s.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import { Script, console } from "forge-std/Script.sol"; -import { LinkHandleEntrypoint } from "../src/entrypoints/LinkHandleEntrypoint.sol"; -import { LinkHandleCommandVerifier } from "../src/verifiers/LinkHandleCommandVerifier.sol"; -import { HonkVerifier } from "../test/fixtures/handleCommand/HonkVerifier.sol"; - -contract DeployLinkHandleEntrypointScript is Script { - // sepolia - // address public constant DKIM_REGISTRY = 0xe24c24Ab94c93D5754De1cbE61b777e47cc57723; - // sepolia always valid dkim registry - address public constant DKIM_REGISTRY = 0xc4f628496b8c474096650C8f9023954643cC614F; - - function run() external { - uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); - - vm.startBroadcast(deployerPrivateKey); - - LinkHandleCommandVerifier commandVerifier = - new LinkHandleCommandVerifier(address(new HonkVerifier()), DKIM_REGISTRY); - LinkHandleEntrypoint verifier = new LinkHandleEntrypoint(address(commandVerifier), "com.twitter"); - vm.stopBroadcast(); - - console.log("LINK_HANDLE_VERIFIER=", address(verifier)); - } -} From a4fbb0fb60d95fb9dfd13ccfe5b97192107a7fc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bence=20H=C3=A1romi?= <56651250+benceharomi@users.noreply.github.com> Date: Wed, 18 Feb 2026 16:45:55 +0000 Subject: [PATCH 03/11] feat: added platform name check and renamed key to record --- .../DeployLinkHandleEntrypointTwitter.s.sol | 6 +++++- .../_DeployLinkHandleEntrypoint.s.sol | 18 +++++++++++------ src/entrypoints/LinkEmailEntrypoint.sol | 2 +- src/entrypoints/LinkHandleEntrypoint.sol | 12 ++++++++--- src/entrypoints/LinkTextRecordEntrypoint.sol | 18 ++++++++++++----- .../LinkHandleEntrypoint.t.sol | 20 +++++++++++++++---- .../_LinkHandleEntrypointHelper.sol | 8 +++++++- 7 files changed, 63 insertions(+), 21 deletions(-) diff --git a/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol b/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol index cf86c33..263f5c6 100644 --- a/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol +++ b/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol @@ -14,7 +14,11 @@ contract DeployLinkHandleEntrypointTwitterScript is DeployLinkHandleEntrypointSc return 0xc4f628496b8c474096650C8f9023954643cC614F; } - function _keyName() internal pure override returns (string memory) { + function _recordName() internal pure override returns (string memory) { return "com.twitter"; } + + function _platformName() internal pure override returns (string memory) { + return "x"; + } } diff --git a/script/DeployLinkHandleEntrypoint/_DeployLinkHandleEntrypoint.s.sol b/script/DeployLinkHandleEntrypoint/_DeployLinkHandleEntrypoint.s.sol index 0b309ff..1b13edd 100644 --- a/script/DeployLinkHandleEntrypoint/_DeployLinkHandleEntrypoint.s.sol +++ b/script/DeployLinkHandleEntrypoint/_DeployLinkHandleEntrypoint.s.sol @@ -21,14 +21,15 @@ abstract contract DeployLinkHandleEntrypointScript is Script { console.log("LinkHandleCommandVerifier deployed at:", address(commandVerifier)); console.log("\n=== Step 3: Deploy LinkHandleEntrypoint ==="); - LinkHandleEntrypoint verifier = new LinkHandleEntrypoint(address(commandVerifier), _keyName()); + LinkHandleEntrypoint verifier = + new LinkHandleEntrypoint(address(commandVerifier), _recordName(), _platformName()); console.log("LinkHandleEntrypoint deployed at:", address(verifier)); vm.stopBroadcast(); console.log("\n=== Deployment Complete ==="); console.log("HONK_VERIFIER=", address(honkVerifier)); - console.log("KEY_NAME=", _keyName()); + console.log("RECORD_NAME=", _recordName()); console.log("LINK_HANDLE_VERIFIER=", address(verifier)); } @@ -49,9 +50,14 @@ abstract contract DeployLinkHandleEntrypointScript is Script { function _dkimRegistry() internal pure virtual returns (address); /** - * @notice The key name for the text record. - * @dev Example: return "com.twitter"; - * @return The key name for the text record + * @notice ENS text record name (e.g. "com.twitter") — the key in setText(node, key, value). + * @return The record name for the text record */ - function _keyName() internal pure virtual returns (string memory); + function _recordName() internal pure virtual returns (string memory); + + /** + * @notice The platform name in the command (e.g. "x"). + * @return The platform name used in the command + */ + function _platformName() internal pure virtual returns (string memory); } diff --git a/src/entrypoints/LinkEmailEntrypoint.sol b/src/entrypoints/LinkEmailEntrypoint.sol index 4edfa27..7d43c4a 100644 --- a/src/entrypoints/LinkEmailEntrypoint.sol +++ b/src/entrypoints/LinkEmailEntrypoint.sol @@ -10,7 +10,7 @@ import { LinkEmailCommand } from "../verifiers/LinkEmailCommandVerifier.sol"; * @dev The verifier can be updated via the entrypoint function. */ contract LinkEmailEntrypoint is LinkTextRecordEntrypoint { - constructor(address verifier) LinkTextRecordEntrypoint(verifier, "email") { } + constructor(address verifier) LinkTextRecordEntrypoint(verifier, "email", "email") { } /** * @inheritdoc LinkTextRecordEntrypoint diff --git a/src/entrypoints/LinkHandleEntrypoint.sol b/src/entrypoints/LinkHandleEntrypoint.sol index 0cbb62f..6307b41 100644 --- a/src/entrypoints/LinkHandleEntrypoint.sol +++ b/src/entrypoints/LinkHandleEntrypoint.sol @@ -13,10 +13,16 @@ contract LinkHandleEntrypoint is LinkTextRecordEntrypoint { /** * @notice Constructor * @param verifier The LinkHandleCommandVerifier contract address - * @param keyName The key name for the text record (e.g. "com.twitter") - * @dev The key name is used to identify the text record in the mapping + * @param recordName ENS text record name (e.g. "com.twitter") — the key in setText(node, key, value) + * @param platformName The platform name in the command (e.g. "Twitter") */ - constructor(address verifier, string memory keyName) LinkTextRecordEntrypoint(verifier, keyName) { } + constructor( + address verifier, + string memory recordName, + string memory platformName + ) + LinkTextRecordEntrypoint(verifier, recordName, platformName) + { } /** * @inheritdoc LinkTextRecordEntrypoint diff --git a/src/entrypoints/LinkTextRecordEntrypoint.sol b/src/entrypoints/LinkTextRecordEntrypoint.sol index 2a93a32..c6374a8 100644 --- a/src/entrypoints/LinkTextRecordEntrypoint.sol +++ b/src/entrypoints/LinkTextRecordEntrypoint.sol @@ -21,7 +21,8 @@ struct TextRecord { abstract contract LinkTextRecordEntrypoint is IEntryPoint, ITextRecordVerifier { using EnsUtils for bytes; - bytes32 private immutable _KEY; + bytes32 private immutable _recordNameHash; + bytes32 private immutable _platformNameHash; // link text record command verifier address public immutable VERIFIER; @@ -35,9 +36,12 @@ abstract contract LinkTextRecordEntrypoint is IEntryPoint, ITextRecordVerifier { error InvalidCommand(); error NullifierUsed(); - constructor(address verifier, string memory keyName) { + /// @param recordName ENS text record name (e.g. "com.twitter") — the key in setText(node, key, value) + /// @param platformName Platform name in the command (e.g. "x") + constructor(address verifier, string memory recordName, string memory platformName) { VERIFIER = verifier; - _KEY = keccak256(bytes(keyName)); + _recordNameHash = keccak256(bytes(recordName)); + _platformNameHash = bytes(platformName).length == 0 ? bytes32(0) : keccak256(bytes(platformName)); } /** @@ -48,6 +52,10 @@ abstract contract LinkTextRecordEntrypoint is IEntryPoint, ITextRecordVerifier { function entrypoint(bytes memory data) external { TextRecord memory record = _extractTextRecord(data); + if (_platformNameHash != bytes32(0) && keccak256(bytes(record.platformName)) != _platformNameHash) { + revert InvalidCommand(); + } + if (_isUsed[record.nullifier]) { revert NullifierUsed(); } @@ -82,8 +90,8 @@ abstract contract LinkTextRecordEntrypoint is IEntryPoint, ITextRecordVerifier { * @inheritdoc ITextRecordVerifier */ function verifyTextRecord(bytes32 node, string memory key, string memory value) external view returns (bool) { - // this verifier only supports this specific text record - if (keccak256(bytes(key)) != _KEY) { + // this verifier only supports this specific text record (key must match constructor recordName) + if (keccak256(bytes(key)) != _recordNameHash) { revert UnsupportedKey(); } string memory storedTextRecord = textRecord[node]; diff --git a/test/src/entrypoints/LinkHandleEntrypoint/LinkHandleEntrypoint.t.sol b/test/src/entrypoints/LinkHandleEntrypoint/LinkHandleEntrypoint.t.sol index 6251c03..680f8c4 100644 --- a/test/src/entrypoints/LinkHandleEntrypoint/LinkHandleEntrypoint.t.sol +++ b/test/src/entrypoints/LinkHandleEntrypoint/LinkHandleEntrypoint.t.sol @@ -14,7 +14,8 @@ import { IDKIMRegistry } from "@zk-email/contracts/interfaces/IERC7969.sol"; contract LinkHandleVerifierTest is Test { using EnsUtils for bytes; - string public constant KEY_NAME = "com.platform-domain"; + string public constant RECORD_NAME = "com.twitter"; + string public constant PLATFORM_NAME = "x"; LinkHandleCommandVerifier public verifier; LinkHandleEntrypointHelper public linkHandle; @@ -32,7 +33,7 @@ contract LinkHandleVerifierTest is Test { abi.encode(true) ); verifier = new LinkHandleCommandVerifier(address(new HonkVerifier()), dkimRegistry); - linkHandle = new LinkHandleEntrypointHelper(address(verifier), KEY_NAME); + linkHandle = new LinkHandleEntrypointHelper(address(verifier), RECORD_NAME, PLATFORM_NAME); } function test_entrypoint_correctlyEncodesAndValidatesCommand() public { @@ -55,13 +56,24 @@ contract LinkHandleVerifierTest is Test { linkHandle.entrypoint(encodedCommand); } + function test_entrypoint_revertsWhenPlatformNameMismatch() public { + (LinkHandleCommand memory command, bytes32[] memory expectedPublicInputs) = + HandleCommandTestFixture.getLinkXFixture(); + // Entrypoint configured for "discord" but command has platformName "x" (from fixture) + LinkHandleEntrypointHelper discordEntrypoint = + new LinkHandleEntrypointHelper(address(verifier), RECORD_NAME, "discord"); + bytes memory encodedCommand = discordEntrypoint.encode(command.proof, expectedPublicInputs); + vm.expectRevert(abi.encodeWithSelector(LinkTextRecordEntrypoint.InvalidCommand.selector)); + discordEntrypoint.entrypoint(encodedCommand); + } + function test_verifyTextRecord_returnsFalseWhenTextRecordIsIncorrect() public { (LinkHandleCommand memory command, bytes32[] memory expectedPublicInputs) = HandleCommandTestFixture.getLinkXFixture(); bytes memory encodedCommand = linkHandle.encode(command.proof, expectedPublicInputs); linkHandle.entrypoint(encodedCommand); assertEq( - linkHandle.verifyTextRecord(bytes(command.textRecord.ensName).namehash(), KEY_NAME, "incorrect"), false + linkHandle.verifyTextRecord(bytes(command.textRecord.ensName).namehash(), RECORD_NAME, "incorrect"), false ); } @@ -72,7 +84,7 @@ contract LinkHandleVerifierTest is Test { linkHandle.entrypoint(encodedCommand); assertEq( linkHandle.verifyTextRecord( - bytes(command.textRecord.ensName).namehash(), KEY_NAME, command.textRecord.value + bytes(command.textRecord.ensName).namehash(), RECORD_NAME, command.textRecord.value ), true ); diff --git a/test/src/entrypoints/LinkHandleEntrypoint/_LinkHandleEntrypointHelper.sol b/test/src/entrypoints/LinkHandleEntrypoint/_LinkHandleEntrypointHelper.sol index ff95ae7..070fb56 100644 --- a/test/src/entrypoints/LinkHandleEntrypoint/_LinkHandleEntrypointHelper.sol +++ b/test/src/entrypoints/LinkHandleEntrypoint/_LinkHandleEntrypointHelper.sol @@ -4,7 +4,13 @@ pragma solidity ^0.8.30; import { LinkHandleEntrypoint } from "../../../../src/entrypoints/LinkHandleEntrypoint.sol"; contract LinkHandleEntrypointHelper is LinkHandleEntrypoint { - constructor(address verifier, string memory keyName) LinkHandleEntrypoint(verifier, keyName) { } + constructor( + address verifier, + string memory recordName, + string memory platformName + ) + LinkHandleEntrypoint(verifier, recordName, platformName) + { } function isUsed(bytes32 nullifier) public view returns (bool) { return _isUsed[nullifier]; From ead64bbfd5ee4789c0e68136bd3ac1b367107ac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bence=20H=C3=A1romi?= <56651250+benceharomi@users.noreply.github.com> Date: Wed, 18 Feb 2026 16:57:32 +0000 Subject: [PATCH 04/11] chore: small script changes --- .../DeployLinkHandleEntrypointTwitter.s.sol | 12 ++--- .../_DeployLinkHandleEntrypoint.s.sol | 50 +++++++++---------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol b/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol index 263f5c6..8868593 100644 --- a/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol +++ b/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol @@ -5,20 +5,20 @@ import { DeployLinkHandleEntrypointScript } from "./_DeployLinkHandleEntrypoint. import { HonkVerifier } from "../../test/fixtures/handleCommand/HonkVerifier.sol"; contract DeployLinkHandleEntrypointTwitterScript is DeployLinkHandleEntrypointScript { - function _deployHonkVerifier() internal override returns (address) { + function _getHonkVerifierAddress() internal override returns (address) { return address(new HonkVerifier()); } - function _dkimRegistry() internal pure override returns (address) { + function _getDkimRegistryAddress() internal pure override returns (address) { // sepolia always valid dkim registry return 0xc4f628496b8c474096650C8f9023954643cC614F; } - function _recordName() internal pure override returns (string memory) { - return "com.twitter"; + function _getPlatformName() internal pure override returns (string memory) { + return "x"; } - function _platformName() internal pure override returns (string memory) { - return "x"; + function _getRecordName() internal pure override returns (string memory) { + return "com.twitter"; } } diff --git a/script/DeployLinkHandleEntrypoint/_DeployLinkHandleEntrypoint.s.sol b/script/DeployLinkHandleEntrypoint/_DeployLinkHandleEntrypoint.s.sol index 1b13edd..902d30a 100644 --- a/script/DeployLinkHandleEntrypoint/_DeployLinkHandleEntrypoint.s.sol +++ b/script/DeployLinkHandleEntrypoint/_DeployLinkHandleEntrypoint.s.sol @@ -11,35 +11,35 @@ abstract contract DeployLinkHandleEntrypointScript is Script { vm.startBroadcast(deployerPrivateKey); - console.log("\n=== Step 1: Deploy HonkVerifier ==="); - - address honkVerifier = _deployHonkVerifier(); - console.log("HonkVerifier deployed at:", address(honkVerifier)); - - console.log("\n=== Step 2: Deploy LinkHandleCommandVerifier ==="); - LinkHandleCommandVerifier commandVerifier = new LinkHandleCommandVerifier(honkVerifier, _dkimRegistry()); + console.log("\n=== Step 1: Deploy LinkHandleCommandVerifier ==="); + LinkHandleCommandVerifier commandVerifier = + new LinkHandleCommandVerifier(_getHonkVerifierAddress(), _getDkimRegistryAddress()); console.log("LinkHandleCommandVerifier deployed at:", address(commandVerifier)); - console.log("\n=== Step 3: Deploy LinkHandleEntrypoint ==="); - LinkHandleEntrypoint verifier = - new LinkHandleEntrypoint(address(commandVerifier), _recordName(), _platformName()); - console.log("LinkHandleEntrypoint deployed at:", address(verifier)); + console.log("\n=== Step 2: Deploy LinkHandleEntrypoint ==="); + LinkHandleEntrypoint entrypoint = + new LinkHandleEntrypoint(address(commandVerifier), _getRecordName(), _getPlatformName()); + console.log("LinkHandleEntrypoint deployed at:", address(entrypoint)); vm.stopBroadcast(); console.log("\n=== Deployment Complete ==="); - console.log("HONK_VERIFIER=", address(honkVerifier)); - console.log("RECORD_NAME=", _recordName()); - console.log("LINK_HANDLE_VERIFIER=", address(verifier)); + console.log("HONK_VERIFIER=", _getHonkVerifierAddress()); + console.log("DKIM_REGISTRY=", _getDkimRegistryAddress()); + console.log("LINK_HANDLE_COMMAND_VERIFIER=", address(commandVerifier)); + console.log("RECORD_NAME=", _getRecordName()); + console.log("PLATFORM_NAME=", _getPlatformName()); + console.log("LINK_HANDLE_ENTRYPOINT=", address(entrypoint)); } /** - * @notice Deploys the HonkVerifier. This is needed because each platform has its own HonkVerifier generated from - * the circuit. - * @dev Example: return address(new HonkVerifier()); + * @notice The HonkVerifier address. + * @dev TODO: ideally ths would be pure and would only return the address of the HonkVerifier deployed by the + * registry. Currently this is deployed inside this function. Remove it once the registry deploys the + * HonkVerifier. * @return The address of the HonkVerifier */ - function _deployHonkVerifier() internal virtual returns (address); + function _getHonkVerifierAddress() internal virtual returns (address); /** * @notice The DKIM registry address. @@ -47,17 +47,17 @@ abstract contract DeployLinkHandleEntrypointScript is Script { * Example (sepolia always valid): return 0xc4f628496b8c474096650C8f9023954643cC614F; * @return The address of the DKIM registry */ - function _dkimRegistry() internal pure virtual returns (address); + function _getDkimRegistryAddress() internal pure virtual returns (address); /** - * @notice ENS text record name (e.g. "com.twitter") — the key in setText(node, key, value). - * @return The record name for the text record + * @notice The platform name in the command (e.g. "x"). + * @return The platform name used in the command */ - function _recordName() internal pure virtual returns (string memory); + function _getPlatformName() internal pure virtual returns (string memory); /** - * @notice The platform name in the command (e.g. "x"). - * @return The platform name used in the command + * @notice ENS text record name (e.g. "com.twitter") — the key in setText(node, key, value). + * @return The record name for the text record */ - function _platformName() internal pure virtual returns (string memory); + function _getRecordName() internal pure virtual returns (string memory); } From 54f1245e839b2637afbf165373ce8bf1ca39385b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bence=20H=C3=A1romi?= <56651250+benceharomi@users.noreply.github.com> Date: Wed, 18 Feb 2026 17:43:16 +0000 Subject: [PATCH 05/11] chore: organized linkHandleCommand fixtures --- .gitignore | 4 +- .prettierignore | 5 +- foundry.toml | 5 +- script/DeployAllDiscord.s.sol | 2 +- script/DeployAllX.s.sol | 2 +- script/DeployHandleRegistrar.s.sol | 2 +- .../DeployLinkHandleEntrypointTwitter.s.sol | 2 +- script/LinkHandleWithFixture.s.sol | 4 +- .../HandleCommandTestFixture.sol | 23 +- .../LinkHandleCommandTestFixture.sol | 88 + test/fixtures/linkHandleCommand/clean.sh | 21 + test/fixtures/linkHandleCommand/compile.sh | 74 + test/fixtures/linkHandleCommand/prove.sh | 97 + .../linkHandleCommand/twitter/Nargo.toml | 10 + .../twitter/Prover.sample.toml | 40 + .../twitter/files}/email.eml | 0 .../files}/expected_public_inputs.json | 0 .../twitter/files}/proof | Bin .../twitter/files}/public_inputs | Bin .../twitter/raw_inputs.sample.json | 3 + .../linkHandleCommand/twitter/src/main.nr | 85 + .../twitter/src/sender_domain_regex.nr | 229 ++ .../twitter/src/x_handle_regex.nr | 167 ++ .../twitter/target/HonkVerifier.sol | 1883 +++++++++++++++++ .../HandleRegistrar/_HandleRegistrarTest.sol | 2 +- .../LinkHandleEntrypoint.t.sol | 16 +- .../HandleResolver/HandleResolver.t.sol | 2 +- .../ResolverRegistrarIntegration.t.sol | 2 +- .../ClaimHandleCommandVerifier/Encode.t.sol | 2 +- .../ClaimHandleCommandVerifier/IsValid.t.sol | 2 +- .../LinkHandleCommandVerifier/Encode.t.sol | 6 +- .../LinkHandleCommandVerifier/IsValid.t.sol | 14 +- .../PackPublicInputs.t.sol | 4 +- 33 files changed, 2736 insertions(+), 60 deletions(-) create mode 100644 test/fixtures/linkHandleCommand/LinkHandleCommandTestFixture.sol create mode 100755 test/fixtures/linkHandleCommand/clean.sh create mode 100755 test/fixtures/linkHandleCommand/compile.sh create mode 100755 test/fixtures/linkHandleCommand/prove.sh create mode 100644 test/fixtures/linkHandleCommand/twitter/Nargo.toml create mode 100644 test/fixtures/linkHandleCommand/twitter/Prover.sample.toml rename test/fixtures/{handleCommand/files/linkX => linkHandleCommand/twitter/files}/email.eml (100%) rename test/fixtures/{handleCommand/files/linkX => linkHandleCommand/twitter/files}/expected_public_inputs.json (100%) rename test/fixtures/{handleCommand/files/linkX => linkHandleCommand/twitter/files}/proof (100%) rename test/fixtures/{handleCommand/files/linkX => linkHandleCommand/twitter/files}/public_inputs (100%) create mode 100644 test/fixtures/linkHandleCommand/twitter/raw_inputs.sample.json create mode 100644 test/fixtures/linkHandleCommand/twitter/src/main.nr create mode 100644 test/fixtures/linkHandleCommand/twitter/src/sender_domain_regex.nr create mode 100644 test/fixtures/linkHandleCommand/twitter/src/x_handle_regex.nr create mode 100644 test/fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol diff --git a/.gitignore b/.gitignore index 31de14b..1b490e6 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,6 @@ lcov.info Prover.toml raw_inputs.json -target/ \ No newline at end of file +# ignore target dir contents but keep generated .sol verifiers (e.g. HonkVerifier.sol) +**/target/* +!**/target/*.sol \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index 7c11bf4..9fd606d 100644 --- a/.prettierignore +++ b/.prettierignore @@ -7,9 +7,8 @@ coverage/ node_modules/ out/ -# circuit generated files -test/fixtures/handleCommand/circuit/target -test/fixtures/redditHandleCommand/circuit/target +# ignore circuit generated files (target directories under fixtures) +test/fixtures/**/target # files .env diff --git a/foundry.toml b/foundry.toml index 77fa593..b716d88 100644 --- a/foundry.toml +++ b/foundry.toml @@ -26,7 +26,6 @@ quote_style = "double" tab_width = 4 wrap_comments = true ignore = [ - # ignore circuit generated files - "test/fixtures/handleCommand/circuit/target/*.sol", - "test/fixtures/redditHandleCommand/circuit/target/*.sol", + # ignore circuit generated files (target directories under fixtures) + "test/fixtures/**/target/*.sol", ] diff --git a/script/DeployAllDiscord.s.sol b/script/DeployAllDiscord.s.sol index 6af00d1..efb0a1e 100644 --- a/script/DeployAllDiscord.s.sol +++ b/script/DeployAllDiscord.s.sol @@ -5,7 +5,7 @@ import { Script, console } from "forge-std/Script.sol"; import { HandleRegistrar } from "../src/entrypoints/HandleRegistrar.sol"; import { HandleResolver } from "../src/resolvers/HandleResolver.sol"; import { ClaimHandleCommandVerifier } from "../src/verifiers/ClaimHandleCommandVerifier.sol"; -import { HonkVerifier } from "../test/fixtures/handleCommand/HonkVerifier.sol"; +import { HonkVerifier } from "../test/fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol"; import { EnsUtils } from "../src/utils/EnsUtils.sol"; contract DeployAllDiscordScript is Script { diff --git a/script/DeployAllX.s.sol b/script/DeployAllX.s.sol index a1fe7e1..06a541a 100644 --- a/script/DeployAllX.s.sol +++ b/script/DeployAllX.s.sol @@ -5,7 +5,7 @@ import { Script, console } from "forge-std/Script.sol"; import { HandleRegistrar } from "../src/entrypoints/HandleRegistrar.sol"; import { HandleResolver } from "../src/resolvers/HandleResolver.sol"; import { ClaimHandleCommandVerifier } from "../src/verifiers/ClaimHandleCommandVerifier.sol"; -import { HonkVerifier } from "../test/fixtures/handleCommand/HonkVerifier.sol"; +import { HonkVerifier } from "../test/fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol"; import { EnsUtils } from "../src/utils/EnsUtils.sol"; contract DeployAllXScript is Script { diff --git a/script/DeployHandleRegistrar.s.sol b/script/DeployHandleRegistrar.s.sol index db29a44..8c431e6 100644 --- a/script/DeployHandleRegistrar.s.sol +++ b/script/DeployHandleRegistrar.s.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.30; import { Script, console } from "forge-std/Script.sol"; import { HandleRegistrar } from "../src/entrypoints/HandleRegistrar.sol"; import { ClaimHandleCommandVerifier } from "../src/verifiers/ClaimHandleCommandVerifier.sol"; -import { HonkVerifier } from "../test/fixtures/handleCommand/HonkVerifier.sol"; +import { HonkVerifier } from "../test/fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol"; import { EnsUtils } from "../src/utils/EnsUtils.sol"; contract DeployHandleRegistrarScript is Script { diff --git a/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol b/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol index 8868593..0534709 100644 --- a/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol +++ b/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.30; import { DeployLinkHandleEntrypointScript } from "./_DeployLinkHandleEntrypoint.s.sol"; -import { HonkVerifier } from "../../test/fixtures/handleCommand/HonkVerifier.sol"; +import { HonkVerifier } from "../../test/fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol"; contract DeployLinkHandleEntrypointTwitterScript is DeployLinkHandleEntrypointScript { function _getHonkVerifierAddress() internal override returns (address) { diff --git a/script/LinkHandleWithFixture.s.sol b/script/LinkHandleWithFixture.s.sol index e9aa218..dc90c2a 100644 --- a/script/LinkHandleWithFixture.s.sol +++ b/script/LinkHandleWithFixture.s.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.30; import { Script } from "forge-std/Script.sol"; import { LinkHandleEntrypoint } from "../src/entrypoints/LinkHandleEntrypoint.sol"; import { LinkHandleCommand } from "../src/verifiers/HandleVerifier.sol"; -import { HandleCommandTestFixture } from "../test/fixtures/handleCommand/HandleCommandTestFixture.sol"; +import { LinkHandleCommandTestFixture } from "../test/fixtures/linkHandleCommand/LinkHandleCommandTestFixture.sol"; contract LinkHandleWithFixtureScript is Script { // sepolia mock @@ -16,7 +16,7 @@ contract LinkHandleWithFixtureScript is Script { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); LinkHandleEntrypoint verifier = LinkHandleEntrypoint(LINK_X_HANDLE_VERIFIER); - (LinkHandleCommand memory command,) = HandleCommandTestFixture.getLinkXFixture(); + (LinkHandleCommand memory command,) = LinkHandleCommandTestFixture.getTwitterFixture(); vm.startBroadcast(deployerPrivateKey); diff --git a/test/fixtures/handleCommand/HandleCommandTestFixture.sol b/test/fixtures/handleCommand/HandleCommandTestFixture.sol index cd725d9..6db9afc 100644 --- a/test/fixtures/handleCommand/HandleCommandTestFixture.sol +++ b/test/fixtures/handleCommand/HandleCommandTestFixture.sol @@ -2,9 +2,8 @@ pragma solidity ^0.8.30; import { Vm } from "forge-std/Vm.sol"; -import { LinkHandleCommand, PublicInputs } from "../../../src/verifiers/HandleVerifier.sol"; +import { PublicInputs } from "../../../src/verifiers/HandleVerifier.sol"; import { ClaimHandleCommand } from "../../../src/verifiers/ClaimHandleCommandVerifier.sol"; -import { TextRecord } from "../../../src/entrypoints/LinkTextRecordEntrypoint.sol"; import { TestStringUtils } from "../../utils/TestStringUtils.sol"; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; @@ -33,26 +32,6 @@ library HandleCommandTestFixture { return (command, _getPublicInputsFieldsFromBinary(string.concat(path, "files/claimX/public_inputs"))); } - function getLinkXFixture() internal view returns (LinkHandleCommand memory command, bytes32[] memory publicInputs) { - string memory path = string.concat(vm.projectRoot(), "/test/fixtures/handleCommand/"); - - PublicInputs memory expectedPublicInputs = - _getExpectedPublicInputs(string.concat(path, "files/linkX/expected_public_inputs.json")); - - command = LinkHandleCommand({ - textRecord: TextRecord({ - platformName: TestStringUtils.getNthWord(expectedPublicInputs.command, 2), - ensName: TestStringUtils.getNthWord(expectedPublicInputs.command, -1), - value: expectedPublicInputs.handle, - nullifier: expectedPublicInputs.emailNullifier - }), - proof: abi.encodePacked(_getProofFieldsFromBinary(string.concat(path, "files/linkX/proof"))), - publicInputs: expectedPublicInputs - }); - - return (command, _getPublicInputsFieldsFromBinary(string.concat(path, "files/linkX/public_inputs"))); - } - /** * @notice Reads the expected pub signals from a `expected_public_inputs.json` file (PublicInputs struct object) * @param path Path to the file with the expected public inputs diff --git a/test/fixtures/linkHandleCommand/LinkHandleCommandTestFixture.sol b/test/fixtures/linkHandleCommand/LinkHandleCommandTestFixture.sol new file mode 100644 index 0000000..2b958b9 --- /dev/null +++ b/test/fixtures/linkHandleCommand/LinkHandleCommandTestFixture.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import { Vm } from "forge-std/Vm.sol"; +import { LinkHandleCommand, PublicInputs } from "../../../src/verifiers/HandleVerifier.sol"; +import { TextRecord } from "../../../src/entrypoints/LinkTextRecordEntrypoint.sol"; +import { TestStringUtils } from "../../utils/TestStringUtils.sol"; + +address constant _LINK_HANDLE_VM_ADDR = address(uint160(uint256(keccak256("hevm cheat code")))); +Vm constant linkHandleVm = Vm(_LINK_HANDLE_VM_ADDR); + +/** + * @title LinkHandleCommandTestFixture + * @notice Provides link-handle command fixtures per platform (e.g. Twitter/X). + * @dev Each platform has a dedicated getter; add fixture data under test/fixtures/linkHandleCommand//files/ + * (expected_public_inputs.json, proof, public_inputs, email.eml) to enable that platform. + */ +library LinkHandleCommandTestFixture { + function getTwitterFixture() + internal + view + returns (LinkHandleCommand memory command, bytes32[] memory publicInputs) + { + return getFixture("twitter"); + } + + /** + * @notice Load link-handle fixture for a given platform subdir (e.g. "twitter", "discord"). + * @param platform Subdir name under test/fixtures/linkHandleCommand/ + */ + function getFixture(string memory platform) + internal + view + returns (LinkHandleCommand memory command, bytes32[] memory publicInputs) + { + string memory path = + string.concat(linkHandleVm.projectRoot(), "/test/fixtures/linkHandleCommand/", platform, "/"); + + PublicInputs memory expectedPublicInputs = + _getExpectedPublicInputs(string.concat(path, "files/expected_public_inputs.json")); + + command = LinkHandleCommand({ + textRecord: TextRecord({ + platformName: TestStringUtils.getNthWord(expectedPublicInputs.command, 2), + ensName: TestStringUtils.getNthWord(expectedPublicInputs.command, -1), + value: expectedPublicInputs.handle, + nullifier: expectedPublicInputs.emailNullifier + }), + proof: abi.encodePacked(_getProofFieldsFromBinary(string.concat(path, "files/proof"))), + publicInputs: expectedPublicInputs + }); + + return (command, _getPublicInputsFieldsFromBinary(string.concat(path, "files/public_inputs"))); + } + + function _getExpectedPublicInputs(string memory path) private view returns (PublicInputs memory publicInputs) { + string memory publicInputsFile = linkHandleVm.readFile(path); + return PublicInputs({ + pubkeyHash: abi.decode(linkHandleVm.parseJson(publicInputsFile, ".pubkeyHash"), (bytes32)), + emailNullifier: abi.decode(linkHandleVm.parseJson(publicInputsFile, ".emailNullifier"), (bytes32)), + headerHash: abi.decode(linkHandleVm.parseJson(publicInputsFile, ".headerHash"), (bytes32)), + proverAddress: abi.decode(linkHandleVm.parseJson(publicInputsFile, ".proverAddress"), (address)), + command: abi.decode(linkHandleVm.parseJson(publicInputsFile, ".command"), (string)), + handle: abi.decode(linkHandleVm.parseJson(publicInputsFile, ".handle"), (string)), + senderDomain: abi.decode(linkHandleVm.parseJson(publicInputsFile, ".senderDomain"), (string)) + }); + } + + function _getProofFieldsFromBinary(string memory path) private view returns (bytes32[] memory proofFields) { + bytes memory packed = linkHandleVm.readFileBinary(path); + (bytes32[440] memory proofFixed) = abi.decode(packed, (bytes32[440])); + proofFields = new bytes32[](440); + for (uint256 i = 0; i < 440; i++) { + proofFields[i] = proofFixed[i]; + } + return proofFields; + } + + function _getPublicInputsFieldsFromBinary(string memory path) private view returns (bytes32[] memory publicInputs) { + bytes memory publicInputsFieldsData = linkHandleVm.readFileBinary(path); + (bytes32[155] memory publicInputsFixed) = abi.decode(publicInputsFieldsData, (bytes32[155])); + publicInputs = new bytes32[](155); + for (uint256 i = 0; i < 155; i++) { + publicInputs[i] = publicInputsFixed[i]; + } + return publicInputs; + } +} diff --git a/test/fixtures/linkHandleCommand/clean.sh b/test/fixtures/linkHandleCommand/clean.sh new file mode 100755 index 0000000..0415ca2 --- /dev/null +++ b/test/fixtures/linkHandleCommand/clean.sh @@ -0,0 +1,21 @@ +#! /bin/bash + +set -euo pipefail + +if [ -z "${1:-}" ]; then + echo "Usage: $0 " >&2 + echo "Example: $0 twitter" >&2 + exit 1 +fi + +PLATFORM="$1" +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" +WORKDIR="$SCRIPT_DIR/$PLATFORM" + +if [ ! -d "$WORKDIR" ]; then + echo "Platform directory not found: $WORKDIR" >&2 + exit 1 +fi + +cd "$WORKDIR" +rm -rf target diff --git a/test/fixtures/linkHandleCommand/compile.sh b/test/fixtures/linkHandleCommand/compile.sh new file mode 100755 index 0000000..1d99c3c --- /dev/null +++ b/test/fixtures/linkHandleCommand/compile.sh @@ -0,0 +1,74 @@ +#! /bin/bash + +set -euo pipefail + +if [ -z "${1:-}" ]; then + echo "Usage: $0 " >&2 + echo "Example: $0 twitter" >&2 + exit 1 +fi + +PLATFORM="$1" +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" +WORKDIR="$SCRIPT_DIR/$PLATFORM" + +if [ ! -d "$WORKDIR" ]; then + echo "Platform directory not found: $WORKDIR" >&2 + exit 1 +fi + +cd "$WORKDIR" + +CIRCUIT_NAME=$(grep '^name = ' Nargo.toml | sed 's/name = "\(.*\)"/\1/' | tr -d ' ') +if [ -z "$CIRCUIT_NAME" ]; then + echo "Could not read circuit name from Nargo.toml" >&2 + exit 1 +fi + +NARGO_VERSION="1.0.0-beta.5" +BB_VERSION="0.84.0" + +LOG_FILE="compile.log" + +# Truncate log file at start +: > "$LOG_FILE" + +log() { + printf "[%s] %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$1" | tee -a "$LOG_FILE" +} + +log "=== Compiling $CIRCUIT_NAME noir circuit (platform: $PLATFORM) ===" + +log "Step 0: Checking Noir and BB versions" +if [ "$(nargo --version | grep "nargo version = $NARGO_VERSION")" != "nargo version = $NARGO_VERSION" ]; then + log "Noir version is not $NARGO_VERSION, running noirup --version $NARGO_VERSION" + noirup --version $NARGO_VERSION >> "$LOG_FILE" 2>&1 +fi + +if [ "$(bb --version)" != "v$BB_VERSION" ]; then + log "BB version is not $BB_VERSION, running bbup --version $BB_VERSION" + bbup --version $BB_VERSION >> "$LOG_FILE" 2>&1 +fi + +log "Step 1: Compiling circuit" +nargo compile >> "$LOG_FILE" 2>&1 +if [ $? -ne 0 ]; then + log "Failed to compile circuit" + exit 1 +fi + +log "Step 2: Writing VK" +bb write_vk --bytecode_path ./target/$CIRCUIT_NAME.json --output_path ./target --oracle_hash keccak >> "$LOG_FILE" 2>&1 +if [ $? -ne 0 ]; then + log "Failed to write VK" + exit 1 +fi + +log "Step 3: Writing Solidity verifier" +bb write_solidity_verifier --vk_path ./target/vk --output_path ./target/HonkVerifier.sol >> "$LOG_FILE" 2>&1 +if [ $? -ne 0 ]; then + log "Failed to write Solidity verifier" + exit 1 +fi + +log "=== Done compiling $CIRCUIT_NAME noir circuit ===" diff --git a/test/fixtures/linkHandleCommand/prove.sh b/test/fixtures/linkHandleCommand/prove.sh new file mode 100755 index 0000000..6ab7f4e --- /dev/null +++ b/test/fixtures/linkHandleCommand/prove.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +set -euo pipefail + +if [ -z "${1:-}" ]; then + echo "Usage: $0 " >&2 + echo "Example: $0 twitter" >&2 + exit 1 +fi + +PLATFORM="$1" +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" +WORKDIR="$SCRIPT_DIR/$PLATFORM" + +if [ ! -d "$WORKDIR" ]; then + echo "Platform directory not found: $WORKDIR" >&2 + exit 1 +fi + +cd "$WORKDIR" + +CIRCUIT_NAME=$(grep '^name = ' Nargo.toml | sed 's/name = "\(.*\)"/\1/' | tr -d ' ') +if [ -z "$CIRCUIT_NAME" ]; then + echo "Could not read circuit name from Nargo.toml" >&2 + exit 1 +fi + +WITNESS_NAME="$CIRCUIT_NAME" + +LOG_FILE="prove.log" + +# Truncate log file at start +: > "$LOG_FILE" + +log() { + printf "[%s] %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$1" | tee -a "$LOG_FILE" +} + +log "=== Generating proof for $CIRCUIT_NAME (platform: $PLATFORM) ===" + +log "Step 1: Executing circuit to generate witness" +nargo execute "$WITNESS_NAME" >> "$LOG_FILE" 2>&1 +if [ $? -ne 0 ]; then + log "Failed to execute circuit" + exit 1 +fi + +log "Step 2: Generating proof (binary format)" +bb prove \ + --scheme ultra_honk \ + --bytecode_path ./target/$CIRCUIT_NAME.json \ + --witness_path ./target/$WITNESS_NAME.gz \ + --output_path ./target \ + --oracle_hash keccak \ + >> "$LOG_FILE" 2>&1 +if [ $? -ne 0 ]; then + log "Failed to generate proof" + exit 1 +fi + +log "Step 3: Generating proof in fields format (JSON-compatible)" +# Create a temporary directory for fields output +mkdir -p ./target/fields_output +bb prove \ + --scheme ultra_honk \ + --bytecode_path ./target/$CIRCUIT_NAME.json \ + --witness_path ./target/$WITNESS_NAME.gz \ + --output_path ./target/fields_output \ + --oracle_hash keccak \ + --output_format fields \ + >> "$LOG_FILE" 2>&1 +if [ $? -ne 0 ]; then + log "Failed to generate proof in fields format" + exit 1 +fi + +log "Step 4: Moving fields output to target directory" +if [ -f "./target/fields_output/proof_fields.json" ]; then + mv ./target/fields_output/proof_fields.json ./target/proof_fields.json + log "Moved proof_fields.json to ./target/" +fi +if [ -f "./target/fields_output/public_inputs_fields.json" ]; then + mv ./target/fields_output/public_inputs_fields.json ./target/public_inputs_fields.json + log "Moved public_inputs_fields.json to ./target/" +fi +# Clean up temp directory +rm -rf ./target/fields_output + +log "=== Proof generation complete ===" +log "Files generated:" +log " - Binary proof: ./target/proof" +log " - Binary public inputs: ./target/public_inputs" +log " - Fields proof (JSON): ./target/proof_fields.json" +log " - Fields public inputs (JSON): ./target/public_inputs_fields.json" +log "" +log "To view the proof in JSON format: cat ./target/proof_fields.json" +log "To view the public inputs in JSON format: cat ./target/public_inputs_fields.json" diff --git a/test/fixtures/linkHandleCommand/twitter/Nargo.toml b/test/fixtures/linkHandleCommand/twitter/Nargo.toml new file mode 100644 index 0000000..2573e2d --- /dev/null +++ b/test/fixtures/linkHandleCommand/twitter/Nargo.toml @@ -0,0 +1,10 @@ +[package] +name = "link_x_handle_command" +type = "bin" +authors = [] +compiler_version = ">=1.0.0" + +[dependencies] +zkemail = { tag = "v.1.0.1-beta.5", git = "https://github.com/zkemail/zkemail.nr", directory = "lib" } +zkregex = { tag = "2.2.0", git = "https://github.com/zkemail/zk-regex", directory = "noir" } +poseidon = { tag = "v0.1.0", git = "https://github.com/noir-lang/poseidon" } diff --git a/test/fixtures/linkHandleCommand/twitter/Prover.sample.toml b/test/fixtures/linkHandleCommand/twitter/Prover.sample.toml new file mode 100644 index 0000000..2448159 --- /dev/null +++ b/test/fixtures/linkHandleCommand/twitter/Prover.sample.toml @@ -0,0 +1,40 @@ +body_hash_index = "366" +command = ["85032600163920399473468279312950221173836508678231302942561155984767675459", "179150172561695665779863979615782336199001738146281935132720574537795002744", "228470014919439913465702", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"] +partial_body_hash = ["2716496725", "1937426258", "2293599503", "2645896470", "4105601631", "4002592056", "3491810135", "2710259935"] +partial_body_real_length = "14098" +prover_address = ["0x0000000000000000000000000000000000000000"] +sender_domain_capture_group_1_id = ["0", "0", "0", "0", "0", "1", "1", "1", "1", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"] +sender_domain_capture_group_1_start = ["0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"] +sender_domain_capture_group_start_indices = ["5"] +sender_domain_current_states = ["1", "2", "2", "2", "2", "3", "4", "4", "4", "4", "4", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"] +sender_domain_match_length = "11" +sender_domain_match_start = "46" +sender_domain_next_states = ["2", "2", "2", "2", "3", "4", "4", "4", "4", "4", "5", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"] +signature = ["0xaf369158ed2c1281bae66cc102b770", "0x46c860c6a37d6b34fe7154782db5bb", "0x807b78c6113870aca8593121974a33", "0x81c0ce8a64a90101540cca6aad735c", "0x24e1f294de4cc3d5e3b32399356f49", "0xbafd0c7ae22763f8fb35b21c6ccc48", "0x8056511765d161bc8b7fd5ac724224", "0x86d2a6813c87995842cc4b481e0371", "0x6fbdb44d30d0f07db7439347332970", "0xe4ec855bb972d867ee1d363c8b4cfb", "0x176074c03680b51a9045367daec140", "0x167aac207a1b85ebb433106e074a33", "0x4e03eb000dd8446900995a9d7d004b", "0x041ee164b1ae04af00e400f74625ea", "0xb082c568149d794dbaf46261ebd495", "0x332c971fe36e86668583ae50827f64", "0x5b9bc926a11fca1b5226d23100a853", "0xb3"] +x_handle_capture_group_1_id = ["0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "1", "1", "1", "1", "1", "1", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"] +x_handle_capture_group_1_start = ["0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"] +x_handle_capture_group_start_indices = ["26"] +x_handle_current_states = ["0", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "28", "28", "28", "28", "28", "28", "28", "29", "30", "31", "32", "33", "34", "35", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"] +x_handle_match_length = "42" +x_handle_match_start = "514" +x_handle_next_states = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "28", "28", "28", "28", "28", "28", "28", "29", "30", "31", "32", "33", "34", "35", "36", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"] + +[body] +len = "1554" +storage = ["117", "114", "105", "116", "121", "32", "116", "105", "112", "115", "60", "47", "97", "62", "32", "60", "47", "115", "112", "61", "13", "10", "97", "110", "62", "32", "60", "47", "116", "100", "62", "13", "10", "60", "47", "116", "114", "62", "13", "10", "60", "116", "114", "62", "13", "10", "60", "116", "100", "32", "104", "101", "105", "103", "104", "116", "61", "51", "68", "34", "49", "50", "34", "32", "115", "116", "121", "108", "101", "61", "51", "68", "34", "104", "101", "105", "103", "104", "116", "58", "49", "50", "112", "120", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "112", "120", "59", "102", "111", "110", "116", "45", "115", "105", "122", "101", "58", "49", "112", "120", "59", "112", "97", "100", "100", "105", "110", "61", "13", "10", "103", "58", "48", "59", "109", "97", "114", "103", "105", "110", "58", "48", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "112", "120", "59", "102", "111", "110", "116", "45", "115", "105", "122", "101", "58", "49", "112", "120", "59", "34", "62", "60", "47", "116", "100", "62", "13", "10", "60", "47", "116", "114", "62", "13", "10", "60", "116", "114", "62", "13", "10", "60", "116", "100", "32", "97", "108", "105", "103", "110", "61", "51", "68", "34", "99", "101", "110", "116", "101", "114", "34", "32", "115", "116", "121", "108", "101", "61", "51", "68", "34", "112", "97", "100", "100", "105", "110", "103", "58", "48", "59", "109", "97", "114", "103", "105", "110", "58", "48", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "112", "120", "59", "102", "111", "110", "116", "45", "115", "105", "122", "101", "58", "61", "13", "10", "49", "112", "120", "59", "34", "62", "32", "60", "115", "112", "97", "110", "32", "99", "108", "97", "115", "115", "61", "51", "68", "34", "115", "109", "97", "108", "108", "45", "99", "111", "112", "121", "34", "32", "115", "116", "121", "108", "101", "61", "51", "68", "34", "102", "111", "110", "116", "45", "102", "97", "109", "105", "108", "121", "58", "39", "72", "101", "108", "118", "101", "116", "105", "99", "97", "78", "101", "117", "101", "39", "44", "32", "39", "72", "101", "61", "13", "10", "108", "118", "101", "116", "105", "99", "97", "32", "78", "101", "117", "101", "39", "44", "32", "72", "101", "108", "118", "101", "116", "105", "99", "97", "44", "32", "65", "114", "105", "97", "108", "44", "32", "115", "97", "110", "115", "45", "115", "101", "114", "105", "102", "59", "102", "111", "110", "116", "45", "115", "105", "122", "101", "58", "49", "50", "112", "120", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "54", "112", "120", "61", "13", "10", "59", "102", "111", "110", "116", "45", "119", "101", "105", "103", "104", "116", "58", "52", "48", "48", "59", "99", "111", "108", "111", "114", "58", "35", "56", "56", "57", "57", "65", "54", "59", "116", "101", "120", "116", "45", "97", "108", "105", "103", "110", "58", "108", "101", "102", "116", "59", "116", "101", "120", "116", "45", "100", "101", "99", "111", "114", "97", "116", "105", "111", "110", "58", "110", "111", "110", "101", "59", "45", "119", "101", "98", "107", "105", "116", "61", "13", "10", "45", "102", "111", "110", "116", "45", "115", "109", "111", "111", "116", "104", "105", "110", "103", "58", "97", "110", "116", "105", "97", "108", "105", "97", "115", "101", "100", "59", "34", "62", "32", "84", "104", "105", "115", "32", "101", "109", "97", "105", "108", "32", "119", "97", "115", "32", "109", "101", "97", "110", "116", "32", "102", "111", "114", "32", "64", "116", "104", "101", "122", "100", "101", "118", "49", "32", "60", "47", "115", "112", "97", "110", "62", "32", "60", "61", "13", "10", "47", "116", "100", "62", "13", "10", "60", "47", "116", "114", "62", "13", "10", "60", "116", "114", "62", "13", "10", "60", "116", "100", "32", "104", "101", "105", "103", "104", "116", "61", "51", "68", "34", "54", "34", "32", "115", "116", "121", "108", "101", "61", "51", "68", "34", "104", "101", "105", "103", "104", "116", "58", "54", "112", "120", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "112", "120", "59", "102", "111", "110", "116", "45", "115", "105", "122", "101", "58", "49", "112", "120", "59", "112", "97", "100", "100", "105", "110", "103", "58", "61", "13", "10", "48", "59", "109", "97", "114", "103", "105", "110", "58", "48", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "112", "120", "59", "102", "111", "110", "116", "45", "115", "105", "122", "101", "58", "49", "112", "120", "59", "34", "62", "60", "47", "116", "100", "62", "13", "10", "60", "47", "116", "114", "62", "13", "10", "60", "116", "114", "62", "13", "10", "60", "116", "100", "32", "97", "108", "105", "103", "110", "61", "51", "68", "34", "99", "101", "110", "116", "101", "114", "34", "32", "115", "116", "121", "108", "101", "61", "51", "68", "34", "112", "97", "100", "100", "105", "110", "103", "58", "48", "59", "109", "97", "114", "103", "105", "110", "58", "48", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "112", "120", "59", "102", "111", "110", "116", "45", "115", "105", "122", "101", "58", "61", "13", "10", "49", "112", "120", "59", "34", "62", "32", "60", "115", "112", "97", "110", "32", "99", "108", "97", "115", "115", "61", "51", "68", "34", "97", "100", "100", "114", "101", "115", "115", "34", "62", "32", "60", "97", "32", "104", "114", "101", "102", "61", "51", "68", "34", "35", "34", "32", "115", "116", "121", "108", "101", "61", "51", "68", "34", "116", "101", "120", "116", "45", "100", "101", "99", "111", "114", "97", "116", "105", "111", "110", "58", "110", "111", "110", "101", "61", "13", "10", "59", "98", "111", "114", "100", "101", "114", "45", "115", "116", "121", "108", "101", "58", "110", "111", "110", "101", "59", "98", "111", "114", "100", "101", "114", "58", "48", "59", "112", "97", "100", "100", "105", "110", "103", "58", "48", "59", "109", "97", "114", "103", "105", "110", "58", "48", "59", "102", "111", "110", "116", "45", "102", "97", "109", "105", "108", "121", "58", "39", "72", "101", "108", "118", "101", "116", "105", "99", "97", "78", "101", "117", "101", "39", "44", "61", "13", "10", "32", "39", "72", "101", "108", "118", "101", "116", "105", "99", "97", "32", "78", "101", "117", "101", "39", "44", "32", "72", "101", "108", "118", "101", "116", "105", "99", "97", "44", "32", "65", "114", "105", "97", "108", "44", "32", "115", "97", "110", "115", "45", "115", "101", "114", "105", "102", "59", "45", "119", "101", "98", "107", "105", "116", "45", "102", "111", "110", "116", "45", "115", "109", "111", "111", "116", "104", "105", "110", "103", "58", "97", "110", "116", "105", "61", "13", "10", "97", "108", "105", "97", "115", "101", "100", "59", "99", "111", "108", "111", "114", "58", "35", "56", "56", "57", "57", "65", "54", "59", "102", "111", "110", "116", "45", "115", "105", "122", "101", "58", "49", "50", "112", "120", "59", "112", "97", "100", "100", "105", "110", "103", "58", "48", "112", "120", "59", "109", "97", "114", "103", "105", "110", "58", "48", "112", "120", "59", "102", "111", "110", "116", "45", "119", "101", "105", "103", "104", "116", "58", "110", "111", "114", "61", "13", "10", "109", "97", "108", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "50", "112", "120", "59", "99", "117", "114", "115", "111", "114", "58", "100", "101", "102", "97", "117", "108", "116", "59", "34", "62", "88", "32", "67", "111", "114", "112", "46", "32", "49", "51", "53", "53", "32", "77", "97", "114", "107", "101", "116", "32", "83", "116", "114", "101", "101", "116", "44", "32", "83", "117", "105", "116", "101", "32", "57", "48", "48", "61", "13", "10", "32", "83", "97", "110", "32", "70", "114", "97", "110", "99", "105", "115", "99", "111", "44", "32", "67", "65", "32", "57", "52", "49", "48", "51", "60", "47", "97", "62", "32", "60", "47", "115", "112", "97", "110", "62", "32", "60", "47", "116", "100", "62", "13", "10", "60", "47", "116", "114", "62", "13", "10", "60", "116", "114", "62", "13", "10", "60", "116", "100", "32", "104", "101", "105", "103", "104", "116", "61", "51", "68", "34", "55", "50", "34", "32", "115", "116", "121", "108", "101", "61", "51", "68", "34", "104", "101", "105", "103", "104", "116", "58", "55", "50", "112", "120", "59", "112", "97", "100", "100", "105", "110", "103", "58", "48", "59", "109", "97", "114", "103", "105", "110", "58", "48", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "112", "120", "59", "102", "61", "13", "10", "111", "110", "116", "45", "115", "105", "122", "101", "58", "49", "112", "120", "59", "34", "62", "60", "47", "116", "100", "62", "13", "10", "60", "47", "116", "114", "62", "13", "10", "60", "47", "116", "98", "111", "100", "121", "62", "13", "10", "60", "47", "116", "97", "98", "108", "101", "62", "13", "10", "60", "33", "45", "45", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "32", "101", "110", "100", "32", "102", "111", "111", "116", "101", "114", "32", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "45", "45", "62", "32", "60", "47", "116", "100", "62", "13", "10", "60", "47", "116", "114", "62", "13", "10", "60", "47", "116", "98", "111", "100", "121", "62", "13", "10", "60", "47", "116", "97", "98", "108", "101", "62", "13", "10", "60", "47", "98", "111", "100", "121", "62", "13", "10", "60", "47", "104", "116", "109", "108", "62", "13", "10", "45", "45", "45", "45", "45", "45", "61", "95", "80", "97", "114", "116", "95", "51", "48", "50", "53", "53", "52", "49", "95", "49", "51", "57", "53", "53", "57", "50", "53", "54", "54", "46", "49", "55", "53", "54", "55", "52", "52", "49", "55", "49", "50", "51", "48", "45", "45", "13", "10", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"] + +[decoded_body] +len = "1509" +storage = ["117", "114", "105", "116", "121", "32", "116", "105", "112", "115", "60", "47", "97", "62", "32", "60", "47", "115", "112", "97", "110", "62", "32", "60", "47", "116", "100", "62", "13", "10", "60", "47", "116", "114", "62", "13", "10", "60", "116", "114", "62", "13", "10", "60", "116", "100", "32", "104", "101", "105", "103", "104", "116", "61", "51", "68", "34", "49", "50", "34", "32", "115", "116", "121", "108", "101", "61", "51", "68", "34", "104", "101", "105", "103", "104", "116", "58", "49", "50", "112", "120", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "112", "120", "59", "102", "111", "110", "116", "45", "115", "105", "122", "101", "58", "49", "112", "120", "59", "112", "97", "100", "100", "105", "110", "103", "58", "48", "59", "109", "97", "114", "103", "105", "110", "58", "48", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "112", "120", "59", "102", "111", "110", "116", "45", "115", "105", "122", "101", "58", "49", "112", "120", "59", "34", "62", "60", "47", "116", "100", "62", "13", "10", "60", "47", "116", "114", "62", "13", "10", "60", "116", "114", "62", "13", "10", "60", "116", "100", "32", "97", "108", "105", "103", "110", "61", "51", "68", "34", "99", "101", "110", "116", "101", "114", "34", "32", "115", "116", "121", "108", "101", "61", "51", "68", "34", "112", "97", "100", "100", "105", "110", "103", "58", "48", "59", "109", "97", "114", "103", "105", "110", "58", "48", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "112", "120", "59", "102", "111", "110", "116", "45", "115", "105", "122", "101", "58", "49", "112", "120", "59", "34", "62", "32", "60", "115", "112", "97", "110", "32", "99", "108", "97", "115", "115", "61", "51", "68", "34", "115", "109", "97", "108", "108", "45", "99", "111", "112", "121", "34", "32", "115", "116", "121", "108", "101", "61", "51", "68", "34", "102", "111", "110", "116", "45", "102", "97", "109", "105", "108", "121", "58", "39", "72", "101", "108", "118", "101", "116", "105", "99", "97", "78", "101", "117", "101", "39", "44", "32", "39", "72", "101", "108", "118", "101", "116", "105", "99", "97", "32", "78", "101", "117", "101", "39", "44", "32", "72", "101", "108", "118", "101", "116", "105", "99", "97", "44", "32", "65", "114", "105", "97", "108", "44", "32", "115", "97", "110", "115", "45", "115", "101", "114", "105", "102", "59", "102", "111", "110", "116", "45", "115", "105", "122", "101", "58", "49", "50", "112", "120", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "54", "112", "120", "59", "102", "111", "110", "116", "45", "119", "101", "105", "103", "104", "116", "58", "52", "48", "48", "59", "99", "111", "108", "111", "114", "58", "35", "56", "56", "57", "57", "65", "54", "59", "116", "101", "120", "116", "45", "97", "108", "105", "103", "110", "58", "108", "101", "102", "116", "59", "116", "101", "120", "116", "45", "100", "101", "99", "111", "114", "97", "116", "105", "111", "110", "58", "110", "111", "110", "101", "59", "45", "119", "101", "98", "107", "105", "116", "45", "102", "111", "110", "116", "45", "115", "109", "111", "111", "116", "104", "105", "110", "103", "58", "97", "110", "116", "105", "97", "108", "105", "97", "115", "101", "100", "59", "34", "62", "32", "84", "104", "105", "115", "32", "101", "109", "97", "105", "108", "32", "119", "97", "115", "32", "109", "101", "97", "110", "116", "32", "102", "111", "114", "32", "64", "116", "104", "101", "122", "100", "101", "118", "49", "32", "60", "47", "115", "112", "97", "110", "62", "32", "60", "47", "116", "100", "62", "13", "10", "60", "47", "116", "114", "62", "13", "10", "60", "116", "114", "62", "13", "10", "60", "116", "100", "32", "104", "101", "105", "103", "104", "116", "61", "51", "68", "34", "54", "34", "32", "115", "116", "121", "108", "101", "61", "51", "68", "34", "104", "101", "105", "103", "104", "116", "58", "54", "112", "120", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "112", "120", "59", "102", "111", "110", "116", "45", "115", "105", "122", "101", "58", "49", "112", "120", "59", "112", "97", "100", "100", "105", "110", "103", "58", "48", "59", "109", "97", "114", "103", "105", "110", "58", "48", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "112", "120", "59", "102", "111", "110", "116", "45", "115", "105", "122", "101", "58", "49", "112", "120", "59", "34", "62", "60", "47", "116", "100", "62", "13", "10", "60", "47", "116", "114", "62", "13", "10", "60", "116", "114", "62", "13", "10", "60", "116", "100", "32", "97", "108", "105", "103", "110", "61", "51", "68", "34", "99", "101", "110", "116", "101", "114", "34", "32", "115", "116", "121", "108", "101", "61", "51", "68", "34", "112", "97", "100", "100", "105", "110", "103", "58", "48", "59", "109", "97", "114", "103", "105", "110", "58", "48", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "112", "120", "59", "102", "111", "110", "116", "45", "115", "105", "122", "101", "58", "49", "112", "120", "59", "34", "62", "32", "60", "115", "112", "97", "110", "32", "99", "108", "97", "115", "115", "61", "51", "68", "34", "97", "100", "100", "114", "101", "115", "115", "34", "62", "32", "60", "97", "32", "104", "114", "101", "102", "61", "51", "68", "34", "35", "34", "32", "115", "116", "121", "108", "101", "61", "51", "68", "34", "116", "101", "120", "116", "45", "100", "101", "99", "111", "114", "97", "116", "105", "111", "110", "58", "110", "111", "110", "101", "59", "98", "111", "114", "100", "101", "114", "45", "115", "116", "121", "108", "101", "58", "110", "111", "110", "101", "59", "98", "111", "114", "100", "101", "114", "58", "48", "59", "112", "97", "100", "100", "105", "110", "103", "58", "48", "59", "109", "97", "114", "103", "105", "110", "58", "48", "59", "102", "111", "110", "116", "45", "102", "97", "109", "105", "108", "121", "58", "39", "72", "101", "108", "118", "101", "116", "105", "99", "97", "78", "101", "117", "101", "39", "44", "32", "39", "72", "101", "108", "118", "101", "116", "105", "99", "97", "32", "78", "101", "117", "101", "39", "44", "32", "72", "101", "108", "118", "101", "116", "105", "99", "97", "44", "32", "65", "114", "105", "97", "108", "44", "32", "115", "97", "110", "115", "45", "115", "101", "114", "105", "102", "59", "45", "119", "101", "98", "107", "105", "116", "45", "102", "111", "110", "116", "45", "115", "109", "111", "111", "116", "104", "105", "110", "103", "58", "97", "110", "116", "105", "97", "108", "105", "97", "115", "101", "100", "59", "99", "111", "108", "111", "114", "58", "35", "56", "56", "57", "57", "65", "54", "59", "102", "111", "110", "116", "45", "115", "105", "122", "101", "58", "49", "50", "112", "120", "59", "112", "97", "100", "100", "105", "110", "103", "58", "48", "112", "120", "59", "109", "97", "114", "103", "105", "110", "58", "48", "112", "120", "59", "102", "111", "110", "116", "45", "119", "101", "105", "103", "104", "116", "58", "110", "111", "114", "109", "97", "108", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "50", "112", "120", "59", "99", "117", "114", "115", "111", "114", "58", "100", "101", "102", "97", "117", "108", "116", "59", "34", "62", "88", "32", "67", "111", "114", "112", "46", "32", "49", "51", "53", "53", "32", "77", "97", "114", "107", "101", "116", "32", "83", "116", "114", "101", "101", "116", "44", "32", "83", "117", "105", "116", "101", "32", "57", "48", "48", "32", "83", "97", "110", "32", "70", "114", "97", "110", "99", "105", "115", "99", "111", "44", "32", "67", "65", "32", "57", "52", "49", "48", "51", "60", "47", "97", "62", "32", "60", "47", "115", "112", "97", "110", "62", "32", "60", "47", "116", "100", "62", "13", "10", "60", "47", "116", "114", "62", "13", "10", "60", "116", "114", "62", "13", "10", "60", "116", "100", "32", "104", "101", "105", "103", "104", "116", "61", "51", "68", "34", "55", "50", "34", "32", "115", "116", "121", "108", "101", "61", "51", "68", "34", "104", "101", "105", "103", "104", "116", "58", "55", "50", "112", "120", "59", "112", "97", "100", "100", "105", "110", "103", "58", "48", "59", "109", "97", "114", "103", "105", "110", "58", "48", "59", "108", "105", "110", "101", "45", "104", "101", "105", "103", "104", "116", "58", "49", "112", "120", "59", "102", "111", "110", "116", "45", "115", "105", "122", "101", "58", "49", "112", "120", "59", "34", "62", "60", "47", "116", "100", "62", "13", "10", "60", "47", "116", "114", "62", "13", "10", "60", "47", "116", "98", "111", "100", "121", "62", "13", "10", "60", "47", "116", "97", "98", "108", "101", "62", "13", "10", "60", "33", "45", "45", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "32", "101", "110", "100", "32", "102", "111", "111", "116", "101", "114", "32", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "47", "45", "45", "62", "32", "60", "47", "116", "100", "62", "13", "10", "60", "47", "116", "114", "62", "13", "10", "60", "47", "116", "98", "111", "100", "121", "62", "13", "10", "60", "47", "116", "97", "98", "108", "101", "62", "13", "10", "60", "47", "98", "111", "100", "121", "62", "13", "10", "60", "47", "104", "116", "109", "108", "62", "13", "10", "45", "45", "45", "45", "45", "45", "61", "95", "80", "97", "114", "116", "95", "51", "48", "50", "53", "53", "52", "49", "95", "49", "51", "57", "53", "53", "57", "50", "53", "54", "54", "46", "49", "55", "53", "54", "55", "52", "52", "49", "55", "49", "50", "51", "48", "45", "45", "13", "10", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"] + +[dkim_header_sequence] +index = "272" +length = "203" + +[header] +len = "475" +storage = ["100", "97", "116", "101", "58", "77", "111", "110", "44", "32", "48", "49", "32", "83", "101", "112", "32", "50", "48", "50", "53", "32", "49", "54", "58", "50", "57", "58", "51", "49", "32", "43", "48", "48", "48", "48", "13", "10", "102", "114", "111", "109", "58", "88", "32", "60", "105", "110", "102", "111", "64", "120", "46", "99", "111", "109", "62", "13", "10", "116", "111", "58", "122", "100", "101", "118", "32", "60", "116", "104", "101", "122", "100", "101", "118", "49", "64", "103", "109", "97", "105", "108", "46", "99", "111", "109", "62", "13", "10", "115", "117", "98", "106", "101", "99", "116", "58", "80", "97", "115", "115", "119", "111", "114", "100", "32", "114", "101", "115", "101", "116", "32", "114", "101", "113", "117", "101", "115", "116", "13", "10", "109", "105", "109", "101", "45", "118", "101", "114", "115", "105", "111", "110", "58", "49", "46", "48", "13", "10", "99", "111", "110", "116", "101", "110", "116", "45", "116", "121", "112", "101", "58", "109", "117", "108", "116", "105", "112", "97", "114", "116", "47", "97", "108", "116", "101", "114", "110", "97", "116", "105", "118", "101", "59", "32", "98", "111", "117", "110", "100", "97", "114", "121", "61", "34", "45", "45", "45", "45", "61", "95", "80", "97", "114", "116", "95", "51", "48", "50", "53", "53", "52", "49", "95", "49", "51", "57", "53", "53", "57", "50", "53", "54", "54", "46", "49", "55", "53", "54", "55", "52", "52", "49", "55", "49", "50", "51", "48", "34", "13", "10", "109", "101", "115", "115", "97", "103", "101", "45", "105", "100", "58", "60", "48", "53", "46", "70", "56", "46", "50", "57", "55", "52", "51", "46", "66", "69", "57", "67", "53", "66", "56", "54", "64", "120", "46", "99", "111", "109", "62", "13", "10", "100", "107", "105", "109", "45", "115", "105", "103", "110", "97", "116", "117", "114", "101", "58", "118", "61", "49", "59", "32", "97", "61", "114", "115", "97", "45", "115", "104", "97", "50", "53", "54", "59", "32", "99", "61", "114", "101", "108", "97", "120", "101", "100", "47", "114", "101", "108", "97", "120", "101", "100", "59", "32", "100", "61", "120", "46", "99", "111", "109", "59", "32", "115", "61", "100", "107", "105", "109", "45", "50", "48", "50", "51", "48", "56", "59", "32", "116", "61", "49", "55", "53", "54", "55", "52", "52", "49", "55", "49", "59", "32", "98", "104", "61", "88", "47", "115", "78", "77", "109", "87", "52", "77", "121", "48", "98", "82", "100", "50", "73", "78", "114", "75", "57", "48", "65", "66", "121", "98", "80", "117", "88", "101", "79", "84", "82", "99", "47", "104", "67", "105", "101", "101", "104", "102", "104", "115", "61", "59", "32", "104", "61", "68", "97", "116", "101", "58", "70", "114", "111", "109", "58", "84", "111", "58", "83", "117", "98", "106", "101", "99", "116", "58", "77", "73", "77", "69", "45", "86", "101", "114", "115", "105", "111", "110", "58", "67", "111", "110", "116", "101", "110", "116", "45", "84", "121", "112", "101", "58", "77", "101", "115", "115", "97", "103", "101", "45", "73", "68", "59", "32", "98", "61", "128", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "14", "216", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"] + +[pubkey] +modulus = ["0x8967a931d2ca21c652df494825c63d", "0x7d068b9c6250147cacb8f0786dccb5", "0x7436a40c9b68e7298c65045a93fc87", "0x9020a67668fbaac0d540947f0653f3", "0xd19710c0036acc7efb1c5f6c8a4faf", "0xefe0b5c633b0be4b86ebe17db85154", "0xc33caef88bc13f6ab2725c3386f721", "0x075051819421b1a461accf75851dff", "0x6fa3c2ec6bae4360f33c7a6bdc1647", "0xe197ac59d1c54fef22294ba23274d5", "0x1fe2fcf682109ce8f7875c7789c84b", "0xbfc2b278635688cc33b89956ed8d73", "0x2ae064a2431efe13336926c9b8b82a", "0xf8b24f943dd0acf064691e18beb4f7", "0xc618092fcc16c581b9e81113cc87c1", "0xf9113b691b82bfa396cf869b94bf6e", "0x76f3879ada6d3f8859e8150281a74b", "0xbf"] +redc = ["0x49d32b52b73e1f5dcf16b848dc145c", "0x2ebcef9575a2de39b251488d54d757", "0x44e4d199a932fc02a2629211332a85", "0x6a48be2e6a7bb5f18ed4234482b935", "0x120fb1d1d1a6d14702f54d22f3b353", "0x412475e6ad621e9e9e3dd17e4df885", "0x0ac7170aa843385efbdbffd8f00531", "0xe179c9a19576d47188d09bed675b37", "0x18bcf06ab745979ecee27ecb307ff0", "0xbd50d9ffba4eb337089a8d2bf08e0a", "0xbf428561893f274568c298836ac2c5", "0x9713d20bb3f20d843b18164a8dfdb7", "0xdb2339e26a7c78c265887fb09e8594", "0x1694eb4fc858b0b003c83073921753", "0xde3d74b94c549832e46fb3c8e9669c", "0x68a2b9d5fc918bf336b4629c844d8c", "0x9a81f331fe70c1560a62352fb5d41c", "0x1564"] diff --git a/test/fixtures/handleCommand/files/linkX/email.eml b/test/fixtures/linkHandleCommand/twitter/files/email.eml similarity index 100% rename from test/fixtures/handleCommand/files/linkX/email.eml rename to test/fixtures/linkHandleCommand/twitter/files/email.eml diff --git a/test/fixtures/handleCommand/files/linkX/expected_public_inputs.json b/test/fixtures/linkHandleCommand/twitter/files/expected_public_inputs.json similarity index 100% rename from test/fixtures/handleCommand/files/linkX/expected_public_inputs.json rename to test/fixtures/linkHandleCommand/twitter/files/expected_public_inputs.json diff --git a/test/fixtures/handleCommand/files/linkX/proof b/test/fixtures/linkHandleCommand/twitter/files/proof similarity index 100% rename from test/fixtures/handleCommand/files/linkX/proof rename to test/fixtures/linkHandleCommand/twitter/files/proof diff --git a/test/fixtures/handleCommand/files/linkX/public_inputs b/test/fixtures/linkHandleCommand/twitter/files/public_inputs similarity index 100% rename from test/fixtures/handleCommand/files/linkX/public_inputs rename to test/fixtures/linkHandleCommand/twitter/files/public_inputs diff --git a/test/fixtures/linkHandleCommand/twitter/raw_inputs.sample.json b/test/fixtures/linkHandleCommand/twitter/raw_inputs.sample.json new file mode 100644 index 0000000..0f887c4 --- /dev/null +++ b/test/fixtures/linkHandleCommand/twitter/raw_inputs.sample.json @@ -0,0 +1,3 @@ +{ + "input": "{\"body\":{\"len\":1554,\"storage\":[117,114,105,116,121,32,116,105,112,115,60,47,97,62,32,60,47,115,112,61,13,10,97,110,62,32,60,47,116,100,62,13,10,60,47,116,114,62,13,10,60,116,114,62,13,10,60,116,100,32,104,101,105,103,104,116,61,51,68,34,49,50,34,32,115,116,121,108,101,61,51,68,34,104,101,105,103,104,116,58,49,50,112,120,59,108,105,110,101,45,104,101,105,103,104,116,58,49,112,120,59,102,111,110,116,45,115,105,122,101,58,49,112,120,59,112,97,100,100,105,110,61,13,10,103,58,48,59,109,97,114,103,105,110,58,48,59,108,105,110,101,45,104,101,105,103,104,116,58,49,112,120,59,102,111,110,116,45,115,105,122,101,58,49,112,120,59,34,62,60,47,116,100,62,13,10,60,47,116,114,62,13,10,60,116,114,62,13,10,60,116,100,32,97,108,105,103,110,61,51,68,34,99,101,110,116,101,114,34,32,115,116,121,108,101,61,51,68,34,112,97,100,100,105,110,103,58,48,59,109,97,114,103,105,110,58,48,59,108,105,110,101,45,104,101,105,103,104,116,58,49,112,120,59,102,111,110,116,45,115,105,122,101,58,61,13,10,49,112,120,59,34,62,32,60,115,112,97,110,32,99,108,97,115,115,61,51,68,34,115,109,97,108,108,45,99,111,112,121,34,32,115,116,121,108,101,61,51,68,34,102,111,110,116,45,102,97,109,105,108,121,58,39,72,101,108,118,101,116,105,99,97,78,101,117,101,39,44,32,39,72,101,61,13,10,108,118,101,116,105,99,97,32,78,101,117,101,39,44,32,72,101,108,118,101,116,105,99,97,44,32,65,114,105,97,108,44,32,115,97,110,115,45,115,101,114,105,102,59,102,111,110,116,45,115,105,122,101,58,49,50,112,120,59,108,105,110,101,45,104,101,105,103,104,116,58,49,54,112,120,61,13,10,59,102,111,110,116,45,119,101,105,103,104,116,58,52,48,48,59,99,111,108,111,114,58,35,56,56,57,57,65,54,59,116,101,120,116,45,97,108,105,103,110,58,108,101,102,116,59,116,101,120,116,45,100,101,99,111,114,97,116,105,111,110,58,110,111,110,101,59,45,119,101,98,107,105,116,61,13,10,45,102,111,110,116,45,115,109,111,111,116,104,105,110,103,58,97,110,116,105,97,108,105,97,115,101,100,59,34,62,32,84,104,105,115,32,101,109,97,105,108,32,119,97,115,32,109,101,97,110,116,32,102,111,114,32,64,116,104,101,122,100,101,118,49,32,60,47,115,112,97,110,62,32,60,61,13,10,47,116,100,62,13,10,60,47,116,114,62,13,10,60,116,114,62,13,10,60,116,100,32,104,101,105,103,104,116,61,51,68,34,54,34,32,115,116,121,108,101,61,51,68,34,104,101,105,103,104,116,58,54,112,120,59,108,105,110,101,45,104,101,105,103,104,116,58,49,112,120,59,102,111,110,116,45,115,105,122,101,58,49,112,120,59,112,97,100,100,105,110,103,58,61,13,10,48,59,109,97,114,103,105,110,58,48,59,108,105,110,101,45,104,101,105,103,104,116,58,49,112,120,59,102,111,110,116,45,115,105,122,101,58,49,112,120,59,34,62,60,47,116,100,62,13,10,60,47,116,114,62,13,10,60,116,114,62,13,10,60,116,100,32,97,108,105,103,110,61,51,68,34,99,101,110,116,101,114,34,32,115,116,121,108,101,61,51,68,34,112,97,100,100,105,110,103,58,48,59,109,97,114,103,105,110,58,48,59,108,105,110,101,45,104,101,105,103,104,116,58,49,112,120,59,102,111,110,116,45,115,105,122,101,58,61,13,10,49,112,120,59,34,62,32,60,115,112,97,110,32,99,108,97,115,115,61,51,68,34,97,100,100,114,101,115,115,34,62,32,60,97,32,104,114,101,102,61,51,68,34,35,34,32,115,116,121,108,101,61,51,68,34,116,101,120,116,45,100,101,99,111,114,97,116,105,111,110,58,110,111,110,101,61,13,10,59,98,111,114,100,101,114,45,115,116,121,108,101,58,110,111,110,101,59,98,111,114,100,101,114,58,48,59,112,97,100,100,105,110,103,58,48,59,109,97,114,103,105,110,58,48,59,102,111,110,116,45,102,97,109,105,108,121,58,39,72,101,108,118,101,116,105,99,97,78,101,117,101,39,44,61,13,10,32,39,72,101,108,118,101,116,105,99,97,32,78,101,117,101,39,44,32,72,101,108,118,101,116,105,99,97,44,32,65,114,105,97,108,44,32,115,97,110,115,45,115,101,114,105,102,59,45,119,101,98,107,105,116,45,102,111,110,116,45,115,109,111,111,116,104,105,110,103,58,97,110,116,105,61,13,10,97,108,105,97,115,101,100,59,99,111,108,111,114,58,35,56,56,57,57,65,54,59,102,111,110,116,45,115,105,122,101,58,49,50,112,120,59,112,97,100,100,105,110,103,58,48,112,120,59,109,97,114,103,105,110,58,48,112,120,59,102,111,110,116,45,119,101,105,103,104,116,58,110,111,114,61,13,10,109,97,108,59,108,105,110,101,45,104,101,105,103,104,116,58,49,50,112,120,59,99,117,114,115,111,114,58,100,101,102,97,117,108,116,59,34,62,88,32,67,111,114,112,46,32,49,51,53,53,32,77,97,114,107,101,116,32,83,116,114,101,101,116,44,32,83,117,105,116,101,32,57,48,48,61,13,10,32,83,97,110,32,70,114,97,110,99,105,115,99,111,44,32,67,65,32,57,52,49,48,51,60,47,97,62,32,60,47,115,112,97,110,62,32,60,47,116,100,62,13,10,60,47,116,114,62,13,10,60,116,114,62,13,10,60,116,100,32,104,101,105,103,104,116,61,51,68,34,55,50,34,32,115,116,121,108,101,61,51,68,34,104,101,105,103,104,116,58,55,50,112,120,59,112,97,100,100,105,110,103,58,48,59,109,97,114,103,105,110,58,48,59,108,105,110,101,45,104,101,105,103,104,116,58,49,112,120,59,102,61,13,10,111,110,116,45,115,105,122,101,58,49,112,120,59,34,62,60,47,116,100,62,13,10,60,47,116,114,62,13,10,60,47,116,98,111,100,121,62,13,10,60,47,116,97,98,108,101,62,13,10,60,33,45,45,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,32,101,110,100,32,102,111,111,116,101,114,32,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,45,45,62,32,60,47,116,100,62,13,10,60,47,116,114,62,13,10,60,47,116,98,111,100,121,62,13,10,60,47,116,97,98,108,101,62,13,10,60,47,98,111,100,121,62,13,10,60,47,104,116,109,108,62,13,10,45,45,45,45,45,45,61,95,80,97,114,116,95,51,48,50,53,53,52,49,95,49,51,57,53,53,57,50,53,54,54,46,49,55,53,54,55,52,52,49,55,49,50,51,48,45,45,13,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},\"body_hash_index\":366,\"command\":[\"85032600163920399473468279312950221173836508678231302942561155984767675459\",\"179150172561695665779863979615782336199001738146281935132720574537795002744\",\"228470014919439913465702\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\"],\"decoded_body\":{\"len\":1509,\"storage\":[117,114,105,116,121,32,116,105,112,115,60,47,97,62,32,60,47,115,112,97,110,62,32,60,47,116,100,62,13,10,60,47,116,114,62,13,10,60,116,114,62,13,10,60,116,100,32,104,101,105,103,104,116,61,51,68,34,49,50,34,32,115,116,121,108,101,61,51,68,34,104,101,105,103,104,116,58,49,50,112,120,59,108,105,110,101,45,104,101,105,103,104,116,58,49,112,120,59,102,111,110,116,45,115,105,122,101,58,49,112,120,59,112,97,100,100,105,110,103,58,48,59,109,97,114,103,105,110,58,48,59,108,105,110,101,45,104,101,105,103,104,116,58,49,112,120,59,102,111,110,116,45,115,105,122,101,58,49,112,120,59,34,62,60,47,116,100,62,13,10,60,47,116,114,62,13,10,60,116,114,62,13,10,60,116,100,32,97,108,105,103,110,61,51,68,34,99,101,110,116,101,114,34,32,115,116,121,108,101,61,51,68,34,112,97,100,100,105,110,103,58,48,59,109,97,114,103,105,110,58,48,59,108,105,110,101,45,104,101,105,103,104,116,58,49,112,120,59,102,111,110,116,45,115,105,122,101,58,49,112,120,59,34,62,32,60,115,112,97,110,32,99,108,97,115,115,61,51,68,34,115,109,97,108,108,45,99,111,112,121,34,32,115,116,121,108,101,61,51,68,34,102,111,110,116,45,102,97,109,105,108,121,58,39,72,101,108,118,101,116,105,99,97,78,101,117,101,39,44,32,39,72,101,108,118,101,116,105,99,97,32,78,101,117,101,39,44,32,72,101,108,118,101,116,105,99,97,44,32,65,114,105,97,108,44,32,115,97,110,115,45,115,101,114,105,102,59,102,111,110,116,45,115,105,122,101,58,49,50,112,120,59,108,105,110,101,45,104,101,105,103,104,116,58,49,54,112,120,59,102,111,110,116,45,119,101,105,103,104,116,58,52,48,48,59,99,111,108,111,114,58,35,56,56,57,57,65,54,59,116,101,120,116,45,97,108,105,103,110,58,108,101,102,116,59,116,101,120,116,45,100,101,99,111,114,97,116,105,111,110,58,110,111,110,101,59,45,119,101,98,107,105,116,45,102,111,110,116,45,115,109,111,111,116,104,105,110,103,58,97,110,116,105,97,108,105,97,115,101,100,59,34,62,32,84,104,105,115,32,101,109,97,105,108,32,119,97,115,32,109,101,97,110,116,32,102,111,114,32,64,116,104,101,122,100,101,118,49,32,60,47,115,112,97,110,62,32,60,47,116,100,62,13,10,60,47,116,114,62,13,10,60,116,114,62,13,10,60,116,100,32,104,101,105,103,104,116,61,51,68,34,54,34,32,115,116,121,108,101,61,51,68,34,104,101,105,103,104,116,58,54,112,120,59,108,105,110,101,45,104,101,105,103,104,116,58,49,112,120,59,102,111,110,116,45,115,105,122,101,58,49,112,120,59,112,97,100,100,105,110,103,58,48,59,109,97,114,103,105,110,58,48,59,108,105,110,101,45,104,101,105,103,104,116,58,49,112,120,59,102,111,110,116,45,115,105,122,101,58,49,112,120,59,34,62,60,47,116,100,62,13,10,60,47,116,114,62,13,10,60,116,114,62,13,10,60,116,100,32,97,108,105,103,110,61,51,68,34,99,101,110,116,101,114,34,32,115,116,121,108,101,61,51,68,34,112,97,100,100,105,110,103,58,48,59,109,97,114,103,105,110,58,48,59,108,105,110,101,45,104,101,105,103,104,116,58,49,112,120,59,102,111,110,116,45,115,105,122,101,58,49,112,120,59,34,62,32,60,115,112,97,110,32,99,108,97,115,115,61,51,68,34,97,100,100,114,101,115,115,34,62,32,60,97,32,104,114,101,102,61,51,68,34,35,34,32,115,116,121,108,101,61,51,68,34,116,101,120,116,45,100,101,99,111,114,97,116,105,111,110,58,110,111,110,101,59,98,111,114,100,101,114,45,115,116,121,108,101,58,110,111,110,101,59,98,111,114,100,101,114,58,48,59,112,97,100,100,105,110,103,58,48,59,109,97,114,103,105,110,58,48,59,102,111,110,116,45,102,97,109,105,108,121,58,39,72,101,108,118,101,116,105,99,97,78,101,117,101,39,44,32,39,72,101,108,118,101,116,105,99,97,32,78,101,117,101,39,44,32,72,101,108,118,101,116,105,99,97,44,32,65,114,105,97,108,44,32,115,97,110,115,45,115,101,114,105,102,59,45,119,101,98,107,105,116,45,102,111,110,116,45,115,109,111,111,116,104,105,110,103,58,97,110,116,105,97,108,105,97,115,101,100,59,99,111,108,111,114,58,35,56,56,57,57,65,54,59,102,111,110,116,45,115,105,122,101,58,49,50,112,120,59,112,97,100,100,105,110,103,58,48,112,120,59,109,97,114,103,105,110,58,48,112,120,59,102,111,110,116,45,119,101,105,103,104,116,58,110,111,114,109,97,108,59,108,105,110,101,45,104,101,105,103,104,116,58,49,50,112,120,59,99,117,114,115,111,114,58,100,101,102,97,117,108,116,59,34,62,88,32,67,111,114,112,46,32,49,51,53,53,32,77,97,114,107,101,116,32,83,116,114,101,101,116,44,32,83,117,105,116,101,32,57,48,48,32,83,97,110,32,70,114,97,110,99,105,115,99,111,44,32,67,65,32,57,52,49,48,51,60,47,97,62,32,60,47,115,112,97,110,62,32,60,47,116,100,62,13,10,60,47,116,114,62,13,10,60,116,114,62,13,10,60,116,100,32,104,101,105,103,104,116,61,51,68,34,55,50,34,32,115,116,121,108,101,61,51,68,34,104,101,105,103,104,116,58,55,50,112,120,59,112,97,100,100,105,110,103,58,48,59,109,97,114,103,105,110,58,48,59,108,105,110,101,45,104,101,105,103,104,116,58,49,112,120,59,102,111,110,116,45,115,105,122,101,58,49,112,120,59,34,62,60,47,116,100,62,13,10,60,47,116,114,62,13,10,60,47,116,98,111,100,121,62,13,10,60,47,116,97,98,108,101,62,13,10,60,33,45,45,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,32,101,110,100,32,102,111,111,116,101,114,32,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,45,45,62,32,60,47,116,100,62,13,10,60,47,116,114,62,13,10,60,47,116,98,111,100,121,62,13,10,60,47,116,97,98,108,101,62,13,10,60,47,98,111,100,121,62,13,10,60,47,104,116,109,108,62,13,10,45,45,45,45,45,45,61,95,80,97,114,116,95,51,48,50,53,53,52,49,95,49,51,57,53,53,57,50,53,54,54,46,49,55,53,54,55,52,52,49,55,49,50,51,48,45,45,13,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},\"dkim_header_sequence\":{\"index\":272,\"length\":203},\"header\":{\"len\":475,\"storage\":[100,97,116,101,58,77,111,110,44,32,48,49,32,83,101,112,32,50,48,50,53,32,49,54,58,50,57,58,51,49,32,43,48,48,48,48,13,10,102,114,111,109,58,88,32,60,105,110,102,111,64,120,46,99,111,109,62,13,10,116,111,58,122,100,101,118,32,60,116,104,101,122,100,101,118,49,64,103,109,97,105,108,46,99,111,109,62,13,10,115,117,98,106,101,99,116,58,80,97,115,115,119,111,114,100,32,114,101,115,101,116,32,114,101,113,117,101,115,116,13,10,109,105,109,101,45,118,101,114,115,105,111,110,58,49,46,48,13,10,99,111,110,116,101,110,116,45,116,121,112,101,58,109,117,108,116,105,112,97,114,116,47,97,108,116,101,114,110,97,116,105,118,101,59,32,98,111,117,110,100,97,114,121,61,34,45,45,45,45,61,95,80,97,114,116,95,51,48,50,53,53,52,49,95,49,51,57,53,53,57,50,53,54,54,46,49,55,53,54,55,52,52,49,55,49,50,51,48,34,13,10,109,101,115,115,97,103,101,45,105,100,58,60,48,53,46,70,56,46,50,57,55,52,51,46,66,69,57,67,53,66,56,54,64,120,46,99,111,109,62,13,10,100,107,105,109,45,115,105,103,110,97,116,117,114,101,58,118,61,49,59,32,97,61,114,115,97,45,115,104,97,50,53,54,59,32,99,61,114,101,108,97,120,101,100,47,114,101,108,97,120,101,100,59,32,100,61,120,46,99,111,109,59,32,115,61,100,107,105,109,45,50,48,50,51,48,56,59,32,116,61,49,55,53,54,55,52,52,49,55,49,59,32,98,104,61,88,47,115,78,77,109,87,52,77,121,48,98,82,100,50,73,78,114,75,57,48,65,66,121,98,80,117,88,101,79,84,82,99,47,104,67,105,101,101,104,102,104,115,61,59,32,104,61,68,97,116,101,58,70,114,111,109,58,84,111,58,83,117,98,106,101,99,116,58,77,73,77,69,45,86,101,114,115,105,111,110,58,67,111,110,116,101,110,116,45,84,121,112,101,58,77,101,115,115,97,103,101,45,73,68,59,32,98,61,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},\"partial_body_hash\":[2716496725,1937426258,2293599503,2645896470,4105601631,4002592056,3491810135,2710259935],\"partial_body_real_length\":14098,\"prover_address\":[\"0x0000000000000000000000000000000000000000\"],\"pubkey\":{\"modulus\":[\"0x8967a931d2ca21c652df494825c63d\",\"0x7d068b9c6250147cacb8f0786dccb5\",\"0x7436a40c9b68e7298c65045a93fc87\",\"0x9020a67668fbaac0d540947f0653f3\",\"0xd19710c0036acc7efb1c5f6c8a4faf\",\"0xefe0b5c633b0be4b86ebe17db85154\",\"0xc33caef88bc13f6ab2725c3386f721\",\"0x075051819421b1a461accf75851dff\",\"0x6fa3c2ec6bae4360f33c7a6bdc1647\",\"0xe197ac59d1c54fef22294ba23274d5\",\"0x1fe2fcf682109ce8f7875c7789c84b\",\"0xbfc2b278635688cc33b89956ed8d73\",\"0x2ae064a2431efe13336926c9b8b82a\",\"0xf8b24f943dd0acf064691e18beb4f7\",\"0xc618092fcc16c581b9e81113cc87c1\",\"0xf9113b691b82bfa396cf869b94bf6e\",\"0x76f3879ada6d3f8859e8150281a74b\",\"0xbf\"],\"redc\":[\"0x49d32b52b73e1f5dcf16b848dc145c\",\"0x2ebcef9575a2de39b251488d54d757\",\"0x44e4d199a932fc02a2629211332a85\",\"0x6a48be2e6a7bb5f18ed4234482b935\",\"0x120fb1d1d1a6d14702f54d22f3b353\",\"0x412475e6ad621e9e9e3dd17e4df885\",\"0x0ac7170aa843385efbdbffd8f00531\",\"0xe179c9a19576d47188d09bed675b37\",\"0x18bcf06ab745979ecee27ecb307ff0\",\"0xbd50d9ffba4eb337089a8d2bf08e0a\",\"0xbf428561893f274568c298836ac2c5\",\"0x9713d20bb3f20d843b18164a8dfdb7\",\"0xdb2339e26a7c78c265887fb09e8594\",\"0x1694eb4fc858b0b003c83073921753\",\"0xde3d74b94c549832e46fb3c8e9669c\",\"0x68a2b9d5fc918bf336b4629c844d8c\",\"0x9a81f331fe70c1560a62352fb5d41c\",\"0x1564\"]},\"sender_domain_capture_group_1_id\":[0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"sender_domain_capture_group_1_start\":[0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"sender_domain_capture_group_start_indices\":[5],\"sender_domain_current_states\":[1,2,2,2,2,3,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"sender_domain_match_length\":11,\"sender_domain_match_start\":46,\"sender_domain_next_states\":[2,2,2,2,3,4,4,4,4,4,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"signature\":[\"0xaf369158ed2c1281bae66cc102b770\",\"0x46c860c6a37d6b34fe7154782db5bb\",\"0x807b78c6113870aca8593121974a33\",\"0x81c0ce8a64a90101540cca6aad735c\",\"0x24e1f294de4cc3d5e3b32399356f49\",\"0xbafd0c7ae22763f8fb35b21c6ccc48\",\"0x8056511765d161bc8b7fd5ac724224\",\"0x86d2a6813c87995842cc4b481e0371\",\"0x6fbdb44d30d0f07db7439347332970\",\"0xe4ec855bb972d867ee1d363c8b4cfb\",\"0x176074c03680b51a9045367daec140\",\"0x167aac207a1b85ebb433106e074a33\",\"0x4e03eb000dd8446900995a9d7d004b\",\"0x041ee164b1ae04af00e400f74625ea\",\"0xb082c568149d794dbaf46261ebd495\",\"0x332c971fe36e86668583ae50827f64\",\"0x5b9bc926a11fca1b5226d23100a853\",\"0xb3\"],\"x_handle_capture_group_1_id\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"x_handle_capture_group_1_start\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"x_handle_capture_group_start_indices\":[26],\"x_handle_current_states\":[0,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,28,28,28,28,28,28,28,29,30,31,32,33,34,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"x_handle_match_length\":42,\"x_handle_match_start\":514,\"x_handle_next_states\":[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,28,28,28,28,28,28,28,29,30,31,32,33,34,35,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}" +} diff --git a/test/fixtures/linkHandleCommand/twitter/src/main.nr b/test/fixtures/linkHandleCommand/twitter/src/main.nr new file mode 100644 index 0000000..0bf2d04 --- /dev/null +++ b/test/fixtures/linkHandleCommand/twitter/src/main.nr @@ -0,0 +1,85 @@ +mod x_handle_regex; +mod sender_domain_regex; +use poseidon::poseidon; +use std::{collections::bounded_vec::BoundedVec, hash::pedersen_hash}; +use zkemail::{ + dkim::RSAPubkey, hash::poseidon_large, headers::body_hash::get_body_hash, KEY_LIMBS_2048, + partial_hash::partial_sha256_var_end, remove_soft_line_breaks::remove_soft_line_breaks, + Sequence, utils::pack_bytes, +}; +fn main( + header: BoundedVec, + pubkey: RSAPubkey, + signature: [Field; KEY_LIMBS_2048], + prover_address: [Field; 1], + dkim_header_sequence: Sequence, + body: BoundedVec, + body_hash_index: u32, + partial_body_hash: [u32; 8], + partial_body_real_length: u64, + decoded_body: BoundedVec, + command: [Field; 20], + x_handle_match_start: u32, + x_handle_match_length: u32, + x_handle_current_states: [Field; 64], + x_handle_next_states: [Field; 64], + x_handle_capture_group_1_id: [Field; 64], + x_handle_capture_group_1_start: [Field; 64], + x_handle_capture_group_start_indices: [Field; 1], + sender_domain_match_start: u32, + sender_domain_match_length: u32, + sender_domain_current_states: [Field; 64], + sender_domain_next_states: [Field; 64], + sender_domain_capture_group_1_id: [Field; 64], + sender_domain_capture_group_1_start: [Field; 64], + sender_domain_capture_group_start_indices: [Field; 1], + ) -> pub (Field, Field, Field, Field, [Field; 1], [Field; 20], BoundedVec, BoundedVec) { + // check the body and header lengths are within bounds + assert(header.len() <= 960); + assert(body.len() <= 1920); + // DKIM Verification + let header_hash: [u8; 32] = pubkey.verify_dkim_signature(header, signature); + let header_hash: [Field; 2] = pack_bytes::<32, 16>(header_hash); + // Body Hash Verification + let signed_body_hash = get_body_hash(header, dkim_header_sequence, body_hash_index); + let computed_body_hash: [u8; 32] = partial_sha256_var_end( + partial_body_hash, + body.storage(), + body.len() as u64, + partial_body_real_length, + ); + assert( + signed_body_hash == computed_body_hash, + "SHA256 hash computed over body does not match body hash found in DKIM-signed header", + ); + assert( + remove_soft_line_breaks(body.storage(), decoded_body.storage()), + "Decoded body does not properly remove soft line breaks", + ); + let pubkey_hash = pubkey.hash(); + let email_nullifier = poseidon::bn254::hash_1([poseidon_large(signature)]); + let x_handle_capture_1 = x_handle_regex::regex_match::<1920, 64>( + decoded_body.storage(), + x_handle_match_start, + x_handle_match_length, + x_handle_current_states, + x_handle_next_states, + x_handle_capture_group_1_id, + x_handle_capture_group_1_start, + x_handle_capture_group_start_indices, + ); + let sender_domain_capture_1 = sender_domain_regex::regex_match::<960, 64>( + header.storage(), + sender_domain_match_start, + sender_domain_match_length, + sender_domain_current_states, + sender_domain_next_states, + sender_domain_capture_group_1_id, + sender_domain_capture_group_1_start, + sender_domain_capture_group_start_indices, + ); + ( + pubkey_hash, email_nullifier, header_hash[0], header_hash[1], prover_address, command, + x_handle_capture_1, sender_domain_capture_1, + ) +} diff --git a/test/fixtures/linkHandleCommand/twitter/src/sender_domain_regex.nr b/test/fixtures/linkHandleCommand/twitter/src/sender_domain_regex.nr new file mode 100644 index 0000000..373d104 --- /dev/null +++ b/test/fixtures/linkHandleCommand/twitter/src/sender_domain_regex.nr @@ -0,0 +1,229 @@ +use zkregex::utils::{ + captures::capture_substring, select_subarray, sparse_array::SparseArray, + transitions::check_transition_with_captures, +}; + +global TRANSITION_TABLE: SparseArray<380, Field> = SparseArray { + keys: [ + 0x00000000, 0x00022523, 0x00022524, 0x00022525, 0x00022725, 0x00022726, 0x00022727, + 0x00022826, 0x00022827, 0x00022828, 0x00022927, 0x00022928, 0x00022929, 0x00022a28, + 0x00022a29, 0x00022a2a, 0x00022b29, 0x00022b2a, 0x00022b2b, 0x00022e2c, 0x00022e2d, + 0x00022e2e, 0x00022f2d, 0x00022f2e, 0x00022f2f, 0x0002312f, 0x00023130, 0x00023131, + 0x00023230, 0x00023231, 0x00023232, 0x00023331, 0x00023332, 0x00023333, 0x00023432, + 0x00023433, 0x00023434, 0x00023533, 0x00023534, 0x00023535, 0x00023634, 0x00023635, + 0x00023636, 0x00023735, 0x00023736, 0x00023737, 0x00023836, 0x00023837, 0x00023838, + 0x00023937, 0x00023938, 0x00023939, 0x00023a38, 0x00023a39, 0x00023a3a, 0x00023b39, + 0x00023b3a, 0x00023b3b, 0x00023c3a, 0x00023c3b, 0x00023c3c, 0x00023d3b, 0x00023d3c, + 0x00023d3d, 0x0002413f, 0x00024140, 0x00024141, 0x00024341, 0x00024342, 0x00024343, + 0x00024543, 0x00024544, 0x00024545, 0x00024644, 0x00024645, 0x00024646, 0x00024745, + 0x00024746, 0x00024747, 0x00024846, 0x00024847, 0x00024848, 0x00024947, 0x00024948, + 0x00024949, 0x00024a48, 0x00024a49, 0x00024a4a, 0x00024b49, 0x00024b4a, 0x00024b4b, + 0x00024c4a, 0x00024c4b, 0x00024c4c, 0x00024d4b, 0x00024d4c, 0x00024d4d, 0x00024e4c, + 0x00024e4d, 0x00024e4e, 0x00024f4d, 0x00024f4e, 0x00024f4f, 0x0002504e, 0x0002504f, + 0x00025050, 0x0002514f, 0x00025150, 0x00025151, 0x00025250, 0x00025251, 0x00025252, + 0x00025351, 0x00025352, 0x00025353, 0x00025452, 0x00025453, 0x00025454, 0x00025553, + 0x00025554, 0x00025555, 0x00025654, 0x00025655, 0x00025656, 0x00025755, 0x00025756, + 0x00025757, 0x00025856, 0x00025857, 0x00025858, 0x00025957, 0x00025958, 0x00025959, + 0x00025a58, 0x00025a59, 0x00025a5a, 0x00025b59, 0x00025b5a, 0x00025b5b, 0x00025c5a, + 0x00025c5b, 0x00025c5c, 0x00025d5b, 0x00025d5c, 0x00025d5d, 0x00025e5c, 0x00025e5d, + 0x00025e5e, 0x00026260, 0x00026261, 0x00026262, 0x00026361, 0x00026362, 0x00026363, + 0x00026462, 0x00026463, 0x00026464, 0x00026563, 0x00026564, 0x00026565, 0x00026664, + 0x00026665, 0x00026666, 0x00026765, 0x00026766, 0x00026767, 0x00026866, 0x00026867, + 0x00026868, 0x00026967, 0x00026968, 0x00026969, 0x00026a68, 0x00026a69, 0x00026a6a, + 0x00026b69, 0x00026b6a, 0x00026b6b, 0x00026c6a, 0x00026c6b, 0x00026c6c, 0x00026d6b, + 0x00026d6c, 0x00026d6d, 0x00026e6c, 0x00026e6d, 0x00026e6e, 0x00026f6d, 0x00026f6e, + 0x00026f6f, 0x0002706e, 0x0002706f, 0x00027070, 0x0002716f, 0x00027170, 0x00027171, + 0x00027270, 0x00027271, 0x00027272, 0x00027371, 0x00027372, 0x00027373, 0x00027472, + 0x00027473, 0x00027474, 0x00027573, 0x00027574, 0x00027575, 0x00027674, 0x00027675, + 0x00027676, 0x00027775, 0x00027776, 0x00027777, 0x00027876, 0x00027877, 0x00027878, + 0x00027977, 0x00027978, 0x00027979, 0x00027a78, 0x00027a79, 0x00027a7a, 0x00027b79, + 0x00027b7a, 0x00027b7b, 0x00027c7a, 0x00027c7b, 0x00027c7c, 0x00027d7b, 0x00027d7c, + 0x00027d7d, 0x00027e7c, 0x00027e7d, 0x00027e7e, 0x00027f7d, 0x00027f7e, 0x00027f7f, + 0x0002807e, 0x0002807f, 0x00028080, 0x0002817f, 0x00028180, 0x00028181, 0x00028280, + 0x00028281, 0x00028282, 0x00034645, 0x00043534, 0x00043535, 0x00043635, 0x00043636, + 0x00043837, 0x00043838, 0x00043938, 0x00043939, 0x00043a39, 0x00043a3a, 0x00043b3a, + 0x00043b3b, 0x00043c3b, 0x00043c3c, 0x00043d3c, 0x00043d3d, 0x00043e3d, 0x00043e3e, + 0x00043f3e, 0x00043f3f, 0x0004403f, 0x00044040, 0x00044140, 0x00044141, 0x00044847, + 0x00044848, 0x00044948, 0x00044949, 0x00044a49, 0x00044a4a, 0x00044b4a, 0x00044b4b, + 0x00044c4b, 0x00044c4c, 0x00044d4c, 0x00044d4d, 0x00044e4d, 0x00044e4e, 0x00044f4e, + 0x00044f4f, 0x0004504f, 0x00045050, 0x00045150, 0x00045151, 0x00045251, 0x00045252, + 0x00045352, 0x00045353, 0x00045453, 0x00045454, 0x00045554, 0x00045555, 0x00045655, + 0x00045656, 0x00045756, 0x00045757, 0x00045857, 0x00045858, 0x00045958, 0x00045959, + 0x00045a59, 0x00045a5a, 0x00045b5a, 0x00045b5b, 0x00045c5b, 0x00045c5c, 0x00045d5c, + 0x00045d5d, 0x00045e5d, 0x00045e5e, 0x00045f5e, 0x00045f5f, 0x0004605f, 0x00046060, + 0x00046160, 0x00046161, 0x00046261, 0x00046262, 0x00046968, 0x00046969, 0x00046a69, + 0x00046a6a, 0x00046b6a, 0x00046b6b, 0x00046c6b, 0x00046c6c, 0x00046d6c, 0x00046d6d, + 0x00046e6d, 0x00046e6e, 0x00046f6e, 0x00046f6f, 0x0004706f, 0x00047070, 0x00047170, + 0x00047171, 0x00047271, 0x00047272, 0x00047372, 0x00047373, 0x00047473, 0x00047474, + 0x00047574, 0x00047575, 0x00047675, 0x00047676, 0x00047776, 0x00047777, 0x00047877, + 0x00047878, 0x00047978, 0x00047979, 0x00047a79, 0x00047a7a, 0x00047b7a, 0x00047b7b, + 0x00047c7b, 0x00047c7c, 0x00047d7c, 0x00047d7d, 0x00047e7d, 0x00047e7e, 0x00047f7e, + 0x00047f7f, 0x0004807f, 0x00048080, 0x00048180, 0x00048181, 0x00048281, 0x00048282, + 0x00051413, 0x00051716, 0x00054847, 0x00060a09, + ], + values: [ + 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000001, 0x00000001, 0x00000001, 0x00000000, + ], + maximum: 0x00060a09, +}; + +pub global CAPTURE_1_MAX_LENGTH: u32 = 64; +pub global NUM_CAPTURE_GROUPS: u32 = 1; + +/** + * Constrains a start state to be valid + * @dev start states are hardcoded in this function - "(start_state - {state})" for each start + * example: `(start_state - 0) * (start_state - 1) * (start_state - 2)` means 0, 1, or 2 + * are valid first states + * + * @param start_state - The start state of the NFA + */ +fn check_start_state(start_state: Field) { + let valid_start_state = (start_state - 0) * (start_state - 1); + assert(valid_start_state == 0, "Invalid start state"); +} + +/** + * Constrains the recognition of accept_state being reached. If an aceppt state is reached, + * ensures asserted traversal path is valid + * @dev accept states are hardcoded in this function - "(next_state - {state})" for each accept + * example: `(next_state - 19) * (next_state - 20) * (next_state - 21)` means 19, 20, or 21 + * are valid accept states + * + * @param next_state - The asserted next state of the NFA + * @param haystack_index - The index being operated on in the haystack + * @param asserted_match_length - The asserted traversal path length + * @return - 0 if accept_state is reached, nonzero otherwise + */ +fn check_accept_state( + next_state: Field, + haystack_index: Field, + asserted_match_length: Field, +) -> Field { + // check if the next state is an accept state + let accept_state_reached = (next_state - 5); + let accept_state_reached_bool = (accept_state_reached == 0) as Field; + + // check if the haystack index is the asserted match length + // should equal 1 since haystack_index should be 1 less than asserted_match)length + let asserted_path_traversed = (asserted_match_length - haystack_index == 1) as Field; + + (1 - (accept_state_reached_bool * asserted_path_traversed)) +} + +/** + * SenderDomainRegex matching function + * Regex: [A-Za-z0-9!#$%&'*+=?\\-\\^_`{|}~./]+@([A-Za-z0-9.\\-@]+)[>\r\n] + * @param in_haystack - The input haystack to search from + * @param match_start - The start index in the haystack for the subarray to match from + * @param match_length - The length of the subarray to extract from haystack + * @param current_states - The current states of the NFA at each index in the match subarray + * @param next_states - The next states of the NFA at each index in the match subarray + * @param capture_group__ids - The ids of the capture groups in the match subarray + * @param capture_group__starts - The start positions of the capture groups in the match subarray + * @param capture_group_start_indices - The start indices of the capture groups in the match subarray + * @return - tuple of substring captures as dictated by the regular expression + */ +pub fn regex_match( + in_haystack: [u8; MAX_HAYSTACK_LEN], + match_start: u32, + match_length: u32, + current_states: [Field; MAX_MATCH_LEN], + next_states: [Field; MAX_MATCH_LEN], + capture_group_1_id: [Field; MAX_MATCH_LEN], + capture_group_1_start: [Field; MAX_MATCH_LEN], + capture_group_start_indices: [Field; NUM_CAPTURE_GROUPS], +) -> (BoundedVec) { + // resize haystack + let haystack: [u8; MAX_MATCH_LEN] = + select_subarray::(in_haystack, match_start, match_length); + + check_start_state(current_states[0]); + for i in 0..MAX_MATCH_LEN - 1 { + // match length - 1 since current states should be 1 less than next states + let in_range = (i < match_length - 1) as Field; + let matching_states = current_states[i + 1] - next_states[i]; + assert(in_range * matching_states == 0, "Invalid Transition Input"); + } + let mut reached_end_state = 1; + for i in 0..MAX_MATCH_LEN { + let active_capture_groups_at_index = [capture_group_1_id[i]]; + let active_capture_groups_starts_at_index = [capture_group_1_start[i]]; + check_transition_with_captures( + TRANSITION_TABLE, + haystack[i] as Field, + current_states[i], + next_states[i], + active_capture_groups_at_index, + active_capture_groups_starts_at_index, + reached_end_state, + ); + reached_end_state = reached_end_state + * check_accept_state(next_states[i], i as Field, match_length as Field); + } + assert(reached_end_state == 0, "Did not reach a valid end state"); + + // Capture Group 1 + let capture_1 = capture_substring::( + haystack, + capture_group_1_id, + capture_group_1_start, + capture_group_start_indices[0], + ); + + (capture_1) +} diff --git a/test/fixtures/linkHandleCommand/twitter/src/x_handle_regex.nr b/test/fixtures/linkHandleCommand/twitter/src/x_handle_regex.nr new file mode 100644 index 0000000..d59bbdf --- /dev/null +++ b/test/fixtures/linkHandleCommand/twitter/src/x_handle_regex.nr @@ -0,0 +1,167 @@ +use zkregex::utils::{ + captures::capture_substring, select_subarray, sparse_array::SparseArray, + transitions::check_transition_with_captures, +}; + +global TRANSITION_TABLE: SparseArray<161, Field> = SparseArray { + keys: [ + 0x00000000, 0x00025856, 0x00025857, 0x00036e6d, 0x00047170, 0x00057d7c, 0x00062c2b, + 0x00077372, 0x00087d7c, 0x00097372, 0x000a7d7c, 0x000b8281, 0x000c3837, 0x000d9190, + 0x000e7d7c, 0x000f9190, 0x0010403f, 0x00118f8e, 0x00128988, 0x00138786, 0x00149695, + 0x00159e9d, 0x00164c4b, 0x00179493, 0x00189f9e, 0x0019a4a3, 0x001a5453, 0x001b7675, + 0x001c6867, 0x001c6868, 0x001c6968, 0x001c6969, 0x001c6a69, 0x001c6a6a, 0x001c6b6a, + 0x001c6b6b, 0x001c6c6b, 0x001c6c6c, 0x001c6d6c, 0x001c6d6d, 0x001c6e6d, 0x001c6e6e, + 0x001c6f6e, 0x001c6f6f, 0x001c706f, 0x001c7070, 0x001c7170, 0x001c7171, 0x001c7978, + 0x001c7979, 0x001c7a79, 0x001c7a7a, 0x001c7b7a, 0x001c7b7b, 0x001c7c7b, 0x001c7c7c, + 0x001c7d7c, 0x001c7d7d, 0x001c7e7d, 0x001c7e7e, 0x001c7f7e, 0x001c7f7f, 0x001c807f, + 0x001c8080, 0x001c8180, 0x001c8181, 0x001c8281, 0x001c8282, 0x001c8382, 0x001c8383, + 0x001c8483, 0x001c8484, 0x001c8584, 0x001c8585, 0x001c8685, 0x001c8686, 0x001c8786, + 0x001c8787, 0x001c8887, 0x001c8888, 0x001c8988, 0x001c8989, 0x001c8a89, 0x001c8a8a, + 0x001c8b8a, 0x001c8b8b, 0x001c8c8b, 0x001c8c8c, 0x001c8d8c, 0x001c8d8d, 0x001c8e8d, + 0x001c8e8e, 0x001c8f8e, 0x001c8f8f, 0x001c908f, 0x001c9090, 0x001c9190, 0x001c9191, + 0x001c9291, 0x001c9292, 0x001c9796, 0x001c9797, 0x001c9998, 0x001c9999, 0x001c9a99, + 0x001c9a9a, 0x001c9b9a, 0x001c9b9b, 0x001c9c9b, 0x001c9c9c, 0x001c9d9c, 0x001c9d9d, + 0x001c9e9d, 0x001c9e9e, 0x001c9f9e, 0x001c9f9f, 0x001ca09f, 0x001ca0a0, 0x001ca1a0, + 0x001ca1a1, 0x001ca2a1, 0x001ca2a2, 0x001ca3a2, 0x001ca3a3, 0x001ca4a3, 0x001ca4a4, + 0x001ca5a4, 0x001ca5a5, 0x001ca6a5, 0x001ca6a6, 0x001ca7a6, 0x001ca7a7, 0x001ca8a7, + 0x001ca8a8, 0x001ca9a8, 0x001ca9a9, 0x001caaa9, 0x001caaaa, 0x001cabaa, 0x001cabab, + 0x001cacab, 0x001cacac, 0x001cadac, 0x001cadad, 0x001caead, 0x001caeae, 0x001cafae, + 0x001cafaf, 0x001cb0af, 0x001cb0b0, 0x001cb1b0, 0x001cb1b1, 0x001cb2b1, 0x001cb2b2, + 0x001d5a59, 0x001e7877, 0x001f6d6c, 0x0020b3b2, 0x0021b2b1, 0x0022a5a4, 0x0023b4b3, + 0x00248685, 0x00254847, + ], + values: [ + 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, + 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, + 0x00000005, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, + 0x00000001, 0x00000001, 0x00000000, + ], + maximum: 0x00254847, +}; + +pub global CAPTURE_1_MAX_LENGTH: u32 = 64; +pub global NUM_CAPTURE_GROUPS: u32 = 1; + +/** + * Constrains a start state to be valid + * @dev start states are hardcoded in this function - "(start_state - {state})" for each start + * example: `(start_state - 0) * (start_state - 1) * (start_state - 2)` means 0, 1, or 2 + * are valid first states + * + * @param start_state - The start state of the NFA + */ +fn check_start_state(start_state: Field) { + let valid_start_state = (start_state - 0) * (start_state - 1); + assert(valid_start_state == 0, "Invalid start state"); +} + +/** + * Constrains the recognition of accept_state being reached. If an aceppt state is reached, + * ensures asserted traversal path is valid + * @dev accept states are hardcoded in this function - "(next_state - {state})" for each accept + * example: `(next_state - 19) * (next_state - 20) * (next_state - 21)` means 19, 20, or 21 + * are valid accept states + * + * @param next_state - The asserted next state of the NFA + * @param haystack_index - The index being operated on in the haystack + * @param asserted_match_length - The asserted traversal path length + * @return - 0 if accept_state is reached, nonzero otherwise + */ +fn check_accept_state( + next_state: Field, + haystack_index: Field, + asserted_match_length: Field, +) -> Field { + // check if the next state is an accept state + let accept_state_reached = (next_state - 36); + let accept_state_reached_bool = (accept_state_reached == 0) as Field; + + // check if the haystack index is the asserted match length + // should equal 1 since haystack_index should be 1 less than asserted_match)length + let asserted_path_traversed = (asserted_match_length - haystack_index == 1) as Field; + + (1 - (accept_state_reached_bool * asserted_path_traversed)) +} + +/** + * XHandleRegex matching function + * Regex: This email was meant for @([A-Za-z0-9_]+) + * @param in_haystack - The input haystack to search from + * @param match_start - The start index in the haystack for the subarray to match from + * @param match_length - The length of the subarray to extract from haystack + * @param current_states - The current states of the NFA at each index in the match subarray + * @param next_states - The next states of the NFA at each index in the match subarray + * @param capture_group__ids - The ids of the capture groups in the match subarray + * @param capture_group__starts - The start positions of the capture groups in the match subarray + * @param capture_group_start_indices - The start indices of the capture groups in the match subarray + * @return - tuple of substring captures as dictated by the regular expression + */ +pub fn regex_match( + in_haystack: [u8; MAX_HAYSTACK_LEN], + match_start: u32, + match_length: u32, + current_states: [Field; MAX_MATCH_LEN], + next_states: [Field; MAX_MATCH_LEN], + capture_group_1_id: [Field; MAX_MATCH_LEN], + capture_group_1_start: [Field; MAX_MATCH_LEN], + capture_group_start_indices: [Field; NUM_CAPTURE_GROUPS], +) -> (BoundedVec) { + // resize haystack + let haystack: [u8; MAX_MATCH_LEN] = + select_subarray::(in_haystack, match_start, match_length); + + check_start_state(current_states[0]); + for i in 0..MAX_MATCH_LEN - 1 { + // match length - 1 since current states should be 1 less than next states + let in_range = (i < match_length - 1) as Field; + let matching_states = current_states[i + 1] - next_states[i]; + assert(in_range * matching_states == 0, "Invalid Transition Input"); + } + let mut reached_end_state = 1; + for i in 0..MAX_MATCH_LEN { + let active_capture_groups_at_index = [capture_group_1_id[i]]; + let active_capture_groups_starts_at_index = [capture_group_1_start[i]]; + check_transition_with_captures( + TRANSITION_TABLE, + haystack[i] as Field, + current_states[i], + next_states[i], + active_capture_groups_at_index, + active_capture_groups_starts_at_index, + reached_end_state, + ); + reached_end_state = reached_end_state + * check_accept_state(next_states[i], i as Field, match_length as Field); + } + assert(reached_end_state == 0, "Did not reach a valid end state"); + + // Capture Group 1 + let capture_1 = capture_substring::( + haystack, + capture_group_1_id, + capture_group_1_start, + capture_group_start_indices[0], + ); + + (capture_1) +} diff --git a/test/fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol b/test/fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol new file mode 100644 index 0000000..28bd7b2 --- /dev/null +++ b/test/fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol @@ -0,0 +1,1883 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2022 Aztec +pragma solidity >=0.8.21; + +uint256 constant N = 524288; +uint256 constant LOG_N = 19; +uint256 constant NUMBER_OF_PUBLIC_INPUTS = 155; +library HonkVerificationKey { + function loadVerificationKey() internal pure returns (Honk.VerificationKey memory) { + Honk.VerificationKey memory vk = Honk.VerificationKey({ + circuitSize: uint256(524288), + logCircuitSize: uint256(19), + publicInputsSize: uint256(155), + ql: Honk.G1Point({ + x: uint256(0x1a7210ba96c8b6c29b36aee5b50314f5c4158b938bc01af8a806d891cfff6480), + y: uint256(0x145831f09c7528cf686ccfaa6690596a8a8fd2976c9e7f915fdfcd7af416c3d9) + }), + qr: Honk.G1Point({ + x: uint256(0x2c23a7bf1a4c0e1f8f6bd815fff6d2bc1e4adb170987d98727899a9dd7ecd5f7), + y: uint256(0x14ea777c20aab015bef566f664204487995b714ba5565f8b8f84ba1bd72f22b2) + }), + qo: Honk.G1Point({ + x: uint256(0x16f662e2c4345028c82ac5a5b0121d0e7e4ee0b2085fa7fad70b2c17a998cc7d), + y: uint256(0x0ce1d12dd14f5209aa10a93c87701ded85802b3bd41ef7822e43e08402a4da5b) + }), + q4: Honk.G1Point({ + x: uint256(0x208969616f7d5aedbffa302e7090aea6af18d65a9d83d69df6ef1facd353d0e7), + y: uint256(0x179f6562d9adb58dd4103b16efc77c7d5e61ff80c77f1f5f26aded02c6d733f0) + }), + qm: Honk.G1Point({ + x: uint256(0x12921b19b24447ba841027ebe25dd5428781bda07af9d8ef6ff480946dd75e92), + y: uint256(0x2e9aa3501ceba3ac369602fd299c109e915891cb4a5f04e9b567c366c75c3b1f) + }), + qc: Honk.G1Point({ + x: uint256(0x0ce49c89c2833a08c0dfa578860de87188278085f2d6cde77a385e1b8f72785a), + y: uint256(0x068bb8e2a0ac69b84d51bf0f7f5a23a92ef5cf2a65a38781ffd24a5d8a7ba24e) + }), + qArith: Honk.G1Point({ + x: uint256(0x2e44810bb8254da0223f05a48f676b6cf9d937b1cbc9593d263743a76d017cec), + y: uint256(0x12ebaa449b5153bdeefeefd18db82c08315d2ec6e95610c898ed771fb953b4a8) + }), + qDeltaRange: Honk.G1Point({ + x: uint256(0x0255d78987e5cb213de5ae10e81a36f0d218936d5f5b396787d5dce64118837a), + y: uint256(0x23fb776efa1c16e8f911648fb199823fb996aa54a7852b07f33c0cde5585b7e1) + }), + qElliptic: Honk.G1Point({ + x: uint256(0x175d1b3a92888ac3b21d5460919d7a8dee522fc3f7e7588bb7937356f31318a6), + y: uint256(0x258d10d36596389fef6524bbe933afff25a338f8a1be8ea6eff462ebb699df6f) + }), + qAux: Honk.G1Point({ + x: uint256(0x25f6b4c4b1d0bf5b8bc82298369a1c49d41c83e922502d9ee6cefa2f1f2b1ae4), + y: uint256(0x0fca6cf0671751857d3f332e12041afd19dc4aa03cc341516bdf30c2d52f9787) + }), + qLookup: Honk.G1Point({ + x: uint256(0x076d3f92dff00e732053b3b7248f2949cf66e2ff39fe4800f14a23555881d08f), + y: uint256(0x19f2844ef71502fada8390017b2881c376c839f0a71748129279029ec262c939) + }), + qPoseidon2External: Honk.G1Point({ + x: uint256(0x27965a98c47f39936cae1d648b2ea446f3bfcb7c72e041f56d2c6f0a00d01f0b), + y: uint256(0x2855b07d2683d0ec1b7636353522722b2027eb33e77d1b7c78857ec1efdcef08) + }), + qPoseidon2Internal: Honk.G1Point({ + x: uint256(0x1e9291bd098e69bc19943506da6c5fa5930482c111625bb10561bc7dd2b74216), + y: uint256(0x22a4094030024039e3a35ed18c464923e19ece17a26a11c593a43d93113f4cf7) + }), + s1: Honk.G1Point({ + x: uint256(0x15dc27b81554a6ddb3a649a3e101c0a224fa707e1dc302fad9a69eaa08bd4f38), + y: uint256(0x129a625be0f4d4897a4166d8941edcb4eaae32867d331292f88e8e44cd38d155) + }), + s2: Honk.G1Point({ + x: uint256(0x29512e721dcdbe168ff49b6f5c03e9448bb0b84a2b3a2775a1458ad7e2c1c32e), + y: uint256(0x13df76c9ac079116a26bed197bcb59c44b868ce6a09e7d720e1c16a403fc1726) + }), + s3: Honk.G1Point({ + x: uint256(0x2aa14957fae029f300cd9212dabece20eab126fe10b485a34a9f0362e306f76f), + y: uint256(0x2f3ca257e590e53f7c5211db28e97a10cf0caa33966acc9ba02c3b3d43c420c6) + }), + s4: Honk.G1Point({ + x: uint256(0x15f830463f615fd2f06f785f54414e650ae5843a97ab6a66a226821cdbe40d30), + y: uint256(0x05ec0391af74def03aebc53630b022f0fdd01f00198aa189a995813eac300a97) + }), + t1: Honk.G1Point({ + x: uint256(0x0dd222939afbd6003c7c4f993cb8c1febbcc78eabdd8f8c64b3cc99d67e7bc60), + y: uint256(0x0b24bbcbf63f6831e3556faf0faa608f6217d424f792e0b1bfb8f3e76d9fbd63) + }), + t2: Honk.G1Point({ + x: uint256(0x0f3b9ddedb0512c47e8dd3bbeedbbbcec72de691652997c1b4e7ab77b47372f2), + y: uint256(0x26e208f54695e664f4bd6e8702e24bfe12f28d3769425beb2a729d77c38d3b06) + }), + t3: Honk.G1Point({ + x: uint256(0x14debd26a50495873bf21841857729cb99b3c28b1ba6bc3f7240f39f17ca1c27), + y: uint256(0x2b3afdc5fb6fbdfa39c15a0db1cdea6e20a415754e1e032233f048f84d588b7c) + }), + t4: Honk.G1Point({ + x: uint256(0x171de77a99874ca1f1035e5950a0cb131756627388ab64ea530d5967400c846b), + y: uint256(0x16e024c7a0985ad98c91599ff8b5478356f289b60c9cb110eaa18ea464d89faa) + }), + id1: Honk.G1Point({ + x: uint256(0x191750aa8336e364f0d08db18bb521f1bce1b46700e71f791eda547d98aff253), + y: uint256(0x2a68390660612925ccc0abb53a966562d3402e3673cfd27b431d39f34f1da311) + }), + id2: Honk.G1Point({ + x: uint256(0x07a4f4a3b0922201179fabd2354553d553480b0d7868d8a70744072e8bde71b3), + y: uint256(0x063feb660361d9bc79992f7b1ceb8bf1836944190bcd45e80fc47d79cfc1b61e) + }), + id3: Honk.G1Point({ + x: uint256(0x1bc6c2aa9d5c73803e9245b07f86394fcb8c721d5acaeeef31e177be41463e50), + y: uint256(0x0192e119993e4aa355eb6183a27377b0363927cbc3868bdbb0cc609d9d73afb3) + }), + id4: Honk.G1Point({ + x: uint256(0x151189c9e62b0ef38907ab84cb472ccedb531721266dea883dbf250245b6251b), + y: uint256(0x1f1416bb4654f31e85e2049a732b5dfd90f036689bce26ee5417779abe44f1e9) + }), + lagrangeFirst: Honk.G1Point({ + x: uint256(0x0000000000000000000000000000000000000000000000000000000000000001), + y: uint256(0x0000000000000000000000000000000000000000000000000000000000000002) + }), + lagrangeLast: Honk.G1Point({ + x: uint256(0x1e813ba4f3d08a3289ed528ef9425189ae1240e7c2e086dd4c267edd6b729705), + y: uint256(0x1bb8bb58399caa55cccf0b1fb45ca0a9ca863c2769aacb6f79bf6839f8b142a6) + }) + }); + return vk; + } +} + +pragma solidity ^0.8.27; + +type Fr is uint256; + +using { add as + } for Fr global; +using { sub as - } for Fr global; +using { mul as * } for Fr global; +using { exp as ^ } for Fr global; +using { notEqual as != } for Fr global; +using { equal as == } for Fr global; + +uint256 constant MODULUS = + 21888242871839275222246405745257275088548364400416034343698204186575808495617; // Prime field order + +Fr constant MINUS_ONE = Fr.wrap(MODULUS - 1); + +// Instantiation +library FrLib +{ + function from(uint256 value) internal pure returns(Fr) + { + return Fr.wrap(value % MODULUS); + } + + function fromBytes32(bytes32 value) internal pure returns(Fr) + { + return Fr.wrap(uint256(value) % MODULUS); + } + + function toBytes32(Fr value) internal pure returns(bytes32) + { + return bytes32(Fr.unwrap(value)); + } + + function invert(Fr value) internal view returns(Fr) + { + uint256 v = Fr.unwrap(value); + uint256 result; + + // Call the modexp precompile to invert in the field + assembly + { + let free := mload(0x40) + mstore(free, 0x20) + mstore(add(free, 0x20), 0x20) + mstore(add(free, 0x40), 0x20) + mstore(add(free, 0x60), v) + mstore(add(free, 0x80), sub(MODULUS, 2)) + mstore(add(free, 0xa0), MODULUS) + let success := staticcall(gas(), 0x05, free, 0xc0, 0x00, 0x20) + if iszero(success) { + revert(0, 0) + } + result := mload(0x00) + } + + return Fr.wrap(result); + } + + function pow(Fr base, uint256 v) internal view returns(Fr) + { + uint256 b = Fr.unwrap(base); + uint256 result; + + // Call the modexp precompile to invert in the field + assembly + { + let free := mload(0x40) + mstore(free, 0x20) + mstore(add(free, 0x20), 0x20) + mstore(add(free, 0x40), 0x20) + mstore(add(free, 0x60), b) + mstore(add(free, 0x80), v) + mstore(add(free, 0xa0), MODULUS) + let success := staticcall(gas(), 0x05, free, 0xc0, 0x00, 0x20) + if iszero(success) { + revert(0, 0) + } + result := mload(0x00) + } + + return Fr.wrap(result); + } + + function div(Fr numerator, Fr denominator) internal view returns(Fr) + { + return numerator * invert(denominator); + } + + function sqr(Fr value) internal pure returns (Fr) { + return value * value; + } + + function unwrap(Fr value) internal pure returns (uint256) { + return Fr.unwrap(value); + } + + function neg(Fr value) internal pure returns (Fr) { + return Fr.wrap(MODULUS - Fr.unwrap(value)); + } +} + +// Free functions +function add(Fr a, Fr b) pure returns(Fr) +{ + return Fr.wrap(addmod(Fr.unwrap(a), Fr.unwrap(b), MODULUS)); +} + +function mul(Fr a, Fr b) pure returns(Fr) +{ + return Fr.wrap(mulmod(Fr.unwrap(a), Fr.unwrap(b), MODULUS)); +} + +function sub(Fr a, Fr b) pure returns(Fr) +{ + return Fr.wrap(addmod(Fr.unwrap(a), MODULUS - Fr.unwrap(b), MODULUS)); +} + +function exp(Fr base, Fr exponent) pure returns(Fr) +{ + if (Fr.unwrap(exponent) == 0) return Fr.wrap(1); + + for (uint256 i = 1; i < Fr.unwrap(exponent); i += i) { + base = base * base; + } + return base; +} + +function notEqual(Fr a, Fr b) pure returns(bool) +{ + return Fr.unwrap(a) != Fr.unwrap(b); +} + +function equal(Fr a, Fr b) pure returns(bool) +{ + return Fr.unwrap(a) == Fr.unwrap(b); +} + +uint256 constant CONST_PROOF_SIZE_LOG_N = 28; + +uint256 constant NUMBER_OF_SUBRELATIONS = 26; +uint256 constant BATCHED_RELATION_PARTIAL_LENGTH = 8; +uint256 constant NUMBER_OF_ENTITIES = 40; +uint256 constant NUMBER_UNSHIFTED = 35; +uint256 constant NUMBER_TO_BE_SHIFTED = 5; + +// Alphas are used as relation separators so there should be NUMBER_OF_SUBRELATIONS - 1 +uint256 constant NUMBER_OF_ALPHAS = 25; + +// Prime field order +uint256 constant Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; // EC group order. F_q +uint256 constant P = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // Prime field order, F_r + +// ENUM FOR WIRES +enum WIRE { + Q_M, + Q_C, + Q_L, + Q_R, + Q_O, + Q_4, + Q_LOOKUP, + Q_ARITH, + Q_RANGE, + Q_ELLIPTIC, + Q_AUX, + Q_POSEIDON2_EXTERNAL, + Q_POSEIDON2_INTERNAL, + SIGMA_1, + SIGMA_2, + SIGMA_3, + SIGMA_4, + ID_1, + ID_2, + ID_3, + ID_4, + TABLE_1, + TABLE_2, + TABLE_3, + TABLE_4, + LAGRANGE_FIRST, + LAGRANGE_LAST, + W_L, + W_R, + W_O, + W_4, + Z_PERM, + LOOKUP_INVERSES, + LOOKUP_READ_COUNTS, + LOOKUP_READ_TAGS, + W_L_SHIFT, + W_R_SHIFT, + W_O_SHIFT, + W_4_SHIFT, + Z_PERM_SHIFT +} + +library Honk { + struct G1Point { + uint256 x; + uint256 y; + } + + struct G1ProofPoint { + uint256 x_0; + uint256 x_1; + uint256 y_0; + uint256 y_1; + } + + struct VerificationKey { + // Misc Params + uint256 circuitSize; + uint256 logCircuitSize; + uint256 publicInputsSize; + // Selectors + G1Point qm; + G1Point qc; + G1Point ql; + G1Point qr; + G1Point qo; + G1Point q4; + G1Point qLookup; // Lookup + G1Point qArith; // Arithmetic widget + G1Point qDeltaRange; // Delta Range sort + G1Point qAux; // Auxillary + G1Point qElliptic; // Auxillary + G1Point qPoseidon2External; + G1Point qPoseidon2Internal; + // Copy cnstraints + G1Point s1; + G1Point s2; + G1Point s3; + G1Point s4; + // Copy identity + G1Point id1; + G1Point id2; + G1Point id3; + G1Point id4; + // Precomputed lookup table + G1Point t1; + G1Point t2; + G1Point t3; + G1Point t4; + // Fixed first and last + G1Point lagrangeFirst; + G1Point lagrangeLast; + } + + struct RelationParameters { + // challenges + Fr eta; + Fr etaTwo; + Fr etaThree; + Fr beta; + Fr gamma; + // derived + Fr publicInputsDelta; + } + + + struct Proof { + // Free wires + Honk.G1ProofPoint w1; + Honk.G1ProofPoint w2; + Honk.G1ProofPoint w3; + Honk.G1ProofPoint w4; + // Lookup helpers - Permutations + Honk.G1ProofPoint zPerm; + // Lookup helpers - logup + Honk.G1ProofPoint lookupReadCounts; + Honk.G1ProofPoint lookupReadTags; + Honk.G1ProofPoint lookupInverses; + // Sumcheck + Fr[BATCHED_RELATION_PARTIAL_LENGTH][CONST_PROOF_SIZE_LOG_N] sumcheckUnivariates; + Fr[NUMBER_OF_ENTITIES] sumcheckEvaluations; + // Shplemini + Honk.G1ProofPoint[CONST_PROOF_SIZE_LOG_N - 1] geminiFoldComms; + Fr[CONST_PROOF_SIZE_LOG_N] geminiAEvaluations; + Honk.G1ProofPoint shplonkQ; + Honk.G1ProofPoint kzgQuotient; + } +} + +// Transcript library to generate fiat shamir challenges +struct Transcript { + // Oink + Honk.RelationParameters relationParameters; + Fr[NUMBER_OF_ALPHAS] alphas; + Fr[CONST_PROOF_SIZE_LOG_N] gateChallenges; + // Sumcheck + Fr[CONST_PROOF_SIZE_LOG_N] sumCheckUChallenges; + // Gemini + Fr rho; + Fr geminiR; + // Shplonk + Fr shplonkNu; + Fr shplonkZ; +} + +library TranscriptLib { + function generateTranscript(Honk.Proof memory proof, bytes32[] calldata publicInputs, uint256 circuitSize, uint256 publicInputsSize, uint256 pubInputsOffset) + internal + pure + returns (Transcript memory t) + { + Fr previousChallenge; + (t.relationParameters, previousChallenge) = + generateRelationParametersChallenges(proof, publicInputs, circuitSize, publicInputsSize, pubInputsOffset, previousChallenge); + + (t.alphas, previousChallenge) = generateAlphaChallenges(previousChallenge, proof); + + (t.gateChallenges, previousChallenge) = generateGateChallenges(previousChallenge); + + (t.sumCheckUChallenges, previousChallenge) = generateSumcheckChallenges(proof, previousChallenge); + + (t.rho, previousChallenge) = generateRhoChallenge(proof, previousChallenge); + + (t.geminiR, previousChallenge) = generateGeminiRChallenge(proof, previousChallenge); + + (t.shplonkNu, previousChallenge) = generateShplonkNuChallenge(proof, previousChallenge); + + (t.shplonkZ, previousChallenge) = generateShplonkZChallenge(proof, previousChallenge); + + return t; + } + + function splitChallenge(Fr challenge) internal pure returns (Fr first, Fr second) { + uint256 challengeU256 = uint256(Fr.unwrap(challenge)); + uint256 lo = challengeU256 & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + uint256 hi = challengeU256 >> 128; + first = FrLib.fromBytes32(bytes32(lo)); + second = FrLib.fromBytes32(bytes32(hi)); + } + + function generateRelationParametersChallenges( + Honk.Proof memory proof, + bytes32[] calldata publicInputs, + uint256 circuitSize, + uint256 publicInputsSize, + uint256 pubInputsOffset, + Fr previousChallenge + ) internal pure returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) { + (rp.eta, rp.etaTwo, rp.etaThree, previousChallenge) = + generateEtaChallenge(proof, publicInputs, circuitSize, publicInputsSize, pubInputsOffset); + + (rp.beta, rp.gamma, nextPreviousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof); + + } + + function generateEtaChallenge(Honk.Proof memory proof, bytes32[] calldata publicInputs, uint256 circuitSize, uint256 publicInputsSize, uint256 pubInputsOffset) + internal + pure + returns (Fr eta, Fr etaTwo, Fr etaThree, Fr previousChallenge) + { + bytes32[] memory round0 = new bytes32[](3 + publicInputsSize + 12); + round0[0] = bytes32(circuitSize); + round0[1] = bytes32(publicInputsSize); + round0[2] = bytes32(pubInputsOffset); + for (uint256 i = 0; i < publicInputsSize; i++) { + round0[3 + i] = bytes32(publicInputs[i]); + } + + // Create the first challenge + // Note: w4 is added to the challenge later on + round0[3 + publicInputsSize] = bytes32(proof.w1.x_0); + round0[3 + publicInputsSize + 1] = bytes32(proof.w1.x_1); + round0[3 + publicInputsSize + 2] = bytes32(proof.w1.y_0); + round0[3 + publicInputsSize + 3] = bytes32(proof.w1.y_1); + round0[3 + publicInputsSize + 4] = bytes32(proof.w2.x_0); + round0[3 + publicInputsSize + 5] = bytes32(proof.w2.x_1); + round0[3 + publicInputsSize + 6] = bytes32(proof.w2.y_0); + round0[3 + publicInputsSize + 7] = bytes32(proof.w2.y_1); + round0[3 + publicInputsSize + 8] = bytes32(proof.w3.x_0); + round0[3 + publicInputsSize + 9] = bytes32(proof.w3.x_1); + round0[3 + publicInputsSize + 10] = bytes32(proof.w3.y_0); + round0[3 + publicInputsSize + 11] = bytes32(proof.w3.y_1); + + previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round0))); + (eta, etaTwo) = splitChallenge(previousChallenge); + previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge)))); + Fr unused; + (etaThree, unused) = splitChallenge(previousChallenge); + } + + function generateBetaAndGammaChallenges(Fr previousChallenge, Honk.Proof memory proof) + internal + pure + returns (Fr beta, Fr gamma, Fr nextPreviousChallenge) + { + bytes32[13] memory round1; + round1[0] = FrLib.toBytes32(previousChallenge); + round1[1] = bytes32(proof.lookupReadCounts.x_0); + round1[2] = bytes32(proof.lookupReadCounts.x_1); + round1[3] = bytes32(proof.lookupReadCounts.y_0); + round1[4] = bytes32(proof.lookupReadCounts.y_1); + round1[5] = bytes32(proof.lookupReadTags.x_0); + round1[6] = bytes32(proof.lookupReadTags.x_1); + round1[7] = bytes32(proof.lookupReadTags.y_0); + round1[8] = bytes32(proof.lookupReadTags.y_1); + round1[9] = bytes32(proof.w4.x_0); + round1[10] = bytes32(proof.w4.x_1); + round1[11] = bytes32(proof.w4.y_0); + round1[12] = bytes32(proof.w4.y_1); + + nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round1))); + (beta, gamma) = splitChallenge(nextPreviousChallenge); + } + + // Alpha challenges non-linearise the gate contributions + function generateAlphaChallenges(Fr previousChallenge, Honk.Proof memory proof) + internal + pure + returns (Fr[NUMBER_OF_ALPHAS] memory alphas, Fr nextPreviousChallenge) + { + // Generate the original sumcheck alpha 0 by hashing zPerm and zLookup + uint256[9] memory alpha0; + alpha0[0] = Fr.unwrap(previousChallenge); + alpha0[1] = proof.lookupInverses.x_0; + alpha0[2] = proof.lookupInverses.x_1; + alpha0[3] = proof.lookupInverses.y_0; + alpha0[4] = proof.lookupInverses.y_1; + alpha0[5] = proof.zPerm.x_0; + alpha0[6] = proof.zPerm.x_1; + alpha0[7] = proof.zPerm.y_0; + alpha0[8] = proof.zPerm.y_1; + + nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(alpha0))); + (alphas[0], alphas[1]) = splitChallenge(nextPreviousChallenge); + + for (uint256 i = 1; i < NUMBER_OF_ALPHAS / 2; i++) { + nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(nextPreviousChallenge)))); + (alphas[2 * i], alphas[2 * i + 1]) = splitChallenge(nextPreviousChallenge); + } + if (((NUMBER_OF_ALPHAS & 1) == 1) && (NUMBER_OF_ALPHAS > 2)) { + nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(nextPreviousChallenge)))); + Fr unused; + (alphas[NUMBER_OF_ALPHAS - 1], unused) = splitChallenge(nextPreviousChallenge); + } + } + + function generateGateChallenges(Fr previousChallenge) + internal + pure + returns (Fr[CONST_PROOF_SIZE_LOG_N] memory gateChallenges, Fr nextPreviousChallenge) + { + for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) { + previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge)))); + Fr unused; + (gateChallenges[i], unused) = splitChallenge(previousChallenge); + } + nextPreviousChallenge = previousChallenge; + } + + function generateSumcheckChallenges(Honk.Proof memory proof, Fr prevChallenge) + internal + pure + returns (Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckChallenges, Fr nextPreviousChallenge) + { + for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) { + Fr[BATCHED_RELATION_PARTIAL_LENGTH + 1] memory univariateChal; + univariateChal[0] = prevChallenge; + + for (uint256 j = 0; j < BATCHED_RELATION_PARTIAL_LENGTH; j++) { + univariateChal[j + 1] = proof.sumcheckUnivariates[i][j]; + } + prevChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(univariateChal))); + Fr unused; + (sumcheckChallenges[i], unused) = splitChallenge(prevChallenge); + } + nextPreviousChallenge = prevChallenge; + } + + function generateRhoChallenge(Honk.Proof memory proof, Fr prevChallenge) + internal + pure + returns (Fr rho, Fr nextPreviousChallenge) + { + Fr[NUMBER_OF_ENTITIES + 1] memory rhoChallengeElements; + rhoChallengeElements[0] = prevChallenge; + + for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) { + rhoChallengeElements[i + 1] = proof.sumcheckEvaluations[i]; + } + + nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(rhoChallengeElements))); + Fr unused; + (rho, unused) = splitChallenge(nextPreviousChallenge); + } + + function generateGeminiRChallenge(Honk.Proof memory proof, Fr prevChallenge) + internal + pure + returns (Fr geminiR, Fr nextPreviousChallenge) + { + uint256[(CONST_PROOF_SIZE_LOG_N - 1) * 4 + 1] memory gR; + gR[0] = Fr.unwrap(prevChallenge); + + for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; i++) { + gR[1 + i * 4] = proof.geminiFoldComms[i].x_0; + gR[2 + i * 4] = proof.geminiFoldComms[i].x_1; + gR[3 + i * 4] = proof.geminiFoldComms[i].y_0; + gR[4 + i * 4] = proof.geminiFoldComms[i].y_1; + } + + nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(gR))); + Fr unused; + (geminiR, unused) = splitChallenge(nextPreviousChallenge); + } + + function generateShplonkNuChallenge(Honk.Proof memory proof, Fr prevChallenge) + internal + pure + returns (Fr shplonkNu, Fr nextPreviousChallenge) + { + uint256[(CONST_PROOF_SIZE_LOG_N) + 1] memory shplonkNuChallengeElements; + shplonkNuChallengeElements[0] = Fr.unwrap(prevChallenge); + + for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) { + shplonkNuChallengeElements[i + 1] = Fr.unwrap(proof.geminiAEvaluations[i]); + } + + nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(shplonkNuChallengeElements))); + Fr unused; + (shplonkNu, unused) = splitChallenge(nextPreviousChallenge); + } + + function generateShplonkZChallenge(Honk.Proof memory proof, Fr prevChallenge) + internal + pure + returns (Fr shplonkZ, Fr nextPreviousChallenge) + { + uint256[5] memory shplonkZChallengeElements; + shplonkZChallengeElements[0] = Fr.unwrap(prevChallenge); + + shplonkZChallengeElements[1] = proof.shplonkQ.x_0; + shplonkZChallengeElements[2] = proof.shplonkQ.x_1; + shplonkZChallengeElements[3] = proof.shplonkQ.y_0; + shplonkZChallengeElements[4] = proof.shplonkQ.y_1; + + nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(shplonkZChallengeElements))); + Fr unused; + (shplonkZ, unused) = splitChallenge(nextPreviousChallenge); + } + + function loadProof(bytes calldata proof) internal pure returns (Honk.Proof memory p) { + // Commitments + p.w1 = bytesToG1ProofPoint(proof[0x0:0x80]); + + p.w2 = bytesToG1ProofPoint(proof[0x80:0x100]); + p.w3 = bytesToG1ProofPoint(proof[0x100:0x180]); + + // Lookup / Permutation Helper Commitments + p.lookupReadCounts = bytesToG1ProofPoint(proof[0x180:0x200]); + p.lookupReadTags = bytesToG1ProofPoint(proof[0x200:0x280]); + p.w4 = bytesToG1ProofPoint(proof[0x280:0x300]); + p.lookupInverses = bytesToG1ProofPoint(proof[0x300:0x380]); + p.zPerm = bytesToG1ProofPoint(proof[0x380:0x400]); + uint256 boundary = 0x400; + + // Sumcheck univariates + for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) { + for (uint256 j = 0; j < BATCHED_RELATION_PARTIAL_LENGTH; j++) { + p.sumcheckUnivariates[i][j] = bytesToFr(proof[boundary:boundary + 0x20]); + boundary += 0x20; + } + } + // Sumcheck evaluations + for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) { + p.sumcheckEvaluations[i] = bytesToFr(proof[boundary:boundary + 0x20]); + boundary += 0x20; + } + + // Gemini + // Read gemini fold univariates + for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; i++) { + p.geminiFoldComms[i] = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); + boundary += 0x80; + } + + // Read gemini a evaluations + for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) { + p.geminiAEvaluations[i] = bytesToFr(proof[boundary:boundary + 0x20]); + boundary += 0x20; + } + + // Shplonk + p.shplonkQ = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); + boundary = boundary + 0x80; + // KZG + p.kzgQuotient = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); + } +} + + +// Fr utility + +function bytesToFr(bytes calldata proofSection) pure returns (Fr scalar) { + require(proofSection.length == 0x20, "invalid bytes scalar"); + scalar = FrLib.fromBytes32(bytes32(proofSection)); +} + +// EC Point utilities +function convertProofPoint(Honk.G1ProofPoint memory input) pure returns (Honk.G1Point memory) { + return Honk.G1Point({x: input.x_0 | (input.x_1 << 136), y: input.y_0 | (input.y_1 << 136)}); +} + +function bytesToG1ProofPoint(bytes calldata proofSection) pure returns (Honk.G1ProofPoint memory point) { + require(proofSection.length == 0x80, "invalid bytes point"); + point = Honk.G1ProofPoint({ + x_0: uint256(bytes32(proofSection[0x00:0x20])), + x_1: uint256(bytes32(proofSection[0x20:0x40])), + y_0: uint256(bytes32(proofSection[0x40:0x60])), + y_1: uint256(bytes32(proofSection[0x60:0x80])) + }); +} + +function negateInplace(Honk.G1Point memory point) pure returns (Honk.G1Point memory) { + point.y = (Q - point.y) % Q; + return point; +} + + function pairing(Honk.G1Point memory rhs, Honk.G1Point memory lhs) view returns (bool) { + bytes memory input = abi.encodePacked( + rhs.x, + rhs.y, + // Fixed G1 point + uint256(0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2), + uint256(0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed), + uint256(0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b), + uint256(0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa), + lhs.x, + lhs.y, + // G1 point from VK + uint256(0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1), + uint256(0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0), + uint256(0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4), + uint256(0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55) + ); + + (bool success, bytes memory result) = address(0x08).staticcall(input); + bool decodedResult = abi.decode(result, (bool)); + return success && decodedResult; + } + + +library RelationsLib { + Fr internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = Fr.wrap(17); // -(-17) + + function accumulateRelationEvaluations( + Fr[NUMBER_OF_ENTITIES] memory purportedEvaluations, + Honk.RelationParameters memory rp, + Fr[NUMBER_OF_ALPHAS] memory alphas, + Fr powPartialEval + ) internal pure returns (Fr accumulator) { + Fr[NUMBER_OF_SUBRELATIONS] memory evaluations; + + // Accumulate all relations in Ultra Honk - each with varying number of subrelations + accumulateArithmeticRelation(purportedEvaluations, evaluations, powPartialEval); + accumulatePermutationRelation(purportedEvaluations, rp, evaluations, powPartialEval); + accumulateLogDerivativeLookupRelation(purportedEvaluations, rp, evaluations, powPartialEval); + accumulateDeltaRangeRelation(purportedEvaluations, evaluations, powPartialEval); + accumulateEllipticRelation(purportedEvaluations, evaluations, powPartialEval); + accumulateAuxillaryRelation(purportedEvaluations, rp, evaluations, powPartialEval); + accumulatePoseidonExternalRelation(purportedEvaluations, evaluations, powPartialEval); + accumulatePoseidonInternalRelation(purportedEvaluations, evaluations, powPartialEval); + // batch the subrelations with the alpha challenges to obtain the full honk relation + accumulator = scaleAndBatchSubrelations(evaluations, alphas); + } + + /** + * Aesthetic helper function that is used to index by enum into proof.sumcheckEvaluations, it avoids + * the relation checking code being cluttered with uint256 type casting, which is often a different colour in code + * editors, and thus is noisy. + */ + function wire(Fr[NUMBER_OF_ENTITIES] memory p, WIRE _wire) internal pure returns (Fr) { + return p[uint256(_wire)]; + } + + uint256 internal constant NEG_HALF_MODULO_P = 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000; + /** + * Ultra Arithmetic Relation + * + */ + function accumulateArithmeticRelation( + Fr[NUMBER_OF_ENTITIES] memory p, + Fr[NUMBER_OF_SUBRELATIONS] memory evals, + Fr domainSep + ) internal pure { + // Relation 0 + Fr q_arith = wire(p, WIRE.Q_ARITH); + { + Fr neg_half = Fr.wrap(NEG_HALF_MODULO_P); + + Fr accum = (q_arith - Fr.wrap(3)) * (wire(p, WIRE.Q_M) * wire(p, WIRE.W_R) * wire(p, WIRE.W_L)) * neg_half; + accum = accum + (wire(p, WIRE.Q_L) * wire(p, WIRE.W_L)) + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_R)) + + (wire(p, WIRE.Q_O) * wire(p, WIRE.W_O)) + (wire(p, WIRE.Q_4) * wire(p, WIRE.W_4)) + wire(p, WIRE.Q_C); + accum = accum + (q_arith - Fr.wrap(1)) * wire(p, WIRE.W_4_SHIFT); + accum = accum * q_arith; + accum = accum * domainSep; + evals[0] = accum; + } + + // Relation 1 + { + Fr accum = wire(p, WIRE.W_L) + wire(p, WIRE.W_4) - wire(p, WIRE.W_L_SHIFT) + wire(p, WIRE.Q_M); + accum = accum * (q_arith - Fr.wrap(2)); + accum = accum * (q_arith - Fr.wrap(1)); + accum = accum * q_arith; + accum = accum * domainSep; + evals[1] = accum; + } + } + + function accumulatePermutationRelation( + Fr[NUMBER_OF_ENTITIES] memory p, + Honk.RelationParameters memory rp, + Fr[NUMBER_OF_SUBRELATIONS] memory evals, + Fr domainSep + ) internal pure { + Fr grand_product_numerator; + Fr grand_product_denominator; + + { + Fr num = wire(p, WIRE.W_L) + wire(p, WIRE.ID_1) * rp.beta + rp.gamma; + num = num * (wire(p, WIRE.W_R) + wire(p, WIRE.ID_2) * rp.beta + rp.gamma); + num = num * (wire(p, WIRE.W_O) + wire(p, WIRE.ID_3) * rp.beta + rp.gamma); + num = num * (wire(p, WIRE.W_4) + wire(p, WIRE.ID_4) * rp.beta + rp.gamma); + + grand_product_numerator = num; + } + { + Fr den = wire(p, WIRE.W_L) + wire(p, WIRE.SIGMA_1) * rp.beta + rp.gamma; + den = den * (wire(p, WIRE.W_R) + wire(p, WIRE.SIGMA_2) * rp.beta + rp.gamma); + den = den * (wire(p, WIRE.W_O) + wire(p, WIRE.SIGMA_3) * rp.beta + rp.gamma); + den = den * (wire(p, WIRE.W_4) + wire(p, WIRE.SIGMA_4) * rp.beta + rp.gamma); + + grand_product_denominator = den; + } + + // Contribution 2 + { + Fr acc = (wire(p, WIRE.Z_PERM) + wire(p, WIRE.LAGRANGE_FIRST)) * grand_product_numerator; + + acc = acc + - ( + (wire(p, WIRE.Z_PERM_SHIFT) + (wire(p, WIRE.LAGRANGE_LAST) * rp.publicInputsDelta)) + * grand_product_denominator + ); + acc = acc * domainSep; + evals[2] = acc; + } + + // Contribution 3 + { + Fr acc = (wire(p, WIRE.LAGRANGE_LAST) * wire(p, WIRE.Z_PERM_SHIFT)) * domainSep; + evals[3] = acc; + } + } + + function accumulateLogDerivativeLookupRelation( + Fr[NUMBER_OF_ENTITIES] memory p, + Honk.RelationParameters memory rp, + Fr[NUMBER_OF_SUBRELATIONS] memory evals, + Fr domainSep + ) internal pure { + Fr write_term; + Fr read_term; + + // Calculate the write term (the table accumulation) + { + write_term = wire(p, WIRE.TABLE_1) + rp.gamma + (wire(p, WIRE.TABLE_2) * rp.eta) + + (wire(p, WIRE.TABLE_3) * rp.etaTwo) + (wire(p, WIRE.TABLE_4) * rp.etaThree); + } + + // Calculate the write term + { + Fr derived_entry_1 = wire(p, WIRE.W_L) + rp.gamma + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_L_SHIFT)); + Fr derived_entry_2 = wire(p, WIRE.W_R) + wire(p, WIRE.Q_M) * wire(p, WIRE.W_R_SHIFT); + Fr derived_entry_3 = wire(p, WIRE.W_O) + wire(p, WIRE.Q_C) * wire(p, WIRE.W_O_SHIFT); + + read_term = derived_entry_1 + (derived_entry_2 * rp.eta) + (derived_entry_3 * rp.etaTwo) + + (wire(p, WIRE.Q_O) * rp.etaThree); + } + + Fr read_inverse = wire(p, WIRE.LOOKUP_INVERSES) * write_term; + Fr write_inverse = wire(p, WIRE.LOOKUP_INVERSES) * read_term; + + Fr inverse_exists_xor = wire(p, WIRE.LOOKUP_READ_TAGS) + wire(p, WIRE.Q_LOOKUP) + - (wire(p, WIRE.LOOKUP_READ_TAGS) * wire(p, WIRE.Q_LOOKUP)); + + // Inverse calculated correctly relation + Fr accumulatorNone = read_term * write_term * wire(p, WIRE.LOOKUP_INVERSES) - inverse_exists_xor; + accumulatorNone = accumulatorNone * domainSep; + + // Inverse + Fr accumulatorOne = wire(p, WIRE.Q_LOOKUP) * read_inverse - wire(p, WIRE.LOOKUP_READ_COUNTS) * write_inverse; + + evals[4] = accumulatorNone; + evals[5] = accumulatorOne; + } + + function accumulateDeltaRangeRelation( + Fr[NUMBER_OF_ENTITIES] memory p, + Fr[NUMBER_OF_SUBRELATIONS] memory evals, + Fr domainSep + ) internal pure { + Fr minus_one = Fr.wrap(0) - Fr.wrap(1); + Fr minus_two = Fr.wrap(0) - Fr.wrap(2); + Fr minus_three = Fr.wrap(0) - Fr.wrap(3); + + // Compute wire differences + Fr delta_1 = wire(p, WIRE.W_R) - wire(p, WIRE.W_L); + Fr delta_2 = wire(p, WIRE.W_O) - wire(p, WIRE.W_R); + Fr delta_3 = wire(p, WIRE.W_4) - wire(p, WIRE.W_O); + Fr delta_4 = wire(p, WIRE.W_L_SHIFT) - wire(p, WIRE.W_4); + + // Contribution 6 + { + Fr acc = delta_1; + acc = acc * (delta_1 + minus_one); + acc = acc * (delta_1 + minus_two); + acc = acc * (delta_1 + minus_three); + acc = acc * wire(p, WIRE.Q_RANGE); + acc = acc * domainSep; + evals[6] = acc; + } + + // Contribution 7 + { + Fr acc = delta_2; + acc = acc * (delta_2 + minus_one); + acc = acc * (delta_2 + minus_two); + acc = acc * (delta_2 + minus_three); + acc = acc * wire(p, WIRE.Q_RANGE); + acc = acc * domainSep; + evals[7] = acc; + } + + // Contribution 8 + { + Fr acc = delta_3; + acc = acc * (delta_3 + minus_one); + acc = acc * (delta_3 + minus_two); + acc = acc * (delta_3 + minus_three); + acc = acc * wire(p, WIRE.Q_RANGE); + acc = acc * domainSep; + evals[8] = acc; + } + + // Contribution 9 + { + Fr acc = delta_4; + acc = acc * (delta_4 + minus_one); + acc = acc * (delta_4 + minus_two); + acc = acc * (delta_4 + minus_three); + acc = acc * wire(p, WIRE.Q_RANGE); + acc = acc * domainSep; + evals[9] = acc; + } + } + + struct EllipticParams { + // Points + Fr x_1; + Fr y_1; + Fr x_2; + Fr y_2; + Fr y_3; + Fr x_3; + // push accumulators into memory + Fr x_double_identity; + } + + function accumulateEllipticRelation( + Fr[NUMBER_OF_ENTITIES] memory p, + Fr[NUMBER_OF_SUBRELATIONS] memory evals, + Fr domainSep + ) internal pure { + EllipticParams memory ep; + ep.x_1 = wire(p, WIRE.W_R); + ep.y_1 = wire(p, WIRE.W_O); + + ep.x_2 = wire(p, WIRE.W_L_SHIFT); + ep.y_2 = wire(p, WIRE.W_4_SHIFT); + ep.y_3 = wire(p, WIRE.W_O_SHIFT); + ep.x_3 = wire(p, WIRE.W_R_SHIFT); + + Fr q_sign = wire(p, WIRE.Q_L); + Fr q_is_double = wire(p, WIRE.Q_M); + + // Contribution 10 point addition, x-coordinate check + // q_elliptic * (x3 + x2 + x1)(x2 - x1)(x2 - x1) - y2^2 - y1^2 + 2(y2y1)*q_sign = 0 + Fr x_diff = (ep.x_2 - ep.x_1); + Fr y1_sqr = (ep.y_1 * ep.y_1); + { + // Move to top + Fr partialEval = domainSep; + + Fr y2_sqr = (ep.y_2 * ep.y_2); + Fr y1y2 = ep.y_1 * ep.y_2 * q_sign; + Fr x_add_identity = (ep.x_3 + ep.x_2 + ep.x_1); + x_add_identity = x_add_identity * x_diff * x_diff; + x_add_identity = x_add_identity - y2_sqr - y1_sqr + y1y2 + y1y2; + + evals[10] = x_add_identity * partialEval * wire(p, WIRE.Q_ELLIPTIC) * (Fr.wrap(1) - q_is_double); + } + + // Contribution 11 point addition, x-coordinate check + // q_elliptic * (q_sign * y1 + y3)(x2 - x1) + (x3 - x1)(y2 - q_sign * y1) = 0 + { + Fr y1_plus_y3 = ep.y_1 + ep.y_3; + Fr y_diff = ep.y_2 * q_sign - ep.y_1; + Fr y_add_identity = y1_plus_y3 * x_diff + (ep.x_3 - ep.x_1) * y_diff; + evals[11] = y_add_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * (Fr.wrap(1) - q_is_double); + } + + // Contribution 10 point doubling, x-coordinate check + // (x3 + x1 + x1) (4y1*y1) - 9 * x1 * x1 * x1 * x1 = 0 + // N.B. we're using the equivalence x1*x1*x1 === y1*y1 - curve_b to reduce degree by 1 + { + Fr x_pow_4 = (y1_sqr + GRUMPKIN_CURVE_B_PARAMETER_NEGATED) * ep.x_1; + Fr y1_sqr_mul_4 = y1_sqr + y1_sqr; + y1_sqr_mul_4 = y1_sqr_mul_4 + y1_sqr_mul_4; + Fr x1_pow_4_mul_9 = x_pow_4 * Fr.wrap(9); + + // NOTE: pushed into memory (stack >:'( ) + ep.x_double_identity = (ep.x_3 + ep.x_1 + ep.x_1) * y1_sqr_mul_4 - x1_pow_4_mul_9; + + Fr acc = ep.x_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; + evals[10] = evals[10] + acc; + } + + // Contribution 11 point doubling, y-coordinate check + // (y1 + y1) (2y1) - (3 * x1 * x1)(x1 - x3) = 0 + { + Fr x1_sqr_mul_3 = (ep.x_1 + ep.x_1 + ep.x_1) * ep.x_1; + Fr y_double_identity = x1_sqr_mul_3 * (ep.x_1 - ep.x_3) - (ep.y_1 + ep.y_1) * (ep.y_1 + ep.y_3); + evals[11] = evals[11] + y_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; + } + } + + // Constants for the auxiliary relation + Fr constant LIMB_SIZE = Fr.wrap(uint256(1) << 68); + Fr constant SUBLIMB_SHIFT = Fr.wrap(uint256(1) << 14); + + // Parameters used within the Auxiliary Relation + // A struct is used to work around stack too deep. This relation has alot of variables + struct AuxParams { + Fr limb_subproduct; + Fr non_native_field_gate_1; + Fr non_native_field_gate_2; + Fr non_native_field_gate_3; + Fr limb_accumulator_1; + Fr limb_accumulator_2; + Fr memory_record_check; + Fr partial_record_check; + Fr next_gate_access_type; + Fr record_delta; + Fr index_delta; + Fr adjacent_values_match_if_adjacent_indices_match; + Fr adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation; + Fr access_check; + Fr next_gate_access_type_is_boolean; + Fr ROM_consistency_check_identity; + Fr RAM_consistency_check_identity; + Fr timestamp_delta; + Fr RAM_timestamp_check_identity; + Fr memory_identity; + Fr index_is_monotonically_increasing; + Fr auxiliary_identity; + } + + function accumulateAuxillaryRelation( + Fr[NUMBER_OF_ENTITIES] memory p, + Honk.RelationParameters memory rp, + Fr[NUMBER_OF_SUBRELATIONS] memory evals, + Fr domainSep + ) internal pure { + AuxParams memory ap; + + /** + * Contribution 12 + * Non native field arithmetic gate 2 + * deg 4 + * + * _ _ + * / _ _ _ 14 \ + * 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 | + * \_ _/ + * + * + */ + ap.limb_subproduct = wire(p, WIRE.W_L) * wire(p, WIRE.W_R_SHIFT) + wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R); + ap.non_native_field_gate_2 = + (wire(p, WIRE.W_L) * wire(p, WIRE.W_4) + wire(p, WIRE.W_R) * wire(p, WIRE.W_O) - wire(p, WIRE.W_O_SHIFT)); + ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * LIMB_SIZE; + ap.non_native_field_gate_2 = ap.non_native_field_gate_2 - wire(p, WIRE.W_4_SHIFT); + ap.non_native_field_gate_2 = ap.non_native_field_gate_2 + ap.limb_subproduct; + ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * wire(p, WIRE.Q_4); + + ap.limb_subproduct = ap.limb_subproduct * LIMB_SIZE; + ap.limb_subproduct = ap.limb_subproduct + (wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R_SHIFT)); + ap.non_native_field_gate_1 = ap.limb_subproduct; + ap.non_native_field_gate_1 = ap.non_native_field_gate_1 - (wire(p, WIRE.W_O) + wire(p, WIRE.W_4)); + ap.non_native_field_gate_1 = ap.non_native_field_gate_1 * wire(p, WIRE.Q_O); + + ap.non_native_field_gate_3 = ap.limb_subproduct; + ap.non_native_field_gate_3 = ap.non_native_field_gate_3 + wire(p, WIRE.W_4); + ap.non_native_field_gate_3 = ap.non_native_field_gate_3 - (wire(p, WIRE.W_O_SHIFT) + wire(p, WIRE.W_4_SHIFT)); + ap.non_native_field_gate_3 = ap.non_native_field_gate_3 * wire(p, WIRE.Q_M); + + Fr non_native_field_identity = + ap.non_native_field_gate_1 + ap.non_native_field_gate_2 + ap.non_native_field_gate_3; + non_native_field_identity = non_native_field_identity * wire(p, WIRE.Q_R); + + // ((((w2' * 2^14 + w1') * 2^14 + w3) * 2^14 + w2) * 2^14 + w1 - w4) * qm + // deg 2 + ap.limb_accumulator_1 = wire(p, WIRE.W_R_SHIFT) * SUBLIMB_SHIFT; + ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_L_SHIFT); + ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT; + ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_O); + ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT; + ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_R); + ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT; + ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_L); + ap.limb_accumulator_1 = ap.limb_accumulator_1 - wire(p, WIRE.W_4); + ap.limb_accumulator_1 = ap.limb_accumulator_1 * wire(p, WIRE.Q_4); + + // ((((w3' * 2^14 + w2') * 2^14 + w1') * 2^14 + w4) * 2^14 + w3 - w4') * qm + // deg 2 + ap.limb_accumulator_2 = wire(p, WIRE.W_O_SHIFT) * SUBLIMB_SHIFT; + ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_R_SHIFT); + ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT; + ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_L_SHIFT); + ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT; + ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_4); + ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT; + ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_O); + ap.limb_accumulator_2 = ap.limb_accumulator_2 - wire(p, WIRE.W_4_SHIFT); + ap.limb_accumulator_2 = ap.limb_accumulator_2 * wire(p, WIRE.Q_M); + + Fr limb_accumulator_identity = ap.limb_accumulator_1 + ap.limb_accumulator_2; + limb_accumulator_identity = limb_accumulator_identity * wire(p, WIRE.Q_O); // deg 3 + + /** + * MEMORY + * + * A RAM memory record contains a tuple of the following fields: + * * i: `index` of memory cell being accessed + * * t: `timestamp` of memory cell being accessed (used for RAM, set to 0 for ROM) + * * v: `value` of memory cell being accessed + * * a: `access` type of record. read: 0 = read, 1 = write + * * r: `record` of memory cell. record = access + index * eta + timestamp * eta_two + value * eta_three + * + * A ROM memory record contains a tuple of the following fields: + * * i: `index` of memory cell being accessed + * * v: `value1` of memory cell being accessed (ROM tables can store up to 2 values per index) + * * v2:`value2` of memory cell being accessed (ROM tables can store up to 2 values per index) + * * r: `record` of memory cell. record = index * eta + value2 * eta_two + value1 * eta_three + * + * When performing a read/write access, the values of i, t, v, v2, a, r are stored in the following wires + + * selectors, depending on whether the gate is a RAM read/write or a ROM read + * + * | gate type | i | v2/t | v | a | r | + * | --------- | -- | ----- | -- | -- | -- | + * | ROM | w1 | w2 | w3 | -- | w4 | + * | RAM | w1 | w2 | w3 | qc | w4 | + * + * (for accesses where `index` is a circuit constant, it is assumed the circuit will apply a copy constraint on + * `w2` to fix its value) + * + * + */ + + /** + * Memory Record Check + * Partial degree: 1 + * Total degree: 4 + * + * A ROM/ROM access gate can be evaluated with the identity: + * + * qc + w1 \eta + w2 \eta_two + w3 \eta_three - w4 = 0 + * + * For ROM gates, qc = 0 + */ + ap.memory_record_check = wire(p, WIRE.W_O) * rp.etaThree; + ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_R) * rp.etaTwo); + ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_L) * rp.eta); + ap.memory_record_check = ap.memory_record_check + wire(p, WIRE.Q_C); + ap.partial_record_check = ap.memory_record_check; // used in RAM consistency check; deg 1 or 4 + ap.memory_record_check = ap.memory_record_check - wire(p, WIRE.W_4); + + /** + * Contribution 13 & 14 + * ROM Consistency Check + * Partial degree: 1 + * Total degree: 4 + * + * For every ROM read, a set equivalence check is applied between the record witnesses, and a second set of + * records that are sorted. + * + * We apply the following checks for the sorted records: + * + * 1. w1, w2, w3 correctly map to 'index', 'v1, 'v2' for a given record value at w4 + * 2. index values for adjacent records are monotonically increasing + * 3. if, at gate i, index_i == index_{i + 1}, then value1_i == value1_{i + 1} and value2_i == value2_{i + 1} + * + */ + ap.index_delta = wire(p, WIRE.W_L_SHIFT) - wire(p, WIRE.W_L); + ap.record_delta = wire(p, WIRE.W_4_SHIFT) - wire(p, WIRE.W_4); + + ap.index_is_monotonically_increasing = ap.index_delta * ap.index_delta - ap.index_delta; // deg 2 + + ap.adjacent_values_match_if_adjacent_indices_match = (ap.index_delta * MINUS_ONE + Fr.wrap(1)) * ap.record_delta; // deg 2 + + evals[13] = ap.adjacent_values_match_if_adjacent_indices_match * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) + * (wire(p, WIRE.Q_AUX) * domainSep); // deg 5 + evals[14] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) + * (wire(p, WIRE.Q_AUX) * domainSep); // deg 5 + + ap.ROM_consistency_check_identity = ap.memory_record_check * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)); // deg 3 or 7 + + /** + * Contributions 15,16,17 + * RAM Consistency Check + * + * The 'access' type of the record is extracted with the expression `w_4 - ap.partial_record_check` + * (i.e. for an honest Prover `w1 * eta + w2 * eta^2 + w3 * eta^3 - w4 = access`. + * This is validated by requiring `access` to be boolean + * + * For two adjacent entries in the sorted list if _both_ + * A) index values match + * B) adjacent access value is 0 (i.e. next gate is a READ) + * then + * C) both values must match. + * The gate boolean check is + * (A && B) => C === !(A && B) || C === !A || !B || C + * + * N.B. it is the responsibility of the circuit writer to ensure that every RAM cell is initialized + * with a WRITE operation. + */ + Fr access_type = (wire(p, WIRE.W_4) - ap.partial_record_check); // will be 0 or 1 for honest Prover; deg 1 or 4 + ap.access_check = access_type * access_type - access_type; // check value is 0 or 1; deg 2 or 8 + + ap.next_gate_access_type = wire(p, WIRE.W_O_SHIFT) * rp.etaThree; + ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_R_SHIFT) * rp.etaTwo); + ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_L_SHIFT) * rp.eta); + ap.next_gate_access_type = wire(p, WIRE.W_4_SHIFT) - ap.next_gate_access_type; + + Fr value_delta = wire(p, WIRE.W_O_SHIFT) - wire(p, WIRE.W_O); + ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = ( + ap.index_delta * MINUS_ONE + Fr.wrap(1) + ) * value_delta * (ap.next_gate_access_type * MINUS_ONE + Fr.wrap(1)); // deg 3 or 6 + + // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the + // next gate would make the identity fail). We need to validate that its 'access type' bool is correct. Can't + // do with an arithmetic gate because of the `eta` factors. We need to check that the *next* gate's access + // type is correct, to cover this edge case + // deg 2 or 4 + ap.next_gate_access_type_is_boolean = + ap.next_gate_access_type * ap.next_gate_access_type - ap.next_gate_access_type; + + // Putting it all together... + evals[15] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation + * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_AUX) * domainSep); // deg 5 or 8 + evals[16] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_AUX) * domainSep); // deg 4 + evals[17] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_ARITH)) * (wire(p, WIRE.Q_AUX) * domainSep); // deg 4 or 6 + + ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_ARITH)); // deg 3 or 9 + + /** + * RAM Timestamp Consistency Check + * + * | w1 | w2 | w3 | w4 | + * | index | timestamp | timestamp_check | -- | + * + * Let delta_index = index_{i + 1} - index_{i} + * + * Iff delta_index == 0, timestamp_check = timestamp_{i + 1} - timestamp_i + * Else timestamp_check = 0 + */ + ap.timestamp_delta = wire(p, WIRE.W_R_SHIFT) - wire(p, WIRE.W_R); + ap.RAM_timestamp_check_identity = + (ap.index_delta * MINUS_ONE + Fr.wrap(1)) * ap.timestamp_delta - wire(p, WIRE.W_O); // deg 3 + + /** + * Complete Contribution 12 + * The complete RAM/ROM memory identity + * Partial degree: + */ + ap.memory_identity = ap.ROM_consistency_check_identity; // deg 3 or 6 + ap.memory_identity = + ap.memory_identity + ap.RAM_timestamp_check_identity * (wire(p, WIRE.Q_4) * wire(p, WIRE.Q_L)); // deg 4 + ap.memory_identity = ap.memory_identity + ap.memory_record_check * (wire(p, WIRE.Q_M) * wire(p, WIRE.Q_L)); // deg 3 or 6 + ap.memory_identity = ap.memory_identity + ap.RAM_consistency_check_identity; // deg 3 or 9 + + // (deg 3 or 9) + (deg 4) + (deg 3) + ap.auxiliary_identity = ap.memory_identity + non_native_field_identity + limb_accumulator_identity; + ap.auxiliary_identity = ap.auxiliary_identity * (wire(p, WIRE.Q_AUX) * domainSep); // deg 4 or 10 + evals[12] = ap.auxiliary_identity; + } + + struct PoseidonExternalParams { + Fr s1; + Fr s2; + Fr s3; + Fr s4; + Fr u1; + Fr u2; + Fr u3; + Fr u4; + Fr t0; + Fr t1; + Fr t2; + Fr t3; + Fr v1; + Fr v2; + Fr v3; + Fr v4; + Fr q_pos_by_scaling; + } + + function accumulatePoseidonExternalRelation( + Fr[NUMBER_OF_ENTITIES] memory p, + Fr[NUMBER_OF_SUBRELATIONS] memory evals, + Fr domainSep + ) internal pure { + PoseidonExternalParams memory ep; + + ep.s1 = wire(p, WIRE.W_L) + wire(p, WIRE.Q_L); + ep.s2 = wire(p, WIRE.W_R) + wire(p, WIRE.Q_R); + ep.s3 = wire(p, WIRE.W_O) + wire(p, WIRE.Q_O); + ep.s4 = wire(p, WIRE.W_4) + wire(p, WIRE.Q_4); + + ep.u1 = ep.s1 * ep.s1 * ep.s1 * ep.s1 * ep.s1; + ep.u2 = ep.s2 * ep.s2 * ep.s2 * ep.s2 * ep.s2; + ep.u3 = ep.s3 * ep.s3 * ep.s3 * ep.s3 * ep.s3; + ep.u4 = ep.s4 * ep.s4 * ep.s4 * ep.s4 * ep.s4; + // matrix mul v = M_E * u with 14 additions + ep.t0 = ep.u1 + ep.u2; // u_1 + u_2 + ep.t1 = ep.u3 + ep.u4; // u_3 + u_4 + ep.t2 = ep.u2 + ep.u2 + ep.t1; // 2u_2 + // ep.t2 += ep.t1; // 2u_2 + u_3 + u_4 + ep.t3 = ep.u4 + ep.u4 + ep.t0; // 2u_4 + // ep.t3 += ep.t0; // u_1 + u_2 + 2u_4 + ep.v4 = ep.t1 + ep.t1; + ep.v4 = ep.v4 + ep.v4 + ep.t3; + // ep.v4 += ep.t3; // u_1 + u_2 + 4u_3 + 6u_4 + ep.v2 = ep.t0 + ep.t0; + ep.v2 = ep.v2 + ep.v2 + ep.t2; + // ep.v2 += ep.t2; // 4u_1 + 6u_2 + u_3 + u_4 + ep.v1 = ep.t3 + ep.v2; // 5u_1 + 7u_2 + u_3 + 3u_4 + ep.v3 = ep.t2 + ep.v4; // u_1 + 3u_2 + 5u_3 + 7u_4 + + ep.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_EXTERNAL) * domainSep; + evals[18] = evals[18] + ep.q_pos_by_scaling * (ep.v1 - wire(p, WIRE.W_L_SHIFT)); + + evals[19] = evals[19] + ep.q_pos_by_scaling * (ep.v2 - wire(p, WIRE.W_R_SHIFT)); + + evals[20] = evals[20] + ep.q_pos_by_scaling * (ep.v3 - wire(p, WIRE.W_O_SHIFT)); + + evals[21] = evals[21] + ep.q_pos_by_scaling * (ep.v4 - wire(p, WIRE.W_4_SHIFT)); + } + + struct PoseidonInternalParams { + Fr u1; + Fr u2; + Fr u3; + Fr u4; + Fr u_sum; + Fr v1; + Fr v2; + Fr v3; + Fr v4; + Fr s1; + Fr q_pos_by_scaling; + } + + function accumulatePoseidonInternalRelation( + Fr[NUMBER_OF_ENTITIES] memory p, + Fr[NUMBER_OF_SUBRELATIONS] memory evals, + Fr domainSep + ) internal pure { + PoseidonInternalParams memory ip; + + Fr[4] memory INTERNAL_MATRIX_DIAGONAL = [ + FrLib.from(0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7), + FrLib.from(0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b), + FrLib.from(0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15), + FrLib.from(0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b) + ]; + + // add round constants + ip.s1 = wire(p, WIRE.W_L) + wire(p, WIRE.Q_L); + + // apply s-box round + ip.u1 = ip.s1 * ip.s1 * ip.s1 * ip.s1 * ip.s1; + ip.u2 = wire(p, WIRE.W_R); + ip.u3 = wire(p, WIRE.W_O); + ip.u4 = wire(p, WIRE.W_4); + + // matrix mul with v = M_I * u 4 muls and 7 additions + ip.u_sum = ip.u1 + ip.u2 + ip.u3 + ip.u4; + + ip.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_INTERNAL) * domainSep; + + ip.v1 = ip.u1 * INTERNAL_MATRIX_DIAGONAL[0] + ip.u_sum; + evals[22] = evals[22] + ip.q_pos_by_scaling * (ip.v1 - wire(p, WIRE.W_L_SHIFT)); + + ip.v2 = ip.u2 * INTERNAL_MATRIX_DIAGONAL[1] + ip.u_sum; + evals[23] = evals[23] + ip.q_pos_by_scaling * (ip.v2 - wire(p, WIRE.W_R_SHIFT)); + + ip.v3 = ip.u3 * INTERNAL_MATRIX_DIAGONAL[2] + ip.u_sum; + evals[24] = evals[24] + ip.q_pos_by_scaling * (ip.v3 - wire(p, WIRE.W_O_SHIFT)); + + ip.v4 = ip.u4 * INTERNAL_MATRIX_DIAGONAL[3] + ip.u_sum; + evals[25] = evals[25] + ip.q_pos_by_scaling * (ip.v4 - wire(p, WIRE.W_4_SHIFT)); + } + + function scaleAndBatchSubrelations( + Fr[NUMBER_OF_SUBRELATIONS] memory evaluations, + Fr[NUMBER_OF_ALPHAS] memory subrelationChallenges + ) internal pure returns (Fr accumulator) { + accumulator = accumulator + evaluations[0]; + + for (uint256 i = 1; i < NUMBER_OF_SUBRELATIONS; ++i) { + accumulator = accumulator + evaluations[i] * subrelationChallenges[i - 1]; + } + } +} + +struct ShpleminiIntermediates { + Fr unshiftedScalar; + Fr shiftedScalar; + // Scalar to be multiplied by [1]₁ + Fr constantTermAccumulator; + // Accumulator for powers of rho + Fr batchingChallenge; + // Linear combination of multilinear (sumcheck) evaluations and powers of rho + Fr batchedEvaluation; + // 1/(z - r^{2^i}) for i = 0, ..., logSize, dynamically updated + Fr posInvertedDenominator; + // 1/(z + r^{2^i}) for i = 0, ..., logSize, dynamically updated + Fr negInvertedDenominator; + // v^{2i} * 1/(z - r^{2^i}) + Fr scalingFactorPos; + // v^{2i+1} * 1/(z + r^{2^i}) + Fr scalingFactorNeg; + // // Fold_i(r^{2^i}) reconstructed by Verifier + // Fr[CONST_PROOF_SIZE_LOG_N] foldPosEvaluations; +} + +library CommitmentSchemeLib { + using FrLib for Fr; + + function computeSquares(Fr r) internal pure returns (Fr[CONST_PROOF_SIZE_LOG_N] memory squares) { + squares[0] = r; + for (uint256 i = 1; i < CONST_PROOF_SIZE_LOG_N; ++i) { + squares[i] = squares[i - 1].sqr(); + } + } + + // Compute the evaluations A_l(r^{2^l}) for l = 0, ..., m-1 + function computeFoldPosEvaluations( + Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckUChallenges, + Fr batchedEvalAccumulator, + Fr[CONST_PROOF_SIZE_LOG_N] memory geminiEvaluations, + Fr[CONST_PROOF_SIZE_LOG_N] memory geminiEvalChallengePowers, + uint256 logSize + ) internal view returns (Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations) { + for (uint256 i = CONST_PROOF_SIZE_LOG_N; i > 0; --i) { + Fr challengePower = geminiEvalChallengePowers[i - 1]; + Fr u = sumcheckUChallenges[i - 1]; + + Fr batchedEvalRoundAcc = ( + (challengePower * batchedEvalAccumulator * Fr.wrap(2)) + - geminiEvaluations[i - 1] * (challengePower * (Fr.wrap(1) - u) - u) + ); + // Divide by the denominator + batchedEvalRoundAcc = batchedEvalRoundAcc * (challengePower * (Fr.wrap(1) - u) + u).invert(); + + if (i <= logSize) { + batchedEvalAccumulator = batchedEvalRoundAcc; + foldPosEvaluations[i - 1] = batchedEvalRoundAcc; + } + } + + } +} + +interface IVerifier { + function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool); +} + + +abstract contract BaseHonkVerifier is IVerifier { + using FrLib for Fr; + + uint256 immutable n; + uint256 immutable logN; + uint256 immutable numPublicInputs; + + constructor(uint256 _n, uint256 _logN, uint256 _numPublicInputs) { + n = _n; + logN = _logN; + numPublicInputs = _numPublicInputs; + } + + error ProofLengthWrong(); + error PublicInputsLengthWrong(); + error SumcheckFailed(); + error ShpleminiFailed(); + + // Number of field elements in a ultra honk zero knowledge proof + uint256 constant PROOF_SIZE = 440; + + function loadVerificationKey() internal pure virtual returns (Honk.VerificationKey memory); + + function verify(bytes calldata proof, bytes32[] calldata publicInputs) public view override returns (bool) { + // Check the received proof is the expected size where each field element is 32 bytes + if (proof.length != PROOF_SIZE * 32) { + revert ProofLengthWrong(); + } + + Honk.VerificationKey memory vk = loadVerificationKey(); + Honk.Proof memory p = TranscriptLib.loadProof(proof); + + if (publicInputs.length != vk.publicInputsSize) { + revert PublicInputsLengthWrong(); + } + + // Generate the fiat shamir challenges for the whole protocol + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1281): Add pubInputsOffset to VK or remove entirely. + Transcript memory t = TranscriptLib.generateTranscript(p, publicInputs, vk.circuitSize, vk.publicInputsSize, /*pubInputsOffset=*/1); + + // Derive public input delta + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1281): Add pubInputsOffset to VK or remove entirely. + t.relationParameters.publicInputsDelta = computePublicInputDelta( + publicInputs, t.relationParameters.beta, t.relationParameters.gamma, /*pubInputsOffset=*/1 + ); + + // Sumcheck + bool sumcheckVerified = verifySumcheck(p, t); + if (!sumcheckVerified) revert SumcheckFailed(); + + bool shpleminiVerified = verifyShplemini(p, vk, t); + if (!shpleminiVerified) revert ShpleminiFailed(); + + return sumcheckVerified && shpleminiVerified; // Boolean condition not required - nice for vanity :) + } + + function computePublicInputDelta(bytes32[] memory publicInputs, Fr beta, Fr gamma, uint256 offset) + internal + view + returns (Fr publicInputDelta) + { + Fr numerator = Fr.wrap(1); + Fr denominator = Fr.wrap(1); + + Fr numeratorAcc = gamma + (beta * FrLib.from(n + offset)); + Fr denominatorAcc = gamma - (beta * FrLib.from(offset + 1)); + + { + for (uint256 i = 0; i < numPublicInputs; i++) { + Fr pubInput = FrLib.fromBytes32(publicInputs[i]); + + numerator = numerator * (numeratorAcc + pubInput); + denominator = denominator * (denominatorAcc + pubInput); + + numeratorAcc = numeratorAcc + beta; + denominatorAcc = denominatorAcc - beta; + } + } + + // Fr delta = numerator / denominator; // TOOO: batch invert later? + publicInputDelta = FrLib.div(numerator, denominator); + } + + function verifySumcheck(Honk.Proof memory proof, Transcript memory tp) internal view returns (bool verified) { + Fr roundTarget; + Fr powPartialEvaluation = Fr.wrap(1); + + // We perform sumcheck reductions over log n rounds ( the multivariate degree ) + for (uint256 round; round < logN; ++round) { + Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariate = proof.sumcheckUnivariates[round]; + bool valid = checkSum(roundUnivariate, roundTarget); + if (!valid) revert SumcheckFailed(); + + Fr roundChallenge = tp.sumCheckUChallenges[round]; + + // Update the round target for the next rounf + roundTarget = computeNextTargetSum(roundUnivariate, roundChallenge); + powPartialEvaluation = partiallyEvaluatePOW(tp.gateChallenges[round], powPartialEvaluation, roundChallenge); + } + + // Last round + Fr grandHonkRelationSum = + RelationsLib.accumulateRelationEvaluations(proof.sumcheckEvaluations, tp.relationParameters, tp.alphas, powPartialEvaluation); + verified = (grandHonkRelationSum == roundTarget); + } + + function checkSum(Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariate, Fr roundTarget) + internal + pure + returns (bool checked) + { + Fr totalSum = roundUnivariate[0] + roundUnivariate[1]; + checked = totalSum == roundTarget; + } + + // Return the new target sum for the next sumcheck round + function computeNextTargetSum(Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariates, Fr roundChallenge) + internal + view + returns (Fr targetSum) + { + // TODO: inline + Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory BARYCENTRIC_LAGRANGE_DENOMINATORS = [ + Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51), + Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000002d0), + Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffff11), + Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000000090), + Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffff71), + Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000000f0), + Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31), + Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000013b0) + ]; + + // To compute the next target sum, we evaluate the given univariate at a point u (challenge). + + // Performing Barycentric evaluations + // Compute B(x) + Fr numeratorValue = Fr.wrap(1); + for (uint256 i = 0; i < BATCHED_RELATION_PARTIAL_LENGTH; ++i) { + numeratorValue = numeratorValue * (roundChallenge - Fr.wrap(i)); + } + + // Calculate domain size N of inverses + Fr[BATCHED_RELATION_PARTIAL_LENGTH] memory denominatorInverses; + for (uint256 i = 0; i < BATCHED_RELATION_PARTIAL_LENGTH; ++i) { + Fr inv = BARYCENTRIC_LAGRANGE_DENOMINATORS[i]; + inv = inv * (roundChallenge - Fr.wrap(i)); + inv = FrLib.invert(inv); + denominatorInverses[i] = inv; + } + + for (uint256 i = 0; i < BATCHED_RELATION_PARTIAL_LENGTH; ++i) { + Fr term = roundUnivariates[i]; + term = term * denominatorInverses[i]; + targetSum = targetSum + term; + } + + // Scale the sum by the value of B(x) + targetSum = targetSum * numeratorValue; + } + + // Univariate evaluation of the monomial ((1-X_l) + X_l.B_l) at the challenge point X_l=u_l + function partiallyEvaluatePOW(Fr gateChallenge, Fr currentEvaluation, Fr roundChallenge) + internal + pure + returns (Fr newEvaluation) + { + Fr univariateEval = Fr.wrap(1) + (roundChallenge * (gateChallenge - Fr.wrap(1))); + newEvaluation = currentEvaluation * univariateEval; + } + + function verifyShplemini(Honk.Proof memory proof, Honk.VerificationKey memory vk, Transcript memory tp) + internal + view + returns (bool verified) + { + ShpleminiIntermediates memory mem; // stack + + // - Compute vector (r, r², ... , r²⁽ⁿ⁻¹⁾), where n = log_circuit_size + Fr[CONST_PROOF_SIZE_LOG_N] memory powers_of_evaluation_challenge = CommitmentSchemeLib.computeSquares(tp.geminiR); + + // Arrays hold values that will be linearly combined for the gemini and shplonk batch openings + Fr[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory scalars; + Honk.G1Point[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory commitments; + + mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[0]).invert(); + mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[0]).invert(); + + mem.unshiftedScalar = mem.posInvertedDenominator + (tp.shplonkNu * mem.negInvertedDenominator); + mem.shiftedScalar = + tp.geminiR.invert() * (mem.posInvertedDenominator - (tp.shplonkNu * mem.negInvertedDenominator)); + + scalars[0] = Fr.wrap(1); + commitments[0] = convertProofPoint(proof.shplonkQ); + + mem.batchingChallenge = Fr.wrap(1); + mem.batchedEvaluation = Fr.wrap(0); + + for (uint256 i = 1; i <= NUMBER_UNSHIFTED; ++i) { + scalars[i] = mem.unshiftedScalar.neg() * mem.batchingChallenge; + mem.batchedEvaluation = mem.batchedEvaluation + (proof.sumcheckEvaluations[i - 1] * mem.batchingChallenge); + mem.batchingChallenge = mem.batchingChallenge * tp.rho; + } + // g commitments are accumulated at r + for (uint256 i = NUMBER_UNSHIFTED + 1; i <= NUMBER_OF_ENTITIES; ++i) { + scalars[i] = mem.shiftedScalar.neg() * mem.batchingChallenge; + mem.batchedEvaluation = mem.batchedEvaluation + (proof.sumcheckEvaluations[i - 1] * mem.batchingChallenge); + mem.batchingChallenge = mem.batchingChallenge * tp.rho; + } + + commitments[1] = vk.qm; + commitments[2] = vk.qc; + commitments[3] = vk.ql; + commitments[4] = vk.qr; + commitments[5] = vk.qo; + commitments[6] = vk.q4; + commitments[7] = vk.qLookup; + commitments[8] = vk.qArith; + commitments[9] = vk.qDeltaRange; + commitments[10] = vk.qElliptic; + commitments[11] = vk.qAux; + commitments[12] = vk.qPoseidon2External; + commitments[13] = vk.qPoseidon2Internal; + commitments[14] = vk.s1; + commitments[15] = vk.s2; + commitments[16] = vk.s3; + commitments[17] = vk.s4; + commitments[18] = vk.id1; + commitments[19] = vk.id2; + commitments[20] = vk.id3; + commitments[21] = vk.id4; + commitments[22] = vk.t1; + commitments[23] = vk.t2; + commitments[24] = vk.t3; + commitments[25] = vk.t4; + commitments[26] = vk.lagrangeFirst; + commitments[27] = vk.lagrangeLast; + + // Accumulate proof points + commitments[28] = convertProofPoint(proof.w1); + commitments[29] = convertProofPoint(proof.w2); + commitments[30] = convertProofPoint(proof.w3); + commitments[31] = convertProofPoint(proof.w4); + commitments[32] = convertProofPoint(proof.zPerm); + commitments[33] = convertProofPoint(proof.lookupInverses); + commitments[34] = convertProofPoint(proof.lookupReadCounts); + commitments[35] = convertProofPoint(proof.lookupReadTags); + + // to be Shifted + commitments[36] = convertProofPoint(proof.w1); + commitments[37] = convertProofPoint(proof.w2); + commitments[38] = convertProofPoint(proof.w3); + commitments[39] = convertProofPoint(proof.w4); + commitments[40] = convertProofPoint(proof.zPerm); + + // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: + // Compute the evaluations A_l(r^{2^l}) for l = 0, ..., logN - 1 + Fr[CONST_PROOF_SIZE_LOG_N] memory foldPosEvaluations = CommitmentSchemeLib.computeFoldPosEvaluations( + tp.sumCheckUChallenges, + mem.batchedEvaluation, + proof.geminiAEvaluations, + powers_of_evaluation_challenge, + logN + ); + + // Compute the Shplonk constant term contributions from A₀(±r) + mem.constantTermAccumulator = foldPosEvaluations[0] * mem.posInvertedDenominator; + mem.constantTermAccumulator = + mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator); + mem.batchingChallenge = tp.shplonkNu.sqr(); + + // Compute Shplonk constant term contributions from Aₗ(±r^{2ˡ}) for l = 1, ..., m-1; + // Compute scalar multipliers for each fold commitment + for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) { + bool dummy_round = i >= (logN - 1); + + if (!dummy_round) { + // Update inverted denominators + mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[i + 1]).invert(); + mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[i + 1]).invert(); + + // Compute the scalar multipliers for Aₗ(± r^{2ˡ}) and [Aₗ] + mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator; + mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator; + // [Aₗ] is multiplied by -v^{2l}/(z-r^{2^l}) - v^{2l+1} /(z+ r^{2^l}) + scalars[NUMBER_OF_ENTITIES + 1 + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg(); + + // Accumulate the const term contribution given by + // v^{2l} * Aₗ(r^{2ˡ}) /(z-r^{2^l}) + v^{2l+1} * Aₗ(-r^{2ˡ}) /(z+ r^{2^l}) + Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; + accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1]; + mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; + // Update the running power of v + mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; + } + + commitments[NUMBER_OF_ENTITIES + 1 + i] = convertProofPoint(proof.geminiFoldComms[i]); + } + + // Finalise the batch opening claim + commitments[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N] = Honk.G1Point({x: 1, y: 2}); + scalars[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N] = mem.constantTermAccumulator; + + Honk.G1Point memory quotient_commitment = convertProofPoint(proof.kzgQuotient); + + commitments[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 1] = quotient_commitment; + scalars[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 1] = tp.shplonkZ; // evaluation challenge + + Honk.G1Point memory P_0 = batchMul(commitments, scalars); + Honk.G1Point memory P_1 = negateInplace(quotient_commitment); + + return pairing(P_0, P_1); + } + + // This implementation is the same as above with different constants + function batchMul( + Honk.G1Point[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory base, + Fr[NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2] memory scalars + ) internal view returns (Honk.G1Point memory result) { + uint256 limit = NUMBER_OF_ENTITIES + CONST_PROOF_SIZE_LOG_N + 2; + assembly { + let success := 0x01 + let free := mload(0x40) + + // Write the original into the accumulator + // Load into memory for ecMUL, leave offset for eccAdd result + // base is an array of pointers, so we have to dereference them + mstore(add(free, 0x40), mload(mload(base))) + mstore(add(free, 0x60), mload(add(0x20, mload(base)))) + // Add scalar + mstore(add(free, 0x80), mload(scalars)) + success := and(success, staticcall(gas(), 7, add(free, 0x40), 0x60, free, 0x40)) + + let count := 0x01 + for {} lt(count, limit) { count := add(count, 1) } { + // Get loop offsets + let base_base := add(base, mul(count, 0x20)) + let scalar_base := add(scalars, mul(count, 0x20)) + + mstore(add(free, 0x40), mload(mload(base_base))) + mstore(add(free, 0x60), mload(add(0x20, mload(base_base)))) + // Add scalar + mstore(add(free, 0x80), mload(scalar_base)) + + success := and(success, staticcall(gas(), 7, add(free, 0x40), 0x60, add(free, 0x40), 0x40)) + // accumulator = accumulator + accumulator_2 + success := and(success, staticcall(gas(), 6, free, 0x80, free, 0x40)) + } + + // Return the result - i hate this + mstore(result, mload(free)) + mstore(add(result, 0x20), mload(add(free, 0x20))) + } + } +} + +contract HonkVerifier is BaseHonkVerifier(N, LOG_N, NUMBER_OF_PUBLIC_INPUTS) { + function loadVerificationKey() internal pure override returns (Honk.VerificationKey memory) { + return HonkVerificationKey.loadVerificationKey(); + } +} diff --git a/test/src/entrypoints/HandleRegistrar/_HandleRegistrarTest.sol b/test/src/entrypoints/HandleRegistrar/_HandleRegistrarTest.sol index 6866c72..08f071a 100644 --- a/test/src/entrypoints/HandleRegistrar/_HandleRegistrarTest.sol +++ b/test/src/entrypoints/HandleRegistrar/_HandleRegistrarTest.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.30; import { Test } from "forge-std/Test.sol"; import { HandleRegistrarHelper } from "./_HandleRegistrarHelper.sol"; import { HandleCommandTestFixture } from "../../../fixtures/handleCommand/HandleCommandTestFixture.sol"; -import { HonkVerifier } from "../../../fixtures/handleCommand/HonkVerifier.sol"; +import { HonkVerifier } from "../../../fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol"; import { ClaimHandleCommand, ClaimHandleCommandVerifier diff --git a/test/src/entrypoints/LinkHandleEntrypoint/LinkHandleEntrypoint.t.sol b/test/src/entrypoints/LinkHandleEntrypoint/LinkHandleEntrypoint.t.sol index 680f8c4..64cc81c 100644 --- a/test/src/entrypoints/LinkHandleEntrypoint/LinkHandleEntrypoint.t.sol +++ b/test/src/entrypoints/LinkHandleEntrypoint/LinkHandleEntrypoint.t.sol @@ -4,11 +4,11 @@ pragma solidity ^0.8.30; import { Test } from "forge-std/Test.sol"; import { LinkHandleCommand } from "../../../../src/verifiers/HandleVerifier.sol"; import { LinkHandleCommandVerifier } from "../../../../src/verifiers/LinkHandleCommandVerifier.sol"; -import { HonkVerifier } from "../../../fixtures/handleCommand/HonkVerifier.sol"; +import { HonkVerifier } from "../../../fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol"; import { EnsUtils } from "../../../../src/utils/EnsUtils.sol"; import { LinkHandleEntrypointHelper } from "./_LinkHandleEntrypointHelper.sol"; import { LinkTextRecordEntrypoint } from "../../../../src/entrypoints/LinkTextRecordEntrypoint.sol"; -import { HandleCommandTestFixture } from "../../../fixtures/handleCommand/HandleCommandTestFixture.sol"; +import { LinkHandleCommandTestFixture } from "../../../fixtures/linkHandleCommand/LinkHandleCommandTestFixture.sol"; import { IDKIMRegistry } from "@zk-email/contracts/interfaces/IERC7969.sol"; contract LinkHandleVerifierTest is Test { @@ -21,7 +21,7 @@ contract LinkHandleVerifierTest is Test { LinkHandleEntrypointHelper public linkHandle; function setUp() public { - (LinkHandleCommand memory command,) = HandleCommandTestFixture.getLinkXFixture(); + (LinkHandleCommand memory command,) = LinkHandleCommandTestFixture.getTwitterFixture(); address dkimRegistry = makeAddr("dkimRegistry"); vm.mockCall( dkimRegistry, @@ -38,7 +38,7 @@ contract LinkHandleVerifierTest is Test { function test_entrypoint_correctlyEncodesAndValidatesCommand() public { (LinkHandleCommand memory command, bytes32[] memory expectedPublicInputs) = - HandleCommandTestFixture.getLinkXFixture(); + LinkHandleCommandTestFixture.getTwitterFixture(); bytes memory encodedCommand = linkHandle.encode(command.proof, expectedPublicInputs); assertEq(linkHandle.textRecord(bytes(command.textRecord.ensName).namehash()), ""); @@ -49,7 +49,7 @@ contract LinkHandleVerifierTest is Test { function test_entrypoint_revertsWhenNullifierIsUsed() public { (LinkHandleCommand memory command, bytes32[] memory expectedPublicInputs) = - HandleCommandTestFixture.getLinkXFixture(); + LinkHandleCommandTestFixture.getTwitterFixture(); bytes memory encodedCommand = linkHandle.encode(command.proof, expectedPublicInputs); linkHandle.entrypoint(encodedCommand); vm.expectRevert(abi.encodeWithSelector(LinkTextRecordEntrypoint.NullifierUsed.selector)); @@ -58,7 +58,7 @@ contract LinkHandleVerifierTest is Test { function test_entrypoint_revertsWhenPlatformNameMismatch() public { (LinkHandleCommand memory command, bytes32[] memory expectedPublicInputs) = - HandleCommandTestFixture.getLinkXFixture(); + LinkHandleCommandTestFixture.getTwitterFixture(); // Entrypoint configured for "discord" but command has platformName "x" (from fixture) LinkHandleEntrypointHelper discordEntrypoint = new LinkHandleEntrypointHelper(address(verifier), RECORD_NAME, "discord"); @@ -69,7 +69,7 @@ contract LinkHandleVerifierTest is Test { function test_verifyTextRecord_returnsFalseWhenTextRecordIsIncorrect() public { (LinkHandleCommand memory command, bytes32[] memory expectedPublicInputs) = - HandleCommandTestFixture.getLinkXFixture(); + LinkHandleCommandTestFixture.getTwitterFixture(); bytes memory encodedCommand = linkHandle.encode(command.proof, expectedPublicInputs); linkHandle.entrypoint(encodedCommand); assertEq( @@ -79,7 +79,7 @@ contract LinkHandleVerifierTest is Test { function test_verifyTextRecord_returnsTrueWhenTextRecordIsCorrect() public { (LinkHandleCommand memory command, bytes32[] memory expectedPublicInputs) = - HandleCommandTestFixture.getLinkXFixture(); + LinkHandleCommandTestFixture.getTwitterFixture(); bytes memory encodedCommand = linkHandle.encode(command.proof, expectedPublicInputs); linkHandle.entrypoint(encodedCommand); assertEq( diff --git a/test/src/resolvers/HandleResolver/HandleResolver.t.sol b/test/src/resolvers/HandleResolver/HandleResolver.t.sol index b27bc1f..fca5c83 100644 --- a/test/src/resolvers/HandleResolver/HandleResolver.t.sol +++ b/test/src/resolvers/HandleResolver/HandleResolver.t.sol @@ -9,7 +9,7 @@ import { ITextResolver } from "@ensdomains/ens-contracts/contracts/resolvers/pro import { IAddrResolver } from "@ensdomains/ens-contracts/contracts/resolvers/profiles/IAddrResolver.sol"; import { NameCoder } from "@ensdomains/ens-contracts/contracts/utils/NameCoder.sol"; import { ClaimHandleCommandVerifier } from "../../../../src/verifiers/ClaimHandleCommandVerifier.sol"; -import { HonkVerifier } from "../../../fixtures/handleCommand/HonkVerifier.sol"; +import { HonkVerifier } from "../../../fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol"; import { EnsUtils } from "../../../../src/utils/EnsUtils.sol"; contract HandleResolverTest is Test { diff --git a/test/src/resolvers/HandleResolver/ResolverRegistrarIntegration.t.sol b/test/src/resolvers/HandleResolver/ResolverRegistrarIntegration.t.sol index 2c144b3..96676a5 100644 --- a/test/src/resolvers/HandleResolver/ResolverRegistrarIntegration.t.sol +++ b/test/src/resolvers/HandleResolver/ResolverRegistrarIntegration.t.sol @@ -11,7 +11,7 @@ import { ClaimHandleCommand, ClaimHandleCommandVerifier } from "../../../../src/verifiers/ClaimHandleCommandVerifier.sol"; -import { HonkVerifier } from "../../../fixtures/handleCommand/HonkVerifier.sol"; +import { HonkVerifier } from "../../../fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol"; import { HandleCommandTestFixture } from "../../../fixtures/handleCommand/HandleCommandTestFixture.sol"; import { IDKIMRegistry } from "@zk-email/contracts/interfaces/IERC7969.sol"; import { EnsUtils } from "../../../../src/utils/EnsUtils.sol"; diff --git a/test/src/verifiers/ClaimHandleCommandVerifier/Encode.t.sol b/test/src/verifiers/ClaimHandleCommandVerifier/Encode.t.sol index 2a4ee89..b123946 100644 --- a/test/src/verifiers/ClaimHandleCommandVerifier/Encode.t.sol +++ b/test/src/verifiers/ClaimHandleCommandVerifier/Encode.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.30; import { HandleCommandTestFixture } from "../../../fixtures/handleCommand/HandleCommandTestFixture.sol"; -import { HonkVerifier } from "../../../fixtures/handleCommand/HonkVerifier.sol"; +import { HonkVerifier } from "../../../fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol"; import { ClaimHandleCommand, ClaimHandleCommandVerifier, diff --git a/test/src/verifiers/ClaimHandleCommandVerifier/IsValid.t.sol b/test/src/verifiers/ClaimHandleCommandVerifier/IsValid.t.sol index 5a75b9c..ccad52e 100644 --- a/test/src/verifiers/ClaimHandleCommandVerifier/IsValid.t.sol +++ b/test/src/verifiers/ClaimHandleCommandVerifier/IsValid.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.30; import { Test } from "forge-std/Test.sol"; import { HandleCommandTestFixture } from "../../../fixtures/handleCommand/HandleCommandTestFixture.sol"; -import { HonkVerifier } from "../../../fixtures/handleCommand/HonkVerifier.sol"; +import { HonkVerifier } from "../../../fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol"; import { ClaimHandleCommand, ClaimHandleCommandVerifier diff --git a/test/src/verifiers/LinkHandleCommandVerifier/Encode.t.sol b/test/src/verifiers/LinkHandleCommandVerifier/Encode.t.sol index 79af73e..e5ce83f 100644 --- a/test/src/verifiers/LinkHandleCommandVerifier/Encode.t.sol +++ b/test/src/verifiers/LinkHandleCommandVerifier/Encode.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.30; -import { HandleCommandTestFixture } from "../../../fixtures/handleCommand/HandleCommandTestFixture.sol"; -import { HonkVerifier } from "../../../fixtures/handleCommand/HonkVerifier.sol"; +import { LinkHandleCommandTestFixture } from "../../../fixtures/linkHandleCommand/LinkHandleCommandTestFixture.sol"; +import { HonkVerifier } from "../../../fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol"; import { LinkHandleCommand, LinkHandleCommandVerifier, @@ -20,7 +20,7 @@ contract EncodeTest is _EmailAuthVerifierTest { function test_correctlyEncodesAndDecodesCommand() public view { (LinkHandleCommand memory command, bytes32[] memory expectedPublicInputs) = - HandleCommandTestFixture.getLinkXFixture(); + LinkHandleCommandTestFixture.getTwitterFixture(); bytes memory encodedData = _verifier.encode(command.proof, expectedPublicInputs); LinkHandleCommand memory decodedCommand = abi.decode(encodedData, (LinkHandleCommand)); diff --git a/test/src/verifiers/LinkHandleCommandVerifier/IsValid.t.sol b/test/src/verifiers/LinkHandleCommandVerifier/IsValid.t.sol index f3cb3e1..bdd893c 100644 --- a/test/src/verifiers/LinkHandleCommandVerifier/IsValid.t.sol +++ b/test/src/verifiers/LinkHandleCommandVerifier/IsValid.t.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.30; import { Test } from "forge-std/Test.sol"; -import { HandleCommandTestFixture } from "../../../fixtures/handleCommand/HandleCommandTestFixture.sol"; -import { HonkVerifier } from "../../../fixtures/handleCommand/HonkVerifier.sol"; +import { LinkHandleCommandTestFixture } from "../../../fixtures/linkHandleCommand/LinkHandleCommandTestFixture.sol"; +import { HonkVerifier } from "../../../fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol"; import { LinkHandleCommand, LinkHandleCommandVerifier } from "../../../../src/verifiers/LinkHandleCommandVerifier.sol"; import { IDKIMRegistry } from "@zk-email/contracts/interfaces/IERC7969.sol"; @@ -11,7 +11,7 @@ contract IsValidTest is Test { LinkHandleCommandVerifier internal _verifier; function setUp() public { - (LinkHandleCommand memory command,) = HandleCommandTestFixture.getLinkXFixture(); + (LinkHandleCommand memory command,) = LinkHandleCommandTestFixture.getTwitterFixture(); address dkimRegistry = makeAddr("dkimRegistry"); vm.mockCall( dkimRegistry, @@ -29,7 +29,7 @@ contract IsValidTest is Test { // expect revert for now // TODO: figure this out function test_revertsWhen_InvalidProof() public { - (LinkHandleCommand memory command,) = HandleCommandTestFixture.getLinkXFixture(); + (LinkHandleCommand memory command,) = LinkHandleCommandTestFixture.getTwitterFixture(); bytes memory proof = new bytes(command.proof.length); proof[0] = command.proof[0] ^ bytes1(uint8(1)); command.proof = proof; @@ -38,20 +38,20 @@ contract IsValidTest is Test { } function test_returnsTrueForValidCommand() public view { - (LinkHandleCommand memory command,) = HandleCommandTestFixture.getLinkXFixture(); + (LinkHandleCommand memory command,) = LinkHandleCommandTestFixture.getTwitterFixture(); bool isValid = _verifier.verify(abi.encode(command)); assertTrue(isValid); } function test_returnsFalseForWrongENSName() public view { - (LinkHandleCommand memory command,) = HandleCommandTestFixture.getLinkXFixture(); + (LinkHandleCommand memory command,) = LinkHandleCommandTestFixture.getTwitterFixture(); command.textRecord.ensName = "wrong.eth"; bool isValid = _verifier.verify(abi.encode(command)); assertFalse(isValid); } function test_returnsFalseForWrongHandle() public view { - (LinkHandleCommand memory command,) = HandleCommandTestFixture.getLinkXFixture(); + (LinkHandleCommand memory command,) = LinkHandleCommandTestFixture.getTwitterFixture(); command.textRecord.value = "wrong"; bool isValid = _verifier.verify(abi.encode(command)); assertFalse(isValid); diff --git a/test/src/verifiers/LinkHandleCommandVerifier/PackPublicInputs.t.sol b/test/src/verifiers/LinkHandleCommandVerifier/PackPublicInputs.t.sol index e87a39a..a9db3cf 100644 --- a/test/src/verifiers/LinkHandleCommandVerifier/PackPublicInputs.t.sol +++ b/test/src/verifiers/LinkHandleCommandVerifier/PackPublicInputs.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.30; import { Test } from "forge-std/Test.sol"; -import { HandleCommandTestFixture } from "../../../fixtures/handleCommand/HandleCommandTestFixture.sol"; +import { LinkHandleCommandTestFixture } from "../../../fixtures/linkHandleCommand/LinkHandleCommandTestFixture.sol"; import { LinkHandleCommand } from "../../../../src/verifiers/HandleVerifier.sol"; import { LinkHandleCommandVerifierHelper } from "./_LinkHandleCommandVerifierHelper.sol"; @@ -17,7 +17,7 @@ contract PackPublicInputsTest is Test { function test_correctlyPacksPublicInputsForLinkHandleCommand() public view { (LinkHandleCommand memory command, bytes32[] memory expectedPublicInputs) = - HandleCommandTestFixture.getLinkXFixture(); + LinkHandleCommandTestFixture.getTwitterFixture(); bytes32[] memory publicInputs = _verifier.packPublicInputs(command.publicInputs); _assertEq(publicInputs, expectedPublicInputs); } From b3799b62b73a7ecbb25f6a25f25b2940fa2c144e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bence=20H=C3=A1romi?= <56651250+benceharomi@users.noreply.github.com> Date: Wed, 18 Feb 2026 18:31:01 +0000 Subject: [PATCH 06/11] fix: deployment script --- .../DeployLinkHandleEntrypointTwitter.s.sol | 2 +- .../_DeployLinkHandleEntrypoint.s.sol | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol b/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol index 0534709..816d516 100644 --- a/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol +++ b/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointTwitter.s.sol @@ -5,7 +5,7 @@ import { DeployLinkHandleEntrypointScript } from "./_DeployLinkHandleEntrypoint. import { HonkVerifier } from "../../test/fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol"; contract DeployLinkHandleEntrypointTwitterScript is DeployLinkHandleEntrypointScript { - function _getHonkVerifierAddress() internal override returns (address) { + function _deployHonkVerifier() internal override returns (address) { return address(new HonkVerifier()); } diff --git a/script/DeployLinkHandleEntrypoint/_DeployLinkHandleEntrypoint.s.sol b/script/DeployLinkHandleEntrypoint/_DeployLinkHandleEntrypoint.s.sol index 902d30a..04dfcd2 100644 --- a/script/DeployLinkHandleEntrypoint/_DeployLinkHandleEntrypoint.s.sol +++ b/script/DeployLinkHandleEntrypoint/_DeployLinkHandleEntrypoint.s.sol @@ -11,9 +11,13 @@ abstract contract DeployLinkHandleEntrypointScript is Script { vm.startBroadcast(deployerPrivateKey); + console.log("\n=== Step 0: Deploy HonkVerifier ==="); + address honkVerifierAddress = _deployHonkVerifier(); + console.log("HonkVerifier deployed at:", honkVerifierAddress); + console.log("\n=== Step 1: Deploy LinkHandleCommandVerifier ==="); LinkHandleCommandVerifier commandVerifier = - new LinkHandleCommandVerifier(_getHonkVerifierAddress(), _getDkimRegistryAddress()); + new LinkHandleCommandVerifier(honkVerifierAddress, _getDkimRegistryAddress()); console.log("LinkHandleCommandVerifier deployed at:", address(commandVerifier)); console.log("\n=== Step 2: Deploy LinkHandleEntrypoint ==="); @@ -24,7 +28,7 @@ abstract contract DeployLinkHandleEntrypointScript is Script { vm.stopBroadcast(); console.log("\n=== Deployment Complete ==="); - console.log("HONK_VERIFIER=", _getHonkVerifierAddress()); + console.log("HONK_VERIFIER=", honkVerifierAddress); console.log("DKIM_REGISTRY=", _getDkimRegistryAddress()); console.log("LINK_HANDLE_COMMAND_VERIFIER=", address(commandVerifier)); console.log("RECORD_NAME=", _getRecordName()); @@ -33,13 +37,14 @@ abstract contract DeployLinkHandleEntrypointScript is Script { } /** - * @notice The HonkVerifier address. - * @dev TODO: ideally ths would be pure and would only return the address of the HonkVerifier deployed by the + * @notice Deploys the HonkVerifier and returns the address. + * @dev TODO: ideally ths would be a pure address getter and would only return the address of the HonkVerifier + * deployed by the * registry. Currently this is deployed inside this function. Remove it once the registry deploys the * HonkVerifier. * @return The address of the HonkVerifier */ - function _getHonkVerifierAddress() internal virtual returns (address); + function _deployHonkVerifier() internal virtual returns (address); /** * @notice The DKIM registry address. From 72e160869aa50938b03b2adc0f858a14c9efec14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bence=20H=C3=A1romi?= <56651250+benceharomi@users.noreply.github.com> Date: Wed, 18 Feb 2026 18:31:47 +0000 Subject: [PATCH 07/11] feat: removed discord --- .../DeployLinkHandleEntrypointDiscord.s.sol | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointDiscord.s.sol diff --git a/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointDiscord.s.sol b/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointDiscord.s.sol deleted file mode 100644 index cf86c33..0000000 --- a/script/DeployLinkHandleEntrypoint/DeployLinkHandleEntrypointDiscord.s.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import { DeployLinkHandleEntrypointScript } from "./_DeployLinkHandleEntrypoint.s.sol"; -import { HonkVerifier } from "../../test/fixtures/handleCommand/HonkVerifier.sol"; - -contract DeployLinkHandleEntrypointTwitterScript is DeployLinkHandleEntrypointScript { - function _deployHonkVerifier() internal override returns (address) { - return address(new HonkVerifier()); - } - - function _dkimRegistry() internal pure override returns (address) { - // sepolia always valid dkim registry - return 0xc4f628496b8c474096650C8f9023954643cC614F; - } - - function _keyName() internal pure override returns (string memory) { - return "com.twitter"; - } -} From cad061023879f5dda26df148424cdfad2c516104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bence=20H=C3=A1romi?= <56651250+benceharomi@users.noreply.github.com> Date: Thu, 19 Feb 2026 14:42:44 +0000 Subject: [PATCH 08/11] feat: updated twitter circuit --- .../linkHandleCommand/twitter/Nargo.toml | 2 +- .../twitter/files/blueprint.json | 61 +++++++ .../linkHandleCommand/twitter/src/main.nr | 8 +- .../twitter/src/sender_domain_regex.nr | 155 +++--------------- .../twitter/src/x_handle_regex.nr | 93 +++-------- 5 files changed, 109 insertions(+), 210 deletions(-) create mode 100644 test/fixtures/linkHandleCommand/twitter/files/blueprint.json diff --git a/test/fixtures/linkHandleCommand/twitter/Nargo.toml b/test/fixtures/linkHandleCommand/twitter/Nargo.toml index 2573e2d..437d182 100644 --- a/test/fixtures/linkHandleCommand/twitter/Nargo.toml +++ b/test/fixtures/linkHandleCommand/twitter/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "link_x_handle_command" +name = "benceharomi/x_handle@v1" type = "bin" authors = [] compiler_version = ">=1.0.0" diff --git a/test/fixtures/linkHandleCommand/twitter/files/blueprint.json b/test/fixtures/linkHandleCommand/twitter/files/blueprint.json new file mode 100644 index 0000000..e12b1a0 --- /dev/null +++ b/test/fixtures/linkHandleCommand/twitter/files/blueprint.json @@ -0,0 +1,61 @@ +{ + "name": "x_handle", + "values": [ + { + "parts": [ + { + "isPublic": false, + "regexDef": "This email was meant for @" + }, + { + "isPublic": true, + "regexDef": "[A-Za-z0-9_]+", + "maxLength": 64 + }, + { + "isPublic": false, + "regexDef": " " + } + ], + "name": "x_handle", + "maxLength": 8, + "location": "body", + "maxMatchLength": 64 + }, + { + "parts": [ + { + "isPublic": false, + "regexDef": "[A-Za-z0-9!#$%&'*+=?\\-\\^_`{|}~./]+@" + }, + { + "isPublic": true, + "regexDef": "[A-Za-z0-9.\\-@]+", + "maxLength": 64 + }, + { + "isPublic": false, + "regexDef": "[>\r\n]" + } + ], + "name": "sender_domain", + "maxLength": 5, + "location": "header", + "maxMatchLength": 64 + } + ], + "version": 1, + "senderDomain": "x.com", + "externalInputs": [ + { + "name": "command", + "maxLength": 605 + } + ], + "emailBodyMaxLength": 1920, + "ignoreBodyHashCheck": false, + "emailHeaderMaxLength": 960, + "shaPrecomputeSelector": " pub (Field, Field, Field, Field, [Field; 1], [Field; 20], BoundedVec, BoundedVec) { +) -> pub (Field, Field, Field, Field, [Field; 1] , [Field; 20], BoundedVec, BoundedVec) { // check the body and header lengths are within bounds assert(header.len() <= 960); assert(body.len() <= 1920); @@ -78,8 +79,5 @@ fn main( sender_domain_capture_group_1_start, sender_domain_capture_group_start_indices, ); - ( - pubkey_hash, email_nullifier, header_hash[0], header_hash[1], prover_address, command, - x_handle_capture_1, sender_domain_capture_1, - ) + (pubkey_hash, email_nullifier, header_hash[0], header_hash[1], prover_address, command, x_handle_capture_1, sender_domain_capture_1) } diff --git a/test/fixtures/linkHandleCommand/twitter/src/sender_domain_regex.nr b/test/fixtures/linkHandleCommand/twitter/src/sender_domain_regex.nr index 373d104..6d625f5 100644 --- a/test/fixtures/linkHandleCommand/twitter/src/sender_domain_regex.nr +++ b/test/fixtures/linkHandleCommand/twitter/src/sender_domain_regex.nr @@ -1,124 +1,14 @@ use zkregex::utils::{ - captures::capture_substring, select_subarray, sparse_array::SparseArray, - transitions::check_transition_with_captures, + select_subarray, + captures::capture_substring, + sparse_array::SparseArray, + transitions::check_transition_with_captures }; global TRANSITION_TABLE: SparseArray<380, Field> = SparseArray { - keys: [ - 0x00000000, 0x00022523, 0x00022524, 0x00022525, 0x00022725, 0x00022726, 0x00022727, - 0x00022826, 0x00022827, 0x00022828, 0x00022927, 0x00022928, 0x00022929, 0x00022a28, - 0x00022a29, 0x00022a2a, 0x00022b29, 0x00022b2a, 0x00022b2b, 0x00022e2c, 0x00022e2d, - 0x00022e2e, 0x00022f2d, 0x00022f2e, 0x00022f2f, 0x0002312f, 0x00023130, 0x00023131, - 0x00023230, 0x00023231, 0x00023232, 0x00023331, 0x00023332, 0x00023333, 0x00023432, - 0x00023433, 0x00023434, 0x00023533, 0x00023534, 0x00023535, 0x00023634, 0x00023635, - 0x00023636, 0x00023735, 0x00023736, 0x00023737, 0x00023836, 0x00023837, 0x00023838, - 0x00023937, 0x00023938, 0x00023939, 0x00023a38, 0x00023a39, 0x00023a3a, 0x00023b39, - 0x00023b3a, 0x00023b3b, 0x00023c3a, 0x00023c3b, 0x00023c3c, 0x00023d3b, 0x00023d3c, - 0x00023d3d, 0x0002413f, 0x00024140, 0x00024141, 0x00024341, 0x00024342, 0x00024343, - 0x00024543, 0x00024544, 0x00024545, 0x00024644, 0x00024645, 0x00024646, 0x00024745, - 0x00024746, 0x00024747, 0x00024846, 0x00024847, 0x00024848, 0x00024947, 0x00024948, - 0x00024949, 0x00024a48, 0x00024a49, 0x00024a4a, 0x00024b49, 0x00024b4a, 0x00024b4b, - 0x00024c4a, 0x00024c4b, 0x00024c4c, 0x00024d4b, 0x00024d4c, 0x00024d4d, 0x00024e4c, - 0x00024e4d, 0x00024e4e, 0x00024f4d, 0x00024f4e, 0x00024f4f, 0x0002504e, 0x0002504f, - 0x00025050, 0x0002514f, 0x00025150, 0x00025151, 0x00025250, 0x00025251, 0x00025252, - 0x00025351, 0x00025352, 0x00025353, 0x00025452, 0x00025453, 0x00025454, 0x00025553, - 0x00025554, 0x00025555, 0x00025654, 0x00025655, 0x00025656, 0x00025755, 0x00025756, - 0x00025757, 0x00025856, 0x00025857, 0x00025858, 0x00025957, 0x00025958, 0x00025959, - 0x00025a58, 0x00025a59, 0x00025a5a, 0x00025b59, 0x00025b5a, 0x00025b5b, 0x00025c5a, - 0x00025c5b, 0x00025c5c, 0x00025d5b, 0x00025d5c, 0x00025d5d, 0x00025e5c, 0x00025e5d, - 0x00025e5e, 0x00026260, 0x00026261, 0x00026262, 0x00026361, 0x00026362, 0x00026363, - 0x00026462, 0x00026463, 0x00026464, 0x00026563, 0x00026564, 0x00026565, 0x00026664, - 0x00026665, 0x00026666, 0x00026765, 0x00026766, 0x00026767, 0x00026866, 0x00026867, - 0x00026868, 0x00026967, 0x00026968, 0x00026969, 0x00026a68, 0x00026a69, 0x00026a6a, - 0x00026b69, 0x00026b6a, 0x00026b6b, 0x00026c6a, 0x00026c6b, 0x00026c6c, 0x00026d6b, - 0x00026d6c, 0x00026d6d, 0x00026e6c, 0x00026e6d, 0x00026e6e, 0x00026f6d, 0x00026f6e, - 0x00026f6f, 0x0002706e, 0x0002706f, 0x00027070, 0x0002716f, 0x00027170, 0x00027171, - 0x00027270, 0x00027271, 0x00027272, 0x00027371, 0x00027372, 0x00027373, 0x00027472, - 0x00027473, 0x00027474, 0x00027573, 0x00027574, 0x00027575, 0x00027674, 0x00027675, - 0x00027676, 0x00027775, 0x00027776, 0x00027777, 0x00027876, 0x00027877, 0x00027878, - 0x00027977, 0x00027978, 0x00027979, 0x00027a78, 0x00027a79, 0x00027a7a, 0x00027b79, - 0x00027b7a, 0x00027b7b, 0x00027c7a, 0x00027c7b, 0x00027c7c, 0x00027d7b, 0x00027d7c, - 0x00027d7d, 0x00027e7c, 0x00027e7d, 0x00027e7e, 0x00027f7d, 0x00027f7e, 0x00027f7f, - 0x0002807e, 0x0002807f, 0x00028080, 0x0002817f, 0x00028180, 0x00028181, 0x00028280, - 0x00028281, 0x00028282, 0x00034645, 0x00043534, 0x00043535, 0x00043635, 0x00043636, - 0x00043837, 0x00043838, 0x00043938, 0x00043939, 0x00043a39, 0x00043a3a, 0x00043b3a, - 0x00043b3b, 0x00043c3b, 0x00043c3c, 0x00043d3c, 0x00043d3d, 0x00043e3d, 0x00043e3e, - 0x00043f3e, 0x00043f3f, 0x0004403f, 0x00044040, 0x00044140, 0x00044141, 0x00044847, - 0x00044848, 0x00044948, 0x00044949, 0x00044a49, 0x00044a4a, 0x00044b4a, 0x00044b4b, - 0x00044c4b, 0x00044c4c, 0x00044d4c, 0x00044d4d, 0x00044e4d, 0x00044e4e, 0x00044f4e, - 0x00044f4f, 0x0004504f, 0x00045050, 0x00045150, 0x00045151, 0x00045251, 0x00045252, - 0x00045352, 0x00045353, 0x00045453, 0x00045454, 0x00045554, 0x00045555, 0x00045655, - 0x00045656, 0x00045756, 0x00045757, 0x00045857, 0x00045858, 0x00045958, 0x00045959, - 0x00045a59, 0x00045a5a, 0x00045b5a, 0x00045b5b, 0x00045c5b, 0x00045c5c, 0x00045d5c, - 0x00045d5d, 0x00045e5d, 0x00045e5e, 0x00045f5e, 0x00045f5f, 0x0004605f, 0x00046060, - 0x00046160, 0x00046161, 0x00046261, 0x00046262, 0x00046968, 0x00046969, 0x00046a69, - 0x00046a6a, 0x00046b6a, 0x00046b6b, 0x00046c6b, 0x00046c6c, 0x00046d6c, 0x00046d6d, - 0x00046e6d, 0x00046e6e, 0x00046f6e, 0x00046f6f, 0x0004706f, 0x00047070, 0x00047170, - 0x00047171, 0x00047271, 0x00047272, 0x00047372, 0x00047373, 0x00047473, 0x00047474, - 0x00047574, 0x00047575, 0x00047675, 0x00047676, 0x00047776, 0x00047777, 0x00047877, - 0x00047878, 0x00047978, 0x00047979, 0x00047a79, 0x00047a7a, 0x00047b7a, 0x00047b7b, - 0x00047c7b, 0x00047c7c, 0x00047d7c, 0x00047d7d, 0x00047e7d, 0x00047e7e, 0x00047f7e, - 0x00047f7f, 0x0004807f, 0x00048080, 0x00048180, 0x00048181, 0x00048281, 0x00048282, - 0x00051413, 0x00051716, 0x00054847, 0x00060a09, - ], - values: [ - 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000001, 0x00000001, 0x00000001, 0x00000000, - ], - maximum: 0x00060a09, + keys: [0x00000000, 0x00022523, 0x00022524, 0x00022525, 0x00022725, 0x00022726, 0x00022727, 0x00022826, 0x00022827, 0x00022828, 0x00022927, 0x00022928, 0x00022929, 0x00022a28, 0x00022a29, 0x00022a2a, 0x00022b29, 0x00022b2a, 0x00022b2b, 0x00022e2c, 0x00022e2d, 0x00022e2e, 0x00022f2d, 0x00022f2e, 0x00022f2f, 0x0002312f, 0x00023130, 0x00023131, 0x00023230, 0x00023231, 0x00023232, 0x00023331, 0x00023332, 0x00023333, 0x00023432, 0x00023433, 0x00023434, 0x00023533, 0x00023534, 0x00023535, 0x00023634, 0x00023635, 0x00023636, 0x00023735, 0x00023736, 0x00023737, 0x00023836, 0x00023837, 0x00023838, 0x00023937, 0x00023938, 0x00023939, 0x00023a38, 0x00023a39, 0x00023a3a, 0x00023b39, 0x00023b3a, 0x00023b3b, 0x00023c3a, 0x00023c3b, 0x00023c3c, 0x00023d3b, 0x00023d3c, 0x00023d3d, 0x0002413f, 0x00024140, 0x00024141, 0x00024341, 0x00024342, 0x00024343, 0x00024543, 0x00024544, 0x00024545, 0x00024644, 0x00024645, 0x00024646, 0x00024745, 0x00024746, 0x00024747, 0x00024846, 0x00024847, 0x00024848, 0x00024947, 0x00024948, 0x00024949, 0x00024a48, 0x00024a49, 0x00024a4a, 0x00024b49, 0x00024b4a, 0x00024b4b, 0x00024c4a, 0x00024c4b, 0x00024c4c, 0x00024d4b, 0x00024d4c, 0x00024d4d, 0x00024e4c, 0x00024e4d, 0x00024e4e, 0x00024f4d, 0x00024f4e, 0x00024f4f, 0x0002504e, 0x0002504f, 0x00025050, 0x0002514f, 0x00025150, 0x00025151, 0x00025250, 0x00025251, 0x00025252, 0x00025351, 0x00025352, 0x00025353, 0x00025452, 0x00025453, 0x00025454, 0x00025553, 0x00025554, 0x00025555, 0x00025654, 0x00025655, 0x00025656, 0x00025755, 0x00025756, 0x00025757, 0x00025856, 0x00025857, 0x00025858, 0x00025957, 0x00025958, 0x00025959, 0x00025a58, 0x00025a59, 0x00025a5a, 0x00025b59, 0x00025b5a, 0x00025b5b, 0x00025c5a, 0x00025c5b, 0x00025c5c, 0x00025d5b, 0x00025d5c, 0x00025d5d, 0x00025e5c, 0x00025e5d, 0x00025e5e, 0x00026260, 0x00026261, 0x00026262, 0x00026361, 0x00026362, 0x00026363, 0x00026462, 0x00026463, 0x00026464, 0x00026563, 0x00026564, 0x00026565, 0x00026664, 0x00026665, 0x00026666, 0x00026765, 0x00026766, 0x00026767, 0x00026866, 0x00026867, 0x00026868, 0x00026967, 0x00026968, 0x00026969, 0x00026a68, 0x00026a69, 0x00026a6a, 0x00026b69, 0x00026b6a, 0x00026b6b, 0x00026c6a, 0x00026c6b, 0x00026c6c, 0x00026d6b, 0x00026d6c, 0x00026d6d, 0x00026e6c, 0x00026e6d, 0x00026e6e, 0x00026f6d, 0x00026f6e, 0x00026f6f, 0x0002706e, 0x0002706f, 0x00027070, 0x0002716f, 0x00027170, 0x00027171, 0x00027270, 0x00027271, 0x00027272, 0x00027371, 0x00027372, 0x00027373, 0x00027472, 0x00027473, 0x00027474, 0x00027573, 0x00027574, 0x00027575, 0x00027674, 0x00027675, 0x00027676, 0x00027775, 0x00027776, 0x00027777, 0x00027876, 0x00027877, 0x00027878, 0x00027977, 0x00027978, 0x00027979, 0x00027a78, 0x00027a79, 0x00027a7a, 0x00027b79, 0x00027b7a, 0x00027b7b, 0x00027c7a, 0x00027c7b, 0x00027c7c, 0x00027d7b, 0x00027d7c, 0x00027d7d, 0x00027e7c, 0x00027e7d, 0x00027e7e, 0x00027f7d, 0x00027f7e, 0x00027f7f, 0x0002807e, 0x0002807f, 0x00028080, 0x0002817f, 0x00028180, 0x00028181, 0x00028280, 0x00028281, 0x00028282, 0x00034645, 0x00043534, 0x00043535, 0x00043635, 0x00043636, 0x00043837, 0x00043838, 0x00043938, 0x00043939, 0x00043a39, 0x00043a3a, 0x00043b3a, 0x00043b3b, 0x00043c3b, 0x00043c3c, 0x00043d3c, 0x00043d3d, 0x00043e3d, 0x00043e3e, 0x00043f3e, 0x00043f3f, 0x0004403f, 0x00044040, 0x00044140, 0x00044141, 0x00044847, 0x00044848, 0x00044948, 0x00044949, 0x00044a49, 0x00044a4a, 0x00044b4a, 0x00044b4b, 0x00044c4b, 0x00044c4c, 0x00044d4c, 0x00044d4d, 0x00044e4d, 0x00044e4e, 0x00044f4e, 0x00044f4f, 0x0004504f, 0x00045050, 0x00045150, 0x00045151, 0x00045251, 0x00045252, 0x00045352, 0x00045353, 0x00045453, 0x00045454, 0x00045554, 0x00045555, 0x00045655, 0x00045656, 0x00045756, 0x00045757, 0x00045857, 0x00045858, 0x00045958, 0x00045959, 0x00045a59, 0x00045a5a, 0x00045b5a, 0x00045b5b, 0x00045c5b, 0x00045c5c, 0x00045d5c, 0x00045d5d, 0x00045e5d, 0x00045e5e, 0x00045f5e, 0x00045f5f, 0x0004605f, 0x00046060, 0x00046160, 0x00046161, 0x00046261, 0x00046262, 0x00046968, 0x00046969, 0x00046a69, 0x00046a6a, 0x00046b6a, 0x00046b6b, 0x00046c6b, 0x00046c6c, 0x00046d6c, 0x00046d6d, 0x00046e6d, 0x00046e6e, 0x00046f6e, 0x00046f6f, 0x0004706f, 0x00047070, 0x00047170, 0x00047171, 0x00047271, 0x00047272, 0x00047372, 0x00047373, 0x00047473, 0x00047474, 0x00047574, 0x00047575, 0x00047675, 0x00047676, 0x00047776, 0x00047777, 0x00047877, 0x00047878, 0x00047978, 0x00047979, 0x00047a79, 0x00047a7a, 0x00047b7a, 0x00047b7b, 0x00047c7b, 0x00047c7c, 0x00047d7c, 0x00047d7d, 0x00047e7d, 0x00047e7e, 0x00047f7e, 0x00047f7f, 0x0004807f, 0x00048080, 0x00048180, 0x00048181, 0x00048281, 0x00048282, 0x00051413, 0x00051716, 0x00054847, 0x00060a09], + values: [0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000001, 0x00000001, 0x00000001, 0x00000000], + maximum: 0x00060a09 }; pub global CAPTURE_1_MAX_LENGTH: u32 = 64; @@ -129,21 +19,21 @@ pub global NUM_CAPTURE_GROUPS: u32 = 1; * @dev start states are hardcoded in this function - "(start_state - {state})" for each start * example: `(start_state - 0) * (start_state - 1) * (start_state - 2)` means 0, 1, or 2 * are valid first states - * + * * @param start_state - The start state of the NFA */ fn check_start_state(start_state: Field) { let valid_start_state = (start_state - 0) * (start_state - 1); assert(valid_start_state == 0, "Invalid start state"); } - + /** * Constrains the recognition of accept_state being reached. If an aceppt state is reached, * ensures asserted traversal path is valid * @dev accept states are hardcoded in this function - "(next_state - {state})" for each accept * example: `(next_state - 19) * (next_state - 20) * (next_state - 21)` means 19, 20, or 21 * are valid accept states - * + * * @param next_state - The asserted next state of the NFA * @param haystack_index - The index being operated on in the haystack * @param asserted_match_length - The asserted traversal path length @@ -151,8 +41,8 @@ fn check_start_state(start_state: Field) { */ fn check_accept_state( next_state: Field, - haystack_index: Field, - asserted_match_length: Field, + haystack_index: Field, + asserted_match_length: Field ) -> Field { // check if the next state is an accept state let accept_state_reached = (next_state - 5); @@ -188,12 +78,11 @@ pub fn regex_match( capture_group_1_start: [Field; MAX_MATCH_LEN], capture_group_start_indices: [Field; NUM_CAPTURE_GROUPS], ) -> (BoundedVec) { - // resize haystack - let haystack: [u8; MAX_MATCH_LEN] = - select_subarray::(in_haystack, match_start, match_length); + // resize haystack + let haystack: [u8; MAX_MATCH_LEN] = select_subarray::(in_haystack, match_start, match_length); check_start_state(current_states[0]); - for i in 0..MAX_MATCH_LEN - 1 { + for i in 0..MAX_MATCH_LEN-1 { // match length - 1 since current states should be 1 less than next states let in_range = (i < match_length - 1) as Field; let matching_states = current_states[i + 1] - next_states[i]; @@ -210,20 +99,20 @@ pub fn regex_match( next_states[i], active_capture_groups_at_index, active_capture_groups_starts_at_index, - reached_end_state, + reached_end_state ); - reached_end_state = reached_end_state - * check_accept_state(next_states[i], i as Field, match_length as Field); + reached_end_state = reached_end_state * check_accept_state(next_states[i], i as Field, match_length as Field); } assert(reached_end_state == 0, "Did not reach a valid end state"); // Capture Group 1 let capture_1 = capture_substring::( - haystack, - capture_group_1_id, - capture_group_1_start, - capture_group_start_indices[0], + haystack, + capture_group_1_id, + capture_group_1_start, + capture_group_start_indices[0] ); (capture_1) } + diff --git a/test/fixtures/linkHandleCommand/twitter/src/x_handle_regex.nr b/test/fixtures/linkHandleCommand/twitter/src/x_handle_regex.nr index d59bbdf..6909014 100644 --- a/test/fixtures/linkHandleCommand/twitter/src/x_handle_regex.nr +++ b/test/fixtures/linkHandleCommand/twitter/src/x_handle_regex.nr @@ -1,62 +1,14 @@ use zkregex::utils::{ - captures::capture_substring, select_subarray, sparse_array::SparseArray, - transitions::check_transition_with_captures, + select_subarray, + captures::capture_substring, + sparse_array::SparseArray, + transitions::check_transition_with_captures }; global TRANSITION_TABLE: SparseArray<161, Field> = SparseArray { - keys: [ - 0x00000000, 0x00025856, 0x00025857, 0x00036e6d, 0x00047170, 0x00057d7c, 0x00062c2b, - 0x00077372, 0x00087d7c, 0x00097372, 0x000a7d7c, 0x000b8281, 0x000c3837, 0x000d9190, - 0x000e7d7c, 0x000f9190, 0x0010403f, 0x00118f8e, 0x00128988, 0x00138786, 0x00149695, - 0x00159e9d, 0x00164c4b, 0x00179493, 0x00189f9e, 0x0019a4a3, 0x001a5453, 0x001b7675, - 0x001c6867, 0x001c6868, 0x001c6968, 0x001c6969, 0x001c6a69, 0x001c6a6a, 0x001c6b6a, - 0x001c6b6b, 0x001c6c6b, 0x001c6c6c, 0x001c6d6c, 0x001c6d6d, 0x001c6e6d, 0x001c6e6e, - 0x001c6f6e, 0x001c6f6f, 0x001c706f, 0x001c7070, 0x001c7170, 0x001c7171, 0x001c7978, - 0x001c7979, 0x001c7a79, 0x001c7a7a, 0x001c7b7a, 0x001c7b7b, 0x001c7c7b, 0x001c7c7c, - 0x001c7d7c, 0x001c7d7d, 0x001c7e7d, 0x001c7e7e, 0x001c7f7e, 0x001c7f7f, 0x001c807f, - 0x001c8080, 0x001c8180, 0x001c8181, 0x001c8281, 0x001c8282, 0x001c8382, 0x001c8383, - 0x001c8483, 0x001c8484, 0x001c8584, 0x001c8585, 0x001c8685, 0x001c8686, 0x001c8786, - 0x001c8787, 0x001c8887, 0x001c8888, 0x001c8988, 0x001c8989, 0x001c8a89, 0x001c8a8a, - 0x001c8b8a, 0x001c8b8b, 0x001c8c8b, 0x001c8c8c, 0x001c8d8c, 0x001c8d8d, 0x001c8e8d, - 0x001c8e8e, 0x001c8f8e, 0x001c8f8f, 0x001c908f, 0x001c9090, 0x001c9190, 0x001c9191, - 0x001c9291, 0x001c9292, 0x001c9796, 0x001c9797, 0x001c9998, 0x001c9999, 0x001c9a99, - 0x001c9a9a, 0x001c9b9a, 0x001c9b9b, 0x001c9c9b, 0x001c9c9c, 0x001c9d9c, 0x001c9d9d, - 0x001c9e9d, 0x001c9e9e, 0x001c9f9e, 0x001c9f9f, 0x001ca09f, 0x001ca0a0, 0x001ca1a0, - 0x001ca1a1, 0x001ca2a1, 0x001ca2a2, 0x001ca3a2, 0x001ca3a3, 0x001ca4a3, 0x001ca4a4, - 0x001ca5a4, 0x001ca5a5, 0x001ca6a5, 0x001ca6a6, 0x001ca7a6, 0x001ca7a7, 0x001ca8a7, - 0x001ca8a8, 0x001ca9a8, 0x001ca9a9, 0x001caaa9, 0x001caaaa, 0x001cabaa, 0x001cabab, - 0x001cacab, 0x001cacac, 0x001cadac, 0x001cadad, 0x001caead, 0x001caeae, 0x001cafae, - 0x001cafaf, 0x001cb0af, 0x001cb0b0, 0x001cb1b0, 0x001cb1b1, 0x001cb2b1, 0x001cb2b2, - 0x001d5a59, 0x001e7877, 0x001f6d6c, 0x0020b3b2, 0x0021b2b1, 0x0022a5a4, 0x0023b4b3, - 0x00248685, 0x00254847, - ], - values: [ - 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, - 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, - 0x00000005, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, - 0x00000001, 0x00000001, 0x00000000, - ], - maximum: 0x00254847, + keys: [0x00000000, 0x00025856, 0x00025857, 0x00036e6d, 0x00047170, 0x00057d7c, 0x00062c2b, 0x00077372, 0x00087d7c, 0x00097372, 0x000a7d7c, 0x000b8281, 0x000c3837, 0x000d9190, 0x000e7d7c, 0x000f9190, 0x0010403f, 0x00118f8e, 0x00128988, 0x00138786, 0x00149695, 0x00159e9d, 0x00164c4b, 0x00179493, 0x00189f9e, 0x0019a4a3, 0x001a5453, 0x001b7675, 0x001c6867, 0x001c6868, 0x001c6968, 0x001c6969, 0x001c6a69, 0x001c6a6a, 0x001c6b6a, 0x001c6b6b, 0x001c6c6b, 0x001c6c6c, 0x001c6d6c, 0x001c6d6d, 0x001c6e6d, 0x001c6e6e, 0x001c6f6e, 0x001c6f6f, 0x001c706f, 0x001c7070, 0x001c7170, 0x001c7171, 0x001c7978, 0x001c7979, 0x001c7a79, 0x001c7a7a, 0x001c7b7a, 0x001c7b7b, 0x001c7c7b, 0x001c7c7c, 0x001c7d7c, 0x001c7d7d, 0x001c7e7d, 0x001c7e7e, 0x001c7f7e, 0x001c7f7f, 0x001c807f, 0x001c8080, 0x001c8180, 0x001c8181, 0x001c8281, 0x001c8282, 0x001c8382, 0x001c8383, 0x001c8483, 0x001c8484, 0x001c8584, 0x001c8585, 0x001c8685, 0x001c8686, 0x001c8786, 0x001c8787, 0x001c8887, 0x001c8888, 0x001c8988, 0x001c8989, 0x001c8a89, 0x001c8a8a, 0x001c8b8a, 0x001c8b8b, 0x001c8c8b, 0x001c8c8c, 0x001c8d8c, 0x001c8d8d, 0x001c8e8d, 0x001c8e8e, 0x001c8f8e, 0x001c8f8f, 0x001c908f, 0x001c9090, 0x001c9190, 0x001c9191, 0x001c9291, 0x001c9292, 0x001c9796, 0x001c9797, 0x001c9998, 0x001c9999, 0x001c9a99, 0x001c9a9a, 0x001c9b9a, 0x001c9b9b, 0x001c9c9b, 0x001c9c9c, 0x001c9d9c, 0x001c9d9d, 0x001c9e9d, 0x001c9e9e, 0x001c9f9e, 0x001c9f9f, 0x001ca09f, 0x001ca0a0, 0x001ca1a0, 0x001ca1a1, 0x001ca2a1, 0x001ca2a2, 0x001ca3a2, 0x001ca3a3, 0x001ca4a3, 0x001ca4a4, 0x001ca5a4, 0x001ca5a5, 0x001ca6a5, 0x001ca6a6, 0x001ca7a6, 0x001ca7a7, 0x001ca8a7, 0x001ca8a8, 0x001ca9a8, 0x001ca9a9, 0x001caaa9, 0x001caaaa, 0x001cabaa, 0x001cabab, 0x001cacab, 0x001cacac, 0x001cadac, 0x001cadad, 0x001caead, 0x001caeae, 0x001cafae, 0x001cafaf, 0x001cb0af, 0x001cb0b0, 0x001cb1b0, 0x001cb1b1, 0x001cb2b1, 0x001cb2b2, 0x001d5a59, 0x001e7877, 0x001f6d6c, 0x0020b3b2, 0x0021b2b1, 0x0022a5a4, 0x0023b4b3, 0x00248685, 0x00254847], + values: [0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000007, 0x00000005, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000000], + maximum: 0x00254847 }; pub global CAPTURE_1_MAX_LENGTH: u32 = 64; @@ -67,21 +19,21 @@ pub global NUM_CAPTURE_GROUPS: u32 = 1; * @dev start states are hardcoded in this function - "(start_state - {state})" for each start * example: `(start_state - 0) * (start_state - 1) * (start_state - 2)` means 0, 1, or 2 * are valid first states - * + * * @param start_state - The start state of the NFA */ fn check_start_state(start_state: Field) { let valid_start_state = (start_state - 0) * (start_state - 1); assert(valid_start_state == 0, "Invalid start state"); } - + /** * Constrains the recognition of accept_state being reached. If an aceppt state is reached, * ensures asserted traversal path is valid * @dev accept states are hardcoded in this function - "(next_state - {state})" for each accept * example: `(next_state - 19) * (next_state - 20) * (next_state - 21)` means 19, 20, or 21 * are valid accept states - * + * * @param next_state - The asserted next state of the NFA * @param haystack_index - The index being operated on in the haystack * @param asserted_match_length - The asserted traversal path length @@ -89,8 +41,8 @@ fn check_start_state(start_state: Field) { */ fn check_accept_state( next_state: Field, - haystack_index: Field, - asserted_match_length: Field, + haystack_index: Field, + asserted_match_length: Field ) -> Field { // check if the next state is an accept state let accept_state_reached = (next_state - 36); @@ -126,12 +78,11 @@ pub fn regex_match( capture_group_1_start: [Field; MAX_MATCH_LEN], capture_group_start_indices: [Field; NUM_CAPTURE_GROUPS], ) -> (BoundedVec) { - // resize haystack - let haystack: [u8; MAX_MATCH_LEN] = - select_subarray::(in_haystack, match_start, match_length); + // resize haystack + let haystack: [u8; MAX_MATCH_LEN] = select_subarray::(in_haystack, match_start, match_length); check_start_state(current_states[0]); - for i in 0..MAX_MATCH_LEN - 1 { + for i in 0..MAX_MATCH_LEN-1 { // match length - 1 since current states should be 1 less than next states let in_range = (i < match_length - 1) as Field; let matching_states = current_states[i + 1] - next_states[i]; @@ -148,20 +99,20 @@ pub fn regex_match( next_states[i], active_capture_groups_at_index, active_capture_groups_starts_at_index, - reached_end_state, + reached_end_state ); - reached_end_state = reached_end_state - * check_accept_state(next_states[i], i as Field, match_length as Field); + reached_end_state = reached_end_state * check_accept_state(next_states[i], i as Field, match_length as Field); } assert(reached_end_state == 0, "Did not reach a valid end state"); // Capture Group 1 let capture_1 = capture_substring::( - haystack, - capture_group_1_id, - capture_group_1_start, - capture_group_start_indices[0], + haystack, + capture_group_1_id, + capture_group_1_start, + capture_group_start_indices[0] ); (capture_1) } + From 3c2f413aef7c297c62a81b343496158bcf6deee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bence=20H=C3=A1romi?= <56651250+benceharomi@users.noreply.github.com> Date: Fri, 20 Feb 2026 18:51:18 +0000 Subject: [PATCH 09/11] test: unsupported key --- .../LinkEmailEntrypoint/LinkEmailEntrypoint.t.sol | 8 ++++++++ .../LinkHandleEntrypoint/LinkHandleEntrypoint.t.sol | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/test/src/entrypoints/LinkEmailEntrypoint/LinkEmailEntrypoint.t.sol b/test/src/entrypoints/LinkEmailEntrypoint/LinkEmailEntrypoint.t.sol index 676fdc6..eac78e3 100644 --- a/test/src/entrypoints/LinkEmailEntrypoint/LinkEmailEntrypoint.t.sol +++ b/test/src/entrypoints/LinkEmailEntrypoint/LinkEmailEntrypoint.t.sol @@ -8,6 +8,7 @@ import { Groth16Verifier } from "../../../fixtures/Groth16Verifier.sol"; import { EnsUtils } from "../../../../src/utils/EnsUtils.sol"; import { LinkEmailEntrypointHelper } from "./_LinkEmailEntrypointHelper.sol"; import { LinkTextRecordEntrypoint } from "../../../../src/entrypoints/LinkTextRecordEntrypoint.sol"; +import { ITextRecordVerifier } from "../../../../src/interfaces/ITextRecordVerifier.sol"; import { IDKIMRegistry } from "@zk-email/contracts/interfaces/IERC7969.sol"; contract LinkEmailEntrypointTest is Test { @@ -50,6 +51,13 @@ contract LinkEmailEntrypointTest is Test { linkEmail.entrypoint(encodedCommand); } + function test_verifyTextRecord_revertsWhenKeyIsUnsupported() public { + (LinkEmailCommand memory command,) = TestFixtures.linkEmailCommand(); + bytes32 node = bytes(command.textRecord.ensName).namehash(); + vm.expectRevert(abi.encodeWithSelector(ITextRecordVerifier.UnsupportedKey.selector)); + linkEmail.verifyTextRecord(node, "com.twitter", command.textRecord.value); + } + function test_verifyTextRecord_returnsTrueWhenTextRecordIsCorrect() public { (LinkEmailCommand memory command, bytes32[] memory expectedPublicInputs) = TestFixtures.linkEmailCommand(); bytes memory encodedCommand = linkEmail.encode(command.emailAuthProof.proof, expectedPublicInputs); diff --git a/test/src/entrypoints/LinkHandleEntrypoint/LinkHandleEntrypoint.t.sol b/test/src/entrypoints/LinkHandleEntrypoint/LinkHandleEntrypoint.t.sol index 64cc81c..31a7328 100644 --- a/test/src/entrypoints/LinkHandleEntrypoint/LinkHandleEntrypoint.t.sol +++ b/test/src/entrypoints/LinkHandleEntrypoint/LinkHandleEntrypoint.t.sol @@ -8,6 +8,7 @@ import { HonkVerifier } from "../../../fixtures/linkHandleCommand/twitter/target import { EnsUtils } from "../../../../src/utils/EnsUtils.sol"; import { LinkHandleEntrypointHelper } from "./_LinkHandleEntrypointHelper.sol"; import { LinkTextRecordEntrypoint } from "../../../../src/entrypoints/LinkTextRecordEntrypoint.sol"; +import { ITextRecordVerifier } from "../../../../src/interfaces/ITextRecordVerifier.sol"; import { LinkHandleCommandTestFixture } from "../../../fixtures/linkHandleCommand/LinkHandleCommandTestFixture.sol"; import { IDKIMRegistry } from "@zk-email/contracts/interfaces/IERC7969.sol"; @@ -67,6 +68,13 @@ contract LinkHandleVerifierTest is Test { discordEntrypoint.entrypoint(encodedCommand); } + function test_verifyTextRecord_revertsWhenKeyIsUnsupported() public { + (LinkHandleCommand memory command,) = LinkHandleCommandTestFixture.getTwitterFixture(); + bytes32 node = bytes(command.textRecord.ensName).namehash(); + vm.expectRevert(abi.encodeWithSelector(ITextRecordVerifier.UnsupportedKey.selector)); + linkHandle.verifyTextRecord(node, "com.discord", command.textRecord.value); + } + function test_verifyTextRecord_returnsFalseWhenTextRecordIsIncorrect() public { (LinkHandleCommand memory command, bytes32[] memory expectedPublicInputs) = LinkHandleCommandTestFixture.getTwitterFixture(); From 82bb3584b6a6f3cab36555b4bd5af0d680ad0dfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bence=20H=C3=A1romi?= <56651250+benceharomi@users.noreply.github.com> Date: Fri, 20 Feb 2026 18:35:38 +0000 Subject: [PATCH 10/11] chore: fixture compile script fix --- test/fixtures/linkHandleCommand/compile.sh | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/test/fixtures/linkHandleCommand/compile.sh b/test/fixtures/linkHandleCommand/compile.sh index 1d99c3c..e41a86a 100755 --- a/test/fixtures/linkHandleCommand/compile.sh +++ b/test/fixtures/linkHandleCommand/compile.sh @@ -42,31 +42,34 @@ log "=== Compiling $CIRCUIT_NAME noir circuit (platform: $PLATFORM) ===" log "Step 0: Checking Noir and BB versions" if [ "$(nargo --version | grep "nargo version = $NARGO_VERSION")" != "nargo version = $NARGO_VERSION" ]; then log "Noir version is not $NARGO_VERSION, running noirup --version $NARGO_VERSION" - noirup --version $NARGO_VERSION >> "$LOG_FILE" 2>&1 + if ! noirup --version $NARGO_VERSION >> "$LOG_FILE" 2>&1; then + log "Failed to run noirup --version $NARGO_VERSION" + exit 1 + fi fi if [ "$(bb --version)" != "v$BB_VERSION" ]; then log "BB version is not $BB_VERSION, running bbup --version $BB_VERSION" - bbup --version $BB_VERSION >> "$LOG_FILE" 2>&1 + if ! bbup --version $BB_VERSION >> "$LOG_FILE" 2>&1; then + log "Failed to run bbup --version $BB_VERSION" + exit 1 + fi fi log "Step 1: Compiling circuit" -nargo compile >> "$LOG_FILE" 2>&1 -if [ $? -ne 0 ]; then +if ! nargo compile >> "$LOG_FILE" 2>&1; then log "Failed to compile circuit" exit 1 fi log "Step 2: Writing VK" -bb write_vk --bytecode_path ./target/$CIRCUIT_NAME.json --output_path ./target --oracle_hash keccak >> "$LOG_FILE" 2>&1 -if [ $? -ne 0 ]; then +if ! bb write_vk --bytecode_path ./target/$CIRCUIT_NAME.json --output_path ./target --oracle_hash keccak >> "$LOG_FILE" 2>&1; then log "Failed to write VK" exit 1 fi log "Step 3: Writing Solidity verifier" -bb write_solidity_verifier --vk_path ./target/vk --output_path ./target/HonkVerifier.sol >> "$LOG_FILE" 2>&1 -if [ $? -ne 0 ]; then +if ! bb write_solidity_verifier --vk_path ./target/vk --output_path ./target/HonkVerifier.sol >> "$LOG_FILE" 2>&1; then log "Failed to write Solidity verifier" exit 1 fi From 53db751936b86a9fdaff86bf04b2a85f730ae744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bence=20H=C3=A1romi?= <56651250+benceharomi@users.noreply.github.com> Date: Thu, 19 Feb 2026 14:56:28 +0000 Subject: [PATCH 11/11] chore: added sepolia rpc to foundry.toml --- .env.example | 2 +- foundry.toml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 03d2803..acb6697 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,3 @@ PRIVATE_KEY= ETHERSCAN_API_KEY= -SEPOLIA_URL= \ No newline at end of file +SEPOLIA_RPC_URL= diff --git a/foundry.toml b/foundry.toml index b716d88..7cebaba 100644 --- a/foundry.toml +++ b/foundry.toml @@ -13,6 +13,9 @@ evm_version = "prague" ignored_warnings_from = ["node_modules"] fs_permissions = [{ access = "read", path = "./test/fixtures" }] +[rpc_endpoints] +sepolia = "${SEPOLIA_RPC_URL}" + [profile.ci] verbosity = 4