From 72cae20b61d38735af4092ea95152bd15366b404 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Mon, 3 May 2021 14:26:44 +0800 Subject: [PATCH] Add Orchard commitments HomomorphicPedersenCommit -> ValueCommit SinsemillaCommit -> NoteCommit SinsemillaShortCommit -> CommitIvk --- orchard_commitments.py | 73 ++++++++++++++++++++++++++++++++++++++++++ orchard_pallas.py | 10 ++++++ 2 files changed, 83 insertions(+) create mode 100644 orchard_commitments.py diff --git a/orchard_commitments.py b/orchard_commitments.py new file mode 100644 index 0000000..288d0dd --- /dev/null +++ b/orchard_commitments.py @@ -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() diff --git a/orchard_pallas.py b/orchard_pallas.py index 29d5ad3..fe89954 100644 --- a/orchard_pallas.py +++ b/orchard_pallas.py @@ -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)