From d82c76e4ccdccd0da359f623afe9cf1cbb63739d Mon Sep 17 00:00:00 2001 From: Mike Ounsworth Date: Sun, 7 Jun 2026 21:08:36 -0500 Subject: [PATCH 01/13] removed nightly feature from mldsa --- alpha_0.1.2_release_notes.md | 2 ++ crypto/core/src/lib.rs | 1 - crypto/mldsa/src/hash_mldsa.rs | 51 +++++++++++++++++++------------ crypto/mldsa/src/lib.rs | 11 +++---- crypto/rng/src/hash_drbg80090a.rs | 29 +++++++++++++++--- crypto/rng/src/lib.rs | 2 -- 6 files changed, 62 insertions(+), 34 deletions(-) diff --git a/alpha_0.1.2_release_notes.md b/alpha_0.1.2_release_notes.md index 06dcefa..5039c13 100644 --- a/alpha_0.1.2_release_notes.md +++ b/alpha_0.1.2_release_notes.md @@ -23,6 +23,8 @@ appropriate. * Probably it makes sense to leave Hex and Base64 as requiring std; ... or maybe add a no_std version that uses fixed-sized blocks? +* Make this build on the stable compiler. IE Remove the rust-toolchain.toml file that builds with nightly. Will require + some refactoring. * Create a cargo feature #[cfg(feature='rng')] and put it around things like keygen that takes an rng so that the build dependency on bouncycastle_rng is optional. * Enhance the default HashDRBG instantiation to take in NIST-compatible CPU jitter entropy? Or not? Maybe this is the diff --git a/crypto/core/src/lib.rs b/crypto/core/src/lib.rs index cb0d8d8..379e54c 100644 --- a/crypto/core/src/lib.rs +++ b/crypto/core/src/lib.rs @@ -3,7 +3,6 @@ // todo -- this is the goal, but first need to remove all the Vec in favour of compile-time array sizing. // #![no_std] -#![feature(adt_const_params)] #![forbid(unsafe_code)] pub mod errors; diff --git a/crypto/mldsa/src/hash_mldsa.rs b/crypto/mldsa/src/hash_mldsa.rs index 780bd76..15f1464 100644 --- a/crypto/mldsa/src/hash_mldsa.rs +++ b/crypto/mldsa/src/hash_mldsa.rs @@ -94,7 +94,7 @@ use bouncycastle_core::traits::{ Algorithm, Hash, PHSignature, RNG, SecurityStrength, Signature, XOF, }; use bouncycastle_rng::HashDRBG_SHA512; -use bouncycastle_sha2::{SHA256, SHA512}; +use bouncycastle_sha2::{SHA256, SHA256_NAME, SHA512, SHA512_NAME}; use core::marker::PhantomData; // Imports needed only for docs @@ -126,7 +126,6 @@ pub const HASH_ML_DSA_87_WITH_SHA512_NAME: &str = "HashML-DSA-87_with_SHA512"; pub type HashMLDSA44_with_SHA256 = HashMLDSA< SHA256, 32, - SHA256_OID, MLDSA44_PK_LEN, MLDSA44_SK_LEN, MLDSA44_SIG_LEN, @@ -160,7 +159,6 @@ impl Algorithm for HashMLDSA44_with_SHA256 { pub type HashMLDSA65_with_SHA256 = HashMLDSA< SHA256, 32, - SHA256_OID, MLDSA65_PK_LEN, MLDSA65_SK_LEN, MLDSA65_SIG_LEN, @@ -194,7 +192,6 @@ impl Algorithm for HashMLDSA65_with_SHA256 { pub type HashMLDSA87_with_SHA256 = HashMLDSA< SHA256, 32, - SHA256_OID, MLDSA87_PK_LEN, MLDSA87_SK_LEN, MLDSA87_SIG_LEN, @@ -228,7 +225,6 @@ impl Algorithm for HashMLDSA87_with_SHA256 { pub type HashMLDSA44_with_SHA512 = HashMLDSA< SHA512, 64, - SHA512_OID, MLDSA44_PK_LEN, MLDSA44_SK_LEN, MLDSA44_SIG_LEN, @@ -262,7 +258,6 @@ impl Algorithm for HashMLDSA44_with_SHA512 { pub type HashMLDSA65_with_SHA512 = HashMLDSA< SHA512, 64, - SHA512_OID, MLDSA65_PK_LEN, MLDSA65_SK_LEN, MLDSA65_SIG_LEN, @@ -296,7 +291,6 @@ impl Algorithm for HashMLDSA65_with_SHA512 { pub type HashMLDSA87_with_SHA512 = HashMLDSA< SHA512, 64, - SHA512_OID, MLDSA87_PK_LEN, MLDSA87_SK_LEN, MLDSA87_SIG_LEN, @@ -332,9 +326,8 @@ impl Algorithm for HashMLDSA87_with_SHA512 { /// by specifying the hash function to use (in the verifier), and specifying the bytes of the OID to /// to use as its domain separator in constructing the message representative M'. pub struct HashMLDSA< - HASH: Hash + Default, + HASH: Hash + Algorithm + Default, const HASH_LEN: usize, - const oid: &'static [u8], const PK_LEN: usize, const SK_LEN: usize, const SIG_LEN: usize, @@ -381,9 +374,8 @@ pub struct HashMLDSA< } impl< - HASH: Hash + Default, + HASH: Hash + Algorithm + Default, const PH_LEN: usize, - const oid: &'static [u8], const PK_LEN: usize, const SK_LEN: usize, const SIG_LEN: usize, @@ -410,7 +402,6 @@ impl< HashMLDSA< HASH, PH_LEN, - oid, PK_LEN, SK_LEN, SIG_LEN, @@ -568,7 +559,20 @@ impl< h.absorb(&[1u8]); h.absorb(&[ctx.len() as u8]); h.absorb(ctx); - h.absorb(oid); + + // this is all statics, so the branch should compile out. + // Really, this should be a generic param of HashMLDSA, but unsized_const_params is currently + // a nightly-only feature. + match HASH::ALG_NAME { + SHA256_NAME => h.absorb(SHA256_OID), + SHA512_NAME => h.absorb(SHA512_OID), + _ => { + return Err(SignatureError::GenericError( + "Unsupported hash algorithm; you need to add it to the switch", + )); + } + }; + h.absorb(ph); let mut mu = [0u8; MLDSA_MU_LEN]; let bytes_written = h.squeeze_out(&mut mu); @@ -691,7 +695,18 @@ impl< h.absorb(&[1u8]); h.absorb(&[ctx.len() as u8]); h.absorb(ctx); - h.absorb(oid); + // this is all statics, so the branch should compile out. + // Really, this should be a generic param of HashMLDSA, but unsized_const_params is currently + // a nightly-only feature. + match HASH::ALG_NAME { + SHA256_NAME => h.absorb(SHA256_OID), + SHA512_NAME => h.absorb(SHA512_OID), + _ => { + return Err(SignatureError::GenericError( + "Unsupported hash algorithm; you need to add it to the switch", + )); + } + }; h.absorb(ph); let mut mu = [0u8; MLDSA_MU_LEN]; _ = h.squeeze_out(&mut mu); @@ -765,12 +780,11 @@ impl< } impl< - HASH: Hash + Default, + HASH: Hash + Algorithm + Default, PK: MLDSAPublicKeyTrait + MLDSAPublicKeyInternalTrait, SK: MLDSAPrivateKeyTrait + MLDSAPrivateKeyInternalTrait, const PH_LEN: usize, - const oid: &'static [u8], const PK_LEN: usize, const SK_LEN: usize, const SIG_LEN: usize, @@ -794,7 +808,6 @@ impl< for HashMLDSA< HASH, PH_LEN, - oid, PK_LEN, SK_LEN, SIG_LEN, @@ -971,9 +984,8 @@ impl< } impl< - HASH: Hash + Default, + HASH: Hash + Algorithm + Default, const PH_LEN: usize, - const oid: &'static [u8], const PK_LEN: usize, const SK_LEN: usize, const SIG_LEN: usize, @@ -1000,7 +1012,6 @@ impl< for HashMLDSA< HASH, PH_LEN, - oid, PK_LEN, SK_LEN, SIG_LEN, diff --git a/crypto/mldsa/src/lib.rs b/crypto/mldsa/src/lib.rs index 06e37f9..9c3a2b8 100644 --- a/crypto/mldsa/src/lib.rs +++ b/crypto/mldsa/src/lib.rs @@ -115,9 +115,6 @@ #![no_std] #![forbid(missing_docs)] #![forbid(unsafe_code)] -#![allow(incomplete_features)] // needed because currently generic_const_exprs is experimental -#![feature(generic_const_exprs)] -#![feature(adt_const_params)] // These are because I'm matching variable names exactly against FIPS 204, for example both 'K' and 'k', // or 'A' and 'a' are used and have specific meanings. // But need to tell the rust linter to not care. @@ -127,8 +124,10 @@ // MLDSA implementation, but I don't want accessed from outside, such as FIPS-internal functions. #![allow(private_bounds)] #![allow(private_interfaces)] -// Used in HashMLDSA -#![feature(unsized_const_params)] +// Used in HashMLDSA for oid: &'static [u8] params. +// #![allow(incomplete_features)] // needed because currently unsized_const_params is experimental +// #![feature(adt_const_params)] +// #![feature(unsized_const_params)] // imports needed just for docs #[allow(unused_imports)] @@ -136,8 +135,6 @@ use bouncycastle_core::key_material::KeyMaterialTrait; #[allow(unused_imports)] use bouncycastle_core::traits::Signature; -// todo -- re-run mutants - // todo -- crucible tests mod aux_functions; diff --git a/crypto/rng/src/hash_drbg80090a.rs b/crypto/rng/src/hash_drbg80090a.rs index 4614692..2a06228 100644 --- a/crypto/rng/src/hash_drbg80090a.rs +++ b/crypto/rng/src/hash_drbg80090a.rs @@ -6,7 +6,7 @@ use crate::Sp80090ADrbg; use bouncycastle_core::errors::{KeyMaterialError, RNGError}; -use bouncycastle_core::key_material::{KeyMaterial512, KeyType, KeyMaterialTrait}; +use bouncycastle_core::key_material::{KeyMaterial512, KeyMaterialTrait, KeyType}; use bouncycastle_core::traits::{Hash, HashAlgParams, RNG, SecurityStrength}; use bouncycastle_sha2::{SHA256, SHA512}; use bouncycastle_utils::min; @@ -67,6 +67,7 @@ const LARGEST_HASHER_OUTPUT_LEN: usize = 64; #[allow(private_bounds)] /// Implementation of the Hash_DRBG algorithm as specified in NIST SP 800-90Ar1. pub struct HashDRBG80090A { + _phantom: core::marker::PhantomData, // Rust is stupid. What's the point of having a generic parameter if we can't use constants inside it? // state: WorkingState, state: WorkingState, @@ -123,6 +124,7 @@ impl HashDRBG80090A { /// and relies on you to provide a strong seed.** pub fn new_unititialized() -> Self { Self { + _phantom: core::marker::PhantomData, state: WorkingState:: { v: [0u8; LARGEST_HASHER_OUTPUT_LEN], c: [0u8; LARGEST_HASHER_OUTPUT_LEN], @@ -266,7 +268,11 @@ impl Sp80090ADrbg for HashDRBG80090A { Ok(()) } - fn reseed(&mut self, seed: &impl KeyMaterialTrait, additional_input: &[u8]) -> Result<(), RNGError> { + fn reseed( + &mut self, + seed: &impl KeyMaterialTrait, + additional_input: &[u8], + ) -> Result<(), RNGError> { // Hash_DRBG Reseed Process: // 1. seed_material = 0x01 || V || entropy_input || additional_input. // 2. seed = Hash_df (seed_material, seedlen). @@ -475,7 +481,10 @@ impl RNG for HashDRBG80090A { // todo!() // } - fn add_seed_keymaterial(&mut self, additional_seed: impl KeyMaterialTrait) -> Result<(), RNGError> { + fn add_seed_keymaterial( + &mut self, + additional_seed: impl KeyMaterialTrait, + ) -> Result<(), RNGError> { self.reseed(&additional_seed, "add_seed_keymaterial".as_bytes()) } @@ -572,7 +581,19 @@ fn test_hash_df() { assert_ne!(out, [0u8; 100]); // repeatability test // println!("out: {:?}", out); - assert_eq!(out, [150u8, 177u8, 87u8, 145u8, 138u8, 4u8, 164u8, 14u8, 162u8, 43u8, 159u8, 152u8, 121u8, 117u8, 6u8, 18u8, 253u8, 84u8, 41u8, 64u8, 40u8, 209u8, 16u8, 176u8, 106u8, 115u8, 172u8, 193u8, 246u8, 228u8, 208u8, 79u8, 37u8, 31u8, 134u8, 141u8, 200u8, 7u8, 42u8, 199u8, 229u8, 236u8, 236u8, 186u8, 28u8, 87u8, 200u8, 14u8, 127u8, 36u8, 132u8, 23u8, 36u8, 150u8, 23u8, 215u8, 247u8, 121u8, 175u8, 82u8, 99u8, 187u8, 235u8, 25u8, 213u8, 18u8, 106u8, 22u8, 4u8, 99u8, 1u8, 184u8, 211u8, 160u8, 177u8, 67u8, 78u8, 181u8, 69u8, 51u8, 117u8, 2u8, 72u8, 36u8, 134u8, 72u8, 2u8, 9u8, 105u8, 149u8, 136u8, 35u8, 81u8, 114u8, 142u8, 80u8, 94u8, 42u8, 85u8, 155]); + assert_eq!( + out, + [ + 150u8, 177u8, 87u8, 145u8, 138u8, 4u8, 164u8, 14u8, 162u8, 43u8, 159u8, 152u8, 121u8, + 117u8, 6u8, 18u8, 253u8, 84u8, 41u8, 64u8, 40u8, 209u8, 16u8, 176u8, 106u8, 115u8, + 172u8, 193u8, 246u8, 228u8, 208u8, 79u8, 37u8, 31u8, 134u8, 141u8, 200u8, 7u8, 42u8, + 199u8, 229u8, 236u8, 236u8, 186u8, 28u8, 87u8, 200u8, 14u8, 127u8, 36u8, 132u8, 23u8, + 36u8, 150u8, 23u8, 215u8, 247u8, 121u8, 175u8, 82u8, 99u8, 187u8, 235u8, 25u8, 213u8, + 18u8, 106u8, 22u8, 4u8, 99u8, 1u8, 184u8, 211u8, 160u8, 177u8, 67u8, 78u8, 181u8, 69u8, + 51u8, 117u8, 2u8, 72u8, 36u8, 134u8, 72u8, 2u8, 9u8, 105u8, 149u8, 136u8, 35u8, 81u8, + 114u8, 142u8, 80u8, 94u8, 42u8, 85u8, 155 + ] + ); // Test success with out.len() at the maximum allowed for SHA256 (255 * 32 = 8160) let mut out_max_sha256 = vec![0u8; 255 * 32]; diff --git a/crypto/rng/src/lib.rs b/crypto/rng/src/lib.rs index dbe62fb..43a65c1 100644 --- a/crypto/rng/src/lib.rs +++ b/crypto/rng/src/lib.rs @@ -28,8 +28,6 @@ //! cryptographic application. #![forbid(unsafe_code)] -#![allow(incomplete_features)] // Need this because generic_const_exprs is currently experimental. -#![feature(generic_const_exprs)] use crate::hash_drbg80090a::{ HashDRBG80090A, HashDRBG80090AParams_SHA256, HashDRBG80090AParams_SHA512, From 8022962999938b61ccd55dfe1246155d7a69ed42 Mon Sep 17 00:00:00 2001 From: Mike Ounsworth Date: Mon, 8 Jun 2026 12:45:41 -0500 Subject: [PATCH 02/13] Merging Quant-TheodoreFelix's improvement to ct::Condition. Closes #7 --- .../publish_doc_benches_to_ghpages.yaml | 37 +- CONTRIBUTING.md | 19 +- crypto/core/src/errors.rs | 1 + crypto/core/src/key_material.rs | 6 +- crypto/core/tests/key_material_tests.rs | 38 +- crypto/mldsa_lowmemory/src/lib.rs | 2 +- crypto/utils/src/ct.rs | 163 +- crypto/utils/tests/ct_tests.rs | 268 +-- mem_usage_benches/bench_mldsa_mem_usage.rs | 1793 ++++++++++++++++- src/bench_mldsa_mem_usage.rs | 469 +++++ 10 files changed, 2412 insertions(+), 384 deletions(-) create mode 100644 src/bench_mldsa_mem_usage.rs diff --git a/.github/workflows/publish_doc_benches_to_ghpages.yaml b/.github/workflows/publish_doc_benches_to_ghpages.yaml index 80e7d87..819803b 100644 --- a/.github/workflows/publish_doc_benches_to_ghpages.yaml +++ b/.github/workflows/publish_doc_benches_to_ghpages.yaml @@ -37,21 +37,22 @@ jobs: with: name: code_quality_stats path: ./code_stats.txt - run_benches: - runs-on: ubuntu-latest - if: github.ref == 'refs/heads/main' - steps: - - name: Checkout code - uses: actions/checkout@v4 - - run: cargo bench --all - - name: Save artifacts - uses: actions/upload-artifact@v4 - with: - name: bc-rust-benches - path: ./target/criterion + # the benches run crazy slow on the github agent. So there's really no point because it's not useful data. + # run_benches: + # runs-on: ubuntu-latest + # if: github.ref == 'refs/heads/main' + # steps: + # - name: Checkout code + # uses: actions/checkout@v4 + # - run: cargo bench --all + # - name: Save artifacts + # uses: actions/upload-artifact@v4 + # with: + # name: bc-rust-benches + # path: ./target/criterion collect_ghpages: if: github.ref == 'refs/heads/main' - needs: [build_docs, code_stats, run_benches] + needs: [build_docs, code_stats] runs-on: ubuntu-latest steps: - run: mkdir ./gh-pages @@ -65,11 +66,11 @@ jobs: with: name: code_quality_stats path: ./gh-pages/ - - name: Get benches from previous job - uses: actions/download-artifact@v4 - with: - name: bc-rust-benches - path: ./gh-pages/benches + # - name: Get benches from previous job + # uses: actions/download-artifact@v4 + # with: + # name: bc-rust-benches + # path: ./gh-pages/benches - name: Archive Compatibility Matrix For Download uses: actions/upload-pages-artifact@v3 with: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 104f2ff..d402afd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,6 +20,23 @@ before posting anything public. See [Security Policy](SECURITY.md). If a related discussion or issue doesn't exist, and the issue is not security related, you can [open a new issue](https://github.com/bcgit/bc-java/issues/new). An issue can be converted into a discussion if regarded as one. +## Coding philosophy + +> Slow is smooth, smooth is fast. + +There is a time and a place for "Move fast and break things", but the source code of a crypto library is not one of them. + +This project takes the philosophy that taking the time to do things right pays off in the long run, both in terms of +the runtime and memory footprint of the code, and it terms of the time required for a future maintainer to get up to speed with the code +and avoid introducing bugs due to the code being hard to understand. + +Some specifics: + +* Respect that the innovative process sometimes requires exploring several dead-ends before you find the most elegant solution. +* Public APIs of a library should be both ergonomic and expressive. When defining a new trait or public function, ask yourself whether a programmer who is new to cryptography is likely to use this in a way that will get them into trouble. +* Variables should be well-named, well-structured, and well-commented (a comment-to-code ration of 1:1 is a goal to be strived for!). Think about memory footprint and, where possible, use unnamed scopes to allow the compiler to pop intermediate value variables off the stack as soon as they are no longer needed. +* Always run your code through `cargo mutants` and get the issue count as low as your can. As a first pass, this forces you to write thorough unit tests. As a second pass, this draws your attention to bits of your code that cannot be tested from the outside. Often this means that the code can be simplified without affecting functionality (as defined by your set of unit tests) -- "simpler code" usually means faster runtime and easier future maintenance. + ## Contribute to the code For substantial, non-trivial contributions, you may be asked to sign a contributor assignment agreement. Optionally, you can also have your name and contact information listed in [Contributors](https://www.bouncycastle.org/contributors.html). @@ -56,5 +73,5 @@ Don't forget to self-review. Please follow these simple guidelines: #### Your pull request is merged -For acceptance, pull requests need to meet specific quality criteria, including tests for anything substantial. Someone on the Bouncy Castle core team will review the pull request when there is time, and let you know if something is missing or suggest improvements. If it is a useful and generic feature it will be integrated in Bouncy Castle to be available in a later release. +Someone on the Bouncy Castle core team will review the pull request when there is time, and let you know if something is missing or suggest improvements. If it is a useful and generic feature it will be integrated in Bouncy Castle to be available in a later release. diff --git a/crypto/core/src/errors.rs b/crypto/core/src/errors.rs index de80d9a..9b52bc6 100644 --- a/crypto/core/src/errors.rs +++ b/crypto/core/src/errors.rs @@ -145,3 +145,4 @@ impl From for SignatureError { impl From for SignatureError { fn from(e: RNGError) -> SignatureError { Self::RNGError(e) } } + diff --git a/crypto/core/src/key_material.rs b/crypto/core/src/key_material.rs index 56aae3f..df17c88 100644 --- a/crypto/core/src/key_material.rs +++ b/crypto/core/src/key_material.rs @@ -39,7 +39,7 @@ use crate::errors::KeyMaterialError; use crate::traits::{RNG, SecurityStrength, Secret}; -use bouncycastle_utils::{ct, max, min}; +use bouncycastle_utils::{ct, min}; use core::cmp::{Ordering, PartialOrd}; use core::fmt; @@ -569,8 +569,8 @@ impl KeyMaterialTrait for KeyMaterial { } self.buf[self.key_len..new_key_len].copy_from_slice(other.ref_to_bytes()); self.key_len += other.key_len(); - self.key_type = max(&self.key_type, &other.key_type()).clone(); - self.security_strength = max(&self.security_strength, &other.security_strength()).clone(); + self.key_type = min(&self.key_type, &other.key_type()).clone(); + self.security_strength = min(&self.security_strength, &other.security_strength()).clone(); Ok(self.key_len()) } diff --git a/crypto/core/tests/key_material_tests.rs b/crypto/core/tests/key_material_tests.rs index 4bb3083..41fca0b 100644 --- a/crypto/core/tests/key_material_tests.rs +++ b/crypto/core/tests/key_material_tests.rs @@ -620,8 +620,9 @@ mod test_key_material { assert_eq!(zeroized_key.key_len(), 8); zeroized_key.concatenate(&key2).unwrap(); assert_eq!(zeroized_key.key_len(), 24); - // should take max(Zeroized, BytesLowEntropy) - assert_eq!(zeroized_key.key_type(), KeyType::BytesLowEntropy); + // The result takes the lesser (min) of the two key types: min(Zeroized, BytesLowEntropy). + // Folding in zeroized (uninitialized) bytes taints the whole buffer as Zeroized. + assert_eq!(zeroized_key.key_type(), KeyType::Zeroized); assert_eq!(zeroized_key.security_strength(), SecurityStrength::None); // This should be symmetric, so test it in the other direction too. @@ -634,8 +635,8 @@ mod test_key_material { let mut key2 = KeyMaterial256::from_bytes(&[1u8; 16]).unwrap(); key2.concatenate(&zeroized_key).unwrap(); assert_eq!(key2.key_len(), 24); - // should take max(Zeroized, BytesLowEntropy) - assert_eq!(key2.key_type(), KeyType::BytesLowEntropy); + // The result takes the lesser (min) of the two key types: min(BytesLowEntropy, Zeroized). + assert_eq!(key2.key_type(), KeyType::Zeroized); assert_eq!(key2.security_strength(), SecurityStrength::None); // now try it with keys of different key types @@ -644,10 +645,11 @@ mod test_key_material { let full_entropy_key = KeyMaterial256::from_bytes_as_type(&[2u8; 16], KeyType::BytesFullEntropy).unwrap(); low_entropy_key.concatenate(&full_entropy_key).unwrap(); - // should take max(BytesLowEntropy, BytesFullEntropy) - assert_eq!(low_entropy_key.key_type(), KeyType::BytesFullEntropy); - // should take max(None, _128Bit) - assert_eq!(low_entropy_key.security_strength(), SecurityStrength::_128bit); + // Conservative model: concatenating a full-entropy key with a low-entropy key yields a + // low-entropy key. min(BytesLowEntropy, BytesFullEntropy) == BytesLowEntropy. + assert_eq!(low_entropy_key.key_type(), KeyType::BytesLowEntropy); + // min(None, _128bit) == None (and BytesLowEntropy keys must have strength None anyway). + assert_eq!(low_entropy_key.security_strength(), SecurityStrength::None); // and in the other direction too let low_entropy_key = @@ -655,22 +657,22 @@ mod test_key_material { let mut full_entropy_key = KeyMaterial256::from_bytes_as_type(&[2u8; 16], KeyType::BytesFullEntropy).unwrap(); full_entropy_key.concatenate(&low_entropy_key).unwrap(); - // should take max(BytesLowEntropy, BytesFullEntropy) - assert_eq!(full_entropy_key.key_type(), KeyType::BytesFullEntropy); - // should take max(None, _128Bit) - assert_eq!(full_entropy_key.security_strength(), SecurityStrength::_128bit); + // min(BytesFullEntropy, BytesLowEntropy) == BytesLowEntropy. + assert_eq!(full_entropy_key.key_type(), KeyType::BytesLowEntropy); + // min(_128bit, None) == None. + assert_eq!(full_entropy_key.security_strength(), SecurityStrength::None); // now with full entropy keys at different security levels - let mut low_entropy_key = + let mut full_entropy_key_112 = KeyMaterial512::from_bytes_as_type(&[1u8; 16], KeyType::BytesFullEntropy).unwrap(); // Now we're gonna explictly tag it at the 112bit security level -- does not require allow_hazardous_operations(). - low_entropy_key.set_security_strength(SecurityStrength::_112bit).unwrap(); + full_entropy_key_112.set_security_strength(SecurityStrength::_112bit).unwrap(); let full_entropy_key = KeyMaterial256::from_bytes_as_type(&[2u8; 32], KeyType::BytesFullEntropy).unwrap(); - low_entropy_key.concatenate(&full_entropy_key).unwrap(); - assert_eq!(low_entropy_key.key_type(), KeyType::BytesFullEntropy); - // should take max(_112Bit, _256Bit) - assert_eq!(low_entropy_key.security_strength(), SecurityStrength::_256bit); + full_entropy_key_112.concatenate(&full_entropy_key).unwrap(); + assert_eq!(full_entropy_key_112.key_type(), KeyType::BytesFullEntropy); + // The combined key keeps the lower of the two security strengths: min(_112bit, _256bit). + assert_eq!(full_entropy_key_112.security_strength(), SecurityStrength::_112bit); } #[test] diff --git a/crypto/mldsa_lowmemory/src/lib.rs b/crypto/mldsa_lowmemory/src/lib.rs index ccc5a33..4463d77 100644 --- a/crypto/mldsa_lowmemory/src/lib.rs +++ b/crypto/mldsa_lowmemory/src/lib.rs @@ -45,7 +45,7 @@ //! //! We also get a surprising amount of memory-savings by good coding hygiene: //! Using un-named scopes to tell the compiler when an intermediate variable is no longer needed and -//! con be popped off the stack. This sometimes requires re-ordering the steps of the algorithms given in +//! can be popped off the stack. This sometimes requires re-ordering the steps of the algorithms given in //! FIPS 204 so that variables can be created, used, and released in a self-contained block. //! Sometimes this is not possible and we have to make a choice between keeping the variable around //! or releasing it and re-deriving it later. diff --git a/crypto/utils/src/ct.rs b/crypto/utils/src/ct.rs index 24ca9bf..96b1950 100644 --- a/crypto/utils/src/ct.rs +++ b/crypto/utils/src/ct.rs @@ -38,7 +38,9 @@ impl Condition { // MikeO: TODO: there are a bunch of impls in here that seem to be generic and not related to i64, // MikeO: TODO: could those be moved to a generic impl for Condition ? - pub const TRUE: Self = Self(1); + /// TRUE is the bit vector of all 1's + pub const TRUE: Self = Self(-1); + /// FALSE is the bit vector of all 0's pub const FALSE: Self = Self(0); pub const fn from_bool() -> Self { @@ -111,13 +113,31 @@ impl Condition { *dst = self.select(src, *dst); } - // MikeO: TODO: I have no idea what this does, .negate(-1) seems to give -3 ?? Is that a bug? /// Conditionally negate the value. + /// + /// negate(-1) gives -3 + /// + /// `value` is `-1` (i.e., all bits are `1`, `...1111`) + /// + /// Condition `self.0` is 1 (`...0001`) (assuming `TRUE`) + /// + /// XOR operation was executed as `value ^ self.0` + /// + /// Then `...1111 XOR ...0001 = ...1110` (i.e., `-2`) + /// + /// Subtraction operation is `wrapping_sub(self.0)` + /// + /// Then `-2 - 1 = -3` + /// + /// As a result, `1`, which is the negation of `-1`, should be returned, but `-3` is output. + /// + /// Therefore, if the [Self::TRUE] constant value of the i64 [Condition] implementation is changed to `-1`, + /// the test also runs normally. pub const fn negate(self, value: i64) -> i64 { (value ^ self.0).wrapping_sub(self.0) } - const fn or_halves(value: i64) -> i64 { + pub const fn or_halves(value: i64) -> i64 { (value | (value >> 32)) & 0xFFFFFFFF } @@ -136,93 +156,36 @@ impl Condition { } } -// TODO: ... this doesn't ... work. We should get this working and then then do u8. +// TODO: We should do Condition. // TODO: then and change Hex and Base64 to use this. // TODO: (there's probably no noticeable performance difference u8 and u64 bit ops on a 64-bit machine, // TODO: but there would be on a 8, 16, or 32-bit machine.) -// impl Condition { -// pub const TRUE: Self = Self(1); -// pub const FALSE: Self = Self(0); -// -// pub const fn new() -> Self { -// Self((VALUE as u64).wrapping_neg()) -// } -// -// pub const fn from_bool(value: bool) -> Self { -// Self((value as u64).wrapping_neg()) -// } -// -// pub const fn is_bit_set(value: u64, bit: u64) -> Self { -// Self(((value >> bit) & 1).wrapping_neg()) -// } -// -// // MikeO: TODO ?? What does "negative" mean for an unsigned value? -// pub const fn is_negative(value: u64) -> Self { -// Self(((value as i64) >> 63) as u64) -// } -// -// pub const fn is_not_zero(value: u64) -> Self { -// Self::is_negative(Self::or_halves(value).wrapping_neg()) -// } -// -// pub const fn is_zero(value: u64) -> Self { -// Self::is_negative(Self::or_halves(value).wrapping_sub(1)) -// } -// -// // MikeO: TODO: I borrowed this formula from Botan, but rust complains about u64 subtraction overflow if x < y, so this works in C but won't work in rust. -// // MikeO: TODO: I played with u64.wrapping_sub(y) but that doesn't work either. -// pub const fn is_lt(x: u64, y: u64) -> Self { -// Self::is_zero(x ^ ((x ^ y) | (x.wrapping_sub(y)) ^ x)) -// } -// -// // Note: haven't found a clever way to make this const, since it either needs a (non-const) not (!) or a boolean OR is_zero. -// // pub fn is_lte(x: i64, y: i64) -> Self { !Self::is_gt(x, y) } -// -// // pub const fn is_gt(x: i64, y: i64) -> Self { Self::is_lt(y, x) } -// -// // Note: haven't found a clever way to make this const, since it either needs a (non-const) not (!) or a boolean OR is_zero. -// // pub fn is_gte(x: i64, y: i64) -> Self { !Self::is_lt(x, y) } -// -// pub fn is_in_list(value: u64, list: &[u64]) -> Self { -// // Research question: is this actually constant-time? -// // A clever compiler might turn this into a short-circuiting loop. -// // A quick google search shows that rust doesn't have the ability to annotate specific code blocks -// // as no-optimize; the only option is to insert direct assembly. -// -// let mut c = Self::FALSE; -// for i in 0..list.len() { -// let diff = value ^ list[i]; -// c |= Condition::::is_zero(diff); -// } -// -// c -// } -// -// pub fn mov(self, src: u64, dst: &mut u64) { -// *dst = self.select(src, *dst); -// } -// -// // MikeO: TODO: This needs a docstring because I have no idea what this does. -// pub const fn negate(self, value: u64) -> u64 { -// (value ^ self.0).wrapping_sub(self.0) -// } -// -// const fn or_halves(value: u64) -> u64 { -// (value & 0xFFFFFFFF) | (value >> 32) -// } -// -// pub const fn select(self, true_value: u64, false_value: u64) -> u64 { -// (true_value & self.0) | (false_value & !self.0) -// } -// -// pub const fn swap(self, lhs: u64, rhs: u64) -> (u64, u64) { -// (self.select(rhs, lhs), self.select(lhs, rhs)) -// } -// -// pub const fn to_bool_var(self) -> bool { -// self.0 != 0 -// } -// } +impl Condition { + /// TRUE is the bit vector of all 1's + pub const TRUE: Self = Self(u64::MAX); + /// FALSE is the bit vector of all 0's + pub const FALSE: Self = Self(0); + + // this is the core logic for constant-time mask generation for unsigned integers + // Unlike signed integers where we can rely on Two's Complement via negation `-(v as i64)`, + // for u64 we must use wrapping subtraction to achieve the all-ones bit pattern (u64::MAX) for true + pub const fn from_bool() -> Self { + // If VALUE is true (1) -> 0 - 1 = u64::MAX (All 1s) + // If VALUE is false (0) -> 0 - 0 = 0 (All 0s) + Self(0u64.wrapping_sub(VALUE as u64)) + } + + // the select function manually for u64 + // although a fully generic impl would be the ultimate long-term goal + pub fn select(self, a: u64, b: u64) -> u64 { + let mask = self.0; + (a & mask) | (b & !mask) + } + + pub fn is_true(&self) -> bool { + self.0 != 0 + } +} impl BitAnd for Condition where @@ -327,22 +290,22 @@ pub fn conditional_copy_bytes( a: &[u8; LEN], b: &[u8; LEN], out: &mut [u8; LEN], - take_a: bool) { - - // we want the behaviour of + take_a: bool, +) { + // we want the behaviour of // if take_a { 0xFF } else { 0x00 } // but without using any branches that could leak timing signals - let mask: u8 = (take_a as u8) | - (take_a as u8) <<1 | - (take_a as u8) <<2 | - (take_a as u8) <<3 | - (take_a as u8) <<4 | - (take_a as u8) <<5 | - (take_a as u8) <<6 | - (take_a as u8) <<7; - + let mask: u8 = (take_a as u8) + | (take_a as u8) << 1 + | (take_a as u8) << 2 + | (take_a as u8) << 3 + | (take_a as u8) << 4 + | (take_a as u8) << 5 + | (take_a as u8) << 6 + | (take_a as u8) << 7; + debug_assert_eq!(mask, if take_a { 0xFF } else { 0x00 }); - + for i in 0..LEN { out[i] = std::hint::black_box(a[i] & mask) | std::hint::black_box(b[i] & !mask); } diff --git a/crypto/utils/tests/ct_tests.rs b/crypto/utils/tests/ct_tests.rs index c9d2712..8e9be76 100644 --- a/crypto/utils/tests/ct_tests.rs +++ b/crypto/utils/tests/ct_tests.rs @@ -143,10 +143,7 @@ mod i64_tests { let c1 = Condition::::TRUE; assert_eq!(c1.negate(1), -1); assert_eq!(c1.negate(0), 0); - - // MikeO: TODO: I don't understand what this function does well enough to test it. - // MikeO: TODO: is this failing test a real bug? - // assert_eq!(c1.negate(-1), 1); + assert_eq!(c1.negate(-1), 1); let c2 = Condition::::FALSE; assert_eq!(c2.negate(1), 1); @@ -154,10 +151,35 @@ mod i64_tests { assert_eq!(c2.negate(-1), -1); } - // MikeO: TODO: I don't understand what this function does well enough to test it. #[test] fn test_or_halves() { - // todo + // 0 input -> 0 output + assert_eq!(Condition::::or_halves(0), 0); + + // Lower 32 bits should be preserved + assert_eq!(Condition::::or_halves(1), 1); + assert_eq!(Condition::::or_halves(0x12345678), 0x12345678); + + // Upper 32 bits should be folded into lower 32 bits + // (1 << 32) OR (1 << 32 >> 32) => 0 OR 1 => 1 + assert_eq!(Condition::::or_halves(1 << 32), 1); + + // Mixed case: Upper 0x10000000 | Lower 0x00000001 => 0x10000001 + assert_eq!(Condition::::or_halves(0x10000000_00000001), 0x10000001); + + // Negative number check (-1) + // -1 is 0xFFFF...FFFF + // (-1 >> 32) is -1 (Arithmetic shift preserves sign) + // (-1 | -1) is -1 + // -1 & 0xFFFFFFFF is 0x00000000FFFFFFFF (i64 value: 4294967295) + assert_eq!(Condition::::or_halves(-1), 0xFFFFFFFF); + + // i64::MIN check (Only MSB set) + // i64::MIN = 0x80000000_00000000 + // (val >> 32) = 0xFFFFFFFF_80000000 (Sign extension) + // (val | shifted) = 0xFFFFFFFF_80000000 + // (& mask) = 0x00000000_80000000 + assert_eq!(Condition::::or_halves(i64::MIN), 0x80000000); } #[test] @@ -187,179 +209,67 @@ mod i64_tests { } } -// #[cfg(test)] -// mod u64_tests { -// use super::*; -// -// #[test] -// fn const_tests() { -// assert_eq!(Condition::::TRUE.to_bool_var(), true); -// assert_eq!(Condition::::FALSE.to_bool_var(), false); -// } -// -// #[test] -// fn from_bool() { -// assert_eq!(Condition::::new::().to_bool_var(), true); -// assert_eq!(Condition::::new::().to_bool_var(), false); -// -// let btrue: bool = true; -// let bfalse: bool = false; -// assert_eq!(Condition::::from_bool(btrue).to_bool_var(), true); -// assert_eq!(Condition::::from_bool(bfalse).to_bool_var(), false); -// } -// -// #[test] -// fn is_bit_set() { -// assert_eq!(Condition::::is_bit_set(1, 0).to_bool_var(), true); -// assert_eq!(Condition::::is_bit_set(1, 1).to_bool_var(), false); -// assert_eq!(Condition::::is_bit_set(8, 3).to_bool_var(), true); -// } -// -// // MikeO: TODO ?? What does "negative" mean for an unsigned value? -// #[test] -// fn is_negative() { -// // assert_eq!(Condition::::is_negative(-1).to_bool_var(), true); // << This doesn't compile, for obvious reasons. -// assert_eq!(Condition::::is_negative(0).to_bool_var(), false); -// assert_eq!(Condition::::is_negative(1).to_bool_var(), false); -// assert_eq!(Condition::::is_negative(1 << 12).to_bool_var(), false); -// } -// -// #[test] -// fn is_not_zero() { -// assert_eq!(Condition::::is_not_zero(1).to_bool_var(), true); -// assert_eq!(Condition::::is_not_zero(0).to_bool_var(), false); -// assert_eq!(Condition::::is_not_zero(1 << 12).to_bool_var(), true); -// } -// -// #[test] -// fn is_zero() { -// assert_eq!(Condition::::is_zero(1).to_bool_var(), false); -// assert_eq!(Condition::::is_zero(0).to_bool_var(), true); -// assert_eq!(Condition::::is_zero(1 << 12).to_bool_var(), false); -// } -// -// // TODO: turn this back on once implemented -// #[test] -// fn is_lt() { -// assert_eq!(Condition::::is_lt(1, 2).to_bool_var(), true); -// assert_eq!(Condition::::is_lt(2, 1).to_bool_var(), false); -// assert_eq!(Condition::::is_lt(2, 2).to_bool_var(), false); -// assert_eq!(Condition::::is_lt(0, 1).to_bool_var(), true); -// -// let mut i: u64 = 0; -// assert_eq!(Condition::::is_lt(i, 1).to_bool_var(), true); -// i = 1; -// assert_eq!(Condition::::is_lt(i, 1).to_bool_var(), false); -// } -// -// // TODO: turn this back on once implemented -// // #[test] -// // fn is_lte() { -// // assert_eq!(Condition::::is_lte(1, 2).to_bool_var(), true); -// // assert_eq!(Condition::::is_lte(2, 1).to_bool_var(), false); -// // assert_eq!(Condition::::is_lte(2, 2).to_bool_var(), true); -// // assert_eq!(Condition::::is_lte(0, 1).to_bool_var(), true); -// // assert_eq!(Condition::::is_lte(-100, -99).to_bool_var(), true); -// // assert_eq!(Condition::::is_lte(-98, 98).to_bool_var(), true); -// // } -// -// // #[test] -// // fn is_gt() { -// // assert_eq!(Condition::::is_gt(1, 2).to_bool_var(), false); -// // assert_eq!(Condition::::is_gt(2, 1).to_bool_var(), true); -// // assert_eq!(Condition::::is_gt(2, 2).to_bool_var(), false); -// // assert_eq!(Condition::::is_gt(0, 1).to_bool_var(), false); -// // assert_eq!(Condition::::is_gt(-100, -99).to_bool_var(), false); -// // assert_eq!(Condition::::is_gt(-98, 98).to_bool_var(), false); -// // } -// -// // #[test] -// // fn is_gte() { -// // assert_eq!(Condition::::is_gte(1, 2).to_bool_var(), false); -// // assert_eq!(Condition::::is_gte(2, 1).to_bool_var(), true); -// // assert_eq!(Condition::::is_gte(2, 2).to_bool_var(), true); -// // assert_eq!(Condition::::is_gte(0, 1).to_bool_var(), false); -// // assert_eq!(Condition::::is_gte(-100, -99).to_bool_var(), false); -// // assert_eq!(Condition::::is_gte(-98, 98).to_bool_var(), false); -// // } -// -// // TODO: turn this back on once implemented -// // #[test] -// // fn is_in_range() { -// // assert_eq!(Condition::::is_within_range(1, 0, 2).to_bool_var(), true); -// // assert_eq!(Condition::::is_within_range(2, 0, 1).to_bool_var(), false); -// // assert_eq!(Condition::::is_within_range(1, -5, 2).to_bool_var(), true); -// // assert_eq!(Condition::::is_within_range(0, -5, 5).to_bool_var(), true); -// // assert_eq!(Condition::::is_within_range(1, 0, 0).to_bool_var(), false); -// // } -// -// #[test] -// fn is_in_list() { -// assert_eq!(Condition::::is_in_list(1, &[1, 2, 3]).to_bool_var(), true); -// assert_eq!(Condition::::is_in_list(4, &[1, 2, 3]).to_bool_var(), false); -// assert_eq!(Condition::::is_in_list(3, &[1, 2, 3, 3, 3, 3]).to_bool_var(), true); -// } -// -// #[test] -// fn test_mov() { -// let src = 1u64; -// let mut dst = 2u64; -// let c1 = Condition::::TRUE; -// c1.mov(src, &mut dst); -// assert_eq!(dst, 1); -// -// let c2 = Condition::::FALSE; -// dst = 2; -// c2.mov(src, &mut dst); -// assert_eq!(dst, 2); -// } -// -// // MikeO: TODO: I don't understand what this function does well enough to test it. -// // #[test] -// // fn test_negate() { -// // let c1 = Condition::::TRUE; -// // assert_eq!(c1.negate(1), -1); -// // assert_eq!(c1.negate(0), 0); -// // assert_eq!(c1.negate(-1), 1); -// // -// // let c2 = Condition::::FALSE; -// // assert_eq!(c2.negate(1), 1); -// // assert_eq!(c2.negate(0), 0); -// // assert_eq!(c2.negate(-1),-1); -// // } -// -// // MikeO: TODO: I don't understand what this function does well enough to test it. -// #[test] -// fn test_or_halves() { -// todo!() -// } -// -// #[test] -// fn test_select() { -// let c = Condition::::TRUE; -// assert_eq!(c.select(1, 2), 1); -// assert_eq!((!c).select(1, 2), 2); -// -// // or the inverse behaviour if you start with 'false'. -// let cfalse = Condition::::FALSE; -// assert_eq!(cfalse.select(1, 2), 2); -// assert_eq!((!cfalse).select(1, 2), 1); -// } -// -// #[test] -// fn test_swap() { -// let c = Condition::::from_bool::(); -// let (lhs, rhs) = c.swap(1, 2); -// assert_eq!(lhs, 2); -// assert_eq!(rhs, 1); -// -// // or the inverse behaviour if you start with 'false'. -// let c = Condition::::from_bool::(); -// let (lhs, rhs) = c.swap(1, 2); -// assert_eq!(lhs, 1); -// assert_eq!(rhs, 2); -// } -// } +#[cfg(test)] +mod u64_tests { + use super::*; + + #[test] + fn const_tests() { + // Ensure TRUE/FALSE are correctly interpreted as boolean. + assert_eq!(Condition::::TRUE.is_true(), true); + assert_eq!(Condition::::FALSE.is_true(), false); + } + + #[test] + fn from_bool() { + // Compile-time const generics check + assert_eq!(Condition::::from_bool::().is_true(), true); + assert_eq!(Condition::::from_bool::().is_true(), false); + } + + #[test] + fn select() { + let t = Condition::::TRUE; + let f = Condition::::FALSE; + + let val1: u64 = 0xDEADBEEFCAFEBABE; + let val2: u64 = 0x0000000000000000; + + // This test is CRITICAL. + // If TRUE was defined as '1' (like i64), this would fail because 'select' relies on bitwise mask. + // It requires TRUE to be u64::MAX (all 1s) to preserve the full bits of val1. + assert_eq!(t.select(val1, val2), val1); + assert_eq!(f.select(val1, val2), val2); + + // Cross check with from_bool + let t_gen = Condition::::from_bool::(); + assert_eq!(t_gen.select(val1, val2), val1); + } + + #[test] + fn bit_ops() { + let t = Condition::::TRUE; + let f = Condition::::FALSE; + + // NOT + assert_eq!((!t).is_true(), false); + assert_eq!((!f).is_true(), true); + + // AND + assert_eq!((t & t).is_true(), true); + assert_eq!((t & f).is_true(), false); + assert_eq!((f & f).is_true(), false); + + // OR + assert_eq!((t | t).is_true(), true); + assert_eq!((t | f).is_true(), true); + assert_eq!((f | f).is_true(), false); + + // XOR + assert_eq!((t ^ t).is_true(), false); + assert_eq!((t ^ f).is_true(), true); + } +} #[cfg(test)] mod generic_impl_tests { diff --git a/mem_usage_benches/bench_mldsa_mem_usage.rs b/mem_usage_benches/bench_mldsa_mem_usage.rs index 6b648fe..6dc8351 100644 --- a/mem_usage_benches/bench_mldsa_mem_usage.rs +++ b/mem_usage_benches/bench_mldsa_mem_usage.rs @@ -22,49 +22,82 @@ use bouncycastle::core::key_material::{KeyMaterial256, KeyType}; use bouncycastle::core::traits::{Signature, SignaturePrivateKey, SignaturePublicKey}; -use bouncycastle::hex as hex; +use bouncycastle::hex; use bouncycastle::mldsa::MLDSA44_SIG_LEN; /// This prints the in-memory size of all the public and private key structs fn print_struct_sizes() { - use core::mem::size_of; use bouncycastle::mldsa; use bouncycastle::mldsa_lowmemory; - + use core::mem::size_of; println!("\nML-DSA-44"); println!("size_of: {}", size_of::()); - println!("size_of: {}", size_of::()); + println!( + "size_of: {}", + size_of::() + ); println!("size_of: {}", size_of::()); - println!("size_of: {}", size_of::()); - + println!( + "size_of: {}", + size_of::() + ); println!("\nML-DSA-65"); println!("size_of: {}", size_of::()); - println!("size_of: {}", size_of::()); + println!( + "size_of: {}", + size_of::() + ); println!("size_of: {}", size_of::()); - println!("size_of: {}", size_of::()); + println!( + "size_of: {}", + size_of::() + ); println!("\nML-DSA-87"); println!("size_of: {}", size_of::()); - println!("size_of: {}", size_of::()); + println!( + "size_of: {}", + size_of::() + ); println!("size_of: {}", size_of::()); - println!("size_of: {}", size_of::()); + println!( + "size_of: {}", + size_of::() + ); println!("\n\nlowmemory"); println!("\nML-KEM-512_lowmemory"); - println!("size_of: {}", size_of::()); - println!("size_of: {}", size_of::()); - + println!( + "size_of: {}", + size_of::() + ); + println!( + "size_of: {}", + size_of::() + ); println!("\nML-KEM-768_lowmemory"); - println!("size_of: {}", size_of::()); - println!("size_of: {}", size_of::()); + println!( + "size_of: {}", + size_of::() + ); + println!( + "size_of: {}", + size_of::() + ); println!("\nML-KEM-1024_lowmemory"); - println!("size_of: {}", size_of::()); - println!("size_of: {}", size_of::()); + println!( + "size_of: {}", + size_of::() + ); + println!( + "size_of: {}", + size_of::() + ); } /// This exists so I can use /usr/bin/time to measure the base memory footprint of the cargo bench harness @@ -75,91 +108,121 @@ fn bench_do_nothing() { } fn bench_mldsa44_keygen() { - use bouncycastle::mldsa::{MLDSATrait, MLDSA44}; + use bouncycastle::mldsa::{MLDSA44, MLDSATrait}; eprintln!("MLDSA44/KeyGen"); let seed = KeyMaterial256::from_bytes_as_type( - &[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f], + &[ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F, + ], KeyType::Seed, - ).unwrap(); + ) + .unwrap(); let (pk, _sk) = MLDSA44::keygen_from_seed(&seed).unwrap(); println!("{:x?}", pk.encode()); } fn bench_mldsa44_lowmem_keygen() { - use bouncycastle::mldsa_lowmemory::{MLDSATrait, MLDSA44}; + use bouncycastle::mldsa_lowmemory::{MLDSA44, MLDSATrait}; eprintln!("MLDSA44_lowmemory/KeyGen"); let seed = KeyMaterial256::from_bytes_as_type( - &[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f], + &[ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F, + ], KeyType::Seed, - ).unwrap(); + ) + .unwrap(); let (pk, _sk) = MLDSA44::keygen_from_seed(&seed).unwrap(); println!("{:x?}", pk.encode()); } fn bench_mldsa65_keygen() { - use bouncycastle::mldsa::{MLDSATrait, MLDSA65}; + use bouncycastle::mldsa::{MLDSA65, MLDSATrait}; eprintln!("MLDSA65/KeyGen"); let seed = KeyMaterial256::from_bytes_as_type( - &[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f], + &[ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F, + ], KeyType::Seed, - ).unwrap(); + ) + .unwrap(); let (pk, _sk) = MLDSA65::keygen_from_seed(&seed).unwrap(); println!("{:x?}", pk.encode()); } fn bench_mldsa65_lowmemory_keygen() { - use bouncycastle::mldsa_lowmemory::{MLDSATrait, MLDSA65}; + use bouncycastle::mldsa_lowmemory::{MLDSA65, MLDSATrait}; eprintln!("MLDSA65_lowmemory/KeyGen"); let seed = KeyMaterial256::from_bytes_as_type( - &[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f], + &[ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F, + ], KeyType::Seed, - ).unwrap(); + ) + .unwrap(); let (pk, _sk) = MLDSA65::keygen_from_seed(&seed).unwrap(); println!("{:x?}", pk.encode()); } fn bench_mldsa87_keygen() { - use bouncycastle::mldsa::{MLDSATrait, MLDSA87}; + use bouncycastle::mldsa::{MLDSA87, MLDSATrait}; eprintln!("MLDSA87/KeyGen"); let seed = KeyMaterial256::from_bytes_as_type( - &[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f], + &[ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F, + ], KeyType::Seed, - ).unwrap(); + ) + .unwrap(); let (pk, _sk) = MLDSA87::keygen_from_seed(&seed).unwrap(); println!("{:x?}", pk.encode()); } fn bench_mldsa87_lowmemory_keygen() { - use bouncycastle::mldsa_lowmemory::{MLDSATrait, MLDSA87}; + use bouncycastle::mldsa_lowmemory::{MLDSA87, MLDSATrait}; eprintln!("MLDSA87_lowmemory/KeyGen"); let seed = KeyMaterial256::from_bytes_as_type( - &[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f], + &[ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, + 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F, + ], KeyType::Seed, - ).unwrap(); + ) + .unwrap(); let (pk, _sk) = MLDSA87::keygen_from_seed(&seed).unwrap(); println!("{:x?}", pk.encode()); } fn bench_mldsa44_sign() { - use bouncycastle::mldsa::{MLDSATrait, MLDSA44, MLDSA44PrivateKey, MLDSA44_SK_LEN}; + use bouncycastle::mldsa::{MLDSA44, MLDSA44_SK_LEN, MLDSA44PrivateKey, MLDSATrait}; eprintln!("MLDSA44/Sign"); @@ -172,7 +235,180 @@ fn bench_mldsa44_sign() { // use bouncycastle_hex as hex; // eprintln!("sk:\n{}", &hex::encode(sk.encode())); - let sk = MLDSA44PrivateKey::from_bytes(&[0xd7,0xb2,0xb4,0x72,0x54,0xaa,0xe0,0xdb,0x45,0xe7,0x93,0x0d,0x4a,0x98,0xd2,0xc9,0x7d,0x8f,0x13,0x97,0xd1,0x78,0x9d,0xaf,0xa1,0x70,0x24,0xb3,0x16,0xe9,0xbe,0xc9,0x39,0xce,0x0f,0x7f,0x77,0xf8,0xdb,0x56,0x44,0xdc,0xda,0x36,0x6b,0xfe,0x47,0x34,0xbd,0x95,0xf4,0x35,0xff,0x9a,0x61,0x3a,0xa5,0x4a,0xa4,0x1c,0x2c,0x69,0x4c,0x04,0x32,0x9a,0x07,0xb1,0xfa,0xbb,0x48,0xf5,0x2a,0x30,0x9f,0x11,0xa1,0x89,0x8f,0x84,0x8e,0x23,0x22,0xff,0xe6,0x23,0xec,0x81,0x0d,0xb3,0xbe,0xe3,0x36,0x85,0x85,0x4a,0x88,0x26,0x9d,0xa3,0x20,0xd5,0x12,0x0b,0xfc,0xfe,0x89,0xa1,0x8e,0x30,0xf7,0x11,0x4d,0x83,0xaa,0x40,0x4a,0x64,0x6b,0x6c,0x99,0x73,0x89,0x86,0x0d,0x12,0x52,0x2e,0xe0,0x00,0x6e,0x23,0x84,0x81,0x91,0x86,0x61,0x9b,0x26,0x0d,0x11,0x86,0x64,0xd4,0xa6,0x28,0x22,0x18,0x44,0x82,0x40,0x28,0x98,0x14,0x61,0x48,0xa6,0x61,0x4c,0x42,0x48,0xa1,0x92,0x08,0xc2,0x38,0x29,0x51,0x24,0x48,0x08,0xa1,0x25,0xc2,0x08,0x31,0x08,0xc4,0x71,0x20,0x14,0x09,0x14,0x83,0x6c,0x18,0xa7,0x80,0x84,0x10,0x6e,0xc9,0xc0,0x70,0x22,0xb5,0x64,0x08,0xb0,0x61,0x0c,0x07,0x04,0x98,0x12,0x44,0x51,0x88,0x69,0x59,0x00,0x46,0x22,0x93,0x20,0x41,0x06,0x2e,0x42,0xb6,0x4c,0x01,0x16,0x49,0x14,0x28,0x4c,0x41,0xa8,0x51,0x80,0x46,0x0a,0x51,0x16,0x51,0x5a,0x08,0x20,0x02,0x22,0x44,0xdc,0x98,0x49,0xd1,0x32,0x51,0xe1,0x30,0x65,0xd3,0xc0,0x85,0x92,0xa8,0x51,0x12,0xa1,0x64,0x00,0x39,0x22,0x09,0x46,0x62,0x1c,0xc7,0x0c,0xd9,0x08,0x6d,0xd0,0x06,0x26,0x52,0x40,0x85,0x80,0x44,0x30,0x91,0x06,0x2c,0x50,0xc8,0x09,0x24,0xc5,0x84,0x1a,0x96,0x6d,0x4a,0x98,0x2c,0x99,0x06,0x6d,0xa4,0x44,0x32,0x20,0xa7,0x64,0x5a,0x32,0x6e,0x11,0xb5,0x70,0x20,0x92,0x61,0x24,0x13,0x8e,0x04,0x85,0x2c,0x0a,0x48,0x72,0xc8,0xa0,0x51,0xd3,0x08,0x2a,0x99,0x20,0x80,0x58,0x24,0x20,0x24,0x07,0x4e,0x59,0x14,0x88,0x10,0xa4,0x64,0x60,0xc0,0x6d,0xe0,0xb2,0x8d,0x1b,0x19,0x09,0x20,0x34,0x22,0xc0,0x24,0x41,0x09,0x43,0x71,0x0a,0x21,0x20,0x61,0xa2,0x01,0x52,0x22,0x52,0x1b,0x80,0x80,0x9a,0x34,0x00,0x13,0x93,0x4d,0xd3,0x32,0x29,0x22,0x17,0x0a,0x98,0x92,0x69,0x1a,0x14,0x51,0x20,0x27,0x21,0x9c,0xc0,0x20,0x62,0xa2,0x81,0x48,0x18,0x69,0x1a,0x85,0x4d,0x83,0x44,0x69,0x5b,0x20,0x41,0x03,0x12,0x42,0xcb,0x18,0x46,0x01,0xa9,0x0d,0x0c,0x02,0x31,0x83,0xb0,0x21,0x5a,0x22,0x4a,0xc8,0x92,0x05,0xd9,0x90,0x69,0x04,0x30,0x6a,0x4b,0x06,0x4a,0xd2,0xb2,0x01,0x1c,0x40,0x40,0x81,0x42,0x32,0x52,0x32,0x72,0x54,0xa6,0x40,0x5a,0x18,0x10,0x0c,0x32,0x12,0x92,0xc2,0x80,0x52,0x12,0x62,0x5c,0x82,0x28,0x0b,0xb4,0x6c,0x03,0x42,0x8d,0x53,0x10,0x0c,0x14,0x01,0x0e,0xe1,0x36,0x52,0x88,0x84,0x24,0x91,0x02,0x0a,0x63,0x46,0x26,0x20,0x06,0x29,0x11,0xc2,0x28,0xd0,0x20,0x48,0x02,0xb3,0x6c,0xa2,0x36,0x09,0x5a,0x86,0x48,0xcb,0xb4,0x61,0x8b,0x46,0x62,0xc4,0x40,0x82,0x1a,0x89,0x09,0x10,0x02,0x4d,0x24,0xb2,0x45,0x20,0x12,0x25,0x24,0xc9,0x05,0x88,0x28,0x8c,0xc9,0xc0,0x4d,0x59,0x48,0x22,0x0a,0x27,0x6e,0xc1,0x34,0x64,0x4c,0x90,0x60,0x5b,0x44,0x50,0x82,0x86,0x49,0x43,0x88,0x04,0x43,0xb2,0x8c,0x60,0x30,0x80,0xa2,0x88,0x2d,0x84,0xa4,0x6d,0x8c,0xa6,0x29,0xd0,0xc6,0x84,0x42,0x06,0x46,0x89,0x88,0x51,0x00,0xa9,0x8d,0x01,0x49,0x8d,0xe4,0x38,0x0d,0xa4,0x06,0x8d,0xd3,0x94,0x71,0x42,0xb2,0x6c,0x1a,0x84,0x61,0x1b,0xa3,0x28,0x42,0xb4,0x28,0x08,0xa0,0x71,0x1a,0xc5,0x31,0xe0,0xa0,0x4c,0x01,0x37,0x65,0x24,0x28,0x62,0x14,0x28,0x90,0x09,0x10,0x61,0xd9,0x40,0x22,0x1b,0x33,0x60,0x09,0x02,0x92,0xd0,0x24,0x81,0x20,0x04,0x08,0x49,0x18,0x44,0xa3,0x22,0x2d,0x5c,0x88,0x44,0x14,0x98,0x08,0xa4,0x46,0x61,0x01,0x95,0x64,0x0b,0x39,0x0a,0x0c,0x94,0x50,0xca,0x40,0x6a,0xd2,0xb2,0x20,0xc0,0x38,0x01,0x82,0x30,0x8e,0x13,0xb9,0x08,0x91,0x80,0x84,0x14,0x88,0x29,0xc0,0x18,0x91,0x12,0x35,0x0d,0xa0,0x24,0x22,0xe2,0x04,0x06,0xd9,0xc2,0x85,0x04,0x28,0x12,0x1c,0xc9,0x89,0x18,0x02,0x72,0xd2,0x40,0x29,0xc2,0x08,0x12,0xd8,0x06,0x2a,0x99,0x94,0x71,0x9b,0xb8,0x68,0x23,0x84,0x29,0x1a,0x22,0x89,0x14,0x45,0x11,0xdc,0x82,0x44,0x50,0x96,0x45,0x0c,0x44,0x84,0xc0,0xb2,0x04,0x9a,0xa6,0x05,0x43,0x86,0x2c,0x44,0x32,0x6e,0x88,0x44,0x21,0x20,0xa8,0x4c,0x9a,0x30,0x70,0xe3,0xb8,0x2d,0x63,0x26,0x88,0x03,0x25,0x49,0x03,0x43,0x8c,0x48,0xa8,0x09,0xca,0x14,0x72,0x53,0x34,0x4e,0x12,0x43,0x08,0x1b,0xa7,0x04,0x59,0x30,0x22,0xd9,0x94,0x80,0xe2,0x34,0x22,0x81,0x42,0x12,0x9c,0x30,0x2a,0x94,0x34,0x26,0x61,0x04,0x45,0x24,0x26,0x28,0x13,0x46,0x09,0x4a,0x32,0x6d,0x11,0x28,0x09,0x18,0xb8,0x25,0x62,0x28,0x11,0x13,0x41,0x0d,0x41,0xb2,0x11,0x90,0x84,0x4c,0x8b,0x12,0x12,0xa2,0xc6,0x88,0xc9,0xc0,0x30,0x22,0x06,0x06,0xd2,0x18,0x8e,0x84,0x86,0x30,0x90,0x44,0x52,0x12,0x88,0x31,0xd9,0x20,0x71,0x13,0xc5,0x28,0x43,0x06,0x0e,0x03,0x30,0x60,0xcc,0xa6,0x84,0x58,0x26,0x52,0x4c,0x88,0x01,0x1e,0xf7,0x25,0x62,0xc8,0x5f,0xfa,0x43,0xac,0xfa,0x49,0x21,0x7f,0x2b,0x17,0x2d,0x7b,0xbc,0x14,0x62,0x0e,0x6d,0x98,0x0a,0x71,0xaa,0xbb,0xdf,0x0c,0x45,0xe9,0xa2,0x06,0xec,0xb1,0x42,0x3f,0xee,0x15,0xde,0xcc,0x17,0x60,0x13,0x00,0x14,0x9d,0x92,0x23,0xcd,0x6e,0x6c,0x6e,0x1f,0xa8,0xe4,0x1f,0xc7,0xc6,0x49,0x38,0xab,0x68,0x90,0x5f,0xd3,0xdc,0xda,0x50,0xd8,0x70,0x82,0xe7,0xd0,0xd7,0x1d,0x1b,0xc9,0xb2,0xb8,0x4c,0x85,0x52,0x3c,0xa8,0xfe,0x6c,0xad,0x29,0x4a,0xdf,0x83,0xbe,0x15,0xb1,0x08,0xff,0x72,0x1d,0x0c,0xc8,0x7b,0xc3,0xdd,0x3a,0x75,0x90,0x18,0x4b,0x0e,0x84,0x56,0x63,0xa9,0x1f,0xc9,0xe1,0xc3,0xc5,0x3a,0x61,0xd8,0x67,0x42,0x0b,0x04,0xf0,0x92,0x35,0x57,0x53,0xbc,0x65,0xa0,0x63,0x68,0xfd,0x41,0x29,0x5f,0xd0,0x99,0x24,0x13,0x2c,0x6f,0x91,0xf6,0x79,0x64,0xc1,0x42,0x67,0x4a,0x72,0x5c,0x34,0x39,0x14,0xc4,0xce,0xcf,0x58,0xc0,0x74,0xbc,0xaf,0x45,0x58,0xc9,0x7b,0xf7,0x91,0x1e,0x07,0xaa,0x6d,0x09,0x38,0xf2,0xee,0x2b,0xb3,0xc1,0xa8,0xc5,0x95,0xd6,0x35,0xe8,0x43,0x42,0xfd,0xea,0x01,0xdc,0x24,0xb2,0x11,0xad,0x2f,0xc2,0x81,0xcf,0x77,0xe5,0x91,0x10,0xc7,0xab,0xc5,0x4b,0xf0,0xc8,0x6d,0x48,0x0b,0x9b,0xe2,0x76,0x47,0x1d,0xc9,0xd6,0x03,0xce,0xe9,0x8c,0xfd,0xab,0x3e,0x9f,0xcf,0xb7,0x03,0x79,0x35,0x60,0x54,0x9e,0xa4,0x45,0x0f,0xa7,0xb3,0x3f,0xb9,0x16,0x9c,0x44,0xb4,0xd2,0x5f,0xb9,0xc4,0x57,0xf4,0x97,0x91,0xcd,0x3d,0xa0,0x3e,0xac,0x96,0x09,0x58,0x13,0xc1,0x05,0x13,0x2c,0xcd,0xa4,0xe6,0x3e,0x49,0x22,0x8c,0xd2,0x3d,0x8a,0x1f,0x37,0x85,0x6f,0x14,0x2d,0x93,0xb9,0x0d,0xb0,0x9f,0x82,0xaf,0x89,0x25,0x8c,0x63,0xaa,0xb8,0x04,0x7a,0x80,0xc0,0x36,0xc9,0x35,0x7e,0xa2,0x04,0x6f,0x8d,0xc6,0x35,0x4f,0x0c,0x52,0x95,0xf3,0x42,0xbb,0x41,0x7d,0x3c,0xfe,0xb0,0xb1,0xfd,0x33,0x62,0x2c,0x29,0xe1,0x4c,0xbb,0xd9,0x2e,0x13,0x63,0xc6,0x5e,0xbd,0x45,0x04,0xb7,0x51,0x23,0x29,0xb9,0x67,0x0e,0x32,0xe1,0xb2,0xc6,0x7a,0x54,0xe7,0xf1,0xa5,0x5f,0x8b,0x9f,0x9e,0xa0,0x4e,0x8c,0xa3,0xa7,0x05,0xe6,0x2a,0x3c,0x5e,0x63,0x73,0x74,0xaf,0xb7,0xae,0xb6,0xdd,0xea,0x61,0x2c,0xde,0x28,0xf0,0x1a,0x20,0x2d,0x7a,0xa4,0xe3,0x47,0x22,0xd2,0x7d,0xd3,0xf9,0xb8,0x98,0x94,0xd0,0x19,0xfd,0x5d,0x4d,0x71,0x19,0xef,0xe3,0x72,0x3b,0xba,0x10,0x4c,0xb8,0xbb,0x09,0x81,0xe0,0x74,0xde,0x3a,0xfe,0x20,0x0d,0xaa,0xae,0xad,0x82,0x6c,0xc4,0x5f,0x24,0x4d,0xbf,0x43,0x1a,0xfa,0xb3,0x4e,0xfb,0xdf,0x78,0x24,0x74,0xd2,0xfd,0x57,0x11,0x8f,0x64,0x62,0x14,0x93,0x4e,0xd9,0x9c,0xba,0x3b,0x00,0x3e,0x8d,0x67,0xa3,0x83,0x6f,0x6f,0x19,0xfc,0x41,0x91,0x0c,0xe5,0x16,0x3e,0xe3,0xae,0x99,0xeb,0x84,0xd5,0x14,0xeb,0x76,0x1e,0x63,0x68,0x4e,0xa5,0x6f,0x97,0x91,0xd2,0xdd,0x4a,0xac,0x6e,0x61,0x68,0xb9,0x48,0xc8,0x17,0xf7,0x5a,0x22,0x2a,0xcb,0x0e,0x8c,0xdc,0x03,0xcc,0x4a,0xfe,0x8f,0x67,0x15,0x7e,0x1a,0x36,0x3b,0x7f,0xae,0xff,0x9f,0x17,0x2b,0x98,0x91,0x36,0x77,0xc5,0xa1,0xdd,0x08,0x5e,0x9e,0xe4,0xc2,0x20,0x52,0xc1,0xaf,0x58,0x19,0x31,0x16,0x67,0x3d,0xcd,0x3b,0xfc,0x5f,0x34,0xb8,0x55,0xdc,0xc6,0xc7,0x78,0x85,0x64,0x9e,0x9e,0x71,0xf4,0x3d,0x4a,0xea,0x0f,0x4b,0x72,0xca,0x7e,0xda,0x05,0x78,0xba,0x13,0xd3,0x1a,0x65,0x8d,0x2d,0x06,0x0a,0x9a,0x66,0xff,0x69,0xed,0x1b,0xe7,0x99,0x7a,0x2f,0xb1,0xd2,0x72,0x3d,0x38,0xf9,0xbf,0xab,0xe1,0x8f,0x8e,0x7b,0x3c,0xda,0x90,0x6e,0x4e,0x9b,0x5e,0x94,0x2c,0x8e,0xae,0xb2,0x96,0x07,0x0e,0xbf,0xd3,0x64,0x94,0x7a,0x94,0x0c,0xc9,0x78,0xbe,0xd6,0x6b,0x37,0x74,0x9e,0x6d,0x5d,0xcd,0x7b,0xe8,0xc4,0x94,0x44,0x0e,0x2b,0x84,0xce,0xcf,0xef,0xb9,0x8c,0x0b,0xed,0xfb,0x3c,0x41,0xe3,0x35,0x9d,0x2c,0xd7,0x19,0x7f,0xbe,0x72,0x0c,0x48,0xaa,0x6c,0x6b,0x64,0x65,0xc1,0xee,0x63,0xe3,0x56,0x9c,0x2a,0xdc,0x74,0x44,0x91,0x37,0x0b,0x7f,0x78,0x26,0xfe,0x0b,0x77,0xa1,0xd1,0x9d,0x64,0x10,0x1d,0x03,0x2b,0x91,0x81,0x06,0xb4,0x2d,0x2e,0xf7,0x37,0x47,0xe5,0x60,0x1f,0xe4,0xba,0x50,0xf2,0x3e,0xde,0x52,0x1f,0x03,0x1a,0x81,0x7d,0x15,0x29,0x4a,0x43,0x72,0x2e,0x83,0x78,0x78,0x4b,0x6d,0xb0,0xcf,0x1b,0xa9,0xe8,0xae,0x91,0x1d,0x92,0x01,0xb9,0xce,0x9c,0xc3,0x01,0x9c,0x6f,0x5c,0x27,0xcb,0x98,0xda,0x26,0x14,0x4b,0x64,0x22,0x5a,0x7c,0x93,0x2b,0x30,0xf7,0x61,0xe7,0x8a,0x2d,0x59,0xa1,0xd8,0xb8,0x3e,0xc6,0x34,0x4a,0x2f,0x6d,0xd4,0x7e,0x76,0x57,0x06,0xd0,0x0b,0xf4,0xa7,0x9a,0x6a,0x92,0x6c,0x3b,0xa9,0x1d,0x81,0x2c,0x8f,0x2c,0x79,0x7a,0xb1,0x79,0x67,0x09,0xe5,0xd1,0x68,0x56,0x77,0x82,0x93,0x52,0x9f,0x02,0x86,0xd0,0x15,0xc3,0xb5,0x39,0x96,0x19,0x64,0x2a,0x33,0x3e,0x9e,0x59,0x3d,0x6e,0x3f,0x53,0x53,0x99,0x42,0x08,0xe9,0xe6,0xa3,0x32,0x85,0x1d,0x7f,0x65,0x25,0x22,0xa9,0x28,0xb9,0x17,0xe2,0x7e,0x2d,0x6d,0x42,0x13,0x7d,0xfe,0x2e,0xbf,0xa6,0xfb,0x1c,0x67,0xb2,0x6c,0x02,0x54,0x52,0x86,0x85,0xf7,0xeb,0xdb,0xe3,0x15,0xa6,0x8e,0xaa,0x2d,0xa7,0x69,0xe8,0xa9,0xf4,0x2d,0x3e,0x60,0x00,0x7c,0x71,0x33,0x09,0x26,0xb2,0xc0,0x01,0x2d,0x83,0xea,0xd4,0xe4,0xfd,0x1e,0xd8,0x72,0xcc,0xd1,0x97,0x22,0x01,0xd2,0xb0,0x27,0xf3,0x54,0x5a,0xc2,0xd3,0x0c,0xd7,0x8b,0xc1,0xd7,0x40,0xfe,0xcc,0xbc,0x6f,0xc2,0xa0,0x44,0x6c,0x6e,0x30,0xea,0xc5,0x1f,0x5a,0x69,0x09,0x8a,0xa2,0xd4,0x47,0xf2,0x08,0x5b,0x4e,0x4e,0x4b,0x92,0xcc,0xc2,0x69,0x21,0xd2,0xde,0x47,0x85,0x18,0xcd,0x09,0x0c,0xe2,0x67,0xae,0xa2,0xd2,0x7a,0xda,0x57,0xfd,0x88,0xb4,0x97,0x6d,0x89,0xfb,0x84,0x3c,0xdc,0xcf,0x49,0xa7,0x6c,0xa2,0x67,0x9e,0x68,0x01,0xbf,0xa7,0xfb,0x03,0x18,0x96,0xfb,0x50,0x62,0x97,0x04,0xb9,0x92,0x39,0x36,0xbb,0x5d,0xd3,0x85,0x31,0x11,0x21,0xca,0xdf,0xb1,0x19,0x95,0xe5,0x9b,0x73,0x03,0x4c,0xf6,0x7e,0xd0,0x3a,0xb8,0x13,0x86,0x76,0x48,0xd0,0x25,0x82,0x80,0x87,0xe9,0x49,0xa9,0xaf,0xd1,0x6b,0x95,0xd7,0x2d,0x99,0xb1,0xed,0xca,0x25,0x7a,0xac,0x13,0x2f,0xfb,0x7a,0x07,0x09,0xae,0xd5,0xa9,0xc0,0xff,0x05,0xfb,0x0f,0x2b,0xbf,0x28,0x40,0x9e,0xed,0x7b,0x5f,0x58,0x01,0xbe,0x96,0x4c,0xed,0x01,0x9e,0x1c,0xb7,0x85,0x1d,0x38,0x51,0xf1,0x02,0x90,0x67,0x4e,0x19,0xff,0xb0,0x08,0xb3,0x01,0xc4,0xac,0xf6,0x41,0xa2,0xbb,0x14,0x21,0x6e,0x1d,0x69,0xca,0xbf,0x52,0xb5,0xef,0x22,0x74,0x96,0xb0,0xf3,0x07,0x99,0xa8,0x55,0xd1,0x17,0xfa,0xd3,0x74,0x4a,0x6f,0xa3,0x35,0x03,0xea,0x79,0x8b,0x52,0xdd,0xd7,0xee,0x54,0x26,0x60,0x9d,0xbf,0xcd,0x3f,0x0c,0x13,0xb1,0x64,0xd6,0xc0,0x51,0xf7,0xed,0x4a,0x11,0x97,0x19,0xa7,0x12,0xe3,0x88,0xd3,0x28,0x40,0x20,0x81,0xff,0x13,0x54,0xb5,0x54,0xd2,0xc2,0x37,0xaf,0xed,0x3b,0x15,0x1c,0x4b,0xa8,0xe9,0xf4,0xbd,0xeb,0x84,0x99,0xa3,0x06,0x6e,0x26,0xbb,0xc6,0x9e,0x8a,0xf0,0x89,0xde,0xc7,0x17,0x31,0xd1,0xdc,0x52,0x9e,0xab,0x17,0xef,0x73,0x74,0x73,0x4c,0x0f,0xe4,0x75,0x49,0x4c,0x83,0x83,0x6b,0xdd,0x34,0xa0,0x3b,0x9b,0xc8,0x99,0x14,0x71,0x60,0x61,0xbf,0xb9,0x8e,0xc6,0xe6,0x1c,0x3e,0xd4,0x43,0x8e,0xdc,0xaf,0x25,0x24,0x3c,0x64,0x70,0x86,0xb9,0xea,0x70,0x18,0xb0,0xd9,0xa8,0xa0,0xb0,0x0c,0xec,0xb0,0x0a,0xbd,0xe2,0x49,0x8d,0x69,0xc2,0x33,0x61,0x01,0xa7,0x72,0xcb,0xe4,0xf5,0x71,0x52,0x3f,0x51,0xbd,0x05,0x88,0x2c,0xdf,0x35,0x8b,0x84,0x9c,0xc1,0x40,0xaa,0x1f,0xaf,0x22,0x42,0x3a,0x12,0x85,0x1c,0xe0,0xe3,0x3f,0xd4,0x89,0x75,0xa4,0x95,0x9f,0xa5,0xc5,0xfe,0x41,0x8c,0x93,0x90,0x81,0x91,0xab,0x6e,0x74,0x1b,0x77,0xbf,0xe0,0x2c,0xbd,0x69,0x8e,0xe7,0x95,0xc4,0x66,0xd6,0x15,0x61,0x9e,0x64,0x41,0x38,0x2c,0x6e,0xac,0x01,0x83,0x4e,0xe9,0xab,0x73,0xce,0xa8,0x0b,0xbe,0x23,0x5c,0x78,0xda,0x91,0xbd,0x79,0xb6,0xf8,0x2f,0x89,0x97,0x85,0xd6,0x87,0x00,0xd3,0x93,0xe6,0x75,0xc2,0x22,0x4d,0x6b,0x7a,0x1a,0xd2,0x13,0x20,0x49,0x56,0x79,0xad,0xae,0xd7,0x01,0x67,0xb5,0x08,0x66,0x71,0x3a,0x53,0x10,0x9d,0xb7,0xb6,0xf7,0xd8,0x13,0x04,0xec,0xdf,0xd8,0x3b,0x31,0x9b,0x1e,0xf2,0x48,0x30,0x6b,0x45,0xad,0x29,0xe7,0xdd,0xcc,0x86,0x3d,0xac,0x56,0x04,0x8b,0x5d,0x69,0xea,0x17,0x50,0x11,0xf7,0x61,0x4c,0x00,0xa8,0x6a,0x86,0x3c,0xde,0x18,0x72,0xa8,0x93,0x28,0x78,0xb9,0xac,0x7e,0x1a,0xc5,0xbd,0xa4,0x99,0x7b,0x72,0x06,0x4f,0x0c,0xd7,0x5f,0x4c,0x81,0x4e,0x03,0x4d,0xe1,0x1a,0xcb,0x90,0x13,0xcf,0x7e,0xa9,0x26,0xb4,0xe7,0xea,0xac,0xe0,0x70,0xc7,0xba,0x21,0x88,0xef,0xad,0x2e,0x43,0x1e,0x12,0x23,0xd4,0x5d,0xd0,0x5c,0x4d,0x84,0x03,0xc2,0xe4,0x5c,0xee,0x64,0x13,0xec,0xbe,0x75,0x27,0xe8,0x73,0xe4,0x55,0xc4,0xe6,0x10,0xa6,0x18,0x39,0xaa,0xcc,0x0b,0xd5,0x6d,0x24,0x83,0xe7,0x8f,0x29,0x8b,0x66,0xa4,0x78,0xeb,0x2f,0x55,0x8c,0xba,0xfc,0xa8,0x6b,0xe8,0x47,0xba,0xeb,0x02,0xc5,0xb2,0x16,0xc8,0xcd,0x88,0xfe,0xa4,0xdf,0x24,0x9b,0x09,0xe6,0x70,0xa2,0x07,0x03,0xab,0xac,0x24,0xb0,0xa9,0x1a,0xbc,0x4a,0x56,0x46,0x60,0x14,0x42,0xba,0x10,0xbe,0xcf,0xd3,0x09,0x93,0x88,0x00,0x51,0xd0,0x7f,0x56,0xa0,0x5a,0x93,0x79,0xe7,0xa8,0xe6,0xbe,0xfe,0xe3,0xf2,0x2f,0xaa,0x10,0x63,0x98,0xf7,0x70,0x60,0x06,0xe4,0x2e,0x9b,0xe1,0xef,0x89,0xd2,0x5c,0x27,0x2f,0x11,0xa9,0x50,0x95,0xc5,0x87,0xd7,0x13,0x73,0x22,0x84,0xde,0x9d,0xbd,0x3c,0x72,0x17,0xb0,0x68,0x9e,0x21,0xd8,0xeb,0x0f,0xf6,0x96,0x68]).unwrap(); + let sk = MLDSA44PrivateKey::from_bytes(&[ + 0xD7, 0xB2, 0xB4, 0x72, 0x54, 0xAA, 0xE0, 0xDB, 0x45, 0xE7, 0x93, 0x0D, 0x4A, 0x98, 0xD2, + 0xC9, 0x7D, 0x8F, 0x13, 0x97, 0xD1, 0x78, 0x9D, 0xAF, 0xA1, 0x70, 0x24, 0xB3, 0x16, 0xE9, + 0xBE, 0xC9, 0x39, 0xCE, 0x0F, 0x7F, 0x77, 0xF8, 0xDB, 0x56, 0x44, 0xDC, 0xDA, 0x36, 0x6B, + 0xFE, 0x47, 0x34, 0xBD, 0x95, 0xF4, 0x35, 0xFF, 0x9A, 0x61, 0x3A, 0xA5, 0x4A, 0xA4, 0x1C, + 0x2C, 0x69, 0x4C, 0x04, 0x32, 0x9A, 0x07, 0xB1, 0xFA, 0xBB, 0x48, 0xF5, 0x2A, 0x30, 0x9F, + 0x11, 0xA1, 0x89, 0x8F, 0x84, 0x8E, 0x23, 0x22, 0xFF, 0xE6, 0x23, 0xEC, 0x81, 0x0D, 0xB3, + 0xBE, 0xE3, 0x36, 0x85, 0x85, 0x4A, 0x88, 0x26, 0x9D, 0xA3, 0x20, 0xD5, 0x12, 0x0B, 0xFC, + 0xFE, 0x89, 0xA1, 0x8E, 0x30, 0xF7, 0x11, 0x4D, 0x83, 0xAA, 0x40, 0x4A, 0x64, 0x6B, 0x6C, + 0x99, 0x73, 0x89, 0x86, 0x0D, 0x12, 0x52, 0x2E, 0xE0, 0x00, 0x6E, 0x23, 0x84, 0x81, 0x91, + 0x86, 0x61, 0x9B, 0x26, 0x0D, 0x11, 0x86, 0x64, 0xD4, 0xA6, 0x28, 0x22, 0x18, 0x44, 0x82, + 0x40, 0x28, 0x98, 0x14, 0x61, 0x48, 0xA6, 0x61, 0x4C, 0x42, 0x48, 0xA1, 0x92, 0x08, 0xC2, + 0x38, 0x29, 0x51, 0x24, 0x48, 0x08, 0xA1, 0x25, 0xC2, 0x08, 0x31, 0x08, 0xC4, 0x71, 0x20, + 0x14, 0x09, 0x14, 0x83, 0x6C, 0x18, 0xA7, 0x80, 0x84, 0x10, 0x6E, 0xC9, 0xC0, 0x70, 0x22, + 0xB5, 0x64, 0x08, 0xB0, 0x61, 0x0C, 0x07, 0x04, 0x98, 0x12, 0x44, 0x51, 0x88, 0x69, 0x59, + 0x00, 0x46, 0x22, 0x93, 0x20, 0x41, 0x06, 0x2E, 0x42, 0xB6, 0x4C, 0x01, 0x16, 0x49, 0x14, + 0x28, 0x4C, 0x41, 0xA8, 0x51, 0x80, 0x46, 0x0A, 0x51, 0x16, 0x51, 0x5A, 0x08, 0x20, 0x02, + 0x22, 0x44, 0xDC, 0x98, 0x49, 0xD1, 0x32, 0x51, 0xE1, 0x30, 0x65, 0xD3, 0xC0, 0x85, 0x92, + 0xA8, 0x51, 0x12, 0xA1, 0x64, 0x00, 0x39, 0x22, 0x09, 0x46, 0x62, 0x1C, 0xC7, 0x0C, 0xD9, + 0x08, 0x6D, 0xD0, 0x06, 0x26, 0x52, 0x40, 0x85, 0x80, 0x44, 0x30, 0x91, 0x06, 0x2C, 0x50, + 0xC8, 0x09, 0x24, 0xC5, 0x84, 0x1A, 0x96, 0x6D, 0x4A, 0x98, 0x2C, 0x99, 0x06, 0x6D, 0xA4, + 0x44, 0x32, 0x20, 0xA7, 0x64, 0x5A, 0x32, 0x6E, 0x11, 0xB5, 0x70, 0x20, 0x92, 0x61, 0x24, + 0x13, 0x8E, 0x04, 0x85, 0x2C, 0x0A, 0x48, 0x72, 0xC8, 0xA0, 0x51, 0xD3, 0x08, 0x2A, 0x99, + 0x20, 0x80, 0x58, 0x24, 0x20, 0x24, 0x07, 0x4E, 0x59, 0x14, 0x88, 0x10, 0xA4, 0x64, 0x60, + 0xC0, 0x6D, 0xE0, 0xB2, 0x8D, 0x1B, 0x19, 0x09, 0x20, 0x34, 0x22, 0xC0, 0x24, 0x41, 0x09, + 0x43, 0x71, 0x0A, 0x21, 0x20, 0x61, 0xA2, 0x01, 0x52, 0x22, 0x52, 0x1B, 0x80, 0x80, 0x9A, + 0x34, 0x00, 0x13, 0x93, 0x4D, 0xD3, 0x32, 0x29, 0x22, 0x17, 0x0A, 0x98, 0x92, 0x69, 0x1A, + 0x14, 0x51, 0x20, 0x27, 0x21, 0x9C, 0xC0, 0x20, 0x62, 0xA2, 0x81, 0x48, 0x18, 0x69, 0x1A, + 0x85, 0x4D, 0x83, 0x44, 0x69, 0x5B, 0x20, 0x41, 0x03, 0x12, 0x42, 0xCB, 0x18, 0x46, 0x01, + 0xA9, 0x0D, 0x0C, 0x02, 0x31, 0x83, 0xB0, 0x21, 0x5A, 0x22, 0x4A, 0xC8, 0x92, 0x05, 0xD9, + 0x90, 0x69, 0x04, 0x30, 0x6A, 0x4B, 0x06, 0x4A, 0xD2, 0xB2, 0x01, 0x1C, 0x40, 0x40, 0x81, + 0x42, 0x32, 0x52, 0x32, 0x72, 0x54, 0xA6, 0x40, 0x5A, 0x18, 0x10, 0x0C, 0x32, 0x12, 0x92, + 0xC2, 0x80, 0x52, 0x12, 0x62, 0x5C, 0x82, 0x28, 0x0B, 0xB4, 0x6C, 0x03, 0x42, 0x8D, 0x53, + 0x10, 0x0C, 0x14, 0x01, 0x0E, 0xE1, 0x36, 0x52, 0x88, 0x84, 0x24, 0x91, 0x02, 0x0A, 0x63, + 0x46, 0x26, 0x20, 0x06, 0x29, 0x11, 0xC2, 0x28, 0xD0, 0x20, 0x48, 0x02, 0xB3, 0x6C, 0xA2, + 0x36, 0x09, 0x5A, 0x86, 0x48, 0xCB, 0xB4, 0x61, 0x8B, 0x46, 0x62, 0xC4, 0x40, 0x82, 0x1A, + 0x89, 0x09, 0x10, 0x02, 0x4D, 0x24, 0xB2, 0x45, 0x20, 0x12, 0x25, 0x24, 0xC9, 0x05, 0x88, + 0x28, 0x8C, 0xC9, 0xC0, 0x4D, 0x59, 0x48, 0x22, 0x0A, 0x27, 0x6E, 0xC1, 0x34, 0x64, 0x4C, + 0x90, 0x60, 0x5B, 0x44, 0x50, 0x82, 0x86, 0x49, 0x43, 0x88, 0x04, 0x43, 0xB2, 0x8C, 0x60, + 0x30, 0x80, 0xA2, 0x88, 0x2D, 0x84, 0xA4, 0x6D, 0x8C, 0xA6, 0x29, 0xD0, 0xC6, 0x84, 0x42, + 0x06, 0x46, 0x89, 0x88, 0x51, 0x00, 0xA9, 0x8D, 0x01, 0x49, 0x8D, 0xE4, 0x38, 0x0D, 0xA4, + 0x06, 0x8D, 0xD3, 0x94, 0x71, 0x42, 0xB2, 0x6C, 0x1A, 0x84, 0x61, 0x1B, 0xA3, 0x28, 0x42, + 0xB4, 0x28, 0x08, 0xA0, 0x71, 0x1A, 0xC5, 0x31, 0xE0, 0xA0, 0x4C, 0x01, 0x37, 0x65, 0x24, + 0x28, 0x62, 0x14, 0x28, 0x90, 0x09, 0x10, 0x61, 0xD9, 0x40, 0x22, 0x1B, 0x33, 0x60, 0x09, + 0x02, 0x92, 0xD0, 0x24, 0x81, 0x20, 0x04, 0x08, 0x49, 0x18, 0x44, 0xA3, 0x22, 0x2D, 0x5C, + 0x88, 0x44, 0x14, 0x98, 0x08, 0xA4, 0x46, 0x61, 0x01, 0x95, 0x64, 0x0B, 0x39, 0x0A, 0x0C, + 0x94, 0x50, 0xCA, 0x40, 0x6A, 0xD2, 0xB2, 0x20, 0xC0, 0x38, 0x01, 0x82, 0x30, 0x8E, 0x13, + 0xB9, 0x08, 0x91, 0x80, 0x84, 0x14, 0x88, 0x29, 0xC0, 0x18, 0x91, 0x12, 0x35, 0x0D, 0xA0, + 0x24, 0x22, 0xE2, 0x04, 0x06, 0xD9, 0xC2, 0x85, 0x04, 0x28, 0x12, 0x1C, 0xC9, 0x89, 0x18, + 0x02, 0x72, 0xD2, 0x40, 0x29, 0xC2, 0x08, 0x12, 0xD8, 0x06, 0x2A, 0x99, 0x94, 0x71, 0x9B, + 0xB8, 0x68, 0x23, 0x84, 0x29, 0x1A, 0x22, 0x89, 0x14, 0x45, 0x11, 0xDC, 0x82, 0x44, 0x50, + 0x96, 0x45, 0x0C, 0x44, 0x84, 0xC0, 0xB2, 0x04, 0x9A, 0xA6, 0x05, 0x43, 0x86, 0x2C, 0x44, + 0x32, 0x6E, 0x88, 0x44, 0x21, 0x20, 0xA8, 0x4C, 0x9A, 0x30, 0x70, 0xE3, 0xB8, 0x2D, 0x63, + 0x26, 0x88, 0x03, 0x25, 0x49, 0x03, 0x43, 0x8C, 0x48, 0xA8, 0x09, 0xCA, 0x14, 0x72, 0x53, + 0x34, 0x4E, 0x12, 0x43, 0x08, 0x1B, 0xA7, 0x04, 0x59, 0x30, 0x22, 0xD9, 0x94, 0x80, 0xE2, + 0x34, 0x22, 0x81, 0x42, 0x12, 0x9C, 0x30, 0x2A, 0x94, 0x34, 0x26, 0x61, 0x04, 0x45, 0x24, + 0x26, 0x28, 0x13, 0x46, 0x09, 0x4A, 0x32, 0x6D, 0x11, 0x28, 0x09, 0x18, 0xB8, 0x25, 0x62, + 0x28, 0x11, 0x13, 0x41, 0x0D, 0x41, 0xB2, 0x11, 0x90, 0x84, 0x4C, 0x8B, 0x12, 0x12, 0xA2, + 0xC6, 0x88, 0xC9, 0xC0, 0x30, 0x22, 0x06, 0x06, 0xD2, 0x18, 0x8E, 0x84, 0x86, 0x30, 0x90, + 0x44, 0x52, 0x12, 0x88, 0x31, 0xD9, 0x20, 0x71, 0x13, 0xC5, 0x28, 0x43, 0x06, 0x0E, 0x03, + 0x30, 0x60, 0xCC, 0xA6, 0x84, 0x58, 0x26, 0x52, 0x4C, 0x88, 0x01, 0x1E, 0xF7, 0x25, 0x62, + 0xC8, 0x5F, 0xFA, 0x43, 0xAC, 0xFA, 0x49, 0x21, 0x7F, 0x2B, 0x17, 0x2D, 0x7B, 0xBC, 0x14, + 0x62, 0x0E, 0x6D, 0x98, 0x0A, 0x71, 0xAA, 0xBB, 0xDF, 0x0C, 0x45, 0xE9, 0xA2, 0x06, 0xEC, + 0xB1, 0x42, 0x3F, 0xEE, 0x15, 0xDE, 0xCC, 0x17, 0x60, 0x13, 0x00, 0x14, 0x9D, 0x92, 0x23, + 0xCD, 0x6E, 0x6C, 0x6E, 0x1F, 0xA8, 0xE4, 0x1F, 0xC7, 0xC6, 0x49, 0x38, 0xAB, 0x68, 0x90, + 0x5F, 0xD3, 0xDC, 0xDA, 0x50, 0xD8, 0x70, 0x82, 0xE7, 0xD0, 0xD7, 0x1D, 0x1B, 0xC9, 0xB2, + 0xB8, 0x4C, 0x85, 0x52, 0x3C, 0xA8, 0xFE, 0x6C, 0xAD, 0x29, 0x4A, 0xDF, 0x83, 0xBE, 0x15, + 0xB1, 0x08, 0xFF, 0x72, 0x1D, 0x0C, 0xC8, 0x7B, 0xC3, 0xDD, 0x3A, 0x75, 0x90, 0x18, 0x4B, + 0x0E, 0x84, 0x56, 0x63, 0xA9, 0x1F, 0xC9, 0xE1, 0xC3, 0xC5, 0x3A, 0x61, 0xD8, 0x67, 0x42, + 0x0B, 0x04, 0xF0, 0x92, 0x35, 0x57, 0x53, 0xBC, 0x65, 0xA0, 0x63, 0x68, 0xFD, 0x41, 0x29, + 0x5F, 0xD0, 0x99, 0x24, 0x13, 0x2C, 0x6F, 0x91, 0xF6, 0x79, 0x64, 0xC1, 0x42, 0x67, 0x4A, + 0x72, 0x5C, 0x34, 0x39, 0x14, 0xC4, 0xCE, 0xCF, 0x58, 0xC0, 0x74, 0xBC, 0xAF, 0x45, 0x58, + 0xC9, 0x7B, 0xF7, 0x91, 0x1E, 0x07, 0xAA, 0x6D, 0x09, 0x38, 0xF2, 0xEE, 0x2B, 0xB3, 0xC1, + 0xA8, 0xC5, 0x95, 0xD6, 0x35, 0xE8, 0x43, 0x42, 0xFD, 0xEA, 0x01, 0xDC, 0x24, 0xB2, 0x11, + 0xAD, 0x2F, 0xC2, 0x81, 0xCF, 0x77, 0xE5, 0x91, 0x10, 0xC7, 0xAB, 0xC5, 0x4B, 0xF0, 0xC8, + 0x6D, 0x48, 0x0B, 0x9B, 0xE2, 0x76, 0x47, 0x1D, 0xC9, 0xD6, 0x03, 0xCE, 0xE9, 0x8C, 0xFD, + 0xAB, 0x3E, 0x9F, 0xCF, 0xB7, 0x03, 0x79, 0x35, 0x60, 0x54, 0x9E, 0xA4, 0x45, 0x0F, 0xA7, + 0xB3, 0x3F, 0xB9, 0x16, 0x9C, 0x44, 0xB4, 0xD2, 0x5F, 0xB9, 0xC4, 0x57, 0xF4, 0x97, 0x91, + 0xCD, 0x3D, 0xA0, 0x3E, 0xAC, 0x96, 0x09, 0x58, 0x13, 0xC1, 0x05, 0x13, 0x2C, 0xCD, 0xA4, + 0xE6, 0x3E, 0x49, 0x22, 0x8C, 0xD2, 0x3D, 0x8A, 0x1F, 0x37, 0x85, 0x6F, 0x14, 0x2D, 0x93, + 0xB9, 0x0D, 0xB0, 0x9F, 0x82, 0xAF, 0x89, 0x25, 0x8C, 0x63, 0xAA, 0xB8, 0x04, 0x7A, 0x80, + 0xC0, 0x36, 0xC9, 0x35, 0x7E, 0xA2, 0x04, 0x6F, 0x8D, 0xC6, 0x35, 0x4F, 0x0C, 0x52, 0x95, + 0xF3, 0x42, 0xBB, 0x41, 0x7D, 0x3C, 0xFE, 0xB0, 0xB1, 0xFD, 0x33, 0x62, 0x2C, 0x29, 0xE1, + 0x4C, 0xBB, 0xD9, 0x2E, 0x13, 0x63, 0xC6, 0x5E, 0xBD, 0x45, 0x04, 0xB7, 0x51, 0x23, 0x29, + 0xB9, 0x67, 0x0E, 0x32, 0xE1, 0xB2, 0xC6, 0x7A, 0x54, 0xE7, 0xF1, 0xA5, 0x5F, 0x8B, 0x9F, + 0x9E, 0xA0, 0x4E, 0x8C, 0xA3, 0xA7, 0x05, 0xE6, 0x2A, 0x3C, 0x5E, 0x63, 0x73, 0x74, 0xAF, + 0xB7, 0xAE, 0xB6, 0xDD, 0xEA, 0x61, 0x2C, 0xDE, 0x28, 0xF0, 0x1A, 0x20, 0x2D, 0x7A, 0xA4, + 0xE3, 0x47, 0x22, 0xD2, 0x7D, 0xD3, 0xF9, 0xB8, 0x98, 0x94, 0xD0, 0x19, 0xFD, 0x5D, 0x4D, + 0x71, 0x19, 0xEF, 0xE3, 0x72, 0x3B, 0xBA, 0x10, 0x4C, 0xB8, 0xBB, 0x09, 0x81, 0xE0, 0x74, + 0xDE, 0x3A, 0xFE, 0x20, 0x0D, 0xAA, 0xAE, 0xAD, 0x82, 0x6C, 0xC4, 0x5F, 0x24, 0x4D, 0xBF, + 0x43, 0x1A, 0xFA, 0xB3, 0x4E, 0xFB, 0xDF, 0x78, 0x24, 0x74, 0xD2, 0xFD, 0x57, 0x11, 0x8F, + 0x64, 0x62, 0x14, 0x93, 0x4E, 0xD9, 0x9C, 0xBA, 0x3B, 0x00, 0x3E, 0x8D, 0x67, 0xA3, 0x83, + 0x6F, 0x6F, 0x19, 0xFC, 0x41, 0x91, 0x0C, 0xE5, 0x16, 0x3E, 0xE3, 0xAE, 0x99, 0xEB, 0x84, + 0xD5, 0x14, 0xEB, 0x76, 0x1E, 0x63, 0x68, 0x4E, 0xA5, 0x6F, 0x97, 0x91, 0xD2, 0xDD, 0x4A, + 0xAC, 0x6E, 0x61, 0x68, 0xB9, 0x48, 0xC8, 0x17, 0xF7, 0x5A, 0x22, 0x2A, 0xCB, 0x0E, 0x8C, + 0xDC, 0x03, 0xCC, 0x4A, 0xFE, 0x8F, 0x67, 0x15, 0x7E, 0x1A, 0x36, 0x3B, 0x7F, 0xAE, 0xFF, + 0x9F, 0x17, 0x2B, 0x98, 0x91, 0x36, 0x77, 0xC5, 0xA1, 0xDD, 0x08, 0x5E, 0x9E, 0xE4, 0xC2, + 0x20, 0x52, 0xC1, 0xAF, 0x58, 0x19, 0x31, 0x16, 0x67, 0x3D, 0xCD, 0x3B, 0xFC, 0x5F, 0x34, + 0xB8, 0x55, 0xDC, 0xC6, 0xC7, 0x78, 0x85, 0x64, 0x9E, 0x9E, 0x71, 0xF4, 0x3D, 0x4A, 0xEA, + 0x0F, 0x4B, 0x72, 0xCA, 0x7E, 0xDA, 0x05, 0x78, 0xBA, 0x13, 0xD3, 0x1A, 0x65, 0x8D, 0x2D, + 0x06, 0x0A, 0x9A, 0x66, 0xFF, 0x69, 0xED, 0x1B, 0xE7, 0x99, 0x7A, 0x2F, 0xB1, 0xD2, 0x72, + 0x3D, 0x38, 0xF9, 0xBF, 0xAB, 0xE1, 0x8F, 0x8E, 0x7B, 0x3C, 0xDA, 0x90, 0x6E, 0x4E, 0x9B, + 0x5E, 0x94, 0x2C, 0x8E, 0xAE, 0xB2, 0x96, 0x07, 0x0E, 0xBF, 0xD3, 0x64, 0x94, 0x7A, 0x94, + 0x0C, 0xC9, 0x78, 0xBE, 0xD6, 0x6B, 0x37, 0x74, 0x9E, 0x6D, 0x5D, 0xCD, 0x7B, 0xE8, 0xC4, + 0x94, 0x44, 0x0E, 0x2B, 0x84, 0xCE, 0xCF, 0xEF, 0xB9, 0x8C, 0x0B, 0xED, 0xFB, 0x3C, 0x41, + 0xE3, 0x35, 0x9D, 0x2C, 0xD7, 0x19, 0x7F, 0xBE, 0x72, 0x0C, 0x48, 0xAA, 0x6C, 0x6B, 0x64, + 0x65, 0xC1, 0xEE, 0x63, 0xE3, 0x56, 0x9C, 0x2A, 0xDC, 0x74, 0x44, 0x91, 0x37, 0x0B, 0x7F, + 0x78, 0x26, 0xFE, 0x0B, 0x77, 0xA1, 0xD1, 0x9D, 0x64, 0x10, 0x1D, 0x03, 0x2B, 0x91, 0x81, + 0x06, 0xB4, 0x2D, 0x2E, 0xF7, 0x37, 0x47, 0xE5, 0x60, 0x1F, 0xE4, 0xBA, 0x50, 0xF2, 0x3E, + 0xDE, 0x52, 0x1F, 0x03, 0x1A, 0x81, 0x7D, 0x15, 0x29, 0x4A, 0x43, 0x72, 0x2E, 0x83, 0x78, + 0x78, 0x4B, 0x6D, 0xB0, 0xCF, 0x1B, 0xA9, 0xE8, 0xAE, 0x91, 0x1D, 0x92, 0x01, 0xB9, 0xCE, + 0x9C, 0xC3, 0x01, 0x9C, 0x6F, 0x5C, 0x27, 0xCB, 0x98, 0xDA, 0x26, 0x14, 0x4B, 0x64, 0x22, + 0x5A, 0x7C, 0x93, 0x2B, 0x30, 0xF7, 0x61, 0xE7, 0x8A, 0x2D, 0x59, 0xA1, 0xD8, 0xB8, 0x3E, + 0xC6, 0x34, 0x4A, 0x2F, 0x6D, 0xD4, 0x7E, 0x76, 0x57, 0x06, 0xD0, 0x0B, 0xF4, 0xA7, 0x9A, + 0x6A, 0x92, 0x6C, 0x3B, 0xA9, 0x1D, 0x81, 0x2C, 0x8F, 0x2C, 0x79, 0x7A, 0xB1, 0x79, 0x67, + 0x09, 0xE5, 0xD1, 0x68, 0x56, 0x77, 0x82, 0x93, 0x52, 0x9F, 0x02, 0x86, 0xD0, 0x15, 0xC3, + 0xB5, 0x39, 0x96, 0x19, 0x64, 0x2A, 0x33, 0x3E, 0x9E, 0x59, 0x3D, 0x6E, 0x3F, 0x53, 0x53, + 0x99, 0x42, 0x08, 0xE9, 0xE6, 0xA3, 0x32, 0x85, 0x1D, 0x7F, 0x65, 0x25, 0x22, 0xA9, 0x28, + 0xB9, 0x17, 0xE2, 0x7E, 0x2D, 0x6D, 0x42, 0x13, 0x7D, 0xFE, 0x2E, 0xBF, 0xA6, 0xFB, 0x1C, + 0x67, 0xB2, 0x6C, 0x02, 0x54, 0x52, 0x86, 0x85, 0xF7, 0xEB, 0xDB, 0xE3, 0x15, 0xA6, 0x8E, + 0xAA, 0x2D, 0xA7, 0x69, 0xE8, 0xA9, 0xF4, 0x2D, 0x3E, 0x60, 0x00, 0x7C, 0x71, 0x33, 0x09, + 0x26, 0xB2, 0xC0, 0x01, 0x2D, 0x83, 0xEA, 0xD4, 0xE4, 0xFD, 0x1E, 0xD8, 0x72, 0xCC, 0xD1, + 0x97, 0x22, 0x01, 0xD2, 0xB0, 0x27, 0xF3, 0x54, 0x5A, 0xC2, 0xD3, 0x0C, 0xD7, 0x8B, 0xC1, + 0xD7, 0x40, 0xFE, 0xCC, 0xBC, 0x6F, 0xC2, 0xA0, 0x44, 0x6C, 0x6E, 0x30, 0xEA, 0xC5, 0x1F, + 0x5A, 0x69, 0x09, 0x8A, 0xA2, 0xD4, 0x47, 0xF2, 0x08, 0x5B, 0x4E, 0x4E, 0x4B, 0x92, 0xCC, + 0xC2, 0x69, 0x21, 0xD2, 0xDE, 0x47, 0x85, 0x18, 0xCD, 0x09, 0x0C, 0xE2, 0x67, 0xAE, 0xA2, + 0xD2, 0x7A, 0xDA, 0x57, 0xFD, 0x88, 0xB4, 0x97, 0x6D, 0x89, 0xFB, 0x84, 0x3C, 0xDC, 0xCF, + 0x49, 0xA7, 0x6C, 0xA2, 0x67, 0x9E, 0x68, 0x01, 0xBF, 0xA7, 0xFB, 0x03, 0x18, 0x96, 0xFB, + 0x50, 0x62, 0x97, 0x04, 0xB9, 0x92, 0x39, 0x36, 0xBB, 0x5D, 0xD3, 0x85, 0x31, 0x11, 0x21, + 0xCA, 0xDF, 0xB1, 0x19, 0x95, 0xE5, 0x9B, 0x73, 0x03, 0x4C, 0xF6, 0x7E, 0xD0, 0x3A, 0xB8, + 0x13, 0x86, 0x76, 0x48, 0xD0, 0x25, 0x82, 0x80, 0x87, 0xE9, 0x49, 0xA9, 0xAF, 0xD1, 0x6B, + 0x95, 0xD7, 0x2D, 0x99, 0xB1, 0xED, 0xCA, 0x25, 0x7A, 0xAC, 0x13, 0x2F, 0xFB, 0x7A, 0x07, + 0x09, 0xAE, 0xD5, 0xA9, 0xC0, 0xFF, 0x05, 0xFB, 0x0F, 0x2B, 0xBF, 0x28, 0x40, 0x9E, 0xED, + 0x7B, 0x5F, 0x58, 0x01, 0xBE, 0x96, 0x4C, 0xED, 0x01, 0x9E, 0x1C, 0xB7, 0x85, 0x1D, 0x38, + 0x51, 0xF1, 0x02, 0x90, 0x67, 0x4E, 0x19, 0xFF, 0xB0, 0x08, 0xB3, 0x01, 0xC4, 0xAC, 0xF6, + 0x41, 0xA2, 0xBB, 0x14, 0x21, 0x6E, 0x1D, 0x69, 0xCA, 0xBF, 0x52, 0xB5, 0xEF, 0x22, 0x74, + 0x96, 0xB0, 0xF3, 0x07, 0x99, 0xA8, 0x55, 0xD1, 0x17, 0xFA, 0xD3, 0x74, 0x4A, 0x6F, 0xA3, + 0x35, 0x03, 0xEA, 0x79, 0x8B, 0x52, 0xDD, 0xD7, 0xEE, 0x54, 0x26, 0x60, 0x9D, 0xBF, 0xCD, + 0x3F, 0x0C, 0x13, 0xB1, 0x64, 0xD6, 0xC0, 0x51, 0xF7, 0xED, 0x4A, 0x11, 0x97, 0x19, 0xA7, + 0x12, 0xE3, 0x88, 0xD3, 0x28, 0x40, 0x20, 0x81, 0xFF, 0x13, 0x54, 0xB5, 0x54, 0xD2, 0xC2, + 0x37, 0xAF, 0xED, 0x3B, 0x15, 0x1C, 0x4B, 0xA8, 0xE9, 0xF4, 0xBD, 0xEB, 0x84, 0x99, 0xA3, + 0x06, 0x6E, 0x26, 0xBB, 0xC6, 0x9E, 0x8A, 0xF0, 0x89, 0xDE, 0xC7, 0x17, 0x31, 0xD1, 0xDC, + 0x52, 0x9E, 0xAB, 0x17, 0xEF, 0x73, 0x74, 0x73, 0x4C, 0x0F, 0xE4, 0x75, 0x49, 0x4C, 0x83, + 0x83, 0x6B, 0xDD, 0x34, 0xA0, 0x3B, 0x9B, 0xC8, 0x99, 0x14, 0x71, 0x60, 0x61, 0xBF, 0xB9, + 0x8E, 0xC6, 0xE6, 0x1C, 0x3E, 0xD4, 0x43, 0x8E, 0xDC, 0xAF, 0x25, 0x24, 0x3C, 0x64, 0x70, + 0x86, 0xB9, 0xEA, 0x70, 0x18, 0xB0, 0xD9, 0xA8, 0xA0, 0xB0, 0x0C, 0xEC, 0xB0, 0x0A, 0xBD, + 0xE2, 0x49, 0x8D, 0x69, 0xC2, 0x33, 0x61, 0x01, 0xA7, 0x72, 0xCB, 0xE4, 0xF5, 0x71, 0x52, + 0x3F, 0x51, 0xBD, 0x05, 0x88, 0x2C, 0xDF, 0x35, 0x8B, 0x84, 0x9C, 0xC1, 0x40, 0xAA, 0x1F, + 0xAF, 0x22, 0x42, 0x3A, 0x12, 0x85, 0x1C, 0xE0, 0xE3, 0x3F, 0xD4, 0x89, 0x75, 0xA4, 0x95, + 0x9F, 0xA5, 0xC5, 0xFE, 0x41, 0x8C, 0x93, 0x90, 0x81, 0x91, 0xAB, 0x6E, 0x74, 0x1B, 0x77, + 0xBF, 0xE0, 0x2C, 0xBD, 0x69, 0x8E, 0xE7, 0x95, 0xC4, 0x66, 0xD6, 0x15, 0x61, 0x9E, 0x64, + 0x41, 0x38, 0x2C, 0x6E, 0xAC, 0x01, 0x83, 0x4E, 0xE9, 0xAB, 0x73, 0xCE, 0xA8, 0x0B, 0xBE, + 0x23, 0x5C, 0x78, 0xDA, 0x91, 0xBD, 0x79, 0xB6, 0xF8, 0x2F, 0x89, 0x97, 0x85, 0xD6, 0x87, + 0x00, 0xD3, 0x93, 0xE6, 0x75, 0xC2, 0x22, 0x4D, 0x6B, 0x7A, 0x1A, 0xD2, 0x13, 0x20, 0x49, + 0x56, 0x79, 0xAD, 0xAE, 0xD7, 0x01, 0x67, 0xB5, 0x08, 0x66, 0x71, 0x3A, 0x53, 0x10, 0x9D, + 0xB7, 0xB6, 0xF7, 0xD8, 0x13, 0x04, 0xEC, 0xDF, 0xD8, 0x3B, 0x31, 0x9B, 0x1E, 0xF2, 0x48, + 0x30, 0x6B, 0x45, 0xAD, 0x29, 0xE7, 0xDD, 0xCC, 0x86, 0x3D, 0xAC, 0x56, 0x04, 0x8B, 0x5D, + 0x69, 0xEA, 0x17, 0x50, 0x11, 0xF7, 0x61, 0x4C, 0x00, 0xA8, 0x6A, 0x86, 0x3C, 0xDE, 0x18, + 0x72, 0xA8, 0x93, 0x28, 0x78, 0xB9, 0xAC, 0x7E, 0x1A, 0xC5, 0xBD, 0xA4, 0x99, 0x7B, 0x72, + 0x06, 0x4F, 0x0C, 0xD7, 0x5F, 0x4C, 0x81, 0x4E, 0x03, 0x4D, 0xE1, 0x1A, 0xCB, 0x90, 0x13, + 0xCF, 0x7E, 0xA9, 0x26, 0xB4, 0xE7, 0xEA, 0xAC, 0xE0, 0x70, 0xC7, 0xBA, 0x21, 0x88, 0xEF, + 0xAD, 0x2E, 0x43, 0x1E, 0x12, 0x23, 0xD4, 0x5D, 0xD0, 0x5C, 0x4D, 0x84, 0x03, 0xC2, 0xE4, + 0x5C, 0xEE, 0x64, 0x13, 0xEC, 0xBE, 0x75, 0x27, 0xE8, 0x73, 0xE4, 0x55, 0xC4, 0xE6, 0x10, + 0xA6, 0x18, 0x39, 0xAA, 0xCC, 0x0B, 0xD5, 0x6D, 0x24, 0x83, 0xE7, 0x8F, 0x29, 0x8B, 0x66, + 0xA4, 0x78, 0xEB, 0x2F, 0x55, 0x8C, 0xBA, 0xFC, 0xA8, 0x6B, 0xE8, 0x47, 0xBA, 0xEB, 0x02, + 0xC5, 0xB2, 0x16, 0xC8, 0xCD, 0x88, 0xFE, 0xA4, 0xDF, 0x24, 0x9B, 0x09, 0xE6, 0x70, 0xA2, + 0x07, 0x03, 0xAB, 0xAC, 0x24, 0xB0, 0xA9, 0x1A, 0xBC, 0x4A, 0x56, 0x46, 0x60, 0x14, 0x42, + 0xBA, 0x10, 0xBE, 0xCF, 0xD3, 0x09, 0x93, 0x88, 0x00, 0x51, 0xD0, 0x7F, 0x56, 0xA0, 0x5A, + 0x93, 0x79, 0xE7, 0xA8, 0xE6, 0xBE, 0xFE, 0xE3, 0xF2, 0x2F, 0xAA, 0x10, 0x63, 0x98, 0xF7, + 0x70, 0x60, 0x06, 0xE4, 0x2E, 0x9B, 0xE1, 0xEF, 0x89, 0xD2, 0x5C, 0x27, 0x2F, 0x11, 0xA9, + 0x50, 0x95, 0xC5, 0x87, 0xD7, 0x13, 0x73, 0x22, 0x84, 0xDE, 0x9D, 0xBD, 0x3C, 0x72, 0x17, + 0xB0, 0x68, 0x9E, 0x21, 0xD8, 0xEB, 0x0F, 0xF6, 0x96, 0x68, + ]) + .unwrap(); let msg = b"The quick brown fox jumped over the lazy dog"; @@ -182,7 +418,7 @@ fn bench_mldsa44_sign() { } fn bench_mldsa44_lowmemory_sign() { - use bouncycastle::mldsa_lowmemory::{MLDSATrait, MLDSA44, MLDSA44PrivateKey, MLDSA44_SK_LEN}; + use bouncycastle::mldsa_lowmemory::{MLDSA44, MLDSA44_SK_LEN, MLDSA44PrivateKey, MLDSATrait}; eprintln!("MLDSA44_lowmemory/Sign"); @@ -195,7 +431,12 @@ fn bench_mldsa44_lowmemory_sign() { // use bouncycastle_hex as hex; // eprintln!("sk:\n{}", &hex::encode(sk.encode())); - let sk = MLDSA44PrivateKey::from_bytes(&[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f]).unwrap(); + let sk = MLDSA44PrivateKey::from_bytes(&[ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, + 0x1E, 0x1F, + ]) + .unwrap(); let msg = b"The quick brown fox jumped over the lazy dog"; @@ -205,7 +446,7 @@ fn bench_mldsa44_lowmemory_sign() { } fn bench_mldsa65_sign() { - use bouncycastle::mldsa::{MLDSATrait, MLDSA65, MLDSA65PrivateKey, MLDSA65_SK_LEN}; + use bouncycastle::mldsa::{MLDSA65, MLDSA65_SK_LEN, MLDSA65PrivateKey, MLDSATrait}; eprintln!("MLDSA65/Sign"); @@ -219,7 +460,278 @@ fn bench_mldsa65_sign() { // use bouncycastle_hex as hex; // eprintln!("sk:\n{}", &hex::encode(sk.encode())); - let sk = MLDSA65PrivateKey::from_bytes(&[0x48,0x68,0x3d,0x91,0x97,0x8e,0x31,0xeb,0x3d,0xdd,0xb8,0xb0,0x47,0x34,0x82,0xd2,0xb8,0x8a,0x5f,0x62,0x59,0x49,0xfd,0x8f,0x58,0xa5,0x61,0xe6,0x96,0xbd,0x4c,0x27,0xd8,0x53,0xfa,0x69,0xb8,0x19,0x90,0x23,0xe8,0xcd,0x67,0x8d,0xd9,0xfa,0xbf,0x90,0x47,0x64,0x6f,0xfd,0x0c,0xb3,0xcc,0x7f,0x79,0x58,0x05,0xa7,0x1e,0x70,0xd2,0x37,0x1b,0x05,0x63,0xe3,0xcd,0x33,0x46,0x14,0x9c,0x8c,0x9e,0xbc,0xf2,0x3b,0x0a,0x4e,0x5a,0x90,0x0e,0xea,0x9c,0x65,0x62,0x79,0x0a,0x7c,0x63,0xe3,0x86,0x63,0xda,0xa2,0xdd,0xdb,0x6e,0x48,0x0d,0xc4,0x05,0xa1,0xe7,0x01,0x94,0x8b,0x74,0x84,0x1e,0xf5,0xcc,0x1c,0x3f,0x2b,0xf3,0x27,0x97,0x2e,0x95,0x10,0x51,0x0c,0xd5,0x37,0x5e,0xcc,0x08,0x55,0x71,0x77,0x11,0x87,0x22,0x21,0x86,0x23,0x81,0x00,0x04,0x24,0x77,0x80,0x61,0x47,0x50,0x07,0x50,0x17,0x17,0x03,0x55,0x04,0x51,0x51,0x25,0x47,0x18,0x38,0x04,0x61,0x75,0x72,0x22,0x44,0x10,0x88,0x68,0x60,0x86,0x46,0x01,0x27,0x47,0x56,0x71,0x80,0x87,0x06,0x66,0x86,0x43,0x32,0x44,0x41,0x22,0x04,0x36,0x38,0x66,0x75,0x02,0x82,0x36,0x34,0x24,0x43,0x22,0x05,0x73,0x64,0x10,0x64,0x55,0x54,0x77,0x22,0x75,0x56,0x81,0x43,0x36,0x14,0x62,0x55,0x08,0x20,0x64,0x37,0x68,0x54,0x68,0x75,0x43,0x53,0x75,0x10,0x68,0x71,0x83,0x33,0x80,0x54,0x75,0x05,0x25,0x80,0x75,0x28,0x18,0x84,0x38,0x11,0x08,0x72,0x60,0x20,0x20,0x08,0x58,0x83,0x01,0x83,0x61,0x13,0x82,0x82,0x12,0x06,0x17,0x11,0x57,0x87,0x68,0x78,0x88,0x78,0x64,0x37,0x54,0x60,0x16,0x57,0x15,0x50,0x84,0x71,0x88,0x66,0x07,0x27,0x32,0x88,0x06,0x64,0x74,0x18,0x56,0x76,0x21,0x80,0x31,0x82,0x76,0x64,0x15,0x78,0x24,0x50,0x25,0x64,0x66,0x43,0x11,0x35,0x04,0x36,0x47,0x80,0x12,0x66,0x73,0x14,0x30,0x11,0x66,0x06,0x55,0x86,0x47,0x18,0x36,0x88,0x63,0x50,0x38,0x47,0x86,0x11,0x01,0x20,0x23,0x56,0x11,0x61,0x37,0x86,0x07,0x85,0x32,0x12,0x40,0x07,0x54,0x78,0x82,0x30,0x43,0x66,0x61,0x16,0x60,0x42,0x55,0x41,0x82,0x85,0x60,0x53,0x67,0x78,0x56,0x38,0x43,0x44,0x30,0x63,0x26,0x10,0x77,0x07,0x31,0x78,0x42,0x72,0x14,0x11,0x16,0x53,0x03,0x85,0x27,0x68,0x67,0x46,0x01,0x50,0x82,0x37,0x35,0x32,0x07,0x66,0x10,0x75,0x04,0x68,0x12,0x48,0x06,0x66,0x03,0x03,0x26,0x52,0x31,0x24,0x45,0x40,0x88,0x00,0x31,0x80,0x88,0x76,0x72,0x17,0x30,0x71,0x82,0x47,0x21,0x51,0x27,0x80,0x11,0x65,0x44,0x74,0x86,0x61,0x72,0x23,0x33,0x80,0x86,0x60,0x64,0x46,0x83,0x52,0x15,0x84,0x20,0x36,0x80,0x11,0x80,0x21,0x18,0x18,0x33,0x17,0x73,0x54,0x53,0x48,0x81,0x00,0x44,0x86,0x53,0x67,0x43,0x70,0x57,0x72,0x58,0x83,0x34,0x60,0x38,0x42,0x32,0x85,0x68,0x10,0x06,0x04,0x26,0x04,0x25,0x84,0x56,0x02,0x35,0x68,0x20,0x51,0x83,0x86,0x38,0x43,0x24,0x21,0x22,0x42,0x45,0x64,0x58,0x58,0x67,0x71,0x45,0x72,0x85,0x04,0x78,0x87,0x17,0x18,0x06,0x18,0x83,0x60,0x86,0x86,0x41,0x56,0x50,0x81,0x16,0x50,0x26,0x46,0x70,0x06,0x08,0x26,0x62,0x27,0x38,0x31,0x72,0x40,0x72,0x57,0x30,0x07,0x27,0x28,0x86,0x20,0x66,0x75,0x88,0x68,0x26,0x07,0x06,0x40,0x20,0x33,0x03,0x43,0x66,0x31,0x55,0x46,0x42,0x45,0x34,0x56,0x67,0x18,0x73,0x45,0x65,0x83,0x70,0x22,0x50,0x84,0x68,0x56,0x28,0x80,0x70,0x36,0x70,0x84,0x62,0x37,0x17,0x10,0x06,0x57,0x17,0x58,0x47,0x78,0x70,0x86,0x55,0x53,0x78,0x22,0x35,0x14,0x46,0x77,0x28,0x56,0x73,0x03,0x22,0x87,0x00,0x14,0x33,0x20,0x61,0x71,0x58,0x45,0x52,0x66,0x32,0x50,0x26,0x51,0x33,0x47,0x77,0x38,0x03,0x55,0x16,0x43,0x13,0x47,0x35,0x10,0x66,0x27,0x51,0x75,0x74,0x02,0x46,0x88,0x81,0x70,0x67,0x43,0x46,0x81,0x86,0x01,0x76,0x52,0x45,0x33,0x30,0x87,0x21,0x04,0x34,0x34,0x01,0x03,0x22,0x87,0x63,0x51,0x55,0x26,0x50,0x81,0x30,0x77,0x45,0x44,0x41,0x68,0x15,0x41,0x83,0x63,0x64,0x11,0x20,0x40,0x26,0x87,0x30,0x43,0x67,0x77,0x12,0x80,0x88,0x46,0x35,0x54,0x53,0x00,0x62,0x45,0x81,0x04,0x58,0x36,0x51,0x24,0x84,0x27,0x80,0x34,0x51,0x66,0x63,0x58,0x43,0x78,0x56,0x01,0x46,0x51,0x15,0x74,0x23,0x21,0x43,0x66,0x85,0x22,0x47,0x77,0x31,0x34,0x50,0x17,0x83,0x62,0x42,0x05,0x50,0x00,0x64,0x84,0x47,0x12,0x34,0x40,0x88,0x00,0x60,0x47,0x35,0x40,0x57,0x83,0x33,0x63,0x08,0x21,0x06,0x15,0x22,0x52,0x07,0x24,0x88,0x51,0x34,0x86,0x37,0x06,0x76,0x22,0x58,0x85,0x71,0x26,0x56,0x73,0x47,0x68,0x16,0x46,0x46,0x84,0x25,0x87,0x08,0x12,0x27,0x05,0x50,0x08,0x38,0x32,0x00,0x23,0x20,0x80,0x66,0x34,0x53,0x36,0x00,0x33,0x46,0x85,0x72,0x47,0x06,0x35,0x54,0x00,0x35,0x77,0x12,0x27,0x52,0x30,0x71,0x42,0x53,0x68,0x74,0x37,0x45,0x70,0x05,0x66,0x43,0x22,0x44,0x82,0x85,0x20,0x72,0x18,0x33,0x30,0x20,0x53,0x37,0x33,0x40,0x77,0x27,0x80,0x55,0x25,0x30,0x63,0x52,0x50,0x40,0x67,0x33,0x46,0x13,0x18,0x07,0x28,0x07,0x17,0x24,0x83,0x77,0x63,0x45,0x73,0x18,0x58,0x51,0x60,0x23,0x33,0x44,0x36,0x25,0x16,0x43,0x38,0x16,0x08,0x58,0x77,0x34,0x62,0x42,0x88,0x30,0x07,0x03,0x65,0x85,0x37,0x55,0x00,0x75,0x52,0x31,0x50,0x37,0x02,0x13,0x24,0x63,0x04,0x37,0x08,0x68,0x06,0x36,0x15,0x03,0x03,0x00,0x43,0x58,0x63,0x57,0x08,0x02,0x11,0x06,0x64,0x73,0x46,0x35,0x22,0x62,0x03,0x30,0x43,0x80,0x21,0x08,0x52,0x87,0x57,0x83,0x21,0x07,0x88,0x67,0x48,0x08,0x56,0x34,0x74,0x36,0x73,0x42,0x84,0x05,0x84,0x66,0x84,0x14,0x37,0x00,0x55,0x10,0x87,0x34,0x26,0x44,0x77,0x21,0x12,0x73,0x84,0x73,0x65,0x26,0x47,0x25,0x77,0x14,0x47,0x04,0x17,0x86,0x44,0x26,0x02,0x47,0x11,0x87,0x40,0x81,0x22,0x16,0x60,0x58,0x47,0x17,0x81,0x37,0x06,0x76,0x80,0x81,0x70,0x58,0x18,0x55,0x85,0x47,0x13,0x63,0x42,0x10,0x75,0x58,0x01,0x63,0x58,0x35,0x85,0x18,0x44,0x03,0x84,0x71,0x10,0x33,0x87,0x42,0x62,0x82,0x47,0x74,0x13,0x65,0x54,0x42,0x70,0x73,0x46,0x35,0x77,0x75,0x00,0x66,0x25,0x62,0x68,0x42,0x02,0x12,0x46,0x83,0x86,0x46,0x16,0x64,0x60,0x31,0x22,0x53,0x88,0x84,0x54,0x00,0x84,0x57,0x34,0x46,0x47,0x54,0x47,0x25,0x60,0x54,0x61,0x66,0x84,0x66,0x30,0x88,0x06,0x38,0x27,0x15,0x63,0x28,0x71,0x83,0x84,0x06,0x52,0x24,0x76,0x81,0x16,0x06,0x62,0x13,0x03,0x30,0x18,0x68,0x02,0x80,0x13,0x84,0x63,0x05,0x05,0x65,0x72,0x38,0x75,0x83,0x65,0x72,0x32,0x30,0x68,0x80,0x46,0x12,0x26,0x06,0x65,0x16,0x75,0x57,0x05,0x32,0x41,0x32,0x27,0x67,0x35,0x17,0x08,0x01,0x53,0x00,0x16,0x28,0x46,0x01,0x34,0x88,0x77,0x01,0x11,0x88,0x15,0x57,0x13,0x15,0x46,0x43,0x11,0x70,0x47,0x32,0x88,0x28,0x56,0x36,0x82,0x34,0x55,0x50,0x41,0x86,0x27,0x65,0x63,0x11,0x11,0x68,0x75,0x05,0x10,0x42,0x54,0x41,0x44,0x27,0x85,0x22,0x11,0x17,0x17,0x88,0x15,0x36,0x85,0x15,0x74,0x47,0x16,0x62,0x55,0x36,0x55,0x83,0x63,0x02,0x50,0x28,0x55,0x76,0x87,0x53,0x27,0x13,0x71,0x03,0x72,0x37,0x05,0x71,0x47,0x61,0x71,0x36,0x51,0x84,0x12,0x42,0x36,0x64,0x44,0x66,0x41,0x43,0x52,0x05,0x21,0x08,0x51,0x57,0x03,0x33,0x63,0x86,0x02,0x58,0x42,0x66,0x28,0x14,0x81,0x10,0x54,0x62,0x68,0x17,0x30,0x38,0x75,0x64,0x33,0x21,0x65,0x88,0x56,0x86,0x63,0x63,0x28,0x13,0x40,0x62,0x54,0x01,0x20,0x40,0x88,0x65,0x47,0x88,0x61,0x71,0x65,0x76,0x23,0x72,0x62,0x34,0x86,0x70,0x30,0x11,0x51,0x15,0x63,0x20,0x50,0x75,0x35,0x02,0x12,0x21,0x08,0x42,0x65,0x31,0x43,0x55,0x67,0x11,0x15,0x25,0x72,0x01,0x06,0x85,0x36,0x30,0x15,0x05,0x57,0x58,0x60,0x58,0x78,0x43,0x14,0x31,0x32,0x78,0x78,0x80,0x87,0x38,0x47,0x88,0x63,0x78,0x81,0x81,0x38,0x73,0x42,0x61,0x78,0x38,0x85,0x24,0x66,0x77,0x33,0x50,0x60,0x21,0x15,0x14,0x64,0x23,0x82,0x32,0x68,0x01,0x35,0x44,0x07,0x83,0x47,0x53,0x85,0x53,0x57,0x52,0x83,0x23,0x35,0x18,0x76,0x01,0x15,0x21,0x34,0x32,0x57,0x73,0x33,0x36,0x55,0x18,0x86,0x15,0x81,0x61,0x68,0x24,0x18,0x42,0x21,0x22,0x30,0x84,0x14,0x48,0x15,0x12,0x01,0x10,0x30,0x24,0x77,0x72,0x42,0x54,0x43,0x66,0x06,0x77,0x17,0x70,0x76,0x03,0x01,0x45,0x25,0x40,0x35,0x00,0x18,0x38,0x73,0x23,0x77,0x35,0x26,0x50,0x86,0x35,0x71,0x13,0x73,0x44,0x81,0x60,0x52,0x77,0x45,0x65,0x53,0x73,0x00,0x85,0x83,0x77,0x85,0x03,0x51,0x21,0x11,0x54,0x80,0x62,0x88,0x50,0x18,0x02,0x68,0x13,0x86,0x52,0x05,0x34,0x68,0x01,0x32,0x07,0x24,0x18,0x03,0x21,0x30,0x05,0x72,0x38,0x64,0x07,0x64,0x27,0x11,0x41,0x01,0x83,0x85,0x25,0x51,0x06,0x32,0x60,0x71,0x04,0x86,0x51,0x76,0x83,0x38,0x28,0x57,0x27,0x62,0x35,0x45,0x18,0x73,0x50,0x83,0x13,0x28,0x86,0x37,0x66,0x61,0x42,0x63,0x11,0x67,0x50,0x33,0x11,0x25,0x53,0x76,0x41,0x76,0x03,0x14,0x33,0x17,0x72,0x12,0x23,0x44,0x18,0xa8,0x2e,0x4f,0x5c,0x9e,0xa0,0xfa,0xf9,0x9e,0xb0,0x4d,0x78,0xa7,0x33,0x27,0x11,0x11,0x7c,0x33,0xf1,0x8e,0xca,0x21,0xf8,0x74,0x33,0x76,0xad,0xa5,0x21,0x98,0x04,0xa7,0xed,0x9a,0x55,0x57,0xfc,0xd6,0x7a,0x35,0x50,0xb3,0xa4,0xb8,0xc5,0x88,0x62,0x9c,0x02,0x14,0x75,0xfa,0x3d,0x56,0xd5,0xd6,0xcf,0xbb,0x1a,0x09,0xbd,0xa8,0xd1,0x4d,0xe6,0x22,0xdd,0xff,0x16,0xd8,0xbc,0x99,0xb1,0x42,0x78,0xa8,0xaf,0x1d,0x76,0xbe,0xd1,0x57,0x67,0x2d,0xd9,0xc3,0x23,0x16,0xf9,0x7e,0x8d,0xaa,0xde,0xf8,0xd9,0xda,0x69,0x58,0x67,0x25,0x56,0x7f,0xb9,0x6b,0x59,0x99,0x0d,0x4b,0xf0,0xbc,0x9c,0x19,0x5b,0x90,0xb7,0x42,0x95,0xf5,0x67,0x5b,0x24,0x25,0x7c,0x27,0x10,0xc1,0x75,0xb0,0x15,0x3f,0x29,0x11,0x32,0x8c,0x2e,0xb7,0xab,0xb9,0xad,0x46,0xe7,0x0a,0x8b,0x53,0xc3,0x9e,0xa6,0x42,0xce,0xe4,0xb3,0xcb,0x42,0x62,0x0e,0x86,0x3c,0xe8,0xb6,0x50,0xce,0x8a,0xdc,0xd9,0x23,0x72,0x1a,0x16,0x87,0x02,0x3c,0x67,0x3a,0x8c,0xbb,0x6b,0x03,0xd5,0x1c,0xd1,0x97,0xe8,0xc3,0x46,0xeb,0xad,0xce,0x93,0x95,0x0f,0x88,0xce,0xe2,0x01,0xdb,0x9e,0x32,0x08,0x43,0xe2,0x9f,0x30,0x0d,0x9a,0x19,0x50,0x0d,0x70,0xa4,0xca,0xf2,0x72,0xc6,0x9e,0x4e,0xef,0x69,0xfb,0xb8,0xa5,0x5e,0xfd,0x7c,0xa2,0xbe,0xd9,0x90,0xd2,0xd3,0xb5,0x82,0x84,0x8f,0x9c,0x45,0xc2,0xab,0xc5,0x4c,0xfc,0x47,0xd3,0x4f,0x06,0xc0,0xff,0xa5,0x6f,0xcd,0x76,0x2a,0xb9,0xcb,0xa9,0x14,0x6d,0x77,0x25,0x21,0x89,0x63,0xb2,0x40,0xd7,0x2b,0x6d,0x22,0xc9,0x31,0x71,0xfb,0xd4,0x77,0x88,0xb7,0x6e,0x72,0x04,0x2d,0xef,0x08,0x78,0xd2,0x3d,0xf6,0x31,0xa1,0xa1,0xe5,0xa6,0x02,0x76,0x86,0xde,0x5b,0x4a,0x10,0xe9,0x10,0x69,0xc8,0xf2,0xba,0x02,0x59,0xb0,0x4d,0x64,0x09,0xda,0x96,0x56,0x7c,0xa5,0x2d,0xa4,0x97,0x02,0x6e,0x58,0x3a,0x0e,0xce,0xfc,0x1f,0x01,0xe6,0xb9,0x88,0xe2,0x1f,0x97,0x67,0xa2,0xb7,0xe1,0x67,0x2d,0xeb,0x9a,0x1e,0x2a,0x3f,0xcc,0x86,0x3a,0xa9,0x15,0x17,0xc3,0x34,0x62,0x06,0x01,0xb4,0xfe,0x79,0x73,0x0e,0x93,0x49,0x35,0xf4,0xb6,0xfb,0xc4,0xe3,0x26,0x95,0x14,0x5c,0x2b,0x5f,0x6a,0x12,0x7f,0xec,0xc0,0xa2,0x77,0x45,0x1e,0xbc,0x3f,0xd5,0x23,0x44,0x4f,0x9e,0xe7,0xc9,0xc3,0x45,0x34,0xf3,0x56,0xdb,0x54,0x4f,0xc3,0x1c,0x1b,0xfd,0xe5,0xf6,0x5c,0x77,0xea,0x2f,0x7c,0x2e,0xae,0x4c,0x55,0xeb,0xaf,0x10,0x42,0x71,0xc5,0x66,0xfd,0x4e,0xba,0xc7,0x1c,0x7a,0x62,0xc7,0x49,0x52,0x81,0x7a,0xe6,0x75,0x50,0x4d,0x95,0x99,0xb1,0xb7,0x62,0xb6,0xac,0xa1,0x68,0xa8,0x32,0x48,0xc9,0xd9,0xad,0xb0,0xce,0xb1,0x55,0x6e,0x57,0x59,0x49,0x0b,0xbc,0x0c,0x79,0x00,0x79,0x5a,0xd7,0x21,0x23,0x03,0x8b,0x66,0x2f,0x64,0xf1,0x06,0xa9,0x99,0x36,0x81,0xa2,0x5d,0x59,0xaf,0x7b,0xc9,0x7a,0x23,0x5b,0xe9,0x28,0x4c,0x5b,0xc4,0x5a,0x6c,0x90,0xcb,0x1c,0x29,0x99,0xc6,0x63,0xd9,0x6b,0x47,0x8e,0x23,0x07,0xf8,0x55,0x48,0x95,0x7d,0x65,0x74,0x0e,0x26,0x73,0xe9,0xeb,0xd1,0x35,0x28,0x29,0x03,0x8f,0x46,0x2b,0x8f,0xd3,0xb5,0x68,0x1d,0xa5,0x5c,0x02,0x52,0x52,0x38,0x53,0x52,0x5e,0xa0,0xad,0x64,0x7e,0x71,0xac,0x2c,0x5a,0x88,0x93,0xe6,0x03,0xac,0x97,0xe5,0x6c,0x04,0xce,0xb2,0xf2,0x6f,0x5c,0x5b,0x4b,0x6d,0x94,0xab,0x81,0x13,0x80,0xfd,0x00,0xf2,0x20,0x8f,0xe8,0x65,0x35,0x08,0x6a,0xeb,0xfd,0x35,0xc2,0x91,0x20,0x62,0x4c,0x04,0xfb,0xb6,0x11,0x39,0x29,0xd9,0xc5,0x56,0x35,0x02,0x53,0x76,0x6c,0x20,0x9f,0xdb,0xa8,0x3c,0x95,0xfc,0xcd,0x34,0x2a,0x28,0x09,0x93,0x55,0xd0,0x0b,0xc8,0x63,0xf4,0xee,0xf5,0x96,0xeb,0x0b,0x42,0xeb,0xcc,0x7c,0x79,0x49,0x1c,0xce,0xae,0x20,0x5e,0xa0,0xb8,0x05,0x9f,0xbb,0x8a,0x57,0x26,0xc5,0x94,0x9d,0x2b,0x15,0xe7,0xe2,0x9c,0x51,0xfc,0x9b,0x02,0xee,0x1a,0x4f,0xc3,0x57,0xb5,0xf1,0xbe,0xf9,0xc4,0xad,0xd4,0x6a,0x2a,0x92,0x0c,0x2f,0xbf,0x08,0xa3,0x7e,0xb1,0x51,0x4b,0xfa,0x15,0x11,0x0a,0x43,0x92,0xa7,0x4c,0x6f,0x13,0xc5,0x0c,0x5c,0xff,0xd9,0x75,0x31,0x09,0x8d,0x7c,0xd2,0x3b,0x60,0xeb,0x35,0xc4,0xa4,0x28,0xb4,0x6c,0x55,0x38,0x6e,0x10,0x10,0xc4,0xba,0x7f,0x70,0xe4,0xc7,0xec,0xb7,0x57,0x5f,0x30,0x63,0xa7,0x1e,0x84,0xdf,0xdc,0xf0,0x9a,0x58,0xb2,0xcd,0xb0,0xf9,0x9f,0x27,0xed,0x37,0x86,0x10,0xd2,0x5c,0xba,0xd7,0xbf,0xa6,0xba,0x0d,0x59,0x18,0x9c,0xfe,0x88,0xea,0xb9,0xb4,0x6d,0x7e,0x6d,0xb0,0x30,0x7e,0xab,0xe4,0x19,0x8e,0x99,0xbd,0x71,0xf7,0x79,0xab,0x66,0x58,0x1e,0x09,0x12,0xfc,0x7b,0x1d,0x25,0x85,0x24,0x5e,0x9a,0x12,0x68,0x7a,0x97,0x5c,0xd5,0xe8,0xe1,0xdc,0xc0,0x45,0xd5,0xf8,0x91,0xc4,0xc6,0x85,0xdb,0x07,0xcf,0x81,0xe7,0x73,0x89,0xb3,0x63,0xeb,0x6b,0xdf,0xe3,0x9b,0x27,0xff,0x84,0xc9,0x7e,0xef,0xee,0x16,0x2e,0x3b,0x45,0x1f,0xe6,0x91,0x47,0x19,0xcb,0x64,0x36,0xd8,0x55,0x96,0x0f,0xf9,0x15,0xd7,0xce,0xa6,0xad,0xea,0xfd,0xfc,0x1c,0x05,0x78,0x6c,0x49,0xf9,0x23,0xa4,0x74,0xff,0xdf,0xc3,0x15,0x3a,0x06,0xe6,0xed,0x0b,0x0a,0xd2,0x20,0xd7,0x25,0x24,0x43,0x4d,0x52,0x73,0xc0,0xaa,0xb6,0xdd,0xe4,0xe9,0x14,0x76,0xd5,0x81,0xa2,0x69,0x5a,0x60,0xde,0x6d,0x9f,0x44,0xd7,0x7a,0xa0,0x82,0x66,0xe9,0x38,0xee,0xb4,0xa9,0x59,0x7c,0x9b,0x64,0x98,0x60,0x59,0xe4,0x92,0x62,0xa4,0xea,0xb2,0x45,0x4e,0x14,0x01,0x5a,0xd0,0x53,0x6c,0x42,0x73,0x3a,0x5d,0x77,0xd7,0x99,0x5c,0x2a,0x20,0x44,0x60,0x09,0xeb,0xfe,0x56,0x32,0xc8,0x0c,0x08,0xed,0x2b,0x97,0xaf,0x35,0x06,0x64,0x89,0xf5,0x97,0xeb,0x1b,0x1f,0x11,0xf0,0x4f,0x60,0xe0,0xc9,0x04,0x01,0x59,0xc4,0x4a,0xb3,0xe6,0x0e,0x0a,0x15,0x22,0x9d,0x19,0x12,0x28,0xbe,0xd1,0x7b,0xbc,0x3a,0xc9,0x39,0xb3,0xc6,0x7c,0xee,0x13,0x5f,0x35,0x2c,0x27,0x21,0x6c,0x9c,0x31,0xf7,0x2a,0x3e,0x87,0x04,0x0c,0x5f,0x61,0x93,0x06,0xeb,0x0b,0x6c,0xca,0x2a,0x9c,0xe7,0xb2,0x2a,0x16,0x94,0xd0,0x0c,0xa9,0xc0,0x5e,0x31,0x51,0x26,0x45,0x7f,0x26,0xce,0x84,0xf9,0x61,0x72,0x41,0x86,0x07,0x82,0xf8,0x64,0xb4,0x73,0xd8,0x40,0x17,0x49,0x19,0x02,0xb1,0xbd,0xc8,0xcd,0xc5,0x80,0x0d,0xd4,0x61,0x27,0xfb,0x80,0xa7,0x1c,0x09,0x5b,0x47,0x3a,0x56,0x25,0x29,0xb3,0xb1,0xe7,0xe4,0x37,0xe1,0x58,0xa5,0xf6,0x66,0x6e,0x99,0x74,0xd0,0x05,0xb0,0x62,0xc2,0x30,0x9e,0x6d,0xce,0x98,0xf9,0xb6,0x58,0xc6,0xe3,0xf9,0xa2,0x16,0xd5,0x8c,0x8c,0x91,0x42,0xbd,0x1c,0x8c,0x85,0xa9,0xda,0x87,0x2e,0xbb,0xfa,0xd3,0xfe,0xa9,0xd9,0xab,0xa2,0xb6,0x8c,0x0e,0x8f,0x19,0xc6,0xff,0x5f,0x00,0x58,0x4d,0x45,0xda,0xf9,0xd6,0xc9,0xd6,0x9e,0xd0,0x4b,0x8d,0xa8,0xd6,0x87,0x25,0x8b,0x77,0x80,0x79,0x27,0x61,0x2c,0x53,0x04,0x46,0xfe,0xa7,0x69,0x7a,0xe3,0xf9,0x26,0x69,0x89,0x29,0xbc,0x6a,0x5a,0x8c,0xf3,0xe2,0x02,0x4c,0x0f,0x0c,0x5e,0xe5,0x7b,0x58,0x69,0xbf,0x98,0x18,0x81,0xca,0xf9,0xe3,0x66,0x5f,0xc7,0xf7,0xef,0xc6,0x78,0x92,0x9f,0x87,0xa5,0x6e,0xaa,0x42,0xea,0x4d,0x1f,0xf6,0x69,0x18,0x22,0xdd,0x79,0xa4,0x70,0x96,0xb7,0x76,0xd1,0xd8,0xf0,0x14,0x56,0xe5,0x87,0x3b,0x07,0x38,0x40,0x6c,0x38,0x2c,0x57,0x3a,0xe9,0xcd,0xe2,0xd9,0xe7,0xf2,0x31,0xb6,0xcc,0x5c,0x67,0x6e,0x7c,0xf4,0x39,0x63,0x37,0x30,0x13,0xa5,0x80,0x75,0x38,0x1f,0xf0,0x94,0x9b,0xe0,0x84,0x54,0x6d,0x72,0xe4,0xf8,0xa3,0xe5,0xfe,0x4a,0xa5,0x09,0x1a,0xdd,0x23,0x4e,0x2a,0xfe,0x00,0x30,0xb1,0xb6,0x63,0xae,0x9d,0x2d,0x32,0x41,0x09,0x86,0xb9,0x40,0x2a,0xaa,0xf2,0x46,0x5b,0x74,0xa5,0xe2,0xd0,0xbc,0x38,0xe3,0xa9,0x2b,0xbd,0xdd,0x8a,0x1f,0xed,0x7b,0x94,0x8c,0x23,0xcc,0xe6,0xf8,0xc0,0x8f,0xe3,0x56,0x83,0x5b,0xa6,0x5b,0x0f,0x98,0x40,0x68,0x61,0x6e,0xf4,0x81,0x38,0xef,0xd8,0x9b,0xf3,0x57,0xa5,0x4d,0x2e,0xbb,0xf3,0x76,0xcb,0xdc,0xc6,0x9c,0x5f,0x1f,0x61,0xc6,0x4d,0x27,0x94,0xbc,0x06,0xcc,0xb9,0xab,0xdf,0x66,0xe2,0x50,0x85,0xd8,0xc8,0x30,0xe2,0xae,0x3b,0x0f,0xe0,0xf0,0x7a,0x7a,0xf8,0xb9,0x32,0x0b,0xf3,0x42,0x97,0x09,0x97,0xd6,0x7d,0x7c,0x12,0x59,0x3a,0x8f,0xbf,0xad,0xe6,0x35,0xaa,0xc5,0x30,0x83,0xa7,0x02,0x2c,0x47,0xd5,0xf7,0x7a,0x52,0xb5,0x7b,0x59,0x8d,0xa9,0x39,0x2a,0xe6,0xd8,0x6a,0xfc,0x46,0xfc,0x06,0x45,0x51,0x81,0xb9,0xc7,0x5a,0x64,0x6d,0xc2,0x1f,0x81,0xe4,0xbf,0x21,0x37,0x53,0xde,0x73,0x7f,0xd2,0xa1,0x40,0x02,0x79,0x20,0xad,0xd3,0x5a,0x22,0x3f,0x9f,0x5f,0x44,0x65,0xce,0xb6,0x0c,0x03,0xed,0x04,0x55,0xa3,0x33,0xa5,0xcc,0x83,0xad,0xbf,0x43,0xf1,0xf4,0x2c,0x2c,0xcb,0x83,0x28,0xc2,0x1c,0x7a,0xb7,0xfa,0xed,0x2b,0x21,0xcf,0xad,0xe2,0xda,0x55,0x22,0x3a,0xaa,0xb2,0xaf,0x9b,0x41,0xc7,0x33,0x23,0x41,0x74,0x63,0x41,0xb3,0x9a,0xa2,0xf4,0x38,0x15,0x65,0x0f,0x54,0x80,0x51,0x14,0x24,0xcf,0xa6,0x90,0x17,0x79,0xc4,0xd1,0x8b,0x63,0x8c,0xc0,0x28,0x7a,0xaa,0xf3,0x16,0x80,0x33,0x8d,0x20,0xb1,0x7c,0x74,0x49,0xfd,0xc6,0xa2,0x78,0xa8,0xd9,0x6a,0x82,0xee,0x4c,0x4e,0xca,0x40,0x12,0x5e,0x2d,0x65,0x29,0x00,0x71,0xc7,0xae,0xf1,0xbe,0x6a,0x99,0x15,0x98,0xfb,0x9d,0x59,0x51,0x25,0x23,0xbc,0xd4,0xb3,0x8c,0x56,0x6b,0x8e,0x80,0xa7,0x3a,0xe3,0x33,0xe1,0x34,0x41,0x43,0x27,0xef,0x1d,0x83,0xc4,0x7c,0x49,0xdf,0xe7,0x93,0x6d,0xf1,0x33,0x8a,0x5e,0x24,0x77,0x87,0x86,0x8f,0xc8,0x4f,0xdc,0xb9,0x5a,0xc8,0x9c,0x18,0x5c,0x4b,0xb5,0xfd,0x57,0xb2,0x33,0x8a,0xc4,0x2b,0x41,0xc1,0x0a,0x82,0x3d,0xf3,0x96,0x24,0xf3,0x6b,0x15,0xa2,0xf0,0x67,0x58,0x4e,0x06,0xca,0x2e,0x08,0xcc,0xaf,0xf1,0x61,0x8f,0xe0,0x1d,0xd0,0x6d,0xf3,0x51,0x2e,0x0b,0x72,0x4d,0xec,0x85,0x06,0xda,0x24,0x21,0x5a,0xca,0xcc,0x2c,0x51,0xb8,0x2a,0xd8,0xd3,0x02,0x00,0x2f,0xb4,0x10,0x68,0xb1,0xda,0x4f,0x8b,0xb1,0x47,0x98,0x7b,0x35,0x16,0xba,0xd5,0xdb,0xdd,0xf0,0x13,0x18,0xfd,0x3f,0xa9,0xbc,0x43,0x70,0x2a,0xc4,0x98,0xc7,0x19,0xd9,0x5f,0x2e,0x84,0x1b,0x62,0x2a,0x5e,0x48,0x48,0xa3,0xc5,0xc2,0x62,0x95,0x99,0x92,0xea,0x7a,0x7d,0x72,0xca,0x8a,0x36,0x80,0x28,0xf4,0x97,0xdf,0xad,0x93,0x35,0x5c,0xbb,0x1b,0xb9,0x78,0x6d,0x14,0xff,0x2c,0xf5,0x90,0x31,0x78,0x48,0xf9,0x58,0x56,0x42,0x71,0x10,0xdd,0xa3,0x6f,0x51,0x92,0xa8,0x16,0xce,0x9c,0x88,0x16,0xcc,0x7b,0xbf,0xc8,0x04,0xef,0xc4,0x00,0x85,0xa3,0x85,0x0b,0x89,0xf1,0xe7,0xfe,0x56,0x56,0xdb,0xa4,0x10,0xf9,0x06,0xa9,0x7c,0x32,0x33,0x6c,0x1a,0xe7,0xe8,0x17,0x37,0xa8,0x3e,0x08,0x73,0x54,0xe4,0x28,0xda,0x85,0x38,0xd9,0x48,0xdb,0xf5,0xdf,0xac,0xb5,0x9d,0xd2,0xb5,0xfd,0x3b,0xc8,0x03,0xf4,0xba,0x43,0x2c,0x9a,0x73,0x9d,0xf2,0xcf,0xa9,0xed,0x94,0x84,0x32,0x0f,0x97,0xed,0xff,0x1a,0x48,0xc6,0xb8,0x6b,0x30,0x02,0xcf,0xb7,0x72,0xdd,0x5e,0x56,0x2b,0xc4,0xc3,0xd6,0x83,0xed,0x96,0x4b,0x61,0x99,0xfa,0x05,0x14,0xb0,0x79,0x0d,0x95,0x80,0x95,0xb7,0xb8,0x5c,0x6b,0xe8,0x75,0xfb,0xb5,0x59,0xe1,0x93,0x01,0x46,0xcc,0xea,0x63,0xa3,0x88,0xa1,0x94,0xfe,0x09,0xc3,0xde,0xa0,0x3b,0xe5,0x2d,0xe2,0x7e,0x90,0x10,0x17,0xaf,0xe8,0x09,0xaf,0x63,0x0a,0x73,0x82,0xbf,0x5c,0x4c,0xd4,0xd1,0xb8,0xf4,0x15,0x79,0xfb,0x43,0x48,0xed,0xe4,0xca,0x05,0xf4,0xcd,0x3f,0x13,0x9a,0x31,0xb2,0x54,0x4e,0x51,0x6d,0xbe,0x40,0x86,0xb9,0xbb,0x4b,0x2b,0xed,0x47,0xe2,0xd2,0x30,0x98,0x2d,0xd5,0x19,0x24,0x29,0xd3,0x77,0xb7,0xc0,0x74,0x5c,0xc0,0x68,0xe2,0xf5,0xa4,0xaa,0x04,0xc7,0xff,0x87,0x20,0x9e,0xd1,0x25,0x99,0x76,0xa0,0xfc,0x9b,0x25,0xe9,0xe8,0x51,0xd4,0xe3,0x50,0x2c,0x02,0xc8,0x5d,0x6d,0xff,0x02,0x9e,0x21,0x1d,0x01,0xeb,0xf0,0xe9,0xe7,0x18,0x8d,0x56,0x8f,0x84,0x37,0xd8,0x13,0xb0,0xf1,0x22,0xf2,0xfb,0x17,0x60,0x3b,0x69,0x3e,0xd9,0xc3,0x8f,0x17,0xcf,0xd5,0x0b,0x81,0x5e,0x6d,0x9d,0xfc,0x0e,0xd2,0xcc,0xf1,0x9f,0x63,0x99,0x27,0x4a,0x14,0x20,0xf2,0x35,0xa5,0x9d,0x8b,0xf7,0x24,0x34,0x5e,0x14,0xe4,0x5d,0x9e,0x4b,0xe8,0x93,0x4d,0xfc,0x3f,0xa9,0x26,0x78,0xdb,0x61,0xd7,0x11,0x8b,0xf5,0x3c,0xb8,0xa2,0x22,0x5b,0x33,0x5f,0x7e,0xae,0x50,0xe3,0xf9,0x41,0x23,0x76,0x28,0xdb,0x76,0xd8,0xea,0x38,0xf7,0x7a,0x72,0xaf,0x3a,0x26,0xc8,0x1f,0xe4,0x35,0x23,0xb3,0x35,0x53,0x5a,0x5d,0x1d,0xb7,0xc3,0x8f,0x34,0x10,0x82,0xbb,0x57,0x34,0xd0,0x89,0xe8,0xae,0x30,0x9c,0xfd,0xa3,0xa0,0xbc,0xb5,0xcd,0x5b,0x09,0x71,0x13,0xc8,0xed,0xf9,0x61,0x6a,0xa4,0xf6,0xe6,0x63,0x1b,0x91,0x25,0x27,0x6f,0xb3,0xf6,0x80,0xa3,0x43,0x41,0xc3,0xdb,0x66,0x8d,0xc6,0xca,0xd4,0x5f,0xc9,0x3b,0x27,0x08,0xca,0x2a,0xf7,0x5c,0xcc,0xe7,0x34,0xfd,0x19,0x1c,0x50,0x08,0x9d,0xad,0x53,0x98,0x2f,0xdd,0xae,0x02,0x53,0x1f,0xf9,0x3e,0x1f,0x21,0xff,0x39,0x5f,0xc0,0xa1,0x28,0x74,0xed,0xf0,0x6b,0x6f,0x96,0x47,0xe9,0x5a,0x73,0x24,0x58,0x6c,0x71,0xdf,0xd9,0x1d,0x90,0x1d,0x62,0x18,0x58,0x19,0x0f,0xec,0xd0,0x0c,0xcd,0x11,0x0b,0xba,0xc5,0x9f,0x96,0xcb,0x88,0x4c,0x3c,0x93,0x99,0x47,0x48,0xa5,0x6f,0x41,0x28,0x3b,0xfc,0x41,0xfb,0x89,0x05,0x21,0x53,0xa8,0x94,0x58,0x8c,0x3c,0xb9,0x01,0x7f,0x3d,0x66,0x32,0x6c,0x98,0x56,0x37,0xe5,0x75,0xac,0xb8,0x12,0x34,0x63,0x42,0x65,0x40,0x25,0xd6,0x02,0xde,0x3b,0xa9,0x40,0xc1,0x9a,0xc1,0xa6,0x33,0xdf,0xfd,0xa9,0x77,0xb5,0x29,0xb8,0x01,0x3e,0x19,0xc1,0xd6,0xd0,0x68,0x0f,0x4d,0xae,0x62,0xc9,0x24,0x45,0x0a,0xe6,0x6a,0xab,0x82,0xf2,0x14,0x73,0x06,0x1d,0xab,0x3d,0x62,0xb2,0x47,0xf9,0x07,0xe3,0x55,0x19,0x39,0xad,0x3f,0x54,0x65,0xe9,0xd0,0x8a,0x82,0xbf,0xea,0x17,0xee,0xa1,0xb6,0xb2,0xb9,0x23,0x75,0x74,0x77,0xf9,0x93,0x00,0x0b,0x2f,0x43,0xb7,0x0f,0x28,0xaa,0xab,0x1f,0xe9,0xa2,0x6a,0xd1,0xfd,0x33,0x61,0x61,0x6c,0x0b,0x0e,0x24,0x2f,0xe7,0x66,0x04,0xb7,0x03,0x3a,0x1f,0x30,0xe9,0x7e,0x28,0xf5,0x26,0xca,0x3c,0x88,0x0f,0xe2,0xb8,0xd9,0xd1,0xb0,0xc9,0xff,0x18,0x8b,0x31,0xcb,0x9d,0x97,0x42,0x5a,0xca,0xb9,0xb2,0x16,0xd9,0x8a,0x6a,0xe3,0x55,0xe5,0x83,0xda,0x71,0xe8,0x86,0x4e,0xe3,0xd1,0x6b,0x07,0x59,0x79,0x61,0x90,0xef,0x54,0x5c,0x1e,0x62,0xbf,0xef,0x92,0xaf,0x6c,0xa1,0x47,0xb1,0x32,0x44,0xd6,0xc8,0x92,0xfc,0x8e,0xf2,0x23,0xab,0x3f,0x43,0xf9,0x24,0xc2,0xf4,0x66,0x09,0x7e,0xe8]).unwrap(); + let sk = MLDSA65PrivateKey::from_bytes(&[ + 0x48, 0x68, 0x3D, 0x91, 0x97, 0x8E, 0x31, 0xEB, 0x3D, 0xDD, 0xB8, 0xB0, 0x47, 0x34, 0x82, + 0xD2, 0xB8, 0x8A, 0x5F, 0x62, 0x59, 0x49, 0xFD, 0x8F, 0x58, 0xA5, 0x61, 0xE6, 0x96, 0xBD, + 0x4C, 0x27, 0xD8, 0x53, 0xFA, 0x69, 0xB8, 0x19, 0x90, 0x23, 0xE8, 0xCD, 0x67, 0x8D, 0xD9, + 0xFA, 0xBF, 0x90, 0x47, 0x64, 0x6F, 0xFD, 0x0C, 0xB3, 0xCC, 0x7F, 0x79, 0x58, 0x05, 0xA7, + 0x1E, 0x70, 0xD2, 0x37, 0x1B, 0x05, 0x63, 0xE3, 0xCD, 0x33, 0x46, 0x14, 0x9C, 0x8C, 0x9E, + 0xBC, 0xF2, 0x3B, 0x0A, 0x4E, 0x5A, 0x90, 0x0E, 0xEA, 0x9C, 0x65, 0x62, 0x79, 0x0A, 0x7C, + 0x63, 0xE3, 0x86, 0x63, 0xDA, 0xA2, 0xDD, 0xDB, 0x6E, 0x48, 0x0D, 0xC4, 0x05, 0xA1, 0xE7, + 0x01, 0x94, 0x8B, 0x74, 0x84, 0x1E, 0xF5, 0xCC, 0x1C, 0x3F, 0x2B, 0xF3, 0x27, 0x97, 0x2E, + 0x95, 0x10, 0x51, 0x0C, 0xD5, 0x37, 0x5E, 0xCC, 0x08, 0x55, 0x71, 0x77, 0x11, 0x87, 0x22, + 0x21, 0x86, 0x23, 0x81, 0x00, 0x04, 0x24, 0x77, 0x80, 0x61, 0x47, 0x50, 0x07, 0x50, 0x17, + 0x17, 0x03, 0x55, 0x04, 0x51, 0x51, 0x25, 0x47, 0x18, 0x38, 0x04, 0x61, 0x75, 0x72, 0x22, + 0x44, 0x10, 0x88, 0x68, 0x60, 0x86, 0x46, 0x01, 0x27, 0x47, 0x56, 0x71, 0x80, 0x87, 0x06, + 0x66, 0x86, 0x43, 0x32, 0x44, 0x41, 0x22, 0x04, 0x36, 0x38, 0x66, 0x75, 0x02, 0x82, 0x36, + 0x34, 0x24, 0x43, 0x22, 0x05, 0x73, 0x64, 0x10, 0x64, 0x55, 0x54, 0x77, 0x22, 0x75, 0x56, + 0x81, 0x43, 0x36, 0x14, 0x62, 0x55, 0x08, 0x20, 0x64, 0x37, 0x68, 0x54, 0x68, 0x75, 0x43, + 0x53, 0x75, 0x10, 0x68, 0x71, 0x83, 0x33, 0x80, 0x54, 0x75, 0x05, 0x25, 0x80, 0x75, 0x28, + 0x18, 0x84, 0x38, 0x11, 0x08, 0x72, 0x60, 0x20, 0x20, 0x08, 0x58, 0x83, 0x01, 0x83, 0x61, + 0x13, 0x82, 0x82, 0x12, 0x06, 0x17, 0x11, 0x57, 0x87, 0x68, 0x78, 0x88, 0x78, 0x64, 0x37, + 0x54, 0x60, 0x16, 0x57, 0x15, 0x50, 0x84, 0x71, 0x88, 0x66, 0x07, 0x27, 0x32, 0x88, 0x06, + 0x64, 0x74, 0x18, 0x56, 0x76, 0x21, 0x80, 0x31, 0x82, 0x76, 0x64, 0x15, 0x78, 0x24, 0x50, + 0x25, 0x64, 0x66, 0x43, 0x11, 0x35, 0x04, 0x36, 0x47, 0x80, 0x12, 0x66, 0x73, 0x14, 0x30, + 0x11, 0x66, 0x06, 0x55, 0x86, 0x47, 0x18, 0x36, 0x88, 0x63, 0x50, 0x38, 0x47, 0x86, 0x11, + 0x01, 0x20, 0x23, 0x56, 0x11, 0x61, 0x37, 0x86, 0x07, 0x85, 0x32, 0x12, 0x40, 0x07, 0x54, + 0x78, 0x82, 0x30, 0x43, 0x66, 0x61, 0x16, 0x60, 0x42, 0x55, 0x41, 0x82, 0x85, 0x60, 0x53, + 0x67, 0x78, 0x56, 0x38, 0x43, 0x44, 0x30, 0x63, 0x26, 0x10, 0x77, 0x07, 0x31, 0x78, 0x42, + 0x72, 0x14, 0x11, 0x16, 0x53, 0x03, 0x85, 0x27, 0x68, 0x67, 0x46, 0x01, 0x50, 0x82, 0x37, + 0x35, 0x32, 0x07, 0x66, 0x10, 0x75, 0x04, 0x68, 0x12, 0x48, 0x06, 0x66, 0x03, 0x03, 0x26, + 0x52, 0x31, 0x24, 0x45, 0x40, 0x88, 0x00, 0x31, 0x80, 0x88, 0x76, 0x72, 0x17, 0x30, 0x71, + 0x82, 0x47, 0x21, 0x51, 0x27, 0x80, 0x11, 0x65, 0x44, 0x74, 0x86, 0x61, 0x72, 0x23, 0x33, + 0x80, 0x86, 0x60, 0x64, 0x46, 0x83, 0x52, 0x15, 0x84, 0x20, 0x36, 0x80, 0x11, 0x80, 0x21, + 0x18, 0x18, 0x33, 0x17, 0x73, 0x54, 0x53, 0x48, 0x81, 0x00, 0x44, 0x86, 0x53, 0x67, 0x43, + 0x70, 0x57, 0x72, 0x58, 0x83, 0x34, 0x60, 0x38, 0x42, 0x32, 0x85, 0x68, 0x10, 0x06, 0x04, + 0x26, 0x04, 0x25, 0x84, 0x56, 0x02, 0x35, 0x68, 0x20, 0x51, 0x83, 0x86, 0x38, 0x43, 0x24, + 0x21, 0x22, 0x42, 0x45, 0x64, 0x58, 0x58, 0x67, 0x71, 0x45, 0x72, 0x85, 0x04, 0x78, 0x87, + 0x17, 0x18, 0x06, 0x18, 0x83, 0x60, 0x86, 0x86, 0x41, 0x56, 0x50, 0x81, 0x16, 0x50, 0x26, + 0x46, 0x70, 0x06, 0x08, 0x26, 0x62, 0x27, 0x38, 0x31, 0x72, 0x40, 0x72, 0x57, 0x30, 0x07, + 0x27, 0x28, 0x86, 0x20, 0x66, 0x75, 0x88, 0x68, 0x26, 0x07, 0x06, 0x40, 0x20, 0x33, 0x03, + 0x43, 0x66, 0x31, 0x55, 0x46, 0x42, 0x45, 0x34, 0x56, 0x67, 0x18, 0x73, 0x45, 0x65, 0x83, + 0x70, 0x22, 0x50, 0x84, 0x68, 0x56, 0x28, 0x80, 0x70, 0x36, 0x70, 0x84, 0x62, 0x37, 0x17, + 0x10, 0x06, 0x57, 0x17, 0x58, 0x47, 0x78, 0x70, 0x86, 0x55, 0x53, 0x78, 0x22, 0x35, 0x14, + 0x46, 0x77, 0x28, 0x56, 0x73, 0x03, 0x22, 0x87, 0x00, 0x14, 0x33, 0x20, 0x61, 0x71, 0x58, + 0x45, 0x52, 0x66, 0x32, 0x50, 0x26, 0x51, 0x33, 0x47, 0x77, 0x38, 0x03, 0x55, 0x16, 0x43, + 0x13, 0x47, 0x35, 0x10, 0x66, 0x27, 0x51, 0x75, 0x74, 0x02, 0x46, 0x88, 0x81, 0x70, 0x67, + 0x43, 0x46, 0x81, 0x86, 0x01, 0x76, 0x52, 0x45, 0x33, 0x30, 0x87, 0x21, 0x04, 0x34, 0x34, + 0x01, 0x03, 0x22, 0x87, 0x63, 0x51, 0x55, 0x26, 0x50, 0x81, 0x30, 0x77, 0x45, 0x44, 0x41, + 0x68, 0x15, 0x41, 0x83, 0x63, 0x64, 0x11, 0x20, 0x40, 0x26, 0x87, 0x30, 0x43, 0x67, 0x77, + 0x12, 0x80, 0x88, 0x46, 0x35, 0x54, 0x53, 0x00, 0x62, 0x45, 0x81, 0x04, 0x58, 0x36, 0x51, + 0x24, 0x84, 0x27, 0x80, 0x34, 0x51, 0x66, 0x63, 0x58, 0x43, 0x78, 0x56, 0x01, 0x46, 0x51, + 0x15, 0x74, 0x23, 0x21, 0x43, 0x66, 0x85, 0x22, 0x47, 0x77, 0x31, 0x34, 0x50, 0x17, 0x83, + 0x62, 0x42, 0x05, 0x50, 0x00, 0x64, 0x84, 0x47, 0x12, 0x34, 0x40, 0x88, 0x00, 0x60, 0x47, + 0x35, 0x40, 0x57, 0x83, 0x33, 0x63, 0x08, 0x21, 0x06, 0x15, 0x22, 0x52, 0x07, 0x24, 0x88, + 0x51, 0x34, 0x86, 0x37, 0x06, 0x76, 0x22, 0x58, 0x85, 0x71, 0x26, 0x56, 0x73, 0x47, 0x68, + 0x16, 0x46, 0x46, 0x84, 0x25, 0x87, 0x08, 0x12, 0x27, 0x05, 0x50, 0x08, 0x38, 0x32, 0x00, + 0x23, 0x20, 0x80, 0x66, 0x34, 0x53, 0x36, 0x00, 0x33, 0x46, 0x85, 0x72, 0x47, 0x06, 0x35, + 0x54, 0x00, 0x35, 0x77, 0x12, 0x27, 0x52, 0x30, 0x71, 0x42, 0x53, 0x68, 0x74, 0x37, 0x45, + 0x70, 0x05, 0x66, 0x43, 0x22, 0x44, 0x82, 0x85, 0x20, 0x72, 0x18, 0x33, 0x30, 0x20, 0x53, + 0x37, 0x33, 0x40, 0x77, 0x27, 0x80, 0x55, 0x25, 0x30, 0x63, 0x52, 0x50, 0x40, 0x67, 0x33, + 0x46, 0x13, 0x18, 0x07, 0x28, 0x07, 0x17, 0x24, 0x83, 0x77, 0x63, 0x45, 0x73, 0x18, 0x58, + 0x51, 0x60, 0x23, 0x33, 0x44, 0x36, 0x25, 0x16, 0x43, 0x38, 0x16, 0x08, 0x58, 0x77, 0x34, + 0x62, 0x42, 0x88, 0x30, 0x07, 0x03, 0x65, 0x85, 0x37, 0x55, 0x00, 0x75, 0x52, 0x31, 0x50, + 0x37, 0x02, 0x13, 0x24, 0x63, 0x04, 0x37, 0x08, 0x68, 0x06, 0x36, 0x15, 0x03, 0x03, 0x00, + 0x43, 0x58, 0x63, 0x57, 0x08, 0x02, 0x11, 0x06, 0x64, 0x73, 0x46, 0x35, 0x22, 0x62, 0x03, + 0x30, 0x43, 0x80, 0x21, 0x08, 0x52, 0x87, 0x57, 0x83, 0x21, 0x07, 0x88, 0x67, 0x48, 0x08, + 0x56, 0x34, 0x74, 0x36, 0x73, 0x42, 0x84, 0x05, 0x84, 0x66, 0x84, 0x14, 0x37, 0x00, 0x55, + 0x10, 0x87, 0x34, 0x26, 0x44, 0x77, 0x21, 0x12, 0x73, 0x84, 0x73, 0x65, 0x26, 0x47, 0x25, + 0x77, 0x14, 0x47, 0x04, 0x17, 0x86, 0x44, 0x26, 0x02, 0x47, 0x11, 0x87, 0x40, 0x81, 0x22, + 0x16, 0x60, 0x58, 0x47, 0x17, 0x81, 0x37, 0x06, 0x76, 0x80, 0x81, 0x70, 0x58, 0x18, 0x55, + 0x85, 0x47, 0x13, 0x63, 0x42, 0x10, 0x75, 0x58, 0x01, 0x63, 0x58, 0x35, 0x85, 0x18, 0x44, + 0x03, 0x84, 0x71, 0x10, 0x33, 0x87, 0x42, 0x62, 0x82, 0x47, 0x74, 0x13, 0x65, 0x54, 0x42, + 0x70, 0x73, 0x46, 0x35, 0x77, 0x75, 0x00, 0x66, 0x25, 0x62, 0x68, 0x42, 0x02, 0x12, 0x46, + 0x83, 0x86, 0x46, 0x16, 0x64, 0x60, 0x31, 0x22, 0x53, 0x88, 0x84, 0x54, 0x00, 0x84, 0x57, + 0x34, 0x46, 0x47, 0x54, 0x47, 0x25, 0x60, 0x54, 0x61, 0x66, 0x84, 0x66, 0x30, 0x88, 0x06, + 0x38, 0x27, 0x15, 0x63, 0x28, 0x71, 0x83, 0x84, 0x06, 0x52, 0x24, 0x76, 0x81, 0x16, 0x06, + 0x62, 0x13, 0x03, 0x30, 0x18, 0x68, 0x02, 0x80, 0x13, 0x84, 0x63, 0x05, 0x05, 0x65, 0x72, + 0x38, 0x75, 0x83, 0x65, 0x72, 0x32, 0x30, 0x68, 0x80, 0x46, 0x12, 0x26, 0x06, 0x65, 0x16, + 0x75, 0x57, 0x05, 0x32, 0x41, 0x32, 0x27, 0x67, 0x35, 0x17, 0x08, 0x01, 0x53, 0x00, 0x16, + 0x28, 0x46, 0x01, 0x34, 0x88, 0x77, 0x01, 0x11, 0x88, 0x15, 0x57, 0x13, 0x15, 0x46, 0x43, + 0x11, 0x70, 0x47, 0x32, 0x88, 0x28, 0x56, 0x36, 0x82, 0x34, 0x55, 0x50, 0x41, 0x86, 0x27, + 0x65, 0x63, 0x11, 0x11, 0x68, 0x75, 0x05, 0x10, 0x42, 0x54, 0x41, 0x44, 0x27, 0x85, 0x22, + 0x11, 0x17, 0x17, 0x88, 0x15, 0x36, 0x85, 0x15, 0x74, 0x47, 0x16, 0x62, 0x55, 0x36, 0x55, + 0x83, 0x63, 0x02, 0x50, 0x28, 0x55, 0x76, 0x87, 0x53, 0x27, 0x13, 0x71, 0x03, 0x72, 0x37, + 0x05, 0x71, 0x47, 0x61, 0x71, 0x36, 0x51, 0x84, 0x12, 0x42, 0x36, 0x64, 0x44, 0x66, 0x41, + 0x43, 0x52, 0x05, 0x21, 0x08, 0x51, 0x57, 0x03, 0x33, 0x63, 0x86, 0x02, 0x58, 0x42, 0x66, + 0x28, 0x14, 0x81, 0x10, 0x54, 0x62, 0x68, 0x17, 0x30, 0x38, 0x75, 0x64, 0x33, 0x21, 0x65, + 0x88, 0x56, 0x86, 0x63, 0x63, 0x28, 0x13, 0x40, 0x62, 0x54, 0x01, 0x20, 0x40, 0x88, 0x65, + 0x47, 0x88, 0x61, 0x71, 0x65, 0x76, 0x23, 0x72, 0x62, 0x34, 0x86, 0x70, 0x30, 0x11, 0x51, + 0x15, 0x63, 0x20, 0x50, 0x75, 0x35, 0x02, 0x12, 0x21, 0x08, 0x42, 0x65, 0x31, 0x43, 0x55, + 0x67, 0x11, 0x15, 0x25, 0x72, 0x01, 0x06, 0x85, 0x36, 0x30, 0x15, 0x05, 0x57, 0x58, 0x60, + 0x58, 0x78, 0x43, 0x14, 0x31, 0x32, 0x78, 0x78, 0x80, 0x87, 0x38, 0x47, 0x88, 0x63, 0x78, + 0x81, 0x81, 0x38, 0x73, 0x42, 0x61, 0x78, 0x38, 0x85, 0x24, 0x66, 0x77, 0x33, 0x50, 0x60, + 0x21, 0x15, 0x14, 0x64, 0x23, 0x82, 0x32, 0x68, 0x01, 0x35, 0x44, 0x07, 0x83, 0x47, 0x53, + 0x85, 0x53, 0x57, 0x52, 0x83, 0x23, 0x35, 0x18, 0x76, 0x01, 0x15, 0x21, 0x34, 0x32, 0x57, + 0x73, 0x33, 0x36, 0x55, 0x18, 0x86, 0x15, 0x81, 0x61, 0x68, 0x24, 0x18, 0x42, 0x21, 0x22, + 0x30, 0x84, 0x14, 0x48, 0x15, 0x12, 0x01, 0x10, 0x30, 0x24, 0x77, 0x72, 0x42, 0x54, 0x43, + 0x66, 0x06, 0x77, 0x17, 0x70, 0x76, 0x03, 0x01, 0x45, 0x25, 0x40, 0x35, 0x00, 0x18, 0x38, + 0x73, 0x23, 0x77, 0x35, 0x26, 0x50, 0x86, 0x35, 0x71, 0x13, 0x73, 0x44, 0x81, 0x60, 0x52, + 0x77, 0x45, 0x65, 0x53, 0x73, 0x00, 0x85, 0x83, 0x77, 0x85, 0x03, 0x51, 0x21, 0x11, 0x54, + 0x80, 0x62, 0x88, 0x50, 0x18, 0x02, 0x68, 0x13, 0x86, 0x52, 0x05, 0x34, 0x68, 0x01, 0x32, + 0x07, 0x24, 0x18, 0x03, 0x21, 0x30, 0x05, 0x72, 0x38, 0x64, 0x07, 0x64, 0x27, 0x11, 0x41, + 0x01, 0x83, 0x85, 0x25, 0x51, 0x06, 0x32, 0x60, 0x71, 0x04, 0x86, 0x51, 0x76, 0x83, 0x38, + 0x28, 0x57, 0x27, 0x62, 0x35, 0x45, 0x18, 0x73, 0x50, 0x83, 0x13, 0x28, 0x86, 0x37, 0x66, + 0x61, 0x42, 0x63, 0x11, 0x67, 0x50, 0x33, 0x11, 0x25, 0x53, 0x76, 0x41, 0x76, 0x03, 0x14, + 0x33, 0x17, 0x72, 0x12, 0x23, 0x44, 0x18, 0xA8, 0x2E, 0x4F, 0x5C, 0x9E, 0xA0, 0xFA, 0xF9, + 0x9E, 0xB0, 0x4D, 0x78, 0xA7, 0x33, 0x27, 0x11, 0x11, 0x7C, 0x33, 0xF1, 0x8E, 0xCA, 0x21, + 0xF8, 0x74, 0x33, 0x76, 0xAD, 0xA5, 0x21, 0x98, 0x04, 0xA7, 0xED, 0x9A, 0x55, 0x57, 0xFC, + 0xD6, 0x7A, 0x35, 0x50, 0xB3, 0xA4, 0xB8, 0xC5, 0x88, 0x62, 0x9C, 0x02, 0x14, 0x75, 0xFA, + 0x3D, 0x56, 0xD5, 0xD6, 0xCF, 0xBB, 0x1A, 0x09, 0xBD, 0xA8, 0xD1, 0x4D, 0xE6, 0x22, 0xDD, + 0xFF, 0x16, 0xD8, 0xBC, 0x99, 0xB1, 0x42, 0x78, 0xA8, 0xAF, 0x1D, 0x76, 0xBE, 0xD1, 0x57, + 0x67, 0x2D, 0xD9, 0xC3, 0x23, 0x16, 0xF9, 0x7E, 0x8D, 0xAA, 0xDE, 0xF8, 0xD9, 0xDA, 0x69, + 0x58, 0x67, 0x25, 0x56, 0x7F, 0xB9, 0x6B, 0x59, 0x99, 0x0D, 0x4B, 0xF0, 0xBC, 0x9C, 0x19, + 0x5B, 0x90, 0xB7, 0x42, 0x95, 0xF5, 0x67, 0x5B, 0x24, 0x25, 0x7C, 0x27, 0x10, 0xC1, 0x75, + 0xB0, 0x15, 0x3F, 0x29, 0x11, 0x32, 0x8C, 0x2E, 0xB7, 0xAB, 0xB9, 0xAD, 0x46, 0xE7, 0x0A, + 0x8B, 0x53, 0xC3, 0x9E, 0xA6, 0x42, 0xCE, 0xE4, 0xB3, 0xCB, 0x42, 0x62, 0x0E, 0x86, 0x3C, + 0xE8, 0xB6, 0x50, 0xCE, 0x8A, 0xDC, 0xD9, 0x23, 0x72, 0x1A, 0x16, 0x87, 0x02, 0x3C, 0x67, + 0x3A, 0x8C, 0xBB, 0x6B, 0x03, 0xD5, 0x1C, 0xD1, 0x97, 0xE8, 0xC3, 0x46, 0xEB, 0xAD, 0xCE, + 0x93, 0x95, 0x0F, 0x88, 0xCE, 0xE2, 0x01, 0xDB, 0x9E, 0x32, 0x08, 0x43, 0xE2, 0x9F, 0x30, + 0x0D, 0x9A, 0x19, 0x50, 0x0D, 0x70, 0xA4, 0xCA, 0xF2, 0x72, 0xC6, 0x9E, 0x4E, 0xEF, 0x69, + 0xFB, 0xB8, 0xA5, 0x5E, 0xFD, 0x7C, 0xA2, 0xBE, 0xD9, 0x90, 0xD2, 0xD3, 0xB5, 0x82, 0x84, + 0x8F, 0x9C, 0x45, 0xC2, 0xAB, 0xC5, 0x4C, 0xFC, 0x47, 0xD3, 0x4F, 0x06, 0xC0, 0xFF, 0xA5, + 0x6F, 0xCD, 0x76, 0x2A, 0xB9, 0xCB, 0xA9, 0x14, 0x6D, 0x77, 0x25, 0x21, 0x89, 0x63, 0xB2, + 0x40, 0xD7, 0x2B, 0x6D, 0x22, 0xC9, 0x31, 0x71, 0xFB, 0xD4, 0x77, 0x88, 0xB7, 0x6E, 0x72, + 0x04, 0x2D, 0xEF, 0x08, 0x78, 0xD2, 0x3D, 0xF6, 0x31, 0xA1, 0xA1, 0xE5, 0xA6, 0x02, 0x76, + 0x86, 0xDE, 0x5B, 0x4A, 0x10, 0xE9, 0x10, 0x69, 0xC8, 0xF2, 0xBA, 0x02, 0x59, 0xB0, 0x4D, + 0x64, 0x09, 0xDA, 0x96, 0x56, 0x7C, 0xA5, 0x2D, 0xA4, 0x97, 0x02, 0x6E, 0x58, 0x3A, 0x0E, + 0xCE, 0xFC, 0x1F, 0x01, 0xE6, 0xB9, 0x88, 0xE2, 0x1F, 0x97, 0x67, 0xA2, 0xB7, 0xE1, 0x67, + 0x2D, 0xEB, 0x9A, 0x1E, 0x2A, 0x3F, 0xCC, 0x86, 0x3A, 0xA9, 0x15, 0x17, 0xC3, 0x34, 0x62, + 0x06, 0x01, 0xB4, 0xFE, 0x79, 0x73, 0x0E, 0x93, 0x49, 0x35, 0xF4, 0xB6, 0xFB, 0xC4, 0xE3, + 0x26, 0x95, 0x14, 0x5C, 0x2B, 0x5F, 0x6A, 0x12, 0x7F, 0xEC, 0xC0, 0xA2, 0x77, 0x45, 0x1E, + 0xBC, 0x3F, 0xD5, 0x23, 0x44, 0x4F, 0x9E, 0xE7, 0xC9, 0xC3, 0x45, 0x34, 0xF3, 0x56, 0xDB, + 0x54, 0x4F, 0xC3, 0x1C, 0x1B, 0xFD, 0xE5, 0xF6, 0x5C, 0x77, 0xEA, 0x2F, 0x7C, 0x2E, 0xAE, + 0x4C, 0x55, 0xEB, 0xAF, 0x10, 0x42, 0x71, 0xC5, 0x66, 0xFD, 0x4E, 0xBA, 0xC7, 0x1C, 0x7A, + 0x62, 0xC7, 0x49, 0x52, 0x81, 0x7A, 0xE6, 0x75, 0x50, 0x4D, 0x95, 0x99, 0xB1, 0xB7, 0x62, + 0xB6, 0xAC, 0xA1, 0x68, 0xA8, 0x32, 0x48, 0xC9, 0xD9, 0xAD, 0xB0, 0xCE, 0xB1, 0x55, 0x6E, + 0x57, 0x59, 0x49, 0x0B, 0xBC, 0x0C, 0x79, 0x00, 0x79, 0x5A, 0xD7, 0x21, 0x23, 0x03, 0x8B, + 0x66, 0x2F, 0x64, 0xF1, 0x06, 0xA9, 0x99, 0x36, 0x81, 0xA2, 0x5D, 0x59, 0xAF, 0x7B, 0xC9, + 0x7A, 0x23, 0x5B, 0xE9, 0x28, 0x4C, 0x5B, 0xC4, 0x5A, 0x6C, 0x90, 0xCB, 0x1C, 0x29, 0x99, + 0xC6, 0x63, 0xD9, 0x6B, 0x47, 0x8E, 0x23, 0x07, 0xF8, 0x55, 0x48, 0x95, 0x7D, 0x65, 0x74, + 0x0E, 0x26, 0x73, 0xE9, 0xEB, 0xD1, 0x35, 0x28, 0x29, 0x03, 0x8F, 0x46, 0x2B, 0x8F, 0xD3, + 0xB5, 0x68, 0x1D, 0xA5, 0x5C, 0x02, 0x52, 0x52, 0x38, 0x53, 0x52, 0x5E, 0xA0, 0xAD, 0x64, + 0x7E, 0x71, 0xAC, 0x2C, 0x5A, 0x88, 0x93, 0xE6, 0x03, 0xAC, 0x97, 0xE5, 0x6C, 0x04, 0xCE, + 0xB2, 0xF2, 0x6F, 0x5C, 0x5B, 0x4B, 0x6D, 0x94, 0xAB, 0x81, 0x13, 0x80, 0xFD, 0x00, 0xF2, + 0x20, 0x8F, 0xE8, 0x65, 0x35, 0x08, 0x6A, 0xEB, 0xFD, 0x35, 0xC2, 0x91, 0x20, 0x62, 0x4C, + 0x04, 0xFB, 0xB6, 0x11, 0x39, 0x29, 0xD9, 0xC5, 0x56, 0x35, 0x02, 0x53, 0x76, 0x6C, 0x20, + 0x9F, 0xDB, 0xA8, 0x3C, 0x95, 0xFC, 0xCD, 0x34, 0x2A, 0x28, 0x09, 0x93, 0x55, 0xD0, 0x0B, + 0xC8, 0x63, 0xF4, 0xEE, 0xF5, 0x96, 0xEB, 0x0B, 0x42, 0xEB, 0xCC, 0x7C, 0x79, 0x49, 0x1C, + 0xCE, 0xAE, 0x20, 0x5E, 0xA0, 0xB8, 0x05, 0x9F, 0xBB, 0x8A, 0x57, 0x26, 0xC5, 0x94, 0x9D, + 0x2B, 0x15, 0xE7, 0xE2, 0x9C, 0x51, 0xFC, 0x9B, 0x02, 0xEE, 0x1A, 0x4F, 0xC3, 0x57, 0xB5, + 0xF1, 0xBE, 0xF9, 0xC4, 0xAD, 0xD4, 0x6A, 0x2A, 0x92, 0x0C, 0x2F, 0xBF, 0x08, 0xA3, 0x7E, + 0xB1, 0x51, 0x4B, 0xFA, 0x15, 0x11, 0x0A, 0x43, 0x92, 0xA7, 0x4C, 0x6F, 0x13, 0xC5, 0x0C, + 0x5C, 0xFF, 0xD9, 0x75, 0x31, 0x09, 0x8D, 0x7C, 0xD2, 0x3B, 0x60, 0xEB, 0x35, 0xC4, 0xA4, + 0x28, 0xB4, 0x6C, 0x55, 0x38, 0x6E, 0x10, 0x10, 0xC4, 0xBA, 0x7F, 0x70, 0xE4, 0xC7, 0xEC, + 0xB7, 0x57, 0x5F, 0x30, 0x63, 0xA7, 0x1E, 0x84, 0xDF, 0xDC, 0xF0, 0x9A, 0x58, 0xB2, 0xCD, + 0xB0, 0xF9, 0x9F, 0x27, 0xED, 0x37, 0x86, 0x10, 0xD2, 0x5C, 0xBA, 0xD7, 0xBF, 0xA6, 0xBA, + 0x0D, 0x59, 0x18, 0x9C, 0xFE, 0x88, 0xEA, 0xB9, 0xB4, 0x6D, 0x7E, 0x6D, 0xB0, 0x30, 0x7E, + 0xAB, 0xE4, 0x19, 0x8E, 0x99, 0xBD, 0x71, 0xF7, 0x79, 0xAB, 0x66, 0x58, 0x1E, 0x09, 0x12, + 0xFC, 0x7B, 0x1D, 0x25, 0x85, 0x24, 0x5E, 0x9A, 0x12, 0x68, 0x7A, 0x97, 0x5C, 0xD5, 0xE8, + 0xE1, 0xDC, 0xC0, 0x45, 0xD5, 0xF8, 0x91, 0xC4, 0xC6, 0x85, 0xDB, 0x07, 0xCF, 0x81, 0xE7, + 0x73, 0x89, 0xB3, 0x63, 0xEB, 0x6B, 0xDF, 0xE3, 0x9B, 0x27, 0xFF, 0x84, 0xC9, 0x7E, 0xEF, + 0xEE, 0x16, 0x2E, 0x3B, 0x45, 0x1F, 0xE6, 0x91, 0x47, 0x19, 0xCB, 0x64, 0x36, 0xD8, 0x55, + 0x96, 0x0F, 0xF9, 0x15, 0xD7, 0xCE, 0xA6, 0xAD, 0xEA, 0xFD, 0xFC, 0x1C, 0x05, 0x78, 0x6C, + 0x49, 0xF9, 0x23, 0xA4, 0x74, 0xFF, 0xDF, 0xC3, 0x15, 0x3A, 0x06, 0xE6, 0xED, 0x0B, 0x0A, + 0xD2, 0x20, 0xD7, 0x25, 0x24, 0x43, 0x4D, 0x52, 0x73, 0xC0, 0xAA, 0xB6, 0xDD, 0xE4, 0xE9, + 0x14, 0x76, 0xD5, 0x81, 0xA2, 0x69, 0x5A, 0x60, 0xDE, 0x6D, 0x9F, 0x44, 0xD7, 0x7A, 0xA0, + 0x82, 0x66, 0xE9, 0x38, 0xEE, 0xB4, 0xA9, 0x59, 0x7C, 0x9B, 0x64, 0x98, 0x60, 0x59, 0xE4, + 0x92, 0x62, 0xA4, 0xEA, 0xB2, 0x45, 0x4E, 0x14, 0x01, 0x5A, 0xD0, 0x53, 0x6C, 0x42, 0x73, + 0x3A, 0x5D, 0x77, 0xD7, 0x99, 0x5C, 0x2A, 0x20, 0x44, 0x60, 0x09, 0xEB, 0xFE, 0x56, 0x32, + 0xC8, 0x0C, 0x08, 0xED, 0x2B, 0x97, 0xAF, 0x35, 0x06, 0x64, 0x89, 0xF5, 0x97, 0xEB, 0x1B, + 0x1F, 0x11, 0xF0, 0x4F, 0x60, 0xE0, 0xC9, 0x04, 0x01, 0x59, 0xC4, 0x4A, 0xB3, 0xE6, 0x0E, + 0x0A, 0x15, 0x22, 0x9D, 0x19, 0x12, 0x28, 0xBE, 0xD1, 0x7B, 0xBC, 0x3A, 0xC9, 0x39, 0xB3, + 0xC6, 0x7C, 0xEE, 0x13, 0x5F, 0x35, 0x2C, 0x27, 0x21, 0x6C, 0x9C, 0x31, 0xF7, 0x2A, 0x3E, + 0x87, 0x04, 0x0C, 0x5F, 0x61, 0x93, 0x06, 0xEB, 0x0B, 0x6C, 0xCA, 0x2A, 0x9C, 0xE7, 0xB2, + 0x2A, 0x16, 0x94, 0xD0, 0x0C, 0xA9, 0xC0, 0x5E, 0x31, 0x51, 0x26, 0x45, 0x7F, 0x26, 0xCE, + 0x84, 0xF9, 0x61, 0x72, 0x41, 0x86, 0x07, 0x82, 0xF8, 0x64, 0xB4, 0x73, 0xD8, 0x40, 0x17, + 0x49, 0x19, 0x02, 0xB1, 0xBD, 0xC8, 0xCD, 0xC5, 0x80, 0x0D, 0xD4, 0x61, 0x27, 0xFB, 0x80, + 0xA7, 0x1C, 0x09, 0x5B, 0x47, 0x3A, 0x56, 0x25, 0x29, 0xB3, 0xB1, 0xE7, 0xE4, 0x37, 0xE1, + 0x58, 0xA5, 0xF6, 0x66, 0x6E, 0x99, 0x74, 0xD0, 0x05, 0xB0, 0x62, 0xC2, 0x30, 0x9E, 0x6D, + 0xCE, 0x98, 0xF9, 0xB6, 0x58, 0xC6, 0xE3, 0xF9, 0xA2, 0x16, 0xD5, 0x8C, 0x8C, 0x91, 0x42, + 0xBD, 0x1C, 0x8C, 0x85, 0xA9, 0xDA, 0x87, 0x2E, 0xBB, 0xFA, 0xD3, 0xFE, 0xA9, 0xD9, 0xAB, + 0xA2, 0xB6, 0x8C, 0x0E, 0x8F, 0x19, 0xC6, 0xFF, 0x5F, 0x00, 0x58, 0x4D, 0x45, 0xDA, 0xF9, + 0xD6, 0xC9, 0xD6, 0x9E, 0xD0, 0x4B, 0x8D, 0xA8, 0xD6, 0x87, 0x25, 0x8B, 0x77, 0x80, 0x79, + 0x27, 0x61, 0x2C, 0x53, 0x04, 0x46, 0xFE, 0xA7, 0x69, 0x7A, 0xE3, 0xF9, 0x26, 0x69, 0x89, + 0x29, 0xBC, 0x6A, 0x5A, 0x8C, 0xF3, 0xE2, 0x02, 0x4C, 0x0F, 0x0C, 0x5E, 0xE5, 0x7B, 0x58, + 0x69, 0xBF, 0x98, 0x18, 0x81, 0xCA, 0xF9, 0xE3, 0x66, 0x5F, 0xC7, 0xF7, 0xEF, 0xC6, 0x78, + 0x92, 0x9F, 0x87, 0xA5, 0x6E, 0xAA, 0x42, 0xEA, 0x4D, 0x1F, 0xF6, 0x69, 0x18, 0x22, 0xDD, + 0x79, 0xA4, 0x70, 0x96, 0xB7, 0x76, 0xD1, 0xD8, 0xF0, 0x14, 0x56, 0xE5, 0x87, 0x3B, 0x07, + 0x38, 0x40, 0x6C, 0x38, 0x2C, 0x57, 0x3A, 0xE9, 0xCD, 0xE2, 0xD9, 0xE7, 0xF2, 0x31, 0xB6, + 0xCC, 0x5C, 0x67, 0x6E, 0x7C, 0xF4, 0x39, 0x63, 0x37, 0x30, 0x13, 0xA5, 0x80, 0x75, 0x38, + 0x1F, 0xF0, 0x94, 0x9B, 0xE0, 0x84, 0x54, 0x6D, 0x72, 0xE4, 0xF8, 0xA3, 0xE5, 0xFE, 0x4A, + 0xA5, 0x09, 0x1A, 0xDD, 0x23, 0x4E, 0x2A, 0xFE, 0x00, 0x30, 0xB1, 0xB6, 0x63, 0xAE, 0x9D, + 0x2D, 0x32, 0x41, 0x09, 0x86, 0xB9, 0x40, 0x2A, 0xAA, 0xF2, 0x46, 0x5B, 0x74, 0xA5, 0xE2, + 0xD0, 0xBC, 0x38, 0xE3, 0xA9, 0x2B, 0xBD, 0xDD, 0x8A, 0x1F, 0xED, 0x7B, 0x94, 0x8C, 0x23, + 0xCC, 0xE6, 0xF8, 0xC0, 0x8F, 0xE3, 0x56, 0x83, 0x5B, 0xA6, 0x5B, 0x0F, 0x98, 0x40, 0x68, + 0x61, 0x6E, 0xF4, 0x81, 0x38, 0xEF, 0xD8, 0x9B, 0xF3, 0x57, 0xA5, 0x4D, 0x2E, 0xBB, 0xF3, + 0x76, 0xCB, 0xDC, 0xC6, 0x9C, 0x5F, 0x1F, 0x61, 0xC6, 0x4D, 0x27, 0x94, 0xBC, 0x06, 0xCC, + 0xB9, 0xAB, 0xDF, 0x66, 0xE2, 0x50, 0x85, 0xD8, 0xC8, 0x30, 0xE2, 0xAE, 0x3B, 0x0F, 0xE0, + 0xF0, 0x7A, 0x7A, 0xF8, 0xB9, 0x32, 0x0B, 0xF3, 0x42, 0x97, 0x09, 0x97, 0xD6, 0x7D, 0x7C, + 0x12, 0x59, 0x3A, 0x8F, 0xBF, 0xAD, 0xE6, 0x35, 0xAA, 0xC5, 0x30, 0x83, 0xA7, 0x02, 0x2C, + 0x47, 0xD5, 0xF7, 0x7A, 0x52, 0xB5, 0x7B, 0x59, 0x8D, 0xA9, 0x39, 0x2A, 0xE6, 0xD8, 0x6A, + 0xFC, 0x46, 0xFC, 0x06, 0x45, 0x51, 0x81, 0xB9, 0xC7, 0x5A, 0x64, 0x6D, 0xC2, 0x1F, 0x81, + 0xE4, 0xBF, 0x21, 0x37, 0x53, 0xDE, 0x73, 0x7F, 0xD2, 0xA1, 0x40, 0x02, 0x79, 0x20, 0xAD, + 0xD3, 0x5A, 0x22, 0x3F, 0x9F, 0x5F, 0x44, 0x65, 0xCE, 0xB6, 0x0C, 0x03, 0xED, 0x04, 0x55, + 0xA3, 0x33, 0xA5, 0xCC, 0x83, 0xAD, 0xBF, 0x43, 0xF1, 0xF4, 0x2C, 0x2C, 0xCB, 0x83, 0x28, + 0xC2, 0x1C, 0x7A, 0xB7, 0xFA, 0xED, 0x2B, 0x21, 0xCF, 0xAD, 0xE2, 0xDA, 0x55, 0x22, 0x3A, + 0xAA, 0xB2, 0xAF, 0x9B, 0x41, 0xC7, 0x33, 0x23, 0x41, 0x74, 0x63, 0x41, 0xB3, 0x9A, 0xA2, + 0xF4, 0x38, 0x15, 0x65, 0x0F, 0x54, 0x80, 0x51, 0x14, 0x24, 0xCF, 0xA6, 0x90, 0x17, 0x79, + 0xC4, 0xD1, 0x8B, 0x63, 0x8C, 0xC0, 0x28, 0x7A, 0xAA, 0xF3, 0x16, 0x80, 0x33, 0x8D, 0x20, + 0xB1, 0x7C, 0x74, 0x49, 0xFD, 0xC6, 0xA2, 0x78, 0xA8, 0xD9, 0x6A, 0x82, 0xEE, 0x4C, 0x4E, + 0xCA, 0x40, 0x12, 0x5E, 0x2D, 0x65, 0x29, 0x00, 0x71, 0xC7, 0xAE, 0xF1, 0xBE, 0x6A, 0x99, + 0x15, 0x98, 0xFB, 0x9D, 0x59, 0x51, 0x25, 0x23, 0xBC, 0xD4, 0xB3, 0x8C, 0x56, 0x6B, 0x8E, + 0x80, 0xA7, 0x3A, 0xE3, 0x33, 0xE1, 0x34, 0x41, 0x43, 0x27, 0xEF, 0x1D, 0x83, 0xC4, 0x7C, + 0x49, 0xDF, 0xE7, 0x93, 0x6D, 0xF1, 0x33, 0x8A, 0x5E, 0x24, 0x77, 0x87, 0x86, 0x8F, 0xC8, + 0x4F, 0xDC, 0xB9, 0x5A, 0xC8, 0x9C, 0x18, 0x5C, 0x4B, 0xB5, 0xFD, 0x57, 0xB2, 0x33, 0x8A, + 0xC4, 0x2B, 0x41, 0xC1, 0x0A, 0x82, 0x3D, 0xF3, 0x96, 0x24, 0xF3, 0x6B, 0x15, 0xA2, 0xF0, + 0x67, 0x58, 0x4E, 0x06, 0xCA, 0x2E, 0x08, 0xCC, 0xAF, 0xF1, 0x61, 0x8F, 0xE0, 0x1D, 0xD0, + 0x6D, 0xF3, 0x51, 0x2E, 0x0B, 0x72, 0x4D, 0xEC, 0x85, 0x06, 0xDA, 0x24, 0x21, 0x5A, 0xCA, + 0xCC, 0x2C, 0x51, 0xB8, 0x2A, 0xD8, 0xD3, 0x02, 0x00, 0x2F, 0xB4, 0x10, 0x68, 0xB1, 0xDA, + 0x4F, 0x8B, 0xB1, 0x47, 0x98, 0x7B, 0x35, 0x16, 0xBA, 0xD5, 0xDB, 0xDD, 0xF0, 0x13, 0x18, + 0xFD, 0x3F, 0xA9, 0xBC, 0x43, 0x70, 0x2A, 0xC4, 0x98, 0xC7, 0x19, 0xD9, 0x5F, 0x2E, 0x84, + 0x1B, 0x62, 0x2A, 0x5E, 0x48, 0x48, 0xA3, 0xC5, 0xC2, 0x62, 0x95, 0x99, 0x92, 0xEA, 0x7A, + 0x7D, 0x72, 0xCA, 0x8A, 0x36, 0x80, 0x28, 0xF4, 0x97, 0xDF, 0xAD, 0x93, 0x35, 0x5C, 0xBB, + 0x1B, 0xB9, 0x78, 0x6D, 0x14, 0xFF, 0x2C, 0xF5, 0x90, 0x31, 0x78, 0x48, 0xF9, 0x58, 0x56, + 0x42, 0x71, 0x10, 0xDD, 0xA3, 0x6F, 0x51, 0x92, 0xA8, 0x16, 0xCE, 0x9C, 0x88, 0x16, 0xCC, + 0x7B, 0xBF, 0xC8, 0x04, 0xEF, 0xC4, 0x00, 0x85, 0xA3, 0x85, 0x0B, 0x89, 0xF1, 0xE7, 0xFE, + 0x56, 0x56, 0xDB, 0xA4, 0x10, 0xF9, 0x06, 0xA9, 0x7C, 0x32, 0x33, 0x6C, 0x1A, 0xE7, 0xE8, + 0x17, 0x37, 0xA8, 0x3E, 0x08, 0x73, 0x54, 0xE4, 0x28, 0xDA, 0x85, 0x38, 0xD9, 0x48, 0xDB, + 0xF5, 0xDF, 0xAC, 0xB5, 0x9D, 0xD2, 0xB5, 0xFD, 0x3B, 0xC8, 0x03, 0xF4, 0xBA, 0x43, 0x2C, + 0x9A, 0x73, 0x9D, 0xF2, 0xCF, 0xA9, 0xED, 0x94, 0x84, 0x32, 0x0F, 0x97, 0xED, 0xFF, 0x1A, + 0x48, 0xC6, 0xB8, 0x6B, 0x30, 0x02, 0xCF, 0xB7, 0x72, 0xDD, 0x5E, 0x56, 0x2B, 0xC4, 0xC3, + 0xD6, 0x83, 0xED, 0x96, 0x4B, 0x61, 0x99, 0xFA, 0x05, 0x14, 0xB0, 0x79, 0x0D, 0x95, 0x80, + 0x95, 0xB7, 0xB8, 0x5C, 0x6B, 0xE8, 0x75, 0xFB, 0xB5, 0x59, 0xE1, 0x93, 0x01, 0x46, 0xCC, + 0xEA, 0x63, 0xA3, 0x88, 0xA1, 0x94, 0xFE, 0x09, 0xC3, 0xDE, 0xA0, 0x3B, 0xE5, 0x2D, 0xE2, + 0x7E, 0x90, 0x10, 0x17, 0xAF, 0xE8, 0x09, 0xAF, 0x63, 0x0A, 0x73, 0x82, 0xBF, 0x5C, 0x4C, + 0xD4, 0xD1, 0xB8, 0xF4, 0x15, 0x79, 0xFB, 0x43, 0x48, 0xED, 0xE4, 0xCA, 0x05, 0xF4, 0xCD, + 0x3F, 0x13, 0x9A, 0x31, 0xB2, 0x54, 0x4E, 0x51, 0x6D, 0xBE, 0x40, 0x86, 0xB9, 0xBB, 0x4B, + 0x2B, 0xED, 0x47, 0xE2, 0xD2, 0x30, 0x98, 0x2D, 0xD5, 0x19, 0x24, 0x29, 0xD3, 0x77, 0xB7, + 0xC0, 0x74, 0x5C, 0xC0, 0x68, 0xE2, 0xF5, 0xA4, 0xAA, 0x04, 0xC7, 0xFF, 0x87, 0x20, 0x9E, + 0xD1, 0x25, 0x99, 0x76, 0xA0, 0xFC, 0x9B, 0x25, 0xE9, 0xE8, 0x51, 0xD4, 0xE3, 0x50, 0x2C, + 0x02, 0xC8, 0x5D, 0x6D, 0xFF, 0x02, 0x9E, 0x21, 0x1D, 0x01, 0xEB, 0xF0, 0xE9, 0xE7, 0x18, + 0x8D, 0x56, 0x8F, 0x84, 0x37, 0xD8, 0x13, 0xB0, 0xF1, 0x22, 0xF2, 0xFB, 0x17, 0x60, 0x3B, + 0x69, 0x3E, 0xD9, 0xC3, 0x8F, 0x17, 0xCF, 0xD5, 0x0B, 0x81, 0x5E, 0x6D, 0x9D, 0xFC, 0x0E, + 0xD2, 0xCC, 0xF1, 0x9F, 0x63, 0x99, 0x27, 0x4A, 0x14, 0x20, 0xF2, 0x35, 0xA5, 0x9D, 0x8B, + 0xF7, 0x24, 0x34, 0x5E, 0x14, 0xE4, 0x5D, 0x9E, 0x4B, 0xE8, 0x93, 0x4D, 0xFC, 0x3F, 0xA9, + 0x26, 0x78, 0xDB, 0x61, 0xD7, 0x11, 0x8B, 0xF5, 0x3C, 0xB8, 0xA2, 0x22, 0x5B, 0x33, 0x5F, + 0x7E, 0xAE, 0x50, 0xE3, 0xF9, 0x41, 0x23, 0x76, 0x28, 0xDB, 0x76, 0xD8, 0xEA, 0x38, 0xF7, + 0x7A, 0x72, 0xAF, 0x3A, 0x26, 0xC8, 0x1F, 0xE4, 0x35, 0x23, 0xB3, 0x35, 0x53, 0x5A, 0x5D, + 0x1D, 0xB7, 0xC3, 0x8F, 0x34, 0x10, 0x82, 0xBB, 0x57, 0x34, 0xD0, 0x89, 0xE8, 0xAE, 0x30, + 0x9C, 0xFD, 0xA3, 0xA0, 0xBC, 0xB5, 0xCD, 0x5B, 0x09, 0x71, 0x13, 0xC8, 0xED, 0xF9, 0x61, + 0x6A, 0xA4, 0xF6, 0xE6, 0x63, 0x1B, 0x91, 0x25, 0x27, 0x6F, 0xB3, 0xF6, 0x80, 0xA3, 0x43, + 0x41, 0xC3, 0xDB, 0x66, 0x8D, 0xC6, 0xCA, 0xD4, 0x5F, 0xC9, 0x3B, 0x27, 0x08, 0xCA, 0x2A, + 0xF7, 0x5C, 0xCC, 0xE7, 0x34, 0xFD, 0x19, 0x1C, 0x50, 0x08, 0x9D, 0xAD, 0x53, 0x98, 0x2F, + 0xDD, 0xAE, 0x02, 0x53, 0x1F, 0xF9, 0x3E, 0x1F, 0x21, 0xFF, 0x39, 0x5F, 0xC0, 0xA1, 0x28, + 0x74, 0xED, 0xF0, 0x6B, 0x6F, 0x96, 0x47, 0xE9, 0x5A, 0x73, 0x24, 0x58, 0x6C, 0x71, 0xDF, + 0xD9, 0x1D, 0x90, 0x1D, 0x62, 0x18, 0x58, 0x19, 0x0F, 0xEC, 0xD0, 0x0C, 0xCD, 0x11, 0x0B, + 0xBA, 0xC5, 0x9F, 0x96, 0xCB, 0x88, 0x4C, 0x3C, 0x93, 0x99, 0x47, 0x48, 0xA5, 0x6F, 0x41, + 0x28, 0x3B, 0xFC, 0x41, 0xFB, 0x89, 0x05, 0x21, 0x53, 0xA8, 0x94, 0x58, 0x8C, 0x3C, 0xB9, + 0x01, 0x7F, 0x3D, 0x66, 0x32, 0x6C, 0x98, 0x56, 0x37, 0xE5, 0x75, 0xAC, 0xB8, 0x12, 0x34, + 0x63, 0x42, 0x65, 0x40, 0x25, 0xD6, 0x02, 0xDE, 0x3B, 0xA9, 0x40, 0xC1, 0x9A, 0xC1, 0xA6, + 0x33, 0xDF, 0xFD, 0xA9, 0x77, 0xB5, 0x29, 0xB8, 0x01, 0x3E, 0x19, 0xC1, 0xD6, 0xD0, 0x68, + 0x0F, 0x4D, 0xAE, 0x62, 0xC9, 0x24, 0x45, 0x0A, 0xE6, 0x6A, 0xAB, 0x82, 0xF2, 0x14, 0x73, + 0x06, 0x1D, 0xAB, 0x3D, 0x62, 0xB2, 0x47, 0xF9, 0x07, 0xE3, 0x55, 0x19, 0x39, 0xAD, 0x3F, + 0x54, 0x65, 0xE9, 0xD0, 0x8A, 0x82, 0xBF, 0xEA, 0x17, 0xEE, 0xA1, 0xB6, 0xB2, 0xB9, 0x23, + 0x75, 0x74, 0x77, 0xF9, 0x93, 0x00, 0x0B, 0x2F, 0x43, 0xB7, 0x0F, 0x28, 0xAA, 0xAB, 0x1F, + 0xE9, 0xA2, 0x6A, 0xD1, 0xFD, 0x33, 0x61, 0x61, 0x6C, 0x0B, 0x0E, 0x24, 0x2F, 0xE7, 0x66, + 0x04, 0xB7, 0x03, 0x3A, 0x1F, 0x30, 0xE9, 0x7E, 0x28, 0xF5, 0x26, 0xCA, 0x3C, 0x88, 0x0F, + 0xE2, 0xB8, 0xD9, 0xD1, 0xB0, 0xC9, 0xFF, 0x18, 0x8B, 0x31, 0xCB, 0x9D, 0x97, 0x42, 0x5A, + 0xCA, 0xB9, 0xB2, 0x16, 0xD9, 0x8A, 0x6A, 0xE3, 0x55, 0xE5, 0x83, 0xDA, 0x71, 0xE8, 0x86, + 0x4E, 0xE3, 0xD1, 0x6B, 0x07, 0x59, 0x79, 0x61, 0x90, 0xEF, 0x54, 0x5C, 0x1E, 0x62, 0xBF, + 0xEF, 0x92, 0xAF, 0x6C, 0xA1, 0x47, 0xB1, 0x32, 0x44, 0xD6, 0xC8, 0x92, 0xFC, 0x8E, 0xF2, + 0x23, 0xAB, 0x3F, 0x43, 0xF9, 0x24, 0xC2, 0xF4, 0x66, 0x09, 0x7E, 0xE8, + ]) + .unwrap(); let msg = b"The quick brown fox jumped over the lazy dog"; @@ -229,7 +741,7 @@ fn bench_mldsa65_sign() { } fn bench_mldsa65_lowmemory_sign() { - use bouncycastle::mldsa_lowmemory::{MLDSATrait, MLDSA65, MLDSA65PrivateKey, MLDSA65_SK_LEN}; + use bouncycastle::mldsa_lowmemory::{MLDSA65, MLDSA65_SK_LEN, MLDSA65PrivateKey, MLDSATrait}; eprintln!("MLDSA65_lowmemory/Sign"); @@ -242,7 +754,12 @@ fn bench_mldsa65_lowmemory_sign() { // use bouncycastle_hex as hex; // eprintln!("sk:\n{}", &hex::encode(sk.encode())); - let sk = MLDSA65PrivateKey::from_bytes(&[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f]).unwrap(); + let sk = MLDSA65PrivateKey::from_bytes(&[ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, + 0x1E, 0x1F, + ]) + .unwrap(); let msg = b"The quick brown fox jumped over the lazy dog"; @@ -252,7 +769,7 @@ fn bench_mldsa65_lowmemory_sign() { } fn bench_mldsa87_sign() { - use bouncycastle::mldsa::{MLDSATrait, MLDSA87, MLDSA87PrivateKey}; + use bouncycastle::mldsa::{MLDSA87, MLDSA87PrivateKey, MLDSATrait}; eprintln!("MLDSA87/Sign"); @@ -268,7 +785,336 @@ fn bench_mldsa87_sign() { let msg = b"The quick brown fox jumped over the lazy dog"; // let (_pk, sk) = MLDSA87::keygen_from_seed(&seed).unwrap(); - let sk = MLDSA87PrivateKey::from_bytes(&[0x97,0x92,0xbc,0xec,0x2f,0x24,0x30,0x68,0x6a,0x82,0xfc,0xcf,0x3c,0x2f,0x5f,0xf6,0x65,0xe7,0x71,0xd7,0xab,0x41,0xb9,0x02,0x58,0xcf,0xa7,0xe9,0x0e,0xc9,0x71,0x24,0xd8,0xe9,0xee,0x4e,0x90,0xa1,0x6c,0x60,0x2f,0x5e,0xc9,0xbc,0x38,0x51,0x7d,0xc3,0x0e,0x32,0x9d,0x5a,0xb2,0x76,0x73,0xbd,0x85,0xf4,0xc9,0xb0,0x30,0x0f,0x77,0x63,0x89,0x88,0x67,0x50,0xb5,0x7c,0x24,0xdb,0x3f,0xc0,0x12,0xe6,0x1e,0xde,0x59,0x75,0x33,0x37,0x37,0x4f,0xa7,0x12,0x49,0x91,0x54,0x9a,0xf2,0x43,0x49,0x6d,0x06,0x37,0xcb,0x3b,0xe0,0x5a,0x59,0x48,0x23,0x5b,0xf7,0x98,0x75,0xf8,0x96,0xd8,0xfe,0x0c,0xab,0x30,0xc8,0x49,0x48,0xdb,0x4d,0x63,0x15,0xaa,0xaf,0x16,0x0a,0xc6,0x24,0x36,0x64,0x22,0x01,0x48,0x16,0x11,0x09,0x11,0x2c,0x94,0x02,0x89,0x22,0x45,0x2c,0x62,0xb8,0x45,0x00,0x45,0x2a,0x08,0x96,0x70,0x90,0x12,0x6e,0x14,0x93,0x70,0xd4,0x46,0x10,0x84,0x44,0x51,0x58,0x96,0x91,0x0c,0xa9,0x29,0x82,0xb2,0x41,0xc9,0x08,0x71,0xc4,0x28,0x68,0x04,0x96,0x89,0x48,0x40,0x85,0x9b,0x22,0x6d,0x1c,0x28,0x64,0x59,0x12,0x41,0x9c,0xb8,0x91,0x84,0x04,0x89,0x44,0x90,0x05,0xcb,0x34,0x62,0xa0,0x86,0x90,0x40,0x26,0x92,0x20,0x99,0x29,0x13,0x05,0x69,0x5c,0x34,0x68,0xa4,0x32,0x8e,0x19,0x26,0x92,0x59,0x46,0x10,0x09,0xa4,0x49,0x23,0x42,0x4d,0x12,0x36,0x61,0x58,0x10,0x65,0x01,0x28,0x90,0x1a,0x33,0x4c,0x99,0x86,0x31,0xd3,0xa2,0x49,0x09,0x82,0x25,0x43,0x14,0x28,0xc0,0x38,0x81,0x03,0x15,0x4d,0x5b,0x28,0x86,0x08,0x87,0x48,0x23,0x31,0x52,0x94,0x22,0x25,0xc3,0xc0,0x4d,0xa4,0x98,0x21,0x98,0x40,0x20,0xd1,0x42,0x86,0xcb,0x40,0x70,0x5b,0xb0,0x71,0x9c,0x96,0x2c,0xc1,0x12,0x06,0x53,0x46,0x09,0x0c,0x45,0x02,0x14,0x46,0x6e,0x91,0xb4,0x21,0x54,0xb0,0x8c,0xe4,0x46,0x42,0x9a,0x20,0x8c,0x01,0x21,0x25,0x13,0x41,0x05,0x5a,0x40,0x22,0x13,0xc9,0x0c,0xa0,0x18,0x40,0x52,0xc2,0x30,0xcb,0x34,0x2c,0x4b,0xc8,0x68,0x1b,0xa4,0x60,0x49,0x84,0x84,0x63,0x30,0x29,0x4a,0xa0,0x69,0x5b,0x80,0x04,0xd2,0x38,0x0a,0x14,0x26,0x4c,0xe2,0xb2,0x44,0x8b,0xa2,0x11,0x24,0x46,0x49,0xc4,0x14,0x52,0x0b,0x42,0x71,0x03,0xb2,0x10,0x92,0x28,0x80,0x01,0x24,0x88,0xe3,0x08,0x11,0x0a,0x05,0x28,0x19,0xc4,0x81,0x00,0x20,0x22,0xdc,0x44,0x68,0x42,0x12,0x22,0x44,0x00,0x2a,0xc9,0x26,0x6a,0x0c,0x87,0x31,0xe0,0xc0,0x44,0x99,0x14,0x84,0x18,0x36,0x0d,0x11,0x37,0x42,0x22,0x18,0x8c,0x63,0xb2,0x91,0x0c,0x98,0x08,0xa1,0xa0,0x01,0x08,0x92,0x44,0x04,0x13,0x24,0x5c,0x98,0x71,0x82,0x84,0x71,0x84,0x32,0x52,0x51,0xb0,0x31,0x9c,0x42,0x2e,0x1a,0xa8,0x28,0x02,0x08,0x91,0x01,0xc0,0x89,0x0b,0xc7,0x05,0x8a,0x24,0x65,0x22,0xc2,0x64,0x4c,0x88,0x91,0x5c,0x82,0x68,0x13,0xa5,0x64,0x50,0x20,0x86,0x21,0x04,0x02,0x91,0x94,0x44,0x48,0x22,0x30,0x22,0x39,0x4a,0x02,0x98,0x84,0x09,0xa2,0x88,0x19,0x19,0x29,0x44,0x48,0x8c,0x22,0x95,0x0c,0xa1,0x04,0x72,0x04,0x87,0x70,0x12,0x21,0x10,0x42,0x06,0x84,0x1b,0x49,0x85,0x89,0x06,0x4a,0xd3,0x36,0x08,0xdb,0xc0,0x40,0x58,0xb6,0x51,0x0c,0xa7,0x09,0x8c,0x24,0x61,0x99,0x90,0x64,0x8c,0xc2,0x90,0x5b,0x24,0x90,0x10,0xa3,0x49,0x03,0x25,0x61,0x43,0x32,0x8a,0x11,0x98,0x44,0xc8,0xb2,0x20,0x04,0x38,0x41,0x10,0x47,0x2c,0x19,0xc6,0x44,0x1c,0x25,0x2c,0x04,0x88,0x30,0xd9,0x46,0x69,0x9b,0x20,0x00,0x1b,0x46,0x82,0x5a,0xa4,0x80,0x5b,0xa0,0x49,0x18,0x90,0x25,0x00,0x26,0x80,0x0b,0xc2,0x31,0x5a,0x40,0x72,0x54,0xc6,0x20,0xc1,0xb0,0x31,0x24,0xb1,0x4d,0x10,0x95,0x28,0x14,0x00,0x0a,0xa0,0xc8,0x4d,0x54,0xa2,0x88,0x23,0x98,0x81,0x60,0x90,0x04,0x02,0x16,0x2c,0x13,0x21,0x40,0x91,0x86,0x8d,0x08,0xc2,0x91,0x91,0x14,0x26,0xd0,0xb4,0x0c,0x09,0xc6,0x60,0x51,0x44,0x2e,0x04,0x11,0x26,0x00,0x29,0x11,0x93,0xc2,0x08,0x63,0xa4,0x31,0x22,0x00,0x28,0xc1,0x14,0x08,0x0c,0x40,0x2c,0x41,0x14,0x06,0x9c,0x20,0x72,0x54,0x22,0x06,0x8b,0x08,0x4d,0xa1,0x48,0x69,0x10,0x30,0x41,0x1c,0x28,0x49,0x44,0x18,0x8e,0xcc,0x96,0x48,0xd9,0x42,0x50,0x1b,0x06,0x49,0x0c,0x45,0x88,0x23,0x04,0x0d,0x20,0x30,0x2e,0x23,0x85,0x2c,0x14,0x07,0x30,0x40,0xb6,0x85,0x4c,0xc0,0x20,0x44,0x86,0x20,0x19,0x00,0x6c,0x54,0x02,0x48,0xcc,0x88,0x6c,0x59,0x06,0x32,0x49,0x14,0x84,0x04,0xc7,0x50,0x13,0x49,0x28,0xe4,0x06,0x09,0xd3,0xc6,0x10,0xc8,0x28,0x4c,0x23,0x39,0x44,0x52,0xa4,0x64,0xcc,0xa8,0x49,0x44,0x38,0x32,0x0a,0x89,0x84,0x00,0x34,0x2c,0x22,0x85,0x8d,0x10,0x31,0x09,0x09,0x32,0x65,0x1c,0x89,0x8c,0x40,0x40,0x29,0x21,0x85,0x00,0x09,0xa1,0x6d,0x84,0xc0,0x64,0xe2,0x02,0x2d,0x48,0x04,0x40,0x12,0x09,0x8e,0xe0,0x42,0x2e,0x93,0x44,0x08,0x12,0x10,0x6a,0x01,0x84,0x05,0x92,0x30,0x8a,0xcb,0x34,0x8e,0xa2,0x26,0x2e,0x5c,0x86,0x11,0x0b,0x35,0x08,0x18,0x10,0x00,0x02,0x34,0x26,0x24,0x23,0x89,0xd1,0x84,0x00,0x24,0x46,0x60,0x13,0xb2,0x49,0x24,0x28,0x46,0x18,0x02,0x71,0xa0,0x38,0x90,0x89,0x14,0x44,0xd3,0x96,0x2d,0xa3,0x18,0x40,0x23,0x27,0x21,0xc0,0x18,0x50,0x43,0xc8,0x04,0x41,0x42,0x8d,0x5c,0x26,0x41,0x44,0xa2,0x6d,0x48,0x12,0x0e,0x40,0x32,0x25,0x0b,0x14,0x82,0x0a,0x48,0x2e,0xcb,0x82,0x88,0x03,0xa3,0x60,0x1b,0x25,0x26,0x8c,0xb8,0x20,0x24,0xb0,0x85,0x98,0x04,0x21,0x08,0xa7,0x2c,0x83,0x38,0x64,0x54,0x32,0x89,0x01,0x04,0x01,0x23,0x49,0x84,0x02,0x95,0x69,0xd1,0xa4,0x4d,0x13,0xa4,0x0c,0x91,0x46,0x0d,0x61,0x94,0x80,0x90,0x38,0x45,0x5c,0xc6,0x50,0x01,0x17,0x20,0x53,0xc6,0x28,0x9b,0x18,0x10,0x41,0x12,0x68,0x90,0x12,0x21,0xc0,0x10,0x84,0x42,0x16,0x92,0x53,0x82,0x29,0x81,0x26,0x49,0xd8,0xa4,0x05,0x9a,0x26,0x24,0x24,0x03,0x29,0xe0,0x40,0x26,0xd2,0x02,0x48,0x11,0x24,0x68,0x11,0x99,0x89,0x98,0x14,0x85,0xc9,0x20,0x0d,0x50,0x12,0x8c,0x1c,0x08,0x10,0x02,0x10,0x00,0x00,0x95,0x28,0xc1,0x28,0x90,0x59,0xb4,0x85,0xd3,0x14,0x65,0x0a,0x40,0x6e,0x11,0x29,0x65,0x18,0xc2,0x4c,0x21,0x34,0x65,0xd8,0x30,0x69,0x10,0x30,0x52,0x19,0x31,0x66,0x8c,0x18,0x8a,0xc8,0xc0,0x08,0x4c,0x98,0x30,0xa3,0xa6,0x20,0x41,0x16,0x22,0x18,0x05,0x2e,0x22,0x25,0x2a,0x64,0xb8,0x25,0x0a,0xb3,0x01,0x63,0x20,0x84,0x09,0x80,0x09,0x19,0x28,0x0e,0x02,0x11,0x01,0xa3,0x94,0x11,0xe3,0x98,0x6c,0x58,0x20,0x21,0x09,0x41,0x10,0x60,0x36,0x22,0x08,0x06,0x71,0x12,0xc2,0x85,0x5a,0xa0,0x85,0xc0,0xc6,0x84,0x5c,0x38,0x06,0xcb,0xb6,0x69,0x14,0x84,0x84,0x53,0x22,0x82,0xa1,0xa6,0x40,0xcc,0x86,0x00,0xc4,0x26,0x22,0xa0,0xa8,0x08,0x98,0x34,0x72,0xd4,0x20,0x41,0x43,0xc4,0x90,0x48,0x16,0x68,0x1b,0x16,0x52,0x1a,0x37,0x02,0x50,0x20,0x42,0x48,0x48,0x8a,0x20,0x11,0x41,0xe2,0x00,0x6c,0xc0,0xc2,0x0c,0x14,0x06,0x49,0x11,0x31,0x4d,0x19,0x06,0x0a,0x89,0x46,0x09,0x1b,0x81,0x65,0x44,0xc8,0x00,0x82,0x06,0x70,0x00,0x16,0x72,0xcc,0x24,0x50,0x8a,0x42,0x89,0x9c,0x96,0x90,0x64,0x28,0x70,0x92,0xb2,0x68,0x98,0x26,0x62,0x61,0x94,0x40,0xc1,0x16,0x89,0xd8,0x42,0x64,0x1a,0x21,0x4e,0x62,0x90,0x64,0x21,0xc8,0x24,0x8b,0x28,0x6d,0x5c,0x42,0x92,0xa0,0xc6,0x4d,0x0c,0x85,0x80,0xcc,0x88,0x4d,0xd4,0x42,0x8d,0x42,0x34,0x8a,0x0b,0x04,0x51,0xc3,0x26,0x86,0x24,0x25,0x81,0x12,0x35,0x06,0xa0,0x44,0x04,0xc8,0x94,0x81,0x5b,0xb4,0x31,0x1c,0x08,0x06,0x5c,0x24,0x08,0x03,0x27,0x6a,0x20,0xc2,0x25,0xe1,0x80,0x90,0x19,0xb4,0x6d,0xa3,0x46,0x0c,0x4b,0x18,0x60,0x50,0xc6,0x2c,0x1b,0x92,0x2d,0x11,0x15,0x04,0xa2,0x00,0x04,0x21,0x48,0x2e,0xd8,0x16,0x06,0xd2,0x10,0x8a,0x83,0xa2,0x25,0x08,0x31,0x0d,0x09,0x38,0x51,0xd9,0x48,0x49,0x0b,0x16,0x4c,0x23,0x32,0x25,0x19,0x19,0x02,0x4a,0x44,0x09,0xd1,0xb2,0x21,0x0b,0x83,0x2c,0x23,0x25,0x85,0x93,0x16,0x85,0x44,0xa0,0x44,0x1b,0x83,0x50,0x02,0x22,0x72,0x4b,0x04,0x80,0x9b,0x14,0x65,0x21,0x93,0x60,0x18,0x13,0x0a,0xd9,0x46,0x0d,0x22,0x45,0x61,0xc8,0xb4,0x40,0xa1,0x42,0x2d,0x02,0xb8,0x09,0x00,0x14,0x44,0x9b,0xb6,0x11,0x0b,0x97,0x8c,0x40,0x10,0x4a,0x82,0x14,0x6a,0xda,0x90,0x05,0x1c,0x02,0x8e,0x0c,0x19,0x72,0xa3,0xb4,0x8d,0x24,0x30,0x50,0x11,0x87,0x09,0x64,0xc6,0x28,0xe4,0x18,0x92,0x98,0xb4,0x6c,0x61,0x16,0x51,0x40,0x46,0x0e,0x1c,0x32,0x48,0xda,0x20,0x51,0x88,0x36,0x8a,0x23,0xb1,0x21,0x82,0x90,0x28,0x1a,0x15,0x32,0xe2,0x18,0x61,0x92,0x04,0x8e,0x13,0xb6,0x90,0x13,0x13,0x68,0xc9,0x84,0x68,0x4c,0x40,0x6d,0x0b,0x33,0x00,0x81,0x46,0x4d,0xd2,0x38,0x0c,0x04,0x96,0x81,0xa4,0x88,0x50,0x02,0x90,0x85,0x22,0xb0,0x04,0xd3,0xa4,0x71,0xd2,0x80,0x10,0xca,0x96,0x40,0x51,0xa6,0x41,0xa4,0x84,0x28,0xe0,0x08,0x52,0x0b,0x30,0x8c,0xd2,0x38,0x0a,0x0c,0x29,0x51,0xc3,0x82,0x09,0xca,0x20,0x91,0xd8,0x36,0x92,0xa3,0xa6,0x28,0x92,0x42,0x22,0xa2,0x16,0x01,0x1a,0x34,0x86,0x37,0xd9,0xa6,0x59,0x16,0x98,0x81,0xec,0x21,0xcf,0x48,0x11,0x86,0x9d,0x1d,0x7f,0x13,0x9f,0x05,0x37,0xe9,0x6f,0x11,0x84,0x58,0x54,0x05,0xfd,0x17,0x80,0x8a,0xf1,0xe0,0x62,0x39,0xd3,0xb3,0x4e,0x5a,0xca,0x8b,0xf1,0x36,0x96,0x77,0xb4,0x47,0xac,0x71,0x8a,0xc4,0x7d,0x85,0x0c,0x4d,0x77,0xb0,0xbe,0x31,0xdc,0x9f,0x50,0x8e,0x39,0x78,0xf2,0x42,0x74,0xab,0x01,0x85,0xf7,0x27,0xab,0xdf,0xf5,0x9f,0x44,0x90,0x37,0x1b,0xf0,0x46,0x10,0xe3,0x64,0xe6,0x4e,0xc8,0x75,0xef,0x9d,0x20,0xdc,0x94,0x07,0x7e,0x1e,0x16,0x63,0x27,0xa8,0x79,0xb8,0xab,0x51,0x61,0x60,0xb2,0xa3,0xf7,0x74,0x37,0xb9,0xb3,0xcc,0x7d,0x17,0xae,0xad,0xdc,0x84,0xdb,0x62,0x74,0x6a,0x35,0xac,0x09,0x6f,0x78,0x2f,0x62,0xa7,0xf0,0x1a,0xa6,0xd6,0x69,0x3d,0xee,0xc9,0x0b,0x23,0xc6,0x69,0x85,0xa0,0x23,0x07,0xe0,0xa1,0xca,0xe5,0x98,0xa6,0x73,0x24,0xdb,0xa0,0xf5,0x2f,0x22,0x43,0x22,0x75,0xe9,0x32,0x57,0x06,0x5c,0x3b,0x7e,0x5e,0x1c,0xfe,0x1d,0xfd,0x4d,0x0d,0xf0,0x86,0xdf,0x21,0x24,0x34,0x14,0xa2,0xd2,0x7e,0x20,0x23,0x0a,0x82,0x9b,0xe4,0xeb,0x4c,0x82,0xc1,0x6d,0x35,0xf7,0x8b,0x0e,0x5e,0x19,0x83,0x32,0xe0,0x00,0x74,0xbb,0x64,0x61,0x2f,0xab,0x17,0xd4,0xc8,0x97,0x1c,0xb6,0x8e,0x5e,0xda,0xb0,0x36,0x9f,0x11,0x57,0xb3,0x46,0x9a,0xbd,0x83,0x84,0xe2,0xd9,0x55,0x3f,0x1b,0x78,0xe7,0x86,0xe1,0xee,0x9d,0x0b,0x98,0xd3,0x9f,0x83,0xcc,0xec,0xf3,0x7d,0x1e,0xbd,0x3a,0x9d,0x63,0xae,0xc7,0x66,0x16,0x4a,0x10,0x17,0x1a,0x4f,0xd8,0xc6,0x3d,0xaf,0x18,0x2c,0x42,0x12,0x58,0xc5,0xf5,0x29,0xaa,0x55,0xcb,0x7e,0xba,0xe2,0xe1,0x65,0x23,0x15,0xe1,0xf7,0x1e,0x8a,0x74,0x13,0x14,0x10,0xd0,0x32,0x47,0xed,0xe1,0x1d,0x34,0xdb,0x91,0xf6,0xf0,0x8a,0xa2,0x47,0x8f,0xd7,0x89,0x67,0x9c,0x04,0x94,0x9f,0x71,0xbc,0x01,0x71,0xe0,0x7e,0x3a,0x8b,0xb5,0x75,0x3d,0xbb,0xda,0xa4,0x11,0xa6,0x35,0x0a,0xb4,0x6e,0xef,0xbf,0x86,0xfc,0x55,0x1c,0x29,0xef,0xe4,0xcd,0xd7,0x66,0x1d,0x5c,0xf6,0xc3,0xdb,0x22,0xd0,0xce,0xdd,0xe5,0x99,0x85,0x44,0x59,0xd9,0x7f,0x20,0xdf,0x74,0x55,0xbd,0xf3,0x56,0xa1,0x98,0xd0,0xf7,0xeb,0x6d,0x34,0x11,0x1f,0xc9,0x40,0xb2,0x5c,0x05,0x43,0xb7,0x88,0xed,0xda,0x9d,0x26,0x81,0x0e,0xac,0x3d,0x6c,0xc9,0xc5,0x13,0x27,0xc2,0xcf,0x83,0xe8,0x87,0xd4,0x08,0x9e,0x19,0x69,0x5e,0x11,0xad,0xd8,0x37,0xf6,0xf4,0x40,0xcc,0x36,0x0f,0x93,0xf3,0x2f,0xee,0x8a,0x96,0x63,0x71,0x2c,0x6b,0xbd,0x38,0xc8,0x4a,0xb7,0xb5,0x48,0x23,0xec,0x36,0x3e,0xb7,0xe4,0x2e,0xb5,0x9f,0xc1,0xfc,0xe6,0x0f,0xbd,0x55,0x30,0x7b,0x3e,0xc8,0x5f,0xd9,0xda,0xf3,0x20,0x6d,0x7b,0x4b,0x39,0x17,0xf1,0xc8,0xb7,0xa9,0x2e,0x3c,0x67,0xd8,0x98,0x80,0xfd,0xf2,0xe4,0x7f,0x5a,0x0c,0x99,0x45,0x95,0xdb,0x17,0x0a,0xf4,0x1b,0xab,0xf5,0xa2,0x5b,0x4d,0xc1,0xc4,0x2d,0xd6,0xa9,0xdb,0x27,0x1e,0x76,0x4d,0xe2,0xfb,0x01,0x5a,0x49,0xa8,0x50,0xc7,0x91,0x9b,0xe4,0x70,0x06,0xa3,0x36,0xe2,0xe3,0x25,0xfd,0xe5,0x3a,0xc5,0x99,0x55,0x4d,0x0a,0x7d,0xe4,0xef,0x45,0xec,0x40,0xc3,0x9d,0x6b,0xaf,0xf3,0x11,0xbe,0xee,0x75,0xd8,0x9e,0x02,0xad,0x31,0xf4,0xbe,0x4b,0xd2,0x0a,0xe9,0x19,0x4f,0x5e,0xdd,0xda,0xa6,0x65,0x07,0x76,0x11,0x6e,0x9f,0x27,0x0f,0x77,0x71,0x4a,0xd7,0xa8,0xe8,0x9a,0xce,0xf7,0x4b,0x7f,0xf7,0xd8,0xdb,0xec,0x27,0xf8,0x02,0x0a,0x98,0x52,0x47,0xe2,0xcd,0xac,0xef,0x48,0x94,0xa4,0xd6,0x8b,0xa3,0x7c,0xa9,0x12,0xd6,0xbe,0x73,0x50,0x1c,0x99,0x51,0x81,0xe5,0xb7,0x77,0x23,0x35,0x0b,0x36,0x31,0xda,0x37,0x00,0xe1,0x3f,0xd3,0x66,0xe1,0x31,0xbf,0x06,0xb3,0x6e,0xb6,0xb0,0x34,0x50,0x93,0x20,0x9f,0x0a,0x7b,0xef,0xfa,0xe1,0xfd,0xd8,0x75,0xb0,0x06,0x87,0xc1,0x16,0x3c,0x35,0x3d,0x7d,0x2a,0xc9,0x09,0x37,0xb3,0x4e,0x97,0x8e,0x92,0xf8,0x21,0xad,0xc9,0x66,0x22,0x02,0xec,0xe8,0x9a,0x17,0xe7,0xbb,0x65,0xae,0x17,0xd8,0x3b,0x90,0xdb,0xbe,0x6a,0x50,0x1a,0x4e,0x13,0x45,0xbe,0xe4,0xe5,0xa5,0xb5,0x3a,0xf2,0xe5,0xba,0x3d,0x1e,0xf3,0xf4,0xe0,0x5a,0xdf,0x0b,0x3a,0x4c,0xf2,0xe5,0x30,0x36,0x0f,0xee,0x64,0x92,0x99,0x02,0xb5,0x71,0xf6,0xfd,0x2e,0x30,0x56,0x52,0xa4,0xcb,0x01,0x0f,0x79,0xf8,0x15,0xe1,0x8f,0x2b,0xbb,0x8c,0xc8,0x9f,0xa6,0xfc,0x76,0xf7,0x7c,0x89,0xe2,0x93,0xcf,0x17,0x5a,0x0b,0x19,0x58,0x00,0xfe,0x72,0xd2,0xcc,0xdd,0x7d,0x75,0xe5,0xbd,0x90,0xbc,0x6a,0xc4,0x35,0xd6,0xa4,0x40,0xef,0x85,0x2e,0x9a,0x1c,0x8c,0x53,0xde,0x03,0xbf,0x19,0x33,0x65,0xd7,0x35,0xaa,0xf2,0x9c,0x51,0x62,0xa6,0x17,0xe3,0x64,0xe7,0xf9,0x44,0x16,0x8d,0x0f,0xb4,0x8f,0xef,0x40,0x55,0x8f,0x45,0x42,0x97,0xcc,0x3d,0xd5,0x08,0x66,0x2c,0xf2,0x3f,0xb8,0x8e,0x19,0x54,0xaa,0x45,0xd1,0xc5,0xe1,0x15,0xbc,0xc3,0x6f,0x05,0xb3,0xe0,0x98,0xd5,0x55,0x22,0x0f,0x40,0xbe,0x26,0x29,0xb3,0x45,0x07,0xb8,0x46,0x4c,0x54,0xc2,0x7b,0x5d,0xec,0x78,0xda,0x8f,0x22,0x65,0x05,0x14,0x79,0x7a,0xf8,0x6a,0x25,0x12,0xbc,0xb7,0xe2,0x92,0x33,0x79,0xef,0x6d,0x73,0xc1,0x37,0x00,0x6c,0x1b,0x38,0xf5,0x1e,0x37,0xf9,0x35,0x85,0xe2,0x90,0x41,0xa3,0xe4,0xe3,0xaf,0x46,0x00,0x7c,0xe1,0x3b,0x8b,0x5f,0x7b,0x17,0xd5,0xd6,0x5d,0x7d,0x56,0x68,0xe4,0x27,0xbc,0xbe,0x7e,0xc1,0xd7,0xc4,0x08,0xc0,0x54,0xa4,0x8c,0x1a,0xe7,0x97,0xbf,0x99,0xac,0xbc,0x8d,0x26,0x07,0x52,0x29,0x35,0xfd,0x66,0x5e,0xa7,0x82,0x2d,0x93,0x0f,0x23,0xea,0xbf,0xf7,0x83,0xbb,0x23,0x69,0x75,0x69,0xe2,0x04,0xb9,0x43,0x14,0x1e,0x00,0xc0,0x88,0x10,0x95,0x6b,0xe0,0x52,0x53,0x65,0xdb,0xab,0x54,0xed,0x48,0xcb,0x76,0x96,0x4c,0xcd,0xf5,0xcb,0xd3,0xae,0xe7,0x28,0x2d,0x4a,0x00,0x00,0xd2,0x78,0x4d,0x7b,0x8f,0xab,0x16,0xb2,0xf7,0xf0,0xd5,0x22,0x57,0x32,0xb1,0xef,0xbc,0x4e,0xb1,0xcf,0xed,0xeb,0x43,0xfd,0xe7,0x9b,0x69,0xec,0xc0,0xfb,0xea,0xa1,0xe6,0xb4,0x07,0x28,0x67,0x3b,0xd4,0xb2,0xe9,0x8a,0x0d,0x4a,0x8f,0x02,0xf8,0x53,0x95,0x07,0x30,0xf2,0x8d,0x35,0xeb,0x12,0xfc,0xc7,0x97,0x68,0xb8,0xe1,0x8e,0x4b,0xda,0x0e,0x58,0xa3,0x31,0xa2,0xf7,0x1d,0x7c,0xcc,0x2d,0x45,0x1b,0x32,0xb1,0xc6,0x5c,0x31,0x2a,0xcf,0x47,0xee,0x51,0x3b,0x21,0x95,0x4c,0x41,0xc0,0x0c,0x87,0x38,0x72,0xee,0x94,0xcf,0x14,0xf4,0x60,0x37,0x42,0x53,0x61,0xf4,0xbd,0xb5,0x48,0x21,0xf7,0x11,0x46,0x0c,0xeb,0xae,0x8c,0x07,0x50,0x8a,0x92,0x19,0xf8,0x8f,0xa6,0xbe,0xda,0xa6,0x78,0xee,0xd5,0x01,0x94,0x4a,0x16,0xae,0x6f,0x7b,0x5b,0xb7,0xa2,0xe1,0xe3,0x57,0xe7,0x0d,0x7b,0x98,0x46,0x1a,0x2c,0x71,0xcb,0x0f,0xa7,0x62,0xd6,0xad,0x98,0x24,0x08,0x1d,0x37,0xf2,0x92,0xfd,0x4b,0xe8,0xb8,0x4c,0x36,0x11,0x0d,0xc7,0x44,0x36,0x02,0x01,0xbe,0xeb,0xe0,0xbd,0x6c,0x9d,0x05,0xe8,0x69,0x25,0x6d,0x2f,0xf3,0xf9,0x95,0x17,0xb7,0xef,0xd2,0xa3,0x37,0x74,0x05,0x6c,0xb5,0x67,0x16,0x75,0xa8,0xb4,0x92,0xe9,0xf5,0xf2,0x62,0x0e,0xb8,0xef,0x93,0x81,0xd3,0xd1,0xdf,0x19,0x93,0x8b,0x7b,0x5f,0xfa,0xac,0x59,0xbc,0x81,0x10,0xfa,0x87,0xba,0x8d,0x7a,0x3d,0x01,0x65,0xf8,0xe4,0x1d,0xd0,0xf8,0x04,0xf1,0x1b,0x9d,0xed,0x0f,0x35,0x2a,0x59,0x78,0x35,0xd0,0x63,0x07,0xa8,0xe0,0xc6,0xef,0x4d,0x21,0x90,0x43,0x39,0xe1,0xcf,0x45,0x89,0x23,0xa3,0xe8,0x9e,0x02,0x5d,0x94,0x53,0x47,0x36,0x6c,0x02,0xf3,0xdd,0x63,0x68,0xd4,0xe4,0x7e,0x85,0xd3,0xd2,0xa9,0x70,0x5b,0xd5,0x79,0x61,0x85,0x2e,0x5a,0x57,0x9f,0x93,0xb1,0xc5,0x14,0xc5,0x39,0xf4,0x9e,0xa1,0x16,0x3a,0x2a,0x49,0x3b,0x0e,0xfc,0xb4,0x7f,0x47,0x48,0xf6,0xa9,0x9e,0x10,0xbf,0x70,0x78,0x28,0x2e,0x4a,0xce,0x18,0x13,0x6e,0x2a,0x8b,0x3e,0xe0,0xa3,0x80,0xdc,0xd3,0xb3,0xef,0x3e,0x65,0xe1,0xb8,0x15,0x72,0x89,0xd6,0x24,0x67,0xad,0x48,0x8b,0xa0,0x39,0x2b,0x2e,0x90,0xa1,0xed,0xed,0xcb,0xdc,0x93,0x1d,0xc1,0x72,0x98,0xcc,0xef,0x76,0x64,0x5c,0x7d,0x33,0x0a,0x05,0xc2,0xce,0x40,0xf8,0x9b,0x85,0x46,0x8f,0x35,0x7a,0x21,0x77,0x51,0xe1,0x54,0x63,0x13,0x04,0xec,0x4e,0x04,0xbb,0x45,0xb3,0x67,0x89,0x09,0xc7,0x4a,0xf5,0x1c,0xe3,0x70,0x36,0x4d,0x8f,0x4f,0x7e,0xb1,0xe6,0x1e,0x00,0x28,0x74,0x29,0xc9,0x96,0x1d,0xe8,0x32,0x2c,0xa9,0xa2,0x62,0x9b,0x13,0x09,0xd8,0x00,0xe9,0x2b,0xc1,0xdc,0x50,0x55,0xdc,0xc7,0x97,0xf3,0x38,0x66,0xeb,0x0c,0xfd,0x8d,0x49,0x02,0x50,0xd4,0x8f,0xfc,0xa8,0x02,0x2f,0x49,0x29,0x0e,0x2d,0x53,0x76,0x16,0x2f,0xba,0xa9,0x82,0xd1,0x64,0x53,0xc8,0x25,0xb3,0x5f,0x65,0x15,0x63,0x5e,0xa9,0x2b,0xea,0x72,0x36,0x7b,0xaa,0x54,0xde,0x3f,0x9e,0xae,0xa6,0x95,0x42,0xa8,0x1a,0x41,0x27,0xf7,0x1c,0xba,0xa2,0x57,0xf3,0x24,0xfe,0xfe,0xf1,0x4f,0x08,0xfb,0xd6,0x5a,0x04,0x9c,0xd2,0xfb,0x36,0x25,0x94,0xa8,0xe2,0x3f,0xf1,0xa2,0x61,0x7d,0xb5,0xb1,0x58,0xf6,0xf0,0x1c,0xf5,0x0a,0xb0,0xed,0x95,0xc6,0xe7,0x09,0x84,0x11,0x64,0x10,0x8b,0x06,0xe1,0xb4,0x0a,0xb0,0xab,0x11,0xc4,0x08,0x30,0x1d,0x3d,0x9d,0x8e,0xa6,0x9e,0x96,0x8a,0x96,0x00,0xb3,0xd1,0x7f,0x38,0x01,0x1c,0xe2,0x80,0x74,0xe2,0xc2,0xe1,0x0b,0xf6,0x19,0x7c,0x60,0x2d,0x8d,0x0c,0xe7,0xd3,0xa3,0xef,0x2d,0x89,0x62,0x3b,0xc9,0xf1,0x2e,0xa3,0x38,0x79,0x1e,0x92,0x66,0xbb,0x8c,0xe0,0x2b,0x12,0x4c,0x6c,0x79,0x29,0xba,0xea,0x69,0x32,0x44,0x09,0x84,0x54,0xa0,0x80,0xeb,0x75,0x23,0xe1,0x3b,0xb1,0xb7,0xc5,0xb6,0x77,0x5f,0xab,0xab,0xab,0xbe,0x90,0x75,0xfe,0x56,0x87,0xaa,0x45,0x13,0x97,0xbb,0x9c,0xfc,0xcd,0x05,0x12,0x43,0xe9,0xbf,0x5a,0xef,0x24,0x06,0x2d,0x33,0x5d,0xe5,0xfc,0xe2,0x4e,0x9d,0xdb,0xde,0x11,0x91,0x05,0x2d,0x80,0xc3,0x6d,0xf9,0xf8,0x43,0x48,0x72,0xf2,0x77,0xed,0x4f,0x5a,0x1c,0xe8,0xeb,0xd3,0xb9,0x60,0x82,0x4a,0x4e,0x4f,0x10,0x01,0xb0,0x4c,0xb6,0x85,0xf9,0xbe,0xe4,0xd0,0xdd,0xb0,0xc5,0x71,0x59,0x8a,0xc2,0x02,0x1a,0x66,0x06,0xfd,0x23,0x34,0x5c,0x6f,0xbb,0x84,0xf0,0xce,0x05,0xfe,0x52,0x73,0x45,0x21,0xb7,0xb0,0x7c,0x63,0x88,0xd3,0xa3,0xb9,0x93,0x18,0xbf,0x01,0x31,0x50,0x4a,0xa9,0xdf,0xba,0xf5,0x48,0xf9,0xd3,0x2a,0x9c,0xd4,0xc6,0x89,0x35,0x24,0xb1,0x13,0x30,0xa2,0xd3,0xaa,0xd3,0xed,0x2a,0x58,0x96,0x6e,0xbb,0x01,0x34,0x46,0x5d,0x54,0x3f,0xd7,0x79,0x7a,0xf5,0x49,0xf5,0x68,0xea,0xeb,0xe9,0x57,0xf6,0x4f,0xec,0x85,0x46,0x74,0x90,0x2b,0x97,0x55,0x87,0x56,0x98,0x69,0x46,0xea,0x3a,0xb7,0xa2,0x51,0xcb,0xbe,0xa1,0x1a,0x68,0x7b,0xd4,0x3f,0x5d,0x0b,0xd8,0x9c,0xd2,0xca,0xba,0x61,0xd5,0x21,0x83,0x74,0x99,0x0e,0xe8,0xb9,0x22,0x19,0xed,0x25,0xdc,0xa0,0x11,0xc6,0x8a,0x97,0x57,0xc0,0x13,0xbd,0x83,0x7b,0x2d,0xd7,0x34,0xe3,0x75,0x1f,0x64,0xfc,0xb4,0xb2,0x3d,0xcd,0x6b,0xc5,0x7e,0xa5,0x67,0xf5,0x71,0x6e,0x17,0x36,0x72,0x44,0x75,0x1e,0x23,0x03,0xb2,0x2a,0x95,0x3e,0x77,0x27,0x56,0x95,0x6c,0xdc,0xc0,0x13,0xff,0xd2,0xc3,0x24,0x90,0x75,0x44,0x22,0xa5,0x72,0x52,0x9d,0x4c,0x92,0xf1,0xeb,0xb1,0x9f,0x1d,0xad,0x4d,0x03,0x6f,0x2f,0xdf,0x31,0xca,0x91,0x01,0xbd,0xf8,0x1a,0xea,0x94,0x8a,0xed,0xcf,0x21,0x7a,0xa8,0xfc,0xcd,0x7a,0x07,0x71,0xaa,0x27,0x53,0xe1,0xa8,0x23,0xbf,0x41,0xc9,0x53,0x77,0xa2,0xff,0xa6,0x1b,0x22,0x65,0x13,0x81,0x53,0xce,0x86,0xd2,0xc8,0x7d,0xd0,0x7a,0x4b,0x32,0xd2,0x7f,0x5f,0x28,0x72,0x64,0x14,0x31,0xce,0x9a,0x18,0xa5,0x02,0xaa,0xef,0xd9,0xaf,0xc5,0xb0,0xd1,0x3c,0xd4,0x6c,0x35,0x7e,0x38,0xe6,0x9e,0x1e,0xe9,0x45,0xad,0xd1,0x99,0x29,0x32,0xa5,0xb1,0xe5,0xc5,0x62,0x9c,0x9f,0x48,0xf7,0x66,0x18,0x53,0xda,0x00,0x78,0x7c,0x9d,0x78,0xfb,0x92,0x55,0x53,0xbf,0x07,0xa5,0x0d,0xd5,0xb9,0xd9,0x35,0x85,0x34,0x20,0xe4,0xd1,0xa7,0x1a,0xe6,0x2f,0xf9,0x0c,0xa1,0x93,0xcd,0xd6,0xc2,0xf4,0xbe,0xd2,0x63,0x41,0x5a,0xaf,0x9a,0x35,0x09,0x4b,0xc2,0xa2,0x2e,0x2a,0x66,0x3c,0x76,0x45,0x00,0x1c,0xd1,0x90,0xb7,0xbc,0x17,0xc7,0x5f,0xea,0xdf,0x8e,0x87,0xce,0x5c,0x24,0xb7,0x63,0xb6,0x58,0x4e,0xd3,0x2e,0x71,0xb0,0x26,0x81,0x42,0xea,0x3e,0xd6,0x89,0x81,0x57,0xbf,0x92,0x3b,0xeb,0xf0,0x19,0x2d,0x1b,0xf5,0xee,0x30,0xa7,0xd3,0x51,0x63,0x4a,0x60,0xb5,0x04,0xdd,0xe3,0x8a,0x2e,0x11,0x4f,0x7a,0xe9,0xbf,0x17,0x6d,0x4a,0x18,0xba,0x28,0x95,0xa7,0xbb,0x4b,0x47,0x44,0x4a,0x9b,0xa8,0xdb,0xb4,0xc1,0x24,0xcd,0x41,0xbb,0xb3,0x2f,0x4b,0xcb,0x1d,0xe4,0x8c,0x4a,0xbb,0x51,0x06,0x07,0xa0,0x01,0xb5,0xa0,0x00,0xbb,0xa4,0x36,0x18,0xb6,0xc1,0x9e,0x43,0x51,0x7b,0x45,0xb4,0x24,0x05,0x92,0x8b,0x67,0xc7,0x13,0x88,0x18,0x58,0xba,0xd3,0xa4,0x25,0x11,0xc2,0x71,0x6f,0xf9,0xcd,0x33,0x20,0x34,0xb6,0x72,0xb5,0x2f,0xf1,0x66,0x10,0x80,0x5c,0xdb,0xe7,0x54,0x4a,0x8a,0x84,0xb6,0x6e,0x1c,0x74,0x5a,0x73,0xc1,0xb6,0xbc,0xda,0x5b,0x77,0xb9,0x51,0xf3,0x6c,0x0f,0x7a,0x53,0x72,0xde,0x9e,0x5d,0x1f,0x9b,0xbc,0xde,0x88,0x43,0xc6,0x90,0x90,0x02,0xdd,0xa4,0x87,0x5e,0x67,0x57,0x1a,0xf0,0xbe,0xc5,0x81,0x85,0x6c,0x32,0xc0,0x9c,0x24,0x0e,0x66,0x4e,0x76,0x1e,0x57,0xcd,0x0d,0x8d,0xc8,0xa7,0x1c,0xb9,0x18,0xa5,0x76,0x2d,0x11,0x12,0x85,0xcd,0x8b,0x56,0x13,0xdd,0xbd,0x0c,0xa0,0x8a,0xc0,0x34,0x2b,0x2b,0xde,0xe3,0x8f,0x96,0xfa,0x75,0x4b,0xb2,0xb0,0x87,0x17,0x9c,0x11,0x3c,0x93,0x98,0x6a,0x81,0x03,0x56,0xeb,0x94,0x54,0x0b,0x93,0xcb,0x9d,0xec,0x4a,0xa9,0x29,0x0f,0xf1,0x2e,0xc1,0xaa,0x2e,0x65,0x6c,0x9b,0xe3,0xd5,0x90,0x75,0x3c,0x36,0x6c,0x60,0x14,0x06,0xc0,0x61,0xbc,0x22,0x03,0x3a,0x1f,0xd1,0xf4,0xe1,0x11,0x1d,0x03,0x9b,0x88,0x13,0xb9,0x83,0xcb,0x50,0x6c,0x3e,0xa7,0xff,0x30,0x57,0x98,0x3e,0x8b,0xf0,0x16,0x82,0xfb,0xb0,0x0f,0x43,0x00,0x53,0x13,0xc8,0x2c,0x13,0x92,0x91,0x8a,0x61,0x65,0xa1,0x33,0x38,0xff,0xe1,0x1a,0x99,0x2c,0x1f,0xb3,0xd1,0x03,0x2a,0xa6,0x79,0xa4,0x18,0xc8,0xba,0x4f,0x8a,0x0b,0xc1,0x99,0xe1,0x0c,0xf6,0xbd,0x77,0xa1,0x4f,0xdd,0x6a,0x06,0x09,0x35,0x14,0x34,0x8e,0x3a,0x89,0x74,0x43,0x4a,0xe8,0xa3,0x67,0x63,0x69,0xc6,0xbe,0x2c,0xf9,0x0e,0x67,0x2b,0x34,0x3f,0xce,0x04,0xac,0x6b,0x22,0xe0,0xcf,0x47,0x56,0x8b,0xc4,0x5d,0x70,0xa6,0x8e,0x68,0xc6,0x49,0xa4,0x83,0x0a,0xe2,0x18,0x59,0x0c,0x1a,0x43,0x7e,0x7a,0x23,0xa5,0x4e,0xfe,0x44,0xf6,0x70,0x86,0xeb,0x69,0x7b,0x9f,0xa5,0x78,0x35,0xf0,0xb8,0xf7,0x0f,0x0a,0x92,0x92,0x26,0xef,0xb3,0x36,0xc0,0xe2,0x18,0x33,0xa0,0x28,0x21,0x8c,0xd6,0x37,0x32,0xc8,0x0a,0xa4,0x77,0xe6,0x2d,0x14,0x1d,0xba,0x81,0x85,0x4f,0x70,0xda,0x68,0xda,0xff,0x4a,0x84,0xcb,0x6d,0xe7,0x79,0x25,0x4e,0x8a,0x97,0xe7,0x35,0x65,0x37,0x4a,0xf4,0x09,0x2a,0xf0,0x5c,0xbd,0x66,0x54,0xaf,0xc3,0xfd,0x72,0xf0,0xae,0x23,0x26,0x95,0xcb,0x66,0x68,0xea,0xfe,0xcc,0x40,0x69,0xbd,0x90,0xbb,0x52,0x8b,0x83,0xef,0xa2,0xfb,0xcd,0xbd,0x93,0xb2,0x89,0x92,0x96,0x21,0xed,0x74,0xd8,0x08,0x73,0x8f,0xc1,0x03,0xee,0xb1,0x05,0x51,0x08,0x51,0xfc,0x93,0x19,0xf1,0x71,0xea,0x0c,0xed,0x0b,0x97,0xb5,0xb9,0xfb,0x5e,0xf9,0x85,0x18,0x6b,0xc5,0x20,0x98,0xf9,0xeb,0x47,0x6f,0x67,0xb7,0xcc,0x76,0x65,0xd4,0x75,0x87,0x97,0x5c,0xb4,0x5a,0x50,0xfc,0x64,0x10,0x07,0x19,0xbf,0x76,0x34,0x5f,0x0f,0xdf,0x1e,0x09,0xef,0xe9,0xfb,0x80,0x0d,0xc1,0x14,0xe4,0x6b,0xe0,0x87,0x9a,0x19,0x5c,0xc0,0x68,0x70,0xe2,0x3d,0x26,0x31,0xda,0xe7,0x1c,0x39,0x94,0x48,0x1c,0x87,0x61,0xc4,0x0d,0x07,0xc5,0xbf,0xca,0x95,0xe7,0x18,0xb7,0xb2,0x25,0x85,0xaf,0x03,0xed,0x34,0x17,0x5a,0x46,0xd5,0x7a,0xf3,0x51,0x8e,0x32,0xa7,0xfc,0x1a,0xa4,0x48,0x27,0x32,0xa8,0x1a,0x87,0xf7,0x24,0xf8,0xd2,0xe7,0x80,0xb3,0xa3,0x9d,0x45,0x1a,0x38,0x0f,0x75,0xc2,0xd6,0x80,0xcc,0x72,0x13,0xea,0xb1,0xd4,0xa5,0x9d,0x39,0x4a,0xe3,0x81,0x0a,0x1c,0x90,0x81,0x8d,0x52,0xf9,0x3f,0xb2,0x03,0xe2,0xd8,0xb1,0xb5,0xfa,0x8f,0x60,0xb2,0xd5,0x85,0xd9,0x13,0x5d,0x64,0x88,0x46,0xf1,0x38,0xb8,0x69,0x53,0x24,0x2d,0x2b,0xb1,0xf2,0xec,0xdf,0x38,0x9b,0x4d,0xe7,0x65,0x18,0x17,0xb8,0xe4,0xe6,0x4b,0x33,0x3f,0x1a,0xac,0x52,0x3a,0x93,0xf2,0x74,0x8a,0x9c,0x38,0xff,0xbc,0x29,0xce,0xd4,0x57,0xb6,0xf9,0x78,0x1b,0x08,0xa6,0x7a,0x19,0x75,0xd0,0x31,0xcc,0xd7,0x15,0x45,0xc0,0x03,0x74,0x34,0x05,0x6c,0x24,0x34,0xd1,0x3e,0x6c,0x4b,0xee,0xbf,0x46,0xfc,0x12,0x22,0x2c,0x0b,0x2e,0xcc,0xd6,0x15,0x9d,0x5a,0xea,0x8e,0x55,0x4d,0x7a,0x09,0x65,0x2b,0x06,0xbf,0x7c,0xa6,0x99,0xa7,0x19,0x9e,0x71,0x6d,0x05,0xdd,0x55,0x30,0x41,0xa8,0xf2,0xb3,0x03,0xd2,0x36,0xa9,0xba,0xba,0xaf,0xb9,0xfa,0x52,0x8f,0x28,0xa2,0xca,0x2a,0xa7,0x80,0xb9,0x40,0x38,0x3c,0x09,0x9a,0xa6,0x5a,0x00,0x74,0xb8,0x3f,0xd1,0xf0,0xbc,0x5b,0x7b,0x5e,0x46,0xc2,0x5e,0x54,0x83,0x8b,0x3c,0xbc,0xfc,0x95,0xf8,0x7f,0x1d,0x47,0x1b,0x3b,0xa8,0x94,0x43,0x4f,0xa5,0x89,0x52,0xfd,0xcb,0x77,0xf1,0x61,0x37,0x26,0x93,0x30,0x6d,0xba,0x4e,0x8f,0x21,0x6d,0x1c,0x8e,0x5c,0xaf,0xf0,0xfe,0x83,0x60,0xa5,0x1c,0x60,0x76,0x36,0x44,0x16,0x9f,0xdc,0x6a,0x82,0x67,0xf2,0xe3,0xf9,0x09,0xa6,0x1b,0x2a,0x67,0x8b,0xce,0x6a,0xe9,0x04,0x03,0xa8,0x36,0xb1,0xa7,0xb7,0xe8,0xcd,0x8b,0x54,0xc3,0x70,0x87,0xa9,0xe1,0x44,0x46,0xd9,0x5e,0x69,0x08,0xd2,0xee,0xdb,0xfc,0xc6,0x53,0xe0,0x2f,0xdf,0x77,0x1f,0x70,0x1a,0x79,0xb9,0xe5,0xa2,0x6e,0xd0,0xa9,0x47,0x84,0x20,0x70,0xf3,0xb5,0x70,0x17,0x42,0x21,0x12,0x19,0xe7,0x61,0x76,0x2c,0x37,0xf0,0xd0,0xa1,0xd1,0xb9,0x75,0x0f,0xee,0x57,0x7e,0x12,0x08,0x11,0x5c,0x66,0xac,0x07,0xec,0x09,0x1e,0x6a,0x3f,0xc4,0xaa,0x6a,0x25,0x3b,0xcb,0xa8,0x68,0xed,0xd3,0x15,0x4d,0xca,0xf5,0x16,0x2f,0x61,0x5e,0x85,0x49,0x0a,0x6c,0xa3,0x42,0xf3,0x4c,0x43,0xac,0x61,0xa3,0xea,0x6b,0xfe,0xef,0xd8,0x50,0xe1,0x90,0xeb,0x1d,0x8d,0xa4,0xd2,0x8b,0x5e,0xce,0xeb,0x16,0x78,0xc0,0x24,0x33,0xec,0xd5,0xd4,0x8b,0x25,0x36,0x40,0x42,0x57,0xe8,0xca,0x7b,0xef,0x58,0x55,0xf2,0xb8,0x13,0xed,0x2f,0x4c,0x40,0x94,0x45,0xa3,0x31,0x7c,0x9b,0xe1,0xa3,0x5a,0xe2,0xfb,0x4d,0x2b,0x87,0x92,0x1b,0x90,0x4b,0xf2,0xc1,0x4d,0xb5,0x14,0xce,0xe0,0x45,0x25,0x1c,0xfc,0x27,0x63,0x74,0xdb,0x15,0xc9,0x9d,0xea,0x15,0xac,0xde,0x19,0x7c,0x6e,0xb5,0x24,0x98,0x8e,0x39,0xb6,0x32,0x87,0xbe,0xb8,0x67,0x68,0x65,0xaa,0xa3,0xba,0xd1,0xb4,0x3b,0x8c,0xab,0x15,0xcb,0xf2,0x7a,0x49,0x87,0x59,0xe3,0x20,0x3a,0xbf,0x36,0x9e,0x97,0x24,0x2f,0x0b,0x01,0x54,0x14,0x9f,0x14,0xac,0x23,0x3c,0xdb,0x73,0xa2,0x2b,0x7f,0xb8,0xf0,0x93,0x25,0xbf,0x2a,0xce,0x83,0xbb,0x6b,0x5d,0xb8,0xa1,0x21,0xa2,0xb6,0x82,0x14,0x9a,0x69,0x13,0x1c,0xcc,0xe5,0x22,0x29,0x84,0x0b,0x11,0x3f,0xc7,0xb0,0xbc,0xc5,0x84,0x05,0xbf,0xe8,0x7f,0x1f,0x95,0xff,0xc2,0xe9,0x6f,0xc5,0x59,0x65,0x67,0xe9,0x43,0x64,0xdf,0xaa,0x6d,0x9d,0x5a,0x6e,0xb9,0x9a,0xe4,0xdd,0xf4,0x24]).unwrap(); + let sk = MLDSA87PrivateKey::from_bytes(&[ + 0x97, 0x92, 0xBC, 0xEC, 0x2F, 0x24, 0x30, 0x68, 0x6A, 0x82, 0xFC, 0xCF, 0x3C, 0x2F, 0x5F, + 0xF6, 0x65, 0xE7, 0x71, 0xD7, 0xAB, 0x41, 0xB9, 0x02, 0x58, 0xCF, 0xA7, 0xE9, 0x0E, 0xC9, + 0x71, 0x24, 0xD8, 0xE9, 0xEE, 0x4E, 0x90, 0xA1, 0x6C, 0x60, 0x2F, 0x5E, 0xC9, 0xBC, 0x38, + 0x51, 0x7D, 0xC3, 0x0E, 0x32, 0x9D, 0x5A, 0xB2, 0x76, 0x73, 0xBD, 0x85, 0xF4, 0xC9, 0xB0, + 0x30, 0x0F, 0x77, 0x63, 0x89, 0x88, 0x67, 0x50, 0xB5, 0x7C, 0x24, 0xDB, 0x3F, 0xC0, 0x12, + 0xE6, 0x1E, 0xDE, 0x59, 0x75, 0x33, 0x37, 0x37, 0x4F, 0xA7, 0x12, 0x49, 0x91, 0x54, 0x9A, + 0xF2, 0x43, 0x49, 0x6D, 0x06, 0x37, 0xCB, 0x3B, 0xE0, 0x5A, 0x59, 0x48, 0x23, 0x5B, 0xF7, + 0x98, 0x75, 0xF8, 0x96, 0xD8, 0xFE, 0x0C, 0xAB, 0x30, 0xC8, 0x49, 0x48, 0xDB, 0x4D, 0x63, + 0x15, 0xAA, 0xAF, 0x16, 0x0A, 0xC6, 0x24, 0x36, 0x64, 0x22, 0x01, 0x48, 0x16, 0x11, 0x09, + 0x11, 0x2C, 0x94, 0x02, 0x89, 0x22, 0x45, 0x2C, 0x62, 0xB8, 0x45, 0x00, 0x45, 0x2A, 0x08, + 0x96, 0x70, 0x90, 0x12, 0x6E, 0x14, 0x93, 0x70, 0xD4, 0x46, 0x10, 0x84, 0x44, 0x51, 0x58, + 0x96, 0x91, 0x0C, 0xA9, 0x29, 0x82, 0xB2, 0x41, 0xC9, 0x08, 0x71, 0xC4, 0x28, 0x68, 0x04, + 0x96, 0x89, 0x48, 0x40, 0x85, 0x9B, 0x22, 0x6D, 0x1C, 0x28, 0x64, 0x59, 0x12, 0x41, 0x9C, + 0xB8, 0x91, 0x84, 0x04, 0x89, 0x44, 0x90, 0x05, 0xCB, 0x34, 0x62, 0xA0, 0x86, 0x90, 0x40, + 0x26, 0x92, 0x20, 0x99, 0x29, 0x13, 0x05, 0x69, 0x5C, 0x34, 0x68, 0xA4, 0x32, 0x8E, 0x19, + 0x26, 0x92, 0x59, 0x46, 0x10, 0x09, 0xA4, 0x49, 0x23, 0x42, 0x4D, 0x12, 0x36, 0x61, 0x58, + 0x10, 0x65, 0x01, 0x28, 0x90, 0x1A, 0x33, 0x4C, 0x99, 0x86, 0x31, 0xD3, 0xA2, 0x49, 0x09, + 0x82, 0x25, 0x43, 0x14, 0x28, 0xC0, 0x38, 0x81, 0x03, 0x15, 0x4D, 0x5B, 0x28, 0x86, 0x08, + 0x87, 0x48, 0x23, 0x31, 0x52, 0x94, 0x22, 0x25, 0xC3, 0xC0, 0x4D, 0xA4, 0x98, 0x21, 0x98, + 0x40, 0x20, 0xD1, 0x42, 0x86, 0xCB, 0x40, 0x70, 0x5B, 0xB0, 0x71, 0x9C, 0x96, 0x2C, 0xC1, + 0x12, 0x06, 0x53, 0x46, 0x09, 0x0C, 0x45, 0x02, 0x14, 0x46, 0x6E, 0x91, 0xB4, 0x21, 0x54, + 0xB0, 0x8C, 0xE4, 0x46, 0x42, 0x9A, 0x20, 0x8C, 0x01, 0x21, 0x25, 0x13, 0x41, 0x05, 0x5A, + 0x40, 0x22, 0x13, 0xC9, 0x0C, 0xA0, 0x18, 0x40, 0x52, 0xC2, 0x30, 0xCB, 0x34, 0x2C, 0x4B, + 0xC8, 0x68, 0x1B, 0xA4, 0x60, 0x49, 0x84, 0x84, 0x63, 0x30, 0x29, 0x4A, 0xA0, 0x69, 0x5B, + 0x80, 0x04, 0xD2, 0x38, 0x0A, 0x14, 0x26, 0x4C, 0xE2, 0xB2, 0x44, 0x8B, 0xA2, 0x11, 0x24, + 0x46, 0x49, 0xC4, 0x14, 0x52, 0x0B, 0x42, 0x71, 0x03, 0xB2, 0x10, 0x92, 0x28, 0x80, 0x01, + 0x24, 0x88, 0xE3, 0x08, 0x11, 0x0A, 0x05, 0x28, 0x19, 0xC4, 0x81, 0x00, 0x20, 0x22, 0xDC, + 0x44, 0x68, 0x42, 0x12, 0x22, 0x44, 0x00, 0x2A, 0xC9, 0x26, 0x6A, 0x0C, 0x87, 0x31, 0xE0, + 0xC0, 0x44, 0x99, 0x14, 0x84, 0x18, 0x36, 0x0D, 0x11, 0x37, 0x42, 0x22, 0x18, 0x8C, 0x63, + 0xB2, 0x91, 0x0C, 0x98, 0x08, 0xA1, 0xA0, 0x01, 0x08, 0x92, 0x44, 0x04, 0x13, 0x24, 0x5C, + 0x98, 0x71, 0x82, 0x84, 0x71, 0x84, 0x32, 0x52, 0x51, 0xB0, 0x31, 0x9C, 0x42, 0x2E, 0x1A, + 0xA8, 0x28, 0x02, 0x08, 0x91, 0x01, 0xC0, 0x89, 0x0B, 0xC7, 0x05, 0x8A, 0x24, 0x65, 0x22, + 0xC2, 0x64, 0x4C, 0x88, 0x91, 0x5C, 0x82, 0x68, 0x13, 0xA5, 0x64, 0x50, 0x20, 0x86, 0x21, + 0x04, 0x02, 0x91, 0x94, 0x44, 0x48, 0x22, 0x30, 0x22, 0x39, 0x4A, 0x02, 0x98, 0x84, 0x09, + 0xA2, 0x88, 0x19, 0x19, 0x29, 0x44, 0x48, 0x8C, 0x22, 0x95, 0x0C, 0xA1, 0x04, 0x72, 0x04, + 0x87, 0x70, 0x12, 0x21, 0x10, 0x42, 0x06, 0x84, 0x1B, 0x49, 0x85, 0x89, 0x06, 0x4A, 0xD3, + 0x36, 0x08, 0xDB, 0xC0, 0x40, 0x58, 0xB6, 0x51, 0x0C, 0xA7, 0x09, 0x8C, 0x24, 0x61, 0x99, + 0x90, 0x64, 0x8C, 0xC2, 0x90, 0x5B, 0x24, 0x90, 0x10, 0xA3, 0x49, 0x03, 0x25, 0x61, 0x43, + 0x32, 0x8A, 0x11, 0x98, 0x44, 0xC8, 0xB2, 0x20, 0x04, 0x38, 0x41, 0x10, 0x47, 0x2C, 0x19, + 0xC6, 0x44, 0x1C, 0x25, 0x2C, 0x04, 0x88, 0x30, 0xD9, 0x46, 0x69, 0x9B, 0x20, 0x00, 0x1B, + 0x46, 0x82, 0x5A, 0xA4, 0x80, 0x5B, 0xA0, 0x49, 0x18, 0x90, 0x25, 0x00, 0x26, 0x80, 0x0B, + 0xC2, 0x31, 0x5A, 0x40, 0x72, 0x54, 0xC6, 0x20, 0xC1, 0xB0, 0x31, 0x24, 0xB1, 0x4D, 0x10, + 0x95, 0x28, 0x14, 0x00, 0x0A, 0xA0, 0xC8, 0x4D, 0x54, 0xA2, 0x88, 0x23, 0x98, 0x81, 0x60, + 0x90, 0x04, 0x02, 0x16, 0x2C, 0x13, 0x21, 0x40, 0x91, 0x86, 0x8D, 0x08, 0xC2, 0x91, 0x91, + 0x14, 0x26, 0xD0, 0xB4, 0x0C, 0x09, 0xC6, 0x60, 0x51, 0x44, 0x2E, 0x04, 0x11, 0x26, 0x00, + 0x29, 0x11, 0x93, 0xC2, 0x08, 0x63, 0xA4, 0x31, 0x22, 0x00, 0x28, 0xC1, 0x14, 0x08, 0x0C, + 0x40, 0x2C, 0x41, 0x14, 0x06, 0x9C, 0x20, 0x72, 0x54, 0x22, 0x06, 0x8B, 0x08, 0x4D, 0xA1, + 0x48, 0x69, 0x10, 0x30, 0x41, 0x1C, 0x28, 0x49, 0x44, 0x18, 0x8E, 0xCC, 0x96, 0x48, 0xD9, + 0x42, 0x50, 0x1B, 0x06, 0x49, 0x0C, 0x45, 0x88, 0x23, 0x04, 0x0D, 0x20, 0x30, 0x2E, 0x23, + 0x85, 0x2C, 0x14, 0x07, 0x30, 0x40, 0xB6, 0x85, 0x4C, 0xC0, 0x20, 0x44, 0x86, 0x20, 0x19, + 0x00, 0x6C, 0x54, 0x02, 0x48, 0xCC, 0x88, 0x6C, 0x59, 0x06, 0x32, 0x49, 0x14, 0x84, 0x04, + 0xC7, 0x50, 0x13, 0x49, 0x28, 0xE4, 0x06, 0x09, 0xD3, 0xC6, 0x10, 0xC8, 0x28, 0x4C, 0x23, + 0x39, 0x44, 0x52, 0xA4, 0x64, 0xCC, 0xA8, 0x49, 0x44, 0x38, 0x32, 0x0A, 0x89, 0x84, 0x00, + 0x34, 0x2C, 0x22, 0x85, 0x8D, 0x10, 0x31, 0x09, 0x09, 0x32, 0x65, 0x1C, 0x89, 0x8C, 0x40, + 0x40, 0x29, 0x21, 0x85, 0x00, 0x09, 0xA1, 0x6D, 0x84, 0xC0, 0x64, 0xE2, 0x02, 0x2D, 0x48, + 0x04, 0x40, 0x12, 0x09, 0x8E, 0xE0, 0x42, 0x2E, 0x93, 0x44, 0x08, 0x12, 0x10, 0x6A, 0x01, + 0x84, 0x05, 0x92, 0x30, 0x8A, 0xCB, 0x34, 0x8E, 0xA2, 0x26, 0x2E, 0x5C, 0x86, 0x11, 0x0B, + 0x35, 0x08, 0x18, 0x10, 0x00, 0x02, 0x34, 0x26, 0x24, 0x23, 0x89, 0xD1, 0x84, 0x00, 0x24, + 0x46, 0x60, 0x13, 0xB2, 0x49, 0x24, 0x28, 0x46, 0x18, 0x02, 0x71, 0xA0, 0x38, 0x90, 0x89, + 0x14, 0x44, 0xD3, 0x96, 0x2D, 0xA3, 0x18, 0x40, 0x23, 0x27, 0x21, 0xC0, 0x18, 0x50, 0x43, + 0xC8, 0x04, 0x41, 0x42, 0x8D, 0x5C, 0x26, 0x41, 0x44, 0xA2, 0x6D, 0x48, 0x12, 0x0E, 0x40, + 0x32, 0x25, 0x0B, 0x14, 0x82, 0x0A, 0x48, 0x2E, 0xCB, 0x82, 0x88, 0x03, 0xA3, 0x60, 0x1B, + 0x25, 0x26, 0x8C, 0xB8, 0x20, 0x24, 0xB0, 0x85, 0x98, 0x04, 0x21, 0x08, 0xA7, 0x2C, 0x83, + 0x38, 0x64, 0x54, 0x32, 0x89, 0x01, 0x04, 0x01, 0x23, 0x49, 0x84, 0x02, 0x95, 0x69, 0xD1, + 0xA4, 0x4D, 0x13, 0xA4, 0x0C, 0x91, 0x46, 0x0D, 0x61, 0x94, 0x80, 0x90, 0x38, 0x45, 0x5C, + 0xC6, 0x50, 0x01, 0x17, 0x20, 0x53, 0xC6, 0x28, 0x9B, 0x18, 0x10, 0x41, 0x12, 0x68, 0x90, + 0x12, 0x21, 0xC0, 0x10, 0x84, 0x42, 0x16, 0x92, 0x53, 0x82, 0x29, 0x81, 0x26, 0x49, 0xD8, + 0xA4, 0x05, 0x9A, 0x26, 0x24, 0x24, 0x03, 0x29, 0xE0, 0x40, 0x26, 0xD2, 0x02, 0x48, 0x11, + 0x24, 0x68, 0x11, 0x99, 0x89, 0x98, 0x14, 0x85, 0xC9, 0x20, 0x0D, 0x50, 0x12, 0x8C, 0x1C, + 0x08, 0x10, 0x02, 0x10, 0x00, 0x00, 0x95, 0x28, 0xC1, 0x28, 0x90, 0x59, 0xB4, 0x85, 0xD3, + 0x14, 0x65, 0x0A, 0x40, 0x6E, 0x11, 0x29, 0x65, 0x18, 0xC2, 0x4C, 0x21, 0x34, 0x65, 0xD8, + 0x30, 0x69, 0x10, 0x30, 0x52, 0x19, 0x31, 0x66, 0x8C, 0x18, 0x8A, 0xC8, 0xC0, 0x08, 0x4C, + 0x98, 0x30, 0xA3, 0xA6, 0x20, 0x41, 0x16, 0x22, 0x18, 0x05, 0x2E, 0x22, 0x25, 0x2A, 0x64, + 0xB8, 0x25, 0x0A, 0xB3, 0x01, 0x63, 0x20, 0x84, 0x09, 0x80, 0x09, 0x19, 0x28, 0x0E, 0x02, + 0x11, 0x01, 0xA3, 0x94, 0x11, 0xE3, 0x98, 0x6C, 0x58, 0x20, 0x21, 0x09, 0x41, 0x10, 0x60, + 0x36, 0x22, 0x08, 0x06, 0x71, 0x12, 0xC2, 0x85, 0x5A, 0xA0, 0x85, 0xC0, 0xC6, 0x84, 0x5C, + 0x38, 0x06, 0xCB, 0xB6, 0x69, 0x14, 0x84, 0x84, 0x53, 0x22, 0x82, 0xA1, 0xA6, 0x40, 0xCC, + 0x86, 0x00, 0xC4, 0x26, 0x22, 0xA0, 0xA8, 0x08, 0x98, 0x34, 0x72, 0xD4, 0x20, 0x41, 0x43, + 0xC4, 0x90, 0x48, 0x16, 0x68, 0x1B, 0x16, 0x52, 0x1A, 0x37, 0x02, 0x50, 0x20, 0x42, 0x48, + 0x48, 0x8A, 0x20, 0x11, 0x41, 0xE2, 0x00, 0x6C, 0xC0, 0xC2, 0x0C, 0x14, 0x06, 0x49, 0x11, + 0x31, 0x4D, 0x19, 0x06, 0x0A, 0x89, 0x46, 0x09, 0x1B, 0x81, 0x65, 0x44, 0xC8, 0x00, 0x82, + 0x06, 0x70, 0x00, 0x16, 0x72, 0xCC, 0x24, 0x50, 0x8A, 0x42, 0x89, 0x9C, 0x96, 0x90, 0x64, + 0x28, 0x70, 0x92, 0xB2, 0x68, 0x98, 0x26, 0x62, 0x61, 0x94, 0x40, 0xC1, 0x16, 0x89, 0xD8, + 0x42, 0x64, 0x1A, 0x21, 0x4E, 0x62, 0x90, 0x64, 0x21, 0xC8, 0x24, 0x8B, 0x28, 0x6D, 0x5C, + 0x42, 0x92, 0xA0, 0xC6, 0x4D, 0x0C, 0x85, 0x80, 0xCC, 0x88, 0x4D, 0xD4, 0x42, 0x8D, 0x42, + 0x34, 0x8A, 0x0B, 0x04, 0x51, 0xC3, 0x26, 0x86, 0x24, 0x25, 0x81, 0x12, 0x35, 0x06, 0xA0, + 0x44, 0x04, 0xC8, 0x94, 0x81, 0x5B, 0xB4, 0x31, 0x1C, 0x08, 0x06, 0x5C, 0x24, 0x08, 0x03, + 0x27, 0x6A, 0x20, 0xC2, 0x25, 0xE1, 0x80, 0x90, 0x19, 0xB4, 0x6D, 0xA3, 0x46, 0x0C, 0x4B, + 0x18, 0x60, 0x50, 0xC6, 0x2C, 0x1B, 0x92, 0x2D, 0x11, 0x15, 0x04, 0xA2, 0x00, 0x04, 0x21, + 0x48, 0x2E, 0xD8, 0x16, 0x06, 0xD2, 0x10, 0x8A, 0x83, 0xA2, 0x25, 0x08, 0x31, 0x0D, 0x09, + 0x38, 0x51, 0xD9, 0x48, 0x49, 0x0B, 0x16, 0x4C, 0x23, 0x32, 0x25, 0x19, 0x19, 0x02, 0x4A, + 0x44, 0x09, 0xD1, 0xB2, 0x21, 0x0B, 0x83, 0x2C, 0x23, 0x25, 0x85, 0x93, 0x16, 0x85, 0x44, + 0xA0, 0x44, 0x1B, 0x83, 0x50, 0x02, 0x22, 0x72, 0x4B, 0x04, 0x80, 0x9B, 0x14, 0x65, 0x21, + 0x93, 0x60, 0x18, 0x13, 0x0A, 0xD9, 0x46, 0x0D, 0x22, 0x45, 0x61, 0xC8, 0xB4, 0x40, 0xA1, + 0x42, 0x2D, 0x02, 0xB8, 0x09, 0x00, 0x14, 0x44, 0x9B, 0xB6, 0x11, 0x0B, 0x97, 0x8C, 0x40, + 0x10, 0x4A, 0x82, 0x14, 0x6A, 0xDA, 0x90, 0x05, 0x1C, 0x02, 0x8E, 0x0C, 0x19, 0x72, 0xA3, + 0xB4, 0x8D, 0x24, 0x30, 0x50, 0x11, 0x87, 0x09, 0x64, 0xC6, 0x28, 0xE4, 0x18, 0x92, 0x98, + 0xB4, 0x6C, 0x61, 0x16, 0x51, 0x40, 0x46, 0x0E, 0x1C, 0x32, 0x48, 0xDA, 0x20, 0x51, 0x88, + 0x36, 0x8A, 0x23, 0xB1, 0x21, 0x82, 0x90, 0x28, 0x1A, 0x15, 0x32, 0xE2, 0x18, 0x61, 0x92, + 0x04, 0x8E, 0x13, 0xB6, 0x90, 0x13, 0x13, 0x68, 0xC9, 0x84, 0x68, 0x4C, 0x40, 0x6D, 0x0B, + 0x33, 0x00, 0x81, 0x46, 0x4D, 0xD2, 0x38, 0x0C, 0x04, 0x96, 0x81, 0xA4, 0x88, 0x50, 0x02, + 0x90, 0x85, 0x22, 0xB0, 0x04, 0xD3, 0xA4, 0x71, 0xD2, 0x80, 0x10, 0xCA, 0x96, 0x40, 0x51, + 0xA6, 0x41, 0xA4, 0x84, 0x28, 0xE0, 0x08, 0x52, 0x0B, 0x30, 0x8C, 0xD2, 0x38, 0x0A, 0x0C, + 0x29, 0x51, 0xC3, 0x82, 0x09, 0xCA, 0x20, 0x91, 0xD8, 0x36, 0x92, 0xA3, 0xA6, 0x28, 0x92, + 0x42, 0x22, 0xA2, 0x16, 0x01, 0x1A, 0x34, 0x86, 0x37, 0xD9, 0xA6, 0x59, 0x16, 0x98, 0x81, + 0xEC, 0x21, 0xCF, 0x48, 0x11, 0x86, 0x9D, 0x1D, 0x7F, 0x13, 0x9F, 0x05, 0x37, 0xE9, 0x6F, + 0x11, 0x84, 0x58, 0x54, 0x05, 0xFD, 0x17, 0x80, 0x8A, 0xF1, 0xE0, 0x62, 0x39, 0xD3, 0xB3, + 0x4E, 0x5A, 0xCA, 0x8B, 0xF1, 0x36, 0x96, 0x77, 0xB4, 0x47, 0xAC, 0x71, 0x8A, 0xC4, 0x7D, + 0x85, 0x0C, 0x4D, 0x77, 0xB0, 0xBE, 0x31, 0xDC, 0x9F, 0x50, 0x8E, 0x39, 0x78, 0xF2, 0x42, + 0x74, 0xAB, 0x01, 0x85, 0xF7, 0x27, 0xAB, 0xDF, 0xF5, 0x9F, 0x44, 0x90, 0x37, 0x1B, 0xF0, + 0x46, 0x10, 0xE3, 0x64, 0xE6, 0x4E, 0xC8, 0x75, 0xEF, 0x9D, 0x20, 0xDC, 0x94, 0x07, 0x7E, + 0x1E, 0x16, 0x63, 0x27, 0xA8, 0x79, 0xB8, 0xAB, 0x51, 0x61, 0x60, 0xB2, 0xA3, 0xF7, 0x74, + 0x37, 0xB9, 0xB3, 0xCC, 0x7D, 0x17, 0xAE, 0xAD, 0xDC, 0x84, 0xDB, 0x62, 0x74, 0x6A, 0x35, + 0xAC, 0x09, 0x6F, 0x78, 0x2F, 0x62, 0xA7, 0xF0, 0x1A, 0xA6, 0xD6, 0x69, 0x3D, 0xEE, 0xC9, + 0x0B, 0x23, 0xC6, 0x69, 0x85, 0xA0, 0x23, 0x07, 0xE0, 0xA1, 0xCA, 0xE5, 0x98, 0xA6, 0x73, + 0x24, 0xDB, 0xA0, 0xF5, 0x2F, 0x22, 0x43, 0x22, 0x75, 0xE9, 0x32, 0x57, 0x06, 0x5C, 0x3B, + 0x7E, 0x5E, 0x1C, 0xFE, 0x1D, 0xFD, 0x4D, 0x0D, 0xF0, 0x86, 0xDF, 0x21, 0x24, 0x34, 0x14, + 0xA2, 0xD2, 0x7E, 0x20, 0x23, 0x0A, 0x82, 0x9B, 0xE4, 0xEB, 0x4C, 0x82, 0xC1, 0x6D, 0x35, + 0xF7, 0x8B, 0x0E, 0x5E, 0x19, 0x83, 0x32, 0xE0, 0x00, 0x74, 0xBB, 0x64, 0x61, 0x2F, 0xAB, + 0x17, 0xD4, 0xC8, 0x97, 0x1C, 0xB6, 0x8E, 0x5E, 0xDA, 0xB0, 0x36, 0x9F, 0x11, 0x57, 0xB3, + 0x46, 0x9A, 0xBD, 0x83, 0x84, 0xE2, 0xD9, 0x55, 0x3F, 0x1B, 0x78, 0xE7, 0x86, 0xE1, 0xEE, + 0x9D, 0x0B, 0x98, 0xD3, 0x9F, 0x83, 0xCC, 0xEC, 0xF3, 0x7D, 0x1E, 0xBD, 0x3A, 0x9D, 0x63, + 0xAE, 0xC7, 0x66, 0x16, 0x4A, 0x10, 0x17, 0x1A, 0x4F, 0xD8, 0xC6, 0x3D, 0xAF, 0x18, 0x2C, + 0x42, 0x12, 0x58, 0xC5, 0xF5, 0x29, 0xAA, 0x55, 0xCB, 0x7E, 0xBA, 0xE2, 0xE1, 0x65, 0x23, + 0x15, 0xE1, 0xF7, 0x1E, 0x8A, 0x74, 0x13, 0x14, 0x10, 0xD0, 0x32, 0x47, 0xED, 0xE1, 0x1D, + 0x34, 0xDB, 0x91, 0xF6, 0xF0, 0x8A, 0xA2, 0x47, 0x8F, 0xD7, 0x89, 0x67, 0x9C, 0x04, 0x94, + 0x9F, 0x71, 0xBC, 0x01, 0x71, 0xE0, 0x7E, 0x3A, 0x8B, 0xB5, 0x75, 0x3D, 0xBB, 0xDA, 0xA4, + 0x11, 0xA6, 0x35, 0x0A, 0xB4, 0x6E, 0xEF, 0xBF, 0x86, 0xFC, 0x55, 0x1C, 0x29, 0xEF, 0xE4, + 0xCD, 0xD7, 0x66, 0x1D, 0x5C, 0xF6, 0xC3, 0xDB, 0x22, 0xD0, 0xCE, 0xDD, 0xE5, 0x99, 0x85, + 0x44, 0x59, 0xD9, 0x7F, 0x20, 0xDF, 0x74, 0x55, 0xBD, 0xF3, 0x56, 0xA1, 0x98, 0xD0, 0xF7, + 0xEB, 0x6D, 0x34, 0x11, 0x1F, 0xC9, 0x40, 0xB2, 0x5C, 0x05, 0x43, 0xB7, 0x88, 0xED, 0xDA, + 0x9D, 0x26, 0x81, 0x0E, 0xAC, 0x3D, 0x6C, 0xC9, 0xC5, 0x13, 0x27, 0xC2, 0xCF, 0x83, 0xE8, + 0x87, 0xD4, 0x08, 0x9E, 0x19, 0x69, 0x5E, 0x11, 0xAD, 0xD8, 0x37, 0xF6, 0xF4, 0x40, 0xCC, + 0x36, 0x0F, 0x93, 0xF3, 0x2F, 0xEE, 0x8A, 0x96, 0x63, 0x71, 0x2C, 0x6B, 0xBD, 0x38, 0xC8, + 0x4A, 0xB7, 0xB5, 0x48, 0x23, 0xEC, 0x36, 0x3E, 0xB7, 0xE4, 0x2E, 0xB5, 0x9F, 0xC1, 0xFC, + 0xE6, 0x0F, 0xBD, 0x55, 0x30, 0x7B, 0x3E, 0xC8, 0x5F, 0xD9, 0xDA, 0xF3, 0x20, 0x6D, 0x7B, + 0x4B, 0x39, 0x17, 0xF1, 0xC8, 0xB7, 0xA9, 0x2E, 0x3C, 0x67, 0xD8, 0x98, 0x80, 0xFD, 0xF2, + 0xE4, 0x7F, 0x5A, 0x0C, 0x99, 0x45, 0x95, 0xDB, 0x17, 0x0A, 0xF4, 0x1B, 0xAB, 0xF5, 0xA2, + 0x5B, 0x4D, 0xC1, 0xC4, 0x2D, 0xD6, 0xA9, 0xDB, 0x27, 0x1E, 0x76, 0x4D, 0xE2, 0xFB, 0x01, + 0x5A, 0x49, 0xA8, 0x50, 0xC7, 0x91, 0x9B, 0xE4, 0x70, 0x06, 0xA3, 0x36, 0xE2, 0xE3, 0x25, + 0xFD, 0xE5, 0x3A, 0xC5, 0x99, 0x55, 0x4D, 0x0A, 0x7D, 0xE4, 0xEF, 0x45, 0xEC, 0x40, 0xC3, + 0x9D, 0x6B, 0xAF, 0xF3, 0x11, 0xBE, 0xEE, 0x75, 0xD8, 0x9E, 0x02, 0xAD, 0x31, 0xF4, 0xBE, + 0x4B, 0xD2, 0x0A, 0xE9, 0x19, 0x4F, 0x5E, 0xDD, 0xDA, 0xA6, 0x65, 0x07, 0x76, 0x11, 0x6E, + 0x9F, 0x27, 0x0F, 0x77, 0x71, 0x4A, 0xD7, 0xA8, 0xE8, 0x9A, 0xCE, 0xF7, 0x4B, 0x7F, 0xF7, + 0xD8, 0xDB, 0xEC, 0x27, 0xF8, 0x02, 0x0A, 0x98, 0x52, 0x47, 0xE2, 0xCD, 0xAC, 0xEF, 0x48, + 0x94, 0xA4, 0xD6, 0x8B, 0xA3, 0x7C, 0xA9, 0x12, 0xD6, 0xBE, 0x73, 0x50, 0x1C, 0x99, 0x51, + 0x81, 0xE5, 0xB7, 0x77, 0x23, 0x35, 0x0B, 0x36, 0x31, 0xDA, 0x37, 0x00, 0xE1, 0x3F, 0xD3, + 0x66, 0xE1, 0x31, 0xBF, 0x06, 0xB3, 0x6E, 0xB6, 0xB0, 0x34, 0x50, 0x93, 0x20, 0x9F, 0x0A, + 0x7B, 0xEF, 0xFA, 0xE1, 0xFD, 0xD8, 0x75, 0xB0, 0x06, 0x87, 0xC1, 0x16, 0x3C, 0x35, 0x3D, + 0x7D, 0x2A, 0xC9, 0x09, 0x37, 0xB3, 0x4E, 0x97, 0x8E, 0x92, 0xF8, 0x21, 0xAD, 0xC9, 0x66, + 0x22, 0x02, 0xEC, 0xE8, 0x9A, 0x17, 0xE7, 0xBB, 0x65, 0xAE, 0x17, 0xD8, 0x3B, 0x90, 0xDB, + 0xBE, 0x6A, 0x50, 0x1A, 0x4E, 0x13, 0x45, 0xBE, 0xE4, 0xE5, 0xA5, 0xB5, 0x3A, 0xF2, 0xE5, + 0xBA, 0x3D, 0x1E, 0xF3, 0xF4, 0xE0, 0x5A, 0xDF, 0x0B, 0x3A, 0x4C, 0xF2, 0xE5, 0x30, 0x36, + 0x0F, 0xEE, 0x64, 0x92, 0x99, 0x02, 0xB5, 0x71, 0xF6, 0xFD, 0x2E, 0x30, 0x56, 0x52, 0xA4, + 0xCB, 0x01, 0x0F, 0x79, 0xF8, 0x15, 0xE1, 0x8F, 0x2B, 0xBB, 0x8C, 0xC8, 0x9F, 0xA6, 0xFC, + 0x76, 0xF7, 0x7C, 0x89, 0xE2, 0x93, 0xCF, 0x17, 0x5A, 0x0B, 0x19, 0x58, 0x00, 0xFE, 0x72, + 0xD2, 0xCC, 0xDD, 0x7D, 0x75, 0xE5, 0xBD, 0x90, 0xBC, 0x6A, 0xC4, 0x35, 0xD6, 0xA4, 0x40, + 0xEF, 0x85, 0x2E, 0x9A, 0x1C, 0x8C, 0x53, 0xDE, 0x03, 0xBF, 0x19, 0x33, 0x65, 0xD7, 0x35, + 0xAA, 0xF2, 0x9C, 0x51, 0x62, 0xA6, 0x17, 0xE3, 0x64, 0xE7, 0xF9, 0x44, 0x16, 0x8D, 0x0F, + 0xB4, 0x8F, 0xEF, 0x40, 0x55, 0x8F, 0x45, 0x42, 0x97, 0xCC, 0x3D, 0xD5, 0x08, 0x66, 0x2C, + 0xF2, 0x3F, 0xB8, 0x8E, 0x19, 0x54, 0xAA, 0x45, 0xD1, 0xC5, 0xE1, 0x15, 0xBC, 0xC3, 0x6F, + 0x05, 0xB3, 0xE0, 0x98, 0xD5, 0x55, 0x22, 0x0F, 0x40, 0xBE, 0x26, 0x29, 0xB3, 0x45, 0x07, + 0xB8, 0x46, 0x4C, 0x54, 0xC2, 0x7B, 0x5D, 0xEC, 0x78, 0xDA, 0x8F, 0x22, 0x65, 0x05, 0x14, + 0x79, 0x7A, 0xF8, 0x6A, 0x25, 0x12, 0xBC, 0xB7, 0xE2, 0x92, 0x33, 0x79, 0xEF, 0x6D, 0x73, + 0xC1, 0x37, 0x00, 0x6C, 0x1B, 0x38, 0xF5, 0x1E, 0x37, 0xF9, 0x35, 0x85, 0xE2, 0x90, 0x41, + 0xA3, 0xE4, 0xE3, 0xAF, 0x46, 0x00, 0x7C, 0xE1, 0x3B, 0x8B, 0x5F, 0x7B, 0x17, 0xD5, 0xD6, + 0x5D, 0x7D, 0x56, 0x68, 0xE4, 0x27, 0xBC, 0xBE, 0x7E, 0xC1, 0xD7, 0xC4, 0x08, 0xC0, 0x54, + 0xA4, 0x8C, 0x1A, 0xE7, 0x97, 0xBF, 0x99, 0xAC, 0xBC, 0x8D, 0x26, 0x07, 0x52, 0x29, 0x35, + 0xFD, 0x66, 0x5E, 0xA7, 0x82, 0x2D, 0x93, 0x0F, 0x23, 0xEA, 0xBF, 0xF7, 0x83, 0xBB, 0x23, + 0x69, 0x75, 0x69, 0xE2, 0x04, 0xB9, 0x43, 0x14, 0x1E, 0x00, 0xC0, 0x88, 0x10, 0x95, 0x6B, + 0xE0, 0x52, 0x53, 0x65, 0xDB, 0xAB, 0x54, 0xED, 0x48, 0xCB, 0x76, 0x96, 0x4C, 0xCD, 0xF5, + 0xCB, 0xD3, 0xAE, 0xE7, 0x28, 0x2D, 0x4A, 0x00, 0x00, 0xD2, 0x78, 0x4D, 0x7B, 0x8F, 0xAB, + 0x16, 0xB2, 0xF7, 0xF0, 0xD5, 0x22, 0x57, 0x32, 0xB1, 0xEF, 0xBC, 0x4E, 0xB1, 0xCF, 0xED, + 0xEB, 0x43, 0xFD, 0xE7, 0x9B, 0x69, 0xEC, 0xC0, 0xFB, 0xEA, 0xA1, 0xE6, 0xB4, 0x07, 0x28, + 0x67, 0x3B, 0xD4, 0xB2, 0xE9, 0x8A, 0x0D, 0x4A, 0x8F, 0x02, 0xF8, 0x53, 0x95, 0x07, 0x30, + 0xF2, 0x8D, 0x35, 0xEB, 0x12, 0xFC, 0xC7, 0x97, 0x68, 0xB8, 0xE1, 0x8E, 0x4B, 0xDA, 0x0E, + 0x58, 0xA3, 0x31, 0xA2, 0xF7, 0x1D, 0x7C, 0xCC, 0x2D, 0x45, 0x1B, 0x32, 0xB1, 0xC6, 0x5C, + 0x31, 0x2A, 0xCF, 0x47, 0xEE, 0x51, 0x3B, 0x21, 0x95, 0x4C, 0x41, 0xC0, 0x0C, 0x87, 0x38, + 0x72, 0xEE, 0x94, 0xCF, 0x14, 0xF4, 0x60, 0x37, 0x42, 0x53, 0x61, 0xF4, 0xBD, 0xB5, 0x48, + 0x21, 0xF7, 0x11, 0x46, 0x0C, 0xEB, 0xAE, 0x8C, 0x07, 0x50, 0x8A, 0x92, 0x19, 0xF8, 0x8F, + 0xA6, 0xBE, 0xDA, 0xA6, 0x78, 0xEE, 0xD5, 0x01, 0x94, 0x4A, 0x16, 0xAE, 0x6F, 0x7B, 0x5B, + 0xB7, 0xA2, 0xE1, 0xE3, 0x57, 0xE7, 0x0D, 0x7B, 0x98, 0x46, 0x1A, 0x2C, 0x71, 0xCB, 0x0F, + 0xA7, 0x62, 0xD6, 0xAD, 0x98, 0x24, 0x08, 0x1D, 0x37, 0xF2, 0x92, 0xFD, 0x4B, 0xE8, 0xB8, + 0x4C, 0x36, 0x11, 0x0D, 0xC7, 0x44, 0x36, 0x02, 0x01, 0xBE, 0xEB, 0xE0, 0xBD, 0x6C, 0x9D, + 0x05, 0xE8, 0x69, 0x25, 0x6D, 0x2F, 0xF3, 0xF9, 0x95, 0x17, 0xB7, 0xEF, 0xD2, 0xA3, 0x37, + 0x74, 0x05, 0x6C, 0xB5, 0x67, 0x16, 0x75, 0xA8, 0xB4, 0x92, 0xE9, 0xF5, 0xF2, 0x62, 0x0E, + 0xB8, 0xEF, 0x93, 0x81, 0xD3, 0xD1, 0xDF, 0x19, 0x93, 0x8B, 0x7B, 0x5F, 0xFA, 0xAC, 0x59, + 0xBC, 0x81, 0x10, 0xFA, 0x87, 0xBA, 0x8D, 0x7A, 0x3D, 0x01, 0x65, 0xF8, 0xE4, 0x1D, 0xD0, + 0xF8, 0x04, 0xF1, 0x1B, 0x9D, 0xED, 0x0F, 0x35, 0x2A, 0x59, 0x78, 0x35, 0xD0, 0x63, 0x07, + 0xA8, 0xE0, 0xC6, 0xEF, 0x4D, 0x21, 0x90, 0x43, 0x39, 0xE1, 0xCF, 0x45, 0x89, 0x23, 0xA3, + 0xE8, 0x9E, 0x02, 0x5D, 0x94, 0x53, 0x47, 0x36, 0x6C, 0x02, 0xF3, 0xDD, 0x63, 0x68, 0xD4, + 0xE4, 0x7E, 0x85, 0xD3, 0xD2, 0xA9, 0x70, 0x5B, 0xD5, 0x79, 0x61, 0x85, 0x2E, 0x5A, 0x57, + 0x9F, 0x93, 0xB1, 0xC5, 0x14, 0xC5, 0x39, 0xF4, 0x9E, 0xA1, 0x16, 0x3A, 0x2A, 0x49, 0x3B, + 0x0E, 0xFC, 0xB4, 0x7F, 0x47, 0x48, 0xF6, 0xA9, 0x9E, 0x10, 0xBF, 0x70, 0x78, 0x28, 0x2E, + 0x4A, 0xCE, 0x18, 0x13, 0x6E, 0x2A, 0x8B, 0x3E, 0xE0, 0xA3, 0x80, 0xDC, 0xD3, 0xB3, 0xEF, + 0x3E, 0x65, 0xE1, 0xB8, 0x15, 0x72, 0x89, 0xD6, 0x24, 0x67, 0xAD, 0x48, 0x8B, 0xA0, 0x39, + 0x2B, 0x2E, 0x90, 0xA1, 0xED, 0xED, 0xCB, 0xDC, 0x93, 0x1D, 0xC1, 0x72, 0x98, 0xCC, 0xEF, + 0x76, 0x64, 0x5C, 0x7D, 0x33, 0x0A, 0x05, 0xC2, 0xCE, 0x40, 0xF8, 0x9B, 0x85, 0x46, 0x8F, + 0x35, 0x7A, 0x21, 0x77, 0x51, 0xE1, 0x54, 0x63, 0x13, 0x04, 0xEC, 0x4E, 0x04, 0xBB, 0x45, + 0xB3, 0x67, 0x89, 0x09, 0xC7, 0x4A, 0xF5, 0x1C, 0xE3, 0x70, 0x36, 0x4D, 0x8F, 0x4F, 0x7E, + 0xB1, 0xE6, 0x1E, 0x00, 0x28, 0x74, 0x29, 0xC9, 0x96, 0x1D, 0xE8, 0x32, 0x2C, 0xA9, 0xA2, + 0x62, 0x9B, 0x13, 0x09, 0xD8, 0x00, 0xE9, 0x2B, 0xC1, 0xDC, 0x50, 0x55, 0xDC, 0xC7, 0x97, + 0xF3, 0x38, 0x66, 0xEB, 0x0C, 0xFD, 0x8D, 0x49, 0x02, 0x50, 0xD4, 0x8F, 0xFC, 0xA8, 0x02, + 0x2F, 0x49, 0x29, 0x0E, 0x2D, 0x53, 0x76, 0x16, 0x2F, 0xBA, 0xA9, 0x82, 0xD1, 0x64, 0x53, + 0xC8, 0x25, 0xB3, 0x5F, 0x65, 0x15, 0x63, 0x5E, 0xA9, 0x2B, 0xEA, 0x72, 0x36, 0x7B, 0xAA, + 0x54, 0xDE, 0x3F, 0x9E, 0xAE, 0xA6, 0x95, 0x42, 0xA8, 0x1A, 0x41, 0x27, 0xF7, 0x1C, 0xBA, + 0xA2, 0x57, 0xF3, 0x24, 0xFE, 0xFE, 0xF1, 0x4F, 0x08, 0xFB, 0xD6, 0x5A, 0x04, 0x9C, 0xD2, + 0xFB, 0x36, 0x25, 0x94, 0xA8, 0xE2, 0x3F, 0xF1, 0xA2, 0x61, 0x7D, 0xB5, 0xB1, 0x58, 0xF6, + 0xF0, 0x1C, 0xF5, 0x0A, 0xB0, 0xED, 0x95, 0xC6, 0xE7, 0x09, 0x84, 0x11, 0x64, 0x10, 0x8B, + 0x06, 0xE1, 0xB4, 0x0A, 0xB0, 0xAB, 0x11, 0xC4, 0x08, 0x30, 0x1D, 0x3D, 0x9D, 0x8E, 0xA6, + 0x9E, 0x96, 0x8A, 0x96, 0x00, 0xB3, 0xD1, 0x7F, 0x38, 0x01, 0x1C, 0xE2, 0x80, 0x74, 0xE2, + 0xC2, 0xE1, 0x0B, 0xF6, 0x19, 0x7C, 0x60, 0x2D, 0x8D, 0x0C, 0xE7, 0xD3, 0xA3, 0xEF, 0x2D, + 0x89, 0x62, 0x3B, 0xC9, 0xF1, 0x2E, 0xA3, 0x38, 0x79, 0x1E, 0x92, 0x66, 0xBB, 0x8C, 0xE0, + 0x2B, 0x12, 0x4C, 0x6C, 0x79, 0x29, 0xBA, 0xEA, 0x69, 0x32, 0x44, 0x09, 0x84, 0x54, 0xA0, + 0x80, 0xEB, 0x75, 0x23, 0xE1, 0x3B, 0xB1, 0xB7, 0xC5, 0xB6, 0x77, 0x5F, 0xAB, 0xAB, 0xAB, + 0xBE, 0x90, 0x75, 0xFE, 0x56, 0x87, 0xAA, 0x45, 0x13, 0x97, 0xBB, 0x9C, 0xFC, 0xCD, 0x05, + 0x12, 0x43, 0xE9, 0xBF, 0x5A, 0xEF, 0x24, 0x06, 0x2D, 0x33, 0x5D, 0xE5, 0xFC, 0xE2, 0x4E, + 0x9D, 0xDB, 0xDE, 0x11, 0x91, 0x05, 0x2D, 0x80, 0xC3, 0x6D, 0xF9, 0xF8, 0x43, 0x48, 0x72, + 0xF2, 0x77, 0xED, 0x4F, 0x5A, 0x1C, 0xE8, 0xEB, 0xD3, 0xB9, 0x60, 0x82, 0x4A, 0x4E, 0x4F, + 0x10, 0x01, 0xB0, 0x4C, 0xB6, 0x85, 0xF9, 0xBE, 0xE4, 0xD0, 0xDD, 0xB0, 0xC5, 0x71, 0x59, + 0x8A, 0xC2, 0x02, 0x1A, 0x66, 0x06, 0xFD, 0x23, 0x34, 0x5C, 0x6F, 0xBB, 0x84, 0xF0, 0xCE, + 0x05, 0xFE, 0x52, 0x73, 0x45, 0x21, 0xB7, 0xB0, 0x7C, 0x63, 0x88, 0xD3, 0xA3, 0xB9, 0x93, + 0x18, 0xBF, 0x01, 0x31, 0x50, 0x4A, 0xA9, 0xDF, 0xBA, 0xF5, 0x48, 0xF9, 0xD3, 0x2A, 0x9C, + 0xD4, 0xC6, 0x89, 0x35, 0x24, 0xB1, 0x13, 0x30, 0xA2, 0xD3, 0xAA, 0xD3, 0xED, 0x2A, 0x58, + 0x96, 0x6E, 0xBB, 0x01, 0x34, 0x46, 0x5D, 0x54, 0x3F, 0xD7, 0x79, 0x7A, 0xF5, 0x49, 0xF5, + 0x68, 0xEA, 0xEB, 0xE9, 0x57, 0xF6, 0x4F, 0xEC, 0x85, 0x46, 0x74, 0x90, 0x2B, 0x97, 0x55, + 0x87, 0x56, 0x98, 0x69, 0x46, 0xEA, 0x3A, 0xB7, 0xA2, 0x51, 0xCB, 0xBE, 0xA1, 0x1A, 0x68, + 0x7B, 0xD4, 0x3F, 0x5D, 0x0B, 0xD8, 0x9C, 0xD2, 0xCA, 0xBA, 0x61, 0xD5, 0x21, 0x83, 0x74, + 0x99, 0x0E, 0xE8, 0xB9, 0x22, 0x19, 0xED, 0x25, 0xDC, 0xA0, 0x11, 0xC6, 0x8A, 0x97, 0x57, + 0xC0, 0x13, 0xBD, 0x83, 0x7B, 0x2D, 0xD7, 0x34, 0xE3, 0x75, 0x1F, 0x64, 0xFC, 0xB4, 0xB2, + 0x3D, 0xCD, 0x6B, 0xC5, 0x7E, 0xA5, 0x67, 0xF5, 0x71, 0x6E, 0x17, 0x36, 0x72, 0x44, 0x75, + 0x1E, 0x23, 0x03, 0xB2, 0x2A, 0x95, 0x3E, 0x77, 0x27, 0x56, 0x95, 0x6C, 0xDC, 0xC0, 0x13, + 0xFF, 0xD2, 0xC3, 0x24, 0x90, 0x75, 0x44, 0x22, 0xA5, 0x72, 0x52, 0x9D, 0x4C, 0x92, 0xF1, + 0xEB, 0xB1, 0x9F, 0x1D, 0xAD, 0x4D, 0x03, 0x6F, 0x2F, 0xDF, 0x31, 0xCA, 0x91, 0x01, 0xBD, + 0xF8, 0x1A, 0xEA, 0x94, 0x8A, 0xED, 0xCF, 0x21, 0x7A, 0xA8, 0xFC, 0xCD, 0x7A, 0x07, 0x71, + 0xAA, 0x27, 0x53, 0xE1, 0xA8, 0x23, 0xBF, 0x41, 0xC9, 0x53, 0x77, 0xA2, 0xFF, 0xA6, 0x1B, + 0x22, 0x65, 0x13, 0x81, 0x53, 0xCE, 0x86, 0xD2, 0xC8, 0x7D, 0xD0, 0x7A, 0x4B, 0x32, 0xD2, + 0x7F, 0x5F, 0x28, 0x72, 0x64, 0x14, 0x31, 0xCE, 0x9A, 0x18, 0xA5, 0x02, 0xAA, 0xEF, 0xD9, + 0xAF, 0xC5, 0xB0, 0xD1, 0x3C, 0xD4, 0x6C, 0x35, 0x7E, 0x38, 0xE6, 0x9E, 0x1E, 0xE9, 0x45, + 0xAD, 0xD1, 0x99, 0x29, 0x32, 0xA5, 0xB1, 0xE5, 0xC5, 0x62, 0x9C, 0x9F, 0x48, 0xF7, 0x66, + 0x18, 0x53, 0xDA, 0x00, 0x78, 0x7C, 0x9D, 0x78, 0xFB, 0x92, 0x55, 0x53, 0xBF, 0x07, 0xA5, + 0x0D, 0xD5, 0xB9, 0xD9, 0x35, 0x85, 0x34, 0x20, 0xE4, 0xD1, 0xA7, 0x1A, 0xE6, 0x2F, 0xF9, + 0x0C, 0xA1, 0x93, 0xCD, 0xD6, 0xC2, 0xF4, 0xBE, 0xD2, 0x63, 0x41, 0x5A, 0xAF, 0x9A, 0x35, + 0x09, 0x4B, 0xC2, 0xA2, 0x2E, 0x2A, 0x66, 0x3C, 0x76, 0x45, 0x00, 0x1C, 0xD1, 0x90, 0xB7, + 0xBC, 0x17, 0xC7, 0x5F, 0xEA, 0xDF, 0x8E, 0x87, 0xCE, 0x5C, 0x24, 0xB7, 0x63, 0xB6, 0x58, + 0x4E, 0xD3, 0x2E, 0x71, 0xB0, 0x26, 0x81, 0x42, 0xEA, 0x3E, 0xD6, 0x89, 0x81, 0x57, 0xBF, + 0x92, 0x3B, 0xEB, 0xF0, 0x19, 0x2D, 0x1B, 0xF5, 0xEE, 0x30, 0xA7, 0xD3, 0x51, 0x63, 0x4A, + 0x60, 0xB5, 0x04, 0xDD, 0xE3, 0x8A, 0x2E, 0x11, 0x4F, 0x7A, 0xE9, 0xBF, 0x17, 0x6D, 0x4A, + 0x18, 0xBA, 0x28, 0x95, 0xA7, 0xBB, 0x4B, 0x47, 0x44, 0x4A, 0x9B, 0xA8, 0xDB, 0xB4, 0xC1, + 0x24, 0xCD, 0x41, 0xBB, 0xB3, 0x2F, 0x4B, 0xCB, 0x1D, 0xE4, 0x8C, 0x4A, 0xBB, 0x51, 0x06, + 0x07, 0xA0, 0x01, 0xB5, 0xA0, 0x00, 0xBB, 0xA4, 0x36, 0x18, 0xB6, 0xC1, 0x9E, 0x43, 0x51, + 0x7B, 0x45, 0xB4, 0x24, 0x05, 0x92, 0x8B, 0x67, 0xC7, 0x13, 0x88, 0x18, 0x58, 0xBA, 0xD3, + 0xA4, 0x25, 0x11, 0xC2, 0x71, 0x6F, 0xF9, 0xCD, 0x33, 0x20, 0x34, 0xB6, 0x72, 0xB5, 0x2F, + 0xF1, 0x66, 0x10, 0x80, 0x5C, 0xDB, 0xE7, 0x54, 0x4A, 0x8A, 0x84, 0xB6, 0x6E, 0x1C, 0x74, + 0x5A, 0x73, 0xC1, 0xB6, 0xBC, 0xDA, 0x5B, 0x77, 0xB9, 0x51, 0xF3, 0x6C, 0x0F, 0x7A, 0x53, + 0x72, 0xDE, 0x9E, 0x5D, 0x1F, 0x9B, 0xBC, 0xDE, 0x88, 0x43, 0xC6, 0x90, 0x90, 0x02, 0xDD, + 0xA4, 0x87, 0x5E, 0x67, 0x57, 0x1A, 0xF0, 0xBE, 0xC5, 0x81, 0x85, 0x6C, 0x32, 0xC0, 0x9C, + 0x24, 0x0E, 0x66, 0x4E, 0x76, 0x1E, 0x57, 0xCD, 0x0D, 0x8D, 0xC8, 0xA7, 0x1C, 0xB9, 0x18, + 0xA5, 0x76, 0x2D, 0x11, 0x12, 0x85, 0xCD, 0x8B, 0x56, 0x13, 0xDD, 0xBD, 0x0C, 0xA0, 0x8A, + 0xC0, 0x34, 0x2B, 0x2B, 0xDE, 0xE3, 0x8F, 0x96, 0xFA, 0x75, 0x4B, 0xB2, 0xB0, 0x87, 0x17, + 0x9C, 0x11, 0x3C, 0x93, 0x98, 0x6A, 0x81, 0x03, 0x56, 0xEB, 0x94, 0x54, 0x0B, 0x93, 0xCB, + 0x9D, 0xEC, 0x4A, 0xA9, 0x29, 0x0F, 0xF1, 0x2E, 0xC1, 0xAA, 0x2E, 0x65, 0x6C, 0x9B, 0xE3, + 0xD5, 0x90, 0x75, 0x3C, 0x36, 0x6C, 0x60, 0x14, 0x06, 0xC0, 0x61, 0xBC, 0x22, 0x03, 0x3A, + 0x1F, 0xD1, 0xF4, 0xE1, 0x11, 0x1D, 0x03, 0x9B, 0x88, 0x13, 0xB9, 0x83, 0xCB, 0x50, 0x6C, + 0x3E, 0xA7, 0xFF, 0x30, 0x57, 0x98, 0x3E, 0x8B, 0xF0, 0x16, 0x82, 0xFB, 0xB0, 0x0F, 0x43, + 0x00, 0x53, 0x13, 0xC8, 0x2C, 0x13, 0x92, 0x91, 0x8A, 0x61, 0x65, 0xA1, 0x33, 0x38, 0xFF, + 0xE1, 0x1A, 0x99, 0x2C, 0x1F, 0xB3, 0xD1, 0x03, 0x2A, 0xA6, 0x79, 0xA4, 0x18, 0xC8, 0xBA, + 0x4F, 0x8A, 0x0B, 0xC1, 0x99, 0xE1, 0x0C, 0xF6, 0xBD, 0x77, 0xA1, 0x4F, 0xDD, 0x6A, 0x06, + 0x09, 0x35, 0x14, 0x34, 0x8E, 0x3A, 0x89, 0x74, 0x43, 0x4A, 0xE8, 0xA3, 0x67, 0x63, 0x69, + 0xC6, 0xBE, 0x2C, 0xF9, 0x0E, 0x67, 0x2B, 0x34, 0x3F, 0xCE, 0x04, 0xAC, 0x6B, 0x22, 0xE0, + 0xCF, 0x47, 0x56, 0x8B, 0xC4, 0x5D, 0x70, 0xA6, 0x8E, 0x68, 0xC6, 0x49, 0xA4, 0x83, 0x0A, + 0xE2, 0x18, 0x59, 0x0C, 0x1A, 0x43, 0x7E, 0x7A, 0x23, 0xA5, 0x4E, 0xFE, 0x44, 0xF6, 0x70, + 0x86, 0xEB, 0x69, 0x7B, 0x9F, 0xA5, 0x78, 0x35, 0xF0, 0xB8, 0xF7, 0x0F, 0x0A, 0x92, 0x92, + 0x26, 0xEF, 0xB3, 0x36, 0xC0, 0xE2, 0x18, 0x33, 0xA0, 0x28, 0x21, 0x8C, 0xD6, 0x37, 0x32, + 0xC8, 0x0A, 0xA4, 0x77, 0xE6, 0x2D, 0x14, 0x1D, 0xBA, 0x81, 0x85, 0x4F, 0x70, 0xDA, 0x68, + 0xDA, 0xFF, 0x4A, 0x84, 0xCB, 0x6D, 0xE7, 0x79, 0x25, 0x4E, 0x8A, 0x97, 0xE7, 0x35, 0x65, + 0x37, 0x4A, 0xF4, 0x09, 0x2A, 0xF0, 0x5C, 0xBD, 0x66, 0x54, 0xAF, 0xC3, 0xFD, 0x72, 0xF0, + 0xAE, 0x23, 0x26, 0x95, 0xCB, 0x66, 0x68, 0xEA, 0xFE, 0xCC, 0x40, 0x69, 0xBD, 0x90, 0xBB, + 0x52, 0x8B, 0x83, 0xEF, 0xA2, 0xFB, 0xCD, 0xBD, 0x93, 0xB2, 0x89, 0x92, 0x96, 0x21, 0xED, + 0x74, 0xD8, 0x08, 0x73, 0x8F, 0xC1, 0x03, 0xEE, 0xB1, 0x05, 0x51, 0x08, 0x51, 0xFC, 0x93, + 0x19, 0xF1, 0x71, 0xEA, 0x0C, 0xED, 0x0B, 0x97, 0xB5, 0xB9, 0xFB, 0x5E, 0xF9, 0x85, 0x18, + 0x6B, 0xC5, 0x20, 0x98, 0xF9, 0xEB, 0x47, 0x6F, 0x67, 0xB7, 0xCC, 0x76, 0x65, 0xD4, 0x75, + 0x87, 0x97, 0x5C, 0xB4, 0x5A, 0x50, 0xFC, 0x64, 0x10, 0x07, 0x19, 0xBF, 0x76, 0x34, 0x5F, + 0x0F, 0xDF, 0x1E, 0x09, 0xEF, 0xE9, 0xFB, 0x80, 0x0D, 0xC1, 0x14, 0xE4, 0x6B, 0xE0, 0x87, + 0x9A, 0x19, 0x5C, 0xC0, 0x68, 0x70, 0xE2, 0x3D, 0x26, 0x31, 0xDA, 0xE7, 0x1C, 0x39, 0x94, + 0x48, 0x1C, 0x87, 0x61, 0xC4, 0x0D, 0x07, 0xC5, 0xBF, 0xCA, 0x95, 0xE7, 0x18, 0xB7, 0xB2, + 0x25, 0x85, 0xAF, 0x03, 0xED, 0x34, 0x17, 0x5A, 0x46, 0xD5, 0x7A, 0xF3, 0x51, 0x8E, 0x32, + 0xA7, 0xFC, 0x1A, 0xA4, 0x48, 0x27, 0x32, 0xA8, 0x1A, 0x87, 0xF7, 0x24, 0xF8, 0xD2, 0xE7, + 0x80, 0xB3, 0xA3, 0x9D, 0x45, 0x1A, 0x38, 0x0F, 0x75, 0xC2, 0xD6, 0x80, 0xCC, 0x72, 0x13, + 0xEA, 0xB1, 0xD4, 0xA5, 0x9D, 0x39, 0x4A, 0xE3, 0x81, 0x0A, 0x1C, 0x90, 0x81, 0x8D, 0x52, + 0xF9, 0x3F, 0xB2, 0x03, 0xE2, 0xD8, 0xB1, 0xB5, 0xFA, 0x8F, 0x60, 0xB2, 0xD5, 0x85, 0xD9, + 0x13, 0x5D, 0x64, 0x88, 0x46, 0xF1, 0x38, 0xB8, 0x69, 0x53, 0x24, 0x2D, 0x2B, 0xB1, 0xF2, + 0xEC, 0xDF, 0x38, 0x9B, 0x4D, 0xE7, 0x65, 0x18, 0x17, 0xB8, 0xE4, 0xE6, 0x4B, 0x33, 0x3F, + 0x1A, 0xAC, 0x52, 0x3A, 0x93, 0xF2, 0x74, 0x8A, 0x9C, 0x38, 0xFF, 0xBC, 0x29, 0xCE, 0xD4, + 0x57, 0xB6, 0xF9, 0x78, 0x1B, 0x08, 0xA6, 0x7A, 0x19, 0x75, 0xD0, 0x31, 0xCC, 0xD7, 0x15, + 0x45, 0xC0, 0x03, 0x74, 0x34, 0x05, 0x6C, 0x24, 0x34, 0xD1, 0x3E, 0x6C, 0x4B, 0xEE, 0xBF, + 0x46, 0xFC, 0x12, 0x22, 0x2C, 0x0B, 0x2E, 0xCC, 0xD6, 0x15, 0x9D, 0x5A, 0xEA, 0x8E, 0x55, + 0x4D, 0x7A, 0x09, 0x65, 0x2B, 0x06, 0xBF, 0x7C, 0xA6, 0x99, 0xA7, 0x19, 0x9E, 0x71, 0x6D, + 0x05, 0xDD, 0x55, 0x30, 0x41, 0xA8, 0xF2, 0xB3, 0x03, 0xD2, 0x36, 0xA9, 0xBA, 0xBA, 0xAF, + 0xB9, 0xFA, 0x52, 0x8F, 0x28, 0xA2, 0xCA, 0x2A, 0xA7, 0x80, 0xB9, 0x40, 0x38, 0x3C, 0x09, + 0x9A, 0xA6, 0x5A, 0x00, 0x74, 0xB8, 0x3F, 0xD1, 0xF0, 0xBC, 0x5B, 0x7B, 0x5E, 0x46, 0xC2, + 0x5E, 0x54, 0x83, 0x8B, 0x3C, 0xBC, 0xFC, 0x95, 0xF8, 0x7F, 0x1D, 0x47, 0x1B, 0x3B, 0xA8, + 0x94, 0x43, 0x4F, 0xA5, 0x89, 0x52, 0xFD, 0xCB, 0x77, 0xF1, 0x61, 0x37, 0x26, 0x93, 0x30, + 0x6D, 0xBA, 0x4E, 0x8F, 0x21, 0x6D, 0x1C, 0x8E, 0x5C, 0xAF, 0xF0, 0xFE, 0x83, 0x60, 0xA5, + 0x1C, 0x60, 0x76, 0x36, 0x44, 0x16, 0x9F, 0xDC, 0x6A, 0x82, 0x67, 0xF2, 0xE3, 0xF9, 0x09, + 0xA6, 0x1B, 0x2A, 0x67, 0x8B, 0xCE, 0x6A, 0xE9, 0x04, 0x03, 0xA8, 0x36, 0xB1, 0xA7, 0xB7, + 0xE8, 0xCD, 0x8B, 0x54, 0xC3, 0x70, 0x87, 0xA9, 0xE1, 0x44, 0x46, 0xD9, 0x5E, 0x69, 0x08, + 0xD2, 0xEE, 0xDB, 0xFC, 0xC6, 0x53, 0xE0, 0x2F, 0xDF, 0x77, 0x1F, 0x70, 0x1A, 0x79, 0xB9, + 0xE5, 0xA2, 0x6E, 0xD0, 0xA9, 0x47, 0x84, 0x20, 0x70, 0xF3, 0xB5, 0x70, 0x17, 0x42, 0x21, + 0x12, 0x19, 0xE7, 0x61, 0x76, 0x2C, 0x37, 0xF0, 0xD0, 0xA1, 0xD1, 0xB9, 0x75, 0x0F, 0xEE, + 0x57, 0x7E, 0x12, 0x08, 0x11, 0x5C, 0x66, 0xAC, 0x07, 0xEC, 0x09, 0x1E, 0x6A, 0x3F, 0xC4, + 0xAA, 0x6A, 0x25, 0x3B, 0xCB, 0xA8, 0x68, 0xED, 0xD3, 0x15, 0x4D, 0xCA, 0xF5, 0x16, 0x2F, + 0x61, 0x5E, 0x85, 0x49, 0x0A, 0x6C, 0xA3, 0x42, 0xF3, 0x4C, 0x43, 0xAC, 0x61, 0xA3, 0xEA, + 0x6B, 0xFE, 0xEF, 0xD8, 0x50, 0xE1, 0x90, 0xEB, 0x1D, 0x8D, 0xA4, 0xD2, 0x8B, 0x5E, 0xCE, + 0xEB, 0x16, 0x78, 0xC0, 0x24, 0x33, 0xEC, 0xD5, 0xD4, 0x8B, 0x25, 0x36, 0x40, 0x42, 0x57, + 0xE8, 0xCA, 0x7B, 0xEF, 0x58, 0x55, 0xF2, 0xB8, 0x13, 0xED, 0x2F, 0x4C, 0x40, 0x94, 0x45, + 0xA3, 0x31, 0x7C, 0x9B, 0xE1, 0xA3, 0x5A, 0xE2, 0xFB, 0x4D, 0x2B, 0x87, 0x92, 0x1B, 0x90, + 0x4B, 0xF2, 0xC1, 0x4D, 0xB5, 0x14, 0xCE, 0xE0, 0x45, 0x25, 0x1C, 0xFC, 0x27, 0x63, 0x74, + 0xDB, 0x15, 0xC9, 0x9D, 0xEA, 0x15, 0xAC, 0xDE, 0x19, 0x7C, 0x6E, 0xB5, 0x24, 0x98, 0x8E, + 0x39, 0xB6, 0x32, 0x87, 0xBE, 0xB8, 0x67, 0x68, 0x65, 0xAA, 0xA3, 0xBA, 0xD1, 0xB4, 0x3B, + 0x8C, 0xAB, 0x15, 0xCB, 0xF2, 0x7A, 0x49, 0x87, 0x59, 0xE3, 0x20, 0x3A, 0xBF, 0x36, 0x9E, + 0x97, 0x24, 0x2F, 0x0B, 0x01, 0x54, 0x14, 0x9F, 0x14, 0xAC, 0x23, 0x3C, 0xDB, 0x73, 0xA2, + 0x2B, 0x7F, 0xB8, 0xF0, 0x93, 0x25, 0xBF, 0x2A, 0xCE, 0x83, 0xBB, 0x6B, 0x5D, 0xB8, 0xA1, + 0x21, 0xA2, 0xB6, 0x82, 0x14, 0x9A, 0x69, 0x13, 0x1C, 0xCC, 0xE5, 0x22, 0x29, 0x84, 0x0B, + 0x11, 0x3F, 0xC7, 0xB0, 0xBC, 0xC5, 0x84, 0x05, 0xBF, 0xE8, 0x7F, 0x1F, 0x95, 0xFF, 0xC2, + 0xE9, 0x6F, 0xC5, 0x59, 0x65, 0x67, 0xE9, 0x43, 0x64, 0xDF, 0xAA, 0x6D, 0x9D, 0x5A, 0x6E, + 0xB9, 0x9A, 0xE4, 0xDD, 0xF4, 0x24, + ]) + .unwrap(); let mu = MLDSA87::compute_mu_from_sk(&sk, msg, None).unwrap(); let sig = MLDSA87::sign_mu_deterministic(&sk, None, &mu, [0u8; 32]).unwrap(); @@ -276,7 +1122,7 @@ fn bench_mldsa87_sign() { } fn bench_mldsa87_lowmemory_sign() { - use bouncycastle::mldsa_lowmemory::{MLDSATrait, MLDSA87, MLDSA87PrivateKey, MLDSA87_SK_LEN}; + use bouncycastle::mldsa_lowmemory::{MLDSA87, MLDSA87_SK_LEN, MLDSA87PrivateKey, MLDSATrait}; eprintln!("MLDSA87_lowmemory/Sign"); @@ -289,7 +1135,12 @@ fn bench_mldsa87_lowmemory_sign() { // use bouncycastle_hex as hex; // eprintln!("sk:\n{}", &hex::encode(sk.encode())); - let sk = MLDSA87PrivateKey::from_bytes(&[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f]).unwrap(); + let sk = MLDSA87PrivateKey::from_bytes(&[ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, + 0x1E, 0x1F, + ]) + .unwrap(); let msg = b"The quick brown fox jumped over the lazy dog"; @@ -299,8 +1150,8 @@ fn bench_mldsa87_lowmemory_sign() { } fn bench_mldsa44_verify() { - use bouncycastle::mldsa::{MLDSATrait, MLDSA44, MLDSA44_SIG_LEN, MLDSA44PublicKey}; use bouncycastle::hex; + use bouncycastle::mldsa::{MLDSA44, MLDSA44_SIG_LEN, MLDSA44PublicKey, MLDSATrait}; eprintln!("MLDSA44/Verify"); @@ -319,8 +1170,261 @@ fn bench_mldsa44_verify() { // let sig = MLDSA44::sign_mu_deterministic(&mldsa44_sk, &mu, [0u8; 32]).unwrap(); // eprintln!("sig:\n{}", &*hex::encode(sig)); - let mldsa44_pk = MLDSA44PublicKey::from_bytes(&[0xd7,0xb2,0xb4,0x72,0x54,0xaa,0xe0,0xdb,0x45,0xe7,0x93,0x0d,0x4a,0x98,0xd2,0xc9,0x7d,0x8f,0x13,0x97,0xd1,0x78,0x9d,0xaf,0xa1,0x70,0x24,0xb3,0x16,0xe9,0xbe,0xc9,0x4f,0xc9,0x94,0x6d,0x42,0xf1,0x9b,0x79,0xa7,0x41,0x3b,0xba,0xa3,0x3e,0x71,0x49,0xcb,0x42,0xed,0x51,0x15,0x69,0x3a,0xc0,0x41,0xfa,0xcb,0x98,0x8a,0xde,0xb5,0xfe,0x0e,0x1d,0x86,0x31,0x18,0x49,0x95,0xb5,0x92,0xc3,0x97,0xd2,0x29,0x4e,0x2e,0x14,0xf9,0x0a,0xa4,0x14,0xba,0x38,0x26,0x89,0x9a,0xc4,0x3f,0x4c,0xcc,0xac,0xbc,0x26,0xe9,0xa8,0x32,0xb9,0x51,0x18,0xd5,0xcb,0x43,0x3c,0xbe,0xf9,0x66,0x0b,0x00,0x13,0x8e,0x08,0x17,0xf6,0x1e,0x76,0x2c,0xa2,0x74,0xc3,0x6a,0xd5,0x54,0xeb,0x22,0xaa,0xc1,0x16,0x2e,0x4a,0xb0,0x1a,0xcb,0xa1,0xe3,0x8c,0x4e,0xfd,0x8f,0x80,0xb6,0x5b,0x33,0x3d,0x0f,0x72,0xe5,0x5d,0xfe,0x71,0xce,0x9c,0x1e,0xbb,0x98,0x89,0xe7,0xc5,0x61,0x06,0xc0,0xfd,0x73,0x80,0x3a,0x2a,0xec,0xfe,0xaf,0xde,0xd7,0xaa,0x3c,0xb2,0xce,0xda,0x54,0xd1,0x2b,0xd8,0xcd,0x36,0xa7,0x8c,0xf9,0x75,0x94,0x3b,0x47,0xab,0xd2,0x5e,0x88,0x0a,0xc4,0x52,0xe5,0x74,0x2e,0xd1,0xe8,0xd1,0xa8,0x2a,0xfa,0x86,0xe5,0x90,0xc7,0x58,0xc1,0x5a,0xe4,0xd2,0x84,0x0d,0x92,0xbc,0xa1,0xa5,0x09,0x0f,0x40,0x49,0x65,0x97,0xfc,0xa7,0xd8,0xb9,0x51,0x3f,0x1a,0x1b,0xda,0x6e,0x95,0x0a,0xaa,0x98,0xde,0x46,0x75,0x07,0xd4,0xa4,0xf5,0xa4,0xf0,0x59,0x92,0x16,0x58,0x2c,0x35,0x72,0xf6,0x2e,0xda,0x89,0x05,0xab,0x35,0x81,0x67,0x0c,0x4a,0x02,0x77,0x7a,0x33,0xe0,0xca,0x72,0x95,0xfd,0x8f,0x4f,0xf6,0xd1,0xa0,0xa3,0xa7,0x68,0x3d,0x65,0xf5,0xf5,0xf7,0xfc,0x60,0xda,0x02,0x3e,0x82,0x6c,0x5f,0x92,0x14,0x4c,0x02,0xf7,0xd1,0xba,0x10,0x75,0x98,0x75,0x53,0xea,0x93,0x67,0xfc,0xd7,0x6d,0x99,0x0b,0x7f,0xa9,0x9c,0xd4,0x5a,0xfd,0xb8,0x83,0x6d,0x43,0xe4,0x59,0xf5,0x18,0x7d,0xf0,0x58,0x47,0x97,0x09,0xa0,0x1e,0xa6,0x83,0x59,0x35,0xfa,0x70,0x46,0x09,0x90,0xcd,0x3d,0xc1,0xba,0x40,0x1b,0xa9,0x4b,0xab,0x1d,0xde,0x41,0xac,0x67,0xab,0x33,0x19,0xdc,0xac,0xa0,0x60,0x48,0xd4,0xc4,0xee,0xf2,0x7e,0xe1,0x3a,0x9c,0x17,0xd0,0x53,0x8f,0x43,0x0f,0x2d,0x64,0x2d,0xc2,0x41,0x56,0x60,0xde,0x78,0x87,0x7d,0x8d,0x8a,0xbc,0x72,0x52,0x39,0x78,0xc0,0x42,0xe4,0x28,0x5f,0x43,0x19,0x84,0x6c,0x44,0x12,0x62,0x42,0x97,0x68,0x44,0xc1,0x0e,0x55,0x6b,0xa2,0x15,0xb5,0xa7,0x19,0xe5,0x9d,0x0c,0x6b,0x2a,0x96,0xd3,0x98,0x59,0x07,0x1f,0xdc,0xc2,0xcd,0xe7,0x52,0x4a,0x7b,0xed,0xae,0x54,0xe8,0x5b,0x31,0x8e,0x85,0x4e,0x8f,0xe2,0xb2,0xf3,0xed,0xfa,0xc9,0x71,0x91,0x28,0x27,0x0a,0xaf,0xd1,0xe5,0x04,0x4c,0x3a,0x4f,0xda,0xfd,0x9f,0xf3,0x1f,0x90,0x78,0x4b,0x8e,0x8e,0x45,0x96,0x14,0x4a,0x0d,0xaf,0x58,0x65,0x11,0xd3,0xd9,0x96,0x2b,0x9e,0xa9,0x5a,0xf1,0x97,0xb4,0xe5,0xfc,0x60,0xf2,0xb1,0xed,0x15,0xde,0x3a,0x5b,0xef,0x5f,0x89,0xbd,0xc7,0x9d,0x91,0x05,0x1d,0x9b,0x28,0x16,0xe7,0x4f,0xa5,0x45,0x31,0xef,0xdc,0x1c,0xbe,0x74,0xd4,0x48,0x85,0x7f,0x47,0x6b,0xcd,0x58,0xf2,0x1c,0x0b,0x65,0x3b,0x3b,0x76,0xa4,0xe0,0x76,0xa6,0x55,0x9a,0x30,0x27,0x18,0x55,0x5c,0xc6,0x3f,0x74,0x85,0x9a,0xab,0xab,0x92,0x5f,0x02,0x38,0x61,0xca,0x8c,0xd0,0xf7,0xba,0xdb,0x28,0x71,0xf6,0x7d,0x55,0x32,0x6d,0x74,0x51,0x13,0x5a,0xd4,0x5f,0x4a,0x1b,0xa6,0x91,0x18,0xfb,0xb2,0xc8,0xa3,0x0e,0xec,0x93,0x92,0xef,0x3f,0x97,0x70,0x66,0xc9,0xad,0xd5,0xc7,0x10,0xcc,0x64,0x7b,0x15,0x14,0xd2,0x17,0xd9,0x58,0xc7,0x01,0x7c,0x3e,0x90,0xfd,0x20,0xc0,0x4e,0x67,0x4b,0x90,0x48,0x6e,0x93,0x70,0xa3,0x1a,0x00,0x1d,0x32,0xf4,0x73,0x97,0x9e,0x49,0x06,0x74,0x9e,0x7e,0x47,0x7f,0xa0,0xb7,0x45,0x08,0xf8,0xa5,0xf2,0x37,0x83,0x12,0xb8,0x3c,0x25,0xbd,0x38,0x8c,0xa0,0xb0,0xff,0xf7,0x47,0x8b,0xaf,0x42,0xb7,0x16,0x67,0xed,0xaa,0xc9,0x7c,0x46,0xb1,0x29,0x64,0x3e,0x58,0x6e,0x5b,0x05,0x5a,0x0c,0x21,0x19,0x46,0xd4,0xf3,0x6e,0x67,0x5b,0xed,0x58,0x60,0xfa,0x04,0x2a,0x31,0x5d,0x98,0x26,0x16,0x4d,0x6a,0x92,0x37,0xc3,0x5a,0x5f,0xbf,0x49,0x54,0x90,0xa5,0xbd,0x4d,0xf2,0x48,0xb9,0x5c,0x4a,0xae,0x77,0x84,0xb6,0x05,0x67,0x31,0x66,0xac,0x42,0x45,0xb5,0xb4,0xb0,0x82,0xa0,0x9e,0x93,0x23,0xe6,0x2f,0x20,0x78,0xc5,0xb7,0x67,0x83,0x44,0x6d,0xef,0xd7,0x36,0xad,0x3a,0x37,0x02,0xd4,0x9b,0x08,0x98,0x44,0x90,0x0a,0x61,0x83,0x33,0x97,0xbc,0x44,0x19,0xb3,0x0d,0x7a,0x97,0xa0,0xb3,0x87,0xc1,0x91,0x14,0x74,0xc4,0xd4,0x1b,0x53,0xe3,0x2a,0x97,0x7a,0xcb,0x6f,0x0e,0xa7,0x5d,0xb6,0x5b,0xb3,0x9e,0x59,0xe7,0x01,0xe7,0x69,0x57,0xde,0xf6,0xf2,0xd4,0x45,0x59,0xc3,0x1a,0x77,0x12,0x2b,0x52,0x04,0xe3,0xb5,0xc2,0x19,0xf1,0x68,0x8b,0x14,0xed,0x0b,0xc0,0xb8,0x01,0xb3,0xe6,0xe8,0x2d,0xcd,0x43,0xe9,0xc0,0xe9,0xf4,0x17,0x44,0xcd,0x98,0x15,0xbd,0x1b,0xc8,0x82,0x0d,0x8b,0xb1,0x23,0xf0,0x4f,0xac,0xd1,0xb1,0xb6,0x85,0xdd,0x5a,0x2b,0x1b,0x8d,0xbb,0xf3,0xed,0x93,0x36,0x70,0xf0,0x95,0xa1,0x80,0xb4,0xf1,0x92,0xd0,0x8b,0x10,0xb8,0xfa,0xbb,0xdf,0xcc,0x2b,0x24,0x51,0x8e,0x32,0xee,0xa0,0xa5,0xe0,0xc9,0x04,0xca,0x84,0x47,0x80,0x08,0x3f,0x3b,0x0c,0xd2,0xd0,0xb8,0xb6,0xaf,0x67,0xbc,0x35,0x5b,0x94,0x94,0x02,0x5d,0xc7,0xb0,0xa7,0x8f,0xa8,0x0e,0x3a,0x2d,0xbf,0xeb,0x51,0x32,0x88,0x51,0xd6,0x07,0x81,0x98,0xe9,0x49,0x36,0x51,0xae,0x78,0x7e,0xc0,0x25,0x1f,0x92,0x2b,0xa3,0x0e,0x9f,0x51,0xdf,0x62,0xa6,0xd7,0x27,0x84,0xcf,0x3d,0xd2,0x05,0x39,0x31,0x76,0xdf,0xa3,0x24,0xa5,0x12,0xbd,0x94,0x97,0x0a,0x36,0xdd,0x34,0xa5,0x14,0xa8,0x67,0x91,0xf0,0xeb,0x36,0xf0,0x14,0x5b,0x09,0xab,0x64,0x65,0x1b,0x4a,0x03,0x13,0xb2,0x99,0x61,0x1a,0x2a,0x1c,0x48,0x89,0x16,0x27,0x59,0x87,0x68,0xa3,0x11,0x40,0x60,0xba,0x44,0x43,0x48,0x6d,0xf5,0x15,0x22,0xa1,0xce,0x88,0xb3,0x09,0x85,0xc2,0x16,0xf8,0xe6,0xed,0x17,0x8d,0xd5,0x67,0xb3,0x04,0xa0,0xd4,0xca,0xfb,0xa8,0x82,0xa2,0x83,0x42,0xf1,0x7a,0x9a,0xa2,0x6a,0xe5,0x8d,0xb6,0x30,0x08,0x3d,0x2c,0x35,0x8f,0xdf,0x56,0x6c,0x3f,0x5d,0x62,0xa4,0x28,0x56,0x7b,0xc9,0xea,0x8c,0xe9,0x5c,0xaa,0x0f,0x35,0x47,0x4b,0x0b,0xfa,0x8f,0x33,0x9a,0x25,0x0a,0xb4,0xdf,0xcf,0x20,0x83,0xbe,0x8e,0xef,0xbc,0x10,0x55,0xe1,0x8f,0xe1,0x53,0x70,0xee,0xcb,0x26,0x05,0x66,0xd8,0x3f,0xf0,0x6b,0x21,0x1a,0xae,0xc4,0x3c,0xa2,0x9b,0x54,0xcc,0xd0,0x0f,0x88,0x15,0xa2,0x46,0x5e,0xf0,0xb4,0x65,0x15,0xcc,0x7e,0x41,0xf3,0x12,0x4f,0x09,0xef,0xff,0x73,0x93,0x09,0xab,0x58,0xb2,0x9a,0x14,0x59,0xa0,0x0b,0xce,0x50,0x38,0xe9,0x38,0xc9,0x67,0x8f,0x72,0xeb,0x0e,0x4e,0xe5,0xfd,0xaa,0xe6,0x6d,0x9f,0x85,0x73,0xfc,0x97,0xfc,0x42,0xb4,0x95,0x9f,0x4b,0xf8,0xb6,0x1d,0x78,0x43,0x3e,0x86,0xb0,0x33,0x5d,0x6e,0x91,0x91,0xc4,0xd8,0xbf,0x48,0x7b,0x39,0x05,0xc1,0x08,0xcf,0xd6,0xac,0x24,0xb0,0xce,0xb7,0xdc,0xb7,0xcf,0x51,0xf8,0x4d,0x0e,0xd6,0x87,0xb9,0x5e,0xae,0xb1,0xc5,0x33,0xc0,0x6f,0x0d,0x97,0x02,0x3d,0x92,0xa7,0x08,0x25,0x83,0x7b,0x59,0xba,0x6c,0xb7,0xd4,0xe5,0x6b,0x0a,0x87,0xc2,0x03,0x86,0x2a,0xe8,0xf3,0x15,0xba,0x59,0x25,0xe8,0xed,0xef,0xa6,0x79,0x36,0x9a,0x22,0x02,0x76,0x61,0x51,0xf1,0x6a,0x96,0x5f,0x9f,0x81,0xec,0xe7,0x6c,0xc0,0x70,0xb5,0x58,0x69,0xe4,0xdb,0x97,0x84,0xcf,0x05,0xc8,0x30,0xb3,0x24,0x2c,0x83,0x12]).unwrap(); - let sig: [u8; MLDSA44_SIG_LEN] = [0x5e,0x93,0xb7,0x85,0xc5,0x11,0x9c,0x39,0x83,0xa2,0x91,0xb1,0x84,0x20,0xfd,0xbe,0x4b,0xca,0x53,0xd5,0xa3,0x73,0x29,0x22,0xfa,0xaa,0xcd,0x5a,0x5d,0x32,0xa7,0x45,0xc7,0x8d,0x10,0x5b,0xa1,0x0b,0xee,0x1e,0xd8,0x06,0x9f,0x19,0xe6,0xc5,0x37,0xbd,0xa1,0x6e,0x89,0xd3,0x90,0x04,0xc3,0x59,0xd1,0xfd,0x38,0x1a,0x02,0x91,0xf1,0xc5,0x1f,0x1c,0x38,0xed,0xcd,0xb3,0x15,0xc8,0xc6,0x95,0x70,0xd8,0xf2,0x5f,0x16,0x55,0xba,0x8e,0xa8,0x3a,0xff,0x24,0xb8,0xb6,0xbe,0x8d,0xe7,0x62,0x34,0x2e,0x34,0x7e,0xab,0x2c,0xaa,0x68,0x03,0xed,0x70,0x59,0x52,0xdd,0x64,0x50,0xc5,0x18,0x5e,0x9d,0x60,0xce,0x96,0xe8,0xdc,0xa4,0x23,0xa0,0x2f,0x64,0x6c,0xea,0x69,0x01,0x64,0xa2,0x26,0xe4,0xc3,0xd6,0xa5,0x15,0xce,0x16,0x29,0x0f,0x19,0xb2,0xc6,0x26,0xda,0x9b,0x45,0x0e,0xcf,0x66,0x50,0x13,0xc5,0xe2,0x26,0xb6,0xc0,0xac,0x5c,0x07,0xce,0x90,0xe2,0x78,0xf1,0xb0,0x13,0x4e,0x38,0x5d,0x13,0xe7,0x42,0x08,0xa0,0xb3,0xff,0x05,0x2a,0x36,0x25,0x79,0xf9,0x20,0x7e,0xa0,0x1f,0x18,0xa0,0x39,0xaa,0x1b,0x97,0xae,0x34,0x52,0x67,0x5b,0x62,0x07,0x71,0xf8,0x01,0x2e,0xe7,0xa4,0xe5,0x5c,0x98,0xbf,0xd2,0x01,0x9e,0xd8,0xa3,0xb0,0x0a,0xce,0xa8,0xe8,0xab,0x28,0x17,0x2f,0xaa,0x42,0xca,0x1f,0xda,0x83,0xc5,0xff,0xe8,0x1a,0x45,0xbe,0x73,0x6b,0xde,0xdd,0x5f,0xb3,0x00,0xce,0x17,0x07,0x8b,0x38,0x0f,0x62,0x0b,0xde,0xeb,0xad,0x69,0x36,0x01,0x37,0x2c,0x85,0xea,0xcf,0x79,0xbc,0x98,0xe1,0xb4,0x8f,0x2a,0xd7,0xe5,0xdc,0xe4,0x27,0x9a,0x12,0x95,0xbb,0x2b,0xa6,0x0a,0x0c,0x5e,0x37,0x26,0x64,0x2d,0x23,0x36,0xc5,0xeb,0x1d,0x37,0xc8,0x62,0x3c,0x75,0x58,0x24,0x13,0x18,0xd8,0x9b,0xc7,0x83,0xc4,0xf0,0x00,0x98,0x07,0x74,0x84,0x62,0x3c,0x21,0x75,0x60,0xa0,0xc7,0xaa,0xf7,0x5d,0xca,0xcc,0xb7,0x8e,0xe6,0x9c,0x20,0x7c,0x27,0xc8,0xbf,0x39,0x65,0xcc,0xf5,0x8a,0x80,0xc8,0x8e,0xfc,0xc7,0xe5,0xde,0xb3,0x61,0x5d,0x50,0x45,0xa7,0x41,0xc4,0xda,0xc0,0xa0,0x21,0xdd,0x06,0x0d,0x31,0x5d,0x4e,0xc2,0x85,0x7e,0xb6,0x64,0xd7,0x28,0xd0,0xaf,0x97,0x3b,0xea,0x07,0xe1,0xca,0x56,0x3f,0xaa,0x0e,0x19,0x99,0x6c,0xea,0x37,0x70,0x31,0x6c,0x11,0xa5,0x06,0x66,0x65,0x66,0x20,0x05,0xac,0xe9,0x8f,0x61,0x10,0xe8,0x83,0xba,0xe0,0x60,0xda,0xa7,0xb6,0xd8,0x33,0x79,0xe0,0x87,0x87,0x96,0x69,0x17,0x08,0xa3,0x2b,0x85,0x73,0x0d,0xe8,0xb9,0x2d,0x89,0xf9,0x0a,0x36,0x60,0xc9,0x49,0x16,0x5b,0x14,0x61,0x25,0x67,0x66,0x2e,0x16,0x22,0x32,0x29,0x6c,0xbd,0x14,0x35,0x17,0xa2,0x82,0xe2,0x2c,0x46,0xb6,0x36,0x06,0xd3,0xc1,0x4e,0xd4,0x55,0x9a,0x5a,0x1c,0x45,0x9b,0xab,0x7f,0x35,0x50,0x07,0xad,0x6f,0x7e,0x3b,0x1e,0x07,0x44,0x5d,0xfc,0x96,0xbd,0x9b,0x75,0x08,0x0b,0x3d,0x4f,0x68,0x99,0x84,0x90,0xa2,0x6b,0x5e,0x09,0x0b,0xe2,0x67,0x40,0x71,0xab,0x92,0x5b,0xb6,0x50,0x59,0x08,0x56,0xc5,0x9f,0x8b,0xa7,0x48,0x8d,0x2b,0x72,0xf8,0x40,0xac,0x3e,0xaf,0xe4,0xdd,0x91,0xf0,0xf5,0x1c,0x43,0x64,0x11,0x2c,0x1a,0x13,0x9e,0x3e,0x94,0x2a,0x59,0x7b,0x93,0xa1,0xe3,0xf4,0xfa,0xde,0xd1,0x29,0xc1,0x4b,0x59,0x78,0xb3,0x15,0xe2,0x24,0x6a,0x93,0x14,0x6a,0x79,0x36,0x5f,0x0f,0x59,0x7a,0x18,0x34,0x0c,0xca,0x86,0xbb,0x15,0xce,0xed,0x39,0xf1,0x75,0xea,0xb1,0xe5,0x46,0x53,0x5a,0xfb,0x96,0x6f,0x0a,0x65,0xa8,0xf6,0x6f,0x73,0x7a,0xb0,0x28,0x97,0xed,0xdf,0xe9,0x2c,0xf7,0x78,0x68,0x94,0x84,0x3c,0x26,0x91,0x46,0x47,0x76,0xc9,0x4b,0xd4,0x50,0xa1,0x06,0x91,0x38,0xb2,0x6d,0xf8,0x3b,0x2d,0x1d,0xd8,0x01,0x14,0x3a,0x8f,0xdf,0xdc,0x25,0x14,0xcc,0x5b,0x58,0x31,0xab,0x53,0xa7,0x5c,0x55,0xef,0x29,0xf4,0x0e,0x7c,0x63,0xd2,0xc7,0x2a,0xbe,0x97,0xe2,0xaf,0x14,0x85,0x3b,0xe4,0x9b,0xe1,0x6f,0x47,0x30,0xa1,0x59,0x97,0x49,0x70,0x95,0x14,0x39,0xe5,0x5c,0x15,0x89,0xd0,0xf4,0xa1,0x62,0xe3,0x51,0x7d,0xf9,0xd7,0xab,0xc9,0x8d,0x8a,0x30,0x72,0x16,0xe7,0xf1,0xcb,0x46,0x27,0xc9,0x17,0x5c,0x0e,0xef,0x23,0x33,0x7e,0x56,0xd5,0x28,0x1b,0x83,0x72,0x6f,0xff,0x40,0xa1,0x48,0xb0,0xc4,0x8e,0x8d,0xf3,0x49,0x6a,0x21,0x18,0xd8,0x02,0x19,0xae,0xf8,0xf4,0x0b,0x29,0xfb,0xa1,0xf2,0xf7,0x87,0x86,0xb6,0x7f,0xfb,0x7b,0x7d,0x47,0xd4,0x06,0xb7,0x65,0xbd,0x13,0x66,0x10,0xbe,0xde,0xb9,0x5c,0xd7,0x32,0x1f,0x58,0xf3,0xb8,0x36,0xc9,0x25,0x8b,0xe3,0x5d,0x78,0xb4,0x98,0xf3,0xef,0xe1,0xdb,0x2b,0x24,0x3d,0x73,0x4f,0xab,0x15,0x9b,0xae,0xd8,0x80,0x7c,0x3c,0xcc,0xf8,0x3e,0xb2,0xea,0xf8,0xa9,0xaf,0x01,0xa5,0x18,0xd4,0x8c,0x60,0xe9,0x1a,0x96,0x81,0x2a,0xd6,0x89,0xc2,0xd8,0x3c,0xc4,0xe8,0xe9,0xb3,0x65,0x04,0x22,0xbe,0xd6,0xf1,0x3c,0x24,0xad,0xaa,0xd9,0x1c,0x95,0xb3,0xe3,0xcf,0x35,0x4f,0x0f,0x6b,0xc9,0xee,0x89,0x41,0xa6,0xb1,0x5b,0x69,0x75,0x13,0x1d,0x95,0x23,0x3d,0x89,0x35,0xde,0x36,0x7e,0xfc,0x6d,0x86,0xa4,0x5d,0xac,0x7d,0x0f,0x1d,0xdd,0x9a,0xeb,0xd2,0xc5,0x9c,0x02,0x7f,0xcd,0xa4,0x48,0x80,0x1e,0x93,0xe7,0x33,0xac,0xa5,0x18,0x74,0xbe,0x9a,0xb9,0x27,0xa9,0x04,0xf9,0x6d,0xdb,0x7a,0x46,0xb2,0xda,0x13,0x26,0x1d,0x52,0x2b,0x23,0xc9,0x50,0xc0,0x1d,0x5f,0x5e,0x11,0x2b,0x76,0xf8,0x51,0xff,0x23,0x4f,0x06,0xf8,0xd5,0xe6,0x5b,0x13,0x19,0xab,0xcd,0x79,0xa1,0x80,0xae,0x06,0x3d,0x65,0xb2,0x8c,0x74,0x58,0x78,0xc0,0x6d,0xbb,0x69,0xba,0x73,0x29,0x3e,0xab,0x34,0x43,0x4b,0xf1,0xa9,0x2f,0xba,0x69,0x19,0x93,0xbd,0x0f,0xf3,0xed,0xac,0x76,0xa1,0x2f,0x80,0xc0,0xad,0xa4,0xb1,0x96,0x9c,0x76,0x65,0x58,0x9d,0x53,0x0a,0x67,0x01,0x6a,0x62,0x54,0x03,0xc5,0x37,0x03,0x29,0x04,0xf2,0xe1,0x04,0x54,0x7c,0xd3,0xea,0x40,0x62,0x60,0xdd,0x35,0x7f,0xa0,0x6e,0xa0,0x12,0xa7,0x85,0x82,0x6c,0x16,0x0e,0x99,0xff,0xd0,0x65,0xb0,0xe3,0xf3,0x3c,0x76,0x89,0xd3,0x55,0x2a,0xb9,0xe2,0xe0,0x9f,0xa7,0xe5,0x5b,0xbc,0xef,0x04,0x22,0x42,0xbc,0xac,0xad,0x8a,0x3d,0xa4,0x7b,0xcc,0x54,0xa1,0x21,0xf1,0x52,0x6c,0x8c,0xd4,0xcc,0x5a,0x89,0x2a,0x81,0x31,0xcf,0x4e,0xef,0xaf,0x42,0x48,0xdd,0xd6,0xa1,0x1e,0xc4,0x27,0xba,0x37,0x8a,0xae,0x89,0xaa,0xf5,0x82,0xce,0x1f,0x4e,0x32,0x69,0x0a,0x55,0x5e,0x74,0x07,0x61,0xd3,0x58,0xad,0x4e,0x92,0xbc,0x38,0x41,0x8a,0xa7,0x82,0xda,0x91,0x65,0x24,0xfb,0x09,0xab,0x2c,0xa6,0xb3,0xd3,0x11,0x3d,0x6f,0x2c,0x2a,0x6a,0x9b,0x9d,0x29,0xd4,0xe7,0x48,0x92,0x55,0x25,0x2a,0xf0,0x75,0xcb,0xf9,0xfe,0xac,0xed,0xae,0x6f,0x3e,0xc0,0xb0,0x70,0x82,0x46,0x89,0xdd,0x3c,0x78,0xac,0x14,0x3e,0xd6,0x77,0x6d,0x95,0xdd,0x8f,0x13,0xd4,0x35,0xa2,0x90,0xbd,0xca,0x4c,0x11,0x31,0x8e,0x5a,0xcc,0xe0,0x44,0x69,0x64,0x4e,0x13,0x74,0xa9,0x45,0x1b,0x62,0x04,0xf3,0xb3,0x96,0x1b,0x7d,0xd2,0x39,0xe3,0x06,0xfe,0xf5,0xf4,0xf4,0xe5,0x1b,0x78,0xb0,0xfb,0x9d,0xce,0xe6,0x9c,0x3e,0x79,0x0b,0x23,0x1f,0x2e,0x65,0xfd,0x1a,0xb1,0xc2,0xa7,0x5b,0x07,0x06,0x7d,0x5c,0x16,0xdd,0xe0,0x09,0x83,0xa5,0x8f,0xfc,0xda,0xaa,0xee,0x16,0xd2,0x74,0x2e,0x13,0x3e,0xd7,0x37,0xb4,0x80,0x64,0xc8,0xa3,0x8e,0xca,0x35,0xab,0x3f,0xa1,0x8f,0x6d,0x62,0xf6,0x42,0xb1,0x2c,0xfd,0xc7,0x98,0x0f,0x2a,0xb7,0xdb,0x32,0x1f,0xec,0x9d,0xcf,0xe4,0x99,0xb4,0xfc,0x1e,0xe7,0xeb,0x29,0x79,0x54,0x05,0x66,0x17,0xc6,0x0a,0x66,0x40,0xb9,0x28,0x35,0xd1,0x65,0xc3,0xc0,0x0a,0x95,0x19,0x52,0x61,0x44,0x88,0xd5,0x65,0x7b,0xa0,0xb5,0xe9,0x0a,0xe9,0xe0,0xef,0x7b,0x3b,0x9e,0xca,0xeb,0xd8,0x1b,0x85,0x51,0xb6,0xd7,0x0e,0x83,0x5b,0x27,0x34,0x76,0x16,0x39,0xd4,0x2e,0x76,0xff,0xc5,0xb3,0x27,0x2b,0x61,0xc8,0x96,0xb4,0x5b,0x4b,0xd1,0x8f,0x30,0xe5,0x8c,0x44,0x06,0x43,0xba,0x15,0x92,0x21,0xcc,0x67,0x39,0xa1,0x9a,0x65,0xf2,0x91,0x1f,0xae,0x47,0xb0,0xd4,0xca,0xc4,0x20,0x0a,0x6f,0x04,0x3b,0x17,0xa0,0x3a,0xd3,0x93,0xec,0xb8,0x23,0xed,0x03,0xc8,0xb6,0xcd,0x68,0x16,0x7e,0x6c,0x82,0x34,0xf7,0x43,0x25,0x57,0xdb,0x27,0x20,0x79,0xee,0x89,0x9a,0xed,0xe7,0x3b,0x6b,0x98,0xd6,0x00,0x3f,0x45,0x78,0x9a,0x14,0x1b,0x60,0xd6,0xdb,0x40,0xcd,0x2a,0x59,0x74,0x57,0x1a,0x4a,0xd3,0x66,0x7b,0x88,0x93,0x18,0xba,0x60,0x28,0x5d,0x90,0x3a,0x2e,0xac,0x01,0xc2,0x16,0x08,0x83,0x8c,0x40,0x90,0x7d,0xe6,0xbb,0xab,0xe0,0x42,0xcf,0x2e,0xcd,0xd9,0x7f,0x54,0x9f,0x95,0xec,0x69,0x8d,0x79,0x22,0x2c,0x65,0xba,0x27,0xc3,0x0d,0x33,0x2a,0x68,0xd0,0x57,0xae,0xcd,0xc9,0x38,0x8a,0xa3,0x43,0x20,0xe0,0xaa,0x74,0xfd,0xbd,0x4d,0x1b,0x64,0x3c,0xac,0xe2,0x16,0xb6,0xd8,0xad,0x8f,0x07,0xa9,0x99,0x55,0xbf,0xdb,0x74,0x3a,0x86,0xb4,0x0f,0xc6,0x15,0x27,0xba,0xca,0x43,0x4a,0xc2,0xa7,0xfb,0xea,0xa7,0x71,0x11,0xdc,0x80,0x98,0xb1,0x7e,0x80,0x0f,0x59,0xdd,0x77,0xcc,0xb0,0xe6,0x77,0x07,0xe6,0x01,0x23,0xd3,0x34,0xe0,0x73,0xa2,0xf5,0xa1,0x6f,0xfb,0xcd,0x70,0x13,0x89,0xad,0xd5,0x7c,0x3c,0xec,0xcb,0x88,0xb2,0x86,0xac,0x1e,0x6e,0x3e,0x64,0x85,0xaf,0x1a,0x12,0xea,0x24,0x1d,0x14,0xa1,0xb5,0x00,0x3d,0x7f,0x3b,0xc9,0xe9,0x57,0xd4,0x48,0x3c,0x0f,0x9f,0x70,0x3b,0x3a,0x18,0x7d,0x55,0xe5,0x05,0x81,0x76,0x15,0xfb,0xc4,0xae,0x08,0x37,0x61,0x61,0x84,0x24,0x5c,0xfb,0xa6,0x1c,0xe3,0xb9,0x29,0xe3,0x3f,0x52,0xb7,0x1c,0xdd,0x7b,0x6a,0x0d,0xa5,0x5c,0x1f,0x99,0x75,0x10,0xb1,0xa9,0x00,0x2c,0xa4,0xe0,0x67,0x83,0x73,0xa3,0xb1,0xab,0x28,0x97,0xe6,0xb4,0x23,0xf1,0x5a,0x44,0x0a,0x63,0x6c,0xc8,0x61,0x49,0x1e,0xf4,0x1a,0xd0,0xaa,0x62,0x7d,0x8e,0x19,0x8a,0x5e,0xe7,0xbd,0x7b,0x6c,0xb2,0xc9,0xce,0x2a,0x8c,0xc0,0x15,0xf0,0xd2,0x06,0xde,0x4c,0x49,0xe2,0xf8,0x7f,0x31,0x09,0x54,0xa1,0x0d,0x86,0xe2,0x94,0xf7,0x42,0xee,0x18,0x6f,0x4a,0xe9,0x81,0x5f,0x69,0x96,0x22,0x79,0x22,0x06,0xca,0xfb,0xa8,0xf5,0x62,0x17,0x38,0x16,0x0e,0x6c,0x5d,0x61,0x1a,0x82,0x52,0xc6,0xf3,0x50,0x85,0xb6,0x04,0xef,0x89,0x51,0x64,0xd4,0xea,0x6d,0xdd,0x31,0x0c,0x7d,0x8f,0x0c,0x87,0x9f,0xb1,0xf8,0x84,0xc5,0x74,0x1d,0x09,0x6b,0x3d,0x2d,0xa0,0xce,0x11,0x51,0x79,0x0d,0xda,0x88,0x1d,0x18,0xcb,0x6b,0x19,0xa9,0xfe,0xd6,0xf5,0x25,0x4b,0x7d,0x52,0xd5,0xd9,0x2b,0xbb,0xe2,0x4c,0x9d,0x6a,0x65,0x60,0x4a,0x0b,0x8e,0xd2,0x4a,0xd5,0xc1,0x97,0xd6,0x83,0xf5,0x98,0x74,0x3c,0x96,0xb5,0x96,0x0e,0x87,0x23,0x73,0x2b,0x5b,0xd6,0x47,0xe9,0xdb,0xea,0xa8,0x51,0xd0,0xe1,0xcf,0x6d,0x2c,0x07,0x0d,0x44,0x42,0x76,0x2c,0x28,0x09,0x8c,0x5c,0xf5,0xa5,0x4b,0x2b,0x5e,0x69,0xa9,0x9b,0x10,0x81,0x5b,0xf0,0xf4,0x77,0xbb,0x71,0xf0,0xd5,0xd3,0xa6,0x2b,0xa2,0xb3,0xe2,0x9b,0xf8,0x4d,0x4b,0x4e,0x57,0x47,0x07,0xf5,0xf7,0x4a,0xf7,0x04,0xd2,0x77,0xbd,0x6c,0xa3,0x8d,0xa2,0x1e,0x2c,0xda,0xc5,0x49,0xe5,0xea,0xe1,0xde,0x7a,0x18,0xee,0x53,0x4c,0x8c,0x22,0x91,0xc9,0x08,0xca,0xab,0xf1,0x59,0xe9,0x0e,0x65,0x49,0xdb,0x94,0xba,0x7a,0x3f,0x3d,0x97,0xdd,0x39,0x8a,0x75,0xdf,0x5b,0x1a,0x7c,0xdf,0xb2,0x54,0x10,0xb7,0xef,0xc4,0xed,0x00,0xd9,0x99,0x5b,0x37,0xb5,0x8b,0xf9,0x1e,0xd7,0xa3,0x51,0x0c,0xff,0xea,0x82,0xf9,0xe1,0xc2,0xa3,0x29,0x04,0x06,0x00,0x4d,0x09,0x05,0x7d,0x63,0xb7,0x70,0xfa,0x0e,0x53,0x10,0x31,0x99,0x54,0x4e,0xba,0x66,0x2a,0x2c,0x30,0x2c,0xf3,0x90,0x08,0xf1,0x42,0xd2,0xb1,0x69,0x63,0xe9,0x5a,0xb1,0x0b,0xe7,0xc2,0x61,0x01,0x68,0x60,0x8f,0x35,0x3a,0x2f,0x2c,0x41,0xc7,0x05,0x6d,0xec,0x1a,0x8c,0x7a,0x6b,0xfa,0x00,0x27,0xf9,0xde,0xda,0xcb,0x77,0x86,0xb6,0x7e,0xa2,0xc4,0x94,0xd4,0x3b,0xa8,0x51,0xcf,0x94,0x15,0xc1,0xbc,0xc5,0x2f,0x02,0x7e,0xc0,0x2c,0x65,0x53,0x4f,0x60,0x8e,0x9d,0x16,0x6d,0x51,0xdd,0x43,0x1c,0xdf,0x58,0x71,0xf5,0xcd,0xd1,0x57,0x9c,0xc0,0x60,0x79,0xdf,0x07,0x5a,0x25,0x06,0x2b,0xa7,0xe7,0x0d,0x96,0x66,0xc4,0xe7,0xfe,0xd3,0x4c,0xea,0x0e,0xa0,0xf1,0x1a,0xde,0x1e,0xb2,0xa9,0xb3,0x97,0xbc,0xaa,0xad,0x10,0x61,0x27,0x0e,0xcf,0x49,0x78,0x03,0xa5,0xfc,0xe7,0xf4,0x1e,0x65,0x04,0xfb,0xec,0x71,0xa7,0xde,0x7d,0x06,0x6b,0x82,0x61,0x86,0x8a,0xfc,0x49,0xb9,0xe6,0x85,0xf0,0xdc,0xce,0x75,0xe2,0xfc,0xb3,0xba,0x8c,0xf1,0x90,0x57,0xe3,0x94,0x15,0x76,0xba,0xf5,0x8f,0xb8,0x21,0xbd,0x42,0x68,0xf7,0xfa,0xe3,0x02,0x86,0x01,0xda,0x02,0x2e,0x9b,0x46,0x86,0x46,0xab,0xdb,0x4f,0xa6,0x09,0x8a,0x44,0x9b,0x42,0x67,0xd5,0x09,0xd9,0xa3,0x3f,0x4c,0x3e,0xbc,0xc3,0x2d,0xac,0x09,0x4d,0x48,0xed,0x60,0x0e,0x76,0x57,0x87,0xfb,0x92,0xb1,0x97,0x4f,0x74,0xf7,0xbb,0x4c,0x66,0xeb,0x2b,0xbd,0x02,0x89,0x5e,0x6a,0x38,0x1c,0x1c,0x45,0x2e,0xaa,0xb1,0xae,0x47,0x31,0xcf,0x63,0x2f,0x61,0xae,0x2c,0x90,0x59,0x21,0x17,0x4a,0x3b,0xc9,0xbb,0x4c,0xdc,0x89,0xd6,0x30,0x26,0x4b,0x61,0x49,0x88,0xf3,0xab,0xbe,0xa1,0xbd,0x61,0x7f,0xfa,0x53,0xd7,0x1b,0x7d,0x8a,0x37,0x14,0x62,0xb7,0x73,0x35,0x1a,0x2d,0xcc,0xae,0xdd,0x7f,0x59,0xcd,0x72,0x8f,0xad,0xee,0x05,0x90,0x67,0xbd,0x80,0xc9,0x4c,0x8c,0x9a,0x1f,0xfc,0xa2,0xdc,0x4f,0x84,0x8b,0x82,0x9c,0x05,0x61,0x38,0x5a,0xa8,0x2c,0xc9,0x85,0x03,0xd0,0xbb,0x66,0xa6,0xaa,0x4f,0xae,0x07,0x03,0xd1,0x2e,0x60,0xe1,0x46,0x0e,0xfb,0xbc,0xdf,0x24,0x12,0xc1,0x3e,0x7c,0x68,0x4d,0x1b,0x01,0x10,0x20,0x26,0x34,0x3a,0x41,0x43,0x44,0x58,0x5f,0x6e,0x70,0x72,0x74,0x8b,0xae,0xb5,0xbb,0xc6,0xd1,0xe2,0xef,0xfb,0xfe,0x06,0x0e,0x2e,0x3e,0x51,0x60,0x79,0x7c,0x9e,0xa6,0xba,0xc7,0xf1,0x10,0x24,0x40,0x4a,0x52,0x57,0x5f,0x6c,0x89,0x8c,0x97,0xaa,0xb2,0xc3,0xcc,0xea,0xf2,0x2f,0x3f,0x53,0x5f,0x7b,0x81,0x83,0x96,0xa1,0xb1,0xbc,0xe6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x25,0x36,0x42]; + let mldsa44_pk = MLDSA44PublicKey::from_bytes(&[ + 0xD7, 0xB2, 0xB4, 0x72, 0x54, 0xAA, 0xE0, 0xDB, 0x45, 0xE7, 0x93, 0x0D, 0x4A, 0x98, 0xD2, + 0xC9, 0x7D, 0x8F, 0x13, 0x97, 0xD1, 0x78, 0x9D, 0xAF, 0xA1, 0x70, 0x24, 0xB3, 0x16, 0xE9, + 0xBE, 0xC9, 0x4F, 0xC9, 0x94, 0x6D, 0x42, 0xF1, 0x9B, 0x79, 0xA7, 0x41, 0x3B, 0xBA, 0xA3, + 0x3E, 0x71, 0x49, 0xCB, 0x42, 0xED, 0x51, 0x15, 0x69, 0x3A, 0xC0, 0x41, 0xFA, 0xCB, 0x98, + 0x8A, 0xDE, 0xB5, 0xFE, 0x0E, 0x1D, 0x86, 0x31, 0x18, 0x49, 0x95, 0xB5, 0x92, 0xC3, 0x97, + 0xD2, 0x29, 0x4E, 0x2E, 0x14, 0xF9, 0x0A, 0xA4, 0x14, 0xBA, 0x38, 0x26, 0x89, 0x9A, 0xC4, + 0x3F, 0x4C, 0xCC, 0xAC, 0xBC, 0x26, 0xE9, 0xA8, 0x32, 0xB9, 0x51, 0x18, 0xD5, 0xCB, 0x43, + 0x3C, 0xBE, 0xF9, 0x66, 0x0B, 0x00, 0x13, 0x8E, 0x08, 0x17, 0xF6, 0x1E, 0x76, 0x2C, 0xA2, + 0x74, 0xC3, 0x6A, 0xD5, 0x54, 0xEB, 0x22, 0xAA, 0xC1, 0x16, 0x2E, 0x4A, 0xB0, 0x1A, 0xCB, + 0xA1, 0xE3, 0x8C, 0x4E, 0xFD, 0x8F, 0x80, 0xB6, 0x5B, 0x33, 0x3D, 0x0F, 0x72, 0xE5, 0x5D, + 0xFE, 0x71, 0xCE, 0x9C, 0x1E, 0xBB, 0x98, 0x89, 0xE7, 0xC5, 0x61, 0x06, 0xC0, 0xFD, 0x73, + 0x80, 0x3A, 0x2A, 0xEC, 0xFE, 0xAF, 0xDE, 0xD7, 0xAA, 0x3C, 0xB2, 0xCE, 0xDA, 0x54, 0xD1, + 0x2B, 0xD8, 0xCD, 0x36, 0xA7, 0x8C, 0xF9, 0x75, 0x94, 0x3B, 0x47, 0xAB, 0xD2, 0x5E, 0x88, + 0x0A, 0xC4, 0x52, 0xE5, 0x74, 0x2E, 0xD1, 0xE8, 0xD1, 0xA8, 0x2A, 0xFA, 0x86, 0xE5, 0x90, + 0xC7, 0x58, 0xC1, 0x5A, 0xE4, 0xD2, 0x84, 0x0D, 0x92, 0xBC, 0xA1, 0xA5, 0x09, 0x0F, 0x40, + 0x49, 0x65, 0x97, 0xFC, 0xA7, 0xD8, 0xB9, 0x51, 0x3F, 0x1A, 0x1B, 0xDA, 0x6E, 0x95, 0x0A, + 0xAA, 0x98, 0xDE, 0x46, 0x75, 0x07, 0xD4, 0xA4, 0xF5, 0xA4, 0xF0, 0x59, 0x92, 0x16, 0x58, + 0x2C, 0x35, 0x72, 0xF6, 0x2E, 0xDA, 0x89, 0x05, 0xAB, 0x35, 0x81, 0x67, 0x0C, 0x4A, 0x02, + 0x77, 0x7A, 0x33, 0xE0, 0xCA, 0x72, 0x95, 0xFD, 0x8F, 0x4F, 0xF6, 0xD1, 0xA0, 0xA3, 0xA7, + 0x68, 0x3D, 0x65, 0xF5, 0xF5, 0xF7, 0xFC, 0x60, 0xDA, 0x02, 0x3E, 0x82, 0x6C, 0x5F, 0x92, + 0x14, 0x4C, 0x02, 0xF7, 0xD1, 0xBA, 0x10, 0x75, 0x98, 0x75, 0x53, 0xEA, 0x93, 0x67, 0xFC, + 0xD7, 0x6D, 0x99, 0x0B, 0x7F, 0xA9, 0x9C, 0xD4, 0x5A, 0xFD, 0xB8, 0x83, 0x6D, 0x43, 0xE4, + 0x59, 0xF5, 0x18, 0x7D, 0xF0, 0x58, 0x47, 0x97, 0x09, 0xA0, 0x1E, 0xA6, 0x83, 0x59, 0x35, + 0xFA, 0x70, 0x46, 0x09, 0x90, 0xCD, 0x3D, 0xC1, 0xBA, 0x40, 0x1B, 0xA9, 0x4B, 0xAB, 0x1D, + 0xDE, 0x41, 0xAC, 0x67, 0xAB, 0x33, 0x19, 0xDC, 0xAC, 0xA0, 0x60, 0x48, 0xD4, 0xC4, 0xEE, + 0xF2, 0x7E, 0xE1, 0x3A, 0x9C, 0x17, 0xD0, 0x53, 0x8F, 0x43, 0x0F, 0x2D, 0x64, 0x2D, 0xC2, + 0x41, 0x56, 0x60, 0xDE, 0x78, 0x87, 0x7D, 0x8D, 0x8A, 0xBC, 0x72, 0x52, 0x39, 0x78, 0xC0, + 0x42, 0xE4, 0x28, 0x5F, 0x43, 0x19, 0x84, 0x6C, 0x44, 0x12, 0x62, 0x42, 0x97, 0x68, 0x44, + 0xC1, 0x0E, 0x55, 0x6B, 0xA2, 0x15, 0xB5, 0xA7, 0x19, 0xE5, 0x9D, 0x0C, 0x6B, 0x2A, 0x96, + 0xD3, 0x98, 0x59, 0x07, 0x1F, 0xDC, 0xC2, 0xCD, 0xE7, 0x52, 0x4A, 0x7B, 0xED, 0xAE, 0x54, + 0xE8, 0x5B, 0x31, 0x8E, 0x85, 0x4E, 0x8F, 0xE2, 0xB2, 0xF3, 0xED, 0xFA, 0xC9, 0x71, 0x91, + 0x28, 0x27, 0x0A, 0xAF, 0xD1, 0xE5, 0x04, 0x4C, 0x3A, 0x4F, 0xDA, 0xFD, 0x9F, 0xF3, 0x1F, + 0x90, 0x78, 0x4B, 0x8E, 0x8E, 0x45, 0x96, 0x14, 0x4A, 0x0D, 0xAF, 0x58, 0x65, 0x11, 0xD3, + 0xD9, 0x96, 0x2B, 0x9E, 0xA9, 0x5A, 0xF1, 0x97, 0xB4, 0xE5, 0xFC, 0x60, 0xF2, 0xB1, 0xED, + 0x15, 0xDE, 0x3A, 0x5B, 0xEF, 0x5F, 0x89, 0xBD, 0xC7, 0x9D, 0x91, 0x05, 0x1D, 0x9B, 0x28, + 0x16, 0xE7, 0x4F, 0xA5, 0x45, 0x31, 0xEF, 0xDC, 0x1C, 0xBE, 0x74, 0xD4, 0x48, 0x85, 0x7F, + 0x47, 0x6B, 0xCD, 0x58, 0xF2, 0x1C, 0x0B, 0x65, 0x3B, 0x3B, 0x76, 0xA4, 0xE0, 0x76, 0xA6, + 0x55, 0x9A, 0x30, 0x27, 0x18, 0x55, 0x5C, 0xC6, 0x3F, 0x74, 0x85, 0x9A, 0xAB, 0xAB, 0x92, + 0x5F, 0x02, 0x38, 0x61, 0xCA, 0x8C, 0xD0, 0xF7, 0xBA, 0xDB, 0x28, 0x71, 0xF6, 0x7D, 0x55, + 0x32, 0x6D, 0x74, 0x51, 0x13, 0x5A, 0xD4, 0x5F, 0x4A, 0x1B, 0xA6, 0x91, 0x18, 0xFB, 0xB2, + 0xC8, 0xA3, 0x0E, 0xEC, 0x93, 0x92, 0xEF, 0x3F, 0x97, 0x70, 0x66, 0xC9, 0xAD, 0xD5, 0xC7, + 0x10, 0xCC, 0x64, 0x7B, 0x15, 0x14, 0xD2, 0x17, 0xD9, 0x58, 0xC7, 0x01, 0x7C, 0x3E, 0x90, + 0xFD, 0x20, 0xC0, 0x4E, 0x67, 0x4B, 0x90, 0x48, 0x6E, 0x93, 0x70, 0xA3, 0x1A, 0x00, 0x1D, + 0x32, 0xF4, 0x73, 0x97, 0x9E, 0x49, 0x06, 0x74, 0x9E, 0x7E, 0x47, 0x7F, 0xA0, 0xB7, 0x45, + 0x08, 0xF8, 0xA5, 0xF2, 0x37, 0x83, 0x12, 0xB8, 0x3C, 0x25, 0xBD, 0x38, 0x8C, 0xA0, 0xB0, + 0xFF, 0xF7, 0x47, 0x8B, 0xAF, 0x42, 0xB7, 0x16, 0x67, 0xED, 0xAA, 0xC9, 0x7C, 0x46, 0xB1, + 0x29, 0x64, 0x3E, 0x58, 0x6E, 0x5B, 0x05, 0x5A, 0x0C, 0x21, 0x19, 0x46, 0xD4, 0xF3, 0x6E, + 0x67, 0x5B, 0xED, 0x58, 0x60, 0xFA, 0x04, 0x2A, 0x31, 0x5D, 0x98, 0x26, 0x16, 0x4D, 0x6A, + 0x92, 0x37, 0xC3, 0x5A, 0x5F, 0xBF, 0x49, 0x54, 0x90, 0xA5, 0xBD, 0x4D, 0xF2, 0x48, 0xB9, + 0x5C, 0x4A, 0xAE, 0x77, 0x84, 0xB6, 0x05, 0x67, 0x31, 0x66, 0xAC, 0x42, 0x45, 0xB5, 0xB4, + 0xB0, 0x82, 0xA0, 0x9E, 0x93, 0x23, 0xE6, 0x2F, 0x20, 0x78, 0xC5, 0xB7, 0x67, 0x83, 0x44, + 0x6D, 0xEF, 0xD7, 0x36, 0xAD, 0x3A, 0x37, 0x02, 0xD4, 0x9B, 0x08, 0x98, 0x44, 0x90, 0x0A, + 0x61, 0x83, 0x33, 0x97, 0xBC, 0x44, 0x19, 0xB3, 0x0D, 0x7A, 0x97, 0xA0, 0xB3, 0x87, 0xC1, + 0x91, 0x14, 0x74, 0xC4, 0xD4, 0x1B, 0x53, 0xE3, 0x2A, 0x97, 0x7A, 0xCB, 0x6F, 0x0E, 0xA7, + 0x5D, 0xB6, 0x5B, 0xB3, 0x9E, 0x59, 0xE7, 0x01, 0xE7, 0x69, 0x57, 0xDE, 0xF6, 0xF2, 0xD4, + 0x45, 0x59, 0xC3, 0x1A, 0x77, 0x12, 0x2B, 0x52, 0x04, 0xE3, 0xB5, 0xC2, 0x19, 0xF1, 0x68, + 0x8B, 0x14, 0xED, 0x0B, 0xC0, 0xB8, 0x01, 0xB3, 0xE6, 0xE8, 0x2D, 0xCD, 0x43, 0xE9, 0xC0, + 0xE9, 0xF4, 0x17, 0x44, 0xCD, 0x98, 0x15, 0xBD, 0x1B, 0xC8, 0x82, 0x0D, 0x8B, 0xB1, 0x23, + 0xF0, 0x4F, 0xAC, 0xD1, 0xB1, 0xB6, 0x85, 0xDD, 0x5A, 0x2B, 0x1B, 0x8D, 0xBB, 0xF3, 0xED, + 0x93, 0x36, 0x70, 0xF0, 0x95, 0xA1, 0x80, 0xB4, 0xF1, 0x92, 0xD0, 0x8B, 0x10, 0xB8, 0xFA, + 0xBB, 0xDF, 0xCC, 0x2B, 0x24, 0x51, 0x8E, 0x32, 0xEE, 0xA0, 0xA5, 0xE0, 0xC9, 0x04, 0xCA, + 0x84, 0x47, 0x80, 0x08, 0x3F, 0x3B, 0x0C, 0xD2, 0xD0, 0xB8, 0xB6, 0xAF, 0x67, 0xBC, 0x35, + 0x5B, 0x94, 0x94, 0x02, 0x5D, 0xC7, 0xB0, 0xA7, 0x8F, 0xA8, 0x0E, 0x3A, 0x2D, 0xBF, 0xEB, + 0x51, 0x32, 0x88, 0x51, 0xD6, 0x07, 0x81, 0x98, 0xE9, 0x49, 0x36, 0x51, 0xAE, 0x78, 0x7E, + 0xC0, 0x25, 0x1F, 0x92, 0x2B, 0xA3, 0x0E, 0x9F, 0x51, 0xDF, 0x62, 0xA6, 0xD7, 0x27, 0x84, + 0xCF, 0x3D, 0xD2, 0x05, 0x39, 0x31, 0x76, 0xDF, 0xA3, 0x24, 0xA5, 0x12, 0xBD, 0x94, 0x97, + 0x0A, 0x36, 0xDD, 0x34, 0xA5, 0x14, 0xA8, 0x67, 0x91, 0xF0, 0xEB, 0x36, 0xF0, 0x14, 0x5B, + 0x09, 0xAB, 0x64, 0x65, 0x1B, 0x4A, 0x03, 0x13, 0xB2, 0x99, 0x61, 0x1A, 0x2A, 0x1C, 0x48, + 0x89, 0x16, 0x27, 0x59, 0x87, 0x68, 0xA3, 0x11, 0x40, 0x60, 0xBA, 0x44, 0x43, 0x48, 0x6D, + 0xF5, 0x15, 0x22, 0xA1, 0xCE, 0x88, 0xB3, 0x09, 0x85, 0xC2, 0x16, 0xF8, 0xE6, 0xED, 0x17, + 0x8D, 0xD5, 0x67, 0xB3, 0x04, 0xA0, 0xD4, 0xCA, 0xFB, 0xA8, 0x82, 0xA2, 0x83, 0x42, 0xF1, + 0x7A, 0x9A, 0xA2, 0x6A, 0xE5, 0x8D, 0xB6, 0x30, 0x08, 0x3D, 0x2C, 0x35, 0x8F, 0xDF, 0x56, + 0x6C, 0x3F, 0x5D, 0x62, 0xA4, 0x28, 0x56, 0x7B, 0xC9, 0xEA, 0x8C, 0xE9, 0x5C, 0xAA, 0x0F, + 0x35, 0x47, 0x4B, 0x0B, 0xFA, 0x8F, 0x33, 0x9A, 0x25, 0x0A, 0xB4, 0xDF, 0xCF, 0x20, 0x83, + 0xBE, 0x8E, 0xEF, 0xBC, 0x10, 0x55, 0xE1, 0x8F, 0xE1, 0x53, 0x70, 0xEE, 0xCB, 0x26, 0x05, + 0x66, 0xD8, 0x3F, 0xF0, 0x6B, 0x21, 0x1A, 0xAE, 0xC4, 0x3C, 0xA2, 0x9B, 0x54, 0xCC, 0xD0, + 0x0F, 0x88, 0x15, 0xA2, 0x46, 0x5E, 0xF0, 0xB4, 0x65, 0x15, 0xCC, 0x7E, 0x41, 0xF3, 0x12, + 0x4F, 0x09, 0xEF, 0xFF, 0x73, 0x93, 0x09, 0xAB, 0x58, 0xB2, 0x9A, 0x14, 0x59, 0xA0, 0x0B, + 0xCE, 0x50, 0x38, 0xE9, 0x38, 0xC9, 0x67, 0x8F, 0x72, 0xEB, 0x0E, 0x4E, 0xE5, 0xFD, 0xAA, + 0xE6, 0x6D, 0x9F, 0x85, 0x73, 0xFC, 0x97, 0xFC, 0x42, 0xB4, 0x95, 0x9F, 0x4B, 0xF8, 0xB6, + 0x1D, 0x78, 0x43, 0x3E, 0x86, 0xB0, 0x33, 0x5D, 0x6E, 0x91, 0x91, 0xC4, 0xD8, 0xBF, 0x48, + 0x7B, 0x39, 0x05, 0xC1, 0x08, 0xCF, 0xD6, 0xAC, 0x24, 0xB0, 0xCE, 0xB7, 0xDC, 0xB7, 0xCF, + 0x51, 0xF8, 0x4D, 0x0E, 0xD6, 0x87, 0xB9, 0x5E, 0xAE, 0xB1, 0xC5, 0x33, 0xC0, 0x6F, 0x0D, + 0x97, 0x02, 0x3D, 0x92, 0xA7, 0x08, 0x25, 0x83, 0x7B, 0x59, 0xBA, 0x6C, 0xB7, 0xD4, 0xE5, + 0x6B, 0x0A, 0x87, 0xC2, 0x03, 0x86, 0x2A, 0xE8, 0xF3, 0x15, 0xBA, 0x59, 0x25, 0xE8, 0xED, + 0xEF, 0xA6, 0x79, 0x36, 0x9A, 0x22, 0x02, 0x76, 0x61, 0x51, 0xF1, 0x6A, 0x96, 0x5F, 0x9F, + 0x81, 0xEC, 0xE7, 0x6C, 0xC0, 0x70, 0xB5, 0x58, 0x69, 0xE4, 0xDB, 0x97, 0x84, 0xCF, 0x05, + 0xC8, 0x30, 0xB3, 0x24, 0x2C, 0x83, 0x12, + ]) + .unwrap(); + let sig: [u8; MLDSA44_SIG_LEN] = [ + 0x5E, 0x93, 0xB7, 0x85, 0xC5, 0x11, 0x9C, 0x39, 0x83, 0xA2, 0x91, 0xB1, 0x84, 0x20, 0xFD, + 0xBE, 0x4B, 0xCA, 0x53, 0xD5, 0xA3, 0x73, 0x29, 0x22, 0xFA, 0xAA, 0xCD, 0x5A, 0x5D, 0x32, + 0xA7, 0x45, 0xC7, 0x8D, 0x10, 0x5B, 0xA1, 0x0B, 0xEE, 0x1E, 0xD8, 0x06, 0x9F, 0x19, 0xE6, + 0xC5, 0x37, 0xBD, 0xA1, 0x6E, 0x89, 0xD3, 0x90, 0x04, 0xC3, 0x59, 0xD1, 0xFD, 0x38, 0x1A, + 0x02, 0x91, 0xF1, 0xC5, 0x1F, 0x1C, 0x38, 0xED, 0xCD, 0xB3, 0x15, 0xC8, 0xC6, 0x95, 0x70, + 0xD8, 0xF2, 0x5F, 0x16, 0x55, 0xBA, 0x8E, 0xA8, 0x3A, 0xFF, 0x24, 0xB8, 0xB6, 0xBE, 0x8D, + 0xE7, 0x62, 0x34, 0x2E, 0x34, 0x7E, 0xAB, 0x2C, 0xAA, 0x68, 0x03, 0xED, 0x70, 0x59, 0x52, + 0xDD, 0x64, 0x50, 0xC5, 0x18, 0x5E, 0x9D, 0x60, 0xCE, 0x96, 0xE8, 0xDC, 0xA4, 0x23, 0xA0, + 0x2F, 0x64, 0x6C, 0xEA, 0x69, 0x01, 0x64, 0xA2, 0x26, 0xE4, 0xC3, 0xD6, 0xA5, 0x15, 0xCE, + 0x16, 0x29, 0x0F, 0x19, 0xB2, 0xC6, 0x26, 0xDA, 0x9B, 0x45, 0x0E, 0xCF, 0x66, 0x50, 0x13, + 0xC5, 0xE2, 0x26, 0xB6, 0xC0, 0xAC, 0x5C, 0x07, 0xCE, 0x90, 0xE2, 0x78, 0xF1, 0xB0, 0x13, + 0x4E, 0x38, 0x5D, 0x13, 0xE7, 0x42, 0x08, 0xA0, 0xB3, 0xFF, 0x05, 0x2A, 0x36, 0x25, 0x79, + 0xF9, 0x20, 0x7E, 0xA0, 0x1F, 0x18, 0xA0, 0x39, 0xAA, 0x1B, 0x97, 0xAE, 0x34, 0x52, 0x67, + 0x5B, 0x62, 0x07, 0x71, 0xF8, 0x01, 0x2E, 0xE7, 0xA4, 0xE5, 0x5C, 0x98, 0xBF, 0xD2, 0x01, + 0x9E, 0xD8, 0xA3, 0xB0, 0x0A, 0xCE, 0xA8, 0xE8, 0xAB, 0x28, 0x17, 0x2F, 0xAA, 0x42, 0xCA, + 0x1F, 0xDA, 0x83, 0xC5, 0xFF, 0xE8, 0x1A, 0x45, 0xBE, 0x73, 0x6B, 0xDE, 0xDD, 0x5F, 0xB3, + 0x00, 0xCE, 0x17, 0x07, 0x8B, 0x38, 0x0F, 0x62, 0x0B, 0xDE, 0xEB, 0xAD, 0x69, 0x36, 0x01, + 0x37, 0x2C, 0x85, 0xEA, 0xCF, 0x79, 0xBC, 0x98, 0xE1, 0xB4, 0x8F, 0x2A, 0xD7, 0xE5, 0xDC, + 0xE4, 0x27, 0x9A, 0x12, 0x95, 0xBB, 0x2B, 0xA6, 0x0A, 0x0C, 0x5E, 0x37, 0x26, 0x64, 0x2D, + 0x23, 0x36, 0xC5, 0xEB, 0x1D, 0x37, 0xC8, 0x62, 0x3C, 0x75, 0x58, 0x24, 0x13, 0x18, 0xD8, + 0x9B, 0xC7, 0x83, 0xC4, 0xF0, 0x00, 0x98, 0x07, 0x74, 0x84, 0x62, 0x3C, 0x21, 0x75, 0x60, + 0xA0, 0xC7, 0xAA, 0xF7, 0x5D, 0xCA, 0xCC, 0xB7, 0x8E, 0xE6, 0x9C, 0x20, 0x7C, 0x27, 0xC8, + 0xBF, 0x39, 0x65, 0xCC, 0xF5, 0x8A, 0x80, 0xC8, 0x8E, 0xFC, 0xC7, 0xE5, 0xDE, 0xB3, 0x61, + 0x5D, 0x50, 0x45, 0xA7, 0x41, 0xC4, 0xDA, 0xC0, 0xA0, 0x21, 0xDD, 0x06, 0x0D, 0x31, 0x5D, + 0x4E, 0xC2, 0x85, 0x7E, 0xB6, 0x64, 0xD7, 0x28, 0xD0, 0xAF, 0x97, 0x3B, 0xEA, 0x07, 0xE1, + 0xCA, 0x56, 0x3F, 0xAA, 0x0E, 0x19, 0x99, 0x6C, 0xEA, 0x37, 0x70, 0x31, 0x6C, 0x11, 0xA5, + 0x06, 0x66, 0x65, 0x66, 0x20, 0x05, 0xAC, 0xE9, 0x8F, 0x61, 0x10, 0xE8, 0x83, 0xBA, 0xE0, + 0x60, 0xDA, 0xA7, 0xB6, 0xD8, 0x33, 0x79, 0xE0, 0x87, 0x87, 0x96, 0x69, 0x17, 0x08, 0xA3, + 0x2B, 0x85, 0x73, 0x0D, 0xE8, 0xB9, 0x2D, 0x89, 0xF9, 0x0A, 0x36, 0x60, 0xC9, 0x49, 0x16, + 0x5B, 0x14, 0x61, 0x25, 0x67, 0x66, 0x2E, 0x16, 0x22, 0x32, 0x29, 0x6C, 0xBD, 0x14, 0x35, + 0x17, 0xA2, 0x82, 0xE2, 0x2C, 0x46, 0xB6, 0x36, 0x06, 0xD3, 0xC1, 0x4E, 0xD4, 0x55, 0x9A, + 0x5A, 0x1C, 0x45, 0x9B, 0xAB, 0x7F, 0x35, 0x50, 0x07, 0xAD, 0x6F, 0x7E, 0x3B, 0x1E, 0x07, + 0x44, 0x5D, 0xFC, 0x96, 0xBD, 0x9B, 0x75, 0x08, 0x0B, 0x3D, 0x4F, 0x68, 0x99, 0x84, 0x90, + 0xA2, 0x6B, 0x5E, 0x09, 0x0B, 0xE2, 0x67, 0x40, 0x71, 0xAB, 0x92, 0x5B, 0xB6, 0x50, 0x59, + 0x08, 0x56, 0xC5, 0x9F, 0x8B, 0xA7, 0x48, 0x8D, 0x2B, 0x72, 0xF8, 0x40, 0xAC, 0x3E, 0xAF, + 0xE4, 0xDD, 0x91, 0xF0, 0xF5, 0x1C, 0x43, 0x64, 0x11, 0x2C, 0x1A, 0x13, 0x9E, 0x3E, 0x94, + 0x2A, 0x59, 0x7B, 0x93, 0xA1, 0xE3, 0xF4, 0xFA, 0xDE, 0xD1, 0x29, 0xC1, 0x4B, 0x59, 0x78, + 0xB3, 0x15, 0xE2, 0x24, 0x6A, 0x93, 0x14, 0x6A, 0x79, 0x36, 0x5F, 0x0F, 0x59, 0x7A, 0x18, + 0x34, 0x0C, 0xCA, 0x86, 0xBB, 0x15, 0xCE, 0xED, 0x39, 0xF1, 0x75, 0xEA, 0xB1, 0xE5, 0x46, + 0x53, 0x5A, 0xFB, 0x96, 0x6F, 0x0A, 0x65, 0xA8, 0xF6, 0x6F, 0x73, 0x7A, 0xB0, 0x28, 0x97, + 0xED, 0xDF, 0xE9, 0x2C, 0xF7, 0x78, 0x68, 0x94, 0x84, 0x3C, 0x26, 0x91, 0x46, 0x47, 0x76, + 0xC9, 0x4B, 0xD4, 0x50, 0xA1, 0x06, 0x91, 0x38, 0xB2, 0x6D, 0xF8, 0x3B, 0x2D, 0x1D, 0xD8, + 0x01, 0x14, 0x3A, 0x8F, 0xDF, 0xDC, 0x25, 0x14, 0xCC, 0x5B, 0x58, 0x31, 0xAB, 0x53, 0xA7, + 0x5C, 0x55, 0xEF, 0x29, 0xF4, 0x0E, 0x7C, 0x63, 0xD2, 0xC7, 0x2A, 0xBE, 0x97, 0xE2, 0xAF, + 0x14, 0x85, 0x3B, 0xE4, 0x9B, 0xE1, 0x6F, 0x47, 0x30, 0xA1, 0x59, 0x97, 0x49, 0x70, 0x95, + 0x14, 0x39, 0xE5, 0x5C, 0x15, 0x89, 0xD0, 0xF4, 0xA1, 0x62, 0xE3, 0x51, 0x7D, 0xF9, 0xD7, + 0xAB, 0xC9, 0x8D, 0x8A, 0x30, 0x72, 0x16, 0xE7, 0xF1, 0xCB, 0x46, 0x27, 0xC9, 0x17, 0x5C, + 0x0E, 0xEF, 0x23, 0x33, 0x7E, 0x56, 0xD5, 0x28, 0x1B, 0x83, 0x72, 0x6F, 0xFF, 0x40, 0xA1, + 0x48, 0xB0, 0xC4, 0x8E, 0x8D, 0xF3, 0x49, 0x6A, 0x21, 0x18, 0xD8, 0x02, 0x19, 0xAE, 0xF8, + 0xF4, 0x0B, 0x29, 0xFB, 0xA1, 0xF2, 0xF7, 0x87, 0x86, 0xB6, 0x7F, 0xFB, 0x7B, 0x7D, 0x47, + 0xD4, 0x06, 0xB7, 0x65, 0xBD, 0x13, 0x66, 0x10, 0xBE, 0xDE, 0xB9, 0x5C, 0xD7, 0x32, 0x1F, + 0x58, 0xF3, 0xB8, 0x36, 0xC9, 0x25, 0x8B, 0xE3, 0x5D, 0x78, 0xB4, 0x98, 0xF3, 0xEF, 0xE1, + 0xDB, 0x2B, 0x24, 0x3D, 0x73, 0x4F, 0xAB, 0x15, 0x9B, 0xAE, 0xD8, 0x80, 0x7C, 0x3C, 0xCC, + 0xF8, 0x3E, 0xB2, 0xEA, 0xF8, 0xA9, 0xAF, 0x01, 0xA5, 0x18, 0xD4, 0x8C, 0x60, 0xE9, 0x1A, + 0x96, 0x81, 0x2A, 0xD6, 0x89, 0xC2, 0xD8, 0x3C, 0xC4, 0xE8, 0xE9, 0xB3, 0x65, 0x04, 0x22, + 0xBE, 0xD6, 0xF1, 0x3C, 0x24, 0xAD, 0xAA, 0xD9, 0x1C, 0x95, 0xB3, 0xE3, 0xCF, 0x35, 0x4F, + 0x0F, 0x6B, 0xC9, 0xEE, 0x89, 0x41, 0xA6, 0xB1, 0x5B, 0x69, 0x75, 0x13, 0x1D, 0x95, 0x23, + 0x3D, 0x89, 0x35, 0xDE, 0x36, 0x7E, 0xFC, 0x6D, 0x86, 0xA4, 0x5D, 0xAC, 0x7D, 0x0F, 0x1D, + 0xDD, 0x9A, 0xEB, 0xD2, 0xC5, 0x9C, 0x02, 0x7F, 0xCD, 0xA4, 0x48, 0x80, 0x1E, 0x93, 0xE7, + 0x33, 0xAC, 0xA5, 0x18, 0x74, 0xBE, 0x9A, 0xB9, 0x27, 0xA9, 0x04, 0xF9, 0x6D, 0xDB, 0x7A, + 0x46, 0xB2, 0xDA, 0x13, 0x26, 0x1D, 0x52, 0x2B, 0x23, 0xC9, 0x50, 0xC0, 0x1D, 0x5F, 0x5E, + 0x11, 0x2B, 0x76, 0xF8, 0x51, 0xFF, 0x23, 0x4F, 0x06, 0xF8, 0xD5, 0xE6, 0x5B, 0x13, 0x19, + 0xAB, 0xCD, 0x79, 0xA1, 0x80, 0xAE, 0x06, 0x3D, 0x65, 0xB2, 0x8C, 0x74, 0x58, 0x78, 0xC0, + 0x6D, 0xBB, 0x69, 0xBA, 0x73, 0x29, 0x3E, 0xAB, 0x34, 0x43, 0x4B, 0xF1, 0xA9, 0x2F, 0xBA, + 0x69, 0x19, 0x93, 0xBD, 0x0F, 0xF3, 0xED, 0xAC, 0x76, 0xA1, 0x2F, 0x80, 0xC0, 0xAD, 0xA4, + 0xB1, 0x96, 0x9C, 0x76, 0x65, 0x58, 0x9D, 0x53, 0x0A, 0x67, 0x01, 0x6A, 0x62, 0x54, 0x03, + 0xC5, 0x37, 0x03, 0x29, 0x04, 0xF2, 0xE1, 0x04, 0x54, 0x7C, 0xD3, 0xEA, 0x40, 0x62, 0x60, + 0xDD, 0x35, 0x7F, 0xA0, 0x6E, 0xA0, 0x12, 0xA7, 0x85, 0x82, 0x6C, 0x16, 0x0E, 0x99, 0xFF, + 0xD0, 0x65, 0xB0, 0xE3, 0xF3, 0x3C, 0x76, 0x89, 0xD3, 0x55, 0x2A, 0xB9, 0xE2, 0xE0, 0x9F, + 0xA7, 0xE5, 0x5B, 0xBC, 0xEF, 0x04, 0x22, 0x42, 0xBC, 0xAC, 0xAD, 0x8A, 0x3D, 0xA4, 0x7B, + 0xCC, 0x54, 0xA1, 0x21, 0xF1, 0x52, 0x6C, 0x8C, 0xD4, 0xCC, 0x5A, 0x89, 0x2A, 0x81, 0x31, + 0xCF, 0x4E, 0xEF, 0xAF, 0x42, 0x48, 0xDD, 0xD6, 0xA1, 0x1E, 0xC4, 0x27, 0xBA, 0x37, 0x8A, + 0xAE, 0x89, 0xAA, 0xF5, 0x82, 0xCE, 0x1F, 0x4E, 0x32, 0x69, 0x0A, 0x55, 0x5E, 0x74, 0x07, + 0x61, 0xD3, 0x58, 0xAD, 0x4E, 0x92, 0xBC, 0x38, 0x41, 0x8A, 0xA7, 0x82, 0xDA, 0x91, 0x65, + 0x24, 0xFB, 0x09, 0xAB, 0x2C, 0xA6, 0xB3, 0xD3, 0x11, 0x3D, 0x6F, 0x2C, 0x2A, 0x6A, 0x9B, + 0x9D, 0x29, 0xD4, 0xE7, 0x48, 0x92, 0x55, 0x25, 0x2A, 0xF0, 0x75, 0xCB, 0xF9, 0xFE, 0xAC, + 0xED, 0xAE, 0x6F, 0x3E, 0xC0, 0xB0, 0x70, 0x82, 0x46, 0x89, 0xDD, 0x3C, 0x78, 0xAC, 0x14, + 0x3E, 0xD6, 0x77, 0x6D, 0x95, 0xDD, 0x8F, 0x13, 0xD4, 0x35, 0xA2, 0x90, 0xBD, 0xCA, 0x4C, + 0x11, 0x31, 0x8E, 0x5A, 0xCC, 0xE0, 0x44, 0x69, 0x64, 0x4E, 0x13, 0x74, 0xA9, 0x45, 0x1B, + 0x62, 0x04, 0xF3, 0xB3, 0x96, 0x1B, 0x7D, 0xD2, 0x39, 0xE3, 0x06, 0xFE, 0xF5, 0xF4, 0xF4, + 0xE5, 0x1B, 0x78, 0xB0, 0xFB, 0x9D, 0xCE, 0xE6, 0x9C, 0x3E, 0x79, 0x0B, 0x23, 0x1F, 0x2E, + 0x65, 0xFD, 0x1A, 0xB1, 0xC2, 0xA7, 0x5B, 0x07, 0x06, 0x7D, 0x5C, 0x16, 0xDD, 0xE0, 0x09, + 0x83, 0xA5, 0x8F, 0xFC, 0xDA, 0xAA, 0xEE, 0x16, 0xD2, 0x74, 0x2E, 0x13, 0x3E, 0xD7, 0x37, + 0xB4, 0x80, 0x64, 0xC8, 0xA3, 0x8E, 0xCA, 0x35, 0xAB, 0x3F, 0xA1, 0x8F, 0x6D, 0x62, 0xF6, + 0x42, 0xB1, 0x2C, 0xFD, 0xC7, 0x98, 0x0F, 0x2A, 0xB7, 0xDB, 0x32, 0x1F, 0xEC, 0x9D, 0xCF, + 0xE4, 0x99, 0xB4, 0xFC, 0x1E, 0xE7, 0xEB, 0x29, 0x79, 0x54, 0x05, 0x66, 0x17, 0xC6, 0x0A, + 0x66, 0x40, 0xB9, 0x28, 0x35, 0xD1, 0x65, 0xC3, 0xC0, 0x0A, 0x95, 0x19, 0x52, 0x61, 0x44, + 0x88, 0xD5, 0x65, 0x7B, 0xA0, 0xB5, 0xE9, 0x0A, 0xE9, 0xE0, 0xEF, 0x7B, 0x3B, 0x9E, 0xCA, + 0xEB, 0xD8, 0x1B, 0x85, 0x51, 0xB6, 0xD7, 0x0E, 0x83, 0x5B, 0x27, 0x34, 0x76, 0x16, 0x39, + 0xD4, 0x2E, 0x76, 0xFF, 0xC5, 0xB3, 0x27, 0x2B, 0x61, 0xC8, 0x96, 0xB4, 0x5B, 0x4B, 0xD1, + 0x8F, 0x30, 0xE5, 0x8C, 0x44, 0x06, 0x43, 0xBA, 0x15, 0x92, 0x21, 0xCC, 0x67, 0x39, 0xA1, + 0x9A, 0x65, 0xF2, 0x91, 0x1F, 0xAE, 0x47, 0xB0, 0xD4, 0xCA, 0xC4, 0x20, 0x0A, 0x6F, 0x04, + 0x3B, 0x17, 0xA0, 0x3A, 0xD3, 0x93, 0xEC, 0xB8, 0x23, 0xED, 0x03, 0xC8, 0xB6, 0xCD, 0x68, + 0x16, 0x7E, 0x6C, 0x82, 0x34, 0xF7, 0x43, 0x25, 0x57, 0xDB, 0x27, 0x20, 0x79, 0xEE, 0x89, + 0x9A, 0xED, 0xE7, 0x3B, 0x6B, 0x98, 0xD6, 0x00, 0x3F, 0x45, 0x78, 0x9A, 0x14, 0x1B, 0x60, + 0xD6, 0xDB, 0x40, 0xCD, 0x2A, 0x59, 0x74, 0x57, 0x1A, 0x4A, 0xD3, 0x66, 0x7B, 0x88, 0x93, + 0x18, 0xBA, 0x60, 0x28, 0x5D, 0x90, 0x3A, 0x2E, 0xAC, 0x01, 0xC2, 0x16, 0x08, 0x83, 0x8C, + 0x40, 0x90, 0x7D, 0xE6, 0xBB, 0xAB, 0xE0, 0x42, 0xCF, 0x2E, 0xCD, 0xD9, 0x7F, 0x54, 0x9F, + 0x95, 0xEC, 0x69, 0x8D, 0x79, 0x22, 0x2C, 0x65, 0xBA, 0x27, 0xC3, 0x0D, 0x33, 0x2A, 0x68, + 0xD0, 0x57, 0xAE, 0xCD, 0xC9, 0x38, 0x8A, 0xA3, 0x43, 0x20, 0xE0, 0xAA, 0x74, 0xFD, 0xBD, + 0x4D, 0x1B, 0x64, 0x3C, 0xAC, 0xE2, 0x16, 0xB6, 0xD8, 0xAD, 0x8F, 0x07, 0xA9, 0x99, 0x55, + 0xBF, 0xDB, 0x74, 0x3A, 0x86, 0xB4, 0x0F, 0xC6, 0x15, 0x27, 0xBA, 0xCA, 0x43, 0x4A, 0xC2, + 0xA7, 0xFB, 0xEA, 0xA7, 0x71, 0x11, 0xDC, 0x80, 0x98, 0xB1, 0x7E, 0x80, 0x0F, 0x59, 0xDD, + 0x77, 0xCC, 0xB0, 0xE6, 0x77, 0x07, 0xE6, 0x01, 0x23, 0xD3, 0x34, 0xE0, 0x73, 0xA2, 0xF5, + 0xA1, 0x6F, 0xFB, 0xCD, 0x70, 0x13, 0x89, 0xAD, 0xD5, 0x7C, 0x3C, 0xEC, 0xCB, 0x88, 0xB2, + 0x86, 0xAC, 0x1E, 0x6E, 0x3E, 0x64, 0x85, 0xAF, 0x1A, 0x12, 0xEA, 0x24, 0x1D, 0x14, 0xA1, + 0xB5, 0x00, 0x3D, 0x7F, 0x3B, 0xC9, 0xE9, 0x57, 0xD4, 0x48, 0x3C, 0x0F, 0x9F, 0x70, 0x3B, + 0x3A, 0x18, 0x7D, 0x55, 0xE5, 0x05, 0x81, 0x76, 0x15, 0xFB, 0xC4, 0xAE, 0x08, 0x37, 0x61, + 0x61, 0x84, 0x24, 0x5C, 0xFB, 0xA6, 0x1C, 0xE3, 0xB9, 0x29, 0xE3, 0x3F, 0x52, 0xB7, 0x1C, + 0xDD, 0x7B, 0x6A, 0x0D, 0xA5, 0x5C, 0x1F, 0x99, 0x75, 0x10, 0xB1, 0xA9, 0x00, 0x2C, 0xA4, + 0xE0, 0x67, 0x83, 0x73, 0xA3, 0xB1, 0xAB, 0x28, 0x97, 0xE6, 0xB4, 0x23, 0xF1, 0x5A, 0x44, + 0x0A, 0x63, 0x6C, 0xC8, 0x61, 0x49, 0x1E, 0xF4, 0x1A, 0xD0, 0xAA, 0x62, 0x7D, 0x8E, 0x19, + 0x8A, 0x5E, 0xE7, 0xBD, 0x7B, 0x6C, 0xB2, 0xC9, 0xCE, 0x2A, 0x8C, 0xC0, 0x15, 0xF0, 0xD2, + 0x06, 0xDE, 0x4C, 0x49, 0xE2, 0xF8, 0x7F, 0x31, 0x09, 0x54, 0xA1, 0x0D, 0x86, 0xE2, 0x94, + 0xF7, 0x42, 0xEE, 0x18, 0x6F, 0x4A, 0xE9, 0x81, 0x5F, 0x69, 0x96, 0x22, 0x79, 0x22, 0x06, + 0xCA, 0xFB, 0xA8, 0xF5, 0x62, 0x17, 0x38, 0x16, 0x0E, 0x6C, 0x5D, 0x61, 0x1A, 0x82, 0x52, + 0xC6, 0xF3, 0x50, 0x85, 0xB6, 0x04, 0xEF, 0x89, 0x51, 0x64, 0xD4, 0xEA, 0x6D, 0xDD, 0x31, + 0x0C, 0x7D, 0x8F, 0x0C, 0x87, 0x9F, 0xB1, 0xF8, 0x84, 0xC5, 0x74, 0x1D, 0x09, 0x6B, 0x3D, + 0x2D, 0xA0, 0xCE, 0x11, 0x51, 0x79, 0x0D, 0xDA, 0x88, 0x1D, 0x18, 0xCB, 0x6B, 0x19, 0xA9, + 0xFE, 0xD6, 0xF5, 0x25, 0x4B, 0x7D, 0x52, 0xD5, 0xD9, 0x2B, 0xBB, 0xE2, 0x4C, 0x9D, 0x6A, + 0x65, 0x60, 0x4A, 0x0B, 0x8E, 0xD2, 0x4A, 0xD5, 0xC1, 0x97, 0xD6, 0x83, 0xF5, 0x98, 0x74, + 0x3C, 0x96, 0xB5, 0x96, 0x0E, 0x87, 0x23, 0x73, 0x2B, 0x5B, 0xD6, 0x47, 0xE9, 0xDB, 0xEA, + 0xA8, 0x51, 0xD0, 0xE1, 0xCF, 0x6D, 0x2C, 0x07, 0x0D, 0x44, 0x42, 0x76, 0x2C, 0x28, 0x09, + 0x8C, 0x5C, 0xF5, 0xA5, 0x4B, 0x2B, 0x5E, 0x69, 0xA9, 0x9B, 0x10, 0x81, 0x5B, 0xF0, 0xF4, + 0x77, 0xBB, 0x71, 0xF0, 0xD5, 0xD3, 0xA6, 0x2B, 0xA2, 0xB3, 0xE2, 0x9B, 0xF8, 0x4D, 0x4B, + 0x4E, 0x57, 0x47, 0x07, 0xF5, 0xF7, 0x4A, 0xF7, 0x04, 0xD2, 0x77, 0xBD, 0x6C, 0xA3, 0x8D, + 0xA2, 0x1E, 0x2C, 0xDA, 0xC5, 0x49, 0xE5, 0xEA, 0xE1, 0xDE, 0x7A, 0x18, 0xEE, 0x53, 0x4C, + 0x8C, 0x22, 0x91, 0xC9, 0x08, 0xCA, 0xAB, 0xF1, 0x59, 0xE9, 0x0E, 0x65, 0x49, 0xDB, 0x94, + 0xBA, 0x7A, 0x3F, 0x3D, 0x97, 0xDD, 0x39, 0x8A, 0x75, 0xDF, 0x5B, 0x1A, 0x7C, 0xDF, 0xB2, + 0x54, 0x10, 0xB7, 0xEF, 0xC4, 0xED, 0x00, 0xD9, 0x99, 0x5B, 0x37, 0xB5, 0x8B, 0xF9, 0x1E, + 0xD7, 0xA3, 0x51, 0x0C, 0xFF, 0xEA, 0x82, 0xF9, 0xE1, 0xC2, 0xA3, 0x29, 0x04, 0x06, 0x00, + 0x4D, 0x09, 0x05, 0x7D, 0x63, 0xB7, 0x70, 0xFA, 0x0E, 0x53, 0x10, 0x31, 0x99, 0x54, 0x4E, + 0xBA, 0x66, 0x2A, 0x2C, 0x30, 0x2C, 0xF3, 0x90, 0x08, 0xF1, 0x42, 0xD2, 0xB1, 0x69, 0x63, + 0xE9, 0x5A, 0xB1, 0x0B, 0xE7, 0xC2, 0x61, 0x01, 0x68, 0x60, 0x8F, 0x35, 0x3A, 0x2F, 0x2C, + 0x41, 0xC7, 0x05, 0x6D, 0xEC, 0x1A, 0x8C, 0x7A, 0x6B, 0xFA, 0x00, 0x27, 0xF9, 0xDE, 0xDA, + 0xCB, 0x77, 0x86, 0xB6, 0x7E, 0xA2, 0xC4, 0x94, 0xD4, 0x3B, 0xA8, 0x51, 0xCF, 0x94, 0x15, + 0xC1, 0xBC, 0xC5, 0x2F, 0x02, 0x7E, 0xC0, 0x2C, 0x65, 0x53, 0x4F, 0x60, 0x8E, 0x9D, 0x16, + 0x6D, 0x51, 0xDD, 0x43, 0x1C, 0xDF, 0x58, 0x71, 0xF5, 0xCD, 0xD1, 0x57, 0x9C, 0xC0, 0x60, + 0x79, 0xDF, 0x07, 0x5A, 0x25, 0x06, 0x2B, 0xA7, 0xE7, 0x0D, 0x96, 0x66, 0xC4, 0xE7, 0xFE, + 0xD3, 0x4C, 0xEA, 0x0E, 0xA0, 0xF1, 0x1A, 0xDE, 0x1E, 0xB2, 0xA9, 0xB3, 0x97, 0xBC, 0xAA, + 0xAD, 0x10, 0x61, 0x27, 0x0E, 0xCF, 0x49, 0x78, 0x03, 0xA5, 0xFC, 0xE7, 0xF4, 0x1E, 0x65, + 0x04, 0xFB, 0xEC, 0x71, 0xA7, 0xDE, 0x7D, 0x06, 0x6B, 0x82, 0x61, 0x86, 0x8A, 0xFC, 0x49, + 0xB9, 0xE6, 0x85, 0xF0, 0xDC, 0xCE, 0x75, 0xE2, 0xFC, 0xB3, 0xBA, 0x8C, 0xF1, 0x90, 0x57, + 0xE3, 0x94, 0x15, 0x76, 0xBA, 0xF5, 0x8F, 0xB8, 0x21, 0xBD, 0x42, 0x68, 0xF7, 0xFA, 0xE3, + 0x02, 0x86, 0x01, 0xDA, 0x02, 0x2E, 0x9B, 0x46, 0x86, 0x46, 0xAB, 0xDB, 0x4F, 0xA6, 0x09, + 0x8A, 0x44, 0x9B, 0x42, 0x67, 0xD5, 0x09, 0xD9, 0xA3, 0x3F, 0x4C, 0x3E, 0xBC, 0xC3, 0x2D, + 0xAC, 0x09, 0x4D, 0x48, 0xED, 0x60, 0x0E, 0x76, 0x57, 0x87, 0xFB, 0x92, 0xB1, 0x97, 0x4F, + 0x74, 0xF7, 0xBB, 0x4C, 0x66, 0xEB, 0x2B, 0xBD, 0x02, 0x89, 0x5E, 0x6A, 0x38, 0x1C, 0x1C, + 0x45, 0x2E, 0xAA, 0xB1, 0xAE, 0x47, 0x31, 0xCF, 0x63, 0x2F, 0x61, 0xAE, 0x2C, 0x90, 0x59, + 0x21, 0x17, 0x4A, 0x3B, 0xC9, 0xBB, 0x4C, 0xDC, 0x89, 0xD6, 0x30, 0x26, 0x4B, 0x61, 0x49, + 0x88, 0xF3, 0xAB, 0xBE, 0xA1, 0xBD, 0x61, 0x7F, 0xFA, 0x53, 0xD7, 0x1B, 0x7D, 0x8A, 0x37, + 0x14, 0x62, 0xB7, 0x73, 0x35, 0x1A, 0x2D, 0xCC, 0xAE, 0xDD, 0x7F, 0x59, 0xCD, 0x72, 0x8F, + 0xAD, 0xEE, 0x05, 0x90, 0x67, 0xBD, 0x80, 0xC9, 0x4C, 0x8C, 0x9A, 0x1F, 0xFC, 0xA2, 0xDC, + 0x4F, 0x84, 0x8B, 0x82, 0x9C, 0x05, 0x61, 0x38, 0x5A, 0xA8, 0x2C, 0xC9, 0x85, 0x03, 0xD0, + 0xBB, 0x66, 0xA6, 0xAA, 0x4F, 0xAE, 0x07, 0x03, 0xD1, 0x2E, 0x60, 0xE1, 0x46, 0x0E, 0xFB, + 0xBC, 0xDF, 0x24, 0x12, 0xC1, 0x3E, 0x7C, 0x68, 0x4D, 0x1B, 0x01, 0x10, 0x20, 0x26, 0x34, + 0x3A, 0x41, 0x43, 0x44, 0x58, 0x5F, 0x6E, 0x70, 0x72, 0x74, 0x8B, 0xAE, 0xB5, 0xBB, 0xC6, + 0xD1, 0xE2, 0xEF, 0xFB, 0xFE, 0x06, 0x0E, 0x2E, 0x3E, 0x51, 0x60, 0x79, 0x7C, 0x9E, 0xA6, + 0xBA, 0xC7, 0xF1, 0x10, 0x24, 0x40, 0x4A, 0x52, 0x57, 0x5F, 0x6C, 0x89, 0x8C, 0x97, 0xAA, + 0xB2, 0xC3, 0xCC, 0xEA, 0xF2, 0x2F, 0x3F, 0x53, 0x5F, 0x7B, 0x81, 0x83, 0x96, 0xA1, 0xB1, + 0xBC, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x25, 0x36, 0x42, + ]; if MLDSA44::verify(&mldsa44_pk, msg, None, &sig).is_ok() { println!("Verification succeeded!"); @@ -330,7 +1434,7 @@ fn bench_mldsa44_verify() { } fn bench_mldsa44_lowmemory_verify() { - use bouncycastle::mldsa_lowmemory::{MLDSATrait, MLDSA44, MLDSA44_SIG_LEN, MLDSA44PublicKey}; + use bouncycastle::mldsa_lowmemory::{MLDSA44, MLDSA44_SIG_LEN, MLDSA44PublicKey, MLDSATrait}; eprintln!("MLDSA44_lowmemory/Verify"); @@ -349,8 +1453,261 @@ fn bench_mldsa44_lowmemory_verify() { // let sig = MLDSA44::sign_mu_deterministic(&mldsa44_sk, &mu, [0u8; 32]).unwrap(); // eprintln!("sig:\n{}", &*hex::encode(sig)); - let pk = MLDSA44PublicKey::from_bytes(&[0xd7,0xb2,0xb4,0x72,0x54,0xaa,0xe0,0xdb,0x45,0xe7,0x93,0x0d,0x4a,0x98,0xd2,0xc9,0x7d,0x8f,0x13,0x97,0xd1,0x78,0x9d,0xaf,0xa1,0x70,0x24,0xb3,0x16,0xe9,0xbe,0xc9,0x4f,0xc9,0x94,0x6d,0x42,0xf1,0x9b,0x79,0xa7,0x41,0x3b,0xba,0xa3,0x3e,0x71,0x49,0xcb,0x42,0xed,0x51,0x15,0x69,0x3a,0xc0,0x41,0xfa,0xcb,0x98,0x8a,0xde,0xb5,0xfe,0x0e,0x1d,0x86,0x31,0x18,0x49,0x95,0xb5,0x92,0xc3,0x97,0xd2,0x29,0x4e,0x2e,0x14,0xf9,0x0a,0xa4,0x14,0xba,0x38,0x26,0x89,0x9a,0xc4,0x3f,0x4c,0xcc,0xac,0xbc,0x26,0xe9,0xa8,0x32,0xb9,0x51,0x18,0xd5,0xcb,0x43,0x3c,0xbe,0xf9,0x66,0x0b,0x00,0x13,0x8e,0x08,0x17,0xf6,0x1e,0x76,0x2c,0xa2,0x74,0xc3,0x6a,0xd5,0x54,0xeb,0x22,0xaa,0xc1,0x16,0x2e,0x4a,0xb0,0x1a,0xcb,0xa1,0xe3,0x8c,0x4e,0xfd,0x8f,0x80,0xb6,0x5b,0x33,0x3d,0x0f,0x72,0xe5,0x5d,0xfe,0x71,0xce,0x9c,0x1e,0xbb,0x98,0x89,0xe7,0xc5,0x61,0x06,0xc0,0xfd,0x73,0x80,0x3a,0x2a,0xec,0xfe,0xaf,0xde,0xd7,0xaa,0x3c,0xb2,0xce,0xda,0x54,0xd1,0x2b,0xd8,0xcd,0x36,0xa7,0x8c,0xf9,0x75,0x94,0x3b,0x47,0xab,0xd2,0x5e,0x88,0x0a,0xc4,0x52,0xe5,0x74,0x2e,0xd1,0xe8,0xd1,0xa8,0x2a,0xfa,0x86,0xe5,0x90,0xc7,0x58,0xc1,0x5a,0xe4,0xd2,0x84,0x0d,0x92,0xbc,0xa1,0xa5,0x09,0x0f,0x40,0x49,0x65,0x97,0xfc,0xa7,0xd8,0xb9,0x51,0x3f,0x1a,0x1b,0xda,0x6e,0x95,0x0a,0xaa,0x98,0xde,0x46,0x75,0x07,0xd4,0xa4,0xf5,0xa4,0xf0,0x59,0x92,0x16,0x58,0x2c,0x35,0x72,0xf6,0x2e,0xda,0x89,0x05,0xab,0x35,0x81,0x67,0x0c,0x4a,0x02,0x77,0x7a,0x33,0xe0,0xca,0x72,0x95,0xfd,0x8f,0x4f,0xf6,0xd1,0xa0,0xa3,0xa7,0x68,0x3d,0x65,0xf5,0xf5,0xf7,0xfc,0x60,0xda,0x02,0x3e,0x82,0x6c,0x5f,0x92,0x14,0x4c,0x02,0xf7,0xd1,0xba,0x10,0x75,0x98,0x75,0x53,0xea,0x93,0x67,0xfc,0xd7,0x6d,0x99,0x0b,0x7f,0xa9,0x9c,0xd4,0x5a,0xfd,0xb8,0x83,0x6d,0x43,0xe4,0x59,0xf5,0x18,0x7d,0xf0,0x58,0x47,0x97,0x09,0xa0,0x1e,0xa6,0x83,0x59,0x35,0xfa,0x70,0x46,0x09,0x90,0xcd,0x3d,0xc1,0xba,0x40,0x1b,0xa9,0x4b,0xab,0x1d,0xde,0x41,0xac,0x67,0xab,0x33,0x19,0xdc,0xac,0xa0,0x60,0x48,0xd4,0xc4,0xee,0xf2,0x7e,0xe1,0x3a,0x9c,0x17,0xd0,0x53,0x8f,0x43,0x0f,0x2d,0x64,0x2d,0xc2,0x41,0x56,0x60,0xde,0x78,0x87,0x7d,0x8d,0x8a,0xbc,0x72,0x52,0x39,0x78,0xc0,0x42,0xe4,0x28,0x5f,0x43,0x19,0x84,0x6c,0x44,0x12,0x62,0x42,0x97,0x68,0x44,0xc1,0x0e,0x55,0x6b,0xa2,0x15,0xb5,0xa7,0x19,0xe5,0x9d,0x0c,0x6b,0x2a,0x96,0xd3,0x98,0x59,0x07,0x1f,0xdc,0xc2,0xcd,0xe7,0x52,0x4a,0x7b,0xed,0xae,0x54,0xe8,0x5b,0x31,0x8e,0x85,0x4e,0x8f,0xe2,0xb2,0xf3,0xed,0xfa,0xc9,0x71,0x91,0x28,0x27,0x0a,0xaf,0xd1,0xe5,0x04,0x4c,0x3a,0x4f,0xda,0xfd,0x9f,0xf3,0x1f,0x90,0x78,0x4b,0x8e,0x8e,0x45,0x96,0x14,0x4a,0x0d,0xaf,0x58,0x65,0x11,0xd3,0xd9,0x96,0x2b,0x9e,0xa9,0x5a,0xf1,0x97,0xb4,0xe5,0xfc,0x60,0xf2,0xb1,0xed,0x15,0xde,0x3a,0x5b,0xef,0x5f,0x89,0xbd,0xc7,0x9d,0x91,0x05,0x1d,0x9b,0x28,0x16,0xe7,0x4f,0xa5,0x45,0x31,0xef,0xdc,0x1c,0xbe,0x74,0xd4,0x48,0x85,0x7f,0x47,0x6b,0xcd,0x58,0xf2,0x1c,0x0b,0x65,0x3b,0x3b,0x76,0xa4,0xe0,0x76,0xa6,0x55,0x9a,0x30,0x27,0x18,0x55,0x5c,0xc6,0x3f,0x74,0x85,0x9a,0xab,0xab,0x92,0x5f,0x02,0x38,0x61,0xca,0x8c,0xd0,0xf7,0xba,0xdb,0x28,0x71,0xf6,0x7d,0x55,0x32,0x6d,0x74,0x51,0x13,0x5a,0xd4,0x5f,0x4a,0x1b,0xa6,0x91,0x18,0xfb,0xb2,0xc8,0xa3,0x0e,0xec,0x93,0x92,0xef,0x3f,0x97,0x70,0x66,0xc9,0xad,0xd5,0xc7,0x10,0xcc,0x64,0x7b,0x15,0x14,0xd2,0x17,0xd9,0x58,0xc7,0x01,0x7c,0x3e,0x90,0xfd,0x20,0xc0,0x4e,0x67,0x4b,0x90,0x48,0x6e,0x93,0x70,0xa3,0x1a,0x00,0x1d,0x32,0xf4,0x73,0x97,0x9e,0x49,0x06,0x74,0x9e,0x7e,0x47,0x7f,0xa0,0xb7,0x45,0x08,0xf8,0xa5,0xf2,0x37,0x83,0x12,0xb8,0x3c,0x25,0xbd,0x38,0x8c,0xa0,0xb0,0xff,0xf7,0x47,0x8b,0xaf,0x42,0xb7,0x16,0x67,0xed,0xaa,0xc9,0x7c,0x46,0xb1,0x29,0x64,0x3e,0x58,0x6e,0x5b,0x05,0x5a,0x0c,0x21,0x19,0x46,0xd4,0xf3,0x6e,0x67,0x5b,0xed,0x58,0x60,0xfa,0x04,0x2a,0x31,0x5d,0x98,0x26,0x16,0x4d,0x6a,0x92,0x37,0xc3,0x5a,0x5f,0xbf,0x49,0x54,0x90,0xa5,0xbd,0x4d,0xf2,0x48,0xb9,0x5c,0x4a,0xae,0x77,0x84,0xb6,0x05,0x67,0x31,0x66,0xac,0x42,0x45,0xb5,0xb4,0xb0,0x82,0xa0,0x9e,0x93,0x23,0xe6,0x2f,0x20,0x78,0xc5,0xb7,0x67,0x83,0x44,0x6d,0xef,0xd7,0x36,0xad,0x3a,0x37,0x02,0xd4,0x9b,0x08,0x98,0x44,0x90,0x0a,0x61,0x83,0x33,0x97,0xbc,0x44,0x19,0xb3,0x0d,0x7a,0x97,0xa0,0xb3,0x87,0xc1,0x91,0x14,0x74,0xc4,0xd4,0x1b,0x53,0xe3,0x2a,0x97,0x7a,0xcb,0x6f,0x0e,0xa7,0x5d,0xb6,0x5b,0xb3,0x9e,0x59,0xe7,0x01,0xe7,0x69,0x57,0xde,0xf6,0xf2,0xd4,0x45,0x59,0xc3,0x1a,0x77,0x12,0x2b,0x52,0x04,0xe3,0xb5,0xc2,0x19,0xf1,0x68,0x8b,0x14,0xed,0x0b,0xc0,0xb8,0x01,0xb3,0xe6,0xe8,0x2d,0xcd,0x43,0xe9,0xc0,0xe9,0xf4,0x17,0x44,0xcd,0x98,0x15,0xbd,0x1b,0xc8,0x82,0x0d,0x8b,0xb1,0x23,0xf0,0x4f,0xac,0xd1,0xb1,0xb6,0x85,0xdd,0x5a,0x2b,0x1b,0x8d,0xbb,0xf3,0xed,0x93,0x36,0x70,0xf0,0x95,0xa1,0x80,0xb4,0xf1,0x92,0xd0,0x8b,0x10,0xb8,0xfa,0xbb,0xdf,0xcc,0x2b,0x24,0x51,0x8e,0x32,0xee,0xa0,0xa5,0xe0,0xc9,0x04,0xca,0x84,0x47,0x80,0x08,0x3f,0x3b,0x0c,0xd2,0xd0,0xb8,0xb6,0xaf,0x67,0xbc,0x35,0x5b,0x94,0x94,0x02,0x5d,0xc7,0xb0,0xa7,0x8f,0xa8,0x0e,0x3a,0x2d,0xbf,0xeb,0x51,0x32,0x88,0x51,0xd6,0x07,0x81,0x98,0xe9,0x49,0x36,0x51,0xae,0x78,0x7e,0xc0,0x25,0x1f,0x92,0x2b,0xa3,0x0e,0x9f,0x51,0xdf,0x62,0xa6,0xd7,0x27,0x84,0xcf,0x3d,0xd2,0x05,0x39,0x31,0x76,0xdf,0xa3,0x24,0xa5,0x12,0xbd,0x94,0x97,0x0a,0x36,0xdd,0x34,0xa5,0x14,0xa8,0x67,0x91,0xf0,0xeb,0x36,0xf0,0x14,0x5b,0x09,0xab,0x64,0x65,0x1b,0x4a,0x03,0x13,0xb2,0x99,0x61,0x1a,0x2a,0x1c,0x48,0x89,0x16,0x27,0x59,0x87,0x68,0xa3,0x11,0x40,0x60,0xba,0x44,0x43,0x48,0x6d,0xf5,0x15,0x22,0xa1,0xce,0x88,0xb3,0x09,0x85,0xc2,0x16,0xf8,0xe6,0xed,0x17,0x8d,0xd5,0x67,0xb3,0x04,0xa0,0xd4,0xca,0xfb,0xa8,0x82,0xa2,0x83,0x42,0xf1,0x7a,0x9a,0xa2,0x6a,0xe5,0x8d,0xb6,0x30,0x08,0x3d,0x2c,0x35,0x8f,0xdf,0x56,0x6c,0x3f,0x5d,0x62,0xa4,0x28,0x56,0x7b,0xc9,0xea,0x8c,0xe9,0x5c,0xaa,0x0f,0x35,0x47,0x4b,0x0b,0xfa,0x8f,0x33,0x9a,0x25,0x0a,0xb4,0xdf,0xcf,0x20,0x83,0xbe,0x8e,0xef,0xbc,0x10,0x55,0xe1,0x8f,0xe1,0x53,0x70,0xee,0xcb,0x26,0x05,0x66,0xd8,0x3f,0xf0,0x6b,0x21,0x1a,0xae,0xc4,0x3c,0xa2,0x9b,0x54,0xcc,0xd0,0x0f,0x88,0x15,0xa2,0x46,0x5e,0xf0,0xb4,0x65,0x15,0xcc,0x7e,0x41,0xf3,0x12,0x4f,0x09,0xef,0xff,0x73,0x93,0x09,0xab,0x58,0xb2,0x9a,0x14,0x59,0xa0,0x0b,0xce,0x50,0x38,0xe9,0x38,0xc9,0x67,0x8f,0x72,0xeb,0x0e,0x4e,0xe5,0xfd,0xaa,0xe6,0x6d,0x9f,0x85,0x73,0xfc,0x97,0xfc,0x42,0xb4,0x95,0x9f,0x4b,0xf8,0xb6,0x1d,0x78,0x43,0x3e,0x86,0xb0,0x33,0x5d,0x6e,0x91,0x91,0xc4,0xd8,0xbf,0x48,0x7b,0x39,0x05,0xc1,0x08,0xcf,0xd6,0xac,0x24,0xb0,0xce,0xb7,0xdc,0xb7,0xcf,0x51,0xf8,0x4d,0x0e,0xd6,0x87,0xb9,0x5e,0xae,0xb1,0xc5,0x33,0xc0,0x6f,0x0d,0x97,0x02,0x3d,0x92,0xa7,0x08,0x25,0x83,0x7b,0x59,0xba,0x6c,0xb7,0xd4,0xe5,0x6b,0x0a,0x87,0xc2,0x03,0x86,0x2a,0xe8,0xf3,0x15,0xba,0x59,0x25,0xe8,0xed,0xef,0xa6,0x79,0x36,0x9a,0x22,0x02,0x76,0x61,0x51,0xf1,0x6a,0x96,0x5f,0x9f,0x81,0xec,0xe7,0x6c,0xc0,0x70,0xb5,0x58,0x69,0xe4,0xdb,0x97,0x84,0xcf,0x05,0xc8,0x30,0xb3,0x24,0x2c,0x83,0x12]).unwrap(); - let sig: [u8; MLDSA44_SIG_LEN] = [0x5e,0x93,0xb7,0x85,0xc5,0x11,0x9c,0x39,0x83,0xa2,0x91,0xb1,0x84,0x20,0xfd,0xbe,0x4b,0xca,0x53,0xd5,0xa3,0x73,0x29,0x22,0xfa,0xaa,0xcd,0x5a,0x5d,0x32,0xa7,0x45,0xc7,0x8d,0x10,0x5b,0xa1,0x0b,0xee,0x1e,0xd8,0x06,0x9f,0x19,0xe6,0xc5,0x37,0xbd,0xa1,0x6e,0x89,0xd3,0x90,0x04,0xc3,0x59,0xd1,0xfd,0x38,0x1a,0x02,0x91,0xf1,0xc5,0x1f,0x1c,0x38,0xed,0xcd,0xb3,0x15,0xc8,0xc6,0x95,0x70,0xd8,0xf2,0x5f,0x16,0x55,0xba,0x8e,0xa8,0x3a,0xff,0x24,0xb8,0xb6,0xbe,0x8d,0xe7,0x62,0x34,0x2e,0x34,0x7e,0xab,0x2c,0xaa,0x68,0x03,0xed,0x70,0x59,0x52,0xdd,0x64,0x50,0xc5,0x18,0x5e,0x9d,0x60,0xce,0x96,0xe8,0xdc,0xa4,0x23,0xa0,0x2f,0x64,0x6c,0xea,0x69,0x01,0x64,0xa2,0x26,0xe4,0xc3,0xd6,0xa5,0x15,0xce,0x16,0x29,0x0f,0x19,0xb2,0xc6,0x26,0xda,0x9b,0x45,0x0e,0xcf,0x66,0x50,0x13,0xc5,0xe2,0x26,0xb6,0xc0,0xac,0x5c,0x07,0xce,0x90,0xe2,0x78,0xf1,0xb0,0x13,0x4e,0x38,0x5d,0x13,0xe7,0x42,0x08,0xa0,0xb3,0xff,0x05,0x2a,0x36,0x25,0x79,0xf9,0x20,0x7e,0xa0,0x1f,0x18,0xa0,0x39,0xaa,0x1b,0x97,0xae,0x34,0x52,0x67,0x5b,0x62,0x07,0x71,0xf8,0x01,0x2e,0xe7,0xa4,0xe5,0x5c,0x98,0xbf,0xd2,0x01,0x9e,0xd8,0xa3,0xb0,0x0a,0xce,0xa8,0xe8,0xab,0x28,0x17,0x2f,0xaa,0x42,0xca,0x1f,0xda,0x83,0xc5,0xff,0xe8,0x1a,0x45,0xbe,0x73,0x6b,0xde,0xdd,0x5f,0xb3,0x00,0xce,0x17,0x07,0x8b,0x38,0x0f,0x62,0x0b,0xde,0xeb,0xad,0x69,0x36,0x01,0x37,0x2c,0x85,0xea,0xcf,0x79,0xbc,0x98,0xe1,0xb4,0x8f,0x2a,0xd7,0xe5,0xdc,0xe4,0x27,0x9a,0x12,0x95,0xbb,0x2b,0xa6,0x0a,0x0c,0x5e,0x37,0x26,0x64,0x2d,0x23,0x36,0xc5,0xeb,0x1d,0x37,0xc8,0x62,0x3c,0x75,0x58,0x24,0x13,0x18,0xd8,0x9b,0xc7,0x83,0xc4,0xf0,0x00,0x98,0x07,0x74,0x84,0x62,0x3c,0x21,0x75,0x60,0xa0,0xc7,0xaa,0xf7,0x5d,0xca,0xcc,0xb7,0x8e,0xe6,0x9c,0x20,0x7c,0x27,0xc8,0xbf,0x39,0x65,0xcc,0xf5,0x8a,0x80,0xc8,0x8e,0xfc,0xc7,0xe5,0xde,0xb3,0x61,0x5d,0x50,0x45,0xa7,0x41,0xc4,0xda,0xc0,0xa0,0x21,0xdd,0x06,0x0d,0x31,0x5d,0x4e,0xc2,0x85,0x7e,0xb6,0x64,0xd7,0x28,0xd0,0xaf,0x97,0x3b,0xea,0x07,0xe1,0xca,0x56,0x3f,0xaa,0x0e,0x19,0x99,0x6c,0xea,0x37,0x70,0x31,0x6c,0x11,0xa5,0x06,0x66,0x65,0x66,0x20,0x05,0xac,0xe9,0x8f,0x61,0x10,0xe8,0x83,0xba,0xe0,0x60,0xda,0xa7,0xb6,0xd8,0x33,0x79,0xe0,0x87,0x87,0x96,0x69,0x17,0x08,0xa3,0x2b,0x85,0x73,0x0d,0xe8,0xb9,0x2d,0x89,0xf9,0x0a,0x36,0x60,0xc9,0x49,0x16,0x5b,0x14,0x61,0x25,0x67,0x66,0x2e,0x16,0x22,0x32,0x29,0x6c,0xbd,0x14,0x35,0x17,0xa2,0x82,0xe2,0x2c,0x46,0xb6,0x36,0x06,0xd3,0xc1,0x4e,0xd4,0x55,0x9a,0x5a,0x1c,0x45,0x9b,0xab,0x7f,0x35,0x50,0x07,0xad,0x6f,0x7e,0x3b,0x1e,0x07,0x44,0x5d,0xfc,0x96,0xbd,0x9b,0x75,0x08,0x0b,0x3d,0x4f,0x68,0x99,0x84,0x90,0xa2,0x6b,0x5e,0x09,0x0b,0xe2,0x67,0x40,0x71,0xab,0x92,0x5b,0xb6,0x50,0x59,0x08,0x56,0xc5,0x9f,0x8b,0xa7,0x48,0x8d,0x2b,0x72,0xf8,0x40,0xac,0x3e,0xaf,0xe4,0xdd,0x91,0xf0,0xf5,0x1c,0x43,0x64,0x11,0x2c,0x1a,0x13,0x9e,0x3e,0x94,0x2a,0x59,0x7b,0x93,0xa1,0xe3,0xf4,0xfa,0xde,0xd1,0x29,0xc1,0x4b,0x59,0x78,0xb3,0x15,0xe2,0x24,0x6a,0x93,0x14,0x6a,0x79,0x36,0x5f,0x0f,0x59,0x7a,0x18,0x34,0x0c,0xca,0x86,0xbb,0x15,0xce,0xed,0x39,0xf1,0x75,0xea,0xb1,0xe5,0x46,0x53,0x5a,0xfb,0x96,0x6f,0x0a,0x65,0xa8,0xf6,0x6f,0x73,0x7a,0xb0,0x28,0x97,0xed,0xdf,0xe9,0x2c,0xf7,0x78,0x68,0x94,0x84,0x3c,0x26,0x91,0x46,0x47,0x76,0xc9,0x4b,0xd4,0x50,0xa1,0x06,0x91,0x38,0xb2,0x6d,0xf8,0x3b,0x2d,0x1d,0xd8,0x01,0x14,0x3a,0x8f,0xdf,0xdc,0x25,0x14,0xcc,0x5b,0x58,0x31,0xab,0x53,0xa7,0x5c,0x55,0xef,0x29,0xf4,0x0e,0x7c,0x63,0xd2,0xc7,0x2a,0xbe,0x97,0xe2,0xaf,0x14,0x85,0x3b,0xe4,0x9b,0xe1,0x6f,0x47,0x30,0xa1,0x59,0x97,0x49,0x70,0x95,0x14,0x39,0xe5,0x5c,0x15,0x89,0xd0,0xf4,0xa1,0x62,0xe3,0x51,0x7d,0xf9,0xd7,0xab,0xc9,0x8d,0x8a,0x30,0x72,0x16,0xe7,0xf1,0xcb,0x46,0x27,0xc9,0x17,0x5c,0x0e,0xef,0x23,0x33,0x7e,0x56,0xd5,0x28,0x1b,0x83,0x72,0x6f,0xff,0x40,0xa1,0x48,0xb0,0xc4,0x8e,0x8d,0xf3,0x49,0x6a,0x21,0x18,0xd8,0x02,0x19,0xae,0xf8,0xf4,0x0b,0x29,0xfb,0xa1,0xf2,0xf7,0x87,0x86,0xb6,0x7f,0xfb,0x7b,0x7d,0x47,0xd4,0x06,0xb7,0x65,0xbd,0x13,0x66,0x10,0xbe,0xde,0xb9,0x5c,0xd7,0x32,0x1f,0x58,0xf3,0xb8,0x36,0xc9,0x25,0x8b,0xe3,0x5d,0x78,0xb4,0x98,0xf3,0xef,0xe1,0xdb,0x2b,0x24,0x3d,0x73,0x4f,0xab,0x15,0x9b,0xae,0xd8,0x80,0x7c,0x3c,0xcc,0xf8,0x3e,0xb2,0xea,0xf8,0xa9,0xaf,0x01,0xa5,0x18,0xd4,0x8c,0x60,0xe9,0x1a,0x96,0x81,0x2a,0xd6,0x89,0xc2,0xd8,0x3c,0xc4,0xe8,0xe9,0xb3,0x65,0x04,0x22,0xbe,0xd6,0xf1,0x3c,0x24,0xad,0xaa,0xd9,0x1c,0x95,0xb3,0xe3,0xcf,0x35,0x4f,0x0f,0x6b,0xc9,0xee,0x89,0x41,0xa6,0xb1,0x5b,0x69,0x75,0x13,0x1d,0x95,0x23,0x3d,0x89,0x35,0xde,0x36,0x7e,0xfc,0x6d,0x86,0xa4,0x5d,0xac,0x7d,0x0f,0x1d,0xdd,0x9a,0xeb,0xd2,0xc5,0x9c,0x02,0x7f,0xcd,0xa4,0x48,0x80,0x1e,0x93,0xe7,0x33,0xac,0xa5,0x18,0x74,0xbe,0x9a,0xb9,0x27,0xa9,0x04,0xf9,0x6d,0xdb,0x7a,0x46,0xb2,0xda,0x13,0x26,0x1d,0x52,0x2b,0x23,0xc9,0x50,0xc0,0x1d,0x5f,0x5e,0x11,0x2b,0x76,0xf8,0x51,0xff,0x23,0x4f,0x06,0xf8,0xd5,0xe6,0x5b,0x13,0x19,0xab,0xcd,0x79,0xa1,0x80,0xae,0x06,0x3d,0x65,0xb2,0x8c,0x74,0x58,0x78,0xc0,0x6d,0xbb,0x69,0xba,0x73,0x29,0x3e,0xab,0x34,0x43,0x4b,0xf1,0xa9,0x2f,0xba,0x69,0x19,0x93,0xbd,0x0f,0xf3,0xed,0xac,0x76,0xa1,0x2f,0x80,0xc0,0xad,0xa4,0xb1,0x96,0x9c,0x76,0x65,0x58,0x9d,0x53,0x0a,0x67,0x01,0x6a,0x62,0x54,0x03,0xc5,0x37,0x03,0x29,0x04,0xf2,0xe1,0x04,0x54,0x7c,0xd3,0xea,0x40,0x62,0x60,0xdd,0x35,0x7f,0xa0,0x6e,0xa0,0x12,0xa7,0x85,0x82,0x6c,0x16,0x0e,0x99,0xff,0xd0,0x65,0xb0,0xe3,0xf3,0x3c,0x76,0x89,0xd3,0x55,0x2a,0xb9,0xe2,0xe0,0x9f,0xa7,0xe5,0x5b,0xbc,0xef,0x04,0x22,0x42,0xbc,0xac,0xad,0x8a,0x3d,0xa4,0x7b,0xcc,0x54,0xa1,0x21,0xf1,0x52,0x6c,0x8c,0xd4,0xcc,0x5a,0x89,0x2a,0x81,0x31,0xcf,0x4e,0xef,0xaf,0x42,0x48,0xdd,0xd6,0xa1,0x1e,0xc4,0x27,0xba,0x37,0x8a,0xae,0x89,0xaa,0xf5,0x82,0xce,0x1f,0x4e,0x32,0x69,0x0a,0x55,0x5e,0x74,0x07,0x61,0xd3,0x58,0xad,0x4e,0x92,0xbc,0x38,0x41,0x8a,0xa7,0x82,0xda,0x91,0x65,0x24,0xfb,0x09,0xab,0x2c,0xa6,0xb3,0xd3,0x11,0x3d,0x6f,0x2c,0x2a,0x6a,0x9b,0x9d,0x29,0xd4,0xe7,0x48,0x92,0x55,0x25,0x2a,0xf0,0x75,0xcb,0xf9,0xfe,0xac,0xed,0xae,0x6f,0x3e,0xc0,0xb0,0x70,0x82,0x46,0x89,0xdd,0x3c,0x78,0xac,0x14,0x3e,0xd6,0x77,0x6d,0x95,0xdd,0x8f,0x13,0xd4,0x35,0xa2,0x90,0xbd,0xca,0x4c,0x11,0x31,0x8e,0x5a,0xcc,0xe0,0x44,0x69,0x64,0x4e,0x13,0x74,0xa9,0x45,0x1b,0x62,0x04,0xf3,0xb3,0x96,0x1b,0x7d,0xd2,0x39,0xe3,0x06,0xfe,0xf5,0xf4,0xf4,0xe5,0x1b,0x78,0xb0,0xfb,0x9d,0xce,0xe6,0x9c,0x3e,0x79,0x0b,0x23,0x1f,0x2e,0x65,0xfd,0x1a,0xb1,0xc2,0xa7,0x5b,0x07,0x06,0x7d,0x5c,0x16,0xdd,0xe0,0x09,0x83,0xa5,0x8f,0xfc,0xda,0xaa,0xee,0x16,0xd2,0x74,0x2e,0x13,0x3e,0xd7,0x37,0xb4,0x80,0x64,0xc8,0xa3,0x8e,0xca,0x35,0xab,0x3f,0xa1,0x8f,0x6d,0x62,0xf6,0x42,0xb1,0x2c,0xfd,0xc7,0x98,0x0f,0x2a,0xb7,0xdb,0x32,0x1f,0xec,0x9d,0xcf,0xe4,0x99,0xb4,0xfc,0x1e,0xe7,0xeb,0x29,0x79,0x54,0x05,0x66,0x17,0xc6,0x0a,0x66,0x40,0xb9,0x28,0x35,0xd1,0x65,0xc3,0xc0,0x0a,0x95,0x19,0x52,0x61,0x44,0x88,0xd5,0x65,0x7b,0xa0,0xb5,0xe9,0x0a,0xe9,0xe0,0xef,0x7b,0x3b,0x9e,0xca,0xeb,0xd8,0x1b,0x85,0x51,0xb6,0xd7,0x0e,0x83,0x5b,0x27,0x34,0x76,0x16,0x39,0xd4,0x2e,0x76,0xff,0xc5,0xb3,0x27,0x2b,0x61,0xc8,0x96,0xb4,0x5b,0x4b,0xd1,0x8f,0x30,0xe5,0x8c,0x44,0x06,0x43,0xba,0x15,0x92,0x21,0xcc,0x67,0x39,0xa1,0x9a,0x65,0xf2,0x91,0x1f,0xae,0x47,0xb0,0xd4,0xca,0xc4,0x20,0x0a,0x6f,0x04,0x3b,0x17,0xa0,0x3a,0xd3,0x93,0xec,0xb8,0x23,0xed,0x03,0xc8,0xb6,0xcd,0x68,0x16,0x7e,0x6c,0x82,0x34,0xf7,0x43,0x25,0x57,0xdb,0x27,0x20,0x79,0xee,0x89,0x9a,0xed,0xe7,0x3b,0x6b,0x98,0xd6,0x00,0x3f,0x45,0x78,0x9a,0x14,0x1b,0x60,0xd6,0xdb,0x40,0xcd,0x2a,0x59,0x74,0x57,0x1a,0x4a,0xd3,0x66,0x7b,0x88,0x93,0x18,0xba,0x60,0x28,0x5d,0x90,0x3a,0x2e,0xac,0x01,0xc2,0x16,0x08,0x83,0x8c,0x40,0x90,0x7d,0xe6,0xbb,0xab,0xe0,0x42,0xcf,0x2e,0xcd,0xd9,0x7f,0x54,0x9f,0x95,0xec,0x69,0x8d,0x79,0x22,0x2c,0x65,0xba,0x27,0xc3,0x0d,0x33,0x2a,0x68,0xd0,0x57,0xae,0xcd,0xc9,0x38,0x8a,0xa3,0x43,0x20,0xe0,0xaa,0x74,0xfd,0xbd,0x4d,0x1b,0x64,0x3c,0xac,0xe2,0x16,0xb6,0xd8,0xad,0x8f,0x07,0xa9,0x99,0x55,0xbf,0xdb,0x74,0x3a,0x86,0xb4,0x0f,0xc6,0x15,0x27,0xba,0xca,0x43,0x4a,0xc2,0xa7,0xfb,0xea,0xa7,0x71,0x11,0xdc,0x80,0x98,0xb1,0x7e,0x80,0x0f,0x59,0xdd,0x77,0xcc,0xb0,0xe6,0x77,0x07,0xe6,0x01,0x23,0xd3,0x34,0xe0,0x73,0xa2,0xf5,0xa1,0x6f,0xfb,0xcd,0x70,0x13,0x89,0xad,0xd5,0x7c,0x3c,0xec,0xcb,0x88,0xb2,0x86,0xac,0x1e,0x6e,0x3e,0x64,0x85,0xaf,0x1a,0x12,0xea,0x24,0x1d,0x14,0xa1,0xb5,0x00,0x3d,0x7f,0x3b,0xc9,0xe9,0x57,0xd4,0x48,0x3c,0x0f,0x9f,0x70,0x3b,0x3a,0x18,0x7d,0x55,0xe5,0x05,0x81,0x76,0x15,0xfb,0xc4,0xae,0x08,0x37,0x61,0x61,0x84,0x24,0x5c,0xfb,0xa6,0x1c,0xe3,0xb9,0x29,0xe3,0x3f,0x52,0xb7,0x1c,0xdd,0x7b,0x6a,0x0d,0xa5,0x5c,0x1f,0x99,0x75,0x10,0xb1,0xa9,0x00,0x2c,0xa4,0xe0,0x67,0x83,0x73,0xa3,0xb1,0xab,0x28,0x97,0xe6,0xb4,0x23,0xf1,0x5a,0x44,0x0a,0x63,0x6c,0xc8,0x61,0x49,0x1e,0xf4,0x1a,0xd0,0xaa,0x62,0x7d,0x8e,0x19,0x8a,0x5e,0xe7,0xbd,0x7b,0x6c,0xb2,0xc9,0xce,0x2a,0x8c,0xc0,0x15,0xf0,0xd2,0x06,0xde,0x4c,0x49,0xe2,0xf8,0x7f,0x31,0x09,0x54,0xa1,0x0d,0x86,0xe2,0x94,0xf7,0x42,0xee,0x18,0x6f,0x4a,0xe9,0x81,0x5f,0x69,0x96,0x22,0x79,0x22,0x06,0xca,0xfb,0xa8,0xf5,0x62,0x17,0x38,0x16,0x0e,0x6c,0x5d,0x61,0x1a,0x82,0x52,0xc6,0xf3,0x50,0x85,0xb6,0x04,0xef,0x89,0x51,0x64,0xd4,0xea,0x6d,0xdd,0x31,0x0c,0x7d,0x8f,0x0c,0x87,0x9f,0xb1,0xf8,0x84,0xc5,0x74,0x1d,0x09,0x6b,0x3d,0x2d,0xa0,0xce,0x11,0x51,0x79,0x0d,0xda,0x88,0x1d,0x18,0xcb,0x6b,0x19,0xa9,0xfe,0xd6,0xf5,0x25,0x4b,0x7d,0x52,0xd5,0xd9,0x2b,0xbb,0xe2,0x4c,0x9d,0x6a,0x65,0x60,0x4a,0x0b,0x8e,0xd2,0x4a,0xd5,0xc1,0x97,0xd6,0x83,0xf5,0x98,0x74,0x3c,0x96,0xb5,0x96,0x0e,0x87,0x23,0x73,0x2b,0x5b,0xd6,0x47,0xe9,0xdb,0xea,0xa8,0x51,0xd0,0xe1,0xcf,0x6d,0x2c,0x07,0x0d,0x44,0x42,0x76,0x2c,0x28,0x09,0x8c,0x5c,0xf5,0xa5,0x4b,0x2b,0x5e,0x69,0xa9,0x9b,0x10,0x81,0x5b,0xf0,0xf4,0x77,0xbb,0x71,0xf0,0xd5,0xd3,0xa6,0x2b,0xa2,0xb3,0xe2,0x9b,0xf8,0x4d,0x4b,0x4e,0x57,0x47,0x07,0xf5,0xf7,0x4a,0xf7,0x04,0xd2,0x77,0xbd,0x6c,0xa3,0x8d,0xa2,0x1e,0x2c,0xda,0xc5,0x49,0xe5,0xea,0xe1,0xde,0x7a,0x18,0xee,0x53,0x4c,0x8c,0x22,0x91,0xc9,0x08,0xca,0xab,0xf1,0x59,0xe9,0x0e,0x65,0x49,0xdb,0x94,0xba,0x7a,0x3f,0x3d,0x97,0xdd,0x39,0x8a,0x75,0xdf,0x5b,0x1a,0x7c,0xdf,0xb2,0x54,0x10,0xb7,0xef,0xc4,0xed,0x00,0xd9,0x99,0x5b,0x37,0xb5,0x8b,0xf9,0x1e,0xd7,0xa3,0x51,0x0c,0xff,0xea,0x82,0xf9,0xe1,0xc2,0xa3,0x29,0x04,0x06,0x00,0x4d,0x09,0x05,0x7d,0x63,0xb7,0x70,0xfa,0x0e,0x53,0x10,0x31,0x99,0x54,0x4e,0xba,0x66,0x2a,0x2c,0x30,0x2c,0xf3,0x90,0x08,0xf1,0x42,0xd2,0xb1,0x69,0x63,0xe9,0x5a,0xb1,0x0b,0xe7,0xc2,0x61,0x01,0x68,0x60,0x8f,0x35,0x3a,0x2f,0x2c,0x41,0xc7,0x05,0x6d,0xec,0x1a,0x8c,0x7a,0x6b,0xfa,0x00,0x27,0xf9,0xde,0xda,0xcb,0x77,0x86,0xb6,0x7e,0xa2,0xc4,0x94,0xd4,0x3b,0xa8,0x51,0xcf,0x94,0x15,0xc1,0xbc,0xc5,0x2f,0x02,0x7e,0xc0,0x2c,0x65,0x53,0x4f,0x60,0x8e,0x9d,0x16,0x6d,0x51,0xdd,0x43,0x1c,0xdf,0x58,0x71,0xf5,0xcd,0xd1,0x57,0x9c,0xc0,0x60,0x79,0xdf,0x07,0x5a,0x25,0x06,0x2b,0xa7,0xe7,0x0d,0x96,0x66,0xc4,0xe7,0xfe,0xd3,0x4c,0xea,0x0e,0xa0,0xf1,0x1a,0xde,0x1e,0xb2,0xa9,0xb3,0x97,0xbc,0xaa,0xad,0x10,0x61,0x27,0x0e,0xcf,0x49,0x78,0x03,0xa5,0xfc,0xe7,0xf4,0x1e,0x65,0x04,0xfb,0xec,0x71,0xa7,0xde,0x7d,0x06,0x6b,0x82,0x61,0x86,0x8a,0xfc,0x49,0xb9,0xe6,0x85,0xf0,0xdc,0xce,0x75,0xe2,0xfc,0xb3,0xba,0x8c,0xf1,0x90,0x57,0xe3,0x94,0x15,0x76,0xba,0xf5,0x8f,0xb8,0x21,0xbd,0x42,0x68,0xf7,0xfa,0xe3,0x02,0x86,0x01,0xda,0x02,0x2e,0x9b,0x46,0x86,0x46,0xab,0xdb,0x4f,0xa6,0x09,0x8a,0x44,0x9b,0x42,0x67,0xd5,0x09,0xd9,0xa3,0x3f,0x4c,0x3e,0xbc,0xc3,0x2d,0xac,0x09,0x4d,0x48,0xed,0x60,0x0e,0x76,0x57,0x87,0xfb,0x92,0xb1,0x97,0x4f,0x74,0xf7,0xbb,0x4c,0x66,0xeb,0x2b,0xbd,0x02,0x89,0x5e,0x6a,0x38,0x1c,0x1c,0x45,0x2e,0xaa,0xb1,0xae,0x47,0x31,0xcf,0x63,0x2f,0x61,0xae,0x2c,0x90,0x59,0x21,0x17,0x4a,0x3b,0xc9,0xbb,0x4c,0xdc,0x89,0xd6,0x30,0x26,0x4b,0x61,0x49,0x88,0xf3,0xab,0xbe,0xa1,0xbd,0x61,0x7f,0xfa,0x53,0xd7,0x1b,0x7d,0x8a,0x37,0x14,0x62,0xb7,0x73,0x35,0x1a,0x2d,0xcc,0xae,0xdd,0x7f,0x59,0xcd,0x72,0x8f,0xad,0xee,0x05,0x90,0x67,0xbd,0x80,0xc9,0x4c,0x8c,0x9a,0x1f,0xfc,0xa2,0xdc,0x4f,0x84,0x8b,0x82,0x9c,0x05,0x61,0x38,0x5a,0xa8,0x2c,0xc9,0x85,0x03,0xd0,0xbb,0x66,0xa6,0xaa,0x4f,0xae,0x07,0x03,0xd1,0x2e,0x60,0xe1,0x46,0x0e,0xfb,0xbc,0xdf,0x24,0x12,0xc1,0x3e,0x7c,0x68,0x4d,0x1b,0x01,0x10,0x20,0x26,0x34,0x3a,0x41,0x43,0x44,0x58,0x5f,0x6e,0x70,0x72,0x74,0x8b,0xae,0xb5,0xbb,0xc6,0xd1,0xe2,0xef,0xfb,0xfe,0x06,0x0e,0x2e,0x3e,0x51,0x60,0x79,0x7c,0x9e,0xa6,0xba,0xc7,0xf1,0x10,0x24,0x40,0x4a,0x52,0x57,0x5f,0x6c,0x89,0x8c,0x97,0xaa,0xb2,0xc3,0xcc,0xea,0xf2,0x2f,0x3f,0x53,0x5f,0x7b,0x81,0x83,0x96,0xa1,0xb1,0xbc,0xe6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x25,0x36,0x42]; + let pk = MLDSA44PublicKey::from_bytes(&[ + 0xD7, 0xB2, 0xB4, 0x72, 0x54, 0xAA, 0xE0, 0xDB, 0x45, 0xE7, 0x93, 0x0D, 0x4A, 0x98, 0xD2, + 0xC9, 0x7D, 0x8F, 0x13, 0x97, 0xD1, 0x78, 0x9D, 0xAF, 0xA1, 0x70, 0x24, 0xB3, 0x16, 0xE9, + 0xBE, 0xC9, 0x4F, 0xC9, 0x94, 0x6D, 0x42, 0xF1, 0x9B, 0x79, 0xA7, 0x41, 0x3B, 0xBA, 0xA3, + 0x3E, 0x71, 0x49, 0xCB, 0x42, 0xED, 0x51, 0x15, 0x69, 0x3A, 0xC0, 0x41, 0xFA, 0xCB, 0x98, + 0x8A, 0xDE, 0xB5, 0xFE, 0x0E, 0x1D, 0x86, 0x31, 0x18, 0x49, 0x95, 0xB5, 0x92, 0xC3, 0x97, + 0xD2, 0x29, 0x4E, 0x2E, 0x14, 0xF9, 0x0A, 0xA4, 0x14, 0xBA, 0x38, 0x26, 0x89, 0x9A, 0xC4, + 0x3F, 0x4C, 0xCC, 0xAC, 0xBC, 0x26, 0xE9, 0xA8, 0x32, 0xB9, 0x51, 0x18, 0xD5, 0xCB, 0x43, + 0x3C, 0xBE, 0xF9, 0x66, 0x0B, 0x00, 0x13, 0x8E, 0x08, 0x17, 0xF6, 0x1E, 0x76, 0x2C, 0xA2, + 0x74, 0xC3, 0x6A, 0xD5, 0x54, 0xEB, 0x22, 0xAA, 0xC1, 0x16, 0x2E, 0x4A, 0xB0, 0x1A, 0xCB, + 0xA1, 0xE3, 0x8C, 0x4E, 0xFD, 0x8F, 0x80, 0xB6, 0x5B, 0x33, 0x3D, 0x0F, 0x72, 0xE5, 0x5D, + 0xFE, 0x71, 0xCE, 0x9C, 0x1E, 0xBB, 0x98, 0x89, 0xE7, 0xC5, 0x61, 0x06, 0xC0, 0xFD, 0x73, + 0x80, 0x3A, 0x2A, 0xEC, 0xFE, 0xAF, 0xDE, 0xD7, 0xAA, 0x3C, 0xB2, 0xCE, 0xDA, 0x54, 0xD1, + 0x2B, 0xD8, 0xCD, 0x36, 0xA7, 0x8C, 0xF9, 0x75, 0x94, 0x3B, 0x47, 0xAB, 0xD2, 0x5E, 0x88, + 0x0A, 0xC4, 0x52, 0xE5, 0x74, 0x2E, 0xD1, 0xE8, 0xD1, 0xA8, 0x2A, 0xFA, 0x86, 0xE5, 0x90, + 0xC7, 0x58, 0xC1, 0x5A, 0xE4, 0xD2, 0x84, 0x0D, 0x92, 0xBC, 0xA1, 0xA5, 0x09, 0x0F, 0x40, + 0x49, 0x65, 0x97, 0xFC, 0xA7, 0xD8, 0xB9, 0x51, 0x3F, 0x1A, 0x1B, 0xDA, 0x6E, 0x95, 0x0A, + 0xAA, 0x98, 0xDE, 0x46, 0x75, 0x07, 0xD4, 0xA4, 0xF5, 0xA4, 0xF0, 0x59, 0x92, 0x16, 0x58, + 0x2C, 0x35, 0x72, 0xF6, 0x2E, 0xDA, 0x89, 0x05, 0xAB, 0x35, 0x81, 0x67, 0x0C, 0x4A, 0x02, + 0x77, 0x7A, 0x33, 0xE0, 0xCA, 0x72, 0x95, 0xFD, 0x8F, 0x4F, 0xF6, 0xD1, 0xA0, 0xA3, 0xA7, + 0x68, 0x3D, 0x65, 0xF5, 0xF5, 0xF7, 0xFC, 0x60, 0xDA, 0x02, 0x3E, 0x82, 0x6C, 0x5F, 0x92, + 0x14, 0x4C, 0x02, 0xF7, 0xD1, 0xBA, 0x10, 0x75, 0x98, 0x75, 0x53, 0xEA, 0x93, 0x67, 0xFC, + 0xD7, 0x6D, 0x99, 0x0B, 0x7F, 0xA9, 0x9C, 0xD4, 0x5A, 0xFD, 0xB8, 0x83, 0x6D, 0x43, 0xE4, + 0x59, 0xF5, 0x18, 0x7D, 0xF0, 0x58, 0x47, 0x97, 0x09, 0xA0, 0x1E, 0xA6, 0x83, 0x59, 0x35, + 0xFA, 0x70, 0x46, 0x09, 0x90, 0xCD, 0x3D, 0xC1, 0xBA, 0x40, 0x1B, 0xA9, 0x4B, 0xAB, 0x1D, + 0xDE, 0x41, 0xAC, 0x67, 0xAB, 0x33, 0x19, 0xDC, 0xAC, 0xA0, 0x60, 0x48, 0xD4, 0xC4, 0xEE, + 0xF2, 0x7E, 0xE1, 0x3A, 0x9C, 0x17, 0xD0, 0x53, 0x8F, 0x43, 0x0F, 0x2D, 0x64, 0x2D, 0xC2, + 0x41, 0x56, 0x60, 0xDE, 0x78, 0x87, 0x7D, 0x8D, 0x8A, 0xBC, 0x72, 0x52, 0x39, 0x78, 0xC0, + 0x42, 0xE4, 0x28, 0x5F, 0x43, 0x19, 0x84, 0x6C, 0x44, 0x12, 0x62, 0x42, 0x97, 0x68, 0x44, + 0xC1, 0x0E, 0x55, 0x6B, 0xA2, 0x15, 0xB5, 0xA7, 0x19, 0xE5, 0x9D, 0x0C, 0x6B, 0x2A, 0x96, + 0xD3, 0x98, 0x59, 0x07, 0x1F, 0xDC, 0xC2, 0xCD, 0xE7, 0x52, 0x4A, 0x7B, 0xED, 0xAE, 0x54, + 0xE8, 0x5B, 0x31, 0x8E, 0x85, 0x4E, 0x8F, 0xE2, 0xB2, 0xF3, 0xED, 0xFA, 0xC9, 0x71, 0x91, + 0x28, 0x27, 0x0A, 0xAF, 0xD1, 0xE5, 0x04, 0x4C, 0x3A, 0x4F, 0xDA, 0xFD, 0x9F, 0xF3, 0x1F, + 0x90, 0x78, 0x4B, 0x8E, 0x8E, 0x45, 0x96, 0x14, 0x4A, 0x0D, 0xAF, 0x58, 0x65, 0x11, 0xD3, + 0xD9, 0x96, 0x2B, 0x9E, 0xA9, 0x5A, 0xF1, 0x97, 0xB4, 0xE5, 0xFC, 0x60, 0xF2, 0xB1, 0xED, + 0x15, 0xDE, 0x3A, 0x5B, 0xEF, 0x5F, 0x89, 0xBD, 0xC7, 0x9D, 0x91, 0x05, 0x1D, 0x9B, 0x28, + 0x16, 0xE7, 0x4F, 0xA5, 0x45, 0x31, 0xEF, 0xDC, 0x1C, 0xBE, 0x74, 0xD4, 0x48, 0x85, 0x7F, + 0x47, 0x6B, 0xCD, 0x58, 0xF2, 0x1C, 0x0B, 0x65, 0x3B, 0x3B, 0x76, 0xA4, 0xE0, 0x76, 0xA6, + 0x55, 0x9A, 0x30, 0x27, 0x18, 0x55, 0x5C, 0xC6, 0x3F, 0x74, 0x85, 0x9A, 0xAB, 0xAB, 0x92, + 0x5F, 0x02, 0x38, 0x61, 0xCA, 0x8C, 0xD0, 0xF7, 0xBA, 0xDB, 0x28, 0x71, 0xF6, 0x7D, 0x55, + 0x32, 0x6D, 0x74, 0x51, 0x13, 0x5A, 0xD4, 0x5F, 0x4A, 0x1B, 0xA6, 0x91, 0x18, 0xFB, 0xB2, + 0xC8, 0xA3, 0x0E, 0xEC, 0x93, 0x92, 0xEF, 0x3F, 0x97, 0x70, 0x66, 0xC9, 0xAD, 0xD5, 0xC7, + 0x10, 0xCC, 0x64, 0x7B, 0x15, 0x14, 0xD2, 0x17, 0xD9, 0x58, 0xC7, 0x01, 0x7C, 0x3E, 0x90, + 0xFD, 0x20, 0xC0, 0x4E, 0x67, 0x4B, 0x90, 0x48, 0x6E, 0x93, 0x70, 0xA3, 0x1A, 0x00, 0x1D, + 0x32, 0xF4, 0x73, 0x97, 0x9E, 0x49, 0x06, 0x74, 0x9E, 0x7E, 0x47, 0x7F, 0xA0, 0xB7, 0x45, + 0x08, 0xF8, 0xA5, 0xF2, 0x37, 0x83, 0x12, 0xB8, 0x3C, 0x25, 0xBD, 0x38, 0x8C, 0xA0, 0xB0, + 0xFF, 0xF7, 0x47, 0x8B, 0xAF, 0x42, 0xB7, 0x16, 0x67, 0xED, 0xAA, 0xC9, 0x7C, 0x46, 0xB1, + 0x29, 0x64, 0x3E, 0x58, 0x6E, 0x5B, 0x05, 0x5A, 0x0C, 0x21, 0x19, 0x46, 0xD4, 0xF3, 0x6E, + 0x67, 0x5B, 0xED, 0x58, 0x60, 0xFA, 0x04, 0x2A, 0x31, 0x5D, 0x98, 0x26, 0x16, 0x4D, 0x6A, + 0x92, 0x37, 0xC3, 0x5A, 0x5F, 0xBF, 0x49, 0x54, 0x90, 0xA5, 0xBD, 0x4D, 0xF2, 0x48, 0xB9, + 0x5C, 0x4A, 0xAE, 0x77, 0x84, 0xB6, 0x05, 0x67, 0x31, 0x66, 0xAC, 0x42, 0x45, 0xB5, 0xB4, + 0xB0, 0x82, 0xA0, 0x9E, 0x93, 0x23, 0xE6, 0x2F, 0x20, 0x78, 0xC5, 0xB7, 0x67, 0x83, 0x44, + 0x6D, 0xEF, 0xD7, 0x36, 0xAD, 0x3A, 0x37, 0x02, 0xD4, 0x9B, 0x08, 0x98, 0x44, 0x90, 0x0A, + 0x61, 0x83, 0x33, 0x97, 0xBC, 0x44, 0x19, 0xB3, 0x0D, 0x7A, 0x97, 0xA0, 0xB3, 0x87, 0xC1, + 0x91, 0x14, 0x74, 0xC4, 0xD4, 0x1B, 0x53, 0xE3, 0x2A, 0x97, 0x7A, 0xCB, 0x6F, 0x0E, 0xA7, + 0x5D, 0xB6, 0x5B, 0xB3, 0x9E, 0x59, 0xE7, 0x01, 0xE7, 0x69, 0x57, 0xDE, 0xF6, 0xF2, 0xD4, + 0x45, 0x59, 0xC3, 0x1A, 0x77, 0x12, 0x2B, 0x52, 0x04, 0xE3, 0xB5, 0xC2, 0x19, 0xF1, 0x68, + 0x8B, 0x14, 0xED, 0x0B, 0xC0, 0xB8, 0x01, 0xB3, 0xE6, 0xE8, 0x2D, 0xCD, 0x43, 0xE9, 0xC0, + 0xE9, 0xF4, 0x17, 0x44, 0xCD, 0x98, 0x15, 0xBD, 0x1B, 0xC8, 0x82, 0x0D, 0x8B, 0xB1, 0x23, + 0xF0, 0x4F, 0xAC, 0xD1, 0xB1, 0xB6, 0x85, 0xDD, 0x5A, 0x2B, 0x1B, 0x8D, 0xBB, 0xF3, 0xED, + 0x93, 0x36, 0x70, 0xF0, 0x95, 0xA1, 0x80, 0xB4, 0xF1, 0x92, 0xD0, 0x8B, 0x10, 0xB8, 0xFA, + 0xBB, 0xDF, 0xCC, 0x2B, 0x24, 0x51, 0x8E, 0x32, 0xEE, 0xA0, 0xA5, 0xE0, 0xC9, 0x04, 0xCA, + 0x84, 0x47, 0x80, 0x08, 0x3F, 0x3B, 0x0C, 0xD2, 0xD0, 0xB8, 0xB6, 0xAF, 0x67, 0xBC, 0x35, + 0x5B, 0x94, 0x94, 0x02, 0x5D, 0xC7, 0xB0, 0xA7, 0x8F, 0xA8, 0x0E, 0x3A, 0x2D, 0xBF, 0xEB, + 0x51, 0x32, 0x88, 0x51, 0xD6, 0x07, 0x81, 0x98, 0xE9, 0x49, 0x36, 0x51, 0xAE, 0x78, 0x7E, + 0xC0, 0x25, 0x1F, 0x92, 0x2B, 0xA3, 0x0E, 0x9F, 0x51, 0xDF, 0x62, 0xA6, 0xD7, 0x27, 0x84, + 0xCF, 0x3D, 0xD2, 0x05, 0x39, 0x31, 0x76, 0xDF, 0xA3, 0x24, 0xA5, 0x12, 0xBD, 0x94, 0x97, + 0x0A, 0x36, 0xDD, 0x34, 0xA5, 0x14, 0xA8, 0x67, 0x91, 0xF0, 0xEB, 0x36, 0xF0, 0x14, 0x5B, + 0x09, 0xAB, 0x64, 0x65, 0x1B, 0x4A, 0x03, 0x13, 0xB2, 0x99, 0x61, 0x1A, 0x2A, 0x1C, 0x48, + 0x89, 0x16, 0x27, 0x59, 0x87, 0x68, 0xA3, 0x11, 0x40, 0x60, 0xBA, 0x44, 0x43, 0x48, 0x6D, + 0xF5, 0x15, 0x22, 0xA1, 0xCE, 0x88, 0xB3, 0x09, 0x85, 0xC2, 0x16, 0xF8, 0xE6, 0xED, 0x17, + 0x8D, 0xD5, 0x67, 0xB3, 0x04, 0xA0, 0xD4, 0xCA, 0xFB, 0xA8, 0x82, 0xA2, 0x83, 0x42, 0xF1, + 0x7A, 0x9A, 0xA2, 0x6A, 0xE5, 0x8D, 0xB6, 0x30, 0x08, 0x3D, 0x2C, 0x35, 0x8F, 0xDF, 0x56, + 0x6C, 0x3F, 0x5D, 0x62, 0xA4, 0x28, 0x56, 0x7B, 0xC9, 0xEA, 0x8C, 0xE9, 0x5C, 0xAA, 0x0F, + 0x35, 0x47, 0x4B, 0x0B, 0xFA, 0x8F, 0x33, 0x9A, 0x25, 0x0A, 0xB4, 0xDF, 0xCF, 0x20, 0x83, + 0xBE, 0x8E, 0xEF, 0xBC, 0x10, 0x55, 0xE1, 0x8F, 0xE1, 0x53, 0x70, 0xEE, 0xCB, 0x26, 0x05, + 0x66, 0xD8, 0x3F, 0xF0, 0x6B, 0x21, 0x1A, 0xAE, 0xC4, 0x3C, 0xA2, 0x9B, 0x54, 0xCC, 0xD0, + 0x0F, 0x88, 0x15, 0xA2, 0x46, 0x5E, 0xF0, 0xB4, 0x65, 0x15, 0xCC, 0x7E, 0x41, 0xF3, 0x12, + 0x4F, 0x09, 0xEF, 0xFF, 0x73, 0x93, 0x09, 0xAB, 0x58, 0xB2, 0x9A, 0x14, 0x59, 0xA0, 0x0B, + 0xCE, 0x50, 0x38, 0xE9, 0x38, 0xC9, 0x67, 0x8F, 0x72, 0xEB, 0x0E, 0x4E, 0xE5, 0xFD, 0xAA, + 0xE6, 0x6D, 0x9F, 0x85, 0x73, 0xFC, 0x97, 0xFC, 0x42, 0xB4, 0x95, 0x9F, 0x4B, 0xF8, 0xB6, + 0x1D, 0x78, 0x43, 0x3E, 0x86, 0xB0, 0x33, 0x5D, 0x6E, 0x91, 0x91, 0xC4, 0xD8, 0xBF, 0x48, + 0x7B, 0x39, 0x05, 0xC1, 0x08, 0xCF, 0xD6, 0xAC, 0x24, 0xB0, 0xCE, 0xB7, 0xDC, 0xB7, 0xCF, + 0x51, 0xF8, 0x4D, 0x0E, 0xD6, 0x87, 0xB9, 0x5E, 0xAE, 0xB1, 0xC5, 0x33, 0xC0, 0x6F, 0x0D, + 0x97, 0x02, 0x3D, 0x92, 0xA7, 0x08, 0x25, 0x83, 0x7B, 0x59, 0xBA, 0x6C, 0xB7, 0xD4, 0xE5, + 0x6B, 0x0A, 0x87, 0xC2, 0x03, 0x86, 0x2A, 0xE8, 0xF3, 0x15, 0xBA, 0x59, 0x25, 0xE8, 0xED, + 0xEF, 0xA6, 0x79, 0x36, 0x9A, 0x22, 0x02, 0x76, 0x61, 0x51, 0xF1, 0x6A, 0x96, 0x5F, 0x9F, + 0x81, 0xEC, 0xE7, 0x6C, 0xC0, 0x70, 0xB5, 0x58, 0x69, 0xE4, 0xDB, 0x97, 0x84, 0xCF, 0x05, + 0xC8, 0x30, 0xB3, 0x24, 0x2C, 0x83, 0x12, + ]) + .unwrap(); + let sig: [u8; MLDSA44_SIG_LEN] = [ + 0x5E, 0x93, 0xB7, 0x85, 0xC5, 0x11, 0x9C, 0x39, 0x83, 0xA2, 0x91, 0xB1, 0x84, 0x20, 0xFD, + 0xBE, 0x4B, 0xCA, 0x53, 0xD5, 0xA3, 0x73, 0x29, 0x22, 0xFA, 0xAA, 0xCD, 0x5A, 0x5D, 0x32, + 0xA7, 0x45, 0xC7, 0x8D, 0x10, 0x5B, 0xA1, 0x0B, 0xEE, 0x1E, 0xD8, 0x06, 0x9F, 0x19, 0xE6, + 0xC5, 0x37, 0xBD, 0xA1, 0x6E, 0x89, 0xD3, 0x90, 0x04, 0xC3, 0x59, 0xD1, 0xFD, 0x38, 0x1A, + 0x02, 0x91, 0xF1, 0xC5, 0x1F, 0x1C, 0x38, 0xED, 0xCD, 0xB3, 0x15, 0xC8, 0xC6, 0x95, 0x70, + 0xD8, 0xF2, 0x5F, 0x16, 0x55, 0xBA, 0x8E, 0xA8, 0x3A, 0xFF, 0x24, 0xB8, 0xB6, 0xBE, 0x8D, + 0xE7, 0x62, 0x34, 0x2E, 0x34, 0x7E, 0xAB, 0x2C, 0xAA, 0x68, 0x03, 0xED, 0x70, 0x59, 0x52, + 0xDD, 0x64, 0x50, 0xC5, 0x18, 0x5E, 0x9D, 0x60, 0xCE, 0x96, 0xE8, 0xDC, 0xA4, 0x23, 0xA0, + 0x2F, 0x64, 0x6C, 0xEA, 0x69, 0x01, 0x64, 0xA2, 0x26, 0xE4, 0xC3, 0xD6, 0xA5, 0x15, 0xCE, + 0x16, 0x29, 0x0F, 0x19, 0xB2, 0xC6, 0x26, 0xDA, 0x9B, 0x45, 0x0E, 0xCF, 0x66, 0x50, 0x13, + 0xC5, 0xE2, 0x26, 0xB6, 0xC0, 0xAC, 0x5C, 0x07, 0xCE, 0x90, 0xE2, 0x78, 0xF1, 0xB0, 0x13, + 0x4E, 0x38, 0x5D, 0x13, 0xE7, 0x42, 0x08, 0xA0, 0xB3, 0xFF, 0x05, 0x2A, 0x36, 0x25, 0x79, + 0xF9, 0x20, 0x7E, 0xA0, 0x1F, 0x18, 0xA0, 0x39, 0xAA, 0x1B, 0x97, 0xAE, 0x34, 0x52, 0x67, + 0x5B, 0x62, 0x07, 0x71, 0xF8, 0x01, 0x2E, 0xE7, 0xA4, 0xE5, 0x5C, 0x98, 0xBF, 0xD2, 0x01, + 0x9E, 0xD8, 0xA3, 0xB0, 0x0A, 0xCE, 0xA8, 0xE8, 0xAB, 0x28, 0x17, 0x2F, 0xAA, 0x42, 0xCA, + 0x1F, 0xDA, 0x83, 0xC5, 0xFF, 0xE8, 0x1A, 0x45, 0xBE, 0x73, 0x6B, 0xDE, 0xDD, 0x5F, 0xB3, + 0x00, 0xCE, 0x17, 0x07, 0x8B, 0x38, 0x0F, 0x62, 0x0B, 0xDE, 0xEB, 0xAD, 0x69, 0x36, 0x01, + 0x37, 0x2C, 0x85, 0xEA, 0xCF, 0x79, 0xBC, 0x98, 0xE1, 0xB4, 0x8F, 0x2A, 0xD7, 0xE5, 0xDC, + 0xE4, 0x27, 0x9A, 0x12, 0x95, 0xBB, 0x2B, 0xA6, 0x0A, 0x0C, 0x5E, 0x37, 0x26, 0x64, 0x2D, + 0x23, 0x36, 0xC5, 0xEB, 0x1D, 0x37, 0xC8, 0x62, 0x3C, 0x75, 0x58, 0x24, 0x13, 0x18, 0xD8, + 0x9B, 0xC7, 0x83, 0xC4, 0xF0, 0x00, 0x98, 0x07, 0x74, 0x84, 0x62, 0x3C, 0x21, 0x75, 0x60, + 0xA0, 0xC7, 0xAA, 0xF7, 0x5D, 0xCA, 0xCC, 0xB7, 0x8E, 0xE6, 0x9C, 0x20, 0x7C, 0x27, 0xC8, + 0xBF, 0x39, 0x65, 0xCC, 0xF5, 0x8A, 0x80, 0xC8, 0x8E, 0xFC, 0xC7, 0xE5, 0xDE, 0xB3, 0x61, + 0x5D, 0x50, 0x45, 0xA7, 0x41, 0xC4, 0xDA, 0xC0, 0xA0, 0x21, 0xDD, 0x06, 0x0D, 0x31, 0x5D, + 0x4E, 0xC2, 0x85, 0x7E, 0xB6, 0x64, 0xD7, 0x28, 0xD0, 0xAF, 0x97, 0x3B, 0xEA, 0x07, 0xE1, + 0xCA, 0x56, 0x3F, 0xAA, 0x0E, 0x19, 0x99, 0x6C, 0xEA, 0x37, 0x70, 0x31, 0x6C, 0x11, 0xA5, + 0x06, 0x66, 0x65, 0x66, 0x20, 0x05, 0xAC, 0xE9, 0x8F, 0x61, 0x10, 0xE8, 0x83, 0xBA, 0xE0, + 0x60, 0xDA, 0xA7, 0xB6, 0xD8, 0x33, 0x79, 0xE0, 0x87, 0x87, 0x96, 0x69, 0x17, 0x08, 0xA3, + 0x2B, 0x85, 0x73, 0x0D, 0xE8, 0xB9, 0x2D, 0x89, 0xF9, 0x0A, 0x36, 0x60, 0xC9, 0x49, 0x16, + 0x5B, 0x14, 0x61, 0x25, 0x67, 0x66, 0x2E, 0x16, 0x22, 0x32, 0x29, 0x6C, 0xBD, 0x14, 0x35, + 0x17, 0xA2, 0x82, 0xE2, 0x2C, 0x46, 0xB6, 0x36, 0x06, 0xD3, 0xC1, 0x4E, 0xD4, 0x55, 0x9A, + 0x5A, 0x1C, 0x45, 0x9B, 0xAB, 0x7F, 0x35, 0x50, 0x07, 0xAD, 0x6F, 0x7E, 0x3B, 0x1E, 0x07, + 0x44, 0x5D, 0xFC, 0x96, 0xBD, 0x9B, 0x75, 0x08, 0x0B, 0x3D, 0x4F, 0x68, 0x99, 0x84, 0x90, + 0xA2, 0x6B, 0x5E, 0x09, 0x0B, 0xE2, 0x67, 0x40, 0x71, 0xAB, 0x92, 0x5B, 0xB6, 0x50, 0x59, + 0x08, 0x56, 0xC5, 0x9F, 0x8B, 0xA7, 0x48, 0x8D, 0x2B, 0x72, 0xF8, 0x40, 0xAC, 0x3E, 0xAF, + 0xE4, 0xDD, 0x91, 0xF0, 0xF5, 0x1C, 0x43, 0x64, 0x11, 0x2C, 0x1A, 0x13, 0x9E, 0x3E, 0x94, + 0x2A, 0x59, 0x7B, 0x93, 0xA1, 0xE3, 0xF4, 0xFA, 0xDE, 0xD1, 0x29, 0xC1, 0x4B, 0x59, 0x78, + 0xB3, 0x15, 0xE2, 0x24, 0x6A, 0x93, 0x14, 0x6A, 0x79, 0x36, 0x5F, 0x0F, 0x59, 0x7A, 0x18, + 0x34, 0x0C, 0xCA, 0x86, 0xBB, 0x15, 0xCE, 0xED, 0x39, 0xF1, 0x75, 0xEA, 0xB1, 0xE5, 0x46, + 0x53, 0x5A, 0xFB, 0x96, 0x6F, 0x0A, 0x65, 0xA8, 0xF6, 0x6F, 0x73, 0x7A, 0xB0, 0x28, 0x97, + 0xED, 0xDF, 0xE9, 0x2C, 0xF7, 0x78, 0x68, 0x94, 0x84, 0x3C, 0x26, 0x91, 0x46, 0x47, 0x76, + 0xC9, 0x4B, 0xD4, 0x50, 0xA1, 0x06, 0x91, 0x38, 0xB2, 0x6D, 0xF8, 0x3B, 0x2D, 0x1D, 0xD8, + 0x01, 0x14, 0x3A, 0x8F, 0xDF, 0xDC, 0x25, 0x14, 0xCC, 0x5B, 0x58, 0x31, 0xAB, 0x53, 0xA7, + 0x5C, 0x55, 0xEF, 0x29, 0xF4, 0x0E, 0x7C, 0x63, 0xD2, 0xC7, 0x2A, 0xBE, 0x97, 0xE2, 0xAF, + 0x14, 0x85, 0x3B, 0xE4, 0x9B, 0xE1, 0x6F, 0x47, 0x30, 0xA1, 0x59, 0x97, 0x49, 0x70, 0x95, + 0x14, 0x39, 0xE5, 0x5C, 0x15, 0x89, 0xD0, 0xF4, 0xA1, 0x62, 0xE3, 0x51, 0x7D, 0xF9, 0xD7, + 0xAB, 0xC9, 0x8D, 0x8A, 0x30, 0x72, 0x16, 0xE7, 0xF1, 0xCB, 0x46, 0x27, 0xC9, 0x17, 0x5C, + 0x0E, 0xEF, 0x23, 0x33, 0x7E, 0x56, 0xD5, 0x28, 0x1B, 0x83, 0x72, 0x6F, 0xFF, 0x40, 0xA1, + 0x48, 0xB0, 0xC4, 0x8E, 0x8D, 0xF3, 0x49, 0x6A, 0x21, 0x18, 0xD8, 0x02, 0x19, 0xAE, 0xF8, + 0xF4, 0x0B, 0x29, 0xFB, 0xA1, 0xF2, 0xF7, 0x87, 0x86, 0xB6, 0x7F, 0xFB, 0x7B, 0x7D, 0x47, + 0xD4, 0x06, 0xB7, 0x65, 0xBD, 0x13, 0x66, 0x10, 0xBE, 0xDE, 0xB9, 0x5C, 0xD7, 0x32, 0x1F, + 0x58, 0xF3, 0xB8, 0x36, 0xC9, 0x25, 0x8B, 0xE3, 0x5D, 0x78, 0xB4, 0x98, 0xF3, 0xEF, 0xE1, + 0xDB, 0x2B, 0x24, 0x3D, 0x73, 0x4F, 0xAB, 0x15, 0x9B, 0xAE, 0xD8, 0x80, 0x7C, 0x3C, 0xCC, + 0xF8, 0x3E, 0xB2, 0xEA, 0xF8, 0xA9, 0xAF, 0x01, 0xA5, 0x18, 0xD4, 0x8C, 0x60, 0xE9, 0x1A, + 0x96, 0x81, 0x2A, 0xD6, 0x89, 0xC2, 0xD8, 0x3C, 0xC4, 0xE8, 0xE9, 0xB3, 0x65, 0x04, 0x22, + 0xBE, 0xD6, 0xF1, 0x3C, 0x24, 0xAD, 0xAA, 0xD9, 0x1C, 0x95, 0xB3, 0xE3, 0xCF, 0x35, 0x4F, + 0x0F, 0x6B, 0xC9, 0xEE, 0x89, 0x41, 0xA6, 0xB1, 0x5B, 0x69, 0x75, 0x13, 0x1D, 0x95, 0x23, + 0x3D, 0x89, 0x35, 0xDE, 0x36, 0x7E, 0xFC, 0x6D, 0x86, 0xA4, 0x5D, 0xAC, 0x7D, 0x0F, 0x1D, + 0xDD, 0x9A, 0xEB, 0xD2, 0xC5, 0x9C, 0x02, 0x7F, 0xCD, 0xA4, 0x48, 0x80, 0x1E, 0x93, 0xE7, + 0x33, 0xAC, 0xA5, 0x18, 0x74, 0xBE, 0x9A, 0xB9, 0x27, 0xA9, 0x04, 0xF9, 0x6D, 0xDB, 0x7A, + 0x46, 0xB2, 0xDA, 0x13, 0x26, 0x1D, 0x52, 0x2B, 0x23, 0xC9, 0x50, 0xC0, 0x1D, 0x5F, 0x5E, + 0x11, 0x2B, 0x76, 0xF8, 0x51, 0xFF, 0x23, 0x4F, 0x06, 0xF8, 0xD5, 0xE6, 0x5B, 0x13, 0x19, + 0xAB, 0xCD, 0x79, 0xA1, 0x80, 0xAE, 0x06, 0x3D, 0x65, 0xB2, 0x8C, 0x74, 0x58, 0x78, 0xC0, + 0x6D, 0xBB, 0x69, 0xBA, 0x73, 0x29, 0x3E, 0xAB, 0x34, 0x43, 0x4B, 0xF1, 0xA9, 0x2F, 0xBA, + 0x69, 0x19, 0x93, 0xBD, 0x0F, 0xF3, 0xED, 0xAC, 0x76, 0xA1, 0x2F, 0x80, 0xC0, 0xAD, 0xA4, + 0xB1, 0x96, 0x9C, 0x76, 0x65, 0x58, 0x9D, 0x53, 0x0A, 0x67, 0x01, 0x6A, 0x62, 0x54, 0x03, + 0xC5, 0x37, 0x03, 0x29, 0x04, 0xF2, 0xE1, 0x04, 0x54, 0x7C, 0xD3, 0xEA, 0x40, 0x62, 0x60, + 0xDD, 0x35, 0x7F, 0xA0, 0x6E, 0xA0, 0x12, 0xA7, 0x85, 0x82, 0x6C, 0x16, 0x0E, 0x99, 0xFF, + 0xD0, 0x65, 0xB0, 0xE3, 0xF3, 0x3C, 0x76, 0x89, 0xD3, 0x55, 0x2A, 0xB9, 0xE2, 0xE0, 0x9F, + 0xA7, 0xE5, 0x5B, 0xBC, 0xEF, 0x04, 0x22, 0x42, 0xBC, 0xAC, 0xAD, 0x8A, 0x3D, 0xA4, 0x7B, + 0xCC, 0x54, 0xA1, 0x21, 0xF1, 0x52, 0x6C, 0x8C, 0xD4, 0xCC, 0x5A, 0x89, 0x2A, 0x81, 0x31, + 0xCF, 0x4E, 0xEF, 0xAF, 0x42, 0x48, 0xDD, 0xD6, 0xA1, 0x1E, 0xC4, 0x27, 0xBA, 0x37, 0x8A, + 0xAE, 0x89, 0xAA, 0xF5, 0x82, 0xCE, 0x1F, 0x4E, 0x32, 0x69, 0x0A, 0x55, 0x5E, 0x74, 0x07, + 0x61, 0xD3, 0x58, 0xAD, 0x4E, 0x92, 0xBC, 0x38, 0x41, 0x8A, 0xA7, 0x82, 0xDA, 0x91, 0x65, + 0x24, 0xFB, 0x09, 0xAB, 0x2C, 0xA6, 0xB3, 0xD3, 0x11, 0x3D, 0x6F, 0x2C, 0x2A, 0x6A, 0x9B, + 0x9D, 0x29, 0xD4, 0xE7, 0x48, 0x92, 0x55, 0x25, 0x2A, 0xF0, 0x75, 0xCB, 0xF9, 0xFE, 0xAC, + 0xED, 0xAE, 0x6F, 0x3E, 0xC0, 0xB0, 0x70, 0x82, 0x46, 0x89, 0xDD, 0x3C, 0x78, 0xAC, 0x14, + 0x3E, 0xD6, 0x77, 0x6D, 0x95, 0xDD, 0x8F, 0x13, 0xD4, 0x35, 0xA2, 0x90, 0xBD, 0xCA, 0x4C, + 0x11, 0x31, 0x8E, 0x5A, 0xCC, 0xE0, 0x44, 0x69, 0x64, 0x4E, 0x13, 0x74, 0xA9, 0x45, 0x1B, + 0x62, 0x04, 0xF3, 0xB3, 0x96, 0x1B, 0x7D, 0xD2, 0x39, 0xE3, 0x06, 0xFE, 0xF5, 0xF4, 0xF4, + 0xE5, 0x1B, 0x78, 0xB0, 0xFB, 0x9D, 0xCE, 0xE6, 0x9C, 0x3E, 0x79, 0x0B, 0x23, 0x1F, 0x2E, + 0x65, 0xFD, 0x1A, 0xB1, 0xC2, 0xA7, 0x5B, 0x07, 0x06, 0x7D, 0x5C, 0x16, 0xDD, 0xE0, 0x09, + 0x83, 0xA5, 0x8F, 0xFC, 0xDA, 0xAA, 0xEE, 0x16, 0xD2, 0x74, 0x2E, 0x13, 0x3E, 0xD7, 0x37, + 0xB4, 0x80, 0x64, 0xC8, 0xA3, 0x8E, 0xCA, 0x35, 0xAB, 0x3F, 0xA1, 0x8F, 0x6D, 0x62, 0xF6, + 0x42, 0xB1, 0x2C, 0xFD, 0xC7, 0x98, 0x0F, 0x2A, 0xB7, 0xDB, 0x32, 0x1F, 0xEC, 0x9D, 0xCF, + 0xE4, 0x99, 0xB4, 0xFC, 0x1E, 0xE7, 0xEB, 0x29, 0x79, 0x54, 0x05, 0x66, 0x17, 0xC6, 0x0A, + 0x66, 0x40, 0xB9, 0x28, 0x35, 0xD1, 0x65, 0xC3, 0xC0, 0x0A, 0x95, 0x19, 0x52, 0x61, 0x44, + 0x88, 0xD5, 0x65, 0x7B, 0xA0, 0xB5, 0xE9, 0x0A, 0xE9, 0xE0, 0xEF, 0x7B, 0x3B, 0x9E, 0xCA, + 0xEB, 0xD8, 0x1B, 0x85, 0x51, 0xB6, 0xD7, 0x0E, 0x83, 0x5B, 0x27, 0x34, 0x76, 0x16, 0x39, + 0xD4, 0x2E, 0x76, 0xFF, 0xC5, 0xB3, 0x27, 0x2B, 0x61, 0xC8, 0x96, 0xB4, 0x5B, 0x4B, 0xD1, + 0x8F, 0x30, 0xE5, 0x8C, 0x44, 0x06, 0x43, 0xBA, 0x15, 0x92, 0x21, 0xCC, 0x67, 0x39, 0xA1, + 0x9A, 0x65, 0xF2, 0x91, 0x1F, 0xAE, 0x47, 0xB0, 0xD4, 0xCA, 0xC4, 0x20, 0x0A, 0x6F, 0x04, + 0x3B, 0x17, 0xA0, 0x3A, 0xD3, 0x93, 0xEC, 0xB8, 0x23, 0xED, 0x03, 0xC8, 0xB6, 0xCD, 0x68, + 0x16, 0x7E, 0x6C, 0x82, 0x34, 0xF7, 0x43, 0x25, 0x57, 0xDB, 0x27, 0x20, 0x79, 0xEE, 0x89, + 0x9A, 0xED, 0xE7, 0x3B, 0x6B, 0x98, 0xD6, 0x00, 0x3F, 0x45, 0x78, 0x9A, 0x14, 0x1B, 0x60, + 0xD6, 0xDB, 0x40, 0xCD, 0x2A, 0x59, 0x74, 0x57, 0x1A, 0x4A, 0xD3, 0x66, 0x7B, 0x88, 0x93, + 0x18, 0xBA, 0x60, 0x28, 0x5D, 0x90, 0x3A, 0x2E, 0xAC, 0x01, 0xC2, 0x16, 0x08, 0x83, 0x8C, + 0x40, 0x90, 0x7D, 0xE6, 0xBB, 0xAB, 0xE0, 0x42, 0xCF, 0x2E, 0xCD, 0xD9, 0x7F, 0x54, 0x9F, + 0x95, 0xEC, 0x69, 0x8D, 0x79, 0x22, 0x2C, 0x65, 0xBA, 0x27, 0xC3, 0x0D, 0x33, 0x2A, 0x68, + 0xD0, 0x57, 0xAE, 0xCD, 0xC9, 0x38, 0x8A, 0xA3, 0x43, 0x20, 0xE0, 0xAA, 0x74, 0xFD, 0xBD, + 0x4D, 0x1B, 0x64, 0x3C, 0xAC, 0xE2, 0x16, 0xB6, 0xD8, 0xAD, 0x8F, 0x07, 0xA9, 0x99, 0x55, + 0xBF, 0xDB, 0x74, 0x3A, 0x86, 0xB4, 0x0F, 0xC6, 0x15, 0x27, 0xBA, 0xCA, 0x43, 0x4A, 0xC2, + 0xA7, 0xFB, 0xEA, 0xA7, 0x71, 0x11, 0xDC, 0x80, 0x98, 0xB1, 0x7E, 0x80, 0x0F, 0x59, 0xDD, + 0x77, 0xCC, 0xB0, 0xE6, 0x77, 0x07, 0xE6, 0x01, 0x23, 0xD3, 0x34, 0xE0, 0x73, 0xA2, 0xF5, + 0xA1, 0x6F, 0xFB, 0xCD, 0x70, 0x13, 0x89, 0xAD, 0xD5, 0x7C, 0x3C, 0xEC, 0xCB, 0x88, 0xB2, + 0x86, 0xAC, 0x1E, 0x6E, 0x3E, 0x64, 0x85, 0xAF, 0x1A, 0x12, 0xEA, 0x24, 0x1D, 0x14, 0xA1, + 0xB5, 0x00, 0x3D, 0x7F, 0x3B, 0xC9, 0xE9, 0x57, 0xD4, 0x48, 0x3C, 0x0F, 0x9F, 0x70, 0x3B, + 0x3A, 0x18, 0x7D, 0x55, 0xE5, 0x05, 0x81, 0x76, 0x15, 0xFB, 0xC4, 0xAE, 0x08, 0x37, 0x61, + 0x61, 0x84, 0x24, 0x5C, 0xFB, 0xA6, 0x1C, 0xE3, 0xB9, 0x29, 0xE3, 0x3F, 0x52, 0xB7, 0x1C, + 0xDD, 0x7B, 0x6A, 0x0D, 0xA5, 0x5C, 0x1F, 0x99, 0x75, 0x10, 0xB1, 0xA9, 0x00, 0x2C, 0xA4, + 0xE0, 0x67, 0x83, 0x73, 0xA3, 0xB1, 0xAB, 0x28, 0x97, 0xE6, 0xB4, 0x23, 0xF1, 0x5A, 0x44, + 0x0A, 0x63, 0x6C, 0xC8, 0x61, 0x49, 0x1E, 0xF4, 0x1A, 0xD0, 0xAA, 0x62, 0x7D, 0x8E, 0x19, + 0x8A, 0x5E, 0xE7, 0xBD, 0x7B, 0x6C, 0xB2, 0xC9, 0xCE, 0x2A, 0x8C, 0xC0, 0x15, 0xF0, 0xD2, + 0x06, 0xDE, 0x4C, 0x49, 0xE2, 0xF8, 0x7F, 0x31, 0x09, 0x54, 0xA1, 0x0D, 0x86, 0xE2, 0x94, + 0xF7, 0x42, 0xEE, 0x18, 0x6F, 0x4A, 0xE9, 0x81, 0x5F, 0x69, 0x96, 0x22, 0x79, 0x22, 0x06, + 0xCA, 0xFB, 0xA8, 0xF5, 0x62, 0x17, 0x38, 0x16, 0x0E, 0x6C, 0x5D, 0x61, 0x1A, 0x82, 0x52, + 0xC6, 0xF3, 0x50, 0x85, 0xB6, 0x04, 0xEF, 0x89, 0x51, 0x64, 0xD4, 0xEA, 0x6D, 0xDD, 0x31, + 0x0C, 0x7D, 0x8F, 0x0C, 0x87, 0x9F, 0xB1, 0xF8, 0x84, 0xC5, 0x74, 0x1D, 0x09, 0x6B, 0x3D, + 0x2D, 0xA0, 0xCE, 0x11, 0x51, 0x79, 0x0D, 0xDA, 0x88, 0x1D, 0x18, 0xCB, 0x6B, 0x19, 0xA9, + 0xFE, 0xD6, 0xF5, 0x25, 0x4B, 0x7D, 0x52, 0xD5, 0xD9, 0x2B, 0xBB, 0xE2, 0x4C, 0x9D, 0x6A, + 0x65, 0x60, 0x4A, 0x0B, 0x8E, 0xD2, 0x4A, 0xD5, 0xC1, 0x97, 0xD6, 0x83, 0xF5, 0x98, 0x74, + 0x3C, 0x96, 0xB5, 0x96, 0x0E, 0x87, 0x23, 0x73, 0x2B, 0x5B, 0xD6, 0x47, 0xE9, 0xDB, 0xEA, + 0xA8, 0x51, 0xD0, 0xE1, 0xCF, 0x6D, 0x2C, 0x07, 0x0D, 0x44, 0x42, 0x76, 0x2C, 0x28, 0x09, + 0x8C, 0x5C, 0xF5, 0xA5, 0x4B, 0x2B, 0x5E, 0x69, 0xA9, 0x9B, 0x10, 0x81, 0x5B, 0xF0, 0xF4, + 0x77, 0xBB, 0x71, 0xF0, 0xD5, 0xD3, 0xA6, 0x2B, 0xA2, 0xB3, 0xE2, 0x9B, 0xF8, 0x4D, 0x4B, + 0x4E, 0x57, 0x47, 0x07, 0xF5, 0xF7, 0x4A, 0xF7, 0x04, 0xD2, 0x77, 0xBD, 0x6C, 0xA3, 0x8D, + 0xA2, 0x1E, 0x2C, 0xDA, 0xC5, 0x49, 0xE5, 0xEA, 0xE1, 0xDE, 0x7A, 0x18, 0xEE, 0x53, 0x4C, + 0x8C, 0x22, 0x91, 0xC9, 0x08, 0xCA, 0xAB, 0xF1, 0x59, 0xE9, 0x0E, 0x65, 0x49, 0xDB, 0x94, + 0xBA, 0x7A, 0x3F, 0x3D, 0x97, 0xDD, 0x39, 0x8A, 0x75, 0xDF, 0x5B, 0x1A, 0x7C, 0xDF, 0xB2, + 0x54, 0x10, 0xB7, 0xEF, 0xC4, 0xED, 0x00, 0xD9, 0x99, 0x5B, 0x37, 0xB5, 0x8B, 0xF9, 0x1E, + 0xD7, 0xA3, 0x51, 0x0C, 0xFF, 0xEA, 0x82, 0xF9, 0xE1, 0xC2, 0xA3, 0x29, 0x04, 0x06, 0x00, + 0x4D, 0x09, 0x05, 0x7D, 0x63, 0xB7, 0x70, 0xFA, 0x0E, 0x53, 0x10, 0x31, 0x99, 0x54, 0x4E, + 0xBA, 0x66, 0x2A, 0x2C, 0x30, 0x2C, 0xF3, 0x90, 0x08, 0xF1, 0x42, 0xD2, 0xB1, 0x69, 0x63, + 0xE9, 0x5A, 0xB1, 0x0B, 0xE7, 0xC2, 0x61, 0x01, 0x68, 0x60, 0x8F, 0x35, 0x3A, 0x2F, 0x2C, + 0x41, 0xC7, 0x05, 0x6D, 0xEC, 0x1A, 0x8C, 0x7A, 0x6B, 0xFA, 0x00, 0x27, 0xF9, 0xDE, 0xDA, + 0xCB, 0x77, 0x86, 0xB6, 0x7E, 0xA2, 0xC4, 0x94, 0xD4, 0x3B, 0xA8, 0x51, 0xCF, 0x94, 0x15, + 0xC1, 0xBC, 0xC5, 0x2F, 0x02, 0x7E, 0xC0, 0x2C, 0x65, 0x53, 0x4F, 0x60, 0x8E, 0x9D, 0x16, + 0x6D, 0x51, 0xDD, 0x43, 0x1C, 0xDF, 0x58, 0x71, 0xF5, 0xCD, 0xD1, 0x57, 0x9C, 0xC0, 0x60, + 0x79, 0xDF, 0x07, 0x5A, 0x25, 0x06, 0x2B, 0xA7, 0xE7, 0x0D, 0x96, 0x66, 0xC4, 0xE7, 0xFE, + 0xD3, 0x4C, 0xEA, 0x0E, 0xA0, 0xF1, 0x1A, 0xDE, 0x1E, 0xB2, 0xA9, 0xB3, 0x97, 0xBC, 0xAA, + 0xAD, 0x10, 0x61, 0x27, 0x0E, 0xCF, 0x49, 0x78, 0x03, 0xA5, 0xFC, 0xE7, 0xF4, 0x1E, 0x65, + 0x04, 0xFB, 0xEC, 0x71, 0xA7, 0xDE, 0x7D, 0x06, 0x6B, 0x82, 0x61, 0x86, 0x8A, 0xFC, 0x49, + 0xB9, 0xE6, 0x85, 0xF0, 0xDC, 0xCE, 0x75, 0xE2, 0xFC, 0xB3, 0xBA, 0x8C, 0xF1, 0x90, 0x57, + 0xE3, 0x94, 0x15, 0x76, 0xBA, 0xF5, 0x8F, 0xB8, 0x21, 0xBD, 0x42, 0x68, 0xF7, 0xFA, 0xE3, + 0x02, 0x86, 0x01, 0xDA, 0x02, 0x2E, 0x9B, 0x46, 0x86, 0x46, 0xAB, 0xDB, 0x4F, 0xA6, 0x09, + 0x8A, 0x44, 0x9B, 0x42, 0x67, 0xD5, 0x09, 0xD9, 0xA3, 0x3F, 0x4C, 0x3E, 0xBC, 0xC3, 0x2D, + 0xAC, 0x09, 0x4D, 0x48, 0xED, 0x60, 0x0E, 0x76, 0x57, 0x87, 0xFB, 0x92, 0xB1, 0x97, 0x4F, + 0x74, 0xF7, 0xBB, 0x4C, 0x66, 0xEB, 0x2B, 0xBD, 0x02, 0x89, 0x5E, 0x6A, 0x38, 0x1C, 0x1C, + 0x45, 0x2E, 0xAA, 0xB1, 0xAE, 0x47, 0x31, 0xCF, 0x63, 0x2F, 0x61, 0xAE, 0x2C, 0x90, 0x59, + 0x21, 0x17, 0x4A, 0x3B, 0xC9, 0xBB, 0x4C, 0xDC, 0x89, 0xD6, 0x30, 0x26, 0x4B, 0x61, 0x49, + 0x88, 0xF3, 0xAB, 0xBE, 0xA1, 0xBD, 0x61, 0x7F, 0xFA, 0x53, 0xD7, 0x1B, 0x7D, 0x8A, 0x37, + 0x14, 0x62, 0xB7, 0x73, 0x35, 0x1A, 0x2D, 0xCC, 0xAE, 0xDD, 0x7F, 0x59, 0xCD, 0x72, 0x8F, + 0xAD, 0xEE, 0x05, 0x90, 0x67, 0xBD, 0x80, 0xC9, 0x4C, 0x8C, 0x9A, 0x1F, 0xFC, 0xA2, 0xDC, + 0x4F, 0x84, 0x8B, 0x82, 0x9C, 0x05, 0x61, 0x38, 0x5A, 0xA8, 0x2C, 0xC9, 0x85, 0x03, 0xD0, + 0xBB, 0x66, 0xA6, 0xAA, 0x4F, 0xAE, 0x07, 0x03, 0xD1, 0x2E, 0x60, 0xE1, 0x46, 0x0E, 0xFB, + 0xBC, 0xDF, 0x24, 0x12, 0xC1, 0x3E, 0x7C, 0x68, 0x4D, 0x1B, 0x01, 0x10, 0x20, 0x26, 0x34, + 0x3A, 0x41, 0x43, 0x44, 0x58, 0x5F, 0x6E, 0x70, 0x72, 0x74, 0x8B, 0xAE, 0xB5, 0xBB, 0xC6, + 0xD1, 0xE2, 0xEF, 0xFB, 0xFE, 0x06, 0x0E, 0x2E, 0x3E, 0x51, 0x60, 0x79, 0x7C, 0x9E, 0xA6, + 0xBA, 0xC7, 0xF1, 0x10, 0x24, 0x40, 0x4A, 0x52, 0x57, 0x5F, 0x6C, 0x89, 0x8C, 0x97, 0xAA, + 0xB2, 0xC3, 0xCC, 0xEA, 0xF2, 0x2F, 0x3F, 0x53, 0x5F, 0x7B, 0x81, 0x83, 0x96, 0xA1, 0xB1, + 0xBC, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x25, 0x36, 0x42, + ]; if MLDSA44::verify(&pk, msg, None, &sig).is_ok() { println!("Verification succeeded!"); @@ -360,8 +1717,8 @@ fn bench_mldsa44_lowmemory_verify() { } fn bench_mldsa65_verify() { - use bouncycastle::mldsa::{MLDSATrait, MLDSA65, MLDSA65_SIG_LEN, MLDSA65PublicKey}; use bouncycastle::hex; + use bouncycastle::mldsa::{MLDSA65, MLDSA65_SIG_LEN, MLDSA65PublicKey, MLDSATrait}; eprintln!("MLDSA65/Verify"); @@ -381,7 +1738,140 @@ fn bench_mldsa65_verify() { // let sig = MLDSA65::sign_mu_deterministic(&mldsa65_sk, &mu, [0u8; 32]).unwrap(); // eprintln!("sig:\n{}", &*hex::encode(sig)); - let mldsa65_pk = MLDSA65PublicKey::from_bytes(&[0x48,0x68,0x3d,0x91,0x97,0x8e,0x31,0xeb,0x3d,0xdd,0xb8,0xb0,0x47,0x34,0x82,0xd2,0xb8,0x8a,0x5f,0x62,0x59,0x49,0xfd,0x8f,0x58,0xa5,0x61,0xe6,0x96,0xbd,0x4c,0x27,0xd0,0x5b,0x38,0xdb,0xb2,0xed,0xf0,0x1e,0x66,0x4e,0xfd,0x81,0xbe,0x1e,0xa8,0x93,0x68,0x8c,0xe6,0x8a,0xa2,0xd5,0x1c,0x59,0x58,0xf8,0xbb,0xc6,0xeb,0x4e,0x89,0xee,0x67,0xd2,0xc0,0x32,0x09,0x54,0xd5,0x72,0x12,0xca,0xc7,0x22,0x9f,0xf1,0xd6,0xea,0xf0,0x39,0x28,0xbd,0x51,0x51,0x1f,0x8d,0x88,0xd8,0x47,0x73,0x6c,0x7d,0xe2,0x73,0x0d,0x59,0x78,0xe5,0x41,0x07,0x13,0x16,0x09,0x78,0x86,0x77,0x11,0xbf,0x55,0x39,0xa0,0xbf,0xc4,0xc3,0x50,0xc2,0xbe,0x57,0x2b,0xaf,0x0e,0xe2,0xe2,0xfb,0x16,0xcc,0xfe,0xa0,0x80,0x28,0xd9,0x9a,0xc4,0x9a,0xeb,0xb7,0x59,0x37,0xdd,0xce,0x11,0x1c,0xda,0xb6,0x2f,0xff,0x3c,0xea,0x8b,0xa2,0x23,0x3d,0x1e,0x56,0xfb,0xc5,0xc5,0xa1,0xe7,0x26,0xde,0x63,0xfa,0xdd,0x2a,0xf0,0x16,0xb1,0x19,0x17,0x7f,0xa3,0xd9,0x71,0xa2,0xd9,0x27,0x71,0x73,0xfc,0xe5,0x5b,0x67,0x74,0x5a,0xf0,0xb7,0xc2,0x1d,0x59,0x7d,0xbe,0xb9,0x3e,0x6a,0x32,0xf3,0x41,0xc4,0x9a,0x5a,0x8b,0xe9,0xe8,0x25,0x08,0x8d,0x1f,0x2a,0xa4,0x51,0x55,0xd6,0xc8,0xae,0x15,0x36,0x7e,0x4e,0xb0,0x03,0xb8,0xfd,0xf7,0x85,0x10,0x71,0x94,0x97,0x39,0xf9,0xff,0xf0,0x90,0x23,0xea,0xf4,0x51,0x04,0xd2,0xa8,0x4a,0x45,0x90,0x6e,0xed,0x46,0x71,0xa4,0x4d,0xc2,0x8d,0x27,0x98,0x7b,0xb5,0x5d,0xf6,0x9e,0x9e,0x85,0x61,0xf6,0x1a,0x80,0xa7,0x26,0x99,0x50,0x38,0x65,0xfe,0xd9,0xb7,0xee,0x72,0xa8,0xe1,0x7a,0x19,0xc4,0x08,0x14,0x4f,0x4b,0x29,0xaf,0xef,0x70,0x31,0xc3,0xa6,0xd8,0x57,0x16,0x10,0xb4,0x2c,0x9f,0x42,0x12,0x45,0xa8,0x8f,0x19,0x7e,0x16,0x81,0x2b,0x03,0x11,0x59,0xb6,0x5b,0x96,0x87,0xe5,0xb3,0xe9,0x34,0xc5,0x22,0x5a,0xe9,0x8a,0x79,0xba,0x73,0xd2,0xb3,0x99,0xd7,0x35,0x10,0xef,0xfa,0xd1,0x9e,0x53,0xb8,0x45,0x0f,0x0b,0xa8,0xfc,0xe1,0x01,0x2f,0xd9,0x8d,0x26,0x0a,0x74,0xaa,0xaa,0x13,0xfa,0xe2,0x49,0xa0,0x06,0xb1,0xc3,0x4f,0x5b,0xa0,0xb8,0x82,0xf2,0x63,0x78,0x22,0x2f,0xb3,0x6f,0x22,0x83,0xc2,0x43,0xf0,0xff,0xeb,0x5f,0x1b,0xb4,0x14,0xa0,0xa7,0x0d,0x55,0xe3,0xd4,0x0a,0x56,0xb6,0xcb,0xc8,0x8a,0xe1,0xf0,0x3b,0x7b,0x28,0x82,0xd9,0x8d,0xee,0xa2,0x8e,0x14,0x5c,0x9d,0xed,0xfd,0x8e,0xaf,0x1c,0xef,0x2e,0xd9,0x4a,0x8b,0x05,0x0f,0x89,0x64,0xf4,0x6d,0x1e,0xa0,0xd0,0xc2,0xa4,0x3e,0x0d,0xda,0x61,0x82,0xad,0xbf,0x4f,0x6e,0xd1,0x75,0xb6,0x74,0x22,0x57,0x85,0x9b,0xf2,0x2f,0x3a,0x41,0x7e,0xcf,0x1f,0x9d,0x89,0x31,0x7b,0x5e,0x53,0x9d,0x58,0x7a,0xf1,0x6b,0x9e,0x13,0x13,0xe0,0x45,0x14,0xff,0xa6,0x4b,0xa8,0xb3,0xff,0x2b,0x83,0x21,0xf8,0x81,0x1c,0xb3,0xfb,0x02,0x2c,0x8f,0x64,0x4e,0x70,0xa4,0xb8,0x0a,0x2f,0xbf,0xee,0x60,0x4a,0xbb,0x73,0x79,0x09,0x1e,0xa8,0xe6,0xc5,0xc7,0x4d,0xfc,0x02,0x83,0x66,0x6b,0x40,0xc0,0x79,0x38,0x70,0x02,0x82,0x04,0xa1,0x36,0xbf,0x5d,0xa9,0x56,0x8e,0xb7,0x98,0xd3,0x49,0x03,0x8b,0xdb,0x0c,0x11,0xe0,0x34,0x45,0xe7,0x84,0x7c,0xb5,0x06,0x9c,0x75,0xcf,0x28,0xac,0x60,0x1c,0x77,0x99,0xd9,0x58,0x21,0x0d,0xdb,0xcb,0x22,0x6e,0x51,0xaf,0xef,0x9f,0x1d,0xe4,0x7b,0x07,0x38,0x73,0xd6,0xd3,0xf9,0x74,0x56,0xbe,0xde,0x08,0x50,0x82,0xe7,0x4a,0x29,0x8b,0x2c,0xd4,0x8f,0x4b,0x30,0x93,0x15,0x5f,0x36,0x6c,0x8f,0xa6,0x01,0xc6,0xaf,0x85,0x8d,0xfa,0x32,0xc0,0x84,0x91,0xb2,0xa2,0x98,0x87,0xf9,0x03,0x35,0x94,0x9a,0x5d,0x6e,0xda,0xa6,0x79,0x88,0x2a,0x3a,0x95,0xd6,0xbf,0x6d,0x97,0x0a,0x22,0x1f,0x4b,0x9d,0x3d,0x8c,0xbf,0x38,0x4a,0xf8,0x1a,0xac,0x95,0xe2,0xb3,0x29,0x4e,0x04,0x78,0x9a,0xc8,0x37,0x27,0xa5,0xdc,0x04,0x55,0x9f,0x96,0xaf,0x41,0xd8,0xa0,0x53,0x51,0x6f,0xee,0xee,0xbc,0x52,0x74,0x6e,0xb6,0xab,0x28,0x19,0xe0,0x91,0x08,0x71,0x0d,0x83,0x5f,0x01,0x1f,0xa6,0x30,0x65,0x87,0x2a,0xd3,0x34,0xd5,0xcd,0xff,0xb2,0xb2,0x31,0x05,0x07,0xe9,0x2f,0xc9,0x93,0xae,0x31,0x7d,0xa9,0x7f,0x4f,0x30,0x9c,0xda,0xf0,0xf6,0x7e,0xd9,0x9d,0x90,0x21,0x55,0x76,0x08,0x38,0x49,0xf9,0x53,0xb2,0x46,0xd7,0xfe,0xdb,0x3f,0xdb,0x67,0x67,0x98,0x50,0xa5,0xad,0x40,0x4e,0x64,0x14,0x7f,0xb7,0xcf,0x4f,0x6a,0xed,0xdd,0x05,0xaf,0xb4,0xb8,0x34,0x96,0x8d,0x1f,0xe8,0x80,0x14,0x96,0x0d,0xce,0x5d,0x94,0x22,0x36,0x52,0x6e,0x12,0xa4,0x78,0xd6,0x9e,0x5f,0xbe,0x69,0x70,0x31,0x0b,0x30,0x8c,0x06,0x84,0x50,0x18,0xcf,0xc7,0xb2,0xab,0x43,0x0a,0x13,0xa6,0xb1,0xac,0x7b,0xb0,0x2c,0xcc,0xbb,0x3d,0x91,0x1a,0xc2,0xf1,0x10,0x68,0x61,0x3f,0xbe,0x02,0x9b,0xfd,0xce,0x02,0xcf,0x5c,0xd3,0x89,0x50,0xed,0x72,0xc8,0x39,0x44,0xed,0xfb,0xc7,0x56,0x15,0xaf,0x87,0xf8,0x64,0xc0,0x51,0xf3,0xc5,0x54,0x56,0xc5,0x41,0x28,0x63,0xa4,0x0c,0x06,0xd1,0xda,0xb5,0x62,0xbd,0xff,0x05,0x71,0xb8,0xd3,0xc3,0x91,0x7b,0xbd,0x30,0x08,0x80,0xbb,0xa5,0xe9,0x98,0x23,0x9b,0x95,0xfa,0x91,0xb7,0xd6,0x41,0x6d,0x4f,0x39,0x8b,0x3a,0xdb,0xcd,0x30,0x98,0x3e,0xd3,0x59,0x2b,0x4d,0x9e,0xf7,0xd4,0x23,0x6f,0xd0,0x0f,0x50,0xd9,0x8a,0xa5,0x3a,0x23,0x5a,0xc4,0x17,0x27,0x20,0xf7,0x7d,0x96,0x17,0x26,0x72,0x98,0x0c,0xfe,0x8f,0xf7,0xa5,0xa7,0x02,0x78,0x3e,0xdc,0x2b,0xa3,0x1b,0x22,0x59,0x01,0x5a,0x11,0x2f,0xc7,0xf4,0x68,0xa9,0xc2,0xf9,0x46,0x40,0x39,0x00,0x2d,0x30,0xef,0x67,0x8b,0x4c,0xb7,0x98,0xbc,0x11,0x62,0x16,0xbf,0x7a,0x9a,0x7c,0x18,0xba,0x03,0xb7,0xb5,0x8f,0xd0,0x75,0x15,0xd3,0x11,0x50,0x49,0xd3,0x61,0x4b,0xe7,0xa0,0x7e,0x74,0x43,0x00,0x75,0x0d,0xf1,0xd2,0xc5,0x87,0x53,0x38,0x90,0x59,0xea,0xfc,0x3d,0x78,0x5c,0xcd,0xd3,0x1c,0x07,0x64,0x8b,0xed,0xc0,0x3a,0x5c,0x3b,0x8a,0xd4,0x6d,0x06,0x4d,0x59,0xc1,0x3d,0x57,0x37,0x47,0x29,0xfc,0x4e,0x29,0x53,0x62,0xe2,0xa5,0x19,0x12,0x04,0x53,0x04,0x28,0xbc,0x15,0x22,0xaf,0xa2,0x8f,0xf5,0xfe,0x16,0x55,0xe3,0x04,0xca,0x5b,0xc8,0xc2,0x7a,0xd0,0xe0,0xc6,0xa3,0x9d,0xd4,0xdf,0x28,0x95,0x6c,0x14,0xb3,0x8c,0xc9,0x36,0x82,0xce,0xfe,0x40,0x2b,0xbd,0x5e,0x82,0xd2,0x9c,0x46,0x4e,0x44,0xeb,0x5d,0x37,0xb4,0x8f,0xc5,0x68,0xdf,0xe0,0xcc,0x6e,0x8e,0x16,0xba,0xea,0x05,0xe5,0x13,0x55,0x90,0xf1,0x92,0x94,0xe7,0x3e,0x83,0x67,0xb0,0x21,0x6d,0xbb,0x81,0x50,0x30,0xb9,0xde,0x55,0x91,0x3f,0x08,0x03,0x9c,0x42,0x35,0x1c,0x59,0xe5,0x51,0x5d,0xd5,0xaf,0x8e,0x08,0x9a,0x15,0xe6,0x25,0xe8,0xf6,0xde,0xe6,0x39,0x38,0x6c,0x46,0x49,0x7d,0x7a,0x26,0x32,0x88,0x77,0x4d,0xe5,0x81,0xa7,0xde,0x96,0x29,0xb4,0x1b,0x44,0x24,0x14,0x1f,0x97,0x8f,0xb8,0x33,0x12,0x08,0xef,0xde,0xc3,0xc6,0xe0,0xde,0x39,0xbc,0x57,0x06,0x3f,0x3d,0xcd,0x6c,0x47,0x03,0x73,0xc0,0x88,0x91,0xea,0x29,0xcb,0xc7,0xcc,0x6d,0x64,0x83,0xb8,0x88,0x90,0x83,0xac,0xe8,0x6a,0xa7,0xb5,0x1b,0x1c,0x2c,0xfe,0x6e,0x2a,0xd1,0x8d,0x97,0xce,0x36,0xfb,0xc5,0x6e,0xa4,0x2f,0xae,0x97,0xe6,0xa7,0xac,0x11,0x48,0x64,0x47,0x8c,0x36,0x6d,0xf1,0xeb,0xb1,0xe7,0xb1,0x1a,0x90,0x98,0x50,0x4f,0xd5,0x97,0x5b,0xdf,0x1f,0x49,0xdc,0x70,0x00,0x2b,0x63,0xc1,0x73,0x9a,0x9d,0x26,0x3f,0xba,0xd4,0x07,0x3f,0x6a,0x9f,0x6c,0x2b,0x8a,0xf4,0xb4,0xc3,0x32,0xa1,0x03,0xa0,0xcf,0xfa,0x5d,0xee,0xb2,0xd0,0x62,0xca,0x3c,0x21,0x5f,0xd3,0x60,0x02,0x6b,0xe7,0xc5,0x16,0x4f,0x4a,0x44,0x24,0xef,0x74,0x94,0x88,0x04,0xd6,0x6f,0x46,0x48,0x77,0x32,0xc8,0x20,0x2c,0x79,0x54,0x78,0x64,0x7b,0x4e,0xa7,0x1d,0x62,0x7c,0x08,0x60,0x24,0xcc,0xa3,0x54,0xa4,0x1f,0x08,0x77,0xb3,0x8f,0x19,0xb3,0x77,0x4a,0xd2,0x09,0x5c,0x8d,0xa5,0x3b,0x06,0x9e,0x21,0xc7,0x6a,0xe2,0xd2,0x00,0x7e,0x16,0x71,0x9e,0xd4,0x00,0x80,0xd3,0x34,0xf7,0xda,0x52,0xe9,0xf5,0xa5,0x99,0x04,0x39,0xca,0xf0,0x83,0xa9,0x5b,0x83,0x3f,0x02,0xad,0x10,0xa0,0x8c,0x1a,0x6d,0x0f,0x26,0x0c,0x00,0x72,0x85,0xbd,0x4a,0x2f,0x47,0x70,0x3a,0x5a,0xef,0x46,0x52,0x87,0xd2,0x53,0xb1,0x8a,0xc2,0x25,0x14,0x31,0x62,0x10,0xff,0x56,0x68,0x14,0xb1,0x0f,0x87,0xa2,0x93,0xd6,0xf1,0x99,0xd3,0xc3,0x95,0x99,0x90,0xd0,0xc1,0x26,0x8b,0x4f,0x50,0xd5,0xf9,0xfc,0xef,0xbb,0xf2,0x37,0xbd,0x0c,0x28,0xb8,0x01,0x82,0xd6,0x65,0x97,0x41,0xf1,0x4f,0x10,0xbf,0xbb,0x21,0xbb,0xa1,0x2a,0xb6,0x20,0xaa,0x23,0x96,0xf5,0x6c,0x06,0x86,0xb4,0xea,0x90,0x17,0x99,0x02,0x24,0x21,0x6b,0x2f,0xe8,0xad,0x76,0xc4,0xa9,0x14,0x8e,0xef,0x9a,0x86,0xa3,0x63,0x5a,0x6a,0xa7,0x7b,0xc1,0xdc,0xfb,0x6f,0xba,0x59,0xa7,0x7d,0xfd,0xa9,0xb7,0x53,0x0d,0xc0,0xca,0x86,0x48,0xc8,0xd9,0x73,0x73,0x8e,0x01,0xba,0xb8,0xf0,0x8b,0x49,0x05,0xe8,0x4a,0xa4,0x64,0x1b,0xd6,0x02,0x41,0x0c,0xd9,0x75,0x20,0x26,0x5f,0x2f,0x23,0x1f,0x2b,0x35,0xe1,0x5e,0xb2,0xfa,0x04,0xd2,0xbd,0x94,0xd5,0xa7,0x7a,0xba,0xf1,0xe0,0xe1,0x61,0x01,0x0a,0x99,0x00,0x87,0xf5,0xb4,0x6e,0xa9,0x88,0xb2,0xbc,0x05,0x12,0xfd,0xa0,0xfa,0x92,0x3d,0xad,0xd6,0xc4,0x5c,0x53,0x01,0xd0,0x94,0x83,0x67,0x32,0x65,0xb5,0xab,0x2e,0x10,0xf4,0xba,0x52,0x0f,0x6b,0xba,0xd5,0x64,0xa5,0xc3,0xd5,0xe2,0x7b,0xdb,0x08,0x0f,0x7d,0x20,0xe1,0x32,0x96,0xa3,0x18,0x19,0x54,0xc3,0x9c,0x64,0x9c,0x94,0x3e,0xbe,0x17,0xdf,0x5c,0x1f,0x7a,0xae,0x0a,0x8f,0xe1,0x26,0xc4,0x77,0x58,0x5a,0x5d,0x4d,0x64,0x8a,0x0d,0x00,0x8b,0x6a,0xf5,0xe8,0xcd,0x31,0xbe,0x69,0xa9,0x29,0x6d,0x4f,0x3f,0xd2,0x5e,0xd8,0x6f,0x22,0x1e,0x4b,0x93,0xf6,0x5f,0x59,0x29,0x96,0x75,0x33,0x62,0x4b,0x92,0x35,0x75,0x0c,0x30,0x70,0x75,0x50,0xb5,0x85,0x36,0xd1,0x09,0xa7,0x13,0x1c,0x5a,0x5b,0xbe,0x4a,0x57,0x15,0x56,0x7c,0x12,0x53,0x4a,0xec,0x76,0x60,0x76,0x1e,0xeb,0xb9,0xfa,0xe2,0x89,0x1c,0x77,0x45,0x89,0xb8,0x0e,0x56,0x6a,0xd5,0x57,0xdd,0xef,0x73,0x67,0x19,0x6b,0x72,0x27,0xea,0x98,0x70,0xef,0x09,0xdd,0xfe,0xc7,0x9d,0x6b,0x93,0x19,0xa6,0x87,0x9b,0x52,0x05,0xd7,0x6b,0xf7,0xab,0xa5,0xac,0xf3,0x3a,0xfb,0x59,0xd1,0x7f,0xc5,0x4e,0x68,0x38,0x3d,0x6b,0xe5,0xa0,0x8e,0x9b,0x66,0xda,0x53,0xdc,0xde,0x00,0x8b,0xb2,0x94,0xb8,0x58,0x2b,0xd1,0x32,0xcd,0xcc,0x49,0x95,0x9f,0xdb,0xc2,0x1e,0x52,0x72,0x18,0x80,0xc8,0xad,0x03,0x52,0xc7,0x9f,0x03,0xa4,0x3b,0xbd,0x84,0xc4,0xcd,0xfd,0xc6,0xc5,0x29,0x00,0x5e,0x1e,0x7c,0xd9,0xa3,0x49,0xa7,0x16,0x8a,0x35,0x56,0x9b,0xa5,0xde,0xa8,0x18,0x96,0x8d,0x5a,0x91,0x46,0x6b,0xd6,0xe6,0x4e,0x20,0xbf,0x62,0x41,0x71,0x98,0xaf,0xc4,0xe8,0x1c,0x28,0xdd,0x77,0xed,0x40,0x28,0x23,0x23,0x98,0xb5,0x2f,0xbd,0xe8,0x6b,0xc8,0x4f,0x47,0x5b,0x90,0x16,0x71,0x0c,0xe2,0xaa,0xbc,0x11,0xa0,0x6b,0x4d,0xba,0xc9,0x01,0xec,0x16,0xcf,0x36,0x5c,0xa3,0xf2,0xd5,0x38,0x13,0x94,0x8a,0x69,0x3a,0x0f,0x93,0xe7,0x9c,0x46,0xca,0x5d,0x5a,0x6d,0xca,0x3d,0x28,0xca,0x50,0xad,0x18,0xbd,0x13,0xfc,0xa5,0x50,0x59,0xdd,0x9b,0x18,0x5f,0x79,0xf9,0xc4,0x71,0x96,0xa4,0xe8,0x1b,0x21,0x04,0xbc,0x46,0x0a,0x05,0x1e,0x02,0xf2,0xe8,0x44,0x4f]).unwrap(); + let mldsa65_pk = MLDSA65PublicKey::from_bytes(&[ + 0x48, 0x68, 0x3D, 0x91, 0x97, 0x8E, 0x31, 0xEB, 0x3D, 0xDD, 0xB8, 0xB0, 0x47, 0x34, 0x82, + 0xD2, 0xB8, 0x8A, 0x5F, 0x62, 0x59, 0x49, 0xFD, 0x8F, 0x58, 0xA5, 0x61, 0xE6, 0x96, 0xBD, + 0x4C, 0x27, 0xD0, 0x5B, 0x38, 0xDB, 0xB2, 0xED, 0xF0, 0x1E, 0x66, 0x4E, 0xFD, 0x81, 0xBE, + 0x1E, 0xA8, 0x93, 0x68, 0x8C, 0xE6, 0x8A, 0xA2, 0xD5, 0x1C, 0x59, 0x58, 0xF8, 0xBB, 0xC6, + 0xEB, 0x4E, 0x89, 0xEE, 0x67, 0xD2, 0xC0, 0x32, 0x09, 0x54, 0xD5, 0x72, 0x12, 0xCA, 0xC7, + 0x22, 0x9F, 0xF1, 0xD6, 0xEA, 0xF0, 0x39, 0x28, 0xBD, 0x51, 0x51, 0x1F, 0x8D, 0x88, 0xD8, + 0x47, 0x73, 0x6C, 0x7D, 0xE2, 0x73, 0x0D, 0x59, 0x78, 0xE5, 0x41, 0x07, 0x13, 0x16, 0x09, + 0x78, 0x86, 0x77, 0x11, 0xBF, 0x55, 0x39, 0xA0, 0xBF, 0xC4, 0xC3, 0x50, 0xC2, 0xBE, 0x57, + 0x2B, 0xAF, 0x0E, 0xE2, 0xE2, 0xFB, 0x16, 0xCC, 0xFE, 0xA0, 0x80, 0x28, 0xD9, 0x9A, 0xC4, + 0x9A, 0xEB, 0xB7, 0x59, 0x37, 0xDD, 0xCE, 0x11, 0x1C, 0xDA, 0xB6, 0x2F, 0xFF, 0x3C, 0xEA, + 0x8B, 0xA2, 0x23, 0x3D, 0x1E, 0x56, 0xFB, 0xC5, 0xC5, 0xA1, 0xE7, 0x26, 0xDE, 0x63, 0xFA, + 0xDD, 0x2A, 0xF0, 0x16, 0xB1, 0x19, 0x17, 0x7F, 0xA3, 0xD9, 0x71, 0xA2, 0xD9, 0x27, 0x71, + 0x73, 0xFC, 0xE5, 0x5B, 0x67, 0x74, 0x5A, 0xF0, 0xB7, 0xC2, 0x1D, 0x59, 0x7D, 0xBE, 0xB9, + 0x3E, 0x6A, 0x32, 0xF3, 0x41, 0xC4, 0x9A, 0x5A, 0x8B, 0xE9, 0xE8, 0x25, 0x08, 0x8D, 0x1F, + 0x2A, 0xA4, 0x51, 0x55, 0xD6, 0xC8, 0xAE, 0x15, 0x36, 0x7E, 0x4E, 0xB0, 0x03, 0xB8, 0xFD, + 0xF7, 0x85, 0x10, 0x71, 0x94, 0x97, 0x39, 0xF9, 0xFF, 0xF0, 0x90, 0x23, 0xEA, 0xF4, 0x51, + 0x04, 0xD2, 0xA8, 0x4A, 0x45, 0x90, 0x6E, 0xED, 0x46, 0x71, 0xA4, 0x4D, 0xC2, 0x8D, 0x27, + 0x98, 0x7B, 0xB5, 0x5D, 0xF6, 0x9E, 0x9E, 0x85, 0x61, 0xF6, 0x1A, 0x80, 0xA7, 0x26, 0x99, + 0x50, 0x38, 0x65, 0xFE, 0xD9, 0xB7, 0xEE, 0x72, 0xA8, 0xE1, 0x7A, 0x19, 0xC4, 0x08, 0x14, + 0x4F, 0x4B, 0x29, 0xAF, 0xEF, 0x70, 0x31, 0xC3, 0xA6, 0xD8, 0x57, 0x16, 0x10, 0xB4, 0x2C, + 0x9F, 0x42, 0x12, 0x45, 0xA8, 0x8F, 0x19, 0x7E, 0x16, 0x81, 0x2B, 0x03, 0x11, 0x59, 0xB6, + 0x5B, 0x96, 0x87, 0xE5, 0xB3, 0xE9, 0x34, 0xC5, 0x22, 0x5A, 0xE9, 0x8A, 0x79, 0xBA, 0x73, + 0xD2, 0xB3, 0x99, 0xD7, 0x35, 0x10, 0xEF, 0xFA, 0xD1, 0x9E, 0x53, 0xB8, 0x45, 0x0F, 0x0B, + 0xA8, 0xFC, 0xE1, 0x01, 0x2F, 0xD9, 0x8D, 0x26, 0x0A, 0x74, 0xAA, 0xAA, 0x13, 0xFA, 0xE2, + 0x49, 0xA0, 0x06, 0xB1, 0xC3, 0x4F, 0x5B, 0xA0, 0xB8, 0x82, 0xF2, 0x63, 0x78, 0x22, 0x2F, + 0xB3, 0x6F, 0x22, 0x83, 0xC2, 0x43, 0xF0, 0xFF, 0xEB, 0x5F, 0x1B, 0xB4, 0x14, 0xA0, 0xA7, + 0x0D, 0x55, 0xE3, 0xD4, 0x0A, 0x56, 0xB6, 0xCB, 0xC8, 0x8A, 0xE1, 0xF0, 0x3B, 0x7B, 0x28, + 0x82, 0xD9, 0x8D, 0xEE, 0xA2, 0x8E, 0x14, 0x5C, 0x9D, 0xED, 0xFD, 0x8E, 0xAF, 0x1C, 0xEF, + 0x2E, 0xD9, 0x4A, 0x8B, 0x05, 0x0F, 0x89, 0x64, 0xF4, 0x6D, 0x1E, 0xA0, 0xD0, 0xC2, 0xA4, + 0x3E, 0x0D, 0xDA, 0x61, 0x82, 0xAD, 0xBF, 0x4F, 0x6E, 0xD1, 0x75, 0xB6, 0x74, 0x22, 0x57, + 0x85, 0x9B, 0xF2, 0x2F, 0x3A, 0x41, 0x7E, 0xCF, 0x1F, 0x9D, 0x89, 0x31, 0x7B, 0x5E, 0x53, + 0x9D, 0x58, 0x7A, 0xF1, 0x6B, 0x9E, 0x13, 0x13, 0xE0, 0x45, 0x14, 0xFF, 0xA6, 0x4B, 0xA8, + 0xB3, 0xFF, 0x2B, 0x83, 0x21, 0xF8, 0x81, 0x1C, 0xB3, 0xFB, 0x02, 0x2C, 0x8F, 0x64, 0x4E, + 0x70, 0xA4, 0xB8, 0x0A, 0x2F, 0xBF, 0xEE, 0x60, 0x4A, 0xBB, 0x73, 0x79, 0x09, 0x1E, 0xA8, + 0xE6, 0xC5, 0xC7, 0x4D, 0xFC, 0x02, 0x83, 0x66, 0x6B, 0x40, 0xC0, 0x79, 0x38, 0x70, 0x02, + 0x82, 0x04, 0xA1, 0x36, 0xBF, 0x5D, 0xA9, 0x56, 0x8E, 0xB7, 0x98, 0xD3, 0x49, 0x03, 0x8B, + 0xDB, 0x0C, 0x11, 0xE0, 0x34, 0x45, 0xE7, 0x84, 0x7C, 0xB5, 0x06, 0x9C, 0x75, 0xCF, 0x28, + 0xAC, 0x60, 0x1C, 0x77, 0x99, 0xD9, 0x58, 0x21, 0x0D, 0xDB, 0xCB, 0x22, 0x6E, 0x51, 0xAF, + 0xEF, 0x9F, 0x1D, 0xE4, 0x7B, 0x07, 0x38, 0x73, 0xD6, 0xD3, 0xF9, 0x74, 0x56, 0xBE, 0xDE, + 0x08, 0x50, 0x82, 0xE7, 0x4A, 0x29, 0x8B, 0x2C, 0xD4, 0x8F, 0x4B, 0x30, 0x93, 0x15, 0x5F, + 0x36, 0x6C, 0x8F, 0xA6, 0x01, 0xC6, 0xAF, 0x85, 0x8D, 0xFA, 0x32, 0xC0, 0x84, 0x91, 0xB2, + 0xA2, 0x98, 0x87, 0xF9, 0x03, 0x35, 0x94, 0x9A, 0x5D, 0x6E, 0xDA, 0xA6, 0x79, 0x88, 0x2A, + 0x3A, 0x95, 0xD6, 0xBF, 0x6D, 0x97, 0x0A, 0x22, 0x1F, 0x4B, 0x9D, 0x3D, 0x8C, 0xBF, 0x38, + 0x4A, 0xF8, 0x1A, 0xAC, 0x95, 0xE2, 0xB3, 0x29, 0x4E, 0x04, 0x78, 0x9A, 0xC8, 0x37, 0x27, + 0xA5, 0xDC, 0x04, 0x55, 0x9F, 0x96, 0xAF, 0x41, 0xD8, 0xA0, 0x53, 0x51, 0x6F, 0xEE, 0xEE, + 0xBC, 0x52, 0x74, 0x6E, 0xB6, 0xAB, 0x28, 0x19, 0xE0, 0x91, 0x08, 0x71, 0x0D, 0x83, 0x5F, + 0x01, 0x1F, 0xA6, 0x30, 0x65, 0x87, 0x2A, 0xD3, 0x34, 0xD5, 0xCD, 0xFF, 0xB2, 0xB2, 0x31, + 0x05, 0x07, 0xE9, 0x2F, 0xC9, 0x93, 0xAE, 0x31, 0x7D, 0xA9, 0x7F, 0x4F, 0x30, 0x9C, 0xDA, + 0xF0, 0xF6, 0x7E, 0xD9, 0x9D, 0x90, 0x21, 0x55, 0x76, 0x08, 0x38, 0x49, 0xF9, 0x53, 0xB2, + 0x46, 0xD7, 0xFE, 0xDB, 0x3F, 0xDB, 0x67, 0x67, 0x98, 0x50, 0xA5, 0xAD, 0x40, 0x4E, 0x64, + 0x14, 0x7F, 0xB7, 0xCF, 0x4F, 0x6A, 0xED, 0xDD, 0x05, 0xAF, 0xB4, 0xB8, 0x34, 0x96, 0x8D, + 0x1F, 0xE8, 0x80, 0x14, 0x96, 0x0D, 0xCE, 0x5D, 0x94, 0x22, 0x36, 0x52, 0x6E, 0x12, 0xA4, + 0x78, 0xD6, 0x9E, 0x5F, 0xBE, 0x69, 0x70, 0x31, 0x0B, 0x30, 0x8C, 0x06, 0x84, 0x50, 0x18, + 0xCF, 0xC7, 0xB2, 0xAB, 0x43, 0x0A, 0x13, 0xA6, 0xB1, 0xAC, 0x7B, 0xB0, 0x2C, 0xCC, 0xBB, + 0x3D, 0x91, 0x1A, 0xC2, 0xF1, 0x10, 0x68, 0x61, 0x3F, 0xBE, 0x02, 0x9B, 0xFD, 0xCE, 0x02, + 0xCF, 0x5C, 0xD3, 0x89, 0x50, 0xED, 0x72, 0xC8, 0x39, 0x44, 0xED, 0xFB, 0xC7, 0x56, 0x15, + 0xAF, 0x87, 0xF8, 0x64, 0xC0, 0x51, 0xF3, 0xC5, 0x54, 0x56, 0xC5, 0x41, 0x28, 0x63, 0xA4, + 0x0C, 0x06, 0xD1, 0xDA, 0xB5, 0x62, 0xBD, 0xFF, 0x05, 0x71, 0xB8, 0xD3, 0xC3, 0x91, 0x7B, + 0xBD, 0x30, 0x08, 0x80, 0xBB, 0xA5, 0xE9, 0x98, 0x23, 0x9B, 0x95, 0xFA, 0x91, 0xB7, 0xD6, + 0x41, 0x6D, 0x4F, 0x39, 0x8B, 0x3A, 0xDB, 0xCD, 0x30, 0x98, 0x3E, 0xD3, 0x59, 0x2B, 0x4D, + 0x9E, 0xF7, 0xD4, 0x23, 0x6F, 0xD0, 0x0F, 0x50, 0xD9, 0x8A, 0xA5, 0x3A, 0x23, 0x5A, 0xC4, + 0x17, 0x27, 0x20, 0xF7, 0x7D, 0x96, 0x17, 0x26, 0x72, 0x98, 0x0C, 0xFE, 0x8F, 0xF7, 0xA5, + 0xA7, 0x02, 0x78, 0x3E, 0xDC, 0x2B, 0xA3, 0x1B, 0x22, 0x59, 0x01, 0x5A, 0x11, 0x2F, 0xC7, + 0xF4, 0x68, 0xA9, 0xC2, 0xF9, 0x46, 0x40, 0x39, 0x00, 0x2D, 0x30, 0xEF, 0x67, 0x8B, 0x4C, + 0xB7, 0x98, 0xBC, 0x11, 0x62, 0x16, 0xBF, 0x7A, 0x9A, 0x7C, 0x18, 0xBA, 0x03, 0xB7, 0xB5, + 0x8F, 0xD0, 0x75, 0x15, 0xD3, 0x11, 0x50, 0x49, 0xD3, 0x61, 0x4B, 0xE7, 0xA0, 0x7E, 0x74, + 0x43, 0x00, 0x75, 0x0D, 0xF1, 0xD2, 0xC5, 0x87, 0x53, 0x38, 0x90, 0x59, 0xEA, 0xFC, 0x3D, + 0x78, 0x5C, 0xCD, 0xD3, 0x1C, 0x07, 0x64, 0x8B, 0xED, 0xC0, 0x3A, 0x5C, 0x3B, 0x8A, 0xD4, + 0x6D, 0x06, 0x4D, 0x59, 0xC1, 0x3D, 0x57, 0x37, 0x47, 0x29, 0xFC, 0x4E, 0x29, 0x53, 0x62, + 0xE2, 0xA5, 0x19, 0x12, 0x04, 0x53, 0x04, 0x28, 0xBC, 0x15, 0x22, 0xAF, 0xA2, 0x8F, 0xF5, + 0xFE, 0x16, 0x55, 0xE3, 0x04, 0xCA, 0x5B, 0xC8, 0xC2, 0x7A, 0xD0, 0xE0, 0xC6, 0xA3, 0x9D, + 0xD4, 0xDF, 0x28, 0x95, 0x6C, 0x14, 0xB3, 0x8C, 0xC9, 0x36, 0x82, 0xCE, 0xFE, 0x40, 0x2B, + 0xBD, 0x5E, 0x82, 0xD2, 0x9C, 0x46, 0x4E, 0x44, 0xEB, 0x5D, 0x37, 0xB4, 0x8F, 0xC5, 0x68, + 0xDF, 0xE0, 0xCC, 0x6E, 0x8E, 0x16, 0xBA, 0xEA, 0x05, 0xE5, 0x13, 0x55, 0x90, 0xF1, 0x92, + 0x94, 0xE7, 0x3E, 0x83, 0x67, 0xB0, 0x21, 0x6D, 0xBB, 0x81, 0x50, 0x30, 0xB9, 0xDE, 0x55, + 0x91, 0x3F, 0x08, 0x03, 0x9C, 0x42, 0x35, 0x1C, 0x59, 0xE5, 0x51, 0x5D, 0xD5, 0xAF, 0x8E, + 0x08, 0x9A, 0x15, 0xE6, 0x25, 0xE8, 0xF6, 0xDE, 0xE6, 0x39, 0x38, 0x6C, 0x46, 0x49, 0x7D, + 0x7A, 0x26, 0x32, 0x88, 0x77, 0x4D, 0xE5, 0x81, 0xA7, 0xDE, 0x96, 0x29, 0xB4, 0x1B, 0x44, + 0x24, 0x14, 0x1F, 0x97, 0x8F, 0xB8, 0x33, 0x12, 0x08, 0xEF, 0xDE, 0xC3, 0xC6, 0xE0, 0xDE, + 0x39, 0xBC, 0x57, 0x06, 0x3F, 0x3D, 0xCD, 0x6C, 0x47, 0x03, 0x73, 0xC0, 0x88, 0x91, 0xEA, + 0x29, 0xCB, 0xC7, 0xCC, 0x6D, 0x64, 0x83, 0xB8, 0x88, 0x90, 0x83, 0xAC, 0xE8, 0x6A, 0xA7, + 0xB5, 0x1B, 0x1C, 0x2C, 0xFE, 0x6E, 0x2A, 0xD1, 0x8D, 0x97, 0xCE, 0x36, 0xFB, 0xC5, 0x6E, + 0xA4, 0x2F, 0xAE, 0x97, 0xE6, 0xA7, 0xAC, 0x11, 0x48, 0x64, 0x47, 0x8C, 0x36, 0x6D, 0xF1, + 0xEB, 0xB1, 0xE7, 0xB1, 0x1A, 0x90, 0x98, 0x50, 0x4F, 0xD5, 0x97, 0x5B, 0xDF, 0x1F, 0x49, + 0xDC, 0x70, 0x00, 0x2B, 0x63, 0xC1, 0x73, 0x9A, 0x9D, 0x26, 0x3F, 0xBA, 0xD4, 0x07, 0x3F, + 0x6A, 0x9F, 0x6C, 0x2B, 0x8A, 0xF4, 0xB4, 0xC3, 0x32, 0xA1, 0x03, 0xA0, 0xCF, 0xFA, 0x5D, + 0xEE, 0xB2, 0xD0, 0x62, 0xCA, 0x3C, 0x21, 0x5F, 0xD3, 0x60, 0x02, 0x6B, 0xE7, 0xC5, 0x16, + 0x4F, 0x4A, 0x44, 0x24, 0xEF, 0x74, 0x94, 0x88, 0x04, 0xD6, 0x6F, 0x46, 0x48, 0x77, 0x32, + 0xC8, 0x20, 0x2C, 0x79, 0x54, 0x78, 0x64, 0x7B, 0x4E, 0xA7, 0x1D, 0x62, 0x7C, 0x08, 0x60, + 0x24, 0xCC, 0xA3, 0x54, 0xA4, 0x1F, 0x08, 0x77, 0xB3, 0x8F, 0x19, 0xB3, 0x77, 0x4A, 0xD2, + 0x09, 0x5C, 0x8D, 0xA5, 0x3B, 0x06, 0x9E, 0x21, 0xC7, 0x6A, 0xE2, 0xD2, 0x00, 0x7E, 0x16, + 0x71, 0x9E, 0xD4, 0x00, 0x80, 0xD3, 0x34, 0xF7, 0xDA, 0x52, 0xE9, 0xF5, 0xA5, 0x99, 0x04, + 0x39, 0xCA, 0xF0, 0x83, 0xA9, 0x5B, 0x83, 0x3F, 0x02, 0xAD, 0x10, 0xA0, 0x8C, 0x1A, 0x6D, + 0x0F, 0x26, 0x0C, 0x00, 0x72, 0x85, 0xBD, 0x4A, 0x2F, 0x47, 0x70, 0x3A, 0x5A, 0xEF, 0x46, + 0x52, 0x87, 0xD2, 0x53, 0xB1, 0x8A, 0xC2, 0x25, 0x14, 0x31, 0x62, 0x10, 0xFF, 0x56, 0x68, + 0x14, 0xB1, 0x0F, 0x87, 0xA2, 0x93, 0xD6, 0xF1, 0x99, 0xD3, 0xC3, 0x95, 0x99, 0x90, 0xD0, + 0xC1, 0x26, 0x8B, 0x4F, 0x50, 0xD5, 0xF9, 0xFC, 0xEF, 0xBB, 0xF2, 0x37, 0xBD, 0x0C, 0x28, + 0xB8, 0x01, 0x82, 0xD6, 0x65, 0x97, 0x41, 0xF1, 0x4F, 0x10, 0xBF, 0xBB, 0x21, 0xBB, 0xA1, + 0x2A, 0xB6, 0x20, 0xAA, 0x23, 0x96, 0xF5, 0x6C, 0x06, 0x86, 0xB4, 0xEA, 0x90, 0x17, 0x99, + 0x02, 0x24, 0x21, 0x6B, 0x2F, 0xE8, 0xAD, 0x76, 0xC4, 0xA9, 0x14, 0x8E, 0xEF, 0x9A, 0x86, + 0xA3, 0x63, 0x5A, 0x6A, 0xA7, 0x7B, 0xC1, 0xDC, 0xFB, 0x6F, 0xBA, 0x59, 0xA7, 0x7D, 0xFD, + 0xA9, 0xB7, 0x53, 0x0D, 0xC0, 0xCA, 0x86, 0x48, 0xC8, 0xD9, 0x73, 0x73, 0x8E, 0x01, 0xBA, + 0xB8, 0xF0, 0x8B, 0x49, 0x05, 0xE8, 0x4A, 0xA4, 0x64, 0x1B, 0xD6, 0x02, 0x41, 0x0C, 0xD9, + 0x75, 0x20, 0x26, 0x5F, 0x2F, 0x23, 0x1F, 0x2B, 0x35, 0xE1, 0x5E, 0xB2, 0xFA, 0x04, 0xD2, + 0xBD, 0x94, 0xD5, 0xA7, 0x7A, 0xBA, 0xF1, 0xE0, 0xE1, 0x61, 0x01, 0x0A, 0x99, 0x00, 0x87, + 0xF5, 0xB4, 0x6E, 0xA9, 0x88, 0xB2, 0xBC, 0x05, 0x12, 0xFD, 0xA0, 0xFA, 0x92, 0x3D, 0xAD, + 0xD6, 0xC4, 0x5C, 0x53, 0x01, 0xD0, 0x94, 0x83, 0x67, 0x32, 0x65, 0xB5, 0xAB, 0x2E, 0x10, + 0xF4, 0xBA, 0x52, 0x0F, 0x6B, 0xBA, 0xD5, 0x64, 0xA5, 0xC3, 0xD5, 0xE2, 0x7B, 0xDB, 0x08, + 0x0F, 0x7D, 0x20, 0xE1, 0x32, 0x96, 0xA3, 0x18, 0x19, 0x54, 0xC3, 0x9C, 0x64, 0x9C, 0x94, + 0x3E, 0xBE, 0x17, 0xDF, 0x5C, 0x1F, 0x7A, 0xAE, 0x0A, 0x8F, 0xE1, 0x26, 0xC4, 0x77, 0x58, + 0x5A, 0x5D, 0x4D, 0x64, 0x8A, 0x0D, 0x00, 0x8B, 0x6A, 0xF5, 0xE8, 0xCD, 0x31, 0xBE, 0x69, + 0xA9, 0x29, 0x6D, 0x4F, 0x3F, 0xD2, 0x5E, 0xD8, 0x6F, 0x22, 0x1E, 0x4B, 0x93, 0xF6, 0x5F, + 0x59, 0x29, 0x96, 0x75, 0x33, 0x62, 0x4B, 0x92, 0x35, 0x75, 0x0C, 0x30, 0x70, 0x75, 0x50, + 0xB5, 0x85, 0x36, 0xD1, 0x09, 0xA7, 0x13, 0x1C, 0x5A, 0x5B, 0xBE, 0x4A, 0x57, 0x15, 0x56, + 0x7C, 0x12, 0x53, 0x4A, 0xEC, 0x76, 0x60, 0x76, 0x1E, 0xEB, 0xB9, 0xFA, 0xE2, 0x89, 0x1C, + 0x77, 0x45, 0x89, 0xB8, 0x0E, 0x56, 0x6A, 0xD5, 0x57, 0xDD, 0xEF, 0x73, 0x67, 0x19, 0x6B, + 0x72, 0x27, 0xEA, 0x98, 0x70, 0xEF, 0x09, 0xDD, 0xFE, 0xC7, 0x9D, 0x6B, 0x93, 0x19, 0xA6, + 0x87, 0x9B, 0x52, 0x05, 0xD7, 0x6B, 0xF7, 0xAB, 0xA5, 0xAC, 0xF3, 0x3A, 0xFB, 0x59, 0xD1, + 0x7F, 0xC5, 0x4E, 0x68, 0x38, 0x3D, 0x6B, 0xE5, 0xA0, 0x8E, 0x9B, 0x66, 0xDA, 0x53, 0xDC, + 0xDE, 0x00, 0x8B, 0xB2, 0x94, 0xB8, 0x58, 0x2B, 0xD1, 0x32, 0xCD, 0xCC, 0x49, 0x95, 0x9F, + 0xDB, 0xC2, 0x1E, 0x52, 0x72, 0x18, 0x80, 0xC8, 0xAD, 0x03, 0x52, 0xC7, 0x9F, 0x03, 0xA4, + 0x3B, 0xBD, 0x84, 0xC4, 0xCD, 0xFD, 0xC6, 0xC5, 0x29, 0x00, 0x5E, 0x1E, 0x7C, 0xD9, 0xA3, + 0x49, 0xA7, 0x16, 0x8A, 0x35, 0x56, 0x9B, 0xA5, 0xDE, 0xA8, 0x18, 0x96, 0x8D, 0x5A, 0x91, + 0x46, 0x6B, 0xD6, 0xE6, 0x4E, 0x20, 0xBF, 0x62, 0x41, 0x71, 0x98, 0xAF, 0xC4, 0xE8, 0x1C, + 0x28, 0xDD, 0x77, 0xED, 0x40, 0x28, 0x23, 0x23, 0x98, 0xB5, 0x2F, 0xBD, 0xE8, 0x6B, 0xC8, + 0x4F, 0x47, 0x5B, 0x90, 0x16, 0x71, 0x0C, 0xE2, 0xAA, 0xBC, 0x11, 0xA0, 0x6B, 0x4D, 0xBA, + 0xC9, 0x01, 0xEC, 0x16, 0xCF, 0x36, 0x5C, 0xA3, 0xF2, 0xD5, 0x38, 0x13, 0x94, 0x8A, 0x69, + 0x3A, 0x0F, 0x93, 0xE7, 0x9C, 0x46, 0xCA, 0x5D, 0x5A, 0x6D, 0xCA, 0x3D, 0x28, 0xCA, 0x50, + 0xAD, 0x18, 0xBD, 0x13, 0xFC, 0xA5, 0x50, 0x59, 0xDD, 0x9B, 0x18, 0x5F, 0x79, 0xF9, 0xC4, + 0x71, 0x96, 0xA4, 0xE8, 0x1B, 0x21, 0x04, 0xBC, 0x46, 0x0A, 0x05, 0x1E, 0x02, 0xF2, 0xE8, + 0x44, 0x4F, + ]) + .unwrap(); // todo -- there's something I don't understand here that removing this hex:: for a straight array causes peak memory usage to go up. // Find the optimal and make all the tests the same. let sig = &*hex::decode("9061f15cbf2092f744fbcd799eb02414053c1b0f7412124bedc41cf9a3db0166469e874037d7f081e5f8d3d2033a0307d1c49ed01fe64578c4a6fabd80880cdf1911848f184d4bcf536ca795a0fb1aa19ab7ee3ba6b58bd64bbeac9f58650fff1ef5a97ab6916df962072e20e7c6be96090e3a781a504bc4442bd8889a0aa628907a74299f39fa836031f1bd68355bebe7ae93c1e361a9efbed1325d96227070461fcd6f151b8669d9229b977d9ee51fd2260c3e4a2e820416f9e074958dc3b3e2217e6312b7e0b582a048981cf6579f4bc7715b78c808e4c57e3b8aa38b05c04fcedf209f52c1e331ae83dbdff60ba450a17cc397568e54bc3f16ddf30b92747ce460d925b9be20a1d35e2aed97f124af2616a5361df28ba30e522dd08fa00fd28d1ac484d756a89e3a442fefe8332c56cd2a9fde691bdbda43f1cc54cef57bead96120b50c7d4695bdbb1303cc5ddda898e4eeb83083176e40e0232cdd1c3150371df05d6fdad7e1164d90393cf308e99edfeb31fed263e2866ee3b7f3937b399c974d87ba7b489efe3c9b80371d2928446adc31991ab0cefaaa080575b9ec81cfa133a9911c035a8058d0d3f2e34de4a9fb009bb4ccdb16de7b908574a7496725ff857556c1b33917e986c80f1014a9e3083add2fb35f345c5d06159e443329d0da099987b996c3731592b460c2ffd2955f7546f4216100ba43188803ff9b36969685f909fa2539323b8c8ec1c095a5085e554dd450e0e67ab670b6a11ebf6c25520fc13e364060f91f9b7f3d5cb48ff28b8fc83d4293f1f35ad6ff6ae4574ad7a1c6005fc0389a7b21386b0850a05d832fe6a14bb2b1db1f8e20bd09174946cd098b81c8f797e95f2143a949770cf1219bfef039db51a80fc247f65f41554c7173dd805ba82fdf47ab6d4bfd37dfe46fc47904421ae00dc005a22f9c4784b0ea9e665392a412245016d5c6d7673a6a180d228d4255a538e451ffd8b414d40304c0c888992e0ab6de1602109527417bc1c7eb782ae77a8c3cdfc1d13a1e874207898264e38080243109c5969649ac8383417e922ba115331142d0ed35440b15d40bee0cf58af37c0f0524ffac1c71ceed3bb82f76ab108a8ad1a0c8b78d9341148c642369be7bef59d46f49d70c83560607f140848ec9a7607d4a08f8b6e4447f5523f416981888a8de9647ffef79389e4983e5c9387698d0cc2d429322365ce7e7b5fd6d6eb921c813fcf06199fe1ca41e9cfe03b539f321671a2acad0963f876f9db7a1c4371b9f101005217995b5b6a40976246d245da603dba8dac812a5480c3476a99d0ffdf0ef943d72d912543148b2fe78e8b0159324fe9bcd4ced33cd212fe4f3dfd6d4c5e1958beb95ac6b533ace3e78015e3880b52bf45299263a4c0096f8ba5fe3a6298cab675cb7f382e7ef49720eb4cf47376e2d2574122ccf91129c858e948904fecefb91226ed42403ba12dd3258909a87dfcbf65cc3adc3d98d277fdcec7664e2292b7d27afbb5aafb405c20a34b2fe2c0849ee280bb891dfdf59f19b89b0246358db54cf3fdc66eaaaa750c8903f1d42678f3edf0b7530410aa881bc617f94346379854af4532e61f65aae7576c35faf55e155bd6787b4634d54191907e155c239e68480cdfa0c87054bfb62855f409a20d5335fb123e681e64ec847cd985b6062059f436aebac623c038b6c3405ac325191a8d1126a5ef8f38cccbf144a5c324c1e093cf99efbe10ca03d439bcfb8ba5e293b7d318837f7bc42a99964392369da76e79d71d1a2c248a11324a87ae1e3cbeab6fb0d0bcae1ef55e43dfb6f1b4cfb82c7a778fb828a3727ef07685fe38a74b3dd25d015322c2d9f245c08d8c2b43865694233782eb734436c4eddef5406208d6c4572c7371262fe02319cfbbcf2e23bed8aa969d1ae6f5f25ff6b8ebcf0925066f761a39bbff49f0c8dbc3be84f0c442b044ea01b669747e3c8293cfe9ccdf2ef063ae3d28d10720c279a2691616abd23b055cfc6c562125df4ad0fa6631304972ddc3674b1aaa7665bf621320d83eac8d5b371d7d719829f58b23458182558710de31d81ef9a47d8839c79640b2025d1965a418bc90e4115f1423311a8b64fcde0f2d2145ee535b0931b84bc8110445f2ff68d136ed709ddb7ea9ff75f3b4e8b4f836230ca9e81069477f634e07270af60ef96f72557a081d664abcf35548f699484653da645483ff2bf5998617ae8bfa62d56e714f3c0136e5035a3f78e06c2f470df7fd3380d14033f81e2aae6b4d90487dab76b9b3b8761fb56c36f5429da3d4346cb22e641ad8d7d2d80fa240d4e0154e6b3d2f1b3ef6cf174c08d062f575c83a4078174f874364df36a6328beeef69ba7f90e1df9fdcec9a2f15ebf04fa7d6756da2e5a59c9cbbcbc397d6fb28d0fc9a60534dff0752716ed079ad1ab19a224d1c8ae8a53242fd164989ff997489b6520eb3c0e97f4bcc1a9c3cbd44f008c03ef52cf7e626881d246925e0336c0ac668867f853da7820f914115a7c77ac31b66f46fbf97f66fa26416fc4581d459a4f2462d52cf0c79b278955aa73e8fa56e3c320f516bcc54c97e587199c15ab953cc37189b81c70cabb2559e445bcc9d8174ad7574e9acb02f43e0c34ff5e6746ee730ad41ff8eef93c2071c2649063dd92f343c06ef6abaf98f28d98d968071c12cc10a90c22d8b3b3480c76f7a51b7ec594b3435d2e3d779c1a15037697f3a058650472e47eecd5f32eb3243a516f0e703f9888c84690750648d6a9a876bf1f353db6891dc6d317d6e87ac088f42b5f6f20d799ece4fa7aaa928d2ac795e8de83d1e1c7fa2f9a4106693e981c21c63b3221c4fa2649f45f0c6e05dbf24011af16ab2e5fe94a640b485988037ebe1e8ad0b2623d95e9947f0726121d7828614e3b2d77a7a1f9a938bea9a1a7a2627b7d2e358c42ccc6c0b80a15a1c2f6e9aaf0495bdb7bb8d4b0e28a1ab5ab93ca0ff3e3f910c490c13486852534d5e12160835ec5916c5c68349c4e2d8fa956c643277edd3b6c81c88c010421705fd317ff9e3c94df0ed5305f530acbccf8dd0e87140cd38152664a572c168cd72595b7fac243c03f3fb33ef74a28c0e4469f94587c13704e9efe8010b2125aca78c22c33c82366e1a7c4028c2ae2e8d26e1a57e4297fac987f84a0a27f42b4c93a4f4d14569824b0880fb67407ed58f267ac403aa0b1f93784b4b4c67036037e60d58072611b0e90ca316976ef4e0b302cdad1b6dcca92efb8e1f6be2397967508be2c02a25ed0380ba1f7955f857c8fb043297780d136b2b064040c8e55143d715ea997e134ed973c98ef82786f0ccf66c17d863542180c66d54d08e116f2e35d995e214489ad0fad7a55fe9ebc1a777fe34141147c080b98d13463a3bbc6fc82f2fc95f4de7b3591d9c8cd4416917a4338095d5620104b7be13f5a131dd3f7aad5b559d11e8171dfb91e2bb1e47ac3810b1cdc1a1e370c867b7b7b50c4688dce545763157e02f47e1cc661d5bf2fbc336cfae080ab15728b1ab9dd199f2779d451e6178977fb658c17344cffb7aa3af5791a28fc8a089c85187753e5e313c8d1f0fe7755e28be444426a189e8bce2d2f79db31d4c3ca911a83455525355f95d159351cd731a88e55403851236ee2128f279d5be644c042453ae65d9e9f3b40d6c82bdeb002acdee061ecca3f2dceabef9a900e6e063d56ab39cb82dbc77a4677572d7616cd72c0f6d5b9b941dfda1fe7c896b8cc24d65a4322d712a84e94adfc8ed0cc56cc1ae97f775bd3cea5b20b524d9a7a916056e19af095d30171e5e14c7c998f78dc44845edf307363eab7913f680a5e5a1540a6f945507ffa67591f8d1a2920ab3b6e754e35379dd67870c242335e2717903ff3c687e5c33dc953416865d5f23bd752e55492b9d5d888d7b37ef33b0a6774d052b0987c066a2e01767207aa7fbfc393ca62874613dde3794f74fadb5d55b877b877a605918c812610fbcafad72ee245e6dd8721138d6bd3f4eedad853aed1ec437ad02ac937c80dae26fa5f70083bd346779b779387f7b3d2aae57770d8177928833281ccb7a38da24834fd9726fd17eb603cba9041e82bfeed0e33942dde1d48c271f5b39aa7230f41afb89d36f7976eee4f51a036743031c534f64685b94c990a93a5737fe628ee9cda8ed9c08b11d3836f833835c445b317a77ead7599d1a0c08873014510d36bb7ff5fb961277589ea48c32a60c87ec40681be067b17785ec44825bd89faa25249e735a628b6eebcc6cce4e0314c627588118c40b2e0d460d8d5ce358c56458f36914ca203f5a5381c6deb5a76bbc08c40a87437da0d0b571788a05e9f96d9bb770de8a0b1b960ff2a44a964c9b7939853742e83ce8deb79191b2d82454655f227079dd8c5b0216c8470b8e1ac70526301bbfa2bc4adca68a766ccb2a6e0ebf2e99905bf5242590b01703868b3faf841c11c383be145a40fea6375e18a01468e459603b5efdf8a4e9abd179280ae8b5947d78d2f0c4d37715eaa42bc37cf8730e41ffbf9826d46424f2922a96033cefaa8b4bbe4c8b89d43501fd5211d5392ca19a98ba127d9025b5c6e86ba024471940549a2b5d8e14961c9dc19696da1a5bffd01030d5e6100000000000000000000000000000000000000000000000005090f131a1f").unwrap(); @@ -395,8 +1885,8 @@ fn bench_mldsa65_verify() { } fn bench_mldsa65_lowmemory_verify() { - use bouncycastle::mldsa_lowmemory::{MLDSATrait, MLDSA65, MLDSA65_SIG_LEN, MLDSA65PublicKey}; use bouncycastle::hex; + use bouncycastle::mldsa_lowmemory::{MLDSA65, MLDSA65_SIG_LEN, MLDSA65PublicKey, MLDSATrait}; eprintln!("MLDSA65_lowmemory/Verify"); @@ -428,8 +1918,10 @@ fn bench_mldsa65_lowmemory_verify() { } fn bench_mldsa87_verify() { - use bouncycastle::mldsa::{MLDSATrait, MLDSA87, MLDSA87_PK_LEN, MLDSA87_SIG_LEN, MLDSA87PublicKey}; use bouncycastle::hex; + use bouncycastle::mldsa::{ + MLDSA87, MLDSA87_PK_LEN, MLDSA87_SIG_LEN, MLDSA87PublicKey, MLDSATrait, + }; eprintln!("MLDSA87/Verify"); @@ -450,7 +1942,182 @@ fn bench_mldsa87_verify() { // eprintln!("sig:\n{}", &*hex::encode(sig)); // let mldsa87_pk = MLDSA87PublicKey::from_bytes(&*hex::decode("9792bcec2f2430686a82fccf3c2f5ff665e771d7ab41b90258cfa7e90ec97124a73b323b9ba21ab64d767c433f5a521effe18f86e46a188952c4467e048b729e7fc4d115e7e48da1896d5fe119b10dcddef62cb307954074b42336e52836de61da941f8d37ea68ac8106fabe19070679af6008537120f70793b8ea9cc0e6e7b7b4c9a5c7421c60f24451ba1e933db1a2ee16c79559f21b3d1b8305850aa42afbb13f1f4d5b9f4835f9d87dfceb162d0ef4a7fdc4cba1743cd1c87bb4967da16cc8764b6569df8ee5bdcbffe9a4e05748e6fdf225af9e4eeb7773b62e8f85f9b56b548945551844fbd89806a4ac369bed2d256100f688a6ad5e0a709826dc4449e91e23c5506e642361ef5a313712f79bc4b3186861ca85a4bab17e7f943d1b8a333aa3ae7ce16b440d6018f9e04daf5725c7f1a93fad1a5a27b67895bd249aa91685de20af32c8b7e268c7f96877d0c85001135a4f0a8f1b8264fa6ebe5a349d8aecad1a16299ccf2fd9c7b85bace2ced3aa1276ba61ee78ed7e5ca5b67cdd458a9354030e6abbbabf56a0a2316fec9dba83b51d42fd3167f1e0f90855d5c66509b210265dc1e54ec44b43ba7cf9aef118b44d80912ce75166a6651e116cebe49229a7062c09931f71abd2293f76f7efc3215ba97800037e58e470bdbbb43c1b0439eaf79c54d93b44aac9efe9fbe151874cfb2a64cbee28cc4c0fe7775e5d870f1c02e5b2e3c5004c995f24c9b779cb753a277d0e71fd425eb6bc2ca56ce129db51f70740f31e63976b50c7312e9797d78c5b1ac24a5fa347cc916e0a83f5c3b675cd30b81e3fa10b93444e07397571cce98b28da51db9056bc728c5b0b1181e2fbd387b4c79ab1a5fefece37167af772ddad14eb4c3982da5a59d0e9eb173ec6315091170027a3ab5ef6aa129cb8585727b9358a28501d713a72f3f1db31714286f9b6408013af06045d75592fc0b7dd47c73ed9c75b11e9d7c69f7cadfc3280a9062c5273c43be1c34f87448864cea7b5c97d6d32f59bd5f25384653bb5c4faa45bea8b89402843e645b6b9269e2bd988ddacb033328ffb060450f7df080053e6969b251e875ecec32cfc592840d69ab69a75e06b379c535d95266b082f4f09c93162b33b0d9f7307a4eaaa52104437fed66f8ee3eabbd45d67b25a8133f496468b52baffdbfad93eef1a9818b5e42ec722788a3d8d3529fc777d2ba570801dfae01ec88302837c1fb9e0355727645ee1046c3f915f6ae82dad4fb6b0356a46518ffc834155c3b4fe6dafa6cc8a5ccf53c73a0849d8d44f7dcf72754e70e1b7dfb447bb4ef49d1a718f6171bbce200950e0ce926106b151a3e871d5ce49731bd6650a9b0ca972da1c5f136d44820ea6383c08f3b384cf2338e789c513f618cc5694a6f0cee104511e1ed7c5f23a1ebfd8a0db8424553240156dbf622831b0c643d1c551b6f3f7a98d29b85c2de05a65fa615eee16495bd90737672115b53e91c5d90028cf3f1a93953a153de53b44084e9ccff6b736693926daefebb2d77aa5ad689b92f31686669df16d1715cc58f7a2cfb72dd1a51e92f825993a74022be7e9eb6054654457094d14928f20215e7b222ac56b51adbec8d8bdb6983979a7e3a21b44b5d1518ca97d0b5195f51ed6a24350c89747e1edea51b448e3e9147054ce927873c90db394d86888e07dff177593d6f79e152302204aeb03be2386af3e24078bd028b1689f5e147c9f452c8ceb02ec59cc9db63a03576ceeafe98239023897da0236630a53c0de7f435a19869792fab36e7b9e635760f09069e6432e700035ac2a02879fff0a1e1bec522047193d94eb5df1efd53eea1144ca78940852f5ec9727904b366ede4f5e2d331fad5fc282ea2c47e923142771c3dd75a87357487def99e5f18e9d9ed623c175d02888c51f82c07a80d54716b3c3c2bdbe2e9f0a9bbaaebeb4d52936876406f5c00e8e4bbd0a5ec05797e6207c5ab6c88f1a688421bd05a114f4d7de2ac241fa0e8bedff47f762ddcbeaa91004f8d31e85095c81054994ad3826e344ba96040810fc0b2ad1de48cfade002c62e5a49a0731ab38344bc1636df16bf607d56855e56d684003c718e4bad9e5a099979fcddeeb1c4a7776cd37a3417cb0e184e29ef9bc0e87475ba663be09e00ab562eb7c0f7165f969a9b42414198ccf1bff2a2c8d689a414ece7662927665689e94db961ebaec5615cbc1a7895c6851ac961432ff1118d4607d32ef9dc732d51333be4b4d0e30ddea784eca8be47e741be9c19631dc470a52ef4dc13a4f3633fd434d787c170977b417df598e1d0dde506bb71d6f0bc17ec70e3b03cdc1965cb36993f633b0472e50d0923ac6c66fdf1d3e6459cc121f0f5f94d09e9dbcf5d690e23233838a0bacb7c638d1b2650a4308cd171b6855126d1da672a6ed85a8d78c286fb56f4ab3d21497528045c63262c8a42af2f9802c53b7bb8be28e78fe0b5ce45fbb7a1af1a3b28a8d94b7890e3c882e39bc98e9f0ad76025bf0dd2f00298e7141a226b3d7cee414f604d1e0ba54d11d5fe58bccea6ad77ad2e8c1caacf32459014b7b91001b1efa8ad172a523fb8e365b577121bf9fd88a2c60c21e821d7b6acb47a5a995e40caced5c223b8fe6de5e18e9d2e5893aefebb7aae7ff1a146260e2f110e939528213a0025a38ec79aabc861b25ebc509a4674c132aaacb7e0146f14efd11cfcaf4caa4f775a716ce325e0a435a4d349d720bcf137450afc45046fc1a1f83a9d329777a7084e4aadae7122ce97005930528eb3c7f7f1129b372887a371155a3ba201a25cbf1dcb64e7cdee092c3141fb5550fe3d0dd82e870e578b2b46500818113b8f6569773c677385b69a42b77dcba7acffd95fd4452e23aaa1d37e1da2151ea658d40a3596b27ac9f8129dc6cf0643772624b59f4f461230df471ca26087c3942d5c6687df6082835935a3f87cb762b0c3b1d0dda4a6533965bef1b7b8292e254c014d090fed857c44c1839c694c0a64e3fad90a11f534722b6ee1574f2e149d55d744de4887024e08511431c062750e16c74ab9f3242f2db3ffb12a8d6107faa229d6f6373b07f36d3932b3bdb04c19dd64eadd7f93c3c564c358a1c81dcf1c9c31e5b06568f97544c17dc15698c5cb38983a9afc42783faa773a52c9d8260690be9e3156aa5bc1509dea3f69587695cd6ff172ba83e6a6d8a7d6bbebbbcda3672731983f89bc5831dc37c3f3c5c56facc697f3cb20bd5dbadbd702e54844ac2f626901fe159db93dfd4773d8fe73562b846c1fc856d1802762840ebc72d7988bde75cbca70d319d32ce0cc0253bb2ad455723ee0c7f4736ce6e6665c5aca32a481c53839bc259167b013d0423395eeb9aaaee3206149a7d550d67fc5fdfe4a8a5c35d2510b664379ab8f72855a2af47abce2a632048eaf89e5cb4a88debc53a595103acce4f1cff18acff07afe1eb5716aa1e40b63134c3a3ae9579fa87f515be093c2d29db6d6b65c93661e00636b592704d093cc6716c2342eb1853d48c85c63ac8a2854462c7b77e7e3bd1eac5bca28ffaa00b5d349f8a547ad875b96a8c2b2910c9301309a3f9138a5693111f55b3c009ca947c39dfc82d98eb1caa4a9cbe885f786fa86e55be062222f8ba90a974073326b31212aece0a34a60").unwrap()).unwrap(); - let pk = MLDSA87PublicKey::from_bytes(&[0x97,0x92,0xbc,0xec,0x2f,0x24,0x30,0x68,0x6a,0x82,0xfc,0xcf,0x3c,0x2f,0x5f,0xf6,0x65,0xe7,0x71,0xd7,0xab,0x41,0xb9,0x02,0x58,0xcf,0xa7,0xe9,0x0e,0xc9,0x71,0x24,0xa7,0x3b,0x32,0x3b,0x9b,0xa2,0x1a,0xb6,0x4d,0x76,0x7c,0x43,0x3f,0x5a,0x52,0x1e,0xff,0xe1,0x8f,0x86,0xe4,0x6a,0x18,0x89,0x52,0xc4,0x46,0x7e,0x04,0x8b,0x72,0x9e,0x7f,0xc4,0xd1,0x15,0xe7,0xe4,0x8d,0xa1,0x89,0x6d,0x5f,0xe1,0x19,0xb1,0x0d,0xcd,0xde,0xf6,0x2c,0xb3,0x07,0x95,0x40,0x74,0xb4,0x23,0x36,0xe5,0x28,0x36,0xde,0x61,0xda,0x94,0x1f,0x8d,0x37,0xea,0x68,0xac,0x81,0x06,0xfa,0xbe,0x19,0x07,0x06,0x79,0xaf,0x60,0x08,0x53,0x71,0x20,0xf7,0x07,0x93,0xb8,0xea,0x9c,0xc0,0xe6,0xe7,0xb7,0xb4,0xc9,0xa5,0xc7,0x42,0x1c,0x60,0xf2,0x44,0x51,0xba,0x1e,0x93,0x3d,0xb1,0xa2,0xee,0x16,0xc7,0x95,0x59,0xf2,0x1b,0x3d,0x1b,0x83,0x05,0x85,0x0a,0xa4,0x2a,0xfb,0xb1,0x3f,0x1f,0x4d,0x5b,0x9f,0x48,0x35,0xf9,0xd8,0x7d,0xfc,0xeb,0x16,0x2d,0x0e,0xf4,0xa7,0xfd,0xc4,0xcb,0xa1,0x74,0x3c,0xd1,0xc8,0x7b,0xb4,0x96,0x7d,0xa1,0x6c,0xc8,0x76,0x4b,0x65,0x69,0xdf,0x8e,0xe5,0xbd,0xcb,0xff,0xe9,0xa4,0xe0,0x57,0x48,0xe6,0xfd,0xf2,0x25,0xaf,0x9e,0x4e,0xeb,0x77,0x73,0xb6,0x2e,0x8f,0x85,0xf9,0xb5,0x6b,0x54,0x89,0x45,0x55,0x18,0x44,0xfb,0xd8,0x98,0x06,0xa4,0xac,0x36,0x9b,0xed,0x2d,0x25,0x61,0x00,0xf6,0x88,0xa6,0xad,0x5e,0x0a,0x70,0x98,0x26,0xdc,0x44,0x49,0xe9,0x1e,0x23,0xc5,0x50,0x6e,0x64,0x23,0x61,0xef,0x5a,0x31,0x37,0x12,0xf7,0x9b,0xc4,0xb3,0x18,0x68,0x61,0xca,0x85,0xa4,0xba,0xb1,0x7e,0x7f,0x94,0x3d,0x1b,0x8a,0x33,0x3a,0xa3,0xae,0x7c,0xe1,0x6b,0x44,0x0d,0x60,0x18,0xf9,0xe0,0x4d,0xaf,0x57,0x25,0xc7,0xf1,0xa9,0x3f,0xad,0x1a,0x5a,0x27,0xb6,0x78,0x95,0xbd,0x24,0x9a,0xa9,0x16,0x85,0xde,0x20,0xaf,0x32,0xc8,0xb7,0xe2,0x68,0xc7,0xf9,0x68,0x77,0xd0,0xc8,0x50,0x01,0x13,0x5a,0x4f,0x0a,0x8f,0x1b,0x82,0x64,0xfa,0x6e,0xbe,0x5a,0x34,0x9d,0x8a,0xec,0xad,0x1a,0x16,0x29,0x9c,0xcf,0x2f,0xd9,0xc7,0xb8,0x5b,0xac,0xe2,0xce,0xd3,0xaa,0x12,0x76,0xba,0x61,0xee,0x78,0xed,0x7e,0x5c,0xa5,0xb6,0x7c,0xdd,0x45,0x8a,0x93,0x54,0x03,0x0e,0x6a,0xbb,0xba,0xbf,0x56,0xa0,0xa2,0x31,0x6f,0xec,0x9d,0xba,0x83,0xb5,0x1d,0x42,0xfd,0x31,0x67,0xf1,0xe0,0xf9,0x08,0x55,0xd5,0xc6,0x65,0x09,0xb2,0x10,0x26,0x5d,0xc1,0xe5,0x4e,0xc4,0x4b,0x43,0xba,0x7c,0xf9,0xae,0xf1,0x18,0xb4,0x4d,0x80,0x91,0x2c,0xe7,0x51,0x66,0xa6,0x65,0x1e,0x11,0x6c,0xeb,0xe4,0x92,0x29,0xa7,0x06,0x2c,0x09,0x93,0x1f,0x71,0xab,0xd2,0x29,0x3f,0x76,0xf7,0xef,0xc3,0x21,0x5b,0xa9,0x78,0x00,0x03,0x7e,0x58,0xe4,0x70,0xbd,0xbb,0xb4,0x3c,0x1b,0x04,0x39,0xea,0xf7,0x9c,0x54,0xd9,0x3b,0x44,0xaa,0xc9,0xef,0xe9,0xfb,0xe1,0x51,0x87,0x4c,0xfb,0x2a,0x64,0xcb,0xee,0x28,0xcc,0x4c,0x0f,0xe7,0x77,0x5e,0x5d,0x87,0x0f,0x1c,0x02,0xe5,0xb2,0xe3,0xc5,0x00,0x4c,0x99,0x5f,0x24,0xc9,0xb7,0x79,0xcb,0x75,0x3a,0x27,0x7d,0x0e,0x71,0xfd,0x42,0x5e,0xb6,0xbc,0x2c,0xa5,0x6c,0xe1,0x29,0xdb,0x51,0xf7,0x07,0x40,0xf3,0x1e,0x63,0x97,0x6b,0x50,0xc7,0x31,0x2e,0x97,0x97,0xd7,0x8c,0x5b,0x1a,0xc2,0x4a,0x5f,0xa3,0x47,0xcc,0x91,0x6e,0x0a,0x83,0xf5,0xc3,0xb6,0x75,0xcd,0x30,0xb8,0x1e,0x3f,0xa1,0x0b,0x93,0x44,0x4e,0x07,0x39,0x75,0x71,0xcc,0xe9,0x8b,0x28,0xda,0x51,0xdb,0x90,0x56,0xbc,0x72,0x8c,0x5b,0x0b,0x11,0x81,0xe2,0xfb,0xd3,0x87,0xb4,0xc7,0x9a,0xb1,0xa5,0xfe,0xfe,0xce,0x37,0x16,0x7a,0xf7,0x72,0xdd,0xad,0x14,0xeb,0x4c,0x39,0x82,0xda,0x5a,0x59,0xd0,0xe9,0xeb,0x17,0x3e,0xc6,0x31,0x50,0x91,0x17,0x00,0x27,0xa3,0xab,0x5e,0xf6,0xaa,0x12,0x9c,0xb8,0x58,0x57,0x27,0xb9,0x35,0x8a,0x28,0x50,0x1d,0x71,0x3a,0x72,0xf3,0xf1,0xdb,0x31,0x71,0x42,0x86,0xf9,0xb6,0x40,0x80,0x13,0xaf,0x06,0x04,0x5d,0x75,0x59,0x2f,0xc0,0xb7,0xdd,0x47,0xc7,0x3e,0xd9,0xc7,0x5b,0x11,0xe9,0xd7,0xc6,0x9f,0x7c,0xad,0xfc,0x32,0x80,0xa9,0x06,0x2c,0x52,0x73,0xc4,0x3b,0xe1,0xc3,0x4f,0x87,0x44,0x88,0x64,0xce,0xa7,0xb5,0xc9,0x7d,0x6d,0x32,0xf5,0x9b,0xd5,0xf2,0x53,0x84,0x65,0x3b,0xb5,0xc4,0xfa,0xa4,0x5b,0xea,0x8b,0x89,0x40,0x28,0x43,0xe6,0x45,0xb6,0xb9,0x26,0x9e,0x2b,0xd9,0x88,0xdd,0xac,0xb0,0x33,0x32,0x8f,0xfb,0x06,0x04,0x50,0xf7,0xdf,0x08,0x00,0x53,0xe6,0x96,0x9b,0x25,0x1e,0x87,0x5e,0xce,0xc3,0x2c,0xfc,0x59,0x28,0x40,0xd6,0x9a,0xb6,0x9a,0x75,0xe0,0x6b,0x37,0x9c,0x53,0x5d,0x95,0x26,0x6b,0x08,0x2f,0x4f,0x09,0xc9,0x31,0x62,0xb3,0x3b,0x0d,0x9f,0x73,0x07,0xa4,0xea,0xaa,0x52,0x10,0x44,0x37,0xfe,0xd6,0x6f,0x8e,0xe3,0xea,0xbb,0xd4,0x5d,0x67,0xb2,0x5a,0x81,0x33,0xf4,0x96,0x46,0x8b,0x52,0xba,0xff,0xdb,0xfa,0xd9,0x3e,0xef,0x1a,0x98,0x18,0xb5,0xe4,0x2e,0xc7,0x22,0x78,0x8a,0x3d,0x8d,0x35,0x29,0xfc,0x77,0x7d,0x2b,0xa5,0x70,0x80,0x1d,0xfa,0xe0,0x1e,0xc8,0x83,0x02,0x83,0x7c,0x1f,0xb9,0xe0,0x35,0x57,0x27,0x64,0x5e,0xe1,0x04,0x6c,0x3f,0x91,0x5f,0x6a,0xe8,0x2d,0xad,0x4f,0xb6,0xb0,0x35,0x6a,0x46,0x51,0x8f,0xfc,0x83,0x41,0x55,0xc3,0xb4,0xfe,0x6d,0xaf,0xa6,0xcc,0x8a,0x5c,0xcf,0x53,0xc7,0x3a,0x08,0x49,0xd8,0xd4,0x4f,0x7d,0xcf,0x72,0x75,0x4e,0x70,0xe1,0xb7,0xdf,0xb4,0x47,0xbb,0x4e,0xf4,0x9d,0x1a,0x71,0x8f,0x61,0x71,0xbb,0xce,0x20,0x09,0x50,0xe0,0xce,0x92,0x61,0x06,0xb1,0x51,0xa3,0xe8,0x71,0xd5,0xce,0x49,0x73,0x1b,0xd6,0x65,0x0a,0x9b,0x0c,0xa9,0x72,0xda,0x1c,0x5f,0x13,0x6d,0x44,0x82,0x0e,0xa6,0x38,0x3c,0x08,0xf3,0xb3,0x84,0xcf,0x23,0x38,0xe7,0x89,0xc5,0x13,0xf6,0x18,0xcc,0x56,0x94,0xa6,0xf0,0xce,0xe1,0x04,0x51,0x1e,0x1e,0xd7,0xc5,0xf2,0x3a,0x1e,0xbf,0xd8,0xa0,0xdb,0x84,0x24,0x55,0x32,0x40,0x15,0x6d,0xbf,0x62,0x28,0x31,0xb0,0xc6,0x43,0xd1,0xc5,0x51,0xb6,0xf3,0xf7,0xa9,0x8d,0x29,0xb8,0x5c,0x2d,0xe0,0x5a,0x65,0xfa,0x61,0x5e,0xee,0x16,0x49,0x5b,0xd9,0x07,0x37,0x67,0x21,0x15,0xb5,0x3e,0x91,0xc5,0xd9,0x00,0x28,0xcf,0x3f,0x1a,0x93,0x95,0x3a,0x15,0x3d,0xe5,0x3b,0x44,0x08,0x4e,0x9c,0xcf,0xf6,0xb7,0x36,0x69,0x39,0x26,0xda,0xef,0xeb,0xb2,0xd7,0x7a,0xa5,0xad,0x68,0x9b,0x92,0xf3,0x16,0x86,0x66,0x9d,0xf1,0x6d,0x17,0x15,0xcc,0x58,0xf7,0xa2,0xcf,0xb7,0x2d,0xd1,0xa5,0x1e,0x92,0xf8,0x25,0x99,0x3a,0x74,0x02,0x2b,0xe7,0xe9,0xeb,0x60,0x54,0x65,0x44,0x57,0x09,0x4d,0x14,0x92,0x8f,0x20,0x21,0x5e,0x7b,0x22,0x2a,0xc5,0x6b,0x51,0xad,0xbe,0xc8,0xd8,0xbd,0xb6,0x98,0x39,0x79,0xa7,0xe3,0xa2,0x1b,0x44,0xb5,0xd1,0x51,0x8c,0xa9,0x7d,0x0b,0x51,0x95,0xf5,0x1e,0xd6,0xa2,0x43,0x50,0xc8,0x97,0x47,0xe1,0xed,0xea,0x51,0xb4,0x48,0xe3,0xe9,0x14,0x70,0x54,0xce,0x92,0x78,0x73,0xc9,0x0d,0xb3,0x94,0xd8,0x68,0x88,0xe0,0x7d,0xff,0x17,0x75,0x93,0xd6,0xf7,0x9e,0x15,0x23,0x02,0x20,0x4a,0xeb,0x03,0xbe,0x23,0x86,0xaf,0x3e,0x24,0x07,0x8b,0xd0,0x28,0xb1,0x68,0x9f,0x5e,0x14,0x7c,0x9f,0x45,0x2c,0x8c,0xeb,0x02,0xec,0x59,0xcc,0x9d,0xb6,0x3a,0x03,0x57,0x6c,0xee,0xaf,0xe9,0x82,0x39,0x02,0x38,0x97,0xda,0x02,0x36,0x63,0x0a,0x53,0xc0,0xde,0x7f,0x43,0x5a,0x19,0x86,0x97,0x92,0xfa,0xb3,0x6e,0x7b,0x9e,0x63,0x57,0x60,0xf0,0x90,0x69,0xe6,0x43,0x2e,0x70,0x00,0x35,0xac,0x2a,0x02,0x87,0x9f,0xff,0x0a,0x1e,0x1b,0xec,0x52,0x20,0x47,0x19,0x3d,0x94,0xeb,0x5d,0xf1,0xef,0xd5,0x3e,0xea,0x11,0x44,0xca,0x78,0x94,0x08,0x52,0xf5,0xec,0x97,0x27,0x90,0x4b,0x36,0x6e,0xde,0x4f,0x5e,0x2d,0x33,0x1f,0xad,0x5f,0xc2,0x82,0xea,0x2c,0x47,0xe9,0x23,0x14,0x27,0x71,0xc3,0xdd,0x75,0xa8,0x73,0x57,0x48,0x7d,0xef,0x99,0xe5,0xf1,0x8e,0x9d,0x9e,0xd6,0x23,0xc1,0x75,0xd0,0x28,0x88,0xc5,0x1f,0x82,0xc0,0x7a,0x80,0xd5,0x47,0x16,0xb3,0xc3,0xc2,0xbd,0xbe,0x2e,0x9f,0x0a,0x9b,0xba,0xae,0xbe,0xb4,0xd5,0x29,0x36,0x87,0x64,0x06,0xf5,0xc0,0x0e,0x8e,0x4b,0xbd,0x0a,0x5e,0xc0,0x57,0x97,0xe6,0x20,0x7c,0x5a,0xb6,0xc8,0x8f,0x1a,0x68,0x84,0x21,0xbd,0x05,0xa1,0x14,0xf4,0xd7,0xde,0x2a,0xc2,0x41,0xfa,0x0e,0x8b,0xed,0xff,0x47,0xf7,0x62,0xdd,0xcb,0xea,0xa9,0x10,0x04,0xf8,0xd3,0x1e,0x85,0x09,0x5c,0x81,0x05,0x49,0x94,0xad,0x38,0x26,0xe3,0x44,0xba,0x96,0x04,0x08,0x10,0xfc,0x0b,0x2a,0xd1,0xde,0x48,0xcf,0xad,0xe0,0x02,0xc6,0x2e,0x5a,0x49,0xa0,0x73,0x1a,0xb3,0x83,0x44,0xbc,0x16,0x36,0xdf,0x16,0xbf,0x60,0x7d,0x56,0x85,0x5e,0x56,0xd6,0x84,0x00,0x3c,0x71,0x8e,0x4b,0xad,0x9e,0x5a,0x09,0x99,0x79,0xfc,0xdd,0xee,0xb1,0xc4,0xa7,0x77,0x6c,0xd3,0x7a,0x34,0x17,0xcb,0x0e,0x18,0x4e,0x29,0xef,0x9b,0xc0,0xe8,0x74,0x75,0xba,0x66,0x3b,0xe0,0x9e,0x00,0xab,0x56,0x2e,0xb7,0xc0,0xf7,0x16,0x5f,0x96,0x9a,0x9b,0x42,0x41,0x41,0x98,0xcc,0xf1,0xbf,0xf2,0xa2,0xc8,0xd6,0x89,0xa4,0x14,0xec,0xe7,0x66,0x29,0x27,0x66,0x56,0x89,0xe9,0x4d,0xb9,0x61,0xeb,0xae,0xc5,0x61,0x5c,0xbc,0x1a,0x78,0x95,0xc6,0x85,0x1a,0xc9,0x61,0x43,0x2f,0xf1,0x11,0x8d,0x46,0x07,0xd3,0x2e,0xf9,0xdc,0x73,0x2d,0x51,0x33,0x3b,0xe4,0xb4,0xd0,0xe3,0x0d,0xde,0xa7,0x84,0xec,0xa8,0xbe,0x47,0xe7,0x41,0xbe,0x9c,0x19,0x63,0x1d,0xc4,0x70,0xa5,0x2e,0xf4,0xdc,0x13,0xa4,0xf3,0x63,0x3f,0xd4,0x34,0xd7,0x87,0xc1,0x70,0x97,0x7b,0x41,0x7d,0xf5,0x98,0xe1,0xd0,0xdd,0xe5,0x06,0xbb,0x71,0xd6,0xf0,0xbc,0x17,0xec,0x70,0xe3,0xb0,0x3c,0xdc,0x19,0x65,0xcb,0x36,0x99,0x3f,0x63,0x3b,0x04,0x72,0xe5,0x0d,0x09,0x23,0xac,0x6c,0x66,0xfd,0xf1,0xd3,0xe6,0x45,0x9c,0xc1,0x21,0xf0,0xf5,0xf9,0x4d,0x09,0xe9,0xdb,0xcf,0x5d,0x69,0x0e,0x23,0x23,0x38,0x38,0xa0,0xba,0xcb,0x7c,0x63,0x8d,0x1b,0x26,0x50,0xa4,0x30,0x8c,0xd1,0x71,0xb6,0x85,0x51,0x26,0xd1,0xda,0x67,0x2a,0x6e,0xd8,0x5a,0x8d,0x78,0xc2,0x86,0xfb,0x56,0xf4,0xab,0x3d,0x21,0x49,0x75,0x28,0x04,0x5c,0x63,0x26,0x2c,0x8a,0x42,0xaf,0x2f,0x98,0x02,0xc5,0x3b,0x7b,0xb8,0xbe,0x28,0xe7,0x8f,0xe0,0xb5,0xce,0x45,0xfb,0xb7,0xa1,0xaf,0x1a,0x3b,0x28,0xa8,0xd9,0x4b,0x78,0x90,0xe3,0xc8,0x82,0xe3,0x9b,0xc9,0x8e,0x9f,0x0a,0xd7,0x60,0x25,0xbf,0x0d,0xd2,0xf0,0x02,0x98,0xe7,0x14,0x1a,0x22,0x6b,0x3d,0x7c,0xee,0x41,0x4f,0x60,0x4d,0x1e,0x0b,0xa5,0x4d,0x11,0xd5,0xfe,0x58,0xbc,0xce,0xa6,0xad,0x77,0xad,0x2e,0x8c,0x1c,0xaa,0xcf,0x32,0x45,0x90,0x14,0xb7,0xb9,0x10,0x01,0xb1,0xef,0xa8,0xad,0x17,0x2a,0x52,0x3f,0xb8,0xe3,0x65,0xb5,0x77,0x12,0x1b,0xf9,0xfd,0x88,0xa2,0xc6,0x0c,0x21,0xe8,0x21,0xd7,0xb6,0xac,0xb4,0x7a,0x5a,0x99,0x5e,0x40,0xca,0xce,0xd5,0xc2,0x23,0xb8,0xfe,0x6d,0xe5,0xe1,0x8e,0x9d,0x2e,0x58,0x93,0xae,0xfe,0xbb,0x7a,0xae,0x7f,0xf1,0xa1,0x46,0x26,0x0e,0x2f,0x11,0x0e,0x93,0x95,0x28,0x21,0x3a,0x00,0x25,0xa3,0x8e,0xc7,0x9a,0xab,0xc8,0x61,0xb2,0x5e,0xbc,0x50,0x9a,0x46,0x74,0xc1,0x32,0xaa,0xac,0xb7,0xe0,0x14,0x6f,0x14,0xef,0xd1,0x1c,0xfc,0xaf,0x4c,0xaa,0x4f,0x77,0x5a,0x71,0x6c,0xe3,0x25,0xe0,0xa4,0x35,0xa4,0xd3,0x49,0xd7,0x20,0xbc,0xf1,0x37,0x45,0x0a,0xfc,0x45,0x04,0x6f,0xc1,0xa1,0xf8,0x3a,0x9d,0x32,0x97,0x77,0xa7,0x08,0x4e,0x4a,0xad,0xae,0x71,0x22,0xce,0x97,0x00,0x59,0x30,0x52,0x8e,0xb3,0xc7,0xf7,0xf1,0x12,0x9b,0x37,0x28,0x87,0xa3,0x71,0x15,0x5a,0x3b,0xa2,0x01,0xa2,0x5c,0xbf,0x1d,0xcb,0x64,0xe7,0xcd,0xee,0x09,0x2c,0x31,0x41,0xfb,0x55,0x50,0xfe,0x3d,0x0d,0xd8,0x2e,0x87,0x0e,0x57,0x8b,0x2b,0x46,0x50,0x08,0x18,0x11,0x3b,0x8f,0x65,0x69,0x77,0x3c,0x67,0x73,0x85,0xb6,0x9a,0x42,0xb7,0x7d,0xcb,0xa7,0xac,0xff,0xd9,0x5f,0xd4,0x45,0x2e,0x23,0xaa,0xa1,0xd3,0x7e,0x1d,0xa2,0x15,0x1e,0xa6,0x58,0xd4,0x0a,0x35,0x96,0xb2,0x7a,0xc9,0xf8,0x12,0x9d,0xc6,0xcf,0x06,0x43,0x77,0x26,0x24,0xb5,0x9f,0x4f,0x46,0x12,0x30,0xdf,0x47,0x1c,0xa2,0x60,0x87,0xc3,0x94,0x2d,0x5c,0x66,0x87,0xdf,0x60,0x82,0x83,0x59,0x35,0xa3,0xf8,0x7c,0xb7,0x62,0xb0,0xc3,0xb1,0xd0,0xdd,0xa4,0xa6,0x53,0x39,0x65,0xbe,0xf1,0xb7,0xb8,0x29,0x2e,0x25,0x4c,0x01,0x4d,0x09,0x0f,0xed,0x85,0x7c,0x44,0xc1,0x83,0x9c,0x69,0x4c,0x0a,0x64,0xe3,0xfa,0xd9,0x0a,0x11,0xf5,0x34,0x72,0x2b,0x6e,0xe1,0x57,0x4f,0x2e,0x14,0x9d,0x55,0xd7,0x44,0xde,0x48,0x87,0x02,0x4e,0x08,0x51,0x14,0x31,0xc0,0x62,0x75,0x0e,0x16,0xc7,0x4a,0xb9,0xf3,0x24,0x2f,0x2d,0xb3,0xff,0xb1,0x2a,0x8d,0x61,0x07,0xfa,0xa2,0x29,0xd6,0xf6,0x37,0x3b,0x07,0xf3,0x6d,0x39,0x32,0xb3,0xbd,0xb0,0x4c,0x19,0xdd,0x64,0xea,0xdd,0x7f,0x93,0xc3,0xc5,0x64,0xc3,0x58,0xa1,0xc8,0x1d,0xcf,0x1c,0x9c,0x31,0xe5,0xb0,0x65,0x68,0xf9,0x75,0x44,0xc1,0x7d,0xc1,0x56,0x98,0xc5,0xcb,0x38,0x98,0x3a,0x9a,0xfc,0x42,0x78,0x3f,0xaa,0x77,0x3a,0x52,0xc9,0xd8,0x26,0x06,0x90,0xbe,0x9e,0x31,0x56,0xaa,0x5b,0xc1,0x50,0x9d,0xea,0x3f,0x69,0x58,0x76,0x95,0xcd,0x6f,0xf1,0x72,0xba,0x83,0xe6,0xa6,0xd8,0xa7,0xd6,0xbb,0xeb,0xbb,0xcd,0xa3,0x67,0x27,0x31,0x98,0x3f,0x89,0xbc,0x58,0x31,0xdc,0x37,0xc3,0xf3,0xc5,0xc5,0x6f,0xac,0xc6,0x97,0xf3,0xcb,0x20,0xbd,0x5d,0xba,0xdb,0xd7,0x02,0xe5,0x48,0x44,0xac,0x2f,0x62,0x69,0x01,0xfe,0x15,0x9d,0xb9,0x3d,0xfd,0x47,0x73,0xd8,0xfe,0x73,0x56,0x2b,0x84,0x6c,0x1f,0xc8,0x56,0xd1,0x80,0x27,0x62,0x84,0x0e,0xbc,0x72,0xd7,0x98,0x8b,0xde,0x75,0xcb,0xca,0x70,0xd3,0x19,0xd3,0x2c,0xe0,0xcc,0x02,0x53,0xbb,0x2a,0xd4,0x55,0x72,0x3e,0xe0,0xc7,0xf4,0x73,0x6c,0xe6,0xe6,0x66,0x5c,0x5a,0xca,0x32,0xa4,0x81,0xc5,0x38,0x39,0xbc,0x25,0x91,0x67,0xb0,0x13,0xd0,0x42,0x33,0x95,0xee,0xb9,0xaa,0xae,0xe3,0x20,0x61,0x49,0xa7,0xd5,0x50,0xd6,0x7f,0xc5,0xfd,0xfe,0x4a,0x8a,0x5c,0x35,0xd2,0x51,0x0b,0x66,0x43,0x79,0xab,0x8f,0x72,0x85,0x5a,0x2a,0xf4,0x7a,0xbc,0xe2,0xa6,0x32,0x04,0x8e,0xaf,0x89,0xe5,0xcb,0x4a,0x88,0xde,0xbc,0x53,0xa5,0x95,0x10,0x3a,0xcc,0xe4,0xf1,0xcf,0xf1,0x8a,0xcf,0xf0,0x7a,0xfe,0x1e,0xb5,0x71,0x6a,0xa1,0xe4,0x0b,0x63,0x13,0x4c,0x3a,0x3a,0xe9,0x57,0x9f,0xa8,0x7f,0x51,0x5b,0xe0,0x93,0xc2,0xd2,0x9d,0xb6,0xd6,0xb6,0x5c,0x93,0x66,0x1e,0x00,0x63,0x6b,0x59,0x27,0x04,0xd0,0x93,0xcc,0x67,0x16,0xc2,0x34,0x2e,0xb1,0x85,0x3d,0x48,0xc8,0x5c,0x63,0xac,0x8a,0x28,0x54,0x46,0x2c,0x7b,0x77,0xe7,0xe3,0xbd,0x1e,0xac,0x5b,0xca,0x28,0xff,0xaa,0x00,0xb5,0xd3,0x49,0xf8,0xa5,0x47,0xad,0x87,0x5b,0x96,0xa8,0xc2,0xb2,0x91,0x0c,0x93,0x01,0x30,0x9a,0x3f,0x91,0x38,0xa5,0x69,0x31,0x11,0xf5,0x5b,0x3c,0x00,0x9c,0xa9,0x47,0xc3,0x9d,0xfc,0x82,0xd9,0x8e,0xb1,0xca,0xa4,0xa9,0xcb,0xe8,0x85,0xf7,0x86,0xfa,0x86,0xe5,0x5b,0xe0,0x62,0x22,0x2f,0x8b,0xa9,0x0a,0x97,0x40,0x73,0x32,0x6b,0x31,0x21,0x2a,0xec,0xe0,0xa3,0x4a,0x60]).unwrap(); + let pk = MLDSA87PublicKey::from_bytes(&[ + 0x97, 0x92, 0xBC, 0xEC, 0x2F, 0x24, 0x30, 0x68, 0x6A, 0x82, 0xFC, 0xCF, 0x3C, 0x2F, 0x5F, + 0xF6, 0x65, 0xE7, 0x71, 0xD7, 0xAB, 0x41, 0xB9, 0x02, 0x58, 0xCF, 0xA7, 0xE9, 0x0E, 0xC9, + 0x71, 0x24, 0xA7, 0x3B, 0x32, 0x3B, 0x9B, 0xA2, 0x1A, 0xB6, 0x4D, 0x76, 0x7C, 0x43, 0x3F, + 0x5A, 0x52, 0x1E, 0xFF, 0xE1, 0x8F, 0x86, 0xE4, 0x6A, 0x18, 0x89, 0x52, 0xC4, 0x46, 0x7E, + 0x04, 0x8B, 0x72, 0x9E, 0x7F, 0xC4, 0xD1, 0x15, 0xE7, 0xE4, 0x8D, 0xA1, 0x89, 0x6D, 0x5F, + 0xE1, 0x19, 0xB1, 0x0D, 0xCD, 0xDE, 0xF6, 0x2C, 0xB3, 0x07, 0x95, 0x40, 0x74, 0xB4, 0x23, + 0x36, 0xE5, 0x28, 0x36, 0xDE, 0x61, 0xDA, 0x94, 0x1F, 0x8D, 0x37, 0xEA, 0x68, 0xAC, 0x81, + 0x06, 0xFA, 0xBE, 0x19, 0x07, 0x06, 0x79, 0xAF, 0x60, 0x08, 0x53, 0x71, 0x20, 0xF7, 0x07, + 0x93, 0xB8, 0xEA, 0x9C, 0xC0, 0xE6, 0xE7, 0xB7, 0xB4, 0xC9, 0xA5, 0xC7, 0x42, 0x1C, 0x60, + 0xF2, 0x44, 0x51, 0xBA, 0x1E, 0x93, 0x3D, 0xB1, 0xA2, 0xEE, 0x16, 0xC7, 0x95, 0x59, 0xF2, + 0x1B, 0x3D, 0x1B, 0x83, 0x05, 0x85, 0x0A, 0xA4, 0x2A, 0xFB, 0xB1, 0x3F, 0x1F, 0x4D, 0x5B, + 0x9F, 0x48, 0x35, 0xF9, 0xD8, 0x7D, 0xFC, 0xEB, 0x16, 0x2D, 0x0E, 0xF4, 0xA7, 0xFD, 0xC4, + 0xCB, 0xA1, 0x74, 0x3C, 0xD1, 0xC8, 0x7B, 0xB4, 0x96, 0x7D, 0xA1, 0x6C, 0xC8, 0x76, 0x4B, + 0x65, 0x69, 0xDF, 0x8E, 0xE5, 0xBD, 0xCB, 0xFF, 0xE9, 0xA4, 0xE0, 0x57, 0x48, 0xE6, 0xFD, + 0xF2, 0x25, 0xAF, 0x9E, 0x4E, 0xEB, 0x77, 0x73, 0xB6, 0x2E, 0x8F, 0x85, 0xF9, 0xB5, 0x6B, + 0x54, 0x89, 0x45, 0x55, 0x18, 0x44, 0xFB, 0xD8, 0x98, 0x06, 0xA4, 0xAC, 0x36, 0x9B, 0xED, + 0x2D, 0x25, 0x61, 0x00, 0xF6, 0x88, 0xA6, 0xAD, 0x5E, 0x0A, 0x70, 0x98, 0x26, 0xDC, 0x44, + 0x49, 0xE9, 0x1E, 0x23, 0xC5, 0x50, 0x6E, 0x64, 0x23, 0x61, 0xEF, 0x5A, 0x31, 0x37, 0x12, + 0xF7, 0x9B, 0xC4, 0xB3, 0x18, 0x68, 0x61, 0xCA, 0x85, 0xA4, 0xBA, 0xB1, 0x7E, 0x7F, 0x94, + 0x3D, 0x1B, 0x8A, 0x33, 0x3A, 0xA3, 0xAE, 0x7C, 0xE1, 0x6B, 0x44, 0x0D, 0x60, 0x18, 0xF9, + 0xE0, 0x4D, 0xAF, 0x57, 0x25, 0xC7, 0xF1, 0xA9, 0x3F, 0xAD, 0x1A, 0x5A, 0x27, 0xB6, 0x78, + 0x95, 0xBD, 0x24, 0x9A, 0xA9, 0x16, 0x85, 0xDE, 0x20, 0xAF, 0x32, 0xC8, 0xB7, 0xE2, 0x68, + 0xC7, 0xF9, 0x68, 0x77, 0xD0, 0xC8, 0x50, 0x01, 0x13, 0x5A, 0x4F, 0x0A, 0x8F, 0x1B, 0x82, + 0x64, 0xFA, 0x6E, 0xBE, 0x5A, 0x34, 0x9D, 0x8A, 0xEC, 0xAD, 0x1A, 0x16, 0x29, 0x9C, 0xCF, + 0x2F, 0xD9, 0xC7, 0xB8, 0x5B, 0xAC, 0xE2, 0xCE, 0xD3, 0xAA, 0x12, 0x76, 0xBA, 0x61, 0xEE, + 0x78, 0xED, 0x7E, 0x5C, 0xA5, 0xB6, 0x7C, 0xDD, 0x45, 0x8A, 0x93, 0x54, 0x03, 0x0E, 0x6A, + 0xBB, 0xBA, 0xBF, 0x56, 0xA0, 0xA2, 0x31, 0x6F, 0xEC, 0x9D, 0xBA, 0x83, 0xB5, 0x1D, 0x42, + 0xFD, 0x31, 0x67, 0xF1, 0xE0, 0xF9, 0x08, 0x55, 0xD5, 0xC6, 0x65, 0x09, 0xB2, 0x10, 0x26, + 0x5D, 0xC1, 0xE5, 0x4E, 0xC4, 0x4B, 0x43, 0xBA, 0x7C, 0xF9, 0xAE, 0xF1, 0x18, 0xB4, 0x4D, + 0x80, 0x91, 0x2C, 0xE7, 0x51, 0x66, 0xA6, 0x65, 0x1E, 0x11, 0x6C, 0xEB, 0xE4, 0x92, 0x29, + 0xA7, 0x06, 0x2C, 0x09, 0x93, 0x1F, 0x71, 0xAB, 0xD2, 0x29, 0x3F, 0x76, 0xF7, 0xEF, 0xC3, + 0x21, 0x5B, 0xA9, 0x78, 0x00, 0x03, 0x7E, 0x58, 0xE4, 0x70, 0xBD, 0xBB, 0xB4, 0x3C, 0x1B, + 0x04, 0x39, 0xEA, 0xF7, 0x9C, 0x54, 0xD9, 0x3B, 0x44, 0xAA, 0xC9, 0xEF, 0xE9, 0xFB, 0xE1, + 0x51, 0x87, 0x4C, 0xFB, 0x2A, 0x64, 0xCB, 0xEE, 0x28, 0xCC, 0x4C, 0x0F, 0xE7, 0x77, 0x5E, + 0x5D, 0x87, 0x0F, 0x1C, 0x02, 0xE5, 0xB2, 0xE3, 0xC5, 0x00, 0x4C, 0x99, 0x5F, 0x24, 0xC9, + 0xB7, 0x79, 0xCB, 0x75, 0x3A, 0x27, 0x7D, 0x0E, 0x71, 0xFD, 0x42, 0x5E, 0xB6, 0xBC, 0x2C, + 0xA5, 0x6C, 0xE1, 0x29, 0xDB, 0x51, 0xF7, 0x07, 0x40, 0xF3, 0x1E, 0x63, 0x97, 0x6B, 0x50, + 0xC7, 0x31, 0x2E, 0x97, 0x97, 0xD7, 0x8C, 0x5B, 0x1A, 0xC2, 0x4A, 0x5F, 0xA3, 0x47, 0xCC, + 0x91, 0x6E, 0x0A, 0x83, 0xF5, 0xC3, 0xB6, 0x75, 0xCD, 0x30, 0xB8, 0x1E, 0x3F, 0xA1, 0x0B, + 0x93, 0x44, 0x4E, 0x07, 0x39, 0x75, 0x71, 0xCC, 0xE9, 0x8B, 0x28, 0xDA, 0x51, 0xDB, 0x90, + 0x56, 0xBC, 0x72, 0x8C, 0x5B, 0x0B, 0x11, 0x81, 0xE2, 0xFB, 0xD3, 0x87, 0xB4, 0xC7, 0x9A, + 0xB1, 0xA5, 0xFE, 0xFE, 0xCE, 0x37, 0x16, 0x7A, 0xF7, 0x72, 0xDD, 0xAD, 0x14, 0xEB, 0x4C, + 0x39, 0x82, 0xDA, 0x5A, 0x59, 0xD0, 0xE9, 0xEB, 0x17, 0x3E, 0xC6, 0x31, 0x50, 0x91, 0x17, + 0x00, 0x27, 0xA3, 0xAB, 0x5E, 0xF6, 0xAA, 0x12, 0x9C, 0xB8, 0x58, 0x57, 0x27, 0xB9, 0x35, + 0x8A, 0x28, 0x50, 0x1D, 0x71, 0x3A, 0x72, 0xF3, 0xF1, 0xDB, 0x31, 0x71, 0x42, 0x86, 0xF9, + 0xB6, 0x40, 0x80, 0x13, 0xAF, 0x06, 0x04, 0x5D, 0x75, 0x59, 0x2F, 0xC0, 0xB7, 0xDD, 0x47, + 0xC7, 0x3E, 0xD9, 0xC7, 0x5B, 0x11, 0xE9, 0xD7, 0xC6, 0x9F, 0x7C, 0xAD, 0xFC, 0x32, 0x80, + 0xA9, 0x06, 0x2C, 0x52, 0x73, 0xC4, 0x3B, 0xE1, 0xC3, 0x4F, 0x87, 0x44, 0x88, 0x64, 0xCE, + 0xA7, 0xB5, 0xC9, 0x7D, 0x6D, 0x32, 0xF5, 0x9B, 0xD5, 0xF2, 0x53, 0x84, 0x65, 0x3B, 0xB5, + 0xC4, 0xFA, 0xA4, 0x5B, 0xEA, 0x8B, 0x89, 0x40, 0x28, 0x43, 0xE6, 0x45, 0xB6, 0xB9, 0x26, + 0x9E, 0x2B, 0xD9, 0x88, 0xDD, 0xAC, 0xB0, 0x33, 0x32, 0x8F, 0xFB, 0x06, 0x04, 0x50, 0xF7, + 0xDF, 0x08, 0x00, 0x53, 0xE6, 0x96, 0x9B, 0x25, 0x1E, 0x87, 0x5E, 0xCE, 0xC3, 0x2C, 0xFC, + 0x59, 0x28, 0x40, 0xD6, 0x9A, 0xB6, 0x9A, 0x75, 0xE0, 0x6B, 0x37, 0x9C, 0x53, 0x5D, 0x95, + 0x26, 0x6B, 0x08, 0x2F, 0x4F, 0x09, 0xC9, 0x31, 0x62, 0xB3, 0x3B, 0x0D, 0x9F, 0x73, 0x07, + 0xA4, 0xEA, 0xAA, 0x52, 0x10, 0x44, 0x37, 0xFE, 0xD6, 0x6F, 0x8E, 0xE3, 0xEA, 0xBB, 0xD4, + 0x5D, 0x67, 0xB2, 0x5A, 0x81, 0x33, 0xF4, 0x96, 0x46, 0x8B, 0x52, 0xBA, 0xFF, 0xDB, 0xFA, + 0xD9, 0x3E, 0xEF, 0x1A, 0x98, 0x18, 0xB5, 0xE4, 0x2E, 0xC7, 0x22, 0x78, 0x8A, 0x3D, 0x8D, + 0x35, 0x29, 0xFC, 0x77, 0x7D, 0x2B, 0xA5, 0x70, 0x80, 0x1D, 0xFA, 0xE0, 0x1E, 0xC8, 0x83, + 0x02, 0x83, 0x7C, 0x1F, 0xB9, 0xE0, 0x35, 0x57, 0x27, 0x64, 0x5E, 0xE1, 0x04, 0x6C, 0x3F, + 0x91, 0x5F, 0x6A, 0xE8, 0x2D, 0xAD, 0x4F, 0xB6, 0xB0, 0x35, 0x6A, 0x46, 0x51, 0x8F, 0xFC, + 0x83, 0x41, 0x55, 0xC3, 0xB4, 0xFE, 0x6D, 0xAF, 0xA6, 0xCC, 0x8A, 0x5C, 0xCF, 0x53, 0xC7, + 0x3A, 0x08, 0x49, 0xD8, 0xD4, 0x4F, 0x7D, 0xCF, 0x72, 0x75, 0x4E, 0x70, 0xE1, 0xB7, 0xDF, + 0xB4, 0x47, 0xBB, 0x4E, 0xF4, 0x9D, 0x1A, 0x71, 0x8F, 0x61, 0x71, 0xBB, 0xCE, 0x20, 0x09, + 0x50, 0xE0, 0xCE, 0x92, 0x61, 0x06, 0xB1, 0x51, 0xA3, 0xE8, 0x71, 0xD5, 0xCE, 0x49, 0x73, + 0x1B, 0xD6, 0x65, 0x0A, 0x9B, 0x0C, 0xA9, 0x72, 0xDA, 0x1C, 0x5F, 0x13, 0x6D, 0x44, 0x82, + 0x0E, 0xA6, 0x38, 0x3C, 0x08, 0xF3, 0xB3, 0x84, 0xCF, 0x23, 0x38, 0xE7, 0x89, 0xC5, 0x13, + 0xF6, 0x18, 0xCC, 0x56, 0x94, 0xA6, 0xF0, 0xCE, 0xE1, 0x04, 0x51, 0x1E, 0x1E, 0xD7, 0xC5, + 0xF2, 0x3A, 0x1E, 0xBF, 0xD8, 0xA0, 0xDB, 0x84, 0x24, 0x55, 0x32, 0x40, 0x15, 0x6D, 0xBF, + 0x62, 0x28, 0x31, 0xB0, 0xC6, 0x43, 0xD1, 0xC5, 0x51, 0xB6, 0xF3, 0xF7, 0xA9, 0x8D, 0x29, + 0xB8, 0x5C, 0x2D, 0xE0, 0x5A, 0x65, 0xFA, 0x61, 0x5E, 0xEE, 0x16, 0x49, 0x5B, 0xD9, 0x07, + 0x37, 0x67, 0x21, 0x15, 0xB5, 0x3E, 0x91, 0xC5, 0xD9, 0x00, 0x28, 0xCF, 0x3F, 0x1A, 0x93, + 0x95, 0x3A, 0x15, 0x3D, 0xE5, 0x3B, 0x44, 0x08, 0x4E, 0x9C, 0xCF, 0xF6, 0xB7, 0x36, 0x69, + 0x39, 0x26, 0xDA, 0xEF, 0xEB, 0xB2, 0xD7, 0x7A, 0xA5, 0xAD, 0x68, 0x9B, 0x92, 0xF3, 0x16, + 0x86, 0x66, 0x9D, 0xF1, 0x6D, 0x17, 0x15, 0xCC, 0x58, 0xF7, 0xA2, 0xCF, 0xB7, 0x2D, 0xD1, + 0xA5, 0x1E, 0x92, 0xF8, 0x25, 0x99, 0x3A, 0x74, 0x02, 0x2B, 0xE7, 0xE9, 0xEB, 0x60, 0x54, + 0x65, 0x44, 0x57, 0x09, 0x4D, 0x14, 0x92, 0x8F, 0x20, 0x21, 0x5E, 0x7B, 0x22, 0x2A, 0xC5, + 0x6B, 0x51, 0xAD, 0xBE, 0xC8, 0xD8, 0xBD, 0xB6, 0x98, 0x39, 0x79, 0xA7, 0xE3, 0xA2, 0x1B, + 0x44, 0xB5, 0xD1, 0x51, 0x8C, 0xA9, 0x7D, 0x0B, 0x51, 0x95, 0xF5, 0x1E, 0xD6, 0xA2, 0x43, + 0x50, 0xC8, 0x97, 0x47, 0xE1, 0xED, 0xEA, 0x51, 0xB4, 0x48, 0xE3, 0xE9, 0x14, 0x70, 0x54, + 0xCE, 0x92, 0x78, 0x73, 0xC9, 0x0D, 0xB3, 0x94, 0xD8, 0x68, 0x88, 0xE0, 0x7D, 0xFF, 0x17, + 0x75, 0x93, 0xD6, 0xF7, 0x9E, 0x15, 0x23, 0x02, 0x20, 0x4A, 0xEB, 0x03, 0xBE, 0x23, 0x86, + 0xAF, 0x3E, 0x24, 0x07, 0x8B, 0xD0, 0x28, 0xB1, 0x68, 0x9F, 0x5E, 0x14, 0x7C, 0x9F, 0x45, + 0x2C, 0x8C, 0xEB, 0x02, 0xEC, 0x59, 0xCC, 0x9D, 0xB6, 0x3A, 0x03, 0x57, 0x6C, 0xEE, 0xAF, + 0xE9, 0x82, 0x39, 0x02, 0x38, 0x97, 0xDA, 0x02, 0x36, 0x63, 0x0A, 0x53, 0xC0, 0xDE, 0x7F, + 0x43, 0x5A, 0x19, 0x86, 0x97, 0x92, 0xFA, 0xB3, 0x6E, 0x7B, 0x9E, 0x63, 0x57, 0x60, 0xF0, + 0x90, 0x69, 0xE6, 0x43, 0x2E, 0x70, 0x00, 0x35, 0xAC, 0x2A, 0x02, 0x87, 0x9F, 0xFF, 0x0A, + 0x1E, 0x1B, 0xEC, 0x52, 0x20, 0x47, 0x19, 0x3D, 0x94, 0xEB, 0x5D, 0xF1, 0xEF, 0xD5, 0x3E, + 0xEA, 0x11, 0x44, 0xCA, 0x78, 0x94, 0x08, 0x52, 0xF5, 0xEC, 0x97, 0x27, 0x90, 0x4B, 0x36, + 0x6E, 0xDE, 0x4F, 0x5E, 0x2D, 0x33, 0x1F, 0xAD, 0x5F, 0xC2, 0x82, 0xEA, 0x2C, 0x47, 0xE9, + 0x23, 0x14, 0x27, 0x71, 0xC3, 0xDD, 0x75, 0xA8, 0x73, 0x57, 0x48, 0x7D, 0xEF, 0x99, 0xE5, + 0xF1, 0x8E, 0x9D, 0x9E, 0xD6, 0x23, 0xC1, 0x75, 0xD0, 0x28, 0x88, 0xC5, 0x1F, 0x82, 0xC0, + 0x7A, 0x80, 0xD5, 0x47, 0x16, 0xB3, 0xC3, 0xC2, 0xBD, 0xBE, 0x2E, 0x9F, 0x0A, 0x9B, 0xBA, + 0xAE, 0xBE, 0xB4, 0xD5, 0x29, 0x36, 0x87, 0x64, 0x06, 0xF5, 0xC0, 0x0E, 0x8E, 0x4B, 0xBD, + 0x0A, 0x5E, 0xC0, 0x57, 0x97, 0xE6, 0x20, 0x7C, 0x5A, 0xB6, 0xC8, 0x8F, 0x1A, 0x68, 0x84, + 0x21, 0xBD, 0x05, 0xA1, 0x14, 0xF4, 0xD7, 0xDE, 0x2A, 0xC2, 0x41, 0xFA, 0x0E, 0x8B, 0xED, + 0xFF, 0x47, 0xF7, 0x62, 0xDD, 0xCB, 0xEA, 0xA9, 0x10, 0x04, 0xF8, 0xD3, 0x1E, 0x85, 0x09, + 0x5C, 0x81, 0x05, 0x49, 0x94, 0xAD, 0x38, 0x26, 0xE3, 0x44, 0xBA, 0x96, 0x04, 0x08, 0x10, + 0xFC, 0x0B, 0x2A, 0xD1, 0xDE, 0x48, 0xCF, 0xAD, 0xE0, 0x02, 0xC6, 0x2E, 0x5A, 0x49, 0xA0, + 0x73, 0x1A, 0xB3, 0x83, 0x44, 0xBC, 0x16, 0x36, 0xDF, 0x16, 0xBF, 0x60, 0x7D, 0x56, 0x85, + 0x5E, 0x56, 0xD6, 0x84, 0x00, 0x3C, 0x71, 0x8E, 0x4B, 0xAD, 0x9E, 0x5A, 0x09, 0x99, 0x79, + 0xFC, 0xDD, 0xEE, 0xB1, 0xC4, 0xA7, 0x77, 0x6C, 0xD3, 0x7A, 0x34, 0x17, 0xCB, 0x0E, 0x18, + 0x4E, 0x29, 0xEF, 0x9B, 0xC0, 0xE8, 0x74, 0x75, 0xBA, 0x66, 0x3B, 0xE0, 0x9E, 0x00, 0xAB, + 0x56, 0x2E, 0xB7, 0xC0, 0xF7, 0x16, 0x5F, 0x96, 0x9A, 0x9B, 0x42, 0x41, 0x41, 0x98, 0xCC, + 0xF1, 0xBF, 0xF2, 0xA2, 0xC8, 0xD6, 0x89, 0xA4, 0x14, 0xEC, 0xE7, 0x66, 0x29, 0x27, 0x66, + 0x56, 0x89, 0xE9, 0x4D, 0xB9, 0x61, 0xEB, 0xAE, 0xC5, 0x61, 0x5C, 0xBC, 0x1A, 0x78, 0x95, + 0xC6, 0x85, 0x1A, 0xC9, 0x61, 0x43, 0x2F, 0xF1, 0x11, 0x8D, 0x46, 0x07, 0xD3, 0x2E, 0xF9, + 0xDC, 0x73, 0x2D, 0x51, 0x33, 0x3B, 0xE4, 0xB4, 0xD0, 0xE3, 0x0D, 0xDE, 0xA7, 0x84, 0xEC, + 0xA8, 0xBE, 0x47, 0xE7, 0x41, 0xBE, 0x9C, 0x19, 0x63, 0x1D, 0xC4, 0x70, 0xA5, 0x2E, 0xF4, + 0xDC, 0x13, 0xA4, 0xF3, 0x63, 0x3F, 0xD4, 0x34, 0xD7, 0x87, 0xC1, 0x70, 0x97, 0x7B, 0x41, + 0x7D, 0xF5, 0x98, 0xE1, 0xD0, 0xDD, 0xE5, 0x06, 0xBB, 0x71, 0xD6, 0xF0, 0xBC, 0x17, 0xEC, + 0x70, 0xE3, 0xB0, 0x3C, 0xDC, 0x19, 0x65, 0xCB, 0x36, 0x99, 0x3F, 0x63, 0x3B, 0x04, 0x72, + 0xE5, 0x0D, 0x09, 0x23, 0xAC, 0x6C, 0x66, 0xFD, 0xF1, 0xD3, 0xE6, 0x45, 0x9C, 0xC1, 0x21, + 0xF0, 0xF5, 0xF9, 0x4D, 0x09, 0xE9, 0xDB, 0xCF, 0x5D, 0x69, 0x0E, 0x23, 0x23, 0x38, 0x38, + 0xA0, 0xBA, 0xCB, 0x7C, 0x63, 0x8D, 0x1B, 0x26, 0x50, 0xA4, 0x30, 0x8C, 0xD1, 0x71, 0xB6, + 0x85, 0x51, 0x26, 0xD1, 0xDA, 0x67, 0x2A, 0x6E, 0xD8, 0x5A, 0x8D, 0x78, 0xC2, 0x86, 0xFB, + 0x56, 0xF4, 0xAB, 0x3D, 0x21, 0x49, 0x75, 0x28, 0x04, 0x5C, 0x63, 0x26, 0x2C, 0x8A, 0x42, + 0xAF, 0x2F, 0x98, 0x02, 0xC5, 0x3B, 0x7B, 0xB8, 0xBE, 0x28, 0xE7, 0x8F, 0xE0, 0xB5, 0xCE, + 0x45, 0xFB, 0xB7, 0xA1, 0xAF, 0x1A, 0x3B, 0x28, 0xA8, 0xD9, 0x4B, 0x78, 0x90, 0xE3, 0xC8, + 0x82, 0xE3, 0x9B, 0xC9, 0x8E, 0x9F, 0x0A, 0xD7, 0x60, 0x25, 0xBF, 0x0D, 0xD2, 0xF0, 0x02, + 0x98, 0xE7, 0x14, 0x1A, 0x22, 0x6B, 0x3D, 0x7C, 0xEE, 0x41, 0x4F, 0x60, 0x4D, 0x1E, 0x0B, + 0xA5, 0x4D, 0x11, 0xD5, 0xFE, 0x58, 0xBC, 0xCE, 0xA6, 0xAD, 0x77, 0xAD, 0x2E, 0x8C, 0x1C, + 0xAA, 0xCF, 0x32, 0x45, 0x90, 0x14, 0xB7, 0xB9, 0x10, 0x01, 0xB1, 0xEF, 0xA8, 0xAD, 0x17, + 0x2A, 0x52, 0x3F, 0xB8, 0xE3, 0x65, 0xB5, 0x77, 0x12, 0x1B, 0xF9, 0xFD, 0x88, 0xA2, 0xC6, + 0x0C, 0x21, 0xE8, 0x21, 0xD7, 0xB6, 0xAC, 0xB4, 0x7A, 0x5A, 0x99, 0x5E, 0x40, 0xCA, 0xCE, + 0xD5, 0xC2, 0x23, 0xB8, 0xFE, 0x6D, 0xE5, 0xE1, 0x8E, 0x9D, 0x2E, 0x58, 0x93, 0xAE, 0xFE, + 0xBB, 0x7A, 0xAE, 0x7F, 0xF1, 0xA1, 0x46, 0x26, 0x0E, 0x2F, 0x11, 0x0E, 0x93, 0x95, 0x28, + 0x21, 0x3A, 0x00, 0x25, 0xA3, 0x8E, 0xC7, 0x9A, 0xAB, 0xC8, 0x61, 0xB2, 0x5E, 0xBC, 0x50, + 0x9A, 0x46, 0x74, 0xC1, 0x32, 0xAA, 0xAC, 0xB7, 0xE0, 0x14, 0x6F, 0x14, 0xEF, 0xD1, 0x1C, + 0xFC, 0xAF, 0x4C, 0xAA, 0x4F, 0x77, 0x5A, 0x71, 0x6C, 0xE3, 0x25, 0xE0, 0xA4, 0x35, 0xA4, + 0xD3, 0x49, 0xD7, 0x20, 0xBC, 0xF1, 0x37, 0x45, 0x0A, 0xFC, 0x45, 0x04, 0x6F, 0xC1, 0xA1, + 0xF8, 0x3A, 0x9D, 0x32, 0x97, 0x77, 0xA7, 0x08, 0x4E, 0x4A, 0xAD, 0xAE, 0x71, 0x22, 0xCE, + 0x97, 0x00, 0x59, 0x30, 0x52, 0x8E, 0xB3, 0xC7, 0xF7, 0xF1, 0x12, 0x9B, 0x37, 0x28, 0x87, + 0xA3, 0x71, 0x15, 0x5A, 0x3B, 0xA2, 0x01, 0xA2, 0x5C, 0xBF, 0x1D, 0xCB, 0x64, 0xE7, 0xCD, + 0xEE, 0x09, 0x2C, 0x31, 0x41, 0xFB, 0x55, 0x50, 0xFE, 0x3D, 0x0D, 0xD8, 0x2E, 0x87, 0x0E, + 0x57, 0x8B, 0x2B, 0x46, 0x50, 0x08, 0x18, 0x11, 0x3B, 0x8F, 0x65, 0x69, 0x77, 0x3C, 0x67, + 0x73, 0x85, 0xB6, 0x9A, 0x42, 0xB7, 0x7D, 0xCB, 0xA7, 0xAC, 0xFF, 0xD9, 0x5F, 0xD4, 0x45, + 0x2E, 0x23, 0xAA, 0xA1, 0xD3, 0x7E, 0x1D, 0xA2, 0x15, 0x1E, 0xA6, 0x58, 0xD4, 0x0A, 0x35, + 0x96, 0xB2, 0x7A, 0xC9, 0xF8, 0x12, 0x9D, 0xC6, 0xCF, 0x06, 0x43, 0x77, 0x26, 0x24, 0xB5, + 0x9F, 0x4F, 0x46, 0x12, 0x30, 0xDF, 0x47, 0x1C, 0xA2, 0x60, 0x87, 0xC3, 0x94, 0x2D, 0x5C, + 0x66, 0x87, 0xDF, 0x60, 0x82, 0x83, 0x59, 0x35, 0xA3, 0xF8, 0x7C, 0xB7, 0x62, 0xB0, 0xC3, + 0xB1, 0xD0, 0xDD, 0xA4, 0xA6, 0x53, 0x39, 0x65, 0xBE, 0xF1, 0xB7, 0xB8, 0x29, 0x2E, 0x25, + 0x4C, 0x01, 0x4D, 0x09, 0x0F, 0xED, 0x85, 0x7C, 0x44, 0xC1, 0x83, 0x9C, 0x69, 0x4C, 0x0A, + 0x64, 0xE3, 0xFA, 0xD9, 0x0A, 0x11, 0xF5, 0x34, 0x72, 0x2B, 0x6E, 0xE1, 0x57, 0x4F, 0x2E, + 0x14, 0x9D, 0x55, 0xD7, 0x44, 0xDE, 0x48, 0x87, 0x02, 0x4E, 0x08, 0x51, 0x14, 0x31, 0xC0, + 0x62, 0x75, 0x0E, 0x16, 0xC7, 0x4A, 0xB9, 0xF3, 0x24, 0x2F, 0x2D, 0xB3, 0xFF, 0xB1, 0x2A, + 0x8D, 0x61, 0x07, 0xFA, 0xA2, 0x29, 0xD6, 0xF6, 0x37, 0x3B, 0x07, 0xF3, 0x6D, 0x39, 0x32, + 0xB3, 0xBD, 0xB0, 0x4C, 0x19, 0xDD, 0x64, 0xEA, 0xDD, 0x7F, 0x93, 0xC3, 0xC5, 0x64, 0xC3, + 0x58, 0xA1, 0xC8, 0x1D, 0xCF, 0x1C, 0x9C, 0x31, 0xE5, 0xB0, 0x65, 0x68, 0xF9, 0x75, 0x44, + 0xC1, 0x7D, 0xC1, 0x56, 0x98, 0xC5, 0xCB, 0x38, 0x98, 0x3A, 0x9A, 0xFC, 0x42, 0x78, 0x3F, + 0xAA, 0x77, 0x3A, 0x52, 0xC9, 0xD8, 0x26, 0x06, 0x90, 0xBE, 0x9E, 0x31, 0x56, 0xAA, 0x5B, + 0xC1, 0x50, 0x9D, 0xEA, 0x3F, 0x69, 0x58, 0x76, 0x95, 0xCD, 0x6F, 0xF1, 0x72, 0xBA, 0x83, + 0xE6, 0xA6, 0xD8, 0xA7, 0xD6, 0xBB, 0xEB, 0xBB, 0xCD, 0xA3, 0x67, 0x27, 0x31, 0x98, 0x3F, + 0x89, 0xBC, 0x58, 0x31, 0xDC, 0x37, 0xC3, 0xF3, 0xC5, 0xC5, 0x6F, 0xAC, 0xC6, 0x97, 0xF3, + 0xCB, 0x20, 0xBD, 0x5D, 0xBA, 0xDB, 0xD7, 0x02, 0xE5, 0x48, 0x44, 0xAC, 0x2F, 0x62, 0x69, + 0x01, 0xFE, 0x15, 0x9D, 0xB9, 0x3D, 0xFD, 0x47, 0x73, 0xD8, 0xFE, 0x73, 0x56, 0x2B, 0x84, + 0x6C, 0x1F, 0xC8, 0x56, 0xD1, 0x80, 0x27, 0x62, 0x84, 0x0E, 0xBC, 0x72, 0xD7, 0x98, 0x8B, + 0xDE, 0x75, 0xCB, 0xCA, 0x70, 0xD3, 0x19, 0xD3, 0x2C, 0xE0, 0xCC, 0x02, 0x53, 0xBB, 0x2A, + 0xD4, 0x55, 0x72, 0x3E, 0xE0, 0xC7, 0xF4, 0x73, 0x6C, 0xE6, 0xE6, 0x66, 0x5C, 0x5A, 0xCA, + 0x32, 0xA4, 0x81, 0xC5, 0x38, 0x39, 0xBC, 0x25, 0x91, 0x67, 0xB0, 0x13, 0xD0, 0x42, 0x33, + 0x95, 0xEE, 0xB9, 0xAA, 0xAE, 0xE3, 0x20, 0x61, 0x49, 0xA7, 0xD5, 0x50, 0xD6, 0x7F, 0xC5, + 0xFD, 0xFE, 0x4A, 0x8A, 0x5C, 0x35, 0xD2, 0x51, 0x0B, 0x66, 0x43, 0x79, 0xAB, 0x8F, 0x72, + 0x85, 0x5A, 0x2A, 0xF4, 0x7A, 0xBC, 0xE2, 0xA6, 0x32, 0x04, 0x8E, 0xAF, 0x89, 0xE5, 0xCB, + 0x4A, 0x88, 0xDE, 0xBC, 0x53, 0xA5, 0x95, 0x10, 0x3A, 0xCC, 0xE4, 0xF1, 0xCF, 0xF1, 0x8A, + 0xCF, 0xF0, 0x7A, 0xFE, 0x1E, 0xB5, 0x71, 0x6A, 0xA1, 0xE4, 0x0B, 0x63, 0x13, 0x4C, 0x3A, + 0x3A, 0xE9, 0x57, 0x9F, 0xA8, 0x7F, 0x51, 0x5B, 0xE0, 0x93, 0xC2, 0xD2, 0x9D, 0xB6, 0xD6, + 0xB6, 0x5C, 0x93, 0x66, 0x1E, 0x00, 0x63, 0x6B, 0x59, 0x27, 0x04, 0xD0, 0x93, 0xCC, 0x67, + 0x16, 0xC2, 0x34, 0x2E, 0xB1, 0x85, 0x3D, 0x48, 0xC8, 0x5C, 0x63, 0xAC, 0x8A, 0x28, 0x54, + 0x46, 0x2C, 0x7B, 0x77, 0xE7, 0xE3, 0xBD, 0x1E, 0xAC, 0x5B, 0xCA, 0x28, 0xFF, 0xAA, 0x00, + 0xB5, 0xD3, 0x49, 0xF8, 0xA5, 0x47, 0xAD, 0x87, 0x5B, 0x96, 0xA8, 0xC2, 0xB2, 0x91, 0x0C, + 0x93, 0x01, 0x30, 0x9A, 0x3F, 0x91, 0x38, 0xA5, 0x69, 0x31, 0x11, 0xF5, 0x5B, 0x3C, 0x00, + 0x9C, 0xA9, 0x47, 0xC3, 0x9D, 0xFC, 0x82, 0xD9, 0x8E, 0xB1, 0xCA, 0xA4, 0xA9, 0xCB, 0xE8, + 0x85, 0xF7, 0x86, 0xFA, 0x86, 0xE5, 0x5B, 0xE0, 0x62, 0x22, 0x2F, 0x8B, 0xA9, 0x0A, 0x97, + 0x40, 0x73, 0x32, 0x6B, 0x31, 0x21, 0x2A, 0xEC, 0xE0, 0xA3, 0x4A, 0x60, + ]) + .unwrap(); let sig = &*hex::decode("781368e64dba542a7eacbd2257335cc943a03241009b797093c615f76a671a7591430441d80bb582304b33b9fce295e0dd57fe169355ddf4453a2aca62d8eb8109ef0d9cf3f5b0a94e04ad81b3e786014243ecde816551aa7fe01c639054256a491756bef59f5034f717ff4f85e70ba7731a49971415b6a7e7d816ab434b9f17a3095ede6fd432be2bfa82724045dda0dfff7a0281e9000939ccba3d8ab3245139c441648c76a6536127e4d1ef0df1531883ab78c8b41323617ad8db03d9908c9e08a9f7321c45051b3c94213347b11c4a84491de7a7be68701e47d7f0e0b33e767bef17694e4d33244ed92ebd74c85ab6c84441cddc14331e6ae8bd23674bda27f09c050d88f7d430feee7f15a72a24d653bb6bec54491b98362ce131d37c7d78a3f9a893db5abdccd6663593b88bc6c97f07f8eafccfd25e8180d918efbcd95bbf3da29f081e3e1932095939198e2a155b2d803a3e84ca4f34569df695c259faf3c0d8f0cd217ebd2dbad542b32fbb54e44aaf0b5dc739fafef2e46db8d68bfc35f44f038cb1f5231a1b5b134ae683e7f3297cc7a95bd191b310f68201450797fe3293cde1672dfeca4b493f53c768ea048a972a4cd84d39ef682957b8f28ba29487b4689b43fec2655823d9bb99ffcf31490366a9860a5d5b8e32a3b8bfeb6f55f88fb80c8c0142086f220e1f6f2862dabda58c3b6f5faa805b39cfac4b6d7ea7acdf1b0690063b0c1ea38c7c4755189966dc631055f153f71b77b114fa5c309316ba512330ea5cdb0bb176001e57461563d17259f35d0c30ef5ac838c0325402bab52c531469526ae3ee6293f7b5769d27e69fa81cd25a31cd095b126e70c57ac3169a5f585a11f1748d9d22f2564911c26a24b2153a78f3a06822f5f1963f237abeb48efd9a9cd478de579c5a0ba84d00e96fbde36d8ce20e7e948547fb6850834ff79d211830f6ee973359781d9d5008fb43a89354782fde4158177f5206ce1d38c889e99e4bb5b4ab34d6a05c42f5d719ea03dbc54adba75a3bb44a3c08c7556462f8c5b7c568a69242cf5be6098eba0a2249c1ca5b2109b6404a962abc1c159c6b48a79fb97e4a3337d99323746221297423f9bd1b12e78489e01e6a10f0fd6bba1cfd6ae1b75dbe69f8b8ee51a4e7f68ba2c407c9c0bad3892b29b0170ab75836fdd49a7ee3c2bb30f2c3d226bcec49140952170b0d160f97b30b7b7b096719538677ebb06922f26925227c8852acc107a8f173b38d96697584bd3dfe169b4073aa58a7bf371d5c4bb0eed30f08212defb3aec902d4546084176bf0f86d93cf36a4689a5e874b32d6b7d3c1e3fbcfd988c35dbc9a8d0a019ad6d7e15ec3ac97125db6abfe00beffe35a81666699a91e15945c62d646690b5b52de8b835ee9be53588fde5d63023b52b2b1f4610c237a829f5901a46042963cce7b85aa040adde02985e14e23c4eadb75221c607d24672e244c66c9c24c3cb7fd90bb23295c9d3d9da516bce3dd462d6660f9f91ef0618a4d4d3d6668c5d1e2e8ed433ebfe0762beb743324e11608f8b14b69ce4c221c1654ba4992a5af2d949c2939f95d1c8fb767af2a843cc7c78f57259d5c0c6ca83fca41ef5ecc4eeeea93e4518c24d3040f2cd90df3e535e989e606fa109e2c453ed7353db1cdb27137f005f9dd8d2aebfb7255a6098b690215e100cfe44ca0f2745fced48322bc9667ab16d2e1c0ff491b96a17b833d4fd44d31c2230ac835796e063ab03000f04f15c70560033763a48552cceaacade9ca5c8055f3745e179068a287183f2bc3ef6327dec5ac7cf7b052ef5a8873e697efde089688f43be464827c2fa83eb531b3674145e95c699c82990e684967dad319d9f64ab16cd9fe9b6c41232ac4ae3795fd8a76aa9b02e970242061c6da45a2af74ad9cb2a79935c92625e242f4bc7fce54d5c10a9e61f875162fa651b66057ba036f062d6d39d0502b93a5640b78c6c2fd20b02ff83676a87a94945d476c349803ea4fe60cdcea65bb2629e2bc09d4472ec63422dee2052f098deaf5531e6c9bed6672a8b699802efe0cded80c8455f585d1ba633d281f1a21adab48e63b44e0c2a4d7608cf98aabf8adc86bcb8f61e8b06cd2385f82e0a3cdd03cab152d5951859c4532f9168e78f17ba2a5772780327dcf4e62b4d26e443762fc488ae4cd4d1156dbd5782595cfd7697a514abc9b160c9ccf08edc86134a755b90e9bb543511e888e3157721a52d1bc5db33029fb335ea2114e21c03368c8d7f4d827960641772a4a32a738df60d19ec77ab09d22f57cc2523b9503b3f5b1cebc5ae15f885f159842db7359a1c89d3d82d3407068f15b6739626eb8c521fc8c5c7491f945d49f14e6989da340bdf49e7f8a792747aa658bc114143ba93f26022d001735b744639bbf22aab2a1851cfc934f9c69d3764fdea3d23db17998e6138cfd7cd9e9a47cb74193bd71aaf28cdd9d1eb595125546a4f4357ebbd1f410e3bf8557892de68509b5b98c5c229e942c910fdd3e54cb6ad54d8dd886cb97ecc06d1e401b8395d0bcb0db9a031dc66c9294f9053c68fc42042b1fa1671fc7d510b70916c0139cfebe3a91244527ce9439860cedb30908197be851cbd1d3b18ca541358449fb34fb5cd569630ed5f67b8795e87828f2ce3becfe457579d82333b0bbab094de391e1f8157bd431e365ca864630932bbebb48f45f8134424e18ab455029b54b19e2f3bfec5e44ad0ea5c03f53d8f925b635838aa7015a7c9e325bdfaff966ea9512dd50f87c8995cea7561c23f4fb06d964ab8f1913a6ca17e4ca60d6bc078e1784f89c673c91d955bcf45f58ca9709579d5e3831df12cfdb7516fd21878cb54243579b9346d2de4be25f508e84b1adc78cb91c03da3c4fd59e4529189838f74f6312820620a5996b791ffcb332f847094613f2148b862034fa89d0d0ff1808d902c5d1af64d5522492d61ecde4c73be89a33782cef1acc1dc327fb2eb9d17642209b85aa8b1dc57cbf067c7aa29da6b7e157d23e171d3ae6f3855834071791402c851ff2dd67109979f7ee5e09e64b4eefdee7112b55ce200bb8c8051e3428c305fa1d576bffbb25a70eb571168fc60dadd928b10cfd07de80a85b8df3edc372d488c21f0d5787611cc6fb73aeeb6f920a109294b49d3870f90de3b360d14df77ef95640bcac7a4dbca901a31db83e83f5c59ce327207ea9b27c3b978d30d53865c1b84764f025e8732d5007554ce5c9cc410b2eefd7e4d990c538557606a6bc47577a43768d30aa3e8598fd6f4fe7ac439f3931c58fd69d90765ac9f456ac7de085e14a0898c4557f5d3baaae07edc607de6900146b97b35aae570153dc107815ef9febdd4fd567d637fee8f8bfb4b3413ea6aead4846ab733a04f1e4bc32a3bbb1c16baf8d0bdb9ccb82fe46479ccfd040b5e64064e539b39c66e4501dc822873ac6119a4a112a1f7cd6df0e5f84356ce853ced34ce69a9e7383534983c51c50269bf8b9586a0e5ba905fd3bce080b00e7f7d48e55f489479b5771e995fb020e58feb74af65c3ee76aa4e69b5ba8bda249a1b2d62c08d418c3635d061846040843991ab475473da85d94981fb84425e7ad951ce0a42be642fe658b7aaae72b147cdc086c24b1571eb2272e2a72b15660d854ebe19ec7d9ab7ea17800d0b6ae727b39217467c662ba08e6f19193951eeff02806a7843eb5c71b2f04dcb605ecedc5128cd67703038c44bf20fe06f3ed8c1368fe38e72944d5c52fca46a45fd48d8fe5da64183d4d62ec01aa3d9d672ec67a01c17f21e02525f0513cce030c664fc8784763086608bc8099c204c255ffed1daf432ceb45fbd135e21e8190c5bfee192171faa77520481e69e87b7f76790bef76cb8d3c88f5c6e32fc59e7bd45351d66696b61d9f40726fb9a98000b68738cf7e34b98b6a4aaa2ac1d7b1407db89783f8077103ea9c9e89247eae078adfb36e21474c3bb1fe0c87687c6233a533a01e1081b93a3521d339f39c075609bace531994988ae314f77fc6034113a138c67eb7e03750cbec8d28bd21afedfefa8f091619ae500b4ca4599d019dc8ca4bf118d70b8676dfc796a4f6d986adba4c8574ed4abaea5465466220e5e53dc8fcb395d1e59d278673cbc4e3f40658df98ac2fd126a94922879e1a3be91c1acc20803c35fa764abbadab07bde85ff4bd9e0fb6f06baf5bf42b8a2cbf6c2f62606becc361552921a12d6c8236fde84db4bddac77e8872478cffc4e148c1c7acfedf6b17d98731c2de36f3cbef1f6f781a940e0874d5b74535bbe066b53064d43b13926570a9e1c4e6da206c8bd252caf2b62e7d223f7ac12939137f330be59374d7295a6c2dff92e07c727510e48d970593e47229fc8bc3bd5b8ea780dacff4d23063df65feda5f8f65b17a333e532acad7916780c74d6a70d38b367f3f6f4e947b85fc15235bbe46b26495d2780098db853a931377cfbedea620f2355ca21e81ce9e0078b0dd6cb70f23ed558682be3b3d594eefe85344e1f275428b316cc088995939298f2a2d15ac9b676ac3e9cb92f2a64dec7732a91fc761aa1b126ea575e3953177da6e1cd78faea824665330a81d9e24572b9860bf0aba4df8bd5d4e3e2c72bbfbb2a985c7ae2f077951fe8401e1d156ecada1e353817b20f41e0b2460a0caaf2b36d6a7f1b35125d797dcc714421027d14171765a646071ed952b6a5294eecf6a3a71c104c843a4a8b3efcc27467b20cb0a94abf5802229ea4d8312783e78791a50b3c0a88fe6497198cd4bf470dac46f34e50019fdee2040cfe99124b312b1122b83e51d878877cec0855f1158c445cfdc2253f4389d5e3a8ba1669abb5976a4617e85f543da9f5e30b10ca7481c8185392782b46fb0a0e5ab408b2945e3c79a1cc49fb7c27254a9b540e7397a5b655bf7e4f83184db32a128aa2e00a624d7dcd6b77efd151f1e5cba8890af9170fa06c555715dc1787e995ad19270973ae95b88dcafdaf62c28843d3f8b9c78dc8e37d911dab3f7ee9d4c7389c654bdcfc05056b360020140e57e31473258a4081e2a708f7caba90c356d0847098fc0762484086aba898a60b023d6a3060402406240748785d51caff52a0ef3dc2a45dadf80ac18502d24422a8cbb10192b88f4e9160206b2ed3e04114f2a339df269e2c36b8613ce37087471701755330cb559575366ee0fa2d3afcda32eede6dd906345daaa04812198e96c42239c242edb90059709f497da5b87705384aef2af22dc2edfef3c00d8c9156d8b3163fe7a7779e04f04911a8b934fb3072eee844484fede5e2ee96d338eefe2da986067ffe0218ada7de1d0e42d823d6b033918278888ba0608ab8f7be997bdf263689a36f5204c802ad836363779b4b0d6ce5083df0b98a2e2c700062a4fa5e57bc73bd45357e01d90c7954bc6904d1ce8166a9168da39a60c5cae8119bb6b9ab074fb2d0aee384fc2c0e4806811d6002b4e2401e7430b50cb0e8075f33d5386aecde256e169d95e2f9c6556c08ba042e68a53ce8aca9cc02818f7382f150dc04de0019b19c7a3ab0d72d6ed013d7a115d74b279f71fd6effef34049877e0b11e0659be938a5de684eaf23513095eb4a1bdf536c3c01a4655c4b4a0673214cef29a481d06a02cc9a5bfc7b8d846c33484cd67b1de98f60b69918f177b64558ca567a6237d35ff01771a42320ce02bb98f3e4ad4ac7db75611bd9961eac662a38b1f785970c99f3dd105ff586f61301c48d66708cbf7d53a733e357b6c256e8b73f0e1305a0bc137989e521100c2ee6259e607fe12198e8bcb988b0854668e40d7cae6adc3ba40ba121b7319d06d988a073d03097b9f5c1c07284b6473ae57bf154811b77baceb0412b8a6983bdd0ccd9e3bf014e520009cb26d5780eabef1bbafa5e25d41098a54c47fce8b68d395291d54284d33aa50b9664d1510b467c8a539361ca9a4448bc01fcb4c4e3ef475e8afb46a494ae13ee9ea8a1266825fba7f32b9712fde252698a68359b50141d90f5c4a06283ddb54ad7e1412ac5ebb12501f7a82b2a7f27b2dbab626c3db4074523b3211d3182ea261397a6f7b187cf2b8a356ded10812f1d305169aedf79b5ff1cf7c2d6e86ee11f28e96aa63b5a03f59fc960ac7d0572e91dda61905c0711a9b26344a2a10aa2041f2b13cb1a9a9a27774b6d0deddc9d81ea1b142ad7b72be47991f2c9261d6708156e38d00b074020766eb0c494392d65b82ca65f7c3352f9bb78325ecb6df596c8ae57826b08ccd6f1d529d2e25925c1ac972425bedeb88a5d0e3138ddc434da3462ebdf6b1239a21f141ec62cbe4bb993ba253b55a76d30fac19c2c1384ef6b9746c07787aa1fe913a1348390bd8c1f386a08c77cf7106c927ce24dffc9d6ee1b32354d95ed2923482531de6b390bf0f5eb80276e90e7ed11131c848bbabec4d317236269a0a3a7cbe0f1272f93949ca6d23ea2a7ee3f697791aab71533423066d400000000000000000000000000000000000000000000000000000000050e181f23292c2f").unwrap(); assert_eq!(sig.len(), MLDSA87_SIG_LEN); @@ -462,8 +2129,8 @@ fn bench_mldsa87_verify() { } fn bench_mldsa87_lowmemory_verify() { - use bouncycastle::mldsa_lowmemory::{MLDSATrait, MLDSA87, MLDSA87_SIG_LEN, MLDSA87PublicKey}; use bouncycastle::hex; + use bouncycastle::mldsa_lowmemory::{MLDSA87, MLDSA87_SIG_LEN, MLDSA87PublicKey, MLDSATrait}; eprintln!("MLDSA87/Verify"); @@ -494,8 +2161,6 @@ fn bench_mldsa87_lowmemory_verify() { } } - - fn main() { // print_struct_sizes() // bench_do_nothing() @@ -510,11 +2175,11 @@ fn main() { // bench_mldsa65_sign() // bench_mldsa65_lowmemory_sign() // bench_mldsa87_sign() - // bench_mldsa87_lowmemory_sign() + bench_mldsa87_lowmemory_sign() // bench_mldsa44_verify() // bench_mldsa44_lowmemory_verify() // bench_mldsa65_verify() // bench_mldsa65_lowmemory_verify() // bench_mldsa87_verify() - bench_mldsa87_lowmemory_verify() -} \ No newline at end of file + // bench_mldsa87_lowmemory_verify() +} diff --git a/src/bench_mldsa_mem_usage.rs b/src/bench_mldsa_mem_usage.rs new file mode 100644 index 0000000..55bdc24 --- /dev/null +++ b/src/bench_mldsa_mem_usage.rs @@ -0,0 +1,469 @@ +//! The purpose of this binary is to perform a single run of the primitive under test so that +//! its peak memory usage can be measured with: +//! +//! > valgrind --tool=massif --heap=no --stacks=yes -- target/release/bench_mldsa_mem_usage > /dev/null +//! +//! > ms_print massif.out.835000 +//! +//! or, shoved all into one line: +//! +//! > clear; clear; valgrind --tool=massif --heap=no --stacks=yes -- target/release/bench_mldsa_mem_usage > /dev/null; ms_print massif.out.*; rm massif.out.* +//! +//! Make sure you build in release mode! +//! +//! Note: I'm using print!() to force the compiler not to optimize away the actual code. +//! I'm printing the important stuff for benchmarking to stderr so that I can pipe the junk to /dev/null +//! (I'm not doing it the other way because /usr/bin/time prints its useful stuff to stderr as well) +//! +//! Main is at the bottom, controls which this was actually run. + +#![allow(dead_code)] +#![allow(unused_imports)] + +use bouncycastle_core_interface::key_material::{KeyMaterial256, KeyType}; +use bouncycastle_core_interface::traits::{Signature, SignaturePublicKey}; +use bouncycastle_hex as hex; +use bouncycastle_mldsa::MLDSA44PublicKey; + +/// This exists so I can use /usr/bin/time to measure the base memory footprint of the cargo bench harness +fn bench_do_nothing() { + eprintln!("DoNothing"); + + print!("{}", 1 + 1); +} + +fn bench_mldsa44_keygen() { + use bouncycastle_mldsa::{MLDSATrait, MLDSA44}; + + eprintln!("MLDSA44/KeyGen"); + + let seed = KeyMaterial256::from_bytes_as_type( + &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + KeyType::Seed, + ).unwrap(); + + let (pk, _sk) = MLDSA44::keygen_from_seed(&seed).unwrap(); + println!("{:x?}", pk.encode()); +} + +fn bench_mldsa44_lowmem_keygen() { + use bouncycastle_mldsa_lowmemory::{MLDSATrait, MLDSA44}; + + eprintln!("MLDSA44_lowmemory/KeyGen"); + + let seed = KeyMaterial256::from_bytes_as_type( + &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + KeyType::Seed, + ).unwrap(); + + let (pk, _sk) = MLDSA44::keygen_from_seed(&seed).unwrap(); + println!("{:x?}", pk.encode()); +} + +fn bench_mldsa65_keygen() { + use bouncycastle_mldsa::{MLDSATrait, MLDSA65}; + + eprintln!("MLDSA65/KeyGen"); + + let seed = KeyMaterial256::from_bytes_as_type( + &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + KeyType::Seed, + ).unwrap(); + + let (pk, _sk) = MLDSA65::keygen_from_seed(&seed).unwrap(); + println!("{:x?}", pk.encode()); +} + +fn bench_mldsa65_lowmemory_keygen() { + use bouncycastle_mldsa_lowmemory::{MLDSATrait, MLDSA65}; + + eprintln!("MLDSA65_lowmemory/KeyGen"); + + let seed = KeyMaterial256::from_bytes_as_type( + &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + KeyType::Seed, + ).unwrap(); + + let (pk, _sk) = MLDSA65::keygen_from_seed(&seed).unwrap(); + println!("{:x?}", pk.encode()); +} + +fn bench_mldsa87_keygen() { + use bouncycastle_mldsa::{MLDSATrait, MLDSA87}; + + eprintln!("MLDSA87/KeyGen"); + + let seed = KeyMaterial256::from_bytes_as_type( + &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + KeyType::Seed, + ).unwrap(); + + let (pk, _sk) = MLDSA87::keygen_from_seed(&seed).unwrap(); + println!("{:x?}", pk.encode()); +} + +fn bench_mldsa87_lowmemory_keygen() { + use bouncycastle_mldsa_lowmemory::{MLDSATrait, MLDSA87}; + + eprintln!("MLDSA87_lowmemory/KeyGen"); + + let seed = KeyMaterial256::from_bytes_as_type( + &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + KeyType::Seed, + ).unwrap(); + + let (pk, _sk) = MLDSA87::keygen_from_seed(&seed).unwrap(); + println!("{:x?}", pk.encode()); +} + +fn bench_mldsa44_sign() { + use bouncycastle_mldsa::{MLDSATrait, MLDSA44}; + + eprintln!("MLDSA44/Sign"); + + // set up the seeds outside of the timing loop + // Doing different seeds so that the CPU doesn't cache them or do too much branch prediction + let seed = KeyMaterial256::from_bytes_as_type( + &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + KeyType::Seed, + ).unwrap(); + + let msg = b"The quick brown fox jumped over the lazy dog"; + + /*** ML-DSA-44 ***/ + // since the goal here is to measure peak memory usage; we're here making an assumption that + // mem usage of .sign will be higher than .keygen + let (_mldsa44_pk, mldsa44_sk) = MLDSA44::keygen_from_seed(&seed).unwrap(); + + let mu = MLDSA44::compute_mu_from_sk(&mldsa44_sk, msg, None).unwrap(); + let sig = MLDSA44::sign_mu_deterministic(&mldsa44_sk, &mu, [0u8; 32]).unwrap(); + print!("{:x?}", sig); +} + +fn bench_mldsa44_lowmemory_sign() { + use bouncycastle_mldsa_lowmemory::{MLDSATrait, MLDSA44}; + + eprintln!("MLDSA44_lowmemory/Sign"); + + // set up the seeds outside of the timing loop + // Doing different seeds so that the CPU doesn't cache them or do too much branch prediction + let seed = KeyMaterial256::from_bytes_as_type( + &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + KeyType::Seed, + ).unwrap(); + + let msg = b"The quick brown fox jumped over the lazy dog"; + + /*** ML-DSA-44 ***/ + let (_mldsa44_pk, mldsa44_sk) = MLDSA44::keygen_from_seed(&seed).unwrap(); + + let mu = MLDSA44::compute_mu_from_sk(&mldsa44_sk, msg, None).unwrap(); + let sig = MLDSA44::sign_mu_deterministic(&mldsa44_sk, &mu, [0u8; 32]).unwrap(); + print!("{:x?}", sig); +} + +fn bench_mldsa65_sign() { + use bouncycastle_mldsa::{MLDSATrait, MLDSA65}; + + eprintln!("MLDSA65/Sign"); + + // set up the seeds outside of the timing loop + // Doing different seeds so that the CPU doesn't cache them or do too much branch prediction + let seed = KeyMaterial256::from_bytes_as_type( + &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + KeyType::Seed, + ).unwrap(); + + let msg = b"The quick brown fox jumped over the lazy dog"; + + let (_pk, sk) = MLDSA65::keygen_from_seed(&seed).unwrap(); + + let mu = MLDSA65::compute_mu_from_sk(&sk, msg, None).unwrap(); + let sig = MLDSA65::sign_mu_deterministic(&sk, &mu, [0u8; 32]).unwrap(); + print!("{:x?}", sig); +} + +fn bench_mldsa65_lowmemory_sign() { + use bouncycastle_mldsa_lowmemory::{MLDSATrait, MLDSA65}; + + eprintln!("MLDSA65_lowmemory/Sign"); + + // set up the seeds outside of the timing loop + // Doing different seeds so that the CPU doesn't cache them or do too much branch prediction + let seed = KeyMaterial256::from_bytes_as_type( + &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + KeyType::Seed, + ).unwrap(); + + let msg = b"The quick brown fox jumped over the lazy dog"; + + /*** ML-DSA-44 ***/ + let (_mldsa44_pk, mldsa44_sk) = MLDSA65::keygen_from_seed(&seed).unwrap(); + + let mu = MLDSA65::compute_mu_from_sk(&mldsa44_sk, msg, None).unwrap(); + let sig = MLDSA65::sign_mu_deterministic(&mldsa44_sk, &mu, [0u8; 32]).unwrap(); + print!("{:x?}", sig); +} + +fn bench_mldsa87_sign() { + use bouncycastle_mldsa::{MLDSATrait, MLDSA87}; + + eprintln!("MLDSA87/Sign"); + + // set up the seeds outside of the timing loop + // Doing different seeds so that the CPU doesn't cache them or do too much branch prediction + let seed = KeyMaterial256::from_bytes_as_type( + &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + KeyType::Seed, + ).unwrap(); + + let msg = b"The quick brown fox jumped over the lazy dog"; + + let (_pk, sk) = MLDSA87::keygen_from_seed(&seed).unwrap(); + + let mu = MLDSA87::compute_mu_from_sk(&sk, msg, None).unwrap(); + let sig = MLDSA87::sign_mu_deterministic(&sk, &mu, [0u8; 32]).unwrap(); + print!("{:x?}", sig); +} + +fn bench_mldsa87_lowmemory_sign() { + use bouncycastle_mldsa_lowmemory::{MLDSATrait, MLDSA87}; + + eprintln!("MLDSA87_lowmemory/Sign"); + + // set up the seeds outside of the timing loop + // Doing different seeds so that the CPU doesn't cache them or do too much branch prediction + let seed = KeyMaterial256::from_bytes_as_type( + &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + KeyType::Seed, + ).unwrap(); + + let msg = b"The quick brown fox jumped over the lazy dog"; + + /*** ML-DSA-44 ***/ + let (_mldsa44_pk, mldsa44_sk) = MLDSA87::keygen_from_seed(&seed).unwrap(); + + let mu = MLDSA87::compute_mu_from_sk(&mldsa44_sk, msg, None).unwrap(); + let sig = MLDSA87::sign_mu_deterministic(&mldsa44_sk, &mu, [0u8; 32]).unwrap(); + print!("{:x?}", sig); +} + +fn bench_mldsa44_verify() { + use bouncycastle_mldsa::{MLDSATrait, MLDSA44, MLDSA44_SIG_LEN, MLDSA44PublicKey}; + use bouncycastle_hex as hex; + + eprintln!("MLDSA44/Verify"); + + let msg = b"The quick brown fox jumped over the lazy dog"; + + /* One-time setup of the KAT -- commented out so that we're not capturing keygen in the bench */ + // let seed = KeyMaterial256::from_bytes_as_type( + // &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + // KeyType::Seed, + // ).unwrap(); + // + // let (mldsa44_pk, _mldsa44_sk) = MLDSA44::keygen_from_seed(&seed).unwrap(); + + // eprintln!("pk:\n{}", &*hex::encode(&mldsa44_pk.encode())); + // let mu = MLDSA44::compute_mu_from_sk(&mldsa44_sk, msg, None).unwrap(); + // let sig = MLDSA44::sign_mu_deterministic(&mldsa44_sk, &mu, [0u8; 32]).unwrap(); + // eprintln!("sig:\n{}", &*hex::encode(sig)); + + let mldsa44_pk = MLDSA44PublicKey::from_bytes(&*hex::decode("d7b2b47254aae0db45e7930d4a98d2c97d8f1397d1789dafa17024b316e9bec94fc9946d42f19b79a7413bbaa33e7149cb42ed5115693ac041facb988adeb5fe0e1d8631184995b592c397d2294e2e14f90aa414ba3826899ac43f4cccacbc26e9a832b95118d5cb433cbef9660b00138e0817f61e762ca274c36ad554eb22aac1162e4ab01acba1e38c4efd8f80b65b333d0f72e55dfe71ce9c1ebb9889e7c56106c0fd73803a2aecfeafded7aa3cb2ceda54d12bd8cd36a78cf975943b47abd25e880ac452e5742ed1e8d1a82afa86e590c758c15ae4d2840d92bca1a5090f40496597fca7d8b9513f1a1bda6e950aaa98de467507d4a4f5a4f0599216582c3572f62eda8905ab3581670c4a02777a33e0ca7295fd8f4ff6d1a0a3a7683d65f5f5f7fc60da023e826c5f92144c02f7d1ba1075987553ea9367fcd76d990b7fa99cd45afdb8836d43e459f5187df058479709a01ea6835935fa70460990cd3dc1ba401ba94bab1dde41ac67ab3319dcaca06048d4c4eef27ee13a9c17d0538f430f2d642dc2415660de78877d8d8abc72523978c042e4285f4319846c44126242976844c10e556ba215b5a719e59d0c6b2a96d39859071fdcc2cde7524a7bedae54e85b318e854e8fe2b2f3edfac9719128270aafd1e5044c3a4fdafd9ff31f90784b8e8e4596144a0daf586511d3d9962b9ea95af197b4e5fc60f2b1ed15de3a5bef5f89bdc79d91051d9b2816e74fa54531efdc1cbe74d448857f476bcd58f21c0b653b3b76a4e076a6559a302718555cc63f74859aabab925f023861ca8cd0f7badb2871f67d55326d7451135ad45f4a1ba69118fbb2c8a30eec9392ef3f977066c9add5c710cc647b1514d217d958c7017c3e90fd20c04e674b90486e9370a31a001d32f473979e4906749e7e477fa0b74508f8a5f2378312b83c25bd388ca0b0fff7478baf42b71667edaac97c46b129643e586e5b055a0c211946d4f36e675bed5860fa042a315d9826164d6a9237c35a5fbf495490a5bd4df248b95c4aae7784b605673166ac4245b5b4b082a09e9323e62f2078c5b76783446defd736ad3a3702d49b089844900a61833397bc4419b30d7a97a0b387c1911474c4d41b53e32a977acb6f0ea75db65bb39e59e701e76957def6f2d44559c31a77122b5204e3b5c219f1688b14ed0bc0b801b3e6e82dcd43e9c0e9f41744cd9815bd1bc8820d8bb123f04facd1b1b685dd5a2b1b8dbbf3ed933670f095a180b4f192d08b10b8fabbdfcc2b24518e32eea0a5e0c904ca844780083f3b0cd2d0b8b6af67bc355b9494025dc7b0a78fa80e3a2dbfeb51328851d6078198e9493651ae787ec0251f922ba30e9f51df62a6d72784cf3dd205393176dfa324a512bd94970a36dd34a514a86791f0eb36f0145b09ab64651b4a0313b299611a2a1c48891627598768a3114060ba4443486df51522a1ce88b30985c216f8e6ed178dd567b304a0d4cafba882a28342f17a9aa26ae58db630083d2c358fdf566c3f5d62a428567bc9ea8ce95caa0f35474b0bfa8f339a250ab4dfcf2083be8eefbc1055e18fe15370eecb260566d83ff06b211aaec43ca29b54ccd00f8815a2465ef0b46515cc7e41f3124f09efff739309ab58b29a1459a00bce5038e938c9678f72eb0e4ee5fdaae66d9f8573fc97fc42b4959f4bf8b61d78433e86b0335d6e9191c4d8bf487b3905c108cfd6ac24b0ceb7dcb7cf51f84d0ed687b95eaeb1c533c06f0d97023d92a70825837b59ba6cb7d4e56b0a87c203862ae8f315ba5925e8edefa679369a2202766151f16a965f9f81ece76cc070b55869e4db9784cf05c830b3242c8312").unwrap()).unwrap(); + let sig = &*hex::decode("5e93b785c5119c3983a291b18420fdbe4bca53d5a3732922faaacd5a5d32a745c78d105ba10bee1ed8069f19e6c537bda16e89d39004c359d1fd381a0291f1c51f1c38edcdb315c8c69570d8f25f1655ba8ea83aff24b8b6be8de762342e347eab2caa6803ed705952dd6450c5185e9d60ce96e8dca423a02f646cea690164a226e4c3d6a515ce16290f19b2c626da9b450ecf665013c5e226b6c0ac5c07ce90e278f1b0134e385d13e74208a0b3ff052a362579f9207ea01f18a039aa1b97ae3452675b620771f8012ee7a4e55c98bfd2019ed8a3b00acea8e8ab28172faa42ca1fda83c5ffe81a45be736bdedd5fb300ce17078b380f620bdeebad693601372c85eacf79bc98e1b48f2ad7e5dce4279a1295bb2ba60a0c5e3726642d2336c5eb1d37c8623c7558241318d89bc783c4f00098077484623c217560a0c7aaf75dcaccb78ee69c207c27c8bf3965ccf58a80c88efcc7e5deb3615d5045a741c4dac0a021dd060d315d4ec2857eb664d728d0af973bea07e1ca563faa0e19996cea3770316c11a5066665662005ace98f6110e883bae060daa7b6d83379e0878796691708a32b85730de8b92d89f90a3660c949165b14612567662e162232296cbd143517a282e22c46b63606d3c14ed4559a5a1c459bab7f355007ad6f7e3b1e07445dfc96bd9b75080b3d4f68998490a26b5e090be2674071ab925bb650590856c59f8ba7488d2b72f840ac3eafe4dd91f0f51c4364112c1a139e3e942a597b93a1e3f4faded129c14b5978b315e2246a93146a79365f0f597a18340cca86bb15ceed39f175eab1e546535afb966f0a65a8f66f737ab02897eddfe92cf7786894843c2691464776c94bd450a1069138b26df83b2d1dd801143a8fdfdc2514cc5b5831ab53a75c55ef29f40e7c63d2c72abe97e2af14853be49be16f4730a159974970951439e55c1589d0f4a162e3517df9d7abc98d8a307216e7f1cb4627c9175c0eef23337e56d5281b83726fff40a148b0c48e8df3496a2118d80219aef8f40b29fba1f2f78786b67ffb7b7d47d406b765bd136610bedeb95cd7321f58f3b836c9258be35d78b498f3efe1db2b243d734fab159baed8807c3cccf83eb2eaf8a9af01a518d48c60e91a96812ad689c2d83cc4e8e9b3650422bed6f13c24adaad91c95b3e3cf354f0f6bc9ee8941a6b15b6975131d95233d8935de367efc6d86a45dac7d0f1ddd9aebd2c59c027fcda448801e93e733aca51874be9ab927a904f96ddb7a46b2da13261d522b23c950c01d5f5e112b76f851ff234f06f8d5e65b1319abcd79a180ae063d65b28c745878c06dbb69ba73293eab34434bf1a92fba691993bd0ff3edac76a12f80c0ada4b1969c7665589d530a67016a625403c537032904f2e104547cd3ea406260dd357fa06ea012a785826c160e99ffd065b0e3f33c7689d3552ab9e2e09fa7e55bbcef042242bcacad8a3da47bcc54a121f1526c8cd4cc5a892a8131cf4eefaf4248ddd6a11ec427ba378aae89aaf582ce1f4e32690a555e740761d358ad4e92bc38418aa782da916524fb09ab2ca6b3d3113d6f2c2a6a9b9d29d4e7489255252af075cbf9feacedae6f3ec0b070824689dd3c78ac143ed6776d95dd8f13d435a290bdca4c11318e5acce04469644e1374a9451b6204f3b3961b7dd239e306fef5f4f4e51b78b0fb9dcee69c3e790b231f2e65fd1ab1c2a75b07067d5c16dde00983a58ffcdaaaee16d2742e133ed737b48064c8a38eca35ab3fa18f6d62f642b12cfdc7980f2ab7db321fec9dcfe499b4fc1ee7eb297954056617c60a6640b92835d165c3c00a951952614488d5657ba0b5e90ae9e0ef7b3b9ecaebd81b8551b6d70e835b2734761639d42e76ffc5b3272b61c896b45b4bd18f30e58c440643ba159221cc6739a19a65f2911fae47b0d4cac4200a6f043b17a03ad393ecb823ed03c8b6cd68167e6c8234f7432557db272079ee899aede73b6b98d6003f45789a141b60d6db40cd2a5974571a4ad3667b889318ba60285d903a2eac01c21608838c40907de6bbabe042cf2ecdd97f549f95ec698d79222c65ba27c30d332a68d057aecdc9388aa34320e0aa74fdbd4d1b643cace216b6d8ad8f07a99955bfdb743a86b40fc61527baca434ac2a7fbeaa77111dc8098b17e800f59dd77ccb0e67707e60123d334e073a2f5a16ffbcd701389add57c3ceccb88b286ac1e6e3e6485af1a12ea241d14a1b5003d7f3bc9e957d4483c0f9f703b3a187d55e505817615fbc4ae0837616184245cfba61ce3b929e33f52b71cdd7b6a0da55c1f997510b1a9002ca4e0678373a3b1ab2897e6b423f15a440a636cc861491ef41ad0aa627d8e198a5ee7bd7b6cb2c9ce2a8cc015f0d206de4c49e2f87f310954a10d86e294f742ee186f4ae9815f699622792206cafba8f5621738160e6c5d611a8252c6f35085b604ef895164d4ea6ddd310c7d8f0c879fb1f884c5741d096b3d2da0ce1151790dda881d18cb6b19a9fed6f5254b7d52d5d92bbbe24c9d6a65604a0b8ed24ad5c197d683f598743c96b5960e8723732b5bd647e9dbeaa851d0e1cf6d2c070d4442762c28098c5cf5a54b2b5e69a99b10815bf0f477bb71f0d5d3a62ba2b3e29bf84d4b4e574707f5f74af704d277bd6ca38da21e2cdac549e5eae1de7a18ee534c8c2291c908caabf159e90e6549db94ba7a3f3d97dd398a75df5b1a7cdfb25410b7efc4ed00d9995b37b58bf91ed7a3510cffea82f9e1c2a3290406004d09057d63b770fa0e53103199544eba662a2c302cf39008f142d2b16963e95ab10be7c2610168608f353a2f2c41c7056dec1a8c7a6bfa0027f9dedacb7786b67ea2c494d43ba851cf9415c1bcc52f027ec02c65534f608e9d166d51dd431cdf5871f5cdd1579cc06079df075a25062ba7e70d9666c4e7fed34cea0ea0f11ade1eb2a9b397bcaaad1061270ecf497803a5fce7f41e6504fbec71a7de7d066b8261868afc49b9e685f0dcce75e2fcb3ba8cf19057e3941576baf58fb821bd4268f7fae3028601da022e9b468646abdb4fa6098a449b4267d509d9a33f4c3ebcc32dac094d48ed600e765787fb92b1974f74f7bb4c66eb2bbd02895e6a381c1c452eaab1ae4731cf632f61ae2c905921174a3bc9bb4cdc89d630264b614988f3abbea1bd617ffa53d71b7d8a371462b773351a2dccaedd7f59cd728fadee059067bd80c94c8c9a1ffca2dc4f848b829c0561385aa82cc98503d0bb66a6aa4fae0703d12e60e1460efbbcdf2412c13e7c684d1b01102026343a414344585f6e7072748baeb5bbc6d1e2effbfe060e2e3e5160797c9ea6bac7f11024404a52575f6c898c97aab2c3cceaf22f3f535f7b818396a1b1bce6000000000000000000000000000018253642").unwrap(); + assert_eq!(sig.len(), MLDSA44_SIG_LEN); + + if MLDSA44::verify(&mldsa44_pk, msg, None, &sig).is_ok() { + eprintln!("Verification succeeded!"); + } else { + panic!("Verification failed! -- figure that out"); + } +} + +fn bench_mldsa44_lowmemory_verify() { + use bouncycastle_mldsa_lowmemory::{MLDSATrait, MLDSA44, MLDSA44_SIG_LEN, MLDSA44PublicKey}; + use bouncycastle_hex as hex; + + eprintln!("MLDSA44_lowmemory/Verify"); + + let msg = b"The quick brown fox jumped over the lazy dog"; + + /* One-time setup of the KAT -- commented out so that we're not capturing keygen in the bench */ + // let seed = KeyMaterial256::from_bytes_as_type( + // &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + // KeyType::Seed, + // ).unwrap(); + // + // let (mldsa44_pk, _mldsa44_sk) = MLDSA44::keygen_from_seed(&seed).unwrap(); + + // eprintln!("pk:\n{}", &*hex::encode(&mldsa44_pk.encode())); + // let mu = MLDSA44::compute_mu_from_sk(&mldsa44_sk, msg, None).unwrap(); + // let sig = MLDSA44::sign_mu_deterministic(&mldsa44_sk, &mu, [0u8; 32]).unwrap(); + // eprintln!("sig:\n{}", &*hex::encode(sig)); + + let mldsa44_pk = MLDSA44PublicKey::from_bytes(&*hex::decode("d7b2b47254aae0db45e7930d4a98d2c97d8f1397d1789dafa17024b316e9bec94fc9946d42f19b79a7413bbaa33e7149cb42ed5115693ac041facb988adeb5fe0e1d8631184995b592c397d2294e2e14f90aa414ba3826899ac43f4cccacbc26e9a832b95118d5cb433cbef9660b00138e0817f61e762ca274c36ad554eb22aac1162e4ab01acba1e38c4efd8f80b65b333d0f72e55dfe71ce9c1ebb9889e7c56106c0fd73803a2aecfeafded7aa3cb2ceda54d12bd8cd36a78cf975943b47abd25e880ac452e5742ed1e8d1a82afa86e590c758c15ae4d2840d92bca1a5090f40496597fca7d8b9513f1a1bda6e950aaa98de467507d4a4f5a4f0599216582c3572f62eda8905ab3581670c4a02777a33e0ca7295fd8f4ff6d1a0a3a7683d65f5f5f7fc60da023e826c5f92144c02f7d1ba1075987553ea9367fcd76d990b7fa99cd45afdb8836d43e459f5187df058479709a01ea6835935fa70460990cd3dc1ba401ba94bab1dde41ac67ab3319dcaca06048d4c4eef27ee13a9c17d0538f430f2d642dc2415660de78877d8d8abc72523978c042e4285f4319846c44126242976844c10e556ba215b5a719e59d0c6b2a96d39859071fdcc2cde7524a7bedae54e85b318e854e8fe2b2f3edfac9719128270aafd1e5044c3a4fdafd9ff31f90784b8e8e4596144a0daf586511d3d9962b9ea95af197b4e5fc60f2b1ed15de3a5bef5f89bdc79d91051d9b2816e74fa54531efdc1cbe74d448857f476bcd58f21c0b653b3b76a4e076a6559a302718555cc63f74859aabab925f023861ca8cd0f7badb2871f67d55326d7451135ad45f4a1ba69118fbb2c8a30eec9392ef3f977066c9add5c710cc647b1514d217d958c7017c3e90fd20c04e674b90486e9370a31a001d32f473979e4906749e7e477fa0b74508f8a5f2378312b83c25bd388ca0b0fff7478baf42b71667edaac97c46b129643e586e5b055a0c211946d4f36e675bed5860fa042a315d9826164d6a9237c35a5fbf495490a5bd4df248b95c4aae7784b605673166ac4245b5b4b082a09e9323e62f2078c5b76783446defd736ad3a3702d49b089844900a61833397bc4419b30d7a97a0b387c1911474c4d41b53e32a977acb6f0ea75db65bb39e59e701e76957def6f2d44559c31a77122b5204e3b5c219f1688b14ed0bc0b801b3e6e82dcd43e9c0e9f41744cd9815bd1bc8820d8bb123f04facd1b1b685dd5a2b1b8dbbf3ed933670f095a180b4f192d08b10b8fabbdfcc2b24518e32eea0a5e0c904ca844780083f3b0cd2d0b8b6af67bc355b9494025dc7b0a78fa80e3a2dbfeb51328851d6078198e9493651ae787ec0251f922ba30e9f51df62a6d72784cf3dd205393176dfa324a512bd94970a36dd34a514a86791f0eb36f0145b09ab64651b4a0313b299611a2a1c48891627598768a3114060ba4443486df51522a1ce88b30985c216f8e6ed178dd567b304a0d4cafba882a28342f17a9aa26ae58db630083d2c358fdf566c3f5d62a428567bc9ea8ce95caa0f35474b0bfa8f339a250ab4dfcf2083be8eefbc1055e18fe15370eecb260566d83ff06b211aaec43ca29b54ccd00f8815a2465ef0b46515cc7e41f3124f09efff739309ab58b29a1459a00bce5038e938c9678f72eb0e4ee5fdaae66d9f8573fc97fc42b4959f4bf8b61d78433e86b0335d6e9191c4d8bf487b3905c108cfd6ac24b0ceb7dcb7cf51f84d0ed687b95eaeb1c533c06f0d97023d92a70825837b59ba6cb7d4e56b0a87c203862ae8f315ba5925e8edefa679369a2202766151f16a965f9f81ece76cc070b55869e4db9784cf05c830b3242c8312").unwrap()).unwrap(); + let sig = &*hex::decode("5e93b785c5119c3983a291b18420fdbe4bca53d5a3732922faaacd5a5d32a745c78d105ba10bee1ed8069f19e6c537bda16e89d39004c359d1fd381a0291f1c51f1c38edcdb315c8c69570d8f25f1655ba8ea83aff24b8b6be8de762342e347eab2caa6803ed705952dd6450c5185e9d60ce96e8dca423a02f646cea690164a226e4c3d6a515ce16290f19b2c626da9b450ecf665013c5e226b6c0ac5c07ce90e278f1b0134e385d13e74208a0b3ff052a362579f9207ea01f18a039aa1b97ae3452675b620771f8012ee7a4e55c98bfd2019ed8a3b00acea8e8ab28172faa42ca1fda83c5ffe81a45be736bdedd5fb300ce17078b380f620bdeebad693601372c85eacf79bc98e1b48f2ad7e5dce4279a1295bb2ba60a0c5e3726642d2336c5eb1d37c8623c7558241318d89bc783c4f00098077484623c217560a0c7aaf75dcaccb78ee69c207c27c8bf3965ccf58a80c88efcc7e5deb3615d5045a741c4dac0a021dd060d315d4ec2857eb664d728d0af973bea07e1ca563faa0e19996cea3770316c11a5066665662005ace98f6110e883bae060daa7b6d83379e0878796691708a32b85730de8b92d89f90a3660c949165b14612567662e162232296cbd143517a282e22c46b63606d3c14ed4559a5a1c459bab7f355007ad6f7e3b1e07445dfc96bd9b75080b3d4f68998490a26b5e090be2674071ab925bb650590856c59f8ba7488d2b72f840ac3eafe4dd91f0f51c4364112c1a139e3e942a597b93a1e3f4faded129c14b5978b315e2246a93146a79365f0f597a18340cca86bb15ceed39f175eab1e546535afb966f0a65a8f66f737ab02897eddfe92cf7786894843c2691464776c94bd450a1069138b26df83b2d1dd801143a8fdfdc2514cc5b5831ab53a75c55ef29f40e7c63d2c72abe97e2af14853be49be16f4730a159974970951439e55c1589d0f4a162e3517df9d7abc98d8a307216e7f1cb4627c9175c0eef23337e56d5281b83726fff40a148b0c48e8df3496a2118d80219aef8f40b29fba1f2f78786b67ffb7b7d47d406b765bd136610bedeb95cd7321f58f3b836c9258be35d78b498f3efe1db2b243d734fab159baed8807c3cccf83eb2eaf8a9af01a518d48c60e91a96812ad689c2d83cc4e8e9b3650422bed6f13c24adaad91c95b3e3cf354f0f6bc9ee8941a6b15b6975131d95233d8935de367efc6d86a45dac7d0f1ddd9aebd2c59c027fcda448801e93e733aca51874be9ab927a904f96ddb7a46b2da13261d522b23c950c01d5f5e112b76f851ff234f06f8d5e65b1319abcd79a180ae063d65b28c745878c06dbb69ba73293eab34434bf1a92fba691993bd0ff3edac76a12f80c0ada4b1969c7665589d530a67016a625403c537032904f2e104547cd3ea406260dd357fa06ea012a785826c160e99ffd065b0e3f33c7689d3552ab9e2e09fa7e55bbcef042242bcacad8a3da47bcc54a121f1526c8cd4cc5a892a8131cf4eefaf4248ddd6a11ec427ba378aae89aaf582ce1f4e32690a555e740761d358ad4e92bc38418aa782da916524fb09ab2ca6b3d3113d6f2c2a6a9b9d29d4e7489255252af075cbf9feacedae6f3ec0b070824689dd3c78ac143ed6776d95dd8f13d435a290bdca4c11318e5acce04469644e1374a9451b6204f3b3961b7dd239e306fef5f4f4e51b78b0fb9dcee69c3e790b231f2e65fd1ab1c2a75b07067d5c16dde00983a58ffcdaaaee16d2742e133ed737b48064c8a38eca35ab3fa18f6d62f642b12cfdc7980f2ab7db321fec9dcfe499b4fc1ee7eb297954056617c60a6640b92835d165c3c00a951952614488d5657ba0b5e90ae9e0ef7b3b9ecaebd81b8551b6d70e835b2734761639d42e76ffc5b3272b61c896b45b4bd18f30e58c440643ba159221cc6739a19a65f2911fae47b0d4cac4200a6f043b17a03ad393ecb823ed03c8b6cd68167e6c8234f7432557db272079ee899aede73b6b98d6003f45789a141b60d6db40cd2a5974571a4ad3667b889318ba60285d903a2eac01c21608838c40907de6bbabe042cf2ecdd97f549f95ec698d79222c65ba27c30d332a68d057aecdc9388aa34320e0aa74fdbd4d1b643cace216b6d8ad8f07a99955bfdb743a86b40fc61527baca434ac2a7fbeaa77111dc8098b17e800f59dd77ccb0e67707e60123d334e073a2f5a16ffbcd701389add57c3ceccb88b286ac1e6e3e6485af1a12ea241d14a1b5003d7f3bc9e957d4483c0f9f703b3a187d55e505817615fbc4ae0837616184245cfba61ce3b929e33f52b71cdd7b6a0da55c1f997510b1a9002ca4e0678373a3b1ab2897e6b423f15a440a636cc861491ef41ad0aa627d8e198a5ee7bd7b6cb2c9ce2a8cc015f0d206de4c49e2f87f310954a10d86e294f742ee186f4ae9815f699622792206cafba8f5621738160e6c5d611a8252c6f35085b604ef895164d4ea6ddd310c7d8f0c879fb1f884c5741d096b3d2da0ce1151790dda881d18cb6b19a9fed6f5254b7d52d5d92bbbe24c9d6a65604a0b8ed24ad5c197d683f598743c96b5960e8723732b5bd647e9dbeaa851d0e1cf6d2c070d4442762c28098c5cf5a54b2b5e69a99b10815bf0f477bb71f0d5d3a62ba2b3e29bf84d4b4e574707f5f74af704d277bd6ca38da21e2cdac549e5eae1de7a18ee534c8c2291c908caabf159e90e6549db94ba7a3f3d97dd398a75df5b1a7cdfb25410b7efc4ed00d9995b37b58bf91ed7a3510cffea82f9e1c2a3290406004d09057d63b770fa0e53103199544eba662a2c302cf39008f142d2b16963e95ab10be7c2610168608f353a2f2c41c7056dec1a8c7a6bfa0027f9dedacb7786b67ea2c494d43ba851cf9415c1bcc52f027ec02c65534f608e9d166d51dd431cdf5871f5cdd1579cc06079df075a25062ba7e70d9666c4e7fed34cea0ea0f11ade1eb2a9b397bcaaad1061270ecf497803a5fce7f41e6504fbec71a7de7d066b8261868afc49b9e685f0dcce75e2fcb3ba8cf19057e3941576baf58fb821bd4268f7fae3028601da022e9b468646abdb4fa6098a449b4267d509d9a33f4c3ebcc32dac094d48ed600e765787fb92b1974f74f7bb4c66eb2bbd02895e6a381c1c452eaab1ae4731cf632f61ae2c905921174a3bc9bb4cdc89d630264b614988f3abbea1bd617ffa53d71b7d8a371462b773351a2dccaedd7f59cd728fadee059067bd80c94c8c9a1ffca2dc4f848b829c0561385aa82cc98503d0bb66a6aa4fae0703d12e60e1460efbbcdf2412c13e7c684d1b01102026343a414344585f6e7072748baeb5bbc6d1e2effbfe060e2e3e5160797c9ea6bac7f11024404a52575f6c898c97aab2c3cceaf22f3f535f7b818396a1b1bce6000000000000000000000000000018253642").unwrap(); + assert_eq!(sig.len(), MLDSA44_SIG_LEN); + + if MLDSA44::verify(&mldsa44_pk, msg, None, &sig).is_ok() { + eprintln!("Verification succeeded!"); + } else { + panic!("Verification failed! -- figure that out"); + } +} + +fn bench_mldsa65_verify() { + use bouncycastle_mldsa::{MLDSATrait, MLDSA65, MLDSA65_SIG_LEN, MLDSA65PublicKey}; + use bouncycastle_hex as hex; + + eprintln!("MLDSA65/Verify"); + + let msg = b"The quick brown fox jumped over the lazy dog"; + + /* One-time setup of the KAT -- commented out so that we're not capturing keygen in the bench */ + + // let seed = KeyMaterial256::from_bytes_as_type( + // &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + // KeyType::Seed, + // ).unwrap(); + // + // let (mldsa65_pk, mldsa65_sk) = MLDSA65::keygen_from_seed(&seed).unwrap(); + // + // eprintln!("pk:\n{}", &*hex::encode(&mldsa65_pk.encode())); + // let mu = MLDSA65::compute_mu_from_sk(&mldsa65_sk, msg, None).unwrap(); + // let sig = MLDSA65::sign_mu_deterministic(&mldsa65_sk, &mu, [0u8; 32]).unwrap(); + // eprintln!("sig:\n{}", &*hex::encode(sig)); + + let mldsa65_pk = MLDSA65PublicKey::from_bytes(&*hex::decode("48683d91978e31eb3dddb8b0473482d2b88a5f625949fd8f58a561e696bd4c27d05b38dbb2edf01e664efd81be1ea893688ce68aa2d51c5958f8bbc6eb4e89ee67d2c0320954d57212cac7229ff1d6eaf03928bd51511f8d88d847736c7de2730d5978e5410713160978867711bf5539a0bfc4c350c2be572baf0ee2e2fb16ccfea08028d99ac49aebb75937ddce111cdab62fff3cea8ba2233d1e56fbc5c5a1e726de63fadd2af016b119177fa3d971a2d9277173fce55b67745af0b7c21d597dbeb93e6a32f341c49a5a8be9e825088d1f2aa45155d6c8ae15367e4eb003b8fdf7851071949739f9fff09023eaf45104d2a84a45906eed4671a44dc28d27987bb55df69e9e8561f61a80a72699503865fed9b7ee72a8e17a19c408144f4b29afef7031c3a6d8571610b42c9f421245a88f197e16812b031159b65b9687e5b3e934c5225ae98a79ba73d2b399d73510effad19e53b8450f0ba8fce1012fd98d260a74aaaa13fae249a006b1c34f5ba0b882f26378222fb36f2283c243f0ffeb5f1bb414a0a70d55e3d40a56b6cbc88ae1f03b7b2882d98deea28e145c9dedfd8eaf1cef2ed94a8b050f8964f46d1ea0d0c2a43e0dda6182adbf4f6ed175b6742257859bf22f3a417ecf1f9d89317b5e539d587af16b9e1313e04514ffa64ba8b3ff2b8321f8811cb3fb022c8f644e70a4b80a2fbfee604abb7379091ea8e6c5c74dfc0283666b40c0793870028204a136bf5da9568eb798d349038bdb0c11e03445e7847cb5069c75cf28ac601c7799d958210ddbcb226e51afef9f1de47b073873d6d3f97456bede085082e74a298b2cd48f4b3093155f366c8fa601c6af858dfa32c08491b2a29887f90335949a5d6edaa679882a3a95d6bf6d970a221f4b9d3d8cbf384af81aac95e2b3294e04789ac83727a5dc04559f96af41d8a053516feeeebc52746eb6ab2819e09108710d835f011fa63065872ad334d5cdffb2b2310507e92fc993ae317da97f4f309cdaf0f67ed99d90215576083849f953b246d7fedb3fdb67679850a5ad404e64147fb7cf4f6aeddd05afb4b834968d1fe88014960dce5d942236526e12a478d69e5fbe6970310b308c06845018cfc7b2ab430a13a6b1ac7bb02cccbb3d911ac2f11068613fbe029bfdce02cf5cd38950ed72c83944edfbc75615af87f864c051f3c55456c5412863a40c06d1dab562bdff0571b8d3c3917bbd300880bba5e998239b95fa91b7d6416d4f398b3adbcd30983ed3592b4d9ef7d4236fd00f50d98aa53a235ac4172720f77d96172672980cfe8ff7a5a702783edc2ba31b2259015a112fc7f468a9c2f9464039002d30ef678b4cb798bc116216bf7a9a7c18ba03b7b58fd07515d3115049d3614be7a07e744300750df1d2c58753389059eafc3d785ccdd31c07648bedc03a5c3b8ad46d064d59c13d57374729fc4e295362e2a5191204530428bc1522afa28ff5fe1655e304ca5bc8c27ad0e0c6a39dd4df28956c14b38cc93682cefe402bbd5e82d29c464e44eb5d37b48fc568dfe0cc6e8e16baea05e5135590f19294e73e8367b0216dbb815030b9de55913f08039c42351c59e5515dd5af8e089a15e625e8f6dee639386c46497d7a263288774de581a7de9629b41b4424141f978fb8331208efdec3c6e0de39bc57063f3dcd6c470373c08891ea29cbc7cc6d6483b8889083ace86aa7b51b1c2cfe6e2ad18d97ce36fbc56ea42fae97e6a7ac114864478c366df1ebb1e7b11a9098504fd5975bdf1f49dc70002b63c1739a9d263fbad4073f6a9f6c2b8af4b4c332a103a0cffa5deeb2d062ca3c215fd360026be7c5164f4a4424ef74948804d66f46487732c8202c795478647b4ea71d627c086024cca354a41f0877b38f19b3774ad2095c8da53b069e21c76ae2d2007e16719ed40080d334f7da52e9f5a5990439caf083a95b833f02ad10a08c1a6d0f260c007285bd4a2f47703a5aef465287d253b18ac22514316210ff566814b10f87a293d6f199d3c3959990d0c1268b4f50d5f9fcefbbf237bd0c28b80182d6659741f14f10bfbb21bba12ab620aa2396f56c0686b4ea9017990224216b2fe8ad76c4a9148eef9a86a3635a6aa77bc1dcfb6fba59a77dfda9b7530dc0ca8648c8d973738e01bab8f08b4905e84aa4641bd602410cd97520265f2f231f2b35e15eb2fa04d2bd94d5a77abaf1e0e161010a990087f5b46ea988b2bc0512fda0fa923dadd6c45c5301d09483673265b5ab2e10f4ba520f6bbad564a5c3d5e27bdb080f7d20e13296a3181954c39c649c943ebe17df5c1f7aae0a8fe126c477585a5d4d648a0d008b6af5e8cd31be69a9296d4f3fd25ed86f221e4b93f65f5929967533624b9235750c30707550b58536d109a7131c5a5bbe4a5715567c12534aec7660761eebb9fae2891c774589b80e566ad557ddef7367196b7227ea9870ef09ddfec79d6b9319a6879b5205d76bf7aba5acf33afb59d17fc54e68383d6be5a08e9b66da53dcde008bb294b8582bd132cdcc49959fdbc21e52721880c8ad0352c79f03a43bbd84c4cdfdc6c529005e1e7cd9a349a7168a35569ba5dea818968d5a91466bd6e64e20bf62417198afc4e81c28dd77ed4028232398b52fbde86bc84f475b9016710ce2aabc11a06b4dbac901ec16cf365ca3f2d53813948a693a0f93e79c46ca5d5a6dca3d28ca50ad18bd13fca55059dd9b185f79f9c47196a4e81b2104bc460a051e02f2e8444f").unwrap()).unwrap(); + let sig = &*hex::decode("9061f15cbf2092f744fbcd799eb02414053c1b0f7412124bedc41cf9a3db0166469e874037d7f081e5f8d3d2033a0307d1c49ed01fe64578c4a6fabd80880cdf1911848f184d4bcf536ca795a0fb1aa19ab7ee3ba6b58bd64bbeac9f58650fff1ef5a97ab6916df962072e20e7c6be96090e3a781a504bc4442bd8889a0aa628907a74299f39fa836031f1bd68355bebe7ae93c1e361a9efbed1325d96227070461fcd6f151b8669d9229b977d9ee51fd2260c3e4a2e820416f9e074958dc3b3e2217e6312b7e0b582a048981cf6579f4bc7715b78c808e4c57e3b8aa38b05c04fcedf209f52c1e331ae83dbdff60ba450a17cc397568e54bc3f16ddf30b92747ce460d925b9be20a1d35e2aed97f124af2616a5361df28ba30e522dd08fa00fd28d1ac484d756a89e3a442fefe8332c56cd2a9fde691bdbda43f1cc54cef57bead96120b50c7d4695bdbb1303cc5ddda898e4eeb83083176e40e0232cdd1c3150371df05d6fdad7e1164d90393cf308e99edfeb31fed263e2866ee3b7f3937b399c974d87ba7b489efe3c9b80371d2928446adc31991ab0cefaaa080575b9ec81cfa133a9911c035a8058d0d3f2e34de4a9fb009bb4ccdb16de7b908574a7496725ff857556c1b33917e986c80f1014a9e3083add2fb35f345c5d06159e443329d0da099987b996c3731592b460c2ffd2955f7546f4216100ba43188803ff9b36969685f909fa2539323b8c8ec1c095a5085e554dd450e0e67ab670b6a11ebf6c25520fc13e364060f91f9b7f3d5cb48ff28b8fc83d4293f1f35ad6ff6ae4574ad7a1c6005fc0389a7b21386b0850a05d832fe6a14bb2b1db1f8e20bd09174946cd098b81c8f797e95f2143a949770cf1219bfef039db51a80fc247f65f41554c7173dd805ba82fdf47ab6d4bfd37dfe46fc47904421ae00dc005a22f9c4784b0ea9e665392a412245016d5c6d7673a6a180d228d4255a538e451ffd8b414d40304c0c888992e0ab6de1602109527417bc1c7eb782ae77a8c3cdfc1d13a1e874207898264e38080243109c5969649ac8383417e922ba115331142d0ed35440b15d40bee0cf58af37c0f0524ffac1c71ceed3bb82f76ab108a8ad1a0c8b78d9341148c642369be7bef59d46f49d70c83560607f140848ec9a7607d4a08f8b6e4447f5523f416981888a8de9647ffef79389e4983e5c9387698d0cc2d429322365ce7e7b5fd6d6eb921c813fcf06199fe1ca41e9cfe03b539f321671a2acad0963f876f9db7a1c4371b9f101005217995b5b6a40976246d245da603dba8dac812a5480c3476a99d0ffdf0ef943d72d912543148b2fe78e8b0159324fe9bcd4ced33cd212fe4f3dfd6d4c5e1958beb95ac6b533ace3e78015e3880b52bf45299263a4c0096f8ba5fe3a6298cab675cb7f382e7ef49720eb4cf47376e2d2574122ccf91129c858e948904fecefb91226ed42403ba12dd3258909a87dfcbf65cc3adc3d98d277fdcec7664e2292b7d27afbb5aafb405c20a34b2fe2c0849ee280bb891dfdf59f19b89b0246358db54cf3fdc66eaaaa750c8903f1d42678f3edf0b7530410aa881bc617f94346379854af4532e61f65aae7576c35faf55e155bd6787b4634d54191907e155c239e68480cdfa0c87054bfb62855f409a20d5335fb123e681e64ec847cd985b6062059f436aebac623c038b6c3405ac325191a8d1126a5ef8f38cccbf144a5c324c1e093cf99efbe10ca03d439bcfb8ba5e293b7d318837f7bc42a99964392369da76e79d71d1a2c248a11324a87ae1e3cbeab6fb0d0bcae1ef55e43dfb6f1b4cfb82c7a778fb828a3727ef07685fe38a74b3dd25d015322c2d9f245c08d8c2b43865694233782eb734436c4eddef5406208d6c4572c7371262fe02319cfbbcf2e23bed8aa969d1ae6f5f25ff6b8ebcf0925066f761a39bbff49f0c8dbc3be84f0c442b044ea01b669747e3c8293cfe9ccdf2ef063ae3d28d10720c279a2691616abd23b055cfc6c562125df4ad0fa6631304972ddc3674b1aaa7665bf621320d83eac8d5b371d7d719829f58b23458182558710de31d81ef9a47d8839c79640b2025d1965a418bc90e4115f1423311a8b64fcde0f2d2145ee535b0931b84bc8110445f2ff68d136ed709ddb7ea9ff75f3b4e8b4f836230ca9e81069477f634e07270af60ef96f72557a081d664abcf35548f699484653da645483ff2bf5998617ae8bfa62d56e714f3c0136e5035a3f78e06c2f470df7fd3380d14033f81e2aae6b4d90487dab76b9b3b8761fb56c36f5429da3d4346cb22e641ad8d7d2d80fa240d4e0154e6b3d2f1b3ef6cf174c08d062f575c83a4078174f874364df36a6328beeef69ba7f90e1df9fdcec9a2f15ebf04fa7d6756da2e5a59c9cbbcbc397d6fb28d0fc9a60534dff0752716ed079ad1ab19a224d1c8ae8a53242fd164989ff997489b6520eb3c0e97f4bcc1a9c3cbd44f008c03ef52cf7e626881d246925e0336c0ac668867f853da7820f914115a7c77ac31b66f46fbf97f66fa26416fc4581d459a4f2462d52cf0c79b278955aa73e8fa56e3c320f516bcc54c97e587199c15ab953cc37189b81c70cabb2559e445bcc9d8174ad7574e9acb02f43e0c34ff5e6746ee730ad41ff8eef93c2071c2649063dd92f343c06ef6abaf98f28d98d968071c12cc10a90c22d8b3b3480c76f7a51b7ec594b3435d2e3d779c1a15037697f3a058650472e47eecd5f32eb3243a516f0e703f9888c84690750648d6a9a876bf1f353db6891dc6d317d6e87ac088f42b5f6f20d799ece4fa7aaa928d2ac795e8de83d1e1c7fa2f9a4106693e981c21c63b3221c4fa2649f45f0c6e05dbf24011af16ab2e5fe94a640b485988037ebe1e8ad0b2623d95e9947f0726121d7828614e3b2d77a7a1f9a938bea9a1a7a2627b7d2e358c42ccc6c0b80a15a1c2f6e9aaf0495bdb7bb8d4b0e28a1ab5ab93ca0ff3e3f910c490c13486852534d5e12160835ec5916c5c68349c4e2d8fa956c643277edd3b6c81c88c010421705fd317ff9e3c94df0ed5305f530acbccf8dd0e87140cd38152664a572c168cd72595b7fac243c03f3fb33ef74a28c0e4469f94587c13704e9efe8010b2125aca78c22c33c82366e1a7c4028c2ae2e8d26e1a57e4297fac987f84a0a27f42b4c93a4f4d14569824b0880fb67407ed58f267ac403aa0b1f93784b4b4c67036037e60d58072611b0e90ca316976ef4e0b302cdad1b6dcca92efb8e1f6be2397967508be2c02a25ed0380ba1f7955f857c8fb043297780d136b2b064040c8e55143d715ea997e134ed973c98ef82786f0ccf66c17d863542180c66d54d08e116f2e35d995e214489ad0fad7a55fe9ebc1a777fe34141147c080b98d13463a3bbc6fc82f2fc95f4de7b3591d9c8cd4416917a4338095d5620104b7be13f5a131dd3f7aad5b559d11e8171dfb91e2bb1e47ac3810b1cdc1a1e370c867b7b7b50c4688dce545763157e02f47e1cc661d5bf2fbc336cfae080ab15728b1ab9dd199f2779d451e6178977fb658c17344cffb7aa3af5791a28fc8a089c85187753e5e313c8d1f0fe7755e28be444426a189e8bce2d2f79db31d4c3ca911a83455525355f95d159351cd731a88e55403851236ee2128f279d5be644c042453ae65d9e9f3b40d6c82bdeb002acdee061ecca3f2dceabef9a900e6e063d56ab39cb82dbc77a4677572d7616cd72c0f6d5b9b941dfda1fe7c896b8cc24d65a4322d712a84e94adfc8ed0cc56cc1ae97f775bd3cea5b20b524d9a7a916056e19af095d30171e5e14c7c998f78dc44845edf307363eab7913f680a5e5a1540a6f945507ffa67591f8d1a2920ab3b6e754e35379dd67870c242335e2717903ff3c687e5c33dc953416865d5f23bd752e55492b9d5d888d7b37ef33b0a6774d052b0987c066a2e01767207aa7fbfc393ca62874613dde3794f74fadb5d55b877b877a605918c812610fbcafad72ee245e6dd8721138d6bd3f4eedad853aed1ec437ad02ac937c80dae26fa5f70083bd346779b779387f7b3d2aae57770d8177928833281ccb7a38da24834fd9726fd17eb603cba9041e82bfeed0e33942dde1d48c271f5b39aa7230f41afb89d36f7976eee4f51a036743031c534f64685b94c990a93a5737fe628ee9cda8ed9c08b11d3836f833835c445b317a77ead7599d1a0c08873014510d36bb7ff5fb961277589ea48c32a60c87ec40681be067b17785ec44825bd89faa25249e735a628b6eebcc6cce4e0314c627588118c40b2e0d460d8d5ce358c56458f36914ca203f5a5381c6deb5a76bbc08c40a87437da0d0b571788a05e9f96d9bb770de8a0b1b960ff2a44a964c9b7939853742e83ce8deb79191b2d82454655f227079dd8c5b0216c8470b8e1ac70526301bbfa2bc4adca68a766ccb2a6e0ebf2e99905bf5242590b01703868b3faf841c11c383be145a40fea6375e18a01468e459603b5efdf8a4e9abd179280ae8b5947d78d2f0c4d37715eaa42bc37cf8730e41ffbf9826d46424f2922a96033cefaa8b4bbe4c8b89d43501fd5211d5392ca19a98ba127d9025b5c6e86ba024471940549a2b5d8e14961c9dc19696da1a5bffd01030d5e6100000000000000000000000000000000000000000000000005090f131a1f").unwrap(); + assert_eq!(sig.len(), MLDSA65_SIG_LEN); + + if MLDSA65::verify(&mldsa65_pk, msg, None, &sig).is_ok() { + eprintln!("Verification succeeded!"); + } else { + panic!("Verification failed! -- figure that out"); + } +} + +fn bench_mldsa65_lowmemory_verify() { + use bouncycastle_mldsa_lowmemory::{MLDSATrait, MLDSA65, MLDSA65_SIG_LEN, MLDSA65PublicKey}; + use bouncycastle_hex as hex; + + eprintln!("MLDSA65_lowmemory/Verify"); + + let msg = b"The quick brown fox jumped over the lazy dog"; + + /* One-time setup of the KAT -- commented out so that we're not capturing keygen in the bench */ + + // let seed = KeyMaterial256::from_bytes_as_type( + // &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + // KeyType::Seed, + // ).unwrap(); + // + // let (mldsa65_pk, mldsa65_sk) = MLDSA65::keygen_from_seed(&seed).unwrap(); + // + // eprintln!("pk:\n{}", &*hex::encode(&mldsa65_pk.encode())); + // let mu = MLDSA65::compute_mu_from_sk(&mldsa65_sk, msg, None).unwrap(); + // let sig = MLDSA65::sign_mu_deterministic(&mldsa65_sk, &mu, [0u8; 32]).unwrap(); + // eprintln!("sig:\n{}", &*hex::encode(sig)); + + let mldsa65_pk = MLDSA65PublicKey::from_bytes(&*hex::decode("48683d91978e31eb3dddb8b0473482d2b88a5f625949fd8f58a561e696bd4c27d05b38dbb2edf01e664efd81be1ea893688ce68aa2d51c5958f8bbc6eb4e89ee67d2c0320954d57212cac7229ff1d6eaf03928bd51511f8d88d847736c7de2730d5978e5410713160978867711bf5539a0bfc4c350c2be572baf0ee2e2fb16ccfea08028d99ac49aebb75937ddce111cdab62fff3cea8ba2233d1e56fbc5c5a1e726de63fadd2af016b119177fa3d971a2d9277173fce55b67745af0b7c21d597dbeb93e6a32f341c49a5a8be9e825088d1f2aa45155d6c8ae15367e4eb003b8fdf7851071949739f9fff09023eaf45104d2a84a45906eed4671a44dc28d27987bb55df69e9e8561f61a80a72699503865fed9b7ee72a8e17a19c408144f4b29afef7031c3a6d8571610b42c9f421245a88f197e16812b031159b65b9687e5b3e934c5225ae98a79ba73d2b399d73510effad19e53b8450f0ba8fce1012fd98d260a74aaaa13fae249a006b1c34f5ba0b882f26378222fb36f2283c243f0ffeb5f1bb414a0a70d55e3d40a56b6cbc88ae1f03b7b2882d98deea28e145c9dedfd8eaf1cef2ed94a8b050f8964f46d1ea0d0c2a43e0dda6182adbf4f6ed175b6742257859bf22f3a417ecf1f9d89317b5e539d587af16b9e1313e04514ffa64ba8b3ff2b8321f8811cb3fb022c8f644e70a4b80a2fbfee604abb7379091ea8e6c5c74dfc0283666b40c0793870028204a136bf5da9568eb798d349038bdb0c11e03445e7847cb5069c75cf28ac601c7799d958210ddbcb226e51afef9f1de47b073873d6d3f97456bede085082e74a298b2cd48f4b3093155f366c8fa601c6af858dfa32c08491b2a29887f90335949a5d6edaa679882a3a95d6bf6d970a221f4b9d3d8cbf384af81aac95e2b3294e04789ac83727a5dc04559f96af41d8a053516feeeebc52746eb6ab2819e09108710d835f011fa63065872ad334d5cdffb2b2310507e92fc993ae317da97f4f309cdaf0f67ed99d90215576083849f953b246d7fedb3fdb67679850a5ad404e64147fb7cf4f6aeddd05afb4b834968d1fe88014960dce5d942236526e12a478d69e5fbe6970310b308c06845018cfc7b2ab430a13a6b1ac7bb02cccbb3d911ac2f11068613fbe029bfdce02cf5cd38950ed72c83944edfbc75615af87f864c051f3c55456c5412863a40c06d1dab562bdff0571b8d3c3917bbd300880bba5e998239b95fa91b7d6416d4f398b3adbcd30983ed3592b4d9ef7d4236fd00f50d98aa53a235ac4172720f77d96172672980cfe8ff7a5a702783edc2ba31b2259015a112fc7f468a9c2f9464039002d30ef678b4cb798bc116216bf7a9a7c18ba03b7b58fd07515d3115049d3614be7a07e744300750df1d2c58753389059eafc3d785ccdd31c07648bedc03a5c3b8ad46d064d59c13d57374729fc4e295362e2a5191204530428bc1522afa28ff5fe1655e304ca5bc8c27ad0e0c6a39dd4df28956c14b38cc93682cefe402bbd5e82d29c464e44eb5d37b48fc568dfe0cc6e8e16baea05e5135590f19294e73e8367b0216dbb815030b9de55913f08039c42351c59e5515dd5af8e089a15e625e8f6dee639386c46497d7a263288774de581a7de9629b41b4424141f978fb8331208efdec3c6e0de39bc57063f3dcd6c470373c08891ea29cbc7cc6d6483b8889083ace86aa7b51b1c2cfe6e2ad18d97ce36fbc56ea42fae97e6a7ac114864478c366df1ebb1e7b11a9098504fd5975bdf1f49dc70002b63c1739a9d263fbad4073f6a9f6c2b8af4b4c332a103a0cffa5deeb2d062ca3c215fd360026be7c5164f4a4424ef74948804d66f46487732c8202c795478647b4ea71d627c086024cca354a41f0877b38f19b3774ad2095c8da53b069e21c76ae2d2007e16719ed40080d334f7da52e9f5a5990439caf083a95b833f02ad10a08c1a6d0f260c007285bd4a2f47703a5aef465287d253b18ac22514316210ff566814b10f87a293d6f199d3c3959990d0c1268b4f50d5f9fcefbbf237bd0c28b80182d6659741f14f10bfbb21bba12ab620aa2396f56c0686b4ea9017990224216b2fe8ad76c4a9148eef9a86a3635a6aa77bc1dcfb6fba59a77dfda9b7530dc0ca8648c8d973738e01bab8f08b4905e84aa4641bd602410cd97520265f2f231f2b35e15eb2fa04d2bd94d5a77abaf1e0e161010a990087f5b46ea988b2bc0512fda0fa923dadd6c45c5301d09483673265b5ab2e10f4ba520f6bbad564a5c3d5e27bdb080f7d20e13296a3181954c39c649c943ebe17df5c1f7aae0a8fe126c477585a5d4d648a0d008b6af5e8cd31be69a9296d4f3fd25ed86f221e4b93f65f5929967533624b9235750c30707550b58536d109a7131c5a5bbe4a5715567c12534aec7660761eebb9fae2891c774589b80e566ad557ddef7367196b7227ea9870ef09ddfec79d6b9319a6879b5205d76bf7aba5acf33afb59d17fc54e68383d6be5a08e9b66da53dcde008bb294b8582bd132cdcc49959fdbc21e52721880c8ad0352c79f03a43bbd84c4cdfdc6c529005e1e7cd9a349a7168a35569ba5dea818968d5a91466bd6e64e20bf62417198afc4e81c28dd77ed4028232398b52fbde86bc84f475b9016710ce2aabc11a06b4dbac901ec16cf365ca3f2d53813948a693a0f93e79c46ca5d5a6dca3d28ca50ad18bd13fca55059dd9b185f79f9c47196a4e81b2104bc460a051e02f2e8444f").unwrap()).unwrap(); + let sig = &*hex::decode("9061f15cbf2092f744fbcd799eb02414053c1b0f7412124bedc41cf9a3db0166469e874037d7f081e5f8d3d2033a0307d1c49ed01fe64578c4a6fabd80880cdf1911848f184d4bcf536ca795a0fb1aa19ab7ee3ba6b58bd64bbeac9f58650fff1ef5a97ab6916df962072e20e7c6be96090e3a781a504bc4442bd8889a0aa628907a74299f39fa836031f1bd68355bebe7ae93c1e361a9efbed1325d96227070461fcd6f151b8669d9229b977d9ee51fd2260c3e4a2e820416f9e074958dc3b3e2217e6312b7e0b582a048981cf6579f4bc7715b78c808e4c57e3b8aa38b05c04fcedf209f52c1e331ae83dbdff60ba450a17cc397568e54bc3f16ddf30b92747ce460d925b9be20a1d35e2aed97f124af2616a5361df28ba30e522dd08fa00fd28d1ac484d756a89e3a442fefe8332c56cd2a9fde691bdbda43f1cc54cef57bead96120b50c7d4695bdbb1303cc5ddda898e4eeb83083176e40e0232cdd1c3150371df05d6fdad7e1164d90393cf308e99edfeb31fed263e2866ee3b7f3937b399c974d87ba7b489efe3c9b80371d2928446adc31991ab0cefaaa080575b9ec81cfa133a9911c035a8058d0d3f2e34de4a9fb009bb4ccdb16de7b908574a7496725ff857556c1b33917e986c80f1014a9e3083add2fb35f345c5d06159e443329d0da099987b996c3731592b460c2ffd2955f7546f4216100ba43188803ff9b36969685f909fa2539323b8c8ec1c095a5085e554dd450e0e67ab670b6a11ebf6c25520fc13e364060f91f9b7f3d5cb48ff28b8fc83d4293f1f35ad6ff6ae4574ad7a1c6005fc0389a7b21386b0850a05d832fe6a14bb2b1db1f8e20bd09174946cd098b81c8f797e95f2143a949770cf1219bfef039db51a80fc247f65f41554c7173dd805ba82fdf47ab6d4bfd37dfe46fc47904421ae00dc005a22f9c4784b0ea9e665392a412245016d5c6d7673a6a180d228d4255a538e451ffd8b414d40304c0c888992e0ab6de1602109527417bc1c7eb782ae77a8c3cdfc1d13a1e874207898264e38080243109c5969649ac8383417e922ba115331142d0ed35440b15d40bee0cf58af37c0f0524ffac1c71ceed3bb82f76ab108a8ad1a0c8b78d9341148c642369be7bef59d46f49d70c83560607f140848ec9a7607d4a08f8b6e4447f5523f416981888a8de9647ffef79389e4983e5c9387698d0cc2d429322365ce7e7b5fd6d6eb921c813fcf06199fe1ca41e9cfe03b539f321671a2acad0963f876f9db7a1c4371b9f101005217995b5b6a40976246d245da603dba8dac812a5480c3476a99d0ffdf0ef943d72d912543148b2fe78e8b0159324fe9bcd4ced33cd212fe4f3dfd6d4c5e1958beb95ac6b533ace3e78015e3880b52bf45299263a4c0096f8ba5fe3a6298cab675cb7f382e7ef49720eb4cf47376e2d2574122ccf91129c858e948904fecefb91226ed42403ba12dd3258909a87dfcbf65cc3adc3d98d277fdcec7664e2292b7d27afbb5aafb405c20a34b2fe2c0849ee280bb891dfdf59f19b89b0246358db54cf3fdc66eaaaa750c8903f1d42678f3edf0b7530410aa881bc617f94346379854af4532e61f65aae7576c35faf55e155bd6787b4634d54191907e155c239e68480cdfa0c87054bfb62855f409a20d5335fb123e681e64ec847cd985b6062059f436aebac623c038b6c3405ac325191a8d1126a5ef8f38cccbf144a5c324c1e093cf99efbe10ca03d439bcfb8ba5e293b7d318837f7bc42a99964392369da76e79d71d1a2c248a11324a87ae1e3cbeab6fb0d0bcae1ef55e43dfb6f1b4cfb82c7a778fb828a3727ef07685fe38a74b3dd25d015322c2d9f245c08d8c2b43865694233782eb734436c4eddef5406208d6c4572c7371262fe02319cfbbcf2e23bed8aa969d1ae6f5f25ff6b8ebcf0925066f761a39bbff49f0c8dbc3be84f0c442b044ea01b669747e3c8293cfe9ccdf2ef063ae3d28d10720c279a2691616abd23b055cfc6c562125df4ad0fa6631304972ddc3674b1aaa7665bf621320d83eac8d5b371d7d719829f58b23458182558710de31d81ef9a47d8839c79640b2025d1965a418bc90e4115f1423311a8b64fcde0f2d2145ee535b0931b84bc8110445f2ff68d136ed709ddb7ea9ff75f3b4e8b4f836230ca9e81069477f634e07270af60ef96f72557a081d664abcf35548f699484653da645483ff2bf5998617ae8bfa62d56e714f3c0136e5035a3f78e06c2f470df7fd3380d14033f81e2aae6b4d90487dab76b9b3b8761fb56c36f5429da3d4346cb22e641ad8d7d2d80fa240d4e0154e6b3d2f1b3ef6cf174c08d062f575c83a4078174f874364df36a6328beeef69ba7f90e1df9fdcec9a2f15ebf04fa7d6756da2e5a59c9cbbcbc397d6fb28d0fc9a60534dff0752716ed079ad1ab19a224d1c8ae8a53242fd164989ff997489b6520eb3c0e97f4bcc1a9c3cbd44f008c03ef52cf7e626881d246925e0336c0ac668867f853da7820f914115a7c77ac31b66f46fbf97f66fa26416fc4581d459a4f2462d52cf0c79b278955aa73e8fa56e3c320f516bcc54c97e587199c15ab953cc37189b81c70cabb2559e445bcc9d8174ad7574e9acb02f43e0c34ff5e6746ee730ad41ff8eef93c2071c2649063dd92f343c06ef6abaf98f28d98d968071c12cc10a90c22d8b3b3480c76f7a51b7ec594b3435d2e3d779c1a15037697f3a058650472e47eecd5f32eb3243a516f0e703f9888c84690750648d6a9a876bf1f353db6891dc6d317d6e87ac088f42b5f6f20d799ece4fa7aaa928d2ac795e8de83d1e1c7fa2f9a4106693e981c21c63b3221c4fa2649f45f0c6e05dbf24011af16ab2e5fe94a640b485988037ebe1e8ad0b2623d95e9947f0726121d7828614e3b2d77a7a1f9a938bea9a1a7a2627b7d2e358c42ccc6c0b80a15a1c2f6e9aaf0495bdb7bb8d4b0e28a1ab5ab93ca0ff3e3f910c490c13486852534d5e12160835ec5916c5c68349c4e2d8fa956c643277edd3b6c81c88c010421705fd317ff9e3c94df0ed5305f530acbccf8dd0e87140cd38152664a572c168cd72595b7fac243c03f3fb33ef74a28c0e4469f94587c13704e9efe8010b2125aca78c22c33c82366e1a7c4028c2ae2e8d26e1a57e4297fac987f84a0a27f42b4c93a4f4d14569824b0880fb67407ed58f267ac403aa0b1f93784b4b4c67036037e60d58072611b0e90ca316976ef4e0b302cdad1b6dcca92efb8e1f6be2397967508be2c02a25ed0380ba1f7955f857c8fb043297780d136b2b064040c8e55143d715ea997e134ed973c98ef82786f0ccf66c17d863542180c66d54d08e116f2e35d995e214489ad0fad7a55fe9ebc1a777fe34141147c080b98d13463a3bbc6fc82f2fc95f4de7b3591d9c8cd4416917a4338095d5620104b7be13f5a131dd3f7aad5b559d11e8171dfb91e2bb1e47ac3810b1cdc1a1e370c867b7b7b50c4688dce545763157e02f47e1cc661d5bf2fbc336cfae080ab15728b1ab9dd199f2779d451e6178977fb658c17344cffb7aa3af5791a28fc8a089c85187753e5e313c8d1f0fe7755e28be444426a189e8bce2d2f79db31d4c3ca911a83455525355f95d159351cd731a88e55403851236ee2128f279d5be644c042453ae65d9e9f3b40d6c82bdeb002acdee061ecca3f2dceabef9a900e6e063d56ab39cb82dbc77a4677572d7616cd72c0f6d5b9b941dfda1fe7c896b8cc24d65a4322d712a84e94adfc8ed0cc56cc1ae97f775bd3cea5b20b524d9a7a916056e19af095d30171e5e14c7c998f78dc44845edf307363eab7913f680a5e5a1540a6f945507ffa67591f8d1a2920ab3b6e754e35379dd67870c242335e2717903ff3c687e5c33dc953416865d5f23bd752e55492b9d5d888d7b37ef33b0a6774d052b0987c066a2e01767207aa7fbfc393ca62874613dde3794f74fadb5d55b877b877a605918c812610fbcafad72ee245e6dd8721138d6bd3f4eedad853aed1ec437ad02ac937c80dae26fa5f70083bd346779b779387f7b3d2aae57770d8177928833281ccb7a38da24834fd9726fd17eb603cba9041e82bfeed0e33942dde1d48c271f5b39aa7230f41afb89d36f7976eee4f51a036743031c534f64685b94c990a93a5737fe628ee9cda8ed9c08b11d3836f833835c445b317a77ead7599d1a0c08873014510d36bb7ff5fb961277589ea48c32a60c87ec40681be067b17785ec44825bd89faa25249e735a628b6eebcc6cce4e0314c627588118c40b2e0d460d8d5ce358c56458f36914ca203f5a5381c6deb5a76bbc08c40a87437da0d0b571788a05e9f96d9bb770de8a0b1b960ff2a44a964c9b7939853742e83ce8deb79191b2d82454655f227079dd8c5b0216c8470b8e1ac70526301bbfa2bc4adca68a766ccb2a6e0ebf2e99905bf5242590b01703868b3faf841c11c383be145a40fea6375e18a01468e459603b5efdf8a4e9abd179280ae8b5947d78d2f0c4d37715eaa42bc37cf8730e41ffbf9826d46424f2922a96033cefaa8b4bbe4c8b89d43501fd5211d5392ca19a98ba127d9025b5c6e86ba024471940549a2b5d8e14961c9dc19696da1a5bffd01030d5e6100000000000000000000000000000000000000000000000005090f131a1f").unwrap(); + assert_eq!(sig.len(), MLDSA65_SIG_LEN); + + if MLDSA65::verify(&mldsa65_pk, msg, None, &sig).is_ok() { + eprintln!("Verification succeeded!"); + } else { + panic!("Verification failed! -- figure that out"); + } +} + +fn bench_mldsa87_verify() { + use bouncycastle_mldsa::{MLDSATrait, MLDSA87, MLDSA87_SIG_LEN, MLDSA87PublicKey}; + use bouncycastle_hex as hex; + + eprintln!("MLDSA87/Verify"); + + let msg = b"The quick brown fox jumped over the lazy dog"; + + /* One-time setup of the KAT -- commented out so that we're not capturing keygen in the bench */ + + // let seed = KeyMaterial256::from_bytes_as_type( + // &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + // KeyType::Seed, + // ).unwrap(); + // + // let (mldsa65_pk, mldsa65_sk) = MLDSA87::keygen_from_seed(&seed).unwrap(); + // + // eprintln!("pk:\n{}", &*hex::encode(&mldsa65_pk.encode())); + // let mu = MLDSA87::compute_mu_from_sk(&mldsa65_sk, msg, None).unwrap(); + // let sig = MLDSA87::sign_mu_deterministic(&mldsa65_sk, &mu, [0u8; 32]).unwrap(); + // eprintln!("sig:\n{}", &*hex::encode(sig)); + + let mldsa87_pk = MLDSA87PublicKey::from_bytes(&*hex::decode("9792bcec2f2430686a82fccf3c2f5ff665e771d7ab41b90258cfa7e90ec97124a73b323b9ba21ab64d767c433f5a521effe18f86e46a188952c4467e048b729e7fc4d115e7e48da1896d5fe119b10dcddef62cb307954074b42336e52836de61da941f8d37ea68ac8106fabe19070679af6008537120f70793b8ea9cc0e6e7b7b4c9a5c7421c60f24451ba1e933db1a2ee16c79559f21b3d1b8305850aa42afbb13f1f4d5b9f4835f9d87dfceb162d0ef4a7fdc4cba1743cd1c87bb4967da16cc8764b6569df8ee5bdcbffe9a4e05748e6fdf225af9e4eeb7773b62e8f85f9b56b548945551844fbd89806a4ac369bed2d256100f688a6ad5e0a709826dc4449e91e23c5506e642361ef5a313712f79bc4b3186861ca85a4bab17e7f943d1b8a333aa3ae7ce16b440d6018f9e04daf5725c7f1a93fad1a5a27b67895bd249aa91685de20af32c8b7e268c7f96877d0c85001135a4f0a8f1b8264fa6ebe5a349d8aecad1a16299ccf2fd9c7b85bace2ced3aa1276ba61ee78ed7e5ca5b67cdd458a9354030e6abbbabf56a0a2316fec9dba83b51d42fd3167f1e0f90855d5c66509b210265dc1e54ec44b43ba7cf9aef118b44d80912ce75166a6651e116cebe49229a7062c09931f71abd2293f76f7efc3215ba97800037e58e470bdbbb43c1b0439eaf79c54d93b44aac9efe9fbe151874cfb2a64cbee28cc4c0fe7775e5d870f1c02e5b2e3c5004c995f24c9b779cb753a277d0e71fd425eb6bc2ca56ce129db51f70740f31e63976b50c7312e9797d78c5b1ac24a5fa347cc916e0a83f5c3b675cd30b81e3fa10b93444e07397571cce98b28da51db9056bc728c5b0b1181e2fbd387b4c79ab1a5fefece37167af772ddad14eb4c3982da5a59d0e9eb173ec6315091170027a3ab5ef6aa129cb8585727b9358a28501d713a72f3f1db31714286f9b6408013af06045d75592fc0b7dd47c73ed9c75b11e9d7c69f7cadfc3280a9062c5273c43be1c34f87448864cea7b5c97d6d32f59bd5f25384653bb5c4faa45bea8b89402843e645b6b9269e2bd988ddacb033328ffb060450f7df080053e6969b251e875ecec32cfc592840d69ab69a75e06b379c535d95266b082f4f09c93162b33b0d9f7307a4eaaa52104437fed66f8ee3eabbd45d67b25a8133f496468b52baffdbfad93eef1a9818b5e42ec722788a3d8d3529fc777d2ba570801dfae01ec88302837c1fb9e0355727645ee1046c3f915f6ae82dad4fb6b0356a46518ffc834155c3b4fe6dafa6cc8a5ccf53c73a0849d8d44f7dcf72754e70e1b7dfb447bb4ef49d1a718f6171bbce200950e0ce926106b151a3e871d5ce49731bd6650a9b0ca972da1c5f136d44820ea6383c08f3b384cf2338e789c513f618cc5694a6f0cee104511e1ed7c5f23a1ebfd8a0db8424553240156dbf622831b0c643d1c551b6f3f7a98d29b85c2de05a65fa615eee16495bd90737672115b53e91c5d90028cf3f1a93953a153de53b44084e9ccff6b736693926daefebb2d77aa5ad689b92f31686669df16d1715cc58f7a2cfb72dd1a51e92f825993a74022be7e9eb6054654457094d14928f20215e7b222ac56b51adbec8d8bdb6983979a7e3a21b44b5d1518ca97d0b5195f51ed6a24350c89747e1edea51b448e3e9147054ce927873c90db394d86888e07dff177593d6f79e152302204aeb03be2386af3e24078bd028b1689f5e147c9f452c8ceb02ec59cc9db63a03576ceeafe98239023897da0236630a53c0de7f435a19869792fab36e7b9e635760f09069e6432e700035ac2a02879fff0a1e1bec522047193d94eb5df1efd53eea1144ca78940852f5ec9727904b366ede4f5e2d331fad5fc282ea2c47e923142771c3dd75a87357487def99e5f18e9d9ed623c175d02888c51f82c07a80d54716b3c3c2bdbe2e9f0a9bbaaebeb4d52936876406f5c00e8e4bbd0a5ec05797e6207c5ab6c88f1a688421bd05a114f4d7de2ac241fa0e8bedff47f762ddcbeaa91004f8d31e85095c81054994ad3826e344ba96040810fc0b2ad1de48cfade002c62e5a49a0731ab38344bc1636df16bf607d56855e56d684003c718e4bad9e5a099979fcddeeb1c4a7776cd37a3417cb0e184e29ef9bc0e87475ba663be09e00ab562eb7c0f7165f969a9b42414198ccf1bff2a2c8d689a414ece7662927665689e94db961ebaec5615cbc1a7895c6851ac961432ff1118d4607d32ef9dc732d51333be4b4d0e30ddea784eca8be47e741be9c19631dc470a52ef4dc13a4f3633fd434d787c170977b417df598e1d0dde506bb71d6f0bc17ec70e3b03cdc1965cb36993f633b0472e50d0923ac6c66fdf1d3e6459cc121f0f5f94d09e9dbcf5d690e23233838a0bacb7c638d1b2650a4308cd171b6855126d1da672a6ed85a8d78c286fb56f4ab3d21497528045c63262c8a42af2f9802c53b7bb8be28e78fe0b5ce45fbb7a1af1a3b28a8d94b7890e3c882e39bc98e9f0ad76025bf0dd2f00298e7141a226b3d7cee414f604d1e0ba54d11d5fe58bccea6ad77ad2e8c1caacf32459014b7b91001b1efa8ad172a523fb8e365b577121bf9fd88a2c60c21e821d7b6acb47a5a995e40caced5c223b8fe6de5e18e9d2e5893aefebb7aae7ff1a146260e2f110e939528213a0025a38ec79aabc861b25ebc509a4674c132aaacb7e0146f14efd11cfcaf4caa4f775a716ce325e0a435a4d349d720bcf137450afc45046fc1a1f83a9d329777a7084e4aadae7122ce97005930528eb3c7f7f1129b372887a371155a3ba201a25cbf1dcb64e7cdee092c3141fb5550fe3d0dd82e870e578b2b46500818113b8f6569773c677385b69a42b77dcba7acffd95fd4452e23aaa1d37e1da2151ea658d40a3596b27ac9f8129dc6cf0643772624b59f4f461230df471ca26087c3942d5c6687df6082835935a3f87cb762b0c3b1d0dda4a6533965bef1b7b8292e254c014d090fed857c44c1839c694c0a64e3fad90a11f534722b6ee1574f2e149d55d744de4887024e08511431c062750e16c74ab9f3242f2db3ffb12a8d6107faa229d6f6373b07f36d3932b3bdb04c19dd64eadd7f93c3c564c358a1c81dcf1c9c31e5b06568f97544c17dc15698c5cb38983a9afc42783faa773a52c9d8260690be9e3156aa5bc1509dea3f69587695cd6ff172ba83e6a6d8a7d6bbebbbcda3672731983f89bc5831dc37c3f3c5c56facc697f3cb20bd5dbadbd702e54844ac2f626901fe159db93dfd4773d8fe73562b846c1fc856d1802762840ebc72d7988bde75cbca70d319d32ce0cc0253bb2ad455723ee0c7f4736ce6e6665c5aca32a481c53839bc259167b013d0423395eeb9aaaee3206149a7d550d67fc5fdfe4a8a5c35d2510b664379ab8f72855a2af47abce2a632048eaf89e5cb4a88debc53a595103acce4f1cff18acff07afe1eb5716aa1e40b63134c3a3ae9579fa87f515be093c2d29db6d6b65c93661e00636b592704d093cc6716c2342eb1853d48c85c63ac8a2854462c7b77e7e3bd1eac5bca28ffaa00b5d349f8a547ad875b96a8c2b2910c9301309a3f9138a5693111f55b3c009ca947c39dfc82d98eb1caa4a9cbe885f786fa86e55be062222f8ba90a974073326b31212aece0a34a60").unwrap()).unwrap(); + let sig = &*hex::decode("781368e64dba542a7eacbd2257335cc943a03241009b797093c615f76a671a7591430441d80bb582304b33b9fce295e0dd57fe169355ddf4453a2aca62d8eb8109ef0d9cf3f5b0a94e04ad81b3e786014243ecde816551aa7fe01c639054256a491756bef59f5034f717ff4f85e70ba7731a49971415b6a7e7d816ab434b9f17a3095ede6fd432be2bfa82724045dda0dfff7a0281e9000939ccba3d8ab3245139c441648c76a6536127e4d1ef0df1531883ab78c8b41323617ad8db03d9908c9e08a9f7321c45051b3c94213347b11c4a84491de7a7be68701e47d7f0e0b33e767bef17694e4d33244ed92ebd74c85ab6c84441cddc14331e6ae8bd23674bda27f09c050d88f7d430feee7f15a72a24d653bb6bec54491b98362ce131d37c7d78a3f9a893db5abdccd6663593b88bc6c97f07f8eafccfd25e8180d918efbcd95bbf3da29f081e3e1932095939198e2a155b2d803a3e84ca4f34569df695c259faf3c0d8f0cd217ebd2dbad542b32fbb54e44aaf0b5dc739fafef2e46db8d68bfc35f44f038cb1f5231a1b5b134ae683e7f3297cc7a95bd191b310f68201450797fe3293cde1672dfeca4b493f53c768ea048a972a4cd84d39ef682957b8f28ba29487b4689b43fec2655823d9bb99ffcf31490366a9860a5d5b8e32a3b8bfeb6f55f88fb80c8c0142086f220e1f6f2862dabda58c3b6f5faa805b39cfac4b6d7ea7acdf1b0690063b0c1ea38c7c4755189966dc631055f153f71b77b114fa5c309316ba512330ea5cdb0bb176001e57461563d17259f35d0c30ef5ac838c0325402bab52c531469526ae3ee6293f7b5769d27e69fa81cd25a31cd095b126e70c57ac3169a5f585a11f1748d9d22f2564911c26a24b2153a78f3a06822f5f1963f237abeb48efd9a9cd478de579c5a0ba84d00e96fbde36d8ce20e7e948547fb6850834ff79d211830f6ee973359781d9d5008fb43a89354782fde4158177f5206ce1d38c889e99e4bb5b4ab34d6a05c42f5d719ea03dbc54adba75a3bb44a3c08c7556462f8c5b7c568a69242cf5be6098eba0a2249c1ca5b2109b6404a962abc1c159c6b48a79fb97e4a3337d99323746221297423f9bd1b12e78489e01e6a10f0fd6bba1cfd6ae1b75dbe69f8b8ee51a4e7f68ba2c407c9c0bad3892b29b0170ab75836fdd49a7ee3c2bb30f2c3d226bcec49140952170b0d160f97b30b7b7b096719538677ebb06922f26925227c8852acc107a8f173b38d96697584bd3dfe169b4073aa58a7bf371d5c4bb0eed30f08212defb3aec902d4546084176bf0f86d93cf36a4689a5e874b32d6b7d3c1e3fbcfd988c35dbc9a8d0a019ad6d7e15ec3ac97125db6abfe00beffe35a81666699a91e15945c62d646690b5b52de8b835ee9be53588fde5d63023b52b2b1f4610c237a829f5901a46042963cce7b85aa040adde02985e14e23c4eadb75221c607d24672e244c66c9c24c3cb7fd90bb23295c9d3d9da516bce3dd462d6660f9f91ef0618a4d4d3d6668c5d1e2e8ed433ebfe0762beb743324e11608f8b14b69ce4c221c1654ba4992a5af2d949c2939f95d1c8fb767af2a843cc7c78f57259d5c0c6ca83fca41ef5ecc4eeeea93e4518c24d3040f2cd90df3e535e989e606fa109e2c453ed7353db1cdb27137f005f9dd8d2aebfb7255a6098b690215e100cfe44ca0f2745fced48322bc9667ab16d2e1c0ff491b96a17b833d4fd44d31c2230ac835796e063ab03000f04f15c70560033763a48552cceaacade9ca5c8055f3745e179068a287183f2bc3ef6327dec5ac7cf7b052ef5a8873e697efde089688f43be464827c2fa83eb531b3674145e95c699c82990e684967dad319d9f64ab16cd9fe9b6c41232ac4ae3795fd8a76aa9b02e970242061c6da45a2af74ad9cb2a79935c92625e242f4bc7fce54d5c10a9e61f875162fa651b66057ba036f062d6d39d0502b93a5640b78c6c2fd20b02ff83676a87a94945d476c349803ea4fe60cdcea65bb2629e2bc09d4472ec63422dee2052f098deaf5531e6c9bed6672a8b699802efe0cded80c8455f585d1ba633d281f1a21adab48e63b44e0c2a4d7608cf98aabf8adc86bcb8f61e8b06cd2385f82e0a3cdd03cab152d5951859c4532f9168e78f17ba2a5772780327dcf4e62b4d26e443762fc488ae4cd4d1156dbd5782595cfd7697a514abc9b160c9ccf08edc86134a755b90e9bb543511e888e3157721a52d1bc5db33029fb335ea2114e21c03368c8d7f4d827960641772a4a32a738df60d19ec77ab09d22f57cc2523b9503b3f5b1cebc5ae15f885f159842db7359a1c89d3d82d3407068f15b6739626eb8c521fc8c5c7491f945d49f14e6989da340bdf49e7f8a792747aa658bc114143ba93f26022d001735b744639bbf22aab2a1851cfc934f9c69d3764fdea3d23db17998e6138cfd7cd9e9a47cb74193bd71aaf28cdd9d1eb595125546a4f4357ebbd1f410e3bf8557892de68509b5b98c5c229e942c910fdd3e54cb6ad54d8dd886cb97ecc06d1e401b8395d0bcb0db9a031dc66c9294f9053c68fc42042b1fa1671fc7d510b70916c0139cfebe3a91244527ce9439860cedb30908197be851cbd1d3b18ca541358449fb34fb5cd569630ed5f67b8795e87828f2ce3becfe457579d82333b0bbab094de391e1f8157bd431e365ca864630932bbebb48f45f8134424e18ab455029b54b19e2f3bfec5e44ad0ea5c03f53d8f925b635838aa7015a7c9e325bdfaff966ea9512dd50f87c8995cea7561c23f4fb06d964ab8f1913a6ca17e4ca60d6bc078e1784f89c673c91d955bcf45f58ca9709579d5e3831df12cfdb7516fd21878cb54243579b9346d2de4be25f508e84b1adc78cb91c03da3c4fd59e4529189838f74f6312820620a5996b791ffcb332f847094613f2148b862034fa89d0d0ff1808d902c5d1af64d5522492d61ecde4c73be89a33782cef1acc1dc327fb2eb9d17642209b85aa8b1dc57cbf067c7aa29da6b7e157d23e171d3ae6f3855834071791402c851ff2dd67109979f7ee5e09e64b4eefdee7112b55ce200bb8c8051e3428c305fa1d576bffbb25a70eb571168fc60dadd928b10cfd07de80a85b8df3edc372d488c21f0d5787611cc6fb73aeeb6f920a109294b49d3870f90de3b360d14df77ef95640bcac7a4dbca901a31db83e83f5c59ce327207ea9b27c3b978d30d53865c1b84764f025e8732d5007554ce5c9cc410b2eefd7e4d990c538557606a6bc47577a43768d30aa3e8598fd6f4fe7ac439f3931c58fd69d90765ac9f456ac7de085e14a0898c4557f5d3baaae07edc607de6900146b97b35aae570153dc107815ef9febdd4fd567d637fee8f8bfb4b3413ea6aead4846ab733a04f1e4bc32a3bbb1c16baf8d0bdb9ccb82fe46479ccfd040b5e64064e539b39c66e4501dc822873ac6119a4a112a1f7cd6df0e5f84356ce853ced34ce69a9e7383534983c51c50269bf8b9586a0e5ba905fd3bce080b00e7f7d48e55f489479b5771e995fb020e58feb74af65c3ee76aa4e69b5ba8bda249a1b2d62c08d418c3635d061846040843991ab475473da85d94981fb84425e7ad951ce0a42be642fe658b7aaae72b147cdc086c24b1571eb2272e2a72b15660d854ebe19ec7d9ab7ea17800d0b6ae727b39217467c662ba08e6f19193951eeff02806a7843eb5c71b2f04dcb605ecedc5128cd67703038c44bf20fe06f3ed8c1368fe38e72944d5c52fca46a45fd48d8fe5da64183d4d62ec01aa3d9d672ec67a01c17f21e02525f0513cce030c664fc8784763086608bc8099c204c255ffed1daf432ceb45fbd135e21e8190c5bfee192171faa77520481e69e87b7f76790bef76cb8d3c88f5c6e32fc59e7bd45351d66696b61d9f40726fb9a98000b68738cf7e34b98b6a4aaa2ac1d7b1407db89783f8077103ea9c9e89247eae078adfb36e21474c3bb1fe0c87687c6233a533a01e1081b93a3521d339f39c075609bace531994988ae314f77fc6034113a138c67eb7e03750cbec8d28bd21afedfefa8f091619ae500b4ca4599d019dc8ca4bf118d70b8676dfc796a4f6d986adba4c8574ed4abaea5465466220e5e53dc8fcb395d1e59d278673cbc4e3f40658df98ac2fd126a94922879e1a3be91c1acc20803c35fa764abbadab07bde85ff4bd9e0fb6f06baf5bf42b8a2cbf6c2f62606becc361552921a12d6c8236fde84db4bddac77e8872478cffc4e148c1c7acfedf6b17d98731c2de36f3cbef1f6f781a940e0874d5b74535bbe066b53064d43b13926570a9e1c4e6da206c8bd252caf2b62e7d223f7ac12939137f330be59374d7295a6c2dff92e07c727510e48d970593e47229fc8bc3bd5b8ea780dacff4d23063df65feda5f8f65b17a333e532acad7916780c74d6a70d38b367f3f6f4e947b85fc15235bbe46b26495d2780098db853a931377cfbedea620f2355ca21e81ce9e0078b0dd6cb70f23ed558682be3b3d594eefe85344e1f275428b316cc088995939298f2a2d15ac9b676ac3e9cb92f2a64dec7732a91fc761aa1b126ea575e3953177da6e1cd78faea824665330a81d9e24572b9860bf0aba4df8bd5d4e3e2c72bbfbb2a985c7ae2f077951fe8401e1d156ecada1e353817b20f41e0b2460a0caaf2b36d6a7f1b35125d797dcc714421027d14171765a646071ed952b6a5294eecf6a3a71c104c843a4a8b3efcc27467b20cb0a94abf5802229ea4d8312783e78791a50b3c0a88fe6497198cd4bf470dac46f34e50019fdee2040cfe99124b312b1122b83e51d878877cec0855f1158c445cfdc2253f4389d5e3a8ba1669abb5976a4617e85f543da9f5e30b10ca7481c8185392782b46fb0a0e5ab408b2945e3c79a1cc49fb7c27254a9b540e7397a5b655bf7e4f83184db32a128aa2e00a624d7dcd6b77efd151f1e5cba8890af9170fa06c555715dc1787e995ad19270973ae95b88dcafdaf62c28843d3f8b9c78dc8e37d911dab3f7ee9d4c7389c654bdcfc05056b360020140e57e31473258a4081e2a708f7caba90c356d0847098fc0762484086aba898a60b023d6a3060402406240748785d51caff52a0ef3dc2a45dadf80ac18502d24422a8cbb10192b88f4e9160206b2ed3e04114f2a339df269e2c36b8613ce37087471701755330cb559575366ee0fa2d3afcda32eede6dd906345daaa04812198e96c42239c242edb90059709f497da5b87705384aef2af22dc2edfef3c00d8c9156d8b3163fe7a7779e04f04911a8b934fb3072eee844484fede5e2ee96d338eefe2da986067ffe0218ada7de1d0e42d823d6b033918278888ba0608ab8f7be997bdf263689a36f5204c802ad836363779b4b0d6ce5083df0b98a2e2c700062a4fa5e57bc73bd45357e01d90c7954bc6904d1ce8166a9168da39a60c5cae8119bb6b9ab074fb2d0aee384fc2c0e4806811d6002b4e2401e7430b50cb0e8075f33d5386aecde256e169d95e2f9c6556c08ba042e68a53ce8aca9cc02818f7382f150dc04de0019b19c7a3ab0d72d6ed013d7a115d74b279f71fd6effef34049877e0b11e0659be938a5de684eaf23513095eb4a1bdf536c3c01a4655c4b4a0673214cef29a481d06a02cc9a5bfc7b8d846c33484cd67b1de98f60b69918f177b64558ca567a6237d35ff01771a42320ce02bb98f3e4ad4ac7db75611bd9961eac662a38b1f785970c99f3dd105ff586f61301c48d66708cbf7d53a733e357b6c256e8b73f0e1305a0bc137989e521100c2ee6259e607fe12198e8bcb988b0854668e40d7cae6adc3ba40ba121b7319d06d988a073d03097b9f5c1c07284b6473ae57bf154811b77baceb0412b8a6983bdd0ccd9e3bf014e520009cb26d5780eabef1bbafa5e25d41098a54c47fce8b68d395291d54284d33aa50b9664d1510b467c8a539361ca9a4448bc01fcb4c4e3ef475e8afb46a494ae13ee9ea8a1266825fba7f32b9712fde252698a68359b50141d90f5c4a06283ddb54ad7e1412ac5ebb12501f7a82b2a7f27b2dbab626c3db4074523b3211d3182ea261397a6f7b187cf2b8a356ded10812f1d305169aedf79b5ff1cf7c2d6e86ee11f28e96aa63b5a03f59fc960ac7d0572e91dda61905c0711a9b26344a2a10aa2041f2b13cb1a9a9a27774b6d0deddc9d81ea1b142ad7b72be47991f2c9261d6708156e38d00b074020766eb0c494392d65b82ca65f7c3352f9bb78325ecb6df596c8ae57826b08ccd6f1d529d2e25925c1ac972425bedeb88a5d0e3138ddc434da3462ebdf6b1239a21f141ec62cbe4bb993ba253b55a76d30fac19c2c1384ef6b9746c07787aa1fe913a1348390bd8c1f386a08c77cf7106c927ce24dffc9d6ee1b32354d95ed2923482531de6b390bf0f5eb80276e90e7ed11131c848bbabec4d317236269a0a3a7cbe0f1272f93949ca6d23ea2a7ee3f697791aab71533423066d400000000000000000000000000000000000000000000000000000000050e181f23292c2f").unwrap(); + assert_eq!(sig.len(), MLDSA87_SIG_LEN); + + if MLDSA87::verify(&mldsa87_pk, msg, None, &sig).is_ok() { + eprintln!("Verification succeeded!"); + } else { + panic!("Verification failed! -- figure that out"); + } +} + +fn bench_mldsa87_lowmemory_verify() { + use bouncycastle_mldsa_lowmemory::{MLDSATrait, MLDSA87, MLDSA87_SIG_LEN, MLDSA87PublicKey}; + use bouncycastle_hex as hex; + + eprintln!("MLDSA87/Verify"); + + let msg = b"The quick brown fox jumped over the lazy dog"; + + /* One-time setup of the KAT -- commented out so that we're not capturing keygen in the bench */ + + // let seed = KeyMaterial256::from_bytes_as_type( + // &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(), + // KeyType::Seed, + // ).unwrap(); + // + // let (mldsa65_pk, mldsa65_sk) = MLDSA87::keygen_from_seed(&seed).unwrap(); + // + // eprintln!("pk:\n{}", &*hex::encode(&mldsa65_pk.encode())); + // let mu = MLDSA87::compute_mu_from_sk(&mldsa65_sk, msg, None).unwrap(); + // let sig = MLDSA87::sign_mu_deterministic(&mldsa65_sk, &mu, [0u8; 32]).unwrap(); + // eprintln!("sig:\n{}", &*hex::encode(sig)); + + let mldsa87_pk = MLDSA87PublicKey::from_bytes(&*hex::decode("9792bcec2f2430686a82fccf3c2f5ff665e771d7ab41b90258cfa7e90ec97124a73b323b9ba21ab64d767c433f5a521effe18f86e46a188952c4467e048b729e7fc4d115e7e48da1896d5fe119b10dcddef62cb307954074b42336e52836de61da941f8d37ea68ac8106fabe19070679af6008537120f70793b8ea9cc0e6e7b7b4c9a5c7421c60f24451ba1e933db1a2ee16c79559f21b3d1b8305850aa42afbb13f1f4d5b9f4835f9d87dfceb162d0ef4a7fdc4cba1743cd1c87bb4967da16cc8764b6569df8ee5bdcbffe9a4e05748e6fdf225af9e4eeb7773b62e8f85f9b56b548945551844fbd89806a4ac369bed2d256100f688a6ad5e0a709826dc4449e91e23c5506e642361ef5a313712f79bc4b3186861ca85a4bab17e7f943d1b8a333aa3ae7ce16b440d6018f9e04daf5725c7f1a93fad1a5a27b67895bd249aa91685de20af32c8b7e268c7f96877d0c85001135a4f0a8f1b8264fa6ebe5a349d8aecad1a16299ccf2fd9c7b85bace2ced3aa1276ba61ee78ed7e5ca5b67cdd458a9354030e6abbbabf56a0a2316fec9dba83b51d42fd3167f1e0f90855d5c66509b210265dc1e54ec44b43ba7cf9aef118b44d80912ce75166a6651e116cebe49229a7062c09931f71abd2293f76f7efc3215ba97800037e58e470bdbbb43c1b0439eaf79c54d93b44aac9efe9fbe151874cfb2a64cbee28cc4c0fe7775e5d870f1c02e5b2e3c5004c995f24c9b779cb753a277d0e71fd425eb6bc2ca56ce129db51f70740f31e63976b50c7312e9797d78c5b1ac24a5fa347cc916e0a83f5c3b675cd30b81e3fa10b93444e07397571cce98b28da51db9056bc728c5b0b1181e2fbd387b4c79ab1a5fefece37167af772ddad14eb4c3982da5a59d0e9eb173ec6315091170027a3ab5ef6aa129cb8585727b9358a28501d713a72f3f1db31714286f9b6408013af06045d75592fc0b7dd47c73ed9c75b11e9d7c69f7cadfc3280a9062c5273c43be1c34f87448864cea7b5c97d6d32f59bd5f25384653bb5c4faa45bea8b89402843e645b6b9269e2bd988ddacb033328ffb060450f7df080053e6969b251e875ecec32cfc592840d69ab69a75e06b379c535d95266b082f4f09c93162b33b0d9f7307a4eaaa52104437fed66f8ee3eabbd45d67b25a8133f496468b52baffdbfad93eef1a9818b5e42ec722788a3d8d3529fc777d2ba570801dfae01ec88302837c1fb9e0355727645ee1046c3f915f6ae82dad4fb6b0356a46518ffc834155c3b4fe6dafa6cc8a5ccf53c73a0849d8d44f7dcf72754e70e1b7dfb447bb4ef49d1a718f6171bbce200950e0ce926106b151a3e871d5ce49731bd6650a9b0ca972da1c5f136d44820ea6383c08f3b384cf2338e789c513f618cc5694a6f0cee104511e1ed7c5f23a1ebfd8a0db8424553240156dbf622831b0c643d1c551b6f3f7a98d29b85c2de05a65fa615eee16495bd90737672115b53e91c5d90028cf3f1a93953a153de53b44084e9ccff6b736693926daefebb2d77aa5ad689b92f31686669df16d1715cc58f7a2cfb72dd1a51e92f825993a74022be7e9eb6054654457094d14928f20215e7b222ac56b51adbec8d8bdb6983979a7e3a21b44b5d1518ca97d0b5195f51ed6a24350c89747e1edea51b448e3e9147054ce927873c90db394d86888e07dff177593d6f79e152302204aeb03be2386af3e24078bd028b1689f5e147c9f452c8ceb02ec59cc9db63a03576ceeafe98239023897da0236630a53c0de7f435a19869792fab36e7b9e635760f09069e6432e700035ac2a02879fff0a1e1bec522047193d94eb5df1efd53eea1144ca78940852f5ec9727904b366ede4f5e2d331fad5fc282ea2c47e923142771c3dd75a87357487def99e5f18e9d9ed623c175d02888c51f82c07a80d54716b3c3c2bdbe2e9f0a9bbaaebeb4d52936876406f5c00e8e4bbd0a5ec05797e6207c5ab6c88f1a688421bd05a114f4d7de2ac241fa0e8bedff47f762ddcbeaa91004f8d31e85095c81054994ad3826e344ba96040810fc0b2ad1de48cfade002c62e5a49a0731ab38344bc1636df16bf607d56855e56d684003c718e4bad9e5a099979fcddeeb1c4a7776cd37a3417cb0e184e29ef9bc0e87475ba663be09e00ab562eb7c0f7165f969a9b42414198ccf1bff2a2c8d689a414ece7662927665689e94db961ebaec5615cbc1a7895c6851ac961432ff1118d4607d32ef9dc732d51333be4b4d0e30ddea784eca8be47e741be9c19631dc470a52ef4dc13a4f3633fd434d787c170977b417df598e1d0dde506bb71d6f0bc17ec70e3b03cdc1965cb36993f633b0472e50d0923ac6c66fdf1d3e6459cc121f0f5f94d09e9dbcf5d690e23233838a0bacb7c638d1b2650a4308cd171b6855126d1da672a6ed85a8d78c286fb56f4ab3d21497528045c63262c8a42af2f9802c53b7bb8be28e78fe0b5ce45fbb7a1af1a3b28a8d94b7890e3c882e39bc98e9f0ad76025bf0dd2f00298e7141a226b3d7cee414f604d1e0ba54d11d5fe58bccea6ad77ad2e8c1caacf32459014b7b91001b1efa8ad172a523fb8e365b577121bf9fd88a2c60c21e821d7b6acb47a5a995e40caced5c223b8fe6de5e18e9d2e5893aefebb7aae7ff1a146260e2f110e939528213a0025a38ec79aabc861b25ebc509a4674c132aaacb7e0146f14efd11cfcaf4caa4f775a716ce325e0a435a4d349d720bcf137450afc45046fc1a1f83a9d329777a7084e4aadae7122ce97005930528eb3c7f7f1129b372887a371155a3ba201a25cbf1dcb64e7cdee092c3141fb5550fe3d0dd82e870e578b2b46500818113b8f6569773c677385b69a42b77dcba7acffd95fd4452e23aaa1d37e1da2151ea658d40a3596b27ac9f8129dc6cf0643772624b59f4f461230df471ca26087c3942d5c6687df6082835935a3f87cb762b0c3b1d0dda4a6533965bef1b7b8292e254c014d090fed857c44c1839c694c0a64e3fad90a11f534722b6ee1574f2e149d55d744de4887024e08511431c062750e16c74ab9f3242f2db3ffb12a8d6107faa229d6f6373b07f36d3932b3bdb04c19dd64eadd7f93c3c564c358a1c81dcf1c9c31e5b06568f97544c17dc15698c5cb38983a9afc42783faa773a52c9d8260690be9e3156aa5bc1509dea3f69587695cd6ff172ba83e6a6d8a7d6bbebbbcda3672731983f89bc5831dc37c3f3c5c56facc697f3cb20bd5dbadbd702e54844ac2f626901fe159db93dfd4773d8fe73562b846c1fc856d1802762840ebc72d7988bde75cbca70d319d32ce0cc0253bb2ad455723ee0c7f4736ce6e6665c5aca32a481c53839bc259167b013d0423395eeb9aaaee3206149a7d550d67fc5fdfe4a8a5c35d2510b664379ab8f72855a2af47abce2a632048eaf89e5cb4a88debc53a595103acce4f1cff18acff07afe1eb5716aa1e40b63134c3a3ae9579fa87f515be093c2d29db6d6b65c93661e00636b592704d093cc6716c2342eb1853d48c85c63ac8a2854462c7b77e7e3bd1eac5bca28ffaa00b5d349f8a547ad875b96a8c2b2910c9301309a3f9138a5693111f55b3c009ca947c39dfc82d98eb1caa4a9cbe885f786fa86e55be062222f8ba90a974073326b31212aece0a34a60").unwrap()).unwrap(); + let sig = &*hex::decode("781368e64dba542a7eacbd2257335cc943a03241009b797093c615f76a671a7591430441d80bb582304b33b9fce295e0dd57fe169355ddf4453a2aca62d8eb8109ef0d9cf3f5b0a94e04ad81b3e786014243ecde816551aa7fe01c639054256a491756bef59f5034f717ff4f85e70ba7731a49971415b6a7e7d816ab434b9f17a3095ede6fd432be2bfa82724045dda0dfff7a0281e9000939ccba3d8ab3245139c441648c76a6536127e4d1ef0df1531883ab78c8b41323617ad8db03d9908c9e08a9f7321c45051b3c94213347b11c4a84491de7a7be68701e47d7f0e0b33e767bef17694e4d33244ed92ebd74c85ab6c84441cddc14331e6ae8bd23674bda27f09c050d88f7d430feee7f15a72a24d653bb6bec54491b98362ce131d37c7d78a3f9a893db5abdccd6663593b88bc6c97f07f8eafccfd25e8180d918efbcd95bbf3da29f081e3e1932095939198e2a155b2d803a3e84ca4f34569df695c259faf3c0d8f0cd217ebd2dbad542b32fbb54e44aaf0b5dc739fafef2e46db8d68bfc35f44f038cb1f5231a1b5b134ae683e7f3297cc7a95bd191b310f68201450797fe3293cde1672dfeca4b493f53c768ea048a972a4cd84d39ef682957b8f28ba29487b4689b43fec2655823d9bb99ffcf31490366a9860a5d5b8e32a3b8bfeb6f55f88fb80c8c0142086f220e1f6f2862dabda58c3b6f5faa805b39cfac4b6d7ea7acdf1b0690063b0c1ea38c7c4755189966dc631055f153f71b77b114fa5c309316ba512330ea5cdb0bb176001e57461563d17259f35d0c30ef5ac838c0325402bab52c531469526ae3ee6293f7b5769d27e69fa81cd25a31cd095b126e70c57ac3169a5f585a11f1748d9d22f2564911c26a24b2153a78f3a06822f5f1963f237abeb48efd9a9cd478de579c5a0ba84d00e96fbde36d8ce20e7e948547fb6850834ff79d211830f6ee973359781d9d5008fb43a89354782fde4158177f5206ce1d38c889e99e4bb5b4ab34d6a05c42f5d719ea03dbc54adba75a3bb44a3c08c7556462f8c5b7c568a69242cf5be6098eba0a2249c1ca5b2109b6404a962abc1c159c6b48a79fb97e4a3337d99323746221297423f9bd1b12e78489e01e6a10f0fd6bba1cfd6ae1b75dbe69f8b8ee51a4e7f68ba2c407c9c0bad3892b29b0170ab75836fdd49a7ee3c2bb30f2c3d226bcec49140952170b0d160f97b30b7b7b096719538677ebb06922f26925227c8852acc107a8f173b38d96697584bd3dfe169b4073aa58a7bf371d5c4bb0eed30f08212defb3aec902d4546084176bf0f86d93cf36a4689a5e874b32d6b7d3c1e3fbcfd988c35dbc9a8d0a019ad6d7e15ec3ac97125db6abfe00beffe35a81666699a91e15945c62d646690b5b52de8b835ee9be53588fde5d63023b52b2b1f4610c237a829f5901a46042963cce7b85aa040adde02985e14e23c4eadb75221c607d24672e244c66c9c24c3cb7fd90bb23295c9d3d9da516bce3dd462d6660f9f91ef0618a4d4d3d6668c5d1e2e8ed433ebfe0762beb743324e11608f8b14b69ce4c221c1654ba4992a5af2d949c2939f95d1c8fb767af2a843cc7c78f57259d5c0c6ca83fca41ef5ecc4eeeea93e4518c24d3040f2cd90df3e535e989e606fa109e2c453ed7353db1cdb27137f005f9dd8d2aebfb7255a6098b690215e100cfe44ca0f2745fced48322bc9667ab16d2e1c0ff491b96a17b833d4fd44d31c2230ac835796e063ab03000f04f15c70560033763a48552cceaacade9ca5c8055f3745e179068a287183f2bc3ef6327dec5ac7cf7b052ef5a8873e697efde089688f43be464827c2fa83eb531b3674145e95c699c82990e684967dad319d9f64ab16cd9fe9b6c41232ac4ae3795fd8a76aa9b02e970242061c6da45a2af74ad9cb2a79935c92625e242f4bc7fce54d5c10a9e61f875162fa651b66057ba036f062d6d39d0502b93a5640b78c6c2fd20b02ff83676a87a94945d476c349803ea4fe60cdcea65bb2629e2bc09d4472ec63422dee2052f098deaf5531e6c9bed6672a8b699802efe0cded80c8455f585d1ba633d281f1a21adab48e63b44e0c2a4d7608cf98aabf8adc86bcb8f61e8b06cd2385f82e0a3cdd03cab152d5951859c4532f9168e78f17ba2a5772780327dcf4e62b4d26e443762fc488ae4cd4d1156dbd5782595cfd7697a514abc9b160c9ccf08edc86134a755b90e9bb543511e888e3157721a52d1bc5db33029fb335ea2114e21c03368c8d7f4d827960641772a4a32a738df60d19ec77ab09d22f57cc2523b9503b3f5b1cebc5ae15f885f159842db7359a1c89d3d82d3407068f15b6739626eb8c521fc8c5c7491f945d49f14e6989da340bdf49e7f8a792747aa658bc114143ba93f26022d001735b744639bbf22aab2a1851cfc934f9c69d3764fdea3d23db17998e6138cfd7cd9e9a47cb74193bd71aaf28cdd9d1eb595125546a4f4357ebbd1f410e3bf8557892de68509b5b98c5c229e942c910fdd3e54cb6ad54d8dd886cb97ecc06d1e401b8395d0bcb0db9a031dc66c9294f9053c68fc42042b1fa1671fc7d510b70916c0139cfebe3a91244527ce9439860cedb30908197be851cbd1d3b18ca541358449fb34fb5cd569630ed5f67b8795e87828f2ce3becfe457579d82333b0bbab094de391e1f8157bd431e365ca864630932bbebb48f45f8134424e18ab455029b54b19e2f3bfec5e44ad0ea5c03f53d8f925b635838aa7015a7c9e325bdfaff966ea9512dd50f87c8995cea7561c23f4fb06d964ab8f1913a6ca17e4ca60d6bc078e1784f89c673c91d955bcf45f58ca9709579d5e3831df12cfdb7516fd21878cb54243579b9346d2de4be25f508e84b1adc78cb91c03da3c4fd59e4529189838f74f6312820620a5996b791ffcb332f847094613f2148b862034fa89d0d0ff1808d902c5d1af64d5522492d61ecde4c73be89a33782cef1acc1dc327fb2eb9d17642209b85aa8b1dc57cbf067c7aa29da6b7e157d23e171d3ae6f3855834071791402c851ff2dd67109979f7ee5e09e64b4eefdee7112b55ce200bb8c8051e3428c305fa1d576bffbb25a70eb571168fc60dadd928b10cfd07de80a85b8df3edc372d488c21f0d5787611cc6fb73aeeb6f920a109294b49d3870f90de3b360d14df77ef95640bcac7a4dbca901a31db83e83f5c59ce327207ea9b27c3b978d30d53865c1b84764f025e8732d5007554ce5c9cc410b2eefd7e4d990c538557606a6bc47577a43768d30aa3e8598fd6f4fe7ac439f3931c58fd69d90765ac9f456ac7de085e14a0898c4557f5d3baaae07edc607de6900146b97b35aae570153dc107815ef9febdd4fd567d637fee8f8bfb4b3413ea6aead4846ab733a04f1e4bc32a3bbb1c16baf8d0bdb9ccb82fe46479ccfd040b5e64064e539b39c66e4501dc822873ac6119a4a112a1f7cd6df0e5f84356ce853ced34ce69a9e7383534983c51c50269bf8b9586a0e5ba905fd3bce080b00e7f7d48e55f489479b5771e995fb020e58feb74af65c3ee76aa4e69b5ba8bda249a1b2d62c08d418c3635d061846040843991ab475473da85d94981fb84425e7ad951ce0a42be642fe658b7aaae72b147cdc086c24b1571eb2272e2a72b15660d854ebe19ec7d9ab7ea17800d0b6ae727b39217467c662ba08e6f19193951eeff02806a7843eb5c71b2f04dcb605ecedc5128cd67703038c44bf20fe06f3ed8c1368fe38e72944d5c52fca46a45fd48d8fe5da64183d4d62ec01aa3d9d672ec67a01c17f21e02525f0513cce030c664fc8784763086608bc8099c204c255ffed1daf432ceb45fbd135e21e8190c5bfee192171faa77520481e69e87b7f76790bef76cb8d3c88f5c6e32fc59e7bd45351d66696b61d9f40726fb9a98000b68738cf7e34b98b6a4aaa2ac1d7b1407db89783f8077103ea9c9e89247eae078adfb36e21474c3bb1fe0c87687c6233a533a01e1081b93a3521d339f39c075609bace531994988ae314f77fc6034113a138c67eb7e03750cbec8d28bd21afedfefa8f091619ae500b4ca4599d019dc8ca4bf118d70b8676dfc796a4f6d986adba4c8574ed4abaea5465466220e5e53dc8fcb395d1e59d278673cbc4e3f40658df98ac2fd126a94922879e1a3be91c1acc20803c35fa764abbadab07bde85ff4bd9e0fb6f06baf5bf42b8a2cbf6c2f62606becc361552921a12d6c8236fde84db4bddac77e8872478cffc4e148c1c7acfedf6b17d98731c2de36f3cbef1f6f781a940e0874d5b74535bbe066b53064d43b13926570a9e1c4e6da206c8bd252caf2b62e7d223f7ac12939137f330be59374d7295a6c2dff92e07c727510e48d970593e47229fc8bc3bd5b8ea780dacff4d23063df65feda5f8f65b17a333e532acad7916780c74d6a70d38b367f3f6f4e947b85fc15235bbe46b26495d2780098db853a931377cfbedea620f2355ca21e81ce9e0078b0dd6cb70f23ed558682be3b3d594eefe85344e1f275428b316cc088995939298f2a2d15ac9b676ac3e9cb92f2a64dec7732a91fc761aa1b126ea575e3953177da6e1cd78faea824665330a81d9e24572b9860bf0aba4df8bd5d4e3e2c72bbfbb2a985c7ae2f077951fe8401e1d156ecada1e353817b20f41e0b2460a0caaf2b36d6a7f1b35125d797dcc714421027d14171765a646071ed952b6a5294eecf6a3a71c104c843a4a8b3efcc27467b20cb0a94abf5802229ea4d8312783e78791a50b3c0a88fe6497198cd4bf470dac46f34e50019fdee2040cfe99124b312b1122b83e51d878877cec0855f1158c445cfdc2253f4389d5e3a8ba1669abb5976a4617e85f543da9f5e30b10ca7481c8185392782b46fb0a0e5ab408b2945e3c79a1cc49fb7c27254a9b540e7397a5b655bf7e4f83184db32a128aa2e00a624d7dcd6b77efd151f1e5cba8890af9170fa06c555715dc1787e995ad19270973ae95b88dcafdaf62c28843d3f8b9c78dc8e37d911dab3f7ee9d4c7389c654bdcfc05056b360020140e57e31473258a4081e2a708f7caba90c356d0847098fc0762484086aba898a60b023d6a3060402406240748785d51caff52a0ef3dc2a45dadf80ac18502d24422a8cbb10192b88f4e9160206b2ed3e04114f2a339df269e2c36b8613ce37087471701755330cb559575366ee0fa2d3afcda32eede6dd906345daaa04812198e96c42239c242edb90059709f497da5b87705384aef2af22dc2edfef3c00d8c9156d8b3163fe7a7779e04f04911a8b934fb3072eee844484fede5e2ee96d338eefe2da986067ffe0218ada7de1d0e42d823d6b033918278888ba0608ab8f7be997bdf263689a36f5204c802ad836363779b4b0d6ce5083df0b98a2e2c700062a4fa5e57bc73bd45357e01d90c7954bc6904d1ce8166a9168da39a60c5cae8119bb6b9ab074fb2d0aee384fc2c0e4806811d6002b4e2401e7430b50cb0e8075f33d5386aecde256e169d95e2f9c6556c08ba042e68a53ce8aca9cc02818f7382f150dc04de0019b19c7a3ab0d72d6ed013d7a115d74b279f71fd6effef34049877e0b11e0659be938a5de684eaf23513095eb4a1bdf536c3c01a4655c4b4a0673214cef29a481d06a02cc9a5bfc7b8d846c33484cd67b1de98f60b69918f177b64558ca567a6237d35ff01771a42320ce02bb98f3e4ad4ac7db75611bd9961eac662a38b1f785970c99f3dd105ff586f61301c48d66708cbf7d53a733e357b6c256e8b73f0e1305a0bc137989e521100c2ee6259e607fe12198e8bcb988b0854668e40d7cae6adc3ba40ba121b7319d06d988a073d03097b9f5c1c07284b6473ae57bf154811b77baceb0412b8a6983bdd0ccd9e3bf014e520009cb26d5780eabef1bbafa5e25d41098a54c47fce8b68d395291d54284d33aa50b9664d1510b467c8a539361ca9a4448bc01fcb4c4e3ef475e8afb46a494ae13ee9ea8a1266825fba7f32b9712fde252698a68359b50141d90f5c4a06283ddb54ad7e1412ac5ebb12501f7a82b2a7f27b2dbab626c3db4074523b3211d3182ea261397a6f7b187cf2b8a356ded10812f1d305169aedf79b5ff1cf7c2d6e86ee11f28e96aa63b5a03f59fc960ac7d0572e91dda61905c0711a9b26344a2a10aa2041f2b13cb1a9a9a27774b6d0deddc9d81ea1b142ad7b72be47991f2c9261d6708156e38d00b074020766eb0c494392d65b82ca65f7c3352f9bb78325ecb6df596c8ae57826b08ccd6f1d529d2e25925c1ac972425bedeb88a5d0e3138ddc434da3462ebdf6b1239a21f141ec62cbe4bb993ba253b55a76d30fac19c2c1384ef6b9746c07787aa1fe913a1348390bd8c1f386a08c77cf7106c927ce24dffc9d6ee1b32354d95ed2923482531de6b390bf0f5eb80276e90e7ed11131c848bbabec4d317236269a0a3a7cbe0f1272f93949ca6d23ea2a7ee3f697791aab71533423066d400000000000000000000000000000000000000000000000000000000050e181f23292c2f").unwrap(); + assert_eq!(sig.len(), MLDSA87_SIG_LEN); + + if MLDSA87::verify(&mldsa87_pk, msg, None, &sig).is_ok() { + eprintln!("Verification succeeded!"); + } else { + panic!("Verification failed! -- figure that out"); + } +} + + + +fn main() { + // bench_do_nothing(); + // bench_mldsa44_keygen(); + // bench_mldsa44_lowmem_keygen(); + // bench_mldsa65_keygen(); + // bench_mldsa65_lowmemory_keygen() + // bench_mldsa87_keygen(); + // bench_mldsa87_lowmemory_keygen() + // bench_mldsa44_sign(); + // bench_mldsa44_lowmemory_sign(); + // bench_mldsa65_sign(); + // bench_mldsa65_lowmemory_sign(); + // bench_mldsa87_sign(); + // bench_mldsa87_lowmemory_sign(); + // bench_mldsa44_verify(); + // bench_mldsa44_lowmemory_verify(); + // bench_mldsa65_verify(); + // bench_mldsa65_lowmemory_verify(); + // bench_mldsa87_verify(); + bench_mldsa87_lowmemory_verify(); +} \ No newline at end of file From ef214a65b0c8e77a6daf9ddf4b3f32dfe1c76efd Mon Sep 17 00:00:00 2001 From: Quant-TheodoreFelix <53819958+Quant-TheodoreFelix@users.noreply.github.com> Date: Tue, 9 Jun 2026 14:42:35 +0900 Subject: [PATCH 03/13] =?UTF-8?q?=EC=B6=9C=EB=A0=A5=20=EB=B2=84=ED=8D=BC?= =?UTF-8?q?=20zeroize=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 좜λ ₯ 슬라이슀λ₯Ό λ°›λŠ” _out 계열 ν•¨μˆ˜ μ§„μž…λΆ€μ—μ„œ out fill(0) μ„ -μ΄ˆκΈ°ν™” - μ˜€λ²„μ‚¬μ΄μ¦ˆ 버퍼 λ’€μͺ½μ΄λ‚˜ μ‘°κΈ° λ°˜ν™˜ μ‹œ λ‚¨λŠ” 이전 데이터 λ…ΈμΆœ λ°©μ§€ - digest 좜λ ₯ 버퍼 λ’€μͺ½κΉŒμ§€ 0이 λ˜λ„λ‘ sha3 ν…ŒμŠ€νŠΈ 1건 κ°±μ‹  - ν–‰ λ‹¨μœ„ λΆ€λΆ„ 기둝 ν•¨μˆ˜λŠ” λ‹€λ₯Έ 행을 μ§€μš°λ―€λ‘œ μ œμ™Έ --- crypto/base64/src/lib.rs | 2 ++ crypto/factory/src/hash_factory.rs | 4 ++++ crypto/factory/src/mac_factory.rs | 4 ++++ crypto/factory/src/rng_factory.rs | 2 ++ crypto/factory/src/xof_factory.rs | 6 ++++++ crypto/hex/src/lib.rs | 4 ++++ crypto/hmac/src/lib.rs | 6 ++++++ crypto/mldsa/src/aux_functions.rs | 2 ++ crypto/mldsa/src/hash_mldsa.rs | 12 ++++++++++++ crypto/mldsa/src/mldsa.rs | 14 ++++++++++++++ crypto/mldsa/src/mldsa_keys.rs | 10 ++++++++++ crypto/mldsa_lowmemory/src/aux_functions.rs | 2 ++ crypto/mldsa_lowmemory/src/hash_mldsa.rs | 8 ++++++++ crypto/mldsa_lowmemory/src/mldsa.rs | 8 ++++++++ crypto/mldsa_lowmemory/src/mldsa_keys.rs | 2 ++ crypto/mlkem/src/matrix.rs | 2 ++ crypto/mlkem/src/mlkem_keys.rs | 10 +++++++++- crypto/mlkem/src/polynomial.rs | 2 ++ crypto/mlkem_lowmemory/src/mlkem_keys.rs | 4 ++++ crypto/mlkem_lowmemory/src/polynomial.rs | 2 ++ crypto/rng/src/hash_drbg80090a.rs | 8 ++++++++ crypto/sha2/src/sha256.rs | 4 ++++ crypto/sha2/src/sha512.rs | 4 ++++ crypto/sha3/src/keccak.rs | 2 ++ crypto/sha3/src/sha3.rs | 8 ++++++++ crypto/sha3/src/shake.rs | 10 +++++++++- crypto/sha3/tests/sha3_tests.rs | 7 +++++-- crypto/utils/src/ct.rs | 2 ++ 28 files changed, 147 insertions(+), 4 deletions(-) diff --git a/crypto/base64/src/lib.rs b/crypto/base64/src/lib.rs index 8b7cfeb..90330d0 100644 --- a/crypto/base64/src/lib.rs +++ b/crypto/base64/src/lib.rs @@ -193,6 +193,8 @@ impl Base64Encoder { assert!(inref.len() >= 3); assert!(out.len() >= 4); + out.fill(0); + out[0] = Self::ct_bin_to_b64(inref[0] >> 2); out[1] = Self::ct_bin_to_b64(((inref[0] & 0x03) << 4) | inref[1] >> 4); out[2] = Self::ct_bin_to_b64(((inref[1] & 0x0F) << 2) | inref[2] >> 6); diff --git a/crypto/factory/src/hash_factory.rs b/crypto/factory/src/hash_factory.rs index d65586f..9d12117 100644 --- a/crypto/factory/src/hash_factory.rs +++ b/crypto/factory/src/hash_factory.rs @@ -129,6 +129,8 @@ impl Hash for HashFactory { } fn hash_out(self, data: &[u8], output: &mut [u8]) -> usize { + output.fill(0); + match self { Self::SHA224(h) => h.hash_out(data, output), Self::SHA256(h) => h.hash_out(data, output), @@ -168,6 +170,8 @@ impl Hash for HashFactory { } fn do_final_out(self, output: &mut [u8]) -> usize { + output.fill(0); + match self { Self::SHA224(h) => h.do_final_out(output), Self::SHA256(h) => h.do_final_out(output), diff --git a/crypto/factory/src/mac_factory.rs b/crypto/factory/src/mac_factory.rs index 64ae090..141c59f 100644 --- a/crypto/factory/src/mac_factory.rs +++ b/crypto/factory/src/mac_factory.rs @@ -175,6 +175,8 @@ impl MAC for MACFactory { } fn mac_out(self, data: &[u8], out: &mut [u8]) -> Result { + out.fill(0); + match self { Self::HMAC_SHA224(h) => h.mac_out(data, out), Self::HMAC_SHA256(h) => h.mac_out(data, out), @@ -227,6 +229,8 @@ impl MAC for MACFactory { } fn do_final_out(self, mut out: &mut [u8]) -> Result { + out.fill(0); + match self { Self::HMAC_SHA224(h) => h.do_final_out(&mut out), Self::HMAC_SHA256(h) => h.do_final_out(&mut out), diff --git a/crypto/factory/src/rng_factory.rs b/crypto/factory/src/rng_factory.rs index 89aa3e7..f1792d1 100644 --- a/crypto/factory/src/rng_factory.rs +++ b/crypto/factory/src/rng_factory.rs @@ -108,6 +108,8 @@ impl RNG for RNGFactory { } fn next_bytes_out(&mut self, out: &mut [u8]) -> Result { + out.fill(0); + match self { Self::HashDRBG_SHA256(rng) => {rng.next_bytes_out(out) }, Self::HashDRBG_SHA512(rng) => { rng.next_bytes_out(out) }, diff --git a/crypto/factory/src/xof_factory.rs b/crypto/factory/src/xof_factory.rs index 2809a39..e35e86e 100644 --- a/crypto/factory/src/xof_factory.rs +++ b/crypto/factory/src/xof_factory.rs @@ -86,6 +86,8 @@ impl XOF for XOFFactory { } fn hash_xof_out(self, data: &[u8], output: &mut [u8]) -> usize { + output.fill(0); + match self { Self::SHAKE128(h) => h.hash_xof_out(data, output), Self::SHAKE256(h) => h.hash_xof_out(data, output), @@ -118,6 +120,8 @@ impl XOF for XOFFactory { } fn squeeze_out(&mut self, output: &mut [u8]) -> usize { + output.fill(0); + match self { Self::SHAKE128(h) => h.squeeze_out(output), Self::SHAKE256(h) => h.squeeze_out(output), @@ -136,6 +140,8 @@ impl XOF for XOFFactory { num_bits: usize, output: &mut u8, ) -> Result<(), HashError> { + *output = 0; + match self { Self::SHAKE128(h) => h.squeeze_partial_byte_final_out(num_bits, output), Self::SHAKE256(h) => h.squeeze_partial_byte_final_out(num_bits, output), diff --git a/crypto/hex/src/lib.rs b/crypto/hex/src/lib.rs index 2e71988..6fcf787 100644 --- a/crypto/hex/src/lib.rs +++ b/crypto/hex/src/lib.rs @@ -47,6 +47,8 @@ pub fn encode_out>(input: T, out: &mut [u8]) -> Result> 4); out[2 * i + 1] = ct_word_to_hex(inref[i] & 0x0F); @@ -90,6 +92,8 @@ pub fn decode_out>(input: T, out: &mut [u8]) -> Result HMAC { )); } + out.fill(0); + // Per RFC 2104 Section 2, save our inner digest to calculate our // outer digest. Note that we can't (necessarily) reuse out as a // scratch pad here: if we're truncating the output but not @@ -378,6 +380,8 @@ impl MAC for HMAC { } fn mac_out(mut self, data: &[u8], mut out: &mut [u8]) -> Result { + out.fill(0); + self.do_update(data); self.do_final_out(&mut out) } @@ -398,6 +402,8 @@ impl MAC for HMAC { } fn do_final_out(self, mut out: &mut [u8]) -> Result { + out.fill(0); + self.do_final_internal_out(&mut out) } diff --git a/crypto/mldsa/src/aux_functions.rs b/crypto/mldsa/src/aux_functions.rs index 8303063..3164838 100644 --- a/crypto/mldsa/src/aux_functions.rs +++ b/crypto/mldsa/src/aux_functions.rs @@ -397,6 +397,8 @@ pub(crate) fn sig_encode< h: &Vector, output: &mut [u8; SIG_LEN], ) -> usize { + output.fill(0); + let mut pos = 0; output[..LAMBDA_over_4].copy_from_slice(c_tilde); diff --git a/crypto/mldsa/src/hash_mldsa.rs b/crypto/mldsa/src/hash_mldsa.rs index 780bd76..52fbdc8 100644 --- a/crypto/mldsa/src/hash_mldsa.rs +++ b/crypto/mldsa/src/hash_mldsa.rs @@ -478,6 +478,8 @@ impl< ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mut ph_m = [0u8; PH_LEN]; _ = HASH::default().hash_out(msg, &mut ph_m); Self::sign_ph_with_expanded_key_out(sk, &ph_m, ctx, output) @@ -500,6 +502,8 @@ impl< ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mut rnd: [u8; MLDSA_RND_LEN] = [0u8; MLDSA_RND_LEN]; HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?; Self::sign_ph_deterministic_out(&sk.sk, Some(&sk.A_hat), ctx, ph, rnd, output) @@ -556,6 +560,8 @@ impl< return Err(SignatureError::LengthError("ctx value is longer than 255 bytes")); } + output.fill(0); + // Algorithm 7 // 6: πœ‡ ← H(BytesToBits(π‘‘π‘Ÿ)||𝑀', 64) let mu = { @@ -860,6 +866,8 @@ impl< ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mut ph_m = [0u8; PH_LEN]; _ = HASH::default().hash_out(msg, &mut ph_m); Self::sign_ph_out(sk, &ph_m, ctx, output) @@ -898,6 +906,8 @@ impl< )); } + output.fill(0); + if self.sk.is_some() { if self.signer_rnd.is_none() { Self::sign_ph_out(&self.sk.unwrap(), &ph, Some(&self.ctx[..self.ctx_len]), output) @@ -1045,6 +1055,8 @@ impl< ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mut rnd: [u8; MLDSA_RND_LEN] = [0u8; MLDSA_RND_LEN]; HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?; Self::sign_ph_deterministic_out(sk, None, ctx, ph, rnd, output) diff --git a/crypto/mldsa/src/mldsa.rs b/crypto/mldsa/src/mldsa.rs index d207f01..dd8eb0f 100644 --- a/crypto/mldsa/src/mldsa.rs +++ b/crypto/mldsa/src/mldsa.rs @@ -845,6 +845,8 @@ impl< rnd: [u8; 32], output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + // 1: (𝜌, 𝐾, π‘‘π‘Ÿ, 𝐬1, 𝐬2, 𝐭0) ← skDecode(π‘ π‘˜) // 2: 𝐬1Μ‚_hat ← NTT(𝐬1) // 3: 𝐬2Μ‚_hat ← NTT(𝐬2) @@ -1134,6 +1136,8 @@ impl< ctx: Option<&[u8]>, out: &mut [u8; SIG_LEN], ) -> Result { + out.fill(0); + let mu = MuBuilder::compute_mu(&sk.tr(), msg, ctx)?; Self::sign_mu_out(&sk.sk, Some(&sk.A_hat), &mu, out) } @@ -1154,6 +1158,8 @@ impl< mu: &[u8; 64], output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mut rnd: [u8; MLDSA_RND_LEN] = [0u8; MLDSA_RND_LEN]; HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?; @@ -1175,6 +1181,8 @@ impl< mu: &[u8; 64], out: &mut [u8; SIG_LEN], ) -> Result { + out.fill(0); + Self::sign_mu_out(&sk.sk, A_hat, mu, out) } @@ -1196,6 +1204,8 @@ impl< rnd: [u8; 32], output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + match A_hat { Some(A_hat) => Self::sign_internal(sk, A_hat, mu, rnd, output), None => Self::sign_internal(sk, &sk.A_hat(), mu, rnd, output), @@ -1930,6 +1940,8 @@ impl< ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mu = MuBuilder::compute_mu(&sk.tr(), msg, ctx)?; let bytes_written = Self::sign_mu_out(sk, None, &mu, output)?; @@ -1966,6 +1978,8 @@ impl< )); } + output.fill(0); + if self.sk.is_some() { if self.signer_rnd.is_none() { Self::sign_mu_out(&self.sk.unwrap(), None, &mu, output) diff --git a/crypto/mldsa/src/mldsa_keys.rs b/crypto/mldsa/src/mldsa_keys.rs index 96a3a5d..c1643ba 100644 --- a/crypto/mldsa/src/mldsa_keys.rs +++ b/crypto/mldsa/src/mldsa_keys.rs @@ -203,6 +203,8 @@ impl SignaturePublicKey usize { + out.fill(0); + self.pk_encode_out(out) } @@ -279,6 +281,8 @@ impl< } fn encode_out(&self, out: &mut [u8; PK_LEN]) -> usize { + out.fill(0); + self.pk.encode_out(out) } @@ -431,6 +435,8 @@ impl usize { + out.fill(0); + // counter of progress along the output buffer let mut off: usize = 0; @@ -720,6 +726,8 @@ impl usize { + out.fill(0); + self.sk_encode_out(out) } @@ -976,6 +984,8 @@ impl< } fn encode_out(&self, out: &mut [u8; SK_LEN]) -> usize { + out.fill(0); + self.sk.encode_out(out) } diff --git a/crypto/mldsa_lowmemory/src/aux_functions.rs b/crypto/mldsa_lowmemory/src/aux_functions.rs index ce0f4ca..bcc1e52 100644 --- a/crypto/mldsa_lowmemory/src/aux_functions.rs +++ b/crypto/mldsa_lowmemory/src/aux_functions.rs @@ -167,6 +167,8 @@ pub(crate) fn bitpack_gamma1( z: &Polynomial, out: &mut [u8; POLY_Z_PACKED_LEN], ) { + out.fill(0); + let mut t: [u32; 4] = [0; 4]; match GAMMA1 { MLDSA44_GAMMA1 => { diff --git a/crypto/mldsa_lowmemory/src/hash_mldsa.rs b/crypto/mldsa_lowmemory/src/hash_mldsa.rs index 33b9176..99140fa 100644 --- a/crypto/mldsa_lowmemory/src/hash_mldsa.rs +++ b/crypto/mldsa_lowmemory/src/hash_mldsa.rs @@ -590,6 +590,8 @@ impl< return Err(SignatureError::LengthError("ctx value is longer than 255 bytes")); } + output.fill(0); + // Algorithm 7 // 6: πœ‡ ← H(BytesToBits(π‘‘π‘Ÿ)||𝑀', 64) let mut h = H::new(); @@ -809,6 +811,8 @@ impl< ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mut ph_m = [0u8; PH_LEN]; _ = HASH::default().hash_out(msg, &mut ph_m); Self::sign_ph_out(sk, &ph_m, ctx, output) @@ -847,6 +851,8 @@ impl< )); } + output.fill(0); + if self.sk.is_some() { if self.signer_rnd.is_none() { Self::sign_ph_out( @@ -1024,6 +1030,8 @@ impl< ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mut rnd: [u8; MLDSA_RND_LEN] = [0u8; MLDSA_RND_LEN]; HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?; Self::sign_ph_deterministic_out(sk, ctx, ph, rnd, output) diff --git a/crypto/mldsa_lowmemory/src/mldsa.rs b/crypto/mldsa_lowmemory/src/mldsa.rs index a6efa48..dc6ae2e 100644 --- a/crypto/mldsa_lowmemory/src/mldsa.rs +++ b/crypto/mldsa_lowmemory/src/mldsa.rs @@ -949,6 +949,8 @@ impl< mu: &[u8; 64], output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mut rnd: [u8; MLDSA_RND_LEN] = [0u8; MLDSA_RND_LEN]; HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?; @@ -1181,6 +1183,8 @@ impl< rnd: [u8; 32], output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + SK::from_keymaterial(&seed)?; Self::sign_mu_deterministic_out(&SK::from_keymaterial(&seed)?, mu, rnd, output) } @@ -1586,6 +1590,8 @@ impl< ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN], ) -> Result { + output.fill(0); + let mu = MuBuilder::compute_mu(&sk.tr(), msg, ctx)?; let bytes_written = Self::sign_mu_out(sk, &mu, output)?; @@ -1622,6 +1628,8 @@ impl< )); } + output.fill(0); + if self.sk.is_some() { if self.signer_rnd.is_none() { Self::sign_mu_out(&self.sk.unwrap(), &mu, output) diff --git a/crypto/mldsa_lowmemory/src/mldsa_keys.rs b/crypto/mldsa_lowmemory/src/mldsa_keys.rs index 81985bd..b805d89 100644 --- a/crypto/mldsa_lowmemory/src/mldsa_keys.rs +++ b/crypto/mldsa_lowmemory/src/mldsa_keys.rs @@ -183,6 +183,8 @@ impl SignatureP fn encode_out(&self, out: &mut [u8; PK_LEN]) -> usize { debug_assert_eq!(out.len(), PK_LEN); + out.fill(0); + out[..32].copy_from_slice(&self.rho); out[32..].copy_from_slice(&self.t1_packed); diff --git a/crypto/mlkem/src/matrix.rs b/crypto/mlkem/src/matrix.rs index 381e7be..563d19c 100644 --- a/crypto/mlkem/src/matrix.rs +++ b/crypto/mlkem/src/matrix.rs @@ -171,6 +171,8 @@ impl Vector // let mut s = self.clone(); // s.conditional_sub_q(); + out.fill(0); + let mut idx = 0; match du { 10 => { // MLKEM512 and MLKEM 768 diff --git a/crypto/mlkem/src/mlkem_keys.rs b/crypto/mlkem/src/mlkem_keys.rs index df04429..a93934d 100644 --- a/crypto/mlkem/src/mlkem_keys.rs +++ b/crypto/mlkem/src/mlkem_keys.rs @@ -180,6 +180,8 @@ impl KEMPublicKey for MLKEMPublicK debug_assert_eq!(PK_LEN, 12*k*32 + 32); debug_assert_eq!(POLY_BYTES, 12*32); + out.fill(0); + let (pk_chunks, last_chunk) = out.as_chunks_mut::(); // that should divide evenly the remainder of the array, leaving space for rho at the end @@ -276,6 +278,8 @@ impl, const PK_LEN: u } fn encode_out(&self, out: &mut [u8; PK_LEN]) -> usize { + out.fill(0); + self.ek.encode_out(out) } @@ -390,7 +394,7 @@ impl< /// 3: dk ← (dkPKE β€– ek β€– H(ek) β€– 𝑧) fn sk_encode_out(&self, out: &mut [u8; SK_LEN]) -> usize { out.fill(0); - + debug_assert_eq!(SK_LEN, /* dk_pke*/12*k*32 + /*ek*/PK_LEN + /*H(ek)*/32 + /*z*/32); let mut pos = 0usize; @@ -584,6 +588,8 @@ impl< } fn encode_out(&self, out: &mut [u8; SK_LEN]) -> usize { + out.fill(0); + self.sk_encode_out(out) } @@ -751,6 +757,8 @@ impl< } fn encode_out(&self, out: &mut [u8; SK_LEN]) -> usize { + out.fill(0); + self.dk.encode_out(out) } diff --git a/crypto/mlkem/src/polynomial.rs b/crypto/mlkem/src/polynomial.rs index 13bc411..1a9bb2e 100644 --- a/crypto/mlkem/src/polynomial.rs +++ b/crypto/mlkem/src/polynomial.rs @@ -127,6 +127,8 @@ impl Polynomial { // each of the N i16's will take dv bits debug_assert_eq!(out.len(), N * (dv as usize) / 8); + out.fill(0); + let mut t = [0u8; 8]; let mut idx = 0; diff --git a/crypto/mlkem_lowmemory/src/mlkem_keys.rs b/crypto/mlkem_lowmemory/src/mlkem_keys.rs index b897d17..b9e58f3 100644 --- a/crypto/mlkem_lowmemory/src/mlkem_keys.rs +++ b/crypto/mlkem_lowmemory/src/mlkem_keys.rs @@ -174,6 +174,8 @@ impl KEMPublicKe fn encode_out(&self, out: &mut [u8; PK_LEN]) -> usize { debug_assert_eq!(self.t_hat_packed.len(), T_PACKED_LEN); + out.fill(0); + out[..T_PACKED_LEN].copy_from_slice(&self.t_hat_packed); debug_assert_eq!(out[T_PACKED_LEN..].len(), 32); out[T_PACKED_LEN..].copy_from_slice(&self.rho); @@ -549,6 +551,8 @@ impl< fn encode_out(&self, out: &mut [u8; SK_LEN]) -> usize { debug_assert_eq!(SK_LEN, 64); + out.fill(0); + out[..32].copy_from_slice(&self.seed_d); out[32..].copy_from_slice(&self.z); diff --git a/crypto/mlkem_lowmemory/src/polynomial.rs b/crypto/mlkem_lowmemory/src/polynomial.rs index bec4ee4..a2b1603 100644 --- a/crypto/mlkem_lowmemory/src/polynomial.rs +++ b/crypto/mlkem_lowmemory/src/polynomial.rs @@ -150,6 +150,8 @@ impl Polynomial { // each of the N i16's will take dv bits debug_assert_eq!(out.len(), N * (dv as usize) / 8); + out.fill(0); + let mut t = [0u8; 8]; let mut idx = 0; diff --git a/crypto/rng/src/hash_drbg80090a.rs b/crypto/rng/src/hash_drbg80090a.rs index 4614692..31486ea 100644 --- a/crypto/rng/src/hash_drbg80090a.rs +++ b/crypto/rng/src/hash_drbg80090a.rs @@ -376,6 +376,8 @@ impl Sp80090ADrbg for HashDRBG80090A { return Err(RNGError::ReseedRequired); } + out.fill(0); + // 2. If (additional_input β‰  Null), then do // 2.1 w = Hash (0x02 || V || additional_input). // 2.2 V = (V + w) mod 2^seedlen. @@ -490,6 +492,8 @@ impl RNG for HashDRBG80090A { } fn next_bytes_out(&mut self, out: &mut [u8]) -> Result { + out.fill(0); + self.generate_out("next_bytes_out".as_bytes(), out) } @@ -521,6 +525,8 @@ fn hash_df( panic!("hash_df can't produce that much output!") } + out.fill(0); + // out is "temp" in SP 800-90Ar1 let no_of_bits_to_return: u32 = (out.len() * 8) as u32; let len = u32::div_ceil(out.len() as u32, H::OUTPUT_LEN as u32); @@ -614,6 +620,8 @@ fn hashgen(v: &[u8], out: &mut [u8]) { // 6. Return (returned_bits). // 1. m = ceil(requested_no_of_bits / outlen) + out.fill(0); + let m = u32::div_ceil(out.len() as u32, H::OUTPUT_LEN as u32); // requested_no_of_bits = out.len() diff --git a/crypto/sha2/src/sha256.rs b/crypto/sha2/src/sha256.rs index 10d45e1..7073c59 100644 --- a/crypto/sha2/src/sha256.rs +++ b/crypto/sha2/src/sha256.rs @@ -197,6 +197,8 @@ impl Hash for SHA256Internal { } fn hash_out(mut self, data: &[u8], output: &mut [u8]) -> usize { + output.fill(0); + self.do_update(data); self.do_final_out(output) } @@ -241,6 +243,8 @@ impl Hash for SHA256Internal { } fn do_final_out(mut self, output: &mut [u8]) -> usize { + output.fill(0); + let n = *min(&output.len(), &PARAMS::OUTPUT_LEN); let bit_len: u64 = self.byte_count << 3; diff --git a/crypto/sha2/src/sha512.rs b/crypto/sha2/src/sha512.rs index 66d5265..c404fc6 100644 --- a/crypto/sha2/src/sha512.rs +++ b/crypto/sha2/src/sha512.rs @@ -209,6 +209,8 @@ impl Hash for Sha512Internal { } fn hash_out(mut self, data: &[u8], output: &mut [u8]) -> usize { + output.fill(0); + self.do_update(data); self.do_final_out(output) } @@ -252,6 +254,8 @@ impl Hash for Sha512Internal { } fn do_final_out(mut self, output: &mut [u8]) -> usize { + output.fill(0); + let n = *min(&output.len(), &PARAMS::OUTPUT_LEN); let bit_len_hi: u64 = self.byte_count >> 61; diff --git a/crypto/sha3/src/keccak.rs b/crypto/sha3/src/keccak.rs index 55ee617..5e6f6a8 100644 --- a/crypto/sha3/src/keccak.rs +++ b/crypto/sha3/src/keccak.rs @@ -271,6 +271,8 @@ impl KeccakDigest { /// Panics if the output buffer is too small. /// Returns the number of bytes written. pub(super) fn squeeze(&mut self, out: &mut [u8]) -> usize { + out.fill(0); + if !self.squeezing { self.pad_and_switch_to_squeezing_phase(); } diff --git a/crypto/sha3/src/sha3.rs b/crypto/sha3/src/sha3.rs index a55ac26..ed5656c 100644 --- a/crypto/sha3/src/sha3.rs +++ b/crypto/sha3/src/sha3.rs @@ -29,6 +29,8 @@ impl SHA3 { /// Swallows errors and simply returns an empty Vec if the hashes fails for whatever reason. fn hash_internal(mut self, data: &[u8], output: &mut [u8]) -> usize { + output.fill(0); + self.do_update(data); self.do_final_out(output) } @@ -121,6 +123,8 @@ impl Hash for SHA3 { } fn hash_out(self, data: &[u8], mut output: &mut [u8]) -> usize { + output.fill(0); + self.hash_internal(data, &mut output) } @@ -140,6 +144,8 @@ impl Hash for SHA3 { // todo -- why doesn't this take a &mut [u8; HASH_LEN] ? // That's probably more user-friendly than this auto-truncating that I have here. fn do_final_out(mut self, output: &mut [u8]) -> usize { + output.fill(0); + self.keccak.absorb_bits(0x02, 2).expect("do_final_out: keccak.absorb_bits failed."); // this shouldn't fail because by construction you can only enter this function once, and this is the only way to absorb partial bits. let bytes_written = if output.len() <= self.output_len() { @@ -172,6 +178,8 @@ impl Hash for SHA3 { num_partial_bits: usize, output: &mut [u8], ) -> Result { + output.fill(0); + // Mutants note: yep, this is just bit-setting into empty space, so it doesn't matter whether it's OR or XOR. let mut final_input: u16 = ((partial_byte as u16) & ((1 << num_partial_bits) - 1)) | (0x02 << num_partial_bits); diff --git a/crypto/sha3/src/shake.rs b/crypto/sha3/src/shake.rs index f7cd88e..edf953d 100644 --- a/crypto/sha3/src/shake.rs +++ b/crypto/sha3/src/shake.rs @@ -54,6 +54,8 @@ impl SHAKE { } fn hash_internal_out(mut self, data: &[u8], output: &mut [u8]) -> usize { + output.fill(0); + self.absorb(data); self.squeeze_out(output) } @@ -200,6 +202,8 @@ impl XOF for SHAKE { } fn hash_xof_out(self, data: &[u8], output: &mut [u8]) -> usize { + output.fill(0); + self.hash_internal_out(data, output) } @@ -239,6 +243,8 @@ impl XOF for SHAKE { } fn squeeze_out(&mut self, output: &mut [u8]) -> usize { + output.fill(0); + if !self.keccak.squeezing { self.keccak.absorb_bits(0x0F, 4).expect("Absorb_bits failed"); }; @@ -262,6 +268,8 @@ impl XOF for SHAKE { return Err(HashError::InvalidLength("must be in the range [0,7]")); } + *output = 0; + let mut buf = [0u8; 1]; self.keccak.squeeze(&mut buf); *output = buf[0] >> 8 - num_bits; @@ -271,4 +279,4 @@ impl XOF for SHAKE { fn max_security_strength(&self) -> SecurityStrength { SecurityStrength::from_bits(PARAMS::SIZE as usize) } -} \ No newline at end of file +} diff --git a/crypto/sha3/tests/sha3_tests.rs b/crypto/sha3/tests/sha3_tests.rs index 787e9fb..b2d5311 100644 --- a/crypto/sha3/tests/sha3_tests.rs +++ b/crypto/sha3/tests/sha3_tests.rs @@ -66,10 +66,13 @@ mod sha3_tests { assert_eq!(&out, b"\x58\x4c\xc7\x02\xc2\x22\x9a\x0a\xbc\x78\x9b\xfa\x64\xb4\x27\x1f\xb8\xf0\xbb\x78\x67\x15\x88\xb9\xef\x1d\x09\x3e\xa3\xd4\x72\x58\x4c\x6d\x43\xb5\x68\x33\x59\x47\x2f\x44\x1b\x33\x85\x6f\x68\x28\x59\xf0\xc3\x95\x4b\x56\x80\x8f\xd1\xfb\xa0\xb5\x9c\x9d\x19\x54"); assert_eq!(bytes_written, 64); - // check that if you feed it an output slice that's bigger than it needs, that it doesn't touch the extra bytes. + // Q. T. Felix NOTE: With the application of zeroize, the entire output buffer is pre-initialized to 0, + // so the bytes after the digest length are now also 0. + // Previously, the contract was to leave the trailing bytes untouched, + // but this has been changed to fill them with zeros to prevent exposure of stale data. let mut out = DUMMY_SEED_512.clone(); SHA3_256::new().hash_out(DUMMY_SEED_512, &mut out); - assert_eq!(&out[32..], &DUMMY_SEED_512[32..]); + assert!(out[32..].iter().all(|&b| b == 0)); } #[test] diff --git a/crypto/utils/src/ct.rs b/crypto/utils/src/ct.rs index 96b1950..10b23e7 100644 --- a/crypto/utils/src/ct.rs +++ b/crypto/utils/src/ct.rs @@ -292,6 +292,8 @@ pub fn conditional_copy_bytes( out: &mut [u8; LEN], take_a: bool, ) { + out.fill(0); + // we want the behaviour of // if take_a { 0xFF } else { 0x00 } // but without using any branches that could leak timing signals From 837b8d6aecd4255b72f8e88cb2ebb50960492ba6 Mon Sep 17 00:00:00 2001 From: Mike Ounsworth Date: Tue, 9 Jun 2026 18:56:01 -0500 Subject: [PATCH 04/13] adjusted the todo list --- alpha_0.1.2_release_notes.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/alpha_0.1.2_release_notes.md b/alpha_0.1.2_release_notes.md index 5039c13..ae53ed2 100644 --- a/alpha_0.1.2_release_notes.md +++ b/alpha_0.1.2_release_notes.md @@ -54,7 +54,11 @@ # 0.1.2 Features / Changelog -* ML-DSA -* Low-Memory ML-DSA -- runs in about 1/10th of the usual memory (~ 30 kb of stack) with only minor performance impact. +* New algorithms added to crypto/ : + * mldsa (FIPS 204) + * mldsa-lowmemory -- runs in about 1/10th of the usual memory (~ 30 kb of stack) with comparable performance impact. + * mlkem (FIPS 203) + * mlkem-lowmemory -- runs in about 1/4th of the usual memory (~ 12 kb of stack) with comparable performance impact. * Github issues resolved: - * #2, or whatever \ No newline at end of file + * #6: https://github.com/bcgit/bc-rust/issues/6, thanks to Q. T. Felix (github: @Quant-TheodoreFelix) + * #10: https://github.com/bcgit/bc-rust/issues/10, thanks to Nicola Tuveri (github: @romen) \ No newline at end of file From c642ef633108ce1983bb357f5e338bd34c545345 Mon Sep 17 00:00:00 2001 From: Quant-TheodoreFelix <53819958+Quant-TheodoreFelix@users.noreply.github.com> Date: Wed, 10 Jun 2026 13:36:21 +0900 Subject: [PATCH 05/13] =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= =?UTF-8?q?=20-=20=EB=B9=84=EA=B3=B5=EA=B0=9C=20mlkem=20compress=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20fill(0)=20=EC=A0=9C=EA=B1=B0=20(=EC=84=B1?= =?UTF-8?q?=EB=8A=A5)=20-=20ct=20conditional=5Fcopy=5Fbytes=20fill(0)=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=20(constant-time=20=EA=B0=80=EC=A0=95=20?= =?UTF-8?q?=EC=9C=84=EB=B0=98=20=EA=B0=80=EB=8A=A5)=20-=20core=20traits?= =?UTF-8?q?=EC=9D=98=20=5Fout=20=ED=95=A8=EC=88=98=20docstring=EC=97=90=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=20=EB=B2=84=ED=8D=BC=20zeroize=20=EB=AA=85?= =?UTF-8?q?=EC=8B=9C=20-=20sha3=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=EC=97=90=EC=84=9C=20=EC=9D=B4=EB=A6=84=EA=B3=BC=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EC=9D=B4=EB=A0=A5=20=EC=A0=9C=EA=B1=B0=20?= =?UTF-8?q?-=20=EB=A6=B4=EB=A6=AC=EC=A6=88=20=EB=85=B8=ED=8A=B8=EC=9D=98?= =?UTF-8?q?=20=EC=99=84=EB=A3=8C=EB=90=9C=20TODO=20=ED=95=AD=EB=AA=A9?= =?UTF-8?q?=EC=9D=84=20changelog=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- alpha_0.1.2_release_notes.md | 4 ++-- crypto/core/src/traits.rs | 20 ++++++++++++++++++++ crypto/mlkem/src/matrix.rs | 2 -- crypto/mlkem/src/polynomial.rs | 2 -- crypto/mlkem_lowmemory/src/polynomial.rs | 2 -- crypto/sha3/tests/sha3_tests.rs | 5 +---- crypto/utils/src/ct.rs | 2 -- 7 files changed, 23 insertions(+), 14 deletions(-) diff --git a/alpha_0.1.2_release_notes.md b/alpha_0.1.2_release_notes.md index 06dcefa..d6609db 100644 --- a/alpha_0.1.2_release_notes.md +++ b/alpha_0.1.2_release_notes.md @@ -12,8 +12,6 @@ * Check out Megan's email May 13 about KeyMaterial: "I was wondering if there might be scope for a closure based approach that could guarantee encapsulation of the state change from safe to hazardous back to safe again." -* Anywhere that you have an `_out(.. out: &mut [u8])`, start by zeroizing it with .fill(0); .. a good task for Claude? - And should be documented in the style guide? * Go back to previous algs and apply memory optimization tricks like internal functions. And add a docs section "Memory Usage" that measures with valgrind. * Ensure that all crates have `#![forbid(missing_docs)]` @@ -54,5 +52,7 @@ * ML-DSA * Low-Memory ML-DSA -- runs in about 1/10th of the usual memory (~ 30 kb of stack) with only minor performance impact. +* All public `*_out(.., out: &mut [u8])` functions now begin by zeroizing the entire output buffer with `.fill(0)`, + preventing exposure of stale data in oversized output buffers or on early error returns. * Github issues resolved: * #2, or whatever \ No newline at end of file diff --git a/crypto/core/src/traits.rs b/crypto/core/src/traits.rs index 27dd844..3713fcb 100644 --- a/crypto/core/src/traits.rs +++ b/crypto/core/src/traits.rs @@ -30,6 +30,7 @@ pub trait Hash : Default { /// A static one-shot API that hashes the provided data into the provided output slice. /// `data` can be of any length, including zero bytes. + /// The entire output buffer is zeroized before the hash output is written. /// The return value is the number of bytes written. fn hash_out(self, data: &[u8], output: &mut [u8]) -> usize; @@ -50,6 +51,8 @@ pub trait Hash : Default { /// If the provided buffer is smaller than the hash's output length, the output will be truncated. /// If the provided buffor is larger than the hash's output length, the output will be placed in /// the first [Hash::output_len] bytes. + /// The entire output buffer is zeroized before the hash output is written, so any bytes past + /// [Hash::output_len] will be 0. /// /// The return value is the number of bytes written. fn do_final_out(self, output: &mut [u8]) -> usize; @@ -65,6 +68,7 @@ pub trait Hash : Default { /// The same as [Hash::do_final_out], but allows for supplying a partial byte as the last input. /// Assumes that the input is in the least significant bits (big endian). /// will be placed in the first [Hash::output_len] bytes. + /// The entire output buffer is zeroized before the hash output is written. /// The return value is the number of bytes written. fn do_final_partial_bits_out( self, @@ -208,6 +212,7 @@ pub trait KEMPublicKey : PartialEq + Eq + Clone + Debug + D /// Write it out to bytes in its standard encoding. fn encode(&self) -> [u8; PK_LEN]; /// Write it out to bytes in its standard encoding. + /// The entire output buffer is zeroized before the encoding is written. fn encode_out(&self, out: &mut [u8; PK_LEN]) -> usize; /// Read it in from bytes in its standard encoding. fn from_bytes(bytes: &[u8]) -> Result; @@ -218,6 +223,7 @@ pub trait KEMPrivateKey : PartialEq + Eq + Clone + Secret + /// Write it out to bytes in its standard encoding. fn encode(&self) -> [u8; SK_LEN]; /// Write it out to bytes in its standard encoding. + /// The entire output buffer is zeroized before the encoding is written. fn encode_out(&self, out: &mut [u8; SK_LEN]) -> usize; /// Read it in from bytes in its standard encoding. fn from_bytes(bytes: &[u8]) -> Result; @@ -293,6 +299,8 @@ pub trait MAC: Sized { /// Depending on the underlying MAC implementation, NIST may require that the library enforce /// a minimum length on the mac output value. See documentation for the underlying implementation /// to see conditions under which it throws [MACError::InvalidLength]. + /// + /// The entire output buffer is zeroized before the MAC value is written. fn mac_out(self, data: &[u8],out: &mut [u8]) -> Result; /// One-shot API that verifies a MAC for the provided data. @@ -318,6 +326,8 @@ pub trait MAC: Sized { /// Depending on the underlying MAC implementation, NIST may require that the library enforce /// a minimum length on the mac output value. See documentation for the underlying implementation /// to see conditions under which it throws [MACError::InvalidLength]. + /// + /// The entire output buffer is zeroized before the MAC value is written. fn do_final_out(self, out: &mut [u8]) -> Result; /// Internally, this will re-compute the MAC value and then compare it to the provided mac value @@ -392,6 +402,7 @@ pub trait RNG : Default { fn next_bytes(&mut self, len: usize) -> Result, RNGError>; /// Returns the number of bytes written. + /// The entire output buffer is zeroized before the random bytes are written. fn next_bytes_out(&mut self, out: &mut [u8]) -> Result; fn fill_keymaterial_out(&mut self, out: &mut impl KeyMaterialTrait) -> Result; @@ -443,6 +454,7 @@ pub trait PHSignature< /// might throw an error, ignore the provided ctx value, or append the ctx to the msg in a non-standard way. fn sign_ph(sk: &SK, ph: &[u8; PH_LEN], ctx: Option<&[u8]>) -> Result<[u8; SIG_LEN], SignatureError>; /// Returns the number of bytes written to the output buffer. Can be called with an oversized buffer. + /// The entire output buffer is zeroized before the signature is written. fn sign_ph_out(sk: &SK, ph: &[u8; PH_LEN], ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN]) -> Result; /// On success, returns Ok(()) /// On failure, returns Err([SignatureError::SignatureVerificationFailed]); may also return other types of [SignatureError] as appropriate (such as for invalid-length inputs). @@ -501,6 +513,7 @@ pub trait Signature< fn sign(sk: &SK, msg: &[u8], ctx: Option<&[u8]>) -> Result<[u8; SIG_LEN], SignatureError>; /// Returns the number of bytes written to the output buffer. Can be called with an oversized buffer. + /// The entire output buffer is zeroized before the signature is written. fn sign_out(sk: &SK, msg: &[u8], ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN]) -> Result; /* streaming signing API */ @@ -516,6 +529,7 @@ pub trait Signature< fn sign_final(self) -> Result<[u8; SIG_LEN], SignatureError>; /// Returns the number of bytes written to the output buffer. Can be called with an oversized buffer. + /// The entire output buffer is zeroized before the signature is written. fn sign_final_out(self, output: &mut [u8; SIG_LEN]) -> Result; /// On success, returns Ok(()) @@ -543,6 +557,7 @@ pub trait SignaturePublicKey : PartialEq + Eq + Clone + Deb /// Write it out to bytes in its standard encoding. fn encode(&self) -> [u8; PK_LEN]; /// Write it out to bytes in its standard encoding. + /// The entire output buffer is zeroized before the encoding is written. fn encode_out(&self, out: &mut [u8; PK_LEN]) -> usize; /// Read it in from bytes in its standard encoding. fn from_bytes(bytes: &[u8]) -> Result; @@ -553,6 +568,7 @@ pub trait SignaturePrivateKey : PartialEq + Eq + Clone + Se /// Write it out to bytes in its standard encoding. fn encode(&self) -> [u8; SK_LEN]; /// Write it out to bytes in its standard encoding. + /// The entire output buffer is zeroized before the encoding is written. fn encode_out(&self, out: &mut [u8; SK_LEN]) -> usize; /// Read it in from bytes in its standard encoding. fn from_bytes(bytes: &[u8]) -> Result; @@ -583,6 +599,7 @@ pub trait XOF : Default { /// A static one-shot API that digests the input data and produces `result_len` bytes of output. /// Fills the provided output slice. + /// The entire output buffer is zeroized before the output is written. fn hash_xof_out(self, data: &[u8], output: &mut [u8]) -> usize; fn absorb(&mut self, data: &[u8]); @@ -599,6 +616,7 @@ pub trait XOF : Default { /// Can be called multiple times. /// Fills the provided output slice. + /// The entire output buffer is zeroized before the output is written. fn squeeze_out(&mut self, output: &mut [u8]) -> usize; /// Squeezes a partial byte from the XOF. @@ -606,6 +624,8 @@ pub trait XOF : Default { /// This is a final call and consumes self. fn squeeze_partial_byte_final(self, num_bits: usize) -> Result; + /// The same as [XOF::squeeze_partial_byte_final], but writes into the provided output byte. + /// The output byte is zeroized before the result is written. fn squeeze_partial_byte_final_out( self, num_bits: usize, diff --git a/crypto/mlkem/src/matrix.rs b/crypto/mlkem/src/matrix.rs index 563d19c..381e7be 100644 --- a/crypto/mlkem/src/matrix.rs +++ b/crypto/mlkem/src/matrix.rs @@ -171,8 +171,6 @@ impl Vector // let mut s = self.clone(); // s.conditional_sub_q(); - out.fill(0); - let mut idx = 0; match du { 10 => { // MLKEM512 and MLKEM 768 diff --git a/crypto/mlkem/src/polynomial.rs b/crypto/mlkem/src/polynomial.rs index 1a9bb2e..13bc411 100644 --- a/crypto/mlkem/src/polynomial.rs +++ b/crypto/mlkem/src/polynomial.rs @@ -127,8 +127,6 @@ impl Polynomial { // each of the N i16's will take dv bits debug_assert_eq!(out.len(), N * (dv as usize) / 8); - out.fill(0); - let mut t = [0u8; 8]; let mut idx = 0; diff --git a/crypto/mlkem_lowmemory/src/polynomial.rs b/crypto/mlkem_lowmemory/src/polynomial.rs index a2b1603..bec4ee4 100644 --- a/crypto/mlkem_lowmemory/src/polynomial.rs +++ b/crypto/mlkem_lowmemory/src/polynomial.rs @@ -150,8 +150,6 @@ impl Polynomial { // each of the N i16's will take dv bits debug_assert_eq!(out.len(), N * (dv as usize) / 8); - out.fill(0); - let mut t = [0u8; 8]; let mut idx = 0; diff --git a/crypto/sha3/tests/sha3_tests.rs b/crypto/sha3/tests/sha3_tests.rs index b2d5311..68fd94b 100644 --- a/crypto/sha3/tests/sha3_tests.rs +++ b/crypto/sha3/tests/sha3_tests.rs @@ -66,10 +66,7 @@ mod sha3_tests { assert_eq!(&out, b"\x58\x4c\xc7\x02\xc2\x22\x9a\x0a\xbc\x78\x9b\xfa\x64\xb4\x27\x1f\xb8\xf0\xbb\x78\x67\x15\x88\xb9\xef\x1d\x09\x3e\xa3\xd4\x72\x58\x4c\x6d\x43\xb5\x68\x33\x59\x47\x2f\x44\x1b\x33\x85\x6f\x68\x28\x59\xf0\xc3\x95\x4b\x56\x80\x8f\xd1\xfb\xa0\xb5\x9c\x9d\x19\x54"); assert_eq!(bytes_written, 64); - // Q. T. Felix NOTE: With the application of zeroize, the entire output buffer is pre-initialized to 0, - // so the bytes after the digest length are now also 0. - // Previously, the contract was to leave the trailing bytes untouched, - // but this has been changed to fill them with zeros to prevent exposure of stale data. + // check that the bytes of an oversized output buffer past the digest length get zeroized. let mut out = DUMMY_SEED_512.clone(); SHA3_256::new().hash_out(DUMMY_SEED_512, &mut out); assert!(out[32..].iter().all(|&b| b == 0)); diff --git a/crypto/utils/src/ct.rs b/crypto/utils/src/ct.rs index 10b23e7..96b1950 100644 --- a/crypto/utils/src/ct.rs +++ b/crypto/utils/src/ct.rs @@ -292,8 +292,6 @@ pub fn conditional_copy_bytes( out: &mut [u8; LEN], take_a: bool, ) { - out.fill(0); - // we want the behaviour of // if take_a { 0xFF } else { 0x00 } // but without using any branches that could leak timing signals From 8b460ac298eeae90c6ac183485bcef2102f2434b Mon Sep 17 00:00:00 2001 From: Mike Ounsworth Date: Wed, 10 Jun 2026 03:05:55 -0500 Subject: [PATCH 06/13] Split the Signature trait into Signer and SignatureVerifier --- cli/src/mldsa_cmd.rs | 2 +- crypto/core-test-framework/src/signature.rs | 146 +++++---- crypto/core/src/traits.rs | 164 +++++++--- crypto/mldsa/benches/mldsa_benches.rs | 2 +- crypto/mldsa/src/hash_mldsa.rs | 208 +++++++++--- crypto/mldsa/src/lib.rs | 7 +- crypto/mldsa/src/mldsa.rs | 98 ++++-- crypto/mldsa/tests/bc_test_data.rs | 2 +- crypto/mldsa/tests/hash_mldsa_tests.rs | 22 +- crypto/mldsa/tests/mldsa_key_tests.rs | 12 +- crypto/mldsa/tests/mldsa_tests.rs | 8 +- crypto/mldsa/tests/wycheproof.rs | 2 +- .../mldsa_lowmemory/benches/mldsa_benches.rs | 2 +- crypto/mldsa_lowmemory/src/hash_mldsa.rs | 302 ++++++++++++++---- crypto/mldsa_lowmemory/src/lib.rs | 7 +- crypto/mldsa_lowmemory/src/mldsa.rs | 113 ++++++- crypto/mldsa_lowmemory/tests/bc_test_data.rs | 2 +- .../mldsa_lowmemory/tests/hash_mldsa_tests.rs | 22 +- .../mldsa_lowmemory/tests/mldsa_key_tests.rs | 8 +- crypto/mldsa_lowmemory/tests/mldsa_tests.rs | 8 +- crypto/mldsa_lowmemory/tests/wycheproof.rs | 2 +- mem_usage_benches/bench_mldsa_mem_usage.rs | 2 +- 22 files changed, 828 insertions(+), 313 deletions(-) diff --git a/cli/src/mldsa_cmd.rs b/cli/src/mldsa_cmd.rs index 79ba941..abced47 100644 --- a/cli/src/mldsa_cmd.rs +++ b/cli/src/mldsa_cmd.rs @@ -2,7 +2,7 @@ //! by using generics or macros. I just, haven't ... yet. use crate::helpers::{parse_seed, read_from_file, read_from_file_or_stdin, write_bytes_or_hex}; -use bouncycastle::core::traits::{Signature, SignaturePrivateKey, SignaturePublicKey}; +use bouncycastle::core::traits::{SignatureVerifier, Signer, SignaturePrivateKey, SignaturePublicKey}; use bouncycastle::hex; use bouncycastle::mldsa::{MLDSA_SEED_LEN, MLDSA44, MLDSA44_SK_LEN, MLDSA44PrivateKey, MLDSA87_SK_LEN, MLDSAPrivateKeyTrait, MLDSATrait, MLDSA44PublicKey, MLDSA44_PK_LEN, MLDSA65_SK_LEN, MLDSA65PrivateKey, MLDSA65, MLDSA65PublicKey, MLDSA65_PK_LEN, MLDSA87PrivateKey, MLDSA87, MLDSA87PublicKey, MLDSA87_PK_LEN, HashMLDSA44_with_SHA512, HashMLDSA65_with_SHA512, HashMLDSA87_with_SHA512}; use std::{io}; diff --git a/crypto/core-test-framework/src/signature.rs b/crypto/core-test-framework/src/signature.rs index d97dc0c..914ae44 100644 --- a/crypto/core-test-framework/src/signature.rs +++ b/crypto/core-test-framework/src/signature.rs @@ -1,7 +1,8 @@ use crate::DUMMY_SEED_1024; use bouncycastle_core::errors::SignatureError; use bouncycastle_core::traits::{ - Hash, PHSignature, Signature, SignaturePrivateKey, SignaturePublicKey, + Hash, PHSignatureVerifier, PHSigner, SignaturePrivateKey, SignaturePublicKey, + SignatureVerifier, Signer, }; pub struct TestFrameworkSignature { @@ -18,54 +19,59 @@ impl TestFrameworkSignature { Self { alg_is_deterministic, alg_accepts_ctx } } - /// Test all the members of trait Hash against the given input-output pair. + /// Test all the members of traits [Signer] and [SignatureVerifier] against the given input-output pair. /// This gives good baseline test coverage, but is not exhaustive. + /// + /// Since key generation is not part of either signature trait, the caller supplies a + /// `keygen` function pointer (the inherent `keygen` associated function on the algorithm struct). pub fn test_signature< PK: SignaturePublicKey, SK: SignaturePrivateKey, - SigAlg: Signature, + SIGNER: Signer, + VERIFIER: SignatureVerifier, const PK_LEN: usize, const SK_LEN: usize, const SIG_LEN: usize, >( &self, + keygen: fn() -> Result<(PK, SK), SignatureError>, run_full_bitflipping_tests: bool, ) { let msg = b"The quick brown fox jumped over the lazy dog"; // Basic test - let (pk, sk) = SigAlg::keygen().unwrap(); - let sig_val = SigAlg::sign(&sk, msg, None).unwrap(); - SigAlg::verify(&pk, msg, None, &sig_val).unwrap(); + let (pk, sk) = keygen().unwrap(); + let sig_val = SIGNER::sign(&sk, msg, None).unwrap(); + VERIFIER::verify(&pk, msg, None, &sig_val).unwrap(); // Test non-determinism if !self.alg_is_deterministic { - let sig1 = SigAlg::sign(&sk, msg, None).unwrap(); - let sig2 = SigAlg::sign(&sk, msg, None).unwrap(); + let sig1 = SIGNER::sign(&sk, msg, None).unwrap(); + let sig2 = SIGNER::sign(&sk, msg, None).unwrap(); assert_ne!(sig1, sig2); } // uses ctx // success case - let sig = SigAlg::sign(&sk, msg, Some(b"test with ctx")).unwrap(); - SigAlg::verify(&pk, msg, Some(b"test with ctx"), &sig).unwrap(); + let sig = SIGNER::sign(&sk, msg, Some(b"test with ctx")).unwrap(); + VERIFIER::verify(&pk, msg, Some(b"test with ctx"), &sig).unwrap(); // but it had better produce something different if !self.alg_accepts_ctx { - let sig1 = SigAlg::sign(&sk, msg, None).unwrap(); - let sig2 = SigAlg::sign(&sk, msg, Some(&[0u8; 1])).unwrap(); + let sig1 = SIGNER::sign(&sk, msg, None).unwrap(); + let sig2 = SIGNER::sign(&sk, msg, Some(&[0u8; 1])).unwrap(); assert_ne!(sig1, sig2); } // Test that verification fails for broken signature value - let (pk, sk) = SigAlg::keygen().unwrap(); - let sig_val = SigAlg::sign(&sk, msg, None).unwrap(); + let (pk, sk) = keygen().unwrap(); + let sig_val = SIGNER::sign(&sk, msg, None).unwrap(); // spot-check let mut sig_val_copy = sig_val.clone(); sig_val_copy[8] ^= 0x0F; // should throw an Err - match SigAlg::verify(&pk, msg, None, &sig_val_copy) { + match VERIFIER::verify(&pk, msg, None, &sig_val_copy) { Err(SignatureError::SignatureVerificationFailed) => (), _ => panic!("This should have thrown an error but it didn't."), } @@ -78,7 +84,7 @@ impl TestFrameworkSignature { sig_val_copy[i] ^= 1 << j; // should throw an Err - match SigAlg::verify(&pk, msg, None, &sig_val_copy) { + match VERIFIER::verify(&pk, msg, None, &sig_val_copy) { Err(SignatureError::SignatureVerificationFailed) => (), _ => panic!( "This should have thrown an error but it didn't when byte {i} bit {j} of the signature was flipped" @@ -93,13 +99,13 @@ impl TestFrameworkSignature { // Success case let mut output = [0u8; SIG_LEN]; - let bytes_written = SigAlg::sign_out(&sk, msg, None, &mut output).unwrap(); + let bytes_written = SIGNER::sign_out(&sk, msg, None, &mut output).unwrap(); assert_eq!(bytes_written, SIG_LEN); - SigAlg::verify(&pk, msg, None, &sig_val).unwrap(); + VERIFIER::verify(&pk, msg, None, &sig_val).unwrap(); // test with a large message - let sig = SigAlg::sign(&sk, DUMMY_SEED_1024, None).unwrap(); - SigAlg::verify(&pk, DUMMY_SEED_1024, None, &sig).unwrap(); + let sig = SIGNER::sign(&sk, DUMMY_SEED_1024, None).unwrap(); + VERIFIER::verify(&pk, DUMMY_SEED_1024, None, &sig).unwrap(); // Test the streaming signing API // fn sign_init(&mut self, sk: &SK) -> Result<(), SignatureError>; @@ -108,37 +114,37 @@ impl TestFrameworkSignature { // fn sign_final_out(&mut self, msg_chunk: &[u8], ctx: &[u8], output: &mut [u8]) -> Result<(), SignatureError>; // First, test the streaming API with one call to .sign_update - let mut s = SigAlg::sign_init(&sk, Some(b"streaming API")).unwrap(); + let mut s = SIGNER::sign_init(&sk, Some(b"streaming API")).unwrap(); s.sign_update(DUMMY_SEED_1024); let sig_val = s.sign_final().unwrap(); - SigAlg::verify(&pk, DUMMY_SEED_1024, Some(b"streaming API"), &sig_val).unwrap(); + VERIFIER::verify(&pk, DUMMY_SEED_1024, Some(b"streaming API"), &sig_val).unwrap(); // Then with the message broken into chunks - let mut s = SigAlg::sign_init(&sk, Some(b"streaming API chunked")).unwrap(); + let mut s = SIGNER::sign_init(&sk, Some(b"streaming API chunked")).unwrap(); for msg_chunk in DUMMY_SEED_1024.chunks(100) { s.sign_update(msg_chunk); } let sig_val = s.sign_final().unwrap(); - SigAlg::verify(&pk, DUMMY_SEED_1024, Some(b"streaming API chunked"), &sig_val).unwrap(); + VERIFIER::verify(&pk, DUMMY_SEED_1024, Some(b"streaming API chunked"), &sig_val).unwrap(); // Test the streaming verification API // one-shot - let sig = SigAlg::sign(&sk, DUMMY_SEED_1024, Some(b"streaming API")).unwrap(); - let mut v = SigAlg::verify_init(&pk, Some(b"streaming API")).unwrap(); + let sig = SIGNER::sign(&sk, DUMMY_SEED_1024, Some(b"streaming API")).unwrap(); + let mut v = VERIFIER::verify_init(&pk, Some(b"streaming API")).unwrap(); v.verify_update(DUMMY_SEED_1024); v.verify_final(&sig).unwrap(); // chunked - let sig = SigAlg::sign(&sk, DUMMY_SEED_1024, Some(b"streaming API")).unwrap(); - let mut v = SigAlg::verify_init(&pk, Some(b"streaming API")).unwrap(); + let sig = SIGNER::sign(&sk, DUMMY_SEED_1024, Some(b"streaming API")).unwrap(); + let mut v = VERIFIER::verify_init(&pk, Some(b"streaming API")).unwrap(); for msg_chunk in DUMMY_SEED_1024.chunks(100) { v.verify_update(msg_chunk); } v.verify_final(&sig).unwrap(); // failure case for streaming verify - let sig = SigAlg::sign(&sk, DUMMY_SEED_1024, Some(b"streaming API")).unwrap(); - let mut v = SigAlg::verify_init(&pk, Some(b"streaming API")).unwrap(); + let sig = SIGNER::sign(&sk, DUMMY_SEED_1024, Some(b"streaming API")).unwrap(); + let mut v = VERIFIER::verify_init(&pk, Some(b"streaming API")).unwrap(); v.verify_update(b"this is the wrong message"); match v.verify_final(&sig) { Err(SignatureError::SignatureVerificationFailed) => (), @@ -146,25 +152,30 @@ impl TestFrameworkSignature { } // test sign_out version of streaming API - let mut s = SigAlg::sign_init(&sk, Some(b"streaming API")).unwrap(); + let mut s = SIGNER::sign_init(&sk, Some(b"streaming API")).unwrap(); s.sign_update(DUMMY_SEED_1024); let mut sig_val = [0u8; SIG_LEN]; let bytes_written = s.sign_final_out(&mut sig_val).unwrap(); assert_eq!(bytes_written, SIG_LEN); - SigAlg::verify(&pk, DUMMY_SEED_1024, Some(b"streaming API"), &sig_val).unwrap(); + VERIFIER::verify(&pk, DUMMY_SEED_1024, Some(b"streaming API"), &sig_val).unwrap(); // the ::verify API should accept a sig value that's too long and just ignore the extra bytes let mut sig_val_too_long = vec![1u8; SIG_LEN + 2]; sig_val_too_long[..SIG_LEN].copy_from_slice(&sig_val); - SigAlg::verify(&pk, DUMMY_SEED_1024, Some(b"streaming API"), &sig_val).unwrap(); + VERIFIER::verify(&pk, DUMMY_SEED_1024, Some(b"streaming API"), &sig_val).unwrap(); } - /// Test all the members of trait Hash against the given input-output pair. + /// Test all the members of traits [PHSigner] and [PHSignatureVerifier] against the given input-output pair. /// This gives good baseline test coverage, but is not exhaustive. + /// + /// Since key generation is not part of either signature trait, the caller supplies a + /// `keygen` function pointer (the inherent `keygen` associated function on the algorithm struct). pub fn test_ph_signature< PK: SignaturePublicKey, SK: SignaturePrivateKey, - SigAlg: PHSignature, + // todo split this into two params: SIGNER: Signer and VERIFIER: SignatureVerifier + PHSIGNER: PHSigner, + PHVERIFIER: PHSignatureVerifier, HASH: Hash + Default, const PK_LEN: usize, const SK_LEN: usize, @@ -172,43 +183,44 @@ impl TestFrameworkSignature { const PH_LEN: usize, >( &self, + keygen: fn() -> Result<(PK, SK), SignatureError>, run_full_bitflipping_tests: bool, ) { let msg = b"The quick brown fox jumped over the lazy dog"; // Basic test - let (pk, sk) = SigAlg::keygen().unwrap(); - let sig_val = SigAlg::sign(&sk, msg, None).unwrap(); - SigAlg::verify(&pk, msg, None, &sig_val).unwrap(); + let (pk, sk) = keygen().unwrap(); + let sig_val = PHSIGNER::sign(&sk, msg, None).unwrap(); + PHVERIFIER::verify(&pk, msg, None, &sig_val).unwrap(); // Test non-determinism if !self.alg_is_deterministic { - let sig1 = SigAlg::sign(&sk, msg, None).unwrap(); - let sig2 = SigAlg::sign(&sk, msg, None).unwrap(); + let sig1 = PHSIGNER::sign(&sk, msg, None).unwrap(); + let sig2 = PHSIGNER::sign(&sk, msg, None).unwrap(); assert_ne!(sig1, sig2); } // uses ctx // success case - let sig = SigAlg::sign(&sk, msg, Some(b"test with ctx")).unwrap(); - SigAlg::verify(&pk, msg, Some(b"test with ctx"), &sig).unwrap(); + let sig = PHSIGNER::sign(&sk, msg, Some(b"test with ctx")).unwrap(); + PHVERIFIER::verify(&pk, msg, Some(b"test with ctx"), &sig).unwrap(); // but it had better produce something different if !self.alg_accepts_ctx { - let sig1 = SigAlg::sign(&sk, msg, None).unwrap(); - let sig2 = SigAlg::sign(&sk, msg, Some(&[0u8; 1])).unwrap(); + let sig1 = PHSIGNER::sign(&sk, msg, None).unwrap(); + let sig2 = PHSIGNER::sign(&sk, msg, Some(&[0u8; 1])).unwrap(); assert_ne!(sig1, sig2); } // Test that verification fails for broken signature value - let (pk, sk) = SigAlg::keygen().unwrap(); - let sig_val = SigAlg::sign(&sk, msg, None).unwrap(); + let (pk, sk) = keygen().unwrap(); + let sig_val = PHSIGNER::sign(&sk, msg, None).unwrap(); // spot-check let mut sig_val_copy = sig_val.clone(); sig_val_copy[8] ^= 0x0F; // should throw an Err - match SigAlg::verify(&pk, msg, None, &sig_val_copy) { + match PHVERIFIER::verify(&pk, msg, None, &sig_val_copy) { Err(SignatureError::SignatureVerificationFailed) => (), _ => panic!("This should have thrown an error but it didn't."), } @@ -221,7 +233,7 @@ impl TestFrameworkSignature { sig_val_copy[i] ^= 1 << j; // should throw an Err - match SigAlg::verify(&pk, msg, None, &sig_val_copy) { + match PHVERIFIER::verify(&pk, msg, None, &sig_val_copy) { Err(SignatureError::SignatureVerificationFailed) => (), _ => panic!( "This should have thrown an error but it didn't when byte {i} bit {j} of the signature was flipped" @@ -236,37 +248,37 @@ impl TestFrameworkSignature { // Success case let mut output = [0u8; SIG_LEN]; - let bytes_written = SigAlg::sign_out(&sk, msg, None, &mut output).unwrap(); + let bytes_written = PHSIGNER::sign_out(&sk, msg, None, &mut output).unwrap(); assert_eq!(bytes_written, SIG_LEN); - SigAlg::verify(&pk, msg, None, &sig_val).unwrap(); + PHVERIFIER::verify(&pk, msg, None, &sig_val).unwrap(); // test with a large message - let sig = SigAlg::sign(&sk, DUMMY_SEED_1024, None).unwrap(); - SigAlg::verify(&pk, DUMMY_SEED_1024, None, &sig).unwrap(); + let sig = PHSIGNER::sign(&sk, DUMMY_SEED_1024, None).unwrap(); + PHVERIFIER::verify(&pk, DUMMY_SEED_1024, None, &sig).unwrap(); // the ::verify API should not accept a sig value that's too let mut sig_val_too_long = vec![1u8; SIG_LEN + 2]; sig_val_too_long[..SIG_LEN].copy_from_slice(&sig); - match SigAlg::verify(&pk, DUMMY_SEED_1024, None, &sig_val_too_long) { + match PHVERIFIER::verify(&pk, DUMMY_SEED_1024, None, &sig_val_too_long) { Err(SignatureError::LengthError(_)) => (), _ => panic!("Unexpected error"), } // sign_ph - let (pk, sk) = SigAlg::keygen().unwrap(); + let (pk, sk) = keygen().unwrap(); let ph: [u8; PH_LEN] = HASH::default().hash(msg)[..PH_LEN].try_into().unwrap(); - let sig_val = SigAlg::sign_ph(&sk, &ph, None).unwrap(); - SigAlg::verify(&pk, msg, None, &sig_val).unwrap(); - SigAlg::verify_ph(&pk, &ph, None, &sig_val).unwrap(); + let sig_val = PHSIGNER::sign_ph(&sk, &ph, None).unwrap(); + PHVERIFIER::verify(&pk, msg, None, &sig_val).unwrap(); + PHVERIFIER::verify_ph(&pk, &ph, None, &sig_val).unwrap(); // sign_ph_out - let (pk, sk) = SigAlg::keygen().unwrap(); + let (pk, sk) = keygen().unwrap(); let ph: [u8; PH_LEN] = HASH::default().hash(msg)[..PH_LEN].try_into().unwrap(); let mut sig_val = [0u8; SIG_LEN]; - let bytes_written = SigAlg::sign_ph_out(&sk, &ph, None, &mut sig_val).unwrap(); + let bytes_written = PHSIGNER::sign_ph_out(&sk, &ph, None, &mut sig_val).unwrap(); assert_eq!(bytes_written, SIG_LEN); - SigAlg::verify_ph(&pk, &ph, None, &sig_val).unwrap(); - SigAlg::verify(&pk, msg, None, &sig_val).unwrap(); + PHVERIFIER::verify_ph(&pk, &ph, None, &sig_val).unwrap(); + PHVERIFIER::verify(&pk, msg, None, &sig_val).unwrap(); } } @@ -277,31 +289,31 @@ impl TestFrameworkSignatureKeys { Self {} } + /// Since key generation is not part of either signature trait, the caller supplies a + /// `keygen` function pointer (the inherent `keygen` associated function on the algorithm struct). pub fn test_keys< PK: SignaturePublicKey, SK: SignaturePrivateKey, - SigAlg: Signature, const PK_LEN: usize, const SK_LEN: usize, - const SIG_LEN: usize, >( &self, + keygen: fn() -> Result<(PK, SK), SignatureError>, ) { - self.test_boundary_conditions::(); + self.test_boundary_conditions::(keygen); } /// Tests the correct behaviour on buffers too large / too small. fn test_boundary_conditions< PK: SignaturePublicKey, SK: SignaturePrivateKey, - SigAlg: Signature, const PK_LEN: usize, const SK_LEN: usize, - const SIG_LEN: usize, >( &self, + keygen: fn() -> Result<(PK, SK), SignatureError>, ) { - let (pk, sk) = SigAlg::keygen().unwrap(); + let (pk, sk) = keygen().unwrap(); let pk_bytes = pk.encode(); assert_eq!(pk_bytes.len(), PK_LEN); diff --git a/crypto/core/src/traits.rs b/crypto/core/src/traits.rs index 27dd844..1a623ab 100644 --- a/crypto/core/src/traits.rs +++ b/crypto/core/src/traits.rs @@ -1,9 +1,9 @@ //! Provides simplified abstracted APIs over classes of cryptigraphic primitives, such as Hash, KDF, etc. -use core::marker::Sized; -use core::fmt::{Debug, Display}; use crate::errors::{HashError, KDFError, KEMError, MACError, RNGError, SignatureError}; use crate::key_material::KeyMaterialTrait; +use core::fmt::{Debug, Display}; +use core::marker::Sized; // Imports needed for docs #[allow(unused_imports)] @@ -17,7 +17,7 @@ pub trait Algorithm { const MAX_SECURITY_STRENGTH: SecurityStrength; } -pub trait Hash : Default { +pub trait Hash: Default { /// The size of the internal block in bits -- needed by functions such as HMAC to compute security parameters. fn block_bitlen(&self) -> usize; @@ -84,7 +84,7 @@ pub trait HashAlgParams: Algorithm { /// A Key Derivation Function (KDF) is a function that takes in one or more input key and some unstructured /// additional input, and uses them to produces a derived key. -pub trait KDF : Default { +pub trait KDF: Default { /// Implementations of this function are capable of deriving an output key from an input key, /// assuming that they have been properly initialized. /// @@ -186,11 +186,12 @@ pub trait KEM< const SK_LEN: usize, const CT_LEN: usize, const SS_LEN: usize, ->: Sized { +>: Sized +{ /// Generate a keypair. /// Error condition: Basically only on RNG failures fn keygen() -> Result<(PK, SK), KEMError>; - + /// Performs an encapsulation against the given public key. /// Returns the ciphertext and derived shared secret. fn encaps(pk: &PK) -> Result<(KeyMaterial, [u8; CT_LEN]), KEMError>; @@ -204,7 +205,9 @@ pub trait KEM< // todo: that automatically call the encode and from_bytes() ? /// A public key for a KEM algorithm, often denoted "pk". -pub trait KEMPublicKey : PartialEq + Eq + Clone + Debug + Display + Sized { +pub trait KEMPublicKey: + PartialEq + Eq + Clone + Debug + Display + Sized +{ /// Write it out to bytes in its standard encoding. fn encode(&self) -> [u8; PK_LEN]; /// Write it out to bytes in its standard encoding. @@ -214,7 +217,7 @@ pub trait KEMPublicKey : PartialEq + Eq + Clone + Debug + D } /// A private key for a KEM algorithm, often denoted "sk" (for "secret key"). -pub trait KEMPrivateKey : PartialEq + Eq + Clone + Secret + Sized { +pub trait KEMPrivateKey: PartialEq + Eq + Clone + Secret + Sized { /// Write it out to bytes in its standard encoding. fn encode(&self) -> [u8; SK_LEN]; /// Write it out to bytes in its standard encoding. @@ -223,7 +226,6 @@ pub trait KEMPrivateKey : PartialEq + Eq + Clone + Secret + fn from_bytes(bytes: &[u8]) -> Result; } - /// A Message Authentication Code algorithm is a keyed hash function that behaves somewhat like a symmetric signature function. /// A MAC algorithm takes in a key and some data, and produces a MAC (message authentication code) that /// can be used to verify the integrity of data. @@ -293,7 +295,7 @@ pub trait MAC: Sized { /// Depending on the underlying MAC implementation, NIST may require that the library enforce /// a minimum length on the mac output value. See documentation for the underlying implementation /// to see conditions under which it throws [MACError::InvalidLength]. - fn mac_out(self, data: &[u8],out: &mut [u8]) -> Result; + fn mac_out(self, data: &[u8], out: &mut [u8]) -> Result; /// One-shot API that verifies a MAC for the provided data. /// `data` can be of any length, including zero bytes. @@ -381,11 +383,14 @@ impl SecurityStrength { /// be used by applications that intend to submit to FIPS certification as it more closely aligns with the /// requirements of SP 800-90A. /// Note: this interface produces bytes. If you want a [KeyMaterialTrait], then use [KeyMaterial::from_rng]. -pub trait RNG : Default { +pub trait RNG: Default { // TODO: add back once we figure out streaming interaction with entropy sources. // fn add_seed_bytes(&mut self, additional_seed: &[u8]) -> Result<(), RNGError>; - fn add_seed_keymaterial(&mut self, additional_seed: impl KeyMaterialTrait) -> Result<(), RNGError>; + fn add_seed_keymaterial( + &mut self, + additional_seed: impl KeyMaterialTrait, + ) -> Result<(), RNGError>; fn next_int(&mut self) -> Result; /// Returns the number of requested bytes. @@ -402,21 +407,23 @@ pub trait RNG : Default { /// A trait that forces an object to implement a zeroizing Drop() as well as Debug and Display that /// will not log the sensitive contents, even in error or crash-dump scenarios. -#[allow(drop_bounds)] // Since rust auto-implements Drop, there's a lint that explicitly bounding on Drop is useless. - // I disagree because I want to force things that are secrets to manually implement Drop that zeroizes the data. - // So I'm turning off this lint. -pub trait Secret : Drop + Debug + Display {} +// Since rust auto-implements Drop, there's a lint that explicitly bounding on Drop is useless. +// I disagree because I want to force things that are secrets to manually implement Drop that zeroizes the data. +// So I'm turning off this lint. +#[allow(drop_bounds)] +pub trait Secret: Drop + Debug + Display {} -/// Pre-Hashed Signature is an extension to [Signature] that adds functionality specific to signature +/// Pre-Hashed Signer is an extension to [Signer] that adds functionality specific to signature /// primatives that can operate on a pre-hashed message instead of the full message. -pub trait PHSignature< +pub trait PHSigner< PK: SignaturePublicKey, SK: SignaturePrivateKey, const PK_LEN: usize, const SK_LEN: usize, const SIG_LEN: usize, - const PH_LEN: usize>: - Signature{ + const PH_LEN: usize, +>: Signer +{ /// Produce a signature for the provided pre-hashed message and context. /// /// `ctx` accepts a zero-length byte array. @@ -441,40 +448,92 @@ pub trait PHSignature< /// Not all signature primitives will support a context value, so you may need to consult the /// documentation for the underlying primitive for how it handles a ctx in that case, for example, it /// might throw an error, ignore the provided ctx value, or append the ctx to the msg in a non-standard way. - fn sign_ph(sk: &SK, ph: &[u8; PH_LEN], ctx: Option<&[u8]>) -> Result<[u8; SIG_LEN], SignatureError>; + fn sign_ph( + sk: &SK, + ph: &[u8; PH_LEN], + ctx: Option<&[u8]>, + ) -> Result<[u8; SIG_LEN], SignatureError>; /// Returns the number of bytes written to the output buffer. Can be called with an oversized buffer. - fn sign_ph_out(sk: &SK, ph: &[u8; PH_LEN], ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN]) -> Result; + fn sign_ph_out( + sk: &SK, + ph: &[u8; PH_LEN], + ctx: Option<&[u8]>, + output: &mut [u8; SIG_LEN], + ) -> Result; +} + +/// Pre-Hashed Signature Verifier is an extension to [SignatureVerifier] that adds functionality specific to signature +/// primatives that can operate on a pre-hashed message instead of the full message. +pub trait PHSignatureVerifier< + PK: SignaturePublicKey, + const PK_LEN: usize, + const SIG_LEN: usize, + const PH_LEN: usize, +>: SignatureVerifier +{ /// On success, returns Ok(()) /// On failure, returns Err([SignatureError::SignatureVerificationFailed]); may also return other types of [SignatureError] as appropriate (such as for invalid-length inputs). - fn verify_ph(pk: &PK, ph: &[u8; PH_LEN], ctx: Option<&[u8]>, sig: &[u8]) -> Result<(), SignatureError>; + fn verify_ph( + pk: &PK, + ph: &[u8; PH_LEN], + ctx: Option<&[u8]>, + sig: &[u8], + ) -> Result<(), SignatureError>; +} + +// todo: could the public and private key types impl Into> and From> +// todo: that automatically call the encode and from_bytes() ? + +/// A public key for a signature algorithm, often denoted "pk". +pub trait SignaturePublicKey: + PartialEq + Eq + Clone + Debug + Display + Sized +{ + /// Write it out to bytes in its standard encoding. + fn encode(&self) -> [u8; PK_LEN]; + /// Write it out to bytes in its standard encoding. + /// The entire output buffer is zeroized before the encoding is written. + fn encode_out(&self, out: &mut [u8; PK_LEN]) -> usize; + /// Read it in from bytes in its standard encoding. + fn from_bytes(bytes: &[u8]) -> Result; +} + +/// A private key for a signature algorithm, often denoted "sk" (for "secret key"). +pub trait SignaturePrivateKey: + PartialEq + Eq + Clone + Secret + Sized +{ + /// Write it out to bytes in its standard encoding. + fn encode(&self) -> [u8; SK_LEN]; + /// Write it out to bytes in its standard encoding. + /// The entire output buffer is zeroized before the encoding is written. + fn encode_out(&self, out: &mut [u8; SK_LEN]) -> usize; + /// Read it in from bytes in its standard encoding. + fn from_bytes(bytes: &[u8]) -> Result; } /// A digital signature algorithm is defined as a set of three operations: /// key generation, signing, and verification. /// -/// To avoid the use of dyn, this trait does not include key generation; you'll have to consult the -/// documentation for the underlying signature primitive for how to generate a key pair. +/// This trait represents the operations performed by the holder of the signing private key: +/// which include signing and key generation. Verification operations are performed by the corresponding +/// [SignatureVerifier] trait. +/// There are several reasons for this split: first is architectural; some complex algorithms may +/// benefit from having the signature generation and verification implementations split into separate modules. +/// Second is for compliance: sometimes a policy soft-deprecates an algorithm so that new signatures +/// can no longer be created, but existing signatures can still be verified. Splitting the traits +/// makes this policy easier to enforce. /// /// This high-level trait defines the operations over a generic signature algorithm that is assumed /// to source all its randomness from bouncycastle's default os-backed RNG. /// The underlying signature primitives will expose APIs that allow for specifying a specific RNG /// or deterministic seed values. /// -/// Here we statically-size the arrays used to encode public keys, private keys, and signature values +/// The arrays used to encode public keys, private keys, and signature values are statically-sized /// because this allows us to safely remove runtime checks for array lengths, which overall reduces /// the fallibility of the library. This design choice could make this trait complicated to apply /// to a signature algorithm that do not have fixed sizes for the encodings of these objects. -pub trait Signature< - PK: SignaturePublicKey, - SK: SignaturePrivateKey, - const PK_LEN: usize, - const SK_LEN: usize, - const SIG_LEN: usize ->: Sized { - /// Generate a keypair. - /// Error condition: Basically only on RNG failures - fn keygen() -> Result<(PK, SK), SignatureError>; - +pub trait Signer, const SK_LEN: usize, const SIG_LEN: usize>: + Sized +{ /// Produce a signature for the provided message and context. /// Both the `msg` and `ctx` accept zero-length byte arrays. /// @@ -501,7 +560,12 @@ pub trait Signature< fn sign(sk: &SK, msg: &[u8], ctx: Option<&[u8]>) -> Result<[u8; SIG_LEN], SignatureError>; /// Returns the number of bytes written to the output buffer. Can be called with an oversized buffer. - fn sign_out(sk: &SK, msg: &[u8], ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN]) -> Result; + fn sign_out( + sk: &SK, + msg: &[u8], + ctx: Option<&[u8]>, + output: &mut [u8; SIG_LEN], + ) -> Result; /* streaming signing API */ /// Initialize a signer for streaming mode with the provided private key. @@ -517,7 +581,29 @@ pub trait Signature< /// Returns the number of bytes written to the output buffer. Can be called with an oversized buffer. fn sign_final_out(self, output: &mut [u8; SIG_LEN]) -> Result; +} +/// A digital signature algorithm is defined as a set of three operations: +/// key generation, signing, and verification. +/// +/// This trait represents the verification operations performed by the holder of the verification public key. +/// Keygen and signing operations are performed by the corresponding [Signer] trait. +/// There are several reasons for this split: first is architectural; some complex algorithms may +/// benefit from having the signature generation and verification implementations split into separate modules. +/// Second is for compliance: sometimes a policy soft-deprecates an algorithm so that new signatures +/// can no longer be created, but existing signatures can still be verified. Splitting the traits +/// makes this policy easier to enforce. +/// +/// Here we statically-size the arrays used to encode public keys, private keys, and signature values +/// because this allows us to safely remove runtime checks for array lengths, which overall reduces +/// the fallibility of the library. This design choice could make this trait complicated to apply +/// to a signature algorithm that do not have fixed sizes for the encodings of these objects. +pub trait SignatureVerifier< + PK: SignaturePublicKey, + const PK_LEN: usize, + const SIG_LEN: usize, +>: Sized +{ /// On success, returns Ok(()) /// On failure, returns Err([SignatureError::SignatureVerificationFailed]); may also return other types of [SignatureError] as appropriate (such as for invalid-length inputs). fn verify(pk: &PK, msg: &[u8], ctx: Option<&[u8]>, sig: &[u8]) -> Result<(), SignatureError>; @@ -577,7 +663,7 @@ pub trait SignaturePrivateKey : PartialEq + Eq + Clone + Se /// to break anonymity-preserving technology. /// Applications that require the arbitrary-length output of an XOF, but also care about these /// distinguishing attacks should consider adding a cryptographic salt to diversify the inputs. -pub trait XOF : Default { +pub trait XOF: Default { /// A static one-shot API that digests the input data and produces `result_len` bytes of output. fn hash_xof(self, data: &[u8], result_len: usize) -> Vec; diff --git a/crypto/mldsa/benches/mldsa_benches.rs b/crypto/mldsa/benches/mldsa_benches.rs index 9d019a4..2c44529 100644 --- a/crypto/mldsa/benches/mldsa_benches.rs +++ b/crypto/mldsa/benches/mldsa_benches.rs @@ -1,7 +1,7 @@ use criterion::{Criterion, criterion_group, criterion_main}; use bouncycastle_core::key_material::{KeyMaterial256, KeyType}; use std::hint::black_box; -use bouncycastle_core::traits::Signature; +use bouncycastle_core::traits::{SignatureVerifier, Signer}; use bouncycastle_mldsa::{MLDSA44PrivateKeyExpanded, MLDSA44PublicKeyExpanded, MLDSA65PrivateKeyExpanded, MLDSA65PublicKeyExpanded, MLDSA87PrivateKeyExpanded, MLDSA87PublicKeyExpanded, MLDSAPrivateKeyTrait, MLDSAPublicKeyTrait, MLDSATrait, MLDSA44, MLDSA44_SIG_LEN, MLDSA65, MLDSA65_SIG_LEN, MLDSA87, MLDSA87_SIG_LEN}; use bouncycastle_hex as hex; diff --git a/crypto/mldsa/src/hash_mldsa.rs b/crypto/mldsa/src/hash_mldsa.rs index 15f1464..48442aa 100644 --- a/crypto/mldsa/src/hash_mldsa.rs +++ b/crypto/mldsa/src/hash_mldsa.rs @@ -3,12 +3,12 @@ //! mode of [MLDSA]; possibly because you have to digest the message before you know which public key //! will sign it. //! -//! HashML-DSA is a full signature algorithm implementing the [Signature] trait: +//! HashML-DSA is a full signature algorithm implementing the [Signer] and [SignatureVerifier] traits: //! //! ```rust //! use bouncycastle_core::errors::SignatureError; //! use bouncycastle_mldsa::{HashMLDSA65_with_SHA512, MLDSATrait, HashMLDSA44_with_SHA512}; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! //! let msg = b"The quick brown fox jumped over the lazy dog"; //! @@ -24,12 +24,14 @@ //! } //! ``` //! -//! But you also have access to the pre-hashed function available from [PHSignature]: +//! But you also have access to the pre-hashed functions available from [PHSigner] and [PHVerifier]: //! //! ```rust //! use bouncycastle_core::errors::SignatureError; //! use bouncycastle_mldsa::{HashMLDSA65_with_SHA512, MLDSATrait, HashMLDSA44_with_SHA512}; -//! use bouncycastle_core::traits::{Signature, PHSignature, Hash}; +//! use bouncycastle_core::traits::{ +//! Hash, PHSignatureVerifier, PHSigner, SignatureVerifier, Signer, +//! }; //! use bouncycastle_sha2::SHA512; //! //! let msg = b"The quick brown fox jumped over the lazy dog"; @@ -44,14 +46,14 @@ //! let sig = HashMLDSA65_with_SHA512::sign_ph(&sk, &ph, None).unwrap(); //! // This is the signature value that you can save to a file or whatever you need. //! -//! // This verifies either through the usual one-shot API of the [Signature] trait +//! // This verifies either through the usual one-shot API of the [SignatureVerifier] trait //! match HashMLDSA65_with_SHA512::verify(&pk, msg, None, &sig) { //! Ok(()) => println!("Signature is valid!"), //! Err(SignatureError::SignatureVerificationFailed) => println!("Signature is invalid!"), //! Err(e) => panic!("Something else went wrong: {:?}", e), //! } //! -//! // Or though the verify_ph of the [PHSignature] trait +//! // Or though the verify_ph of the [PHSignatureVerifier] trait //! match HashMLDSA65_with_SHA512::verify_ph(&pk, &ph, None, &sig) { //! Ok(()) => println!("Signature is valid!"), //! Err(SignatureError::SignatureVerificationFailed) => println!("Signature is invalid!"), @@ -61,7 +63,7 @@ //! //! Note that the [HashMLDSA] object is just a light wrapper around [MLDSA], and, for example, they share key types, //! so if you need the fancy keygen functions, just use them from [MLDSA]. -//! But a simple [HashMLDSA::keygen] is provided in order to have conformance to the [Signature] trait. +//! But a simple [HashMLDSA::keygen] is provided. use crate::mldsa::{H, MLDSA_MU_LEN, MLDSA_RND_LEN, MLDSATrait}; use crate::mldsa::{ @@ -91,7 +93,8 @@ use crate::{ use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::KeyMaterial; use bouncycastle_core::traits::{ - Algorithm, Hash, PHSignature, RNG, SecurityStrength, Signature, XOF, + Algorithm, Hash, PHSignatureVerifier, PHSigner, RNG, SecurityStrength, SignatureVerifier, + Signer, XOF, }; use bouncycastle_rng::HashDRBG_SHA512; use bouncycastle_sha2::{SHA256, SHA256_NAME, SHA512, SHA512_NAME}; @@ -425,6 +428,38 @@ impl< GAMMA1_MASK_LEN, > { + /// Generate a keypair, sourcing randomness from bouncycastle's default os-backed RNG. + /// + /// Key generation is intentionally not part of the [Signer] / [SignatureVerifier] traits; + /// it is provided as an inherent associated function directly on the algorithm struct. + /// Keygen, and keys in general, are interchangeable between MLDSA and HashMLDSA. + /// Error condition: basically only on RNG failures. + pub fn keygen() -> Result<(PK, SK), SignatureError> { + MLDSA::< + PK_LEN, + SK_LEN, + SIG_LEN, + PK, + SK, + TAU, + LAMBDA, + GAMMA1, + GAMMA2, + k, + l, + ETA, + BETA, + OMEGA, + C_TILDE, + POLY_Z_PACKED_LEN, + POLY_W1_PACKED_LEN, + LAMBDA_over_4, + GAMMA1_MINUS_BETA, + GAMMA2_MINUS_BETA, + GAMMA1_MASK_LEN, + >::keygen() + } + /// Imports a secret key from a seed. pub fn keygen_from_seed(seed: &KeyMaterial<32>) -> Result<(PK, SK), SignatureError> { MLDSA::< @@ -451,7 +486,7 @@ impl< GAMMA1_MASK_LEN, >::keygen_internal(seed) } - /// Same as [Signature::sign], but signs from an [MLDSAPrivateKeyExpanded]. + /// Same as [Signer::sign], but signs from an [MLDSAPrivateKeyExpanded]. pub fn sign_with_expanded_key( sk: &MLDSAPrivateKeyExpanded, msg: &[u8], @@ -462,7 +497,7 @@ impl< Ok(out) } - /// Same as [Signature::sign_out], but signs from an [MLDSAPrivateKeyExpanded]. + /// Same as [Signer::sign_out], but signs from an [MLDSAPrivateKeyExpanded]. pub fn sign_with_expanded_key_out( sk: &MLDSAPrivateKeyExpanded, msg: &[u8], @@ -473,7 +508,7 @@ impl< _ = HASH::default().hash_out(msg, &mut ph_m); Self::sign_ph_with_expanded_key_out(sk, &ph_m, ctx, output) } - /// Same as [PHSignature::sign_ph], but signs from an [MLDSAPrivateKeyExpanded]. + /// Same as [PHSigner::sign_ph], but signs from an [MLDSAPrivateKeyExpanded]. pub fn sign_ph_with_expanded_key( sk: &MLDSAPrivateKeyExpanded, ph: &[u8; PH_LEN], @@ -484,7 +519,7 @@ impl< Ok(out) } - /// Same as [PHSignature::sign_ph_out], but signs from an [MLDSAPrivateKeyExpanded]. + /// Same as [PHSigner::sign_ph_out], but signs from an [MLDSAPrivateKeyExpanded]. pub fn sign_ph_with_expanded_key_out( sk: &MLDSAPrivateKeyExpanded, ph: &[u8; PH_LEN], @@ -609,9 +644,9 @@ impl< Ok(bytes_written) } - /// To be used for deterministic signing in conjunction with the [Signature::sign_init], - /// [Signature::sign_update], and [Signature::sign_final] flow. - /// Can be set anywhere after [Signature::sign_init] and before [Signature::sign_final] + /// To be used for deterministic signing in conjunction with the [Signer::sign_init], + /// [Signer::sign_update], and [Signer::sign_final] flow. + /// Can be set anywhere after [Signer::sign_init] and before [Signer::sign_final] pub fn set_signer_rnd(&mut self, rnd: [u8; 32]) { self.signer_rnd = Some(rnd); } @@ -650,7 +685,7 @@ impl< ctx_len, }) } - /// Same as [Signature::verify], but verifies from an [MLDSAPublicKeyExpanded]. + /// Same as [SignatureVerifier::verify], but verifies from an [MLDSAPublicKeyExpanded]. pub fn verify_with_expanded_key( pk: &MLDSAPublicKeyExpanded, msg: &[u8], @@ -804,7 +839,7 @@ impl< const GAMMA1_MINUS_BETA: i32, const GAMMA2_MINUS_BETA: i32, const GAMMA1_MASK_LEN: usize, -> Signature +> Signer for HashMLDSA< HASH, PH_LEN, @@ -831,33 +866,6 @@ impl< GAMMA1_MASK_LEN, > { - /// Keygen, and keys in general, are interchangeable between MLDSA and HashMLDSA. - fn keygen() -> Result<(PK, SK), SignatureError> { - MLDSA::< - PK_LEN, - SK_LEN, - SIG_LEN, - PK, - SK, - TAU, - LAMBDA, - GAMMA1, - GAMMA2, - k, - l, - ETA, - BETA, - OMEGA, - C_TILDE, - POLY_Z_PACKED_LEN, - POLY_W1_PACKED_LEN, - LAMBDA_over_4, - GAMMA1_MINUS_BETA, - GAMMA2_MINUS_BETA, - GAMMA1_MASK_LEN, - >::keygen() - } - /// Algorithm 4 HashML-DSA.Sign(π‘ π‘˜, 𝑀 , 𝑐𝑑π‘₯, PH) /// Generate a β€œpre-hash” ML-DSA signature. fn sign(sk: &SK, msg: &[u8], ctx: Option<&[u8]>) -> Result<[u8; SIG_LEN], SignatureError> { @@ -947,7 +955,62 @@ impl< unreachable!() } } +} +impl< + HASH: Hash + Default, + PK: MLDSAPublicKeyTrait + MLDSAPublicKeyInternalTrait, + SK: MLDSAPrivateKeyTrait + + MLDSAPrivateKeyInternalTrait, + const PH_LEN: usize, + const oid: &'static [u8], + const PK_LEN: usize, + const SK_LEN: usize, + const SIG_LEN: usize, + const TAU: i32, + const LAMBDA: i32, + const GAMMA1: i32, + const GAMMA2: i32, + const k: usize, + const l: usize, + const ETA: usize, + const BETA: i32, + const OMEGA: i32, + const C_TILDE: usize, + const POLY_Z_PACKED_LEN: usize, + const POLY_W1_PACKED_LEN: usize, + const LAMBDA_over_4: usize, + const GAMMA1_MINUS_BETA: i32, + const GAMMA2_MINUS_BETA: i32, + const GAMMA1_MASK_LEN: usize, +> SignatureVerifier + for HashMLDSA< + HASH, + PH_LEN, + oid, + PK_LEN, + SK_LEN, + SIG_LEN, + PK, + SK, + TAU, + LAMBDA, + GAMMA1, + GAMMA2, + k, + l, + ETA, + BETA, + OMEGA, + C_TILDE, + POLY_Z_PACKED_LEN, + POLY_W1_PACKED_LEN, + LAMBDA_over_4, + GAMMA1_MINUS_BETA, + GAMMA2_MINUS_BETA, + GAMMA1_MASK_LEN, + > +{ fn verify(pk: &PK, msg: &[u8], ctx: Option<&[u8]>, sig: &[u8]) -> Result<(), SignatureError> { let mut ph_m = [0u8; PH_LEN]; _ = HASH::default().hash_out(msg, &mut ph_m); @@ -1008,7 +1071,7 @@ impl< const GAMMA1_MASK_LEN: usize, const GAMMA1_MINUS_BETA: i32, const GAMMA2_MINUS_BETA: i32, -> PHSignature +> PHSigner for HashMLDSA< HASH, PH_LEN, @@ -1060,7 +1123,62 @@ impl< HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?; Self::sign_ph_deterministic_out(sk, None, ctx, ph, rnd, output) } +} +impl< + HASH: Hash + Default, + const PH_LEN: usize, + const oid: &'static [u8], + const PK_LEN: usize, + const SK_LEN: usize, + const SIG_LEN: usize, + PK: MLDSAPublicKeyTrait + MLDSAPublicKeyInternalTrait, + SK: MLDSAPrivateKeyTrait + + MLDSAPrivateKeyInternalTrait, + const TAU: i32, + const LAMBDA: i32, + const GAMMA1: i32, + const GAMMA2: i32, + const k: usize, + const l: usize, + const ETA: usize, + const BETA: i32, + const OMEGA: i32, + const C_TILDE: usize, + const POLY_Z_PACKED_LEN: usize, + const POLY_W1_PACKED_LEN: usize, + const LAMBDA_over_4: usize, + const GAMMA1_MASK_LEN: usize, + const GAMMA1_MINUS_BETA: i32, + const GAMMA2_MINUS_BETA: i32, +> PHSignatureVerifier + for HashMLDSA< + HASH, + PH_LEN, + oid, + PK_LEN, + SK_LEN, + SIG_LEN, + PK, + SK, + TAU, + LAMBDA, + GAMMA1, + GAMMA2, + k, + l, + ETA, + BETA, + OMEGA, + C_TILDE, + POLY_Z_PACKED_LEN, + POLY_W1_PACKED_LEN, + LAMBDA_over_4, + GAMMA1_MINUS_BETA, + GAMMA2_MINUS_BETA, + GAMMA1_MASK_LEN, + > +{ fn verify_ph( pk: &PK, ph: &[u8; PH_LEN], diff --git a/crypto/mldsa/src/lib.rs b/crypto/mldsa/src/lib.rs index 9c3a2b8..c304171 100644 --- a/crypto/mldsa/src/lib.rs +++ b/crypto/mldsa/src/lib.rs @@ -15,7 +15,6 @@ //! //! ```rust //! use bouncycastle_mldsa::MLDSA65; -//! use bouncycastle_core::traits::Signature; //! //! let (pk, sk) = MLDSA65::keygen().unwrap(); //! ``` @@ -39,13 +38,13 @@ //! //! See [MLDSATrait] and [MLDSATrait::sign_mu_deterministic_from_seed] for an API flow that uses a merged //! keygen-and-sign function to provide improved speed and memory performance compared with making -//! separate calls to [MLDSATrait::keygen_from_seed] followed by [Signature::sign]. +//! separate calls to [MLDSATrait::keygen_from_seed] followed by [Signer::sign]. //! //! ## Generating and Verifying Signatures //! //! ```rust //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait}; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_core::errors::SignatureError; //! //! let msg = b"The quick brown fox"; @@ -133,7 +132,7 @@ #[allow(unused_imports)] use bouncycastle_core::key_material::KeyMaterialTrait; #[allow(unused_imports)] -use bouncycastle_core::traits::Signature; +use bouncycastle_core::traits::{SignatureVerifier, Signer}; // todo -- crucible tests diff --git a/crypto/mldsa/src/mldsa.rs b/crypto/mldsa/src/mldsa.rs index d207f01..6fe2001 100644 --- a/crypto/mldsa/src/mldsa.rs +++ b/crypto/mldsa/src/mldsa.rs @@ -9,7 +9,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let (pk, sk) = MLDSA65::keygen().unwrap(); @@ -51,7 +51,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let (pk, sk) = MLDSA65::keygen().unwrap(); @@ -98,7 +98,7 @@ //! ```rust //! use bouncycastle_core::errors::SignatureError; //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! //! let (pk, _) = MLDSA65::keygen().unwrap(); //! @@ -116,7 +116,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let (pk, _) = MLDSA65::keygen().unwrap(); @@ -136,7 +136,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let msg = b"The quick brown fox jumped over the lazy dog"; @@ -182,7 +182,7 @@ //! ```rust //! use bouncycastle_core::errors::SignatureError; //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait}; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! //! let msg = b"The quick brown fox"; //! let ctx = b"FooTextDocumentFormat"; @@ -220,7 +220,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let msg = b"The quick brown fox jumped over the lazy dog"; @@ -258,7 +258,7 @@ //! ```rust //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait}; //! use bouncycastle_mldsa::{MLDSA65PublicKeyExpanded, MLDSA65PrivateKeyExpanded}; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_core::errors::SignatureError; //! //! let msg = b"The quick brown fox"; @@ -303,7 +303,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_core::key_material::{KeyMaterial256, KeyType, KeyMaterialTrait}; //! use bouncycastle_hex as hex; //! use bouncycastle_mldsa::{MLDSA44, MLDSA44_SIG_LEN, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; @@ -375,7 +375,7 @@ //! ```rust //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait}; //! use bouncycastle_mldsa::{MLDSA65PublicKeyExpanded, MLDSA65PrivateKeyExpanded}; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_core::errors::SignatureError; //! //! let msg = b"The quick brown fox jumped over the lazy dog"; @@ -412,7 +412,7 @@ use crate::{ }; use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial, KeyMaterial256, KeyMaterialTrait, KeyType}; -use bouncycastle_core::traits::{Algorithm, RNG, SecurityStrength, Signature, XOF}; +use bouncycastle_core::traits::{Algorithm, RNG, SecurityStrength, SignatureVerifier, Signer, XOF}; use bouncycastle_rng::HashDRBG_SHA512; use bouncycastle_sha3::{SHAKE128, SHAKE256}; use core::marker::PhantomData; @@ -421,7 +421,7 @@ use core::marker::PhantomData; #[allow(unused_imports)] use crate::hash_mldsa; #[allow(unused_imports)] -use bouncycastle_core::traits::PHSignature; +use bouncycastle_core::traits::{PHSignatureVerifier, PHSigner}; /*** Constants ***/ @@ -728,6 +728,15 @@ impl< GAMMA1_MASK_LEN, > { + /// Generate a keypair, sourcing randomness from bouncycastle's default os-backed RNG. + /// + /// Key generation is intentionally not part of the [Signer] / [SignatureVerifier] traits; + /// it is provided as an inherent associated function directly on the algorithm struct. + /// Error condition: basically only on RNG failures. + pub fn keygen() -> Result<(PK, SK), SignatureError> { + Self::keygen_from_os_rng() + } + /// Should still be ok in FIPS mode pub fn keygen_from_os_rng() -> Result<(PK, SK), SignatureError> { let mut seed = KeyMaterial256::new(); @@ -1712,7 +1721,7 @@ pub trait MLDSATrait< msg: &[u8], ctx: Option<&[u8]>, ) -> Result<[u8; 64], SignatureError>; - /// Same as [Signature::sign], but signs from an [MLDSAPrivateKeyExpanded]. + /// Same as [Signer::sign], but signs from an [MLDSAPrivateKeyExpanded]. fn sign_with_expanded_key( sk: &MLDSAPrivateKeyExpanded, msg: &[u8], @@ -1750,13 +1759,13 @@ pub trait MLDSATrait< mu: &[u8; 64], output: &mut [u8; SIG_LEN], ) -> Result; - /// Same as [Signature::sign_mu], but signs from an [MLDSAPrivateKeyExpanded]. + /// Same as [MLDSATrait::sign_mu], but signs from an [MLDSAPrivateKeyExpanded]. fn sign_mu_with_expanded_key( sk: &MLDSAPrivateKeyExpanded, A_hat: Option<&Matrix>, mu: &[u8; 64], ) -> Result<[u8; SIG_LEN], SignatureError>; - /// Same as [Signature::sign_mu_out], but signs from an [MLDSAPrivateKeyExpanded]. + /// Same as [MLDSATrait::sign_mu_out], but signs from an [MLDSAPrivateKeyExpanded]. fn sign_mu_with_expanded_key_out( sk: &MLDSAPrivateKeyExpanded, A_hat: Option<&Matrix>, @@ -1846,7 +1855,7 @@ pub trait MLDSATrait< seed: &KeyMaterial<32>, ctx: Option<&[u8]>, ) -> Result; - /// Same as [Signature::verify], but signs from an expanded key object. + /// Same as [SignatureVerifier::verify], but signs from an expanded key object. fn verify_with_expanded_key( pk: &MLDSAPublicKeyExpanded, msg: &[u8], @@ -1888,7 +1897,7 @@ impl< const GAMMA1_MINUS_BETA: i32, const GAMMA2_MINUS_BETA: i32, const GAMMA1_MASK_LEN: usize, -> Signature +> Signer for MLDSA< PK_LEN, SK_LEN, @@ -1913,10 +1922,6 @@ impl< GAMMA1_MASK_LEN, > { - fn keygen() -> Result<(PK, SK), SignatureError> { - Self::keygen_from_os_rng() - } - fn sign(sk: &SK, msg: &[u8], ctx: Option<&[u8]>) -> Result<[u8; SIG_LEN], SignatureError> { let mut out = [0u8; SIG_LEN]; Self::sign_out(sk, msg, ctx, &mut out)?; @@ -1991,7 +1996,56 @@ impl< unreachable!() } } +} +impl< + const PK_LEN: usize, + const SK_LEN: usize, + const SIG_LEN: usize, + PK: MLDSAPublicKeyTrait + MLDSAPublicKeyInternalTrait, + SK: MLDSAPrivateKeyTrait + + MLDSAPrivateKeyInternalTrait, + const TAU: i32, + const LAMBDA: i32, + const GAMMA1: i32, + const GAMMA2: i32, + const k: usize, + const l: usize, + const ETA: usize, + const BETA: i32, + const OMEGA: i32, + const C_TILDE: usize, + const POLY_Z_PACKED_LEN: usize, + const POLY_W1_PACKED_LEN: usize, + const LAMBDA_over_4: usize, + const GAMMA1_MINUS_BETA: i32, + const GAMMA2_MINUS_BETA: i32, + const GAMMA1_MASK_LEN: usize, +> SignatureVerifier + for MLDSA< + PK_LEN, + SK_LEN, + SIG_LEN, + PK, + SK, + TAU, + LAMBDA, + GAMMA1, + GAMMA2, + k, + l, + ETA, + BETA, + OMEGA, + C_TILDE, + POLY_Z_PACKED_LEN, + POLY_W1_PACKED_LEN, + LAMBDA_over_4, + GAMMA1_MINUS_BETA, + GAMMA2_MINUS_BETA, + GAMMA1_MASK_LEN, + > +{ fn verify(pk: &PK, msg: &[u8], ctx: Option<&[u8]>, sig: &[u8]) -> Result<(), SignatureError> { let mu = MuBuilder::compute_mu(&pk.compute_tr(), msg, ctx)?; @@ -2048,7 +2102,7 @@ impl< /// Note: this struct is only exposed for "pure" ML-DSA and not for HashML-DSA because HashML-DSA /// does not benefit from allowing external construction of the message representative mu. /// You can get the same behaviour by computing the pre-hash `ph` with the appropriate hash function -/// and providing that to HashMLDSA via [PHSignature::sign_ph]. +/// and providing that to HashMLDSA via [PHSigner::sign_ph]. pub struct MuBuilder { h: H, } diff --git a/crypto/mldsa/tests/bc_test_data.rs b/crypto/mldsa/tests/bc_test_data.rs index 77ae858..a732489 100644 --- a/crypto/mldsa/tests/bc_test_data.rs +++ b/crypto/mldsa/tests/bc_test_data.rs @@ -14,7 +14,7 @@ mod bc_test_data { use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyMaterialTrait, KeyType}; use bouncycastle_core::traits::{ - Hash, SecurityStrength, Signature, SignaturePrivateKey, SignaturePublicKey, + Hash, SecurityStrength, SignaturePrivateKey, SignaturePublicKey, SignatureVerifier, }; use bouncycastle_hex as hex; use bouncycastle_mldsa::{ diff --git a/crypto/mldsa/tests/hash_mldsa_tests.rs b/crypto/mldsa/tests/hash_mldsa_tests.rs index 4301d7b..ecdfb7c 100644 --- a/crypto/mldsa/tests/hash_mldsa_tests.rs +++ b/crypto/mldsa/tests/hash_mldsa_tests.rs @@ -2,7 +2,9 @@ mod hash_mldsa_tests { use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyType}; - use bouncycastle_core::traits::{Hash, PHSignature, Signature}; + use bouncycastle_core::traits::{ + Hash, PHSignatureVerifier, PHSigner, SignatureVerifier, Signer, + }; use bouncycastle_core_test_framework::signature::TestFrameworkSignature; use bouncycastle_hex as hex; use bouncycastle_mldsa::{ @@ -21,19 +23,19 @@ mod hash_mldsa_tests { let tf = TestFrameworkSignature::new(false, true); // Test HashML-DSA-SHA512 as a regular signature alg - tf.test_signature::(false); - tf.test_signature::(false); - tf.test_signature::(false); + tf.test_signature::(HashMLDSA44_with_SHA512::keygen, false); + tf.test_signature::(HashMLDSA65_with_SHA512::keygen, false); + tf.test_signature::(HashMLDSA87_with_SHA512::keygen, false); // Test HashML-DSA-SHA256 as a ph signature alg - tf.test_ph_signature::(false); - tf.test_ph_signature::(false); - tf.test_ph_signature::(false); + tf.test_ph_signature::(HashMLDSA44_with_SHA256::keygen, false); + tf.test_ph_signature::(HashMLDSA65_with_SHA256::keygen, false); + tf.test_ph_signature::(HashMLDSA87_with_SHA256::keygen, false); // Test HashML-DSA-SHA512 as a ph signature alg - tf.test_ph_signature::(false); - tf.test_ph_signature::(false); - tf.test_ph_signature::(false); + tf.test_ph_signature::(HashMLDSA44_with_SHA512::keygen, false); + tf.test_ph_signature::(HashMLDSA65_with_SHA512::keygen, false); + tf.test_ph_signature::(HashMLDSA87_with_SHA512::keygen, false); } #[test] diff --git a/crypto/mldsa/tests/mldsa_key_tests.rs b/crypto/mldsa/tests/mldsa_key_tests.rs index c2451a0..476a5b6 100644 --- a/crypto/mldsa/tests/mldsa_key_tests.rs +++ b/crypto/mldsa/tests/mldsa_key_tests.rs @@ -3,7 +3,7 @@ mod mldsa_key_tests { use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyMaterialTrait, KeyType}; use bouncycastle_core::traits::{ - SecurityStrength, Signature, SignaturePrivateKey, SignaturePublicKey, + SecurityStrength, SignaturePrivateKey, SignaturePublicKey, }; use bouncycastle_core_test_framework::signature::TestFrameworkSignatureKeys; use bouncycastle_hex as hex; @@ -15,17 +15,17 @@ mod mldsa_key_tests { MLDSAPrivateKeyTrait, MLDSATrait, }; use bouncycastle_mldsa::{ - MLDSA44_PK_LEN, MLDSA44_SIG_LEN, MLDSA44_SK_LEN, MLDSA65_PK_LEN, MLDSA65_SIG_LEN, - MLDSA65_SK_LEN, MLDSA87_PK_LEN, MLDSA87_SIG_LEN, MLDSA87_SK_LEN, + MLDSA44_PK_LEN, MLDSA44_SK_LEN, MLDSA65_PK_LEN, MLDSA65_SK_LEN, MLDSA87_PK_LEN, + MLDSA87_SK_LEN, }; #[test] fn core_framework_tests() { let tf = TestFrameworkSignatureKeys::new(); - tf.test_keys::(); - tf.test_keys::(); - tf.test_keys::(); + tf.test_keys::(MLDSA44::keygen); + tf.test_keys::(MLDSA65::keygen); + tf.test_keys::(MLDSA87::keygen); } #[test] diff --git a/crypto/mldsa/tests/mldsa_tests.rs b/crypto/mldsa/tests/mldsa_tests.rs index b5a1b5f..b87a0a8 100644 --- a/crypto/mldsa/tests/mldsa_tests.rs +++ b/crypto/mldsa/tests/mldsa_tests.rs @@ -5,7 +5,7 @@ mod mldsa_tests { use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyMaterialTrait, KeyType}; use bouncycastle_core::traits::{ - RNG, SecurityStrength, Signature, SignaturePrivateKey, SignaturePublicKey, + RNG, SecurityStrength, SignaturePrivateKey, SignaturePublicKey, SignatureVerifier, Signer, }; use bouncycastle_core_test_framework::DUMMY_SEED_1024; use bouncycastle_core_test_framework::signature::*; @@ -44,9 +44,9 @@ mod mldsa_tests { fn test_framework_signature() { let tf = TestFrameworkSignature::new(false, true); - tf.test_signature::(false); - tf.test_signature::(false); - tf.test_signature::(false); + tf.test_signature::(MLDSA44::keygen, false); + tf.test_signature::(MLDSA65::keygen, false); + tf.test_signature::(MLDSA87::keygen, false); } /// This runs the full bitflipping tests and takes several minutes. diff --git a/crypto/mldsa/tests/wycheproof.rs b/crypto/mldsa/tests/wycheproof.rs index bc7fd34..abe6842 100644 --- a/crypto/mldsa/tests/wycheproof.rs +++ b/crypto/mldsa/tests/wycheproof.rs @@ -20,7 +20,7 @@ use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyMaterialTrait, KeyType}; use bouncycastle_core::traits::{ - SecurityStrength, Signature, SignaturePrivateKey, SignaturePublicKey, + SecurityStrength, SignaturePrivateKey, SignaturePublicKey, SignatureVerifier, }; use bouncycastle_hex as hex; use bouncycastle_mldsa::{ diff --git a/crypto/mldsa_lowmemory/benches/mldsa_benches.rs b/crypto/mldsa_lowmemory/benches/mldsa_benches.rs index 79ffd00..c6eb407 100644 --- a/crypto/mldsa_lowmemory/benches/mldsa_benches.rs +++ b/crypto/mldsa_lowmemory/benches/mldsa_benches.rs @@ -1,7 +1,7 @@ use criterion::{Criterion, criterion_group, criterion_main}; use bouncycastle_core::key_material::{KeyMaterial256, KeyType}; use std::hint::black_box; -use bouncycastle_core::traits::Signature; +use bouncycastle_core::traits::{SignatureVerifier, Signer}; use bouncycastle_mldsa_lowmemory::{MLDSATrait, MLDSA44, MLDSA44_SIG_LEN, MLDSA65, MLDSA65_SIG_LEN, MLDSA87, MLDSA87_SIG_LEN}; use bouncycastle_hex as hex; diff --git a/crypto/mldsa_lowmemory/src/hash_mldsa.rs b/crypto/mldsa_lowmemory/src/hash_mldsa.rs index 33b9176..27cbf7e 100644 --- a/crypto/mldsa_lowmemory/src/hash_mldsa.rs +++ b/crypto/mldsa_lowmemory/src/hash_mldsa.rs @@ -3,11 +3,11 @@ //! mode of [MLDSA]; possibly because you have to digest the message before you know which public key //! will sign it. //! -//! HashML-DSA is a full signature algorithm implementing the [Signature] trait: +//! HashML-DSA is a full signature algorithm implementing the [Signer] and [SignatureVerifier] traits: //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSATrait, HashMLDSA65_with_SHA512, HashMLDSA44_with_SHA512}; //! //! let msg = b"The quick brown fox jumped over the lazy dog"; @@ -24,11 +24,13 @@ //! } //! ``` //! -//! But you also have access to the pre-hashed function available from [PHSignature]: +//! But you also have access to the pre-hashed function available from [PHSigner] and [PHSignatureVerifier]: //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::{Signature, PHSignature, Hash}; +//! use bouncycastle_core::traits::{ +//! Hash, PHSignatureVerifier, PHSigner, SignatureVerifier, Signer, +//! }; //! use bouncycastle_sha2::SHA512; //! use bouncycastle_mldsa_lowmemory::{MLDSATrait, HashMLDSA65_with_SHA512, HashMLDSA44_with_SHA512}; //! @@ -44,14 +46,14 @@ //! let sig = HashMLDSA65_with_SHA512::sign_ph(&sk, &ph, None).unwrap(); //! // This is the signature value that you can save to a file or whatever you need. //! -//! // This verifies either through the usual one-shot API of the [Signature] trait +//! // This verifies either through the usual one-shot API of the [SignatureVerifier] trait //! match HashMLDSA65_with_SHA512::verify(&pk, msg, None, &sig) { //! Ok(()) => println!("Signature is valid!"), //! Err(SignatureError::SignatureVerificationFailed) => println!("Signature is invalid!"), //! Err(e) => panic!("Something else went wrong: {:?}", e), //! } //! -//! // Or though the verify_ph of the [PHSignature] trait +//! // Or though the verify_ph of the [PHSignatureVerifier] trait //! match HashMLDSA65_with_SHA512::verify_ph(&pk, &ph, None, &sig) { //! Ok(()) => println!("Signature is valid!"), //! Err(SignatureError::SignatureVerificationFailed) => println!("Signature is invalid!"), @@ -61,27 +63,30 @@ //! //! Note that the [HashMLDSA] object is just a light wrapper around [MLDSA], and, for example, they share key types, //! so if you need the fancy keygen functions, just use them from [MLDSA]. -//! But a simple [HashMLDSA::keygen] is provided in order to have conformance to the [Signature] trait. +//! But a simple [HashMLDSA::keygen] is provided. use crate::mldsa::{H, MLDSA_MU_LEN, MLDSA_RND_LEN, MLDSATrait}; use crate::mldsa::{ - MLDSA44_BETA, MLDSA44_C_TILDE, MLDSA44_ETA, MLDSA44_GAMMA1, MLDSA44_GAMMA1_MINUS_BETA, MLDSA44_GAMMA2_MINUS_BETA, MLDSA44_GAMMA1_MASK_LEN, - MLDSA44_GAMMA2, MLDSA44_LAMBDA, MLDSA44_LAMBDA_over_4, MLDSA44_OMEGA, MLDSA44_PK_LEN, - MLDSA44_POLY_W1_PACKED_LEN, MLDSA44_POLY_Z_PACKED_LEN, - MLDSA44_SIG_LEN, MLDSA44_SK_LEN, MLDSA44_FULL_SK_LEN, MLDSA44_TAU, MLDSA44_S1_PACKED_LEN, MLDSA44_S2_PACKED_LEN, MLDSA44_k, MLDSA44_l, + MLDSA44_BETA, MLDSA44_C_TILDE, MLDSA44_ETA, MLDSA44_FULL_SK_LEN, MLDSA44_GAMMA1, + MLDSA44_GAMMA1_MASK_LEN, MLDSA44_GAMMA1_MINUS_BETA, MLDSA44_GAMMA2, MLDSA44_GAMMA2_MINUS_BETA, + MLDSA44_LAMBDA, MLDSA44_LAMBDA_over_4, MLDSA44_OMEGA, MLDSA44_PK_LEN, + MLDSA44_POLY_W1_PACKED_LEN, MLDSA44_POLY_Z_PACKED_LEN, MLDSA44_S1_PACKED_LEN, + MLDSA44_S2_PACKED_LEN, MLDSA44_SIG_LEN, MLDSA44_SK_LEN, MLDSA44_TAU, MLDSA44_k, MLDSA44_l, }; use crate::mldsa::{MLDSA44_T1_PACKED_LEN, MLDSA65_T1_PACKED_LEN, MLDSA87_T1_PACKED_LEN}; use crate::mldsa::{ - MLDSA65_BETA, MLDSA65_C_TILDE, MLDSA65_ETA, MLDSA65_GAMMA1, MLDSA65_GAMMA1_MINUS_BETA, MLDSA65_GAMMA2_MINUS_BETA, MLDSA65_GAMMA1_MASK_LEN, - MLDSA65_GAMMA2, MLDSA65_LAMBDA, MLDSA65_LAMBDA_over_4, MLDSA65_OMEGA, MLDSA65_PK_LEN, - MLDSA65_POLY_W1_PACKED_LEN, MLDSA65_POLY_Z_PACKED_LEN, - MLDSA65_SIG_LEN, MLDSA65_SK_LEN, MLDSA65_FULL_SK_LEN, MLDSA65_TAU, MLDSA65_S1_PACKED_LEN, MLDSA65_S2_PACKED_LEN, MLDSA65_k, MLDSA65_l, + MLDSA65_BETA, MLDSA65_C_TILDE, MLDSA65_ETA, MLDSA65_FULL_SK_LEN, MLDSA65_GAMMA1, + MLDSA65_GAMMA1_MASK_LEN, MLDSA65_GAMMA1_MINUS_BETA, MLDSA65_GAMMA2, MLDSA65_GAMMA2_MINUS_BETA, + MLDSA65_LAMBDA, MLDSA65_LAMBDA_over_4, MLDSA65_OMEGA, MLDSA65_PK_LEN, + MLDSA65_POLY_W1_PACKED_LEN, MLDSA65_POLY_Z_PACKED_LEN, MLDSA65_S1_PACKED_LEN, + MLDSA65_S2_PACKED_LEN, MLDSA65_SIG_LEN, MLDSA65_SK_LEN, MLDSA65_TAU, MLDSA65_k, MLDSA65_l, }; use crate::mldsa::{ - MLDSA87_BETA, MLDSA87_C_TILDE, MLDSA87_ETA, MLDSA87_GAMMA1, MLDSA87_GAMMA1_MINUS_BETA, MLDSA87_GAMMA2_MINUS_BETA, MLDSA87_GAMMA1_MASK_LEN, - MLDSA87_GAMMA2, MLDSA87_LAMBDA, MLDSA87_LAMBDA_over_4, MLDSA87_OMEGA, MLDSA87_PK_LEN, - MLDSA87_POLY_W1_PACKED_LEN, MLDSA87_POLY_Z_PACKED_LEN, - MLDSA87_SIG_LEN, MLDSA87_SK_LEN, MLDSA87_FULL_SK_LEN, MLDSA87_TAU, MLDSA87_S1_PACKED_LEN, MLDSA87_S2_PACKED_LEN, MLDSA87_k, MLDSA87_l, + MLDSA87_BETA, MLDSA87_C_TILDE, MLDSA87_ETA, MLDSA87_FULL_SK_LEN, MLDSA87_GAMMA1, + MLDSA87_GAMMA1_MASK_LEN, MLDSA87_GAMMA1_MINUS_BETA, MLDSA87_GAMMA2, MLDSA87_GAMMA2_MINUS_BETA, + MLDSA87_LAMBDA, MLDSA87_LAMBDA_over_4, MLDSA87_OMEGA, MLDSA87_PK_LEN, + MLDSA87_POLY_W1_PACKED_LEN, MLDSA87_POLY_Z_PACKED_LEN, MLDSA87_S1_PACKED_LEN, + MLDSA87_S2_PACKED_LEN, MLDSA87_SIG_LEN, MLDSA87_SK_LEN, MLDSA87_TAU, MLDSA87_k, MLDSA87_l, }; use crate::mldsa_keys::{MLDSAPrivateKeyInternalTrait, MLDSAPublicKeyInternalTrait}; use crate::{ @@ -91,7 +96,8 @@ use crate::{ use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::KeyMaterial; use bouncycastle_core::traits::{ - Algorithm, Hash, PHSignature, RNG, SecurityStrength, Signature, XOF, + Algorithm, Hash, PHSignatureVerifier, PHSigner, RNG, SecurityStrength, SignatureVerifier, + Signer, XOF, }; use bouncycastle_rng::HashDRBG_SHA512; use bouncycastle_sha2::{SHA256, SHA512}; @@ -508,6 +514,42 @@ impl< GAMMA1_MASK_LEN, > { + /// Generate a keypair, sourcing randomness from bouncycastle's default os-backed RNG. + /// + /// Key generation is intentionally not part of the [Signer] / [SignatureVerifier] traits; + /// it is provided as an inherent associated function directly on the algorithm struct. + /// Keys are interchangeable between MLDSA and HashMLDSA. + /// Error condition: basically only on RNG failures. + pub fn keygen() -> Result<(PK, SK), SignatureError> { + MLDSA::< + PK_LEN, + SK_LEN, + FULL_SK_LEN, + SIG_LEN, + PK, + SK, + TAU, + LAMBDA, + GAMMA1, + GAMMA2, + k, + l, + ETA, + BETA, + OMEGA, + C_TILDE, + POLY_Z_PACKED_LEN, + POLY_W1_PACKED_LEN, + S1_PACKED_LEN, + S2_PACKED_LEN, + T1_PACKED_LEN, + LAMBDA_over_4, + GAMMA1_MINUS_BETA, + GAMMA2_MINUS_BETA, + GAMMA1_MASK_LEN, + >::keygen() + } + /// Imports a secret key from a seed. pub fn keygen_from_seed(seed: &KeyMaterial<32>) -> Result<(PK, SK), SignatureError> { MLDSA::< @@ -639,9 +681,9 @@ impl< Ok(bytes_written) } - /// To be used for deterministic signing in conjunction with the [Signature::sign_init], - /// [Signature::sign_update], and [Signature::sign_final] flow. - /// Can be set anywhere after [Signature::sign_init] and before [Signature::sign_final] + /// To be used for deterministic signing in conjunction with the [Signer::sign_init], + /// [Signer::sign_update], and [Signer::sign_final] flow. + /// Can be set anywhere after [Signer::sign_init] and before [Signer::sign_final] pub fn set_signer_rnd(&mut self, rnd: [u8; 32]) { self.signer_rnd = Some(rnd); } @@ -731,7 +773,7 @@ impl< const GAMMA1_MINUS_BETA: i32, const GAMMA2_MINUS_BETA: i32, const GAMMA1_MASK_LEN: usize, -> Signature +> Signer for HashMLDSA< HASH, PH_LEN, @@ -763,37 +805,6 @@ impl< GAMMA1_MASK_LEN, > { - /// Keygen, and keys in general, are interchangeable between MLDSA and HashMLDSA. - fn keygen() -> Result<(PK, SK), SignatureError> { - MLDSA::< - PK_LEN, - SK_LEN, - FULL_SK_LEN, - SIG_LEN, - PK, - SK, - TAU, - LAMBDA, - GAMMA1, - GAMMA2, - k, - l, - ETA, - BETA, - OMEGA, - C_TILDE, - POLY_Z_PACKED_LEN, - POLY_W1_PACKED_LEN, - S1_PACKED_LEN, - S2_PACKED_LEN, - T1_PACKED_LEN, - LAMBDA_over_4, - GAMMA1_MINUS_BETA, - GAMMA2_MINUS_BETA, - GAMMA1_MASK_LEN, - >::keygen() - } - /// Algorithm 4 HashML-DSA.Sign(π‘ π‘˜, 𝑀 , 𝑐𝑑π‘₯, PH) /// Generate a β€œpre-hash” ML-DSA signature. fn sign(sk: &SK, msg: &[u8], ctx: Option<&[u8]>) -> Result<[u8; SIG_LEN], SignatureError> { @@ -849,12 +860,7 @@ impl< if self.sk.is_some() { if self.signer_rnd.is_none() { - Self::sign_ph_out( - &self.sk.unwrap(), - &ph, - Some(&self.ctx[..self.ctx_len]), - output, - ) + Self::sign_ph_out(&self.sk.unwrap(), &ph, Some(&self.ctx[..self.ctx_len]), output) } else { Self::sign_ph_deterministic_out( &self.sk.unwrap(), @@ -875,18 +881,94 @@ impl< // since at this point we need to fully reconstruct SK in order to compute tr for mu anyway // there is no savings to using the fancy MLDSA::sign_from_seed let (_pk, sk) = Self::keygen_from_seed(&self.seed.unwrap())?; - Self::sign_ph_deterministic_out( - &sk, - Some(&self.ctx[..self.ctx_len]), - &ph, - rnd, - output, - ) + Self::sign_ph_deterministic_out(&sk, Some(&self.ctx[..self.ctx_len]), &ph, rnd, output) } else { unreachable!() } } +} +impl< + HASH: Hash + Default, + PK: MLDSAPublicKeyTrait + + MLDSAPublicKeyInternalTrait, + SK: MLDSAPrivateKeyTrait< + k, + l, + S1_PACKED_LEN, + S2_PACKED_LEN, + T1_PACKED_LEN, + PK_LEN, + SK_LEN, + FULL_SK_LEN, + > + MLDSAPrivateKeyInternalTrait< + LAMBDA, + GAMMA2, + k, + l, + ETA, + S1_PACKED_LEN, + S2_PACKED_LEN, + PK_LEN, + SK_LEN, + >, + const PH_LEN: usize, + const oid: &'static [u8], + const PK_LEN: usize, + const SK_LEN: usize, + const FULL_SK_LEN: usize, + const SIG_LEN: usize, + const TAU: i32, + const LAMBDA: i32, + const GAMMA1: i32, + const GAMMA2: i32, + const k: usize, + const l: usize, + const ETA: usize, + const BETA: i32, + const OMEGA: i32, + const C_TILDE: usize, + const POLY_Z_PACKED_LEN: usize, + const POLY_W1_PACKED_LEN: usize, + const S1_PACKED_LEN: usize, + const S2_PACKED_LEN: usize, + const T1_PACKED_LEN: usize, + const LAMBDA_over_4: usize, + const GAMMA1_MINUS_BETA: i32, + const GAMMA2_MINUS_BETA: i32, + const GAMMA1_MASK_LEN: usize, +> SignatureVerifier + for HashMLDSA< + HASH, + PH_LEN, + oid, + PK_LEN, + SK_LEN, + FULL_SK_LEN, + SIG_LEN, + PK, + SK, + TAU, + LAMBDA, + GAMMA1, + GAMMA2, + k, + l, + ETA, + BETA, + OMEGA, + C_TILDE, + POLY_Z_PACKED_LEN, + POLY_W1_PACKED_LEN, + S1_PACKED_LEN, + S2_PACKED_LEN, + T1_PACKED_LEN, + LAMBDA_over_4, + GAMMA1_MINUS_BETA, + GAMMA2_MINUS_BETA, + GAMMA1_MASK_LEN, + > +{ fn verify(pk: &PK, msg: &[u8], ctx: Option<&[u8]>, sig: &[u8]) -> Result<(), SignatureError> { let mut ph_m = [0u8; PH_LEN]; _ = HASH::default().hash_out(msg, &mut ph_m); @@ -971,7 +1053,7 @@ impl< const GAMMA1_MINUS_BETA: i32, const GAMMA2_MINUS_BETA: i32, const GAMMA1_MASK_LEN: usize, -> PHSignature +> PHSigner for HashMLDSA< HASH, PH_LEN, @@ -1028,7 +1110,89 @@ impl< HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?; Self::sign_ph_deterministic_out(sk, ctx, ph, rnd, output) } +} +impl< + HASH: Hash + Default, + const PH_LEN: usize, + const oid: &'static [u8], + const PK_LEN: usize, + const SK_LEN: usize, + const FULL_SK_LEN: usize, + const SIG_LEN: usize, + PK: MLDSAPublicKeyTrait + + MLDSAPublicKeyInternalTrait, + SK: MLDSAPrivateKeyTrait< + k, + l, + S1_PACKED_LEN, + S2_PACKED_LEN, + T1_PACKED_LEN, + PK_LEN, + SK_LEN, + FULL_SK_LEN, + > + MLDSAPrivateKeyInternalTrait< + LAMBDA, + GAMMA2, + k, + l, + ETA, + S1_PACKED_LEN, + S2_PACKED_LEN, + PK_LEN, + SK_LEN, + >, + const TAU: i32, + const LAMBDA: i32, + const GAMMA1: i32, + const GAMMA2: i32, + const k: usize, + const l: usize, + const ETA: usize, + const BETA: i32, + const OMEGA: i32, + const C_TILDE: usize, + const POLY_Z_PACKED_LEN: usize, + const POLY_W1_PACKED_LEN: usize, + const S1_PACKED_LEN: usize, + const S2_PACKED_LEN: usize, + const T1_PACKED_LEN: usize, + const LAMBDA_over_4: usize, + const GAMMA1_MINUS_BETA: i32, + const GAMMA2_MINUS_BETA: i32, + const GAMMA1_MASK_LEN: usize, +> PHSignatureVerifier + for HashMLDSA< + HASH, + PH_LEN, + oid, + PK_LEN, + SK_LEN, + FULL_SK_LEN, + SIG_LEN, + PK, + SK, + TAU, + LAMBDA, + GAMMA1, + GAMMA2, + k, + l, + ETA, + BETA, + OMEGA, + C_TILDE, + POLY_Z_PACKED_LEN, + POLY_W1_PACKED_LEN, + S1_PACKED_LEN, + S2_PACKED_LEN, + T1_PACKED_LEN, + LAMBDA_over_4, + GAMMA1_MINUS_BETA, + GAMMA2_MINUS_BETA, + GAMMA1_MASK_LEN, + > +{ fn verify_ph( pk: &PK, ph: &[u8; PH_LEN], diff --git a/crypto/mldsa_lowmemory/src/lib.rs b/crypto/mldsa_lowmemory/src/lib.rs index ccc5a33..3af01a2 100644 --- a/crypto/mldsa_lowmemory/src/lib.rs +++ b/crypto/mldsa_lowmemory/src/lib.rs @@ -128,7 +128,6 @@ //! ## Generating Keys //! //! ```rust -//! use bouncycastle_core::traits::Signature; //! use bouncycastle_mldsa_lowmemory::MLDSA65; //! //! let (pk, sk) = MLDSA65::keygen().unwrap(); @@ -153,13 +152,13 @@ //! //! See [MLDSATrait] and [MLDSATrait::sign_mu_deterministic_from_seed] for an API flow that uses a merged //! keygen-and-sign function to provide improved speed and memory performance compared with making -//! separate calls to [MLDSATrait::keygen_from_seed] followed by [Signature::sign]. +//! separate calls to [MLDSATrait::keygen_from_seed] followed by [Signer::sign]. //! //! ## Generating and Verifying Signatures //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait}; //! //! let msg = b"The quick brown fox"; @@ -221,7 +220,7 @@ #[allow(unused_imports)] use bouncycastle_core::key_material::KeyMaterialTrait; #[allow(unused_imports)] -use bouncycastle_core::traits::Signature; +use bouncycastle_core::traits::{SignatureVerifier, Signer}; // todo -- re-run mutants diff --git a/crypto/mldsa_lowmemory/src/mldsa.rs b/crypto/mldsa_lowmemory/src/mldsa.rs index a6efa48..1756a8a 100644 --- a/crypto/mldsa_lowmemory/src/mldsa.rs +++ b/crypto/mldsa_lowmemory/src/mldsa.rs @@ -9,7 +9,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let (pk, sk) = MLDSA65::keygen().unwrap(); @@ -51,7 +51,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let (pk, sk) = MLDSA65::keygen().unwrap(); @@ -97,7 +97,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let (pk, _) = MLDSA65::keygen().unwrap(); @@ -116,7 +116,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let (pk, _) = MLDSA65::keygen().unwrap(); @@ -136,7 +136,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let msg = b"The quick brown fox jumped over the lazy dog"; @@ -181,7 +181,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait}; //! //! let msg = b"The quick brown fox"; @@ -220,7 +220,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let msg = b"The quick brown fox jumped over the lazy dog"; @@ -265,7 +265,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_core::key_material::{KeyMaterial256, KeyType, KeyMaterialTrait}; //! use bouncycastle_hex as hex; //! use bouncycastle_mldsa_lowmemory::{MLDSA44, MLDSA44_SIG_LEN, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; @@ -324,7 +324,7 @@ use crate::{ }; use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::KeyMaterial; -use bouncycastle_core::traits::{Algorithm, RNG, SecurityStrength, Signature, XOF}; +use bouncycastle_core::traits::{Algorithm, RNG, SecurityStrength, SignatureVerifier, Signer, XOF}; use bouncycastle_rng::HashDRBG_SHA512; use bouncycastle_sha3::{SHAKE128, SHAKE256}; use core::marker::PhantomData; @@ -335,7 +335,7 @@ use crate::hash_mldsa; #[allow(unused_imports)] use bouncycastle_core::key_material::KeyMaterial256; #[allow(unused_imports)] -use bouncycastle_core::traits::PHSignature; +use bouncycastle_core::traits::{PHSignatureVerifier, PHSigner}; /*** Constants ***/ /// @@ -718,6 +718,15 @@ impl< GAMMA1_MASK_LEN, > { + /// Generate a keypair, sourcing randomness from bouncycastle's default os-backed RNG. + /// + /// Key generation is intentionally not part of the [Signer] / [SignatureVerifier] traits; + /// it is provided as an inherent associated function directly on the algorithm struct. + /// Error condition: basically only on RNG failures. + pub fn keygen() -> Result<(PK, SK), SignatureError> { + Self::keygen_from_os_rng() + } + /// Should still be ok in FIPS mode pub fn keygen_from_os_rng() -> Result<(PK, SK), SignatureError> { let mut seed = KeyMaterial::<32>::new(); @@ -1540,7 +1549,7 @@ impl< const GAMMA1_MINUS_BETA: i32, const GAMMA2_MINUS_BETA: i32, const GAMMA1_MASK_LEN: usize, -> Signature +> Signer for MLDSA< PK_LEN, SK_LEN, @@ -1569,10 +1578,6 @@ impl< GAMMA1_MASK_LEN, > { - fn keygen() -> Result<(PK, SK), SignatureError> { - Self::keygen_from_os_rng() - } - fn sign(sk: &SK, msg: &[u8], ctx: Option<&[u8]>) -> Result<[u8; SIG_LEN], SignatureError> { let mut out = [0u8; SIG_LEN]; Self::sign_out(sk, msg, ctx, &mut out)?; @@ -1646,7 +1651,83 @@ impl< unreachable!() } } +} +impl< + const PK_LEN: usize, + const SK_LEN: usize, + const FULL_SK_LEN: usize, + const SIG_LEN: usize, + PK: MLDSAPublicKeyTrait + + MLDSAPublicKeyInternalTrait, + SK: MLDSAPrivateKeyTrait< + k, + l, + S1_PACKED_LEN, + S2_PACKED_LEN, + T1_PACKED_LEN, + PK_LEN, + SK_LEN, + FULL_SK_LEN, + > + MLDSAPrivateKeyInternalTrait< + LAMBDA, + GAMMA2, + k, + l, + ETA, + S1_PACKED_LEN, + S2_PACKED_LEN, + PK_LEN, + SK_LEN, + >, + const TAU: i32, + const LAMBDA: i32, + const GAMMA1: i32, + const GAMMA2: i32, + const k: usize, + const l: usize, + const ETA: usize, + const BETA: i32, + const OMEGA: i32, + const C_TILDE: usize, + const POLY_Z_PACKED_LEN: usize, + const POLY_W1_PACKED_LEN: usize, + const S1_PACKED_LEN: usize, + const S2_PACKED_LEN: usize, + const T1_PACKED_LEN: usize, + const LAMBDA_over_4: usize, + const GAMMA1_MINUS_BETA: i32, + const GAMMA2_MINUS_BETA: i32, + const GAMMA1_MASK_LEN: usize, +> SignatureVerifier + for MLDSA< + PK_LEN, + SK_LEN, + FULL_SK_LEN, + SIG_LEN, + PK, + SK, + TAU, + LAMBDA, + GAMMA1, + GAMMA2, + k, + l, + ETA, + BETA, + OMEGA, + C_TILDE, + POLY_Z_PACKED_LEN, + POLY_W1_PACKED_LEN, + S1_PACKED_LEN, + S2_PACKED_LEN, + T1_PACKED_LEN, + LAMBDA_over_4, + GAMMA1_MINUS_BETA, + GAMMA2_MINUS_BETA, + GAMMA1_MASK_LEN, + > +{ fn verify(pk: &PK, msg: &[u8], ctx: Option<&[u8]>, sig: &[u8]) -> Result<(), SignatureError> { let mu = MuBuilder::compute_mu(&pk.compute_tr(), msg, ctx)?; @@ -1703,7 +1784,7 @@ impl< /// Note: this struct is only exposed for "pure" ML-DSA and not for HashML-DSA because HashML-DSA /// does not benefit from allowing external construction of the message representative mu. /// You can get the same behaviour by computing the pre-hash `ph` with the appropriate hash function -/// and providing that to HashMLDSA via [PHSignature::sign_ph]. +/// and providing that to HashMLDSA via [PHSigner::sign_ph]. pub struct MuBuilder { h: H, } diff --git a/crypto/mldsa_lowmemory/tests/bc_test_data.rs b/crypto/mldsa_lowmemory/tests/bc_test_data.rs index 706c82a..fdc5c56 100644 --- a/crypto/mldsa_lowmemory/tests/bc_test_data.rs +++ b/crypto/mldsa_lowmemory/tests/bc_test_data.rs @@ -18,7 +18,7 @@ mod bc_test_data { use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyMaterialTrait, KeyType}; use bouncycastle_core::traits::{ - Hash, SecurityStrength, Signature, SignaturePrivateKey, SignaturePublicKey, + Hash, SecurityStrength, SignaturePrivateKey, SignaturePublicKey, SignatureVerifier, }; use bouncycastle_hex as hex; use bouncycastle_mldsa_lowmemory::{ diff --git a/crypto/mldsa_lowmemory/tests/hash_mldsa_tests.rs b/crypto/mldsa_lowmemory/tests/hash_mldsa_tests.rs index 1380296..d5b1bdf 100644 --- a/crypto/mldsa_lowmemory/tests/hash_mldsa_tests.rs +++ b/crypto/mldsa_lowmemory/tests/hash_mldsa_tests.rs @@ -1,4 +1,4 @@ -use bouncycastle_core::traits::Signature; +use bouncycastle_core::traits::{SignatureVerifier, Signer}; use bouncycastle_hex as hex; #[cfg(test)] @@ -6,7 +6,7 @@ mod hash_mldsa_tests { use super::*; use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyType}; - use bouncycastle_core::traits::{Hash, PHSignature}; + use bouncycastle_core::traits::{Hash, PHSignatureVerifier}; use bouncycastle_core_test_framework::signature::TestFrameworkSignature; use bouncycastle_mldsa_lowmemory::{ HashMLDSA44_with_SHA256, HashMLDSA44_with_SHA512, HashMLDSA65_with_SHA256, @@ -24,19 +24,19 @@ mod hash_mldsa_tests { let tf = TestFrameworkSignature::new(false, true); // Test HashML-DSA-SHA512 as a regular signature alg - tf.test_signature::(false); - tf.test_signature::(false); - tf.test_signature::(false); + tf.test_signature::(HashMLDSA44_with_SHA512::keygen, false); + tf.test_signature::(HashMLDSA65_with_SHA512::keygen, false); + tf.test_signature::(HashMLDSA87_with_SHA512::keygen, false); // Test HashML-DSA-SHA256 as a ph signature alg - tf.test_ph_signature::(false); - tf.test_ph_signature::(false); - tf.test_ph_signature::(false); + tf.test_ph_signature::(HashMLDSA44_with_SHA256::keygen, false); + tf.test_ph_signature::(HashMLDSA65_with_SHA256::keygen, false); + tf.test_ph_signature::(HashMLDSA87_with_SHA256::keygen, false); // Test HashML-DSA-SHA512 as a ph signature alg - tf.test_ph_signature::(false); - tf.test_ph_signature::(false); - tf.test_ph_signature::(false); + tf.test_ph_signature::(HashMLDSA44_with_SHA512::keygen, false); + tf.test_ph_signature::(HashMLDSA65_with_SHA512::keygen, false); + tf.test_ph_signature::(HashMLDSA87_with_SHA512::keygen, false); } #[test] diff --git a/crypto/mldsa_lowmemory/tests/mldsa_key_tests.rs b/crypto/mldsa_lowmemory/tests/mldsa_key_tests.rs index 4919fbb..a957079 100644 --- a/crypto/mldsa_lowmemory/tests/mldsa_key_tests.rs +++ b/crypto/mldsa_lowmemory/tests/mldsa_key_tests.rs @@ -6,7 +6,7 @@ mod mldsa_key_tests { use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyMaterialTrait, KeyType}; use bouncycastle_core::traits::{ - SecurityStrength, Signature, SignaturePrivateKey, SignaturePublicKey, + SecurityStrength, SignaturePrivateKey, SignaturePublicKey, }; use bouncycastle_core_test_framework::signature::TestFrameworkSignatureKeys; use bouncycastle_hex as hex; @@ -24,9 +24,9 @@ mod mldsa_key_tests { fn core_framework_tests() { let tf = TestFrameworkSignatureKeys::new(); - tf.test_keys::(); - tf.test_keys::(); - tf.test_keys::(); + tf.test_keys::(MLDSA44::keygen); + tf.test_keys::(MLDSA65::keygen); + tf.test_keys::(MLDSA87::keygen); } #[test] diff --git a/crypto/mldsa_lowmemory/tests/mldsa_tests.rs b/crypto/mldsa_lowmemory/tests/mldsa_tests.rs index b3eb8c3..e45ed76 100644 --- a/crypto/mldsa_lowmemory/tests/mldsa_tests.rs +++ b/crypto/mldsa_lowmemory/tests/mldsa_tests.rs @@ -5,7 +5,7 @@ mod mldsa_tests { use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyMaterialTrait, KeyType}; use bouncycastle_core::traits::{ - RNG, SecurityStrength, Signature, SignaturePrivateKey, SignaturePublicKey, + RNG, SecurityStrength, SignaturePrivateKey, SignaturePublicKey, SignatureVerifier, Signer, }; use bouncycastle_core_test_framework::DUMMY_SEED_1024; use bouncycastle_core_test_framework::signature::*; @@ -22,9 +22,9 @@ mod mldsa_tests { fn test_framework_signature() { let tf = TestFrameworkSignature::new(false, true); - tf.test_signature::(false); - tf.test_signature::(false); - tf.test_signature::(false); + tf.test_signature::(MLDSA44::keygen, false); + tf.test_signature::(MLDSA65::keygen, false); + tf.test_signature::(MLDSA87::keygen, false); } /// This runs the full bitflipping tests and takes several minutes. diff --git a/crypto/mldsa_lowmemory/tests/wycheproof.rs b/crypto/mldsa_lowmemory/tests/wycheproof.rs index ca9df24..080efdf 100644 --- a/crypto/mldsa_lowmemory/tests/wycheproof.rs +++ b/crypto/mldsa_lowmemory/tests/wycheproof.rs @@ -23,7 +23,7 @@ use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyMaterialTrait, KeyType}; -use bouncycastle_core::traits::{SecurityStrength, Signature, SignaturePublicKey}; +use bouncycastle_core::traits::{SecurityStrength, SignaturePublicKey, SignatureVerifier}; use bouncycastle_hex as hex; use bouncycastle_mldsa_lowmemory::{ MLDSA44, MLDSA44PublicKey, MLDSA65, MLDSA65PublicKey, MLDSA87, MLDSA87PublicKey, diff --git a/mem_usage_benches/bench_mldsa_mem_usage.rs b/mem_usage_benches/bench_mldsa_mem_usage.rs index 6b648fe..92b2c03 100644 --- a/mem_usage_benches/bench_mldsa_mem_usage.rs +++ b/mem_usage_benches/bench_mldsa_mem_usage.rs @@ -21,7 +21,7 @@ #![allow(unused_imports)] use bouncycastle::core::key_material::{KeyMaterial256, KeyType}; -use bouncycastle::core::traits::{Signature, SignaturePrivateKey, SignaturePublicKey}; +use bouncycastle::core::traits::{SignatureVerifier, SignaturePrivateKey, SignaturePublicKey}; use bouncycastle::hex as hex; use bouncycastle::mldsa::MLDSA44_SIG_LEN; From 3cee677e24a5f56ba500cf3183c0c7e8d41d5641 Mon Sep 17 00:00:00 2001 From: Mike Ounsworth Date: Wed, 10 Jun 2026 13:00:11 -0500 Subject: [PATCH 07/13] Refactored the KEM trait into KEMEncapsuloter and KEMDecapsulator --- cli/src/mlkem_cmd.rs | 2 +- crypto/core-test-framework/src/kem.rs | 63 ++++++++-------- crypto/core/src/traits.rs | 73 +++++++++++-------- crypto/mldsa/src/hash_mldsa.rs | 8 +- crypto/mlkem/benches/mlkem_benches.rs | 2 +- crypto/mlkem/src/lib.rs | 41 ++++++----- crypto/mlkem/src/mlkem.rs | 59 +++++++++++---- crypto/mlkem/tests/bc_test_data.rs | 2 +- crypto/mlkem/tests/mlkem_key_tests.rs | 14 ++-- crypto/mlkem/tests/mlkem_tests.rs | 8 +- crypto/mlkem/tests/wycheproof.rs | 2 +- .../mlkem_lowmemory/benches/mlkem_benches.rs | 2 +- crypto/mlkem_lowmemory/src/lib.rs | 29 ++++---- crypto/mlkem_lowmemory/src/mlkem.rs | 54 +++++++++++--- .../mlkem_lowmemory/tests/mlkem_key_tests.rs | 12 +-- crypto/mlkem_lowmemory/tests/mlkem_tests.rs | 8 +- crypto/mlkem_lowmemory/tests/wycheproof.rs | 2 +- mem_usage_benches/bench_mlkem_mem_usage.rs | 2 +- 18 files changed, 227 insertions(+), 156 deletions(-) diff --git a/cli/src/mlkem_cmd.rs b/cli/src/mlkem_cmd.rs index de56238..da69cea 100644 --- a/cli/src/mlkem_cmd.rs +++ b/cli/src/mlkem_cmd.rs @@ -4,7 +4,7 @@ use std::process::exit; use clap::ValueEnum; use bouncycastle::core::key_material::KeyMaterialTrait; -use bouncycastle::core::traits::{KEMPrivateKey, KEMPublicKey, KEM}; +use bouncycastle::core::traits::{KEMDecapsulator, KEMEncapsulator, KEMPrivateKey, KEMPublicKey}; use bouncycastle::hex; use bouncycastle::mlkem::{MLKEM512, MLKEMTrait, MLKEM512PrivateKey, MLKEM512_SK_LEN, MLKEM512PublicKey, MLKEM512_PK_LEN, MLKEMPrivateKeyTrait, MLKEM512_CT_LEN, MLKEM768PrivateKey, MLKEM768_SK_LEN, MLKEM768, MLKEM768PublicKey, MLKEM768_PK_LEN, MLKEM1024PrivateKey, MLKEM1024_SK_LEN, MLKEM1024, MLKEM1024_PK_LEN, MLKEM1024PublicKey, MLKEM768_CT_LEN, MLKEM1024_CT_LEN}; use crate::helpers::{parse_seed, read_from_file, read_from_file_or_stdin, write_bytes_or_hex, write_bytes_or_hex_to_file}; diff --git a/crypto/core-test-framework/src/kem.rs b/crypto/core-test-framework/src/kem.rs index 785d499..82f7783 100644 --- a/crypto/core-test-framework/src/kem.rs +++ b/crypto/core-test-framework/src/kem.rs @@ -1,5 +1,5 @@ use bouncycastle_core::errors::KEMError; -use bouncycastle_core::traits::{KEMPrivateKey, KEMPublicKey, KEM}; +use bouncycastle_core::traits::{KEMDecapsulator, KEMEncapsulator, KEMPrivateKey, KEMPublicKey}; pub struct TestFrameworkKEM { // Put any config options here @@ -16,43 +16,48 @@ impl TestFrameworkKEM { Self { alg_is_deterministic, is_implicitly_rejecting } } - /// Test all the members of trait Hash against the given input-output pair. + /// Test all the members of traits [KEMEncapsulator] and [KEMDecapsulator] against the given input-output pair. /// This gives good baseline test coverage, but is not exhaustive. + /// + /// Since key generation is not part of either KEM trait, the caller supplies a + /// `keygen` function pointer (the inherent `keygen` associated function on the algorithm struct). pub fn test_kem< PK: KEMPublicKey, SK: KEMPrivateKey, - KEMAlg: KEM, + ENCAPSULATOR: KEMEncapsulator, + DECAPSULATOR: KEMDecapsulator, const PK_LEN: usize, const SK_LEN: usize, const CT_LEN: usize, const SS_LEN: usize, >( &self, + keygen: fn() -> Result<(PK, SK), KEMError>, run_full_bitflipping_tests: bool, ) { // Basic test - let (pk, sk) = KEMAlg::keygen().unwrap(); - let (ss, ct) = KEMAlg::encaps(&pk).unwrap(); - let ss1 = KEMAlg::decaps(&sk, &ct).unwrap(); + let (pk, sk) = keygen().unwrap(); + let (ss, ct) = ENCAPSULATOR::encaps(&pk).unwrap(); + let ss1 = DECAPSULATOR::decaps(&sk, &ct).unwrap(); assert_eq!(ss, ss1); // Test non-determinism if !self.alg_is_deterministic { - let (ss1, ct1) = KEMAlg::encaps(&pk).unwrap(); - let (ss2, ct2) = KEMAlg::encaps(&pk).unwrap(); + let (ss1, ct1) = ENCAPSULATOR::encaps(&pk).unwrap(); + let (ss2, ct2) = ENCAPSULATOR::encaps(&pk).unwrap(); assert_ne!(ss1, ss2); assert_ne!(ct1, ct2); } // Test that decaps fails for broken ct value - let (pk, sk) = KEMAlg::keygen().unwrap(); - let (ss, mut ct) = KEMAlg::encaps(&pk).unwrap(); + let (pk, sk) = keygen().unwrap(); + let (ss, mut ct) = ENCAPSULATOR::encaps(&pk).unwrap(); ct[17] ^= 0xFF; if self.is_implicitly_rejecting { - let ss2 = KEMAlg::decaps(&sk, &ct).unwrap(); + let ss2 = DECAPSULATOR::decaps(&sk, &ct).unwrap(); assert_ne!(ss, ss2); } else { - match KEMAlg::decaps(&sk, &ct) { + match DECAPSULATOR::decaps(&sk, &ct) { Err(KEMError::DecapsulationFailed) => /* good */ (), _ => panic!("This should have thrown an error but it didn't."), } @@ -68,10 +73,10 @@ impl TestFrameworkKEM { // should throw an Err if self.is_implicitly_rejecting { - let ss2 = KEMAlg::decaps(&sk, &ct_copy).unwrap(); + let ss2 = DECAPSULATOR::decaps(&sk, &ct_copy).unwrap(); assert_ne!(ss, ss2); } else { - match KEMAlg::decaps(&sk, &ct) { + match DECAPSULATOR::decaps(&sk, &ct) { Err(KEMError::DecapsulationFailed) => /* good */ (), _ => panic!("This should have thrown an error but it didn't."), } @@ -79,22 +84,22 @@ impl TestFrameworkKEM { } } } - + // test ct the wrong length - let (pk, sk) = KEMAlg::keygen().unwrap(); - let (_ss, ct) = KEMAlg::encaps(&pk).unwrap(); - + let (pk, sk) = keygen().unwrap(); + let (_ss, ct) = ENCAPSULATOR::encaps(&pk).unwrap(); + // too short - match KEMAlg::decaps(&sk, &ct[..CT_LEN-1]) { + match DECAPSULATOR::decaps(&sk, &ct[..CT_LEN-1]) { Err(KEMError::LengthError(_)) => { /* good */ }, _ => panic!("This should have thrown an error but it didn't."), }; - + // too long let mut long_ct = vec![1u8; CT_LEN + 2]; long_ct.as_mut_slice()[..CT_LEN].copy_from_slice(&ct); - match KEMAlg::decaps(&sk, &long_ct) { + match DECAPSULATOR::decaps(&sk, &long_ct) { Err(KEMError::LengthError(_)) => { /* good */ }, _ => panic!("This should have thrown an error but it didn't."), }; @@ -109,29 +114,25 @@ impl TestFrameworkKEMKeys { Self { } } + /// Since key generation is not part of either KEM trait, the caller supplies a + /// `keygen` function pointer (the inherent `keygen` associated function on the algorithm struct). pub fn test_keys< PK: KEMPublicKey, SK: KEMPrivateKey, - KEMAlg: KEM, const PK_LEN: usize, const SK_LEN: usize, - const CT_LEN: usize, - const SS_LEN: usize, - >(&self) { - self.test_boundary_conditions::(); + >(&self, keygen: fn() -> Result<(PK, SK), KEMError>) { + self.test_boundary_conditions::(keygen); } /// Tests the correct behaviour on buffers too large / too small. fn test_boundary_conditions< PK: KEMPublicKey, SK: KEMPrivateKey, - KEMAlg: KEM, const PK_LEN: usize, const SK_LEN: usize, - const CT_LEN: usize, - const SS_LEN: usize, - >(&self) { - let (pk, sk) = KEMAlg::keygen().unwrap(); + >(&self, keygen: fn() -> Result<(PK, SK), KEMError>) { + let (pk, sk) = keygen().unwrap(); let pk_bytes = pk.encode(); assert_eq!(pk_bytes.len(), PK_LEN); diff --git a/crypto/core/src/traits.rs b/crypto/core/src/traits.rs index 1a623ab..492180e 100644 --- a/crypto/core/src/traits.rs +++ b/crypto/core/src/traits.rs @@ -178,24 +178,57 @@ pub trait KDF: Default { fn max_security_strength(&self) -> SecurityStrength; } -/// A Key Encapsulation Mechanism -pub trait KEM< +/// A Key Encapsulation Mechanism (KEM) is defined as a set of three operations: +/// key generation, encapsulation, and decapsulation. +/// +/// This trait represents the encapsulation operation performed by the holder of the public key. +/// Decapsulation operations are performed by the corresponding [KEMDecapsulator] trait, and key +/// generation is provided as an inherent associated function directly on the algorithm struct. +/// There are several reasons for this split: first is architectural; some complex algorithms may +/// benefit from having the encapsulation and decapsulation implementations split into separate modules. +/// Second is for compliance: sometimes a policy soft-deprecates an algorithm so that new ciphertexts +/// can no longer be created, but existing ciphertexts can still be decapsulated. Splitting the traits +/// makes this policy easier to enforce. +/// +/// The arrays used to encode public keys, ciphertexts, and shared secrets are statically-sized +/// because this allows us to safely remove runtime checks for array lengths, which overall reduces +/// the fallibility of the library. This design choice could make this trait complicated to apply +/// to a KEM algorithm that does not have fixed sizes for the encodings of these objects. +pub trait KEMEncapsulator< PK: KEMPublicKey, - SK: KEMPrivateKey, const PK_LEN: usize, - const SK_LEN: usize, const CT_LEN: usize, const SS_LEN: usize, >: Sized { - /// Generate a keypair. - /// Error condition: Basically only on RNG failures - fn keygen() -> Result<(PK, SK), KEMError>; - /// Performs an encapsulation against the given public key. /// Returns the ciphertext and derived shared secret. fn encaps(pk: &PK) -> Result<(KeyMaterial, [u8; CT_LEN]), KEMError>; +} +/// A Key Encapsulation Mechanism (KEM) is defined as a set of three operations: +/// key generation, encapsulation, and decapsulation. +/// +/// This trait represents the decapsulation operation performed by the holder of the private key. +/// Encapsulation operations are performed by the corresponding [KEMEncapsulator] trait, and key +/// generation is provided as an inherent associated function directly on the algorithm struct. +/// There are several reasons for this split: first is architectural; some complex algorithms may +/// benefit from having the encapsulation and decapsulation implementations split into separate modules. +/// Second is for compliance: sometimes a policy soft-deprecates an algorithm so that new ciphertexts +/// can no longer be created, but existing ciphertexts can still be decapsulated. Splitting the traits +/// makes this policy easier to enforce. +/// +/// The arrays used to encode private keys, ciphertexts, and shared secrets are statically-sized +/// because this allows us to safely remove runtime checks for array lengths, which overall reduces +/// the fallibility of the library. This design choice could make this trait complicated to apply +/// to a KEM algorithm that does not have fixed sizes for the encodings of these objects. +pub trait KEMDecapsulator< + SK: KEMPrivateKey, + const SK_LEN: usize, + const CT_LEN: usize, + const SS_LEN: usize, +>: Sized +{ /// Performs a decapsulation of the given ciphertext. /// Returns the derived shared secret. fn decaps(sk: &SK, ct: &[u8]) -> Result, KEMError>; @@ -621,30 +654,6 @@ pub trait SignatureVerifier< fn verify_final(self, sig: &[u8]) -> Result<(), SignatureError>; } -// todo: could the public and private key types impl Into> and From> -// todo: that automatically call the encode and from_bytes() ? - -/// A public key for a signature algorithm, often denoted "pk". -pub trait SignaturePublicKey : PartialEq + Eq + Clone + Debug + Display + Sized { - /// Write it out to bytes in its standard encoding. - fn encode(&self) -> [u8; PK_LEN]; - /// Write it out to bytes in its standard encoding. - fn encode_out(&self, out: &mut [u8; PK_LEN]) -> usize; - /// Read it in from bytes in its standard encoding. - fn from_bytes(bytes: &[u8]) -> Result; -} - -/// A private key for a signature algorithm, often denoted "sk" (for "secret key"). -pub trait SignaturePrivateKey : PartialEq + Eq + Clone + Secret + Sized { - /// Write it out to bytes in its standard encoding. - fn encode(&self) -> [u8; SK_LEN]; - /// Write it out to bytes in its standard encoding. - fn encode_out(&self, out: &mut [u8; SK_LEN]) -> usize; - /// Read it in from bytes in its standard encoding. - fn from_bytes(bytes: &[u8]) -> Result; -} - - /// Extensible Output Functions (XOFs) are similar to hash functions, except that they can produce output of arbitrary length. /// The naming used for the functions of this trait are borrowed from the SHA3-style sponge constructions that split XOF operation /// into two phases: an absorb phase in which an arbitrary amount of input is provided to the XOF, diff --git a/crypto/mldsa/src/hash_mldsa.rs b/crypto/mldsa/src/hash_mldsa.rs index 48442aa..609c4fb 100644 --- a/crypto/mldsa/src/hash_mldsa.rs +++ b/crypto/mldsa/src/hash_mldsa.rs @@ -958,12 +958,11 @@ impl< } impl< - HASH: Hash + Default, + HASH: Hash + Algorithm + Default, PK: MLDSAPublicKeyTrait + MLDSAPublicKeyInternalTrait, SK: MLDSAPrivateKeyTrait + MLDSAPrivateKeyInternalTrait, const PH_LEN: usize, - const oid: &'static [u8], const PK_LEN: usize, const SK_LEN: usize, const SIG_LEN: usize, @@ -987,7 +986,6 @@ impl< for HashMLDSA< HASH, PH_LEN, - oid, PK_LEN, SK_LEN, SIG_LEN, @@ -1126,9 +1124,8 @@ impl< } impl< - HASH: Hash + Default, + HASH: Hash + Algorithm + Default, const PH_LEN: usize, - const oid: &'static [u8], const PK_LEN: usize, const SK_LEN: usize, const SIG_LEN: usize, @@ -1155,7 +1152,6 @@ impl< for HashMLDSA< HASH, PH_LEN, - oid, PK_LEN, SK_LEN, SIG_LEN, diff --git a/crypto/mlkem/benches/mlkem_benches.rs b/crypto/mlkem/benches/mlkem_benches.rs index d6a78da..c8d5a2d 100644 --- a/crypto/mlkem/benches/mlkem_benches.rs +++ b/crypto/mlkem/benches/mlkem_benches.rs @@ -1,7 +1,7 @@ use criterion::{Criterion, criterion_group, criterion_main}; use bouncycastle_core::key_material::{KeyMaterial512, KeyType}; use std::hint::black_box; -use bouncycastle_core::traits::KEM; +use bouncycastle_core::traits::KEMDecapsulator; use bouncycastle_hex as hex; use bouncycastle_mlkem::{MLKEM1024PrivateKeyExpanded, MLKEM512PrivateKeyExpanded, MLKEM768PrivateKeyExpanded, MLKEMPublicKeyTrait, MLKEMTrait, MLKEM1024, MLKEM1024_CT_LEN, MLKEM512, MLKEM512_CT_LEN, MLKEM768, MLKEM768_CT_LEN, MLKEM_RND_LEN}; diff --git a/crypto/mlkem/src/lib.rs b/crypto/mlkem/src/lib.rs index 117627d..28142b6 100644 --- a/crypto/mlkem/src/lib.rs +++ b/crypto/mlkem/src/lib.rs @@ -46,7 +46,6 @@ //! //! ```rust //! use bouncycastle_mlkem::MLKEM768; -//! use bouncycastle_core::traits::KEM; //! //! let (pk, sk) = MLKEM768::keygen().unwrap(); //! ``` @@ -76,7 +75,7 @@ //! //! ```rust //! use bouncycastle_mlkem::{MLKEM768, MLKEMTrait}; -//! use bouncycastle_core::traits::KEM; +//! use bouncycastle_core::traits::{KEMEncapsulator, KEMDecapsulator}; //! use bouncycastle_core::errors::KEMError; //! //! let (pk, sk) = MLKEM768::keygen().unwrap(); @@ -138,25 +137,20 @@ //! constant-time after compilation. #![no_std] - #![forbid(missing_docs)] - #![forbid(unsafe_code)] #![allow(incomplete_features)] // needed because currently generic_const_exprs is experimental #![feature(generic_const_exprs)] #![feature(adt_const_params)] - // These are because I'm matching variable names exactly against FIPS 204, for example both 'K' and 'k', // or 'A' and 'a' are used and have specific meanings. // But need to tell the rust linter to not care. #![allow(non_snake_case)] #![allow(non_upper_case_globals)] - // so I can use private traits to hide internal stuff that needs to be generic within the // MLKEM implementation, but I don't want accessed from outside, such as FIPS-internal functions. #![allow(private_bounds)] - // imports needed just for docs #[allow(unused_imports)] use bouncycastle_core::key_material::KeyMaterialTrait; @@ -165,33 +159,40 @@ use bouncycastle_core::key_material::KeyMaterialTrait; // todo -- crucible tests +mod aux_functions; +mod matrix; pub mod mlkem; mod mlkem_keys; mod polynomial; -mod aux_functions; -mod matrix; - /*** Exported types ***/ -pub use mlkem::{MLKEMTrait, MLKEM, MLKEM512, MLKEM768, MLKEM1024}; +pub use mlkem::{MLKEM, MLKEM512, MLKEM768, MLKEM1024, MLKEMTrait}; +pub use mlkem_keys::{ + MLKEM512PrivateKey, MLKEM768PrivateKey, MLKEM1024PrivateKey, MLKEMPrivateKey, +}; +pub use mlkem_keys::{ + MLKEM512PrivateKeyExpanded, MLKEM768PrivateKeyExpanded, MLKEM1024PrivateKeyExpanded, + MLKEMPrivateKeyExpanded, +}; +pub use mlkem_keys::{MLKEM512PublicKey, MLKEM768PublicKey, MLKEM1024PublicKey, MLKEMPublicKey}; +pub use mlkem_keys::{ + MLKEM512PublicKeyExpanded, MLKEM768PublicKeyExpanded, MLKEM1024PublicKeyExpanded, + MLKEMPublicKeyExpanded, +}; pub use mlkem_keys::{MLKEMPrivateKeyTrait, MLKEMPublicKeyTrait}; -pub use mlkem_keys::{MLKEMPublicKey, MLKEM512PublicKey, MLKEM768PublicKey, MLKEM1024PublicKey}; -pub use mlkem_keys::{MLKEMPublicKeyExpanded, MLKEM512PublicKeyExpanded, MLKEM768PublicKeyExpanded, MLKEM1024PublicKeyExpanded}; -pub use mlkem_keys::{MLKEMPrivateKey, MLKEM512PrivateKey, MLKEM768PrivateKey, MLKEM1024PrivateKey}; -pub use mlkem_keys::{MLKEMPrivateKeyExpanded, MLKEM512PrivateKeyExpanded, MLKEM768PrivateKeyExpanded, MLKEM1024PrivateKeyExpanded}; /*** Exported constants ***/ pub use mlkem::ML_KEM_512_NAME; pub use mlkem::ML_KEM_768_NAME; pub use mlkem::ML_KEM_1024_NAME; -pub use mlkem::{MLKEM_SEED_LEN, MLKEM_SS_LEN, MLKEM_RND_LEN}; +pub use mlkem::{MLKEM_RND_LEN, MLKEM_SEED_LEN, MLKEM_SS_LEN}; -pub use mlkem::{MLKEM512_PK_LEN, MLKEM512_SK_LEN, MLKEM512_CT_LEN}; -pub use mlkem::{MLKEM768_PK_LEN, MLKEM768_SK_LEN, MLKEM768_CT_LEN}; -pub use mlkem::{MLKEM1024_PK_LEN, MLKEM1024_SK_LEN, MLKEM1024_CT_LEN}; +pub use mlkem::{MLKEM512_CT_LEN, MLKEM512_PK_LEN, MLKEM512_SK_LEN}; +pub use mlkem::{MLKEM768_CT_LEN, MLKEM768_PK_LEN, MLKEM768_SK_LEN}; +pub use mlkem::{MLKEM1024_CT_LEN, MLKEM1024_PK_LEN, MLKEM1024_SK_LEN}; pub use matrix::Matrix; // re-export just so it's visible to unit tests -pub use polynomial::Polynomial; \ No newline at end of file +pub use polynomial::Polynomial; diff --git a/crypto/mlkem/src/mlkem.rs b/crypto/mlkem/src/mlkem.rs index 70f4352..9e974b9 100644 --- a/crypto/mlkem/src/mlkem.rs +++ b/crypto/mlkem/src/mlkem.rs @@ -30,7 +30,6 @@ //! ```rust //! use bouncycastle_mlkem::{MLKEM768, MLKEMTrait}; //! use bouncycastle_mlkem::{MLKEM768PublicKeyExpanded, MLKEM768PrivateKeyExpanded}; -//! use bouncycastle_core::traits::KEM; //! use bouncycastle_core::errors::KEMError; //! //! let (pk, sk) = MLKEM768::keygen().unwrap(); @@ -60,7 +59,7 @@ //! //! ```rust //! use bouncycastle_mlkem::{MLKEM768, MLKEMTrait}; -//! use bouncycastle_core::traits::KEM; +//! use bouncycastle_core::traits::KEMEncapsulator; //! use bouncycastle_core::errors::KEMError; //! use bouncycastle_core::key_material::{KeyMaterial512, KeyType}; //! use bouncycastle_hex as hex; @@ -104,7 +103,7 @@ //! //! ```rust //! use bouncycastle_mlkem::{MLKEM768, MLKEMTrait}; -//! use bouncycastle_core::traits::{KEM}; +//! use bouncycastle_core::traits::KEMDecapsulator; //! use bouncycastle_core::errors::KEMError; //! use bouncycastle_core::key_material::KeyMaterialTrait; //! @@ -129,7 +128,9 @@ use core::marker::PhantomData; use bouncycastle_core::errors::{KEMError}; use bouncycastle_core::key_material::{KeyMaterialTrait, KeyMaterial, KeyType}; -use bouncycastle_core::traits::{RNG, SecurityStrength, XOF, Algorithm, Hash, KEM}; +use bouncycastle_core::traits::{ + Algorithm, Hash, KEMDecapsulator, KEMEncapsulator, RNG, SecurityStrength, XOF, +}; use bouncycastle_rng::{HashDRBG_SHA512}; use bouncycastle_sha3::{SHA3_256, SHA3_512, SHAKE256}; use bouncycastle_utils::ct::{conditional_copy_bytes, ct_eq_bytes}; @@ -329,6 +330,15 @@ impl< LAMBDA, > { + /// Generate a keypair, sourcing randomness from bouncycastle's default os-backed RNG. + /// + /// Key generation is intentionally not part of the [KEMEncapsulator] / [KEMDecapsulator] traits; + /// it is provided as an inherent associated function directly on the algorithm struct. + /// Error condition: basically only on RNG failures. + pub fn keygen() -> Result<(PK, SK), KEMError> { + Self::keygen_from_os_rng() + } + /// Should still be ok in FIPS mode pub fn keygen_from_os_rng() -> Result< (PK, SK), @@ -544,13 +554,13 @@ impl< /// Alternatively, you can use a [MLKEMPublicKeyExpanded] with [MLKEM::encaps_for_expanded_key]. /// If you specify None, the function will compute A_hat internally and everything will work fine. /// - /// Unlike the more public function exposed by [KEM::encaps], this returns the shared secret as raw bytes + /// Unlike the more public function exposed by [KEMEncapsulator::encaps], this returns the shared secret as raw bytes /// instead of wrapped in an appropriately-set [KeyMaterialTrait], so you're on your own for handling it properly. /// /// Note: this is an internal function that allows the caller to specify the encapsulation /// randomness (which is the message `m` to be encrypted by the underlying PKE scheme). /// This function should not be used directly unless you really have a - /// good reason. [KEM::encaps] should be used in 99.9% of cases. + /// good reason. [KEMEncapsulator::encaps] should be used in 99.9% of cases. /// The reason this is exposed publicly is: A) for unit testing that requires access /// to the deterministically reproducible function, and B) for operational environments /// that wish to provide randomness from their own source instead of the built-in RNG in bc-rust. @@ -876,12 +886,12 @@ pub trait MLKEMTrait< sk: &SK, ) -> Result<(), KEMError>; - /// Same as [KEM::encaps], but acts on an [MLKEMPublicKeyExpanded]. + /// Same as [KEMEncapsulator::encaps], but acts on an [MLKEMPublicKeyExpanded]. fn encaps_for_expanded_key( pk: &MLKEMPublicKeyExpanded ) -> Result<(KeyMaterial, [u8; CT_LEN]), KEMError>; - /// Same as [KEM::decaps], but acts on an [MLKEMPrivateKeyExpanded]. + /// Same as [KEMDecapsulator::decaps], but acts on an [MLKEMPrivateKeyExpanded]. fn decaps_with_expanded_key( sk: &MLKEMPrivateKeyExpanded, ct: &[u8], @@ -900,7 +910,7 @@ impl< const du: i16, const dv: i16, const LAMBDA: i16, -> KEM for MLKEM< +> KEMEncapsulator for MLKEM< PK_LEN, SK_LEN, CT_LEN, @@ -913,11 +923,6 @@ impl< dv, LAMBDA, > { - /// Generates a fresh key pair. - fn keygen() -> Result<(PK, SK), KEMError> { - Self::keygen_from_os_rng() - } - /// Performs an encapsulation against the given public key, using the library's default internal RNG. /// Returns (shared_secret_key, ciphertext) /// The derived shared secret key is returned as a KeyMaterial with the SecurityStrength set to @@ -931,7 +936,33 @@ impl< fn encaps(pk: &PK) -> Result<(KeyMaterial, [u8; CT_LEN]), KEMError> { Self::encaps_for_expanded_key(&MLKEMPublicKeyExpanded::::from(pk)) } +} +impl< + const PK_LEN: usize, + const SK_LEN: usize, + const CT_LEN: usize, + const SS_LEN: usize, + PK: MLKEMPublicKeyTrait + MLKEMPublicKeyInternalTrait, + SK: MLKEMPrivateKeyTrait + MLKEMPrivateKeyInternalTrait, + const k: usize, + const eta: i16, + const du: i16, + const dv: i16, + const LAMBDA: i16, +> KEMDecapsulator for MLKEM< + PK_LEN, + SK_LEN, + CT_LEN, + SS_LEN, + PK, + SK, + k, + eta, + du, + dv, + LAMBDA, +> { /// Performs a decapsulation of the given ciphertext. /// Returns the shared secret key. /// The derived shared secret key is returned as a KeyMaterial with the SecurityStrength set to diff --git a/crypto/mlkem/tests/bc_test_data.rs b/crypto/mlkem/tests/bc_test_data.rs index 5c14a28..036c85c 100644 --- a/crypto/mlkem/tests/bc_test_data.rs +++ b/crypto/mlkem/tests/bc_test_data.rs @@ -5,7 +5,7 @@ #[cfg(test)] mod bc_test_data { use bouncycastle_core::key_material::{KeyMaterial512, KeyMaterialTrait, KeyType}; - use bouncycastle_core::traits::{KEM, KEMPrivateKey, KEMPublicKey, SecurityStrength}; + use bouncycastle_core::traits::{KEMDecapsulator, KEMPrivateKey, KEMPublicKey, SecurityStrength}; use bouncycastle_hex as hex; use bouncycastle_mlkem::{ MLKEM512, MLKEM512_PK_LEN, MLKEM512_SK_LEN, MLKEM512PrivateKey, MLKEM512PublicKey, diff --git a/crypto/mlkem/tests/mlkem_key_tests.rs b/crypto/mlkem/tests/mlkem_key_tests.rs index 7317d50..4a4f3de 100644 --- a/crypto/mlkem/tests/mlkem_key_tests.rs +++ b/crypto/mlkem/tests/mlkem_key_tests.rs @@ -2,12 +2,12 @@ mod mlkem_key_tests { use bouncycastle_core::errors::KEMError; use bouncycastle_core::key_material::{KeyMaterial512, KeyMaterialTrait, KeyType}; - use bouncycastle_core::traits::{KEM, KEMPrivateKey, KEMPublicKey, SecurityStrength}; + use bouncycastle_core::traits::{KEMPrivateKey, KEMPublicKey, SecurityStrength}; use bouncycastle_hex as hex; use bouncycastle_mlkem::{ - MLKEM_SS_LEN, MLKEM512_CT_LEN, MLKEM512_PK_LEN, MLKEM512_SK_LEN, - MLKEM512PrivateKeyExpanded, MLKEM512PublicKeyExpanded, MLKEM768_CT_LEN, MLKEM768_PK_LEN, - MLKEM768_SK_LEN, MLKEM1024_CT_LEN, MLKEM1024_PK_LEN, MLKEM1024_SK_LEN, + MLKEM512_PK_LEN, MLKEM512_SK_LEN, + MLKEM512PrivateKeyExpanded, MLKEM512PublicKeyExpanded, MLKEM768_PK_LEN, + MLKEM768_SK_LEN, MLKEM1024_PK_LEN, MLKEM1024_SK_LEN, MLKEMPrivateKeyTrait, MLKEMPublicKeyTrait, MLKEMTrait, }; use bouncycastle_mlkem::{MLKEM512, MLKEM768, MLKEM1024}; @@ -22,9 +22,9 @@ mod mlkem_key_tests { let tf = TestFrameworkKEMKeys::new(); - tf.test_keys::(); - tf.test_keys::(); - tf.test_keys::(); + tf.test_keys::(MLKEM512::keygen); + tf.test_keys::(MLKEM768::keygen); + tf.test_keys::(MLKEM1024::keygen); } #[test] diff --git a/crypto/mlkem/tests/mlkem_tests.rs b/crypto/mlkem/tests/mlkem_tests.rs index 71137fe..fb087f7 100644 --- a/crypto/mlkem/tests/mlkem_tests.rs +++ b/crypto/mlkem/tests/mlkem_tests.rs @@ -3,7 +3,7 @@ mod mlkem_tests { use bouncycastle_core::errors::KEMError; use bouncycastle_core::key_material::{KeyMaterialTrait, KeyMaterial512, KeyType}; - use bouncycastle_core::traits::{KEMPrivateKey, KEMPublicKey, SecurityStrength, KEM, XOF}; + use bouncycastle_core::traits::{KEMDecapsulator, KEMEncapsulator, KEMPrivateKey, KEMPublicKey, SecurityStrength, XOF}; use bouncycastle_mlkem::{MLKEM512, MLKEM768, MLKEM1024, MLKEM_RND_LEN, Polynomial}; use bouncycastle_mlkem::{MLKEM512PrivateKey, MLKEM512PublicKey, MLKEM768PrivateKey, MLKEM768PublicKey, MLKEM1024PrivateKey, MLKEM1024PublicKey}; use bouncycastle_mlkem::{MLKEMPrivateKeyTrait, MLKEMTrait}; @@ -35,9 +35,9 @@ mod mlkem_tests { let tf = TestFrameworkKEM::new(false, true); - tf.test_kem::(false); - tf.test_kem::(false); - tf.test_kem::(false); + tf.test_kem::(MLKEM512::keygen, false); + tf.test_kem::(MLKEM768::keygen, false); + tf.test_kem::(MLKEM1024::keygen, false); } /// This runs the full bitflipping tests and takes about 30s.. diff --git a/crypto/mlkem/tests/wycheproof.rs b/crypto/mlkem/tests/wycheproof.rs index ee3ddc9..a141e63 100644 --- a/crypto/mlkem/tests/wycheproof.rs +++ b/crypto/mlkem/tests/wycheproof.rs @@ -21,7 +21,7 @@ #![allow(dead_code)] use bouncycastle_core::key_material::{KeyMaterial512, KeyMaterialTrait, KeyType}; -use bouncycastle_core::traits::{KEM, KEMPrivateKey, KEMPublicKey, SecurityStrength}; +use bouncycastle_core::traits::{KEMDecapsulator, KEMPrivateKey, KEMPublicKey, SecurityStrength}; use bouncycastle_hex as hex; use bouncycastle_mlkem::{ MLKEM512, MLKEM512PrivateKey, MLKEM512PublicKey, MLKEM768, MLKEM768PrivateKey, diff --git a/crypto/mlkem_lowmemory/benches/mlkem_benches.rs b/crypto/mlkem_lowmemory/benches/mlkem_benches.rs index a708f3e..277a28d 100644 --- a/crypto/mlkem_lowmemory/benches/mlkem_benches.rs +++ b/crypto/mlkem_lowmemory/benches/mlkem_benches.rs @@ -1,7 +1,7 @@ use criterion::{Criterion, criterion_group, criterion_main}; use bouncycastle_core::key_material::{KeyMaterial512, KeyType}; use std::hint::black_box; -use bouncycastle_core::traits::KEM; +use bouncycastle_core::traits::KEMDecapsulator; use bouncycastle_hex as hex; use bouncycastle_mlkem_lowmemory::{MLKEMTrait, MLKEM1024, MLKEM1024_CT_LEN, MLKEM512, MLKEM512_CT_LEN, MLKEM768, MLKEM768_CT_LEN, MLKEM_RND_LEN}; diff --git a/crypto/mlkem_lowmemory/src/lib.rs b/crypto/mlkem_lowmemory/src/lib.rs index 32b3254..0f70fc5 100644 --- a/crypto/mlkem_lowmemory/src/lib.rs +++ b/crypto/mlkem_lowmemory/src/lib.rs @@ -155,7 +155,6 @@ //! //! ```rust //! use bouncycastle_mlkem_lowmemory::MLKEM768; -//! use bouncycastle_core::traits::KEM; //! //! let (pk, sk) = MLKEM768::keygen().unwrap(); //! ``` @@ -185,7 +184,7 @@ //! //! ```rust //! use bouncycastle_mlkem_lowmemory::{MLKEM768, MLKEMTrait}; -//! use bouncycastle_core::traits::KEM; +//! use bouncycastle_core::traits::{KEMEncapsulator, KEMDecapsulator}; //! use bouncycastle_core::errors::KEMError; //! //! let (pk, sk) = MLKEM768::keygen().unwrap(); @@ -224,20 +223,16 @@ //! constant-time after compilation. #![no_std] - #![forbid(missing_docs)] - #![forbid(unsafe_code)] #![allow(incomplete_features)] // needed because currently generic_const_exprs is experimental #![feature(generic_const_exprs)] #![feature(adt_const_params)] - // These are because I'm matching variable names exactly against FIPS 204, for example both 'K' and 'k', // or 'A' and 'a' are used and have specific meanings. // But need to tell the rust linter to not care. #![allow(non_snake_case)] #![allow(non_upper_case_globals)] - // so I can use private traits to hide internal stuff that needs to be generic within the // MLKEM implementation, but I don't want accessed from outside, such as FIPS-internal functions. #![allow(private_bounds)] @@ -250,28 +245,30 @@ use bouncycastle_core::key_material::KeyMaterialTrait; // todo -- crucible tests +mod aux_functions; +mod low_memory_helpers; pub mod mlkem; mod mlkem_keys; mod polynomial; -mod aux_functions; -mod low_memory_helpers; /*** Exported types ***/ -pub use mlkem::{MLKEMTrait, MLKEM, MLKEM512, MLKEM768, MLKEM1024}; +pub use mlkem::{MLKEM, MLKEM512, MLKEM768, MLKEM1024, MLKEMTrait}; +pub use mlkem_keys::{ + MLKEM512PrivateKey, MLKEM768PrivateKey, MLKEM1024PrivateKey, MLKEMSeedPrivateKey, +}; +pub use mlkem_keys::{MLKEM512PublicKey, MLKEM768PublicKey, MLKEM1024PublicKey, MLKEMPublicKey}; pub use mlkem_keys::{MLKEMPrivateKeyTrait, MLKEMPublicKeyTrait}; -pub use mlkem_keys::{MLKEMPublicKey, MLKEM512PublicKey, MLKEM768PublicKey, MLKEM1024PublicKey}; -pub use mlkem_keys::{MLKEMSeedPrivateKey, MLKEM512PrivateKey, MLKEM768PrivateKey, MLKEM1024PrivateKey}; /*** Exported constants ***/ pub use mlkem::ML_KEM_512_NAME; pub use mlkem::ML_KEM_768_NAME; pub use mlkem::ML_KEM_1024_NAME; -pub use mlkem::{MLKEM_SEED_LEN, MLKEM_SS_LEN, MLKEM_RND_LEN}; +pub use mlkem::{MLKEM_RND_LEN, MLKEM_SEED_LEN, MLKEM_SS_LEN}; -pub use mlkem::{MLKEM512_PK_LEN, MLKEM512_SK_LEN, MLKEM512_CT_LEN}; -pub use mlkem::{MLKEM768_PK_LEN, MLKEM768_SK_LEN, MLKEM768_CT_LEN}; -pub use mlkem::{MLKEM1024_PK_LEN, MLKEM1024_SK_LEN, MLKEM1024_CT_LEN}; +pub use mlkem::{MLKEM512_CT_LEN, MLKEM512_PK_LEN, MLKEM512_SK_LEN}; +pub use mlkem::{MLKEM768_CT_LEN, MLKEM768_PK_LEN, MLKEM768_SK_LEN}; +pub use mlkem::{MLKEM1024_CT_LEN, MLKEM1024_PK_LEN, MLKEM1024_SK_LEN}; // re-export just so it's visible to unit tests -pub use polynomial::Polynomial; \ No newline at end of file +pub use polynomial::Polynomial; diff --git a/crypto/mlkem_lowmemory/src/mlkem.rs b/crypto/mlkem_lowmemory/src/mlkem.rs index 13f9c9c..9a32ca8 100644 --- a/crypto/mlkem_lowmemory/src/mlkem.rs +++ b/crypto/mlkem_lowmemory/src/mlkem.rs @@ -4,7 +4,9 @@ use core::marker::PhantomData; use bouncycastle_core::errors::{KEMError}; use bouncycastle_core::key_material::{KeyMaterial, KeyType, KeyMaterialTrait}; -use bouncycastle_core::traits::{RNG, SecurityStrength, XOF, Algorithm, Hash, KEM}; +use bouncycastle_core::traits::{ + Algorithm, Hash, KEMDecapsulator, KEMEncapsulator, RNG, SecurityStrength, XOF, +}; use bouncycastle_rng::{HashDRBG_SHA512}; use bouncycastle_sha3::{SHA3_256, SHA3_512, SHAKE256}; use bouncycastle_utils::ct::{conditional_copy_bytes, ct_eq_bytes}; @@ -232,6 +234,15 @@ impl< T_PACKED_LEN, > { + /// Generate a keypair, sourcing randomness from bouncycastle's default os-backed RNG. + /// + /// Key generation is intentionally not part of the [KEMEncapsulator] / [KEMDecapsulator] traits; + /// it is provided as an inherent associated function directly on the algorithm struct. + /// Error condition: basically only on RNG failures. + pub fn keygen() -> Result<(PK, SK), KEMError> { + Self::keygen_from_os_rng() + } + /// Should still be ok in FIPS mode pub fn keygen_from_os_rng() -> Result< (PK, SK), @@ -334,13 +345,13 @@ impl< /// Output: shared secret key 𝐾 ∈ 𝔹32 . /// Output: ciphertext 𝑐 ∈ 𝔹32(π‘‘π‘’π‘˜+𝑑𝑣). /// - /// Unlike the more public function exposed by [KEM::encaps], this returns the shared secret as raw bytes + /// Unlike the more public function exposed by [KEMEncapsulator::encaps], this returns the shared secret as raw bytes /// instead of wrapped in an appropriately-set [KeyMaterialTrait], so you're on your own for handling it properly. /// /// Note: this is an internal function that allows the caller to specify the encapsulation /// randomness (which is the message `m` to be encrypted by the underlying PKE scheme). /// This function should not be used directly unless you really have a - /// good reason. [KEM::encaps] should be used in 99.9% of cases. + /// good reason. [KEMEncapsulator::encaps] should be used in 99.9% of cases. /// The reason this is exposed publicly is: A) for unit testing that requires access /// to the deterministically reproducible function, and B) for operational environments /// that wish to provide randomness from their own source instead of the built-in RNG in bc-rust. @@ -644,7 +655,7 @@ impl< const dv: i16, const LAMBDA: i16, const T_PACKED_LEN: usize, -> KEM for MLKEM< +> KEMEncapsulator for MLKEM< PK_LEN, SK_LEN, FULL_SK_LEN, @@ -659,11 +670,6 @@ impl< LAMBDA, T_PACKED_LEN, > { - /// Generates a fresh key pair. - fn keygen() -> Result<(PK, SK), KEMError> { - Self::keygen_from_os_rng() - } - fn encaps(pk: &PK) -> Result<(KeyMaterial, [u8; CT_LEN]), KEMError> { let mut m = [0u8; 32]; HashDRBG_SHA512::new_from_os().next_bytes_out(&mut m)?; @@ -678,7 +684,37 @@ impl< Ok((ss_keymaterial, ct)) } +} +impl< + const PK_LEN: usize, + const SK_LEN: usize, + const FULL_SK_LEN: usize, + const CT_LEN: usize, + const SS_LEN: usize, + PK: MLKEMPublicKeyTrait + MLKEMPublicKeyInternalTrait, + SK: MLKEMPrivateKeyTrait + MLKEMPrivateKeyInternalTrait, + const k: usize, + const eta: i16, + const du: i16, + const dv: i16, + const LAMBDA: i16, + const T_PACKED_LEN: usize, +> KEMDecapsulator for MLKEM< + PK_LEN, + SK_LEN, + FULL_SK_LEN, + CT_LEN, + SS_LEN, + PK, + SK, + k, + eta, + du, + dv, + LAMBDA, + T_PACKED_LEN, +> { fn decaps(sk: &SK, ct: &[u8]) -> Result, KEMError> { if ct.len() != CT_LEN { diff --git a/crypto/mlkem_lowmemory/tests/mlkem_key_tests.rs b/crypto/mlkem_lowmemory/tests/mlkem_key_tests.rs index c7c942b..dc79729 100644 --- a/crypto/mlkem_lowmemory/tests/mlkem_key_tests.rs +++ b/crypto/mlkem_lowmemory/tests/mlkem_key_tests.rs @@ -1,12 +1,12 @@ #[cfg(test)] mod mlkem_key_tests { use bouncycastle_core::key_material::{KeyMaterial512, KeyMaterialTrait, KeyType}; - use bouncycastle_core::traits::{KEM, KEMPrivateKey, KEMPublicKey, SecurityStrength}; + use bouncycastle_core::traits::{KEMPrivateKey, KEMPublicKey, SecurityStrength}; use bouncycastle_hex as hex; use bouncycastle_mlkem_lowmemory::mlkem::MLKEM512_FULL_SK_LEN; use bouncycastle_mlkem_lowmemory::{ - MLKEM_SS_LEN, MLKEM512_CT_LEN, MLKEM512_PK_LEN, MLKEM512_SK_LEN, MLKEM768_CT_LEN, - MLKEM768_PK_LEN, MLKEM768_SK_LEN, MLKEM1024_CT_LEN, MLKEM1024_PK_LEN, MLKEM1024_SK_LEN, + MLKEM512_PK_LEN, MLKEM512_SK_LEN, + MLKEM768_PK_LEN, MLKEM768_SK_LEN, MLKEM1024_PK_LEN, MLKEM1024_SK_LEN, }; use bouncycastle_mlkem_lowmemory::{MLKEM512, MLKEM768, MLKEM1024}; use bouncycastle_mlkem_lowmemory::{ @@ -20,9 +20,9 @@ mod mlkem_key_tests { use bouncycastle_core_test_framework::kem::TestFrameworkKEMKeys; let tf = TestFrameworkKEMKeys::new(); - tf.test_keys::(); - tf.test_keys::(); - tf.test_keys::(); + tf.test_keys::(MLKEM512::keygen); + tf.test_keys::(MLKEM768::keygen); + tf.test_keys::(MLKEM1024::keygen); } #[test] diff --git a/crypto/mlkem_lowmemory/tests/mlkem_tests.rs b/crypto/mlkem_lowmemory/tests/mlkem_tests.rs index 328c90c..e93500d 100644 --- a/crypto/mlkem_lowmemory/tests/mlkem_tests.rs +++ b/crypto/mlkem_lowmemory/tests/mlkem_tests.rs @@ -3,7 +3,7 @@ mod mlkem_tests { use bouncycastle_core::errors::KEMError; use bouncycastle_core::key_material::{KeyMaterialTrait, KeyMaterial512, KeyType}; - use bouncycastle_core::traits::{KEMPrivateKey, KEMPublicKey, SecurityStrength, KEM, XOF}; + use bouncycastle_core::traits::{KEMDecapsulator, KEMEncapsulator, KEMPrivateKey, KEMPublicKey, SecurityStrength, XOF}; use bouncycastle_mlkem_lowmemory::{MLKEM512, MLKEM768, MLKEM1024, MLKEM_RND_LEN, MLKEM_SEED_LEN, Polynomial}; use bouncycastle_mlkem_lowmemory::{MLKEM512PrivateKey, MLKEM512PublicKey, MLKEM768PrivateKey, MLKEM768PublicKey, MLKEM1024PrivateKey, MLKEM1024PublicKey}; use bouncycastle_mlkem_lowmemory::{MLKEMPrivateKeyTrait, MLKEMTrait}; @@ -36,9 +36,9 @@ mod mlkem_tests { let tf = TestFrameworkKEM::new(false, true); - tf.test_kem::(false); - tf.test_kem::(false); - tf.test_kem::(false); + tf.test_kem::(MLKEM512::keygen, false); + tf.test_kem::(MLKEM768::keygen, false); + tf.test_kem::(MLKEM1024::keygen, false); } /// This runs the full bitflipping tests and takes about 1.5 mins.. diff --git a/crypto/mlkem_lowmemory/tests/wycheproof.rs b/crypto/mlkem_lowmemory/tests/wycheproof.rs index b331a3f..f5570c6 100644 --- a/crypto/mlkem_lowmemory/tests/wycheproof.rs +++ b/crypto/mlkem_lowmemory/tests/wycheproof.rs @@ -25,7 +25,7 @@ #![allow(dead_code)] use bouncycastle_core::key_material::{KeyMaterial512, KeyMaterialTrait, KeyType}; -use bouncycastle_core::traits::{KEM, KEMPublicKey, SecurityStrength}; +use bouncycastle_core::traits::{KEMDecapsulator, KEMPublicKey, SecurityStrength}; use bouncycastle_hex as hex; use bouncycastle_mlkem_lowmemory::{ MLKEM512, MLKEM512PublicKey, MLKEM768, MLKEM768PublicKey, MLKEM1024, MLKEM1024PublicKey, diff --git a/mem_usage_benches/bench_mlkem_mem_usage.rs b/mem_usage_benches/bench_mlkem_mem_usage.rs index 494621f..0da3360 100644 --- a/mem_usage_benches/bench_mlkem_mem_usage.rs +++ b/mem_usage_benches/bench_mlkem_mem_usage.rs @@ -26,7 +26,7 @@ #![allow(unused_imports)] use bouncycastle::core::key_material::{KeyMaterial512, KeyType}; -use bouncycastle::core::traits::{KEMPublicKey, KEM}; +use bouncycastle::core::traits::{KEMDecapsulator, KEMEncapsulator, KEMPublicKey}; use bouncycastle::mlkem::mlkem::{MLKEMTrait}; use bouncycastle::mlkem::{MLKEM1024_CT_LEN, MLKEM1024_PK_LEN, MLKEM512_CT_LEN, MLKEM512_PK_LEN, MLKEM768_CT_LEN, MLKEM768_PK_LEN}; From f828c023ecb721078c8992927338ecfc7345720e Mon Sep 17 00:00:00 2001 From: Mike Ounsworth Date: Thu, 11 Jun 2026 14:54:59 -0500 Subject: [PATCH 08/13] tweaked todo list --- alpha_0.1.2_release_notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/alpha_0.1.2_release_notes.md b/alpha_0.1.2_release_notes.md index d6609db..afb4af1 100644 --- a/alpha_0.1.2_release_notes.md +++ b/alpha_0.1.2_release_notes.md @@ -47,6 +47,8 @@ Box is for? * Deal with as many of the inline TODOs as possible * Close all open github issues and document them in this file. +* After everything is merged, circle back to crucible, and make sure that the harness still works (and maybe remove the + nightly build toolchain) # 0.1.2 Features / Changelog From e7eafba3205452d7f5259b117fc7bb0c14758010 Mon Sep 17 00:00:00 2001 From: Mike Ounsworth Date: Thu, 11 Jun 2026 15:02:22 -0500 Subject: [PATCH 09/13] dir rename to use hyphen instead of underscore --- Cargo.toml | 22 +++++++++---------- .../Cargo.toml | 0 .../benches/mldsa_benches.rs | 0 .../benches/note_on_mem_usage_benches.md | 0 .../src/aux_functions.rs | 0 .../src/hash_mldsa.rs | 0 .../src/lib.rs | 0 .../src/low_memory_helpers.rs | 0 .../src/mldsa.rs | 0 .../src/mldsa_keys.rs | 0 .../src/polynomial.rs | 0 .../tests/bc_test_data.rs | 0 .../tests/hash_mldsa_tests.rs | 0 .../tests/mldsa_key_tests.rs | 0 .../tests/mldsa_tests.rs | 0 .../tests/wycheproof.rs | 0 .../Cargo.toml | 0 .../benches/mlkem_benches.rs | 0 .../src/aux_functions.rs | 0 .../src/lib.rs | 0 .../src/low_memory_helpers.rs | 0 .../src/mlkem.rs | 0 .../src/mlkem_keys.rs | 0 .../src/polynomial.rs | 0 .../tests/bc_test_data.rs | 0 .../tests/mlkem_key_tests.rs | 0 .../tests/mlkem_tests.rs | 0 .../tests/wycheproof.rs | 0 28 files changed, 11 insertions(+), 11 deletions(-) rename crypto/{mldsa_lowmemory => mldsa-lowmemory}/Cargo.toml (100%) rename crypto/{mldsa_lowmemory => mldsa-lowmemory}/benches/mldsa_benches.rs (100%) rename crypto/{mldsa_lowmemory => mldsa-lowmemory}/benches/note_on_mem_usage_benches.md (100%) rename crypto/{mldsa_lowmemory => mldsa-lowmemory}/src/aux_functions.rs (100%) rename crypto/{mldsa_lowmemory => mldsa-lowmemory}/src/hash_mldsa.rs (100%) rename crypto/{mldsa_lowmemory => mldsa-lowmemory}/src/lib.rs (100%) rename crypto/{mldsa_lowmemory => mldsa-lowmemory}/src/low_memory_helpers.rs (100%) rename crypto/{mldsa_lowmemory => mldsa-lowmemory}/src/mldsa.rs (100%) rename crypto/{mldsa_lowmemory => mldsa-lowmemory}/src/mldsa_keys.rs (100%) rename crypto/{mldsa_lowmemory => mldsa-lowmemory}/src/polynomial.rs (100%) rename crypto/{mldsa_lowmemory => mldsa-lowmemory}/tests/bc_test_data.rs (100%) rename crypto/{mldsa_lowmemory => mldsa-lowmemory}/tests/hash_mldsa_tests.rs (100%) rename crypto/{mldsa_lowmemory => mldsa-lowmemory}/tests/mldsa_key_tests.rs (100%) rename crypto/{mldsa_lowmemory => mldsa-lowmemory}/tests/mldsa_tests.rs (100%) rename crypto/{mldsa_lowmemory => mldsa-lowmemory}/tests/wycheproof.rs (100%) rename crypto/{mlkem_lowmemory => mlkem-lowmemory}/Cargo.toml (100%) rename crypto/{mlkem_lowmemory => mlkem-lowmemory}/benches/mlkem_benches.rs (100%) rename crypto/{mlkem_lowmemory => mlkem-lowmemory}/src/aux_functions.rs (100%) rename crypto/{mlkem_lowmemory => mlkem-lowmemory}/src/lib.rs (100%) rename crypto/{mlkem_lowmemory => mlkem-lowmemory}/src/low_memory_helpers.rs (100%) rename crypto/{mlkem_lowmemory => mlkem-lowmemory}/src/mlkem.rs (100%) rename crypto/{mlkem_lowmemory => mlkem-lowmemory}/src/mlkem_keys.rs (100%) rename crypto/{mlkem_lowmemory => mlkem-lowmemory}/src/polynomial.rs (100%) rename crypto/{mlkem_lowmemory => mlkem-lowmemory}/tests/bc_test_data.rs (100%) rename crypto/{mlkem_lowmemory => mlkem-lowmemory}/tests/mlkem_key_tests.rs (100%) rename crypto/{mlkem_lowmemory => mlkem-lowmemory}/tests/mlkem_tests.rs (100%) rename crypto/{mlkem_lowmemory => mlkem-lowmemory}/tests/wycheproof.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index ecf3f90..4301f8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = [ "cli", "crypto/*", "mem_usage_benches" ] +members = ["cli", "crypto/*", "mem_usage_benches"] [workspace.package] edition = "2024" @@ -8,21 +8,21 @@ edition = "2024" # *** Internal Dependencies *** bouncycastle = { path = "./", version = "0.1.1" } -bouncycastle-base64 = { path = "./crypto/base64", version = "0.1.1"} +bouncycastle-base64 = { path = "./crypto/base64", version = "0.1.1" } bouncycastle-core = { path = "crypto/core", version = "0.1.1" } -bouncycastle-core-test-framework = { path = "./crypto/core-test-framework", version = "0.1.1"} -bouncycastle-factory = { path = "./crypto/factory", version = "0.1.1"} +bouncycastle-core-test-framework = { path = "./crypto/core-test-framework", version = "0.1.1" } +bouncycastle-factory = { path = "./crypto/factory", version = "0.1.1" } bouncycastle-hex = { path = "./crypto/hex", version = "0.1.1" } -bouncycastle-hkdf = { path = "./crypto/hkdf", version = "0.1.1"} -bouncycastle-hmac = { path = "./crypto/hmac", version = "0.1.1"} +bouncycastle-hkdf = { path = "./crypto/hkdf", version = "0.1.1" } +bouncycastle-hmac = { path = "./crypto/hmac", version = "0.1.1" } bouncycastle-mlkem = { path = "./crypto/mlkem", version = "0.1.2" } -bouncycastle-mlkem-lowmemory = { path = "./crypto/mlkem_lowmemory", version = "0.1.2" } +bouncycastle-mlkem-lowmemory = { path = "./crypto/mlkem-lowmemory", version = "0.1.2" } bouncycastle-mldsa = { path = "./crypto/mldsa", version = "0.1.2" } -bouncycastle-mldsa-lowmemory = { path = "./crypto/mldsa_lowmemory", version = "0.1.2" } +bouncycastle-mldsa-lowmemory = { path = "./crypto/mldsa-lowmemory", version = "0.1.2" } bouncycastle-rng = { path = "./crypto/rng", version = "0.1.1" } -bouncycastle-sha2 = { path = "./crypto/sha2", version = "0.1.1"} -bouncycastle-sha3 = { path = "./crypto/sha3", version = "0.1.1"} -bouncycastle-utils = { path = "./crypto/utils", version = "0.1.1"} +bouncycastle-sha2 = { path = "./crypto/sha2", version = "0.1.1" } +bouncycastle-sha3 = { path = "./crypto/sha3", version = "0.1.1" } +bouncycastle-utils = { path = "./crypto/utils", version = "0.1.1" } # *** External Dependencies *** diff --git a/crypto/mldsa_lowmemory/Cargo.toml b/crypto/mldsa-lowmemory/Cargo.toml similarity index 100% rename from crypto/mldsa_lowmemory/Cargo.toml rename to crypto/mldsa-lowmemory/Cargo.toml diff --git a/crypto/mldsa_lowmemory/benches/mldsa_benches.rs b/crypto/mldsa-lowmemory/benches/mldsa_benches.rs similarity index 100% rename from crypto/mldsa_lowmemory/benches/mldsa_benches.rs rename to crypto/mldsa-lowmemory/benches/mldsa_benches.rs diff --git a/crypto/mldsa_lowmemory/benches/note_on_mem_usage_benches.md b/crypto/mldsa-lowmemory/benches/note_on_mem_usage_benches.md similarity index 100% rename from crypto/mldsa_lowmemory/benches/note_on_mem_usage_benches.md rename to crypto/mldsa-lowmemory/benches/note_on_mem_usage_benches.md diff --git a/crypto/mldsa_lowmemory/src/aux_functions.rs b/crypto/mldsa-lowmemory/src/aux_functions.rs similarity index 100% rename from crypto/mldsa_lowmemory/src/aux_functions.rs rename to crypto/mldsa-lowmemory/src/aux_functions.rs diff --git a/crypto/mldsa_lowmemory/src/hash_mldsa.rs b/crypto/mldsa-lowmemory/src/hash_mldsa.rs similarity index 100% rename from crypto/mldsa_lowmemory/src/hash_mldsa.rs rename to crypto/mldsa-lowmemory/src/hash_mldsa.rs diff --git a/crypto/mldsa_lowmemory/src/lib.rs b/crypto/mldsa-lowmemory/src/lib.rs similarity index 100% rename from crypto/mldsa_lowmemory/src/lib.rs rename to crypto/mldsa-lowmemory/src/lib.rs diff --git a/crypto/mldsa_lowmemory/src/low_memory_helpers.rs b/crypto/mldsa-lowmemory/src/low_memory_helpers.rs similarity index 100% rename from crypto/mldsa_lowmemory/src/low_memory_helpers.rs rename to crypto/mldsa-lowmemory/src/low_memory_helpers.rs diff --git a/crypto/mldsa_lowmemory/src/mldsa.rs b/crypto/mldsa-lowmemory/src/mldsa.rs similarity index 100% rename from crypto/mldsa_lowmemory/src/mldsa.rs rename to crypto/mldsa-lowmemory/src/mldsa.rs diff --git a/crypto/mldsa_lowmemory/src/mldsa_keys.rs b/crypto/mldsa-lowmemory/src/mldsa_keys.rs similarity index 100% rename from crypto/mldsa_lowmemory/src/mldsa_keys.rs rename to crypto/mldsa-lowmemory/src/mldsa_keys.rs diff --git a/crypto/mldsa_lowmemory/src/polynomial.rs b/crypto/mldsa-lowmemory/src/polynomial.rs similarity index 100% rename from crypto/mldsa_lowmemory/src/polynomial.rs rename to crypto/mldsa-lowmemory/src/polynomial.rs diff --git a/crypto/mldsa_lowmemory/tests/bc_test_data.rs b/crypto/mldsa-lowmemory/tests/bc_test_data.rs similarity index 100% rename from crypto/mldsa_lowmemory/tests/bc_test_data.rs rename to crypto/mldsa-lowmemory/tests/bc_test_data.rs diff --git a/crypto/mldsa_lowmemory/tests/hash_mldsa_tests.rs b/crypto/mldsa-lowmemory/tests/hash_mldsa_tests.rs similarity index 100% rename from crypto/mldsa_lowmemory/tests/hash_mldsa_tests.rs rename to crypto/mldsa-lowmemory/tests/hash_mldsa_tests.rs diff --git a/crypto/mldsa_lowmemory/tests/mldsa_key_tests.rs b/crypto/mldsa-lowmemory/tests/mldsa_key_tests.rs similarity index 100% rename from crypto/mldsa_lowmemory/tests/mldsa_key_tests.rs rename to crypto/mldsa-lowmemory/tests/mldsa_key_tests.rs diff --git a/crypto/mldsa_lowmemory/tests/mldsa_tests.rs b/crypto/mldsa-lowmemory/tests/mldsa_tests.rs similarity index 100% rename from crypto/mldsa_lowmemory/tests/mldsa_tests.rs rename to crypto/mldsa-lowmemory/tests/mldsa_tests.rs diff --git a/crypto/mldsa_lowmemory/tests/wycheproof.rs b/crypto/mldsa-lowmemory/tests/wycheproof.rs similarity index 100% rename from crypto/mldsa_lowmemory/tests/wycheproof.rs rename to crypto/mldsa-lowmemory/tests/wycheproof.rs diff --git a/crypto/mlkem_lowmemory/Cargo.toml b/crypto/mlkem-lowmemory/Cargo.toml similarity index 100% rename from crypto/mlkem_lowmemory/Cargo.toml rename to crypto/mlkem-lowmemory/Cargo.toml diff --git a/crypto/mlkem_lowmemory/benches/mlkem_benches.rs b/crypto/mlkem-lowmemory/benches/mlkem_benches.rs similarity index 100% rename from crypto/mlkem_lowmemory/benches/mlkem_benches.rs rename to crypto/mlkem-lowmemory/benches/mlkem_benches.rs diff --git a/crypto/mlkem_lowmemory/src/aux_functions.rs b/crypto/mlkem-lowmemory/src/aux_functions.rs similarity index 100% rename from crypto/mlkem_lowmemory/src/aux_functions.rs rename to crypto/mlkem-lowmemory/src/aux_functions.rs diff --git a/crypto/mlkem_lowmemory/src/lib.rs b/crypto/mlkem-lowmemory/src/lib.rs similarity index 100% rename from crypto/mlkem_lowmemory/src/lib.rs rename to crypto/mlkem-lowmemory/src/lib.rs diff --git a/crypto/mlkem_lowmemory/src/low_memory_helpers.rs b/crypto/mlkem-lowmemory/src/low_memory_helpers.rs similarity index 100% rename from crypto/mlkem_lowmemory/src/low_memory_helpers.rs rename to crypto/mlkem-lowmemory/src/low_memory_helpers.rs diff --git a/crypto/mlkem_lowmemory/src/mlkem.rs b/crypto/mlkem-lowmemory/src/mlkem.rs similarity index 100% rename from crypto/mlkem_lowmemory/src/mlkem.rs rename to crypto/mlkem-lowmemory/src/mlkem.rs diff --git a/crypto/mlkem_lowmemory/src/mlkem_keys.rs b/crypto/mlkem-lowmemory/src/mlkem_keys.rs similarity index 100% rename from crypto/mlkem_lowmemory/src/mlkem_keys.rs rename to crypto/mlkem-lowmemory/src/mlkem_keys.rs diff --git a/crypto/mlkem_lowmemory/src/polynomial.rs b/crypto/mlkem-lowmemory/src/polynomial.rs similarity index 100% rename from crypto/mlkem_lowmemory/src/polynomial.rs rename to crypto/mlkem-lowmemory/src/polynomial.rs diff --git a/crypto/mlkem_lowmemory/tests/bc_test_data.rs b/crypto/mlkem-lowmemory/tests/bc_test_data.rs similarity index 100% rename from crypto/mlkem_lowmemory/tests/bc_test_data.rs rename to crypto/mlkem-lowmemory/tests/bc_test_data.rs diff --git a/crypto/mlkem_lowmemory/tests/mlkem_key_tests.rs b/crypto/mlkem-lowmemory/tests/mlkem_key_tests.rs similarity index 100% rename from crypto/mlkem_lowmemory/tests/mlkem_key_tests.rs rename to crypto/mlkem-lowmemory/tests/mlkem_key_tests.rs diff --git a/crypto/mlkem_lowmemory/tests/mlkem_tests.rs b/crypto/mlkem-lowmemory/tests/mlkem_tests.rs similarity index 100% rename from crypto/mlkem_lowmemory/tests/mlkem_tests.rs rename to crypto/mlkem-lowmemory/tests/mlkem_tests.rs diff --git a/crypto/mlkem_lowmemory/tests/wycheproof.rs b/crypto/mlkem-lowmemory/tests/wycheproof.rs similarity index 100% rename from crypto/mlkem_lowmemory/tests/wycheproof.rs rename to crypto/mlkem-lowmemory/tests/wycheproof.rs From dac74d0ef5b80c8132c8a302c1f8eb4d261a35ee Mon Sep 17 00:00:00 2001 From: Mike Ounsworth Date: Sun, 7 Jun 2026 21:08:36 -0500 Subject: [PATCH 10/13] removed nightly feature from mldsa --- alpha_0.1.2_release_notes.md | 2 ++ crypto/core/src/lib.rs | 1 - crypto/mldsa/src/hash_mldsa.rs | 51 +++++++++++++++++++------------ crypto/mldsa/src/lib.rs | 11 +++---- crypto/rng/src/hash_drbg80090a.rs | 2 ++ crypto/rng/src/lib.rs | 2 -- 6 files changed, 39 insertions(+), 30 deletions(-) diff --git a/alpha_0.1.2_release_notes.md b/alpha_0.1.2_release_notes.md index afb4af1..f4a4bad 100644 --- a/alpha_0.1.2_release_notes.md +++ b/alpha_0.1.2_release_notes.md @@ -21,6 +21,8 @@ appropriate. * Probably it makes sense to leave Hex and Base64 as requiring std; ... or maybe add a no_std version that uses fixed-sized blocks? +* Make this build on the stable compiler. IE Remove the rust-toolchain.toml file that builds with nightly. Will require + some refactoring. * Create a cargo feature #[cfg(feature='rng')] and put it around things like keygen that takes an rng so that the build dependency on bouncycastle_rng is optional. * Enhance the default HashDRBG instantiation to take in NIST-compatible CPU jitter entropy? Or not? Maybe this is the diff --git a/crypto/core/src/lib.rs b/crypto/core/src/lib.rs index cb0d8d8..379e54c 100644 --- a/crypto/core/src/lib.rs +++ b/crypto/core/src/lib.rs @@ -3,7 +3,6 @@ // todo -- this is the goal, but first need to remove all the Vec in favour of compile-time array sizing. // #![no_std] -#![feature(adt_const_params)] #![forbid(unsafe_code)] pub mod errors; diff --git a/crypto/mldsa/src/hash_mldsa.rs b/crypto/mldsa/src/hash_mldsa.rs index 52fbdc8..8803fc6 100644 --- a/crypto/mldsa/src/hash_mldsa.rs +++ b/crypto/mldsa/src/hash_mldsa.rs @@ -94,7 +94,7 @@ use bouncycastle_core::traits::{ Algorithm, Hash, PHSignature, RNG, SecurityStrength, Signature, XOF, }; use bouncycastle_rng::HashDRBG_SHA512; -use bouncycastle_sha2::{SHA256, SHA512}; +use bouncycastle_sha2::{SHA256, SHA256_NAME, SHA512, SHA512_NAME}; use core::marker::PhantomData; // Imports needed only for docs @@ -126,7 +126,6 @@ pub const HASH_ML_DSA_87_WITH_SHA512_NAME: &str = "HashML-DSA-87_with_SHA512"; pub type HashMLDSA44_with_SHA256 = HashMLDSA< SHA256, 32, - SHA256_OID, MLDSA44_PK_LEN, MLDSA44_SK_LEN, MLDSA44_SIG_LEN, @@ -160,7 +159,6 @@ impl Algorithm for HashMLDSA44_with_SHA256 { pub type HashMLDSA65_with_SHA256 = HashMLDSA< SHA256, 32, - SHA256_OID, MLDSA65_PK_LEN, MLDSA65_SK_LEN, MLDSA65_SIG_LEN, @@ -194,7 +192,6 @@ impl Algorithm for HashMLDSA65_with_SHA256 { pub type HashMLDSA87_with_SHA256 = HashMLDSA< SHA256, 32, - SHA256_OID, MLDSA87_PK_LEN, MLDSA87_SK_LEN, MLDSA87_SIG_LEN, @@ -228,7 +225,6 @@ impl Algorithm for HashMLDSA87_with_SHA256 { pub type HashMLDSA44_with_SHA512 = HashMLDSA< SHA512, 64, - SHA512_OID, MLDSA44_PK_LEN, MLDSA44_SK_LEN, MLDSA44_SIG_LEN, @@ -262,7 +258,6 @@ impl Algorithm for HashMLDSA44_with_SHA512 { pub type HashMLDSA65_with_SHA512 = HashMLDSA< SHA512, 64, - SHA512_OID, MLDSA65_PK_LEN, MLDSA65_SK_LEN, MLDSA65_SIG_LEN, @@ -296,7 +291,6 @@ impl Algorithm for HashMLDSA65_with_SHA512 { pub type HashMLDSA87_with_SHA512 = HashMLDSA< SHA512, 64, - SHA512_OID, MLDSA87_PK_LEN, MLDSA87_SK_LEN, MLDSA87_SIG_LEN, @@ -332,9 +326,8 @@ impl Algorithm for HashMLDSA87_with_SHA512 { /// by specifying the hash function to use (in the verifier), and specifying the bytes of the OID to /// to use as its domain separator in constructing the message representative M'. pub struct HashMLDSA< - HASH: Hash + Default, + HASH: Hash + Algorithm + Default, const HASH_LEN: usize, - const oid: &'static [u8], const PK_LEN: usize, const SK_LEN: usize, const SIG_LEN: usize, @@ -381,9 +374,8 @@ pub struct HashMLDSA< } impl< - HASH: Hash + Default, + HASH: Hash + Algorithm + Default, const PH_LEN: usize, - const oid: &'static [u8], const PK_LEN: usize, const SK_LEN: usize, const SIG_LEN: usize, @@ -410,7 +402,6 @@ impl< HashMLDSA< HASH, PH_LEN, - oid, PK_LEN, SK_LEN, SIG_LEN, @@ -574,7 +565,20 @@ impl< h.absorb(&[1u8]); h.absorb(&[ctx.len() as u8]); h.absorb(ctx); - h.absorb(oid); + + // this is all statics, so the branch should compile out. + // Really, this should be a generic param of HashMLDSA, but unsized_const_params is currently + // a nightly-only feature. + match HASH::ALG_NAME { + SHA256_NAME => h.absorb(SHA256_OID), + SHA512_NAME => h.absorb(SHA512_OID), + _ => { + return Err(SignatureError::GenericError( + "Unsupported hash algorithm; you need to add it to the switch", + )); + } + }; + h.absorb(ph); let mut mu = [0u8; MLDSA_MU_LEN]; let bytes_written = h.squeeze_out(&mut mu); @@ -697,7 +701,18 @@ impl< h.absorb(&[1u8]); h.absorb(&[ctx.len() as u8]); h.absorb(ctx); - h.absorb(oid); + // this is all statics, so the branch should compile out. + // Really, this should be a generic param of HashMLDSA, but unsized_const_params is currently + // a nightly-only feature. + match HASH::ALG_NAME { + SHA256_NAME => h.absorb(SHA256_OID), + SHA512_NAME => h.absorb(SHA512_OID), + _ => { + return Err(SignatureError::GenericError( + "Unsupported hash algorithm; you need to add it to the switch", + )); + } + }; h.absorb(ph); let mut mu = [0u8; MLDSA_MU_LEN]; _ = h.squeeze_out(&mut mu); @@ -771,12 +786,11 @@ impl< } impl< - HASH: Hash + Default, + HASH: Hash + Algorithm + Default, PK: MLDSAPublicKeyTrait + MLDSAPublicKeyInternalTrait, SK: MLDSAPrivateKeyTrait + MLDSAPrivateKeyInternalTrait, const PH_LEN: usize, - const oid: &'static [u8], const PK_LEN: usize, const SK_LEN: usize, const SIG_LEN: usize, @@ -800,7 +814,6 @@ impl< for HashMLDSA< HASH, PH_LEN, - oid, PK_LEN, SK_LEN, SIG_LEN, @@ -981,9 +994,8 @@ impl< } impl< - HASH: Hash + Default, + HASH: Hash + Algorithm + Default, const PH_LEN: usize, - const oid: &'static [u8], const PK_LEN: usize, const SK_LEN: usize, const SIG_LEN: usize, @@ -1010,7 +1022,6 @@ impl< for HashMLDSA< HASH, PH_LEN, - oid, PK_LEN, SK_LEN, SIG_LEN, diff --git a/crypto/mldsa/src/lib.rs b/crypto/mldsa/src/lib.rs index 06e37f9..9c3a2b8 100644 --- a/crypto/mldsa/src/lib.rs +++ b/crypto/mldsa/src/lib.rs @@ -115,9 +115,6 @@ #![no_std] #![forbid(missing_docs)] #![forbid(unsafe_code)] -#![allow(incomplete_features)] // needed because currently generic_const_exprs is experimental -#![feature(generic_const_exprs)] -#![feature(adt_const_params)] // These are because I'm matching variable names exactly against FIPS 204, for example both 'K' and 'k', // or 'A' and 'a' are used and have specific meanings. // But need to tell the rust linter to not care. @@ -127,8 +124,10 @@ // MLDSA implementation, but I don't want accessed from outside, such as FIPS-internal functions. #![allow(private_bounds)] #![allow(private_interfaces)] -// Used in HashMLDSA -#![feature(unsized_const_params)] +// Used in HashMLDSA for oid: &'static [u8] params. +// #![allow(incomplete_features)] // needed because currently unsized_const_params is experimental +// #![feature(adt_const_params)] +// #![feature(unsized_const_params)] // imports needed just for docs #[allow(unused_imports)] @@ -136,8 +135,6 @@ use bouncycastle_core::key_material::KeyMaterialTrait; #[allow(unused_imports)] use bouncycastle_core::traits::Signature; -// todo -- re-run mutants - // todo -- crucible tests mod aux_functions; diff --git a/crypto/rng/src/hash_drbg80090a.rs b/crypto/rng/src/hash_drbg80090a.rs index 431d036..75b4177 100644 --- a/crypto/rng/src/hash_drbg80090a.rs +++ b/crypto/rng/src/hash_drbg80090a.rs @@ -67,6 +67,7 @@ const LARGEST_HASHER_OUTPUT_LEN: usize = 64; #[allow(private_bounds)] /// Implementation of the Hash_DRBG algorithm as specified in NIST SP 800-90Ar1. pub struct HashDRBG80090A { + _phantom: core::marker::PhantomData, // Rust is stupid. What's the point of having a generic parameter if we can't use constants inside it? // state: WorkingState, state: WorkingState, @@ -123,6 +124,7 @@ impl HashDRBG80090A { /// and relies on you to provide a strong seed.** pub fn new_unititialized() -> Self { Self { + _phantom: core::marker::PhantomData, state: WorkingState:: { v: [0u8; LARGEST_HASHER_OUTPUT_LEN], c: [0u8; LARGEST_HASHER_OUTPUT_LEN], diff --git a/crypto/rng/src/lib.rs b/crypto/rng/src/lib.rs index dbe62fb..43a65c1 100644 --- a/crypto/rng/src/lib.rs +++ b/crypto/rng/src/lib.rs @@ -28,8 +28,6 @@ //! cryptographic application. #![forbid(unsafe_code)] -#![allow(incomplete_features)] // Need this because generic_const_exprs is currently experimental. -#![feature(generic_const_exprs)] use crate::hash_drbg80090a::{ HashDRBG80090A, HashDRBG80090AParams_SHA256, HashDRBG80090AParams_SHA512, From 8845134a8c3a7bd0e021bc1e612ba03e9106c2bd Mon Sep 17 00:00:00 2001 From: Mike Ounsworth Date: Tue, 9 Jun 2026 18:56:01 -0500 Subject: [PATCH 11/13] adjusted the todo list # Conflicts: # alpha_0.1.2_release_notes.md --- alpha_0.1.2_release_notes.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/alpha_0.1.2_release_notes.md b/alpha_0.1.2_release_notes.md index f4a4bad..9926d0d 100644 --- a/alpha_0.1.2_release_notes.md +++ b/alpha_0.1.2_release_notes.md @@ -54,9 +54,13 @@ # 0.1.2 Features / Changelog -* ML-DSA -* Low-Memory ML-DSA -- runs in about 1/10th of the usual memory (~ 30 kb of stack) with only minor performance impact. +* New algorithms added to crypto/ : + * mldsa (FIPS 204) + * mldsa-lowmemory -- runs in about 1/10th of the usual memory (~ 30 kb of stack) with comparable performance impact. + * mlkem (FIPS 203) + * mlkem-lowmemory -- runs in about 1/4th of the usual memory (~ 12 kb of stack) with comparable performance impact. * All public `*_out(.., out: &mut [u8])` functions now begin by zeroizing the entire output buffer with `.fill(0)`, preventing exposure of stale data in oversized output buffers or on early error returns. * Github issues resolved: - * #2, or whatever \ No newline at end of file + * #6: https://github.com/bcgit/bc-rust/issues/6, thanks to Q. T. Felix (github: @Quant-TheodoreFelix) + * #10: https://github.com/bcgit/bc-rust/issues/10, thanks to Nicola Tuveri (github: @romen) \ No newline at end of file From b9168c94285d11738d36dd52463e8dabbd6df414 Mon Sep 17 00:00:00 2001 From: Mike Ounsworth Date: Wed, 10 Jun 2026 03:05:55 -0500 Subject: [PATCH 12/13] Split the Signature trait into Signer and SignatureVerifier --- cli/src/mldsa_cmd.rs | 2 +- crypto/core-test-framework/src/signature.rs | 146 +++++----- crypto/core/src/traits.rs | 96 +++++-- .../mldsa-lowmemory/benches/mldsa_benches.rs | 2 +- crypto/mldsa-lowmemory/src/hash_mldsa.rs | 260 +++++++++++++++--- crypto/mldsa-lowmemory/src/lib.rs | 7 +- crypto/mldsa-lowmemory/src/mldsa.rs | 113 ++++++-- crypto/mldsa-lowmemory/tests/bc_test_data.rs | 2 +- .../mldsa-lowmemory/tests/hash_mldsa_tests.rs | 22 +- .../mldsa-lowmemory/tests/mldsa_key_tests.rs | 8 +- crypto/mldsa-lowmemory/tests/mldsa_tests.rs | 8 +- crypto/mldsa-lowmemory/tests/wycheproof.rs | 2 +- crypto/mldsa/benches/mldsa_benches.rs | 2 +- crypto/mldsa/src/hash_mldsa.rs | 208 +++++++++++--- crypto/mldsa/src/lib.rs | 7 +- crypto/mldsa/src/mldsa.rs | 98 +++++-- crypto/mldsa/tests/bc_test_data.rs | 2 +- crypto/mldsa/tests/hash_mldsa_tests.rs | 22 +- crypto/mldsa/tests/mldsa_key_tests.rs | 12 +- crypto/mldsa/tests/mldsa_tests.rs | 8 +- crypto/mldsa/tests/wycheproof.rs | 2 +- mem_usage_benches/bench_mldsa_mem_usage.rs | 2 +- 22 files changed, 764 insertions(+), 267 deletions(-) diff --git a/cli/src/mldsa_cmd.rs b/cli/src/mldsa_cmd.rs index 8a1a4e3..e1b9f74 100644 --- a/cli/src/mldsa_cmd.rs +++ b/cli/src/mldsa_cmd.rs @@ -2,7 +2,7 @@ //! by using generics or macros. I just, haven't ... yet. use crate::helpers::{parse_seed, read_from_file, read_from_file_or_stdin, write_bytes_or_hex}; -use bouncycastle::core::traits::{Signature, SignaturePrivateKey, SignaturePublicKey}; +use bouncycastle::core::traits::{SignatureVerifier, Signer, SignaturePrivateKey, SignaturePublicKey}; use bouncycastle::hex; use bouncycastle::mldsa::{ HashMLDSA44_with_SHA512, HashMLDSA65_with_SHA512, HashMLDSA87_with_SHA512, MLDSA_SEED_LEN, diff --git a/crypto/core-test-framework/src/signature.rs b/crypto/core-test-framework/src/signature.rs index d97dc0c..914ae44 100644 --- a/crypto/core-test-framework/src/signature.rs +++ b/crypto/core-test-framework/src/signature.rs @@ -1,7 +1,8 @@ use crate::DUMMY_SEED_1024; use bouncycastle_core::errors::SignatureError; use bouncycastle_core::traits::{ - Hash, PHSignature, Signature, SignaturePrivateKey, SignaturePublicKey, + Hash, PHSignatureVerifier, PHSigner, SignaturePrivateKey, SignaturePublicKey, + SignatureVerifier, Signer, }; pub struct TestFrameworkSignature { @@ -18,54 +19,59 @@ impl TestFrameworkSignature { Self { alg_is_deterministic, alg_accepts_ctx } } - /// Test all the members of trait Hash against the given input-output pair. + /// Test all the members of traits [Signer] and [SignatureVerifier] against the given input-output pair. /// This gives good baseline test coverage, but is not exhaustive. + /// + /// Since key generation is not part of either signature trait, the caller supplies a + /// `keygen` function pointer (the inherent `keygen` associated function on the algorithm struct). pub fn test_signature< PK: SignaturePublicKey, SK: SignaturePrivateKey, - SigAlg: Signature, + SIGNER: Signer, + VERIFIER: SignatureVerifier, const PK_LEN: usize, const SK_LEN: usize, const SIG_LEN: usize, >( &self, + keygen: fn() -> Result<(PK, SK), SignatureError>, run_full_bitflipping_tests: bool, ) { let msg = b"The quick brown fox jumped over the lazy dog"; // Basic test - let (pk, sk) = SigAlg::keygen().unwrap(); - let sig_val = SigAlg::sign(&sk, msg, None).unwrap(); - SigAlg::verify(&pk, msg, None, &sig_val).unwrap(); + let (pk, sk) = keygen().unwrap(); + let sig_val = SIGNER::sign(&sk, msg, None).unwrap(); + VERIFIER::verify(&pk, msg, None, &sig_val).unwrap(); // Test non-determinism if !self.alg_is_deterministic { - let sig1 = SigAlg::sign(&sk, msg, None).unwrap(); - let sig2 = SigAlg::sign(&sk, msg, None).unwrap(); + let sig1 = SIGNER::sign(&sk, msg, None).unwrap(); + let sig2 = SIGNER::sign(&sk, msg, None).unwrap(); assert_ne!(sig1, sig2); } // uses ctx // success case - let sig = SigAlg::sign(&sk, msg, Some(b"test with ctx")).unwrap(); - SigAlg::verify(&pk, msg, Some(b"test with ctx"), &sig).unwrap(); + let sig = SIGNER::sign(&sk, msg, Some(b"test with ctx")).unwrap(); + VERIFIER::verify(&pk, msg, Some(b"test with ctx"), &sig).unwrap(); // but it had better produce something different if !self.alg_accepts_ctx { - let sig1 = SigAlg::sign(&sk, msg, None).unwrap(); - let sig2 = SigAlg::sign(&sk, msg, Some(&[0u8; 1])).unwrap(); + let sig1 = SIGNER::sign(&sk, msg, None).unwrap(); + let sig2 = SIGNER::sign(&sk, msg, Some(&[0u8; 1])).unwrap(); assert_ne!(sig1, sig2); } // Test that verification fails for broken signature value - let (pk, sk) = SigAlg::keygen().unwrap(); - let sig_val = SigAlg::sign(&sk, msg, None).unwrap(); + let (pk, sk) = keygen().unwrap(); + let sig_val = SIGNER::sign(&sk, msg, None).unwrap(); // spot-check let mut sig_val_copy = sig_val.clone(); sig_val_copy[8] ^= 0x0F; // should throw an Err - match SigAlg::verify(&pk, msg, None, &sig_val_copy) { + match VERIFIER::verify(&pk, msg, None, &sig_val_copy) { Err(SignatureError::SignatureVerificationFailed) => (), _ => panic!("This should have thrown an error but it didn't."), } @@ -78,7 +84,7 @@ impl TestFrameworkSignature { sig_val_copy[i] ^= 1 << j; // should throw an Err - match SigAlg::verify(&pk, msg, None, &sig_val_copy) { + match VERIFIER::verify(&pk, msg, None, &sig_val_copy) { Err(SignatureError::SignatureVerificationFailed) => (), _ => panic!( "This should have thrown an error but it didn't when byte {i} bit {j} of the signature was flipped" @@ -93,13 +99,13 @@ impl TestFrameworkSignature { // Success case let mut output = [0u8; SIG_LEN]; - let bytes_written = SigAlg::sign_out(&sk, msg, None, &mut output).unwrap(); + let bytes_written = SIGNER::sign_out(&sk, msg, None, &mut output).unwrap(); assert_eq!(bytes_written, SIG_LEN); - SigAlg::verify(&pk, msg, None, &sig_val).unwrap(); + VERIFIER::verify(&pk, msg, None, &sig_val).unwrap(); // test with a large message - let sig = SigAlg::sign(&sk, DUMMY_SEED_1024, None).unwrap(); - SigAlg::verify(&pk, DUMMY_SEED_1024, None, &sig).unwrap(); + let sig = SIGNER::sign(&sk, DUMMY_SEED_1024, None).unwrap(); + VERIFIER::verify(&pk, DUMMY_SEED_1024, None, &sig).unwrap(); // Test the streaming signing API // fn sign_init(&mut self, sk: &SK) -> Result<(), SignatureError>; @@ -108,37 +114,37 @@ impl TestFrameworkSignature { // fn sign_final_out(&mut self, msg_chunk: &[u8], ctx: &[u8], output: &mut [u8]) -> Result<(), SignatureError>; // First, test the streaming API with one call to .sign_update - let mut s = SigAlg::sign_init(&sk, Some(b"streaming API")).unwrap(); + let mut s = SIGNER::sign_init(&sk, Some(b"streaming API")).unwrap(); s.sign_update(DUMMY_SEED_1024); let sig_val = s.sign_final().unwrap(); - SigAlg::verify(&pk, DUMMY_SEED_1024, Some(b"streaming API"), &sig_val).unwrap(); + VERIFIER::verify(&pk, DUMMY_SEED_1024, Some(b"streaming API"), &sig_val).unwrap(); // Then with the message broken into chunks - let mut s = SigAlg::sign_init(&sk, Some(b"streaming API chunked")).unwrap(); + let mut s = SIGNER::sign_init(&sk, Some(b"streaming API chunked")).unwrap(); for msg_chunk in DUMMY_SEED_1024.chunks(100) { s.sign_update(msg_chunk); } let sig_val = s.sign_final().unwrap(); - SigAlg::verify(&pk, DUMMY_SEED_1024, Some(b"streaming API chunked"), &sig_val).unwrap(); + VERIFIER::verify(&pk, DUMMY_SEED_1024, Some(b"streaming API chunked"), &sig_val).unwrap(); // Test the streaming verification API // one-shot - let sig = SigAlg::sign(&sk, DUMMY_SEED_1024, Some(b"streaming API")).unwrap(); - let mut v = SigAlg::verify_init(&pk, Some(b"streaming API")).unwrap(); + let sig = SIGNER::sign(&sk, DUMMY_SEED_1024, Some(b"streaming API")).unwrap(); + let mut v = VERIFIER::verify_init(&pk, Some(b"streaming API")).unwrap(); v.verify_update(DUMMY_SEED_1024); v.verify_final(&sig).unwrap(); // chunked - let sig = SigAlg::sign(&sk, DUMMY_SEED_1024, Some(b"streaming API")).unwrap(); - let mut v = SigAlg::verify_init(&pk, Some(b"streaming API")).unwrap(); + let sig = SIGNER::sign(&sk, DUMMY_SEED_1024, Some(b"streaming API")).unwrap(); + let mut v = VERIFIER::verify_init(&pk, Some(b"streaming API")).unwrap(); for msg_chunk in DUMMY_SEED_1024.chunks(100) { v.verify_update(msg_chunk); } v.verify_final(&sig).unwrap(); // failure case for streaming verify - let sig = SigAlg::sign(&sk, DUMMY_SEED_1024, Some(b"streaming API")).unwrap(); - let mut v = SigAlg::verify_init(&pk, Some(b"streaming API")).unwrap(); + let sig = SIGNER::sign(&sk, DUMMY_SEED_1024, Some(b"streaming API")).unwrap(); + let mut v = VERIFIER::verify_init(&pk, Some(b"streaming API")).unwrap(); v.verify_update(b"this is the wrong message"); match v.verify_final(&sig) { Err(SignatureError::SignatureVerificationFailed) => (), @@ -146,25 +152,30 @@ impl TestFrameworkSignature { } // test sign_out version of streaming API - let mut s = SigAlg::sign_init(&sk, Some(b"streaming API")).unwrap(); + let mut s = SIGNER::sign_init(&sk, Some(b"streaming API")).unwrap(); s.sign_update(DUMMY_SEED_1024); let mut sig_val = [0u8; SIG_LEN]; let bytes_written = s.sign_final_out(&mut sig_val).unwrap(); assert_eq!(bytes_written, SIG_LEN); - SigAlg::verify(&pk, DUMMY_SEED_1024, Some(b"streaming API"), &sig_val).unwrap(); + VERIFIER::verify(&pk, DUMMY_SEED_1024, Some(b"streaming API"), &sig_val).unwrap(); // the ::verify API should accept a sig value that's too long and just ignore the extra bytes let mut sig_val_too_long = vec![1u8; SIG_LEN + 2]; sig_val_too_long[..SIG_LEN].copy_from_slice(&sig_val); - SigAlg::verify(&pk, DUMMY_SEED_1024, Some(b"streaming API"), &sig_val).unwrap(); + VERIFIER::verify(&pk, DUMMY_SEED_1024, Some(b"streaming API"), &sig_val).unwrap(); } - /// Test all the members of trait Hash against the given input-output pair. + /// Test all the members of traits [PHSigner] and [PHSignatureVerifier] against the given input-output pair. /// This gives good baseline test coverage, but is not exhaustive. + /// + /// Since key generation is not part of either signature trait, the caller supplies a + /// `keygen` function pointer (the inherent `keygen` associated function on the algorithm struct). pub fn test_ph_signature< PK: SignaturePublicKey, SK: SignaturePrivateKey, - SigAlg: PHSignature, + // todo split this into two params: SIGNER: Signer and VERIFIER: SignatureVerifier + PHSIGNER: PHSigner, + PHVERIFIER: PHSignatureVerifier, HASH: Hash + Default, const PK_LEN: usize, const SK_LEN: usize, @@ -172,43 +183,44 @@ impl TestFrameworkSignature { const PH_LEN: usize, >( &self, + keygen: fn() -> Result<(PK, SK), SignatureError>, run_full_bitflipping_tests: bool, ) { let msg = b"The quick brown fox jumped over the lazy dog"; // Basic test - let (pk, sk) = SigAlg::keygen().unwrap(); - let sig_val = SigAlg::sign(&sk, msg, None).unwrap(); - SigAlg::verify(&pk, msg, None, &sig_val).unwrap(); + let (pk, sk) = keygen().unwrap(); + let sig_val = PHSIGNER::sign(&sk, msg, None).unwrap(); + PHVERIFIER::verify(&pk, msg, None, &sig_val).unwrap(); // Test non-determinism if !self.alg_is_deterministic { - let sig1 = SigAlg::sign(&sk, msg, None).unwrap(); - let sig2 = SigAlg::sign(&sk, msg, None).unwrap(); + let sig1 = PHSIGNER::sign(&sk, msg, None).unwrap(); + let sig2 = PHSIGNER::sign(&sk, msg, None).unwrap(); assert_ne!(sig1, sig2); } // uses ctx // success case - let sig = SigAlg::sign(&sk, msg, Some(b"test with ctx")).unwrap(); - SigAlg::verify(&pk, msg, Some(b"test with ctx"), &sig).unwrap(); + let sig = PHSIGNER::sign(&sk, msg, Some(b"test with ctx")).unwrap(); + PHVERIFIER::verify(&pk, msg, Some(b"test with ctx"), &sig).unwrap(); // but it had better produce something different if !self.alg_accepts_ctx { - let sig1 = SigAlg::sign(&sk, msg, None).unwrap(); - let sig2 = SigAlg::sign(&sk, msg, Some(&[0u8; 1])).unwrap(); + let sig1 = PHSIGNER::sign(&sk, msg, None).unwrap(); + let sig2 = PHSIGNER::sign(&sk, msg, Some(&[0u8; 1])).unwrap(); assert_ne!(sig1, sig2); } // Test that verification fails for broken signature value - let (pk, sk) = SigAlg::keygen().unwrap(); - let sig_val = SigAlg::sign(&sk, msg, None).unwrap(); + let (pk, sk) = keygen().unwrap(); + let sig_val = PHSIGNER::sign(&sk, msg, None).unwrap(); // spot-check let mut sig_val_copy = sig_val.clone(); sig_val_copy[8] ^= 0x0F; // should throw an Err - match SigAlg::verify(&pk, msg, None, &sig_val_copy) { + match PHVERIFIER::verify(&pk, msg, None, &sig_val_copy) { Err(SignatureError::SignatureVerificationFailed) => (), _ => panic!("This should have thrown an error but it didn't."), } @@ -221,7 +233,7 @@ impl TestFrameworkSignature { sig_val_copy[i] ^= 1 << j; // should throw an Err - match SigAlg::verify(&pk, msg, None, &sig_val_copy) { + match PHVERIFIER::verify(&pk, msg, None, &sig_val_copy) { Err(SignatureError::SignatureVerificationFailed) => (), _ => panic!( "This should have thrown an error but it didn't when byte {i} bit {j} of the signature was flipped" @@ -236,37 +248,37 @@ impl TestFrameworkSignature { // Success case let mut output = [0u8; SIG_LEN]; - let bytes_written = SigAlg::sign_out(&sk, msg, None, &mut output).unwrap(); + let bytes_written = PHSIGNER::sign_out(&sk, msg, None, &mut output).unwrap(); assert_eq!(bytes_written, SIG_LEN); - SigAlg::verify(&pk, msg, None, &sig_val).unwrap(); + PHVERIFIER::verify(&pk, msg, None, &sig_val).unwrap(); // test with a large message - let sig = SigAlg::sign(&sk, DUMMY_SEED_1024, None).unwrap(); - SigAlg::verify(&pk, DUMMY_SEED_1024, None, &sig).unwrap(); + let sig = PHSIGNER::sign(&sk, DUMMY_SEED_1024, None).unwrap(); + PHVERIFIER::verify(&pk, DUMMY_SEED_1024, None, &sig).unwrap(); // the ::verify API should not accept a sig value that's too let mut sig_val_too_long = vec![1u8; SIG_LEN + 2]; sig_val_too_long[..SIG_LEN].copy_from_slice(&sig); - match SigAlg::verify(&pk, DUMMY_SEED_1024, None, &sig_val_too_long) { + match PHVERIFIER::verify(&pk, DUMMY_SEED_1024, None, &sig_val_too_long) { Err(SignatureError::LengthError(_)) => (), _ => panic!("Unexpected error"), } // sign_ph - let (pk, sk) = SigAlg::keygen().unwrap(); + let (pk, sk) = keygen().unwrap(); let ph: [u8; PH_LEN] = HASH::default().hash(msg)[..PH_LEN].try_into().unwrap(); - let sig_val = SigAlg::sign_ph(&sk, &ph, None).unwrap(); - SigAlg::verify(&pk, msg, None, &sig_val).unwrap(); - SigAlg::verify_ph(&pk, &ph, None, &sig_val).unwrap(); + let sig_val = PHSIGNER::sign_ph(&sk, &ph, None).unwrap(); + PHVERIFIER::verify(&pk, msg, None, &sig_val).unwrap(); + PHVERIFIER::verify_ph(&pk, &ph, None, &sig_val).unwrap(); // sign_ph_out - let (pk, sk) = SigAlg::keygen().unwrap(); + let (pk, sk) = keygen().unwrap(); let ph: [u8; PH_LEN] = HASH::default().hash(msg)[..PH_LEN].try_into().unwrap(); let mut sig_val = [0u8; SIG_LEN]; - let bytes_written = SigAlg::sign_ph_out(&sk, &ph, None, &mut sig_val).unwrap(); + let bytes_written = PHSIGNER::sign_ph_out(&sk, &ph, None, &mut sig_val).unwrap(); assert_eq!(bytes_written, SIG_LEN); - SigAlg::verify_ph(&pk, &ph, None, &sig_val).unwrap(); - SigAlg::verify(&pk, msg, None, &sig_val).unwrap(); + PHVERIFIER::verify_ph(&pk, &ph, None, &sig_val).unwrap(); + PHVERIFIER::verify(&pk, msg, None, &sig_val).unwrap(); } } @@ -277,31 +289,31 @@ impl TestFrameworkSignatureKeys { Self {} } + /// Since key generation is not part of either signature trait, the caller supplies a + /// `keygen` function pointer (the inherent `keygen` associated function on the algorithm struct). pub fn test_keys< PK: SignaturePublicKey, SK: SignaturePrivateKey, - SigAlg: Signature, const PK_LEN: usize, const SK_LEN: usize, - const SIG_LEN: usize, >( &self, + keygen: fn() -> Result<(PK, SK), SignatureError>, ) { - self.test_boundary_conditions::(); + self.test_boundary_conditions::(keygen); } /// Tests the correct behaviour on buffers too large / too small. fn test_boundary_conditions< PK: SignaturePublicKey, SK: SignaturePrivateKey, - SigAlg: Signature, const PK_LEN: usize, const SK_LEN: usize, - const SIG_LEN: usize, >( &self, + keygen: fn() -> Result<(PK, SK), SignatureError>, ) { - let (pk, sk) = SigAlg::keygen().unwrap(); + let (pk, sk) = keygen().unwrap(); let pk_bytes = pk.encode(); assert_eq!(pk_bytes.len(), PK_LEN); diff --git a/crypto/core/src/traits.rs b/crypto/core/src/traits.rs index 089e282..21894a2 100644 --- a/crypto/core/src/traits.rs +++ b/crypto/core/src/traits.rs @@ -418,21 +418,22 @@ pub trait RNG: Default { /// A trait that forces an object to implement a zeroizing Drop() as well as Debug and Display that /// will not log the sensitive contents, even in error or crash-dump scenarios. -#[allow(drop_bounds)] // Since rust auto-implements Drop, there's a lint that explicitly bounding on Drop is useless. +// Since rust auto-implements Drop, there's a lint that explicitly bounding on Drop is useless. // I disagree because I want to force things that are secrets to manually implement Drop that zeroizes the data. // So I'm turning off this lint. +#[allow(drop_bounds)] pub trait Secret: Drop + Debug + Display {} -/// Pre-Hashed Signature is an extension to [Signature] that adds functionality specific to signature +/// Pre-Hashed Signer is an extension to [Signer] that adds functionality specific to signature /// primatives that can operate on a pre-hashed message instead of the full message. -pub trait PHSignature< +pub trait PHSigner< PK: SignaturePublicKey, SK: SignaturePrivateKey, const PK_LEN: usize, const SK_LEN: usize, const SIG_LEN: usize, const PH_LEN: usize, ->: Signature +>: Signer { /// Produce a signature for the provided pre-hashed message and context. /// @@ -471,6 +472,17 @@ pub trait PHSignature< ctx: Option<&[u8]>, output: &mut [u8; SIG_LEN], ) -> Result; +} + +/// Pre-Hashed Signature Verifier is an extension to [SignatureVerifier] that adds functionality specific to signature +/// primatives that can operate on a pre-hashed message instead of the full message. +pub trait PHSignatureVerifier< + PK: SignaturePublicKey, + const PK_LEN: usize, + const SIG_LEN: usize, + const PH_LEN: usize, +>: SignatureVerifier +{ /// On success, returns Ok(()) /// On failure, returns Err([SignatureError::SignatureVerificationFailed]); may also return other types of [SignatureError] as appropriate (such as for invalid-length inputs). fn verify_ph( @@ -481,33 +493,59 @@ pub trait PHSignature< ) -> Result<(), SignatureError>; } +// todo: could the public and private key types impl Into> and From> +// todo: that automatically call the encode and from_bytes() ? + +/// A public key for a signature algorithm, often denoted "pk". +pub trait SignaturePublicKey: + PartialEq + Eq + Clone + Debug + Display + Sized +{ + /// Write it out to bytes in its standard encoding. + fn encode(&self) -> [u8; PK_LEN]; + /// Write it out to bytes in its standard encoding. + /// The entire output buffer is zeroized before the encoding is written. + fn encode_out(&self, out: &mut [u8; PK_LEN]) -> usize; + /// Read it in from bytes in its standard encoding. + fn from_bytes(bytes: &[u8]) -> Result; +} + +/// A private key for a signature algorithm, often denoted "sk" (for "secret key"). +pub trait SignaturePrivateKey: + PartialEq + Eq + Clone + Secret + Sized +{ + /// Write it out to bytes in its standard encoding. + fn encode(&self) -> [u8; SK_LEN]; + /// Write it out to bytes in its standard encoding. + /// The entire output buffer is zeroized before the encoding is written. + fn encode_out(&self, out: &mut [u8; SK_LEN]) -> usize; + /// Read it in from bytes in its standard encoding. + fn from_bytes(bytes: &[u8]) -> Result; +} + /// A digital signature algorithm is defined as a set of three operations: /// key generation, signing, and verification. /// -/// To avoid the use of dyn, this trait does not include key generation; you'll have to consult the -/// documentation for the underlying signature primitive for how to generate a key pair. +/// This trait represents the operations performed by the holder of the signing private key: +/// which include signing and key generation. Verification operations are performed by the corresponding +/// [SignatureVerifier] trait. +/// There are several reasons for this split: first is architectural; some complex algorithms may +/// benefit from having the signature generation and verification implementations split into separate modules. +/// Second is for compliance: sometimes a policy soft-deprecates an algorithm so that new signatures +/// can no longer be created, but existing signatures can still be verified. Splitting the traits +/// makes this policy easier to enforce. /// /// This high-level trait defines the operations over a generic signature algorithm that is assumed /// to source all its randomness from bouncycastle's default os-backed RNG. /// The underlying signature primitives will expose APIs that allow for specifying a specific RNG /// or deterministic seed values. /// -/// Here we statically-size the arrays used to encode public keys, private keys, and signature values +/// The arrays used to encode public keys, private keys, and signature values are statically-sized /// because this allows us to safely remove runtime checks for array lengths, which overall reduces /// the fallibility of the library. This design choice could make this trait complicated to apply /// to a signature algorithm that do not have fixed sizes for the encodings of these objects. -pub trait Signature< - PK: SignaturePublicKey, - SK: SignaturePrivateKey, - const PK_LEN: usize, - const SK_LEN: usize, - const SIG_LEN: usize, ->: Sized +pub trait Signer, const SK_LEN: usize, const SIG_LEN: usize>: + Sized { - /// Generate a keypair. - /// Error condition: Basically only on RNG failures - fn keygen() -> Result<(PK, SK), SignatureError>; - /// Produce a signature for the provided message and context. /// Both the `msg` and `ctx` accept zero-length byte arrays. /// @@ -557,7 +595,29 @@ pub trait Signature< /// Returns the number of bytes written to the output buffer. Can be called with an oversized buffer. /// The entire output buffer is zeroized before the signature is written. fn sign_final_out(self, output: &mut [u8; SIG_LEN]) -> Result; +} +/// A digital signature algorithm is defined as a set of three operations: +/// key generation, signing, and verification. +/// +/// This trait represents the verification operations performed by the holder of the verification public key. +/// Keygen and signing operations are performed by the corresponding [Signer] trait. +/// There are several reasons for this split: first is architectural; some complex algorithms may +/// benefit from having the signature generation and verification implementations split into separate modules. +/// Second is for compliance: sometimes a policy soft-deprecates an algorithm so that new signatures +/// can no longer be created, but existing signatures can still be verified. Splitting the traits +/// makes this policy easier to enforce. +/// +/// Here we statically-size the arrays used to encode public keys, private keys, and signature values +/// because this allows us to safely remove runtime checks for array lengths, which overall reduces +/// the fallibility of the library. This design choice could make this trait complicated to apply +/// to a signature algorithm that do not have fixed sizes for the encodings of these objects. +pub trait SignatureVerifier< + PK: SignaturePublicKey, + const PK_LEN: usize, + const SIG_LEN: usize, +>: Sized +{ /// On success, returns Ok(()) /// On failure, returns Err([SignatureError::SignatureVerificationFailed]); may also return other types of [SignatureError] as appropriate (such as for invalid-length inputs). fn verify(pk: &PK, msg: &[u8], ctx: Option<&[u8]>, sig: &[u8]) -> Result<(), SignatureError>; diff --git a/crypto/mldsa-lowmemory/benches/mldsa_benches.rs b/crypto/mldsa-lowmemory/benches/mldsa_benches.rs index ec12a86..6927d0d 100644 --- a/crypto/mldsa-lowmemory/benches/mldsa_benches.rs +++ b/crypto/mldsa-lowmemory/benches/mldsa_benches.rs @@ -1,5 +1,5 @@ use bouncycastle_core::key_material::{KeyMaterial256, KeyType}; -use bouncycastle_core::traits::Signature; +use bouncycastle_core::traits::{SignatureVerifier, Signer}; use bouncycastle_hex as hex; use bouncycastle_mldsa_lowmemory::{ MLDSA44, MLDSA44_SIG_LEN, MLDSA65, MLDSA65_SIG_LEN, MLDSA87, MLDSA87_SIG_LEN, MLDSATrait, diff --git a/crypto/mldsa-lowmemory/src/hash_mldsa.rs b/crypto/mldsa-lowmemory/src/hash_mldsa.rs index ec0978f..1c9f9e8 100644 --- a/crypto/mldsa-lowmemory/src/hash_mldsa.rs +++ b/crypto/mldsa-lowmemory/src/hash_mldsa.rs @@ -3,11 +3,11 @@ //! mode of [MLDSA]; possibly because you have to digest the message before you know which public key //! will sign it. //! -//! HashML-DSA is a full signature algorithm implementing the [Signature] trait: +//! HashML-DSA is a full signature algorithm implementing the [Signer] and [SignatureVerifier] traits: //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSATrait, HashMLDSA65_with_SHA512, HashMLDSA44_with_SHA512}; //! //! let msg = b"The quick brown fox jumped over the lazy dog"; @@ -24,11 +24,13 @@ //! } //! ``` //! -//! But you also have access to the pre-hashed function available from [PHSignature]: +//! But you also have access to the pre-hashed function available from [PHSigner] and [PHSignatureVerifier]: //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::{Signature, PHSignature, Hash}; +//! use bouncycastle_core::traits::{ +//! Hash, PHSignatureVerifier, PHSigner, SignatureVerifier, Signer, +//! }; //! use bouncycastle_sha2::SHA512; //! use bouncycastle_mldsa_lowmemory::{MLDSATrait, HashMLDSA65_with_SHA512, HashMLDSA44_with_SHA512}; //! @@ -44,14 +46,14 @@ //! let sig = HashMLDSA65_with_SHA512::sign_ph(&sk, &ph, None).unwrap(); //! // This is the signature value that you can save to a file or whatever you need. //! -//! // This verifies either through the usual one-shot API of the [Signature] trait +//! // This verifies either through the usual one-shot API of the [SignatureVerifier] trait //! match HashMLDSA65_with_SHA512::verify(&pk, msg, None, &sig) { //! Ok(()) => println!("Signature is valid!"), //! Err(SignatureError::SignatureVerificationFailed) => println!("Signature is invalid!"), //! Err(e) => panic!("Something else went wrong: {:?}", e), //! } //! -//! // Or though the verify_ph of the [PHSignature] trait +//! // Or though the verify_ph of the [PHSignatureVerifier] trait //! match HashMLDSA65_with_SHA512::verify_ph(&pk, &ph, None, &sig) { //! Ok(()) => println!("Signature is valid!"), //! Err(SignatureError::SignatureVerificationFailed) => println!("Signature is invalid!"), @@ -61,7 +63,7 @@ //! //! Note that the [HashMLDSA] object is just a light wrapper around [MLDSA], and, for example, they share key types, //! so if you need the fancy keygen functions, just use them from [MLDSA]. -//! But a simple [HashMLDSA::keygen] is provided in order to have conformance to the [Signature] trait. +//! But a simple [HashMLDSA::keygen] is provided. use crate::mldsa::{H, MLDSA_MU_LEN, MLDSA_RND_LEN, MLDSATrait}; use crate::mldsa::{ @@ -94,7 +96,8 @@ use crate::{ use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::KeyMaterial; use bouncycastle_core::traits::{ - Algorithm, Hash, PHSignature, RNG, SecurityStrength, Signature, XOF, + Algorithm, Hash, PHSignatureVerifier, PHSigner, RNG, SecurityStrength, SignatureVerifier, + Signer, XOF, }; use bouncycastle_rng::HashDRBG_SHA512; use bouncycastle_sha2::{SHA256, SHA512}; @@ -511,6 +514,42 @@ impl< GAMMA1_MASK_LEN, > { + /// Generate a keypair, sourcing randomness from bouncycastle's default os-backed RNG. + /// + /// Key generation is intentionally not part of the [Signer] / [SignatureVerifier] traits; + /// it is provided as an inherent associated function directly on the algorithm struct. + /// Keys are interchangeable between MLDSA and HashMLDSA. + /// Error condition: basically only on RNG failures. + pub fn keygen() -> Result<(PK, SK), SignatureError> { + MLDSA::< + PK_LEN, + SK_LEN, + FULL_SK_LEN, + SIG_LEN, + PK, + SK, + TAU, + LAMBDA, + GAMMA1, + GAMMA2, + k, + l, + ETA, + BETA, + OMEGA, + C_TILDE, + POLY_Z_PACKED_LEN, + POLY_W1_PACKED_LEN, + S1_PACKED_LEN, + S2_PACKED_LEN, + T1_PACKED_LEN, + LAMBDA_over_4, + GAMMA1_MINUS_BETA, + GAMMA2_MINUS_BETA, + GAMMA1_MASK_LEN, + >::keygen() + } + /// Imports a secret key from a seed. pub fn keygen_from_seed(seed: &KeyMaterial<32>) -> Result<(PK, SK), SignatureError> { MLDSA::< @@ -644,9 +683,9 @@ impl< Ok(bytes_written) } - /// To be used for deterministic signing in conjunction with the [Signature::sign_init], - /// [Signature::sign_update], and [Signature::sign_final] flow. - /// Can be set anywhere after [Signature::sign_init] and before [Signature::sign_final] + /// To be used for deterministic signing in conjunction with the [Signer::sign_init], + /// [Signer::sign_update], and [Signer::sign_final] flow. + /// Can be set anywhere after [Signer::sign_init] and before [Signer::sign_final] pub fn set_signer_rnd(&mut self, rnd: [u8; 32]) { self.signer_rnd = Some(rnd); } @@ -736,7 +775,7 @@ impl< const GAMMA1_MINUS_BETA: i32, const GAMMA2_MINUS_BETA: i32, const GAMMA1_MASK_LEN: usize, -> Signature +> Signer for HashMLDSA< HASH, PH_LEN, @@ -768,37 +807,6 @@ impl< GAMMA1_MASK_LEN, > { - /// Keygen, and keys in general, are interchangeable between MLDSA and HashMLDSA. - fn keygen() -> Result<(PK, SK), SignatureError> { - MLDSA::< - PK_LEN, - SK_LEN, - FULL_SK_LEN, - SIG_LEN, - PK, - SK, - TAU, - LAMBDA, - GAMMA1, - GAMMA2, - k, - l, - ETA, - BETA, - OMEGA, - C_TILDE, - POLY_Z_PACKED_LEN, - POLY_W1_PACKED_LEN, - S1_PACKED_LEN, - S2_PACKED_LEN, - T1_PACKED_LEN, - LAMBDA_over_4, - GAMMA1_MINUS_BETA, - GAMMA2_MINUS_BETA, - GAMMA1_MASK_LEN, - >::keygen() - } - /// Algorithm 4 HashML-DSA.Sign(π‘ π‘˜, 𝑀 , 𝑐𝑑π‘₯, PH) /// Generate a β€œpre-hash” ML-DSA signature. fn sign(sk: &SK, msg: &[u8], ctx: Option<&[u8]>) -> Result<[u8; SIG_LEN], SignatureError> { @@ -884,7 +892,89 @@ impl< unreachable!() } } +} +impl< + HASH: Hash + Default, + PK: MLDSAPublicKeyTrait + + MLDSAPublicKeyInternalTrait, + SK: MLDSAPrivateKeyTrait< + k, + l, + S1_PACKED_LEN, + S2_PACKED_LEN, + T1_PACKED_LEN, + PK_LEN, + SK_LEN, + FULL_SK_LEN, + > + MLDSAPrivateKeyInternalTrait< + LAMBDA, + GAMMA2, + k, + l, + ETA, + S1_PACKED_LEN, + S2_PACKED_LEN, + PK_LEN, + SK_LEN, + >, + const PH_LEN: usize, + const oid: &'static [u8], + const PK_LEN: usize, + const SK_LEN: usize, + const FULL_SK_LEN: usize, + const SIG_LEN: usize, + const TAU: i32, + const LAMBDA: i32, + const GAMMA1: i32, + const GAMMA2: i32, + const k: usize, + const l: usize, + const ETA: usize, + const BETA: i32, + const OMEGA: i32, + const C_TILDE: usize, + const POLY_Z_PACKED_LEN: usize, + const POLY_W1_PACKED_LEN: usize, + const S1_PACKED_LEN: usize, + const S2_PACKED_LEN: usize, + const T1_PACKED_LEN: usize, + const LAMBDA_over_4: usize, + const GAMMA1_MINUS_BETA: i32, + const GAMMA2_MINUS_BETA: i32, + const GAMMA1_MASK_LEN: usize, +> SignatureVerifier + for HashMLDSA< + HASH, + PH_LEN, + oid, + PK_LEN, + SK_LEN, + FULL_SK_LEN, + SIG_LEN, + PK, + SK, + TAU, + LAMBDA, + GAMMA1, + GAMMA2, + k, + l, + ETA, + BETA, + OMEGA, + C_TILDE, + POLY_Z_PACKED_LEN, + POLY_W1_PACKED_LEN, + S1_PACKED_LEN, + S2_PACKED_LEN, + T1_PACKED_LEN, + LAMBDA_over_4, + GAMMA1_MINUS_BETA, + GAMMA2_MINUS_BETA, + GAMMA1_MASK_LEN, + > +{ fn verify(pk: &PK, msg: &[u8], ctx: Option<&[u8]>, sig: &[u8]) -> Result<(), SignatureError> { let mut ph_m = [0u8; PH_LEN]; _ = HASH::default().hash_out(msg, &mut ph_m); @@ -969,7 +1059,7 @@ impl< const GAMMA1_MINUS_BETA: i32, const GAMMA2_MINUS_BETA: i32, const GAMMA1_MASK_LEN: usize, -> PHSignature +> PHSigner for HashMLDSA< HASH, PH_LEN, @@ -1028,7 +1118,89 @@ impl< HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?; Self::sign_ph_deterministic_out(sk, ctx, ph, rnd, output) } +} +impl< + HASH: Hash + Default, + const PH_LEN: usize, + const oid: &'static [u8], + const PK_LEN: usize, + const SK_LEN: usize, + const FULL_SK_LEN: usize, + const SIG_LEN: usize, + PK: MLDSAPublicKeyTrait + + MLDSAPublicKeyInternalTrait, + SK: MLDSAPrivateKeyTrait< + k, + l, + S1_PACKED_LEN, + S2_PACKED_LEN, + T1_PACKED_LEN, + PK_LEN, + SK_LEN, + FULL_SK_LEN, + > + MLDSAPrivateKeyInternalTrait< + LAMBDA, + GAMMA2, + k, + l, + ETA, + S1_PACKED_LEN, + S2_PACKED_LEN, + PK_LEN, + SK_LEN, + >, + const TAU: i32, + const LAMBDA: i32, + const GAMMA1: i32, + const GAMMA2: i32, + const k: usize, + const l: usize, + const ETA: usize, + const BETA: i32, + const OMEGA: i32, + const C_TILDE: usize, + const POLY_Z_PACKED_LEN: usize, + const POLY_W1_PACKED_LEN: usize, + const S1_PACKED_LEN: usize, + const S2_PACKED_LEN: usize, + const T1_PACKED_LEN: usize, + const LAMBDA_over_4: usize, + const GAMMA1_MINUS_BETA: i32, + const GAMMA2_MINUS_BETA: i32, + const GAMMA1_MASK_LEN: usize, +> PHSignatureVerifier + for HashMLDSA< + HASH, + PH_LEN, + oid, + PK_LEN, + SK_LEN, + FULL_SK_LEN, + SIG_LEN, + PK, + SK, + TAU, + LAMBDA, + GAMMA1, + GAMMA2, + k, + l, + ETA, + BETA, + OMEGA, + C_TILDE, + POLY_Z_PACKED_LEN, + POLY_W1_PACKED_LEN, + S1_PACKED_LEN, + S2_PACKED_LEN, + T1_PACKED_LEN, + LAMBDA_over_4, + GAMMA1_MINUS_BETA, + GAMMA2_MINUS_BETA, + GAMMA1_MASK_LEN, + > +{ fn verify_ph( pk: &PK, ph: &[u8; PH_LEN], diff --git a/crypto/mldsa-lowmemory/src/lib.rs b/crypto/mldsa-lowmemory/src/lib.rs index 4463d77..a03106a 100644 --- a/crypto/mldsa-lowmemory/src/lib.rs +++ b/crypto/mldsa-lowmemory/src/lib.rs @@ -128,7 +128,6 @@ //! ## Generating Keys //! //! ```rust -//! use bouncycastle_core::traits::Signature; //! use bouncycastle_mldsa_lowmemory::MLDSA65; //! //! let (pk, sk) = MLDSA65::keygen().unwrap(); @@ -153,13 +152,13 @@ //! //! See [MLDSATrait] and [MLDSATrait::sign_mu_deterministic_from_seed] for an API flow that uses a merged //! keygen-and-sign function to provide improved speed and memory performance compared with making -//! separate calls to [MLDSATrait::keygen_from_seed] followed by [Signature::sign]. +//! separate calls to [MLDSATrait::keygen_from_seed] followed by [Signer::sign]. //! //! ## Generating and Verifying Signatures //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait}; //! //! let msg = b"The quick brown fox"; @@ -221,7 +220,7 @@ #[allow(unused_imports)] use bouncycastle_core::key_material::KeyMaterialTrait; #[allow(unused_imports)] -use bouncycastle_core::traits::Signature; +use bouncycastle_core::traits::{SignatureVerifier, Signer}; // todo -- re-run mutants diff --git a/crypto/mldsa-lowmemory/src/mldsa.rs b/crypto/mldsa-lowmemory/src/mldsa.rs index dc6ae2e..5768e3f 100644 --- a/crypto/mldsa-lowmemory/src/mldsa.rs +++ b/crypto/mldsa-lowmemory/src/mldsa.rs @@ -9,7 +9,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let (pk, sk) = MLDSA65::keygen().unwrap(); @@ -51,7 +51,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let (pk, sk) = MLDSA65::keygen().unwrap(); @@ -97,7 +97,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let (pk, _) = MLDSA65::keygen().unwrap(); @@ -116,7 +116,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let (pk, _) = MLDSA65::keygen().unwrap(); @@ -136,7 +136,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let msg = b"The quick brown fox jumped over the lazy dog"; @@ -181,7 +181,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait}; //! //! let msg = b"The quick brown fox"; @@ -220,7 +220,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let msg = b"The quick brown fox jumped over the lazy dog"; @@ -265,7 +265,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_core::key_material::{KeyMaterial256, KeyType, KeyMaterialTrait}; //! use bouncycastle_hex as hex; //! use bouncycastle_mldsa_lowmemory::{MLDSA44, MLDSA44_SIG_LEN, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; @@ -324,7 +324,7 @@ use crate::{ }; use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::KeyMaterial; -use bouncycastle_core::traits::{Algorithm, RNG, SecurityStrength, Signature, XOF}; +use bouncycastle_core::traits::{Algorithm, RNG, SecurityStrength, SignatureVerifier, Signer, XOF}; use bouncycastle_rng::HashDRBG_SHA512; use bouncycastle_sha3::{SHAKE128, SHAKE256}; use core::marker::PhantomData; @@ -335,7 +335,7 @@ use crate::hash_mldsa; #[allow(unused_imports)] use bouncycastle_core::key_material::KeyMaterial256; #[allow(unused_imports)] -use bouncycastle_core::traits::PHSignature; +use bouncycastle_core::traits::{PHSignatureVerifier, PHSigner}; /*** Constants ***/ /// @@ -718,6 +718,15 @@ impl< GAMMA1_MASK_LEN, > { + /// Generate a keypair, sourcing randomness from bouncycastle's default os-backed RNG. + /// + /// Key generation is intentionally not part of the [Signer] / [SignatureVerifier] traits; + /// it is provided as an inherent associated function directly on the algorithm struct. + /// Error condition: basically only on RNG failures. + pub fn keygen() -> Result<(PK, SK), SignatureError> { + Self::keygen_from_os_rng() + } + /// Should still be ok in FIPS mode pub fn keygen_from_os_rng() -> Result<(PK, SK), SignatureError> { let mut seed = KeyMaterial::<32>::new(); @@ -1544,7 +1553,7 @@ impl< const GAMMA1_MINUS_BETA: i32, const GAMMA2_MINUS_BETA: i32, const GAMMA1_MASK_LEN: usize, -> Signature +> Signer for MLDSA< PK_LEN, SK_LEN, @@ -1573,10 +1582,6 @@ impl< GAMMA1_MASK_LEN, > { - fn keygen() -> Result<(PK, SK), SignatureError> { - Self::keygen_from_os_rng() - } - fn sign(sk: &SK, msg: &[u8], ctx: Option<&[u8]>) -> Result<[u8; SIG_LEN], SignatureError> { let mut out = [0u8; SIG_LEN]; Self::sign_out(sk, msg, ctx, &mut out)?; @@ -1654,7 +1659,83 @@ impl< unreachable!() } } +} +impl< + const PK_LEN: usize, + const SK_LEN: usize, + const FULL_SK_LEN: usize, + const SIG_LEN: usize, + PK: MLDSAPublicKeyTrait + + MLDSAPublicKeyInternalTrait, + SK: MLDSAPrivateKeyTrait< + k, + l, + S1_PACKED_LEN, + S2_PACKED_LEN, + T1_PACKED_LEN, + PK_LEN, + SK_LEN, + FULL_SK_LEN, + > + MLDSAPrivateKeyInternalTrait< + LAMBDA, + GAMMA2, + k, + l, + ETA, + S1_PACKED_LEN, + S2_PACKED_LEN, + PK_LEN, + SK_LEN, + >, + const TAU: i32, + const LAMBDA: i32, + const GAMMA1: i32, + const GAMMA2: i32, + const k: usize, + const l: usize, + const ETA: usize, + const BETA: i32, + const OMEGA: i32, + const C_TILDE: usize, + const POLY_Z_PACKED_LEN: usize, + const POLY_W1_PACKED_LEN: usize, + const S1_PACKED_LEN: usize, + const S2_PACKED_LEN: usize, + const T1_PACKED_LEN: usize, + const LAMBDA_over_4: usize, + const GAMMA1_MINUS_BETA: i32, + const GAMMA2_MINUS_BETA: i32, + const GAMMA1_MASK_LEN: usize, +> SignatureVerifier + for MLDSA< + PK_LEN, + SK_LEN, + FULL_SK_LEN, + SIG_LEN, + PK, + SK, + TAU, + LAMBDA, + GAMMA1, + GAMMA2, + k, + l, + ETA, + BETA, + OMEGA, + C_TILDE, + POLY_Z_PACKED_LEN, + POLY_W1_PACKED_LEN, + S1_PACKED_LEN, + S2_PACKED_LEN, + T1_PACKED_LEN, + LAMBDA_over_4, + GAMMA1_MINUS_BETA, + GAMMA2_MINUS_BETA, + GAMMA1_MASK_LEN, + > +{ fn verify(pk: &PK, msg: &[u8], ctx: Option<&[u8]>, sig: &[u8]) -> Result<(), SignatureError> { let mu = MuBuilder::compute_mu(&pk.compute_tr(), msg, ctx)?; @@ -1711,7 +1792,7 @@ impl< /// Note: this struct is only exposed for "pure" ML-DSA and not for HashML-DSA because HashML-DSA /// does not benefit from allowing external construction of the message representative mu. /// You can get the same behaviour by computing the pre-hash `ph` with the appropriate hash function -/// and providing that to HashMLDSA via [PHSignature::sign_ph]. +/// and providing that to HashMLDSA via [PHSigner::sign_ph]. pub struct MuBuilder { h: H, } diff --git a/crypto/mldsa-lowmemory/tests/bc_test_data.rs b/crypto/mldsa-lowmemory/tests/bc_test_data.rs index 706c82a..fdc5c56 100644 --- a/crypto/mldsa-lowmemory/tests/bc_test_data.rs +++ b/crypto/mldsa-lowmemory/tests/bc_test_data.rs @@ -18,7 +18,7 @@ mod bc_test_data { use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyMaterialTrait, KeyType}; use bouncycastle_core::traits::{ - Hash, SecurityStrength, Signature, SignaturePrivateKey, SignaturePublicKey, + Hash, SecurityStrength, SignaturePrivateKey, SignaturePublicKey, SignatureVerifier, }; use bouncycastle_hex as hex; use bouncycastle_mldsa_lowmemory::{ diff --git a/crypto/mldsa-lowmemory/tests/hash_mldsa_tests.rs b/crypto/mldsa-lowmemory/tests/hash_mldsa_tests.rs index 1380296..d5b1bdf 100644 --- a/crypto/mldsa-lowmemory/tests/hash_mldsa_tests.rs +++ b/crypto/mldsa-lowmemory/tests/hash_mldsa_tests.rs @@ -1,4 +1,4 @@ -use bouncycastle_core::traits::Signature; +use bouncycastle_core::traits::{SignatureVerifier, Signer}; use bouncycastle_hex as hex; #[cfg(test)] @@ -6,7 +6,7 @@ mod hash_mldsa_tests { use super::*; use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyType}; - use bouncycastle_core::traits::{Hash, PHSignature}; + use bouncycastle_core::traits::{Hash, PHSignatureVerifier}; use bouncycastle_core_test_framework::signature::TestFrameworkSignature; use bouncycastle_mldsa_lowmemory::{ HashMLDSA44_with_SHA256, HashMLDSA44_with_SHA512, HashMLDSA65_with_SHA256, @@ -24,19 +24,19 @@ mod hash_mldsa_tests { let tf = TestFrameworkSignature::new(false, true); // Test HashML-DSA-SHA512 as a regular signature alg - tf.test_signature::(false); - tf.test_signature::(false); - tf.test_signature::(false); + tf.test_signature::(HashMLDSA44_with_SHA512::keygen, false); + tf.test_signature::(HashMLDSA65_with_SHA512::keygen, false); + tf.test_signature::(HashMLDSA87_with_SHA512::keygen, false); // Test HashML-DSA-SHA256 as a ph signature alg - tf.test_ph_signature::(false); - tf.test_ph_signature::(false); - tf.test_ph_signature::(false); + tf.test_ph_signature::(HashMLDSA44_with_SHA256::keygen, false); + tf.test_ph_signature::(HashMLDSA65_with_SHA256::keygen, false); + tf.test_ph_signature::(HashMLDSA87_with_SHA256::keygen, false); // Test HashML-DSA-SHA512 as a ph signature alg - tf.test_ph_signature::(false); - tf.test_ph_signature::(false); - tf.test_ph_signature::(false); + tf.test_ph_signature::(HashMLDSA44_with_SHA512::keygen, false); + tf.test_ph_signature::(HashMLDSA65_with_SHA512::keygen, false); + tf.test_ph_signature::(HashMLDSA87_with_SHA512::keygen, false); } #[test] diff --git a/crypto/mldsa-lowmemory/tests/mldsa_key_tests.rs b/crypto/mldsa-lowmemory/tests/mldsa_key_tests.rs index b224f9b..f5ab896 100644 --- a/crypto/mldsa-lowmemory/tests/mldsa_key_tests.rs +++ b/crypto/mldsa-lowmemory/tests/mldsa_key_tests.rs @@ -6,7 +6,7 @@ mod mldsa_key_tests { use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyMaterialTrait, KeyType}; use bouncycastle_core::traits::{ - SecurityStrength, Signature, SignaturePrivateKey, SignaturePublicKey, + SecurityStrength, SignaturePrivateKey, SignaturePublicKey, }; use bouncycastle_core_test_framework::signature::TestFrameworkSignatureKeys; use bouncycastle_hex as hex; @@ -24,9 +24,9 @@ mod mldsa_key_tests { fn core_framework_tests() { let tf = TestFrameworkSignatureKeys::new(); - tf.test_keys::(); - tf.test_keys::(); - tf.test_keys::(); + tf.test_keys::(MLDSA44::keygen); + tf.test_keys::(MLDSA65::keygen); + tf.test_keys::(MLDSA87::keygen); } #[test] diff --git a/crypto/mldsa-lowmemory/tests/mldsa_tests.rs b/crypto/mldsa-lowmemory/tests/mldsa_tests.rs index b3eb8c3..e45ed76 100644 --- a/crypto/mldsa-lowmemory/tests/mldsa_tests.rs +++ b/crypto/mldsa-lowmemory/tests/mldsa_tests.rs @@ -5,7 +5,7 @@ mod mldsa_tests { use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyMaterialTrait, KeyType}; use bouncycastle_core::traits::{ - RNG, SecurityStrength, Signature, SignaturePrivateKey, SignaturePublicKey, + RNG, SecurityStrength, SignaturePrivateKey, SignaturePublicKey, SignatureVerifier, Signer, }; use bouncycastle_core_test_framework::DUMMY_SEED_1024; use bouncycastle_core_test_framework::signature::*; @@ -22,9 +22,9 @@ mod mldsa_tests { fn test_framework_signature() { let tf = TestFrameworkSignature::new(false, true); - tf.test_signature::(false); - tf.test_signature::(false); - tf.test_signature::(false); + tf.test_signature::(MLDSA44::keygen, false); + tf.test_signature::(MLDSA65::keygen, false); + tf.test_signature::(MLDSA87::keygen, false); } /// This runs the full bitflipping tests and takes several minutes. diff --git a/crypto/mldsa-lowmemory/tests/wycheproof.rs b/crypto/mldsa-lowmemory/tests/wycheproof.rs index ca9df24..080efdf 100644 --- a/crypto/mldsa-lowmemory/tests/wycheproof.rs +++ b/crypto/mldsa-lowmemory/tests/wycheproof.rs @@ -23,7 +23,7 @@ use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyMaterialTrait, KeyType}; -use bouncycastle_core::traits::{SecurityStrength, Signature, SignaturePublicKey}; +use bouncycastle_core::traits::{SecurityStrength, SignaturePublicKey, SignatureVerifier}; use bouncycastle_hex as hex; use bouncycastle_mldsa_lowmemory::{ MLDSA44, MLDSA44PublicKey, MLDSA65, MLDSA65PublicKey, MLDSA87, MLDSA87PublicKey, diff --git a/crypto/mldsa/benches/mldsa_benches.rs b/crypto/mldsa/benches/mldsa_benches.rs index aa8f055..87be0fe 100644 --- a/crypto/mldsa/benches/mldsa_benches.rs +++ b/crypto/mldsa/benches/mldsa_benches.rs @@ -1,5 +1,5 @@ use bouncycastle_core::key_material::{KeyMaterial256, KeyType}; -use bouncycastle_core::traits::Signature; +use bouncycastle_core::traits::{SignatureVerifier, Signer}; use bouncycastle_hex as hex; use bouncycastle_mldsa::{ MLDSA44, MLDSA44_SIG_LEN, MLDSA44PrivateKeyExpanded, MLDSA44PublicKeyExpanded, MLDSA65, diff --git a/crypto/mldsa/src/hash_mldsa.rs b/crypto/mldsa/src/hash_mldsa.rs index 8803fc6..9a4dc3d 100644 --- a/crypto/mldsa/src/hash_mldsa.rs +++ b/crypto/mldsa/src/hash_mldsa.rs @@ -3,12 +3,12 @@ //! mode of [MLDSA]; possibly because you have to digest the message before you know which public key //! will sign it. //! -//! HashML-DSA is a full signature algorithm implementing the [Signature] trait: +//! HashML-DSA is a full signature algorithm implementing the [Signer] and [SignatureVerifier] traits: //! //! ```rust //! use bouncycastle_core::errors::SignatureError; //! use bouncycastle_mldsa::{HashMLDSA65_with_SHA512, MLDSATrait, HashMLDSA44_with_SHA512}; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! //! let msg = b"The quick brown fox jumped over the lazy dog"; //! @@ -24,12 +24,14 @@ //! } //! ``` //! -//! But you also have access to the pre-hashed function available from [PHSignature]: +//! But you also have access to the pre-hashed functions available from [PHSigner] and [PHVerifier]: //! //! ```rust //! use bouncycastle_core::errors::SignatureError; //! use bouncycastle_mldsa::{HashMLDSA65_with_SHA512, MLDSATrait, HashMLDSA44_with_SHA512}; -//! use bouncycastle_core::traits::{Signature, PHSignature, Hash}; +//! use bouncycastle_core::traits::{ +//! Hash, PHSignatureVerifier, PHSigner, SignatureVerifier, Signer, +//! }; //! use bouncycastle_sha2::SHA512; //! //! let msg = b"The quick brown fox jumped over the lazy dog"; @@ -44,14 +46,14 @@ //! let sig = HashMLDSA65_with_SHA512::sign_ph(&sk, &ph, None).unwrap(); //! // This is the signature value that you can save to a file or whatever you need. //! -//! // This verifies either through the usual one-shot API of the [Signature] trait +//! // This verifies either through the usual one-shot API of the [SignatureVerifier] trait //! match HashMLDSA65_with_SHA512::verify(&pk, msg, None, &sig) { //! Ok(()) => println!("Signature is valid!"), //! Err(SignatureError::SignatureVerificationFailed) => println!("Signature is invalid!"), //! Err(e) => panic!("Something else went wrong: {:?}", e), //! } //! -//! // Or though the verify_ph of the [PHSignature] trait +//! // Or though the verify_ph of the [PHSignatureVerifier] trait //! match HashMLDSA65_with_SHA512::verify_ph(&pk, &ph, None, &sig) { //! Ok(()) => println!("Signature is valid!"), //! Err(SignatureError::SignatureVerificationFailed) => println!("Signature is invalid!"), @@ -61,7 +63,7 @@ //! //! Note that the [HashMLDSA] object is just a light wrapper around [MLDSA], and, for example, they share key types, //! so if you need the fancy keygen functions, just use them from [MLDSA]. -//! But a simple [HashMLDSA::keygen] is provided in order to have conformance to the [Signature] trait. +//! But a simple [HashMLDSA::keygen] is provided. use crate::mldsa::{H, MLDSA_MU_LEN, MLDSA_RND_LEN, MLDSATrait}; use crate::mldsa::{ @@ -91,7 +93,8 @@ use crate::{ use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::KeyMaterial; use bouncycastle_core::traits::{ - Algorithm, Hash, PHSignature, RNG, SecurityStrength, Signature, XOF, + Algorithm, Hash, PHSignatureVerifier, PHSigner, RNG, SecurityStrength, SignatureVerifier, + Signer, XOF, }; use bouncycastle_rng::HashDRBG_SHA512; use bouncycastle_sha2::{SHA256, SHA256_NAME, SHA512, SHA512_NAME}; @@ -425,6 +428,38 @@ impl< GAMMA1_MASK_LEN, > { + /// Generate a keypair, sourcing randomness from bouncycastle's default os-backed RNG. + /// + /// Key generation is intentionally not part of the [Signer] / [SignatureVerifier] traits; + /// it is provided as an inherent associated function directly on the algorithm struct. + /// Keygen, and keys in general, are interchangeable between MLDSA and HashMLDSA. + /// Error condition: basically only on RNG failures. + pub fn keygen() -> Result<(PK, SK), SignatureError> { + MLDSA::< + PK_LEN, + SK_LEN, + SIG_LEN, + PK, + SK, + TAU, + LAMBDA, + GAMMA1, + GAMMA2, + k, + l, + ETA, + BETA, + OMEGA, + C_TILDE, + POLY_Z_PACKED_LEN, + POLY_W1_PACKED_LEN, + LAMBDA_over_4, + GAMMA1_MINUS_BETA, + GAMMA2_MINUS_BETA, + GAMMA1_MASK_LEN, + >::keygen() + } + /// Imports a secret key from a seed. pub fn keygen_from_seed(seed: &KeyMaterial<32>) -> Result<(PK, SK), SignatureError> { MLDSA::< @@ -451,7 +486,7 @@ impl< GAMMA1_MASK_LEN, >::keygen_internal(seed) } - /// Same as [Signature::sign], but signs from an [MLDSAPrivateKeyExpanded]. + /// Same as [Signer::sign], but signs from an [MLDSAPrivateKeyExpanded]. pub fn sign_with_expanded_key( sk: &MLDSAPrivateKeyExpanded, msg: &[u8], @@ -462,7 +497,7 @@ impl< Ok(out) } - /// Same as [Signature::sign_out], but signs from an [MLDSAPrivateKeyExpanded]. + /// Same as [Signer::sign_out], but signs from an [MLDSAPrivateKeyExpanded]. pub fn sign_with_expanded_key_out( sk: &MLDSAPrivateKeyExpanded, msg: &[u8], @@ -475,7 +510,7 @@ impl< _ = HASH::default().hash_out(msg, &mut ph_m); Self::sign_ph_with_expanded_key_out(sk, &ph_m, ctx, output) } - /// Same as [PHSignature::sign_ph], but signs from an [MLDSAPrivateKeyExpanded]. + /// Same as [PHSigner::sign_ph], but signs from an [MLDSAPrivateKeyExpanded]. pub fn sign_ph_with_expanded_key( sk: &MLDSAPrivateKeyExpanded, ph: &[u8; PH_LEN], @@ -486,7 +521,7 @@ impl< Ok(out) } - /// Same as [PHSignature::sign_ph_out], but signs from an [MLDSAPrivateKeyExpanded]. + /// Same as [PHSigner::sign_ph_out], but signs from an [MLDSAPrivateKeyExpanded]. pub fn sign_ph_with_expanded_key_out( sk: &MLDSAPrivateKeyExpanded, ph: &[u8; PH_LEN], @@ -615,9 +650,9 @@ impl< Ok(bytes_written) } - /// To be used for deterministic signing in conjunction with the [Signature::sign_init], - /// [Signature::sign_update], and [Signature::sign_final] flow. - /// Can be set anywhere after [Signature::sign_init] and before [Signature::sign_final] + /// To be used for deterministic signing in conjunction with the [Signer::sign_init], + /// [Signer::sign_update], and [Signer::sign_final] flow. + /// Can be set anywhere after [Signer::sign_init] and before [Signer::sign_final] pub fn set_signer_rnd(&mut self, rnd: [u8; 32]) { self.signer_rnd = Some(rnd); } @@ -656,7 +691,7 @@ impl< ctx_len, }) } - /// Same as [Signature::verify], but verifies from an [MLDSAPublicKeyExpanded]. + /// Same as [SignatureVerifier::verify], but verifies from an [MLDSAPublicKeyExpanded]. pub fn verify_with_expanded_key( pk: &MLDSAPublicKeyExpanded, msg: &[u8], @@ -810,7 +845,7 @@ impl< const GAMMA1_MINUS_BETA: i32, const GAMMA2_MINUS_BETA: i32, const GAMMA1_MASK_LEN: usize, -> Signature +> Signer for HashMLDSA< HASH, PH_LEN, @@ -837,33 +872,6 @@ impl< GAMMA1_MASK_LEN, > { - /// Keygen, and keys in general, are interchangeable between MLDSA and HashMLDSA. - fn keygen() -> Result<(PK, SK), SignatureError> { - MLDSA::< - PK_LEN, - SK_LEN, - SIG_LEN, - PK, - SK, - TAU, - LAMBDA, - GAMMA1, - GAMMA2, - k, - l, - ETA, - BETA, - OMEGA, - C_TILDE, - POLY_Z_PACKED_LEN, - POLY_W1_PACKED_LEN, - LAMBDA_over_4, - GAMMA1_MINUS_BETA, - GAMMA2_MINUS_BETA, - GAMMA1_MASK_LEN, - >::keygen() - } - /// Algorithm 4 HashML-DSA.Sign(π‘ π‘˜, 𝑀 , 𝑐𝑑π‘₯, PH) /// Generate a β€œpre-hash” ML-DSA signature. fn sign(sk: &SK, msg: &[u8], ctx: Option<&[u8]>) -> Result<[u8; SIG_LEN], SignatureError> { @@ -957,7 +965,62 @@ impl< unreachable!() } } +} +impl< + HASH: Hash + Default, + PK: MLDSAPublicKeyTrait + MLDSAPublicKeyInternalTrait, + SK: MLDSAPrivateKeyTrait + + MLDSAPrivateKeyInternalTrait, + const PH_LEN: usize, + const oid: &'static [u8], + const PK_LEN: usize, + const SK_LEN: usize, + const SIG_LEN: usize, + const TAU: i32, + const LAMBDA: i32, + const GAMMA1: i32, + const GAMMA2: i32, + const k: usize, + const l: usize, + const ETA: usize, + const BETA: i32, + const OMEGA: i32, + const C_TILDE: usize, + const POLY_Z_PACKED_LEN: usize, + const POLY_W1_PACKED_LEN: usize, + const LAMBDA_over_4: usize, + const GAMMA1_MINUS_BETA: i32, + const GAMMA2_MINUS_BETA: i32, + const GAMMA1_MASK_LEN: usize, +> SignatureVerifier + for HashMLDSA< + HASH, + PH_LEN, + oid, + PK_LEN, + SK_LEN, + SIG_LEN, + PK, + SK, + TAU, + LAMBDA, + GAMMA1, + GAMMA2, + k, + l, + ETA, + BETA, + OMEGA, + C_TILDE, + POLY_Z_PACKED_LEN, + POLY_W1_PACKED_LEN, + LAMBDA_over_4, + GAMMA1_MINUS_BETA, + GAMMA2_MINUS_BETA, + GAMMA1_MASK_LEN, + > +{ fn verify(pk: &PK, msg: &[u8], ctx: Option<&[u8]>, sig: &[u8]) -> Result<(), SignatureError> { let mut ph_m = [0u8; PH_LEN]; _ = HASH::default().hash_out(msg, &mut ph_m); @@ -1018,7 +1081,7 @@ impl< const GAMMA1_MASK_LEN: usize, const GAMMA1_MINUS_BETA: i32, const GAMMA2_MINUS_BETA: i32, -> PHSignature +> PHSigner for HashMLDSA< HASH, PH_LEN, @@ -1072,7 +1135,62 @@ impl< HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?; Self::sign_ph_deterministic_out(sk, None, ctx, ph, rnd, output) } +} +impl< + HASH: Hash + Default, + const PH_LEN: usize, + const oid: &'static [u8], + const PK_LEN: usize, + const SK_LEN: usize, + const SIG_LEN: usize, + PK: MLDSAPublicKeyTrait + MLDSAPublicKeyInternalTrait, + SK: MLDSAPrivateKeyTrait + + MLDSAPrivateKeyInternalTrait, + const TAU: i32, + const LAMBDA: i32, + const GAMMA1: i32, + const GAMMA2: i32, + const k: usize, + const l: usize, + const ETA: usize, + const BETA: i32, + const OMEGA: i32, + const C_TILDE: usize, + const POLY_Z_PACKED_LEN: usize, + const POLY_W1_PACKED_LEN: usize, + const LAMBDA_over_4: usize, + const GAMMA1_MASK_LEN: usize, + const GAMMA1_MINUS_BETA: i32, + const GAMMA2_MINUS_BETA: i32, +> PHSignatureVerifier + for HashMLDSA< + HASH, + PH_LEN, + oid, + PK_LEN, + SK_LEN, + SIG_LEN, + PK, + SK, + TAU, + LAMBDA, + GAMMA1, + GAMMA2, + k, + l, + ETA, + BETA, + OMEGA, + C_TILDE, + POLY_Z_PACKED_LEN, + POLY_W1_PACKED_LEN, + LAMBDA_over_4, + GAMMA1_MINUS_BETA, + GAMMA2_MINUS_BETA, + GAMMA1_MASK_LEN, + > +{ fn verify_ph( pk: &PK, ph: &[u8; PH_LEN], diff --git a/crypto/mldsa/src/lib.rs b/crypto/mldsa/src/lib.rs index 9c3a2b8..c304171 100644 --- a/crypto/mldsa/src/lib.rs +++ b/crypto/mldsa/src/lib.rs @@ -15,7 +15,6 @@ //! //! ```rust //! use bouncycastle_mldsa::MLDSA65; -//! use bouncycastle_core::traits::Signature; //! //! let (pk, sk) = MLDSA65::keygen().unwrap(); //! ``` @@ -39,13 +38,13 @@ //! //! See [MLDSATrait] and [MLDSATrait::sign_mu_deterministic_from_seed] for an API flow that uses a merged //! keygen-and-sign function to provide improved speed and memory performance compared with making -//! separate calls to [MLDSATrait::keygen_from_seed] followed by [Signature::sign]. +//! separate calls to [MLDSATrait::keygen_from_seed] followed by [Signer::sign]. //! //! ## Generating and Verifying Signatures //! //! ```rust //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait}; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_core::errors::SignatureError; //! //! let msg = b"The quick brown fox"; @@ -133,7 +132,7 @@ #[allow(unused_imports)] use bouncycastle_core::key_material::KeyMaterialTrait; #[allow(unused_imports)] -use bouncycastle_core::traits::Signature; +use bouncycastle_core::traits::{SignatureVerifier, Signer}; // todo -- crucible tests diff --git a/crypto/mldsa/src/mldsa.rs b/crypto/mldsa/src/mldsa.rs index dd8eb0f..ca41c81 100644 --- a/crypto/mldsa/src/mldsa.rs +++ b/crypto/mldsa/src/mldsa.rs @@ -9,7 +9,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let (pk, sk) = MLDSA65::keygen().unwrap(); @@ -51,7 +51,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let (pk, sk) = MLDSA65::keygen().unwrap(); @@ -98,7 +98,7 @@ //! ```rust //! use bouncycastle_core::errors::SignatureError; //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! //! let (pk, _) = MLDSA65::keygen().unwrap(); //! @@ -116,7 +116,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let (pk, _) = MLDSA65::keygen().unwrap(); @@ -136,7 +136,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let msg = b"The quick brown fox jumped over the lazy dog"; @@ -182,7 +182,7 @@ //! ```rust //! use bouncycastle_core::errors::SignatureError; //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait}; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! //! let msg = b"The quick brown fox"; //! let ctx = b"FooTextDocumentFormat"; @@ -220,7 +220,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; //! //! let msg = b"The quick brown fox jumped over the lazy dog"; @@ -258,7 +258,7 @@ //! ```rust //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait}; //! use bouncycastle_mldsa::{MLDSA65PublicKeyExpanded, MLDSA65PrivateKeyExpanded}; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_core::errors::SignatureError; //! //! let msg = b"The quick brown fox"; @@ -303,7 +303,7 @@ //! //! ```rust //! use bouncycastle_core::errors::SignatureError; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_core::key_material::{KeyMaterial256, KeyType, KeyMaterialTrait}; //! use bouncycastle_hex as hex; //! use bouncycastle_mldsa::{MLDSA44, MLDSA44_SIG_LEN, MLDSATrait, MLDSAPublicKeyTrait, MuBuilder}; @@ -375,7 +375,7 @@ //! ```rust //! use bouncycastle_mldsa::{MLDSA65, MLDSATrait}; //! use bouncycastle_mldsa::{MLDSA65PublicKeyExpanded, MLDSA65PrivateKeyExpanded}; -//! use bouncycastle_core::traits::Signature; +//! use bouncycastle_core::traits::{Signer, SignatureVerifier}; //! use bouncycastle_core::errors::SignatureError; //! //! let msg = b"The quick brown fox jumped over the lazy dog"; @@ -412,7 +412,7 @@ use crate::{ }; use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial, KeyMaterial256, KeyMaterialTrait, KeyType}; -use bouncycastle_core::traits::{Algorithm, RNG, SecurityStrength, Signature, XOF}; +use bouncycastle_core::traits::{Algorithm, RNG, SecurityStrength, SignatureVerifier, Signer, XOF}; use bouncycastle_rng::HashDRBG_SHA512; use bouncycastle_sha3::{SHAKE128, SHAKE256}; use core::marker::PhantomData; @@ -421,7 +421,7 @@ use core::marker::PhantomData; #[allow(unused_imports)] use crate::hash_mldsa; #[allow(unused_imports)] -use bouncycastle_core::traits::PHSignature; +use bouncycastle_core::traits::{PHSignatureVerifier, PHSigner}; /*** Constants ***/ @@ -728,6 +728,15 @@ impl< GAMMA1_MASK_LEN, > { + /// Generate a keypair, sourcing randomness from bouncycastle's default os-backed RNG. + /// + /// Key generation is intentionally not part of the [Signer] / [SignatureVerifier] traits; + /// it is provided as an inherent associated function directly on the algorithm struct. + /// Error condition: basically only on RNG failures. + pub fn keygen() -> Result<(PK, SK), SignatureError> { + Self::keygen_from_os_rng() + } + /// Should still be ok in FIPS mode pub fn keygen_from_os_rng() -> Result<(PK, SK), SignatureError> { let mut seed = KeyMaterial256::new(); @@ -1722,7 +1731,7 @@ pub trait MLDSATrait< msg: &[u8], ctx: Option<&[u8]>, ) -> Result<[u8; 64], SignatureError>; - /// Same as [Signature::sign], but signs from an [MLDSAPrivateKeyExpanded]. + /// Same as [Signer::sign], but signs from an [MLDSAPrivateKeyExpanded]. fn sign_with_expanded_key( sk: &MLDSAPrivateKeyExpanded, msg: &[u8], @@ -1760,13 +1769,13 @@ pub trait MLDSATrait< mu: &[u8; 64], output: &mut [u8; SIG_LEN], ) -> Result; - /// Same as [Signature::sign_mu], but signs from an [MLDSAPrivateKeyExpanded]. + /// Same as [MLDSATrait::sign_mu], but signs from an [MLDSAPrivateKeyExpanded]. fn sign_mu_with_expanded_key( sk: &MLDSAPrivateKeyExpanded, A_hat: Option<&Matrix>, mu: &[u8; 64], ) -> Result<[u8; SIG_LEN], SignatureError>; - /// Same as [Signature::sign_mu_out], but signs from an [MLDSAPrivateKeyExpanded]. + /// Same as [MLDSATrait::sign_mu_out], but signs from an [MLDSAPrivateKeyExpanded]. fn sign_mu_with_expanded_key_out( sk: &MLDSAPrivateKeyExpanded, A_hat: Option<&Matrix>, @@ -1856,7 +1865,7 @@ pub trait MLDSATrait< seed: &KeyMaterial<32>, ctx: Option<&[u8]>, ) -> Result; - /// Same as [Signature::verify], but signs from an expanded key object. + /// Same as [SignatureVerifier::verify], but signs from an expanded key object. fn verify_with_expanded_key( pk: &MLDSAPublicKeyExpanded, msg: &[u8], @@ -1898,7 +1907,7 @@ impl< const GAMMA1_MINUS_BETA: i32, const GAMMA2_MINUS_BETA: i32, const GAMMA1_MASK_LEN: usize, -> Signature +> Signer for MLDSA< PK_LEN, SK_LEN, @@ -1923,10 +1932,6 @@ impl< GAMMA1_MASK_LEN, > { - fn keygen() -> Result<(PK, SK), SignatureError> { - Self::keygen_from_os_rng() - } - fn sign(sk: &SK, msg: &[u8], ctx: Option<&[u8]>) -> Result<[u8; SIG_LEN], SignatureError> { let mut out = [0u8; SIG_LEN]; Self::sign_out(sk, msg, ctx, &mut out)?; @@ -2005,7 +2010,56 @@ impl< unreachable!() } } +} +impl< + const PK_LEN: usize, + const SK_LEN: usize, + const SIG_LEN: usize, + PK: MLDSAPublicKeyTrait + MLDSAPublicKeyInternalTrait, + SK: MLDSAPrivateKeyTrait + + MLDSAPrivateKeyInternalTrait, + const TAU: i32, + const LAMBDA: i32, + const GAMMA1: i32, + const GAMMA2: i32, + const k: usize, + const l: usize, + const ETA: usize, + const BETA: i32, + const OMEGA: i32, + const C_TILDE: usize, + const POLY_Z_PACKED_LEN: usize, + const POLY_W1_PACKED_LEN: usize, + const LAMBDA_over_4: usize, + const GAMMA1_MINUS_BETA: i32, + const GAMMA2_MINUS_BETA: i32, + const GAMMA1_MASK_LEN: usize, +> SignatureVerifier + for MLDSA< + PK_LEN, + SK_LEN, + SIG_LEN, + PK, + SK, + TAU, + LAMBDA, + GAMMA1, + GAMMA2, + k, + l, + ETA, + BETA, + OMEGA, + C_TILDE, + POLY_Z_PACKED_LEN, + POLY_W1_PACKED_LEN, + LAMBDA_over_4, + GAMMA1_MINUS_BETA, + GAMMA2_MINUS_BETA, + GAMMA1_MASK_LEN, + > +{ fn verify(pk: &PK, msg: &[u8], ctx: Option<&[u8]>, sig: &[u8]) -> Result<(), SignatureError> { let mu = MuBuilder::compute_mu(&pk.compute_tr(), msg, ctx)?; @@ -2062,7 +2116,7 @@ impl< /// Note: this struct is only exposed for "pure" ML-DSA and not for HashML-DSA because HashML-DSA /// does not benefit from allowing external construction of the message representative mu. /// You can get the same behaviour by computing the pre-hash `ph` with the appropriate hash function -/// and providing that to HashMLDSA via [PHSignature::sign_ph]. +/// and providing that to HashMLDSA via [PHSigner::sign_ph]. pub struct MuBuilder { h: H, } diff --git a/crypto/mldsa/tests/bc_test_data.rs b/crypto/mldsa/tests/bc_test_data.rs index 77ae858..a732489 100644 --- a/crypto/mldsa/tests/bc_test_data.rs +++ b/crypto/mldsa/tests/bc_test_data.rs @@ -14,7 +14,7 @@ mod bc_test_data { use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyMaterialTrait, KeyType}; use bouncycastle_core::traits::{ - Hash, SecurityStrength, Signature, SignaturePrivateKey, SignaturePublicKey, + Hash, SecurityStrength, SignaturePrivateKey, SignaturePublicKey, SignatureVerifier, }; use bouncycastle_hex as hex; use bouncycastle_mldsa::{ diff --git a/crypto/mldsa/tests/hash_mldsa_tests.rs b/crypto/mldsa/tests/hash_mldsa_tests.rs index 4301d7b..ecdfb7c 100644 --- a/crypto/mldsa/tests/hash_mldsa_tests.rs +++ b/crypto/mldsa/tests/hash_mldsa_tests.rs @@ -2,7 +2,9 @@ mod hash_mldsa_tests { use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyType}; - use bouncycastle_core::traits::{Hash, PHSignature, Signature}; + use bouncycastle_core::traits::{ + Hash, PHSignatureVerifier, PHSigner, SignatureVerifier, Signer, + }; use bouncycastle_core_test_framework::signature::TestFrameworkSignature; use bouncycastle_hex as hex; use bouncycastle_mldsa::{ @@ -21,19 +23,19 @@ mod hash_mldsa_tests { let tf = TestFrameworkSignature::new(false, true); // Test HashML-DSA-SHA512 as a regular signature alg - tf.test_signature::(false); - tf.test_signature::(false); - tf.test_signature::(false); + tf.test_signature::(HashMLDSA44_with_SHA512::keygen, false); + tf.test_signature::(HashMLDSA65_with_SHA512::keygen, false); + tf.test_signature::(HashMLDSA87_with_SHA512::keygen, false); // Test HashML-DSA-SHA256 as a ph signature alg - tf.test_ph_signature::(false); - tf.test_ph_signature::(false); - tf.test_ph_signature::(false); + tf.test_ph_signature::(HashMLDSA44_with_SHA256::keygen, false); + tf.test_ph_signature::(HashMLDSA65_with_SHA256::keygen, false); + tf.test_ph_signature::(HashMLDSA87_with_SHA256::keygen, false); // Test HashML-DSA-SHA512 as a ph signature alg - tf.test_ph_signature::(false); - tf.test_ph_signature::(false); - tf.test_ph_signature::(false); + tf.test_ph_signature::(HashMLDSA44_with_SHA512::keygen, false); + tf.test_ph_signature::(HashMLDSA65_with_SHA512::keygen, false); + tf.test_ph_signature::(HashMLDSA87_with_SHA512::keygen, false); } #[test] diff --git a/crypto/mldsa/tests/mldsa_key_tests.rs b/crypto/mldsa/tests/mldsa_key_tests.rs index c2451a0..476a5b6 100644 --- a/crypto/mldsa/tests/mldsa_key_tests.rs +++ b/crypto/mldsa/tests/mldsa_key_tests.rs @@ -3,7 +3,7 @@ mod mldsa_key_tests { use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyMaterialTrait, KeyType}; use bouncycastle_core::traits::{ - SecurityStrength, Signature, SignaturePrivateKey, SignaturePublicKey, + SecurityStrength, SignaturePrivateKey, SignaturePublicKey, }; use bouncycastle_core_test_framework::signature::TestFrameworkSignatureKeys; use bouncycastle_hex as hex; @@ -15,17 +15,17 @@ mod mldsa_key_tests { MLDSAPrivateKeyTrait, MLDSATrait, }; use bouncycastle_mldsa::{ - MLDSA44_PK_LEN, MLDSA44_SIG_LEN, MLDSA44_SK_LEN, MLDSA65_PK_LEN, MLDSA65_SIG_LEN, - MLDSA65_SK_LEN, MLDSA87_PK_LEN, MLDSA87_SIG_LEN, MLDSA87_SK_LEN, + MLDSA44_PK_LEN, MLDSA44_SK_LEN, MLDSA65_PK_LEN, MLDSA65_SK_LEN, MLDSA87_PK_LEN, + MLDSA87_SK_LEN, }; #[test] fn core_framework_tests() { let tf = TestFrameworkSignatureKeys::new(); - tf.test_keys::(); - tf.test_keys::(); - tf.test_keys::(); + tf.test_keys::(MLDSA44::keygen); + tf.test_keys::(MLDSA65::keygen); + tf.test_keys::(MLDSA87::keygen); } #[test] diff --git a/crypto/mldsa/tests/mldsa_tests.rs b/crypto/mldsa/tests/mldsa_tests.rs index b5a1b5f..b87a0a8 100644 --- a/crypto/mldsa/tests/mldsa_tests.rs +++ b/crypto/mldsa/tests/mldsa_tests.rs @@ -5,7 +5,7 @@ mod mldsa_tests { use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyMaterialTrait, KeyType}; use bouncycastle_core::traits::{ - RNG, SecurityStrength, Signature, SignaturePrivateKey, SignaturePublicKey, + RNG, SecurityStrength, SignaturePrivateKey, SignaturePublicKey, SignatureVerifier, Signer, }; use bouncycastle_core_test_framework::DUMMY_SEED_1024; use bouncycastle_core_test_framework::signature::*; @@ -44,9 +44,9 @@ mod mldsa_tests { fn test_framework_signature() { let tf = TestFrameworkSignature::new(false, true); - tf.test_signature::(false); - tf.test_signature::(false); - tf.test_signature::(false); + tf.test_signature::(MLDSA44::keygen, false); + tf.test_signature::(MLDSA65::keygen, false); + tf.test_signature::(MLDSA87::keygen, false); } /// This runs the full bitflipping tests and takes several minutes. diff --git a/crypto/mldsa/tests/wycheproof.rs b/crypto/mldsa/tests/wycheproof.rs index bc7fd34..abe6842 100644 --- a/crypto/mldsa/tests/wycheproof.rs +++ b/crypto/mldsa/tests/wycheproof.rs @@ -20,7 +20,7 @@ use bouncycastle_core::errors::SignatureError; use bouncycastle_core::key_material::{KeyMaterial256, KeyMaterialTrait, KeyType}; use bouncycastle_core::traits::{ - SecurityStrength, Signature, SignaturePrivateKey, SignaturePublicKey, + SecurityStrength, SignaturePrivateKey, SignaturePublicKey, SignatureVerifier, }; use bouncycastle_hex as hex; use bouncycastle_mldsa::{ diff --git a/mem_usage_benches/bench_mldsa_mem_usage.rs b/mem_usage_benches/bench_mldsa_mem_usage.rs index 6dc8351..9f3ff49 100644 --- a/mem_usage_benches/bench_mldsa_mem_usage.rs +++ b/mem_usage_benches/bench_mldsa_mem_usage.rs @@ -21,7 +21,7 @@ #![allow(unused_imports)] use bouncycastle::core::key_material::{KeyMaterial256, KeyType}; -use bouncycastle::core::traits::{Signature, SignaturePrivateKey, SignaturePublicKey}; +use bouncycastle::core::traits::{SignatureVerifier, SignaturePrivateKey, SignaturePublicKey}; use bouncycastle::hex; use bouncycastle::mldsa::MLDSA44_SIG_LEN; From 7724605d11cd380ad06518b43492a77089bf100c Mon Sep 17 00:00:00 2001 From: Mike Ounsworth Date: Wed, 10 Jun 2026 13:00:11 -0500 Subject: [PATCH 13/13] Refactored the KEM trait into KEMEncapsuloter and KEMDecapsulator --- cli/src/mlkem_cmd.rs | 2 +- crypto/core-test-framework/src/kem.rs | 56 ++++++------- crypto/core/src/traits.rs | 78 ++++++++++--------- crypto/mldsa/src/hash_mldsa.rs | 8 +- .../mlkem-lowmemory/benches/mlkem_benches.rs | 2 +- crypto/mlkem-lowmemory/src/lib.rs | 3 +- crypto/mlkem-lowmemory/src/mlkem.rs | 58 +++++++++++--- .../mlkem-lowmemory/tests/mlkem_key_tests.rs | 12 +-- crypto/mlkem-lowmemory/tests/mlkem_tests.rs | 10 ++- crypto/mlkem-lowmemory/tests/wycheproof.rs | 2 +- crypto/mlkem/benches/mlkem_benches.rs | 2 +- crypto/mlkem/src/lib.rs | 3 +- crypto/mlkem/src/mlkem.rs | 51 ++++++++---- crypto/mlkem/tests/bc_test_data.rs | 2 +- crypto/mlkem/tests/mlkem_key_tests.rs | 14 ++-- crypto/mlkem/tests/mlkem_tests.rs | 10 ++- crypto/mlkem/tests/wycheproof.rs | 2 +- mem_usage_benches/bench_mlkem_mem_usage.rs | 9 +-- 18 files changed, 193 insertions(+), 131 deletions(-) diff --git a/cli/src/mlkem_cmd.rs b/cli/src/mlkem_cmd.rs index 2ac50e2..67214da 100644 --- a/cli/src/mlkem_cmd.rs +++ b/cli/src/mlkem_cmd.rs @@ -6,7 +6,7 @@ use crate::helpers::{ write_bytes_or_hex_to_file, }; use bouncycastle::core::key_material::KeyMaterialTrait; -use bouncycastle::core::traits::{KEM, KEMPrivateKey, KEMPublicKey}; +use bouncycastle::core::traits::{KEMDecapsulator, KEMEncapsulator, KEMPrivateKey, KEMPublicKey}; use bouncycastle::hex; use bouncycastle::mlkem::{ MLKEM512, MLKEM512_CT_LEN, MLKEM512_PK_LEN, MLKEM512_SK_LEN, MLKEM512PrivateKey, diff --git a/crypto/core-test-framework/src/kem.rs b/crypto/core-test-framework/src/kem.rs index cc16593..4509684 100644 --- a/crypto/core-test-framework/src/kem.rs +++ b/crypto/core-test-framework/src/kem.rs @@ -1,5 +1,5 @@ use bouncycastle_core::errors::KEMError; -use bouncycastle_core::traits::{KEM, KEMPrivateKey, KEMPublicKey}; +use bouncycastle_core::traits::{KEMDecapsulator, KEMEncapsulator, KEMPrivateKey, KEMPublicKey}; pub struct TestFrameworkKEM { // Put any config options here @@ -16,43 +16,48 @@ impl TestFrameworkKEM { Self { alg_is_deterministic, is_implicitly_rejecting } } - /// Test all the members of trait Hash against the given input-output pair. + /// Test all the members of traits [KEMEncapsulator] and [KEMDecapsulator] against the given input-output pair. /// This gives good baseline test coverage, but is not exhaustive. + /// + /// Since key generation is not part of either KEM trait, the caller supplies a + /// `keygen` function pointer (the inherent `keygen` associated function on the algorithm struct). pub fn test_kem< PK: KEMPublicKey, SK: KEMPrivateKey, - KEMAlg: KEM, + ENCAPSULATOR: KEMEncapsulator, + DECAPSULATOR: KEMDecapsulator, const PK_LEN: usize, const SK_LEN: usize, const CT_LEN: usize, const SS_LEN: usize, >( &self, + keygen: fn() -> Result<(PK, SK), KEMError>, run_full_bitflipping_tests: bool, ) { // Basic test - let (pk, sk) = KEMAlg::keygen().unwrap(); - let (ss, ct) = KEMAlg::encaps(&pk).unwrap(); - let ss1 = KEMAlg::decaps(&sk, &ct).unwrap(); + let (pk, sk) = keygen().unwrap(); + let (ss, ct) = ENCAPSULATOR::encaps(&pk).unwrap(); + let ss1 = DECAPSULATOR::decaps(&sk, &ct).unwrap(); assert_eq!(ss, ss1); // Test non-determinism if !self.alg_is_deterministic { - let (ss1, ct1) = KEMAlg::encaps(&pk).unwrap(); - let (ss2, ct2) = KEMAlg::encaps(&pk).unwrap(); + let (ss1, ct1) = ENCAPSULATOR::encaps(&pk).unwrap(); + let (ss2, ct2) = ENCAPSULATOR::encaps(&pk).unwrap(); assert_ne!(ss1, ss2); assert_ne!(ct1, ct2); } // Test that decaps fails for broken ct value - let (pk, sk) = KEMAlg::keygen().unwrap(); - let (ss, mut ct) = KEMAlg::encaps(&pk).unwrap(); + let (pk, sk) = keygen().unwrap(); + let (ss, mut ct) = ENCAPSULATOR::encaps(&pk).unwrap(); ct[17] ^= 0xFF; if self.is_implicitly_rejecting { - let ss2 = KEMAlg::decaps(&sk, &ct).unwrap(); + let ss2 = DECAPSULATOR::decaps(&sk, &ct).unwrap(); assert_ne!(ss, ss2); } else { - match KEMAlg::decaps(&sk, &ct) { + match DECAPSULATOR::decaps(&sk, &ct) { Err(KEMError::DecapsulationFailed) => /* good */ { @@ -71,10 +76,10 @@ impl TestFrameworkKEM { // should throw an Err if self.is_implicitly_rejecting { - let ss2 = KEMAlg::decaps(&sk, &ct_copy).unwrap(); + let ss2 = DECAPSULATOR::decaps(&sk, &ct_copy).unwrap(); assert_ne!(ss, ss2); } else { - match KEMAlg::decaps(&sk, &ct) { + match DECAPSULATOR::decaps(&sk, &ct) { Err(KEMError::DecapsulationFailed) => /* good */ { @@ -88,11 +93,10 @@ impl TestFrameworkKEM { } // test ct the wrong length - let (pk, sk) = KEMAlg::keygen().unwrap(); - let (_ss, ct) = KEMAlg::encaps(&pk).unwrap(); - + let (pk, sk) = keygen().unwrap(); + let (_ss, ct) = ENCAPSULATOR::encaps(&pk).unwrap(); // too short - match KEMAlg::decaps(&sk, &ct[..CT_LEN - 1]) { + match DECAPSULATOR::decaps(&sk, &ct[..CT_LEN - 1]) { Err(KEMError::LengthError(_)) => { /* good */ } _ => panic!("This should have thrown an error but it didn't."), }; @@ -100,7 +104,7 @@ impl TestFrameworkKEM { // too long let mut long_ct = vec![1u8; CT_LEN + 2]; long_ct.as_mut_slice()[..CT_LEN].copy_from_slice(&ct); - match KEMAlg::decaps(&sk, &long_ct) { + match DECAPSULATOR::decaps(&sk, &long_ct) { Err(KEMError::LengthError(_)) => { /* good */ } _ => panic!("This should have thrown an error but it didn't."), }; @@ -114,33 +118,31 @@ impl TestFrameworkKEMKeys { Self {} } + /// Since key generation is not part of either KEM trait, the caller supplies a + /// `keygen` function pointer (the inherent `keygen` associated function on the algorithm struct). pub fn test_keys< PK: KEMPublicKey, SK: KEMPrivateKey, - KEMAlg: KEM, const PK_LEN: usize, const SK_LEN: usize, - const CT_LEN: usize, - const SS_LEN: usize, >( &self, + keygen: fn() -> Result<(PK, SK), KEMError>, ) { - self.test_boundary_conditions::(); + self.test_boundary_conditions::(keygen); } /// Tests the correct behaviour on buffers too large / too small. fn test_boundary_conditions< PK: KEMPublicKey, SK: KEMPrivateKey, - KEMAlg: KEM, const PK_LEN: usize, const SK_LEN: usize, - const CT_LEN: usize, - const SS_LEN: usize, >( &self, + keygen: fn() -> Result<(PK, SK), KEMError>, ) { - let (pk, sk) = KEMAlg::keygen().unwrap(); + let (pk, sk) = keygen().unwrap(); let pk_bytes = pk.encode(); assert_eq!(pk_bytes.len(), PK_LEN); diff --git a/crypto/core/src/traits.rs b/crypto/core/src/traits.rs index 21894a2..5247bbd 100644 --- a/crypto/core/src/traits.rs +++ b/crypto/core/src/traits.rs @@ -182,24 +182,57 @@ pub trait KDF: Default { fn max_security_strength(&self) -> SecurityStrength; } -/// A Key Encapsulation Mechanism -pub trait KEM< +/// A Key Encapsulation Mechanism (KEM) is defined as a set of three operations: +/// key generation, encapsulation, and decapsulation. +/// +/// This trait represents the encapsulation operation performed by the holder of the public key. +/// Decapsulation operations are performed by the corresponding [KEMDecapsulator] trait, and key +/// generation is provided as an inherent associated function directly on the algorithm struct. +/// There are several reasons for this split: first is architectural; some complex algorithms may +/// benefit from having the encapsulation and decapsulation implementations split into separate modules. +/// Second is for compliance: sometimes a policy soft-deprecates an algorithm so that new ciphertexts +/// can no longer be created, but existing ciphertexts can still be decapsulated. Splitting the traits +/// makes this policy easier to enforce. +/// +/// The arrays used to encode public keys, ciphertexts, and shared secrets are statically-sized +/// because this allows us to safely remove runtime checks for array lengths, which overall reduces +/// the fallibility of the library. This design choice could make this trait complicated to apply +/// to a KEM algorithm that does not have fixed sizes for the encodings of these objects. +pub trait KEMEncapsulator< PK: KEMPublicKey, - SK: KEMPrivateKey, const PK_LEN: usize, - const SK_LEN: usize, const CT_LEN: usize, const SS_LEN: usize, >: Sized { - /// Generate a keypair. - /// Error condition: Basically only on RNG failures - fn keygen() -> Result<(PK, SK), KEMError>; - /// Performs an encapsulation against the given public key. /// Returns the ciphertext and derived shared secret. fn encaps(pk: &PK) -> Result<(KeyMaterial, [u8; CT_LEN]), KEMError>; +} +/// A Key Encapsulation Mechanism (KEM) is defined as a set of three operations: +/// key generation, encapsulation, and decapsulation. +/// +/// This trait represents the decapsulation operation performed by the holder of the private key. +/// Encapsulation operations are performed by the corresponding [KEMEncapsulator] trait, and key +/// generation is provided as an inherent associated function directly on the algorithm struct. +/// There are several reasons for this split: first is architectural; some complex algorithms may +/// benefit from having the encapsulation and decapsulation implementations split into separate modules. +/// Second is for compliance: sometimes a policy soft-deprecates an algorithm so that new ciphertexts +/// can no longer be created, but existing ciphertexts can still be decapsulated. Splitting the traits +/// makes this policy easier to enforce. +/// +/// The arrays used to encode private keys, ciphertexts, and shared secrets are statically-sized +/// because this allows us to safely remove runtime checks for array lengths, which overall reduces +/// the fallibility of the library. This design choice could make this trait complicated to apply +/// to a KEM algorithm that does not have fixed sizes for the encodings of these objects. +pub trait KEMDecapsulator< + SK: KEMPrivateKey, + const SK_LEN: usize, + const CT_LEN: usize, + const SS_LEN: usize, +>: Sized +{ /// Performs a decapsulation of the given ciphertext. /// Returns the derived shared secret. fn decaps(sk: &SK, ct: &[u8]) -> Result, KEMError>; @@ -635,35 +668,6 @@ pub trait SignatureVerifier< fn verify_final(self, sig: &[u8]) -> Result<(), SignatureError>; } -// todo: could the public and private key types impl Into> and From> -// todo: that automatically call the encode and from_bytes() ? - -/// A public key for a signature algorithm, often denoted "pk". -pub trait SignaturePublicKey: - PartialEq + Eq + Clone + Debug + Display + Sized -{ - /// Write it out to bytes in its standard encoding. - fn encode(&self) -> [u8; PK_LEN]; - /// Write it out to bytes in its standard encoding. - /// The entire output buffer is zeroized before the encoding is written. - fn encode_out(&self, out: &mut [u8; PK_LEN]) -> usize; - /// Read it in from bytes in its standard encoding. - fn from_bytes(bytes: &[u8]) -> Result; -} - -/// A private key for a signature algorithm, often denoted "sk" (for "secret key"). -pub trait SignaturePrivateKey: - PartialEq + Eq + Clone + Secret + Sized -{ - /// Write it out to bytes in its standard encoding. - fn encode(&self) -> [u8; SK_LEN]; - /// Write it out to bytes in its standard encoding. - /// The entire output buffer is zeroized before the encoding is written. - fn encode_out(&self, out: &mut [u8; SK_LEN]) -> usize; - /// Read it in from bytes in its standard encoding. - fn from_bytes(bytes: &[u8]) -> Result; -} - /// Extensible Output Functions (XOFs) are similar to hash functions, except that they can produce output of arbitrary length. /// The naming used for the functions of this trait are borrowed from the SHA3-style sponge constructions that split XOF operation /// into two phases: an absorb phase in which an arbitrary amount of input is provided to the XOF, diff --git a/crypto/mldsa/src/hash_mldsa.rs b/crypto/mldsa/src/hash_mldsa.rs index 9a4dc3d..b7e3988 100644 --- a/crypto/mldsa/src/hash_mldsa.rs +++ b/crypto/mldsa/src/hash_mldsa.rs @@ -968,12 +968,11 @@ impl< } impl< - HASH: Hash + Default, + HASH: Hash + Algorithm + Default, PK: MLDSAPublicKeyTrait + MLDSAPublicKeyInternalTrait, SK: MLDSAPrivateKeyTrait + MLDSAPrivateKeyInternalTrait, const PH_LEN: usize, - const oid: &'static [u8], const PK_LEN: usize, const SK_LEN: usize, const SIG_LEN: usize, @@ -997,7 +996,6 @@ impl< for HashMLDSA< HASH, PH_LEN, - oid, PK_LEN, SK_LEN, SIG_LEN, @@ -1138,9 +1136,8 @@ impl< } impl< - HASH: Hash + Default, + HASH: Hash + Algorithm + Default, const PH_LEN: usize, - const oid: &'static [u8], const PK_LEN: usize, const SK_LEN: usize, const SIG_LEN: usize, @@ -1167,7 +1164,6 @@ impl< for HashMLDSA< HASH, PH_LEN, - oid, PK_LEN, SK_LEN, SIG_LEN, diff --git a/crypto/mlkem-lowmemory/benches/mlkem_benches.rs b/crypto/mlkem-lowmemory/benches/mlkem_benches.rs index 1ecd65a..8ea83ba 100644 --- a/crypto/mlkem-lowmemory/benches/mlkem_benches.rs +++ b/crypto/mlkem-lowmemory/benches/mlkem_benches.rs @@ -1,5 +1,5 @@ use bouncycastle_core::key_material::{KeyMaterial512, KeyType}; -use bouncycastle_core::traits::KEM; +use bouncycastle_core::traits::KEMDecapsulator; use bouncycastle_hex as hex; use bouncycastle_mlkem_lowmemory::{ MLKEM_RND_LEN, MLKEM512, MLKEM512_CT_LEN, MLKEM768, MLKEM768_CT_LEN, MLKEM1024, diff --git a/crypto/mlkem-lowmemory/src/lib.rs b/crypto/mlkem-lowmemory/src/lib.rs index 137afb7..0f70fc5 100644 --- a/crypto/mlkem-lowmemory/src/lib.rs +++ b/crypto/mlkem-lowmemory/src/lib.rs @@ -155,7 +155,6 @@ //! //! ```rust //! use bouncycastle_mlkem_lowmemory::MLKEM768; -//! use bouncycastle_core::traits::KEM; //! //! let (pk, sk) = MLKEM768::keygen().unwrap(); //! ``` @@ -185,7 +184,7 @@ //! //! ```rust //! use bouncycastle_mlkem_lowmemory::{MLKEM768, MLKEMTrait}; -//! use bouncycastle_core::traits::KEM; +//! use bouncycastle_core::traits::{KEMEncapsulator, KEMDecapsulator}; //! use bouncycastle_core::errors::KEMError; //! //! let (pk, sk) = MLKEM768::keygen().unwrap(); diff --git a/crypto/mlkem-lowmemory/src/mlkem.rs b/crypto/mlkem-lowmemory/src/mlkem.rs index 3d75cb3..eca60d4 100644 --- a/crypto/mlkem-lowmemory/src/mlkem.rs +++ b/crypto/mlkem-lowmemory/src/mlkem.rs @@ -14,7 +14,9 @@ use crate::mlkem_keys::{MLKEMPublicKeyInternalTrait, MLKEMPublicKeyTrait}; use crate::polynomial::Polynomial; use bouncycastle_core::errors::KEMError; use bouncycastle_core::key_material::{KeyMaterial, KeyMaterialTrait, KeyType}; -use bouncycastle_core::traits::{Algorithm, Hash, KEM, RNG, SecurityStrength, XOF}; +use bouncycastle_core::traits::{ + Algorithm, Hash, KEMDecapsulator, KEMEncapsulator, RNG, SecurityStrength, XOF, +}; use bouncycastle_rng::HashDRBG_SHA512; use bouncycastle_sha3::{SHA3_256, SHA3_512, SHAKE256}; use bouncycastle_utils::ct::{conditional_copy_bytes, ct_eq_bytes}; @@ -233,6 +235,15 @@ impl< T_PACKED_LEN, > { + /// Generate a keypair, sourcing randomness from bouncycastle's default os-backed RNG. + /// + /// Key generation is intentionally not part of the [KEMEncapsulator] / [KEMDecapsulator] traits; + /// it is provided as an inherent associated function directly on the algorithm struct. + /// Error condition: basically only on RNG failures. + pub fn keygen() -> Result<(PK, SK), KEMError> { + Self::keygen_from_os_rng() + } + /// Should still be ok in FIPS mode pub fn keygen_from_os_rng() -> Result<(PK, SK), KEMError> { let mut seed = KeyMaterial::<64>::new(); @@ -333,13 +344,13 @@ impl< /// Output: shared secret key 𝐾 ∈ 𝔹32 . /// Output: ciphertext 𝑐 ∈ 𝔹32(π‘‘π‘’π‘˜+𝑑𝑣). /// - /// Unlike the more public function exposed by [KEM::encaps], this returns the shared secret as raw bytes + /// Unlike the more public function exposed by [KEMEncapsulator::encaps], this returns the shared secret as raw bytes /// instead of wrapped in an appropriately-set [KeyMaterialTrait], so you're on your own for handling it properly. /// /// Note: this is an internal function that allows the caller to specify the encapsulation /// randomness (which is the message `m` to be encrypted by the underlying PKE scheme). /// This function should not be used directly unless you really have a - /// good reason. [KEM::encaps] should be used in 99.9% of cases. + /// good reason. [KEMEncapsulator::encaps] should be used in 99.9% of cases. /// The reason this is exposed publicly is: A) for unit testing that requires access /// to the deterministically reproducible function, and B) for operational environments /// that wish to provide randomness from their own source instead of the built-in RNG in bc-rust. @@ -657,7 +668,7 @@ impl< const dv: i16, const LAMBDA: i16, const T_PACKED_LEN: usize, -> KEM +> KEMEncapsulator for MLKEM< PK_LEN, SK_LEN, @@ -674,11 +685,6 @@ impl< T_PACKED_LEN, > { - /// Generates a fresh key pair. - fn keygen() -> Result<(PK, SK), KEMError> { - Self::keygen_from_os_rng() - } - fn encaps(pk: &PK) -> Result<(KeyMaterial, [u8; CT_LEN]), KEMError> { let mut m = [0u8; 32]; HashDRBG_SHA512::new_from_os().next_bytes_out(&mut m)?; @@ -693,7 +699,41 @@ impl< Ok((ss_keymaterial, ct)) } +} +impl< + const PK_LEN: usize, + const SK_LEN: usize, + const FULL_SK_LEN: usize, + const CT_LEN: usize, + const SS_LEN: usize, + PK: MLKEMPublicKeyTrait + + MLKEMPublicKeyInternalTrait, + SK: MLKEMPrivateKeyTrait + + MLKEMPrivateKeyInternalTrait, + const k: usize, + const eta: i16, + const du: i16, + const dv: i16, + const LAMBDA: i16, + const T_PACKED_LEN: usize, +> KEMDecapsulator + for MLKEM< + PK_LEN, + SK_LEN, + FULL_SK_LEN, + CT_LEN, + SS_LEN, + PK, + SK, + k, + eta, + du, + dv, + LAMBDA, + T_PACKED_LEN, + > +{ fn decaps(sk: &SK, ct: &[u8]) -> Result, KEMError> { if ct.len() != CT_LEN { return Err(KEMError::LengthError("Invalid ciphertext length")); diff --git a/crypto/mlkem-lowmemory/tests/mlkem_key_tests.rs b/crypto/mlkem-lowmemory/tests/mlkem_key_tests.rs index 8a72ef9..6275f5e 100644 --- a/crypto/mlkem-lowmemory/tests/mlkem_key_tests.rs +++ b/crypto/mlkem-lowmemory/tests/mlkem_key_tests.rs @@ -1,12 +1,12 @@ #[cfg(test)] mod mlkem_key_tests { use bouncycastle_core::key_material::{KeyMaterial512, KeyMaterialTrait, KeyType}; - use bouncycastle_core::traits::{KEM, KEMPrivateKey, KEMPublicKey, SecurityStrength}; + use bouncycastle_core::traits::{KEMPrivateKey, KEMPublicKey, SecurityStrength}; use bouncycastle_hex as hex; use bouncycastle_mlkem_lowmemory::mlkem::MLKEM512_FULL_SK_LEN; use bouncycastle_mlkem_lowmemory::{ - MLKEM_SS_LEN, MLKEM512_CT_LEN, MLKEM512_PK_LEN, MLKEM512_SK_LEN, MLKEM768_CT_LEN, - MLKEM768_PK_LEN, MLKEM768_SK_LEN, MLKEM1024_CT_LEN, MLKEM1024_PK_LEN, MLKEM1024_SK_LEN, + MLKEM512_PK_LEN, MLKEM512_SK_LEN, + MLKEM768_PK_LEN, MLKEM768_SK_LEN, MLKEM1024_PK_LEN, MLKEM1024_SK_LEN, }; use bouncycastle_mlkem_lowmemory::{MLKEM512, MLKEM768, MLKEM1024}; use bouncycastle_mlkem_lowmemory::{ @@ -20,9 +20,9 @@ mod mlkem_key_tests { use bouncycastle_core_test_framework::kem::TestFrameworkKEMKeys; let tf = TestFrameworkKEMKeys::new(); - tf.test_keys::(); - tf.test_keys::(); - tf.test_keys::(); + tf.test_keys::(MLKEM512::keygen); + tf.test_keys::(MLKEM768::keygen); + tf.test_keys::(MLKEM1024::keygen); } #[test] diff --git a/crypto/mlkem-lowmemory/tests/mlkem_tests.rs b/crypto/mlkem-lowmemory/tests/mlkem_tests.rs index ff8cc5c..71cc449 100644 --- a/crypto/mlkem-lowmemory/tests/mlkem_tests.rs +++ b/crypto/mlkem-lowmemory/tests/mlkem_tests.rs @@ -3,7 +3,9 @@ mod mlkem_tests { use bouncycastle_core::errors::KEMError; use bouncycastle_core::key_material::{KeyMaterial512, KeyMaterialTrait, KeyType}; - use bouncycastle_core::traits::{KEM, KEMPrivateKey, KEMPublicKey, SecurityStrength, XOF}; + use bouncycastle_core::traits::{ + KEMDecapsulator, KEMEncapsulator, KEMPrivateKey, KEMPublicKey, SecurityStrength, XOF, + }; use bouncycastle_hex as hex; use bouncycastle_mlkem_lowmemory::mlkem::{ MLKEM512_FULL_SK_LEN, MLKEM768_FULL_SK_LEN, MLKEM1024_FULL_SK_LEN, @@ -46,9 +48,9 @@ mod mlkem_tests { let tf = TestFrameworkKEM::new(false, true); - tf.test_kem::(false); - tf.test_kem::(false); - tf.test_kem::(false); + tf.test_kem::(MLKEM512::keygen, false); + tf.test_kem::(MLKEM768::keygen, false); + tf.test_kem::(MLKEM1024::keygen, false); } /// This runs the full bitflipping tests and takes about 1.5 mins.. diff --git a/crypto/mlkem-lowmemory/tests/wycheproof.rs b/crypto/mlkem-lowmemory/tests/wycheproof.rs index b331a3f..f5570c6 100644 --- a/crypto/mlkem-lowmemory/tests/wycheproof.rs +++ b/crypto/mlkem-lowmemory/tests/wycheproof.rs @@ -25,7 +25,7 @@ #![allow(dead_code)] use bouncycastle_core::key_material::{KeyMaterial512, KeyMaterialTrait, KeyType}; -use bouncycastle_core::traits::{KEM, KEMPublicKey, SecurityStrength}; +use bouncycastle_core::traits::{KEMDecapsulator, KEMPublicKey, SecurityStrength}; use bouncycastle_hex as hex; use bouncycastle_mlkem_lowmemory::{ MLKEM512, MLKEM512PublicKey, MLKEM768, MLKEM768PublicKey, MLKEM1024, MLKEM1024PublicKey, diff --git a/crypto/mlkem/benches/mlkem_benches.rs b/crypto/mlkem/benches/mlkem_benches.rs index 5330f73..b445005 100644 --- a/crypto/mlkem/benches/mlkem_benches.rs +++ b/crypto/mlkem/benches/mlkem_benches.rs @@ -1,5 +1,5 @@ use bouncycastle_core::key_material::{KeyMaterial512, KeyType}; -use bouncycastle_core::traits::KEM; +use bouncycastle_core::traits::KEMDecapsulator; use bouncycastle_hex as hex; use bouncycastle_mlkem::{ MLKEM_RND_LEN, MLKEM512, MLKEM512_CT_LEN, MLKEM512PrivateKeyExpanded, MLKEM768, diff --git a/crypto/mlkem/src/lib.rs b/crypto/mlkem/src/lib.rs index 4de7d42..28142b6 100644 --- a/crypto/mlkem/src/lib.rs +++ b/crypto/mlkem/src/lib.rs @@ -46,7 +46,6 @@ //! //! ```rust //! use bouncycastle_mlkem::MLKEM768; -//! use bouncycastle_core::traits::KEM; //! //! let (pk, sk) = MLKEM768::keygen().unwrap(); //! ``` @@ -76,7 +75,7 @@ //! //! ```rust //! use bouncycastle_mlkem::{MLKEM768, MLKEMTrait}; -//! use bouncycastle_core::traits::KEM; +//! use bouncycastle_core::traits::{KEMEncapsulator, KEMDecapsulator}; //! use bouncycastle_core::errors::KEMError; //! //! let (pk, sk) = MLKEM768::keygen().unwrap(); diff --git a/crypto/mlkem/src/mlkem.rs b/crypto/mlkem/src/mlkem.rs index bd31e43..c87e896 100644 --- a/crypto/mlkem/src/mlkem.rs +++ b/crypto/mlkem/src/mlkem.rs @@ -30,7 +30,6 @@ //! ```rust //! use bouncycastle_mlkem::{MLKEM768, MLKEMTrait}; //! use bouncycastle_mlkem::{MLKEM768PublicKeyExpanded, MLKEM768PrivateKeyExpanded}; -//! use bouncycastle_core::traits::KEM; //! use bouncycastle_core::errors::KEMError; //! //! let (pk, sk) = MLKEM768::keygen().unwrap(); @@ -60,7 +59,7 @@ //! //! ```rust //! use bouncycastle_mlkem::{MLKEM768, MLKEMTrait}; -//! use bouncycastle_core::traits::KEM; +//! use bouncycastle_core::traits::KEMEncapsulator; //! use bouncycastle_core::errors::KEMError; //! use bouncycastle_core::key_material::{KeyMaterial512, KeyType}; //! use bouncycastle_hex as hex; @@ -104,7 +103,7 @@ //! //! ```rust //! use bouncycastle_mlkem::{MLKEM768, MLKEMTrait}; -//! use bouncycastle_core::traits::{KEM}; +//! use bouncycastle_core::traits::KEMDecapsulator; //! use bouncycastle_core::errors::KEMError; //! use bouncycastle_core::key_material::KeyMaterialTrait; //! @@ -142,12 +141,13 @@ use crate::mlkem_keys::{MLKEMPrivateKeyInternalTrait, MLKEMPrivateKeyTrait}; use crate::polynomial::Polynomial; use bouncycastle_core::errors::KEMError; use bouncycastle_core::key_material::{KeyMaterial, KeyMaterialTrait, KeyType}; -use bouncycastle_core::traits::{Algorithm, Hash, KEM, RNG, SecurityStrength, XOF}; +use bouncycastle_core::traits::{ + Algorithm, Hash, KEMDecapsulator, KEMEncapsulator, RNG, SecurityStrength, XOF, +}; use bouncycastle_rng::HashDRBG_SHA512; use bouncycastle_sha3::{SHA3_256, SHA3_512, SHAKE256}; use bouncycastle_utils::ct::{conditional_copy_bytes, ct_eq_bytes}; use core::marker::PhantomData; - /*** Constants ***/ /// @@ -319,6 +319,15 @@ impl< const LAMBDA: i16, > MLKEM { + /// Generate a keypair, sourcing randomness from bouncycastle's default os-backed RNG. + /// + /// Key generation is intentionally not part of the [KEMEncapsulator] / [KEMDecapsulator] traits; + /// it is provided as an inherent associated function directly on the algorithm struct. + /// Error condition: basically only on RNG failures. + pub fn keygen() -> Result<(PK, SK), KEMError> { + Self::keygen_from_os_rng() + } + /// Should still be ok in FIPS mode pub fn keygen_from_os_rng() -> Result<(PK, SK), KEMError> { let mut seed = KeyMaterial::<64>::new(); @@ -527,13 +536,13 @@ impl< /// Alternatively, you can use a [MLKEMPublicKeyExpanded] with [MLKEM::encaps_for_expanded_key]. /// If you specify None, the function will compute A_hat internally and everything will work fine. /// - /// Unlike the more public function exposed by [KEM::encaps], this returns the shared secret as raw bytes + /// Unlike the more public function exposed by [KEMEncapsulator::encaps], this returns the shared secret as raw bytes /// instead of wrapped in an appropriately-set [KeyMaterialTrait], so you're on your own for handling it properly. /// /// Note: this is an internal function that allows the caller to specify the encapsulation /// randomness (which is the message `m` to be encrypted by the underlying PKE scheme). /// This function should not be used directly unless you really have a - /// good reason. [KEM::encaps] should be used in 99.9% of cases. + /// good reason. [KEMEncapsulator::encaps] should be used in 99.9% of cases. /// The reason this is exposed publicly is: A) for unit testing that requires access /// to the deterministically reproducible function, and B) for operational environments /// that wish to provide randomness from their own source instead of the built-in RNG in bc-rust. @@ -843,12 +852,12 @@ pub trait MLKEMTrait< /// Returns either `()` or [KEMError::ConsistencyCheckFailed]. fn keypair_consistency_check(pk: &PK, sk: &SK) -> Result<(), KEMError>; - /// Same as [KEM::encaps], but acts on an [MLKEMPublicKeyExpanded]. + /// Same as [KEMEncapsulator::encaps], but acts on an [MLKEMPublicKeyExpanded]. fn encaps_for_expanded_key( pk: &MLKEMPublicKeyExpanded, ) -> Result<(KeyMaterial, [u8; CT_LEN]), KEMError>; - /// Same as [KEM::decaps], but acts on an [MLKEMPrivateKeyExpanded]. + /// Same as [KEMDecapsulator::decaps], but acts on an [MLKEMPrivateKeyExpanded]. fn decaps_with_expanded_key( sk: &MLKEMPrivateKeyExpanded, ct: &[u8], @@ -868,14 +877,9 @@ impl< const du: i16, const dv: i16, const LAMBDA: i16, -> KEM +> KEMEncapsulator for MLKEM { - /// Generates a fresh key pair. - fn keygen() -> Result<(PK, SK), KEMError> { - Self::keygen_from_os_rng() - } - /// Performs an encapsulation against the given public key, using the library's default internal RNG. /// Returns (shared_secret_key, ciphertext) /// The derived shared secret key is returned as a KeyMaterial with the SecurityStrength set to @@ -889,7 +893,24 @@ impl< fn encaps(pk: &PK) -> Result<(KeyMaterial, [u8; CT_LEN]), KEMError> { Self::encaps_for_expanded_key(&MLKEMPublicKeyExpanded::::from(pk)) } +} +impl< + const PK_LEN: usize, + const SK_LEN: usize, + const CT_LEN: usize, + const SS_LEN: usize, + PK: MLKEMPublicKeyTrait + MLKEMPublicKeyInternalTrait, + SK: MLKEMPrivateKeyTrait + + MLKEMPrivateKeyInternalTrait, + const k: usize, + const eta: i16, + const du: i16, + const dv: i16, + const LAMBDA: i16, +> KEMDecapsulator + for MLKEM +{ /// Performs a decapsulation of the given ciphertext. /// Returns the shared secret key. /// The derived shared secret key is returned as a KeyMaterial with the SecurityStrength set to diff --git a/crypto/mlkem/tests/bc_test_data.rs b/crypto/mlkem/tests/bc_test_data.rs index 5c14a28..036c85c 100644 --- a/crypto/mlkem/tests/bc_test_data.rs +++ b/crypto/mlkem/tests/bc_test_data.rs @@ -5,7 +5,7 @@ #[cfg(test)] mod bc_test_data { use bouncycastle_core::key_material::{KeyMaterial512, KeyMaterialTrait, KeyType}; - use bouncycastle_core::traits::{KEM, KEMPrivateKey, KEMPublicKey, SecurityStrength}; + use bouncycastle_core::traits::{KEMDecapsulator, KEMPrivateKey, KEMPublicKey, SecurityStrength}; use bouncycastle_hex as hex; use bouncycastle_mlkem::{ MLKEM512, MLKEM512_PK_LEN, MLKEM512_SK_LEN, MLKEM512PrivateKey, MLKEM512PublicKey, diff --git a/crypto/mlkem/tests/mlkem_key_tests.rs b/crypto/mlkem/tests/mlkem_key_tests.rs index 7317d50..4a4f3de 100644 --- a/crypto/mlkem/tests/mlkem_key_tests.rs +++ b/crypto/mlkem/tests/mlkem_key_tests.rs @@ -2,12 +2,12 @@ mod mlkem_key_tests { use bouncycastle_core::errors::KEMError; use bouncycastle_core::key_material::{KeyMaterial512, KeyMaterialTrait, KeyType}; - use bouncycastle_core::traits::{KEM, KEMPrivateKey, KEMPublicKey, SecurityStrength}; + use bouncycastle_core::traits::{KEMPrivateKey, KEMPublicKey, SecurityStrength}; use bouncycastle_hex as hex; use bouncycastle_mlkem::{ - MLKEM_SS_LEN, MLKEM512_CT_LEN, MLKEM512_PK_LEN, MLKEM512_SK_LEN, - MLKEM512PrivateKeyExpanded, MLKEM512PublicKeyExpanded, MLKEM768_CT_LEN, MLKEM768_PK_LEN, - MLKEM768_SK_LEN, MLKEM1024_CT_LEN, MLKEM1024_PK_LEN, MLKEM1024_SK_LEN, + MLKEM512_PK_LEN, MLKEM512_SK_LEN, + MLKEM512PrivateKeyExpanded, MLKEM512PublicKeyExpanded, MLKEM768_PK_LEN, + MLKEM768_SK_LEN, MLKEM1024_PK_LEN, MLKEM1024_SK_LEN, MLKEMPrivateKeyTrait, MLKEMPublicKeyTrait, MLKEMTrait, }; use bouncycastle_mlkem::{MLKEM512, MLKEM768, MLKEM1024}; @@ -22,9 +22,9 @@ mod mlkem_key_tests { let tf = TestFrameworkKEMKeys::new(); - tf.test_keys::(); - tf.test_keys::(); - tf.test_keys::(); + tf.test_keys::(MLKEM512::keygen); + tf.test_keys::(MLKEM768::keygen); + tf.test_keys::(MLKEM1024::keygen); } #[test] diff --git a/crypto/mlkem/tests/mlkem_tests.rs b/crypto/mlkem/tests/mlkem_tests.rs index c24abd2..d5aa274 100644 --- a/crypto/mlkem/tests/mlkem_tests.rs +++ b/crypto/mlkem/tests/mlkem_tests.rs @@ -3,7 +3,9 @@ mod mlkem_tests { use bouncycastle_core::errors::KEMError; use bouncycastle_core::key_material::{KeyMaterial512, KeyMaterialTrait, KeyType}; - use bouncycastle_core::traits::{KEM, KEMPrivateKey, KEMPublicKey, SecurityStrength, XOF}; + use bouncycastle_core::traits::{ + KEMDecapsulator, KEMEncapsulator, KEMPrivateKey, KEMPublicKey, SecurityStrength, XOF, + }; use bouncycastle_hex as hex; use bouncycastle_mlkem::{MLKEM_RND_LEN, MLKEM512, MLKEM768, MLKEM1024, Polynomial}; use bouncycastle_mlkem::{ @@ -41,9 +43,9 @@ mod mlkem_tests { let tf = TestFrameworkKEM::new(false, true); - tf.test_kem::(false); - tf.test_kem::(false); - tf.test_kem::(false); + tf.test_kem::(MLKEM512::keygen, false); + tf.test_kem::(MLKEM768::keygen, false); + tf.test_kem::(MLKEM1024::keygen, false); } /// This runs the full bitflipping tests and takes about 30s.. diff --git a/crypto/mlkem/tests/wycheproof.rs b/crypto/mlkem/tests/wycheproof.rs index ee3ddc9..a141e63 100644 --- a/crypto/mlkem/tests/wycheproof.rs +++ b/crypto/mlkem/tests/wycheproof.rs @@ -21,7 +21,7 @@ #![allow(dead_code)] use bouncycastle_core::key_material::{KeyMaterial512, KeyMaterialTrait, KeyType}; -use bouncycastle_core::traits::{KEM, KEMPrivateKey, KEMPublicKey, SecurityStrength}; +use bouncycastle_core::traits::{KEMDecapsulator, KEMPrivateKey, KEMPublicKey, SecurityStrength}; use bouncycastle_hex as hex; use bouncycastle_mlkem::{ MLKEM512, MLKEM512PrivateKey, MLKEM512PublicKey, MLKEM768, MLKEM768PrivateKey, diff --git a/mem_usage_benches/bench_mlkem_mem_usage.rs b/mem_usage_benches/bench_mlkem_mem_usage.rs index bd93ac4..99aafbc 100644 --- a/mem_usage_benches/bench_mlkem_mem_usage.rs +++ b/mem_usage_benches/bench_mlkem_mem_usage.rs @@ -26,12 +26,9 @@ #![allow(unused_imports)] use bouncycastle::core::key_material::{KeyMaterial512, KeyType}; -use bouncycastle::core::traits::{KEM, KEMPublicKey}; -use bouncycastle::mlkem::mlkem::MLKEMTrait; -use bouncycastle::mlkem::{ - MLKEM512_CT_LEN, MLKEM512_PK_LEN, MLKEM768_CT_LEN, MLKEM768_PK_LEN, MLKEM1024_CT_LEN, - MLKEM1024_PK_LEN, -}; +use bouncycastle::core::traits::{KEMDecapsulator, KEMEncapsulator, KEMPublicKey}; +use bouncycastle::mlkem::mlkem::{MLKEMTrait}; +use bouncycastle::mlkem::{MLKEM1024_CT_LEN, MLKEM1024_PK_LEN, MLKEM512_CT_LEN, MLKEM512_PK_LEN, MLKEM768_CT_LEN, MLKEM768_PK_LEN}; /// This exists so I can use /usr/bin/time to measure the base memory footprint of the cargo bench harness fn bench_do_nothing() {