From c5b746665ca321d84513a19c8756d05a3583c719 Mon Sep 17 00:00:00 2001 From: thomaslavaur Date: Mon, 17 Nov 2025 10:38:39 +0100 Subject: [PATCH 1/4] modify hash to use compression() instead of poseidon2_hash(2) --- .../Blend/generate_inputs_for_poq.py | 16 +- circom_circuits/Blend/poq.circom | 4 +- .../Mantle/generate_inputs_for_pol.py | 16 +- .../generate_inputs_for_proof_of_claim.py | 8 +- .../Mantle/generate_inputs_for_signature.py | 197 ------------------ circom_circuits/Mantle/poc.circom | 6 +- circom_circuits/Mantle/pol.circom | 1 + circom_circuits/hash_bn/merkle.circom | 6 +- circom_circuits/hash_bn/poseidon2_perm.circom | 3 +- circom_circuits/ledger/notes.circom | 3 +- 10 files changed, 32 insertions(+), 228 deletions(-) diff --git a/circom_circuits/Blend/generate_inputs_for_poq.py b/circom_circuits/Blend/generate_inputs_for_poq.py index 714e152..3761771 100644 --- a/circom_circuits/Blend/generate_inputs_for_poq.py +++ b/circom_circuits/Blend/generate_inputs_for_poq.py @@ -155,7 +155,7 @@ def Permutation(inp): return state def Compression(inp): - return Permutation([inp[0],inp[1],F(0)]) + return Permutation([inp[0],inp[1],F(0)])[0] def PoseidonSponge(data, capacity, output_len): rate = 3 - capacity; @@ -221,16 +221,16 @@ if not core_or_leader in [0,1]: # 1) Core‐node registry Merkle‐proof # pick a random core_sk and derive its public key core_sk = F(randrange(0,p,1)) -pk_core = poseidon2_hash([ F(1296193216988918402894), core_sk ]) +pk_core = Compression([ F(1296193216988918402894), core_sk ]) core_selectors = randrange(0,2**20,1) core_selectors = format(int(core_selectors),'020b') core_nodes = [F(randrange(0,p,1)) for i in range(20)] core_root = pk_core for i in range(20): if int(core_selectors[19-i]) == 0: - core_root = poseidon2_hash([core_root,core_nodes[i]]) + core_root = Compression([core_root,core_nodes[i]]) else: - core_root = poseidon2_hash([core_nodes[i],core_root]) + core_root = Compression([core_nodes[i],core_root]) #pk_root, core_path, core_selectors = merkle_root_and_path(pk_core, 20) @@ -262,9 +262,9 @@ for i in range(25): if int(slot_secret_indexes[24-i]) == 0: secret_root = poseidon2_hash([secret_root,slot_secret_path[i]]) else: - secret_root = poseidon2_hash([slot_secret_path[i],secret_root]) + secret_root = Compression([slot_secret_path[i],secret_root]) sk = poseidon2_hash([F(256174383281726064679014503048630094),starting_slot,secret_root]) -pk = poseidon2_hash([F(1296193216988918402894),sk]) +pk = Compression([F(1296193216988918402894),sk]) note_id = poseidon2_hash([F(65580641562429851895355409762135920462),tx_hash,output_number,value,pk]) ticket = poseidon2_hash([F(13887241025832268),F(epoch_nonce),F(slot_number),note_id,sk]) @@ -279,9 +279,9 @@ aged_selectors = format(aged_selectors,'032b') aged_root = note_id for i in range(32): if int(aged_selectors[31-i]) == 0: - aged_root = poseidon2_hash([aged_root,aged_nodes[i]]) + aged_root = Compression([aged_root,aged_nodes[i]]) else: - aged_root = poseidon2_hash([aged_nodes[i],aged_root]) + aged_root = Compression([aged_nodes[i],aged_root]) # 3) Choose branch & index index = randrange(0, Ql if core_or_leader else Qc,1) diff --git a/circom_circuits/Blend/poq.circom b/circom_circuits/Blend/poq.circom index 86c82c0..20ee738 100644 --- a/circom_circuits/Blend/poq.circom +++ b/circom_circuits/Blend/poq.circom @@ -1,7 +1,7 @@ // PoQ.circom pragma circom 2.1.9; -include "../hash_bn/poseidon2_hash.circom"; +include "../hash_bn/poseidon2_perm.circom"; include "../misc/constants.circom"; // defines NOMOS_KDF, SELECTION_RANDOMNESS, PROOF_NULLIFIER include "../misc/comparator.circom"; include "../circomlib/circuits/bitify.circom"; @@ -125,7 +125,7 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) { // Derive key_nullifier - component nf = Poseidon2_hash(2); + component nf = Compression(); component dstNF = KEY_NULLIFIER_V1(); nf.inp[0] <== dstNF.out; nf.inp[1] <== selection_randomness.out; diff --git a/circom_circuits/Mantle/generate_inputs_for_pol.py b/circom_circuits/Mantle/generate_inputs_for_pol.py index 101fdeb..db65f56 100755 --- a/circom_circuits/Mantle/generate_inputs_for_pol.py +++ b/circom_circuits/Mantle/generate_inputs_for_pol.py @@ -155,7 +155,7 @@ def Permutation(inp): return state def Compression(inp): - return Permutation([inp[0],inp[1],F(0)]) + return Permutation([inp[0],inp[1],F(0)])[0] def PoseidonSponge(data, capacity, output_len): rate = 3 - capacity; @@ -241,11 +241,11 @@ slot_secret_path = [F(randrange(0,p,1)) for i in range(25)] secret_root = slot_secret for i in range(25): if int(slot_secret_indexes[24-i]) == 0: - secret_root = poseidon2_hash([secret_root,slot_secret_path[i]]) + secret_root = Compression([secret_root,slot_secret_path[i]]) else: - secret_root = poseidon2_hash([slot_secret_path[i],secret_root]) + secret_root = Compression([slot_secret_path[i],secret_root]) sk = poseidon2_hash([F(256174383281726064679014503048630094),starting_slot,secret_root]) -pk = poseidon2_hash([F(1296193216988918402894),sk]) +pk = Compression([F(1296193216988918402894),sk]) note_id = poseidon2_hash([F(65580641562429851895355409762135920462),tx_hash,output_number,value,pk]) ticket = poseidon2_hash([F(13887241025832268),F(epoch_nonce),F(slot_number),note_id,sk]) @@ -260,9 +260,9 @@ aged_selectors = format(aged_selectors,'032b') aged_root = note_id for i in range(32): if int(aged_selectors[31-i]) == 0: - aged_root = poseidon2_hash([aged_root,aged_nodes[i]]) + aged_root = Compression([aged_root,aged_nodes[i]]) else: - aged_root = poseidon2_hash([aged_nodes[i],aged_root]) + aged_root = Compression([aged_nodes[i],aged_root]) unspent_nodes = [F(randrange(0,p,1)) for i in range(32)] unspent_selectors = randrange(0,2**32,1) @@ -271,9 +271,9 @@ unspent_selectors = format(unspent_selectors,'032b') latest_root = note_id for i in range(32): if int(unspent_selectors[31-i]) == 0: - latest_root = poseidon2_hash([latest_root,unspent_nodes[i]]) + latest_root = Compression([latest_root,unspent_nodes[i]]) else: - latest_root = poseidon2_hash([unspent_nodes[i],latest_root]) + latest_root = Compression([unspent_nodes[i],latest_root]) diff --git a/circom_circuits/Mantle/generate_inputs_for_proof_of_claim.py b/circom_circuits/Mantle/generate_inputs_for_proof_of_claim.py index 2b8d9a2..d607373 100755 --- a/circom_circuits/Mantle/generate_inputs_for_proof_of_claim.py +++ b/circom_circuits/Mantle/generate_inputs_for_proof_of_claim.py @@ -156,7 +156,7 @@ def Permutation(inp): return state def Compression(inp): - return Permutation([inp[0],inp[1],F(0)]) + return Permutation([inp[0],inp[1],F(0)])[0] def PoseidonSponge(data, capacity, output_len): rate = 3 - capacity; @@ -208,7 +208,7 @@ def PoseidonSponge(data, capacity, output_len): secret_voucher = F(randrange(0,p,1)) -reward_voucher = poseidon2_hash([F(1668646695034522932676805048878418),secret_voucher]) +reward_voucher = Compression([F(1668646695034522932676805048878418),secret_voucher]) merkle_nodes = [F(randrange(0,p,1)) for i in range(32)] selectors = randrange(0,2**32,1) @@ -216,9 +216,9 @@ selectors = format(selectors,'032b') voucher_root = reward_voucher for i in range(32): if int(selectors[31-i]) == 0: - voucher_root = poseidon2_hash([voucher_root,merkle_nodes[i]]) + voucher_root = Compression([voucher_root,merkle_nodes[i]]) else: - voucher_root = poseidon2_hash([merkle_nodes[i],voucher_root]) + voucher_root = Compression([merkle_nodes[i],voucher_root]) data_msg = F(randrange(0,p,1)) diff --git a/circom_circuits/Mantle/generate_inputs_for_signature.py b/circom_circuits/Mantle/generate_inputs_for_signature.py index b8e66d2..fdd35d2 100755 --- a/circom_circuits/Mantle/generate_inputs_for_signature.py +++ b/circom_circuits/Mantle/generate_inputs_for_signature.py @@ -7,203 +7,6 @@ from sage.all import * p = 21888242871839275222246405745257275088548364400416034343698204186575808495617 F = FiniteField(p) -def poseidon2_hash(data): - return PoseidonSponge(data,2,1)[0] - - - -def Poseidon2_sponge_hash_rate_1(data, n): - return PoseidonSponge(data,3,2,n,1) - -def Poseidon2_sponge_hash_rate_2(data, n): - return PoseidonSponge(data,3,1,n,1) - - -def SBox(inp): - return inp**5 - -def InternalRound(inp, i): - round_consts = [ - 0x1a1d063e54b1e764b63e1855bff015b8cedd192f47308731499573f23597d4b5, - 0x26abc66f3fdf8e68839d10956259063708235dccc1aa3793b91b002c5b257c37, - 0x0c7c64a9d887385381a578cfed5aed370754427aabca92a70b3c2b12ff4d7be8, - 0x1cf5998769e9fab79e17f0b6d08b2d1eba2ebac30dc386b0edd383831354b495, - 0x0f5e3a8566be31b7564ca60461e9e08b19828764a9669bc17aba0b97e66b0109, - 0x18df6a9d19ea90d895e60e4db0794a01f359a53a180b7d4b42bf3d7a531c976e, - 0x04f7bf2c5c0538ac6e4b782c3c6e601ad0ea1d3a3b9d25ef4e324055fa3123dc, - 0x29c76ce22255206e3c40058523748531e770c0584aa2328ce55d54628b89ebe6, - 0x198d425a45b78e85c053659ab4347f5d65b1b8e9c6108dbe00e0e945dbc5ff15, - 0x25ee27ab6296cd5e6af3cc79c598a1daa7ff7f6878b3c49d49d3a9a90c3fdf74, - 0x138ea8e0af41a1e024561001c0b6eb1505845d7d0c55b1b2c0f88687a96d1381, - 0x306197fb3fab671ef6e7c2cba2eefd0e42851b5b9811f2ca4013370a01d95687, - 0x1a0c7d52dc32a4432b66f0b4894d4f1a21db7565e5b4250486419eaf00e8f620, - 0x2b46b418de80915f3ff86a8e5c8bdfccebfbe5f55163cd6caa52997da2c54a9f, - 0x12d3e0dc0085873701f8b777b9673af9613a1af5db48e05bfb46e312b5829f64, - 0x263390cf74dc3a8870f5002ed21d089ffb2bf768230f648dba338a5cb19b3a1f, - 0x0a14f33a5fe668a60ac884b4ca607ad0f8abb5af40f96f1d7d543db52b003dcd, - 0x28ead9c586513eab1a5e86509d68b2da27be3a4f01171a1dd847df829bc683b9, - 0x1c6ab1c328c3c6430972031f1bdb2ac9888f0ea1abe71cffea16cda6e1a7416c, - 0x1fc7e71bc0b819792b2500239f7f8de04f6decd608cb98a932346015c5b42c94, - 0x03e107eb3a42b2ece380e0d860298f17c0c1e197c952650ee6dd85b93a0ddaa8, - 0x2d354a251f381a4669c0d52bf88b772c46452ca57c08697f454505f6941d78cd, - 0x094af88ab05d94baf687ef14bc566d1c522551d61606eda3d14b4606826f794b, - 0x19705b783bf3d2dc19bcaeabf02f8ca5e1ab5b6f2e3195a9d52b2d249d1396f7, - 0x09bf4acc3a8bce3f1fcc33fee54fc5b28723b16b7d740a3e60cef6852271200e, - 0x1803f8200db6013c50f83c0c8fab62843413732f301f7058543a073f3f3b5e4e, - 0x0f80afb5046244de30595b160b8d1f38bf6fb02d4454c0add41f7fef2faf3e5c, - 0x126ee1f8504f15c3d77f0088c1cfc964abcfcf643f4a6fea7dc3f98219529d78, - 0x23c203d10cfcc60f69bfb3d919552ca10ffb4ee63175ddf8ef86f991d7d0a591, - 0x2a2ae15d8b143709ec0d09705fa3a6303dec1ee4eec2cf747c5a339f7744fb94, - 0x07b60dee586ed6ef47e5c381ab6343ecc3d3b3006cb461bbb6b5d89081970b2b, - 0x27316b559be3edfd885d95c494c1ae3d8a98a320baa7d152132cfe583c9311bd, - 0x1d5c49ba157c32b8d8937cb2d3f84311ef834cc2a743ed662f5f9af0c0342e76, - 0x2f8b124e78163b2f332774e0b850b5ec09c01bf6979938f67c24bd5940968488, - 0x1e6843a5457416b6dc5b7aa09a9ce21b1d4cba6554e51d84665f75260113b3d5, - 0x11cdf00a35f650c55fca25c9929c8ad9a68daf9ac6a189ab1f5bc79f21641d4b, - 0x21632de3d3bbc5e42ef36e588158d6d4608b2815c77355b7e82b5b9b7eb560bc, - 0x0de625758452efbd97b27025fbd245e0255ae48ef2a329e449d7b5c51c18498a, - 0x2ad253c053e75213e2febfd4d976cc01dd9e1e1c6f0fb6b09b09546ba0838098, - 0x1d6b169ed63872dc6ec7681ec39b3be93dd49cdd13c813b7d35702e38d60b077, - 0x1660b740a143664bb9127c4941b67fed0be3ea70a24d5568c3a54e706cfef7fe, - 0x0065a92d1de81f34114f4ca2deef76e0ceacdddb12cf879096a29f10376ccbfe, - 0x1f11f065202535987367f823da7d672c353ebe2ccbc4869bcf30d50a5871040d, - 0x26596f5c5dd5a5d1b437ce7b14a2c3dd3bd1d1a39b6759ba110852d17df0693e, - 0x16f49bc727e45a2f7bf3056efcf8b6d38539c4163a5f1e706743db15af91860f, - 0x1abe1deb45b3e3119954175efb331bf4568feaf7ea8b3dc5e1a4e7438dd39e5f, - 0x0e426ccab66984d1d8993a74ca548b779f5db92aaec5f102020d34aea15fba59, - 0x0e7c30c2e2e8957f4933bd1942053f1f0071684b902d534fa841924303f6a6c6, - 0x0812a017ca92cf0a1622708fc7edff1d6166ded6e3528ead4c76e1f31d3fc69d, - 0x21a5ade3df2bc1b5bba949d1db96040068afe5026edd7a9c2e276b47cf010d54, - 0x01f3035463816c84ad711bf1a058c6c6bd101945f50e5afe72b1a5233f8749ce, - 0x0b115572f038c0e2028c2aafc2d06a5e8bf2f9398dbd0fdf4dcaa82b0f0c1c8b, - 0x1c38ec0b99b62fd4f0ef255543f50d2e27fc24db42bc910a3460613b6ef59e2f, - 0x1c89c6d9666272e8425c3ff1f4ac737b2f5d314606a297d4b1d0b254d880c53e, - 0x03326e643580356bf6d44008ae4c042a21ad4880097a5eb38b71e2311bb88f8f, - 0x268076b0054fb73f67cee9ea0e51e3ad50f27a6434b5dceb5bdde2299910a4c9, -] - - - sb = SBox(inp[0] + round_consts[i]) - out = [F(0) for i in range(3)] - out[0] = 2*sb + inp[1] + inp[2]; - out[1] = sb + 2*inp[1] + inp[2]; - out[2] = sb + inp[1] + 3*inp[2]; - return out - -def ExternalRound(inp, i): - out = [F(0) for j in range(3)] - round_consts = [ [F(0x1d066a255517b7fd8bddd3a93f7804ef7f8fcde48bb4c37a59a09a1a97052816) - , F(0x29daefb55f6f2dc6ac3f089cebcc6120b7c6fef31367b68eb7238547d32c1610) - , F(0x1f2cb1624a78ee001ecbd88ad959d7012572d76f08ec5c4f9e8b7ad7b0b4e1d1) - ] - , [ F(0x0aad2e79f15735f2bd77c0ed3d14aa27b11f092a53bbc6e1db0672ded84f31e5) - , F(0x2252624f8617738cd6f661dd4094375f37028a98f1dece66091ccf1595b43f28) - , F(0x1a24913a928b38485a65a84a291da1ff91c20626524b2b87d49f4f2c9018d735) - ] - , [ F(0x22fc468f1759b74d7bfc427b5f11ebb10a41515ddff497b14fd6dae1508fc47a) - , F(0x1059ca787f1f89ed9cd026e9c9ca107ae61956ff0b4121d5efd65515617f6e4d) - , F(0x02be9473358461d8f61f3536d877de982123011f0bf6f155a45cbbfae8b981ce) - ] - , [ F(0x0ec96c8e32962d462778a749c82ed623aba9b669ac5b8736a1ff3a441a5084a4) - , F(0x292f906e073677405442d9553c45fa3f5a47a7cdb8c99f9648fb2e4d814df57e) - , F(0x274982444157b86726c11b9a0f5e39a5cc611160a394ea460c63f0b2ffe5657e) - ] - , [ F(0x1acd63c67fbc9ab1626ed93491bda32e5da18ea9d8e4f10178d04aa6f8747ad0) - , F(0x19f8a5d670e8ab66c4e3144be58ef6901bf93375e2323ec3ca8c86cd2a28b5a5) - , F(0x1c0dc443519ad7a86efa40d2df10a011068193ea51f6c92ae1cfbb5f7b9b6893) - ] - , [ F(0x14b39e7aa4068dbe50fe7190e421dc19fbeab33cb4f6a2c4180e4c3224987d3d) - , F(0x1d449b71bd826ec58f28c63ea6c561b7b820fc519f01f021afb1e35e28b0795e) - , F(0x1ea2c9a89baaddbb60fa97fe60fe9d8e89de141689d1252276524dc0a9e987fc) - ] - , [ F(0x0478d66d43535a8cb57e9c1c3d6a2bd7591f9a46a0e9c058134d5cefdb3c7ff1) - , F(0x19272db71eece6a6f608f3b2717f9cd2662e26ad86c400b21cde5e4a7b00bebe) - , F(0x14226537335cab33c749c746f09208abb2dd1bd66a87ef75039be846af134166) - ] - , [ F(0x01fd6af15956294f9dfe38c0d976a088b21c21e4a1c2e823f912f44961f9a9ce) - , F(0x18e5abedd626ec307bca190b8b2cab1aaee2e62ed229ba5a5ad8518d4e5f2a57) - , F(0x0fc1bbceba0590f5abbdffa6d3b35e3297c021a3a409926d0e2d54dc1c84fda6) - ]] - - - sb = [F(0) for j in range(3)] - for j in range(3): - sb[j] = SBox(F(inp[j] + round_consts[i][j])) - out = [F(0) for j in range(3)] - out[0] = 2*sb[0] + sb[1] + sb[2] - out[1] = sb[0] + 2*sb[1] + sb[2] - out[2] = sb[0]+ sb[1] + 2*sb[2] - return out - -def LinearLayer(inp): - out = [F(0) for i in range(3)] - out[0] = 2*inp[0] + inp[1] + inp[2] - out[1] = inp[0] + 2*inp[1] + inp[2] - out[2] = inp[0] + inp[1] + 2*inp[2] - return out - -def Permutation(inp): - out = [F(0) for i in range(3)] - - state = LinearLayer(inp) - - for k in range(4): - state = ExternalRound(state, k) - for k in range(56): - state = InternalRound(state, k) - for k in range(4): - state = ExternalRound(state, k+4) - return state - -def Compression(inp): - return Permutation([inp[0],inp[1],F(0)]) - -def PoseidonSponge(data, capacity, output_len): - rate = 3 - capacity; - output = [F(0) for i in range(output_len)] - assert( capacity > 0 ) - assert( rate > 0 ) - assert( capacity < 3 ) - assert( rate < 3 ) - - # round up to rate the input + 1 field element ("10*" padding) - nblocks = ((len(data) + 1) + (rate-1)) // rate; - nout = (output_len + (rate-1)) // rate; - padded_len = nblocks * rate; - - padded = [] - for i in range(len(data)): - padded.append(F(data[i])) - padded.append(F(1)) - for i in range(len(data)+1,padded_len): - padded.append(F(0)) - - civ = F(0) - - state = [F(0),F(0),F(civ)] - sorbed = [F(0) for j in range(rate)] - - for m in range(nblocks): - for i in range(rate): - a = state[i] - b = padded[m*rate+i] - sorbed[i] = a + b - state = Permutation(sorbed[0:rate] + state[rate:3]) - - q = min(rate, output_len) - for i in range(q): - output[i] = state[i] - out_ptr = rate - - for n in range(1,nout): - state[nblocks+n] = Permutation(state[nblocks+n-1]) - q = min(rate, output_len-out_ptr) - for i in range(q): - output[out_ptr+i] = state[nblocks+n][i] - out_ptr += rate - - return output - if len(sys.argv) != Integer(2): print("Usage: