diff --git a/Cargo.lock b/Cargo.lock index 4b61b466fa..63b1c3eb26 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,7 +114,9 @@ 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)", ] @@ -197,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 7bfea8b559..45e1ff0fb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,13 @@ 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" rev = "e554b473dd10885d232f42237c13282f5b6fee43" + +[profile.release] +lto = true +panic = 'abort' diff --git a/include/librustzcash.h b/include/librustzcash.h index 87b99428a3..df937e526e 100644 --- a/include/librustzcash.h +++ b/include/librustzcash.h @@ -5,6 +5,29 @@ extern "C" { uint64_t librustzcash_xor(uint64_t a, uint64_t b); + + /// 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. + /// + /// `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( + 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 244d411074..ea358cc206 100644 --- a/src/rustzcash.rs +++ b/src/rustzcash.rs @@ -1,7 +1,97 @@ extern crate libc; extern crate sapling_crypto; +extern crate pairing; -use libc::uint64_t; +#[macro_use] +extern crate lazy_static; + +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}; + +lazy_static! { + static ref JUBJUB: JubjubBls12 = { + JubjubBls12::new() + }; +} + +#[no_mangle] +pub extern "system" fn librustzcash_tree_uncommitted( + result: *mut [c_uchar; 32] +) +{ + let tmp = sapling_crypto::primitives::Note::::uncommitted().into_repr(); + + // 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( + depth: size_t, + a: *const [c_uchar; 32], + b: *const [c_uchar; 32], + result: *mut [c_uchar; 32], +) +{ + 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)), + &JUBJUB + ).into_xy().0.into_repr(); + + // 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(); +} /// XOR two uint64_t values and return the result, used /// as a temporary mechanism for introducing Rust into