bc_components/
lib.rs

1#![doc(html_root_url = "https://docs.rs/bc-components/0.18.2")]
2#![warn(rust_2018_idioms)]
3
4//! # Introduction
5//!
6//! A collection of useful primitives for cryptography, semantic graphs, and
7//! cryptocurrency, primarily for use in higher-level [Blockchain
8//! Commons](https://blockchaincommons.com) projects like [Gordian
9//! Envelope](https://crates.io/crates/bc-envelope). All the types are
10//! [CBOR](https://cbor.io) serializable, and a number of them can also be
11//! serialized to and from [URs](https://crates.io/crates/bc-ur).
12//!
13//! Also includes a library of CBOR tags and UR types for use with these types.
14//!
15//! # Getting Started
16//!
17//! ```toml
18//! [dependencies]
19//! bc-components = "0.18.2"
20//! ```
21
22mod digest;
23pub use digest::Digest;
24
25mod id;
26pub use id::{XIDProvider, ARID, URI, UUID, XID};
27
28mod digest_provider;
29pub use digest_provider::DigestProvider;
30
31mod compressed;
32pub use compressed::Compressed;
33
34mod nonce;
35pub use nonce::Nonce;
36
37mod symmetric;
38pub use symmetric::{AuthenticationTag, EncryptedMessage, SymmetricKey};
39
40mod salt;
41pub use salt::Salt;
42
43mod x25519;
44pub use x25519::{X25519PrivateKey, X25519PublicKey};
45
46mod ed25519;
47pub use ed25519::{Ed25519PrivateKey, Ed25519PublicKey};
48
49mod seed;
50pub use seed::Seed;
51
52mod signing;
53pub use signing::{
54    Signature, SignatureScheme, Signer, SigningOptions, SigningPrivateKey, SigningPublicKey,
55    Verifier,
56};
57
58mod encrypter;
59pub use encrypter::{Decrypter, Encrypter};
60
61mod ec_key;
62pub use ec_key::*;
63
64mod reference;
65pub use reference::*;
66
67/// CBOR Tags used or defined by this crate.
68pub mod tags_registry;
69pub use tags::{register_tags, register_tags_in};
70pub use tags_registry as tags;
71
72mod private_key_data_provider;
73pub use private_key_data_provider::PrivateKeyDataProvider;
74
75mod private_key_base;
76pub use private_key_base::PrivateKeyBase;
77
78mod private_keys;
79pub use private_keys::{PrivateKeys, PrivateKeysProvider};
80
81mod public_keys;
82pub use public_keys::{PublicKeys, PublicKeysProvider};
83
84mod mldsa;
85pub use mldsa::{MLDSAPrivateKey, MLDSAPublicKey, MLDSASignature, MLDSA};
86
87mod mlkem;
88pub use mlkem::{MLKEMCiphertext, MLKEMPrivateKey, MLKEMPublicKey, MLKEM};
89
90mod encapsulation;
91pub use encapsulation::{
92    EncapsulationCiphertext, EncapsulationPrivateKey, EncapsulationPublicKey, EncapsulationScheme,
93    SealedMessage,
94};
95
96mod sskr_mod;
97pub use sskr_mod::{
98    sskr_combine, sskr_generate, sskr_generate_using, SSKRGroupSpec, SSKRSecret, SSKRShare,
99    SSKRSpec,
100};
101
102pub use sskr::SSKRError;
103
104mod hkdf_rng;
105pub use hkdf_rng::HKDFRng;
106
107mod keypair;
108pub use keypair::{keypair, keypair_opt, keypair_opt_using, keypair_using};
109
110#[cfg(test)]
111mod tests {
112    use std::ops::Deref;
113
114    use crate::{
115        ECPrivateKey, PrivateKeyBase, Signature, Signer, SigningOptions, SigningPrivateKey,
116        SigningPublicKey, Verifier, X25519PrivateKey, X25519PublicKey,
117    };
118    use bc_crypto::{
119        ecdsa_new_private_key_using, ecdsa_public_key_from_private_key, ecdsa_sign, ecdsa_verify,
120        schnorr_public_key_from_private_key, schnorr_sign_using, schnorr_verify,
121    };
122    use bc_rand::make_fake_random_number_generator;
123    use bc_ur::{URDecodable, UREncodable};
124    use hex_literal::hex;
125    use indoc::indoc;
126    use ssh_key::{
127        Algorithm as SSHAlgorithm, EcdsaCurve, HashAlg, LineEnding, PrivateKey as SSHPrivateKey,
128        PublicKey as SSHPublicKey,
129    };
130
131    #[test]
132    fn test_x25519_keys() {
133        crate::register_tags();
134        let mut rng = make_fake_random_number_generator();
135        let private_key = X25519PrivateKey::new_using(&mut rng);
136        let private_key_ur = private_key.ur_string();
137        assert_eq!(
138            private_key_ur,
139            "ur:agreement-private-key/hdcxkbrehkrkrsjztodseytknecfgewmgdmwfsvdvysbpmghuozsprknfwkpnehydlweynwkrtct"
140        );
141        assert_eq!(
142            X25519PrivateKey::from_ur_string(private_key_ur).unwrap(),
143            private_key
144        );
145
146        let public_key = private_key.public_key();
147        let public_key_ur = public_key.ur_string();
148        assert_eq!(
149            public_key_ur,
150            "ur:agreement-public-key/hdcxwnryknkbbymnoxhswmptgydsotwswsghfmrkksfxntbzjyrnuornkildchgswtdahehpwkrl"
151        );
152        assert_eq!(
153            X25519PublicKey::from_ur_string(public_key_ur).unwrap(),
154            public_key
155        );
156
157        let derived_private_key = X25519PrivateKey::derive_from_key_material("password".as_bytes());
158        assert_eq!(
159            derived_private_key.ur_string(),
160            "ur:agreement-private-key/hdcxkgcfkomeeyiemywkftvabnrdolmttlrnfhjnguvaiehlrldmdpemgyjlatdthsnecytdoxat"
161        );
162    }
163
164    #[test]
165    fn test_agreement() {
166        let mut rng = make_fake_random_number_generator();
167        let alice_private_key = X25519PrivateKey::new_using(&mut rng);
168        let alice_public_key = alice_private_key.public_key();
169
170        let bob_private_key = X25519PrivateKey::new_using(&mut rng);
171        let bob_public_key = bob_private_key.public_key();
172
173        let alice_shared_key = alice_private_key.shared_key_with(&bob_public_key);
174        let bob_shared_key = bob_private_key.shared_key_with(&alice_public_key);
175        assert_eq!(alice_shared_key, bob_shared_key);
176    }
177
178    #[test]
179    fn test_ecdsa_signing_keys() {
180        crate::register_tags();
181        let mut rng = make_fake_random_number_generator();
182        let schnorr_private_key = SigningPrivateKey::new_schnorr(ECPrivateKey::new_using(&mut rng));
183        let schnorr_private_key_ur = schnorr_private_key.ur_string();
184        assert_eq!(
185            schnorr_private_key_ur,
186            "ur:signing-private-key/hdcxkbrehkrkrsjztodseytknecfgewmgdmwfsvdvysbpmghuozsprknfwkpnehydlweynwkrtct"
187        );
188        assert_eq!(
189            SigningPrivateKey::from_ur_string(schnorr_private_key_ur).unwrap(),
190            schnorr_private_key
191        );
192
193        let ecdsa_private_key = SigningPrivateKey::new_ecdsa(ECPrivateKey::new_using(&mut rng));
194        let ecdsa_public_key = ecdsa_private_key.public_key().unwrap();
195        let ecdsa_public_key_ur = ecdsa_public_key.ur_string();
196        assert_eq!(
197            ecdsa_public_key_ur,
198            "ur:signing-public-key/lfadhdclaxbzutckgevlpkmdfnuoemlnvsgllokicfdekesswnfdtibkylrskomwgubaahyntaktbksbdt"
199        );
200        assert_eq!(
201            SigningPublicKey::from_ur_string(ecdsa_public_key_ur).unwrap(),
202            ecdsa_public_key
203        );
204
205        let schnorr_public_key = schnorr_private_key.public_key().unwrap();
206        let schnorr_public_key_ur = schnorr_public_key.ur_string();
207        assert_eq!(
208            schnorr_public_key_ur,
209            "ur:signing-public-key/hdcxjsrhdnidbgosndmobzwntdglzonnidmwoyrnuomdrpsptkcskerhfljssgaoidjewyjymhcp"
210        );
211        assert_eq!(
212            SigningPublicKey::from_ur_string(schnorr_public_key_ur).unwrap(),
213            schnorr_public_key
214        );
215
216        let derived_private_key = SigningPrivateKey::new_schnorr(
217            ECPrivateKey::derive_from_key_material("password".as_bytes()),
218        );
219        assert_eq!(
220            derived_private_key.ur_string(),
221            "ur:signing-private-key/hdcxahsfgobtpkkpahmnhsfmhnjnmkmkzeuraonneshkbysseyjkoeayrlvtvsmndicwkkvattfs"
222        );
223    }
224
225    fn test_ssh_signing(
226        algorithm: SSHAlgorithm,
227        expected_private_key: Option<&str>,
228        expected_public_key: Option<&str>,
229    ) {
230        const SEED: [u8; 16] = hex!("59f2293a5bce7d4de59e71b4207ac5d2");
231        let private_key_base = PrivateKeyBase::from_data(SEED);
232
233        let private_key: SigningPrivateKey = private_key_base
234            .ssh_signing_private_key(algorithm, "Key comment.")
235            .unwrap();
236        let ssh_private_key: &SSHPrivateKey = private_key.to_ssh().unwrap();
237        let ssh_private_key_string = ssh_private_key.to_openssh(LineEnding::default()).unwrap();
238
239        let public_key: SigningPublicKey = private_key.public_key().unwrap();
240        let ssh_public_key: &SSHPublicKey = public_key.to_ssh().unwrap();
241        let ssh_public_key_string = ssh_public_key.to_openssh().unwrap();
242
243        if let Some(expected_private_key) = expected_private_key {
244            assert_eq!(ssh_private_key_string.deref(), expected_private_key);
245        } else {
246            println!("{}", *ssh_private_key_string);
247        }
248
249        if let Some(expected_public_key) = expected_public_key {
250            assert_eq!(ssh_public_key_string.deref(), expected_public_key);
251        } else {
252            println!("{}", ssh_public_key_string);
253        }
254
255        const MESSAGE: &dyn AsRef<[u8]> = b"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
256        let options = SigningOptions::Ssh {
257            namespace: "test".to_string(),
258            hash_alg: HashAlg::Sha256,
259        };
260        let signature: Signature = private_key
261            .sign_with_options(MESSAGE, Some(options))
262            .unwrap();
263        assert!(public_key.verify(&signature, MESSAGE));
264    }
265
266    #[test]
267    fn test_ssh_dsa_signing() {
268        let expected_private_key = Some(indoc! {
269            r#"
270                    -----BEGIN OPENSSH PRIVATE KEY-----
271                    b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsgAAAAdzc2gtZH
272                    NzAAAAgQCWG4f7r8FAMT/IL11w9OfM/ZduIQ8vEq1Ub+uMdyJS8wS/jXL5OB2/dPnXCNSt
273                    L4vjSqpDzMs+Dtd5wJy6baSQ3zGEbYv71mkIRJB/AtSVmd8FZe5AEjLFvHxYMSlO0jpi1Y
274                    /1nLM7vLQu4QByDCLhYYjPxgrZKXB3cLxtjvly5wAAABUA4fIZLivnDVcg9PXzwcb5m07H
275                    9k0AAACBAJK5Vm6t1Sg7n+C63wrNgDA6LTNyGzxqRVM2unI16jisCOzuC98Dgs+IbAkLhT
276                    qWSY+nI+U9HBHc7sr+KKdWCzR76NLK5eSilXvtt8g+LfHIXvCjD4Q2puowtjDoXSEQAJYd
277                    c1gtef21KZ2eoKoyAwzQIehCbvLpwYbxnhap5usVAAAAgGCrsbfReaDZo1Cw4/dFlJWBDP
278                    sMGeG04/2hCThNmU+zLiKCwsEg0X6onOTMTonCXve3fVb5lNjIU92iTmt5QkmOj2hjsbgo
279                    q/0sa0lALHp7UcK/W4IdU4Abtc4m0SUflgJcds1nsy2rKUNEtAfRa/WwtDResWOa4T7L+3
280                    FEUdavAAAB6F0RJ3hdESd4AAAAB3NzaC1kc3MAAACBAJYbh/uvwUAxP8gvXXD058z9l24h
281                    Dy8SrVRv64x3IlLzBL+Ncvk4Hb90+dcI1K0vi+NKqkPMyz4O13nAnLptpJDfMYRti/vWaQ
282                    hEkH8C1JWZ3wVl7kASMsW8fFgxKU7SOmLVj/Wcszu8tC7hAHIMIuFhiM/GCtkpcHdwvG2O
283                    +XLnAAAAFQDh8hkuK+cNVyD09fPBxvmbTsf2TQAAAIEAkrlWbq3VKDuf4LrfCs2AMDotM3
284                    IbPGpFUza6cjXqOKwI7O4L3wOCz4hsCQuFOpZJj6cj5T0cEdzuyv4op1YLNHvo0srl5KKV
285                    e+23yD4t8che8KMPhDam6jC2MOhdIRAAlh1zWC15/bUpnZ6gqjIDDNAh6EJu8unBhvGeFq
286                    nm6xUAAACAYKuxt9F5oNmjULDj90WUlYEM+wwZ4bTj/aEJOE2ZT7MuIoLCwSDRfqic5MxO
287                    icJe97d9VvmU2MhT3aJOa3lCSY6PaGOxuCir/SxrSUAsentRwr9bgh1TgBu1zibRJR+WAl
288                    x2zWezLaspQ0S0B9Fr9bC0NF6xY5rhPsv7cURR1q8AAAAVANWljfuxQcmJ/T7wSmAUXmXo
289                    6ZI0AAAADEtleSBjb21tZW50LgECAwQF
290                    -----END OPENSSH PRIVATE KEY-----
291                "#
292        });
293        let expected_public_key = Some(
294            "ssh-dss AAAAB3NzaC1kc3MAAACBAJYbh/uvwUAxP8gvXXD058z9l24hDy8SrVRv64x3IlLzBL+Ncvk4Hb90+dcI1K0vi+NKqkPMyz4O13nAnLptpJDfMYRti/vWaQhEkH8C1JWZ3wVl7kASMsW8fFgxKU7SOmLVj/Wcszu8tC7hAHIMIuFhiM/GCtkpcHdwvG2O+XLnAAAAFQDh8hkuK+cNVyD09fPBxvmbTsf2TQAAAIEAkrlWbq3VKDuf4LrfCs2AMDotM3IbPGpFUza6cjXqOKwI7O4L3wOCz4hsCQuFOpZJj6cj5T0cEdzuyv4op1YLNHvo0srl5KKVe+23yD4t8che8KMPhDam6jC2MOhdIRAAlh1zWC15/bUpnZ6gqjIDDNAh6EJu8unBhvGeFqnm6xUAAACAYKuxt9F5oNmjULDj90WUlYEM+wwZ4bTj/aEJOE2ZT7MuIoLCwSDRfqic5MxOicJe97d9VvmU2MhT3aJOa3lCSY6PaGOxuCir/SxrSUAsentRwr9bgh1TgBu1zibRJR+WAlx2zWezLaspQ0S0B9Fr9bC0NF6xY5rhPsv7cURR1q8= Key comment."
295        );
296        test_ssh_signing(SSHAlgorithm::Dsa, expected_private_key, expected_public_key);
297    }
298
299    #[test]
300    #[ignore]
301    fn test_ssh_dsa_nistp256_signing() {
302        let expected_private_key = Some(indoc! {
303            r#"
304                    -----BEGIN OPENSSH PRIVATE KEY-----
305                    b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
306                    1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTtBE6+WTueAierXl/c/f83JAmoxm0k
307                    YlGMVMofLOUFeKx3FqUW0VRVljx1wHL03faFhiTPVR9CNG5iZCUqa4eLAAAAqPC+XgXwvl
308                    4FAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBO0ETr5ZO54CJ6te
309                    X9z9/zckCajGbSRiUYxUyh8s5QV4rHcWpRbRVFWWPHXAcvTd9oWGJM9VH0I0bmJkJSprh4
310                    sAAAAgAVk1Bq0ILFsF/ADaUq8G5Tow0Xv+Qs8V21gfOBSWQDEAAAAMS2V5IGNvbW1lbnQu
311                    AQIDBA==
312                    -----END OPENSSH PRIVATE KEY-----
313                "#
314        });
315        let expected_public_key = Some(
316            "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBO0ETr5ZO54CJ6teX9z9/zckCajGbSRiUYxUyh8s5QV4rHcWpRbRVFWWPHXAcvTd9oWGJM9VH0I0bmJkJSprh4s= Key comment."
317        );
318        test_ssh_signing(
319            SSHAlgorithm::Ecdsa { curve: EcdsaCurve::NistP256 },
320            expected_private_key,
321            expected_public_key,
322        );
323    }
324
325    #[test]
326    #[ignore]
327    fn test_ssh_dsa_nistp384_signing() {
328        let expected_private_key = Some(indoc! {
329            r#"
330                    -----BEGIN OPENSSH PRIVATE KEY-----
331                    b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS
332                    1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQSdYtV5QyUoBDDJX9gOG3DcJyv4qhjV
333                    L7ntdIlyOCVCdqMMWa2EUsyxV/PLrrDYGCDUruf83rRNdJwuZ+7oZWm0N6yfLOT4QPQNxv
334                    LqMJJ1hvw/xBxZVjMsr2gb/ohSG6IAAADYBFI75gRSO+YAAAATZWNkc2Etc2hhMi1uaXN0
335                    cDM4NAAAAAhuaXN0cDM4NAAAAGEEnWLVeUMlKAQwyV/YDhtw3Ccr+KoY1S+57XSJcjglQn
336                    ajDFmthFLMsVfzy66w2Bgg1K7n/N60TXScLmfu6GVptDesnyzk+ED0Dcby6jCSdYb8P8Qc
337                    WVYzLK9oG/6IUhuiAAAAMQCFOcU/ldvVE92+kXn2C/q5+wuGX3Q61YHG3LNn4655GZeL7a
338                    rH0jbCy0lsAQ5WbsMAAAAMS2V5IGNvbW1lbnQuAQID
339                    -----END OPENSSH PRIVATE KEY-----
340                "#
341        });
342        let expected_public_key = Some(
343            "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBJ1i1XlDJSgEMMlf2A4bcNwnK/iqGNUvue10iXI4JUJ2owxZrYRSzLFX88uusNgYINSu5/zetE10nC5n7uhlabQ3rJ8s5PhA9A3G8uowknWG/D/EHFlWMyyvaBv+iFIbog== Key comment."
344        );
345        test_ssh_signing(
346            SSHAlgorithm::Ecdsa { curve: EcdsaCurve::NistP384 },
347            expected_private_key,
348            expected_public_key,
349        );
350    }
351
352    // Should succeed but fails part of the time. See next test.
353    #[test]
354    #[ignore]
355    fn test_ssh_dsa_nistp521_signing() {
356        let expected_private_key = Some(indoc! {
357            r#"
358                    -----BEGIN OPENSSH PRIVATE KEY-----
359                    b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNlY2RzYS
360                    1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQBD3AAo2UN1WreSuQWtp4DTbfzQ+D2
361                    LyK9u5ykCfFXd/AMpQbyIyEQGbAiLNyAhGOfLgarJiAv4myKcHSGW2fTxQUB3V09IqubOw
362                    JdNLaCJbszLQQSqoZlIWrXD51X7FdQFtXYY4GKmVeMKuK+u9Iby6F41nSrYpHlaFzzxr+D
363                    5n1uq7cAAAEQrIPPE6yDzxMAAAATZWNkc2Etc2hhMi1uaXN0cDUyMQAAAAhuaXN0cDUyMQ
364                    AAAIUEAQ9wAKNlDdVq3krkFraeA02380Pg9i8ivbucpAnxV3fwDKUG8iMhEBmwIizcgIRj
365                    ny4GqyYgL+JsinB0hltn08UFAd1dPSKrmzsCXTS2giW7My0EEqqGZSFq1w+dV+xXUBbV2G
366                    OBiplXjCrivrvSG8uheNZ0q2KR5Whc88a/g+Z9bqu3AAAAQgGDA9XptdyVFY5Svw8XXSJ5
367                    7lrvc2R/T2CBthF0FgxqlNF5oTdqmrFuEqJ34oxIvhd9sJB/3qBpoJnPVKcuVmGC6gAAAA
368                    xLZXkgY29tbWVudC4BAgMEBQY=
369                    -----END OPENSSH PRIVATE KEY-----
370                "#
371        });
372        let expected_public_key = Some(
373            "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAEPcACjZQ3Vat5K5Ba2ngNNt/ND4PYvIr27nKQJ8Vd38AylBvIjIRAZsCIs3ICEY58uBqsmIC/ibIpwdIZbZ9PFBQHdXT0iq5s7Al00toIluzMtBBKqhmUhatcPnVfsV1AW1dhjgYqZV4wq4r670hvLoXjWdKtikeVoXPPGv4PmfW6rtw== Key comment."
374        );
375        test_ssh_signing(
376            SSHAlgorithm::Ecdsa { curve: EcdsaCurve::NistP521 },
377            expected_private_key,
378            expected_public_key,
379        );
380    }
381
382    // Filed as https://github.com/RustCrypto/SSH/issues/232
383    #[ignore]
384    #[test]
385    fn test_dsa_nistp521() {
386        let encoded_key = r#"
387-----BEGIN OPENSSH PRIVATE KEY-----
388b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNlY2RzYS
3891zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQBD3AAo2UN1WreSuQWtp4DTbfzQ+D2
390LyK9u5ykCfFXd/AMpQbyIyEQGbAiLNyAhGOfLgarJiAv4myKcHSGW2fTxQUB3V09IqubOw
391JdNLaCJbszLQQSqoZlIWrXD51X7FdQFtXYY4GKmVeMKuK+u9Iby6F41nSrYpHlaFzzxr+D
3925n1uq7cAAAEQrIPPE6yDzxMAAAATZWNkc2Etc2hhMi1uaXN0cDUyMQAAAAhuaXN0cDUyMQ
393AAAIUEAQ9wAKNlDdVq3krkFraeA02380Pg9i8ivbucpAnxV3fwDKUG8iMhEBmwIizcgIRj
394ny4GqyYgL+JsinB0hltn08UFAd1dPSKrmzsCXTS2giW7My0EEqqGZSFq1w+dV+xXUBbV2G
395OBiplXjCrivrvSG8uheNZ0q2KR5Whc88a/g+Z9bqu3AAAAQgGDA9XptdyVFY5Svw8XXSJ5
3967lrvc2R/T2CBthF0FgxqlNF5oTdqmrFuEqJ34oxIvhd9sJB/3qBpoJnPVKcuVmGC6gAAAA
397xLZXkgY29tbWVudC4BAgMEBQY=
398-----END OPENSSH PRIVATE KEY-----
399"#;
400        let private_key = SSHPrivateKey::from_openssh(encoded_key).unwrap();
401        const MESSAGE: &[u8] = b"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
402        const NAMESPACE: &str = "test";
403        let signature = private_key
404            .sign(NAMESPACE, HashAlg::Sha256, MESSAGE)
405            .unwrap();
406        let public_key = private_key.public_key();
407        public_key.verify(NAMESPACE, MESSAGE, &signature).unwrap();
408    }
409
410    #[test]
411    fn test_ssh_ed25519_signing() {
412        let expected_private_key = Some(indoc! {
413            r#"
414                    -----BEGIN OPENSSH PRIVATE KEY-----
415                    b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
416                    QyNTUxOQAAACBUe4FDGyGIgHf75yVdE4hYl9guj02FdsIadgLC04zObQAAAJA+TyZiPk8m
417                    YgAAAAtzc2gtZWQyNTUxOQAAACBUe4FDGyGIgHf75yVdE4hYl9guj02FdsIadgLC04zObQ
418                    AAAECsX3CKi3hm5VrrU26ffa2FB2YrFogg45ucOVbIz4FQo1R7gUMbIYiAd/vnJV0TiFiX
419                    2C6PTYV2whp2AsLTjM5tAAAADEtleSBjb21tZW50LgE=
420                    -----END OPENSSH PRIVATE KEY-----
421                "#
422        });
423        let expected_public_key = Some(
424            "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFR7gUMbIYiAd/vnJV0TiFiX2C6PTYV2whp2AsLTjM5t Key comment."
425        );
426        test_ssh_signing(
427            SSHAlgorithm::Ed25519,
428            expected_private_key,
429            expected_public_key,
430        );
431    }
432
433    #[test]
434    fn test_ecdsa_signing() {
435        let mut rng = make_fake_random_number_generator();
436        let private_key = ecdsa_new_private_key_using(&mut rng);
437        const MESSAGE: &[u8] = b"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
438
439        let ecdsa_public_key = ecdsa_public_key_from_private_key(&private_key);
440        let ecdsa_signature = ecdsa_sign(&private_key, MESSAGE);
441        assert_eq!(
442            ecdsa_signature,
443            hex!(
444                "e75702ed8f645ce7fe510507b2403029e461ef4570d12aa440e4f81385546a13740b7d16878ff0b46b1cbe08bc218ccb0b00937b61c4707de2ca6148508e51fb"
445            )
446        );
447        assert!(ecdsa_verify(&ecdsa_public_key, &ecdsa_signature, MESSAGE));
448
449        let schnorr_public_key = schnorr_public_key_from_private_key(&private_key);
450        let schnorr_signature = schnorr_sign_using(&private_key, MESSAGE, &mut rng);
451        assert_eq!(
452            schnorr_signature,
453            hex!(
454                "df3e33900f0b94e23b6f8685f620ed92705ebfcf885ccb321620acb9927bce1e2218dcfba7cb9c3bba11611446f38774a564f265917899194e82945c8b60a996"
455            )
456        );
457        assert!(schnorr_verify(
458            &schnorr_public_key,
459            &schnorr_signature,
460            MESSAGE
461        ));
462    }
463
464    #[test]
465    fn test_readme_deps() {
466        version_sync::assert_markdown_deps_updated!("README.md");
467    }
468
469    #[test]
470    fn test_html_root_url() {
471        version_sync::assert_html_root_url_updated!("src/lib.rs");
472    }
473}