From 4ef2e9ae685875c433ad2cdce6358a5c70c00fbd Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 21 May 2018 14:46:31 -0700 Subject: [PATCH] Add ffi and computation for Sapling note commitment. --- include/librustzcash.h | 21 ++++++++++++ src/rustzcash.rs | 76 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/include/librustzcash.h b/include/librustzcash.h index b6e1184..876e727 100644 --- a/include/librustzcash.h +++ b/include/librustzcash.h @@ -102,6 +102,27 @@ extern "C" { /// `librustzcash_sapling_verification_ctx_init`. void librustzcash_sapling_verification_ctx_free(void *); + /// Compute a Sapling commitment. + /// + /// The `diversifier` parameter must be 11 bytes in length. + /// The `pk_d` and `r` parameters must be of length 32. + /// The result is also of length 32 and placed in `result`. + /// Returns false if the diversifier or pk_d is not valid + bool librustzcash_sapling_compute_cm( + const unsigned char *diversifier, + const unsigned char *pk_d, + const uint64_t value, + const unsigned char *r, + unsigned char *result + ); + + /// Generate uniform Sapling commitment randomness `r`. + /// The result is of length 32. + /// Returns false if there was an error. + bool librustzcash_sapling_generate_commitment_randomness( + unsigned char *result + ); + /// Sprout JoinSplit proof generation. void librustzcash_sprout_prove( unsigned char *proof_out, diff --git a/src/rustzcash.rs b/src/rustzcash.rs index 08fe1f3..f43bfb1 100644 --- a/src/rustzcash.rs +++ b/src/rustzcash.rs @@ -13,7 +13,7 @@ use pairing::{BitIterator, Field, PrimeField, PrimeFieldRepr, bls12_381::{Bls12, use sapling_crypto::{circuit::multipack, constants::CRH_IVK_PERSONALIZATION, jubjub::{edwards, FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, - PrimeOrder, ToUniform, Unknown, fs::FsRepr}, + PrimeOrder, ToUniform, Unknown, fs::{Fs, FsRepr}}, pedersen_hash::{pedersen_hash, Personalization}, redjubjub::{self, Signature}}; use sapling_crypto::circuit::sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH}; @@ -25,7 +25,7 @@ use blake2_rfc::blake2s::Blake2s; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use rand::OsRng; +use rand::{OsRng, Rng}; use std::io::BufReader; use libc::{c_char, c_uchar, size_t, int64_t, uint32_t, uint64_t}; @@ -301,6 +301,78 @@ pub extern "system" fn librustzcash_ivk_to_pkd( } } +/// Return 32 byte randomness, uniform, to be used for a Sapling commitment. +#[no_mangle] +pub extern "system" fn librustzcash_sapling_generate_commitment_randomness( + result: *mut [c_uchar; 32], +) -> bool { + // create random 64 byte buffer + let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut buffer = [0u8; 64]; + for i in 0..buffer.len() { + buffer[i] = rng.gen(); + } + + // TODO: Remove this debug statement + println!("buffer of random bytes: {:?}", &buffer[..]); + + // reduce to uniform value + let r = ::Fs::to_uniform(&buffer[..]); + let result = unsafe { &mut *result }; + r.into_repr() + .write_le(&mut result[..]) + .expect("result must be 32 bytes"); + + true +} + +/// Compute Sapling note commitment. +#[no_mangle] +pub extern "system" fn librustzcash_sapling_compute_cm( + diversifier: *const [c_uchar; 11], + pk_d: *const [c_uchar; 32], + value: uint64_t, + r: *const [c_uchar; 32], + result: *mut [c_uchar; 32], +) -> bool { + let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); + let g_d = match diversifier.g_d::(&JUBJUB) { + Some(g_d) => g_d, + None => return false, + }; + + let pk_d = match edwards::Point::::read(&(unsafe { &*pk_d })[..], &JUBJUB) { + Ok(p) => p, + Err(_) => return false, + }; + + let pk_d = match pk_d.as_prime_order(&JUBJUB) { + Some(pk_d) => pk_d, + None => return false, + }; + + // Deserialize randomness + let r = unsafe { *r }; + let mut repr = FsRepr::default(); + repr.read_le(&r[..]).expect("length is not 32 bytes"); + let r = match Fs::from_repr(repr) { + Ok(p) => p, + Err(_) => return false, + }; + + let note = sapling_crypto::primitives::Note { + value, + g_d, + pk_d, + r, + }; + + let result = unsafe { &mut *result }; + write_le(note.cm(&JUBJUB).into_repr(), &mut result[..]); + + true +} + /// XOR two uint64_t values and return the result, used /// as a temporary mechanism for introducing Rust into /// Zcash.