diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5e3e93c..0e2f5bf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -39,5 +39,8 @@ jobs: - name: Run cargo clippy (tests) run: cargo clippy --tests -- -D warnings - - name: Run cargo clippy (bench) - run: cargo clippy --bench -- -D warnings + - name: Run cargo clippy (bench bls381_benches) + run: cargo clippy --bench bls381_benches -- -D warnings + + - name: Run cargo clippy (bench multi_verify_benches) + run: cargo clippy --bench multi_verify_benches -- -D warnings diff --git a/README.md b/README.md new file mode 100644 index 0000000..b940961 --- /dev/null +++ b/README.md @@ -0,0 +1,188 @@ +# multiversx-bls for Rust + +This is a wrapper library of [bls](https://github.com/herumi/bls/), that bridges the functionality with MultiversX [crypto packages](https://github.com/multiversx/mx-chain-crypto-go). + +## Spec Name + +multiversx-bls | Spec Name| +------|-----------------| +G1|Signature| +G2|Public Key| + +## G1 - Signature + +`verify(&self, public_key: G2, msg: &[u8]) -> bool` + +- Checks if self is a valid signature of message for the given public key. + +`fast_aggregate_verify(&self, public_keys: &[G2], msg: &[u8]) -> bool` + +- Checks if self is a valid aggregated signature of message for multiple public keys. + +`add_assign(&mut self, signature: G1)` + +- Adds another signature to self (signature aggregation). + +`is_valid_order(&self) -> bool` + +- Checks if self is a valid signature of the correct group order. + +`aggregate(&mut self, sigs: &[G1])` + +- Sets self as the aggregated signature of signatures. + +`is_zero(&self) -> bool` + +- Checks if self is the point at infinity (zero element). + +`is_valid(&self) -> boo`l + +- Checks if self is a valid G1 element. + +`verify_signature_order(verify: bool)` + +- Enables or disables signature order verification: + - `true`: verification enabled; + - `false`: verification disabled (default). + +`deserialize(&mut self, buf: &[u8]) -> bool` + +- Deserialize a signature from an array of bytes. + +`from_serialized(buf: &[u8]) -> Result` + +- Creates a new G1 element from a serialized buffer: + - G1 if successful; + - Return `BlsError::InvalidData` on failure. + +`serialize(&self) -> Result, BlsError>` + +- Serializes the signature into a vector of bytes: + - A vector of bytes if successful; + - Return `BlsError::SerializeError` on failure. + +## G2 - Public Key + +`add_assign(&mut self, public_key: G2)` + +- Adds another public key to self. + +`is_valid_order(&self) -> bool` + +- Checks if self is a valid public key of the correct group order. + +`set_str(&mut self, s: &str)` + +- Sets the G2 element from a **base-10** string. + +`deserialize_g2(&mut self, buf: &[u8]) -> bool` + +- Deserializes a G2 element from a byte buffer. + +`is_zero(&self) -> bool` + +- Checks if self is the point at infinity (zero element). + +`is_valid(&self) -> bool` + +- Checks if self is a valid G2 element. + +`verify_public_key_order(verify: bool)` + +- Enables/disables verification of public key order when setting keys: + - true: verification enabled; + - false: verification disabled (default). + +`serialize(&self) -> Result, BlsError>` + +- Serializes the public key into a byte array. + - A vector of bytes if successful; + - Return `BlsError::SerializeError` on failure. + +`deserialize(&mut self, buf: &[u8]) -> bool` + +- Deserializes a public key from a byte array. + +`from_serialized(buf: &[u8]) -> Result` + +- Creates a new G2 element from a serialized buffer: + - Returns G2 if successful; + - Returns `BlsError::InvalidData` otherwise. + +## Secret Key + +`set_by_csprng(&mut self)` + +- Initializes the secret key using a cryptographically secure random number generator (CSPRNG). Panics if the generated key is zero. + +`set_hex_str(&mut self, s: &str) -> bool` + +- Sets the secret key from a hexadecimal string. + +`from_hex_str(s: &str) -> Result` + +- Creates a new secret key from a hexadecimal string: + - Returns SecretKey if valid; + - Returns `BlsError::InvalidData` if invalid. + +`get_public_key(&self) -> G2` + +- Derives the public key (G2) corresponding to this secret key. + +`sign(&self, msg: &[u8]) -> G1` + +- Generates a signature (G1) of the given message. + +`deserialize(&mut self, buf: &[u8]) -> bool` + +- Deserializes a secret key from a byte array. Returns true if successful and length matches. + +`from_serialized(buf: &[u8]) -> Result` + +- Creates a new secret key from serialized data: + - Returns SecretKey if valid; + - Returns `BlsError::InvalidData` if invalid. + +`serialize(&self) -> Result, BlsError>` + +- Serializes the secret key into a byte array: + - A vector of bytes if successful; + - Return `BlsError::SerializeError` on failure. + +## Executors + +- Executors are extracted from [bls-go-binary](https://github.com/herumi/bls-go-binary), version `v1.28.2`. + +## Usage + +Example: creating a public key from a vector of bytes. + +```rust +let buffer = [0; 96]; + +let mut public_key = G2::default(); + +if !public_key.deserialize_g2(buffer) { + return Err(BlsError::InvalidData); +} +``` + +Example: creating a signature from a vector of bytes. + +```rust +let buffer = [0; 48]; + +let mut sign = G1::default(); + +if !sign.deserialize(buffer) { + return Err(BlsError::InvalidData); +} +``` + +Example: verifying a BLS signature with a single public key and message. + +```rust +fn verify_signature(signature: G1, public_key: G2, message: &[u8]) { + signature.verify(public_key, message) +} +``` diff --git a/readme.md b/readme.md deleted file mode 100644 index 47790ea..0000000 --- a/readme.md +++ /dev/null @@ -1,83 +0,0 @@ -[![Build Status](https://github.com/herumi/bls-eth-rust/actions/workflows/main.yml/badge.svg)](https://github.com/herumi/bls-eth-rust/actions/workflows/main.yml) - -# bls-eth for Rust - -This is a wrapper library of [bls](https://github.com/herumi/bls/) with `BLS_ETH=1`. - -# How to build `libbls384_256.a` - -copy from [bls-eth-go-binary/bls/lib](https://github.com/herumi/bls-eth-go-binary/tree/master/bls/lib) or build it at yourself according to [readme.md](https://github.com/herumi/bls-eth-go-binary#how-to-build-the-static-binary). - -# News -- 2020/May/19 : The default hash function has change to the function defined at [BLS12381G2_XMD:SHA-256_SSWU_RO_](https://www.ietf.org/id/draft-irtf-cfrg-hash-to-curve-07.html#name-bls12381g2_xmdsha-256_sswu_). -- The default hash function has changed to the function defined at [draft-irtf-cfrg-hash-to-curve](https://cfrg.github.io/draft-irtf-cfrg-hash-to-curve/draft-irtf-cfrg-hash-to-curve.txt). - -bls-eth-rust | old eth2.0 spec name| -------|-----------------| -SecretKey::sign|Sign| -PublicKey::verify|Verify| -Signature::aggregate|Aggregate| -Signature::fast_aggregate_verify|FastAggregateVerify| -Signature::aggregate_verify_no_check|AggregateVerify| - -Check functions: -- verify_signature_order ; make `deserialize` check the correctness of the order -- Signature::is_valid_order ; check the correctness of the order -- verify_publickey_order ; make `deserialize` check the correctness of the order -- PublicKey::is_valid_order ; check the correctness of the order -- are_all_msg_different ; check that all messages are different each other -# How to test - -``` -env RUSTFLAGS="-L" cargo test -``` - -For example, on Linux, - -``` -mkdir work -cd work -git clone https://github.com/herumi/bls-eth-go-binary -git clone https://github.com/herumi/bls-eth-rust -cd bls-eth-rust -env RUSTFLAGS="-L../bls-eth-go-binary/bls/lib/linux/amd64/" cargo test -- --test-threads 1 -``` - -For windows, - -## msvc - -``` -mkdir work -git clone https://github.com/herumi/bls -git clone https://github.com/herumi/bls-eth-rust -cd bls -mklib eth -cd ../bls-eth-rust -set RUSTLFAGS=-L../bls/lib -cargo test --target=x86_64-pc-windows-msvc -``` -## gnu - -``` -set RUSTFLAGS=-L../bls-eth-go-binary/bls/lib/windows/amd64 -cargo test --target=x86_64-pc-windows-gnu -``` - -# How to run benchs - -``` -env RUSTFLAGS="-L../bls-eth-go-binary/bls/lib/linux/amd64/" cargo bench -``` - -# License - -modified new BSD License -http://opensource.org/licenses/BSD-3-Clause - -# Author - -MITSUNARI Shigeo(herumi@nifty.com) - -## Sponsors welcome -[GitHub Sponsor](https://github.com/sponsors/herumi) diff --git a/src/bls_api.rs b/src/bls_api.rs index 45dfcb2..c8c00bc 100644 --- a/src/bls_api.rs +++ b/src/bls_api.rs @@ -4,30 +4,40 @@ use crate::gt::GT; use crate::secret_key::SecretKey; unsafe extern "C" { - pub fn blsInit(curve: usize, compiledTimeVar: usize) -> i32; - - pub fn mclBnFr_isZero(secret_key: *const SecretKey) -> i32; - pub fn mclBn_getFrByteSize() -> usize; - pub fn mclBn_getFpByteSize() -> usize; - pub fn mclBnG2_setStr(x: *mut G2, buf: *const u8, buf_size: usize, io_mode: i32) -> i32; - pub fn mclBnG2_deserialize(x: *mut G2, buf: *const u8, buf_size: usize) -> usize; - pub fn mclBnG2_isZero(x: *const G2) -> u8; - pub fn mclBnG2_isValid(x: *const G2) -> u8; - - pub fn mclBnG1_isZero(x: *const G1) -> u8; - pub fn mclBnG1_isValid(x: *const G1) -> u8; - - pub fn blsSecretKeySetByCSPRNG(x: *mut SecretKey); - pub fn blsSecretKeySetHexStr(x: *mut SecretKey, buf: *const u8, buf_size: usize) -> i32; - pub fn blsGetPublicKey(y: *mut G2, x: *const SecretKey); - pub fn blsSignatureVerifyOrder(do_verify: i32); - pub fn blsSignatureIsValidOrder(sig: *const G1) -> i32; - pub fn blsPublicKeyVerifyOrder(do_verify: i32); - pub fn blsPublicKeyIsValidOrder(public_key: *const G2) -> i32; - - pub fn blsSign(sig: *mut G1, secret_key: *const SecretKey, msg: *const u8, msg_len: usize); - pub fn blsVerify(sig: *const G1, public_key: *const G2, msg: *const u8, msg_len: usize) -> i32; - pub fn blsFastAggregateVerify( + pub unsafe fn blsInit(curve: usize, compiledTimeVar: usize) -> i32; + + pub unsafe fn mclBnFr_isZero(secret_key: *const SecretKey) -> i32; + pub unsafe fn mclBn_getFrByteSize() -> usize; + pub unsafe fn mclBn_getFpByteSize() -> usize; + pub unsafe fn mclBnG2_setStr(x: *mut G2, buf: *const u8, buf_size: usize, io_mode: i32) -> i32; + pub unsafe fn mclBnG2_deserialize(x: *mut G2, buf: *const u8, buf_size: usize) -> usize; + pub unsafe fn mclBnG2_isZero(x: *const G2) -> u8; + pub unsafe fn mclBnG2_isValid(x: *const G2) -> u8; + + pub unsafe fn mclBnG1_isZero(x: *const G1) -> u8; + pub unsafe fn mclBnG1_isValid(x: *const G1) -> u8; + + pub unsafe fn blsSecretKeySetByCSPRNG(x: *mut SecretKey); + pub unsafe fn blsSecretKeySetHexStr(x: *mut SecretKey, buf: *const u8, buf_size: usize) -> i32; + pub unsafe fn blsGetPublicKey(y: *mut G2, x: *const SecretKey); + pub unsafe fn blsSignatureVerifyOrder(do_verify: i32); + pub unsafe fn blsSignatureIsValidOrder(sig: *const G1) -> i32; + pub unsafe fn blsPublicKeyVerifyOrder(do_verify: i32); + pub unsafe fn blsPublicKeyIsValidOrder(public_key: *const G2) -> i32; + + pub unsafe fn blsSign( + sig: *mut G1, + secret_key: *const SecretKey, + msg: *const u8, + msg_len: usize, + ); + pub unsafe fn blsVerify( + sig: *const G1, + public_key: *const G2, + msg: *const u8, + msg_len: usize, + ) -> i32; + pub unsafe fn blsFastAggregateVerify( sig: *const G1, public_key: *const G2, public_keys_len: usize, @@ -35,26 +45,34 @@ unsafe extern "C" { msg_len: usize, ) -> i32; - pub fn blsAggregateSignature( + pub unsafe fn blsAggregateSignature( aggregate_sig: *mut G1, signature: *const G1, signatures_len: usize, ); - pub fn blsSecretKeyIsEqual(lhs: *const SecretKey, rhs: *const SecretKey) -> i32; - pub fn blsPublicKeyIsEqual(lhs: *const G2, rhs: *const G2) -> i32; - pub fn blsSignatureIsEqual(lhs: *const G1, rhs: *const G1) -> i32; + pub unsafe fn blsSecretKeyIsEqual(lhs: *const SecretKey, rhs: *const SecretKey) -> i32; + pub unsafe fn blsPublicKeyIsEqual(lhs: *const G2, rhs: *const G2) -> i32; + pub unsafe fn blsSignatureIsEqual(lhs: *const G1, rhs: *const G1) -> i32; - pub fn blsSecretKeySerialize(buf: *mut u8, max_buf_len: usize, x: *const SecretKey) -> usize; - pub fn blsPublicKeySerialize(buf: *mut u8, max_buf_len: usize, x: *const G2) -> usize; - pub fn blsSignatureSerialize(buf: *mut u8, max_buf_len: usize, x: *const G1) -> usize; + pub unsafe fn blsSecretKeySerialize( + buf: *mut u8, + max_buf_len: usize, + x: *const SecretKey, + ) -> usize; + pub unsafe fn blsPublicKeySerialize(buf: *mut u8, max_buf_len: usize, x: *const G2) -> usize; + pub unsafe fn blsSignatureSerialize(buf: *mut u8, max_buf_len: usize, x: *const G1) -> usize; - pub fn blsSecretKeyDeserialize(x: *mut SecretKey, buf: *const u8, buf_len: usize) -> usize; - pub fn blsPublicKeyDeserialize(x: *mut G2, buf: *const u8, buf_len: usize) -> usize; - pub fn blsSignatureDeserialize(x: *mut G1, buf: *const u8, buf_len: usize) -> usize; + pub unsafe fn blsSecretKeyDeserialize( + x: *mut SecretKey, + buf: *const u8, + buf_len: usize, + ) -> usize; + pub unsafe fn blsPublicKeyDeserialize(x: *mut G2, buf: *const u8, buf_len: usize) -> usize; + pub unsafe fn blsSignatureDeserialize(x: *mut G1, buf: *const u8, buf_len: usize) -> usize; - pub fn blsPublicKeyAdd(public_key_1: *mut G2, public_key_2: *const G2); - pub fn blsSignatureAdd(signature_1: *mut G1, signature_2: *const G1); + pub unsafe fn blsPublicKeyAdd(public_key_1: *mut G2, public_key_2: *const G2); + pub unsafe fn blsSignatureAdd(signature_1: *mut G1, signature_2: *const G1); - pub fn mclBnGT_isEqual(lhs: *const GT, rhs: *const GT) -> i32; + pub unsafe fn mclBnGT_isEqual(lhs: *const GT, rhs: *const GT) -> i32; } diff --git a/src/g1.rs b/src/g1.rs index f25608c..1c2aa22 100644 --- a/src/g1.rs +++ b/src/g1.rs @@ -1,5 +1,3 @@ -use std::collections::HashSet; - use crate::constants::MCLBN_FP_UNIT_SIZE; use crate::g2::G2; use crate::init::{init_library, INIT}; @@ -140,22 +138,3 @@ impl G1 { Ok(buf) } } - -/// return true if `size`-byte splitted `msgs` are different each other -/// * `msgs` - an array that `size`-byte messages are concatenated -/// * `size` - length of one message -pub fn are_all_msg_different(msgs: &[u8], size: usize) -> bool { - let n = msgs.len() / size; - assert!(msgs.len() == n * size); - - let mut set = HashSet::new(); - for i in 0..n { - let msg = &msgs[i * size..(i + 1) * size]; - if set.contains(msg) { - return false; - } - set.insert(msg); - } - - true -} diff --git a/src/lib.rs b/src/lib.rs index 9a4e5c4..d6baadb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ mod init; mod secret_key; pub use error::BlsError; -pub use g1::{are_all_msg_different, G1}; +pub use g1::G1; pub use g2::G2; pub use gt::GT; pub use secret_key::SecretKey; diff --git a/tests/test.rs b/tests/test.rs index 9a4bf03..de93e56 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,4 +1,5 @@ use std::{ + collections::HashSet, fs::File, io::{BufRead, BufReader}, mem, @@ -156,3 +157,22 @@ fn test_signature_with_dummy_key() { let sig_hex = "283ae6bd67b23ee056888f2b119beac4224b6bece92553913a03a8fec53b68c37fae3d9315b58468d2cdae05bf236298"; assert_eq!(signature_serialize_to_hex_str(&sig), sig_hex); } + +/// return true if `size`-byte split `msgs` are different each other +/// * `msgs` - an array that `size`-byte messages are concatenated +/// * `size` - length of one message +fn are_all_msg_different(msgs: &[u8], size: usize) -> bool { + let n = msgs.len() / size; + assert!(msgs.len() == n * size); + + let mut set = HashSet::new(); + for i in 0..n { + let msg = &msgs[i * size..(i + 1) * size]; + if set.contains(msg) { + return false; + } + set.insert(msg); + } + + true +}