#![deny(unsafe_code)]
#![deny(missing_docs)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::panic)]
use super::traits::{EcKeyPair, EcSignature, sealed};
use crate::prelude::error::{LatticeArcError, Result};
use k256::ecdsa::{Signature, SigningKey, VerifyingKey, signature::Signer, signature::Verifier};
use rand::rngs::OsRng;
use subtle::ConstantTimeEq;
use zeroize::Zeroizing;
pub struct Secp256k1KeyPair {
public_key: VerifyingKey,
secret_bytes: Zeroizing<[u8; 32]>,
}
impl std::fmt::Debug for Secp256k1KeyPair {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Secp256k1KeyPair")
.field("public_key", &self.public_key)
.field("secret_bytes", &"[REDACTED]")
.finish()
}
}
impl ConstantTimeEq for Secp256k1KeyPair {
fn ct_eq(&self, other: &Self) -> subtle::Choice {
self.secret_bytes.ct_eq(&*other.secret_bytes)
}
}
impl Secp256k1KeyPair {
fn signing_key(&self) -> Result<SigningKey> {
SigningKey::from_bytes((&self.secret_bytes[..]).into())
.map_err(|e| LatticeArcError::KeyGenerationError(e.to_string()))
}
}
impl EcKeyPair for Secp256k1KeyPair {
fn generate() -> Result<Self> {
let sk = SigningKey::random(&mut OsRng {});
let public_key = VerifyingKey::from(&sk);
let mut secret_bytes = Zeroizing::new([0u8; 32]);
secret_bytes.copy_from_slice(&sk.to_bytes());
drop(sk);
let keypair = Self { public_key, secret_bytes };
crate::primitives::pct::pct_secp256k1(&keypair)
.map_err(|e| LatticeArcError::KeyGenerationError(e.to_string()))?;
Ok(keypair)
}
fn from_secret_key(secret_key_bytes: &[u8]) -> Result<Self> {
if secret_key_bytes.len() != 32 {
return Err(LatticeArcError::InvalidKeyLength {
expected: 32,
actual: secret_key_bytes.len(),
});
}
let sk = SigningKey::from_bytes(secret_key_bytes.into())
.map_err(|e| LatticeArcError::KeyGenerationError(e.to_string()))?;
let public_key = VerifyingKey::from(&sk);
drop(sk);
let mut secret_bytes = Zeroizing::new([0u8; 32]);
secret_bytes.copy_from_slice(secret_key_bytes);
Ok(Self { public_key, secret_bytes })
}
fn public_key_bytes(&self) -> Vec<u8> {
self.public_key.to_encoded_point(false).as_bytes().to_vec()
}
fn secret_key_bytes(&self) -> Zeroizing<Vec<u8>> {
Zeroizing::new(self.secret_bytes.to_vec())
}
}
pub struct Secp256k1Signature;
impl sealed::Sealed for Secp256k1KeyPair {}
impl sealed::Sealed for Secp256k1Signature {}
impl EcSignature for Secp256k1Signature {
type Signature = Signature;
fn verify(public_key_bytes: &[u8], message: &[u8], signature: &Self::Signature) -> Result<()> {
let public_key = VerifyingKey::from_sec1_bytes(public_key_bytes)
.map_err(|e| LatticeArcError::InvalidKey(e.to_string()))?;
public_key.verify(message, signature).map_err(|_e| {
LatticeArcError::SignatureVerificationError("secp256k1 verification failed".to_string())
})
}
fn signature_len() -> usize {
64
}
fn signature_bytes(signature: &Self::Signature) -> Vec<u8> {
signature.to_bytes().to_vec()
}
fn signature_from_bytes(bytes: &[u8]) -> Result<Self::Signature> {
if bytes.len() != Self::signature_len() {
return Err(LatticeArcError::InvalidSignatureLength {
expected: Self::signature_len(),
got: bytes.len(),
});
}
Signature::from_bytes(bytes.into())
.map_err(|e| LatticeArcError::InvalidSignature(e.to_string()))
}
}
impl Secp256k1KeyPair {
pub fn sign(&self, message: &[u8]) -> Result<Signature> {
let sk = self.signing_key()?;
Ok(sk.sign(message))
}
}
#[cfg(test)]
#[allow(clippy::panic_in_result_fn)] mod tests {
use super::*;
use crate::prelude::error::Result;
#[test]
fn test_secp256k1_keypair_generation_succeeds() -> Result<()> {
let keypair = Secp256k1KeyPair::generate()?;
assert_eq!(keypair.secret_key_bytes().len(), 32);
assert_eq!(keypair.public_key_bytes().len(), 65);
Ok(())
}
#[test]
fn test_secp256k1_keypair_from_secret_succeeds() -> Result<()> {
let original = Secp256k1KeyPair::generate()?;
let secret_bytes = original.secret_key_bytes();
let reconstructed = Secp256k1KeyPair::from_secret_key(&secret_bytes)?;
assert_eq!(original.public_key_bytes(), reconstructed.public_key_bytes());
Ok(())
}
#[test]
fn test_secp256k1_sign_verify_roundtrip() -> Result<()> {
let keypair = Secp256k1KeyPair::generate()?;
let message = b"Hello, secp256k1!";
let signature = keypair.sign(message)?;
let public_key_bytes = keypair.public_key_bytes();
Secp256k1Signature::verify(&public_key_bytes, message, &signature)?;
let wrong_message = b"Wrong message";
assert!(Secp256k1Signature::verify(&public_key_bytes, wrong_message, &signature).is_err());
Ok(())
}
#[test]
fn test_secp256k1_signature_serialization_succeeds() -> Result<()> {
let keypair = Secp256k1KeyPair::generate()?;
let message = b"Test message";
let signature = keypair.sign(message)?;
let sig_bytes = Secp256k1Signature::signature_bytes(&signature);
assert_eq!(sig_bytes.len(), 64);
let reconstructed_sig = Secp256k1Signature::signature_from_bytes(&sig_bytes)?;
assert_eq!(signature, reconstructed_sig);
Ok(())
}
#[test]
fn test_secp256k1_from_secret_key_invalid_length_fails() {
let too_short = vec![0u8; 16];
let result = Secp256k1KeyPair::from_secret_key(&too_short);
assert!(result.is_err());
let too_long = vec![0u8; 64];
let result = Secp256k1KeyPair::from_secret_key(&too_long);
assert!(result.is_err());
}
#[test]
fn test_secp256k1_signature_from_bytes_invalid_length_fails() {
let too_short = vec![0u8; 32];
let result = Secp256k1Signature::signature_from_bytes(&too_short);
assert!(result.is_err());
let too_long = vec![0u8; 128];
let result = Secp256k1Signature::signature_from_bytes(&too_long);
assert!(result.is_err());
}
#[test]
fn test_secp256k1_byte_accessors_return_correct_lengths_has_correct_size() -> Result<()> {
let keypair = Secp256k1KeyPair::generate()?;
assert_eq!(keypair.public_key_bytes().len(), 65);
assert_eq!(keypair.secret_key_bytes().len(), 32);
Ok(())
}
#[test]
fn test_secp256k1_signature_len_is_64_bytes_succeeds() {
assert_eq!(Secp256k1Signature::signature_len(), 64);
}
#[test]
fn test_secp256k1_verify_invalid_public_key_fails() {
let invalid_pk = vec![0u8; 10];
let sig = Signature::from_bytes(&[0u8; 64].into());
if let Ok(sig) = sig {
let result = Secp256k1Signature::verify(&invalid_pk, b"test", &sig);
assert!(result.is_err());
}
}
}