From 8ec096bdebbecdcce7415de5c44cdfd2d4dc286b Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 7 Jun 2018 10:36:52 -0700 Subject: [PATCH] Add function librustzcash_sapling_compute_nf. Also add function priv_get_note to refactor common code from librustzcash_sapling_compute_cm. --- include/librustzcash.h | 17 ++++++ src/rustzcash.rs | 118 +++++++++++++++++++++++++++++++---------- 2 files changed, 107 insertions(+), 28 deletions(-) diff --git a/include/librustzcash.h b/include/librustzcash.h index f877eef..34f346d 100644 --- a/include/librustzcash.h +++ b/include/librustzcash.h @@ -102,6 +102,23 @@ extern "C" { /// `librustzcash_sapling_verification_ctx_init`. void librustzcash_sapling_verification_ctx_free(void *); + /// Compute a Sapling nullifier. + /// + /// The `diversifier` parameter must be 11 bytes in length. + /// The `pk_d`, `r`, `ak` and `nk` 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_nf( + const unsigned char *diversifier, + const unsigned char *pk_d, + const uint64_t value, + const unsigned char *r, + const unsigned char *ak, + const unsigned char *nk, + const uint64_t position, + unsigned char *result + ); + /// Compute a Sapling commitment. /// /// The `diversifier` parameter must be 11 bytes in length. diff --git a/src/rustzcash.rs b/src/rustzcash.rs index 8ff895f..ac76a35 100644 --- a/src/rustzcash.rs +++ b/src/rustzcash.rs @@ -33,6 +33,8 @@ use std::ffi::CStr; use std::fs::File; use std::slice; +use sapling_crypto::primitives::ViewingKey; + pub mod equihash; #[cfg(test)] @@ -338,6 +340,93 @@ pub extern "system" fn librustzcash_sapling_generate_r(result: *mut [c_uchar; 32 .expect("result must be 32 bytes"); } +// Private utility function to get Note from C parameters +fn priv_get_note( + diversifier: *const [c_uchar; 11], + pk_d: *const [c_uchar; 32], + value: uint64_t, + r: *const [c_uchar; 32], +) -> Result, ()> { + let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); + let g_d = match diversifier.g_d::(&JUBJUB) { + Some(g_d) => g_d, + None => return Err(()), + }; + + let pk_d = match edwards::Point::::read(&(unsafe { &*pk_d })[..], &JUBJUB) { + Ok(p) => p, + Err(_) => return Err(()), + }; + + let pk_d = match pk_d.as_prime_order(&JUBJUB) { + Some(pk_d) => pk_d, + None => return Err(()), + }; + + // 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 Err(()), + }; + + let note = sapling_crypto::primitives::Note { + value, + g_d, + pk_d, + r, + }; + + Ok(note) +} + +/// Compute Sapling note nullifier. +#[no_mangle] +pub extern "system" fn librustzcash_sapling_compute_nf( + diversifier: *const [c_uchar; 11], + pk_d: *const [c_uchar; 32], + value: uint64_t, + r: *const [c_uchar; 32], + ak: *const [c_uchar; 32], + nk: *const [c_uchar; 32], + position: uint64_t, + result: *mut [c_uchar; 32], +) -> bool { + let note = match priv_get_note(diversifier, pk_d, value, r) { + Ok(p) => p, + Err(_) => return false, + }; + + let ak = match edwards::Point::::read(&(unsafe { &*ak })[..], &JUBJUB) { + Ok(p) => p, + Err(_) => return false, + }; + + let ak = match ak.as_prime_order(&JUBJUB) { + Some(ak) => ak, + None => return false, + }; + + let nk = match edwards::Point::::read(&(unsafe { &*nk })[..], &JUBJUB) { + Ok(p) => p, + Err(_) => return false, + }; + + let nk = match nk.as_prime_order(&JUBJUB) { + Some(nk) => nk, + None => return false, + }; + + let vk = ViewingKey { ak, nk }; + let nf = note.nf(&vk, position, &JUBJUB); + let result = unsafe { &mut *result }; + result.copy_from_slice(&nf); + + true +} + /// Compute Sapling note commitment. #[no_mangle] pub extern "system" fn librustzcash_sapling_compute_cm( @@ -347,38 +436,11 @@ pub extern "system" fn librustzcash_sapling_compute_cm( 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) { + let note = match priv_get_note(diversifier, pk_d, value, r) { 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[..]);