diff --git a/README.md b/README.md index c6563f6..3c01302 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,11 @@ Deploy cost (T3) - circomlibjs: 2,156,516 gas Hash cost (T2) - - poseidon-solidity: 18,614 gas + - poseidon-solidity: 15,548 gas - circomlibjs: 19,395 gas Hash cost (T3) - - poseidon-solidity: 29,893 gas + - poseidon-solidity: 25,806 gas - circomlibjs: 32,173 gas Hash cost (T4) diff --git a/contracts/PoseidonT2.sol b/contracts/PoseidonT2.sol index 7fcbcdd..dbb08c9 100644 --- a/contracts/PoseidonT2.sol +++ b/contracts/PoseidonT2.sol @@ -2,8 +2,6 @@ pragma solidity >=0.7.0; library PoseidonT2 { - uint constant F = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - uint constant M00 = 0x066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad5; uint constant M01 = 0x0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff9; uint constant M10 = 0x2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e8; @@ -13,197 +11,294 @@ library PoseidonT2 { // Based on: https://github.com/iden3/circomlibjs/blob/v0.0.8/src/poseidon_slow.js function hash(uint[1] memory) public pure returns (uint) { assembly { - // memory 0x00 to 0x3f (64 bytes) is scratch space for hash algos - // we can use it in inline assembly because we're not calling e.g. keccak - // - // memory 0x80 is the default offset for free memory - // we take inputs as a memory argument so we simply write over - // that memory after loading it - - // we have the following variables at memory offsets - // state0 - 0x00 - // state1 - 0x20 - // state2 - 0x80 - // state3 - 0xa0 - // state4 - ... - - function pRound(c0, c1) { - let state0 := addmod(mload(0x0), c0, F) - let state1 := addmod(mload(0x20), c1, F) - - let p := mulmod(state0, state0, F) - state0 := mulmod(mulmod(p, p, F), state0, F) - - mstore(0x0, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F)) - mstore(0x20, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F)) - } - - function fRound(c0, c1) { - let state0 := addmod(mload(0x0), c0, F) - let state1 := addmod(mload(0x20), c1, F) - - let p := mulmod(state0, state0, F) - state0 := mulmod(mulmod(p, p, F), state0, F) - p := mulmod(state1, state1, F) - state1 := mulmod(mulmod(p, p, F), state1, F) - - mstore(0x0, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F)) - mstore(0x20, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F)) - } - - // scratch variable for exponentiation - let p - - { - // load the inputs from memory - let state1 := addmod(mload(0x80), 0x0c0356530896eec42a97ed937f3135cfc5142b3ae405b8343c1d83ffa604cb81, F) - mstore(0x20, addmod(mload(0xa0), 0x1e28a1d935698ad1142e51182bb54cf4a00ea5aabd6268bd317ea977cc154a30, F)) - - p := mulmod(state1, state1, F) - state1 := mulmod(mulmod(p, p, F), state1, F) - - // state0 pow5mod and M[] multiplications are pre-calculated - - mstore(0x0, addmod(0x4b87ca7dc8593e8efd436c4e47f32a16e36f24c756ebb53ff0ab98c1608e8f5, mulmod(state1, M10, F), F)) - mstore(0x20, addmod(0x20a7d25895731bd7cf65a14cce92a52ae70d529cd9531696f88536d5859bf85a, mulmod(state1, M11, F), F)) - } - - fRound(0x1e28a1d935698ad1142e51182bb54cf4a00ea5aabd6268bd317ea977cc154a30, 0x27af2d831a9d2748080965db30e298e40e5757c3e008db964cf9e2b12b91251f) - - fRound(0x1e6f11ce60fc8f513a6a3cfe16ae175a41291462f214cd0879aaf43545b74e03, 0x2a67384d3bbd5e438541819cb681f0be04462ed14c3613d8f719206268d142d3) - - fRound(0x0b66fdf356093a611609f8e12fbfecf0b985e381f025188936408f5d5c9f45d0, 0x012ee3ec1e78d470830c61093c2ade370b26c83cc5cebeeddaa6852dbdb09e21) - - pRound(0x0252ba5f6760bfbdfd88f67f8175e3fd6cd1c431b099b6bb2d108e7b445bb1b9, 0x179474cceca5ff676c6bec3cef54296354391a8935ff71d6ef5aeaad7ca932f1) - - pRound(0x2c24261379a51bfa9228ff4a503fd4ed9c1f974a264969b37e1a2589bbed2b91, 0x1cc1d7b62692e63eac2f288bd0695b43c2f63f5001fc0fc553e66c0551801b05) - - pRound(0x255059301aada98bb2ed55f852979e9600784dbf17fbacd05d9eff5fd9c91b56, 0x28437be3ac1cb2e479e1f5c0eccd32b3aea24234970a8193b11c29ce7e59efd9) - - pRound(0x28216a442f2e1f711ca4fa6b53766eb118548da8fb4f78d4338762c37f5f2043, 0x2c1f47cd17fa5adf1f39f4e7056dd03feee1efce03094581131f2377323482c9) - - pRound(0x07abad02b7a5ebc48632bcc9356ceb7dd9dafca276638a63646b8566a621afc9, 0x0230264601ffdf29275b33ffaab51dfe9429f90880a69cd137da0c4d15f96c3c) - - pRound(0x1bc973054e51d905a0f168656497ca40a864414557ee289e717e5d66899aa0a9, 0x2e1c22f964435008206c3157e86341edd249aff5c2d8421f2a6b22288f0a67fc) - - pRound(0x1224f38df67c5378121c1d5f461bbc509e8ea1598e46c9f7a70452bc2bba86b8, 0x02e4e69d8ba59e519280b4bd9ed0068fd7bfe8cd9dfeda1969d2989186cde20e) - - pRound(0x1f1eccc34aaba0137f5df81fc04ff3ee4f19ee364e653f076d47e9735d98018e, 0x1672ad3d709a353974266c3039a9a7311424448032cd1819eacb8a4d4284f582) - - pRound(0x283e3fdc2c6e420c56f44af5192b4ae9cda6961f284d24991d2ed602df8c8fc7, 0x1c2a3d120c550ecfd0db0957170fa013683751f8fdff59d6614fbd69ff394bcc) - - pRound(0x216f84877aac6172f7897a7323456efe143a9a43773ea6f296cb6b8177653fbd, 0x2c0d272becf2a75764ba7e8e3e28d12bceaa47ea61ca59a411a1f51552f94788) - - pRound(0x16e34299865c0e28484ee7a74c454e9f170a5480abe0508fcb4a6c3d89546f43, 0x175ceba599e96f5b375a232a6fb9cc71772047765802290f48cd939755488fc5) - - pRound(0x0c7594440dc48c16fead9e1758b028066aa410bfbc354f54d8c5ffbb44a1ee32, 0x1a3c29bc39f21bb5c466db7d7eb6fd8f760e20013ccf912c92479882d919fd8d) - - pRound(0x0ccfdd906f3426e5c0986ea049b253400855d349074f5a6695c8eeabcd22e68f, 0x14f6bc81d9f186f62bdb475ce6c9411866a7a8a3fd065b3ce0e699b67dd9e796) - - pRound(0x0962b82789fb3d129702ca70b2f6c5aacc099810c9c495c888edeb7386b97052, 0x1a880af7074d18b3bf20c79de25127bc13284ab01ef02575afef0c8f6a31a86d) - - pRound(0x10cba18419a6a332cd5e77f0211c154b20af2924fc20ff3f4c3012bb7ae9311b, 0x057e62a9a8f89b3ebdc76ba63a9eaca8fa27b7319cae3406756a2849f302f10d) - - pRound(0x287c971de91dc0abd44adf5384b4988cb961303bbf65cff5afa0413b44280cee, 0x21df3388af1687bbb3bca9da0cca908f1e562bc46d4aba4e6f7f7960e306891d) - - pRound(0x1be5c887d25bce703e25cc974d0934cd789df8f70b498fd83eff8b560e1682b3, 0x268da36f76e568fb68117175cea2cd0dd2cb5d42fda5acea48d59c2706a0d5c1) - - pRound(0x0e17ab091f6eae50c609beaf5510ececc5d8bb74135ebd05bd06460cc26a5ed6, 0x04d727e728ffa0a67aee535ab074a43091ef62d8cf83d270040f5caa1f62af40) - - pRound(0x0ddbd7bf9c29341581b549762bc022ed33702ac10f1bfd862b15417d7e39ca6e, 0x2790eb3351621752768162e82989c6c234f5b0d1d3af9b588a29c49c8789654b) - - pRound(0x1e457c601a63b73e4471950193d8a570395f3d9ab8b2fd0984b764206142f9e9, 0x21ae64301dca9625638d6ab2bbe7135ffa90ecd0c43ff91fc4c686fc46e091b0) - - pRound(0x0379f63c8ce3468d4da293166f494928854be9e3432e09555858534eed8d350b, 0x002d56420359d0266a744a080809e054ca0e4921a46686ac8c9f58a324c35049) - - pRound(0x123158e5965b5d9b1d68b3cd32e10bbeda8d62459e21f4090fc2c5af963515a6, 0x0be29fc40847a941661d14bbf6cbe0420fbb2b6f52836d4e60c80eb49cad9ec1) - - pRound(0x1ac96991dec2bb0557716142015a453c36db9d859cad5f9a233802f24fdf4c1a, 0x1596443f763dbcc25f4964fc61d23b3e5e12c9fa97f18a9251ca3355bcb0627e) - - pRound(0x12e0bcd3654bdfa76b2861d4ec3aeae0f1857d9f17e715aed6d049eae3ba3212, 0x0fc92b4f1bbea82b9ea73d4af9af2a50ceabac7f37154b1904e6c76c7cf964ba) - - pRound(0x1f9c0b1610446442d6f2e592a8013f40b14f7c7722236f4f9c7e965233872762, 0x0ebd74244ae72675f8cde06157a782f4050d914da38b4c058d159f643dbbf4d3) - - pRound(0x2cb7f0ed39e16e9f69a9fafd4ab951c03b0671e97346ee397a839839dccfc6d1, 0x1a9d6e2ecff022cc5605443ee41bab20ce761d0514ce526690c72bca7352d9bf) - - pRound(0x2a115439607f335a5ea83c3bc44a9331d0c13326a9a7ba3087da182d648ec72f, 0x23f9b6529b5d040d15b8fa7aee3e3410e738b56305cd44f29535c115c5a4c060) - - pRound(0x05872c16db0f72a2249ac6ba484bb9c3a3ce97c16d58b68b260eb939f0e6e8a7, 0x1300bdee08bb7824ca20fb80118075f40219b6151d55b5c52b624a7cdeddf6a7) - - pRound(0x19b9b63d2f108e17e63817863a8f6c288d7ad29916d98cb1072e4e7b7d52b376, 0x015bee1357e3c015b5bda237668522f613d1c88726b5ec4224a20128481b4f7f) - - pRound(0x2953736e94bb6b9f1b9707a4f1615e4efe1e1ce4bab218cbea92c785b128ffd1, 0x0b069353ba091618862f806180c0385f851b98d372b45f544ce7266ed6608dfc) - - pRound(0x304f74d461ccc13115e4e0bcfb93817e55aeb7eb9306b64e4f588ac97d81f429, 0x15bbf146ce9bca09e8a33f5e77dfe4f5aad2a164a4617a4cb8ee5415cde913fc) - - pRound(0x0ab4dfe0c2742cde44901031487964ed9b8f4b850405c10ca9ff23859572c8c6, 0x0e32db320a044e3197f45f7649a19675ef5eedfea546dea9251de39f9639779a) - - pRound(0x0a1756aa1f378ca4b27635a78b6888e66797733a82774896a3078efa516da016, 0x044c4a33b10f693447fd17177f952ef895e61d328f85efa94254d6a2a25d93ef) - - pRound(0x2ed3611b725b8a70be655b537f66f700fe0879d79a496891d37b07b5466c4b8b, 0x1f9ba4e8bab7ce42c8ecc3d722aa2e0eadfdeb9cfdd347b5d8339ea7120858aa) - - pRound(0x1b233043052e8c288f7ee907a84e518aa38e82ac4502066db74056f865c5d3da, 0x2431e1cc164bb8d074031ab72bd55b4c902053bfc0f14db0ca2f97b020875954) - - pRound(0x082f934c91f5aac330cd6953a0a7db45a13e322097583319a791f273965801fd, 0x2b9a0a223e7538b0a34be074315542a3c77245e2ae7cbe999ad6bb930c48997c) - - pRound(0x0e1cd91edd2cfa2cceb85483b887a9be8164163e75a8a00eb0b589cc70214e7d, 0x2e1eac0f2bfdfd63c951f61477e3698999774f19854d00f588d324601cebe2f9) - - pRound(0x0cbfa95f37fb74060c76158e769d6d157345784d8efdb33c23d748115b500b83, 0x08f05b3be923ed44d65ad49d8a61e9a676d991e3a77513d9980c232dfa4a4f84) - - pRound(0x22719e2a070bcd0852bf8e21984d0443e7284925dc0758a325a2dd510c047ef6, 0x041f596a9ee1cb2bc060f7fcc3a1ab4c7bdbf036119982c0f41f62b2f26830c0) - - pRound(0x233fd35de1be520a87628eb06f6b1d4c021be1c2d0dc464a19fcdd0986b10f89, 0x0524b46d1aa87a5e4325e0a423ebc810d31e078aa1b4707eefcb453c61c9c267) - - pRound(0x2c34f424c81e5716ce47fcac894b85824227bb954b0f3199cc4486237c515211, 0x0b5f2a4b63387819207effc2b5541fb72dd2025b5457cc97f33010327de4915e) - - pRound(0x22207856082ccc54c5b72fe439d2cfd6c17435d2f57af6ceaefac41fe05c659f, 0x24d57a8bf5da63fe4e24159b7f8950b5cdfb210194caf79f27854048ce2c8171) - - pRound(0x0afab181fdd5e0583b371d75bd693f98374ad7097bb01a8573919bb23b79396e, 0x2dba9b108f208772998a52efac7cbd5676c0057194c16c0bf16290d62b1128ee) - - pRound(0x26349b66edb8b16f56f881c788f53f83cbb83de0bd592b255aff13e6bce420b3, 0x25af7ce0e5e10357685e95f92339753ad81a56d28ecc193b235288a3e6f137db) - - pRound(0x25b4ce7bd2294390c094d6a55edd68b970eed7aae88b2bff1f7c0187fe35011f, 0x22c543f10f6c89ec387e53f1908a88e5de9cef28ebdf30b18cb9d54c1e02b631) - - pRound(0x0236f93e7789c4724fc7908a9f191e1e425e906a919d7a34df668e74882f87a9, 0x29350b401166ca010e7d27e37d05da99652bdae114eb01659cb497af980c4b52) - - pRound(0x0eed787d65820d3f6bd31bbab547f75a65edb75d844ebb89ee1260916652363f, 0x07cc1170f13b46f2036a753f520b3291fdcd0e99bd94297d1906f656f4de6fad) - - pRound(0x22b939233b1d7205f49bcf613a3d30b1908786d7f9f5d10c2059435689e8acea, 0x01451762a0aab81c8aad1dc8bc33e870740f083a5aa85438add650ace60ae5a6) - - pRound(0x23506bb5d8727d4461fabf1025d46d1fe32eaa61dec7da57e704fec0892fce89, 0x2e484c44e838aea0bac06ae3f71bdd092a3709531e1efea97f8bd68907355522) - - pRound(0x0f4bc7d07ebafd64379e78c50bd2e42baf4a594545cedc2545418da26835b54c, 0x1f4d3c8f6583e9e5fa76637862faaee851582388725df460e620996d50d8e74e) - - pRound(0x093514e0c70711f82660d07be0e4a988fae02abc7b681d9153eb9bcb48fe7389, 0x1adab0c8e2b3bad346699a2b5f3bc03643ee83ece47228f24a58e0a347e153d8) - - pRound(0x1672b1726057d99dd14709ebb474641a378c1b94b8072bac1a22dbef9e80dad2, 0x1dfd53d4576af2e38f44f53fdcab468cc5d8e2fae0acc4ee30d47b239b479c14) - - pRound(0x0c6888a10b75b0f3a70a36263a37e17fe6d77d640f6fc3debc7f207753205c60, 0x1addb933a65be77092b34a7e77d12fe8611a61e00ee6848b85091ecca9d1e508) - - pRound(0x00d7540dcd268a845c10ae18d1de933cf638ff5425f0afff7935628e299d1791, 0x140c0e42687e9ead01b2827a5664ca9c26fedde4acd99db1d316939d20b82c0e) - - pRound(0x2f0c3a115d4317d191ba89b8d13d1806c20a0f9b24f8c5edc091e2ae56565984, 0x0c4ee778ff7c14553006ed220cf9c81008a0cff670b22b82d8c538a1dc958c61) - - pRound(0x1704f2766d46f82c3693f00440ccc3609424ed26c0acc66227c3d7485de74c69, 0x2f2d19cc3ea5d78ea7a02c1b51d244abf0769c9f8544e40239b66fe9009c3cfa) - - fRound(0x1ae03853b75fcaba5053f112e2a8e8dcdd7ee6cb9cfed9c7d6c766a806fc6629, 0x0971aabf795241df51d131d0fa61aa5f3556921b2d6f014e4e41a86ddaf056d5) - - fRound(0x1408c316e6014e1a91d4cf6b6e0de73eda624f8380df1c875f5c29f7bfe2f646, 0x1667f3fe2edbe850248abe42b543093b6c89f1f773ef285341691f39822ef5bd) - - fRound(0x13bf7c5d0d2c4376a48b0a03557cdf915b81718409e5c133424c69576500fe37, 0x07620a6dfb0b6cec3016adf3d3533c24024b95347856b79719bc0ba743a62c2c) - - { - let state0 := addmod(mload(0x0), 0x1574c7ef0c43545f36a8ca08bdbdd8b075d2959e2f322b731675de3e1982b4d0, F) - let state1 := addmod(mload(0x20), 0x269e4b5b7a2eb21afd567970a717ceec5bd4184571c254fdc06e03a7ff8378f0, F) - - p := mulmod(state0, state0, F) - state0 := mulmod(mulmod(p, p, F), state0, F) - p := mulmod(state1, state1, F) - state1 := mulmod(mulmod(p, p, F), state1, F) - - mstore(0x0, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F)) - return(0, 0x20) - } + let F := 21888242871839275222246405745257275088548364400416034343698204186575808495617 + // load the inputs from memory + let state0 + let scratch0 + let state1 + let scratch1 + + state1 := addmod(mload(0x80), 0x0c0356530896eec42a97ed937f3135cfc5142b3ae405b8343c1d83ffa604cb81, F) + scratch0 := mulmod(state1, state1, F) + state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F) + scratch0 := addmod( + 0x1e28a1d935698ad1142e51182bb54cf4a00ea5aabd6268bd317ea977cc154a30, + addmod(2135211596334038589877319861485022046541061518379136709265746501298180122869, mulmod(state1, M10, F), F), + F + ) + scratch1 := addmod( + 0x27af2d831a9d2748080965db30e298e40e5757c3e008db964cf9e2b12b91251f, + addmod(14770526369429531795265880089668477939070475643153877209429555040029415045210, mulmod(state1, M11, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := mulmod(scratch1, scratch1, F) + scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F) + state0 := addmod(0x1e6f11ce60fc8f513a6a3cfe16ae175a41291462f214cd0879aaf43545b74e03, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x2a67384d3bbd5e438541819cb681f0be04462ed14c3613d8f719206268d142d3, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := mulmod(state1, state1, F) + state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F) + scratch0 := addmod(0x0b66fdf356093a611609f8e12fbfecf0b985e381f025188936408f5d5c9f45d0, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x012ee3ec1e78d470830c61093c2ade370b26c83cc5cebeeddaa6852dbdb09e21, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := mulmod(scratch1, scratch1, F) + scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F) + state0 := addmod(0x0252ba5f6760bfbdfd88f67f8175e3fd6cd1c431b099b6bb2d108e7b445bb1b9, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x179474cceca5ff676c6bec3cef54296354391a8935ff71d6ef5aeaad7ca932f1, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x2c24261379a51bfa9228ff4a503fd4ed9c1f974a264969b37e1a2589bbed2b91, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x1cc1d7b62692e63eac2f288bd0695b43c2f63f5001fc0fc553e66c0551801b05, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x255059301aada98bb2ed55f852979e9600784dbf17fbacd05d9eff5fd9c91b56, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x28437be3ac1cb2e479e1f5c0eccd32b3aea24234970a8193b11c29ce7e59efd9, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x28216a442f2e1f711ca4fa6b53766eb118548da8fb4f78d4338762c37f5f2043, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x2c1f47cd17fa5adf1f39f4e7056dd03feee1efce03094581131f2377323482c9, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x07abad02b7a5ebc48632bcc9356ceb7dd9dafca276638a63646b8566a621afc9, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x0230264601ffdf29275b33ffaab51dfe9429f90880a69cd137da0c4d15f96c3c, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x1bc973054e51d905a0f168656497ca40a864414557ee289e717e5d66899aa0a9, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x2e1c22f964435008206c3157e86341edd249aff5c2d8421f2a6b22288f0a67fc, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x1224f38df67c5378121c1d5f461bbc509e8ea1598e46c9f7a70452bc2bba86b8, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x02e4e69d8ba59e519280b4bd9ed0068fd7bfe8cd9dfeda1969d2989186cde20e, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x1f1eccc34aaba0137f5df81fc04ff3ee4f19ee364e653f076d47e9735d98018e, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x1672ad3d709a353974266c3039a9a7311424448032cd1819eacb8a4d4284f582, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x283e3fdc2c6e420c56f44af5192b4ae9cda6961f284d24991d2ed602df8c8fc7, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x1c2a3d120c550ecfd0db0957170fa013683751f8fdff59d6614fbd69ff394bcc, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x216f84877aac6172f7897a7323456efe143a9a43773ea6f296cb6b8177653fbd, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x2c0d272becf2a75764ba7e8e3e28d12bceaa47ea61ca59a411a1f51552f94788, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x16e34299865c0e28484ee7a74c454e9f170a5480abe0508fcb4a6c3d89546f43, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x175ceba599e96f5b375a232a6fb9cc71772047765802290f48cd939755488fc5, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x0c7594440dc48c16fead9e1758b028066aa410bfbc354f54d8c5ffbb44a1ee32, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x1a3c29bc39f21bb5c466db7d7eb6fd8f760e20013ccf912c92479882d919fd8d, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x0ccfdd906f3426e5c0986ea049b253400855d349074f5a6695c8eeabcd22e68f, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x14f6bc81d9f186f62bdb475ce6c9411866a7a8a3fd065b3ce0e699b67dd9e796, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x0962b82789fb3d129702ca70b2f6c5aacc099810c9c495c888edeb7386b97052, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x1a880af7074d18b3bf20c79de25127bc13284ab01ef02575afef0c8f6a31a86d, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x10cba18419a6a332cd5e77f0211c154b20af2924fc20ff3f4c3012bb7ae9311b, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x057e62a9a8f89b3ebdc76ba63a9eaca8fa27b7319cae3406756a2849f302f10d, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x287c971de91dc0abd44adf5384b4988cb961303bbf65cff5afa0413b44280cee, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x21df3388af1687bbb3bca9da0cca908f1e562bc46d4aba4e6f7f7960e306891d, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x1be5c887d25bce703e25cc974d0934cd789df8f70b498fd83eff8b560e1682b3, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x268da36f76e568fb68117175cea2cd0dd2cb5d42fda5acea48d59c2706a0d5c1, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x0e17ab091f6eae50c609beaf5510ececc5d8bb74135ebd05bd06460cc26a5ed6, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x04d727e728ffa0a67aee535ab074a43091ef62d8cf83d270040f5caa1f62af40, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x0ddbd7bf9c29341581b549762bc022ed33702ac10f1bfd862b15417d7e39ca6e, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x2790eb3351621752768162e82989c6c234f5b0d1d3af9b588a29c49c8789654b, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x1e457c601a63b73e4471950193d8a570395f3d9ab8b2fd0984b764206142f9e9, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x21ae64301dca9625638d6ab2bbe7135ffa90ecd0c43ff91fc4c686fc46e091b0, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x0379f63c8ce3468d4da293166f494928854be9e3432e09555858534eed8d350b, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x002d56420359d0266a744a080809e054ca0e4921a46686ac8c9f58a324c35049, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x123158e5965b5d9b1d68b3cd32e10bbeda8d62459e21f4090fc2c5af963515a6, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x0be29fc40847a941661d14bbf6cbe0420fbb2b6f52836d4e60c80eb49cad9ec1, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x1ac96991dec2bb0557716142015a453c36db9d859cad5f9a233802f24fdf4c1a, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x1596443f763dbcc25f4964fc61d23b3e5e12c9fa97f18a9251ca3355bcb0627e, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x12e0bcd3654bdfa76b2861d4ec3aeae0f1857d9f17e715aed6d049eae3ba3212, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x0fc92b4f1bbea82b9ea73d4af9af2a50ceabac7f37154b1904e6c76c7cf964ba, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x1f9c0b1610446442d6f2e592a8013f40b14f7c7722236f4f9c7e965233872762, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x0ebd74244ae72675f8cde06157a782f4050d914da38b4c058d159f643dbbf4d3, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x2cb7f0ed39e16e9f69a9fafd4ab951c03b0671e97346ee397a839839dccfc6d1, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x1a9d6e2ecff022cc5605443ee41bab20ce761d0514ce526690c72bca7352d9bf, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x2a115439607f335a5ea83c3bc44a9331d0c13326a9a7ba3087da182d648ec72f, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x23f9b6529b5d040d15b8fa7aee3e3410e738b56305cd44f29535c115c5a4c060, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x05872c16db0f72a2249ac6ba484bb9c3a3ce97c16d58b68b260eb939f0e6e8a7, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x1300bdee08bb7824ca20fb80118075f40219b6151d55b5c52b624a7cdeddf6a7, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x19b9b63d2f108e17e63817863a8f6c288d7ad29916d98cb1072e4e7b7d52b376, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x015bee1357e3c015b5bda237668522f613d1c88726b5ec4224a20128481b4f7f, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x2953736e94bb6b9f1b9707a4f1615e4efe1e1ce4bab218cbea92c785b128ffd1, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x0b069353ba091618862f806180c0385f851b98d372b45f544ce7266ed6608dfc, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x304f74d461ccc13115e4e0bcfb93817e55aeb7eb9306b64e4f588ac97d81f429, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x15bbf146ce9bca09e8a33f5e77dfe4f5aad2a164a4617a4cb8ee5415cde913fc, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x0ab4dfe0c2742cde44901031487964ed9b8f4b850405c10ca9ff23859572c8c6, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x0e32db320a044e3197f45f7649a19675ef5eedfea546dea9251de39f9639779a, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x0a1756aa1f378ca4b27635a78b6888e66797733a82774896a3078efa516da016, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x044c4a33b10f693447fd17177f952ef895e61d328f85efa94254d6a2a25d93ef, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x2ed3611b725b8a70be655b537f66f700fe0879d79a496891d37b07b5466c4b8b, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x1f9ba4e8bab7ce42c8ecc3d722aa2e0eadfdeb9cfdd347b5d8339ea7120858aa, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x1b233043052e8c288f7ee907a84e518aa38e82ac4502066db74056f865c5d3da, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x2431e1cc164bb8d074031ab72bd55b4c902053bfc0f14db0ca2f97b020875954, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x082f934c91f5aac330cd6953a0a7db45a13e322097583319a791f273965801fd, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x2b9a0a223e7538b0a34be074315542a3c77245e2ae7cbe999ad6bb930c48997c, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x0e1cd91edd2cfa2cceb85483b887a9be8164163e75a8a00eb0b589cc70214e7d, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x2e1eac0f2bfdfd63c951f61477e3698999774f19854d00f588d324601cebe2f9, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x0cbfa95f37fb74060c76158e769d6d157345784d8efdb33c23d748115b500b83, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x08f05b3be923ed44d65ad49d8a61e9a676d991e3a77513d9980c232dfa4a4f84, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x22719e2a070bcd0852bf8e21984d0443e7284925dc0758a325a2dd510c047ef6, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x041f596a9ee1cb2bc060f7fcc3a1ab4c7bdbf036119982c0f41f62b2f26830c0, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x233fd35de1be520a87628eb06f6b1d4c021be1c2d0dc464a19fcdd0986b10f89, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x0524b46d1aa87a5e4325e0a423ebc810d31e078aa1b4707eefcb453c61c9c267, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x2c34f424c81e5716ce47fcac894b85824227bb954b0f3199cc4486237c515211, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x0b5f2a4b63387819207effc2b5541fb72dd2025b5457cc97f33010327de4915e, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x22207856082ccc54c5b72fe439d2cfd6c17435d2f57af6ceaefac41fe05c659f, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x24d57a8bf5da63fe4e24159b7f8950b5cdfb210194caf79f27854048ce2c8171, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x0afab181fdd5e0583b371d75bd693f98374ad7097bb01a8573919bb23b79396e, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x2dba9b108f208772998a52efac7cbd5676c0057194c16c0bf16290d62b1128ee, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x26349b66edb8b16f56f881c788f53f83cbb83de0bd592b255aff13e6bce420b3, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x25af7ce0e5e10357685e95f92339753ad81a56d28ecc193b235288a3e6f137db, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x25b4ce7bd2294390c094d6a55edd68b970eed7aae88b2bff1f7c0187fe35011f, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x22c543f10f6c89ec387e53f1908a88e5de9cef28ebdf30b18cb9d54c1e02b631, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x0236f93e7789c4724fc7908a9f191e1e425e906a919d7a34df668e74882f87a9, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x29350b401166ca010e7d27e37d05da99652bdae114eb01659cb497af980c4b52, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x0eed787d65820d3f6bd31bbab547f75a65edb75d844ebb89ee1260916652363f, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x07cc1170f13b46f2036a753f520b3291fdcd0e99bd94297d1906f656f4de6fad, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x22b939233b1d7205f49bcf613a3d30b1908786d7f9f5d10c2059435689e8acea, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x01451762a0aab81c8aad1dc8bc33e870740f083a5aa85438add650ace60ae5a6, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x23506bb5d8727d4461fabf1025d46d1fe32eaa61dec7da57e704fec0892fce89, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x2e484c44e838aea0bac06ae3f71bdd092a3709531e1efea97f8bd68907355522, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x0f4bc7d07ebafd64379e78c50bd2e42baf4a594545cedc2545418da26835b54c, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x1f4d3c8f6583e9e5fa76637862faaee851582388725df460e620996d50d8e74e, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x093514e0c70711f82660d07be0e4a988fae02abc7b681d9153eb9bcb48fe7389, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x1adab0c8e2b3bad346699a2b5f3bc03643ee83ece47228f24a58e0a347e153d8, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x1672b1726057d99dd14709ebb474641a378c1b94b8072bac1a22dbef9e80dad2, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x1dfd53d4576af2e38f44f53fdcab468cc5d8e2fae0acc4ee30d47b239b479c14, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x0c6888a10b75b0f3a70a36263a37e17fe6d77d640f6fc3debc7f207753205c60, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x1addb933a65be77092b34a7e77d12fe8611a61e00ee6848b85091ecca9d1e508, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x00d7540dcd268a845c10ae18d1de933cf638ff5425f0afff7935628e299d1791, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x140c0e42687e9ead01b2827a5664ca9c26fedde4acd99db1d316939d20b82c0e, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x2f0c3a115d4317d191ba89b8d13d1806c20a0f9b24f8c5edc091e2ae56565984, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x0c4ee778ff7c14553006ed220cf9c81008a0cff670b22b82d8c538a1dc958c61, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod(0x1704f2766d46f82c3693f00440ccc3609424ed26c0acc66227c3d7485de74c69, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x2f2d19cc3ea5d78ea7a02c1b51d244abf0769c9f8544e40239b66fe9009c3cfa, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod(0x1ae03853b75fcaba5053f112e2a8e8dcdd7ee6cb9cfed9c7d6c766a806fc6629, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x0971aabf795241df51d131d0fa61aa5f3556921b2d6f014e4e41a86ddaf056d5, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := mulmod(state1, state1, F) + state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F) + scratch0 := addmod(0x1408c316e6014e1a91d4cf6b6e0de73eda624f8380df1c875f5c29f7bfe2f646, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x1667f3fe2edbe850248abe42b543093b6c89f1f773ef285341691f39822ef5bd, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := mulmod(scratch1, scratch1, F) + scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F) + state0 := addmod(0x13bf7c5d0d2c4376a48b0a03557cdf915b81718409e5c133424c69576500fe37, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), F) + state1 := addmod(0x07620a6dfb0b6cec3016adf3d3533c24024b95347856b79719bc0ba743a62c2c, addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), F) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := mulmod(state1, state1, F) + state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F) + scratch0 := addmod(0x1574c7ef0c43545f36a8ca08bdbdd8b075d2959e2f322b731675de3e1982b4d0, addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), F) + scratch1 := addmod(0x269e4b5b7a2eb21afd567970a717ceec5bd4184571c254fdc06e03a7ff8378f0, addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), F) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := mulmod(scratch1, scratch1, F) + scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F) + + mstore(0x0, addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F)) + + return(0, 0x20) } } } diff --git a/contracts/PoseidonT3.sol b/contracts/PoseidonT3.sol index 0bc9754..b3746c2 100644 --- a/contracts/PoseidonT3.sol +++ b/contracts/PoseidonT3.sol @@ -2,480 +2,1155 @@ pragma solidity >=0.7.0; library PoseidonT3 { - uint constant F = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - uint constant M00 = 0x109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b; uint constant M01 = 0x2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771; uint constant M02 = 0x143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7; uint constant M10 = 0x16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e0; uint constant M11 = 0x2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe23; uint constant M12 = 0x176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee2911; - uint constant M20 = 0x2b90bba00fca0589f617e7dcbfe82e0df706ab640ceb247b791a93b74e36736d; - uint constant M21 = 0x101071f0032379b697315876690f053d148d4e109f5fb065c8aacc55a0f89bfa; - uint constant M22 = 0x19a3fc0a56702bf417ba7fee3802593fa644470307043f7773279cd71d25d5e0; // See here for a simplified implementation: https://github.com/vimwitch/poseidon-solidity/blob/e57becdabb65d99fdc586fe1e1e09e7108202d53/contracts/Poseidon.sol#L40 // Based on: https://github.com/iden3/circomlibjs/blob/v0.0.8/src/poseidon_slow.js function hash(uint[2] memory) public pure returns (uint) { assembly { - // memory 0x00 to 0x3f (64 bytes) is scratch space for hash algos - // we can use it in inline assembly because we're not calling e.g. keccak - // - // memory 0x80 is the default offset for free memory - // we take inputs as a memory argument so we simply write over - // that memory after loading it - - // we have the following variables at memory offsets - // state0 - 0x00 - // state1 - 0x20 - // state2 - 0x80 - // state3 - 0xa0 - // state4 - ... - - function pRound(c0, c1, c2) { - let state0 := addmod(mload(0x0), c0, F) - let state1 := addmod(mload(0x20), c1, F) - let state2 := addmod(mload(0x80), c2, F) - - let p := mulmod(state0, state0, F) - state0 := mulmod(mulmod(p, p, F), state0, F) - - mstore(0x0, addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F)) - mstore(0x20, addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F)) - mstore(0x80, addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F)) - } - - function fRound(c0, c1, c2) { - let state0 := addmod(mload(0x0), c0, F) - let state1 := addmod(mload(0x20), c1, F) - let state2 := addmod(mload(0x80), c2, F) - - let p := mulmod(state0, state0, F) - state0 := mulmod(mulmod(p, p, F), state0, F) - p := mulmod(state1, state1, F) - state1 := mulmod(mulmod(p, p, F), state1, F) - p := mulmod(state2, state2, F) - state2 := mulmod(mulmod(p, p, F), state2, F) - - mstore(0x0, addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F)) - mstore(0x20, addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F)) - mstore(0x80, addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F)) - } - - // scratch variable for exponentiation - let p - - { - // load the inputs from memory - let state1 := addmod(mload(0x80), 0x00f1445235f2148c5986587169fc1bcd887b08d4d00868df5696fff40956e864, F) - let state2 := addmod(mload(0xa0), 0x08dff3487e8ac99e1f29a058d0fa80b930c728730b7ab36ce879f3890ecf73f5, F) - mstore(0x60, addmod(mload(0xc0), 0x2f27be690fdaee46c3ce28f7532b13c856c35342c84bda6e20966310fadc01d0, F)) - - p := mulmod(state1, state1, F) - state1 := mulmod(mulmod(p, p, F), state1, F) - p := mulmod(state2, state2, F) - state2 := mulmod(mulmod(p, p, F), state2, F) - - // state0 pow5mod and M[] multiplications are pre-calculated - - mstore(0x0, addmod(addmod(0x2229fe5e63f56eef4bfba02c26292de10ac2b2b045e6184acff16e4660c05f6b, mulmod(state1, M10, F), F), mulmod(state2, M20, F), F)) - mstore(0x20, addmod(addmod(0x2949435275a29cdbffe3e4101a45669873f9408a5d11e21b4ec6edf8501eee4d, mulmod(state1, M11, F), F), mulmod(state2, M21, F), F)) - mstore(0x80, addmod(addmod(0x20c290a7269657965092ef5700a447f5bc2c41dfca932f527cb2600ac9bcfefb, mulmod(state1, M12, F), F), mulmod(state2, M22, F), F)) - } - - fRound( + let F := 21888242871839275222246405745257275088548364400416034343698204186575808495617 + let M20 := 0x2b90bba00fca0589f617e7dcbfe82e0df706ab640ceb247b791a93b74e36736d + let M21 := 0x101071f0032379b697315876690f053d148d4e109f5fb065c8aacc55a0f89bfa + let M22 := 0x19a3fc0a56702bf417ba7fee3802593fa644470307043f7773279cd71d25d5e0 + // load the inputs from memory + let state0 + let scratch0 + let state1 + let scratch1 + let state2 + let scratch2 + + state1 := addmod(mload(0x80), 0x00f1445235f2148c5986587169fc1bcd887b08d4d00868df5696fff40956e864, F) + state2 := addmod(mload(0xa0), 0x08dff3487e8ac99e1f29a058d0fa80b930c728730b7ab36ce879f3890ecf73f5, F) + scratch0 := mulmod(state1, state1, F) + state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F) + scratch0 := mulmod(state2, state2, F) + state2 := mulmod(mulmod(scratch0, scratch0, F), state2, F) + scratch0 := addmod( 0x2f27be690fdaee46c3ce28f7532b13c856c35342c84bda6e20966310fadc01d0, + addmod(addmod(15452833169820924772166449970675545095234312153403844297388521437673434406763, mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x2b2ae1acf68b7b8d2416bebf3d4f6234b763fe04b8043ee48b8327bebca16cf2, - 0x0319d062072bef7ecca5eac06f97d4d55952c175ab6b03eae64b44c7dbf11cfa + addmod(addmod(18674271267752038776579386132900109523609358935013267566297499497165104279117, mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - fRound( + scratch2 := addmod( + 0x0319d062072bef7ecca5eac06f97d4d55952c175ab6b03eae64b44c7dbf11cfa, + addmod(addmod(14817777843080276494683266178512808687156649753153012854386334860566696099579, mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := mulmod(scratch1, scratch1, F) + scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F) + state0 := mulmod(scratch2, scratch2, F) + scratch2 := mulmod(mulmod(state0, state0, F), scratch2, F) + state0 := addmod( 0x28813dcaebaeaa828a376df87af4a63bc8b7bf27ad49c6298ef7b387bf28526d, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x2727673b2ccbc903f181bf38e1c1d40d2033865200c352bc150928adddf9cb78, - 0x234ec45ca27727c2e74abd2b2a1494cd6efbd43e340587d6b8fb9e31e65cc632 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - fRound( + state2 := addmod( + 0x234ec45ca27727c2e74abd2b2a1494cd6efbd43e340587d6b8fb9e31e65cc632, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := mulmod(state1, state1, F) + state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F) + scratch0 := mulmod(state2, state2, F) + state2 := mulmod(mulmod(scratch0, scratch0, F), state2, F) + scratch0 := addmod( 0x15b52534031ae18f7f862cb2cf7cf760ab10a8150a337b1ccd99ff6e8797d428, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x0dc8fad6d9e4b35f5ed9a3d186b79ce38e0e8a8d1b58b132d701d4eecf68d1f6, - 0x1bcd95ffc211fbca600f705fad3fb567ea4eb378f62e1fec97805518a47e4d9c + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x1bcd95ffc211fbca600f705fad3fb567ea4eb378f62e1fec97805518a47e4d9c, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := mulmod(scratch1, scratch1, F) + scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F) + state0 := mulmod(scratch2, scratch2, F) + scratch2 := mulmod(mulmod(state0, state0, F), scratch2, F) + state0 := addmod( 0x10520b0ab721cadfe9eff81b016fc34dc76da36c2578937817cb978d069de559, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x1f6d48149b8e7f7d9b257d8ed5fbbaf42932498075fed0ace88a9eb81f5627f6, - 0x1d9655f652309014d29e00ef35a2089bfff8dc1c816f0dc9ca34bdb5460c8705 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x1d9655f652309014d29e00ef35a2089bfff8dc1c816f0dc9ca34bdb5460c8705, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x04df5a56ff95bcafb051f7b1cd43a99ba731ff67e47032058fe3d4185697cc7d, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x0672d995f8fff640151b3d290cedaf148690a10a8c8424a7f6ec282b6e4be828, - 0x099952b414884454b21200d7ffafdd5f0c9a9dcc06f2708e9fc1d8209b5c75b9 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x099952b414884454b21200d7ffafdd5f0c9a9dcc06f2708e9fc1d8209b5c75b9, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x052cba2255dfd00c7c483143ba8d469448e43586a9b4cd9183fd0e843a6b9fa6, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x0b8badee690adb8eb0bd74712b7999af82de55707251ad7716077cb93c464ddc, - 0x119b1590f13307af5a1ee651020c07c749c15d60683a8050b963d0a8e4b2bdd1 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x119b1590f13307af5a1ee651020c07c749c15d60683a8050b963d0a8e4b2bdd1, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x03150b7cd6d5d17b2529d36be0f67b832c4acfc884ef4ee5ce15be0bfb4a8d09, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x2cc6182c5e14546e3cf1951f173912355374efb83d80898abe69cb317c9ea565, - 0x005032551e6378c450cfe129a404b3764218cadedac14e2b92d2cd73111bf0f9 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x005032551e6378c450cfe129a404b3764218cadedac14e2b92d2cd73111bf0f9, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x233237e3289baa34bb147e972ebcb9516469c399fcc069fb88f9da2cc28276b5, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x05c8f4f4ebd4a6e3c980d31674bfbe6323037f21b34ae5a4e80c2d4c24d60280, - 0x0a7b1db13042d396ba05d818a319f25252bcf35ef3aeed91ee1f09b2590fc65b + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x0a7b1db13042d396ba05d818a319f25252bcf35ef3aeed91ee1f09b2590fc65b, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x2a73b71f9b210cf5b14296572c9d32dbf156e2b086ff47dc5df542365a404ec0, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x1ac9b0417abcc9a1935107e9ffc91dc3ec18f2c4dbe7f22976a760bb5c50c460, - 0x12c0339ae08374823fabb076707ef479269f3e4d6cb104349015ee046dc93fc0 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x12c0339ae08374823fabb076707ef479269f3e4d6cb104349015ee046dc93fc0, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x0b7475b102a165ad7f5b18db4e1e704f52900aa3253baac68246682e56e9a28e, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x037c2849e191ca3edb1c5e49f6e8b8917c843e379366f2ea32ab3aa88d7f8448, - 0x05a6811f8556f014e92674661e217e9bd5206c5c93a07dc145fdb176a716346f + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x05a6811f8556f014e92674661e217e9bd5206c5c93a07dc145fdb176a716346f, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x29a795e7d98028946e947b75d54e9f044076e87a7b2883b47b675ef5f38bd66e, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x20439a0c84b322eb45a3857afc18f5826e8c7382c8a1585c507be199981fd22f, - 0x2e0ba8d94d9ecf4a94ec2050c7371ff1bb50f27799a84b6d4a2a6f2a0982c887 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x2e0ba8d94d9ecf4a94ec2050c7371ff1bb50f27799a84b6d4a2a6f2a0982c887, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x143fd115ce08fb27ca38eb7cce822b4517822cd2109048d2e6d0ddcca17d71c8, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x0c64cbecb1c734b857968dbbdcf813cdf8611659323dbcbfc84323623be9caf1, - 0x028a305847c683f646fca925c163ff5ae74f348d62c2b670f1426cef9403da53 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x028a305847c683f646fca925c163ff5ae74f348d62c2b670f1426cef9403da53, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x2e4ef510ff0b6fda5fa940ab4c4380f26a6bcb64d89427b824d6755b5db9e30c, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x0081c95bc43384e663d79270c956ce3b8925b4f6d033b078b96384f50579400e, - 0x2ed5f0c91cbd9749187e2fade687e05ee2491b349c039a0bba8a9f4023a0bb38 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x2ed5f0c91cbd9749187e2fade687e05ee2491b349c039a0bba8a9f4023a0bb38, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x30509991f88da3504bbf374ed5aae2f03448a22c76234c8c990f01f33a735206, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x1c3f20fd55409a53221b7c4d49a356b9f0a1119fb2067b41a7529094424ec6ad, - 0x10b4e7f3ab5df003049514459b6e18eec46bb2213e8e131e170887b47ddcb96c + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x10b4e7f3ab5df003049514459b6e18eec46bb2213e8e131e170887b47ddcb96c, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x2a1982979c3ff7f43ddd543d891c2abddd80f804c077d775039aa3502e43adef, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x1c74ee64f15e1db6feddbead56d6d55dba431ebc396c9af95cad0f1315bd5c91, - 0x07533ec850ba7f98eab9303cace01b4b9e4f2e8b82708cfa9c2fe45a0ae146a0 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x07533ec850ba7f98eab9303cace01b4b9e4f2e8b82708cfa9c2fe45a0ae146a0, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x21576b438e500449a151e4eeaf17b154285c68f42d42c1808a11abf3764c0750, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x2f17c0559b8fe79608ad5ca193d62f10bce8384c815f0906743d6930836d4a9e, - 0x2d477e3862d07708a79e8aae946170bc9775a4201318474ae665b0b1b7e2730e + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x2d477e3862d07708a79e8aae946170bc9775a4201318474ae665b0b1b7e2730e, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x162f5243967064c390e095577984f291afba2266c38f5abcd89be0f5b2747eab, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x2b4cb233ede9ba48264ecd2c8ae50d1ad7a8596a87f29f8a7777a70092393311, - 0x2c8fbcb2dd8573dc1dbaf8f4622854776db2eece6d85c4cf4254e7c35e03b07a + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x2c8fbcb2dd8573dc1dbaf8f4622854776db2eece6d85c4cf4254e7c35e03b07a, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x1d6f347725e4816af2ff453f0cd56b199e1b61e9f601e9ade5e88db870949da9, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x204b0c397f4ebe71ebc2d8b3df5b913df9e6ac02b68d31324cd49af5c4565529, - 0x0c4cb9dc3c4fd8174f1149b3c63c3c2f9ecb827cd7dc25534ff8fb75bc79c502 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x0c4cb9dc3c4fd8174f1149b3c63c3c2f9ecb827cd7dc25534ff8fb75bc79c502, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x174ad61a1448c899a25416474f4930301e5c49475279e0639a616ddc45bc7b54, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x1a96177bcf4d8d89f759df4ec2f3cde2eaaa28c177cc0fa13a9816d49a38d2ef, - 0x066d04b24331d71cd0ef8054bc60c4ff05202c126a233c1a8242ace360b8a30a + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x066d04b24331d71cd0ef8054bc60c4ff05202c126a233c1a8242ace360b8a30a, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x2a4c4fc6ec0b0cf52195782871c6dd3b381cc65f72e02ad527037a62aa1bd804, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x13ab2d136ccf37d447e9f2e14a7cedc95e727f8446f6d9d7e55afc01219fd649, - 0x1121552fca26061619d24d843dc82769c1b04fcec26f55194c2e3e869acc6a9a + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x1121552fca26061619d24d843dc82769c1b04fcec26f55194c2e3e869acc6a9a, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x00ef653322b13d6c889bc81715c37d77a6cd267d595c4a8909a5546c7c97cff1, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x0e25483e45a665208b261d8ba74051e6400c776d652595d9845aca35d8a397d3, - 0x29f536dcb9dd7682245264659e15d88e395ac3d4dde92d8c46448db979eeba89 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x29f536dcb9dd7682245264659e15d88e395ac3d4dde92d8c46448db979eeba89, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x2a56ef9f2c53febadfda33575dbdbd885a124e2780bbea170e456baace0fa5be, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x1c8361c78eb5cf5decfb7a2d17b5c409f2ae2999a46762e8ee416240a8cb9af1, - 0x151aff5f38b20a0fc0473089aaf0206b83e8e68a764507bfd3d0ab4be74319c5 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x151aff5f38b20a0fc0473089aaf0206b83e8e68a764507bfd3d0ab4be74319c5, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x04c6187e41ed881dc1b239c88f7f9d43a9f52fc8c8b6cdd1e76e47615b51f100, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x13b37bd80f4d27fb10d84331f6fb6d534b81c61ed15776449e801b7ddc9c2967, - 0x01a5c536273c2d9df578bfbd32c17b7a2ce3664c2a52032c9321ceb1c4e8a8e4 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x01a5c536273c2d9df578bfbd32c17b7a2ce3664c2a52032c9321ceb1c4e8a8e4, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x2ab3561834ca73835ad05f5d7acb950b4a9a2c666b9726da832239065b7c3b02, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x1d4d8ec291e720db200fe6d686c0d613acaf6af4e95d3bf69f7ed516a597b646, - 0x041294d2cc484d228f5784fe7919fd2bb925351240a04b711514c9c80b65af1d + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x041294d2cc484d228f5784fe7919fd2bb925351240a04b711514c9c80b65af1d, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x154ac98e01708c611c4fa715991f004898f57939d126e392042971dd90e81fc6, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x0b339d8acca7d4f83eedd84093aef51050b3684c88f8b0b04524563bc6ea4da4, - 0x0955e49e6610c94254a4f84cfbab344598f0e71eaff4a7dd81ed95b50839c82e + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x0955e49e6610c94254a4f84cfbab344598f0e71eaff4a7dd81ed95b50839c82e, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x06746a6156eba54426b9e22206f15abca9a6f41e6f535c6f3525401ea0654626, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x0f18f5a0ecd1423c496f3820c549c27838e5790e2bd0a196ac917c7ff32077fb, - 0x04f6eeca1751f7308ac59eff5beb261e4bb563583ede7bc92a738223d6f76e13 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x04f6eeca1751f7308ac59eff5beb261e4bb563583ede7bc92a738223d6f76e13, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x2b56973364c4c4f5c1a3ec4da3cdce038811eb116fb3e45bc1768d26fc0b3758, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x123769dd49d5b054dcd76b89804b1bcb8e1392b385716a5d83feb65d437f29ef, - 0x2147b424fc48c80a88ee52b91169aacea989f6446471150994257b2fb01c63e9 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x2147b424fc48c80a88ee52b91169aacea989f6446471150994257b2fb01c63e9, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x0fdc1f58548b85701a6c5505ea332a29647e6f34ad4243c2ea54ad897cebe54d, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x12373a8251fea004df68abcf0f7786d4bceff28c5dbbe0c3944f685cc0a0b1f2, - 0x21e4f4ea5f35f85bad7ea52ff742c9e8a642756b6af44203dd8a1f35c1a90035 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x21e4f4ea5f35f85bad7ea52ff742c9e8a642756b6af44203dd8a1f35c1a90035, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x16243916d69d2ca3dfb4722224d4c462b57366492f45e90d8a81934f1bc3b147, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x1efbe46dd7a578b4f66f9adbc88b4378abc21566e1a0453ca13a4159cac04ac2, - 0x07ea5e8537cf5dd08886020e23a7f387d468d5525be66f853b672cc96a88969a + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x07ea5e8537cf5dd08886020e23a7f387d468d5525be66f853b672cc96a88969a, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x05a8c4f9968b8aa3b7b478a30f9a5b63650f19a75e7ce11ca9fe16c0b76c00bc, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x20f057712cc21654fbfe59bd345e8dac3f7818c701b9c7882d9d57b72a32e83f, - 0x04a12ededa9dfd689672f8c67fee31636dcd8e88d01d49019bd90b33eb33db69 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x04a12ededa9dfd689672f8c67fee31636dcd8e88d01d49019bd90b33eb33db69, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x27e88d8c15f37dcee44f1e5425a51decbd136ce5091a6767e49ec9544ccd101a, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x2feed17b84285ed9b8a5c8c5e95a41f66e096619a7703223176c41ee433de4d1, - 0x1ed7cc76edf45c7c404241420f729cf394e5942911312a0d6972b8bd53aff2b8 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x1ed7cc76edf45c7c404241420f729cf394e5942911312a0d6972b8bd53aff2b8, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x15742e99b9bfa323157ff8c586f5660eac6783476144cdcadf2874be45466b1a, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x1aac285387f65e82c895fc6887ddf40577107454c6ec0317284f033f27d0c785, - 0x25851c3c845d4790f9ddadbdb6057357832e2e7a49775f71ec75a96554d67c77 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x25851c3c845d4790f9ddadbdb6057357832e2e7a49775f71ec75a96554d67c77, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x15a5821565cc2ec2ce78457db197edf353b7ebba2c5523370ddccc3d9f146a67, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x2411d57a4813b9980efa7e31a1db5966dcf64f36044277502f15485f28c71727, - 0x002e6f8d6520cd4713e335b8c0b6d2e647e9a98e12f4cd2558828b5ef6cb4c9b + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x002e6f8d6520cd4713e335b8c0b6d2e647e9a98e12f4cd2558828b5ef6cb4c9b, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x2ff7bc8f4380cde997da00b616b0fcd1af8f0e91e2fe1ed7398834609e0315d2, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x00b9831b948525595ee02724471bcd182e9521f6b7bb68f1e93be4febb0d3cbe, - 0x0a2f53768b8ebf6a86913b0e57c04e011ca408648a4743a87d77adbf0c9c3512 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x0a2f53768b8ebf6a86913b0e57c04e011ca408648a4743a87d77adbf0c9c3512, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x00248156142fd0373a479f91ff239e960f599ff7e94be69b7f2a290305e1198d, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x171d5620b87bfb1328cf8c02ab3f0c9a397196aa6a542c2350eb512a2b2bcda9, - 0x170a4f55536f7dc970087c7c10d6fad760c952172dd54dd99d1045e4ec34a808 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x170a4f55536f7dc970087c7c10d6fad760c952172dd54dd99d1045e4ec34a808, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x29aba33f799fe66c2ef3134aea04336ecc37e38c1cd211ba482eca17e2dbfae1, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x1e9bc179a4fdd758fdd1bb1945088d47e70d114a03f6a0e8b5ba650369e64973, - 0x1dd269799b660fad58f7f4892dfb0b5afeaad869a9c4b44f9c9e1c43bdaf8f09 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x1dd269799b660fad58f7f4892dfb0b5afeaad869a9c4b44f9c9e1c43bdaf8f09, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x22cdbc8b70117ad1401181d02e15459e7ccd426fe869c7c95d1dd2cb0f24af38, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x0ef042e454771c533a9f57a55c503fcefd3150f52ed94a7cd5ba93b9c7dacefd, - 0x11609e06ad6c8fe2f287f3036037e8851318e8b08a0359a03b304ffca62e8284 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x11609e06ad6c8fe2f287f3036037e8851318e8b08a0359a03b304ffca62e8284, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x1166d9e554616dba9e753eea427c17b7fecd58c076dfe42708b08f5b783aa9af, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x2de52989431a859593413026354413db177fbf4cd2ac0b56f855a888357ee466, - 0x3006eb4ffc7a85819a6da492f3a8ac1df51aee5b17b8e89d74bf01cf5f71e9ad + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x3006eb4ffc7a85819a6da492f3a8ac1df51aee5b17b8e89d74bf01cf5f71e9ad, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x2af41fbb61ba8a80fdcf6fff9e3f6f422993fe8f0a4639f962344c8225145086, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x119e684de476155fe5a6b41a8ebc85db8718ab27889e85e781b214bace4827c3, - 0x1835b786e2e8925e188bea59ae363537b51248c23828f047cff784b97b3fd800 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x1835b786e2e8925e188bea59ae363537b51248c23828f047cff784b97b3fd800, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x28201a34c594dfa34d794996c6433a20d152bac2a7905c926c40e285ab32eeb6, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x083efd7a27d1751094e80fefaf78b000864c82eb571187724a761f88c22cc4e7, - 0x0b6f88a3577199526158e61ceea27be811c16df7774dd8519e079564f61fd13b + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x0b6f88a3577199526158e61ceea27be811c16df7774dd8519e079564f61fd13b, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x0ec868e6d15e51d9644f66e1d6471a94589511ca00d29e1014390e6ee4254f5b, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x2af33e3f866771271ac0c9b3ed2e1142ecd3e74b939cd40d00d937ab84c98591, - 0x0b520211f904b5e7d09b5d961c6ace7734568c547dd6858b364ce5e47951f178 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x0b520211f904b5e7d09b5d961c6ace7734568c547dd6858b364ce5e47951f178, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x0b2d722d0919a1aad8db58f10062a92ea0c56ac4270e822cca228620188a1d40, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x1f790d4d7f8cf094d980ceb37c2453e957b54a9991ca38bbe0061d1ed6e562d4, - 0x0171eb95dfbf7d1eaea97cd385f780150885c16235a2a6a8da92ceb01e504233 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x0171eb95dfbf7d1eaea97cd385f780150885c16235a2a6a8da92ceb01e504233, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x0c2d0e3b5fd57549329bf6885da66b9b790b40defd2c8650762305381b168873, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x1162fb28689c27154e5a8228b4e72b377cbcafa589e283c35d3803054407a18d, - 0x2f1459b65dee441b64ad386a91e8310f282c5a92a89e19921623ef8249711bc0 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x2f1459b65dee441b64ad386a91e8310f282c5a92a89e19921623ef8249711bc0, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x1e6ff3216b688c3d996d74367d5cd4c1bc489d46754eb712c243f70d1b53cfbb, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x01ca8be73832b8d0681487d27d157802d741a6f36cdc2a0576881f9326478875, - 0x1f7735706ffe9fc586f976d5bdf223dc680286080b10cea00b9b5de315f9650e + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x1f7735706ffe9fc586f976d5bdf223dc680286080b10cea00b9b5de315f9650e, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x2522b60f4ea3307640a0c2dce041fba921ac10a3d5f096ef4745ca838285f019, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x23f0bee001b1029d5255075ddc957f833418cad4f52b6c3f8ce16c235572575b, - 0x2bc1ae8b8ddbb81fcaac2d44555ed5685d142633e9df905f66d9401093082d59 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x2bc1ae8b8ddbb81fcaac2d44555ed5685d142633e9df905f66d9401093082d59, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x0f9406b8296564a37304507b8dba3ed162371273a07b1fc98011fcd6ad72205f, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x2360a8eb0cc7defa67b72998de90714e17e75b174a52ee4acb126c8cd995f0a8, - 0x15871a5cddead976804c803cbaef255eb4815a5e96df8b006dcbbc2767f88948 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x15871a5cddead976804c803cbaef255eb4815a5e96df8b006dcbbc2767f88948, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x193a56766998ee9e0a8652dd2f3b1da0362f4f54f72379544f957ccdeefb420f, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x2a394a43934f86982f9be56ff4fab1703b2e63c8ad334834e4309805e777ae0f, - 0x1859954cfeb8695f3e8b635dcb345192892cd11223443ba7b4166e8876c0d142 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x1859954cfeb8695f3e8b635dcb345192892cd11223443ba7b4166e8876c0d142, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x04e1181763050e58013444dbcb99f1902b11bc25d90bbdca408d3819f4fed32b, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x0fdb253dee83869d40c335ea64de8c5bb10eb82db08b5e8b1f5e5552bfd05f23, - 0x058cbe8a9a5027bdaa4efb623adead6275f08686f1c08984a9d7c5bae9b4f1c0 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x058cbe8a9a5027bdaa4efb623adead6275f08686f1c08984a9d7c5bae9b4f1c0, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x1382edce9971e186497eadb1aeb1f52b23b4b83bef023ab0d15228b4cceca59a, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x03464990f045c6ee0819ca51fd11b0be7f61b8eb99f14b77e1e6634601d9e8b5, - 0x23f7bfc8720dc296fff33b41f98ff83c6fcab4605db2eb5aaa5bc137aeb70a58 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x23f7bfc8720dc296fff33b41f98ff83c6fcab4605db2eb5aaa5bc137aeb70a58, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x0a59a158e3eec2117e6e94e7f0e9decf18c3ffd5e1531a9219636158bbaf62f2, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x06ec54c80381c052b58bf23b312ffd3ce2c4eba065420af8f4c23ed0075fd07b, - 0x118872dc832e0eb5476b56648e867ec8b09340f7a7bcb1b4962f0ff9ed1f9d01 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x118872dc832e0eb5476b56648e867ec8b09340f7a7bcb1b4962f0ff9ed1f9d01, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x13d69fa127d834165ad5c7cba7ad59ed52e0b0f0e42d7fea95e1906b520921b1, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x169a177f63ea681270b1c6877a73d21bde143942fb71dc55fd8a49f19f10c77b, - 0x04ef51591c6ead97ef42f287adce40d93abeb032b922f66ffb7e9a5a7450544d + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x04ef51591c6ead97ef42f287adce40d93abeb032b922f66ffb7e9a5a7450544d, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x256e175a1dc079390ecd7ca703fb2e3b19ec61805d4f03ced5f45ee6dd0f69ec, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x30102d28636abd5fe5f2af412ff6004f75cc360d3205dd2da002813d3e2ceeb2, - 0x10998e42dfcd3bbf1c0714bc73eb1bf40443a3fa99bef4a31fd31be182fcc792 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x10998e42dfcd3bbf1c0714bc73eb1bf40443a3fa99bef4a31fd31be182fcc792, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x193edd8e9fcf3d7625fa7d24b598a1d89f3362eaf4d582efecad76f879e36860, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x18168afd34f2d915d0368ce80b7b3347d1c7a561ce611425f2664d7aa51f0b5d, - 0x29383c01ebd3b6ab0c017656ebe658b6a328ec77bc33626e29e2e95b33ea6111 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x29383c01ebd3b6ab0c017656ebe658b6a328ec77bc33626e29e2e95b33ea6111, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x10646d2f2603de39a1f4ae5e7771a64a702db6e86fb76ab600bf573f9010c711, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x0beb5e07d1b27145f575f1395a55bf132f90c25b40da7b3864d0242dcb1117fb, - 0x16d685252078c133dc0d3ecad62b5c8830f95bb2e54b59abdffbf018d96fa336 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x16d685252078c133dc0d3ecad62b5c8830f95bb2e54b59abdffbf018d96fa336, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x0a6abd1d833938f33c74154e0404b4b40a555bbbec21ddfafd672dd62047f01a, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x1a679f5d36eb7b5c8ea12a4c2dedc8feb12dffeec450317270a6f19b34cf1860, - 0x0980fb233bd456c23974d50e0ebfde4726a423eada4e8f6ffbc7592e3f1b93d6 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x0980fb233bd456c23974d50e0ebfde4726a423eada4e8f6ffbc7592e3f1b93d6, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x161b42232e61b84cbf1810af93a38fc0cece3d5628c9282003ebacb5c312c72b, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x0ada10a90c7f0520950f7d47a60d5e6a493f09787f1564e5d09203db47de1a0b, - 0x1a730d372310ba82320345a29ac4238ed3f07a8a2b4e121bb50ddb9af407f451 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x1a730d372310ba82320345a29ac4238ed3f07a8a2b4e121bb50ddb9af407f451, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x2c8120f268ef054f817064c369dda7ea908377feaba5c4dffbda10ef58e8c556, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x1c7c8824f758753fa57c00789c684217b930e95313bcb73e6e7b8649a4968f70, - 0x2cd9ed31f5f8691c8e39e4077a74faa0f400ad8b491eb3f7b47b27fa3fd1cf77 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x2cd9ed31f5f8691c8e39e4077a74faa0f400ad8b491eb3f7b47b27fa3fd1cf77, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x23ff4f9d46813457cf60d92f57618399a5e022ac321ca550854ae23918a22eea, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x09945a5d147a4f66ceece6405dddd9d0af5a2c5103529407dff1ea58f180426d, - 0x188d9c528025d4c2b67660c6b771b90f7c7da6eaa29d3f268a6dd223ec6fc630 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - pRound( + state2 := addmod( + 0x188d9c528025d4c2b67660c6b771b90f7c7da6eaa29d3f268a6dd223ec6fc630, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x3050e37996596b7f81f68311431d8734dba7d926d3633595e0c0d8ddf4f0f47f, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x15af1169396830a91600ca8102c35c426ceae5461e3f95d89d829518d30afd78, - 0x1da6d09885432ea9a06d9f37f873d985dae933e351466b2904284da3320d8acc + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - pRound( + scratch2 := addmod( + 0x1da6d09885432ea9a06d9f37f873d985dae933e351466b2904284da3320d8acc, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := addmod( 0x2796ea90d269af29f5f8acf33921124e4e4fad3dbe658945e546ee411ddaa9cb, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x202d7dd1da0f6b4b0325c8b3307742f01e15612ec8e9304a7cb0319e01d32d60, - 0x096d6790d05bb759156a952ba263d672a2d7f9c788f4c831a29dace4c0f8be5f + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - fRound( + state2 := addmod( + 0x096d6790d05bb759156a952ba263d672a2d7f9c788f4c831a29dace4c0f8be5f, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := addmod( 0x054efa1f65b0fce283808965275d877b438da23ce5b13e1963798cb1447d25a4, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x1b162f83d917e93edb3308c29802deb9d8aa690113b2e14864ccf6e18e4165f1, - 0x21e5241e12564dd6fd9f1cdd2a0de39eedfefc1466cc568ec5ceb745a0506edc + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) - - fRound( + scratch2 := addmod( + 0x21e5241e12564dd6fd9f1cdd2a0de39eedfefc1466cc568ec5ceb745a0506edc, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := mulmod(scratch1, scratch1, F) + scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F) + state0 := mulmod(scratch2, scratch2, F) + scratch2 := mulmod(mulmod(state0, state0, F), scratch2, F) + state0 := addmod( 0x1cfb5662e8cf5ac9226a80ee17b36abecb73ab5f87e161927b4349e10e4bdf08, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( 0x0f21177e302a771bbae6d8d1ecb373b62c99af346220ac0129c53f666eb24100, - 0x1671522374606992affb0dd7f71b12bec4236aede6290546bcef7e1f515c2320 + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F ) - - fRound( + state2 := addmod( + 0x1671522374606992affb0dd7f71b12bec4236aede6290546bcef7e1f515c2320, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := mulmod(state1, state1, F) + state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F) + scratch0 := mulmod(state2, state2, F) + state2 := mulmod(mulmod(scratch0, scratch0, F), state2, F) + scratch0 := addmod( 0x0fa3ec5b9488259c2eb4cf24501bfad9be2ec9e42c5cc8ccd419d2a692cad870, + addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F), + F + ) + scratch1 := addmod( 0x193c0e04e0bd298357cb266c1506080ed36edce85c648cc085e8c57b1ab54bba, - 0x102adf8ef74735a27e9128306dcbc3c99f6f7291cd406578ce14ea2adaba68f8 + addmod(addmod(mulmod(state0, M01, F), mulmod(state1, M11, F), F), mulmod(state2, M21, F), F), + F ) + scratch2 := addmod( + 0x102adf8ef74735a27e9128306dcbc3c99f6f7291cd406578ce14ea2adaba68f8, + addmod(addmod(mulmod(state0, M02, F), mulmod(state1, M12, F), F), mulmod(state2, M22, F), F), + F + ) + state0 := mulmod(scratch0, scratch0, F) + scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F) + state0 := mulmod(scratch1, scratch1, F) + scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F) + state0 := mulmod(scratch2, scratch2, F) + scratch2 := mulmod(mulmod(state0, state0, F), scratch2, F) + state0 := addmod( + 0x0fe0af7858e49859e2a54d6f1ad945b1316aa24bfbdd23ae40a6d0cb70c3eab1, + addmod(addmod(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F), F), mulmod(scratch2, M20, F), F), + F + ) + state1 := addmod( + 0x216f6717bbc7dedb08536a2220843f4e2da5f1daa9ebdefde8a5ea7344798d22, + addmod(addmod(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F), F), mulmod(scratch2, M21, F), F), + F + ) + state2 := addmod( + 0x1da55cc900f0d21f4a3e694391918a1b3c23b2ac773c6b3ef88e2e4228325161, + addmod(addmod(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F), F), mulmod(scratch2, M22, F), F), + F + ) + scratch0 := mulmod(state0, state0, F) + state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F) + scratch0 := mulmod(state1, state1, F) + state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F) + scratch0 := mulmod(state2, state2, F) + state2 := mulmod(mulmod(scratch0, scratch0, F), state2, F) - { - let state0 := addmod(mload(0x0), 0x0fe0af7858e49859e2a54d6f1ad945b1316aa24bfbdd23ae40a6d0cb70c3eab1, F) - let state1 := addmod(mload(0x20), 0x216f6717bbc7dedb08536a2220843f4e2da5f1daa9ebdefde8a5ea7344798d22, F) - let state2 := addmod(mload(0x80), 0x1da55cc900f0d21f4a3e694391918a1b3c23b2ac773c6b3ef88e2e4228325161, F) - - p := mulmod(state0, state0, F) - state0 := mulmod(mulmod(p, p, F), state0, F) - p := mulmod(state1, state1, F) - state1 := mulmod(mulmod(p, p, F), state1, F) - p := mulmod(state2, state2, F) - state2 := mulmod(mulmod(p, p, F), state2, F) + mstore(0x0, addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F)) - mstore(0x0, addmod(addmod(mulmod(state0, M00, F), mulmod(state1, M10, F), F), mulmod(state2, M20, F), F)) - return(0, 0x20) - } + return(0, 0x20) } } } diff --git a/src/T.js b/src/T.js deleted file mode 100644 index 6fb9abb..0000000 --- a/src/T.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = [2, 3, 4, 5, 6] diff --git a/src/T.mjs b/src/T.mjs new file mode 100644 index 0000000..f496633 --- /dev/null +++ b/src/T.mjs @@ -0,0 +1,28 @@ +import { genTContract } from './buildPoseidon.mjs' +import { genTContractSimple } from './buildPoseidonSimple.mjs' + +export default [ + { + T: 2, + build: () => + genTContractSimple(2, { + mStackCount: 0, + }), + }, + { + T: 3, + build: () => genTContractSimple(3), + }, + { + T: 4, + build: () => genTContract(4), + }, + { + T: 5, + build: () => genTContract(5), + }, + { + T: 6, + build: () => genTContract(6), + }, +] diff --git a/src/build.mjs b/src/build.mjs index 22bde11..44a219a 100644 --- a/src/build.mjs +++ b/src/build.mjs @@ -1,16 +1,15 @@ -import { genTContract } from './buildPoseidon.mjs' import prettier from 'prettier' import fs from 'fs/promises' import path from 'path' import url from 'url' -import T from './T.js' +import T from './T.mjs' const __dirname = path.dirname(url.fileURLToPath(import.meta.url)) for (const t of T) { - let c = genTContract(t) + let c = t.build() try { - c = prettier.format(genTContract(t), { + c = prettier.format(t.build(), { parser: 'solidity-parse', printWidth: 180, tabWidth: 2, @@ -19,5 +18,8 @@ for (const t of T) { bracketSpacing: false, }) } catch (_) {} - await fs.writeFile(path.join(__dirname, `../contracts/PoseidonT${t}.sol`), c) + await fs.writeFile( + path.join(__dirname, `../contracts/PoseidonT${t.T}.sol`), + c + ) } diff --git a/src/buildPoseidonSimple.mjs b/src/buildPoseidonSimple.mjs new file mode 100644 index 0000000..e0306b2 --- /dev/null +++ b/src/buildPoseidonSimple.mjs @@ -0,0 +1,150 @@ +import fs from 'fs/promises' +import path from 'path' +import url from 'url' + +const __dirname = path.dirname(url.fileURLToPath(import.meta.url)) + +const constantPath = path.join(__dirname, 'poseidon_constants.json') +const constants = JSON.parse((await fs.readFile(constantPath)).toString()) + +// generate the function + +const ROUNDS_F = 8 +const _ROUNDS_P = [ + 56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68, +] +const F = + '21888242871839275222246405745257275088548364400416034343698204186575808495617' + +const MAX_ARGS = 5 + +const toHex = (n) => '0x' + BigInt(n).toString(16) + +const mul = (v1, v2) => `mulmod(${v1}, ${v2}, F)` +const add = (v1, v2) => `addmod(${v1}, ${v2}, F)` + +const mix = (T, state, x, _M) => { + const muls = Array(T) + .fill() + .map((_, i) => { + if (i === 0 && _M) return _M + return mul(`${state}${i}`, `M${i}${x}`) + }) + let _add = add(muls.shift(), muls.shift()) + for (let y = 0; y < muls.length; y++) { + _add = add(_add, muls[y]) + } + return _add +} + +export function genTContractSimple(T, options = {}) { + //***** + // build settings + //***** + // whether to assign mix output to an intermediate var + // increases stack depth if enabled + const compressMixAdd = options.compressMixAdd ?? true + // how many m constants to put on the stack + // affects contract size + const mStackCount = options.mStackCount ?? 3 + // Premultiply/exponentiate the first round state 0 variable + const premultiplyState0 = options.premultiplState0 ?? true + //***** + + const C = constants.C[T - 2] + const M = constants.M[T - 2] + const ROUNDS_P = _ROUNDS_P[T - 2] + + let f = `/// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0; + +library PoseidonT${T} { + +` + + for (let x = 0; x < T * T - mStackCount; x++) { + const y = Math.floor(x / T) + const z = x % T + f += `uint constant M${y}${z} = ${M[z][y]};\n` + } + + f += ` + +// See here for a simplified implementation: https://github.com/vimwitch/poseidon-solidity/blob/e57becdabb65d99fdc586fe1e1e09e7108202d53/contracts/Poseidon.sol#L40 +// Based on: https://github.com/iden3/circomlibjs/blob/v0.0.8/src/poseidon_slow.js +function hash(uint[${T - 1}] memory) public pure returns (uint) { +assembly { + + let F := ${F} +` + for (let x = T * T - mStackCount; x < T * T; x++) { + const y = Math.floor(x / T) + const z = x % T + f += `let M${y}${z} := ${M[z][y]}\n` + } + let r = 0 + + // pre-calculate the first state0 pow5mod + // and the first mix values + + const state0 = BigInt(C[0]) ** BigInt(5) % BigInt(F) + + const SM = [] + for (let x = 0; x < T; x++) { + SM[x] = (state0 * BigInt(M[x][0])) % BigInt(F) + } + + f += '// load the inputs from memory\n' + + for (let x = 0; x < T; x++) { + f += `let state${x}\n` + f += `let scratch${x}\n` + } + + f += '\n' + + for (; r < ROUNDS_F + ROUNDS_P; r++) { + const isFRound = r < ROUNDS_F / 2 || r >= ROUNDS_P + ROUNDS_F / 2 + const state = r % 2 === 0 ? 'state' : 'scratch' + const scratch = r % 2 === 0 ? 'scratch' : 'state' + if (r === 0 || !compressMixAdd) { + for (let y = 0; y < T; y++) { + if (r === 0 && y === 0 && premultiplyState0) continue + if (r === 0 && y > 0) { + const mem = toHex(128 + 32 * (y - 1)) + f += `${state}${y} := addmod(mload(${mem}), ${C[r * T + y]}, F)\n` + } else { + f += `${state}${y} := addmod(${state}${y}, ${C[r * T + y]}, F)\n` + } + } + } + for (let y = 0; y < (isFRound ? T : 1); y++) { + if (r === 0 && y === 0 && premultiplyState0) continue + f += `${scratch}0 := mulmod(${state}${y}, ${state}${y}, F)\n` + f += `${state}${y} := mulmod(mulmod(${scratch}0, ${scratch}0, F), ${state}${y}, F)\n` + } + for (let y = 0; y < T; y++) { + if (y > 0 && r === ROUNDS_F + ROUNDS_P - 1) break + const m = mix(T, state, y, r === 0 && premultiplyState0 ? SM[y] : null) + if (r < ROUNDS_F + ROUNDS_P - 1 && compressMixAdd) { + f += `${scratch}${y} := ${add(C[(r + 1) * T + y], m)}\n` + } else if (compressMixAdd) { + f += '\n' + f += `mstore(0x0, ${m})\n` + } else { + f += `${scratch}${y} := ${m}\n` + } + } + } + + if (!compressMixAdd) { + f += `mstore(0x0, ${r % 2 === 0 ? 'state0' : 'scratch0'})\n` + } + f += ` + return (0, 0x20) +} +} +} + ` + return f +} diff --git a/test/poseidon.test.js b/test/poseidon.test.js index ae3161d..19da1a6 100644 --- a/test/poseidon.test.js +++ b/test/poseidon.test.js @@ -2,7 +2,8 @@ const { ethers } = require('hardhat') const { poseidon_slow, poseidon_gencontract } = require('circomlibjs') const poseidon = require('poseidon-lite') const assert = require('assert') -const T = require('../src/T') + +const T = [2, 3, 4, 5, 6] const F_MAX = BigInt(