use std::fmt;
pub use ic_verify_bls_signature::{
InvalidPrivateKey, InvalidPublicKey, InvalidSignature, Signature,
};
#[derive(Clone, Eq, PartialEq)]
pub struct PublicKey {
key: ic_verify_bls_signature::PublicKey,
identity: bool,
}
impl PublicKey {
pub const BYTES: usize = ic_verify_bls_signature::PublicKey::BYTES;
fn from_upstream(key: ic_verify_bls_signature::PublicKey) -> Self {
let point = ic_bls12_381::G2Affine::from_compressed(&key.serialize()).unwrap();
Self {
key,
identity: point.is_identity().into(),
}
}
pub fn serialize(&self) -> [u8; Self::BYTES] {
self.key.serialize()
}
pub fn deserialize(bytes: &[u8]) -> Result<Self, InvalidPublicKey> {
ic_verify_bls_signature::PublicKey::deserialize(bytes).map(Self::from_upstream)
}
#[expect(
clippy::result_unit_err,
reason = "Preserve the existing BLS verification contract."
)]
pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), ()> {
if self.identity {
return Err(());
}
self.key.verify(message, signature)
}
}
impl fmt::Debug for PublicKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.key.fmt(f)
}
}
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct PrivateKey(ic_verify_bls_signature::PrivateKey);
impl PrivateKey {
pub const BYTES: usize = ic_verify_bls_signature::PrivateKey::BYTES;
pub fn serialize(&self) -> [u8; Self::BYTES] {
self.0.serialize()
}
pub fn deserialize(bytes: &[u8]) -> Result<Self, InvalidPrivateKey> {
ic_verify_bls_signature::PrivateKey::deserialize(bytes).map(Self)
}
pub fn public_key(&self) -> PublicKey {
PublicKey::from_upstream(self.0.public_key())
}
pub fn sign(&self, message: &[u8]) -> Signature {
self.0.sign(message)
}
}
impl fmt::Debug for PrivateKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[expect(
clippy::result_unit_err,
reason = "Preserve the existing BLS verification contract."
)]
pub fn verify_bls_signature(signature: &[u8], message: &[u8], key: &[u8]) -> Result<(), ()> {
let signature = Signature::deserialize(signature).map_err(|_| ())?;
PublicKey::deserialize(key)
.map_err(|_| ())?
.verify(message, &signature)
}