ensured everything is aligned with the specs

This commit is contained in:
thomaslavaur 2025-08-26 10:37:51 +02:00
parent da9101c761
commit da383e1a87
4 changed files with 45 additions and 46 deletions

View File

@ -6,6 +6,7 @@ include "../misc/constants.circom"; // defines NOMOS_KDF, SELECTION_RAND
include "../misc/comparator.circom";
include "../circomlib/circuits/bitify.circom";
include "../Mantle/pol.circom"; // defines proof_of_leadership
include "../ledger/notes.circom";
/**
* ProofOfQuota(nLevelsPK, nLevelsPol)
@ -61,24 +62,29 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
selector * (1 - selector) === 0;
// derive pk_core = Poseidon(NOMOS_KDF || core_sk)
component kdf = Poseidon2_hash(2);
component dstKdf = NOMOS_KDF_V1();
kdf.inp[0] <== dstKdf.out;
kdf.inp[1] <== core_sk;
signal pk_core;
pk_core <== kdf.out;
// 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;
// Merkleverify pk_core in core_root
component coreReg = proof_of_membership(nLevelsPK);
// derive zk_id
component zk_id = derive_public_key();
zk_id.secret_key <== core_sk;
// Merkleverify zk_id in core_root
component is_registered = proof_of_membership(nLevelsPK);
for (var i = 0; i < nLevelsPK; i++) {
//check that the selectors are indeed bits
core_path_selectors[i] * (1 - core_path_selectors[i]) === 0;
coreReg.nodes[i] <== core_path[i];
coreReg.selector[i] <== core_path_selectors[i];
//call the merkle proof checker
is_registered.nodes[i] <== core_path[i];
is_registered.selector[i] <== core_path_selectors[i];
}
coreReg.root <== core_root;
coreReg.leaf <== pk_core;
is_registered.root <== core_root;
is_registered.leaf <== zk_id.out;
// enforce potential PoL (without verification that the note is unspent)
@ -103,31 +109,24 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
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;
selector * (would_win.out - is_registered.out) + is_registered.out === 1;
// Derive selection_randomness
component randomness = Poseidon2_hash(4);
component selection_randomness = Poseidon2_hash(4);
component dstSel = SELECTION_RANDOMNESS_V1();
randomness.inp[0] <== dstSel.out;
selection_randomness.inp[0] <== dstSel.out;
// choose core_sk or pol.secret_key:
randomness.inp[1] <== selector * (would_win.secret_key - core_sk ) + core_sk;
randomness.inp[2] <== index;
randomness.inp[3] <== session;
selection_randomness.inp[1] <== selector * (would_win.secret_key - core_sk ) + core_sk;
selection_randomness.inp[2] <== index;
selection_randomness.inp[3] <== session;
// Derive key_nullifier
component nf = Poseidon2_hash(2);
component dstNF = KEY_NULLIFIER_V1();
nf.inp[0] <== dstNF.out;
nf.inp[1] <== randomness.out;
nf.inp[1] <== selection_randomness.out;
key_nullifier <== nf.out;
}

View File

@ -27,20 +27,6 @@ template ticket_calculator(){
out <== hash.out;
}
template derive_secret_key(){
signal input starting_slot;
signal input secrets_root;
signal output out;
component hash = Poseidon2_hash(3);
component dst = NOMOS_POL_SK_V1();
hash.inp[0] <== dst.out;
hash.inp[1] <== starting_slot;
hash.inp[2] <== secrets_root;
out <== hash.out;
}
template derive_entropy(){
signal input slot;
signal input note_id;
@ -85,7 +71,7 @@ template would_win_leadership(secret_depth){
signal output secret_key;
// Check the knowledge of the slot secret at position slot - starting_slot
// Derivation of the secrets root from 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;

View File

@ -4,12 +4,26 @@ pragma circom 2.1.9;
include "../hash_bn/poseidon2_hash.circom";
include "../misc/constants.circom";
template derive_secret_key(){
signal input starting_slot;
signal input secrets_root;
signal output out;
component hash = Poseidon2_hash(3);
component dst = NOMOS_POL_SK_V1();
hash.inp[0] <== dst.out;
hash.inp[1] <== starting_slot;
hash.inp[2] <== secrets_root;
out <== hash.out;
}
template derive_public_key(){
signal input secret_key;
signal output out;
component hash = Poseidon2_hash(2);
component dst = NOMOS_KDF_V1();
component dst = NOMOS_KDF();
hash.inp[0] <== dst.out;
hash.inp[1] <== secret_key;
out <== hash.out;

View File

@ -25,10 +25,10 @@ template NOMOS_NONCE_CONTRIB_V1(){
}
// int.from_bytes(hashlib.blake2b(b"NOMOS_KDF_V1", digest_size=32).digest()[:-1], "little") = 71828171600713765359243601848789410494517675262904677980449468236927732106
template NOMOS_KDF_V1(){
// int.from_bytes(hashlib.blake2b(b"NOMOS_KDF", digest_size=32).digest()[:-1], "little") = 212459341846278437262234987091558730706084889692483733611934435194121904625
template NOMOS_KDF(){
signal output out;
out <== 71828171600713765359243601848789410494517675262904677980449468236927732106;
out <== 212459341846278437262234987091558730706084889692483733611934435194121904625;
}