diff --git a/coordination-layer/balance_commitment.py b/coordination-layer/balance_commitment.py new file mode 100644 index 0000000..8ff08f8 --- /dev/null +++ b/coordination-layer/balance_commitment.py @@ -0,0 +1,20 @@ +""" +This module holds the logic for building and verifying homomorphic balance commitments. +""" + +from constraints import Constraint +from crypto import Field, Point, prf, hash_to_curve, pederson_commit, _str_to_vec + + +def balance_commitment(value: Field, blinding: Field, unit: Point): + return pederson_commit(value, blinding, unit) + + +def fungibility_domain(unit: str, birth_cm: Field) -> Point: + """The fungibility domain of this note""" + return hash_to_curve("CL_NOTE_NULL", birth_cm, *_str_to_vec(unit)) + + +def blinding(tx_rand: Field, nf_pk: Field) -> Field: + """Blinding factor used in balance commitments""" + return prf("CL_NOTE_BAL_BLIND", tx_rand, nf_pk) diff --git a/coordination-layer/crypto.py b/coordination-layer/crypto.py index 2b40a6f..af6ca29 100644 --- a/coordination-layer/crypto.py +++ b/coordination-layer/crypto.py @@ -1,3 +1,4 @@ +from py_ecc import bn128 from keum import grumpkin import poseidon @@ -5,8 +6,11 @@ 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 +# Point = grumpkin.AffineWeierstrass +# Field = grumpkin.Fq + +Point = bn128.FQ +Field = bn128.Point2D[FQ] def fake_algebraic_hash(data) -> Field: diff --git a/coordination-layer/note.py b/coordination-layer/note.py index f148657..3d73158 100644 --- a/coordination-layer/note.py +++ b/coordination-layer/note.py @@ -76,7 +76,7 @@ class InnerNote: return prf("CL_NOTE_COMM_RAND", self.rand, index) @property - def fungibility_domain(self) -> Field: + def fungibility_domain(self) -> Point: """The fungibility domain of this note""" return hash_to_curve( "CL_NOTE_NULL", self.birth_constraint.hash(), *_str_to_vec(self.unit) diff --git a/coordination-layer/notes.org b/coordination-layer/notes.org index c463464..1e247d0 100644 --- a/coordination-layer/notes.org +++ b/coordination-layer/notes.org @@ -1,5 +1,57 @@ * Open Issues +** Do we need both Public, Secret and Inner Note? + +Can't we simply have a Note (currently InnerNote) and the partial transaction will introduce +a wrapper over the Note struct that will have the extra fields necessary for using notes within +a transaction system: + +#+begin_src python + + + # ----- note.py ----- + + @dataclass(unsafe_hash=True) + class Note: + value: Field + unit: str + birth_constraint: Constraint + death_constraints: list[Constraint] + state: Field + nonce: Field + rand: Field + + def verify_death(self, death_cm: Field, death_proof: Proof) -> bool: + pass + + def verify_birth(self, birth_proof: Proof) -> bool: + pass + + def verify_value(self) -> bool: + pass + + def fungibility_domain(self) -> Field: + pass + + # ----- partial_transaction.py ----- + + @dataclass + class InputNote: + note: Note + nullifier: Note + death_cm: Field + death_proof: Proof + balance_cm: Point + + @dataclass + class OutputNote: + note: PublicNote + birth_proof: Proof + balance_cm: Point + +#+end_src + + ** provided commitment to zero may removing the blinding of the pederson commitment Since you can subtract the randomness from the commitment to get just the binding part. diff --git a/coordination-layer/test_balance_commitment.py b/coordination-layer/test_balance_commitment.py new file mode 100644 index 0000000..97e14db --- /dev/null +++ b/coordination-layer/test_balance_commitment.py @@ -0,0 +1,30 @@ +from unittest import TestCase + +from hypothesis import example, given, settings, strategies as st + +from crypto import Field, hash_to_curve +from balance_commitment import balance_commitment + + +@st.composite +def field(draw): + x = draw(st.integers(min_value=0, max_value=Field.ORDER - 1)) + return Field(x) + + +@st.composite +def point(draw): + x = draw(field()) + return hash_to_curve("T", x) + + +class TestBalanceCommitment(TestCase): + @given(r=field(), a=field(), b=field(), unit=point()) + @settings(max_examples=3) + def test_value_additive(self, r, a, b, unit): + print(r, a, b, unit) + b1 = balance_commitment(r, a, unit) + b2 = balance_commitment(r, b, unit) + b3 = balance_commitment(r, a + b, unit) + + assert b1 + b2 == b3 diff --git a/requirements.txt b/requirements.txt index e26da00..bd9bf31 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,3 +12,4 @@ 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 +hypothesis==6.103.0