From 25debdc051ae38cbfe06a9be1ff0886e7fd18f8c Mon Sep 17 00:00:00 2001 From: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com> Date: Mon, 27 Apr 2026 13:35:20 -0700 Subject: [PATCH] Add Signature + Verifying key types (#93) --- Cargo.lock | 1 + core/crypto/Cargo.toml | 2 +- core/crypto/src/lib.rs | 2 + core/crypto/src/signatures.rs | 83 +++++++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 core/crypto/src/signatures.rs diff --git a/Cargo.lock b/Cargo.lock index e763180..c26b345 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -639,6 +639,7 @@ checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ "curve25519-dalek", "ed25519", + "rand_core 0.6.4", "serde", "sha2", "subtle", diff --git a/core/crypto/Cargo.toml b/core/crypto/Cargo.toml index 2c688f3..04100aa 100644 --- a/core/crypto/Cargo.toml +++ b/core/crypto/Cargo.toml @@ -8,7 +8,7 @@ x25519-dalek = { version = "2.0.1", features = ["static_secrets"] } hkdf = "0.12" sha2 = "0.10" rand_core = { version = "0.6", features = ["getrandom"] } -ed25519-dalek = "2.2.0" +ed25519-dalek = { version = "2.2.0", features = ["rand_core"] } xeddsa = "1.0.2" zeroize = {version = "1.8.2", features= ["derive"]} generic-array = "1.3.5" diff --git a/core/crypto/src/lib.rs b/core/crypto/src/lib.rs index fff9cd2..1759091 100644 --- a/core/crypto/src/lib.rs +++ b/core/crypto/src/lib.rs @@ -1,9 +1,11 @@ mod identity; mod keys; +mod signatures; mod x3dh; mod xeddsa_sign; pub use identity::Identity; pub use keys::{PrivateKey, PublicKey, SymmetricKey32}; +pub use signatures::{Ed25519SigningKey, Ed25519VerifyingKey}; pub use x3dh::{DomainSeparator, PrekeyBundle, X3Handshake}; pub use xeddsa_sign::{Ed25519Signature, SignatureError, xeddsa_sign, xeddsa_verify}; diff --git a/core/crypto/src/signatures.rs b/core/crypto/src/signatures.rs new file mode 100644 index 0000000..28eb6dd --- /dev/null +++ b/core/crypto/src/signatures.rs @@ -0,0 +1,83 @@ +use ed25519_dalek::{self, Signer}; +use rand_core::OsRng; +use std::fmt::Debug; +use thiserror::Error; + +#[derive(Debug, Error)] +#[error("verification failed of the Ed25519 Signature")] +pub struct SignatureVerificationError {} + +/// A 64-byte XEdDSA signature over an Ed25519-compatible curve. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Ed25519Signature([u8; 64]); + +impl Ed25519Signature { + pub fn empty() -> Self { + Self([0u8; 64]) + } +} + +impl AsRef<[u8; 64]> for Ed25519Signature { + fn as_ref(&self) -> &[u8; 64] { + &self.0 + } +} + +impl From<[u8; 64]> for Ed25519Signature { + fn from(bytes: [u8; 64]) -> Self { + Self(bytes) + } +} + +#[derive(Clone)] +pub struct Ed25519SigningKey(ed25519_dalek::SigningKey); + +impl Ed25519SigningKey { + pub fn generate() -> Self { + Self(ed25519_dalek::SigningKey::generate(&mut OsRng)) + } + + pub fn sign(&self, msg: &[u8]) -> Ed25519Signature { + self.0.sign(msg).to_bytes().into() + } + + pub fn verifying_key(&self) -> Ed25519VerifyingKey { + self.0.verifying_key().into() + } +} + +impl Debug for Ed25519SigningKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("Ed25519SigningKey") + .field(&"[redacted]") + .finish() + } +} + +#[derive(Clone, Debug)] +pub struct Ed25519VerifyingKey(ed25519_dalek::VerifyingKey); + +impl Ed25519VerifyingKey { + pub fn verify( + &self, + msg: &[u8], + signature: &Ed25519Signature, + ) -> Result<(), SignatureVerificationError> { + let inner_signature = signature.0; + self.0 + .verify_strict(msg, &ed25519_dalek::Signature::from_bytes(&inner_signature)) + .map_err(|_| SignatureVerificationError {}) + } +} + +impl From for Ed25519VerifyingKey { + fn from(value: ed25519_dalek::VerifyingKey) -> Self { + Ed25519VerifyingKey(value) + } +} + +impl AsRef<[u8]> for Ed25519VerifyingKey { + fn as_ref(&self) -> &[u8] { + self.0.as_bytes() + } +}