wip: executable spec

This commit is contained in:
David Rusu 2024-05-20 20:00:03 +05:30
parent 211a543513
commit fd007c6625
5 changed files with 166 additions and 3 deletions

View File

@ -0,0 +1,8 @@
from dataclasses import dataclass
@dataclass
class Constraint:
def hash(self) -> bytes:
raise NotImplementedError()

View 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))

View 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)

View 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

View File

@ -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