Merge pull request #28 from zcash-hackworks/orchard-commitments

Add Orchard commitments
This commit is contained in:
ying tong 2021-05-26 11:38:36 +08:00 committed by GitHub
commit 12a07b4f61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 188 additions and 28 deletions

2
ff1.py
View File

@ -7,7 +7,7 @@ from binascii import unhexlify, hexlify
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from sapling_utils import bebs2ip, i2bebsp, beos2ip, bebs2osp, cldiv
from utils import bebs2ip, i2bebsp, beos2ip, bebs2osp, cldiv
# Morris Dworkin
# NIST Special Publication 800-38G

76
orchard_commitments.py Normal file
View File

@ -0,0 +1,76 @@
#!/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 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(rand):
return Scalar.random(rand)
# https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit
def sinsemilla_commit(r: Scalar, D, M):
assert isinstance(r, Scalar)
return sinsemilla_hash_to_point(D + b"-M", M).checked_incomplete_add(
group_hash(D + b"-r", 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,
b"z.cash:Orchard-NoteCommit",
g_d + pk_d + i2lebsp(64, v) + i2lebsp(L_ORCHARD_BASE, rho.s) + i2lebsp(L_ORCHARD_BASE, psi.s)
)
def rcm_trapdoor(rand):
return Scalar.random(rand)
# https://zips.z.cash/protocol/nu5.pdf#concreteorchardnotecommit
def commit_ivk(rivk: Scalar, ak: Fp, nk: Fp):
return sinsemilla_short_commit(
rivk,
b"z.cash:Orchard-CommitIvk",
i2lebsp(L_ORCHARD_BASE, ak.s) + i2lebsp(L_ORCHARD_BASE, nk.s)
)
def rivk_trapdoor(rand):
return Scalar.random(rand)
# Test consistency of ValueCommit^{Orchard} with precomputed generators
def test_value_commit():
from random import Random
from tv_rand import Rand
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)
rand = Rand(randbytes)
rcv = rcv_trapdoor(rand)
v = Scalar(100000000)
assert value_commit(rcv, v) == VALUE_COMMITMENT_RANDOMNESS_BASE * rcv + VALUE_COMMITMENT_VALUE_BASE * v
if __name__ == '__main__':
test_value_commit()

61
orchard_generators.py Normal file
View File

@ -0,0 +1,61 @@
#!/usr/bin/env python3
import sys; assert sys.version_info[0] >= 3, "Python 3 required."
from pyblake2 import blake2s
from tv_output import render_args, render_tv
from orchard_group_hash import group_hash
from orchard_sinsemilla import sinsemilla_hash_to_point
# https://zips.z.cash/protocol/nu5.pdf#concretespendauthsig
SPENDING_KEY_BASE = group_hash(b'z.cash:Orchard', b'G')
# https://zips.z.cash/protocol/nu5.pdf#commitmentsandnullifiers
NULLIFIER_K_BASE = group_hash(b'z.cash:Orchard', b'K')
# https://zips.z.cash/protocol/nu5.pdf#concretehomomorphiccommit
VALUE_COMMITMENT_VALUE_BASE = group_hash(b'z.cash:Orchard-cv', b'v')
VALUE_COMMITMENT_RANDOMNESS_BASE = group_hash(b'z.cash:Orchard-cv', b'r')
# Used in SinsemillaCommit (https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit)
NOTE_COMMITMENT_BASE = group_hash(b'z.cash:Orchard-NoteCommit-r', b'')
NOTE_COMMITMENT_Q = group_hash(b'z.cash:SinsemillaQ', b'z.cash:Orchard-NoteCommit-M')
# Used in SinsemillaShortCommit (https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit)
IVK_COMMITMENT_BASE = group_hash(b'z.cash:Orchard-CommitIvk-r', b'')
IVK_COMMITMENT_Q = group_hash(b'z.cash:SinsemillaQ', b'z.cash:Orchard-CommitIvk-M')
# Used in SinsemillaHash (https://zips.z.cash/protocol/nu5.pdf#orchardmerklecrh)
MERKLE_CRH_Q = group_hash(b'z.cash:SinsemillaQ', b'z.cash:Orchard-MerkleCRH')
def main():
render_tv(
render_args(),
'orchard_generators',
(
('skb', '[u8; 32]'),
('nkb', '[u8; 32]'),
('vcvb', '[u8; 32]'),
('vcrb', '[u8; 32]'),
('cmb', '[u8; 32]'),
('cmq', '[u8; 32]'),
('ivkb', '[u8; 32]'),
('ivkq', '[u8; 32]'),
('mcq', '[u8; 32]'),
),
{
'skb': bytes(SPENDING_KEY_BASE),
'nkb': bytes(NULLIFIER_K_BASE),
'vcvb': bytes(VALUE_COMMITMENT_VALUE_BASE),
'vcrb': bytes(VALUE_COMMITMENT_RANDOMNESS_BASE),
'cmb': bytes(NOTE_COMMITMENT_BASE),
'cmq': bytes(NOTE_COMMITMENT_Q),
'ivkb': bytes(IVK_COMMITMENT_BASE),
'ivkq': bytes(IVK_COMMITMENT_Q),
'mcq': bytes(MERKLE_CRH_Q),
},
)
if __name__ == '__main__':
main()

View File

@ -8,7 +8,7 @@ import orchard_iso_pallas
from pyblake2 import blake2b
from orchard_pallas import Fp, p, q, PALLAS_B, Point
from orchard_iso_pallas import PALLAS_ISO_B, PALLAS_ISO_A
from sapling_utils import i2beosp, cldiv, beos2ip, i2leosp, lebs2ip
from utils import i2beosp, cldiv, beos2ip, i2leosp, lebs2ip
from tv_output import render_args, render_tv
from tv_rand import Rand
@ -16,7 +16,9 @@ from tv_rand import Rand
def sxor(s1,s2):
return bytes([a ^ b for a,b in zip(s1,s2)])
def expand_message_xmd(msg, dst, len_in_bytes):
def expand_message_xmd(msg: bytes, dst: bytes, len_in_bytes: int):
assert isinstance(msg, bytes)
assert isinstance(dst, bytes)
assert len(dst) <= 255
b_in_bytes = 64 # hash function output size

View File

@ -3,7 +3,7 @@
from orchard_group_hash import map_to_curve_simple_swu
from orchard_iso_pallas import Point as IsoPoint
from orchard_pallas import Fp
from sapling_utils import leos2ip
from utils import leos2ip
from tv_output import render_args, render_tv
from tv_rand import Rand

View File

@ -6,7 +6,7 @@ from binascii import unhexlify
from orchard_pallas import Fp
from orchard_sinsemilla import sinsemilla_hash
from sapling_utils import i2lebsp, leos2bsp
from utils import i2lebsp, leos2bsp
# https://zips.z.cash/protocol/nu5.pdf#constants
MERKLE_DEPTH = 32

View File

@ -3,7 +3,7 @@
import sys; assert sys.version_info[0] >= 3, "Python 3 required."
from sapling_jubjub import FieldElement
from sapling_utils import leos2ip
from utils import leos2ip
p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
@ -31,6 +31,13 @@ class Fp(FieldElement):
def from_bytes(buf):
return Fp(leos2ip(buf), strict=True)
def random(rand):
while True:
try:
return Fp(leos2ip(rand.b(32)), strict=True)
except ValueError:
pass
def __init__(self, s, strict=False):
FieldElement.__init__(self, Fp, s, p, strict=strict)
@ -90,16 +97,29 @@ class Scalar(FieldElement):
def __str__(self):
return 'Scalar(%s)' % self.s
Fp.ZERO = Fp(0)
Fp.ONE = Fp(1)
Fp.MINUS_ONE = Fp(-1)
@staticmethod
def from_bytes(buf):
return Scalar(leos2ip(buf), strict=True)
assert Fp.ZERO + Fp.ZERO == Fp.ZERO
assert Fp.ZERO + Fp.ONE == Fp.ONE
assert Fp.ONE + Fp.ZERO == Fp.ONE
assert Fp.ZERO - Fp.ONE == Fp.MINUS_ONE
assert Fp.ZERO * Fp.ONE == Fp.ZERO
assert Fp.ONE * Fp.ZERO == Fp.ZERO
def random(rand):
while True:
try:
return Scalar(leos2ip(rand.b(32)), strict=True)
except ValueError:
pass
for F in (Fp, Scalar):
F.ZERO = F(0)
F.ONE = F(1)
F.MINUS_ONE = F(-1)
assert F.ZERO + F.ZERO == F.ZERO
assert F.ZERO + F.ONE == F.ONE
assert F.ONE + F.ZERO == F.ONE
assert F.ZERO - F.ONE == F.MINUS_ONE
assert F.ZERO * F.ONE == F.ZERO
assert F.ONE * F.ZERO == F.ZERO
#
@ -209,6 +229,7 @@ class Point(object):
return self.x
def __mul__(self, s):
assert isinstance(s, Scalar)
s = format(s.s, '0256b')
ret = self.ZERO
for c in s:

View File

@ -1,6 +1,6 @@
from orchard_pallas import Fp
import numpy as np
from sapling_utils import leos2ip
from utils import leos2ip
from tv_output import render_args, render_tv
from tv_rand import Rand

View File

@ -1,6 +1,6 @@
from orchard_pallas import Fp
from orchard_poseidon import perm
from sapling_utils import leos2ip
from utils import leos2ip
from tv_output import render_args, render_tv
from tv_rand import Rand

View File

@ -6,7 +6,7 @@ import math
import orchard_iso_pallas
from orchard_pallas import Fp, Point
from sapling_utils import cldiv, lebs2ip, i2leosp
from utils import cldiv, lebs2ip, i2leosp
from orchard_group_hash import group_hash
from tv_output import render_args, render_tv
from tv_rand import Rand

View File

@ -5,7 +5,7 @@ from pyblake2 import blake2s
from sapling_jubjub import Point, JUBJUB_COFACTOR
from tv_output import render_args, render_tv
from sapling_utils import i2leosp
from utils import i2leosp
# First 64 bytes of the BLAKE2s input during group hash.
# This is chosen to be some random string that we couldn't have

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3
import sys; assert sys.version_info[0] >= 3, "Python 3 required."
from sapling_utils import i2lebsp, leos2ip, i2leosp
from utils import i2lebsp, leos2ip, i2leosp
q_j = 52435875175126190479447740508185965837690552500527637822603658699938581184513
r_j = 6554484396890773809930967563523245729705921265872317281365359162392183254199

View File

@ -7,7 +7,7 @@ from sapling_generators import PROVING_KEY_BASE, SPENDING_KEY_BASE, group_hash
from sapling_jubjub import Fr
from sapling_merkle_tree import MERKLE_DEPTH
from sapling_notes import note_commit, note_nullifier
from sapling_utils import leos2bsp, leos2ip
from utils import leos2bsp, leos2ip
from tv_output import render_args, render_tv
#

View File

@ -4,7 +4,7 @@ import sys; assert sys.version_info[0] >= 3, "Python 3 required."
from binascii import unhexlify
from sapling_pedersen import pedersen_hash
from sapling_utils import i2lebsp, leos2bsp
from utils import i2lebsp, leos2bsp
MERKLE_DEPTH = 32

View File

@ -10,7 +10,7 @@ from sapling_generators import VALUE_COMMITMENT_VALUE_BASE, VALUE_COMMITMENT_RAN
from sapling_jubjub import Fr, JUBJUB_COFACTOR
from sapling_key_components import SpendingKey, diversify_hash
from sapling_notes import note_commit
from sapling_utils import leos2bsp, leos2ip
from utils import leos2bsp, leos2ip
from tv_output import render_args, render_tv

View File

@ -7,7 +7,7 @@ from sapling_pedersen import (
mixing_pedersen_hash,
windowed_pedersen_commitment,
)
from sapling_utils import i2lebsp
from utils import i2lebsp
def note_commit(rcm, g_d, pk_d, v):
return windowed_pedersen_commitment(rcm, [1] * 6 + i2lebsp(64, v) + g_d + pk_d)

View File

@ -7,7 +7,7 @@ from sapling_generators import (
WINDOWED_PEDERSEN_RANDOMNESS_BASE,
)
from sapling_jubjub import Fr, Point
from sapling_utils import cldiv, i2leosp
from utils import cldiv, i2leosp
#

View File

@ -7,7 +7,7 @@ from pyblake2 import blake2b
from sapling_generators import SPENDING_KEY_BASE
from sapling_jubjub import Fr, Point, r_j
from sapling_key_components import to_scalar
from sapling_utils import cldiv, leos2ip
from utils import cldiv, leos2ip
from tv_output import render_args, render_tv

View File

@ -5,7 +5,7 @@ from pyblake2 import blake2b
from sapling_key_components import to_scalar, prf_expand, diversify_hash, DerivedAkNk, DerivedIvk
from sapling_generators import SPENDING_KEY_BASE, PROVING_KEY_BASE
from sapling_utils import i2leosp, i2lebsp, lebs2osp
from utils import i2leosp, i2lebsp, lebs2osp
from ff1 import ff1_aes256_encrypt
from tv_output import render_args, render_tv, option, Some

View File

@ -3,7 +3,7 @@ import struct
from sapling_generators import find_group_hash, SPENDING_KEY_BASE
from sapling_jubjub import Fq, Point
from sapling_utils import leos2ip
from utils import leos2ip
from zc_utils import write_compact_size
MAX_MONEY = 21000000 * 100000000