rust: Move history tree FFI logic into a module

This commit is contained in:
Jack Grigg 2021-06-17 01:54:39 +01:00
parent b0e6119551
commit fbeb9412f2
3 changed files with 183 additions and 180 deletions

181
src/rust/src/history_ffi.rs Normal file
View File

@ -0,0 +1,181 @@
use std::slice;
use libc::{c_uchar, size_t};
use zcash_history::{Entry as MMREntry, NodeData as MMRNodeData, Tree as MMRTree};
fn construct_mmr_tree(
// Consensus branch id
cbranch: u32,
// Length of tree in array representation
t_len: u32,
// Indices of provided tree nodes, length of p_len+e_len
ni_ptr: *const u32,
// Provided tree nodes data, length of p_len+e_len
n_ptr: *const [c_uchar; zcash_history::MAX_ENTRY_SIZE],
// Peaks count
p_len: size_t,
// Extra nodes loaded (for deletion) count
e_len: size_t,
) -> Result<MMRTree, &'static str> {
let (indices, nodes) = unsafe {
(
slice::from_raw_parts(ni_ptr, p_len + e_len),
slice::from_raw_parts(n_ptr, p_len + e_len),
)
};
let mut peaks: Vec<_> = indices
.iter()
.zip(nodes.iter())
.map(
|(index, node)| match MMREntry::from_bytes(cbranch, &node[..]) {
Ok(entry) => Ok((*index, entry)),
Err(_) => Err("Invalid encoding"),
},
)
.collect::<Result<_, _>>()?;
let extra = peaks.split_off(p_len);
Ok(MMRTree::new(t_len, peaks, extra))
}
#[no_mangle]
pub extern "system" fn librustzcash_mmr_append(
// Consensus branch id
cbranch: u32,
// Length of tree in array representation
t_len: u32,
// Indices of provided tree nodes, length of p_len
ni_ptr: *const u32,
// Provided tree nodes data, length of p_len
n_ptr: *const [c_uchar; zcash_history::MAX_ENTRY_SIZE],
// Peaks count
p_len: size_t,
// New node pointer
nn_ptr: *const [u8; zcash_history::MAX_NODE_DATA_SIZE],
// Return of root commitment
rt_ret: *mut [u8; 32],
// Return buffer for appended leaves, should be pre-allocated of ceiling(log2(t_len)) length
buf_ret: *mut [c_uchar; zcash_history::MAX_NODE_DATA_SIZE],
) -> u32 {
let new_node_bytes: &[u8; zcash_history::MAX_NODE_DATA_SIZE] = unsafe {
match nn_ptr.as_ref() {
Some(r) => r,
None => {
return 0;
} // Null pointer passed, error
}
};
let mut tree = match construct_mmr_tree(cbranch, t_len, ni_ptr, n_ptr, p_len, 0) {
Ok(t) => t,
_ => {
return 0;
} // error
};
let node = match MMRNodeData::from_bytes(cbranch, &new_node_bytes[..]) {
Ok(node) => node,
_ => {
return 0;
} // error
};
let appended = match tree.append_leaf(node) {
Ok(appended) => appended,
_ => {
return 0;
}
};
let return_count = appended.len();
let root_node = tree
.root_node()
.expect("Just added, should resolve always; qed");
unsafe {
*rt_ret = root_node.data().hash();
for (idx, next_buf) in slice::from_raw_parts_mut(buf_ret, return_count as usize)
.iter_mut()
.enumerate()
{
tree.resolve_link(appended[idx])
.expect("This was generated by the tree and thus resolvable; qed")
.data()
.write(&mut &mut next_buf[..])
.expect("Write using cursor with enough buffer size cannot fail; qed");
}
}
return_count as u32
}
#[no_mangle]
pub extern "system" fn librustzcash_mmr_delete(
// Consensus branch id
cbranch: u32,
// Length of tree in array representation
t_len: u32,
// Indices of provided tree nodes, length of p_len+e_len
ni_ptr: *const u32,
// Provided tree nodes data, length of p_len+e_len
n_ptr: *const [c_uchar; zcash_history::MAX_ENTRY_SIZE],
// Peaks count
p_len: size_t,
// Extra nodes loaded (for deletion) count
e_len: size_t,
// Return of root commitment
rt_ret: *mut [u8; 32],
) -> u32 {
let mut tree = match construct_mmr_tree(cbranch, t_len, ni_ptr, n_ptr, p_len, e_len) {
Ok(t) => t,
_ => {
return 0;
} // error
};
let truncate_len = match tree.truncate_leaf() {
Ok(v) => v,
_ => {
return 0;
} // Error
};
unsafe {
*rt_ret = tree
.root_node()
.expect("Just generated without errors, root should be resolving")
.data()
.hash();
}
truncate_len
}
#[no_mangle]
pub extern "system" fn librustzcash_mmr_hash_node(
cbranch: u32,
n_ptr: *const [u8; zcash_history::MAX_NODE_DATA_SIZE],
h_ret: *mut [u8; 32],
) -> u32 {
let node_bytes: &[u8; zcash_history::MAX_NODE_DATA_SIZE] = unsafe {
match n_ptr.as_ref() {
Some(r) => r,
None => return 1,
}
};
let node = match MMRNodeData::from_bytes(cbranch, &node_bytes[..]) {
Ok(n) => n,
_ => return 1, // error
};
unsafe {
*h_ret = node.hash();
}
0
}

View File

@ -61,14 +61,13 @@ use zcash_proofs::{
sprout, sprout,
}; };
use zcash_history::{Entry as MMREntry, NodeData as MMRNodeData, Tree as MMRTree};
mod blake2b; mod blake2b;
mod ed25519; mod ed25519;
mod metrics_ffi; mod metrics_ffi;
mod streams_ffi; mod streams_ffi;
mod tracing_ffi; mod tracing_ffi;
mod history_ffi;
mod orchard_ffi; mod orchard_ffi;
mod transaction_ffi; mod transaction_ffi;
@ -1092,183 +1091,6 @@ pub extern "C" fn librustzcash_zip32_xfvk_address(
true true
} }
fn construct_mmr_tree(
// Consensus branch id
cbranch: u32,
// Length of tree in array representation
t_len: u32,
// Indices of provided tree nodes, length of p_len+e_len
ni_ptr: *const u32,
// Provided tree nodes data, length of p_len+e_len
n_ptr: *const [c_uchar; zcash_history::MAX_ENTRY_SIZE],
// Peaks count
p_len: size_t,
// Extra nodes loaded (for deletion) count
e_len: size_t,
) -> Result<MMRTree, &'static str> {
let (indices, nodes) = unsafe {
(
slice::from_raw_parts(ni_ptr, p_len + e_len),
slice::from_raw_parts(n_ptr, p_len + e_len),
)
};
let mut peaks: Vec<_> = indices
.iter()
.zip(nodes.iter())
.map(
|(index, node)| match MMREntry::from_bytes(cbranch, &node[..]) {
Ok(entry) => Ok((*index, entry)),
Err(_) => Err("Invalid encoding"),
},
)
.collect::<Result<_, _>>()?;
let extra = peaks.split_off(p_len);
Ok(MMRTree::new(t_len, peaks, extra))
}
#[no_mangle]
pub extern "system" fn librustzcash_mmr_append(
// Consensus branch id
cbranch: u32,
// Length of tree in array representation
t_len: u32,
// Indices of provided tree nodes, length of p_len
ni_ptr: *const u32,
// Provided tree nodes data, length of p_len
n_ptr: *const [c_uchar; zcash_history::MAX_ENTRY_SIZE],
// Peaks count
p_len: size_t,
// New node pointer
nn_ptr: *const [u8; zcash_history::MAX_NODE_DATA_SIZE],
// Return of root commitment
rt_ret: *mut [u8; 32],
// Return buffer for appended leaves, should be pre-allocated of ceiling(log2(t_len)) length
buf_ret: *mut [c_uchar; zcash_history::MAX_NODE_DATA_SIZE],
) -> u32 {
let new_node_bytes: &[u8; zcash_history::MAX_NODE_DATA_SIZE] = unsafe {
match nn_ptr.as_ref() {
Some(r) => r,
None => {
return 0;
} // Null pointer passed, error
}
};
let mut tree = match construct_mmr_tree(cbranch, t_len, ni_ptr, n_ptr, p_len, 0) {
Ok(t) => t,
_ => {
return 0;
} // error
};
let node = match MMRNodeData::from_bytes(cbranch, &new_node_bytes[..]) {
Ok(node) => node,
_ => {
return 0;
} // error
};
let appended = match tree.append_leaf(node) {
Ok(appended) => appended,
_ => {
return 0;
}
};
let return_count = appended.len();
let root_node = tree
.root_node()
.expect("Just added, should resolve always; qed");
unsafe {
*rt_ret = root_node.data().hash();
for (idx, next_buf) in slice::from_raw_parts_mut(buf_ret, return_count as usize)
.iter_mut()
.enumerate()
{
tree.resolve_link(appended[idx])
.expect("This was generated by the tree and thus resolvable; qed")
.data()
.write(&mut &mut next_buf[..])
.expect("Write using cursor with enough buffer size cannot fail; qed");
}
}
return_count as u32
}
#[no_mangle]
pub extern "system" fn librustzcash_mmr_delete(
// Consensus branch id
cbranch: u32,
// Length of tree in array representation
t_len: u32,
// Indices of provided tree nodes, length of p_len+e_len
ni_ptr: *const u32,
// Provided tree nodes data, length of p_len+e_len
n_ptr: *const [c_uchar; zcash_history::MAX_ENTRY_SIZE],
// Peaks count
p_len: size_t,
// Extra nodes loaded (for deletion) count
e_len: size_t,
// Return of root commitment
rt_ret: *mut [u8; 32],
) -> u32 {
let mut tree = match construct_mmr_tree(cbranch, t_len, ni_ptr, n_ptr, p_len, e_len) {
Ok(t) => t,
_ => {
return 0;
} // error
};
let truncate_len = match tree.truncate_leaf() {
Ok(v) => v,
_ => {
return 0;
} // Error
};
unsafe {
*rt_ret = tree
.root_node()
.expect("Just generated without errors, root should be resolving")
.data()
.hash();
}
truncate_len
}
#[no_mangle]
pub extern "system" fn librustzcash_mmr_hash_node(
cbranch: u32,
n_ptr: *const [u8; zcash_history::MAX_NODE_DATA_SIZE],
h_ret: *mut [u8; 32],
) -> u32 {
let node_bytes: &[u8; zcash_history::MAX_NODE_DATA_SIZE] = unsafe {
match n_ptr.as_ref() {
Some(r) => r,
None => return 1,
}
};
let node = match MMRNodeData::from_bytes(cbranch, &node_bytes[..]) {
Ok(n) => n,
_ => return 1, // error
};
unsafe {
*h_ret = node.hash();
}
0
}
#[no_mangle] #[no_mangle]
pub extern "C" fn librustzcash_getrandom(buf: *mut u8, buf_len: usize) { pub extern "C" fn librustzcash_getrandom(buf: *mut u8, buf_len: usize) {
let buf = unsafe { slice::from_raw_parts_mut(buf, buf_len) }; let buf = unsafe { slice::from_raw_parts_mut(buf, buf_len) };

View File

@ -1,6 +1,6 @@
use zcash_history::{Entry, EntryLink, NodeData}; use zcash_history::{Entry, EntryLink, NodeData};
use crate::{librustzcash_mmr_append, librustzcash_mmr_delete}; use crate::history_ffi::{librustzcash_mmr_append, librustzcash_mmr_delete};
const NODE_DATA_16L: &[u8] = include_bytes!("./res/tree16.dat"); const NODE_DATA_16L: &[u8] = include_bytes!("./res/tree16.dat");
const NODE_DATA_1023L: &[u8] = include_bytes!("./res/tree1023.dat"); const NODE_DATA_1023L: &[u8] = include_bytes!("./res/tree1023.dat");