Rust 编译为 C 接口 Native Library 时的 panic 处理
问题代码
例如这份代码
// WARNING still updating the code, it works, but is still in process the refactor.
pub mod eddsa;
use poseidon_rs::Poseidon;
pub type Fr = poseidon_rs::Fr;
#[macro_use]
extern crate ff;
#[macro_use]
extern crate arrayref;
extern crate generic_array;
//extern crate mimc_rs;
extern crate num;
extern crate num_bigint;
extern crate num_traits;
extern crate rand6;
extern crate rand;
extern crate blake; // compatible version with Blake used at circomlib
#[macro_use]
extern crate lazy_static;
use ff::*;
use std::str;
use crate::eddsa::{Signature, decompress_point, Point, PrivateKey, verify, decompress_signature, /*compress_point,*/ PointProjective, Q, B8, new_key};
use num_bigint::{Sign, BigInt, ToBigInt};
use std::os::raw::{c_char};
use std::ffi::{CStr, CString};
use std::cmp::min;
use std::str::FromStr;
use num_traits::{Num, ToPrimitive};
use rustc_hex::{FromHex, ToHex};
use num::Zero;
/*lazy_static! {
static ref B8: Point = Point {
x: Fr::from_str(
"5299619240641551281634865583518297030282874472190772894086521144482721001553",
)
.unwrap(),
y: Fr::from_str(
"16950150798460657717958625567821834550301663161624707787222815936182638968203",
)
.unwrap(),
// z: Fr::one(),
};
}*/
#[no_mangle]
pub extern fn pack_signature(signature: *const c_char) -> *mut c_char {
let signature_cstr = unsafe { CStr::from_ptr(signature) };
let signature_str = match signature_cstr.to_str() {
Err(_) => "there",
Ok(string) => string,
};
let signature_bytes_raw = signature_str.from_hex().unwrap();
let mut signature_bytes: [u8; 64] = [0; 64];
signature_bytes.copy_from_slice(&signature_bytes_raw);
let r_b8_bytes: [u8; 32] = *array_ref!(signature_bytes[..32], 0, 32);
let s: BigInt = BigInt::from_bytes_le(Sign::Plus, &signature_bytes[32..]);
//let x_big = BigInt::parse_bytes(&r_b8_bytes[..16], 16).unwrap();
//let y_big = BigInt::parse_bytes(&r_b8_bytes[16..], 16).unwrap();
/*let (_, x_bytes) = x_big.to_bytes_le();
let (_, y_bytes) = y_big.to_bytes_le();
let mut x_16bytes: [u8; 16] = [0; 16];
let lenx = min(x_bytes.len(), x_16bytes.len());
x_16bytes[..lenx].copy_from_slice(&x_bytes[..lenx]);
b.append(&mut x_16bytes.to_vec());
let mut y_16bytes: [u8; 16] = [0; 16];
let leny = min(y_bytes.len(), y_16bytes.len());
y_16bytes[..leny].copy_from_slice(&y_bytes[..leny]);
b.append(&mut y_16bytes.to_vec());*/
//let x_string = to_hex_string(r_b8_bytes[..16].to_vec());
//let x_str = x_string.as_str();
//let y_string = to_hex_string(r_b8_bytes[16..].to_vec());
//let r_b8 = decompress_point(r_b8_bytes).unwrap();
//let y_str = y_string.as_str();
//let x_big = BigInt::parse_bytes(&r_b8_bytes[0..15], 16).unwrap();
//let y_big = BigInt::parse_bytes(&r_b8_bytes[15..32], 16).unwrap();
let x_big: BigInt = BigInt::from_bytes_le(Sign::Plus, &r_b8_bytes[0..15]);
let y_big: BigInt = BigInt::from_bytes_le(Sign::Plus, &r_b8_bytes[15..32]);
//let y_big = x_big.clone();
let r_b8: Point = Point {
x: Fr::from_str(
&x_big.to_string(),
).unwrap(),
y: Fr::from_str(
&y_big.to_string(),
).unwrap(),
};
let sig = Signature { r_b8 : r_b8.clone(), s };
let res = sig.compress();
let hex_string = to_hex_string(res.to_vec());
CString::new(hex_string.as_str()).unwrap().into_raw()
}
#[no_mangle]
pub extern fn unpack_signature(compressed_signature: *const c_char) -> *mut c_char {
let compressed_signature_cstr = unsafe { CStr::from_ptr(compressed_signature) };
let compressed_signature_str = match compressed_signature_cstr.to_str() {
Err(_) => "there",
Ok(string) => string,
};
let compressed_signature_bytes_raw = compressed_signature_str.from_hex().unwrap();
let mut compressed_signature_bytes: [u8; 64] = [0; 64];
compressed_signature_bytes.copy_from_slice(&compressed_signature_bytes_raw);
let decompressed_sig = decompress_signature(&compressed_signature_bytes).unwrap();
let mut b: Vec<u8> = Vec::new();
let x_big = BigInt::parse_bytes(to_hex(&decompressed_sig.r_b8.x).as_bytes(), 16).unwrap();
let y_big = BigInt::parse_bytes(to_hex(&decompressed_sig.r_b8.y).as_bytes(), 16).unwrap();
let (_, x_bytes) = x_big.to_bytes_le();
let (_, y_bytes) = y_big.to_bytes_le();
let mut x_16bytes: [u8; 16] = [0; 16];
let lenx = min(x_bytes.len(), x_16bytes.len());
x_16bytes[..lenx].copy_from_slice(&x_bytes[..lenx]);
b.append(&mut x_16bytes.to_vec());
let mut y_16bytes: [u8; 16] = [0; 16];
let leny = min(y_bytes.len(), y_16bytes.len());
y_16bytes[..leny].copy_from_slice(&y_bytes[..leny]);
b.append(&mut y_16bytes.to_vec());
let (_, s_bytes) = decompressed_sig.s.to_bytes_le();
let mut s_32bytes: [u8; 32] = [0; 32];
let lens = min(s_bytes.len(), s_32bytes.len());
s_32bytes[..lens].copy_from_slice(&s_bytes[..lens]);
b.append(&mut s_32bytes.to_vec());
let mut r: [u8; 64] = [0; 64];
let res_len = min(r.len(), b.len());
r[..res_len].copy_from_slice(&b[..res_len]);
let hex_string = to_hex_string(r.to_vec());
CString::new(hex_string.as_str()).unwrap().into_raw()
}
fn vector_as_u8_64_array(vector: Vec<u8>) -> [u8; 64] {
let mut arr = [0u8;64];
for (place, element) in arr.iter_mut().zip(vector.iter()) {
*place = *element;
}
arr
}
#[no_mangle]
pub extern fn pack_point(point_x: *const c_char, point_y: *const c_char) -> *mut c_char {
let point_x_cstr = unsafe { CStr::from_ptr(point_x) };
let point_x_str = match point_x_cstr.to_str() {
Err(_) => "there",
Ok(string) => string,
};
let point_y_cstr = unsafe { CStr::from_ptr(point_y) };
let point_y_str = match point_y_cstr.to_str() {
Err(_) => "there",
Ok(string) => string,
};
let p: Point = Point {
x: Fr::from_str(point_x_str).unwrap(),
y: Fr::from_str(point_y_str).unwrap(),
};
let compressed_point = p.compress();
let hex_string = to_hex_string(compressed_point.to_vec());
CString::new(hex_string.as_str()).unwrap().into_raw()
}
pub fn to_hex_string(bytes: Vec<u8>) -> String {
let strs: Vec<String> = bytes.iter()
.map(|b| format!("{:02X}", b))
.collect();
strs.join("")
}
#[no_mangle]
pub extern fn unpack_point(compressed_point: *const c_char) -> *mut c_char {
let compressed_point_str = unsafe { CStr::from_ptr(compressed_point) }.to_str().unwrap();
let y_bytes_raw = compressed_point_str.from_hex().unwrap();
let mut y_bytes: [u8; 32] = [0; 32];
y_bytes.copy_from_slice(&y_bytes_raw);
let p = decompress_point(y_bytes).unwrap();
let x_big = BigInt::parse_bytes(to_hex(&p.x).as_bytes(), 16).unwrap();
let y_big = BigInt::parse_bytes(to_hex(&p.y).as_bytes(), 16).unwrap();
let mut result_string: String = "".to_owned();
result_string.push_str(&x_big.to_string());
result_string.push_str(",");
result_string.push_str(&y_big.to_string());
CString::new(result_string.as_str()).unwrap().into_raw()
}
#[no_mangle]
pub extern fn prv2pub(private_key: *const c_char) -> *mut c_char {
/*let private_key_bytes: [u8; 32] = *array_ref!(private_key[..32], 0, 32);
let private_key = PrivateKey::import(private_key_bytes.to_vec()).unwrap();*/
let private_key_str = unsafe { CStr::from_ptr(private_key) }.to_str().unwrap();
//let pk_bigint = BigInt::from_str(private_key_str).unwrap();
let pk_bytes_raw = private_key_str.from_hex().unwrap();
let mut pk_bytes: [u8; 32] = [0; 32];
pk_bytes.copy_from_slice(&pk_bytes_raw);
let pk = PrivateKey { key: pk_bytes };
let public_key = pk.public();
let mut result_string: String = "".to_owned();
result_string.push_str(&public_key.x.to_string());
result_string.push_str(",");
result_string.push_str(&public_key.y.to_string());
CString::new(result_string.as_str()).unwrap().into_raw()
}
#[no_mangle]
pub extern fn poseidon_hash(input: *const c_char) -> *mut c_char {
let input_str = unsafe { CStr::from_ptr(input) }.to_str().unwrap();
let b0: Fr = Fr::from_str(input_str).unwrap();
let hm_input = vec![b0.clone()];
//let hm_input = vec![x.clone(), y.clone(), z.clone()];
let poseidon = Poseidon::new();
let hm = poseidon.hash(hm_input).unwrap();
return CString::new(to_hex(&hm).as_str()).unwrap().into_raw();
}
#[no_mangle]
//pub extern fn hash_poseidon(tx_compressed_data: *const c_char, to_eth_addr: *const c_char, to_bjj_ay: *const c_char, rq_txcompressed_data_v2: *const c_char, rq_to_eth_addr: *const c_char, rq_to_bjj_ay: *const c_char) -> *mut c_char {
pub extern fn hash_poseidon(claims_tree: *const c_char, revocation_tree: *const c_char, roots_tree_root: *const c_char) -> *mut c_char {
//let claims_tree_str = unsafe { CStr::from_ptr(claims_tree) }.to_str().unwrap();
//let claims_tree_bigint = match claims_tree_str.parse::<i32>() {
// Ok(n) => BigInt::from(n),
// Err(e) => BigInt::zero(),
// };
//let b0: Fr = Fr::from_str(
// &claims_tree_bigint.to_string(),
// ).unwrap();
//let revocation_tree_str = unsafe { CStr::from_ptr(revocation_tree) }.to_str().unwrap();
//let revocation_tree_bigint = match revocation_tree_str.parse::<i32>() {
// Ok(n) => BigInt::from(n),
// Err(e) => BigInt::zero(),
// };
//let b1: Fr = Fr::from_str(
// &revocation_tree_bigint.to_string(),
// ).unwrap();
//let roots_tree_root_str = unsafe { CStr::from_ptr(roots_tree_root) }.to_str().unwrap();
// let roots_tree_root_bigint = match roots_tree_root_str.parse::<i32>() {
// Ok(n) => BigInt::from(n),
// Err(e) => BigInt::zero(),
// };
// let b2: Fr = Fr::from_str(
// &roots_tree_root_bigint.to_string(),
// ).unwrap();
//let x: Fr = Fr::from_str(
// "4648350302718598839424502774166524253703556728225603109003078358379460427828",
// ).unwrap();
//let x: Fr = Fr::from_str(
// "23520646440406697341854711669252473191475099932451150382882460752222516889098").unwrap();
//let y: Fr = Fr::zero();
//let z: Fr = Fr::zero();
let claims_tree_str = unsafe { CStr::from_ptr(claims_tree) }.to_str().unwrap();
let b0: Fr = Fr::from_str(claims_tree_str).unwrap();
let revocation_tree_str = unsafe { CStr::from_ptr(revocation_tree) }.to_str().unwrap();
let b1: Fr = Fr::from_str(revocation_tree_str).unwrap();
let roots_tree_root_str = unsafe { CStr::from_ptr(roots_tree_root) }.to_str().unwrap();
let b2: Fr = Fr::from_str(roots_tree_root_str).unwrap();
//if to_eth_addr.is_null() {
// let to_eth_addr_str = unsafe { CStr::from_ptr(to_eth_addr) }.to_str().unwrap();
// let b1: Fr = Fr::from_str(to_eth_addr_str).unwrap();
// let mut b1_input = vec![b1.clone()];
// hm_input.append(&mut b1_input);
//}
//if to_bjj_ay.is_null() {
// let to_bjj_ay_str = unsafe { CStr::from_ptr(to_bjj_ay) }.to_str().unwrap();
// let b2: Fr = Fr::from_str(to_bjj_ay_str).unwrap();
// let mut b2_input = vec![b2.clone()];
// hm_input.append(&mut b2_input);
//}
//if rq_txcompressed_data_v2.is_null() {
// let rq_txcompressed_data_v2_str = unsafe { CStr::from_ptr(rq_txcompressed_data_v2) }.to_str().unwrap();
// let b3: Fr = Fr::from_str(rq_txcompressed_data_v2_str).unwrap();
// let mut b3_input = vec![b3.clone()];
// hm_input.append(&mut b3_input);
//}
//if rq_to_eth_addr.is_null() {
// let rq_to_eth_addr_str = unsafe { CStr::from_ptr(rq_to_eth_addr) }.to_str().unwrap();
// let b4: Fr = Fr::from_str(rq_to_eth_addr_str).unwrap();
// let mut b4_input = vec![b4.clone()];
// hm_input.append(&mut b4_input);
//}
//if rq_to_bjj_ay.is_null() {
// let rq_to_bjj_ay_str = unsafe { CStr::from_ptr(rq_to_bjj_ay) }.to_str().unwrap();
// let b5: Fr = Fr::from_str(rq_to_bjj_ay_str).unwrap();
// let mut b5_input = vec![b5.clone()];
// hm_input.append(&mut b5_input);
//}
let hm_input = vec![b0.clone(), b1.clone(), b2.clone()];
//let hm_input = vec![x.clone(), y.clone(), z.clone()];
let poseidon = Poseidon::new();
let hm = poseidon.hash(hm_input).unwrap();
return CString::new(to_hex(&hm).as_str()).unwrap().into_raw();
}
#[no_mangle]
pub extern fn sign_poseidon(private_key: *const c_char, msg: *const c_char) -> *mut c_char {
let private_key_str = unsafe { CStr::from_ptr(private_key) }.to_str().unwrap();
//let pk_bigint = BigInt::from_str(private_key_str).unwrap();
let pk_bytes_raw = private_key_str.from_hex().unwrap();
let mut pk_bytes: [u8; 32] = [0; 32];
pk_bytes.copy_from_slice(&pk_bytes_raw);
let pk = PrivateKey { key: pk_bytes };
let message_str = unsafe { CStr::from_ptr(msg) }.to_str().unwrap();
let message_bigint = BigInt::from_str(message_str).unwrap();
let sig = pk.sign(message_bigint.clone()).unwrap();
let compressed_signature = sig.compress();
let hex_string = compressed_signature.to_hex();
CString::new(hex_string.as_str()).unwrap().into_raw()
}
#[no_mangle]
pub extern fn verify_poseidon(private_key: *const c_char, compressed_signature: *const c_char, message: *const c_char) -> *mut c_char {
let private_key_str = unsafe { CStr::from_ptr(private_key) }.to_str().unwrap();
// let pk_bigint = BigInt::from_str(private_key_str).unwrap();
let pk_bytes_raw = private_key_str.from_hex().unwrap();
let mut pk_bytes: [u8; 32] = [0; 32];
pk_bytes.copy_from_slice(&pk_bytes_raw);
let pk = PrivateKey { key: pk_bytes };
let compressed_signature_str = unsafe { CStr::from_ptr(compressed_signature) }.to_str().unwrap();
let signature_bytes_raw = compressed_signature_str.from_hex().unwrap();
let mut signature_bytes: [u8; 64] = [0; 64];
signature_bytes.copy_from_slice(&signature_bytes_raw);
let sig = decompress_signature(&signature_bytes).unwrap();
let message_c_str = unsafe { CStr::from_ptr(message) };
let message_str = match message_c_str.to_str() {
Err(_) => "there",
Ok(string) => string,
};
let message_bigint = match message_str.parse::<i32>() {
Ok(n) => BigInt::from(n),
Err(e) => BigInt::zero(),
};
if verify(pk.public(), sig.clone(), message_bigint.clone()) {
CString::new("1".to_owned()).unwrap().into_raw()
} else {
CString::new("0".to_owned()).unwrap().into_raw()
}
}
#[no_mangle]
pub extern fn cstring_free(str: *mut c_char) {
unsafe {
if str.is_null() { return }
CString::from_raw(str)
};
}
问题原因
里面有大量的未经判断的不安全unwrap,这些未经判断的unwrap 会导致 panic。
而 Rust 默认的 panic 行为是直接退出程序,这样就会导致调用这个 Native Library 的程序也会退出。
try catch?
这个 rust 代码提供了 c 语言接口的函数。
如果我们在 c 语言中试图用 try-catch 保护,会出现如下问题。

从打印日志可以看出, 虽然 panic 可以被 catch 到,但是如果不 throw 出去,还是会打印
fatal runtime error: Rust panics must be rethrown
解决方案
从https://doc.rust-lang.org里的这个文档 内容来看, 一旦 Panic 越过了 C 和 rust 之间的 boundary, 那么 panic 就无法被正确处理了。
文章的这部分也给出了解决方案: catch_unwind
所以我们只要在 rust 代码中用 catch_unwind 包裹住可能会 panic 的代码,就可以避免 panic 越过 boundary 了。
更新后的代码
// WARNING still updating the code, it works, but is still in process the refactor.
pub mod eddsa;
use poseidon_rs::Poseidon;
pub type Fr = poseidon_rs::Fr;
#[macro_use]
extern crate ff;
#[macro_use]
extern crate arrayref;
extern crate generic_array;
//extern crate mimc_rs;
extern crate num;
extern crate num_bigint;
extern crate num_traits;
extern crate rand6;
extern crate rand;
extern crate blake; // compatible version with Blake used at circomlib
#[macro_use]
extern crate lazy_static;
use ff::*;
use std::str;
use crate::eddsa::{Signature, decompress_point, Point, PrivateKey, verify, decompress_signature, /*compress_point,*/ PointProjective, Q, B8, new_key};
use num_bigint::{Sign, BigInt, ToBigInt};
use std::os::raw::{c_char};
use std::ffi::{CStr, CString};
use std::cmp::min;
use std::str::FromStr;
use num_traits::{Num, ToPrimitive};
use rustc_hex::{FromHex, ToHex};
use num::Zero;
use std::panic::catch_unwind;
/*lazy_static! {
static ref B8: Point = Point {
x: Fr::from_str(
"5299619240641551281634865583518297030282874472190772894086521144482721001553",
)
.unwrap(),
y: Fr::from_str(
"16950150798460657717958625567821834550301663161624707787222815936182638968203",
)
.unwrap(),
// z: Fr::one(),
};
}*/
#[no_mangle]
pub /*extern*/ fn pack_signature_internal(signature: *const c_char) -> *mut c_char {
let signature_cstr = unsafe { CStr::from_ptr(signature) };
let signature_str = match signature_cstr.to_str() {
Err(_) => "there",
Ok(string) => string,
};
let signature_bytes_raw = signature_str.from_hex().unwrap();
let mut signature_bytes: [u8; 64] = [0; 64];
signature_bytes.copy_from_slice(&signature_bytes_raw);
let r_b8_bytes: [u8; 32] = *array_ref!(signature_bytes[..32], 0, 32);
let s: BigInt = BigInt::from_bytes_le(Sign::Plus, &signature_bytes[32..]);
//let x_big = BigInt::parse_bytes(&r_b8_bytes[..16], 16).unwrap();
//let y_big = BigInt::parse_bytes(&r_b8_bytes[16..], 16).unwrap();
/*let (_, x_bytes) = x_big.to_bytes_le();
let (_, y_bytes) = y_big.to_bytes_le();
let mut x_16bytes: [u8; 16] = [0; 16];
let lenx = min(x_bytes.len(), x_16bytes.len());
x_16bytes[..lenx].copy_from_slice(&x_bytes[..lenx]);
b.append(&mut x_16bytes.to_vec());
let mut y_16bytes: [u8; 16] = [0; 16];
let leny = min(y_bytes.len(), y_16bytes.len());
y_16bytes[..leny].copy_from_slice(&y_bytes[..leny]);
b.append(&mut y_16bytes.to_vec());*/
//let x_string = to_hex_string(r_b8_bytes[..16].to_vec());
//let x_str = x_string.as_str();
//let y_string = to_hex_string(r_b8_bytes[16..].to_vec());
//let r_b8 = decompress_point(r_b8_bytes).unwrap();
//let y_str = y_string.as_str();
//let x_big = BigInt::parse_bytes(&r_b8_bytes[0..15], 16).unwrap();
//let y_big = BigInt::parse_bytes(&r_b8_bytes[15..32], 16).unwrap();
let x_big: BigInt = BigInt::from_bytes_le(Sign::Plus, &r_b8_bytes[0..15]);
let y_big: BigInt = BigInt::from_bytes_le(Sign::Plus, &r_b8_bytes[15..32]);
//let y_big = x_big.clone();
let x:Fr = Fr::from_str(
&x_big.to_string(),
).unwrap();
let y:Fr = Fr::from_str(
&y_big.to_string(),
).unwrap();
let r_b8: Point = Point {
x: x,
y: y,
};
let sig = Signature { r_b8 : r_b8.clone(), s };
let res = sig.compress();
let hex_string = to_hex_string(res.to_vec());
CString::new(hex_string.as_str()).unwrap().into_raw()
}
#[no_mangle]
pub extern fn pack_signature(signature: *const c_char) -> *mut c_char {
let result = catch_unwind(|| pack_signature_internal(signature));
match result {
Ok(res) => res,
Err(e) => {
println!("pack_signature Rust Err: {:?}", e);
std::ptr::null_mut()
}
}
}
#[no_mangle]
pub /*extern*/ fn unpack_signature_internal(compressed_signature: *const c_char) -> *mut c_char {
let compressed_signature_cstr = unsafe { CStr::from_ptr(compressed_signature) };
let compressed_signature_str = match compressed_signature_cstr.to_str() {
Err(_) => "there",
Ok(string) => string,
};
let compressed_signature_bytes_raw = compressed_signature_str.from_hex().unwrap();
let mut compressed_signature_bytes: [u8; 64] = [0; 64];
compressed_signature_bytes.copy_from_slice(&compressed_signature_bytes_raw);
let decompressed_sig = decompress_signature(&compressed_signature_bytes).unwrap();
let mut b: Vec<u8> = Vec::new();
let x_big = BigInt::parse_bytes(to_hex(&decompressed_sig.r_b8.x).as_bytes(), 16).unwrap();
let y_big = BigInt::parse_bytes(to_hex(&decompressed_sig.r_b8.y).as_bytes(), 16).unwrap();
let (_, x_bytes) = x_big.to_bytes_le();
let (_, y_bytes) = y_big.to_bytes_le();
let mut x_16bytes: [u8; 16] = [0; 16];
let lenx = min(x_bytes.len(), x_16bytes.len());
x_16bytes[..lenx].copy_from_slice(&x_bytes[..lenx]);
b.append(&mut x_16bytes.to_vec());
let mut y_16bytes: [u8; 16] = [0; 16];
let leny = min(y_bytes.len(), y_16bytes.len());
y_16bytes[..leny].copy_from_slice(&y_bytes[..leny]);
b.append(&mut y_16bytes.to_vec());
let (_, s_bytes) = decompressed_sig.s.to_bytes_le();
let mut s_32bytes: [u8; 32] = [0; 32];
let lens = min(s_bytes.len(), s_32bytes.len());
s_32bytes[..lens].copy_from_slice(&s_bytes[..lens]);
b.append(&mut s_32bytes.to_vec());
let mut r: [u8; 64] = [0; 64];
let res_len = min(r.len(), b.len());
r[..res_len].copy_from_slice(&b[..res_len]);
let hex_string = to_hex_string(r.to_vec());
CString::new(hex_string.as_str()).unwrap().into_raw()
}
#[no_mangle]
pub extern fn unpack_signature(compressed_signature: *const c_char) -> *mut c_char {
println!("Rust unpack_signature");
let result = catch_unwind(|| unpack_signature_internal(compressed_signature));
match result {
Ok(res) => res,
Err(e) => {
println!("unpack_signature Rust Err: {:?}", e);
std::ptr::null_mut()
}
}
}
fn vector_as_u8_64_array(vector: Vec<u8>) -> [u8; 64] {
let mut arr = [0u8;64];
for (place, element) in arr.iter_mut().zip(vector.iter()) {
*place = *element;
}
arr
}
#[no_mangle]
pub /*extern*/ fn pack_point_internal(point_x: *const c_char, point_y: *const c_char) -> *mut c_char {
let point_x_cstr = unsafe { CStr::from_ptr(point_x) };
let point_x_str = match point_x_cstr.to_str() {
Err(_) => "there",
Ok(string) => string,
};
let point_y_cstr = unsafe { CStr::from_ptr(point_y) };
let point_y_str = match point_y_cstr.to_str() {
Err(_) => "there",
Ok(string) => string,
};
let p: Point = Point {
x: Fr::from_str(point_x_str).unwrap(),
y: Fr::from_str(point_y_str).unwrap(),
};
let compressed_point = p.compress();
let hex_string = to_hex_string(compressed_point.to_vec());
CString::new(hex_string.as_str()).unwrap().into_raw()
}
#[no_mangle]
pub extern fn pack_point(point_x: *const c_char, point_y: *const c_char) -> *mut c_char {
let result = catch_unwind(|| pack_point_internal(point_x, point_y));
match result {
Ok(res) => res,
Err(e) => {
println!("pack_point Rust Err: {:?}", e);
std::ptr::null_mut()
}
}
}
pub fn to_hex_string(bytes: Vec<u8>) -> String {
let strs: Vec<String> = bytes.iter()
.map(|b| format!("{:02X}", b))
.collect();
strs.join("")
}
#[no_mangle]
pub /*extern*/ fn unpack_point_internal(compressed_point: *const c_char) -> *mut c_char {
let compressed_point_str = unsafe { CStr::from_ptr(compressed_point) }.to_str().unwrap();
let y_bytes_raw = compressed_point_str.from_hex().unwrap();
let mut y_bytes: [u8; 32] = [0; 32];
y_bytes.copy_from_slice(&y_bytes_raw);
let p = decompress_point(y_bytes).unwrap();
let x_big = BigInt::parse_bytes(to_hex(&p.x).as_bytes(), 16).unwrap();
let y_big = BigInt::parse_bytes(to_hex(&p.y).as_bytes(), 16).unwrap();
let mut result_string: String = "".to_owned();
result_string.push_str(&x_big.to_string());
result_string.push_str(",");
result_string.push_str(&y_big.to_string());
CString::new(result_string.as_str()).unwrap().into_raw()
}
#[no_mangle]
pub extern fn unpack_point(compressed_point: *const c_char) -> *mut c_char {
let result = catch_unwind(|| unpack_point_internal(compressed_point));
match result {
Ok(res) => res,
Err(e) => {
println!("unpack_point Rust Err: {:?}", e);
std::ptr::null_mut()
}
}
}
#[no_mangle]
pub /*extern*/ fn prv2pub_internal(private_key: *const c_char) -> *mut c_char {
/*let private_key_bytes: [u8; 32] = *array_ref!(private_key[..32], 0, 32);
let private_key = PrivateKey::import(private_key_bytes.to_vec()).unwrap();*/
let private_key_str = unsafe { CStr::from_ptr(private_key) }.to_str().unwrap();
//let pk_bigint = BigInt::from_str(private_key_str).unwrap();
let pk_bytes_raw = private_key_str.from_hex().unwrap();
let mut pk_bytes: [u8; 32] = [0; 32];
pk_bytes.copy_from_slice(&pk_bytes_raw);
let pk = PrivateKey { key: pk_bytes };
let public_key = pk.public();
let mut result_string: String = "".to_owned();
result_string.push_str(&public_key.x.to_string());
result_string.push_str(",");
result_string.push_str(&public_key.y.to_string());
CString::new(result_string.as_str()).unwrap().into_raw()
}
#[no_mangle]
pub extern fn prv2pub(private_key: *const c_char) -> *mut c_char {
let result = catch_unwind(|| prv2pub_internal(private_key));
match result {
Ok(res) => res,
Err(e) => {
println!("prv2pub Rust Err: {:?}", e);
std::ptr::null_mut()
}
}
}
#[no_mangle]
pub /*extern*/ fn poseidon_hash_internal(input: *const c_char) -> *mut c_char {
let input_str = unsafe { CStr::from_ptr(input) }.to_str().unwrap();
let b0: Fr = Fr::from_str(input_str).unwrap();
let hm_input = vec![b0.clone()];
//let hm_input = vec![x.clone(), y.clone(), z.clone()];
let poseidon = Poseidon::new();
let hm = poseidon.hash(hm_input).unwrap();
//hm.to_string: Fr(0x29176100eaa962bdc1fe6c654d6a3c130e96a4d1168b33848b897dc502820133)
return CString::new(to_hex(&hm).as_str()).unwrap().into_raw();
//return CString::new(hm.to_string()).unwrap().into_raw();
}
#[no_mangle]
pub extern fn poseidon_hash(input: *const c_char) -> *mut c_char {
let result = catch_unwind(|| poseidon_hash_internal(input));
match result {
Ok(res) => res,
Err(e) => {
println!("poseidon_hash Rust Err: {:?}", e);
std::ptr::null_mut()
}
}
}
#[no_mangle]
pub extern "C" fn poseidon_hash2_internal(input1: *const c_char, input2: *const c_char) -> *mut c_char {
let input_str1 = unsafe { CStr::from_ptr(input1) }.to_str().unwrap();
let input_str2 = unsafe { CStr::from_ptr(input2) }.to_str().unwrap();
let b1: Fr = Fr::from_str(input_str1).unwrap();
let b2: Fr = Fr::from_str(input_str2).unwrap();
let hm_input = vec![b1.clone(), b2.clone()];
let poseidon = Poseidon::new();
let hm = poseidon.hash(hm_input).unwrap();
return CString::new(to_hex(&hm).as_str()).unwrap().into_raw();
}
#[no_mangle]
pub extern "C" fn poseidon_hash2(input1: *const c_char, input2: *const c_char) -> *mut c_char {
let result = catch_unwind(|| poseidon_hash2_internal(input1, input2));
match result {
Ok(res) => res,
Err(e) => {
println!("poseidon_hash2 Rust Err: {:?}", e);
std::ptr::null_mut()
}
}
}
#[no_mangle]
pub extern "C" fn poseidon_hash3_internal(input1: *const c_char, input2: *const c_char, input3: *const c_char) -> *mut c_char {
let input_str1 = unsafe { CStr::from_ptr(input1) }.to_str().unwrap();
let input_str2 = unsafe { CStr::from_ptr(input2) }.to_str().unwrap();
let input_str3 = unsafe { CStr::from_ptr(input3) }.to_str().unwrap();
let b1: Fr = Fr::from_str(input_str1).unwrap();
let b2: Fr = Fr::from_str(input_str2).unwrap();
let b3: Fr = Fr::from_str(input_str3).unwrap();
let hm_input = vec![b1.clone(), b2.clone(), b3.clone()];
let poseidon = Poseidon::new();
let hm = poseidon.hash(hm_input).unwrap();
return CString::new(to_hex(&hm).as_str()).unwrap().into_raw();
}
#[no_mangle]
pub extern "C" fn poseidon_hash3(input1: *const c_char, input2: *const c_char, input3: *const c_char) -> *mut c_char {
let result = catch_unwind(|| poseidon_hash3_internal(input1, input2, input3));
match result {
Ok(res) => res,
Err(e) => {
println!("poseidon_hash3 Rust Err: {:?}", e);
std::ptr::null_mut()
}
}
}
#[no_mangle]
pub extern "C" fn poseidon_hash4_internal(input1: *const c_char, input2: *const c_char, input3: *const c_char, input4: *const c_char) -> *mut c_char {
let input_str1 = unsafe { CStr::from_ptr(input1) }.to_str().unwrap();
let input_str2 = unsafe { CStr::from_ptr(input2) }.to_str().unwrap();
let input_str3 = unsafe { CStr::from_ptr(input3) }.to_str().unwrap();
let input_str4 = unsafe { CStr::from_ptr(input4) }.to_str().unwrap();
let b1: Fr = Fr::from_str(input_str1).unwrap();
let b2: Fr = Fr::from_str(input_str2).unwrap();
let b3: Fr = Fr::from_str(input_str3).unwrap();
let b4: Fr = Fr::from_str(input_str4).unwrap();
let hm_input = vec![b1.clone(), b2.clone(), b3.clone(), b4.clone()];
let poseidon = Poseidon::new();
let hm = poseidon.hash(hm_input).unwrap();
return CString::new(to_hex(&hm).as_str()).unwrap().into_raw();
}
#[no_mangle]
pub extern "C" fn poseidon_hash4(input1: *const c_char, input2: *const c_char, input3: *const c_char, input4: *const c_char) -> *mut c_char {
let result = catch_unwind(|| poseidon_hash4_internal(input1, input2, input3, input4));
match result {
Ok(res) => res,
Err(e) => {
println!("poseidon_hash4 Rust Err: {:?}", e);
std::ptr::null_mut()
}
}
}
#[no_mangle]
//pub extern fn hash_poseidon(tx_compressed_data: *const c_char, to_eth_addr: *const c_char, to_bjj_ay: *const c_char, rq_txcompressed_data_v2: *const c_char, rq_to_eth_addr: *const c_char, rq_to_bjj_ay: *const c_char) -> *mut c_char {
pub /*extern*/ fn hash_poseidon_internal(claims_tree: *const c_char, revocation_tree: *const c_char, roots_tree_root: *const c_char) -> *mut c_char {
//let claims_tree_str = unsafe { CStr::from_ptr(claims_tree) }.to_str().unwrap();
//let claims_tree_bigint = match claims_tree_str.parse::<i32>() {
// Ok(n) => BigInt::from(n),
// Err(e) => BigInt::zero(),
// };
//let b0: Fr = Fr::from_str(
// &claims_tree_bigint.to_string(),
// ).unwrap();
//let revocation_tree_str = unsafe { CStr::from_ptr(revocation_tree) }.to_str().unwrap();
//let revocation_tree_bigint = match revocation_tree_str.parse::<i32>() {
// Ok(n) => BigInt::from(n),
// Err(e) => BigInt::zero(),
// };
//let b1: Fr = Fr::from_str(
// &revocation_tree_bigint.to_string(),
// ).unwrap();
//let roots_tree_root_str = unsafe { CStr::from_ptr(roots_tree_root) }.to_str().unwrap();
// let roots_tree_root_bigint = match roots_tree_root_str.parse::<i32>() {
// Ok(n) => BigInt::from(n),
// Err(e) => BigInt::zero(),
// };
// let b2: Fr = Fr::from_str(
// &roots_tree_root_bigint.to_string(),
// ).unwrap();
//let x: Fr = Fr::from_str(
// "4648350302718598839424502774166524253703556728225603109003078358379460427828",
// ).unwrap();
//let x: Fr = Fr::from_str(
// "23520646440406697341854711669252473191475099932451150382882460752222516889098").unwrap();
//let y: Fr = Fr::zero();
//let z: Fr = Fr::zero();
let claims_tree_str = unsafe { CStr::from_ptr(claims_tree) }.to_str().unwrap();
let b0: Fr = Fr::from_str(claims_tree_str).unwrap();
let revocation_tree_str = unsafe { CStr::from_ptr(revocation_tree) }.to_str().unwrap();
let b1: Fr = Fr::from_str(revocation_tree_str).unwrap();
let roots_tree_root_str = unsafe { CStr::from_ptr(roots_tree_root) }.to_str().unwrap();
let b2: Fr = Fr::from_str(roots_tree_root_str).unwrap();
//if to_eth_addr.is_null() {
// let to_eth_addr_str = unsafe { CStr::from_ptr(to_eth_addr) }.to_str().unwrap();
// let b1: Fr = Fr::from_str(to_eth_addr_str).unwrap();
// let mut b1_input = vec![b1.clone()];
// hm_input.append(&mut b1_input);
//}
//if to_bjj_ay.is_null() {
// let to_bjj_ay_str = unsafe { CStr::from_ptr(to_bjj_ay) }.to_str().unwrap();
// let b2: Fr = Fr::from_str(to_bjj_ay_str).unwrap();
// let mut b2_input = vec![b2.clone()];
// hm_input.append(&mut b2_input);
//}
//if rq_txcompressed_data_v2.is_null() {
// let rq_txcompressed_data_v2_str = unsafe { CStr::from_ptr(rq_txcompressed_data_v2) }.to_str().unwrap();
// let b3: Fr = Fr::from_str(rq_txcompressed_data_v2_str).unwrap();
// let mut b3_input = vec![b3.clone()];
// hm_input.append(&mut b3_input);
//}
//if rq_to_eth_addr.is_null() {
// let rq_to_eth_addr_str = unsafe { CStr::from_ptr(rq_to_eth_addr) }.to_str().unwrap();
// let b4: Fr = Fr::from_str(rq_to_eth_addr_str).unwrap();
// let mut b4_input = vec![b4.clone()];
// hm_input.append(&mut b4_input);
//}
//if rq_to_bjj_ay.is_null() {
// let rq_to_bjj_ay_str = unsafe { CStr::from_ptr(rq_to_bjj_ay) }.to_str().unwrap();
// let b5: Fr = Fr::from_str(rq_to_bjj_ay_str).unwrap();
// let mut b5_input = vec![b5.clone()];
// hm_input.append(&mut b5_input);
//}
let hm_input = vec![b0.clone(), b1.clone(), b2.clone()];
//let hm_input = vec![x.clone(), y.clone(), z.clone()];
let poseidon = Poseidon::new();
let hm = poseidon.hash(hm_input).unwrap();
return CString::new(to_hex(&hm).as_str()).unwrap().into_raw();
}
#[no_mangle]
pub extern fn hash_poseidon(claims_tree: *const c_char, revocation_tree: *const c_char, roots_tree_root: *const c_char) -> *mut c_char {
let result = catch_unwind(|| hash_poseidon_internal(claims_tree, revocation_tree, roots_tree_root));
match result {
Ok(res) => res,
Err(e) => {
println!("hash_poseidon Rust Err: {:?}", e);
std::ptr::null_mut()
}
}
}
#[no_mangle]
pub /*extern*/ fn sign_poseidon_internal(private_key: *const c_char, msg: *const c_char) -> *mut c_char {
let private_key_str = unsafe { CStr::from_ptr(private_key) }.to_str().unwrap();
//let pk_bigint = BigInt::from_str(private_key_str).unwrap();
let pk_bytes_raw = private_key_str.from_hex().unwrap();
let mut pk_bytes: [u8; 32] = [0; 32];
pk_bytes.copy_from_slice(&pk_bytes_raw);
let pk = PrivateKey { key: pk_bytes };
let message_str = unsafe { CStr::from_ptr(msg) }.to_str().unwrap();
let message_bigint = BigInt::from_str(message_str).unwrap();
let sig = pk.sign(message_bigint.clone()).unwrap();
let compressed_signature = sig.compress();
let hex_string = compressed_signature.to_hex();
CString::new(hex_string.as_str()).unwrap().into_raw()
}
#[no_mangle]
pub extern fn sign_poseidon(private_key: *const c_char, msg: *const c_char) -> *mut c_char {
let result = catch_unwind(|| sign_poseidon_internal(private_key, msg));
match result {
Ok(res) => res,
Err(e) => {
println!("sign_poseidon Rust Err: {:?}", e);
std::ptr::null_mut()
}
}
}
#[no_mangle]
pub /*extern*/ fn verify_poseidon_internal(private_key: *const c_char, compressed_signature: *const c_char, message: *const c_char) -> *mut c_char {
let private_key_str = unsafe { CStr::from_ptr(private_key) }.to_str().unwrap();
// let pk_bigint = BigInt::from_str(private_key_str).unwrap();
let pk_bytes_raw = private_key_str.from_hex().unwrap();
let mut pk_bytes: [u8; 32] = [0; 32];
pk_bytes.copy_from_slice(&pk_bytes_raw);
let pk = PrivateKey { key: pk_bytes };
let compressed_signature_str = unsafe { CStr::from_ptr(compressed_signature) }.to_str().unwrap();
let signature_bytes_raw = compressed_signature_str.from_hex().unwrap();
let mut signature_bytes: [u8; 64] = [0; 64];
signature_bytes.copy_from_slice(&signature_bytes_raw);
let sig = decompress_signature(&signature_bytes).unwrap();
let message_c_str = unsafe { CStr::from_ptr(message) };
let message_str = match message_c_str.to_str() {
Err(_) => "there",
Ok(string) => string,
};
let message_bigint = match message_str.parse::<i32>() {
Ok(n) => BigInt::from(n),
Err(e) => BigInt::zero(),
};
if verify(pk.public(), sig.clone(), message_bigint.clone()) {
CString::new("1".to_owned()).unwrap().into_raw()
} else {
CString::new("0".to_owned()).unwrap().into_raw()
}
}
#[no_mangle]
pub extern fn verify_poseidon(private_key: *const c_char, compressed_signature: *const c_char, message: *const c_char) -> *mut c_char {
let result = catch_unwind(|| verify_poseidon_internal(private_key, compressed_signature, message));
match result {
Ok(res) => res,
Err(e) => {
println!("verify_poseidon Rust Err: {:?}", e);
std::ptr::null_mut()
}
}
}
#[no_mangle]
pub extern fn cstring_free(str: *mut c_char) {
unsafe {
if str.is_null() { return }
CString::from_raw(str)
};
}