From 11b9d06357e6861c7837b21885b8dab43ffb4bad Mon Sep 17 00:00:00 2001 From: thomaslavaur Date: Thu, 10 Apr 2025 10:40:20 +0200 Subject: [PATCH] edit pol with the new shielded and unshielded notes --- .../Mantle/generate_inputs_for_pol.py | 118 ++++++++---------- circom_circuits/Mantle/pol.circom | 44 ++++--- circom_circuits/misc/constants.circom | 6 + 3 files changed, 90 insertions(+), 78 deletions(-) diff --git a/circom_circuits/Mantle/generate_inputs_for_pol.py b/circom_circuits/Mantle/generate_inputs_for_pol.py index d0e1b1b..f499829 100755 --- a/circom_circuits/Mantle/generate_inputs_for_pol.py +++ b/circom_circuits/Mantle/generate_inputs_for_pol.py @@ -250,40 +250,49 @@ while(ticket > threshold): note_nonce += 1 note_cm = poseidon2_hash([F(181645510297841241569044198526601622686169271532834574969543446901055041748),state,value,unit,note_nonce,pk,F(363778563868520716613768381832117227806204156179492995214325445980623358665)]) ticket = poseidon2_hash([F(137836078329650723736739065075984465408055658421620421917147974048265460598),F(epoch_nonce),F(slot_number),note_cm,sk]) - -cm_aged_nodes = [F(randrange(0,p,1)) for i in range(32)] -cm_aged_selectors = randrange(0,2**32,1) -cm_aged_selectors = format(cm_aged_selectors,'032b') + +tx_hash = F(randrange(0,p,1)) +output_number = F(randrange(0,4,1)) +note_id = poseidon2_hash([F(342101038445105569972307194441697646307927876218883552376182649811837164915),tx_hash,output_number,note_cm]) + +aged_nodes = [F(randrange(0,p,1)) for i in range(32)] +aged_selectors = randrange(0,2**32,1) +aged_selectors = format(aged_selectors,'032b') cm_aged_root = note_cm for i in range(32): - if int(cm_aged_selectors[31-i]) == 0: - cm_aged_root = poseidon2_hash([cm_aged_root,cm_aged_nodes[i]]) + if int(aged_selectors[31-i]) == 0: + cm_aged_root = poseidon2_hash([cm_aged_root,aged_nodes[i]]) else: - cm_aged_root = poseidon2_hash([cm_aged_nodes[i],cm_aged_root]) + cm_aged_root = poseidon2_hash([aged_nodes[i],cm_aged_root]) -cm_unspent_nodes = [F(randrange(0,p,1)) for i in range(32)] -cm_unspent_selectors = randrange(0,2**32,1) -cm_unspent_selectors = format(cm_unspent_selectors,'032b') -cm_unspent_root = note_cm +note_id_aged_root = note_id for i in range(32): - if int(cm_unspent_selectors[31-i]) == 0: - cm_unspent_root = poseidon2_hash([cm_unspent_root,cm_unspent_nodes[i]]) + if int(aged_selectors[31-i]) == 0: + note_id_aged_root = poseidon2_hash([note_id_aged_root,aged_nodes[i]]) else: - cm_unspent_root = poseidon2_hash([cm_unspent_nodes[i],cm_unspent_root]) + note_id_aged_root = poseidon2_hash([aged_nodes[i],note_id_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') + +note_id_unspent_root = note_id +for i in range(32): + if int(unspent_selectors[31-i]) == 0: + note_id_unspent_root = poseidon2_hash([note_id_unspent_root,unspent_nodes[i]]) + else: + note_id_unspent_root = poseidon2_hash([unspent_nodes[i],note_id_unspent_root]) note_nf = poseidon2_hash([F(310945536431723660304787929213143698356852257431717126117833288836338828411),note_cm,sk]) nf_previous = F(randrange(0,note_nf,1)) nf_next = F(randrange(note_nf+1,p,1)) -nf_nodes = [F(randrange(0,p,1)) for i in range(32)] -nf_selectors = randrange(0,2**32,1) -nf_selectors = format(nf_selectors,'032b') nf_root = poseidon2_hash([nf_previous, nf_next]) for i in range(32): - if int(nf_selectors[31-i]) == 0: - nf_root = poseidon2_hash([nf_root,nf_nodes[i]]) + if int(unspent_selectors[31-i]) == 0: + nf_root = poseidon2_hash([nf_root,unspent_nodes[i]]) else: - nf_root = poseidon2_hash([nf_nodes[i],nf_root]) + nf_root = poseidon2_hash([unspent_nodes[i],nf_root]) with open("input.json", "w") as file: file.write('{\n\t"slot":\t\t\t\t\t\t"'+str(slot_number)+'",') @@ -305,66 +314,49 @@ with open("input.json", "w") as file: file.write('],') else: file.write(',') - file.write('\n\t"cm_aged_nodes" :\t\t\t\t\t[') + file.write('\n\t"aged_nodes" :\t\t\t\t\t[') for i in range(32): file.write('"') - file.write(str(cm_aged_nodes[i])) + file.write(str(aged_nodes[i])) file.write('"') if i == 31: file.write('],') else: file.write(',') - file.write('\n\t"cm_aged_selectors" :\t\t\t\t\t[') + file.write('\n\t"aged_selectors" :\t\t\t\t\t[') for i in range(32): file.write('"') - file.write(str(cm_aged_selectors[i])) + file.write(str(aged_selectors[i])) file.write('"') if i == 31: file.write('],') else: file.write(',') file.write('\n\t"commitments_aged_root" :\t\t\t\t"'+str(cm_aged_root)+'",') + file.write('\n\t"note_id_aged_root" :\t\t\t\t"'+str(note_id_aged_root)+'",') + file.write('\n\t"transaction_hash" :\t\t\t\t"'+str(tx_hash)+'",') + file.write('\n\t"output_number" :\t\t\t\t"'+str(output_number)+'",') file.write('\n\t"nf_previous" :\t\t\t\t"'+str(nf_previous)+'",') file.write('\n\t"nf_next" :\t\t\t\t"'+str(nf_next)+'",') - if anonymity == "public": - file.write('\n\t"unspent_nodes" :\t\t\t\t\t[') - for i in range(32): - file.write('"') - file.write(str(cm_unspent_nodes[i])) - file.write('"') - if i == 31: - file.write('],') - else: - file.write(',') - file.write('\n\t"unspent_selectors" :\t\t\t\t\t[') - for i in range(32): - file.write('"') - file.write(str(cm_unspent_selectors[i])) - file.write('"') - if i == 31: - file.write('],') - else: - file.write(',') - file.write('\n\t"cm_unspent_root" :\t\t\t\t"'+str(cm_unspent_root)+'",') - if anonymity == "private": - file.write('\n\t"unspent_nodes" :\t\t\t\t\t[') - for i in range(32): - file.write('"') - file.write(str(nf_nodes[i])) - file.write('"') - if i == 31: - file.write('],') - else: - file.write(',') - file.write('\n\t"unspent_selectors" :\t\t\t\t\t[') - for i in range(32): - file.write('"') - file.write(str(nf_selectors[i])) - file.write('"') - if i == 31: - file.write('],') - else: - file.write(',') + file.write('\n\t"unspent_nodes" :\t\t\t\t\t[') + for i in range(32): + file.write('"') + file.write(str(unspent_nodes[i])) + file.write('"') + if i == 31: + file.write('],') + else: + file.write(',') + file.write('\n\t"unspent_selectors" :\t\t\t\t\t[') + for i in range(32): + file.write('"') + file.write(str(unspent_selectors[i])) + file.write('"') + if i == 31: + file.write('],') + else: + file.write(',') + file.write('\n\t"note_id_unspent_root" :\t\t\t\t"'+str(note_id_unspent_root)+'",') file.write('\n\t"nf_unspent_root" :\t\t\t\t"'+str(nf_root)+'",') file.write('\n\t"starting_slot" :\t\t\t\t"'+str(starting_slot)+'",') file.write('\n\t"secrets_root" :\t\t\t\t"'+str(secret_root)+'",') diff --git a/circom_circuits/Mantle/pol.circom b/circom_circuits/Mantle/pol.circom index 1e157ce..d21b734 100644 --- a/circom_circuits/Mantle/pol.circom +++ b/circom_circuits/Mantle/pol.circom @@ -58,7 +58,7 @@ template derive_entropy(){ template proof_of_leadership(){ - signal input selector; // 0 if the note is private and 1 if the note is public + signal input selector; // 0 if the note is shielded and 1 if the note is unshielded // Check that the selector is indeed a bit selector * (1- selector) === 0; @@ -70,11 +70,17 @@ template proof_of_leadership(){ signal input slot_secret; signal input slot_secret_path[25]; - //Part of the commitment proof of membership to prove aged - signal input cm_aged_nodes[32]; - signal input cm_aged_selectors[32]; // must be bits + //Part of the commitment or note id proof of membership to prove aged + signal input aged_nodes[32]; + signal input aged_selectors[32]; // must be bits signal input commitments_aged_root; + signal input note_id_aged_root; + + //Used to derive the note identifier, it can be dumb inputs if it's a shielded note + signal input transaction_hash; + signal input output_number; + //Part of the nullifer proof of non-membership/commitment proof of membership to prove the note is unspent signal input nf_previous; // Can be mocked and set to any value if selector == 1 as long as previous < nullifier < next @@ -82,7 +88,7 @@ template proof_of_leadership(){ signal input unspent_nodes[32]; signal input unspent_selectors[32]; // must be bits signal input nf_unspent_root; - signal input cm_unspent_root; + signal input note_id_unspent_root; //Part of the secret key signal input starting_slot; @@ -131,19 +137,27 @@ template proof_of_leadership(){ nf.secret_key <== sk.out; + // Derive the note id + component note_id = Poseidon2_hash(4); + component dst_note_id = NOMOS_NOTE_ID(); + note_id.inp[0] <== dst_note_id.out; + note_id.inp[1] <== transaction_hash; + note_id.inp[2] <== output_number; + note_id.inp[3] <== cm.out; + // Check commitment membership (is aged enough) //First check selectors are indeed bits for(var i = 0; i < 32; i++){ - cm_aged_selectors[i] * (1 - cm_aged_selectors[i]) === 0; + aged_selectors[i] * (1 - aged_selectors[i]) === 0; } //Then check the proof of membership - component cm_aged_membership = proof_of_membership(32); + component aged_membership = proof_of_membership(32); for(var i = 0; i < 32; i++){ - cm_aged_membership.nodes[i] <== cm_aged_nodes[i]; - cm_aged_membership.selector[i] <== cm_aged_selectors[i]; + aged_membership.nodes[i] <== aged_nodes[i]; + aged_membership.selector[i] <== aged_selectors[i]; } - cm_aged_membership.root <== commitments_aged_root; - cm_aged_membership.leaf <== cm.out; + aged_membership.root <== (note_id_aged_root - commitments_aged_root) * selector + commitments_aged_root; + aged_membership.leaf <== (note_id.out - cm.out) * selector + cm.out; // Compute the lottery ticket @@ -173,18 +187,18 @@ template proof_of_leadership(){ for(var i = 0; i < 32; i++){ unspent_selectors[i] * (1 - unspent_selectors[i]) === 0; } - //Then check the proof of membership (that the nullifier leaf is in the set or that the commitment is) + //Then check the proof of membership (that the nullifier leaf is in the set or that the note identifier is) component unspent_membership = proof_of_membership(32); for(var i = 0; i < 32; i++){ unspent_membership.nodes[i] <== unspent_nodes[i]; unspent_membership.selector[i] <== unspent_selectors[i]; } - unspent_membership.root <== (cm_unspent_root - nf_unspent_root) * selector + nf_unspent_root; + unspent_membership.root <== (note_id_unspent_root - nf_unspent_root) * selector + nf_unspent_root; //Compute the leaf if it's a private note representing previous nf pointing to next in the IMT component hash = Poseidon2_hash(2); hash.inp[0] <== nf_previous; hash.inp[1] <== nf_next; - unspent_membership.leaf <== (cm.out - hash.out) * selector + hash.out; // the leaf is then either the commitment or the leaf computed before + unspent_membership.leaf <== (note_id.out - hash.out) * selector + hash.out; // the leaf is then either the note identifier or the leaf computed before // Check that nullifier stictly falls between previous and next if the note is private. // If the note is public previous and next can be any values such that previous < nullifier < next @@ -227,4 +241,4 @@ template proof_of_leadership(){ entropy_contrib <== entropy.out; } -component main {public [slot,epoch_nonce,t0,t1,commitments_aged_root,nf_unspent_root,cm_unspent_root,one_time_key]}= proof_of_leadership(); \ No newline at end of file +component main {public [slot,epoch_nonce,t0,t1,commitments_aged_root,note_id_aged_root,nf_unspent_root,note_id_unspent_root,one_time_key]}= proof_of_leadership(); \ No newline at end of file diff --git a/circom_circuits/misc/constants.circom b/circom_circuits/misc/constants.circom index 69b36c2..3fb97e7 100644 --- a/circom_circuits/misc/constants.circom +++ b/circom_circuits/misc/constants.circom @@ -71,4 +71,10 @@ template NOMOS_UNIT(){ template NMO(){ signal output out; out <== 19676183153323264216568033390884511718872104179761154996527087027500271872825; +} + +// int.from_bytes(hashlib.sha256(b"NOMOS_NOTE_ID").digest()[:-1], "little") = 342101038445105569972307194441697646307927876218883552376182649811837164915 +template NOMOS_NOTE_ID(){ + signal output out; + out <== 342101038445105569972307194441697646307927876218883552376182649811837164915; } \ No newline at end of file