Add orchard_bundle FFI.

Co-authored-by: Jack Grigg <jack@electriccoin.co>
This commit is contained in:
therealyingtong 2022-06-03 20:46:30 +08:00
parent bb64e895c2
commit d18fcc7092
3 changed files with 147 additions and 3 deletions

View File

@ -47,13 +47,16 @@ endif
# TODO: Figure out how to avoid an explicit file list.
CXXBRIDGE_RS = \
rust/src/blake2b.rs \
rust/src/equihash.rs
rust/src/equihash.rs \
rust/src/orchard_bundle.rs
CXXBRIDGE_H = \
rust/gen/include/rust/blake2b.h \
rust/gen/include/rust/equihash.h
rust/gen/include/rust/equihash.h \
rust/gen/include/rust/orchard_bundle.h
CXXBRIDGE_CPP = \
rust/gen/src/blake2b.cpp \
rust/gen/src/equihash.cpp
rust/gen/src/equihash.cpp \
rust/gen/src/orchard_bundle.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.

View File

@ -0,0 +1,140 @@
use orchard::{
bundle::Authorized,
primitives::redpallas::{Signature, SpendAuth},
};
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<Bundle>;
fn actions(self: &Bundle) -> Vec<Action>;
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<u8>;
fn binding_sig(self: &Bundle) -> [u8; 64];
}
}
pub struct Action(orchard::Action<Signature<SpendAuth>>);
impl Action {
fn cv(&self) -> [u8; 32] {
self.0.cv_net().to_bytes()
}
fn nullifier(&self) -> [u8; 32] {
self.0.nullifier().to_bytes()
}
fn rk(&self) -> [u8; 32] {
self.0.rk().into()
}
fn cmx(&self) -> [u8; 32] {
self.0.cmx().to_bytes()
}
fn ephemeral_key(&self) -> [u8; 32] {
self.0.encrypted_note().epk_bytes
}
fn enc_ciphertext(&self) -> [u8; 580] {
self.0.encrypted_note().enc_ciphertext
}
fn out_ciphertext(&self) -> [u8; 80] {
self.0.encrypted_note().out_ciphertext
}
fn spend_auth_sig(&self) -> [u8; 64] {
self.0.authorization().into()
}
}
pub struct Bundle(Option<orchard::Bundle<Authorized, Amount>>);
pub struct OrchardBundle;
unsafe fn from_tx_bundle(bundle: *const OrchardBundle) -> Box<Bundle> {
Box::new(Bundle(
{ (bundle as *const orchard::Bundle<Authorized, Amount>).as_ref() }.cloned(),
))
}
impl Bundle {
fn actions(&self) -> Vec<Action> {
self.0
.iter()
.flat_map(|b| b.actions().iter())
.cloned()
.map(Action)
.collect()
}
fn num_actions(&self) -> usize {
self.0.as_ref().map(|b| b.actions().len()).unwrap_or(0)
}
fn enable_spends(&self) -> bool {
self.0
.as_ref()
.map(|b| b.flags().spends_enabled())
.unwrap_or(false)
}
fn enable_outputs(&self) -> bool {
self.0
.as_ref()
.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)
}
fn anchor(&self) -> [u8; 32] {
self.0
.as_ref()
.expect("Bundle actions should have been checked to be non-empty")
.anchor()
.to_bytes()
}
fn proof(&self) -> Vec<u8> {
self.0
.as_ref()
.expect("Bundle actions should have been checked to be non-empty")
.authorization()
.proof()
.as_ref()
.to_vec()
}
fn binding_sig(&self) -> [u8; 64] {
self.0
.as_ref()
.expect("Bundle actions should have been checked to be non-empty")
.authorization()
.binding_signature()
.into()
}
}

View File

@ -78,6 +78,7 @@ mod history_ffi;
mod incremental_merkle_tree;
mod incremental_merkle_tree_ffi;
mod init_ffi;
mod orchard_bundle;
mod orchard_ffi;
mod orchard_keys_ffi;
mod transaction_ffi;