From 929b36ccfd7c40f01c79a85fca01afe7b1ee1e7e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 18 May 2018 12:48:53 +1200 Subject: [PATCH] Implement Pedersen hashes and commitments --- sapling_jubjub.py | 4 ++++ sapling_pedersen.py | 51 +++++++++++++++++++++++++++++++++++++++++++++ sapling_utils.py | 4 ++++ 3 files changed, 59 insertions(+) create mode 100644 sapling_pedersen.py create mode 100644 sapling_utils.py diff --git a/sapling_jubjub.py b/sapling_jubjub.py index aca2e0f..1e70df2 100644 --- a/sapling_jubjub.py +++ b/sapling_jubjub.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +from sapling_utils import i2lebsp ENDIANNESS = 'little' @@ -44,6 +45,9 @@ class FieldElement(object): def inv(self): return self.exp(self.m - 2) + def bits(self, l): + return i2lebsp(l, self.s) + def __bytes__(self): return self.s.to_bytes(32, byteorder=ENDIANNESS) diff --git a/sapling_pedersen.py b/sapling_pedersen.py new file mode 100644 index 0000000..e11ea5c --- /dev/null +++ b/sapling_pedersen.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +from sapling_generators import find_group_hash, NOTE_POSITION_BASE, WINDOWED_PEDERSEN_RANDOMNESS_BASE +from sapling_jubjub import ENDIANNESS, Fr + + +# +# Pedersen hashes +# + +def I_D_i(D, i): + return find_group_hash(D, (i - 1).to_bytes(4, byteorder=ENDIANNESS)) + +def encode_chunk(mj): + (s0, s1, s2) = mj + return (1 - 2*s2) * (1 + s0 + 2*s1) + +def encode_segment(Mi): + ki = len(Mi) / 3 + Michunks = [Mi[i:i+3] for i in range(0, len(Mi), 3)] + assert(len(Michunks) == ki) + return Fr(sum([encode_chunk(Michunks[j-1]) * 2**(4*(j-1)) for j in range(1, ki + 1)])) + +def cldiv(n, divisor): + return (n + (divisor - 1)) // divisor + +c = 63 + +def pedersen_hash_to_point(D, M): + # Pad M to a multiple of 3 bits + Mdash = M + [0] * ((-len(M)) % 3) + n = cldiv(len(Mdash), 3 * c) + Msegs = [Mdash[i:i+(3*c)] for i in range(0, len(Mdash), 3*c)] + assert(len(Msegs) == n) + return sum([I_D_i(D, i) * encode_segment(Msegs[i-1]) for i in range(1, n + 1)]) + +def pedersen_hash(D, M): + return pedersen_hash_to_point(D, M).u.bits(255) + +def mixing_pedersen_hash(P, x): + return P + NOTE_POSITION_BASE * x + + +# +# Pedersen commitments +# + +def windowed_pedersen_commitment(r, s): + return pedersen_hash_to_point(b'Zcash_PH', s) + WINDOWED_PEDERSEN_RANDOMNESS_BASE * r + +def homomorphic_pedersen_commitment(rcv, D, v): + return find_group_hash(D, b'v') * v + find_group_hash(D, b'r') * rcv diff --git a/sapling_utils.py b/sapling_utils.py new file mode 100644 index 0000000..0a32dff --- /dev/null +++ b/sapling_utils.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python3 + +def i2lebsp(l, x): + return [int(c) for c in format(x, '0%sb' % l)[::-1]]