diff --git a/.gitignore b/.gitignore index 692feab..49032b4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ **/corpus /fuzz/.gitignore /dudect/Cargo.lock +**/node_modules +**/dist +**/pkg \ No newline at end of file diff --git a/dudect/README.md b/dudect/README.md index d4877d1..df8273a 100644 --- a/dudect/README.md +++ b/dudect/README.md @@ -1,5 +1,5 @@ -Need to rework the rng +Need to rework the rng (to return hardcoded values) ~~~ See https://docs.rs/dudect-bencher/latest/dudect_bencher/ diff --git a/fuzz/README.md b/fuzz/README.md index a154fdb..af87ef9 100644 --- a/fuzz/README.md +++ b/fuzz/README.md @@ -1,35 +1,77 @@ - +See ~~~ $ rustup default nightly -$ head -c 6292 seed1 -$ cargo fuzz run fuzz_all -j 4 +$ cd fuzz # +$ mkdir -p corpus/fuzz_all +$ head -c 6292 corpus/fuzz_all/seed1 +$ cargo fuzz run fuzz_all -j 4 -- -max_total_time=300 + +(run twice) INFO: Running with entropic power schedule (0xFF, 100). -INFO: Seed: 1973874562 -INFO: Loaded 1 modules (33986 inline 8-bit counters): 33986 [0x55bac21089e0, 0x55bac2110ea2), -INFO: Loaded 1 PC tables (33986 PCs): 33986 [0x55bac2110ea8,0x55bac2195ac8), +INFO: Seed: 708871690 +INFO: Loaded 1 modules (39289 inline 8-bit counters): 39289 [0x56391a65e620, 0x56391a667f99), +INFO: Loaded 1 PC tables (39289 PCs): 39289 [0x56391a667fa0,0x56391a701730), INFO: -fork=4: fuzzing in separate process(s) -INFO: -fork=4: 118 seed inputs, starting to fuzz in /tmp/libFuzzerTemp.FuzzWithFork320486.dir -#327: cov: 3130 ft: 3130 corp: 118 exec/s 163 oom/timeout/crash: 0/0/0 time: 5s job: 1 dft_time: 0 -#785: cov: 4503 ft: 3130 corp: 118 exec/s 152 oom/timeout/crash: 0/0/0 time: 6s job: 2 dft_time: 0 -#1404: cov: 4504 ft: 3140 corp: 120 exec/s 154 oom/timeout/crash: 0/0/0 time: 7s job: 3 dft_time: 0 -#2173: cov: 4507 ft: 3147 corp: 122 exec/s 153 oom/timeout/crash: 0/0/0 time: 8s job: 4 dft_time: 0 -#3145: cov: 4508 ft: 3155 corp: 123 exec/s 162 oom/timeout/crash: 0/0/0 time: 11s job: 5 dft_time: 0 -#4313: cov: 4508 ft: 3157 corp: 125 exec/s 166 oom/timeout/crash: 0/0/0 time: 13s job: 6 dft_time: 0 -#5703: cov: 4509 ft: 3169 corp: 129 exec/s 173 oom/timeout/crash: 0/0/0 time: 16s job: 7 dft_time: 0 -#7240: cov: 4509 ft: 3169 corp: 129 exec/s 170 oom/timeout/crash: 0/0/0 time: 18s job: 8 dft_time: 0 -#9004: cov: 4509 ft: 3169 corp: 129 exec/s 176 oom/timeout/crash: 0/0/0 time: 22s job: 9 dft_time: 0 -#10897: cov: 4509 ft: 3170 corp: 130 exec/s 172 oom/timeout/crash: 0/0/0 time: 25s job: 10 dft_time: 0 -#12934: cov: 4510 ft: 3186 corp: 134 exec/s 169 oom/timeout/crash: 0/0/0 time: 28s job: 11 dft_time: 0 -#15217: cov: 4510 ft: 3186 corp: 134 exec/s 175 oom/timeout/crash: 0/0/0 time: 31s job: 12 dft_time: 0 -#17627: cov: 4510 ft: 3186 corp: 134 exec/s 172 oom/timeout/crash: 0/0/0 time: 36s job: 13 dft_time: 0 -#20175: cov: 4510 ft: 3191 corp: 137 exec/s 169 oom/timeout/crash: 0/0/0 time: 40s job: 14 dft_time: 0 -#22838: cov: 4510 ft: 3191 corp: 137 exec/s 166 oom/timeout/crash: 0/0/0 time: 44s job: 15 dft_time: 0 -#25656: cov: 4510 ft: 3194 corp: 138 exec/s 165 oom/timeout/crash: 0/0/0 time: 48s job: 16 dft_time: 0 -#28572: cov: 4510 ft: 3201 corp: 140 exec/s 162 oom/timeout/crash: 0/0/0 time: 54s job: 17 dft_time: 0 -#31705: cov: 4510 ft: 3210 corp: 143 exec/s 164 oom/timeout/crash: 0/0/0 time: 60s job: 18 dft_time: 0 -#35087: cov: 4510 ft: 3210 corp: 143 exec/s 169 oom/timeout/crash: 0/0/0 time: 65s job: 19 dft_time: 0 -#38565: cov: 4510 ft: 3222 corp: 145 exec/s 165 oom/timeout/crash: 0/0/0 time: 70s job: 20 dft_time: 0 -... +INFO: -fork=4: 106 seed inputs, starting to fuzz in /tmp/libFuzzerTemp.FuzzWithFork491405.dir +#375: cov: 3099 ft: 3099 corp: 106 exec/s 187 oom/timeout/crash: 0/0/0 time: 3s job: 1 dft_time: 0 +... (new funcs) ... +#870: cov: 4821 ft: 3108 corp: 110 exec/s 165 oom/timeout/crash: 0/0/0 time: 4s job: 2 dft_time: 0 +#1591: cov: 4823 ft: 3119 corp: 114 exec/s 180 oom/timeout/crash: 0/0/0 time: 5s job: 3 dft_time: 0 +#2576: cov: 4826 ft: 3136 corp: 117 exec/s 197 oom/timeout/crash: 0/0/0 time: 6s job: 4 dft_time: 0 +#3600: cov: 4827 ft: 3141 corp: 119 exec/s 170 oom/timeout/crash: 0/0/0 time: 10s job: 5 dft_time: 0 +#4829: cov: 4828 ft: 3149 corp: 121 exec/s 175 oom/timeout/crash: 0/0/0 time: 12s job: 6 dft_time: 0 +#6223: cov: 4829 ft: 3155 corp: 124 exec/s 174 oom/timeout/crash: 0/0/0 time: 14s job: 7 dft_time: 0 +#7730: cov: 4829 ft: 3212 corp: 129 exec/s 167 oom/timeout/crash: 0/0/0 time: 16s job: 8 dft_time: 0 +#9431: cov: 4830 ft: 3218 corp: 131 exec/s 170 oom/timeout/crash: 0/0/0 time: 20s job: 9 dft_time: 0 +#11273: cov: 4831 ft: 3231 corp: 136 exec/s 167 oom/timeout/crash: 0/0/0 time: 23s job: 10 dft_time: 0 +#13215: cov: 4831 ft: 3236 corp: 139 exec/s 161 oom/timeout/crash: 0/0/0 time: 26s job: 11 dft_time: 0 +#15318: cov: 4831 ft: 3238 corp: 141 exec/s 161 oom/timeout/crash: 0/0/0 time: 29s job: 12 dft_time: 0 +#17653: cov: 4831 ft: 3241 corp: 142 exec/s 166 oom/timeout/crash: 0/0/0 time: 35s job: 13 dft_time: 0 +#20163: cov: 4831 ft: 3243 corp: 143 exec/s 167 oom/timeout/crash: 0/0/0 time: 38s job: 14 dft_time: 0 +#22799: cov: 4831 ft: 3247 corp: 144 exec/s 164 oom/timeout/crash: 0/0/0 time: 42s job: 15 dft_time: 0 +#25644: cov: 4831 ft: 3255 corp: 146 exec/s 167 oom/timeout/crash: 0/0/0 time: 47s job: 16 dft_time: 0 +#28572: cov: 4831 ft: 3255 corp: 146 exec/s 162 oom/timeout/crash: 0/0/0 time: 53s job: 17 dft_time: 0 +#31644: cov: 4831 ft: 3258 corp: 147 exec/s 161 oom/timeout/crash: 0/0/0 time: 58s job: 18 dft_time: 0 +#34948: cov: 4831 ft: 3258 corp: 147 exec/s 165 oom/timeout/crash: 0/0/0 time: 63s job: 19 dft_time: 0 +#38534: cov: 4831 ft: 3262 corp: 149 exec/s 170 oom/timeout/crash: 0/0/0 time: 68s job: 20 dft_time: 0 +#42350: cov: 4831 ft: 3263 corp: 150 exec/s 173 oom/timeout/crash: 0/0/0 time: 76s job: 21 dft_time: 0 +#45956: cov: 4831 ft: 3268 corp: 151 exec/s 156 oom/timeout/crash: 0/0/0 time: 81s job: 22 dft_time: 0 +#50243: cov: 4831 ft: 3275 corp: 154 exec/s 178 oom/timeout/crash: 0/0/0 time: 87s job: 23 dft_time: 0 +#54612: cov: 4831 ft: 3278 corp: 156 exec/s 174 oom/timeout/crash: 0/0/0 time: 93s job: 24 dft_time: 0 +#59006: cov: 4831 ft: 3282 corp: 157 exec/s 169 oom/timeout/crash: 0/0/0 time: 102s job: 25 dft_time: 0 +#63622: cov: 4831 ft: 3282 corp: 157 exec/s 170 oom/timeout/crash: 0/0/0 time: 109s job: 26 dft_time: 0 +#68600: cov: 4831 ft: 3379 corp: 158 exec/s 177 oom/timeout/crash: 0/0/0 time: 116s job: 27 dft_time: 0 +#73305: cov: 4831 ft: 3381 corp: 159 exec/s 162 oom/timeout/crash: 0/0/0 time: 123s job: 28 dft_time: 0 +#78406: cov: 4831 ft: 3381 corp: 159 exec/s 170 oom/timeout/crash: 0/0/0 time: 132s job: 29 dft_time: 0 +#83511: cov: 4831 ft: 3381 corp: 159 exec/s 164 oom/timeout/crash: 0/0/0 time: 140s job: 30 dft_time: 0 +#88768: cov: 4831 ft: 3381 corp: 159 exec/s 164 oom/timeout/crash: 0/0/0 time: 149s job: 31 dft_time: 0 +#94078: cov: 4831 ft: 3382 corp: 160 exec/s 160 oom/timeout/crash: 0/0/0 time: 157s job: 32 dft_time: 0 +#99544: cov: 4831 ft: 3382 corp: 160 exec/s 160 oom/timeout/crash: 0/0/0 time: 167s job: 33 dft_time: 0 +#105351: cov: 4831 ft: 3384 corp: 161 exec/s 165 oom/timeout/crash: 0/0/0 time: 176s job: 34 dft_time: 0 +#111111: cov: 4831 ft: 3384 corp: 161 exec/s 160 oom/timeout/crash: 0/0/0 time: 185s job: 35 dft_time: 0 +#117276: cov: 4831 ft: 3384 corp: 161 exec/s 166 oom/timeout/crash: 0/0/0 time: 194s job: 36 dft_time: 0 +#123570: cov: 4831 ft: 3384 corp: 161 exec/s 165 oom/timeout/crash: 0/0/0 time: 205s job: 37 dft_time: 0 +#130052: cov: 4831 ft: 3384 corp: 161 exec/s 166 oom/timeout/crash: 0/0/0 time: 215s job: 38 dft_time: 0 +#137189: cov: 4831 ft: 3384 corp: 161 exec/s 178 oom/timeout/crash: 0/0/0 time: 226s job: 39 dft_time: 0 +#144270: cov: 4831 ft: 3385 corp: 162 exec/s 172 oom/timeout/crash: 0/0/0 time: 236s job: 40 dft_time: 0 +#151734: cov: 4831 ft: 3386 corp: 163 exec/s 177 oom/timeout/crash: 0/0/0 time: 248s job: 41 dft_time: 0 +#158944: cov: 4831 ft: 3390 corp: 165 exec/s 167 oom/timeout/crash: 0/0/0 time: 259s job: 42 dft_time: 0 +#166412: cov: 4831 ft: 3395 corp: 167 exec/s 169 oom/timeout/crash: 0/0/0 time: 270s job: 43 dft_time: 0 +#173716: cov: 4831 ft: 3396 corp: 168 exec/s 162 oom/timeout/crash: 0/0/0 time: 281s job: 44 dft_time: 0 +#181399: cov: 4831 ft: 3396 corp: 168 exec/s 167 oom/timeout/crash: 0/0/0 time: 294s job: 45 dft_time: 0 +#189143: cov: 4831 ft: 3402 corp: 169 exec/s 164 oom/timeout/crash: 0/0/0 time: 306s job: 46 dft_time: 0 +INFO: fuzzed for 307 seconds, wrapping up soon +INFO: exiting: 0 time: 307s +~~~ + +Now generate a coverage report... + +~~~ + +$ cargo fuzz coverage fuzz_all + +$ cargo cov -- show target/x86_64-unknown-linux-gnu/coverage/x86_64-unknown-linux-gnu/release/fuzz_all \ + --format=html -instr-profile=./coverage/fuzz_all/coverage.profdata > index.html ~~~ \ No newline at end of file diff --git a/fuzz/fuzz_targets/fuzz_all.rs b/fuzz/fuzz_targets/fuzz_all.rs index 1145a42..06d3110 100644 --- a/fuzz/fuzz_targets/fuzz_all.rs +++ b/fuzz/fuzz_targets/fuzz_all.rs @@ -1,35 +1,53 @@ #![no_main] use libfuzzer_sys::fuzz_target; -use fips204::ml_dsa_44; -use fips204::traits::{SerDes, Signer, Verifier}; +use fips204::ml_dsa_44::{PrivateKey, PublicKey, KG, SIG_LEN}; +use fips204::traits::{KeyGen, SerDes, Signer, Verifier}; fuzz_target!(|data: [u8; 2560+2420+1312]| { // sk_len + sig_len + pk_len = 6292 - // Deserialize a 'fuzzy' secret key - let sk = ml_dsa_44::PrivateKey::try_from_bytes(data[0..2560].try_into().unwrap()); - - // Try to use 'fuzzy' sk (a decent (?) proportion will deserialize OK) - if let Ok(sk) = sk { - let _sig = sk.try_sign_ct(&[0u8, 1, 2, 3]); + // A good reference set + let (pk_good, sk_good) = KG::try_keygen_vt().unwrap(); + let sig_good = sk_good.try_sign_ct(&[0u8, 1, 2, 3]).unwrap(); + + // Extract then deserialize a 'fuzzy' secret key + let sk_bytes = data[0..2560].try_into().unwrap(); + let sk_fuzz = PrivateKey::try_from_bytes(sk_bytes); + + // Extract a 'fuzzy' signature + let sig_fuzz: [u8; SIG_LEN] = data[2560..2560+2420].try_into().unwrap(); + + // Extract then deserialize a 'fuzzy' public key + let pk_bytes = data[2560+2420..2560+2420+1312].try_into().unwrap(); + let pk_fuzz = PublicKey::try_from_bytes(pk_bytes); + + // Try to use 'fuzzy' sk + if let Ok(ref sk) = sk_fuzz { + let sig1 = sk.try_sign_ct(&[0u8, 1, 2, 3]).unwrap(); + let sk2 = KG::gen_expanded_private_vt(&sk).unwrap(); + let sig2 = sk2.try_sign_ct(&[4u8, 5, 6, 7]).unwrap(); + // ...with good pk + let res = pk_good.try_verify_vt(&[0u8, 1, 2, 3], &sig1); + assert!(res.is_err() || !res.unwrap()); + let res = pk_good.try_verify_vt(&[0u8, 1, 2, 3], &sig2); + assert!(res.is_err() || !res.unwrap()); } + // Try to use 'fuzzy' pk + if let Ok(ref pk) = pk_fuzz { + let res = pk.try_verify_vt(&[0u8, 1, 2, 3], &sig_fuzz); + assert!(res.is_err() || !res.unwrap()); + let pk2 = KG::gen_expanded_public_vt(&pk).unwrap(); + let res = pk2.try_verify_vt(&[0u8, 1, 2, 3], &sig_fuzz); + assert!(res.is_err() || !res.unwrap()); + // .. with good sig + let res = pk2.try_verify_vt(&[0u8, 1, 2, 3], &sig_good); + assert!(res.is_err() || !res.unwrap()); + } - // Deserialize a 'fuzzy' signature - let sig: [u8; ml_dsa_44::SIG_LEN] = data[2560..2560+2420].try_into().unwrap(); - - // Try to use 'fuzzy' signature (a decent (?) proportion will deserialize OK) - let (pk, _) = ml_dsa_44::try_keygen_vt().unwrap(); // Get a good pk - let _v = pk.try_verify_vt(&[0u8, 1, 2, 3], &sig); - - - // Deserialize a 'fuzzy' public key - let pk = ml_dsa_44::PublicKey::try_from_bytes(data[2560+2420..2560+2420+1312].try_into().unwrap()); - - // Try to use 'fuzzy' pk (a decent (?) proportion will deserialize OK) - if let Ok(pk) = pk { - let (_, sk) = ml_dsa_44::try_keygen_vt().unwrap(); - let sig2 = sk.try_sign_ct(&[0u8, 1, 2, 3]).unwrap(); - let _v = pk.try_verify_vt(&[0u8, 1, 2, 3], &sig2); + // Try to use 'fuzzy' sk and 'fuzzy' pk + if let (Ok(sk), Ok(pk)) = (sk_fuzz, pk_fuzz) { + let _sig = sk.try_sign_ct(&[0u8, 1, 2, 3]).unwrap(); + let _v = pk.try_verify_vt(&[0u8, 1, 2, 3], &sig_fuzz).unwrap(); } }); diff --git a/src/helpers.rs b/src/helpers.rs index 911e3f1..ca3d9db 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -44,7 +44,7 @@ pub(crate) const fn partial_reduce64(a: i64) -> i32 { // cannot generate a carry (and thus we have maximum rounding-down error // accumulated), or a = 2**31 - 2**22 - 1, which then suggests (0xFF) Q to // be subtracted. Then, a - (a >> 23)*Q is 6283008 or 2**23 - 2**21 - 2**8. -// The negative result works out to -6283008. Note Q is 2**23 - 2**13 + 1. TODO: Recheck +// The negative result works out to -6283008. Note Q is 2**23 - 2**13 + 1. TODO: Recheck #s #[inline(always)] #[allow(clippy::inline_always)] pub(crate) const fn partial_reduce32(a: i32) -> i32 { @@ -56,7 +56,7 @@ pub(crate) const fn partial_reduce32(a: i32) -> i32 { pub(crate) const fn full_reduce32(a: i32) -> i32 { - let x = partial_reduce32(a); // puts us within -Q to +Q + let x = partial_reduce32(a); // puts us within better than -Q to +Q x + ((x >> 31) & Q) // add Q if negative } @@ -114,13 +114,15 @@ pub fn infinity_norm(w: &[[i32; COL]; ROW]) for row in w { for element in row { let z_q = center_mod(*element).abs(); - result = if z_q > result { z_q } else { result }; + result = if z_q > result { z_q } else { result }; // TODO: check CT } } result } +// ----- The following functions only run at compile time (thus, not CT etc) ----- + /// HAC Algorithm 14.76 Right-to-left binary exponentiation mod Q. const fn pow_mod_q(g: i32, e: u8) -> i32 { let g = g as i64; diff --git a/src/lib.rs b/src/lib.rs index b48d7b7..589bc8d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,11 +7,9 @@ // Roadmap // 1. Clean up; resolve math -// 2. CT inspection -// 3. implement ct_cm4 -// 4. rework fuzz harness to include expanded keys -// 5. Intensive/extensive pass on documentation -// 6. Revisit/expand unit testing; consider whether to test debug statements: release-vs-test +// 2. Closer CT inspection +// 3. Intensive/extensive pass on documentation +// 4. Revisit/expand unit testing; consider whether to test debug statements: release-vs-test // Functionality map per FIPS 204 draft @@ -59,7 +57,7 @@ // Note: many of the debug_assert()! and ensure()! guardrails will be removed when // the specification is finalized and performance optimizations begin in earnest. - +// The current situation is overkill. mod conversion; mod encodings; @@ -73,6 +71,7 @@ mod types; /// All functionality is covered by traits, such that consumers can utilize trait objects as desired. pub mod traits; +// Applies across all security parameter sets const Q: i32 = 8_380_417; // 2i32.pow(23) - 2i32.pow(13) + 1; See https://oeis.org/A234388 const ZETA: i32 = 1753; // See line 906 et al of FIPS 204 const D: u32 = 13; diff --git a/tests/messages.rs b/tests/messages.rs new file mode 100644 index 0000000..d8779e7 --- /dev/null +++ b/tests/messages.rs @@ -0,0 +1,17 @@ +use fips204::ml_dsa_44; +use fips204::traits::{KeyGen, SerDes, Signer, Verifier}; +use rand_chacha::rand_core::SeedableRng; + + +#[test] +fn test_browser_message() { + let msg = b"asdf"; + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(123); + let (pk, sk) = ml_dsa_44::KG::try_keygen_with_rng_vt(&mut rng).unwrap(); + let sig = sk.try_sign_with_rng_ct(&mut rng, msg).unwrap(); + assert!(pk.try_verify_vt(msg, &sig).unwrap()); + + assert_eq!(sk.into_bytes(), *hex::decode("755193ec3402eb0e17947e6ed5605118967eb1200a28f9d8173097059141c572f89a1e160ddeea3733d4269eef95714edf361f4ea94a6a6a15988abaf3a0b96d866a1b34339105fa5eaebcd8443a8235c7dcf137148e31245644dff462d2c5f971ad7807207bed65b31ef7c4e8b89813360eeb5775a02c8bb34fb7599677b314cb388c61a02d11430cd0128910186411250621a97009446a0c8980008109c88609a44641d2420d14442c52288981088499088198106419b34824b4086300308ab40d02052922c62149c22c414262104160a2c42d80b08448122001230052086a9b9600c4b065e2a4298b02910239504c8680a1280913874d19b571dc0269808069a38265d34400dc02241c2621d1302a1a41880329121b454d20918c59b00501a181e4262544382811288a824641532264e24642c880854b2888a4364d94b6041a346c192706a008280b492dc314200a212cc32246a1c489e08865cbc0518442222280904a146a229245118049da388462826464348141c02420a1305294041a96815832600a8891012081db861190b2001027321c11440c2861a1440614a09101828d22a32850102212c1042103241940290a9430da964442463193a640439461e2164013a40c04862900c48140c6814ac42c102226d9c809e40261c2940091825093444548a62910a12904106908226e0436101c22925a18264224040298019230615908310c042018442218c78093a491923625ca0000d4246208b60c4b8820e14632643446504009e034811b498cd1228a02044ec93645da9241814286a44045448625c00209cab82c14b66c1ba3405cc0045b129050c08d63362d521820c34661193672d2204953882889b644c8008a8b886cd3162a59020819992411a14ccb4881a0146da13651d90652831608243766db38650bc20d24340c582841da32299b1285d242068c1265839481000909a2186990b48c600030a13289db866463c62c592425d2c020e4284e14b905483444142541da000103163191220542a26400a64dc3242d084869222380622245a12264d9002d1c183102040022326444446c804628842249c318280496298946498b96640c01845ca6909306308bc27063368e440801424690a2480ae4304a9c14290c040893466a14a82d18422c03a6011498200a202292a40940b88464c624080429a218000a884c92c80da320901b832d62280698168d42c669d2288522132481026e080822049891a2a26588a884d429c236d53e588ce26befb446068b8d645b6340a67629df72eb1d57749921ae68121b27d1be0b621700a6d74905bd4fea70abe4d8feb328604cedc398a05c092691fb21a660419076e4a7af47c12d5fa2c22de7bb639d838520360c2e498570b176c5701c0f83128b07c55ff86c870e12e59799d79f5c840bf76a289b20e23b55009b6f8b305c6308215651ed34d6ba2a3e68ea22b15bfbf7e2601ebbd67e62be92a68bd58f5d6073990c56f329334e7c2cd05f7351ba00f5dec74a860affabc2d659e66f690e301fe31bfedd80c9f3d28b80de370fb31fd083fe9672b6abd7d3c380617af9a03dfed16bec77306b3f70dd23852cc53c33745c0f721b0378651a721a0ee420498da53d07f24587547d2ef2fe6d27b73544d1b34c1065dc1ca93fad3b0fd5bd3f46fd04a292a04bf2a96b8310e72f6df8020daad70ddd7dbcdb3d97c3b29a90b9e2d4f57f9498da26a59b12311da8c3479da84de1608a98f663b82d19347fef84262b6ee2092a8d2671486b044ef53ba95b487ec708399c3bf6947abbf0631b056bef4d8eb4f6caac11c435eba6e3fd09088e59cd4bf03bc04dcd8db06568b81e5da620e20f10d502aaf3a53d23911abd8f92ed2a0d08415047bb07c0133963cc130e13e59704f82dbe75517bcbdbb8493352935473616a86aadcd47cc897af3fc62dccc135fd97bb1d8073fe2a7014eb13bd7a1a8e88de401b3ca33d20991ee6c0ab67b11204f763733dec1ac61ae888b73cdb820e0b4c8023bace285ea217a317d006ab0166e53a1d3006dc358f91d2e33b327f039b60292a5cb9062a0ef5b58096d11cdef6acd2daa9348fa72c92e79929acd39eda35b5c061854d6c4de697b6712aa08ef40576e2e6c211e0bf5bed8e38595c39925f5b3a63586b52976b3c9019c0c172bcc52739ad8c174220ef2000d4b67bfc84e5d7674bd10f8562e62bba0ed3087a44f91148e9a05542cc9eaea64d4c435a1213c2179138943f6aa7c946948f91d8a8d8b6110184da06608a3b97146af85be96976dd9896bbeaa3b6d6a597397839ca882e27039a2d38109fe3a212540f4763e7dd3a5f49c08ec7eff9d96f4b238718f2826c690a0094da2bf6b0a728843c40b72204d03e7885d1c0818521087ad2dad0fd681fe00bc59984f8ca2016556067fb5adb64369d371a4cfc59ae2c3d63973b3cb105f03574016c2ab0be88b474f5d84bfc9579e9c33aa1d5c423a15b3e20170441752a5a7c8426868fb71439763da42746d20c1f42fd94bc9f475200fab8844f8cd080728c0935b0b3eeceb2fbf33127de2d17ac01c9d73ce8b9b7a81bed673cdb9665812e1c3bfbd5d8b6d16b6ab41004e507b1d85680dd92bc2dcba32e2e1101e94f7b73a877618bf90796320ab1f56ff01c0abfa6b50718e6f1c2714969c440ba932a43a39215836afb9940034e8efed8b1e4a7eb852dd5afe147e4e31ade7731a36c82ce583560102b0255394f4bc34cb3b34f32094138989ff992ee2c933077cfa226d96710954348415935af6eee21947e962ed4fe68dc555ab02e9e60a623589ca3502261f5ea54e89ebee32697cc48edd1869a40f6b7cb532483a53e82ad4f6511306ef0067e8084e6f0accd4528e8927a3f1c6ef3623f7e4fe3d90f3a3e1e6b770255975ebf7b3f7a78708190b87eec9e447df0c48b694fca20905005072277610888c7a7e907be47b788d9aba9f8a3a73261da4a14ce3dd11ae8109347927ac74a2fc775e8587bc7223a473ef4d732b690080f0903462f016df4c801a60246920201e12e7bd80864b88b126f2ad98b5b42c39bb549394132ac096a74eb39deaecf922ccb44d21213f7c81b71494740475535abc0c401e36038863724bd0a5e4cb227ff831c3c3c85f3dd6787e899873964a4ac583e903f32e79093552b5871f7b4a806151c603c8a3d1f63eac47f08eee013078af7733692a1688137cb4a047eb3d8657469194f8dd7c57dd75a1263931fd420fddafa31ed4ae51afb507cc9fe7f8a0bf0e7ebecfc14c2e9537a73a8ae7956fb5f6cb8fccb8e94c9d60c9e7129cecf94b0bd47b0794e3069d7dc59958179bdcef2168639f4f4867a674c00bdb5379f2c3e3d9ba115bce0fece5e51d3f9142254a6cf8de6323b4fe22b779ae7aac6dc6ac259bee4f8d0c708131c22a6f1530708bcbaa0305639425d92965ceb45d911ad13b98ea4c20868004aaebe3ef1d2dd737d114d075990704ebb7c480cc59eec5b08eb9d6b7a8b850355e2650fe5fcb40a6e8145c9470ffcbdfe26d2ceccad99fcc06cbd5be7c06d4e90992aa1bb2829701272defd878f3e59a0377de7a021e73320e5ba46f426857888").unwrap(), "sk not correct"); + assert_eq!(sig, *hex::decode("204e71dc783f063158152fdce71919c5d4e6c832f174bb4185a179dd228987f7a8cc5234eb918ae5cc6667b080bad306fa60de7729e002e2d84596456985a6fd2e2251b7b4d1ce3f5d52e319312c1bb1433f4d1009a15724a75f8a3aaeea98c7c5a64c017b931dd6927d682f0608ab72866a6f55dba1a2a44ba3cf76893cab7a989325f1717577cc2afe4becc5d5489b5cc83132956ee5f44069068fb27ee0eb404ab2fd97d87c2ea4133a8cb7b51d4870ad71f36c2086cbf9dae9943f674b02269b6542a91b455977d687c932473676dfebff831a3cffa9bea3742d0237ab25f14917541d136183717f2999860f48bf135f5fd0a0e3096e9a4e7fdf041673f476c4a97746a79aea11182033da6d46583446a56eec999dd894939380c164f64e9d2642a21a93c61b96e2e1a64a98f24fb4c1adf3a228e8c1cc8890fe62ce9bf2b9d9eb0c0a8b9257504626b0218e67af1902e25564617f936b9351a0de225964103b15b4acb52351ceed45f74520f2d9b4cd76fecfac78a0dcc1dfb4cada17e257a2559ccf4f68ff9ae15acc5033209a179e01d94fc3b0a4d52e5f3fac6ae487f10cc0ad07ecec8def6c7f356ea4ef08f479ed83db9b5c346af252a2624c6e51170620180f1296881a9ce5970acb4ce9dd8279f17d5dc5b65f367601ff941c0307bbf75761af428f2af32159e5516b397cfef7ae924faa07a63461a60f32c9027217f06e5bba3bf8f82621b5ee5393a405609dcfc3580602391eee890bb27112da6981acb1a7bfdba5b1a46cdb315b5d7f6f3bf20346d3016e9d964ac81e3481f5f7848e2df803075f9bca43cfa61758480a45f90a9dd281c9ec3d707762d83da6dcb321d57cbbdde3e1bdde8834ce3613ad999d3e007b7358e45611ff3995edf5e90125521763f9ec10930cd7c11a0154c8d58a68fb891f210e0aac24f9e72061a29ed74c5f70e71ac6f9427f68959f062bb90af17d6ce1521d52674d2762fff239365094f84f95929ca690c7f4d8f6bf1d76ba7372ee9f98315fc26593ea4367434440004c117c85ac833d9be51d5410f1c3a644adb104268b94e2418735fb645d73351ef5f480dd1f4ff1623f479d6fae6cdacf5075f971e81bc218850da40695f47d3c392fd23657f70a5cc9fa394ab7b5c2622ea4949210435ecc29878ca4a582af0a977a5947003f03bcbdcebe25ed395468480da9c155b02e4a42094fbda5068ad21890c03bac7a1e55e67a9c79a0f5458075f6b602b51b1ab223a5206193770d0170a3d39870abdb5f5fc948071ecc81b6201eb76e1b68f0f2838b0e2a9413273a19ba44f097c13a452b6b5dcbae603cdec3e4a8657924d813e190b0c7f18e77f2ff1ff51bc263bea49dc190a667d581264614594a57910376215f9bee23261e08b82242d20a087c1cc6d11ad27d4d613bc5f61177924946a9b7d45020e643f5a66d032b42e7fff9a462a778b447993158c9561c830db561a4e92453523e605ca229fc4458356effa93dc64e8f4d659392bc9b3e291342eba8cff9b97344e11f6ad14f69335fc48eda49f1ebcb4fbe2c40657eb8628a1ed21924e676f2019e868bdcbc24b318e74aa4533ab28b5c56386e905fd92e4fc80d10e98b586cce1c4c9c6bf8fcc02c4b99e9e43153a2652cbaae0f6e53c15eff93b0099548a2c3a8a9e1e4186874a083ec981f94ace4da1ea3ad0500173de9d9e15fed94975152cf5fd07e46c41e7207799e13b7b1a01e7895dfde5ba81e45b5f0529154b152d2a98c149f2ada55cd6f05823ae0ecac0e174dab9ba7979e793e65a024994007a50a3739ad4a9511f5af1d46fe3701014d46e7e9da21c27aabcbc13438bbf5fbc2f60073bbf71bb7ccefed210eb621557345cc53c1a631117da74b3df288d30004ba10c1d0bf7ce30acd706c6acc65b5bb6e7a550f93c3529453fa4811d18a4117700267c501c202f3de0e55a72afb5f592efe4cbffb0e3c686086ca253fe38a4349b39b94f40b60b64c7b34b1657550f2ccecad18d0ade2212b46edeff7c63dc30bd3d6d248e083f10f3e156e7bdf4b6ccee2a577ed98317c34f8b987b6d1f8458496fea46c7df8cf29bc32bbf76294698b115c999fe9f50d18c2ca451fc356392cb6553af5f78d4b816aeabdc392b33638fc2f12ada1bdd403978a65c370bd98225af3febd978393d92c73a419ee78542adfb6a452e3eea0d0d5a5ad332a14c7c98219c5b8566e0ce1a7bb473a105e7dba3d2829f8bd6e2eda5a98f1b609698ea1dd0f2eed00cdc5cbc2912fe7b98f7fde7f9bf795b0c2a5e49cee77c9d2caa4e408ee964137b0ec192dfbf04c32fa7ac0b9ad682dcdda249a17c2c2b1f664cf3d877aa9619a44b6dfbd5a75738fbb40ecd0d753f8d4cd753cf2f6bb2cee52c6875bef04a887ddf8dab3173c208f1f7a370cf2514fd807e316c86f4f54e98b42313e5e8a508f1957d5c6a54c4e4f7e53da8911163c87c2d3fdf66b2642428db4cc13de10aedbd431e9306f12fdf95e88d163fdd93f30330611e3fa277a606013c3c9cb16cedddb3183757f450d530f263d22a765c3afb027664353d5879605cfc5e673a728b975161835bbc85e274edcf6b071bd5fde7d6fa80ffea0bf124bf72ae642adab1b0ec6c6247f462d32622ea63df8322fe5e966e7701c6783df9642d98ca1026852f91fb04fea69ae521bfde282cf39ae3c02e368f5e3aab180ce736fb22330e26fd91c767e0789ba9b356d59bb55112f9c438dc049adf69278edfa504da7cb5c291efc76f1d22c81f50a1edc1fa9e841b55599e0ea09dd0b63da47073e7fa7afa0e3a5f5f4ce778aab7cbd0ce54b5c105ffc405ca3482274fd64a14caf1db94bce36d95714eb416f6ce8a2a02067bb0ebe925587592c1ead49c22a16cef7386f1a94335d7c5d9383293b7d47fc9108d971856c35d834f369bedc555ffb5573f286ca30325e319c9a6b59207b51f1ea2f57197a01b9d1f7e9b8f70690eaeb07b104f94dd9870e493bd6909e5efd0894788e8b9f5c6d615b96f46a06457cb88a4befffd15c882953a6b265618443a8fec0fe2977cc871dc400a2d352afb7d82f2fd5d87bb19dbea8eae0a137885ad98d10e0412e698524e646061706b697b464977fb016331429e8e788e59c63ffb985d87cce0cbe9db668bb866e729f7f85de173d3c34d1eed790ad8ea0f54a86a222ed012a36320fa3a79c4f4c9c996996f28e422f4ff5e2fd6d1c5c94933f1965a4a71dda50dc75f1b5343d1ba5d7b0d66fc31d0fc050f65689636b335634315ea2bf23d870b1b386aa57c80c0d3f60657bccd1d621283f5a6590aab7c9d8ecf72a31414b5764798698b7c1d1dce3060b1130343e5376788ca1d8f6fb0000000000000000000000000000000000000000000000000000000000000009152331").unwrap(), "sig not correct"); + assert_eq!(pk.into_bytes(), *hex::decode("755193ec3402eb0e17947e6ed5605118967eb1200a28f9d8173097059141c57222978e92d50f3bf79c99f9cb0914d99847c35ff42c2d85a99abff46b4b344fb938e646f4ff1bfd80d090680682c1025129608e871af32ca533ce5c63f9ab4a897e739c84a356500e6ee02733ea3bd45ee57288cf9dbd9946ca7e0feebc47da5afc2974f5c58a3b48ab12689bac01e1d11c90b093a9ca231c68dfb3357eac610c36ff3da9ccdf79e382af9ed163d6e6e2dfa46c2b17f30386ca653fd3b689669f60ad8d29daee11c612ad5dede7859f4fd725b8ca847767d05abfee31070869b6b753634d1505034ee8c2e0fc1148cb857f59110f14c69afe8d72578680268d01b4bfc3479f3eebfe3820458e0f01fb5d6019936fc24bb4d2cceb0501d3bba9c6355708d1233867c201f0a77b560854ae4da538903e78116b248cfe1e438667f7e3d231b2ef21ea6c0c7543a80ac54a84e483ec7f9f4b12e151f0c3472bd241c972b32d1985d08cb2b1acc469cf9921c0e95018583af7f636796e4fe0616c44c0d6881097147a31d922b7fa9ba1ca906bf4bb15962d9c0e7aea69c144093ce6e9f7311548d346ba05bbbc24d3e299c48276a96cf28f05e146d9210009d76de1bffb9412c69011d029bad1a976224f8448a6243c3e791dbe809328eb50c7d3b2a67ea64bc28e06885842d18b8fa41ac099038ca9d243589a2b945db05db519bd202cccdd20cdad61b50f91b6213874337bcfe3c102cec4d86b8323ffec9570c2455f1a5bd978cb478c34b6799adddeb16554ff9512cead0a7861c22d6c9a764080e90b7395c84a39339712dd8084a31fc9e10f822cc976d71a2e1a67bd8288d0fb23174ea34521694dbc75fa4f13e3a1067b01d814779a9eb7732b1fc0b15d4dea15a9924bce53b31fd2cec142cd1a1c54911bab5ff71e6d700350ee445a08d3b127afc5856a6cb0b67d0563f8a5b4961f930e0634bceefc2a1072c2cf08f317d48533e93956d3ee42f4dbd94527a114ce09749f79a3d5d23c00870011b749c17ddbd4dbc8ef93f8a03d715a92e7f9213f4af4f501dc2d7aa967fee4379db783a17f6cd5c1d3fc0126236ca3fc23b74d0cec1f7439c1f5dae7bb06f44ca4a050a744101c2f1244b8f4f3d389e7c8b2cf558c5e4cce1a7ada441181c187cadcc1dbe1dfd95a295fdf4bfef9a3e818060b1e89d09ae09029d23baaa314c6d114f5be5300ef67a3c945ee6854712355ae7c9dbe8e54d43363daf2f6cc92d219783c580d4f026d80c93e401df20beef1de3e8804caf19133359a910cffceb708ec8b9acd1e717237d55ec62c86b66ed571fde9da48aa9b0f48e83b2145807c51c4c124e96a2229a876e3c42d90298a3c5f31d316a12145b66b550b52ab954657c413d41e8c2b6637f45d7d2338be0734c684ddc255b741d8e3b13f925e70f4270480d1e5b87ef64c0196f38c98fbd1b56ec2a38ec6e38ad0fff3eec32af25c4346a9feb232b1deabeb0e10bac63e07272b265a12718822efab2c805aa9f86b17041cfeca7c167faad7f8e3789b54a9be3b367e86cc8f392f8fea518bc714baeceddcc9a86a1dd1214e9df8c72d0f72e18ad4585da4550a4747d44a8c832fcc467f777ae4eb7fe7c361d8fe0bb72664df2e223c7491d01e709fa74254f6fdec386eddf4ffc9fefa706bfbeaedc350e156fe2af0de33935ba04934dc69ebb20f3c480caff6e91115f97a9510f9b03b1abe67366ff0afd9cf7d2f39e332e57162d0fdde642349f9b2248273f064a3bec19dbd9e75c01049b98ea673e1cca53994aa6ad06757f8a2f045775418ae9ccac497a3dd54ee26c194cdb53d2ac109648e98c4d931").unwrap(), "pk not correct"); +} diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml new file mode 100644 index 0000000..53fe453 --- /dev/null +++ b/wasm/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "wasm" +version = "0.1.0" +authors = ["eschorn1 "] +edition = "2018" +description = "Sample web page utilizing FIPS 204 code" +repository = "" +license = "MIT OR Apache-2.0" + + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +default = ["console_error_panic_hook"] + +[dependencies] +wasm-bindgen = "0.2.84" +fips204 = { path = "../../fips204", default-features = false, features = ["ml-dsa-44"] } +rand_chacha = "0.3.1" + +# The `console_error_panic_hook` crate provides better debugging of panics by +# logging them with `console.error`. This is great for development, but requires +# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for +# code size when deploying. +console_error_panic_hook = { version = "0.1.7", optional = true } +#rand = { version = "0.9.0-alpha.0" , features = ["js"]} +rand = "0.8.5" +getrandom = { version = "0.2", features = ["js"] } +hex = "0.4.3" + +[dev-dependencies] +wasm-bindgen-test = "0.3.34" + +[profile.release] +# Tell `rustc` to optimize for small code size. +opt-level = "s" diff --git a/wasm/README.md b/wasm/README.md new file mode 100644 index 0000000..09fe91b --- /dev/null +++ b/wasm/README.md @@ -0,0 +1,106 @@ + + +One-off installation + +~~~ +$ cargo install wasm-pack +$ sudo npm install npm@latest -g +~~~ + +To run: + +~~~ +$ cd wasm # this directory +$ wasm-pack build +$ cd www +$ npm install +$ export NODE_OPTIONS=--openssl-legacy-provider +$ npm run start +~~~ + + + +
+ +

wasm-pack-template

+ + A template for kick starting a Rust and WebAssembly project using wasm-pack. + +

+ Build Status +

+ +

+ Tutorial + | + Chat +

+ + Built with 🦀🕸 by The Rust and WebAssembly Working Group +
+ +## About + +[**📚 Read this template tutorial! 📚**][template-docs] + +This template is designed for compiling Rust libraries into WebAssembly and +publishing the resulting package to NPM. + +Be sure to check out [other `wasm-pack` tutorials online][tutorials] for other +templates and usages of `wasm-pack`. + +[tutorials]: https://rustwasm.github.io/docs/wasm-pack/tutorials/index.html +[template-docs]: https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html + +## 🚴 Usage + +### 🐑 Use `cargo generate` to Clone this Template + +[Learn more about `cargo generate` here.](https://github.com/ashleygwilliams/cargo-generate) + +``` +cargo generate --git https://github.com/rustwasm/wasm-pack-template.git --name my-project +cd my-project +``` + +### 🛠️ Build with `wasm-pack build` + +``` +wasm-pack build +``` + +### 🔬 Test in Headless Browsers with `wasm-pack test` + +``` +wasm-pack test --headless --firefox +``` + +### 🎁 Publish to NPM with `wasm-pack publish` + +``` +wasm-pack publish +``` + +## 🔋 Batteries Included + +* [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating + between WebAssembly and JavaScript. +* [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook) + for logging panic messages to the developer console. +* `LICENSE-APACHE` and `LICENSE-MIT`: most Rust projects are licensed this way, so these are included for you + +## License + +Licensed under either of + +* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) +* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs new file mode 100644 index 0000000..25a01a5 --- /dev/null +++ b/wasm/src/lib.rs @@ -0,0 +1,27 @@ +use wasm_bindgen::prelude::*; +use rand_chacha::rand_core::SeedableRng; +use fips204::ml_dsa_44; +use fips204::traits::{SerDes, Signer, Verifier}; + + +#[wasm_bindgen] +pub fn sign(message: &str) -> String { + let seed = 123; + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed); + let (pk, sk) = ml_dsa_44::try_keygen_with_rng_vt(&mut rng).expect("keygen failed"); + let sig = sk.try_sign_with_rng_ct(&mut rng, message.as_ref()).expect("sign failed"); + assert!(pk.try_verify_vt(message.as_ref(), &sig).expect("verify error"), "verify failed"); + + let sk_hex = hex::encode(&sk.into_bytes()); + let sig_hex = hex::encode(&sig); + let pk_hex = hex::encode(&pk.into_bytes()); + + let s0 = format!("The message to sign is: {} len {}\n", message, message.len()); + let s1 = format!("The seed used to generate the keys is: {}\n\n", seed); + let s2 = format!("The generated public||private key is: {}\n", sk_hex); + let s3 = format!("Using that private key, the calculated signature is: {}\n\n", sig_hex); + let s4 = format!("The generated public key is: {}\n", pk_hex); + let s5 = "The public key verifies the signature on the message."; // because the above assert! passed + + (s0 + &s1 + &s2 + &s3 + &s4 + &s5).into() +}