use p256::ecdsa::{signature::Signer, Signature, SigningKey};
use serde::Serialize;
use crate::binary::to_bytes;
use crate::hash::{compute_digest_from_hash, hash_bytes};
use crate::r1::wallet::get_public_key_id;
use crate::types::{Result, SignatureProof};
pub fn sign<T: Serialize>(data: &T, private_key: &str) -> Result<SignatureProof> {
let bytes = to_bytes(data, false)?;
let hash = hash_bytes(&bytes);
let signature = sign_hash(&hash.value, private_key)?;
let id = get_public_key_id(private_key)?;
Ok(SignatureProof { id, signature })
}
pub fn sign_data_update<T: Serialize>(data: &T, private_key: &str) -> Result<SignatureProof> {
let bytes = to_bytes(data, true)?;
let hash = hash_bytes(&bytes);
let signature = sign_hash(&hash.value, private_key)?;
let id = get_public_key_id(private_key)?;
Ok(SignatureProof { id, signature })
}
pub fn sign_hash(hash_hex: &str, private_key: &str) -> Result<String> {
let private_key_bytes = hex::decode(private_key)?;
let signing_key = SigningKey::from_slice(&private_key_bytes)?;
let digest = compute_digest_from_hash(hash_hex);
let signature: Signature = signing_key.sign(&digest);
Ok(hex::encode(signature.to_der().as_bytes()))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::r1::wallet::generate_key_pair;
use serde_json::json;
#[test]
fn test_sign() {
let key_pair = generate_key_pair();
let data = json!({"id": "test", "value": 42});
let proof = sign(&data, &key_pair.private_key).unwrap();
assert_eq!(proof.id.len(), 128);
assert!(!proof.signature.is_empty());
}
#[test]
fn test_sign_data_update() {
let key_pair = generate_key_pair();
let data = json!({"id": "test"});
let proof = sign_data_update(&data, &key_pair.private_key).unwrap();
assert_eq!(proof.id.len(), 128);
assert!(!proof.signature.is_empty());
}
#[test]
fn test_sign_different_for_regular_vs_data_update() {
let key_pair = generate_key_pair();
let data = json!({"id": "test"});
let regular_proof = sign(&data, &key_pair.private_key).unwrap();
let update_proof = sign_data_update(&data, &key_pair.private_key).unwrap();
assert_eq!(regular_proof.id, update_proof.id);
assert_ne!(regular_proof.signature, update_proof.signature);
}
}