use k256::ecdsa::{Signature, VerifyingKey, signature::hazmat::PrehashVerifier};
use thiserror::Error;
#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
pub enum ChainKeySignatureError {
#[error("malformed secp256k1 public key")]
MalformedPublicKey,
#[error("malformed compact secp256k1 signature")]
MalformedSignature,
#[error("high-S secp256k1 signature")]
HighSSignature,
#[error("invalid secp256k1 signature")]
InvalidSignature,
}
pub fn validate_secp256k1_public_key(public_key: &[u8]) -> Result<(), ChainKeySignatureError> {
parse_public_key(public_key).map(|_| ())
}
pub fn verify_secp256k1_prehash(
public_key: &[u8],
prehash: &[u8; 32],
signature: &[u8],
) -> Result<(), ChainKeySignatureError> {
VerificationMaterial::parse(public_key, signature)?.verify_prehash(prehash)
}
pub fn normalize_secp256k1_signature(signature: &[u8]) -> Result<[u8; 64], ChainKeySignatureError> {
let parsed = parse_signature(signature)?;
Ok(parsed.normalize_s().unwrap_or(parsed).to_bytes().into())
}
fn parse_public_key(public_key: &[u8]) -> Result<VerifyingKey, ChainKeySignatureError> {
VerifyingKey::from_sec1_bytes(public_key)
.map_err(|_| ChainKeySignatureError::MalformedPublicKey)
}
fn parse_signature(signature: &[u8]) -> Result<Signature, ChainKeySignatureError> {
Signature::from_slice(signature).map_err(|_| ChainKeySignatureError::MalformedSignature)
}
pub(crate) struct VerificationMaterial {
key: VerifyingKey,
signature: Signature,
}
impl VerificationMaterial {
pub(crate) fn parse(
public_key: &[u8],
signature: &[u8],
) -> Result<Self, ChainKeySignatureError> {
let key = parse_public_key(public_key)?;
let signature = parse_signature(signature)?;
if signature.normalize_s().is_some() {
return Err(ChainKeySignatureError::HighSSignature);
}
Ok(Self { key, signature })
}
pub(crate) fn verify_prehash(&self, prehash: &[u8; 32]) -> Result<(), ChainKeySignatureError> {
self.key
.verify_prehash(prehash, &self.signature)
.map_err(|_| ChainKeySignatureError::InvalidSignature)
}
}