use core::{cmp, fmt, hash};
use asn1_der::typed::{DerDecodable, Sequence};
use k256::{
ecdsa::Signature,
sha2::{Digest as ShaDigestTrait, Sha256},
ProjectivePoint,
};
use zeroize::Zeroize;
use super::error::DecodingError;
#[derive(Clone)]
pub struct Keypair {
secret: SecretKey,
public: PublicKey,
}
impl Keypair {
#[cfg(feature = "rand")]
pub fn generate() -> Keypair {
Keypair::from(SecretKey::generate())
}
pub fn public(&self) -> &PublicKey {
&self.public
}
pub fn secret(&self) -> &SecretKey {
&self.secret
}
}
impl fmt::Debug for Keypair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Keypair")
.field("public", &self.public)
.finish()
}
}
impl From<SecretKey> for Keypair {
fn from(secret: SecretKey) -> Keypair {
let public = PublicKey(*secret.0.verifying_key());
Keypair { secret, public }
}
}
impl From<Keypair> for SecretKey {
fn from(kp: Keypair) -> SecretKey {
kp.secret
}
}
#[derive(Clone)]
pub struct SecretKey(k256::ecdsa::SigningKey);
impl fmt::Debug for SecretKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "SecretKey")
}
}
impl SecretKey {
#[cfg(feature = "rand")]
pub fn generate() -> SecretKey {
SecretKey(k256::ecdsa::SigningKey::random(&mut rand::thread_rng()))
}
pub fn try_from_bytes(mut sk: impl AsMut<[u8]>) -> Result<SecretKey, DecodingError> {
let sk_bytes = sk.as_mut();
let secret = k256::ecdsa::SigningKey::from_slice(sk_bytes)
.map_err(|e| DecodingError::failed_to_parse("parse secp256k1 secret key", e))?;
sk_bytes.zeroize();
Ok(SecretKey(secret))
}
pub fn from_der(mut der: impl AsMut<[u8]>) -> Result<SecretKey, DecodingError> {
let der_obj = der.as_mut();
let mut sk_bytes = Sequence::decode(der_obj)
.and_then(|seq| seq.get(1))
.and_then(Vec::load)
.map_err(|e| DecodingError::failed_to_parse("secp256k1 SecretKey bytes", e))?;
let sk = SecretKey::try_from_bytes(&mut sk_bytes)?;
sk_bytes.zeroize();
der_obj.zeroize();
Ok(sk)
}
pub fn sign(&self, msg: &[u8]) -> Vec<u8> {
use k256::ecdsa::signature::Signer;
Signer::<k256::ecdsa::Signature>::sign(&self.0, msg)
.to_der()
.to_bytes()
.into_vec()
}
pub fn to_bytes(&self) -> [u8; 32] {
self.0.to_bytes().into()
}
}
#[derive(Eq, Clone)]
pub struct PublicKey(k256::ecdsa::VerifyingKey);
impl fmt::Debug for PublicKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("PublicKey(compressed): ")?;
for byte in &self.to_bytes() {
write!(f, "{byte:x}")?;
}
Ok(())
}
}
impl cmp::PartialEq for PublicKey {
fn eq(&self, other: &Self) -> bool {
self.to_bytes().eq(&other.to_bytes())
}
}
impl hash::Hash for PublicKey {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.to_bytes().hash(state);
}
}
impl cmp::PartialOrd for PublicKey {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl cmp::Ord for PublicKey {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.to_bytes().cmp(&other.to_bytes())
}
}
impl PublicKey {
pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool {
let digest = Sha256::new_with_prefix(msg);
self.verify_hash(digest.finalize().as_slice(), sig)
}
pub fn verify_hash(&self, msg: &[u8], sig: &[u8]) -> bool {
Signature::from_der(sig).is_ok_and(|s| {
k256::ecdsa::hazmat::verify_prehashed(
&ProjectivePoint::from(self.0.as_affine()),
msg.into(),
&s,
)
.is_ok()
})
}
pub fn to_bytes(&self) -> [u8; 33] {
let encoded_point = self.0.to_encoded_point(true);
debug_assert!(encoded_point.as_bytes().len() == 33);
let mut array: [u8; 33] = [0u8; 33];
array.copy_from_slice(encoded_point.as_bytes());
array
}
pub fn to_bytes_uncompressed(&self) -> [u8; 65] {
let encoded_point = self.0.to_encoded_point(false);
debug_assert!(encoded_point.as_bytes().len() == 65);
let mut array: [u8; 65] = [0u8; 65];
array.copy_from_slice(encoded_point.as_bytes());
array
}
pub fn try_from_bytes(k: &[u8]) -> Result<PublicKey, DecodingError> {
k256::ecdsa::VerifyingKey::from_sec1_bytes(k)
.map_err(|e| DecodingError::failed_to_parse("secp256k1 public key", e))
.map(PublicKey)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(feature = "rand")]
fn secp256k1_secret_from_bytes() {
let sk1 = SecretKey::generate();
let mut sk_bytes = [0; 32];
sk_bytes.copy_from_slice(&sk1.to_bytes()[..]);
let sk2 = SecretKey::try_from_bytes(&mut sk_bytes).unwrap();
assert_eq!(sk1.to_bytes(), sk2.to_bytes());
assert_eq!(sk_bytes, [0; 32]);
}
}