Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BLS & Multi-BLS signature verification #1756

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions framework/scenario/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@ pathdiff = "0.2.1"
itertools = "0.13.0"
colored = "2.0"
unwrap-infallible = "0.1.5"
blst = { version= "0.3.13", optional = true }


[features]
default = ["wasm-incompatible"]
wasm-incompatible = ["multiversx-chain-vm/wasm-incompatible"]
run-go-tests = []
bls = ["blst"]

[dependencies.multiversx-sc]
version = "=0.52.3"
Expand Down
4 changes: 3 additions & 1 deletion vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ categories = ["cryptography::cryptocurrencies", "development-tools::debugging"]
[features]
# not supported when compiling to wasm
wasm-incompatible = ["rand"]
bls = ["blst"]

[dependencies]
num-bigint = "0.4"
Expand All @@ -33,6 +34,7 @@ colored = "2.1.0"
rand = { version= "0.8.5", optional = true }
rand_seeder = "0.3.0"
ed25519-dalek = "2.1.0"
blst = { version= "0.3.13", optional = true }

[dependencies.multiversx-chain-vm-executor]
version = "0.2.0"
version = "0.2.0"
56 changes: 56 additions & 0 deletions vm/src/crypto_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use sha3::{Digest, Keccak256};

pub const SHA256_RESULT_LEN: usize = 32;
pub const KECCAK256_RESULT_LEN: usize = 32;
pub const BLS_DST_VALUE: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_";

pub fn sha256(data: &[u8]) -> [u8; SHA256_RESULT_LEN] {
let mut hasher = Sha256::new();
Expand Down Expand Up @@ -42,3 +43,58 @@ pub fn verify_ed25519(key: &[u8], message: &[u8], signature: &[u8]) -> bool {
let result = verifying_key.verify(message, &sig);
result.is_ok()
}

#[cfg(feature = "bls")]
pub fn verify_bls_signature(key: &[u8], message: &[u8], signature: &[u8]) -> bool {
use blst::{
min_pk::{PublicKey, Signature},
BLST_ERROR,
};

let public_key = PublicKey::from_bytes(key).unwrap();

let sig = Signature::from_bytes(signature).unwrap();

let verify_response = sig.verify(true, message, BLS_DST_VALUE, &[], &public_key, true);

matches!(verify_response, BLST_ERROR::BLST_SUCCESS)
}

#[cfg(feature = "bls")]
pub fn verify_multi_bls_signature(
public_keys: Vec<&[u8]>,
message: &[u8],
aggregated_signature: &[u8],
) -> bool {
use blst::{
min_pk::{AggregatePublicKey, AggregateSignature, PublicKey, Signature},
BLST_ERROR,
};

let mut aggregate_pk: AggregatePublicKey =
AggregatePublicKey::from_public_key(&PublicKey::default());

let public_keys_converted: Vec<PublicKey> = public_keys
.iter()
.filter_map(|key| PublicKey::from_bytes(key).ok())
.collect();

public_keys_converted
.iter()
.for_each(|pk| aggregate_pk.add_public_key(pk, true).unwrap());

let aggregate_sig: Signature =
AggregateSignature::from_signature(&Signature::from_bytes(aggregated_signature).unwrap())
.to_signature();

let verify_response = aggregate_sig.verify(
true,
message,
BLS_DST_VALUE,
&[],
&aggregate_pk.to_public_key(),
true,
);

matches!(verify_response, BLST_ERROR::BLST_SUCCESS)
}
59 changes: 59 additions & 0 deletions vm/tests/test_crypto.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#[cfg(feature = "bls")]
use blst::min_pk::{AggregateSignature, Signature};

use hex::FromHex;

use multiversx_chain_vm::crypto_functions;

#[test]
Expand Down Expand Up @@ -42,3 +46,58 @@ fn test_verify_ed25519_invalid_args() {
let success = crypto_functions::verify_ed25519(&pub_bytes, &msg_bytes, &sig_bytes);
assert!(!success);
}

#[cfg(feature = "bls")]
#[test]
fn test_verify_bls_signature() {
let public_key_hex = b"82eb2ddfa71f1673fbfbd17952838cbca3816d5e60bf5cdb220d8cad6cb800e2ed18bb747ef45b17c9b8cbc971c6b980";
let message = b"hello";
let signature_hex = b"979a97882bd59dd97d860c99f9c4295e7d63e3fede1823b942d31d71ea3707d8c179ab733d38f7497b53bfa1535fe5e202f2a1c6e4df1dbc97dbe315dccd51676dbef31af1fe60d4b11c304db61913dc1d39e929f80f2cd10b72cbc661235048";

let public_key_bytes: Vec<u8> = FromHex::from_hex(public_key_hex).unwrap();
let signature_bytes: Vec<u8> = FromHex::from_hex(signature_hex).unwrap();

let success =
crypto_functions::verify_bls_signature(&public_key_bytes, message, &signature_bytes);

assert!(success, "BLS signature verification failed");
}

#[cfg(feature = "bls")]
#[test]
fn test_verify_aggregated_signatures() {
let message = b"hello";

let pk1 = b"82eb2ddfa71f1673fbfbd17952838cbca3816d5e60bf5cdb220d8cad6cb800e2ed18bb747ef45b17c9b8cbc971c6b980";
let pk2 = b"a81795a7afa09274717a170d6ba42ab06b65b25c7887eca7be46dfddae4e5b1a249f104b15551a7a445cccac9b403926";
let pk3 = b"8bf9e68f8fc54d8cb808ba43f0ada562cafa3c07448ab038eff6f579f1e4c1d497a957f50f6eca2608f36c39d874cbea";

let pk1_bytes: Vec<u8> = FromHex::from_hex(pk1).unwrap();
let pk2_bytes: Vec<u8> = FromHex::from_hex(pk2).unwrap();
let pk3_bytes: Vec<u8> = FromHex::from_hex(pk3).unwrap();

let sig1 = b"979a97882bd59dd97d860c99f9c4295e7d63e3fede1823b942d31d71ea3707d8c179ab733d38f7497b53bfa1535fe5e202f2a1c6e4df1dbc97dbe315dccd51676dbef31af1fe60d4b11c304db61913dc1d39e929f80f2cd10b72cbc661235048";
let sig2 = b"a5a465bb34264faa5d695ad844cfbacc5514ef8cb50abdc874bbbe065e74fc2dcd69f22e6e3a25260c8a9b6c55d7ca6d0d42227a58385f7af440b85d447675bee433c88726c582ef66fba5357b60e6d980ce43e7c6a6929ed605dbe51d47c453";
let sig3 = b"9936262ea50315d00c2b082cae3a97315f8852a021de195cb256bf532d439f1965a65c9fa536693ecb7a238611cb9ac30926d4958a7852955ff56aba9f60d9bda7ba10a939bd8b370bc42b667ee2f4fe4bb671482abc93bcac11ec10c0230229";

let sig1_bytes: Vec<u8> = FromHex::from_hex(sig1).unwrap();
let sig2_bytes: Vec<u8> = FromHex::from_hex(sig2).unwrap();
let sig3_bytes: Vec<u8> = FromHex::from_hex(sig3).unwrap();

let sig1_converted = Signature::from_bytes(&sig1_bytes).unwrap();
let sig2_converted = Signature::from_bytes(&sig2_bytes).unwrap();
let sig3_converted = Signature::from_bytes(&sig3_bytes).unwrap();

let mut agg_sig = AggregateSignature::from_signature(&sig1_converted);
agg_sig.add_signature(&sig2_converted, true).unwrap();
agg_sig.add_signature(&sig3_converted, true).unwrap();
let final_agg_sig = agg_sig.to_signature();

let success = crypto_functions::verify_multi_bls_signature(
vec![&pk1_bytes, &pk2_bytes, &pk3_bytes],
message,
&final_agg_sig.to_bytes(),
);

assert!(success, "Aggregated BLS signature verification failed");
}
Loading