diff --git a/README.md b/README.md index 388863a..21e5a39 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ Code to generate test vectors for various parts of Zcash. Requires `pyblake2`. +`sapling_note_encryption.py` also requires `chacha20poly1305`. + ## License Licensed under either of diff --git a/sapling_note_encryption.py b/sapling_note_encryption.py new file mode 100644 index 0000000..736b652 --- /dev/null +++ b/sapling_note_encryption.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python3 +import sys; assert sys.version_info[0] >= 3, "Python 3 required." + +from chacha20poly1305 import ChaCha20Poly1305 +import os +from pyblake2 import blake2b +import struct + +from sapling_generators import VALUE_COMMITMENT_VALUE_BASE, VALUE_COMMITMENT_RANDOMNESS_BASE +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 tv_output import render_args, render_tv + + +def kdf_sapling(shared_secret, epk): + digest = blake2b(digest_size=32, person=b'Zcash_SaplingKDF') + digest.update(bytes(shared_secret)) + digest.update(bytes(epk)) + return digest.digest() + +def prf_ock(ovk, cv, cmu, ephemeral_key): + digest = blake2b(digest_size=32, person=b'Zcash_Derive_ock') + digest.update(ovk) + digest.update(cv) + digest.update(cmu) + digest.update(ephemeral_key) + return digest.digest() + +class SaplingKeyAgreement(object): + @staticmethod + def private(random): + return Fr(leos2ip(random(32))) + + @staticmethod + def derive_public(esk, g_d): + return g_d * esk + + @staticmethod + def agree(esk, pk_d): + return pk_d * esk * JUBJUB_COFACTOR + +class SaplingSym(object): + @staticmethod + def k(random): + return random(32) + + @staticmethod + def encrypt(key, plaintext): + cip = ChaCha20Poly1305(key) + return bytes(cip.encrypt(b'\x00' * 12, plaintext)) + + +class SaplingNotePlaintext(object): + def __init__(self, d, v, rcm, memo): + self.d = d + self.v = v + self.rcm = rcm + self.memo = memo + + def __bytes__(self): + return ( + b'\x01' + + self.d + + struct.pack('