use k256::ecdsa::{
signature::hazmat::PrehashSigner,
Signature, SigningKey,
};
use crate::{Result, VeilCryptoError};
pub fn ecdsa_sign(message_hash: &[u8], secret_key: &[u8]) -> Result<Vec<u8>> {
if message_hash.len() != 32 {
return Err(VeilCryptoError::InvalidInput(
"Message hash must be 32 bytes".to_string(),
));
}
if secret_key.len() != 32 {
return Err(VeilCryptoError::InvalidSecretKey);
}
let signing_key = SigningKey::from_bytes(secret_key.into())
.map_err(|_| VeilCryptoError::InvalidSecretKey)?;
let signature: Signature = signing_key
.sign_prehash(message_hash)
.map_err(|e| VeilCryptoError::SignatureError(format!("ECDSA signing failed: {}", e)))?;
Ok(signature.to_der().as_bytes().to_vec())
}
pub fn ecdsa_sign_compact(message_hash: &[u8], secret_key: &[u8]) -> Result<Vec<u8>> {
if message_hash.len() != 32 {
return Err(VeilCryptoError::InvalidInput(
"Message hash must be 32 bytes".to_string(),
));
}
if secret_key.len() != 32 {
return Err(VeilCryptoError::InvalidSecretKey);
}
let signing_key = SigningKey::from_bytes(secret_key.into())
.map_err(|_| VeilCryptoError::InvalidSecretKey)?;
let signature: Signature = signing_key
.sign_prehash(message_hash)
.map_err(|e| VeilCryptoError::SignatureError(format!("ECDSA signing failed: {}", e)))?;
Ok(signature.to_bytes().to_vec())
}
pub fn ecdsa_get_public_key(secret_key: &[u8]) -> Result<Vec<u8>> {
if secret_key.len() != 32 {
return Err(VeilCryptoError::InvalidSecretKey);
}
let signing_key = SigningKey::from_bytes(secret_key.into())
.map_err(|_| VeilCryptoError::InvalidSecretKey)?;
let public_key = signing_key.verifying_key();
let encoded = public_key.to_encoded_point(true);
Ok(encoded.as_bytes().to_vec())
}
#[cfg(test)]
mod tests {
use super::*;
use k256::ecdsa::{signature::hazmat::PrehashVerifier, VerifyingKey};
#[test]
fn test_ecdsa_sign_and_verify() {
let secret_key = hex::decode(
"e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"
).unwrap();
let message_hash = hex::decode(
"9302bda273a887cb40c13e02a50b4071a31fd3aae3ae04021b0b843dd61ad18e"
).unwrap();
let signature_der = ecdsa_sign(&message_hash, &secret_key).unwrap();
assert!(signature_der.len() >= 68 && signature_der.len() <= 72);
assert_eq!(signature_der[0], 0x30);
let pubkey_bytes = ecdsa_get_public_key(&secret_key).unwrap();
assert_eq!(pubkey_bytes.len(), 33);
let signature = Signature::from_der(&signature_der).unwrap();
let verifying_key = VerifyingKey::from_sec1_bytes(&pubkey_bytes).unwrap();
assert!(verifying_key.verify_prehash(&message_hash, &signature).is_ok());
}
#[test]
fn test_ecdsa_sign_compact() {
let secret_key = hex::decode(
"e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"
).unwrap();
let message_hash = hex::decode(
"9302bda273a887cb40c13e02a50b4071a31fd3aae3ae04021b0b843dd61ad18e"
).unwrap();
let signature_compact = ecdsa_sign_compact(&message_hash, &secret_key).unwrap();
assert_eq!(signature_compact.len(), 64);
}
#[test]
fn test_ecdsa_invalid_inputs() {
let valid_secret = [0x01u8; 32];
let valid_hash = [0x02u8; 32];
assert!(ecdsa_sign(&[0u8; 31], &valid_secret).is_err());
assert!(ecdsa_sign(&[0u8; 33], &valid_secret).is_err());
assert!(ecdsa_sign(&valid_hash, &[0u8; 31]).is_err());
assert!(ecdsa_sign(&valid_hash, &[0u8; 33]).is_err());
assert!(ecdsa_sign(&valid_hash, &[0u8; 32]).is_err());
}
#[test]
fn test_low_s_normalization() {
let secret_key = hex::decode(
"0000000000000000000000000000000000000000000000000000000000000001"
).unwrap();
let message_hash = [0xffu8; 32];
let signature_compact = ecdsa_sign_compact(&message_hash, &secret_key).unwrap();
let s_first_byte = signature_compact[32];
assert!(s_first_byte < 0x80, "Signature S value should be in low range");
}
}