diff --git a/Cargo.toml b/Cargo.toml index 77c5d22..b290159 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,11 +30,6 @@ hkdf = { version = "0.11.0", optional = true } blst_lib = { version = "0.3.10", optional = true, package = "blst" } blstrs = { version = "0.7.0", optional = true } -[workspace] -members = [ - "bls-signatures-ffi", -] - [features] default = ["pairing", "multicore"] multicore = ["rayon"] diff --git a/bls-signatures-ffi/Cargo.toml b/bls-signatures-ffi/Cargo.toml deleted file mode 100644 index 1b8dc62..0000000 --- a/bls-signatures-ffi/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "bls-signatures-ffi" -version = "0.1.0" -authors = ["sidke ", "dignifiedquire "] -license = "MIT OR Apache-2.0" -edition = "2018" -publish = false - -[lib] -crate-type = ["staticlib"] - -[dependencies] -bls-signatures = { path = "..", default-features = false } -rand = "0.8" -libc = "0.2" - -rayon = { version = "1.5.0", optional = true } -blstrs = { version = "0.7.0", optional = true } -bls12_381 = { version = "0.8.0", optional = true, features = ["experimental"] } -group = "0.13" - -[build-dependencies] -cbindgen = { version = "0.13.1", default-features = false } - -[features] -default = ["pairing", "multicore"] -pairing = [ "bls-signatures/pairing", "bls12_381" ] -blst = [ "bls-signatures/blst", "blstrs" ] -blst-portable = [ "bls-signatures/blst-portable", "blstrs/portable" ] -multicore = [ "bls-signatures/multicore", "rayon" ] diff --git a/bls-signatures-ffi/build.rs b/bls-signatures-ffi/build.rs deleted file mode 100644 index 2f274c5..0000000 --- a/bls-signatures-ffi/build.rs +++ /dev/null @@ -1,68 +0,0 @@ -extern crate cbindgen; - -use std::env; -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; -use std::process::Command; - -const VERSION: &str = env!("CARGO_PKG_VERSION"); - -fn main() { - let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); - let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - let target_path = out_path.join("../../.."); - - let cfg = cbindgen::Config::from_root_or_default(std::path::Path::new(&crate_dir)); - - let c = cbindgen::Builder::new() - .with_config(cfg) - .with_crate(crate_dir) - .with_header(format!( - "/* libbls_signatures Header Version {} */", - VERSION - )) - .with_language(cbindgen::Language::C) - .generate(); - - // This is needed to ensure we don't panic if there are errors in the crates code - // but rather just tell the rest of the system we can't proceed. - match c { - Ok(res) => { - res.write_to_file(target_path.join("libbls_signatures.h")); - } - Err(err) => { - eprintln!("unable to generate bindings: {:?}", err); - std::process::exit(1); - } - } - - let git_output = Command::new("git") - .args(&["rev-parse", "HEAD"]) - .output() - .unwrap(); - let git_hash = String::from_utf8(git_output.stdout).unwrap(); - - let libs = if cfg!(target_os = "linux") { - "-lutil -lutil -ldl -lrt -lpthread -lgcc_s -lc -lm -lrt -lpthread -lutil -lutil" - } else if cfg!(target_os = "macos") { - "-lSystem -lresolv -lc -lm" - } else { - "" - }; - - let mut pc_file = File::create(target_path.join("libbls_signatures.pc")) - .expect("unable to generate .pc file: {:?}"); - - write!( - pc_file, - "Name: bls signatures -Version: {version} -Description: bls signature scheme library -Libs: {libs} -", - version = git_hash.trim(), - libs = libs - ) - .expect("unable to write to .pc file: {:?}"); -} diff --git a/bls-signatures-ffi/src/lib.rs b/bls-signatures-ffi/src/lib.rs deleted file mode 100644 index a8eec5b..0000000 --- a/bls-signatures-ffi/src/lib.rs +++ /dev/null @@ -1,376 +0,0 @@ -#![allow(clippy::missing_safety_doc)] - -use std::slice::from_raw_parts; - -#[cfg(feature = "pairing")] -use bls12_381::{G2Affine, G2Projective}; -use bls_signatures::{ - aggregate as aggregate_sig, hash as hash_sig, verify as verify_sig, - verify_messages as verify_messages_sig, Error, PrivateKey, PublicKey, Serialize, Signature, -}; -#[cfg(feature = "blst")] -use blstrs::{G2Affine, G2Projective}; -use group::GroupEncoding; -use rand::rngs::OsRng; -#[cfg(feature = "multicore")] -use rayon::prelude::*; - -pub mod responses; - -const SIGNATURE_BYTES: usize = 96; -const PRIVATE_KEY_BYTES: usize = 32; -const PUBLIC_KEY_BYTES: usize = 48; -const DIGEST_BYTES: usize = 96; -const G2_COMPRESSED_SIZE: usize = 96; - -type BLSSignature = [u8; SIGNATURE_BYTES]; -type BLSPrivateKey = [u8; PRIVATE_KEY_BYTES]; -type BLSPublicKey = [u8; PUBLIC_KEY_BYTES]; -type BLSDigest = [u8; DIGEST_BYTES]; - -/// Unwraps or returns the passed in value. -macro_rules! try_ffi { - ($res:expr, $val:expr) => {{ - match $res { - Ok(res) => res, - Err(_) => return $val, - } - }}; -} - -/// Compute the digest of a message -/// -/// # Arguments -/// -/// * `message_ptr` - pointer to a message byte array -/// * `message_len` - length of the byte array -#[no_mangle] -pub unsafe extern "C" fn hash( - message_ptr: *const u8, - message_len: libc::size_t, -) -> *mut responses::HashResponse { - // prep request - let message = from_raw_parts(message_ptr, message_len); - - // call method - let digest = hash_sig(message); - - // prep response - let mut raw_digest: [u8; DIGEST_BYTES] = [0; DIGEST_BYTES]; - raw_digest.copy_from_slice(digest.to_bytes().as_ref()); - - let response = responses::HashResponse { digest: raw_digest }; - - Box::into_raw(Box::new(response)) -} - -/// Aggregate signatures together into a new signature -/// -/// # Arguments -/// -/// * `flattened_signatures_ptr` - pointer to a byte array containing signatures -/// * `flattened_signatures_len` - length of the byte array (multiple of SIGNATURE_BYTES) -/// -/// Returns `NULL` on error. Result must be freed using `destroy_aggregate_response`. -#[no_mangle] -pub unsafe extern "C" fn aggregate( - flattened_signatures_ptr: *const u8, - flattened_signatures_len: libc::size_t, -) -> *mut responses::AggregateResponse { - // prep request - - #[cfg(feature = "multicore")] - let parts = from_raw_parts(flattened_signatures_ptr, flattened_signatures_len) - .par_chunks(SIGNATURE_BYTES); - #[cfg(not(feature = "multicore"))] - let parts = - from_raw_parts(flattened_signatures_ptr, flattened_signatures_len).chunks(SIGNATURE_BYTES); - - let signatures = try_ffi!( - parts - .map(Signature::from_bytes) - .collect::, _>>(), - std::ptr::null_mut() - ); - - let mut raw_signature: [u8; SIGNATURE_BYTES] = [0; SIGNATURE_BYTES]; - try_ffi!(aggregate_sig(&signatures), std::ptr::null_mut()) - .write_bytes(&mut raw_signature.as_mut()) - .expect("preallocated"); - - let response = responses::AggregateResponse { - signature: raw_signature, - }; - - Box::into_raw(Box::new(response)) -} - -/// Verify that a signature is the aggregated signature of hashes - pubkeys -/// -/// # Arguments -/// -/// * `signature_ptr` - pointer to a signature byte array (SIGNATURE_BYTES long) -/// * `flattened_digests_ptr` - pointer to a byte array containing digests -/// * `flattened_digests_len` - length of the byte array (multiple of DIGEST_BYTES) -/// * `flattened_public_keys_ptr` - pointer to a byte array containing public keys -#[no_mangle] -pub unsafe extern "C" fn verify( - signature_ptr: *const u8, - flattened_digests_ptr: *const u8, - flattened_digests_len: libc::size_t, - flattened_public_keys_ptr: *const u8, - flattened_public_keys_len: libc::size_t, -) -> libc::c_int { - // prep request - let raw_signature = from_raw_parts(signature_ptr, SIGNATURE_BYTES); - let signature = try_ffi!(Signature::from_bytes(raw_signature), 0); - - let raw_digests = from_raw_parts(flattened_digests_ptr, flattened_digests_len); - let raw_public_keys = from_raw_parts(flattened_public_keys_ptr, flattened_public_keys_len); - - if raw_digests.len() % DIGEST_BYTES != 0 { - return 0; - } - if raw_public_keys.len() % PUBLIC_KEY_BYTES != 0 { - return 0; - } - - if raw_digests.len() / DIGEST_BYTES != raw_public_keys.len() / PUBLIC_KEY_BYTES { - return 0; - } - - #[cfg(feature = "multicore")] - let raw = raw_digests.par_chunks(DIGEST_BYTES); - #[cfg(not(feature = "multicore"))] - let raw = raw_digests.chunks(DIGEST_BYTES); - - let digests: Vec<_> = try_ffi!( - raw.map(|item: &[u8]| -> Result { - let mut digest = [0u8; G2_COMPRESSED_SIZE]; - digest.as_mut().copy_from_slice(item); - - let affine: Option = Option::from(G2Affine::from_compressed(&digest)); - affine.map(Into::into).ok_or(Error::CurveDecode) - }) - .collect::, Error>>(), - 0 - ); - - #[cfg(feature = "multicore")] - let raw = raw_public_keys.par_chunks(PUBLIC_KEY_BYTES); - #[cfg(not(feature = "multicore"))] - let raw = raw_public_keys.chunks(PUBLIC_KEY_BYTES); - - let public_keys: Vec<_> = try_ffi!( - raw.map(|item| { PublicKey::from_bytes(item) }) - .collect::>(), - 0 - ); - - verify_sig(&signature, digests.as_slice(), public_keys.as_slice()) as libc::c_int -} - -/// Verify that a signature is the aggregated signature of the given messages - pubkeys -/// -/// # Arguments -/// -/// * `signature_ptr` - pointer to a signature byte array (SIGNATURE_BYTES long) -/// * `flattened_messages_ptr` - pointer to a byte array containing all messages -/// * `flattened_messages_len` - length of the byte array -/// * `messages_sizes_ptr` - pointer to an array containing the lengths of the messages -/// * `messages_len` - length of the two messages arrays -/// * `flattened_public_keys_ptr` - pointer to a byte array containing public keys -#[no_mangle] -pub unsafe extern "C" fn verify_messages( - signature_ptr: *const u8, - flattened_messages_ptr: *const u8, - flattened_messages_len: libc::size_t, - message_sizes_ptr: *const libc::size_t, - message_sizes_len: libc::size_t, - flattened_public_keys_ptr: *const u8, - flattened_public_keys_len: libc::size_t, -) -> libc::c_int { - // prep request - let raw_signature = from_raw_parts(signature_ptr, SIGNATURE_BYTES); - let signature = try_ffi!(Signature::from_bytes(raw_signature), 0); - - let flattened = from_raw_parts(flattened_messages_ptr, flattened_messages_len); - let raw_public_keys = from_raw_parts(flattened_public_keys_ptr, flattened_public_keys_len); - let chunk_sizes = from_raw_parts(message_sizes_ptr, message_sizes_len); - - // split the flattened message array into slices of individual messages to - // be hashed - let mut messages: Vec<&[u8]> = Vec::with_capacity(message_sizes_len); - let mut offset = 0; - for chunk_size in chunk_sizes.iter() { - messages.push(&flattened[offset..offset + *chunk_size]); - offset += *chunk_size - } - - if raw_public_keys.len() % PUBLIC_KEY_BYTES != 0 { - return 0; - } - - if messages.len() != raw_public_keys.len() / PUBLIC_KEY_BYTES { - return 0; - } - - #[cfg(feature = "multicore")] - let raw = raw_public_keys.par_chunks(PUBLIC_KEY_BYTES); - #[cfg(not(feature = "multicore"))] - let raw = raw_public_keys.chunks(PUBLIC_KEY_BYTES); - - let public_keys: Vec<_> = try_ffi!( - raw.map(|item| { PublicKey::from_bytes(item) }) - .collect::>(), - 0 - ); - - verify_messages_sig(&signature, &messages, public_keys.as_slice()) as libc::c_int -} - -/// Generate a new private key -/// -/// # Arguments -/// -/// * `raw_seed_ptr` - pointer to a seed byte array -#[no_mangle] -pub unsafe extern "C" fn private_key_generate() -> *mut responses::PrivateKeyGenerateResponse { - let mut raw_private_key: [u8; PRIVATE_KEY_BYTES] = [0; PRIVATE_KEY_BYTES]; - PrivateKey::generate(&mut OsRng) - .write_bytes(&mut raw_private_key.as_mut()) - .expect("preallocated"); - - let response = responses::PrivateKeyGenerateResponse { - private_key: raw_private_key, - }; - - Box::into_raw(Box::new(response)) -} - -/// Sign a message with a private key and return the signature -/// -/// # Arguments -/// -/// * `raw_private_key_ptr` - pointer to a private key byte array -/// * `message_ptr` - pointer to a message byte array -/// * `message_len` - length of the byte array -/// -/// Returns `NULL` when passed invalid arguments. -#[no_mangle] -pub unsafe extern "C" fn private_key_sign( - raw_private_key_ptr: *const u8, - message_ptr: *const u8, - message_len: libc::size_t, -) -> *mut responses::PrivateKeySignResponse { - // prep request - let private_key_slice = from_raw_parts(raw_private_key_ptr, PRIVATE_KEY_BYTES); - let private_key = try_ffi!( - PrivateKey::from_bytes(private_key_slice), - std::ptr::null_mut() - ); - let message = from_raw_parts(message_ptr, message_len); - - let mut raw_signature: [u8; SIGNATURE_BYTES] = [0; SIGNATURE_BYTES]; - PrivateKey::sign(&private_key, message) - .write_bytes(&mut raw_signature.as_mut()) - .expect("preallocated"); - - let response = responses::PrivateKeySignResponse { - signature: raw_signature, - }; - - Box::into_raw(Box::new(response)) -} - -/// Generate the public key for a private key -/// -/// # Arguments -/// -/// * `raw_private_key_ptr` - pointer to a private key byte array -/// -/// Returns `NULL` when passed invalid arguments. -#[no_mangle] -pub unsafe extern "C" fn private_key_public_key( - raw_private_key_ptr: *const u8, -) -> *mut responses::PrivateKeyPublicKeyResponse { - let private_key_slice = from_raw_parts(raw_private_key_ptr, PRIVATE_KEY_BYTES); - let private_key = try_ffi!( - PrivateKey::from_bytes(private_key_slice), - std::ptr::null_mut() - ); - - let mut raw_public_key: [u8; PUBLIC_KEY_BYTES] = [0; PUBLIC_KEY_BYTES]; - private_key - .public_key() - .write_bytes(&mut raw_public_key.as_mut()) - .expect("preallocated"); - - let response = responses::PrivateKeyPublicKeyResponse { - public_key: raw_public_key, - }; - - Box::into_raw(Box::new(response)) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn key_verification() { - unsafe { - let private_key = (*private_key_generate()).private_key; - let public_key = (*private_key_public_key(&private_key[0])).public_key; - let message = b"hello world"; - let digest = (*hash(&message[0], message.len())).digest; - let signature = - (*private_key_sign(&private_key[0], &message[0], message.len())).signature; - let verified = verify( - &signature[0], - &digest[0], - digest.len(), - &public_key[0], - public_key.len(), - ); - - assert_eq!(1, verified); - - let message_sizes = [message.len()]; - let verified2 = verify_messages( - signature.as_ptr(), - message.as_ptr(), - message.len(), - message_sizes.as_ptr(), - message_sizes.len(), - public_key.as_ptr(), - public_key.len(), - ); - assert_eq!(1, verified2); - - let different_message = b"bye world"; - let different_digest = (*hash(&different_message[0], different_message.len())).digest; - let not_verified = verify( - &signature[0], - &different_digest[0], - different_digest.len(), - &public_key[0], - public_key.len(), - ); - - assert_eq!(0, not_verified); - - // garbage verification - let different_digest = vec![0, 1, 2, 3, 4]; - let not_verified = verify( - &signature[0], - &different_digest[0], - different_digest.len(), - &public_key[0], - public_key.len(), - ); - - assert_eq!(0, not_verified); - } - } -} diff --git a/bls-signatures-ffi/src/responses.rs b/bls-signatures-ffi/src/responses.rs deleted file mode 100644 index a105906..0000000 --- a/bls-signatures-ffi/src/responses.rs +++ /dev/null @@ -1,65 +0,0 @@ -use crate::{BLSDigest, BLSPrivateKey, BLSPublicKey, BLSSignature}; - -/// HashResponse - -#[repr(C)] -pub struct HashResponse { - pub digest: BLSDigest, -} - -#[no_mangle] -pub unsafe extern "C" fn destroy_hash_response(ptr: *mut HashResponse) { - let _ = Box::from_raw(ptr); -} - -/// AggregateResponse - -#[repr(C)] -pub struct AggregateResponse { - pub signature: BLSSignature, -} - -#[no_mangle] -pub unsafe extern "C" fn destroy_aggregate_response(ptr: *mut AggregateResponse) { - let _ = Box::from_raw(ptr); -} - -/// PrivateKeyGenerateResponse - -#[repr(C)] -pub struct PrivateKeyGenerateResponse { - pub private_key: BLSPrivateKey, -} - -#[no_mangle] -pub unsafe extern "C" fn destroy_private_key_generate_response( - ptr: *mut PrivateKeyGenerateResponse, -) { - let _ = Box::from_raw(ptr); -} - -/// PrivateKeySignResponse - -#[repr(C)] -pub struct PrivateKeySignResponse { - pub signature: BLSSignature, -} - -#[no_mangle] -pub unsafe extern "C" fn destroy_private_key_sign_response(ptr: *mut PrivateKeySignResponse) { - let _ = Box::from_raw(ptr); -} - -/// PrivateKeyPublicKeyResponse - -#[repr(C)] -pub struct PrivateKeyPublicKeyResponse { - pub public_key: BLSPublicKey, -} - -#[no_mangle] -pub unsafe extern "C" fn destroy_private_key_public_key_response( - ptr: *mut PrivateKeyPublicKeyResponse, -) { - let _ = Box::from_raw(ptr); -}