referrerpolicy=no-referrer-when-downgrade

snowbridge_beacon_primitives/
bls.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
3use crate::{PublicKey, Signature};
4use codec::{Decode, DecodeWithMemTracking, Encode};
5use frame_support::{ensure, PalletError};
6pub use milagro_bls::{
7	AggregatePublicKey, AggregateSignature, PublicKey as PublicKeyPrepared,
8	Signature as SignaturePrepared,
9};
10use scale_info::TypeInfo;
11use sp_core::H256;
12use sp_runtime::RuntimeDebug;
13use sp_std::prelude::*;
14
15#[derive(
16	Copy,
17	Clone,
18	Encode,
19	Decode,
20	DecodeWithMemTracking,
21	Eq,
22	PartialEq,
23	TypeInfo,
24	RuntimeDebug,
25	PalletError,
26)]
27pub enum BlsError {
28	InvalidSignature,
29	InvalidPublicKey,
30	InvalidAggregatePublicKeys,
31	SignatureVerificationFailed,
32}
33
34/// fast_aggregate_verify optimized with aggregate key subtracting absent ones.
35pub fn fast_aggregate_verify(
36	aggregate_pubkey: &PublicKeyPrepared,
37	absent_pubkeys: &Vec<PublicKeyPrepared>,
38	message: H256,
39	signature: &Signature,
40) -> Result<(), BlsError> {
41	let agg_sig = prepare_aggregate_signature(signature)?;
42	let agg_key = prepare_aggregate_pubkey_from_absent(aggregate_pubkey, absent_pubkeys)?;
43	fast_aggregate_verify_pre_aggregated(agg_sig, agg_key, message)
44}
45
46/// Decompress one public key into a point in G1.
47pub fn prepare_milagro_pubkey(pubkey: &PublicKey) -> Result<PublicKeyPrepared, BlsError> {
48	PublicKeyPrepared::from_bytes_unchecked(&pubkey.0).map_err(|_| BlsError::InvalidPublicKey)
49}
50
51/// Prepare for G1 public keys.
52pub fn prepare_g1_pubkeys(pubkeys: &[PublicKey]) -> Result<Vec<PublicKeyPrepared>, BlsError> {
53	pubkeys
54		.iter()
55		// Deserialize one public key from compressed bytes
56		.map(prepare_milagro_pubkey)
57		.collect::<Result<Vec<PublicKeyPrepared>, BlsError>>()
58}
59
60/// Prepare for G1 AggregatePublicKey.
61pub fn prepare_aggregate_pubkey(
62	pubkeys: &[PublicKeyPrepared],
63) -> Result<AggregatePublicKey, BlsError> {
64	AggregatePublicKey::into_aggregate(pubkeys).map_err(|_| BlsError::InvalidPublicKey)
65}
66
67/// Prepare for G1 AggregatePublicKey.
68pub fn prepare_aggregate_pubkey_from_absent(
69	aggregate_key: &PublicKeyPrepared,
70	absent_pubkeys: &Vec<PublicKeyPrepared>,
71) -> Result<AggregatePublicKey, BlsError> {
72	let mut aggregate_pubkey = AggregatePublicKey::from_public_key(aggregate_key);
73	if !absent_pubkeys.is_empty() {
74		let absent_aggregate_key = prepare_aggregate_pubkey(absent_pubkeys)?;
75		aggregate_pubkey.point.sub(&absent_aggregate_key.point);
76	}
77	Ok(AggregatePublicKey { point: aggregate_pubkey.point })
78}
79
80/// Prepare for G2 AggregateSignature, normally more expensive than G1 operation.
81pub fn prepare_aggregate_signature(signature: &Signature) -> Result<AggregateSignature, BlsError> {
82	Ok(AggregateSignature::from_signature(
83		&SignaturePrepared::from_bytes(&signature.0).map_err(|_| BlsError::InvalidSignature)?,
84	))
85}
86
87/// fast_aggregate_verify_pre_aggregated which is the most expensive call in beacon light client.
88pub fn fast_aggregate_verify_pre_aggregated(
89	agg_sig: AggregateSignature,
90	aggregate_key: AggregatePublicKey,
91	message: H256,
92) -> Result<(), BlsError> {
93	ensure!(
94		agg_sig.fast_aggregate_verify_pre_aggregated(&message[..], &aggregate_key),
95		BlsError::SignatureVerificationFailed
96	);
97	Ok(())
98}