use blst::{
blst_p1_affine, blst_p1_affine_in_g1, blst_p1_affine_is_inf, blst_p1_uncompress, BLST_ERROR,
};
use chia_bls::{sign as aug_sign, verify as aug_verify, PublicKey, Signature};
pub use chia_bls::SecretKey;
const G1_ZERO: [u8; 48] = [0u8; 48];
pub fn public_key_bytes(sk: &SecretKey) -> [u8; 48] {
sk.public_key().to_bytes()
}
pub fn g1_subgroup_check(pk: &[u8; 48]) -> bool {
if pk == &G1_ZERO {
return false;
}
unsafe {
let mut affine = blst_p1_affine::default();
if blst_p1_uncompress(&mut affine, pk.as_ptr()) != BLST_ERROR::BLST_SUCCESS {
return false;
}
if blst_p1_affine_is_inf(&affine) {
return false;
}
blst_p1_affine_in_g1(&affine)
}
}
pub fn sign_message(sk: &SecretKey, msg: &[u8]) -> [u8; 96] {
aug_sign(sk, msg).to_bytes()
}
pub fn verify_signature(pk: &[u8; 48], msg: &[u8], sig: &[u8; 96]) -> bool {
let (Ok(pk), Ok(sig)) = (PublicKey::from_bytes(pk), Signature::from_bytes(sig)) else {
return false;
};
aug_verify(&sig, &pk, msg)
}
#[cfg(test)]
mod tests {
use super::*;
use sha2::{Digest, Sha256};
fn identity_sk(label: &str) -> SecretKey {
let seed: [u8; 32] = Sha256::digest(label.as_bytes()).into();
SecretKey::from_seed(&seed)
}
#[test]
fn sign_then_verify_round_trips() {
let sk = identity_sk("bls/round-trip");
let pk = public_key_bytes(&sk);
let msg = b"dig-tls binding message";
let sig = sign_message(&sk, msg);
assert!(verify_signature(&pk, msg, &sig));
}
#[test]
fn verify_rejects_wrong_message() {
let sk = identity_sk("bls/wrong-msg");
let pk = public_key_bytes(&sk);
let sig = sign_message(&sk, b"the real message");
assert!(!verify_signature(&pk, b"a different message", &sig));
}
#[test]
fn verify_rejects_wrong_key() {
let signer = identity_sk("bls/signer");
let other = public_key_bytes(&identity_sk("bls/other"));
let msg = b"payload";
let sig = sign_message(&signer, msg);
assert!(!verify_signature(&other, msg, &sig));
}
#[test]
fn verify_rejects_malformed_bytes() {
let sk = identity_sk("bls/malformed");
let pk = public_key_bytes(&sk);
assert!(!verify_signature(&pk, b"m", &[0xFFu8; 96]));
assert!(!verify_signature(
&[0xFFu8; 48],
b"m",
&sign_message(&sk, b"m")
));
}
#[test]
fn subgroup_check_accepts_real_key_rejects_junk() {
let pk = public_key_bytes(&identity_sk("bls/subgroup"));
assert!(
g1_subgroup_check(&pk),
"a real G1 identity key is in-subgroup"
);
assert!(
!g1_subgroup_check(&[0u8; 48]),
"the zero buffer is rejected"
);
assert!(
!g1_subgroup_check(&[0xFFu8; 48]),
"off-curve junk is rejected"
);
}
}