115 lines
3.0 KiB
Python
Raw Normal View History

2024-05-20 20:00:03 +05:30
from dataclasses import dataclass
2024-05-27 18:58:45 +04:00
from crypto import Field, Point, prf
from constraints import Constraint
2024-05-20 20:00:03 +05:30
@dataclass
2024-05-27 18:58:45 +04:00
class NoteCommitment:
cm: Field
blinding: Field
zero: Field
2024-05-20 20:00:03 +05:30
@dataclass
class Nullifier:
nf: bytes
2024-05-27 18:58:45 +04:00
def nf_pk(nf_sk) -> Field:
return prf("CL_NOTE_NF", nf_sk)
2024-05-20 20:00:03 +05:30
2024-05-27 18:58:45 +04:00
@dataclass(unsafe_hash=True)
class InnerNote:
value: Field
unit: str
birth_constraint: Constraint
death_constraints: list[Constraint]
state: Field
nonce: Field
rand: Field # source of randomness for note commitment
def r(self, index: int):
prf("CL_NOTE_COMM_RAND", self.rand, index)
def verify_value(self) -> bool:
return 0 <= self.value and value <= 2**64
@property
def fungibility_domain(self) -> Field:
"""The fungibility domain of this note"""
return crypto.prf(
"CL_NOTE_NULL", self.birth_constraint.hash(), *crypto.str_to_vec(unit)
2024-05-20 20:00:03 +05:30
)
2024-05-27 18:58:45 +04:00
def death_constraints_root(self) -> Field:
"""
Returns the merkle root over the set of death constraints
"""
return crypto.merkle_root(self.death_constraints)
2024-05-20 20:00:03 +05:30
2024-05-27 18:58:45 +04:00
@dataclass(unsafe_hash=True)
2024-05-20 20:00:03 +05:30
class PublicNote:
note: InnerNote
2024-05-27 18:58:45 +04:00
nf_pk: Field
def blinding(self, rand: Field) -> Field:
"""Blinding factor used in balance commitments"""
return prf("CL_NOTE_BAL_BLIND", rand, self.nonce, self.nf_pk)
2024-05-20 20:00:03 +05:30
2024-05-27 18:58:45 +04:00
def commit(self) -> Field:
# blinding factors between data elems ensure no information is leaked in merkle paths
return crypto.merkle_root(
self.note.r(0),
2024-05-20 20:00:03 +05:30
self.note.birth_constraint.hash(),
2024-05-27 18:58:45 +04:00
self.note.r(1),
2024-05-20 20:00:03 +05:30
self.note.death_constraints_root(),
2024-05-27 18:58:45 +04:00
self.note.r(2),
2024-05-20 20:00:03 +05:30
self.note.value,
2024-05-27 18:58:45 +04:00
self.note.r(3),
2024-05-20 20:00:03 +05:30
self.note.unit,
2024-05-27 18:58:45 +04:00
self.note.r(4),
2024-05-20 20:00:03 +05:30
self.note.state,
2024-05-27 18:58:45 +04:00
self.note.r(5),
2024-05-20 20:00:03 +05:30
self.note.nonce,
2024-05-27 18:58:45 +04:00
self.note.r(6),
2024-05-20 20:00:03 +05:30
self.nf_pk,
)
2024-05-27 18:58:45 +04:00
@dataclass(unsafe_hash=True)
class SecretNote:
note: InnerNote
nf_sk: Field
2024-05-20 20:00:03 +05:30
2024-05-27 18:58:45 +04:00
def to_public_note(self) -> PublicNote:
return PublicNote(note=self.note, nf_pk=nf_pk(self.nf_sk))
def nullifier(self):
2024-05-20 20:00:03 +05:30
"""
2024-05-27 18:58:45 +04:00
The nullifier that must be provided when spending this note along
with a proof that the nf_sk used to compute the nullifier corresponds
to the nf_pk in the public note commitment.
2024-05-20 20:00:03 +05:30
"""
2024-05-27 18:58:45 +04:00
return prf("NULLIFIER", self.nonce, self.nf_sk)
def balance(self, rand):
"""
Returns the pederson commitment to the notes value.
"""
return crypto.pederson_commit(
self.note.value, self.blinding(rand), self.note.fungibility_domain
)
def zero(self, rand):
"""
Returns the pederson commitment to zero using the same blinding as the balance
commitment.
"""
return crypto.pederson_commit(
0, self.blinding(rand), self.note.fungibility_domain
)