diff --git a/src/Makefile.am b/src/Makefile.am index 1cafc2b99..0d6c4cd4f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -50,34 +50,21 @@ if ENABLE_WALLET LIBBITCOIN_WALLET=libbitcoin_wallet.a endif -# TODO: Figure out how to avoid an explicit file list. CXXBRIDGE_RS = \ rust/src/blake2b.rs \ - rust/src/bundlecache.rs \ rust/src/equihash.rs \ - rust/src/merkle_frontier.rs \ - rust/src/orchard_bundle.rs \ - rust/src/sapling.rs \ rust/src/streams.rs \ - rust/src/wallet_scanner.rs + rust/src/bridge.rs CXXBRIDGE_H = \ rust/gen/include/rust/blake2b.h \ - rust/gen/include/rust/bundlecache.h \ rust/gen/include/rust/equihash.h \ - rust/gen/include/rust/merkle_frontier.h \ - rust/gen/include/rust/orchard_bundle.h \ - rust/gen/include/rust/sapling.h \ rust/gen/include/rust/streams.h \ - rust/gen/include/rust/wallet_scanner.h + rust/gen/include/rust/bridge.h CXXBRIDGE_CPP = \ rust/gen/src/blake2b.cpp \ - rust/gen/src/bundlecache.cpp \ rust/gen/src/equihash.cpp \ - rust/gen/src/merkle_frontier.cpp \ - rust/gen/src/orchard_bundle.cpp \ - rust/gen/src/sapling.cpp \ rust/gen/src/streams.cpp \ - rust/gen/src/wallet_scanner.cpp + rust/gen/src/bridge.cpp # We add a rust/cxx.h include to indicate that we provide this (via the rustcxx depends # package), so that cxxbridge doesn't include it within the generated headers and code. diff --git a/src/bench/verification.cpp b/src/bench/verification.cpp index 7441639be..c4dc8ea12 100644 --- a/src/bench/verification.cpp +++ b/src/bench/verification.cpp @@ -15,8 +15,8 @@ #include "version.h" #include "librustzcash.h" +#include #include -#include static void ECDSA(benchmark::State& state) { diff --git a/src/chainparams.h b/src/chainparams.h index eb752e7a8..0286c2c3b 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -14,7 +14,7 @@ #include -#include +#include struct CDNSSeedData { std::string name, host; diff --git a/src/gtest/main.cpp b/src/gtest/main.cpp index a35a99c8f..83c4ed654 100644 --- a/src/gtest/main.cpp +++ b/src/gtest/main.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include diff --git a/src/gtest/test_checktransaction.cpp b/src/gtest/test_checktransaction.cpp index 8990c8dea..bcc5e8153 100644 --- a/src/gtest/test_checktransaction.cpp +++ b/src/gtest/test_checktransaction.cpp @@ -11,8 +11,8 @@ #include "zcash/JoinSplit.hpp" #include +#include #include -#include #include // Subclass of CTransaction which doesn't call UpdateHash when constructing diff --git a/src/init.cpp b/src/init.cpp index ce644f642..a57145ea0 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -67,7 +67,7 @@ #include "zmq/zmqnotificationinterface.h" #endif -#include +#include #include #include diff --git a/src/main.h b/src/main.h index 31e5316da..270fba025 100644 --- a/src/main.h +++ b/src/main.h @@ -43,7 +43,7 @@ #include #include -#include +#include #include #include diff --git a/src/miner.cpp b/src/miner.cpp index 57c1ddfa2..cd8620678 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -37,7 +37,7 @@ #include "validationinterface.h" #include -#include +#include #include #include diff --git a/src/primitives/orchard.h b/src/primitives/orchard.h index 644915e5a..28b453b1d 100644 --- a/src/primitives/orchard.h +++ b/src/primitives/orchard.h @@ -8,8 +8,9 @@ #include "streams.h" #include + +#include #include -#include #include #include "zcash/address/orchard.hpp" diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 204618519..1645d86d0 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -32,7 +32,7 @@ #include #include -#include +#include using namespace std; diff --git a/src/rust/src/bridge.rs b/src/rust/src/bridge.rs new file mode 100644 index 000000000..5c2cb1e76 --- /dev/null +++ b/src/rust/src/bridge.rs @@ -0,0 +1,277 @@ +//! FFI bridges between `zcashd`'s Rust and C++ code. +//! +//! These are all collected into a single file because we can't use the same Rust type +//! across multiple bridges until https://github.com/dtolnay/cxx/issues/496 is closed. +//! +//! The bridges that we leave separate are either standalone Rust code, or exporting C++ +//! types to Rust (because we _can_ use the same C++ type across multiple bridges). + +use crate::{ + bundlecache::init as bundlecache_init, + merkle_frontier::{new_orchard, orchard_empty_root, parse_orchard, Orchard, OrchardWallet}, + note_encryption::{ + try_sapling_note_decryption, try_sapling_output_recovery, DecryptedSaplingOutput, + }, + orchard_bundle::{from_tx_bundle, Action, Bundle, OrchardBundle}, + params::{network, Network}, + sapling::{ + finish_bundle_assembly, init_batch_validator, init_prover, init_verifier, + new_bundle_assembler, BatchValidator, Bundle as SaplingBundle, + BundleAssembler as SaplingBundleAssembler, Prover, Verifier, + }, + wallet_scanner::{init_batch_scanner, BatchResult, BatchScanner}, +}; + +#[cxx::bridge] +pub(crate) mod ffi { + extern "C++" { + include!("streams.h"); + + #[cxx_name = "RustDataStream"] + type RustStream = crate::streams::ffi::RustStream; + } + + #[namespace = "consensus"] + extern "Rust" { + type Network; + + fn network( + network: &str, + overwinter: i32, + sapling: i32, + blossom: i32, + heartwood: i32, + canopy: i32, + nu5: i32, + ) -> Result>; + } + + #[namespace = "libzcash"] + unsafe extern "C++" { + include!("zcash/cache.h"); + + type BundleValidityCache; + + fn NewBundleValidityCache(kind: &str, bytes: usize) -> UniquePtr; + fn insert(self: Pin<&mut BundleValidityCache>, entry: [u8; 32]); + fn contains(&self, entry: &[u8; 32], erase: bool) -> bool; + } + #[namespace = "bundlecache"] + extern "Rust" { + #[rust_name = "bundlecache_init"] + fn init(cache_bytes: usize); + } + + #[namespace = "sapling"] + extern "Rust" { + #[rust_name = "SaplingBundle"] + type Bundle; + + #[rust_name = "SaplingBundleAssembler"] + type BundleAssembler; + + fn new_bundle_assembler() -> Box; + fn add_spend( + self: &mut SaplingBundleAssembler, + cv: &[u8; 32], + anchor: &[u8; 32], + nullifier: [u8; 32], + rk: &[u8; 32], + zkproof: [u8; 192], // GROTH_PROOF_SIZE + spend_auth_sig: &[u8; 64], + ) -> bool; + fn add_output( + self: &mut SaplingBundleAssembler, + cv: &[u8; 32], + cmu: &[u8; 32], + ephemeral_key: [u8; 32], + enc_ciphertext: [u8; 580], + out_ciphertext: [u8; 80], + zkproof: [u8; 192], // GROTH_PROOF_SIZE + ) -> bool; + fn finish_bundle_assembly( + assembler: Box, + value_balance: i64, + binding_sig: [u8; 64], + ) -> Box; + + type Prover; + + fn init_prover() -> Box; + #[allow(clippy::too_many_arguments)] + fn create_spend_proof( + self: &mut Prover, + ak: &[u8; 32], + nsk: &[u8; 32], + diversifier: &[u8; 11], + rcm: &[u8; 32], + ar: &[u8; 32], + value: u64, + anchor: &[u8; 32], + merkle_path: &[u8; 1065], // 1 + 33 * SAPLING_TREE_DEPTH + 8 + cv: &mut [u8; 32], + rk_out: &mut [u8; 32], + zkproof: &mut [u8; 192], // GROTH_PROOF_SIZE + ) -> bool; + fn create_output_proof( + self: &mut Prover, + esk: &[u8; 32], + payment_address: &[u8; 43], + rcm: &[u8; 32], + value: u64, + cv: &mut [u8; 32], + zkproof: &mut [u8; 192], // GROTH_PROOF_SIZE + ) -> bool; + fn binding_sig( + self: &mut Prover, + value_balance: i64, + sighash: &[u8; 32], + result: &mut [u8; 64], + ) -> bool; + + type Verifier; + + fn init_verifier() -> Box; + #[allow(clippy::too_many_arguments)] + fn check_spend( + self: &mut Verifier, + cv: &[u8; 32], + anchor: &[u8; 32], + nullifier: &[u8; 32], + rk: &[u8; 32], + zkproof: &[u8; 192], // GROTH_PROOF_SIZE + spend_auth_sig: &[u8; 64], + sighash_value: &[u8; 32], + ) -> bool; + fn check_output( + self: &mut Verifier, + cv: &[u8; 32], + cm: &[u8; 32], + ephemeral_key: &[u8; 32], + zkproof: &[u8; 192], // GROTH_PROOF_SIZE + ) -> bool; + fn final_check( + self: &Verifier, + value_balance: i64, + binding_sig: &[u8; 64], + sighash_value: &[u8; 32], + ) -> bool; + + type BatchValidator; + fn init_batch_validator(cache_store: bool) -> Box; + fn check_bundle( + self: &mut BatchValidator, + bundle: Box, + sighash: [u8; 32], + ) -> bool; + fn validate(self: &mut BatchValidator) -> bool; + } + + #[namespace = "orchard_bundle"] + extern "Rust" { + type Action; + type Bundle; + type OrchardBundle; + + fn cv(self: &Action) -> [u8; 32]; + fn nullifier(self: &Action) -> [u8; 32]; + fn rk(self: &Action) -> [u8; 32]; + fn cmx(self: &Action) -> [u8; 32]; + fn ephemeral_key(self: &Action) -> [u8; 32]; + fn enc_ciphertext(self: &Action) -> [u8; 580]; + fn out_ciphertext(self: &Action) -> [u8; 80]; + fn spend_auth_sig(self: &Action) -> [u8; 64]; + + unsafe fn from_tx_bundle(bundle: *const OrchardBundle) -> Box; + fn actions(self: &Bundle) -> Vec; + fn num_actions(self: &Bundle) -> usize; + fn enable_spends(self: &Bundle) -> bool; + fn enable_outputs(self: &Bundle) -> bool; + fn value_balance_zat(self: &Bundle) -> i64; + fn anchor(self: &Bundle) -> [u8; 32]; + fn proof(self: &Bundle) -> Vec; + fn binding_sig(self: &Bundle) -> [u8; 64]; + } + + #[namespace = "merkle_frontier"] + extern "Rust" { + type Orchard; + type OrchardWallet; + + fn orchard_empty_root() -> [u8; 32]; + fn new_orchard() -> Box; + fn box_clone(self: &Orchard) -> Box; + fn parse_orchard(stream: Pin<&mut RustStream>) -> Result>; + fn serialize(self: &Orchard, stream: Pin<&mut RustStream>) -> Result<()>; + fn serialize_legacy(self: &Orchard, stream: Pin<&mut RustStream>) -> Result<()>; + fn dynamic_memory_usage(self: &Orchard) -> usize; + fn root(self: &Orchard) -> [u8; 32]; + fn size(self: &Orchard) -> u64; + fn append_bundle(self: &mut Orchard, bundle: &Bundle) -> bool; + unsafe fn init_wallet(self: &Orchard, wallet: *mut OrchardWallet) -> bool; + } + + #[namespace = "wallet"] + struct SaplingDecryptionResult { + txid: [u8; 32], + output: u32, + ivk: [u8; 32], + diversifier: [u8; 11], + pk_d: [u8; 32], + } + + #[namespace = "wallet"] + pub(crate) struct SaplingShieldedOutput { + cv: [u8; 32], + cmu: [u8; 32], + ephemeral_key: [u8; 32], + enc_ciphertext: [u8; 580], + out_ciphertext: [u8; 80], + } + + #[namespace = "wallet"] + extern "Rust" { + fn try_sapling_note_decryption( + network: &Network, + height: u32, + raw_ivk: &[u8; 32], + output: SaplingShieldedOutput, + ) -> Result>; + fn try_sapling_output_recovery( + network: &Network, + height: u32, + ovk: [u8; 32], + output: SaplingShieldedOutput, + ) -> Result>; + + type DecryptedSaplingOutput; + fn note_value(self: &DecryptedSaplingOutput) -> u64; + fn note_rseed(self: &DecryptedSaplingOutput) -> [u8; 32]; + fn zip_212_enabled(self: &DecryptedSaplingOutput) -> bool; + fn recipient_d(self: &DecryptedSaplingOutput) -> [u8; 11]; + fn recipient_pk_d(self: &DecryptedSaplingOutput) -> [u8; 32]; + fn memo(self: &DecryptedSaplingOutput) -> [u8; 512]; + + type BatchScanner; + type BatchResult; + + fn init_batch_scanner( + network: &Network, + sapling_ivks: &[[u8; 32]], + ) -> Result>; + fn add_transaction( + self: &mut BatchScanner, + block_tag: [u8; 32], + tx_bytes: &[u8], + height: u32, + ) -> Result<()>; + fn flush(self: &mut BatchScanner); + fn collect_results( + self: &mut BatchScanner, + block_tag: [u8; 32], + txid: [u8; 32], + ) -> Box; + + fn get_sapling(self: &BatchResult) -> Vec; + } +} diff --git a/src/rust/src/bundlecache.rs b/src/rust/src/bundlecache.rs index e5873dc1b..f9cfd4acc 100644 --- a/src/rust/src/bundlecache.rs +++ b/src/rust/src/bundlecache.rs @@ -5,23 +5,7 @@ use std::{ use rand_core::{OsRng, RngCore}; -#[cxx::bridge] -mod ffi { - #[namespace = "libzcash"] - unsafe extern "C++" { - include!("zcash/cache.h"); - - type BundleValidityCache; - - fn NewBundleValidityCache(kind: &str, bytes: usize) -> UniquePtr; - fn insert(self: Pin<&mut BundleValidityCache>, entry: [u8; 32]); - fn contains(&self, entry: &[u8; 32], erase: bool) -> bool; - } - #[namespace = "bundlecache"] - extern "Rust" { - fn init(cache_bytes: usize); - } -} +use crate::bridge::ffi; pub(crate) struct CacheEntry([u8; 32]); @@ -114,7 +98,7 @@ static BUNDLE_CACHES_LOADED: Once = Once::new(); static mut SAPLING_BUNDLE_VALIDITY_CACHE: Option> = None; static mut ORCHARD_BUNDLE_VALIDITY_CACHE: Option> = None; -fn init(cache_bytes: usize) { +pub(crate) fn init(cache_bytes: usize) { BUNDLE_CACHES_LOADED.call_once(|| unsafe { SAPLING_BUNDLE_VALIDITY_CACHE = Some(RwLock::new(BundleValidityCache::new( "Sapling", diff --git a/src/rust/src/merkle_frontier.rs b/src/rust/src/merkle_frontier.rs index 29a958db5..200c89f54 100644 --- a/src/rust/src/merkle_frontier.rs +++ b/src/rust/src/merkle_frontier.rs @@ -2,63 +2,31 @@ use core::mem::size_of_val; use core::pin::Pin; use incrementalmerkletree::{bridgetree, Altitude, Frontier, Hashable}; -use orchard::{bundle::Authorized, tree::MerkleHashOrchard}; +use orchard::tree::MerkleHashOrchard; use tracing::error; -use zcash_primitives::{ - merkle_tree::{ - incremental::{read_frontier_v1, write_frontier_v1}, - CommitmentTree, HashSer, - }, - transaction::components::Amount, +use zcash_primitives::merkle_tree::{ + incremental::{read_frontier_v1, write_frontier_v1}, + CommitmentTree, HashSer, }; -use crate::{streams::CppStream, wallet::Wallet}; +use crate::{bridge::ffi, orchard_bundle, streams::CppStream, wallet::Wallet}; pub const MERKLE_DEPTH: u8 = 32; -#[cxx::bridge] -mod ffi { - extern "C++" { - include!("streams.h"); - - #[cxx_name = "RustDataStream"] - type RustStream = crate::streams::ffi::RustStream; - } - - #[namespace = "merkle_frontier"] - extern "Rust" { - type Orchard; - type OrchardBundle; - type OrchardWallet; - - fn orchard_empty_root() -> [u8; 32]; - fn new_orchard() -> Box; - fn box_clone(self: &Orchard) -> Box; - fn parse_orchard(stream: Pin<&mut RustStream>) -> Result>; - fn serialize(self: &Orchard, stream: Pin<&mut RustStream>) -> Result<()>; - fn serialize_legacy(self: &Orchard, stream: Pin<&mut RustStream>) -> Result<()>; - fn dynamic_memory_usage(self: &Orchard) -> usize; - fn root(self: &Orchard) -> [u8; 32]; - fn size(self: &Orchard) -> u64; - unsafe fn append_bundle(self: &mut Orchard, bundle: *const OrchardBundle) -> bool; - unsafe fn init_wallet(self: &Orchard, wallet: *mut OrchardWallet) -> bool; - } -} - type Inner = bridgetree::Frontier; /// An incremental Merkle frontier. #[derive(Clone)] -struct MerkleFrontier(Inner); +pub(crate) struct MerkleFrontier(Inner); impl MerkleFrontier { /// Returns a copy of the value. - fn box_clone(&self) -> Box { + pub(crate) fn box_clone(&self) -> Box { Box::new(self.clone()) } /// Attempts to parse a Merkle frontier from the given C++ stream. - fn parse(stream: Pin<&mut ffi::RustStream>) -> Result, String> { + pub(crate) fn parse(stream: Pin<&mut ffi::RustStream>) -> Result, String> { let reader = CppStream::from(stream); match read_frontier_v1(reader) { @@ -68,14 +36,14 @@ impl MerkleFrontier { } /// Serializes the frontier to the given C++ stream. - fn serialize(&self, stream: Pin<&mut ffi::RustStream>) -> Result<(), String> { + pub(crate) fn serialize(&self, stream: Pin<&mut ffi::RustStream>) -> Result<(), String> { let writer = CppStream::from(stream); write_frontier_v1(writer, &self.0) .map_err(|e| format!("Failed to serialize v5 Merkle frontier: {}", e)) } /// Serializes the frontier to the given C++ stream in the legacy frontier encoding. - fn serialize_legacy(&self, stream: Pin<&mut ffi::RustStream>) -> Result<(), String> { + pub(crate) fn serialize_legacy(&self, stream: Pin<&mut ffi::RustStream>) -> Result<(), String> { let writer = CppStream::from(stream); let commitment_tree = CommitmentTree::from_frontier(&self.0); commitment_tree.write(writer).map_err(|e| { @@ -89,13 +57,13 @@ impl MerkleFrontier { /// Returns the amount of memory dynamically allocated for the frontier. /// /// Includes `self` because this type is stored on the heap when passed to C++. - fn dynamic_memory_usage(&self) -> usize { + pub(crate) fn dynamic_memory_usage(&self) -> usize { size_of_val(&self.0) + self.0.dynamic_memory_usage() } /// Obtains the current root of this Merkle frontier by hashing against empty nodes up /// to the maximum height of the pruned tree that the frontier represents. - fn root(&self) -> [u8; 32] { + pub(crate) fn root(&self) -> [u8; 32] { let mut root = [0; 32]; self.0 .root() @@ -105,39 +73,36 @@ impl MerkleFrontier { } /// Returns the number of leaves appended to the frontier. - fn size(&self) -> u64 { + pub(crate) fn size(&self) -> u64 { self.0.position().map_or(0, |p| ::from(p) + 1) } } /// Returns the root of an empty Orchard Merkle tree. -fn orchard_empty_root() -> [u8; 32] { +pub(crate) fn orchard_empty_root() -> [u8; 32] { let altitude = Altitude::from(MERKLE_DEPTH); MerkleHashOrchard::empty_root(altitude).to_bytes() } /// An Orchard incremental Merkle frontier. -type Orchard = MerkleFrontier; +pub(crate) type Orchard = MerkleFrontier; /// Constructs a new empty Orchard Merkle frontier. -fn new_orchard() -> Box { +pub(crate) fn new_orchard() -> Box { Box::new(MerkleFrontier(Inner::empty())) } /// Attempts to parse an Orchard Merkle frontier from the given C++ stream. -fn parse_orchard(stream: Pin<&mut ffi::RustStream>) -> Result, String> { +pub(crate) fn parse_orchard(stream: Pin<&mut ffi::RustStream>) -> Result, String> { Orchard::parse(stream) } -struct OrchardBundle; -struct OrchardWallet; +pub(crate) struct OrchardWallet; impl Orchard { /// Appends the note commitments in the given bundle to this frontier. - fn append_bundle(&mut self, bundle: *const OrchardBundle) -> bool { - let bundle = unsafe { (bundle as *const orchard::Bundle).as_ref() }; - - if let Some(bundle) = bundle { + pub(crate) fn append_bundle(&mut self, bundle: &orchard_bundle::Bundle) -> bool { + if let Some(bundle) = bundle.inner() { for action in bundle.actions().iter() { if !self.0.append(&MerkleHashOrchard::from_cmx(action.cmx())) { error!("Orchard note commitment tree is full."); @@ -155,7 +120,7 @@ impl Orchard { /// This will fail with an assertion error if any checkpoints exist in the tree. /// /// TODO: Remove once `crate::wallet` is migrated to `cxx`. - fn init_wallet(&self, wallet: *mut OrchardWallet) -> bool { + pub(crate) fn init_wallet(&self, wallet: *mut OrchardWallet) -> bool { crate::wallet::orchard_wallet_init_from_frontier(wallet as *mut Wallet, &self.0) } } diff --git a/src/rust/src/note_encryption.rs b/src/rust/src/note_encryption.rs index 19486ab4f..069fc712c 100644 --- a/src/rust/src/note_encryption.rs +++ b/src/rust/src/note_encryption.rs @@ -15,7 +15,7 @@ use zcash_primitives::{ }, }; -use crate::{params::Network, wallet_scanner::ffi::SaplingShieldedOutput}; +use crate::{bridge::ffi::SaplingShieldedOutput, params::Network}; /// Trial decryption of the full note plaintext by the recipient. /// diff --git a/src/rust/src/orchard_bundle.rs b/src/rust/src/orchard_bundle.rs index f91d9888b..353ed0698 100644 --- a/src/rust/src/orchard_bundle.rs +++ b/src/rust/src/orchard_bundle.rs @@ -4,80 +4,56 @@ use orchard::{ }; use zcash_primitives::transaction::components::Amount; -#[cxx::bridge(namespace = "orchard_bundle")] -mod ffi { - extern "Rust" { - type Action; - type Bundle; - type OrchardBundle; - - fn cv(self: &Action) -> [u8; 32]; - fn nullifier(self: &Action) -> [u8; 32]; - fn rk(self: &Action) -> [u8; 32]; - fn cmx(self: &Action) -> [u8; 32]; - fn ephemeral_key(self: &Action) -> [u8; 32]; - fn enc_ciphertext(self: &Action) -> [u8; 580]; - fn out_ciphertext(self: &Action) -> [u8; 80]; - fn spend_auth_sig(self: &Action) -> [u8; 64]; - - unsafe fn from_tx_bundle(bundle: *const OrchardBundle) -> Box; - fn actions(self: &Bundle) -> Vec; - fn num_actions(self: &Bundle) -> usize; - fn enable_spends(self: &Bundle) -> bool; - fn enable_outputs(self: &Bundle) -> bool; - fn value_balance_zat(self: &Bundle) -> i64; - fn anchor(self: &Bundle) -> [u8; 32]; - fn proof(self: &Bundle) -> Vec; - fn binding_sig(self: &Bundle) -> [u8; 64]; - } -} - pub struct Action(orchard::Action>); impl Action { - fn cv(&self) -> [u8; 32] { + pub(crate) fn cv(&self) -> [u8; 32] { self.0.cv_net().to_bytes() } - fn nullifier(&self) -> [u8; 32] { + pub(crate) fn nullifier(&self) -> [u8; 32] { self.0.nullifier().to_bytes() } - fn rk(&self) -> [u8; 32] { + pub(crate) fn rk(&self) -> [u8; 32] { self.0.rk().into() } - fn cmx(&self) -> [u8; 32] { + pub(crate) fn cmx(&self) -> [u8; 32] { self.0.cmx().to_bytes() } - fn ephemeral_key(&self) -> [u8; 32] { + pub(crate) fn ephemeral_key(&self) -> [u8; 32] { self.0.encrypted_note().epk_bytes } - fn enc_ciphertext(&self) -> [u8; 580] { + pub(crate) fn enc_ciphertext(&self) -> [u8; 580] { self.0.encrypted_note().enc_ciphertext } - fn out_ciphertext(&self) -> [u8; 80] { + pub(crate) fn out_ciphertext(&self) -> [u8; 80] { self.0.encrypted_note().out_ciphertext } - fn spend_auth_sig(&self) -> [u8; 64] { + pub(crate) fn spend_auth_sig(&self) -> [u8; 64] { self.0.authorization().into() } } pub struct Bundle(Option>); pub struct OrchardBundle; -unsafe fn from_tx_bundle(bundle: *const OrchardBundle) -> Box { +pub(crate) unsafe fn from_tx_bundle(bundle: *const OrchardBundle) -> Box { Box::new(Bundle( { (bundle as *const orchard::Bundle).as_ref() }.cloned(), )) } impl Bundle { - fn actions(&self) -> Vec { + pub(crate) fn inner(&self) -> Option<&orchard::Bundle> { + self.0.as_ref() + } + + pub(crate) fn actions(&self) -> Vec { self.0 .iter() .flat_map(|b| b.actions().iter()) @@ -86,42 +62,35 @@ impl Bundle { .collect() } - fn num_actions(&self) -> usize { - self.0.as_ref().map(|b| b.actions().len()).unwrap_or(0) + pub(crate) fn num_actions(&self) -> usize { + self.inner().map(|b| b.actions().len()).unwrap_or(0) } - fn enable_spends(&self) -> bool { - self.0 - .as_ref() + pub(crate) fn enable_spends(&self) -> bool { + self.inner() .map(|b| b.flags().spends_enabled()) .unwrap_or(false) } - fn enable_outputs(&self) -> bool { - self.0 - .as_ref() + pub(crate) fn enable_outputs(&self) -> bool { + self.inner() .map(|b| b.flags().outputs_enabled()) .unwrap_or(false) } - fn value_balance_zat(&self) -> i64 { - self.0 - .as_ref() - .map(|b| b.value_balance().into()) - .unwrap_or(0) + pub(crate) fn value_balance_zat(&self) -> i64 { + self.inner().map(|b| b.value_balance().into()).unwrap_or(0) } - fn anchor(&self) -> [u8; 32] { - self.0 - .as_ref() + pub(crate) fn anchor(&self) -> [u8; 32] { + self.inner() .expect("Bundle actions should have been checked to be non-empty") .anchor() .to_bytes() } - fn proof(&self) -> Vec { - self.0 - .as_ref() + pub(crate) fn proof(&self) -> Vec { + self.inner() .expect("Bundle actions should have been checked to be non-empty") .authorization() .proof() @@ -129,9 +98,8 @@ impl Bundle { .to_vec() } - fn binding_sig(&self) -> [u8; 64] { - self.0 - .as_ref() + pub(crate) fn binding_sig(&self) -> [u8; 64] { + self.inner() .expect("Bundle actions should have been checked to be non-empty") .authorization() .binding_signature() diff --git a/src/rust/src/rustzcash.rs b/src/rust/src/rustzcash.rs index 8a64018e6..8f3762be5 100644 --- a/src/rust/src/rustzcash.rs +++ b/src/rust/src/rustzcash.rs @@ -70,6 +70,8 @@ mod streams_ffi; mod tracing_ffi; mod zcashd_orchard; +mod bridge; + mod address_ffi; mod builder_ffi; mod bundlecache; diff --git a/src/rust/src/sapling.rs b/src/rust/src/sapling.rs index 81bbbf156..95bc38552 100644 --- a/src/rust/src/sapling.rs +++ b/src/rust/src/sapling.rs @@ -36,106 +36,7 @@ use crate::bundlecache::{ sapling_bundle_validity_cache, sapling_bundle_validity_cache_mut, CacheEntries, }; -#[cxx::bridge(namespace = "sapling")] -mod ffi { - extern "Rust" { - type Bundle; - type BundleAssembler; - fn new_bundle_assembler() -> Box; - fn add_spend( - self: &mut BundleAssembler, - cv: &[u8; 32], - anchor: &[u8; 32], - nullifier: [u8; 32], - rk: &[u8; 32], - zkproof: [u8; 192], // GROTH_PROOF_SIZE - spend_auth_sig: &[u8; 64], - ) -> bool; - fn add_output( - self: &mut BundleAssembler, - cv: &[u8; 32], - cmu: &[u8; 32], - ephemeral_key: [u8; 32], - enc_ciphertext: [u8; 580], - out_ciphertext: [u8; 80], - zkproof: [u8; 192], // GROTH_PROOF_SIZE - ) -> bool; - fn finish_bundle_assembly( - assembler: Box, - value_balance: i64, - binding_sig: [u8; 64], - ) -> Box; - - type Prover; - - fn init_prover() -> Box; - #[allow(clippy::too_many_arguments)] - fn create_spend_proof( - self: &mut Prover, - ak: &[u8; 32], - nsk: &[u8; 32], - diversifier: &[u8; 11], - rcm: &[u8; 32], - ar: &[u8; 32], - value: u64, - anchor: &[u8; 32], - merkle_path: &[u8; 1065], // 1 + 33 * SAPLING_TREE_DEPTH + 8 - cv: &mut [u8; 32], - rk_out: &mut [u8; 32], - zkproof: &mut [u8; 192], // GROTH_PROOF_SIZE - ) -> bool; - fn create_output_proof( - self: &mut Prover, - esk: &[u8; 32], - payment_address: &[u8; 43], - rcm: &[u8; 32], - value: u64, - cv: &mut [u8; 32], - zkproof: &mut [u8; 192], // GROTH_PROOF_SIZE - ) -> bool; - fn binding_sig( - self: &mut Prover, - value_balance: i64, - sighash: &[u8; 32], - result: &mut [u8; 64], - ) -> bool; - - type Verifier; - - fn init_verifier() -> Box; - #[allow(clippy::too_many_arguments)] - fn check_spend( - self: &mut Verifier, - cv: &[u8; 32], - anchor: &[u8; 32], - nullifier: &[u8; 32], - rk: &[u8; 32], - zkproof: &[u8; 192], // GROTH_PROOF_SIZE - spend_auth_sig: &[u8; 64], - sighash_value: &[u8; 32], - ) -> bool; - fn check_output( - self: &mut Verifier, - cv: &[u8; 32], - cm: &[u8; 32], - ephemeral_key: &[u8; 32], - zkproof: &[u8; 192], // GROTH_PROOF_SIZE - ) -> bool; - fn final_check( - self: &Verifier, - value_balance: i64, - binding_sig: &[u8; 64], - sighash_value: &[u8; 32], - ) -> bool; - - type BatchValidator; - fn init_batch_validator(cache_store: bool) -> Box; - fn check_bundle(self: &mut BatchValidator, bundle: Box, sighash: [u8; 32]) -> bool; - fn validate(self: &mut BatchValidator) -> bool; - } -} - -struct Bundle(sapling::Bundle); +pub(crate) struct Bundle(sapling::Bundle); impl Bundle { fn commitment>(&self, digester: D) -> D::SaplingDigest { @@ -143,12 +44,12 @@ impl Bundle { } } -struct BundleAssembler { +pub(crate) struct BundleAssembler { shielded_spends: Vec>, shielded_outputs: Vec>, // GROTH_PROOF_SIZE } -fn new_bundle_assembler() -> Box { +pub(crate) fn new_bundle_assembler() -> Box { Box::new(BundleAssembler { shielded_spends: vec![], shielded_outputs: vec![], @@ -156,7 +57,7 @@ fn new_bundle_assembler() -> Box { } impl BundleAssembler { - fn add_spend( + pub(crate) fn add_spend( self: &mut BundleAssembler, cv: &[u8; 32], anchor: &[u8; 32], @@ -203,7 +104,7 @@ impl BundleAssembler { true } - fn add_output( + pub(crate) fn add_output( self: &mut BundleAssembler, cv: &[u8; 32], cm: &[u8; 32], @@ -239,7 +140,7 @@ impl BundleAssembler { } #[allow(clippy::boxed_local)] -fn finish_bundle_assembly( +pub(crate) fn finish_bundle_assembly( assembler: Box, value_balance: i64, binding_sig: [u8; 64], @@ -255,15 +156,15 @@ fn finish_bundle_assembly( ))) } -struct Prover(SaplingProvingContext); +pub(crate) struct Prover(SaplingProvingContext); -fn init_prover() -> Box { +pub(crate) fn init_prover() -> Box { Box::new(Prover(SaplingProvingContext::new())) } impl Prover { #[allow(clippy::too_many_arguments)] - fn create_spend_proof( + pub(crate) fn create_spend_proof( &mut self, ak: &[u8; 32], nsk: &[u8; 32], @@ -361,7 +262,8 @@ impl Prover { true } - fn create_output_proof( + + pub(crate) fn create_output_proof( &mut self, esk: &[u8; 32], payment_address: &[u8; 43], @@ -409,7 +311,8 @@ impl Prover { true } - fn binding_sig( + + pub(crate) fn binding_sig( &mut self, value_balance: i64, sighash: &[u8; 32], @@ -434,9 +337,9 @@ impl Prover { } } -struct Verifier(SaplingVerificationContext); +pub(crate) struct Verifier(SaplingVerificationContext); -fn init_verifier() -> Box { +pub(crate) fn init_verifier() -> Box { // We consider ZIP 216 active all of the time because blocks prior to NU5 // activation (on mainnet and testnet) did not contain Sapling transactions // that violated its canonicity rule. @@ -445,7 +348,7 @@ fn init_verifier() -> Box { impl Verifier { #[allow(clippy::too_many_arguments)] - fn check_spend( + pub(crate) fn check_spend( &mut self, cv: &[u8; 32], anchor: &[u8; 32], @@ -500,7 +403,8 @@ impl Verifier { ), ) } - fn check_output( + + pub(crate) fn check_output( &mut self, cv: &[u8; 32], cm: &[u8; 32], @@ -543,7 +447,8 @@ impl Verifier { ), ) } - fn final_check( + + pub(crate) fn final_check( &self, value_balance: i64, binding_sig: &[u8; 64], @@ -570,9 +475,9 @@ struct BatchValidatorInner { queued_entries: CacheEntries, } -struct BatchValidator(Option); +pub(crate) struct BatchValidator(Option); -fn init_batch_validator(cache_store: bool) -> Box { +pub(crate) fn init_batch_validator(cache_store: bool) -> Box { Box::new(BatchValidator(Some(BatchValidatorInner { validator: sapling_proofs::BatchValidator::new(), queued_entries: CacheEntries::new(cache_store), @@ -594,7 +499,7 @@ impl BatchValidator { /// the global bundle validity cache, it will have been removed (and this method will /// return `true`). #[allow(clippy::boxed_local)] - fn check_bundle(&mut self, bundle: Box, sighash: [u8; 32]) -> bool { + pub(crate) fn check_bundle(&mut self, bundle: Box, sighash: [u8; 32]) -> bool { if let Some(inner) = &mut self.0 { let cache = sapling_bundle_validity_cache(); @@ -637,7 +542,7 @@ impl BatchValidator { /// If this batch was configured to cache the results, then if this method returns /// `true` every bundle added to the batch will have also been added to the global /// bundle validity cache. - fn validate(&mut self) -> bool { + pub(crate) fn validate(&mut self) -> bool { if let Some(inner) = self.0.take() { if inner.validator.validate( unsafe { SAPLING_SPEND_VK.as_ref() } diff --git a/src/rust/src/wallet_scanner.rs b/src/rust/src/wallet_scanner.rs index 3aa0adf7a..8e4fc9f88 100644 --- a/src/rust/src/wallet_scanner.rs +++ b/src/rust/src/wallet_scanner.rs @@ -21,95 +21,7 @@ use zcash_primitives::{ }, }; -use crate::{ - note_encryption::{ - parse_and_prepare_sapling_ivk, try_sapling_note_decryption, try_sapling_output_recovery, - DecryptedSaplingOutput, - }, - params::{network, Network}, -}; - -#[cxx::bridge] -pub(crate) mod ffi { - #[namespace = "wallet"] - pub(crate) struct SaplingShieldedOutput { - cv: [u8; 32], - cmu: [u8; 32], - ephemeral_key: [u8; 32], - enc_ciphertext: [u8; 580], - out_ciphertext: [u8; 80], - } - - #[namespace = "wallet"] - struct SaplingDecryptionResult { - txid: [u8; 32], - output: u32, - ivk: [u8; 32], - diversifier: [u8; 11], - pk_d: [u8; 32], - } - - #[namespace = "consensus"] - extern "Rust" { - type Network; - - fn network( - network: &str, - overwinter: i32, - sapling: i32, - blossom: i32, - heartwood: i32, - canopy: i32, - nu5: i32, - ) -> Result>; - } - - #[namespace = "wallet"] - extern "Rust" { - fn try_sapling_note_decryption( - network: &Network, - height: u32, - raw_ivk: &[u8; 32], - output: SaplingShieldedOutput, - ) -> Result>; - fn try_sapling_output_recovery( - network: &Network, - height: u32, - ovk: [u8; 32], - output: SaplingShieldedOutput, - ) -> Result>; - - type DecryptedSaplingOutput; - fn note_value(self: &DecryptedSaplingOutput) -> u64; - fn note_rseed(self: &DecryptedSaplingOutput) -> [u8; 32]; - fn zip_212_enabled(self: &DecryptedSaplingOutput) -> bool; - fn recipient_d(self: &DecryptedSaplingOutput) -> [u8; 11]; - fn recipient_pk_d(self: &DecryptedSaplingOutput) -> [u8; 32]; - fn memo(self: &DecryptedSaplingOutput) -> [u8; 512]; - - type BatchScanner; - type BatchResult; - - fn init_batch_scanner( - network: &Network, - sapling_ivks: &[[u8; 32]], - ) -> Result>; - fn add_transaction( - self: &mut BatchScanner, - block_tag: [u8; 32], - tx_bytes: &[u8], - height: u32, - ) -> Result<()>; - fn flush(self: &mut BatchScanner); - fn collect_results( - self: &mut BatchScanner, - block_tag: [u8; 32], - txid: [u8; 32], - ) -> Box; - - fn get_sapling(self: &BatchResult) -> Vec; - } -} +use crate::{bridge::ffi, note_encryption::parse_and_prepare_sapling_ivk, params::Network}; /// The minimum number of outputs to trial decrypt in a batch. /// @@ -641,7 +553,7 @@ type SaplingRunner = BatchRunner<[u8; 32], SaplingDomain, OutputDescription, WithUsage>; /// A batch scanner for the `zcashd` wallet. -struct BatchScanner { +pub(crate) struct BatchScanner { params: Network, sapling_runner: Option, } @@ -656,7 +568,7 @@ impl DynamicUsage for BatchScanner { } } -fn init_batch_scanner( +pub(crate) fn init_batch_scanner( network: &Network, sapling_ivks: &[[u8; 32]], ) -> Result, &'static str> { @@ -690,7 +602,7 @@ impl BatchScanner { /// After adding the outputs, any accumulated batch of sufficient size is run on the /// global threadpool. Subsequent calls to `Self::add_transaction` will accumulate /// those output kinds into new batches. - fn add_transaction( + pub(crate) fn add_transaction( &mut self, block_tag: [u8; 32], tx_bytes: &[u8], @@ -724,7 +636,7 @@ impl BatchScanner { /// Runs the currently accumulated batches on the global threadpool. /// /// Subsequent calls to `Self::add_transaction` will be accumulated into new batches. - fn flush(&mut self) { + pub(crate) fn flush(&mut self) { if let Some(runner) = &mut self.sapling_runner { runner.flush(); } @@ -737,7 +649,11 @@ impl BatchScanner { /// mempool change). /// /// TODO: Return the `HashMap`s directly once `cxx` supports it. - fn collect_results(&mut self, block_tag: [u8; 32], txid: [u8; 32]) -> Box { + pub(crate) fn collect_results( + &mut self, + block_tag: [u8; 32], + txid: [u8; 32], + ) -> Box { let block_tag = BlockHash(block_tag); let txid = TxId::from_bytes(txid); @@ -754,12 +670,12 @@ impl BatchScanner { } } -struct BatchResult { +pub(crate) struct BatchResult { sapling: HashMap<(TxId, usize), DecryptedNote<[u8; 32], SaplingDomain>>, } impl BatchResult { - fn get_sapling(&self) -> Vec { + pub(crate) fn get_sapling(&self) -> Vec { self.sapling .iter() .map( diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 02a47ad88..715a9ec1b 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -34,7 +34,7 @@ #include "librustzcash.h" -#include +#include const std::function G_TRANSLATION_FUN = nullptr; diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 48d098976..66a19bd88 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -35,8 +35,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/transaction_builder.h b/src/transaction_builder.h index c38842c4a..a6e0b5b65 100644 --- a/src/transaction_builder.h +++ b/src/transaction_builder.h @@ -22,8 +22,8 @@ #include +#include #include -#include #define NO_MEMO {{0xF6}} diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 4a03e3ec9..6b21a1727 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -42,7 +42,7 @@ #include #include -#include +#include #include diff --git a/src/zcash/IncrementalMerkleTree.hpp b/src/zcash/IncrementalMerkleTree.hpp index d4f2bfef3..204aecba6 100644 --- a/src/zcash/IncrementalMerkleTree.hpp +++ b/src/zcash/IncrementalMerkleTree.hpp @@ -12,7 +12,7 @@ #include "zcash/util.h" #include -#include +#include namespace libzcash { @@ -316,8 +316,7 @@ public: } bool AppendBundle(const OrchardBundle& bundle) { - return inner->append_bundle( - reinterpret_cast(bundle.inner.get())); + return inner->append_bundle(*bundle.GetDetails()); } const uint256 root() const { diff --git a/src/zcash/Note.hpp b/src/zcash/Note.hpp index 9bba0b896..731ece937 100644 --- a/src/zcash/Note.hpp +++ b/src/zcash/Note.hpp @@ -11,7 +11,7 @@ #include #include -#include +#include namespace libzcash { diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp index d633a9a3c..379090e65 100644 --- a/src/zcbenchmarks.cpp +++ b/src/zcbenchmarks.cpp @@ -35,8 +35,8 @@ #include "zcash/Note.hpp" #include "librustzcash.h" +#include #include -#include using namespace libzcash; // This method is based on Shutdown from init.cpp