Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ path = "keetanetwork-utils"
default-features = false

[workspace.dependencies.keetanetwork-crypto]
version = "0.2.0"
version = "0.3.0"
path = "keetanetwork-crypto"
default-features = false

Expand All @@ -159,7 +159,7 @@ path = "keetanetwork-account"
default-features = false

[workspace.dependencies.keetanetwork-x509]
version = "0.2.1"
version = "0.3.0"
path = "keetanetwork-x509"
default-features = false

Expand All @@ -184,7 +184,7 @@ path = "keetanetwork-client"
default-features = false

[workspace.dependencies.keetanetwork-bindings]
version = "0.3.0"
version = "0.3.1"
path = "keetanetwork-bindings"
default-features = false

Expand Down
2 changes: 1 addition & 1 deletion keetanetwork-bindings/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "keetanetwork-bindings"
version = "0.3.0"
version = "0.3.1"
edition.workspace = true
authors.workspace = true
license.workspace = true
Expand Down
1 change: 1 addition & 0 deletions keetanetwork-bindings/src/x509.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ impl From<CertificateError> for CodedError {
CertificateError::InvalidExtension { .. } => "INVALID_EXTENSION",
CertificateError::ChainValidationFailed { .. } => "CHAIN_VALIDATION_FAILED",
CertificateError::UnsupportedVersion { .. } => "UNSUPPORTED_VERSION",
CertificateError::UnsupportedSignatureHash { .. } => "UNSUPPORTED_SIGNATURE_HASH",
CertificateError::CertificateSignatureVerificationFailed => "SIGNATURE_VERIFICATION_FAILED",
CertificateError::CertificateDuplicateIncluded => "CERTIFICATE_DUPLICATE",
CertificateError::CertificateOrphanFound => "CERTIFICATE_ORPHAN",
Expand Down
2 changes: 1 addition & 1 deletion keetanetwork-crypto/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "keetanetwork-crypto"
version.workspace = true
version = "0.3.0"
edition.workspace = true
authors.workspace = true
license.workspace = true
Expand Down
44 changes: 4 additions & 40 deletions keetanetwork-crypto/src/algorithms/secp256k1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ use crate::operations::encryption::{AsymmetricEncryption, KeyExchange, KeyGenera
#[cfg(feature = "encryption")]
use crate::utils::generate_random_seed;

#[cfg(feature = "signature")]
use crate::hash::{hash_default, HashAlgorithm};
#[cfg(feature = "signature")]
use crate::operations::signature::{
CryptoSigner, CryptoSignerWithOptions, CryptoVerifier, CryptoVerifierWithOptions, SigningOptions,
Expand Down Expand Up @@ -223,25 +221,10 @@ impl CryptoSignerWithOptions<Signature> for Secp256k1PrivateKey {
message: T,
options: SigningOptions,
) -> Result<Signature, ::signature::Error> {
let message = message.as_ref();
let signing_key = SigningKey::from(&self.inner);

if options.raw {
// For raw signing, treat the message as a pre-computed hash
// and use prehash signing to avoid double hashing
if message.len() != 32 {
return Err(::signature::Error::new());
}
signing_key.sign_prehash(message)
} else if options.for_cert {
// For certificate signing, use SHA2-256
let data = HashAlgorithm::Sha2_256.hash(message);
signing_key.sign_prehash(&data)
} else {
// For regular signing, use the default hash algorithm
let data = hash_default(message).to_vec();
signing_key.sign_prehash(&data)
}
let digest = options.digest(message.as_ref())?;
signing_key.sign_prehash(&digest)
}
}

Expand Down Expand Up @@ -338,29 +321,10 @@ impl CryptoVerifierWithOptions<Signature> for Secp256k1PublicKey {
signature: &Signature,
options: SigningOptions,
) -> Result<(), ::signature::Error> {
let message = message.as_ref();
let verifying_key = VerifyingKey::from(&self.inner);

if options.raw {
// For raw verification, treat the message as a pre-computed hash
// and use prehash verification to avoid double hashing
if message.len() != 32 {
return Err(::signature::Error::new());
}
verifying_key.verify_prehash(message, signature)
} else {
// For non-raw verification, hash the message first
let data = if options.for_cert {
// For certificates, use SHA2-256
HashAlgorithm::Sha2_256.hash(message)
} else {
// For regular verification, use default hash
hash_default(message).to_vec()
};

// Use prehash verification since we've already computed the hash
verifying_key.verify_prehash(&data, signature)
}
let digest = options.digest(message.as_ref())?;
verifying_key.verify_prehash(&digest, signature)
}
}

Expand Down
40 changes: 4 additions & 36 deletions keetanetwork-crypto/src/algorithms/secp256r1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ use aead::KeyInit;
#[cfg(feature = "encryption")]
use p256::ecdh::diffie_hellman;

#[cfg(feature = "signature")]
use crate::hash::{hash_default, HashAlgorithm};
#[cfg(feature = "signature")]
use crate::operations::signature::{
CryptoSigner, CryptoSignerWithOptions, CryptoVerifier, CryptoVerifierWithOptions, SigningOptions,
Expand Down Expand Up @@ -224,25 +222,10 @@ impl CryptoSignerWithOptions<Signature> for Secp256r1PrivateKey {
message: T,
options: SigningOptions,
) -> Result<Signature, ::signature::Error> {
let message = message.as_ref();
let signing_key = SigningKey::from(&self.inner);

if options.raw {
// For raw signing, treat the message as a pre-computed hash
// and use prehash signing to avoid double hashing
if message.len() != 32 {
return Err(::signature::Error::new());
}
signing_key.sign_prehash(message)
} else if options.for_cert {
// For certificate signing, use SHA2-256
let data = HashAlgorithm::Sha2_256.hash(message);
signing_key.sign_prehash(&data)
} else {
// For regular signing, use the default hash algorithm (SHA3-256)
let data = hash_default(message).to_vec();
signing_key.sign_prehash(&data)
}
let digest = options.digest(message.as_ref())?;
signing_key.sign_prehash(&digest)
}
}

Expand Down Expand Up @@ -338,25 +321,10 @@ impl CryptoVerifierWithOptions<Signature> for Secp256r1PublicKey {
signature: &Signature,
options: SigningOptions,
) -> Result<(), ::signature::Error> {
let message = message.as_ref();
let verifying_key = VerifyingKey::from(&self.inner);

if options.raw {
// For raw verification, treat the message as a pre-computed hash
// and use prehash verification to avoid double hashing
if message.len() != 32 {
return Err(::signature::Error::new());
}
verifying_key.verify_prehash(message, signature)
} else if options.for_cert {
// For certificate verification, use SHA2-256
let data = HashAlgorithm::Sha2_256.hash(message);
verifying_key.verify_prehash(&data, signature)
} else {
// For regular verification, use the default hash algorithm
let data = hash_default(message).to_vec();
verifying_key.verify_prehash(&data, signature)
}
let digest = options.digest(message.as_ref())?;
verifying_key.verify_prehash(&digest, signature)
}
}

Expand Down
60 changes: 51 additions & 9 deletions keetanetwork-crypto/src/operations/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
//! This module provides idiomatic traits and types for cryptographic signing
//! and verification operations, leveraging the RustCrypto ecosystem.

use alloc::borrow::Cow;
use alloc::vec::Vec;

use crate::algorithms::CryptoAlgorithm;
use crate::hash::hash_default;

// Re-export key RustCrypto signature traits for easier use
pub use signature::{
Expand Down Expand Up @@ -50,27 +52,38 @@ where
/// Signing and verification options for cryptographic operations.
///
/// Default options are:
/// - raw: false (will pre-hash the message)
/// - for_cert: false (use SEC format, not DER)
/// - raw: false (will pre-hash the message with the network default hash)
///
/// Callers that need a different hash pre-hash the message themselves
/// and use [`SigningOptions::raw`].
#[derive(Debug, Copy, Clone, Default)]
pub struct SigningOptions {
/// If true, use the raw message without hashing
/// If false, pre-hash the message before signing/verification
pub raw: bool,

/// For certificate processing
pub for_cert: bool,
}

impl SigningOptions {
/// Create options for raw message processing (no pre-hashing)
pub fn raw() -> Self {
Self { raw: true, for_cert: false }
Self { raw: true }
}

/// Create options for certificate processing
pub fn for_cert() -> Self {
Self { raw: false, for_cert: true }
/// Resolve `message` into the digest to sign or verify.
///
/// - raw: `message` must already be a 32-byte digest (borrowed as-is)
/// - otherwise: pre-hash with the network default hash (SHA3-256)
pub fn digest<'a>(&self, message: &'a [u8]) -> Result<Cow<'a, [u8]>, SignatureError> {
if self.raw {
if message.len() != 32 {
return Err(SignatureError::new());
}

return Ok(Cow::Borrowed(message));
}

let digest = hash_default(message);
Ok(Cow::Owned(digest.to_vec()))
}
}

Expand All @@ -96,3 +109,32 @@ pub trait CryptoVerifierWithOptions<S>: CryptoVerifier<S> {
options: SigningOptions,
) -> Result<(), SignatureError>;
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_digest_raw_borrows_precomputed_hash() -> Result<(), SignatureError> {
let precomputed = [0x42u8; 32];
let digest = SigningOptions::raw().digest(&precomputed)?;
assert!(matches!(digest, Cow::Borrowed(_)));
assert_eq!(digest.as_ref(), precomputed);
Ok(())
}

#[test]
fn test_digest_raw_rejects_non_digest_length() {
assert!(SigningOptions::raw().digest(b"too short").is_err());
assert!(SigningOptions::raw().digest(&[0u8; 64]).is_err());
}

#[test]
fn test_digest_default_prehashes_with_network_default() -> Result<(), SignatureError> {
let message = b"message to hash";
let digest = SigningOptions::default().digest(message)?;
assert!(matches!(digest, Cow::Owned(_)));
assert_eq!(digest.as_ref(), hash_default(message));
Ok(())
}
}
18 changes: 0 additions & 18 deletions keetanetwork-crypto/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,21 +330,9 @@ macro_rules! test_signatures {
let different_hash = [0x42u8; 32]; // Different from hash_default(message)
let signature_raw = private_key.sign_with_options(different_hash, raw_options)?;

// Test with cert options (pre-hash, but for_cert flag set)
let cert_options = crate::operations::signature::SigningOptions::for_cert();
let signature_cert = private_key.sign_with_options(message, cert_options)?;

// Signatures should be different when using different message processing
assert_ne!(signature_default.to_bytes(), signature_raw.to_bytes());

// For Ed25519, default and cert should be the same since they both pre-hash
// For ECDSA curves, they should be different due to different hash algorithms
if stringify!($seed_suffix) == "\"ed25519\"" {
assert_eq!(signature_default.to_bytes(), signature_cert.to_bytes());
} else {
assert_ne!(signature_default.to_bytes(), signature_cert.to_bytes());
}

// Verify that the regular signing (which signs raw message) differs from options-based signing (which pre-hashes)
// For Ed25519: try_sign signs raw message, sign_with_options(default) signs hash of message
// For ECDSA: try_sign pre-hashes using one method, sign_with_options(default) might use different hash
Expand Down Expand Up @@ -375,12 +363,6 @@ macro_rules! test_signatures {
.verify_with_options(pre_computed_hash, &signature_raw, raw_options)
.is_ok());

let cert_options = crate::operations::signature::SigningOptions::for_cert();
let signature_cert = private_key.sign_with_options(message, cert_options)?;
assert!(public_key
.verify_with_options(message, &signature_cert, cert_options)
.is_ok());

// Test verification failure with mismatched options
assert!(public_key
.verify_with_options(pre_computed_hash, &signature_raw, default_options)
Expand Down
2 changes: 1 addition & 1 deletion keetanetwork-x509/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "keetanetwork-x509"
version = "0.2.1"
version = "0.3.0"
edition.workspace = true
authors.workspace = true
license.workspace = true
Expand Down
Loading
Loading