From f1d35708bcb3c8d4e7b9da0139f8c274a5d2153e Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Wed, 11 Apr 2018 21:51:30 -0600 Subject: [PATCH] Expose API for init/free of parameters and, to test, a merkle tree hash invocation. --- Cargo.lock | 1 + Cargo.toml | 1 + include/librustzcash.h | 34 +++++++++++++++ src/rustzcash.rs | 95 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 130 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 4b61b466f..a6b99b77b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -110,6 +110,7 @@ name = "librustzcash" version = "0.1.0" dependencies = [ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "pairing 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1 (git+https://github.com/zcash-hackworks/sapling-crypto?rev=e554b473dd10885d232f42237c13282f5b6fee43)", ] diff --git a/Cargo.toml b/Cargo.toml index 7bfea8b55..390cccbbc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ crate-type = ["staticlib"] [dependencies] libc = "0.2" +pairing = "0.14.1" [dependencies.sapling-crypto] git = "https://github.com/zcash-hackworks/sapling-crypto" diff --git a/include/librustzcash.h b/include/librustzcash.h index 87b99428a..666f780f8 100644 --- a/include/librustzcash.h +++ b/include/librustzcash.h @@ -3,8 +3,42 @@ #include +struct librustzcash_params { +}; + extern "C" { uint64_t librustzcash_xor(uint64_t a, uint64_t b); + + /// Initializes some parameters for sapling-crypto, + /// returning a pointer to the parameters. You should + /// free this when you're done with + /// `librustzcash_init_params()`. + librustzcash_params* librustzcash_init_params(); + + /// Frees some parameters that were previously returned + /// from `librustzcash_init_params()`. Only call this + /// once. + void librustzcash_free_params(librustzcash_params* params); + + /// Computes a merkle tree hash for a given depth. + /// The `depth` parameter should not be larger than + /// 62. + /// + /// Params must be a valid pointer that was returned + /// from `librustzcash_init_params()`. + /// + /// `a` and `b` each must be of length 32, and must each + /// be scalars of BLS12-381. + /// + /// The result of the merkle tree hash is placed in + /// `result`, which must also be of length 32. + void librustzcash_merkle_hash( + const librustzcash_params* params, + size_t depth, + const unsigned char *a, + const unsigned char *b, + unsigned char *result + ); } #endif // LIBRUSTZCASH_INCLUDE_H_ diff --git a/src/rustzcash.rs b/src/rustzcash.rs index 244d41107..70bf70ba4 100644 --- a/src/rustzcash.rs +++ b/src/rustzcash.rs @@ -1,7 +1,100 @@ extern crate libc; extern crate sapling_crypto; +extern crate pairing; -use libc::uint64_t; +use pairing::{ + BitIterator, + PrimeFieldRepr, + PrimeField, + bls12_381::{ + Bls12, + Fr, + FrRepr + } +}; + +use sapling_crypto::{ + jubjub::JubjubBls12, + pedersen_hash::{ + pedersen_hash, + Personalization + } +}; + +use libc::{uint64_t, size_t, c_uchar}; + +pub struct SaplingParams { + pub jubjub_params: JubjubBls12 +} + +#[no_mangle] +pub extern "system" fn librustzcash_init_params() -> *mut SaplingParams { + Box::into_raw(Box::new(SaplingParams{ + jubjub_params: JubjubBls12::new() + })) +} + +#[no_mangle] +pub extern "system" fn librustzcash_free_params( + params: *mut SaplingParams +) +{ + let tmp = unsafe { Box::from_raw(params) }; + + drop(tmp); +} + +#[no_mangle] +pub extern "system" fn librustzcash_merkle_hash( + params: *const SaplingParams, + depth: size_t, + a: *const [c_uchar; 32], + b: *const [c_uchar; 32], + result: *mut [c_uchar; 32], +) +{ + // Should be okay, because caller is responsible for ensuring + // params points to valid parameters. + let params = unsafe { &*params }; + + let mut a_repr = FrRepr::default(); + let mut b_repr = FrRepr::default(); + + // 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 + a_repr.read_be(unsafe { &(&*a)[..] }).unwrap(); + + // 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 + b_repr.read_be(unsafe { &(&*b)[..] }).unwrap(); + + let mut lhs = [false; 256]; + let mut rhs = [false; 256]; + + for (a, b) in lhs.iter_mut().rev().zip(BitIterator::new(a_repr)) { + *a = b; + } + + for (a, b) in rhs.iter_mut().rev().zip(BitIterator::new(b_repr)) { + *a = b; + } + + let tmp = pedersen_hash::( + Personalization::MerkleTree(depth), + lhs.iter().map(|&x| x) + .take(Fr::NUM_BITS as usize) + .chain(rhs.iter().map(|&x| x).take(Fr::NUM_BITS as usize)), + ¶ms.jubjub_params + ).into_xy().0.into_repr(); + + // Should be okay, caller is responsible for ensuring the pointer + // is valid. + let result = unsafe { &mut *result }; + + tmp.write_be(&mut result[..]).unwrap(); +} /// XOR two uint64_t values and return the result, used /// as a temporary mechanism for introducing Rust into