Compare commits

...

8 Commits
v0.2.0 ... main

Author SHA1 Message Date
Antonio
678ea4e75e
Merge pull request #9 from logos-blockchain/aa/change-circuits-output
chore: rename nomos to logos-blockchain
2026-01-20 11:12:23 +01:00
Antonio Antonino
0b9ad0bdb6
Rename nomos to logos-blockchain 2026-01-19 14:54:26 +01:00
thomaslavaur
0b0054a57b
Merge pull request #7 from logos-blockchain/tl/PoL_update
Tl/po l update
2026-01-15 13:15:36 +01:00
thomaslavaur
e84e7f801c fix misspelling 2026-01-15 12:42:36 +01:00
thomaslavaur
6aa15f2bd7 remove protection against adaptive adversaries and update DSTs 2026-01-15 12:39:41 +01:00
thomaslavaur
0674fa2ac0 reflect nomos-pocs change on the circuits (add compression to nullifier, public keys and reward voucher) 2025-11-18 08:26:15 +01:00
thomaslavaur
8a9590b892
Merge pull request #6 from logos-co/tl/poseidon_optimization
reflect nomos-pocs changes in circuits
2025-11-17 14:37:44 +01:00
thomaslavaur
d0891d80a7 reflect nomos-pocs changes in circuits 2025-11-17 14:36:39 +01:00
15 changed files with 73 additions and 366 deletions

View File

@ -326,7 +326,7 @@ jobs:
- name: Create Unified Release Bundle - name: Create Unified Release Bundle
env: env:
BUNDLE_NAME: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }} BUNDLE_NAME: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}
run: | run: |
# Create the bundle directory structure # Create the bundle directory structure
mkdir -p "${BUNDLE_NAME}"/{pol,poq,zksign,poc} mkdir -p "${BUNDLE_NAME}"/{pol,poq,zksign,poc}
@ -374,8 +374,8 @@ jobs:
- name: Upload Unified Release Bundle - name: Upload Unified Release Bundle
uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8 uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8
with: with:
name: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz name: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz
path: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz path: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz
build-windows: build-windows:
name: Build Windows Binaries (Native) name: Build Windows Binaries (Native)
@ -605,7 +605,7 @@ jobs:
- name: Create Unified Release Bundle - name: Create Unified Release Bundle
shell: msys2 {0} shell: msys2 {0}
env: env:
BUNDLE_NAME: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }} BUNDLE_NAME: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}
run: | run: |
# Create the bundle directory structure # Create the bundle directory structure
mkdir -p "${BUNDLE_NAME}"/{pol,poq,zksign,poc} mkdir -p "${BUNDLE_NAME}"/{pol,poq,zksign,poc}
@ -645,8 +645,8 @@ jobs:
- name: Upload Unified Release Bundle - name: Upload Unified Release Bundle
uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8 uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8
with: with:
name: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz name: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz
path: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz path: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz
build-macos: build-macos:
name: Build MacOS Binaries (Native) name: Build MacOS Binaries (Native)
@ -831,7 +831,7 @@ jobs:
- name: Create Unified Release Bundle - name: Create Unified Release Bundle
env: env:
BUNDLE_NAME: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }} BUNDLE_NAME: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}
run: | run: |
# Create the bundle directory structure # Create the bundle directory structure
mkdir -p "${BUNDLE_NAME}"/{pol,poq,zksign,poc} mkdir -p "${BUNDLE_NAME}"/{pol,poq,zksign,poc}
@ -879,8 +879,8 @@ jobs:
- name: Upload Unified Release Bundle - name: Upload Unified Release Bundle
uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8 uses: actions/upload-artifact@de65e23aa2b7e23d713bb51fbfcb6d502f8667d8
with: with:
name: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz name: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz
path: nomos-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz path: logos-blockchain-circuits-${{ env.VERSION }}-${{ env.OS }}-${{ env.ARCH }}.tar.gz
publish-release: publish-release:
name: Create Release name: Create Release
@ -943,7 +943,7 @@ jobs:
arch: x86_64 arch: x86_64
env: env:
UPLOAD_URL: ${{ needs.publish-release.outputs.upload_url }} UPLOAD_URL: ${{ needs.publish-release.outputs.upload_url }}
ARTIFACT_NAME: nomos-circuits-${{ needs.setup.outputs.version }}-${{ matrix.platform.os }}-${{ matrix.platform.arch }}.tar.gz ARTIFACT_NAME: logos-blockchain-circuits-${{ needs.setup.outputs.version }}-${{ matrix.platform.os }}-${{ matrix.platform.arch }}.tar.gz
steps: steps:
- name: Download Unified Bundle - name: Download Unified Bundle
uses: actions/download-artifact@448e3f862ab3ef47aa50ff917776823c9946035b uses: actions/download-artifact@448e3f862ab3ef47aa50ff917776823c9946035b

View File

@ -1,6 +1,6 @@
# Contributor's Guide # Contributor's Guide
## Triggering a New Release for Nomos Circuits ## Triggering a New Release for Logos Blockchain Circuits
To trigger a release build: To trigger a release build:
@ -18,14 +18,14 @@ Each release includes a single unified bundle per platform:
For each supported platform (Linux x86_64, macOS aarch64, Windows x86_64): For each supported platform (Linux x86_64, macOS aarch64, Windows x86_64):
- **`nomos-circuits-{version}-{os}-{arch}.tar.gz`** - **`logos-blockchain-circuits-{version}-{os}-{arch}.tar.gz`**
A complete bundle containing all components needed to generate and verify proofs for all circuits. A complete bundle containing all components needed to generate and verify proofs for all circuits.
**Bundle Structure:** **Bundle Structure:**
``` ```
nomos-circuits-{version}-{os}-{arch}/ logos-blockchain-circuits-{version}-{os}-{arch}/
├── VERSION ├── VERSION
├── prover[.exe] ├── prover[.exe]
├── verifier[.exe] ├── verifier[.exe]
@ -87,5 +87,5 @@ Once everything looks good:
- Uncheck **“This is a pre-release.”** - Uncheck **“This is a pre-release.”**
- Publish the release (removing the Draft state). - Publish the release (removing the Draft state).
> ⚡ **Important:** Nomos builds will only pick up the new circuits once the release is published as **Latest** (i.e. not marked as draft or pre-release). > ⚡ **Important:** Logos Blockchain builds will only pick up the new circuits once the release is published as **Latest** (i.e. not marked as draft or pre-release).

View File

@ -1 +1 @@
# Nomos Circuits # Logos Blockchain Circuits

View File

@ -155,7 +155,7 @@ def Permutation(inp):
return state return state
def Compression(inp): def Compression(inp):
return Permutation([inp[0],inp[1],F(0)]) return Permutation([inp[0],inp[1],F(0)])[0]
def PoseidonSponge(data, capacity, output_len): def PoseidonSponge(data, capacity, output_len):
rate = 3 - capacity; rate = 3 - capacity;
@ -221,16 +221,16 @@ if not core_or_leader in [0,1]:
# 1) Corenode registry Merkleproof # 1) Corenode registry Merkleproof
# pick a random core_sk and derive its public key # pick a random core_sk and derive its public key
core_sk = F(randrange(0,p,1)) core_sk = F(randrange(0,p,1))
pk_core = poseidon2_hash([ F(1296193216988918402894), core_sk ]) pk_core = Compression([ F(4605003), core_sk ])
core_selectors = randrange(0,2**20,1) core_selectors = randrange(0,2**20,1)
core_selectors = format(int(core_selectors),'020b') core_selectors = format(int(core_selectors),'020b')
core_nodes = [F(randrange(0,p,1)) for i in range(20)] core_nodes = [F(randrange(0,p,1)) for i in range(20)]
core_root = pk_core core_root = pk_core
for i in range(20): for i in range(20):
if int(core_selectors[19-i]) == 0: if int(core_selectors[19-i]) == 0:
core_root = poseidon2_hash([core_root,core_nodes[i]]) core_root = Compression([core_root,core_nodes[i]])
else: else:
core_root = poseidon2_hash([core_nodes[i],core_root]) core_root = Compression([core_nodes[i],core_root])
#pk_root, core_path, core_selectors = merkle_root_and_path(pk_core, 20) #pk_root, core_path, core_selectors = merkle_root_and_path(pk_core, 20)
@ -247,30 +247,18 @@ t1 = F(p- (int(t1_constant) // total_stake**2))
value = F(total_stake / 100) value = F(total_stake / 100)
threshold = (t0 + t1 * value) * value threshold = (t0 + t1 * value) * value
starting_slot = randrange(max(0,slot_number-2**25+1),slot_number,1)
slot_secret = F(randrange(0,p,1))
slot_secret_indexes = format(int(slot_number - starting_slot),'025b')
sk = F(randrange(0,p,1))
tx_hash = F(randrange(0,p,1)) tx_hash = F(randrange(0,p,1))
output_number = F(randrange(0,50,1)) output_number = F(randrange(0,50,1))
pk = Compression([F(4605003),sk])
slot_secret_path = [F(randrange(0,p,1)) for i in range(25)] note_id = poseidon2_hash([F(232989242343357190262606),tx_hash,output_number,value,pk])
secret_root = slot_secret
for i in range(25):
if int(slot_secret_indexes[24-i]) == 0:
secret_root = poseidon2_hash([secret_root,slot_secret_path[i]])
else:
secret_root = poseidon2_hash([slot_secret_path[i],secret_root])
sk = poseidon2_hash([F(256174383281726064679014503048630094),starting_slot,secret_root])
pk = poseidon2_hash([F(1296193216988918402894),sk])
note_id = poseidon2_hash([F(65580641562429851895355409762135920462),tx_hash,output_number,value,pk])
ticket = poseidon2_hash([F(13887241025832268),F(epoch_nonce),F(slot_number),note_id,sk]) ticket = poseidon2_hash([F(13887241025832268),F(epoch_nonce),F(slot_number),note_id,sk])
while(ticket > threshold): while(ticket > threshold):
output_number += 1 output_number += 1
note_id = poseidon2_hash([F(65580641562429851895355409762135920462),tx_hash,output_number,value,pk]) note_id = poseidon2_hash([F(232989242343357190262606),tx_hash,output_number,value,pk])
ticket = poseidon2_hash([F(13887241025832268),F(epoch_nonce),F(slot_number),note_id,sk]) ticket = poseidon2_hash([F(13887241025832268),F(epoch_nonce),F(slot_number),note_id,sk])
aged_nodes = [F(randrange(0,p,1)) for i in range(32)] aged_nodes = [F(randrange(0,p,1)) for i in range(32)]
@ -279,9 +267,9 @@ aged_selectors = format(aged_selectors,'032b')
aged_root = note_id aged_root = note_id
for i in range(32): for i in range(32):
if int(aged_selectors[31-i]) == 0: if int(aged_selectors[31-i]) == 0:
aged_root = poseidon2_hash([aged_root,aged_nodes[i]]) aged_root = Compression([aged_root,aged_nodes[i]])
else: else:
aged_root = poseidon2_hash([aged_nodes[i],aged_root]) aged_root = Compression([aged_nodes[i],aged_root])
# 3) Choose branch & index # 3) Choose branch & index
index = randrange(0, Ql if core_or_leader else Qc,1) index = randrange(0, Ql if core_or_leader else Qc,1)
@ -308,13 +296,11 @@ inp = {
"pol_epoch_nonce": str(epoch_nonce), "pol_epoch_nonce": str(epoch_nonce),
"pol_t0": str(t0), "pol_t0": str(t0),
"pol_t1": str(t1), "pol_t1": str(t1),
"pol_slot_secret": str(slot_secret), "pol_secret_key": str(sk),
"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": [str(x) for x in aged_nodes],
"pol_noteid_path_selectors": [str(x) for x in aged_selectors], "pol_noteid_path_selectors": [str(x) for x in aged_selectors],
"pol_note_tx_hash": str(tx_hash), "pol_note_tx_hash": str(tx_hash),
"pol_note_output_number": str(output_number), "pol_note_output_number": str(output_number),
"pol_sk_starting_slot": str(starting_slot),
"pol_note_value": str(value) "pol_note_value": str(value)
} }

View File

@ -2,7 +2,7 @@
pragma circom 2.1.9; pragma circom 2.1.9;
include "../hash_bn/poseidon2_hash.circom"; include "../hash_bn/poseidon2_hash.circom";
include "../misc/constants.circom"; // defines NOMOS_KDF, SELECTION_RANDOMNESS, PROOF_NULLIFIER include "../misc/constants.circom"; // defines KDF, SELECTION_RANDOMNESS, PROOF_NULLIFIER
include "../misc/comparator.circom"; include "../misc/comparator.circom";
include "../circomlib/circuits/bitify.circom"; include "../circomlib/circuits/bitify.circom";
include "../mantle/pol_lib.circom"; // defines proof_of_leadership include "../mantle/pol_lib.circom"; // defines proof_of_leadership
@ -48,15 +48,13 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
signal input pol_epoch_nonce; signal input pol_epoch_nonce;
signal input pol_t0; signal input pol_t0;
signal input pol_t1; signal input pol_t1;
signal input pol_slot_secret;
signal input pol_slot_secret_path[nLevelsPol];
signal input pol_noteid_path[32]; signal input pol_noteid_path[32];
signal input pol_noteid_path_selectors[32]; signal input pol_noteid_path_selectors[32];
signal input pol_secret_key;
signal input pol_note_tx_hash; signal input pol_note_tx_hash;
signal input pol_note_output_number; signal input pol_note_output_number;
signal input pol_sk_starting_slot;
signal input pol_note_value; signal input pol_note_value;
@ -96,10 +94,6 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
would_win.epoch_nonce <== pol_epoch_nonce; would_win.epoch_nonce <== pol_epoch_nonce;
would_win.t0 <== pol_t0; would_win.t0 <== pol_t0;
would_win.t1 <== pol_t1; 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] <== pol_slot_secret_path[i];
}
for (var i = 0; i < 32; i++) { for (var i = 0; i < 32; i++) {
would_win.aged_nodes[i] <== pol_noteid_path[i]; would_win.aged_nodes[i] <== pol_noteid_path[i];
would_win.aged_selectors[i] <== pol_noteid_path_selectors[i]; would_win.aged_selectors[i] <== pol_noteid_path_selectors[i];
@ -107,7 +101,7 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
would_win.aged_root <== pol_ledger_aged; would_win.aged_root <== pol_ledger_aged;
would_win.transaction_hash <== pol_note_tx_hash; would_win.transaction_hash <== pol_note_tx_hash;
would_win.output_number <== pol_note_output_number; would_win.output_number <== pol_note_output_number;
would_win.starting_slot <== pol_sk_starting_slot; would_win.secret_key <== pol_secret_key;
would_win.value <== pol_note_value; would_win.value <== pol_note_value;
// Enforce the selected role is correct // Enforce the selected role is correct
@ -125,7 +119,7 @@ template ProofOfQuota(nLevelsPK, nLevelsPol, bitsQuota) {
// Derive key_nullifier // Derive key_nullifier
component nf = Poseidon2_hash(2); component nf = Compression();
component dstNF = KEY_NULLIFIER_V1(); component dstNF = KEY_NULLIFIER_V1();
nf.inp[0] <== dstNF.out; nf.inp[0] <== dstNF.out;
nf.inp[1] <== selection_randomness.out; nf.inp[1] <== selection_randomness.out;

View File

@ -1,7 +1,7 @@
//test //test
pragma circom 2.1.9; pragma circom 2.1.9;
include "../hash_bn/poseidon2_hash.circom"; include "../hash_bn/poseidon2_perm.circom";
include "../circomlib/circuits/comparators.circom"; include "../circomlib/circuits/comparators.circom";
// compute a merkle root of depth n // compute a merkle root of depth n
@ -15,12 +15,12 @@ template compute_merkle_root(n) {
component compression_hash[n]; component compression_hash[n];
compression_hash[0] = Poseidon2_hash(2); compression_hash[0] = Compression();
compression_hash[0].inp[0] <== leaf - selector[n-1] * (leaf - nodes[0]); compression_hash[0].inp[0] <== leaf - selector[n-1] * (leaf - nodes[0]);
compression_hash[0].inp[1] <== nodes[0] - selector[n-1] * (nodes[0] - leaf); compression_hash[0].inp[1] <== nodes[0] - selector[n-1] * (nodes[0] - leaf);
for(var i=1; i<n; i++){ for(var i=1; i<n; i++){
compression_hash[i] = Poseidon2_hash(2); compression_hash[i] = Compression();
compression_hash[i].inp[0] <== compression_hash[i-1].out - selector[n-1-i] * (compression_hash[i-1].out - nodes[i]); compression_hash[i].inp[0] <== compression_hash[i-1].out - selector[n-1-i] * (compression_hash[i-1].out - nodes[i]);
compression_hash[i].inp[1] <== nodes[i] - selector[n-1-i] * (nodes[i] - compression_hash[i-1].out); compression_hash[i].inp[1] <== nodes[i] - selector[n-1-i] * (nodes[i] - compression_hash[i-1].out);
} }

View File

@ -214,4 +214,3 @@ template Compression() {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -2,28 +2,15 @@
pragma circom 2.1.9; pragma circom 2.1.9;
include "../hash_bn/poseidon2_hash.circom"; include "../hash_bn/poseidon2_hash.circom";
include "../hash_bn/poseidon2_perm.circom";
include "../misc/constants.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(){ template derive_public_key(){
signal input secret_key; signal input secret_key;
signal output out; signal output out;
component hash = Poseidon2_hash(2); component hash = Compression();
component dst = NOMOS_KDF(); component dst = KDF();
hash.inp[0] <== dst.out; hash.inp[0] <== dst.out;
hash.inp[1] <== secret_key; hash.inp[1] <== secret_key;
out <== hash.out; out <== hash.out;

View File

@ -155,7 +155,7 @@ def Permutation(inp):
return state return state
def Compression(inp): def Compression(inp):
return Permutation([inp[0],inp[1],F(0)]) return Permutation([inp[0],inp[1],F(0)])[0]
def PoseidonSponge(data, capacity, output_len): def PoseidonSponge(data, capacity, output_len):
rate = 3 - capacity; rate = 3 - capacity;
@ -228,30 +228,17 @@ t1 = F(p- (int(t1_constant) // total_stake**2))
value = F(total_stake / 100) value = F(total_stake / 100)
threshold = (t0 + t1 * value) * value threshold = (t0 + t1 * value) * value
starting_slot = randrange(max(0,slot_number-2**25+1),slot_number,1)
slot_secret = F(randrange(0,p,1))
slot_secret_indexes = format(int(slot_number - starting_slot),'025b')
sk = F(randrange(0,p,1))
tx_hash = F(randrange(0,p,1)) tx_hash = F(randrange(0,p,1))
output_number = F(randrange(0,50,1)) output_number = F(randrange(0,50,1))
pk = Compression([F(4605003),sk])
note_id = poseidon2_hash([F(232989242343357190262606),tx_hash,output_number,value,pk])
slot_secret_path = [F(randrange(0,p,1)) for i in range(25)]
secret_root = slot_secret
for i in range(25):
if int(slot_secret_indexes[24-i]) == 0:
secret_root = poseidon2_hash([secret_root,slot_secret_path[i]])
else:
secret_root = poseidon2_hash([slot_secret_path[i],secret_root])
sk = poseidon2_hash([F(256174383281726064679014503048630094),starting_slot,secret_root])
pk = poseidon2_hash([F(1296193216988918402894),sk])
note_id = poseidon2_hash([F(65580641562429851895355409762135920462),tx_hash,output_number,value,pk])
ticket = poseidon2_hash([F(13887241025832268),F(epoch_nonce),F(slot_number),note_id,sk]) ticket = poseidon2_hash([F(13887241025832268),F(epoch_nonce),F(slot_number),note_id,sk])
while(ticket > threshold): while(ticket > threshold):
output_number += 1 output_number += 1
note_id = poseidon2_hash([F(65580641562429851895355409762135920462),tx_hash,output_number,value,pk]) note_id = poseidon2_hash([F(232989242343357190262606),tx_hash,output_number,value,pk])
ticket = poseidon2_hash([F(13887241025832268),F(epoch_nonce),F(slot_number),note_id,sk]) ticket = poseidon2_hash([F(13887241025832268),F(epoch_nonce),F(slot_number),note_id,sk])
aged_nodes = [F(randrange(0,p,1)) for i in range(32)] aged_nodes = [F(randrange(0,p,1)) for i in range(32)]
@ -260,9 +247,9 @@ aged_selectors = format(aged_selectors,'032b')
aged_root = note_id aged_root = note_id
for i in range(32): for i in range(32):
if int(aged_selectors[31-i]) == 0: if int(aged_selectors[31-i]) == 0:
aged_root = poseidon2_hash([aged_root,aged_nodes[i]]) aged_root = Compression([aged_root,aged_nodes[i]])
else: else:
aged_root = poseidon2_hash([aged_nodes[i],aged_root]) aged_root = Compression([aged_nodes[i],aged_root])
unspent_nodes = [F(randrange(0,p,1)) for i in range(32)] unspent_nodes = [F(randrange(0,p,1)) for i in range(32)]
unspent_selectors = randrange(0,2**32,1) unspent_selectors = randrange(0,2**32,1)
@ -271,9 +258,9 @@ unspent_selectors = format(unspent_selectors,'032b')
latest_root = note_id latest_root = note_id
for i in range(32): for i in range(32):
if int(unspent_selectors[31-i]) == 0: if int(unspent_selectors[31-i]) == 0:
latest_root = poseidon2_hash([latest_root,unspent_nodes[i]]) latest_root = Compression([latest_root,unspent_nodes[i]])
else: else:
latest_root = poseidon2_hash([unspent_nodes[i],latest_root]) latest_root = Compression([unspent_nodes[i],latest_root])
@ -284,10 +271,9 @@ inp = {
"epoch_nonce": str(epoch_nonce), "epoch_nonce": str(epoch_nonce),
"t0": str(t0), "t0": str(t0),
"t1": str(t1), "t1": str(t1),
"slot_secret": str(slot_secret), "secret_key": str(sk),
"P_lead_part_one": str(F(123456)), "P_lead_part_one": str(F(123456)),
"P_lead_part_two": str(F(654321)), "P_lead_part_two": str(F(654321)),
"slot_secret_path": [str(x) for x in slot_secret_path],
"noteid_aged_path": [str(x) for x in aged_nodes], "noteid_aged_path": [str(x) for x in aged_nodes],
"noteid_aged_selectors": [str(x) for x in aged_selectors], "noteid_aged_selectors": [str(x) for x in aged_selectors],
"ledger_aged": str(aged_root), "ledger_aged": str(aged_root),
@ -296,7 +282,6 @@ inp = {
"noteid_latest_path": [str(x) for x in unspent_nodes], "noteid_latest_path": [str(x) for x in unspent_nodes],
"noteid_latest_selectors": [str(x) for x in unspent_selectors], "noteid_latest_selectors": [str(x) for x in unspent_selectors],
"ledger_latest": str(latest_root), "ledger_latest": str(latest_root),
"starting_slot": str(starting_slot),
"v": str(value) "v": str(value)
} }

View File

@ -156,7 +156,7 @@ def Permutation(inp):
return state return state
def Compression(inp): def Compression(inp):
return Permutation([inp[0],inp[1],F(0)]) return Permutation([inp[0],inp[1],F(0)])[0]
def PoseidonSponge(data, capacity, output_len): def PoseidonSponge(data, capacity, output_len):
rate = 3 - capacity; rate = 3 - capacity;
@ -208,7 +208,7 @@ def PoseidonSponge(data, capacity, output_len):
secret_voucher = F(randrange(0,p,1)) secret_voucher = F(randrange(0,p,1))
reward_voucher = poseidon2_hash([F(1668646695034522932676805048878418),secret_voucher]) reward_voucher = Compression([F(1668646695034522932676805048878418),secret_voucher])
merkle_nodes = [F(randrange(0,p,1)) for i in range(32)] merkle_nodes = [F(randrange(0,p,1)) for i in range(32)]
selectors = randrange(0,2**32,1) selectors = randrange(0,2**32,1)
@ -216,9 +216,9 @@ selectors = format(selectors,'032b')
voucher_root = reward_voucher voucher_root = reward_voucher
for i in range(32): for i in range(32):
if int(selectors[31-i]) == 0: if int(selectors[31-i]) == 0:
voucher_root = poseidon2_hash([voucher_root,merkle_nodes[i]]) voucher_root = Compression([voucher_root,merkle_nodes[i]])
else: else:
voucher_root = poseidon2_hash([merkle_nodes[i],voucher_root]) voucher_root = Compression([merkle_nodes[i],voucher_root])
data_msg = F(randrange(0,p,1)) data_msg = F(randrange(0,p,1))

View File

@ -7,203 +7,6 @@ from sage.all import *
p = 21888242871839275222246405745257275088548364400416034343698204186575808495617 p = 21888242871839275222246405745257275088548364400416034343698204186575808495617
F = FiniteField(p) F = FiniteField(p)
def poseidon2_hash(data):
return PoseidonSponge(data,2,1)[0]
def Poseidon2_sponge_hash_rate_1(data, n):
return PoseidonSponge(data,3,2,n,1)
def Poseidon2_sponge_hash_rate_2(data, n):
return PoseidonSponge(data,3,1,n,1)
def SBox(inp):
return inp**5
def InternalRound(inp, i):
round_consts = [
0x1a1d063e54b1e764b63e1855bff015b8cedd192f47308731499573f23597d4b5,
0x26abc66f3fdf8e68839d10956259063708235dccc1aa3793b91b002c5b257c37,
0x0c7c64a9d887385381a578cfed5aed370754427aabca92a70b3c2b12ff4d7be8,
0x1cf5998769e9fab79e17f0b6d08b2d1eba2ebac30dc386b0edd383831354b495,
0x0f5e3a8566be31b7564ca60461e9e08b19828764a9669bc17aba0b97e66b0109,
0x18df6a9d19ea90d895e60e4db0794a01f359a53a180b7d4b42bf3d7a531c976e,
0x04f7bf2c5c0538ac6e4b782c3c6e601ad0ea1d3a3b9d25ef4e324055fa3123dc,
0x29c76ce22255206e3c40058523748531e770c0584aa2328ce55d54628b89ebe6,
0x198d425a45b78e85c053659ab4347f5d65b1b8e9c6108dbe00e0e945dbc5ff15,
0x25ee27ab6296cd5e6af3cc79c598a1daa7ff7f6878b3c49d49d3a9a90c3fdf74,
0x138ea8e0af41a1e024561001c0b6eb1505845d7d0c55b1b2c0f88687a96d1381,
0x306197fb3fab671ef6e7c2cba2eefd0e42851b5b9811f2ca4013370a01d95687,
0x1a0c7d52dc32a4432b66f0b4894d4f1a21db7565e5b4250486419eaf00e8f620,
0x2b46b418de80915f3ff86a8e5c8bdfccebfbe5f55163cd6caa52997da2c54a9f,
0x12d3e0dc0085873701f8b777b9673af9613a1af5db48e05bfb46e312b5829f64,
0x263390cf74dc3a8870f5002ed21d089ffb2bf768230f648dba338a5cb19b3a1f,
0x0a14f33a5fe668a60ac884b4ca607ad0f8abb5af40f96f1d7d543db52b003dcd,
0x28ead9c586513eab1a5e86509d68b2da27be3a4f01171a1dd847df829bc683b9,
0x1c6ab1c328c3c6430972031f1bdb2ac9888f0ea1abe71cffea16cda6e1a7416c,
0x1fc7e71bc0b819792b2500239f7f8de04f6decd608cb98a932346015c5b42c94,
0x03e107eb3a42b2ece380e0d860298f17c0c1e197c952650ee6dd85b93a0ddaa8,
0x2d354a251f381a4669c0d52bf88b772c46452ca57c08697f454505f6941d78cd,
0x094af88ab05d94baf687ef14bc566d1c522551d61606eda3d14b4606826f794b,
0x19705b783bf3d2dc19bcaeabf02f8ca5e1ab5b6f2e3195a9d52b2d249d1396f7,
0x09bf4acc3a8bce3f1fcc33fee54fc5b28723b16b7d740a3e60cef6852271200e,
0x1803f8200db6013c50f83c0c8fab62843413732f301f7058543a073f3f3b5e4e,
0x0f80afb5046244de30595b160b8d1f38bf6fb02d4454c0add41f7fef2faf3e5c,
0x126ee1f8504f15c3d77f0088c1cfc964abcfcf643f4a6fea7dc3f98219529d78,
0x23c203d10cfcc60f69bfb3d919552ca10ffb4ee63175ddf8ef86f991d7d0a591,
0x2a2ae15d8b143709ec0d09705fa3a6303dec1ee4eec2cf747c5a339f7744fb94,
0x07b60dee586ed6ef47e5c381ab6343ecc3d3b3006cb461bbb6b5d89081970b2b,
0x27316b559be3edfd885d95c494c1ae3d8a98a320baa7d152132cfe583c9311bd,
0x1d5c49ba157c32b8d8937cb2d3f84311ef834cc2a743ed662f5f9af0c0342e76,
0x2f8b124e78163b2f332774e0b850b5ec09c01bf6979938f67c24bd5940968488,
0x1e6843a5457416b6dc5b7aa09a9ce21b1d4cba6554e51d84665f75260113b3d5,
0x11cdf00a35f650c55fca25c9929c8ad9a68daf9ac6a189ab1f5bc79f21641d4b,
0x21632de3d3bbc5e42ef36e588158d6d4608b2815c77355b7e82b5b9b7eb560bc,
0x0de625758452efbd97b27025fbd245e0255ae48ef2a329e449d7b5c51c18498a,
0x2ad253c053e75213e2febfd4d976cc01dd9e1e1c6f0fb6b09b09546ba0838098,
0x1d6b169ed63872dc6ec7681ec39b3be93dd49cdd13c813b7d35702e38d60b077,
0x1660b740a143664bb9127c4941b67fed0be3ea70a24d5568c3a54e706cfef7fe,
0x0065a92d1de81f34114f4ca2deef76e0ceacdddb12cf879096a29f10376ccbfe,
0x1f11f065202535987367f823da7d672c353ebe2ccbc4869bcf30d50a5871040d,
0x26596f5c5dd5a5d1b437ce7b14a2c3dd3bd1d1a39b6759ba110852d17df0693e,
0x16f49bc727e45a2f7bf3056efcf8b6d38539c4163a5f1e706743db15af91860f,
0x1abe1deb45b3e3119954175efb331bf4568feaf7ea8b3dc5e1a4e7438dd39e5f,
0x0e426ccab66984d1d8993a74ca548b779f5db92aaec5f102020d34aea15fba59,
0x0e7c30c2e2e8957f4933bd1942053f1f0071684b902d534fa841924303f6a6c6,
0x0812a017ca92cf0a1622708fc7edff1d6166ded6e3528ead4c76e1f31d3fc69d,
0x21a5ade3df2bc1b5bba949d1db96040068afe5026edd7a9c2e276b47cf010d54,
0x01f3035463816c84ad711bf1a058c6c6bd101945f50e5afe72b1a5233f8749ce,
0x0b115572f038c0e2028c2aafc2d06a5e8bf2f9398dbd0fdf4dcaa82b0f0c1c8b,
0x1c38ec0b99b62fd4f0ef255543f50d2e27fc24db42bc910a3460613b6ef59e2f,
0x1c89c6d9666272e8425c3ff1f4ac737b2f5d314606a297d4b1d0b254d880c53e,
0x03326e643580356bf6d44008ae4c042a21ad4880097a5eb38b71e2311bb88f8f,
0x268076b0054fb73f67cee9ea0e51e3ad50f27a6434b5dceb5bdde2299910a4c9,
]
sb = SBox(inp[0] + round_consts[i])
out = [F(0) for i in range(3)]
out[0] = 2*sb + inp[1] + inp[2];
out[1] = sb + 2*inp[1] + inp[2];
out[2] = sb + inp[1] + 3*inp[2];
return out
def ExternalRound(inp, i):
out = [F(0) for j in range(3)]
round_consts = [ [F(0x1d066a255517b7fd8bddd3a93f7804ef7f8fcde48bb4c37a59a09a1a97052816)
, F(0x29daefb55f6f2dc6ac3f089cebcc6120b7c6fef31367b68eb7238547d32c1610)
, F(0x1f2cb1624a78ee001ecbd88ad959d7012572d76f08ec5c4f9e8b7ad7b0b4e1d1)
]
, [ F(0x0aad2e79f15735f2bd77c0ed3d14aa27b11f092a53bbc6e1db0672ded84f31e5)
, F(0x2252624f8617738cd6f661dd4094375f37028a98f1dece66091ccf1595b43f28)
, F(0x1a24913a928b38485a65a84a291da1ff91c20626524b2b87d49f4f2c9018d735)
]
, [ F(0x22fc468f1759b74d7bfc427b5f11ebb10a41515ddff497b14fd6dae1508fc47a)
, F(0x1059ca787f1f89ed9cd026e9c9ca107ae61956ff0b4121d5efd65515617f6e4d)
, F(0x02be9473358461d8f61f3536d877de982123011f0bf6f155a45cbbfae8b981ce)
]
, [ F(0x0ec96c8e32962d462778a749c82ed623aba9b669ac5b8736a1ff3a441a5084a4)
, F(0x292f906e073677405442d9553c45fa3f5a47a7cdb8c99f9648fb2e4d814df57e)
, F(0x274982444157b86726c11b9a0f5e39a5cc611160a394ea460c63f0b2ffe5657e)
]
, [ F(0x1acd63c67fbc9ab1626ed93491bda32e5da18ea9d8e4f10178d04aa6f8747ad0)
, F(0x19f8a5d670e8ab66c4e3144be58ef6901bf93375e2323ec3ca8c86cd2a28b5a5)
, F(0x1c0dc443519ad7a86efa40d2df10a011068193ea51f6c92ae1cfbb5f7b9b6893)
]
, [ F(0x14b39e7aa4068dbe50fe7190e421dc19fbeab33cb4f6a2c4180e4c3224987d3d)
, F(0x1d449b71bd826ec58f28c63ea6c561b7b820fc519f01f021afb1e35e28b0795e)
, F(0x1ea2c9a89baaddbb60fa97fe60fe9d8e89de141689d1252276524dc0a9e987fc)
]
, [ F(0x0478d66d43535a8cb57e9c1c3d6a2bd7591f9a46a0e9c058134d5cefdb3c7ff1)
, F(0x19272db71eece6a6f608f3b2717f9cd2662e26ad86c400b21cde5e4a7b00bebe)
, F(0x14226537335cab33c749c746f09208abb2dd1bd66a87ef75039be846af134166)
]
, [ F(0x01fd6af15956294f9dfe38c0d976a088b21c21e4a1c2e823f912f44961f9a9ce)
, F(0x18e5abedd626ec307bca190b8b2cab1aaee2e62ed229ba5a5ad8518d4e5f2a57)
, F(0x0fc1bbceba0590f5abbdffa6d3b35e3297c021a3a409926d0e2d54dc1c84fda6)
]]
sb = [F(0) for j in range(3)]
for j in range(3):
sb[j] = SBox(F(inp[j] + round_consts[i][j]))
out = [F(0) for j in range(3)]
out[0] = 2*sb[0] + sb[1] + sb[2]
out[1] = sb[0] + 2*sb[1] + sb[2]
out[2] = sb[0]+ sb[1] + 2*sb[2]
return out
def LinearLayer(inp):
out = [F(0) for i in range(3)]
out[0] = 2*inp[0] + inp[1] + inp[2]
out[1] = inp[0] + 2*inp[1] + inp[2]
out[2] = inp[0] + inp[1] + 2*inp[2]
return out
def Permutation(inp):
out = [F(0) for i in range(3)]
state = LinearLayer(inp)
for k in range(4):
state = ExternalRound(state, k)
for k in range(56):
state = InternalRound(state, k)
for k in range(4):
state = ExternalRound(state, k+4)
return state
def Compression(inp):
return Permutation([inp[0],inp[1],F(0)])
def PoseidonSponge(data, capacity, output_len):
rate = 3 - capacity;
output = [F(0) for i in range(output_len)]
assert( capacity > 0 )
assert( rate > 0 )
assert( capacity < 3 )
assert( rate < 3 )
# round up to rate the input + 1 field element ("10*" padding)
nblocks = ((len(data) + 1) + (rate-1)) // rate;
nout = (output_len + (rate-1)) // rate;
padded_len = nblocks * rate;
padded = []
for i in range(len(data)):
padded.append(F(data[i]))
padded.append(F(1))
for i in range(len(data)+1,padded_len):
padded.append(F(0))
civ = F(0)
state = [F(0),F(0),F(civ)]
sorbed = [F(0) for j in range(rate)]
for m in range(nblocks):
for i in range(rate):
a = state[i]
b = padded[m*rate+i]
sorbed[i] = a + b
state = Permutation(sorbed[0:rate] + state[rate:3])
q = min(rate, output_len)
for i in range(q):
output[i] = state[i]
out_ptr = rate
for n in range(1,nout):
state[nblocks+n] = Permutation(state[nblocks+n-1])
q = min(rate, output_len-out_ptr)
for i in range(q):
output[out_ptr+i] = state[nblocks+n][i]
out_ptr += rate
return output
if len(sys.argv) != Integer(2): if len(sys.argv) != Integer(2):
print("Usage: <script> <number of input>") print("Usage: <script> <number of input>")
exit() exit()

View File

@ -9,7 +9,7 @@ template derive_voucher_nullifier(){
signal input secret_voucher; signal input secret_voucher;
signal output out; signal output out;
component hash = Poseidon2_hash(2); component hash = Compression();
component dst = VOUCHER_NF(); component dst = VOUCHER_NF();
hash.inp[0] <== dst.out; hash.inp[0] <== dst.out;
hash.inp[1] <== secret_voucher; hash.inp[1] <== secret_voucher;
@ -21,7 +21,7 @@ template derive_reward_voucher(){
signal input secret_voucher; signal input secret_voucher;
signal output out; signal output out;
component hash = Poseidon2_hash(2); component hash = Compression( );
component dst = REWARD_VOUCHER(); component dst = REWARD_VOUCHER();
hash.inp[0] <== dst.out; hash.inp[0] <== dst.out;
hash.inp[1] <== secret_voucher; hash.inp[1] <== secret_voucher;

View File

@ -1,3 +1,4 @@
//
pragma circom 2.1.9; pragma circom 2.1.9;
include "pol_lib.circom"; include "pol_lib.circom";

View File

@ -34,7 +34,7 @@ template derive_entropy(){
signal output out; signal output out;
component hash = Poseidon2_hash(4); component hash = Poseidon2_hash(4);
component dst = NOMOS_NONCE_CONTRIB_V1(); component dst = NONCE_CONTRIB_V1();
hash.inp[0] <== dst.out; hash.inp[0] <== dst.out;
hash.inp[1] <== slot; hash.inp[1] <== slot;
hash.inp[2] <== note_id; hash.inp[2] <== note_id;
@ -48,8 +48,6 @@ template would_win_leadership(secret_depth){
signal input epoch_nonce; signal input epoch_nonce;
signal input t0; signal input t0;
signal input t1; signal input t1;
signal input slot_secret;
signal input slot_secret_path[secret_depth];
//Part of the note id proof of membership to prove aged //Part of the note id proof of membership to prove aged
signal input aged_nodes[32]; signal input aged_nodes[32];
@ -59,51 +57,23 @@ template would_win_leadership(secret_depth){
//Used to derive the note identifier //Used to derive the note identifier
signal input transaction_hash; signal input transaction_hash;
signal input output_number; signal input output_number;
signal input secret_key;
//Part of the secret key
signal input starting_slot;
// The winning note value // The winning note value
signal input value; signal input value;
signal output out; signal output out;
signal output note_identifier; signal output note_identifier;
signal output secret_key;
// 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 = SafeFullLessThan();
checker.a <== starting_slot;
checker.b <== slot;
// Compute the positions related to slot - starting_slot and make sure slot - starting_slot is a 25 bits number
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.root;
// Derive the public key from the secret key // Derive the public key from the secret key
component pk = derive_public_key(); component pk = derive_public_key();
pk.secret_key <== sk.out; pk.secret_key <== secret_key;
// Derive the note id // Derive the note id
component note_id = Poseidon2_hash(5); component note_id = Poseidon2_hash(5);
component dst_note_id = NOMOS_NOTE_ID_V1(); component dst_note_id = NOTE_ID_V1();
note_id.inp[0] <== dst_note_id.out; note_id.inp[0] <== dst_note_id.out;
note_id.inp[1] <== transaction_hash; note_id.inp[1] <== transaction_hash;
note_id.inp[2] <== output_number; note_id.inp[2] <== output_number;
@ -131,7 +101,7 @@ template would_win_leadership(secret_depth){
ticket.epoch_nonce <== epoch_nonce; ticket.epoch_nonce <== epoch_nonce;
ticket.slot <== slot; ticket.slot <== slot;
ticket.note_id <== note_id.out; ticket.note_id <== note_id.out;
ticket.secret_key <== sk.out; ticket.secret_key <== secret_key;
// Compute the lottery threshold // Compute the lottery threshold
@ -147,12 +117,9 @@ template would_win_leadership(secret_depth){
winning.b <== threshold; winning.b <== threshold;
// Check that every constraint holds // Check that every constraint holds
signal intermediate_out; out <== aged_membership.out * winning.out;
intermediate_out <== aged_membership.out * winning.out;
out <== intermediate_out * checker.out;
note_identifier <== note_id.out; note_identifier <== note_id.out;
secret_key <== sk.out;
} }
@ -161,8 +128,6 @@ template proof_of_leadership(secret_depth){
signal input epoch_nonce; // the epoch nonce eta signal input epoch_nonce; // the epoch nonce eta
signal input t0; signal input t0;
signal input t1; signal input t1;
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 //Part of the note id proof of membership to prove aged
signal input noteid_aged_path[32]; signal input noteid_aged_path[32];
@ -170,6 +135,7 @@ template proof_of_leadership(secret_depth){
signal input ledger_aged; signal input ledger_aged;
//Used to derive the note identifier //Used to derive the note identifier
signal input secret_key;
signal input note_tx_hash; signal input note_tx_hash;
signal input note_output_number; signal input note_output_number;
@ -178,10 +144,7 @@ template proof_of_leadership(secret_depth){
signal input noteid_latest_selectors[32]; // must be bits signal input noteid_latest_selectors[32]; // must be bits
signal input ledger_latest; signal input ledger_latest;
//Part of the secret key // The winning note.
signal input starting_slot;
// The winning note. The unit is supposed to be NMO and the ZoneID is MANTLE
signal input v; // value of the note signal input v; // value of the note
@ -191,10 +154,6 @@ template proof_of_leadership(secret_depth){
lottery_checker.epoch_nonce <== epoch_nonce; lottery_checker.epoch_nonce <== epoch_nonce;
lottery_checker.t0 <== t0; lottery_checker.t0 <== t0;
lottery_checker.t1 <== t1; lottery_checker.t1 <== t1;
lottery_checker.slot_secret <== slot_secret;
for(var i = 0; i < secret_depth; i++){
lottery_checker.slot_secret_path[i] <== slot_secret_path[i];
}
for(var i = 0; i < 32; i++){ for(var i = 0; i < 32; i++){
lottery_checker.aged_nodes[i] <== noteid_aged_path[i]; lottery_checker.aged_nodes[i] <== noteid_aged_path[i];
lottery_checker.aged_selectors[i] <== noteid_aged_selectors[i]; lottery_checker.aged_selectors[i] <== noteid_aged_selectors[i];
@ -202,7 +161,7 @@ template proof_of_leadership(secret_depth){
lottery_checker.aged_root <== ledger_aged; lottery_checker.aged_root <== ledger_aged;
lottery_checker.transaction_hash <== note_tx_hash; lottery_checker.transaction_hash <== note_tx_hash;
lottery_checker.output_number <== note_output_number; lottery_checker.output_number <== note_output_number;
lottery_checker.starting_slot <== starting_slot; lottery_checker.secret_key <== secret_key;
lottery_checker.value <== v; lottery_checker.value <== v;
@ -241,7 +200,7 @@ template proof_of_leadership(secret_depth){
component entropy = derive_entropy(); component entropy = derive_entropy();
entropy.slot <== sl; entropy.slot <== sl;
entropy.note_id <== lottery_checker.note_identifier; entropy.note_id <== lottery_checker.note_identifier;
entropy.secret_key <== lottery_checker.secret_key; entropy.secret_key <== secret_key;
entropy_contribution <== entropy.out; entropy_contribution <== entropy.out;
} }

View File

@ -11,31 +11,24 @@ template LEAD_V1(){
} }
// int.from_bytes(b"NOMOS_POL_SK_V1", byteorder="little") = 256174383281726064679014503048630094 // int.from_bytes(b"NONCE_CONTRIB_V1", byteorder="little") = 65580641403957881555985426713123114830
template NOMOS_POL_SK_V1(){ template NONCE_CONTRIB_V1(){
signal output out; signal output out;
out <== 256174383281726064679014503048630094; out <== 65580641403957881555985426713123114830;
} }
// int.from_bytes(b"NOMOS_NONCE_CONTRIB_V1", byteorder="little") = 18459309511848927313552932915476467038165525790019406 // int.from_bytes(b"KDF", byteorder="little") = 4605003
template NOMOS_NONCE_CONTRIB_V1(){ template KDF(){
signal output out; signal output out;
out <== 18459309511848927313552932915476467038165525790019406; out <== 4605003;
} }
// int.from_bytes(b"NOMOS_KDF", byteorder="little") = 1296193216988918402894 // int.from_bytes(b"NOTE_ID_V1", byteorder="little") = 232989242343357190262606
template NOMOS_KDF(){ template NOTE_ID_V1(){
signal output out; signal output out;
out <== 1296193216988918402894; out <== 232989242343357190262606;
}
// int.from_bytes(b"NOMOS_NOTE_ID_V1", byteorder="little") = 65580641562429851895355409762135920462
template NOMOS_NOTE_ID_V1(){
signal output out;
out <== 65580641562429851895355409762135920462;
} }