use ecdsa::signature::hazmat::PrehashVerifier;
use elliptic_curve::FieldBytes;
use p256;
use sha2::Digest;
use sha2::Sha256;
use subtle::CtOption;
use crate::ecc::PublicKey;
use crate::ecc::PublicKeyAddress;
use crate::ecc::SecretKey;
use crate::error::Error;
use crate::error::Result;
pub fn sign(sec: SecretKey, hash: &[u8; 32]) -> Result<[u8; 64]> {
let sk_bytes: FieldBytes<p256::NistP256> = sec.into();
let sk = ecdsa::SigningKey::<p256::NistP256>::from_bytes(&sk_bytes)?;
let (sig, _rid) = sk.sign_prehash_recoverable(hash)?;
let sig_bytes: [u8; 64] = sig.to_bytes().as_slice().try_into()?;
Ok(sig_bytes)
}
pub fn magic_prefix(msg: &[u8]) -> Vec<u8> {
let mut prefix_msg = format!("\x19Rings Signed Message:\n{}", msg.len()).into_bytes();
prefix_msg.extend_from_slice(msg);
prefix_msg.to_vec()
}
pub fn hash(msg: &[u8]) -> [u8; 32] {
let prefix_msg = magic_prefix(msg);
let hash = Sha256::digest(prefix_msg);
hash.into()
}
pub fn verify(
msg: &[u8],
address: &PublicKeyAddress,
sig: impl AsRef<[u8]>,
pubkey: &PublicKey<33>,
) -> bool {
if pubkey.address() != *address {
return false;
}
if sig.as_ref().len() != 64 {
return false;
}
let ct_pk: CtOption<Result<ecdsa::VerifyingKey<p256::NistP256>>> =
(*pubkey).ct_try_into_secp256r1_pubkey();
if !bool::from(ct_pk.is_some()) {
return false;
}
let msg_hash = hash(msg);
let res: Result<()> = ct_pk.unwrap().and_then(|pk| {
pk.verify_prehash(
&msg_hash,
&ecdsa::Signature::<p256::NistP256>::from_slice(sig.as_ref())
.map_err(Error::ECDSAError)?,
)
.map_err(Error::ECDSAError)
});
res.is_ok()
}
#[cfg(test)]
mod test_secp256r1;