removed the secrets_root input from pol and poq

This commit is contained in:
thomaslavaur 2025-08-26 09:57:02 +02:00
parent 5c0465a41e
commit da9101c761
6 changed files with 66 additions and 48 deletions

View File

@ -207,7 +207,7 @@ def PoseidonSponge(data, capacity, output_len):
# Main
# ———————————————————————
if len(sys.argv) != 5:
print("Usage: python3 generate_inputs_for_poq.py <session> <Qc> <Ql> <core (0) or leader (1)>")
print("Usage: python3 generate_inputs_for_poq.py <session> <core_quota> <leader_quota> <core (0) or leader (1)>")
sys.exit(1)
session = int(sys.argv[1])
@ -314,7 +314,6 @@ inp = {
"pol_note_tx_hash": str(tx_hash),
"pol_note_output_number": str(output_number),
"pol_sk_starting_slot": str(starting_slot),
"secrets_root": str(secret_root), # THIS NEEDS TO BE REMOVED
"pol_note_value": str(value)
}

View File

@ -54,14 +54,13 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
signal input pol_note_output_number;
signal input pol_sk_starting_slot;
signal input secrets_root; // THIS NEEDS TO BE REMOVED
signal input pol_note_value;
// Constraints
// Constraint the selector to be a bit
selector * (1 - selector) === 0;
// derive pk_core = Poseidon(NOMOS_KDF || core_sk)
component kdf = Poseidon2_hash(2);
component dstKdf = NOMOS_KDF_V1();
@ -70,6 +69,7 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
signal pk_core;
pk_core <== kdf.out;
// Merkleverify pk_core in core_root
component coreReg = proof_of_membership(nLevelsPK);
for (var i = 0; i < nLevelsPK; i++) {
@ -80,6 +80,7 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
coreReg.root <== core_root;
coreReg.leaf <== pk_core;
// enforce potential PoL (without verification that the note is unspent)
// (All constraints inside pol ensure LeadershipVerify)
component would_win = would_win_leadership(nLevelsPol);
@ -99,21 +100,19 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
would_win.transaction_hash <== pol_note_tx_hash;
would_win.output_number <== pol_note_output_number;
would_win.starting_slot <== pol_sk_starting_slot;
would_win.secrets_root <== secrets_root;
would_win.value <== pol_note_value;
// Enforce the selected role is correct
selector * (would_win.out - coreReg.out) + coreReg.out === 1;
// Quota check: index < core_quota if core, index < leader_quota if leader
component cmp = SafeLessThan(bitsQuota);
cmp.in[0] <== index;
cmp.in[1] <== selector * (leader_quota - core_quota) + core_quota;
cmp.out === 1;
// Derive selection_randomness
component randomness = Poseidon2_hash(4);
component dstSel = SELECTION_RANDOMNESS_V1();
@ -123,9 +122,10 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
randomness.inp[2] <== index;
randomness.inp[3] <== session;
// Derive key_nullifier
component nf = Poseidon2_hash(2);
component dstNF = PROOF_NULLIFIER_V1(); // THIS NEEDS TO BE UPDATED
component dstNF = KEY_NULLIFIER_V1();
nf.inp[0] <== dstNF.out;
nf.inp[1] <== randomness.out;
key_nullifier <== nf.out;

View File

@ -295,7 +295,6 @@ inp = {
"noteid_latest_selectors": [str(x) for x in unspent_selectors],
"ledger_latest": str(latest_root),
"starting_slot": str(starting_slot),
"secrets_root": str(secret_root) ,
"v": str(value)
}

View File

@ -3,7 +3,7 @@ pragma circom 2.1.9;
include "../hash_bn/poseidon2_hash.circom";
include "../ledger/notes.circom";
include "../ledger/merkle.circom";
include "../hash_bn/merkle.circom";
include "../misc/comparator.circom";
include "../circomlib/circuits/bitify.circom";
include "../misc/constants.circom";
@ -76,7 +76,6 @@ template would_win_leadership(secret_depth){
//Part of the secret key
signal input starting_slot;
signal input secrets_root;
// The winning note value
signal input value;
@ -86,10 +85,29 @@ template would_win_leadership(secret_depth){
signal output secret_key;
// Check the knowledge of the slot secret at position slot - starting_slot
// Verify that the substraction wont underflow (starting_slot < slot)
component checker = SafeLessEqThan(252);
checker.in[0] <== starting_slot;
checker.in[1] <== slot;
// Compute the positions related to slot - starting_slot (and make sure secret_depth = 25 bits)
component bits = Num2Bits(secret_depth);
bits.in <== slot - starting_slot;
// Derive the secrets root
component secrets_root = compute_merkle_root(secret_depth);
for(var i=0; i<secret_depth; i++){
secrets_root.nodes[i] <== slot_secret_path[i];
secrets_root.selector[i] <== bits.out[secret_depth-1-i];
}
secrets_root.leaf <== slot_secret;
// Derive the secret key
component sk = derive_secret_key();
sk.starting_slot <== starting_slot;
sk.secrets_root <== secrets_root;
sk.secrets_root <== secrets_root.root;
// Derive the public key from the secret key
@ -142,29 +160,10 @@ template would_win_leadership(secret_depth){
winning.a <== ticket.out;
winning.b <== threshold;
// Check the knowledge of the secret at position slot - starting_slot
// Verify that the substraction wont underflow (starting_slot < slot)
component checker = SafeLessEqThan(252);
checker.in[0] <== starting_slot;
checker.in[1] <== slot;
// Compute the positions related to slot - starting_slot (and make sure it's 25 bits)
component bits = Num2Bits(secret_depth);
bits.in <== slot - starting_slot;
// Check the membership of the secret_slot against the secrets_root
component secret_membership = proof_of_membership(secret_depth);
for(var i =0; i<secret_depth; i++){
secret_membership.nodes[i] <== slot_secret_path[i];
secret_membership.selector[i] <== bits.out[secret_depth-1-i];
}
secret_membership.root <== secrets_root;
secret_membership.leaf <== slot_secret;
// Check that every constraint holds
signal intermediate_out[2];
intermediate_out[0] <== aged_membership.out * winning.out;
intermediate_out[1] <== checker.out * secret_membership.out;
out <== intermediate_out[0] * intermediate_out[1];
signal intermediate_out;
intermediate_out <== aged_membership.out * winning.out;
out <== intermediate_out * checker.out;
note_identifier <== note_id.out;
secret_key <== sk.out;
@ -195,11 +194,11 @@ template proof_of_leadership(secret_depth){
//Part of the secret key
signal input starting_slot;
signal input secrets_root; // THIS NEEDS TO BE REMOVED
// The winning note. The unit is supposed to be NMO and the ZoneID is MANTLE
signal input v; // value of the note
// Verify the note is winning the lottery
component lottery_checker = would_win_leadership(secret_depth);
lottery_checker.slot <== sl;
@ -218,7 +217,6 @@ template proof_of_leadership(secret_depth){
lottery_checker.transaction_hash <== note_tx_hash;
lottery_checker.output_number <== note_output_number;
lottery_checker.starting_slot <== starting_slot;
lottery_checker.secrets_root <== secrets_root;
lottery_checker.value <== v;
@ -226,6 +224,7 @@ template proof_of_leadership(secret_depth){
signal input P_lead_part_one;
signal input P_lead_part_two;
//Avoid the circom optimisation that removes unused public input
signal dummy_one;
signal dummy_two;

View File

@ -4,14 +4,13 @@ pragma circom 2.1.9;
include "../hash_bn/poseidon2_hash.circom";
include "../circomlib/circuits/comparators.circom";
// proof of Merkle membership of depth n
// compute a merkle root of depth n
// /!\ To call this function, it's important to check that each selector is a bit before!!!
template proof_of_membership(n) {
signal input nodes[n]; // The path forming the Merkle proof
signal input selector[n]; // it's the leaf's indice in big endian bits
signal input root;
template compute_merkle_root(n) {
signal input nodes[n]; // The Merkle path
signal input selector[n]; // it's the leaf's indice in big endian bits indicating if complementary nodes are left or right
signal input leaf;
signal output out;
signal output root;
component compression_hash[n];
@ -26,9 +25,31 @@ template proof_of_membership(n) {
compression_hash[i].inp[1] <== nodes[i] - selector[n-1-i] * (nodes[i] - compression_hash[i-1].out);
}
root <== compression_hash[n-1].out;
}
// Verify a Merkle proof of depth n
// /!\ To call this function, it's important to check that each selector is a bit before!!!
template proof_of_membership(n) {
signal input nodes[n]; // The Merkle path
signal input selector[n]; // it's the leaf's indice in big endian bits indicating if complementary nodes are left or right
signal input root;
signal input leaf;
signal output out;
component root_calculator = compute_merkle_root(n);
for(var i=0; i<n; i++){
root_calculator.nodes[i] <== nodes[i];
root_calculator.selector[i] <== selector[i];
}
root_calculator.leaf <== leaf;
component eq = IsEqual();
eq.in[0] <== root;
eq.in[1] <== compression_hash[n-1].out;
eq.in[0] <== root_calculator.root;
eq.in[1] <== root;
out <== eq.out;
}

View File

@ -46,10 +46,10 @@ template SELECTION_RANDOMNESS_V1(){
}
// int.from_bytes(hashlib.blake2b(b"PROOF_NULLIFIER_V1", digest_size=32).digest()[:-1], "little") = 122037697982558563853882923701277343284564598726996395839110393320403237949
template PROOF_NULLIFIER_V1(){
// int.from_bytes(hashlib.blake2b(b"KEY_NULLIFIER_V1", digest_size=32).digest()[:-1], "little") = 276099761984071152198272194832739979363346624368736196681403791762138255387
template KEY_NULLIFIER_V1(){
signal output out;
out <== 122037697982558563853882923701277343284564598726996395839110393320403237949;
out <== 276099761984071152198272194832739979363346624368736196681403791762138255387;
}
// int.from_bytes(hashlib.blake2b(b"REWARD_VOUCHER", digest_size=32).digest()[:-1], "little") = 220700623067091879569340598814410483038955857088532228155209730029981553361