use crate::error::{Error, Result};
use crate::primitives::{sha256, to_base64, PrivateKey, PublicKey};
use crate::wallet::KeyDeriver;
use super::SIGNED_VERSION;
pub fn sign(message: &[u8], signer: &PrivateKey, verifier: Option<&PublicKey>) -> Result<Vec<u8>> {
let key_id: [u8; 32] = rand::random();
let key_id_base64 = to_base64(&key_id);
let invoice_number = format!("2-message signing-{}", key_id_base64);
let (_, anyone_pubkey) = KeyDeriver::anyone_key();
let verifier_pubkey = verifier.unwrap_or(&anyone_pubkey);
let signing_key = signer.derive_child(verifier_pubkey, &invoice_number)?;
let message_hash = sha256(message);
let signature = signing_key.sign(&message_hash)?;
let signature_der = signature.to_der();
let mut result = Vec::with_capacity(4 + 33 + 33 + 32 + signature_der.len());
result.extend_from_slice(&SIGNED_VERSION);
result.extend_from_slice(&signer.public_key().to_compressed());
if verifier.is_none() {
result.push(0x00); } else {
result.extend_from_slice(&verifier_pubkey.to_compressed());
}
result.extend_from_slice(&key_id);
result.extend_from_slice(&signature_der);
Ok(result)
}
pub fn verify(message: &[u8], sig: &[u8], recipient: Option<&PrivateKey>) -> Result<bool> {
if sig.len() < 78 {
return Err(Error::MessageError(format!(
"signature too short: expected at least 78 bytes, got {}",
sig.len()
)));
}
let mut offset = 0;
let version = &sig[offset..offset + 4];
offset += 4;
if version != SIGNED_VERSION {
return Err(Error::MessageVersionMismatch {
expected: hex::encode(SIGNED_VERSION),
actual: hex::encode(version),
});
}
let sender_pubkey = PublicKey::from_bytes(&sig[offset..offset + 33])?;
offset += 33;
let recipient_first_byte = sig[offset];
offset += 1;
let verifier_privkey: PrivateKey;
if recipient_first_byte == 0x00 {
let (anyone_priv, _anyone_pub) = KeyDeriver::anyone_key();
verifier_privkey = anyone_priv;
} else {
if recipient.is_none() {
let expected_pubkey_bytes = &sig[offset - 1..offset + 32];
return Err(Error::MessageError(format!(
"this signature can only be verified with knowledge of a specific private key. The associated public key is: {}",
hex::encode(expected_pubkey_bytes)
)));
}
let recipient_key = recipient.unwrap();
verifier_privkey = recipient_key.clone();
let verifier_pubkey = recipient_key.public_key();
let expected_pubkey_rest = &sig[offset..offset + 32];
offset += 32;
let mut expected_pubkey_bytes = [0u8; 33];
expected_pubkey_bytes[0] = recipient_first_byte;
expected_pubkey_bytes[1..].copy_from_slice(expected_pubkey_rest);
let expected_pubkey = PublicKey::from_bytes(&expected_pubkey_bytes)?;
if verifier_pubkey.to_compressed() != expected_pubkey.to_compressed() {
return Err(Error::MessageRecipientMismatch {
expected: hex::encode(expected_pubkey.to_compressed()),
actual: hex::encode(verifier_pubkey.to_compressed()),
});
}
}
let key_id = &sig[offset..offset + 32];
offset += 32;
let signature_der = &sig[offset..];
let signature = crate::primitives::Signature::from_der(signature_der)?;
let key_id_base64 = to_base64(key_id);
let invoice_number = format!("2-message signing-{}", key_id_base64);
let signing_pubkey = sender_pubkey.derive_child(&verifier_privkey, &invoice_number)?;
let message_hash = sha256(message);
Ok(signing_pubkey.verify(&message_hash, &signature))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::primitives::PrivateKey;
#[test]
fn test_sign_for_specific_recipient() {
let sender = PrivateKey::random();
let recipient = PrivateKey::random();
let message = b"Test message for specific recipient";
let sig = sign(message, &sender, Some(&recipient.public_key())).unwrap();
assert!(sig.len() > 4 + 33 + 33 + 32);
assert_eq!(&sig[0..4], &SIGNED_VERSION);
let valid = verify(message, &sig, Some(&recipient)).unwrap();
assert!(valid);
}
#[test]
fn test_sign_for_anyone() {
let sender = PrivateKey::random();
let message = b"Test message for anyone";
let sig = sign(message, &sender, None).unwrap();
assert!(sig.len() > 4 + 33 + 1 + 32);
assert_eq!(&sig[0..4], &SIGNED_VERSION);
assert_eq!(sig[4 + 33], 0x00);
let valid = verify(message, &sig, None).unwrap();
assert!(valid);
}
#[test]
fn test_wrong_version() {
let sender = PrivateKey::random();
let message = b"Test message";
let mut sig = sign(message, &sender, None).unwrap();
sig[0] = 0xFF;
let result = verify(message, &sig, None);
assert!(result.is_err());
match result {
Err(Error::MessageVersionMismatch { expected, actual }) => {
assert_eq!(expected, hex::encode(SIGNED_VERSION));
assert!(actual.starts_with("ff"));
}
_ => panic!("Expected MessageVersionMismatch error"),
}
}
#[test]
fn test_missing_recipient_when_required() {
let sender = PrivateKey::random();
let recipient = PrivateKey::random();
let message = b"Test message";
let sig = sign(message, &sender, Some(&recipient.public_key())).unwrap();
let result = verify(message, &sig, None);
assert!(result.is_err());
match result {
Err(Error::MessageError(msg)) => {
assert!(msg.contains("specific private key"));
}
_ => panic!("Expected MessageError"),
}
}
#[test]
fn test_wrong_recipient() {
let sender = PrivateKey::random();
let recipient = PrivateKey::random();
let wrong_recipient = PrivateKey::random();
let message = b"Test message";
let sig = sign(message, &sender, Some(&recipient.public_key())).unwrap();
let result = verify(message, &sig, Some(&wrong_recipient));
assert!(result.is_err());
match result {
Err(Error::MessageRecipientMismatch { expected, actual }) => {
assert_eq!(
expected,
hex::encode(recipient.public_key().to_compressed())
);
assert_eq!(
actual,
hex::encode(wrong_recipient.public_key().to_compressed())
);
}
_ => panic!("Expected MessageRecipientMismatch error"),
}
}
#[test]
fn test_tampered_message_specific_recipient() {
let sender = PrivateKey::random();
let recipient = PrivateKey::random();
let message = b"Original message";
let tampered = b"Tampered message";
let sig = sign(message, &sender, Some(&recipient.public_key())).unwrap();
let valid = verify(tampered, &sig, Some(&recipient)).unwrap();
assert!(!valid);
}
#[test]
fn test_tampered_message_anyone() {
let sender = PrivateKey::random();
let message = b"Original message";
let tampered = b"Tampered message";
let sig = sign(message, &sender, None).unwrap();
let valid = verify(tampered, &sig, None).unwrap();
assert!(!valid);
}
#[test]
fn test_empty_message() {
let sender = PrivateKey::random();
let message = b"";
let sig = sign(message, &sender, None).unwrap();
let valid = verify(message, &sig, None).unwrap();
assert!(valid);
}
#[test]
fn test_large_message() {
let sender = PrivateKey::random();
let message = vec![0xAB; 10000];
let sig = sign(&message, &sender, None).unwrap();
let valid = verify(&message, &sig, None).unwrap();
assert!(valid);
}
fn key_from_scalar(scalar: u8) -> PrivateKey {
let mut bytes = [0u8; 32];
bytes[31] = scalar;
PrivateKey::from_bytes(&bytes).unwrap()
}
#[test]
fn test_deterministic_keys_specific_recipient() {
let sender = key_from_scalar(15);
let recipient = key_from_scalar(21);
let message = [1u8, 2, 4, 8, 16, 32];
let signature = sign(&message, &sender, Some(&recipient.public_key())).unwrap();
let valid = verify(&message, &signature, Some(&recipient)).unwrap();
assert!(valid);
}
#[test]
fn test_deterministic_keys_anyone() {
let sender = key_from_scalar(15);
let message = [1u8, 2, 4, 8, 16, 32];
let signature = sign(&message, &sender, None).unwrap();
let valid = verify(&message, &signature, None).unwrap();
assert!(valid);
}
#[test]
fn test_deterministic_keys_wrong_version_error_format() {
let sender = key_from_scalar(15);
let recipient = key_from_scalar(21);
let message = [1u8, 2, 4, 8, 16, 32];
let mut signature = sign(&message, &sender, Some(&recipient.public_key())).unwrap();
signature[0] = 1;
let result = verify(&message, &signature, Some(&recipient));
match result {
Err(Error::MessageVersionMismatch { expected, actual }) => {
assert_eq!(expected, "42423301");
assert_eq!(actual, "01423301");
}
_ => panic!("Expected MessageVersionMismatch error"),
}
}
#[test]
fn test_deterministic_keys_no_verifier_error_format() {
let sender = key_from_scalar(15);
let recipient = key_from_scalar(21);
let message = [1u8, 2, 4, 8, 16, 32];
let signature = sign(&message, &sender, Some(&recipient.public_key())).unwrap();
let result = verify(&message, &signature, None);
match result {
Err(Error::MessageError(msg)) => {
let recipient_pubkey_hex = hex::encode(recipient.public_key().to_compressed());
assert!(
msg.contains(&recipient_pubkey_hex),
"Error should contain recipient pubkey: {}",
msg
);
}
_ => panic!("Expected MessageError"),
}
}
#[test]
fn test_deterministic_keys_wrong_verifier_error_format() {
let sender = key_from_scalar(15);
let recipient = key_from_scalar(21);
let wrong_recipient = key_from_scalar(22);
let message = [1u8, 2, 4, 8, 16, 32];
let signature = sign(&message, &sender, Some(&recipient.public_key())).unwrap();
let result = verify(&message, &signature, Some(&wrong_recipient));
match result {
Err(Error::MessageRecipientMismatch { expected, actual }) => {
let expected_hex = hex::encode(recipient.public_key().to_compressed());
let actual_hex = hex::encode(wrong_recipient.public_key().to_compressed());
assert_eq!(expected, expected_hex);
assert_eq!(actual, actual_hex);
}
_ => panic!("Expected MessageRecipientMismatch error"),
}
}
}