From 360a964ee87f30264877880a873d918ed68fd35b Mon Sep 17 00:00:00 2001 From: thomaslavaur Date: Fri, 30 May 2025 12:20:28 +0200 Subject: [PATCH] updated poq removing the need to verify the winning note is unspent --- .../Blend/generate_inputs_for_poq.py | 16 +------ circom_circuits/Blend/poq.circom | 47 ++++++++----------- 2 files changed, 21 insertions(+), 42 deletions(-) diff --git a/circom_circuits/Blend/generate_inputs_for_poq.py b/circom_circuits/Blend/generate_inputs_for_poq.py index 9cb52c5..bafc75e 100644 --- a/circom_circuits/Blend/generate_inputs_for_poq.py +++ b/circom_circuits/Blend/generate_inputs_for_poq.py @@ -280,17 +280,6 @@ for i in range(32): else: aged_root = poseidon2_hash([aged_nodes[i],aged_root]) -unspent_nodes = [F(randrange(0,p,1)) for i in range(32)] -unspent_selectors = randrange(0,2**32,1) -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]]) - else: - latest_root = poseidon2_hash([unspent_nodes[i],latest_root]) - # 3) Choose branch & index index = randrange(0, Ql if core_or_leader else Qc,1) @@ -304,7 +293,6 @@ inp = { "Ql": str(Ql), "pk_root": str(core_root), "aged_root": str(aged_root), - "latest_root": str(latest_root), "K": str(K), "selector": str(core_or_leader), "index": str(index), @@ -321,15 +309,13 @@ inp = { "aged_selectors": [str(x) for x in aged_selectors], "transaction_hash": str(tx_hash), "output_number": str(output_number), - "latest_nodes": [str(x) for x in unspent_nodes], - "latest_selectors": [str(x) for x in unspent_selectors], "starting_slot": str(starting_slot), "secrets_root": str(secret_root), "value": str(value) } if core_or_leader == 0: - inp["latest_root"] = randrange(0,p,1) + inp["aged_root"] = randrange(0,p,1) else: inp["pk_root"] = randrange(0,p,1) diff --git a/circom_circuits/Blend/poq.circom b/circom_circuits/Blend/poq.circom index 6a5323d..0b4ee9c 100644 --- a/circom_circuits/Blend/poq.circom +++ b/circom_circuits/Blend/poq.circom @@ -21,7 +21,6 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) { signal input Ql; // leadership quota Q_L signal input pk_root; // Merkle root of registered core-node public keys signal input aged_root; // PoL: aged notes root - signal input latest_root; // PoL: latest notes root signal input K; // Blend: one-time signature public key signal dummy; @@ -50,8 +49,6 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) { signal input aged_selectors[32]; signal input transaction_hash; signal input output_number; - signal input latest_nodes[32]; - signal input latest_selectors[32]; signal input starting_slot; signal input secrets_root; @@ -80,34 +77,30 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) { coreReg.root <== pk_root; coreReg.leaf <== pk_core; - // enforce PoL + // enforce potential PoL (without verification that the note is unspent) // (All constraints inside pol ensure LeadershipVerify) - // /!\ copy the PoL constraints here /!\ - component win = is_winning_leadership(nLevelsPol); - win.slot <== slot; - win.epoch_nonce <== epoch_nonce; - win.t0 <== t0; - win.t1 <== t1; - win.slot_secret <== slot_secret; + component would_win = would_win_leadership(nLevelsPol); + would_win.slot <== slot; + would_win.epoch_nonce <== epoch_nonce; + would_win.t0 <== t0; + would_win.t1 <== t1; + would_win.slot_secret <== slot_secret; for (var i = 0; i < nLevelsPol; i++) { - win.slot_secret_path[i] <== slot_secret_path[i]; + would_win.slot_secret_path[i] <== slot_secret_path[i]; } for (var i = 0; i < 32; i++) { - win.aged_nodes[i] <== aged_nodes[i]; - win.aged_selectors[i] <== aged_selectors[i]; - win.latest_nodes[i] <== latest_nodes[i]; - win.latest_selectors[i]<== latest_selectors[i]; + would_win.aged_nodes[i] <== aged_nodes[i]; + would_win.aged_selectors[i] <== aged_selectors[i]; } - win.aged_root <== aged_root; - win.transaction_hash <== transaction_hash; - win.output_number <== output_number; - win.latest_root <== latest_root; - win.starting_slot <== starting_slot; - win.secrets_root <== secrets_root; - win.value <== value; + would_win.aged_root <== aged_root; + would_win.transaction_hash <== transaction_hash; + would_win.output_number <== output_number; + would_win.starting_slot <== starting_slot; + would_win.secrets_root <== secrets_root; + would_win.value <== value; // Enforce the selected role is correct - selector * (win.out - coreReg.out) + coreReg.out === 1; + selector * (would_win.out - coreReg.out) + coreReg.out === 1; @@ -123,7 +116,7 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) { component dstSel = SELECTION_RANDOMNESS_V1(); randomness.inp[0] <== dstSel.out; // choose core_sk or pol.secret_key: - randomness.inp[1] <== selector * (win.secret_key - core_sk ) + core_sk; + randomness.inp[1] <== selector * (would_win.secret_key - core_sk ) + core_sk; randomness.inp[2] <== index; randomness.inp[3] <== session; @@ -136,5 +129,5 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) { } // Instantiate with chosen depths: 20 for core PK tree, 25 for PoL slot tree -component main { public [ session, Qc, Ql, pk_root, aged_root, latest_root, K ] } - = ProofOfQuota(20, 25, 6); \ No newline at end of file +component main { public [ session, Qc, Ql, pk_root, aged_root, K ] } + = ProofOfQuota(20, 25, 20); \ No newline at end of file