From 128af9fc82c65e4f655b11d7b271f79df87a120a Mon Sep 17 00:00:00 2001 From: Jay Graber Date: Wed, 9 May 2018 06:51:19 -0700 Subject: [PATCH 1/5] Add to_scalar call --- include/librustzcash.h | 2 ++ src/rustzcash.rs | 21 +++++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/include/librustzcash.h b/include/librustzcash.h index 9033dc280..6aa388ac9 100644 --- a/include/librustzcash.h +++ b/include/librustzcash.h @@ -6,6 +6,8 @@ extern "C" { uint64_t librustzcash_xor(uint64_t a, uint64_t b); + void librustzcash_to_scalar(const unsigned char *input, unsigned char *result); + /// Loads the zk-SNARK parameters into memory and saves /// paths as necessary. Only called once. void librustzcash_init_zksnark_params( diff --git a/src/rustzcash.rs b/src/rustzcash.rs index 35c63d391..74fc1151c 100644 --- a/src/rustzcash.rs +++ b/src/rustzcash.rs @@ -12,8 +12,8 @@ extern crate lazy_static; use pairing::{BitIterator, Field, PrimeField, PrimeFieldRepr, bls12_381::{Bls12, Fr, FrRepr}}; use sapling_crypto::{circuit::multipack, - jubjub::{edwards, FixedGenerators, JubjubBls12, JubjubParams, Unknown, - fs::FsRepr}, + jubjub::{edwards, FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, + ToUniform, Unknown, fs::FsRepr}, pedersen_hash::{pedersen_hash, Personalization}, redjubjub::{self, Signature}}; use sapling_crypto::circuit::sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH}; @@ -185,6 +185,23 @@ pub extern "system" fn librustzcash_merkle_hash( write_le(tmp, &mut result[..]); } +#[no_mangle] // ToScalar +pub extern "system" fn librustzcash_to_scalar( + input: *const [c_uchar; 64], + result: *mut [c_uchar; 32], +) { + // Should be okay, because caller is responsible for ensuring + // the pointer is a valid pointer to 32 bytes, and that is the + // size of the representation + let scalar = ::Fs::to_uniform(unsafe { &(&*input)[..] }).into_repr(); + + let result = unsafe { &mut *result }; + + scalar + .write_le(&mut result[..]) + .expect("length is 32 bytes"); +} + /// XOR two uint64_t values and return the result, used /// as a temporary mechanism for introducing Rust into /// Zcash. From c44d70299ba9a2b3116e733ecc10fc805ff4e9da Mon Sep 17 00:00:00 2001 From: Jay Graber Date: Mon, 14 May 2018 20:40:35 -0700 Subject: [PATCH 2/5] Add ask_to_ak and nsk_to_nk --- include/librustzcash.h | 4 ++++ src/rustzcash.rs | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/include/librustzcash.h b/include/librustzcash.h index 6aa388ac9..794662bcf 100644 --- a/include/librustzcash.h +++ b/include/librustzcash.h @@ -8,6 +8,10 @@ extern "C" { void librustzcash_to_scalar(const unsigned char *input, unsigned char *result); + void librustzcash_ask_to_ak(const unsigned char *ask, unsigned char *result); + + void librustzcash_nsk_to_nk(const unsigned char *nsk, unsigned char *result); + /// Loads the zk-SNARK parameters into memory and saves /// paths as necessary. Only called once. void librustzcash_init_zksnark_params( diff --git a/src/rustzcash.rs b/src/rustzcash.rs index 74fc1151c..b9f7b6bad 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, jubjub::{edwards, FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, - ToUniform, Unknown, fs::FsRepr}, + PrimeOrder, ToUniform, Unknown, fs::FsRepr}, pedersen_hash::{pedersen_hash, Personalization}, redjubjub::{self, Signature}}; use sapling_crypto::circuit::sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH}; @@ -71,6 +71,19 @@ fn read_le(from: &[u8]) -> FrRepr { f } +/// Reads an FsRepr from [u8] of length 32 +/// and multiplies it by the given base. +/// This will panic (abort) if length provided is +/// not correct +fn fixed_scalar_mult(from: &[u8], p_g: FixedGenerators) -> edwards::Point { + assert_eq!(from.len(), 32); + + let mut f = <::Fs as PrimeField>::Repr::default(); + f.read_le(from).expect("length is 32 bytes"); + + JUBJUB.generator(p_g).mul(f, &JUBJUB) +} + #[no_mangle] pub extern "system" fn librustzcash_init_zksnark_params( spend_path: *const c_char, @@ -202,6 +215,32 @@ pub extern "system" fn librustzcash_to_scalar( .expect("length is 32 bytes"); } +#[no_mangle] +pub extern "system" fn librustzcash_ask_to_ak( + ask: *const [c_uchar; 32], + result: *mut [c_uchar; 32], +) { + let ask = unsafe { &*ask }; + let ak = fixed_scalar_mult(ask, FixedGenerators::SpendingKeyGenerator); + + let result = unsafe { &mut *result }; + + ak.write(&mut result[..]).expect("length is 32 bytes"); +} + +#[no_mangle] +pub extern "system" fn librustzcash_nsk_to_nk( + nsk: *const [c_uchar; 32], + result: *mut [c_uchar; 32], +) { + let nsk = unsafe { &*nsk }; + let nk = fixed_scalar_mult(nsk, FixedGenerators::ProofGenerationKey); + + let result = unsafe { &mut *result }; + + nk.write(&mut result[..]).expect("length is 32 bytes"); +} + /// XOR two uint64_t values and return the result, used /// as a temporary mechanism for introducing Rust into /// Zcash. From 23c2f0e527e26996d6ff5eb9603e8f306a7ee20a Mon Sep 17 00:00:00 2001 From: Jay Graber Date: Mon, 14 May 2018 21:23:21 -0700 Subject: [PATCH 3/5] Add crh_ivk --- include/librustzcash.h | 2 ++ src/rustzcash.rs | 26 +++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/include/librustzcash.h b/include/librustzcash.h index 794662bcf..8473959e5 100644 --- a/include/librustzcash.h +++ b/include/librustzcash.h @@ -12,6 +12,8 @@ extern "C" { void librustzcash_nsk_to_nk(const unsigned char *nsk, unsigned char *result); + void librustzcash_crh_ivk(const unsigned char *ak, const unsigned char *nk, unsigned char *result); + /// Loads the zk-SNARK parameters into memory and saves /// paths as necessary. Only called once. void librustzcash_init_zksnark_params( diff --git a/src/rustzcash.rs b/src/rustzcash.rs index b9f7b6bad..50a482d60 100644 --- a/src/rustzcash.rs +++ b/src/rustzcash.rs @@ -11,7 +11,7 @@ extern crate lazy_static; use pairing::{BitIterator, Field, PrimeField, PrimeFieldRepr, bls12_381::{Bls12, Fr, FrRepr}}; -use sapling_crypto::{circuit::multipack, +use sapling_crypto::{circuit::multipack, constants::CRH_IVK_PERSONALIZATION, jubjub::{edwards, FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, PrimeOrder, ToUniform, Unknown, fs::FsRepr}, pedersen_hash::{pedersen_hash, Personalization}, redjubjub::{self, Signature}}; @@ -21,6 +21,8 @@ use sapling_crypto::circuit::sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH}; use bellman::groth16::{create_random_proof, prepare_verifying_key, verify_proof, Parameters, PreparedVerifyingKey, Proof, VerifyingKey}; +use blake2_rfc::blake2s::Blake2s; + use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use rand::OsRng; @@ -241,6 +243,28 @@ pub extern "system" fn librustzcash_nsk_to_nk( nk.write(&mut result[..]).expect("length is 32 bytes"); } +#[no_mangle] +pub extern "system" fn librustzcash_crh_ivk( + ak: *const [c_uchar; 32], + nk: *const [c_uchar; 32], + result: *mut [c_uchar; 32], +) { + let ak = unsafe { &*ak }; + let nk = unsafe { &*nk }; + + let mut h = Blake2s::with_params(32, &[], &[], CRH_IVK_PERSONALIZATION); + h.update(ak); + h.update(nk); + let mut h = h.finalize().as_ref().to_vec(); + + // Drop the last five bits, so it can be interpreted as a scalar. + h[31] &= 0b0000_0111; + + let result = unsafe { &mut *result }; + + result.copy_from_slice(&h); +} + /// XOR two uint64_t values and return the result, used /// as a temporary mechanism for introducing Rust into /// Zcash. From be1b3074463a574cdcb2123596a62b32cf93fdbe Mon Sep 17 00:00:00 2001 From: Jay Graber Date: Mon, 14 May 2018 22:34:27 -0700 Subject: [PATCH 4/5] Add check_diversifier and ivk_to_pkd --- include/librustzcash.h | 4 ++++ src/rustzcash.rs | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/include/librustzcash.h b/include/librustzcash.h index 8473959e5..b6e11846f 100644 --- a/include/librustzcash.h +++ b/include/librustzcash.h @@ -14,6 +14,10 @@ extern "C" { void librustzcash_crh_ivk(const unsigned char *ak, const unsigned char *nk, unsigned char *result); + bool librustzcash_check_diversifier(const unsigned char *diversifier); + + bool librustzcash_ivk_to_pkd(const unsigned char *ivk, const unsigned char *diversifier, unsigned char *result); + /// Loads the zk-SNARK parameters into memory and saves /// paths as necessary. Only called once. void librustzcash_init_zksnark_params( diff --git a/src/rustzcash.rs b/src/rustzcash.rs index 50a482d60..08fe1f3bb 100644 --- a/src/rustzcash.rs +++ b/src/rustzcash.rs @@ -74,15 +74,24 @@ fn read_le(from: &[u8]) -> FrRepr { } /// Reads an FsRepr from [u8] of length 32 -/// and multiplies it by the given base. /// This will panic (abort) if length provided is /// not correct -fn fixed_scalar_mult(from: &[u8], p_g: FixedGenerators) -> edwards::Point { +fn read_fs(from: &[u8]) -> FsRepr { assert_eq!(from.len(), 32); let mut f = <::Fs as PrimeField>::Repr::default(); f.read_le(from).expect("length is 32 bytes"); + f +} + +/// Reads an FsRepr from [u8] of length 32 +/// and multiplies it by the given base. +/// This will panic (abort) if length provided is +/// not correct +fn fixed_scalar_mult(from: &[u8], p_g: FixedGenerators) -> edwards::Point { + let f = read_fs(from); + JUBJUB.generator(p_g).mul(f, &JUBJUB) } @@ -265,6 +274,33 @@ pub extern "system" fn librustzcash_crh_ivk( result.copy_from_slice(&h); } +#[no_mangle] +pub extern "system" fn librustzcash_check_diversifier(diversifier: *const [c_uchar; 11]) -> bool { + let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); + diversifier.g_d::(&JUBJUB).is_some() +} + +#[no_mangle] +pub extern "system" fn librustzcash_ivk_to_pkd( + ivk: *const [c_uchar; 32], + diversifier: *const [c_uchar; 11], + result: *mut [c_uchar; 32], +) -> bool { + let ivk = read_fs(unsafe { &*ivk }); + let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); + if let Some(g_d) = diversifier.g_d::(&JUBJUB) { + let pk_d = g_d.mul(ivk, &JUBJUB); + + let result = unsafe { &mut *result }; + + pk_d.write(&mut result[..]).expect("length is 32 bytes"); + + true + } else { + false + } +} + /// XOR two uint64_t values and return the result, used /// as a temporary mechanism for introducing Rust into /// Zcash. From b54e028bb27670488b71e33c93286c9c9ac37648 Mon Sep 17 00:00:00 2001 From: str4d Date: Wed, 30 May 2018 12:03:43 +1200 Subject: [PATCH 5/5] Test librustzcash key component APIs against test vectors --- src/tests/key_components.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/tests/key_components.rs b/src/tests/key_components.rs index af3278e73..8b72b109d 100644 --- a/src/tests/key_components.rs +++ b/src/tests/key_components.rs @@ -4,6 +4,9 @@ use sapling_crypto::{jubjub::{FixedGenerators, JubjubEngine, JubjubParams, fs::F use super::JUBJUB; +use {librustzcash_ask_to_ak, librustzcash_check_diversifier, librustzcash_crh_ivk, + librustzcash_ivk_to_pkd, librustzcash_nsk_to_nk}; + #[test] fn key_components() { #![allow(dead_code)] @@ -601,6 +604,11 @@ fn key_components() { ak.write(&mut vec).unwrap(); assert_eq!(&vec, &tv.ak); } + { + let mut ak = [0u8; 32]; + librustzcash_ask_to_ak(&tv.ask, &mut ak); + assert_eq!(&ak, &tv.ak); + } let pgk = ProofGenerationKey { ak, nsk }; let fvk = pgk.into_viewing_key(&JUBJUB); @@ -609,20 +617,37 @@ fn key_components() { fvk.nk.write(&mut vec).unwrap(); assert_eq!(&vec, &tv.nk); } + { + let mut nk = [0u8; 32]; + librustzcash_nsk_to_nk(&tv.nsk, &mut nk); + assert_eq!(&nk, &tv.nk); + } { let mut vec = Vec::new(); fvk.ivk().into_repr().write_le(&mut vec).unwrap(); assert_eq!(&vec, &tv.ivk); } + { + let mut ivk = [0u8; 32]; + librustzcash_crh_ivk(&tv.ak, &tv.nk, &mut ivk); + assert_eq!(&ivk, &tv.ivk); + } let diversifier = Diversifier(tv.default_d); + assert!(librustzcash_check_diversifier(&tv.default_d)); + let addr = fvk.into_payment_address(diversifier, &JUBJUB).unwrap(); { let mut vec = Vec::new(); addr.pk_d.write(&mut vec).unwrap(); assert_eq!(&vec, &tv.default_pk_d); } + { + let mut default_pk_d = [0u8; 32]; + librustzcash_ivk_to_pkd(&tv.ivk, &tv.default_d, &mut default_pk_d); + assert_eq!(&default_pk_d, &tv.default_pk_d); + } let mut note_r_repr = FsRepr::default(); note_r_repr.read_le(&tv.note_r[..]).unwrap();