diff --git a/bench/bls.exs b/bench/bls.exs new file mode 100644 index 000000000..501a2ceab --- /dev/null +++ b/bench/bls.exs @@ -0,0 +1,35 @@ +public_key = + Base.decode16!( + "a491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a", + case: :mixed + ) + +message = + Base.decode16!( + "0000000000000000000000000000000000000000000000000000000000000000", + case: :mixed + ) + +signature = + Base.decode16!( + "b6ed936746e01f8ecf281f020953fbf1f01debd5657c4a383940b020b26507f6076334f91e2366c96e9ab279fb5158090352ea1c5b0c9274504f4f0e7053af24802e51e4568d164fe986834f41e55c8e850ce1f98458c0cfc9ab380b55285a55", + case: :mixed + ) + +pk = [public_key] +pk_10 = List.duplicate(public_key, 10) +pk_100 = List.duplicate(public_key, 100) +pk_500 = List.duplicate(public_key, 500) +pk_2048 = List.duplicate(public_key, 2048) + +Benchee.run( + %{ + "1" => fn -> Bls.fast_aggregate_valid?(pk, message, signature) end, + "10" => fn -> Bls.fast_aggregate_valid?(pk_10, message, signature) end, + "100" => fn -> Bls.fast_aggregate_valid?(pk_100, message, signature) end, + "500" => fn -> Bls.fast_aggregate_valid?(pk_500, message, signature) end, + "2048" => fn -> Bls.fast_aggregate_valid?(pk_2048, message, signature) end + }, + warmup: 2, + time: 5 +) diff --git a/native/bls_nif/src/lib.rs b/native/bls_nif/src/lib.rs index f048be374..995aab869 100644 --- a/native/bls_nif/src/lib.rs +++ b/native/bls_nif/src/lib.rs @@ -10,6 +10,23 @@ pub(crate) fn bytes_to_binary<'env>(env: Env<'env>, bytes: &[u8]) -> Binary<'env binary.into() } +// Deserialize a PublicKey from a slice of bytes. +// Faster than PublicKey::deserialize() as it doesn't validate the key +// Returns Error on invalid BLST encoding or on Infinity Public Key. +fn fast_public_key_deserialize(pk: &[u8]) -> Result { + if pk == &bls::INFINITY_PUBLIC_KEY[..] { + Err("Infinity public Key".to_owned()) + } else { + bls::impls::blst::types::PublicKey::from_bytes(pk) + .map_err(|err| format!("BlstError({:?})", err)) + .and_then(|pk| { + PublicKey::deserialize_uncompressed(pk.serialize().as_slice()) + // This should never be an error as the pk is obtained from an uncompressed valid key + .map_err(|e| format!("Deserialization error: {:?}", e)) + }) + } +} + #[rustler::nif] fn sign<'env>( env: Env<'env>, @@ -59,7 +76,7 @@ fn verify<'env>(public_key: Binary, message: Binary, signature: Binary) -> Resul } let sig = Signature::deserialize(signature.as_slice()).map_err(|err| format!("{:?}", err))?; let pubkey = - PublicKey::deserialize(public_key.as_slice()).map_err(|err| format!("{:?}", err))?; + fast_public_key_deserialize(public_key.as_slice()).map_err(|err| format!("{:?}", err))?; Ok(sig.verify(&pubkey, Hash256::from_slice(message.as_slice()))) } @@ -74,7 +91,7 @@ fn aggregate_verify<'env>( .map_err(|err| format!("{:?}", err))?; let pubkeys_result = public_keys .iter() - .map(|pkb| PublicKey::deserialize(pkb.as_slice())) + .map(|pkb| fast_public_key_deserialize(pkb.as_slice())) .collect::, _>>(); let pubkeys = pubkeys_result.map_err(|err| format!("{:?}", err))?; @@ -86,7 +103,7 @@ fn aggregate_verify<'env>( Ok(aggregate_sig.aggregate_verify(&msgs, &pubkey_refs)) } -#[rustler::nif] +#[rustler::nif(schedule = "DirtyCpu")] fn fast_aggregate_verify<'env>( public_keys: Vec, message: Binary, @@ -99,7 +116,8 @@ fn fast_aggregate_verify<'env>( .map_err(|err| format!("{:?}", err))?; let pubkeys_result = public_keys .iter() - .map(|pkb| PublicKey::deserialize(pkb.as_slice())) + .map(|pkb| fast_public_key_deserialize(pkb.as_slice())) + //.map(|pkb| PublicKey::deserialize(pkb.as_slice())) .collect::, _>>(); let pubkeys = pubkeys_result.map_err(|err| format!("{:?}", err))?; @@ -120,7 +138,7 @@ fn eth_fast_aggregate_verify<'env>( .map_err(|err| format!("{:?}", err))?; let pubkeys_result = public_keys .iter() - .map(|pkb| PublicKey::deserialize(pkb.as_slice())) + .map(|pkb| fast_public_key_deserialize(pkb.as_slice())) .collect::, _>>(); let pubkeys = pubkeys_result.map_err(|err| format!("{:?}", err))?; @@ -139,7 +157,7 @@ fn eth_aggregate_pubkeys<'env>( _ => { let pubkeys_result = public_keys .iter() - .map(|pkb| PublicKey::deserialize(pkb.as_slice())) + .map(|pkb| fast_public_key_deserialize(pkb.as_slice())) .collect::, _>>(); let pubkeys = pubkeys_result.map_err(|err| format!("{:?}", err))?; @@ -156,8 +174,7 @@ fn eth_aggregate_pubkeys<'env>( } #[rustler::nif] fn key_validate<'env>(public_key: Binary) -> Result { - let _pubkey = - PublicKey::deserialize(public_key.as_slice()).map_err(|err| format!("{:?}", err))?; + let _pubkey = fast_public_key_deserialize(public_key.as_slice())?; Ok(true) } @@ -173,17 +190,4 @@ fn derive_pubkey<'env>(env: Env<'env>, private_key: Binary) -> Result