Skip to content
Open
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: 4 additions & 2 deletions CODING.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ The `bc-ur` crate is also in this workspace and provides the UR serialization/de
| `SymmetricKey`, `EncryptedMessage` | Types for symmetric encryption |
| `ECPrivateKey`, `ECPublicKey` | Elliptic curve cryptography keys |
| `Ed25519PrivateKey`, `Ed25519PublicKey` | Ed25519 cryptographic keys |
| `Sr25519PrivateKey`, `Sr25519PublicKey` | SR25519 (Schnorr-Ristretto) cryptographic keys |
| `X25519PrivateKey`, `X25519PublicKey` | X25519 key agreement keys |
| `SigningPrivateKey`, `SigningPublicKey` | Keys for digital signatures |
| `MLDSAPrivateKey`, `MLDSAPublicKey` | Post-quantum digital signature keys |
Expand Down Expand Up @@ -154,10 +155,11 @@ This section inventories all public API items that need documentation, ordered f
2. **✅ `AuthenticationTag`** (`symmetric/authentication_tag.rs`) - Authentication tag for authenticated encryption
3. **✅ `EncryptedMessage`** (`symmetric/encrypted_message.rs`) - A symmetrically-encrypted message

#### Ed25519 and X25519
#### Ed25519, SR25519, and X25519

1. **✅ `Ed25519PrivateKey`**, **✅ `Ed25519PublicKey`** (`ed25519/ed25519_private_key.rs`, `ed25519/ed25519_public_key.rs`) - Ed25519 keys
2. **✅ `X25519PrivateKey`**, **✅ `X25519PublicKey`** (`x25519/x25519_private_key.rs`, `x25519/x25519_public_key.rs`) - X25519 keys
2. **✅ `Sr25519PrivateKey`**, **✅ `Sr25519PublicKey`** (`sr25519/sr25519_private_key.rs`, `sr25519/sr25519_public_key.rs`) - SR25519 keys
3. **✅ `X25519PrivateKey`**, **✅ `X25519PublicKey`** (`x25519/x25519_private_key.rs`, `x25519/x25519_public_key.rs`) - X25519 keys

#### ECDSA

Expand Down
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ zeroize = { version = "1.8.1", default-features = false, features = [
"zeroize_derive",
] }
rand_core = "^0.9.3"
schnorrkel = { version = "0.11.5", optional = true }
blake2 = { version = "0.10", optional = true }
pqcrypto-mlkem = { version = "^0.1.0", optional = true }
pqcrypto-mldsa = { version = "^0.1.1", optional = true }
pqcrypto-traits = { version = "^0.3.5", optional = true }
Expand All @@ -46,9 +48,10 @@ indoc = "^2.0.0"
version-sync = "^0.9.0"

[features]
default = ["secp256k1", "ed25519", "pqcrypto", "ssh"]
default = ["secp256k1", "ed25519", "sr25519", "pqcrypto", "ssh"]
secp256k1 = ["bc-crypto/secp256k1"]
ed25519 = ["bc-crypto/ed25519"]
sr25519 = ["dep:schnorrkel", "dep:blake2"]
pqcrypto = ["dep:pqcrypto-mlkem", "dep:pqcrypto-mldsa", "dep:pqcrypto-traits"]
ssh = ["dep:ssh-key"]
ssh-agent = ["dep:ssh-agent-client-rs"]
Expand Down
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ The library is organized into several categories of cryptographic primitives and
| `SchnorrPublicKey` | A Schnorr (x-only) elliptic curve public key (BIP-340) |
| `Ed25519PrivateKey` | An Edwards curve (Ed25519) private key for signatures |
| `Ed25519PublicKey` | An Edwards curve (Ed25519) public key |
| `Sr25519PrivateKey` | A Schnorr-Ristretto (SR25519) private key for signatures |
| `Sr25519PublicKey` | A Schnorr-Ristretto (SR25519) public key |
| `X25519PrivateKey` | A Curve25519 private key used for key agreement |
| `X25519PublicKey` | A Curve25519 public key used for key agreement |

Expand All @@ -81,14 +83,14 @@ The library is organized into several categories of cryptographic primitives and

### Digital Signatures

| Name | Description |
| ------------------- | ----------------------------------------------------------------------------- |
| `SigningPrivateKey` | A private key for digital signatures (Schnorr, ECDSA, Ed25519, MLDSA, or SSH) |
| `SigningPublicKey` | A public key for signature verification |
| `Signature` | A digital signature supporting multiple algorithms |
| `SignatureScheme` | Enumeration of supported signature schemes |
| `Signer` | A trait for types that can create signatures |
| `Verifier` | A trait for types that can verify signatures |
| Name | Description |
| ------------------- | -------------------------------------------------------------------------------------- |
| `SigningPrivateKey` | A private key for digital signatures (Schnorr, ECDSA, Ed25519, Sr25519, MLDSA, or SSH) |
| `SigningPublicKey` | A public key for signature verification |
| `Signature` | A digital signature supporting multiple algorithms |
| `SignatureScheme` | Enumeration of supported signature schemes |
| `Signer` | A trait for types that can create signatures |
| `Verifier` | A trait for types that can verify signatures |

### Key Encapsulation and Encryption

Expand Down
3 changes: 3 additions & 0 deletions run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,14 @@ cargo test --lib --bins --tests --benches --no-default-features > /dev/null
test_only_features "pqcrypto"
test_only_features "secp256k1"
test_only_features "ed25519"
test_only_features "sr25519"
test_only_features "ssh"

test_only_features "ssh,ed25519"
test_only_features "secp256k1,ed25519,pqcrypto"
test_only_features "secp256k1,pqcrypto,ssh"
test_only_features "sr25519,ed25519"
test_only_features "sr25519,secp256k1"

test_additional_features "ssh-agent"
test_additional_features "ssh-agent-tests"
Expand Down
2 changes: 2 additions & 0 deletions src/keypair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ pub fn keypair_opt(
#[cfg(any(
feature = "secp256k1",
feature = "ed25519",
feature = "sr25519",
feature = "ssh",
feature = "pqcrypto"
))]
Expand All @@ -130,6 +131,7 @@ pub fn keypair_opt(
#[cfg(not(any(
feature = "secp256k1",
feature = "ed25519",
feature = "sr25519",
feature = "ssh",
feature = "pqcrypto"
)))]
Expand Down
5 changes: 5 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ mod ed25519;
#[cfg(feature = "ed25519")]
pub use ed25519::{Ed25519PrivateKey, Ed25519PublicKey};

#[cfg(feature = "sr25519")]
mod sr25519;
#[cfg(feature = "sr25519")]
pub use sr25519::{Sr25519PrivateKey, Sr25519PublicKey};

mod seed;
pub use seed::Seed;

Expand Down
2 changes: 2 additions & 0 deletions src/private_keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ impl CBORTaggedEncodable for PrivateKeys {
#[cfg(any(
feature = "secp256k1",
feature = "ed25519",
feature = "sr25519",
feature = "ssh",
feature = "pqcrypto"
))]
Expand All @@ -169,6 +170,7 @@ impl CBORTaggedEncodable for PrivateKeys {
#[cfg(not(any(
feature = "secp256k1",
feature = "ed25519",
feature = "sr25519",
feature = "ssh",
feature = "pqcrypto"
)))]
Expand Down
2 changes: 2 additions & 0 deletions src/public_keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ impl CBORTaggedEncodable for PublicKeys {
#[cfg(any(
feature = "secp256k1",
feature = "ed25519",
feature = "sr25519",
feature = "ssh",
feature = "pqcrypto"
))]
Expand All @@ -163,6 +164,7 @@ impl CBORTaggedEncodable for PublicKeys {
#[cfg(not(any(
feature = "secp256k1",
feature = "ed25519",
feature = "sr25519",
feature = "ssh",
feature = "pqcrypto"
)))]
Expand Down
66 changes: 59 additions & 7 deletions src/signing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ mod tests {
use bc_rand::make_fake_random_number_generator;
#[cfg(any(feature = "secp256k1", feature = "pqcrypto"))]
use dcbor::prelude::*;
#[cfg(any(feature = "secp256k1", feature = "ed25519"))]
#[cfg(any(feature = "secp256k1", feature = "ed25519", feature = "sr25519"))]
use hex_literal::hex;
#[cfg(feature = "secp256k1")]
use indoc::indoc;
Expand All @@ -100,6 +100,7 @@ mod tests {
#[cfg(any(
feature = "secp256k1",
feature = "ed25519",
feature = "sr25519",
feature = "ssh"
))]
use super::SignatureScheme;
Expand All @@ -110,17 +111,22 @@ mod tests {
#[cfg(any(
feature = "secp256k1",
feature = "ed25519",
feature = "sr25519",
feature = "ssh"
))]
use crate::SigningOptions;
#[cfg(all(feature = "secp256k1", not(feature = "ed25519")))]
use crate::SigningPrivateKey;
#[cfg(feature = "ed25519")]
use crate::{Ed25519PrivateKey, Signer, SigningPrivateKey, Verifier};
use crate::Ed25519PrivateKey;
#[cfg(feature = "sr25519")]
use crate::Sr25519PrivateKey;
#[cfg(any(feature = "ed25519", feature = "sr25519"))]
use crate::{Signer, SigningPrivateKey, Verifier};
#[cfg(feature = "pqcrypto")]
use crate::{MLDSA, MLDSASignature};
#[cfg(all(
not(feature = "ed25519"),
not(any(feature = "ed25519", feature = "sr25519")),
any(feature = "secp256k1", feature = "ssh")
))]
use crate::{Signer, Verifier};
Expand All @@ -142,9 +148,17 @@ mod tests {
"322b5c1dd5a17c3481c2297990c85c232ed3c17b52ce9905c6ec5193ad132c36"
)));

#[cfg(feature = "sr25519")]
fn sr25519_signing_private_key() -> SigningPrivateKey {
SigningPrivateKey::new_sr25519(Sr25519PrivateKey::from_seed(hex!(
"322b5c1dd5a17c3481c2297990c85c232ed3c17b52ce9905c6ec5193ad132c36"
)))
}

#[cfg(any(
feature = "secp256k1",
feature = "ed25519",
feature = "sr25519",
feature = "pqcrypto",
feature = "ssh"
))]
Expand Down Expand Up @@ -227,6 +241,22 @@ mod tests {
assert_eq!(signature, received_signature);
}

#[test]
#[cfg(feature = "sr25519")]
fn test_sr25519_cbor() {
let private_key = sr25519_signing_private_key();
let signature = private_key.sign(MESSAGE).unwrap();
let signature_cbor: CBOR = signature.clone().into();
let tagged_cbor_data = signature_cbor.to_cbor_data();

let received_signature =
Signature::from_tagged_cbor_data(&tagged_cbor_data).unwrap();

let public_key = private_key.public_key().unwrap();
assert!(public_key.verify(&signature, MESSAGE));
assert!(public_key.verify(&received_signature, MESSAGE));
}

#[test]
#[cfg(feature = "ed25519")]
fn test_ed25519_signing() {
Expand All @@ -242,6 +272,22 @@ mod tests {
assert!(public_key.verify(&another_signature, MESSAGE));
}

#[test]
#[cfg(feature = "sr25519")]
fn test_sr25519_signing() {
let private_key = sr25519_signing_private_key();
let public_key = private_key.public_key().unwrap();
let signature = private_key.sign(MESSAGE).unwrap();

assert!(public_key.verify(&signature, MESSAGE));
assert!(!public_key.verify(&signature, b"Wolf Mcnally"));

// SR25519 signatures include randomness, so they differ each time
let another_signature = private_key.sign(MESSAGE).unwrap();
assert_ne!(signature, another_signature);
assert!(public_key.verify(&another_signature, MESSAGE));
}

#[test]
#[cfg(feature = "pqcrypto")]
fn test_mldsa_signing() {
Expand All @@ -268,7 +314,7 @@ mod tests {
assert_eq!(signature, received_signature);
}

#[cfg(any(feature = "secp256k1", feature = "ed25519", feature = "ssh"))]
#[cfg(any(feature = "secp256k1", feature = "ed25519", feature = "sr25519", feature = "ssh"))]
fn test_keypair_signing(
scheme: SignatureScheme,
options: Option<SigningOptions>,
Expand Down Expand Up @@ -297,10 +343,16 @@ mod tests {
test_keypair_signing(SignatureScheme::Ed25519, None);
}

#[test]
#[cfg(feature = "sr25519")]
fn test_sr25519_keypair() {
test_keypair_signing(SignatureScheme::Sr25519, None);
}

#[test]
#[cfg(all(
feature = "pqcrypto",
any(feature = "secp256k1", feature = "ed25519")
any(feature = "secp256k1", feature = "ed25519", feature = "sr25519")
))]
fn test_mldsa44_keypair() {
test_keypair_signing(SignatureScheme::MLDSA44, None);
Expand All @@ -309,7 +361,7 @@ mod tests {
#[test]
#[cfg(all(
feature = "pqcrypto",
any(feature = "secp256k1", feature = "ed25519")
any(feature = "secp256k1", feature = "ed25519", feature = "sr25519")
))]
fn test_mldsa65_keypair() {
test_keypair_signing(SignatureScheme::MLDSA65, None);
Expand All @@ -318,7 +370,7 @@ mod tests {
#[test]
#[cfg(all(
feature = "pqcrypto",
any(feature = "secp256k1", feature = "ed25519")
any(feature = "secp256k1", feature = "ed25519", feature = "sr25519")
))]
fn test_mldsa87_keypair() {
test_keypair_signing(SignatureScheme::MLDSA87, None);
Expand Down
Loading