From ad0f6ebaa6ae88cfb98d19d517f41554f5537854 Mon Sep 17 00:00:00 2001 From: josh crites Date: Mon, 5 Feb 2024 09:42:09 -0500 Subject: [PATCH 1/6] Update package.json --- foundry-voting/package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/foundry-voting/package.json b/foundry-voting/package.json index c475efd..a721bdc 100644 --- a/foundry-voting/package.json +++ b/foundry-voting/package.json @@ -18,14 +18,13 @@ "@aztec/bb.js": "0.3.6", "@iarna/toml": "^2.2.5", "@noir-lang/acvm_js": "git+https://github.com/noir-lang/acvm-simulator-wasm.git", - "@types/mocha": "^10.0.1", "fflate": "^0.8.0", "toml": "^3.0.0" }, "devDependencies": { "@typechain/ethers-v5": "^10.0.0", "@types/chai": "^4.3.0", - "@types/mocha": "^9.1.0", + "@types/mocha": "^10.0.1", "@types/node": "^17.0.35", "chai": "^4.3.6", "ethers": "^5.7.2", From 7a7687355526a7d73b14034a5b09a70334070520 Mon Sep 17 00:00:00 2001 From: josh crites Date: Mon, 5 Feb 2024 10:20:47 -0500 Subject: [PATCH 2/6] Update Nargo.toml --- foundry-voting/circuits/Nargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/foundry-voting/circuits/Nargo.toml b/foundry-voting/circuits/Nargo.toml index 62313e1..409c746 100644 --- a/foundry-voting/circuits/Nargo.toml +++ b/foundry-voting/circuits/Nargo.toml @@ -1,7 +1,7 @@ [package] authors = [""] -compiler_version = "~0.10.3" +compiler_version = ">=0.22.0" name="foundry_voting" type="bin" -[dependencies] \ No newline at end of file +[dependencies] From 3e1b01d78db16bc33cbf9c1d5f7881e8be69c191 Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Mon, 5 Feb 2024 10:35:28 -0500 Subject: [PATCH 3/6] update to 0.22 --- foundry-voting/circuits/Prover.toml | 6 +- foundry-voting/circuits/Verifier.toml | 4 +- .../contract/foundry_voting/plonk_vk.sol | 266 ++++++++++-------- .../circuits/proofs/foundry_voting.proof | 2 +- foundry-voting/circuits/src/main.nr | 88 +++--- 5 files changed, 200 insertions(+), 166 deletions(-) diff --git a/foundry-voting/circuits/Prover.toml b/foundry-voting/circuits/Prover.toml index 21207f6..4d48e9c 100644 --- a/foundry-voting/circuits/Prover.toml +++ b/foundry-voting/circuits/Prover.toml @@ -1,9 +1,9 @@ hash_path = [ - "0x2d961d9814298c04a4639a56c5c95030d704340ab6d13c135a326da5e515559d", - "0x1501e80783ee5c988327f46f5fcdce388cb97aa7e959ad345c1e2cbaa0b42b83" + "0x1efa9d6bb4dfdf86063cc77efdec90eb9262079230f1898049efad264835b6c8", + "0x2a653551d87767c545a2a11b29f0581a392b4e177a87c8e3eb425c51a26a8c77" ] index = "0" proposalId = "0" -root = "0x29fd5ee89e33f559a7b32ac39f57400aa5a6c77492e28c088f9eb511b0c73e78" +root = "0x215597bacd9c7e977dfc170f320074155de974be494579d2586e5b268fa3b629" secret = "1" vote = "1" \ No newline at end of file diff --git a/foundry-voting/circuits/Verifier.toml b/foundry-voting/circuits/Verifier.toml index 70e9dc8..b595728 100644 --- a/foundry-voting/circuits/Verifier.toml +++ b/foundry-voting/circuits/Verifier.toml @@ -1,4 +1,4 @@ proposalId = "0x0000000000000000000000000000000000000000000000000000000000000000" -return = "0x1cbb284a43dde14da2c3790e12872bcb7e53c53e27b5187384c617841174ace5" -root = "0x29fd5ee89e33f559a7b32ac39f57400aa5a6c77492e28c088f9eb511b0c73e78" +return = "0x079d88735cdd786b64a950b1cd887ae89308e3b4176ef4adb308267888fe1f91" +root = "0x215597bacd9c7e977dfc170f320074155de974be494579d2586e5b268fa3b629" vote = "0x0000000000000000000000000000000000000000000000000000000000000001" diff --git a/foundry-voting/circuits/contract/foundry_voting/plonk_vk.sol b/foundry-voting/circuits/contract/foundry_voting/plonk_vk.sol index f28f5b6..56f64e1 100644 --- a/foundry-voting/circuits/contract/foundry_voting/plonk_vk.sol +++ b/foundry-voting/circuits/contract/foundry_voting/plonk_vk.sol @@ -1,76 +1,75 @@ -// Verification Key Hash: 2c4ede1e99f014ab0b99ce60d152b569e56f26bb83cf0e03230b3afeebf390ad +// Verification Key Hash: 3cf4e7181c5ed77337e3e15850edaf6a635b9649788c010c9d0b2ba854ad10f2 // SPDX-License-Identifier: Apache-2.0 // Copyright 2022 Aztec pragma solidity >=0.8.4; library UltraVerificationKey { function verificationKeyHash() internal pure returns(bytes32) { - return 0x2c4ede1e99f014ab0b99ce60d152b569e56f26bb83cf0e03230b3afeebf390ad; + return 0x3cf4e7181c5ed77337e3e15850edaf6a635b9649788c010c9d0b2ba854ad10f2; } function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure { assembly { - mstore(add(_vk, 0x00), 0x0000000000000000000000000000000000000000000000000000000000004000) // vk.circuit_size + mstore(add(_vk, 0x00), 0x0000000000000000000000000000000000000000000000000000000000008000) // vk.circuit_size mstore(add(_vk, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000004) // vk.num_inputs - mstore(add(_vk, 0x40), 0x2d965651cdd9e4811f4e51b80ddca8a8b4a93ee17420aae6adaa01c2617c6e85) // vk.work_root - mstore(add(_vk, 0x60), 0x30638ce1a7661b6337a964756aa75257c6bf4778d89789ab819ce60c19b04001) // vk.domain_inverse - mstore(add(_vk, 0x80), 0x21900729f438840cbcc2a40c1e6358e5c96838d7c92ad66a7b6e8840f0254872) // vk.Q1.x - mstore(add(_vk, 0xa0), 0x262b78c1faf8549b23a7daa9993605a014daf0223dc98874d62b9f26b4b2fd41) // vk.Q1.y - mstore(add(_vk, 0xc0), 0x01065a45c6332110f42df30bfacdfe6ba5b21c31627a1cb1b04867852fba7cc4) // vk.Q2.x - mstore(add(_vk, 0xe0), 0x04d7567b3796fd81b9089e644e49bceeb5da86707c84264f8c60147ffc459e6b) // vk.Q2.y - mstore(add(_vk, 0x100), 0x09ecb29e830b035f8b6e705534503de8b7636be94d92eff06c1747d34e939dc8) // vk.Q3.x - mstore(add(_vk, 0x120), 0x00ed3594e82a29d1a087a818bf8781699472e16c610e8f4d1874d4bd3b13cf07) // vk.Q3.y - mstore(add(_vk, 0x140), 0x162099cf128d88a12c8e833bde847fe7c8b6adfee57bfb1f349f285ce29dd874) // vk.Q4.x - mstore(add(_vk, 0x160), 0x0412ac7371df5001639ab0b221da0725a84ca7ae156d931214e872ebc08a4912) // vk.Q4.y - mstore(add(_vk, 0x180), 0x2dac905f15d39b15765a17d87e58d7f3b7dfc8ea9d3b4f50f48411d8294af6bb) // vk.Q_M.x - mstore(add(_vk, 0x1a0), 0x1434ec11741a383e9fb99c7d282b026718bd2cd6303989f543cc92b46221c844) // vk.Q_M.y - mstore(add(_vk, 0x1c0), 0x2977a33414f89bfeabfdc37b604af6f506f58495e15bab3a714bf71d99e9fc18) // vk.Q_C.x - mstore(add(_vk, 0x1e0), 0x1847437dd7d64919411dcbf5b7cd8174bf2bff22f4c36b8e4d313640ee8cd79b) // vk.Q_C.y - mstore(add(_vk, 0x200), 0x18168832b954a473d4e89d433c813393732a896e0d201313e81c88570a852191) // vk.Q_ARITHMETIC.x - mstore(add(_vk, 0x220), 0x0e95d18cce6011bb0993d43d0b965a8d2008f571f66c0dd6e4dbb60d6c230a33) // vk.Q_ARITHMETIC.y - mstore(add(_vk, 0x240), 0x0cf353ade5a9cb3b0a6123e04e0b024a0cf9a6466c6f303bdbaf5037baf3dc4a) // vk.QSORT.x - mstore(add(_vk, 0x260), 0x04e2f918f9f03b268720821844cf5e5c697479d0cbfb75cd392b7dc813c7306f) // vk.QSORT.y - mstore(add(_vk, 0x280), 0x0a6fbcd9fccad81710817b144e49632e167aeefcc4fee8dcfa93845cefb48b34) // vk.Q_ELLIPTIC.x - mstore(add(_vk, 0x2a0), 0x1a487fff19e1915706837aa9e5a0f18251c957550e92cbfd25f129e3d60f9735) // vk.Q_ELLIPTIC.y - mstore(add(_vk, 0x2c0), 0x2c4c5b5ebd83d5248c92a7ef9552c3b45bcd805ed7c28e911beb9634f3ee5843) // vk.Q_AUX.x - mstore(add(_vk, 0x2e0), 0x1c3e8854a1e23d7f9d2e76f71b85de046c50622c7c3346787f392f89d5c29526) // vk.Q_AUX.y - mstore(add(_vk, 0x300), 0x288de316edef81b6ae58f2640125d8bdc493bd543e5bbf1b37560b93c8b60b92) // vk.SIGMA1.x - mstore(add(_vk, 0x320), 0x2157b2862ef9b23dd35c4fef7ebe5358bd97eed21c9246994787a346fb3e0ff5) // vk.SIGMA1.y - mstore(add(_vk, 0x340), 0x2a4c6c8100b2b7c1977b7f4c072099c5a5d6f83544a07fc9c8b9edc8d93c26a4) // vk.SIGMA2.x - mstore(add(_vk, 0x360), 0x004fa4e51aae2e2a09fbc7704d8196ab426072fb0c935e8c217e261571a5cafd) // vk.SIGMA2.y - mstore(add(_vk, 0x380), 0x2f97e44dab538180a322866964852f455cdd2631345fa1d7aff2e734641c8db7) // vk.SIGMA3.x - mstore(add(_vk, 0x3a0), 0x01bc5d8736fa1bbd63b780c3f8902d24aa16b9d886fe60c969b6bd2fc03b7594) // vk.SIGMA3.y - mstore(add(_vk, 0x3c0), 0x0aa6c363b625c7b972eb7123084063ad5b1e0573ef16587a2a932fa00223298c) // vk.SIGMA4.x - mstore(add(_vk, 0x3e0), 0x0729bd5e4f33388b2dbafe1657bca0b3cfd86ce3e3be24beefe7e7814f69986e) // vk.SIGMA4.y - mstore(add(_vk, 0x400), 0x1967204ca4d4bcda212da5d8c3d167670fa8eb4f194821e2b58d4e903fdaf697) // vk.TABLE1.x - mstore(add(_vk, 0x420), 0x2c2c5f454b384ceab390e24e72e967cb05eead9e45a234b182ca96303adf9004) // vk.TABLE1.y - mstore(add(_vk, 0x440), 0x23214c84f0e5004bb8d81b18355e527236e4c790e60c7d063cd23b92cf311bd6) // vk.TABLE2.x - mstore(add(_vk, 0x460), 0x026c55d9eedfcc68a83a8737f779fe416ad83fc595ed94a8bfc579527280b6f0) // vk.TABLE2.y - mstore(add(_vk, 0x480), 0x1c3be535e593cc38213855a5a3e1f41c56d2abb2e8e7c7379247c0d53a9b6311) // vk.TABLE3.x - mstore(add(_vk, 0x4a0), 0x2de768e6c0360d2e8ef2ee405cf1f4c5b0fa47a0942f0ffa078832bc563d6db5) // vk.TABLE3.y - mstore(add(_vk, 0x4c0), 0x195d9df89ed03300614b539f468481451efc9869ad8ca7c921ff209ca4431715) // vk.TABLE4.x - mstore(add(_vk, 0x4e0), 0x2b74a335fb3df4112ca1c451f833a83fe65b7ba143da8ae5223071926da2efce) // vk.TABLE4.y - mstore(add(_vk, 0x500), 0x268c1bf7a1975733cce8479a95caa4eb11784d7e7e87f0715024973639900251) // vk.TABLE_TYPE.x - mstore(add(_vk, 0x520), 0x092fc6fee4bb5c077f6455de7bbaa30f73c1b1cc4d882df6ae3d3dfefccf3771) // vk.TABLE_TYPE.y - mstore(add(_vk, 0x540), 0x00b51fef15752cc3abf241d4278293100d2f38860a4fb6b25685327336bdbf55) // vk.ID1.x - mstore(add(_vk, 0x560), 0x0e91cbcd71a6b164e4c73107b645d945b9cbc0b7838a57c3447a30339449ca5e) // vk.ID1.y - mstore(add(_vk, 0x580), 0x134ac049c18e993522dec09a74adf35735709cd8a58afa56174c80c35ce2eb5a) // vk.ID2.x - mstore(add(_vk, 0x5a0), 0x18e1b12624ab279cd42d7465be77623fc69b167338f7e4d360d2f9cccb5e03d2) // vk.ID2.y - mstore(add(_vk, 0x5c0), 0x0effd5130013083482d9830e83c42a610cd5bca9f14f659f0cfd1a4d78b443a4) // vk.ID3.x - mstore(add(_vk, 0x5e0), 0x1b3e6f67cf7991683d352ef03967bd9f4675a3e2cdd82f4cbafb5096f6b590af) // vk.ID3.y - mstore(add(_vk, 0x600), 0x19ced062a3fdc3d9d6e1607349f98323efdbdbc3477c54726c01ed95da8a04be) // vk.ID4.x - mstore(add(_vk, 0x620), 0x08f330a8bf7a25999018dc63974bd27d1fd20e180e6e6868ffa951bb8efe40ba) // vk.ID4.y + mstore(add(_vk, 0x40), 0x2d1ba66f5941dc91017171fa69ec2bd0022a2a2d4115a009a93458fd4e26ecfb) // vk.work_root + mstore(add(_vk, 0x60), 0x3063edaa444bddc677fcd515f614555a777997e0a9287d1e62bf6dd004d82001) // vk.domain_inverse + mstore(add(_vk, 0x80), 0x16f643c5e2a0c578e81d747be575fbf9b91732e3be6e753b694dd2ed5471e7fb) // vk.Q1.x + mstore(add(_vk, 0xa0), 0x1d8fb151c68ae5e8f7ee117623cc1c61b6c8c9947709a94c799ab056e8310209) // vk.Q1.y + mstore(add(_vk, 0xc0), 0x0bcb8ac908e3b4a08c8f5e78a35304952d69bc90aef22f763920bd42f33c00c8) // vk.Q2.x + mstore(add(_vk, 0xe0), 0x21e0744ed22f59201721e921180ac96657261cd33bf329cae83c9eac3cda84d6) // vk.Q2.y + mstore(add(_vk, 0x100), 0x0e51b6323bf93ddb10b13b5758d218d9442b6efc2a788cf40215b92884b761d4) // vk.Q3.x + mstore(add(_vk, 0x120), 0x147196a7dd55ba53cc1603091071b291f72b50bb5cd036f8a083b4c8615ee3f0) // vk.Q3.y + mstore(add(_vk, 0x140), 0x1ba99524ff055c629564114238516180f5f43b5f5eaa3d11adabb01e5a65b6c9) // vk.Q4.x + mstore(add(_vk, 0x160), 0x20694e7d9e25acd5718ac314d387e957c39bb7359fa7a7f3b3d6174cccb9fb3c) // vk.Q4.y + mstore(add(_vk, 0x180), 0x1186c2efb2bd64cdca3bef1584dc7a05256de2b6895e903903a44a0418075054) // vk.Q_M.x + mstore(add(_vk, 0x1a0), 0x27d7e5008b484a1398258b2ae92d1bc11fa527836ebf131854cce0b82c0866f8) // vk.Q_M.y + mstore(add(_vk, 0x1c0), 0x1b60fa4003663d324e4edbe79b499ed0d46e1a62b61f5dcb707304a26a74995d) // vk.Q_C.x + mstore(add(_vk, 0x1e0), 0x06dcc8743d5c44abdeb447fad451205e8b2e1e04ec434c4bef3ba6d558ee9fdd) // vk.Q_C.y + mstore(add(_vk, 0x200), 0x096d3d7fce6ea24ea0a82145380ddb0f3b06cb4deee91c7468a1c2722000c6e3) // vk.Q_ARITHMETIC.x + mstore(add(_vk, 0x220), 0x2ab594dae595e5df7071bd3b76c22f3ef03fa9f9e271283d28fd4ba86acf5314) // vk.Q_ARITHMETIC.y + mstore(add(_vk, 0x240), 0x088157fe7915970a3667db252a333660a4f28895efcaa2b4e91a1b00dc74616e) // vk.QSORT.x + mstore(add(_vk, 0x260), 0x2a9af15b7ebc36fb4ea2ccf4a8a5465c963cfae2727bb76e725ac3fa67b49817) // vk.QSORT.y + mstore(add(_vk, 0x280), 0x050541309eb13db9c19d8331540f07a867cecc5764c7fed772f4c962a8585931) // vk.Q_ELLIPTIC.x + mstore(add(_vk, 0x2a0), 0x0823785abd1759e0fef5971a0aa16c6d161c340b961cad588ad8d4eeb122dad0) // vk.Q_ELLIPTIC.y + mstore(add(_vk, 0x2c0), 0x16262200e3a244db5f8c2449af13644215b799d556ba8208d8bca9b6662d71d4) // vk.Q_AUX.x + mstore(add(_vk, 0x2e0), 0x2fff50d724a01bb83cef80b7049fbe01be798df1569718d9d22a2823782644d8) // vk.Q_AUX.y + mstore(add(_vk, 0x300), 0x0f6bba913dc4e6eaa8dbf357baf71cbee107140b8008f232c3380d1a23f5857b) // vk.SIGMA1.x + mstore(add(_vk, 0x320), 0x1de071957bb2c9ddbe39956df09c45ee6bfc5cb4c63d201c7f924f37768f2b97) // vk.SIGMA1.y + mstore(add(_vk, 0x340), 0x2be2c9a2d194b00c4a5324f76e0251c3d33ae02fd12ec2dac5c3b51ebf23079f) // vk.SIGMA2.x + mstore(add(_vk, 0x360), 0x27f6a191d1bd457864ec3ac30ac37d0d3fe86eaff730ab90c868bea99912084b) // vk.SIGMA2.y + mstore(add(_vk, 0x380), 0x10e5fb310ce836d792f0c8d70fd8bc40a4bdf347886cd8abf7050eb51a26a3ba) // vk.SIGMA3.x + mstore(add(_vk, 0x3a0), 0x24aad54275c9cba0d33e809157b42871d7fd5a6e52137b8888cc7e7fd316295d) // vk.SIGMA3.y + mstore(add(_vk, 0x3c0), 0x229772481efe74fba701e06dd3aee2087c022961fddd0c7bc678fb457890ef48) // vk.SIGMA4.x + mstore(add(_vk, 0x3e0), 0x2ea21e10c30eb6656650436e5d20d84cd3a2d1e1a34d997d4546ca65dc5c9c03) // vk.SIGMA4.y + mstore(add(_vk, 0x400), 0x14fa3d2f7838cd2b628013fbcc4a5964f90f86fee3c44f90f15b66cbb883b16d) // vk.TABLE1.x + mstore(add(_vk, 0x420), 0x087cff60b464aea188316044a5bdd7ad11e09061a6bbb1538a16ea2043d818bb) // vk.TABLE1.y + mstore(add(_vk, 0x440), 0x0edc0845445f3a9214ca8c4ce8bfd53897d91e27fc085631d7fb2a1225d3c40e) // vk.TABLE2.x + mstore(add(_vk, 0x460), 0x30521fd3f90d6823143b31aa19fdb95c3622a2ebcfe40878a9b926f9bb595870) // vk.TABLE2.y + mstore(add(_vk, 0x480), 0x030ac1cc92a28b967df7160de3f4bb3d18ea9b4e815b5c595a4cb7cae56db7c6) // vk.TABLE3.x + mstore(add(_vk, 0x4a0), 0x2465a7e5d40cdae7124e40609f69a02cdbae4b8de36519517a574e2a2c8201fd) // vk.TABLE3.y + mstore(add(_vk, 0x4c0), 0x0d3a5fd296b6cb7657205032d326c1126531247361cfb572fe626cdbc274fe6a) // vk.TABLE4.x + mstore(add(_vk, 0x4e0), 0x2c76ae3fdcd620f284426dc5c68ba0a2c4b08dda0c3a6ccb925a93efdc34eeff) // vk.TABLE4.y + mstore(add(_vk, 0x500), 0x037860d2d867bc0aedfb78139023ece5960992e852efa09b9fcba326653b9802) // vk.TABLE_TYPE.x + mstore(add(_vk, 0x520), 0x0c763504923d3d79db875de9e151b0add2efa2a7e00c8f88883824d3d0a4c080) // vk.TABLE_TYPE.y + mstore(add(_vk, 0x540), 0x171a06b1badd06125fb2f0f52bc8f653daab775de9b28669860ee5d0b0f62a0d) // vk.ID1.x + mstore(add(_vk, 0x560), 0x305877be31389f2e8a184dc3a0f8f1ce2d7627542e116c50d6a48291128c4bfd) // vk.ID1.y + mstore(add(_vk, 0x580), 0x263941e5944250e4481ca3e34e090cafefdaf93477c219974586936f9ca26f85) // vk.ID2.x + mstore(add(_vk, 0x5a0), 0x161e8bf5d2e01c6f1b2fbdc9a726beba044e1d185bfc4dee0301130d2d31dbdf) // vk.ID2.y + mstore(add(_vk, 0x5c0), 0x1eae95b0f2389ee3ae9dc172bfbd362a0eb3ea9e02bdc51b989d11ad1464ac60) // vk.ID3.x + mstore(add(_vk, 0x5e0), 0x155b2dda9d3e893e55fd87d49436d4fb938b754ae01545e18cc50f8a32e35bba) // vk.ID3.y + mstore(add(_vk, 0x600), 0x0cdb06569071e31209599397bdc7a822fca496741ce24dfdf751bf44425e8e11) // vk.ID4.x + mstore(add(_vk, 0x620), 0x228b6aee9124d7b8e657108584f7fa88fc43bcdb05fb3ec309eb3aa265a54468) // vk.ID4.y mstore(add(_vk, 0x640), 0x00) // vk.contains_recursive_proof mstore(add(_vk, 0x660), 0) // vk.recursive_proof_public_input_indices mstore(add(_vk, 0x680), 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1) // vk.g2_x.X.c1 mstore(add(_vk, 0x6a0), 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0) // vk.g2_x.X.c0 mstore(add(_vk, 0x6c0), 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4) // vk.g2_x.Y.c1 mstore(add(_vk, 0x6e0), 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55) // vk.g2_x.Y.c0 - mstore(_omegaInverseLoc, 0x281c036f06e7e9e911680d42558e6e8cf40976b0677771c0f8eee934641c8410) // vk.work_root_inverse + mstore(_omegaInverseLoc, 0x05d33766e4590b3722701b6f2fa43d0dc3f028424d384e68c92a742fb2dbc0b4) // vk.work_root_inverse } } } - /** * @title Ultra Plonk proof verification contract * @dev Top level Plonk proof verification contract, which allows Plonk proof to be verified @@ -354,6 +353,9 @@ abstract contract BaseUltraVerifier { uint256 internal constant LIMB_SIZE = 0x100000000000000000; // 2<<68 uint256 internal constant SUBLIMB_SHIFT = 0x4000; // 2<<14 + // y^2 = x^3 + ax + b + // for Grumpkin, a = 0 and b = -17. We use b in a custom gate relation that evaluates elliptic curve arithmetic + uint256 internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = 17; error PUBLIC_INPUT_COUNT_INVALID(uint256 expected, uint256 actual); error PUBLIC_INPUT_INVALID_BN128_G1_POINT(); error PUBLIC_INPUT_GE_P(); @@ -1226,96 +1228,130 @@ abstract contract BaseUltraVerifier { * sign_term += sign_term * sign_term *= q_sign */ + // q_elliptic * (x3 + x2 + x1)(x2 - x1)(x2 - x1) - y2^2 - y1^2 + 2(y2y1)*q_sign = 0 + let x_diff := addmod(mload(X2_EVAL_LOC), sub(p, mload(X1_EVAL_LOC)), p) + let y2_sqr := mulmod(mload(Y2_EVAL_LOC), mload(Y2_EVAL_LOC), p) + let y1_sqr := mulmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p) + let y1y2 := mulmod(mulmod(mload(Y1_EVAL_LOC), mload(Y2_EVAL_LOC), p), mload(QSIGN_LOC), p) - let endo_term := + let x_add_identity := + addmod( + mulmod( + addmod(mload(X3_EVAL_LOC), addmod(mload(X2_EVAL_LOC), mload(X1_EVAL_LOC), p), p), + mulmod(x_diff, x_diff, p), + p + ), + addmod( + sub( + p, + addmod(y2_sqr, y1_sqr, p) + ), + addmod(y1y2, y1y2, p), + p + ), + p + ) + x_add_identity := mulmod( mulmod( - mulmod(sub(p, mload(X2_EVAL_LOC)), mload(X1_EVAL_LOC), p), - addmod(addmod(mload(X3_EVAL_LOC), mload(X3_EVAL_LOC), p), mload(X1_EVAL_LOC), p), + x_add_identity, + addmod( + 1, + sub(p, mload(QM_EVAL_LOC)), + p + ), p ), - mload(QBETA_LOC), + mload(C_ALPHA_BASE_LOC), p ) - let endo_sqr_term := mulmod(mload(X2_EVAL_LOC), mload(X2_EVAL_LOC), p) - endo_sqr_term := mulmod(endo_sqr_term, addmod(mload(X3_EVAL_LOC), sub(p, mload(X1_EVAL_LOC)), p), p) - endo_sqr_term := mulmod(endo_sqr_term, mload(QBETA_SQR_LOC), p) + // q_elliptic * (x3 + x2 + x1)(x2 - x1)(x2 - x1) - y2^2 - y1^2 + 2(y2y1)*q_sign = 0 + let y1_plus_y3 := addmod( + mload(Y1_EVAL_LOC), + mload(Y3_EVAL_LOC), + p + ) + let y_diff := addmod(mulmod(mload(Y2_EVAL_LOC), mload(QSIGN_LOC), p), sub(p, mload(Y1_EVAL_LOC)), p) + let y_add_identity := + addmod( + mulmod(y1_plus_y3, x_diff, p), + mulmod(addmod(mload(X3_EVAL_LOC), sub(p, mload(X1_EVAL_LOC)), p), y_diff, p), + p + ) + y_add_identity := + mulmod( + mulmod(y_add_identity, addmod(1, sub(p, mload(QM_EVAL_LOC)), p), p), + mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p), + p + ) - let leftovers := mulmod(mload(X2_EVAL_LOC), mload(X2_EVAL_LOC), p) - leftovers := mulmod(leftovers, mload(X2_EVAL_LOC), p) - leftovers := + // ELLIPTIC_IDENTITY = (x_identity + y_identity) * Q_ELLIPTIC_EVAL + mstore( + ELLIPTIC_IDENTITY, mulmod(addmod(x_add_identity, y_add_identity, p), mload(QELLIPTIC_EVAL_LOC), p) + ) + } + { + /** + * x_pow_4 = (y_1_sqr - curve_b) * x_1; + * y_1_sqr_mul_4 = y_1_sqr + y_1_sqr; + * y_1_sqr_mul_4 += y_1_sqr_mul_4; + * x_1_pow_4_mul_9 = x_pow_4; + * x_1_pow_4_mul_9 += x_1_pow_4_mul_9; + * x_1_pow_4_mul_9 += x_1_pow_4_mul_9; + * x_1_pow_4_mul_9 += x_1_pow_4_mul_9; + * x_1_pow_4_mul_9 += x_pow_4; + * x_1_sqr_mul_3 = x_1_sqr + x_1_sqr + x_1_sqr; + * x_double_identity = (x_3 + x_1 + x_1) * y_1_sqr_mul_4 - x_1_pow_4_mul_9; + * y_double_identity = x_1_sqr_mul_3 * (x_1 - x_3) - (y_1 + y_1) * (y_1 + y_3); + */ + // (x3 + x1 + x1) (4y1*y1) - 9 * x1 * x1 * x1 * x1 = 0 + let x1_sqr := mulmod(mload(X1_EVAL_LOC), mload(X1_EVAL_LOC), p) + let y1_sqr := mulmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p) + let x_pow_4 := mulmod(addmod(y1_sqr, GRUMPKIN_CURVE_B_PARAMETER_NEGATED, p), mload(X1_EVAL_LOC), p) + let y1_sqr_mul_4 := mulmod(y1_sqr, 4, p) + let x1_pow_4_mul_9 := mulmod(x_pow_4, 9, p) + let x1_sqr_mul_3 := mulmod(x1_sqr, 3, p) + let x_double_identity := addmod( - leftovers, mulmod( - mulmod(mload(X1_EVAL_LOC), mload(X1_EVAL_LOC), p), - addmod(mload(X3_EVAL_LOC), mload(X1_EVAL_LOC), p), + addmod(mload(X3_EVAL_LOC), addmod(mload(X1_EVAL_LOC), mload(X1_EVAL_LOC), p), p), + y1_sqr_mul_4, p ), + sub(p, x1_pow_4_mul_9), p ) - leftovers := + // (y1 + y1) (2y1) - (3 * x1 * x1)(x1 - x3) = 0 + let y_double_identity := addmod( - leftovers, + mulmod(x1_sqr_mul_3, addmod(mload(X1_EVAL_LOC), sub(p, mload(X3_EVAL_LOC)), p), p), sub( p, - addmod( - mulmod(mload(Y2_EVAL_LOC), mload(Y2_EVAL_LOC), p), - mulmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p), + mulmod( + addmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p), + addmod(mload(Y1_EVAL_LOC), mload(Y3_EVAL_LOC), p), p ) ), p ) - - let sign_term := mulmod(mload(Y2_EVAL_LOC), mload(Y1_EVAL_LOC), p) - sign_term := addmod(sign_term, sign_term, p) - sign_term := mulmod(sign_term, mload(QSIGN_LOC), p) - - /** - * x_identity = endo_term + endo_sqr_term + sign_term + leftovers - * x_identity *= alpha_base - * endo_term = (x_2 * q_beta) * (y_3 + y_1) - * sign_term = -((y2 * q_sign) * (x_1 + x_3)) - * leftovers = - x1 * (y_3 + y_1) + y_1 * (x_1 - x_3) - * y_identity = (endo_term + sign_term + leftovers) * (alpha_base * α) - */ - - let x_identity := addmod(addmod(endo_term, endo_sqr_term, p), addmod(sign_term, leftovers, p), p) - x_identity := mulmod(x_identity, mload(C_ALPHA_BASE_LOC), p) - endo_term := - mulmod( - mulmod(mload(X2_EVAL_LOC), mload(QBETA_LOC), p), - addmod(mload(Y3_EVAL_LOC), mload(Y1_EVAL_LOC), p), - p - ) - sign_term := - sub( - p, - mulmod( - mulmod(mload(Y2_EVAL_LOC), mload(QSIGN_LOC), p), - addmod(mload(X1_EVAL_LOC), sub(p, mload(X3_EVAL_LOC)), p), - p - ) - ) - leftovers := + x_double_identity := mulmod(x_double_identity, mload(C_ALPHA_BASE_LOC), p) + y_double_identity := + mulmod(y_double_identity, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p), p) + x_double_identity := mulmod(x_double_identity, mload(QM_EVAL_LOC), p) + y_double_identity := mulmod(y_double_identity, mload(QM_EVAL_LOC), p) + // ELLIPTIC_IDENTITY += (x_double_identity + y_double_identity) * Q_DOUBLE_EVAL + mstore( + ELLIPTIC_IDENTITY, addmod( - sub(p, mulmod(mload(X1_EVAL_LOC), addmod(mload(Y3_EVAL_LOC), mload(Y1_EVAL_LOC), p), p)), - mulmod(mload(Y1_EVAL_LOC), addmod(mload(X1_EVAL_LOC), sub(p, mload(X3_EVAL_LOC)), p), p), + mload(ELLIPTIC_IDENTITY), + mulmod(addmod(x_double_identity, y_double_identity, p), mload(QELLIPTIC_EVAL_LOC), p), p ) - let y_identity := - mulmod( - addmod(addmod(endo_term, sign_term, p), leftovers, p), - mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p), - p - ) - - // ELLIPTIC_IDENTITY = (x_identity + y_identity) * Q_ELLIPTIC_EVAL - mstore(ELLIPTIC_IDENTITY, mulmod(addmod(x_identity, y_identity, p), mload(QELLIPTIC_EVAL_LOC), p)) + ) // update alpha - // The paper says to use ALPHA^2, we use ALPHA^4 this is a small oversight in the prover protocol mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_QUAD_LOC), p)) } diff --git a/foundry-voting/circuits/proofs/foundry_voting.proof b/foundry-voting/circuits/proofs/foundry_voting.proof index 26fb747..0725d59 100644 --- a/foundry-voting/circuits/proofs/foundry_voting.proof +++ b/foundry-voting/circuits/proofs/foundry_voting.proof @@ -1 +1 @@ -2658b502417a72793c5bb419b1b6c37b7978a41c907c91a85eed84fd0ac495cf2f0e9a525c4015b443b330362a48c41226f0019dd3598f14de0fd572ad4b9aa82e37b1303412b5eb0ff19a3665f9ac1beb37b2573cb1b7900b957074913c64f210751ca7583988690affec05be5256f5d2a00c2629c16c412748a6b49cdbd71d19ab4bab576642895db6b53281654b449e0f7d10f5daee3ae1831943c6d6dd5914b04f0c8b92b2147fa48c0bee2b7f7668ab181a5cbf48f43d994fea72a8ab95272d73408df1dad1ccb1fc7693a1ad00ec5d90a5a476ac6c17d93c9097cb5fde150736ba98f41c6d580b303ad0f4c049a8c471c6aa1221e8d13f16401f6d6cd81cdf1044f1f277c8179ce1fc3f63c35edc0bda4b16b105b729edb137295232300f52f5e815b2720f9eafaf926c4669f686c31e54bd31679b451908395ea2c22e11a677237e15ad0143c2099cf634464f94e5f6eba76991d73f96569b501f2cd70dee501be36949aa205a9f1ba025b3c8e9f290c000115f51b8048028ba6ab9c313690f7fa8c00e7dbcc33015f1737976cd5c17bbb68b6eec99fc9f567c48ebf8083486d61fb825e53b40941f031488636f7f794e78d1ef8b8d000b9414e5c9cb300f2750d614720f6d6a7569e547fd7eef57616d775128ff00ad4ce38ea6770b095a85d308c834694f09a3b2df064543d174d7fd7033f9a8eac331023508a2e110d030ffc1fe58fa3df0d9c34c5828eef5598456c29e1bc61cc23765b5fea07c11a33fa2caf3f1001f5f78a6633447f8f72dc03c5849126c4e2c35093722d0bc28f68ca3067e4d5caf1e02aafb2c2772aa708f4f1d402e404e0f8445322b5eec23d1f08a77869f5c46992d5138a60c42a5956a32b8a8d4b53f401df4ef0a9cad25d5fc035cd831a158e420f878b65a6f21f71e287e070580f1c606792ff6fec724d78e72d3985dfb2c1e2e5bc67d505294756e608ec6d5b1cb26b4e35c9aaf521046a5929ecba953ebad49c985f841b012b06e0bde15b7844e069b7a8f12d2c32ff56a3d464b3df1036a41262a7040c7716000d55600578e16a7870cc2de62f92914b6fbf1f623a6fc1acc23482bb362455e7002c577651171306b554e5a23832b3e3c21d679b4c991703a83cc028639ec5d47bc38a7cfba3ffaddf0d95d7a4c04556ca7b3c705b4f9e842bd324f6e6aa8f20787c291709dd27e07cecc2d63e212c1048f2e4526da85e167d174e1d7d4d7621f39b869feca4439207b41a5249d1a5a0c53ed6bc7d95ca306381c82adc116de0256aa5651dc1f64bed2ab11d25d21ad55787775c99cb8c085b41b836432a39ec7d82c6c3dc45ae0b488f5e27ff116088c9be94dc4d3de0de58884d3c2d2c3b914c70f7b9e6614759f41d765c952263bd45cac56b2a66f19515171f67966fcd232cc9ddb5fbbe26de779423df00017c40d65ee1b75313b76942b69b99dfe9e5f8ed58884aa2049e99cf1ae8bc99e022f74e670e015bb4f5769f786628bb49ae19569873f5445940d866dac85d7ed2053760464e08d0b4a3f445f6dcac45bd5779bfd068e8c5c23c2c3c8e56915be07cf604db2514280deb3bef294ea947026c8f2d59d83864bcc1f0a5017cf5e7412dea0c6c389f0cdb96f55bef8ffb8c075525ee200e153bba369340c9b142ba52e0aeb564f94a00b63148d2c1e1eaf9f189bbf480f19aedafb7c14bd07a200440786ee06c75e6ccdcf7fea0aa8d36703b8755a0c2ac05d223d6878ed13de1de42454a5c400325cb14e294db23c9e9d3a78eede9704d51bcf64fa9a11f63cc7ab292e3b83f7476dcc75e69b12e9ebe4c715db18b4604412faeb8323ba7a26a7ca288f32302ef53c8fad11fc11d86bbf13f37bc0f1d6f5d6cefc431a012eb61246092775b71932e725842949152e8b68839959c399ff6b223e2260238d07369769278ccd4c1604a241e715e0a7b7ada54127079bebde6cbf817f1e2b0f96ecdf4f1c72fba8ec71704192e560b0e7d2fe2d4640b3a2c0239d58caefda21b731ae032a1e6f3dc77db19e4c123e9dc67e2b45eed13d9467a53320ccb5a34a4642388c0f672050fcdf58bb006d105afc6e19cffacfaabd61f24eb63157e52e27cb82701f45bd6afc430014f7170acb38dead7f1e2dda2b51a9c4ff2afed5bffc409d421c4aac89debdc3e827a79b7052e85a8087cd73ab0a44d42283794fc488587a080b50eed0b0534e8c18b81875a6c88d658f2842a9e1bb2516ffe3c8c24e46ab542eff0936aea53c5f85ab44844245ef9c6b3b0f4df8e681ca837a7e6ccb7dd73f2e529adb3c4ee5c79f396a26a0f17a20d36c86cc1be257ff4bddcdfea4f1604c01a88e6bb0bc1c4103170ec800785f5f824c5539b83ede998070d578b24e51190a70ba99c30ceb14253eb31d289493dcf4f825423b35495a71a4ce6f0ff832b92dfe8a0367ce592a6c8cf8f0634af820cd18c4830210f1b34b0f5b7687e501d311a62c09011bf812f48182cd18e178d27a487445205491521c4b9f7cb9033e372a5252c67f674223f7f0123531d37e978eb1ce0ba5333ae832e31969b00950e20f77bfc4e9dea82b7cd5daef4e2e124ab6635d7b19065ecb5a2fc974a5ce80831d35512c6cb67b667c0d6e037040aec92a38a8ea91b38d3ac49cc862f79ff2c31241c7080ab1945e26e04bedc59837505ea0736292e2b6135bb35191c615ba6006c9e50daec27bb9251141515d66d618e4f9da36f0f287cc7d3c50c5cd52c0af117082ed8dfdeb0729d6e34b495c79e11417715c5ef2e0789e812496d5bb763f025320872608132c0774ab22b439604283d70683d257568b8567f17954a1a9bd116ecf0520ddaa72eb6e4b65402991571ccce30aeafadb4dd0b60dca41925fcf21597f0e888036cb152fa83b5b571a1da54b5af4a7d944e8e8242bf36fc5b8a029cba139053cd35e79714c7a2978b0c6f4f7906ccec0fd56cba81174310177c61d3875b835422169687460ddc607c546477e35d5c6013a122e80b5d58db7f0d4 \ No newline at end of file +0afb8880e6061af80eb6e66624bafbcf6b57f347ecacfddd0cf7280d26f994bd21be8df560c338a1a01b97bb1995eb7beab51e3b10748675706539d1049f0b2e30498eba9495b418aad4aad07a5c1c5fef6fe2090a473c0ade7bba4257abad760b0e9ef1dcae0ab11be20233a31e96ea823d81ae1e663fdc581197561e2ca81c26135038f2e9ca140b6d8f728ec290cde9f737449250d264703d99e07e71d080033cd7f41051f8f04caed621925ac85ab33744100e1919120329e705ce48b0c91a18b805645721c89e42e4b1d4289d0eac7269416039859a877c8f33c1cd84562690a538da230b52cc018d1fa3f63658e87ece554138002be11c831c0652911b2ada2d9eab00f82bb7f931b1c2d5e0dc0535738eb59d8cd386f4e5bd96aac02408bf1a65f710b7a8a9f9709c71926f316d75f667c8d964e81f690798fef99174173b6eb5867376be215383783077c161fea18f8360098e139ac27e5c6195f52407cf1069921a7c8d3ee9aa09b6dc2d6d06f546f1ea92c3c4241fa1826938172708e5205a944eeefac7c33cfb1278f67035763d10b2be271fea1927ecc56f29e427845f7f00d3a17c9fdd2b4b0b57a8173681c862ce40678275a02241a53e4b39178b058c00586bed5960613010aece9bdf260ef124a94d7763116c99472ecdfb1cc29f906bb6e2bd886e9c18ad2d2d8f1a03b0d2eec6e73910e40b8082aa2f992633d81c1be805b76daa5188acc57e4af49f3985334350acf27c7b5446131bb3238f655365b9e9f54280275cf685dba5067c9c0b170b678b52e81f6e4a7ef6381689292b0e62771ae57eb8bac5d1cb0f84e420bfd3ee6f07065973d469b603de2437cff0e9bc76340fa924d1d6de2e2f7771828ec46efd896f75846c75b424ca00bda3a3f528e8b7ccf4a6da879172e5ae2450b9dfd31b518a74bfad567b1b812ce13cf2146664cf2c31ecd9ad74aa5eb5e404795cc246be429efaeade42fee41563c70fc862ca955eb1d0330e1f4bf93bc5cf94f7f9c6a2f295cbdf1391704026fdf2160c61fa6da948f3e4899afc013e474e5176f2b6142377cd041c715e7d1013b8fc50fcc6d3fd7735a3e7cd332cd6d6642380298cc65d7e29d65619389206f6d6c9117f04ba84c95d85dc6aed2996205ad7423bd763872d8963b6b58688024d37e3322272dcb7bf9702dd49b0b0241fa2f01cd5ab148510a163e7f09d2f1d2aefcf0cd0b50e0915d8e3ff17ffc4cb0d1b93f5d153be12e2396ab330b58c17aaaaa0c8bd29e62aeb1f98de5ffbfd3ecd152feaff1e1ab254b02243eed8712de61d452e052ee3b695708069773fd0fe9c7ff4a647a059e7004b8ce7ddc4b30102348095699c84dc43f0e3f392ad5eaa2058a5782d6813c6974d55efb7c4fa2a050ac99d2a8997266ff3cafe2f7dfe15da6581cd6599a984a2c9d01189b2b2146493577a0d1e3519494f350e379261837157db9de92a82a6dcac08d103ff0b23676998b310f449febac6d479ea1bb2887ada9ede297c9b07b0265f00ce711312532e670e4bd03d71c3f067512f106120a29b55760430c47f8f4caed4e70e3a305ce23db535eea5096d673dac1368c847fcdcffc8d23cecce90e59548ddfc3c2045b894f788eb1667cf5f1b0a89db162adf5d52ff7d6c5e5204e2d03cd010d722c71726238fa2c037a7f62715842a83c0a5ad9c0c5dc7ccd2f1455ad53fb6e10f69e350c5fa27bdacbc0c22bc3a8a79bac4c4fb5aa8059764c0d7986ed4a2812e09522f2a5ea9bb2af104f59217dc65af4e773b30e59e81dc71e7d32b2b44f801068a28504a30e2a5f77f4d4371446544eb004dab15d6028ad68976fec18af821ba3177e8131aa46bc82044da24649c7ccb3ff77b67460e85053bb6ad2dcaf50f7bacc48e7322f33052d81cfd00893f2dbec9210a3a63bf9cce34233b61eb912676b4bc891ae72ef4748e1b771a8cfa69d16a8ee1158e89e480440aafa1f8a12a97b67558ad4334599b516d5e25f014a6de93e3babf3de999a7a2c1d1d1de420cfb690407110b0f5cc0ba1a1017e5e465d8ee0aec961eb438f484c4a71f0d42230b293bac55ebc74b9f6217f1c645566db6ddb6c373e73340035ad5c317eb88131bbe93f75ce81ca149855545448f550a404c5a849c051aeb33f0a8f2c6424e0f90fa4e3ff30f414c0e2a3011f9d00aef18b9c2a1f6fce7c6ccdf4743a7c9c30018f76dceb759a0ca880f65c815e400a452cb7ce8176433b4b7c7295bb5d17411f1d216a8cda1878e2017884f2923f20d6a25bce70e820c4b8219785f37f3dd2e258a3717660181dd81ac473bcd8a40429796dca5e9d0090147ee94d9f7d4221859ccf41b7228b90b93532edaf96da6cb50d399e0e1ea1309428c6bb2ba993f26176efed52f436f65a7d1b572626cc0633dbc9be392403c4e1af4934b2ff5992c3bb5ca645342df94d3461d7ff9dc6a80eaadcd2b8efe0beb5da2bafe498cfb181ffb828e9b81e495f27b8f6e57085c7c1805144b239062f50be0cfd61b1ec90453d607b4e516bcb6507edb2e0dd36cb50aecf7513428ffbdcecd308edf56251536d35ea2afacec4d4893956c0f4856b4b130f8243973a550578e6558bae9c414b7ebfec48ff623da6beae1a79a51bfe5503e30fffc29453171e1e96a8e6b3018e24266a68f984ef9759fff037730bd1f66c74b528ac22475e26c73b990ab0615d65d709ab058f66edcc708d794d2bb16daee7c25359ad0556071ddb99e3f7c0fee8e02fe65f813c349eb49281a356d26b726110207b6e8f926131173d4058521aa12502238a7dc37fdcde6e02c734166753f731a9151001ed8dee72dc4cce62201ba28b60c273ac76774c825d0c96e54e44530bdc9c82c0fb98fdc6e6c12682fdb183a3bcd82cb421a967dff841c2bfe785fb9871b1a377eef11aa3df2c47301994735e9afd94604babe92ebea82193cd3487c25532c1c168d33a075cb4e7a282f59346c07645c9df4b4acbddad3d09a492701662ad3db11f5ac3a2f9ee737 \ No newline at end of file diff --git a/foundry-voting/circuits/src/main.nr b/foundry-voting/circuits/src/main.nr index 3e735ee..d028dbf 100644 --- a/foundry-voting/circuits/src/main.nr +++ b/foundry-voting/circuits/src/main.nr @@ -1,56 +1,54 @@ use dep::std; -fn main(root : pub Field, index : Field, hash_path : [Field; 2], secret: Field, proposalId: pub Field, vote: pub Field) -> pub Field { - let note_commitment = std::hash::pedersen([secret]); - let nullifier = std::hash::pedersen([root, secret, proposalId]); - - let check_root = std::merkle::compute_merkle_root(note_commitment[0], index, hash_path); +fn main( + root: pub Field, + index: Field, + hash_path: [Field; 2], + secret: Field, + proposalId: pub Field, + vote: pub Field +) -> pub Field { + let note_commitment = std::hash::pedersen_hash([secret]); + let nullifier = std::hash::pedersen_hash([root, secret, proposalId]); + + let check_root = std::merkle::compute_merkle_root(note_commitment, index, hash_path); assert(root == check_root); - - // Originally contrained the vote to avoid front-running, - // but including the vote as a public input is sufficient - // assert(vote <= 1); + // Originally contrained the vote to avoid front-running, + // but including the vote as a public input is sufficient - nullifier[0] -} + // assert(vote <= 1); + nullifier +} #[test] fn test_valid_build_merkle_tree() { - let commitment_0 = std::hash::pedersen([1])[0]; - let commitment_1 = std::hash::pedersen([2])[0]; - let commitment_2 = std::hash::pedersen([3])[0]; - let commitment_3 = std::hash::pedersen([4])[0]; + let commitment_0 = std::hash::pedersen_hash([1]); + let commitment_1 = std::hash::pedersen_hash([2]); + let commitment_2 = std::hash::pedersen_hash([3]); + let commitment_3 = std::hash::pedersen_hash([4]); - let left_branch = std::hash::pedersen([commitment_0, commitment_1])[0]; - let right_branch = std::hash::pedersen([commitment_2, commitment_3])[0]; + let left_branch = std::hash::pedersen_hash([commitment_0, commitment_1]); + let right_branch = std::hash::pedersen_hash([commitment_2, commitment_3]); + + let root = std::hash::pedersen_hash([left_branch, right_branch]); - let root = std::hash::pedersen([left_branch, right_branch])[0]; - let proposalId = 0; let vote = 1; - let nullifier = main( - root, - 0, - [commitment_1, right_branch], - 1, - proposalId, - vote - ); + let nullifier = main(root, 0, [commitment_1, right_branch], 1, proposalId, vote); - let expected_nullifier = std::hash::pedersen([root, 1, proposalId]); + let expected_nullifier = std::hash::pedersen_hash([root, 1, proposalId]); std::println("Merkle Tree:"); std::println([root]); std::println([left_branch, right_branch]); std::println([commitment_0, commitment_1, commitment_2, commitment_3]); - assert(nullifier == expected_nullifier[0]); + assert(nullifier == expected_nullifier); } - // fn main(root : pub Field, index : Field, hash_path : [Field; 2], secret: Field, priv_key: Field, proposalId: pub Field, vote: pub u8) -> pub Field { // let note_commitment = std::hash::pedersen([priv_key, secret]); // let nullifier = std::hash::pedersen([root, priv_key, proposalId]); @@ -69,21 +67,21 @@ fn test_valid_build_merkle_tree() { // Helpers for getting note_commitments to build the merkle tree. // To view: nargo test --show-output -// #[test] -// fn test_build_merkle_tree() { -// let secret = 9; -// let commitment_0 = std::hash::pedersen([0, secret])[0]; -// let commitment_1 = std::hash::pedersen([1, secret])[0]; -// let commitment_2 = std::hash::pedersen([2, secret])[0]; -// let commitment_3 = std::hash::pedersen([3, secret])[0]; +#[test] +fn test_build_merkle_tree() { + let secret = 9; + let commitment_0 = std::hash::pedersen_hash([0, secret]); + let commitment_1 = std::hash::pedersen_hash([1, secret]); + let commitment_2 = std::hash::pedersen_hash([2, secret]); + let commitment_3 = std::hash::pedersen_hash([3, secret]); -// let left_branch = std::hash::pedersen([commitment_0, commitment_1])[0]; -// let right_branch = std::hash::pedersen([commitment_2, commitment_3])[0]; + let left_branch = std::hash::pedersen_hash([commitment_0, commitment_1]); + let right_branch = std::hash::pedersen_hash([commitment_2, commitment_3]); -// let root = std::hash::pedersen([left_branch, right_branch])[0]; + let root = std::hash::pedersen_hash([left_branch, right_branch]); - // std::println("Merkle Tree:"); - // std::println([root]); - // std::println([left_branch, right_branch]); - // std::println([commitment_0, commitment_1, commitment_2, commitment_3]); -// } + std::println("Merkle Tree:"); + std::println([root]); + std::println([left_branch, right_branch]); + std::println([commitment_0, commitment_1, commitment_2, commitment_3]); +} From 83909b1e0032bd46888c6e2eeb02b5e653c53caf Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Mon, 5 Feb 2024 10:40:43 -0500 Subject: [PATCH 4/6] update test input --- foundry-voting/data/input.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/foundry-voting/data/input.json b/foundry-voting/data/input.json index 80c00e0..c1bc72b 100644 --- a/foundry-voting/data/input.json +++ b/foundry-voting/data/input.json @@ -1,4 +1,4 @@ { - "merkleRoot": "0x29fd5ee89e33f559a7b32ac39f57400aa5a6c77492e28c088f9eb511b0c73e78", - "nullifierHash": "0x1cbb284a43dde14da2c3790e12872bcb7e53c53e27b5187384c617841174ace5" -} \ No newline at end of file + "merkleRoot": "0x215597bacd9c7e977dfc170f320074155de974be494579d2586e5b268fa3b629", + "nullifierHash": "0x079d88735cdd786b64a950b1cd887ae89308e3b4176ef4adb308267888fe1f91" +} From a6ac92eaa1da424a108aa05030a622969dbbad08 Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Mon, 5 Feb 2024 10:43:51 -0500 Subject: [PATCH 5/6] remove old code --- .../circuits/target/debug_foundry_voting.json | 1 + .../circuits/target/foundry_voting.json | 2 +- foundry-voting/package.json | 6 +- foundry-voting/test/integration.test.ts | 95 ------------------ foundry-voting/tsconfig.json | 18 +--- foundry-voting/utils/noirNode.ts | 99 ------------------- foundry-voting/utils/populate.ts | 46 --------- 7 files changed, 7 insertions(+), 260 deletions(-) create mode 100644 foundry-voting/circuits/target/debug_foundry_voting.json delete mode 100644 foundry-voting/test/integration.test.ts delete mode 100644 foundry-voting/utils/noirNode.ts delete mode 100644 foundry-voting/utils/populate.ts diff --git a/foundry-voting/circuits/target/debug_foundry_voting.json b/foundry-voting/circuits/target/debug_foundry_voting.json new file mode 100644 index 0000000..9666d3d --- /dev/null +++ b/foundry-voting/circuits/target/debug_foundry_voting.json @@ -0,0 +1 @@ +{"debug_symbols":[{"locations":{"0":[{"span":{"start":199,"end":233},"file":0},{"span":{"start":755,"end":793},"file":23}],"1":[{"span":{"start":255,"end":307},"file":0},{"span":{"start":755,"end":793},"file":23}],"2":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":529,"end":555},"file":25},{"span":{"start":122,"end":149},"file":15}],"3":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":529,"end":555},"file":25},{"span":{"start":122,"end":149},"file":15}],"4":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":529,"end":555},"file":25},{"span":{"start":122,"end":149},"file":15}],"5":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":529,"end":555},"file":25},{"span":{"start":122,"end":149},"file":15}],"6":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":716,"end":728},"file":25}],"7":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"8":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"9":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"10":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"11":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"12":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"13":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"14":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":716,"end":728},"file":25}],"15":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"16":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"17":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"18":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"19":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"20":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"21":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"22":[{"span":{"start":411,"end":429},"file":0}]}}],"file_map":{"0":{"source":"use dep::std;\n\nfn main(\n root: pub Field,\n index: Field,\n hash_path: [Field; 2],\n secret: Field,\n proposalId: pub Field,\n vote: pub Field\n) -> pub Field {\n let note_commitment = std::hash::pedersen_hash([secret]);\n let nullifier = std::hash::pedersen_hash([root, secret, proposalId]);\n\n let check_root = std::merkle::compute_merkle_root(note_commitment, index, hash_path);\n assert(root == check_root);\n\n // Originally contrained the vote to avoid front-running,\n // but including the vote as a public input is sufficient\n\n // assert(vote <= 1);\n\n nullifier\n}\n\n#[test]\nfn test_valid_build_merkle_tree() {\n let commitment_0 = std::hash::pedersen_hash([1]);\n let commitment_1 = std::hash::pedersen_hash([2]);\n let commitment_2 = std::hash::pedersen_hash([3]);\n let commitment_3 = std::hash::pedersen_hash([4]);\n\n let left_branch = std::hash::pedersen_hash([commitment_0, commitment_1]);\n let right_branch = std::hash::pedersen_hash([commitment_2, commitment_3]);\n\n let root = std::hash::pedersen_hash([left_branch, right_branch]);\n\n let proposalId = 0;\n let vote = 1;\n\n let nullifier = main(root, 0, [commitment_1, right_branch], 1, proposalId, vote);\n\n let expected_nullifier = std::hash::pedersen_hash([root, 1, proposalId]);\n\n std::println(\"Merkle Tree:\");\n std::println([root]);\n std::println([left_branch, right_branch]);\n std::println([commitment_0, commitment_1, commitment_2, commitment_3]);\n\n assert(nullifier == expected_nullifier);\n}\n\n// fn main(root : pub Field, index : Field, hash_path : [Field; 2], secret: Field, priv_key: Field, proposalId: pub Field, vote: pub u8) -> pub Field {\n// let note_commitment = std::hash::pedersen([priv_key, secret]);\n// let nullifier = std::hash::pedersen([root, priv_key, proposalId]);\n\n// let check_root = std::merkle::compute_merkle_root(note_commitment[0], index, hash_path);\n// assert(root == check_root);\n\n// // Originally contrained the vote to avoid front-running,\n// // but including the vote as a public input is sufficient\n\n// assert(vote <= 1);\n\n// nullifier[0]\n// }\n\n// Helpers for getting note_commitments to build the merkle tree.\n// To view: nargo test --show-output\n\n#[test]\nfn test_build_merkle_tree() {\n let secret = 9;\n let commitment_0 = std::hash::pedersen_hash([0, secret]);\n let commitment_1 = std::hash::pedersen_hash([1, secret]);\n let commitment_2 = std::hash::pedersen_hash([2, secret]);\n let commitment_3 = std::hash::pedersen_hash([3, secret]);\n\n let left_branch = std::hash::pedersen_hash([commitment_0, commitment_1]);\n let right_branch = std::hash::pedersen_hash([commitment_2, commitment_3]);\n\n let root = std::hash::pedersen_hash([left_branch, right_branch]);\n\n std::println(\"Merkle Tree:\");\n std::println([root]);\n std::println([left_branch, right_branch]);\n std::println([commitment_0, commitment_1, commitment_2, commitment_3]);\n}\n","path":"/home/josh/Documents/Github/noir-examples/foundry-voting/circuits/src/main.nr"},"15":{"source":"impl Field {\n pub fn to_le_bits(self: Self, bit_size: u32) -> [u1] {\n crate::assert_constant(bit_size);\n self.__to_le_bits(bit_size)\n }\n \n pub fn to_be_bits(self: Self, bit_size: u32) -> [u1] {\n crate::assert_constant(bit_size);\n self.__to_be_bits(bit_size)\n }\n\n #[builtin(to_le_bits)]\n fn __to_le_bits(_self: Self, _bit_size: u32) -> [u1] {}\n \n #[builtin(to_be_bits)]\n fn __to_be_bits(_self: Self, _bit_size: u32) -> [u1] {}\n\n pub fn to_le_bytes(self: Self, byte_size: u32) -> [u8] {\n self.to_le_radix(256, byte_size)\n }\n\n pub fn to_be_bytes(self: Self, byte_size: u32) -> [u8] {\n self.to_be_radix(256, byte_size)\n }\n\n\n pub fn to_le_radix(self: Self, radix: u32, result_len: u32) -> [u8] {\n crate::assert_constant(radix);\n crate::assert_constant(result_len);\n self.__to_le_radix(radix, result_len)\n }\n\n pub fn to_be_radix(self: Self, radix: u32, result_len: u32) -> [u8] {\n crate::assert_constant(radix);\n crate::assert_constant(result_len);\n self.__to_be_radix(radix, result_len)\n }\n\n\n\n // decompose `_self` into a `_result_len` vector over the `_radix` basis\n // `_radix` must be less than 256\n #[builtin(to_le_radix)]\n fn __to_le_radix(_self: Self, _radix: u32, _result_len: u32) -> [u8] {}\n \n #[builtin(to_be_radix)]\n fn __to_be_radix(_self: Self, _radix: u32, _result_len: u32) -> [u8] {}\n\n\n // Returns self to the power of the given exponent value.\n // Caution: we assume the exponent fits into 32 bits\n // using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits\n pub fn pow_32(self, exponent: Field) -> Field {\n let mut r: Field = 1;\n let b = exponent.to_le_bits(32);\n\n for i in 1..33 {\n r *= r;\n r = (b[32-i] as Field) * (r * self) + (1 - b[32-i] as Field) * r;\n }\n r\n }\n\n // Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1.\n pub fn sgn0(self) -> u1 {\n self as u1\n }\n}\n\n#[builtin(modulus_num_bits)]\npub fn modulus_num_bits() -> Field {}\n\n#[builtin(modulus_be_bits)]\npub fn modulus_be_bits() -> [u1] {}\n\n#[builtin(modulus_le_bits)]\npub fn modulus_le_bits() -> [u1] {}\n\n#[builtin(modulus_be_bytes)]\npub fn modulus_be_bytes() -> [u8] {}\n\n#[builtin(modulus_le_bytes)]\npub fn modulus_le_bytes() -> [u8] {}\n// Convert a 32 byte array to a field element\npub fn bytes32_to_field(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..16 {\n high = high + (bytes32[15 - i] as Field) * v;\n low = low + (bytes32[16 + 15 - i] as Field) * v;\n v = v * 256;\n }\n // Abuse that a % p + b % p = (a + b) % p and that low < p\n low + high * v\n}\n","path":"std/field.nr"},"23":{"source":"mod poseidon;\nmod mimc;\n\n#[foreign(sha256)]\npub fn sha256(_input: [u8; N]) -> [u8; 32] {}\n\n#[foreign(blake2s)]\npub fn blake2s(_input: [u8; N]) -> [u8; 32] {}\n\nstruct PedersenPoint {\n x : Field,\n y : Field,\n}\n\npub fn pedersen_commitment(input: [Field; N]) -> PedersenPoint {\n pedersen_commitment_with_separator(input, 0)\n}\n\n#[foreign(pedersen_commitment)]\npub fn __pedersen_commitment_with_separator(_input: [Field; N], _separator: u32) -> [Field; 2] {}\n\npub fn pedersen_commitment_with_separator(input: [Field; N], separator: u32) -> PedersenPoint {\n let values = __pedersen_commitment_with_separator(input, separator);\n PedersenPoint { x: values[0], y: values[1] }\n}\n\npub fn pedersen_hash(input: [Field; N]) -> Field {\n pedersen_hash_with_separator(input, 0)\n}\n\n#[foreign(pedersen_hash)]\npub fn pedersen_hash_with_separator(_input: [Field; N], _separator: u32) -> Field {}\n\npub fn hash_to_field(_input: [Field; N]) -> Field {\n let mut inputs_as_bytes = [];\n\n for i in 0..N {\n let input_bytes = _input[i].to_le_bytes(32);\n for i in 0..32 {\n inputs_as_bytes = inputs_as_bytes.push_back(input_bytes[i]);\n }\n }\n\n let hashed_input = blake2s(inputs_as_bytes);\n crate::field::bytes32_to_field(hashed_input)\n}\n\n#[foreign(keccak256)]\npub fn keccak256(_input: [u8; N], _message_size: u32) -> [u8; 32] {}\n\n","path":"std/hash.nr"},"25":{"source":"// Regular merkle tree means a append-only merkle tree (Explain why this is the only way to have privacy and alternatives if you don't want it)\n// Currently we assume that it is a binary tree, so depth k implies a width of 2^k\n// XXX: In the future we can add an arity parameter\n// Returns the merkle root of the tree from the provided leaf, its hashpath, using a pedersen hash function.\npub fn compute_merkle_root(leaf: Field, index: Field, hash_path: [Field; N]) -> Field {\n let n = hash_path.len();\n let index_bits = index.to_le_bits(n as u32);\n let mut current = leaf;\n for i in 0..n {\n let path_bit = index_bits[i] as bool;\n let (hash_left, hash_right) = if path_bit {\n (hash_path[i], current)\n } else {\n (current, hash_path[i])\n };\n current = crate::hash::pedersen_hash([hash_left, hash_right]);\n }\n current\n}\n","path":"std/merkle.nr"}},"warnings":[]} \ No newline at end of file diff --git a/foundry-voting/circuits/target/foundry_voting.json b/foundry-voting/circuits/target/foundry_voting.json index 67cf1d5..b8b9b7e 100644 --- a/foundry-voting/circuits/target/foundry_voting.json +++ b/foundry-voting/circuits/target/foundry_voting.json @@ -1 +1 @@ -{"backend":"acvm-backend-barretenberg","abi":{"parameters":[{"name":"root","type":{"kind":"field"},"visibility":"public"},{"name":"index","type":{"kind":"field"},"visibility":"private"},{"name":"hash_path","type":{"kind":"array","length":2,"type":{"kind":"field"}},"visibility":"private"},{"name":"secret","type":{"kind":"field"},"visibility":"private"},{"name":"proposalId","type":{"kind":"field"},"visibility":"public"},{"name":"vote","type":{"kind":"field"},"visibility":"public"}],"param_witnesses":{"hash_path":[3,4],"index":[2],"proposalId":[6],"root":[1],"secret":[5],"vote":[7]},"return_type":{"kind":"field"},"return_witnesses":[10]},"bytecode":"H4sIAAAAAAAA/9VZbU/CMBC+bYBvGwiCIBJMNNFEY9KyDbpv/hWJ4///AmMbrqGb+8bTZGtyubKUa5/netfb+klEazq2PuuQdaSlpyXQMmBtx/1y/1LLlTMm4ucBj7FjB85/rrXc8Dx2LnLsf7EW5zUZ4mwJu85YS8LrDljH3Le/EwcLOVz6wpaKbZaVu00pU/ktNsVe5SLL91sllcxV/rNRaVqqTO2KfbEThczSUh7yIj2wsRhgqzwcWwLk3OUvrPHXBszW1hDo165gHoExo2PfxFvcYPdc3GvC7m80bpOPhx5wP5GfuI7A67wFcgn0tUTz5yNeRh72zXMH4sVHnnihbsTLGMgl0NcSyZ+tTe15anKEqUXHdKpJJ1ruqNrQ528CtDWlbtQcSMwzanfNYd6VEsLnkldqdw41sTP1gPuNupFD74FcAn0t0fz5iJeZh33z3nLcJkdMPOD+oG7EyxzIJdDXEslfveYwOcLUGnM61RwLLQ9UbejvRAHQbwugrSUOo4jo//c2InzcItfsrvfR6fdYhw17YuABE9XmqfM4bHjW6iJsyYSi7a4It/l94V7hfVQ5CNrMqRs49uKiT9ULCRNAFw4OcxHxB5AbxdoBGQAA","proving_key":null,"verification_key":null} \ No newline at end of file +{"noir_version":"0.22.0+3fae4a03fded4e3f5065e7461c563f7e39745604","hash":14491308408831426258,"abi":{"parameters":[{"name":"root","type":{"kind":"field"},"visibility":"public"},{"name":"index","type":{"kind":"field"},"visibility":"private"},{"name":"hash_path","type":{"kind":"array","length":2,"type":{"kind":"field"}},"visibility":"private"},{"name":"secret","type":{"kind":"field"},"visibility":"private"},{"name":"proposalId","type":{"kind":"field"},"visibility":"public"},{"name":"vote","type":{"kind":"field"},"visibility":"public"}],"param_witnesses":{"hash_path":[{"start":3,"end":5}],"index":[{"start":2,"end":3}],"proposalId":[{"start":6,"end":7}],"root":[{"start":1,"end":2}],"secret":[{"start":5,"end":6}],"vote":[{"start":7,"end":8}]},"return_type":{"abi_type":{"kind":"field"},"visibility":"public"},"return_witnesses":[9]},"bytecode":"H4sIAAAAAAAA/9VYbW6DMAx16cdW6Nqu3bRN2qROu0BCoIR/u8rQ4P4nqIrVoAZ+lucKLEUEET3iZ/s5yg8RvdHFJvV4cE+2eT1Obv7ofZ9660/euoW3flmPwMMib/7rnqqf6QCHpQKHE9YjcnuX2HPo/tHFNeqYJGUWl9roPxXnhU1VkhZHq61ObfofW2NKm9gsL/JM5Toxpa7S3FQOOARyIeF35HhF+x2B/W5sKpiryFjfilVWF5PiLxDM775YK2BcJWqFc09CI15o2BrBPWYl4Pcr3Ucj+u7zCcglMNYazZ9EvUjkzfsI6kVCJz5oHPWyBnIJjLVG8tecuZt+yhrBZ+w1Xc/aG2obuvdGQKwtDbv3zkjmnPpJw9YSzqGtgN9fNA4teQZyCYy1RvMnUS8SeXMYuN+sERsBv79pHPWyA3J5AGIh+ev2XtYI7rk7uvbePbWt23tVP9MTYMz2QG5mnr+cW/w+p/bd4ILa94lLj6czaflhJ3gUAAA="} \ No newline at end of file diff --git a/foundry-voting/package.json b/foundry-voting/package.json index a721bdc..4ac9cfc 100644 --- a/foundry-voting/package.json +++ b/foundry-voting/package.json @@ -8,16 +8,12 @@ "test": "test" }, "scripts": { - "test": "forge test", - "integration-test": "vitest", - "populate-prover-toml": "ts-node --esm --experimental-specifier-resolution=node ./utils/populate.ts" + "test": "forge test" }, "author": "", "license": "ISC", "dependencies": { - "@aztec/bb.js": "0.3.6", "@iarna/toml": "^2.2.5", - "@noir-lang/acvm_js": "git+https://github.com/noir-lang/acvm-simulator-wasm.git", "fflate": "^0.8.0", "toml": "^3.0.0" }, diff --git a/foundry-voting/test/integration.test.ts b/foundry-voting/test/integration.test.ts deleted file mode 100644 index aaa5c5d..0000000 --- a/foundry-voting/test/integration.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { expect } from 'chai'; -// import { describe, it } from 'mocha'; -import { NoirNode } from "../utils/noirNode"; -import { convertToHex } from "../utils/common"; - -import { beforeAll, afterAll, describe } from 'vitest'; -import circuit from '../circuits/target/foundry_voting.json' assert { type: "json" }; - -const noir = new NoirNode(); - -describe('Integration tests', function () { - let merkleData: any; - - beforeAll(async () => { - await noir.init(circuit); - merkleData = await getMerkleTree(); - }); - - afterAll(async () => { - await noir.destroy(); - }); - - function generateInitialWitness(input: any) { - const initialWitness = new Map(); - - initialWitness.set(1, input.root); - initialWitness.set(2, convertToHex(input.index)); - initialWitness.set(3, input.hash_path[0]); - initialWitness.set(4, input.hash_path[1]); - initialWitness.set(5, convertToHex(input.secret)); - initialWitness.set(6, convertToHex(input.proposalId)); - initialWitness.set(7, convertToHex(input.vote)); - - return initialWitness; - } - - async function getMerkleTree() { - let commitment1 = await noir.pedersenHash([BigInt(1)]); - let commitment2 = await noir.pedersenHash([BigInt(2)]); - let commitment3 = await noir.pedersenHash([BigInt(3)]); - let commitment4 = await noir.pedersenHash([BigInt(4)]); - - let leftSubtree = await noir.pedersenHash([commitment1, commitment2]); - let rightSubtree = await noir.pedersenHash([commitment3, commitment4]); - - let root = await noir.pedersenHash([leftSubtree, rightSubtree]); - - return { - root: convertToHex(root), - hashPath: [convertToHex(commitment2), convertToHex(rightSubtree)] - } - } - - it("Should be able to generate proof and verify it for valid inputs", async () => { - - let inputs = { - root: merkleData.root, - index: 0, - hash_path: merkleData.hashPath, - secret: 1, - proposalId: 0, - vote: 1 - } - - const initialWitness = generateInitialWitness(inputs) - - const witness = await noir.generateWitness(initialWitness); - const proof = await noir.generateProof(witness); - - expect(proof instanceof Uint8Array).to.be.true; - - const verified = await noir.verifyProof(proof); - - expect(verified).to.be.true; - }); - - it("Should fail to execute for failing contraints", async () => { - let inputs = { - root: "0x29fd5ee89e33f559a7b32ac39f57400aa5a6c77492e28c088f9eb511b0c73e70", - index: 0, - hash_path: merkleData.hashPath, - secret: 1, - proposalId: 0, - vote: 1 - } - try { - const initialWitness = generateInitialWitness(inputs) - await noir.generateWitness(initialWitness); - } - catch (err: any) { - expect(err).to.equal("could not satisfy all constraints"); - } - }); - -}); diff --git a/foundry-voting/tsconfig.json b/foundry-voting/tsconfig.json index 9722a3c..5977398 100644 --- a/foundry-voting/tsconfig.json +++ b/foundry-voting/tsconfig.json @@ -12,17 +12,7 @@ "resolveJsonModule": true, "noImplicitAny": true, "plugins": [], - "lib": [ - "dom", - "EsNext" - ] - }, - "include": [ - "./test/**/*" - ], - "exclude": [ - "node_modules", - "**/node_modules/**" - ] - -} \ No newline at end of file + "lib": ["dom", "EsNext"] + }, + "exclude": ["node_modules", "**/node_modules/**"] +} diff --git a/foundry-voting/utils/noirNode.ts b/foundry-voting/utils/noirNode.ts deleted file mode 100644 index acbe5f9..0000000 --- a/foundry-voting/utils/noirNode.ts +++ /dev/null @@ -1,99 +0,0 @@ -// TODO use the JSON directly for now -// import { compile } from '@noir-lang/noir_wasm'; -import { decompressSync } from 'fflate'; -import { - BarretenbergApiAsync, - Crs, - newBarretenbergApiAsync, - RawBuffer, -} from '@aztec/bb.js/dest/node/index.js'; -import { executeCircuit, compressWitness } from '@noir-lang/acvm_js'; -import { ethers } from 'ethers'; -import { Ptr, Fr } from '@aztec/bb.js/dest/node/types/index.js'; - - -export class NoirNode { - acir: string = ''; - acirBuffer: Uint8Array = Uint8Array.from([]); - acirBufferUncompressed: Uint8Array = Uint8Array.from([]); - - api = {} as BarretenbergApiAsync; - acirComposer = {} as Ptr; - - async init(circuit: any) { - this.acirBuffer = Buffer.from(circuit.bytecode, 'base64'); - this.acirBufferUncompressed = decompressSync(this.acirBuffer); - - this.api = await newBarretenbergApiAsync(4); - - const [exact, total, subgroup] = await this.api.acirGetCircuitSizes( - this.acirBufferUncompressed, - ); - const subgroupSize = Math.pow(2, Math.ceil(Math.log2(total))); - const crs = await Crs.new(subgroupSize + 1); - await this.api.commonInitSlabAllocator(subgroupSize); - await this.api.srsInitSrs( - new RawBuffer(crs.getG1Data()), - crs.numPoints, - new RawBuffer(crs.getG2Data()), - ); - - this.acirComposer = await this.api.acirNewAcirComposer(subgroupSize); - } - - async generateWitness(initialWitness: Map): Promise { - const witnessMap = await executeCircuit(this.acirBuffer, initialWitness, () => { - throw Error('unexpected oracle'); - }); - - const witnessBuff = compressWitness(witnessMap); - return witnessBuff; - } - - async generateProof(witness: Uint8Array) { - const proof = await this.api.acirCreateProof( - this.acirComposer, - this.acirBufferUncompressed, - decompressSync(witness), - false, - ); - return proof; - } - - async verifyProof(proof: Uint8Array) { - await this.api.acirInitProvingKey(this.acirComposer, this.acirBufferUncompressed); - const verified = await this.api.acirVerifyProof(this.acirComposer, proof, false); - return verified; - } - - async compressInputs(values: number[]) { - let serialised_inputs = [] - for (var i = 0; i < values.length; i++) { - let number_hex = values[i].toString(16); - let padded_number_hex = number_hex.length % 2 == 0 ? "0x" + number_hex : "0x0" + number_hex; // TOOD: this logic should be placed inside the `serialise_public_inputs` method - serialised_inputs.push( - Fr.fromString(padded_number_hex) - ); - } - const compressed_inputs = await this.api.pedersenHashMultiple(serialised_inputs); - return compressed_inputs; - } - - async pedersenHash(data: BigInt[]) { - let hexData = []; - - for (let dataPoint of data) { - let hexVal = ethers.utils.hexZeroPad(`0x${dataPoint.toString(16)}`, 32); - let num = Fr.fromString(hexVal); - - hexData.push(num); - } - - let hash = await this.api.pedersenPlookupCommit(hexData); - return hash.value; - } - - async destroy() { - await this.api.destroy(); - } -} \ No newline at end of file diff --git a/foundry-voting/utils/populate.ts b/foundry-voting/utils/populate.ts deleted file mode 100644 index ed67202..0000000 --- a/foundry-voting/utils/populate.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { NoirNode } from "./NoirNode"; -import { convertToHex, writeToToml } from "./common"; -import config from "../data/config.json" assert { type: "json" }; -import circuit from '../circuits/target/circuits.json' assert { type: "json" }; -import { fileURLToPath } from 'url'; -import { resolve, dirname } from "path"; - -async function getMerkleTree(noir: NoirNode) { - - let commitment1 = await noir.pedersenHash([BigInt(1)]); - let commitment2 = await noir.pedersenHash([BigInt(2)]); - let commitment3 = await noir.pedersenHash([BigInt(3)]); - let commitment4 = await noir.pedersenHash([BigInt(4)]); - - let leftSubtree = await noir.pedersenHash([commitment1, commitment2]); - let rightSubtree = await noir.pedersenHash([commitment3, commitment4]); - - let root = await noir.pedersenHash([leftSubtree, rightSubtree]); - - return { - root: convertToHex(root), - hashPath: [convertToHex(commitment2), convertToHex(rightSubtree)] - } -} - -async function main() { - const noir = new NoirNode(); - await noir.init(circuit); - - let merkleData = await getMerkleTree(noir); - - let data = { - hash_path: merkleData.hashPath, - index: config.index, - proposalId: config.proposalId, - root: merkleData.root, - secret: config.secret - } - - const dir = dirname(fileURLToPath(import.meta.url)); - let path = resolve(dir + "/../circuits/Prover.toml"); - - writeToToml(data, path); -} - -main(); \ No newline at end of file From ad1e012709ad40e30bdc396b36d90604ebadd45c Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Wed, 7 Feb 2024 21:00:11 -0500 Subject: [PATCH 6/6] remove generated files --- .../contract/foundry_voting/plonk_vk.sol | 2647 ----------------- .../circuits/proofs/foundry_voting.proof | 1 - .../circuits/target/debug_foundry_voting.json | 1 - .../circuits/target/foundry_voting.json | 1 - 4 files changed, 2650 deletions(-) delete mode 100644 foundry-voting/circuits/contract/foundry_voting/plonk_vk.sol delete mode 100644 foundry-voting/circuits/proofs/foundry_voting.proof delete mode 100644 foundry-voting/circuits/target/debug_foundry_voting.json delete mode 100644 foundry-voting/circuits/target/foundry_voting.json diff --git a/foundry-voting/circuits/contract/foundry_voting/plonk_vk.sol b/foundry-voting/circuits/contract/foundry_voting/plonk_vk.sol deleted file mode 100644 index 56f64e1..0000000 --- a/foundry-voting/circuits/contract/foundry_voting/plonk_vk.sol +++ /dev/null @@ -1,2647 +0,0 @@ -// Verification Key Hash: 3cf4e7181c5ed77337e3e15850edaf6a635b9649788c010c9d0b2ba854ad10f2 -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2022 Aztec -pragma solidity >=0.8.4; - -library UltraVerificationKey { - function verificationKeyHash() internal pure returns(bytes32) { - return 0x3cf4e7181c5ed77337e3e15850edaf6a635b9649788c010c9d0b2ba854ad10f2; - } - - function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure { - assembly { - mstore(add(_vk, 0x00), 0x0000000000000000000000000000000000000000000000000000000000008000) // vk.circuit_size - mstore(add(_vk, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000004) // vk.num_inputs - mstore(add(_vk, 0x40), 0x2d1ba66f5941dc91017171fa69ec2bd0022a2a2d4115a009a93458fd4e26ecfb) // vk.work_root - mstore(add(_vk, 0x60), 0x3063edaa444bddc677fcd515f614555a777997e0a9287d1e62bf6dd004d82001) // vk.domain_inverse - mstore(add(_vk, 0x80), 0x16f643c5e2a0c578e81d747be575fbf9b91732e3be6e753b694dd2ed5471e7fb) // vk.Q1.x - mstore(add(_vk, 0xa0), 0x1d8fb151c68ae5e8f7ee117623cc1c61b6c8c9947709a94c799ab056e8310209) // vk.Q1.y - mstore(add(_vk, 0xc0), 0x0bcb8ac908e3b4a08c8f5e78a35304952d69bc90aef22f763920bd42f33c00c8) // vk.Q2.x - mstore(add(_vk, 0xe0), 0x21e0744ed22f59201721e921180ac96657261cd33bf329cae83c9eac3cda84d6) // vk.Q2.y - mstore(add(_vk, 0x100), 0x0e51b6323bf93ddb10b13b5758d218d9442b6efc2a788cf40215b92884b761d4) // vk.Q3.x - mstore(add(_vk, 0x120), 0x147196a7dd55ba53cc1603091071b291f72b50bb5cd036f8a083b4c8615ee3f0) // vk.Q3.y - mstore(add(_vk, 0x140), 0x1ba99524ff055c629564114238516180f5f43b5f5eaa3d11adabb01e5a65b6c9) // vk.Q4.x - mstore(add(_vk, 0x160), 0x20694e7d9e25acd5718ac314d387e957c39bb7359fa7a7f3b3d6174cccb9fb3c) // vk.Q4.y - mstore(add(_vk, 0x180), 0x1186c2efb2bd64cdca3bef1584dc7a05256de2b6895e903903a44a0418075054) // vk.Q_M.x - mstore(add(_vk, 0x1a0), 0x27d7e5008b484a1398258b2ae92d1bc11fa527836ebf131854cce0b82c0866f8) // vk.Q_M.y - mstore(add(_vk, 0x1c0), 0x1b60fa4003663d324e4edbe79b499ed0d46e1a62b61f5dcb707304a26a74995d) // vk.Q_C.x - mstore(add(_vk, 0x1e0), 0x06dcc8743d5c44abdeb447fad451205e8b2e1e04ec434c4bef3ba6d558ee9fdd) // vk.Q_C.y - mstore(add(_vk, 0x200), 0x096d3d7fce6ea24ea0a82145380ddb0f3b06cb4deee91c7468a1c2722000c6e3) // vk.Q_ARITHMETIC.x - mstore(add(_vk, 0x220), 0x2ab594dae595e5df7071bd3b76c22f3ef03fa9f9e271283d28fd4ba86acf5314) // vk.Q_ARITHMETIC.y - mstore(add(_vk, 0x240), 0x088157fe7915970a3667db252a333660a4f28895efcaa2b4e91a1b00dc74616e) // vk.QSORT.x - mstore(add(_vk, 0x260), 0x2a9af15b7ebc36fb4ea2ccf4a8a5465c963cfae2727bb76e725ac3fa67b49817) // vk.QSORT.y - mstore(add(_vk, 0x280), 0x050541309eb13db9c19d8331540f07a867cecc5764c7fed772f4c962a8585931) // vk.Q_ELLIPTIC.x - mstore(add(_vk, 0x2a0), 0x0823785abd1759e0fef5971a0aa16c6d161c340b961cad588ad8d4eeb122dad0) // vk.Q_ELLIPTIC.y - mstore(add(_vk, 0x2c0), 0x16262200e3a244db5f8c2449af13644215b799d556ba8208d8bca9b6662d71d4) // vk.Q_AUX.x - mstore(add(_vk, 0x2e0), 0x2fff50d724a01bb83cef80b7049fbe01be798df1569718d9d22a2823782644d8) // vk.Q_AUX.y - mstore(add(_vk, 0x300), 0x0f6bba913dc4e6eaa8dbf357baf71cbee107140b8008f232c3380d1a23f5857b) // vk.SIGMA1.x - mstore(add(_vk, 0x320), 0x1de071957bb2c9ddbe39956df09c45ee6bfc5cb4c63d201c7f924f37768f2b97) // vk.SIGMA1.y - mstore(add(_vk, 0x340), 0x2be2c9a2d194b00c4a5324f76e0251c3d33ae02fd12ec2dac5c3b51ebf23079f) // vk.SIGMA2.x - mstore(add(_vk, 0x360), 0x27f6a191d1bd457864ec3ac30ac37d0d3fe86eaff730ab90c868bea99912084b) // vk.SIGMA2.y - mstore(add(_vk, 0x380), 0x10e5fb310ce836d792f0c8d70fd8bc40a4bdf347886cd8abf7050eb51a26a3ba) // vk.SIGMA3.x - mstore(add(_vk, 0x3a0), 0x24aad54275c9cba0d33e809157b42871d7fd5a6e52137b8888cc7e7fd316295d) // vk.SIGMA3.y - mstore(add(_vk, 0x3c0), 0x229772481efe74fba701e06dd3aee2087c022961fddd0c7bc678fb457890ef48) // vk.SIGMA4.x - mstore(add(_vk, 0x3e0), 0x2ea21e10c30eb6656650436e5d20d84cd3a2d1e1a34d997d4546ca65dc5c9c03) // vk.SIGMA4.y - mstore(add(_vk, 0x400), 0x14fa3d2f7838cd2b628013fbcc4a5964f90f86fee3c44f90f15b66cbb883b16d) // vk.TABLE1.x - mstore(add(_vk, 0x420), 0x087cff60b464aea188316044a5bdd7ad11e09061a6bbb1538a16ea2043d818bb) // vk.TABLE1.y - mstore(add(_vk, 0x440), 0x0edc0845445f3a9214ca8c4ce8bfd53897d91e27fc085631d7fb2a1225d3c40e) // vk.TABLE2.x - mstore(add(_vk, 0x460), 0x30521fd3f90d6823143b31aa19fdb95c3622a2ebcfe40878a9b926f9bb595870) // vk.TABLE2.y - mstore(add(_vk, 0x480), 0x030ac1cc92a28b967df7160de3f4bb3d18ea9b4e815b5c595a4cb7cae56db7c6) // vk.TABLE3.x - mstore(add(_vk, 0x4a0), 0x2465a7e5d40cdae7124e40609f69a02cdbae4b8de36519517a574e2a2c8201fd) // vk.TABLE3.y - mstore(add(_vk, 0x4c0), 0x0d3a5fd296b6cb7657205032d326c1126531247361cfb572fe626cdbc274fe6a) // vk.TABLE4.x - mstore(add(_vk, 0x4e0), 0x2c76ae3fdcd620f284426dc5c68ba0a2c4b08dda0c3a6ccb925a93efdc34eeff) // vk.TABLE4.y - mstore(add(_vk, 0x500), 0x037860d2d867bc0aedfb78139023ece5960992e852efa09b9fcba326653b9802) // vk.TABLE_TYPE.x - mstore(add(_vk, 0x520), 0x0c763504923d3d79db875de9e151b0add2efa2a7e00c8f88883824d3d0a4c080) // vk.TABLE_TYPE.y - mstore(add(_vk, 0x540), 0x171a06b1badd06125fb2f0f52bc8f653daab775de9b28669860ee5d0b0f62a0d) // vk.ID1.x - mstore(add(_vk, 0x560), 0x305877be31389f2e8a184dc3a0f8f1ce2d7627542e116c50d6a48291128c4bfd) // vk.ID1.y - mstore(add(_vk, 0x580), 0x263941e5944250e4481ca3e34e090cafefdaf93477c219974586936f9ca26f85) // vk.ID2.x - mstore(add(_vk, 0x5a0), 0x161e8bf5d2e01c6f1b2fbdc9a726beba044e1d185bfc4dee0301130d2d31dbdf) // vk.ID2.y - mstore(add(_vk, 0x5c0), 0x1eae95b0f2389ee3ae9dc172bfbd362a0eb3ea9e02bdc51b989d11ad1464ac60) // vk.ID3.x - mstore(add(_vk, 0x5e0), 0x155b2dda9d3e893e55fd87d49436d4fb938b754ae01545e18cc50f8a32e35bba) // vk.ID3.y - mstore(add(_vk, 0x600), 0x0cdb06569071e31209599397bdc7a822fca496741ce24dfdf751bf44425e8e11) // vk.ID4.x - mstore(add(_vk, 0x620), 0x228b6aee9124d7b8e657108584f7fa88fc43bcdb05fb3ec309eb3aa265a54468) // vk.ID4.y - mstore(add(_vk, 0x640), 0x00) // vk.contains_recursive_proof - mstore(add(_vk, 0x660), 0) // vk.recursive_proof_public_input_indices - mstore(add(_vk, 0x680), 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1) // vk.g2_x.X.c1 - mstore(add(_vk, 0x6a0), 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0) // vk.g2_x.X.c0 - mstore(add(_vk, 0x6c0), 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4) // vk.g2_x.Y.c1 - mstore(add(_vk, 0x6e0), 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55) // vk.g2_x.Y.c0 - mstore(_omegaInverseLoc, 0x05d33766e4590b3722701b6f2fa43d0dc3f028424d384e68c92a742fb2dbc0b4) // vk.work_root_inverse - } - } -} -/** - * @title Ultra Plonk proof verification contract - * @dev Top level Plonk proof verification contract, which allows Plonk proof to be verified - */ -abstract contract BaseUltraVerifier { - // VERIFICATION KEY MEMORY LOCATIONS - uint256 internal constant N_LOC = 0x380; - uint256 internal constant NUM_INPUTS_LOC = 0x3a0; - uint256 internal constant OMEGA_LOC = 0x3c0; - uint256 internal constant DOMAIN_INVERSE_LOC = 0x3e0; - uint256 internal constant Q1_X_LOC = 0x400; - uint256 internal constant Q1_Y_LOC = 0x420; - uint256 internal constant Q2_X_LOC = 0x440; - uint256 internal constant Q2_Y_LOC = 0x460; - uint256 internal constant Q3_X_LOC = 0x480; - uint256 internal constant Q3_Y_LOC = 0x4a0; - uint256 internal constant Q4_X_LOC = 0x4c0; - uint256 internal constant Q4_Y_LOC = 0x4e0; - uint256 internal constant QM_X_LOC = 0x500; - uint256 internal constant QM_Y_LOC = 0x520; - uint256 internal constant QC_X_LOC = 0x540; - uint256 internal constant QC_Y_LOC = 0x560; - uint256 internal constant QARITH_X_LOC = 0x580; - uint256 internal constant QARITH_Y_LOC = 0x5a0; - uint256 internal constant QSORT_X_LOC = 0x5c0; - uint256 internal constant QSORT_Y_LOC = 0x5e0; - uint256 internal constant QELLIPTIC_X_LOC = 0x600; - uint256 internal constant QELLIPTIC_Y_LOC = 0x620; - uint256 internal constant QAUX_X_LOC = 0x640; - uint256 internal constant QAUX_Y_LOC = 0x660; - uint256 internal constant SIGMA1_X_LOC = 0x680; - uint256 internal constant SIGMA1_Y_LOC = 0x6a0; - uint256 internal constant SIGMA2_X_LOC = 0x6c0; - uint256 internal constant SIGMA2_Y_LOC = 0x6e0; - uint256 internal constant SIGMA3_X_LOC = 0x700; - uint256 internal constant SIGMA3_Y_LOC = 0x720; - uint256 internal constant SIGMA4_X_LOC = 0x740; - uint256 internal constant SIGMA4_Y_LOC = 0x760; - uint256 internal constant TABLE1_X_LOC = 0x780; - uint256 internal constant TABLE1_Y_LOC = 0x7a0; - uint256 internal constant TABLE2_X_LOC = 0x7c0; - uint256 internal constant TABLE2_Y_LOC = 0x7e0; - uint256 internal constant TABLE3_X_LOC = 0x800; - uint256 internal constant TABLE3_Y_LOC = 0x820; - uint256 internal constant TABLE4_X_LOC = 0x840; - uint256 internal constant TABLE4_Y_LOC = 0x860; - uint256 internal constant TABLE_TYPE_X_LOC = 0x880; - uint256 internal constant TABLE_TYPE_Y_LOC = 0x8a0; - uint256 internal constant ID1_X_LOC = 0x8c0; - uint256 internal constant ID1_Y_LOC = 0x8e0; - uint256 internal constant ID2_X_LOC = 0x900; - uint256 internal constant ID2_Y_LOC = 0x920; - uint256 internal constant ID3_X_LOC = 0x940; - uint256 internal constant ID3_Y_LOC = 0x960; - uint256 internal constant ID4_X_LOC = 0x980; - uint256 internal constant ID4_Y_LOC = 0x9a0; - uint256 internal constant CONTAINS_RECURSIVE_PROOF_LOC = 0x9c0; - uint256 internal constant RECURSIVE_PROOF_PUBLIC_INPUT_INDICES_LOC = 0x9e0; - uint256 internal constant G2X_X0_LOC = 0xa00; - uint256 internal constant G2X_X1_LOC = 0xa20; - uint256 internal constant G2X_Y0_LOC = 0xa40; - uint256 internal constant G2X_Y1_LOC = 0xa60; - - // ### PROOF DATA MEMORY LOCATIONS - uint256 internal constant W1_X_LOC = 0x1200; - uint256 internal constant W1_Y_LOC = 0x1220; - uint256 internal constant W2_X_LOC = 0x1240; - uint256 internal constant W2_Y_LOC = 0x1260; - uint256 internal constant W3_X_LOC = 0x1280; - uint256 internal constant W3_Y_LOC = 0x12a0; - uint256 internal constant W4_X_LOC = 0x12c0; - uint256 internal constant W4_Y_LOC = 0x12e0; - uint256 internal constant S_X_LOC = 0x1300; - uint256 internal constant S_Y_LOC = 0x1320; - uint256 internal constant Z_X_LOC = 0x1340; - uint256 internal constant Z_Y_LOC = 0x1360; - uint256 internal constant Z_LOOKUP_X_LOC = 0x1380; - uint256 internal constant Z_LOOKUP_Y_LOC = 0x13a0; - uint256 internal constant T1_X_LOC = 0x13c0; - uint256 internal constant T1_Y_LOC = 0x13e0; - uint256 internal constant T2_X_LOC = 0x1400; - uint256 internal constant T2_Y_LOC = 0x1420; - uint256 internal constant T3_X_LOC = 0x1440; - uint256 internal constant T3_Y_LOC = 0x1460; - uint256 internal constant T4_X_LOC = 0x1480; - uint256 internal constant T4_Y_LOC = 0x14a0; - - uint256 internal constant W1_EVAL_LOC = 0x1600; - uint256 internal constant W2_EVAL_LOC = 0x1620; - uint256 internal constant W3_EVAL_LOC = 0x1640; - uint256 internal constant W4_EVAL_LOC = 0x1660; - uint256 internal constant S_EVAL_LOC = 0x1680; - uint256 internal constant Z_EVAL_LOC = 0x16a0; - uint256 internal constant Z_LOOKUP_EVAL_LOC = 0x16c0; - uint256 internal constant Q1_EVAL_LOC = 0x16e0; - uint256 internal constant Q2_EVAL_LOC = 0x1700; - uint256 internal constant Q3_EVAL_LOC = 0x1720; - uint256 internal constant Q4_EVAL_LOC = 0x1740; - uint256 internal constant QM_EVAL_LOC = 0x1760; - uint256 internal constant QC_EVAL_LOC = 0x1780; - uint256 internal constant QARITH_EVAL_LOC = 0x17a0; - uint256 internal constant QSORT_EVAL_LOC = 0x17c0; - uint256 internal constant QELLIPTIC_EVAL_LOC = 0x17e0; - uint256 internal constant QAUX_EVAL_LOC = 0x1800; - uint256 internal constant TABLE1_EVAL_LOC = 0x1840; - uint256 internal constant TABLE2_EVAL_LOC = 0x1860; - uint256 internal constant TABLE3_EVAL_LOC = 0x1880; - uint256 internal constant TABLE4_EVAL_LOC = 0x18a0; - uint256 internal constant TABLE_TYPE_EVAL_LOC = 0x18c0; - uint256 internal constant ID1_EVAL_LOC = 0x18e0; - uint256 internal constant ID2_EVAL_LOC = 0x1900; - uint256 internal constant ID3_EVAL_LOC = 0x1920; - uint256 internal constant ID4_EVAL_LOC = 0x1940; - uint256 internal constant SIGMA1_EVAL_LOC = 0x1960; - uint256 internal constant SIGMA2_EVAL_LOC = 0x1980; - uint256 internal constant SIGMA3_EVAL_LOC = 0x19a0; - uint256 internal constant SIGMA4_EVAL_LOC = 0x19c0; - uint256 internal constant W1_OMEGA_EVAL_LOC = 0x19e0; - uint256 internal constant W2_OMEGA_EVAL_LOC = 0x2000; - uint256 internal constant W3_OMEGA_EVAL_LOC = 0x2020; - uint256 internal constant W4_OMEGA_EVAL_LOC = 0x2040; - uint256 internal constant S_OMEGA_EVAL_LOC = 0x2060; - uint256 internal constant Z_OMEGA_EVAL_LOC = 0x2080; - uint256 internal constant Z_LOOKUP_OMEGA_EVAL_LOC = 0x20a0; - uint256 internal constant TABLE1_OMEGA_EVAL_LOC = 0x20c0; - uint256 internal constant TABLE2_OMEGA_EVAL_LOC = 0x20e0; - uint256 internal constant TABLE3_OMEGA_EVAL_LOC = 0x2100; - uint256 internal constant TABLE4_OMEGA_EVAL_LOC = 0x2120; - - uint256 internal constant PI_Z_X_LOC = 0x2300; - uint256 internal constant PI_Z_Y_LOC = 0x2320; - uint256 internal constant PI_Z_OMEGA_X_LOC = 0x2340; - uint256 internal constant PI_Z_OMEGA_Y_LOC = 0x2360; - - // Used for elliptic widget. These are alias names for wire + shifted wire evaluations - uint256 internal constant X1_EVAL_LOC = W2_EVAL_LOC; - uint256 internal constant X2_EVAL_LOC = W1_OMEGA_EVAL_LOC; - uint256 internal constant X3_EVAL_LOC = W2_OMEGA_EVAL_LOC; - uint256 internal constant Y1_EVAL_LOC = W3_EVAL_LOC; - uint256 internal constant Y2_EVAL_LOC = W4_OMEGA_EVAL_LOC; - uint256 internal constant Y3_EVAL_LOC = W3_OMEGA_EVAL_LOC; - uint256 internal constant QBETA_LOC = Q3_EVAL_LOC; - uint256 internal constant QBETA_SQR_LOC = Q4_EVAL_LOC; - uint256 internal constant QSIGN_LOC = Q1_EVAL_LOC; - - // ### CHALLENGES MEMORY OFFSETS - - uint256 internal constant C_BETA_LOC = 0x2600; - uint256 internal constant C_GAMMA_LOC = 0x2620; - uint256 internal constant C_ALPHA_LOC = 0x2640; - uint256 internal constant C_ETA_LOC = 0x2660; - uint256 internal constant C_ETA_SQR_LOC = 0x2680; - uint256 internal constant C_ETA_CUBE_LOC = 0x26a0; - - uint256 internal constant C_ZETA_LOC = 0x26c0; - uint256 internal constant C_CURRENT_LOC = 0x26e0; - uint256 internal constant C_V0_LOC = 0x2700; - uint256 internal constant C_V1_LOC = 0x2720; - uint256 internal constant C_V2_LOC = 0x2740; - uint256 internal constant C_V3_LOC = 0x2760; - uint256 internal constant C_V4_LOC = 0x2780; - uint256 internal constant C_V5_LOC = 0x27a0; - uint256 internal constant C_V6_LOC = 0x27c0; - uint256 internal constant C_V7_LOC = 0x27e0; - uint256 internal constant C_V8_LOC = 0x2800; - uint256 internal constant C_V9_LOC = 0x2820; - uint256 internal constant C_V10_LOC = 0x2840; - uint256 internal constant C_V11_LOC = 0x2860; - uint256 internal constant C_V12_LOC = 0x2880; - uint256 internal constant C_V13_LOC = 0x28a0; - uint256 internal constant C_V14_LOC = 0x28c0; - uint256 internal constant C_V15_LOC = 0x28e0; - uint256 internal constant C_V16_LOC = 0x2900; - uint256 internal constant C_V17_LOC = 0x2920; - uint256 internal constant C_V18_LOC = 0x2940; - uint256 internal constant C_V19_LOC = 0x2960; - uint256 internal constant C_V20_LOC = 0x2980; - uint256 internal constant C_V21_LOC = 0x29a0; - uint256 internal constant C_V22_LOC = 0x29c0; - uint256 internal constant C_V23_LOC = 0x29e0; - uint256 internal constant C_V24_LOC = 0x2a00; - uint256 internal constant C_V25_LOC = 0x2a20; - uint256 internal constant C_V26_LOC = 0x2a40; - uint256 internal constant C_V27_LOC = 0x2a60; - uint256 internal constant C_V28_LOC = 0x2a80; - uint256 internal constant C_V29_LOC = 0x2aa0; - uint256 internal constant C_V30_LOC = 0x2ac0; - - uint256 internal constant C_U_LOC = 0x2b00; - - // ### LOCAL VARIABLES MEMORY OFFSETS - uint256 internal constant DELTA_NUMERATOR_LOC = 0x3000; - uint256 internal constant DELTA_DENOMINATOR_LOC = 0x3020; - uint256 internal constant ZETA_POW_N_LOC = 0x3040; - uint256 internal constant PUBLIC_INPUT_DELTA_LOC = 0x3060; - uint256 internal constant ZERO_POLY_LOC = 0x3080; - uint256 internal constant L_START_LOC = 0x30a0; - uint256 internal constant L_END_LOC = 0x30c0; - uint256 internal constant R_ZERO_EVAL_LOC = 0x30e0; - - uint256 internal constant PLOOKUP_DELTA_NUMERATOR_LOC = 0x3100; - uint256 internal constant PLOOKUP_DELTA_DENOMINATOR_LOC = 0x3120; - uint256 internal constant PLOOKUP_DELTA_LOC = 0x3140; - - uint256 internal constant ACCUMULATOR_X_LOC = 0x3160; - uint256 internal constant ACCUMULATOR_Y_LOC = 0x3180; - uint256 internal constant ACCUMULATOR2_X_LOC = 0x31a0; - uint256 internal constant ACCUMULATOR2_Y_LOC = 0x31c0; - uint256 internal constant PAIRING_LHS_X_LOC = 0x31e0; - uint256 internal constant PAIRING_LHS_Y_LOC = 0x3200; - uint256 internal constant PAIRING_RHS_X_LOC = 0x3220; - uint256 internal constant PAIRING_RHS_Y_LOC = 0x3240; - - // ### SUCCESS FLAG MEMORY LOCATIONS - uint256 internal constant GRAND_PRODUCT_SUCCESS_FLAG = 0x3300; - uint256 internal constant ARITHMETIC_TERM_SUCCESS_FLAG = 0x3020; - uint256 internal constant BATCH_OPENING_SUCCESS_FLAG = 0x3340; - uint256 internal constant OPENING_COMMITMENT_SUCCESS_FLAG = 0x3360; - uint256 internal constant PAIRING_PREAMBLE_SUCCESS_FLAG = 0x3380; - uint256 internal constant PAIRING_SUCCESS_FLAG = 0x33a0; - uint256 internal constant RESULT_FLAG = 0x33c0; - - // misc stuff - uint256 internal constant OMEGA_INVERSE_LOC = 0x3400; - uint256 internal constant C_ALPHA_SQR_LOC = 0x3420; - uint256 internal constant C_ALPHA_CUBE_LOC = 0x3440; - uint256 internal constant C_ALPHA_QUAD_LOC = 0x3460; - uint256 internal constant C_ALPHA_BASE_LOC = 0x3480; - - // ### RECURSION VARIABLE MEMORY LOCATIONS - uint256 internal constant RECURSIVE_P1_X_LOC = 0x3500; - uint256 internal constant RECURSIVE_P1_Y_LOC = 0x3520; - uint256 internal constant RECURSIVE_P2_X_LOC = 0x3540; - uint256 internal constant RECURSIVE_P2_Y_LOC = 0x3560; - - uint256 internal constant PUBLIC_INPUTS_HASH_LOCATION = 0x3580; - - // sub-identity storage - uint256 internal constant PERMUTATION_IDENTITY = 0x3600; - uint256 internal constant PLOOKUP_IDENTITY = 0x3620; - uint256 internal constant ARITHMETIC_IDENTITY = 0x3640; - uint256 internal constant SORT_IDENTITY = 0x3660; - uint256 internal constant ELLIPTIC_IDENTITY = 0x3680; - uint256 internal constant AUX_IDENTITY = 0x36a0; - uint256 internal constant AUX_NON_NATIVE_FIELD_EVALUATION = 0x36c0; - uint256 internal constant AUX_LIMB_ACCUMULATOR_EVALUATION = 0x36e0; - uint256 internal constant AUX_RAM_CONSISTENCY_EVALUATION = 0x3700; - uint256 internal constant AUX_ROM_CONSISTENCY_EVALUATION = 0x3720; - uint256 internal constant AUX_MEMORY_EVALUATION = 0x3740; - - uint256 internal constant QUOTIENT_EVAL_LOC = 0x3760; - uint256 internal constant ZERO_POLY_INVERSE_LOC = 0x3780; - - // when hashing public inputs we use memory at NU_CHALLENGE_INPUT_LOC_A, as the hash input size is unknown at compile time - uint256 internal constant NU_CHALLENGE_INPUT_LOC_A = 0x37a0; - uint256 internal constant NU_CHALLENGE_INPUT_LOC_B = 0x37c0; - uint256 internal constant NU_CHALLENGE_INPUT_LOC_C = 0x37e0; - - bytes4 internal constant PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR = 0xeba9f4a6; - bytes4 internal constant PUBLIC_INPUT_GE_P_SELECTOR = 0x374a972f; - bytes4 internal constant MOD_EXP_FAILURE_SELECTOR = 0xf894a7bc; - bytes4 internal constant EC_SCALAR_MUL_FAILURE_SELECTOR = 0xf755f369; - bytes4 internal constant PROOF_FAILURE_SELECTOR = 0x0711fcec; - - uint256 internal constant ETA_INPUT_LENGTH = 0xc0; // W1, W2, W3 = 6 * 0x20 bytes - - // We need to hash 41 field elements when generating the NU challenge - // w1, w2, w3, w4, s, z, z_lookup, q1, q2, q3, q4, qm, qc, qarith (14) - // qsort, qelliptic, qaux, sigma1, sigma2, sigma, sigma4, (7) - // table1, table2, table3, table4, tabletype, id1, id2, id3, id4, (9) - // w1_omega, w2_omega, w3_omega, w4_omega, s_omega, z_omega, z_lookup_omega, (7) - // table1_omega, table2_omega, table3_omega, table4_omega (4) - uint256 internal constant NU_INPUT_LENGTH = 0x520; // 0x520 = 41 * 0x20 - - // There are ELEVEN G1 group elements added into the transcript in the `beta` round, that we need to skip over - // W1, W2, W3, W4, S, Z, Z_LOOKUP, T1, T2, T3, T4 - uint256 internal constant NU_CALLDATA_SKIP_LENGTH = 0x2c0; // 11 * 0x40 = 0x2c0 - - uint256 internal constant NEGATIVE_INVERSE_OF_2_MODULO_P = - 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000; - uint256 internal constant LIMB_SIZE = 0x100000000000000000; // 2<<68 - uint256 internal constant SUBLIMB_SHIFT = 0x4000; // 2<<14 - - // y^2 = x^3 + ax + b - // for Grumpkin, a = 0 and b = -17. We use b in a custom gate relation that evaluates elliptic curve arithmetic - uint256 internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = 17; - error PUBLIC_INPUT_COUNT_INVALID(uint256 expected, uint256 actual); - error PUBLIC_INPUT_INVALID_BN128_G1_POINT(); - error PUBLIC_INPUT_GE_P(); - error MOD_EXP_FAILURE(); - error EC_SCALAR_MUL_FAILURE(); - error PROOF_FAILURE(); - - function getVerificationKeyHash() public pure virtual returns (bytes32); - - function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure virtual; - - /** - * @notice Verify a Ultra Plonk proof - * @param _proof - The serialized proof - * @param _publicInputs - An array of the public inputs - * @return True if proof is valid, reverts otherwise - */ - function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) { - loadVerificationKey(N_LOC, OMEGA_INVERSE_LOC); - - uint256 requiredPublicInputCount; - assembly { - requiredPublicInputCount := mload(NUM_INPUTS_LOC) - } - if (requiredPublicInputCount != _publicInputs.length) { - revert PUBLIC_INPUT_COUNT_INVALID(requiredPublicInputCount, _publicInputs.length); - } - - assembly { - let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // EC group order - let p := 21888242871839275222246405745257275088548364400416034343698204186575808495617 // Prime field order - - /** - * LOAD PROOF FROM CALLDATA - */ - { - let data_ptr := add(calldataload(0x04), 0x24) - - mstore(W1_Y_LOC, mod(calldataload(data_ptr), q)) - mstore(W1_X_LOC, mod(calldataload(add(data_ptr, 0x20)), q)) - - mstore(W2_Y_LOC, mod(calldataload(add(data_ptr, 0x40)), q)) - mstore(W2_X_LOC, mod(calldataload(add(data_ptr, 0x60)), q)) - - mstore(W3_Y_LOC, mod(calldataload(add(data_ptr, 0x80)), q)) - mstore(W3_X_LOC, mod(calldataload(add(data_ptr, 0xa0)), q)) - - mstore(W4_Y_LOC, mod(calldataload(add(data_ptr, 0xc0)), q)) - mstore(W4_X_LOC, mod(calldataload(add(data_ptr, 0xe0)), q)) - - mstore(S_Y_LOC, mod(calldataload(add(data_ptr, 0x100)), q)) - mstore(S_X_LOC, mod(calldataload(add(data_ptr, 0x120)), q)) - mstore(Z_Y_LOC, mod(calldataload(add(data_ptr, 0x140)), q)) - mstore(Z_X_LOC, mod(calldataload(add(data_ptr, 0x160)), q)) - mstore(Z_LOOKUP_Y_LOC, mod(calldataload(add(data_ptr, 0x180)), q)) - mstore(Z_LOOKUP_X_LOC, mod(calldataload(add(data_ptr, 0x1a0)), q)) - mstore(T1_Y_LOC, mod(calldataload(add(data_ptr, 0x1c0)), q)) - mstore(T1_X_LOC, mod(calldataload(add(data_ptr, 0x1e0)), q)) - - mstore(T2_Y_LOC, mod(calldataload(add(data_ptr, 0x200)), q)) - mstore(T2_X_LOC, mod(calldataload(add(data_ptr, 0x220)), q)) - - mstore(T3_Y_LOC, mod(calldataload(add(data_ptr, 0x240)), q)) - mstore(T3_X_LOC, mod(calldataload(add(data_ptr, 0x260)), q)) - - mstore(T4_Y_LOC, mod(calldataload(add(data_ptr, 0x280)), q)) - mstore(T4_X_LOC, mod(calldataload(add(data_ptr, 0x2a0)), q)) - - mstore(W1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x2c0)), p)) - mstore(W2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x2e0)), p)) - mstore(W3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x300)), p)) - mstore(W4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x320)), p)) - mstore(S_EVAL_LOC, mod(calldataload(add(data_ptr, 0x340)), p)) - mstore(Z_EVAL_LOC, mod(calldataload(add(data_ptr, 0x360)), p)) - mstore(Z_LOOKUP_EVAL_LOC, mod(calldataload(add(data_ptr, 0x380)), p)) - mstore(Q1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3a0)), p)) - mstore(Q2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3c0)), p)) - mstore(Q3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3e0)), p)) - mstore(Q4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x400)), p)) - mstore(QM_EVAL_LOC, mod(calldataload(add(data_ptr, 0x420)), p)) - mstore(QC_EVAL_LOC, mod(calldataload(add(data_ptr, 0x440)), p)) - mstore(QARITH_EVAL_LOC, mod(calldataload(add(data_ptr, 0x460)), p)) - mstore(QSORT_EVAL_LOC, mod(calldataload(add(data_ptr, 0x480)), p)) - mstore(QELLIPTIC_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4a0)), p)) - mstore(QAUX_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4c0)), p)) - - mstore(SIGMA1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4e0)), p)) - mstore(SIGMA2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x500)), p)) - - mstore(SIGMA3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x520)), p)) - mstore(SIGMA4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x540)), p)) - - mstore(TABLE1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x560)), p)) - mstore(TABLE2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x580)), p)) - mstore(TABLE3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5a0)), p)) - mstore(TABLE4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5c0)), p)) - mstore(TABLE_TYPE_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5e0)), p)) - - mstore(ID1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x600)), p)) - mstore(ID2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x620)), p)) - mstore(ID3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x640)), p)) - mstore(ID4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x660)), p)) - - mstore(W1_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x680)), p)) - mstore(W2_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6a0)), p)) - mstore(W3_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6c0)), p)) - mstore(W4_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6e0)), p)) - mstore(S_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x700)), p)) - - mstore(Z_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x720)), p)) - - mstore(Z_LOOKUP_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x740)), p)) - mstore(TABLE1_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x760)), p)) - mstore(TABLE2_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x780)), p)) - mstore(TABLE3_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x7a0)), p)) - mstore(TABLE4_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x7c0)), p)) - - mstore(PI_Z_Y_LOC, mod(calldataload(add(data_ptr, 0x7e0)), q)) - mstore(PI_Z_X_LOC, mod(calldataload(add(data_ptr, 0x800)), q)) - - mstore(PI_Z_OMEGA_Y_LOC, mod(calldataload(add(data_ptr, 0x820)), q)) - mstore(PI_Z_OMEGA_X_LOC, mod(calldataload(add(data_ptr, 0x840)), q)) - } - - /** - * LOAD RECURSIVE PROOF INTO MEMORY - */ - { - if mload(CONTAINS_RECURSIVE_PROOF_LOC) { - let public_inputs_ptr := add(calldataload(0x24), 0x24) - let index_counter := add(shl(5, mload(RECURSIVE_PROOF_PUBLIC_INPUT_INDICES_LOC)), public_inputs_ptr) - - let x0 := calldataload(index_counter) - x0 := add(x0, shl(68, calldataload(add(index_counter, 0x20)))) - x0 := add(x0, shl(136, calldataload(add(index_counter, 0x40)))) - x0 := add(x0, shl(204, calldataload(add(index_counter, 0x60)))) - let y0 := calldataload(add(index_counter, 0x80)) - y0 := add(y0, shl(68, calldataload(add(index_counter, 0xa0)))) - y0 := add(y0, shl(136, calldataload(add(index_counter, 0xc0)))) - y0 := add(y0, shl(204, calldataload(add(index_counter, 0xe0)))) - let x1 := calldataload(add(index_counter, 0x100)) - x1 := add(x1, shl(68, calldataload(add(index_counter, 0x120)))) - x1 := add(x1, shl(136, calldataload(add(index_counter, 0x140)))) - x1 := add(x1, shl(204, calldataload(add(index_counter, 0x160)))) - let y1 := calldataload(add(index_counter, 0x180)) - y1 := add(y1, shl(68, calldataload(add(index_counter, 0x1a0)))) - y1 := add(y1, shl(136, calldataload(add(index_counter, 0x1c0)))) - y1 := add(y1, shl(204, calldataload(add(index_counter, 0x1e0)))) - mstore(RECURSIVE_P1_X_LOC, x0) - mstore(RECURSIVE_P1_Y_LOC, y0) - mstore(RECURSIVE_P2_X_LOC, x1) - mstore(RECURSIVE_P2_Y_LOC, y1) - - // validate these are valid bn128 G1 points - if iszero(and(and(lt(x0, q), lt(x1, q)), and(lt(y0, q), lt(y1, q)))) { - mstore(0x00, PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR) - revert(0x00, 0x04) - } - } - } - - { - /** - * Generate initial challenge - */ - mstore(0x00, shl(224, mload(N_LOC))) - mstore(0x04, shl(224, mload(NUM_INPUTS_LOC))) - let challenge := keccak256(0x00, 0x08) - - /** - * Generate eta challenge - */ - mstore(PUBLIC_INPUTS_HASH_LOCATION, challenge) - // The public input location is stored at 0x24, we then add 0x24 to skip selector and the length of public inputs - let public_inputs_start := add(calldataload(0x24), 0x24) - // copy the public inputs over - let public_input_size := mul(mload(NUM_INPUTS_LOC), 0x20) - calldatacopy(add(PUBLIC_INPUTS_HASH_LOCATION, 0x20), public_inputs_start, public_input_size) - - // copy W1, W2, W3 into challenge. Each point is 0x40 bytes, so load 0xc0 = 3 * 0x40 bytes (ETA input length) - let w_start := add(calldataload(0x04), 0x24) - calldatacopy(add(add(PUBLIC_INPUTS_HASH_LOCATION, 0x20), public_input_size), w_start, ETA_INPUT_LENGTH) - - // Challenge is the old challenge + public inputs + W1, W2, W3 (0x20 + public_input_size + 0xc0) - let challenge_bytes_size := add(0x20, add(public_input_size, ETA_INPUT_LENGTH)) - - challenge := keccak256(PUBLIC_INPUTS_HASH_LOCATION, challenge_bytes_size) - { - let eta := mod(challenge, p) - mstore(C_ETA_LOC, eta) - mstore(C_ETA_SQR_LOC, mulmod(eta, eta, p)) - mstore(C_ETA_CUBE_LOC, mulmod(mload(C_ETA_SQR_LOC), eta, p)) - } - - /** - * Generate beta challenge - */ - mstore(0x00, challenge) - mstore(0x20, mload(W4_Y_LOC)) - mstore(0x40, mload(W4_X_LOC)) - mstore(0x60, mload(S_Y_LOC)) - mstore(0x80, mload(S_X_LOC)) - challenge := keccak256(0x00, 0xa0) - mstore(C_BETA_LOC, mod(challenge, p)) - - /** - * Generate gamma challenge - */ - mstore(0x00, challenge) - mstore8(0x20, 0x01) - challenge := keccak256(0x00, 0x21) - mstore(C_GAMMA_LOC, mod(challenge, p)) - - /** - * Generate alpha challenge - */ - mstore(0x00, challenge) - mstore(0x20, mload(Z_Y_LOC)) - mstore(0x40, mload(Z_X_LOC)) - mstore(0x60, mload(Z_LOOKUP_Y_LOC)) - mstore(0x80, mload(Z_LOOKUP_X_LOC)) - challenge := keccak256(0x00, 0xa0) - mstore(C_ALPHA_LOC, mod(challenge, p)) - - /** - * Compute and store some powers of alpha for future computations - */ - let alpha := mload(C_ALPHA_LOC) - mstore(C_ALPHA_SQR_LOC, mulmod(alpha, alpha, p)) - mstore(C_ALPHA_CUBE_LOC, mulmod(mload(C_ALPHA_SQR_LOC), alpha, p)) - mstore(C_ALPHA_QUAD_LOC, mulmod(mload(C_ALPHA_CUBE_LOC), alpha, p)) - mstore(C_ALPHA_BASE_LOC, alpha) - - /** - * Generate zeta challenge - */ - mstore(0x00, challenge) - mstore(0x20, mload(T1_Y_LOC)) - mstore(0x40, mload(T1_X_LOC)) - mstore(0x60, mload(T2_Y_LOC)) - mstore(0x80, mload(T2_X_LOC)) - mstore(0xa0, mload(T3_Y_LOC)) - mstore(0xc0, mload(T3_X_LOC)) - mstore(0xe0, mload(T4_Y_LOC)) - mstore(0x100, mload(T4_X_LOC)) - - challenge := keccak256(0x00, 0x120) - - mstore(C_ZETA_LOC, mod(challenge, p)) - mstore(C_CURRENT_LOC, challenge) - } - - /** - * EVALUATE FIELD OPERATIONS - */ - - /** - * COMPUTE PUBLIC INPUT DELTA - * ΔPI = ∏ᵢ∈ℓ(wᵢ + β σ(i) + γ) / ∏ᵢ∈ℓ(wᵢ + β σ'(i) + γ) - */ - { - let beta := mload(C_BETA_LOC) // β - let gamma := mload(C_GAMMA_LOC) // γ - let work_root := mload(OMEGA_LOC) // ω - let numerator_value := 1 - let denominator_value := 1 - - let p_clone := p // move p to the front of the stack - let valid_inputs := true - - // Load the starting point of the public inputs (jump over the selector and the length of public inputs [0x24]) - let public_inputs_ptr := add(calldataload(0x24), 0x24) - - // endpoint_ptr = public_inputs_ptr + num_inputs * 0x20. // every public input is 0x20 bytes - let endpoint_ptr := add(public_inputs_ptr, mul(mload(NUM_INPUTS_LOC), 0x20)) - - // root_1 = β * 0x05 - let root_1 := mulmod(beta, 0x05, p_clone) // k1.β - // root_2 = β * 0x0c - let root_2 := mulmod(beta, 0x0c, p_clone) - // @note 0x05 + 0x07 == 0x0c == external coset generator - - for {} lt(public_inputs_ptr, endpoint_ptr) { public_inputs_ptr := add(public_inputs_ptr, 0x20) } { - /** - * input = public_input[i] - * valid_inputs &= input < p - * temp = input + gamma - * numerator_value *= (β.σ(i) + wᵢ + γ) // σ(i) = 0x05.ωⁱ - * denominator_value *= (β.σ'(i) + wᵢ + γ) // σ'(i) = 0x0c.ωⁱ - * root_1 *= ω - * root_2 *= ω - */ - - let input := calldataload(public_inputs_ptr) - valid_inputs := and(valid_inputs, lt(input, p_clone)) - let temp := addmod(input, gamma, p_clone) - - numerator_value := mulmod(numerator_value, add(root_1, temp), p_clone) - denominator_value := mulmod(denominator_value, add(root_2, temp), p_clone) - - root_1 := mulmod(root_1, work_root, p_clone) - root_2 := mulmod(root_2, work_root, p_clone) - } - - // Revert if not all public inputs are field elements (i.e. < p) - if iszero(valid_inputs) { - mstore(0x00, PUBLIC_INPUT_GE_P_SELECTOR) - revert(0x00, 0x04) - } - - mstore(DELTA_NUMERATOR_LOC, numerator_value) - mstore(DELTA_DENOMINATOR_LOC, denominator_value) - } - - /** - * Compute Plookup delta factor [γ(1 + β)]^{n-k} - * k = num roots cut out of Z_H = 4 - */ - { - let delta_base := mulmod(mload(C_GAMMA_LOC), addmod(mload(C_BETA_LOC), 1, p), p) - let delta_numerator := delta_base - { - let exponent := mload(N_LOC) - let count := 1 - for {} lt(count, exponent) { count := add(count, count) } { - delta_numerator := mulmod(delta_numerator, delta_numerator, p) - } - } - mstore(PLOOKUP_DELTA_NUMERATOR_LOC, delta_numerator) - - let delta_denominator := mulmod(delta_base, delta_base, p) - delta_denominator := mulmod(delta_denominator, delta_denominator, p) - mstore(PLOOKUP_DELTA_DENOMINATOR_LOC, delta_denominator) - } - /** - * Compute lagrange poly and vanishing poly fractions - */ - { - /** - * vanishing_numerator = zeta - * ZETA_POW_N = zeta^n - * vanishing_numerator -= 1 - * accumulating_root = omega_inverse - * work_root = p - accumulating_root - * domain_inverse = domain_inverse - * vanishing_denominator = zeta + work_root - * work_root *= accumulating_root - * vanishing_denominator *= (zeta + work_root) - * work_root *= accumulating_root - * vanishing_denominator *= (zeta + work_root) - * vanishing_denominator *= (zeta + (zeta + accumulating_root)) - * work_root = omega - * lagrange_numerator = vanishing_numerator * domain_inverse - * l_start_denominator = zeta - 1 - * accumulating_root = work_root^2 - * l_end_denominator = accumulating_root^2 * work_root * zeta - 1 - * Note: l_end_denominator term contains a term \omega^5 to cut out 5 roots of unity from vanishing poly - */ - - let zeta := mload(C_ZETA_LOC) - - // compute zeta^n, where n is a power of 2 - let vanishing_numerator := zeta - { - // pow_small - let exponent := mload(N_LOC) - let count := 1 - for {} lt(count, exponent) { count := add(count, count) } { - vanishing_numerator := mulmod(vanishing_numerator, vanishing_numerator, p) - } - } - mstore(ZETA_POW_N_LOC, vanishing_numerator) - vanishing_numerator := addmod(vanishing_numerator, sub(p, 1), p) - - let accumulating_root := mload(OMEGA_INVERSE_LOC) - let work_root := sub(p, accumulating_root) - let domain_inverse := mload(DOMAIN_INVERSE_LOC) - - let vanishing_denominator := addmod(zeta, work_root, p) - work_root := mulmod(work_root, accumulating_root, p) - vanishing_denominator := mulmod(vanishing_denominator, addmod(zeta, work_root, p), p) - work_root := mulmod(work_root, accumulating_root, p) - vanishing_denominator := mulmod(vanishing_denominator, addmod(zeta, work_root, p), p) - vanishing_denominator := - mulmod(vanishing_denominator, addmod(zeta, mulmod(work_root, accumulating_root, p), p), p) - - work_root := mload(OMEGA_LOC) - - let lagrange_numerator := mulmod(vanishing_numerator, domain_inverse, p) - let l_start_denominator := addmod(zeta, sub(p, 1), p) - - accumulating_root := mulmod(work_root, work_root, p) - - let l_end_denominator := - addmod( - mulmod(mulmod(mulmod(accumulating_root, accumulating_root, p), work_root, p), zeta, p), sub(p, 1), p - ) - - /** - * Compute inversions using Montgomery's batch inversion trick - */ - let accumulator := mload(DELTA_DENOMINATOR_LOC) - let t0 := accumulator - accumulator := mulmod(accumulator, vanishing_denominator, p) - let t1 := accumulator - accumulator := mulmod(accumulator, vanishing_numerator, p) - let t2 := accumulator - accumulator := mulmod(accumulator, l_start_denominator, p) - let t3 := accumulator - accumulator := mulmod(accumulator, mload(PLOOKUP_DELTA_DENOMINATOR_LOC), p) - let t4 := accumulator - { - mstore(0, 0x20) - mstore(0x20, 0x20) - mstore(0x40, 0x20) - mstore(0x60, mulmod(accumulator, l_end_denominator, p)) - mstore(0x80, sub(p, 2)) - mstore(0xa0, p) - if iszero(staticcall(gas(), 0x05, 0x00, 0xc0, 0x00, 0x20)) { - mstore(0x0, MOD_EXP_FAILURE_SELECTOR) - revert(0x00, 0x04) - } - accumulator := mload(0x00) - } - - t4 := mulmod(accumulator, t4, p) - accumulator := mulmod(accumulator, l_end_denominator, p) - - t3 := mulmod(accumulator, t3, p) - accumulator := mulmod(accumulator, mload(PLOOKUP_DELTA_DENOMINATOR_LOC), p) - - t2 := mulmod(accumulator, t2, p) - accumulator := mulmod(accumulator, l_start_denominator, p) - - t1 := mulmod(accumulator, t1, p) - accumulator := mulmod(accumulator, vanishing_numerator, p) - - t0 := mulmod(accumulator, t0, p) - accumulator := mulmod(accumulator, vanishing_denominator, p) - - accumulator := mulmod(mulmod(accumulator, accumulator, p), mload(DELTA_DENOMINATOR_LOC), p) - - mstore(PUBLIC_INPUT_DELTA_LOC, mulmod(mload(DELTA_NUMERATOR_LOC), accumulator, p)) - mstore(ZERO_POLY_LOC, mulmod(vanishing_numerator, t0, p)) - mstore(ZERO_POLY_INVERSE_LOC, mulmod(vanishing_denominator, t1, p)) - mstore(L_START_LOC, mulmod(lagrange_numerator, t2, p)) - mstore(PLOOKUP_DELTA_LOC, mulmod(mload(PLOOKUP_DELTA_NUMERATOR_LOC), t3, p)) - mstore(L_END_LOC, mulmod(lagrange_numerator, t4, p)) - } - - /** - * UltraPlonk Widget Ordering: - * - * 1. Permutation widget - * 2. Plookup widget - * 3. Arithmetic widget - * 4. Fixed base widget (?) - * 5. GenPermSort widget - * 6. Elliptic widget - * 7. Auxiliary widget - */ - - /** - * COMPUTE PERMUTATION WIDGET EVALUATION - */ - { - let alpha := mload(C_ALPHA_LOC) - let beta := mload(C_BETA_LOC) - let gamma := mload(C_GAMMA_LOC) - - /** - * t1 = (W1 + gamma + beta * ID1) * (W2 + gamma + beta * ID2) - * t2 = (W3 + gamma + beta * ID3) * (W4 + gamma + beta * ID4) - * result = alpha_base * z_eval * t1 * t2 - * t1 = (W1 + gamma + beta * sigma_1_eval) * (W2 + gamma + beta * sigma_2_eval) - * t2 = (W2 + gamma + beta * sigma_3_eval) * (W3 + gamma + beta * sigma_4_eval) - * result -= (alpha_base * z_omega_eval * t1 * t2) - */ - let t1 := - mulmod( - add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(ID1_EVAL_LOC), p)), - add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(ID2_EVAL_LOC), p)), - p - ) - let t2 := - mulmod( - add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(ID3_EVAL_LOC), p)), - add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(ID4_EVAL_LOC), p)), - p - ) - let result := mulmod(mload(C_ALPHA_BASE_LOC), mulmod(mload(Z_EVAL_LOC), mulmod(t1, t2, p), p), p) - t1 := - mulmod( - add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA1_EVAL_LOC), p)), - add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA2_EVAL_LOC), p)), - p - ) - t2 := - mulmod( - add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA3_EVAL_LOC), p)), - add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA4_EVAL_LOC), p)), - p - ) - result := - addmod( - result, - sub(p, mulmod(mload(C_ALPHA_BASE_LOC), mulmod(mload(Z_OMEGA_EVAL_LOC), mulmod(t1, t2, p), p), p)), - p - ) - - /** - * alpha_base *= alpha - * result += alpha_base . (L_{n-k}(ʓ) . (z(ʓ.ω) - ∆_{PI})) - * alpha_base *= alpha - * result += alpha_base . (L_1(ʓ)(Z(ʓ) - 1)) - * alpha_Base *= alpha - */ - mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p)) - result := - addmod( - result, - mulmod( - mload(C_ALPHA_BASE_LOC), - mulmod( - mload(L_END_LOC), - addmod(mload(Z_OMEGA_EVAL_LOC), sub(p, mload(PUBLIC_INPUT_DELTA_LOC)), p), - p - ), - p - ), - p - ) - mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p)) - mstore( - PERMUTATION_IDENTITY, - addmod( - result, - mulmod( - mload(C_ALPHA_BASE_LOC), - mulmod(mload(L_START_LOC), addmod(mload(Z_EVAL_LOC), sub(p, 1), p), p), - p - ), - p - ) - ) - mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p)) - } - - /** - * COMPUTE PLOOKUP WIDGET EVALUATION - */ - { - /** - * Goal: f = (w1(z) + q2.w1(zω)) + η(w2(z) + qm.w2(zω)) + η²(w3(z) + qc.w_3(zω)) + q3(z).η³ - * f = η.q3(z) - * f += (w3(z) + qc.w_3(zω)) - * f *= η - * f += (w2(z) + qm.w2(zω)) - * f *= η - * f += (w1(z) + q2.w1(zω)) - */ - let f := mulmod(mload(C_ETA_LOC), mload(Q3_EVAL_LOC), p) - f := - addmod(f, addmod(mload(W3_EVAL_LOC), mulmod(mload(QC_EVAL_LOC), mload(W3_OMEGA_EVAL_LOC), p), p), p) - f := mulmod(f, mload(C_ETA_LOC), p) - f := - addmod(f, addmod(mload(W2_EVAL_LOC), mulmod(mload(QM_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), p), p) - f := mulmod(f, mload(C_ETA_LOC), p) - f := - addmod(f, addmod(mload(W1_EVAL_LOC), mulmod(mload(Q2_EVAL_LOC), mload(W1_OMEGA_EVAL_LOC), p), p), p) - - // t(z) = table4(z).η³ + table3(z).η² + table2(z).η + table1(z) - let t := - addmod( - addmod( - addmod( - mulmod(mload(TABLE4_EVAL_LOC), mload(C_ETA_CUBE_LOC), p), - mulmod(mload(TABLE3_EVAL_LOC), mload(C_ETA_SQR_LOC), p), - p - ), - mulmod(mload(TABLE2_EVAL_LOC), mload(C_ETA_LOC), p), - p - ), - mload(TABLE1_EVAL_LOC), - p - ) - - // t(zw) = table4(zw).η³ + table3(zw).η² + table2(zw).η + table1(zw) - let t_omega := - addmod( - addmod( - addmod( - mulmod(mload(TABLE4_OMEGA_EVAL_LOC), mload(C_ETA_CUBE_LOC), p), - mulmod(mload(TABLE3_OMEGA_EVAL_LOC), mload(C_ETA_SQR_LOC), p), - p - ), - mulmod(mload(TABLE2_OMEGA_EVAL_LOC), mload(C_ETA_LOC), p), - p - ), - mload(TABLE1_OMEGA_EVAL_LOC), - p - ) - - /** - * Goal: numerator = (TABLE_TYPE_EVAL * f(z) + γ) * (t(z) + βt(zω) + γ(β + 1)) * (β + 1) - * gamma_beta_constant = γ(β + 1) - * numerator = f * TABLE_TYPE_EVAL + gamma - * temp0 = t(z) + t(zω) * β + gamma_beta_constant - * numerator *= temp0 - * numerator *= (β + 1) - * temp0 = alpha * l_1 - * numerator += temp0 - * numerator *= z_lookup(z) - * numerator -= temp0 - */ - let gamma_beta_constant := mulmod(mload(C_GAMMA_LOC), addmod(mload(C_BETA_LOC), 1, p), p) - let numerator := addmod(mulmod(f, mload(TABLE_TYPE_EVAL_LOC), p), mload(C_GAMMA_LOC), p) - let temp0 := addmod(addmod(t, mulmod(t_omega, mload(C_BETA_LOC), p), p), gamma_beta_constant, p) - numerator := mulmod(numerator, temp0, p) - numerator := mulmod(numerator, addmod(mload(C_BETA_LOC), 1, p), p) - temp0 := mulmod(mload(C_ALPHA_LOC), mload(L_START_LOC), p) - numerator := addmod(numerator, temp0, p) - numerator := mulmod(numerator, mload(Z_LOOKUP_EVAL_LOC), p) - numerator := addmod(numerator, sub(p, temp0), p) - - /** - * Goal: denominator = z_lookup(zω)*[s(z) + βs(zω) + γ(1 + β)] - [z_lookup(zω) - [γ(1 + β)]^{n-k}]*α²L_end(z) - * note: delta_factor = [γ(1 + β)]^{n-k} - * denominator = s(z) + βs(zω) + γ(β + 1) - * temp1 = α²L_end(z) - * denominator -= temp1 - * denominator *= z_lookup(zω) - * denominator += temp1 * delta_factor - * PLOOKUP_IDENTITY = (numerator - denominator).alpha_base - * alpha_base *= alpha^3 - */ - let denominator := - addmod( - addmod(mload(S_EVAL_LOC), mulmod(mload(S_OMEGA_EVAL_LOC), mload(C_BETA_LOC), p), p), - gamma_beta_constant, - p - ) - let temp1 := mulmod(mload(C_ALPHA_SQR_LOC), mload(L_END_LOC), p) - denominator := addmod(denominator, sub(p, temp1), p) - denominator := mulmod(denominator, mload(Z_LOOKUP_OMEGA_EVAL_LOC), p) - denominator := addmod(denominator, mulmod(temp1, mload(PLOOKUP_DELTA_LOC), p), p) - - mstore(PLOOKUP_IDENTITY, mulmod(addmod(numerator, sub(p, denominator), p), mload(C_ALPHA_BASE_LOC), p)) - - // update alpha - mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p)) - } - - /** - * COMPUTE ARITHMETIC WIDGET EVALUATION - */ - { - /** - * The basic arithmetic gate identity in standard plonk is as follows. - * (w_1 . w_2 . q_m) + (w_1 . q_1) + (w_2 . q_2) + (w_3 . q_3) + (w_4 . q_4) + q_c = 0 - * However, for Ultraplonk, we extend this to support "passing" wires between rows (shown without alpha scaling below): - * q_arith * ( ( (-1/2) * (q_arith - 3) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c ) + - * (q_arith - 1)*( α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m) + w_4_omega) ) = 0 - * - * This formula results in several cases depending on q_arith: - * 1. q_arith == 0: Arithmetic gate is completely disabled - * - * 2. q_arith == 1: Everything in the minigate on the right is disabled. The equation is just a standard plonk equation - * with extra wires: q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c = 0 - * - * 3. q_arith == 2: The (w_1 + w_4 - ...) term is disabled. THe equation is: - * (1/2) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + w_4_omega = 0 - * It allows defining w_4 at next index (w_4_omega) in terms of current wire values - * - * 4. q_arith == 3: The product of w_1 and w_2 is disabled, but a mini addition gate is enabled. α allows us to split - * the equation into two: - * - * q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + 2 * w_4_omega = 0 - * and - * w_1 + w_4 - w_1_omega + q_m = 0 (we are reusing q_m here) - * - * 5. q_arith > 3: The product of w_1 and w_2 is scaled by (q_arith - 3), while the w_4_omega term is scaled by (q_arith - 1). - * The equation can be split into two: - * - * (q_arith - 3)* q_m * w_1 * w_ 2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + (q_arith - 1) * w_4_omega = 0 - * and - * w_1 + w_4 - w_1_omega + q_m = 0 - * - * The problem that q_m is used both in both equations can be dealt with by appropriately changing selector values at - * the next gate. Then we can treat (q_arith - 1) as a simulated q_6 selector and scale q_m to handle (q_arith - 3) at - * product. - */ - - let w1q1 := mulmod(mload(W1_EVAL_LOC), mload(Q1_EVAL_LOC), p) - let w2q2 := mulmod(mload(W2_EVAL_LOC), mload(Q2_EVAL_LOC), p) - let w3q3 := mulmod(mload(W3_EVAL_LOC), mload(Q3_EVAL_LOC), p) - let w4q3 := mulmod(mload(W4_EVAL_LOC), mload(Q4_EVAL_LOC), p) - - // @todo - Add a explicit test that hits QARITH == 3 - // w1w2qm := (w_1 . w_2 . q_m . (QARITH_EVAL_LOC - 3)) / 2 - let w1w2qm := - mulmod( - mulmod( - mulmod(mulmod(mload(W1_EVAL_LOC), mload(W2_EVAL_LOC), p), mload(QM_EVAL_LOC), p), - addmod(mload(QARITH_EVAL_LOC), sub(p, 3), p), - p - ), - NEGATIVE_INVERSE_OF_2_MODULO_P, - p - ) - - // (w_1 . w_2 . q_m . (q_arith - 3)) / -2) + (w_1 . q_1) + (w_2 . q_2) + (w_3 . q_3) + (w_4 . q_4) + q_c - let identity := - addmod( - mload(QC_EVAL_LOC), addmod(w4q3, addmod(w3q3, addmod(w2q2, addmod(w1q1, w1w2qm, p), p), p), p), p - ) - - // if q_arith == 3 we evaluate an additional mini addition gate (on top of the regular one), where: - // w_1 + w_4 - w_1_omega + q_m = 0 - // we use this gate to save an addition gate when adding or subtracting non-native field elements - // α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m) - let extra_small_addition_gate_identity := - mulmod( - mload(C_ALPHA_LOC), - mulmod( - addmod(mload(QARITH_EVAL_LOC), sub(p, 2), p), - addmod( - mload(QM_EVAL_LOC), - addmod( - sub(p, mload(W1_OMEGA_EVAL_LOC)), addmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p), p - ), - p - ), - p - ), - p - ) - - // if q_arith == 2 OR q_arith == 3 we add the 4th wire of the NEXT gate into the arithmetic identity - // N.B. if q_arith > 2, this wire value will be scaled by (q_arith - 1) relative to the other gate wires! - // alpha_base * q_arith * (identity + (q_arith - 1) * (w_4_omega + extra_small_addition_gate_identity)) - mstore( - ARITHMETIC_IDENTITY, - mulmod( - mload(C_ALPHA_BASE_LOC), - mulmod( - mload(QARITH_EVAL_LOC), - addmod( - identity, - mulmod( - addmod(mload(QARITH_EVAL_LOC), sub(p, 1), p), - addmod(mload(W4_OMEGA_EVAL_LOC), extra_small_addition_gate_identity, p), - p - ), - p - ), - p - ), - p - ) - ) - - // update alpha - mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_SQR_LOC), p)) - } - - /** - * COMPUTE GENPERMSORT WIDGET EVALUATION - */ - { - /** - * D1 = (w2 - w1) - * D2 = (w3 - w2) - * D3 = (w4 - w3) - * D4 = (w1_omega - w4) - * - * α_a = alpha_base - * α_b = alpha_base * α - * α_c = alpha_base * α^2 - * α_d = alpha_base * α^3 - * - * range_accumulator = ( - * D1(D1 - 1)(D1 - 2)(D1 - 3).α_a + - * D2(D2 - 1)(D2 - 2)(D2 - 3).α_b + - * D3(D3 - 1)(D3 - 2)(D3 - 3).α_c + - * D4(D4 - 1)(D4 - 2)(D4 - 3).α_d + - * ) . q_sort - */ - let minus_two := sub(p, 2) - let minus_three := sub(p, 3) - let d1 := addmod(mload(W2_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p) - let d2 := addmod(mload(W3_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p) - let d3 := addmod(mload(W4_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p) - let d4 := addmod(mload(W1_OMEGA_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p) - - let range_accumulator := - mulmod( - mulmod( - mulmod(addmod(mulmod(d1, d1, p), sub(p, d1), p), addmod(d1, minus_two, p), p), - addmod(d1, minus_three, p), - p - ), - mload(C_ALPHA_BASE_LOC), - p - ) - range_accumulator := - addmod( - range_accumulator, - mulmod( - mulmod( - mulmod(addmod(mulmod(d2, d2, p), sub(p, d2), p), addmod(d2, minus_two, p), p), - addmod(d2, minus_three, p), - p - ), - mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p), - p - ), - p - ) - range_accumulator := - addmod( - range_accumulator, - mulmod( - mulmod( - mulmod(addmod(mulmod(d3, d3, p), sub(p, d3), p), addmod(d3, minus_two, p), p), - addmod(d3, minus_three, p), - p - ), - mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_SQR_LOC), p), - p - ), - p - ) - range_accumulator := - addmod( - range_accumulator, - mulmod( - mulmod( - mulmod(addmod(mulmod(d4, d4, p), sub(p, d4), p), addmod(d4, minus_two, p), p), - addmod(d4, minus_three, p), - p - ), - mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p), - p - ), - p - ) - range_accumulator := mulmod(range_accumulator, mload(QSORT_EVAL_LOC), p) - - mstore(SORT_IDENTITY, range_accumulator) - - // update alpha - mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_QUAD_LOC), p)) - } - - /** - * COMPUTE ELLIPTIC WIDGET EVALUATION - */ - { - /** - * endo_term = (-x_2) * x_1 * (x_3 * 2 + x_1) * q_beta - * endo_sqr_term = x_2^2 - * endo_sqr_term *= (x_3 - x_1) - * endo_sqr_term *= q_beta^2 - * leftovers = x_2^2 - * leftovers *= x_2 - * leftovers += x_1^2 * (x_3 + x_1) @follow-up Invalid comment in BB widget - * leftovers -= (y_2^2 + y_1^2) - * sign_term = y_2 * y_1 - * sign_term += sign_term - * sign_term *= q_sign - */ - // q_elliptic * (x3 + x2 + x1)(x2 - x1)(x2 - x1) - y2^2 - y1^2 + 2(y2y1)*q_sign = 0 - let x_diff := addmod(mload(X2_EVAL_LOC), sub(p, mload(X1_EVAL_LOC)), p) - let y2_sqr := mulmod(mload(Y2_EVAL_LOC), mload(Y2_EVAL_LOC), p) - let y1_sqr := mulmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p) - let y1y2 := mulmod(mulmod(mload(Y1_EVAL_LOC), mload(Y2_EVAL_LOC), p), mload(QSIGN_LOC), p) - - let x_add_identity := - addmod( - mulmod( - addmod(mload(X3_EVAL_LOC), addmod(mload(X2_EVAL_LOC), mload(X1_EVAL_LOC), p), p), - mulmod(x_diff, x_diff, p), - p - ), - addmod( - sub( - p, - addmod(y2_sqr, y1_sqr, p) - ), - addmod(y1y2, y1y2, p), - p - ), - p - ) - x_add_identity := - mulmod( - mulmod( - x_add_identity, - addmod( - 1, - sub(p, mload(QM_EVAL_LOC)), - p - ), - p - ), - mload(C_ALPHA_BASE_LOC), - p - ) - - // q_elliptic * (x3 + x2 + x1)(x2 - x1)(x2 - x1) - y2^2 - y1^2 + 2(y2y1)*q_sign = 0 - let y1_plus_y3 := addmod( - mload(Y1_EVAL_LOC), - mload(Y3_EVAL_LOC), - p - ) - let y_diff := addmod(mulmod(mload(Y2_EVAL_LOC), mload(QSIGN_LOC), p), sub(p, mload(Y1_EVAL_LOC)), p) - let y_add_identity := - addmod( - mulmod(y1_plus_y3, x_diff, p), - mulmod(addmod(mload(X3_EVAL_LOC), sub(p, mload(X1_EVAL_LOC)), p), y_diff, p), - p - ) - y_add_identity := - mulmod( - mulmod(y_add_identity, addmod(1, sub(p, mload(QM_EVAL_LOC)), p), p), - mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p), - p - ) - - // ELLIPTIC_IDENTITY = (x_identity + y_identity) * Q_ELLIPTIC_EVAL - mstore( - ELLIPTIC_IDENTITY, mulmod(addmod(x_add_identity, y_add_identity, p), mload(QELLIPTIC_EVAL_LOC), p) - ) - } - { - /** - * x_pow_4 = (y_1_sqr - curve_b) * x_1; - * y_1_sqr_mul_4 = y_1_sqr + y_1_sqr; - * y_1_sqr_mul_4 += y_1_sqr_mul_4; - * x_1_pow_4_mul_9 = x_pow_4; - * x_1_pow_4_mul_9 += x_1_pow_4_mul_9; - * x_1_pow_4_mul_9 += x_1_pow_4_mul_9; - * x_1_pow_4_mul_9 += x_1_pow_4_mul_9; - * x_1_pow_4_mul_9 += x_pow_4; - * x_1_sqr_mul_3 = x_1_sqr + x_1_sqr + x_1_sqr; - * x_double_identity = (x_3 + x_1 + x_1) * y_1_sqr_mul_4 - x_1_pow_4_mul_9; - * y_double_identity = x_1_sqr_mul_3 * (x_1 - x_3) - (y_1 + y_1) * (y_1 + y_3); - */ - // (x3 + x1 + x1) (4y1*y1) - 9 * x1 * x1 * x1 * x1 = 0 - let x1_sqr := mulmod(mload(X1_EVAL_LOC), mload(X1_EVAL_LOC), p) - let y1_sqr := mulmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p) - let x_pow_4 := mulmod(addmod(y1_sqr, GRUMPKIN_CURVE_B_PARAMETER_NEGATED, p), mload(X1_EVAL_LOC), p) - let y1_sqr_mul_4 := mulmod(y1_sqr, 4, p) - let x1_pow_4_mul_9 := mulmod(x_pow_4, 9, p) - let x1_sqr_mul_3 := mulmod(x1_sqr, 3, p) - let x_double_identity := - addmod( - mulmod( - addmod(mload(X3_EVAL_LOC), addmod(mload(X1_EVAL_LOC), mload(X1_EVAL_LOC), p), p), - y1_sqr_mul_4, - p - ), - sub(p, x1_pow_4_mul_9), - p - ) - // (y1 + y1) (2y1) - (3 * x1 * x1)(x1 - x3) = 0 - let y_double_identity := - addmod( - mulmod(x1_sqr_mul_3, addmod(mload(X1_EVAL_LOC), sub(p, mload(X3_EVAL_LOC)), p), p), - sub( - p, - mulmod( - addmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p), - addmod(mload(Y1_EVAL_LOC), mload(Y3_EVAL_LOC), p), - p - ) - ), - p - ) - x_double_identity := mulmod(x_double_identity, mload(C_ALPHA_BASE_LOC), p) - y_double_identity := - mulmod(y_double_identity, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p), p) - x_double_identity := mulmod(x_double_identity, mload(QM_EVAL_LOC), p) - y_double_identity := mulmod(y_double_identity, mload(QM_EVAL_LOC), p) - // ELLIPTIC_IDENTITY += (x_double_identity + y_double_identity) * Q_DOUBLE_EVAL - mstore( - ELLIPTIC_IDENTITY, - addmod( - mload(ELLIPTIC_IDENTITY), - mulmod(addmod(x_double_identity, y_double_identity, p), mload(QELLIPTIC_EVAL_LOC), p), - p - ) - ) - - // update alpha - mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_QUAD_LOC), p)) - } - - /** - * COMPUTE AUXILIARY WIDGET EVALUATION - */ - { - { - /** - * Non native field arithmetic gate 2 - * _ _ - * / _ _ _ 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 | - * \_ _/ - * - * limb_subproduct = w_1 . w_2_omega + w_1_omega . w_2 - * non_native_field_gate_2 = w_1 * w_4 + w_4 * w_3 - w_3_omega - * non_native_field_gate_2 = non_native_field_gate_2 * limb_size - * non_native_field_gate_2 -= w_4_omega - * non_native_field_gate_2 += limb_subproduct - * non_native_field_gate_2 *= q_4 - * limb_subproduct *= limb_size - * limb_subproduct += w_1_omega * w_2_omega - * non_native_field_gate_1 = (limb_subproduct + w_3 + w_4) * q_3 - * non_native_field_gate_3 = (limb_subproduct + w_4 - (w_3_omega + w_4_omega)) * q_m - * non_native_field_identity = (non_native_field_gate_1 + non_native_field_gate_2 + non_native_field_gate_3) * q_2 - */ - - let limb_subproduct := - addmod( - mulmod(mload(W1_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), - mulmod(mload(W1_OMEGA_EVAL_LOC), mload(W2_EVAL_LOC), p), - p - ) - - let non_native_field_gate_2 := - addmod( - addmod( - mulmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p), - mulmod(mload(W2_EVAL_LOC), mload(W3_EVAL_LOC), p), - p - ), - sub(p, mload(W3_OMEGA_EVAL_LOC)), - p - ) - non_native_field_gate_2 := mulmod(non_native_field_gate_2, LIMB_SIZE, p) - non_native_field_gate_2 := addmod(non_native_field_gate_2, sub(p, mload(W4_OMEGA_EVAL_LOC)), p) - non_native_field_gate_2 := addmod(non_native_field_gate_2, limb_subproduct, p) - non_native_field_gate_2 := mulmod(non_native_field_gate_2, mload(Q4_EVAL_LOC), p) - limb_subproduct := mulmod(limb_subproduct, LIMB_SIZE, p) - limb_subproduct := - addmod(limb_subproduct, mulmod(mload(W1_OMEGA_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), p) - let non_native_field_gate_1 := - mulmod( - addmod(limb_subproduct, sub(p, addmod(mload(W3_EVAL_LOC), mload(W4_EVAL_LOC), p)), p), - mload(Q3_EVAL_LOC), - p - ) - let non_native_field_gate_3 := - mulmod( - addmod( - addmod(limb_subproduct, mload(W4_EVAL_LOC), p), - sub(p, addmod(mload(W3_OMEGA_EVAL_LOC), mload(W4_OMEGA_EVAL_LOC), p)), - p - ), - mload(QM_EVAL_LOC), - p - ) - let non_native_field_identity := - mulmod( - addmod(addmod(non_native_field_gate_1, non_native_field_gate_2, p), non_native_field_gate_3, p), - mload(Q2_EVAL_LOC), - p - ) - - mstore(AUX_NON_NATIVE_FIELD_EVALUATION, non_native_field_identity) - } - - { - /** - * limb_accumulator_1 = w_2_omega; - * limb_accumulator_1 *= SUBLIMB_SHIFT; - * limb_accumulator_1 += w_1_omega; - * limb_accumulator_1 *= SUBLIMB_SHIFT; - * limb_accumulator_1 += w_3; - * limb_accumulator_1 *= SUBLIMB_SHIFT; - * limb_accumulator_1 += w_2; - * limb_accumulator_1 *= SUBLIMB_SHIFT; - * limb_accumulator_1 += w_1; - * limb_accumulator_1 -= w_4; - * limb_accumulator_1 *= q_4; - */ - let limb_accumulator_1 := mulmod(mload(W2_OMEGA_EVAL_LOC), SUBLIMB_SHIFT, p) - limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_OMEGA_EVAL_LOC), p) - limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p) - limb_accumulator_1 := addmod(limb_accumulator_1, mload(W3_EVAL_LOC), p) - limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p) - limb_accumulator_1 := addmod(limb_accumulator_1, mload(W2_EVAL_LOC), p) - limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p) - limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_EVAL_LOC), p) - limb_accumulator_1 := addmod(limb_accumulator_1, sub(p, mload(W4_EVAL_LOC)), p) - limb_accumulator_1 := mulmod(limb_accumulator_1, mload(Q4_EVAL_LOC), p) - - /** - * limb_accumulator_2 = w_3_omega; - * limb_accumulator_2 *= SUBLIMB_SHIFT; - * limb_accumulator_2 += w_2_omega; - * limb_accumulator_2 *= SUBLIMB_SHIFT; - * limb_accumulator_2 += w_1_omega; - * limb_accumulator_2 *= SUBLIMB_SHIFT; - * limb_accumulator_2 += w_4; - * limb_accumulator_2 *= SUBLIMB_SHIFT; - * limb_accumulator_2 += w_3; - * limb_accumulator_2 -= w_4_omega; - * limb_accumulator_2 *= q_m; - */ - let limb_accumulator_2 := mulmod(mload(W3_OMEGA_EVAL_LOC), SUBLIMB_SHIFT, p) - limb_accumulator_2 := addmod(limb_accumulator_2, mload(W2_OMEGA_EVAL_LOC), p) - limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p) - limb_accumulator_2 := addmod(limb_accumulator_2, mload(W1_OMEGA_EVAL_LOC), p) - limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p) - limb_accumulator_2 := addmod(limb_accumulator_2, mload(W4_EVAL_LOC), p) - limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p) - limb_accumulator_2 := addmod(limb_accumulator_2, mload(W3_EVAL_LOC), p) - limb_accumulator_2 := addmod(limb_accumulator_2, sub(p, mload(W4_OMEGA_EVAL_LOC)), p) - limb_accumulator_2 := mulmod(limb_accumulator_2, mload(QM_EVAL_LOC), p) - - mstore( - AUX_LIMB_ACCUMULATOR_EVALUATION, - mulmod(addmod(limb_accumulator_1, limb_accumulator_2, p), mload(Q3_EVAL_LOC), p) - ) - } - - { - /** - * memory_record_check = w_3; - * memory_record_check *= eta; - * memory_record_check += w_2; - * memory_record_check *= eta; - * memory_record_check += w_1; - * memory_record_check *= eta; - * memory_record_check += q_c; - * - * partial_record_check = memory_record_check; - * - * memory_record_check -= w_4; - */ - - let memory_record_check := mulmod(mload(W3_EVAL_LOC), mload(C_ETA_LOC), p) - memory_record_check := addmod(memory_record_check, mload(W2_EVAL_LOC), p) - memory_record_check := mulmod(memory_record_check, mload(C_ETA_LOC), p) - memory_record_check := addmod(memory_record_check, mload(W1_EVAL_LOC), p) - memory_record_check := mulmod(memory_record_check, mload(C_ETA_LOC), p) - memory_record_check := addmod(memory_record_check, mload(QC_EVAL_LOC), p) - - let partial_record_check := memory_record_check - memory_record_check := addmod(memory_record_check, sub(p, mload(W4_EVAL_LOC)), p) - - mstore(AUX_MEMORY_EVALUATION, memory_record_check) - - // index_delta = w_1_omega - w_1 - let index_delta := addmod(mload(W1_OMEGA_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p) - // record_delta = w_4_omega - w_4 - let record_delta := addmod(mload(W4_OMEGA_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p) - // index_is_monotonically_increasing = index_delta * (index_delta - 1) - let index_is_monotonically_increasing := mulmod(index_delta, addmod(index_delta, sub(p, 1), p), p) - - // adjacent_values_match_if_adjacent_indices_match = record_delta * (1 - index_delta) - let adjacent_values_match_if_adjacent_indices_match := - mulmod(record_delta, addmod(1, sub(p, index_delta), p), p) - - // AUX_ROM_CONSISTENCY_EVALUATION = ((adjacent_values_match_if_adjacent_indices_match * alpha) + index_is_monotonically_increasing) * alpha + partial_record_check - mstore( - AUX_ROM_CONSISTENCY_EVALUATION, - addmod( - mulmod( - addmod( - mulmod(adjacent_values_match_if_adjacent_indices_match, mload(C_ALPHA_LOC), p), - index_is_monotonically_increasing, - p - ), - mload(C_ALPHA_LOC), - p - ), - memory_record_check, - p - ) - ) - - { - /** - * next_gate_access_type = w_3_omega; - * next_gate_access_type *= eta; - * next_gate_access_type += w_2_omega; - * next_gate_access_type *= eta; - * next_gate_access_type += w_1_omega; - * next_gate_access_type *= eta; - * next_gate_access_type = w_4_omega - next_gate_access_type; - */ - let next_gate_access_type := mulmod(mload(W3_OMEGA_EVAL_LOC), mload(C_ETA_LOC), p) - next_gate_access_type := addmod(next_gate_access_type, mload(W2_OMEGA_EVAL_LOC), p) - next_gate_access_type := mulmod(next_gate_access_type, mload(C_ETA_LOC), p) - next_gate_access_type := addmod(next_gate_access_type, mload(W1_OMEGA_EVAL_LOC), p) - next_gate_access_type := mulmod(next_gate_access_type, mload(C_ETA_LOC), p) - next_gate_access_type := addmod(mload(W4_OMEGA_EVAL_LOC), sub(p, next_gate_access_type), p) - - // value_delta = w_3_omega - w_3 - let value_delta := addmod(mload(W3_OMEGA_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p) - // adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = (1 - index_delta) * value_delta * (1 - next_gate_access_type); - - let adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation := - mulmod( - addmod(1, sub(p, index_delta), p), - mulmod(value_delta, addmod(1, sub(p, next_gate_access_type), p), p), - p - ) - - // AUX_RAM_CONSISTENCY_EVALUATION - - /** - * access_type = w_4 - partial_record_check - * access_check = access_type^2 - access_type - * next_gate_access_type_is_boolean = next_gate_access_type^2 - next_gate_access_type - * RAM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation; - * RAM_consistency_check_identity *= alpha; - * RAM_consistency_check_identity += index_is_monotonically_increasing; - * RAM_consistency_check_identity *= alpha; - * RAM_consistency_check_identity += next_gate_access_type_is_boolean; - * RAM_consistency_check_identity *= alpha; - * RAM_consistency_check_identity += access_check; - */ - - let access_type := addmod(mload(W4_EVAL_LOC), sub(p, partial_record_check), p) - let access_check := mulmod(access_type, addmod(access_type, sub(p, 1), p), p) - let next_gate_access_type_is_boolean := - mulmod(next_gate_access_type, addmod(next_gate_access_type, sub(p, 1), p), p) - let RAM_cci := - mulmod( - adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation, - mload(C_ALPHA_LOC), - p - ) - RAM_cci := addmod(RAM_cci, index_is_monotonically_increasing, p) - RAM_cci := mulmod(RAM_cci, mload(C_ALPHA_LOC), p) - RAM_cci := addmod(RAM_cci, next_gate_access_type_is_boolean, p) - RAM_cci := mulmod(RAM_cci, mload(C_ALPHA_LOC), p) - RAM_cci := addmod(RAM_cci, access_check, p) - - mstore(AUX_RAM_CONSISTENCY_EVALUATION, RAM_cci) - } - - { - // timestamp_delta = w_2_omega - w_2 - let timestamp_delta := addmod(mload(W2_OMEGA_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p) - - // RAM_timestamp_check_identity = (1 - index_delta) * timestamp_delta - w_3 - let RAM_timestamp_check_identity := - addmod( - mulmod(timestamp_delta, addmod(1, sub(p, index_delta), p), p), sub(p, mload(W3_EVAL_LOC)), p - ) - - /** - * memory_identity = ROM_consistency_check_identity * q_2; - * memory_identity += RAM_timestamp_check_identity * q_4; - * memory_identity += memory_record_check * q_m; - * memory_identity *= q_1; - * memory_identity += (RAM_consistency_check_identity * q_arith); - * - * auxiliary_identity = memory_identity + non_native_field_identity + limb_accumulator_identity; - * auxiliary_identity *= q_aux; - * auxiliary_identity *= alpha_base; - */ - let memory_identity := mulmod(mload(AUX_ROM_CONSISTENCY_EVALUATION), mload(Q2_EVAL_LOC), p) - memory_identity := - addmod(memory_identity, mulmod(RAM_timestamp_check_identity, mload(Q4_EVAL_LOC), p), p) - memory_identity := - addmod(memory_identity, mulmod(mload(AUX_MEMORY_EVALUATION), mload(QM_EVAL_LOC), p), p) - memory_identity := mulmod(memory_identity, mload(Q1_EVAL_LOC), p) - memory_identity := - addmod( - memory_identity, mulmod(mload(AUX_RAM_CONSISTENCY_EVALUATION), mload(QARITH_EVAL_LOC), p), p - ) - - let auxiliary_identity := addmod(memory_identity, mload(AUX_NON_NATIVE_FIELD_EVALUATION), p) - auxiliary_identity := addmod(auxiliary_identity, mload(AUX_LIMB_ACCUMULATOR_EVALUATION), p) - auxiliary_identity := mulmod(auxiliary_identity, mload(QAUX_EVAL_LOC), p) - auxiliary_identity := mulmod(auxiliary_identity, mload(C_ALPHA_BASE_LOC), p) - - mstore(AUX_IDENTITY, auxiliary_identity) - - // update alpha - mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p)) - } - } - } - - { - /** - * quotient = ARITHMETIC_IDENTITY - * quotient += PERMUTATION_IDENTITY - * quotient += PLOOKUP_IDENTITY - * quotient += SORT_IDENTITY - * quotient += ELLIPTIC_IDENTITY - * quotient += AUX_IDENTITY - * quotient *= ZERO_POLY_INVERSE - */ - mstore( - QUOTIENT_EVAL_LOC, - mulmod( - addmod( - addmod( - addmod( - addmod( - addmod(mload(PERMUTATION_IDENTITY), mload(PLOOKUP_IDENTITY), p), - mload(ARITHMETIC_IDENTITY), - p - ), - mload(SORT_IDENTITY), - p - ), - mload(ELLIPTIC_IDENTITY), - p - ), - mload(AUX_IDENTITY), - p - ), - mload(ZERO_POLY_INVERSE_LOC), - p - ) - ) - } - - /** - * GENERATE NU AND SEPARATOR CHALLENGES - */ - { - let current_challenge := mload(C_CURRENT_LOC) - // get a calldata pointer that points to the start of the data we want to copy - let calldata_ptr := add(calldataload(0x04), 0x24) - - calldata_ptr := add(calldata_ptr, NU_CALLDATA_SKIP_LENGTH) - - mstore(NU_CHALLENGE_INPUT_LOC_A, current_challenge) - mstore(NU_CHALLENGE_INPUT_LOC_B, mload(QUOTIENT_EVAL_LOC)) - calldatacopy(NU_CHALLENGE_INPUT_LOC_C, calldata_ptr, NU_INPUT_LENGTH) - - // hash length = (0x20 + num field elements), we include the previous challenge in the hash - let challenge := keccak256(NU_CHALLENGE_INPUT_LOC_A, add(NU_INPUT_LENGTH, 0x40)) - - mstore(C_V0_LOC, mod(challenge, p)) - // We need THIRTY-ONE independent nu challenges! - mstore(0x00, challenge) - mstore8(0x20, 0x01) - mstore(C_V1_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x02) - mstore(C_V2_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x03) - mstore(C_V3_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x04) - mstore(C_V4_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x05) - mstore(C_V5_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x06) - mstore(C_V6_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x07) - mstore(C_V7_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x08) - mstore(C_V8_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x09) - mstore(C_V9_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x0a) - mstore(C_V10_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x0b) - mstore(C_V11_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x0c) - mstore(C_V12_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x0d) - mstore(C_V13_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x0e) - mstore(C_V14_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x0f) - mstore(C_V15_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x10) - mstore(C_V16_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x11) - mstore(C_V17_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x12) - mstore(C_V18_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x13) - mstore(C_V19_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x14) - mstore(C_V20_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x15) - mstore(C_V21_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x16) - mstore(C_V22_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x17) - mstore(C_V23_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x18) - mstore(C_V24_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x19) - mstore(C_V25_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x1a) - mstore(C_V26_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x1b) - mstore(C_V27_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x1c) - mstore(C_V28_LOC, mod(keccak256(0x00, 0x21), p)) - mstore8(0x20, 0x1d) - mstore(C_V29_LOC, mod(keccak256(0x00, 0x21), p)) - - // @follow-up - Why are both v29 and v30 using appending 0x1d to the prior challenge and hashing, should it not change? - mstore8(0x20, 0x1d) - challenge := keccak256(0x00, 0x21) - mstore(C_V30_LOC, mod(challenge, p)) - - // separator - mstore(0x00, challenge) - mstore(0x20, mload(PI_Z_Y_LOC)) - mstore(0x40, mload(PI_Z_X_LOC)) - mstore(0x60, mload(PI_Z_OMEGA_Y_LOC)) - mstore(0x80, mload(PI_Z_OMEGA_X_LOC)) - - mstore(C_U_LOC, mod(keccak256(0x00, 0xa0), p)) - } - - let success := 0 - // VALIDATE T1 - { - let x := mload(T1_X_LOC) - let y := mload(T1_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)) - mstore(ACCUMULATOR_X_LOC, x) - mstore(add(ACCUMULATOR_X_LOC, 0x20), y) - } - // VALIDATE T2 - { - let x := mload(T2_X_LOC) // 0x1400 - let y := mload(T2_Y_LOC) // 0x1420 - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(ZETA_POW_N_LOC)) - // accumulator_2 = [T2].zeta^n - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = [T1] + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE T3 - { - let x := mload(T3_X_LOC) - let y := mload(T3_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(mload(ZETA_POW_N_LOC), mload(ZETA_POW_N_LOC), p)) - // accumulator_2 = [T3].zeta^{2n} - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE T4 - { - let x := mload(T4_X_LOC) - let y := mload(T4_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(mulmod(mload(ZETA_POW_N_LOC), mload(ZETA_POW_N_LOC), p), mload(ZETA_POW_N_LOC), p)) - // accumulator_2 = [T4].zeta^{3n} - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE W1 - { - let x := mload(W1_X_LOC) - let y := mload(W1_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V0_LOC), p)) - // accumulator_2 = v0.(u + 1).[W1] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE W2 - { - let x := mload(W2_X_LOC) - let y := mload(W2_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V1_LOC), p)) - // accumulator_2 = v1.(u + 1).[W2] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE W3 - { - let x := mload(W3_X_LOC) - let y := mload(W3_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V2_LOC), p)) - // accumulator_2 = v2.(u + 1).[W3] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE W4 - { - let x := mload(W4_X_LOC) - let y := mload(W4_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V3_LOC), p)) - // accumulator_2 = v3.(u + 1).[W4] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE S - { - let x := mload(S_X_LOC) - let y := mload(S_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V4_LOC), p)) - // accumulator_2 = v4.(u + 1).[S] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE Z - { - let x := mload(Z_X_LOC) - let y := mload(Z_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V5_LOC), p)) - // accumulator_2 = v5.(u + 1).[Z] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE Z_LOOKUP - { - let x := mload(Z_LOOKUP_X_LOC) - let y := mload(Z_LOOKUP_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V6_LOC), p)) - // accumulator_2 = v6.(u + 1).[Z_LOOKUP] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE Q1 - { - let x := mload(Q1_X_LOC) - let y := mload(Q1_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V7_LOC)) - // accumulator_2 = v7.[Q1] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE Q2 - { - let x := mload(Q2_X_LOC) - let y := mload(Q2_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V8_LOC)) - // accumulator_2 = v8.[Q2] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE Q3 - { - let x := mload(Q3_X_LOC) - let y := mload(Q3_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V9_LOC)) - // accumulator_2 = v9.[Q3] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE Q4 - { - let x := mload(Q4_X_LOC) - let y := mload(Q4_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V10_LOC)) - // accumulator_2 = v10.[Q4] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE QM - { - let x := mload(QM_X_LOC) - let y := mload(QM_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V11_LOC)) - // accumulator_2 = v11.[Q;] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE QC - { - let x := mload(QC_X_LOC) - let y := mload(QC_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V12_LOC)) - // accumulator_2 = v12.[QC] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE QARITH - { - let x := mload(QARITH_X_LOC) - let y := mload(QARITH_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V13_LOC)) - // accumulator_2 = v13.[QARITH] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE QSORT - { - let x := mload(QSORT_X_LOC) - let y := mload(QSORT_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V14_LOC)) - // accumulator_2 = v14.[QSORT] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE QELLIPTIC - { - let x := mload(QELLIPTIC_X_LOC) - let y := mload(QELLIPTIC_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V15_LOC)) - // accumulator_2 = v15.[QELLIPTIC] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE QAUX - { - let x := mload(QAUX_X_LOC) - let y := mload(QAUX_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V16_LOC)) - // accumulator_2 = v15.[Q_AUX] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE SIGMA1 - { - let x := mload(SIGMA1_X_LOC) - let y := mload(SIGMA1_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V17_LOC)) - // accumulator_2 = v17.[sigma1] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE SIGMA2 - { - let x := mload(SIGMA2_X_LOC) - let y := mload(SIGMA2_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V18_LOC)) - // accumulator_2 = v18.[sigma2] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE SIGMA3 - { - let x := mload(SIGMA3_X_LOC) - let y := mload(SIGMA3_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V19_LOC)) - // accumulator_2 = v19.[sigma3] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE SIGMA4 - { - let x := mload(SIGMA4_X_LOC) - let y := mload(SIGMA4_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V20_LOC)) - // accumulator_2 = v20.[sigma4] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE TABLE1 - { - let x := mload(TABLE1_X_LOC) - let y := mload(TABLE1_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V21_LOC), p)) - // accumulator_2 = u.[table1] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE TABLE2 - { - let x := mload(TABLE2_X_LOC) - let y := mload(TABLE2_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V22_LOC), p)) - // accumulator_2 = u.[table2] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE TABLE3 - { - let x := mload(TABLE3_X_LOC) - let y := mload(TABLE3_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V23_LOC), p)) - // accumulator_2 = u.[table3] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE TABLE4 - { - let x := mload(TABLE4_X_LOC) - let y := mload(TABLE4_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V24_LOC), p)) - // accumulator_2 = u.[table4] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE TABLE_TYPE - { - let x := mload(TABLE_TYPE_X_LOC) - let y := mload(TABLE_TYPE_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V25_LOC)) - // accumulator_2 = v25.[TableType] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE ID1 - { - let x := mload(ID1_X_LOC) - let y := mload(ID1_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V26_LOC)) - // accumulator_2 = v26.[ID1] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE ID2 - { - let x := mload(ID2_X_LOC) - let y := mload(ID2_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V27_LOC)) - // accumulator_2 = v27.[ID2] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE ID3 - { - let x := mload(ID3_X_LOC) - let y := mload(ID3_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V28_LOC)) - // accumulator_2 = v28.[ID3] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE ID4 - { - let x := mload(ID4_X_LOC) - let y := mload(ID4_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mload(C_V29_LOC)) - // accumulator_2 = v29.[ID4] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - /** - * COMPUTE BATCH EVALUATION SCALAR MULTIPLIER - */ - { - /** - * batch_evaluation = v0 * (w_1_omega * u + w_1_eval) - * batch_evaluation += v1 * (w_2_omega * u + w_2_eval) - * batch_evaluation += v2 * (w_3_omega * u + w_3_eval) - * batch_evaluation += v3 * (w_4_omega * u + w_4_eval) - * batch_evaluation += v4 * (s_omega_eval * u + s_eval) - * batch_evaluation += v5 * (z_omega_eval * u + z_eval) - * batch_evaluation += v6 * (z_lookup_omega_eval * u + z_lookup_eval) - */ - let batch_evaluation := - mulmod( - mload(C_V0_LOC), - addmod(mulmod(mload(W1_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W1_EVAL_LOC), p), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V1_LOC), - addmod(mulmod(mload(W2_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W2_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V2_LOC), - addmod(mulmod(mload(W3_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W3_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V3_LOC), - addmod(mulmod(mload(W4_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W4_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V4_LOC), - addmod(mulmod(mload(S_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(S_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V5_LOC), - addmod(mulmod(mload(Z_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(Z_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V6_LOC), - addmod(mulmod(mload(Z_LOOKUP_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(Z_LOOKUP_EVAL_LOC), p), - p - ), - p - ) - - /** - * batch_evaluation += v7 * Q1_EVAL - * batch_evaluation += v8 * Q2_EVAL - * batch_evaluation += v9 * Q3_EVAL - * batch_evaluation += v10 * Q4_EVAL - * batch_evaluation += v11 * QM_EVAL - * batch_evaluation += v12 * QC_EVAL - * batch_evaluation += v13 * QARITH_EVAL - * batch_evaluation += v14 * QSORT_EVAL_LOC - * batch_evaluation += v15 * QELLIPTIC_EVAL_LOC - * batch_evaluation += v16 * QAUX_EVAL_LOC - * batch_evaluation += v17 * SIGMA1_EVAL_LOC - * batch_evaluation += v18 * SIGMA2_EVAL_LOC - * batch_evaluation += v19 * SIGMA3_EVAL_LOC - * batch_evaluation += v20 * SIGMA4_EVAL_LOC - */ - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V7_LOC), mload(Q1_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V8_LOC), mload(Q2_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V9_LOC), mload(Q3_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V10_LOC), mload(Q4_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V11_LOC), mload(QM_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V12_LOC), mload(QC_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V13_LOC), mload(QARITH_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V14_LOC), mload(QSORT_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V15_LOC), mload(QELLIPTIC_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V16_LOC), mload(QAUX_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V17_LOC), mload(SIGMA1_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V18_LOC), mload(SIGMA2_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V19_LOC), mload(SIGMA3_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V20_LOC), mload(SIGMA4_EVAL_LOC), p), p) - - /** - * batch_evaluation += v21 * (table1(zw) * u + table1(z)) - * batch_evaluation += v22 * (table2(zw) * u + table2(z)) - * batch_evaluation += v23 * (table3(zw) * u + table3(z)) - * batch_evaluation += v24 * (table4(zw) * u + table4(z)) - * batch_evaluation += v25 * table_type_eval - * batch_evaluation += v26 * id1_eval - * batch_evaluation += v27 * id2_eval - * batch_evaluation += v28 * id3_eval - * batch_evaluation += v29 * id4_eval - * batch_evaluation += quotient_eval - */ - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V21_LOC), - addmod(mulmod(mload(TABLE1_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE1_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V22_LOC), - addmod(mulmod(mload(TABLE2_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE2_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V23_LOC), - addmod(mulmod(mload(TABLE3_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE3_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := - addmod( - batch_evaluation, - mulmod( - mload(C_V24_LOC), - addmod(mulmod(mload(TABLE4_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE4_EVAL_LOC), p), - p - ), - p - ) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V25_LOC), mload(TABLE_TYPE_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V26_LOC), mload(ID1_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V27_LOC), mload(ID2_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V28_LOC), mload(ID3_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V29_LOC), mload(ID4_EVAL_LOC), p), p) - batch_evaluation := addmod(batch_evaluation, mload(QUOTIENT_EVAL_LOC), p) - - mstore(0x00, 0x01) // [1].x - mstore(0x20, 0x02) // [1].y - mstore(0x40, sub(p, batch_evaluation)) - // accumulator_2 = -[1].(batch_evaluation) - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - mstore(OPENING_COMMITMENT_SUCCESS_FLAG, success) - } - - /** - * PERFORM PAIRING PREAMBLE - */ - { - let u := mload(C_U_LOC) - let zeta := mload(C_ZETA_LOC) - // VALIDATE PI_Z - { - let x := mload(PI_Z_X_LOC) - let y := mload(PI_Z_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)) - mstore(0x00, x) - mstore(0x20, y) - } - // compute zeta.[PI_Z] and add into accumulator - mstore(0x40, zeta) - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - - // VALIDATE PI_Z_OMEGA - { - let x := mload(PI_Z_OMEGA_X_LOC) - let y := mload(PI_Z_OMEGA_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - mstore(0x40, mulmod(mulmod(u, zeta, p), mload(OMEGA_LOC), p)) - // accumulator_2 = u.zeta.omega.[PI_Z_OMEGA] - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) - // PAIRING_RHS = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, PAIRING_RHS_X_LOC, 0x40)) - - mstore(0x00, mload(PI_Z_X_LOC)) - mstore(0x20, mload(PI_Z_Y_LOC)) - mstore(0x40, mload(PI_Z_OMEGA_X_LOC)) - mstore(0x60, mload(PI_Z_OMEGA_Y_LOC)) - mstore(0x80, u) - success := and(success, staticcall(gas(), 7, 0x40, 0x60, 0x40, 0x40)) - // PAIRING_LHS = [PI_Z] + [PI_Z_OMEGA] * u - success := and(success, staticcall(gas(), 6, 0x00, 0x80, PAIRING_LHS_X_LOC, 0x40)) - // negate lhs y-coordinate - mstore(PAIRING_LHS_Y_LOC, sub(q, mload(PAIRING_LHS_Y_LOC))) - - if mload(CONTAINS_RECURSIVE_PROOF_LOC) { - // VALIDATE RECURSIVE P1 - { - let x := mload(RECURSIVE_P1_X_LOC) - let y := mload(RECURSIVE_P1_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - - // compute u.u.[recursive_p1] and write into 0x60 - mstore(0x40, mulmod(u, u, p)) - success := and(success, staticcall(gas(), 7, 0x00, 0x60, 0x60, 0x40)) - // VALIDATE RECURSIVE P2 - { - let x := mload(RECURSIVE_P2_X_LOC) - let y := mload(RECURSIVE_P2_Y_LOC) - let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) - mstore(0x00, x) - mstore(0x20, y) - } - // compute u.u.[recursive_p2] and write into 0x00 - // 0x40 still contains u*u - success := and(success, staticcall(gas(), 7, 0x00, 0x60, 0x00, 0x40)) - - // compute u.u.[recursiveP1] + rhs and write into rhs - mstore(0xa0, mload(PAIRING_RHS_X_LOC)) - mstore(0xc0, mload(PAIRING_RHS_Y_LOC)) - success := and(success, staticcall(gas(), 6, 0x60, 0x80, PAIRING_RHS_X_LOC, 0x40)) - - // compute u.u.[recursiveP2] + lhs and write into lhs - mstore(0x40, mload(PAIRING_LHS_X_LOC)) - mstore(0x60, mload(PAIRING_LHS_Y_LOC)) - success := and(success, staticcall(gas(), 6, 0x00, 0x80, PAIRING_LHS_X_LOC, 0x40)) - } - - if iszero(success) { - mstore(0x0, EC_SCALAR_MUL_FAILURE_SELECTOR) - revert(0x00, 0x04) - } - mstore(PAIRING_PREAMBLE_SUCCESS_FLAG, success) - } - - /** - * PERFORM PAIRING - */ - { - // rhs paired with [1]_2 - // lhs paired with [x]_2 - - mstore(0x00, mload(PAIRING_RHS_X_LOC)) - mstore(0x20, mload(PAIRING_RHS_Y_LOC)) - mstore(0x40, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) // this is [1]_2 - mstore(0x60, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) - mstore(0x80, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) - mstore(0xa0, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) - - mstore(0xc0, mload(PAIRING_LHS_X_LOC)) - mstore(0xe0, mload(PAIRING_LHS_Y_LOC)) - mstore(0x100, mload(G2X_X0_LOC)) - mstore(0x120, mload(G2X_X1_LOC)) - mstore(0x140, mload(G2X_Y0_LOC)) - mstore(0x160, mload(G2X_Y1_LOC)) - - success := staticcall(gas(), 8, 0x00, 0x180, 0x00, 0x20) - mstore(PAIRING_SUCCESS_FLAG, success) - mstore(RESULT_FLAG, mload(0x00)) - } - if iszero( - and( - and(and(mload(PAIRING_SUCCESS_FLAG), mload(RESULT_FLAG)), mload(PAIRING_PREAMBLE_SUCCESS_FLAG)), - mload(OPENING_COMMITMENT_SUCCESS_FLAG) - ) - ) { - mstore(0x0, PROOF_FAILURE_SELECTOR) - revert(0x00, 0x04) - } - { - mstore(0x00, 0x01) - return(0x00, 0x20) // Proof succeeded! - } - } - } -} - -contract UltraVerifier is BaseUltraVerifier { - function getVerificationKeyHash() public pure override(BaseUltraVerifier) returns (bytes32) { - return UltraVerificationKey.verificationKeyHash(); - } - - function loadVerificationKey(uint256 vk, uint256 _omegaInverseLoc) internal pure virtual override(BaseUltraVerifier) { - UltraVerificationKey.loadVerificationKey(vk, _omegaInverseLoc); - } -} diff --git a/foundry-voting/circuits/proofs/foundry_voting.proof b/foundry-voting/circuits/proofs/foundry_voting.proof deleted file mode 100644 index 0725d59..0000000 --- a/foundry-voting/circuits/proofs/foundry_voting.proof +++ /dev/null @@ -1 +0,0 @@ -0afb8880e6061af80eb6e66624bafbcf6b57f347ecacfddd0cf7280d26f994bd21be8df560c338a1a01b97bb1995eb7beab51e3b10748675706539d1049f0b2e30498eba9495b418aad4aad07a5c1c5fef6fe2090a473c0ade7bba4257abad760b0e9ef1dcae0ab11be20233a31e96ea823d81ae1e663fdc581197561e2ca81c26135038f2e9ca140b6d8f728ec290cde9f737449250d264703d99e07e71d080033cd7f41051f8f04caed621925ac85ab33744100e1919120329e705ce48b0c91a18b805645721c89e42e4b1d4289d0eac7269416039859a877c8f33c1cd84562690a538da230b52cc018d1fa3f63658e87ece554138002be11c831c0652911b2ada2d9eab00f82bb7f931b1c2d5e0dc0535738eb59d8cd386f4e5bd96aac02408bf1a65f710b7a8a9f9709c71926f316d75f667c8d964e81f690798fef99174173b6eb5867376be215383783077c161fea18f8360098e139ac27e5c6195f52407cf1069921a7c8d3ee9aa09b6dc2d6d06f546f1ea92c3c4241fa1826938172708e5205a944eeefac7c33cfb1278f67035763d10b2be271fea1927ecc56f29e427845f7f00d3a17c9fdd2b4b0b57a8173681c862ce40678275a02241a53e4b39178b058c00586bed5960613010aece9bdf260ef124a94d7763116c99472ecdfb1cc29f906bb6e2bd886e9c18ad2d2d8f1a03b0d2eec6e73910e40b8082aa2f992633d81c1be805b76daa5188acc57e4af49f3985334350acf27c7b5446131bb3238f655365b9e9f54280275cf685dba5067c9c0b170b678b52e81f6e4a7ef6381689292b0e62771ae57eb8bac5d1cb0f84e420bfd3ee6f07065973d469b603de2437cff0e9bc76340fa924d1d6de2e2f7771828ec46efd896f75846c75b424ca00bda3a3f528e8b7ccf4a6da879172e5ae2450b9dfd31b518a74bfad567b1b812ce13cf2146664cf2c31ecd9ad74aa5eb5e404795cc246be429efaeade42fee41563c70fc862ca955eb1d0330e1f4bf93bc5cf94f7f9c6a2f295cbdf1391704026fdf2160c61fa6da948f3e4899afc013e474e5176f2b6142377cd041c715e7d1013b8fc50fcc6d3fd7735a3e7cd332cd6d6642380298cc65d7e29d65619389206f6d6c9117f04ba84c95d85dc6aed2996205ad7423bd763872d8963b6b58688024d37e3322272dcb7bf9702dd49b0b0241fa2f01cd5ab148510a163e7f09d2f1d2aefcf0cd0b50e0915d8e3ff17ffc4cb0d1b93f5d153be12e2396ab330b58c17aaaaa0c8bd29e62aeb1f98de5ffbfd3ecd152feaff1e1ab254b02243eed8712de61d452e052ee3b695708069773fd0fe9c7ff4a647a059e7004b8ce7ddc4b30102348095699c84dc43f0e3f392ad5eaa2058a5782d6813c6974d55efb7c4fa2a050ac99d2a8997266ff3cafe2f7dfe15da6581cd6599a984a2c9d01189b2b2146493577a0d1e3519494f350e379261837157db9de92a82a6dcac08d103ff0b23676998b310f449febac6d479ea1bb2887ada9ede297c9b07b0265f00ce711312532e670e4bd03d71c3f067512f106120a29b55760430c47f8f4caed4e70e3a305ce23db535eea5096d673dac1368c847fcdcffc8d23cecce90e59548ddfc3c2045b894f788eb1667cf5f1b0a89db162adf5d52ff7d6c5e5204e2d03cd010d722c71726238fa2c037a7f62715842a83c0a5ad9c0c5dc7ccd2f1455ad53fb6e10f69e350c5fa27bdacbc0c22bc3a8a79bac4c4fb5aa8059764c0d7986ed4a2812e09522f2a5ea9bb2af104f59217dc65af4e773b30e59e81dc71e7d32b2b44f801068a28504a30e2a5f77f4d4371446544eb004dab15d6028ad68976fec18af821ba3177e8131aa46bc82044da24649c7ccb3ff77b67460e85053bb6ad2dcaf50f7bacc48e7322f33052d81cfd00893f2dbec9210a3a63bf9cce34233b61eb912676b4bc891ae72ef4748e1b771a8cfa69d16a8ee1158e89e480440aafa1f8a12a97b67558ad4334599b516d5e25f014a6de93e3babf3de999a7a2c1d1d1de420cfb690407110b0f5cc0ba1a1017e5e465d8ee0aec961eb438f484c4a71f0d42230b293bac55ebc74b9f6217f1c645566db6ddb6c373e73340035ad5c317eb88131bbe93f75ce81ca149855545448f550a404c5a849c051aeb33f0a8f2c6424e0f90fa4e3ff30f414c0e2a3011f9d00aef18b9c2a1f6fce7c6ccdf4743a7c9c30018f76dceb759a0ca880f65c815e400a452cb7ce8176433b4b7c7295bb5d17411f1d216a8cda1878e2017884f2923f20d6a25bce70e820c4b8219785f37f3dd2e258a3717660181dd81ac473bcd8a40429796dca5e9d0090147ee94d9f7d4221859ccf41b7228b90b93532edaf96da6cb50d399e0e1ea1309428c6bb2ba993f26176efed52f436f65a7d1b572626cc0633dbc9be392403c4e1af4934b2ff5992c3bb5ca645342df94d3461d7ff9dc6a80eaadcd2b8efe0beb5da2bafe498cfb181ffb828e9b81e495f27b8f6e57085c7c1805144b239062f50be0cfd61b1ec90453d607b4e516bcb6507edb2e0dd36cb50aecf7513428ffbdcecd308edf56251536d35ea2afacec4d4893956c0f4856b4b130f8243973a550578e6558bae9c414b7ebfec48ff623da6beae1a79a51bfe5503e30fffc29453171e1e96a8e6b3018e24266a68f984ef9759fff037730bd1f66c74b528ac22475e26c73b990ab0615d65d709ab058f66edcc708d794d2bb16daee7c25359ad0556071ddb99e3f7c0fee8e02fe65f813c349eb49281a356d26b726110207b6e8f926131173d4058521aa12502238a7dc37fdcde6e02c734166753f731a9151001ed8dee72dc4cce62201ba28b60c273ac76774c825d0c96e54e44530bdc9c82c0fb98fdc6e6c12682fdb183a3bcd82cb421a967dff841c2bfe785fb9871b1a377eef11aa3df2c47301994735e9afd94604babe92ebea82193cd3487c25532c1c168d33a075cb4e7a282f59346c07645c9df4b4acbddad3d09a492701662ad3db11f5ac3a2f9ee737 \ No newline at end of file diff --git a/foundry-voting/circuits/target/debug_foundry_voting.json b/foundry-voting/circuits/target/debug_foundry_voting.json deleted file mode 100644 index 9666d3d..0000000 --- a/foundry-voting/circuits/target/debug_foundry_voting.json +++ /dev/null @@ -1 +0,0 @@ -{"debug_symbols":[{"locations":{"0":[{"span":{"start":199,"end":233},"file":0},{"span":{"start":755,"end":793},"file":23}],"1":[{"span":{"start":255,"end":307},"file":0},{"span":{"start":755,"end":793},"file":23}],"2":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":529,"end":555},"file":25},{"span":{"start":122,"end":149},"file":15}],"3":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":529,"end":555},"file":25},{"span":{"start":122,"end":149},"file":15}],"4":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":529,"end":555},"file":25},{"span":{"start":122,"end":149},"file":15}],"5":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":529,"end":555},"file":25},{"span":{"start":122,"end":149},"file":15}],"6":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":716,"end":728},"file":25}],"7":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"8":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"9":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"10":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"11":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"12":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"13":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"14":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":716,"end":728},"file":25}],"15":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"16":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"17":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"18":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"19":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"20":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"21":[{"span":{"start":331,"end":398},"file":0},{"span":{"start":821,"end":872},"file":25},{"span":{"start":755,"end":793},"file":23}],"22":[{"span":{"start":411,"end":429},"file":0}]}}],"file_map":{"0":{"source":"use dep::std;\n\nfn main(\n root: pub Field,\n index: Field,\n hash_path: [Field; 2],\n secret: Field,\n proposalId: pub Field,\n vote: pub Field\n) -> pub Field {\n let note_commitment = std::hash::pedersen_hash([secret]);\n let nullifier = std::hash::pedersen_hash([root, secret, proposalId]);\n\n let check_root = std::merkle::compute_merkle_root(note_commitment, index, hash_path);\n assert(root == check_root);\n\n // Originally contrained the vote to avoid front-running,\n // but including the vote as a public input is sufficient\n\n // assert(vote <= 1);\n\n nullifier\n}\n\n#[test]\nfn test_valid_build_merkle_tree() {\n let commitment_0 = std::hash::pedersen_hash([1]);\n let commitment_1 = std::hash::pedersen_hash([2]);\n let commitment_2 = std::hash::pedersen_hash([3]);\n let commitment_3 = std::hash::pedersen_hash([4]);\n\n let left_branch = std::hash::pedersen_hash([commitment_0, commitment_1]);\n let right_branch = std::hash::pedersen_hash([commitment_2, commitment_3]);\n\n let root = std::hash::pedersen_hash([left_branch, right_branch]);\n\n let proposalId = 0;\n let vote = 1;\n\n let nullifier = main(root, 0, [commitment_1, right_branch], 1, proposalId, vote);\n\n let expected_nullifier = std::hash::pedersen_hash([root, 1, proposalId]);\n\n std::println(\"Merkle Tree:\");\n std::println([root]);\n std::println([left_branch, right_branch]);\n std::println([commitment_0, commitment_1, commitment_2, commitment_3]);\n\n assert(nullifier == expected_nullifier);\n}\n\n// fn main(root : pub Field, index : Field, hash_path : [Field; 2], secret: Field, priv_key: Field, proposalId: pub Field, vote: pub u8) -> pub Field {\n// let note_commitment = std::hash::pedersen([priv_key, secret]);\n// let nullifier = std::hash::pedersen([root, priv_key, proposalId]);\n\n// let check_root = std::merkle::compute_merkle_root(note_commitment[0], index, hash_path);\n// assert(root == check_root);\n\n// // Originally contrained the vote to avoid front-running,\n// // but including the vote as a public input is sufficient\n\n// assert(vote <= 1);\n\n// nullifier[0]\n// }\n\n// Helpers for getting note_commitments to build the merkle tree.\n// To view: nargo test --show-output\n\n#[test]\nfn test_build_merkle_tree() {\n let secret = 9;\n let commitment_0 = std::hash::pedersen_hash([0, secret]);\n let commitment_1 = std::hash::pedersen_hash([1, secret]);\n let commitment_2 = std::hash::pedersen_hash([2, secret]);\n let commitment_3 = std::hash::pedersen_hash([3, secret]);\n\n let left_branch = std::hash::pedersen_hash([commitment_0, commitment_1]);\n let right_branch = std::hash::pedersen_hash([commitment_2, commitment_3]);\n\n let root = std::hash::pedersen_hash([left_branch, right_branch]);\n\n std::println(\"Merkle Tree:\");\n std::println([root]);\n std::println([left_branch, right_branch]);\n std::println([commitment_0, commitment_1, commitment_2, commitment_3]);\n}\n","path":"/home/josh/Documents/Github/noir-examples/foundry-voting/circuits/src/main.nr"},"15":{"source":"impl Field {\n pub fn to_le_bits(self: Self, bit_size: u32) -> [u1] {\n crate::assert_constant(bit_size);\n self.__to_le_bits(bit_size)\n }\n \n pub fn to_be_bits(self: Self, bit_size: u32) -> [u1] {\n crate::assert_constant(bit_size);\n self.__to_be_bits(bit_size)\n }\n\n #[builtin(to_le_bits)]\n fn __to_le_bits(_self: Self, _bit_size: u32) -> [u1] {}\n \n #[builtin(to_be_bits)]\n fn __to_be_bits(_self: Self, _bit_size: u32) -> [u1] {}\n\n pub fn to_le_bytes(self: Self, byte_size: u32) -> [u8] {\n self.to_le_radix(256, byte_size)\n }\n\n pub fn to_be_bytes(self: Self, byte_size: u32) -> [u8] {\n self.to_be_radix(256, byte_size)\n }\n\n\n pub fn to_le_radix(self: Self, radix: u32, result_len: u32) -> [u8] {\n crate::assert_constant(radix);\n crate::assert_constant(result_len);\n self.__to_le_radix(radix, result_len)\n }\n\n pub fn to_be_radix(self: Self, radix: u32, result_len: u32) -> [u8] {\n crate::assert_constant(radix);\n crate::assert_constant(result_len);\n self.__to_be_radix(radix, result_len)\n }\n\n\n\n // decompose `_self` into a `_result_len` vector over the `_radix` basis\n // `_radix` must be less than 256\n #[builtin(to_le_radix)]\n fn __to_le_radix(_self: Self, _radix: u32, _result_len: u32) -> [u8] {}\n \n #[builtin(to_be_radix)]\n fn __to_be_radix(_self: Self, _radix: u32, _result_len: u32) -> [u8] {}\n\n\n // Returns self to the power of the given exponent value.\n // Caution: we assume the exponent fits into 32 bits\n // using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits\n pub fn pow_32(self, exponent: Field) -> Field {\n let mut r: Field = 1;\n let b = exponent.to_le_bits(32);\n\n for i in 1..33 {\n r *= r;\n r = (b[32-i] as Field) * (r * self) + (1 - b[32-i] as Field) * r;\n }\n r\n }\n\n // Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1.\n pub fn sgn0(self) -> u1 {\n self as u1\n }\n}\n\n#[builtin(modulus_num_bits)]\npub fn modulus_num_bits() -> Field {}\n\n#[builtin(modulus_be_bits)]\npub fn modulus_be_bits() -> [u1] {}\n\n#[builtin(modulus_le_bits)]\npub fn modulus_le_bits() -> [u1] {}\n\n#[builtin(modulus_be_bytes)]\npub fn modulus_be_bytes() -> [u8] {}\n\n#[builtin(modulus_le_bytes)]\npub fn modulus_le_bytes() -> [u8] {}\n// Convert a 32 byte array to a field element\npub fn bytes32_to_field(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..16 {\n high = high + (bytes32[15 - i] as Field) * v;\n low = low + (bytes32[16 + 15 - i] as Field) * v;\n v = v * 256;\n }\n // Abuse that a % p + b % p = (a + b) % p and that low < p\n low + high * v\n}\n","path":"std/field.nr"},"23":{"source":"mod poseidon;\nmod mimc;\n\n#[foreign(sha256)]\npub fn sha256(_input: [u8; N]) -> [u8; 32] {}\n\n#[foreign(blake2s)]\npub fn blake2s(_input: [u8; N]) -> [u8; 32] {}\n\nstruct PedersenPoint {\n x : Field,\n y : Field,\n}\n\npub fn pedersen_commitment(input: [Field; N]) -> PedersenPoint {\n pedersen_commitment_with_separator(input, 0)\n}\n\n#[foreign(pedersen_commitment)]\npub fn __pedersen_commitment_with_separator(_input: [Field; N], _separator: u32) -> [Field; 2] {}\n\npub fn pedersen_commitment_with_separator(input: [Field; N], separator: u32) -> PedersenPoint {\n let values = __pedersen_commitment_with_separator(input, separator);\n PedersenPoint { x: values[0], y: values[1] }\n}\n\npub fn pedersen_hash(input: [Field; N]) -> Field {\n pedersen_hash_with_separator(input, 0)\n}\n\n#[foreign(pedersen_hash)]\npub fn pedersen_hash_with_separator(_input: [Field; N], _separator: u32) -> Field {}\n\npub fn hash_to_field(_input: [Field; N]) -> Field {\n let mut inputs_as_bytes = [];\n\n for i in 0..N {\n let input_bytes = _input[i].to_le_bytes(32);\n for i in 0..32 {\n inputs_as_bytes = inputs_as_bytes.push_back(input_bytes[i]);\n }\n }\n\n let hashed_input = blake2s(inputs_as_bytes);\n crate::field::bytes32_to_field(hashed_input)\n}\n\n#[foreign(keccak256)]\npub fn keccak256(_input: [u8; N], _message_size: u32) -> [u8; 32] {}\n\n","path":"std/hash.nr"},"25":{"source":"// Regular merkle tree means a append-only merkle tree (Explain why this is the only way to have privacy and alternatives if you don't want it)\n// Currently we assume that it is a binary tree, so depth k implies a width of 2^k\n// XXX: In the future we can add an arity parameter\n// Returns the merkle root of the tree from the provided leaf, its hashpath, using a pedersen hash function.\npub fn compute_merkle_root(leaf: Field, index: Field, hash_path: [Field; N]) -> Field {\n let n = hash_path.len();\n let index_bits = index.to_le_bits(n as u32);\n let mut current = leaf;\n for i in 0..n {\n let path_bit = index_bits[i] as bool;\n let (hash_left, hash_right) = if path_bit {\n (hash_path[i], current)\n } else {\n (current, hash_path[i])\n };\n current = crate::hash::pedersen_hash([hash_left, hash_right]);\n }\n current\n}\n","path":"std/merkle.nr"}},"warnings":[]} \ No newline at end of file diff --git a/foundry-voting/circuits/target/foundry_voting.json b/foundry-voting/circuits/target/foundry_voting.json deleted file mode 100644 index b8b9b7e..0000000 --- a/foundry-voting/circuits/target/foundry_voting.json +++ /dev/null @@ -1 +0,0 @@ -{"noir_version":"0.22.0+3fae4a03fded4e3f5065e7461c563f7e39745604","hash":14491308408831426258,"abi":{"parameters":[{"name":"root","type":{"kind":"field"},"visibility":"public"},{"name":"index","type":{"kind":"field"},"visibility":"private"},{"name":"hash_path","type":{"kind":"array","length":2,"type":{"kind":"field"}},"visibility":"private"},{"name":"secret","type":{"kind":"field"},"visibility":"private"},{"name":"proposalId","type":{"kind":"field"},"visibility":"public"},{"name":"vote","type":{"kind":"field"},"visibility":"public"}],"param_witnesses":{"hash_path":[{"start":3,"end":5}],"index":[{"start":2,"end":3}],"proposalId":[{"start":6,"end":7}],"root":[{"start":1,"end":2}],"secret":[{"start":5,"end":6}],"vote":[{"start":7,"end":8}]},"return_type":{"abi_type":{"kind":"field"},"visibility":"public"},"return_witnesses":[9]},"bytecode":"H4sIAAAAAAAA/9VYbW6DMAx16cdW6Nqu3bRN2qROu0BCoIR/u8rQ4P4nqIrVoAZ+lucKLEUEET3iZ/s5yg8RvdHFJvV4cE+2eT1Obv7ofZ9660/euoW3flmPwMMib/7rnqqf6QCHpQKHE9YjcnuX2HPo/tHFNeqYJGUWl9roPxXnhU1VkhZHq61ObfofW2NKm9gsL/JM5Toxpa7S3FQOOARyIeF35HhF+x2B/W5sKpiryFjfilVWF5PiLxDM775YK2BcJWqFc09CI15o2BrBPWYl4Pcr3Ucj+u7zCcglMNYazZ9EvUjkzfsI6kVCJz5oHPWyBnIJjLVG8tecuZt+yhrBZ+w1Xc/aG2obuvdGQKwtDbv3zkjmnPpJw9YSzqGtgN9fNA4teQZyCYy1RvMnUS8SeXMYuN+sERsBv79pHPWyA3J5AGIh+ev2XtYI7rk7uvbePbWt23tVP9MTYMz2QG5mnr+cW/w+p/bd4ILa94lLj6czaflhJ3gUAAA="} \ No newline at end of file