updated the circuit to reflect the names of the specs

This commit is contained in:
thomaslavaur 2025-08-25 15:51:48 +02:00
parent 73e5ecb7e7
commit 5c0465a41e
11 changed files with 132 additions and 134 deletions

View File

@ -292,36 +292,36 @@ K_two = F(randrange(0,p,1))
# 5) Assemble JSON
inp = {
"session": str(session),
"Qc": str(Qc),
"Ql": str(Ql),
"pk_root": str(core_root),
"aged_root": str(aged_root),
"core_quota": str(Qc),
"leader_quota": str(Ql),
"core_root": str(core_root),
"pol_ledger_aged": str(aged_root),
"K_part_one": str(K_one),
"K_part_two": str(K_two),
"selector": str(core_or_leader),
"index": str(index),
"core_sk": str(core_sk),
"core_path": [str(x) for x in core_nodes],
"core_selectors": [str(x) for x in core_selectors],
"slot": str(slot_number),
"epoch_nonce": str(epoch_nonce),
"t0": str(t0),
"t1": str(t1),
"slot_secret": str(slot_secret),
"slot_secret_path": [str(x) for x in slot_secret_path],
"aged_nodes": [str(x) for x in aged_nodes],
"aged_selectors": [str(x) for x in aged_selectors],
"transaction_hash": str(tx_hash),
"output_number": str(output_number),
"starting_slot": str(starting_slot),
"secrets_root": str(secret_root),
"value": str(value)
"core_path_selectors": [str(x) for x in core_selectors],
"pol_sl": str(slot_number),
"pol_epoch_nonce": str(epoch_nonce),
"pol_t0": str(t0),
"pol_t1": str(t1),
"pol_slot_secret": str(slot_secret),
"pol_slot_secret_path": [str(x) for x in slot_secret_path],
"pol_noteid_path": [str(x) for x in aged_nodes],
"pol_noteid_path_selectors": [str(x) for x in aged_selectors],
"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)
}
if core_or_leader == 0:
inp["aged_root"] = randrange(0,p,1)
inp["pol_ledger_aged"] = randrange(0,p,1)
else:
inp["pk_root"] = randrange(0,p,1)
inp["core_root"] = randrange(0,p,1)
import json

View File

@ -17,10 +17,10 @@ include "../Mantle/pol.circom"; // defines proof_of_leadership
template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
// Public Inputs
signal input session; // session s
signal input Qc; // core quota Q_C
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 core_quota;
signal input leader_quota;
signal input core_root;
signal input pol_ledger_aged; // PoL: aged notes root
signal input K_part_one; // Blend: one-time signature public key
signal input K_part_two; // Blend: one-time signature public key
@ -29,7 +29,7 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
signal dummy_two;
dummy_two <== K_part_two * K_part_two;
signal output nullifier; //key_nullifier
signal output key_nullifier; //key_nullifier
// Private Inputs
signal input selector; // 0 = core, 1 = leader
@ -38,24 +38,24 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
// Core-nodes inputs
signal input core_sk; // core node secret key
signal input core_path[nLevelsPK]; // Merkle path for core PK
signal input core_selectors[nLevelsPK]; // path selectors (bits)
signal input core_path_selectors[nLevelsPK]; // path selectors (bits)
// PoL branch inputs (all the PoL private data)
signal input slot;
signal input epoch_nonce;
signal input t0;
signal input t1;
signal input slot_secret;
signal input slot_secret_path[nLevelsPol];
signal input pol_sl;
signal input pol_epoch_nonce;
signal input pol_t0;
signal input pol_t1;
signal input pol_slot_secret;
signal input pol_slot_secret_path[nLevelsPol];
signal input aged_nodes[32];
signal input aged_selectors[32];
signal input transaction_hash;
signal input output_number;
signal input pol_noteid_path[32];
signal input pol_noteid_path_selectors[32];
signal input pol_note_tx_hash;
signal input pol_note_output_number;
signal input starting_slot;
signal input secrets_root;
signal input value;
signal input pol_sk_starting_slot;
signal input secrets_root; // THIS NEEDS TO BE REMOVED
signal input pol_note_value;
@ -70,37 +70,37 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
signal pk_core;
pk_core <== kdf.out;
// Merkleverify pk_core in pk_root
// Merkleverify pk_core in core_root
component coreReg = proof_of_membership(nLevelsPK);
for (var i = 0; i < nLevelsPK; i++) {
core_selectors[i] * (1 - core_selectors[i]) === 0;
core_path_selectors[i] * (1 - core_path_selectors[i]) === 0;
coreReg.nodes[i] <== core_path[i];
coreReg.selector[i] <== core_selectors[i];
coreReg.selector[i] <== core_path_selectors[i];
}
coreReg.root <== pk_root;
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);
would_win.slot <== slot;
would_win.epoch_nonce <== epoch_nonce;
would_win.t0 <== t0;
would_win.t1 <== t1;
would_win.slot_secret <== slot_secret;
would_win.slot <== pol_sl;
would_win.epoch_nonce <== pol_epoch_nonce;
would_win.t0 <== pol_t0;
would_win.t1 <== pol_t1;
would_win.slot_secret <== pol_slot_secret;
for (var i = 0; i < nLevelsPol; i++) {
would_win.slot_secret_path[i] <== slot_secret_path[i];
would_win.slot_secret_path[i] <== pol_slot_secret_path[i];
}
for (var i = 0; i < 32; i++) {
would_win.aged_nodes[i] <== aged_nodes[i];
would_win.aged_selectors[i] <== aged_selectors[i];
would_win.aged_nodes[i] <== pol_noteid_path[i];
would_win.aged_selectors[i] <== pol_noteid_path_selectors[i];
}
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.aged_root <== pol_ledger_aged;
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 <== value;
would_win.value <== pol_note_value;
// Enforce the selected role is correct
selector * (would_win.out - coreReg.out) + coreReg.out === 1;
@ -108,10 +108,10 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
// Quota check: index < Qc if core, index < Ql if leader
// Quota check: index < core_quota if core, index < leader_quota if leader
component cmp = SafeLessThan(bitsQuota);
cmp.in[0] <== index;
cmp.in[1] <== selector * (Ql - Qc) + Qc;
cmp.in[1] <== selector * (leader_quota - core_quota) + core_quota;
cmp.out === 1;
// Derive selection_randomness
@ -123,14 +123,14 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
randomness.inp[2] <== index;
randomness.inp[3] <== session;
// Derive proof_nullifier
// Derive key_nullifier
component nf = Poseidon2_hash(2);
component dstNF = PROOF_NULLIFIER_V1();
component dstNF = PROOF_NULLIFIER_V1(); // THIS NEEDS TO BE UPDATED
nf.inp[0] <== dstNF.out;
nf.inp[1] <== randomness.out;
nullifier <== nf.out;
key_nullifier <== nf.out;
}
// Instantiate with chosen depths: 20 for core PK tree, 25 for PoL slot tree
component main { public [ session, Qc, Ql, pk_root, aged_root, K_part_one, K_part_two ] }
// Instantiate with chosen depths: 20 for core PK tree, 25 for PoL secret slot tree
component main { public [ session, core_quota, leader_quota, core_root, pol_ledger_aged, K_part_one, K_part_two ] }
= ProofOfQuota(20, 25, 20);

View File

@ -278,25 +278,25 @@ for i in range(32):
# 5) Assemble JSON
inp = {
"slot": str(slot_number),
"sl": str(slot_number),
"epoch_nonce": str(epoch_nonce),
"t0": str(t0),
"t1": str(t1),
"slot_secret": str(slot_secret),
"one_time_key_part_one": str(F(123456)),
"one_time_key_part_two": str(F(654321)),
"P_lead_part_one": str(F(123456)),
"P_lead_part_two": str(F(654321)),
"slot_secret_path": [str(x) for x in slot_secret_path],
"aged_nodes": [str(x) for x in aged_nodes],
"aged_selectors": [str(x) for x in aged_selectors],
"aged_root": str(aged_root),
"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],
"latest_root": str(latest_root),
"noteid_aged_path": [str(x) for x in aged_nodes],
"noteid_aged_selectors": [str(x) for x in aged_selectors],
"ledger_aged": str(aged_root),
"note_tx_hash": str(tx_hash),
"note_output_number": str(output_number),
"noteid_latest_path": [str(x) for x in unspent_nodes],
"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) ,
"value": str(value)
"v": str(value)
}
import json

View File

@ -224,9 +224,9 @@ data_msg = F(randrange(0,p,1))
inp = {
"secret_voucher": str(secret_voucher),
"merkle_nodes": [str(x) for x in merkle_nodes],
"selectors": [str(x) for x in selectors],
"attached_data": str(data_msg),
"voucher_merkle_path":[str(x) for x in merkle_nodes],
"voucher_merkle_path_selectors": [str(x) for x in selectors],
"mantle_tx_hash": str(data_msg),
"voucher_root": str(voucher_root)
}

View File

@ -215,13 +215,13 @@ data_msg = F(randrange(0,p,1))
if nInput == 1:
inp = {
"secret_key": str(sk[0]),
"attached_data": str(data_msg)
"secret_keys": str(sk[0]),
"msg": str(data_msg)
}
else:
inp = {
"secret_key": [str(x) for x in sk],
"attached_data": str(data_msg)
"secret_keys": [str(x) for x in sk],
"msg": str(data_msg)
}
import json

View File

@ -172,37 +172,37 @@ template would_win_leadership(secret_depth){
template proof_of_leadership(secret_depth){
signal input slot;
signal input epoch_nonce;
signal input sl;
signal input epoch_nonce; // the epoch nonce eta
signal input t0;
signal input t1;
signal input slot_secret;
signal input slot_secret; // This is r_sl
signal input slot_secret_path[secret_depth];
//Part of the note id proof of membership to prove aged
signal input aged_nodes[32];
signal input aged_selectors[32]; // must be bits
signal input aged_root;
signal input noteid_aged_path[32];
signal input noteid_aged_selectors[32]; // must be bits
signal input ledger_aged;
//Used to derive the note identifier
signal input transaction_hash;
signal input output_number;
signal input note_tx_hash;
signal input note_output_number;
//Part of the note id proof of membership to prove it's unspent
signal input latest_nodes[32];
signal input latest_selectors[32]; // must be bits
signal input latest_root;
signal input noteid_latest_path[32];
signal input noteid_latest_selectors[32]; // must be bits
signal input ledger_latest;
//Part of the secret key
signal input starting_slot;
signal input secrets_root;
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 value;
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 <== slot;
lottery_checker.slot <== sl;
lottery_checker.epoch_nonce <== epoch_nonce;
lottery_checker.t0 <== t0;
lottery_checker.t1 <== t1;
@ -211,42 +211,42 @@ template proof_of_leadership(secret_depth){
lottery_checker.slot_secret_path[i] <== slot_secret_path[i];
}
for(var i = 0; i < 32; i++){
lottery_checker.aged_nodes[i] <== aged_nodes[i];
lottery_checker.aged_selectors[i] <== aged_selectors[i];
lottery_checker.aged_nodes[i] <== noteid_aged_path[i];
lottery_checker.aged_selectors[i] <== noteid_aged_selectors[i];
}
lottery_checker.aged_root <== aged_root;
lottery_checker.transaction_hash <== transaction_hash;
lottery_checker.output_number <== output_number;
lottery_checker.aged_root <== ledger_aged;
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 <== value;
lottery_checker.value <== v;
// One time signing key used to sign the block proposal and the block
signal input one_time_key_part_one;
signal input one_time_key_part_two;
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;
dummy_one <== one_time_key_part_one * one_time_key_part_one;
dummy_two <== one_time_key_part_two * one_time_key_part_two;
dummy_one <== P_lead_part_one * P_lead_part_one;
dummy_two <== P_lead_part_two * P_lead_part_two;
signal output entropy_contrib;
signal output entropy_contribution; // This is rho_lead
// Check that the note is unspent
//First check selectors are indeed bits
for(var i = 0; i < 32; i++){
latest_selectors[i] * (1 - latest_selectors[i]) === 0;
noteid_latest_selectors[i] * (1 - noteid_latest_selectors[i]) === 0;
}
//Then check the note id is in the latest ledger state
component unspent_membership = proof_of_membership(32);
for(var i = 0; i < 32; i++){
unspent_membership.nodes[i] <== latest_nodes[i];
unspent_membership.selector[i] <== latest_selectors[i];
unspent_membership.nodes[i] <== noteid_latest_path[i];
unspent_membership.selector[i] <== noteid_latest_selectors[i];
}
unspent_membership.root <== latest_root;
unspent_membership.root <== ledger_latest;
unspent_membership.leaf <== lottery_checker.note_identifier;
lottery_checker.out * unspent_membership.out === 1;
@ -254,12 +254,12 @@ template proof_of_leadership(secret_depth){
// Compute the entropy contribution
component entropy = derive_entropy();
entropy.slot <== slot;
entropy.slot <== sl;
entropy.note_id <== lottery_checker.note_identifier;
entropy.secret_key <== lottery_checker.secret_key;
entropy_contrib <== entropy.out;
entropy_contribution <== entropy.out;
}
component main {public [slot,epoch_nonce,t0,t1,aged_root,latest_root,one_time_key_part_one,one_time_key_part_two]}= proof_of_leadership(25);
//component main {public [sl,epoch_nonce,t0,t1,ledger_aged,ledger_latest,P_lead_part_one,P_lead_part_two]}= proof_of_leadership(25);

View File

@ -31,9 +31,9 @@ template derive_reward_voucher(){
template proof_of_claim(){
signal input secret_voucher;
signal input merkle_nodes[32];
signal input selectors[32];
signal input attached_data;
signal input voucher_merkle_path[32];
signal input voucher_merkle_path_selectors[32];
signal input mantle_tx_hash;
signal input voucher_root;
signal output voucher_nullifier;
@ -45,13 +45,13 @@ template proof_of_claim(){
//Check reward voucher membership
//First check selectors are indeed bits
for(var i = 0; i < 32; i++){
selectors[i] * (1 - selectors[i]) === 0;
voucher_merkle_path_selectors[i] * (1 - voucher_merkle_path_selectors[i]) === 0;
}
//Then check the proof of membership
component reward_membership = proof_of_membership(32);
for(var i = 0; i < 32; i++){
reward_membership.nodes[i] <== merkle_nodes[i];
reward_membership.selector[i] <== selectors[i];
reward_membership.nodes[i] <== voucher_merkle_path[i];
reward_membership.selector[i] <== voucher_merkle_path_selectors[i];
}
reward_membership.root <== voucher_root;
reward_membership.leaf <== reward_voucher.out;
@ -68,7 +68,7 @@ template proof_of_claim(){
// dummy constraint to avoid unused public input to be erased after compilation optimisation
signal dummy;
dummy <== attached_data * attached_data;
dummy <== mantle_tx_hash * mantle_tx_hash;
}
component main {public [voucher_root,attached_data]}= proof_of_claim();
component main {public [voucher_root,mantle_tx_hash]}= proof_of_claim();

View File

@ -5,22 +5,20 @@ include "../ledger/notes.circom";
include "../misc/constants.circom";
template zkSignature(maxInput){
signal input secret_key[maxInput];
signal input attached_data;
signal output public_key[maxInput];
signal input secret_keys[maxInput];
signal input msg;
signal output public_keys[maxInput];
component pk[maxInput];
for(var i =0; i<maxInput; i++){
pk[i] = derive_public_key();
pk[i].secret_key <== secret_key[i];
public_key[i] <== pk[i].out;
pk[i].secret_key <== secret_keys[i];
public_keys[i] <== pk[i].out;
}
// dummy constraint to avoid unused public input to be erased after compilation optimisation
signal dummy;
dummy <== attached_data * attached_data;
dummy <== msg * msg;
}
component main {public [attached_data]}= zkSignature(32);
component main {public [msg]}= zkSignature(32);

View File

@ -1,5 +1,5 @@
//
pragma circom 2.0.0;
pragma circom 2.1.9;
include "poseidon2_sponge.circom";

View File

@ -1,5 +1,5 @@
//
pragma circom 2.0.0;
pragma circom 2.1.9;
//
// The Poseidon2 permutation for bn128 and t=3

View File

@ -1,5 +1,5 @@
//
pragma circom 2.0.0;
pragma circom 2.1.9;
include "poseidon2_perm.circom";