wip: executable spec
This commit is contained in:
parent
211a543513
commit
fd007c6625
|
@ -0,0 +1,8 @@
|
|||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class Constraint:
|
||||
|
||||
def hash(self) -> bytes:
|
||||
raise NotImplementedError()
|
|
@ -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))
|
|
@ -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)
|
|
@ -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
|
||||
black==23.12.1
|
||||
sympy==1.12
|
||||
sh==2.0.6
|
||||
toml==0.10.2
|
||||
portalocker==2.8.2
|
||||
sh==2.0.6 # used for shelling out to noir
|
||||
toml==0.10.2 # used for noir
|
||||
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…
Reference in New Issue