diff --git a/Cargo.lock b/Cargo.lock index 7feb0fc..bc740bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -344,6 +344,7 @@ dependencies = [ "pairing 0.14.2", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", + "zip32 0.0.0", ] [[package]] diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml index 0494c07..b9b4334 100644 --- a/librustzcash/Cargo.toml +++ b/librustzcash/Cargo.toml @@ -21,6 +21,7 @@ lazy_static = "1" byteorder = "1" rand = "0.4" sapling-crypto = { path = "../sapling-crypto" } +zip32 = { path = "../zip32" } [dependencies.blake2-rfc] git = "https://github.com/gtank/blake2-rfc" diff --git a/librustzcash/include/librustzcash.h b/librustzcash/include/librustzcash.h index adab766..6fa9469 100644 --- a/librustzcash/include/librustzcash.h +++ b/librustzcash/include/librustzcash.h @@ -270,6 +270,35 @@ extern "C" { uint64_t vpub_old, uint64_t vpub_new ); + + /// Derive the master ExtendedSpendingKey from a seed. + void librustzcash_zip32_xsk_master( + const unsigned char *seed, + size_t seedlen, + unsigned char *xsk_master + ); + + /// Derive a child ExtendedSpendingKey from a parent. + void librustzcash_zip32_xsk_derive( + const unsigned char *xsk_parent, + uint32_t i, + unsigned char *xsk_i + ); + + /// Derive a child ExtendedFullViewingKey from a parent. + bool librustzcash_zip32_xfvk_derive( + const unsigned char *xfvk_parent, + uint32_t i, + unsigned char *xfvk_i + ); + + /// Derive a PaymentAddress from an ExtendedFullViewingKey. + bool librustzcash_zip32_xfvk_address( + const unsigned char *xfvk, + const unsigned char *j, + unsigned char *j_ret, + unsigned char *addr_ret + ); } #endif // LIBRUSTZCASH_INCLUDE_H_ diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 8ca9647..86cb659 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -5,6 +5,7 @@ extern crate libc; extern crate pairing; extern crate rand; extern crate sapling_crypto; +extern crate zip32; mod hashreader; @@ -12,16 +13,20 @@ mod hashreader; extern crate lazy_static; use pairing::{ - bls12_381::{Bls12, Fr, FrRepr}, BitIterator, Field, PrimeField, PrimeFieldRepr, + bls12_381::{Bls12, Fr, FrRepr}, + BitIterator, Field, PrimeField, PrimeFieldRepr, }; use sapling_crypto::{ - circuit::multipack, constants::CRH_IVK_PERSONALIZATION, + circuit::multipack, + constants::CRH_IVK_PERSONALIZATION, jubjub::{ - edwards, fs::{Fs, FsRepr}, FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, - PrimeOrder, ToUniform, Unknown, + edwards, + fs::{Fs, FsRepr}, + FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, PrimeOrder, ToUniform, Unknown, }, - pedersen_hash::{pedersen_hash, Personalization}, redjubjub::{self, Signature}, + pedersen_hash::{pedersen_hash, Personalization}, + redjubjub::{self, Signature}, }; use sapling_crypto::circuit::sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH}; @@ -1563,3 +1568,86 @@ pub extern "system" fn librustzcash_sapling_proving_ctx_init() -> *mut SaplingPr pub extern "system" fn librustzcash_sapling_proving_ctx_free(ctx: *mut SaplingProvingContext) { drop(unsafe { Box::from_raw(ctx) }); } + +#[no_mangle] +pub extern "system" fn librustzcash_zip32_xsk_master( + seed: *const c_uchar, + seedlen: size_t, + xsk_master: *mut [c_uchar; 169], +) { + let seed = unsafe { std::slice::from_raw_parts(seed, seedlen) }; + + let xsk = zip32::ExtendedSpendingKey::master(seed); + + xsk.write(&mut (unsafe { &mut *xsk_master })[..]) + .expect("should be able to serialize an ExtendedSpendingKey"); +} + +#[no_mangle] +pub extern "system" fn librustzcash_zip32_xsk_derive( + xsk_parent: *const [c_uchar; 169], + i: uint32_t, + xsk_i: *mut [c_uchar; 169], +) { + let xsk_parent = zip32::ExtendedSpendingKey::read(&unsafe { *xsk_parent }[..]) + .expect("valid ExtendedSpendingKey"); + let i = zip32::ChildIndex::from_index(i); + + let xsk = xsk_parent.derive_child(i); + + xsk.write(&mut (unsafe { &mut *xsk_i })[..]) + .expect("should be able to serialize an ExtendedSpendingKey"); +} + +#[no_mangle] +pub extern "system" fn librustzcash_zip32_xfvk_derive( + xfvk_parent: *const [c_uchar; 169], + i: uint32_t, + xfvk_i: *mut [c_uchar; 169], +) -> bool { + let xfvk_parent = zip32::ExtendedFullViewingKey::read(&unsafe { *xfvk_parent }[..]) + .expect("valid ExtendedFullViewingKey"); + let i = zip32::ChildIndex::from_index(i); + + let xfvk = match xfvk_parent.derive_child(i) { + Ok(xfvk) => xfvk, + Err(_) => return false, + }; + + xfvk.write(&mut (unsafe { &mut *xfvk_i })[..]) + .expect("should be able to serialize an ExtendedFullViewingKey"); + + true +} + +#[no_mangle] +pub extern "system" fn librustzcash_zip32_xfvk_address( + xfvk: *const [c_uchar; 169], + j: *const [c_uchar; 11], + j_ret: *mut [c_uchar; 11], + addr_ret: *mut [c_uchar; 43], +) -> bool { + let xfvk = zip32::ExtendedFullViewingKey::read(&unsafe { *xfvk }[..]) + .expect("valid ExtendedFullViewingKey"); + let j = zip32::DiversifierIndex(unsafe { *j }); + + let addr = match xfvk.address(j) { + Ok(addr) => addr, + Err(_) => return false, + }; + + let j_ret = unsafe { &mut *j_ret }; + let addr_ret = unsafe { &mut *addr_ret }; + + j_ret.copy_from_slice(&(addr.0).0); + addr_ret + .get_mut(..11) + .unwrap() + .copy_from_slice(&addr.1.diversifier.0); + addr.1 + .pk_d + .write(addr_ret.get_mut(11..).unwrap()) + .expect("should be able to serialize a PaymentAddress"); + + true +} diff --git a/librustzcash/src/tests/signatures.rs b/librustzcash/src/tests/signatures.rs index ae4ba3a..23fc75b 100644 --- a/librustzcash/src/tests/signatures.rs +++ b/librustzcash/src/tests/signatures.rs @@ -1,6 +1,7 @@ use pairing::{bls12_381::Bls12, PrimeField, PrimeFieldRepr}; use sapling_crypto::{ - jubjub::{FixedGenerators, JubjubEngine}, redjubjub::{PrivateKey, PublicKey, Signature}, + jubjub::{FixedGenerators, JubjubEngine}, + redjubjub::{PrivateKey, PublicKey, Signature}, }; use super::JUBJUB;