Fix signature key import/export, add tests

Signed-off-by: Lee Smet <lee.smet@hotmail.com>
This commit is contained in:
Lee Smet
2025-05-16 14:37:10 +02:00
parent d29a8fbb67
commit 365814b424
2 changed files with 82 additions and 7 deletions

View File

@@ -12,6 +12,7 @@ pub struct SigningKeypair {
vk: VerifyingKey,
}
#[derive(Debug, PartialEq, Eq)]
pub struct PublicKey(VerifyingKey);
impl SigningKeypair {
@@ -58,13 +59,14 @@ impl SigningKeypair {
impl PublicKey {
/// Import a public key from raw bytes
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CryptoError> {
if bytes.len() == 64 {
Ok(Self(
VerifyingKey::from_sec1_bytes(bytes).expect("Key is of valid size"),
))
} else {
Err(CryptoError::InvalidKeySize)
}
Ok(Self(VerifyingKey::from_sec1_bytes(bytes)?))
}
/// Get the raw bytes of this `PublicKey`, which can be transferred to another party.
///
/// The public key is SEC-1 encoded and compressed.
pub fn as_bytes(&self) -> Box<[u8]> {
self.0.to_encoded_point(true).to_bytes()
}
pub fn verify_signature(&self, message: &[u8], sig: &[u8]) -> Result<(), CryptoError> {
@@ -74,3 +76,67 @@ impl PublicKey {
.map_err(|_| CryptoError::SignatureFailed)
}
}
#[cfg(test)]
mod tests {
/// Generate a key, get the public key, export the bytes of said public key, import them again
/// as a public key, and verify the keys match. This make sure public keys can be exchanged.
#[test]
fn recover_public_key() {
let sk = super::SigningKeypair::new().expect("Can generate new key");
let pk = sk.public_key();
let pk_bytes = pk.as_bytes();
let pk2 = super::PublicKey::from_bytes(&pk_bytes).expect("Can import public key");
assert_eq!(pk, pk2);
}
/// Sign a message and validate the signature with the public key. Together with the above test
/// this makes sure a remote system can receive our public key and validate messages we sign.
#[test]
fn validate_signature() {
let sk = super::SigningKeypair::new().expect("Can generate new key");
let pk = sk.public_key();
let message = b"this is an arbitrary message we want to sign";
let sig = sk.sign(message).expect("Message can be signed");
assert!(pk.verify_signature(message, &sig).is_ok());
}
/// Make sure a signature which is tampered with does not pass signature validation
#[test]
fn corrupt_signature_does_not_validate() {
let sk = super::SigningKeypair::new().expect("Can generate new key");
let pk = sk.public_key();
let message = b"this is an arbitrary message we want to sign";
let mut sig = sk.sign(message).expect("Message can be signed");
// Tamper with the sig
sig[0] = sig[0].wrapping_add(1);
assert!(pk.verify_signature(message, &sig).is_err());
}
/// Make sure a valid signature does not work for a message which has been modified
#[test]
fn tampered_message_does_not_validate() {
let sk = super::SigningKeypair::new().expect("Can generate new key");
let pk = sk.public_key();
let message = b"this is an arbitrary message we want to sign";
let mut message_clone = message.to_vec();
let sig = sk.sign(message).expect("Message can be signed");
// Modify the message
message_clone[0] = message[0].wrapping_add(1);
assert!(pk.verify_signature(&message_clone, &sig).is_err());
}
}