mirror of
https://github.com/logos-co/nomos-specs.git
synced 2025-02-02 10:34:50 +00:00
wip: executable spec
This commit is contained in:
parent
211a543513
commit
fd007c6625
8
coordination-layer/constraint.py
Normal file
8
coordination-layer/constraint.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Constraint:
|
||||||
|
|
||||||
|
def hash(self) -> bytes:
|
||||||
|
raise NotImplementedError()
|
71
coordination-layer/crypto.py
Normal file
71
coordination-layer/crypto.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
from keum import grumpkin
|
||||||
|
import poseidon
|
||||||
|
|
||||||
|
|
||||||
|
# !Important! The crypto primitives here must be in agreement with the proving system
|
||||||
|
# E.g. if you are using noir with the Barretenberg, we must use the Grumpkin curve.
|
||||||
|
|
||||||
|
Point = grumpkin.AffineWeierstrass
|
||||||
|
Field = grumpkin.Fq
|
||||||
|
|
||||||
|
|
||||||
|
def poseidon_grumpkin_field():
|
||||||
|
# TODO: These parameters are made up.
|
||||||
|
# return poseidon.Poseidon(
|
||||||
|
# p=Field.ORDER,
|
||||||
|
# security_level=128,
|
||||||
|
# alpha=5,
|
||||||
|
# input_rate=3,
|
||||||
|
# t=9,
|
||||||
|
# )
|
||||||
|
h, _ = poseidon.case_simple()
|
||||||
|
|
||||||
|
# TODO: this is a hack to make poseidon take in arbitrary input length.
|
||||||
|
# Fix is to implement a sponge as described in section 2.1 of
|
||||||
|
# https://eprint.iacr.org/2019/458.pdf
|
||||||
|
def inner(data):
|
||||||
|
digest = 0
|
||||||
|
for i in range(0, len(data), h.input_rate - 1):
|
||||||
|
digest = h.run_hash([digest, *data[i : i + h.input_rate - 1]])
|
||||||
|
return digest
|
||||||
|
|
||||||
|
return inner
|
||||||
|
|
||||||
|
|
||||||
|
POSEIDON = poseidon_grumpkin_field()
|
||||||
|
|
||||||
|
|
||||||
|
def prf(domain, *elements):
|
||||||
|
return POSEIDON(str_to_vec(domain) + elements)
|
||||||
|
|
||||||
|
|
||||||
|
def comm(*elements):
|
||||||
|
"""
|
||||||
|
Returns a commitment to the sequence of elements.
|
||||||
|
|
||||||
|
The commitmtent can be opened at index 0..len(elements)
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
def merkle_root(data) -> Field:
|
||||||
|
data = _pad_to_power_of_2(data)
|
||||||
|
nodes = [CRH(d) for d in data]
|
||||||
|
while len(nodes) > 1:
|
||||||
|
nodes = [CRH(nodes[i], nodes[i + 1]) for i in range(0, len(nodes), 2)]
|
||||||
|
|
||||||
|
return nodes[0]
|
||||||
|
|
||||||
|
|
||||||
|
def _pad_to_power_of_2(data):
|
||||||
|
import math
|
||||||
|
|
||||||
|
max_lower_bound = int(math.log2(len(data)))
|
||||||
|
if 2**max_lower_bound == len(data):
|
||||||
|
return data
|
||||||
|
to_pad = 2 ** (max_lower_bound + 1) - len(data)
|
||||||
|
return data + [0] * to_pad
|
||||||
|
|
||||||
|
|
||||||
|
def _str_to_vec(s):
|
||||||
|
return list(map(ord, s))
|
59
coordination-layer/note.py
Normal file
59
coordination-layer/note.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
from crypto import Field, Point
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Commitment:
|
||||||
|
cm: bytes
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Nullifier:
|
||||||
|
nf: bytes
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SecretNote:
|
||||||
|
note: InnerNote
|
||||||
|
nf_sk: Field
|
||||||
|
|
||||||
|
def to_public_note(self) -> PublicNote:
|
||||||
|
return PublicNote(
|
||||||
|
note=self.note,
|
||||||
|
nf_pk=Point.generator().mul(self.nf_sk),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class PublicNote:
|
||||||
|
note: InnerNote
|
||||||
|
nf_pk: Point
|
||||||
|
|
||||||
|
def commit(self) -> Commitment:
|
||||||
|
return crypto.COMM(
|
||||||
|
self.note.birth_constraint.hash(),
|
||||||
|
self.note.death_constraints_root(),
|
||||||
|
self.note.value,
|
||||||
|
self.note.unit,
|
||||||
|
self.note.state,
|
||||||
|
self.note.nonce,
|
||||||
|
self.nf_pk,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class InnerNote:
|
||||||
|
value: Field
|
||||||
|
unit: str
|
||||||
|
birth_constraint: Constraint
|
||||||
|
death_constraints: set[Constraint]
|
||||||
|
state: Field
|
||||||
|
nonce: Field
|
||||||
|
rand: Field
|
||||||
|
|
||||||
|
def death_constraints_root(self) -> Field:
|
||||||
|
"""
|
||||||
|
Returns the merkle root over the set of death constraints
|
||||||
|
"""
|
||||||
|
return crypto.merkle_root(self.death_constraints)
|
23
coordination-layer/state.py
Normal file
23
coordination-layer/state.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
"""
|
||||||
|
This module maintains the state of the CL.
|
||||||
|
|
||||||
|
Namely we are interested in:
|
||||||
|
- the set of note commitments
|
||||||
|
- the set of note nullifiers (spent notes)
|
||||||
|
- the set of constraints
|
||||||
|
"""
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
import note
|
||||||
|
import constraint
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class State:
|
||||||
|
commitments: set[note.Commitment]
|
||||||
|
nullifiers: set[note.Nullifier]
|
||||||
|
constraints: dict[bytes, constraint.Constraint]
|
||||||
|
|
||||||
|
def add_constraint(self, c: constraint.Constraint):
|
||||||
|
self.constraints[c.hash()] = c
|
@ -7,6 +7,8 @@ pysphinx==0.0.1
|
|||||||
scipy==1.11.4
|
scipy==1.11.4
|
||||||
black==23.12.1
|
black==23.12.1
|
||||||
sympy==1.12
|
sympy==1.12
|
||||||
sh==2.0.6
|
sh==2.0.6 # used for shelling out to noir
|
||||||
toml==0.10.2
|
toml==0.10.2 # used for noir
|
||||||
portalocker==2.8.2
|
portalocker==2.8.2 # portable file locking
|
||||||
|
keum==0.2.0 # for CL's use of more obscure curves
|
||||||
|
poseidon-hash==0.1.4 # used as the algebraic hash in CL
|
||||||
|
Loading…
x
Reference in New Issue
Block a user