Skip to content

Commit 5f442d9

Browse files
Add sr25519
1 parent 6529923 commit 5f442d9

16 files changed

+690
-21
lines changed

CODING.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ The `bc-ur` crate is also in this workspace and provides the UR serialization/de
6161
| `SymmetricKey`, `EncryptedMessage` | Types for symmetric encryption |
6262
| `ECPrivateKey`, `ECPublicKey` | Elliptic curve cryptography keys |
6363
| `Ed25519PrivateKey`, `Ed25519PublicKey` | Ed25519 cryptographic keys |
64+
| `Sr25519PrivateKey`, `Sr25519PublicKey` | SR25519 (Schnorr-Ristretto) cryptographic keys |
6465
| `X25519PrivateKey`, `X25519PublicKey` | X25519 key agreement keys |
6566
| `SigningPrivateKey`, `SigningPublicKey` | Keys for digital signatures |
6667
| `MLDSAPrivateKey`, `MLDSAPublicKey` | Post-quantum digital signature keys |
@@ -154,10 +155,11 @@ This section inventories all public API items that need documentation, ordered f
154155
2. **`AuthenticationTag`** (`symmetric/authentication_tag.rs`) - Authentication tag for authenticated encryption
155156
3. **`EncryptedMessage`** (`symmetric/encrypted_message.rs`) - A symmetrically-encrypted message
156157

157-
#### Ed25519 and X25519
158+
#### Ed25519, SR25519, and X25519
158159

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

162164
#### ECDSA
163165

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ zeroize = { version = "1.8.1", default-features = false, features = [
3535
"zeroize_derive",
3636
] }
3737
rand_core = "0.6.4"
38+
schnorrkel = { version = "0.11.5", optional = true }
39+
blake2 = { version = "0.10", optional = true }
3840
pqcrypto-mlkem = { version = "^0.1.0", optional = true }
3941
pqcrypto-mldsa = { version = "^0.1.1", optional = true }
4042
pqcrypto-traits = { version = "^0.3.5", optional = true }
@@ -46,9 +48,10 @@ indoc = "^2.0.0"
4648
version-sync = "^0.9.0"
4749

4850
[features]
49-
default = ["secp256k1", "ed25519", "pqcrypto", "ssh"]
51+
default = ["secp256k1", "ed25519", "sr25519", "pqcrypto", "ssh"]
5052
secp256k1 = ["bc-crypto/secp256k1"]
5153
ed25519 = ["bc-crypto/ed25519"]
54+
sr25519 = ["dep:schnorrkel", "dep:blake2"]
5255
pqcrypto = ["dep:pqcrypto-mlkem", "dep:pqcrypto-mldsa", "dep:pqcrypto-traits"]
5356
ssh = ["dep:ssh-key"]
5457
ssh-agent = ["dep:ssh-agent-client-rs"]

README.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ The library is organized into several categories of cryptographic primitives and
6565
| `SchnorrPublicKey` | A Schnorr (x-only) elliptic curve public key (BIP-340) |
6666
| `Ed25519PrivateKey` | An Edwards curve (Ed25519) private key for signatures |
6767
| `Ed25519PublicKey` | An Edwards curve (Ed25519) public key |
68+
| `Sr25519PrivateKey` | A Schnorr-Ristretto (SR25519) private key for signatures |
69+
| `Sr25519PublicKey` | A Schnorr-Ristretto (SR25519) public key |
6870
| `X25519PrivateKey` | A Curve25519 private key used for key agreement |
6971
| `X25519PublicKey` | A Curve25519 public key used for key agreement |
7072

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

8284
### Digital Signatures
8385

84-
| Name | Description |
85-
| ------------------- | ----------------------------------------------------------------------------- |
86-
| `SigningPrivateKey` | A private key for digital signatures (Schnorr, ECDSA, Ed25519, MLDSA, or SSH) |
87-
| `SigningPublicKey` | A public key for signature verification |
88-
| `Signature` | A digital signature supporting multiple algorithms |
89-
| `SignatureScheme` | Enumeration of supported signature schemes |
90-
| `Signer` | A trait for types that can create signatures |
91-
| `Verifier` | A trait for types that can verify signatures |
86+
| Name | Description |
87+
| ------------------- | -------------------------------------------------------------------------------------- |
88+
| `SigningPrivateKey` | A private key for digital signatures (Schnorr, ECDSA, Ed25519, Sr25519, MLDSA, or SSH) |
89+
| `SigningPublicKey` | A public key for signature verification |
90+
| `Signature` | A digital signature supporting multiple algorithms |
91+
| `SignatureScheme` | Enumeration of supported signature schemes |
92+
| `Signer` | A trait for types that can create signatures |
93+
| `Verifier` | A trait for types that can verify signatures |
9294

9395
### Key Encapsulation and Encryption
9496

run_tests.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,14 @@ cargo test --lib --bins --tests --benches --no-default-features > /dev/null
4040
test_only_features "pqcrypto"
4141
test_only_features "secp256k1"
4242
test_only_features "ed25519"
43+
test_only_features "sr25519"
4344
test_only_features "ssh"
4445

4546
test_only_features "ssh,ed25519"
4647
test_only_features "secp256k1,ed25519,pqcrypto"
4748
test_only_features "secp256k1,pqcrypto,ssh"
49+
test_only_features "sr25519,ed25519"
50+
test_only_features "sr25519,secp256k1"
4851

4952
test_additional_features "ssh-agent"
5053
test_additional_features "ssh-agent-tests"

src/keypair.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ pub fn keypair_opt(
111111
#[cfg(any(
112112
feature = "secp256k1",
113113
feature = "ed25519",
114+
feature = "sr25519",
114115
feature = "ssh",
115116
feature = "pqcrypto"
116117
))]
@@ -130,6 +131,7 @@ pub fn keypair_opt(
130131
#[cfg(not(any(
131132
feature = "secp256k1",
132133
feature = "ed25519",
134+
feature = "sr25519",
133135
feature = "ssh",
134136
feature = "pqcrypto"
135137
)))]

src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ mod ed25519;
5757
#[cfg(feature = "ed25519")]
5858
pub use ed25519::{Ed25519PrivateKey, Ed25519PublicKey};
5959

60+
#[cfg(feature = "sr25519")]
61+
mod sr25519;
62+
#[cfg(feature = "sr25519")]
63+
pub use sr25519::{Sr25519PrivateKey, Sr25519PublicKey};
64+
6065
mod seed;
6166
pub use seed::Seed;
6267

src/private_keys.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ impl CBORTaggedEncodable for PrivateKeys {
156156
#[cfg(any(
157157
feature = "secp256k1",
158158
feature = "ed25519",
159+
feature = "sr25519",
159160
feature = "ssh",
160161
feature = "pqcrypto"
161162
))]
@@ -169,6 +170,7 @@ impl CBORTaggedEncodable for PrivateKeys {
169170
#[cfg(not(any(
170171
feature = "secp256k1",
171172
feature = "ed25519",
173+
feature = "sr25519",
172174
feature = "ssh",
173175
feature = "pqcrypto"
174176
)))]

src/public_keys.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ impl CBORTaggedEncodable for PublicKeys {
150150
#[cfg(any(
151151
feature = "secp256k1",
152152
feature = "ed25519",
153+
feature = "sr25519",
153154
feature = "ssh",
154155
feature = "pqcrypto"
155156
))]
@@ -163,6 +164,7 @@ impl CBORTaggedEncodable for PublicKeys {
163164
#[cfg(not(any(
164165
feature = "secp256k1",
165166
feature = "ed25519",
167+
feature = "sr25519",
166168
feature = "ssh",
167169
feature = "pqcrypto"
168170
)))]

src/signing/mod.rs

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ mod tests {
9090
use bc_rand::make_fake_random_number_generator;
9191
#[cfg(any(feature = "secp256k1", feature = "pqcrypto"))]
9292
use dcbor::prelude::*;
93-
#[cfg(any(feature = "secp256k1", feature = "ed25519"))]
93+
#[cfg(any(feature = "secp256k1", feature = "ed25519", feature = "sr25519"))]
9494
use hex_literal::hex;
9595
#[cfg(feature = "secp256k1")]
9696
use indoc::indoc;
@@ -100,6 +100,7 @@ mod tests {
100100
#[cfg(any(
101101
feature = "secp256k1",
102102
feature = "ed25519",
103+
feature = "sr25519",
103104
feature = "ssh"
104105
))]
105106
use super::SignatureScheme;
@@ -110,17 +111,22 @@ mod tests {
110111
#[cfg(any(
111112
feature = "secp256k1",
112113
feature = "ed25519",
114+
feature = "sr25519",
113115
feature = "ssh"
114116
))]
115117
use crate::SigningOptions;
116118
#[cfg(all(feature = "secp256k1", not(feature = "ed25519")))]
117119
use crate::SigningPrivateKey;
118120
#[cfg(feature = "ed25519")]
119-
use crate::{Ed25519PrivateKey, Signer, SigningPrivateKey, Verifier};
121+
use crate::Ed25519PrivateKey;
122+
#[cfg(feature = "sr25519")]
123+
use crate::Sr25519PrivateKey;
124+
#[cfg(any(feature = "ed25519", feature = "sr25519"))]
125+
use crate::{Signer, SigningPrivateKey, Verifier};
120126
#[cfg(feature = "pqcrypto")]
121127
use crate::{MLDSA, MLDSASignature};
122128
#[cfg(all(
123-
not(feature = "ed25519"),
129+
not(any(feature = "ed25519", feature = "sr25519")),
124130
any(feature = "secp256k1", feature = "ssh")
125131
))]
126132
use crate::{Signer, Verifier};
@@ -142,9 +148,17 @@ mod tests {
142148
"322b5c1dd5a17c3481c2297990c85c232ed3c17b52ce9905c6ec5193ad132c36"
143149
)));
144150

151+
#[cfg(feature = "sr25519")]
152+
fn sr25519_signing_private_key() -> SigningPrivateKey {
153+
SigningPrivateKey::new_sr25519(Sr25519PrivateKey::from_seed(hex!(
154+
"322b5c1dd5a17c3481c2297990c85c232ed3c17b52ce9905c6ec5193ad132c36"
155+
)))
156+
}
157+
145158
#[cfg(any(
146159
feature = "secp256k1",
147160
feature = "ed25519",
161+
feature = "sr25519",
148162
feature = "pqcrypto",
149163
feature = "ssh"
150164
))]
@@ -242,6 +256,22 @@ mod tests {
242256
assert!(public_key.verify(&another_signature, MESSAGE));
243257
}
244258

259+
#[test]
260+
#[cfg(feature = "sr25519")]
261+
fn test_sr25519_signing() {
262+
let private_key = sr25519_signing_private_key();
263+
let public_key = private_key.public_key().unwrap();
264+
let signature = private_key.sign(MESSAGE).unwrap();
265+
266+
assert!(public_key.verify(&signature, MESSAGE));
267+
assert!(!public_key.verify(&signature, b"Wolf Mcnally"));
268+
269+
// SR25519 signatures include randomness, so they differ each time
270+
let another_signature = private_key.sign(MESSAGE).unwrap();
271+
assert_ne!(signature, another_signature);
272+
assert!(public_key.verify(&another_signature, MESSAGE));
273+
}
274+
245275
#[test]
246276
#[cfg(feature = "pqcrypto")]
247277
fn test_mldsa_signing() {
@@ -268,7 +298,7 @@ mod tests {
268298
assert_eq!(signature, received_signature);
269299
}
270300

271-
#[cfg(any(feature = "secp256k1", feature = "ed25519", feature = "ssh"))]
301+
#[cfg(any(feature = "secp256k1", feature = "ed25519", feature = "sr25519", feature = "ssh"))]
272302
fn test_keypair_signing(
273303
scheme: SignatureScheme,
274304
options: Option<SigningOptions>,
@@ -297,10 +327,16 @@ mod tests {
297327
test_keypair_signing(SignatureScheme::Ed25519, None);
298328
}
299329

330+
#[test]
331+
#[cfg(feature = "sr25519")]
332+
fn test_sr25519_keypair() {
333+
test_keypair_signing(SignatureScheme::Sr25519, None);
334+
}
335+
300336
#[test]
301337
#[cfg(all(
302338
feature = "pqcrypto",
303-
any(feature = "secp256k1", feature = "ed25519")
339+
any(feature = "secp256k1", feature = "ed25519", feature = "sr25519")
304340
))]
305341
fn test_mldsa44_keypair() {
306342
test_keypair_signing(SignatureScheme::MLDSA44, None);
@@ -309,7 +345,7 @@ mod tests {
309345
#[test]
310346
#[cfg(all(
311347
feature = "pqcrypto",
312-
any(feature = "secp256k1", feature = "ed25519")
348+
any(feature = "secp256k1", feature = "ed25519", feature = "sr25519")
313349
))]
314350
fn test_mldsa65_keypair() {
315351
test_keypair_signing(SignatureScheme::MLDSA65, None);
@@ -318,7 +354,7 @@ mod tests {
318354
#[test]
319355
#[cfg(all(
320356
feature = "pqcrypto",
321-
any(feature = "secp256k1", feature = "ed25519")
357+
any(feature = "secp256k1", feature = "ed25519", feature = "sr25519")
322358
))]
323359
fn test_mldsa87_keypair() {
324360
test_keypair_signing(SignatureScheme::MLDSA87, None);

0 commit comments

Comments
 (0)