Implement RedJubjub
This commit is contained in:
parent
6d12cb9a74
commit
2f152758ba
|
@ -4,6 +4,7 @@ from pyblake2 import blake2b, blake2s
|
||||||
|
|
||||||
from sapling_generators import PROVING_KEY_BASE, SPENDING_KEY_BASE, group_hash
|
from sapling_generators import PROVING_KEY_BASE, SPENDING_KEY_BASE, group_hash
|
||||||
from sapling_jubjub import Fr
|
from sapling_jubjub import Fr
|
||||||
|
from sapling_utils import chunk
|
||||||
|
|
||||||
#
|
#
|
||||||
# PRFs and hashes
|
# PRFs and hashes
|
||||||
|
@ -80,10 +81,6 @@ class SpendingKey(object):
|
||||||
return group_hash(b'Zcash_gd', self.default_d()) * self.ivk()
|
return group_hash(b'Zcash_gd', self.default_d()) * self.ivk()
|
||||||
|
|
||||||
|
|
||||||
def chunk(h):
|
|
||||||
h = str(h, 'utf-8')
|
|
||||||
return '0x' + ', 0x'.join([h[i:i+2] for i in range(0, len(h), 2)])
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
print('''
|
print('''
|
||||||
struct TestVector {
|
struct TestVector {
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
from binascii import hexlify
|
||||||
|
import os
|
||||||
|
from pyblake2 import blake2b
|
||||||
|
|
||||||
|
from sapling_generators import SPENDING_KEY_BASE
|
||||||
|
from sapling_jubjub import Fr, Point
|
||||||
|
from sapling_utils import cldiv, chunk, leos2ip
|
||||||
|
|
||||||
|
|
||||||
|
def H(x):
|
||||||
|
digest = blake2b(person=b'Zcash_RedJubjubH')
|
||||||
|
digest.update(x)
|
||||||
|
return digest.digest()
|
||||||
|
|
||||||
|
def h_star(B):
|
||||||
|
return Fr(leos2ip(H(B)))
|
||||||
|
|
||||||
|
|
||||||
|
class RedJubjub(object):
|
||||||
|
l_G = 256 # l_J
|
||||||
|
l_H = 512
|
||||||
|
Public = Point
|
||||||
|
Private = Fr
|
||||||
|
Random = Fr
|
||||||
|
|
||||||
|
def __init__(self, P_g, random=os.urandom):
|
||||||
|
self.P_g = P_g
|
||||||
|
self._random = random
|
||||||
|
|
||||||
|
def gen_private(self):
|
||||||
|
return self.Private.from_bytes(self._random(64))
|
||||||
|
|
||||||
|
def derive_public(self, sk):
|
||||||
|
return self.P_g * sk
|
||||||
|
|
||||||
|
def gen_random(self):
|
||||||
|
T = self._random((self.l_H + 128) // 8)
|
||||||
|
return h_star(T)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def randomize_private(sk, alpha):
|
||||||
|
return sk + alpha
|
||||||
|
|
||||||
|
def randomize_public(self, vk, alpha):
|
||||||
|
return vk + self.P_g * alpha
|
||||||
|
|
||||||
|
def sign(self, sk, M):
|
||||||
|
T = self._random((self.l_H + 128) // 8)
|
||||||
|
r = h_star(T + M)
|
||||||
|
R = self.P_g * r
|
||||||
|
Rbar = bytes(R)
|
||||||
|
S = r + h_star(Rbar + M) * sk
|
||||||
|
Sbar = bytes(S) # TODO: bitlength(r_j)
|
||||||
|
return Rbar + Sbar
|
||||||
|
|
||||||
|
def verify(self, vk, M, sig):
|
||||||
|
mid = cldiv(self.l_G, 8)
|
||||||
|
(Rbar, Sbar) = (sig[:mid], sig[mid:]) # TODO: bitlength(r_j)
|
||||||
|
R = Point.from_bytes(Rbar)
|
||||||
|
S = Fr.from_bytes(Sbar)
|
||||||
|
c = h_star(Rbar + M)
|
||||||
|
return R and S.s == leos2ip(Sbar) and self.P_g * S == R + vk * c
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
from random import Random
|
||||||
|
rng = Random(0xabad533d)
|
||||||
|
def randbytes(l):
|
||||||
|
ret = []
|
||||||
|
while len(ret) < l:
|
||||||
|
ret.append(rng.randrange(0, 256))
|
||||||
|
return bytes(ret)
|
||||||
|
rj = RedJubjub(SPENDING_KEY_BASE, randbytes)
|
||||||
|
|
||||||
|
print('''
|
||||||
|
struct TestVector {
|
||||||
|
sk: [u8; 32],
|
||||||
|
vk: [u8; 32],
|
||||||
|
alpha: [u8; 32],
|
||||||
|
rsk: [u8; 32],
|
||||||
|
rvk: [u8; 32],
|
||||||
|
m: [u8; 32],
|
||||||
|
sig: [u8; 32],
|
||||||
|
rsig: [u8; 32],
|
||||||
|
};
|
||||||
|
|
||||||
|
let test_vectors = vec![''')
|
||||||
|
for i in range(0, 10):
|
||||||
|
sk = rj.gen_private()
|
||||||
|
vk = rj.derive_public(sk)
|
||||||
|
alpha = rj.gen_random()
|
||||||
|
rsk = rj.randomize_private(sk, alpha)
|
||||||
|
rvk = rj.randomize_public(vk, alpha)
|
||||||
|
|
||||||
|
M = bytes([i] * 32)
|
||||||
|
sig = rj.sign(sk, M)
|
||||||
|
rsig = rj.sign(rsk, M)
|
||||||
|
assert rj.verify(vk, M, sig)
|
||||||
|
assert rj.verify(rvk, M, rsig)
|
||||||
|
assert not rj.verify(vk, M, rsig)
|
||||||
|
assert not rj.verify(rvk, M, sig)
|
||||||
|
|
||||||
|
print(''' TestVector {
|
||||||
|
sk: [
|
||||||
|
%s
|
||||||
|
],
|
||||||
|
vk: [
|
||||||
|
%s
|
||||||
|
],
|
||||||
|
alpha: [
|
||||||
|
%s
|
||||||
|
],
|
||||||
|
rsk: [
|
||||||
|
%s
|
||||||
|
],
|
||||||
|
rvk: [
|
||||||
|
%s
|
||||||
|
],
|
||||||
|
m: [
|
||||||
|
%s
|
||||||
|
],
|
||||||
|
sig: [
|
||||||
|
%s
|
||||||
|
],
|
||||||
|
rsig: [
|
||||||
|
%s
|
||||||
|
],
|
||||||
|
},''' % (
|
||||||
|
chunk(hexlify(bytes(sk))),
|
||||||
|
chunk(hexlify(bytes(vk))),
|
||||||
|
chunk(hexlify(bytes(alpha))),
|
||||||
|
chunk(hexlify(bytes(rsk))),
|
||||||
|
chunk(hexlify(bytes(rvk))),
|
||||||
|
chunk(hexlify(M)),
|
||||||
|
chunk(hexlify(sig)),
|
||||||
|
chunk(hexlify(rsig)),
|
||||||
|
))
|
||||||
|
print(' ];')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
|
@ -3,6 +3,10 @@
|
||||||
def cldiv(n, divisor):
|
def cldiv(n, divisor):
|
||||||
return (n + (divisor - 1)) // divisor
|
return (n + (divisor - 1)) // divisor
|
||||||
|
|
||||||
|
def chunk(h):
|
||||||
|
h = str(h, 'utf-8')
|
||||||
|
return '0x' + ', 0x'.join([h[i:i+2] for i in range(0, len(h), 2)])
|
||||||
|
|
||||||
def i2lebsp(l, x):
|
def i2lebsp(l, x):
|
||||||
return [int(c) for c in format(x, '0%sb' % l)[::-1]]
|
return [int(c) for c in format(x, '0%sb' % l)[::-1]]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue