Skip to main content

arcana/rsa/
pkcs1.rs

1//! PKCS#1 v1.5 padding for encryption and signatures (RFC 8017).
2//!
3//! Encryption padding: `0x00 || 0x02 || PS || 0x00 || M`
4//! Signature padding: `0x00 || 0x01 || PS || 0x00 || DigestInfo || H`
5//!
6//! # ⚠ Use OAEP / PSS for new deployments
7//!
8//! PKCS#1 v1.5 is the **legacy** padding scheme. New code should
9//! prefer:
10//! - [`super::oaep`] for encryption (RFC 8017 §7.1).
11//! - [`super::pss`] for signatures (RFC 8017 §8.1).
12//!
13//! v1.5 is preserved here because it is still the only padding
14//! supported by some embedded TLS stacks and HSMs. Where the
15//! choice exists, do not select it.
16//!
17//! # Side-channel posture — Bleichenbacher
18//!
19//! The PKCS#1 v1.5 **encryption** scheme is the historical
20//! Bleichenbacher target (CRYPTO 1998): a padding oracle on the
21//! `02` prefix recovers the plaintext in ~2²⁰ – 2²² queries. RFC
22//! 8017 §7.2.2 defines a constant-time decrypt that **always**
23//! returns the same number of bytes whether or not padding parses
24//! correctly, with the data being an internally-derived
25//! deterministic dummy in the failure path. Roadmap item `T2-J`
26//! tracks the audit + tightening of `pkcs1::decrypt` against this
27//! recipe.
28//!
29//! The PKCS#1 v1.5 **signature** scheme has no analogous oracle,
30//! but inherits the underlying [`super::rsa::rsa_decrypt_raw`]
31//! Bellcore exposure (roadmap item `T1-C`).
32
33use super::bigint::BigInt;
34use super::rsa::{RsaPublicKey, RsaSecretKey, rsa_decrypt_raw, rsa_encrypt_raw};
35use crate::Hasher;
36use crate::hash::ripemd160::Ripemd160;
37use crate::hash::sha1::Sha1;
38use crate::hash::sha3::{Sha3_256, Sha3_384, Sha3_512};
39use crate::hash::sha256::Sha256;
40use crate::hash::sha384::Sha384;
41use crate::hash::sha512::Sha512;
42
43/// Hash algorithm identifiers for PKCS#1 v1.5 signatures.
44///
45/// Each variant carries the DER-encoded `DigestInfo` prefix that
46/// gets prepended to the hash output `H` to form `T = prefix || H`.
47/// Per RFC 8017 §9.2 Note 1 the prefix encodes
48///
49/// ```text
50/// DigestInfo ::= SEQUENCE {
51///     digestAlgorithm  SEQUENCE { OID, NULL },
52///     digest           OCTET STRING
53/// }
54/// ```
55///
56/// SHA-3 prefixes use the OIDs assigned by NIST CSOR
57/// (`2.16.840.1.101.3.4.2.{8,9,10}`) which were standardised after
58/// RFC 8017 was published, but follow the same template as the
59/// SHA-2 prefixes.
60///
61/// **Note on RIPEMD-160**: included for backwards compatibility
62/// with legacy systems (Bitcoin signatures, some X.509 CAs from
63/// the 2000s). Not recommended for new designs.
64#[derive(Clone, Copy, Debug, PartialEq)]
65pub enum HashAlg {
66    /// SHA-1 (FIPS 180-4). 20-byte output. **Legacy / collision-broken**;
67    /// included only for compatibility with old certificates and HMAC-SHA-1.
68    Sha1,
69    /// SHA-256 (FIPS 180-4). 32-byte output.
70    Sha256,
71    /// SHA-384 (FIPS 180-4). 48-byte output.
72    Sha384,
73    /// SHA-512 (FIPS 180-4). 64-byte output.
74    Sha512,
75    /// SHA3-256 (FIPS 202). 32-byte output.
76    Sha3_256,
77    /// SHA3-384 (FIPS 202). 48-byte output.
78    Sha3_384,
79    /// SHA3-512 (FIPS 202). 64-byte output.
80    Sha3_512,
81    /// RIPEMD-160 (ISO/IEC 10118-3). 20-byte output. **Legacy**;
82    /// included for Bitcoin and 2000s European X.509 CAs.
83    Ripemd160,
84}
85
86impl HashAlg {
87    /// DER-encoded DigestInfo prefix for this hash algorithm
88    /// (RFC 8017 §9.2 Note 1, plus the SHA-3 family OIDs from
89    /// NIST CSOR `2.16.840.1.101.3.4.2.{8,9,10}`, and the
90    /// TeleTrusT OID `1.3.36.3.2.1` for RIPEMD-160).
91    fn digest_info_prefix(&self) -> &'static [u8] {
92        match self {
93            // SHA-1: OID 1.3.14.3.2.26 (5-byte OID)
94            // -> prefix 30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14
95            HashAlg::Sha1 => &[
96                0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14,
97            ],
98            // SHA-256: OID 2.16.840.1.101.3.4.2.1
99            HashAlg::Sha256 => &[
100                0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00,
101                0x04, 0x20,
102            ],
103            // SHA-384: OID 2.16.840.1.101.3.4.2.2
104            HashAlg::Sha384 => &[
105                0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00,
106                0x04, 0x30,
107            ],
108            // SHA-512: OID 2.16.840.1.101.3.4.2.3
109            HashAlg::Sha512 => &[
110                0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00,
111                0x04, 0x40,
112            ],
113            // SHA3-256: OID 2.16.840.1.101.3.4.2.8
114            HashAlg::Sha3_256 => &[
115                0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08, 0x05, 0x00,
116                0x04, 0x20,
117            ],
118            // SHA3-384: OID 2.16.840.1.101.3.4.2.9
119            HashAlg::Sha3_384 => &[
120                0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09, 0x05, 0x00,
121                0x04, 0x30,
122            ],
123            // SHA3-512: OID 2.16.840.1.101.3.4.2.10
124            HashAlg::Sha3_512 => &[
125                0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0a, 0x05, 0x00,
126                0x04, 0x40,
127            ],
128            // RIPEMD-160: OID 1.3.36.3.2.1 (5-byte OID, same shape as SHA-1)
129            // -> prefix 30 21 30 09 06 05 2b 24 03 02 01 05 00 04 14
130            HashAlg::Ripemd160 => &[
131                0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14,
132            ],
133        }
134    }
135
136    /// Output length of the hash in bytes.
137    fn hash_len(&self) -> usize {
138        match self {
139            HashAlg::Sha1 | HashAlg::Ripemd160 => 20,
140            HashAlg::Sha256 | HashAlg::Sha3_256 => 32,
141            HashAlg::Sha384 | HashAlg::Sha3_384 => 48,
142            HashAlg::Sha512 | HashAlg::Sha3_512 => 64,
143        }
144    }
145}
146
147/// PKCS#1 v1.5 encryption.
148///
149/// Pads `msg` and encrypts with `pk`. `rng` fills buffers with random bytes.
150/// Returns the ciphertext as a byte vector of length equal to the modulus.
151pub fn pkcs1v15_encrypt(pk: &RsaPublicKey, msg: &[u8], rng: &mut dyn FnMut(&mut [u8])) -> Vec<u8> {
152    let k = pk.modulus_byte_len();
153    assert!(
154        msg.len() <= k - 11,
155        "PKCS1v15 encrypt: message too long (max {} bytes, got {})",
156        k - 11,
157        msg.len()
158    );
159
160    // EM = 0x00 || 0x02 || PS || 0x00 || M
161    let ps_len = k - msg.len() - 3;
162    let mut em = vec![0u8; k];
163    em[0] = 0x00;
164    em[1] = 0x02;
165
166    // PS: random non-zero bytes.
167    rng(&mut em[2..2 + ps_len]);
168    for b in em[2..2 + ps_len].iter_mut() {
169        while *b == 0 {
170            let mut tmp = [0u8; 1];
171            rng(&mut tmp);
172            *b = tmp[0];
173        }
174    }
175
176    em[2 + ps_len] = 0x00;
177    em[3 + ps_len..].copy_from_slice(msg);
178
179    let m = BigInt::from_be_bytes(&em);
180    let c = rsa_encrypt_raw(pk, &m);
181    c.to_be_bytes(k)
182}
183
184/// PKCS#1 v1.5 decryption.
185///
186/// Decrypts `ct` with `sk` and removes padding.
187/// Returns `None` if padding is invalid.
188pub fn pkcs1v15_decrypt(sk: &RsaSecretKey, ct: &[u8]) -> Option<Vec<u8>> {
189    let k = sk.modulus_byte_len();
190    if ct.len() != k || k < 11 {
191        return None;
192    }
193
194    let c = BigInt::from_be_bytes(ct);
195    let m = rsa_decrypt_raw(sk, &c);
196    let em = m.to_be_bytes(k);
197
198    // Check format: 0x00 || 0x02 || PS || 0x00 || M
199    if em[0] != 0x00 || em[1] != 0x02 {
200        return None;
201    }
202
203    // Find the 0x00 separator after PS (PS must be at least 8 bytes).
204    let mut sep = None;
205    for i in 2..em.len() {
206        if em[i] == 0x00 {
207            if i < 10 {
208                // PS too short
209                return None;
210            }
211            sep = Some(i);
212            break;
213        }
214    }
215
216    let sep = sep?;
217    Some(em[sep + 1..].to_vec())
218}
219
220/// PKCS#1 v1.5 signature generation.
221///
222/// Signs the pre-computed `hash` (of `hash_alg` type) with `sk`.
223pub fn pkcs1v15_sign(sk: &RsaSecretKey, hash: &[u8], hash_alg: HashAlg) -> Vec<u8> {
224    let k = sk.modulus_byte_len();
225    let prefix = hash_alg.digest_info_prefix();
226    let t_len = prefix.len() + hash_alg.hash_len();
227
228    assert!(hash.len() == hash_alg.hash_len(), "Hash length mismatch");
229    assert!(k >= t_len + 11, "Modulus too short for PKCS1v15 signature");
230
231    // EM = 0x00 || 0x01 || PS || 0x00 || T
232    let ps_len = k - t_len - 3;
233    let mut em = vec![0u8; k];
234    em[0] = 0x00;
235    em[1] = 0x01;
236    for i in 0..ps_len {
237        em[2 + i] = 0xFF;
238    }
239    em[2 + ps_len] = 0x00;
240    em[3 + ps_len..3 + ps_len + prefix.len()].copy_from_slice(prefix);
241    em[3 + ps_len + prefix.len()..].copy_from_slice(hash);
242
243    let m = BigInt::from_be_bytes(&em);
244    let s = rsa_decrypt_raw(sk, &m); // signing = decryption with private key
245    s.to_be_bytes(k)
246}
247
248/// PKCS#1 v1.5 signature verification.
249///
250/// Verifies that `sig` is a valid signature of `hash` under `pk`.
251pub fn pkcs1v15_verify(pk: &RsaPublicKey, hash: &[u8], hash_alg: HashAlg, sig: &[u8]) -> bool {
252    let k = pk.modulus_byte_len();
253    if sig.len() != k {
254        return false;
255    }
256    if hash.len() != hash_alg.hash_len() {
257        return false;
258    }
259
260    let s = BigInt::from_be_bytes(sig);
261    let m = rsa_encrypt_raw(pk, &s); // verification = encryption with public key
262    let em = m.to_be_bytes(k);
263
264    // Reconstruct expected EM.
265    let prefix = hash_alg.digest_info_prefix();
266    let t_len = prefix.len() + hash_alg.hash_len();
267    if k < t_len + 11 {
268        return false;
269    }
270
271    let ps_len = k - t_len - 3;
272    let mut expected = vec![0u8; k];
273    expected[0] = 0x00;
274    expected[1] = 0x01;
275    for i in 0..ps_len {
276        expected[2 + i] = 0xFF;
277    }
278    expected[2 + ps_len] = 0x00;
279    expected[3 + ps_len..3 + ps_len + prefix.len()].copy_from_slice(prefix);
280    expected[3 + ps_len + prefix.len()..].copy_from_slice(hash);
281
282    // Constant-time comparison.
283    let mut diff = 0u8;
284    for (a, b) in em.iter().zip(expected.iter()) {
285        diff |= a ^ b;
286    }
287    diff == 0 && em.len() == expected.len()
288}
289
290// ============================================================================
291// Convenience helpers: hash a message with the chosen hash, then sign / verify.
292// ============================================================================
293//
294// One pair per supported (hash, HashAlg variant). The macro factors the
295// trivial 2-line body so adding a new hash in the future is a single line.
296// SHA-256 keeps its standalone definition (and not the macro) to preserve
297// the byte-for-byte stability of the public symbol that pre-existed this
298// commit -- this avoids any chance of accidentally changing its inlining
299// behaviour.
300
301/// Convenience: hash a message with SHA-256, then sign.
302pub fn pkcs1v15_sign_sha256(sk: &RsaSecretKey, message: &[u8]) -> Vec<u8> {
303    let hash = Sha256::hash(message);
304    pkcs1v15_sign(sk, &hash, HashAlg::Sha256)
305}
306
307/// Convenience: hash a message with SHA-256, then verify.
308pub fn pkcs1v15_verify_sha256(pk: &RsaPublicKey, message: &[u8], sig: &[u8]) -> bool {
309    let hash = Sha256::hash(message);
310    pkcs1v15_verify(pk, &hash, HashAlg::Sha256, sig)
311}
312
313macro_rules! convenience_pair {
314    ($sign_fn:ident, $verify_fn:ident, $hasher:ty, $alg:expr, $doc:literal) => {
315        #[doc = $doc]
316        pub fn $sign_fn(sk: &RsaSecretKey, message: &[u8]) -> Vec<u8> {
317            let hash = <$hasher as Hasher>::hash(message);
318            pkcs1v15_sign(sk, &hash, $alg)
319        }
320
321        #[doc = $doc]
322        pub fn $verify_fn(pk: &RsaPublicKey, message: &[u8], sig: &[u8]) -> bool {
323            let hash = <$hasher as Hasher>::hash(message);
324            pkcs1v15_verify(pk, &hash, $alg, sig)
325        }
326    };
327}
328
329convenience_pair!(
330    pkcs1v15_sign_sha1,
331    pkcs1v15_verify_sha1,
332    Sha1,
333    HashAlg::Sha1,
334    "Convenience: hash a message with SHA-1, then sign / verify. \
335     **Legacy**: do not use for new designs; SHA-1 is collision-broken."
336);
337
338convenience_pair!(
339    pkcs1v15_sign_sha384,
340    pkcs1v15_verify_sha384,
341    Sha384,
342    HashAlg::Sha384,
343    "Convenience: hash a message with SHA-384, then sign / verify."
344);
345
346convenience_pair!(
347    pkcs1v15_sign_sha512,
348    pkcs1v15_verify_sha512,
349    Sha512,
350    HashAlg::Sha512,
351    "Convenience: hash a message with SHA-512, then sign / verify."
352);
353
354convenience_pair!(
355    pkcs1v15_sign_sha3_256,
356    pkcs1v15_verify_sha3_256,
357    Sha3_256,
358    HashAlg::Sha3_256,
359    "Convenience: hash a message with SHA3-256, then sign / verify."
360);
361
362convenience_pair!(
363    pkcs1v15_sign_sha3_384,
364    pkcs1v15_verify_sha3_384,
365    Sha3_384,
366    HashAlg::Sha3_384,
367    "Convenience: hash a message with SHA3-384, then sign / verify."
368);
369
370convenience_pair!(
371    pkcs1v15_sign_sha3_512,
372    pkcs1v15_verify_sha3_512,
373    Sha3_512,
374    HashAlg::Sha3_512,
375    "Convenience: hash a message with SHA3-512, then sign / verify."
376);
377
378convenience_pair!(
379    pkcs1v15_sign_ripemd160,
380    pkcs1v15_verify_ripemd160,
381    Ripemd160,
382    HashAlg::Ripemd160,
383    "Convenience: hash a message with RIPEMD-160, then sign / verify. \
384     **Legacy**: included for compatibility with older systems \
385     (Bitcoin, some 2000s X.509 CAs); not recommended for new designs."
386);
387
388#[cfg(test)]
389mod tests {
390    use super::*;
391
392    fn test_rng() -> impl FnMut(&mut [u8]) {
393        let mut state: u64 = 0xdeadbeefcafebabe;
394        move |buf: &mut [u8]| {
395            for b in buf.iter_mut() {
396                state = state
397                    .wrapping_mul(6364136223846793005)
398                    .wrapping_add(1442695040888963407);
399                *b = (state >> 33) as u8;
400            }
401        }
402    }
403
404    #[test]
405    fn test_pkcs1v15_encrypt_decrypt_roundtrip() {
406        let mut rng = test_rng();
407        let (pk, sk) = super::super::rsa::rsa_keygen(512, &mut rng);
408        let msg = b"Hello, RSA!";
409        let ct = pkcs1v15_encrypt(&pk, msg, &mut rng);
410        let pt = pkcs1v15_decrypt(&sk, &ct).expect("decryption failed");
411        assert_eq!(&pt, msg);
412    }
413
414    #[test]
415    fn test_pkcs1v15_sign_verify_roundtrip() {
416        let mut rng = test_rng();
417        let (pk, sk) = super::super::rsa::rsa_keygen(512, &mut rng);
418        let message = b"Sign me!";
419        let sig = pkcs1v15_sign_sha256(&sk, message);
420        assert!(pkcs1v15_verify_sha256(&pk, message, &sig));
421        // Tamper with signature => should fail.
422        let mut bad_sig = sig.clone();
423        bad_sig[0] ^= 0xFF;
424        assert!(!pkcs1v15_verify_sha256(&pk, message, &bad_sig));
425    }
426
427    /// Round-trip every supported hash through the convenience helpers.
428    /// Uses a single 1024-bit key (regenerating per hash would multiply
429    /// the test runtime by 7 with no extra coverage).
430    ///
431    /// 1024 bits is the smallest modulus that fits all 7 EMSA-PKCS1-v1_5
432    /// padded values: SHA-512 / SHA3-512 need `t_len = 19 + 64 = 83`
433    /// bytes plus 11 bytes of mandatory padding overhead = 94 bytes
434    /// minimum, so a 768-bit (96-byte) modulus would just barely work
435    /// and 1024 bits (128 bytes) is the next standard size.
436    #[test]
437    fn pkcs1v15_all_supported_hashes_roundtrip() {
438        let mut rng = test_rng();
439        let (pk, sk) = super::super::rsa::rsa_keygen(1024, &mut rng);
440        let msg = b"hash flexibility test";
441
442        // SHA-1
443        let sig = pkcs1v15_sign_sha1(&sk, msg);
444        assert!(pkcs1v15_verify_sha1(&pk, msg, &sig));
445        // SHA-256 (already covered by the older test, but include here too)
446        let sig = pkcs1v15_sign_sha256(&sk, msg);
447        assert!(pkcs1v15_verify_sha256(&pk, msg, &sig));
448        // SHA-384
449        let sig = pkcs1v15_sign_sha384(&sk, msg);
450        assert!(pkcs1v15_verify_sha384(&pk, msg, &sig));
451        // SHA-512
452        let sig = pkcs1v15_sign_sha512(&sk, msg);
453        assert!(pkcs1v15_verify_sha512(&pk, msg, &sig));
454        // SHA3-256
455        let sig = pkcs1v15_sign_sha3_256(&sk, msg);
456        assert!(pkcs1v15_verify_sha3_256(&pk, msg, &sig));
457        // SHA3-384
458        let sig = pkcs1v15_sign_sha3_384(&sk, msg);
459        assert!(pkcs1v15_verify_sha3_384(&pk, msg, &sig));
460        // SHA3-512
461        let sig = pkcs1v15_sign_sha3_512(&sk, msg);
462        assert!(pkcs1v15_verify_sha3_512(&pk, msg, &sig));
463        // RIPEMD-160
464        let sig = pkcs1v15_sign_ripemd160(&sk, msg);
465        assert!(pkcs1v15_verify_ripemd160(&pk, msg, &sig));
466    }
467
468    /// Verify must reject when the **declared hash algorithm** does
469    /// not match what the signer used. This is the property that
470    /// makes the DigestInfo prefix actually meaningful: a SHA-256
471    /// signature must NOT verify as if it were a SHA-512 signature
472    /// even with the same RSA key and the same message bytes.
473    ///
474    /// Catches a class of attacks where a downgrade in the declared
475    /// hash would let an attacker substitute a precomputed-collision
476    /// payload under a weaker hash.
477    #[test]
478    fn pkcs1v15_hash_mismatch_rejected() {
479        let mut rng = test_rng();
480        let (pk, sk) = super::super::rsa::rsa_keygen(1024, &mut rng);
481        let msg = b"hash mismatch test";
482
483        // Sign with SHA-256, verify as SHA-256 -> OK.
484        let sig256 = pkcs1v15_sign_sha256(&sk, msg);
485        assert!(pkcs1v15_verify_sha256(&pk, msg, &sig256));
486
487        // Same signature, verify as SHA-512 -> must reject (different
488        // DigestInfo prefix, different hash length, completely
489        // different reconstructed EM).
490        assert!(!pkcs1v15_verify_sha512(&pk, msg, &sig256));
491
492        // Same signature, verify as SHA3-256 -> must reject (same
493        // hash length but different OID byte in the DigestInfo
494        // prefix, so the reconstructed EM differs by exactly one
495        // byte). This is the strictest possible mismatch test.
496        assert!(!pkcs1v15_verify_sha3_256(&pk, msg, &sig256));
497
498        // Sign with SHA-512, verify as SHA-256 -> must reject.
499        let sig512 = pkcs1v15_sign_sha512(&sk, msg);
500        assert!(pkcs1v15_verify_sha512(&pk, msg, &sig512));
501        assert!(!pkcs1v15_verify_sha256(&pk, msg, &sig512));
502
503        // Sign with SHA3-256, verify as SHA-256 -> must reject (the
504        // critical hash-family mixup case).
505        let sig3_256 = pkcs1v15_sign_sha3_256(&sk, msg);
506        assert!(pkcs1v15_verify_sha3_256(&pk, msg, &sig3_256));
507        assert!(!pkcs1v15_verify_sha256(&pk, msg, &sig3_256));
508    }
509
510    /// `HashAlg::hash_len()` must agree with the actual `OUTPUT_LEN`
511    /// of the underlying `Hasher` implementation. If they ever
512    /// drifted (e.g. someone changed SHA-3 truncation), the sign
513    /// path would assert-fail at runtime; this test catches that
514    /// at compile-then-run time.
515    #[test]
516    fn hashalg_lengths_agree_with_hasher_output_len() {
517        assert_eq!(HashAlg::Sha1.hash_len(), <Sha1 as Hasher>::OUTPUT_LEN);
518        assert_eq!(HashAlg::Sha256.hash_len(), <Sha256 as Hasher>::OUTPUT_LEN);
519        assert_eq!(HashAlg::Sha384.hash_len(), <Sha384 as Hasher>::OUTPUT_LEN);
520        assert_eq!(HashAlg::Sha512.hash_len(), <Sha512 as Hasher>::OUTPUT_LEN);
521        assert_eq!(HashAlg::Sha3_256.hash_len(), <Sha3_256 as Hasher>::OUTPUT_LEN);
522        assert_eq!(HashAlg::Sha3_384.hash_len(), <Sha3_384 as Hasher>::OUTPUT_LEN);
523        assert_eq!(HashAlg::Sha3_512.hash_len(), <Sha3_512 as Hasher>::OUTPUT_LEN);
524        assert_eq!(HashAlg::Ripemd160.hash_len(), <Ripemd160 as Hasher>::OUTPUT_LEN);
525    }
526}