From f2dabd99cd216870c764b0ac5c14d43de834c54f Mon Sep 17 00:00:00 2001 From: aumetra Date: Sat, 27 Jan 2024 18:50:39 +0100 Subject: [PATCH 1/7] progress --- Cargo.lock | 350 ++++++++++++------------------ dsa/Cargo.toml | 10 +- dsa/src/components.rs | 45 ++-- dsa/src/generate.rs | 13 +- dsa/src/generate/components.rs | 47 ++-- dsa/src/generate/keypair.rs | 11 +- dsa/src/generate/secret_number.rs | 39 ++-- dsa/src/lib.rs | 51 +++-- dsa/src/signing_key.rs | 42 ++-- dsa/src/verifying_key.rs | 51 +++-- dsa/tests/deterministic.rs | 80 ++++--- dsa/tests/signing_key.rs | 15 +- dsa/tests/verifying_key.rs | 11 +- 13 files changed, 382 insertions(+), 383 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 478c274d..4b447275 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,15 +30,15 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "base16ct" @@ -78,15 +78,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -108,9 +102,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.15.4" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" @@ -169,18 +163,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "8f6b81fb3c84f5563d509c59b5a48d935f689e993afa90fe39047f05adef9142" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "5ca6706fd5224857d9ac5eb9355f6683563cc0541c7cd9d014043b57cbec78ac" dependencies = [ "anstyle", "clap_lex", @@ -188,9 +182,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "const-oid" @@ -200,9 +194,9 @@ checksum = "f7e3352a27098ba6b09546e5f13b15165e6a88b5c2723afecb3ea9576b27e3ea" [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -264,9 +258,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -283,6 +277,7 @@ dependencies = [ "hybrid-array", "num-traits", "rand_core", + "serdect 0.2.0", "subtle", "zeroize", ] @@ -308,6 +303,16 @@ dependencies = [ "rand_core", ] +[[package]] +name = "crypto-primes" +version = "0.6.0-pre.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31bb1382ea4ef18b2da595f36ca284c7b6366d22264ac02f8baee109361cd6b0" +dependencies = [ + "crypto-bigint", + "rand_core", +] + [[package]] name = "ctr" version = "0.9.2" @@ -320,7 +325,7 @@ dependencies = [ [[package]] name = "der" version = "0.8.0-pre.0" -source = "git+https://github.com/RustCrypto/formats.git?branch=master#270dbcb01ff75791d6527ff7759d335a39585420" +source = "git+https://github.com/RustCrypto/formats.git?branch=master#97ead54665f0b2067121e9896db9039ebbd0bccb" dependencies = [ "const-oid", "pem-rfc7468", @@ -354,9 +359,9 @@ dependencies = [ name = "dsa" version = "0.7.0-pre" dependencies = [ + "crypto-bigint", + "crypto-primes", "digest 0.11.0-pre.8", - "num-bigint-dig", - "num-traits", "pkcs8", "rand", "rand_chacha", @@ -410,9 +415,9 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "elliptic-curve" @@ -448,9 +453,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys", @@ -458,9 +463,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "ff" @@ -491,9 +496,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -513,9 +518,9 @@ dependencies = [ [[package]] name = "half" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ "cfg-if", "crunchy", @@ -559,9 +564,9 @@ dependencies = [ [[package]] name = "hybrid-array" -version = "0.2.0-rc.8" +version = "0.2.0-rc.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53668f5da5a41d9eaf4bf7064be46d1ebe6a4e1ceed817f387587b18f2b51047" +checksum = "4d306b679262030ad8813a82d4915fc04efff97776e4db7f8eb5137039d56400" dependencies = [ "typenum", "zeroize", @@ -622,18 +627,15 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -dependencies = [ - "spin", -] +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libm" @@ -643,9 +645,9 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lms-signature" @@ -666,15 +668,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "ml-dsa" @@ -685,50 +687,20 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] -[[package]] -name = "num-bigint-dig" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" -dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand", - "smallvec", - "zeroize", -] - [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" -dependencies = [ - "autocfg", - "num-integer", "num-traits", ] @@ -750,9 +722,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "paste" @@ -769,30 +741,20 @@ dependencies = [ "base64ct", ] -[[package]] -name = "pkcs5" -version = "0.8.0-pre.0" -source = "git+https://github.com/RustCrypto/formats.git?branch=master#270dbcb01ff75791d6527ff7759d335a39585420" -dependencies = [ - "der", - "spki", -] - [[package]] name = "pkcs8" version = "0.11.0-pre.0" -source = "git+https://github.com/RustCrypto/formats.git?branch=master#270dbcb01ff75791d6527ff7759d335a39585420" +source = "git+https://github.com/RustCrypto/formats.git?branch=master#97ead54665f0b2067121e9896db9039ebbd0bccb" dependencies = [ "der", - "pkcs5", "spki", ] [[package]] name = "plotters" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" dependencies = [ "num-traits", "plotters-backend", @@ -803,15 +765,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" +checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" [[package]] name = "plotters-svg" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" dependencies = [ "plotters-backend", ] @@ -824,22 +786,22 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.5.0", + "bitflags", "lazy_static", "num-traits", "rand", @@ -881,9 +843,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -947,20 +909,11 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "regex" -version = "1.10.4" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", @@ -970,9 +923,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -981,9 +934,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rfc6979" @@ -997,11 +950,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.28" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -1022,9 +975,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -1038,7 +991,7 @@ dependencies = [ [[package]] name = "sec1" version = "0.8.0-pre.1" -source = "git+https://github.com/RustCrypto/formats.git?branch=master#270dbcb01ff75791d6527ff7759d335a39585420" +source = "git+https://github.com/RustCrypto/formats.git?branch=master#97ead54665f0b2067121e9896db9039ebbd0bccb" dependencies = [ "base16ct", "der", @@ -1051,38 +1004,38 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.192" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.14" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.72", ] [[package]] name = "serde_json" -version = "1.0.109" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "itoa", "ryu", @@ -1190,22 +1143,10 @@ dependencies = [ "zerocopy-derive", ] -[[package]] -name = "smallvec" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spki" version = "0.8.0-pre.0" -source = "git+https://github.com/RustCrypto/formats.git?branch=master#270dbcb01ff75791d6527ff7759d335a39585420" +source = "git+https://github.com/RustCrypto/formats.git?branch=master#97ead54665f0b2067121e9896db9039ebbd0bccb" dependencies = [ "base64ct", "der", @@ -1219,9 +1160,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -1236,9 +1177,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", @@ -1247,13 +1188,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.9.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", "rustix", "windows-sys", ] @@ -1338,7 +1278,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.72", "wasm-bindgen-shared", ] @@ -1360,7 +1300,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.72", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1381,37 +1321,15 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys", ] -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "windows-sys" version = "0.52.0" @@ -1423,13 +1341,14 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -1438,51 +1357,57 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", "zerocopy-derive", @@ -1490,13 +1415,13 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.72", ] [[package]] @@ -1504,3 +1429,8 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[patch.unused]] +name = "pkcs5" +version = "0.8.0-pre.0" +source = "git+https://github.com/RustCrypto/formats.git?branch=master#97ead54665f0b2067121e9896db9039ebbd0bccb" diff --git a/dsa/Cargo.toml b/dsa/Cargo.toml index bc394aba..4a476026 100644 --- a/dsa/Cargo.toml +++ b/dsa/Cargo.toml @@ -17,12 +17,16 @@ rust-version = "1.72" [dependencies] digest = "=0.11.0-pre.8" -num-bigint = { package = "num-bigint-dig", version = "0.8", default-features = false, features = ["prime", "rand", "zeroize"] } -num-traits = { version = "0.2", default-features = false } +crypto-bigint = { version = "0.6.0-pre.7", features = ["alloc", "zeroize"] } +crypto-primes = "0.6.0-pre.0" pkcs8 = { version = "=0.11.0-pre.0", default-features = false, features = ["alloc"] } rfc6979 = { version = "=0.5.0-pre.3", path = "../rfc6979" } sha2 = { version = "=0.11.0-pre.3", default-features = false } -signature = { version = "=2.3.0-pre.3", default-features = false, features = ["alloc", "digest", "rand_core"] } +signature = { version = "=2.3.0-pre.3", default-features = false, features = [ + "alloc", + "digest", + "rand_core", +] } zeroize = { version = "1", default-features = false } [dev-dependencies] diff --git a/dsa/src/components.rs b/dsa/src/components.rs index dbc708e9..c03cccea 100644 --- a/dsa/src/components.rs +++ b/dsa/src/components.rs @@ -3,8 +3,7 @@ //! use crate::{size::KeySize, two}; -use num_bigint::BigUint; -use num_traits::Zero; +use crypto_bigint::{BoxedUint, NonZero}; use pkcs8::der::{ self, asn1::UintRef, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag, Writer, @@ -18,19 +17,23 @@ use signature::rand_core::CryptoRngCore; #[must_use] pub struct Components { /// Prime p - p: BigUint, + p: NonZero, /// Quotient q - q: BigUint, + q: NonZero, /// Generator g - g: BigUint, + g: NonZero, } impl Components { /// Construct the common components container from its inner values (p, q and g) - pub fn from_components(p: BigUint, q: BigUint, g: BigUint) -> signature::Result { - if p < two() || q < two() || g.is_zero() || g > p { + pub fn from_components( + p: NonZero, + q: NonZero, + g: NonZero, + ) -> signature::Result { + if *p < two() || *q < two() || g > p { return Err(signature::Error::new()); } @@ -45,19 +48,19 @@ impl Components { /// DSA prime p #[must_use] - pub const fn p(&self) -> &BigUint { + pub const fn p(&self) -> &NonZero { &self.p } /// DSA quotient q #[must_use] - pub const fn q(&self) -> &BigUint { + pub const fn q(&self) -> &NonZero { &self.q } /// DSA generator g #[must_use] - pub const fn g(&self) -> &BigUint { + pub const fn g(&self) -> &NonZero { &self.g } } @@ -70,9 +73,13 @@ impl<'a> DecodeValue<'a> for Components { let q = reader.decode::>()?; let g = reader.decode::>()?; - let p = BigUint::from_bytes_be(p.as_bytes()); - let q = BigUint::from_bytes_be(q.as_bytes()); - let g = BigUint::from_bytes_be(g.as_bytes()); + let p = BoxedUint::from_be_slice(p.as_bytes(), (p.as_bytes().len() * 8) as u32).unwrap(); + let q = BoxedUint::from_be_slice(q.as_bytes(), (q.as_bytes().len() * 8) as u32).unwrap(); + let g = BoxedUint::from_be_slice(g.as_bytes(), (g.as_bytes().len() * 8) as u32).unwrap(); + + let p = NonZero::new(p).unwrap(); + let q = NonZero::new(q).unwrap(); + let g = NonZero::new(g).unwrap(); Self::from_components(p, q, g).map_err(|_| Tag::Integer.value_error()) } @@ -80,15 +87,15 @@ impl<'a> DecodeValue<'a> for Components { impl EncodeValue for Components { fn value_len(&self) -> der::Result { - UintRef::new(&self.p.to_bytes_be())?.encoded_len()? - + UintRef::new(&self.q.to_bytes_be())?.encoded_len()? - + UintRef::new(&self.g.to_bytes_be())?.encoded_len()? + UintRef::new(&self.p.to_be_bytes())?.encoded_len()? + + UintRef::new(&self.q.to_be_bytes())?.encoded_len()? + + UintRef::new(&self.g.to_be_bytes())?.encoded_len()? } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { - UintRef::new(&self.p.to_bytes_be())?.encode(writer)?; - UintRef::new(&self.q.to_bytes_be())?.encode(writer)?; - UintRef::new(&self.g.to_bytes_be())?.encode(writer)?; + UintRef::new(&self.p.to_be_bytes())?.encode(writer)?; + UintRef::new(&self.q.to_be_bytes())?.encode(writer)?; + UintRef::new(&self.g.to_be_bytes())?.encode(writer)?; Ok(()) } } diff --git a/dsa/src/generate.rs b/dsa/src/generate.rs index 1e9b12c3..749a36a7 100644 --- a/dsa/src/generate.rs +++ b/dsa/src/generate.rs @@ -1,6 +1,5 @@ use crate::two; -use num_bigint::{BigUint, RandPrime}; -use num_traits::Pow; +use crypto_bigint::BoxedUint; use signature::rand_core::CryptoRngCore; mod components; @@ -13,9 +12,9 @@ pub use self::secret_number::{secret_number, secret_number_rfc6979}; /// Calculate the upper and lower bounds for generating values like p or q #[inline] -fn calculate_bounds(size: u32) -> (BigUint, BigUint) { - let lower = two().pow(size - 1); - let upper = two().pow(size); +fn calculate_bounds(size: u32) -> (BoxedUint, BoxedUint) { + let lower = two().shl(size - 1); + let upper = two().shl(size); (lower, upper) } @@ -24,6 +23,6 @@ fn calculate_bounds(size: u32) -> (BigUint, BigUint) { /// /// This wrapper function mainly exists to enforce the [`CryptoRng`](rand::CryptoRng) requirement (I might otherwise forget it) #[inline] -fn generate_prime(bit_length: usize, rng: &mut impl CryptoRngCore) -> BigUint { - rng.gen_prime(bit_length) +fn generate_prime(bit_length: u32, rng: &mut impl CryptoRngCore) -> BoxedUint { + crypto_primes::generate_prime_with_rng(rng, bit_length, bit_length) } diff --git a/dsa/src/generate/components.rs b/dsa/src/generate/components.rs index 101aefab..f8511c4e 100644 --- a/dsa/src/generate/components.rs +++ b/dsa/src/generate/components.rs @@ -7,59 +7,63 @@ use crate::{ size::KeySize, two, Components, }; -use num_bigint::{prime::probably_prime, BigUint, RandBigInt}; -use num_traits::One; +use crypto_bigint::{ + modular::{BoxedMontyForm, BoxedMontyParams}, + BoxedUint, NonZero, Odd, RandomBits, +}; use signature::rand_core::CryptoRngCore; -/// Numbers of miller-rabin rounds performed to determine primality -const MR_ROUNDS: usize = 64; - /// Generate the common components p, q, and g /// /// # Returns /// -/// Tuple of three `BigUint`s. Ordered like this `(p, q, g)` +/// Tuple of three `BoxedUint`s. Ordered like this `(p, q, g)` pub fn common( rng: &mut impl CryptoRngCore, KeySize { l, n }: KeySize, -) -> (BigUint, BigUint, BigUint) { +) -> (NonZero, NonZero, NonZero) { // Calculate the lower and upper bounds of p and q let (p_min, p_max) = calculate_bounds(l); let (q_min, q_max) = calculate_bounds(n); let (p, q) = 'gen_pq: loop { - let q = generate_prime(n as usize, rng); + let q = generate_prime(n, rng); if q < q_min || q > q_max { continue; } + let q = NonZero::new(q).unwrap(); // Attempt to find a prime p which has a subgroup of the order q for _ in 0..4096 { let m = 'gen_m: loop { - let m = rng.gen_biguint(l as usize); + let m = BoxedUint::random_bits(rng, l); if m > p_min && m < p_max { break 'gen_m m; } }; - let mr = &m % (two() * &q); - let p = m - mr + BigUint::one(); + let mr = &m % NonZero::new(two() * &*q).unwrap(); + let p = m - mr + BoxedUint::one(); + let p = NonZero::new(p).unwrap(); - if probably_prime(&p, MR_ROUNDS) { + if crypto_primes::is_prime_with_rng(rng, &*p) { break 'gen_pq (p, q); } } }; // Generate g using the unverifiable method as defined by Appendix A.2.1 - let e = (&p - BigUint::one()) / &q; - let mut h = BigUint::one(); + let e = (&*p - &BoxedUint::one()) / &q; + let mut h = BoxedUint::one(); let g = loop { - let g = h.modpow(&e, &p); - if !g.is_one() { - break g; + let params = BoxedMontyParams::new_vartime(Odd::new((*p).clone()).unwrap()); + let form = BoxedMontyForm::new(h.clone(), params); + let g = form.pow(&e).to_montgomery(); + + if !bool::from(g.is_one()) { + break NonZero::new(g).unwrap(); } - h += BigUint::one(); + h = h + BoxedUint::one(); }; (p, q, g) @@ -67,9 +71,12 @@ pub fn common( /// Calculate the public component from the common components and the private component #[inline] -pub fn public(components: &Components, x: &BigUint) -> BigUint { +pub fn public(components: &Components, x: &NonZero) -> NonZero { let p = components.p(); let g = components.g(); - g.modpow(x, p) + let params = BoxedMontyParams::new_vartime(Odd::new((**p).clone()).unwrap()); + let form = BoxedMontyForm::new((**g).clone(), params); + + NonZero::new(form.pow(x).to_montgomery()).unwrap() } diff --git a/dsa/src/generate/keypair.rs b/dsa/src/generate/keypair.rs index 39cdc2b5..e07b5e23 100644 --- a/dsa/src/generate/keypair.rs +++ b/dsa/src/generate/keypair.rs @@ -3,14 +3,19 @@ //! use crate::{generate::components, Components, SigningKey, VerifyingKey}; -use num_bigint::{BigUint, RandBigInt}; -use num_traits::One; +use crypto_bigint::{BoxedUint, NonZero, RandomMod}; use signature::rand_core::CryptoRngCore; /// Generate a new keypair #[inline] pub fn keypair(rng: &mut impl CryptoRngCore, components: Components) -> SigningKey { - let x = rng.gen_biguint_range(&BigUint::one(), components.q()); + let x = loop { + let x = BoxedUint::random_mod(rng, components.q()); + if let Some(x) = NonZero::new(x).into() { + break x; + } + }; + let y = components::public(&components, &x); VerifyingKey::from_components(components, y) diff --git a/dsa/src/generate/secret_number.rs b/dsa/src/generate/secret_number.rs index 3c974ed4..2009dba1 100644 --- a/dsa/src/generate/secret_number.rs +++ b/dsa/src/generate/secret_number.rs @@ -5,25 +5,24 @@ use crate::{Components, SigningKey}; use alloc::{vec, vec::Vec}; use core::cmp::min; +use crypto_bigint::{BoxedUint, InvMod, NonZero, RandomBits}; use digest::{core_api::BlockSizeUser, Digest, FixedOutputReset}; -use num_bigint::{BigUint, ModInverse, RandBigInt}; -use num_traits::{One, Zero}; use rfc6979::HmacDrbg; use signature::rand_core::CryptoRngCore; use zeroize::Zeroize; /// Reduce the hash into an RFC-6979 appropriate form -fn reduce_hash(q: &BigUint, hash: &[u8]) -> Vec { +fn reduce_hash(q: &NonZero, hash: &[u8]) -> Vec { // Reduce the hash modulo Q let q_byte_len = q.bits() / 8; - let hash_len = min(hash.len(), q_byte_len); + let hash_len = min(hash.len(), q_byte_len as usize); let hash = &hash[..hash_len]; - let hash = BigUint::from_bytes_be(hash); - let mut reduced = (hash % q).to_bytes_be(); + let hash = BoxedUint::from_be_slice(hash, (hash.len() * 8) as u32).unwrap(); + let mut reduced = Vec::from((hash % q).to_be_bytes()); - while reduced.len() < q_byte_len { + while reduced.len() < q_byte_len as usize { reduced.insert(0, 0); } @@ -36,15 +35,15 @@ fn reduce_hash(q: &BigUint, hash: &[u8]) -> Vec { /// /// Secret number k and its modular multiplicative inverse with q #[inline] -pub fn secret_number_rfc6979(signing_key: &SigningKey, hash: &[u8]) -> (BigUint, BigUint) +pub fn secret_number_rfc6979(signing_key: &SigningKey, hash: &[u8]) -> (BoxedUint, BoxedUint) where D: Digest + BlockSizeUser + FixedOutputReset, { let q = signing_key.verifying_key().components().q(); - let k_size = q.bits() / 8; + let k_size = (q.bits() / 8) as usize; let hash = reduce_hash(q, hash); - let mut x_bytes = signing_key.x().to_bytes_be(); + let mut x_bytes = signing_key.x().to_be_bytes(); let mut hmac = HmacDrbg::::new(&x_bytes, &hash, &[]); x_bytes.zeroize(); @@ -52,11 +51,9 @@ where loop { hmac.fill_bytes(&mut buffer); - let k = BigUint::from_bytes_be(&buffer); - if let Some(inv_k) = (&k).mod_inverse(q) { - let inv_k = inv_k.to_biguint().unwrap(); - - if k > BigUint::zero() && &k < q { + let k = BoxedUint::from_be_slice(&buffer, (buffer.len() * 8) as u32).unwrap(); + if let Some(inv_k) = k.inv_mod(q).into() { + if k > BoxedUint::zero() && k < **q { return (k, inv_k); } } @@ -72,21 +69,19 @@ where pub fn secret_number( rng: &mut impl CryptoRngCore, components: &Components, -) -> Option<(BigUint, BigUint)> { +) -> Option<(BoxedUint, BoxedUint)> { let q = components.q(); let n = q.bits(); // Attempt to try a fitting secret number // Give up after 4096 tries for _ in 0..4096 { - let c = rng.gen_biguint(n + 64); - let k = (c % (q - BigUint::one())) + BigUint::one(); - - if let Some(inv_k) = (&k).mod_inverse(q) { - let inv_k = inv_k.to_biguint().unwrap(); + let c = BoxedUint::random_bits(rng, n + 64); + let k = (c % NonZero::new(&**q - &BoxedUint::one()).unwrap()) + BoxedUint::one(); + if let Some(inv_k) = k.inv_mod(q).into() { // `k` and `k^-1` both have to be in the range `[1, q-1]` - if (inv_k > BigUint::zero() && &inv_k < q) && (k > BigUint::zero() && &k < q) { + if (inv_k > BoxedUint::zero() && inv_k < **q) && (k > BoxedUint::zero() && k < **q) { return Some((k, inv_k)); } } diff --git a/dsa/src/lib.rs b/dsa/src/lib.rs index 89805fd3..9c39b5a4 100644 --- a/dsa/src/lib.rs +++ b/dsa/src/lib.rs @@ -24,11 +24,11 @@ //! //! ``` //! # use dsa::{Components, SigningKey, VerifyingKey}; -//! # use num_bigint::BigUint; +//! # use crypto_bigint::BoxedUint; //! # use num_traits::One; -//! # let read_common_parameters = || (BigUint::one(), BigUint::one(), BigUint::one()); -//! # let read_public_component = || BigUint::one(); -//! # let read_private_component = || BigUint::one(); +//! # let read_common_parameters = || (BoxedUint::one(), BoxedUint::one(), BoxedUint::one()); +//! # let read_public_component = || BoxedUint::one(); +//! # let read_private_component = || BoxedUint::one(); //! # || -> signature::Result<()> { //! let (p, q, g) = read_common_parameters(); //! let components = Components::from_components(p, q, g)?; @@ -50,7 +50,8 @@ pub use crate::{ components::Components, signing_key::SigningKey, size::KeySize, verifying_key::VerifyingKey, }; -pub use num_bigint::BigUint; +pub use crypto_bigint::BoxedUint; +use crypto_bigint::NonZero; pub use pkcs8; pub use signature; @@ -68,7 +69,6 @@ mod verifying_key; pub const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10040.4.1"); use alloc::{boxed::Box, vec::Vec}; -use num_traits::Zero; use pkcs8::der::{ self, asn1::UintRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Writer, @@ -80,31 +80,27 @@ use signature::SignatureEncoding; #[must_use] pub struct Signature { /// Signature part r - r: BigUint, + r: NonZero, /// Signature part s - s: BigUint, + s: NonZero, } impl Signature { /// Create a new Signature container from its components - pub fn from_components(r: BigUint, s: BigUint) -> signature::Result { - if r.is_zero() || s.is_zero() { - return Err(signature::Error::new()); - } - - Ok(Self { r, s }) + pub fn from_components(r: NonZero, s: NonZero) -> Self { + Self { r, s } } /// Signature part r #[must_use] - pub fn r(&self) -> &BigUint { + pub fn r(&self) -> &NonZero { &self.r } /// Signature part s #[must_use] - pub fn s(&self) -> &BigUint { + pub fn s(&self) -> &NonZero { &self.s } } @@ -117,23 +113,26 @@ impl<'a> DecodeValue<'a> for Signature { let r = UintRef::decode(reader)?; let s = UintRef::decode(reader)?; - let r = BigUint::from_bytes_be(r.as_bytes()); - let s = BigUint::from_bytes_be(s.as_bytes()); + let r = BoxedUint::from_be_slice(r.as_bytes(), r.as_bytes().len() as u32 * 8).unwrap(); + let s = BoxedUint::from_be_slice(s.as_bytes(), s.as_bytes().len() as u32 * 8).unwrap(); + + let r = NonZero::new(r).unwrap(); + let s = NonZero::new(s).unwrap(); - Self::from_components(r, s).map_err(|_| der::Tag::Integer.value_error()) + Ok(Self::from_components(r, s)) }) } } impl EncodeValue for Signature { fn value_len(&self) -> der::Result { - UintRef::new(&self.r.to_bytes_be())?.encoded_len()? - + UintRef::new(&self.s.to_bytes_be())?.encoded_len()? + UintRef::new(&self.r.to_be_bytes())?.encoded_len()? + + UintRef::new(&self.s.to_be_bytes())?.encoded_len()? } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { - UintRef::new(&self.r.to_bytes_be())?.encode(writer)?; - UintRef::new(&self.s.to_bytes_be())?.encode(writer)?; + UintRef::new(&self.r.to_be_bytes())?.encode(writer)?; + UintRef::new(&self.s.to_be_bytes())?.encode(writer)?; Ok(()) } } @@ -179,8 +178,8 @@ impl TryFrom<&[u8]> for Signature { } } -/// Returns a `BigUint` with the value 2 +/// Returns a `BoxedUint` with the value 2 #[inline] -fn two() -> BigUint { - BigUint::from(2_u8) +fn two() -> BoxedUint { + BoxedUint::from(2_u8) } diff --git a/dsa/src/signing_key.rs b/dsa/src/signing_key.rs index 698f0576..f408aabf 100644 --- a/dsa/src/signing_key.rs +++ b/dsa/src/signing_key.rs @@ -7,9 +7,11 @@ use core::{ cmp::min, fmt::{self, Debug}, }; +use crypto_bigint::{ + modular::{BoxedMontyForm, BoxedMontyParams}, + BoxedUint, NonZero, Odd, +}; use digest::{core_api::BlockSizeUser, Digest, FixedOutputReset}; -use num_bigint::BigUint; -use num_traits::Zero; use pkcs8::{ der::{asn1::UintRef, AnyRef, Decode, Encode}, AlgorithmIdentifierRef, EncodePrivateKey, PrivateKeyInfo, SecretDocument, @@ -32,13 +34,16 @@ pub struct SigningKey { verifying_key: VerifyingKey, /// Private component x - x: Zeroizing, + x: Zeroizing>, } impl SigningKey { /// Construct a new private key from the public key and private component - pub fn from_components(verifying_key: VerifyingKey, x: BigUint) -> signature::Result { - if x.is_zero() || x > *verifying_key.components().q() { + pub fn from_components( + verifying_key: VerifyingKey, + x: NonZero, + ) -> signature::Result { + if x > *verifying_key.components().q() { return Err(signature::Error::new()); } @@ -63,7 +68,7 @@ impl SigningKey { /// /// If you decide to clone this value, please consider using [`Zeroize::zeroize`](::zeroize::Zeroize::zeroize()) to zero out the memory after you're done using the clone #[must_use] - pub fn x(&self) -> &BigUint { + pub fn x(&self) -> &NonZero { &self.x } @@ -82,24 +87,27 @@ impl SigningKey { /// Sign some pre-hashed data fn sign_prehashed( &self, - (k, inv_k): (BigUint, BigUint), + (k, inv_k): (BoxedUint, BoxedUint), hash: &[u8], ) -> signature::Result { let components = self.verifying_key().components(); let (p, q, g) = (components.p(), components.q(), components.g()); let x = self.x(); - let r = g.modpow(&k, p) % q; + let params = BoxedMontyParams::new(Odd::new(k).unwrap()); + let form = BoxedMontyForm::new((**g).clone(), params); + let r = NonZero::new(form.pow(p).to_montgomery() % q).unwrap(); let n = q.bits() / 8; let block_size = hash.len(); // Hash function output size - let z_len = min(n, block_size); - let z = BigUint::from_bytes_be(&hash[..z_len]); + let z_len = min(n as usize, block_size); + let z = BoxedUint::from_be_slice(&hash[..z_len], z_len as u32 * 8).unwrap(); - let s = (inv_k * (z + x * &r)) % q; + let s = inv_k.mul_mod(&(z + &**x * &*r), q); + let s = NonZero::new(s).unwrap(); - let signature = Signature::from_components(r, s)?; + let signature = Signature::from_components(r, s); if signature.r() < q && signature.s() < q { Ok(signature) @@ -178,7 +186,7 @@ impl EncodePrivateKey for SigningKey { parameters: Some(parameters), }; - let mut x_bytes = self.x().to_bytes_be(); + let mut x_bytes = self.x().to_be_bytes(); let x = UintRef::new(&x_bytes)?; let mut signing_key = x.to_der()?; @@ -202,11 +210,15 @@ impl<'a> TryFrom> for SigningKey { let components = parameters.decode_as::()?; let x = UintRef::from_der(value.private_key)?; - let x = BigUint::from_bytes_be(x.as_bytes()); + let x = BoxedUint::from_be_slice(x.as_bytes(), x.as_bytes().len() as u32 * 8).unwrap(); + let x = NonZero::new(x).unwrap(); let y = if let Some(y_bytes) = value.public_key { let y = UintRef::from_der(y_bytes)?; - BigUint::from_bytes_be(y.as_bytes()) + NonZero::new( + BoxedUint::from_be_slice(y.as_bytes(), y.as_bytes().len() as u32 * 8).unwrap(), + ) + .unwrap() } else { crate::generate::public_component(&components, &x) }; diff --git a/dsa/src/verifying_key.rs b/dsa/src/verifying_key.rs index e44bebf4..95c7ff74 100644 --- a/dsa/src/verifying_key.rs +++ b/dsa/src/verifying_key.rs @@ -4,9 +4,11 @@ use crate::{two, Components, Signature, OID}; use core::cmp::min; +use crypto_bigint::{ + modular::{BoxedMontyForm, BoxedMontyParams}, + BoxedUint, InvMod, NonZero, Odd, +}; use digest::Digest; -use num_bigint::{BigUint, ModInverse}; -use num_traits::One; use pkcs8::{ der::{ asn1::{BitStringRef, UintRef}, @@ -24,13 +26,19 @@ pub struct VerifyingKey { components: Components, /// Public component y - y: BigUint, + y: NonZero, } impl VerifyingKey { /// Construct a new public key from the common components and the public component - pub fn from_components(components: Components, y: BigUint) -> signature::Result { - if y < two() || y.modpow(components.q(), components.p()) != BigUint::one() { + pub fn from_components( + components: Components, + y: NonZero, + ) -> signature::Result { + let params = BoxedMontyParams::new_vartime(Odd::new((**components.p()).clone()).unwrap()); + let form = BoxedMontyForm::new((*y).clone(), params); + + if *y < two() || form.pow(components.q()).to_montgomery() != BoxedUint::one() { return Err(signature::Error::new()); } @@ -44,7 +52,7 @@ impl VerifyingKey { /// DSA public component #[must_use] - pub const fn y(&self) -> &BigUint { + pub const fn y(&self) -> &NonZero { &self.y } @@ -60,19 +68,26 @@ impl VerifyingKey { return Some(false); } - let w = s.mod_inverse(q)?.to_biguint().unwrap(); + let w = Option::from(s.inv_mod(q))?; let n = q.bits() / 8; let block_size = hash.len(); // Hash function output size - let z_len = min(n, block_size); - let z = BigUint::from_bytes_be(&hash[..z_len]); + let z_len = min(n as usize, block_size); + let z = BoxedUint::from_be_slice(&hash[..z_len], z_len as u32 * 8).unwrap(); let u1 = (&z * &w) % q; - let u2 = (r * &w) % q; - let v = (g.modpow(&u1, p) * y.modpow(&u2, p) % p) % q; + let u2 = r.mul_mod(&w, q); + + let u1_params = BoxedMontyParams::new(Odd::new(u1).unwrap()); + let u2_params = BoxedMontyParams::new(Odd::new(u2).unwrap()); + + let g_form = BoxedMontyForm::new((**g).clone(), u1_params); + let y_form = BoxedMontyForm::new((**y).clone(), u2_params); + + let v = (g_form.pow(p).to_montgomery() * y_form.pow(p).to_montgomery() % p) % q; - Some(v == *r) + Some(v == **r) } } @@ -124,7 +139,7 @@ impl EncodePublicKey for VerifyingKey { parameters: Some(parameters), }; - let y_bytes = self.y.to_bytes_be(); + let y_bytes = self.y.to_be_bytes(); let y = UintRef::new(&y_bytes)?; let public_key = y.to_der()?; @@ -151,7 +166,13 @@ impl<'a> TryFrom> for VerifyingKey { .ok_or(spki::Error::KeyMalformed)?, )?; - Self::from_components(components, BigUint::from_bytes_be(y.as_bytes())) - .map_err(|_| spki::Error::KeyMalformed) + Self::from_components( + components, + NonZero::new( + BoxedUint::from_be_slice(y.as_bytes(), y.as_bytes().len() as u32 * 8).unwrap(), + ) + .unwrap(), + ) + .map_err(|_| spki::Error::KeyMalformed) } } diff --git a/dsa/tests/deterministic.rs b/dsa/tests/deterministic.rs index 483844a0..3d21e2df 100644 --- a/dsa/tests/deterministic.rs +++ b/dsa/tests/deterministic.rs @@ -1,7 +1,6 @@ +use crypto_bigint::{BoxedUint, NonZero}; use digest::{core_api::BlockSizeUser, Digest, FixedOutputReset}; use dsa::{Components, Signature, SigningKey, VerifyingKey}; -use num_bigint::BigUint; -use num_traits::Num; use sha1::Sha1; use sha2::{Sha224, Sha256, Sha384, Sha512}; use signature::DigestSigner; @@ -10,33 +9,37 @@ const MESSAGE: &[u8] = b"sample"; const MESSAGE_2: &[u8] = b"test"; fn dsa_1024_signing_key() -> SigningKey { - let p = BigUint::from_str_radix( - "86F5CA03DCFEB225063FF830A0C769B9DD9D6153AD91D7CE27F787C43278B447\ + let p_str = "86F5CA03DCFEB225063FF830A0C769B9DD9D6153AD91D7CE27F787C43278B447\ E6533B86B18BED6E8A48B784A14C252C5BE0DBF60B86D6385BD2F12FB763ED88\ 73ABFD3F5BA2E0A8C0A59082EAC056935E529DAF7C610467899C77ADEDFC846C\ - 881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779", - 16, - ) - .unwrap(); - let q = BigUint::from_str_radix("996F967F6C8E388D9E28D01E205FBA957A5698B1", 16).unwrap(); - let g = BigUint::from_str_radix( - "07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D\ + 881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779"; + let p = BoxedUint::from_be_hex(p_str, p_str.len() as u32 * 8 / 2).unwrap(); + + let q_str = "996F967F6C8E388D9E28D01E205FBA957A5698B1"; + let q = BoxedUint::from_be_hex(q_str, q_str.len() as u32 * 8 / 2).unwrap(); + + let g_str = "07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D\ 89BBCD97E904E09114D9A7DEFDEADFC9078EA544D2E401AEECC40BB9FBBF78FD\ 87995A10A1C27CB7789B594BA7EFB5C4326A9FE59A070E136DB77175464ADCA4\ - 17BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD", - 16, - ) - .unwrap(); + 17BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD"; + let g = BoxedUint::from_be_hex(g_str, g_str.len() as u32 / 2 * 8).unwrap(); - let x = BigUint::from_str_radix("411602CB19A6CCC34494D79D98EF1E7ED5AF25F7", 16).unwrap(); - let y = BigUint::from_str_radix( - "5DF5E01DED31D0297E274E1691C192FE5868FEF9E19A84776454B100CF16F653\ + let x_str = "411602CB19A6CCC34494D79D98EF1E7ED5AF25F7"; + let x = BoxedUint::from_be_hex(x_str, x_str.len() as u32 / 2 * 8).unwrap(); + + let y_str = "5DF5E01DED31D0297E274E1691C192FE5868FEF9E19A84776454B100CF16F653\ 92195A38B90523E2542EE61871C0440CB87C322FC4B4D2EC5E1E7EC766E1BE8D\ 4CE935437DC11C3C8FD426338933EBFE739CB3465F4D3668C5E473508253B1E6\ - 82F65CBDC4FAE93C2EA212390E54905A86E2223170B44EAA7DA5DD9FFCFB7F3B", - 16, - ) - .unwrap(); + 82F65CBDC4FAE93C2EA212390E54905A86E2223170B44EAA7DA5DD9FFCFB7F3B"; + let y = BoxedUint::from_be_hex(y_str, y_str.len() as u32 / 2 * 8).unwrap(); + + let (p, q, g, y, x) = ( + NonZero::new(p).unwrap(), + NonZero::new(q).unwrap(), + NonZero::new(g).unwrap(), + NonZero::new(y).unwrap(), + NonZero::new(x).unwrap(), + ); let components = Components::from_components(p, q, g).expect("Invalid components"); let verifying_key = @@ -46,7 +49,7 @@ fn dsa_1024_signing_key() -> SigningKey { } fn dsa_2048_signing_key() -> SigningKey { - let p = BigUint::from_str_radix( + let p = BoxedUint::from_be_hex( "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48\ C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F\ FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5\ @@ -55,15 +58,15 @@ fn dsa_2048_signing_key() -> SigningKey { F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE\ 92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15\ 3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B", - 16, + 2048, ) .unwrap(); - let q = BigUint::from_str_radix( + let q = BoxedUint::from_be_hex( "F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F", - 16, + 2048, ) .unwrap(); - let g = BigUint::from_str_radix( + let g = BoxedUint::from_be_hex( "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613\ D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4\ 6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472\ @@ -72,16 +75,16 @@ fn dsa_2048_signing_key() -> SigningKey { 3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71\ BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0\ DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", - 16, + 2048, ) .unwrap(); - let x = BigUint::from_str_radix( + let x = BoxedUint::from_be_hex( "69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC", - 16, + 2048, ) .unwrap(); - let y = BigUint::from_str_radix( + let y = BoxedUint::from_be_hex( "667098C654426C78D7F8201EAC6C203EF030D43605032C2F1FA937E5237DBD94\ 9F34A0A2564FE126DC8B715C5141802CE0979C8246463C40E6B6BDAA2513FA61\ 1728716C2E4FD53BC95B89E69949D96512E873B9C8F8DFD499CC312882561ADE\ @@ -90,10 +93,18 @@ fn dsa_2048_signing_key() -> SigningKey { 687972A2D382599C9BAC4E0ED7998193078913032558134976410B89D2C171D1\ 23AC35FD977219597AA7D15C1A9A428E59194F75C721EBCBCFAE44696A499AFA\ 74E04299F132026601638CB87AB79190D4A0986315DA8EEC6561C938996BEADF", - 16, + 2048, ) .unwrap(); + let (p, q, g, y, x) = ( + NonZero::new(p).unwrap(), + NonZero::new(q).unwrap(), + NonZero::new(g).unwrap(), + NonZero::new(y).unwrap(), + NonZero::new(x).unwrap(), + ); + let components = Components::from_components(p, q, g).expect("Invalid components"); let verifying_key = VerifyingKey::from_components(components, y).expect("Invalid verifying key"); @@ -128,10 +139,9 @@ where /// Create a signature container from the two components in their textual hexadecimal form fn from_str_signature(r: &str, s: &str) -> Signature { Signature::from_components( - BigUint::from_str_radix(r, 16).unwrap(), - BigUint::from_str_radix(s, 16).unwrap(), + NonZero::new(BoxedUint::from_be_hex(r, r.len() as u32 / 2 * 8).unwrap()).unwrap(), + NonZero::new(BoxedUint::from_be_hex(s, s.len() as u32 / 2 * 8).unwrap()).unwrap(), ) - .unwrap() } /// Return the RFC 6979 test cases diff --git a/dsa/tests/signing_key.rs b/dsa/tests/signing_key.rs index 5b853987..a5d68b48 100644 --- a/dsa/tests/signing_key.rs +++ b/dsa/tests/signing_key.rs @@ -2,10 +2,12 @@ // But we want to use those small key sizes for fast tests #![allow(deprecated)] +use crypto_bigint::{ + modular::{BoxedMontyForm, BoxedMontyParams}, + BoxedUint, Odd, +}; use digest::Digest; use dsa::{Components, KeySize, SigningKey}; -use num_bigint::BigUint; -use num_traits::Zero; use pkcs8::{DecodePrivateKey, EncodePrivateKey, LineEnding}; use sha1::Sha1; use signature::{DigestVerifier, RandomizedDigestSigner}; @@ -59,13 +61,16 @@ fn verify_validity() { let signing_key = generate_keypair(); let components = signing_key.verifying_key().components(); + let params = BoxedMontyParams::new(Odd::new((**signing_key.x()).clone()).unwrap()); + let form = BoxedMontyForm::new((**components.g()).clone(), params); + assert!( - BigUint::zero() < *signing_key.x() && signing_key.x() < components.q(), + BoxedUint::zero() < **signing_key.x() && signing_key.x() < components.q(), "Requirement 0 Date: Sat, 27 Jan 2024 20:05:34 +0100 Subject: [PATCH 2/7] fix hex decoding --- Cargo.lock | 1 + dsa/Cargo.toml | 3 ++- dsa/tests/deterministic.rs | 49 +++++++++++++++++--------------------- 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4b447275..7c49c7e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -362,6 +362,7 @@ dependencies = [ "crypto-bigint", "crypto-primes", "digest 0.11.0-pre.8", + "hex", "pkcs8", "rand", "rand_chacha", diff --git a/dsa/Cargo.toml b/dsa/Cargo.toml index 4a476026..afaba5ce 100644 --- a/dsa/Cargo.toml +++ b/dsa/Cargo.toml @@ -17,7 +17,7 @@ rust-version = "1.72" [dependencies] digest = "=0.11.0-pre.8" -crypto-bigint = { version = "0.6.0-pre.7", features = ["alloc", "zeroize"] } +crypto-bigint = { version = "0.6.0-pre.12", features = ["alloc", "zeroize"] } crypto-primes = "0.6.0-pre.0" pkcs8 = { version = "=0.11.0-pre.0", default-features = false, features = ["alloc"] } rfc6979 = { version = "=0.5.0-pre.3", path = "../rfc6979" } @@ -30,6 +30,7 @@ signature = { version = "=2.3.0-pre.3", default-features = false, features = [ zeroize = { version = "1", default-features = false } [dev-dependencies] +hex = "0.4.3" pkcs8 = { version = "=0.11.0-pre.0", default-features = false, features = ["pem"] } rand = "0.8" rand_chacha = "0.3" diff --git a/dsa/tests/deterministic.rs b/dsa/tests/deterministic.rs index 3d21e2df..3ed3f265 100644 --- a/dsa/tests/deterministic.rs +++ b/dsa/tests/deterministic.rs @@ -8,30 +8,35 @@ use signature::DigestSigner; const MESSAGE: &[u8] = b"sample"; const MESSAGE_2: &[u8] = b"test"; +fn decode_hex_number(txt: &str) -> BoxedUint { + let val = hex::decode(txt).unwrap(); + BoxedUint::from_be_slice(&val, val.len() as u32 * 8).unwrap() +} + fn dsa_1024_signing_key() -> SigningKey { let p_str = "86F5CA03DCFEB225063FF830A0C769B9DD9D6153AD91D7CE27F787C43278B447\ E6533B86B18BED6E8A48B784A14C252C5BE0DBF60B86D6385BD2F12FB763ED88\ 73ABFD3F5BA2E0A8C0A59082EAC056935E529DAF7C610467899C77ADEDFC846C\ 881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779"; - let p = BoxedUint::from_be_hex(p_str, p_str.len() as u32 * 8 / 2).unwrap(); + let p = decode_hex_number(p_str); let q_str = "996F967F6C8E388D9E28D01E205FBA957A5698B1"; - let q = BoxedUint::from_be_hex(q_str, q_str.len() as u32 * 8 / 2).unwrap(); + let q = decode_hex_number(q_str); let g_str = "07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D\ 89BBCD97E904E09114D9A7DEFDEADFC9078EA544D2E401AEECC40BB9FBBF78FD\ 87995A10A1C27CB7789B594BA7EFB5C4326A9FE59A070E136DB77175464ADCA4\ 17BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD"; - let g = BoxedUint::from_be_hex(g_str, g_str.len() as u32 / 2 * 8).unwrap(); + let g = decode_hex_number(g_str); let x_str = "411602CB19A6CCC34494D79D98EF1E7ED5AF25F7"; - let x = BoxedUint::from_be_hex(x_str, x_str.len() as u32 / 2 * 8).unwrap(); + let x = decode_hex_number(x_str); let y_str = "5DF5E01DED31D0297E274E1691C192FE5868FEF9E19A84776454B100CF16F653\ 92195A38B90523E2542EE61871C0440CB87C322FC4B4D2EC5E1E7EC766E1BE8D\ 4CE935437DC11C3C8FD426338933EBFE739CB3465F4D3668C5E473508253B1E6\ 82F65CBDC4FAE93C2EA212390E54905A86E2223170B44EAA7DA5DD9FFCFB7F3B"; - let y = BoxedUint::from_be_hex(y_str, y_str.len() as u32 / 2 * 8).unwrap(); + let y = decode_hex_number(y_str); let (p, q, g, y, x) = ( NonZero::new(p).unwrap(), @@ -49,7 +54,7 @@ fn dsa_1024_signing_key() -> SigningKey { } fn dsa_2048_signing_key() -> SigningKey { - let p = BoxedUint::from_be_hex( + let p = decode_hex_number( "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48\ C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F\ FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5\ @@ -58,15 +63,11 @@ fn dsa_2048_signing_key() -> SigningKey { F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE\ 92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15\ 3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B", - 2048, - ) - .unwrap(); - let q = BoxedUint::from_be_hex( + ); + let q = decode_hex_number( "F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F", - 2048, - ) - .unwrap(); - let g = BoxedUint::from_be_hex( + ); + let g = decode_hex_number( "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613\ D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4\ 6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472\ @@ -75,16 +76,12 @@ fn dsa_2048_signing_key() -> SigningKey { 3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71\ BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0\ DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", - 2048, - ) - .unwrap(); + ); - let x = BoxedUint::from_be_hex( + let x = decode_hex_number( "69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC", - 2048, - ) - .unwrap(); - let y = BoxedUint::from_be_hex( + ); + let y = decode_hex_number( "667098C654426C78D7F8201EAC6C203EF030D43605032C2F1FA937E5237DBD94\ 9F34A0A2564FE126DC8B715C5141802CE0979C8246463C40E6B6BDAA2513FA61\ 1728716C2E4FD53BC95B89E69949D96512E873B9C8F8DFD499CC312882561ADE\ @@ -93,9 +90,7 @@ fn dsa_2048_signing_key() -> SigningKey { 687972A2D382599C9BAC4E0ED7998193078913032558134976410B89D2C171D1\ 23AC35FD977219597AA7D15C1A9A428E59194F75C721EBCBCFAE44696A499AFA\ 74E04299F132026601638CB87AB79190D4A0986315DA8EEC6561C938996BEADF", - 2048, - ) - .unwrap(); + ); let (p, q, g, y, x) = ( NonZero::new(p).unwrap(), @@ -139,8 +134,8 @@ where /// Create a signature container from the two components in their textual hexadecimal form fn from_str_signature(r: &str, s: &str) -> Signature { Signature::from_components( - NonZero::new(BoxedUint::from_be_hex(r, r.len() as u32 / 2 * 8).unwrap()).unwrap(), - NonZero::new(BoxedUint::from_be_hex(s, s.len() as u32 / 2 * 8).unwrap()).unwrap(), + NonZero::new(decode_hex_number(r)).unwrap(), + NonZero::new(decode_hex_number(s)).unwrap(), ) } From 3933fb4fbf5ed184375eb8f86b76ff58e856b468 Mon Sep 17 00:00:00 2001 From: aumetra Date: Sat, 27 Jan 2024 20:15:30 +0100 Subject: [PATCH 3/7] `.to_montgomery()` -> `.retrieve` --- dsa/src/generate/components.rs | 4 ++-- dsa/src/signing_key.rs | 2 +- dsa/src/verifying_key.rs | 4 ++-- dsa/tests/deterministic.rs | 8 ++------ dsa/tests/signing_key.rs | 2 +- dsa/tests/verifying_key.rs | 2 +- 6 files changed, 9 insertions(+), 13 deletions(-) diff --git a/dsa/src/generate/components.rs b/dsa/src/generate/components.rs index f8511c4e..5820d12f 100644 --- a/dsa/src/generate/components.rs +++ b/dsa/src/generate/components.rs @@ -57,7 +57,7 @@ pub fn common( let g = loop { let params = BoxedMontyParams::new_vartime(Odd::new((*p).clone()).unwrap()); let form = BoxedMontyForm::new(h.clone(), params); - let g = form.pow(&e).to_montgomery(); + let g = form.pow(&e).retrieve(); if !bool::from(g.is_one()) { break NonZero::new(g).unwrap(); @@ -78,5 +78,5 @@ pub fn public(components: &Components, x: &NonZero) -> NonZero SigningKey { 92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15\ 3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B", ); - let q = decode_hex_number( - "F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F", - ); + let q = decode_hex_number("F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F"); let g = decode_hex_number( "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613\ D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4\ @@ -78,9 +76,7 @@ fn dsa_2048_signing_key() -> SigningKey { DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", ); - let x = decode_hex_number( - "69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC", - ); + let x = decode_hex_number("69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC"); let y = decode_hex_number( "667098C654426C78D7F8201EAC6C203EF030D43605032C2F1FA937E5237DBD94\ 9F34A0A2564FE126DC8B715C5141802CE0979C8246463C40E6B6BDAA2513FA61\ diff --git a/dsa/tests/signing_key.rs b/dsa/tests/signing_key.rs index a5d68b48..47aa39cd 100644 --- a/dsa/tests/signing_key.rs +++ b/dsa/tests/signing_key.rs @@ -70,7 +70,7 @@ fn verify_validity() { ); assert_eq!( **signing_key.verifying_key().y(), - form.pow(signing_key.x()).to_montgomery(), + form.pow(signing_key.x()).retrieve(), "Requirement y=(g^x)%p not met" ); } diff --git a/dsa/tests/verifying_key.rs b/dsa/tests/verifying_key.rs index 41aff62d..6aa6c173 100644 --- a/dsa/tests/verifying_key.rs +++ b/dsa/tests/verifying_key.rs @@ -50,5 +50,5 @@ fn validate_verifying_key() { let form = BoxedMontyForm::new((**verifying_key.y()).clone(), params); // Taken from the parameter validation from bouncy castle - assert_eq!(form.pow(p).to_montgomery(), BoxedUint::one()); + assert_eq!(form.pow(p).retrieve(), BoxedUint::one()); } From 28b960484de1842296216f84e6a86e72cb3fedcb Mon Sep 17 00:00:00 2001 From: aumetra Date: Sat, 27 Jan 2024 20:29:28 +0100 Subject: [PATCH 4/7] pin dependencies --- dsa/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dsa/Cargo.toml b/dsa/Cargo.toml index afaba5ce..fe42369b 100644 --- a/dsa/Cargo.toml +++ b/dsa/Cargo.toml @@ -17,8 +17,8 @@ rust-version = "1.72" [dependencies] digest = "=0.11.0-pre.8" -crypto-bigint = { version = "0.6.0-pre.12", features = ["alloc", "zeroize"] } -crypto-primes = "0.6.0-pre.0" +crypto-bigint = { version = "=0.6.0-pre.12", default-features = false, features = ["alloc", "zeroize"] } +crypto-primes = { version = "=0.6.0-pre.0", default-features = false } pkcs8 = { version = "=0.11.0-pre.0", default-features = false, features = ["alloc"] } rfc6979 = { version = "=0.5.0-pre.3", path = "../rfc6979" } sha2 = { version = "=0.11.0-pre.3", default-features = false } From 92f783b5129b2474d1d89e9b80b6b45da18df3af Mon Sep 17 00:00:00 2001 From: aumetra Date: Sat, 27 Jan 2024 20:51:13 +0100 Subject: [PATCH 5/7] bump msrv --- .github/workflows/dsa.yml | 4 ++-- dsa/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dsa.yml b/.github/workflows/dsa.yml index 646dbbc5..35eff1b3 100644 --- a/.github/workflows/dsa.yml +++ b/.github/workflows/dsa.yml @@ -24,7 +24,7 @@ jobs: - thumbv7em-none-eabi - wasm32-unknown-unknown toolchain: - - 1.72.0 # MSRV + - 1.73.0 # MSRV - stable steps: - uses: actions/checkout@v4 @@ -42,7 +42,7 @@ jobs: - macos-latest - windows-latest toolchain: - - 1.72.0 # MSRV + - 1.73.0 # MSRV - stable runs-on: ${{ matrix.platform }} steps: diff --git a/dsa/Cargo.toml b/dsa/Cargo.toml index fe42369b..07f4d51a 100644 --- a/dsa/Cargo.toml +++ b/dsa/Cargo.toml @@ -13,7 +13,7 @@ homepage = "https://github.com/RustCrypto/signatures/tree/master/dsa" repository = "https://github.com/RustCrypto/signatures" categories = ["cryptography", "no-std"] keywords = ["crypto", "nist", "signature"] -rust-version = "1.72" +rust-version = "1.73" [dependencies] digest = "=0.11.0-pre.8" From d584735dbfaa8de60c12eff57ab85a0bec01ce69 Mon Sep 17 00:00:00 2001 From: aumetra Date: Sun, 28 Jan 2024 19:28:40 +0100 Subject: [PATCH 6/7] fix rfc6979 generation --- dsa/src/generate/secret_number.rs | 49 +++++++++++++------------------ 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/dsa/src/generate/secret_number.rs b/dsa/src/generate/secret_number.rs index 2009dba1..218bb574 100644 --- a/dsa/src/generate/secret_number.rs +++ b/dsa/src/generate/secret_number.rs @@ -3,30 +3,14 @@ //! use crate::{Components, SigningKey}; -use alloc::{vec, vec::Vec}; -use core::cmp::min; -use crypto_bigint::{BoxedUint, InvMod, NonZero, RandomBits}; +use alloc::vec; +use crypto_bigint::{BoxedUint, Integer, InvMod, NonZero, RandomBits}; use digest::{core_api::BlockSizeUser, Digest, FixedOutputReset}; -use rfc6979::HmacDrbg; use signature::rand_core::CryptoRngCore; -use zeroize::Zeroize; +use zeroize::Zeroizing; -/// Reduce the hash into an RFC-6979 appropriate form -fn reduce_hash(q: &NonZero, hash: &[u8]) -> Vec { - // Reduce the hash modulo Q - let q_byte_len = q.bits() / 8; - - let hash_len = min(hash.len(), q_byte_len as usize); - let hash = &hash[..hash_len]; - - let hash = BoxedUint::from_be_slice(hash, (hash.len() * 8) as u32).unwrap(); - let mut reduced = Vec::from((hash % q).to_be_bytes()); - - while reduced.len() < q_byte_len as usize { - reduced.insert(0, 0); - } - - reduced +fn strip_leading_zeros(buffer: &[u8], desired_size: usize) -> &[u8] { + &buffer[(buffer.len() - desired_size)..] } /// Generate a per-message secret number k deterministically using the method described in RFC 6979 @@ -40,20 +24,27 @@ where D: Digest + BlockSizeUser + FixedOutputReset, { let q = signing_key.verifying_key().components().q(); - let k_size = (q.bits() / 8) as usize; - let hash = reduce_hash(q, hash); + let size = (q.bits() / 8) as usize; + + // Reduce hash mod q + let hash = BoxedUint::from_be_slice(hash, (hash.len() * 8) as u32).unwrap(); + let hash = (hash % q).to_be_bytes(); + let hash = strip_leading_zeros(&hash, size); + + let q_bytes = q.to_be_bytes(); + let q_bytes = strip_leading_zeros(&q_bytes, size); - let mut x_bytes = signing_key.x().to_be_bytes(); - let mut hmac = HmacDrbg::::new(&x_bytes, &hash, &[]); - x_bytes.zeroize(); + let x_bytes = Zeroizing::new(signing_key.x().to_be_bytes()); + let x_bytes = strip_leading_zeros(&x_bytes, size); - let mut buffer = vec![0; k_size]; + let mut buffer = vec![0; size]; loop { - hmac.fill_bytes(&mut buffer); + rfc6979::generate_k_mut::(x_bytes, q_bytes, hash, &[], &mut buffer); let k = BoxedUint::from_be_slice(&buffer, (buffer.len() * 8) as u32).unwrap(); if let Some(inv_k) = k.inv_mod(q).into() { - if k > BoxedUint::zero() && k < **q { + if (bool::from(k.is_nonzero())) & (k < **q) { + debug_assert!(bool::from(k.is_odd())); return (k, inv_k); } } From ab0d36e7848c0dd95b9f693d57986d0c0921dd25 Mon Sep 17 00:00:00 2001 From: Aumetra Weisman Date: Tue, 23 Jul 2024 22:16:48 +0200 Subject: [PATCH 7/7] align all the precisions (its ugly) --- dsa/src/components.rs | 9 ++++++--- dsa/src/generate/secret_number.rs | 4 ++-- dsa/src/signing_key.rs | 14 ++++++++++++-- dsa/tests/deterministic.rs | 29 ++++++++++++++++++----------- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/dsa/src/components.rs b/dsa/src/components.rs index c03cccea..6458a777 100644 --- a/dsa/src/components.rs +++ b/dsa/src/components.rs @@ -73,9 +73,12 @@ impl<'a> DecodeValue<'a> for Components { let q = reader.decode::>()?; let g = reader.decode::>()?; - let p = BoxedUint::from_be_slice(p.as_bytes(), (p.as_bytes().len() * 8) as u32).unwrap(); - let q = BoxedUint::from_be_slice(q.as_bytes(), (q.as_bytes().len() * 8) as u32).unwrap(); - let g = BoxedUint::from_be_slice(g.as_bytes(), (g.as_bytes().len() * 8) as u32).unwrap(); + // Just use the precision of `p` since `p` will be the largest value and all values need to have the same precision + let precision = (p.as_bytes().len() * 8) as u32; + + let p = BoxedUint::from_be_slice(p.as_bytes(), precision).unwrap(); + let q = BoxedUint::from_be_slice(q.as_bytes(), precision).unwrap(); + let g = BoxedUint::from_be_slice(g.as_bytes(), precision).unwrap(); let p = NonZero::new(p).unwrap(); let q = NonZero::new(q).unwrap(); diff --git a/dsa/src/generate/secret_number.rs b/dsa/src/generate/secret_number.rs index 218bb574..83e3379c 100644 --- a/dsa/src/generate/secret_number.rs +++ b/dsa/src/generate/secret_number.rs @@ -27,7 +27,7 @@ where let size = (q.bits() / 8) as usize; // Reduce hash mod q - let hash = BoxedUint::from_be_slice(hash, (hash.len() * 8) as u32).unwrap(); + let hash = BoxedUint::from_be_slice(hash, q.bits_precision()).unwrap(); let hash = (hash % q).to_be_bytes(); let hash = strip_leading_zeros(&hash, size); @@ -41,7 +41,7 @@ where loop { rfc6979::generate_k_mut::(x_bytes, q_bytes, hash, &[], &mut buffer); - let k = BoxedUint::from_be_slice(&buffer, (buffer.len() * 8) as u32).unwrap(); + let k = BoxedUint::from_be_slice(&buffer, q.bits_precision()).unwrap(); if let Some(inv_k) = k.inv_mod(q).into() { if (bool::from(k.is_nonzero())) & (k < **q) { debug_assert!(bool::from(k.is_odd())); diff --git a/dsa/src/signing_key.rs b/dsa/src/signing_key.rs index f0222430..35b4d6a1 100644 --- a/dsa/src/signing_key.rs +++ b/dsa/src/signing_key.rs @@ -94,6 +94,12 @@ impl SigningKey { let (p, q, g) = (components.p(), components.q(), components.g()); let x = self.x(); + // Verify all the precisions check out. Otherwise the math operations will fail + debug_assert_eq!(p.bits_precision(), q.bits_precision()); + debug_assert_eq!(q.bits_precision(), g.bits_precision()); + debug_assert_eq!(g.bits_precision(), x.bits_precision()); + debug_assert_eq!(x.bits_precision(), k.bits_precision()); + let params = BoxedMontyParams::new(Odd::new(k).unwrap()); let form = BoxedMontyForm::new((**g).clone(), params); let r = NonZero::new(form.pow(p).retrieve() % q).unwrap(); @@ -209,14 +215,18 @@ impl<'a> TryFrom> for SigningKey { let parameters = value.algorithm.parameters_any()?; let components = parameters.decode_as::()?; + // Use the precision of `p`. `p` will always have the largest precision. + // Every operation is mod `p` anyway, so it will always fit. + let precision = components.p().bits_precision(); + let x = UintRef::from_der(value.private_key)?; - let x = BoxedUint::from_be_slice(x.as_bytes(), x.as_bytes().len() as u32 * 8).unwrap(); + let x = BoxedUint::from_be_slice(x.as_bytes(), precision).unwrap(); let x = NonZero::new(x).unwrap(); let y = if let Some(y_bytes) = value.public_key { let y = UintRef::from_der(y_bytes)?; NonZero::new( - BoxedUint::from_be_slice(y.as_bytes(), y.as_bytes().len() as u32 * 8).unwrap(), + BoxedUint::from_be_slice(y.as_bytes(), precision).unwrap(), ) .unwrap() } else { diff --git a/dsa/tests/deterministic.rs b/dsa/tests/deterministic.rs index cac7f95d..8236af68 100644 --- a/dsa/tests/deterministic.rs +++ b/dsa/tests/deterministic.rs @@ -8,9 +8,9 @@ use signature::DigestSigner; const MESSAGE: &[u8] = b"sample"; const MESSAGE_2: &[u8] = b"test"; -fn decode_hex_number(txt: &str) -> BoxedUint { +fn decode_hex_number(txt: &str, precision: u32) -> BoxedUint { let val = hex::decode(txt).unwrap(); - BoxedUint::from_be_slice(&val, val.len() as u32 * 8).unwrap() + BoxedUint::from_be_slice(&val, precision).unwrap() } fn dsa_1024_signing_key() -> SigningKey { @@ -18,25 +18,25 @@ fn dsa_1024_signing_key() -> SigningKey { E6533B86B18BED6E8A48B784A14C252C5BE0DBF60B86D6385BD2F12FB763ED88\ 73ABFD3F5BA2E0A8C0A59082EAC056935E529DAF7C610467899C77ADEDFC846C\ 881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779"; - let p = decode_hex_number(p_str); + let p = decode_hex_number(p_str, 1024); let q_str = "996F967F6C8E388D9E28D01E205FBA957A5698B1"; - let q = decode_hex_number(q_str); + let q = decode_hex_number(q_str, 1024); let g_str = "07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D\ 89BBCD97E904E09114D9A7DEFDEADFC9078EA544D2E401AEECC40BB9FBBF78FD\ 87995A10A1C27CB7789B594BA7EFB5C4326A9FE59A070E136DB77175464ADCA4\ 17BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD"; - let g = decode_hex_number(g_str); + let g = decode_hex_number(g_str, 1024); let x_str = "411602CB19A6CCC34494D79D98EF1E7ED5AF25F7"; - let x = decode_hex_number(x_str); + let x = decode_hex_number(x_str, 1024); let y_str = "5DF5E01DED31D0297E274E1691C192FE5868FEF9E19A84776454B100CF16F653\ 92195A38B90523E2542EE61871C0440CB87C322FC4B4D2EC5E1E7EC766E1BE8D\ 4CE935437DC11C3C8FD426338933EBFE739CB3465F4D3668C5E473508253B1E6\ 82F65CBDC4FAE93C2EA212390E54905A86E2223170B44EAA7DA5DD9FFCFB7F3B"; - let y = decode_hex_number(y_str); + let y = decode_hex_number(y_str, 1024); let (p, q, g, y, x) = ( NonZero::new(p).unwrap(), @@ -63,8 +63,9 @@ fn dsa_2048_signing_key() -> SigningKey { F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE\ 92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15\ 3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B", + 2048, ); - let q = decode_hex_number("F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F"); + let q = decode_hex_number("F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F", 2048); let g = decode_hex_number( "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613\ D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4\ @@ -74,9 +75,10 @@ fn dsa_2048_signing_key() -> SigningKey { 3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71\ BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0\ DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", + 2048, ); - let x = decode_hex_number("69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC"); + let x = decode_hex_number("69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC", 2048); let y = decode_hex_number( "667098C654426C78D7F8201EAC6C203EF030D43605032C2F1FA937E5237DBD94\ 9F34A0A2564FE126DC8B715C5141802CE0979C8246463C40E6B6BDAA2513FA61\ @@ -86,6 +88,7 @@ fn dsa_2048_signing_key() -> SigningKey { 687972A2D382599C9BAC4E0ED7998193078913032558134976410B89D2C171D1\ 23AC35FD977219597AA7D15C1A9A428E59194F75C721EBCBCFAE44696A499AFA\ 74E04299F132026601638CB87AB79190D4A0986315DA8EEC6561C938996BEADF", + 2048, ); let (p, q, g, y, x) = ( @@ -129,9 +132,13 @@ where /// Create a signature container from the two components in their textual hexadecimal form fn from_str_signature(r: &str, s: &str) -> Signature { + assert_eq!(r.len(), s.len()); + + let precision = (r.len() * 8) as u32; + Signature::from_components( - NonZero::new(decode_hex_number(r)).unwrap(), - NonZero::new(decode_hex_number(s)).unwrap(), + NonZero::new(decode_hex_number(r, precision)).unwrap(), + NonZero::new(decode_hex_number(s, precision)).unwrap(), ) }