From bba5f671894d50e1219e193e862ed6fbabeb533c Mon Sep 17 00:00:00 2001 From: Erin Swenson-Healey Date: Mon, 30 Jul 2018 10:10:56 -0700 Subject: [PATCH] Modify seal function to be callable from C (#99) * modify seal function to be callable from cgo - can't pass arrays by value in C; need to pass pointer to first cell - seal accepts pointer to result-array so that callers manage memory instead of Rust * line reorg * rename symbol * apply cargo fmt * add comments for seal parameters * create lib crate-type for Rust tests * dylib seems to work with cgo * kick off ci --- Cargo.toml | 3 ++ src/api/mod.rs | 118 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 117 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6a1b6951..57c7483d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,9 @@ name = "proofs" version = "0.1.0" authors = ["dignifiedquire "] +[lib] +crate-type = ["rlib", "dylib"] + [dependencies] sapling-crypto = { git = "https://github.com/zcash-hackworks/sapling-crypto", branch = "master" } rand = "0.4" diff --git a/src/api/mod.rs b/src/api/mod.rs index 101c2809..17c9437f 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,14 +1,24 @@ use libc; use std::ffi::{CStr, CString}; +use std::slice; type CstrT = *const libc::c_char; type SectorID = i32; type Commitment = u32; type ProverID = [u8; 31]; +type ChallengeSeed = [u32; 8]; +type RandomSeed = [u32; 8]; + +// arrays cannot be passed by value in C; callers instead pass a pointer to the +// head and Rust makes runtime assertions of length while marshaling +type ProverIDPtr = *const u8; +type ChallengeSeedPtr = *const u32; +type RandomSeedPtr = *const u32; +type ResultPtr = *const Commitment; type SectorAccess = CstrT; -type SectorAccessor = extern "C" fn(i: SectorID) -> CstrT; +type SectorAccessor = extern "C" fn(i: SectorID) -> SectorAccess; fn from_cstr(c_str: CstrT) -> String { unsafe { @@ -19,6 +29,38 @@ fn from_cstr(c_str: CstrT) -> String { } } +fn u32ptr_to_array8(x: *const u32) -> [u32; 8] { + let s = unsafe { slice::from_raw_parts(x, 8).to_owned() }; + + assert_eq!( + s.len(), + 8, + "actual len(s) = {}, expected len(s) = {}", + s.len(), + 8 + ); + + let mut out: [u32; 8] = Default::default(); + out.copy_from_slice(&s[0..8]); + out +} + +fn u8ptr_to_array31(x: *const u8) -> [u8; 31] { + let s = unsafe { slice::from_raw_parts(x, 31).to_owned() }; + + assert_eq!( + s.len(), + 31, + "actual len(s) = {}, expected len(s) = {}", + s.len(), + 31 + ); + + let mut out: [u8; 31] = Default::default(); + out.copy_from_slice(&s[0..31]); + out +} + fn to_cstring(s: &str) -> CString { CString::new(s).unwrap() } @@ -26,14 +68,60 @@ fn to_cstring(s: &str) -> CString { const DUMMY_COMM_R: Commitment = 12345; const DUMMY_COMM_D: Commitment = 54321; +/// Seals a sector. +/// +/// # Arguments +/// +/// * `sector_id` - identity of the unsealed sector +/// * `unsealed` - function pointer used to get access to unsealed +/// sector +/// * `sealed` - function pointer used to get access to sealed +/// sector +/// * `_prover_id_ptr` - pointer to first cell in a 31-length array of u8 +/// * `_challenge_seed_ptr` - pointer to first cell in a 8-length array of u32 +/// * `_random_seed_ptr` - pointer to first cell in a 8-length array of u32 +/// * `result_ptr` - pointer to first cell in a 2-length array of u32, +/// mutated by seal in order to pass commitments back +/// to caller +/// ``` #[no_mangle] pub extern "C" fn seal( + sector_id: SectorID, + unsealed: SectorAccessor, + sealed: SectorAccessor, + _prover_id_ptr: ProverIDPtr, + _challenge_seed_ptr: ChallengeSeedPtr, + _random_seed_ptr: RandomSeedPtr, + result_ptr: ResultPtr, +) -> () { + let prover_id = u8ptr_to_array31(_prover_id_ptr); + let challenge_seed = u32ptr_to_array8(_challenge_seed_ptr); + let random_seed = u32ptr_to_array8(_random_seed_ptr); + + let comms = seal_internal( + sector_id, + unsealed, + sealed, + prover_id, + challenge_seed, + random_seed, + ); + + // let caller manage this memory, preventing the need for calling back into + // Rust code later to deallocate + unsafe { + *(result_ptr.offset(0 as isize) as *mut u32) = comms[0]; + *(result_ptr.offset(1 as isize) as *mut u32) = comms[1]; + }; +} + +fn seal_internal( sector_id: SectorID, unsealed: SectorAccessor, sealed: SectorAccessor, _prover_id: ProverID, - _challenge_seed: [u32; 8], - _random_seed: [u32; 8], + _challenge_seed: ChallengeSeed, + _random_seed: RandomSeed, ) -> [Commitment; 2] { let _in_path = from_cstr(unsealed(sector_id)); let _out_path = from_cstr(sealed(sector_id)); @@ -73,7 +161,29 @@ mod tests { #[test] fn seal_verify() { - let comms = seal( + let result: [u32; 2] = [0; 2]; + let prover_id: [u8; 31] = [1; 31]; + let challenge_seed: [u32; 8] = [2; 8]; + let random_seed: [u32; 8] = [3; 8]; + + seal( + 123, + sector_accessor, + sector_accessor, + &prover_id[0], + &challenge_seed[0], + &random_seed[0], + &result[0], + ); + + assert_ne!(result[0], result[1]); + assert!(verifySeal(result[0], result[1])); + assert!(!verifySeal(result[1], result[0])); + } + + #[test] + fn seal_internal_verify() { + let comms = seal_internal( 123, sector_accessor, sector_accessor,