Add Orchard commitments
HomomorphicPedersenCommit -> ValueCommit SinsemillaCommit -> NoteCommit SinsemillaShortCommit -> CommitIvk
This commit is contained in:
parent
bd7c367590
commit
72cae20b61
|
@ -0,0 +1,73 @@
|
|||
#!/usr/bin/env python3
|
||||
import sys; assert sys.version_info[0] >= 3, "Python 3 required."
|
||||
|
||||
from orchard_group_hash import group_hash
|
||||
from orchard_pallas import Fp, Scalar
|
||||
from orchard_sinsemilla import sinsemilla_hash_to_point
|
||||
from sapling_utils import i2lebsp
|
||||
|
||||
# Commitment schemes used in Orchard https://zips.z.cash/protocol/nu5.pdf#concretecommit
|
||||
|
||||
# https://zips.z.cash/protocol/nu5.pdf#constants
|
||||
L_ORCHARD_BASE = 255
|
||||
|
||||
# https://zips.z.cash/protocol/nu5.pdf#concretehomomorphiccommit
|
||||
def homomorphic_pedersen_commitment(rcv: Scalar, D, v: Scalar):
|
||||
return group_hash(D, b"v") * v + group_hash(D, b"r") * rcv
|
||||
|
||||
def value_commit(rcv: Scalar, v: Scalar):
|
||||
return homomorphic_pedersen_commitment(rcv, b"z.cash:Orchard-cv", v)
|
||||
|
||||
def rcv_trapdoor(randbytes):
|
||||
return Scalar.random(randbytes)
|
||||
|
||||
# https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit
|
||||
def sinsemilla_commit(r: Scalar, D, M):
|
||||
return sinsemilla_hash_to_point(D + b"-M", M).checked_incomplete_add(
|
||||
r * group_hash(D + b"-r", "")
|
||||
)
|
||||
|
||||
def sinsemilla_short_commit(r: Scalar, D, M):
|
||||
return sinsemilla_commit(r, D, M).extract()
|
||||
|
||||
# https://zips.z.cash/protocol/nu5.pdf#concreteorchardnotecommit
|
||||
def note_commit(rcm, g_d, pk_d, v, rho, psi):
|
||||
return sinsemilla_commit(
|
||||
rcm,
|
||||
"z.cash: Orchard-NoteCommit",
|
||||
g_d + pk_d + i2lebsp(64, v) + i2lebsp(L_ORCHARD_BASE, rho) + i2lebsp(L_ORCHARD_BASE, psi)
|
||||
)
|
||||
|
||||
def rcm_trapdoor(randbytes):
|
||||
return Scalar.random(randbytes)
|
||||
|
||||
# https://zips.z.cash/protocol/nu5.pdf#concreteorchardnotecommit
|
||||
def commit_ivk(rivk, ak, nk):
|
||||
return sinsemilla_short_commit(
|
||||
rivk,
|
||||
"z.cash: Orchard-CommitIvk",
|
||||
i2lebsp(L_ORCHARD_BASE, ak) + i2lebsp(L_ORCHARD_BASE, nk)
|
||||
)
|
||||
|
||||
def rivk_trapdoor(randbytes):
|
||||
return Scalar.random(randbytes)
|
||||
|
||||
# Test consistency of ValueCommit^{Orchard} with precomputed generators
|
||||
def test_value_commit():
|
||||
from random import Random
|
||||
from orchard_generators import VALUE_COMMITMENT_RANDOMNESS_BASE, VALUE_COMMITMENT_VALUE_BASE
|
||||
|
||||
rng = Random(0xabad533d)
|
||||
def randbytes(l):
|
||||
ret = []
|
||||
while len(ret) < l:
|
||||
ret.append(rng.randrange(0, 256))
|
||||
return bytes(ret)
|
||||
|
||||
rcv = rcv_trapdoor(randbytes)
|
||||
v = Scalar(100000000)
|
||||
|
||||
assert value_commit(rcv, v) == VALUE_COMMITMENT_RANDOMNESS_BASE * rcv + VALUE_COMMITMENT_VALUE_BASE * v
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_value_commit()
|
|
@ -31,6 +31,9 @@ class Fp(FieldElement):
|
|||
def from_bytes(buf):
|
||||
return Fp(leos2ip(buf), strict=True)
|
||||
|
||||
def random(randbytes):
|
||||
return Fp(leos2ip(randbytes(32)), strict=False)
|
||||
|
||||
def __init__(self, s, strict=False):
|
||||
FieldElement.__init__(self, Fp, s, p, strict=strict)
|
||||
|
||||
|
@ -90,6 +93,13 @@ class Scalar(FieldElement):
|
|||
def __str__(self):
|
||||
return 'Scalar(%s)' % self.s
|
||||
|
||||
@staticmethod
|
||||
def from_bytes(buf):
|
||||
return Scalar(leos2ip(buf), strict=True)
|
||||
|
||||
def random(randbytes):
|
||||
return Scalar(leos2ip(randbytes(32)), strict=False)
|
||||
|
||||
Fp.ZERO = Fp(0)
|
||||
Fp.ONE = Fp(1)
|
||||
Fp.MINUS_ONE = Fp(-1)
|
||||
|
|
Loading…
Reference in New Issue