bc_components/
lib.rs

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