diff --git a/include/librustzcash.h b/include/librustzcash.h index 794662b..8473959 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 b9f7b6b..50a482d 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.