use crate::runtime::functions::RuntimeError;
use base64::{engine::general_purpose, Engine as _};
use ed25519_dalek::{
Signature as Ed25519Signature, SigningKey as Ed25519SigningKey,
VerifyingKey as Ed25519VerifyingKey,
};
use hex;
use k256::ecdsa::signature::Verifier as EcdsaVerifier;
use k256::{
ecdsa::{signature::Signer, Signature as K256Signature, SigningKey, VerifyingKey},
SecretKey,
};
use sha2::{Digest, Sha256};
use std::collections::HashMap;
fn default_last_seen_for_replay_check() -> u64 {
u64::MIN
}
#[derive(Debug, Clone)]
pub struct NonceManager {
nonces: HashMap<String, u64>, }
impl NonceManager {
pub fn new() -> Self {
Self {
nonces: HashMap::new(),
}
}
pub fn check_nonce(&mut self, key: &str, nonce: u64) -> Result<bool, RuntimeError> {
let last_seen = self
.nonces
.get(key)
.copied()
.unwrap_or_else(default_last_seen_for_replay_check);
if nonce <= last_seen {
return Ok(false); }
self.nonces.insert(key.to_string(), nonce);
Ok(true)
}
pub fn get_next_nonce(&self, key: &str) -> u64 {
self.nonces.get(key).map(|&n| n + 1).unwrap_or(1)
}
}
pub struct ECDSASignatureVerifier;
impl ECDSASignatureVerifier {
pub fn verify(message: &[u8], signature: &str, public_key: &str) -> Result<bool, RuntimeError> {
let mut hasher = Sha256::new();
hasher.update(message);
let message_hash = hasher.finalize();
let signature_bytes = hex::decode(signature)
.map_err(|e| RuntimeError::General(format!("Invalid hex signature: {}", e)))?;
let sig_bytes = if signature_bytes.len() == 65 {
&signature_bytes[0..64]
} else if signature_bytes.len() == 64 {
&signature_bytes[..]
} else {
return Err(RuntimeError::General(format!(
"Invalid signature length: expected 64 or 65 bytes, got {}",
signature_bytes.len()
)));
};
let signature = K256Signature::from_slice(sig_bytes)
.map_err(|e| RuntimeError::General(format!("Invalid ECDSA signature: {}", e)))?;
let pubkey_bytes = hex::decode(public_key)
.map_err(|e| RuntimeError::General(format!("Invalid hex public key: {}", e)))?;
let verifying_key = VerifyingKey::from_sec1_bytes(&pubkey_bytes)
.map_err(|e| RuntimeError::General(format!("Invalid public key: {}", e)))?;
match verifying_key.verify(&message_hash, &signature) {
Ok(_) => Ok(true),
Err(_) => Ok(false),
}
}
pub fn sign(message: &[u8], private_key: &str) -> Result<String, RuntimeError> {
let mut hasher = Sha256::new();
hasher.update(message);
let message_hash = hasher.finalize();
let privkey_bytes = hex::decode(private_key)
.map_err(|e| RuntimeError::General(format!("Invalid hex private key: {}", e)))?;
if privkey_bytes.len() != 32 {
return Err(RuntimeError::General(format!(
"Invalid private key length: expected 32 bytes, got {}",
privkey_bytes.len()
)));
}
let secret_key = SecretKey::from_slice(&privkey_bytes)
.map_err(|e| RuntimeError::General(format!("Invalid private key: {}", e)))?;
let signing_key = SigningKey::from(secret_key);
let signature: K256Signature = signing_key.sign(&message_hash);
Ok(hex::encode(signature.to_bytes()))
}
pub fn generate_keypair() -> Result<(String, String), RuntimeError> {
use rand::rngs::OsRng;
let secret_key = SecretKey::random(&mut OsRng);
let private_key_bytes = secret_key.to_bytes();
let signing_key = SigningKey::from(secret_key);
let verifying_key = signing_key.verifying_key();
let private_key_hex = hex::encode(private_key_bytes);
let public_key_hex = hex::encode(verifying_key.to_encoded_point(true).as_bytes());
Ok((private_key_hex, public_key_hex))
}
}
pub fn sign(data: &[u8], private_key: &str) -> Result<String, String> {
ECDSASignatureVerifier::sign(data, private_key).map_err(|e| format!("{}", e))
}
pub fn verify(data: &[u8], signature: &str, public_key: &str) -> Result<bool, String> {
ECDSASignatureVerifier::verify(data, signature, public_key).map_err(|e| format!("{}", e))
}
pub struct EdDSASignatureVerifier;
impl EdDSASignatureVerifier {
pub fn verify(message: &[u8], signature: &str, public_key: &str) -> Result<bool, RuntimeError> {
let signature_bytes = if let Ok(bytes) = hex::decode(signature) {
bytes
} else if let Ok(bytes) = general_purpose::STANDARD.decode(signature) {
bytes
} else {
return Err(RuntimeError::General(
"Signature must be hex or base64 encoded".to_string(),
));
};
if signature_bytes.len() != 64 {
return Err(RuntimeError::General(format!(
"Invalid Ed25519 signature length: expected 64 bytes, got {}",
signature_bytes.len()
)));
}
let signature = Ed25519Signature::from_slice(&signature_bytes)
.map_err(|e| RuntimeError::General(format!("Invalid Ed25519 signature: {}", e)))?;
let pubkey_bytes = if let Ok(bytes) = hex::decode(public_key) {
bytes
} else if let Ok(bytes) = general_purpose::STANDARD.decode(public_key) {
bytes
} else {
return Err(RuntimeError::General(
"Public key must be hex or base64 encoded".to_string(),
));
};
if pubkey_bytes.len() != 32 {
return Err(RuntimeError::General(format!(
"Invalid Ed25519 public key length: expected 32 bytes, got {}",
pubkey_bytes.len()
)));
}
let verifying_key =
Ed25519VerifyingKey::from_bytes(pubkey_bytes.as_slice().try_into().map_err(|_| {
RuntimeError::General("Failed to convert public key bytes".to_string())
})?)
.map_err(|e| RuntimeError::General(format!("Invalid Ed25519 public key: {}", e)))?;
match verifying_key.verify(message, &signature) {
Ok(_) => Ok(true),
Err(_) => Ok(false),
}
}
pub fn verify_hex(
message: &[u8],
signature_hex: &str,
pubkey_hex: &str,
) -> Result<bool, RuntimeError> {
Self::verify(message, signature_hex, pubkey_hex)
}
pub fn verify_base64(
message: &[u8],
signature_b64: &str,
pubkey_b64: &str,
) -> Result<bool, RuntimeError> {
Self::verify(message, signature_b64, pubkey_b64)
}
pub fn sign(message: &[u8], private_key: &str) -> Result<String, RuntimeError> {
let privkey_bytes = if let Ok(bytes) = hex::decode(private_key) {
bytes
} else if let Ok(bytes) = general_purpose::STANDARD.decode(private_key) {
bytes
} else {
return Err(RuntimeError::General(
"Private key must be hex or base64 encoded".to_string(),
));
};
if privkey_bytes.len() != 32 {
return Err(RuntimeError::General(format!(
"Invalid Ed25519 private key length: expected 32 bytes, got {}",
privkey_bytes.len()
)));
}
let signing_key =
Ed25519SigningKey::from_bytes(privkey_bytes.as_slice().try_into().map_err(|_| {
RuntimeError::General("Failed to convert private key bytes".to_string())
})?);
let signature = signing_key.sign(message);
Ok(hex::encode(signature.to_bytes()))
}
pub fn generate_keypair() -> Result<(String, String), RuntimeError> {
let mut seed = [0u8; 32];
rand::RngCore::fill_bytes(&mut rand::rngs::OsRng, &mut seed);
let signing_key = Ed25519SigningKey::from_bytes(&seed);
let verifying_key = signing_key.verifying_key();
let private_key_hex = hex::encode(signing_key.to_bytes());
let public_key_hex = hex::encode(verifying_key.to_bytes());
Ok((private_key_hex, public_key_hex))
}
}
#[derive(Debug, Clone)]
pub struct SecureSignatureVerifier {
nonce_manager: NonceManager,
}
impl SecureSignatureVerifier {
pub fn new() -> Self {
Self {
nonce_manager: NonceManager::new(),
}
}
pub fn verify_with_nonce(
&mut self,
message: &[u8],
signature: &str,
public_key: &str,
nonce: u64,
signer_key: &str,
scheme: &str,
) -> Result<bool, RuntimeError> {
if !self.nonce_manager.check_nonce(signer_key, nonce)? {
return Err(RuntimeError::General(format!(
"Replay attack detected: nonce {} already used",
nonce
)));
}
let mut hasher = Sha256::new();
hasher.update(message);
hasher.update(&nonce.to_be_bytes());
let message_with_nonce = hasher.finalize();
let is_valid = match scheme.to_lowercase().as_str() {
"ecdsa" | "ethereum" => {
ECDSASignatureVerifier::verify(&message_with_nonce, signature, public_key)?
}
"eddsa" | "solana" => {
EdDSASignatureVerifier::verify(&message_with_nonce, signature, public_key)?
}
_ => {
return Err(RuntimeError::General(format!(
"Unsupported signature scheme: {}",
scheme
)));
}
};
Ok(is_valid)
}
pub fn get_next_nonce(&self, signer_key: &str) -> u64 {
self.nonce_manager.get_next_nonce(signer_key)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_nonce_manager() {
let mut manager = NonceManager::new();
let key = format!("test_nonce_{}", std::process::id());
assert!(manager.check_nonce(&key, 1).unwrap());
assert!(!manager.check_nonce(&key, 1).unwrap());
assert!(manager.check_nonce(&key, 2).unwrap());
assert!(!manager.check_nonce(&key, 1).unwrap());
}
#[test]
fn test_ecdsa_keypair_generation() {
let result = ECDSASignatureVerifier::generate_keypair();
assert!(result.is_ok());
let (private_key, public_key) = result.unwrap();
assert_eq!(private_key.len(), 64);
assert_eq!(public_key.len(), 66);
}
#[test]
fn test_ecdsa_sign_and_verify() {
let (private_key, public_key) = ECDSASignatureVerifier::generate_keypair().unwrap();
let message = b"Hello, dist_agent_lang!";
let signature_result = ECDSASignatureVerifier::sign(message, &private_key);
assert!(signature_result.is_ok());
let signature = signature_result.unwrap();
assert_eq!(signature.len(), 128);
let verify_result = ECDSASignatureVerifier::verify(message, &signature, &public_key);
assert!(verify_result.is_ok());
assert!(verify_result.unwrap());
let wrong_message = b"Wrong message";
let verify_wrong = ECDSASignatureVerifier::verify(wrong_message, &signature, &public_key);
assert!(verify_wrong.is_ok());
assert!(!verify_wrong.unwrap()); }
#[test]
fn test_ecdsa_invalid_inputs() {
let result = ECDSASignatureVerifier::sign(b"message", "not_hex");
assert!(result.is_err());
let result = ECDSASignatureVerifier::sign(b"message", "aabbcc");
assert!(result.is_err());
let (_, public_key) = ECDSASignatureVerifier::generate_keypair().unwrap();
let result = ECDSASignatureVerifier::verify(b"message", "invalid_sig", &public_key);
assert!(result.is_err());
}
#[test]
fn test_eddsa_verification_hex() {
let message = b"test message";
let signature_hex = "a".repeat(128); let pubkey_hex = "b".repeat(64);
let result = EdDSASignatureVerifier::verify(message, &signature_hex, &pubkey_hex);
assert!(result.is_ok() || result.is_err());
}
#[test]
fn test_eddsa_invalid_lengths() {
let message = b"test message";
let short_sig = "aa"; let pubkey = "b".repeat(64);
let result = EdDSASignatureVerifier::verify(message, short_sig, &pubkey);
assert!(result.is_err());
let signature = "a".repeat(128);
let short_pubkey = "bb"; let result = EdDSASignatureVerifier::verify(message, &signature, short_pubkey);
assert!(result.is_err());
}
#[test]
fn test_eddsa_base64_encoding() {
let message = b"test message";
let signature_bytes = vec![0u8; 64];
let pubkey_bytes = vec![0u8; 32];
let signature_b64 = general_purpose::STANDARD.encode(&signature_bytes);
let pubkey_b64 = general_purpose::STANDARD.encode(&pubkey_bytes);
let result = EdDSASignatureVerifier::verify(message, &signature_b64, &pubkey_b64);
assert!(result.is_ok() || result.is_err());
}
#[test]
fn test_signature_verifier_with_nonce() {
let mut verifier = SecureSignatureVerifier::new();
let (private_key, public_key) = ECDSASignatureVerifier::generate_keypair().unwrap();
let message = b"test message";
let nonce = std::process::id() as u64;
let signer_key = format!("test_signer_{}", std::process::id());
let mut hasher = Sha256::new();
hasher.update(message);
hasher.update(&nonce.to_be_bytes());
let message_with_nonce = hasher.finalize();
let signature = ECDSASignatureVerifier::sign(&message_with_nonce, &private_key).unwrap();
let result1 = verifier.verify_with_nonce(
message,
&signature,
&public_key,
nonce,
&signer_key,
"ecdsa",
);
assert!(result1.is_ok());
assert!(result1.unwrap());
let result2 = verifier.verify_with_nonce(
message,
&signature,
&public_key,
nonce,
&signer_key,
"ecdsa",
);
assert!(result2.is_err()); let error_msg = result2.unwrap_err().to_string().to_lowercase();
assert!(
error_msg.contains("replay")
|| error_msg.contains("nonce")
|| error_msg.contains("used")
);
}
#[test]
fn test_ecdsa_ffi_wrappers() {
let (private_key, public_key) = ECDSASignatureVerifier::generate_keypair().unwrap();
let message = b"FFI test message";
let signature_result = sign(message, &private_key);
assert!(signature_result.is_ok());
let signature = signature_result.unwrap();
let verify_result = verify(message, &signature, &public_key);
assert!(verify_result.is_ok());
assert!(verify_result.unwrap());
}
#[test]
fn test_get_next_nonce() {
let verifier = SecureSignatureVerifier::new();
let key = format!("test_nonce_key_{}", std::process::id());
let first_nonce = verifier.get_next_nonce(&key);
assert_eq!(first_nonce, 1);
let mut verifier_mut = SecureSignatureVerifier::new();
verifier_mut
.nonce_manager
.check_nonce(&key, first_nonce)
.unwrap();
assert_eq!(verifier_mut.get_next_nonce(&key), 2);
}
}