diff --git a/src/algs.rs b/src/algs.rs index d90e7c5..c81ba22 100644 --- a/src/algs.rs +++ b/src/algs.rs @@ -1,15 +1,16 @@ use generic_array::{ArrayLength, GenericArray}; +use generic_array::typenum::U33; use rand_core::CryptoRngCore; use sha3::{ digest::{ExtendableOutput, Update, XofReader}, Shake256, }; - use crate::types::{ Adrs, ForsPk, ForsSig, HtSig, SlhDsaSig, SlhPrivateKey, SlhPublicKey, WotsPk, WotsSig, XmssSig, }; use crate::types::{FORS_PRF, FORS_ROOTS, FORS_TREE, TREE, WOTS_HASH, WOTS_PK, WOTS_PRF}; + /// Algorithm 1: `toInt(X, n)` on page 14. /// Convert a byte string to an integer. /// @@ -116,22 +117,11 @@ pub(crate) fn base_2b(x: &[u8], b: u32, out_len: usize, baseb: &mut [u64]) { // 14: return baseb (mutable parameter) } - -#[must_use] -pub(crate) fn shake256(input: &[&[u8]]) -> GenericArray { +pub(crate) fn shake256_a(input: &[&[u8]], out: &mut [u8]) { let mut hasher = Shake256::default(); input.iter().for_each(|item| hasher.update(item)); let mut reader = hasher.finalize_xof(); - let mut result = GenericArray::default(); - reader.read(&mut result); - result -} - - -pub(crate) fn f( - pk_seed: &[u8], adrs: &Adrs, tmp: &GenericArray, -) -> GenericArray { - shake256(&[&pk_seed, &adrs.to_32_bytes(), tmp]) + reader.read(out); } @@ -171,7 +161,8 @@ pub(crate) fn chain( adrs.set_hash_address(j.try_into().expect("usize->u32 fails")); // TODO: something better than expect? // 9: tmp ← F(PK.seed, ADRS, tmp) - tmp = f(pk_seed, &adrs, &tmp); + //tmp = f(pk_seed, &adrs, &tmp); + shake256_a(&[pk_seed, &adrs.to_32_bytes(), &tmp.clone()], &mut tmp[..]); // 10: end for } @@ -181,23 +172,10 @@ pub(crate) fn chain( } -#[allow(clippy::similar_names)] -pub(crate) fn prf( - pk_seed: &[u8], sk_seed: &[u8], adrs: &[u8], -) -> GenericArray { - shake256(&[&pk_seed, &adrs, &sk_seed]) // note order -} // NOTE ORDER - -#[allow(clippy::similar_names)] -pub(crate) fn prf2(a0: &[u8], b1: &[u8], c2: &[u8]) -> GenericArray { - shake256(&[&a0, &b1, &c2]) -} // NOTE ORDER - - pub(crate) fn tlen( pk_seed: &[u8], adrs: &Adrs, ml: &GenericArray, LEN>, ) -> GenericArray -where + where { let mut hasher = Shake256::default(); hasher.update(pk_seed); @@ -242,7 +220,8 @@ pub(crate) fn wots_pkgen( sk_adrs.set_chain_address(i); // 6: sk ← PRF(PK.seed, SK.seed, skADRS) ▷ Compute secret value for chain i - let sk = prf(pk_seed, sk_seed, &sk_adrs.to_32_bytes()); + let mut sk = GenericArray::default(); + shake256_a(&[pk_seed, &sk_adrs.to_32_bytes(), sk_seed], &mut sk); // Note spec swaps latter two parms // 7: ADRS.setChainAddress(i) adrs.set_chain_address(i); @@ -333,7 +312,8 @@ pub(crate) fn wots_sign( sk_addrs.set_chain_address(i as u32); // 17: sk ← PRF(PK.seed, SK.seed, skADRS) ▷ Compute secret value for chain i - let sk = prf(pk_seed, sk_seed, &sk_addrs.to_32_bytes()); + let mut sk = GenericArray::default(); + shake256_a(&[pk_seed, &sk_addrs.to_32_bytes(), sk_seed], &mut sk); // 18: ADRS.setChainAddress(i) adrs.set_chain_address(i as u32); @@ -408,7 +388,7 @@ pub(crate) fn wots_pk_from_sig( pk_seed, &adrs, ) - .expect("chain broke2!"); + .expect("chain broke2!"); // 14: end for } @@ -430,21 +410,6 @@ pub(crate) fn wots_pk_from_sig( } -#[allow(clippy::similar_names)] // lnode and rnode -pub(crate) fn h( - pk_seed: &[u8], adrs: &[u8], lnode: &[u8], rnode: &[u8], -) -> GenericArray { - let mut hasher = Shake256::default(); - [pk_seed, adrs, lnode, rnode] - .iter() - .for_each(|item| hasher.update(item)); - let mut reader = hasher.finalize_xof(); - let mut result = GenericArray::default(); - reader.read(&mut result); - result -} - - /// Algorithm 8: `xmss_node(SK.seed, i, z, PK.seed, ADRS)` on page 22. /// Compute the root of a Merkle subtree of WOTS+ public keys. /// @@ -478,7 +443,7 @@ pub(crate) fn xmss_node(sk_seed, pk_seed, &adrs).0.clone() // TODO remove clone? - // 8: else + // 8: else } else { // // 9: lnode ← xmss_node(SK.seed, 2 * i, z − 1, PK.seed, ADRS) @@ -497,7 +462,9 @@ pub(crate) fn xmss_node> k) & 1) == 0 { + let node_1 = if ((idx >> k) & 1) == 0 { // // 12: ADRS.setTreeIndex(ADRS.getTreeIndex()/2) let tmp = adrs.get_tree_index() / 2; adrs.set_tree_index(tmp); // 13: node[1] ← H(PK.seed, ADRS, node[0] ∥ AUTH[k]) - h(pk_seed, &adrs.to_32_bytes(), &node_0, &auth[k as usize]) + let mut node_1 = GenericArray::default(); + shake256_a(&[pk_seed, &adrs.to_32_bytes(), &node_0, &auth[k as usize]], &mut node_1); + node_1 // 14: else } else { @@ -607,7 +576,9 @@ pub(crate) fn xmss_pk_from_sig>= HP::to_u32(); @@ -726,7 +698,9 @@ pub(crate) fn ht_verify( sk_adrs.set_tree_index(idx); // 5: return PRF(PK.seed, SK.seed, skADRS) - prf(pk_seed, sk_seed, &sk_adrs.to_32_bytes()) + let mut res = GenericArray::default(); + shake256_a(&[pk_seed, &sk_adrs.to_32_bytes(), sk_seed], &mut res); // Note the spec swaps latter two parms + res } @@ -807,7 +783,7 @@ pub(crate) fn fors_node( let node = if z == 0 { // // 5: sk ← fors_SKgen(SK.seed, PK.seed, ADRS, i) - let sk = fors_sk_gen(sk_seed, pk_seed, &adrs, i); + let sk: GenericArray = fors_sk_gen(sk_seed, pk_seed, &adrs, i); // 6: ADRS.setTreeHeight(0) adrs.set_tree_height(0); @@ -816,7 +792,9 @@ pub(crate) fn fors_node( adrs.set_tree_index(i); // 8: node ← F(PK.seed, ADRS, sk) - f(pk_seed, &adrs, &sk) + let mut node = GenericArray::default(); + shake256_a(&[pk_seed, &adrs.to_32_bytes(), &sk], &mut node); + node // 9: else } else { @@ -834,7 +812,9 @@ pub(crate) fn fors_node( adrs.set_tree_index(i); // 14: node ← H(PK.seed, ADRS, lnode ∥ rnode) - h(pk_seed, &adrs.to_32_bytes(), &lnode, &rnode) + let mut node = GenericArray::default(); + shake256_a(&[pk_seed, &adrs.to_32_bytes(), &lnode, &rnode], &mut node); + node // 15: end if }; @@ -933,7 +913,8 @@ pub(crate) fn fors_pk_from_sig( adrs.set_tree_index(i * 2u32.pow(A::to_u32()) + indices[i as usize] as u32); // 6: node[0] ← F(PK.seed, ADRS, sk) - let mut node_0 = f(pk_seed, &adrs, &sk); + let mut node_0 = GenericArray::default(); + shake256_a(&[pk_seed, &adrs.to_32_bytes(), &sk], &mut node_0); // 7: // 8: auth ← SIGFORS.getAUTH(i) ▷ SIGFORS [(i · (a + 1) + 1) · n : (i + 1) · (a + 1) · n] @@ -953,7 +934,9 @@ pub(crate) fn fors_pk_from_sig( adrs.set_tree_index(tmp); // 13: node[1] ← H(PK.seed, ADRS, node[0] ∥ auth[j]) - h(pk_seed, &adrs.to_32_bytes(), &node_0, &auth.tree[j as usize]) + let mut node_1 = GenericArray::default(); + shake256_a(&[pk_seed, &adrs.to_32_bytes(), &node_0, &auth.tree[j as usize]], &mut node_1); + node_1 // 14: else } else { @@ -963,7 +946,9 @@ pub(crate) fn fors_pk_from_sig( adrs.set_tree_index(tmp); // 16: node[1] ← H(PK.seed, ADRS, auth[j] ∥ node[0]) - h(pk_seed, &adrs.to_32_bytes(), &auth.tree[j as usize], &node_0) + let mut node_1 = GenericArray::default(); + shake256_a(&[pk_seed, &adrs.to_32_bytes(), &auth.tree[j as usize], &node_0], &mut node_1); + node_1 // 17: end if }; @@ -990,7 +975,13 @@ pub(crate) fn fors_pk_from_sig( fors_pk_adrs.set_key_pair_address(adrs.get_key_pair_address()); // 25: pk ← Tk(PK.seed, forspkADRS, root) - let pk = tlen(pk_seed, &fors_pk_adrs, &root); + let mut pk = GenericArray::default(); // TODO: UGLY UGLY UGLY!! + let mut root_refs: GenericArray<&[u8], U33> = GenericArray::default(); + root_refs[0] = &pk_seed; + let binding = fors_pk_adrs.to_32_bytes(); + root_refs[1] = &binding; + root.iter().enumerate().for_each(|(a, b)| root_refs[a + 2] = b); + shake256_a(&root_refs[0..K::to_usize() + 2], &mut pk); // 26: return pk; ForsPk { key: pk } @@ -1080,7 +1071,8 @@ pub(crate) fn slh_sign_with_rng< } // 7: R ← PRF_msg(SK.prf, opt_rand, M) ▷ Generate randomizer - let r = prf2(&sk.sk_prf, &opt_rand, m); + let mut r = GenericArray::default(); + shake256_a(&[&sk.sk_prf, &opt_rand, m], &mut r); // 8: SIG ← R @@ -1089,7 +1081,8 @@ pub(crate) fn slh_sign_with_rng< // 9: // 10: digest ← H_msg(R, PK.seed, PK.root, M) ▷ Compute message digest - let digest = h::(&r, &sk.pk_seed, &sk.pk_root, m); + let mut digest: generic_array::GenericArray = GenericArray::default(); + shake256_a(&[&r, &sk.pk_seed, &sk.pk_root, m], &mut digest); // 11: md ← digest[0 : ceil(k·a/8)] ▷ first ceil(k·a/8) bytes @@ -1169,7 +1162,7 @@ pub(crate) fn slh_verify< // 1: if |SIG| != (1 + k(1 + a) + h + d · len) · n then // 2: return false // 3: end if - // TODO: THIS FUNCTION PROBABLY WANTS A BYTE ARRAY SIGNATURE, THEN DESERIALIZE (??) + // The above size is performed in the wrapper/adapter deserialize function // 4: ADRS ← toByte(0, 32) let mut adrs = Adrs::default(); @@ -1185,7 +1178,8 @@ pub(crate) fn slh_verify< // 8: // 9: digest ← Hmsg(R, PK.seed, PK.root, M) ▷ Compute message digest - let digest = h::(r, &pk.pk_seed, &pk.pk_root, m); + let mut digest: generic_array::GenericArray = GenericArray::default(); + shake256_a(&[&r, &pk.pk_seed, &pk.pk_root, m], &mut digest); // 10: md ← digest[0 : ceil(k·a/8)] ▷ first ceil(k·a/8) bytes let index1 = (K::to_usize() * A::to_usize()).div_ceil(8); diff --git a/src/lib.rs b/src/lib.rs index d8b4c6d..b835b24 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,14 +3,12 @@ #![deny(warnings)] #![deny(missing_docs)] // TODO -// 1. Get one instance working (or at least not erroring) -// 3. revisit/clean hash functions +// 1. General clean-up +// 2. revisit/clean hash functions +// 3. Doc, of course! //! TKTK crate doc -//extern crate alloc; -//extern crate core; // TODO: remove (with vecs) - mod algs; mod test; mod traits; @@ -30,7 +28,6 @@ macro_rules! functionality { /// blah /// # Errors - /// pub fn slh_keygen_with_rng( rng: &mut impl CryptoRngCore, ) -> Result<(SlhPrivateKey, SlhPublicKey), &'static str> { @@ -39,20 +36,19 @@ macro_rules! functionality { /// blah /// # Errors - /// pub fn slh_sign_with_rng( rng: &mut impl CryptoRngCore, m: &[u8], sk: &SlhPrivateKey, randomize: bool, - ) -> Result, U3>, N>, &'static str> { - crate::algs::slh_sign_with_rng::, U3>, M, N>( - rng, &m, &sk, randomize, - ) + ) -> Result<[u8; SIG_LEN], &'static str> { + let sig = crate::algs::slh_sign_with_rng::, U3>, M, N>(rng, &m, &sk, randomize); + sig.map(|s| s.deserialize()) } /// blah #[must_use] pub fn slh_verify( - m: &[u8], sig: &SlhDsaSig, U3>, N>, pk: &SlhPublicKey, + m: &[u8], sig_bytes: &[u8; SIG_LEN], pk: &SlhPublicKey ) -> bool { + let sig = SlhDsaSig::, U3>, N>::serialize(sig_bytes); crate::algs::slh_verify::, U3>, M, N>(&m, &sig, &pk) } @@ -71,9 +67,9 @@ macro_rules! functionality { let sig = slh_sign_with_rng(&mut rng, &message, &sk, false).unwrap(); let result = slh_verify(&message, &sig, &pk); assert_eq!(result, true, "Signature failed to verify"); - message[3] = i + 1 as u8; + message[3] = (i + 1) as u8; let result = slh_verify(&message, &sig, &pk); - assert_eq!(result, false, "Signature should not have verifed"); + assert_eq!(result, false, "Signature should not have verified"); } } } @@ -93,7 +89,7 @@ pub mod slh_dsa_sha2_128s { type K = U14; type M = U30; //const PK_LEN: usize = 32; - //const SIG_LEN: usize = 7856; + const SIG_LEN: usize = 7856; //const SK_LEN: usize = 0000; functionality!(); diff --git a/src/test.rs b/src/test.rs index 89ff71e..c791718 100644 --- a/src/test.rs +++ b/src/test.rs @@ -42,7 +42,6 @@ mod tests { use crate::slh_dsa_sha2_128s::{slh_keygen_with_rng, slh_sign_with_rng, slh_verify}; - #[ignore] #[test] fn vector_debug() { let m = @@ -58,35 +57,13 @@ mod tests { rnd.push(&decode(sk_seed).unwrap()); let (sk, pk) = slh_keygen_with_rng(&mut rnd).unwrap(); - assert_eq!( - *decode("ac524902fc81f5032bc27b17d9261ebd").unwrap(), - *sk.pk_root, - "pk_root failed!!!!!!" - ); + assert_eq!(*decode("ac524902fc81f5032bc27b17d9261ebd").unwrap(), *sk.pk_root, "pk_root failed!!!!!!"); - let sig = slh_sign_with_rng(&mut rnd, &m, &sk, true).unwrap(); - assert_eq!( - *decode("43f8eb75d58b652f779c5a0f5378709e").unwrap(), - *sig.fors_sig.private_key_value[0], - "fors_sig failed!!!" - ); - assert_eq!( - *decode("ad62955228fdf4c3be9c22f601397a11").unwrap(), - *sig.ht_sig.xmss_sigs[0].sig_wots.data[0], - "fors_sig failed!!!" - ); - //println!("{:x?}", &sig); - - let mut sig_array_act = [0u8; 7856]; - let sig2 = sig.clone(); - sig2.deser(&mut sig_array_act); + let sig_act = slh_sign_with_rng(&mut rnd, &m, &sk, true).unwrap(); let sig_exp = decode("07eb19e7d838d71ef66b8263b5d1f8ec43f8eb75d58b652f779c5a0f5378709eff39c179556ee3871600fa606ff751dcccce5e7a6981fbb8a0e959afff26ea6aef4fef5ccb66728f9d119ca2a547f0af0d3509364c7e3c9981e930c8c77ac74b8f385979dc8582063eac5b2a2532c8eb97fe1bea498bdb8b6496fcd3c5931393ac17cf96ccb35aaa9c7491b1a9897ccfbf35b70fec94687aad4e06c1b8d3aea67554d470804eec25309bf34c6487aea92b1d49edfc7afcb31d78ad4be8c1e4403b634d2db503b8cd08270dc3579aa8d639c33d024d3bebb9d401424b009793dd87053e5e0d0538b90a7a5324e5f08a8ab13de4dc1ed0b9848b421f40e5cd1ab70f07f652f3df23853c1d44ff0da5dac93d0fdd2007a1100b3c4abc9779e0fae578653d3848b520e96300cabce717b11dc1257f6c0c54add4fef22be57a67c45b288997b8f496f6fb3cde4a4cbb646b6cd922c7cb04c0bc2dd1bddca39a6154c10a07a1110c23df6b89dfd65c4107371cb98a352f88ce579bf49cda3c7062f9744594b9e431391e85622b13a6356a8fc1900f29dfd0d2a408aa2f15958707a14948294194cc3d51d26ca81dd64fa8a119d156e83ac0b1350ee98ef246e04b85edcf6567f917f4aa1e379244465145f9965a4f7a56fb14a949a0bcd08550a2de294f74ce74bf178dcf521a27d2ef642aeb05b38f835b7cd0e4ad4f2279c46c50378c06d4829ada543cac46a56fdd681dd4f473d792250cfece0fa98fecf1735caf37ec75b00a6212cfd31f57550c89e7acf2cdb257e5c021d1d465b7663b0b64d0e47b38460fcc28b1cf9e40ec44d420fa5677043ad647eb5c80b58ba88fc55e1c5c394a0f7e592a0edcb1dcf6ccfc5f1b25b30ca191e8c31232a39b0563d5b7dc2ad42582b58efbf84cb34d4572a8146ef8da7dace23229a732a901f15c7cb1a36aaa82838d6f554e49f2f18b9b73f7ef1fcc325bb31e668167c74777e0606806d81420df2dedcd56538d5d1386f2122b71e894e348820594869b84455d9a195061dfe1fc2795acb7103f25522caa538420af67dd03859480e0d046c8f175038d78d603af58176a1ab26f560ec78a8f2e45f4fa9da71f2e99c9ce038e5d95b07e8dfad89b8c6b1fb990b081bda6e848d8ce5577f852481396175cfcab40fc296e71996ec4a5c6d52a8a237bdcdc2b57680e9379deed17f929e774bf90906de5c3941a212801dd09e58a013a08a8903a0aabaa90118250370b3318db6b17f586b961a2a98678cf54ca6c422dfe32767c99ad4e12a28a3b36e85bc299f0881a5ff4d2e0efea327656f67851fdd95fd8b9d1bd941345b7ab065f78a8c342a5184ef6150f304e7d7b806de025d5c571831ad4537db35033b0121effeccdb100ecaa9805dc90e965995b39748c645e644331fee496956b6a1fb7a6029eafbae80be5e68c5aa66b369c9e9d7c96c77d32592c6696e3368ccae005a479492d400c926df2b809dcf1c49e77877792ef9c9c1cef36e679e9bfc01a67c92f093cd8ee4ec44fbc0318988014650f4d158edc630443cfde99d674f9763f20c60ea3657a2ea53af1fc2a3e7ea723e546eecfdf3be0309f5a773c228c168fdbcc97325cab9c9137322736a606935f6aa74a10d0f5bc6a83aed3fd2cd94621fbafef01bb3e601222522a9c9f6d4ceae117a2d53d2bd774eaa5948a1fa9a83b871bf763ba4787117ec0e7d62cd587edaae53427fd56e7dd25c9525886ef401a05bb58d3647e305314ba9a2c1c10a394b6cc7ce983fd11f79f6c05a624e16699be007cc57cabfb972a1b1988c1e47b4394fe4a404d0aa641b4281aa98ee047d22466c09f3a0dbf7ec6e51bfcfbe6380a23b81e6062300710423b44e88f8967f4f88e559486f7ef84726c501224c4a9faebce33e188bf9a72edee1326438f23620eaad0ab0ce53a87e8b410f243511eb3ef87c9f7af983c4b0d6e6b2a1a1407ac10c1305cda22d6dd0bbc470fd61c2e4a38c4244dd2a7ceb9d347d8d8f58906cc5b1c5934c973b048fa97a49c39a401c452a92ae8c826781b3edb77416625213e826aa6bbb131dda303cf63cd4f6f200056d13e69be148be51eaee8d059fc47f7ffeb24796a79007c0b83b75be70eeb65f46fc51c071f4ef7bc24d71374cd7955c88bc28f4ee285b6823a45abc8b157c3275c49a925d7ad45183b4f09687a8002e54635f8294768f711a47499234b7a57c5a311534920f12c284ed21522b25ca7890610aaac91666ac54bab87c3f3a566d31f1a66689d6036e968ab30c162da446ebc7cfaa9eb9bf22a8652926e7334265897b2af934d8c2bc261b4d86aaffcce72d7514326052f8c4120868be79b05c9a8f3068a5ee4e5d82b5d3d7afd3d03490caa9a3d75084e2906dc039e72837e85768d7c034b17d26eac57a86f5a3f000dfb783089d14532048eab5bfcb65f1e21af9869254f3a0873a8cb1d94c4a4849972e0d1013d3918631830473529bf392c35948e7fd8b5f60dbc03c168d3d5e5d4f074910ae674740c37be037d84d4390708aaaff47a64ad23ffeda22b8eb0006d9ab9eaa629a07899c6d9f79615a4c6c05cd2639dc87d53f60bb78e0c246766a1de332ca6f6f9b0dcaf58d3fa82149d2e244721f5c47fa6734a01071ab23a871ebeb676a16151402223cda2901338c17d5b0c59139ba82403709bce2ee6cb5b8a419a74ca8046b9da98a10efa6fa5726e235ec329938f4f36e0b3310ed946cce3f2f05a23bf7b203ad82057d8ab2dd6e6f9614187fe90ae1397a927bad5bdea19768da4e1277fdbc2465b73fd0f224a94ed00a765268b081288d14342a0e303e106bf460c247ba3bfb806da76264b8c0b0364e81da052ea399bfa331170c130e96f268c0f3c2deaa8df5462b685ad128c6a1fab979d8187cef285a555416ba01165abfec8e0fd44030288cf475f82c60f50323b3277a965f7fe57c78ec1ff8fa798f0b3f10fb4307e8c8f516a7c8ea8ef723c14782906e6295fe14af513e20f12577d53e7108d0c82ffbd5b9671afee77a7aea7f6f90b49da727447681a4de3ac28a892086026de61794cbdc43d2539379c0d16a44631e36ab058a7bda1b02f484e5a76b47f5a684fbf0a88b74721e9f28cd4cc3121ec938a042bbe315580cb7ed924de0a542bea6f52eda7c923449b41859268389694fa5f7f2cc4784b89952ff8569d7d75e1a4ee7ae7edd1fdc45a5c50b14a6d123e055f6704a25bf90b0c509e219f03d07f3d23c70437901eaff3a8110c6d24ba729553c184236189f3adc1eb5c1b8eabe544e7acd94770e44aa2660da38321c1c8e1151c96c15204cd8a661f1d5d4bced5e7e82012d3bdb6d99e9661c96de8be6bd5f4cc95991a5a4564e33acab99b1a8174610464af89d87bce2622e03ebfc5809ed27770d17137455995e05b5fbea2704da46a6968803fa7340af422db2777e2ab00c44ac0012f5495fc6728b1188400503f3a08e833359e678dae7d23d19391d6f822dd867e629d4ad8509c1510795b4268cad99acc0f73e5aa4b0fbabff30abc2ec614c3ef558d1fc5f4123a4cabb701a48f3f5d5e086426b8de105698599e81de7e4e78c153acc24ba435f943761e2203520fac0f10011ee5860d90241e06261c7b23ec61206357af23a6d8f18e41d572da802ef827ef4857a8ffdbf1dbf980756785fd7a5b3ae6235844d6fa58e7345ae767f77fa9bef0423c7d5d5759022c8953c8de5663d856b27f8b7970bd442c27869f2d08c84b2f1c35f3081bfe9d680998786591301912850b61902439b04c9bd58f1521c7832ea9dfcf8ec461435a0972d876717fd21ad56a68652f74a4bc717825c98e4e408f6f0c233b5650ea5e21b0e27b9f7987568d70e49e9919be1ada26d4613ddf96c748fc195c59cef3c20e6839a9a5ebaed476d8c2e775735eda1a25b4bde7aff4acd9c0fe7a64a4d59c123229e25a14f05e90166b2348c935f511d3ad1ae94b4e67b4ced7e9e7235e90e1f6349128e3b0df59e0e4c656bc44f59f1ef3deada102d7aa64638d2e5f85f459c2343049300e924dbc19482f4dceb78d2721c303f045cc008ae0408ed8ad68b2d6ea105166b8eaa60f971a53eee16831d7639da898c959a21b35c7df2782358f19ad62955228fdf4c3be9c22f601397a11aa015dedd38507af0fdb66630a1be7bfa33256ffe71bf0f89ed0ff10308beeade6e9adff75cf4e48c3f7190e02822fa3ad9f6f358fc664e59275daa9b933d4428458bb0fb89d5d13e11decb47a8e50d66cf14bb54f818e27c2161e1a195ff6fd76cae99ac86ef222f0fc398f99e3791b9018d73e9b535f9b8144bade55618824fca2b069667e2bf126895f86e183f430aa8961b7ee7cb437dd5c4b932069fbcff6e5bf725d2694ab6e910d68c4c165cbd3c5b9f96c0f35de72c9ebab10ca749231d7d1ecc5c2ddf0f7935907dff1897e3c1a1cf881b6701621ee50319b90c86cd2ed219605db6322b059947c4d8dc3ce3d81d045714ba4a4224d36f0b9cd54b79957872a8da4f596699e11ff9b72be5ecb9742891b95bc414204a351ac74ed4142514938b657492d8dd9d418c45c5df7351a8a685d5861c776959a77fc33f04e090ff543c5342e5147186906b9d1b3d13ec20e210b3b83a6129728abc0fc053e7f81fce4a66a9304bf2ab51e9ca0a11637a4792bc050eb678939ad86875f9497c9d52b0a32048eb3506180fa1f251f3f7e2908033e017687aae393c767579c768a091a1559dcdf6ce18f1e8591d8276b22cf06d9297b84f61ad350b8a81e5097ca1ff7d90f91de00439c3825832a93327c987916e079f56ece29209f74cea18e81d93e78974684bf01dd6e62b991fa6e1e32db935761652afeb5178c5de579e47d4e579871454e95fc651d9dde6ebbaa08ce4c82b7c36bb02cd024404059fbf2d0790cbd93dcccea566030933e4a58b88a23ad3f596992b23f45566869777b1b12070ae7b1bdebc0360f2e76cc266765930a5edb0f0c0536a2e8590fafc0a02396c1049a0d0029b873ded63a70b3080db0bce8c5ba703994b96b170a6bb6fe440568a212442aa121b1c18578b24f97523a80e46daf9b340899b05d5af4264dba6aa2fdd363e924bf7ea2f6550edfe48d24e852ecf53f82e10e47aba2a6cb72637703aea31d6158bf5fb1cb5160123ffc6f6468ba522505167e804a68f7267fbcc78723273af95ce853187aae169d4e9fa41e5fc0fa715b53faf686a06d679d34232eb166176edce277f7f4b0847c5ab6e52c11779e9b62df0e42c19c77c44756433a4817c4a84cd8d8f5c8d32ea246a4a34995ea4e4f8e31ce532a499ff50fe2ec01d7d4e3386bf389be1ecbc914fc481a6397f6598eeec872ab4783f95a5f864b9e2ec9a53ae9432e6de2ee4b45ccdee7bc5b8451f8ce0e9f4d6dd154dc8c57284d6b9f6c27471fe354be61733b7213769244c16539446e80d7760ed6e4d3747c5505e2078ccb7fdd7c34d07e7f8f3a354427b281a982cc77225ae8df5565eeddc73b605f757c79ebc9b468380fa192989a91008971f05bd03e80fdc82baea15264fd36d343782fe8d9bbf6323ca2b63c5920d2eb1b13b5a50c5314f7ac5a8968e281d8e1460cbac0e1a7e8233fb10b4e180dfe29c9f94041df9f4cd765d5c8ae45ac05548e732fb1018db4fa5e954f35ea88c5638c1b9983708f7c8013939b9604954d8e408729a495d2995f01f6c1df28ec303f701c165596771a438b933123b4214789fd31069cc6ce8435ba524384c9352854a845e5e3c1b27e50e3300f69ee4cf14fc52735ef1cc63dda2baa6b278f7383f9eb4e22206106803f72209f55918f000f27798d3f0a9040d4666778b36c6db25421176c44383e373d520f50dbfe48a9c268638b8c22f3639c86e9c104ecc3d222b692092e46d0e2ca546417ae1def31f5b4bd7a619b255378551f227cffe31a4436f062da978c6e95e959d2bb342e5328bdf9cd460fe154d13b9995c2f92613c564c88d972012faadc6a9bbeee0734e96f5ff55fdea1eefb50a1e059c53935c1b35820d2cd39b7705d66eda7c7adfa9b5b90cb97a261e10409a2eec2d5703be7c75443bdcb78d74fbc977394da78332a2be69416788c8e33be4bcc6f5466ba8c5ce2b7d5258d3a76c926f0663f7615a9fb08f8bb2c50283c14c2ba81af8b29ae11ae0f21d52be009fa4362831afd508c42e982dc23f249b33a162fde1cc854f85047eee35af5dedee193445e7748a3d6922dc462abfbc382a482a1651b4f3a5e4b6da2fb7e6fba7752828a0d52ec15c6041365f0ed760b0c9148fb45169ef99bb68bf129269cc9fd8bdd74f58d9863ba1fc4f17cd9fa6e9158504d70d54271c124b387bce9c9d749364522a90f79e766d234a22182f7248c165798d548429175ab1e9d54d335fec9a852a2b5dcda5d69bed9313df9928f3dea3c619b258cf776fd5365081d8994f6bc2471e7bb3e90e038b06da18b8351f99f4b7a95c66d0b0b86e2ee4dfbd666fca62be05bcae0cac34d9ec3d0c95e96d878ffc8bf21811fcd6bb8acd65171fcc3add6082d4b78c94bebb503cb5ca33f0988adf089d9c5ef0c009ff69a433328feb66ae5cfb2c85c622193e894eefef9b1f4e1540dac5b539f30448046c0edb544a6b46f2312d1c6d923d87dab1fab5f404f7d040bf77d5c7d78548ca92123c86c6eafa22664c38044da5baeb01184b1e8410a5b4d46972ea687ad0680ff2bd7ef645e43bc694da818f787f378f6b5ea1a238233bfd47cb62d31f57006782ba1235fbbe9c5919dcdd123683aac9ee84fc8f5d0b7261b07ab76db21a073584be6cfc44b3b2922a9b7bd88094b2f7cd28a251c516f84cdfbb8bac0a501234e0cf11548a9e116b79b07a08f834474f5af1cac7ec99be23be3ee3b4237188ce5d6d051684ad3281173413c9418c770abf830852dc4c7c2f6892e95d108ba5388b4f1e4d7c8ee4fe1c30af7e78b3bd6f94f0c53a89b66dd337c77f2a51d50fb1ba67724a1de08a7299351e797f185b65ddb8ef0b49e89b13fdfecf8f75c8442e9b62f53f91c9cdf2c1716758a83735ca34b3363849709b820c6f6e7429bab71f1ff3e5526ed629e0663813eca12befb988022f1613105ee7f5e7e594bec90a5cf04c632cce4ca56c4e10487352f1c99e7911f3c974af2a35155fead6aeebd6008f7d2cf5ebcc56860b373a130f65cc7eac4e2cb30abfb025214eac079b33f6a41bf2ac21afc3c7e3ec72874cce7f775445e972efaee607059aac7712441e7521803a9515570942735827a0572f37f8a4e6ed8a874171e59b87fbd496032f90c223c59adec3751de260ec228b003c65213c4a24d8c9d12693dac94548a3ef524adbc538bb074b35c8610b298585ee287d5054ebc381573db3cf32ba136a31e46fc8b76f9a9308a7165c7831daab52277711a10da0187c1836acbdb688080b6fd682927e7eae62bfb9b9b6638342a16ca35c5d04224753c3c3cdc0152e45cabdde589bc8aaabe81429a1c037b0d3dd0da79d1621ebaf2ff8c8e13e0cc21725bfc58e3563a01b63cd4b3a6a3755738393140a1558edc7d9245831a8d5e4bc1421cf525ea747f5510c4e34aecd05e9c2c527c8015bc88d7e7dc8933d412f83bc138d765860bc6fd6a5aa33253654911b891221bc7b0588802c3e4952dbc07911161eb9d99604cc20f5565a0d4d673bfe673489087efe4f6013e5c519b7bb8391299e29bc0af88877658397d77843a7786cf82f7770791ec7786cc75af919af22551c3cf7bd20a41cbeb0b0536c7f752da1a6e37088976373195467005e68ff58ac6311daef4b09b5aa8e49728c7e93120e408c845272f92b70e42e351ad308bd51345715c7d39b967d743acb106d719d9c8010e89bcc0a8c3447cf14f3b387dd8615f26b04db4a7649a5a66e09e99009084bee7337eb45265e55ef9e245d5d818bb22bb9919f01669c5e775fab64514f6591fc1ab4be2cc4b0632d96a6162e6a7d391bf5f94ccc5da34cef4ee7d9abd1a5d30f2fbb5d481c40857f56e3781d9e50b26a34ff7a3bdcf230cb1d29b13d9686ec24d70832642d2c1a9bce3107d287f421a56ad9844266f8edfd64afb25d84a7547971056b0cbdfee3238783903ab824f60aa20767b488c00467c9c7d0e6f6809658c9f0ad6c5b70228146dfd5eb1e59d3c36292654f25064b7cdc4631ac08d5a8bfba26529bc45510ecb86cabac40fe81b49466c66d99b48fa7036f9036cffb90d07f9b07c04ed74926331d4b192aa8ecf5b764d2472d8289979a0f3275b09852db3f657d38f68b29ff141213e75b4954c810d94aea49f14f05ec28443bad8936da3a6d4464cda85236a4255ba3dea323e9f7a14f5fc80819a748133f41eee39e30b8fd55d66f7e6fbc580b29bd7031908d7ef808c3967127e8a1e1d9db783c0b7eb9dea9f5ae52ab3e49085b2e21b2012bf0901d707ddccdee3f72f6d3059dda130754dac9522840d9b880208c663580985a8ce30977fa21446edd897f5955f893d60d8ee7f1605e0d7ef01620db3d293e3799ca54bda6a24ca9008aad5c0ef03207293d5b57f970f227a7be653c53c0a3a8cc5f25c5cf303cc97405dc65d4d3808e3bb21dc867a4e110724e1609d1b7dde8dfbb85ef501e3e0b7a358c45513a84f1f08a618e2b678fe6b68e13df7b0775c599563533cc043e3fc2433f7eb38e4136177ca272ef424dfa2281d3818f2aaf78a2337d67ecca9b90a451e5c175398c2ad713483f52a2d9fd1a9bfd256fc1ff38270ccb06e5b9ab9a2bd5ff589cc27df4faa28f57d13b50202fa46e04424f0fb06e091581b7066c2a732f1d647086c6308ff04df31cda244e583021d89d4ff4ae341fa06ad75c743d425ec6e5324cb1646d7d2bf6a5b168e48cd3527659d79a417856a2dd4bca5b106f74525db242d8c92e33312b8d91a489f6fb1983ea6bbe51422da1e8523ccb9f38e18abbc5601d27b9382bf2e2b4b15690202405c3fa5404c701c8106528f52f9ea4840040af12b4152d13638bdee216682c97a245e7f3c7f31988f5cb907ac195912750d9e45712590d3e88b24f6cec6ea1972fc8f7c900c53967b3657798482f5865a9313214a41cab7601e958cc66c25251f414e71654077828e7f29c57c2acfbd36ef0d9d4d909675035f9005f68013a9431026f971a597b29b032ffa13c857e2dac2deaf0d094f0fd3e184148ff8adb535f062219acd1724d313a7e1f985bed6e2b5736d3bc127a98ef99259a7a7d5714696826d11175a63cad28a23f1c8a06277996ddc3fa07f33d5e89243adfc21ac31d7ab9a61fd0bf7a0074a527e3061a5e45e6dfb9953ac8c20e1120fb6b23ab02870f18ae2d976ae186fea47e5f3105fca1547e4763ccc61f7ce555b740881903ca09505515e1d41539226a6320c70427f56091fb9efdc6d4f94f4273fda0bda64ef363a30214a952140b373a5e914a34f3fdf10206774b7edb4d996d72f1f377ac84806603710b77640150723894101b7799cb272a4a4ab9704cf4a6c3071175d0812aeed7e8f9c96c823d94333a1e749cbc58e86979ce2eefeb159500dd6b90bb8a76497ce94cffb38f262e0d87e6bfb86a8417d308c1a2a1b97a749c8b175760ae790ec92d8b5cefdab7e4f56d28dc8f2be6b0fbf50e3003d2d5a28b3b14a75384b2662becec4b453ec011865647c1146138defb64fae31aef84950430fe2ebd42561b9c2d772e678d7248ad72bf36675ca4eac508bd91f8aba0578bc317c837cee9032eb06d09adc2ce45eb51a03cbe52e3ee55cf02b919d78eaac99340a8bbc43c492e74b438cb5610b048d154a40985d7c105a35a3001bfdfa732ba7952b1c41e20b9c168a7dc30c34c912576c883187cf744e5fe9e29db07538df2eec05630277a6b15f7b6d6b65e5788371efe5f316388f536ddc1446783c066d760b572c0787643e6deed01b30ebd40ff253eb3279a17660c7226d925645c5d6300bbb19f209a5bc79c274a593c606edc005669e875962ea5028ce50b46b8611868db892fc596de68751caab22a7f6c3237c60f6f16bc80f6a71dd6d75dddd626d6b8182239a61079694cf45c55cd13d19d4a38bf78903c17c5c37402ed2c5dff7c164aa90869acee38c22e09bd5b8ab1542c4aafaed32f6347bd156171717ea5f2f09db652a7e7fe48b833945a46cca438eea7d77eb1d164ff5fcbe72d445aac73bc1fd44b16405348b8905399b3268608f7d89133cdc08ea8a89fcc6839ecbcd46549de8f1447b7e273596887ba3764dea52fd1ea84605034f4ccd7a6c3b5582fc7c284b22dc984840e38d9dff2109ee4ce3354f2322368d70b13d9799ae8e0bc68bf21e39a2e5174e247d1ebe28bcc24aec45e93739054fdf7f843fd3422b75459223c319c820284199488aafb41423b37990e59a6bbec4b14617eddaeb0fe7f72faf1fdbde90976542f745df725cd9947ded598c637b66034f94fac301855b4563dde7e9996c7579b147b73b331169dc6fb5ee0dae47d49c085df89956c33abdc38d891836881a1c899a8ac11e1c105ed7dfee521cb145acab582784cdf88baf835f601cce97ef21ca8223d3e83a2b2e5618872d7d51debbabd3bbe2328ddf5832bb1888866d9cfe59f41bbb574201793cc7154813c9f638838def7ccabb3ce56793143470516a7dd54a0b06db3d422189124d680cb36cd116ef8cadfeaa3b9a083fa4545b278486c6cf5a72dcd3754bc5a60ed19abe376e21f0529071fe6521b1c3f8d938acffa9fc793aeabea0e37cb53fe9eb598d2649602f2c8043826707a66d3c785fc01f00aa96faf5000ac1504a1efd2a68ae8afa0024d6d36daaa385a10da650c28eb4be4b251eff0a780b7a2b26e700bd8ed0485dbad40ec57a6a1d133c025735c8d8d645eb5d24ac65bddf1b9b90799513f58917e92673a05f67670be70e8bb1ca2cd0bb25b8efef2ad3db516234e9ce4a79f0d5a0d0c7831a926073e482be6ca6e745407dfb5d6700733e2c89f74db5a7d92ae0b2969def84ada576a1bcea10c1398a66361cb4f96de45be2454db7ee6975e47ae95222dba6a406832254e1f05a4d3db0a7e17061b18213d6bbdc66bd61b29d1ea53").unwrap(); - assert_eq!(sig_array_act, *sig_exp); - // for i in 0..sig_exp.len() { - // if sig_array_act[i] != sig_exp[i] {println!(" {} ",i)} - // } + assert_eq!(sig_act, *sig_exp); - let result = slh_verify(&m, &sig, &pk); + let result = slh_verify(&m, &sig_act, &pk); assert_eq!(result, true, "Signature did not verify!"); } } diff --git a/src/types.rs b/src/types.rs index bef9c78..0600377 100644 --- a/src/types.rs +++ b/src/types.rs @@ -26,8 +26,9 @@ impl< N: ArrayLength, > SlhDsaSig { - pub fn deser(self, out: &mut [u8]) { - assert_eq!( + pub fn deserialize(self) -> [u8; SIG_LEN] { + let mut out = [0u8; SIG_LEN]; + debug_assert_eq!( out.len(), N::to_usize() + // randomness N::to_usize() * K::to_usize() + K::to_usize() * A::to_usize() * N::to_usize() + // ForsSig @@ -35,10 +36,6 @@ impl< ); out[0..N::to_usize()].copy_from_slice(&self.randomness); let mut start = N::to_usize(); - // for k in 0..K::to_usize() { - // out[start..(start+N::to_usize())].copy_from_slice(&self.fors_sig.private_key_value[k]); - // start += N::to_usize(); - // } for k in 0..K::to_usize() { out[start..(start + N::to_usize())] .copy_from_slice(&self.fors_sig.private_key_value[k]); @@ -62,9 +59,47 @@ impl< } } debug_assert_eq!(start, out.len()); + out + } + + pub fn serialize(bytes: &[u8]) -> Self { + debug_assert_eq!( + bytes.len(), + N::to_usize() + // randomness + N::to_usize() * K::to_usize() + K::to_usize() * A::to_usize() * N::to_usize() + // ForsSig + D::to_usize() * (HP::to_usize() * N::to_usize() + LEN::to_usize() * N::to_usize()) + ); + let mut output = Self::default(); + output.randomness.copy_from_slice(&bytes[0..N::to_usize()]); + let mut start = N::to_usize(); + for k in 0..K::to_usize() { + output.fors_sig.private_key_value[k] + .copy_from_slice(&bytes[start..(start + N::to_usize())]); + start += N::to_usize(); + for a in 0..A::to_usize() { + output.fors_sig.auth[k].tree[a] + .copy_from_slice(&bytes[start..(start + N::to_usize())]); + start += N::to_usize(); + } + } + for d in 0..D::to_usize() { + for len in 0..LEN::to_usize() { + output.ht_sig.xmss_sigs[d].sig_wots.data[len] + .copy_from_slice(&bytes[start..(start + N::to_usize())]); + start += N::to_usize(); + } + for hp in 0..HP::to_usize() { + output.ht_sig.xmss_sigs[d].auth[hp] + .copy_from_slice(&bytes[start..(start + N::to_usize())]); + start += N::to_usize(); + } + } + debug_assert_eq!(start, bytes.len()); + output } } + #[derive(Clone, Default, Zeroize, ZeroizeOnDrop)] pub struct SlhPublicKey { pub(crate) pk_seed: GenericArray,