From f1d35708bcb3c8d4e7b9da0139f8c274a5d2153e Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Wed, 11 Apr 2018 21:51:30 -0600 Subject: [PATCH 1/4] 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 4b61b46..a6b99b7 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 7bfea8b..390cccb 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 87b9942..666f780 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 244d411..70bf70b 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 From 96654ee5bd172b16642ae54d6ada1f974ad5593b Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Thu, 12 Apr 2018 15:01:48 -0600 Subject: [PATCH 2/4] Fix typos --- include/librustzcash.h | 2 +- src/rustzcash.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/librustzcash.h b/include/librustzcash.h index 666f780..5a06b00 100644 --- a/include/librustzcash.h +++ b/include/librustzcash.h @@ -12,7 +12,7 @@ extern "C" { /// 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_free_params()`. librustzcash_params* librustzcash_init_params(); /// Frees some parameters that were previously returned diff --git a/src/rustzcash.rs b/src/rustzcash.rs index 70bf70b..19fe22b 100644 --- a/src/rustzcash.rs +++ b/src/rustzcash.rs @@ -90,7 +90,7 @@ pub extern "system" fn librustzcash_merkle_hash( ).into_xy().0.into_repr(); // Should be okay, caller is responsible for ensuring the pointer - // is valid. + // is a valid pointer to 32 bytes that can be mutated. let result = unsafe { &mut *result }; tmp.write_be(&mut result[..]).unwrap(); From cb8c9ebbce9482a46e2dc6ea121a1d9ea1128d58 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Thu, 12 Apr 2018 15:35:20 -0600 Subject: [PATCH 3/4] Make panic abort to avoid FFI problems. --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 390cccb..e1d1339 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,7 @@ pairing = "0.14.1" [dependencies.sapling-crypto] git = "https://github.com/zcash-hackworks/sapling-crypto" rev = "e554b473dd10885d232f42237c13282f5b6fee43" + +[profile.release] +lto = true +panic = 'abort' From 37f20fb90c856e82634c2eabb6bb3f754f3b350e Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Thu, 12 Apr 2018 18:38:25 -0600 Subject: [PATCH 4/4] Use lazy_static to initialize the Jubjub parameters, to avoid passing parameters around. --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + include/librustzcash.h | 23 ++++++----------------- src/rustzcash.rs | 35 ++++++++++++++++------------------- 4 files changed, 30 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a6b99b7..63b1c3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -100,6 +100,11 @@ dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lazy_static" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" version = "0.2.40" @@ -109,6 +114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "librustzcash" version = "0.1.0" dependencies = [ + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", @@ -198,6 +204,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" +"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" diff --git a/Cargo.toml b/Cargo.toml index e1d1339..45e1ff0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ crate-type = ["staticlib"] [dependencies] libc = "0.2" pairing = "0.14.1" +lazy_static = "1" [dependencies.sapling-crypto] git = "https://github.com/zcash-hackworks/sapling-crypto" diff --git a/include/librustzcash.h b/include/librustzcash.h index 5a06b00..df937e5 100644 --- a/include/librustzcash.h +++ b/include/librustzcash.h @@ -3,37 +3,26 @@ #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_free_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); + /// Writes the "uncommitted" note value for empty leaves + /// of the merkle tree. `result` must be a valid pointer + /// to 32 bytes which will be written. + void librustzcash_tree_uncommitted( + unsigned char *result + ); /// 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, diff --git a/src/rustzcash.rs b/src/rustzcash.rs index 19fe22b..ea358cc 100644 --- a/src/rustzcash.rs +++ b/src/rustzcash.rs @@ -2,6 +2,9 @@ extern crate libc; extern crate sapling_crypto; extern crate pairing; +#[macro_use] +extern crate lazy_static; + use pairing::{ BitIterator, PrimeFieldRepr, @@ -23,40 +26,34 @@ use sapling_crypto::{ 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() - })) +lazy_static! { + static ref JUBJUB: JubjubBls12 = { + JubjubBls12::new() + }; } #[no_mangle] -pub extern "system" fn librustzcash_free_params( - params: *mut SaplingParams +pub extern "system" fn librustzcash_tree_uncommitted( + result: *mut [c_uchar; 32] ) { - let tmp = unsafe { Box::from_raw(params) }; + let tmp = sapling_crypto::primitives::Note::::uncommitted().into_repr(); - drop(tmp); + // Should be okay, caller is responsible for ensuring the pointer + // is a valid pointer to 32 bytes that can be mutated. + let result = unsafe { &mut *result }; + + tmp.write_be(&mut result[..]).unwrap(); } #[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(); @@ -86,7 +83,7 @@ pub extern "system" fn librustzcash_merkle_hash( 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 + &JUBJUB ).into_xy().0.into_repr(); // Should be okay, caller is responsible for ensuring the pointer