use secp256k1::ecdsa::Signature;
use secp256k1::{Message, PublicKey, Secp256k1};
use serde::Serialize;
use crate::binary::to_bytes;
use crate::hash::{compute_digest_from_hash, hash_bytes};
use crate::types::{Result, SignatureProof, Signed, VerificationResult};
use crate::wallet::normalize_public_key;
pub fn verify<T: Serialize>(signed: &Signed<T>, is_data_update: bool) -> VerificationResult {
let bytes = match to_bytes(&signed.value, is_data_update) {
Ok(b) => b,
Err(_) => {
return VerificationResult {
is_valid: false,
valid_proofs: vec![],
invalid_proofs: signed.proofs.clone(),
};
}
};
let hash = hash_bytes(&bytes);
let mut valid_proofs = Vec::new();
let mut invalid_proofs = Vec::new();
for proof in &signed.proofs {
match verify_hash(&hash.value, &proof.signature, &proof.id) {
Ok(true) => valid_proofs.push(proof.clone()),
Ok(false) | Err(_) => invalid_proofs.push(proof.clone()),
}
}
VerificationResult {
is_valid: invalid_proofs.is_empty() && !valid_proofs.is_empty(),
valid_proofs,
invalid_proofs,
}
}
pub fn verify_hash(hash_hex: &str, signature: &str, public_key_id: &str) -> Result<bool> {
let secp = Secp256k1::new();
let full_public_key = normalize_public_key(public_key_id);
let public_key_bytes = hex::decode(&full_public_key)?;
let public_key = PublicKey::from_slice(&public_key_bytes)?;
let signature_bytes = hex::decode(signature)?;
let mut sig = Signature::from_der(&signature_bytes)?;
sig.normalize_s();
let digest = compute_digest_from_hash(hash_hex);
let message = Message::from_digest_slice(&digest)?;
Ok(secp.verify_ecdsa(&message, &sig, &public_key).is_ok())
}
pub fn verify_signature<T: Serialize>(
data: &T,
proof: &SignatureProof,
is_data_update: bool,
) -> Result<bool> {
let bytes = to_bytes(data, is_data_update)?;
let hash = hash_bytes(&bytes);
verify_hash(&hash.value, &proof.signature, &proof.id)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::sign::{sign, sign_data_update};
use crate::wallet::generate_key_pair;
use serde_json::json;
#[test]
fn test_verify_signed_object() {
let key_pair = generate_key_pair();
let data = json!({"id": "test", "value": 42});
let proof = sign(&data, &key_pair.private_key).unwrap();
let signed = Signed {
value: data,
proofs: vec![proof],
};
let result = verify(&signed, false);
assert!(result.is_valid);
assert_eq!(result.valid_proofs.len(), 1);
assert!(result.invalid_proofs.is_empty());
}
#[test]
fn test_verify_data_update() {
let key_pair = generate_key_pair();
let data = json!({"id": "test"});
let proof = sign_data_update(&data, &key_pair.private_key).unwrap();
let signed = Signed {
value: data,
proofs: vec![proof],
};
let result = verify(&signed, true);
assert!(result.is_valid);
}
#[test]
fn test_verify_tampered_data() {
let key_pair = generate_key_pair();
let original_data = json!({"id": "test", "value": 42});
let proof = sign(&original_data, &key_pair.private_key).unwrap();
let tampered_data = json!({"id": "test", "value": 999});
let signed = Signed {
value: tampered_data,
proofs: vec![proof],
};
let result = verify(&signed, false);
assert!(!result.is_valid);
assert!(result.valid_proofs.is_empty());
assert_eq!(result.invalid_proofs.len(), 1);
}
#[test]
fn test_verify_hash() {
let key_pair = generate_key_pair();
let data = json!({"id": "test"});
let proof = sign(&data, &key_pair.private_key).unwrap();
let bytes = to_bytes(&data, false).unwrap();
let hash = hash_bytes(&bytes);
let is_valid = verify_hash(&hash.value, &proof.signature, &proof.id).unwrap();
assert!(is_valid);
}
#[test]
fn test_verify_signature_single() {
let key_pair = generate_key_pair();
let data = json!({"id": "test"});
let proof = sign(&data, &key_pair.private_key).unwrap();
let is_valid = verify_signature(&data, &proof, false).unwrap();
assert!(is_valid);
}
}