diff --git a/src/atecc/atecc.c b/src/atecc/atecc.c index 9f3863d24..7a4302a27 100644 --- a/src/atecc/atecc.c +++ b/src/atecc/atecc.c @@ -34,7 +34,6 @@ typedef enum { ATECC_SLOT_ROLLKEY = 3, ATECC_SLOT_KDF = 4, ATECC_SLOT_ATTESTATION = 5, - ATECC_SLOT_ECC_UNSAFE_SIGN = 6, ATECC_SLOT_DATA0 = 9, // The other slots are currently not in use. } atecc_slot_t; @@ -631,74 +630,6 @@ bool atecc_random(uint8_t* rand_out) return false; } -// Length of priv_key must be 32 bytes -static bool _ecc_write_priv_key(const uint8_t* priv_key) -{ - uint8_t atca_priv_key[36] = {0}; - memcpy(atca_priv_key + 4, priv_key, 32); - - uint8_t encryption_key[32] = {0}; - UTIL_CLEANUP_32(encryption_key); - _interface_functions->get_encryption_key(encryption_key); - - uint8_t nonce_contribution[32] = {0}; - UTIL_CLEANUP_32(nonce_contribution); - _interface_functions->random_32_bytes(nonce_contribution); -#if NONCE_NUMIN_SIZE > 32 -#error "size mismatch" -#endif - - ATCA_STATUS result = _authorize_key(); - if (result != ATCA_SUCCESS) { - return false; - } - - return atcab_priv_write( - ATECC_SLOT_ECC_UNSAFE_SIGN, - atca_priv_key, - ATECC_SLOT_ENCRYPTION_KEY, - encryption_key, - nonce_contribution) == ATCA_SUCCESS; -} - -bool atecc_ecc_generate_public_key(uint8_t* priv_key, uint8_t* pub_key) -{ - if (!_ecc_write_priv_key(priv_key)) { - return false; - } - - ATCA_STATUS result = _authorize_key(); - if (result != ATCA_SUCCESS) { - return false; - } - - result = atcab_get_pubkey(ATECC_SLOT_ECC_UNSAFE_SIGN, pub_key); - if (result != ATCA_SUCCESS) { - return false; - } - - return true; -} - -bool atecc_ecc_unsafe_sign(const uint8_t* priv_key, const uint8_t* msg, uint8_t* sig) -{ - if (!_ecc_write_priv_key(priv_key)) { - return false; - } - - ATCA_STATUS result = _authorize_key(); - if (result != ATCA_SUCCESS) { - return false; - } - - result = atcab_sign(ATECC_SLOT_ECC_UNSAFE_SIGN, msg, sig); - if (result != ATCA_SUCCESS) { - return false; - } - - return true; -} - #if APP_U2F == 1 || FACTORYSETUP == 1 // Read a "standard" sized block from a data slot (must be 32 bytes) static bool _read_data_slot_block(uint8_t* bytes, uint16_t slot, uint8_t block) diff --git a/src/atecc/atecc.h b/src/atecc/atecc.h index 443732609..45e52fe1c 100644 --- a/src/atecc/atecc.h +++ b/src/atecc/atecc.h @@ -98,24 +98,6 @@ USE_RESULT bool atecc_monotonic_increments_remaining(uint32_t* remaining_out); */ USE_RESULT bool atecc_random(uint8_t* rand_out); -/** - * Generates the matching public key to the provided private key. Will put private key in unsafe - * ECC slot. - * @param[in] priv_key Private key (32 bytes). - * @param[out] pub_key Public key. Format will be the X and Y coordinates in big-endian (64 bytes). - * @return True if success - */ -USE_RESULT bool atecc_ecc_generate_public_key(uint8_t* priv_key, uint8_t* pub_key); - -/** - * Sign hash with private key. Will put private key in unsafe ECC slot. - * @param[in] priv_key Private key to use for signing (32 bytes) - * @param[in] msg Message to sign (32 bytes) - * @param[out] sig Signature (64 bytes) - * @return True if success - */ -USE_RESULT bool atecc_ecc_unsafe_sign(const uint8_t* priv_key, const uint8_t* msg, uint8_t* sig); - #if APP_U2F == 1 || FACTORYSETUP == 1 /** * Set the u2f counter to `counter`. Should only be used for initialization. diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 040bdbc1d..ae35dbfa0 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -30,6 +30,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base58ck" version = "0.1.0" @@ -122,6 +128,7 @@ dependencies = [ "bitbox02-rust", "bitcoin", "hex", + "p256", "sha2", "sha3", "util", @@ -253,6 +260,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "cpufeatures" version = "0.2.9" @@ -277,6 +290,18 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -313,6 +338,16 @@ dependencies = [ "syn", ] +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "digest" version = "0.10.7" @@ -320,10 +355,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", +] + [[package]] name = "ed25519" version = "2.2.3" @@ -352,6 +401,24 @@ version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "erc20_params" version = "0.1.0" @@ -359,6 +426,16 @@ dependencies = [ "hex", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + [[package]] name = "fiat-crypto" version = "0.2.3" @@ -367,12 +444,24 @@ checksum = "f69037fe1b785e84986b4f2cbcf647381876a00671d25ceef715d7812dd7e1dd" [[package]] name = "generic-array" -version = "0.14.4" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", ] [[package]] @@ -531,6 +620,18 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + [[package]] name = "poly1305" version = "0.8.0" @@ -542,6 +643,15 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro2" version = "1.0.82" @@ -589,6 +699,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "rustc_version" version = "0.4.0" @@ -604,6 +724,19 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "subtle", + "zeroize", +] + [[package]] name = "secp256k1" version = "0.29.0" @@ -688,6 +821,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", + "rand_core", ] [[package]] diff --git a/src/rust/bitbox02-rust-c/Cargo.toml b/src/rust/bitbox02-rust-c/Cargo.toml index 0f8f8d71d..44cb5cc4c 100644 --- a/src/rust/bitbox02-rust-c/Cargo.toml +++ b/src/rust/bitbox02-rust-c/Cargo.toml @@ -28,6 +28,7 @@ bitbox02-rust = { path = "../bitbox02-rust", optional = true } bitbox02 = { path = "../bitbox02", optional = true } bitbox02-noise = { path = "../bitbox02-noise", optional = true } util = { path = "../util" } +p256 = { version = "0.13.2", default-features = false, features = ["arithmetic", "ecdsa"] } hex = { workspace = true } sha2 = { workspace = true, optional = true } sha3 = { workspace = true, optional = true } diff --git a/src/rust/bitbox02-rust-c/src/lib.rs b/src/rust/bitbox02-rust-c/src/lib.rs index ec83f91e9..72c1d1056 100644 --- a/src/rust/bitbox02-rust-c/src/lib.rs +++ b/src/rust/bitbox02-rust-c/src/lib.rs @@ -35,6 +35,9 @@ mod sha2; #[cfg(feature = "firmware")] mod workflow; +#[cfg(feature = "firmware")] +mod p256; + // Whenever execution reaches somewhere it isn't supposed to rust code will "panic". Our panic // handler will print the available information on the screen. If we compile with `panic=abort` // this code will never get executed. diff --git a/src/rust/bitbox02-rust-c/src/p256.rs b/src/rust/bitbox02-rust-c/src/p256.rs new file mode 100644 index 000000000..78895e1b8 --- /dev/null +++ b/src/rust/bitbox02-rust-c/src/p256.rs @@ -0,0 +1,87 @@ +// Copyright 2024 Shift Crypto AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// Derive the public key of a ECC NIST-P256 private key. +/// private_key must be 32 bytes, public_key_out must be 64 bytes. +#[no_mangle] +pub extern "C" fn rust_p256_pubkey( + private_key: crate::util::Bytes, + mut public_key_out: crate::util::BytesMut, +) { + use p256::elliptic_curve::sec1::ToEncodedPoint; + let secret_key = p256::SecretKey::from_slice(private_key.as_ref()).unwrap(); + let public_key = secret_key.public_key(); + let encoded_point = public_key.to_encoded_point(false); + public_key_out.as_mut()[..32].copy_from_slice(&encoded_point.x().unwrap()); + public_key_out.as_mut()[32..].copy_from_slice(&encoded_point.y().unwrap()); +} + +/// Signs a msg using ECC-DSA NIST-P256. +/// private_key must be 32 bytes. +/// msg must be 32 bytes digest and is signed directly without further hashing. +/// sig_out must be 64 bytes. +#[no_mangle] +pub extern "C" fn rust_p256_sign( + private_key: crate::util::Bytes, + msg: crate::util::Bytes, + mut sig_out: crate::util::BytesMut, +) { + use p256::ecdsa::{signature::hazmat::PrehashSigner, Signature, SigningKey}; + let signing_key = SigningKey::from_slice(private_key.as_ref()).unwrap(); + let (signature, _): (Signature, _) = signing_key.sign_prehash(msg.as_ref()).unwrap(); + sig_out.as_mut().copy_from_slice(&signature.to_bytes()); +} + +#[cfg(test)] +mod tests { + use super::*; + use sha2::{Digest, Sha256}; + + #[test] + fn test_rust_p256_pubkey() { + // Same in Python: + // import ecdsa + // privkey = bytes.fromhex("503e32eeb9cab8673f7847c047fa57ad2be0485d0759948413cc8c002b529fe4") + // ecdsa.SigningKey.from_string(privkey, curve=ecdsa.curves.NIST256p).verifying_key.to_string().hex() + + let privkey = b"\x50\x3e\x32\xee\xb9\xca\xb8\x67\x3f\x78\x47\xc0\x47\xfa\x57\xad\x2b\xe0\x48\x5d\x07\x59\x94\x84\x13\xcc\x8c\x00\x2b\x52\x9f\xe4"; + let mut pubkey = [0u8; 64]; + rust_p256_pubkey( + crate::util::rust_util_bytes(privkey.as_ptr(), privkey.len()), + unsafe { crate::util::rust_util_bytes_mut(pubkey.as_mut_ptr(), pubkey.len()) }, + ); + } + + #[test] + fn test_rust_p256_sign() { + // Same in Python: + // import ecdsa + // privkey = bytes.fromhex("503e32eeb9cab8673f7847c047fa57ad2be0485d0759948413cc8c002b529fe4") + // sig = bytes.fromhex("5a1f4c00a5104edd39fc8f55863b04a82c662c56448a10c3a35fd4d0decb9d8a8240cbcdd251c6d76d78981b14092c01466c90ad7e1c699f2c5e11523ec6df8c") + // ecdsa.SigningKey.from_string(privkey, curve=ecdsa.curves.NIST256p).verifying_key.verify(sig, b"msg", hashfunc=hashlib.sha256) + + let privkey = b"\x50\x3e\x32\xee\xb9\xca\xb8\x67\x3f\x78\x47\xc0\x47\xfa\x57\xad\x2b\xe0\x48\x5d\x07\x59\x94\x84\x13\xcc\x8c\x00\x2b\x52\x9f\xe4"; + let msg = Sha256::digest(b"msg"); + let mut sig = [0u8; 64]; + rust_p256_sign( + crate::util::rust_util_bytes(privkey.as_ptr(), privkey.len()), + crate::util::rust_util_bytes(msg.as_ptr(), msg.len()), + unsafe { crate::util::rust_util_bytes_mut(sig.as_mut_ptr(), sig.len()) }, + ); + assert_eq!( + hex::encode(sig), + "5a1f4c00a5104edd39fc8f55863b04a82c662c56448a10c3a35fd4d0decb9d8a8240cbcdd251c6d76d78981b14092c01466c90ad7e1c699f2c5e11523ec6df8c", + ); + } +} diff --git a/src/rust/vendor/base16ct/.cargo-checksum.json b/src/rust/vendor/base16ct/.cargo-checksum.json new file mode 100644 index 000000000..e2a9fd372 --- /dev/null +++ b/src/rust/vendor/base16ct/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"4804ca1b5d84da4177354125912a29ca7a9a6a4ebba5b752fcee61911c9fe23f","Cargo.toml":"5050aa1f3351bf8c11a55b9695a41f5ec4652c95d7243c5b45a301692e2782e6","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"0aa8963e105e8b6e02f634484145d4e5b0f42d0a6dd05c16f8148f033383adef","README.md":"535e9fe765cd20cc185be3458871253bca8ded1c2132e6e20ed3706044ddf2e9","benches/mod.rs":"976e6c0443e69a0578a2cf2252c4ed486ff0dc39823d0c369625e31c89941657","src/display.rs":"7042d46254a4fe4c1d66fe41be90916010247fd6dbdf3e87532541aa1a199696","src/error.rs":"8c5ac9c8d2d3b6fe18d8cf56d7e48149fb4d44c32ccb71f566f243c70e9bb187","src/lib.rs":"be52249977ee3d023a22beb0f805ad2d2bd69333cd17a0670c92002e57557ce9","src/lower.rs":"5ed8a602a6fbbe15c01c27a18a579a9df0599cecab7bd0420b26862c62ea91aa","src/mixed.rs":"12fc969194a5bf4776c9f1ccfd208c1abfa9e0abcd265a9b493f0af8382163dc","src/upper.rs":"c75c9b6ef7eddc5e23ef1699b1445ddf729e031a13e328c9e9b181e681daeec1","tests/lib.rs":"1b5ae439670c8c1ca3843922bd484dc642b660d91f401a29fa279d9e01fdab92"},"package":"4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"} \ No newline at end of file diff --git a/src/rust/vendor/base16ct/CHANGELOG.md b/src/rust/vendor/base16ct/CHANGELOG.md new file mode 100644 index 000000000..3c3df348a --- /dev/null +++ b/src/rust/vendor/base16ct/CHANGELOG.md @@ -0,0 +1,22 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.2.0 (2023-02-26) +### Changed +- MSRV 1.60 ([#802]) +- Lint improvements ([#824]) + +[#802]: https://github.com/RustCrypto/formats/pull/802 +[#824]: https://github.com/RustCrypto/formats/pull/824 + +## 0.1.1 (2022-01-15) +### Added +- `HexDisplay` type ([#329]) + +[#329]: https://github.com/RustCrypto/formats/pull/329 + +## 0.1.0 (2022-01-12) +- Initial release diff --git a/src/rust/vendor/base16ct/Cargo.toml b/src/rust/vendor/base16ct/Cargo.toml new file mode 100644 index 000000000..872816d76 --- /dev/null +++ b/src/rust/vendor/base16ct/Cargo.toml @@ -0,0 +1,48 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.60" +name = "base16ct" +version = "0.2.0" +authors = ["RustCrypto Developers"] +description = """ +Pure Rust implementation of Base16 a.k.a hexadecimal (RFC 4648) which avoids +any usages of data-dependent branches/LUTs and thereby provides portable +\"best effort\" constant-time operation and embedded-friendly no_std support +""" +documentation = "https://docs.rs/base16ct" +readme = "README.md" +keywords = [ + "crypto", + "hex", + "hexadecimal", +] +categories = [ + "cryptography", + "encoding", + "no-std", + "parser-implementations", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/RustCrypto/formats/tree/master/base16ct" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[features] +alloc = [] +std = ["alloc"] diff --git a/src/rust/vendor/base16ct/LICENSE-APACHE b/src/rust/vendor/base16ct/LICENSE-APACHE new file mode 100644 index 000000000..78173fa2e --- /dev/null +++ b/src/rust/vendor/base16ct/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/base16ct/LICENSE-MIT b/src/rust/vendor/base16ct/LICENSE-MIT new file mode 100644 index 000000000..f151c9982 --- /dev/null +++ b/src/rust/vendor/base16ct/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) +Copyright (c) 2022 The RustCrypto Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/base16ct/README.md b/src/rust/vendor/base16ct/README.md new file mode 100644 index 000000000..837c15618 --- /dev/null +++ b/src/rust/vendor/base16ct/README.md @@ -0,0 +1,60 @@ +# [RustCrypto]: Constant-Time Base16 (hexadecimal) + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +[![Build Status][build-image]][build-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Project Chat][chat-image]][chat-link] + +Pure Rust implementation of Base16 ([RFC 4648]). + +Implements lower and upper case Base16 variants without data-dependent branches +or lookup tables, thereby providing portable "best effort" constant-time +operation. + +Supports `no_std` environments and avoids heap allocations in the core API +(but also provides optional `alloc` support for convenience). + +[Documentation][docs-link] + +## Minimum Supported Rust Version + +This crate requires **Rust 1.60** at a minimum. + +We may change the MSRV in the future, but it will be accompanied by a minor +version bump. + +## License + +Licensed under either of: + + * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + * [MIT license](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. + +[//]: # (badges) + +[crate-image]: https://buildstats.info/crate/base16ct +[crate-link]: https://crates.io/crates/base16ct +[docs-image]: https://docs.rs/base16ct/badge.svg +[docs-link]: https://docs.rs/base16ct/ +[build-image]: https://github.com/RustCrypto/formats/actions/workflows/base16ct.yml/badge.svg +[build-link]: https://github.com/RustCrypto/formats/actions/workflows/base16ct.yml +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.60+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/300570-formats + +[//]: # (links) + +[RustCrypto]: https://github.com/rustcrypto +[RFC 4648]: https://tools.ietf.org/html/rfc4648 +[Util::Lookup]: https://arxiv.org/pdf/2108.04600.pdf diff --git a/src/rust/vendor/base16ct/benches/mod.rs b/src/rust/vendor/base16ct/benches/mod.rs new file mode 100644 index 000000000..75af0c9db --- /dev/null +++ b/src/rust/vendor/base16ct/benches/mod.rs @@ -0,0 +1,69 @@ +#![feature(test)] +extern crate test; + +use test::{black_box, Bencher}; + +#[bench] +fn decode_lower(b: &mut Bencher) { + let input = vec![b'1'; 1 << 14]; + let mut buf = vec![0u8; 1 << 13]; + + b.iter(|| { + let input = black_box(&input[..]); + let res = base16ct::lower::decode(input, &mut buf).unwrap(); + black_box(res); + }); + b.bytes = input.len() as u64; +} + +#[bench] +fn decode_upper(b: &mut Bencher) { + let input = vec![b'1'; 1 << 14]; + let mut buf = vec![0u8; 1 << 13]; + + b.iter(|| { + let input = black_box(&input[..]); + let res = base16ct::upper::decode(input, &mut buf).unwrap(); + black_box(res); + }); + b.bytes = input.len() as u64; +} + +#[bench] +fn decode_mixed(b: &mut Bencher) { + let input = vec![b'1'; 1 << 14]; + let mut buf = vec![0u8; 1 << 13]; + + b.iter(|| { + let input = black_box(&input[..]); + let res = base16ct::mixed::decode(input, &mut buf).unwrap(); + black_box(res); + }); + b.bytes = input.len() as u64; +} + +#[bench] +fn encode_lower(b: &mut Bencher) { + let input = vec![0x42; 1 << 14]; + let mut buf = vec![0u8; 1 << 15]; + + b.iter(|| { + let input = black_box(&input[..]); + let res = base16ct::lower::encode(input, &mut buf).unwrap(); + black_box(res); + }); + b.bytes = input.len() as u64; +} + +#[bench] +fn encode_upper(b: &mut Bencher) { + let input = vec![0x42; 1 << 14]; + let mut buf = vec![0u8; 1 << 15]; + + b.iter(|| { + let input = black_box(&input[..]); + let res = base16ct::upper::encode(input, &mut buf).unwrap(); + black_box(res); + }); + b.bytes = input.len() as u64; +} diff --git a/src/rust/vendor/base16ct/src/display.rs b/src/rust/vendor/base16ct/src/display.rs new file mode 100644 index 000000000..1397a91dd --- /dev/null +++ b/src/rust/vendor/base16ct/src/display.rs @@ -0,0 +1,35 @@ +use core::fmt; + +/// `core::fmt` presenter for binary data encoded as hexadecimal (Base16). +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct HexDisplay<'a>(pub &'a [u8]); + +impl fmt::Display for HexDisplay<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:X}", self) + } +} + +impl fmt::UpperHex for HexDisplay<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut hex = [0u8; 2]; + + for &byte in self.0 { + f.write_str(crate::upper::encode_str(&[byte], &mut hex)?)?; + } + + Ok(()) + } +} + +impl fmt::LowerHex for HexDisplay<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut hex = [0u8; 2]; + + for &byte in self.0 { + f.write_str(crate::lower::encode_str(&[byte], &mut hex)?)?; + } + + Ok(()) + } +} diff --git a/src/rust/vendor/base16ct/src/error.rs b/src/rust/vendor/base16ct/src/error.rs new file mode 100644 index 000000000..a5f99c2ea --- /dev/null +++ b/src/rust/vendor/base16ct/src/error.rs @@ -0,0 +1,32 @@ +use core::fmt; + +/// Result type with the `base16ct` crate's [`Error`] type. +pub type Result = core::result::Result; + +/// Error type +#[derive(Clone, Eq, PartialEq, Debug)] +pub enum Error { + /// Invalid encoding of provided Base16 string. + InvalidEncoding, + + /// Insufficient output buffer length. + InvalidLength, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::InvalidEncoding => f.write_str("invalid Base16 encoding"), + Error::InvalidLength => f.write_str("invalid Base16 length"), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for Error {} + +impl From for core::fmt::Error { + fn from(_: Error) -> core::fmt::Error { + core::fmt::Error::default() + } +} diff --git a/src/rust/vendor/base16ct/src/lib.rs b/src/rust/vendor/base16ct/src/lib.rs new file mode 100644 index 000000000..435c50134 --- /dev/null +++ b/src/rust/vendor/base16ct/src/lib.rs @@ -0,0 +1,124 @@ +#![no_std] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" +)] +#![warn( + clippy::mod_module_files, + clippy::unwrap_used, + missing_docs, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] + +//! Pure Rust implementation of Base16 ([RFC 4648], a.k.a. hex). +//! +//! Implements lower and upper case Base16 variants without data-dependent branches +//! or lookup tables, thereby providing portable "best effort" constant-time +//! operation. Not constant-time with respect to message length (only data). +//! +//! Supports `no_std` environments and avoids heap allocations in the core API +//! (but also provides optional `alloc` support for convenience). +//! +//! Based on code from: +//! +//! # Examples +//! ``` +//! let lower_hex_str = "abcd1234"; +//! let upper_hex_str = "ABCD1234"; +//! let mixed_hex_str = "abCD1234"; +//! let raw = b"\xab\xcd\x12\x34"; +//! +//! let mut buf = [0u8; 16]; +//! // length of return slice can be different from the input buffer! +//! let res = base16ct::lower::decode(lower_hex_str, &mut buf).unwrap(); +//! assert_eq!(res, raw); +//! let res = base16ct::lower::encode(raw, &mut buf).unwrap(); +//! assert_eq!(res, lower_hex_str.as_bytes()); +//! // you also can use `encode_str` and `encode_string` to get +//! // `&str` and `String` respectively +//! let res: &str = base16ct::lower::encode_str(raw, &mut buf).unwrap(); +//! assert_eq!(res, lower_hex_str); +//! +//! let res = base16ct::upper::decode(upper_hex_str, &mut buf).unwrap(); +//! assert_eq!(res, raw); +//! let res = base16ct::upper::encode(raw, &mut buf).unwrap(); +//! assert_eq!(res, upper_hex_str.as_bytes()); +//! +//! // In cases when you don't know if input contains upper or lower +//! // hex-encoded value, then use functions from the `mixed` module +//! let res = base16ct::mixed::decode(lower_hex_str, &mut buf).unwrap(); +//! assert_eq!(res, raw); +//! let res = base16ct::mixed::decode(upper_hex_str, &mut buf).unwrap(); +//! assert_eq!(res, raw); +//! let res = base16ct::mixed::decode(mixed_hex_str, &mut buf).unwrap(); +//! assert_eq!(res, raw); +//! ``` +//! +//! [RFC 4648]: https://tools.ietf.org/html/rfc4648 + +#[cfg(feature = "alloc")] +#[macro_use] +extern crate alloc; +#[cfg(feature = "std")] +extern crate std; + +/// Function for decoding and encoding lower Base16 (hex) +pub mod lower; +/// Function for decoding mixed Base16 (hex) +pub mod mixed; +/// Function for decoding and encoding upper Base16 (hex) +pub mod upper; + +/// Display formatter for hex. +mod display; +/// Error types. +mod error; + +pub use crate::{ + display::HexDisplay, + error::{Error, Result}, +}; + +#[cfg(feature = "alloc")] +use alloc::{string::String, vec::Vec}; + +/// Compute decoded length of the given hex-encoded input. +#[inline(always)] +pub fn decoded_len(bytes: &[u8]) -> Result { + if bytes.len() & 1 == 0 { + Ok(bytes.len() / 2) + } else { + Err(Error::InvalidLength) + } +} + +/// Get the length of Base16 (hex) produced by encoding the given bytes. +#[inline(always)] +pub fn encoded_len(bytes: &[u8]) -> usize { + bytes.len() * 2 +} + +fn decode_inner<'a>( + src: &[u8], + dst: &'a mut [u8], + decode_nibble: impl Fn(u8) -> u16, +) -> Result<&'a [u8]> { + let dst = dst + .get_mut(..decoded_len(src)?) + .ok_or(Error::InvalidLength)?; + + let mut err: u16 = 0; + for (src, dst) in src.chunks_exact(2).zip(dst.iter_mut()) { + let byte = (decode_nibble(src[0]) << 4) | decode_nibble(src[1]); + err |= byte >> 8; + *dst = byte as u8; + } + + match err { + 0 => Ok(dst), + _ => Err(Error::InvalidEncoding), + } +} diff --git a/src/rust/vendor/base16ct/src/lower.rs b/src/rust/vendor/base16ct/src/lower.rs new file mode 100644 index 000000000..63aa74db3 --- /dev/null +++ b/src/rust/vendor/base16ct/src/lower.rs @@ -0,0 +1,78 @@ +use crate::{decode_inner, encoded_len, Error}; +#[cfg(feature = "alloc")] +use crate::{decoded_len, String, Vec}; + +/// Decode a lower Base16 (hex) string into the provided destination buffer. +pub fn decode(src: impl AsRef<[u8]>, dst: &mut [u8]) -> Result<&[u8], Error> { + decode_inner(src.as_ref(), dst, decode_nibble) +} + +/// Decode a lower Base16 (hex) string into a byte vector. +#[cfg(feature = "alloc")] +pub fn decode_vec(input: impl AsRef<[u8]>) -> Result, Error> { + let mut output = vec![0u8; decoded_len(input.as_ref())?]; + decode(input, &mut output)?; + Ok(output) +} + +/// Encode the input byte slice as lower Base16. +/// +/// Writes the result into the provided destination slice, returning an +/// ASCII-encoded lower Base16 (hex) string value. +pub fn encode<'a>(src: &[u8], dst: &'a mut [u8]) -> Result<&'a [u8], Error> { + let dst = dst + .get_mut(..encoded_len(src)) + .ok_or(Error::InvalidLength)?; + for (src, dst) in src.iter().zip(dst.chunks_exact_mut(2)) { + dst[0] = encode_nibble(src >> 4); + dst[1] = encode_nibble(src & 0x0f); + } + Ok(dst) +} + +/// Encode input byte slice into a [`&str`] containing lower Base16 (hex). +pub fn encode_str<'a>(src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, Error> { + encode(src, dst).map(|r| unsafe { core::str::from_utf8_unchecked(r) }) +} + +/// Encode input byte slice into a [`String`] containing lower Base16 (hex). +/// +/// # Panics +/// If `input` length is greater than `usize::MAX/2`. +#[cfg(feature = "alloc")] +pub fn encode_string(input: &[u8]) -> String { + let elen = encoded_len(input); + let mut dst = vec![0u8; elen]; + let res = encode(input, &mut dst).expect("dst length is correct"); + + debug_assert_eq!(elen, res.len()); + unsafe { String::from_utf8_unchecked(dst) } +} + +/// Decode a single nibble of lower hex +#[inline(always)] +fn decode_nibble(src: u8) -> u16 { + // 0-9 0x30-0x39 + // A-F 0x41-0x46 or a-f 0x61-0x66 + let byte = src as i16; + let mut ret: i16 = -1; + + // 0-9 0x30-0x39 + // if (byte > 0x2f && byte < 0x3a) ret += byte - 0x30 + 1; // -47 + ret += (((0x2fi16 - byte) & (byte - 0x3a)) >> 8) & (byte - 47); + // a-f 0x61-0x66 + // if (byte > 0x60 && byte < 0x67) ret += byte - 0x61 + 10 + 1; // -86 + ret += (((0x60i16 - byte) & (byte - 0x67)) >> 8) & (byte - 86); + + ret as u16 +} + +/// Encode a single nibble of hex +#[inline(always)] +fn encode_nibble(src: u8) -> u8 { + let mut ret = src as i16 + 0x30; + // 0-9 0x30-0x39 + // a-f 0x61-0x66 + ret += ((0x39i16 - ret) >> 8) & (0x61i16 - 0x3a); + ret as u8 +} diff --git a/src/rust/vendor/base16ct/src/mixed.rs b/src/rust/vendor/base16ct/src/mixed.rs new file mode 100644 index 000000000..0836d3ae4 --- /dev/null +++ b/src/rust/vendor/base16ct/src/mixed.rs @@ -0,0 +1,37 @@ +use crate::{decode_inner, Error}; +#[cfg(feature = "alloc")] +use crate::{decoded_len, Vec}; + +/// Decode a mixed Base16 (hex) string into the provided destination buffer. +pub fn decode(src: impl AsRef<[u8]>, dst: &mut [u8]) -> Result<&[u8], Error> { + decode_inner(src.as_ref(), dst, decode_nibble) +} + +/// Decode a mixed Base16 (hex) string into a byte vector. +#[cfg(feature = "alloc")] +pub fn decode_vec(input: impl AsRef<[u8]>) -> Result, Error> { + let mut output = vec![0u8; decoded_len(input.as_ref())?]; + decode(input, &mut output)?; + Ok(output) +} + +/// Decode a single nibble of lower hex +#[inline(always)] +fn decode_nibble(src: u8) -> u16 { + // 0-9 0x30-0x39 + // A-F 0x41-0x46 or a-f 0x61-0x66 + let byte = src as i16; + let mut ret: i16 = -1; + + // 0-9 0x30-0x39 + // if (byte > 0x2f && byte < 0x3a) ret += byte - 0x30 + 1; // -47 + ret += (((0x2fi16 - byte) & (byte - 0x3a)) >> 8) & (byte - 47); + // A-F 0x41-0x46 + // if (byte > 0x40 && byte < 0x47) ret += byte - 0x41 + 10 + 1; // -54 + ret += (((0x40i16 - byte) & (byte - 0x47)) >> 8) & (byte - 54); + // a-f 0x61-0x66 + // if (byte > 0x60 && byte < 0x67) ret += byte - 0x61 + 10 + 1; // -86 + ret += (((0x60i16 - byte) & (byte - 0x67)) >> 8) & (byte - 86); + + ret as u16 +} diff --git a/src/rust/vendor/base16ct/src/upper.rs b/src/rust/vendor/base16ct/src/upper.rs new file mode 100644 index 000000000..a747f297c --- /dev/null +++ b/src/rust/vendor/base16ct/src/upper.rs @@ -0,0 +1,78 @@ +use crate::{decode_inner, encoded_len, Error}; +#[cfg(feature = "alloc")] +use crate::{decoded_len, String, Vec}; + +/// Decode an upper Base16 (hex) string into the provided destination buffer. +pub fn decode(src: impl AsRef<[u8]>, dst: &mut [u8]) -> Result<&[u8], Error> { + decode_inner(src.as_ref(), dst, decode_nibble) +} + +/// Decode an upper Base16 (hex) string into a byte vector. +#[cfg(feature = "alloc")] +pub fn decode_vec(input: impl AsRef<[u8]>) -> Result, Error> { + let mut output = vec![0u8; decoded_len(input.as_ref())?]; + decode(input, &mut output)?; + Ok(output) +} + +/// Encode the input byte slice as upper Base16. +/// +/// Writes the result into the provided destination slice, returning an +/// ASCII-encoded upper Base16 (hex) string value. +pub fn encode<'a>(src: &[u8], dst: &'a mut [u8]) -> Result<&'a [u8], Error> { + let dst = dst + .get_mut(..encoded_len(src)) + .ok_or(Error::InvalidLength)?; + for (src, dst) in src.iter().zip(dst.chunks_exact_mut(2)) { + dst[0] = encode_nibble(src >> 4); + dst[1] = encode_nibble(src & 0x0f); + } + Ok(dst) +} + +/// Encode input byte slice into a [`&str`] containing upper Base16 (hex). +pub fn encode_str<'a>(src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, Error> { + encode(src, dst).map(|r| unsafe { core::str::from_utf8_unchecked(r) }) +} + +/// Encode input byte slice into a [`String`] containing upper Base16 (hex). +/// +/// # Panics +/// If `input` length is greater than `usize::MAX/2`. +#[cfg(feature = "alloc")] +pub fn encode_string(input: &[u8]) -> String { + let elen = encoded_len(input); + let mut dst = vec![0u8; elen]; + let res = encode(input, &mut dst).expect("dst length is correct"); + + debug_assert_eq!(elen, res.len()); + unsafe { crate::String::from_utf8_unchecked(dst) } +} + +/// Decode a single nibble of upper hex +#[inline(always)] +fn decode_nibble(src: u8) -> u16 { + // 0-9 0x30-0x39 + // A-F 0x41-0x46 or a-f 0x61-0x66 + let byte = src as i16; + let mut ret: i16 = -1; + + // 0-9 0x30-0x39 + // if (byte > 0x2f && byte < 0x3a) ret += byte - 0x30 + 1; // -47 + ret += (((0x2fi16 - byte) & (byte - 0x3a)) >> 8) & (byte - 47); + // A-F 0x41-0x46 + // if (byte > 0x40 && byte < 0x47) ret += byte - 0x41 + 10 + 1; // -54 + ret += (((0x40i16 - byte) & (byte - 0x47)) >> 8) & (byte - 54); + + ret as u16 +} + +/// Encode a single nibble of hex +#[inline(always)] +fn encode_nibble(src: u8) -> u8 { + let mut ret = src as i16 + 0x30; + // 0-9 0x30-0x39 + // A-F 0x41-0x46 + ret += ((0x39i16 - ret) >> 8) & (0x41i16 - 0x3a); + ret as u8 +} diff --git a/src/rust/vendor/base16ct/tests/lib.rs b/src/rust/vendor/base16ct/tests/lib.rs new file mode 100644 index 000000000..eef1b5b84 --- /dev/null +++ b/src/rust/vendor/base16ct/tests/lib.rs @@ -0,0 +1,163 @@ +//! Integration tests. + +/// Hexadecimal test vectors +struct HexVector { + /// Raw bytes + raw: &'static [u8], + /// Lower hex encoded + lower_hex: &'static [u8], + /// Upper hex encoded + upper_hex: &'static [u8], +} + +const HEX_TEST_VECTORS: &[HexVector] = &[ + HexVector { + raw: b"", + lower_hex: b"", + upper_hex: b"", + }, + HexVector { + raw: b"\0", + lower_hex: b"00", + upper_hex: b"00", + }, + HexVector { + raw: b"***", + lower_hex: b"2a2a2a", + upper_hex: b"2A2A2A", + }, + HexVector { + raw: b"\x01\x02\x03\x04", + lower_hex: b"01020304", + upper_hex: b"01020304", + }, + HexVector { + raw: b"\xAD\xAD\xAD\xAD\xAD", + lower_hex: b"adadadadad", + upper_hex: b"ADADADADAD", + }, + HexVector { + raw: b"\xFF\xFF\xFF\xFF\xFF", + lower_hex: b"ffffffffff", + upper_hex: b"FFFFFFFFFF", + }, +]; + +#[test] +fn lower_encode() { + for vector in HEX_TEST_VECTORS { + // 10 is the size of the largest encoded test vector + let mut buf = [0u8; 10]; + let out = base16ct::lower::encode(vector.raw, &mut buf).unwrap(); + assert_eq!(vector.lower_hex, out); + } +} + +#[test] +fn lower_decode() { + for vector in HEX_TEST_VECTORS { + // 5 is the size of the largest decoded test vector + let mut buf = [0u8; 5]; + let out = base16ct::lower::decode(vector.lower_hex, &mut buf).unwrap(); + assert_eq!(vector.raw, out); + } +} + +#[test] +fn lower_reject_odd_size_input() { + let mut out = [0u8; 3]; + assert_eq!( + Err(base16ct::Error::InvalidLength), + base16ct::lower::decode(b"12345", &mut out), + ) +} + +#[test] +fn upper_encode() { + for vector in HEX_TEST_VECTORS { + // 10 is the size of the largest encoded test vector + let mut buf = [0u8; 10]; + let out = base16ct::upper::encode(vector.raw, &mut buf).unwrap(); + assert_eq!(vector.upper_hex, out); + } +} + +#[test] +fn upper_decode() { + for vector in HEX_TEST_VECTORS { + // 5 is the size of the largest decoded test vector + let mut buf = [0u8; 5]; + let out = base16ct::upper::decode(vector.upper_hex, &mut buf).unwrap(); + assert_eq!(vector.raw, out); + } +} + +#[test] +fn upper_reject_odd_size_input() { + let mut out = [0u8; 3]; + assert_eq!( + Err(base16ct::Error::InvalidLength), + base16ct::upper::decode(b"12345", &mut out), + ) +} + +#[test] +fn mixed_decode() { + for vector in HEX_TEST_VECTORS { + // 5 is the size of the largest decoded test vector + let mut buf = [0u8; 5]; + let out = base16ct::mixed::decode(vector.upper_hex, &mut buf).unwrap(); + assert_eq!(vector.raw, out); + let out = base16ct::mixed::decode(vector.lower_hex, &mut buf).unwrap(); + assert_eq!(vector.raw, out); + } +} + +#[test] +fn mixed_reject_odd_size_input() { + let mut out = [0u8; 3]; + assert_eq!( + Err(base16ct::Error::InvalidLength), + base16ct::mixed::decode(b"12345", &mut out), + ) +} + +#[test] +#[cfg(feature = "alloc")] +fn encode_and_decode_various_lengths() { + let data = [b'X'; 64]; + + for i in 0..data.len() { + let encoded = base16ct::lower::encode_string(&data[..i]); + let decoded = base16ct::lower::decode_vec(encoded).unwrap(); + assert_eq!(decoded.as_slice(), &data[..i]); + + let encoded = base16ct::upper::encode_string(&data[..i]); + let decoded = base16ct::upper::decode_vec(encoded).unwrap(); + assert_eq!(decoded.as_slice(), &data[..i]); + + let encoded = base16ct::lower::encode_string(&data[..i]); + let decoded = base16ct::mixed::decode_vec(encoded).unwrap(); + assert_eq!(decoded.as_slice(), &data[..i]); + + let encoded = base16ct::upper::encode_string(&data[..i]); + let decoded = base16ct::mixed::decode_vec(encoded).unwrap(); + assert_eq!(decoded.as_slice(), &data[..i]); + } +} + +#[test] +fn hex_display_upper() { + for vector in HEX_TEST_VECTORS { + let hex = format!("{:X}", base16ct::HexDisplay(vector.raw)); + assert_eq!(hex.as_bytes(), vector.upper_hex); + } +} + +#[test] +fn hex_display_lower() { + for vector in HEX_TEST_VECTORS { + let hex = format!("{:x}", base16ct::HexDisplay(vector.raw)); + assert_eq!(hex.as_bytes(), vector.lower_hex); + } +} diff --git a/src/rust/vendor/const-oid/.cargo-checksum.json b/src/rust/vendor/const-oid/.cargo-checksum.json new file mode 100644 index 000000000..722de3835 --- /dev/null +++ b/src/rust/vendor/const-oid/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"803e097b5076f9f1131fccdb4a43ee7905b6252236e4751a161c4bd430faf349","Cargo.toml":"c646206dd9067b48ca550efcedd9eed7fd2ed230e7d05757a569bbe18f01081c","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"bada9e7ed8dc00d63502053c455d7c8d7575dfb7e8277a2a832531844d900682","README.md":"4a5cdde312d22ca0e6f8c6d4786af313e2a34c06fb572b7ccaef2f1ad19d781d","src/arcs.rs":"997f319f8ff5a3ffc448900993f2bf056c05f1092d48a6a592760bf261468e3d","src/checked.rs":"c3de8e43c638de4766550accb1b73cc7f37765f1779d3e572bfbd908bdb1003f","src/db.rs":"75567c122e9f236b02dcaad1b266efcffa452206877c35e2d343aa8eb3b53fad","src/db/gen.rs":"d80825bd0a307979354f522a1cd9ff4d7f83a65833792fdfb56e5f90acf4500d","src/encoder.rs":"cd799ff208a8a7a7a128c422ad3a5535e6ee6b800ad5e7087da55e27e23e84b3","src/error.rs":"0101b991fe689fd2b20c3144e3cfcca3a6628c6892f1ced4c2ba84d6788d72c9","src/lib.rs":"7476a1feb706595867f6e01e16113e167e03420344708c1a0b3a455549c5f82c","src/parser.rs":"9fe5c4114dad22631e63fd1afa832b2c0ed3b4b28f04587dd2148956ced98768","tests/lib.rs":"d7881ad1388e4c907d5392429927d299042dbd5eaaacfd27cef9e1d692fd5aee"},"package":"c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"} \ No newline at end of file diff --git a/src/rust/vendor/const-oid/CHANGELOG.md b/src/rust/vendor/const-oid/CHANGELOG.md new file mode 100644 index 000000000..f47c0c413 --- /dev/null +++ b/src/rust/vendor/const-oid/CHANGELOG.md @@ -0,0 +1,197 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.9.6 (2023-12-14) +### Added +- RFC 6962 OID ([#1282]) + +[#1282]: https://github.com/RustCrypto/formats/pull/1282 + +## 0.9.5 (2023-08-02) +### Added +- rfc8410 (curve25519) OIDS. ([#867]) + +[#867]: https://github.com/RustCrypto/formats/pull/867 + +## 0.9.4 (2023-07-10) +### Added +- rfc8894 (SCEP) OIDs. ([#1114]) + +[#1114]: https://github.com/RustCrypto/formats/pull/1114 + +## 0.9.3 (2023-06-29) +### Added +- `Database::find_names_for_oid` ([#1129]) + +[#1129]: https://github.com/RustCrypto/formats/pull/1129 + +## 0.9.2 (2023-02-26) +### Added +- Implement `Arbitrary` trait ([#761]) + +[#761]: https://github.com/RustCrypto/formats/pull/761 + +## 0.9.1 (2022-11-12) +### Added +- clippy lints for checked arithmetic and panics ([#561]) +- `DynAssociatedOid` trait ([#758]) + +[#561]: https://github.com/RustCrypto/formats/pull/561 +[#758]: https://github.com/RustCrypto/formats/pull/758 + +## 0.9.0 (2022-03-11) +### Added +- Fallible `const fn` parser + `::new_unwrap` ([#458], [#459]) +- OID database gated under the `db` feature ([#451], [#453], [#456], [#488]) +- `AssociatedOid` trait ([#479]) +- `ObjectIdentifier::push_arc` ([#504]) +- `ObjectIdentifier::parent` ([#505]) + +### Changed +- `ObjectIdentifier::new` now returns a `Result` ([#458]) + +[#451]: https://github.com/RustCrypto/formats/pull/451 +[#453]: https://github.com/RustCrypto/formats/pull/453 +[#456]: https://github.com/RustCrypto/formats/pull/456 +[#458]: https://github.com/RustCrypto/formats/pull/458 +[#459]: https://github.com/RustCrypto/formats/pull/459 +[#479]: https://github.com/RustCrypto/formats/pull/479 +[#488]: https://github.com/RustCrypto/formats/pull/488 +[#504]: https://github.com/RustCrypto/formats/pull/504 +[#505]: https://github.com/RustCrypto/formats/pull/505 + +## 0.8.0 (2022-01-17) +### Changed +- Leverage `const_panic`; MSRV 1.57 ([#341]) + +[#341]: https://github.com/RustCrypto/formats/pull/341 + +## 0.7.1 (2021-11-30) +### Changed +- Increase `MAX_SIZE` to 39 ([#258]) + +[#258]: https://github.com/RustCrypto/formats/pull/258 + +## 0.7.0 (2021-11-14) [YANKED] +### Changed +- Rust 2021 edition upgrade; MSRV 1.56 ([#136]) +- Rename `MAX_LENGTH` to `MAX_SIZE`; bump to `31` ([#174]) +- Make `length` the first field of `ObjectIdentifier` ([#178]) + +### Fixed +- `debug_assert!` false positive on large arc ([#180]) + +[#136]: https://github.com/RustCrypto/formats/pull/136 +[#174]: https://github.com/RustCrypto/formats/pull/174 +[#178]: https://github.com/RustCrypto/formats/pull/178 +[#180]: https://github.com/RustCrypto/formats/pull/180 + +## 0.6.2 (2021-10-14) +### Fixed +- Off-by-one error parsing large BER arcs ([#84]) + +[#84]: https://github.com/RustCrypto/formats/pull/84 + +## 0.6.1 (2021-09-14) [YANKED] +### Changed +- Moved to `formats` repo ([#2]) + +[#2]: https://github.com/RustCrypto/formats/pull/2 + +## 0.6.0 (2021-06-03) [YANKED] +### Changed +- Modernize and remove deprecations; MSRV 1.51+ + +## 0.5.2 (2021-04-20) +### Added +- Expand README.md + +## 0.5.1 (2021-04-15) +### Added +- `ObjectIdentifier::MAX_LENGTH` constant + +### Changed +- Deprecate `ObjectIdentifier::max_len()` function + +## 0.5.0 (2021-03-21) +### Added +- `TryFrom<&[u8]>` impl on `ObjectIdentifier` + +## Changed +- MSRV 1.47+ +- Renamed the following methods: + - `ObjectIdentifier::new` => `ObjectIdentifier::from_arcs` + - `ObjectIdentifier::parse` => `ObjectIdentifier::new` + - `ObjectIdentifier::from_ber` => `ObjectIdentifier::from_bytes` + +### Removed +- Deprecated methods +- `alloc` feature - only used by aforementioned deprecated methods +- `TryFrom<&[Arc]>` impl on `ObjectIdentifier` - use `::from_arcs` + +## 0.4.5 (2021-03-04) +### Added +- `Hash` and `Ord` impls on `ObjectIdentifier` + +## 0.4.4 (2021-02-28) +### Added +- `ObjectIdentifier::as_bytes` method + +### Changed +- Internal representation changed to BER/DER +- Deprecated `ObjectIdentifier::ber_len`, `::write_ber`, and `::to_ber` + +## 0.4.3 (2021-02-24) +### Added +- Const-friendly OID string parser + +## 0.4.2 (2021-02-19) +### Fixed +- Bug in root arc calculation + +## 0.4.1 (2020-12-21) +### Fixed +- Bug in const initializer + +## 0.4.0 (2020-12-16) +### Added +- `Arcs` iterator + +### Changed +- Rename "nodes" to "arcs" +- Layout optimization +- Refactor and improve length limits + +## 0.3.5 (2020-12-12) +### Added +- `ObjectIdentifier::{write_ber, to_ber}` methods + +## 0.3.4 (2020-12-06) +### Changed +- Documentation improvements + +## 0.3.3 (2020-12-05) +### Changed +- Improve description in Cargo.toml/README.md + +## 0.3.2 (2020-12-05) +### Changed +- Documentation improvements + +## 0.3.1 (2020-12-05) +### Added +- Impl `TryFrom<&[u32]>` for ObjectIdentifier + +## 0.3.0 (2020-12-05) [YANKED] +### Added +- Byte and string parsers + +## 0.2.0 (2020-09-05) +### Changed +- Validate OIDs are well-formed; MSRV 1.46+ + +## 0.1.0 (2020-08-04) +- Initial release diff --git a/src/rust/vendor/const-oid/Cargo.toml b/src/rust/vendor/const-oid/Cargo.toml new file mode 100644 index 000000000..cc58c4ccb --- /dev/null +++ b/src/rust/vendor/const-oid/Cargo.toml @@ -0,0 +1,58 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.57" +name = "const-oid" +version = "0.9.6" +authors = ["RustCrypto Developers"] +description = """ +Const-friendly implementation of the ISO/IEC Object Identifier (OID) standard +as defined in ITU X.660, with support for BER/DER encoding/decoding as well as +heapless no_std (i.e. embedded) support +""" +documentation = "https://docs.rs/const-oid" +readme = "README.md" +keywords = [ + "iso", + "iec", + "itu", + "oid", +] +categories = [ + "cryptography", + "data-structures", + "encoding", + "no-std", + "parser-implementations", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/RustCrypto/formats/tree/master/const-oid" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.arbitrary] +version = "1.2" +features = ["derive"] +optional = true + +[dev-dependencies.hex-literal] +version = "0.3" + +[features] +db = [] +std = [] diff --git a/src/rust/vendor/const-oid/LICENSE-APACHE b/src/rust/vendor/const-oid/LICENSE-APACHE new file mode 100644 index 000000000..78173fa2e --- /dev/null +++ b/src/rust/vendor/const-oid/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/const-oid/LICENSE-MIT b/src/rust/vendor/const-oid/LICENSE-MIT new file mode 100644 index 000000000..1b7880915 --- /dev/null +++ b/src/rust/vendor/const-oid/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2020-2022 The RustCrypto Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/const-oid/README.md b/src/rust/vendor/const-oid/README.md new file mode 100644 index 000000000..fae3cfc3f --- /dev/null +++ b/src/rust/vendor/const-oid/README.md @@ -0,0 +1,96 @@ +# [RustCrypto]: Object Identifiers (OIDs) + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +[![Build Status][build-image]][build-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Project Chat][chat-image]][chat-link] + +Const-friendly implementation of the ISO/IEC Object Identifier (OID) standard +as defined in ITU [X.660], with support for BER/DER encoding/decoding as well +as heapless `no_std` (i.e. embedded) environments. + +[Documentation][docs-link] + +## About OIDs + +Object Identifiers, a.k.a. OIDs, are an International Telecommunications +Union (ITU) and ISO/IEC standard for naming any object, concept, or "thing" +with a globally unambiguous persistent name. + +The ITU's [X.660] standard provides the OID specification. Every OID is part of +a hierarchical namespace which begins with a *root OID*, which is either the +ITU's root OID (0), the ISO's root OID (1), or the joint ISO/ITU root OID (2). + +The following is an example of an OID, in this case identifying the +`rsaEncryption` algorithm: + +```text +1.2.840.113549.1.1.1 +``` + +For more information, see: + +## Implementation + +This library supports parsing OIDs in const contexts, e.g.: + +```rust +use const_oid::ObjectIdentifier; + +pub const MY_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.1"); +``` + +The OID parser is implemented entirely in terms of `const fn` and without the +use of proc macros. + +Additionally, it also includes a `const fn` OID serializer, and stores the OIDs +parsed from const contexts encoded using the BER/DER serialization +(sans header). + +This allows `ObjectIdentifier` to impl `AsRef<[u8]>` which can be used to +obtain the BER/DER serialization of an OID, even one declared `const`. + +Additionally, it impls `FromStr` and `TryFrom<&[u8]>` and functions just as +well as a runtime OID library. + +## Minimum Supported Rust Version + +This crate requires **Rust 1.57** at a minimum. + +We may change the MSRV in the future, but it will be accompanied by a minor +version bump. + +## License + +Licensed under either of: + +* [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) +* [MIT license](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. + +[//]: # (badges) + +[crate-image]: https://buildstats.info/crate/const-oid +[crate-link]: https://crates.io/crates/const-oid +[docs-image]: https://docs.rs/const-oid/badge.svg +[docs-link]: https://docs.rs/const-oid/ +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.57+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/300570-formats +[build-image]: https://github.com/RustCrypto/formats/workflows/const-oid/badge.svg?branch=master&event=push +[build-link]: https://github.com/RustCrypto/formats/actions + +[//]: # (links) + +[RustCrypto]: https://github.com/rustcrypto +[X.660]: https://www.itu.int/rec/T-REC-X.660 diff --git a/src/rust/vendor/const-oid/src/arcs.rs b/src/rust/vendor/const-oid/src/arcs.rs new file mode 100644 index 000000000..7bf7a9a13 --- /dev/null +++ b/src/rust/vendor/const-oid/src/arcs.rs @@ -0,0 +1,170 @@ +//! Arcs are integer values which exist within an OID's hierarchy. + +use crate::{Error, ObjectIdentifier, Result}; +use core::mem; + +/// Type alias used to represent an "arc" (i.e. integer identifier value). +/// +/// X.660 does not define a maximum size of an arc. +/// +/// The current representation is `u32`, which has been selected as being +/// sufficient to cover the current PKCS/PKIX use cases this library has been +/// used in conjunction with. +/// +/// Future versions may potentially make it larger if a sufficiently important +/// use case is discovered. +pub type Arc = u32; + +/// Maximum value of the first arc in an OID. +pub(crate) const ARC_MAX_FIRST: Arc = 2; + +/// Maximum value of the second arc in an OID. +pub(crate) const ARC_MAX_SECOND: Arc = 39; + +/// Maximum number of bytes supported in an arc. +const ARC_MAX_BYTES: usize = mem::size_of::(); + +/// Maximum value of the last byte in an arc. +const ARC_MAX_LAST_OCTET: u8 = 0b11110000; // Max bytes of leading 1-bits + +/// [`Iterator`] over [`Arc`] values (a.k.a. nodes) in an [`ObjectIdentifier`]. +/// +/// This iterates over all arcs in an OID, including the root. +pub struct Arcs<'a> { + /// OID we're iterating over + oid: &'a ObjectIdentifier, + + /// Current position within the serialized DER bytes of this OID + cursor: Option, +} + +impl<'a> Arcs<'a> { + /// Create a new iterator over the arcs of this OID + pub(crate) fn new(oid: &'a ObjectIdentifier) -> Self { + Self { oid, cursor: None } + } + + /// Try to parse the next arc in this OID. + /// + /// This method is fallible so it can be used as a first pass to determine + /// that the arcs in the OID are well-formed. + pub(crate) fn try_next(&mut self) -> Result> { + match self.cursor { + // Indicates we're on the root OID + None => { + let root = RootArcs::try_from(self.oid.as_bytes()[0])?; + self.cursor = Some(0); + Ok(Some(root.first_arc())) + } + Some(0) => { + let root = RootArcs::try_from(self.oid.as_bytes()[0])?; + self.cursor = Some(1); + Ok(Some(root.second_arc())) + } + Some(offset) => { + let mut result = 0; + let mut arc_bytes = 0; + + loop { + let len = checked_add!(offset, arc_bytes); + + match self.oid.as_bytes().get(len).cloned() { + // The arithmetic below includes advance checks + // against `ARC_MAX_BYTES` and `ARC_MAX_LAST_OCTET` + // which ensure the operations will not overflow. + #[allow(clippy::integer_arithmetic)] + Some(byte) => { + arc_bytes = checked_add!(arc_bytes, 1); + + if (arc_bytes > ARC_MAX_BYTES) && (byte & ARC_MAX_LAST_OCTET != 0) { + return Err(Error::ArcTooBig); + } + + result = result << 7 | (byte & 0b1111111) as Arc; + + if byte & 0b10000000 == 0 { + self.cursor = Some(checked_add!(offset, arc_bytes)); + return Ok(Some(result)); + } + } + None => { + if arc_bytes == 0 { + return Ok(None); + } else { + return Err(Error::Base128); + } + } + } + } + } + } + } +} + +impl<'a> Iterator for Arcs<'a> { + type Item = Arc; + + fn next(&mut self) -> Option { + // ObjectIdentifier constructors should ensure the OID is well-formed + self.try_next().expect("OID malformed") + } +} + +/// Byte containing the first and second arcs of an OID. +/// +/// This is represented this way in order to reduce the overall size of the +/// [`ObjectIdentifier`] struct. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +struct RootArcs(u8); + +impl RootArcs { + /// Create [`RootArcs`] from the first and second arc values represented + /// as `Arc` integers. + pub(crate) const fn new(first_arc: Arc, second_arc: Arc) -> Result { + if first_arc > ARC_MAX_FIRST { + return Err(Error::ArcInvalid { arc: first_arc }); + } + + if second_arc > ARC_MAX_SECOND { + return Err(Error::ArcInvalid { arc: second_arc }); + } + + // The checks above ensure this operation will not overflow + #[allow(clippy::integer_arithmetic)] + let byte = (first_arc * (ARC_MAX_SECOND + 1)) as u8 + second_arc as u8; + + Ok(Self(byte)) + } + + /// Get the value of the first arc + #[allow(clippy::integer_arithmetic)] + pub(crate) const fn first_arc(self) -> Arc { + self.0 as Arc / (ARC_MAX_SECOND + 1) + } + + /// Get the value of the second arc + #[allow(clippy::integer_arithmetic)] + pub(crate) const fn second_arc(self) -> Arc { + self.0 as Arc % (ARC_MAX_SECOND + 1) + } +} + +impl TryFrom for RootArcs { + type Error = Error; + + // Ensured not to overflow by constructor invariants + #[allow(clippy::integer_arithmetic)] + fn try_from(octet: u8) -> Result { + let first = octet as Arc / (ARC_MAX_SECOND + 1); + let second = octet as Arc % (ARC_MAX_SECOND + 1); + let result = Self::new(first, second)?; + debug_assert_eq!(octet, result.0); + Ok(result) + } +} + +impl From for u8 { + fn from(root_arcs: RootArcs) -> u8 { + root_arcs.0 + } +} diff --git a/src/rust/vendor/const-oid/src/checked.rs b/src/rust/vendor/const-oid/src/checked.rs new file mode 100644 index 000000000..7ff16a2a7 --- /dev/null +++ b/src/rust/vendor/const-oid/src/checked.rs @@ -0,0 +1,11 @@ +//! Checked arithmetic helpers. + +/// `const fn`-friendly checked addition helper. +macro_rules! checked_add { + ($a:expr, $b:expr) => { + match $a.checked_add($b) { + Some(n) => n, + None => return Err(Error::Length), + } + }; +} diff --git a/src/rust/vendor/const-oid/src/db.rs b/src/rust/vendor/const-oid/src/db.rs new file mode 100644 index 000000000..e4b7a47b4 --- /dev/null +++ b/src/rust/vendor/const-oid/src/db.rs @@ -0,0 +1,164 @@ +//! OID Names Database +//! +//! The contents of this database are generated from the official IANA +//! [Object Identifier Descriptors] Registry CSV file and from [RFC 5280]. +//! If we are missing values you care about, please contribute a patch to +//! `oiddbgen` (a subcrate in the source code) to generate the values from +//! the relevant standard. +//! +//! [RFC 5280]: https://datatracker.ietf.org/doc/html/rfc5280 +//! [Object Identifier Descriptors]: https://www.iana.org/assignments/ldap-parameters/ldap-parameters.xhtml#ldap-parameters-3 + +#![allow(clippy::integer_arithmetic, missing_docs)] + +mod gen; + +pub use gen::*; + +use crate::{Error, ObjectIdentifier}; + +/// A const implementation of byte equals. +const fn eq(lhs: &[u8], rhs: &[u8]) -> bool { + if lhs.len() != rhs.len() { + return false; + } + + let mut i = 0usize; + while i < lhs.len() { + if lhs[i] != rhs[i] { + return false; + } + + i += 1; + } + + true +} + +/// A const implementation of case-insensitive ASCII equals. +const fn eq_case(lhs: &[u8], rhs: &[u8]) -> bool { + if lhs.len() != rhs.len() { + return false; + } + + let mut i = 0usize; + while i < lhs.len() { + if !lhs[i].eq_ignore_ascii_case(&rhs[i]) { + return false; + } + + i += 1; + } + + true +} + +/// A query interface for OIDs/Names. +#[derive(Copy, Clone)] +pub struct Database<'a>(&'a [(&'a ObjectIdentifier, &'a str)]); + +impl<'a> Database<'a> { + /// Looks up a name for an OID. + /// + /// Errors if the input is not a valid OID. + /// Returns the input if no name is found. + pub fn resolve<'b>(&self, oid: &'b str) -> Result<&'b str, Error> + where + 'a: 'b, + { + Ok(self.by_oid(&oid.parse()?).unwrap_or(oid)) + } + + /// Finds a named oid by its associated OID. + pub const fn by_oid(&self, oid: &ObjectIdentifier) -> Option<&'a str> { + let mut i = 0; + + while i < self.0.len() { + let lhs = self.0[i].0; + if lhs.length == oid.length && eq(&lhs.bytes, &oid.bytes) { + return Some(self.0[i].1); + } + + i += 1; + } + + None + } + + /// Finds a named oid by its associated name. + pub const fn by_name(&self, name: &str) -> Option<&'a ObjectIdentifier> { + let mut i = 0; + + while i < self.0.len() { + let lhs = self.0[i].1; + if eq_case(lhs.as_bytes(), name.as_bytes()) { + return Some(self.0[i].0); + } + + i += 1; + } + + None + } + + /// Return the list of matched name for the OID. + pub const fn find_names_for_oid(&self, oid: ObjectIdentifier) -> Names<'a> { + Names { + database: *self, + oid, + position: 0, + } + } +} + +/// Iterator returning the multiple names that may be associated with an OID. +pub struct Names<'a> { + database: Database<'a>, + oid: ObjectIdentifier, + position: usize, +} + +impl<'a> Iterator for Names<'a> { + type Item = &'a str; + + fn next(&mut self) -> Option<&'a str> { + let mut i = self.position; + + while i < self.database.0.len() { + let lhs = self.database.0[i].0; + + if lhs.as_bytes().eq(self.oid.as_bytes()) { + self.position = i + 1; + return Some(self.database.0[i].1); + } + + i += 1; + } + + None + } +} + +#[cfg(test)] +mod tests { + use crate::ObjectIdentifier; + + use super::rfc4519::CN; + + #[test] + fn by_oid() { + let cn = super::DB.by_oid(&CN).expect("cn not found"); + assert_eq!("cn", cn); + + let none = ObjectIdentifier::new_unwrap("0.1.2.3.4.5.6.7.8.9"); + assert_eq!(None, super::DB.by_oid(&none)); + } + + #[test] + fn by_name() { + let cn = super::DB.by_name("CN").expect("cn not found"); + assert_eq!(&CN, cn); + + assert_eq!(None, super::DB.by_name("purplePeopleEater")); + } +} diff --git a/src/rust/vendor/const-oid/src/db/gen.rs b/src/rust/vendor/const-oid/src/db/gen.rs new file mode 100644 index 000000000..9c603d824 --- /dev/null +++ b/src/rust/vendor/const-oid/src/db/gen.rs @@ -0,0 +1,4248 @@ +#![doc = "!! DO NOT EDIT !!: This file is auto-generated by oiddbgen."] +pub mod rfc1274 { + pub const TEXT_ENCODED_OR_ADDRESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.2"); + pub const OTHER_MAILBOX: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.22"); + pub const LAST_MODIFIED_TIME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.23"); + pub const LAST_MODIFIED_BY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.24"); + pub const A_RECORD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.26"); + pub const MD_RECORD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.27"); + pub const MX_RECORD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.28"); + pub const NS_RECORD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.29"); + pub const SOA_RECORD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.30"); + pub const CNAME_RECORD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.31"); + pub const JANET_MAILBOX: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.46"); + pub const MAIL_PREFERENCE_OPTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.47"); + pub const DSA_QUALITY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.49"); + pub const SUBTREE_MINIMUM_QUALITY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.51"); + pub const SUBTREE_MAXIMUM_QUALITY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.52"); + pub const PERSONAL_SIGNATURE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.53"); + pub const DIT_REDIRECT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.54"); + pub const AUDIO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.55"); + pub const PHOTO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.7"); + pub const DNS_DOMAIN: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.4.15"); + pub const PILOT_ORGANIZATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.4.20"); + pub const PILOT_DSA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.4.21"); + pub const QUALITY_LABELLED_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.4.22"); + pub const PILOT_OBJECT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.4.3"); + pub const PILOT_PERSON: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.4.4"); +} +pub mod rfc2079 { + pub const LABELED_URI: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.250.1.57"); + pub const LABELED_URI_OBJECT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.250.3.15"); +} +pub mod rfc2164 { + pub const RFC_822_TO_X_400_MAPPING: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.453.7.1.1"); + pub const X_400_TO_RFC_822_MAPPING: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.453.7.1.2"); + pub const OMITTED_OR_ADDRESS_COMPONENT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.453.7.1.3"); + pub const MIXER_GATEWAY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.453.7.1.4"); + pub const ASSOCIATED_X_400_GATEWAY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.453.7.2.3"); + pub const ASSOCIATED_OR_ADDRESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.453.7.2.6"); + pub const OR_ADDRESS_COMPONENT_TYPE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.453.7.2.7"); + pub const ASSOCIATED_INTERNET_GATEWAY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.453.7.2.8"); + pub const MCGAM_TABLES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.453.7.2.9"); +} +pub mod rfc2247 { + pub const DOMAIN_NAME_FORM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.1466.345"); +} +pub mod rfc2252 { + pub const PRESENTATION_ADDRESS_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.22"); + pub const PROTOCOL_INFORMATION_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.24"); +} +pub mod rfc2256 { + pub const KNOWLEDGE_INFORMATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.2"); + pub const PRESENTATION_ADDRESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.29"); + pub const SUPPORTED_APPLICATION_CONTEXT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.30"); + pub const PROTOCOL_INFORMATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.48"); + pub const DMD_NAME: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.54"); + pub const STATE_OR_PROVINCE_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.8"); + pub const STREET_ADDRESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.9"); + pub const APPLICATION_ENTITY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.6.12"); + pub const DSA: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.6.13"); + pub const DMD: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.6.20"); +} +pub mod rfc2293 { + pub const SUBTREE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.453.7.1.1"); + pub const TABLE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.453.7.1.2"); + pub const TABLE_ENTRY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.453.7.1.3"); + pub const TEXT_TABLE_ENTRY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.453.7.1.4"); + pub const DISTINGUISHED_NAME_TABLE_ENTRY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.453.7.1.5"); + pub const TEXT_TABLE_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.453.7.2.1"); + pub const TEXT_TABLE_VALUE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.453.7.2.2"); + pub const DISTINGUISHED_NAME_TABLE_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.453.7.2.3"); +} +pub mod rfc2589 { + pub const DYNAMIC_OBJECT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.1466.101.119.2"); + pub const ENTRY_TTL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.1466.101.119.3"); + pub const DYNAMIC_SUBTREES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.1466.101.119.4"); +} +pub mod rfc2739 { + pub const CAL_CAL_URI: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113556.1.4.478"); + pub const CAL_FBURL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113556.1.4.479"); + pub const CAL_CAPURI: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113556.1.4.480"); + pub const CAL_CAL_ADR_URI: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113556.1.4.481"); + pub const CAL_OTHER_CAL_UR_IS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113556.1.4.482"); + pub const CAL_OTHER_FBUR_LS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113556.1.4.483"); + pub const CAL_OTHER_CAPUR_IS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113556.1.4.484"); + pub const CAL_OTHER_CAL_ADR_UR_IS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113556.1.4.485"); + pub const CAL_ENTRY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113556.1.5.87"); +} +pub mod rfc2798 { + pub const JPEG_PHOTO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.60"); + pub const CAR_LICENSE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113730.3.1.1"); + pub const DEPARTMENT_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113730.3.1.2"); + pub const USER_PKCS_12: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113730.3.1.216"); + pub const DISPLAY_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113730.3.1.241"); + pub const EMPLOYEE_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113730.3.1.3"); + pub const PREFERRED_LANGUAGE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113730.3.1.39"); + pub const EMPLOYEE_TYPE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113730.3.1.4"); + pub const USER_SMIME_CERTIFICATE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113730.3.1.40"); + pub const INET_ORG_PERSON: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113730.3.2.2"); +} +pub mod rfc3280 { + pub const EMAIL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.1"); + pub const EMAIL_ADDRESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.1"); + pub const PSEUDONYM: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.65"); +} +pub mod rfc3296 { + pub const REF: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113730.3.1.34"); + pub const REFERRAL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113730.3.2.6"); +} +pub mod rfc3671 { + pub const COLLECTIVE_ATTRIBUTE_SUBENTRIES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.18.12"); + pub const COLLECTIVE_EXCLUSIONS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.18.7"); + pub const COLLECTIVE_ATTRIBUTE_SUBENTRY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.20.2"); + pub const C_O: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.10.1"); + pub const C_OU: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.11.1"); + pub const C_POSTAL_ADDRESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.16.1"); + pub const C_POSTAL_CODE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.17.1"); + pub const C_POST_OFFICE_BOX: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.18.1"); + pub const C_PHYSICAL_DELIVERY_OFFICE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.19.1"); + pub const C_TELEPHONE_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.20.1"); + pub const C_TELEX_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.21.1"); + pub const C_FACSIMILE_TELEPHONE_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.23.1"); + pub const C_INTERNATIONAL_ISDN_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.25.1"); + pub const C_L: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.7.1"); + pub const C_ST: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.8.1"); + pub const C_STREET: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.9.1"); +} +pub mod rfc3672 { + pub const SUBENTRY: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.17.0"); + pub const ADMINISTRATIVE_ROLE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.18.5"); + pub const SUBTREE_SPECIFICATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.18.6"); + pub const AUTONOMOUS_AREA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.23.1"); + pub const ACCESS_CONTROL_SPECIFIC_AREA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.23.2"); + pub const ACCESS_CONTROL_INNER_AREA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.23.3"); + pub const SUBSCHEMA_ADMIN_SPECIFIC_AREA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.23.4"); + pub const COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.23.5"); + pub const COLLECTIVE_ATTRIBUTE_INNER_AREA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.23.6"); +} +pub mod rfc3687 { + pub const COMPONENT_FILTER_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.36.79672281.1.13.2"); + pub const RDN_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.36.79672281.1.13.3"); + pub const PRESENT_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.36.79672281.1.13.5"); + pub const ALL_COMPONENTS_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.36.79672281.1.13.6"); + pub const DIRECTORY_COMPONENTS_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.36.79672281.1.13.7"); +} +pub mod rfc3698 { + pub const STORED_PREFIX_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.41"); +} +pub mod rfc3703 { + pub const PCIM_POLICY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.1"); + pub const PCIM_RULE_ACTION_ASSOCIATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.10"); + pub const PCIM_CONDITION_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.11"); + pub const PCIM_TPC_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.12"); + pub const PCIM_CONDITION_VENDOR_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.13"); + pub const PCIM_ACTION_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.14"); + pub const PCIM_ACTION_VENDOR_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.15"); + pub const PCIM_POLICY_INSTANCE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.16"); + pub const PCIM_ELEMENT_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.17"); + pub const PCIM_REPOSITORY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.18"); + pub const PCIM_REPOSITORY_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.19"); + pub const PCIM_GROUP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.2"); + pub const PCIM_REPOSITORY_INSTANCE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.20"); + pub const PCIM_SUBTREES_PTR_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.21"); + pub const PCIM_GROUP_CONTAINMENT_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.22"); + pub const PCIM_RULE_CONTAINMENT_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.23"); + pub const PCIM_GROUP_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.3"); + pub const PCIM_GROUP_INSTANCE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.4"); + pub const PCIM_RULE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.5"); + pub const PCIM_RULE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.6"); + pub const PCIM_RULE_INSTANCE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.7"); + pub const PCIM_RULE_CONDITION_ASSOCIATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.8"); + pub const PCIM_RULE_VALIDITY_ASSOCIATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.1.9"); + pub const PCIM_RULE_VALIDITY_PERIOD_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.10"); + pub const PCIM_RULE_USAGE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.11"); + pub const PCIM_RULE_PRIORITY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.12"); + pub const PCIM_RULE_MANDATORY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.13"); + pub const PCIM_RULE_SEQUENCED_ACTIONS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.14"); + pub const PCIM_ROLES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.15"); + pub const PCIM_CONDITION_GROUP_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.16"); + pub const PCIM_CONDITION_NEGATED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.17"); + pub const PCIM_CONDITION_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.18"); + pub const PCIM_CONDITION_DN: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.19"); + pub const PCIM_VALIDITY_CONDITION_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.20"); + pub const PCIM_TIME_PERIOD_CONDITION_DN: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.21"); + pub const PCIM_ACTION_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.22"); + pub const PCIM_ACTION_ORDER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.23"); + pub const PCIM_ACTION_DN: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.24"); + pub const PCIM_TPC_TIME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.25"); + pub const PCIM_TPC_MONTH_OF_YEAR_MASK: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.26"); + pub const PCIM_TPC_DAY_OF_MONTH_MASK: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.27"); + pub const PCIM_TPC_DAY_OF_WEEK_MASK: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.28"); + pub const PCIM_TPC_TIME_OF_DAY_MASK: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.29"); + pub const PCIM_KEYWORDS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.3"); + pub const PCIM_TPC_LOCAL_OR_UTC_TIME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.30"); + pub const PCIM_VENDOR_CONSTRAINT_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.31"); + pub const PCIM_VENDOR_CONSTRAINT_ENCODING: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.32"); + pub const PCIM_VENDOR_ACTION_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.33"); + pub const PCIM_VENDOR_ACTION_ENCODING: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.34"); + pub const PCIM_POLICY_INSTANCE_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.35"); + pub const PCIM_REPOSITORY_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.36"); + pub const PCIM_SUBTREES_AUX_CONTAINED_SET: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.37"); + pub const PCIM_GROUPS_AUX_CONTAINED_SET: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.38"); + pub const PCIM_RULES_AUX_CONTAINED_SET: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.39"); + pub const PCIM_GROUP_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.4"); + pub const PCIM_RULE_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.5"); + pub const PCIM_RULE_ENABLED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.6"); + pub const PCIM_RULE_CONDITION_LIST_TYPE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.7"); + pub const PCIM_RULE_CONDITION_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.8"); + pub const PCIM_RULE_ACTION_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.6.2.9"); +} +pub mod rfc3712 { + pub const PRINTER_XRI_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1107"); + pub const PRINTER_ALIASES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1108"); + pub const PRINTER_CHARSET_CONFIGURED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1109"); + pub const PRINTER_JOB_PRIORITY_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1110"); + pub const PRINTER_JOB_K_OCTETS_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1111"); + pub const PRINTER_CURRENT_OPERATOR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1112"); + pub const PRINTER_SERVICE_PERSON: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1113"); + pub const PRINTER_DELIVERY_ORIENTATION_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1114"); + pub const PRINTER_STACKING_ORDER_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1115"); + pub const PRINTER_OUTPUT_FEATURES_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1116"); + pub const PRINTER_MEDIA_LOCAL_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1117"); + pub const PRINTER_COPIES_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1118"); + pub const PRINTER_NATURAL_LANGUAGE_CONFIGURED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1119"); + pub const PRINTER_PRINT_QUALITY_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1120"); + pub const PRINTER_RESOLUTION_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1121"); + pub const PRINTER_MEDIA_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1122"); + pub const PRINTER_SIDES_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1123"); + pub const PRINTER_NUMBER_UP_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1124"); + pub const PRINTER_FINISHINGS_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1125"); + pub const PRINTER_PAGES_PER_MINUTE_COLOR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1126"); + pub const PRINTER_PAGES_PER_MINUTE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1127"); + pub const PRINTER_COMPRESSION_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1128"); + pub const PRINTER_COLOR_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1129"); + pub const PRINTER_DOCUMENT_FORMAT_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1130"); + pub const PRINTER_CHARSET_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1131"); + pub const PRINTER_MULTIPLE_DOCUMENT_JOBS_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1132"); + pub const PRINTER_IPP_VERSIONS_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1133"); + pub const PRINTER_MORE_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1134"); + pub const PRINTER_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1135"); + pub const PRINTER_LOCATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1136"); + pub const PRINTER_GENERATED_NATURAL_LANGUAGE_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1137"); + pub const PRINTER_MAKE_AND_MODEL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1138"); + pub const PRINTER_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1139"); + pub const PRINTER_URI: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.4.1140"); + pub const PRINTER_LPR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.6.253"); + pub const SLP_SERVICE_PRINTER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.6.254"); + pub const PRINTER_SERVICE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.6.255"); + pub const PRINTER_IPP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.6.256"); + pub const PRINTER_SERVICE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.6.257"); + pub const PRINTER_ABSTRACT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.6.258"); +} +pub mod rfc4104 { + pub const PCELS_POLICY_SET: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.1"); + pub const PCELS_ACTION_ASSOCIATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.10"); + pub const PCELS_SIMPLE_CONDITION_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.11"); + pub const PCELS_COMPOUND_CONDITION_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.12"); + pub const PCELS_COMPOUND_FILTER_CONDITION_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.13"); + pub const PCELS_SIMPLE_ACTION_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.14"); + pub const PCELS_COMPOUND_ACTION_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.15"); + pub const PCELS_VARIABLE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.16"); + pub const PCELS_EXPLICIT_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.17"); + pub const PCELS_IMPLICIT_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.18"); + pub const PCELS_SOURCE_I_PV_4_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.19"); + pub const PCELS_POLICY_SET_ASSOCIATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.2"); + pub const PCELS_SOURCE_I_PV_6_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.20"); + pub const PCELS_DESTINATION_I_PV_4_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.21"); + pub const PCELS_DESTINATION_I_PV_6_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.22"); + pub const PCELS_SOURCE_PORT_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.23"); + pub const PCELS_DESTINATION_PORT_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.24"); + pub const PCELS_IP_PROTOCOL_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.25"); + pub const PCELS_IP_VERSION_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.26"); + pub const PCELS_IP_TO_S_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.27"); + pub const PCELS_DSCP_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.28"); + pub const PCELS_FLOW_ID_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.29"); + pub const PCELS_GROUP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.3"); + pub const PCELS_SOURCE_MAC_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.30"); + pub const PCELS_DESTINATION_MAC_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.31"); + pub const PCELS_VLAN_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.32"); + pub const PCELS_CO_S_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.33"); + pub const PCELS_ETHERTYPE_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.34"); + pub const PCELS_SOURCE_SAP_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.35"); + pub const PCELS_DESTINATION_SAP_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.36"); + pub const PCELS_SNAPOUI_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.37"); + pub const PCELS_SNAP_TYPE_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.38"); + pub const PCELS_FLOW_DIRECTION_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.39"); + pub const PCELS_GROUP_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.4"); + pub const PCELS_VALUE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.40"); + pub const PCELS_I_PV_4_ADDR_VALUE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.41"); + pub const PCELS_I_PV_6_ADDR_VALUE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.42"); + pub const PCELS_MAC_ADDR_VALUE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.43"); + pub const PCELS_STRING_VALUE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.44"); + pub const PCELS_BIT_STRING_VALUE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.45"); + pub const PCELS_INTEGER_VALUE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.46"); + pub const PCELS_BOOLEAN_VALUE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.47"); + pub const PCELS_REUSABLE_CONTAINER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.48"); + pub const PCELS_REUSABLE_CONTAINER_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.49"); + pub const PCELS_GROUP_INSTANCE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.5"); + pub const PCELS_REUSABLE_CONTAINER_INSTANCE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.50"); + pub const PCELS_ROLE_COLLECTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.51"); + pub const PCELS_FILTER_ENTRY_BASE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.52"); + pub const PCELS_IP_HEADERS_FILTER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.53"); + pub const PCELS_8021_FILTER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.54"); + pub const PCELS_FILTER_LIST_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.55"); + pub const PCELS_VENDOR_VARIABLE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.56"); + pub const PCELS_VENDOR_VALUE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.57"); + pub const PCELS_RULE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.6"); + pub const PCELS_RULE_AUX_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.7"); + pub const PCELS_RULE_INSTANCE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.8"); + pub const PCELS_CONDITION_ASSOCIATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.1.9"); + pub const PCELS_POLICY_SET_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.1"); + pub const PCELS_EXECUTION_STRATEGY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.10"); + pub const PCELS_VARIABLE_DN: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.11"); + pub const PCELS_VALUE_DN: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.12"); + pub const PCELS_IS_MIRRORED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.13"); + pub const PCELS_VARIABLE_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.14"); + pub const PCELS_EXPECTED_VALUE_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.15"); + pub const PCELS_VARIABLE_MODEL_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.16"); + pub const PCELS_VARIABLE_MODEL_PROPERTY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.17"); + pub const PCELS_EXPECTED_VALUE_TYPES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.18"); + pub const PCELS_VALUE_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.19"); + pub const PCELS_DECISION_STRATEGY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.2"); + pub const PCELS_I_PV_4_ADDR_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.20"); + pub const PCELS_I_PV_6_ADDR_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.21"); + pub const PCELS_MAC_ADDR_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.22"); + pub const PCELS_STRING_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.23"); + pub const PCELS_BIT_STRING_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.24"); + pub const PCELS_INTEGER_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.25"); + pub const PCELS_BOOLEAN: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.26"); + pub const PCELS_REUSABLE_CONTAINER_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.27"); + pub const PCELS_REUSABLE_CONTAINER_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.28"); + pub const PCELS_ROLE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.29"); + pub const PCELS_POLICY_SET_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.3"); + pub const PCELS_ROLE_COLLECTION_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.30"); + pub const PCELS_ELEMENT_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.31"); + pub const PCELS_FILTER_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.32"); + pub const PCELS_FILTER_IS_NEGATED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.33"); + pub const PCELS_IP_HDR_VERSION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.34"); + pub const PCELS_IP_HDR_SOURCE_ADDRESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.35"); + pub const PCELS_IP_HDR_SOURCE_ADDRESS_END_OF_RANGE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.36"); + pub const PCELS_IP_HDR_SOURCE_MASK: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.37"); + pub const PCELS_IP_HDR_DEST_ADDRESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.38"); + pub const PCELS_IP_HDR_DEST_ADDRESS_END_OF_RANGE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.39"); + pub const PCELS_PRIORITY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.4"); + pub const PCELS_IP_HDR_DEST_MASK: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.40"); + pub const PCELS_IP_HDR_PROTOCOL_ID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.41"); + pub const PCELS_IP_HDR_SOURCE_PORT_START: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.42"); + pub const PCELS_IP_HDR_SOURCE_PORT_END: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.43"); + pub const PCELS_IP_HDR_DEST_PORT_START: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.44"); + pub const PCELS_IP_HDR_DEST_PORT_END: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.45"); + pub const PCELS_IP_HDR_DSCP_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.46"); + pub const PCELS_IP_HDR_FLOW_LABEL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.47"); + pub const PCELS_8021_HDR_SOURCE_MAC_ADDRESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.48"); + pub const PCELS_8021_HDR_SOURCE_MAC_MASK: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.49"); + pub const PCELS_POLICY_SET_DN: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.5"); + pub const PCELS_8021_HDR_DEST_MAC_ADDRESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.50"); + pub const PCELS_8021_HDR_DEST_MAC_MASK: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.51"); + pub const PCELS_8021_HDR_PROTOCOL_ID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.52"); + pub const PCELS_8021_HDR_PRIORITY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.53"); + pub const PCELS_8021_HDR_VLANID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.54"); + pub const PCELS_FILTER_LIST_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.55"); + pub const PCELS_FILTER_DIRECTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.56"); + pub const PCELS_FILTER_ENTRY_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.57"); + pub const PCELS_VENDOR_VARIABLE_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.58"); + pub const PCELS_VENDOR_VARIABLE_ENCODING: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.59"); + pub const PCELS_CONDITION_LIST_TYPE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.6"); + pub const PCELS_VENDOR_VALUE_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.60"); + pub const PCELS_VENDOR_VALUE_ENCODING: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.61"); + pub const PCELS_RULE_VALIDITY_PERIOD_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.62"); + pub const PCELS_CONDITION_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.7"); + pub const PCELS_ACTION_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.8"); + pub const PCELS_SEQUENCED_ACTIONS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.9.2.9"); +} +pub mod rfc4237 { + pub const VPIM_USER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.11.1.1"); + pub const VPIM_TELEPHONE_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.11.2.1"); + pub const VPIM_SUB_MAILBOXES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.11.2.10"); + pub const VPIM_RFC_822_MAILBOX: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.11.2.2"); + pub const VPIM_SPOKEN_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.11.2.3"); + pub const VPIM_SUPPORTED_UA_BEHAVIORS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.11.2.4"); + pub const VPIM_SUPPORTED_AUDIO_MEDIA_TYPES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.11.2.5"); + pub const VPIM_SUPPORTED_MESSAGE_CONTEXT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.11.2.6"); + pub const VPIM_TEXT_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.11.2.7"); + pub const VPIM_EXTENDED_ABSENCE_STATUS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.11.2.8"); + pub const VPIM_MAX_MESSAGE_SIZE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.11.2.9"); +} +pub mod rfc4403 { + pub const UDDIV_3_SERVICE_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.32"); + pub const UDDI_BUSINESS_ENTITY_NAME_FORM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.15.1"); + pub const UDDIV_3_ENTITY_OBITUARY_NAME_FORM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.15.10"); + pub const UDDI_CONTACT_NAME_FORM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.15.2"); + pub const UDDI_ADDRESS_NAME_FORM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.15.3"); + pub const UDDI_BUSINESS_SERVICE_NAME_FORM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.15.4"); + pub const UDDI_BINDING_TEMPLATE_NAME_FORM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.15.5"); + pub const UDDI_T_MODEL_INSTANCE_INFO_NAME_FORM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.15.6"); + pub const UDDI_T_MODEL_NAME_FORM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.15.7"); + pub const UDDI_PUBLISHER_ASSERTION_NAME_FORM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.15.8"); + pub const UDDIV_3_SUBSCRIPTION_NAME_FORM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.15.9"); + pub const UDDI_BUSINESS_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.1"); + pub const UDDI_E_MAIL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.10"); + pub const UDDI_SORT_CODE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.11"); + pub const UDDI_T_MODEL_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.12"); + pub const UDDI_ADDRESS_LINE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.13"); + pub const UDDI_IDENTIFIER_BAG: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.14"); + pub const UDDI_CATEGORY_BAG: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.15"); + pub const UDDI_KEYED_REFERENCE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.16"); + pub const UDDI_SERVICE_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.17"); + pub const UDDI_BINDING_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.18"); + pub const UDDI_ACCESS_POINT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.19"); + pub const UDDI_AUTHORIZED_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.2"); + pub const UDDI_HOSTING_REDIRECTOR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.20"); + pub const UDDI_INSTANCE_DESCRIPTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.21"); + pub const UDDI_INSTANCE_PARMS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.22"); + pub const UDDI_OVERVIEW_DESCRIPTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.23"); + pub const UDDI_OVERVIEW_URL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.24"); + pub const UDDI_FROM_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.25"); + pub const UDDI_TO_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.26"); + pub const UDDI_UUID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.27"); + pub const UDDI_IS_HIDDEN: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.28"); + pub const UDDI_IS_PROJECTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.29"); + pub const UDDI_OPERATOR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.3"); + pub const UDDI_LANG: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.30"); + pub const UDDIV_3_BUSINESS_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.31"); + pub const UDDIV_3_BINDING_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.33"); + pub const UDDIV_3_TMODEL_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.34"); + pub const UDDIV_3_DIGITAL_SIGNATURE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.35"); + pub const UDDIV_3_NODE_ID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.36"); + pub const UDDIV_3_ENTITY_MODIFICATION_TIME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.37"); + pub const UDDIV_3_SUBSCRIPTION_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.38"); + pub const UDDIV_3_SUBSCRIPTION_FILTER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.39"); + pub const UDDI_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.4"); + pub const UDDIV_3_NOTIFICATION_INTERVAL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.40"); + pub const UDDIV_3_MAX_ENTITIES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.41"); + pub const UDDIV_3_EXPIRES_AFTER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.42"); + pub const UDDIV_3_BRIEF_RESPONSE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.43"); + pub const UDDIV_3_ENTITY_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.44"); + pub const UDDIV_3_ENTITY_CREATION_TIME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.45"); + pub const UDDIV_3_ENTITY_DELETION_TIME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.46"); + pub const UDDI_DESCRIPTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.5"); + pub const UDDI_DISCOVERY_UR_LS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.6"); + pub const UDDI_USE_TYPE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.7"); + pub const UDDI_PERSON_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.8"); + pub const UDDI_PHONE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.4.9"); + pub const UDDI_BUSINESS_ENTITY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.6.1"); + pub const UDDIV_3_ENTITY_OBITUARY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.6.10"); + pub const UDDI_CONTACT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.6.2"); + pub const UDDI_ADDRESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.6.3"); + pub const UDDI_BUSINESS_SERVICE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.6.4"); + pub const UDDI_BINDING_TEMPLATE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.6.5"); + pub const UDDI_T_MODEL_INSTANCE_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.6.6"); + pub const UDDI_T_MODEL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.6.7"); + pub const UDDI_PUBLISHER_ASSERTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.6.8"); + pub const UDDIV_3_SUBSCRIPTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.10.6.9"); +} +pub mod rfc4512 { + pub const EXTENSIBLE_OBJECT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.1466.101.120.111"); + pub const SUPPORTED_CONTROL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.1466.101.120.13"); + pub const SUPPORTED_SASL_MECHANISMS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.1466.101.120.14"); + pub const SUPPORTED_LDAP_VERSION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.1466.101.120.15"); + pub const LDAP_SYNTAXES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.1466.101.120.16"); + pub const NAMING_CONTEXTS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.1466.101.120.5"); + pub const ALT_SERVER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.1466.101.120.6"); + pub const SUPPORTED_EXTENSION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.1466.101.120.7"); + pub const SUPPORTED_FEATURES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.4203.1.3.5"); + pub const CREATE_TIMESTAMP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.18.1"); + pub const SUBSCHEMA_SUBENTRY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.18.10"); + pub const MODIFY_TIMESTAMP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.18.2"); + pub const CREATORS_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.18.3"); + pub const MODIFIERS_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.18.4"); + pub const SUBSCHEMA: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.20.1"); + pub const DIT_STRUCTURE_RULES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.21.1"); + pub const GOVERNING_STRUCTURE_RULE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.21.10"); + pub const DIT_CONTENT_RULES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.21.2"); + pub const MATCHING_RULES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.21.4"); + pub const ATTRIBUTE_TYPES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.21.5"); + pub const OBJECT_CLASSES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.21.6"); + pub const NAME_FORMS: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.21.7"); + pub const MATCHING_RULE_USE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.21.8"); + pub const STRUCTURAL_OBJECT_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.21.9"); + pub const OBJECT_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.0"); + pub const ALIASED_OBJECT_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.1"); + pub const TOP: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.6.0"); + pub const ALIAS: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.6.1"); +} +pub mod rfc4517 { + pub const CASE_EXACT_IA_5_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.1466.109.114.1"); + pub const CASE_IGNORE_IA_5_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.1466.109.114.2"); + pub const CASE_IGNORE_IA_5_SUBSTRINGS_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.1466.109.114.3"); + pub const OBJECT_IDENTIFIER_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.0"); + pub const DISTINGUISHED_NAME_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.1"); + pub const NUMERIC_STRING_SUBSTRINGS_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.10"); + pub const CASE_IGNORE_LIST_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.11"); + pub const CASE_IGNORE_LIST_SUBSTRINGS_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.12"); + pub const BOOLEAN_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.13"); + pub const INTEGER_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.14"); + pub const INTEGER_ORDERING_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.15"); + pub const BIT_STRING_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.16"); + pub const OCTET_STRING_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.17"); + pub const OCTET_STRING_ORDERING_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.18"); + pub const CASE_IGNORE_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.2"); + pub const TELEPHONE_NUMBER_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.20"); + pub const TELEPHONE_NUMBER_SUBSTRINGS_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.21"); + pub const UNIQUE_MEMBER_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.23"); + pub const GENERALIZED_TIME_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.27"); + pub const GENERALIZED_TIME_ORDERING_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.28"); + pub const INTEGER_FIRST_COMPONENT_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.29"); + pub const CASE_IGNORE_ORDERING_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.3"); + pub const OBJECT_IDENTIFIER_FIRST_COMPONENT_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.30"); + pub const DIRECTORY_STRING_FIRST_COMPONENT_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.31"); + pub const WORD_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.32"); + pub const KEYWORD_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.33"); + pub const CASE_IGNORE_SUBSTRINGS_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.4"); + pub const CASE_EXACT_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.5"); + pub const CASE_EXACT_ORDERING_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.6"); + pub const CASE_EXACT_SUBSTRINGS_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.7"); + pub const NUMERIC_STRING_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.8"); + pub const NUMERIC_STRING_ORDERING_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.9"); +} +pub mod rfc4519 { + pub const UID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.1"); + pub const USER_ID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.1"); + pub const DC: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.25"); + pub const DOMAIN_COMPONENT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.25"); + pub const UID_OBJECT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.3.1"); + pub const DC_OBJECT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.1466.344"); + pub const O: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.10"); + pub const ORGANIZATION_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.10"); + pub const OU: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.11"); + pub const ORGANIZATIONAL_UNIT_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.11"); + pub const TITLE: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.12"); + pub const DESCRIPTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.13"); + pub const SEARCH_GUIDE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.14"); + pub const BUSINESS_CATEGORY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.15"); + pub const POSTAL_ADDRESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.16"); + pub const POSTAL_CODE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.17"); + pub const POST_OFFICE_BOX: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.18"); + pub const PHYSICAL_DELIVERY_OFFICE_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.19"); + pub const TELEPHONE_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.20"); + pub const TELEX_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.21"); + pub const TELETEX_TERMINAL_IDENTIFIER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.22"); + pub const FACSIMILE_TELEPHONE_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.23"); + pub const X_121_ADDRESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.24"); + pub const INTERNATIONALI_SDN_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.25"); + pub const REGISTERED_ADDRESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.26"); + pub const DESTINATION_INDICATOR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.27"); + pub const PREFERRED_DELIVERY_METHOD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.28"); + pub const CN: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.3"); + pub const COMMON_NAME: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.3"); + pub const MEMBER: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.31"); + pub const OWNER: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.32"); + pub const ROLE_OCCUPANT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.33"); + pub const SEE_ALSO: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.34"); + pub const USER_PASSWORD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.35"); + pub const SN: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.4"); + pub const SURNAME: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.4"); + pub const NAME: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.41"); + pub const GIVEN_NAME: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.42"); + pub const INITIALS: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.43"); + pub const GENERATION_QUALIFIER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.44"); + pub const X_500_UNIQUE_IDENTIFIER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.45"); + pub const DN_QUALIFIER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.46"); + pub const ENHANCED_SEARCH_GUIDE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.47"); + pub const DISTINGUISHED_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.49"); + pub const SERIAL_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.5"); + pub const UNIQUE_MEMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.50"); + pub const HOUSE_IDENTIFIER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.51"); + pub const C: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.6"); + pub const COUNTRY_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.6"); + pub const L: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.7"); + pub const LOCALITY_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.7"); + pub const ST: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.8"); + pub const STREET: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.9"); + pub const RESIDENTIAL_PERSON: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.6.10"); + pub const APPLICATION_PROCESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.6.11"); + pub const DEVICE: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.6.14"); + pub const GROUP_OF_UNIQUE_NAMES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.6.17"); + pub const COUNTRY: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.6.2"); + pub const LOCALITY: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.6.3"); + pub const ORGANIZATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.6.4"); + pub const ORGANIZATIONAL_UNIT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.6.5"); + pub const PERSON: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.6.6"); + pub const ORGANIZATIONAL_PERSON: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.6.7"); + pub const ORGANIZATIONAL_ROLE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.6.8"); + pub const GROUP_OF_NAMES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.6.9"); +} +pub mod rfc4523 { + pub const CERTIFICATE_EXACT_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.34"); + pub const CERTIFICATE_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.35"); + pub const CERTIFICATE_PAIR_EXACT_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.36"); + pub const CERTIFICATE_PAIR_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.37"); + pub const CERTIFICATE_LIST_EXACT_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.38"); + pub const CERTIFICATE_LIST_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.39"); + pub const ALGORITHM_IDENTIFIER_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.13.40"); + pub const USER_CERTIFICATE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.36"); + pub const CA_CERTIFICATE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.37"); + pub const AUTHORITY_REVOCATION_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.38"); + pub const CERTIFICATE_REVOCATION_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.39"); + pub const CROSS_CERTIFICATE_PAIR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.40"); + pub const SUPPORTED_ALGORITHMS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.52"); + pub const DELTA_REVOCATION_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.4.53"); + pub const STRONG_AUTHENTICATION_USER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.6.15"); + pub const CERTIFICATION_AUTHORITY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.6.16"); + pub const CERTIFICATION_AUTHORITY_V_2: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.6.16.2"); + pub const USER_SECURITY_INFORMATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.6.18"); + pub const CRL_DISTRIBUTION_POINT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.6.19"); + pub const PKI_USER: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.6.21"); + pub const PKI_CA: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.6.22"); + pub const DELTA_CRL: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.6.23"); +} +pub mod rfc4524 { + pub const MANAGER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.10"); + pub const DOCUMENT_IDENTIFIER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.11"); + pub const DOCUMENT_TITLE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.12"); + pub const DOCUMENT_VERSION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.13"); + pub const DOCUMENT_AUTHOR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.14"); + pub const DOCUMENT_LOCATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.15"); + pub const HOME_PHONE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.20"); + pub const HOME_TELEPHONE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.20"); + pub const SECRETARY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.21"); + pub const MAIL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.3"); + pub const RFC_822_MAILBOX: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.3"); + pub const ASSOCIATED_DOMAIN: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.37"); + pub const ASSOCIATED_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.38"); + pub const HOME_POSTAL_ADDRESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.39"); + pub const INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.4"); + pub const PERSONAL_TITLE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.40"); + pub const MOBILE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.41"); + pub const MOBILE_TELEPHONE_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.41"); + pub const PAGER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.42"); + pub const PAGER_TELEPHONE_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.42"); + pub const CO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.43"); + pub const FRIENDLY_COUNTRY_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.43"); + pub const UNIQUE_IDENTIFIER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.44"); + pub const ORGANIZATIONAL_STATUS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.45"); + pub const BUILDING_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.48"); + pub const DRINK: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.5"); + pub const FAVOURITE_DRINK: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.5"); + pub const SINGLE_LEVEL_QUALITY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.50"); + pub const DOCUMENT_PUBLISHER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.56"); + pub const ROOM_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.6"); + pub const USER_CLASS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.8"); + pub const HOST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.9"); + pub const DOMAIN: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.4.13"); + pub const RFC_822_LOCAL_PART: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.4.14"); + pub const DOMAIN_RELATED_OBJECT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.4.17"); + pub const FRIENDLY_COUNTRY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.4.18"); + pub const SIMPLE_SECURITY_OBJECT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.4.19"); + pub const ACCOUNT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.4.5"); + pub const DOCUMENT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.4.6"); + pub const ROOM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.4.7"); + pub const DOCUMENT_SERIES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.4.8"); +} +pub mod rfc4530 { + pub const UUID_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.16.2"); + pub const UUID_ORDERING_MATCH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.16.3"); + pub const ENTRY_UUID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.16.4"); +} +pub mod rfc4876 { + pub const DEFAULT_SERVER_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11.1.3.1.1.0"); + pub const DEFAULT_SEARCH_BASE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11.1.3.1.1.1"); + pub const CREDENTIAL_LEVEL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11.1.3.1.1.10"); + pub const OBJECTCLASS_MAP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11.1.3.1.1.11"); + pub const DEFAULT_SEARCH_SCOPE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11.1.3.1.1.12"); + pub const SERVICE_CREDENTIAL_LEVEL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11.1.3.1.1.13"); + pub const SERVICE_SEARCH_DESCRIPTOR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11.1.3.1.1.14"); + pub const SERVICE_AUTHENTICATION_METHOD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11.1.3.1.1.15"); + pub const DEREFERENCE_ALIASES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11.1.3.1.1.16"); + pub const PREFERRED_SERVER_LIST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11.1.3.1.1.2"); + pub const SEARCH_TIME_LIMIT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11.1.3.1.1.3"); + pub const BIND_TIME_LIMIT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11.1.3.1.1.4"); + pub const FOLLOW_REFERRALS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11.1.3.1.1.5"); + pub const AUTHENTICATION_METHOD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11.1.3.1.1.6"); + pub const PROFILE_TTL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11.1.3.1.1.7"); + pub const ATTRIBUTE_MAP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11.1.3.1.1.9"); + pub const DUA_CONFIG_PROFILE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11.1.3.1.2.5"); +} +pub mod rfc5020 { + pub const ENTRY_DN: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.20"); +} +pub mod rfc5280 { + pub const PKCS_9: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9"); + pub const ID_PKIX: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7"); + pub const ID_PE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.1"); + pub const ID_PE_AUTHORITY_INFO_ACCESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.1.1"); + pub const ID_PE_SUBJECT_INFO_ACCESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.1.11"); + pub const ID_QT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.2"); + pub const ID_QT_CPS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.2.1"); + pub const ID_QT_UNOTICE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.2.2"); + pub const ID_KP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3"); + pub const ID_KP_SERVER_AUTH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3.1"); + pub const ID_KP_CLIENT_AUTH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3.2"); + pub const ID_KP_CODE_SIGNING: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3.3"); + pub const ID_KP_EMAIL_PROTECTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3.4"); + pub const ID_KP_TIME_STAMPING: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3.8"); + pub const ID_KP_OCSP_SIGNING: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3.9"); + pub const ID_AD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48"); + pub const ID_AD_OCSP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1"); + pub const ID_AD_CA_ISSUERS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.2"); + pub const ID_AD_TIME_STAMPING: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.3"); + pub const ID_AD_CA_REPOSITORY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.5"); + pub const HOLD_INSTRUCTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.2.840.10040.2"); + pub const ID_HOLDINSTRUCTION_NONE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.2.840.10040.2.1"); + pub const ID_HOLDINSTRUCTION_CALLISSUER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.2.840.10040.2.2"); + pub const ID_HOLDINSTRUCTION_REJECT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.2.840.10040.2.3"); + pub const ID_CE: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.29"); + pub const ID_CE_SUBJECT_KEY_IDENTIFIER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.14"); + pub const ID_CE_KEY_USAGE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.15"); + pub const ID_CE_PRIVATE_KEY_USAGE_PERIOD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.16"); + pub const ID_CE_SUBJECT_ALT_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.17"); + pub const ID_CE_ISSUER_ALT_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.18"); + pub const ID_CE_BASIC_CONSTRAINTS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.19"); + pub const ID_CE_CRL_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.20"); + pub const ID_CE_CRL_REASONS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.21"); + pub const ID_CE_HOLD_INSTRUCTION_CODE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.23"); + pub const ID_CE_INVALIDITY_DATE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.24"); + pub const ID_CE_DELTA_CRL_INDICATOR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.27"); + pub const ID_CE_ISSUING_DISTRIBUTION_POINT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.28"); + pub const ID_CE_CERTIFICATE_ISSUER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.29"); + pub const ID_CE_NAME_CONSTRAINTS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.30"); + pub const ID_CE_CRL_DISTRIBUTION_POINTS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.31"); + pub const ID_CE_CERTIFICATE_POLICIES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.32"); + pub const ANY_POLICY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.32.0"); + pub const ID_CE_POLICY_MAPPINGS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.33"); + pub const ID_CE_AUTHORITY_KEY_IDENTIFIER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.35"); + pub const ID_CE_POLICY_CONSTRAINTS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.36"); + pub const ID_CE_EXT_KEY_USAGE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.37"); + pub const ANY_EXTENDED_KEY_USAGE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.37.0"); + pub const ID_CE_FRESHEST_CRL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.46"); + pub const ID_CE_INHIBIT_ANY_POLICY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.54"); + pub const ID_CE_SUBJECT_DIRECTORY_ATTRIBUTES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.9"); + pub const ID_AT: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4"); +} +pub mod rfc5911 { + pub const ID_PBKDF_2: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.5.12"); + pub const ID_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.7.1"); + pub const ID_SIGNED_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.7.2"); + pub const ID_ENVELOPED_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.7.3"); + pub const ID_DIGESTED_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.7.5"); + pub const ID_ENCRYPTED_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.7.6"); + pub const SMIME_CAPABILITIES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.15"); + pub const ID_SMIME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16"); + pub const ID_CT_RECEIPT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.1"); + pub const ID_CT_FIRMWARE_PACKAGE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.16"); + pub const ID_CT_FIRMWARE_LOAD_RECEIPT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.17"); + pub const ID_CT_FIRMWARE_LOAD_ERROR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.18"); + pub const ID_CT_AUTH_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.2"); + pub const ID_CT_AUTH_ENVELOPED_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.23"); + pub const ID_CT_CONTENT_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.6"); + pub const ID_CAP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.11"); + pub const ID_CAP_PREFER_BINARY_INSIDE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.11.1"); + pub const ID_AA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2"); + pub const ID_AA_RECEIPT_REQUEST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.1"); + pub const ID_AA_CONTENT_REFERENCE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.10"); + pub const ID_AA_ENCRYP_KEY_PREF: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.11"); + pub const ID_AA_SIGNING_CERTIFICATE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.12"); + pub const ID_AA_SECURITY_LABEL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.2"); + pub const ID_AA_ML_EXPAND_HISTORY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.3"); + pub const ID_AA_FIRMWARE_PACKAGE_ID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.35"); + pub const ID_AA_TARGET_HARDWARE_I_DS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.36"); + pub const ID_AA_DECRYPT_KEY_ID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.37"); + pub const ID_AA_IMPL_CRYPTO_ALGS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.38"); + pub const ID_AA_WRAPPED_FIRMWARE_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.39"); + pub const ID_AA_CONTENT_HINT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.4"); + pub const ID_AA_COMMUNITY_IDENTIFIERS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.40"); + pub const ID_AA_FIRMWARE_PACKAGE_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.42"); + pub const ID_AA_IMPL_COMPRESS_ALGS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.43"); + pub const ID_AA_SIGNING_CERTIFICATE_V_2: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.47"); + pub const ID_AA_ER_INTERNAL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.49"); + pub const ID_AA_MSG_SIG_DIGEST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.5"); + pub const ID_AA_ER_EXTERNAL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.50"); + pub const ID_AA_CONTENT_IDENTIFIER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.7"); + pub const ID_AA_EQUIVALENT_LABELS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.9"); + pub const ID_ALG_SSDH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.3.10"); + pub const ID_ALG_ESDH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.3.5"); + pub const ID_ALG_CMS_3_DE_SWRAP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.3.6"); + pub const ID_ALG_CMSRC_2_WRAP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.3.7"); + pub const ID_SKD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.8"); + pub const ID_SKD_GL_USE_KEK: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.8.1"); + pub const ID_SKD_GLA_QUERY_REQUEST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.8.11"); + pub const ID_SKD_GLA_QUERY_RESPONSE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.8.12"); + pub const ID_SKD_GL_PROVIDE_CERT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.8.13"); + pub const ID_SKD_GL_MANAGE_CERT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.8.14"); + pub const ID_SKD_GL_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.8.15"); + pub const ID_SKD_GL_DELETE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.8.2"); + pub const ID_SKD_GL_ADD_MEMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.8.3"); + pub const ID_SKD_GL_DELETE_MEMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.8.4"); + pub const ID_SKD_GL_REKEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.8.5"); + pub const ID_SKD_GL_ADD_OWNER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.8.6"); + pub const ID_SKD_GL_REMOVE_OWNER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.8.7"); + pub const ID_SKD_GL_KEY_COMPROMISE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.8.8"); + pub const ID_SKD_GLK_REFRESH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.8.9"); + pub const ID_CONTENT_TYPE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.3"); + pub const ID_MESSAGE_DIGEST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.4"); + pub const ID_SIGNING_TIME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.5"); + pub const ID_COUNTERSIGNATURE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.6"); + pub const RC_2_CBC: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.3.2"); + pub const DES_EDE_3_CBC: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.3.7"); + pub const LTANS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.11"); + pub const ID_CET_SKD_FAIL_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.15.1"); + pub const ID_CMC_GLA_RR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.99"); + pub const ID_CMC_GLA_SKD_ALG_REQUEST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.99.1"); + pub const ID_CMC_GLA_SKD_ALG_RESPONSE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.99.2"); + pub const ID_ON_HARDWARE_MODULE_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.8.4"); + pub const HMAC_SHA_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.8.1.2"); + pub const AES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1"); + pub const ID_AES_128_CBC: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.2"); + pub const ID_AES_192_CBC: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.22"); + pub const ID_AES_192_WRAP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.25"); + pub const ID_AES_192_GCM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.26"); + pub const ID_AES_192_CCM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.27"); + pub const ID_AES_256_CBC: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.42"); + pub const ID_AES_256_WRAP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.45"); + pub const ID_AES_256_GCM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.46"); + pub const ID_AES_256_CCM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.47"); + pub const ID_AES_128_WRAP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.5"); + pub const ID_AES_128_GCM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.6"); + pub const ID_AES_128_CCM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.1.7"); +} +pub mod rfc5912 { + pub const ID_DSA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.10040.4.1"); + pub const DSA_WITH_SHA_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.10040.4.3"); + pub const ID_EC_PUBLIC_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.10045.2.1"); + pub const SECP_256_R_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.10045.3.1.7"); + pub const ECDSA_WITH_SHA_224: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.1"); + pub const ECDSA_WITH_SHA_256: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.2"); + pub const ECDSA_WITH_SHA_384: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.3"); + pub const ECDSA_WITH_SHA_512: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.4"); + pub const DHPUBLICNUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.10046.2.1"); + pub const ID_PASSWORD_BASED_MAC: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113533.7.66.13"); + pub const ID_DH_BASED_MAC: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113533.7.66.30"); + pub const PKCS_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1"); + pub const RSA_ENCRYPTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.1"); + pub const ID_RSASSA_PSS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.10"); + pub const SHA_256_WITH_RSA_ENCRYPTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.11"); + pub const SHA_384_WITH_RSA_ENCRYPTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.12"); + pub const SHA_512_WITH_RSA_ENCRYPTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.13"); + pub const SHA_224_WITH_RSA_ENCRYPTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.14"); + pub const MD_2_WITH_RSA_ENCRYPTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.2"); + pub const MD_5_WITH_RSA_ENCRYPTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.4"); + pub const SHA_1_WITH_RSA_ENCRYPTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.5"); + pub const ID_RSAES_OAEP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.7"); + pub const ID_MGF_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.8"); + pub const ID_P_SPECIFIED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.9"); + pub const PKCS_9: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9"); + pub const ID_EXTENSION_REQ: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.14"); + pub const ID_SMIME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16"); + pub const ID_CT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1"); + pub const ID_CT_SCVP_CERT_VAL_REQUEST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.10"); + pub const ID_CT_SCVP_CERT_VAL_RESPONSE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.11"); + pub const ID_CT_SCVP_VAL_POL_REQUEST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.12"); + pub const ID_CT_SCVP_VAL_POL_RESPONSE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.13"); + pub const ID_CT_ENC_KEY_WITH_ID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.21"); + pub const ID_AA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2"); + pub const ID_AA_CMC_UNSIGNED_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.34"); + pub const ID_MD_2: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.2.2"); + pub const ID_MD_5: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.2.5"); + pub const SECT_163_K_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.132.0.1"); + pub const SECT_163_R_2: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.132.0.15"); + pub const SECT_283_K_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.132.0.16"); + pub const SECT_283_R_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.132.0.17"); + pub const SECT_233_K_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.132.0.26"); + pub const SECT_233_R_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.132.0.27"); + pub const SECP_224_R_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.132.0.33"); + pub const SECP_384_R_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.132.0.34"); + pub const SECP_521_R_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.132.0.35"); + pub const SECT_409_K_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.132.0.36"); + pub const SECT_409_R_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.132.0.37"); + pub const SECT_571_K_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.132.0.38"); + pub const SECT_571_R_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.132.0.39"); + pub const ID_EC_DH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.132.1.12"); + pub const ID_EC_MQV: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.132.1.13"); + pub const ID_SHA_1: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.14.3.2.26"); + pub const ID_PKIX: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7"); + pub const ID_PE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.1"); + pub const ID_PE_AUTHORITY_INFO_ACCESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.1.1"); + pub const ID_PE_AC_PROXYING: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.1.10"); + pub const ID_PE_SUBJECT_INFO_ACCESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.1.11"); + pub const ID_PE_AC_AUDIT_IDENTITY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.1.4"); + pub const ID_PE_AA_CONTROLS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.1.6"); + pub const ID_ACA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.10"); + pub const ID_ACA_AUTHENTICATION_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.10.1"); + pub const ID_ACA_ACCESS_IDENTITY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.10.2"); + pub const ID_ACA_CHARGING_IDENTITY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.10.3"); + pub const ID_ACA_GROUP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.10.4"); + pub const ID_ACA_ENC_ATTRS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.10.6"); + pub const ID_CCT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.12"); + pub const ID_CCT_PKI_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.12.2"); + pub const ID_CCT_PKI_RESPONSE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.12.3"); + pub const ID_STC: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.17"); + pub const ID_STC_BUILD_PKC_PATH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.17.1"); + pub const ID_STC_BUILD_VALID_PKC_PATH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.17.2"); + pub const ID_STC_BUILD_STATUS_CHECKED_PKC_PATH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.17.3"); + pub const ID_STC_BUILD_AA_PATH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.17.4"); + pub const ID_STC_BUILD_VALID_AA_PATH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.17.5"); + pub const ID_STC_BUILD_STATUS_CHECKED_AA_PATH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.17.6"); + pub const ID_STC_STATUS_CHECK_AC_AND_BUILD_STATUS_CHECKED_AA_PATH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.17.7"); + pub const ID_SWB: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.18"); + pub const ID_SWB_PKC_BEST_CERT_PATH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.18.1"); + pub const ID_SWB_PKC_CERT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.18.10"); + pub const ID_SWB_AC_CERT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.18.11"); + pub const ID_SWB_PKC_ALL_CERT_PATHS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.18.12"); + pub const ID_SWB_PKC_EE_REVOCATION_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.18.13"); + pub const ID_SWB_PKC_C_AS_REVOCATION_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.18.14"); + pub const ID_SWB_PKC_REVOCATION_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.18.2"); + pub const ID_SWB_PKC_PUBLIC_KEY_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.18.4"); + pub const ID_SWB_AA_CERT_PATH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.18.5"); + pub const ID_SWB_AA_REVOCATION_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.18.6"); + pub const ID_SWB_AC_REVOCATION_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.18.7"); + pub const ID_SWB_RELAYED_RESPONSES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.18.9"); + pub const ID_SVP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.19"); + pub const ID_SVP_DEFAULT_VAL_POLICY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.19.1"); + pub const ID_SVP_NAME_VAL_ALG: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.19.2"); + pub const ID_SVP_BASIC_VAL_ALG: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.19.3"); + pub const NAME_COMP_ALG_SET: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.19.4"); + pub const ID_NVA_DN_COMP_ALG: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.19.4"); + pub const ID_QT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.2"); + pub const ID_QT_CPS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.2.1"); + pub const ID_QT_UNOTICE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.2.2"); + pub const ID_KP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3"); + pub const ID_KP_SERVER_AUTH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3.1"); + pub const ID_KP_SCVP_SERVER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3.15"); + pub const ID_KP_SCVP_CLIENT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3.16"); + pub const ID_KP_CLIENT_AUTH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3.2"); + pub const ID_KP_CODE_SIGNING: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3.3"); + pub const ID_KP_EMAIL_PROTECTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3.4"); + pub const ID_KP_TIME_STAMPING: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3.8"); + pub const ID_KP_OCSP_SIGNING: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3.9"); + pub const ID_IT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.4"); + pub const ID_IT_CA_PROT_ENC_CERT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.4.1"); + pub const ID_IT_KEY_PAIR_PARAM_REQ: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.4.10"); + pub const ID_IT_KEY_PAIR_PARAM_REP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.4.11"); + pub const ID_IT_REV_PASSPHRASE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.4.12"); + pub const ID_IT_IMPLICIT_CONFIRM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.4.13"); + pub const ID_IT_CONFIRM_WAIT_TIME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.4.14"); + pub const ID_IT_ORIG_PKI_MESSAGE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.4.15"); + pub const ID_IT_SUPP_LANG_TAGS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.4.16"); + pub const ID_IT_SIGN_KEY_PAIR_TYPES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.4.2"); + pub const ID_IT_ENC_KEY_PAIR_TYPES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.4.3"); + pub const ID_IT_PREFERRED_SYMM_ALG: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.4.4"); + pub const ID_IT_CA_KEY_UPDATE_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.4.5"); + pub const ID_IT_CURRENT_CRL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.4.6"); + pub const ID_IT_UNSUPPORTED_OI_DS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.4.7"); + pub const ID_AD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48"); + pub const ID_AD_OCSP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1"); + pub const ID_AD_CA_ISSUERS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.2"); + pub const ID_AD_TIME_STAMPING: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.3"); + pub const ID_AD_CA_REPOSITORY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.5"); + pub const ID_PKIP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.5"); + pub const ID_REG_CTRL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.5.1"); + pub const ID_REG_CTRL_REG_TOKEN: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.5.1.1"); + pub const ID_REG_CTRL_AUTHENTICATOR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.5.1.2"); + pub const ID_REG_CTRL_PKI_PUBLICATION_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.5.1.3"); + pub const ID_REG_CTRL_PKI_ARCHIVE_OPTIONS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.5.1.4"); + pub const ID_REG_CTRL_OLD_CERT_ID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.5.1.5"); + pub const ID_REG_CTRL_PROTOCOL_ENCR_KEY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.5.1.6"); + pub const ID_REG_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.5.2"); + pub const ID_REG_INFO_UTF_8_PAIRS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.5.2.1"); + pub const ID_REG_INFO_CERT_REQ: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.5.2.2"); + pub const ID_ALG_NO_SIGNATURE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.6.2"); + pub const ID_CMC: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7"); + pub const ID_CMC_STATUS_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.1"); + pub const ID_CMC_DECRYPTED_POP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.10"); + pub const ID_CMC_LRA_POP_WITNESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.11"); + pub const ID_CMC_GET_CERT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.15"); + pub const ID_CMC_GET_CRL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.16"); + pub const ID_CMC_REVOKE_REQUEST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.17"); + pub const ID_CMC_REG_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.18"); + pub const ID_CMC_RESPONSE_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.19"); + pub const ID_CMC_IDENTIFICATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.2"); + pub const ID_CMC_QUERY_PENDING: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.21"); + pub const ID_CMC_POP_LINK_RANDOM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.22"); + pub const ID_CMC_POP_LINK_WITNESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.23"); + pub const ID_CMC_CONFIRM_CERT_ACCEPTANCE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.24"); + pub const ID_CMC_STATUS_INFO_V_2: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.25"); + pub const ID_CMC_TRUSTED_ANCHORS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.26"); + pub const ID_CMC_AUTH_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.27"); + pub const ID_CMC_BATCH_REQUESTS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.28"); + pub const ID_CMC_BATCH_RESPONSES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.29"); + pub const ID_CMC_IDENTITY_PROOF: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.3"); + pub const ID_CMC_PUBLISH_CERT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.30"); + pub const ID_CMC_MOD_CERT_TEMPLATE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.31"); + pub const ID_CMC_CONTROL_PROCESSED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.32"); + pub const ID_CMC_IDENTITY_PROOF_V_2: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.33"); + pub const ID_CMC_POP_LINK_WITNESS_V_2: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.34"); + pub const ID_CMC_DATA_RETURN: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.4"); + pub const ID_CMC_TRANSACTION_ID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.5"); + pub const ID_CMC_SENDER_NONCE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.6"); + pub const ID_CMC_RECIPIENT_NONCE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.7"); + pub const ID_CMC_ADD_EXTENSIONS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.8"); + pub const ID_CMC_ENCRYPTED_POP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.9"); + pub const ID_KEY_EXCHANGE_ALGORITHM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.2.1.1.22"); + pub const ID_SHA_256: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.1"); + pub const ID_SHA_384: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.2"); + pub const ID_SHA_512: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.3"); + pub const ID_SHA_224: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.4"); + pub const DSA_WITH_SHA_224: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.3.1"); + pub const DSA_WITH_SHA_256: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.3.2"); + pub const HOLD_INSTRUCTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.2.840.10040.2"); + pub const ID_HOLDINSTRUCTION_NONE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.2.840.10040.2.1"); + pub const ID_HOLDINSTRUCTION_CALLISSUER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.2.840.10040.2.2"); + pub const ID_HOLDINSTRUCTION_REJECT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.2.840.10040.2.3"); + pub const ID_CE: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.29"); + pub const ID_CE_SUBJECT_KEY_IDENTIFIER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.14"); + pub const ID_CE_KEY_USAGE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.15"); + pub const ID_CE_PRIVATE_KEY_USAGE_PERIOD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.16"); + pub const ID_CE_SUBJECT_ALT_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.17"); + pub const ID_CE_ISSUER_ALT_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.18"); + pub const ID_CE_BASIC_CONSTRAINTS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.19"); + pub const ID_CE_CRL_NUMBER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.20"); + pub const ID_CE_CRL_REASONS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.21"); + pub const ID_CE_HOLD_INSTRUCTION_CODE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.23"); + pub const ID_CE_INVALIDITY_DATE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.24"); + pub const ID_CE_DELTA_CRL_INDICATOR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.27"); + pub const ID_CE_ISSUING_DISTRIBUTION_POINT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.28"); + pub const ID_CE_CERTIFICATE_ISSUER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.29"); + pub const ID_CE_NAME_CONSTRAINTS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.30"); + pub const ID_CE_CRL_DISTRIBUTION_POINTS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.31"); + pub const ID_CE_CERTIFICATE_POLICIES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.32"); + pub const ID_CE_POLICY_MAPPINGS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.33"); + pub const ID_CE_AUTHORITY_KEY_IDENTIFIER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.35"); + pub const ID_CE_POLICY_CONSTRAINTS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.36"); + pub const ID_CE_EXT_KEY_USAGE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.37"); + pub const ANY_EXTENDED_KEY_USAGE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.37.0"); + pub const ID_CE_FRESHEST_CRL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.46"); + pub const ID_CE_INHIBIT_ANY_POLICY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.54"); + pub const ID_CE_TARGET_INFORMATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.55"); + pub const ID_CE_NO_REV_AVAIL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.56"); + pub const ID_CE_SUBJECT_DIRECTORY_ATTRIBUTES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.5.29.9"); + pub const ID_AT: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4"); + pub const ID_AT_ROLE: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("2.5.4.72"); +} +pub mod rfc6109 { + pub const LDIF_LOCATION_URL_OBJECT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.16572.2.1.1"); + pub const PROVIDER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.16572.2.1.2"); + pub const PROVIDER_CERTIFICATE_HASH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.16572.2.2.1"); + pub const PROVIDER_CERTIFICATE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.16572.2.2.2"); + pub const PROVIDER_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.16572.2.2.3"); + pub const MAIL_RECEIPT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.16572.2.2.4"); + pub const MANAGED_DOMAINS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.16572.2.2.5"); + pub const LDIF_LOCATION_URL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.16572.2.2.6"); + pub const PROVIDER_UNIT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.16572.2.2.7"); +} +pub mod rfc6268 { + pub const RSADSI: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549"); + pub const ID_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.7.1"); + pub const ID_SIGNED_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.7.2"); + pub const ID_ENVELOPED_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.7.3"); + pub const ID_DIGESTED_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.7.5"); + pub const ID_ENCRYPTED_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.7.6"); + pub const ID_CT_CONTENT_COLLECTION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.19"); + pub const ID_CT_AUTH_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.2"); + pub const ID_CT_CONTENT_WITH_ATTRS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.20"); + pub const ID_CT_AUTH_ENVELOPED_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.23"); + pub const ID_CT_CONTENT_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.6"); + pub const ID_CT_COMPRESSED_DATA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.9"); + pub const ID_AA_BINARY_SIGNING_TIME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2.46"); + pub const ID_ALG_ZLIB_COMPRESS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.3.8"); + pub const ID_AA_MULTIPLE_SIGNATURES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.2.51"); + pub const ID_CONTENT_TYPE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.3"); + pub const ID_MESSAGE_DIGEST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.4"); + pub const ID_SIGNING_TIME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.5"); + pub const ID_COUNTERSIGNATURE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.6"); + pub const DIGEST_ALGORITHM: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.2"); + pub const ID_HMAC_WITH_SHA_384: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.2.10"); + pub const ID_HMAC_WITH_SHA_512: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.2.11"); + pub const ID_HMAC_WITH_SHA_224: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.2.8"); + pub const ID_HMAC_WITH_SHA_256: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.2.9"); +} +pub mod rfc6960 { + pub const ID_PKIX_OCSP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1"); + pub const ID_PKIX_OCSP_BASIC: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.1"); + pub const ID_PKIX_OCSP_NONCE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.2"); + pub const ID_PKIX_OCSP_CRL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.3"); + pub const ID_PKIX_OCSP_RESPONSE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.4"); + pub const ID_PKIX_OCSP_NOCHECK: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.5"); + pub const ID_PKIX_OCSP_ARCHIVE_CUTOFF: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.6"); + pub const ID_PKIX_OCSP_SERVICE_LOCATOR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.7"); + pub const ID_PKIX_OCSP_PREF_SIG_ALGS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.8"); + pub const ID_PKIX_OCSP_EXTENDED_REVOKE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.9"); +} +pub mod rfc6962 { + pub const GOOGLE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11129"); + pub const CT_PRECERT_SCTS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11129.2.4.2"); + pub const CT_PRECERT_POISON: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11129.2.4.3"); + pub const CT_PRECERT_SIGNING_CERT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.11129.2.4.4"); +} +pub mod rfc7107 { + pub const ID_SMIME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16"); + pub const ID_MOD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.0"); + pub const ID_CT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1"); + pub const ID_EIT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.10"); + pub const ID_CAP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.11"); + pub const ID_PSKC: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.12"); + pub const ID_AA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.2"); + pub const ID_ALG: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.3"); + pub const ID_CD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.4"); + pub const ID_SPQ: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.5"); + pub const ID_CTI: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.6"); + pub const ID_TSP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.7"); + pub const ID_SKD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.8"); + pub const ID_STI: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.9"); +} +pub mod rfc7299 { + pub const ID_PKIX: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7"); + pub const ID_MOD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.0"); + pub const ID_PE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.1"); + pub const ID_ACA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.10"); + pub const ID_QCS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.11"); + pub const ID_CCT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.12"); + pub const ID_TEST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.13"); + pub const ID_CP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.14"); + pub const ID_CET: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.15"); + pub const ID_RI: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.16"); + pub const ID_SCT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.17"); + pub const ID_SWB: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.18"); + pub const ID_SVP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.19"); + pub const ID_NVAE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.19.2"); + pub const ID_BVAE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.19.3"); + pub const ID_DNVAE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.19.4"); + pub const ID_QT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.2"); + pub const ID_LOGO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.20"); + pub const ID_PPL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.21"); + pub const ID_MR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.22"); + pub const ID_SKIS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.23"); + pub const ID_KP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3"); + pub const ID_IT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.4"); + pub const ID_AD: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48"); + pub const ID_PKIX_OCSP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1"); + pub const ID_PKIP: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.5"); + pub const ID_REG_CTRL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.5.1"); + pub const ID_REG_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.5.2"); + pub const ID_ALG: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.6"); + pub const ID_CMC: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7"); + pub const ID_CMC_GLA_RR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.7.99"); + pub const ID_ON: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.8"); + pub const ID_PDA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.9"); +} +pub mod rfc7532 { + pub const FEDFS_UUID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.1"); + pub const FEDFS_FSL_PORT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.10"); + pub const FEDFS_NFS_PATH: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.100"); + pub const FEDFS_NSDB_CONTAINER_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.1001"); + pub const FEDFS_FSN: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.1002"); + pub const FEDFS_FSL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.1003"); + pub const FEDFS_NFS_FSL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.1004"); + pub const FEDFS_NFS_MAJOR_VER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.101"); + pub const FEDFS_NFS_MINOR_VER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.102"); + pub const FEDFS_NFS_CURRENCY: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.103"); + pub const FEDFS_NFS_GEN_FLAG_WRITABLE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.104"); + pub const FEDFS_NFS_GEN_FLAG_GOING: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.105"); + pub const FEDFS_NFS_GEN_FLAG_SPLIT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.106"); + pub const FEDFS_NFS_TRANS_FLAG_RDMA: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.107"); + pub const FEDFS_NFS_CLASS_SIMUL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.108"); + pub const FEDFS_NFS_CLASS_HANDLE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.109"); + pub const FEDFS_FSL_TTL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.11"); + pub const FEDFS_NFS_CLASS_FILEID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.110"); + pub const FEDFS_NFS_CLASS_WRITEVER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.111"); + pub const FEDFS_NFS_CLASS_CHANGE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.112"); + pub const FEDFS_NFS_CLASS_READDIR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.113"); + pub const FEDFS_NFS_READ_RANK: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.114"); + pub const FEDFS_NFS_READ_ORDER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.115"); + pub const FEDFS_NFS_WRITE_RANK: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.116"); + pub const FEDFS_NFS_WRITE_ORDER: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.117"); + pub const FEDFS_NFS_VAR_SUB: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.118"); + pub const FEDFS_NFS_VALID_FOR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.119"); + pub const FEDFS_ANNOTATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.12"); + pub const FEDFS_NFS_URI: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.120"); + pub const FEDFS_DESCR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.13"); + pub const FEDFS_NCE_DN: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.14"); + pub const FEDFS_FSN_TTL: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.15"); + pub const FEDFS_NET_ADDR: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.2"); + pub const FEDFS_NET_PORT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.3"); + pub const FEDFS_FSN_UUID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.4"); + pub const FEDFS_NSDB_NAME: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.5"); + pub const FEDFS_NSDB_PORT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.6"); + pub const FEDFS_NCE_PREFIX: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.7"); + pub const FEDFS_FSL_UUID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.8"); + pub const FEDFS_FSL_HOST: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.4.1.31103.1.9"); +} +pub mod rfc7612 { + pub const PRINTER_DEVICE_ID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.24.46.1.101"); + pub const PRINTER_DEVICE_SERVICE_COUNT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.24.46.1.102"); + pub const PRINTER_UUID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.24.46.1.104"); + pub const PRINTER_CHARGE_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.24.46.1.105"); + pub const PRINTER_CHARGE_INFO_URI: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.24.46.1.106"); + pub const PRINTER_GEO_LOCATION: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.24.46.1.107"); + pub const PRINTER_IPP_FEATURES_SUPPORTED: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.18.0.2.24.46.1.108"); +} +pub mod rfc8284 { + pub const JID_OBJECT: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.23.1"); + pub const JID: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap("1.3.6.1.1.23.2"); +} +pub mod rfc8410 { + pub const ID_EDWARDS_CURVE_ALGS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.101"); + pub const ID_X_25519: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.101.110"); + pub const ID_X_448: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.101.111"); + pub const ID_ED_25519: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.101.112"); + pub const ID_ED_448: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("1.3.101.113"); +} +pub mod rfc8894 { + pub const ID_VERI_SIGN: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113733"); + pub const ID_PKI: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113733.1"); + pub const ID_ATTRIBUTES: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113733.1.9"); + pub const ID_MESSAGE_TYPE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113733.1.9.2"); + pub const ID_PKI_STATUS: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113733.1.9.3"); + pub const ID_FAIL_INFO: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113733.1.9.4"); + pub const ID_SENDER_NONCE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113733.1.9.5"); + pub const ID_RECIPIENT_NONCE: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113733.1.9.6"); + pub const ID_TRANSACTION_ID: crate::ObjectIdentifier = + crate::ObjectIdentifier::new_unwrap("2.16.840.1.113733.1.9.7"); +} +pub const DB: super::Database<'static> = super::Database(&[ + (&rfc1274::TEXT_ENCODED_OR_ADDRESS, "textEncodedORAddress"), + (&rfc1274::OTHER_MAILBOX, "otherMailbox"), + (&rfc1274::LAST_MODIFIED_TIME, "lastModifiedTime"), + (&rfc1274::LAST_MODIFIED_BY, "lastModifiedBy"), + (&rfc1274::A_RECORD, "aRecord"), + (&rfc1274::MD_RECORD, "mDRecord"), + (&rfc1274::MX_RECORD, "mXRecord"), + (&rfc1274::NS_RECORD, "nSRecord"), + (&rfc1274::SOA_RECORD, "sOARecord"), + (&rfc1274::CNAME_RECORD, "cNAMERecord"), + (&rfc1274::JANET_MAILBOX, "janetMailbox"), + (&rfc1274::MAIL_PREFERENCE_OPTION, "mailPreferenceOption"), + (&rfc1274::DSA_QUALITY, "dSAQuality"), + (&rfc1274::SUBTREE_MINIMUM_QUALITY, "subtreeMinimumQuality"), + (&rfc1274::SUBTREE_MAXIMUM_QUALITY, "subtreeMaximumQuality"), + (&rfc1274::PERSONAL_SIGNATURE, "personalSignature"), + (&rfc1274::DIT_REDIRECT, "dITRedirect"), + (&rfc1274::AUDIO, "audio"), + (&rfc1274::PHOTO, "photo"), + (&rfc1274::DNS_DOMAIN, "dNSDomain"), + (&rfc1274::PILOT_ORGANIZATION, "pilotOrganization"), + (&rfc1274::PILOT_DSA, "pilotDSA"), + (&rfc1274::QUALITY_LABELLED_DATA, "qualityLabelledData"), + (&rfc1274::PILOT_OBJECT, "pilotObject"), + (&rfc1274::PILOT_PERSON, "pilotPerson"), + (&rfc2079::LABELED_URI, "labeledURI"), + (&rfc2079::LABELED_URI_OBJECT, "labeledURIObject"), + (&rfc2164::RFC_822_TO_X_400_MAPPING, "rFC822ToX400Mapping"), + (&rfc2164::X_400_TO_RFC_822_MAPPING, "x400ToRFC822Mapping"), + ( + &rfc2164::OMITTED_OR_ADDRESS_COMPONENT, + "omittedORAddressComponent", + ), + (&rfc2164::MIXER_GATEWAY, "mixerGateway"), + (&rfc2164::ASSOCIATED_X_400_GATEWAY, "associatedX400Gateway"), + (&rfc2164::ASSOCIATED_OR_ADDRESS, "associatedORAddress"), + ( + &rfc2164::OR_ADDRESS_COMPONENT_TYPE, + "oRAddressComponentType", + ), + ( + &rfc2164::ASSOCIATED_INTERNET_GATEWAY, + "associatedInternetGateway", + ), + (&rfc2164::MCGAM_TABLES, "mcgamTables"), + (&rfc2247::DOMAIN_NAME_FORM, "domainNameForm"), + ( + &rfc2252::PRESENTATION_ADDRESS_MATCH, + "presentationAddressMatch", + ), + ( + &rfc2252::PROTOCOL_INFORMATION_MATCH, + "protocolInformationMatch", + ), + (&rfc2256::KNOWLEDGE_INFORMATION, "knowledgeInformation"), + (&rfc2256::PRESENTATION_ADDRESS, "presentationAddress"), + ( + &rfc2256::SUPPORTED_APPLICATION_CONTEXT, + "supportedApplicationContext", + ), + (&rfc2256::PROTOCOL_INFORMATION, "protocolInformation"), + (&rfc2256::DMD_NAME, "dmdName"), + (&rfc2256::STATE_OR_PROVINCE_NAME, "stateOrProvinceName"), + (&rfc2256::STREET_ADDRESS, "streetAddress"), + (&rfc2256::APPLICATION_ENTITY, "applicationEntity"), + (&rfc2256::DSA, "dSA"), + (&rfc2256::DMD, "dmd"), + (&rfc2293::SUBTREE, "subtree"), + (&rfc2293::TABLE, "table"), + (&rfc2293::TABLE_ENTRY, "tableEntry"), + (&rfc2293::TEXT_TABLE_ENTRY, "textTableEntry"), + ( + &rfc2293::DISTINGUISHED_NAME_TABLE_ENTRY, + "distinguishedNameTableEntry", + ), + (&rfc2293::TEXT_TABLE_KEY, "textTableKey"), + (&rfc2293::TEXT_TABLE_VALUE, "textTableValue"), + ( + &rfc2293::DISTINGUISHED_NAME_TABLE_KEY, + "distinguishedNameTableKey", + ), + (&rfc2589::DYNAMIC_OBJECT, "dynamicObject"), + (&rfc2589::ENTRY_TTL, "entryTtl"), + (&rfc2589::DYNAMIC_SUBTREES, "dynamicSubtrees"), + (&rfc2739::CAL_CAL_URI, "calCalURI"), + (&rfc2739::CAL_FBURL, "calFBURL"), + (&rfc2739::CAL_CAPURI, "calCAPURI"), + (&rfc2739::CAL_CAL_ADR_URI, "calCalAdrURI"), + (&rfc2739::CAL_OTHER_CAL_UR_IS, "calOtherCalURIs"), + (&rfc2739::CAL_OTHER_FBUR_LS, "calOtherFBURLs"), + (&rfc2739::CAL_OTHER_CAPUR_IS, "calOtherCAPURIs"), + (&rfc2739::CAL_OTHER_CAL_ADR_UR_IS, "calOtherCalAdrURIs"), + (&rfc2739::CAL_ENTRY, "calEntry"), + (&rfc2798::JPEG_PHOTO, "jpegPhoto"), + (&rfc2798::CAR_LICENSE, "carLicense"), + (&rfc2798::DEPARTMENT_NUMBER, "departmentNumber"), + (&rfc2798::USER_PKCS_12, "userPKCS12"), + (&rfc2798::DISPLAY_NAME, "displayName"), + (&rfc2798::EMPLOYEE_NUMBER, "employeeNumber"), + (&rfc2798::PREFERRED_LANGUAGE, "preferredLanguage"), + (&rfc2798::EMPLOYEE_TYPE, "employeeType"), + (&rfc2798::USER_SMIME_CERTIFICATE, "userSMIMECertificate"), + (&rfc2798::INET_ORG_PERSON, "inetOrgPerson"), + (&rfc3280::EMAIL, "email"), + (&rfc3280::EMAIL_ADDRESS, "emailAddress"), + (&rfc3280::PSEUDONYM, "pseudonym"), + (&rfc3296::REF, "ref"), + (&rfc3296::REFERRAL, "referral"), + ( + &rfc3671::COLLECTIVE_ATTRIBUTE_SUBENTRIES, + "collectiveAttributeSubentries", + ), + (&rfc3671::COLLECTIVE_EXCLUSIONS, "collectiveExclusions"), + ( + &rfc3671::COLLECTIVE_ATTRIBUTE_SUBENTRY, + "collectiveAttributeSubentry", + ), + (&rfc3671::C_O, "c-o"), + (&rfc3671::C_OU, "c-ou"), + (&rfc3671::C_POSTAL_ADDRESS, "c-PostalAddress"), + (&rfc3671::C_POSTAL_CODE, "c-PostalCode"), + (&rfc3671::C_POST_OFFICE_BOX, "c-PostOfficeBox"), + ( + &rfc3671::C_PHYSICAL_DELIVERY_OFFICE, + "c-PhysicalDeliveryOffice", + ), + (&rfc3671::C_TELEPHONE_NUMBER, "c-TelephoneNumber"), + (&rfc3671::C_TELEX_NUMBER, "c-TelexNumber"), + ( + &rfc3671::C_FACSIMILE_TELEPHONE_NUMBER, + "c-FacsimileTelephoneNumber", + ), + ( + &rfc3671::C_INTERNATIONAL_ISDN_NUMBER, + "c-InternationalISDNNumber", + ), + (&rfc3671::C_L, "c-l"), + (&rfc3671::C_ST, "c-st"), + (&rfc3671::C_STREET, "c-street"), + (&rfc3672::SUBENTRY, "subentry"), + (&rfc3672::ADMINISTRATIVE_ROLE, "administrativeRole"), + (&rfc3672::SUBTREE_SPECIFICATION, "subtreeSpecification"), + (&rfc3672::AUTONOMOUS_AREA, "autonomousArea"), + ( + &rfc3672::ACCESS_CONTROL_SPECIFIC_AREA, + "accessControlSpecificArea", + ), + ( + &rfc3672::ACCESS_CONTROL_INNER_AREA, + "accessControlInnerArea", + ), + ( + &rfc3672::SUBSCHEMA_ADMIN_SPECIFIC_AREA, + "subschemaAdminSpecificArea", + ), + ( + &rfc3672::COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA, + "collectiveAttributeSpecificArea", + ), + ( + &rfc3672::COLLECTIVE_ATTRIBUTE_INNER_AREA, + "collectiveAttributeInnerArea", + ), + (&rfc3687::COMPONENT_FILTER_MATCH, "componentFilterMatch"), + (&rfc3687::RDN_MATCH, "rdnMatch"), + (&rfc3687::PRESENT_MATCH, "presentMatch"), + (&rfc3687::ALL_COMPONENTS_MATCH, "allComponentsMatch"), + ( + &rfc3687::DIRECTORY_COMPONENTS_MATCH, + "directoryComponentsMatch", + ), + (&rfc3698::STORED_PREFIX_MATCH, "storedPrefixMatch"), + (&rfc3703::PCIM_POLICY, "pcimPolicy"), + ( + &rfc3703::PCIM_RULE_ACTION_ASSOCIATION, + "pcimRuleActionAssociation", + ), + (&rfc3703::PCIM_CONDITION_AUX_CLASS, "pcimConditionAuxClass"), + (&rfc3703::PCIM_TPC_AUX_CLASS, "pcimTPCAuxClass"), + ( + &rfc3703::PCIM_CONDITION_VENDOR_AUX_CLASS, + "pcimConditionVendorAuxClass", + ), + (&rfc3703::PCIM_ACTION_AUX_CLASS, "pcimActionAuxClass"), + ( + &rfc3703::PCIM_ACTION_VENDOR_AUX_CLASS, + "pcimActionVendorAuxClass", + ), + (&rfc3703::PCIM_POLICY_INSTANCE, "pcimPolicyInstance"), + (&rfc3703::PCIM_ELEMENT_AUX_CLASS, "pcimElementAuxClass"), + (&rfc3703::PCIM_REPOSITORY, "pcimRepository"), + ( + &rfc3703::PCIM_REPOSITORY_AUX_CLASS, + "pcimRepositoryAuxClass", + ), + (&rfc3703::PCIM_GROUP, "pcimGroup"), + (&rfc3703::PCIM_REPOSITORY_INSTANCE, "pcimRepositoryInstance"), + ( + &rfc3703::PCIM_SUBTREES_PTR_AUX_CLASS, + "pcimSubtreesPtrAuxClass", + ), + ( + &rfc3703::PCIM_GROUP_CONTAINMENT_AUX_CLASS, + "pcimGroupContainmentAuxClass", + ), + ( + &rfc3703::PCIM_RULE_CONTAINMENT_AUX_CLASS, + "pcimRuleContainmentAuxClass", + ), + (&rfc3703::PCIM_GROUP_AUX_CLASS, "pcimGroupAuxClass"), + (&rfc3703::PCIM_GROUP_INSTANCE, "pcimGroupInstance"), + (&rfc3703::PCIM_RULE, "pcimRule"), + (&rfc3703::PCIM_RULE_AUX_CLASS, "pcimRuleAuxClass"), + (&rfc3703::PCIM_RULE_INSTANCE, "pcimRuleInstance"), + ( + &rfc3703::PCIM_RULE_CONDITION_ASSOCIATION, + "pcimRuleConditionAssociation", + ), + ( + &rfc3703::PCIM_RULE_VALIDITY_ASSOCIATION, + "pcimRuleValidityAssociation", + ), + ( + &rfc3703::PCIM_RULE_VALIDITY_PERIOD_LIST, + "pcimRuleValidityPeriodList", + ), + (&rfc3703::PCIM_RULE_USAGE, "pcimRuleUsage"), + (&rfc3703::PCIM_RULE_PRIORITY, "pcimRulePriority"), + (&rfc3703::PCIM_RULE_MANDATORY, "pcimRuleMandatory"), + ( + &rfc3703::PCIM_RULE_SEQUENCED_ACTIONS, + "pcimRuleSequencedActions", + ), + (&rfc3703::PCIM_ROLES, "pcimRoles"), + ( + &rfc3703::PCIM_CONDITION_GROUP_NUMBER, + "pcimConditionGroupNumber", + ), + (&rfc3703::PCIM_CONDITION_NEGATED, "pcimConditionNegated"), + (&rfc3703::PCIM_CONDITION_NAME, "pcimConditionName"), + (&rfc3703::PCIM_CONDITION_DN, "pcimConditionDN"), + ( + &rfc3703::PCIM_VALIDITY_CONDITION_NAME, + "pcimValidityConditionName", + ), + ( + &rfc3703::PCIM_TIME_PERIOD_CONDITION_DN, + "pcimTimePeriodConditionDN", + ), + (&rfc3703::PCIM_ACTION_NAME, "pcimActionName"), + (&rfc3703::PCIM_ACTION_ORDER, "pcimActionOrder"), + (&rfc3703::PCIM_ACTION_DN, "pcimActionDN"), + (&rfc3703::PCIM_TPC_TIME, "pcimTPCTime"), + ( + &rfc3703::PCIM_TPC_MONTH_OF_YEAR_MASK, + "pcimTPCMonthOfYearMask", + ), + ( + &rfc3703::PCIM_TPC_DAY_OF_MONTH_MASK, + "pcimTPCDayOfMonthMask", + ), + (&rfc3703::PCIM_TPC_DAY_OF_WEEK_MASK, "pcimTPCDayOfWeekMask"), + (&rfc3703::PCIM_TPC_TIME_OF_DAY_MASK, "pcimTPCTimeOfDayMask"), + (&rfc3703::PCIM_KEYWORDS, "pcimKeywords"), + ( + &rfc3703::PCIM_TPC_LOCAL_OR_UTC_TIME, + "pcimTPCLocalOrUtcTime", + ), + ( + &rfc3703::PCIM_VENDOR_CONSTRAINT_DATA, + "pcimVendorConstraintData", + ), + ( + &rfc3703::PCIM_VENDOR_CONSTRAINT_ENCODING, + "pcimVendorConstraintEncoding", + ), + (&rfc3703::PCIM_VENDOR_ACTION_DATA, "pcimVendorActionData"), + ( + &rfc3703::PCIM_VENDOR_ACTION_ENCODING, + "pcimVendorActionEncoding", + ), + ( + &rfc3703::PCIM_POLICY_INSTANCE_NAME, + "pcimPolicyInstanceName", + ), + (&rfc3703::PCIM_REPOSITORY_NAME, "pcimRepositoryName"), + ( + &rfc3703::PCIM_SUBTREES_AUX_CONTAINED_SET, + "pcimSubtreesAuxContainedSet", + ), + ( + &rfc3703::PCIM_GROUPS_AUX_CONTAINED_SET, + "pcimGroupsAuxContainedSet", + ), + ( + &rfc3703::PCIM_RULES_AUX_CONTAINED_SET, + "pcimRulesAuxContainedSet", + ), + (&rfc3703::PCIM_GROUP_NAME, "pcimGroupName"), + (&rfc3703::PCIM_RULE_NAME, "pcimRuleName"), + (&rfc3703::PCIM_RULE_ENABLED, "pcimRuleEnabled"), + ( + &rfc3703::PCIM_RULE_CONDITION_LIST_TYPE, + "pcimRuleConditionListType", + ), + (&rfc3703::PCIM_RULE_CONDITION_LIST, "pcimRuleConditionList"), + (&rfc3703::PCIM_RULE_ACTION_LIST, "pcimRuleActionList"), + (&rfc3712::PRINTER_XRI_SUPPORTED, "printer-xri-supported"), + (&rfc3712::PRINTER_ALIASES, "printer-aliases"), + ( + &rfc3712::PRINTER_CHARSET_CONFIGURED, + "printer-charset-configured", + ), + ( + &rfc3712::PRINTER_JOB_PRIORITY_SUPPORTED, + "printer-job-priority-supported", + ), + ( + &rfc3712::PRINTER_JOB_K_OCTETS_SUPPORTED, + "printer-job-k-octets-supported", + ), + ( + &rfc3712::PRINTER_CURRENT_OPERATOR, + "printer-current-operator", + ), + (&rfc3712::PRINTER_SERVICE_PERSON, "printer-service-person"), + ( + &rfc3712::PRINTER_DELIVERY_ORIENTATION_SUPPORTED, + "printer-delivery-orientation-supported", + ), + ( + &rfc3712::PRINTER_STACKING_ORDER_SUPPORTED, + "printer-stacking-order-supported", + ), + ( + &rfc3712::PRINTER_OUTPUT_FEATURES_SUPPORTED, + "printer-output-features-supported", + ), + ( + &rfc3712::PRINTER_MEDIA_LOCAL_SUPPORTED, + "printer-media-local-supported", + ), + ( + &rfc3712::PRINTER_COPIES_SUPPORTED, + "printer-copies-supported", + ), + ( + &rfc3712::PRINTER_NATURAL_LANGUAGE_CONFIGURED, + "printer-natural-language-configured", + ), + ( + &rfc3712::PRINTER_PRINT_QUALITY_SUPPORTED, + "printer-print-quality-supported", + ), + ( + &rfc3712::PRINTER_RESOLUTION_SUPPORTED, + "printer-resolution-supported", + ), + (&rfc3712::PRINTER_MEDIA_SUPPORTED, "printer-media-supported"), + (&rfc3712::PRINTER_SIDES_SUPPORTED, "printer-sides-supported"), + ( + &rfc3712::PRINTER_NUMBER_UP_SUPPORTED, + "printer-number-up-supported", + ), + ( + &rfc3712::PRINTER_FINISHINGS_SUPPORTED, + "printer-finishings-supported", + ), + ( + &rfc3712::PRINTER_PAGES_PER_MINUTE_COLOR, + "printer-pages-per-minute-color", + ), + ( + &rfc3712::PRINTER_PAGES_PER_MINUTE, + "printer-pages-per-minute", + ), + ( + &rfc3712::PRINTER_COMPRESSION_SUPPORTED, + "printer-compression-supported", + ), + (&rfc3712::PRINTER_COLOR_SUPPORTED, "printer-color-supported"), + ( + &rfc3712::PRINTER_DOCUMENT_FORMAT_SUPPORTED, + "printer-document-format-supported", + ), + ( + &rfc3712::PRINTER_CHARSET_SUPPORTED, + "printer-charset-supported", + ), + ( + &rfc3712::PRINTER_MULTIPLE_DOCUMENT_JOBS_SUPPORTED, + "printer-multiple-document-jobs-supported", + ), + ( + &rfc3712::PRINTER_IPP_VERSIONS_SUPPORTED, + "printer-ipp-versions-supported", + ), + (&rfc3712::PRINTER_MORE_INFO, "printer-more-info"), + (&rfc3712::PRINTER_NAME, "printer-name"), + (&rfc3712::PRINTER_LOCATION, "printer-location"), + ( + &rfc3712::PRINTER_GENERATED_NATURAL_LANGUAGE_SUPPORTED, + "printer-generated-natural-language-supported", + ), + (&rfc3712::PRINTER_MAKE_AND_MODEL, "printer-make-and-model"), + (&rfc3712::PRINTER_INFO, "printer-info"), + (&rfc3712::PRINTER_URI, "printer-uri"), + (&rfc3712::PRINTER_LPR, "printerLPR"), + (&rfc3712::SLP_SERVICE_PRINTER, "slpServicePrinter"), + (&rfc3712::PRINTER_SERVICE, "printerService"), + (&rfc3712::PRINTER_IPP, "printerIPP"), + ( + &rfc3712::PRINTER_SERVICE_AUX_CLASS, + "printerServiceAuxClass", + ), + (&rfc3712::PRINTER_ABSTRACT, "printerAbstract"), + (&rfc4104::PCELS_POLICY_SET, "pcelsPolicySet"), + (&rfc4104::PCELS_ACTION_ASSOCIATION, "pcelsActionAssociation"), + ( + &rfc4104::PCELS_SIMPLE_CONDITION_AUX_CLASS, + "pcelsSimpleConditionAuxClass", + ), + ( + &rfc4104::PCELS_COMPOUND_CONDITION_AUX_CLASS, + "pcelsCompoundConditionAuxClass", + ), + ( + &rfc4104::PCELS_COMPOUND_FILTER_CONDITION_AUX_CLASS, + "pcelsCompoundFilterConditionAuxClass", + ), + ( + &rfc4104::PCELS_SIMPLE_ACTION_AUX_CLASS, + "pcelsSimpleActionAuxClass", + ), + ( + &rfc4104::PCELS_COMPOUND_ACTION_AUX_CLASS, + "pcelsCompoundActionAuxClass", + ), + (&rfc4104::PCELS_VARIABLE, "pcelsVariable"), + ( + &rfc4104::PCELS_EXPLICIT_VARIABLE_AUX_CLASS, + "pcelsExplicitVariableAuxClass", + ), + ( + &rfc4104::PCELS_IMPLICIT_VARIABLE_AUX_CLASS, + "pcelsImplicitVariableAuxClass", + ), + ( + &rfc4104::PCELS_SOURCE_I_PV_4_VARIABLE_AUX_CLASS, + "pcelsSourceIPv4VariableAuxClass", + ), + ( + &rfc4104::PCELS_POLICY_SET_ASSOCIATION, + "pcelsPolicySetAssociation", + ), + ( + &rfc4104::PCELS_SOURCE_I_PV_6_VARIABLE_AUX_CLASS, + "pcelsSourceIPv6VariableAuxClass", + ), + ( + &rfc4104::PCELS_DESTINATION_I_PV_4_VARIABLE_AUX_CLASS, + "pcelsDestinationIPv4VariableAuxClass", + ), + ( + &rfc4104::PCELS_DESTINATION_I_PV_6_VARIABLE_AUX_CLASS, + "pcelsDestinationIPv6VariableAuxClass", + ), + ( + &rfc4104::PCELS_SOURCE_PORT_VARIABLE_AUX_CLASS, + "pcelsSourcePortVariableAuxClass", + ), + ( + &rfc4104::PCELS_DESTINATION_PORT_VARIABLE_AUX_CLASS, + "pcelsDestinationPortVariableAuxClass", + ), + ( + &rfc4104::PCELS_IP_PROTOCOL_VARIABLE_AUX_CLASS, + "pcelsIPProtocolVariableAuxClass", + ), + ( + &rfc4104::PCELS_IP_VERSION_VARIABLE_AUX_CLASS, + "pcelsIPVersionVariableAuxClass", + ), + ( + &rfc4104::PCELS_IP_TO_S_VARIABLE_AUX_CLASS, + "pcelsIPToSVariableAuxClass", + ), + ( + &rfc4104::PCELS_DSCP_VARIABLE_AUX_CLASS, + "pcelsDSCPVariableAuxClass", + ), + ( + &rfc4104::PCELS_FLOW_ID_VARIABLE_AUX_CLASS, + "pcelsFlowIdVariableAuxClass", + ), + (&rfc4104::PCELS_GROUP, "pcelsGroup"), + ( + &rfc4104::PCELS_SOURCE_MAC_VARIABLE_AUX_CLASS, + "pcelsSourceMACVariableAuxClass", + ), + ( + &rfc4104::PCELS_DESTINATION_MAC_VARIABLE_AUX_CLASS, + "pcelsDestinationMACVariableAuxClass", + ), + ( + &rfc4104::PCELS_VLAN_VARIABLE_AUX_CLASS, + "pcelsVLANVariableAuxClass", + ), + ( + &rfc4104::PCELS_CO_S_VARIABLE_AUX_CLASS, + "pcelsCoSVariableAuxClass", + ), + ( + &rfc4104::PCELS_ETHERTYPE_VARIABLE_AUX_CLASS, + "pcelsEthertypeVariableAuxClass", + ), + ( + &rfc4104::PCELS_SOURCE_SAP_VARIABLE_AUX_CLASS, + "pcelsSourceSAPVariableAuxClass", + ), + ( + &rfc4104::PCELS_DESTINATION_SAP_VARIABLE_AUX_CLASS, + "pcelsDestinationSAPVariableAuxClass", + ), + ( + &rfc4104::PCELS_SNAPOUI_VARIABLE_AUX_CLASS, + "pcelsSNAPOUIVariableAuxClass", + ), + ( + &rfc4104::PCELS_SNAP_TYPE_VARIABLE_AUX_CLASS, + "pcelsSNAPTypeVariableAuxClass", + ), + ( + &rfc4104::PCELS_FLOW_DIRECTION_VARIABLE_AUX_CLASS, + "pcelsFlowDirectionVariableAuxClass", + ), + (&rfc4104::PCELS_GROUP_AUX_CLASS, "pcelsGroupAuxClass"), + (&rfc4104::PCELS_VALUE_AUX_CLASS, "pcelsValueAuxClass"), + ( + &rfc4104::PCELS_I_PV_4_ADDR_VALUE_AUX_CLASS, + "pcelsIPv4AddrValueAuxClass", + ), + ( + &rfc4104::PCELS_I_PV_6_ADDR_VALUE_AUX_CLASS, + "pcelsIPv6AddrValueAuxClass", + ), + ( + &rfc4104::PCELS_MAC_ADDR_VALUE_AUX_CLASS, + "pcelsMACAddrValueAuxClass", + ), + ( + &rfc4104::PCELS_STRING_VALUE_AUX_CLASS, + "pcelsStringValueAuxClass", + ), + ( + &rfc4104::PCELS_BIT_STRING_VALUE_AUX_CLASS, + "pcelsBitStringValueAuxClass", + ), + ( + &rfc4104::PCELS_INTEGER_VALUE_AUX_CLASS, + "pcelsIntegerValueAuxClass", + ), + ( + &rfc4104::PCELS_BOOLEAN_VALUE_AUX_CLASS, + "pcelsBooleanValueAuxClass", + ), + (&rfc4104::PCELS_REUSABLE_CONTAINER, "pcelsReusableContainer"), + ( + &rfc4104::PCELS_REUSABLE_CONTAINER_AUX_CLASS, + "pcelsReusableContainerAuxClass", + ), + (&rfc4104::PCELS_GROUP_INSTANCE, "pcelsGroupInstance"), + ( + &rfc4104::PCELS_REUSABLE_CONTAINER_INSTANCE, + "pcelsReusableContainerInstance", + ), + (&rfc4104::PCELS_ROLE_COLLECTION, "pcelsRoleCollection"), + (&rfc4104::PCELS_FILTER_ENTRY_BASE, "pcelsFilterEntryBase"), + (&rfc4104::PCELS_IP_HEADERS_FILTER, "pcelsIPHeadersFilter"), + (&rfc4104::PCELS_8021_FILTER, "pcels8021Filter"), + ( + &rfc4104::PCELS_FILTER_LIST_AUX_CLASS, + "pcelsFilterListAuxClass", + ), + ( + &rfc4104::PCELS_VENDOR_VARIABLE_AUX_CLASS, + "pcelsVendorVariableAuxClass", + ), + ( + &rfc4104::PCELS_VENDOR_VALUE_AUX_CLASS, + "pcelsVendorValueAuxClass", + ), + (&rfc4104::PCELS_RULE, "pcelsRule"), + (&rfc4104::PCELS_RULE_AUX_CLASS, "pcelsRuleAuxClass"), + (&rfc4104::PCELS_RULE_INSTANCE, "pcelsRuleInstance"), + ( + &rfc4104::PCELS_CONDITION_ASSOCIATION, + "pcelsConditionAssociation", + ), + (&rfc4104::PCELS_POLICY_SET_NAME, "pcelsPolicySetName"), + (&rfc4104::PCELS_EXECUTION_STRATEGY, "pcelsExecutionStrategy"), + (&rfc4104::PCELS_VARIABLE_DN, "pcelsVariableDN"), + (&rfc4104::PCELS_VALUE_DN, "pcelsValueDN"), + (&rfc4104::PCELS_IS_MIRRORED, "pcelsIsMirrored"), + (&rfc4104::PCELS_VARIABLE_NAME, "pcelsVariableName"), + ( + &rfc4104::PCELS_EXPECTED_VALUE_LIST, + "pcelsExpectedValueList", + ), + ( + &rfc4104::PCELS_VARIABLE_MODEL_CLASS, + "pcelsVariableModelClass", + ), + ( + &rfc4104::PCELS_VARIABLE_MODEL_PROPERTY, + "pcelsVariableModelProperty", + ), + ( + &rfc4104::PCELS_EXPECTED_VALUE_TYPES, + "pcelsExpectedValueTypes", + ), + (&rfc4104::PCELS_VALUE_NAME, "pcelsValueName"), + (&rfc4104::PCELS_DECISION_STRATEGY, "pcelsDecisionStrategy"), + (&rfc4104::PCELS_I_PV_4_ADDR_LIST, "pcelsIPv4AddrList"), + (&rfc4104::PCELS_I_PV_6_ADDR_LIST, "pcelsIPv6AddrList"), + (&rfc4104::PCELS_MAC_ADDR_LIST, "pcelsMACAddrList"), + (&rfc4104::PCELS_STRING_LIST, "pcelsStringList"), + (&rfc4104::PCELS_BIT_STRING_LIST, "pcelsBitStringList"), + (&rfc4104::PCELS_INTEGER_LIST, "pcelsIntegerList"), + (&rfc4104::PCELS_BOOLEAN, "pcelsBoolean"), + ( + &rfc4104::PCELS_REUSABLE_CONTAINER_NAME, + "pcelsReusableContainerName", + ), + ( + &rfc4104::PCELS_REUSABLE_CONTAINER_LIST, + "pcelsReusableContainerList", + ), + (&rfc4104::PCELS_ROLE, "pcelsRole"), + (&rfc4104::PCELS_POLICY_SET_LIST, "pcelsPolicySetList"), + ( + &rfc4104::PCELS_ROLE_COLLECTION_NAME, + "pcelsRoleCollectionName", + ), + (&rfc4104::PCELS_ELEMENT_LIST, "pcelsElementList"), + (&rfc4104::PCELS_FILTER_NAME, "pcelsFilterName"), + (&rfc4104::PCELS_FILTER_IS_NEGATED, "pcelsFilterIsNegated"), + (&rfc4104::PCELS_IP_HDR_VERSION, "pcelsIPHdrVersion"), + ( + &rfc4104::PCELS_IP_HDR_SOURCE_ADDRESS, + "pcelsIPHdrSourceAddress", + ), + ( + &rfc4104::PCELS_IP_HDR_SOURCE_ADDRESS_END_OF_RANGE, + "pcelsIPHdrSourceAddressEndOfRange", + ), + (&rfc4104::PCELS_IP_HDR_SOURCE_MASK, "pcelsIPHdrSourceMask"), + (&rfc4104::PCELS_IP_HDR_DEST_ADDRESS, "pcelsIPHdrDestAddress"), + ( + &rfc4104::PCELS_IP_HDR_DEST_ADDRESS_END_OF_RANGE, + "pcelsIPHdrDestAddressEndOfRange", + ), + (&rfc4104::PCELS_PRIORITY, "pcelsPriority"), + (&rfc4104::PCELS_IP_HDR_DEST_MASK, "pcelsIPHdrDestMask"), + (&rfc4104::PCELS_IP_HDR_PROTOCOL_ID, "pcelsIPHdrProtocolID"), + ( + &rfc4104::PCELS_IP_HDR_SOURCE_PORT_START, + "pcelsIPHdrSourcePortStart", + ), + ( + &rfc4104::PCELS_IP_HDR_SOURCE_PORT_END, + "pcelsIPHdrSourcePortEnd", + ), + ( + &rfc4104::PCELS_IP_HDR_DEST_PORT_START, + "pcelsIPHdrDestPortStart", + ), + ( + &rfc4104::PCELS_IP_HDR_DEST_PORT_END, + "pcelsIPHdrDestPortEnd", + ), + (&rfc4104::PCELS_IP_HDR_DSCP_LIST, "pcelsIPHdrDSCPList"), + (&rfc4104::PCELS_IP_HDR_FLOW_LABEL, "pcelsIPHdrFlowLabel"), + ( + &rfc4104::PCELS_8021_HDR_SOURCE_MAC_ADDRESS, + "pcels8021HdrSourceMACAddress", + ), + ( + &rfc4104::PCELS_8021_HDR_SOURCE_MAC_MASK, + "pcels8021HdrSourceMACMask", + ), + (&rfc4104::PCELS_POLICY_SET_DN, "pcelsPolicySetDN"), + ( + &rfc4104::PCELS_8021_HDR_DEST_MAC_ADDRESS, + "pcels8021HdrDestMACAddress", + ), + ( + &rfc4104::PCELS_8021_HDR_DEST_MAC_MASK, + "pcels8021HdrDestMACMask", + ), + ( + &rfc4104::PCELS_8021_HDR_PROTOCOL_ID, + "pcels8021HdrProtocolID", + ), + (&rfc4104::PCELS_8021_HDR_PRIORITY, "pcels8021HdrPriority"), + (&rfc4104::PCELS_8021_HDR_VLANID, "pcels8021HdrVLANID"), + (&rfc4104::PCELS_FILTER_LIST_NAME, "pcelsFilterListName"), + (&rfc4104::PCELS_FILTER_DIRECTION, "pcelsFilterDirection"), + (&rfc4104::PCELS_FILTER_ENTRY_LIST, "pcelsFilterEntryList"), + ( + &rfc4104::PCELS_VENDOR_VARIABLE_DATA, + "pcelsVendorVariableData", + ), + ( + &rfc4104::PCELS_VENDOR_VARIABLE_ENCODING, + "pcelsVendorVariableEncoding", + ), + ( + &rfc4104::PCELS_CONDITION_LIST_TYPE, + "pcelsConditionListType", + ), + (&rfc4104::PCELS_VENDOR_VALUE_DATA, "pcelsVendorValueData"), + ( + &rfc4104::PCELS_VENDOR_VALUE_ENCODING, + "pcelsVendorValueEncoding", + ), + ( + &rfc4104::PCELS_RULE_VALIDITY_PERIOD_LIST, + "pcelsRuleValidityPeriodList", + ), + (&rfc4104::PCELS_CONDITION_LIST, "pcelsConditionList"), + (&rfc4104::PCELS_ACTION_LIST, "pcelsActionList"), + (&rfc4104::PCELS_SEQUENCED_ACTIONS, "pcelsSequencedActions"), + (&rfc4237::VPIM_USER, "vPIMUser"), + (&rfc4237::VPIM_TELEPHONE_NUMBER, "vPIMTelephoneNumber"), + (&rfc4237::VPIM_SUB_MAILBOXES, "vPIMSubMailboxes"), + (&rfc4237::VPIM_RFC_822_MAILBOX, "vPIMRfc822Mailbox"), + (&rfc4237::VPIM_SPOKEN_NAME, "vPIMSpokenName"), + ( + &rfc4237::VPIM_SUPPORTED_UA_BEHAVIORS, + "vPIMSupportedUABehaviors", + ), + ( + &rfc4237::VPIM_SUPPORTED_AUDIO_MEDIA_TYPES, + "vPIMSupportedAudioMediaTypes", + ), + ( + &rfc4237::VPIM_SUPPORTED_MESSAGE_CONTEXT, + "vPIMSupportedMessageContext", + ), + (&rfc4237::VPIM_TEXT_NAME, "vPIMTextName"), + ( + &rfc4237::VPIM_EXTENDED_ABSENCE_STATUS, + "vPIMExtendedAbsenceStatus", + ), + (&rfc4237::VPIM_MAX_MESSAGE_SIZE, "vPIMMaxMessageSize"), + (&rfc4403::UDDIV_3_SERVICE_KEY, "uddiv3ServiceKey"), + ( + &rfc4403::UDDI_BUSINESS_ENTITY_NAME_FORM, + "uddiBusinessEntityNameForm", + ), + ( + &rfc4403::UDDIV_3_ENTITY_OBITUARY_NAME_FORM, + "uddiv3EntityObituaryNameForm", + ), + (&rfc4403::UDDI_CONTACT_NAME_FORM, "uddiContactNameForm"), + (&rfc4403::UDDI_ADDRESS_NAME_FORM, "uddiAddressNameForm"), + ( + &rfc4403::UDDI_BUSINESS_SERVICE_NAME_FORM, + "uddiBusinessServiceNameForm", + ), + ( + &rfc4403::UDDI_BINDING_TEMPLATE_NAME_FORM, + "uddiBindingTemplateNameForm", + ), + ( + &rfc4403::UDDI_T_MODEL_INSTANCE_INFO_NAME_FORM, + "uddiTModelInstanceInfoNameForm", + ), + (&rfc4403::UDDI_T_MODEL_NAME_FORM, "uddiTModelNameForm"), + ( + &rfc4403::UDDI_PUBLISHER_ASSERTION_NAME_FORM, + "uddiPublisherAssertionNameForm", + ), + ( + &rfc4403::UDDIV_3_SUBSCRIPTION_NAME_FORM, + "uddiv3SubscriptionNameForm", + ), + (&rfc4403::UDDI_BUSINESS_KEY, "uddiBusinessKey"), + (&rfc4403::UDDI_E_MAIL, "uddiEMail"), + (&rfc4403::UDDI_SORT_CODE, "uddiSortCode"), + (&rfc4403::UDDI_T_MODEL_KEY, "uddiTModelKey"), + (&rfc4403::UDDI_ADDRESS_LINE, "uddiAddressLine"), + (&rfc4403::UDDI_IDENTIFIER_BAG, "uddiIdentifierBag"), + (&rfc4403::UDDI_CATEGORY_BAG, "uddiCategoryBag"), + (&rfc4403::UDDI_KEYED_REFERENCE, "uddiKeyedReference"), + (&rfc4403::UDDI_SERVICE_KEY, "uddiServiceKey"), + (&rfc4403::UDDI_BINDING_KEY, "uddiBindingKey"), + (&rfc4403::UDDI_ACCESS_POINT, "uddiAccessPoint"), + (&rfc4403::UDDI_AUTHORIZED_NAME, "uddiAuthorizedName"), + (&rfc4403::UDDI_HOSTING_REDIRECTOR, "uddiHostingRedirector"), + ( + &rfc4403::UDDI_INSTANCE_DESCRIPTION, + "uddiInstanceDescription", + ), + (&rfc4403::UDDI_INSTANCE_PARMS, "uddiInstanceParms"), + ( + &rfc4403::UDDI_OVERVIEW_DESCRIPTION, + "uddiOverviewDescription", + ), + (&rfc4403::UDDI_OVERVIEW_URL, "uddiOverviewURL"), + (&rfc4403::UDDI_FROM_KEY, "uddiFromKey"), + (&rfc4403::UDDI_TO_KEY, "uddiToKey"), + (&rfc4403::UDDI_UUID, "uddiUUID"), + (&rfc4403::UDDI_IS_HIDDEN, "uddiIsHidden"), + (&rfc4403::UDDI_IS_PROJECTION, "uddiIsProjection"), + (&rfc4403::UDDI_OPERATOR, "uddiOperator"), + (&rfc4403::UDDI_LANG, "uddiLang"), + (&rfc4403::UDDIV_3_BUSINESS_KEY, "uddiv3BusinessKey"), + (&rfc4403::UDDIV_3_BINDING_KEY, "uddiv3BindingKey"), + (&rfc4403::UDDIV_3_TMODEL_KEY, "uddiv3TmodelKey"), + ( + &rfc4403::UDDIV_3_DIGITAL_SIGNATURE, + "uddiv3DigitalSignature", + ), + (&rfc4403::UDDIV_3_NODE_ID, "uddiv3NodeId"), + ( + &rfc4403::UDDIV_3_ENTITY_MODIFICATION_TIME, + "uddiv3EntityModificationTime", + ), + (&rfc4403::UDDIV_3_SUBSCRIPTION_KEY, "uddiv3SubscriptionKey"), + ( + &rfc4403::UDDIV_3_SUBSCRIPTION_FILTER, + "uddiv3SubscriptionFilter", + ), + (&rfc4403::UDDI_NAME, "uddiName"), + ( + &rfc4403::UDDIV_3_NOTIFICATION_INTERVAL, + "uddiv3NotificationInterval", + ), + (&rfc4403::UDDIV_3_MAX_ENTITIES, "uddiv3MaxEntities"), + (&rfc4403::UDDIV_3_EXPIRES_AFTER, "uddiv3ExpiresAfter"), + (&rfc4403::UDDIV_3_BRIEF_RESPONSE, "uddiv3BriefResponse"), + (&rfc4403::UDDIV_3_ENTITY_KEY, "uddiv3EntityKey"), + ( + &rfc4403::UDDIV_3_ENTITY_CREATION_TIME, + "uddiv3EntityCreationTime", + ), + ( + &rfc4403::UDDIV_3_ENTITY_DELETION_TIME, + "uddiv3EntityDeletionTime", + ), + (&rfc4403::UDDI_DESCRIPTION, "uddiDescription"), + (&rfc4403::UDDI_DISCOVERY_UR_LS, "uddiDiscoveryURLs"), + (&rfc4403::UDDI_USE_TYPE, "uddiUseType"), + (&rfc4403::UDDI_PERSON_NAME, "uddiPersonName"), + (&rfc4403::UDDI_PHONE, "uddiPhone"), + (&rfc4403::UDDI_BUSINESS_ENTITY, "uddiBusinessEntity"), + (&rfc4403::UDDIV_3_ENTITY_OBITUARY, "uddiv3EntityObituary"), + (&rfc4403::UDDI_CONTACT, "uddiContact"), + (&rfc4403::UDDI_ADDRESS, "uddiAddress"), + (&rfc4403::UDDI_BUSINESS_SERVICE, "uddiBusinessService"), + (&rfc4403::UDDI_BINDING_TEMPLATE, "uddiBindingTemplate"), + ( + &rfc4403::UDDI_T_MODEL_INSTANCE_INFO, + "uddiTModelInstanceInfo", + ), + (&rfc4403::UDDI_T_MODEL, "uddiTModel"), + (&rfc4403::UDDI_PUBLISHER_ASSERTION, "uddiPublisherAssertion"), + (&rfc4403::UDDIV_3_SUBSCRIPTION, "uddiv3Subscription"), + (&rfc4512::EXTENSIBLE_OBJECT, "extensibleObject"), + (&rfc4512::SUPPORTED_CONTROL, "supportedControl"), + ( + &rfc4512::SUPPORTED_SASL_MECHANISMS, + "supportedSASLMechanisms", + ), + (&rfc4512::SUPPORTED_LDAP_VERSION, "supportedLDAPVersion"), + (&rfc4512::LDAP_SYNTAXES, "ldapSyntaxes"), + (&rfc4512::NAMING_CONTEXTS, "namingContexts"), + (&rfc4512::ALT_SERVER, "altServer"), + (&rfc4512::SUPPORTED_EXTENSION, "supportedExtension"), + (&rfc4512::SUPPORTED_FEATURES, "supportedFeatures"), + (&rfc4512::CREATE_TIMESTAMP, "createTimestamp"), + (&rfc4512::SUBSCHEMA_SUBENTRY, "subschemaSubentry"), + (&rfc4512::MODIFY_TIMESTAMP, "modifyTimestamp"), + (&rfc4512::CREATORS_NAME, "creatorsName"), + (&rfc4512::MODIFIERS_NAME, "modifiersName"), + (&rfc4512::SUBSCHEMA, "subschema"), + (&rfc4512::DIT_STRUCTURE_RULES, "dITStructureRules"), + (&rfc4512::GOVERNING_STRUCTURE_RULE, "governingStructureRule"), + (&rfc4512::DIT_CONTENT_RULES, "dITContentRules"), + (&rfc4512::MATCHING_RULES, "matchingRules"), + (&rfc4512::ATTRIBUTE_TYPES, "attributeTypes"), + (&rfc4512::OBJECT_CLASSES, "objectClasses"), + (&rfc4512::NAME_FORMS, "nameForms"), + (&rfc4512::MATCHING_RULE_USE, "matchingRuleUse"), + (&rfc4512::STRUCTURAL_OBJECT_CLASS, "structuralObjectClass"), + (&rfc4512::OBJECT_CLASS, "objectClass"), + (&rfc4512::ALIASED_OBJECT_NAME, "aliasedObjectName"), + (&rfc4512::TOP, "top"), + (&rfc4512::ALIAS, "alias"), + (&rfc4517::CASE_EXACT_IA_5_MATCH, "caseExactIA5Match"), + (&rfc4517::CASE_IGNORE_IA_5_MATCH, "caseIgnoreIA5Match"), + ( + &rfc4517::CASE_IGNORE_IA_5_SUBSTRINGS_MATCH, + "caseIgnoreIA5SubstringsMatch", + ), + (&rfc4517::OBJECT_IDENTIFIER_MATCH, "objectIdentifierMatch"), + (&rfc4517::DISTINGUISHED_NAME_MATCH, "distinguishedNameMatch"), + ( + &rfc4517::NUMERIC_STRING_SUBSTRINGS_MATCH, + "numericStringSubstringsMatch", + ), + (&rfc4517::CASE_IGNORE_LIST_MATCH, "caseIgnoreListMatch"), + ( + &rfc4517::CASE_IGNORE_LIST_SUBSTRINGS_MATCH, + "caseIgnoreListSubstringsMatch", + ), + (&rfc4517::BOOLEAN_MATCH, "booleanMatch"), + (&rfc4517::INTEGER_MATCH, "integerMatch"), + (&rfc4517::INTEGER_ORDERING_MATCH, "integerOrderingMatch"), + (&rfc4517::BIT_STRING_MATCH, "bitStringMatch"), + (&rfc4517::OCTET_STRING_MATCH, "octetStringMatch"), + ( + &rfc4517::OCTET_STRING_ORDERING_MATCH, + "octetStringOrderingMatch", + ), + (&rfc4517::CASE_IGNORE_MATCH, "caseIgnoreMatch"), + (&rfc4517::TELEPHONE_NUMBER_MATCH, "telephoneNumberMatch"), + ( + &rfc4517::TELEPHONE_NUMBER_SUBSTRINGS_MATCH, + "telephoneNumberSubstringsMatch", + ), + (&rfc4517::UNIQUE_MEMBER_MATCH, "uniqueMemberMatch"), + (&rfc4517::GENERALIZED_TIME_MATCH, "generalizedTimeMatch"), + ( + &rfc4517::GENERALIZED_TIME_ORDERING_MATCH, + "generalizedTimeOrderingMatch", + ), + ( + &rfc4517::INTEGER_FIRST_COMPONENT_MATCH, + "integerFirstComponentMatch", + ), + ( + &rfc4517::CASE_IGNORE_ORDERING_MATCH, + "caseIgnoreOrderingMatch", + ), + ( + &rfc4517::OBJECT_IDENTIFIER_FIRST_COMPONENT_MATCH, + "objectIdentifierFirstComponentMatch", + ), + ( + &rfc4517::DIRECTORY_STRING_FIRST_COMPONENT_MATCH, + "directoryStringFirstComponentMatch", + ), + (&rfc4517::WORD_MATCH, "wordMatch"), + (&rfc4517::KEYWORD_MATCH, "keywordMatch"), + ( + &rfc4517::CASE_IGNORE_SUBSTRINGS_MATCH, + "caseIgnoreSubstringsMatch", + ), + (&rfc4517::CASE_EXACT_MATCH, "caseExactMatch"), + ( + &rfc4517::CASE_EXACT_ORDERING_MATCH, + "caseExactOrderingMatch", + ), + ( + &rfc4517::CASE_EXACT_SUBSTRINGS_MATCH, + "caseExactSubstringsMatch", + ), + (&rfc4517::NUMERIC_STRING_MATCH, "numericStringMatch"), + ( + &rfc4517::NUMERIC_STRING_ORDERING_MATCH, + "numericStringOrderingMatch", + ), + (&rfc4519::UID, "uid"), + (&rfc4519::USER_ID, "userId"), + (&rfc4519::DC, "DC"), + (&rfc4519::DOMAIN_COMPONENT, "domainComponent"), + (&rfc4519::UID_OBJECT, "uidObject"), + (&rfc4519::DC_OBJECT, "dcObject"), + (&rfc4519::O, "o"), + (&rfc4519::ORGANIZATION_NAME, "organizationName"), + (&rfc4519::OU, "ou"), + (&rfc4519::ORGANIZATIONAL_UNIT_NAME, "organizationalUnitName"), + (&rfc4519::TITLE, "title"), + (&rfc4519::DESCRIPTION, "description"), + (&rfc4519::SEARCH_GUIDE, "searchGuide"), + (&rfc4519::BUSINESS_CATEGORY, "businessCategory"), + (&rfc4519::POSTAL_ADDRESS, "postalAddress"), + (&rfc4519::POSTAL_CODE, "postalCode"), + (&rfc4519::POST_OFFICE_BOX, "postOfficeBox"), + ( + &rfc4519::PHYSICAL_DELIVERY_OFFICE_NAME, + "physicalDeliveryOfficeName", + ), + (&rfc4519::TELEPHONE_NUMBER, "telephoneNumber"), + (&rfc4519::TELEX_NUMBER, "telexNumber"), + ( + &rfc4519::TELETEX_TERMINAL_IDENTIFIER, + "teletexTerminalIdentifier", + ), + ( + &rfc4519::FACSIMILE_TELEPHONE_NUMBER, + "facsimileTelephoneNumber", + ), + (&rfc4519::X_121_ADDRESS, "x121Address"), + ( + &rfc4519::INTERNATIONALI_SDN_NUMBER, + "internationaliSDNNumber", + ), + (&rfc4519::REGISTERED_ADDRESS, "registeredAddress"), + (&rfc4519::DESTINATION_INDICATOR, "destinationIndicator"), + ( + &rfc4519::PREFERRED_DELIVERY_METHOD, + "preferredDeliveryMethod", + ), + (&rfc4519::CN, "cn"), + (&rfc4519::COMMON_NAME, "commonName"), + (&rfc4519::MEMBER, "member"), + (&rfc4519::OWNER, "owner"), + (&rfc4519::ROLE_OCCUPANT, "roleOccupant"), + (&rfc4519::SEE_ALSO, "seeAlso"), + (&rfc4519::USER_PASSWORD, "userPassword"), + (&rfc4519::SN, "sn"), + (&rfc4519::SURNAME, "surname"), + (&rfc4519::NAME, "name"), + (&rfc4519::GIVEN_NAME, "givenName"), + (&rfc4519::INITIALS, "initials"), + (&rfc4519::GENERATION_QUALIFIER, "generationQualifier"), + (&rfc4519::X_500_UNIQUE_IDENTIFIER, "x500UniqueIdentifier"), + (&rfc4519::DN_QUALIFIER, "dnQualifier"), + (&rfc4519::ENHANCED_SEARCH_GUIDE, "enhancedSearchGuide"), + (&rfc4519::DISTINGUISHED_NAME, "distinguishedName"), + (&rfc4519::SERIAL_NUMBER, "serialNumber"), + (&rfc4519::UNIQUE_MEMBER, "uniqueMember"), + (&rfc4519::HOUSE_IDENTIFIER, "houseIdentifier"), + (&rfc4519::C, "c"), + (&rfc4519::COUNTRY_NAME, "countryName"), + (&rfc4519::L, "L"), + (&rfc4519::LOCALITY_NAME, "localityName"), + (&rfc4519::ST, "st"), + (&rfc4519::STREET, "street"), + (&rfc4519::RESIDENTIAL_PERSON, "residentialPerson"), + (&rfc4519::APPLICATION_PROCESS, "applicationProcess"), + (&rfc4519::DEVICE, "device"), + (&rfc4519::GROUP_OF_UNIQUE_NAMES, "groupOfUniqueNames"), + (&rfc4519::COUNTRY, "country"), + (&rfc4519::LOCALITY, "locality"), + (&rfc4519::ORGANIZATION, "organization"), + (&rfc4519::ORGANIZATIONAL_UNIT, "organizationalUnit"), + (&rfc4519::PERSON, "person"), + (&rfc4519::ORGANIZATIONAL_PERSON, "organizationalPerson"), + (&rfc4519::ORGANIZATIONAL_ROLE, "organizationalRole"), + (&rfc4519::GROUP_OF_NAMES, "groupOfNames"), + (&rfc4523::CERTIFICATE_EXACT_MATCH, "certificateExactMatch"), + (&rfc4523::CERTIFICATE_MATCH, "certificateMatch"), + ( + &rfc4523::CERTIFICATE_PAIR_EXACT_MATCH, + "certificatePairExactMatch", + ), + (&rfc4523::CERTIFICATE_PAIR_MATCH, "certificatePairMatch"), + ( + &rfc4523::CERTIFICATE_LIST_EXACT_MATCH, + "certificateListExactMatch", + ), + (&rfc4523::CERTIFICATE_LIST_MATCH, "certificateListMatch"), + ( + &rfc4523::ALGORITHM_IDENTIFIER_MATCH, + "algorithmIdentifierMatch", + ), + (&rfc4523::USER_CERTIFICATE, "userCertificate"), + (&rfc4523::CA_CERTIFICATE, "cACertificate"), + ( + &rfc4523::AUTHORITY_REVOCATION_LIST, + "authorityRevocationList", + ), + ( + &rfc4523::CERTIFICATE_REVOCATION_LIST, + "certificateRevocationList", + ), + (&rfc4523::CROSS_CERTIFICATE_PAIR, "crossCertificatePair"), + (&rfc4523::SUPPORTED_ALGORITHMS, "supportedAlgorithms"), + (&rfc4523::DELTA_REVOCATION_LIST, "deltaRevocationList"), + ( + &rfc4523::STRONG_AUTHENTICATION_USER, + "strongAuthenticationUser", + ), + (&rfc4523::CERTIFICATION_AUTHORITY, "certificationAuthority"), + ( + &rfc4523::CERTIFICATION_AUTHORITY_V_2, + "certificationAuthority-V2", + ), + ( + &rfc4523::USER_SECURITY_INFORMATION, + "userSecurityInformation", + ), + (&rfc4523::CRL_DISTRIBUTION_POINT, "cRLDistributionPoint"), + (&rfc4523::PKI_USER, "pkiUser"), + (&rfc4523::PKI_CA, "pkiCA"), + (&rfc4523::DELTA_CRL, "deltaCRL"), + (&rfc4524::MANAGER, "manager"), + (&rfc4524::DOCUMENT_IDENTIFIER, "documentIdentifier"), + (&rfc4524::DOCUMENT_TITLE, "documentTitle"), + (&rfc4524::DOCUMENT_VERSION, "documentVersion"), + (&rfc4524::DOCUMENT_AUTHOR, "documentAuthor"), + (&rfc4524::DOCUMENT_LOCATION, "documentLocation"), + (&rfc4524::HOME_PHONE, "homePhone"), + (&rfc4524::HOME_TELEPHONE, "homeTelephone"), + (&rfc4524::SECRETARY, "secretary"), + (&rfc4524::MAIL, "mail"), + (&rfc4524::RFC_822_MAILBOX, "RFC822Mailbox"), + (&rfc4524::ASSOCIATED_DOMAIN, "associatedDomain"), + (&rfc4524::ASSOCIATED_NAME, "associatedName"), + (&rfc4524::HOME_POSTAL_ADDRESS, "homePostalAddress"), + (&rfc4524::INFO, "info"), + (&rfc4524::PERSONAL_TITLE, "personalTitle"), + (&rfc4524::MOBILE, "mobile"), + (&rfc4524::MOBILE_TELEPHONE_NUMBER, "mobileTelephoneNumber"), + (&rfc4524::PAGER, "pager"), + (&rfc4524::PAGER_TELEPHONE_NUMBER, "pagerTelephoneNumber"), + (&rfc4524::CO, "co"), + (&rfc4524::FRIENDLY_COUNTRY_NAME, "friendlyCountryName"), + (&rfc4524::UNIQUE_IDENTIFIER, "uniqueIdentifier"), + (&rfc4524::ORGANIZATIONAL_STATUS, "organizationalStatus"), + (&rfc4524::BUILDING_NAME, "buildingName"), + (&rfc4524::DRINK, "drink"), + (&rfc4524::FAVOURITE_DRINK, "favouriteDrink"), + (&rfc4524::SINGLE_LEVEL_QUALITY, "singleLevelQuality"), + (&rfc4524::DOCUMENT_PUBLISHER, "documentPublisher"), + (&rfc4524::ROOM_NUMBER, "roomNumber"), + (&rfc4524::USER_CLASS, "userClass"), + (&rfc4524::HOST, "host"), + (&rfc4524::DOMAIN, "domain"), + (&rfc4524::RFC_822_LOCAL_PART, "RFC822LocalPart"), + (&rfc4524::DOMAIN_RELATED_OBJECT, "domainRelatedObject"), + (&rfc4524::FRIENDLY_COUNTRY, "friendlyCountry"), + (&rfc4524::SIMPLE_SECURITY_OBJECT, "simpleSecurityObject"), + (&rfc4524::ACCOUNT, "account"), + (&rfc4524::DOCUMENT, "document"), + (&rfc4524::ROOM, "room"), + (&rfc4524::DOCUMENT_SERIES, "documentSeries"), + (&rfc4530::UUID_MATCH, "uuidMatch"), + (&rfc4530::UUID_ORDERING_MATCH, "uuidOrderingMatch"), + (&rfc4530::ENTRY_UUID, "entryUUID"), + (&rfc4876::DEFAULT_SERVER_LIST, "defaultServerList"), + (&rfc4876::DEFAULT_SEARCH_BASE, "defaultSearchBase"), + (&rfc4876::CREDENTIAL_LEVEL, "credentialLevel"), + (&rfc4876::OBJECTCLASS_MAP, "objectclassMap"), + (&rfc4876::DEFAULT_SEARCH_SCOPE, "defaultSearchScope"), + (&rfc4876::SERVICE_CREDENTIAL_LEVEL, "serviceCredentialLevel"), + ( + &rfc4876::SERVICE_SEARCH_DESCRIPTOR, + "serviceSearchDescriptor", + ), + ( + &rfc4876::SERVICE_AUTHENTICATION_METHOD, + "serviceAuthenticationMethod", + ), + (&rfc4876::DEREFERENCE_ALIASES, "dereferenceAliases"), + (&rfc4876::PREFERRED_SERVER_LIST, "preferredServerList"), + (&rfc4876::SEARCH_TIME_LIMIT, "searchTimeLimit"), + (&rfc4876::BIND_TIME_LIMIT, "bindTimeLimit"), + (&rfc4876::FOLLOW_REFERRALS, "followReferrals"), + (&rfc4876::AUTHENTICATION_METHOD, "authenticationMethod"), + (&rfc4876::PROFILE_TTL, "profileTTL"), + (&rfc4876::ATTRIBUTE_MAP, "attributeMap"), + (&rfc4876::DUA_CONFIG_PROFILE, "DUAConfigProfile"), + (&rfc5020::ENTRY_DN, "entryDN"), + (&rfc5280::PKCS_9, "pkcs-9"), + (&rfc5280::ID_PKIX, "id-pkix"), + (&rfc5280::ID_PE, "id-pe"), + ( + &rfc5280::ID_PE_AUTHORITY_INFO_ACCESS, + "id-pe-authorityInfoAccess", + ), + ( + &rfc5280::ID_PE_SUBJECT_INFO_ACCESS, + "id-pe-subjectInfoAccess", + ), + (&rfc5280::ID_QT, "id-qt"), + (&rfc5280::ID_QT_CPS, "id-qt-cps"), + (&rfc5280::ID_QT_UNOTICE, "id-qt-unotice"), + (&rfc5280::ID_KP, "id-kp"), + (&rfc5280::ID_KP_SERVER_AUTH, "id-kp-serverAuth"), + (&rfc5280::ID_KP_CLIENT_AUTH, "id-kp-clientAuth"), + (&rfc5280::ID_KP_CODE_SIGNING, "id-kp-codeSigning"), + (&rfc5280::ID_KP_EMAIL_PROTECTION, "id-kp-emailProtection"), + (&rfc5280::ID_KP_TIME_STAMPING, "id-kp-timeStamping"), + (&rfc5280::ID_KP_OCSP_SIGNING, "id-kp-OCSPSigning"), + (&rfc5280::ID_AD, "id-ad"), + (&rfc5280::ID_AD_OCSP, "id-ad-ocsp"), + (&rfc5280::ID_AD_CA_ISSUERS, "id-ad-caIssuers"), + (&rfc5280::ID_AD_TIME_STAMPING, "id-ad-timeStamping"), + (&rfc5280::ID_AD_CA_REPOSITORY, "id-ad-caRepository"), + (&rfc5280::HOLD_INSTRUCTION, "holdInstruction"), + (&rfc5280::ID_HOLDINSTRUCTION_NONE, "id-holdinstruction-none"), + ( + &rfc5280::ID_HOLDINSTRUCTION_CALLISSUER, + "id-holdinstruction-callissuer", + ), + ( + &rfc5280::ID_HOLDINSTRUCTION_REJECT, + "id-holdinstruction-reject", + ), + (&rfc5280::ID_CE, "id-ce"), + ( + &rfc5280::ID_CE_SUBJECT_KEY_IDENTIFIER, + "id-ce-subjectKeyIdentifier", + ), + (&rfc5280::ID_CE_KEY_USAGE, "id-ce-keyUsage"), + ( + &rfc5280::ID_CE_PRIVATE_KEY_USAGE_PERIOD, + "id-ce-privateKeyUsagePeriod", + ), + (&rfc5280::ID_CE_SUBJECT_ALT_NAME, "id-ce-subjectAltName"), + (&rfc5280::ID_CE_ISSUER_ALT_NAME, "id-ce-issuerAltName"), + (&rfc5280::ID_CE_BASIC_CONSTRAINTS, "id-ce-basicConstraints"), + (&rfc5280::ID_CE_CRL_NUMBER, "id-ce-cRLNumber"), + (&rfc5280::ID_CE_CRL_REASONS, "id-ce-cRLReasons"), + ( + &rfc5280::ID_CE_HOLD_INSTRUCTION_CODE, + "id-ce-holdInstructionCode", + ), + (&rfc5280::ID_CE_INVALIDITY_DATE, "id-ce-invalidityDate"), + ( + &rfc5280::ID_CE_DELTA_CRL_INDICATOR, + "id-ce-deltaCRLIndicator", + ), + ( + &rfc5280::ID_CE_ISSUING_DISTRIBUTION_POINT, + "id-ce-issuingDistributionPoint", + ), + ( + &rfc5280::ID_CE_CERTIFICATE_ISSUER, + "id-ce-certificateIssuer", + ), + (&rfc5280::ID_CE_NAME_CONSTRAINTS, "id-ce-nameConstraints"), + ( + &rfc5280::ID_CE_CRL_DISTRIBUTION_POINTS, + "id-ce-cRLDistributionPoints", + ), + ( + &rfc5280::ID_CE_CERTIFICATE_POLICIES, + "id-ce-certificatePolicies", + ), + (&rfc5280::ANY_POLICY, "anyPolicy"), + (&rfc5280::ID_CE_POLICY_MAPPINGS, "id-ce-policyMappings"), + ( + &rfc5280::ID_CE_AUTHORITY_KEY_IDENTIFIER, + "id-ce-authorityKeyIdentifier", + ), + ( + &rfc5280::ID_CE_POLICY_CONSTRAINTS, + "id-ce-policyConstraints", + ), + (&rfc5280::ID_CE_EXT_KEY_USAGE, "id-ce-extKeyUsage"), + (&rfc5280::ANY_EXTENDED_KEY_USAGE, "anyExtendedKeyUsage"), + (&rfc5280::ID_CE_FRESHEST_CRL, "id-ce-freshestCRL"), + (&rfc5280::ID_CE_INHIBIT_ANY_POLICY, "id-ce-inhibitAnyPolicy"), + ( + &rfc5280::ID_CE_SUBJECT_DIRECTORY_ATTRIBUTES, + "id-ce-subjectDirectoryAttributes", + ), + (&rfc5280::ID_AT, "id-at"), + (&rfc5911::ID_PBKDF_2, "id-PBKDF2"), + (&rfc5911::ID_DATA, "id-data"), + (&rfc5911::ID_SIGNED_DATA, "id-signedData"), + (&rfc5911::ID_ENVELOPED_DATA, "id-envelopedData"), + (&rfc5911::ID_DIGESTED_DATA, "id-digestedData"), + (&rfc5911::ID_ENCRYPTED_DATA, "id-encryptedData"), + (&rfc5911::SMIME_CAPABILITIES, "smimeCapabilities"), + (&rfc5911::ID_SMIME, "id-smime"), + (&rfc5911::ID_CT_RECEIPT, "id-ct-receipt"), + (&rfc5911::ID_CT_FIRMWARE_PACKAGE, "id-ct-firmwarePackage"), + ( + &rfc5911::ID_CT_FIRMWARE_LOAD_RECEIPT, + "id-ct-firmwareLoadReceipt", + ), + ( + &rfc5911::ID_CT_FIRMWARE_LOAD_ERROR, + "id-ct-firmwareLoadError", + ), + (&rfc5911::ID_CT_AUTH_DATA, "id-ct-authData"), + ( + &rfc5911::ID_CT_AUTH_ENVELOPED_DATA, + "id-ct-authEnvelopedData", + ), + (&rfc5911::ID_CT_CONTENT_INFO, "id-ct-contentInfo"), + (&rfc5911::ID_CAP, "id-cap"), + ( + &rfc5911::ID_CAP_PREFER_BINARY_INSIDE, + "id-cap-preferBinaryInside", + ), + (&rfc5911::ID_AA, "id-aa"), + (&rfc5911::ID_AA_RECEIPT_REQUEST, "id-aa-receiptRequest"), + (&rfc5911::ID_AA_CONTENT_REFERENCE, "id-aa-contentReference"), + (&rfc5911::ID_AA_ENCRYP_KEY_PREF, "id-aa-encrypKeyPref"), + ( + &rfc5911::ID_AA_SIGNING_CERTIFICATE, + "id-aa-signingCertificate", + ), + (&rfc5911::ID_AA_SECURITY_LABEL, "id-aa-securityLabel"), + (&rfc5911::ID_AA_ML_EXPAND_HISTORY, "id-aa-mlExpandHistory"), + ( + &rfc5911::ID_AA_FIRMWARE_PACKAGE_ID, + "id-aa-firmwarePackageID", + ), + ( + &rfc5911::ID_AA_TARGET_HARDWARE_I_DS, + "id-aa-targetHardwareIDs", + ), + (&rfc5911::ID_AA_DECRYPT_KEY_ID, "id-aa-decryptKeyID"), + (&rfc5911::ID_AA_IMPL_CRYPTO_ALGS, "id-aa-implCryptoAlgs"), + ( + &rfc5911::ID_AA_WRAPPED_FIRMWARE_KEY, + "id-aa-wrappedFirmwareKey", + ), + (&rfc5911::ID_AA_CONTENT_HINT, "id-aa-contentHint"), + ( + &rfc5911::ID_AA_COMMUNITY_IDENTIFIERS, + "id-aa-communityIdentifiers", + ), + ( + &rfc5911::ID_AA_FIRMWARE_PACKAGE_INFO, + "id-aa-firmwarePackageInfo", + ), + (&rfc5911::ID_AA_IMPL_COMPRESS_ALGS, "id-aa-implCompressAlgs"), + ( + &rfc5911::ID_AA_SIGNING_CERTIFICATE_V_2, + "id-aa-signingCertificateV2", + ), + (&rfc5911::ID_AA_ER_INTERNAL, "id-aa-er-internal"), + (&rfc5911::ID_AA_MSG_SIG_DIGEST, "id-aa-msgSigDigest"), + (&rfc5911::ID_AA_ER_EXTERNAL, "id-aa-er-external"), + ( + &rfc5911::ID_AA_CONTENT_IDENTIFIER, + "id-aa-contentIdentifier", + ), + (&rfc5911::ID_AA_EQUIVALENT_LABELS, "id-aa-equivalentLabels"), + (&rfc5911::ID_ALG_SSDH, "id-alg-SSDH"), + (&rfc5911::ID_ALG_ESDH, "id-alg-ESDH"), + (&rfc5911::ID_ALG_CMS_3_DE_SWRAP, "id-alg-CMS3DESwrap"), + (&rfc5911::ID_ALG_CMSRC_2_WRAP, "id-alg-CMSRC2wrap"), + (&rfc5911::ID_SKD, "id-skd"), + (&rfc5911::ID_SKD_GL_USE_KEK, "id-skd-glUseKEK"), + (&rfc5911::ID_SKD_GLA_QUERY_REQUEST, "id-skd-glaQueryRequest"), + ( + &rfc5911::ID_SKD_GLA_QUERY_RESPONSE, + "id-skd-glaQueryResponse", + ), + (&rfc5911::ID_SKD_GL_PROVIDE_CERT, "id-skd-glProvideCert"), + (&rfc5911::ID_SKD_GL_MANAGE_CERT, "id-skd-glManageCert"), + (&rfc5911::ID_SKD_GL_KEY, "id-skd-glKey"), + (&rfc5911::ID_SKD_GL_DELETE, "id-skd-glDelete"), + (&rfc5911::ID_SKD_GL_ADD_MEMBER, "id-skd-glAddMember"), + (&rfc5911::ID_SKD_GL_DELETE_MEMBER, "id-skd-glDeleteMember"), + (&rfc5911::ID_SKD_GL_REKEY, "id-skd-glRekey"), + (&rfc5911::ID_SKD_GL_ADD_OWNER, "id-skd-glAddOwner"), + (&rfc5911::ID_SKD_GL_REMOVE_OWNER, "id-skd-glRemoveOwner"), + (&rfc5911::ID_SKD_GL_KEY_COMPROMISE, "id-skd-glKeyCompromise"), + (&rfc5911::ID_SKD_GLK_REFRESH, "id-skd-glkRefresh"), + (&rfc5911::ID_CONTENT_TYPE, "id-contentType"), + (&rfc5911::ID_MESSAGE_DIGEST, "id-messageDigest"), + (&rfc5911::ID_SIGNING_TIME, "id-signingTime"), + (&rfc5911::ID_COUNTERSIGNATURE, "id-countersignature"), + (&rfc5911::RC_2_CBC, "rc2-cbc"), + (&rfc5911::DES_EDE_3_CBC, "des-ede3-cbc"), + (&rfc5911::LTANS, "ltans"), + (&rfc5911::ID_CET_SKD_FAIL_INFO, "id-cet-skdFailInfo"), + (&rfc5911::ID_CMC_GLA_RR, "id-cmc-glaRR"), + ( + &rfc5911::ID_CMC_GLA_SKD_ALG_REQUEST, + "id-cmc-gla-skdAlgRequest", + ), + ( + &rfc5911::ID_CMC_GLA_SKD_ALG_RESPONSE, + "id-cmc-gla-skdAlgResponse", + ), + ( + &rfc5911::ID_ON_HARDWARE_MODULE_NAME, + "id-on-hardwareModuleName", + ), + (&rfc5911::HMAC_SHA_1, "hMAC-SHA1"), + (&rfc5911::AES, "aes"), + (&rfc5911::ID_AES_128_CBC, "id-aes128-CBC"), + (&rfc5911::ID_AES_192_CBC, "id-aes192-CBC"), + (&rfc5911::ID_AES_192_WRAP, "id-aes192-wrap"), + (&rfc5911::ID_AES_192_GCM, "id-aes192-GCM"), + (&rfc5911::ID_AES_192_CCM, "id-aes192-CCM"), + (&rfc5911::ID_AES_256_CBC, "id-aes256-CBC"), + (&rfc5911::ID_AES_256_WRAP, "id-aes256-wrap"), + (&rfc5911::ID_AES_256_GCM, "id-aes256-GCM"), + (&rfc5911::ID_AES_256_CCM, "id-aes256-CCM"), + (&rfc5911::ID_AES_128_WRAP, "id-aes128-wrap"), + (&rfc5911::ID_AES_128_GCM, "id-aes128-GCM"), + (&rfc5911::ID_AES_128_CCM, "id-aes128-CCM"), + (&rfc5912::ID_DSA, "id-dsa"), + (&rfc5912::DSA_WITH_SHA_1, "dsa-with-sha1"), + (&rfc5912::ID_EC_PUBLIC_KEY, "id-ecPublicKey"), + (&rfc5912::SECP_256_R_1, "secp256r1"), + (&rfc5912::ECDSA_WITH_SHA_224, "ecdsa-with-SHA224"), + (&rfc5912::ECDSA_WITH_SHA_256, "ecdsa-with-SHA256"), + (&rfc5912::ECDSA_WITH_SHA_384, "ecdsa-with-SHA384"), + (&rfc5912::ECDSA_WITH_SHA_512, "ecdsa-with-SHA512"), + (&rfc5912::DHPUBLICNUMBER, "dhpublicnumber"), + (&rfc5912::ID_PASSWORD_BASED_MAC, "id-PasswordBasedMac"), + (&rfc5912::ID_DH_BASED_MAC, "id-DHBasedMac"), + (&rfc5912::PKCS_1, "pkcs-1"), + (&rfc5912::RSA_ENCRYPTION, "rsaEncryption"), + (&rfc5912::ID_RSASSA_PSS, "id-RSASSA-PSS"), + ( + &rfc5912::SHA_256_WITH_RSA_ENCRYPTION, + "sha256WithRSAEncryption", + ), + ( + &rfc5912::SHA_384_WITH_RSA_ENCRYPTION, + "sha384WithRSAEncryption", + ), + ( + &rfc5912::SHA_512_WITH_RSA_ENCRYPTION, + "sha512WithRSAEncryption", + ), + ( + &rfc5912::SHA_224_WITH_RSA_ENCRYPTION, + "sha224WithRSAEncryption", + ), + (&rfc5912::MD_2_WITH_RSA_ENCRYPTION, "md2WithRSAEncryption"), + (&rfc5912::MD_5_WITH_RSA_ENCRYPTION, "md5WithRSAEncryption"), + (&rfc5912::SHA_1_WITH_RSA_ENCRYPTION, "sha1WithRSAEncryption"), + (&rfc5912::ID_RSAES_OAEP, "id-RSAES-OAEP"), + (&rfc5912::ID_MGF_1, "id-mgf1"), + (&rfc5912::ID_P_SPECIFIED, "id-pSpecified"), + (&rfc5912::PKCS_9, "pkcs-9"), + (&rfc5912::ID_EXTENSION_REQ, "id-ExtensionReq"), + (&rfc5912::ID_SMIME, "id-smime"), + (&rfc5912::ID_CT, "id-ct"), + ( + &rfc5912::ID_CT_SCVP_CERT_VAL_REQUEST, + "id-ct-scvp-certValRequest", + ), + ( + &rfc5912::ID_CT_SCVP_CERT_VAL_RESPONSE, + "id-ct-scvp-certValResponse", + ), + ( + &rfc5912::ID_CT_SCVP_VAL_POL_REQUEST, + "id-ct-scvp-valPolRequest", + ), + ( + &rfc5912::ID_CT_SCVP_VAL_POL_RESPONSE, + "id-ct-scvp-valPolResponse", + ), + (&rfc5912::ID_CT_ENC_KEY_WITH_ID, "id-ct-encKeyWithID"), + (&rfc5912::ID_AA, "id-aa"), + (&rfc5912::ID_AA_CMC_UNSIGNED_DATA, "id-aa-cmc-unsignedData"), + (&rfc5912::ID_MD_2, "id-md2"), + (&rfc5912::ID_MD_5, "id-md5"), + (&rfc5912::SECT_163_K_1, "sect163k1"), + (&rfc5912::SECT_163_R_2, "sect163r2"), + (&rfc5912::SECT_283_K_1, "sect283k1"), + (&rfc5912::SECT_283_R_1, "sect283r1"), + (&rfc5912::SECT_233_K_1, "sect233k1"), + (&rfc5912::SECT_233_R_1, "sect233r1"), + (&rfc5912::SECP_224_R_1, "secp224r1"), + (&rfc5912::SECP_384_R_1, "secp384r1"), + (&rfc5912::SECP_521_R_1, "secp521r1"), + (&rfc5912::SECT_409_K_1, "sect409k1"), + (&rfc5912::SECT_409_R_1, "sect409r1"), + (&rfc5912::SECT_571_K_1, "sect571k1"), + (&rfc5912::SECT_571_R_1, "sect571r1"), + (&rfc5912::ID_EC_DH, "id-ecDH"), + (&rfc5912::ID_EC_MQV, "id-ecMQV"), + (&rfc5912::ID_SHA_1, "id-sha1"), + (&rfc5912::ID_PKIX, "id-pkix"), + (&rfc5912::ID_PE, "id-pe"), + ( + &rfc5912::ID_PE_AUTHORITY_INFO_ACCESS, + "id-pe-authorityInfoAccess", + ), + (&rfc5912::ID_PE_AC_PROXYING, "id-pe-ac-proxying"), + ( + &rfc5912::ID_PE_SUBJECT_INFO_ACCESS, + "id-pe-subjectInfoAccess", + ), + (&rfc5912::ID_PE_AC_AUDIT_IDENTITY, "id-pe-ac-auditIdentity"), + (&rfc5912::ID_PE_AA_CONTROLS, "id-pe-aaControls"), + (&rfc5912::ID_ACA, "id-aca"), + ( + &rfc5912::ID_ACA_AUTHENTICATION_INFO, + "id-aca-authenticationInfo", + ), + (&rfc5912::ID_ACA_ACCESS_IDENTITY, "id-aca-accessIdentity"), + ( + &rfc5912::ID_ACA_CHARGING_IDENTITY, + "id-aca-chargingIdentity", + ), + (&rfc5912::ID_ACA_GROUP, "id-aca-group"), + (&rfc5912::ID_ACA_ENC_ATTRS, "id-aca-encAttrs"), + (&rfc5912::ID_CCT, "id-cct"), + (&rfc5912::ID_CCT_PKI_DATA, "id-cct-PKIData"), + (&rfc5912::ID_CCT_PKI_RESPONSE, "id-cct-PKIResponse"), + (&rfc5912::ID_STC, "id-stc"), + (&rfc5912::ID_STC_BUILD_PKC_PATH, "id-stc-build-pkc-path"), + ( + &rfc5912::ID_STC_BUILD_VALID_PKC_PATH, + "id-stc-build-valid-pkc-path", + ), + ( + &rfc5912::ID_STC_BUILD_STATUS_CHECKED_PKC_PATH, + "id-stc-build-status-checked-pkc-path", + ), + (&rfc5912::ID_STC_BUILD_AA_PATH, "id-stc-build-aa-path"), + ( + &rfc5912::ID_STC_BUILD_VALID_AA_PATH, + "id-stc-build-valid-aa-path", + ), + ( + &rfc5912::ID_STC_BUILD_STATUS_CHECKED_AA_PATH, + "id-stc-build-status-checked-aa-path", + ), + ( + &rfc5912::ID_STC_STATUS_CHECK_AC_AND_BUILD_STATUS_CHECKED_AA_PATH, + "id-stc-status-check-ac-and-build-status-checked-aa-path", + ), + (&rfc5912::ID_SWB, "id-swb"), + ( + &rfc5912::ID_SWB_PKC_BEST_CERT_PATH, + "id-swb-pkc-best-cert-path", + ), + (&rfc5912::ID_SWB_PKC_CERT, "id-swb-pkc-cert"), + (&rfc5912::ID_SWB_AC_CERT, "id-swb-ac-cert"), + ( + &rfc5912::ID_SWB_PKC_ALL_CERT_PATHS, + "id-swb-pkc-all-cert-paths", + ), + ( + &rfc5912::ID_SWB_PKC_EE_REVOCATION_INFO, + "id-swb-pkc-ee-revocation-info", + ), + ( + &rfc5912::ID_SWB_PKC_C_AS_REVOCATION_INFO, + "id-swb-pkc-CAs-revocation-info", + ), + ( + &rfc5912::ID_SWB_PKC_REVOCATION_INFO, + "id-swb-pkc-revocation-info", + ), + ( + &rfc5912::ID_SWB_PKC_PUBLIC_KEY_INFO, + "id-swb-pkc-public-key-info", + ), + (&rfc5912::ID_SWB_AA_CERT_PATH, "id-swb-aa-cert-path"), + ( + &rfc5912::ID_SWB_AA_REVOCATION_INFO, + "id-swb-aa-revocation-info", + ), + ( + &rfc5912::ID_SWB_AC_REVOCATION_INFO, + "id-swb-ac-revocation-info", + ), + ( + &rfc5912::ID_SWB_RELAYED_RESPONSES, + "id-swb-relayed-responses", + ), + (&rfc5912::ID_SVP, "id-svp"), + ( + &rfc5912::ID_SVP_DEFAULT_VAL_POLICY, + "id-svp-defaultValPolicy", + ), + (&rfc5912::ID_SVP_NAME_VAL_ALG, "id-svp-nameValAlg"), + (&rfc5912::ID_SVP_BASIC_VAL_ALG, "id-svp-basicValAlg"), + (&rfc5912::NAME_COMP_ALG_SET, "NameCompAlgSet"), + (&rfc5912::ID_NVA_DN_COMP_ALG, "id-nva-dnCompAlg"), + (&rfc5912::ID_QT, "id-qt"), + (&rfc5912::ID_QT_CPS, "id-qt-cps"), + (&rfc5912::ID_QT_UNOTICE, "id-qt-unotice"), + (&rfc5912::ID_KP, "id-kp"), + (&rfc5912::ID_KP_SERVER_AUTH, "id-kp-serverAuth"), + (&rfc5912::ID_KP_SCVP_SERVER, "id-kp-scvpServer"), + (&rfc5912::ID_KP_SCVP_CLIENT, "id-kp-scvpClient"), + (&rfc5912::ID_KP_CLIENT_AUTH, "id-kp-clientAuth"), + (&rfc5912::ID_KP_CODE_SIGNING, "id-kp-codeSigning"), + (&rfc5912::ID_KP_EMAIL_PROTECTION, "id-kp-emailProtection"), + (&rfc5912::ID_KP_TIME_STAMPING, "id-kp-timeStamping"), + (&rfc5912::ID_KP_OCSP_SIGNING, "id-kp-OCSPSigning"), + (&rfc5912::ID_IT, "id-it"), + (&rfc5912::ID_IT_CA_PROT_ENC_CERT, "id-it-caProtEncCert"), + (&rfc5912::ID_IT_KEY_PAIR_PARAM_REQ, "id-it-keyPairParamReq"), + (&rfc5912::ID_IT_KEY_PAIR_PARAM_REP, "id-it-keyPairParamRep"), + (&rfc5912::ID_IT_REV_PASSPHRASE, "id-it-revPassphrase"), + (&rfc5912::ID_IT_IMPLICIT_CONFIRM, "id-it-implicitConfirm"), + (&rfc5912::ID_IT_CONFIRM_WAIT_TIME, "id-it-confirmWaitTime"), + (&rfc5912::ID_IT_ORIG_PKI_MESSAGE, "id-it-origPKIMessage"), + (&rfc5912::ID_IT_SUPP_LANG_TAGS, "id-it-suppLangTags"), + ( + &rfc5912::ID_IT_SIGN_KEY_PAIR_TYPES, + "id-it-signKeyPairTypes", + ), + (&rfc5912::ID_IT_ENC_KEY_PAIR_TYPES, "id-it-encKeyPairTypes"), + (&rfc5912::ID_IT_PREFERRED_SYMM_ALG, "id-it-preferredSymmAlg"), + (&rfc5912::ID_IT_CA_KEY_UPDATE_INFO, "id-it-caKeyUpdateInfo"), + (&rfc5912::ID_IT_CURRENT_CRL, "id-it-currentCRL"), + (&rfc5912::ID_IT_UNSUPPORTED_OI_DS, "id-it-unsupportedOIDs"), + (&rfc5912::ID_AD, "id-ad"), + (&rfc5912::ID_AD_OCSP, "id-ad-ocsp"), + (&rfc5912::ID_AD_CA_ISSUERS, "id-ad-caIssuers"), + (&rfc5912::ID_AD_TIME_STAMPING, "id-ad-timeStamping"), + (&rfc5912::ID_AD_CA_REPOSITORY, "id-ad-caRepository"), + (&rfc5912::ID_PKIP, "id-pkip"), + (&rfc5912::ID_REG_CTRL, "id-regCtrl"), + (&rfc5912::ID_REG_CTRL_REG_TOKEN, "id-regCtrl-regToken"), + ( + &rfc5912::ID_REG_CTRL_AUTHENTICATOR, + "id-regCtrl-authenticator", + ), + ( + &rfc5912::ID_REG_CTRL_PKI_PUBLICATION_INFO, + "id-regCtrl-pkiPublicationInfo", + ), + ( + &rfc5912::ID_REG_CTRL_PKI_ARCHIVE_OPTIONS, + "id-regCtrl-pkiArchiveOptions", + ), + (&rfc5912::ID_REG_CTRL_OLD_CERT_ID, "id-regCtrl-oldCertID"), + ( + &rfc5912::ID_REG_CTRL_PROTOCOL_ENCR_KEY, + "id-regCtrl-protocolEncrKey", + ), + (&rfc5912::ID_REG_INFO, "id-regInfo"), + (&rfc5912::ID_REG_INFO_UTF_8_PAIRS, "id-regInfo-utf8Pairs"), + (&rfc5912::ID_REG_INFO_CERT_REQ, "id-regInfo-certReq"), + (&rfc5912::ID_ALG_NO_SIGNATURE, "id-alg-noSignature"), + (&rfc5912::ID_CMC, "id-cmc"), + (&rfc5912::ID_CMC_STATUS_INFO, "id-cmc-statusInfo"), + (&rfc5912::ID_CMC_DECRYPTED_POP, "id-cmc-decryptedPOP"), + (&rfc5912::ID_CMC_LRA_POP_WITNESS, "id-cmc-lraPOPWitness"), + (&rfc5912::ID_CMC_GET_CERT, "id-cmc-getCert"), + (&rfc5912::ID_CMC_GET_CRL, "id-cmc-getCRL"), + (&rfc5912::ID_CMC_REVOKE_REQUEST, "id-cmc-revokeRequest"), + (&rfc5912::ID_CMC_REG_INFO, "id-cmc-regInfo"), + (&rfc5912::ID_CMC_RESPONSE_INFO, "id-cmc-responseInfo"), + (&rfc5912::ID_CMC_IDENTIFICATION, "id-cmc-identification"), + (&rfc5912::ID_CMC_QUERY_PENDING, "id-cmc-queryPending"), + (&rfc5912::ID_CMC_POP_LINK_RANDOM, "id-cmc-popLinkRandom"), + (&rfc5912::ID_CMC_POP_LINK_WITNESS, "id-cmc-popLinkWitness"), + ( + &rfc5912::ID_CMC_CONFIRM_CERT_ACCEPTANCE, + "id-cmc-confirmCertAcceptance", + ), + (&rfc5912::ID_CMC_STATUS_INFO_V_2, "id-cmc-statusInfoV2"), + (&rfc5912::ID_CMC_TRUSTED_ANCHORS, "id-cmc-trustedAnchors"), + (&rfc5912::ID_CMC_AUTH_DATA, "id-cmc-authData"), + (&rfc5912::ID_CMC_BATCH_REQUESTS, "id-cmc-batchRequests"), + (&rfc5912::ID_CMC_BATCH_RESPONSES, "id-cmc-batchResponses"), + (&rfc5912::ID_CMC_IDENTITY_PROOF, "id-cmc-identityProof"), + (&rfc5912::ID_CMC_PUBLISH_CERT, "id-cmc-publishCert"), + (&rfc5912::ID_CMC_MOD_CERT_TEMPLATE, "id-cmc-modCertTemplate"), + ( + &rfc5912::ID_CMC_CONTROL_PROCESSED, + "id-cmc-controlProcessed", + ), + ( + &rfc5912::ID_CMC_IDENTITY_PROOF_V_2, + "id-cmc-identityProofV2", + ), + ( + &rfc5912::ID_CMC_POP_LINK_WITNESS_V_2, + "id-cmc-popLinkWitnessV2", + ), + (&rfc5912::ID_CMC_DATA_RETURN, "id-cmc-dataReturn"), + (&rfc5912::ID_CMC_TRANSACTION_ID, "id-cmc-transactionId"), + (&rfc5912::ID_CMC_SENDER_NONCE, "id-cmc-senderNonce"), + (&rfc5912::ID_CMC_RECIPIENT_NONCE, "id-cmc-recipientNonce"), + (&rfc5912::ID_CMC_ADD_EXTENSIONS, "id-cmc-addExtensions"), + (&rfc5912::ID_CMC_ENCRYPTED_POP, "id-cmc-encryptedPOP"), + ( + &rfc5912::ID_KEY_EXCHANGE_ALGORITHM, + "id-keyExchangeAlgorithm", + ), + (&rfc5912::ID_SHA_256, "id-sha256"), + (&rfc5912::ID_SHA_384, "id-sha384"), + (&rfc5912::ID_SHA_512, "id-sha512"), + (&rfc5912::ID_SHA_224, "id-sha224"), + (&rfc5912::DSA_WITH_SHA_224, "dsa-with-sha224"), + (&rfc5912::DSA_WITH_SHA_256, "dsa-with-sha256"), + (&rfc5912::HOLD_INSTRUCTION, "holdInstruction"), + (&rfc5912::ID_HOLDINSTRUCTION_NONE, "id-holdinstruction-none"), + ( + &rfc5912::ID_HOLDINSTRUCTION_CALLISSUER, + "id-holdinstruction-callissuer", + ), + ( + &rfc5912::ID_HOLDINSTRUCTION_REJECT, + "id-holdinstruction-reject", + ), + (&rfc5912::ID_CE, "id-ce"), + ( + &rfc5912::ID_CE_SUBJECT_KEY_IDENTIFIER, + "id-ce-subjectKeyIdentifier", + ), + (&rfc5912::ID_CE_KEY_USAGE, "id-ce-keyUsage"), + ( + &rfc5912::ID_CE_PRIVATE_KEY_USAGE_PERIOD, + "id-ce-privateKeyUsagePeriod", + ), + (&rfc5912::ID_CE_SUBJECT_ALT_NAME, "id-ce-subjectAltName"), + (&rfc5912::ID_CE_ISSUER_ALT_NAME, "id-ce-issuerAltName"), + (&rfc5912::ID_CE_BASIC_CONSTRAINTS, "id-ce-basicConstraints"), + (&rfc5912::ID_CE_CRL_NUMBER, "id-ce-cRLNumber"), + (&rfc5912::ID_CE_CRL_REASONS, "id-ce-cRLReasons"), + ( + &rfc5912::ID_CE_HOLD_INSTRUCTION_CODE, + "id-ce-holdInstructionCode", + ), + (&rfc5912::ID_CE_INVALIDITY_DATE, "id-ce-invalidityDate"), + ( + &rfc5912::ID_CE_DELTA_CRL_INDICATOR, + "id-ce-deltaCRLIndicator", + ), + ( + &rfc5912::ID_CE_ISSUING_DISTRIBUTION_POINT, + "id-ce-issuingDistributionPoint", + ), + ( + &rfc5912::ID_CE_CERTIFICATE_ISSUER, + "id-ce-certificateIssuer", + ), + (&rfc5912::ID_CE_NAME_CONSTRAINTS, "id-ce-nameConstraints"), + ( + &rfc5912::ID_CE_CRL_DISTRIBUTION_POINTS, + "id-ce-cRLDistributionPoints", + ), + ( + &rfc5912::ID_CE_CERTIFICATE_POLICIES, + "id-ce-certificatePolicies", + ), + (&rfc5912::ID_CE_POLICY_MAPPINGS, "id-ce-policyMappings"), + ( + &rfc5912::ID_CE_AUTHORITY_KEY_IDENTIFIER, + "id-ce-authorityKeyIdentifier", + ), + ( + &rfc5912::ID_CE_POLICY_CONSTRAINTS, + "id-ce-policyConstraints", + ), + (&rfc5912::ID_CE_EXT_KEY_USAGE, "id-ce-extKeyUsage"), + (&rfc5912::ANY_EXTENDED_KEY_USAGE, "anyExtendedKeyUsage"), + (&rfc5912::ID_CE_FRESHEST_CRL, "id-ce-freshestCRL"), + (&rfc5912::ID_CE_INHIBIT_ANY_POLICY, "id-ce-inhibitAnyPolicy"), + ( + &rfc5912::ID_CE_TARGET_INFORMATION, + "id-ce-targetInformation", + ), + (&rfc5912::ID_CE_NO_REV_AVAIL, "id-ce-noRevAvail"), + ( + &rfc5912::ID_CE_SUBJECT_DIRECTORY_ATTRIBUTES, + "id-ce-subjectDirectoryAttributes", + ), + (&rfc5912::ID_AT, "id-at"), + (&rfc5912::ID_AT_ROLE, "id-at-role"), + (&rfc6109::LDIF_LOCATION_URL_OBJECT, "LDIFLocationURLObject"), + (&rfc6109::PROVIDER, "provider"), + ( + &rfc6109::PROVIDER_CERTIFICATE_HASH, + "providerCertificateHash", + ), + (&rfc6109::PROVIDER_CERTIFICATE, "providerCertificate"), + (&rfc6109::PROVIDER_NAME, "providerName"), + (&rfc6109::MAIL_RECEIPT, "mailReceipt"), + (&rfc6109::MANAGED_DOMAINS, "managedDomains"), + (&rfc6109::LDIF_LOCATION_URL, "LDIFLocationURL"), + (&rfc6109::PROVIDER_UNIT, "providerUnit"), + (&rfc6268::RSADSI, "rsadsi"), + (&rfc6268::ID_DATA, "id-data"), + (&rfc6268::ID_SIGNED_DATA, "id-signedData"), + (&rfc6268::ID_ENVELOPED_DATA, "id-envelopedData"), + (&rfc6268::ID_DIGESTED_DATA, "id-digestedData"), + (&rfc6268::ID_ENCRYPTED_DATA, "id-encryptedData"), + ( + &rfc6268::ID_CT_CONTENT_COLLECTION, + "id-ct-contentCollection", + ), + (&rfc6268::ID_CT_AUTH_DATA, "id-ct-authData"), + (&rfc6268::ID_CT_CONTENT_WITH_ATTRS, "id-ct-contentWithAttrs"), + ( + &rfc6268::ID_CT_AUTH_ENVELOPED_DATA, + "id-ct-authEnvelopedData", + ), + (&rfc6268::ID_CT_CONTENT_INFO, "id-ct-contentInfo"), + (&rfc6268::ID_CT_COMPRESSED_DATA, "id-ct-compressedData"), + ( + &rfc6268::ID_AA_BINARY_SIGNING_TIME, + "id-aa-binarySigningTime", + ), + (&rfc6268::ID_ALG_ZLIB_COMPRESS, "id-alg-zlibCompress"), + ( + &rfc6268::ID_AA_MULTIPLE_SIGNATURES, + "id-aa-multipleSignatures", + ), + (&rfc6268::ID_CONTENT_TYPE, "id-contentType"), + (&rfc6268::ID_MESSAGE_DIGEST, "id-messageDigest"), + (&rfc6268::ID_SIGNING_TIME, "id-signingTime"), + (&rfc6268::ID_COUNTERSIGNATURE, "id-countersignature"), + (&rfc6268::DIGEST_ALGORITHM, "digestAlgorithm"), + (&rfc6268::ID_HMAC_WITH_SHA_384, "id-hmacWithSHA384"), + (&rfc6268::ID_HMAC_WITH_SHA_512, "id-hmacWithSHA512"), + (&rfc6268::ID_HMAC_WITH_SHA_224, "id-hmacWithSHA224"), + (&rfc6268::ID_HMAC_WITH_SHA_256, "id-hmacWithSHA256"), + (&rfc6960::ID_PKIX_OCSP, "id-pkix-ocsp"), + (&rfc6960::ID_PKIX_OCSP_BASIC, "id-pkix-ocsp-basic"), + (&rfc6960::ID_PKIX_OCSP_NONCE, "id-pkix-ocsp-nonce"), + (&rfc6960::ID_PKIX_OCSP_CRL, "id-pkix-ocsp-crl"), + (&rfc6960::ID_PKIX_OCSP_RESPONSE, "id-pkix-ocsp-response"), + (&rfc6960::ID_PKIX_OCSP_NOCHECK, "id-pkix-ocsp-nocheck"), + ( + &rfc6960::ID_PKIX_OCSP_ARCHIVE_CUTOFF, + "id-pkix-ocsp-archive-cutoff", + ), + ( + &rfc6960::ID_PKIX_OCSP_SERVICE_LOCATOR, + "id-pkix-ocsp-service-locator", + ), + ( + &rfc6960::ID_PKIX_OCSP_PREF_SIG_ALGS, + "id-pkix-ocsp-pref-sig-algs", + ), + ( + &rfc6960::ID_PKIX_OCSP_EXTENDED_REVOKE, + "id-pkix-ocsp-extended-revoke", + ), + (&rfc6962::GOOGLE, "google"), + (&rfc6962::CT_PRECERT_SCTS, "ct-precert-scts"), + (&rfc6962::CT_PRECERT_POISON, "ct-precert-poison"), + (&rfc6962::CT_PRECERT_SIGNING_CERT, "ct-precert-signing-cert"), + (&rfc7107::ID_SMIME, "id-smime"), + (&rfc7107::ID_MOD, "id-mod"), + (&rfc7107::ID_CT, "id-ct"), + (&rfc7107::ID_EIT, "id-eit"), + (&rfc7107::ID_CAP, "id-cap"), + (&rfc7107::ID_PSKC, "id-pskc"), + (&rfc7107::ID_AA, "id-aa"), + (&rfc7107::ID_ALG, "id-alg"), + (&rfc7107::ID_CD, "id-cd"), + (&rfc7107::ID_SPQ, "id-spq"), + (&rfc7107::ID_CTI, "id-cti"), + (&rfc7107::ID_TSP, "id-tsp"), + (&rfc7107::ID_SKD, "id-skd"), + (&rfc7107::ID_STI, "id-sti"), + (&rfc7299::ID_PKIX, "id-pkix"), + (&rfc7299::ID_MOD, "id-mod"), + (&rfc7299::ID_PE, "id-pe"), + (&rfc7299::ID_ACA, "id-aca"), + (&rfc7299::ID_QCS, "id-qcs"), + (&rfc7299::ID_CCT, "id-cct"), + (&rfc7299::ID_TEST, "id-TEST"), + (&rfc7299::ID_CP, "id-cp"), + (&rfc7299::ID_CET, "id-cet"), + (&rfc7299::ID_RI, "id-ri"), + (&rfc7299::ID_SCT, "id-sct"), + (&rfc7299::ID_SWB, "id-swb"), + (&rfc7299::ID_SVP, "id-svp"), + (&rfc7299::ID_NVAE, "id-nvae"), + (&rfc7299::ID_BVAE, "id-bvae"), + (&rfc7299::ID_DNVAE, "id-dnvae"), + (&rfc7299::ID_QT, "id-qt"), + (&rfc7299::ID_LOGO, "id-logo"), + (&rfc7299::ID_PPL, "id-ppl"), + (&rfc7299::ID_MR, "id-mr"), + (&rfc7299::ID_SKIS, "id-skis"), + (&rfc7299::ID_KP, "id-kp"), + (&rfc7299::ID_IT, "id-it"), + (&rfc7299::ID_AD, "id-ad"), + (&rfc7299::ID_PKIX_OCSP, "id-pkix-ocsp"), + (&rfc7299::ID_PKIP, "id-pkip"), + (&rfc7299::ID_REG_CTRL, "id-regCtrl"), + (&rfc7299::ID_REG_INFO, "id-regInfo"), + (&rfc7299::ID_ALG, "id-alg"), + (&rfc7299::ID_CMC, "id-cmc"), + (&rfc7299::ID_CMC_GLA_RR, "id-cmc-glaRR"), + (&rfc7299::ID_ON, "id-on"), + (&rfc7299::ID_PDA, "id-pda"), + (&rfc7532::FEDFS_UUID, "fedfsUuid"), + (&rfc7532::FEDFS_FSL_PORT, "fedfsFslPort"), + (&rfc7532::FEDFS_NFS_PATH, "fedfsNfsPath"), + ( + &rfc7532::FEDFS_NSDB_CONTAINER_INFO, + "fedfsNsdbContainerInfo", + ), + (&rfc7532::FEDFS_FSN, "fedfsFsn"), + (&rfc7532::FEDFS_FSL, "fedfsFsl"), + (&rfc7532::FEDFS_NFS_FSL, "fedfsNfsFsl"), + (&rfc7532::FEDFS_NFS_MAJOR_VER, "fedfsNfsMajorVer"), + (&rfc7532::FEDFS_NFS_MINOR_VER, "fedfsNfsMinorVer"), + (&rfc7532::FEDFS_NFS_CURRENCY, "fedfsNfsCurrency"), + ( + &rfc7532::FEDFS_NFS_GEN_FLAG_WRITABLE, + "fedfsNfsGenFlagWritable", + ), + (&rfc7532::FEDFS_NFS_GEN_FLAG_GOING, "fedfsNfsGenFlagGoing"), + (&rfc7532::FEDFS_NFS_GEN_FLAG_SPLIT, "fedfsNfsGenFlagSplit"), + (&rfc7532::FEDFS_NFS_TRANS_FLAG_RDMA, "fedfsNfsTransFlagRdma"), + (&rfc7532::FEDFS_NFS_CLASS_SIMUL, "fedfsNfsClassSimul"), + (&rfc7532::FEDFS_NFS_CLASS_HANDLE, "fedfsNfsClassHandle"), + (&rfc7532::FEDFS_FSL_TTL, "fedfsFslTTL"), + (&rfc7532::FEDFS_NFS_CLASS_FILEID, "fedfsNfsClassFileid"), + (&rfc7532::FEDFS_NFS_CLASS_WRITEVER, "fedfsNfsClassWritever"), + (&rfc7532::FEDFS_NFS_CLASS_CHANGE, "fedfsNfsClassChange"), + (&rfc7532::FEDFS_NFS_CLASS_READDIR, "fedfsNfsClassReaddir"), + (&rfc7532::FEDFS_NFS_READ_RANK, "fedfsNfsReadRank"), + (&rfc7532::FEDFS_NFS_READ_ORDER, "fedfsNfsReadOrder"), + (&rfc7532::FEDFS_NFS_WRITE_RANK, "fedfsNfsWriteRank"), + (&rfc7532::FEDFS_NFS_WRITE_ORDER, "fedfsNfsWriteOrder"), + (&rfc7532::FEDFS_NFS_VAR_SUB, "fedfsNfsVarSub"), + (&rfc7532::FEDFS_NFS_VALID_FOR, "fedfsNfsValidFor"), + (&rfc7532::FEDFS_ANNOTATION, "fedfsAnnotation"), + (&rfc7532::FEDFS_NFS_URI, "fedfsNfsURI"), + (&rfc7532::FEDFS_DESCR, "fedfsDescr"), + (&rfc7532::FEDFS_NCE_DN, "fedfsNceDN"), + (&rfc7532::FEDFS_FSN_TTL, "fedfsFsnTTL"), + (&rfc7532::FEDFS_NET_ADDR, "fedfsNetAddr"), + (&rfc7532::FEDFS_NET_PORT, "fedfsNetPort"), + (&rfc7532::FEDFS_FSN_UUID, "fedfsFsnUuid"), + (&rfc7532::FEDFS_NSDB_NAME, "fedfsNsdbName"), + (&rfc7532::FEDFS_NSDB_PORT, "fedfsNsdbPort"), + (&rfc7532::FEDFS_NCE_PREFIX, "fedfsNcePrefix"), + (&rfc7532::FEDFS_FSL_UUID, "fedfsFslUuid"), + (&rfc7532::FEDFS_FSL_HOST, "fedfsFslHost"), + (&rfc7612::PRINTER_DEVICE_ID, "printer-device-id"), + ( + &rfc7612::PRINTER_DEVICE_SERVICE_COUNT, + "printer-device-service-count", + ), + (&rfc7612::PRINTER_UUID, "printer-uuid"), + (&rfc7612::PRINTER_CHARGE_INFO, "printer-charge-info"), + (&rfc7612::PRINTER_CHARGE_INFO_URI, "printer-charge-info-uri"), + (&rfc7612::PRINTER_GEO_LOCATION, "printer-geo-location"), + ( + &rfc7612::PRINTER_IPP_FEATURES_SUPPORTED, + "printer-ipp-features-supported", + ), + (&rfc8284::JID_OBJECT, "JIDObject"), + (&rfc8284::JID, "jid"), + (&rfc8410::ID_EDWARDS_CURVE_ALGS, "id-edwards-curve-algs"), + (&rfc8410::ID_X_25519, "id-X25519"), + (&rfc8410::ID_X_448, "id-X448"), + (&rfc8410::ID_ED_25519, "id-Ed25519"), + (&rfc8410::ID_ED_448, "id-Ed448"), + (&rfc8894::ID_VERI_SIGN, "id-VeriSign"), + (&rfc8894::ID_PKI, "id-pki"), + (&rfc8894::ID_ATTRIBUTES, "id-attributes"), + (&rfc8894::ID_MESSAGE_TYPE, "id-messageType"), + (&rfc8894::ID_PKI_STATUS, "id-pkiStatus"), + (&rfc8894::ID_FAIL_INFO, "id-failInfo"), + (&rfc8894::ID_SENDER_NONCE, "id-senderNonce"), + (&rfc8894::ID_RECIPIENT_NONCE, "id-recipientNonce"), + (&rfc8894::ID_TRANSACTION_ID, "id-transactionID"), +]); diff --git a/src/rust/vendor/const-oid/src/encoder.rs b/src/rust/vendor/const-oid/src/encoder.rs new file mode 100644 index 000000000..4df3aab45 --- /dev/null +++ b/src/rust/vendor/const-oid/src/encoder.rs @@ -0,0 +1,165 @@ +//! OID encoder with `const` support. + +use crate::{ + arcs::{ARC_MAX_FIRST, ARC_MAX_SECOND}, + Arc, Error, ObjectIdentifier, Result, +}; + +/// BER/DER encoder +#[derive(Debug)] +pub(crate) struct Encoder { + /// Current state + state: State, + + /// Bytes of the OID being encoded in-progress + bytes: [u8; ObjectIdentifier::MAX_SIZE], + + /// Current position within the byte buffer + cursor: usize, +} + +/// Current state of the encoder +#[derive(Debug)] +enum State { + /// Initial state - no arcs yet encoded + Initial, + + /// First arc parsed + FirstArc(Arc), + + /// Encoding base 128 body of the OID + Body, +} + +impl Encoder { + /// Create a new encoder initialized to an empty default state. + pub(crate) const fn new() -> Self { + Self { + state: State::Initial, + bytes: [0u8; ObjectIdentifier::MAX_SIZE], + cursor: 0, + } + } + + /// Extend an existing OID. + pub(crate) const fn extend(oid: ObjectIdentifier) -> Self { + Self { + state: State::Body, + bytes: oid.bytes, + cursor: oid.length as usize, + } + } + + /// Encode an [`Arc`] as base 128 into the internal buffer. + pub(crate) const fn arc(mut self, arc: Arc) -> Result { + match self.state { + State::Initial => { + if arc > ARC_MAX_FIRST { + return Err(Error::ArcInvalid { arc }); + } + + self.state = State::FirstArc(arc); + Ok(self) + } + // Ensured not to overflow by `ARC_MAX_SECOND` check + #[allow(clippy::integer_arithmetic)] + State::FirstArc(first_arc) => { + if arc > ARC_MAX_SECOND { + return Err(Error::ArcInvalid { arc }); + } + + self.state = State::Body; + self.bytes[0] = (first_arc * (ARC_MAX_SECOND + 1)) as u8 + arc as u8; + self.cursor = 1; + Ok(self) + } + // TODO(tarcieri): finer-grained overflow safety / checked arithmetic + #[allow(clippy::integer_arithmetic)] + State::Body => { + // Total number of bytes in encoded arc - 1 + let nbytes = base128_len(arc); + + // Shouldn't overflow on any 16-bit+ architectures + if self.cursor + nbytes + 1 >= ObjectIdentifier::MAX_SIZE { + return Err(Error::Length); + } + + let new_cursor = self.cursor + nbytes + 1; + + // TODO(tarcieri): use `?` when stable in `const fn` + match self.encode_base128_byte(arc, nbytes, false) { + Ok(mut encoder) => { + encoder.cursor = new_cursor; + Ok(encoder) + } + Err(err) => Err(err), + } + } + } + } + + /// Finish encoding an OID. + pub(crate) const fn finish(self) -> Result { + if self.cursor >= 2 { + Ok(ObjectIdentifier { + bytes: self.bytes, + length: self.cursor as u8, + }) + } else { + Err(Error::NotEnoughArcs) + } + } + + /// Encode a single byte of a Base 128 value. + const fn encode_base128_byte(mut self, mut n: u32, i: usize, continued: bool) -> Result { + let mask = if continued { 0b10000000 } else { 0 }; + + // Underflow checked by branch + #[allow(clippy::integer_arithmetic)] + if n > 0x80 { + self.bytes[checked_add!(self.cursor, i)] = (n & 0b1111111) as u8 | mask; + n >>= 7; + + if i > 0 { + self.encode_base128_byte(n, i.saturating_sub(1), true) + } else { + Err(Error::Base128) + } + } else { + self.bytes[self.cursor] = n as u8 | mask; + Ok(self) + } + } +} + +/// Compute the length - 1 of an arc when encoded in base 128. +const fn base128_len(arc: Arc) -> usize { + match arc { + 0..=0x7f => 0, + 0x80..=0x3fff => 1, + 0x4000..=0x1fffff => 2, + 0x200000..=0x1fffffff => 3, + _ => 4, + } +} + +#[cfg(test)] +mod tests { + use super::Encoder; + use hex_literal::hex; + + /// OID `1.2.840.10045.2.1` encoded as ASN.1 BER/DER + const EXAMPLE_OID_BER: &[u8] = &hex!("2A8648CE3D0201"); + + #[test] + fn encode() { + let encoder = Encoder::new(); + let encoder = encoder.arc(1).unwrap(); + let encoder = encoder.arc(2).unwrap(); + let encoder = encoder.arc(840).unwrap(); + let encoder = encoder.arc(10045).unwrap(); + let encoder = encoder.arc(2).unwrap(); + let encoder = encoder.arc(1).unwrap(); + assert_eq!(&encoder.bytes[..encoder.cursor], EXAMPLE_OID_BER); + } +} diff --git a/src/rust/vendor/const-oid/src/error.rs b/src/rust/vendor/const-oid/src/error.rs new file mode 100644 index 000000000..528ce785c --- /dev/null +++ b/src/rust/vendor/const-oid/src/error.rs @@ -0,0 +1,83 @@ +//! Error types + +use crate::Arc; +use core::fmt; + +/// Result type +pub type Result = core::result::Result; + +/// OID errors. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub enum Error { + /// Arc exceeds allowed range (i.e. for first or second OID) + ArcInvalid { + /// Arc value that is erroneous. + arc: Arc, + }, + + /// Arc is too big (exceeds 32-bit limits of this library). + /// + /// Technically the size of an arc is not constrained by X.660, however + /// this library has elected to use `u32` as the arc representation as + /// sufficient for PKIX/PKCS usages. + ArcTooBig, + + /// Base 128 encoding error (used in BER/DER serialization of arcs). + Base128, + + /// Expected a digit, but was provided something else. + DigitExpected { + /// What was found instead of a digit + actual: u8, + }, + + /// Input data is empty. + Empty, + + /// OID length is invalid (too short or too long). + Length, + + /// Minimum 3 arcs required. + NotEnoughArcs, + + /// Trailing `.` character at end of input. + TrailingDot, +} + +impl Error { + /// Escalate this error into a panic. + /// + /// This is a workaround until `Result::unwrap` is allowed in `const fn`. + #[allow(clippy::panic)] + pub(crate) const fn panic(self) -> ! { + match self { + Error::ArcInvalid { .. } | Error::ArcTooBig => panic!("OID contains invalid arc"), + Error::Base128 => panic!("OID contains arc with invalid base 128 encoding"), + Error::DigitExpected { .. } => panic!("OID expected to start with digit"), + Error::Empty => panic!("OID value is empty"), + Error::Length => panic!("OID length invalid"), + Error::NotEnoughArcs => panic!("OID requires minimum of 3 arcs"), + Error::TrailingDot => panic!("OID ends with invalid trailing '.'"), + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Error::ArcInvalid { arc } => write!(f, "OID contains out-of-range arc: {}", arc), + Error::ArcTooBig => f.write_str("OID contains arc which is larger than 32-bits"), + Error::Base128 => f.write_str("OID contains arc with invalid base 128 encoding"), + Error::DigitExpected { actual } => { + write!(f, "expected digit, got '{}'", char::from(actual)) + } + Error::Empty => f.write_str("OID value is empty"), + Error::Length => f.write_str("OID length invalid"), + Error::NotEnoughArcs => f.write_str("OID requires minimum of 3 arcs"), + Error::TrailingDot => f.write_str("OID ends with invalid trailing '.'"), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for Error {} diff --git a/src/rust/vendor/const-oid/src/lib.rs b/src/rust/vendor/const-oid/src/lib.rs new file mode 100644 index 000000000..5bdef085d --- /dev/null +++ b/src/rust/vendor/const-oid/src/lib.rs @@ -0,0 +1,280 @@ +#![no_std] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![doc = include_str!("../README.md")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" +)] +#![forbid(unsafe_code)] +#![warn( + clippy::integer_arithmetic, + clippy::panic, + clippy::panic_in_result_fn, + clippy::unwrap_used, + missing_docs, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] + +#[cfg(feature = "std")] +extern crate std; + +#[macro_use] +mod checked; + +mod arcs; +mod encoder; +mod error; +mod parser; + +#[cfg(feature = "db")] +#[cfg_attr(docsrs, doc(cfg(feature = "db")))] +pub mod db; + +pub use crate::{ + arcs::{Arc, Arcs}, + error::{Error, Result}, +}; + +use crate::encoder::Encoder; +use core::{fmt, str::FromStr}; + +/// A trait which associates an OID with a type. +pub trait AssociatedOid { + /// The OID associated with this type. + const OID: ObjectIdentifier; +} + +/// A trait which associates a dynamic, `&self`-dependent OID with a type, +/// which may change depending on the type's value. +/// +/// This trait is object safe and auto-impl'd for any types which impl +/// [`AssociatedOid`]. +pub trait DynAssociatedOid { + /// Get the OID associated with this value. + fn oid(&self) -> ObjectIdentifier; +} + +impl DynAssociatedOid for T { + fn oid(&self) -> ObjectIdentifier { + T::OID + } +} + +/// Object identifier (OID). +/// +/// OIDs are hierarchical structures consisting of "arcs", i.e. integer +/// identifiers. +/// +/// # Validity +/// +/// In order for an OID to be considered valid by this library, it must meet +/// the following criteria: +/// +/// - The OID MUST have at least 3 arcs +/// - The first arc MUST be within the range 0-2 +/// - The second arc MUST be within the range 0-39 +/// - The BER/DER encoding of the OID MUST be shorter than +/// [`ObjectIdentifier::MAX_SIZE`] +#[derive(Copy, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)] +pub struct ObjectIdentifier { + /// Length in bytes + length: u8, + + /// Array containing BER/DER-serialized bytes (no header) + bytes: [u8; Self::MAX_SIZE], +} + +#[allow(clippy::len_without_is_empty)] +impl ObjectIdentifier { + /// Maximum size of a BER/DER-encoded OID in bytes. + pub const MAX_SIZE: usize = 39; // makes `ObjectIdentifier` 40-bytes total w\ 1-byte length + + /// Parse an [`ObjectIdentifier`] from the dot-delimited string form, + /// panicking on parse errors. + /// + /// This function exists as a workaround for `unwrap` not yet being + /// stable in `const fn` contexts, and is intended to allow the result to + /// be bound to a constant value: + /// + /// ``` + /// use const_oid::ObjectIdentifier; + /// + /// pub const MY_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.1"); + /// ``` + /// + /// In future versions of Rust it should be possible to replace this with + /// `ObjectIdentifier::new(...).unwrap()`. + /// + /// Use [`ObjectIdentifier::new`] for fallible parsing. + // TODO(tarcieri): remove this when `Result::unwrap` is `const fn` + pub const fn new_unwrap(s: &str) -> Self { + match Self::new(s) { + Ok(oid) => oid, + Err(err) => err.panic(), + } + } + + /// Parse an [`ObjectIdentifier`] from the dot-delimited string form. + pub const fn new(s: &str) -> Result { + // TODO(tarcieri): use `?` when stable in `const fn` + match parser::Parser::parse(s) { + Ok(parser) => parser.finish(), + Err(err) => Err(err), + } + } + + /// Parse an OID from a slice of [`Arc`] values (i.e. integers). + pub fn from_arcs(arcs: impl IntoIterator) -> Result { + let mut encoder = Encoder::new(); + + for arc in arcs { + encoder = encoder.arc(arc)?; + } + + encoder.finish() + } + + /// Parse an OID from from its BER/DER encoding. + pub fn from_bytes(ber_bytes: &[u8]) -> Result { + let len = ber_bytes.len(); + + match len { + 0 => return Err(Error::Empty), + 3..=Self::MAX_SIZE => (), + _ => return Err(Error::NotEnoughArcs), + } + let mut bytes = [0u8; Self::MAX_SIZE]; + bytes[..len].copy_from_slice(ber_bytes); + + let oid = Self { + bytes, + length: len as u8, + }; + + // Ensure arcs are well-formed + let mut arcs = oid.arcs(); + while arcs.try_next()?.is_some() {} + + Ok(oid) + } + + /// Get the BER/DER serialization of this OID as bytes. + /// + /// Note that this encoding omits the tag/length, and only contains the + /// value portion of the encoded OID. + pub fn as_bytes(&self) -> &[u8] { + &self.bytes[..self.length as usize] + } + + /// Return the arc with the given index, if it exists. + pub fn arc(&self, index: usize) -> Option { + self.arcs().nth(index) + } + + /// Iterate over the arcs (a.k.a. nodes) of an [`ObjectIdentifier`]. + /// + /// Returns [`Arcs`], an iterator over [`Arc`] values. + pub fn arcs(&self) -> Arcs<'_> { + Arcs::new(self) + } + + /// Get the length of this [`ObjectIdentifier`] in arcs. + pub fn len(&self) -> usize { + self.arcs().count() + } + + /// Get the parent OID of this one (if applicable). + pub fn parent(&self) -> Option { + let num_arcs = self.len().checked_sub(1)?; + Self::from_arcs(self.arcs().take(num_arcs)).ok() + } + + /// Push an additional arc onto this OID, returning the child OID. + pub const fn push_arc(self, arc: Arc) -> Result { + // TODO(tarcieri): use `?` when stable in `const fn` + match Encoder::extend(self).arc(arc) { + Ok(encoder) => encoder.finish(), + Err(err) => Err(err), + } + } +} + +impl AsRef<[u8]> for ObjectIdentifier { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl FromStr for ObjectIdentifier { + type Err = Error; + + fn from_str(string: &str) -> Result { + Self::new(string) + } +} + +impl TryFrom<&[u8]> for ObjectIdentifier { + type Error = Error; + + fn try_from(ber_bytes: &[u8]) -> Result { + Self::from_bytes(ber_bytes) + } +} + +impl From<&ObjectIdentifier> for ObjectIdentifier { + fn from(oid: &ObjectIdentifier) -> ObjectIdentifier { + *oid + } +} + +impl fmt::Debug for ObjectIdentifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ObjectIdentifier({})", self) + } +} + +impl fmt::Display for ObjectIdentifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let len = self.arcs().count(); + + for (i, arc) in self.arcs().enumerate() { + write!(f, "{}", arc)?; + + if let Some(j) = i.checked_add(1) { + if j < len { + write!(f, ".")?; + } + } + } + + Ok(()) + } +} + +// Implement by hand because the derive would create invalid values. +// Use the constructor to create a valid oid with at least 3 arcs. +#[cfg(feature = "arbitrary")] +impl<'a> arbitrary::Arbitrary<'a> for ObjectIdentifier { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + let first = u.int_in_range(0..=arcs::ARC_MAX_FIRST)?; + let second = u.int_in_range(0..=arcs::ARC_MAX_SECOND)?; + let third = u.arbitrary()?; + + let mut oid = Self::from_arcs([first, second, third]) + .map_err(|_| arbitrary::Error::IncorrectFormat)?; + + for arc in u.arbitrary_iter()? { + oid = oid + .push_arc(arc?) + .map_err(|_| arbitrary::Error::IncorrectFormat)?; + } + + Ok(oid) + } + + fn size_hint(depth: usize) -> (usize, Option) { + (Arc::size_hint(depth).0.saturating_mul(3), None) + } +} diff --git a/src/rust/vendor/const-oid/src/parser.rs b/src/rust/vendor/const-oid/src/parser.rs new file mode 100644 index 000000000..6f875faaa --- /dev/null +++ b/src/rust/vendor/const-oid/src/parser.rs @@ -0,0 +1,112 @@ +//! OID string parser with `const` support. + +use crate::{encoder::Encoder, Arc, Error, ObjectIdentifier, Result}; + +/// Const-friendly OID string parser. +/// +/// Parses an OID from the dotted string representation. +#[derive(Debug)] +pub(crate) struct Parser { + /// Current arc in progress + current_arc: Arc, + + /// BER/DER encoder + encoder: Encoder, +} + +impl Parser { + /// Parse an OID from a dot-delimited string e.g. `1.2.840.113549.1.1.1` + pub(crate) const fn parse(s: &str) -> Result { + let bytes = s.as_bytes(); + + if bytes.is_empty() { + return Err(Error::Empty); + } + + match bytes[0] { + b'0'..=b'9' => Self { + current_arc: 0, + encoder: Encoder::new(), + } + .parse_bytes(bytes), + actual => Err(Error::DigitExpected { actual }), + } + } + + /// Finish parsing, returning the result + pub(crate) const fn finish(self) -> Result { + self.encoder.finish() + } + + /// Parse the remaining bytes + const fn parse_bytes(mut self, bytes: &[u8]) -> Result { + match bytes { + // TODO(tarcieri): use `?` when stable in `const fn` + [] => match self.encoder.arc(self.current_arc) { + Ok(encoder) => { + self.encoder = encoder; + Ok(self) + } + Err(err) => Err(err), + }, + // TODO(tarcieri): checked arithmetic + #[allow(clippy::integer_arithmetic)] + [byte @ b'0'..=b'9', remaining @ ..] => { + let digit = byte.saturating_sub(b'0'); + self.current_arc = self.current_arc * 10 + digit as Arc; + self.parse_bytes(remaining) + } + [b'.', remaining @ ..] => { + if remaining.is_empty() { + return Err(Error::TrailingDot); + } + + // TODO(tarcieri): use `?` when stable in `const fn` + match self.encoder.arc(self.current_arc) { + Ok(encoder) => { + self.encoder = encoder; + self.current_arc = 0; + self.parse_bytes(remaining) + } + Err(err) => Err(err), + } + } + [byte, ..] => Err(Error::DigitExpected { actual: *byte }), + } + } +} + +#[cfg(test)] +mod tests { + use super::Parser; + use crate::Error; + + #[test] + fn parse() { + let oid = Parser::parse("1.23.456").unwrap().finish().unwrap(); + assert_eq!(oid, "1.23.456".parse().unwrap()); + } + + #[test] + fn reject_empty_string() { + assert_eq!(Parser::parse("").err().unwrap(), Error::Empty); + } + + #[test] + fn reject_non_digits() { + assert_eq!( + Parser::parse("X").err().unwrap(), + Error::DigitExpected { actual: b'X' } + ); + + assert_eq!( + Parser::parse("1.2.X").err().unwrap(), + Error::DigitExpected { actual: b'X' } + ); + } + + #[test] + fn reject_trailing_dot() { + assert_eq!(Parser::parse("1.23.").err().unwrap(), Error::TrailingDot); + } +} diff --git a/src/rust/vendor/const-oid/tests/lib.rs b/src/rust/vendor/const-oid/tests/lib.rs new file mode 100644 index 000000000..e91dfc6ca --- /dev/null +++ b/src/rust/vendor/const-oid/tests/lib.rs @@ -0,0 +1,209 @@ +//! `const-oid` crate tests + +// TODO(tarcieri): test full set of OID encoding constraints specified here: +// + +use const_oid::{Error, ObjectIdentifier}; +use hex_literal::hex; +use std::string::ToString; + +/// Example OID value with a root arc of `0` (and large arc). +const EXAMPLE_OID_0_STR: &str = "0.9.2342.19200300.100.1.1"; +const EXAMPLE_OID_0_BER: &[u8] = &hex!("0992268993F22C640101"); +const EXAMPLE_OID_0: ObjectIdentifier = ObjectIdentifier::new_unwrap(EXAMPLE_OID_0_STR); + +/// Example OID value with a root arc of `1`. +const EXAMPLE_OID_1_STR: &str = "1.2.840.10045.2.1"; +const EXAMPLE_OID_1_BER: &[u8] = &hex!("2A8648CE3D0201"); +const EXAMPLE_OID_1: ObjectIdentifier = ObjectIdentifier::new_unwrap(EXAMPLE_OID_1_STR); + +/// Example OID value with a root arc of `2`. +const EXAMPLE_OID_2_STR: &str = "2.16.840.1.101.3.4.1.42"; +const EXAMPLE_OID_2_BER: &[u8] = &hex!("60864801650304012A"); +const EXAMPLE_OID_2: ObjectIdentifier = ObjectIdentifier::new_unwrap(EXAMPLE_OID_2_STR); + +/// Example OID value with a large arc +const EXAMPLE_OID_LARGE_ARC_STR: &str = "0.9.2342.19200300.100.1.1"; +const EXAMPLE_OID_LARGE_ARC_BER: &[u8] = &hex!("0992268993F22C640101"); +const EXAMPLE_OID_LARGE_ARC: ObjectIdentifier = + ObjectIdentifier::new_unwrap("0.9.2342.19200300.100.1.1"); + +#[test] +fn from_bytes() { + let oid0 = ObjectIdentifier::from_bytes(EXAMPLE_OID_0_BER).unwrap(); + assert_eq!(oid0.arc(0).unwrap(), 0); + assert_eq!(oid0.arc(1).unwrap(), 9); + assert_eq!(oid0, EXAMPLE_OID_0); + + let oid1 = ObjectIdentifier::from_bytes(EXAMPLE_OID_1_BER).unwrap(); + assert_eq!(oid1.arc(0).unwrap(), 1); + assert_eq!(oid1.arc(1).unwrap(), 2); + assert_eq!(oid1, EXAMPLE_OID_1); + + let oid2 = ObjectIdentifier::from_bytes(EXAMPLE_OID_2_BER).unwrap(); + assert_eq!(oid2.arc(0).unwrap(), 2); + assert_eq!(oid2.arc(1).unwrap(), 16); + assert_eq!(oid2, EXAMPLE_OID_2); + + let oid3 = ObjectIdentifier::from_bytes(EXAMPLE_OID_LARGE_ARC_BER).unwrap(); + assert_eq!(oid3.arc(0).unwrap(), 0); + assert_eq!(oid3.arc(1).unwrap(), 9); + assert_eq!(oid3.arc(2).unwrap(), 2342); + assert_eq!(oid3.arc(3).unwrap(), 19200300); + assert_eq!(oid3.arc(4).unwrap(), 100); + assert_eq!(oid3.arc(5).unwrap(), 1); + assert_eq!(oid3.arc(6).unwrap(), 1); + assert_eq!(oid3, EXAMPLE_OID_LARGE_ARC); + + // Empty + assert_eq!(ObjectIdentifier::from_bytes(&[]), Err(Error::Empty)); + + // Truncated + assert_eq!( + ObjectIdentifier::from_bytes(&[42]), + Err(Error::NotEnoughArcs) + ); + assert_eq!( + ObjectIdentifier::from_bytes(&[42, 134]), + Err(Error::NotEnoughArcs) + ); +} + +#[test] +fn from_str() { + let oid0 = EXAMPLE_OID_0_STR.parse::().unwrap(); + assert_eq!(oid0.arc(0).unwrap(), 0); + assert_eq!(oid0.arc(1).unwrap(), 9); + assert_eq!(oid0, EXAMPLE_OID_0); + + let oid1 = EXAMPLE_OID_1_STR.parse::().unwrap(); + assert_eq!(oid1.arc(0).unwrap(), 1); + assert_eq!(oid1.arc(1).unwrap(), 2); + assert_eq!(oid1, EXAMPLE_OID_1); + + let oid2 = EXAMPLE_OID_2_STR.parse::().unwrap(); + assert_eq!(oid2.arc(0).unwrap(), 2); + assert_eq!(oid2.arc(1).unwrap(), 16); + assert_eq!(oid2, EXAMPLE_OID_2); + + let oid3 = EXAMPLE_OID_LARGE_ARC_STR + .parse::() + .unwrap(); + assert_eq!(oid3.arc(0).unwrap(), 0); + assert_eq!(oid3.arc(1).unwrap(), 9); + assert_eq!(oid3.arc(2).unwrap(), 2342); + assert_eq!(oid3.arc(3).unwrap(), 19200300); + assert_eq!(oid3.arc(4).unwrap(), 100); + assert_eq!(oid3.arc(5).unwrap(), 1); + assert_eq!(oid3.arc(6).unwrap(), 1); + assert_eq!(oid3, EXAMPLE_OID_LARGE_ARC); + + // Too short + assert_eq!("1.2".parse::(), Err(Error::NotEnoughArcs)); + + // Truncated + assert_eq!( + "1.2.840.10045.2.".parse::(), + Err(Error::TrailingDot) + ); + + // Invalid first arc + assert_eq!( + "3.2.840.10045.2.1".parse::(), + Err(Error::ArcInvalid { arc: 3 }) + ); + + // Invalid second arc + assert_eq!( + "1.40.840.10045.2.1".parse::(), + Err(Error::ArcInvalid { arc: 40 }) + ); +} + +#[test] +fn display() { + assert_eq!(EXAMPLE_OID_0.to_string(), EXAMPLE_OID_0_STR); + assert_eq!(EXAMPLE_OID_1.to_string(), EXAMPLE_OID_1_STR); + assert_eq!(EXAMPLE_OID_2.to_string(), EXAMPLE_OID_2_STR); + assert_eq!(EXAMPLE_OID_LARGE_ARC.to_string(), EXAMPLE_OID_LARGE_ARC_STR); +} + +#[test] +fn try_from_u32_slice() { + let oid1 = ObjectIdentifier::from_arcs([1, 2, 840, 10045, 2, 1]).unwrap(); + assert_eq!(oid1.arc(0).unwrap(), 1); + assert_eq!(oid1.arc(1).unwrap(), 2); + assert_eq!(EXAMPLE_OID_1, oid1); + + let oid2 = ObjectIdentifier::from_arcs([2, 16, 840, 1, 101, 3, 4, 1, 42]).unwrap(); + assert_eq!(oid2.arc(0).unwrap(), 2); + assert_eq!(oid2.arc(1).unwrap(), 16); + assert_eq!(EXAMPLE_OID_2, oid2); + + // Too short + assert_eq!( + ObjectIdentifier::from_arcs([1, 2]), + Err(Error::NotEnoughArcs) + ); + + // Invalid first arc + assert_eq!( + ObjectIdentifier::from_arcs([3, 2, 840, 10045, 3, 1, 7]), + Err(Error::ArcInvalid { arc: 3 }) + ); + + // Invalid second arc + assert_eq!( + ObjectIdentifier::from_arcs([1, 40, 840, 10045, 3, 1, 7]), + Err(Error::ArcInvalid { arc: 40 }) + ); +} + +#[test] +fn as_bytes() { + assert_eq!(EXAMPLE_OID_1.as_bytes(), EXAMPLE_OID_1_BER); + assert_eq!(EXAMPLE_OID_2.as_bytes(), EXAMPLE_OID_2_BER); +} + +#[test] +fn parse_empty() { + assert_eq!(ObjectIdentifier::new(""), Err(Error::Empty)); +} + +#[test] +fn parse_not_enough_arcs() { + assert_eq!(ObjectIdentifier::new("1.2"), Err(Error::NotEnoughArcs)); +} + +#[test] +fn parse_invalid_first_arc() { + assert_eq!( + ObjectIdentifier::new("3.2.840.10045.3.1.7"), + Err(Error::ArcInvalid { arc: 3 }) + ); +} + +#[test] +fn parse_invalid_second_arc() { + assert_eq!( + ObjectIdentifier::new("1.40.840.10045.3.1.7"), + Err(Error::ArcInvalid { arc: 40 }) + ); +} + +#[test] +fn parent() { + let oid = ObjectIdentifier::new("1.2.3.4").unwrap(); + let parent = oid.parent().unwrap(); + assert_eq!(parent, ObjectIdentifier::new("1.2.3").unwrap()); + assert_eq!(parent.parent(), None); +} + +#[test] +fn push_arc() { + let oid = ObjectIdentifier::new("1.2.3").unwrap(); + assert_eq!( + oid.push_arc(4).unwrap(), + ObjectIdentifier::new("1.2.3.4").unwrap() + ); +} diff --git a/src/rust/vendor/crypto-bigint/.cargo-checksum.json b/src/rust/vendor/crypto-bigint/.cargo-checksum.json new file mode 100644 index 000000000..afc273022 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"dc759cacc69443dc4bbc1dd0227058905e8688f401f09eb6cc6d001315c52cf8","Cargo.toml":"8f04f1a2190bdd3f86b286c9877cfc84760a3e8d405d58bca3b51612e5a3e2ff","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"90c503b61dee04e1449c323ec34c229dfb68d7adcb96c7e140ee55f70fce2d8e","README.md":"e7e4bb1dc815119ed5e087ce1995a6fd45657c0f6d0fd565cbc52721c378b42e","SECURITY.md":"566027e0957dcbe6245eef1df2d3f2e100f8ec60171a79943ac8c7b5a992dea8","benches/bench.rs":"0cf57ae7f1679191aec6bf4cd576b7f286886f7d9c758968e45543917b217fa5","src/array.rs":"9b18991230aa12e88ac358cdb202f4225fcee58788e29c34ab931e29ba5a92aa","src/boxed.rs":"4cd7fe04aa18a63d43ac70b9a3dbcb905c42be8a33551230353f191f1e6d9d4b","src/boxed/uint.rs":"0beb2eb330762109c5c162f996760e71350f9cf5795d1881b1ff0c450036e22d","src/boxed/uint/add.rs":"4fa0c262b01d1c995d31442daa241875fd16f8730f3502997b19669f97065dee","src/boxed/uint/cmp.rs":"c35064b6ad92666cd578ee1743db17f0bd6a736f9d9ab4d0dbd294c04c9b5bc2","src/checked.rs":"7efd3bdc2d2a8263d0b62aba3636ef59069c027636132a800f1c8639be3af5f8","src/ct_choice.rs":"14905f576de07334e955e689e5653b2e9214db56d011f51a01324e9af5ab23d8","src/lib.rs":"62e2050bc81163eec47754da7afab61f6791cce4413be5b8efc8ef5e6c9e23b5","src/limb.rs":"16fba5c446ad5d982509b58b15aed4f3b66894a6c6a5ed726645a354200971e3","src/limb/add.rs":"c4cfbae55657e8366dfacf2ed26cc6cf4c547f810df26566f3f23d2287697cd2","src/limb/bit_and.rs":"019f888b11e16fafbd0518eb5b583094a5e8490f59f458195db9306d86e1adaa","src/limb/bit_not.rs":"0fa7cdec58e1d3058daee88ef26f07ad0ba9e545505c97a130b47ef3fdf46c5a","src/limb/bit_or.rs":"1b5f85eac6768d460070da05b4a1257cceafff2b612b63a609aff3ff48df8480","src/limb/bit_xor.rs":"06acf291a316aa1fa2311bedd1a7aca5170564735c1f0b1103ed9e2c6f24f096","src/limb/bits.rs":"2b1796eafeaac1ccef8479e0a638888a2e184e71a2ac9c1c68c2cd198741c11d","src/limb/cmp.rs":"a59f12dccac4c482a658c9114ea8cb0a20d699cf47e85371b506811e47402cae","src/limb/encoding.rs":"29c9f0d86bfc63c8a5f510ef7f5ced1256697b8f5170ba9b98429241d1191a79","src/limb/from.rs":"7f595d9085730f95d2fe776a81e6f174061c9c4ec89a1fd85ab26feeaae0c2ad","src/limb/mul.rs":"dbfa013061fc5d8cff5bf49814d9acd3d00d386211fbd657091a813bca977820","src/limb/neg.rs":"6e2443804f6a8a191a2fc43b849c9bbe36177b4094afa8e6e9d7a4ef83ccd4f9","src/limb/rand.rs":"770463d84aa86d432b294975b62fd4f95b7dbee93a78ec2c2f3e03e23ea21fdb","src/limb/shl.rs":"b90a4d551bea894ff2f545cf19149a6155c430ef128a37d6cb3a5f1bd615efc1","src/limb/shr.rs":"a95dbd4507dc44308b09bcdf6024d60b37e787588d4f698b6d2c0b30c46d129a","src/limb/sub.rs":"2fe52b63f4876beb4d6fb44f2d04ac62231d66b7071097d592c690ceb4944764","src/macros.rs":"416288d628d10a92056cc42aa84eba4e7bff2342e0836aec7465e70a1f360607","src/non_zero.rs":"893138b2efc0da56a47d50b5609601646cfbb370d7d9904acca110a994902305","src/traits.rs":"61181bd2f6d839aca9b44267c39808716d09de263cc1cece357c52439ed007e3","src/uint.rs":"ff1d174e7c236abb78ccc0aea1f637b86f30f2bb20df929396f9d2eac0fdd1c5","src/uint/add.rs":"3784c73c31eb745372e332143a17703f1f835b53717d23a1d73c36b07a0feef4","src/uint/add_mod.rs":"20579edb2de32fa1e5cd63f0e3368dcffceaeff855faa9ba3b261fe525106e4a","src/uint/array.rs":"81e93b39a64fd5c609556f7ab8c23f3ca15aaf0c77a05e10d80855ac9a56292a","src/uint/bit_and.rs":"54ebcac0e1a481d31e26a2acf3abda3de0ad6775225d02d41549aea4d1d5364a","src/uint/bit_not.rs":"b593a48c0e65849ea643f0a3624d2e8d3fc35d8f16a6b2a5e9de2728f0ad2fb4","src/uint/bit_or.rs":"0fd351e1558c7b067be8fa45329e33c0e43111b4dfa7954a0837af88a3f733e8","src/uint/bit_xor.rs":"4975f3df64a114313fd2d02993c6f7ce5ac02144534c15f2be310022261d18b6","src/uint/bits.rs":"e71e8a3d75c59af2d6bf950e522d565353253fe748fbdfdef9c25e1bb02ad1fe","src/uint/cmp.rs":"ba66fa2b91838fa31afab1b387662ab5f9286d62aaeb990d5537d295f236da51","src/uint/concat.rs":"4705cd8bd6bc78d2fcfbc9ae141f3bbfa4d3e6029940b92de8bc1949de5a2bd2","src/uint/div.rs":"35695ca56e646ec583762b447869cca19832774d1c507d949295be46c424e7a7","src/uint/div_limb.rs":"9f67a65da08ef4deba3953445c913762257ac0f6f3100113a5120641c673a9b1","src/uint/encoding.rs":"6cdee4ec79592bdd7493c33ef25ecda2375f93264ac5d5d9389e37bc0d43a0df","src/uint/encoding/der.rs":"0873e5f48616d297402abba5805012f6aa2c240e321bae79eb9493764c6c1494","src/uint/encoding/rlp.rs":"7c95d481e9da181d80d345f0e3b9669d65f20dbd39de42f27ac875dfecfe6908","src/uint/extra_sizes.rs":"c49de70e027a82213920931faedb395c38e15c72631c8f91023fa62711ec7fe2","src/uint/from.rs":"82e66bbfeceebb0b000f6b50d6e2f8fd2907b0280372038fbdd7ab57a0c641a3","src/uint/inv_mod.rs":"8329baee728e26d371278a02a2dd10b35d3c8ce369521b13a3295c59351763f7","src/uint/macros.rs":"33b23304d78c09f7fb949b8c93ea549596b5842951e667a761bd77f615ced1e5","src/uint/modular.rs":"8ea4b5129312251a076b95fd84e0a41b8951ce4b443ec7dc33c08eef13721a6a","src/uint/modular/add.rs":"6dd440f71305fcebe970ca51ef4a218574075978ab22ccbea7df03227a4b1dec","src/uint/modular/constant_mod.rs":"16a9f268c47368052bcb3599b13b4b8095667002cbe5cf207bc62c2ccea6cd72","src/uint/modular/constant_mod/const_add.rs":"5e2acd3d079f77d31d947fb5deb0bc6a230b483604292e775381eefff8beeb3e","src/uint/modular/constant_mod/const_inv.rs":"a5328161d83d8cb951bbab5ddc6522396296ee02593752515f212a475cda0b55","src/uint/modular/constant_mod/const_mul.rs":"d5250adbc8dee03840c3cfc44c24253469605bf9e3b397e42dbd036b19b283ac","src/uint/modular/constant_mod/const_neg.rs":"29479fed061c2ba34550d098d8255b50a827c93aa6d39af0138c86e8bb006d69","src/uint/modular/constant_mod/const_pow.rs":"42244026d5c9aadc8add7d28ddf8b176278c0eff6a7d7ae2212b37c806bbffc6","src/uint/modular/constant_mod/const_sub.rs":"6cc421643c7ce79a6346c83cf9caaeedcda0f3c61827f1563dad85d4595bf95e","src/uint/modular/constant_mod/macros.rs":"262da2964954b2ef7417c7d395c62bb4c6f9b994042a7a19e85ca07d4971587f","src/uint/modular/div_by_2.rs":"4ae62b414fe7a571285deda7e71ae96ca41629a463313a964b630e4390ca6fa4","src/uint/modular/inv.rs":"7b529a240694b5ed24dc51a2d7cb780877f2fc36b93e90c140ee5fc44ab8a67d","src/uint/modular/mul.rs":"366e145a5cd5af8af2e5eb831592e8df773244cb43e826863d3ed973b40404a6","src/uint/modular/pow.rs":"3585b3bc8250744bd51aff5c3ebe72a49c94bae3c05d026ecfecea42b3c87be3","src/uint/modular/reduction.rs":"7ad87aa75c4d2ce07853f9cb0308e0ca1b7bb78c7572743991d9e05e5ecfcca1","src/uint/modular/runtime_mod.rs":"ee1075d44b73c6719736fa50b6a7f2013aeb0abd435e2e5ab81575fe493ed4cb","src/uint/modular/runtime_mod/runtime_add.rs":"03458894be7de14f8813a5a458662cde6d62dc24fb289bf1fae2bc87a981e159","src/uint/modular/runtime_mod/runtime_inv.rs":"cf5a3776e94e9edd20934b8a4d8775a1269a69209d591ea492862d102842f841","src/uint/modular/runtime_mod/runtime_mul.rs":"6b695a9be7b766aeb592b9cfcb01f27eae7643a45062e24edf1c209ec19fa9da","src/uint/modular/runtime_mod/runtime_neg.rs":"c5948c91e82f92675357a4c53d3ebd6cda7bf4132bf36921e34ffcea530167b4","src/uint/modular/runtime_mod/runtime_pow.rs":"8b727dbb7a3f2627f6a9d4d3ca9a39d225089853794826109088cdf6143c5bce","src/uint/modular/runtime_mod/runtime_sub.rs":"cfc59cacdc1a37827aaf88e0478cf0b7ede8782e2e23c22ab69c02ec0af3d4cf","src/uint/modular/sub.rs":"c50b631f9d0c3309c2e3e445a4f44050f04d9d2632547843204a8797c618cecf","src/uint/mul.rs":"bc2f7ffed01be1d437e6827a20256e3db1d40212570fc50d9b00e6df87df3b27","src/uint/mul_mod.rs":"455af5b2f3e4081f235fb758a2e9ce9bc4ee53ee41389ca1d132373c570dbb2b","src/uint/neg.rs":"bd66efb350c7914299da19d69cb146912ba71ed08053419e07e110ee6030ab95","src/uint/neg_mod.rs":"80bbec84a8ab8ed53dbdf5b2093cbb5a80aa561b374b1795eef00a6a01ace109","src/uint/rand.rs":"09efd658214d43e1ad0238f5a6cd680fac3df334d2aca1dccb942b4e21aad70d","src/uint/resize.rs":"88990e70756fe211ca874538558a9eed7373176668aa71e81f0b1d3bae8eaf56","src/uint/shl.rs":"c97b975c6a66611216696c8de13ca66e402e3ebf96bedc86005cd29dc4a509e4","src/uint/shr.rs":"c9cd42471695d80c1a2d4e2986893781b22a8b616d25e4e209b1450803d5000f","src/uint/split.rs":"6cd6939c1c3711602af0e39821952ecf46ed3139b77fba06172c79c873541c6f","src/uint/sqrt.rs":"daa8e688acfb22c074a2cc23da7b84058a833078f57183399fb917e611c13661","src/uint/sub.rs":"43df967c0cc245a5f97593e19d474f0f09356b61f2b4a98d8773e6fa2e14e335","src/uint/sub_mod.rs":"b2a4155544b1e10b89d5aa2bb1e0b7e949d538378722eb55be1e385ac64323af","src/wrapping.rs":"2b8d96ebfb21b5540e3e4a31c47f8cbc630b085f222fe2c00aa4da9ebf486ce6","tests/const_residue.rs":"d874022d955e065ccbade442679c4046ab47ec495411d24e128e7ea5f1296859","tests/impl_modulus.rs":"ce1d05b4ddfd71b4cb08949db4c87d937efff74b5c6fa7aaae180a5d6bc9dd65","tests/proptests.rs":"f8087dca761b22e040f31872884fab8ed7dea7b6f7f8e125f92d459108fdb35f"},"package":"0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"} \ No newline at end of file diff --git a/src/rust/vendor/crypto-bigint/CHANGELOG.md b/src/rust/vendor/crypto-bigint/CHANGELOG.md new file mode 100644 index 000000000..c308eb2ad --- /dev/null +++ b/src/rust/vendor/crypto-bigint/CHANGELOG.md @@ -0,0 +1,422 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.5.5 (2023-11-18) +### Added +- Multi-exponentiation ([#248]) +- `const_assert_eq!` and `const_assert_ne!` macros ([#293]) + +[#248]: https://github.com/RustCrypto/crypto-bigint/pull/248 +[#293]: https://github.com/RustCrypto/crypto-bigint/pull/293 + +## 0.5.4 (2023-11-12) +### Added +- `trailing_ones[_vartime]()`, `trailing_zeros_vartime()`, `leading_zeros_vartime()` ([#282]) +- Implement `ArrayEncoding` for `U832` ([#288]) + +### Changed +- Make `Uint::random_mod()` work identically on 32- and 64-bit targets ([#285]) + +[#282]: https://github.com/RustCrypto/crypto-bigint/pull/282 +[#285]: https://github.com/RustCrypto/crypto-bigint/pull/285 +[#288]: https://github.com/RustCrypto/crypto-bigint/pull/288 + +## 0.5.3 (2023-09-04) +### Added +- `BoxedUint`: heap-allocated fixed-precision integers ([#221]) +- `extra-sizes` feature ([#229]) +- `U4224` and `U4352` ([#233]) +- Zeroizing support for `DynResidue` ([#235]) +- `cmp_vartime`, `ct_cmp` ([#238]) +- Expose Montgomery form in `Residue`/`DynResidue` ([#239]) +- Make `Uint::pow` work with different sized exponents ([#251]) +- Expose `wrapping_neg` ([#252]) +- Make `concat`, `split`, and multiply work with different sized operands ([#253]) +- `U16384` and `U32768` ([#255]) +- `Uint::{inv_mod, inv_mod2k_vartime}` ([#263]) +- `const fn` constructors for `NonZero` and `NonZero` ([#266]) +- Constant-time `Uint::shr()` and `Uint::shl()` ([#267]) +- Subtle trait impls for `DynResidue` and `DynResidueParams` ([#269]) + +### Changed +- Modular inversion improvements ([#263]) + +### Fixed +- `serdect` usage ([#222]) +- Enforce valid modulus for `DynResidueParams` ([#240]) +- Enforce valid modulus for `Residue` and associated macros ([#243]) +- Make `Uint::{from_be_hex, from_le_hex}` constant-time ([#254]) +- Remove conditionals in `Uint::saturating_add()` and `saturating_mul()` ([#256]) +- More logical checks in the `Uint::random_mod()` test ([#256]) +- Mark `sqrt` for renaming, to explicitly describe it as vartime ([#256]) + +[#221]: https://github.com/RustCrypto/crypto-bigint/pull/221 +[#222]: https://github.com/RustCrypto/crypto-bigint/pull/222 +[#229]: https://github.com/RustCrypto/crypto-bigint/pull/229 +[#233]: https://github.com/RustCrypto/crypto-bigint/pull/233 +[#235]: https://github.com/RustCrypto/crypto-bigint/pull/235 +[#238]: https://github.com/RustCrypto/crypto-bigint/pull/238 +[#239]: https://github.com/RustCrypto/crypto-bigint/pull/239 +[#240]: https://github.com/RustCrypto/crypto-bigint/pull/240 +[#243]: https://github.com/RustCrypto/crypto-bigint/pull/243 +[#251]: https://github.com/RustCrypto/crypto-bigint/pull/251 +[#252]: https://github.com/RustCrypto/crypto-bigint/pull/252 +[#253]: https://github.com/RustCrypto/crypto-bigint/pull/253 +[#254]: https://github.com/RustCrypto/crypto-bigint/pull/254 +[#255]: https://github.com/RustCrypto/crypto-bigint/pull/255 +[#256]: https://github.com/RustCrypto/crypto-bigint/pull/256 +[#263]: https://github.com/RustCrypto/crypto-bigint/pull/263 +[#266]: https://github.com/RustCrypto/crypto-bigint/pull/266 +[#267]: https://github.com/RustCrypto/crypto-bigint/pull/267 +[#269]: https://github.com/RustCrypto/crypto-bigint/pull/269 + +## 0.5.2 (2023-04-26) +### Added +- Expose residue params and modulus in `DynResidue` ([#197]) +- Impl `DefaultIsZeroes` for `Residue` ([#210]) +- `div_by_2()` method for integers in Montgomery form ([#211], [#212]) + +### Changed +- Montgomery multiplication improvements ([#203]) + +[#197]: https://github.com/RustCrypto/crypto-bigint/pull/197 +[#203]: https://github.com/RustCrypto/crypto-bigint/pull/203 +[#210]: https://github.com/RustCrypto/crypto-bigint/pull/210 +[#211]: https://github.com/RustCrypto/crypto-bigint/pull/211 +[#212]: https://github.com/RustCrypto/crypto-bigint/pull/212 + +## 0.5.1 (2023-03-13) +### Changed +- Improve `Debug` impls on `Limb` and `Uint` ([#195]) + +### Fixed +- `const_residue` macro accessibility bug ([#193]) + +[#193]: https://github.com/RustCrypto/crypto-bigint/pull/193 +[#195]: https://github.com/RustCrypto/crypto-bigint/pull/195 + +## 0.5.0 (2023-02-27) +### Added +- `Residue`: modular arithmetic with static compile-time moduli ([#130]) +- `DynResidue`: modular arithmetic with dynamic runtime moduli ([#134]) +- Constant-time division by a single `Limb` ([#141]) +- Windowed exponentiation for `(Dyn)Residue` ([#147]) +- `SubResidue` trait and impls for `Residue` and `DynResidue` ([#149]) +- `Pow`, `Invert` and `Square` ([#155]) +- `CtChoice` type ([#159]) +- `BITS`, `BYTES`, and `LIMBS` to `Integer` trait ([#161]) +- Impl `Random` for `Wrapping` ([#168]) +- Support to concat `U320` and `U640` ([#173]) +- Define `U224` and `U544` on 32-bit platforms ([#179], [#180]) + +### Changed +- Rename `UInt` -> `Uint` ([#143]) +- Rename `Uint` methods ([#144]) + - `limbs` -> `as_limbs` + - `limbs_mut` -> `as_limbs_mut` + - `into_limbs` -> `to_limbs` +- Faster `random_mod` ([#146]) +- Constant-time `leading_zeros()`, `trailing_zeros()`, `bits()`, and `bit()` for `Uint` ([#153]) +- Rename `BIT_SIZE` -> `BITS`, `BYTE_SIZE` -> `BYTES` ([#157]) +- More efficient squaring operation ([#133]) +- Use `CryptoRngCore` ([#164]) +- Bump `serdect` to 0.2 ([#185]) +- Bump `der` dependency to v0.7; MSRV 1.65 ([#187]) + +### Fixed +- Integer overflow in `div2by1()` ([#156]) +- Convert from tuple element ordering ([#183]) + +[#130]: https://github.com/RustCrypto/crypto-bigint/pull/130 +[#134]: https://github.com/RustCrypto/crypto-bigint/pull/134 +[#141]: https://github.com/RustCrypto/crypto-bigint/pull/141 +[#143]: https://github.com/RustCrypto/crypto-bigint/pull/143 +[#144]: https://github.com/RustCrypto/crypto-bigint/pull/144 +[#146]: https://github.com/RustCrypto/crypto-bigint/pull/146 +[#147]: https://github.com/RustCrypto/crypto-bigint/pull/147 +[#149]: https://github.com/RustCrypto/crypto-bigint/pull/149 +[#153]: https://github.com/RustCrypto/crypto-bigint/pull/153 +[#155]: https://github.com/RustCrypto/crypto-bigint/pull/155 +[#156]: https://github.com/RustCrypto/crypto-bigint/pull/156 +[#157]: https://github.com/RustCrypto/crypto-bigint/pull/157 +[#159]: https://github.com/RustCrypto/crypto-bigint/pull/159 +[#161]: https://github.com/RustCrypto/crypto-bigint/pull/161 +[#164]: https://github.com/RustCrypto/crypto-bigint/pull/164 +[#168]: https://github.com/RustCrypto/crypto-bigint/pull/168 +[#173]: https://github.com/RustCrypto/crypto-bigint/pull/173 +[#179]: https://github.com/RustCrypto/crypto-bigint/pull/179 +[#180]: https://github.com/RustCrypto/crypto-bigint/pull/180 +[#183]: https://github.com/RustCrypto/crypto-bigint/pull/183 +[#185]: https://github.com/RustCrypto/crypto-bigint/pull/185 +[#187]: https://github.com/RustCrypto/crypto-bigint/pull/187 + +## 0.4.9 (2022-10-11) +### Added +- `UInt::from_word` and `::from_wide_word` ([#105]) +- `UInt` modulo operations for special moduli ([#108]) +- Non-const `UInt` decoding from an array ([#110]) +- `const fn` impls of `concat` and `split` ([#111]) +- `Limb` left/right bitshifts ([#112]) +- `UInt::LIMBS` constant ([#114]) + +### Changed +- Optimize `UInt::neg_mod` by simply calling `::sub_mod` ([#106]) +- Relax bounds for `UInt::add_mod` and `::sub_mod` ([#104]) +- Always inline `Limb::bitand` ([#109]) +- Faster const decoding of UInt ([#113]) +- Optimize `UInt::neg_mod` ([#127]) +- Faster comparisons ([#128]) +- `UInt::resize` ([#129]) +- `UInt::bit` accessor methods ([#122]) + +### Fixed +- Constant-time behaviour for `ct_reduce`/`ct_div_rem` ([#117]) + +[#104]: https://github.com/RustCrypto/crypto-bigint/pull/104 +[#105]: https://github.com/RustCrypto/crypto-bigint/pull/105 +[#106]: https://github.com/RustCrypto/crypto-bigint/pull/106 +[#108]: https://github.com/RustCrypto/crypto-bigint/pull/108 +[#109]: https://github.com/RustCrypto/crypto-bigint/pull/109 +[#110]: https://github.com/RustCrypto/crypto-bigint/pull/110 +[#111]: https://github.com/RustCrypto/crypto-bigint/pull/111 +[#112]: https://github.com/RustCrypto/crypto-bigint/pull/112 +[#113]: https://github.com/RustCrypto/crypto-bigint/pull/113 +[#114]: https://github.com/RustCrypto/crypto-bigint/pull/114 +[#117]: https://github.com/RustCrypto/crypto-bigint/pull/117 +[#122]: https://github.com/RustCrypto/crypto-bigint/pull/122 +[#127]: https://github.com/RustCrypto/crypto-bigint/pull/127 +[#128]: https://github.com/RustCrypto/crypto-bigint/pull/128 +[#129]: https://github.com/RustCrypto/crypto-bigint/pull/129 + +## 0.4.8 (2022-06-30) +### Added +- `Word` as a replacement for `LimbUInt` ([#88]) +- `WideWord` as a replacement for `WideLimbUInt` ([#88]) +- `UInt::*_words` as a replacement for `UInt::*_uint_array` ([#88]) + +### Changed +- Deprecated `*LimbUInt` and `UInt::*_uint_array` ([#88]) + +[#88]: https://github.com/RustCrypto/crypto-bigint/pull/88 + +## 0.4.7 (2022-06-12) +### Added +- `Encoding` tests ([#93]) + +### Changed +- Use const generic impls of `*Mod` traits ([#98]) + +[#93]: https://github.com/RustCrypto/crypto-bigint/pull/93 +[#98]: https://github.com/RustCrypto/crypto-bigint/pull/98 + +## 0.4.6 (2022-06-12) +### Added +- Impl `ArrayEncoding` for `U576` ([#96]) + +[#96]: https://github.com/RustCrypto/crypto-bigint/pull/96 + +## 0.4.5 (2022-06-12) +### Added +- `serde` support ([#73]) +- `U576` type alias ([#94]) + +[#73]: https://github.com/RustCrypto/crypto-bigint/pull/73 +[#94]: https://github.com/RustCrypto/crypto-bigint/pull/94 + +## 0.4.4 (2022-06-02) +### Added +- `UInt::as_uint_array` ([#91]) + +[#91]: https://github.com/RustCrypto/crypto-bigint/pull/91 + +## 0.4.3 (2022-05-31) +### Added +- Impl `AsRef`/`AsMut<[LimbUInt]>` for `UInt` ([#89]) + +[#89]: https://github.com/RustCrypto/crypto-bigint/pull/89 + +## 0.4.2 (2022-05-18) +### Added +- `UInt::inv_mod2k` ([#86]) + +### Fixed +- Wrong results for remainder ([#84]) + +[#84]: https://github.com/RustCrypto/crypto-bigint/pull/84 +[#86]: https://github.com/RustCrypto/crypto-bigint/pull/86 + +## 0.4.1 (2022-05-10) +### Fixed +- Bug in `from_le_slice` ([#82]) + +[#82]: https://github.com/RustCrypto/crypto-bigint/pull/82 + +## 0.4.0 (2022-05-08) [YANKED] + +NOTE: this release was yanked due to [#82]. + +### Added +- Const-friendly `NonZero` from `UInt` ([#56]) +- Optional `der` feature ([#61], [#80]) + +### Changed +- Use `const_panic`; MSRV 1.57 ([#60]) +- 2021 edition ([#60]) + +### Fixed +- Pad limbs with zeros when displaying hexadecimal representation ([#74]) + +[#56]: https://github.com/RustCrypto/crypto-bigint/pull/56 +[#60]: https://github.com/RustCrypto/crypto-bigint/pull/60 +[#61]: https://github.com/RustCrypto/crypto-bigint/pull/61 +[#74]: https://github.com/RustCrypto/crypto-bigint/pull/74 +[#80]: https://github.com/RustCrypto/crypto-bigint/pull/80 + +## 0.3.2 (2021-11-17) +### Added +- `Output = Self` to all bitwise ops on `Integer` trait ([#53]) + +[#53]: https://github.com/RustCrypto/crypto-bigint/pull/53 + +## 0.3.1 (2021-11-17) +### Added +- Bitwise ops to `Integer` trait ([#51]) + +[#51]: https://github.com/RustCrypto/crypto-bigint/pull/51 + +## 0.3.0 (2021-11-14) [YANKED] +### Added +- Bitwise `Xor`/`Not` operations ([#27]) +- `Zero` trait ([#35]) +- `Checked*` traits ([#41]) +- `prelude` module ([#45]) +- `saturating_*` ops ([#47]) + +### Changed +- Rust 2021 edition upgrade; MSRV 1.56 ([#33]) +- Reverse ordering of `UInt::mul_wide` return tuple ([#34]) +- Have `Div` and `Rem` impls always take `NonZero` args ([#39]) +- Rename `limb::Inner` to `LimbUInt` ([#40]) +- Make `limb` module private ([#40]) +- Use `Zero`/`Integer` traits for `is_zero`, `is_odd`, and `is_even` ([#46]) + +### Fixed +- `random_mod` performance for small moduli ([#36]) +- `NonZero` moduli ([#36]) + +### Removed +- Deprecated `LIMB_BYTES` constant ([#43]) + +[#27]: https://github.com/RustCrypto/crypto-bigint/pull/27 +[#33]: https://github.com/RustCrypto/crypto-bigint/pull/33 +[#34]: https://github.com/RustCrypto/crypto-bigint/pull/34 +[#35]: https://github.com/RustCrypto/crypto-bigint/pull/35 +[#36]: https://github.com/RustCrypto/crypto-bigint/pull/36 +[#39]: https://github.com/RustCrypto/crypto-bigint/pull/39 +[#40]: https://github.com/RustCrypto/crypto-bigint/pull/40 +[#41]: https://github.com/RustCrypto/crypto-bigint/pull/41 +[#43]: https://github.com/RustCrypto/crypto-bigint/pull/43 +[#45]: https://github.com/RustCrypto/crypto-bigint/pull/45 +[#46]: https://github.com/RustCrypto/crypto-bigint/pull/46 +[#47]: https://github.com/RustCrypto/crypto-bigint/pull/47 + +## 0.2.11 (2021-10-16) +### Added +- `AddMod` proptests ([#24]) +- Bitwise `And`/`Or` operations ([#25]) + +[#24]: https://github.com/RustCrypto/crypto-bigint/pull/24 +[#25]: https://github.com/RustCrypto/crypto-bigint/pull/25 + +## 0.2.10 (2021-09-21) +### Added +- `ArrayDecoding` trait ([#12]) +- `NonZero` wrapper ([#13], [#16]) +- Impl `Div`/`Rem` for `NonZero` ([#14]) + +[#12]: https://github.com/RustCrypto/crypto-bigint/pull/12 +[#13]: https://github.com/RustCrypto/crypto-bigint/pull/13 +[#14]: https://github.com/RustCrypto/crypto-bigint/pull/14 +[#16]: https://github.com/RustCrypto/crypto-bigint/pull/16 + +## 0.2.9 (2021-09-16) +### Added +- `UInt::sqrt` ([#9]) + +### Changed +- Make `UInt` division similar to other interfaces ([#8]) + +[#8]: https://github.com/RustCrypto/crypto-bigint/pull/8 +[#9]: https://github.com/RustCrypto/crypto-bigint/pull/9 + +## 0.2.8 (2021-09-14) [YANKED] +### Added +- Implement constant-time division and modulo operations + +### Changed +- Moved from RustCrypto/utils to RustCrypto/crypto-bigint repo ([#2]) + +[#2]: https://github.com/RustCrypto/crypto-bigint/pull/2 + +## 0.2.7 (2021-09-12) +### Added +- `UInt::shl_vartime` + +### Fixed +- `add_mod` overflow handling + +## 0.2.6 (2021-09-08) +### Added +- `Integer` trait +- `ShrAssign` impl for `UInt` +- Recursive Length Prefix (RLP) encoding support for `UInt` + +## 0.2.5 (2021-09-02) +### Fixed +- `ConditionallySelectable` impl for `UInt` + +## 0.2.4 (2021-08-23) [YANKED] +### Added +- Expose `limb` module +- `[limb::Inner; LIMBS]` conversions for `UInt` +- Bitwise right shift support for `UInt` ([#586], [#590]) + +## 0.2.3 (2021-08-16) [YANKED] +### Fixed +- `UInt::wrapping_mul` + +### Added +- Implement the `Hash` trait for `UInt` and `Limb` + +## 0.2.2 (2021-06-26) [YANKED] +### Added +- `Limb::is_odd` and `UInt::is_odd` +- `UInt::new` +- `rand` feature + +### Changed +- Deprecate `LIMB_BYTES` constant +- Make `Limb`'s `Inner` value public + +## 0.2.1 (2021-06-21) [YANKED] +### Added +- `Limb` newtype +- Target-specific rustdocs + +## 0.2.0 (2021-06-07) [YANKED] +### Added +- `ConstantTimeGreater`/`ConstantTimeLess` impls for UInt +- `From` conversions between `UInt` and limb arrays +- `zeroize` feature +- Additional `ArrayEncoding::ByteSize` bounds +- `UInt::into_limbs` +- `Encoding` trait + +### Removed +- `NumBits`/`NumBytes` traits; use `Encoding` instead + +## 0.1.0 (2021-05-30) +- Initial release diff --git a/src/rust/vendor/crypto-bigint/Cargo.toml b/src/rust/vendor/crypto-bigint/Cargo.toml new file mode 100644 index 000000000..f5a152bbf --- /dev/null +++ b/src/rust/vendor/crypto-bigint/Cargo.toml @@ -0,0 +1,119 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.65" +name = "crypto-bigint" +version = "0.5.5" +authors = ["RustCrypto Developers"] +description = """ +Pure Rust implementation of a big integer library which has been designed from +the ground-up for use in cryptographic applications. Provides constant-time, +no_std-friendly implementations of modern formulas using const generics. +""" +readme = "README.md" +keywords = [ + "arbitrary", + "crypto", + "bignum", + "integer", + "precision", +] +categories = [ + "algorithms", + "cryptography", + "data-structures", + "mathematics", + "no-std", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/RustCrypto/crypto-bigint" +resolver = "2" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[[bench]] +name = "bench" +harness = false + +[dependencies.der] +version = "0.7" +optional = true +default-features = false + +[dependencies.generic-array] +version = "0.14" +optional = true + +[dependencies.rand_core] +version = "0.6.4" +optional = true + +[dependencies.rlp] +version = "0.5" +optional = true +default-features = false + +[dependencies.serdect] +version = "0.2" +optional = true +default-features = false + +[dependencies.subtle] +version = "2.4" +default-features = false + +[dependencies.zeroize] +version = "1" +optional = true +default-features = false + +[dev-dependencies.bincode] +version = "1" + +[dev-dependencies.criterion] +version = "0.5" +features = ["html_reports"] + +[dev-dependencies.hex-literal] +version = "0.4" + +[dev-dependencies.num-bigint] +version = "0.4" + +[dev-dependencies.num-integer] +version = "0.1" + +[dev-dependencies.num-traits] +version = "0.2" + +[dev-dependencies.proptest] +version = "1" + +[dev-dependencies.rand_chacha] +version = "0.3" + +[dev-dependencies.rand_core] +version = "0.6" +features = ["std"] + +[features] +alloc = ["serdect?/alloc"] +default = ["rand"] +extra-sizes = [] +rand = ["rand_core/std"] +serde = ["dep:serdect"] diff --git a/src/rust/vendor/crypto-bigint/LICENSE-APACHE b/src/rust/vendor/crypto-bigint/LICENSE-APACHE new file mode 100644 index 000000000..78173fa2e --- /dev/null +++ b/src/rust/vendor/crypto-bigint/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/crypto-bigint/LICENSE-MIT b/src/rust/vendor/crypto-bigint/LICENSE-MIT new file mode 100644 index 000000000..c869ada57 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2021 The RustCrypto Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/crypto-bigint/README.md b/src/rust/vendor/crypto-bigint/README.md new file mode 100644 index 000000000..9198631c7 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/README.md @@ -0,0 +1,79 @@ +# [RustCrypto]: Cryptographic Big Integers + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +[![Build Status][build-image]][build-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Project Chat][chat-image]][chat-link] + +Pure Rust implementation of a big integer library which has been designed from +the ground-up for use in cryptographic applications. + +Provides constant-time, `no_std`-friendly implementations of modern formulas +using const generics. + +[Documentation][docs-link] + +## Goals + +- Supports `no_std`-friendly const generic stack-allocated big integers. +- Constant-time by default. Variable-time functions are explicitly marked as such. +- Leverage what is possible today with const generics on `stable` rust. +- Support `const fn` as much as possible, including decoding big integers from + bytes/hex and performing arithmetic operations on them, with the goal of + being able to compute values at compile-time. + +## Security Notes + +This crate has been [audited by NCC Group] with no significant +findings. We would like to thank [Entropy] for funding the audit. + +All functions contained in the crate are designed to execute in constant +time unless explicitly specified otherwise (via a `*_vartime` name suffix). + +This library is not suitable for use on processors with a variable-time +multiplication operation (e.g. short circuit on multiply-by-zero / +multiply-by-one, such as certain 32-bit PowerPC CPUs and some non-ARM +microcontrollers). + +## Minimum Supported Rust Version + +This crate requires **Rust 1.65** at a minimum. + +We may change the MSRV in the future, but it will be accompanied by a minor +version bump. + +## License + +Licensed under either of: + +- [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) +- [MIT license](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. + +[//]: # (badges) + +[crate-image]: https://buildstats.info/crate/crypto-bigint +[crate-link]: https://crates.io/crates/crypto-bigint +[docs-image]: https://docs.rs/crypto-bigint/badge.svg +[docs-link]: https://docs.rs/crypto-bigint/ +[build-image]: https://github.com/RustCrypto/crypto-bigint/actions/workflows/crypto-bigint.yml/badge.svg +[build-link]: https://github.com/RustCrypto/crypto-bigint/actions/workflows/crypto-bigint.yml +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/300602-crypto-bigint + +[//]: # (links) + +[RustCrypto]: https://github.com/rustcrypto +[audited by NCC Group]: https://research.nccgroup.com/2023/08/30/public-report-entropy-rust-cryptography-review/ +[Entropy]: https://entropy.xyz/ diff --git a/src/rust/vendor/crypto-bigint/SECURITY.md b/src/rust/vendor/crypto-bigint/SECURITY.md new file mode 100644 index 000000000..09c221b0a --- /dev/null +++ b/src/rust/vendor/crypto-bigint/SECURITY.md @@ -0,0 +1,17 @@ +# Security Policy + +## Supported Versions + +Security updates are applied only to the most recent release. + +## Reporting a Vulnerability + +If you have discovered a security vulnerability in this project, please report +it privately. **Do not disclose it as a public issue.** This gives us time to +work with you to fix the issue before public exposure, reducing the chance that +the exploit will be used before a patch is released. + +Please disclose it at [security advisory](https://github.com/RustCrypto/crypto-bigint/security/advisories/new). + +This project is maintained by a team of volunteers on a reasonable-effort basis. +As such, please give us at least 90 days to work on a fix before public exposure. diff --git a/src/rust/vendor/crypto-bigint/benches/bench.rs b/src/rust/vendor/crypto-bigint/benches/bench.rs new file mode 100644 index 000000000..56b4eaf95 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/benches/bench.rs @@ -0,0 +1,264 @@ +use criterion::{ + criterion_group, criterion_main, measurement::Measurement, BatchSize, BenchmarkGroup, Criterion, +}; +use crypto_bigint::{ + modular::runtime_mod::{DynResidue, DynResidueParams}, + Limb, MultiExponentiate, NonZero, Random, Reciprocal, U128, U2048, U256, +}; +use rand_core::OsRng; + +fn bench_division(group: &mut BenchmarkGroup<'_, M>) { + group.bench_function("div/rem, U256/U128, full size", |b| { + b.iter_batched( + || { + let x = U256::random(&mut OsRng); + let y_half = U128::random(&mut OsRng); + let y: U256 = (y_half, U128::ZERO).into(); + (x, NonZero::new(y).unwrap()) + }, + |(x, y)| x.div_rem(&y), + BatchSize::SmallInput, + ) + }); + + group.bench_function("rem, U256/U128, full size", |b| { + b.iter_batched( + || { + let x = U256::random(&mut OsRng); + let y_half = U128::random(&mut OsRng); + let y: U256 = (y_half, U128::ZERO).into(); + (x, NonZero::new(y).unwrap()) + }, + |(x, y)| x.rem(&y), + BatchSize::SmallInput, + ) + }); + + group.bench_function("div/rem, U256/Limb, full size", |b| { + b.iter_batched( + || { + let x = U256::random(&mut OsRng); + let y_small = Limb::random(&mut OsRng); + let y = U256::from_word(y_small.0); + (x, NonZero::new(y).unwrap()) + }, + |(x, y)| x.div_rem(&y), + BatchSize::SmallInput, + ) + }); + + group.bench_function("div/rem, U256/Limb, single limb", |b| { + b.iter_batched( + || { + let x = U256::random(&mut OsRng); + let y = Limb::random(&mut OsRng); + (x, NonZero::new(y).unwrap()) + }, + |(x, y)| x.div_rem_limb(y), + BatchSize::SmallInput, + ) + }); + + group.bench_function("div/rem, U256/Limb, single limb with reciprocal", |b| { + b.iter_batched( + || { + let x = U256::random(&mut OsRng); + let y = Limb::random(&mut OsRng); + let r = Reciprocal::new(y); + (x, r) + }, + |(x, r)| x.div_rem_limb_with_reciprocal(&r), + BatchSize::SmallInput, + ) + }); +} + +fn bench_montgomery_ops(group: &mut BenchmarkGroup<'_, M>) { + let params = DynResidueParams::new(&(U256::random(&mut OsRng) | U256::ONE)); + group.bench_function("multiplication, U256*U256", |b| { + b.iter_batched( + || { + let x = DynResidue::new(&U256::random(&mut OsRng), params); + let y = DynResidue::new(&U256::random(&mut OsRng), params); + (x, y) + }, + |(x, y)| x * y, + BatchSize::SmallInput, + ) + }); + + let m = U256::random(&mut OsRng) | U256::ONE; + let params = DynResidueParams::new(&m); + group.bench_function("modpow, U256^U256", |b| { + b.iter_batched( + || { + let x = U256::random(&mut OsRng); + let x_m = DynResidue::new(&x, params); + let p = U256::random(&mut OsRng) | (U256::ONE << (U256::BITS - 1)); + (x_m, p) + }, + |(x, p)| x.pow(&p), + BatchSize::SmallInput, + ) + }); + + for i in [1, 2, 3, 4, 10, 100] { + group.bench_function( + format!("multi_exponentiate for {i} bases, U256^U256"), + |b| { + b.iter_batched( + || { + let bases_and_exponents: Vec<(DynResidue<{ U256::LIMBS }>, U256)> = (1..=i) + .map(|_| { + let x = U256::random(&mut OsRng); + let x_m = DynResidue::new(&x, params); + let p = U256::random(&mut OsRng) | (U256::ONE << (U256::BITS - 1)); + (x_m, p) + }) + .collect(); + + bases_and_exponents + }, + |bases_and_exponents| { + DynResidue::<{ U256::LIMBS }>::multi_exponentiate( + bases_and_exponents.as_slice(), + ) + }, + BatchSize::SmallInput, + ) + }, + ); + } +} + +fn bench_montgomery_conversion(group: &mut BenchmarkGroup<'_, M>) { + group.bench_function("DynResidueParams creation", |b| { + b.iter_batched( + || U256::random(&mut OsRng) | U256::ONE, + |modulus| DynResidueParams::new(&modulus), + BatchSize::SmallInput, + ) + }); + + let params = DynResidueParams::new(&(U256::random(&mut OsRng) | U256::ONE)); + group.bench_function("DynResidue creation", |b| { + b.iter_batched( + || U256::random(&mut OsRng), + |x| DynResidue::new(&x, params), + BatchSize::SmallInput, + ) + }); + + let params = DynResidueParams::new(&(U256::random(&mut OsRng) | U256::ONE)); + group.bench_function("DynResidue retrieve", |b| { + b.iter_batched( + || DynResidue::new(&U256::random(&mut OsRng), params), + |x| x.retrieve(), + BatchSize::SmallInput, + ) + }); +} + +fn bench_shifts(group: &mut BenchmarkGroup<'_, M>) { + group.bench_function("shl_vartime, small, U2048", |b| { + b.iter_batched(|| U2048::ONE, |x| x.shl_vartime(10), BatchSize::SmallInput) + }); + + group.bench_function("shl_vartime, large, U2048", |b| { + b.iter_batched( + || U2048::ONE, + |x| x.shl_vartime(1024 + 10), + BatchSize::SmallInput, + ) + }); + + group.bench_function("shl, U2048", |b| { + b.iter_batched(|| U2048::ONE, |x| x.shl(1024 + 10), BatchSize::SmallInput) + }); + + group.bench_function("shr, U2048", |b| { + b.iter_batched(|| U2048::ONE, |x| x.shr(1024 + 10), BatchSize::SmallInput) + }); +} + +fn bench_inv_mod(group: &mut BenchmarkGroup<'_, M>) { + group.bench_function("inv_odd_mod, U256", |b| { + b.iter_batched( + || { + let m = U256::random(&mut OsRng) | U256::ONE; + loop { + let x = U256::random(&mut OsRng); + let (_, is_some) = x.inv_odd_mod(&m); + if is_some.into() { + break (x, m); + } + } + }, + |(x, m)| x.inv_odd_mod(&m), + BatchSize::SmallInput, + ) + }); + + group.bench_function("inv_mod, U256, odd modulus", |b| { + b.iter_batched( + || { + let m = U256::random(&mut OsRng) | U256::ONE; + loop { + let x = U256::random(&mut OsRng); + let (_, is_some) = x.inv_odd_mod(&m); + if is_some.into() { + break (x, m); + } + } + }, + |(x, m)| x.inv_mod(&m), + BatchSize::SmallInput, + ) + }); + + group.bench_function("inv_mod, U256", |b| { + b.iter_batched( + || { + let m = U256::random(&mut OsRng); + loop { + let x = U256::random(&mut OsRng); + let (_, is_some) = x.inv_mod(&m); + if is_some.into() { + break (x, m); + } + } + }, + |(x, m)| x.inv_mod(&m), + BatchSize::SmallInput, + ) + }); +} + +fn bench_wrapping_ops(c: &mut Criterion) { + let mut group = c.benchmark_group("wrapping ops"); + bench_division(&mut group); + group.finish(); +} + +fn bench_montgomery(c: &mut Criterion) { + let mut group = c.benchmark_group("Montgomery arithmetic"); + bench_montgomery_conversion(&mut group); + bench_montgomery_ops(&mut group); + group.finish(); +} + +fn bench_modular_ops(c: &mut Criterion) { + let mut group = c.benchmark_group("modular ops"); + bench_shifts(&mut group); + bench_inv_mod(&mut group); + group.finish(); +} + +criterion_group!( + benches, + bench_wrapping_ops, + bench_montgomery, + bench_modular_ops +); + +criterion_main!(benches); diff --git a/src/rust/vendor/crypto-bigint/src/array.rs b/src/rust/vendor/crypto-bigint/src/array.rs new file mode 100644 index 000000000..3528663c7 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/array.rs @@ -0,0 +1,38 @@ +//! Interop support for `generic-array` + +use crate::{Encoding, Integer}; +use core::ops::Add; +use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; + +/// Alias for a byte array whose size is defined by [`ArrayEncoding::ByteSize`]. +pub type ByteArray = GenericArray::ByteSize>; + +/// Support for encoding a big integer as a `GenericArray`. +pub trait ArrayEncoding: Encoding { + /// Size of a byte array which encodes a big integer. + type ByteSize: ArrayLength + Add + Eq + Ord + Unsigned; + + /// Deserialize from a big-endian byte array. + fn from_be_byte_array(bytes: ByteArray) -> Self; + + /// Deserialize from a little-endian byte array. + fn from_le_byte_array(bytes: ByteArray) -> Self; + + /// Serialize to a big-endian byte array. + fn to_be_byte_array(&self) -> ByteArray; + + /// Serialize to a little-endian byte array. + fn to_le_byte_array(&self) -> ByteArray; +} + +/// Support for decoding a `GenericArray` as a big integer. +pub trait ArrayDecoding { + /// Big integer which decodes a `GenericArray`. + type Output: ArrayEncoding + Integer; + + /// Deserialize from a big-endian `GenericArray`. + fn into_uint_be(self) -> Self::Output; + + /// Deserialize from a little-endian `GenericArray`. + fn into_uint_le(self) -> Self::Output; +} diff --git a/src/rust/vendor/crypto-bigint/src/boxed.rs b/src/rust/vendor/crypto-bigint/src/boxed.rs new file mode 100644 index 000000000..4bcb860d9 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/boxed.rs @@ -0,0 +1,3 @@ +//! Heap-allocated "boxed" types. + +pub(crate) mod uint; diff --git a/src/rust/vendor/crypto-bigint/src/boxed/uint.rs b/src/rust/vendor/crypto-bigint/src/boxed/uint.rs new file mode 100644 index 000000000..4771a69e4 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/boxed/uint.rs @@ -0,0 +1,231 @@ +//! Heap-allocated big unsigned integers. + +mod add; +mod cmp; + +use crate::{Limb, Word}; +use alloc::{vec, vec::Vec}; +use core::fmt; + +#[cfg(feature = "zeroize")] +use zeroize::Zeroize; + +/// Fixed-precision heap-allocated big unsigned integer. +/// +/// Alternative to the stack-allocated [`Uint`][`crate::Uint`] but with a +/// fixed precision chosen at runtime instead of compile time. +/// +/// Unlike many other heap-allocated big integer libraries, this type is not +/// arbitrary precision and will wrap at its fixed-precision rather than +/// automatically growing. +#[derive(Clone, Default)] +pub struct BoxedUint { + /// Inner limb vector. Stored from least significant to most significant. + limbs: Vec, +} + +impl BoxedUint { + /// Get the value `0`, represented as succinctly as possible. + pub fn zero() -> Self { + Self::default() + } + + /// Get the value `1`, represented as succinctly as possible. + pub fn one() -> Self { + Self { + limbs: vec![Limb::ONE; 1], + } + } + + /// Create a new [`BoxedUint`] with the given number of bits of precision. + /// + /// Returns `None` if the number of bits is not a multiple of the + /// [`Limb`] size. + pub fn new(bits_precision: usize) -> Option { + if bits_precision == 0 || bits_precision % Limb::BITS != 0 { + return None; + } + + let nlimbs = bits_precision / Limb::BITS; + + Some(Self { + limbs: vec![Limb::ZERO; nlimbs], + }) + } + + /// Get the maximum value for a given number of bits of precision. + /// + /// Returns `None` if the number of bits is not a multiple of the + /// [`Limb`] size. + pub fn max(bits_precision: usize) -> Option { + let mut ret = Self::new(bits_precision)?; + + for limb in &mut ret.limbs { + *limb = Limb::MAX; + } + + Some(ret) + } + + /// Create a [`BoxedUint`] from an array of [`Word`]s (i.e. word-sized unsigned + /// integers). + #[inline] + pub fn from_words(words: &[Word]) -> Self { + Self { + limbs: words.iter().copied().map(Into::into).collect(), + } + } + + /// Create an array of [`Word`]s (i.e. word-sized unsigned integers) from + /// a [`BoxedUint`]. + #[inline] + pub fn to_words(&self) -> Vec { + self.limbs.iter().copied().map(Into::into).collect() + } + + /// Borrow the inner limbs as a slice of [`Word`]s. + pub fn as_words(&self) -> &[Word] { + // SAFETY: `Limb` is a `repr(transparent)` newtype for `Word` + #[allow(trivial_casts, unsafe_code)] + unsafe { + &*((self.limbs.as_slice() as *const _) as *const [Word]) + } + } + + /// Borrow the inner limbs as a mutable array of [`Word`]s. + pub fn as_words_mut(&mut self) -> &mut [Word] { + // SAFETY: `Limb` is a `repr(transparent)` newtype for `Word` + #[allow(trivial_casts, unsafe_code)] + unsafe { + &mut *((self.limbs.as_mut_slice() as *mut _) as *mut [Word]) + } + } + + /// Borrow the limbs of this [`BoxedUint`]. + pub fn as_limbs(&self) -> &[Limb] { + self.limbs.as_ref() + } + + /// Borrow the limbs of this [`BoxedUint`] mutably. + pub fn as_limbs_mut(&mut self) -> &mut [Limb] { + self.limbs.as_mut() + } + + /// Convert this [`BoxedUint`] into its inner limbs. + pub fn to_limbs(&self) -> Vec { + self.limbs.clone() + } + + /// Convert this [`BoxedUint`] into its inner limbs. + pub fn into_limbs(self) -> Vec { + self.limbs + } + + /// Get the precision of this [`BoxedUint`] in bits. + pub fn bits(&self) -> usize { + self.limbs.len() * Limb::BITS + } + + /// Sort two [`BoxedUint`]s by precision, returning a tuple of the shorter + /// followed by the longer, or the original order if their precision is + /// equal. + fn sort_by_precision<'a>(a: &'a Self, b: &'a Self) -> (&'a Self, &'a Self) { + if a.limbs.len() <= b.limbs.len() { + (a, b) + } else { + (b, a) + } + } + + /// Perform a carry chain-like operation over the limbs of the inputs, + /// constructing a result from the returned limbs and carry. + /// + /// If one of the two values has fewer limbs than the other, passes + /// [`Limb::ZERO`] as the value for that limb. + fn chain(a: &Self, b: &Self, mut carry: Limb, f: F) -> (Self, Limb) + where + F: Fn(Limb, Limb, Limb) -> (Limb, Limb), + { + let (shorter, longer) = Self::sort_by_precision(a, b); + let mut limbs = Vec::with_capacity(longer.limbs.len()); + + for i in 0..longer.limbs.len() { + let &a = shorter.limbs.get(i).unwrap_or(&Limb::ZERO); + let &b = longer.limbs.get(i).unwrap_or(&Limb::ZERO); + let (limb, c) = f(a, b, carry); + limbs.push(limb); + carry = c; + } + + (Self { limbs }, carry) + } +} + +impl AsRef<[Word]> for BoxedUint { + fn as_ref(&self) -> &[Word] { + self.as_words() + } +} + +impl AsMut<[Word]> for BoxedUint { + fn as_mut(&mut self) -> &mut [Word] { + self.as_words_mut() + } +} + +impl AsRef<[Limb]> for BoxedUint { + fn as_ref(&self) -> &[Limb] { + self.as_limbs() + } +} + +impl AsMut<[Limb]> for BoxedUint { + fn as_mut(&mut self) -> &mut [Limb] { + self.as_limbs_mut() + } +} + +impl fmt::Debug for BoxedUint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "BoxedUint(0x{self:X})") + } +} + +impl fmt::Display for BoxedUint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::UpperHex::fmt(self, f) + } +} + +impl fmt::LowerHex for BoxedUint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.limbs.is_empty() { + return fmt::LowerHex::fmt(&Limb::ZERO, f); + } + + for limb in self.limbs.iter().rev() { + fmt::LowerHex::fmt(limb, f)?; + } + Ok(()) + } +} + +impl fmt::UpperHex for BoxedUint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.limbs.is_empty() { + return fmt::LowerHex::fmt(&Limb::ZERO, f); + } + + for limb in self.limbs.iter().rev() { + fmt::UpperHex::fmt(limb, f)?; + } + Ok(()) + } +} + +#[cfg(feature = "zeroize")] +impl Zeroize for BoxedUint { + fn zeroize(&mut self) { + self.limbs.zeroize(); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/boxed/uint/add.rs b/src/rust/vendor/crypto-bigint/src/boxed/uint/add.rs new file mode 100644 index 000000000..b6cedc78f --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/boxed/uint/add.rs @@ -0,0 +1,62 @@ +//! [`BoxedUint`] addition operations. + +use crate::{BoxedUint, CheckedAdd, Limb, Zero}; +use subtle::CtOption; + +impl BoxedUint { + /// Computes `a + b + carry`, returning the result along with the new carry. + #[inline(always)] + pub fn adc(&self, rhs: &Self, carry: Limb) -> (Self, Limb) { + Self::chain(self, rhs, carry, |a, b, c| a.adc(b, c)) + } + + /// Perform wrapping addition, discarding overflow. + pub fn wrapping_add(&self, rhs: &Self) -> Self { + self.adc(rhs, Limb::ZERO).0 + } +} + +impl CheckedAdd<&BoxedUint> for BoxedUint { + type Output = Self; + + fn checked_add(&self, rhs: &Self) -> CtOption { + let (result, carry) = self.adc(rhs, Limb::ZERO); + CtOption::new(result, carry.is_zero()) + } +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +mod tests { + use super::{BoxedUint, CheckedAdd, Limb}; + + #[test] + fn adc_no_carry() { + let (res, carry) = BoxedUint::zero().adc(&BoxedUint::one(), Limb::ZERO); + assert_eq!(res, BoxedUint::one()); + assert_eq!(carry, Limb::ZERO); + } + + #[test] + fn adc_with_carry() { + let (res, carry) = BoxedUint::max(Limb::BITS) + .unwrap() + .adc(&BoxedUint::one(), Limb::ZERO); + assert_eq!(res, BoxedUint::zero()); + assert_eq!(carry, Limb::ONE); + } + + #[test] + fn checked_add_ok() { + let result = BoxedUint::zero().checked_add(&BoxedUint::one()); + assert_eq!(result.unwrap(), BoxedUint::one()); + } + + #[test] + fn checked_add_overflow() { + let result = BoxedUint::max(Limb::BITS) + .unwrap() + .checked_add(&BoxedUint::one()); + assert!(!bool::from(result.is_some())); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/boxed/uint/cmp.rs b/src/rust/vendor/crypto-bigint/src/boxed/uint/cmp.rs new file mode 100644 index 000000000..d850fc7d4 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/boxed/uint/cmp.rs @@ -0,0 +1,47 @@ +//! [`BoxedUint`] comparisons. +//! +//! By default these are all constant-time and use the `subtle` crate. + +use super::BoxedUint; +use crate::Limb; +use subtle::{Choice, ConstantTimeEq}; + +impl ConstantTimeEq for BoxedUint { + #[inline] + fn ct_eq(&self, other: &Self) -> Choice { + let (shorter, longer) = Self::sort_by_precision(self, other); + let mut ret = Choice::from(1u8); + + for i in 0..longer.limbs.len() { + let a = shorter.limbs.get(i).unwrap_or(&Limb::ZERO); + let b = longer.limbs.get(i).unwrap_or(&Limb::ZERO); + ret &= a.ct_eq(b); + } + + ret + } +} + +impl Eq for BoxedUint {} +impl PartialEq for BoxedUint { + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } +} + +#[cfg(test)] +mod tests { + use super::BoxedUint; + use subtle::ConstantTimeEq; + + #[test] + fn ct_eq() { + let a = BoxedUint::zero(); + let b = BoxedUint::one(); + + assert!(bool::from(a.ct_eq(&a))); + assert!(!bool::from(a.ct_eq(&b))); + assert!(!bool::from(b.ct_eq(&a))); + assert!(bool::from(b.ct_eq(&b))); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/checked.rs b/src/rust/vendor/crypto-bigint/src/checked.rs new file mode 100644 index 000000000..d1f61604d --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/checked.rs @@ -0,0 +1,131 @@ +//! Checked arithmetic. + +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +#[cfg(feature = "serde")] +use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer}; + +/// Provides intentionally-checked arithmetic on `T`. +/// +/// Internally this leverages the [`CtOption`] type from the [`subtle`] crate +/// in order to handle overflows. +#[derive(Copy, Clone, Debug)] +pub struct Checked(pub CtOption); + +impl Checked { + /// Create a new checked arithmetic wrapper for the given value. + pub fn new(val: T) -> Self { + Self(CtOption::new(val, Choice::from(1))) + } +} + +impl Default for Checked +where + T: Default, +{ + fn default() -> Self { + Self::new(T::default()) + } +} + +impl ConditionallySelectable for Checked { + #[inline] + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self(CtOption::conditional_select(&a.0, &b.0, choice)) + } +} + +impl ConstantTimeEq for Checked { + #[inline] + fn ct_eq(&self, rhs: &Self) -> Choice { + self.0.ct_eq(&rhs.0) + } +} + +impl From> for CtOption { + fn from(checked: Checked) -> CtOption { + checked.0 + } +} + +impl From> for Checked { + fn from(ct_option: CtOption) -> Checked { + Checked(ct_option) + } +} + +impl From> for Option { + fn from(checked: Checked) -> Option { + checked.0.into() + } +} + +#[cfg(feature = "serde")] +impl<'de, T: Default + Deserialize<'de>> Deserialize<'de> for Checked { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let value = Option::::deserialize(deserializer)?; + let choice = Choice::from(value.is_some() as u8); + Ok(Self(CtOption::new(value.unwrap_or_default(), choice))) + } +} + +#[cfg(feature = "serde")] +impl Serialize for Checked { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + Option::::from(self.0).serialize(serializer) + } +} + +#[cfg(all(test, feature = "serde"))] +#[allow(clippy::unwrap_used)] +mod tests { + + use crate::{Checked, U64}; + use subtle::{Choice, ConstantTimeEq, CtOption}; + + #[test] + fn serde() { + let test = Checked::new(U64::from_u64(0x0011223344556677)); + + let serialized = bincode::serialize(&test).unwrap(); + let deserialized: Checked = bincode::deserialize(&serialized).unwrap(); + + assert!(bool::from(test.ct_eq(&deserialized))); + + let test = Checked::new(U64::ZERO) - Checked::new(U64::ONE); + assert!(bool::from( + test.ct_eq(&Checked(CtOption::new(U64::ZERO, Choice::from(0)))) + )); + + let serialized = bincode::serialize(&test).unwrap(); + let deserialized: Checked = bincode::deserialize(&serialized).unwrap(); + + assert!(bool::from(test.ct_eq(&deserialized))); + } + + #[test] + fn serde_owned() { + let test = Checked::new(U64::from_u64(0x0011223344556677)); + + let serialized = bincode::serialize(&test).unwrap(); + let deserialized: Checked = bincode::deserialize_from(serialized.as_slice()).unwrap(); + + assert!(bool::from(test.ct_eq(&deserialized))); + + let test = Checked::new(U64::ZERO) - Checked::new(U64::ONE); + assert!(bool::from( + test.ct_eq(&Checked(CtOption::new(U64::ZERO, Choice::from(0)))) + )); + + let serialized = bincode::serialize(&test).unwrap(); + let deserialized: Checked = bincode::deserialize_from(serialized.as_slice()).unwrap(); + + assert!(bool::from(test.ct_eq(&deserialized))); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/ct_choice.rs b/src/rust/vendor/crypto-bigint/src/ct_choice.rs new file mode 100644 index 000000000..921e72de9 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/ct_choice.rs @@ -0,0 +1,104 @@ +use subtle::Choice; + +use crate::Word; + +/// A boolean value returned by constant-time `const fn`s. +// TODO: should be replaced by `subtle::Choice` or `CtOption` +// when `subtle` starts supporting const fns. +#[derive(Debug, Copy, Clone)] +pub struct CtChoice(Word); + +impl CtChoice { + /// The falsy value. + pub const FALSE: Self = Self(0); + + /// The truthy value. + pub const TRUE: Self = Self(Word::MAX); + + /// Returns the truthy value if `value == Word::MAX`, and the falsy value if `value == 0`. + /// Panics for other values. + pub(crate) const fn from_mask(value: Word) -> Self { + debug_assert!(value == Self::FALSE.0 || value == Self::TRUE.0); + Self(value) + } + + /// Returns the truthy value if `value == 1`, and the falsy value if `value == 0`. + /// Panics for other values. + pub(crate) const fn from_lsb(value: Word) -> Self { + debug_assert!(value == 0 || value == 1); + Self(value.wrapping_neg()) + } + + /// Returns the truthy value if `value != 0`, and the falsy value otherwise. + pub(crate) const fn from_usize_being_nonzero(value: usize) -> Self { + const HI_BIT: u32 = usize::BITS - 1; + Self::from_lsb(((value | value.wrapping_neg()) >> HI_BIT) as Word) + } + + /// Returns the truthy value if `x == y`, and the falsy value otherwise. + pub(crate) const fn from_usize_equality(x: usize, y: usize) -> Self { + Self::from_usize_being_nonzero(x.wrapping_sub(y)).not() + } + + /// Returns the truthy value if `x < y`, and the falsy value otherwise. + pub(crate) const fn from_usize_lt(x: usize, y: usize) -> Self { + let bit = (((!x) & y) | (((!x) | y) & (x.wrapping_sub(y)))) >> (usize::BITS - 1); + Self::from_lsb(bit as Word) + } + + pub(crate) const fn not(&self) -> Self { + Self(!self.0) + } + + pub(crate) const fn or(&self, other: Self) -> Self { + Self(self.0 | other.0) + } + + pub(crate) const fn and(&self, other: Self) -> Self { + Self(self.0 & other.0) + } + + /// Return `b` if `self` is truthy, otherwise return `a`. + pub(crate) const fn select(&self, a: Word, b: Word) -> Word { + a ^ (self.0 & (a ^ b)) + } + + /// Return `x` if `self` is truthy, otherwise return 0. + pub(crate) const fn if_true(&self, x: Word) -> Word { + x & self.0 + } + + pub(crate) const fn is_true_vartime(&self) -> bool { + self.0 == CtChoice::TRUE.0 + } + + pub(crate) const fn to_u8(self) -> u8 { + (self.0 as u8) & 1 + } +} + +impl From for Choice { + fn from(choice: CtChoice) -> Self { + Choice::from(choice.to_u8()) + } +} + +impl From for bool { + fn from(choice: CtChoice) -> Self { + choice.is_true_vartime() + } +} + +#[cfg(test)] +mod tests { + use super::CtChoice; + use crate::Word; + + #[test] + fn select() { + let a: Word = 1; + let b: Word = 2; + assert_eq!(CtChoice::TRUE.select(a, b), b); + assert_eq!(CtChoice::FALSE.select(a, b), a); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/lib.rs b/src/rust/vendor/crypto-bigint/src/lib.rs new file mode 100644 index 000000000..6decb177b --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/lib.rs @@ -0,0 +1,217 @@ +#![no_std] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![doc = include_str!("../README.md")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" +)] +#![deny(unsafe_code)] +#![warn( + clippy::mod_module_files, + clippy::unwrap_used, + missing_docs, + missing_debug_implementations, + missing_copy_implementations, + rust_2018_idioms, + trivial_casts, + trivial_numeric_casts, + unused_qualifications +)] + +//! ## Usage +//! +//! This crate defines a [`Uint`] type which is const generic around an inner +//! [`Limb`] array, where a [`Limb`] is a newtype for a word-sized integer. +//! Thus large integers are represented as arrays of smaller integers which +//! are sized appropriately for the CPU, giving us some assurances of how +//! arithmetic operations over those smaller integers will behave. +//! +//! To obtain appropriately sized integers regardless of what a given CPU's +//! word size happens to be, a number of portable type aliases are provided for +//! integer sizes commonly used in cryptography, for example: +//! [`U128`], [`U384`], [`U256`], [`U2048`], [`U3072`], [`U4096`]. +//! +//! ### `const fn` usage +//! +//! The [`Uint`] type provides a number of `const fn` inherent methods which +//! can be used for initializing and performing arithmetic on big integers in +//! const contexts: +//! +//! ``` +//! use crypto_bigint::U256; +//! +//! // Parse a constant from a big endian hexadecimal string. +//! pub const MODULUS: U256 = +//! U256::from_be_hex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"); +//! +//! // Compute `MODULUS` shifted right by 1 at compile time +//! pub const MODULUS_SHR1: U256 = MODULUS.shr_vartime(1); +//! ``` +//! +//! Note that large constant computations may accidentally trigger a the `const_eval_limit` of the compiler. +//! The current way to deal with this problem is to either simplify this computation, +//! or increase the compiler's limit (currently a nightly feature). +//! One can completely remove the compiler's limit using: +//! ```ignore +//! #![feature(const_eval_limit)] +//! #![const_eval_limit = "0"] +//! ``` +//! +//! ### Trait-based usage +//! +//! The [`Uint`] type itself does not implement the standard arithmetic traits +//! such as [`Add`], [`Sub`], [`Mul`], and [`Div`]. +//! +//! To use these traits you must first pick a wrapper type which determines +//! overflow behavior: [`Wrapping`] or [`Checked`]. +//! +//! #### Wrapping arithmetic +//! +//! ``` +//! use crypto_bigint::{U256, Wrapping}; +//! +//! let a = Wrapping(U256::MAX); +//! let b = Wrapping(U256::ONE); +//! let c = a + b; +//! +//! // `MAX` + 1 wraps back around to zero +//! assert_eq!(c.0, U256::ZERO); +//! ``` +//! +//! #### Checked arithmetic +//! +//! ``` +//! use crypto_bigint::{U256, Checked}; +//! +//! let a = Checked::new(U256::ONE); +//! let b = Checked::new(U256::from(2u8)); +//! let c = a + b; +//! assert_eq!(c.0.unwrap(), U256::from(3u8)) +//! ``` +//! +//! ### Modular arithmetic +//! +//! This library has initial support for modular arithmetic in the form of the +//! [`AddMod`], [`SubMod`], [`NegMod`], and [`MulMod`] traits, as well as the +//! support for the [`Rem`] trait when used with a [`NonZero`] operand. +//! +//! ``` +//! use crypto_bigint::{AddMod, U256}; +//! +//! // mod 3 +//! let modulus = U256::from(3u8); +//! +//! // 1 + 1 mod 3 = 2 +//! let a = U256::ONE.add_mod(&U256::ONE, &modulus); +//! assert_eq!(a, U256::from(2u8)); +//! +//! // 2 + 1 mod 3 = 0 +//! let b = a.add_mod(&U256::ONE, &modulus); +//! assert_eq!(b, U256::ZERO); +//! ``` +//! +//! It also supports modular arithmetic over constant moduli using `Residue`, +//! and over moduli set at runtime using `DynResidue`. +//! That includes modular exponentiation and multiplicative inverses. +//! These features are described in the [`modular`] module. +//! +//! ### Random number generation +//! +//! When the `rand_core` or `rand` features of this crate are enabled, it's +//! possible to generate random numbers using any CSRNG by using the +//! [`Random`] trait: +//! +//! ``` +//! # #[cfg(feature = "rand")] +//! # { +//! use crypto_bigint::{Random, U256, rand_core::OsRng}; +//! +//! let n = U256::random(&mut OsRng); +//! # } +//! ``` +//! +//! #### Modular random number generation +//! +//! The [`RandomMod`] trait supports generating random numbers with a uniform +//! distribution around a given [`NonZero`] modulus. +//! +//! ``` +//! # #[cfg(feature = "rand")] +//! # { +//! use crypto_bigint::{NonZero, RandomMod, U256, rand_core::OsRng}; +//! +//! let modulus = NonZero::new(U256::from(3u8)).unwrap(); +//! let n = U256::random_mod(&mut OsRng, &modulus); +//! # } +//! ``` +//! +//! [`Add`]: core::ops::Add +//! [`Div`]: core::ops::Div +//! [`Mul`]: core::ops::Mul +//! [`Rem`]: core::ops::Rem +//! [`Sub`]: core::ops::Sub + +#[cfg(feature = "alloc")] +#[allow(unused_imports)] +#[macro_use] +extern crate alloc; + +#[macro_use] +mod macros; + +#[cfg(feature = "generic-array")] +mod array; +#[cfg(feature = "alloc")] +mod boxed; +mod checked; +mod ct_choice; +mod limb; +mod non_zero; +mod traits; +mod uint; +mod wrapping; + +pub use crate::{ + checked::Checked, + ct_choice::CtChoice, + limb::{Limb, WideWord, Word}, + non_zero::NonZero, + traits::*, + uint::div_limb::Reciprocal, + uint::*, + wrapping::Wrapping, +}; +pub use subtle; + +#[cfg(feature = "alloc")] +pub use crate::boxed::uint::BoxedUint; + +#[cfg(feature = "generic-array")] +pub use { + crate::array::{ArrayDecoding, ArrayEncoding, ByteArray}, + generic_array::{self, typenum::consts}, +}; + +#[cfg(feature = "rand_core")] +pub use rand_core; + +#[cfg(feature = "rlp")] +pub use rlp; + +#[cfg(feature = "zeroize")] +pub use zeroize; + +/// Import prelude for this crate: includes important traits. +pub mod prelude { + pub use crate::traits::*; + + #[cfg(feature = "generic-array")] + pub use crate::array::{ArrayDecoding, ArrayEncoding}; +} + +#[cfg(sidefuzz)] +#[no_mangle] +pub extern "C" fn fuzz() { + let input = sidefuzz::fetch_input(32); // 32 bytes of of fuzzing input as a &[u8] + sidefuzz::black_box(my_hopefully_constant_fn(input)); +} diff --git a/src/rust/vendor/crypto-bigint/src/limb.rs b/src/rust/vendor/crypto-bigint/src/limb.rs new file mode 100644 index 000000000..a5ca95704 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/limb.rs @@ -0,0 +1,176 @@ +//! Big integers are represented as an array of smaller CPU word-size integers +//! called "limbs". + +mod add; +mod bit_and; +mod bit_not; +mod bit_or; +mod bit_xor; +mod bits; +mod cmp; +mod encoding; +mod from; +mod mul; +mod neg; +mod shl; +mod shr; +mod sub; + +#[cfg(feature = "rand_core")] +mod rand; + +use crate::{Bounded, Zero}; +use core::fmt; +use subtle::{Choice, ConditionallySelectable}; + +#[cfg(feature = "serde")] +use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] +compile_error!("this crate builds on 32-bit and 64-bit platforms only"); + +// +// 32-bit definitions +// + +/// Inner integer type that the [`Limb`] newtype wraps. +#[cfg(target_pointer_width = "32")] +pub type Word = u32; + +/// Unsigned wide integer type: double the width of [`Word`]. +#[cfg(target_pointer_width = "32")] +pub type WideWord = u64; + +// +// 64-bit definitions +// + +/// Unsigned integer type that the [`Limb`] newtype wraps. +#[cfg(target_pointer_width = "64")] +pub type Word = u64; + +/// Wide integer type: double the width of [`Word`]. +#[cfg(target_pointer_width = "64")] +pub type WideWord = u128; + +/// Highest bit in a [`Limb`]. +pub(crate) const HI_BIT: usize = Limb::BITS - 1; + +/// Big integers are represented as an array of smaller CPU word-size integers +/// called "limbs". +// Our PartialEq impl only differs from the default one by being constant-time, so this is safe +#[allow(clippy::derived_hash_with_manual_eq)] +#[derive(Copy, Clone, Default, Hash)] +#[repr(transparent)] +pub struct Limb(pub Word); + +impl Limb { + /// The value `0`. + pub const ZERO: Self = Limb(0); + + /// The value `1`. + pub const ONE: Self = Limb(1); + + /// Maximum value this [`Limb`] can express. + pub const MAX: Self = Limb(Word::MAX); + + // 32-bit + + /// Size of the inner integer in bits. + #[cfg(target_pointer_width = "32")] + pub const BITS: usize = 32; + /// Size of the inner integer in bytes. + #[cfg(target_pointer_width = "32")] + pub const BYTES: usize = 4; + + // 64-bit + + /// Size of the inner integer in bits. + #[cfg(target_pointer_width = "64")] + pub const BITS: usize = 64; + /// Size of the inner integer in bytes. + #[cfg(target_pointer_width = "64")] + pub const BYTES: usize = 8; +} + +impl Bounded for Limb { + const BITS: usize = Self::BITS; + const BYTES: usize = Self::BYTES; +} + +impl ConditionallySelectable for Limb { + #[inline] + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self(Word::conditional_select(&a.0, &b.0, choice)) + } +} + +impl Zero for Limb { + const ZERO: Self = Self::ZERO; +} + +impl fmt::Debug for Limb { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Limb(0x{self:X})") + } +} + +impl fmt::Display for Limb { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::UpperHex::fmt(self, f) + } +} + +impl fmt::LowerHex for Limb { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:0width$x}", &self.0, width = Self::BYTES * 2) + } +} + +impl fmt::UpperHex for Limb { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:0width$X}", &self.0, width = Self::BYTES * 2) + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for Limb { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Ok(Self(Word::deserialize(deserializer)?)) + } +} + +#[cfg(feature = "serde")] +impl Serialize for Limb { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.0.serialize(serializer) + } +} + +#[cfg(feature = "zeroize")] +impl zeroize::DefaultIsZeroes for Limb {} + +#[cfg(test)] +mod tests { + #[cfg(feature = "alloc")] + use {super::Limb, alloc::format}; + + #[cfg(feature = "alloc")] + #[test] + fn debug() { + #[cfg(target_pointer_width = "32")] + assert_eq!(format!("{:?}", Limb(42)), "Limb(0x0000002A)"); + + #[cfg(target_pointer_width = "64")] + assert_eq!(format!("{:?}", Limb(42)), "Limb(0x000000000000002A)"); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/limb/add.rs b/src/rust/vendor/crypto-bigint/src/limb/add.rs new file mode 100644 index 000000000..0ef793b2e --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/limb/add.rs @@ -0,0 +1,180 @@ +//! Limb addition + +use crate::{Checked, CheckedAdd, Limb, WideWord, Word, Wrapping, Zero}; +use core::ops::{Add, AddAssign}; +use subtle::CtOption; + +impl Limb { + /// Computes `self + rhs + carry`, returning the result along with the new carry. + #[inline(always)] + pub const fn adc(self, rhs: Limb, carry: Limb) -> (Limb, Limb) { + let a = self.0 as WideWord; + let b = rhs.0 as WideWord; + let carry = carry.0 as WideWord; + let ret = a + b + carry; + (Limb(ret as Word), Limb((ret >> Self::BITS) as Word)) + } + + /// Perform saturating addition. + #[inline] + pub const fn saturating_add(&self, rhs: Self) -> Self { + Limb(self.0.saturating_add(rhs.0)) + } + + /// Perform wrapping addition, discarding overflow. + #[inline(always)] + pub const fn wrapping_add(&self, rhs: Self) -> Self { + Limb(self.0.wrapping_add(rhs.0)) + } +} + +impl CheckedAdd for Limb { + type Output = Self; + + #[inline] + fn checked_add(&self, rhs: Self) -> CtOption { + let (result, carry) = self.adc(rhs, Limb::ZERO); + CtOption::new(result, carry.is_zero()) + } +} + +impl Add for Wrapping { + type Output = Self; + + fn add(self, rhs: Self) -> Wrapping { + Wrapping(self.0.wrapping_add(rhs.0)) + } +} + +impl Add<&Wrapping> for Wrapping { + type Output = Wrapping; + + fn add(self, rhs: &Wrapping) -> Wrapping { + Wrapping(self.0.wrapping_add(rhs.0)) + } +} + +impl Add> for &Wrapping { + type Output = Wrapping; + + fn add(self, rhs: Wrapping) -> Wrapping { + Wrapping(self.0.wrapping_add(rhs.0)) + } +} + +impl Add<&Wrapping> for &Wrapping { + type Output = Wrapping; + + fn add(self, rhs: &Wrapping) -> Wrapping { + Wrapping(self.0.wrapping_add(rhs.0)) + } +} + +impl AddAssign for Wrapping { + fn add_assign(&mut self, other: Self) { + *self = *self + other; + } +} + +impl AddAssign<&Wrapping> for Wrapping { + fn add_assign(&mut self, other: &Self) { + *self = *self + other; + } +} + +impl Add for Checked { + type Output = Self; + + fn add(self, rhs: Self) -> Checked { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(rhs))), + ) + } +} + +impl Add<&Checked> for Checked { + type Output = Checked; + + fn add(self, rhs: &Checked) -> Checked { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(rhs))), + ) + } +} + +impl Add> for &Checked { + type Output = Checked; + + fn add(self, rhs: Checked) -> Checked { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(rhs))), + ) + } +} + +impl Add<&Checked> for &Checked { + type Output = Checked; + + fn add(self, rhs: &Checked) -> Checked { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(rhs))), + ) + } +} + +impl AddAssign for Checked { + fn add_assign(&mut self, other: Self) { + *self = *self + other; + } +} + +impl AddAssign<&Checked> for Checked { + fn add_assign(&mut self, other: &Self) { + *self = *self + other; + } +} + +#[cfg(test)] +mod tests { + use crate::{CheckedAdd, Limb}; + + #[test] + fn adc_no_carry() { + let (res, carry) = Limb::ZERO.adc(Limb::ONE, Limb::ZERO); + assert_eq!(res, Limb::ONE); + assert_eq!(carry, Limb::ZERO); + } + + #[test] + fn adc_with_carry() { + let (res, carry) = Limb::MAX.adc(Limb::ONE, Limb::ZERO); + assert_eq!(res, Limb::ZERO); + assert_eq!(carry, Limb::ONE); + } + + #[test] + fn wrapping_add_no_carry() { + assert_eq!(Limb::ZERO.wrapping_add(Limb::ONE), Limb::ONE); + } + + #[test] + fn wrapping_add_with_carry() { + assert_eq!(Limb::MAX.wrapping_add(Limb::ONE), Limb::ZERO); + } + + #[test] + fn checked_add_ok() { + let result = Limb::ZERO.checked_add(Limb::ONE); + assert_eq!(result.unwrap(), Limb::ONE); + } + + #[test] + fn checked_add_overflow() { + let result = Limb::MAX.checked_add(Limb::ONE); + assert!(!bool::from(result.is_some())); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/limb/bit_and.rs b/src/rust/vendor/crypto-bigint/src/limb/bit_and.rs new file mode 100644 index 000000000..3f0bfba0e --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/limb/bit_and.rs @@ -0,0 +1,21 @@ +//! Limb bit and operations. + +use super::Limb; +use core::ops::BitAnd; + +impl Limb { + /// Calculates `a & b`. + #[inline(always)] + pub const fn bitand(self, rhs: Self) -> Self { + Limb(self.0 & rhs.0) + } +} + +impl BitAnd for Limb { + type Output = Limb; + + #[inline(always)] + fn bitand(self, rhs: Self) -> Self::Output { + self.bitand(rhs) + } +} diff --git a/src/rust/vendor/crypto-bigint/src/limb/bit_not.rs b/src/rust/vendor/crypto-bigint/src/limb/bit_not.rs new file mode 100644 index 000000000..26676d598 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/limb/bit_not.rs @@ -0,0 +1,19 @@ +//! Limb bit not operations. + +use super::Limb; +use core::ops::Not; + +impl Limb { + /// Calculates `!a`. + pub const fn not(self) -> Self { + Limb(!self.0) + } +} + +impl Not for Limb { + type Output = Limb; + + fn not(self) -> ::Output { + self.not() + } +} diff --git a/src/rust/vendor/crypto-bigint/src/limb/bit_or.rs b/src/rust/vendor/crypto-bigint/src/limb/bit_or.rs new file mode 100644 index 000000000..cafac18da --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/limb/bit_or.rs @@ -0,0 +1,19 @@ +//! Limb bit or operations. + +use super::Limb; +use core::ops::BitOr; + +impl Limb { + /// Calculates `a | b`. + pub const fn bitor(self, rhs: Self) -> Self { + Limb(self.0 | rhs.0) + } +} + +impl BitOr for Limb { + type Output = Limb; + + fn bitor(self, rhs: Self) -> Self::Output { + self.bitor(rhs) + } +} diff --git a/src/rust/vendor/crypto-bigint/src/limb/bit_xor.rs b/src/rust/vendor/crypto-bigint/src/limb/bit_xor.rs new file mode 100644 index 000000000..a50782293 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/limb/bit_xor.rs @@ -0,0 +1,19 @@ +//! Limb bit xor operations. + +use super::Limb; +use core::ops::BitXor; + +impl Limb { + /// Calculates `a ^ b`. + pub const fn bitxor(self, rhs: Self) -> Self { + Limb(self.0 ^ rhs.0) + } +} + +impl BitXor for Limb { + type Output = Limb; + + fn bitxor(self, rhs: Self) -> Self::Output { + self.bitxor(rhs) + } +} diff --git a/src/rust/vendor/crypto-bigint/src/limb/bits.rs b/src/rust/vendor/crypto-bigint/src/limb/bits.rs new file mode 100644 index 000000000..c769e33e9 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/limb/bits.rs @@ -0,0 +1,23 @@ +use super::Limb; + +impl Limb { + /// Calculate the number of bits needed to represent this number. + pub const fn bits(self) -> usize { + Limb::BITS - (self.0.leading_zeros() as usize) + } + + /// Calculate the number of leading zeros in the binary representation of this number. + pub const fn leading_zeros(self) -> usize { + self.0.leading_zeros() as usize + } + + /// Calculate the number of trailing zeros in the binary representation of this number. + pub const fn trailing_zeros(self) -> usize { + self.0.trailing_zeros() as usize + } + + /// Calculate the number of trailing ones the binary representation of this number. + pub const fn trailing_ones(self) -> usize { + self.0.trailing_ones() as usize + } +} diff --git a/src/rust/vendor/crypto-bigint/src/limb/cmp.rs b/src/rust/vendor/crypto-bigint/src/limb/cmp.rs new file mode 100644 index 000000000..4cdec5b5d --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/limb/cmp.rs @@ -0,0 +1,200 @@ +//! Limb comparisons + +use super::HI_BIT; +use crate::{CtChoice, Limb}; +use core::cmp::Ordering; +use subtle::{Choice, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess}; + +impl Limb { + /// Is this limb an odd number? + #[inline] + pub fn is_odd(&self) -> Choice { + Choice::from(self.0 as u8 & 1) + } + + /// Perform a comparison of the inner value in variable-time. + /// + /// Note that the [`PartialOrd`] and [`Ord`] impls wrap constant-time + /// comparisons using the `subtle` crate. + pub fn cmp_vartime(&self, other: &Self) -> Ordering { + self.0.cmp(&other.0) + } + + /// Performs an equality check in variable-time. + pub const fn eq_vartime(&self, other: &Self) -> bool { + self.0 == other.0 + } + + /// Return `b` if `c` is truthy, otherwise return `a`. + #[inline] + pub(crate) const fn ct_select(a: Self, b: Self, c: CtChoice) -> Self { + Self(c.select(a.0, b.0)) + } + + /// Returns the truthy value if `self != 0` and the falsy value otherwise. + #[inline] + pub(crate) const fn ct_is_nonzero(&self) -> CtChoice { + let inner = self.0; + CtChoice::from_lsb((inner | inner.wrapping_neg()) >> HI_BIT) + } + + /// Returns the truthy value if `lhs == rhs` and the falsy value otherwise. + #[inline] + pub(crate) const fn ct_eq(lhs: Self, rhs: Self) -> CtChoice { + let x = lhs.0; + let y = rhs.0; + + // x ^ y == 0 if and only if x == y + Self(x ^ y).ct_is_nonzero().not() + } + + /// Returns the truthy value if `lhs < rhs` and the falsy value otherwise. + #[inline] + pub(crate) const fn ct_lt(lhs: Self, rhs: Self) -> CtChoice { + let x = lhs.0; + let y = rhs.0; + let bit = (((!x) & y) | (((!x) | y) & (x.wrapping_sub(y)))) >> (Limb::BITS - 1); + CtChoice::from_lsb(bit) + } + + /// Returns the truthy value if `lhs <= rhs` and the falsy value otherwise. + #[inline] + pub(crate) const fn ct_le(lhs: Self, rhs: Self) -> CtChoice { + let x = lhs.0; + let y = rhs.0; + let bit = (((!x) | y) & ((x ^ y) | !(y.wrapping_sub(x)))) >> (Limb::BITS - 1); + CtChoice::from_lsb(bit) + } +} + +impl ConstantTimeEq for Limb { + #[inline] + fn ct_eq(&self, other: &Self) -> Choice { + self.0.ct_eq(&other.0) + } +} + +impl ConstantTimeGreater for Limb { + #[inline] + fn ct_gt(&self, other: &Self) -> Choice { + self.0.ct_gt(&other.0) + } +} + +impl ConstantTimeLess for Limb { + #[inline] + fn ct_lt(&self, other: &Self) -> Choice { + self.0.ct_lt(&other.0) + } +} + +impl Eq for Limb {} + +impl Ord for Limb { + fn cmp(&self, other: &Self) -> Ordering { + let mut n = 0i8; + n -= self.ct_lt(other).unwrap_u8() as i8; + n += self.ct_gt(other).unwrap_u8() as i8; + + match n { + -1 => Ordering::Less, + 1 => Ordering::Greater, + _ => { + debug_assert_eq!(n, 0); + debug_assert!(bool::from(self.ct_eq(other))); + Ordering::Equal + } + } + } +} + +impl PartialOrd for Limb { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl PartialEq for Limb { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } +} + +#[cfg(test)] +mod tests { + use crate::{Limb, Zero}; + use core::cmp::Ordering; + use subtle::{ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess}; + + #[test] + fn is_zero() { + assert!(bool::from(Limb::ZERO.is_zero())); + assert!(!bool::from(Limb::ONE.is_zero())); + assert!(!bool::from(Limb::MAX.is_zero())); + } + + #[test] + fn is_odd() { + assert!(!bool::from(Limb::ZERO.is_odd())); + assert!(bool::from(Limb::ONE.is_odd())); + assert!(bool::from(Limb::MAX.is_odd())); + } + + #[test] + fn ct_eq() { + let a = Limb::ZERO; + let b = Limb::MAX; + + assert!(bool::from(a.ct_eq(&a))); + assert!(!bool::from(a.ct_eq(&b))); + assert!(!bool::from(b.ct_eq(&a))); + assert!(bool::from(b.ct_eq(&b))); + } + + #[test] + fn ct_gt() { + let a = Limb::ZERO; + let b = Limb::ONE; + let c = Limb::MAX; + + assert!(bool::from(b.ct_gt(&a))); + assert!(bool::from(c.ct_gt(&a))); + assert!(bool::from(c.ct_gt(&b))); + + assert!(!bool::from(a.ct_gt(&a))); + assert!(!bool::from(b.ct_gt(&b))); + assert!(!bool::from(c.ct_gt(&c))); + + assert!(!bool::from(a.ct_gt(&b))); + assert!(!bool::from(a.ct_gt(&c))); + assert!(!bool::from(b.ct_gt(&c))); + } + + #[test] + fn ct_lt() { + let a = Limb::ZERO; + let b = Limb::ONE; + let c = Limb::MAX; + + assert!(bool::from(a.ct_lt(&b))); + assert!(bool::from(a.ct_lt(&c))); + assert!(bool::from(b.ct_lt(&c))); + + assert!(!bool::from(a.ct_lt(&a))); + assert!(!bool::from(b.ct_lt(&b))); + assert!(!bool::from(c.ct_lt(&c))); + + assert!(!bool::from(b.ct_lt(&a))); + assert!(!bool::from(c.ct_lt(&a))); + assert!(!bool::from(c.ct_lt(&b))); + } + + #[test] + fn cmp() { + assert_eq!(Limb::ZERO.cmp(&Limb::ONE), Ordering::Less); + assert_eq!(Limb::ONE.cmp(&Limb::ONE), Ordering::Equal); + assert_eq!(Limb::MAX.cmp(&Limb::ONE), Ordering::Greater); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/limb/encoding.rs b/src/rust/vendor/crypto-bigint/src/limb/encoding.rs new file mode 100644 index 000000000..ab28a6adb --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/limb/encoding.rs @@ -0,0 +1,64 @@ +//! Limb encoding + +use super::{Limb, Word}; +use crate::Encoding; + +impl Encoding for Limb { + #[cfg(target_pointer_width = "32")] + type Repr = [u8; 4]; + #[cfg(target_pointer_width = "64")] + type Repr = [u8; 8]; + + #[inline] + fn from_be_bytes(bytes: Self::Repr) -> Self { + Limb(Word::from_be_bytes(bytes)) + } + + #[inline] + fn from_le_bytes(bytes: Self::Repr) -> Self { + Limb(Word::from_le_bytes(bytes)) + } + + #[inline] + fn to_be_bytes(&self) -> Self::Repr { + self.0.to_be_bytes() + } + + #[inline] + fn to_le_bytes(&self) -> Self::Repr { + self.0.to_le_bytes() + } +} + +#[cfg(test)] +mod test { + use super::*; + use proptest::prelude::*; + + prop_compose! { + fn limb()(inner in any::()) -> Limb { + Limb(inner) + } + } + + proptest! { + #[test] + fn roundtrip(a in limb()) { + assert_eq!(a, Limb::from_be_bytes(a.to_be_bytes())); + assert_eq!(a, Limb::from_le_bytes(a.to_le_bytes())); + } + } + + proptest! { + #[test] + fn reverse(a in limb()) { + let mut bytes = a.to_be_bytes(); + bytes.reverse(); + assert_eq!(a, Limb::from_le_bytes(bytes)); + + let mut bytes = a.to_le_bytes(); + bytes.reverse(); + assert_eq!(a, Limb::from_be_bytes(bytes)); + } + } +} diff --git a/src/rust/vendor/crypto-bigint/src/limb/from.rs b/src/rust/vendor/crypto-bigint/src/limb/from.rs new file mode 100644 index 000000000..aa6499243 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/limb/from.rs @@ -0,0 +1,74 @@ +//! `From`-like conversions for [`Limb`]. + +use super::{Limb, WideWord, Word}; + +impl Limb { + /// Create a [`Limb`] from a `u8` integer (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + pub const fn from_u8(n: u8) -> Self { + Limb(n as Word) + } + + /// Create a [`Limb`] from a `u16` integer (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + pub const fn from_u16(n: u16) -> Self { + Limb(n as Word) + } + + /// Create a [`Limb`] from a `u32` integer (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + pub const fn from_u32(n: u32) -> Self { + #[allow(trivial_numeric_casts)] + Limb(n as Word) + } + + /// Create a [`Limb`] from a `u64` integer (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + #[cfg(target_pointer_width = "64")] + pub const fn from_u64(n: u64) -> Self { + Limb(n) + } +} + +impl From for Limb { + #[inline] + fn from(n: u8) -> Limb { + Limb(n.into()) + } +} + +impl From for Limb { + #[inline] + fn from(n: u16) -> Limb { + Limb(n.into()) + } +} + +impl From for Limb { + #[inline] + fn from(n: u32) -> Limb { + Limb(n.into()) + } +} + +#[cfg(target_pointer_width = "64")] +impl From for Limb { + #[inline] + fn from(n: u64) -> Limb { + Limb(n) + } +} + +impl From for Word { + #[inline] + fn from(limb: Limb) -> Word { + limb.0 + } +} + +impl From for WideWord { + #[inline] + fn from(limb: Limb) -> WideWord { + limb.0.into() + } +} diff --git a/src/rust/vendor/crypto-bigint/src/limb/mul.rs b/src/rust/vendor/crypto-bigint/src/limb/mul.rs new file mode 100644 index 000000000..7f8b08454 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/limb/mul.rs @@ -0,0 +1,195 @@ +//! Limb multiplication + +use crate::{Checked, CheckedMul, Limb, WideWord, Word, Wrapping, Zero}; +use core::ops::{Mul, MulAssign}; +use subtle::CtOption; + +impl Limb { + /// Computes `self + (b * c) + carry`, returning the result along with the new carry. + #[inline(always)] + pub const fn mac(self, b: Limb, c: Limb, carry: Limb) -> (Limb, Limb) { + let a = self.0 as WideWord; + let b = b.0 as WideWord; + let c = c.0 as WideWord; + let carry = carry.0 as WideWord; + let ret = a + (b * c) + carry; + (Limb(ret as Word), Limb((ret >> Self::BITS) as Word)) + } + + /// Perform saturating multiplication. + #[inline] + pub const fn saturating_mul(&self, rhs: Self) -> Self { + Limb(self.0.saturating_mul(rhs.0)) + } + + /// Perform wrapping multiplication, discarding overflow. + #[inline(always)] + pub const fn wrapping_mul(&self, rhs: Self) -> Self { + Limb(self.0.wrapping_mul(rhs.0)) + } + + /// Compute "wide" multiplication, with a product twice the size of the input. + pub(crate) const fn mul_wide(&self, rhs: Self) -> WideWord { + (self.0 as WideWord) * (rhs.0 as WideWord) + } +} + +impl CheckedMul for Limb { + type Output = Self; + + #[inline] + fn checked_mul(&self, rhs: Self) -> CtOption { + let result = self.mul_wide(rhs); + let overflow = Limb((result >> Self::BITS) as Word); + CtOption::new(Limb(result as Word), overflow.is_zero()) + } +} + +impl Mul for Wrapping { + type Output = Self; + + fn mul(self, rhs: Self) -> Wrapping { + Wrapping(self.0.wrapping_mul(rhs.0)) + } +} + +impl Mul<&Wrapping> for Wrapping { + type Output = Wrapping; + + fn mul(self, rhs: &Wrapping) -> Wrapping { + Wrapping(self.0.wrapping_mul(rhs.0)) + } +} + +impl Mul> for &Wrapping { + type Output = Wrapping; + + fn mul(self, rhs: Wrapping) -> Wrapping { + Wrapping(self.0.wrapping_mul(rhs.0)) + } +} + +impl Mul<&Wrapping> for &Wrapping { + type Output = Wrapping; + + fn mul(self, rhs: &Wrapping) -> Wrapping { + Wrapping(self.0.wrapping_mul(rhs.0)) + } +} + +impl MulAssign for Wrapping { + fn mul_assign(&mut self, other: Self) { + *self = *self * other; + } +} + +impl MulAssign<&Wrapping> for Wrapping { + fn mul_assign(&mut self, other: &Self) { + *self = *self * other; + } +} + +impl Mul for Checked { + type Output = Self; + + fn mul(self, rhs: Self) -> Checked { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(rhs))), + ) + } +} + +impl Mul<&Checked> for Checked { + type Output = Checked; + + fn mul(self, rhs: &Checked) -> Checked { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(rhs))), + ) + } +} + +impl Mul> for &Checked { + type Output = Checked; + + fn mul(self, rhs: Checked) -> Checked { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(rhs))), + ) + } +} + +impl Mul<&Checked> for &Checked { + type Output = Checked; + + fn mul(self, rhs: &Checked) -> Checked { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(rhs))), + ) + } +} + +impl MulAssign for Checked { + fn mul_assign(&mut self, other: Self) { + *self = *self * other; + } +} + +impl MulAssign<&Checked> for Checked { + fn mul_assign(&mut self, other: &Self) { + *self = *self * other; + } +} + +#[cfg(test)] +mod tests { + use super::{CheckedMul, Limb, WideWord}; + + #[test] + fn mul_wide_zero_and_one() { + assert_eq!(Limb::ZERO.mul_wide(Limb::ZERO), 0); + assert_eq!(Limb::ZERO.mul_wide(Limb::ONE), 0); + assert_eq!(Limb::ONE.mul_wide(Limb::ZERO), 0); + assert_eq!(Limb::ONE.mul_wide(Limb::ONE), 1); + } + + #[test] + fn mul_wide() { + let primes: &[u32] = &[3, 5, 17, 257, 65537]; + + for &a_int in primes { + for &b_int in primes { + let actual = Limb::from_u32(a_int).mul_wide(Limb::from_u32(b_int)); + let expected = a_int as WideWord * b_int as WideWord; + assert_eq!(actual, expected); + } + } + } + + #[test] + #[cfg(target_pointer_width = "32")] + fn checked_mul_ok() { + let n = Limb::from_u16(0xffff); + assert_eq!(n.checked_mul(n).unwrap(), Limb::from_u32(0xfffe_0001)); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn checked_mul_ok() { + let n = Limb::from_u32(0xffff_ffff); + assert_eq!( + n.checked_mul(n).unwrap(), + Limb::from_u64(0xffff_fffe_0000_0001) + ); + } + + #[test] + fn checked_mul_overflow() { + let n = Limb::MAX; + assert!(bool::from(n.checked_mul(n).is_none())); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/limb/neg.rs b/src/rust/vendor/crypto-bigint/src/limb/neg.rs new file mode 100644 index 000000000..b658bb9cd --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/limb/neg.rs @@ -0,0 +1,20 @@ +//! Limb negation + +use crate::{Limb, Wrapping}; +use core::ops::Neg; + +impl Neg for Wrapping { + type Output = Self; + + fn neg(self) -> Self::Output { + Self(self.0.wrapping_neg()) + } +} + +impl Limb { + /// Perform wrapping negation. + #[inline(always)] + pub const fn wrapping_neg(self) -> Self { + Limb(self.0.wrapping_neg()) + } +} diff --git a/src/rust/vendor/crypto-bigint/src/limb/rand.rs b/src/rust/vendor/crypto-bigint/src/limb/rand.rs new file mode 100644 index 000000000..43471682d --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/limb/rand.rs @@ -0,0 +1,38 @@ +//! Random number generator support + +use super::Limb; +use crate::{Encoding, NonZero, Random, RandomMod}; +use rand_core::CryptoRngCore; +use subtle::ConstantTimeLess; + +impl Random for Limb { + #[cfg(target_pointer_width = "32")] + fn random(rng: &mut impl CryptoRngCore) -> Self { + Self(rng.next_u32()) + } + + #[cfg(target_pointer_width = "64")] + fn random(rng: &mut impl CryptoRngCore) -> Self { + Self(rng.next_u64()) + } +} + +impl RandomMod for Limb { + fn random_mod(rng: &mut impl CryptoRngCore, modulus: &NonZero) -> Self { + let mut bytes = ::Repr::default(); + + let n_bits = modulus.bits(); + let n_bytes = (n_bits + 7) / 8; + let mask = 0xff >> (8 * n_bytes - n_bits); + + loop { + rng.fill_bytes(&mut bytes[..n_bytes]); + bytes[n_bytes - 1] &= mask; + + let n = Limb::from_le_bytes(bytes); + if n.ct_lt(modulus).into() { + return n; + } + } + } +} diff --git a/src/rust/vendor/crypto-bigint/src/limb/shl.rs b/src/rust/vendor/crypto-bigint/src/limb/shl.rs new file mode 100644 index 000000000..88e37f01e --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/limb/shl.rs @@ -0,0 +1,74 @@ +//! Limb left bitshift + +use crate::{Limb, Word}; +use core::ops::{Shl, ShlAssign}; + +impl Limb { + /// Computes `self << rhs`. + /// Panics if `rhs` overflows `Limb::BITS`. + #[inline(always)] + pub const fn shl(self, rhs: Self) -> Self { + Limb(self.0 << rhs.0) + } +} + +impl Shl for Limb { + type Output = Self; + + #[inline(always)] + fn shl(self, rhs: Self) -> Self::Output { + self.shl(rhs) + } +} + +impl Shl for Limb { + type Output = Self; + + #[inline(always)] + fn shl(self, rhs: usize) -> Self::Output { + self.shl(Limb(rhs as Word)) + } +} + +impl ShlAssign for Limb { + #[inline(always)] + fn shl_assign(&mut self, other: Self) { + *self = self.shl(other); + } +} + +impl ShlAssign for Limb { + #[inline(always)] + fn shl_assign(&mut self, other: usize) { + *self = self.shl(Limb(other as Word)); + } +} + +#[cfg(test)] +mod tests { + use crate::Limb; + + #[test] + fn shl1() { + assert_eq!(Limb(1) << 1, Limb(2)); + } + + #[test] + fn shl2() { + assert_eq!(Limb(1) << 2, Limb(4)); + } + + #[test] + fn shl_assign1() { + let mut l = Limb(1); + l <<= 1; + assert_eq!(l, Limb(2)); + } + + #[test] + fn shl_assign2() { + let mut l = Limb(1); + l <<= 2; + assert_eq!(l, Limb(4)); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/limb/shr.rs b/src/rust/vendor/crypto-bigint/src/limb/shr.rs new file mode 100644 index 000000000..7c422e045 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/limb/shr.rs @@ -0,0 +1,74 @@ +//! Limb right bitshift + +use crate::{Limb, Word}; +use core::ops::{Shr, ShrAssign}; + +impl Limb { + /// Computes `self >> rhs`. + /// Panics if `rhs` overflows `Limb::BITS`. + #[inline(always)] + pub const fn shr(self, rhs: Self) -> Self { + Limb(self.0 >> rhs.0) + } +} + +impl Shr for Limb { + type Output = Self; + + #[inline(always)] + fn shr(self, rhs: Self) -> Self::Output { + self.shr(rhs) + } +} + +impl Shr for Limb { + type Output = Self; + + #[inline(always)] + fn shr(self, rhs: usize) -> Self::Output { + self.shr(Limb(rhs as Word)) + } +} + +impl ShrAssign for Limb { + #[inline(always)] + fn shr_assign(&mut self, other: Self) { + *self = self.shr(other); + } +} + +impl ShrAssign for Limb { + #[inline(always)] + fn shr_assign(&mut self, other: usize) { + *self = self.shr(Limb(other as Word)); + } +} + +#[cfg(test)] +mod tests { + use crate::Limb; + + #[test] + fn shr1() { + assert_eq!(Limb(2) >> 1, Limb(1)); + } + + #[test] + fn shr2() { + assert_eq!(Limb(16) >> 2, Limb(4)); + } + + #[test] + fn shr_assign1() { + let mut l = Limb::ONE; + l >>= 1; + assert_eq!(l, Limb::ZERO); + } + + #[test] + fn shr_assign2() { + let mut l = Limb(32); + l >>= 2; + assert_eq!(l, Limb(8)); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/limb/sub.rs b/src/rust/vendor/crypto-bigint/src/limb/sub.rs new file mode 100644 index 000000000..0fc7a4a68 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/limb/sub.rs @@ -0,0 +1,182 @@ +//! Limb subtraction + +use crate::{Checked, CheckedSub, Limb, WideWord, Word, Wrapping, Zero}; +use core::ops::{Sub, SubAssign}; +use subtle::CtOption; + +impl Limb { + /// Computes `self - (rhs + borrow)`, returning the result along with the new borrow. + #[inline(always)] + pub const fn sbb(self, rhs: Limb, borrow: Limb) -> (Limb, Limb) { + let a = self.0 as WideWord; + let b = rhs.0 as WideWord; + let borrow = (borrow.0 >> (Self::BITS - 1)) as WideWord; + let ret = a.wrapping_sub(b + borrow); + (Limb(ret as Word), Limb((ret >> Self::BITS) as Word)) + } + + /// Perform saturating subtraction. + #[inline] + pub const fn saturating_sub(&self, rhs: Self) -> Self { + Limb(self.0.saturating_sub(rhs.0)) + } + + /// Perform wrapping subtraction, discarding underflow and wrapping around + /// the boundary of the type. + #[inline(always)] + pub const fn wrapping_sub(&self, rhs: Self) -> Self { + Limb(self.0.wrapping_sub(rhs.0)) + } +} + +impl CheckedSub for Limb { + type Output = Self; + + #[inline] + fn checked_sub(&self, rhs: Self) -> CtOption { + let (result, underflow) = self.sbb(rhs, Limb::ZERO); + CtOption::new(result, underflow.is_zero()) + } +} + +impl Sub for Wrapping { + type Output = Self; + + fn sub(self, rhs: Self) -> Wrapping { + Wrapping(self.0.wrapping_sub(rhs.0)) + } +} + +impl Sub<&Wrapping> for Wrapping { + type Output = Wrapping; + + fn sub(self, rhs: &Wrapping) -> Wrapping { + Wrapping(self.0.wrapping_sub(rhs.0)) + } +} + +impl Sub> for &Wrapping { + type Output = Wrapping; + + fn sub(self, rhs: Wrapping) -> Wrapping { + Wrapping(self.0.wrapping_sub(rhs.0)) + } +} + +impl Sub<&Wrapping> for &Wrapping { + type Output = Wrapping; + + fn sub(self, rhs: &Wrapping) -> Wrapping { + Wrapping(self.0.wrapping_sub(rhs.0)) + } +} + +impl SubAssign for Wrapping { + fn sub_assign(&mut self, other: Self) { + *self = *self - other; + } +} + +impl SubAssign<&Wrapping> for Wrapping { + fn sub_assign(&mut self, other: &Self) { + *self = *self - other; + } +} + +impl Sub for Checked { + type Output = Self; + + fn sub(self, rhs: Self) -> Checked { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))), + ) + } +} + +impl Sub<&Checked> for Checked { + type Output = Checked; + + fn sub(self, rhs: &Checked) -> Checked { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))), + ) + } +} + +impl Sub> for &Checked { + type Output = Checked; + + fn sub(self, rhs: Checked) -> Checked { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))), + ) + } +} + +impl Sub<&Checked> for &Checked { + type Output = Checked; + + fn sub(self, rhs: &Checked) -> Checked { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))), + ) + } +} + +impl SubAssign for Checked { + fn sub_assign(&mut self, other: Self) { + *self = *self - other; + } +} + +impl SubAssign<&Checked> for Checked { + fn sub_assign(&mut self, other: &Self) { + *self = *self - other; + } +} + +#[cfg(test)] +mod tests { + use crate::{CheckedSub, Limb}; + + #[test] + fn sbb_no_borrow() { + let (res, borrow) = Limb::ONE.sbb(Limb::ONE, Limb::ZERO); + assert_eq!(res, Limb::ZERO); + assert_eq!(borrow, Limb::ZERO); + } + + #[test] + fn sbb_with_borrow() { + let (res, borrow) = Limb::ZERO.sbb(Limb::ONE, Limb::ZERO); + + assert_eq!(res, Limb::MAX); + assert_eq!(borrow, Limb::MAX); + } + + #[test] + fn wrapping_sub_no_borrow() { + assert_eq!(Limb::ONE.wrapping_sub(Limb::ONE), Limb::ZERO); + } + + #[test] + fn wrapping_sub_with_borrow() { + assert_eq!(Limb::ZERO.wrapping_sub(Limb::ONE), Limb::MAX); + } + + #[test] + fn checked_sub_ok() { + let result = Limb::ONE.checked_sub(Limb::ONE); + assert_eq!(result.unwrap(), Limb::ZERO); + } + + #[test] + fn checked_sub_overflow() { + let result = Limb::ZERO.checked_sub(Limb::ONE); + assert!(!bool::from(result.is_some())); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/macros.rs b/src/rust/vendor/crypto-bigint/src/macros.rs new file mode 100644 index 000000000..7142c214d --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/macros.rs @@ -0,0 +1,79 @@ +//! Macro definitions which are a part of the public API. + +/// Internal implementation detail of [`const_assert_eq`] and [`const_assert_ne`]. +#[doc(hidden)] +#[macro_export] +macro_rules! const_assert_n { + ($n:expr, $($arg:tt)*) => {{ + // TODO(tarcieri): gensym a name so it's unique per invocation of the macro? + mod __const_assert { + pub(super) struct Assert; + + impl Assert { + pub(super) const ASSERT: () = assert!($($arg)*); + } + } + + __const_assert::Assert::<$n>::ASSERT + }}; +} + +/// Const-friendly assertion that two values are equal. +/// +/// ``` +/// const _: () = crypto_bigint::const_assert_eq!(0, 0, "zero equals zero"); +/// ``` +#[macro_export] +macro_rules! const_assert_eq { + ($left:expr, $right:expr $(,)?) => ( + $crate::const_assert_n!($left, $left == $right) + ); + ($left:expr, $right:expr, $($arg:tt)+) => ( + $crate::const_assert_n!($left, $left == $right, $($arg)+) + ); +} + +/// Const-friendly assertion that two values are NOT equal. +/// +/// ``` +/// const _: () = crypto_bigint::const_assert_ne!(0, 1, "zero is NOT equal to one"); +/// ``` +#[macro_export] +macro_rules! const_assert_ne { + ($left:expr, $right:expr $(,)?) => ( + $crate::const_assert_n!($left, $left != $right) + ); + ($left:expr, $right:expr, $($arg:tt)+) => ( + $crate::const_assert_n!($left, $left != $right, $($arg)+) + ); +} + +/// Calculate the number of limbs required to represent the given number of bits. +// TODO(tarcieri): replace with `generic_const_exprs` (rust-lang/rust#76560) when stable +#[macro_export] +macro_rules! nlimbs { + ($bits:expr) => { + $bits / $crate::Limb::BITS + }; +} + +#[cfg(test)] +mod tests { + #[cfg(target_pointer_width = "32")] + #[test] + fn nlimbs_for_bits_macro() { + assert_eq!(nlimbs!(64), 2); + assert_eq!(nlimbs!(128), 4); + assert_eq!(nlimbs!(192), 6); + assert_eq!(nlimbs!(256), 8); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn nlimbs_for_bits_macro() { + assert_eq!(nlimbs!(64), 1); + assert_eq!(nlimbs!(128), 2); + assert_eq!(nlimbs!(192), 3); + assert_eq!(nlimbs!(256), 4); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/non_zero.rs b/src/rust/vendor/crypto-bigint/src/non_zero.rs new file mode 100644 index 000000000..dd4294e5a --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/non_zero.rs @@ -0,0 +1,393 @@ +//! Wrapper type for non-zero integers. + +use crate::{CtChoice, Encoding, Integer, Limb, Uint, Zero}; +use core::{ + fmt, + num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8}, + ops::Deref, +}; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +#[cfg(feature = "generic-array")] +use crate::{ArrayEncoding, ByteArray}; + +#[cfg(feature = "rand_core")] +use {crate::Random, rand_core::CryptoRngCore}; + +#[cfg(feature = "serde")] +use serdect::serde::{ + de::{Error, Unexpected}, + Deserialize, Deserializer, Serialize, Serializer, +}; + +/// Wrapper type for non-zero integers. +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] +pub struct NonZero(T); + +impl NonZero { + /// Creates a new non-zero limb in a const context. + /// The second return value is `FALSE` if `n` is zero, `TRUE` otherwise. + pub const fn const_new(n: Limb) -> (Self, CtChoice) { + (Self(n), n.ct_is_nonzero()) + } +} + +impl NonZero> { + /// Creates a new non-zero integer in a const context. + /// The second return value is `FALSE` if `n` is zero, `TRUE` otherwise. + pub const fn const_new(n: Uint) -> (Self, CtChoice) { + (Self(n), n.ct_is_nonzero()) + } +} + +impl NonZero +where + T: Zero, +{ + /// Create a new non-zero integer. + pub fn new(n: T) -> CtOption { + let is_zero = n.is_zero(); + CtOption::new(Self(n), !is_zero) + } +} + +impl NonZero +where + T: Integer, +{ + /// The value `1`. + pub const ONE: Self = Self(T::ONE); + + /// Maximum value this integer can express. + pub const MAX: Self = Self(T::MAX); +} + +impl NonZero +where + T: Encoding + Zero, +{ + /// Decode from big endian bytes. + pub fn from_be_bytes(bytes: T::Repr) -> CtOption { + Self::new(T::from_be_bytes(bytes)) + } + + /// Decode from little endian bytes. + pub fn from_le_bytes(bytes: T::Repr) -> CtOption { + Self::new(T::from_le_bytes(bytes)) + } +} + +#[cfg(feature = "generic-array")] +impl NonZero +where + T: ArrayEncoding + Zero, +{ + /// Decode a non-zero integer from big endian bytes. + pub fn from_be_byte_array(bytes: ByteArray) -> CtOption { + Self::new(T::from_be_byte_array(bytes)) + } + + /// Decode a non-zero integer from big endian bytes. + pub fn from_le_byte_array(bytes: ByteArray) -> CtOption { + Self::new(T::from_be_byte_array(bytes)) + } +} + +impl AsRef for NonZero +where + T: Zero, +{ + fn as_ref(&self) -> &T { + &self.0 + } +} + +impl ConditionallySelectable for NonZero +where + T: ConditionallySelectable + Zero, +{ + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self(T::conditional_select(&a.0, &b.0, choice)) + } +} + +impl ConstantTimeEq for NonZero +where + T: Zero, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.0.ct_eq(&other.0) + } +} + +impl Deref for NonZero +where + T: Zero, +{ + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + +#[cfg(feature = "rand_core")] +impl Random for NonZero +where + T: Random + Zero, +{ + /// Generate a random `NonZero`. + fn random(mut rng: &mut impl CryptoRngCore) -> Self { + // Use rejection sampling to eliminate zero values. + // While this method isn't constant-time, the attacker shouldn't learn + // anything about unrelated outputs so long as `rng` is a CSRNG. + loop { + if let Some(result) = Self::new(T::random(&mut rng)).into() { + break result; + } + } + } +} + +impl fmt::Display for NonZero +where + T: fmt::Display + Zero, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +impl fmt::Binary for NonZero +where + T: fmt::Binary + Zero, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Binary::fmt(&self.0, f) + } +} + +impl fmt::Octal for NonZero +where + T: fmt::Octal + Zero, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Octal::fmt(&self.0, f) + } +} + +impl fmt::LowerHex for NonZero +where + T: fmt::LowerHex + Zero, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(&self.0, f) + } +} + +impl fmt::UpperHex for NonZero +where + T: fmt::UpperHex + Zero, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::UpperHex::fmt(&self.0, f) + } +} + +impl NonZero { + /// Create a [`NonZero`] from a [`NonZeroU8`] (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + pub const fn from_u8(n: NonZeroU8) -> Self { + Self(Limb::from_u8(n.get())) + } + + /// Create a [`NonZero`] from a [`NonZeroU16`] (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + pub const fn from_u16(n: NonZeroU16) -> Self { + Self(Limb::from_u16(n.get())) + } + + /// Create a [`NonZero`] from a [`NonZeroU32`] (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + pub const fn from_u32(n: NonZeroU32) -> Self { + Self(Limb::from_u32(n.get())) + } + + /// Create a [`NonZero`] from a [`NonZeroU64`] (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + #[cfg(target_pointer_width = "64")] + pub const fn from_u64(n: NonZeroU64) -> Self { + Self(Limb::from_u64(n.get())) + } +} + +impl From for NonZero { + fn from(integer: NonZeroU8) -> Self { + Self::from_u8(integer) + } +} + +impl From for NonZero { + fn from(integer: NonZeroU16) -> Self { + Self::from_u16(integer) + } +} + +impl From for NonZero { + fn from(integer: NonZeroU32) -> Self { + Self::from_u32(integer) + } +} + +#[cfg(target_pointer_width = "64")] +impl From for NonZero { + fn from(integer: NonZeroU64) -> Self { + Self::from_u64(integer) + } +} + +impl NonZero> { + /// Create a [`NonZero`] from a [`Uint`] (const-friendly) + pub const fn from_uint(n: Uint) -> Self { + let mut i = 0; + let mut found_non_zero = false; + while i < LIMBS { + if n.as_limbs()[i].0 != 0 { + found_non_zero = true; + } + i += 1; + } + assert!(found_non_zero, "found zero"); + Self(n) + } + + /// Create a [`NonZero`] from a [`NonZeroU8`] (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + pub const fn from_u8(n: NonZeroU8) -> Self { + Self(Uint::from_u8(n.get())) + } + + /// Create a [`NonZero`] from a [`NonZeroU16`] (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + pub const fn from_u16(n: NonZeroU16) -> Self { + Self(Uint::from_u16(n.get())) + } + + /// Create a [`NonZero`] from a [`NonZeroU32`] (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + pub const fn from_u32(n: NonZeroU32) -> Self { + Self(Uint::from_u32(n.get())) + } + + /// Create a [`NonZero`] from a [`NonZeroU64`] (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + pub const fn from_u64(n: NonZeroU64) -> Self { + Self(Uint::from_u64(n.get())) + } + + /// Create a [`NonZero`] from a [`NonZeroU128`] (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + pub const fn from_u128(n: NonZeroU128) -> Self { + Self(Uint::from_u128(n.get())) + } +} + +impl From for NonZero> { + fn from(integer: NonZeroU8) -> Self { + Self::from_u8(integer) + } +} + +impl From for NonZero> { + fn from(integer: NonZeroU16) -> Self { + Self::from_u16(integer) + } +} + +impl From for NonZero> { + fn from(integer: NonZeroU32) -> Self { + Self::from_u32(integer) + } +} + +impl From for NonZero> { + fn from(integer: NonZeroU64) -> Self { + Self::from_u64(integer) + } +} + +impl From for NonZero> { + fn from(integer: NonZeroU128) -> Self { + Self::from_u128(integer) + } +} + +#[cfg(feature = "serde")] +impl<'de, T: Deserialize<'de> + Zero> Deserialize<'de> for NonZero { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let value: T = T::deserialize(deserializer)?; + + if bool::from(value.is_zero()) { + Err(D::Error::invalid_value( + Unexpected::Other("zero"), + &"a non-zero value", + )) + } else { + Ok(Self(value)) + } + } +} + +#[cfg(feature = "serde")] +impl Serialize for NonZero { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.0.serialize(serializer) + } +} + +#[cfg(all(test, feature = "serde"))] +#[allow(clippy::unwrap_used)] +mod tests { + use crate::{NonZero, U64}; + use bincode::ErrorKind; + + #[test] + fn serde() { + let test = + Option::>::from(NonZero::new(U64::from_u64(0x0011223344556677))).unwrap(); + + let serialized = bincode::serialize(&test).unwrap(); + let deserialized: NonZero = bincode::deserialize(&serialized).unwrap(); + + assert_eq!(test, deserialized); + + let serialized = bincode::serialize(&U64::ZERO).unwrap(); + assert!(matches!( + *bincode::deserialize::>(&serialized).unwrap_err(), + ErrorKind::Custom(message) if message == "invalid value: zero, expected a non-zero value" + )); + } + + #[test] + fn serde_owned() { + let test = + Option::>::from(NonZero::new(U64::from_u64(0x0011223344556677))).unwrap(); + + let serialized = bincode::serialize(&test).unwrap(); + let deserialized: NonZero = bincode::deserialize_from(serialized.as_slice()).unwrap(); + + assert_eq!(test, deserialized); + + let serialized = bincode::serialize(&U64::ZERO).unwrap(); + assert!(matches!( + *bincode::deserialize_from::<_, NonZero>(serialized.as_slice()).unwrap_err(), + ErrorKind::Custom(message) if message == "invalid value: zero, expected a non-zero value" + )); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/traits.rs b/src/rust/vendor/crypto-bigint/src/traits.rs new file mode 100644 index 000000000..0c26941c8 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/traits.rs @@ -0,0 +1,341 @@ +//! Traits provided by this crate + +use crate::{Limb, NonZero}; +use core::fmt::Debug; +use core::ops::{BitAnd, BitOr, BitXor, Div, Not, Rem, Shl, Shr}; +use subtle::{ + Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess, + CtOption, +}; + +#[cfg(feature = "rand_core")] +use rand_core::CryptoRngCore; + +/// Integer type. +pub trait Integer: + 'static + + AsRef<[Limb]> + + BitAnd + + BitOr + + BitXor + + for<'a> CheckedAdd<&'a Self, Output = Self> + + for<'a> CheckedSub<&'a Self, Output = Self> + + for<'a> CheckedMul<&'a Self, Output = Self> + + Copy + + ConditionallySelectable + + ConstantTimeEq + + ConstantTimeGreater + + ConstantTimeLess + + Debug + + Default + + Div, Output = Self> + + Eq + + From + + Not + + Ord + + Rem, Output = Self> + + Send + + Sized + + Shl + + Shr + + Sync + + Zero +{ + /// The value `1`. + const ONE: Self; + + /// Maximum value this integer can express. + const MAX: Self; + + /// Total size of the represented integer in bits. + const BITS: usize; + + /// Total size of the represented integer in bytes. + const BYTES: usize; + + /// The number of limbs used on this platform. + const LIMBS: usize; + + /// Is this integer value an odd number? + /// + /// # Returns + /// + /// If odd, returns `Choice(1)`. Otherwise, returns `Choice(0)`. + fn is_odd(&self) -> Choice; + + /// Is this integer value an even number? + /// + /// # Returns + /// + /// If even, returns `Choice(1)`. Otherwise, returns `Choice(0)`. + fn is_even(&self) -> Choice { + !self.is_odd() + } +} + +/// Zero values. +pub trait Zero: ConstantTimeEq + Sized { + /// The value `0`. + const ZERO: Self; + + /// Determine if this value is equal to zero. + /// + /// # Returns + /// + /// If zero, returns `Choice(1)`. Otherwise, returns `Choice(0)`. + fn is_zero(&self) -> Choice { + self.ct_eq(&Self::ZERO) + } +} + +/// Random number generation support. +#[cfg(feature = "rand_core")] +pub trait Random: Sized { + /// Generate a cryptographically secure random value. + fn random(rng: &mut impl CryptoRngCore) -> Self; +} + +/// Modular random number generation support. +#[cfg(feature = "rand_core")] +pub trait RandomMod: Sized + Zero { + /// Generate a cryptographically secure random number which is less than + /// a given `modulus`. + /// + /// This function uses rejection sampling, a method which produces an + /// unbiased distribution of in-range values provided the underlying + /// CSRNG is unbiased, but runs in variable-time. + /// + /// The variable-time nature of the algorithm should not pose a security + /// issue so long as the underlying random number generator is truly a + /// CSRNG, where previous outputs are unrelated to subsequent + /// outputs and do not reveal information about the RNG's internal state. + fn random_mod(rng: &mut impl CryptoRngCore, modulus: &NonZero) -> Self; +} + +/// Compute `self + rhs mod p`. +pub trait AddMod { + /// Output type. + type Output; + + /// Compute `self + rhs mod p`. + /// + /// Assumes `self` and `rhs` are `< p`. + fn add_mod(&self, rhs: &Rhs, p: &Self) -> Self::Output; +} + +/// Compute `self - rhs mod p`. +pub trait SubMod { + /// Output type. + type Output; + + /// Compute `self - rhs mod p`. + /// + /// Assumes `self` and `rhs` are `< p`. + fn sub_mod(&self, rhs: &Rhs, p: &Self) -> Self::Output; +} + +/// Compute `-self mod p`. +pub trait NegMod { + /// Output type. + type Output; + + /// Compute `-self mod p`. + #[must_use] + fn neg_mod(&self, p: &Self) -> Self::Output; +} + +/// Compute `self * rhs mod p`. +/// +/// Requires `p_inv = -(p^{-1} mod 2^{BITS}) mod 2^{BITS}` to be provided for efficiency. +pub trait MulMod { + /// Output type. + type Output; + + /// Compute `self * rhs mod p`. + /// + /// Requires `p_inv = -(p^{-1} mod 2^{BITS}) mod 2^{BITS}` to be provided for efficiency. + fn mul_mod(&self, rhs: &Rhs, p: &Self, p_inv: Limb) -> Self::Output; +} + +/// Checked addition. +pub trait CheckedAdd: Sized { + /// Output type. + type Output; + + /// Perform checked subtraction, returning a [`CtOption`] which `is_some` + /// only if the operation did not overflow. + fn checked_add(&self, rhs: Rhs) -> CtOption; +} + +/// Checked multiplication. +pub trait CheckedMul: Sized { + /// Output type. + type Output; + + /// Perform checked multiplication, returning a [`CtOption`] which `is_some` + /// only if the operation did not overflow. + fn checked_mul(&self, rhs: Rhs) -> CtOption; +} + +/// Checked subtraction. +pub trait CheckedSub: Sized { + /// Output type. + type Output; + + /// Perform checked subtraction, returning a [`CtOption`] which `is_some` + /// only if the operation did not underflow. + fn checked_sub(&self, rhs: Rhs) -> CtOption; +} + +/// Concatenate two numbers into a "wide" double-width value, using the `lo` +/// value as the least significant value. +pub trait Concat: ConcatMixed { + /// Concatenated output: twice the width of `Self`. + type Output; + + /// Concatenate the two halves, with `self` as most significant and `lo` + /// as the least significant. + fn concat(&self, lo: &Self) -> Self::Output { + self.concat_mixed(lo) + } +} + +/// Concatenate two numbers into a "wide" combined-width value, using the `lo` +/// value as the least significant value. +pub trait ConcatMixed { + /// Concatenated output: combination of `Lo` and `Self`. + type MixedOutput; + + /// Concatenate the two values, with `self` as most significant and `lo` + /// as the least significant. + fn concat_mixed(&self, lo: &Lo) -> Self::MixedOutput; +} + +/// Split a number in half, returning the most significant half followed by +/// the least significant. +pub trait Split: SplitMixed { + /// Split output: high/low components of the value. + type Output; + + /// Split this number in half, returning its high and low components + /// respectively. + fn split(&self) -> (Self::Output, Self::Output) { + self.split_mixed() + } +} + +/// Split a number into parts, returning the most significant part followed by +/// the least significant. +pub trait SplitMixed { + /// Split this number into parts, returning its high and low components + /// respectively. + fn split_mixed(&self) -> (Hi, Lo); +} + +/// Integers whose representation takes a bounded amount of space. +pub trait Bounded { + /// Size of this integer in bits. + const BITS: usize; + + /// Size of this integer in bytes. + const BYTES: usize; +} + +/// Encoding support. +pub trait Encoding: Sized { + /// Byte array representation. + type Repr: AsRef<[u8]> + AsMut<[u8]> + Copy + Clone + Sized; + + /// Decode from big endian bytes. + fn from_be_bytes(bytes: Self::Repr) -> Self; + + /// Decode from little endian bytes. + fn from_le_bytes(bytes: Self::Repr) -> Self; + + /// Encode to big endian bytes. + fn to_be_bytes(&self) -> Self::Repr; + + /// Encode to little endian bytes. + fn to_le_bytes(&self) -> Self::Repr; +} + +/// Support for optimized squaring +pub trait Square: Sized +where + for<'a> &'a Self: core::ops::Mul<&'a Self, Output = Self>, +{ + /// Computes the same as `self.mul(self)`, but may be more efficient. + fn square(&self) -> Self { + self * self + } +} + +/// Constant-time exponentiation. +pub trait Pow { + /// Raises to the `exponent` power. + fn pow(&self, exponent: &Exponent) -> Self; +} + +impl, Exponent: Bounded> Pow for T { + fn pow(&self, exponent: &Exponent) -> Self { + self.pow_bounded_exp(exponent, Exponent::BITS) + } +} + +/// Constant-time exponentiation with exponent of a bounded bit size. +pub trait PowBoundedExp { + /// Raises to the `exponent` power, + /// with `exponent_bits` representing the number of (least significant) bits + /// to take into account for the exponent. + /// + /// NOTE: `exponent_bits` may be leaked in the time pattern. + fn pow_bounded_exp(&self, exponent: &Exponent, exponent_bits: usize) -> Self; +} + +/// Performs modular multi-exponentiation using Montgomery's ladder. +/// +/// See: Straus, E. G. Problems and solutions: Addition chains of vectors. American Mathematical Monthly 71 (1964), 806–808. +pub trait MultiExponentiate: Pow + Sized +where + BasesAndExponents: AsRef<[(Self, Exponent)]> + ?Sized, +{ + /// Calculates `x1 ^ k1 * ... * xn ^ kn`. + fn multi_exponentiate(bases_and_exponents: &BasesAndExponents) -> Self; +} + +impl MultiExponentiate for T +where + T: MultiExponentiateBoundedExp, + Exponent: Bounded, + BasesAndExponents: AsRef<[(Self, Exponent)]> + ?Sized, +{ + fn multi_exponentiate(bases_and_exponents: &BasesAndExponents) -> Self { + Self::multi_exponentiate_bounded_exp(bases_and_exponents, Exponent::BITS) + } +} + +/// Performs modular multi-exponentiation using Montgomery's ladder. +/// `exponent_bits` represents the number of bits to take into account for the exponent. +/// +/// See: Straus, E. G. Problems and solutions: Addition chains of vectors. American Mathematical Monthly 71 (1964), 806–808. +/// +/// NOTE: this value is leaked in the time pattern. +pub trait MultiExponentiateBoundedExp: Pow + Sized +where + BasesAndExponents: AsRef<[(Self, Exponent)]> + ?Sized, +{ + /// Calculates `x1 ^ k1 * ... * xn ^ kn`. + fn multi_exponentiate_bounded_exp( + bases_and_exponents: &BasesAndExponents, + exponent_bits: usize, + ) -> Self; +} + +/// Constant-time inversion. +pub trait Invert: Sized { + /// Output of the inversion. + type Output; + + /// Computes the inverse. + fn invert(&self) -> Self::Output; +} diff --git a/src/rust/vendor/crypto-bigint/src/uint.rs b/src/rust/vendor/crypto-bigint/src/uint.rs new file mode 100644 index 000000000..a64449674 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint.rs @@ -0,0 +1,491 @@ +//! Stack-allocated big unsigned integers. + +#![allow(clippy::needless_range_loop, clippy::many_single_char_names)] + +#[macro_use] +mod macros; + +mod add; +mod add_mod; +mod bit_and; +mod bit_not; +mod bit_or; +mod bit_xor; +mod bits; +mod cmp; +mod concat; +mod div; +pub(crate) mod div_limb; +mod encoding; +mod from; +mod inv_mod; +mod mul; +mod mul_mod; +mod neg; +mod neg_mod; +mod resize; +mod shl; +mod shr; +mod split; +mod sqrt; +mod sub; +mod sub_mod; + +/// Implements modular arithmetic for constant moduli. +pub mod modular; + +#[cfg(feature = "generic-array")] +mod array; + +#[cfg(feature = "rand_core")] +mod rand; + +use crate::{Bounded, Encoding, Integer, Limb, Word, Zero}; +use core::fmt; +use subtle::{Choice, ConditionallySelectable}; + +#[cfg(feature = "serde")] +use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[cfg(feature = "zeroize")] +use zeroize::DefaultIsZeroes; + +/// Stack-allocated big unsigned integer. +/// +/// Generic over the given number of `LIMBS` +/// +/// # Encoding support +/// This type supports many different types of encodings, either via the +/// [`Encoding`][`crate::Encoding`] trait or various `const fn` decoding and +/// encoding functions that can be used with [`Uint`] constants. +/// +/// Optional crate features for encoding (off-by-default): +/// - `generic-array`: enables [`ArrayEncoding`][`crate::ArrayEncoding`] trait which can be used to +/// [`Uint`] as `GenericArray` and a [`ArrayDecoding`][`crate::ArrayDecoding`] trait which +/// can be used to `GenericArray` as [`Uint`]. +/// - `rlp`: support for [Recursive Length Prefix (RLP)][RLP] encoding. +/// +/// [RLP]: https://eth.wiki/fundamentals/rlp +// TODO(tarcieri): make generic around a specified number of bits. +// Our PartialEq impl only differs from the default one by being constant-time, so this is safe +#[allow(clippy::derived_hash_with_manual_eq)] +#[derive(Copy, Clone, Hash)] +pub struct Uint { + /// Inner limb array. Stored from least significant to most significant. + limbs: [Limb; LIMBS], +} + +impl Uint { + /// The value `0`. + pub const ZERO: Self = Self::from_u8(0); + + /// The value `1`. + pub const ONE: Self = Self::from_u8(1); + + /// Maximum value this [`Uint`] can express. + pub const MAX: Self = Self { + limbs: [Limb::MAX; LIMBS], + }; + + /// Total size of the represented integer in bits. + pub const BITS: usize = LIMBS * Limb::BITS; + + /// Bit size of `BITS`. + // Note: assumes the type of `BITS` is `usize`. Any way to assert that? + pub(crate) const LOG2_BITS: usize = (usize::BITS - Self::BITS.leading_zeros()) as usize; + + /// Total size of the represented integer in bytes. + pub const BYTES: usize = LIMBS * Limb::BYTES; + + /// The number of limbs used on this platform. + pub const LIMBS: usize = LIMBS; + + /// Const-friendly [`Uint`] constructor. + pub const fn new(limbs: [Limb; LIMBS]) -> Self { + Self { limbs } + } + + /// Create a [`Uint`] from an array of [`Word`]s (i.e. word-sized unsigned + /// integers). + #[inline] + pub const fn from_words(arr: [Word; LIMBS]) -> Self { + let mut limbs = [Limb::ZERO; LIMBS]; + let mut i = 0; + + while i < LIMBS { + limbs[i] = Limb(arr[i]); + i += 1; + } + + Self { limbs } + } + + /// Create an array of [`Word`]s (i.e. word-sized unsigned integers) from + /// a [`Uint`]. + #[inline] + pub const fn to_words(self) -> [Word; LIMBS] { + let mut arr = [0; LIMBS]; + let mut i = 0; + + while i < LIMBS { + arr[i] = self.limbs[i].0; + i += 1; + } + + arr + } + + /// Borrow the inner limbs as an array of [`Word`]s. + pub const fn as_words(&self) -> &[Word; LIMBS] { + // SAFETY: `Limb` is a `repr(transparent)` newtype for `Word` + #[allow(trivial_casts, unsafe_code)] + unsafe { + &*((&self.limbs as *const _) as *const [Word; LIMBS]) + } + } + + /// Borrow the inner limbs as a mutable array of [`Word`]s. + pub fn as_words_mut(&mut self) -> &mut [Word; LIMBS] { + // SAFETY: `Limb` is a `repr(transparent)` newtype for `Word` + #[allow(trivial_casts, unsafe_code)] + unsafe { + &mut *((&mut self.limbs as *mut _) as *mut [Word; LIMBS]) + } + } + + /// Borrow the limbs of this [`Uint`]. + pub const fn as_limbs(&self) -> &[Limb; LIMBS] { + &self.limbs + } + + /// Borrow the limbs of this [`Uint`] mutably. + pub fn as_limbs_mut(&mut self) -> &mut [Limb; LIMBS] { + &mut self.limbs + } + + /// Convert this [`Uint`] into its inner limbs. + pub const fn to_limbs(self) -> [Limb; LIMBS] { + self.limbs + } +} + +impl AsRef<[Word; LIMBS]> for Uint { + fn as_ref(&self) -> &[Word; LIMBS] { + self.as_words() + } +} + +impl AsMut<[Word; LIMBS]> for Uint { + fn as_mut(&mut self) -> &mut [Word; LIMBS] { + self.as_words_mut() + } +} + +impl AsRef<[Limb]> for Uint { + fn as_ref(&self) -> &[Limb] { + self.as_limbs() + } +} + +impl AsMut<[Limb]> for Uint { + fn as_mut(&mut self) -> &mut [Limb] { + self.as_limbs_mut() + } +} + +impl ConditionallySelectable for Uint { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + let mut limbs = [Limb::ZERO; LIMBS]; + + for i in 0..LIMBS { + limbs[i] = Limb::conditional_select(&a.limbs[i], &b.limbs[i], choice); + } + + Self { limbs } + } +} + +impl Default for Uint { + fn default() -> Self { + Self::ZERO + } +} + +impl Integer for Uint { + const ONE: Self = Self::ONE; + const MAX: Self = Self::MAX; + const BITS: usize = Self::BITS; + const BYTES: usize = Self::BYTES; + const LIMBS: usize = Self::LIMBS; + + fn is_odd(&self) -> Choice { + self.limbs + .first() + .map(|limb| limb.is_odd()) + .unwrap_or_else(|| Choice::from(0)) + } +} + +impl Zero for Uint { + const ZERO: Self = Self::ZERO; +} + +impl Bounded for Uint { + const BITS: usize = Self::BITS; + const BYTES: usize = Self::BYTES; +} + +impl fmt::Debug for Uint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Uint(0x{self:X})") + } +} + +impl fmt::Display for Uint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::UpperHex::fmt(self, f) + } +} + +impl fmt::LowerHex for Uint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for limb in self.limbs.iter().rev() { + fmt::LowerHex::fmt(limb, f)?; + } + Ok(()) + } +} + +impl fmt::UpperHex for Uint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for limb in self.limbs.iter().rev() { + fmt::UpperHex::fmt(limb, f)?; + } + Ok(()) + } +} + +#[cfg(feature = "serde")] +impl<'de, const LIMBS: usize> Deserialize<'de> for Uint +where + Uint: Encoding, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let mut buffer = Self::ZERO.to_le_bytes(); + serdect::array::deserialize_hex_or_bin(buffer.as_mut(), deserializer)?; + + Ok(Self::from_le_bytes(buffer)) + } +} + +#[cfg(feature = "serde")] +impl Serialize for Uint +where + Uint: Encoding, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serdect::array::serialize_hex_lower_or_bin(&Encoding::to_le_bytes(self), serializer) + } +} + +#[cfg(feature = "zeroize")] +impl DefaultIsZeroes for Uint {} + +// TODO(tarcieri): use `generic_const_exprs` when stable to make generic around bits. +impl_uint_aliases! { + (U64, 64, "64-bit"), + (U128, 128, "128-bit"), + (U192, 192, "192-bit"), + (U256, 256, "256-bit"), + (U320, 320, "320-bit"), + (U384, 384, "384-bit"), + (U448, 448, "448-bit"), + (U512, 512, "512-bit"), + (U576, 576, "576-bit"), + (U640, 640, "640-bit"), + (U704, 704, "704-bit"), + (U768, 768, "768-bit"), + (U832, 832, "832-bit"), + (U896, 896, "896-bit"), + (U960, 960, "960-bit"), + (U1024, 1024, "1024-bit"), + (U1280, 1280, "1280-bit"), + (U1536, 1536, "1536-bit"), + (U1792, 1792, "1792-bit"), + (U2048, 2048, "2048-bit"), + (U3072, 3072, "3072-bit"), + (U3584, 3584, "3584-bit"), + (U4096, 4096, "4096-bit"), + (U4224, 4224, "4224-bit"), + (U4352, 4352, "4352-bit"), + (U6144, 6144, "6144-bit"), + (U8192, 8192, "8192-bit"), + (U16384, 16384, "16384-bit"), + (U32768, 32768, "32768-bit") +} + +#[cfg(target_pointer_width = "32")] +impl_uint_aliases! { + (U224, 224, "224-bit"), // For NIST P-224 + (U544, 544, "544-bit") // For NIST P-521 +} + +#[cfg(target_pointer_width = "32")] +impl_uint_concat_split_even! { + U64, +} + +// Implement concat and split for double-width Uint sizes: these should be +// multiples of 128 bits. +impl_uint_concat_split_even! { + U128, + U256, + U384, + U512, + U640, + U768, + U896, + U1024, + U1280, + U1536, + U1792, + U2048, + U3072, + U3584, + U4096, + U4224, + U4352, + U6144, + U8192, + U16384, +} + +// Implement mixed concat and split for combinations not implemented by +// impl_uint_concat_split_even. The numbers represent the size of each +// component Uint in multiple of 64 bits. For example, +// (U256, [1, 3]) will allow splitting U256 into (U64, U192) as well as +// (U192, U64), while the (U128, U128) combination is already covered. +impl_uint_concat_split_mixed! { + (U192, [1, 2]), + (U256, [1, 3]), + (U320, [1, 2, 3, 4]), + (U384, [1, 2, 4, 5]), + (U448, [1, 2, 3, 4, 5, 6]), + (U512, [1, 2, 3, 5, 6, 7]), + (U576, [1, 2, 3, 4, 5, 6, 7, 8]), + (U640, [1, 2, 3, 4, 6, 7, 8, 9]), + (U704, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), + (U768, [1, 2, 3, 4, 5, 7, 8, 9, 10, 11]), + (U832, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), + (U896, [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13]), + (U960, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]), + (U1024, [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15]), +} + +#[cfg(feature = "extra-sizes")] +mod extra_sizes; +#[cfg(feature = "extra-sizes")] +pub use extra_sizes::*; + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +mod tests { + use crate::{Encoding, U128}; + use subtle::ConditionallySelectable; + + #[cfg(feature = "alloc")] + use alloc::format; + + #[cfg(feature = "serde")] + use crate::U64; + + #[cfg(feature = "alloc")] + #[test] + fn debug() { + let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD"; + let n = U128::from_be_hex(hex); + + assert_eq!( + format!("{:?}", n), + "Uint(0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD)" + ); + } + + #[cfg(feature = "alloc")] + #[test] + fn display() { + let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD"; + let n = U128::from_be_hex(hex); + + use alloc::string::ToString; + assert_eq!(hex, n.to_string()); + + let hex = "AAAAAAAABBBBBBBB0000000000000000"; + let n = U128::from_be_hex(hex); + assert_eq!(hex, n.to_string()); + + let hex = "AAAAAAAABBBBBBBB00000000DDDDDDDD"; + let n = U128::from_be_hex(hex); + assert_eq!(hex, n.to_string()); + + let hex = "AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD"; + let n = U128::from_be_hex(hex); + assert_eq!(hex, n.to_string()); + } + + #[test] + fn from_bytes() { + let a = U128::from_be_hex("AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD"); + + let be_bytes = a.to_be_bytes(); + let le_bytes = a.to_le_bytes(); + for i in 0..16 { + assert_eq!(le_bytes[i], be_bytes[15 - i]); + } + + let a_from_be = U128::from_be_bytes(be_bytes); + let a_from_le = U128::from_le_bytes(le_bytes); + assert_eq!(a_from_be, a_from_le); + assert_eq!(a_from_be, a); + } + + #[test] + fn conditional_select() { + let a = U128::from_be_hex("00002222444466668888AAAACCCCEEEE"); + let b = U128::from_be_hex("11113333555577779999BBBBDDDDFFFF"); + + let select_0 = U128::conditional_select(&a, &b, 0.into()); + assert_eq!(a, select_0); + + let select_1 = U128::conditional_select(&a, &b, 1.into()); + assert_eq!(b, select_1); + } + + #[cfg(feature = "serde")] + #[test] + fn serde() { + const TEST: U64 = U64::from_u64(0x0011223344556677); + + let serialized = bincode::serialize(&TEST).unwrap(); + let deserialized: U64 = bincode::deserialize(&serialized).unwrap(); + + assert_eq!(TEST, deserialized); + } + + #[cfg(feature = "serde")] + #[test] + fn serde_owned() { + const TEST: U64 = U64::from_u64(0x0011223344556677); + + let serialized = bincode::serialize(&TEST).unwrap(); + let deserialized: U64 = bincode::deserialize_from(serialized.as_slice()).unwrap(); + + assert_eq!(TEST, deserialized); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/add.rs b/src/rust/vendor/crypto-bigint/src/uint/add.rs new file mode 100644 index 000000000..e4f7bfa42 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/add.rs @@ -0,0 +1,206 @@ +//! [`Uint`] addition operations. + +use crate::{Checked, CheckedAdd, CtChoice, Limb, Uint, Wrapping, Zero}; +use core::ops::{Add, AddAssign}; +use subtle::CtOption; + +impl Uint { + /// Computes `a + b + carry`, returning the result along with the new carry. + #[inline(always)] + pub const fn adc(&self, rhs: &Self, mut carry: Limb) -> (Self, Limb) { + let mut limbs = [Limb::ZERO; LIMBS]; + let mut i = 0; + + while i < LIMBS { + let (w, c) = self.limbs[i].adc(rhs.limbs[i], carry); + limbs[i] = w; + carry = c; + i += 1; + } + + (Self { limbs }, carry) + } + + /// Perform saturating addition, returning `MAX` on overflow. + pub const fn saturating_add(&self, rhs: &Self) -> Self { + let (res, overflow) = self.adc(rhs, Limb::ZERO); + Self::ct_select(&res, &Self::MAX, CtChoice::from_lsb(overflow.0)) + } + + /// Perform wrapping addition, discarding overflow. + pub const fn wrapping_add(&self, rhs: &Self) -> Self { + self.adc(rhs, Limb::ZERO).0 + } + + /// Perform wrapping addition, returning the truthy value as the second element of the tuple + /// if an overflow has occurred. + pub(crate) const fn conditional_wrapping_add( + &self, + rhs: &Self, + choice: CtChoice, + ) -> (Self, CtChoice) { + let actual_rhs = Uint::ct_select(&Uint::ZERO, rhs, choice); + let (sum, carry) = self.adc(&actual_rhs, Limb::ZERO); + (sum, CtChoice::from_lsb(carry.0)) + } +} + +impl CheckedAdd<&Uint> for Uint { + type Output = Self; + + fn checked_add(&self, rhs: &Self) -> CtOption { + let (result, carry) = self.adc(rhs, Limb::ZERO); + CtOption::new(result, carry.is_zero()) + } +} + +impl Add for Wrapping> { + type Output = Self; + + fn add(self, rhs: Self) -> Wrapping> { + Wrapping(self.0.wrapping_add(&rhs.0)) + } +} + +impl Add<&Wrapping>> for Wrapping> { + type Output = Wrapping>; + + fn add(self, rhs: &Wrapping>) -> Wrapping> { + Wrapping(self.0.wrapping_add(&rhs.0)) + } +} + +impl Add>> for &Wrapping> { + type Output = Wrapping>; + + fn add(self, rhs: Wrapping>) -> Wrapping> { + Wrapping(self.0.wrapping_add(&rhs.0)) + } +} + +impl Add<&Wrapping>> for &Wrapping> { + type Output = Wrapping>; + + fn add(self, rhs: &Wrapping>) -> Wrapping> { + Wrapping(self.0.wrapping_add(&rhs.0)) + } +} + +impl AddAssign for Wrapping> { + fn add_assign(&mut self, other: Self) { + *self = *self + other; + } +} + +impl AddAssign<&Wrapping>> for Wrapping> { + fn add_assign(&mut self, other: &Self) { + *self = *self + other; + } +} + +impl Add for Checked> { + type Output = Self; + + fn add(self, rhs: Self) -> Checked> { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))), + ) + } +} + +impl Add<&Checked>> for Checked> { + type Output = Checked>; + + fn add(self, rhs: &Checked>) -> Checked> { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))), + ) + } +} + +impl Add>> for &Checked> { + type Output = Checked>; + + fn add(self, rhs: Checked>) -> Checked> { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))), + ) + } +} + +impl Add<&Checked>> for &Checked> { + type Output = Checked>; + + fn add(self, rhs: &Checked>) -> Checked> { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))), + ) + } +} + +impl AddAssign for Checked> { + fn add_assign(&mut self, other: Self) { + *self = *self + other; + } +} + +impl AddAssign<&Checked>> for Checked> { + fn add_assign(&mut self, other: &Self) { + *self = *self + other; + } +} + +#[cfg(test)] +mod tests { + use crate::{CheckedAdd, Limb, U128}; + + #[test] + fn adc_no_carry() { + let (res, carry) = U128::ZERO.adc(&U128::ONE, Limb::ZERO); + assert_eq!(res, U128::ONE); + assert_eq!(carry, Limb::ZERO); + } + + #[test] + fn adc_with_carry() { + let (res, carry) = U128::MAX.adc(&U128::ONE, Limb::ZERO); + assert_eq!(res, U128::ZERO); + assert_eq!(carry, Limb::ONE); + } + + #[test] + fn saturating_add_no_carry() { + assert_eq!(U128::ZERO.saturating_add(&U128::ONE), U128::ONE); + } + + #[test] + fn saturating_add_with_carry() { + assert_eq!(U128::MAX.saturating_add(&U128::ONE), U128::MAX); + } + + #[test] + fn wrapping_add_no_carry() { + assert_eq!(U128::ZERO.wrapping_add(&U128::ONE), U128::ONE); + } + + #[test] + fn wrapping_add_with_carry() { + assert_eq!(U128::MAX.wrapping_add(&U128::ONE), U128::ZERO); + } + + #[test] + fn checked_add_ok() { + let result = U128::ZERO.checked_add(&U128::ONE); + assert_eq!(result.unwrap(), U128::ONE); + } + + #[test] + fn checked_add_overflow() { + let result = U128::MAX.checked_add(&U128::ONE); + assert!(!bool::from(result.is_some())); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/add_mod.rs b/src/rust/vendor/crypto-bigint/src/uint/add_mod.rs new file mode 100644 index 000000000..091ba4634 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/add_mod.rs @@ -0,0 +1,128 @@ +//! [`Uint`] addition modulus operations. + +use crate::{AddMod, Limb, Uint}; + +impl Uint { + /// Computes `self + rhs mod p`. + /// + /// Assumes `self + rhs` as unbounded integer is `< 2p`. + pub const fn add_mod(&self, rhs: &Uint, p: &Uint) -> Uint { + let (w, carry) = self.adc(rhs, Limb::ZERO); + + // Attempt to subtract the modulus, to ensure the result is in the field. + let (w, borrow) = w.sbb(p, Limb::ZERO); + let (_, borrow) = carry.sbb(Limb::ZERO, borrow); + + // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise + // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the + // modulus. + let mask = Uint::from_words([borrow.0; LIMBS]); + + w.wrapping_add(&p.bitand(&mask)) + } + + /// Computes `self + rhs mod p` for the special modulus + /// `p = MAX+1-c` where `c` is small enough to fit in a single [`Limb`]. + /// + /// Assumes `self + rhs` as unbounded integer is `< 2p`. + pub const fn add_mod_special(&self, rhs: &Self, c: Limb) -> Self { + // `Uint::adc` also works with a carry greater than 1. + let (out, carry) = self.adc(rhs, c); + + // If overflow occurred, then above addition of `c` already accounts + // for the overflow. Otherwise, we need to subtract `c` again, which + // in that case cannot underflow. + let l = carry.0.wrapping_sub(1) & c.0; + out.wrapping_sub(&Uint::from_word(l)) + } +} + +impl AddMod for Uint { + type Output = Self; + + fn add_mod(&self, rhs: &Self, p: &Self) -> Self { + debug_assert!(self < p); + debug_assert!(rhs < p); + self.add_mod(rhs, p) + } +} + +#[cfg(all(test, feature = "rand"))] +mod tests { + use crate::{Limb, NonZero, Random, RandomMod, Uint, U256}; + use rand_core::SeedableRng; + + // TODO(tarcieri): additional tests + proptests + + #[test] + fn add_mod_nist_p256() { + let a = + U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); + let b = + U256::from_be_hex("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"); + let n = + U256::from_be_hex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"); + + let actual = a.add_mod(&b, &n); + let expected = + U256::from_be_hex("1a2472fde50286541d97ca6a3592dd75beb9c9646e40c511b82496cfc3926956"); + + assert_eq!(expected, actual); + } + + macro_rules! test_add_mod_special { + ($size:expr, $test_name:ident) => { + #[test] + fn $test_name() { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); + let moduli = [ + NonZero::::random(&mut rng), + NonZero::::random(&mut rng), + ]; + + for special in &moduli { + let p = &NonZero::new(Uint::ZERO.wrapping_sub(&Uint::from_word(special.0))) + .unwrap(); + + let minus_one = p.wrapping_sub(&Uint::ONE); + + let base_cases = [ + (Uint::ZERO, Uint::ZERO, Uint::ZERO), + (Uint::ONE, Uint::ZERO, Uint::ONE), + (Uint::ZERO, Uint::ONE, Uint::ONE), + (minus_one, Uint::ONE, Uint::ZERO), + (Uint::ONE, minus_one, Uint::ZERO), + ]; + for (a, b, c) in &base_cases { + let x = a.add_mod_special(b, *special.as_ref()); + assert_eq!(*c, x, "{} + {} mod {} = {} != {}", a, b, p, x, c); + } + + for _i in 0..100 { + let a = Uint::<$size>::random_mod(&mut rng, p); + let b = Uint::<$size>::random_mod(&mut rng, p); + + let c = a.add_mod_special(&b, *special.as_ref()); + assert!(c < **p, "not reduced: {} >= {} ", c, p); + + let expected = a.add_mod(&b, p); + assert_eq!(c, expected, "incorrect result"); + } + } + } + }; + } + + test_add_mod_special!(1, add_mod_special_1); + test_add_mod_special!(2, add_mod_special_2); + test_add_mod_special!(3, add_mod_special_3); + test_add_mod_special!(4, add_mod_special_4); + test_add_mod_special!(5, add_mod_special_5); + test_add_mod_special!(6, add_mod_special_6); + test_add_mod_special!(7, add_mod_special_7); + test_add_mod_special!(8, add_mod_special_8); + test_add_mod_special!(9, add_mod_special_9); + test_add_mod_special!(10, add_mod_special_10); + test_add_mod_special!(11, add_mod_special_11); + test_add_mod_special!(12, add_mod_special_12); +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/array.rs b/src/rust/vendor/crypto-bigint/src/uint/array.rs new file mode 100644 index 000000000..1f83dfc19 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/array.rs @@ -0,0 +1,194 @@ +//! `generic-array` integration with `Uint`. +// TODO(tarcieri): completely phase out `generic-array` when const generics are powerful enough + +use crate::{ArrayDecoding, ArrayEncoding, ByteArray}; +use generic_array::{typenum, GenericArray}; + +macro_rules! impl_uint_array_encoding { + ($(($uint:ident, $bytes:path)),+) => { + $( + impl ArrayEncoding for super::$uint { + type ByteSize = $bytes; + + #[inline] + fn from_be_byte_array(bytes: ByteArray) -> Self { + Self::from_be_slice(&bytes) + } + + #[inline] + fn from_le_byte_array(bytes: ByteArray) -> Self { + Self::from_le_slice(&bytes) + } + + #[inline] + fn to_be_byte_array(&self) -> ByteArray { + let mut result = GenericArray::default(); + self.write_be_bytes(&mut result); + result + } + + #[inline] + fn to_le_byte_array(&self) -> ByteArray { + let mut result = GenericArray::default(); + self.write_le_bytes(&mut result); + result + } + } + + impl ArrayDecoding for GenericArray { + type Output = super::$uint; + + fn into_uint_be(self) -> Self::Output { + Self::Output::from_be_byte_array(self) + } + + fn into_uint_le(self) -> Self::Output { + Self::Output::from_le_byte_array(self) + } + } + )+ + }; +} + +// TODO(tarcieri): use `generic_const_exprs` when stable to make generic around bits. +impl_uint_array_encoding! { + (U64, typenum::U8), + (U128, typenum::U16), + (U192, typenum::U24), + (U256, typenum::U32), + (U384, typenum::U48), + (U448, typenum::U56), + (U512, typenum::U64), + (U576, typenum::U72), + (U768, typenum::U96), + (U832, typenum::U104), + (U896, typenum::U112), + (U1024, typenum::U128), + (U1536, typenum::U192), + (U1792, typenum::U224), + (U2048, typenum::U256), + (U3072, typenum::U384), + (U3584, typenum::U448), + (U4096, typenum::U512), + (U6144, typenum::U768), + (U8192, typenum::U1024) +} + +#[cfg(target_pointer_width = "32")] +impl_uint_array_encoding! { + (U224, typenum::U28), // For NIST P-224 + (U544, typenum::U68) // For NIST P-521 +} + +#[cfg(test)] +mod tests { + use crate::{ArrayDecoding, ArrayEncoding, Limb}; + use hex_literal::hex; + + #[cfg(target_pointer_width = "32")] + use crate::U64 as UintEx; + + #[cfg(target_pointer_width = "64")] + use crate::U128 as UintEx; + + /// Byte array that corresponds to `UintEx` + type ByteArray = crate::ByteArray; + + #[test] + #[cfg(target_pointer_width = "32")] + fn from_be_byte_array() { + let n = UintEx::from_be_byte_array(hex!("0011223344556677").into()); + assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn from_be_byte_array() { + let n = UintEx::from_be_byte_array(hex!("00112233445566778899aabbccddeeff").into()); + assert_eq!( + n.as_limbs(), + &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)] + ); + } + + #[test] + #[cfg(target_pointer_width = "32")] + fn from_le_byte_array() { + let n = UintEx::from_le_byte_array(hex!("7766554433221100").into()); + assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn from_le_byte_array() { + let n = UintEx::from_le_byte_array(hex!("ffeeddccbbaa99887766554433221100").into()); + assert_eq!( + n.as_limbs(), + &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)] + ); + } + + #[test] + #[cfg(target_pointer_width = "32")] + fn to_be_byte_array() { + let expected_bytes = ByteArray::from(hex!("0011223344556677")); + let actual_bytes = UintEx::from_be_byte_array(expected_bytes).to_be_byte_array(); + assert_eq!(expected_bytes, actual_bytes); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn to_be_byte_array() { + let expected_bytes = ByteArray::from(hex!("00112233445566778899aabbccddeeff")); + let actual_bytes = UintEx::from_be_byte_array(expected_bytes).to_be_byte_array(); + assert_eq!(expected_bytes, actual_bytes); + } + + #[test] + #[cfg(target_pointer_width = "32")] + fn to_le_byte_array() { + let expected_bytes = ByteArray::from(hex!("7766554433221100")); + let actual_bytes = UintEx::from_le_byte_array(expected_bytes).to_le_byte_array(); + assert_eq!(expected_bytes, actual_bytes); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn to_le_byte_array() { + let expected_bytes = ByteArray::from(hex!("ffeeddccbbaa99887766554433221100")); + let actual_bytes = UintEx::from_le_byte_array(expected_bytes).to_le_byte_array(); + assert_eq!(expected_bytes, actual_bytes); + } + + #[test] + #[cfg(target_pointer_width = "32")] + fn into_uint_be() { + let expected_bytes = ByteArray::from(hex!("0011223344556677")); + let actual_bytes = expected_bytes.into_uint_be().to_be_byte_array(); + assert_eq!(expected_bytes, actual_bytes); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn into_uint_be() { + let expected_bytes = ByteArray::from(hex!("00112233445566778899aabbccddeeff")); + let actual_bytes = expected_bytes.into_uint_be().to_be_byte_array(); + assert_eq!(expected_bytes, actual_bytes); + } + + #[test] + #[cfg(target_pointer_width = "32")] + fn into_uint_le() { + let expected_bytes = ByteArray::from(hex!("7766554433221100")); + let actual_bytes = expected_bytes.into_uint_le().to_le_byte_array(); + assert_eq!(expected_bytes, actual_bytes); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn into_uint_le() { + let expected_bytes = ByteArray::from(hex!("ffeeddccbbaa99887766554433221100")); + let actual_bytes = expected_bytes.into_uint_le().to_le_byte_array(); + assert_eq!(expected_bytes, actual_bytes); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/bit_and.rs b/src/rust/vendor/crypto-bigint/src/uint/bit_and.rs new file mode 100644 index 000000000..18186fb82 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/bit_and.rs @@ -0,0 +1,146 @@ +//! [`Uint`] bitwise and operations. + +use super::Uint; +use crate::{Limb, Wrapping}; +use core::ops::{BitAnd, BitAndAssign}; +use subtle::{Choice, CtOption}; + +impl Uint { + /// Computes bitwise `a & b`. + #[inline(always)] + pub const fn bitand(&self, rhs: &Self) -> Self { + let mut limbs = [Limb::ZERO; LIMBS]; + let mut i = 0; + + while i < LIMBS { + limbs[i] = self.limbs[i].bitand(rhs.limbs[i]); + i += 1; + } + + Self { limbs } + } + + /// Perform wrapping bitwise `AND`. + /// + /// There's no way wrapping could ever happen. + /// This function exists so that all operations are accounted for in the wrapping operations + pub const fn wrapping_and(&self, rhs: &Self) -> Self { + self.bitand(rhs) + } + + /// Perform checked bitwise `AND`, returning a [`CtOption`] which `is_some` always + pub fn checked_and(&self, rhs: &Self) -> CtOption { + let result = self.bitand(rhs); + CtOption::new(result, Choice::from(1)) + } +} + +impl BitAnd for Uint { + type Output = Self; + + fn bitand(self, rhs: Self) -> Uint { + self.bitand(&rhs) + } +} + +impl BitAnd<&Uint> for Uint { + type Output = Uint; + + #[allow(clippy::needless_borrow)] + fn bitand(self, rhs: &Uint) -> Uint { + (&self).bitand(rhs) + } +} + +impl BitAnd> for &Uint { + type Output = Uint; + + fn bitand(self, rhs: Uint) -> Uint { + self.bitand(&rhs) + } +} + +impl BitAnd<&Uint> for &Uint { + type Output = Uint; + + fn bitand(self, rhs: &Uint) -> Uint { + self.bitand(rhs) + } +} + +impl BitAndAssign for Uint { + #[allow(clippy::assign_op_pattern)] + fn bitand_assign(&mut self, other: Self) { + *self = *self & other; + } +} + +impl BitAndAssign<&Uint> for Uint { + #[allow(clippy::assign_op_pattern)] + fn bitand_assign(&mut self, other: &Self) { + *self = *self & other; + } +} + +impl BitAnd for Wrapping> { + type Output = Self; + + fn bitand(self, rhs: Self) -> Wrapping> { + Wrapping(self.0.bitand(&rhs.0)) + } +} + +impl BitAnd<&Wrapping>> for Wrapping> { + type Output = Wrapping>; + + fn bitand(self, rhs: &Wrapping>) -> Wrapping> { + Wrapping(self.0.bitand(&rhs.0)) + } +} + +impl BitAnd>> for &Wrapping> { + type Output = Wrapping>; + + fn bitand(self, rhs: Wrapping>) -> Wrapping> { + Wrapping(self.0.bitand(&rhs.0)) + } +} + +impl BitAnd<&Wrapping>> for &Wrapping> { + type Output = Wrapping>; + + fn bitand(self, rhs: &Wrapping>) -> Wrapping> { + Wrapping(self.0.bitand(&rhs.0)) + } +} + +impl BitAndAssign for Wrapping> { + #[allow(clippy::assign_op_pattern)] + fn bitand_assign(&mut self, other: Self) { + *self = *self & other; + } +} + +impl BitAndAssign<&Wrapping>> for Wrapping> { + #[allow(clippy::assign_op_pattern)] + fn bitand_assign(&mut self, other: &Self) { + *self = *self & other; + } +} + +#[cfg(test)] +mod tests { + use crate::U128; + + #[test] + fn checked_and_ok() { + let result = U128::ZERO.checked_and(&U128::ONE); + assert_eq!(result.unwrap(), U128::ZERO); + } + + #[test] + fn overlapping_and_ok() { + let result = U128::MAX.wrapping_and(&U128::ONE); + assert_eq!(result, U128::ONE); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/bit_not.rs b/src/rust/vendor/crypto-bigint/src/uint/bit_not.rs new file mode 100644 index 000000000..52fea5fd0 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/bit_not.rs @@ -0,0 +1,49 @@ +//! [`Uint`] bitwise not operations. + +use super::Uint; +use crate::{Limb, Wrapping}; +use core::ops::Not; + +impl Uint { + /// Computes bitwise `!a`. + #[inline(always)] + pub const fn not(&self) -> Self { + let mut limbs = [Limb::ZERO; LIMBS]; + let mut i = 0; + + while i < LIMBS { + limbs[i] = self.limbs[i].not(); + i += 1; + } + + Self { limbs } + } +} + +impl Not for Uint { + type Output = Self; + + #[allow(clippy::needless_borrow)] + fn not(self) -> ::Output { + (&self).not() + } +} + +impl Not for Wrapping> { + type Output = Self; + + fn not(self) -> ::Output { + Wrapping(self.0.not()) + } +} + +#[cfg(test)] +mod tests { + use crate::U128; + + #[test] + fn bitnot_ok() { + assert_eq!(U128::ZERO.not(), U128::MAX); + assert_eq!(U128::MAX.not(), U128::ZERO); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/bit_or.rs b/src/rust/vendor/crypto-bigint/src/uint/bit_or.rs new file mode 100644 index 000000000..9a78e366e --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/bit_or.rs @@ -0,0 +1,142 @@ +//! [`Uint`] bitwise or operations. + +use super::Uint; +use crate::{Limb, Wrapping}; +use core::ops::{BitOr, BitOrAssign}; +use subtle::{Choice, CtOption}; + +impl Uint { + /// Computes bitwise `a & b`. + #[inline(always)] + pub const fn bitor(&self, rhs: &Self) -> Self { + let mut limbs = [Limb::ZERO; LIMBS]; + let mut i = 0; + + while i < LIMBS { + limbs[i] = self.limbs[i].bitor(rhs.limbs[i]); + i += 1; + } + + Self { limbs } + } + + /// Perform wrapping bitwise `OR`. + /// + /// There's no way wrapping could ever happen. + /// This function exists so that all operations are accounted for in the wrapping operations + pub const fn wrapping_or(&self, rhs: &Self) -> Self { + self.bitor(rhs) + } + + /// Perform checked bitwise `OR`, returning a [`CtOption`] which `is_some` always + pub fn checked_or(&self, rhs: &Self) -> CtOption { + let result = self.bitor(rhs); + CtOption::new(result, Choice::from(1)) + } +} + +impl BitOr for Uint { + type Output = Self; + + fn bitor(self, rhs: Self) -> Uint { + self.bitor(&rhs) + } +} + +impl BitOr<&Uint> for Uint { + type Output = Uint; + + #[allow(clippy::needless_borrow)] + fn bitor(self, rhs: &Uint) -> Uint { + (&self).bitor(rhs) + } +} + +impl BitOr> for &Uint { + type Output = Uint; + + fn bitor(self, rhs: Uint) -> Uint { + self.bitor(&rhs) + } +} + +impl BitOr<&Uint> for &Uint { + type Output = Uint; + + fn bitor(self, rhs: &Uint) -> Uint { + self.bitor(rhs) + } +} + +impl BitOrAssign for Uint { + fn bitor_assign(&mut self, other: Self) { + *self = *self | other; + } +} + +impl BitOrAssign<&Uint> for Uint { + fn bitor_assign(&mut self, other: &Self) { + *self = *self | other; + } +} + +impl BitOr for Wrapping> { + type Output = Self; + + fn bitor(self, rhs: Self) -> Wrapping> { + Wrapping(self.0.bitor(&rhs.0)) + } +} + +impl BitOr<&Wrapping>> for Wrapping> { + type Output = Wrapping>; + + fn bitor(self, rhs: &Wrapping>) -> Wrapping> { + Wrapping(self.0.bitor(&rhs.0)) + } +} + +impl BitOr>> for &Wrapping> { + type Output = Wrapping>; + + fn bitor(self, rhs: Wrapping>) -> Wrapping> { + Wrapping(self.0.bitor(&rhs.0)) + } +} + +impl BitOr<&Wrapping>> for &Wrapping> { + type Output = Wrapping>; + + fn bitor(self, rhs: &Wrapping>) -> Wrapping> { + Wrapping(self.0.bitor(&rhs.0)) + } +} + +impl BitOrAssign for Wrapping> { + fn bitor_assign(&mut self, other: Self) { + *self = *self | other; + } +} + +impl BitOrAssign<&Wrapping>> for Wrapping> { + fn bitor_assign(&mut self, other: &Self) { + *self = *self | other; + } +} + +#[cfg(test)] +mod tests { + use crate::U128; + + #[test] + fn checked_or_ok() { + let result = U128::ZERO.checked_or(&U128::ONE); + assert_eq!(result.unwrap(), U128::ONE); + } + + #[test] + fn overlapping_or_ok() { + let result = U128::MAX.wrapping_or(&U128::ONE); + assert_eq!(result, U128::MAX); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/bit_xor.rs b/src/rust/vendor/crypto-bigint/src/uint/bit_xor.rs new file mode 100644 index 000000000..91121d234 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/bit_xor.rs @@ -0,0 +1,142 @@ +//! [`Uint`] bitwise xor operations. + +use super::Uint; +use crate::{Limb, Wrapping}; +use core::ops::{BitXor, BitXorAssign}; +use subtle::{Choice, CtOption}; + +impl Uint { + /// Computes bitwise `a ^ b`. + #[inline(always)] + pub const fn bitxor(&self, rhs: &Self) -> Self { + let mut limbs = [Limb::ZERO; LIMBS]; + let mut i = 0; + + while i < LIMBS { + limbs[i] = self.limbs[i].bitxor(rhs.limbs[i]); + i += 1; + } + + Self { limbs } + } + + /// Perform wrapping bitwise `XOR``. + /// + /// There's no way wrapping could ever happen. + /// This function exists so that all operations are accounted for in the wrapping operations + pub const fn wrapping_xor(&self, rhs: &Self) -> Self { + self.bitxor(rhs) + } + + /// Perform checked bitwise `XOR`, returning a [`CtOption`] which `is_some` always + pub fn checked_xor(&self, rhs: &Self) -> CtOption { + let result = self.bitxor(rhs); + CtOption::new(result, Choice::from(1)) + } +} + +impl BitXor for Uint { + type Output = Self; + + fn bitxor(self, rhs: Self) -> Uint { + self.bitxor(&rhs) + } +} + +impl BitXor<&Uint> for Uint { + type Output = Uint; + + #[allow(clippy::needless_borrow)] + fn bitxor(self, rhs: &Uint) -> Uint { + (&self).bitxor(rhs) + } +} + +impl BitXor> for &Uint { + type Output = Uint; + + fn bitxor(self, rhs: Uint) -> Uint { + self.bitxor(&rhs) + } +} + +impl BitXor<&Uint> for &Uint { + type Output = Uint; + + fn bitxor(self, rhs: &Uint) -> Uint { + self.bitxor(rhs) + } +} + +impl BitXorAssign for Uint { + fn bitxor_assign(&mut self, other: Self) { + *self = *self ^ other; + } +} + +impl BitXorAssign<&Uint> for Uint { + fn bitxor_assign(&mut self, other: &Self) { + *self = *self ^ other; + } +} + +impl BitXor for Wrapping> { + type Output = Self; + + fn bitxor(self, rhs: Self) -> Wrapping> { + Wrapping(self.0.bitxor(&rhs.0)) + } +} + +impl BitXor<&Wrapping>> for Wrapping> { + type Output = Wrapping>; + + fn bitxor(self, rhs: &Wrapping>) -> Wrapping> { + Wrapping(self.0.bitxor(&rhs.0)) + } +} + +impl BitXor>> for &Wrapping> { + type Output = Wrapping>; + + fn bitxor(self, rhs: Wrapping>) -> Wrapping> { + Wrapping(self.0.bitxor(&rhs.0)) + } +} + +impl BitXor<&Wrapping>> for &Wrapping> { + type Output = Wrapping>; + + fn bitxor(self, rhs: &Wrapping>) -> Wrapping> { + Wrapping(self.0.bitxor(&rhs.0)) + } +} + +impl BitXorAssign for Wrapping> { + fn bitxor_assign(&mut self, other: Self) { + *self = *self ^ other; + } +} + +impl BitXorAssign<&Wrapping>> for Wrapping> { + fn bitxor_assign(&mut self, other: &Self) { + *self = *self ^ other; + } +} + +#[cfg(test)] +mod tests { + use crate::U128; + + #[test] + fn checked_xor_ok() { + let result = U128::ZERO.checked_xor(&U128::ONE); + assert_eq!(result.unwrap(), U128::ONE); + } + + #[test] + fn overlapping_xor_ok() { + let result = U128::ZERO.wrapping_xor(&U128::ONE); + assert_eq!(result, U128::ONE); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/bits.rs b/src/rust/vendor/crypto-bigint/src/uint/bits.rs new file mode 100644 index 000000000..da514058f --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/bits.rs @@ -0,0 +1,360 @@ +use crate::{CtChoice, Limb, Uint, Word}; + +impl Uint { + /// Returns `true` if the bit at position `index` is set, `false` otherwise. + /// + /// # Remarks + /// This operation is variable time with respect to `index` only. + #[inline(always)] + pub const fn bit_vartime(&self, index: usize) -> bool { + if index >= Self::BITS { + false + } else { + (self.limbs[index / Limb::BITS].0 >> (index % Limb::BITS)) & 1 == 1 + } + } + + /// Calculate the number of bits needed to represent this number. + pub const fn bits_vartime(&self) -> usize { + let mut i = LIMBS - 1; + while i > 0 && self.limbs[i].0 == 0 { + i -= 1; + } + + let limb = self.limbs[i]; + Limb::BITS * (i + 1) - limb.leading_zeros() + } + + /// Calculate the number of leading zeros in the binary representation of this number. + pub const fn leading_zeros(&self) -> usize { + let limbs = self.as_limbs(); + + let mut count: Word = 0; + let mut i = LIMBS; + let mut nonzero_limb_not_encountered = CtChoice::TRUE; + while i > 0 { + i -= 1; + let l = limbs[i]; + let z = l.leading_zeros() as Word; + count += nonzero_limb_not_encountered.if_true(z); + nonzero_limb_not_encountered = + nonzero_limb_not_encountered.and(l.ct_is_nonzero().not()); + } + + count as usize + } + + /// Calculate the number of leading zeros in the binary representation of this number, + /// variable time in `self`. + pub const fn leading_zeros_vartime(&self) -> usize { + let limbs = self.as_limbs(); + + let mut count = 0; + let mut i = LIMBS; + while i > 0 { + i -= 1; + let l = limbs[i]; + let z = l.leading_zeros(); + count += z; + if z != Limb::BITS { + break; + } + } + + count + } + + /// Calculate the number of trailing zeros in the binary representation of this number. + pub const fn trailing_zeros(&self) -> usize { + let limbs = self.as_limbs(); + + let mut count: Word = 0; + let mut i = 0; + let mut nonzero_limb_not_encountered = CtChoice::TRUE; + while i < LIMBS { + let l = limbs[i]; + let z = l.trailing_zeros() as Word; + count += nonzero_limb_not_encountered.if_true(z); + nonzero_limb_not_encountered = + nonzero_limb_not_encountered.and(l.ct_is_nonzero().not()); + i += 1; + } + + count as usize + } + + /// Calculate the number of trailing zeros in the binary representation of this number, + /// variable time in `self`. + pub const fn trailing_zeros_vartime(&self) -> usize { + let limbs = self.as_limbs(); + + let mut count = 0; + let mut i = 0; + while i < LIMBS { + let l = limbs[i]; + let z = l.trailing_zeros(); + count += z; + if z != Limb::BITS { + break; + } + i += 1; + } + + count + } + + /// Calculate the number of trailing ones in the binary representation of this number. + pub const fn trailing_ones(&self) -> usize { + let limbs = self.as_limbs(); + + let mut count: Word = 0; + let mut i = 0; + let mut nonmax_limb_not_encountered = CtChoice::TRUE; + while i < LIMBS { + let l = limbs[i]; + let z = l.trailing_ones() as Word; + count += nonmax_limb_not_encountered.if_true(z); + nonmax_limb_not_encountered = + nonmax_limb_not_encountered.and(Limb::ct_eq(l, Limb::MAX)); + i += 1; + } + + count as usize + } + + /// Calculate the number of trailing ones in the binary representation of this number, + /// variable time in `self`. + pub const fn trailing_ones_vartime(&self) -> usize { + let limbs = self.as_limbs(); + + let mut count = 0; + let mut i = 0; + while i < LIMBS { + let l = limbs[i]; + let z = l.trailing_ones(); + count += z; + if z != Limb::BITS { + break; + } + i += 1; + } + + count + } + + /// Calculate the number of bits needed to represent this number. + pub const fn bits(&self) -> usize { + Self::BITS - self.leading_zeros() + } + + /// Get the value of the bit at position `index`, as a truthy or falsy `CtChoice`. + /// Returns the falsy value for indices out of range. + pub const fn bit(&self, index: usize) -> CtChoice { + let limb_num = index / Limb::BITS; + let index_in_limb = index % Limb::BITS; + let index_mask = 1 << index_in_limb; + + let limbs = self.as_words(); + + let mut result: Word = 0; + let mut i = 0; + while i < LIMBS { + let bit = limbs[i] & index_mask; + let is_right_limb = CtChoice::from_usize_equality(i, limb_num); + result |= is_right_limb.if_true(bit); + i += 1; + } + + CtChoice::from_lsb(result >> index_in_limb) + } + + /// Sets the bit at `index` to 0 or 1 depending on the value of `bit_value`. + pub(crate) const fn set_bit(self, index: usize, bit_value: CtChoice) -> Self { + let mut result = self; + let limb_num = index / Limb::BITS; + let index_in_limb = index % Limb::BITS; + let index_mask = 1 << index_in_limb; + + let mut i = 0; + while i < LIMBS { + let is_right_limb = CtChoice::from_usize_equality(i, limb_num); + let old_limb = result.limbs[i].0; + let new_limb = bit_value.select(old_limb & !index_mask, old_limb | index_mask); + result.limbs[i] = Limb(is_right_limb.select(old_limb, new_limb)); + i += 1; + } + result + } +} + +#[cfg(test)] +mod tests { + use crate::{CtChoice, U256}; + + fn uint_with_bits_at(positions: &[usize]) -> U256 { + let mut result = U256::ZERO; + for pos in positions { + result |= U256::ONE << *pos; + } + result + } + + #[test] + fn bit_vartime() { + let u = uint_with_bits_at(&[16, 48, 112, 127, 255]); + assert!(!u.bit_vartime(0)); + assert!(!u.bit_vartime(1)); + assert!(u.bit_vartime(16)); + assert!(u.bit_vartime(127)); + assert!(u.bit_vartime(255)); + assert!(!u.bit_vartime(256)); + assert!(!u.bit_vartime(260)); + } + + #[test] + fn bit() { + let u = uint_with_bits_at(&[16, 48, 112, 127, 255]); + assert!(!u.bit(0).is_true_vartime()); + assert!(!u.bit(1).is_true_vartime()); + assert!(u.bit(16).is_true_vartime()); + assert!(u.bit(127).is_true_vartime()); + assert!(u.bit(255).is_true_vartime()); + assert!(!u.bit(256).is_true_vartime()); + assert!(!u.bit(260).is_true_vartime()); + } + + #[test] + fn leading_zeros() { + let u = uint_with_bits_at(&[256 - 16, 256 - 79, 256 - 207]); + assert_eq!(u.leading_zeros(), 15); + + let u = uint_with_bits_at(&[256 - 79, 256 - 207]); + assert_eq!(u.leading_zeros(), 78); + + let u = uint_with_bits_at(&[256 - 207]); + assert_eq!(u.leading_zeros(), 206); + + let u = uint_with_bits_at(&[256 - 1, 256 - 75, 256 - 150]); + assert_eq!(u.leading_zeros(), 0); + + let u = U256::ZERO; + assert_eq!(u.leading_zeros(), 256); + } + + #[test] + fn leading_zeros_vartime() { + let u = uint_with_bits_at(&[256 - 16, 256 - 79, 256 - 207]); + assert_eq!(u.leading_zeros_vartime(), 15); + + let u = uint_with_bits_at(&[256 - 79, 256 - 207]); + assert_eq!(u.leading_zeros_vartime(), 78); + + let u = uint_with_bits_at(&[256 - 207]); + assert_eq!(u.leading_zeros_vartime(), 206); + + let u = uint_with_bits_at(&[256 - 1, 256 - 75, 256 - 150]); + assert_eq!(u.leading_zeros_vartime(), 0); + + let u = U256::ZERO; + assert_eq!(u.leading_zeros_vartime(), 256); + } + + #[test] + fn trailing_zeros() { + let u = uint_with_bits_at(&[16, 79, 150]); + assert_eq!(u.trailing_zeros(), 16); + + let u = uint_with_bits_at(&[79, 150]); + assert_eq!(u.trailing_zeros(), 79); + + let u = uint_with_bits_at(&[150, 207]); + assert_eq!(u.trailing_zeros(), 150); + + let u = uint_with_bits_at(&[0, 150, 207]); + assert_eq!(u.trailing_zeros(), 0); + + let u = U256::ZERO; + assert_eq!(u.trailing_zeros(), 256); + } + + #[test] + fn trailing_zeros_vartime() { + let u = uint_with_bits_at(&[16, 79, 150]); + assert_eq!(u.trailing_zeros_vartime(), 16); + + let u = uint_with_bits_at(&[79, 150]); + assert_eq!(u.trailing_zeros_vartime(), 79); + + let u = uint_with_bits_at(&[150, 207]); + assert_eq!(u.trailing_zeros_vartime(), 150); + + let u = uint_with_bits_at(&[0, 150, 207]); + assert_eq!(u.trailing_zeros_vartime(), 0); + + let u = U256::ZERO; + assert_eq!(u.trailing_zeros_vartime(), 256); + } + + #[test] + fn trailing_ones() { + let u = !uint_with_bits_at(&[16, 79, 150]); + assert_eq!(u.trailing_ones(), 16); + + let u = !uint_with_bits_at(&[79, 150]); + assert_eq!(u.trailing_ones(), 79); + + let u = !uint_with_bits_at(&[150, 207]); + assert_eq!(u.trailing_ones(), 150); + + let u = !uint_with_bits_at(&[0, 150, 207]); + assert_eq!(u.trailing_ones(), 0); + + let u = U256::MAX; + assert_eq!(u.trailing_ones(), 256); + } + + #[test] + fn trailing_ones_vartime() { + let u = !uint_with_bits_at(&[16, 79, 150]); + assert_eq!(u.trailing_ones_vartime(), 16); + + let u = !uint_with_bits_at(&[79, 150]); + assert_eq!(u.trailing_ones_vartime(), 79); + + let u = !uint_with_bits_at(&[150, 207]); + assert_eq!(u.trailing_ones_vartime(), 150); + + let u = !uint_with_bits_at(&[0, 150, 207]); + assert_eq!(u.trailing_ones_vartime(), 0); + + let u = U256::MAX; + assert_eq!(u.trailing_ones_vartime(), 256); + } + + #[test] + fn set_bit() { + let u = uint_with_bits_at(&[16, 79, 150]); + assert_eq!( + u.set_bit(127, CtChoice::TRUE), + uint_with_bits_at(&[16, 79, 127, 150]) + ); + + let u = uint_with_bits_at(&[16, 79, 150]); + assert_eq!( + u.set_bit(150, CtChoice::TRUE), + uint_with_bits_at(&[16, 79, 150]) + ); + + let u = uint_with_bits_at(&[16, 79, 150]); + assert_eq!( + u.set_bit(127, CtChoice::FALSE), + uint_with_bits_at(&[16, 79, 150]) + ); + + let u = uint_with_bits_at(&[16, 79, 150]); + assert_eq!( + u.set_bit(150, CtChoice::FALSE), + uint_with_bits_at(&[16, 79]) + ); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/cmp.rs b/src/rust/vendor/crypto-bigint/src/uint/cmp.rs new file mode 100644 index 000000000..b513242e4 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/cmp.rs @@ -0,0 +1,275 @@ +//! [`Uint`] comparisons. +//! +//! By default these are all constant-time and use the `subtle` crate. + +use super::Uint; +use crate::{CtChoice, Limb}; +use core::cmp::Ordering; +use subtle::{Choice, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess}; + +impl Uint { + /// Return `b` if `c` is truthy, otherwise return `a`. + #[inline] + pub(crate) const fn ct_select(a: &Self, b: &Self, c: CtChoice) -> Self { + let mut limbs = [Limb::ZERO; LIMBS]; + + let mut i = 0; + while i < LIMBS { + limbs[i] = Limb::ct_select(a.limbs[i], b.limbs[i], c); + i += 1; + } + + Uint { limbs } + } + + #[inline] + pub(crate) const fn ct_swap(a: &Self, b: &Self, c: CtChoice) -> (Self, Self) { + let new_a = Self::ct_select(a, b, c); + let new_b = Self::ct_select(b, a, c); + + (new_a, new_b) + } + + /// Returns the truthy value if `self`!=0 or the falsy value otherwise. + #[inline] + pub(crate) const fn ct_is_nonzero(&self) -> CtChoice { + let mut b = 0; + let mut i = 0; + while i < LIMBS { + b |= self.limbs[i].0; + i += 1; + } + Limb(b).ct_is_nonzero() + } + + /// Returns the truthy value if `self` is odd or the falsy value otherwise. + pub(crate) const fn ct_is_odd(&self) -> CtChoice { + CtChoice::from_lsb(self.limbs[0].0 & 1) + } + + /// Returns the truthy value if `self == rhs` or the falsy value otherwise. + #[inline] + pub(crate) const fn ct_eq(lhs: &Self, rhs: &Self) -> CtChoice { + let mut acc = 0; + let mut i = 0; + + while i < LIMBS { + acc |= lhs.limbs[i].0 ^ rhs.limbs[i].0; + i += 1; + } + + // acc == 0 if and only if self == rhs + Limb(acc).ct_is_nonzero().not() + } + + /// Returns the truthy value if `self <= rhs` and the falsy value otherwise. + #[inline] + pub(crate) const fn ct_lt(lhs: &Self, rhs: &Self) -> CtChoice { + // We could use the same approach as in Limb::ct_lt(), + // but since we have to use Uint::wrapping_sub(), which calls `sbb()`, + // there are no savings compared to just calling `sbb()` directly. + let (_res, borrow) = lhs.sbb(rhs, Limb::ZERO); + CtChoice::from_mask(borrow.0) + } + + /// Returns the truthy value if `self >= rhs` and the falsy value otherwise. + #[inline] + pub(crate) const fn ct_gt(lhs: &Self, rhs: &Self) -> CtChoice { + let (_res, borrow) = rhs.sbb(lhs, Limb::ZERO); + CtChoice::from_mask(borrow.0) + } + + /// Returns the ordering between `self` and `rhs` as an i8. + /// Values correspond to the Ordering enum: + /// -1 is Less + /// 0 is Equal + /// 1 is Greater + #[inline] + pub(crate) const fn ct_cmp(lhs: &Self, rhs: &Self) -> i8 { + let mut i = 0; + let mut borrow = Limb::ZERO; + let mut diff = Limb::ZERO; + + while i < LIMBS { + let (w, b) = rhs.limbs[i].sbb(lhs.limbs[i], borrow); + diff = diff.bitor(w); + borrow = b; + i += 1; + } + let sgn = ((borrow.0 & 2) as i8) - 1; + (diff.ct_is_nonzero().to_u8() as i8) * sgn + } + + /// Returns the Ordering between `self` and `rhs` in variable time. + pub const fn cmp_vartime(&self, rhs: &Self) -> Ordering { + let mut i = LIMBS - 1; + loop { + let (val, borrow) = self.limbs[i].sbb(rhs.limbs[i], Limb::ZERO); + if val.0 != 0 { + return if borrow.0 != 0 { + Ordering::Less + } else { + Ordering::Greater + }; + } + if i == 0 { + return Ordering::Equal; + } + i -= 1; + } + } +} + +impl ConstantTimeEq for Uint { + #[inline] + fn ct_eq(&self, other: &Self) -> Choice { + Uint::ct_eq(self, other).into() + } +} + +impl ConstantTimeGreater for Uint { + #[inline] + fn ct_gt(&self, other: &Self) -> Choice { + Uint::ct_gt(self, other).into() + } +} + +impl ConstantTimeLess for Uint { + #[inline] + fn ct_lt(&self, other: &Self) -> Choice { + Uint::ct_lt(self, other).into() + } +} + +impl Eq for Uint {} + +impl Ord for Uint { + fn cmp(&self, other: &Self) -> Ordering { + let c = Self::ct_cmp(self, other); + match c { + -1 => Ordering::Less, + 0 => Ordering::Equal, + _ => Ordering::Greater, + } + } +} + +impl PartialOrd for Uint { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl PartialEq for Uint { + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } +} + +#[cfg(test)] +mod tests { + use crate::{Integer, Zero, U128}; + use core::cmp::Ordering; + use subtle::{ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess}; + + #[test] + fn is_zero() { + assert!(bool::from(U128::ZERO.is_zero())); + assert!(!bool::from(U128::ONE.is_zero())); + assert!(!bool::from(U128::MAX.is_zero())); + } + + #[test] + fn is_odd() { + assert!(!bool::from(U128::ZERO.is_odd())); + assert!(bool::from(U128::ONE.is_odd())); + assert!(bool::from(U128::MAX.is_odd())); + } + + #[test] + fn ct_eq() { + let a = U128::ZERO; + let b = U128::MAX; + + assert!(bool::from(a.ct_eq(&a))); + assert!(!bool::from(a.ct_eq(&b))); + assert!(!bool::from(b.ct_eq(&a))); + assert!(bool::from(b.ct_eq(&b))); + } + + #[test] + fn ct_gt() { + let a = U128::ZERO; + let b = U128::ONE; + let c = U128::MAX; + + assert!(bool::from(b.ct_gt(&a))); + assert!(bool::from(c.ct_gt(&a))); + assert!(bool::from(c.ct_gt(&b))); + + assert!(!bool::from(a.ct_gt(&a))); + assert!(!bool::from(b.ct_gt(&b))); + assert!(!bool::from(c.ct_gt(&c))); + + assert!(!bool::from(a.ct_gt(&b))); + assert!(!bool::from(a.ct_gt(&c))); + assert!(!bool::from(b.ct_gt(&c))); + } + + #[test] + fn ct_lt() { + let a = U128::ZERO; + let b = U128::ONE; + let c = U128::MAX; + + assert!(bool::from(a.ct_lt(&b))); + assert!(bool::from(a.ct_lt(&c))); + assert!(bool::from(b.ct_lt(&c))); + + assert!(!bool::from(a.ct_lt(&a))); + assert!(!bool::from(b.ct_lt(&b))); + assert!(!bool::from(c.ct_lt(&c))); + + assert!(!bool::from(b.ct_lt(&a))); + assert!(!bool::from(c.ct_lt(&a))); + assert!(!bool::from(c.ct_lt(&b))); + } + + #[test] + fn cmp() { + let a = U128::ZERO; + let b = U128::ONE; + let c = U128::MAX; + + assert_eq!(a.cmp(&b), Ordering::Less); + assert_eq!(a.cmp(&c), Ordering::Less); + assert_eq!(b.cmp(&c), Ordering::Less); + + assert_eq!(a.cmp(&a), Ordering::Equal); + assert_eq!(b.cmp(&b), Ordering::Equal); + assert_eq!(c.cmp(&c), Ordering::Equal); + + assert_eq!(b.cmp(&a), Ordering::Greater); + assert_eq!(c.cmp(&a), Ordering::Greater); + assert_eq!(c.cmp(&b), Ordering::Greater); + } + + #[test] + fn cmp_vartime() { + let a = U128::ZERO; + let b = U128::ONE; + let c = U128::MAX; + + assert_eq!(a.cmp_vartime(&b), Ordering::Less); + assert_eq!(a.cmp_vartime(&c), Ordering::Less); + assert_eq!(b.cmp_vartime(&c), Ordering::Less); + + assert_eq!(a.cmp_vartime(&a), Ordering::Equal); + assert_eq!(b.cmp_vartime(&b), Ordering::Equal); + assert_eq!(c.cmp_vartime(&c), Ordering::Equal); + + assert_eq!(b.cmp_vartime(&a), Ordering::Greater); + assert_eq!(c.cmp_vartime(&a), Ordering::Greater); + assert_eq!(c.cmp_vartime(&b), Ordering::Greater); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/concat.rs b/src/rust/vendor/crypto-bigint/src/uint/concat.rs new file mode 100644 index 000000000..dde5242a0 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/concat.rs @@ -0,0 +1,70 @@ +use crate::{Concat, ConcatMixed, Limb, Uint}; + +impl Concat for T +where + T: ConcatMixed, +{ + type Output = Self::MixedOutput; +} + +/// Concatenate the two values, with `lo` as least significant and `hi` +/// as the most significant. +#[inline] +pub(crate) const fn concat_mixed( + lo: &Uint, + hi: &Uint, +) -> Uint { + let top = L + H; + let top = if top < O { top } else { O }; + let mut limbs = [Limb::ZERO; O]; + let mut i = 0; + + while i < top { + if i < L { + limbs[i] = lo.limbs[i]; + } else { + limbs[i] = hi.limbs[i - L]; + } + i += 1; + } + + Uint { limbs } +} + +#[cfg(test)] +mod tests { + use crate::{ConcatMixed, U128, U192, U64}; + + #[test] + fn concat() { + let hi = U64::from_u64(0x0011223344556677); + let lo = U64::from_u64(0x8899aabbccddeeff); + assert_eq!( + hi.concat(&lo), + U128::from_be_hex("00112233445566778899aabbccddeeff") + ); + } + + #[test] + fn concat_mixed() { + let a = U64::from_u64(0x0011223344556677); + let b = U128::from_u128(0x8899aabbccddeeff_8899aabbccddeeff); + assert_eq!( + a.concat_mixed(&b), + U192::from_be_hex("00112233445566778899aabbccddeeff8899aabbccddeeff") + ); + assert_eq!( + b.concat_mixed(&a), + U192::from_be_hex("8899aabbccddeeff8899aabbccddeeff0011223344556677") + ); + } + + #[test] + fn convert() { + let res: U128 = U64::ONE.mul_wide(&U64::ONE).into(); + assert_eq!(res, U128::ONE); + + let res: U128 = U64::ONE.square_wide().into(); + assert_eq!(res, U128::ONE); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/div.rs b/src/rust/vendor/crypto-bigint/src/uint/div.rs new file mode 100644 index 000000000..7f5cda732 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/div.rs @@ -0,0 +1,745 @@ +//! [`Uint`] division operations. + +use super::div_limb::{div_rem_limb_with_reciprocal, Reciprocal}; +use crate::{CtChoice, Limb, NonZero, Uint, Word, Wrapping}; +use core::ops::{Div, DivAssign, Rem, RemAssign}; +use subtle::CtOption; + +impl Uint { + /// Computes `self` / `rhs` using a pre-made reciprocal, + /// returns the quotient (q) and remainder (r). + #[inline(always)] + pub const fn ct_div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) { + div_rem_limb_with_reciprocal(self, reciprocal) + } + + /// Computes `self` / `rhs` using a pre-made reciprocal, + /// returns the quotient (q) and remainder (r). + #[inline(always)] + pub fn div_rem_limb_with_reciprocal( + &self, + reciprocal: &CtOption, + ) -> CtOption<(Self, Limb)> { + reciprocal.map(|r| div_rem_limb_with_reciprocal(self, &r)) + } + + /// Computes `self` / `rhs`, returns the quotient (q) and remainder (r). + /// Returns the truthy value as the third element of the tuple if `rhs != 0`, + /// and the falsy value otherwise. + #[inline(always)] + pub(crate) const fn ct_div_rem_limb(&self, rhs: Limb) -> (Self, Limb, CtChoice) { + let (reciprocal, is_some) = Reciprocal::ct_new(rhs); + let (quo, rem) = div_rem_limb_with_reciprocal(self, &reciprocal); + (quo, rem, is_some) + } + + /// Computes `self` / `rhs`, returns the quotient (q) and remainder (r). + #[inline(always)] + pub fn div_rem_limb(&self, rhs: NonZero) -> (Self, Limb) { + // Guaranteed to succeed since `rhs` is nonzero. + let (quo, rem, _is_some) = self.ct_div_rem_limb(*rhs); + (quo, rem) + } + + /// Computes `self` / `rhs`, returns the quotient (q), remainder (r) + /// and the truthy value for is_some or the falsy value for is_none. + /// + /// NOTE: Use only if you need to access const fn. Otherwise use [`Self::div_rem`] because + /// the value for is_some needs to be checked before using `q` and `r`. + /// + /// This is variable only with respect to `rhs`. + /// + /// When used with a fixed `rhs`, this function is constant-time with respect + /// to `self`. + pub(crate) const fn ct_div_rem(&self, rhs: &Self) -> (Self, Self, CtChoice) { + let mb = rhs.bits_vartime(); + let mut bd = Self::BITS - mb; + let mut rem = *self; + let mut quo = Self::ZERO; + let mut c = rhs.shl_vartime(bd); + + loop { + let (mut r, borrow) = rem.sbb(&c, Limb::ZERO); + rem = Self::ct_select(&r, &rem, CtChoice::from_mask(borrow.0)); + r = quo.bitor(&Self::ONE); + quo = Self::ct_select(&r, &quo, CtChoice::from_mask(borrow.0)); + if bd == 0 { + break; + } + bd -= 1; + c = c.shr_vartime(1); + quo = quo.shl_vartime(1); + } + + let is_some = Limb(mb as Word).ct_is_nonzero(); + quo = Self::ct_select(&Self::ZERO, &quo, is_some); + (quo, rem, is_some) + } + + /// Computes `self` % `rhs`, returns the remainder and + /// and the truthy value for is_some or the falsy value for is_none. + /// + /// NOTE: Use only if you need to access const fn. Otherwise use [`Self::rem`]. + /// This is variable only with respect to `rhs`. + /// + /// When used with a fixed `rhs`, this function is constant-time with respect + /// to `self`. + pub const fn const_rem(&self, rhs: &Self) -> (Self, CtChoice) { + let mb = rhs.bits_vartime(); + let mut bd = Self::BITS - mb; + let mut rem = *self; + let mut c = rhs.shl_vartime(bd); + + loop { + let (r, borrow) = rem.sbb(&c, Limb::ZERO); + rem = Self::ct_select(&r, &rem, CtChoice::from_mask(borrow.0)); + if bd == 0 { + break; + } + bd -= 1; + c = c.shr_vartime(1); + } + + let is_some = Limb(mb as Word).ct_is_nonzero(); + (rem, is_some) + } + + /// Computes `self` % `rhs`, returns the remainder and + /// and the truthy value for is_some or the falsy value for is_none. + /// + /// This is variable only with respect to `rhs`. + /// + /// When used with a fixed `rhs`, this function is constant-time with respect + /// to `self`. + pub const fn const_rem_wide(lower_upper: (Self, Self), rhs: &Self) -> (Self, CtChoice) { + let mb = rhs.bits_vartime(); + + // The number of bits to consider is two sets of limbs * BITS - mb (modulus bitcount) + let mut bd = (2 * Self::BITS) - mb; + + // The wide integer to reduce, split into two halves + let (mut lower, mut upper) = lower_upper; + + // Factor of the modulus, split into two halves + let mut c = Self::shl_vartime_wide((*rhs, Uint::ZERO), bd); + + loop { + let (lower_sub, borrow) = lower.sbb(&c.0, Limb::ZERO); + let (upper_sub, borrow) = upper.sbb(&c.1, borrow); + + lower = Self::ct_select(&lower_sub, &lower, CtChoice::from_mask(borrow.0)); + upper = Self::ct_select(&upper_sub, &upper, CtChoice::from_mask(borrow.0)); + if bd == 0 { + break; + } + bd -= 1; + c = Self::shr_vartime_wide(c, 1); + } + + let is_some = Limb(mb as Word).ct_is_nonzero(); + (lower, is_some) + } + + /// Computes `self` % 2^k. Faster than reduce since its a power of 2. + /// Limited to 2^16-1 since Uint doesn't support higher. + pub const fn rem2k(&self, k: usize) -> Self { + let highest = (LIMBS - 1) as u32; + let index = k as u32 / (Limb::BITS as u32); + let le = Limb::ct_le(Limb::from_u32(index), Limb::from_u32(highest)); + let word = Limb::ct_select(Limb::from_u32(highest), Limb::from_u32(index), le).0 as usize; + + let base = k % Limb::BITS; + let mask = (1 << base) - 1; + let mut out = *self; + + let outmask = Limb(out.limbs[word].0 & mask); + + out.limbs[word] = Limb::ct_select(out.limbs[word], outmask, le); + + let mut i = word + 1; + while i < LIMBS { + out.limbs[i] = Limb::ZERO; + i += 1; + } + + out + } + + /// Computes self / rhs, returns the quotient, remainder. + pub fn div_rem(&self, rhs: &NonZero) -> (Self, Self) { + // Since `rhs` is nonzero, this should always hold. + let (q, r, _c) = self.ct_div_rem(rhs); + (q, r) + } + + /// Computes self % rhs, returns the remainder. + pub fn rem(&self, rhs: &NonZero) -> Self { + // Since `rhs` is nonzero, this should always hold. + let (r, _c) = self.const_rem(rhs); + r + } + + /// Wrapped division is just normal division i.e. `self` / `rhs` + /// There’s no way wrapping could ever happen. + /// This function exists, so that all operations are accounted for in the wrapping operations. + /// + /// Panics if `rhs == 0`. + pub const fn wrapping_div(&self, rhs: &Self) -> Self { + let (q, _, c) = self.ct_div_rem(rhs); + assert!(c.is_true_vartime(), "divide by zero"); + q + } + + /// Perform checked division, returning a [`CtOption`] which `is_some` + /// only if the rhs != 0 + pub fn checked_div(&self, rhs: &Self) -> CtOption { + NonZero::new(*rhs).map(|rhs| { + let (q, _r) = self.div_rem(&rhs); + q + }) + } + + /// Wrapped (modular) remainder calculation is just `self` % `rhs`. + /// There’s no way wrapping could ever happen. + /// This function exists, so that all operations are accounted for in the wrapping operations. + /// + /// Panics if `rhs == 0`. + pub const fn wrapping_rem(&self, rhs: &Self) -> Self { + let (r, c) = self.const_rem(rhs); + assert!(c.is_true_vartime(), "modulo zero"); + r + } + + /// Perform checked reduction, returning a [`CtOption`] which `is_some` + /// only if the rhs != 0 + pub fn checked_rem(&self, rhs: &Self) -> CtOption { + NonZero::new(*rhs).map(|rhs| self.rem(&rhs)) + } +} + +// +// Division by a single limb +// + +impl Div<&NonZero> for &Uint { + type Output = Uint; + + fn div(self, rhs: &NonZero) -> Self::Output { + *self / *rhs + } +} + +impl Div<&NonZero> for Uint { + type Output = Uint; + + fn div(self, rhs: &NonZero) -> Self::Output { + self / *rhs + } +} + +impl Div> for &Uint { + type Output = Uint; + + fn div(self, rhs: NonZero) -> Self::Output { + *self / rhs + } +} + +impl Div> for Uint { + type Output = Uint; + + fn div(self, rhs: NonZero) -> Self::Output { + let (q, _, _) = self.ct_div_rem_limb(*rhs); + q + } +} + +impl DivAssign<&NonZero> for Uint { + fn div_assign(&mut self, rhs: &NonZero) { + *self /= *rhs; + } +} + +impl DivAssign> for Uint { + fn div_assign(&mut self, rhs: NonZero) { + *self = *self / rhs; + } +} + +impl Div> for Wrapping> { + type Output = Wrapping>; + + fn div(self, rhs: NonZero) -> Self::Output { + Wrapping(self.0 / rhs) + } +} + +impl Div> for &Wrapping> { + type Output = Wrapping>; + + fn div(self, rhs: NonZero) -> Self::Output { + *self / rhs + } +} + +impl Div<&NonZero> for &Wrapping> { + type Output = Wrapping>; + + fn div(self, rhs: &NonZero) -> Self::Output { + *self / *rhs + } +} + +impl Div<&NonZero> for Wrapping> { + type Output = Wrapping>; + + fn div(self, rhs: &NonZero) -> Self::Output { + self / *rhs + } +} + +impl DivAssign<&NonZero> for Wrapping> { + fn div_assign(&mut self, rhs: &NonZero) { + *self = Wrapping(self.0 / rhs) + } +} + +impl DivAssign> for Wrapping> { + fn div_assign(&mut self, rhs: NonZero) { + *self /= &rhs; + } +} + +impl Rem<&NonZero> for &Uint { + type Output = Limb; + + fn rem(self, rhs: &NonZero) -> Self::Output { + *self % *rhs + } +} + +impl Rem<&NonZero> for Uint { + type Output = Limb; + + fn rem(self, rhs: &NonZero) -> Self::Output { + self % *rhs + } +} + +impl Rem> for &Uint { + type Output = Limb; + + fn rem(self, rhs: NonZero) -> Self::Output { + *self % rhs + } +} + +impl Rem> for Uint { + type Output = Limb; + + fn rem(self, rhs: NonZero) -> Self::Output { + let (_, r, _) = self.ct_div_rem_limb(*rhs); + r + } +} + +impl RemAssign<&NonZero> for Uint { + fn rem_assign(&mut self, rhs: &NonZero) { + *self = (*self % rhs).into(); + } +} + +impl RemAssign> for Uint { + fn rem_assign(&mut self, rhs: NonZero) { + *self %= &rhs; + } +} + +impl Rem> for Wrapping> { + type Output = Wrapping; + + fn rem(self, rhs: NonZero) -> Self::Output { + Wrapping(self.0 % rhs) + } +} + +impl Rem> for &Wrapping> { + type Output = Wrapping; + + fn rem(self, rhs: NonZero) -> Self::Output { + *self % rhs + } +} + +impl Rem<&NonZero> for &Wrapping> { + type Output = Wrapping; + + fn rem(self, rhs: &NonZero) -> Self::Output { + *self % *rhs + } +} + +impl Rem<&NonZero> for Wrapping> { + type Output = Wrapping; + + fn rem(self, rhs: &NonZero) -> Self::Output { + self % *rhs + } +} + +impl RemAssign> for Wrapping> { + fn rem_assign(&mut self, rhs: NonZero) { + *self %= &rhs; + } +} + +impl RemAssign<&NonZero> for Wrapping> { + fn rem_assign(&mut self, rhs: &NonZero) { + *self = Wrapping((self.0 % rhs).into()) + } +} + +// +// Division by an Uint +// + +impl Div<&NonZero>> for &Uint { + type Output = Uint; + + fn div(self, rhs: &NonZero>) -> Self::Output { + *self / *rhs + } +} + +impl Div<&NonZero>> for Uint { + type Output = Uint; + + fn div(self, rhs: &NonZero>) -> Self::Output { + self / *rhs + } +} + +impl Div>> for &Uint { + type Output = Uint; + + fn div(self, rhs: NonZero>) -> Self::Output { + *self / rhs + } +} + +impl Div>> for Uint { + type Output = Uint; + + fn div(self, rhs: NonZero>) -> Self::Output { + let (q, _) = self.div_rem(&rhs); + q + } +} + +impl DivAssign<&NonZero>> for Uint { + fn div_assign(&mut self, rhs: &NonZero>) { + *self /= *rhs + } +} + +impl DivAssign>> for Uint { + fn div_assign(&mut self, rhs: NonZero>) { + *self = *self / rhs; + } +} + +impl Div>> for Wrapping> { + type Output = Wrapping>; + + fn div(self, rhs: NonZero>) -> Self::Output { + Wrapping(self.0 / rhs) + } +} + +impl Div>> for &Wrapping> { + type Output = Wrapping>; + + fn div(self, rhs: NonZero>) -> Self::Output { + *self / rhs + } +} + +impl Div<&NonZero>> for &Wrapping> { + type Output = Wrapping>; + + fn div(self, rhs: &NonZero>) -> Self::Output { + *self / *rhs + } +} + +impl Div<&NonZero>> for Wrapping> { + type Output = Wrapping>; + + fn div(self, rhs: &NonZero>) -> Self::Output { + self / *rhs + } +} + +impl DivAssign<&NonZero>> for Wrapping> { + fn div_assign(&mut self, rhs: &NonZero>) { + *self = Wrapping(self.0 / rhs); + } +} + +impl DivAssign>> for Wrapping> { + fn div_assign(&mut self, rhs: NonZero>) { + *self /= &rhs; + } +} + +impl Rem<&NonZero>> for &Uint { + type Output = Uint; + + fn rem(self, rhs: &NonZero>) -> Self::Output { + *self % *rhs + } +} + +impl Rem<&NonZero>> for Uint { + type Output = Uint; + + fn rem(self, rhs: &NonZero>) -> Self::Output { + self % *rhs + } +} + +impl Rem>> for &Uint { + type Output = Uint; + + fn rem(self, rhs: NonZero>) -> Self::Output { + *self % rhs + } +} + +impl Rem>> for Uint { + type Output = Uint; + + fn rem(self, rhs: NonZero>) -> Self::Output { + Self::rem(&self, &rhs) + } +} + +impl RemAssign<&NonZero>> for Uint { + fn rem_assign(&mut self, rhs: &NonZero>) { + *self %= *rhs + } +} + +impl RemAssign>> for Uint { + fn rem_assign(&mut self, rhs: NonZero>) { + *self = *self % rhs; + } +} + +impl Rem>> for Wrapping> { + type Output = Wrapping>; + + fn rem(self, rhs: NonZero>) -> Self::Output { + Wrapping(self.0 % rhs) + } +} + +impl Rem>> for &Wrapping> { + type Output = Wrapping>; + + fn rem(self, rhs: NonZero>) -> Self::Output { + *self % rhs + } +} + +impl Rem<&NonZero>> for &Wrapping> { + type Output = Wrapping>; + + fn rem(self, rhs: &NonZero>) -> Self::Output { + *self % *rhs + } +} + +impl Rem<&NonZero>> for Wrapping> { + type Output = Wrapping>; + + fn rem(self, rhs: &NonZero>) -> Self::Output { + self % *rhs + } +} + +impl RemAssign>> for Wrapping> { + fn rem_assign(&mut self, rhs: NonZero>) { + *self %= &rhs; + } +} + +impl RemAssign<&NonZero>> for Wrapping> { + fn rem_assign(&mut self, rhs: &NonZero>) { + *self = Wrapping(self.0 % rhs) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{limb::HI_BIT, Limb, U256}; + + #[cfg(feature = "rand")] + use { + crate::{CheckedMul, Random}, + rand_chacha::ChaChaRng, + rand_core::RngCore, + rand_core::SeedableRng, + }; + + #[test] + fn div_word() { + for (n, d, e, ee) in &[ + (200u64, 2u64, 100u64, 0), + (100u64, 25u64, 4u64, 0), + (100u64, 10u64, 10u64, 0), + (1024u64, 8u64, 128u64, 0), + (27u64, 13u64, 2u64, 1u64), + (26u64, 13u64, 2u64, 0u64), + (14u64, 13u64, 1u64, 1u64), + (13u64, 13u64, 1u64, 0u64), + (12u64, 13u64, 0u64, 12u64), + (1u64, 13u64, 0u64, 1u64), + ] { + let lhs = U256::from(*n); + let rhs = U256::from(*d); + let (q, r, is_some) = lhs.ct_div_rem(&rhs); + assert!(is_some.is_true_vartime()); + assert_eq!(U256::from(*e), q); + assert_eq!(U256::from(*ee), r); + } + } + + #[cfg(feature = "rand")] + #[test] + fn div() { + let mut rng = ChaChaRng::from_seed([7u8; 32]); + for _ in 0..25 { + let num = U256::random(&mut rng).shr_vartime(128); + let den = U256::random(&mut rng).shr_vartime(128); + let n = num.checked_mul(&den); + if n.is_some().into() { + let (q, _, is_some) = n.unwrap().ct_div_rem(&den); + assert!(is_some.is_true_vartime()); + assert_eq!(q, num); + } + } + } + + #[test] + fn div_max() { + let mut a = U256::ZERO; + let mut b = U256::ZERO; + b.limbs[b.limbs.len() - 1] = Limb(Word::MAX); + let q = a.wrapping_div(&b); + assert_eq!(q, Uint::ZERO); + a.limbs[a.limbs.len() - 1] = Limb(1 << (HI_BIT - 7)); + b.limbs[b.limbs.len() - 1] = Limb(0x82 << (HI_BIT - 7)); + let q = a.wrapping_div(&b); + assert_eq!(q, Uint::ZERO); + } + + #[test] + fn div_zero() { + let (q, r, is_some) = U256::ONE.ct_div_rem(&U256::ZERO); + assert!(!is_some.is_true_vartime()); + assert_eq!(q, U256::ZERO); + assert_eq!(r, U256::ONE); + } + + #[test] + fn div_one() { + let (q, r, is_some) = U256::from(10u8).ct_div_rem(&U256::ONE); + assert!(is_some.is_true_vartime()); + assert_eq!(q, U256::from(10u8)); + assert_eq!(r, U256::ZERO); + } + + #[test] + fn reduce_one() { + let (r, is_some) = U256::from(10u8).const_rem(&U256::ONE); + assert!(is_some.is_true_vartime()); + assert_eq!(r, U256::ZERO); + } + + #[test] + fn reduce_zero() { + let u = U256::from(10u8); + let (r, is_some) = u.const_rem(&U256::ZERO); + assert!(!is_some.is_true_vartime()); + assert_eq!(r, u); + } + + #[test] + fn reduce_tests() { + let (r, is_some) = U256::from(10u8).const_rem(&U256::from(2u8)); + assert!(is_some.is_true_vartime()); + assert_eq!(r, U256::ZERO); + let (r, is_some) = U256::from(10u8).const_rem(&U256::from(3u8)); + assert!(is_some.is_true_vartime()); + assert_eq!(r, U256::ONE); + let (r, is_some) = U256::from(10u8).const_rem(&U256::from(7u8)); + assert!(is_some.is_true_vartime()); + assert_eq!(r, U256::from(3u8)); + } + + #[test] + fn reduce_tests_wide_zero_padded() { + let (r, is_some) = U256::const_rem_wide((U256::from(10u8), U256::ZERO), &U256::from(2u8)); + assert!(is_some.is_true_vartime()); + assert_eq!(r, U256::ZERO); + let (r, is_some) = U256::const_rem_wide((U256::from(10u8), U256::ZERO), &U256::from(3u8)); + assert!(is_some.is_true_vartime()); + assert_eq!(r, U256::ONE); + let (r, is_some) = U256::const_rem_wide((U256::from(10u8), U256::ZERO), &U256::from(7u8)); + assert!(is_some.is_true_vartime()); + assert_eq!(r, U256::from(3u8)); + } + + #[test] + fn reduce_max() { + let mut a = U256::ZERO; + let mut b = U256::ZERO; + b.limbs[b.limbs.len() - 1] = Limb(Word::MAX); + let r = a.wrapping_rem(&b); + assert_eq!(r, Uint::ZERO); + a.limbs[a.limbs.len() - 1] = Limb(1 << (HI_BIT - 7)); + b.limbs[b.limbs.len() - 1] = Limb(0x82 << (HI_BIT - 7)); + let r = a.wrapping_rem(&b); + assert_eq!(r, a); + } + + #[cfg(feature = "rand")] + #[test] + fn rem2krand() { + let mut rng = ChaChaRng::from_seed([7u8; 32]); + for _ in 0..25 { + let num = U256::random(&mut rng); + let k = (rng.next_u32() % 256) as usize; + let den = U256::ONE.shl_vartime(k); + + let a = num.rem2k(k); + let e = num.wrapping_rem(&den); + assert_eq!(a, e); + } + } + + #[allow(clippy::op_ref)] + #[test] + fn rem_trait() { + let a = U256::from(10u64); + let b = NonZero::new(U256::from(3u64)).unwrap(); + let c = U256::from(1u64); + + assert_eq!(a % b, c); + assert_eq!(a % &b, c); + assert_eq!(&a % b, c); + assert_eq!(&a % &b, c); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/div_limb.rs b/src/rust/vendor/crypto-bigint/src/uint/div_limb.rs new file mode 100644 index 000000000..3edf80af8 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/div_limb.rs @@ -0,0 +1,287 @@ +//! Implementation of constant-time division via reciprocal precomputation, as described in +//! "Improved Division by Invariant Integers" by Niels Möller and Torbjorn Granlund +//! (DOI: 10.1109/TC.2010.143, ). +use subtle::{Choice, ConditionallySelectable, CtOption}; + +use crate::{CtChoice, Limb, Uint, WideWord, Word}; + +/// Calculates the reciprocal of the given 32-bit divisor with the highmost bit set. +#[cfg(target_pointer_width = "32")] +pub const fn reciprocal(d: Word) -> Word { + debug_assert!(d >= (1 << (Word::BITS - 1))); + + let d0 = d & 1; + let d10 = d >> 22; + let d21 = (d >> 11) + 1; + let d31 = (d >> 1) + d0; + let v0 = short_div((1 << 24) - (1 << 14) + (1 << 9), 24, d10, 10); + let (hi, _lo) = mulhilo(v0 * v0, d21); + let v1 = (v0 << 4) - hi - 1; + + // Checks that the expression for `e` can be simplified in the way we did below. + debug_assert!(mulhilo(v1, d31).0 == (1 << 16) - 1); + let e = Word::MAX - v1.wrapping_mul(d31) + 1 + (v1 >> 1) * d0; + + let (hi, _lo) = mulhilo(v1, e); + // Note: the paper does not mention a wrapping add here, + // but the 64-bit version has it at this stage, and the function panics without it + // when calculating a reciprocal for `Word::MAX`. + let v2 = (v1 << 15).wrapping_add(hi >> 1); + + // The paper has `(v2 + 1) * d / 2^32` (there's another 2^32, but it's accounted for later). + // If `v2 == 2^32-1` this should give `d`, but we can't achieve this in our wrapping arithmetic. + // Hence the `ct_select()`. + let x = v2.wrapping_add(1); + let (hi, _lo) = mulhilo(x, d); + let hi = Limb::ct_select(Limb(d), Limb(hi), Limb(x).ct_is_nonzero()).0; + + v2.wrapping_sub(hi).wrapping_sub(d) +} + +/// Calculates the reciprocal of the given 64-bit divisor with the highmost bit set. +#[cfg(target_pointer_width = "64")] +pub const fn reciprocal(d: Word) -> Word { + debug_assert!(d >= (1 << (Word::BITS - 1))); + + let d0 = d & 1; + let d9 = d >> 55; + let d40 = (d >> 24) + 1; + let d63 = (d >> 1) + d0; + let v0 = short_div((1 << 19) - 3 * (1 << 8), 19, d9 as u32, 9) as u64; + let v1 = (v0 << 11) - ((v0 * v0 * d40) >> 40) - 1; + let v2 = (v1 << 13) + ((v1 * ((1 << 60) - v1 * d40)) >> 47); + + // Checks that the expression for `e` can be simplified in the way we did below. + debug_assert!(mulhilo(v2, d63).0 == (1 << 32) - 1); + let e = Word::MAX - v2.wrapping_mul(d63) + 1 + (v2 >> 1) * d0; + + let (hi, _lo) = mulhilo(v2, e); + let v3 = (v2 << 31).wrapping_add(hi >> 1); + + // The paper has `(v3 + 1) * d / 2^64` (there's another 2^64, but it's accounted for later). + // If `v3 == 2^64-1` this should give `d`, but we can't achieve this in our wrapping arithmetic. + // Hence the `ct_select()`. + let x = v3.wrapping_add(1); + let (hi, _lo) = mulhilo(x, d); + let hi = Limb::ct_select(Limb(d), Limb(hi), Limb(x).ct_is_nonzero()).0; + + v3.wrapping_sub(hi).wrapping_sub(d) +} + +/// Returns `u32::MAX` if `a < b` and `0` otherwise. +#[inline] +const fn ct_lt(a: u32, b: u32) -> u32 { + let bit = (((!a) & b) | (((!a) | b) & (a.wrapping_sub(b)))) >> (u32::BITS - 1); + bit.wrapping_neg() +} + +/// Returns `a` if `c == 0` and `b` if `c == u32::MAX`. +#[inline(always)] +const fn ct_select(a: u32, b: u32, c: u32) -> u32 { + a ^ (c & (a ^ b)) +} + +/// Calculates `dividend / divisor`, given `dividend` and `divisor` +/// along with their maximum bitsizes. +#[inline(always)] +const fn short_div(dividend: u32, dividend_bits: u32, divisor: u32, divisor_bits: u32) -> u32 { + // TODO: this may be sped up even more using the fact that `dividend` is a known constant. + + // In the paper this is a table lookup, but since we want it to be constant-time, + // we have to access all the elements of the table, which is quite large. + // So this shift-and-subtract approach is actually faster. + + // Passing `dividend_bits` and `divisor_bits` because calling `.leading_zeros()` + // causes a significant slowdown, and we know those values anyway. + + let mut dividend = dividend; + let mut divisor = divisor << (dividend_bits - divisor_bits); + let mut quotient: u32 = 0; + let mut i = dividend_bits - divisor_bits + 1; + + while i > 0 { + i -= 1; + let bit = ct_lt(dividend, divisor); + dividend = ct_select(dividend.wrapping_sub(divisor), dividend, bit); + divisor >>= 1; + let inv_bit = !bit; + quotient |= (inv_bit >> (u32::BITS - 1)) << i; + } + + quotient +} + +/// Multiplies `x` and `y`, returning the most significant +/// and the least significant words as `(hi, lo)`. +#[inline(always)] +const fn mulhilo(x: Word, y: Word) -> (Word, Word) { + let res = (x as WideWord) * (y as WideWord); + ((res >> Word::BITS) as Word, res as Word) +} + +/// Adds wide numbers represented by pairs of (most significant word, least significant word) +/// and returns the result in the same format `(hi, lo)`. +#[inline(always)] +const fn addhilo(x_hi: Word, x_lo: Word, y_hi: Word, y_lo: Word) -> (Word, Word) { + let res = (((x_hi as WideWord) << Word::BITS) | (x_lo as WideWord)) + + (((y_hi as WideWord) << Word::BITS) | (y_lo as WideWord)); + ((res >> Word::BITS) as Word, res as Word) +} + +/// Calculate the quotient and the remainder of the division of a wide word +/// (supplied as high and low words) by `d`, with a precalculated reciprocal `v`. +#[inline(always)] +const fn div2by1(u1: Word, u0: Word, reciprocal: &Reciprocal) -> (Word, Word) { + let d = reciprocal.divisor_normalized; + + debug_assert!(d >= (1 << (Word::BITS - 1))); + debug_assert!(u1 < d); + + let (q1, q0) = mulhilo(reciprocal.reciprocal, u1); + let (q1, q0) = addhilo(q1, q0, u1, u0); + let q1 = q1.wrapping_add(1); + let r = u0.wrapping_sub(q1.wrapping_mul(d)); + + let r_gt_q0 = Limb::ct_lt(Limb(q0), Limb(r)); + let q1 = Limb::ct_select(Limb(q1), Limb(q1.wrapping_sub(1)), r_gt_q0).0; + let r = Limb::ct_select(Limb(r), Limb(r.wrapping_add(d)), r_gt_q0).0; + + // If this was a normal `if`, we wouldn't need wrapping ops, because there would be no overflow. + // But since we calculate both results either way, we have to wrap. + // Added an assert to still check the lack of overflow in debug mode. + debug_assert!(r < d || q1 < Word::MAX); + let r_ge_d = Limb::ct_le(Limb(d), Limb(r)); + let q1 = Limb::ct_select(Limb(q1), Limb(q1.wrapping_add(1)), r_ge_d).0; + let r = Limb::ct_select(Limb(r), Limb(r.wrapping_sub(d)), r_ge_d).0; + + (q1, r) +} + +/// A pre-calculated reciprocal for division by a single limb. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct Reciprocal { + divisor_normalized: Word, + shift: u32, + reciprocal: Word, +} + +impl Reciprocal { + /// Pre-calculates a reciprocal for a known divisor, + /// to be used in the single-limb division later. + /// Returns the reciprocal, and the truthy value if `divisor != 0` + /// and the falsy value otherwise. + /// + /// Note: if the returned flag is falsy, the returned reciprocal object is still self-consistent + /// and can be passed to functions here without causing them to panic, + /// but the results are naturally not to be used. + pub const fn ct_new(divisor: Limb) -> (Self, CtChoice) { + // Assuming this is constant-time for primitive types. + let shift = divisor.0.leading_zeros(); + + #[allow(trivial_numeric_casts)] + let is_some = Limb((Word::BITS - shift) as Word).ct_is_nonzero(); + + // If `divisor = 0`, shifting `divisor` by `leading_zeros == Word::BITS` will cause a panic. + // Have to substitute a "bogus" shift in that case. + #[allow(trivial_numeric_casts)] + let shift_limb = Limb::ct_select(Limb::ZERO, Limb(shift as Word), is_some); + + // Need to provide bogus normalized divisor and reciprocal too, + // so that we don't get a panic in low-level functions. + let divisor_normalized = divisor.shl(shift_limb); + let divisor_normalized = Limb::ct_select(Limb::MAX, divisor_normalized, is_some).0; + + #[allow(trivial_numeric_casts)] + let shift = shift_limb.0 as u32; + + ( + Self { + divisor_normalized, + shift, + reciprocal: reciprocal(divisor_normalized), + }, + is_some, + ) + } + + /// Returns a default instance of this object. + /// It is a self-consistent `Reciprocal` that will not cause panics in functions that take it. + /// + /// NOTE: intended for using it as a placeholder during compile-time array generation, + /// don't rely on the contents. + pub const fn default() -> Self { + Self { + divisor_normalized: Word::MAX, + shift: 0, + // The result of calling `reciprocal(Word::MAX)` + // This holds both for 32- and 64-bit versions. + reciprocal: 1, + } + } + + /// A non-const-fn version of `new_const()`, wrapping the result in a `CtOption`. + pub fn new(divisor: Limb) -> CtOption { + let (rec, is_some) = Self::ct_new(divisor); + CtOption::new(rec, is_some.into()) + } +} + +impl ConditionallySelectable for Reciprocal { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self { + divisor_normalized: Word::conditional_select( + &a.divisor_normalized, + &b.divisor_normalized, + choice, + ), + shift: u32::conditional_select(&a.shift, &b.shift, choice), + reciprocal: Word::conditional_select(&a.reciprocal, &b.reciprocal, choice), + } + } +} + +// `CtOption.map()` needs this; for some reason it doesn't use the value it already has +// for the `None` branch. +impl Default for Reciprocal { + fn default() -> Self { + Self::default() + } +} + +/// Divides `u` by the divisor encoded in the `reciprocal`, and returns +/// the quotient and the remainder. +#[inline(always)] +pub(crate) const fn div_rem_limb_with_reciprocal( + u: &Uint, + reciprocal: &Reciprocal, +) -> (Uint, Limb) { + let (u_shifted, u_hi) = u.shl_limb(reciprocal.shift as usize); + let mut r = u_hi.0; + let mut q = [Limb::ZERO; L]; + + let mut j = L; + while j > 0 { + j -= 1; + let (qj, rj) = div2by1(r, u_shifted.as_limbs()[j].0, reciprocal); + q[j] = Limb(qj); + r = rj; + } + (Uint::::new(q), Limb(r >> reciprocal.shift)) +} + +#[cfg(test)] +mod tests { + use super::{div2by1, Reciprocal}; + use crate::{Limb, Word}; + #[test] + fn div2by1_overflow() { + // A regression test for a situation when in div2by1() an operation (`q1 + 1`) + // that is protected from overflowing by a condition in the original paper (`r >= d`) + // still overflows because we're calculating the results for both branches. + let r = Reciprocal::new(Limb(Word::MAX - 1)).unwrap(); + assert_eq!( + div2by1(Word::MAX - 2, Word::MAX - 63, &r), + (Word::MAX, Word::MAX - 65) + ); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/encoding.rs b/src/rust/vendor/crypto-bigint/src/uint/encoding.rs new file mode 100644 index 000000000..42f9de183 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/encoding.rs @@ -0,0 +1,292 @@ +//! Const-friendly decoding operations for [`Uint`] + +#[cfg(all(feature = "der", feature = "generic-array"))] +mod der; + +#[cfg(feature = "rlp")] +mod rlp; + +use super::Uint; +use crate::{Encoding, Limb, Word}; + +impl Uint { + /// Create a new [`Uint`] from the provided big endian bytes. + pub const fn from_be_slice(bytes: &[u8]) -> Self { + assert!( + bytes.len() == Limb::BYTES * LIMBS, + "bytes are not the expected size" + ); + + let mut res = [Limb::ZERO; LIMBS]; + let mut buf = [0u8; Limb::BYTES]; + let mut i = 0; + + while i < LIMBS { + let mut j = 0; + while j < Limb::BYTES { + buf[j] = bytes[i * Limb::BYTES + j]; + j += 1; + } + res[LIMBS - i - 1] = Limb(Word::from_be_bytes(buf)); + i += 1; + } + + Uint::new(res) + } + + /// Create a new [`Uint`] from the provided big endian hex string. + pub const fn from_be_hex(hex: &str) -> Self { + let bytes = hex.as_bytes(); + + assert!( + bytes.len() == Limb::BYTES * LIMBS * 2, + "hex string is not the expected size" + ); + + let mut res = [Limb::ZERO; LIMBS]; + let mut buf = [0u8; Limb::BYTES]; + let mut i = 0; + let mut err = 0; + + while i < LIMBS { + let mut j = 0; + while j < Limb::BYTES { + let offset = (i * Limb::BYTES + j) * 2; + let (result, byte_err) = decode_hex_byte([bytes[offset], bytes[offset + 1]]); + err |= byte_err; + buf[j] = result; + j += 1; + } + res[LIMBS - i - 1] = Limb(Word::from_be_bytes(buf)); + i += 1; + } + + assert!(err == 0, "invalid hex byte"); + + Uint::new(res) + } + + /// Create a new [`Uint`] from the provided little endian bytes. + pub const fn from_le_slice(bytes: &[u8]) -> Self { + assert!( + bytes.len() == Limb::BYTES * LIMBS, + "bytes are not the expected size" + ); + + let mut res = [Limb::ZERO; LIMBS]; + let mut buf = [0u8; Limb::BYTES]; + let mut i = 0; + + while i < LIMBS { + let mut j = 0; + while j < Limb::BYTES { + buf[j] = bytes[i * Limb::BYTES + j]; + j += 1; + } + res[i] = Limb(Word::from_le_bytes(buf)); + i += 1; + } + + Uint::new(res) + } + + /// Create a new [`Uint`] from the provided little endian hex string. + pub const fn from_le_hex(hex: &str) -> Self { + let bytes = hex.as_bytes(); + + assert!( + bytes.len() == Limb::BYTES * LIMBS * 2, + "bytes are not the expected size" + ); + + let mut res = [Limb::ZERO; LIMBS]; + let mut buf = [0u8; Limb::BYTES]; + let mut i = 0; + let mut err = 0; + + while i < LIMBS { + let mut j = 0; + while j < Limb::BYTES { + let offset = (i * Limb::BYTES + j) * 2; + let (result, byte_err) = decode_hex_byte([bytes[offset], bytes[offset + 1]]); + err |= byte_err; + buf[j] = result; + j += 1; + } + res[i] = Limb(Word::from_le_bytes(buf)); + i += 1; + } + + assert!(err == 0, "invalid hex byte"); + + Uint::new(res) + } + + /// Serialize this [`Uint`] as big-endian, writing it into the provided + /// byte slice. + #[inline] + pub(crate) fn write_be_bytes(&self, out: &mut [u8]) { + debug_assert_eq!(out.len(), Limb::BYTES * LIMBS); + + for (src, dst) in self + .limbs + .iter() + .rev() + .cloned() + .zip(out.chunks_exact_mut(Limb::BYTES)) + { + dst.copy_from_slice(&src.to_be_bytes()); + } + } + + /// Serialize this [`Uint`] as little-endian, writing it into the provided + /// byte slice. + #[inline] + pub(crate) fn write_le_bytes(&self, out: &mut [u8]) { + debug_assert_eq!(out.len(), Limb::BYTES * LIMBS); + + for (src, dst) in self + .limbs + .iter() + .cloned() + .zip(out.chunks_exact_mut(Limb::BYTES)) + { + dst.copy_from_slice(&src.to_le_bytes()); + } + } +} + +/// Decode a single nibble of upper or lower hex +#[inline(always)] +const fn decode_nibble(src: u8) -> u16 { + let byte = src as i16; + let mut ret: i16 = -1; + + // 0-9 0x30-0x39 + // if (byte > 0x2f && byte < 0x3a) ret += byte - 0x30 + 1; // -47 + ret += (((0x2fi16 - byte) & (byte - 0x3a)) >> 8) & (byte - 47); + // A-F 0x41-0x46 + // if (byte > 0x40 && byte < 0x47) ret += byte - 0x41 + 10 + 1; // -54 + ret += (((0x40i16 - byte) & (byte - 0x47)) >> 8) & (byte - 54); + // a-f 0x61-0x66 + // if (byte > 0x60 && byte < 0x67) ret += byte - 0x61 + 10 + 1; // -86 + ret += (((0x60i16 - byte) & (byte - 0x67)) >> 8) & (byte - 86); + + ret as u16 +} + +/// Decode a single byte encoded as two hexadecimal characters. +/// Second element of the tuple is non-zero if the `bytes` values are not in the valid range +/// (0-9, a-z, A-Z). +#[inline(always)] +const fn decode_hex_byte(bytes: [u8; 2]) -> (u8, u16) { + let hi = decode_nibble(bytes[0]); + let lo = decode_nibble(bytes[1]); + let byte = (hi << 4) | lo; + let err = byte >> 8; + let result = byte as u8; + (result, err) +} + +#[cfg(test)] +mod tests { + use crate::Limb; + use hex_literal::hex; + + #[cfg(feature = "alloc")] + use {crate::U128, alloc::format}; + + #[cfg(target_pointer_width = "32")] + use crate::U64 as UintEx; + + #[cfg(target_pointer_width = "64")] + use crate::U128 as UintEx; + + #[test] + #[cfg(target_pointer_width = "32")] + fn from_be_slice() { + let bytes = hex!("0011223344556677"); + let n = UintEx::from_be_slice(&bytes); + assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn from_be_slice() { + let bytes = hex!("00112233445566778899aabbccddeeff"); + let n = UintEx::from_be_slice(&bytes); + assert_eq!( + n.as_limbs(), + &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)] + ); + } + + #[test] + #[cfg(target_pointer_width = "32")] + fn from_le_slice() { + let bytes = hex!("7766554433221100"); + let n = UintEx::from_le_slice(&bytes); + assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn from_le_slice() { + let bytes = hex!("ffeeddccbbaa99887766554433221100"); + let n = UintEx::from_le_slice(&bytes); + assert_eq!( + n.as_limbs(), + &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)] + ); + } + + #[test] + #[cfg(target_pointer_width = "32")] + fn from_be_hex() { + let n = UintEx::from_be_hex("0011223344556677"); + assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn from_be_hex() { + let n = UintEx::from_be_hex("00112233445566778899aabbccddeeff"); + assert_eq!( + n.as_limbs(), + &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)] + ); + } + + #[test] + #[cfg(target_pointer_width = "32")] + fn from_le_hex() { + let n = UintEx::from_le_hex("7766554433221100"); + assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn from_le_hex() { + let n = UintEx::from_le_hex("ffeeddccbbaa99887766554433221100"); + assert_eq!( + n.as_limbs(), + &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)] + ); + } + + #[cfg(feature = "alloc")] + #[test] + fn hex_upper() { + let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD"; + let n = U128::from_be_hex(hex); + assert_eq!(hex, format!("{:X}", n)); + } + + #[cfg(feature = "alloc")] + #[test] + fn hex_lower() { + let hex = "aaaaaaaabbbbbbbbccccccccdddddddd"; + let n = U128::from_be_hex(hex); + assert_eq!(hex, format!("{:x}", n)); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/encoding/der.rs b/src/rust/vendor/crypto-bigint/src/uint/encoding/der.rs new file mode 100644 index 000000000..dcd766b2b --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/encoding/der.rs @@ -0,0 +1,64 @@ +//! Support for decoding/encoding [`Uint`] as an ASN.1 DER `INTEGER`. + +use crate::{generic_array::GenericArray, ArrayEncoding, Uint}; +use ::der::{ + asn1::{AnyRef, UintRef}, + DecodeValue, EncodeValue, FixedTag, Length, Tag, +}; + +impl<'a, const LIMBS: usize> TryFrom> for Uint +where + Uint: ArrayEncoding, +{ + type Error = der::Error; + + fn try_from(any: AnyRef<'a>) -> der::Result> { + UintRef::try_from(any)?.try_into() + } +} + +impl<'a, const LIMBS: usize> TryFrom> for Uint +where + Uint: ArrayEncoding, +{ + type Error = der::Error; + + fn try_from(bytes: UintRef<'a>) -> der::Result> { + let mut array = GenericArray::default(); + let offset = array.len().saturating_sub(bytes.len().try_into()?); + array[offset..].copy_from_slice(bytes.as_bytes()); + Ok(Uint::from_be_byte_array(array)) + } +} + +impl<'a, const LIMBS: usize> DecodeValue<'a> for Uint +where + Uint: ArrayEncoding, +{ + fn decode_value>(reader: &mut R, header: der::Header) -> der::Result { + UintRef::decode_value(reader, header)?.try_into() + } +} + +impl EncodeValue for Uint +where + Uint: ArrayEncoding, +{ + fn value_len(&self) -> der::Result { + // TODO(tarcieri): more efficient length calculation + let array = self.to_be_byte_array(); + UintRef::new(&array)?.value_len() + } + + fn encode_value(&self, encoder: &mut impl der::Writer) -> der::Result<()> { + let array = self.to_be_byte_array(); + UintRef::new(&array)?.encode_value(encoder) + } +} + +impl FixedTag for Uint +where + Uint: ArrayEncoding, +{ + const TAG: Tag = Tag::Integer; +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/encoding/rlp.rs b/src/rust/vendor/crypto-bigint/src/uint/encoding/rlp.rs new file mode 100644 index 000000000..112efb1eb --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/encoding/rlp.rs @@ -0,0 +1,78 @@ +//! Recursive Length Prefix (RLP) encoding support. + +use crate::{Encoding, Uint}; +use rlp::{DecoderError, Rlp, RlpStream}; + +impl rlp::Encodable for Uint +where + Self: Encoding, +{ + fn rlp_append(&self, stream: &mut RlpStream) { + let bytes = self.to_be_bytes(); + let mut bytes_stripped = bytes.as_ref(); + + while bytes_stripped.first().cloned() == Some(0) { + bytes_stripped = &bytes_stripped[1..]; + } + + stream.encoder().encode_value(bytes_stripped); + } +} + +impl rlp::Decodable for Uint +where + Self: Encoding, + ::Repr: Default, +{ + fn decode(rlp: &Rlp<'_>) -> Result { + rlp.decoder().decode_value(|bytes| { + if bytes.first().cloned() == Some(0) { + Err(rlp::DecoderError::RlpInvalidIndirection) + } else { + let mut repr = ::Repr::default(); + let offset = repr + .as_ref() + .len() + .checked_sub(bytes.len()) + .ok_or(DecoderError::RlpIsTooBig)?; + + repr.as_mut()[offset..].copy_from_slice(bytes); + Ok(Self::from_be_bytes(repr)) + } + }) + } +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +mod tests { + use crate::U256; + use hex_literal::hex; + + /// U256 test vectors from the `rlp` crate. + /// + /// + const U256_VECTORS: &[(U256, &[u8])] = &[ + (U256::ZERO, &hex!("80")), + ( + U256::from_be_hex("0000000000000000000000000000000000000000000000000000000001000000"), + &hex!("8401000000"), + ), + ( + U256::from_be_hex("00000000000000000000000000000000000000000000000000000000ffffffff"), + &hex!("84ffffffff"), + ), + ( + U256::from_be_hex("8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0"), + &hex!("a08090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0"), + ), + ]; + + #[test] + fn round_trip() { + for &(uint, expected_bytes) in U256_VECTORS { + assert_eq!(rlp::encode(&uint), expected_bytes); + assert_eq!(rlp::decode::(expected_bytes).unwrap(), uint); + } + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/extra_sizes.rs b/src/rust/vendor/crypto-bigint/src/uint/extra_sizes.rs new file mode 100644 index 000000000..fb639c713 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/extra_sizes.rs @@ -0,0 +1,160 @@ +//! Support for additional integer sizes beyond the core set which is defined +//! in the toplevel module. +//! +//! These are feature-gated to keep compile times down for applications which +//! do not need them. +// TODO(tarcieri): switch to a fully const generic implementation using `generic_const_exprs` + +use super::*; + +impl_uint_aliases! { + (U1088, 1088, "1088-bit"), + (U1152, 1152, "1152-bit"), + (U1216, 1216, "1216-bit"), + (U1344, 1344, "1344-bit"), + (U1408, 1408, "1408-bit"), + (U1472, 1472, "1472-bit"), + (U1600, 1600, "1600-bit"), + (U1664, 1664, "1664-bit"), + (U1728, 1728, "1728-bit"), + (U1856, 1856, "1856-bit"), + (U1920, 1920, "1920-bit"), + (U1984, 1984, "1984-bit"), + (U2112, 2112, "2112-bit"), + (U2176, 2176, "2176-bit"), + (U2240, 2240, "2240-bit"), + (U2304, 2304, "2304-bit"), + (U2368, 2368, "2368-bit"), + (U2432, 2432, "2432-bit"), + (U2496, 2496, "2496-bit"), + (U2560, 2560, "2560-bit"), + (U2624, 2624, "2624-bit"), + (U2688, 2688, "2688-bit"), + (U2752, 2752, "2752-bit"), + (U2816, 2816, "2816-bit"), + (U2880, 2880, "2880-bit"), + (U2944, 2944, "2944-bit"), + (U3008, 3008, "3008-bit"), + (U3136, 3136, "3136-bit"), + (U3200, 3200, "3200-bit"), + (U3264, 3264, "3264-bit"), + (U3328, 3328, "3328-bit"), + (U3392, 3392, "3392-bit"), + (U3456, 3456, "3456-bit"), + (U3520, 3520, "3520-bit"), + (U3648, 3648, "3648-bit"), + (U3712, 3712, "3712-bit"), + (U3776, 3776, "3776-bit"), + (U3840, 3840, "3840-bit"), + (U3904, 3904, "3904-bit"), + (U3968, 3968, "3968-bit"), + (U4032, 4032, "4032-bit"), + (U4160, 4160, "4160-bit"), + (U4288, 4288, "4288-bit"), + (U4416, 4416, "4416-bit"), + (U4480, 4480, "4480-bit"), + (U4544, 4544, "4544-bit"), + (U4608, 4608, "4608-bit"), + (U4672, 4672, "4672-bit"), + (U4736, 4736, "4736-bit"), + (U4800, 4800, "4800-bit"), + (U4864, 4864, "4864-bit"), + (U4928, 4928, "4928-bit"), + (U4992, 4992, "4992-bit"), + (U5056, 5056, "5056-bit"), + (U5120, 5120, "5120-bit"), + (U5184, 5184, "5184-bit"), + (U5248, 5248, "5248-bit"), + (U5312, 5312, "5312-bit"), + (U5376, 5376, "5376-bit"), + (U5440, 5440, "5440-bit"), + (U5504, 5504, "5504-bit"), + (U5568, 5568, "5568-bit"), + (U5632, 5632, "5632-bit"), + (U5696, 5696, "5696-bit"), + (U5760, 5760, "5760-bit"), + (U5824, 5824, "5824-bit"), + (U5888, 5888, "5888-bit"), + (U5952, 5952, "5952-bit"), + (U6016, 6016, "6016-bit"), + (U6080, 6080, "6080-bit"), + (U6208, 6208, "6208-bit"), + (U6272, 6272, "6272-bit"), + (U6336, 6336, "6336-bit"), + (U6400, 6400, "6400-bit"), + (U6464, 6464, "6464-bit"), + (U6528, 6528, "6528-bit"), + (U6592, 6592, "6592-bit"), + (U6656, 6656, "6656-bit"), + (U6720, 6720, "6720-bit"), + (U6784, 6784, "6784-bit"), + (U6848, 6848, "6848-bit"), + (U6912, 6912, "6912-bit"), + (U6976, 6976, "6976-bit"), + (U7040, 7040, "7040-bit"), + (U7104, 7104, "7104-bit"), + (U7168, 7168, "7168-bit"), + (U7232, 7232, "7232-bit"), + (U7296, 7296, "7296-bit"), + (U7360, 7360, "7360-bit"), + (U7424, 7424, "7424-bit"), + (U7488, 7488, "7488-bit"), + (U7552, 7552, "7552-bit"), + (U7616, 7616, "7616-bit"), + (U7680, 7680, "7680-bit"), + (U7744, 7744, "7744-bit"), + (U7808, 7808, "7808-bit"), + (U7872, 7872, "7872-bit"), + (U7936, 7936, "7936-bit"), + (U8000, 8000, "8000-bit"), + (U8064, 8064, "8064-bit"), + (U8128, 8128, "8128-bit") +} + +impl_uint_concat_split_even! { + U1152, + U1408, + U1664, + U1920, + U2176, + U2304, + U2432, + U2560, + U2688, + U2816, + U2944, + U3200, + U3328, + U3456, + U3712, + U3840, + U3968, + U4480, + U4608, + U4736, + U4864, + U4992, + U5120, + U5248, + U5376, + U5504, + U5632, + U5760, + U5888, + U6016, + U6272, + U6400, + U6528, + U6656, + U6784, + U6912, + U7040, + U7168, + U7296, + U7424, + U7552, + U7680, + U7808, + U7936, + U8064, +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/from.rs b/src/rust/vendor/crypto-bigint/src/uint/from.rs new file mode 100644 index 000000000..0f1bfbca7 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/from.rs @@ -0,0 +1,271 @@ +//! `From`-like conversions for [`Uint`]. + +use crate::{ConcatMixed, Limb, Uint, WideWord, Word, U128, U64}; + +impl Uint { + /// Create a [`Uint`] from a `u8` (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + pub const fn from_u8(n: u8) -> Self { + assert!(LIMBS >= 1, "number of limbs must be greater than zero"); + let mut limbs = [Limb::ZERO; LIMBS]; + limbs[0].0 = n as Word; + Self { limbs } + } + + /// Create a [`Uint`] from a `u16` (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + pub const fn from_u16(n: u16) -> Self { + assert!(LIMBS >= 1, "number of limbs must be greater than zero"); + let mut limbs = [Limb::ZERO; LIMBS]; + limbs[0].0 = n as Word; + Self { limbs } + } + + /// Create a [`Uint`] from a `u32` (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + #[allow(trivial_numeric_casts)] + pub const fn from_u32(n: u32) -> Self { + assert!(LIMBS >= 1, "number of limbs must be greater than zero"); + let mut limbs = [Limb::ZERO; LIMBS]; + limbs[0].0 = n as Word; + Self { limbs } + } + + /// Create a [`Uint`] from a `u64` (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + #[cfg(target_pointer_width = "32")] + pub const fn from_u64(n: u64) -> Self { + assert!(LIMBS >= 2, "number of limbs must be two or greater"); + let mut limbs = [Limb::ZERO; LIMBS]; + limbs[0].0 = (n & 0xFFFFFFFF) as u32; + limbs[1].0 = (n >> 32) as u32; + Self { limbs } + } + + /// Create a [`Uint`] from a `u64` (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + #[cfg(target_pointer_width = "64")] + pub const fn from_u64(n: u64) -> Self { + assert!(LIMBS >= 1, "number of limbs must be greater than zero"); + let mut limbs = [Limb::ZERO; LIMBS]; + limbs[0].0 = n; + Self { limbs } + } + + /// Create a [`Uint`] from a `u128` (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + pub const fn from_u128(n: u128) -> Self { + assert!( + LIMBS >= (128 / Limb::BITS), + "number of limbs must be greater than zero" + ); + + let lo = U64::from_u64((n & 0xffff_ffff_ffff_ffff) as u64); + let hi = U64::from_u64((n >> 64) as u64); + + let mut limbs = [Limb::ZERO; LIMBS]; + + let mut i = 0; + while i < lo.limbs.len() { + limbs[i] = lo.limbs[i]; + i += 1; + } + + let mut j = 0; + while j < hi.limbs.len() { + limbs[i + j] = hi.limbs[j]; + j += 1; + } + + Self { limbs } + } + + /// Create a [`Uint`] from a `Word` (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + pub const fn from_word(n: Word) -> Self { + assert!(LIMBS >= 1, "number of limbs must be greater than zero"); + let mut limbs = [Limb::ZERO; LIMBS]; + limbs[0].0 = n; + Self { limbs } + } + + /// Create a [`Uint`] from a `WideWord` (const-friendly) + // TODO(tarcieri): replace with `const impl From` when stable + pub const fn from_wide_word(n: WideWord) -> Self { + assert!(LIMBS >= 2, "number of limbs must be two or greater"); + let mut limbs = [Limb::ZERO; LIMBS]; + limbs[0].0 = n as Word; + limbs[1].0 = (n >> Limb::BITS) as Word; + Self { limbs } + } +} + +impl From for Uint { + fn from(n: u8) -> Self { + // TODO(tarcieri): const where clause when possible + debug_assert!(LIMBS > 0, "limbs must be non-zero"); + Self::from_u8(n) + } +} + +impl From for Uint { + fn from(n: u16) -> Self { + // TODO(tarcieri): const where clause when possible + debug_assert!(LIMBS > 0, "limbs must be non-zero"); + Self::from_u16(n) + } +} + +impl From for Uint { + fn from(n: u32) -> Self { + // TODO(tarcieri): const where clause when possible + debug_assert!(LIMBS > 0, "limbs must be non-zero"); + Self::from_u32(n) + } +} + +impl From for Uint { + fn from(n: u64) -> Self { + // TODO(tarcieri): const where clause when possible + debug_assert!(LIMBS >= (64 / Limb::BITS), "not enough limbs"); + Self::from_u64(n) + } +} + +impl From for Uint { + fn from(n: u128) -> Self { + // TODO(tarcieri): const where clause when possible + debug_assert!(LIMBS >= (128 / Limb::BITS), "not enough limbs"); + Self::from_u128(n) + } +} + +#[cfg(target_pointer_width = "32")] +impl From for u64 { + fn from(n: U64) -> u64 { + (n.limbs[0].0 as u64) | ((n.limbs[1].0 as u64) << 32) + } +} + +#[cfg(target_pointer_width = "64")] +impl From for u64 { + fn from(n: U64) -> u64 { + n.limbs[0].into() + } +} + +impl From for u128 { + fn from(n: U128) -> u128 { + let mut i = U128::LIMBS - 1; + let mut res = n.limbs[i].0 as u128; + while i > 0 { + i -= 1; + res = (res << Limb::BITS) | (n.limbs[i].0 as u128); + } + res + } +} + +impl From<[Word; LIMBS]> for Uint { + fn from(arr: [Word; LIMBS]) -> Self { + Self::from_words(arr) + } +} + +impl From> for [Word; LIMBS] { + fn from(n: Uint) -> [Word; LIMBS] { + *n.as_ref() + } +} + +impl From<[Limb; LIMBS]> for Uint { + fn from(limbs: [Limb; LIMBS]) -> Self { + Self { limbs } + } +} + +impl From> for [Limb; LIMBS] { + fn from(n: Uint) -> [Limb; LIMBS] { + n.limbs + } +} + +impl From for Uint { + fn from(limb: Limb) -> Self { + limb.0.into() + } +} + +impl From<(Uint, Uint)> for Uint +where + Uint: ConcatMixed, MixedOutput = Uint>, +{ + fn from(nums: (Uint, Uint)) -> Uint { + nums.1.concat_mixed(&nums.0) + } +} + +impl From<&(Uint, Uint)> for Uint +where + Uint: ConcatMixed, MixedOutput = Uint>, +{ + fn from(nums: &(Uint, Uint)) -> Uint { + nums.1.concat_mixed(&nums.0) + } +} + +impl From> for (Uint, Uint) { + fn from(num: Uint) -> (Uint, Uint) { + crate::uint::split::split_mixed(&num) + } +} + +impl From<&Uint> for Uint { + fn from(num: &Uint) -> Uint { + num.resize() + } +} + +#[cfg(test)] +mod tests { + use crate::{Limb, Word, U128}; + + #[cfg(target_pointer_width = "32")] + use crate::U64 as UintEx; + + #[cfg(target_pointer_width = "64")] + use crate::U128 as UintEx; + + #[test] + fn from_u8() { + let n = UintEx::from(42u8); + assert_eq!(n.as_limbs(), &[Limb(42), Limb(0)]); + } + + #[test] + fn from_u16() { + let n = UintEx::from(42u16); + assert_eq!(n.as_limbs(), &[Limb(42), Limb(0)]); + } + + #[test] + fn from_u64() { + let n = UintEx::from(42u64); + assert_eq!(n.as_limbs(), &[Limb(42), Limb(0)]); + } + + #[test] + fn from_u128() { + let n = U128::from(42u128); + assert_eq!(&n.as_limbs()[..2], &[Limb(42), Limb(0)]); + assert_eq!(u128::from(n), 42u128); + } + + #[test] + fn array_round_trip() { + let arr1 = [1, 2]; + let n = UintEx::from(arr1); + let arr2: [Word; 2] = n.into(); + assert_eq!(arr1, arr2); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/inv_mod.rs b/src/rust/vendor/crypto-bigint/src/uint/inv_mod.rs new file mode 100644 index 000000000..e41dc66b5 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/inv_mod.rs @@ -0,0 +1,306 @@ +use super::Uint; +use crate::CtChoice; + +impl Uint { + /// Computes 1/`self` mod `2^k`. + /// This method is constant-time w.r.t. `self` but not `k`. + /// + /// Conditions: `self` < 2^k and `self` must be odd + pub const fn inv_mod2k_vartime(&self, k: usize) -> Self { + // Using the Algorithm 3 from "A Secure Algorithm for Inversion Modulo 2k" + // by Sadiel de la Fe and Carles Ferrer. + // See . + + // Note that we are not using Alrgorithm 4, since we have a different approach + // of enforcing constant-timeness w.r.t. `self`. + + let mut x = Self::ZERO; // keeps `x` during iterations + let mut b = Self::ONE; // keeps `b_i` during iterations + let mut i = 0; + + while i < k { + // X_i = b_i mod 2 + let x_i = b.limbs[0].0 & 1; + let x_i_choice = CtChoice::from_lsb(x_i); + // b_{i+1} = (b_i - a * X_i) / 2 + b = Self::ct_select(&b, &b.wrapping_sub(self), x_i_choice).shr_vartime(1); + // Store the X_i bit in the result (x = x | (1 << X_i)) + x = x.bitor(&Uint::from_word(x_i).shl_vartime(i)); + + i += 1; + } + + x + } + + /// Computes 1/`self` mod `2^k`. + /// + /// Conditions: `self` < 2^k and `self` must be odd + pub const fn inv_mod2k(&self, k: usize) -> Self { + // This is the same algorithm as in `inv_mod2k_vartime()`, + // but made constant-time w.r.t `k` as well. + + let mut x = Self::ZERO; // keeps `x` during iterations + let mut b = Self::ONE; // keeps `b_i` during iterations + let mut i = 0; + + while i < Self::BITS { + // Only iterations for i = 0..k need to change `x`, + // the rest are dummy ones performed for the sake of constant-timeness. + let within_range = CtChoice::from_usize_lt(i, k); + + // X_i = b_i mod 2 + let x_i = b.limbs[0].0 & 1; + let x_i_choice = CtChoice::from_lsb(x_i); + // b_{i+1} = (b_i - a * X_i) / 2 + b = Self::ct_select(&b, &b.wrapping_sub(self), x_i_choice).shr_vartime(1); + + // Store the X_i bit in the result (x = x | (1 << X_i)) + // Don't change the result in dummy iterations. + let x_i_choice = x_i_choice.and(within_range); + x = x.set_bit(i, x_i_choice); + + i += 1; + } + + x + } + + /// Computes the multiplicative inverse of `self` mod `modulus`, where `modulus` is odd. + /// In other words `self^-1 mod modulus`. + /// `bits` and `modulus_bits` are the bounds on the bit size + /// of `self` and `modulus`, respectively + /// (the inversion speed will be proportional to `bits + modulus_bits`). + /// The second element of the tuple is the truthy value if an inverse exists, + /// otherwise it is a falsy value. + /// + /// **Note:** variable time in `bits` and `modulus_bits`. + /// + /// The algorithm is the same as in GMP 6.2.1's `mpn_sec_invert`. + pub const fn inv_odd_mod_bounded( + &self, + modulus: &Self, + bits: usize, + modulus_bits: usize, + ) -> (Self, CtChoice) { + debug_assert!(modulus.ct_is_odd().is_true_vartime()); + + let mut a = *self; + + let mut u = Uint::ONE; + let mut v = Uint::ZERO; + + let mut b = *modulus; + + // `bit_size` can be anything >= `self.bits()` + `modulus.bits()`, setting to the minimum. + let bit_size = bits + modulus_bits; + + let mut m1hp = *modulus; + let (m1hp_new, carry) = m1hp.shr_1(); + debug_assert!(carry.is_true_vartime()); + m1hp = m1hp_new.wrapping_add(&Uint::ONE); + + let mut i = 0; + while i < bit_size { + debug_assert!(b.ct_is_odd().is_true_vartime()); + + let self_odd = a.ct_is_odd(); + + // Set `self -= b` if `self` is odd. + let (new_a, swap) = a.conditional_wrapping_sub(&b, self_odd); + // Set `b += self` if `swap` is true. + b = Uint::ct_select(&b, &b.wrapping_add(&new_a), swap); + // Negate `self` if `swap` is true. + a = new_a.conditional_wrapping_neg(swap); + + let (new_u, new_v) = Uint::ct_swap(&u, &v, swap); + let (new_u, cy) = new_u.conditional_wrapping_sub(&new_v, self_odd); + let (new_u, cyy) = new_u.conditional_wrapping_add(modulus, cy); + debug_assert!(cy.is_true_vartime() == cyy.is_true_vartime()); + + let (new_a, overflow) = a.shr_1(); + debug_assert!(!overflow.is_true_vartime()); + let (new_u, cy) = new_u.shr_1(); + let (new_u, cy) = new_u.conditional_wrapping_add(&m1hp, cy); + debug_assert!(!cy.is_true_vartime()); + + a = new_a; + u = new_u; + v = new_v; + + i += 1; + } + + debug_assert!(!a.ct_is_nonzero().is_true_vartime()); + + (v, Uint::ct_eq(&b, &Uint::ONE)) + } + + /// Computes the multiplicative inverse of `self` mod `modulus`, where `modulus` is odd. + /// Returns `(inverse, CtChoice::TRUE)` if an inverse exists, + /// otherwise `(undefined, CtChoice::FALSE)`. + pub const fn inv_odd_mod(&self, modulus: &Self) -> (Self, CtChoice) { + self.inv_odd_mod_bounded(modulus, Uint::::BITS, Uint::::BITS) + } + + /// Computes the multiplicative inverse of `self` mod `modulus`. + /// Returns `(inverse, CtChoice::TRUE)` if an inverse exists, + /// otherwise `(undefined, CtChoice::FALSE)`. + pub const fn inv_mod(&self, modulus: &Self) -> (Self, CtChoice) { + // Decompose `modulus = s * 2^k` where `s` is odd + let k = modulus.trailing_zeros(); + let s = modulus.shr(k); + + // Decompose `self` into RNS with moduli `2^k` and `s` and calculate the inverses. + // Using the fact that `(z^{-1} mod (m1 * m2)) mod m1 == z^{-1} mod m1` + let (a, a_is_some) = self.inv_odd_mod(&s); + let b = self.inv_mod2k(k); + // inverse modulo 2^k exists either if `k` is 0 or if `self` is odd. + let b_is_some = CtChoice::from_usize_being_nonzero(k) + .not() + .or(self.ct_is_odd()); + + // Restore from RNS: + // self^{-1} = a mod s = b mod 2^k + // => self^{-1} = a + s * ((b - a) * s^(-1) mod 2^k) + // (essentially one step of the Garner's algorithm for recovery from RNS). + + let m_odd_inv = s.inv_mod2k(k); // `s` is odd, so this always exists + + // This part is mod 2^k + let mask = Uint::ONE.shl(k).wrapping_sub(&Uint::ONE); + let t = (b.wrapping_sub(&a).wrapping_mul(&m_odd_inv)).bitand(&mask); + + // Will not overflow since `a <= s - 1`, `t <= 2^k - 1`, + // so `a + s * t <= s * 2^k - 1 == modulus - 1`. + let result = a.wrapping_add(&s.wrapping_mul(&t)); + (result, a_is_some.and(b_is_some)) + } +} + +#[cfg(test)] +mod tests { + use crate::{U1024, U256, U64}; + + #[test] + fn inv_mod2k() { + let v = + U256::from_be_hex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"); + let e = + U256::from_be_hex("3642e6faeaac7c6663b93d3d6a0d489e434ddc0123db5fa627c7f6e22ddacacf"); + let a = v.inv_mod2k(256); + assert_eq!(e, a); + + let v = + U256::from_be_hex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); + let e = + U256::from_be_hex("261776f29b6b106c7680cf3ed83054a1af5ae537cb4613dbb4f20099aa774ec1"); + let a = v.inv_mod2k(256); + assert_eq!(e, a); + } + + #[test] + fn test_invert_odd() { + let a = U1024::from_be_hex(concat![ + "000225E99153B467A5B451979A3F451DAEF3BF8D6C6521D2FA24BBB17F29544E", + "347A412B065B75A351EA9719E2430D2477B11CC9CF9C1AD6EDEE26CB15F463F8", + "BCC72EF87EA30288E95A48AA792226CEC959DCB0672D8F9D80A54CBBEA85CAD8", + "382EC224DEB2F5784E62D0CC2F81C2E6AD14EBABE646D6764B30C32B87688985" + ]); + let m = U1024::from_be_hex(concat![ + "D509E7854ABDC81921F669F1DC6F61359523F3949803E58ED4EA8BC16483DC6F", + "37BFE27A9AC9EEA2969B357ABC5C0EE214BE16A7D4C58FC620D5B5A20AFF001A", + "D198D3155E5799DC4EA76652D64983A7E130B5EACEBAC768D28D589C36EC749C", + "558D0B64E37CD0775C0D0104AE7D98BA23C815185DD43CD8B16292FD94156767" + ]); + let expected = U1024::from_be_hex(concat![ + "B03623284B0EBABCABD5C5881893320281460C0A8E7BF4BFDCFFCBCCBF436A55", + "D364235C8171E46C7D21AAD0680676E57274A8FDA6D12768EF961CACDD2DAE57", + "88D93DA5EB8EDC391EE3726CDCF4613C539F7D23E8702200CB31B5ED5B06E5CA", + "3E520968399B4017BF98A864FABA2B647EFC4998B56774D4F2CB026BC024A336" + ]); + + let (res, is_some) = a.inv_odd_mod(&m); + assert!(is_some.is_true_vartime()); + assert_eq!(res, expected); + + // Even though it is less efficient, it still works + let (res, is_some) = a.inv_mod(&m); + assert!(is_some.is_true_vartime()); + assert_eq!(res, expected); + } + + #[test] + fn test_invert_even() { + let a = U1024::from_be_hex(concat![ + "000225E99153B467A5B451979A3F451DAEF3BF8D6C6521D2FA24BBB17F29544E", + "347A412B065B75A351EA9719E2430D2477B11CC9CF9C1AD6EDEE26CB15F463F8", + "BCC72EF87EA30288E95A48AA792226CEC959DCB0672D8F9D80A54CBBEA85CAD8", + "382EC224DEB2F5784E62D0CC2F81C2E6AD14EBABE646D6764B30C32B87688985" + ]); + let m = U1024::from_be_hex(concat![ + "D509E7854ABDC81921F669F1DC6F61359523F3949803E58ED4EA8BC16483DC6F", + "37BFE27A9AC9EEA2969B357ABC5C0EE214BE16A7D4C58FC620D5B5A20AFF001A", + "D198D3155E5799DC4EA76652D64983A7E130B5EACEBAC768D28D589C36EC749C", + "558D0B64E37CD0775C0D0104AE7D98BA23C815185DD43CD8B16292FD94156000" + ]); + let expected = U1024::from_be_hex(concat![ + "1EBF391306817E1BC610E213F4453AD70911CCBD59A901B2A468A4FC1D64F357", + "DBFC6381EC5635CAA664DF280028AF4651482C77A143DF38D6BFD4D64B6C0225", + "FC0E199B15A64966FB26D88A86AD144271F6BDCD3D63193AB2B3CC53B99F21A3", + "5B9BFAE5D43C6BC6E7A9856C71C7318C76530E9E5AE35882D5ABB02F1696874D", + ]); + + let (res, is_some) = a.inv_mod(&m); + assert!(is_some.is_true_vartime()); + assert_eq!(res, expected); + } + + #[test] + fn test_invert_bounded() { + let a = U1024::from_be_hex(concat![ + "0000000000000000000000000000000000000000000000000000000000000000", + "347A412B065B75A351EA9719E2430D2477B11CC9CF9C1AD6EDEE26CB15F463F8", + "BCC72EF87EA30288E95A48AA792226CEC959DCB0672D8F9D80A54CBBEA85CAD8", + "382EC224DEB2F5784E62D0CC2F81C2E6AD14EBABE646D6764B30C32B87688985" + ]); + let m = U1024::from_be_hex(concat![ + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + "D198D3155E5799DC4EA76652D64983A7E130B5EACEBAC768D28D589C36EC749C", + "558D0B64E37CD0775C0D0104AE7D98BA23C815185DD43CD8B16292FD94156767" + ]); + + let (res, is_some) = a.inv_odd_mod_bounded(&m, 768, 512); + + let expected = U1024::from_be_hex(concat![ + "0000000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + "0DCC94E2FE509E6EBBA0825645A38E73EF85D5927C79C1AD8FFE7C8DF9A822FA", + "09EB396A21B1EF05CBE51E1A8EF284EF01EBDD36A9A4EA17039D8EEFDD934768" + ]); + assert!(is_some.is_true_vartime()); + assert_eq!(res, expected); + } + + #[test] + fn test_invert_small() { + let a = U64::from(3u64); + let m = U64::from(13u64); + + let (res, is_some) = a.inv_odd_mod(&m); + + assert!(is_some.is_true_vartime()); + assert_eq!(U64::from(9u64), res); + } + + #[test] + fn test_no_inverse_small() { + let a = U64::from(14u64); + let m = U64::from(49u64); + + let (_res, is_some) = a.inv_odd_mod(&m); + + assert!(!is_some.is_true_vartime()); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/macros.rs b/src/rust/vendor/crypto-bigint/src/uint/macros.rs new file mode 100644 index 000000000..47d32e79d --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/macros.rs @@ -0,0 +1,115 @@ +// TODO(tarcieri): use `generic_const_exprs` when stable to make generic around bits. +macro_rules! impl_uint_aliases { + ($(($name:ident, $bits:expr, $doc:expr)),+) => { + $( + #[doc = $doc] + #[doc="unsigned big integer."] + pub type $name = Uint<{nlimbs!($bits)}>; + + impl Encoding for $name { + + type Repr = [u8; $bits / 8]; + + #[inline] + fn from_be_bytes(bytes: Self::Repr) -> Self { + Self::from_be_slice(&bytes) + } + + #[inline] + fn from_le_bytes(bytes: Self::Repr) -> Self { + Self::from_le_slice(&bytes) + } + + #[inline] + fn to_be_bytes(&self) -> Self::Repr { + let mut result = [0u8; $bits / 8]; + self.write_be_bytes(&mut result); + result + } + + #[inline] + fn to_le_bytes(&self) -> Self::Repr { + let mut result = [0u8; $bits / 8]; + self.write_le_bytes(&mut result); + result + } + } + )+ + }; +} + +macro_rules! impl_uint_concat_split_mixed { + ($name:ident, $size:literal) => { + impl $crate::traits::ConcatMixed> for Uint<{ <$name>::LIMBS - U64::LIMBS * $size }> + { + type MixedOutput = $name; + + fn concat_mixed(&self, lo: &Uint<{ U64::LIMBS * $size }>) -> Self::MixedOutput { + $crate::uint::concat::concat_mixed(lo, self) + } + } + + impl $crate::traits::SplitMixed, Uint<{ <$name>::LIMBS - U64::LIMBS * $size }>> for $name + { + fn split_mixed(&self) -> (Uint<{ U64::LIMBS * $size }>, Uint<{ <$name>::LIMBS - U64::LIMBS * $size }>) { + $crate::uint::split::split_mixed(self) + } + } + }; + ($name:ident, [ $($size:literal),+ ]) => { + $( + impl_uint_concat_split_mixed!($name, $size); + )+ + }; + ($( ($name:ident, $sizes:tt), )+) => { + $( + impl_uint_concat_split_mixed!($name, $sizes); + )+ + }; +} + +macro_rules! impl_uint_concat_split_even { + ($name:ident) => { + impl $crate::traits::ConcatMixed::LIMBS / 2 }>> for Uint<{ <$name>::LIMBS / 2 }> + { + type MixedOutput = $name; + + fn concat_mixed(&self, lo: &Uint<{ <$name>::LIMBS / 2 }>) -> Self::MixedOutput { + $crate::uint::concat::concat_mixed(lo, self) + } + } + + impl Uint<{ <$name>::LIMBS / 2 }> { + /// Concatenate the two values, with `self` as most significant and `rhs` + /// as the least significant. + pub const fn concat(&self, lo: &Uint<{ <$name>::LIMBS / 2 }>) -> $name { + $crate::uint::concat::concat_mixed(lo, self) + } + } + + impl $crate::traits::SplitMixed::LIMBS / 2 }>, Uint<{ <$name>::LIMBS / 2 }>> for $name + { + fn split_mixed(&self) -> (Uint<{ <$name>::LIMBS / 2 }>, Uint<{ <$name>::LIMBS / 2 }>) { + $crate::uint::split::split_mixed(self) + } + } + + impl $crate::traits::Split for $name + { + type Output = Uint<{ <$name>::LIMBS / 2 }>; + } + + impl $name { + /// Split this number in half, returning its high and low components + /// respectively. + pub const fn split(&self) -> (Uint<{ <$name>::LIMBS / 2 }>, Uint<{ <$name>::LIMBS / 2 }>) { + $crate::uint::split::split_mixed(self) + } + } + }; + ($($name:ident,)+) => { + $( + impl_uint_concat_split_even!($name); + )+ + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular.rs b/src/rust/vendor/crypto-bigint/src/uint/modular.rs new file mode 100644 index 000000000..cd560aa38 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular.rs @@ -0,0 +1,164 @@ +mod reduction; + +/// Implements `Residue`s, supporting modular arithmetic with a constant modulus. +pub mod constant_mod; +/// Implements `DynResidue`s, supporting modular arithmetic with a modulus set at runtime. +pub mod runtime_mod; + +mod add; +mod div_by_2; +mod inv; +mod mul; +mod pow; +mod sub; + +pub use reduction::montgomery_reduction; + +/// A generalization for numbers kept in optimized representations (e.g. Montgomery) +/// that can be converted back to the original form. +pub trait Retrieve { + /// The original type. + type Output; + + /// Convert the number back from the optimized representation. + fn retrieve(&self) -> Self::Output; +} + +#[cfg(test)] +mod tests { + use crate::{ + const_residue, impl_modulus, + modular::{ + constant_mod::Residue, constant_mod::ResidueParams, reduction::montgomery_reduction, + }, + NonZero, Uint, U256, U64, + }; + + impl_modulus!( + Modulus1, + U256, + "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001" + ); + + #[test] + fn test_montgomery_params() { + assert_eq!( + Modulus1::R, + U256::from_be_hex("1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffe") + ); + assert_eq!( + Modulus1::R2, + U256::from_be_hex("0748d9d99f59ff1105d314967254398f2b6cedcb87925c23c999e990f3f29c6d") + ); + assert_eq!( + Modulus1::MOD_NEG_INV, + U64::from_be_hex("fffffffeffffffff").limbs[0] + ); + } + + impl_modulus!( + Modulus2, + U256, + "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551" + ); + + #[test] + fn test_reducing_r() { + // Divide the value R by R, which should equal 1 + assert_eq!( + montgomery_reduction::<{ Modulus2::LIMBS }>( + &(Modulus2::R, Uint::ZERO), + &Modulus2::MODULUS, + Modulus2::MOD_NEG_INV + ), + Uint::ONE + ); + } + + #[test] + fn test_reducing_r2() { + // Divide the value R^2 by R, which should equal R + assert_eq!( + montgomery_reduction::<{ Modulus2::LIMBS }>( + &(Modulus2::R2, Uint::ZERO), + &Modulus2::MODULUS, + Modulus2::MOD_NEG_INV + ), + Modulus2::R + ); + } + + #[test] + fn test_reducing_r2_wide() { + // Divide the value R^2 by R, which should equal R + let (hi, lo) = Modulus2::R.square().split(); + assert_eq!( + montgomery_reduction::<{ Modulus2::LIMBS }>( + &(lo, hi), + &Modulus2::MODULUS, + Modulus2::MOD_NEG_INV + ), + Modulus2::R + ); + } + + #[test] + fn test_reducing_xr_wide() { + // Reducing xR should return x + let x = + U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); + let product = x.mul_wide(&Modulus2::R); + assert_eq!( + montgomery_reduction::<{ Modulus2::LIMBS }>( + &product, + &Modulus2::MODULUS, + Modulus2::MOD_NEG_INV + ), + x + ); + } + + #[test] + fn test_reducing_xr2_wide() { + // Reducing xR^2 should return xR + let x = + U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); + let product = x.mul_wide(&Modulus2::R2); + + // Computing xR mod modulus without Montgomery reduction + let (lo, hi) = x.mul_wide(&Modulus2::R); + let c = hi.concat(&lo); + let red = c.rem(&NonZero::new(U256::ZERO.concat(&Modulus2::MODULUS)).unwrap()); + let (hi, lo) = red.split(); + assert_eq!(hi, Uint::ZERO); + + assert_eq!( + montgomery_reduction::<{ Modulus2::LIMBS }>( + &product, + &Modulus2::MODULUS, + Modulus2::MOD_NEG_INV + ), + lo + ); + } + + #[test] + fn test_new_retrieve() { + let x = + U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); + let x_mod = Residue::::new(&x); + + // Confirm that when creating a Modular and retrieving the value, that it equals the original + assert_eq!(x, x_mod.retrieve()); + } + + #[test] + fn test_residue_macro() { + let x = + U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); + assert_eq!( + Residue::::new(&x), + const_residue!(x, Modulus2) + ); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/add.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/add.rs new file mode 100644 index 000000000..f4d0f79d3 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/add.rs @@ -0,0 +1,9 @@ +use crate::Uint; + +pub(crate) const fn add_montgomery_form( + a: &Uint, + b: &Uint, + modulus: &Uint, +) -> Uint { + a.add_mod(b, modulus) +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod.rs new file mode 100644 index 000000000..bb4995501 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod.rs @@ -0,0 +1,254 @@ +use core::{fmt::Debug, marker::PhantomData}; + +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +use crate::{Limb, Uint, Zero}; + +use super::{div_by_2::div_by_2, reduction::montgomery_reduction, Retrieve}; + +#[cfg(feature = "rand_core")] +use crate::{rand_core::CryptoRngCore, NonZero, Random, RandomMod}; + +#[cfg(feature = "serde")] +use { + crate::Encoding, + serdect::serde::de::Error, + serdect::serde::{Deserialize, Deserializer, Serialize, Serializer}, +}; + +/// Additions between residues with a constant modulus +mod const_add; +/// Multiplicative inverses of residues with a constant modulus +mod const_inv; +/// Multiplications between residues with a constant modulus +mod const_mul; +/// Negations of residues with a constant modulus +mod const_neg; +/// Exponentiation of residues with a constant modulus +mod const_pow; +/// Subtractions between residues with a constant modulus +mod const_sub; + +/// Macros to remove the boilerplate code when dealing with constant moduli. +#[macro_use] +mod macros; + +pub use macros::*; + +/// The parameters to efficiently go to and from the Montgomery form for a given odd modulus. An easy way to generate these parameters is using the `impl_modulus!` macro. These parameters are constant, so they cannot be set at runtime. +/// +/// Unfortunately, `LIMBS` must be generic for now until const generics are stabilized. +pub trait ResidueParams: + Copy + Debug + Default + Eq + Send + Sync + 'static +{ + /// Number of limbs required to encode a residue + const LIMBS: usize; + + /// The constant modulus + const MODULUS: Uint; + /// Parameter used in Montgomery reduction + const R: Uint; + /// R^2, used to move into Montgomery form + const R2: Uint; + /// R^3, used to perform a multiplicative inverse + const R3: Uint; + /// The lowest limbs of -(MODULUS^-1) mod R + // We only need the LSB because during reduction this value is multiplied modulo 2**Limb::BITS. + const MOD_NEG_INV: Limb; +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// A residue mod `MOD`, represented using `LIMBS` limbs. The modulus of this residue is constant, so it cannot be set at runtime. +/// Internally, the value is stored in Montgomery form (multiplied by MOD::R) until it is retrieved. +pub struct Residue +where + MOD: ResidueParams, +{ + montgomery_form: Uint, + phantom: PhantomData, +} + +#[cfg(feature = "zeroize")] +impl, const LIMBS: usize> zeroize::DefaultIsZeroes + for Residue +{ +} + +impl, const LIMBS: usize> Residue { + /// The representation of 0 mod `MOD`. + pub const ZERO: Self = Self { + montgomery_form: Uint::::ZERO, + phantom: PhantomData, + }; + + /// The representation of 1 mod `MOD`. + pub const ONE: Self = Self { + montgomery_form: MOD::R, + phantom: PhantomData, + }; + + // Internal helper function to generate a residue; this lets us wrap the constructors more cleanly + const fn generate_residue(integer: &Uint) -> Self { + let product = integer.mul_wide(&MOD::R2); + let montgomery_form = + montgomery_reduction::(&product, &MOD::MODULUS, MOD::MOD_NEG_INV); + + Self { + montgomery_form, + phantom: PhantomData, + } + } + + /// Instantiates a new `Residue` that represents this `integer` mod `MOD`. + /// If the modulus represented by `MOD` is not odd, this function will panic; use [`new_checked`][`Residue::new_checked`] if you want to be able to detect an invalid modulus. + pub const fn new(integer: &Uint) -> Self { + // A valid modulus must be odd + if MOD::MODULUS.ct_is_odd().to_u8() == 0 { + panic!("modulus must be odd"); + } + + Self::generate_residue(integer) + } + + /// Instantiates a new `Residue` that represents this `integer` mod `MOD` if the modulus is odd. + /// Returns a `CtOption` that is `None` if the provided modulus is not odd; this is a safer version of [`new`][`Residue::new`], which can panic. + // TODO: remove this method when we can use `generic_const_exprs.` to ensure the modulus is + // always valid. + pub fn new_checked(integer: &Uint) -> CtOption { + // A valid modulus must be odd. + CtOption::new( + Self::generate_residue(integer), + MOD::MODULUS.ct_is_odd().into(), + ) + } + + /// Retrieves the integer currently encoded in this `Residue`, guaranteed to be reduced. + pub const fn retrieve(&self) -> Uint { + montgomery_reduction::( + &(self.montgomery_form, Uint::ZERO), + &MOD::MODULUS, + MOD::MOD_NEG_INV, + ) + } + + /// Access the `Residue` value in Montgomery form. + pub const fn as_montgomery(&self) -> &Uint { + &self.montgomery_form + } + + /// Mutably access the `Residue` value in Montgomery form. + pub fn as_montgomery_mut(&mut self) -> &mut Uint { + &mut self.montgomery_form + } + + /// Create a `Residue` from a value in Montgomery form. + pub const fn from_montgomery(integer: Uint) -> Self { + Self { + montgomery_form: integer, + phantom: PhantomData, + } + } + + /// Extract the value from the `Residue` in Montgomery form. + pub const fn to_montgomery(&self) -> Uint { + self.montgomery_form + } + + /// Performs the modular division by 2, that is for given `x` returns `y` + /// such that `y * 2 = x mod p`. This means: + /// - if `x` is even, returns `x / 2`, + /// - if `x` is odd, returns `(x + p) / 2` + /// (since the modulus `p` in Montgomery form is always odd, this divides entirely). + pub fn div_by_2(&self) -> Self { + Self { + montgomery_form: div_by_2(&self.montgomery_form, &MOD::MODULUS), + phantom: PhantomData, + } + } +} + +impl + Copy, const LIMBS: usize> ConditionallySelectable + for Residue +{ + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Residue { + montgomery_form: Uint::conditional_select( + &a.montgomery_form, + &b.montgomery_form, + choice, + ), + phantom: PhantomData, + } + } +} + +impl, const LIMBS: usize> ConstantTimeEq for Residue { + fn ct_eq(&self, other: &Self) -> Choice { + ConstantTimeEq::ct_eq(&self.montgomery_form, &other.montgomery_form) + } +} + +impl, const LIMBS: usize> Default for Residue { + fn default() -> Self { + Self::ZERO + } +} + +impl, const LIMBS: usize> Zero for Residue { + const ZERO: Self = Self::ZERO; +} + +#[cfg(feature = "rand_core")] +impl Random for Residue +where + MOD: ResidueParams, +{ + #[inline] + fn random(rng: &mut impl CryptoRngCore) -> Self { + Self::new(&Uint::random_mod(rng, &NonZero::from_uint(MOD::MODULUS))) + } +} + +impl, const LIMBS: usize> Retrieve for Residue { + type Output = Uint; + fn retrieve(&self) -> Self::Output { + self.retrieve() + } +} + +#[cfg(feature = "serde")] +impl<'de, MOD, const LIMBS: usize> Deserialize<'de> for Residue +where + MOD: ResidueParams, + Uint: Encoding, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Uint::::deserialize(deserializer).and_then(|montgomery_form| { + if Uint::ct_lt(&montgomery_form, &MOD::MODULUS).into() { + Ok(Self { + montgomery_form, + phantom: PhantomData, + }) + } else { + Err(D::Error::custom("montgomery form must be reduced")) + } + }) + } +} + +#[cfg(feature = "serde")] +impl Serialize for Residue +where + MOD: ResidueParams, + Uint: Encoding, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.montgomery_form.serialize(serializer) + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_add.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_add.rs new file mode 100644 index 000000000..82eb8826c --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_add.rs @@ -0,0 +1,98 @@ +use core::ops::{Add, AddAssign}; + +use crate::modular::add::add_montgomery_form; + +use super::{Residue, ResidueParams}; + +impl, const LIMBS: usize> Residue { + /// Adds `rhs`. + pub const fn add(&self, rhs: &Residue) -> Self { + Self { + montgomery_form: add_montgomery_form( + &self.montgomery_form, + &rhs.montgomery_form, + &MOD::MODULUS, + ), + phantom: core::marker::PhantomData, + } + } +} + +impl, const LIMBS: usize> Add<&Residue> + for &Residue +{ + type Output = Residue; + fn add(self, rhs: &Residue) -> Residue { + self.add(rhs) + } +} + +impl, const LIMBS: usize> Add> + for &Residue +{ + type Output = Residue; + #[allow(clippy::op_ref)] + fn add(self, rhs: Residue) -> Residue { + self + &rhs + } +} + +impl, const LIMBS: usize> Add<&Residue> + for Residue +{ + type Output = Residue; + #[allow(clippy::op_ref)] + fn add(self, rhs: &Residue) -> Residue { + &self + rhs + } +} + +impl, const LIMBS: usize> Add> + for Residue +{ + type Output = Residue; + fn add(self, rhs: Residue) -> Residue { + &self + &rhs + } +} + +impl, const LIMBS: usize> AddAssign<&Self> for Residue { + fn add_assign(&mut self, rhs: &Self) { + *self = *self + rhs; + } +} + +impl, const LIMBS: usize> AddAssign for Residue { + fn add_assign(&mut self, rhs: Self) { + *self += &rhs; + } +} + +#[cfg(test)] +mod tests { + use crate::{const_residue, impl_modulus, modular::constant_mod::ResidueParams, U256}; + + impl_modulus!( + Modulus, + U256, + "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551" + ); + + #[test] + fn add_overflow() { + let x = + U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); + let mut x_mod = const_residue!(x, Modulus); + + let y = + U256::from_be_hex("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"); + let y_mod = const_residue!(y, Modulus); + + x_mod += &y_mod; + + let expected = + U256::from_be_hex("1a2472fde50286541d97ca6a3592dd75beb9c9646e40c511b82496cfc3926956"); + + assert_eq!(expected, x_mod.retrieve()); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_inv.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_inv.rs new file mode 100644 index 000000000..28f0622e2 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_inv.rs @@ -0,0 +1,69 @@ +use core::marker::PhantomData; + +use subtle::CtOption; + +use crate::{modular::inv::inv_montgomery_form, traits::Invert, CtChoice, NonZero}; + +use super::{Residue, ResidueParams}; + +impl, const LIMBS: usize> Residue { + /// Computes the residue `self^-1` representing the multiplicative inverse of `self`. + /// I.e. `self * self^-1 = 1`. + /// If the number was invertible, the second element of the tuple is the truthy value, + /// otherwise it is the falsy value (in which case the first element's value is unspecified). + pub const fn invert(&self) -> (Self, CtChoice) { + let (montgomery_form, is_some) = inv_montgomery_form( + &self.montgomery_form, + &MOD::MODULUS, + &MOD::R3, + MOD::MOD_NEG_INV, + ); + + let value = Self { + montgomery_form, + phantom: PhantomData, + }; + + (value, is_some) + } +} + +impl, const LIMBS: usize> Invert for Residue { + type Output = CtOption; + fn invert(&self) -> Self::Output { + let (value, is_some) = self.invert(); + CtOption::new(value, is_some.into()) + } +} + +impl, const LIMBS: usize> Invert for NonZero> { + type Output = Self; + fn invert(&self) -> Self::Output { + // Always succeeds for a non-zero argument + let (value, _is_some) = self.as_ref().invert(); + NonZero::new(value).unwrap() + } +} + +#[cfg(test)] +mod tests { + use crate::{const_residue, impl_modulus, modular::constant_mod::ResidueParams, U256}; + + impl_modulus!( + Modulus, + U256, + "15477BCCEFE197328255BFA79A1217899016D927EF460F4FF404029D24FA4409" + ); + + #[test] + fn test_self_inverse() { + let x = + U256::from_be_hex("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685"); + let x_mod = const_residue!(x, Modulus); + + let (inv, _is_some) = x_mod.invert(); + let res = x_mod * inv; + + assert_eq!(res.retrieve(), U256::ONE); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_mul.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_mul.rs new file mode 100644 index 000000000..3bce1848a --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_mul.rs @@ -0,0 +1,94 @@ +use core::{ + marker::PhantomData, + ops::{Mul, MulAssign}, +}; + +use crate::{ + modular::mul::{mul_montgomery_form, square_montgomery_form}, + traits::Square, +}; + +use super::{Residue, ResidueParams}; + +impl, const LIMBS: usize> Residue { + /// Multiplies by `rhs`. + pub const fn mul(&self, rhs: &Self) -> Self { + Self { + montgomery_form: mul_montgomery_form( + &self.montgomery_form, + &rhs.montgomery_form, + &MOD::MODULUS, + MOD::MOD_NEG_INV, + ), + phantom: PhantomData, + } + } + + /// Computes the (reduced) square of a residue. + pub const fn square(&self) -> Self { + Self { + montgomery_form: square_montgomery_form( + &self.montgomery_form, + &MOD::MODULUS, + MOD::MOD_NEG_INV, + ), + phantom: PhantomData, + } + } +} + +impl, const LIMBS: usize> Mul<&Residue> + for &Residue +{ + type Output = Residue; + fn mul(self, rhs: &Residue) -> Residue { + self.mul(rhs) + } +} + +impl, const LIMBS: usize> Mul> + for &Residue +{ + type Output = Residue; + #[allow(clippy::op_ref)] + fn mul(self, rhs: Residue) -> Residue { + self * &rhs + } +} + +impl, const LIMBS: usize> Mul<&Residue> + for Residue +{ + type Output = Residue; + #[allow(clippy::op_ref)] + fn mul(self, rhs: &Residue) -> Residue { + &self * rhs + } +} + +impl, const LIMBS: usize> Mul> + for Residue +{ + type Output = Residue; + fn mul(self, rhs: Residue) -> Residue { + &self * &rhs + } +} + +impl, const LIMBS: usize> MulAssign<&Self> for Residue { + fn mul_assign(&mut self, rhs: &Residue) { + *self = *self * rhs; + } +} + +impl, const LIMBS: usize> MulAssign for Residue { + fn mul_assign(&mut self, rhs: Self) { + *self *= &rhs; + } +} + +impl, const LIMBS: usize> Square for Residue { + fn square(&self) -> Self { + Residue::square(self) + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_neg.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_neg.rs new file mode 100644 index 000000000..1981f5a20 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_neg.rs @@ -0,0 +1,48 @@ +use core::ops::Neg; + +use super::{Residue, ResidueParams}; + +impl, const LIMBS: usize> Residue { + /// Negates the number. + pub const fn neg(&self) -> Self { + Self::ZERO.sub(self) + } +} + +impl, const LIMBS: usize> Neg for Residue { + type Output = Self; + fn neg(self) -> Self { + Residue::neg(&self) + } +} + +impl, const LIMBS: usize> Neg for &Residue { + type Output = Residue; + fn neg(self) -> Residue { + Residue::neg(self) + } +} + +#[cfg(test)] +mod tests { + use crate::{const_residue, impl_modulus, modular::constant_mod::ResidueParams, U256}; + + impl_modulus!( + Modulus, + U256, + "15477BCCEFE197328255BFA79A1217899016D927EF460F4FF404029D24FA4409" + ); + + #[test] + fn test_negate() { + let x = + U256::from_be_hex("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685"); + let x_mod = const_residue!(x, Modulus); + + let res = -x_mod; + let expected = + U256::from_be_hex("089B67BB2C124F084701AD76E8750D321385E35044C74CE457301A2A9BE061B1"); + + assert_eq!(res.retrieve(), expected); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_pow.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_pow.rs new file mode 100644 index 000000000..803eac69c --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_pow.rs @@ -0,0 +1,233 @@ +use crate::{modular::pow::pow_montgomery_form, MultiExponentiateBoundedExp, PowBoundedExp, Uint}; + +use super::{Residue, ResidueParams}; +use crate::modular::pow::multi_exponentiate_montgomery_form_array; +#[cfg(feature = "alloc")] +use crate::modular::pow::multi_exponentiate_montgomery_form_slice; +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +impl, const LIMBS: usize> Residue { + /// Raises to the `exponent` power. + pub const fn pow( + &self, + exponent: &Uint, + ) -> Residue { + self.pow_bounded_exp(exponent, Uint::::BITS) + } + + /// Raises to the `exponent` power, + /// with `exponent_bits` representing the number of (least significant) bits + /// to take into account for the exponent. + /// + /// NOTE: `exponent_bits` may be leaked in the time pattern. + pub const fn pow_bounded_exp( + &self, + exponent: &Uint, + exponent_bits: usize, + ) -> Residue { + Self { + montgomery_form: pow_montgomery_form( + &self.montgomery_form, + exponent, + exponent_bits, + &MOD::MODULUS, + &MOD::R, + MOD::MOD_NEG_INV, + ), + phantom: core::marker::PhantomData, + } + } +} + +impl, const LIMBS: usize, const RHS_LIMBS: usize> + PowBoundedExp> for Residue +{ + fn pow_bounded_exp(&self, exponent: &Uint, exponent_bits: usize) -> Self { + self.pow_bounded_exp(exponent, exponent_bits) + } +} + +impl, const LIMBS: usize, const RHS_LIMBS: usize> + MultiExponentiateBoundedExp, [(Self, Uint); N]> + for Residue +{ + fn multi_exponentiate_bounded_exp( + bases_and_exponents: &[(Self, Uint); N], + exponent_bits: usize, + ) -> Self { + let mut bases_and_exponents_montgomery_form = + [(Uint::::ZERO, Uint::::ZERO); N]; + + let mut i = 0; + while i < N { + let (base, exponent) = bases_and_exponents[i]; + bases_and_exponents_montgomery_form[i] = (base.montgomery_form, exponent); + i += 1; + } + + Self { + montgomery_form: multi_exponentiate_montgomery_form_array( + &bases_and_exponents_montgomery_form, + exponent_bits, + &MOD::MODULUS, + &MOD::R, + MOD::MOD_NEG_INV, + ), + phantom: core::marker::PhantomData, + } + } +} + +#[cfg(feature = "alloc")] +impl, const LIMBS: usize, const RHS_LIMBS: usize> + MultiExponentiateBoundedExp, [(Self, Uint)]> + for Residue +{ + fn multi_exponentiate_bounded_exp( + bases_and_exponents: &[(Self, Uint)], + exponent_bits: usize, + ) -> Self { + let bases_and_exponents: Vec<(Uint, Uint)> = bases_and_exponents + .iter() + .map(|(base, exp)| (base.montgomery_form, *exp)) + .collect(); + Self { + montgomery_form: multi_exponentiate_montgomery_form_slice( + &bases_and_exponents, + exponent_bits, + &MOD::MODULUS, + &MOD::R, + MOD::MOD_NEG_INV, + ), + phantom: core::marker::PhantomData, + } + } +} + +#[cfg(test)] +mod tests { + use crate::traits::MultiExponentiate; + use crate::{const_residue, impl_modulus, modular::constant_mod::ResidueParams, U256}; + + impl_modulus!( + Modulus, + U256, + "9CC24C5DF431A864188AB905AC751B727C9447A8E99E6366E1AD78A21E8D882B" + ); + + #[test] + fn test_powmod_small_base() { + let base = U256::from(105u64); + let base_mod = const_residue!(base, Modulus); + + let exponent = + U256::from_be_hex("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685"); + + let res = base_mod.pow(&exponent); + + let expected = + U256::from_be_hex("7B2CD7BDDD96C271E6F232F2F415BB03FE2A90BD6CCCEA5E94F1BFD064993766"); + assert_eq!(res.retrieve(), expected); + } + + #[test] + fn test_powmod_small_exponent() { + let base = + U256::from_be_hex("3435D18AA8313EBBE4D20002922225B53F75DC4453BB3EEC0378646F79B524A4"); + let base_mod = const_residue!(base, Modulus); + + let exponent = U256::from(105u64); + + let res = base_mod.pow(&exponent); + + let expected = + U256::from_be_hex("89E2A4E99F649A5AE2C18068148C355CA927B34A3245C938178ED00D6EF218AA"); + assert_eq!(res.retrieve(), expected); + } + + #[test] + fn test_powmod() { + let base = + U256::from_be_hex("3435D18AA8313EBBE4D20002922225B53F75DC4453BB3EEC0378646F79B524A4"); + let base_mod = const_residue!(base, Modulus); + + let exponent = + U256::from_be_hex("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685"); + + let res = base_mod.pow(&exponent); + + let expected = + U256::from_be_hex("3681BC0FEA2E5D394EB178155A127B0FD2EF405486D354251C385BDD51B9D421"); + assert_eq!(res.retrieve(), expected); + } + + #[test] + fn test_multi_exp_array() { + let base = U256::from(2u8); + let base_mod = const_residue!(base, Modulus); + + let exponent = U256::from(33u8); + let bases_and_exponents = [(base_mod, exponent)]; + let res = + crate::modular::constant_mod::Residue::::multi_exponentiate( + &bases_and_exponents, + ); + + let expected = + U256::from_be_hex("0000000000000000000000000000000000000000000000000000000200000000"); + + assert_eq!(res.retrieve(), expected); + + let base2 = + U256::from_be_hex("3435D18AA8313EBBE4D20002922225B53F75DC4453BB3EEC0378646F79B524A4"); + let base2_mod = const_residue!(base2, Modulus); + + let exponent2 = + U256::from_be_hex("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685"); + + let expected = base_mod.pow(&exponent) * base2_mod.pow(&exponent2); + let bases_and_exponents = [(base_mod, exponent), (base2_mod, exponent2)]; + let res = + crate::modular::constant_mod::Residue::::multi_exponentiate( + &bases_and_exponents, + ); + + assert_eq!(res, expected); + } + + #[cfg(feature = "alloc")] + #[test] + fn test_multi_exp_slice() { + let base = U256::from(2u8); + let base_mod = const_residue!(base, Modulus); + + let exponent = U256::from(33u8); + let bases_and_exponents = vec![(base_mod, exponent)]; + let res = + crate::modular::constant_mod::Residue::::multi_exponentiate( + bases_and_exponents.as_slice(), + ); + + let expected = + U256::from_be_hex("0000000000000000000000000000000000000000000000000000000200000000"); + + assert_eq!(res.retrieve(), expected); + + let base2 = + U256::from_be_hex("3435D18AA8313EBBE4D20002922225B53F75DC4453BB3EEC0378646F79B524A4"); + let base2_mod = const_residue!(base2, Modulus); + + let exponent2 = + U256::from_be_hex("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685"); + + let expected = base_mod.pow(&exponent) * base2_mod.pow(&exponent2); + let bases_and_exponents = vec![(base_mod, exponent), (base2_mod, exponent2)]; + let res = + crate::modular::constant_mod::Residue::::multi_exponentiate( + bases_and_exponents.as_slice(), + ); + + assert_eq!(res, expected); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_sub.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_sub.rs new file mode 100644 index 000000000..f65061146 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/const_sub.rs @@ -0,0 +1,98 @@ +use core::ops::{Sub, SubAssign}; + +use crate::modular::sub::sub_montgomery_form; + +use super::{Residue, ResidueParams}; + +impl, const LIMBS: usize> Residue { + /// Subtracts `rhs`. + pub const fn sub(&self, rhs: &Self) -> Self { + Self { + montgomery_form: sub_montgomery_form( + &self.montgomery_form, + &rhs.montgomery_form, + &MOD::MODULUS, + ), + phantom: core::marker::PhantomData, + } + } +} + +impl, const LIMBS: usize> Sub<&Residue> + for &Residue +{ + type Output = Residue; + fn sub(self, rhs: &Residue) -> Residue { + self.sub(rhs) + } +} + +impl, const LIMBS: usize> Sub> + for &Residue +{ + type Output = Residue; + #[allow(clippy::op_ref)] + fn sub(self, rhs: Residue) -> Residue { + self - &rhs + } +} + +impl, const LIMBS: usize> Sub<&Residue> + for Residue +{ + type Output = Residue; + #[allow(clippy::op_ref)] + fn sub(self, rhs: &Residue) -> Residue { + &self - rhs + } +} + +impl, const LIMBS: usize> Sub> + for Residue +{ + type Output = Residue; + fn sub(self, rhs: Residue) -> Residue { + &self - &rhs + } +} + +impl, const LIMBS: usize> SubAssign<&Self> for Residue { + fn sub_assign(&mut self, rhs: &Self) { + *self = *self - rhs; + } +} + +impl, const LIMBS: usize> SubAssign for Residue { + fn sub_assign(&mut self, rhs: Self) { + *self -= &rhs; + } +} + +#[cfg(test)] +mod tests { + use crate::{const_residue, impl_modulus, modular::constant_mod::ResidueParams, U256}; + + impl_modulus!( + Modulus, + U256, + "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551" + ); + + #[test] + fn sub_overflow() { + let x = + U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); + let mut x_mod = const_residue!(x, Modulus); + + let y = + U256::from_be_hex("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"); + let y_mod = const_residue!(y, Modulus); + + x_mod -= &y_mod; + + let expected = + U256::from_be_hex("6f357a71e1d5a03167f34879d469352add829491c6df41ddff65387d7ed56f56"); + + assert_eq!(expected, x_mod.retrieve()); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/macros.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/macros.rs new file mode 100644 index 000000000..dfa440e02 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/constant_mod/macros.rs @@ -0,0 +1,57 @@ +// TODO: Use `adt_const_params` once stabilized to make a `Residue` generic around a modulus rather than having to implement a ZST + trait +#[macro_export] +/// Implements a modulus with the given name, type, and value, in that specific order. Please `use crypto_bigint::traits::Encoding` to make this work. +/// For example, `impl_modulus!(MyModulus, U256, "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001");` implements a 256-bit modulus named `MyModulus`. +/// The modulus _must_ be odd, or this will panic. +macro_rules! impl_modulus { + ($name:ident, $uint_type:ty, $value:expr) => { + #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] + pub struct $name {} + impl + $crate::modular::constant_mod::ResidueParams<{ <$uint_type>::LIMBS }> for $name + where + $uint_type: $crate::ConcatMixed>, + { + const LIMBS: usize = <$uint_type>::LIMBS; + const MODULUS: $uint_type = { + let res = <$uint_type>::from_be_hex($value); + + // Check that the modulus is odd + if res.as_limbs()[0].0 & 1 == 0 { + panic!("modulus must be odd"); + } + + res + }; + const R: $uint_type = $crate::Uint::MAX + .const_rem(&Self::MODULUS) + .0 + .wrapping_add(&$crate::Uint::ONE); + const R2: $uint_type = + $crate::Uint::const_rem_wide(Self::R.square_wide(), &Self::MODULUS).0; + const MOD_NEG_INV: $crate::Limb = $crate::Limb( + $crate::Word::MIN.wrapping_sub( + Self::MODULUS + .inv_mod2k_vartime($crate::Word::BITS as usize) + .as_limbs()[0] + .0, + ), + ); + const R3: $uint_type = $crate::modular::montgomery_reduction( + &Self::R2.square_wide(), + &Self::MODULUS, + Self::MOD_NEG_INV, + ); + } + }; +} + +#[macro_export] +/// Creates a `Residue` with the given value for a specific modulus. +/// For example, `residue!(U256::from(105u64), MyModulus);` creates a `Residue` for 105 mod `MyModulus`. +/// The modulus _must_ be odd, or this will panic. +macro_rules! const_residue { + ($variable:ident, $modulus:ident) => { + $crate::modular::constant_mod::Residue::<$modulus, { $modulus::LIMBS }>::new(&$variable) + }; +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/div_by_2.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/div_by_2.rs new file mode 100644 index 000000000..20c0a5d86 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/div_by_2.rs @@ -0,0 +1,30 @@ +use crate::Uint; + +pub(crate) fn div_by_2(a: &Uint, modulus: &Uint) -> Uint { + // We are looking for such `x` that `x * 2 = y mod modulus`, + // where the given `a = M(y)` is the Montgomery representation of some `y`. + // This means that in Montgomery representation it would still apply: + // `M(x) + M(x) = a mod modulus`. + // So we can just forget about Montgomery representation, and return whatever is + // `a` divided by 2, and this will be the Montgomery representation of `x`. + // (Which means that this function works regardless of whether `a` + // is in Montgomery representation or not, but the algorithm below + // does need `modulus` to be odd) + + // Two possibilities: + // - if `a` is even, we can just divide by 2; + // - if `a` is odd, we divide `(a + modulus)` by 2. + // To stay within the modulus we open the parentheses turning it into `a / 2 + modulus / 2 + 1` + // ("+1" because both `a` and `modulus` are odd, we lose 0.5 in each integer division). + // This will not overflow, so we can just use wrapping operations. + + let (half, is_odd) = a.shr_1(); + let half_modulus = modulus.shr_vartime(1); + + let if_even = half; + let if_odd = half + .wrapping_add(&half_modulus) + .wrapping_add(&Uint::::ONE); + + Uint::::ct_select(&if_even, &if_odd, is_odd) +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/inv.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/inv.rs new file mode 100644 index 000000000..408c03fb8 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/inv.rs @@ -0,0 +1,14 @@ +use crate::{modular::reduction::montgomery_reduction, CtChoice, Limb, Uint}; + +pub const fn inv_montgomery_form( + x: &Uint, + modulus: &Uint, + r3: &Uint, + mod_neg_inv: Limb, +) -> (Uint, CtChoice) { + let (inverse, is_some) = x.inv_odd_mod(modulus); + ( + montgomery_reduction(&inverse.mul_wide(r3), modulus, mod_neg_inv), + is_some, + ) +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/mul.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/mul.rs new file mode 100644 index 000000000..b84ceb5ca --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/mul.rs @@ -0,0 +1,22 @@ +use crate::{Limb, Uint}; + +use super::reduction::montgomery_reduction; + +pub(crate) const fn mul_montgomery_form( + a: &Uint, + b: &Uint, + modulus: &Uint, + mod_neg_inv: Limb, +) -> Uint { + let product = a.mul_wide(b); + montgomery_reduction::(&product, modulus, mod_neg_inv) +} + +pub(crate) const fn square_montgomery_form( + a: &Uint, + modulus: &Uint, + mod_neg_inv: Limb, +) -> Uint { + let product = a.square_wide(); + montgomery_reduction::(&product, modulus, mod_neg_inv) +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/pow.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/pow.rs new file mode 100644 index 000000000..f09bc4c6c --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/pow.rs @@ -0,0 +1,178 @@ +use crate::{Limb, Uint, Word}; + +use super::mul::{mul_montgomery_form, square_montgomery_form}; + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +const WINDOW: usize = 4; +const WINDOW_MASK: Word = (1 << WINDOW) - 1; + +/// Performs modular exponentiation using Montgomery's ladder. +/// `exponent_bits` represents the number of bits to take into account for the exponent. +/// +/// NOTE: this value is leaked in the time pattern. +pub const fn pow_montgomery_form( + x: &Uint, + exponent: &Uint, + exponent_bits: usize, + modulus: &Uint, + r: &Uint, + mod_neg_inv: Limb, +) -> Uint { + multi_exponentiate_montgomery_form_array( + &[(*x, *exponent)], + exponent_bits, + modulus, + r, + mod_neg_inv, + ) +} + +pub const fn multi_exponentiate_montgomery_form_array< + const LIMBS: usize, + const RHS_LIMBS: usize, + const N: usize, +>( + bases_and_exponents: &[(Uint, Uint); N], + exponent_bits: usize, + modulus: &Uint, + r: &Uint, + mod_neg_inv: Limb, +) -> Uint { + if exponent_bits == 0 { + return *r; // 1 in Montgomery form + } + + let mut powers_and_exponents = + [([Uint::::ZERO; 1 << WINDOW], Uint::::ZERO); N]; + + let mut i = 0; + while i < N { + let (base, exponent) = bases_and_exponents[i]; + powers_and_exponents[i] = (compute_powers(&base, modulus, r, mod_neg_inv), exponent); + i += 1; + } + + multi_exponentiate_montgomery_form_internal( + &powers_and_exponents, + exponent_bits, + modulus, + r, + mod_neg_inv, + ) +} + +/// Performs modular multi-exponentiation using Montgomery's ladder. +/// `exponent_bits` represents the number of bits to take into account for the exponent. +/// +/// See: Straus, E. G. Problems and solutions: Addition chains of vectors. American Mathematical Monthly 71 (1964), 806–808. +/// +/// NOTE: this value is leaked in the time pattern. +#[cfg(feature = "alloc")] +pub fn multi_exponentiate_montgomery_form_slice( + bases_and_exponents: &[(Uint, Uint)], + exponent_bits: usize, + modulus: &Uint, + r: &Uint, + mod_neg_inv: Limb, +) -> Uint { + if exponent_bits == 0 { + return *r; // 1 in Montgomery form + } + + let powers_and_exponents: Vec<([Uint; 1 << WINDOW], Uint)> = + bases_and_exponents + .iter() + .map(|(base, exponent)| (compute_powers(base, modulus, r, mod_neg_inv), *exponent)) + .collect(); + + multi_exponentiate_montgomery_form_internal( + powers_and_exponents.as_slice(), + exponent_bits, + modulus, + r, + mod_neg_inv, + ) +} + +const fn compute_powers( + x: &Uint, + modulus: &Uint, + r: &Uint, + mod_neg_inv: Limb, +) -> [Uint; 1 << WINDOW] { + // powers[i] contains x^i + let mut powers = [*r; 1 << WINDOW]; + powers[1] = *x; + + let mut i = 2; + while i < powers.len() { + powers[i] = mul_montgomery_form(&powers[i - 1], x, modulus, mod_neg_inv); + i += 1; + } + + powers +} + +const fn multi_exponentiate_montgomery_form_internal( + powers_and_exponents: &[([Uint; 1 << WINDOW], Uint)], + exponent_bits: usize, + modulus: &Uint, + r: &Uint, + mod_neg_inv: Limb, +) -> Uint { + let starting_limb = (exponent_bits - 1) / Limb::BITS; + let starting_bit_in_limb = (exponent_bits - 1) % Limb::BITS; + let starting_window = starting_bit_in_limb / WINDOW; + let starting_window_mask = (1 << (starting_bit_in_limb % WINDOW + 1)) - 1; + + let mut z = *r; // 1 in Montgomery form + + let mut limb_num = starting_limb + 1; + while limb_num > 0 { + limb_num -= 1; + + let mut window_num = if limb_num == starting_limb { + starting_window + 1 + } else { + Limb::BITS / WINDOW + }; + while window_num > 0 { + window_num -= 1; + + if limb_num != starting_limb || window_num != starting_window { + let mut i = 0; + while i < WINDOW { + i += 1; + z = square_montgomery_form(&z, modulus, mod_neg_inv); + } + } + + let mut i = 0; + while i < powers_and_exponents.len() { + let (powers, exponent) = powers_and_exponents[i]; + let w = exponent.as_limbs()[limb_num].0; + let mut idx = (w >> (window_num * WINDOW)) & WINDOW_MASK; + + if limb_num == starting_limb && window_num == starting_window { + idx &= starting_window_mask; + } + + // Constant-time lookup in the array of powers + let mut power = powers[0]; + let mut j = 1; + while j < 1 << WINDOW { + let choice = Limb::ct_eq(Limb(j as Word), Limb(idx)); + power = Uint::::ct_select(&power, &powers[j], choice); + j += 1; + } + + z = mul_montgomery_form(&z, &power, modulus, mod_neg_inv); + i += 1; + } + } + } + + z +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/reduction.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/reduction.rs new file mode 100644 index 000000000..b206ae32f --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/reduction.rs @@ -0,0 +1,55 @@ +use crate::{Limb, Uint, WideWord, Word}; + +/// Returns `(hi, lo)` such that `hi * R + lo = x * y + z + w`. +#[inline(always)] +const fn muladdcarry(x: Word, y: Word, z: Word, w: Word) -> (Word, Word) { + let res = (x as WideWord) + .wrapping_mul(y as WideWord) + .wrapping_add(z as WideWord) + .wrapping_add(w as WideWord); + ((res >> Word::BITS) as Word, res as Word) +} + +/// Algorithm 14.32 in Handbook of Applied Cryptography +pub const fn montgomery_reduction( + lower_upper: &(Uint, Uint), + modulus: &Uint, + mod_neg_inv: Limb, +) -> Uint { + let (mut lower, mut upper) = *lower_upper; + + let mut meta_carry = Limb(0); + let mut new_sum; + + let mut i = 0; + while i < LIMBS { + let u = lower.limbs[i].0.wrapping_mul(mod_neg_inv.0); + + let (mut carry, _) = muladdcarry(u, modulus.limbs[0].0, lower.limbs[i].0, 0); + let mut new_limb; + + let mut j = 1; + while j < (LIMBS - i) { + (carry, new_limb) = muladdcarry(u, modulus.limbs[j].0, lower.limbs[i + j].0, carry); + lower.limbs[i + j] = Limb(new_limb); + j += 1; + } + while j < LIMBS { + (carry, new_limb) = + muladdcarry(u, modulus.limbs[j].0, upper.limbs[i + j - LIMBS].0, carry); + upper.limbs[i + j - LIMBS] = Limb(new_limb); + j += 1; + } + + (new_sum, meta_carry) = upper.limbs[i].adc(Limb(carry), meta_carry); + upper.limbs[i] = new_sum; + + i += 1; + } + + // Division is simply taking the upper half of the limbs + // Final reduction (at this point, the value is at most 2 * modulus, + // so `meta_carry` is either 0 or 1) + + upper.sub_mod_with_carry(meta_carry, modulus, modulus) +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod.rs new file mode 100644 index 000000000..9f15afe07 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod.rs @@ -0,0 +1,300 @@ +use crate::{Limb, Uint, Word}; + +use super::{ + constant_mod::{Residue, ResidueParams}, + div_by_2::div_by_2, + reduction::montgomery_reduction, + Retrieve, +}; + +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +/// Additions between residues with a modulus set at runtime +mod runtime_add; +/// Multiplicative inverses of residues with a modulus set at runtime +mod runtime_inv; +/// Multiplications between residues with a modulus set at runtime +mod runtime_mul; +/// Negations of residues with a modulus set at runtime +mod runtime_neg; +/// Exponentiation of residues with a modulus set at runtime +mod runtime_pow; +/// Subtractions between residues with a modulus set at runtime +mod runtime_sub; + +/// The parameters to efficiently go to and from the Montgomery form for an odd modulus provided at runtime. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DynResidueParams { + // The constant modulus + modulus: Uint, + // Parameter used in Montgomery reduction + r: Uint, + // R^2, used to move into Montgomery form + r2: Uint, + // R^3, used to compute the multiplicative inverse + r3: Uint, + // The lowest limbs of -(MODULUS^-1) mod R + // We only need the LSB because during reduction this value is multiplied modulo 2**Limb::BITS. + mod_neg_inv: Limb, +} + +impl DynResidueParams { + // Internal helper function to generate parameters; this lets us wrap the constructors more cleanly + const fn generate_params(modulus: &Uint) -> Self { + let r = Uint::MAX.const_rem(modulus).0.wrapping_add(&Uint::ONE); + let r2 = Uint::const_rem_wide(r.square_wide(), modulus).0; + + // Since we are calculating the inverse modulo (Word::MAX+1), + // we can take the modulo right away and calculate the inverse of the first limb only. + let modulus_lo = Uint::<1>::from_words([modulus.limbs[0].0]); + let mod_neg_inv = Limb( + Word::MIN.wrapping_sub(modulus_lo.inv_mod2k_vartime(Word::BITS as usize).limbs[0].0), + ); + + let r3 = montgomery_reduction(&r2.square_wide(), modulus, mod_neg_inv); + + Self { + modulus: *modulus, + r, + r2, + r3, + mod_neg_inv, + } + } + + /// Instantiates a new set of `ResidueParams` representing the given `modulus`, which _must_ be odd. + /// If `modulus` is not odd, this function will panic; use [`new_checked`][`DynResidueParams::new_checked`] if you want to be able to detect an invalid modulus. + pub const fn new(modulus: &Uint) -> Self { + // A valid modulus must be odd + if modulus.ct_is_odd().to_u8() == 0 { + panic!("modulus must be odd"); + } + + Self::generate_params(modulus) + } + + /// Instantiates a new set of `ResidueParams` representing the given `modulus` if it is odd. + /// Returns a `CtOption` that is `None` if the provided modulus is not odd; this is a safer version of [`new`][`DynResidueParams::new`], which can panic. + #[deprecated( + since = "0.5.3", + note = "This functionality will be moved to `new` in a future release." + )] + pub fn new_checked(modulus: &Uint) -> CtOption { + // A valid modulus must be odd. + CtOption::new(Self::generate_params(modulus), modulus.ct_is_odd().into()) + } + + /// Returns the modulus which was used to initialize these parameters. + pub const fn modulus(&self) -> &Uint { + &self.modulus + } + + /// Create `DynResidueParams` corresponding to a `ResidueParams`. + pub const fn from_residue_params

() -> Self + where + P: ResidueParams, + { + Self { + modulus: P::MODULUS, + r: P::R, + r2: P::R2, + r3: P::R3, + mod_neg_inv: P::MOD_NEG_INV, + } + } +} + +impl ConditionallySelectable for DynResidueParams { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self { + modulus: Uint::conditional_select(&a.modulus, &b.modulus, choice), + r: Uint::conditional_select(&a.r, &b.r, choice), + r2: Uint::conditional_select(&a.r2, &b.r2, choice), + r3: Uint::conditional_select(&a.r3, &b.r3, choice), + mod_neg_inv: Limb::conditional_select(&a.mod_neg_inv, &b.mod_neg_inv, choice), + } + } +} + +impl ConstantTimeEq for DynResidueParams { + fn ct_eq(&self, other: &Self) -> Choice { + self.modulus.ct_eq(&other.modulus) + & self.r.ct_eq(&other.r) + & self.r2.ct_eq(&other.r2) + & self.r3.ct_eq(&other.r3) + & self.mod_neg_inv.ct_eq(&other.mod_neg_inv) + } +} + +/// A residue represented using `LIMBS` limbs. The odd modulus of this residue is set at runtime. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DynResidue { + montgomery_form: Uint, + residue_params: DynResidueParams, +} + +impl DynResidue { + /// Instantiates a new `Residue` that represents this `integer` mod `MOD`. + pub const fn new(integer: &Uint, residue_params: DynResidueParams) -> Self { + let product = integer.mul_wide(&residue_params.r2); + let montgomery_form = montgomery_reduction( + &product, + &residue_params.modulus, + residue_params.mod_neg_inv, + ); + + Self { + montgomery_form, + residue_params, + } + } + + /// Retrieves the integer currently encoded in this `Residue`, guaranteed to be reduced. + pub const fn retrieve(&self) -> Uint { + montgomery_reduction( + &(self.montgomery_form, Uint::ZERO), + &self.residue_params.modulus, + self.residue_params.mod_neg_inv, + ) + } + + /// Instantiates a new `Residue` that represents zero. + pub const fn zero(residue_params: DynResidueParams) -> Self { + Self { + montgomery_form: Uint::::ZERO, + residue_params, + } + } + + /// Instantiates a new `Residue` that represents 1. + pub const fn one(residue_params: DynResidueParams) -> Self { + Self { + montgomery_form: residue_params.r, + residue_params, + } + } + + /// Returns the parameter struct used to initialize this residue. + pub const fn params(&self) -> &DynResidueParams { + &self.residue_params + } + + /// Access the `DynResidue` value in Montgomery form. + pub const fn as_montgomery(&self) -> &Uint { + &self.montgomery_form + } + + /// Mutably access the `DynResidue` value in Montgomery form. + pub fn as_montgomery_mut(&mut self) -> &mut Uint { + &mut self.montgomery_form + } + + /// Create a `DynResidue` from a value in Montgomery form. + pub const fn from_montgomery( + integer: Uint, + residue_params: DynResidueParams, + ) -> Self { + Self { + montgomery_form: integer, + residue_params, + } + } + + /// Extract the value from the `DynResidue` in Montgomery form. + pub const fn to_montgomery(&self) -> Uint { + self.montgomery_form + } + + /// Performs the modular division by 2, that is for given `x` returns `y` + /// such that `y * 2 = x mod p`. This means: + /// - if `x` is even, returns `x / 2`, + /// - if `x` is odd, returns `(x + p) / 2` + /// (since the modulus `p` in Montgomery form is always odd, this divides entirely). + pub fn div_by_2(&self) -> Self { + Self { + montgomery_form: div_by_2(&self.montgomery_form, &self.residue_params.modulus), + residue_params: self.residue_params, + } + } +} + +impl Retrieve for DynResidue { + type Output = Uint; + fn retrieve(&self) -> Self::Output { + self.retrieve() + } +} + +impl> From<&Residue> for DynResidue { + fn from(residue: &Residue) -> Self { + Self { + montgomery_form: residue.to_montgomery(), + residue_params: DynResidueParams::from_residue_params::

(), + } + } +} + +impl ConditionallySelectable for DynResidue { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self { + montgomery_form: Uint::conditional_select( + &a.montgomery_form, + &b.montgomery_form, + choice, + ), + residue_params: DynResidueParams::conditional_select( + &a.residue_params, + &b.residue_params, + choice, + ), + } + } +} + +impl ConstantTimeEq for DynResidue { + fn ct_eq(&self, other: &Self) -> Choice { + self.montgomery_form.ct_eq(&other.montgomery_form) + & self.residue_params.ct_eq(&other.residue_params) + } +} + +/// NOTE: this does _not_ zeroize the parameters, in order to maintain some form of type consistency +#[cfg(feature = "zeroize")] +impl zeroize::Zeroize for DynResidue { + fn zeroize(&mut self) { + self.montgomery_form.zeroize() + } +} + +#[cfg(test)] +mod test { + use super::*; + + const LIMBS: usize = nlimbs!(64); + + #[test] + #[allow(deprecated)] + // Test that a valid modulus yields `DynResidueParams` + fn test_valid_modulus() { + let valid_modulus = Uint::::from(3u8); + + DynResidueParams::::new_checked(&valid_modulus).unwrap(); + DynResidueParams::::new(&valid_modulus); + } + + #[test] + #[allow(deprecated)] + // Test that an invalid checked modulus does not yield `DynResidueParams` + fn test_invalid_checked_modulus() { + assert!(bool::from( + DynResidueParams::::new_checked(&Uint::from(2u8)).is_none() + )) + } + + #[test] + #[should_panic] + // Tets that an invalid modulus panics + fn test_invalid_modulus() { + DynResidueParams::::new(&Uint::from(2u8)); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_add.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_add.rs new file mode 100644 index 000000000..eb4708603 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_add.rs @@ -0,0 +1,92 @@ +use core::ops::{Add, AddAssign}; + +use crate::modular::add::add_montgomery_form; + +use super::DynResidue; + +impl DynResidue { + /// Adds `rhs`. + pub const fn add(&self, rhs: &Self) -> Self { + Self { + montgomery_form: add_montgomery_form( + &self.montgomery_form, + &rhs.montgomery_form, + &self.residue_params.modulus, + ), + residue_params: self.residue_params, + } + } +} + +impl Add<&DynResidue> for &DynResidue { + type Output = DynResidue; + fn add(self, rhs: &DynResidue) -> DynResidue { + debug_assert_eq!(self.residue_params, rhs.residue_params); + self.add(rhs) + } +} + +impl Add> for &DynResidue { + type Output = DynResidue; + #[allow(clippy::op_ref)] + fn add(self, rhs: DynResidue) -> DynResidue { + self + &rhs + } +} + +impl Add<&DynResidue> for DynResidue { + type Output = DynResidue; + #[allow(clippy::op_ref)] + fn add(self, rhs: &DynResidue) -> DynResidue { + &self + rhs + } +} + +impl Add> for DynResidue { + type Output = DynResidue; + fn add(self, rhs: DynResidue) -> DynResidue { + &self + &rhs + } +} + +impl AddAssign<&DynResidue> for DynResidue { + fn add_assign(&mut self, rhs: &DynResidue) { + *self = *self + rhs; + } +} + +impl AddAssign> for DynResidue { + fn add_assign(&mut self, rhs: DynResidue) { + *self += &rhs; + } +} + +#[cfg(test)] +mod tests { + use crate::{ + modular::runtime_mod::{DynResidue, DynResidueParams}, + U256, + }; + + #[test] + fn add_overflow() { + let params = DynResidueParams::new(&U256::from_be_hex( + "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + )); + + let x = + U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); + let mut x_mod = DynResidue::new(&x, params); + + let y = + U256::from_be_hex("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"); + let y_mod = DynResidue::new(&y, params); + + x_mod += &y_mod; + + let expected = + U256::from_be_hex("1a2472fde50286541d97ca6a3592dd75beb9c9646e40c511b82496cfc3926956"); + + assert_eq!(expected, x_mod.retrieve()); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_inv.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_inv.rs new file mode 100644 index 000000000..5e639d439 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_inv.rs @@ -0,0 +1,35 @@ +use subtle::CtOption; + +use crate::{modular::inv::inv_montgomery_form, traits::Invert, CtChoice}; + +use super::DynResidue; + +impl DynResidue { + /// Computes the residue `self^-1` representing the multiplicative inverse of `self`. + /// I.e. `self * self^-1 = 1`. + /// If the number was invertible, the second element of the tuple is the truthy value, + /// otherwise it is the falsy value (in which case the first element's value is unspecified). + pub const fn invert(&self) -> (Self, CtChoice) { + let (montgomery_form, is_some) = inv_montgomery_form( + &self.montgomery_form, + &self.residue_params.modulus, + &self.residue_params.r3, + self.residue_params.mod_neg_inv, + ); + + let value = Self { + montgomery_form, + residue_params: self.residue_params, + }; + + (value, is_some) + } +} + +impl Invert for DynResidue { + type Output = CtOption; + fn invert(&self) -> Self::Output { + let (value, is_some) = self.invert(); + CtOption::new(value, is_some.into()) + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_mul.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_mul.rs new file mode 100644 index 000000000..30c4b9c04 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_mul.rs @@ -0,0 +1,84 @@ +use core::ops::{Mul, MulAssign}; + +use crate::{ + modular::mul::{mul_montgomery_form, square_montgomery_form}, + traits::Square, +}; + +use super::DynResidue; + +impl DynResidue { + /// Multiplies by `rhs`. + pub const fn mul(&self, rhs: &Self) -> Self { + Self { + montgomery_form: mul_montgomery_form( + &self.montgomery_form, + &rhs.montgomery_form, + &self.residue_params.modulus, + self.residue_params.mod_neg_inv, + ), + residue_params: self.residue_params, + } + } + + /// Computes the (reduced) square of a residue. + pub const fn square(&self) -> Self { + Self { + montgomery_form: square_montgomery_form( + &self.montgomery_form, + &self.residue_params.modulus, + self.residue_params.mod_neg_inv, + ), + residue_params: self.residue_params, + } + } +} + +impl Mul<&DynResidue> for &DynResidue { + type Output = DynResidue; + fn mul(self, rhs: &DynResidue) -> DynResidue { + debug_assert_eq!(self.residue_params, rhs.residue_params); + self.mul(rhs) + } +} + +impl Mul> for &DynResidue { + type Output = DynResidue; + #[allow(clippy::op_ref)] + fn mul(self, rhs: DynResidue) -> DynResidue { + self * &rhs + } +} + +impl Mul<&DynResidue> for DynResidue { + type Output = DynResidue; + #[allow(clippy::op_ref)] + fn mul(self, rhs: &DynResidue) -> DynResidue { + &self * rhs + } +} + +impl Mul> for DynResidue { + type Output = DynResidue; + fn mul(self, rhs: DynResidue) -> DynResidue { + &self * &rhs + } +} + +impl MulAssign<&DynResidue> for DynResidue { + fn mul_assign(&mut self, rhs: &DynResidue) { + *self = *self * rhs; + } +} + +impl MulAssign> for DynResidue { + fn mul_assign(&mut self, rhs: DynResidue) { + *self *= &rhs; + } +} + +impl Square for DynResidue { + fn square(&self) -> Self { + DynResidue::square(self) + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_neg.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_neg.rs new file mode 100644 index 000000000..fca1ff875 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_neg.rs @@ -0,0 +1,24 @@ +use core::ops::Neg; + +use super::DynResidue; + +impl DynResidue { + /// Negates the number. + pub const fn neg(&self) -> Self { + Self::zero(self.residue_params).sub(self) + } +} + +impl Neg for DynResidue { + type Output = Self; + fn neg(self) -> Self { + DynResidue::neg(&self) + } +} + +impl Neg for &DynResidue { + type Output = DynResidue; + fn neg(self) -> DynResidue { + DynResidue::neg(self) + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_pow.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_pow.rs new file mode 100644 index 000000000..42b6b8beb --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_pow.rs @@ -0,0 +1,113 @@ +use super::DynResidue; +use crate::modular::pow::multi_exponentiate_montgomery_form_array; +#[cfg(feature = "alloc")] +use crate::modular::pow::multi_exponentiate_montgomery_form_slice; +use crate::{modular::pow::pow_montgomery_form, MultiExponentiateBoundedExp, PowBoundedExp, Uint}; +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +impl DynResidue { + /// Raises to the `exponent` power. + pub const fn pow( + &self, + exponent: &Uint, + ) -> DynResidue { + self.pow_bounded_exp(exponent, Uint::::BITS) + } + + /// Raises to the `exponent` power, + /// with `exponent_bits` representing the number of (least significant) bits + /// to take into account for the exponent. + /// + /// NOTE: `exponent_bits` may be leaked in the time pattern. + pub const fn pow_bounded_exp( + &self, + exponent: &Uint, + exponent_bits: usize, + ) -> Self { + Self { + montgomery_form: pow_montgomery_form( + &self.montgomery_form, + exponent, + exponent_bits, + &self.residue_params.modulus, + &self.residue_params.r, + self.residue_params.mod_neg_inv, + ), + residue_params: self.residue_params, + } + } +} + +impl PowBoundedExp> + for DynResidue +{ + fn pow_bounded_exp(&self, exponent: &Uint, exponent_bits: usize) -> Self { + self.pow_bounded_exp(exponent, exponent_bits) + } +} + +impl + MultiExponentiateBoundedExp, [(Self, Uint); N]> + for DynResidue +{ + fn multi_exponentiate_bounded_exp( + bases_and_exponents: &[(Self, Uint); N], + exponent_bits: usize, + ) -> Self { + const_assert_ne!(N, 0, "bases_and_exponents must not be empty"); + let residue_params = bases_and_exponents[0].0.residue_params; + + let mut bases_and_exponents_montgomery_form = + [(Uint::::ZERO, Uint::::ZERO); N]; + + let mut i = 0; + while i < N { + let (base, exponent) = bases_and_exponents[i]; + bases_and_exponents_montgomery_form[i] = (base.montgomery_form, exponent); + i += 1; + } + + Self { + montgomery_form: multi_exponentiate_montgomery_form_array( + &bases_and_exponents_montgomery_form, + exponent_bits, + &residue_params.modulus, + &residue_params.r, + residue_params.mod_neg_inv, + ), + residue_params, + } + } +} + +#[cfg(feature = "alloc")] +impl + MultiExponentiateBoundedExp, [(Self, Uint)]> for DynResidue +{ + fn multi_exponentiate_bounded_exp( + bases_and_exponents: &[(Self, Uint)], + exponent_bits: usize, + ) -> Self { + assert!( + !bases_and_exponents.is_empty(), + "bases_and_exponents must not be empty" + ); + let residue_params = bases_and_exponents[0].0.residue_params; + + let bases_and_exponents: Vec<(Uint, Uint)> = bases_and_exponents + .iter() + .map(|(base, exp)| (base.montgomery_form, *exp)) + .collect(); + Self { + montgomery_form: multi_exponentiate_montgomery_form_slice( + &bases_and_exponents, + exponent_bits, + &residue_params.modulus, + &residue_params.r, + residue_params.mod_neg_inv, + ), + residue_params, + } + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_sub.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_sub.rs new file mode 100644 index 000000000..dd6fd84c8 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/runtime_mod/runtime_sub.rs @@ -0,0 +1,92 @@ +use core::ops::{Sub, SubAssign}; + +use crate::modular::sub::sub_montgomery_form; + +use super::DynResidue; + +impl DynResidue { + /// Subtracts `rhs`. + pub const fn sub(&self, rhs: &Self) -> Self { + Self { + montgomery_form: sub_montgomery_form( + &self.montgomery_form, + &rhs.montgomery_form, + &self.residue_params.modulus, + ), + residue_params: self.residue_params, + } + } +} + +impl Sub<&DynResidue> for &DynResidue { + type Output = DynResidue; + fn sub(self, rhs: &DynResidue) -> DynResidue { + debug_assert_eq!(self.residue_params, rhs.residue_params); + self.sub(rhs) + } +} + +impl Sub> for &DynResidue { + type Output = DynResidue; + #[allow(clippy::op_ref)] + fn sub(self, rhs: DynResidue) -> DynResidue { + self - &rhs + } +} + +impl Sub<&DynResidue> for DynResidue { + type Output = DynResidue; + #[allow(clippy::op_ref)] + fn sub(self, rhs: &DynResidue) -> DynResidue { + &self - rhs + } +} + +impl Sub> for DynResidue { + type Output = DynResidue; + fn sub(self, rhs: DynResidue) -> DynResidue { + &self - &rhs + } +} + +impl SubAssign<&DynResidue> for DynResidue { + fn sub_assign(&mut self, rhs: &DynResidue) { + *self = *self - rhs; + } +} + +impl SubAssign> for DynResidue { + fn sub_assign(&mut self, rhs: DynResidue) { + *self -= &rhs; + } +} + +#[cfg(test)] +mod tests { + use crate::{ + modular::runtime_mod::{DynResidue, DynResidueParams}, + U256, + }; + + #[test] + fn sub_overflow() { + let params = DynResidueParams::new(&U256::from_be_hex( + "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + )); + + let x = + U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); + let mut x_mod = DynResidue::new(&x, params); + + let y = + U256::from_be_hex("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"); + let y_mod = DynResidue::new(&y, params); + + x_mod -= &y_mod; + + let expected = + U256::from_be_hex("6f357a71e1d5a03167f34879d469352add829491c6df41ddff65387d7ed56f56"); + + assert_eq!(expected, x_mod.retrieve()); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/modular/sub.rs b/src/rust/vendor/crypto-bigint/src/uint/modular/sub.rs new file mode 100644 index 000000000..9c4717033 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/modular/sub.rs @@ -0,0 +1,9 @@ +use crate::Uint; + +pub(crate) const fn sub_montgomery_form( + a: &Uint, + b: &Uint, + modulus: &Uint, +) -> Uint { + a.sub_mod(b, modulus) +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/mul.rs b/src/rust/vendor/crypto-bigint/src/uint/mul.rs new file mode 100644 index 000000000..cb29332c5 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/mul.rs @@ -0,0 +1,414 @@ +//! [`Uint`] addition operations. + +use crate::{Checked, CheckedMul, Concat, ConcatMixed, Limb, Uint, WideWord, Word, Wrapping, Zero}; +use core::ops::{Mul, MulAssign}; +use subtle::CtOption; + +impl Uint { + /// Multiply `self` by `rhs`, returning a concatenated "wide" result. + pub fn mul( + &self, + rhs: &Uint, + ) -> as ConcatMixed>::MixedOutput + where + Uint: ConcatMixed, + { + let (lo, hi) = self.mul_wide(rhs); + hi.concat_mixed(&lo) + } + + /// Compute "wide" multiplication, with a product twice the size of the input. + /// + /// Returns a tuple containing the `(lo, hi)` components of the product. + /// + /// # Ordering note + /// + /// Releases of `crypto-bigint` prior to v0.3 used `(hi, lo)` ordering + /// instead. This has been changed for better consistency with the rest of + /// the APIs in this crate. + /// + /// For more info see: + pub const fn mul_wide(&self, rhs: &Uint) -> (Self, Uint) { + let mut i = 0; + let mut lo = Self::ZERO; + let mut hi = Uint::::ZERO; + + // Schoolbook multiplication. + // TODO(tarcieri): use Karatsuba for better performance? + while i < LIMBS { + let mut j = 0; + let mut carry = Limb::ZERO; + + while j < HLIMBS { + let k = i + j; + + if k >= LIMBS { + let (n, c) = hi.limbs[k - LIMBS].mac(self.limbs[i], rhs.limbs[j], carry); + hi.limbs[k - LIMBS] = n; + carry = c; + } else { + let (n, c) = lo.limbs[k].mac(self.limbs[i], rhs.limbs[j], carry); + lo.limbs[k] = n; + carry = c; + } + + j += 1; + } + + if i + j >= LIMBS { + hi.limbs[i + j - LIMBS] = carry; + } else { + lo.limbs[i + j] = carry; + } + i += 1; + } + + (lo, hi) + } + + /// Perform saturating multiplication, returning `MAX` on overflow. + pub const fn saturating_mul(&self, rhs: &Uint) -> Self { + let (res, overflow) = self.mul_wide(rhs); + Self::ct_select(&res, &Self::MAX, overflow.ct_is_nonzero()) + } + + /// Perform wrapping multiplication, discarding overflow. + pub const fn wrapping_mul(&self, rhs: &Uint) -> Self { + self.mul_wide(rhs).0 + } + + /// Square self, returning a concatenated "wide" result. + pub fn square(&self) -> ::Output + where + Self: Concat, + { + let (lo, hi) = self.square_wide(); + hi.concat(&lo) + } + + /// Square self, returning a "wide" result in two parts as (lo, hi). + pub const fn square_wide(&self) -> (Self, Self) { + // Translated from https://github.com/ucbrise/jedi-pairing/blob/c4bf151/include/core/bigint.hpp#L410 + // + // Permission to relicense the resulting translation as Apache 2.0 + MIT was given + // by the original author Sam Kumar: https://github.com/RustCrypto/crypto-bigint/pull/133#discussion_r1056870411 + let mut lo = Self::ZERO; + let mut hi = Self::ZERO; + + // Schoolbook multiplication, but only considering half of the multiplication grid + let mut i = 1; + while i < LIMBS { + let mut j = 0; + let mut carry = Limb::ZERO; + + while j < i { + let k = i + j; + + if k >= LIMBS { + let (n, c) = hi.limbs[k - LIMBS].mac(self.limbs[i], self.limbs[j], carry); + hi.limbs[k - LIMBS] = n; + carry = c; + } else { + let (n, c) = lo.limbs[k].mac(self.limbs[i], self.limbs[j], carry); + lo.limbs[k] = n; + carry = c; + } + + j += 1; + } + + if (2 * i) < LIMBS { + lo.limbs[2 * i] = carry; + } else { + hi.limbs[2 * i - LIMBS] = carry; + } + + i += 1; + } + + // Double the current result, this accounts for the other half of the multiplication grid. + // TODO: The top word is empty so we can also use a special purpose shl. + (lo, hi) = Self::shl_vartime_wide((lo, hi), 1); + + // Handle the diagonal of the multiplication grid, which finishes the multiplication grid. + let mut carry = Limb::ZERO; + let mut i = 0; + while i < LIMBS { + if (i * 2) < LIMBS { + let (n, c) = lo.limbs[i * 2].mac(self.limbs[i], self.limbs[i], carry); + lo.limbs[i * 2] = n; + carry = c; + } else { + let (n, c) = hi.limbs[i * 2 - LIMBS].mac(self.limbs[i], self.limbs[i], carry); + hi.limbs[i * 2 - LIMBS] = n; + carry = c; + } + + if (i * 2 + 1) < LIMBS { + let n = lo.limbs[i * 2 + 1].0 as WideWord + carry.0 as WideWord; + lo.limbs[i * 2 + 1] = Limb(n as Word); + carry = Limb((n >> Word::BITS) as Word); + } else { + let n = hi.limbs[i * 2 + 1 - LIMBS].0 as WideWord + carry.0 as WideWord; + hi.limbs[i * 2 + 1 - LIMBS] = Limb(n as Word); + carry = Limb((n >> Word::BITS) as Word); + } + + i += 1; + } + + (lo, hi) + } +} + +impl CheckedMul<&Uint> for Uint { + type Output = Self; + + fn checked_mul(&self, rhs: &Uint) -> CtOption { + let (lo, hi) = self.mul_wide(rhs); + CtOption::new(lo, hi.is_zero()) + } +} + +impl Mul>> + for Wrapping> +{ + type Output = Self; + + fn mul(self, rhs: Wrapping>) -> Wrapping> { + Wrapping(self.0.wrapping_mul(&rhs.0)) + } +} + +impl Mul<&Wrapping>> + for Wrapping> +{ + type Output = Self; + + fn mul(self, rhs: &Wrapping>) -> Wrapping> { + Wrapping(self.0.wrapping_mul(&rhs.0)) + } +} + +impl Mul>> + for &Wrapping> +{ + type Output = Wrapping>; + + fn mul(self, rhs: Wrapping>) -> Wrapping> { + Wrapping(self.0.wrapping_mul(&rhs.0)) + } +} + +impl Mul<&Wrapping>> + for &Wrapping> +{ + type Output = Wrapping>; + + fn mul(self, rhs: &Wrapping>) -> Wrapping> { + Wrapping(self.0.wrapping_mul(&rhs.0)) + } +} + +impl MulAssign>> + for Wrapping> +{ + fn mul_assign(&mut self, other: Wrapping>) { + *self = *self * other; + } +} + +impl MulAssign<&Wrapping>> + for Wrapping> +{ + fn mul_assign(&mut self, other: &Wrapping>) { + *self = *self * other; + } +} + +impl Mul>> for Checked> { + type Output = Self; + + fn mul(self, rhs: Checked>) -> Checked> { + Checked(self.0.and_then(|a| rhs.0.and_then(|b| a.checked_mul(&b)))) + } +} + +impl Mul<&Checked>> for Checked> { + type Output = Checked>; + + fn mul(self, rhs: &Checked>) -> Checked> { + Checked(self.0.and_then(|a| rhs.0.and_then(|b| a.checked_mul(&b)))) + } +} + +impl Mul>> for &Checked> { + type Output = Checked>; + + fn mul(self, rhs: Checked>) -> Checked> { + Checked(self.0.and_then(|a| rhs.0.and_then(|b| a.checked_mul(&b)))) + } +} + +impl Mul<&Checked>> + for &Checked> +{ + type Output = Checked>; + + fn mul(self, rhs: &Checked>) -> Checked> { + Checked(self.0.and_then(|a| rhs.0.and_then(|b| a.checked_mul(&b)))) + } +} + +impl MulAssign>> + for Checked> +{ + fn mul_assign(&mut self, other: Checked>) { + *self = *self * other; + } +} + +impl MulAssign<&Checked>> + for Checked> +{ + fn mul_assign(&mut self, other: &Checked>) { + *self = *self * other; + } +} + +impl Mul> for Uint +where + Uint: ConcatMixed>, +{ + type Output = as ConcatMixed>::MixedOutput; + + fn mul(self, other: Uint) -> Self::Output { + Uint::mul(&self, &other) + } +} + +impl Mul<&Uint> for Uint +where + Uint: ConcatMixed>, +{ + type Output = as ConcatMixed>::MixedOutput; + + fn mul(self, other: &Uint) -> Self::Output { + Uint::mul(&self, other) + } +} + +impl Mul> for &Uint +where + Uint: ConcatMixed>, +{ + type Output = as ConcatMixed>>::MixedOutput; + + fn mul(self, other: Uint) -> Self::Output { + Uint::mul(self, &other) + } +} + +impl Mul<&Uint> for &Uint +where + Uint: ConcatMixed>, +{ + type Output = as ConcatMixed>>::MixedOutput; + + fn mul(self, other: &Uint) -> Self::Output { + Uint::mul(self, other) + } +} + +#[cfg(test)] +mod tests { + use crate::{CheckedMul, Zero, U128, U192, U256, U64}; + + #[test] + fn mul_wide_zero_and_one() { + assert_eq!(U64::ZERO.mul_wide(&U64::ZERO), (U64::ZERO, U64::ZERO)); + assert_eq!(U64::ZERO.mul_wide(&U64::ONE), (U64::ZERO, U64::ZERO)); + assert_eq!(U64::ONE.mul_wide(&U64::ZERO), (U64::ZERO, U64::ZERO)); + assert_eq!(U64::ONE.mul_wide(&U64::ONE), (U64::ONE, U64::ZERO)); + } + + #[test] + fn mul_wide_lo_only() { + let primes: &[u32] = &[3, 5, 17, 257, 65537]; + + for &a_int in primes { + for &b_int in primes { + let (lo, hi) = U64::from_u32(a_int).mul_wide(&U64::from_u32(b_int)); + let expected = U64::from_u64(a_int as u64 * b_int as u64); + assert_eq!(lo, expected); + assert!(bool::from(hi.is_zero())); + } + } + } + + #[test] + fn mul_concat_even() { + assert_eq!(U64::ZERO * U64::MAX, U128::ZERO); + assert_eq!(U64::MAX * U64::ZERO, U128::ZERO); + assert_eq!( + U64::MAX * U64::MAX, + U128::from_u128(0xfffffffffffffffe_0000000000000001) + ); + assert_eq!( + U64::ONE * U64::MAX, + U128::from_u128(0x0000000000000000_ffffffffffffffff) + ); + } + + #[test] + fn mul_concat_mixed() { + let a = U64::from_u64(0x0011223344556677); + let b = U128::from_u128(0x8899aabbccddeeff_8899aabbccddeeff); + assert_eq!(a * b, U192::from(&a).saturating_mul(&b)); + assert_eq!(b * a, U192::from(&b).saturating_mul(&a)); + } + + #[test] + fn checked_mul_ok() { + let n = U64::from_u32(0xffff_ffff); + assert_eq!( + n.checked_mul(&n).unwrap(), + U64::from_u64(0xffff_fffe_0000_0001) + ); + } + + #[test] + fn checked_mul_overflow() { + let n = U64::from_u64(0xffff_ffff_ffff_ffff); + assert!(bool::from(n.checked_mul(&n).is_none())); + } + + #[test] + fn saturating_mul_no_overflow() { + let n = U64::from_u8(8); + assert_eq!(n.saturating_mul(&n), U64::from_u8(64)); + } + + #[test] + fn saturating_mul_overflow() { + let a = U64::from(0xffff_ffff_ffff_ffffu64); + let b = U64::from(2u8); + assert_eq!(a.saturating_mul(&b), U64::MAX); + } + + #[test] + fn square() { + let n = U64::from_u64(0xffff_ffff_ffff_ffff); + let (hi, lo) = n.square().split(); + assert_eq!(lo, U64::from_u64(1)); + assert_eq!(hi, U64::from_u64(0xffff_ffff_ffff_fffe)); + } + + #[test] + fn square_larger() { + let n = U256::MAX; + let (hi, lo) = n.square().split(); + assert_eq!(lo, U256::ONE); + assert_eq!(hi, U256::MAX.wrapping_sub(&U256::ONE)); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/mul_mod.rs b/src/rust/vendor/crypto-bigint/src/uint/mul_mod.rs new file mode 100644 index 000000000..c46274a4d --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/mul_mod.rs @@ -0,0 +1,133 @@ +//! [`Uint`] multiplication modulus operations. + +use crate::{Limb, Uint, WideWord, Word}; + +impl Uint { + /// Computes `self * rhs mod p` for the special modulus + /// `p = MAX+1-c` where `c` is small enough to fit in a single [`Limb`]. + /// For the modulus reduction, this function implements Algorithm 14.47 from + /// the "Handbook of Applied Cryptography", by A. Menezes, P. van Oorschot, + /// and S. Vanstone, CRC Press, 1996. + pub const fn mul_mod_special(&self, rhs: &Self, c: Limb) -> Self { + // We implicitly assume `LIMBS > 0`, because `Uint<0>` doesn't compile. + // Still the case `LIMBS == 1` needs special handling. + if LIMBS == 1 { + let prod = self.limbs[0].0 as WideWord * rhs.limbs[0].0 as WideWord; + let reduced = prod % Word::MIN.wrapping_sub(c.0) as WideWord; + return Self::from_word(reduced as Word); + } + + let (lo, hi) = self.mul_wide(rhs); + + // Now use Algorithm 14.47 for the reduction + let (lo, carry) = mac_by_limb(&lo, &hi, c, Limb::ZERO); + + let (lo, carry) = { + let rhs = (carry.0 + 1) as WideWord * c.0 as WideWord; + lo.adc(&Self::from_wide_word(rhs), Limb::ZERO) + }; + + let (lo, _) = { + let rhs = carry.0.wrapping_sub(1) & c.0; + lo.sbb(&Self::from_word(rhs), Limb::ZERO) + }; + + lo + } +} + +/// Computes `a + (b * c) + carry`, returning the result along with the new carry. +const fn mac_by_limb( + a: &Uint, + b: &Uint, + c: Limb, + carry: Limb, +) -> (Uint, Limb) { + let mut i = 0; + let mut a = *a; + let mut carry = carry; + + while i < LIMBS { + let (n, c) = a.limbs[i].mac(b.limbs[i], c, carry); + a.limbs[i] = n; + carry = c; + i += 1; + } + + (a, carry) +} + +#[cfg(all(test, feature = "rand"))] +mod tests { + use crate::{Limb, NonZero, Random, RandomMod, Uint}; + use rand_core::SeedableRng; + + macro_rules! test_mul_mod_special { + ($size:expr, $test_name:ident) => { + #[test] + fn $test_name() { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); + let moduli = [ + NonZero::::random(&mut rng), + NonZero::::random(&mut rng), + ]; + + for special in &moduli { + let p = &NonZero::new(Uint::ZERO.wrapping_sub(&Uint::from_word(special.0))) + .unwrap(); + + let minus_one = p.wrapping_sub(&Uint::ONE); + + let base_cases = [ + (Uint::ZERO, Uint::ZERO, Uint::ZERO), + (Uint::ONE, Uint::ZERO, Uint::ZERO), + (Uint::ZERO, Uint::ONE, Uint::ZERO), + (Uint::ONE, Uint::ONE, Uint::ONE), + (minus_one, minus_one, Uint::ONE), + (minus_one, Uint::ONE, minus_one), + (Uint::ONE, minus_one, minus_one), + ]; + for (a, b, c) in &base_cases { + let x = a.mul_mod_special(&b, *special.as_ref()); + assert_eq!(*c, x, "{} * {} mod {} = {} != {}", a, b, p, x, c); + } + + for _i in 0..100 { + let a = Uint::<$size>::random_mod(&mut rng, p); + let b = Uint::<$size>::random_mod(&mut rng, p); + + let c = a.mul_mod_special(&b, *special.as_ref()); + assert!(c < **p, "not reduced: {} >= {} ", c, p); + + let expected = { + let (lo, hi) = a.mul_wide(&b); + let mut prod = Uint::<{ 2 * $size }>::ZERO; + prod.limbs[..$size].clone_from_slice(&lo.limbs); + prod.limbs[$size..].clone_from_slice(&hi.limbs); + let mut modulus = Uint::ZERO; + modulus.limbs[..$size].clone_from_slice(&p.as_ref().limbs); + let reduced = prod.rem(&NonZero::new(modulus).unwrap()); + let mut expected = Uint::ZERO; + expected.limbs[..].clone_from_slice(&reduced.limbs[..$size]); + expected + }; + assert_eq!(c, expected, "incorrect result"); + } + } + } + }; + } + + test_mul_mod_special!(1, mul_mod_special_1); + test_mul_mod_special!(2, mul_mod_special_2); + test_mul_mod_special!(3, mul_mod_special_3); + test_mul_mod_special!(4, mul_mod_special_4); + test_mul_mod_special!(5, mul_mod_special_5); + test_mul_mod_special!(6, mul_mod_special_6); + test_mul_mod_special!(7, mul_mod_special_7); + test_mul_mod_special!(8, mul_mod_special_8); + test_mul_mod_special!(9, mul_mod_special_9); + test_mul_mod_special!(10, mul_mod_special_10); + test_mul_mod_special!(11, mul_mod_special_11); + test_mul_mod_special!(12, mul_mod_special_12); +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/neg.rs b/src/rust/vendor/crypto-bigint/src/uint/neg.rs new file mode 100644 index 000000000..4881a279e --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/neg.rs @@ -0,0 +1,51 @@ +use core::ops::Neg; + +use crate::{CtChoice, Limb, Uint, WideWord, Word, Wrapping}; + +impl Neg for Wrapping> { + type Output = Self; + + fn neg(self) -> Self::Output { + Self(self.0.wrapping_neg()) + } +} + +impl Uint { + /// Negates based on `choice` by wrapping the integer. + pub(crate) const fn conditional_wrapping_neg(&self, choice: CtChoice) -> Uint { + Uint::ct_select(self, &self.wrapping_neg(), choice) + } + + /// Perform wrapping negation. + pub const fn wrapping_neg(&self) -> Self { + let mut ret = [Limb::ZERO; LIMBS]; + let mut carry = 1; + let mut i = 0; + while i < LIMBS { + let r = (!self.limbs[i].0 as WideWord) + carry; + ret[i] = Limb(r as Word); + carry = r >> Limb::BITS; + i += 1; + } + Uint::new(ret) + } +} + +#[cfg(test)] +mod tests { + use crate::U256; + + #[test] + fn wrapping_neg() { + assert_eq!(U256::ZERO.wrapping_neg(), U256::ZERO); + assert_eq!(U256::MAX.wrapping_neg(), U256::ONE); + assert_eq!( + U256::from_u64(13).wrapping_neg(), + U256::from_u64(13).not().saturating_add(&U256::ONE) + ); + assert_eq!( + U256::from_u64(42).wrapping_neg(), + U256::from_u64(42).saturating_sub(&U256::ONE).not() + ); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/neg_mod.rs b/src/rust/vendor/crypto-bigint/src/uint/neg_mod.rs new file mode 100644 index 000000000..38580ed5d --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/neg_mod.rs @@ -0,0 +1,68 @@ +//! [`Uint`] negation modulus operations. + +use crate::{Limb, NegMod, Uint}; + +impl Uint { + /// Computes `-a mod p`. + /// Assumes `self` is in `[0, p)`. + pub const fn neg_mod(&self, p: &Self) -> Self { + let z = self.ct_is_nonzero(); + let mut ret = p.sbb(self, Limb::ZERO).0; + let mut i = 0; + while i < LIMBS { + // Set ret to 0 if the original value was 0, in which + // case ret would be p. + ret.limbs[i].0 = z.if_true(ret.limbs[i].0); + i += 1; + } + ret + } + + /// Computes `-a mod p` for the special modulus + /// `p = MAX+1-c` where `c` is small enough to fit in a single [`Limb`]. + pub const fn neg_mod_special(&self, c: Limb) -> Self { + Self::ZERO.sub_mod_special(self, c) + } +} + +impl NegMod for Uint { + type Output = Self; + + fn neg_mod(&self, p: &Self) -> Self { + debug_assert!(self < p); + self.neg_mod(p) + } +} + +#[cfg(test)] +mod tests { + use crate::U256; + + #[test] + fn neg_mod_random() { + let x = + U256::from_be_hex("8d16e171674b4e6d8529edba4593802bf30b8cb161dd30aa8e550d41380007c2"); + let p = + U256::from_be_hex("928334a4e4be0843ec225a4c9c61df34bdc7a81513e4b6f76f2bfa3148e2e1b5"); + + let actual = x.neg_mod(&p); + let expected = + U256::from_be_hex("056c53337d72b9d666f86c9256ce5f08cabc1b63b207864ce0d6ecf010e2d9f3"); + + assert_eq!(expected, actual); + } + + #[test] + fn neg_mod_zero() { + let x = + U256::from_be_hex("0000000000000000000000000000000000000000000000000000000000000000"); + let p = + U256::from_be_hex("928334a4e4be0843ec225a4c9c61df34bdc7a81513e4b6f76f2bfa3148e2e1b5"); + + let actual = x.neg_mod(&p); + let expected = + U256::from_be_hex("0000000000000000000000000000000000000000000000000000000000000000"); + + assert_eq!(expected, actual); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/rand.rs b/src/rust/vendor/crypto-bigint/src/uint/rand.rs new file mode 100644 index 000000000..80af3bb16 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/rand.rs @@ -0,0 +1,90 @@ +//! Random number generator support + +use super::Uint; +use crate::{Encoding, Limb, NonZero, Random, RandomMod}; +use rand_core::CryptoRngCore; +use subtle::ConstantTimeLess; + +impl Random for Uint { + /// Generate a cryptographically secure random [`Uint`]. + fn random(mut rng: &mut impl CryptoRngCore) -> Self { + let mut limbs = [Limb::ZERO; LIMBS]; + + for limb in &mut limbs { + *limb = Limb::random(&mut rng) + } + + limbs.into() + } +} + +impl RandomMod for Uint { + /// Generate a cryptographically secure random [`Uint`] which is less than + /// a given `modulus`. + /// + /// This function uses rejection sampling, a method which produces an + /// unbiased distribution of in-range values provided the underlying + /// CSRNG is unbiased, but runs in variable-time. + /// + /// The variable-time nature of the algorithm should not pose a security + /// issue so long as the underlying random number generator is truly a + /// CSRNG, where previous outputs are unrelated to subsequent + /// outputs and do not reveal information about the RNG's internal state. + fn random_mod(rng: &mut impl CryptoRngCore, modulus: &NonZero) -> Self { + let mut n = Self::ZERO; + + let n_bits = modulus.as_ref().bits_vartime(); + let n_bytes = (n_bits + 7) / 8; + let n_limbs = (n_bits + Limb::BITS - 1) / Limb::BITS; + let hi_bytes = n_bytes - (n_limbs - 1) * Limb::BYTES; + + let mut bytes = Limb::ZERO.to_le_bytes(); + + loop { + for i in 0..n_limbs - 1 { + rng.fill_bytes(bytes.as_mut()); + // Need to deserialize from little-endian to make sure that two 32-bit limbs + // deserialized sequentially are equal to one 64-bit limb produced from the same + // byte stream. + n.limbs[i] = Limb::from_le_bytes(bytes); + } + + // Generate the high limb which may need to only be filled partially. + bytes.as_mut().fill(0); + rng.fill_bytes(&mut (bytes.as_mut()[0..hi_bytes])); + n.limbs[n_limbs - 1] = Limb::from_le_bytes(bytes); + + if n.ct_lt(modulus).into() { + return n; + } + } + } +} + +#[cfg(test)] +mod tests { + use crate::{NonZero, RandomMod, U256}; + use rand_core::SeedableRng; + + #[test] + fn random_mod() { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); + + // Ensure `random_mod` runs in a reasonable amount of time + let modulus = NonZero::new(U256::from(42u8)).unwrap(); + let res = U256::random_mod(&mut rng, &modulus); + + // Check that the value is in range + assert!(res >= U256::ZERO); + assert!(res < U256::from(42u8)); + + // Ensure `random_mod` runs in a reasonable amount of time + // when the modulus is larger than 1 limb + let modulus = NonZero::new(U256::from(0x10000000000000001u128)).unwrap(); + let res = U256::random_mod(&mut rng, &modulus); + + // Check that the value is in range + assert!(res >= U256::ZERO); + assert!(res < U256::from(0x10000000000000001u128)); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/resize.rs b/src/rust/vendor/crypto-bigint/src/uint/resize.rs new file mode 100644 index 000000000..2c80b895b --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/resize.rs @@ -0,0 +1,37 @@ +use super::Uint; + +impl Uint { + /// Construct a `Uint` from the unsigned integer value, + /// truncating the upper bits if the value is too large to be + /// represented. + #[inline(always)] + pub const fn resize(&self) -> Uint { + let mut res = Uint::ZERO; + let mut i = 0; + let dim = if T < LIMBS { T } else { LIMBS }; + while i < dim { + res.limbs[i] = self.limbs[i]; + i += 1; + } + res + } +} + +#[cfg(test)] +mod tests { + use crate::{U128, U64}; + + #[test] + fn resize_larger() { + let u = U64::from_be_hex("AAAAAAAABBBBBBBB"); + let u2: U128 = u.resize(); + assert_eq!(u2, U128::from_be_hex("0000000000000000AAAAAAAABBBBBBBB")); + } + + #[test] + fn resize_smaller() { + let u = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD"); + let u2: U64 = u.resize(); + assert_eq!(u2, U64::from_be_hex("CCCCCCCCDDDDDDDD")); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/shl.rs b/src/rust/vendor/crypto-bigint/src/uint/shl.rs new file mode 100644 index 000000000..1dbc40f05 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/shl.rs @@ -0,0 +1,216 @@ +//! [`Uint`] bitwise left shift operations. + +use crate::{CtChoice, Limb, Uint, Word}; +use core::ops::{Shl, ShlAssign}; + +impl Uint { + /// Computes `self << shift` where `0 <= shift < Limb::BITS`, + /// returning the result and the carry. + #[inline(always)] + pub(crate) const fn shl_limb(&self, n: usize) -> (Self, Limb) { + let mut limbs = [Limb::ZERO; LIMBS]; + + let nz = Limb(n as Word).ct_is_nonzero(); + let lshift = n as Word; + let rshift = Limb::ct_select(Limb::ZERO, Limb((Limb::BITS - n) as Word), nz).0; + let carry = Limb::ct_select( + Limb::ZERO, + Limb(self.limbs[LIMBS - 1].0.wrapping_shr(Word::BITS - n as u32)), + nz, + ); + + let mut i = LIMBS - 1; + while i > 0 { + let mut limb = self.limbs[i].0 << lshift; + let hi = self.limbs[i - 1].0 >> rshift; + limb |= nz.if_true(hi); + limbs[i] = Limb(limb); + i -= 1 + } + limbs[0] = Limb(self.limbs[0].0 << lshift); + + (Uint::::new(limbs), carry) + } + + /// Computes `self << shift`. + /// + /// NOTE: this operation is variable time with respect to `n` *ONLY*. + /// + /// When used with a fixed `n`, this function is constant-time with respect + /// to `self`. + #[inline(always)] + pub const fn shl_vartime(&self, n: usize) -> Self { + let mut limbs = [Limb::ZERO; LIMBS]; + + if n >= Limb::BITS * LIMBS { + return Self { limbs }; + } + + let shift_num = n / Limb::BITS; + let rem = n % Limb::BITS; + + let mut i = LIMBS; + while i > shift_num { + i -= 1; + limbs[i] = self.limbs[i - shift_num]; + } + + let (new_lower, _carry) = (Self { limbs }).shl_limb(rem); + new_lower + } + + /// Computes a left shift on a wide input as `(lo, hi)`. + /// + /// NOTE: this operation is variable time with respect to `n` *ONLY*. + /// + /// When used with a fixed `n`, this function is constant-time with respect + /// to `self`. + #[inline(always)] + pub const fn shl_vartime_wide(lower_upper: (Self, Self), n: usize) -> (Self, Self) { + let (lower, mut upper) = lower_upper; + let new_lower = lower.shl_vartime(n); + upper = upper.shl_vartime(n); + if n >= Self::BITS { + upper = upper.bitor(&lower.shl_vartime(n - Self::BITS)); + } else { + upper = upper.bitor(&lower.shr_vartime(Self::BITS - n)); + } + + (new_lower, upper) + } + + /// Computes `self << n`. + /// Returns zero if `n >= Self::BITS`. + pub const fn shl(&self, shift: usize) -> Self { + let overflow = CtChoice::from_usize_lt(shift, Self::BITS).not(); + let shift = shift % Self::BITS; + let mut result = *self; + let mut i = 0; + while i < Self::LOG2_BITS { + let bit = CtChoice::from_lsb((shift as Word >> i) & 1); + result = Uint::ct_select(&result, &result.shl_vartime(1 << i), bit); + i += 1; + } + + Uint::ct_select(&result, &Self::ZERO, overflow) + } +} + +impl Shl for Uint { + type Output = Uint; + + /// NOTE: this operation is variable time with respect to `rhs` *ONLY*. + /// + /// When used with a fixed `rhs`, this function is constant-time with respect + /// to `self`. + fn shl(self, rhs: usize) -> Uint { + Uint::::shl(&self, rhs) + } +} + +impl Shl for &Uint { + type Output = Uint; + + /// NOTE: this operation is variable time with respect to `rhs` *ONLY*. + /// + /// When used with a fixed `rhs`, this function is constant-time with respect + /// to `self`. + fn shl(self, rhs: usize) -> Uint { + self.shl(rhs) + } +} + +impl ShlAssign for Uint { + /// NOTE: this operation is variable time with respect to `rhs` *ONLY*. + /// + /// When used with a fixed `rhs`, this function is constant-time with respect + /// to `self`. + fn shl_assign(&mut self, rhs: usize) { + *self = self.shl(rhs) + } +} + +#[cfg(test)] +mod tests { + use crate::{Limb, Uint, U128, U256}; + + const N: U256 = + U256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); + + const TWO_N: U256 = + U256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD755DB9CD5E9140777FA4BD19A06C8282"); + + const FOUR_N: U256 = + U256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAEABB739ABD2280EEFF497A3340D90504"); + + const SIXTY_FIVE: U256 = + U256::from_be_hex("FFFFFFFFFFFFFFFD755DB9CD5E9140777FA4BD19A06C82820000000000000000"); + + const EIGHTY_EIGHT: U256 = + U256::from_be_hex("FFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD03641410000000000000000000000"); + + const SIXTY_FOUR: U256 = + U256::from_be_hex("FFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD03641410000000000000000"); + + #[test] + fn shl_simple() { + let mut t = U256::from(1u8); + assert_eq!(t << 1, U256::from(2u8)); + t = U256::from(3u8); + assert_eq!(t << 8, U256::from(0x300u16)); + } + + #[test] + fn shl1() { + assert_eq!(N << 1, TWO_N); + } + + #[test] + fn shl2() { + assert_eq!(N << 2, FOUR_N); + } + + #[test] + fn shl65() { + assert_eq!(N << 65, SIXTY_FIVE); + } + + #[test] + fn shl88() { + assert_eq!(N << 88, EIGHTY_EIGHT); + } + + #[test] + fn shl256() { + assert_eq!(N << 256, U256::default()); + } + + #[test] + fn shl64() { + assert_eq!(N << 64, SIXTY_FOUR); + } + + #[test] + fn shl_wide_1_1_128() { + assert_eq!( + Uint::shl_vartime_wide((U128::ONE, U128::ONE), 128), + (U128::ZERO, U128::ONE) + ); + } + + #[test] + fn shl_wide_max_0_1() { + assert_eq!( + Uint::shl_vartime_wide((U128::MAX, U128::ZERO), 1), + (U128::MAX.sbb(&U128::ONE, Limb::ZERO).0, U128::ONE) + ); + } + + #[test] + fn shl_wide_max_max_256() { + assert_eq!( + Uint::shl_vartime_wide((U128::MAX, U128::MAX), 256), + (U128::ZERO, U128::ZERO) + ); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/shr.rs b/src/rust/vendor/crypto-bigint/src/uint/shr.rs new file mode 100644 index 000000000..6a36fbe8b --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/shr.rs @@ -0,0 +1,186 @@ +//! [`Uint`] bitwise right shift operations. + +use super::Uint; +use crate::{limb::HI_BIT, CtChoice, Limb, Word}; +use core::ops::{Shr, ShrAssign}; + +impl Uint { + /// Computes `self >> 1` in constant-time, returning [`CtChoice::TRUE`] if the overflowing bit + /// was set, and [`CtChoice::FALSE`] otherwise. + pub(crate) const fn shr_1(&self) -> (Self, CtChoice) { + let mut shifted_bits = [0; LIMBS]; + let mut i = 0; + while i < LIMBS { + shifted_bits[i] = self.limbs[i].0 >> 1; + i += 1; + } + + let mut carry_bits = [0; LIMBS]; + let mut i = 0; + while i < LIMBS { + carry_bits[i] = self.limbs[i].0 << HI_BIT; + i += 1; + } + + let mut limbs = [Limb(0); LIMBS]; + + let mut i = 0; + while i < (LIMBS - 1) { + limbs[i] = Limb(shifted_bits[i] | carry_bits[i + 1]); + i += 1; + } + limbs[LIMBS - 1] = Limb(shifted_bits[LIMBS - 1]); + + debug_assert!(carry_bits[LIMBS - 1] == 0 || carry_bits[LIMBS - 1] == (1 << HI_BIT)); + ( + Uint::new(limbs), + CtChoice::from_lsb(carry_bits[0] >> HI_BIT), + ) + } + + /// Computes `self >> n`. + /// + /// NOTE: this operation is variable time with respect to `n` *ONLY*. + /// + /// When used with a fixed `n`, this function is constant-time with respect + /// to `self`. + #[inline(always)] + pub const fn shr_vartime(&self, shift: usize) -> Self { + let full_shifts = shift / Limb::BITS; + let small_shift = shift & (Limb::BITS - 1); + let mut limbs = [Limb::ZERO; LIMBS]; + + if shift > Limb::BITS * LIMBS { + return Self { limbs }; + } + + let n = LIMBS - full_shifts; + let mut i = 0; + + if small_shift == 0 { + while i < n { + limbs[i] = Limb(self.limbs[i + full_shifts].0); + i += 1; + } + } else { + while i < n { + let mut lo = self.limbs[i + full_shifts].0 >> small_shift; + + if i < (LIMBS - 1) - full_shifts { + lo |= self.limbs[i + full_shifts + 1].0 << (Limb::BITS - small_shift); + } + + limbs[i] = Limb(lo); + i += 1; + } + } + + Self { limbs } + } + + /// Computes a right shift on a wide input as `(lo, hi)`. + /// + /// NOTE: this operation is variable time with respect to `n` *ONLY*. + /// + /// When used with a fixed `n`, this function is constant-time with respect + /// to `self`. + #[inline(always)] + pub const fn shr_vartime_wide(lower_upper: (Self, Self), n: usize) -> (Self, Self) { + let (mut lower, upper) = lower_upper; + let new_upper = upper.shr_vartime(n); + lower = lower.shr_vartime(n); + if n >= Self::BITS { + lower = lower.bitor(&upper.shr_vartime(n - Self::BITS)); + } else { + lower = lower.bitor(&upper.shl_vartime(Self::BITS - n)); + } + + (lower, new_upper) + } + + /// Computes `self << n`. + /// Returns zero if `n >= Self::BITS`. + pub const fn shr(&self, shift: usize) -> Self { + let overflow = CtChoice::from_usize_lt(shift, Self::BITS).not(); + let shift = shift % Self::BITS; + let mut result = *self; + let mut i = 0; + while i < Self::LOG2_BITS { + let bit = CtChoice::from_lsb((shift as Word >> i) & 1); + result = Uint::ct_select(&result, &result.shr_vartime(1 << i), bit); + i += 1; + } + + Uint::ct_select(&result, &Self::ZERO, overflow) + } +} + +impl Shr for Uint { + type Output = Uint; + + /// NOTE: this operation is variable time with respect to `rhs` *ONLY*. + /// + /// When used with a fixed `rhs`, this function is constant-time with respect + /// to `self`. + fn shr(self, rhs: usize) -> Uint { + Uint::::shr(&self, rhs) + } +} + +impl Shr for &Uint { + type Output = Uint; + + /// NOTE: this operation is variable time with respect to `rhs` *ONLY*. + /// + /// When used with a fixed `rhs`, this function is constant-time with respect + /// to `self`. + fn shr(self, rhs: usize) -> Uint { + self.shr(rhs) + } +} + +impl ShrAssign for Uint { + fn shr_assign(&mut self, rhs: usize) { + *self = self.shr(rhs); + } +} + +#[cfg(test)] +mod tests { + use crate::{Uint, U128, U256}; + + const N: U256 = + U256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); + + const N_2: U256 = + U256::from_be_hex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0"); + + #[test] + fn shr1() { + assert_eq!(N >> 1, N_2); + } + + #[test] + fn shr_wide_1_1_128() { + assert_eq!( + Uint::shr_vartime_wide((U128::ONE, U128::ONE), 128), + (U128::ONE, U128::ZERO) + ); + } + + #[test] + fn shr_wide_0_max_1() { + assert_eq!( + Uint::shr_vartime_wide((U128::ZERO, U128::MAX), 1), + (U128::ONE << 127, U128::MAX >> 1) + ); + } + + #[test] + fn shr_wide_max_max_256() { + assert_eq!( + Uint::shr_vartime_wide((U128::MAX, U128::MAX), 256), + (U128::ZERO, U128::ZERO) + ); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/split.rs b/src/rust/vendor/crypto-bigint/src/uint/split.rs new file mode 100644 index 000000000..e6909743c --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/split.rs @@ -0,0 +1,37 @@ +use crate::{Limb, Uint}; + +/// Split this number in half, returning its high and low components +/// respectively. +#[inline] +pub(crate) const fn split_mixed( + n: &Uint, +) -> (Uint, Uint) { + let top = L + H; + let top = if top < O { top } else { O }; + let mut lo = [Limb::ZERO; L]; + let mut hi = [Limb::ZERO; H]; + let mut i = 0; + + while i < top { + if i < L { + lo[i] = n.limbs[i]; + } else { + hi[i - L] = n.limbs[i]; + } + i += 1; + } + + (Uint { limbs: hi }, Uint { limbs: lo }) +} + +#[cfg(test)] +mod tests { + use crate::{U128, U64}; + + #[test] + fn split() { + let (hi, lo) = U128::from_be_hex("00112233445566778899aabbccddeeff").split(); + assert_eq!(hi, U64::from_u64(0x0011223344556677)); + assert_eq!(lo, U64::from_u64(0x8899aabbccddeeff)); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/sqrt.rs b/src/rust/vendor/crypto-bigint/src/uint/sqrt.rs new file mode 100644 index 000000000..5c96afb1a --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/sqrt.rs @@ -0,0 +1,177 @@ +//! [`Uint`] square root operations. + +use super::Uint; +use crate::{Limb, Word}; +use subtle::{ConstantTimeEq, CtOption}; + +impl Uint { + /// See [`Self::sqrt_vartime`]. + #[deprecated( + since = "0.5.3", + note = "This functionality will be moved to `sqrt_vartime` in a future release." + )] + pub const fn sqrt(&self) -> Self { + self.sqrt_vartime() + } + + /// Computes √(`self`) + /// Uses Brent & Zimmermann, Modern Computer Arithmetic, v0.5.9, Algorithm 1.13 + /// + /// Callers can check if `self` is a square by squaring the result + pub const fn sqrt_vartime(&self) -> Self { + let max_bits = (self.bits_vartime() + 1) >> 1; + let cap = Self::ONE.shl_vartime(max_bits); + let mut guess = cap; // ≥ √(`self`) + let mut xn = { + let q = self.wrapping_div(&guess); + let t = guess.wrapping_add(&q); + t.shr_vartime(1) + }; + + // If guess increased, the initial guess was low. + // Repeat until reverse course. + while Uint::ct_lt(&guess, &xn).is_true_vartime() { + // Sometimes an increase is too far, especially with large + // powers, and then takes a long time to walk back. The upper + // bound is based on bit size, so saturate on that. + let le = Limb::ct_le(Limb(xn.bits_vartime() as Word), Limb(max_bits as Word)); + guess = Self::ct_select(&cap, &xn, le); + xn = { + let q = self.wrapping_div(&guess); + let t = guess.wrapping_add(&q); + t.shr_vartime(1) + }; + } + + // Repeat while guess decreases. + while Uint::ct_gt(&guess, &xn).is_true_vartime() && xn.ct_is_nonzero().is_true_vartime() { + guess = xn; + xn = { + let q = self.wrapping_div(&guess); + let t = guess.wrapping_add(&q); + t.shr_vartime(1) + }; + } + + Self::ct_select(&Self::ZERO, &guess, self.ct_is_nonzero()) + } + + /// See [`Self::wrapping_sqrt_vartime`]. + #[deprecated( + since = "0.5.3", + note = "This functionality will be moved to `wrapping_sqrt_vartime` in a future release." + )] + pub const fn wrapping_sqrt(&self) -> Self { + self.wrapping_sqrt_vartime() + } + + /// Wrapped sqrt is just normal √(`self`) + /// There’s no way wrapping could ever happen. + /// This function exists, so that all operations are accounted for in the wrapping operations. + pub const fn wrapping_sqrt_vartime(&self) -> Self { + self.sqrt_vartime() + } + + /// See [`Self::checked_sqrt_vartime`]. + #[deprecated( + since = "0.5.3", + note = "This functionality will be moved to `checked_sqrt_vartime` in a future release." + )] + pub fn checked_sqrt(&self) -> CtOption { + self.checked_sqrt_vartime() + } + + /// Perform checked sqrt, returning a [`CtOption`] which `is_some` + /// only if the √(`self`)² == self + pub fn checked_sqrt_vartime(&self) -> CtOption { + let r = self.sqrt_vartime(); + let s = r.wrapping_mul(&r); + CtOption::new(r, ConstantTimeEq::ct_eq(self, &s)) + } +} + +#[cfg(test)] +mod tests { + use crate::{Limb, U256}; + + #[cfg(feature = "rand")] + use { + crate::{CheckedMul, Random, U512}, + rand_chacha::ChaChaRng, + rand_core::{RngCore, SeedableRng}, + }; + + #[test] + fn edge() { + assert_eq!(U256::ZERO.sqrt_vartime(), U256::ZERO); + assert_eq!(U256::ONE.sqrt_vartime(), U256::ONE); + let mut half = U256::ZERO; + for i in 0..half.limbs.len() / 2 { + half.limbs[i] = Limb::MAX; + } + assert_eq!(U256::MAX.sqrt_vartime(), half,); + } + + #[test] + fn simple() { + let tests = [ + (4u8, 2u8), + (9, 3), + (16, 4), + (25, 5), + (36, 6), + (49, 7), + (64, 8), + (81, 9), + (100, 10), + (121, 11), + (144, 12), + (169, 13), + ]; + for (a, e) in &tests { + let l = U256::from(*a); + let r = U256::from(*e); + assert_eq!(l.sqrt_vartime(), r); + assert_eq!(l.checked_sqrt_vartime().is_some().unwrap_u8(), 1u8); + } + } + + #[test] + fn nonsquares() { + assert_eq!(U256::from(2u8).sqrt_vartime(), U256::from(1u8)); + assert_eq!( + U256::from(2u8).checked_sqrt_vartime().is_some().unwrap_u8(), + 0 + ); + assert_eq!(U256::from(3u8).sqrt_vartime(), U256::from(1u8)); + assert_eq!( + U256::from(3u8).checked_sqrt_vartime().is_some().unwrap_u8(), + 0 + ); + assert_eq!(U256::from(5u8).sqrt_vartime(), U256::from(2u8)); + assert_eq!(U256::from(6u8).sqrt_vartime(), U256::from(2u8)); + assert_eq!(U256::from(7u8).sqrt_vartime(), U256::from(2u8)); + assert_eq!(U256::from(8u8).sqrt_vartime(), U256::from(2u8)); + assert_eq!(U256::from(10u8).sqrt_vartime(), U256::from(3u8)); + } + + #[cfg(feature = "rand")] + #[test] + fn fuzz() { + let mut rng = ChaChaRng::from_seed([7u8; 32]); + for _ in 0..50 { + let t = rng.next_u32() as u64; + let s = U256::from(t); + let s2 = s.checked_mul(&s).unwrap(); + assert_eq!(s2.sqrt_vartime(), s); + assert_eq!(s2.checked_sqrt_vartime().is_some().unwrap_u8(), 1); + } + + for _ in 0..50 { + let s = U256::random(&mut rng); + let mut s2 = U512::ZERO; + s2.limbs[..s.limbs.len()].copy_from_slice(&s.limbs); + assert_eq!(s.square().sqrt_vartime(), s2); + } + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/sub.rs b/src/rust/vendor/crypto-bigint/src/uint/sub.rs new file mode 100644 index 000000000..571dd6aa5 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/sub.rs @@ -0,0 +1,215 @@ +//! [`Uint`] addition operations. + +use super::Uint; +use crate::{Checked, CheckedSub, CtChoice, Limb, Wrapping, Zero}; +use core::ops::{Sub, SubAssign}; +use subtle::CtOption; + +impl Uint { + /// Computes `a - (b + borrow)`, returning the result along with the new borrow. + #[inline(always)] + pub const fn sbb(&self, rhs: &Self, mut borrow: Limb) -> (Self, Limb) { + let mut limbs = [Limb::ZERO; LIMBS]; + let mut i = 0; + + while i < LIMBS { + let (w, b) = self.limbs[i].sbb(rhs.limbs[i], borrow); + limbs[i] = w; + borrow = b; + i += 1; + } + + (Self { limbs }, borrow) + } + + /// Perform saturating subtraction, returning `ZERO` on underflow. + pub const fn saturating_sub(&self, rhs: &Self) -> Self { + let (res, underflow) = self.sbb(rhs, Limb::ZERO); + Self::ct_select(&res, &Self::ZERO, CtChoice::from_mask(underflow.0)) + } + + /// Perform wrapping subtraction, discarding underflow and wrapping around + /// the boundary of the type. + pub const fn wrapping_sub(&self, rhs: &Self) -> Self { + self.sbb(rhs, Limb::ZERO).0 + } + + /// Perform wrapping subtraction, returning the truthy value as the second element of the tuple + /// if an underflow has occurred. + pub(crate) const fn conditional_wrapping_sub( + &self, + rhs: &Self, + choice: CtChoice, + ) -> (Self, CtChoice) { + let actual_rhs = Uint::ct_select(&Uint::ZERO, rhs, choice); + let (res, borrow) = self.sbb(&actual_rhs, Limb::ZERO); + (res, CtChoice::from_mask(borrow.0)) + } +} + +impl CheckedSub<&Uint> for Uint { + type Output = Self; + + fn checked_sub(&self, rhs: &Self) -> CtOption { + let (result, underflow) = self.sbb(rhs, Limb::ZERO); + CtOption::new(result, underflow.is_zero()) + } +} + +impl Sub for Wrapping> { + type Output = Self; + + fn sub(self, rhs: Self) -> Wrapping> { + Wrapping(self.0.wrapping_sub(&rhs.0)) + } +} + +impl Sub<&Wrapping>> for Wrapping> { + type Output = Wrapping>; + + fn sub(self, rhs: &Wrapping>) -> Wrapping> { + Wrapping(self.0.wrapping_sub(&rhs.0)) + } +} + +impl Sub>> for &Wrapping> { + type Output = Wrapping>; + + fn sub(self, rhs: Wrapping>) -> Wrapping> { + Wrapping(self.0.wrapping_sub(&rhs.0)) + } +} + +impl Sub<&Wrapping>> for &Wrapping> { + type Output = Wrapping>; + + fn sub(self, rhs: &Wrapping>) -> Wrapping> { + Wrapping(self.0.wrapping_sub(&rhs.0)) + } +} + +impl SubAssign for Wrapping> { + fn sub_assign(&mut self, other: Self) { + *self = *self - other; + } +} + +impl SubAssign<&Wrapping>> for Wrapping> { + fn sub_assign(&mut self, other: &Self) { + *self = *self - other; + } +} + +impl Sub for Checked> { + type Output = Self; + + fn sub(self, rhs: Self) -> Checked> { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))), + ) + } +} + +impl Sub<&Checked>> for Checked> { + type Output = Checked>; + + fn sub(self, rhs: &Checked>) -> Checked> { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))), + ) + } +} + +impl Sub>> for &Checked> { + type Output = Checked>; + + fn sub(self, rhs: Checked>) -> Checked> { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))), + ) + } +} + +impl Sub<&Checked>> for &Checked> { + type Output = Checked>; + + fn sub(self, rhs: &Checked>) -> Checked> { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))), + ) + } +} + +impl SubAssign for Checked> { + fn sub_assign(&mut self, other: Self) { + *self = *self - other; + } +} + +impl SubAssign<&Checked>> for Checked> { + fn sub_assign(&mut self, other: &Self) { + *self = *self - other; + } +} + +#[cfg(test)] +mod tests { + use crate::{CheckedSub, Limb, U128}; + + #[test] + fn sbb_no_borrow() { + let (res, borrow) = U128::ONE.sbb(&U128::ONE, Limb::ZERO); + assert_eq!(res, U128::ZERO); + assert_eq!(borrow, Limb::ZERO); + } + + #[test] + fn sbb_with_borrow() { + let (res, borrow) = U128::ZERO.sbb(&U128::ONE, Limb::ZERO); + + assert_eq!(res, U128::MAX); + assert_eq!(borrow, Limb::MAX); + } + + #[test] + fn saturating_sub_no_borrow() { + assert_eq!( + U128::from(5u64).saturating_sub(&U128::ONE), + U128::from(4u64) + ); + } + + #[test] + fn saturating_sub_with_borrow() { + assert_eq!( + U128::from(4u64).saturating_sub(&U128::from(5u64)), + U128::ZERO + ); + } + + #[test] + fn wrapping_sub_no_borrow() { + assert_eq!(U128::ONE.wrapping_sub(&U128::ONE), U128::ZERO); + } + + #[test] + fn wrapping_sub_with_borrow() { + assert_eq!(U128::ZERO.wrapping_sub(&U128::ONE), U128::MAX); + } + + #[test] + fn checked_sub_ok() { + let result = U128::ONE.checked_sub(&U128::ONE); + assert_eq!(result.unwrap(), U128::ZERO); + } + + #[test] + fn checked_sub_overflow() { + let result = U128::ZERO.checked_sub(&U128::ONE); + assert!(!bool::from(result.is_some())); + } +} diff --git a/src/rust/vendor/crypto-bigint/src/uint/sub_mod.rs b/src/rust/vendor/crypto-bigint/src/uint/sub_mod.rs new file mode 100644 index 000000000..936c6d7a0 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/uint/sub_mod.rs @@ -0,0 +1,191 @@ +//! [`Uint`] subtraction modulus operations. + +use crate::{Limb, SubMod, Uint}; + +impl Uint { + /// Computes `self - rhs mod p`. + /// + /// Assumes `self - rhs` as unbounded signed integer is in `[-p, p)`. + pub const fn sub_mod(&self, rhs: &Uint, p: &Uint) -> Uint { + let (out, borrow) = self.sbb(rhs, Limb::ZERO); + + // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise + // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. + let mask = Uint::from_words([borrow.0; LIMBS]); + + out.wrapping_add(&p.bitand(&mask)) + } + + /// Returns `(self..., carry) - (rhs...) mod (p...)`, where `carry <= 1`. + /// Assumes `-(p...) <= (self..., carry) - (rhs...) < (p...)`. + #[inline(always)] + pub(crate) const fn sub_mod_with_carry(&self, carry: Limb, rhs: &Self, p: &Self) -> Self { + debug_assert!(carry.0 <= 1); + + let (out, borrow) = self.sbb(rhs, Limb::ZERO); + + // The new `borrow = Word::MAX` iff `carry == 0` and `borrow == Word::MAX`. + let borrow = (!carry.0.wrapping_neg()) & borrow.0; + + // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise + // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. + let mask = Uint::from_words([borrow; LIMBS]); + + out.wrapping_add(&p.bitand(&mask)) + } + + /// Computes `self - rhs mod p` for the special modulus + /// `p = MAX+1-c` where `c` is small enough to fit in a single [`Limb`]. + /// + /// Assumes `self - rhs` as unbounded signed integer is in `[-p, p)`. + pub const fn sub_mod_special(&self, rhs: &Self, c: Limb) -> Self { + let (out, borrow) = self.sbb(rhs, Limb::ZERO); + + // If underflow occurred, then we need to subtract `c` to account for + // the underflow. This cannot underflow due to the assumption + // `self - rhs >= -p`. + let l = borrow.0 & c.0; + out.wrapping_sub(&Uint::from_word(l)) + } +} + +impl SubMod for Uint { + type Output = Self; + + fn sub_mod(&self, rhs: &Self, p: &Self) -> Self { + debug_assert!(self < p); + debug_assert!(rhs < p); + self.sub_mod(rhs, p) + } +} + +#[cfg(all(test, feature = "rand"))] +mod tests { + use crate::{Limb, NonZero, Random, RandomMod, Uint}; + use rand_core::SeedableRng; + + macro_rules! test_sub_mod { + ($size:expr, $test_name:ident) => { + #[test] + fn $test_name() { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); + let moduli = [ + NonZero::>::random(&mut rng), + NonZero::>::random(&mut rng), + ]; + + for p in &moduli { + let base_cases = [ + (1u64, 0u64, 1u64.into()), + (0, 1, p.wrapping_sub(&1u64.into())), + (0, 0, 0u64.into()), + ]; + for (a, b, c) in &base_cases { + let a: Uint<$size> = (*a).into(); + let b: Uint<$size> = (*b).into(); + + let x = a.sub_mod(&b, p); + assert_eq!(*c, x, "{} - {} mod {} = {} != {}", a, b, p, x, c); + } + + if $size > 1 { + for _i in 0..100 { + let a: Uint<$size> = Limb::random(&mut rng).into(); + let b: Uint<$size> = Limb::random(&mut rng).into(); + let (a, b) = if a < b { (b, a) } else { (a, b) }; + + let c = a.sub_mod(&b, p); + assert!(c < **p, "not reduced"); + assert_eq!(c, a.wrapping_sub(&b), "result incorrect"); + } + } + + for _i in 0..100 { + let a = Uint::<$size>::random_mod(&mut rng, p); + let b = Uint::<$size>::random_mod(&mut rng, p); + + let c = a.sub_mod(&b, p); + assert!(c < **p, "not reduced: {} >= {} ", c, p); + + let x = a.wrapping_sub(&b); + if a >= b && x < **p { + assert_eq!(c, x, "incorrect result"); + } + } + } + } + }; + } + + macro_rules! test_sub_mod_special { + ($size:expr, $test_name:ident) => { + #[test] + fn $test_name() { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); + let moduli = [ + NonZero::::random(&mut rng), + NonZero::::random(&mut rng), + ]; + + for special in &moduli { + let p = &NonZero::new(Uint::ZERO.wrapping_sub(&Uint::from_word(special.0))) + .unwrap(); + + let minus_one = p.wrapping_sub(&Uint::ONE); + + let base_cases = [ + (Uint::ZERO, Uint::ZERO, Uint::ZERO), + (Uint::ONE, Uint::ZERO, Uint::ONE), + (Uint::ZERO, Uint::ONE, minus_one), + (minus_one, minus_one, Uint::ZERO), + (Uint::ZERO, minus_one, Uint::ONE), + ]; + for (a, b, c) in &base_cases { + let x = a.sub_mod_special(&b, *special.as_ref()); + assert_eq!(*c, x, "{} - {} mod {} = {} != {}", a, b, p, x, c); + } + + for _i in 0..100 { + let a = Uint::<$size>::random_mod(&mut rng, p); + let b = Uint::<$size>::random_mod(&mut rng, p); + + let c = a.sub_mod_special(&b, *special.as_ref()); + assert!(c < **p, "not reduced: {} >= {} ", c, p); + + let expected = a.sub_mod(&b, p); + assert_eq!(c, expected, "incorrect result"); + } + } + } + }; + } + + // Test requires 1-limb is capable of representing a 64-bit integer + #[cfg(target_pointer_width = "64")] + test_sub_mod!(1, sub1); + + test_sub_mod!(2, sub2); + test_sub_mod!(3, sub3); + test_sub_mod!(4, sub4); + test_sub_mod!(5, sub5); + test_sub_mod!(6, sub6); + test_sub_mod!(7, sub7); + test_sub_mod!(8, sub8); + test_sub_mod!(9, sub9); + test_sub_mod!(10, sub10); + test_sub_mod!(11, sub11); + test_sub_mod!(12, sub12); + + test_sub_mod_special!(1, sub_mod_special_1); + test_sub_mod_special!(2, sub_mod_special_2); + test_sub_mod_special!(3, sub_mod_special_3); + test_sub_mod_special!(4, sub_mod_special_4); + test_sub_mod_special!(5, sub_mod_special_5); + test_sub_mod_special!(6, sub_mod_special_6); + test_sub_mod_special!(7, sub_mod_special_7); + test_sub_mod_special!(8, sub_mod_special_8); + test_sub_mod_special!(9, sub_mod_special_9); + test_sub_mod_special!(10, sub_mod_special_10); + test_sub_mod_special!(11, sub_mod_special_11); + test_sub_mod_special!(12, sub_mod_special_12); +} diff --git a/src/rust/vendor/crypto-bigint/src/wrapping.rs b/src/rust/vendor/crypto-bigint/src/wrapping.rs new file mode 100644 index 000000000..7ee6016e0 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/src/wrapping.rs @@ -0,0 +1,117 @@ +//! Wrapping arithmetic. + +use crate::Zero; +use core::fmt; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; + +#[cfg(feature = "rand_core")] +use {crate::Random, rand_core::CryptoRngCore}; + +#[cfg(feature = "serde")] +use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer}; + +/// Provides intentionally-wrapped arithmetic on `T`. +/// +/// This is analogous to [`core::num::Wrapping`] but allows this crate to +/// define trait impls for this type. +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] +pub struct Wrapping(pub T); + +impl Zero for Wrapping { + const ZERO: Self = Self(T::ZERO); +} + +impl fmt::Display for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl fmt::Binary for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl fmt::Octal for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl fmt::LowerHex for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl fmt::UpperHex for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl ConditionallySelectable for Wrapping { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Wrapping(T::conditional_select(&a.0, &b.0, choice)) + } +} + +impl ConstantTimeEq for Wrapping { + fn ct_eq(&self, other: &Self) -> Choice { + self.0.ct_eq(&other.0) + } +} + +#[cfg(feature = "rand_core")] +impl Random for Wrapping { + fn random(rng: &mut impl CryptoRngCore) -> Self { + Wrapping(Random::random(rng)) + } +} + +#[cfg(feature = "serde")] +impl<'de, T: Deserialize<'de>> Deserialize<'de> for Wrapping { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Ok(Self(T::deserialize(deserializer)?)) + } +} + +#[cfg(feature = "serde")] +impl Serialize for Wrapping { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.0.serialize(serializer) + } +} + +#[cfg(all(test, feature = "serde"))] +#[allow(clippy::unwrap_used)] +mod tests { + use crate::{Wrapping, U64}; + + #[test] + fn serde() { + const TEST: Wrapping = Wrapping(U64::from_u64(0x0011223344556677)); + + let serialized = bincode::serialize(&TEST).unwrap(); + let deserialized: Wrapping = bincode::deserialize(&serialized).unwrap(); + + assert_eq!(TEST, deserialized); + } + + #[test] + fn serde_owned() { + const TEST: Wrapping = Wrapping(U64::from_u64(0x0011223344556677)); + + let serialized = bincode::serialize(&TEST).unwrap(); + let deserialized: Wrapping = bincode::deserialize_from(serialized.as_slice()).unwrap(); + + assert_eq!(TEST, deserialized); + } +} diff --git a/src/rust/vendor/crypto-bigint/tests/const_residue.rs b/src/rust/vendor/crypto-bigint/tests/const_residue.rs new file mode 100644 index 000000000..d02bdb44a --- /dev/null +++ b/src/rust/vendor/crypto-bigint/tests/const_residue.rs @@ -0,0 +1,10 @@ +//! Test to ensure that `const_residue!` works from outside this crate. + +use crypto_bigint::{const_residue, impl_modulus, modular::constant_mod::ResidueParams, U64}; + +impl_modulus!(TestMod, U64, "30e4b8f030ab42f3"); + +fn _test_fun() { + let base = U64::from(2u64); + let _base_mod = const_residue!(base, TestMod); +} diff --git a/src/rust/vendor/crypto-bigint/tests/impl_modulus.rs b/src/rust/vendor/crypto-bigint/tests/impl_modulus.rs new file mode 100644 index 000000000..98f5fe5d6 --- /dev/null +++ b/src/rust/vendor/crypto-bigint/tests/impl_modulus.rs @@ -0,0 +1,5 @@ +//! Test to ensure that `impl_modulus!` works from outside this crate. + +use crypto_bigint::{impl_modulus, U64}; + +impl_modulus!(TestMod, U64, "30e4b8f030ab42f3"); diff --git a/src/rust/vendor/crypto-bigint/tests/proptests.rs b/src/rust/vendor/crypto-bigint/tests/proptests.rs new file mode 100644 index 000000000..bad14bc1b --- /dev/null +++ b/src/rust/vendor/crypto-bigint/tests/proptests.rs @@ -0,0 +1,370 @@ +//! Equivalence tests between `num-bigint` and `crypto-bigint` + +use crypto_bigint::{ + modular::runtime_mod::{DynResidue, DynResidueParams}, + CtChoice, Encoding, Limb, NonZero, Word, U256, +}; +use num_bigint::BigUint; +use num_integer::Integer; +use num_traits::identities::{One, Zero}; +use proptest::prelude::*; +use std::mem; + +/// Example prime number (NIST P-256 curve order) +const P: U256 = + U256::from_be_hex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"); + +fn to_biguint(uint: &U256) -> BigUint { + BigUint::from_bytes_le(uint.to_le_bytes().as_ref()) +} + +fn to_uint(big_uint: BigUint) -> U256 { + let mut input = [0u8; U256::BYTES]; + let encoded = big_uint.to_bytes_le(); + let l = encoded.len().min(U256::BYTES); + input[..l].copy_from_slice(&encoded[..l]); + + U256::from_le_slice(&input) +} + +prop_compose! { + fn uint()(bytes in any::<[u8; 32]>()) -> U256 { + U256::from_le_slice(&bytes) + } +} +prop_compose! { + fn uint_mod_p(p: U256)(a in uint()) -> U256 { + a.wrapping_rem(&p) + } +} +prop_compose! { + fn nonzero_limb()(x in any::()) -> Limb { + if x == 0 { Limb::from(1u32) } else {Limb::from(x)} + } +} + +proptest! { + #[test] + fn roundtrip(a in uint()) { + assert_eq!(a, to_uint(to_biguint(&a))); + } + + #[test] + fn shl_vartime(a in uint(), shift in any::()) { + let a_bi = to_biguint(&a); + + let expected = to_uint(a_bi << shift); + let actual = a.shl_vartime(shift as usize); + + assert_eq!(expected, actual); + } + + #[test] + fn shl(a in uint(), shift in any::()) { + let a_bi = to_biguint(&a); + + // Add a 50% probability of overflow. + let shift = (shift as usize) % (U256::BITS * 2); + + let expected = to_uint((a_bi << shift) & ((BigUint::one() << U256::BITS) - BigUint::one())); + let actual = a.shl(shift); + + assert_eq!(expected, actual); + } + + #[test] + fn shr(a in uint(), shift in any::()) { + let a_bi = to_biguint(&a); + + // Add a 50% probability of overflow. + let shift = (shift as usize) % (U256::BITS * 2); + + let expected = to_uint(a_bi >> shift); + let actual = a.shr(shift); + + assert_eq!(expected, actual); + } + + #[test] + fn wrapping_add(a in uint(), b in uint()) { + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&b); + + let expected = to_uint(a_bi + b_bi); + let actual = a.wrapping_add(&b); + + assert_eq!(expected, actual); + } + + #[test] + fn add_mod_nist_p256(a in uint_mod_p(P), b in uint_mod_p(P)) { + assert!(a < P); + assert!(b < P); + + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&b); + let p_bi = to_biguint(&P); + + let expected = to_uint((a_bi + b_bi) % p_bi); + let actual = a.add_mod(&b, &P); + + assert!(expected < P); + assert!(actual < P); + + assert_eq!(expected, actual); + } + + #[test] + fn sub_mod_nist_p256(mut a in uint_mod_p(P), mut b in uint_mod_p(P)) { + if b > a { + mem::swap(&mut a, &mut b); + } + + assert!(a < P); + assert!(b < P); + + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&b); + let p_bi = to_biguint(&P); + + let expected = to_uint((a_bi - b_bi) % p_bi); + let actual = a.sub_mod(&b, &P); + + assert!(expected < P); + assert!(actual < P); + + assert_eq!(expected, actual); + } + + #[test] + fn wrapping_sub(mut a in uint(), mut b in uint()) { + if b > a { + mem::swap(&mut a, &mut b); + } + + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&b); + + let expected = to_uint(a_bi - b_bi); + let actual = a.wrapping_sub(&b); + + assert_eq!(expected, actual); + } + + #[test] + fn wrapping_mul(a in uint(), b in uint()) { + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&b); + + let expected = to_uint(a_bi * b_bi); + let actual = a.wrapping_mul(&b); + + assert_eq!(expected, actual); + } + + #[test] + fn wrapping_div(a in uint(), b in uint()) { + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&b); + + if !b_bi.is_zero() { + let expected = to_uint(a_bi / b_bi); + let actual = a.wrapping_div(&b); + + assert_eq!(expected, actual); + } + } + + #[test] + fn div_rem_limb(a in uint(), b in nonzero_limb()) { + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&U256::from(b)); + + let (expected_quo, expected_rem) = a_bi.div_rem(&b_bi); + let (actual_quo, actual_rem) = a.div_rem_limb(NonZero::new(b).unwrap()); + assert_eq!(to_uint(expected_quo), actual_quo); + assert_eq!(to_uint(expected_rem), U256::from(actual_rem)); + } + + #[test] + fn div_rem_limb_min_max(a in uint()) { + let a_bi = to_biguint(&a); + + for b in [Limb::from(1u32), Limb::MAX] { + let b_bi = to_biguint(&U256::from(b)); + let (expected_quo, expected_rem) = a_bi.div_rem(&b_bi); + let (actual_quo, actual_rem) = a.div_rem_limb(NonZero::new(b).unwrap()); + assert_eq!(to_uint(expected_quo), actual_quo); + assert_eq!(to_uint(expected_rem), U256::from(actual_rem)); + } + } + + #[test] + fn wrapping_rem(a in uint(), b in uint()) { + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&b); + + if !b_bi.is_zero() { + let expected = to_uint(a_bi % b_bi); + let actual = a.wrapping_rem(&b); + + assert_eq!(expected, actual); + } + } + + #[test] + fn inv_mod2k(a in uint(), k in any::()) { + let a = a | U256::ONE; // make odd + let k = k % (U256::BITS + 1); + let a_bi = to_biguint(&a); + let m_bi = BigUint::one() << k; + + let actual = a.inv_mod2k(k); + let actual_vartime = a.inv_mod2k_vartime(k); + assert_eq!(actual, actual_vartime); + + if k == 0 { + assert_eq!(actual, U256::ZERO); + } + else { + let inv_bi = to_biguint(&actual); + let res = (inv_bi * a_bi) % m_bi; + assert_eq!(res, BigUint::one()); + } + } + + #[test] + fn inv_mod(a in uint(), b in uint()) { + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&b); + + let expected_is_some = if a_bi.gcd(&b_bi) == BigUint::one() { CtChoice::TRUE } else { CtChoice::FALSE }; + let (actual, actual_is_some) = a.inv_mod(&b); + + assert_eq!(bool::from(expected_is_some), bool::from(actual_is_some)); + + if actual_is_some.into() { + let inv_bi = to_biguint(&actual); + let res = (inv_bi * a_bi) % b_bi; + assert_eq!(res, BigUint::one()); + } + } + + #[test] + fn wrapping_sqrt(a in uint()) { + let a_bi = to_biguint(&a); + let expected = to_uint(a_bi.sqrt()); + let actual = a.wrapping_sqrt_vartime(); + + assert_eq!(expected, actual); + } + + #[test] + fn wrapping_or(a in uint(), b in uint()) { + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&b); + + if !b_bi.is_zero() { + let expected = to_uint(a_bi | b_bi); + let actual = a.wrapping_or(&b); + + assert_eq!(expected, actual); + } + } + + #[test] + fn wrapping_and(a in uint(), b in uint()) { + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&b); + + if !b_bi.is_zero() { + let expected = to_uint(a_bi & b_bi); + let actual = a.wrapping_and(&b); + + assert_eq!(expected, actual); + } + } + + #[test] + fn wrapping_xor(a in uint(), b in uint()) { + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&b); + if !b_bi.is_zero() { + let expected = to_uint(a_bi ^ b_bi); + let actual = a.wrapping_xor(&b); + + assert_eq!(expected, actual); + } + } + + #[test] + fn encoding(a in uint()) { + assert_eq!(a, U256::from_be_bytes(a.to_be_bytes())); + assert_eq!(a, U256::from_le_bytes(a.to_le_bytes())); + } + + #[test] + fn encoding_reverse(a in uint()) { + let mut bytes = a.to_be_bytes(); + bytes.reverse(); + assert_eq!(a, U256::from_le_bytes(bytes)); + + let mut bytes = a.to_le_bytes(); + bytes.reverse(); + assert_eq!(a, U256::from_be_bytes(bytes)); + } + + #[test] + fn residue_pow(a in uint_mod_p(P), b in uint()) { + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&b); + let p_bi = to_biguint(&P); + + let expected = to_uint(a_bi.modpow(&b_bi, &p_bi)); + + let params = DynResidueParams::new(&P); + let a_m = DynResidue::new(&a, params); + let actual = a_m.pow(&b).retrieve(); + + assert_eq!(expected, actual); + } + + #[test] + fn residue_pow_bounded_exp(a in uint_mod_p(P), b in uint(), exponent_bits in any::()) { + + let b_masked = b & (U256::ONE << exponent_bits.into()).wrapping_sub(&U256::ONE); + + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&b_masked); + let p_bi = to_biguint(&P); + + let expected = to_uint(a_bi.modpow(&b_bi, &p_bi)); + + let params = DynResidueParams::new(&P); + let a_m = DynResidue::new(&a, params); + let actual = a_m.pow_bounded_exp(&b, exponent_bits.into()).retrieve(); + + assert_eq!(expected, actual); + } + + #[test] + fn residue_div_by_2(a in uint_mod_p(P)) { + let a_bi = to_biguint(&a); + let p_bi = to_biguint(&P); + let two = BigUint::from(2u32); + + let expected = if a_bi.is_even() { + &a_bi / two + } + else { + (&a_bi + &p_bi) / two + }; + let expected = to_uint(expected); + + let params = DynResidueParams::new(&P); + let a_m = DynResidue::new(&a, params); + let actual = a_m.div_by_2().retrieve(); + + assert_eq!(expected, actual); + } +} diff --git a/src/rust/vendor/der/.cargo-checksum.json b/src/rust/vendor/der/.cargo-checksum.json new file mode 100644 index 000000000..9616c155d --- /dev/null +++ b/src/rust/vendor/der/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"20b6f7960a331387bb9eac5a5b2235d185082e821200f46d4bc3879aefab3977","Cargo.toml":"05484e46219261a0226f38d707b7347659362db805ee3da2aca31a135cdfd16a","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"ad64fcb9589f162720f3cc5010ad76ca6ad3764e11861f9192c489df176bb71d","README.md":"7eca00af3894b1bf13f1b50f69e8152b388b0fa1349a272e6c665f70ad3c4f31","src/arrayvec.rs":"725cb437e439ab9ab9b9a11faa3993d85308692affd96a854fedb17723c2993f","src/asn1.rs":"5b4c031224f5f9f81696d6f484824e745b8ddf167a95deac329aef26acfceebf","src/asn1/any.rs":"62c484808ab8167704c4d3ff635a650272b2689ccf0f100623589248a84abad5","src/asn1/bit_string.rs":"b34af7569a6eace60b9b8b1429b8d474e75e176c7682d79c002121c040b598fc","src/asn1/bmp_string.rs":"6adf94af2aed675ba2cb5fbcff7ee6281505c45fb7eb65e087fb87e89445b8b1","src/asn1/boolean.rs":"62f7b026f3990cc21dd4010d1bb26a5d06a6ae7c12cfc1c7d27e551781706291","src/asn1/choice.rs":"721a1322b862e060020b1af9020f7bd80958646c6508aa57aa999d774126ad13","src/asn1/context_specific.rs":"a1ec291b657581f26fee59de02877ea5d287468cf3dfc54a6803ab168bbfc91c","src/asn1/generalized_time.rs":"2d337c6927c56975138425b63a764b03df62e43dc2c76b44d9e51fb8c76fb29b","src/asn1/ia5_string.rs":"a885312bac486523bb70a9d76343df65651336f62b8dda29d6e02b1c6b73e3a7","src/asn1/integer.rs":"daabe34a2b234735bc5bd5ce9350fa687b5f8e602f5367202c48bb91fc3cc808","src/asn1/integer/int.rs":"9c6d72ded7e2d819ec463853e937436c7b8e9baaeed5767e6a316dc5b1b79dde","src/asn1/integer/uint.rs":"3f96610aa6a12a23c9b4f46bf2602207bac35682c1c5fa9fedbe942ff253c285","src/asn1/internal_macros.rs":"0891dfaa499ddfb0e1ca5b857ccd91e652acb61ddbc150737c73029a37daecc2","src/asn1/null.rs":"c28cddc9515b37e1045b75580fb8e53deb7e5649c3a4f0f7f94508267b56600a","src/asn1/octet_string.rs":"932d2a0cbdb4e4e345b6f62d4c95ce3a3eb23a43d9da192b82c996cc56d7665a","src/asn1/oid.rs":"0448b47bb62c4366e11aabf841bb615964d31530bf9ef67a79bdc1c3c8375d17","src/asn1/optional.rs":"782b9563ad34a405c5adb7fb9b165c2ade57091ef6692698f6ac56209809b1f6","src/asn1/printable_string.rs":"95d871fcd0faafe9905f63ac81a28163803b1cda59c137b0c02d865b142c6bd3","src/asn1/real.rs":"6513c27c6f5862b8eebe036e0dab9b61b3a91e5a8c5bc995189ddd8278610b1f","src/asn1/sequence.rs":"74e9ac1aaef547ff4288f899d216e63ac081a8415302a15472069d3bf42376ff","src/asn1/sequence_of.rs":"bd6ee2398ca5ffa7ee31633b3a79543d73f742a15cf7a1591c9493981430766d","src/asn1/set_of.rs":"208667d136f66c123a92a3f04475c068c1613e6ee0bd115e9f2766a45a0c4223","src/asn1/teletex_string.rs":"f5fb132cac430b2435526496a856ac27bcad7f8c738730debf35c1dfda28f06d","src/asn1/utc_time.rs":"37c25624a7a5d86a432619702a54959bffceec411fd5312c9ec14f1aa9af12a2","src/asn1/utf8_string.rs":"c335501488efbc5ce54781e99038e84d6f848c09fe88b53490f9fb4771e5e4b9","src/asn1/videotex_string.rs":"8a663e58e8c73e860613ec7b3078269a6b0e5c371f9d937bd1d4e1bb09f4f28f","src/bytes_owned.rs":"74224637f212ba36edfb989bf82ee3465d684d5b91b04c5252afe6b7356c310a","src/bytes_ref.rs":"6c7d2dd1de785180c1ab8235e5f59778b55bdb0e656eb7e82dafdc6b705f51ac","src/datetime.rs":"d0f269d07f4d5ba9a5f7b9b0ae4727b348487cda73210bb8fc5d4575d5a19f1b","src/decode.rs":"bc4b4e5afd1cfa4878d75283b294b52062f800d568389790200db8c239feddae","src/document.rs":"a56d2aa413892becec182f2c8a32377551ed0fdd3ccb292c41b64c1f48b69dad","src/encode.rs":"6a29ff6e583eb2bd8b6a77e06d61378c75c451bb8ca670df480a6ac0dfb8192d","src/encode_ref.rs":"8b0d0010780335efd6bedb3659caf33ed7e514c8c7ae22c701eb4bdea98b3dbd","src/error.rs":"d33bba19755d5e36dbcf864332c1c00b0f29484a0e5929355874edf8f4699bbe","src/header.rs":"33ddb6b8c03c81f163a0d06b1055ccd515618658b6b2ae6b1e47ab84fa96d4f4","src/length.rs":"283b0f4eb8fba660b742e7cba0cb420610ecd8e839cf467c2fea8584d60485cf","src/lib.rs":"a4aad3d71f3ff18d692088d37f0c409f68cdeee22218795c2ca2a83b029e4f54","src/ord.rs":"6b9685d805a5e0060e2432234e04e93ce81e27fdc7711eae86ba2d01c00b70f7","src/reader.rs":"e065486cb68fab6831ddee0f4a9b9635a05259cc1f0ec2939de767f6e375743f","src/reader/nested.rs":"6e5ab8c7cd54f867c8faa60545c441cbe5634f78a91be75bcbd31692fed5fcf0","src/reader/pem.rs":"b5c5e6e7c4737c4f06dc126ae246f5b3cdd1dc4165401bd5219552fcd5e49e7f","src/reader/slice.rs":"6da8050380694ba43effdfaa160e098dd152748af897bef41c6020f9853a76ef","src/referenced.rs":"e5927bba4665321632c7dc685a948e00e79c1a6ea2a79fb6e00ce8cc7be80223","src/str_owned.rs":"ffb291a7bea958aa931835103641afb4cd310433a1853dcfc65adc5bafd76e95","src/str_ref.rs":"4e4f928ec851ab50ad825792ae42549776d12609ed09da8b7bf2531eec6bd773","src/tag.rs":"1b2c19072ff96fafa74e4200910e31e29808139068409e115b7d31c6b99f0e01","src/tag/class.rs":"dcb78907dbaaf588db0e0929eacd5394553c6ea7f69e8948d733c2597f35d016","src/tag/mode.rs":"52854315fcedf0476015e4afd55c8699f4d4b69d497f58737b0f2572bcaa89bf","src/tag/number.rs":"e89da7d085cdd446bb021c5a5abd46aa53fb95b572f2e15e84cc87b4e2bda86a","src/writer.rs":"36ef12ce394c857b2fc28435dfdac8f11c9b572065e4226781f2af0496d9df60","src/writer/pem.rs":"2d87fbb460fe6f0ff8cf38df2660b09abb0d640def86037b10b2211197ef7e65","src/writer/slice.rs":"ab955ccba9cef14a95a2a8922696bb2ad6ed2cbb2489a746a56dff9498d08528","tests/datetime.proptest-regressions":"f88a3c34c88b8438da12a92d47520e1bc926ed80ce890fd4eff4fdded80d3541","tests/datetime.rs":"e8fd8156618e5f8c0378b41617376e589405966cf284887cb3f73617f854a07f","tests/derive.rs":"5102bfac06f50f258d0e4c11597f9a60a78937461ebdb6a0cd43a8e749678db8","tests/examples/spki.der":"55dd4c74b0e48534e2f4e173ceceb50df8f27a7ac2aa8991cc7ae914e030bced","tests/examples/spki.pem":"36d717203cbca1812f05f30e0415251c928b659882092e653221a028571c6853","tests/pem.rs":"e1c27fae3d6cf0d357f49e12fb826bda977134076a5fdd60d38715d1bbc9d9fa","tests/set_of.rs":"c0562109025829e794e00f2097eaa8f7ed3d2b2aa1baca08fbc0c552f6980ab1"},"package":"f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"} \ No newline at end of file diff --git a/src/rust/vendor/der/CHANGELOG.md b/src/rust/vendor/der/CHANGELOG.md new file mode 100644 index 000000000..d82e7235d --- /dev/null +++ b/src/rust/vendor/der/CHANGELOG.md @@ -0,0 +1,465 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.7.9 (2024-04-01) +### Changed +- ignore RUSTSEC-2023-0071 (backport [#1276]) +- make sure der is comptatible with potential language breaking changed (backport [#1374]) + +[#1276]: https://github.com/RustCrypto/formats/pull/1276 +[#1374]: https://github.com/RustCrypto/formats/pull/1374 + +## 0.7.8 (2023-08-07) +### Added +- `bytes` feature ([#1156]) +- impl `RefToOwned`/`OwnedToRef` for `&[u8]`/`Box<[u8]>` ([#1188]) +- `BmpString` ([#1164]) + +### Changed +- no-panic cleanup ([#1169]) +- Bump `der_derive` dependency to v0.7.2 ([#1192]) + +[#1156]: https://github.com/RustCrypto/formats/pull/1156 +[#1164]: https://github.com/RustCrypto/formats/pull/1164 +[#1169]: https://github.com/RustCrypto/formats/pull/1169 +[#1188]: https://github.com/RustCrypto/formats/pull/1188 +[#1192]: https://github.com/RustCrypto/formats/pull/1192 + +## 0.7.7 (2023-06-29) +### Added +- `TryFrom` impl for strings based on `StrOwned` ([#1064]) + +[#1064]: https://github.com/RustCrypto/formats/pull/1064 + +## 0.7.6 (2023-05-16) +### Added +- `SetOfVec::{extend, from_iter}` methods ([#1065]) +- `SetOf(Vec)::{insert, insert_ordered}` methods ([#1067]) + +### Changed +- Deprecate `SetOf(Vec)::add` ([#1067]) + +### Fixed +- Off-by-one error in `BMPString` tag ([#1037]) +- Handling of non-unique items in `SetOf`(Vec) ([#1066]) + +[#1037]: https://github.com/RustCrypto/formats/pull/1037 +[#1065]: https://github.com/RustCrypto/formats/pull/1065 +[#1066]: https://github.com/RustCrypto/formats/pull/1066 +[#1067]: https://github.com/RustCrypto/formats/pull/1067 + +## 0.7.5 (2023-04-24) +### Added +- adds support for `DateTime::INFINITY` ([#1026]) + +[#1026]: https://github.com/RustCrypto/formats/pull/1026 + +## 0.7.4 (2023-04-19) +### Added +- `Decode` and `Encode` impls for `PhantomData` ([#1009]) +- `ValueOrd` and `DerOrd` impls for `PhantomData` ([#1012]) + +### Changed +- Bump `hex-literal` dependency to v0.4.1 ([#999]) +- Bump `der_derive` dependency to v0.7.1 ([#1016]) + +[#1009]: https://github.com/RustCrypto/formats/pull/1009 +[#1012]: https://github.com/RustCrypto/formats/pull/1012 +[#1016]: https://github.com/RustCrypto/formats/pull/1016 + +## 0.7.3 (2023-04-06) +### Added +- `UtcTime::MAX_YEAR` associated constant ([#989]) + +[#989]: https://github.com/RustCrypto/formats/pull/989 + +## 0.7.2 (2023-04-04) +### Added +- Expose `NestedReader ([#925]) +- `From` impl for `Any` ([#965]) +- `Any::null` helper ([#969]) +- `Any::encode_from` ([#976]) + +[#925]: https://github.com/RustCrypto/formats/pull/925 +[#965]: https://github.com/RustCrypto/formats/pull/965 +[#969]: https://github.com/RustCrypto/formats/pull/969 +[#976]: https://github.com/RustCrypto/formats/pull/976 + +## 0.7.1 (2023-03-07) +### Changed +- Make `zeroize`'s `alloc` feature conditional ([#920]) + +[#920]: https://github.com/RustCrypto/formats/pull/920 + +## 0.7.0 (2023-02-26) [YANKED] +### Added +- `OwnedtoRef`/`RefToOwned` traits; MSRV 1.65 ([#797]) +- `OctetStringRef::decode_into` ([#817]) +- `Int` and `IntRef` types ([#823]) +- `IndefiniteLength` type ([#830]) +- `Any::value` accessor ([#833]) +- Buffered PEM reader ([#839]) +- `OctetString::into_bytes` ([#845]) +- Blanket impls on `Box` for `DecodeValue`, `EncodeValue`, and `Sequence` ([#860]) + +### Changed +- Rename `UIntRef` => `UintRef` ([#786]) +- Replace use of `dyn Writer` with `impl Writer` ([#828]) +- Rename `AnyRef::decode_into` -> `::decode_as` ([#829]) +- Bump `pem-rfc7468` dependency to v0.7 ([#894]) +- Rename `Encode::to_vec` => `::to_der` ([#898]) + +### Removed +- `Sequence::fields` method ([#828]) +- Inherent `AnyRef` decoding methods ([#829]) + +[#786]: https://github.com/RustCrypto/formats/pull/786 +[#797]: https://github.com/RustCrypto/formats/pull/797 +[#817]: https://github.com/RustCrypto/formats/pull/817 +[#823]: https://github.com/RustCrypto/formats/pull/823 +[#828]: https://github.com/RustCrypto/formats/pull/828 +[#829]: https://github.com/RustCrypto/formats/pull/829 +[#830]: https://github.com/RustCrypto/formats/pull/830 +[#833]: https://github.com/RustCrypto/formats/pull/833 +[#839]: https://github.com/RustCrypto/formats/pull/839 +[#845]: https://github.com/RustCrypto/formats/pull/845 +[#860]: https://github.com/RustCrypto/formats/pull/860 +[#894]: https://github.com/RustCrypto/formats/pull/894 +[#898]: https://github.com/RustCrypto/formats/pull/898 + +## 0.6.1 (2022-12-05) +### Added +- Rudimentary implementation of `TeletexString` and `VideotexString` ([#691]) +- Impl `ValueOrd` for `FlagSet` and `UIntRef` ([#723]) + +### Changed +- Eliminate some boilerplate code by using `Deref` ([#697]) + +[#691]: https://github.com/RustCrypto/formats/pull/691 +[#697]: https://github.com/RustCrypto/formats/pull/697 +[#723]: https://github.com/RustCrypto/formats/pull/723 + +## 0.6.0 (2022-05-08) +### Added +- Impl `ValueOrd` for `SetOf` and `SetOfVec` ([#362]) +- `SequenceRef` type ([#374]) +- Support for `SetOf` sorting on heapless `no_std` targets ([#401]) +- Support for mapping `BitString` to/from a `FlagSet` ([#412]) +- `DecodeOwned` marker trait ([#529]) +- Support for the ASN.1 `REAL` type ([#346]) +- `DecodePem` and `EncodePem` traits ([#571]) +- `Document` and `SecretDocument` types ([#571]) +- `EncodeRef`/`EncodeValueRef` wrapper types ([#604]) +- `Writer` trait ([#605]) +- `Reader` trait ([#606]) +- Streaming on-the-fly `PemReader` and `PemWriter` ([#618], [#636]) +- Owned `BitString` ([#636]) +- Owned `Any` and `OctetString` types ([#640]) + +### Changed +- Pass `Header` to `DecodeValue` ([#392]) +- Bump `const-oid` dependency to v0.9 ([#507]) +- Renamed `Decodable`/`Encodable` => `Decode`/`Encode` ([#523]) +- Enable arithmetic, casting, and panic `clippy` lints ([#556], [#579]) +- Use `&mut dyn Writer` as output for `Encode::encode` and `EncodeValue::encode_value` ([#611]) +- Bump `pem-rfc7468` dependency to v0.6 ([#620]) +- Use `Reader<'a>` as input for `Decode::decode` and `DecodeValue::decode_value` ([#633]) +- Renamed `Any` => `AnyRef` ([#637]) +- Renamed `BitString` => `BitStringRef` ([#637]) +- Renamed `Ia5String` => `Ia5StringRef` ([#637]) +- Renamed `OctetString` => `OctetStringRef` ([#637]) +- Renamed `PrintableString` => `PrintableStringRef` ([#637]) +- Renamed `Utf8String` => `Utf8StringRef` ([#637]) +- Renamed `UIntBytes` => `UIntRef` ([#637]) +- Renamed `Decoder` => `SliceReader` ([#651]) +- Renamed `Encoder` => `SliceWriter` ([#651]) + +### Fixed +- Handling of oversized unsigned `INTEGER` inputs ([#447]) + +### Removed +- `bigint` feature ([#344]) +- `OrdIsValueOrd` trait ([#359]) +- `Document` trait ([#571]) +- `OptionalRef` ([#604]) +- Decode-time SET OF ordering checks ([#625]) + +[#344]: https://github.com/RustCrypto/formats/pull/344 +[#346]: https://github.com/RustCrypto/formats/pull/346 +[#359]: https://github.com/RustCrypto/formats/pull/359 +[#362]: https://github.com/RustCrypto/formats/pull/362 +[#374]: https://github.com/RustCrypto/formats/pull/374 +[#392]: https://github.com/RustCrypto/formats/pull/392 +[#401]: https://github.com/RustCrypto/formats/pull/401 +[#412]: https://github.com/RustCrypto/formats/pull/412 +[#447]: https://github.com/RustCrypto/formats/pull/447 +[#507]: https://github.com/RustCrypto/formats/pull/507 +[#523]: https://github.com/RustCrypto/formats/pull/523 +[#529]: https://github.com/RustCrypto/formats/pull/529 +[#556]: https://github.com/RustCrypto/formats/pull/556 +[#571]: https://github.com/RustCrypto/formats/pull/571 +[#579]: https://github.com/RustCrypto/formats/pull/579 +[#604]: https://github.com/RustCrypto/formats/pull/604 +[#605]: https://github.com/RustCrypto/formats/pull/605 +[#606]: https://github.com/RustCrypto/formats/pull/606 +[#611]: https://github.com/RustCrypto/formats/pull/611 +[#618]: https://github.com/RustCrypto/formats/pull/618 +[#620]: https://github.com/RustCrypto/formats/pull/620 +[#625]: https://github.com/RustCrypto/formats/pull/625 +[#633]: https://github.com/RustCrypto/formats/pull/633 +[#636]: https://github.com/RustCrypto/formats/pull/636 +[#637]: https://github.com/RustCrypto/formats/pull/637 +[#640]: https://github.com/RustCrypto/formats/pull/640 +[#651]: https://github.com/RustCrypto/formats/pull/651 + +## 0.5.1 (2021-11-17) +### Added +- `Any::NULL` constant ([#226]) + +[#226]: https://github.com/RustCrypto/formats/pull/226 + +## 0.5.0 (2021-11-15) [YANKED] +### Added +- Support for `IMPLICIT` mode `CONTEXT-SPECIFIC` fields ([#61]) +- `DecodeValue`/`EncodeValue` traits ([#63]) +- Expose `DateTime` through public API ([#75]) +- `SEQUENCE OF` support for `[T; N]` ([#90]) +- `SequenceOf` type ([#95]) +- `SEQUENCE OF` support for `Vec` ([#96]) +- `Document` trait ([#117]) +- Basic integration with `time` crate ([#129]) +- `Tag::NumericString` ([#132]) +- Support for unused bits to `BitString` ([#141]) +- `Decoder::{peek_tag, peek_header}` ([#142]) +- Type hint in `encoder `sequence` method ([#147]) +- `Tag::Enumerated` ([#153]) +- `ErrorKind::TagNumberInvalid` ([#156]) +- `Tag::VisibleString` and `Tag::BmpString` ([#160]) +- Inherent constants for all valid `TagNumber`s ([#165]) +- `DerOrd` and `ValueOrd` traits ([#190]) +- `ContextSpecificRef` type ([#199]) + +### Changed +- Make `ContextSpecific` generic around an inner type ([#60]) +- Removed `SetOf` trait; rename `SetOfArray` => `SetOf` ([#97]) +- Rename `Message` trait to `Sequence` ([#99]) +- Make `GeneralizedTime`/`UtcTime` into `DateTime` newtypes ([#102]) +- Rust 2021 edition upgrade; MSRV 1.56 ([#136]) +- Replace `ErrorKind::Truncated` with `ErrorKind::Incomplete` ([#143]) +- Rename `ErrorKind::UnknownTagMode` => `ErrorKind::TagModeUnknown` ([#155]) +- Rename `ErrorKind::UnexpectedTag` => `ErrorKind::TagUnexpected` ([#155]) +- Rename `ErrorKind::UnknownTag` => `ErrorKind::TagUnknown` ([#155]) +- Consolidate `ErrorKind::{Incomplete, Underlength}` ([#157]) +- Rename `Tagged` => `FixedTag`; add new `Tagged` trait ([#189]) +- Use `DerOrd` for `SetOf*` types ([#200]) +- Switch `impl From for &[u8]` to `TryFrom` ([#203]) +- Bump `crypto-bigint` dependency to v0.3 ([#215]) +- Bump `const-oid` dependency to v0.7 ([#216]) +- Bump `pem-rfc7468` dependency to v0.3 ([#217]) +- Bump `der_derive` dependency to v0.5 ([#221]) + +### Removed +- `Sequence` struct ([#98]) +- `Tagged` bound on `ContextSpecific::decode_implicit` ([#161]) +- `ErrorKind::DuplicateField` ([#162]) + +[#60]: https://github.com/RustCrypto/formats/pull/60 +[#61]: https://github.com/RustCrypto/formats/pull/61 +[#63]: https://github.com/RustCrypto/formats/pull/63 +[#75]: https://github.com/RustCrypto/formats/pull/75 +[#90]: https://github.com/RustCrypto/formats/pull/90 +[#95]: https://github.com/RustCrypto/formats/pull/95 +[#96]: https://github.com/RustCrypto/formats/pull/96 +[#97]: https://github.com/RustCrypto/formats/pull/97 +[#98]: https://github.com/RustCrypto/formats/pull/98 +[#99]: https://github.com/RustCrypto/formats/pull/99 +[#102]: https://github.com/RustCrypto/formats/pull/102 +[#117]: https://github.com/RustCrypto/formats/pull/117 +[#129]: https://github.com/RustCrypto/formats/pull/129 +[#132]: https://github.com/RustCrypto/formats/pull/132 +[#136]: https://github.com/RustCrypto/formats/pull/136 +[#141]: https://github.com/RustCrypto/formats/pull/141 +[#142]: https://github.com/RustCrypto/formats/pull/142 +[#143]: https://github.com/RustCrypto/formats/pull/143 +[#147]: https://github.com/RustCrypto/formats/pull/147 +[#153]: https://github.com/RustCrypto/formats/pull/153 +[#155]: https://github.com/RustCrypto/formats/pull/155 +[#156]: https://github.com/RustCrypto/formats/pull/156 +[#157]: https://github.com/RustCrypto/formats/pull/157 +[#160]: https://github.com/RustCrypto/formats/pull/160 +[#161]: https://github.com/RustCrypto/formats/pull/161 +[#162]: https://github.com/RustCrypto/formats/pull/162 +[#165]: https://github.com/RustCrypto/formats/pull/165 +[#189]: https://github.com/RustCrypto/formats/pull/189 +[#190]: https://github.com/RustCrypto/formats/pull/190 +[#199]: https://github.com/RustCrypto/formats/pull/199 +[#200]: https://github.com/RustCrypto/formats/pull/200 +[#203]: https://github.com/RustCrypto/formats/pull/203 +[#215]: https://github.com/RustCrypto/formats/pull/215 +[#216]: https://github.com/RustCrypto/formats/pull/216 +[#217]: https://github.com/RustCrypto/formats/pull/217 +[#221]: https://github.com/RustCrypto/formats/pull/221 + +## 0.4.5 (2021-12-01) +### Fixed +- Backport [#147] type hint fix for WASM platforms to 0.4.x + +## 0.4.4 (2021-10-06) +### Removed +- Accidentally checked-in `target/` directory ([#66]) + +[#66]: https://github.com/RustCrypto/formats/pull/66 + +## 0.4.3 (2021-09-15) +### Added +- `Tag::unexpected_error` ([#33]) + +[#33]: https://github.com/RustCrypto/formats/pull/33 + +## 0.4.2 (2021-09-14) +### Changed +- Moved to `formats` repo ([#2]) + +### Fixed +- ASN.1 `SET` type now flagged with the constructed bit + +[#2]: https://github.com/RustCrypto/formats/pull/2 + +## 0.4.1 (2021-08-08) +### Fixed +- Encoding `UTCTime` for dates with `20xx` years + +## 0.4.0 (2021-06-07) +### Added +- `TagNumber` type +- Const generic integer de/encoders with support for all of Rust's integer + primitives +- `crypto-bigint` support +- `Tag` number helpers +- `Tag::octet` +- `ErrorKind::Value` helpers +- `SequenceIter` + +### Changed +- Bump `const-oid` crate dependency to v0.6 +- Make `Tag` structured +- Namespace ASN.1 types in `asn1` module +- Refactor context-specific field decoding +- MSRV 1.51 +- Rename `big-uint` crate feature to `bigint` +- Rename `BigUInt` to `UIntBytes` +- Have `Decoder::error()` return an `Error` + +### Removed +- Deprecated methods replaced by associated constants + +## 0.3.5 (2021-05-24) +### Added +- Helper methods for context-specific fields +- `ContextSpecific` field wrapper +- Decoder position tracking for errors during `Any<'a>` decoding + +### Fixed +- `From` conversion for `BitString` into `Any` + +## 0.3.4 (2021-05-16) +### Changed +- Support `Length` of up to 1 MiB + +## 0.3.3 (2021-04-15) +### Added +- `Length` constants + +### Changed +- Deprecate `const fn` methods replaced by `Length` constants + +## 0.3.2 (2021-04-15) +### Fixed +- Non-critical bug allowing `Length` to exceed the max invariant + +## 0.3.1 (2021-04-01) [YANKED] +### Added +- `PartialOrd` + `Ord` impls to all ASN.1 types + +## 0.3.0 (2021-03-22) [YANKED] +### Added +- Impl `Decode`/`Encoded`/`Tagged` for `String` +- `Length::one` and `Length::for_tlv` +- `SET OF` support with `SetOf` trait and `SetOfRef` + +### Changed +- Rename `Decodable::from_bytes` => `Decodable::from_der` +- Separate `sequence` and `message` +- Rename `ErrorKind::Oid` => `ErrorKind::MalformedOid` +- Auto-derive `From` impls for variants when deriving `Choice` +- Make `Length` use `u32` internally +- Make `Sequence` constructor private +- Bump `const_oid` to v0.5 +- Bump `der_derive` to v0.3 + +### Removed +- Deprecated methods +- `BigUIntSize` + +## 0.2.10 (2021-02-28) +### Added +- Impl `From` for `Any` + +### Changed +- Bump minimum `const-oid` dependency to v0.4.4 + +## 0.2.9 (2021-02-24) +### Added +- Support for `IA5String` + +## 0.2.8 (2021-02-22) +### Added +- `Choice` trait + +## 0.2.7 (2021-02-20) +### Added +- Export `Header` publicly +- Make `Encoder::reserve` public + +## 0.2.6 (2021-02-19) +### Added +- Make the unit type an encoding of `NULL` + +## 0.2.5 (2021-02-18) +### Added +- `ErrorKind::UnknownOid` variant + +## 0.2.4 (2021-02-16) +### Added +- `Any::is_null` method + +### Changed +- Deprecate `Any::null` method + +## 0.2.3 (2021-02-15) +### Added +- Additional `rustdoc` documentation + +## 0.2.2 (2021-02-12) +### Added +- Support for `UTCTime` and `GeneralizedTime` + +## 0.2.1 (2021-02-02) +### Added +- Support for `PrintableString` and `Utf8String` + +## 0.2.0 (2021-01-22) +### Added +- `BigUInt` type +- `i16` support +- `u8` and `u16` support +- Integer decoder helper methods + +### Fixed +- Handle leading byte of `BIT STRING`s + +## 0.1.0 (2020-12-21) +- Initial release diff --git a/src/rust/vendor/der/Cargo.toml b/src/rust/vendor/der/Cargo.toml new file mode 100644 index 000000000..027b88a6e --- /dev/null +++ b/src/rust/vendor/der/Cargo.toml @@ -0,0 +1,109 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.65" +name = "der" +version = "0.7.9" +authors = ["RustCrypto Developers"] +description = """ +Pure Rust embedded-friendly implementation of the Distinguished Encoding Rules +(DER) for Abstract Syntax Notation One (ASN.1) as described in ITU X.690 with +full support for heapless no_std targets +""" +readme = "README.md" +keywords = [ + "asn1", + "crypto", + "itu", + "pkcs", +] +categories = [ + "cryptography", + "data-structures", + "encoding", + "no-std", + "parser-implementations", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/RustCrypto/formats/tree/master/der" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.arbitrary] +version = "1.3" +features = ["derive"] +optional = true + +[dependencies.bytes] +version = "1" +optional = true +default-features = false + +[dependencies.const-oid] +version = "0.9.2" +optional = true + +[dependencies.der_derive] +version = "0.7.2" +optional = true + +[dependencies.flagset] +version = "0.4.3" +optional = true + +[dependencies.pem-rfc7468] +version = "0.7" +features = ["alloc"] +optional = true + +[dependencies.time] +version = "0.3.4" +optional = true +default-features = false + +[dependencies.zeroize] +version = "1.5" +optional = true +default-features = false + +[dev-dependencies.hex-literal] +version = "0.4.1" + +[dev-dependencies.proptest] +version = "1" + +[features] +alloc = ["zeroize?/alloc"] +arbitrary = [ + "dep:arbitrary", + "const-oid?/arbitrary", + "std", +] +bytes = [ + "dep:bytes", + "alloc", +] +derive = ["dep:der_derive"] +oid = ["dep:const-oid"] +pem = [ + "dep:pem-rfc7468", + "alloc", + "zeroize", +] +real = [] +std = ["alloc"] diff --git a/src/rust/vendor/der/LICENSE-APACHE b/src/rust/vendor/der/LICENSE-APACHE new file mode 100644 index 000000000..78173fa2e --- /dev/null +++ b/src/rust/vendor/der/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/der/LICENSE-MIT b/src/rust/vendor/der/LICENSE-MIT new file mode 100644 index 000000000..e0d082780 --- /dev/null +++ b/src/rust/vendor/der/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2020-2023 The RustCrypto Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/der/README.md b/src/rust/vendor/der/README.md new file mode 100644 index 000000000..f13053ffe --- /dev/null +++ b/src/rust/vendor/der/README.md @@ -0,0 +1,96 @@ +# [RustCrypto]: ASN.1 DER + +[![Crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +[![Build Status][build-image]][build-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Project Chat][chat-image]][chat-link] + +Pure Rust embedded-friendly implementation of the Distinguished Encoding Rules (DER) +for Abstract Syntax Notation One (ASN.1) as described in ITU X.690. + +[Documentation][docs-link] + +## About + +This crate provides a `no_std`-friendly implementation of a subset of ASN.1 DER +necessary for decoding/encoding the following cryptography-related formats +implemented as crates maintained by the [RustCrypto] project: + +- [`pkcs1`]: RSA Cryptography Specifications +- [`pkcs5`]: Password-Based Cryptography Specification +- [`pkcs7`]: Cryptographic Message Syntax +- [`pkcs8`]: Private-Key Information Syntax Specification +- [`pkcs10`]: Certification Request Syntax Specification +- [`sec1`]: Elliptic Curve Cryptography +- [`spki`]: X.509 Subject Public Key Info +- [`x501`]: Directory Services Types +- [`x509`]: Public Key Infrastructure Certificate + +The core implementation avoids any heap usage (with convenience methods +that allocate gated under the off-by-default `alloc` feature). + +The DER decoder in this crate performs checks to ensure that the input document +is in canonical form, and will return errors if non-canonical productions are +encountered. There is currently no way to disable these checks. + +### Features + +- Rich support for ASN.1 types used by PKCS/PKIX documents +- Performs DER canonicalization checks at decoding time +- `no_std` friendly: supports "heapless" usage +- Optionally supports `alloc` and `std` if desired +- No hard dependencies! Self-contained implementation with optional + integrations with the following crates, all of which are `no_std` friendly: + - `const-oid`: const-friendly OID implementation + - `pem-rfc7468`: PKCS/PKIX-flavored PEM library with constant-time decoder/encoders + - `time` crate: date/time library + +## Minimum Supported Rust Version + +This crate requires **Rust 1.65** at a minimum. + +We may change the MSRV in the future, but it will be accompanied by a minor +version bump. + +## License + +Licensed under either of: + + * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + * [MIT license](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. + +[//]: # (badges) + +[crate-image]: https://buildstats.info/crate/der +[crate-link]: https://crates.io/crates/der +[docs-image]: https://docs.rs/der/badge.svg +[docs-link]: https://docs.rs/der/ +[build-image]: https://github.com/RustCrypto/formats/actions/workflows/der.yml/badge.svg +[build-link]: https://github.com/RustCrypto/formats/actions/workflows/der.yml +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/300570-formats + +[//]: # (links) + +[RustCrypto]: https://github.com/rustcrypto +[`pkcs1`]: https://github.com/RustCrypto/formats/tree/master/pkcs1 +[`pkcs5`]: https://github.com/RustCrypto/formats/tree/master/pkcs5 +[`pkcs7`]: https://github.com/RustCrypto/formats/tree/master/pkcs7 +[`pkcs8`]: https://github.com/RustCrypto/formats/tree/master/pkcs8 +[`pkcs10`]: https://github.com/RustCrypto/formats/tree/master/pkcs10 +[`sec1`]: https://github.com/RustCrypto/formats/tree/master/sec1 +[`spki`]: https://github.com/RustCrypto/formats/tree/master/spki +[`x501`]: https://github.com/RustCrypto/formats/tree/master/x501 +[`x509`]: https://github.com/RustCrypto/formats/tree/master/x509 diff --git a/src/rust/vendor/der/src/arrayvec.rs b/src/rust/vendor/der/src/arrayvec.rs new file mode 100644 index 000000000..6ce608d97 --- /dev/null +++ b/src/rust/vendor/der/src/arrayvec.rs @@ -0,0 +1,145 @@ +//! Array-backed append-only vector type. +// TODO(tarcieri): use `core` impl of `ArrayVec` +// See: https://github.com/rust-lang/rfcs/pull/2990 + +use crate::{ErrorKind, Result}; + +/// Array-backed append-only vector type. +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub(crate) struct ArrayVec { + /// Elements of the set. + elements: [Option; N], + + /// Last populated element. + length: usize, +} + +impl ArrayVec { + /// Create a new [`ArrayVec`]. + pub fn new() -> Self { + Self { + elements: [(); N].map(|_| None), + length: 0, + } + } + + /// Push an item into this [`ArrayVec`]. + pub fn push(&mut self, item: T) -> Result<()> { + match self.length.checked_add(1) { + Some(n) if n <= N => { + self.elements[self.length] = Some(item); + self.length = n; + Ok(()) + } + _ => Err(ErrorKind::Overlength.into()), + } + } + + /// Get an element from this [`ArrayVec`]. + pub fn get(&self, index: usize) -> Option<&T> { + match self.elements.get(index) { + Some(Some(ref item)) => Some(item), + _ => None, + } + } + + /// Iterate over the elements in this [`ArrayVec`]. + pub fn iter(&self) -> Iter<'_, T> { + Iter::new(&self.elements) + } + + /// Is this [`ArrayVec`] empty? + pub fn is_empty(&self) -> bool { + self.length == 0 + } + + /// Get the number of elements in this [`ArrayVec`]. + pub fn len(&self) -> usize { + self.length + } + + /// Get the last item from this [`ArrayVec`]. + pub fn last(&self) -> Option<&T> { + self.length.checked_sub(1).and_then(|n| self.get(n)) + } + + /// Extract the inner array. + pub fn into_array(self) -> [Option; N] { + self.elements + } +} + +impl AsRef<[Option]> for ArrayVec { + fn as_ref(&self) -> &[Option] { + &self.elements[..self.length] + } +} + +impl AsMut<[Option]> for ArrayVec { + fn as_mut(&mut self) -> &mut [Option] { + &mut self.elements[..self.length] + } +} + +impl Default for ArrayVec { + fn default() -> Self { + Self::new() + } +} + +/// Iterator over the elements of an [`ArrayVec`]. +#[derive(Clone, Debug)] +pub struct Iter<'a, T> { + /// Decoder which iterates over the elements of the message. + elements: &'a [Option], + + /// Position within the iterator. + position: usize, +} + +impl<'a, T> Iter<'a, T> { + pub(crate) fn new(elements: &'a [Option]) -> Self { + Self { + elements, + position: 0, + } + } +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { + match self.elements.get(self.position) { + Some(Some(res)) => { + self.position = self.position.checked_add(1)?; + Some(res) + } + _ => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.elements.len().saturating_sub(self.position); + (len, Some(len)) + } +} + +impl<'a, T> ExactSizeIterator for Iter<'a, T> {} + +#[cfg(test)] +mod tests { + use super::ArrayVec; + use crate::ErrorKind; + + #[test] + fn add() { + let mut vec = ArrayVec::::new(); + vec.push(1).unwrap(); + vec.push(2).unwrap(); + vec.push(3).unwrap(); + + assert_eq!(vec.push(4).err().unwrap(), ErrorKind::Overlength.into()); + assert_eq!(vec.len(), 3); + } +} diff --git a/src/rust/vendor/der/src/asn1.rs b/src/rust/vendor/der/src/asn1.rs new file mode 100644 index 000000000..b04b1b58f --- /dev/null +++ b/src/rust/vendor/der/src/asn1.rs @@ -0,0 +1,67 @@ +//! Module containing all of the various ASN.1 built-in types supported by +//! this library. + +#[macro_use] +mod internal_macros; + +mod any; +mod bit_string; +#[cfg(feature = "alloc")] +mod bmp_string; +mod boolean; +mod choice; +mod context_specific; +mod generalized_time; +mod ia5_string; +mod integer; +mod null; +mod octet_string; +#[cfg(feature = "oid")] +mod oid; +mod optional; +mod printable_string; +#[cfg(feature = "real")] +mod real; +mod sequence; +mod sequence_of; +mod set_of; +mod teletex_string; +mod utc_time; +mod utf8_string; +mod videotex_string; + +pub use self::{ + any::AnyRef, + bit_string::{BitStringIter, BitStringRef}, + choice::Choice, + context_specific::{ContextSpecific, ContextSpecificRef}, + generalized_time::GeneralizedTime, + ia5_string::Ia5StringRef, + integer::{int::IntRef, uint::UintRef}, + null::Null, + octet_string::OctetStringRef, + printable_string::PrintableStringRef, + sequence::{Sequence, SequenceRef}, + sequence_of::{SequenceOf, SequenceOfIter}, + set_of::{SetOf, SetOfIter}, + teletex_string::TeletexStringRef, + utc_time::UtcTime, + utf8_string::Utf8StringRef, + videotex_string::VideotexStringRef, +}; + +#[cfg(feature = "alloc")] +pub use self::{ + any::Any, + bit_string::BitString, + bmp_string::BmpString, + ia5_string::Ia5String, + integer::{int::Int, uint::Uint}, + octet_string::OctetString, + printable_string::PrintableString, + set_of::SetOfVec, + teletex_string::TeletexString, +}; + +#[cfg(feature = "oid")] +pub use const_oid::ObjectIdentifier; diff --git a/src/rust/vendor/der/src/asn1/any.rs b/src/rust/vendor/der/src/asn1/any.rs new file mode 100644 index 000000000..017a90908 --- /dev/null +++ b/src/rust/vendor/der/src/asn1/any.rs @@ -0,0 +1,315 @@ +//! ASN.1 `ANY` type. + +#![cfg_attr(feature = "arbitrary", allow(clippy::integer_arithmetic))] + +use crate::{ + BytesRef, Choice, Decode, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind, Header, Length, + Reader, Result, SliceReader, Tag, Tagged, ValueOrd, Writer, +}; +use core::cmp::Ordering; + +#[cfg(feature = "alloc")] +use crate::SliceWriter; + +/// ASN.1 `ANY`: represents any explicitly tagged ASN.1 value. +/// +/// This is a zero-copy reference type which borrows from the input data. +/// +/// Technically `ANY` hasn't been a recommended part of ASN.1 since the X.209 +/// revision from 1988. It was deprecated and replaced by Information Object +/// Classes in X.680 in 1994, and X.690 no longer refers to it whatsoever. +/// +/// Nevertheless, this crate defines an `ANY` type as it remains a familiar +/// and useful concept which is still extensively used in things like +/// PKI-related RFCs. +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct AnyRef<'a> { + /// Tag representing the type of the encoded value. + tag: Tag, + + /// Inner value encoded as bytes. + value: BytesRef<'a>, +} + +impl<'a> AnyRef<'a> { + /// [`AnyRef`] representation of the ASN.1 `NULL` type. + pub const NULL: Self = Self { + tag: Tag::Null, + value: BytesRef::EMPTY, + }; + + /// Create a new [`AnyRef`] from the provided [`Tag`] and DER bytes. + pub fn new(tag: Tag, bytes: &'a [u8]) -> Result { + let value = BytesRef::new(bytes).map_err(|_| ErrorKind::Length { tag })?; + Ok(Self { tag, value }) + } + + /// Infallible creation of an [`AnyRef`] from a [`BytesRef`]. + pub(crate) fn from_tag_and_value(tag: Tag, value: BytesRef<'a>) -> Self { + Self { tag, value } + } + + /// Get the raw value for this [`AnyRef`] type as a byte slice. + pub fn value(self) -> &'a [u8] { + self.value.as_slice() + } + + /// Attempt to decode this [`AnyRef`] type into the inner value. + pub fn decode_as(self) -> Result + where + T: Choice<'a> + DecodeValue<'a>, + { + if !T::can_decode(self.tag) { + return Err(self.tag.unexpected_error(None)); + } + + let header = Header { + tag: self.tag, + length: self.value.len(), + }; + + let mut decoder = SliceReader::new(self.value())?; + let result = T::decode_value(&mut decoder, header)?; + decoder.finish(result) + } + + /// Is this value an ASN.1 `NULL` value? + pub fn is_null(self) -> bool { + self == Self::NULL + } + + /// Attempt to decode this value an ASN.1 `SEQUENCE`, creating a new + /// nested reader and calling the provided argument with it. + pub fn sequence(self, f: F) -> Result + where + F: FnOnce(&mut SliceReader<'a>) -> Result, + { + self.tag.assert_eq(Tag::Sequence)?; + let mut reader = SliceReader::new(self.value.as_slice())?; + let result = f(&mut reader)?; + reader.finish(result) + } +} + +impl<'a> Choice<'a> for AnyRef<'a> { + fn can_decode(_: Tag) -> bool { + true + } +} + +impl<'a> Decode<'a> for AnyRef<'a> { + fn decode>(reader: &mut R) -> Result> { + let header = Header::decode(reader)?; + Self::decode_value(reader, header) + } +} + +impl<'a> DecodeValue<'a> for AnyRef<'a> { + fn decode_value>(reader: &mut R, header: Header) -> Result { + Ok(Self { + tag: header.tag, + value: BytesRef::decode_value(reader, header)?, + }) + } +} + +impl EncodeValue for AnyRef<'_> { + fn value_len(&self) -> Result { + Ok(self.value.len()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.value()) + } +} + +impl Tagged for AnyRef<'_> { + fn tag(&self) -> Tag { + self.tag + } +} + +impl ValueOrd for AnyRef<'_> { + fn value_cmp(&self, other: &Self) -> Result { + self.value.der_cmp(&other.value) + } +} + +impl<'a> From> for BytesRef<'a> { + fn from(any: AnyRef<'a>) -> BytesRef<'a> { + any.value + } +} + +impl<'a> TryFrom<&'a [u8]> for AnyRef<'a> { + type Error = Error; + + fn try_from(bytes: &'a [u8]) -> Result> { + AnyRef::from_der(bytes) + } +} + +#[cfg(feature = "alloc")] +pub use self::allocating::Any; + +#[cfg(feature = "alloc")] +mod allocating { + use super::*; + use crate::{referenced::*, BytesOwned}; + use alloc::boxed::Box; + + /// ASN.1 `ANY`: represents any explicitly tagged ASN.1 value. + /// + /// This type provides the same functionality as [`AnyRef`] but owns the + /// backing data. + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] + #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] + pub struct Any { + /// Tag representing the type of the encoded value. + tag: Tag, + + /// Inner value encoded as bytes. + value: BytesOwned, + } + + impl Any { + /// Create a new [`Any`] from the provided [`Tag`] and DER bytes. + pub fn new(tag: Tag, bytes: impl Into>) -> Result { + let value = BytesOwned::new(bytes)?; + + // Ensure the tag and value are a valid `AnyRef`. + AnyRef::new(tag, value.as_slice())?; + Ok(Self { tag, value }) + } + + /// Allow access to value + pub fn value(&self) -> &[u8] { + self.value.as_slice() + } + + /// Attempt to decode this [`Any`] type into the inner value. + pub fn decode_as<'a, T>(&'a self) -> Result + where + T: Choice<'a> + DecodeValue<'a>, + { + AnyRef::from(self).decode_as() + } + + /// Encode the provided type as an [`Any`] value. + pub fn encode_from(msg: &T) -> Result + where + T: Tagged + EncodeValue, + { + let encoded_len = usize::try_from(msg.value_len()?)?; + let mut buf = vec![0u8; encoded_len]; + let mut writer = SliceWriter::new(&mut buf); + msg.encode_value(&mut writer)?; + writer.finish()?; + Any::new(msg.tag(), buf) + } + + /// Attempt to decode this value an ASN.1 `SEQUENCE`, creating a new + /// nested reader and calling the provided argument with it. + pub fn sequence<'a, F, T>(&'a self, f: F) -> Result + where + F: FnOnce(&mut SliceReader<'a>) -> Result, + { + AnyRef::from(self).sequence(f) + } + + /// [`Any`] representation of the ASN.1 `NULL` type. + pub fn null() -> Self { + Self { + tag: Tag::Null, + value: BytesOwned::default(), + } + } + } + + impl Choice<'_> for Any { + fn can_decode(_: Tag) -> bool { + true + } + } + + impl<'a> Decode<'a> for Any { + fn decode>(reader: &mut R) -> Result { + let header = Header::decode(reader)?; + Self::decode_value(reader, header) + } + } + + impl<'a> DecodeValue<'a> for Any { + fn decode_value>(reader: &mut R, header: Header) -> Result { + let value = reader.read_vec(header.length)?; + Self::new(header.tag, value) + } + } + + impl EncodeValue for Any { + fn value_len(&self) -> Result { + Ok(self.value.len()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.value.as_slice()) + } + } + + impl<'a> From<&'a Any> for AnyRef<'a> { + fn from(any: &'a Any) -> AnyRef<'a> { + // Ensured to parse successfully in constructor + AnyRef::new(any.tag, any.value.as_slice()).expect("invalid ANY") + } + } + + impl Tagged for Any { + fn tag(&self) -> Tag { + self.tag + } + } + + impl ValueOrd for Any { + fn value_cmp(&self, other: &Self) -> Result { + self.value.der_cmp(&other.value) + } + } + + impl<'a, T> From for Any + where + T: Into>, + { + fn from(input: T) -> Any { + let anyref: AnyRef<'a> = input.into(); + Self { + tag: anyref.tag(), + value: BytesOwned::from(anyref.value), + } + } + } + + impl<'a> RefToOwned<'a> for AnyRef<'a> { + type Owned = Any; + fn ref_to_owned(&self) -> Self::Owned { + Any { + tag: self.tag(), + value: BytesOwned::from(self.value), + } + } + } + + impl OwnedToRef for Any { + type Borrowed<'a> = AnyRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + self.into() + } + } + + impl Any { + /// Is this value an ASN.1 `NULL` value? + pub fn is_null(&self) -> bool { + self.owned_to_ref() == AnyRef::NULL + } + } +} diff --git a/src/rust/vendor/der/src/asn1/bit_string.rs b/src/rust/vendor/der/src/asn1/bit_string.rs new file mode 100644 index 000000000..bf3371c40 --- /dev/null +++ b/src/rust/vendor/der/src/asn1/bit_string.rs @@ -0,0 +1,552 @@ +//! ASN.1 `BIT STRING` support. + +use crate::{ + BytesRef, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, + Result, Tag, ValueOrd, Writer, +}; +use core::{cmp::Ordering, iter::FusedIterator}; + +/// ASN.1 `BIT STRING` type. +/// +/// This type contains a sequence of any number of bits, modeled internally as +/// a sequence of bytes with a known number of "unused bits". +/// +/// This is a zero-copy reference type which borrows from the input data. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct BitStringRef<'a> { + /// Number of unused bits in the final octet. + unused_bits: u8, + + /// Length of this `BIT STRING` in bits. + bit_length: usize, + + /// Bitstring represented as a slice of bytes. + inner: BytesRef<'a>, +} + +impl<'a> BitStringRef<'a> { + /// Maximum number of unused bits allowed. + pub const MAX_UNUSED_BITS: u8 = 7; + + /// Create a new ASN.1 `BIT STRING` from a byte slice. + /// + /// Accepts an optional number of "unused bits" (0-7) which are omitted + /// from the final octet. This number is 0 if the value is octet-aligned. + pub fn new(unused_bits: u8, bytes: &'a [u8]) -> Result { + if (unused_bits > Self::MAX_UNUSED_BITS) || (unused_bits != 0 && bytes.is_empty()) { + return Err(Self::TAG.value_error()); + } + + let inner = BytesRef::new(bytes).map_err(|_| Self::TAG.length_error())?; + + let bit_length = usize::try_from(inner.len())? + .checked_mul(8) + .and_then(|n| n.checked_sub(usize::from(unused_bits))) + .ok_or(ErrorKind::Overflow)?; + + Ok(Self { + unused_bits, + bit_length, + inner, + }) + } + + /// Create a new ASN.1 `BIT STRING` from the given bytes. + /// + /// The "unused bits" are set to 0. + pub fn from_bytes(bytes: &'a [u8]) -> Result { + Self::new(0, bytes) + } + + /// Get the number of unused bits in this byte slice. + pub fn unused_bits(&self) -> u8 { + self.unused_bits + } + + /// Is the number of unused bits a value other than 0? + pub fn has_unused_bits(&self) -> bool { + self.unused_bits != 0 + } + + /// Get the length of this `BIT STRING` in bits. + pub fn bit_len(&self) -> usize { + self.bit_length + } + + /// Get the number of bytes/octets needed to represent this `BIT STRING` + /// when serialized in an octet-aligned manner. + pub fn byte_len(&self) -> Length { + self.inner.len() + } + + /// Is the inner byte slice empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + /// Borrow the inner byte slice. + /// + /// Returns `None` if the number of unused bits is *not* equal to zero, + /// i.e. if the `BIT STRING` is not octet aligned. + /// + /// Use [`BitString::raw_bytes`] to obtain access to the raw value + /// regardless of the presence of unused bits. + pub fn as_bytes(&self) -> Option<&'a [u8]> { + if self.has_unused_bits() { + None + } else { + Some(self.raw_bytes()) + } + } + + /// Borrow the raw bytes of this `BIT STRING`. + /// + /// Note that the byte string may contain extra unused bits in the final + /// octet. If the number of unused bits is expected to be 0, the + /// [`BitStringRef::as_bytes`] function can be used instead. + pub fn raw_bytes(&self) -> &'a [u8] { + self.inner.as_slice() + } + + /// Iterator over the bits of this `BIT STRING`. + pub fn bits(self) -> BitStringIter<'a> { + BitStringIter { + bit_string: self, + position: 0, + } + } +} + +impl_any_conversions!(BitStringRef<'a>, 'a); + +impl<'a> DecodeValue<'a> for BitStringRef<'a> { + fn decode_value>(reader: &mut R, header: Header) -> Result { + let header = Header { + tag: header.tag, + length: (header.length - Length::ONE)?, + }; + + let unused_bits = reader.read_byte()?; + let inner = BytesRef::decode_value(reader, header)?; + Self::new(unused_bits, inner.as_slice()) + } +} + +impl EncodeValue for BitStringRef<'_> { + fn value_len(&self) -> Result { + self.byte_len() + Length::ONE + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write_byte(self.unused_bits)?; + writer.write(self.raw_bytes()) + } +} + +impl ValueOrd for BitStringRef<'_> { + fn value_cmp(&self, other: &Self) -> Result { + match self.unused_bits.cmp(&other.unused_bits) { + Ordering::Equal => self.inner.der_cmp(&other.inner), + ordering => Ok(ordering), + } + } +} + +impl<'a> From<&BitStringRef<'a>> for BitStringRef<'a> { + fn from(value: &BitStringRef<'a>) -> BitStringRef<'a> { + *value + } +} + +impl<'a> TryFrom<&'a [u8]> for BitStringRef<'a> { + type Error = Error; + + fn try_from(bytes: &'a [u8]) -> Result> { + BitStringRef::from_bytes(bytes) + } +} + +/// Hack for simplifying the custom derive use case. +impl<'a> TryFrom<&&'a [u8]> for BitStringRef<'a> { + type Error = Error; + + fn try_from(bytes: &&'a [u8]) -> Result> { + BitStringRef::from_bytes(bytes) + } +} + +impl<'a> TryFrom> for &'a [u8] { + type Error = Error; + + fn try_from(bit_string: BitStringRef<'a>) -> Result<&'a [u8]> { + bit_string + .as_bytes() + .ok_or_else(|| Tag::BitString.value_error()) + } +} + +impl<'a> FixedTag for BitStringRef<'a> { + const TAG: Tag = Tag::BitString; +} + +// Implement by hand because the derive would create invalid values. +// Use the constructor to create a valid value. +#[cfg(feature = "arbitrary")] +impl<'a> arbitrary::Arbitrary<'a> for BitStringRef<'a> { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + Self::new( + u.int_in_range(0..=Self::MAX_UNUSED_BITS)?, + BytesRef::arbitrary(u)?.as_slice(), + ) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } + + fn size_hint(depth: usize) -> (usize, Option) { + arbitrary::size_hint::and(u8::size_hint(depth), BytesRef::size_hint(depth)) + } +} + +#[cfg(feature = "alloc")] +pub use self::allocating::BitString; + +#[cfg(feature = "alloc")] +mod allocating { + use super::*; + use crate::referenced::*; + use alloc::vec::Vec; + + /// Owned form of ASN.1 `BIT STRING` type. + /// + /// This type provides the same functionality as [`BitStringRef`] but owns the + /// backing data. + #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] + pub struct BitString { + /// Number of unused bits in the final octet. + unused_bits: u8, + + /// Length of this `BIT STRING` in bits. + bit_length: usize, + + /// Bitstring represented as a slice of bytes. + inner: Vec, + } + + impl BitString { + /// Maximum number of unused bits allowed. + pub const MAX_UNUSED_BITS: u8 = 7; + + /// Create a new ASN.1 `BIT STRING` from a byte slice. + /// + /// Accepts an optional number of "unused bits" (0-7) which are omitted + /// from the final octet. This number is 0 if the value is octet-aligned. + pub fn new(unused_bits: u8, bytes: impl Into>) -> Result { + let inner = bytes.into(); + + // Ensure parameters parse successfully as a `BitStringRef`. + let bit_length = BitStringRef::new(unused_bits, &inner)?.bit_length; + + Ok(BitString { + unused_bits, + bit_length, + inner, + }) + } + + /// Create a new ASN.1 `BIT STRING` from the given bytes. + /// + /// The "unused bits" are set to 0. + pub fn from_bytes(bytes: &[u8]) -> Result { + Self::new(0, bytes) + } + + /// Get the number of unused bits in the octet serialization of this + /// `BIT STRING`. + pub fn unused_bits(&self) -> u8 { + self.unused_bits + } + + /// Is the number of unused bits a value other than 0? + pub fn has_unused_bits(&self) -> bool { + self.unused_bits != 0 + } + + /// Get the length of this `BIT STRING` in bits. + pub fn bit_len(&self) -> usize { + self.bit_length + } + + /// Is the inner byte slice empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + /// Borrow the inner byte slice. + /// + /// Returns `None` if the number of unused bits is *not* equal to zero, + /// i.e. if the `BIT STRING` is not octet aligned. + /// + /// Use [`BitString::raw_bytes`] to obtain access to the raw value + /// regardless of the presence of unused bits. + pub fn as_bytes(&self) -> Option<&[u8]> { + if self.has_unused_bits() { + None + } else { + Some(self.raw_bytes()) + } + } + + /// Borrow the raw bytes of this `BIT STRING`. + pub fn raw_bytes(&self) -> &[u8] { + self.inner.as_slice() + } + + /// Iterator over the bits of this `BIT STRING`. + pub fn bits(&self) -> BitStringIter<'_> { + BitStringRef::from(self).bits() + } + } + + impl_any_conversions!(BitString); + + impl<'a> DecodeValue<'a> for BitString { + fn decode_value>(reader: &mut R, header: Header) -> Result { + let inner_len = (header.length - Length::ONE)?; + let unused_bits = reader.read_byte()?; + let inner = reader.read_vec(inner_len)?; + Self::new(unused_bits, inner) + } + } + + impl EncodeValue for BitString { + fn value_len(&self) -> Result { + Length::ONE + Length::try_from(self.inner.len())? + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write_byte(self.unused_bits)?; + writer.write(&self.inner) + } + } + + impl FixedTag for BitString { + const TAG: Tag = Tag::BitString; + } + + impl<'a> From<&'a BitString> for BitStringRef<'a> { + fn from(bit_string: &'a BitString) -> BitStringRef<'a> { + // Ensured to parse successfully in constructor + BitStringRef::new(bit_string.unused_bits, &bit_string.inner) + .expect("invalid BIT STRING") + } + } + + impl ValueOrd for BitString { + fn value_cmp(&self, other: &Self) -> Result { + match self.unused_bits.cmp(&other.unused_bits) { + Ordering::Equal => self.inner.der_cmp(&other.inner), + ordering => Ok(ordering), + } + } + } + + // Implement by hand because the derive would create invalid values. + // Use the constructor to create a valid value. + #[cfg(feature = "arbitrary")] + impl<'a> arbitrary::Arbitrary<'a> for BitString { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + Self::new( + u.int_in_range(0..=Self::MAX_UNUSED_BITS)?, + BytesRef::arbitrary(u)?.as_slice(), + ) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } + + fn size_hint(depth: usize) -> (usize, Option) { + arbitrary::size_hint::and(u8::size_hint(depth), BytesRef::size_hint(depth)) + } + } + + impl<'a> RefToOwned<'a> for BitStringRef<'a> { + type Owned = BitString; + fn ref_to_owned(&self) -> Self::Owned { + BitString { + unused_bits: self.unused_bits, + bit_length: self.bit_length, + inner: Vec::from(self.inner.as_slice()), + } + } + } + + impl OwnedToRef for BitString { + type Borrowed<'a> = BitStringRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + self.into() + } + } +} + +/// Iterator over the bits of a [`BitString`]. +pub struct BitStringIter<'a> { + /// [`BitString`] being iterated over. + bit_string: BitStringRef<'a>, + + /// Current bit position within the iterator. + position: usize, +} + +impl<'a> Iterator for BitStringIter<'a> { + type Item = bool; + + #[allow(clippy::integer_arithmetic)] + fn next(&mut self) -> Option { + if self.position >= self.bit_string.bit_len() { + return None; + } + + let byte = self.bit_string.raw_bytes().get(self.position / 8)?; + let bit = 1u8 << (7 - (self.position % 8)); + self.position = self.position.checked_add(1)?; + Some(byte & bit != 0) + } +} + +impl<'a> ExactSizeIterator for BitStringIter<'a> { + fn len(&self) -> usize { + self.bit_string.bit_len() + } +} + +impl<'a> FusedIterator for BitStringIter<'a> {} + +#[cfg(feature = "flagset")] +impl FixedTag for flagset::FlagSet { + const TAG: Tag = BitStringRef::TAG; +} + +#[cfg(feature = "flagset")] +impl ValueOrd for flagset::FlagSet +where + T: flagset::Flags, + T::Type: Ord, +{ + fn value_cmp(&self, other: &Self) -> Result { + Ok(self.bits().cmp(&other.bits())) + } +} + +#[cfg(feature = "flagset")] +#[allow(clippy::integer_arithmetic)] +impl<'a, T> DecodeValue<'a> for flagset::FlagSet +where + T: flagset::Flags, + T::Type: From, + T::Type: core::ops::Shl, +{ + fn decode_value>(reader: &mut R, header: Header) -> Result { + let position = reader.position(); + let bits = BitStringRef::decode_value(reader, header)?; + + let mut flags = T::none().bits(); + + if bits.bit_len() > core::mem::size_of_val(&flags) * 8 { + return Err(Error::new(ErrorKind::Overlength, position)); + } + + for (i, bit) in bits.bits().enumerate() { + flags |= T::Type::from(bit) << i; + } + + Ok(Self::new_truncated(flags)) + } +} + +#[cfg(feature = "flagset")] +#[allow(clippy::integer_arithmetic)] +#[inline(always)] +fn encode_flagset(set: &flagset::FlagSet) -> (usize, [u8; 16]) +where + T: flagset::Flags, + u128: From, +{ + let bits: u128 = set.bits().into(); + let mut swap = 0u128; + + for i in 0..128 { + let on = bits & (1 << i); + swap |= on >> i << (128 - i - 1); + } + + (bits.leading_zeros() as usize, swap.to_be_bytes()) +} + +#[cfg(feature = "flagset")] +#[allow(clippy::cast_possible_truncation, clippy::integer_arithmetic)] +impl EncodeValue for flagset::FlagSet +where + T::Type: From, + T::Type: core::ops::Shl, + u128: From, +{ + fn value_len(&self) -> Result { + let (lead, buff) = encode_flagset(self); + let buff = &buff[..buff.len() - lead / 8]; + BitStringRef::new((lead % 8) as u8, buff)?.value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + let (lead, buff) = encode_flagset(self); + let buff = &buff[..buff.len() - lead / 8]; + BitStringRef::new((lead % 8) as u8, buff)?.encode_value(writer) + } +} + +#[cfg(test)] +mod tests { + use super::{BitStringRef, Result, Tag}; + use crate::asn1::AnyRef; + use hex_literal::hex; + + /// Parse a `BitString` from an ASN.1 `Any` value to test decoding behaviors. + fn parse_bitstring(bytes: &[u8]) -> Result> { + AnyRef::new(Tag::BitString, bytes)?.try_into() + } + + #[test] + fn decode_empty_bitstring() { + let bs = parse_bitstring(&hex!("00")).unwrap(); + assert_eq!(bs.as_bytes().unwrap(), &[]); + } + + #[test] + fn decode_non_empty_bitstring() { + let bs = parse_bitstring(&hex!("00010203")).unwrap(); + assert_eq!(bs.as_bytes().unwrap(), &[0x01, 0x02, 0x03]); + } + + #[test] + fn decode_bitstring_with_unused_bits() { + let bs = parse_bitstring(&hex!("066e5dc0")).unwrap(); + assert_eq!(bs.unused_bits(), 6); + assert_eq!(bs.raw_bytes(), &hex!("6e5dc0")); + + // Expected: 011011100101110111 + let mut bits = bs.bits(); + assert_eq!(bits.len(), 18); + + for bit in [0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1] { + assert_eq!(u8::from(bits.next().unwrap()), bit) + } + + // Ensure `None` is returned on successive calls + assert_eq!(bits.next(), None); + assert_eq!(bits.next(), None); + } + + #[test] + fn reject_unused_bits_in_empty_string() { + assert_eq!( + parse_bitstring(&[0x03]).err().unwrap().kind(), + Tag::BitString.value_error().kind() + ) + } +} diff --git a/src/rust/vendor/der/src/asn1/bmp_string.rs b/src/rust/vendor/der/src/asn1/bmp_string.rs new file mode 100644 index 000000000..b4135d518 --- /dev/null +++ b/src/rust/vendor/der/src/asn1/bmp_string.rs @@ -0,0 +1,164 @@ +//! ASN.1 `BMPString` support. + +use crate::{ + BytesOwned, DecodeValue, EncodeValue, Error, FixedTag, Header, Length, Reader, Result, Tag, + Writer, +}; +use alloc::{boxed::Box, vec::Vec}; +use core::{fmt, str::FromStr}; + +/// ASN.1 `BMPString` type. +/// +/// Encodes Basic Multilingual Plane (BMP) subset of Unicode (ISO 10646), +/// a.k.a. UCS-2. +#[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] +pub struct BmpString { + bytes: BytesOwned, +} + +impl BmpString { + /// Create a new [`BmpString`] from its UCS-2 encoding. + pub fn from_ucs2(bytes: impl Into>) -> Result { + let bytes = bytes.into(); + + if bytes.len() % 2 != 0 { + return Err(Tag::BmpString.length_error()); + } + + let ret = Self { + bytes: bytes.try_into()?, + }; + + for maybe_char in char::decode_utf16(ret.codepoints()) { + match maybe_char { + // All surrogates paired and character is in the Basic Multilingual Plane + Ok(c) if (c as u64) < u64::from(u16::MAX) => (), + // Unpaired surrogates or characters outside Basic Multilingual Plane + _ => return Err(Tag::BmpString.value_error()), + } + } + + Ok(ret) + } + + /// Create a new [`BmpString`] from a UTF-8 string. + pub fn from_utf8(utf8: &str) -> Result { + let capacity = utf8 + .len() + .checked_mul(2) + .ok_or_else(|| Tag::BmpString.length_error())?; + + let mut bytes = Vec::with_capacity(capacity); + + for code_point in utf8.encode_utf16() { + bytes.extend(code_point.to_be_bytes()); + } + + Self::from_ucs2(bytes) + } + + /// Borrow the encoded UCS-2 as bytes. + pub fn as_bytes(&self) -> &[u8] { + self.bytes.as_ref() + } + + /// Obtain the inner bytes. + #[inline] + pub fn into_bytes(self) -> Box<[u8]> { + self.bytes.into() + } + + /// Get an iterator over characters in the string. + pub fn chars(&self) -> impl Iterator + '_ { + char::decode_utf16(self.codepoints()) + .map(|maybe_char| maybe_char.expect("unpaired surrogates checked in constructor")) + } + + /// Get an iterator over the `u16` codepoints. + pub fn codepoints(&self) -> impl Iterator + '_ { + // TODO(tarcieri): use `array_chunks` + self.as_bytes() + .chunks_exact(2) + .map(|chunk| u16::from_be_bytes([chunk[0], chunk[1]])) + } +} + +impl AsRef<[u8]> for BmpString { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<'a> DecodeValue<'a> for BmpString { + fn decode_value>(reader: &mut R, header: Header) -> Result { + Self::from_ucs2(reader.read_vec(header.length)?) + } +} + +impl EncodeValue for BmpString { + fn value_len(&self) -> Result { + Ok(self.bytes.len()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.as_bytes()) + } +} + +impl FixedTag for BmpString { + const TAG: Tag = Tag::BmpString; +} + +impl FromStr for BmpString { + type Err = Error; + + fn from_str(s: &str) -> Result { + Self::from_utf8(s) + } +} + +impl fmt::Debug for BmpString { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "BmpString(\"{}\")", self) + } +} + +impl fmt::Display for BmpString { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for c in self.chars() { + write!(f, "{}", c)?; + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::BmpString; + use crate::{Decode, Encode}; + use alloc::string::ToString; + use hex_literal::hex; + + const EXAMPLE_BYTES: &[u8] = &hex!( + "1e 26 00 43 00 65 00 72 00 74" + " 00 69 00 66 00 69 00 63" + " 00 61 00 74 00 65 00 54" + " 00 65 00 6d 00 70 00 6c" + " 00 61 00 74 00 65" + ); + + const EXAMPLE_UTF8: &str = "CertificateTemplate"; + + #[test] + fn decode() { + let bmp_string = BmpString::from_der(EXAMPLE_BYTES).unwrap(); + assert_eq!(bmp_string.to_string(), EXAMPLE_UTF8); + } + + #[test] + fn encode() { + let bmp_string = BmpString::from_utf8(EXAMPLE_UTF8).unwrap(); + let encoded = bmp_string.to_der().unwrap(); + assert_eq!(encoded, EXAMPLE_BYTES); + } +} diff --git a/src/rust/vendor/der/src/asn1/boolean.rs b/src/rust/vendor/der/src/asn1/boolean.rs new file mode 100644 index 000000000..3eb0f2e68 --- /dev/null +++ b/src/rust/vendor/der/src/asn1/boolean.rs @@ -0,0 +1,82 @@ +//! ASN.1 `BOOLEAN` support. + +use crate::{ + asn1::AnyRef, ord::OrdIsValueOrd, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, + Length, Reader, Result, Tag, Writer, +}; + +/// Byte used to encode `true` in ASN.1 DER. From X.690 Section 11.1: +/// +/// > If the encoding represents the boolean value TRUE, its single contents +/// > octet shall have all eight bits set to one. +const TRUE_OCTET: u8 = 0b11111111; + +/// Byte used to encode `false` in ASN.1 DER. +const FALSE_OCTET: u8 = 0b00000000; + +impl<'a> DecodeValue<'a> for bool { + fn decode_value>(reader: &mut R, header: Header) -> Result { + if header.length != Length::ONE { + return Err(reader.error(ErrorKind::Length { tag: Self::TAG })); + } + + match reader.read_byte()? { + FALSE_OCTET => Ok(false), + TRUE_OCTET => Ok(true), + _ => Err(Self::TAG.non_canonical_error()), + } + } +} + +impl EncodeValue for bool { + fn value_len(&self) -> Result { + Ok(Length::ONE) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write_byte(if *self { TRUE_OCTET } else { FALSE_OCTET }) + } +} + +impl FixedTag for bool { + const TAG: Tag = Tag::Boolean; +} + +impl OrdIsValueOrd for bool {} + +impl TryFrom> for bool { + type Error = Error; + + fn try_from(any: AnyRef<'_>) -> Result { + any.try_into() + } +} + +#[cfg(test)] +mod tests { + use crate::{Decode, Encode}; + + #[test] + fn decode() { + assert_eq!(true, bool::from_der(&[0x01, 0x01, 0xFF]).unwrap()); + assert_eq!(false, bool::from_der(&[0x01, 0x01, 0x00]).unwrap()); + } + + #[test] + fn encode() { + let mut buffer = [0u8; 3]; + assert_eq!( + &[0x01, 0x01, 0xFF], + true.encode_to_slice(&mut buffer).unwrap() + ); + assert_eq!( + &[0x01, 0x01, 0x00], + false.encode_to_slice(&mut buffer).unwrap() + ); + } + + #[test] + fn reject_non_canonical() { + assert!(bool::from_der(&[0x01, 0x01, 0x01]).is_err()); + } +} diff --git a/src/rust/vendor/der/src/asn1/choice.rs b/src/rust/vendor/der/src/asn1/choice.rs new file mode 100644 index 000000000..40c7720ca --- /dev/null +++ b/src/rust/vendor/der/src/asn1/choice.rs @@ -0,0 +1,26 @@ +//! ASN.1 `CHOICE` support. + +use crate::{Decode, FixedTag, Tag, Tagged}; + +/// ASN.1 `CHOICE` denotes a union of one or more possible alternatives. +/// +/// The types MUST have distinct tags. +/// +/// This crate models choice as a trait, with a blanket impl for all types +/// which impl `Decode + FixedTag` (i.e. they are modeled as a `CHOICE` +/// with only one possible variant) +pub trait Choice<'a>: Decode<'a> + Tagged { + /// Is the provided [`Tag`] decodable as a variant of this `CHOICE`? + fn can_decode(tag: Tag) -> bool; +} + +/// This blanket impl allows any [`Tagged`] type to function as a [`Choice`] +/// with a single alternative. +impl<'a, T> Choice<'a> for T +where + T: Decode<'a> + FixedTag, +{ + fn can_decode(tag: Tag) -> bool { + T::TAG == tag + } +} diff --git a/src/rust/vendor/der/src/asn1/context_specific.rs b/src/rust/vendor/der/src/asn1/context_specific.rs new file mode 100644 index 000000000..101ddf022 --- /dev/null +++ b/src/rust/vendor/der/src/asn1/context_specific.rs @@ -0,0 +1,354 @@ +//! Context-specific field. + +use crate::{ + asn1::AnyRef, Choice, Decode, DecodeValue, DerOrd, Encode, EncodeValue, EncodeValueRef, Error, + Header, Length, Reader, Result, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer, +}; +use core::cmp::Ordering; + +/// Context-specific field which wraps an owned inner value. +/// +/// This type decodes/encodes a field which is specific to a particular context +/// and is identified by a [`TagNumber`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct ContextSpecific { + /// Context-specific tag number sans the leading `0b10000000` class + /// identifier bit and `0b100000` constructed flag. + pub tag_number: TagNumber, + + /// Tag mode: `EXPLICIT` VS `IMPLICIT`. + pub tag_mode: TagMode, + + /// Value of the field. + pub value: T, +} + +impl ContextSpecific { + /// Attempt to decode an `EXPLICIT` ASN.1 `CONTEXT-SPECIFIC` field with the + /// provided [`TagNumber`]. + /// + /// This method has the following behavior which is designed to simplify + /// handling of extension fields, which are denoted in an ASN.1 schema + /// using the `...` ellipsis extension marker: + /// + /// - Skips over [`ContextSpecific`] fields with a tag number lower than + /// the current one, consuming and ignoring them. + /// - Returns `Ok(None)` if a [`ContextSpecific`] field with a higher tag + /// number is encountered. These fields are not consumed in this case, + /// allowing a field with a lower tag number to be omitted, then the + /// higher numbered field consumed as a follow-up. + /// - Returns `Ok(None)` if anything other than a [`ContextSpecific`] field + /// is encountered. + pub fn decode_explicit<'a, R: Reader<'a>>( + reader: &mut R, + tag_number: TagNumber, + ) -> Result> + where + T: Decode<'a>, + { + Self::decode_with(reader, tag_number, |reader| Self::decode(reader)) + } + + /// Attempt to decode an `IMPLICIT` ASN.1 `CONTEXT-SPECIFIC` field with the + /// provided [`TagNumber`]. + /// + /// This method otherwise behaves the same as `decode_explicit`, + /// but should be used in cases where the particular fields are `IMPLICIT` + /// as opposed to `EXPLICIT`. + pub fn decode_implicit<'a, R: Reader<'a>>( + reader: &mut R, + tag_number: TagNumber, + ) -> Result> + where + T: DecodeValue<'a> + Tagged, + { + Self::decode_with(reader, tag_number, |reader| { + let header = Header::decode(reader)?; + let value = T::decode_value(reader, header)?; + + if header.tag.is_constructed() != value.tag().is_constructed() { + return Err(header.tag.non_canonical_error()); + } + + Ok(Self { + tag_number, + tag_mode: TagMode::Implicit, + value, + }) + }) + } + + /// Attempt to decode a context-specific field with the given + /// helper callback. + fn decode_with<'a, F, R: Reader<'a>>( + reader: &mut R, + tag_number: TagNumber, + f: F, + ) -> Result> + where + F: FnOnce(&mut R) -> Result, + { + while let Some(octet) = reader.peek_byte() { + let tag = Tag::try_from(octet)?; + + if !tag.is_context_specific() || (tag.number() > tag_number) { + break; + } else if tag.number() == tag_number { + return Some(f(reader)).transpose(); + } else { + AnyRef::decode(reader)?; + } + } + + Ok(None) + } +} + +impl<'a, T> Choice<'a> for ContextSpecific +where + T: Decode<'a> + Tagged, +{ + fn can_decode(tag: Tag) -> bool { + tag.is_context_specific() + } +} + +impl<'a, T> Decode<'a> for ContextSpecific +where + T: Decode<'a>, +{ + fn decode>(reader: &mut R) -> Result { + let header = Header::decode(reader)?; + + match header.tag { + Tag::ContextSpecific { + number, + constructed: true, + } => Ok(Self { + tag_number: number, + tag_mode: TagMode::default(), + value: reader.read_nested(header.length, |reader| T::decode(reader))?, + }), + tag => Err(tag.unexpected_error(None)), + } + } +} + +impl EncodeValue for ContextSpecific +where + T: EncodeValue + Tagged, +{ + fn value_len(&self) -> Result { + match self.tag_mode { + TagMode::Explicit => self.value.encoded_len(), + TagMode::Implicit => self.value.value_len(), + } + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + match self.tag_mode { + TagMode::Explicit => self.value.encode(writer), + TagMode::Implicit => self.value.encode_value(writer), + } + } +} + +impl Tagged for ContextSpecific +where + T: Tagged, +{ + fn tag(&self) -> Tag { + let constructed = match self.tag_mode { + TagMode::Explicit => true, + TagMode::Implicit => self.value.tag().is_constructed(), + }; + + Tag::ContextSpecific { + number: self.tag_number, + constructed, + } + } +} + +impl<'a, T> TryFrom> for ContextSpecific +where + T: Decode<'a>, +{ + type Error = Error; + + fn try_from(any: AnyRef<'a>) -> Result> { + match any.tag() { + Tag::ContextSpecific { + number, + constructed: true, + } => Ok(Self { + tag_number: number, + tag_mode: TagMode::default(), + value: T::from_der(any.value())?, + }), + tag => Err(tag.unexpected_error(None)), + } + } +} + +impl ValueOrd for ContextSpecific +where + T: EncodeValue + ValueOrd + Tagged, +{ + fn value_cmp(&self, other: &Self) -> Result { + match self.tag_mode { + TagMode::Explicit => self.der_cmp(other), + TagMode::Implicit => self.value_cmp(other), + } + } +} + +/// Context-specific field reference. +/// +/// This type encodes a field which is specific to a particular context +/// and is identified by a [`TagNumber`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct ContextSpecificRef<'a, T> { + /// Context-specific tag number sans the leading `0b10000000` class + /// identifier bit and `0b100000` constructed flag. + pub tag_number: TagNumber, + + /// Tag mode: `EXPLICIT` VS `IMPLICIT`. + pub tag_mode: TagMode, + + /// Value of the field. + pub value: &'a T, +} + +impl<'a, T> ContextSpecificRef<'a, T> { + /// Convert to a [`ContextSpecific`]. + fn encoder(&self) -> ContextSpecific> { + ContextSpecific { + tag_number: self.tag_number, + tag_mode: self.tag_mode, + value: EncodeValueRef(self.value), + } + } +} + +impl<'a, T> EncodeValue for ContextSpecificRef<'a, T> +where + T: EncodeValue + Tagged, +{ + fn value_len(&self) -> Result { + self.encoder().value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + self.encoder().encode_value(writer) + } +} + +impl<'a, T> Tagged for ContextSpecificRef<'a, T> +where + T: Tagged, +{ + fn tag(&self) -> Tag { + self.encoder().tag() + } +} + +#[cfg(test)] +mod tests { + use super::ContextSpecific; + use crate::{asn1::BitStringRef, Decode, Encode, SliceReader, TagMode, TagNumber}; + use hex_literal::hex; + + // Public key data from `pkcs8` crate's `ed25519-pkcs8-v2.der` + const EXAMPLE_BYTES: &[u8] = + &hex!("A123032100A3A7EAE3A8373830BC47E1167BC50E1DB551999651E0E2DC587623438EAC3F31"); + + #[test] + fn round_trip() { + let field = ContextSpecific::>::from_der(EXAMPLE_BYTES).unwrap(); + assert_eq!(field.tag_number.value(), 1); + assert_eq!( + field.value, + BitStringRef::from_bytes(&EXAMPLE_BYTES[5..]).unwrap() + ); + + let mut buf = [0u8; 128]; + let encoded = field.encode_to_slice(&mut buf).unwrap(); + assert_eq!(encoded, EXAMPLE_BYTES); + } + + #[test] + fn context_specific_with_explicit_field() { + let tag_number = TagNumber::new(0); + + // Empty message + let mut reader = SliceReader::new(&[]).unwrap(); + assert_eq!( + ContextSpecific::::decode_explicit(&mut reader, tag_number).unwrap(), + None + ); + + // Message containing a non-context-specific type + let mut reader = SliceReader::new(&hex!("020100")).unwrap(); + assert_eq!( + ContextSpecific::::decode_explicit(&mut reader, tag_number).unwrap(), + None + ); + + // Message containing an EXPLICIT context-specific field + let mut reader = SliceReader::new(&hex!("A003020100")).unwrap(); + let field = ContextSpecific::::decode_explicit(&mut reader, tag_number) + .unwrap() + .unwrap(); + + assert_eq!(field.tag_number, tag_number); + assert_eq!(field.tag_mode, TagMode::Explicit); + assert_eq!(field.value, 0); + } + + #[test] + fn context_specific_with_implicit_field() { + // From RFC8410 Section 10.3: + // + // + // 81 33: [1] 00 19 BF 44 09 69 84 CD FE 85 41 BA C1 67 DC 3B + // 96 C8 50 86 AA 30 B6 B6 CB 0C 5C 38 AD 70 31 66 + // E1 + let context_specific_implicit_bytes = + hex!("81210019BF44096984CDFE8541BAC167DC3B96C85086AA30B6B6CB0C5C38AD703166E1"); + + let tag_number = TagNumber::new(1); + + let mut reader = SliceReader::new(&context_specific_implicit_bytes).unwrap(); + let field = ContextSpecific::>::decode_implicit(&mut reader, tag_number) + .unwrap() + .unwrap(); + + assert_eq!(field.tag_number, tag_number); + assert_eq!(field.tag_mode, TagMode::Implicit); + assert_eq!( + field.value.as_bytes().unwrap(), + &context_specific_implicit_bytes[3..] + ); + } + + #[test] + fn context_specific_skipping_unknown_field() { + let tag = TagNumber::new(1); + let mut reader = SliceReader::new(&hex!("A003020100A103020101")).unwrap(); + let field = ContextSpecific::::decode_explicit(&mut reader, tag) + .unwrap() + .unwrap(); + assert_eq!(field.value, 1); + } + + #[test] + fn context_specific_returns_none_on_greater_tag_number() { + let tag = TagNumber::new(0); + let mut reader = SliceReader::new(&hex!("A103020101")).unwrap(); + assert_eq!( + ContextSpecific::::decode_explicit(&mut reader, tag).unwrap(), + None + ); + } +} diff --git a/src/rust/vendor/der/src/asn1/generalized_time.rs b/src/rust/vendor/der/src/asn1/generalized_time.rs new file mode 100644 index 000000000..8837917c3 --- /dev/null +++ b/src/rust/vendor/der/src/asn1/generalized_time.rs @@ -0,0 +1,327 @@ +//! ASN.1 `GeneralizedTime` support. +#![cfg_attr(feature = "arbitrary", allow(clippy::integer_arithmetic))] + +use crate::{ + datetime::{self, DateTime}, + ord::OrdIsValueOrd, + DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, +}; +use core::time::Duration; + +#[cfg(feature = "std")] +use { + crate::{asn1::AnyRef, Error}, + std::time::SystemTime, +}; + +#[cfg(feature = "time")] +use time::PrimitiveDateTime; + +/// ASN.1 `GeneralizedTime` type. +/// +/// This type implements the validity requirements specified in +/// [RFC 5280 Section 4.1.2.5.2][1], namely: +/// +/// > For the purposes of this profile, GeneralizedTime values MUST be +/// > expressed in Greenwich Mean Time (Zulu) and MUST include seconds +/// > (i.e., times are `YYYYMMDDHHMMSSZ`), even where the number of seconds +/// > is zero. GeneralizedTime values MUST NOT include fractional seconds. +/// +/// [1]: https://tools.ietf.org/html/rfc5280#section-4.1.2.5.2 +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct GeneralizedTime(DateTime); + +impl GeneralizedTime { + /// Length of an RFC 5280-flavored ASN.1 DER-encoded [`GeneralizedTime`]. + const LENGTH: usize = 15; + + /// Create a [`GeneralizedTime`] from a [`DateTime`]. + pub const fn from_date_time(datetime: DateTime) -> Self { + Self(datetime) + } + + /// Convert this [`GeneralizedTime`] into a [`DateTime`]. + pub fn to_date_time(&self) -> DateTime { + self.0 + } + + /// Create a new [`GeneralizedTime`] given a [`Duration`] since `UNIX_EPOCH` + /// (a.k.a. "Unix time") + pub fn from_unix_duration(unix_duration: Duration) -> Result { + DateTime::from_unix_duration(unix_duration) + .map(Into::into) + .map_err(|_| Self::TAG.value_error()) + } + + /// Get the duration of this timestamp since `UNIX_EPOCH`. + pub fn to_unix_duration(&self) -> Duration { + self.0.unix_duration() + } + + /// Instantiate from [`SystemTime`]. + #[cfg(feature = "std")] + pub fn from_system_time(time: SystemTime) -> Result { + DateTime::try_from(time) + .map(Into::into) + .map_err(|_| Self::TAG.value_error()) + } + + /// Convert to [`SystemTime`]. + #[cfg(feature = "std")] + pub fn to_system_time(&self) -> SystemTime { + self.0.to_system_time() + } +} + +impl_any_conversions!(GeneralizedTime); + +impl<'a> DecodeValue<'a> for GeneralizedTime { + fn decode_value>(reader: &mut R, header: Header) -> Result { + if Self::LENGTH != usize::try_from(header.length)? { + return Err(Self::TAG.value_error()); + } + + let mut bytes = [0u8; Self::LENGTH]; + reader.read_into(&mut bytes)?; + + match bytes { + // RFC 5280 requires mandatory seconds and Z-normalized time zone + [y1, y2, y3, y4, mon1, mon2, day1, day2, hour1, hour2, min1, min2, sec1, sec2, b'Z'] => { + let year = u16::from(datetime::decode_decimal(Self::TAG, y1, y2)?) + .checked_mul(100) + .and_then(|y| { + y.checked_add(datetime::decode_decimal(Self::TAG, y3, y4).ok()?.into()) + }) + .ok_or(ErrorKind::DateTime)?; + let month = datetime::decode_decimal(Self::TAG, mon1, mon2)?; + let day = datetime::decode_decimal(Self::TAG, day1, day2)?; + let hour = datetime::decode_decimal(Self::TAG, hour1, hour2)?; + let minute = datetime::decode_decimal(Self::TAG, min1, min2)?; + let second = datetime::decode_decimal(Self::TAG, sec1, sec2)?; + + DateTime::new(year, month, day, hour, minute, second) + .map_err(|_| Self::TAG.value_error()) + .and_then(|dt| Self::from_unix_duration(dt.unix_duration())) + } + _ => Err(Self::TAG.value_error()), + } + } +} + +impl EncodeValue for GeneralizedTime { + fn value_len(&self) -> Result { + Self::LENGTH.try_into() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + let year_hi = u8::try_from(self.0.year() / 100)?; + let year_lo = u8::try_from(self.0.year() % 100)?; + + datetime::encode_decimal(writer, Self::TAG, year_hi)?; + datetime::encode_decimal(writer, Self::TAG, year_lo)?; + datetime::encode_decimal(writer, Self::TAG, self.0.month())?; + datetime::encode_decimal(writer, Self::TAG, self.0.day())?; + datetime::encode_decimal(writer, Self::TAG, self.0.hour())?; + datetime::encode_decimal(writer, Self::TAG, self.0.minutes())?; + datetime::encode_decimal(writer, Self::TAG, self.0.seconds())?; + writer.write_byte(b'Z') + } +} + +impl FixedTag for GeneralizedTime { + const TAG: Tag = Tag::GeneralizedTime; +} + +impl OrdIsValueOrd for GeneralizedTime {} + +impl From<&GeneralizedTime> for GeneralizedTime { + fn from(value: &GeneralizedTime) -> GeneralizedTime { + *value + } +} + +impl From for DateTime { + fn from(utc_time: GeneralizedTime) -> DateTime { + utc_time.0 + } +} + +impl From<&GeneralizedTime> for DateTime { + fn from(utc_time: &GeneralizedTime) -> DateTime { + utc_time.0 + } +} + +impl From for GeneralizedTime { + fn from(datetime: DateTime) -> Self { + Self::from_date_time(datetime) + } +} + +impl From<&DateTime> for GeneralizedTime { + fn from(datetime: &DateTime) -> Self { + Self::from_date_time(*datetime) + } +} + +impl<'a> DecodeValue<'a> for DateTime { + fn decode_value>(reader: &mut R, header: Header) -> Result { + Ok(GeneralizedTime::decode_value(reader, header)?.into()) + } +} + +impl EncodeValue for DateTime { + fn value_len(&self) -> Result { + GeneralizedTime::from(self).value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + GeneralizedTime::from(self).encode_value(writer) + } +} + +impl FixedTag for DateTime { + const TAG: Tag = Tag::GeneralizedTime; +} + +impl OrdIsValueOrd for DateTime {} + +#[cfg(feature = "std")] +impl<'a> DecodeValue<'a> for SystemTime { + fn decode_value>(reader: &mut R, header: Header) -> Result { + Ok(GeneralizedTime::decode_value(reader, header)?.into()) + } +} + +#[cfg(feature = "std")] +impl EncodeValue for SystemTime { + fn value_len(&self) -> Result { + GeneralizedTime::try_from(self)?.value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + GeneralizedTime::try_from(self)?.encode_value(writer) + } +} + +#[cfg(feature = "std")] +impl From for SystemTime { + fn from(time: GeneralizedTime) -> SystemTime { + time.to_system_time() + } +} + +#[cfg(feature = "std")] +impl From<&GeneralizedTime> for SystemTime { + fn from(time: &GeneralizedTime) -> SystemTime { + time.to_system_time() + } +} + +#[cfg(feature = "std")] +impl TryFrom for GeneralizedTime { + type Error = Error; + + fn try_from(time: SystemTime) -> Result { + GeneralizedTime::from_system_time(time) + } +} + +#[cfg(feature = "std")] +impl TryFrom<&SystemTime> for GeneralizedTime { + type Error = Error; + + fn try_from(time: &SystemTime) -> Result { + GeneralizedTime::from_system_time(*time) + } +} + +#[cfg(feature = "std")] +impl<'a> TryFrom> for SystemTime { + type Error = Error; + + fn try_from(any: AnyRef<'a>) -> Result { + GeneralizedTime::try_from(any).map(|s| s.to_system_time()) + } +} + +#[cfg(feature = "std")] +impl FixedTag for SystemTime { + const TAG: Tag = Tag::GeneralizedTime; +} + +#[cfg(feature = "std")] +impl OrdIsValueOrd for SystemTime {} + +#[cfg(feature = "time")] +impl<'a> DecodeValue<'a> for PrimitiveDateTime { + fn decode_value>(reader: &mut R, header: Header) -> Result { + GeneralizedTime::decode_value(reader, header)?.try_into() + } +} + +#[cfg(feature = "time")] +impl EncodeValue for PrimitiveDateTime { + fn value_len(&self) -> Result { + GeneralizedTime::try_from(self)?.value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + GeneralizedTime::try_from(self)?.encode_value(writer) + } +} + +#[cfg(feature = "time")] +impl FixedTag for PrimitiveDateTime { + const TAG: Tag = Tag::GeneralizedTime; +} + +#[cfg(feature = "time")] +impl OrdIsValueOrd for PrimitiveDateTime {} + +#[cfg(feature = "time")] +impl TryFrom for GeneralizedTime { + type Error = Error; + + fn try_from(time: PrimitiveDateTime) -> Result { + Ok(GeneralizedTime::from_date_time(DateTime::try_from(time)?)) + } +} + +#[cfg(feature = "time")] +impl TryFrom<&PrimitiveDateTime> for GeneralizedTime { + type Error = Error; + + fn try_from(time: &PrimitiveDateTime) -> Result { + Self::try_from(*time) + } +} + +#[cfg(feature = "time")] +impl TryFrom for PrimitiveDateTime { + type Error = Error; + + fn try_from(time: GeneralizedTime) -> Result { + time.to_date_time().try_into() + } +} + +#[cfg(test)] +mod tests { + use super::GeneralizedTime; + use crate::{Decode, Encode, SliceWriter}; + use hex_literal::hex; + + #[test] + fn round_trip() { + let example_bytes = hex!("18 0f 31 39 39 31 30 35 30 36 32 33 34 35 34 30 5a"); + let utc_time = GeneralizedTime::from_der(&example_bytes).unwrap(); + assert_eq!(utc_time.to_unix_duration().as_secs(), 673573540); + + let mut buf = [0u8; 128]; + let mut encoder = SliceWriter::new(&mut buf); + utc_time.encode(&mut encoder).unwrap(); + assert_eq!(example_bytes, encoder.finish().unwrap()); + } +} diff --git a/src/rust/vendor/der/src/asn1/ia5_string.rs b/src/rust/vendor/der/src/asn1/ia5_string.rs new file mode 100644 index 000000000..1b06dcef9 --- /dev/null +++ b/src/rust/vendor/der/src/asn1/ia5_string.rs @@ -0,0 +1,195 @@ +//! ASN.1 `IA5String` support. + +use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag}; +use core::{fmt, ops::Deref}; + +macro_rules! impl_ia5_string { + ($type: ty) => { + impl_ia5_string!($type,); + }; + ($type: ty, $($li: lifetime)?) => { + impl_string_type!($type, $($li),*); + + impl<$($li),*> FixedTag for $type { + const TAG: Tag = Tag::Ia5String; + } + + impl<$($li),*> fmt::Debug for $type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Ia5String({:?})", self.as_str()) + } + } + }; +} + +/// ASN.1 `IA5String` type. +/// +/// Supports the [International Alphabet No. 5 (IA5)] character encoding, i.e. +/// the lower 128 characters of the ASCII alphabet. (Note: IA5 is now +/// technically known as the International Reference Alphabet or IRA as +/// specified in the ITU-T's T.50 recommendation). +/// +/// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`]. +/// +/// This is a zero-copy reference type which borrows from the input data. +/// +/// [International Alphabet No. 5 (IA5)]: https://en.wikipedia.org/wiki/T.50_%28standard%29 +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] +pub struct Ia5StringRef<'a> { + /// Inner value + inner: StrRef<'a>, +} + +impl<'a> Ia5StringRef<'a> { + /// Create a new `IA5String`. + pub fn new(input: &'a T) -> Result + where + T: AsRef<[u8]> + ?Sized, + { + let input = input.as_ref(); + + // Validate all characters are within IA5String's allowed set + if input.iter().any(|&c| c > 0x7F) { + return Err(Self::TAG.value_error()); + } + + StrRef::from_bytes(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } +} + +impl_ia5_string!(Ia5StringRef<'a>, 'a); + +impl<'a> Deref for Ia5StringRef<'a> { + type Target = StrRef<'a>; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl<'a> From<&Ia5StringRef<'a>> for Ia5StringRef<'a> { + fn from(value: &Ia5StringRef<'a>) -> Ia5StringRef<'a> { + *value + } +} + +impl<'a> From> for AnyRef<'a> { + fn from(internationalized_string: Ia5StringRef<'a>) -> AnyRef<'a> { + AnyRef::from_tag_and_value(Tag::Ia5String, internationalized_string.inner.into()) + } +} + +#[cfg(feature = "alloc")] +pub use self::allocation::Ia5String; + +#[cfg(feature = "alloc")] +mod allocation { + use super::Ia5StringRef; + use crate::{ + asn1::AnyRef, + referenced::{OwnedToRef, RefToOwned}, + Error, FixedTag, Result, StrOwned, Tag, + }; + use alloc::string::String; + use core::{fmt, ops::Deref}; + + /// ASN.1 `IA5String` type. + /// + /// Supports the [International Alphabet No. 5 (IA5)] character encoding, i.e. + /// the lower 128 characters of the ASCII alphabet. (Note: IA5 is now + /// technically known as the International Reference Alphabet or IRA as + /// specified in the ITU-T's T.50 recommendation). + /// + /// For UTF-8, use [`String`][`alloc::string::String`]. + /// + /// [International Alphabet No. 5 (IA5)]: https://en.wikipedia.org/wiki/T.50_%28standard%29 + #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] + pub struct Ia5String { + /// Inner value + inner: StrOwned, + } + + impl Ia5String { + /// Create a new `IA5String`. + pub fn new(input: &T) -> Result + where + T: AsRef<[u8]> + ?Sized, + { + let input = input.as_ref(); + Ia5StringRef::new(input)?; + + StrOwned::from_bytes(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } + } + + impl_ia5_string!(Ia5String); + + impl Deref for Ia5String { + type Target = StrOwned; + + fn deref(&self) -> &Self::Target { + &self.inner + } + } + + impl<'a> From> for Ia5String { + fn from(international_string: Ia5StringRef<'a>) -> Ia5String { + let inner = international_string.inner.into(); + Self { inner } + } + } + + impl<'a> From<&'a Ia5String> for AnyRef<'a> { + fn from(international_string: &'a Ia5String) -> AnyRef<'a> { + AnyRef::from_tag_and_value(Tag::Ia5String, (&international_string.inner).into()) + } + } + + impl<'a> RefToOwned<'a> for Ia5StringRef<'a> { + type Owned = Ia5String; + fn ref_to_owned(&self) -> Self::Owned { + Ia5String { + inner: self.inner.ref_to_owned(), + } + } + } + + impl OwnedToRef for Ia5String { + type Borrowed<'a> = Ia5StringRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + Ia5StringRef { + inner: self.inner.owned_to_ref(), + } + } + } + + impl TryFrom for Ia5String { + type Error = Error; + + fn try_from(input: String) -> Result { + Ia5StringRef::new(&input)?; + + StrOwned::new(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } + } +} + +#[cfg(test)] +mod tests { + use super::Ia5StringRef; + use crate::Decode; + use hex_literal::hex; + + #[test] + fn parse_bytes() { + let example_bytes = hex!("16 0d 74 65 73 74 31 40 72 73 61 2e 63 6f 6d"); + let internationalized_string = Ia5StringRef::from_der(&example_bytes).unwrap(); + assert_eq!(internationalized_string.as_str(), "test1@rsa.com"); + } +} diff --git a/src/rust/vendor/der/src/asn1/integer.rs b/src/rust/vendor/der/src/asn1/integer.rs new file mode 100644 index 000000000..a6e913d66 --- /dev/null +++ b/src/rust/vendor/der/src/asn1/integer.rs @@ -0,0 +1,161 @@ +//! ASN.1 `INTEGER` support. + +pub(super) mod int; +pub(super) mod uint; + +use core::{cmp::Ordering, mem}; + +use crate::{EncodeValue, Result, SliceWriter}; + +/// Is the highest bit of the first byte in the slice set to `1`? (if present) +#[inline] +fn is_highest_bit_set(bytes: &[u8]) -> bool { + bytes + .first() + .map(|byte| byte & 0b10000000 != 0) + .unwrap_or(false) +} + +/// Compare two integer values +fn value_cmp(a: T, b: T) -> Result +where + T: Copy + EncodeValue + Sized, +{ + const MAX_INT_SIZE: usize = 16; + debug_assert!(mem::size_of::() <= MAX_INT_SIZE); + + let mut buf1 = [0u8; MAX_INT_SIZE]; + let mut encoder1 = SliceWriter::new(&mut buf1); + a.encode_value(&mut encoder1)?; + + let mut buf2 = [0u8; MAX_INT_SIZE]; + let mut encoder2 = SliceWriter::new(&mut buf2); + b.encode_value(&mut encoder2)?; + + Ok(encoder1.finish()?.cmp(encoder2.finish()?)) +} + +#[cfg(test)] +pub(crate) mod tests { + use crate::{Decode, Encode}; + + // Vectors from Section 5.7 of: + // https://luca.ntop.org/Teaching/Appunti/asn1.html + pub(crate) const I0_BYTES: &[u8] = &[0x02, 0x01, 0x00]; + pub(crate) const I127_BYTES: &[u8] = &[0x02, 0x01, 0x7F]; + pub(crate) const I128_BYTES: &[u8] = &[0x02, 0x02, 0x00, 0x80]; + pub(crate) const I256_BYTES: &[u8] = &[0x02, 0x02, 0x01, 0x00]; + pub(crate) const INEG128_BYTES: &[u8] = &[0x02, 0x01, 0x80]; + pub(crate) const INEG129_BYTES: &[u8] = &[0x02, 0x02, 0xFF, 0x7F]; + + // Additional vectors + pub(crate) const I255_BYTES: &[u8] = &[0x02, 0x02, 0x00, 0xFF]; + pub(crate) const I32767_BYTES: &[u8] = &[0x02, 0x02, 0x7F, 0xFF]; + pub(crate) const I65535_BYTES: &[u8] = &[0x02, 0x03, 0x00, 0xFF, 0xFF]; + pub(crate) const INEG32768_BYTES: &[u8] = &[0x02, 0x02, 0x80, 0x00]; + + #[test] + fn decode_i8() { + assert_eq!(0, i8::from_der(I0_BYTES).unwrap()); + assert_eq!(127, i8::from_der(I127_BYTES).unwrap()); + assert_eq!(-128, i8::from_der(INEG128_BYTES).unwrap()); + } + + #[test] + fn decode_i16() { + assert_eq!(0, i16::from_der(I0_BYTES).unwrap()); + assert_eq!(127, i16::from_der(I127_BYTES).unwrap()); + assert_eq!(128, i16::from_der(I128_BYTES).unwrap()); + assert_eq!(255, i16::from_der(I255_BYTES).unwrap()); + assert_eq!(256, i16::from_der(I256_BYTES).unwrap()); + assert_eq!(32767, i16::from_der(I32767_BYTES).unwrap()); + assert_eq!(-128, i16::from_der(INEG128_BYTES).unwrap()); + assert_eq!(-129, i16::from_der(INEG129_BYTES).unwrap()); + assert_eq!(-32768, i16::from_der(INEG32768_BYTES).unwrap()); + } + + #[test] + fn decode_u8() { + assert_eq!(0, u8::from_der(I0_BYTES).unwrap()); + assert_eq!(127, u8::from_der(I127_BYTES).unwrap()); + assert_eq!(255, u8::from_der(I255_BYTES).unwrap()); + } + + #[test] + fn decode_u16() { + assert_eq!(0, u16::from_der(I0_BYTES).unwrap()); + assert_eq!(127, u16::from_der(I127_BYTES).unwrap()); + assert_eq!(255, u16::from_der(I255_BYTES).unwrap()); + assert_eq!(256, u16::from_der(I256_BYTES).unwrap()); + assert_eq!(32767, u16::from_der(I32767_BYTES).unwrap()); + assert_eq!(65535, u16::from_der(I65535_BYTES).unwrap()); + } + + #[test] + fn encode_i8() { + let mut buffer = [0u8; 3]; + + assert_eq!(I0_BYTES, 0i8.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I127_BYTES, 127i8.encode_to_slice(&mut buffer).unwrap()); + + assert_eq!( + INEG128_BYTES, + (-128i8).encode_to_slice(&mut buffer).unwrap() + ); + } + + #[test] + fn encode_i16() { + let mut buffer = [0u8; 4]; + assert_eq!(I0_BYTES, 0i16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I127_BYTES, 127i16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I128_BYTES, 128i16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I255_BYTES, 255i16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I256_BYTES, 256i16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I32767_BYTES, 32767i16.encode_to_slice(&mut buffer).unwrap()); + + assert_eq!( + INEG128_BYTES, + (-128i16).encode_to_slice(&mut buffer).unwrap() + ); + + assert_eq!( + INEG129_BYTES, + (-129i16).encode_to_slice(&mut buffer).unwrap() + ); + + assert_eq!( + INEG32768_BYTES, + (-32768i16).encode_to_slice(&mut buffer).unwrap() + ); + } + + #[test] + fn encode_u8() { + let mut buffer = [0u8; 4]; + assert_eq!(I0_BYTES, 0u8.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I127_BYTES, 127u8.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I255_BYTES, 255u8.encode_to_slice(&mut buffer).unwrap()); + } + + #[test] + fn encode_u16() { + let mut buffer = [0u8; 5]; + assert_eq!(I0_BYTES, 0u16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I127_BYTES, 127u16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I128_BYTES, 128u16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I255_BYTES, 255u16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I256_BYTES, 256u16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I32767_BYTES, 32767u16.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(I65535_BYTES, 65535u16.encode_to_slice(&mut buffer).unwrap()); + } + + /// Integers must be encoded with a minimum number of octets + #[test] + fn reject_non_canonical() { + assert!(i8::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err()); + assert!(i16::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err()); + assert!(u8::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err()); + assert!(u16::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err()); + } +} diff --git a/src/rust/vendor/der/src/asn1/integer/int.rs b/src/rust/vendor/der/src/asn1/integer/int.rs new file mode 100644 index 000000000..bccc5210c --- /dev/null +++ b/src/rust/vendor/der/src/asn1/integer/int.rs @@ -0,0 +1,442 @@ +//! Support for encoding signed integers + +use super::{is_highest_bit_set, uint, value_cmp}; +use crate::{ + ord::OrdIsValueOrd, AnyRef, BytesRef, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, + Header, Length, Reader, Result, Tag, ValueOrd, Writer, +}; +use core::cmp::Ordering; + +#[cfg(feature = "alloc")] +pub use allocating::Int; + +macro_rules! impl_encoding_traits { + ($($int:ty => $uint:ty),+) => { + $( + impl<'a> DecodeValue<'a> for $int { + fn decode_value>(reader: &mut R, header: Header) -> Result { + let mut buf = [0u8; Self::BITS as usize / 8]; + let max_length = u32::from(header.length) as usize; + + if max_length > buf.len() { + return Err(Self::TAG.non_canonical_error()); + } + + let bytes = reader.read_into(&mut buf[..max_length])?; + + let result = if is_highest_bit_set(bytes) { + <$uint>::from_be_bytes(decode_to_array(bytes)?) as $int + } else { + Self::from_be_bytes(uint::decode_to_array(bytes)?) + }; + + // Ensure we compute the same encoded length as the original any value + if header.length != result.value_len()? { + return Err(Self::TAG.non_canonical_error()); + } + + Ok(result) + } + } + + impl EncodeValue for $int { + fn value_len(&self) -> Result { + if *self < 0 { + negative_encoded_len(&(*self as $uint).to_be_bytes()) + } else { + uint::encoded_len(&self.to_be_bytes()) + } + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + if *self < 0 { + encode_bytes(writer, &(*self as $uint).to_be_bytes()) + } else { + uint::encode_bytes(writer, &self.to_be_bytes()) + } + } + } + + impl FixedTag for $int { + const TAG: Tag = Tag::Integer; + } + + impl ValueOrd for $int { + fn value_cmp(&self, other: &Self) -> Result { + value_cmp(*self, *other) + } + } + + impl TryFrom> for $int { + type Error = Error; + + fn try_from(any: AnyRef<'_>) -> Result { + any.decode_as() + } + } + )+ + }; +} + +impl_encoding_traits!(i8 => u8, i16 => u16, i32 => u32, i64 => u64, i128 => u128); + +/// Signed arbitrary precision ASN.1 `INTEGER` reference type. +/// +/// Provides direct access to the underlying big endian bytes which comprise +/// an signed integer value. +/// +/// Intended for use cases like very large integers that are used in +/// cryptographic applications (e.g. keys, signatures). +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct IntRef<'a> { + /// Inner value + inner: BytesRef<'a>, +} + +impl<'a> IntRef<'a> { + /// Create a new [`IntRef`] from a byte slice. + pub fn new(bytes: &'a [u8]) -> Result { + let inner = BytesRef::new(strip_leading_ones(bytes)) + .map_err(|_| ErrorKind::Length { tag: Self::TAG })?; + + Ok(Self { inner }) + } + + /// Borrow the inner byte slice which contains the least significant bytes + /// of a big endian integer value with all leading ones stripped. + pub fn as_bytes(&self) -> &'a [u8] { + self.inner.as_slice() + } + + /// Get the length of this [`IntRef`] in bytes. + pub fn len(&self) -> Length { + self.inner.len() + } + + /// Is the inner byte slice empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } +} + +impl_any_conversions!(IntRef<'a>, 'a); + +impl<'a> DecodeValue<'a> for IntRef<'a> { + fn decode_value>(reader: &mut R, header: Header) -> Result { + let bytes = BytesRef::decode_value(reader, header)?; + validate_canonical(bytes.as_slice())?; + + let result = Self::new(bytes.as_slice())?; + + // Ensure we compute the same encoded length as the original any value. + if result.value_len()? != header.length { + return Err(Self::TAG.non_canonical_error()); + } + + Ok(result) + } +} + +impl<'a> EncodeValue for IntRef<'a> { + fn value_len(&self) -> Result { + // Signed integers always hold their full encoded form. + Ok(self.inner.len()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.as_bytes()) + } +} + +impl<'a> From<&IntRef<'a>> for IntRef<'a> { + fn from(value: &IntRef<'a>) -> IntRef<'a> { + *value + } +} + +impl<'a> FixedTag for IntRef<'a> { + const TAG: Tag = Tag::Integer; +} + +impl<'a> OrdIsValueOrd for IntRef<'a> {} + +#[cfg(feature = "alloc")] +mod allocating { + use super::{strip_leading_ones, validate_canonical, IntRef}; + use crate::{ + asn1::Uint, + ord::OrdIsValueOrd, + referenced::{OwnedToRef, RefToOwned}, + BytesOwned, DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result, + Tag, Writer, + }; + use alloc::vec::Vec; + + /// Signed arbitrary precision ASN.1 `INTEGER` type. + /// + /// Provides heap-allocated storage for big endian bytes which comprise an + /// signed integer value. + /// + /// Intended for use cases like very large integers that are used in + /// cryptographic applications (e.g. keys, signatures). + #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] + pub struct Int { + /// Inner value + inner: BytesOwned, + } + + impl Int { + /// Create a new [`Int`] from a byte slice. + pub fn new(bytes: &[u8]) -> Result { + let inner = BytesOwned::new(strip_leading_ones(bytes)) + .map_err(|_| ErrorKind::Length { tag: Self::TAG })?; + + Ok(Self { inner }) + } + + /// Borrow the inner byte slice which contains the least significant bytes + /// of a big endian integer value with all leading ones stripped. + pub fn as_bytes(&self) -> &[u8] { + self.inner.as_slice() + } + + /// Get the length of this [`Int`] in bytes. + pub fn len(&self) -> Length { + self.inner.len() + } + + /// Is the inner byte slice empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + } + + impl_any_conversions!(Int); + + impl<'a> DecodeValue<'a> for Int { + fn decode_value>(reader: &mut R, header: Header) -> Result { + let bytes = BytesOwned::decode_value(reader, header)?; + validate_canonical(bytes.as_slice())?; + + let result = Self::new(bytes.as_slice())?; + + // Ensure we compute the same encoded length as the original any value. + if result.value_len()? != header.length { + return Err(Self::TAG.non_canonical_error()); + } + + Ok(result) + } + } + + impl EncodeValue for Int { + fn value_len(&self) -> Result { + // Signed integers always hold their full encoded form. + Ok(self.inner.len()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.as_bytes()) + } + } + + impl<'a> From<&IntRef<'a>> for Int { + fn from(value: &IntRef<'a>) -> Int { + let inner = BytesOwned::new(value.as_bytes()).expect("Invalid Int"); + Int { inner } + } + } + + impl From for Int { + fn from(value: Uint) -> Self { + let mut inner: Vec = Vec::new(); + + // Add leading `0x00` byte if required + if value.value_len().expect("invalid Uint") > value.len() { + inner.push(0x00); + } + + inner.extend_from_slice(value.as_bytes()); + let inner = BytesOwned::new(inner).expect("invalid Uint"); + + Int { inner } + } + } + + impl FixedTag for Int { + const TAG: Tag = Tag::Integer; + } + + impl OrdIsValueOrd for Int {} + + impl<'a> RefToOwned<'a> for IntRef<'a> { + type Owned = Int; + fn ref_to_owned(&self) -> Self::Owned { + let inner = self.inner.ref_to_owned(); + + Int { inner } + } + } + + impl OwnedToRef for Int { + type Borrowed<'a> = IntRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + let inner = self.inner.owned_to_ref(); + + IntRef { inner } + } + } +} + +/// Ensure `INTEGER` is canonically encoded. +fn validate_canonical(bytes: &[u8]) -> Result<()> { + // The `INTEGER` type always encodes a signed value and we're decoding + // as signed here, so we allow a zero extension or sign extension byte, + // but only as permitted under DER canonicalization. + match bytes { + [] => Err(Tag::Integer.non_canonical_error()), + [0x00, byte, ..] if *byte < 0x80 => Err(Tag::Integer.non_canonical_error()), + [0xFF, byte, ..] if *byte >= 0x80 => Err(Tag::Integer.non_canonical_error()), + _ => Ok(()), + } +} + +/// Decode an signed integer of the specified size. +/// +/// Returns a byte array of the requested size containing a big endian integer. +fn decode_to_array(bytes: &[u8]) -> Result<[u8; N]> { + match N.checked_sub(bytes.len()) { + Some(offset) => { + let mut output = [0xFFu8; N]; + output[offset..].copy_from_slice(bytes); + Ok(output) + } + None => { + let expected_len = Length::try_from(N)?; + let actual_len = Length::try_from(bytes.len())?; + + Err(ErrorKind::Incomplete { + expected_len, + actual_len, + } + .into()) + } + } +} + +/// Encode the given big endian bytes representing an integer as ASN.1 DER. +fn encode_bytes(writer: &mut W, bytes: &[u8]) -> Result<()> +where + W: Writer + ?Sized, +{ + writer.write(strip_leading_ones(bytes)) +} + +/// Get the encoded length for the given **negative** integer serialized as bytes. +#[inline] +fn negative_encoded_len(bytes: &[u8]) -> Result { + Length::try_from(strip_leading_ones(bytes).len()) +} + +/// Strip the leading all-ones bytes from the given byte slice. +pub(crate) fn strip_leading_ones(mut bytes: &[u8]) -> &[u8] { + while let Some((byte, rest)) = bytes.split_first() { + if *byte == 0xFF && is_highest_bit_set(rest) { + bytes = rest; + continue; + } + + break; + } + + bytes +} + +#[cfg(test)] +mod tests { + use super::{validate_canonical, IntRef}; + use crate::{asn1::integer::tests::*, Decode, Encode, SliceWriter}; + + #[test] + fn validate_canonical_ok() { + assert_eq!(validate_canonical(&[0x00]), Ok(())); + assert_eq!(validate_canonical(&[0x01]), Ok(())); + assert_eq!(validate_canonical(&[0x00, 0x80]), Ok(())); + assert_eq!(validate_canonical(&[0xFF, 0x00]), Ok(())); + } + + #[test] + fn validate_canonical_err() { + // Empty integers are always non-canonical. + assert!(validate_canonical(&[]).is_err()); + + // Positives with excessive zero extension are non-canonical. + assert!(validate_canonical(&[0x00, 0x00]).is_err()); + + // Negatives with excessive sign extension are non-canonical. + assert!(validate_canonical(&[0xFF, 0x80]).is_err()); + } + + #[test] + fn decode_intref() { + // Positive numbers decode, but have zero extensions as necessary + // (to distinguish them from negative representations). + assert_eq!(&[0], IntRef::from_der(I0_BYTES).unwrap().as_bytes()); + assert_eq!(&[127], IntRef::from_der(I127_BYTES).unwrap().as_bytes()); + assert_eq!(&[0, 128], IntRef::from_der(I128_BYTES).unwrap().as_bytes()); + assert_eq!(&[0, 255], IntRef::from_der(I255_BYTES).unwrap().as_bytes()); + + assert_eq!( + &[0x01, 0x00], + IntRef::from_der(I256_BYTES).unwrap().as_bytes() + ); + + assert_eq!( + &[0x7F, 0xFF], + IntRef::from_der(I32767_BYTES).unwrap().as_bytes() + ); + + // Negative integers decode. + assert_eq!(&[128], IntRef::from_der(INEG128_BYTES).unwrap().as_bytes()); + assert_eq!( + &[255, 127], + IntRef::from_der(INEG129_BYTES).unwrap().as_bytes() + ); + assert_eq!( + &[128, 0], + IntRef::from_der(INEG32768_BYTES).unwrap().as_bytes() + ); + } + + #[test] + fn encode_intref() { + for &example in &[ + I0_BYTES, + I127_BYTES, + I128_BYTES, + I255_BYTES, + I256_BYTES, + I32767_BYTES, + ] { + let uint = IntRef::from_der(example).unwrap(); + + let mut buf = [0u8; 128]; + let mut encoder = SliceWriter::new(&mut buf); + uint.encode(&mut encoder).unwrap(); + + let result = encoder.finish().unwrap(); + assert_eq!(example, result); + } + + for &example in &[INEG128_BYTES, INEG129_BYTES, INEG32768_BYTES] { + let uint = IntRef::from_der(example).unwrap(); + + let mut buf = [0u8; 128]; + let mut encoder = SliceWriter::new(&mut buf); + uint.encode(&mut encoder).unwrap(); + + let result = encoder.finish().unwrap(); + assert_eq!(example, result); + } + } +} diff --git a/src/rust/vendor/der/src/asn1/integer/uint.rs b/src/rust/vendor/der/src/asn1/integer/uint.rs new file mode 100644 index 000000000..95c6297c2 --- /dev/null +++ b/src/rust/vendor/der/src/asn1/integer/uint.rs @@ -0,0 +1,428 @@ +//! Unsigned integer decoders/encoders. + +use super::value_cmp; +use crate::{ + ord::OrdIsValueOrd, AnyRef, BytesRef, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, + Header, Length, Reader, Result, Tag, ValueOrd, Writer, +}; +use core::cmp::Ordering; + +#[cfg(feature = "alloc")] +pub use allocating::Uint; + +macro_rules! impl_encoding_traits { + ($($uint:ty),+) => { + $( + impl<'a> DecodeValue<'a> for $uint { + fn decode_value>(reader: &mut R, header: Header) -> Result { + // Integers always encodes as a signed value, unsigned gets a leading 0x00 that + // needs to be stripped off. We need to provide room for it. + const UNSIGNED_HEADROOM: usize = 1; + + let mut buf = [0u8; (Self::BITS as usize / 8) + UNSIGNED_HEADROOM]; + let max_length = u32::from(header.length) as usize; + + if max_length > buf.len() { + return Err(Self::TAG.non_canonical_error()); + } + + let bytes = reader.read_into(&mut buf[..max_length])?; + + let result = Self::from_be_bytes(decode_to_array(bytes)?); + + // Ensure we compute the same encoded length as the original any value + if header.length != result.value_len()? { + return Err(Self::TAG.non_canonical_error()); + } + + Ok(result) + } + } + + impl EncodeValue for $uint { + fn value_len(&self) -> Result { + encoded_len(&self.to_be_bytes()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + encode_bytes(writer, &self.to_be_bytes()) + } + } + + impl FixedTag for $uint { + const TAG: Tag = Tag::Integer; + } + + impl ValueOrd for $uint { + fn value_cmp(&self, other: &Self) -> Result { + value_cmp(*self, *other) + } + } + + impl TryFrom> for $uint { + type Error = Error; + + fn try_from(any: AnyRef<'_>) -> Result { + any.decode_as() + } + } + )+ + }; +} + +impl_encoding_traits!(u8, u16, u32, u64, u128); + +/// Unsigned arbitrary precision ASN.1 `INTEGER` reference type. +/// +/// Provides direct access to the underlying big endian bytes which comprise an +/// unsigned integer value. +/// +/// Intended for use cases like very large integers that are used in +/// cryptographic applications (e.g. keys, signatures). +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct UintRef<'a> { + /// Inner value + inner: BytesRef<'a>, +} + +impl<'a> UintRef<'a> { + /// Create a new [`UintRef`] from a byte slice. + pub fn new(bytes: &'a [u8]) -> Result { + let inner = BytesRef::new(strip_leading_zeroes(bytes)) + .map_err(|_| ErrorKind::Length { tag: Self::TAG })?; + + Ok(Self { inner }) + } + + /// Borrow the inner byte slice which contains the least significant bytes + /// of a big endian integer value with all leading zeros stripped. + pub fn as_bytes(&self) -> &'a [u8] { + self.inner.as_slice() + } + + /// Get the length of this [`UintRef`] in bytes. + pub fn len(&self) -> Length { + self.inner.len() + } + + /// Is the inner byte slice empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } +} + +impl_any_conversions!(UintRef<'a>, 'a); + +impl<'a> DecodeValue<'a> for UintRef<'a> { + fn decode_value>(reader: &mut R, header: Header) -> Result { + let bytes = BytesRef::decode_value(reader, header)?.as_slice(); + let result = Self::new(decode_to_slice(bytes)?)?; + + // Ensure we compute the same encoded length as the original any value. + if result.value_len()? != header.length { + return Err(Self::TAG.non_canonical_error()); + } + + Ok(result) + } +} + +impl<'a> EncodeValue for UintRef<'a> { + fn value_len(&self) -> Result { + encoded_len(self.inner.as_slice()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + // Add leading `0x00` byte if required + if self.value_len()? > self.len() { + writer.write_byte(0)?; + } + + writer.write(self.as_bytes()) + } +} + +impl<'a> From<&UintRef<'a>> for UintRef<'a> { + fn from(value: &UintRef<'a>) -> UintRef<'a> { + *value + } +} + +impl<'a> FixedTag for UintRef<'a> { + const TAG: Tag = Tag::Integer; +} + +impl<'a> OrdIsValueOrd for UintRef<'a> {} + +#[cfg(feature = "alloc")] +mod allocating { + use super::{decode_to_slice, encoded_len, strip_leading_zeroes, UintRef}; + use crate::{ + ord::OrdIsValueOrd, + referenced::{OwnedToRef, RefToOwned}, + BytesOwned, DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result, + Tag, Writer, + }; + + /// Unsigned arbitrary precision ASN.1 `INTEGER` type. + /// + /// Provides heap-allocated storage for big endian bytes which comprise an + /// unsigned integer value. + /// + /// Intended for use cases like very large integers that are used in + /// cryptographic applications (e.g. keys, signatures). + #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] + pub struct Uint { + /// Inner value + inner: BytesOwned, + } + + impl Uint { + /// Create a new [`Uint`] from a byte slice. + pub fn new(bytes: &[u8]) -> Result { + let inner = BytesOwned::new(strip_leading_zeroes(bytes)) + .map_err(|_| ErrorKind::Length { tag: Self::TAG })?; + + Ok(Self { inner }) + } + + /// Borrow the inner byte slice which contains the least significant bytes + /// of a big endian integer value with all leading zeros stripped. + pub fn as_bytes(&self) -> &[u8] { + self.inner.as_slice() + } + + /// Get the length of this [`Uint`] in bytes. + pub fn len(&self) -> Length { + self.inner.len() + } + + /// Is the inner byte slice empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + } + + impl_any_conversions!(Uint); + + impl<'a> DecodeValue<'a> for Uint { + fn decode_value>(reader: &mut R, header: Header) -> Result { + let bytes = BytesOwned::decode_value(reader, header)?; + let result = Self::new(decode_to_slice(bytes.as_slice())?)?; + + // Ensure we compute the same encoded length as the original any value. + if result.value_len()? != header.length { + return Err(Self::TAG.non_canonical_error()); + } + + Ok(result) + } + } + + impl EncodeValue for Uint { + fn value_len(&self) -> Result { + encoded_len(self.inner.as_slice()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + // Add leading `0x00` byte if required + if self.value_len()? > self.len() { + writer.write_byte(0)?; + } + + writer.write(self.as_bytes()) + } + } + + impl<'a> From<&UintRef<'a>> for Uint { + fn from(value: &UintRef<'a>) -> Uint { + let inner = BytesOwned::new(value.as_bytes()).expect("Invalid Uint"); + Uint { inner } + } + } + + impl FixedTag for Uint { + const TAG: Tag = Tag::Integer; + } + + impl OrdIsValueOrd for Uint {} + + impl<'a> RefToOwned<'a> for UintRef<'a> { + type Owned = Uint; + fn ref_to_owned(&self) -> Self::Owned { + let inner = self.inner.ref_to_owned(); + + Uint { inner } + } + } + + impl OwnedToRef for Uint { + type Borrowed<'a> = UintRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + let inner = self.inner.owned_to_ref(); + + UintRef { inner } + } + } +} + +/// Decode an unsigned integer into a big endian byte slice with all leading +/// zeroes removed. +/// +/// Returns a byte array of the requested size containing a big endian integer. +pub(crate) fn decode_to_slice(bytes: &[u8]) -> Result<&[u8]> { + // The `INTEGER` type always encodes a signed value, so for unsigned + // values the leading `0x00` byte may need to be removed. + // + // We also disallow a leading byte which would overflow a signed ASN.1 + // integer (since we're decoding an unsigned integer). + // We expect all such cases to have a leading `0x00` byte. + match bytes { + [] => Err(Tag::Integer.non_canonical_error()), + [0] => Ok(bytes), + [0, byte, ..] if *byte < 0x80 => Err(Tag::Integer.non_canonical_error()), + [0, rest @ ..] => Ok(rest), + [byte, ..] if *byte >= 0x80 => Err(Tag::Integer.value_error()), + _ => Ok(bytes), + } +} + +/// Decode an unsigned integer into a byte array of the requested size +/// containing a big endian integer. +pub(super) fn decode_to_array(bytes: &[u8]) -> Result<[u8; N]> { + let input = decode_to_slice(bytes)?; + + // Compute number of leading zeroes to add + let num_zeroes = N + .checked_sub(input.len()) + .ok_or_else(|| Tag::Integer.length_error())?; + + // Copy input into `N`-sized output buffer with leading zeroes + let mut output = [0u8; N]; + output[num_zeroes..].copy_from_slice(input); + Ok(output) +} + +/// Encode the given big endian bytes representing an integer as ASN.1 DER. +pub(crate) fn encode_bytes(encoder: &mut W, bytes: &[u8]) -> Result<()> +where + W: Writer + ?Sized, +{ + let bytes = strip_leading_zeroes(bytes); + + if needs_leading_zero(bytes) { + encoder.write_byte(0)?; + } + + encoder.write(bytes) +} + +/// Get the encoded length for the given unsigned integer serialized as bytes. +#[inline] +pub(crate) fn encoded_len(bytes: &[u8]) -> Result { + let bytes = strip_leading_zeroes(bytes); + Length::try_from(bytes.len())? + u8::from(needs_leading_zero(bytes)) +} + +/// Strip the leading zeroes from the given byte slice +pub(crate) fn strip_leading_zeroes(mut bytes: &[u8]) -> &[u8] { + while let Some((byte, rest)) = bytes.split_first() { + if *byte == 0 && !rest.is_empty() { + bytes = rest; + } else { + break; + } + } + + bytes +} + +/// Does the given integer need a leading zero? +fn needs_leading_zero(bytes: &[u8]) -> bool { + matches!(bytes.first(), Some(byte) if *byte >= 0x80) +} + +#[cfg(test)] +mod tests { + use super::{decode_to_array, UintRef}; + use crate::{asn1::integer::tests::*, AnyRef, Decode, Encode, ErrorKind, SliceWriter, Tag}; + + #[test] + fn decode_to_array_no_leading_zero() { + let arr = decode_to_array::<4>(&[1, 2]).unwrap(); + assert_eq!(arr, [0, 0, 1, 2]); + } + + #[test] + fn decode_to_array_leading_zero() { + let arr = decode_to_array::<4>(&[0x00, 0xFF, 0xFE]).unwrap(); + assert_eq!(arr, [0x00, 0x00, 0xFF, 0xFE]); + } + + #[test] + fn decode_to_array_extra_zero() { + let err = decode_to_array::<4>(&[0, 1, 2]).err().unwrap(); + assert_eq!(err.kind(), ErrorKind::Noncanonical { tag: Tag::Integer }); + } + + #[test] + fn decode_to_array_missing_zero() { + // We're decoding an unsigned integer, but this value would be signed + let err = decode_to_array::<4>(&[0xFF, 0xFE]).err().unwrap(); + assert_eq!(err.kind(), ErrorKind::Value { tag: Tag::Integer }); + } + + #[test] + fn decode_to_array_oversized_input() { + let err = decode_to_array::<1>(&[1, 2, 3]).err().unwrap(); + assert_eq!(err.kind(), ErrorKind::Length { tag: Tag::Integer }); + } + + #[test] + fn decode_uintref() { + assert_eq!(&[0], UintRef::from_der(I0_BYTES).unwrap().as_bytes()); + assert_eq!(&[127], UintRef::from_der(I127_BYTES).unwrap().as_bytes()); + assert_eq!(&[128], UintRef::from_der(I128_BYTES).unwrap().as_bytes()); + assert_eq!(&[255], UintRef::from_der(I255_BYTES).unwrap().as_bytes()); + + assert_eq!( + &[0x01, 0x00], + UintRef::from_der(I256_BYTES).unwrap().as_bytes() + ); + + assert_eq!( + &[0x7F, 0xFF], + UintRef::from_der(I32767_BYTES).unwrap().as_bytes() + ); + } + + #[test] + fn encode_uintref() { + for &example in &[ + I0_BYTES, + I127_BYTES, + I128_BYTES, + I255_BYTES, + I256_BYTES, + I32767_BYTES, + ] { + let uint = UintRef::from_der(example).unwrap(); + + let mut buf = [0u8; 128]; + let mut encoder = SliceWriter::new(&mut buf); + uint.encode(&mut encoder).unwrap(); + + let result = encoder.finish().unwrap(); + assert_eq!(example, result); + } + } + + #[test] + fn reject_oversize_without_extra_zero() { + let err = UintRef::try_from(AnyRef::new(Tag::Integer, &[0x81]).unwrap()) + .err() + .unwrap(); + + assert_eq!(err.kind(), ErrorKind::Value { tag: Tag::Integer }); + } +} diff --git a/src/rust/vendor/der/src/asn1/internal_macros.rs b/src/rust/vendor/der/src/asn1/internal_macros.rs new file mode 100644 index 000000000..10ad99d23 --- /dev/null +++ b/src/rust/vendor/der/src/asn1/internal_macros.rs @@ -0,0 +1,75 @@ +macro_rules! impl_any_conversions { + ($type: ty) => { + impl_any_conversions!($type, ); + }; + ($type: ty, $($li: lifetime)?) => { + impl<'__der: $($li),*, $($li),*> TryFrom<$crate::AnyRef<'__der>> for $type { + type Error = $crate::Error; + + fn try_from(any: $crate::AnyRef<'__der>) -> Result<$type> { + any.decode_as() + } + } + + #[cfg(feature = "alloc")] + impl<'__der: $($li),*, $($li),*> TryFrom<&'__der $crate::Any> for $type { + type Error = $crate::Error; + + fn try_from(any: &'__der $crate::Any) -> Result<$type> { + any.decode_as() + } + } + }; +} + +macro_rules! impl_string_type { + ($type: ty, $($li: lifetime)?) => { + impl_any_conversions!($type, $($li),*); + + mod __impl_string { + use super::*; + + use crate::{ + ord::OrdIsValueOrd, BytesRef, DecodeValue, EncodeValue, Header, Length, Reader, + Result, Writer, + }; + use core::{fmt, str}; + + impl<$($li),*> AsRef for $type { + fn as_ref(&self) -> &str { + self.as_str() + } + } + + impl<$($li),*> AsRef<[u8]> for $type { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } + } + + impl<'__der: $($li),*, $($li),*> DecodeValue<'__der> for $type { + fn decode_value>(reader: &mut R, header: Header) -> Result { + Self::new(BytesRef::decode_value(reader, header)?.as_slice()) + } + } + + impl<$($li),*> EncodeValue for $type { + fn value_len(&self) -> Result { + self.inner.value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + self.inner.encode_value(writer) + } + } + + impl<$($li),*> OrdIsValueOrd for $type {} + + impl<$($li),*> fmt::Display for $type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } + } + } + }; +} diff --git a/src/rust/vendor/der/src/asn1/null.rs b/src/rust/vendor/der/src/asn1/null.rs new file mode 100644 index 000000000..7c1e2058a --- /dev/null +++ b/src/rust/vendor/der/src/asn1/null.rs @@ -0,0 +1,102 @@ +//! ASN.1 `NULL` support. + +use crate::{ + asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, DecodeValue, EncodeValue, Error, ErrorKind, + FixedTag, Header, Length, Reader, Result, Tag, Writer, +}; + +/// ASN.1 `NULL` type. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct Null; + +impl_any_conversions!(Null); + +impl<'a> DecodeValue<'a> for Null { + fn decode_value>(reader: &mut R, header: Header) -> Result { + if header.length.is_zero() { + Ok(Null) + } else { + Err(reader.error(ErrorKind::Length { tag: Self::TAG })) + } + } +} + +impl EncodeValue for Null { + fn value_len(&self) -> Result { + Ok(Length::ZERO) + } + + fn encode_value(&self, _writer: &mut impl Writer) -> Result<()> { + Ok(()) + } +} + +impl FixedTag for Null { + const TAG: Tag = Tag::Null; +} + +impl OrdIsValueOrd for Null {} + +impl<'a> From for AnyRef<'a> { + fn from(_: Null) -> AnyRef<'a> { + AnyRef::from_tag_and_value(Tag::Null, BytesRef::default()) + } +} + +impl TryFrom> for () { + type Error = Error; + + fn try_from(any: AnyRef<'_>) -> Result<()> { + Null::try_from(any).map(|_| ()) + } +} + +impl<'a> From<()> for AnyRef<'a> { + fn from(_: ()) -> AnyRef<'a> { + Null.into() + } +} + +impl<'a> DecodeValue<'a> for () { + fn decode_value>(reader: &mut R, header: Header) -> Result { + Null::decode_value(reader, header)?; + Ok(()) + } +} + +impl EncodeValue for () { + fn value_len(&self) -> Result { + Ok(Length::ZERO) + } + + fn encode_value(&self, _writer: &mut impl Writer) -> Result<()> { + Ok(()) + } +} + +impl FixedTag for () { + const TAG: Tag = Tag::Null; +} + +#[cfg(test)] +mod tests { + use super::Null; + use crate::{Decode, Encode}; + + #[test] + fn decode() { + Null::from_der(&[0x05, 0x00]).unwrap(); + } + + #[test] + fn encode() { + let mut buffer = [0u8; 2]; + assert_eq!(&[0x05, 0x00], Null.encode_to_slice(&mut buffer).unwrap()); + assert_eq!(&[0x05, 0x00], ().encode_to_slice(&mut buffer).unwrap()); + } + + #[test] + fn reject_non_canonical() { + assert!(Null::from_der(&[0x05, 0x81, 0x00]).is_err()); + } +} diff --git a/src/rust/vendor/der/src/asn1/octet_string.rs b/src/rust/vendor/der/src/asn1/octet_string.rs new file mode 100644 index 000000000..53d8ecb6a --- /dev/null +++ b/src/rust/vendor/der/src/asn1/octet_string.rs @@ -0,0 +1,257 @@ +//! ASN.1 `OCTET STRING` support. + +use crate::{ + asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, Decode, DecodeValue, EncodeValue, ErrorKind, + FixedTag, Header, Length, Reader, Result, Tag, Writer, +}; + +/// ASN.1 `OCTET STRING` type: borrowed form. +/// +/// Octet strings represent contiguous sequences of octets, a.k.a. bytes. +/// +/// This is a zero-copy reference type which borrows from the input data. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct OctetStringRef<'a> { + /// Inner value + inner: BytesRef<'a>, +} + +impl<'a> OctetStringRef<'a> { + /// Create a new ASN.1 `OCTET STRING` from a byte slice. + pub fn new(slice: &'a [u8]) -> Result { + BytesRef::new(slice) + .map(|inner| Self { inner }) + .map_err(|_| ErrorKind::Length { tag: Self::TAG }.into()) + } + + /// Borrow the inner byte slice. + pub fn as_bytes(&self) -> &'a [u8] { + self.inner.as_slice() + } + + /// Get the length of the inner byte slice. + pub fn len(&self) -> Length { + self.inner.len() + } + + /// Is the inner byte slice empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + /// Parse `T` from this `OCTET STRING`'s contents. + pub fn decode_into>(&self) -> Result { + Decode::from_der(self.as_bytes()) + } +} + +impl_any_conversions!(OctetStringRef<'a>, 'a); + +impl AsRef<[u8]> for OctetStringRef<'_> { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<'a> DecodeValue<'a> for OctetStringRef<'a> { + fn decode_value>(reader: &mut R, header: Header) -> Result { + let inner = BytesRef::decode_value(reader, header)?; + Ok(Self { inner }) + } +} + +impl EncodeValue for OctetStringRef<'_> { + fn value_len(&self) -> Result { + self.inner.value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + self.inner.encode_value(writer) + } +} + +impl FixedTag for OctetStringRef<'_> { + const TAG: Tag = Tag::OctetString; +} + +impl OrdIsValueOrd for OctetStringRef<'_> {} + +impl<'a> From<&OctetStringRef<'a>> for OctetStringRef<'a> { + fn from(value: &OctetStringRef<'a>) -> OctetStringRef<'a> { + *value + } +} + +impl<'a> From> for AnyRef<'a> { + fn from(octet_string: OctetStringRef<'a>) -> AnyRef<'a> { + AnyRef::from_tag_and_value(Tag::OctetString, octet_string.inner) + } +} + +impl<'a> From> for &'a [u8] { + fn from(octet_string: OctetStringRef<'a>) -> &'a [u8] { + octet_string.as_bytes() + } +} + +#[cfg(feature = "alloc")] +pub use self::allocating::OctetString; + +#[cfg(feature = "alloc")] +mod allocating { + use super::*; + use crate::referenced::*; + use alloc::vec::Vec; + + /// ASN.1 `OCTET STRING` type: owned form.. + /// + /// Octet strings represent contiguous sequences of octets, a.k.a. bytes. + /// + /// This type provides the same functionality as [`OctetStringRef`] but owns + /// the backing data. + #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] + pub struct OctetString { + /// Bitstring represented as a slice of bytes. + pub(super) inner: Vec, + } + + impl OctetString { + /// Create a new ASN.1 `OCTET STRING`. + pub fn new(bytes: impl Into>) -> Result { + let inner = bytes.into(); + + // Ensure the bytes parse successfully as an `OctetStringRef` + OctetStringRef::new(&inner)?; + + Ok(Self { inner }) + } + + /// Borrow the inner byte slice. + pub fn as_bytes(&self) -> &[u8] { + self.inner.as_slice() + } + + /// Take ownership of the octet string. + pub fn into_bytes(self) -> Vec { + self.inner + } + + /// Get the length of the inner byte slice. + pub fn len(&self) -> Length { + self.value_len().expect("invalid OCTET STRING length") + } + + /// Is the inner byte slice empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + } + + impl_any_conversions!(OctetString); + + impl AsRef<[u8]> for OctetString { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } + } + + impl<'a> DecodeValue<'a> for OctetString { + fn decode_value>(reader: &mut R, header: Header) -> Result { + Self::new(reader.read_vec(header.length)?) + } + } + + impl EncodeValue for OctetString { + fn value_len(&self) -> Result { + self.inner.len().try_into() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(&self.inner) + } + } + + impl FixedTag for OctetString { + const TAG: Tag = Tag::OctetString; + } + + impl<'a> From<&'a OctetString> for OctetStringRef<'a> { + fn from(octet_string: &'a OctetString) -> OctetStringRef<'a> { + // Ensured to parse successfully in constructor + OctetStringRef::new(&octet_string.inner).expect("invalid OCTET STRING") + } + } + + impl OrdIsValueOrd for OctetString {} + + impl<'a> RefToOwned<'a> for OctetStringRef<'a> { + type Owned = OctetString; + fn ref_to_owned(&self) -> Self::Owned { + OctetString { + inner: Vec::from(self.inner.as_slice()), + } + } + } + + impl OwnedToRef for OctetString { + type Borrowed<'a> = OctetStringRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + self.into() + } + } + + // Implement by hand because the derive would create invalid values. + // Use the constructor to create a valid value. + #[cfg(feature = "arbitrary")] + impl<'a> arbitrary::Arbitrary<'a> for OctetString { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + Self::new(Vec::arbitrary(u)?).map_err(|_| arbitrary::Error::IncorrectFormat) + } + + fn size_hint(depth: usize) -> (usize, Option) { + arbitrary::size_hint::and(u8::size_hint(depth), Vec::::size_hint(depth)) + } + } +} + +#[cfg(feature = "bytes")] +mod bytes { + use super::OctetString; + use crate::{DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, Result, Tag, Writer}; + use bytes::Bytes; + + impl<'a> DecodeValue<'a> for Bytes { + fn decode_value>(reader: &mut R, header: Header) -> Result { + OctetString::decode_value(reader, header).map(|octet_string| octet_string.inner.into()) + } + } + + impl EncodeValue for Bytes { + fn value_len(&self) -> Result { + self.len().try_into() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.as_ref()) + } + } + + impl FixedTag for Bytes { + const TAG: Tag = Tag::OctetString; + } +} + +#[cfg(test)] +mod tests { + use crate::asn1::{OctetStringRef, PrintableStringRef}; + + #[test] + fn octet_string_decode_into() { + // PrintableString "hi" + let der = b"\x13\x02\x68\x69"; + let oct = OctetStringRef::new(der).unwrap(); + + let res = oct.decode_into::>().unwrap(); + assert_eq!(AsRef::::as_ref(&res), "hi"); + } +} diff --git a/src/rust/vendor/der/src/asn1/oid.rs b/src/rust/vendor/der/src/asn1/oid.rs new file mode 100644 index 000000000..3daa452b2 --- /dev/null +++ b/src/rust/vendor/der/src/asn1/oid.rs @@ -0,0 +1,100 @@ +//! ASN.1 `OBJECT IDENTIFIER` + +use crate::{ + asn1::AnyRef, ord::OrdIsValueOrd, DecodeValue, EncodeValue, Error, FixedTag, Header, Length, + Reader, Result, Tag, Tagged, Writer, +}; +use const_oid::ObjectIdentifier; + +#[cfg(feature = "alloc")] +use super::Any; + +impl<'a> DecodeValue<'a> for ObjectIdentifier { + fn decode_value>(reader: &mut R, header: Header) -> Result { + let mut buf = [0u8; ObjectIdentifier::MAX_SIZE]; + let slice = buf + .get_mut(..header.length.try_into()?) + .ok_or_else(|| Self::TAG.length_error())?; + + let actual_len = reader.read_into(slice)?.len(); + debug_assert_eq!(actual_len, header.length.try_into()?); + Ok(Self::from_bytes(slice)?) + } +} + +impl EncodeValue for ObjectIdentifier { + fn value_len(&self) -> Result { + Length::try_from(self.as_bytes().len()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.as_bytes()) + } +} + +impl FixedTag for ObjectIdentifier { + const TAG: Tag = Tag::ObjectIdentifier; +} + +impl OrdIsValueOrd for ObjectIdentifier {} + +impl<'a> From<&'a ObjectIdentifier> for AnyRef<'a> { + fn from(oid: &'a ObjectIdentifier) -> AnyRef<'a> { + // Note: ensuring an infallible conversion is possible relies on the + // invariant that `const_oid::MAX_LEN <= Length::max()`. + // + // The `length()` test below ensures this is the case. + let value = oid + .as_bytes() + .try_into() + .expect("OID length invariant violated"); + + AnyRef::from_tag_and_value(Tag::ObjectIdentifier, value) + } +} + +#[cfg(feature = "alloc")] +impl From for Any { + fn from(oid: ObjectIdentifier) -> Any { + AnyRef::from(&oid).into() + } +} + +impl TryFrom> for ObjectIdentifier { + type Error = Error; + + fn try_from(any: AnyRef<'_>) -> Result { + any.tag().assert_eq(Tag::ObjectIdentifier)?; + Ok(ObjectIdentifier::from_bytes(any.value())?) + } +} + +#[cfg(test)] +mod tests { + use super::ObjectIdentifier; + use crate::{Decode, Encode, Length}; + + const EXAMPLE_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549"); + const EXAMPLE_OID_BYTES: &[u8; 8] = &[0x06, 0x06, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d]; + + #[test] + fn decode() { + let oid = ObjectIdentifier::from_der(EXAMPLE_OID_BYTES).unwrap(); + assert_eq!(EXAMPLE_OID, oid); + } + + #[test] + fn encode() { + let mut buffer = [0u8; 8]; + assert_eq!( + EXAMPLE_OID_BYTES, + EXAMPLE_OID.encode_to_slice(&mut buffer).unwrap() + ); + } + + #[test] + fn length() { + // Ensure an infallible `From` conversion to `Any` will never panic + assert!(ObjectIdentifier::MAX_SIZE <= Length::MAX.try_into().unwrap()); + } +} diff --git a/src/rust/vendor/der/src/asn1/optional.rs b/src/rust/vendor/der/src/asn1/optional.rs new file mode 100644 index 000000000..ecda4f8ec --- /dev/null +++ b/src/rust/vendor/der/src/asn1/optional.rs @@ -0,0 +1,66 @@ +//! ASN.1 `OPTIONAL` as mapped to Rust's `Option` type + +use crate::{Choice, Decode, DerOrd, Encode, Length, Reader, Result, Tag, Writer}; +use core::cmp::Ordering; + +impl<'a, T> Decode<'a> for Option +where + T: Choice<'a>, // NOTE: all `Decode + Tagged` types receive a blanket `Choice` impl +{ + fn decode>(reader: &mut R) -> Result> { + if let Some(byte) = reader.peek_byte() { + if T::can_decode(Tag::try_from(byte)?) { + return T::decode(reader).map(Some); + } + } + + Ok(None) + } +} + +impl DerOrd for Option +where + T: DerOrd, +{ + fn der_cmp(&self, other: &Self) -> Result { + match self { + Some(a) => match other { + Some(b) => a.der_cmp(b), + None => Ok(Ordering::Greater), + }, + None => Ok(Ordering::Less), + } + } +} + +impl Encode for Option +where + T: Encode, +{ + fn encoded_len(&self) -> Result { + (&self).encoded_len() + } + + fn encode(&self, writer: &mut impl Writer) -> Result<()> { + (&self).encode(writer) + } +} + +impl Encode for &Option +where + T: Encode, +{ + fn encoded_len(&self) -> Result { + match self { + Some(encodable) => encodable.encoded_len(), + None => Ok(0u8.into()), + } + } + + fn encode(&self, encoder: &mut impl Writer) -> Result<()> { + match self { + Some(encodable) => encodable.encode(encoder), + None => Ok(()), + } + } +} diff --git a/src/rust/vendor/der/src/asn1/printable_string.rs b/src/rust/vendor/der/src/asn1/printable_string.rs new file mode 100644 index 000000000..d2e51d7da --- /dev/null +++ b/src/rust/vendor/der/src/asn1/printable_string.rs @@ -0,0 +1,252 @@ +//! ASN.1 `PrintableString` support. + +use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag}; +use core::{fmt, ops::Deref}; + +macro_rules! impl_printable_string { + ($type: ty) => { + impl_printable_string!($type,); + }; + ($type: ty, $($li: lifetime)?) => { + impl_string_type!($type, $($li),*); + + impl<$($li),*> FixedTag for $type { + const TAG: Tag = Tag::PrintableString; + } + + impl<$($li),*> fmt::Debug for $type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "PrintableString({:?})", self.as_str()) + } + } + }; +} + +/// ASN.1 `PrintableString` type. +/// +/// Supports a subset the ASCII character set (described below). +/// +/// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead. +/// For the full ASCII character set, use +/// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`]. +/// +/// This is a zero-copy reference type which borrows from the input data. +/// +/// # Supported characters +/// +/// The following ASCII characters/ranges are supported: +/// +/// - `A..Z` +/// - `a..z` +/// - `0..9` +/// - "` `" (i.e. space) +/// - `\` +/// - `(` +/// - `)` +/// - `+` +/// - `,` +/// - `-` +/// - `.` +/// - `/` +/// - `:` +/// - `=` +/// - `?` +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] +pub struct PrintableStringRef<'a> { + /// Inner value + inner: StrRef<'a>, +} + +impl<'a> PrintableStringRef<'a> { + /// Create a new ASN.1 `PrintableString`. + pub fn new(input: &'a T) -> Result + where + T: AsRef<[u8]> + ?Sized, + { + let input = input.as_ref(); + + // Validate all characters are within PrintableString's allowed set + for &c in input.iter() { + match c { + b'A'..=b'Z' + | b'a'..=b'z' + | b'0'..=b'9' + | b' ' + | b'\'' + | b'(' + | b')' + | b'+' + | b',' + | b'-' + | b'.' + | b'/' + | b':' + | b'=' + | b'?' => (), + _ => return Err(Self::TAG.value_error()), + } + } + + StrRef::from_bytes(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } +} + +impl_printable_string!(PrintableStringRef<'a>, 'a); + +impl<'a> Deref for PrintableStringRef<'a> { + type Target = StrRef<'a>; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} +impl<'a> From<&PrintableStringRef<'a>> for PrintableStringRef<'a> { + fn from(value: &PrintableStringRef<'a>) -> PrintableStringRef<'a> { + *value + } +} + +impl<'a> From> for AnyRef<'a> { + fn from(printable_string: PrintableStringRef<'a>) -> AnyRef<'a> { + AnyRef::from_tag_and_value(Tag::PrintableString, printable_string.inner.into()) + } +} + +#[cfg(feature = "alloc")] +pub use self::allocation::PrintableString; + +#[cfg(feature = "alloc")] +mod allocation { + use super::PrintableStringRef; + + use crate::{ + asn1::AnyRef, + referenced::{OwnedToRef, RefToOwned}, + BytesRef, Error, FixedTag, Result, StrOwned, Tag, + }; + use alloc::string::String; + use core::{fmt, ops::Deref}; + + /// ASN.1 `PrintableString` type. + /// + /// Supports a subset the ASCII character set (described below). + /// + /// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead. + /// For the full ASCII character set, use + /// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`]. + /// + /// # Supported characters + /// + /// The following ASCII characters/ranges are supported: + /// + /// - `A..Z` + /// - `a..z` + /// - `0..9` + /// - "` `" (i.e. space) + /// - `\` + /// - `(` + /// - `)` + /// - `+` + /// - `,` + /// - `-` + /// - `.` + /// - `/` + /// - `:` + /// - `=` + /// - `?` + #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] + pub struct PrintableString { + /// Inner value + inner: StrOwned, + } + + impl PrintableString { + /// Create a new ASN.1 `PrintableString`. + pub fn new(input: &T) -> Result + where + T: AsRef<[u8]> + ?Sized, + { + let input = input.as_ref(); + PrintableStringRef::new(input)?; + + StrOwned::from_bytes(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } + } + + impl_printable_string!(PrintableString); + + impl Deref for PrintableString { + type Target = StrOwned; + + fn deref(&self) -> &Self::Target { + &self.inner + } + } + + impl<'a> From> for PrintableString { + fn from(value: PrintableStringRef<'a>) -> PrintableString { + let inner = + StrOwned::from_bytes(value.inner.as_bytes()).expect("Invalid PrintableString"); + Self { inner } + } + } + + impl<'a> From<&'a PrintableString> for AnyRef<'a> { + fn from(printable_string: &'a PrintableString) -> AnyRef<'a> { + AnyRef::from_tag_and_value( + Tag::PrintableString, + BytesRef::new(printable_string.inner.as_bytes()).expect("Invalid PrintableString"), + ) + } + } + + impl<'a> RefToOwned<'a> for PrintableStringRef<'a> { + type Owned = PrintableString; + fn ref_to_owned(&self) -> Self::Owned { + PrintableString { + inner: self.inner.ref_to_owned(), + } + } + } + + impl OwnedToRef for PrintableString { + type Borrowed<'a> = PrintableStringRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + PrintableStringRef { + inner: self.inner.owned_to_ref(), + } + } + } + + impl TryFrom for PrintableString { + type Error = Error; + + fn try_from(input: String) -> Result { + PrintableStringRef::new(&input)?; + + StrOwned::new(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } + } +} + +#[cfg(test)] +mod tests { + use super::PrintableStringRef; + use crate::Decode; + + #[test] + fn parse_bytes() { + let example_bytes = &[ + 0x13, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31, + ]; + + let printable_string = PrintableStringRef::from_der(example_bytes).unwrap(); + assert_eq!(printable_string.as_str(), "Test User 1"); + } +} diff --git a/src/rust/vendor/der/src/asn1/real.rs b/src/rust/vendor/der/src/asn1/real.rs new file mode 100644 index 000000000..b9f2e67f5 --- /dev/null +++ b/src/rust/vendor/der/src/asn1/real.rs @@ -0,0 +1,990 @@ +//! ASN.1 `REAL` support. + +// TODO(tarcieri): checked arithmetic +#![allow( + clippy::cast_lossless, + clippy::cast_sign_loss, + clippy::integer_arithmetic +)] + +use crate::{ + BytesRef, DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, Result, StrRef, Tag, + Writer, +}; + +use super::integer::uint::strip_leading_zeroes; + +impl<'a> DecodeValue<'a> for f64 { + fn decode_value>(reader: &mut R, header: Header) -> Result { + let bytes = BytesRef::decode_value(reader, header)?.as_slice(); + + if header.length == Length::ZERO { + Ok(0.0) + } else if is_nth_bit_one::<7>(bytes) { + // Binary encoding from section 8.5.7 applies + let sign: u64 = u64::from(is_nth_bit_one::<6>(bytes)); + + // Section 8.5.7.2: Check the base -- the DER specs say that only base 2 should be supported in DER + let base = mnth_bits_to_u8::<5, 4>(bytes); + + if base != 0 { + // Real related error: base is not DER compliant (base encoded in enum) + return Err(Tag::Real.value_error()); + } + + // Section 8.5.7.3 + let scaling_factor = mnth_bits_to_u8::<3, 2>(bytes); + + // Section 8.5.7.4 + let mantissa_start; + let exponent = match mnth_bits_to_u8::<1, 0>(bytes) { + 0 => { + mantissa_start = 2; + let ebytes = (i16::from_be_bytes([0x0, bytes[1]])).to_be_bytes(); + u64::from_be_bytes([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ebytes[0], ebytes[1]]) + } + 1 => { + mantissa_start = 3; + let ebytes = (i16::from_be_bytes([bytes[1], bytes[2]])).to_be_bytes(); + u64::from_be_bytes([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ebytes[0], ebytes[1]]) + } + _ => { + // Real related error: encoded exponent cannot be represented on an IEEE-754 double + return Err(Tag::Real.value_error()); + } + }; + // Section 8.5.7.5: Read the remaining bytes for the mantissa + let mut n_bytes = [0x0; 8]; + for (pos, byte) in bytes[mantissa_start..].iter().rev().enumerate() { + n_bytes[7 - pos] = *byte; + } + let n = u64::from_be_bytes(n_bytes); + // Multiply byt 2^F corresponds to just a left shift + let mantissa = n << scaling_factor; + // Create the f64 + Ok(encode_f64(sign, exponent, mantissa)) + } else if is_nth_bit_one::<6>(bytes) { + // This either a special value, or it's the value minus zero is encoded, section 8.5.9 applies + match mnth_bits_to_u8::<1, 0>(bytes) { + 0 => Ok(f64::INFINITY), + 1 => Ok(f64::NEG_INFINITY), + 2 => Ok(f64::NAN), + 3 => Ok(-0.0_f64), + _ => Err(Tag::Real.value_error()), + } + } else { + let astr = StrRef::from_bytes(&bytes[1..])?; + match astr.inner.parse::() { + Ok(val) => Ok(val), + // Real related error: encoding not supported or malformed + Err(_) => Err(Tag::Real.value_error()), + } + } + } +} + +impl EncodeValue for f64 { + fn value_len(&self) -> Result { + if self.is_sign_positive() && (*self) < f64::MIN_POSITIVE { + // Zero: positive yet smaller than the minimum positive number + Ok(Length::ZERO) + } else if self.is_nan() + || self.is_infinite() + || (self.is_sign_negative() && -self < f64::MIN_POSITIVE) + { + // NaN, infinite (positive or negative), or negative zero (negative but its negative is less than the min positive number) + Ok(Length::ONE) + } else { + // The length is that of the first octets plus those needed for the exponent plus those needed for the mantissa + let (_sign, exponent, mantissa) = decode_f64(*self); + + let exponent_len = if exponent == 0 { + // Section 8.5.7.4: there must be at least one octet for exponent encoding + // But, if the exponent is zero, it'll be skipped, so we make sure force it to 1 + Length::ONE + } else { + let ebytes = exponent.to_be_bytes(); + Length::try_from(strip_leading_zeroes(&ebytes).len())? + }; + + let mantissa_len = if mantissa == 0 { + Length::ONE + } else { + let mbytes = mantissa.to_be_bytes(); + Length::try_from(strip_leading_zeroes(&mbytes).len())? + }; + + exponent_len + mantissa_len + Length::ONE + } + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + // Check if special value + // Encode zero first, if it's zero + // Special value from section 8.5.9 if non zero + if self.is_nan() + || self.is_infinite() + || (self.is_sign_negative() && -self < f64::MIN_POSITIVE) + || (self.is_sign_positive() && (*self) < f64::MIN_POSITIVE) + { + if self.is_sign_positive() && (*self) < f64::MIN_POSITIVE { + // Zero + return Ok(()); + } else if self.is_nan() { + // Not a number + writer.write_byte(0b0100_0010)?; + } else if self.is_infinite() { + if self.is_sign_negative() { + // Negative infinity + writer.write_byte(0b0100_0001)?; + } else { + // Plus infinity + writer.write_byte(0b0100_0000)?; + } + } else { + // Minus zero + writer.write_byte(0b0100_0011)?; + } + } else { + // Always use binary encoding, set bit 8 to 1 + let mut first_byte = 0b1000_0000; + + if self.is_sign_negative() { + // Section 8.5.7.1: set bit 7 to 1 if negative + first_byte |= 0b0100_0000; + } + + // Bits 6 and 5 are set to 0 to specify that binary encoding is used + // + // NOTE: the scaling factor is only used to align the implicit point of the mantissa. + // This is unnecessary in DER because the base is 2, and therefore necessarily aligned. + // Therefore, we do not modify the mantissa in anyway after this function call, which + // already adds the implicit one of the IEEE 754 representation. + let (_sign, exponent, mantissa) = decode_f64(*self); + + // Encode the exponent as two's complement on 16 bits and remove the bias + let exponent_bytes = exponent.to_be_bytes(); + let ebytes = strip_leading_zeroes(&exponent_bytes); + + match ebytes.len() { + 0 | 1 => {} + 2 => first_byte |= 0b0000_0001, + 3 => first_byte |= 0b0000_0010, + _ => { + // TODO: support multi octet exponent encoding? + return Err(Tag::Real.value_error()); + } + } + + writer.write_byte(first_byte)?; + + // Encode both bytes or just the last one, handled by encode_bytes directly + // Rust already encodes the data as two's complement, so no further processing is needed + writer.write(ebytes)?; + + // Now, encode the mantissa as unsigned binary number + let mantissa_bytes = mantissa.to_be_bytes(); + let mbytes = strip_leading_zeroes(&mantissa_bytes); + writer.write(mbytes)?; + } + + Ok(()) + } +} + +impl FixedTag for f64 { + const TAG: Tag = Tag::Real; +} + +/// Is the N-th bit 1 in the first octet? +/// NOTE: this function is zero indexed +pub(crate) fn is_nth_bit_one(bytes: &[u8]) -> bool { + if N < 8 { + bytes + .first() + .map(|byte| byte & (1 << N) != 0) + .unwrap_or(false) + } else { + false + } +} + +/// Convert bits M, N into a u8, in the first octet only +pub(crate) fn mnth_bits_to_u8(bytes: &[u8]) -> u8 { + let bit_m = is_nth_bit_one::(bytes); + let bit_n = is_nth_bit_one::(bytes); + (bit_m as u8) << 1 | bit_n as u8 +} + +/// Decode an f64 as its sign, exponent, and mantissa in u64 and in that order, using bit shifts and masks. +/// Note: this function **removes** the 1023 bias from the exponent and adds the implicit 1 +#[allow(clippy::cast_possible_truncation)] +pub(crate) fn decode_f64(f: f64) -> (u64, u64, u64) { + let bits = f.to_bits(); + let sign = bits >> 63; + let exponent = bits >> 52 & 0x7ff; + let exponent_bytes_no_bias = (exponent as i16 - 1023).to_be_bytes(); + let exponent_no_bias = u64::from_be_bytes([ + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + exponent_bytes_no_bias[0], + exponent_bytes_no_bias[1], + ]); + let mantissa = bits & 0xfffffffffffff; + (sign, exponent_no_bias, mantissa + 1) +} + +/// Encode an f64 from its sign, exponent (**without** the 1023 bias), and (mantissa - 1) using bit shifts as received by ASN1 +pub(crate) fn encode_f64(sign: u64, exponent: u64, mantissa: u64) -> f64 { + // Add the bias to the exponent + let exponent_with_bias = + (i16::from_be_bytes([exponent.to_be_bytes()[6], exponent.to_be_bytes()[7]]) + 1023) as u64; + let bits = sign << 63 | exponent_with_bias << 52 | (mantissa - 1); + f64::from_bits(bits) +} + +#[cfg(test)] +mod tests { + use crate::{Decode, Encode}; + + #[test] + fn decode_subnormal() { + assert!(f64::from_der(&[0x09, 0x01, 0b0100_0010]).unwrap().is_nan()); + let plus_infty = f64::from_der(&[0x09, 0x01, 0b0100_0000]).unwrap(); + assert!(plus_infty.is_infinite() && plus_infty.is_sign_positive()); + let neg_infty = f64::from_der(&[0x09, 0x01, 0b0100_0001]).unwrap(); + assert!(neg_infty.is_infinite() && neg_infty.is_sign_negative()); + let neg_zero = f64::from_der(&[0x09, 0x01, 0b0100_0011]).unwrap(); + assert!(neg_zero.is_sign_negative() && neg_zero.abs() < f64::EPSILON); + } + + #[test] + fn encode_subnormal() { + // All subnormal fit in three bytes + let mut buffer = [0u8; 3]; + assert_eq!( + &[0x09, 0x01, 0b0100_0010], + f64::NAN.encode_to_slice(&mut buffer).unwrap() + ); + assert_eq!( + &[0x09, 0x01, 0b0100_0000], + f64::INFINITY.encode_to_slice(&mut buffer).unwrap() + ); + assert_eq!( + &[0x09, 0x01, 0b0100_0001], + f64::NEG_INFINITY.encode_to_slice(&mut buffer).unwrap() + ); + assert_eq!( + &[0x09, 0x01, 0b0100_0011], + (-0.0_f64).encode_to_slice(&mut buffer).unwrap() + ); + } + + #[test] + fn encdec_normal() { + // The comments correspond to the decoded value from the ASN.1 playground when the bytes are inputed. + { + // rec1value R ::= 0 + let val = 0.0; + let expected = &[0x09, 0x0]; + let mut buffer = [0u8; 2]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec1value R ::= { mantissa 1, base 2, exponent 0 } + let val = 1.0; + let expected = &[0x09, 0x03, 0x80, 0x00, 0x01]; + let mut buffer = [0u8; 5]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec1value R ::= { mantissa -1, base 2, exponent 0 } + let val = -1.0; + let expected = &[0x09, 0x03, 0xc0, 0x00, 0x01]; + let mut buffer = [0u8; 5]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec1value R ::= { mantissa -1, base 2, exponent 1 } + let val = -1.0000000000000002; + let expected = &[0x09, 0x03, 0xc0, 0x00, 0x02]; + let mut buffer = [0u8; 5]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec1value R ::= { mantissa 1, base 2, exponent -1022 } + // NOTE: f64::MIN_EXP == -1021 so the exponent decoded by ASN.1 is what we expect + let val = f64::MIN_POSITIVE; + let expected = &[0x09, 0x04, 0x81, 0xfc, 0x02, 0x01]; + let mut buffer = [0u8; 7]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec4value R ::= { mantissa 1, base 2, exponent 3 } + let val = 1.0000000000000016; + let expected = &[0x09, 0x03, 0x80, 0x00, 0x08]; + let mut buffer = [0u8; 5]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec5value R ::= { mantissa 4222124650659841, base 2, exponent 4 } + let val = 31.0; + let expected = &[ + 0x9, 0x9, 0x80, 0x04, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + ]; + let mut buffer = [0u8; 11]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + } + + #[test] + fn encdec_irrationals() { + { + let val = core::f64::consts::PI; + let expected = &[ + 0x09, 0x09, 0x80, 0x01, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x19, + ]; + let mut buffer = [0u8; 11]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = core::f64::consts::E; + let expected = &[ + 0x09, 0x09, 0x80, 0x01, 0x05, 0xbf, 0x0a, 0x8b, 0x14, 0x57, 0x6a, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + { + let val = core::f64::consts::LN_2; + let expected = &[ + 0x09, 0x0a, 0x81, 0xff, 0xff, 0x6, 0x2e, 0x42, 0xfe, 0xfa, 0x39, 0xf0, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + } + + #[test] + fn encdec_reasonable_f64() { + // Tests the encoding and decoding of reals with some arbitrary numbers + { + // rec1value R ::= { mantissa 2414341043715239, base 2, exponent 21 } + let val = 3221417.1584163485; + let expected = &[ + 0x9, 0x9, 0x80, 0x15, 0x8, 0x93, 0xd4, 0x94, 0x46, 0xfc, 0xa7, + ]; + let mut buffer = [0u8; 11]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec1value R ::= { mantissa 2671155248072715, base 2, exponent 23 } + let val = 13364022.365665454; + let expected = &[ + 0x09, 0x09, 0x80, 0x17, 0x09, 0x7d, 0x66, 0xcb, 0xb3, 0x88, 0x0b, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec1value R ::= { mantissa -4386812962460287, base 2, exponent 14 } + let val = -32343.132588105735; + let expected = &[ + 0x09, 0x09, 0xc0, 0x0e, 0x0f, 0x95, 0xc8, 0x7c, 0x52, 0xd2, 0x7f, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = -27084.866751869475; + let expected = &[ + 0x09, 0x09, 0xc0, 0x0e, 0x0a, 0x73, 0x37, 0x78, 0xdc, 0xd5, 0x4a, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + // rec1value R ::= { mantissa -4372913134428149, base 2, exponent 7 } + let val = -252.28566647111404; + let expected = &[ + 0x09, 0x09, 0xc0, 0x07, 0x0f, 0x89, 0x24, 0x2e, 0x02, 0xdf, 0xf5, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = -14.399709612928548; + let expected = &[ + 0x09, 0x09, 0xc0, 0x03, 0x0c, 0xcc, 0xa6, 0xbd, 0x06, 0xd9, 0x92, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = -0.08340570261832964; + let expected = &[ + 0x09, 0x0a, 0xc1, 0xff, 0xfc, 0x05, 0x5a, 0x13, 0x7d, 0x0b, 0xae, 0x3d, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = 0.00536851453803701; + let expected = &[ + 0x09, 0x0a, 0x81, 0xff, 0xf8, 0x05, 0xfd, 0x4b, 0xa5, 0xe7, 0x4c, 0x93, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = 0.00045183525648866433; + let expected = &[ + 0x09, 0x0a, 0x81, 0xff, 0xf4, 0x0d, 0x9c, 0x89, 0xa6, 0x59, 0x33, 0x39, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = 0.000033869092002682955; + let expected = &[ + 0x09, 0x0a, 0x81, 0xff, 0xf1, 0x01, 0xc1, 0xd5, 0x23, 0xd5, 0x54, 0x7c, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = 0.0000011770891033600088; + let expected = &[ + 0x09, 0x0a, 0x81, 0xff, 0xec, 0x03, 0xbf, 0x8f, 0x27, 0xf4, 0x62, 0x56, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = 0.00000005549514041997082; + let expected = &[ + 0x09, 0x0a, 0x81, 0xff, 0xe7, 0x0d, 0xcb, 0x31, 0xab, 0x6e, 0xb8, 0xd7, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = 0.0000000012707044685547803; + let expected = &[ + 0x09, 0x0a, 0x81, 0xff, 0xe2, 0x05, 0xd4, 0x9e, 0x0a, 0xf2, 0xff, 0x1f, + ]; + let mut buffer = [0u8; 12]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + + { + let val = 0.00000000002969611878378562; + let expected = &[ + 0x09, 0x09, 0x81, 0xff, 0xdd, 0x53, 0x5b, 0x6f, 0x97, 0xee, 0xb6, + ]; + let mut buffer = [0u8; 11]; + let encoded = val.encode_to_slice(&mut buffer).unwrap(); + assert_eq!( + expected, encoded, + "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", + val, encoded, expected + ); + let decoded = f64::from_der(encoded).unwrap(); + assert!( + (decoded - val).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + val, + decoded + ); + } + } + + #[test] + fn reject_non_canonical() { + assert!(f64::from_der(&[0x09, 0x81, 0x00]).is_err()); + } + + #[test] + fn encdec_f64() { + use super::{decode_f64, encode_f64}; + // Test that the extraction and recreation works + for val in [ + 1.0, + 0.1, + -0.1, + -1.0, + 0.0, + f64::MIN_POSITIVE, + f64::MAX, + f64::MIN, + 3.1415, + 951.2357864, + -3.1415, + -951.2357864, + ] { + let (s, e, m) = decode_f64(val); + let val2 = encode_f64(s, e, m); + assert!( + (val - val2).abs() < f64::EPSILON, + "fail - want {}\tgot {}", + val, + val2 + ); + } + } + + #[test] + fn validation_cases() { + // Caveat: these test cases are validated on the ASN.1 playground: https://asn1.io/asn1playground/ . + // The test case consists in inputing the bytes in the "decode" field and checking that the decoded + // value corresponds to the one encoded here. + // This tool encodes _all_ values that are non-zero in the ISO 6093 NR3 representation. + // This does not seem to perfectly adhere to the ITU specifications, Special Cases section. + // The implementation of this crate correctly supports decoding such values. It will, however, + // systematically encode REALs in their base 2 form, with a scaling factor where needed to + // ensure that the mantissa is either odd or zero (as per section 11.3.1). + + // Positive trivial numbers + { + let expect = 10.0; + let testcase = &[0x09, 0x05, 0x03, 0x31, 0x2E, 0x45, 0x31]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = 100.0; + let testcase = &[0x09, 0x05, 0x03, 0x31, 0x2E, 0x45, 0x32]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = 101.0; + let testcase = &[0x09, 0x08, 0x03, 0x31, 0x30, 0x31, 0x2E, 0x45, 0x2B, 0x30]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = 101.0; + let testcase = &[0x09, 0x08, 0x03, 0x31, 0x30, 0x31, 0x2E, 0x45, 0x2B, 0x30]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = 0.0; + let testcase = &[0x09, 0x00]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = 951.2357864; + let testcase = &[ + 0x09, 0x0F, 0x03, 0x39, 0x35, 0x31, 0x32, 0x33, 0x35, 0x37, 0x38, 0x36, 0x34, 0x2E, + 0x45, 0x2D, 0x37, + ]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + // Negative trivial numbers + { + let expect = -10.0; + let testcase = &[0x09, 0x06, 0x03, 0x2D, 0x31, 0x2E, 0x45, 0x31]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = -100.0; + let testcase = &[0x09, 0x06, 0x03, 0x2D, 0x31, 0x2E, 0x45, 0x32]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = -101.0; + let testcase = &[ + 0x09, 0x09, 0x03, 0x2D, 0x31, 0x30, 0x31, 0x2E, 0x45, 0x2B, 0x30, + ]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = -0.5; + let testcase = &[0x09, 0x07, 0x03, 0x2D, 0x35, 0x2E, 0x45, 0x2D, 0x31]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + let expect = -0.0; + let testcase = &[0x09, 0x03, 0x01, 0x2D, 0x30]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + { + // Test NR3 decoding + let expect = -951.2357864; + let testcase = &[ + 0x09, 0x10, 0x03, 0x2D, 0x39, 0x35, 0x31, 0x32, 0x33, 0x35, 0x37, 0x38, 0x36, 0x34, + 0x2E, 0x45, 0x2D, 0x37, + ]; + let decoded = f64::from_der(testcase).unwrap(); + assert!( + (decoded - expect).abs() < f64::EPSILON, + "wanted: {}\tgot: {}", + expect, + decoded + ); + } + } +} diff --git a/src/rust/vendor/der/src/asn1/sequence.rs b/src/rust/vendor/der/src/asn1/sequence.rs new file mode 100644 index 000000000..ad4a5d52e --- /dev/null +++ b/src/rust/vendor/der/src/asn1/sequence.rs @@ -0,0 +1,53 @@ +//! The [`Sequence`] trait simplifies writing decoders/encoders which map ASN.1 +//! `SEQUENCE`s to Rust structs. + +use crate::{ + BytesRef, DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, Result, Tag, Writer, +}; + +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + +/// Marker trait for ASN.1 `SEQUENCE`s. +/// +/// This is mainly used for custom derive. +pub trait Sequence<'a>: DecodeValue<'a> + EncodeValue {} + +impl<'a, S> FixedTag for S +where + S: Sequence<'a>, +{ + const TAG: Tag = Tag::Sequence; +} + +#[cfg(feature = "alloc")] +impl<'a, T> Sequence<'a> for Box where T: Sequence<'a> {} + +/// The [`SequenceRef`] type provides raw access to the octets which comprise a +/// DER-encoded `SEQUENCE`. +/// +/// This is a zero-copy reference type which borrows from the input data. +pub struct SequenceRef<'a> { + /// Body of the `SEQUENCE`. + body: BytesRef<'a>, +} + +impl<'a> DecodeValue<'a> for SequenceRef<'a> { + fn decode_value>(reader: &mut R, header: Header) -> Result { + Ok(Self { + body: BytesRef::decode_value(reader, header)?, + }) + } +} + +impl EncodeValue for SequenceRef<'_> { + fn value_len(&self) -> Result { + Ok(self.body.len()) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + self.body.encode_value(writer) + } +} + +impl<'a> Sequence<'a> for SequenceRef<'a> {} diff --git a/src/rust/vendor/der/src/asn1/sequence_of.rs b/src/rust/vendor/der/src/asn1/sequence_of.rs new file mode 100644 index 000000000..befb0298f --- /dev/null +++ b/src/rust/vendor/der/src/asn1/sequence_of.rs @@ -0,0 +1,230 @@ +//! ASN.1 `SEQUENCE OF` support. + +use crate::{ + arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, DerOrd, Encode, EncodeValue, FixedTag, + Header, Length, Reader, Result, Tag, ValueOrd, Writer, +}; +use core::cmp::Ordering; + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +/// ASN.1 `SEQUENCE OF` backed by an array. +/// +/// This type implements an append-only `SEQUENCE OF` type which is stack-based +/// and does not depend on `alloc` support. +// TODO(tarcieri): use `ArrayVec` when/if it's merged into `core` +// See: https://github.com/rust-lang/rfcs/pull/2990 +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SequenceOf { + inner: ArrayVec, +} + +impl SequenceOf { + /// Create a new [`SequenceOf`]. + pub fn new() -> Self { + Self { + inner: ArrayVec::new(), + } + } + + /// Add an element to this [`SequenceOf`]. + pub fn add(&mut self, element: T) -> Result<()> { + self.inner.push(element) + } + + /// Get an element of this [`SequenceOf`]. + pub fn get(&self, index: usize) -> Option<&T> { + self.inner.get(index) + } + + /// Iterate over the elements in this [`SequenceOf`]. + pub fn iter(&self) -> SequenceOfIter<'_, T> { + SequenceOfIter { + inner: self.inner.iter(), + } + } + + /// Is this [`SequenceOf`] empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + /// Number of elements in this [`SequenceOf`]. + pub fn len(&self) -> usize { + self.inner.len() + } +} + +impl Default for SequenceOf { + fn default() -> Self { + Self::new() + } +} + +impl<'a, T, const N: usize> DecodeValue<'a> for SequenceOf +where + T: Decode<'a>, +{ + fn decode_value>(reader: &mut R, header: Header) -> Result { + reader.read_nested(header.length, |reader| { + let mut sequence_of = Self::new(); + + while !reader.is_finished() { + sequence_of.add(T::decode(reader)?)?; + } + + Ok(sequence_of) + }) + } +} + +impl EncodeValue for SequenceOf +where + T: Encode, +{ + fn value_len(&self) -> Result { + self.iter() + .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + for elem in self.iter() { + elem.encode(writer)?; + } + + Ok(()) + } +} + +impl FixedTag for SequenceOf { + const TAG: Tag = Tag::Sequence; +} + +impl ValueOrd for SequenceOf +where + T: DerOrd, +{ + fn value_cmp(&self, other: &Self) -> Result { + iter_cmp(self.iter(), other.iter()) + } +} + +/// Iterator over the elements of an [`SequenceOf`]. +#[derive(Clone, Debug)] +pub struct SequenceOfIter<'a, T> { + /// Inner iterator. + inner: arrayvec::Iter<'a, T>, +} + +impl<'a, T> Iterator for SequenceOfIter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { + self.inner.next() + } +} + +impl<'a, T> ExactSizeIterator for SequenceOfIter<'a, T> {} + +impl<'a, T, const N: usize> DecodeValue<'a> for [T; N] +where + T: Decode<'a>, +{ + fn decode_value>(reader: &mut R, header: Header) -> Result { + let sequence_of = SequenceOf::::decode_value(reader, header)?; + + // TODO(tarcieri): use `[T; N]::try_map` instead of `expect` when stable + if sequence_of.inner.len() == N { + Ok(sequence_of + .inner + .into_array() + .map(|elem| elem.expect("arrayvec length mismatch"))) + } else { + Err(Self::TAG.length_error()) + } + } +} + +impl EncodeValue for [T; N] +where + T: Encode, +{ + fn value_len(&self) -> Result { + self.iter() + .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + for elem in self { + elem.encode(writer)?; + } + + Ok(()) + } +} + +impl FixedTag for [T; N] { + const TAG: Tag = Tag::Sequence; +} + +impl ValueOrd for [T; N] +where + T: DerOrd, +{ + fn value_cmp(&self, other: &Self) -> Result { + iter_cmp(self.iter(), other.iter()) + } +} + +#[cfg(feature = "alloc")] +impl<'a, T> DecodeValue<'a> for Vec +where + T: Decode<'a>, +{ + fn decode_value>(reader: &mut R, header: Header) -> Result { + reader.read_nested(header.length, |reader| { + let mut sequence_of = Self::new(); + + while !reader.is_finished() { + sequence_of.push(T::decode(reader)?); + } + + Ok(sequence_of) + }) + } +} + +#[cfg(feature = "alloc")] +impl EncodeValue for Vec +where + T: Encode, +{ + fn value_len(&self) -> Result { + self.iter() + .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + for elem in self { + elem.encode(writer)?; + } + + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl FixedTag for Vec { + const TAG: Tag = Tag::Sequence; +} + +#[cfg(feature = "alloc")] +impl ValueOrd for Vec +where + T: DerOrd, +{ + fn value_cmp(&self, other: &Self) -> Result { + iter_cmp(self.iter(), other.iter()) + } +} diff --git a/src/rust/vendor/der/src/asn1/set_of.rs b/src/rust/vendor/der/src/asn1/set_of.rs new file mode 100644 index 000000000..ff0131242 --- /dev/null +++ b/src/rust/vendor/der/src/asn1/set_of.rs @@ -0,0 +1,539 @@ +//! ASN.1 `SET OF` support. +//! +//! # Ordering Notes +//! +//! Some DER serializer implementations fail to properly sort elements of a +//! `SET OF`. This is technically non-canonical, but occurs frequently +//! enough that most DER decoders tolerate it. Unfortunately because +//! of that, we must also follow suit. +//! +//! However, all types in this module sort elements of a set at decode-time, +//! ensuring they'll be in the proper order if reserialized. + +use crate::{ + arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, DerOrd, Encode, EncodeValue, Error, + ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd, Writer, +}; +use core::cmp::Ordering; + +#[cfg(feature = "alloc")] +use {alloc::vec::Vec, core::slice}; + +/// ASN.1 `SET OF` backed by an array. +/// +/// This type implements an append-only `SET OF` type which is stack-based +/// and does not depend on `alloc` support. +// TODO(tarcieri): use `ArrayVec` when/if it's merged into `core` +// See: https://github.com/rust-lang/rfcs/pull/2990 +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct SetOf +where + T: DerOrd, +{ + inner: ArrayVec, +} + +impl SetOf +where + T: DerOrd, +{ + /// Create a new [`SetOf`]. + pub fn new() -> Self { + Self { + inner: ArrayVec::default(), + } + } + + /// Add an item to this [`SetOf`]. + /// + /// Items MUST be added in lexicographical order according to the + /// [`DerOrd`] impl on `T`. + #[deprecated(since = "0.7.6", note = "use `insert` or `insert_ordered` instead")] + pub fn add(&mut self, new_elem: T) -> Result<()> { + self.insert_ordered(new_elem) + } + + /// Insert an item into this [`SetOf`]. + pub fn insert(&mut self, item: T) -> Result<()> { + self.inner.push(item)?; + der_sort(self.inner.as_mut()) + } + + /// Insert an item into this [`SetOf`]. + /// + /// Items MUST be added in lexicographical order according to the + /// [`DerOrd`] impl on `T`. + pub fn insert_ordered(&mut self, item: T) -> Result<()> { + // Ensure set elements are lexicographically ordered + if let Some(last) = self.inner.last() { + check_der_ordering(last, &item)?; + } + + self.inner.push(item) + } + + /// Get the nth element from this [`SetOf`]. + pub fn get(&self, index: usize) -> Option<&T> { + self.inner.get(index) + } + + /// Iterate over the elements of this [`SetOf`]. + pub fn iter(&self) -> SetOfIter<'_, T> { + SetOfIter { + inner: self.inner.iter(), + } + } + + /// Is this [`SetOf`] empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + /// Number of elements in this [`SetOf`]. + pub fn len(&self) -> usize { + self.inner.len() + } +} + +impl Default for SetOf +where + T: DerOrd, +{ + fn default() -> Self { + Self::new() + } +} + +impl<'a, T, const N: usize> DecodeValue<'a> for SetOf +where + T: Decode<'a> + DerOrd, +{ + fn decode_value>(reader: &mut R, header: Header) -> Result { + reader.read_nested(header.length, |reader| { + let mut result = Self::new(); + + while !reader.is_finished() { + result.inner.push(T::decode(reader)?)?; + } + + der_sort(result.inner.as_mut())?; + validate(result.inner.as_ref())?; + Ok(result) + }) + } +} + +impl<'a, T, const N: usize> EncodeValue for SetOf +where + T: 'a + Decode<'a> + Encode + DerOrd, +{ + fn value_len(&self) -> Result { + self.iter() + .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + for elem in self.iter() { + elem.encode(writer)?; + } + + Ok(()) + } +} + +impl<'a, T, const N: usize> FixedTag for SetOf +where + T: Decode<'a> + DerOrd, +{ + const TAG: Tag = Tag::Set; +} + +impl TryFrom<[T; N]> for SetOf +where + T: DerOrd, +{ + type Error = Error; + + fn try_from(mut arr: [T; N]) -> Result> { + der_sort(&mut arr)?; + + let mut result = SetOf::new(); + + for elem in arr { + result.insert_ordered(elem)?; + } + + Ok(result) + } +} + +impl ValueOrd for SetOf +where + T: DerOrd, +{ + fn value_cmp(&self, other: &Self) -> Result { + iter_cmp(self.iter(), other.iter()) + } +} + +/// Iterator over the elements of an [`SetOf`]. +#[derive(Clone, Debug)] +pub struct SetOfIter<'a, T> { + /// Inner iterator. + inner: arrayvec::Iter<'a, T>, +} + +impl<'a, T> Iterator for SetOfIter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { + self.inner.next() + } +} + +impl<'a, T> ExactSizeIterator for SetOfIter<'a, T> {} + +/// ASN.1 `SET OF` backed by a [`Vec`]. +/// +/// This type implements an append-only `SET OF` type which is heap-backed +/// and depends on `alloc` support. +#[cfg(feature = "alloc")] +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct SetOfVec +where + T: DerOrd, +{ + inner: Vec, +} + +#[cfg(feature = "alloc")] +impl Default for SetOfVec { + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} + +#[cfg(feature = "alloc")] +impl SetOfVec +where + T: DerOrd, +{ + /// Create a new [`SetOfVec`]. + pub fn new() -> Self { + Self { + inner: Vec::default(), + } + } + + /// Create a new [`SetOfVec`] from the given iterator. + /// + /// Note: this is an inherent method instead of an impl of the + /// [`FromIterator`] trait in order to be fallible. + #[allow(clippy::should_implement_trait)] + pub fn from_iter(iter: I) -> Result + where + I: IntoIterator, + { + Vec::from_iter(iter).try_into() + } + + /// Add an element to this [`SetOfVec`]. + /// + /// Items MUST be added in lexicographical order according to the + /// [`DerOrd`] impl on `T`. + #[deprecated(since = "0.7.6", note = "use `insert` or `insert_ordered` instead")] + pub fn add(&mut self, item: T) -> Result<()> { + self.insert_ordered(item) + } + + /// Extend a [`SetOfVec`] using an iterator. + /// + /// Note: this is an inherent method instead of an impl of the + /// [`Extend`] trait in order to be fallible. + pub fn extend(&mut self, iter: I) -> Result<()> + where + I: IntoIterator, + { + self.inner.extend(iter); + der_sort(&mut self.inner) + } + + /// Insert an item into this [`SetOfVec`]. Must be unique. + pub fn insert(&mut self, item: T) -> Result<()> { + self.inner.push(item); + der_sort(&mut self.inner) + } + + /// Insert an item into this [`SetOfVec`]. Must be unique. + /// + /// Items MUST be added in lexicographical order according to the + /// [`DerOrd`] impl on `T`. + pub fn insert_ordered(&mut self, item: T) -> Result<()> { + // Ensure set elements are lexicographically ordered + if let Some(last) = self.inner.last() { + check_der_ordering(last, &item)?; + } + + self.inner.push(item); + Ok(()) + } + + /// Borrow the elements of this [`SetOfVec`] as a slice. + pub fn as_slice(&self) -> &[T] { + self.inner.as_slice() + } + + /// Get the nth element from this [`SetOfVec`]. + pub fn get(&self, index: usize) -> Option<&T> { + self.inner.get(index) + } + + /// Convert this [`SetOfVec`] into the inner [`Vec`]. + pub fn into_vec(self) -> Vec { + self.inner + } + + /// Iterate over the elements of this [`SetOfVec`]. + pub fn iter(&self) -> slice::Iter<'_, T> { + self.inner.iter() + } + + /// Is this [`SetOfVec`] empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + /// Number of elements in this [`SetOfVec`]. + pub fn len(&self) -> usize { + self.inner.len() + } +} + +#[cfg(feature = "alloc")] +impl AsRef<[T]> for SetOfVec +where + T: DerOrd, +{ + fn as_ref(&self) -> &[T] { + self.as_slice() + } +} + +#[cfg(feature = "alloc")] +impl<'a, T> DecodeValue<'a> for SetOfVec +where + T: Decode<'a> + DerOrd, +{ + fn decode_value>(reader: &mut R, header: Header) -> Result { + reader.read_nested(header.length, |reader| { + let mut inner = Vec::new(); + + while !reader.is_finished() { + inner.push(T::decode(reader)?); + } + + der_sort(inner.as_mut())?; + validate(inner.as_ref())?; + Ok(Self { inner }) + }) + } +} + +#[cfg(feature = "alloc")] +impl<'a, T> EncodeValue for SetOfVec +where + T: 'a + Decode<'a> + Encode + DerOrd, +{ + fn value_len(&self) -> Result { + self.iter() + .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + for elem in self.iter() { + elem.encode(writer)?; + } + + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl FixedTag for SetOfVec +where + T: DerOrd, +{ + const TAG: Tag = Tag::Set; +} + +#[cfg(feature = "alloc")] +impl From> for Vec +where + T: DerOrd, +{ + fn from(set: SetOfVec) -> Vec { + set.into_vec() + } +} + +#[cfg(feature = "alloc")] +impl TryFrom> for SetOfVec +where + T: DerOrd, +{ + type Error = Error; + + fn try_from(mut vec: Vec) -> Result> { + der_sort(vec.as_mut_slice())?; + Ok(SetOfVec { inner: vec }) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<[T; N]> for SetOfVec +where + T: DerOrd, +{ + type Error = Error; + + fn try_from(arr: [T; N]) -> Result> { + Vec::from(arr).try_into() + } +} + +#[cfg(feature = "alloc")] +impl ValueOrd for SetOfVec +where + T: DerOrd, +{ + fn value_cmp(&self, other: &Self) -> Result { + iter_cmp(self.iter(), other.iter()) + } +} + +// Implement by hand because the derive would create invalid values. +// Use the conversion from Vec to create a valid value. +#[cfg(feature = "arbitrary")] +impl<'a, T> arbitrary::Arbitrary<'a> for SetOfVec +where + T: DerOrd + arbitrary::Arbitrary<'a>, +{ + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + Self::try_from( + u.arbitrary_iter()? + .collect::, _>>()?, + ) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } + + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} + +/// Ensure set elements are lexicographically ordered using [`DerOrd`]. +fn check_der_ordering(a: &T, b: &T) -> Result<()> { + match a.der_cmp(b)? { + Ordering::Less => Ok(()), + Ordering::Equal => Err(ErrorKind::SetDuplicate.into()), + Ordering::Greater => Err(ErrorKind::SetOrdering.into()), + } +} + +/// Sort a mut slice according to its [`DerOrd`], returning any errors which +/// might occur during the comparison. +/// +/// The algorithm is insertion sort, which should perform well when the input +/// is mostly sorted to begin with. +/// +/// This function is used rather than Rust's built-in `[T]::sort_by` in order +/// to support heapless `no_std` targets as well as to enable bubbling up +/// sorting errors. +#[allow(clippy::integer_arithmetic)] +fn der_sort(slice: &mut [T]) -> Result<()> { + for i in 0..slice.len() { + let mut j = i; + + while j > 0 { + match slice[j - 1].der_cmp(&slice[j])? { + Ordering::Less => break, + Ordering::Equal => return Err(ErrorKind::SetDuplicate.into()), + Ordering::Greater => { + slice.swap(j - 1, j); + j -= 1; + } + } + } + } + + Ok(()) +} + +/// Validate the elements of a `SET OF`, ensuring that they are all in order +/// and that there are no duplicates. +fn validate(slice: &[T]) -> Result<()> { + if let Some(len) = slice.len().checked_sub(1) { + for i in 0..len { + let j = i.checked_add(1).ok_or(ErrorKind::Overflow)?; + + match slice.get(i..=j) { + Some([a, b]) => { + if a.der_cmp(b)? != Ordering::Less { + return Err(ErrorKind::SetOrdering.into()); + } + } + _ => return Err(Tag::Set.value_error()), + } + } + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::SetOf; + #[cfg(feature = "alloc")] + use super::SetOfVec; + use crate::ErrorKind; + + #[test] + fn setof_tryfrom_array() { + let arr = [3u16, 2, 1, 65535, 0]; + let set = SetOf::try_from(arr).unwrap(); + assert!(set.iter().copied().eq([0, 1, 2, 3, 65535])); + } + + #[test] + fn setof_tryfrom_array_reject_duplicates() { + let arr = [1u16, 1]; + let err = SetOf::try_from(arr).err().unwrap(); + assert_eq!(err.kind(), ErrorKind::SetDuplicate); + } + + #[cfg(feature = "alloc")] + #[test] + fn setofvec_tryfrom_array() { + let arr = [3u16, 2, 1, 65535, 0]; + let set = SetOfVec::try_from(arr).unwrap(); + assert_eq!(set.as_ref(), &[0, 1, 2, 3, 65535]); + } + + #[cfg(feature = "alloc")] + #[test] + fn setofvec_tryfrom_vec() { + let vec = vec![3u16, 2, 1, 65535, 0]; + let set = SetOfVec::try_from(vec).unwrap(); + assert_eq!(set.as_ref(), &[0, 1, 2, 3, 65535]); + } + + #[cfg(feature = "alloc")] + #[test] + fn setofvec_tryfrom_vec_reject_duplicates() { + let vec = vec![1u16, 1]; + let err = SetOfVec::try_from(vec).err().unwrap(); + assert_eq!(err.kind(), ErrorKind::SetDuplicate); + } +} diff --git a/src/rust/vendor/der/src/asn1/teletex_string.rs b/src/rust/vendor/der/src/asn1/teletex_string.rs new file mode 100644 index 000000000..337c071e5 --- /dev/null +++ b/src/rust/vendor/der/src/asn1/teletex_string.rs @@ -0,0 +1,217 @@ +//! ASN.1 `TeletexString` support. +//! +use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag}; +use core::{fmt, ops::Deref}; + +macro_rules! impl_teletex_string { + ($type: ty) => { + impl_teletex_string!($type,); + }; + ($type: ty, $($li: lifetime)?) => { + impl_string_type!($type, $($li),*); + + impl<$($li),*> FixedTag for $type { + const TAG: Tag = Tag::TeletexString; + } + + impl<$($li),*> fmt::Debug for $type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "TeletexString({:?})", self.as_str()) + } + } + }; +} + +/// ASN.1 `TeletexString` type. +/// +/// Supports a subset the ASCII character set (described below). +/// +/// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead. +/// For the full ASCII character set, use +/// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`]. +/// +/// This is a zero-copy reference type which borrows from the input data. +/// +/// # Supported characters +/// +/// The standard defines a complex character set allowed in this type. However, quoting the ASN.1 +/// mailing list, "a sizable volume of software in the world treats TeletexString (T61String) as a +/// simple 8-bit string with mostly Windows Latin 1 (superset of iso-8859-1) encoding". +/// +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] +pub struct TeletexStringRef<'a> { + /// Inner value + inner: StrRef<'a>, +} + +impl<'a> TeletexStringRef<'a> { + /// Create a new ASN.1 `TeletexString`. + pub fn new(input: &'a T) -> Result + where + T: AsRef<[u8]> + ?Sized, + { + let input = input.as_ref(); + + // FIXME: support higher part of the charset + if input.iter().any(|&c| c > 0x7F) { + return Err(Self::TAG.value_error()); + } + + StrRef::from_bytes(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } +} + +impl_teletex_string!(TeletexStringRef<'a>, 'a); + +impl<'a> Deref for TeletexStringRef<'a> { + type Target = StrRef<'a>; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl<'a> From<&TeletexStringRef<'a>> for TeletexStringRef<'a> { + fn from(value: &TeletexStringRef<'a>) -> TeletexStringRef<'a> { + *value + } +} + +impl<'a> From> for AnyRef<'a> { + fn from(teletex_string: TeletexStringRef<'a>) -> AnyRef<'a> { + AnyRef::from_tag_and_value(Tag::TeletexString, teletex_string.inner.into()) + } +} + +#[cfg(feature = "alloc")] +pub use self::allocation::TeletexString; + +#[cfg(feature = "alloc")] +mod allocation { + use super::TeletexStringRef; + + use crate::{ + asn1::AnyRef, + referenced::{OwnedToRef, RefToOwned}, + BytesRef, Error, FixedTag, Result, StrOwned, Tag, + }; + use alloc::string::String; + use core::{fmt, ops::Deref}; + + /// ASN.1 `TeletexString` type. + /// + /// Supports a subset the ASCII character set (described below). + /// + /// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead. + /// For the full ASCII character set, use + /// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`]. + /// + /// # Supported characters + /// + /// The standard defines a complex character set allowed in this type. However, quoting the ASN.1 + /// mailing list, "a sizable volume of software in the world treats TeletexString (T61String) as a + /// simple 8-bit string with mostly Windows Latin 1 (superset of iso-8859-1) encoding". + /// + #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] + pub struct TeletexString { + /// Inner value + inner: StrOwned, + } + + impl TeletexString { + /// Create a new ASN.1 `TeletexString`. + pub fn new(input: &T) -> Result + where + T: AsRef<[u8]> + ?Sized, + { + let input = input.as_ref(); + + TeletexStringRef::new(input)?; + + StrOwned::from_bytes(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } + } + + impl_teletex_string!(TeletexString); + + impl Deref for TeletexString { + type Target = StrOwned; + + fn deref(&self) -> &Self::Target { + &self.inner + } + } + + impl<'a> From> for TeletexString { + fn from(value: TeletexStringRef<'a>) -> TeletexString { + let inner = + StrOwned::from_bytes(value.inner.as_bytes()).expect("Invalid TeletexString"); + Self { inner } + } + } + + impl<'a> From<&'a TeletexString> for AnyRef<'a> { + fn from(teletex_string: &'a TeletexString) -> AnyRef<'a> { + AnyRef::from_tag_and_value( + Tag::TeletexString, + BytesRef::new(teletex_string.inner.as_bytes()).expect("Invalid TeletexString"), + ) + } + } + + impl<'a> RefToOwned<'a> for TeletexStringRef<'a> { + type Owned = TeletexString; + fn ref_to_owned(&self) -> Self::Owned { + TeletexString { + inner: self.inner.ref_to_owned(), + } + } + } + + impl OwnedToRef for TeletexString { + type Borrowed<'a> = TeletexStringRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + TeletexStringRef { + inner: self.inner.owned_to_ref(), + } + } + } + + impl TryFrom for TeletexString { + type Error = Error; + + fn try_from(input: String) -> Result { + TeletexStringRef::new(&input)?; + + StrOwned::new(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } + } +} + +#[cfg(test)] +mod tests { + use super::TeletexStringRef; + use crate::Decode; + use crate::SliceWriter; + + #[test] + fn parse_bytes() { + let example_bytes = &[ + 0x14, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31, + ]; + + let teletex_string = TeletexStringRef::from_der(example_bytes).unwrap(); + assert_eq!(teletex_string.as_str(), "Test User 1"); + let mut out = [0_u8; 30]; + let mut writer = SliceWriter::new(&mut out); + writer.encode(&teletex_string).unwrap(); + let encoded = writer.finish().unwrap(); + assert_eq!(encoded, example_bytes); + } +} diff --git a/src/rust/vendor/der/src/asn1/utc_time.rs b/src/rust/vendor/der/src/asn1/utc_time.rs new file mode 100644 index 000000000..9f2f1713b --- /dev/null +++ b/src/rust/vendor/der/src/asn1/utc_time.rs @@ -0,0 +1,242 @@ +//! ASN.1 `UTCTime` support. + +use crate::{ + datetime::{self, DateTime}, + ord::OrdIsValueOrd, + DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, + Writer, +}; +use core::time::Duration; + +#[cfg(feature = "std")] +use std::time::SystemTime; + +/// ASN.1 `UTCTime` type. +/// +/// This type implements the validity requirements specified in +/// [RFC 5280 Section 4.1.2.5.1][1], namely: +/// +/// > For the purposes of this profile, UTCTime values MUST be expressed in +/// > Greenwich Mean Time (Zulu) and MUST include seconds (i.e., times are +/// > `YYMMDDHHMMSSZ`), even where the number of seconds is zero. Conforming +/// > systems MUST interpret the year field (`YY`) as follows: +/// > +/// > - Where `YY` is greater than or equal to 50, the year SHALL be +/// > interpreted as `19YY`; and +/// > - Where `YY` is less than 50, the year SHALL be interpreted as `20YY`. +/// +/// Note: Due to common operations working on `UNIX_EPOCH` [`UtcTime`]s are +/// only supported for the years 1970-2049. +/// +/// [1]: https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1 +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct UtcTime(DateTime); + +impl UtcTime { + /// Length of an RFC 5280-flavored ASN.1 DER-encoded [`UtcTime`]. + pub const LENGTH: usize = 13; + + /// Maximum year that can be represented as a `UTCTime`. + pub const MAX_YEAR: u16 = 2049; + + /// Create a [`UtcTime`] from a [`DateTime`]. + pub fn from_date_time(datetime: DateTime) -> Result { + if datetime.year() <= UtcTime::MAX_YEAR { + Ok(Self(datetime)) + } else { + Err(Self::TAG.value_error()) + } + } + + /// Convert this [`UtcTime`] into a [`DateTime`]. + pub fn to_date_time(&self) -> DateTime { + self.0 + } + + /// Create a new [`UtcTime`] given a [`Duration`] since `UNIX_EPOCH` + /// (a.k.a. "Unix time") + pub fn from_unix_duration(unix_duration: Duration) -> Result { + DateTime::from_unix_duration(unix_duration)?.try_into() + } + + /// Get the duration of this timestamp since `UNIX_EPOCH`. + pub fn to_unix_duration(&self) -> Duration { + self.0.unix_duration() + } + + /// Instantiate from [`SystemTime`]. + #[cfg(feature = "std")] + pub fn from_system_time(time: SystemTime) -> Result { + DateTime::try_from(time) + .map_err(|_| Self::TAG.value_error())? + .try_into() + } + + /// Convert to [`SystemTime`]. + #[cfg(feature = "std")] + pub fn to_system_time(&self) -> SystemTime { + self.0.to_system_time() + } +} + +impl_any_conversions!(UtcTime); + +impl<'a> DecodeValue<'a> for UtcTime { + fn decode_value>(reader: &mut R, header: Header) -> Result { + if Self::LENGTH != usize::try_from(header.length)? { + return Err(Self::TAG.value_error()); + } + + let mut bytes = [0u8; Self::LENGTH]; + reader.read_into(&mut bytes)?; + + match bytes { + // RFC 5280 requires mandatory seconds and Z-normalized time zone + [year1, year2, mon1, mon2, day1, day2, hour1, hour2, min1, min2, sec1, sec2, b'Z'] => { + let year = u16::from(datetime::decode_decimal(Self::TAG, year1, year2)?); + let month = datetime::decode_decimal(Self::TAG, mon1, mon2)?; + let day = datetime::decode_decimal(Self::TAG, day1, day2)?; + let hour = datetime::decode_decimal(Self::TAG, hour1, hour2)?; + let minute = datetime::decode_decimal(Self::TAG, min1, min2)?; + let second = datetime::decode_decimal(Self::TAG, sec1, sec2)?; + + // RFC 5280 rules for interpreting the year + let year = if year >= 50 { + year.checked_add(1900) + } else { + year.checked_add(2000) + } + .ok_or(ErrorKind::DateTime)?; + + DateTime::new(year, month, day, hour, minute, second) + .map_err(|_| Self::TAG.value_error()) + .and_then(|dt| Self::from_unix_duration(dt.unix_duration())) + } + _ => Err(Self::TAG.value_error()), + } + } +} + +impl EncodeValue for UtcTime { + fn value_len(&self) -> Result { + Self::LENGTH.try_into() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + let year = match self.0.year() { + y @ 1950..=1999 => y.checked_sub(1900), + y @ 2000..=2049 => y.checked_sub(2000), + _ => return Err(Self::TAG.value_error()), + } + .and_then(|y| u8::try_from(y).ok()) + .ok_or(ErrorKind::DateTime)?; + + datetime::encode_decimal(writer, Self::TAG, year)?; + datetime::encode_decimal(writer, Self::TAG, self.0.month())?; + datetime::encode_decimal(writer, Self::TAG, self.0.day())?; + datetime::encode_decimal(writer, Self::TAG, self.0.hour())?; + datetime::encode_decimal(writer, Self::TAG, self.0.minutes())?; + datetime::encode_decimal(writer, Self::TAG, self.0.seconds())?; + writer.write_byte(b'Z') + } +} + +impl FixedTag for UtcTime { + const TAG: Tag = Tag::UtcTime; +} + +impl OrdIsValueOrd for UtcTime {} + +impl From<&UtcTime> for UtcTime { + fn from(value: &UtcTime) -> UtcTime { + *value + } +} + +impl From for DateTime { + fn from(utc_time: UtcTime) -> DateTime { + utc_time.0 + } +} + +impl From<&UtcTime> for DateTime { + fn from(utc_time: &UtcTime) -> DateTime { + utc_time.0 + } +} + +impl TryFrom for UtcTime { + type Error = Error; + + fn try_from(datetime: DateTime) -> Result { + Self::from_date_time(datetime) + } +} + +impl TryFrom<&DateTime> for UtcTime { + type Error = Error; + + fn try_from(datetime: &DateTime) -> Result { + Self::from_date_time(*datetime) + } +} + +#[cfg(feature = "std")] +impl From for SystemTime { + fn from(utc_time: UtcTime) -> SystemTime { + utc_time.to_system_time() + } +} + +// Implement by hand because the derive would create invalid values. +// Use the conversion from DateTime to create a valid value. +// The DateTime type has a way bigger range of valid years than UtcTime, +// so the DateTime year is mapped into a valid range to throw away less inputs. +#[cfg(feature = "arbitrary")] +impl<'a> arbitrary::Arbitrary<'a> for UtcTime { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + const MIN_YEAR: u16 = 1970; + const VALID_YEAR_COUNT: u16 = UtcTime::MAX_YEAR - MIN_YEAR + 1; + const AVERAGE_SECONDS_IN_YEAR: u64 = 31_556_952; + + let datetime = DateTime::arbitrary(u)?; + let year = datetime.year(); + let duration = datetime.unix_duration(); + + // Clamp the year into a valid range to not throw away too much input + let valid_year = (year.saturating_sub(MIN_YEAR)) + .rem_euclid(VALID_YEAR_COUNT) + .saturating_add(MIN_YEAR); + let year_to_remove = year.saturating_sub(valid_year); + let valid_duration = duration + - Duration::from_secs( + u64::from(year_to_remove).saturating_mul(AVERAGE_SECONDS_IN_YEAR), + ); + + Self::from_date_time(DateTime::from_unix_duration(valid_duration).expect("supported range")) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } + + fn size_hint(depth: usize) -> (usize, Option) { + DateTime::size_hint(depth) + } +} + +#[cfg(test)] +mod tests { + use super::UtcTime; + use crate::{Decode, Encode, SliceWriter}; + use hex_literal::hex; + + #[test] + fn round_trip_vector() { + let example_bytes = hex!("17 0d 39 31 30 35 30 36 32 33 34 35 34 30 5a"); + let utc_time = UtcTime::from_der(&example_bytes).unwrap(); + assert_eq!(utc_time.to_unix_duration().as_secs(), 673573540); + + let mut buf = [0u8; 128]; + let mut encoder = SliceWriter::new(&mut buf); + utc_time.encode(&mut encoder).unwrap(); + assert_eq!(example_bytes, encoder.finish().unwrap()); + } +} diff --git a/src/rust/vendor/der/src/asn1/utf8_string.rs b/src/rust/vendor/der/src/asn1/utf8_string.rs new file mode 100644 index 000000000..6018750a0 --- /dev/null +++ b/src/rust/vendor/der/src/asn1/utf8_string.rs @@ -0,0 +1,164 @@ +//! ASN.1 `UTF8String` support. + +use crate::{ + asn1::AnyRef, ord::OrdIsValueOrd, EncodeValue, Error, FixedTag, Length, Result, StrRef, Tag, + Writer, +}; +use core::{fmt, ops::Deref, str}; + +#[cfg(feature = "alloc")] +use { + crate::{DecodeValue, Header, Reader}, + alloc::{borrow::ToOwned, string::String}, +}; + +/// ASN.1 `UTF8String` type. +/// +/// Supports the full UTF-8 encoding. +/// +/// Note that the [`Decode`][`crate::Decode`] and [`Encode`][`crate::Encode`] +/// traits are impl'd for Rust's [`str`][`prim@str`] primitive, which +/// decodes/encodes as a [`Utf8StringRef`]. +/// +/// You are free to use [`str`][`prim@str`] instead of this type, however it's +/// still provided for explicitness in cases where it might be ambiguous with +/// other ASN.1 string encodings such as +/// [`PrintableStringRef`][`crate::asn1::PrintableStringRef`]. +/// +/// This is a zero-copy reference type which borrows from the input data. +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] +pub struct Utf8StringRef<'a> { + /// Inner value + inner: StrRef<'a>, +} + +impl<'a> Utf8StringRef<'a> { + /// Create a new ASN.1 `UTF8String`. + pub fn new(input: &'a T) -> Result + where + T: AsRef<[u8]> + ?Sized, + { + StrRef::from_bytes(input.as_ref()).map(|inner| Self { inner }) + } +} + +impl_string_type!(Utf8StringRef<'a>, 'a); + +impl<'a> Deref for Utf8StringRef<'a> { + type Target = StrRef<'a>; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl FixedTag for Utf8StringRef<'_> { + const TAG: Tag = Tag::Utf8String; +} + +impl<'a> From<&Utf8StringRef<'a>> for Utf8StringRef<'a> { + fn from(value: &Utf8StringRef<'a>) -> Utf8StringRef<'a> { + *value + } +} + +impl<'a> From> for AnyRef<'a> { + fn from(utf_string: Utf8StringRef<'a>) -> AnyRef<'a> { + AnyRef::from_tag_and_value(Tag::Utf8String, utf_string.inner.into()) + } +} + +impl<'a> fmt::Debug for Utf8StringRef<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Utf8String({:?})", self.as_str()) + } +} + +impl<'a> TryFrom> for &'a str { + type Error = Error; + + fn try_from(any: AnyRef<'a>) -> Result<&'a str> { + Utf8StringRef::try_from(any).map(|s| s.as_str()) + } +} + +impl EncodeValue for str { + fn value_len(&self) -> Result { + Utf8StringRef::new(self)?.value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + Utf8StringRef::new(self)?.encode_value(writer) + } +} + +impl FixedTag for str { + const TAG: Tag = Tag::Utf8String; +} + +impl OrdIsValueOrd for str {} + +#[cfg(feature = "alloc")] +impl<'a> From> for String { + fn from(s: Utf8StringRef<'a>) -> String { + s.as_str().to_owned() + } +} + +#[cfg(feature = "alloc")] +impl<'a> TryFrom> for String { + type Error = Error; + + fn try_from(any: AnyRef<'a>) -> Result { + Utf8StringRef::try_from(any).map(|s| s.as_str().to_owned()) + } +} + +#[cfg(feature = "alloc")] +impl<'a> DecodeValue<'a> for String { + fn decode_value>(reader: &mut R, header: Header) -> Result { + Ok(String::from_utf8(reader.read_vec(header.length)?)?) + } +} + +#[cfg(feature = "alloc")] +impl EncodeValue for String { + fn value_len(&self) -> Result { + Utf8StringRef::new(self)?.value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + Utf8StringRef::new(self)?.encode_value(writer) + } +} + +#[cfg(feature = "alloc")] +impl FixedTag for String { + const TAG: Tag = Tag::Utf8String; +} + +#[cfg(feature = "alloc")] +impl OrdIsValueOrd for String {} + +#[cfg(test)] +mod tests { + use super::Utf8StringRef; + use crate::Decode; + + #[test] + fn parse_ascii_bytes() { + let example_bytes = &[ + 0x0c, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31, + ]; + + let utf8_string = Utf8StringRef::from_der(example_bytes).unwrap(); + assert_eq!(utf8_string.as_str(), "Test User 1"); + } + + #[test] + fn parse_utf8_bytes() { + let example_bytes = &[0x0c, 0x06, 0x48, 0x65, 0x6c, 0x6c, 0xc3, 0xb3]; + let utf8_string = Utf8StringRef::from_der(example_bytes).unwrap(); + assert_eq!(utf8_string.as_str(), "Helló"); + } +} diff --git a/src/rust/vendor/der/src/asn1/videotex_string.rs b/src/rust/vendor/der/src/asn1/videotex_string.rs new file mode 100644 index 000000000..55b1a49cf --- /dev/null +++ b/src/rust/vendor/der/src/asn1/videotex_string.rs @@ -0,0 +1,98 @@ +//! ASN.1 `VideotexString` support. + +use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag}; +use core::{fmt, ops::Deref}; + +/// ASN.1 `VideotexString` type. +/// +/// Supports a subset the ASCII character set (described below). +/// +/// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead. +/// For the full ASCII character set, use +/// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`]. +/// +/// This is a zero-copy reference type which borrows from the input data. +/// +/// # Supported characters +/// +/// For the practical purposes VideotexString is treated as IA5string, disallowing non-ASCII chars. +/// +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] +pub struct VideotexStringRef<'a> { + /// Inner value + inner: StrRef<'a>, +} + +impl<'a> VideotexStringRef<'a> { + /// Create a new ASN.1 `VideotexString`. + pub fn new(input: &'a T) -> Result + where + T: AsRef<[u8]> + ?Sized, + { + let input = input.as_ref(); + + // Validate all characters are within VideotexString's allowed set + // FIXME: treat as if it were IA5String + if input.iter().any(|&c| c > 0x7F) { + return Err(Self::TAG.value_error()); + } + + StrRef::from_bytes(input) + .map(|inner| Self { inner }) + .map_err(|_| Self::TAG.value_error()) + } +} + +impl_string_type!(VideotexStringRef<'a>, 'a); + +impl<'a> Deref for VideotexStringRef<'a> { + type Target = StrRef<'a>; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl FixedTag for VideotexStringRef<'_> { + const TAG: Tag = Tag::VideotexString; +} + +impl<'a> From<&VideotexStringRef<'a>> for VideotexStringRef<'a> { + fn from(value: &VideotexStringRef<'a>) -> VideotexStringRef<'a> { + *value + } +} + +impl<'a> From> for AnyRef<'a> { + fn from(printable_string: VideotexStringRef<'a>) -> AnyRef<'a> { + AnyRef::from_tag_and_value(Tag::VideotexString, printable_string.inner.into()) + } +} + +impl<'a> From> for &'a [u8] { + fn from(printable_string: VideotexStringRef<'a>) -> &'a [u8] { + printable_string.as_bytes() + } +} + +impl<'a> fmt::Debug for VideotexStringRef<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "VideotexString({:?})", self.as_str()) + } +} + +#[cfg(test)] +mod tests { + use super::VideotexStringRef; + use crate::Decode; + + #[test] + fn parse_bytes() { + let example_bytes = &[ + 0x15, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31, + ]; + + let printable_string = VideotexStringRef::from_der(example_bytes).unwrap(); + assert_eq!(printable_string.as_str(), "Test User 1"); + } +} diff --git a/src/rust/vendor/der/src/bytes_owned.rs b/src/rust/vendor/der/src/bytes_owned.rs new file mode 100644 index 000000000..b5e928e3b --- /dev/null +++ b/src/rust/vendor/der/src/bytes_owned.rs @@ -0,0 +1,162 @@ +//! Common handling for types backed by byte allocation with enforcement of a +//! library-level length limitation i.e. `Length::max()`. + +use crate::{ + referenced::OwnedToRef, BytesRef, DecodeValue, DerOrd, EncodeValue, Error, Header, Length, + Reader, Result, StrRef, Writer, +}; +use alloc::{boxed::Box, vec::Vec}; +use core::cmp::Ordering; + +/// Byte slice newtype which respects the `Length::max()` limit. +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub(crate) struct BytesOwned { + /// Precomputed `Length` (avoids possible panicking conversions) + length: Length, + + /// Inner value + inner: Box<[u8]>, +} + +impl BytesOwned { + /// Create a new [`BytesOwned`], ensuring that the provided `slice` value + /// is shorter than `Length::max()`. + pub fn new(data: impl Into>) -> Result { + let inner: Box<[u8]> = data.into(); + + Ok(Self { + length: Length::try_from(inner.len())?, + inner, + }) + } + + /// Borrow the inner byte slice + pub fn as_slice(&self) -> &[u8] { + &self.inner + } + + /// Get the [`Length`] of this [`BytesRef`] + pub fn len(&self) -> Length { + self.length + } + + /// Is this [`BytesOwned`] empty? + pub fn is_empty(&self) -> bool { + self.len() == Length::ZERO + } +} + +impl AsRef<[u8]> for BytesOwned { + fn as_ref(&self) -> &[u8] { + self.as_slice() + } +} + +impl<'a> DecodeValue<'a> for BytesOwned { + fn decode_value>(reader: &mut R, header: Header) -> Result { + reader.read_vec(header.length).and_then(Self::new) + } +} + +impl EncodeValue for BytesOwned { + fn value_len(&self) -> Result { + Ok(self.length) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.as_ref()) + } +} + +impl Default for BytesOwned { + fn default() -> Self { + Self { + length: Length::ZERO, + inner: Box::new([]), + } + } +} + +impl DerOrd for BytesOwned { + fn der_cmp(&self, other: &Self) -> Result { + Ok(self.as_slice().cmp(other.as_slice())) + } +} + +impl From for Box<[u8]> { + fn from(bytes: BytesOwned) -> Box<[u8]> { + bytes.inner + } +} + +impl From> for BytesOwned { + fn from(s: StrRef<'_>) -> BytesOwned { + let bytes = s.as_bytes(); + debug_assert_eq!(bytes.len(), usize::try_from(s.length).expect("overflow")); + + BytesOwned { + inner: Box::from(bytes), + length: s.length, + } + } +} + +impl OwnedToRef for BytesOwned { + type Borrowed<'a> = BytesRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + BytesRef { + length: self.length, + inner: self.inner.as_ref(), + } + } +} + +impl From> for BytesOwned { + fn from(s: BytesRef<'_>) -> BytesOwned { + BytesOwned { + length: s.length, + inner: Box::from(s.inner), + } + } +} + +impl TryFrom<&[u8]> for BytesOwned { + type Error = Error; + + fn try_from(bytes: &[u8]) -> Result { + Self::new(bytes) + } +} + +impl TryFrom> for BytesOwned { + type Error = Error; + + fn try_from(bytes: Box<[u8]>) -> Result { + Self::new(bytes) + } +} + +impl TryFrom> for BytesOwned { + type Error = Error; + + fn try_from(bytes: Vec) -> Result { + Self::new(bytes) + } +} + +// Implement by hand because the derive would create invalid values. +// Make sure the length and the inner.len matches. +#[cfg(feature = "arbitrary")] +impl<'a> arbitrary::Arbitrary<'a> for BytesOwned { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + let length = u.arbitrary()?; + Ok(Self { + length, + inner: Box::from(u.bytes(u32::from(length) as usize)?), + }) + } + + fn size_hint(depth: usize) -> (usize, Option) { + arbitrary::size_hint::and(Length::size_hint(depth), (0, None)) + } +} diff --git a/src/rust/vendor/der/src/bytes_ref.rs b/src/rust/vendor/der/src/bytes_ref.rs new file mode 100644 index 000000000..2cee4076e --- /dev/null +++ b/src/rust/vendor/der/src/bytes_ref.rs @@ -0,0 +1,152 @@ +//! Common handling for types backed by byte slices with enforcement of a +//! library-level length limitation i.e. `Length::max()`. + +use crate::{ + DecodeValue, DerOrd, EncodeValue, Error, Header, Length, Reader, Result, StrRef, Writer, +}; +use core::cmp::Ordering; + +#[cfg(feature = "alloc")] +use crate::StrOwned; + +/// Byte slice newtype which respects the `Length::max()` limit. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub(crate) struct BytesRef<'a> { + /// Precomputed `Length` (avoids possible panicking conversions) + pub length: Length, + + /// Inner value + pub inner: &'a [u8], +} + +impl<'a> BytesRef<'a> { + /// Constant value representing an empty byte slice. + pub const EMPTY: Self = Self { + length: Length::ZERO, + inner: &[], + }; + + /// Create a new [`BytesRef`], ensuring that the provided `slice` value + /// is shorter than `Length::max()`. + pub fn new(slice: &'a [u8]) -> Result { + Ok(Self { + length: Length::try_from(slice.len())?, + inner: slice, + }) + } + + /// Borrow the inner byte slice + pub fn as_slice(&self) -> &'a [u8] { + self.inner + } + + /// Get the [`Length`] of this [`BytesRef`] + pub fn len(self) -> Length { + self.length + } + + /// Is this [`BytesRef`] empty? + pub fn is_empty(self) -> bool { + self.len() == Length::ZERO + } +} + +impl AsRef<[u8]> for BytesRef<'_> { + fn as_ref(&self) -> &[u8] { + self.as_slice() + } +} + +impl<'a> DecodeValue<'a> for BytesRef<'a> { + fn decode_value>(reader: &mut R, header: Header) -> Result { + reader.read_slice(header.length).and_then(Self::new) + } +} + +impl EncodeValue for BytesRef<'_> { + fn value_len(&self) -> Result { + Ok(self.length) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.as_ref()) + } +} + +impl Default for BytesRef<'_> { + fn default() -> Self { + Self { + length: Length::ZERO, + inner: &[], + } + } +} + +impl DerOrd for BytesRef<'_> { + fn der_cmp(&self, other: &Self) -> Result { + Ok(self.as_slice().cmp(other.as_slice())) + } +} + +impl<'a> From> for BytesRef<'a> { + fn from(s: StrRef<'a>) -> BytesRef<'a> { + let bytes = s.as_bytes(); + debug_assert_eq!(bytes.len(), usize::try_from(s.length).expect("overflow")); + + BytesRef { + inner: bytes, + length: s.length, + } + } +} + +#[cfg(feature = "alloc")] +impl<'a> From<&'a StrOwned> for BytesRef<'a> { + fn from(s: &'a StrOwned) -> BytesRef<'a> { + let bytes = s.as_bytes(); + debug_assert_eq!(bytes.len(), usize::try_from(s.length).expect("overflow")); + + BytesRef { + inner: bytes, + length: s.length, + } + } +} + +impl<'a> TryFrom<&'a [u8]> for BytesRef<'a> { + type Error = Error; + + fn try_from(slice: &'a [u8]) -> Result { + Self::new(slice) + } +} + +// Implement by hand because the derive would create invalid values. +// Make sure the length and the inner.len matches. +#[cfg(feature = "arbitrary")] +impl<'a> arbitrary::Arbitrary<'a> for BytesRef<'a> { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + let length = u.arbitrary()?; + Ok(Self { + length, + inner: u.bytes(u32::from(length) as usize)?, + }) + } + + fn size_hint(depth: usize) -> (usize, Option) { + arbitrary::size_hint::and(Length::size_hint(depth), (0, None)) + } +} + +#[cfg(feature = "alloc")] +mod allocating { + use super::BytesRef; + use crate::{referenced::RefToOwned, BytesOwned}; + + impl<'a> RefToOwned<'a> for BytesRef<'a> { + type Owned = BytesOwned; + fn ref_to_owned(&self) -> Self::Owned { + BytesOwned::from(*self) + } + } +} diff --git a/src/rust/vendor/der/src/datetime.rs b/src/rust/vendor/der/src/datetime.rs new file mode 100644 index 000000000..fd09b6855 --- /dev/null +++ b/src/rust/vendor/der/src/datetime.rs @@ -0,0 +1,447 @@ +//! Date and time functionality shared between various ASN.1 types +//! (e.g. `GeneralizedTime`, `UTCTime`) + +// Adapted from the `humantime` crate. +// Copyright (c) 2016 The humantime Developers +// Released under the MIT OR Apache 2.0 licenses + +use crate::{Error, ErrorKind, Result, Tag, Writer}; +use core::{fmt, str::FromStr, time::Duration}; + +#[cfg(feature = "std")] +use std::time::{SystemTime, UNIX_EPOCH}; + +#[cfg(feature = "time")] +use time::PrimitiveDateTime; + +/// Minimum year allowed in [`DateTime`] values. +const MIN_YEAR: u16 = 1970; + +/// Maximum duration since `UNIX_EPOCH` which can be represented as a +/// [`DateTime`] (non-inclusive). +/// +/// This corresponds to: 9999-12-31T23:59:59Z +const MAX_UNIX_DURATION: Duration = Duration::from_secs(253_402_300_799); + +/// Date-and-time type shared by multiple ASN.1 types +/// (e.g. `GeneralizedTime`, `UTCTime`). +/// +/// Following conventions from RFC 5280, this type is always Z-normalized +/// (i.e. represents a UTC time). However, it isn't named "UTC time" in order +/// to prevent confusion with ASN.1 `UTCTime`. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct DateTime { + /// Full year (e.g. 2000). + /// + /// Must be >=1970 to permit positive conversions to Unix time. + year: u16, + + /// Month (1-12) + month: u8, + + /// Day of the month (1-31) + day: u8, + + /// Hour (0-23) + hour: u8, + + /// Minutes (0-59) + minutes: u8, + + /// Seconds (0-59) + seconds: u8, + + /// [`Duration`] since the Unix epoch. + unix_duration: Duration, +} + +impl DateTime { + /// This is the maximum date represented by the [`DateTime`] + /// This corresponds to: 9999-12-31T23:59:59Z + pub const INFINITY: DateTime = DateTime { + year: 9999, + month: 12, + day: 31, + hour: 23, + minutes: 59, + seconds: 59, + unix_duration: MAX_UNIX_DURATION, + }; + + /// Create a new [`DateTime`] from the given UTC time components. + // TODO(tarcieri): checked arithmetic + #[allow(clippy::integer_arithmetic)] + pub fn new(year: u16, month: u8, day: u8, hour: u8, minutes: u8, seconds: u8) -> Result { + // Basic validation of the components. + if year < MIN_YEAR + || !(1..=12).contains(&month) + || !(1..=31).contains(&day) + || !(0..=23).contains(&hour) + || !(0..=59).contains(&minutes) + || !(0..=59).contains(&seconds) + { + return Err(ErrorKind::DateTime.into()); + } + + let leap_years = + ((year - 1) - 1968) / 4 - ((year - 1) - 1900) / 100 + ((year - 1) - 1600) / 400; + + let is_leap_year = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); + + let (mut ydays, mdays): (u16, u8) = match month { + 1 => (0, 31), + 2 if is_leap_year => (31, 29), + 2 => (31, 28), + 3 => (59, 31), + 4 => (90, 30), + 5 => (120, 31), + 6 => (151, 30), + 7 => (181, 31), + 8 => (212, 31), + 9 => (243, 30), + 10 => (273, 31), + 11 => (304, 30), + 12 => (334, 31), + _ => return Err(ErrorKind::DateTime.into()), + }; + + if day > mdays || day == 0 { + return Err(ErrorKind::DateTime.into()); + } + + ydays += u16::from(day) - 1; + + if is_leap_year && month > 2 { + ydays += 1; + } + + let days = u64::from(year - 1970) * 365 + u64::from(leap_years) + u64::from(ydays); + let time = u64::from(seconds) + (u64::from(minutes) * 60) + (u64::from(hour) * 3600); + let unix_duration = Duration::from_secs(time + days * 86400); + + if unix_duration > MAX_UNIX_DURATION { + return Err(ErrorKind::DateTime.into()); + } + + Ok(Self { + year, + month, + day, + hour, + minutes, + seconds, + unix_duration, + }) + } + + /// Compute a [`DateTime`] from the given [`Duration`] since the `UNIX_EPOCH`. + /// + /// Returns `None` if the value is outside the supported date range. + // TODO(tarcieri): checked arithmetic + #[allow(clippy::integer_arithmetic)] + pub fn from_unix_duration(unix_duration: Duration) -> Result { + if unix_duration > MAX_UNIX_DURATION { + return Err(ErrorKind::DateTime.into()); + } + + let secs_since_epoch = unix_duration.as_secs(); + + /// 2000-03-01 (mod 400 year, immediately after Feb 29) + const LEAPOCH: i64 = 11017; + const DAYS_PER_400Y: i64 = 365 * 400 + 97; + const DAYS_PER_100Y: i64 = 365 * 100 + 24; + const DAYS_PER_4Y: i64 = 365 * 4 + 1; + + let days = i64::try_from(secs_since_epoch / 86400)? - LEAPOCH; + let secs_of_day = secs_since_epoch % 86400; + + let mut qc_cycles = days / DAYS_PER_400Y; + let mut remdays = days % DAYS_PER_400Y; + + if remdays < 0 { + remdays += DAYS_PER_400Y; + qc_cycles -= 1; + } + + let mut c_cycles = remdays / DAYS_PER_100Y; + if c_cycles == 4 { + c_cycles -= 1; + } + remdays -= c_cycles * DAYS_PER_100Y; + + let mut q_cycles = remdays / DAYS_PER_4Y; + if q_cycles == 25 { + q_cycles -= 1; + } + remdays -= q_cycles * DAYS_PER_4Y; + + let mut remyears = remdays / 365; + if remyears == 4 { + remyears -= 1; + } + remdays -= remyears * 365; + + let mut year = 2000 + remyears + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles; + + let months = [31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29]; + let mut mon = 0; + for mon_len in months.iter() { + mon += 1; + if remdays < *mon_len { + break; + } + remdays -= *mon_len; + } + let mday = remdays + 1; + let mon = if mon + 2 > 12 { + year += 1; + mon - 10 + } else { + mon + 2 + }; + + let second = secs_of_day % 60; + let mins_of_day = secs_of_day / 60; + let minute = mins_of_day % 60; + let hour = mins_of_day / 60; + + Self::new( + year.try_into()?, + mon, + mday.try_into()?, + hour.try_into()?, + minute.try_into()?, + second.try_into()?, + ) + } + + /// Get the year. + pub fn year(&self) -> u16 { + self.year + } + + /// Get the month. + pub fn month(&self) -> u8 { + self.month + } + + /// Get the day. + pub fn day(&self) -> u8 { + self.day + } + + /// Get the hour. + pub fn hour(&self) -> u8 { + self.hour + } + + /// Get the minutes. + pub fn minutes(&self) -> u8 { + self.minutes + } + + /// Get the seconds. + pub fn seconds(&self) -> u8 { + self.seconds + } + + /// Compute [`Duration`] since `UNIX_EPOCH` from the given calendar date. + pub fn unix_duration(&self) -> Duration { + self.unix_duration + } + + /// Instantiate from [`SystemTime`]. + #[cfg(feature = "std")] + pub fn from_system_time(time: SystemTime) -> Result { + time.duration_since(UNIX_EPOCH) + .map_err(|_| ErrorKind::DateTime.into()) + .and_then(Self::from_unix_duration) + } + + /// Convert to [`SystemTime`]. + #[cfg(feature = "std")] + pub fn to_system_time(&self) -> SystemTime { + UNIX_EPOCH + self.unix_duration() + } +} + +impl FromStr for DateTime { + type Err = Error; + + fn from_str(s: &str) -> Result { + match *s.as_bytes() { + [year1, year2, year3, year4, b'-', month1, month2, b'-', day1, day2, b'T', hour1, hour2, b':', min1, min2, b':', sec1, sec2, b'Z'] => + { + let tag = Tag::GeneralizedTime; + let year = decode_year(&[year1, year2, year3, year4])?; + let month = decode_decimal(tag, month1, month2).map_err(|_| ErrorKind::DateTime)?; + let day = decode_decimal(tag, day1, day2).map_err(|_| ErrorKind::DateTime)?; + let hour = decode_decimal(tag, hour1, hour2).map_err(|_| ErrorKind::DateTime)?; + let minutes = decode_decimal(tag, min1, min2).map_err(|_| ErrorKind::DateTime)?; + let seconds = decode_decimal(tag, sec1, sec2).map_err(|_| ErrorKind::DateTime)?; + Self::new(year, month, day, hour, minutes, seconds) + } + _ => Err(ErrorKind::DateTime.into()), + } + } +} + +impl fmt::Display for DateTime { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{:02}-{:02}-{:02}T{:02}:{:02}:{:02}Z", + self.year, self.month, self.day, self.hour, self.minutes, self.seconds + ) + } +} + +#[cfg(feature = "std")] +impl From for SystemTime { + fn from(time: DateTime) -> SystemTime { + time.to_system_time() + } +} + +#[cfg(feature = "std")] +impl From<&DateTime> for SystemTime { + fn from(time: &DateTime) -> SystemTime { + time.to_system_time() + } +} + +#[cfg(feature = "std")] +impl TryFrom for DateTime { + type Error = Error; + + fn try_from(time: SystemTime) -> Result { + DateTime::from_system_time(time) + } +} + +#[cfg(feature = "std")] +impl TryFrom<&SystemTime> for DateTime { + type Error = Error; + + fn try_from(time: &SystemTime) -> Result { + DateTime::from_system_time(*time) + } +} + +#[cfg(feature = "time")] +impl TryFrom for PrimitiveDateTime { + type Error = Error; + + fn try_from(time: DateTime) -> Result { + let month = time.month().try_into()?; + let date = time::Date::from_calendar_date(i32::from(time.year()), month, time.day())?; + let time = time::Time::from_hms(time.hour(), time.minutes(), time.seconds())?; + + Ok(PrimitiveDateTime::new(date, time)) + } +} + +#[cfg(feature = "time")] +impl TryFrom for DateTime { + type Error = Error; + + fn try_from(time: PrimitiveDateTime) -> Result { + DateTime::new( + time.year().try_into().map_err(|_| ErrorKind::DateTime)?, + time.month().into(), + time.day(), + time.hour(), + time.minute(), + time.second(), + ) + } +} + +// Implement by hand because the derive would create invalid values. +// Use the conversion from Duration to create a valid value. +#[cfg(feature = "arbitrary")] +impl<'a> arbitrary::Arbitrary<'a> for DateTime { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + Self::from_unix_duration(Duration::new( + u.int_in_range(0..=MAX_UNIX_DURATION.as_secs().saturating_sub(1))?, + u.int_in_range(0..=999_999_999)?, + )) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } + + fn size_hint(depth: usize) -> (usize, Option) { + arbitrary::size_hint::and(u64::size_hint(depth), u32::size_hint(depth)) + } +} + +/// Decode 2-digit decimal value +// TODO(tarcieri): checked arithmetic +#[allow(clippy::integer_arithmetic)] +pub(crate) fn decode_decimal(tag: Tag, hi: u8, lo: u8) -> Result { + if hi.is_ascii_digit() && lo.is_ascii_digit() { + Ok((hi - b'0') * 10 + (lo - b'0')) + } else { + Err(tag.value_error()) + } +} + +/// Encode 2-digit decimal value +pub(crate) fn encode_decimal(writer: &mut W, tag: Tag, value: u8) -> Result<()> +where + W: Writer + ?Sized, +{ + let hi_val = value / 10; + + if hi_val >= 10 { + return Err(tag.value_error()); + } + + writer.write_byte(b'0'.checked_add(hi_val).ok_or(ErrorKind::Overflow)?)?; + writer.write_byte(b'0'.checked_add(value % 10).ok_or(ErrorKind::Overflow)?) +} + +/// Decode 4-digit year. +// TODO(tarcieri): checked arithmetic +#[allow(clippy::integer_arithmetic)] +fn decode_year(year: &[u8; 4]) -> Result { + let tag = Tag::GeneralizedTime; + let hi = decode_decimal(tag, year[0], year[1]).map_err(|_| ErrorKind::DateTime)?; + let lo = decode_decimal(tag, year[2], year[3]).map_err(|_| ErrorKind::DateTime)?; + Ok(u16::from(hi) * 100 + u16::from(lo)) +} + +#[cfg(test)] +mod tests { + use super::DateTime; + + /// Ensure a day is OK + fn is_date_valid(year: u16, month: u8, day: u8, hour: u8, minute: u8, second: u8) -> bool { + DateTime::new(year, month, day, hour, minute, second).is_ok() + } + + #[test] + fn feb_leap_year_handling() { + assert!(is_date_valid(2000, 2, 29, 0, 0, 0)); + assert!(!is_date_valid(2001, 2, 29, 0, 0, 0)); + assert!(!is_date_valid(2100, 2, 29, 0, 0, 0)); + } + + #[test] + fn from_str() { + let datetime = "2001-01-02T12:13:14Z".parse::().unwrap(); + assert_eq!(datetime.year(), 2001); + assert_eq!(datetime.month(), 1); + assert_eq!(datetime.day(), 2); + assert_eq!(datetime.hour(), 12); + assert_eq!(datetime.minutes(), 13); + assert_eq!(datetime.seconds(), 14); + } + + #[cfg(feature = "alloc")] + #[test] + fn display() { + use alloc::string::ToString; + let datetime = DateTime::new(2001, 01, 02, 12, 13, 14).unwrap(); + assert_eq!(&datetime.to_string(), "2001-01-02T12:13:14Z"); + } +} diff --git a/src/rust/vendor/der/src/decode.rs b/src/rust/vendor/der/src/decode.rs new file mode 100644 index 000000000..fe53341b3 --- /dev/null +++ b/src/rust/vendor/der/src/decode.rs @@ -0,0 +1,99 @@ +//! Trait definition for [`Decode`]. + +use crate::{FixedTag, Header, Reader, Result, SliceReader}; +use core::marker::PhantomData; + +#[cfg(feature = "pem")] +use crate::{pem::PemLabel, PemReader}; + +#[cfg(doc)] +use crate::{Length, Tag}; + +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + +/// Decoding trait. +/// +/// This trait provides the core abstraction upon which all decoding operations +/// are based. +pub trait Decode<'a>: Sized { + /// Attempt to decode this message using the provided decoder. + fn decode>(decoder: &mut R) -> Result; + + /// Parse `Self` from the provided DER-encoded byte slice. + fn from_der(bytes: &'a [u8]) -> Result { + let mut reader = SliceReader::new(bytes)?; + let result = Self::decode(&mut reader)?; + reader.finish(result) + } +} + +impl<'a, T> Decode<'a> for T +where + T: DecodeValue<'a> + FixedTag, +{ + fn decode>(reader: &mut R) -> Result { + let header = Header::decode(reader)?; + header.tag.assert_eq(T::TAG)?; + T::decode_value(reader, header) + } +} + +/// Dummy implementation for [`PhantomData`] which allows deriving +/// implementations on structs with phantom fields. +impl<'a, T> Decode<'a> for PhantomData +where + T: ?Sized, +{ + fn decode>(_reader: &mut R) -> Result> { + Ok(PhantomData) + } +} + +/// Marker trait for data structures that can be decoded from DER without +/// borrowing any data from the decoder. +/// +/// This is primarily useful for trait bounds on functions which require that +/// no data is borrowed from the decoder, for example a PEM decoder which needs +/// to first decode data from Base64. +/// +/// This trait is inspired by the [`DeserializeOwned` trait from `serde`](https://docs.rs/serde/latest/serde/de/trait.DeserializeOwned.html). +pub trait DecodeOwned: for<'a> Decode<'a> {} + +impl DecodeOwned for T where T: for<'a> Decode<'a> {} + +/// PEM decoding trait. +/// +/// This trait is automatically impl'd for any type which impls both +/// [`DecodeOwned`] and [`PemLabel`]. +#[cfg(feature = "pem")] +pub trait DecodePem: DecodeOwned + PemLabel { + /// Try to decode this type from PEM. + fn from_pem(pem: impl AsRef<[u8]>) -> Result; +} + +#[cfg(feature = "pem")] +impl DecodePem for T { + fn from_pem(pem: impl AsRef<[u8]>) -> Result { + let mut reader = PemReader::new(pem.as_ref())?; + Self::validate_pem_label(reader.type_label())?; + T::decode(&mut reader) + } +} + +/// Decode the value part of a Tag-Length-Value encoded field, sans the [`Tag`] +/// and [`Length`]. +pub trait DecodeValue<'a>: Sized { + /// Attempt to decode this message using the provided [`Reader`]. + fn decode_value>(reader: &mut R, header: Header) -> Result; +} + +#[cfg(feature = "alloc")] +impl<'a, T> DecodeValue<'a> for Box +where + T: DecodeValue<'a>, +{ + fn decode_value>(reader: &mut R, header: Header) -> Result { + Ok(Box::new(T::decode_value(reader, header)?)) + } +} diff --git a/src/rust/vendor/der/src/document.rs b/src/rust/vendor/der/src/document.rs new file mode 100644 index 000000000..78355a67a --- /dev/null +++ b/src/rust/vendor/der/src/document.rs @@ -0,0 +1,354 @@ +//! ASN.1 DER-encoded documents stored on the heap. + +use crate::{Decode, Encode, Error, FixedTag, Length, Reader, Result, SliceReader, Tag, Writer}; +use alloc::vec::Vec; +use core::fmt::{self, Debug}; + +#[cfg(feature = "pem")] +use {crate::pem, alloc::string::String}; + +#[cfg(feature = "std")] +use std::{fs, path::Path}; + +#[cfg(all(feature = "pem", feature = "std"))] +use alloc::borrow::ToOwned; + +#[cfg(feature = "zeroize")] +use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing}; + +/// ASN.1 DER-encoded document. +/// +/// This type wraps an encoded ASN.1 DER message. The document checked to +/// ensure it contains a valid DER-encoded `SEQUENCE`. +/// +/// It implements common functionality related to encoding/decoding such +/// documents, such as PEM encapsulation as well as reading/writing documents +/// from/to the filesystem. +/// +/// The [`SecretDocument`] provides a wrapper for this type with additional +/// hardening applied. +#[derive(Clone, Eq, PartialEq)] +pub struct Document { + /// ASN.1 DER encoded bytes. + der_bytes: Vec, + + /// Length of this document. + length: Length, +} + +impl Document { + /// Get the ASN.1 DER-encoded bytes of this document. + pub fn as_bytes(&self) -> &[u8] { + self.der_bytes.as_slice() + } + + /// Convert to a [`SecretDocument`]. + #[cfg(feature = "zeroize")] + pub fn into_secret(self) -> SecretDocument { + SecretDocument(self) + } + + /// Convert to an ASN.1 DER-encoded byte vector. + pub fn into_vec(self) -> Vec { + self.der_bytes + } + + /// Return an ASN.1 DER-encoded byte vector. + pub fn to_vec(&self) -> Vec { + self.der_bytes.clone() + } + + /// Get the length of the encoded ASN.1 DER in bytes. + pub fn len(&self) -> Length { + self.length + } + + /// Try to decode the inner ASN.1 DER message contained in this + /// [`Document`] as the given type. + pub fn decode_msg<'a, T: Decode<'a>>(&'a self) -> Result { + T::from_der(self.as_bytes()) + } + + /// Encode the provided type as ASN.1 DER, storing the resulting encoded DER + /// as a [`Document`]. + pub fn encode_msg(msg: &T) -> Result { + msg.to_der()?.try_into() + } + + /// Decode ASN.1 DER document from PEM. + /// + /// Returns the PEM label and decoded [`Document`] on success. + #[cfg(feature = "pem")] + pub fn from_pem(pem: &str) -> Result<(&str, Self)> { + let (label, der_bytes) = pem::decode_vec(pem.as_bytes())?; + Ok((label, der_bytes.try_into()?)) + } + + /// Encode ASN.1 DER document as a PEM string with encapsulation boundaries + /// containing the provided PEM type `label` (e.g. `CERTIFICATE`). + #[cfg(feature = "pem")] + pub fn to_pem(&self, label: &'static str, line_ending: pem::LineEnding) -> Result { + Ok(pem::encode_string(label, line_ending, self.as_bytes())?) + } + + /// Read ASN.1 DER document from a file. + #[cfg(feature = "std")] + pub fn read_der_file(path: impl AsRef) -> Result { + fs::read(path)?.try_into() + } + + /// Write ASN.1 DER document to a file. + #[cfg(feature = "std")] + pub fn write_der_file(&self, path: impl AsRef) -> Result<()> { + Ok(fs::write(path, self.as_bytes())?) + } + + /// Read PEM-encoded ASN.1 DER document from a file. + #[cfg(all(feature = "pem", feature = "std"))] + pub fn read_pem_file(path: impl AsRef) -> Result<(String, Self)> { + Self::from_pem(&fs::read_to_string(path)?).map(|(label, doc)| (label.to_owned(), doc)) + } + + /// Write PEM-encoded ASN.1 DER document to a file. + #[cfg(all(feature = "pem", feature = "std"))] + pub fn write_pem_file( + &self, + path: impl AsRef, + label: &'static str, + line_ending: pem::LineEnding, + ) -> Result<()> { + let pem = self.to_pem(label, line_ending)?; + Ok(fs::write(path, pem.as_bytes())?) + } +} + +impl AsRef<[u8]> for Document { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl Debug for Document { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Document(")?; + + for byte in self.as_bytes() { + write!(f, "{:02X}", byte)?; + } + + f.write_str(")") + } +} + +impl<'a> Decode<'a> for Document { + fn decode>(reader: &mut R) -> Result { + let header = reader.peek_header()?; + let length = (header.encoded_len()? + header.length)?; + let bytes = reader.read_slice(length)?; + + Ok(Self { + der_bytes: bytes.into(), + length, + }) + } +} + +impl Encode for Document { + fn encoded_len(&self) -> Result { + Ok(self.len()) + } + + fn encode(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.as_bytes()) + } +} + +impl FixedTag for Document { + const TAG: Tag = Tag::Sequence; +} + +impl TryFrom<&[u8]> for Document { + type Error = Error; + + fn try_from(der_bytes: &[u8]) -> Result { + Self::from_der(der_bytes) + } +} + +impl TryFrom> for Document { + type Error = Error; + + fn try_from(der_bytes: Vec) -> Result { + let mut decoder = SliceReader::new(&der_bytes)?; + decode_sequence(&mut decoder)?; + decoder.finish(())?; + + let length = der_bytes.len().try_into()?; + Ok(Self { der_bytes, length }) + } +} + +/// Secret [`Document`] type. +/// +/// Useful for formats which represent potentially secret data, such as +/// cryptographic keys. +/// +/// This type provides additional hardening such as ensuring that the contents +/// are zeroized-on-drop, and also using more restrictive file permissions when +/// writing files to disk. +#[cfg(feature = "zeroize")] +#[derive(Clone)] +pub struct SecretDocument(Document); + +#[cfg(feature = "zeroize")] +impl SecretDocument { + /// Borrow the inner serialized bytes of this document. + pub fn as_bytes(&self) -> &[u8] { + self.0.as_bytes() + } + + /// Return an allocated ASN.1 DER serialization as a byte vector. + pub fn to_bytes(&self) -> Zeroizing> { + Zeroizing::new(self.0.to_vec()) + } + + /// Get the length of the encoded ASN.1 DER in bytes. + pub fn len(&self) -> Length { + self.0.len() + } + + /// Try to decode the inner ASN.1 DER message as the given type. + pub fn decode_msg<'a, T: Decode<'a>>(&'a self) -> Result { + self.0.decode_msg() + } + + /// Encode the provided type as ASN.1 DER. + pub fn encode_msg(msg: &T) -> Result { + Document::encode_msg(msg).map(Self) + } + + /// Decode ASN.1 DER document from PEM. + #[cfg(feature = "pem")] + pub fn from_pem(pem: &str) -> Result<(&str, Self)> { + Document::from_pem(pem).map(|(label, doc)| (label, Self(doc))) + } + + /// Encode ASN.1 DER document as a PEM string. + #[cfg(feature = "pem")] + pub fn to_pem( + &self, + label: &'static str, + line_ending: pem::LineEnding, + ) -> Result> { + self.0.to_pem(label, line_ending).map(Zeroizing::new) + } + + /// Read ASN.1 DER document from a file. + #[cfg(feature = "std")] + pub fn read_der_file(path: impl AsRef) -> Result { + Document::read_der_file(path).map(Self) + } + + /// Write ASN.1 DER document to a file. + #[cfg(feature = "std")] + pub fn write_der_file(&self, path: impl AsRef) -> Result<()> { + write_secret_file(path, self.as_bytes()) + } + + /// Read PEM-encoded ASN.1 DER document from a file. + #[cfg(all(feature = "pem", feature = "std"))] + pub fn read_pem_file(path: impl AsRef) -> Result<(String, Self)> { + Document::read_pem_file(path).map(|(label, doc)| (label, Self(doc))) + } + + /// Write PEM-encoded ASN.1 DER document to a file. + #[cfg(all(feature = "pem", feature = "std"))] + pub fn write_pem_file( + &self, + path: impl AsRef, + label: &'static str, + line_ending: pem::LineEnding, + ) -> Result<()> { + write_secret_file(path, self.to_pem(label, line_ending)?.as_bytes()) + } +} +#[cfg(feature = "zeroize")] +impl Debug for SecretDocument { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("SecretDocument").finish_non_exhaustive() + } +} + +#[cfg(feature = "zeroize")] +impl Drop for SecretDocument { + fn drop(&mut self) { + self.0.der_bytes.zeroize(); + } +} + +#[cfg(feature = "zeroize")] +impl From for SecretDocument { + fn from(doc: Document) -> SecretDocument { + SecretDocument(doc) + } +} + +#[cfg(feature = "zeroize")] +impl TryFrom<&[u8]> for SecretDocument { + type Error = Error; + + fn try_from(der_bytes: &[u8]) -> Result { + Document::try_from(der_bytes).map(Self) + } +} + +#[cfg(feature = "zeroize")] +impl TryFrom> for SecretDocument { + type Error = Error; + + fn try_from(der_bytes: Vec) -> Result { + Document::try_from(der_bytes).map(Self) + } +} + +#[cfg(feature = "zeroize")] +impl ZeroizeOnDrop for SecretDocument {} + +/// Attempt to decode a ASN.1 `SEQUENCE` from the given decoder, returning the +/// entire sequence including the header. +fn decode_sequence<'a>(decoder: &mut SliceReader<'a>) -> Result<&'a [u8]> { + let header = decoder.peek_header()?; + header.tag.assert_eq(Tag::Sequence)?; + + let len = (header.encoded_len()? + header.length)?; + decoder.read_slice(len) +} + +/// Write a file containing secret data to the filesystem, restricting the +/// file permissions so it's only readable by the owner +#[cfg(all(unix, feature = "std", feature = "zeroize"))] +fn write_secret_file(path: impl AsRef, data: &[u8]) -> Result<()> { + use std::{io::Write, os::unix::fs::OpenOptionsExt}; + + /// File permissions for secret data + #[cfg(unix)] + const SECRET_FILE_PERMS: u32 = 0o600; + + fs::OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .mode(SECRET_FILE_PERMS) + .open(path) + .and_then(|mut file| file.write_all(data))?; + + Ok(()) +} + +/// Write a file containing secret data to the filesystem +// TODO(tarcieri): permissions hardening on Windows +#[cfg(all(not(unix), feature = "std", feature = "zeroize"))] +fn write_secret_file(path: impl AsRef, data: &[u8]) -> Result<()> { + fs::write(path, data)?; + Ok(()) +} diff --git a/src/rust/vendor/der/src/encode.rs b/src/rust/vendor/der/src/encode.rs new file mode 100644 index 000000000..28d7cba77 --- /dev/null +++ b/src/rust/vendor/der/src/encode.rs @@ -0,0 +1,158 @@ +//! Trait definition for [`Encode`]. + +use crate::{Header, Length, Result, SliceWriter, Tagged, Writer}; +use core::marker::PhantomData; + +#[cfg(feature = "alloc")] +use {alloc::boxed::Box, alloc::vec::Vec, core::iter}; + +#[cfg(feature = "pem")] +use { + crate::PemWriter, + alloc::string::String, + pem_rfc7468::{self as pem, LineEnding, PemLabel}, +}; + +#[cfg(any(feature = "alloc", feature = "pem"))] +use crate::ErrorKind; + +#[cfg(doc)] +use crate::Tag; + +/// Encoding trait. +pub trait Encode { + /// Compute the length of this value in bytes when encoded as ASN.1 DER. + fn encoded_len(&self) -> Result; + + /// Encode this value as ASN.1 DER using the provided [`Writer`]. + fn encode(&self, encoder: &mut impl Writer) -> Result<()>; + + /// Encode this value to the provided byte slice, returning a sub-slice + /// containing the encoded message. + fn encode_to_slice<'a>(&self, buf: &'a mut [u8]) -> Result<&'a [u8]> { + let mut writer = SliceWriter::new(buf); + self.encode(&mut writer)?; + writer.finish() + } + + /// Encode this message as ASN.1 DER, appending it to the provided + /// byte vector. + #[cfg(feature = "alloc")] + fn encode_to_vec(&self, buf: &mut Vec) -> Result { + let expected_len = usize::try_from(self.encoded_len()?)?; + buf.reserve(expected_len); + buf.extend(iter::repeat(0).take(expected_len)); + + let mut writer = SliceWriter::new(buf); + self.encode(&mut writer)?; + let actual_len = writer.finish()?.len(); + + if expected_len != actual_len { + return Err(ErrorKind::Incomplete { + expected_len: expected_len.try_into()?, + actual_len: actual_len.try_into()?, + } + .into()); + } + + actual_len.try_into() + } + + /// Encode this type as DER, returning a byte vector. + #[cfg(feature = "alloc")] + fn to_der(&self) -> Result> { + let mut buf = Vec::new(); + self.encode_to_vec(&mut buf)?; + Ok(buf) + } +} + +impl Encode for T +where + T: EncodeValue + Tagged, +{ + /// Compute the length of this value in bytes when encoded as ASN.1 DER. + fn encoded_len(&self) -> Result { + self.value_len().and_then(|len| len.for_tlv()) + } + + /// Encode this value as ASN.1 DER using the provided [`Writer`]. + fn encode(&self, writer: &mut impl Writer) -> Result<()> { + self.header()?.encode(writer)?; + self.encode_value(writer) + } +} + +/// Dummy implementation for [`PhantomData`] which allows deriving +/// implementations on structs with phantom fields. +impl Encode for PhantomData +where + T: ?Sized, +{ + fn encoded_len(&self) -> Result { + Ok(Length::ZERO) + } + + fn encode(&self, _writer: &mut impl Writer) -> Result<()> { + Ok(()) + } +} + +/// PEM encoding trait. +/// +/// This trait is automatically impl'd for any type which impls both +/// [`Encode`] and [`PemLabel`]. +#[cfg(feature = "pem")] +pub trait EncodePem: Encode + PemLabel { + /// Try to encode this type as PEM. + fn to_pem(&self, line_ending: LineEnding) -> Result; +} + +#[cfg(feature = "pem")] +impl EncodePem for T { + fn to_pem(&self, line_ending: LineEnding) -> Result { + let der_len = usize::try_from(self.encoded_len()?)?; + let pem_len = pem::encapsulated_len(Self::PEM_LABEL, line_ending, der_len)?; + + let mut buf = vec![0u8; pem_len]; + let mut writer = PemWriter::new(Self::PEM_LABEL, line_ending, &mut buf)?; + self.encode(&mut writer)?; + + let actual_len = writer.finish()?; + buf.truncate(actual_len); + Ok(String::from_utf8(buf)?) + } +} + +/// Encode the value part of a Tag-Length-Value encoded field, sans the [`Tag`] +/// and [`Length`]. +pub trait EncodeValue { + /// Get the [`Header`] used to encode this value. + fn header(&self) -> Result

+ where + Self: Tagged, + { + Header::new(self.tag(), self.value_len()?) + } + + /// Compute the length of this value (sans [`Tag`]+[`Length`] header) when + /// encoded as ASN.1 DER. + fn value_len(&self) -> Result; + + /// Encode value (sans [`Tag`]+[`Length`] header) as ASN.1 DER using the + /// provided [`Writer`]. + fn encode_value(&self, encoder: &mut impl Writer) -> Result<()>; +} + +#[cfg(feature = "alloc")] +impl EncodeValue for Box +where + T: EncodeValue, +{ + fn value_len(&self) -> Result { + T::value_len(self) + } + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + T::encode_value(self, writer) + } +} diff --git a/src/rust/vendor/der/src/encode_ref.rs b/src/rust/vendor/der/src/encode_ref.rs new file mode 100644 index 000000000..8a60a933f --- /dev/null +++ b/src/rust/vendor/der/src/encode_ref.rs @@ -0,0 +1,71 @@ +//! Wrapper object for encoding reference types. +// TODO(tarcieri): replace with blanket impls of `Encode(Value)` for reference types? + +use crate::{Encode, EncodeValue, Length, Result, Tag, Tagged, ValueOrd, Writer}; +use core::cmp::Ordering; + +/// Reference encoder: wrapper type which impls `Encode` for any reference to a +/// type which impls the same. +pub struct EncodeRef<'a, T>(pub &'a T); + +impl<'a, T> AsRef for EncodeRef<'a, T> { + fn as_ref(&self) -> &T { + self.0 + } +} + +impl<'a, T> Encode for EncodeRef<'a, T> +where + T: Encode, +{ + fn encoded_len(&self) -> Result { + self.0.encoded_len() + } + + fn encode(&self, writer: &mut impl Writer) -> Result<()> { + self.0.encode(writer) + } +} + +/// Reference value encoder: wrapper type which impls `EncodeValue` and `Tagged` +/// for any reference type which impls the same. +/// +/// By virtue of the blanket impl, this type also impls `Encode`. +pub struct EncodeValueRef<'a, T>(pub &'a T); + +impl<'a, T> AsRef for EncodeValueRef<'a, T> { + fn as_ref(&self) -> &T { + self.0 + } +} + +impl<'a, T> EncodeValue for EncodeValueRef<'a, T> +where + T: EncodeValue, +{ + fn value_len(&self) -> Result { + self.0.value_len() + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + self.0.encode_value(writer) + } +} + +impl<'a, T> Tagged for EncodeValueRef<'a, T> +where + T: Tagged, +{ + fn tag(&self) -> Tag { + self.0.tag() + } +} + +impl<'a, T> ValueOrd for EncodeValueRef<'a, T> +where + T: ValueOrd, +{ + fn value_cmp(&self, other: &Self) -> Result { + self.0.value_cmp(other.0) + } +} diff --git a/src/rust/vendor/der/src/error.rs b/src/rust/vendor/der/src/error.rs new file mode 100644 index 000000000..902863d49 --- /dev/null +++ b/src/rust/vendor/der/src/error.rs @@ -0,0 +1,369 @@ +//! Error types. + +pub use core::str::Utf8Error; + +use crate::{Length, Tag}; +use core::{convert::Infallible, fmt, num::TryFromIntError}; + +#[cfg(feature = "oid")] +use crate::asn1::ObjectIdentifier; + +#[cfg(feature = "pem")] +use crate::pem; + +/// Result type. +pub type Result = core::result::Result; + +/// Error type. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct Error { + /// Kind of error. + kind: ErrorKind, + + /// Position inside of message where error occurred. + position: Option, +} + +impl Error { + /// Create a new [`Error`]. + pub fn new(kind: ErrorKind, position: Length) -> Error { + Error { + kind, + position: Some(position), + } + } + + /// Create a new [`ErrorKind::Incomplete`] for the given length. + /// + /// Computes the expected len as being one greater than `actual_len`. + pub fn incomplete(actual_len: Length) -> Self { + match actual_len + Length::ONE { + Ok(expected_len) => ErrorKind::Incomplete { + expected_len, + actual_len, + } + .at(actual_len), + Err(err) => err.kind().at(actual_len), + } + } + + /// Get the [`ErrorKind`] which occurred. + pub fn kind(self) -> ErrorKind { + self.kind + } + + /// Get the position inside of the message where the error occurred. + pub fn position(self) -> Option { + self.position + } + + /// For errors occurring inside of a nested message, extend the position + /// count by the location where the nested message occurs. + pub(crate) fn nested(self, nested_position: Length) -> Self { + // TODO(tarcieri): better handle length overflows occurring in this calculation? + let position = (nested_position + self.position.unwrap_or_default()).ok(); + + Self { + kind: self.kind, + position, + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for Error {} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.kind)?; + + if let Some(pos) = self.position { + write!(f, " at DER byte {}", pos)?; + } + + Ok(()) + } +} + +impl From for Error { + fn from(kind: ErrorKind) -> Error { + Error { + kind, + position: None, + } + } +} + +impl From for Error { + fn from(_: Infallible) -> Error { + unreachable!() + } +} + +impl From for Error { + fn from(_: TryFromIntError) -> Error { + Error { + kind: ErrorKind::Overflow, + position: None, + } + } +} + +impl From for Error { + fn from(err: Utf8Error) -> Error { + Error { + kind: ErrorKind::Utf8(err), + position: None, + } + } +} + +#[cfg(feature = "alloc")] +impl From for Error { + fn from(err: alloc::string::FromUtf8Error) -> Error { + ErrorKind::Utf8(err.utf8_error()).into() + } +} + +#[cfg(feature = "oid")] +impl From for Error { + fn from(_: const_oid::Error) -> Error { + ErrorKind::OidMalformed.into() + } +} + +#[cfg(feature = "pem")] +impl From for Error { + fn from(err: pem::Error) -> Error { + ErrorKind::Pem(err).into() + } +} + +#[cfg(feature = "std")] +impl From for Error { + fn from(err: std::io::Error) -> Error { + match err.kind() { + std::io::ErrorKind::NotFound => ErrorKind::FileNotFound, + std::io::ErrorKind::PermissionDenied => ErrorKind::PermissionDenied, + other => ErrorKind::Io(other), + } + .into() + } +} + +#[cfg(feature = "time")] +impl From for Error { + fn from(_: time::error::ComponentRange) -> Error { + ErrorKind::DateTime.into() + } +} + +/// Error type. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[non_exhaustive] +pub enum ErrorKind { + /// Date-and-time related errors. + DateTime, + + /// This error indicates a previous DER parsing operation resulted in + /// an error and tainted the state of a `Decoder` or `Encoder`. + /// + /// Once this occurs, the overall operation has failed and cannot be + /// subsequently resumed. + Failed, + + /// File not found error. + #[cfg(feature = "std")] + FileNotFound, + + /// Message is incomplete and does not contain all of the expected data. + Incomplete { + /// Expected message length. + /// + /// Note that this length represents a *minimum* lower bound on how + /// much additional data is needed to continue parsing the message. + /// + /// It's possible upon subsequent message parsing that the parser will + /// discover even more data is needed. + expected_len: Length, + + /// Actual length of the message buffer currently being processed. + actual_len: Length, + }, + + /// I/O errors. + #[cfg(feature = "std")] + Io(std::io::ErrorKind), + + /// Indefinite length disallowed. + IndefiniteLength, + + /// Incorrect length for a given field. + Length { + /// Tag of the value being decoded. + tag: Tag, + }, + + /// Message is not canonically encoded. + Noncanonical { + /// Tag of the value which is not canonically encoded. + tag: Tag, + }, + + /// OID is improperly encoded. + OidMalformed, + + /// Unknown OID. + /// + /// This error is intended to be used by libraries which parse DER-based + /// formats which encounter unknown or unsupported OID libraries. + /// + /// It enables passing back the OID value to the caller, which allows them + /// to determine which OID(s) are causing the error (and then potentially + /// contribute upstream support for algorithms they care about). + #[cfg(feature = "oid")] + OidUnknown { + /// OID value that was unrecognized by a parser for a DER-based format. + oid: ObjectIdentifier, + }, + + /// `SET` cannot contain duplicates. + SetDuplicate, + + /// `SET` ordering error: items not in canonical order. + SetOrdering, + + /// Integer overflow occurred (library bug!). + Overflow, + + /// Message is longer than this library's internal limits support. + Overlength, + + /// PEM encoding errors. + #[cfg(feature = "pem")] + Pem(pem::Error), + + /// Permission denied reading file. + #[cfg(feature = "std")] + PermissionDenied, + + /// Reader does not support the requested operation. + Reader, + + /// Unknown tag mode. + TagModeUnknown, + + /// Invalid tag number. + /// + /// The "tag number" is the lower 5-bits of a tag's octet. + /// This error occurs in the case that all 5-bits are set to `1`, + /// which indicates a multi-byte tag which is unsupported by this library. + TagNumberInvalid, + + /// Unexpected tag. + TagUnexpected { + /// Tag the decoder was expecting (if there is a single such tag). + /// + /// `None` if multiple tags are expected/allowed, but the `actual` tag + /// does not match any of them. + expected: Option, + + /// Actual tag encountered in the message. + actual: Tag, + }, + + /// Unknown/unsupported tag. + TagUnknown { + /// Raw byte value of the tag. + byte: u8, + }, + + /// Undecoded trailing data at end of message. + TrailingData { + /// Length of the decoded data. + decoded: Length, + + /// Total length of the remaining data left in the buffer. + remaining: Length, + }, + + /// UTF-8 errors. + Utf8(Utf8Error), + + /// Unexpected value. + Value { + /// Tag of the unexpected value. + tag: Tag, + }, +} + +impl ErrorKind { + /// Annotate an [`ErrorKind`] with context about where it occurred, + /// returning an error. + pub fn at(self, position: Length) -> Error { + Error::new(self, position) + } +} + +impl fmt::Display for ErrorKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ErrorKind::DateTime => write!(f, "date/time error"), + ErrorKind::Failed => write!(f, "operation failed"), + #[cfg(feature = "std")] + ErrorKind::FileNotFound => write!(f, "file not found"), + ErrorKind::Incomplete { + expected_len, + actual_len, + } => write!( + f, + "ASN.1 DER message is incomplete: expected {}, actual {}", + expected_len, actual_len + ), + #[cfg(feature = "std")] + ErrorKind::Io(err) => write!(f, "I/O error: {:?}", err), + ErrorKind::IndefiniteLength => write!(f, "indefinite length disallowed"), + ErrorKind::Length { tag } => write!(f, "incorrect length for {}", tag), + ErrorKind::Noncanonical { tag } => { + write!(f, "ASN.1 {} not canonically encoded as DER", tag) + } + ErrorKind::OidMalformed => write!(f, "malformed OID"), + #[cfg(feature = "oid")] + ErrorKind::OidUnknown { oid } => { + write!(f, "unknown/unsupported OID: {}", oid) + } + ErrorKind::SetDuplicate => write!(f, "SET OF contains duplicate"), + ErrorKind::SetOrdering => write!(f, "SET OF ordering error"), + ErrorKind::Overflow => write!(f, "integer overflow"), + ErrorKind::Overlength => write!(f, "ASN.1 DER message is too long"), + #[cfg(feature = "pem")] + ErrorKind::Pem(e) => write!(f, "PEM error: {}", e), + #[cfg(feature = "std")] + ErrorKind::PermissionDenied => write!(f, "permission denied"), + ErrorKind::Reader => write!(f, "reader does not support the requested operation"), + ErrorKind::TagModeUnknown => write!(f, "unknown tag mode"), + ErrorKind::TagNumberInvalid => write!(f, "invalid tag number"), + ErrorKind::TagUnexpected { expected, actual } => { + write!(f, "unexpected ASN.1 DER tag: ")?; + + if let Some(tag) = expected { + write!(f, "expected {}, ", tag)?; + } + + write!(f, "got {}", actual) + } + ErrorKind::TagUnknown { byte } => { + write!(f, "unknown/unsupported ASN.1 DER tag: 0x{:02x}", byte) + } + ErrorKind::TrailingData { decoded, remaining } => { + write!( + f, + "trailing data at end of DER message: decoded {} bytes, {} bytes remaining", + decoded, remaining + ) + } + ErrorKind::Utf8(e) => write!(f, "{}", e), + ErrorKind::Value { tag } => write!(f, "malformed ASN.1 DER value for {}", tag), + } + } +} diff --git a/src/rust/vendor/der/src/header.rs b/src/rust/vendor/der/src/header.rs new file mode 100644 index 000000000..ad303810c --- /dev/null +++ b/src/rust/vendor/der/src/header.rs @@ -0,0 +1,60 @@ +//! ASN.1 DER headers. + +use crate::{Decode, DerOrd, Encode, ErrorKind, Length, Reader, Result, Tag, Writer}; +use core::cmp::Ordering; + +/// ASN.1 DER headers: tag + length component of TLV-encoded values +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct Header { + /// Tag representing the type of the encoded value + pub tag: Tag, + + /// Length of the encoded value + pub length: Length, +} + +impl Header { + /// Create a new [`Header`] from a [`Tag`] and a specified length. + /// + /// Returns an error if the length exceeds the limits of [`Length`]. + pub fn new(tag: Tag, length: impl TryInto) -> Result { + let length = length.try_into().map_err(|_| ErrorKind::Overflow)?; + Ok(Self { tag, length }) + } +} + +impl<'a> Decode<'a> for Header { + fn decode>(reader: &mut R) -> Result
{ + let tag = Tag::decode(reader)?; + + let length = Length::decode(reader).map_err(|e| { + if e.kind() == ErrorKind::Overlength { + ErrorKind::Length { tag }.into() + } else { + e + } + })?; + + Ok(Self { tag, length }) + } +} + +impl Encode for Header { + fn encoded_len(&self) -> Result { + self.tag.encoded_len()? + self.length.encoded_len()? + } + + fn encode(&self, writer: &mut impl Writer) -> Result<()> { + self.tag.encode(writer)?; + self.length.encode(writer) + } +} + +impl DerOrd for Header { + fn der_cmp(&self, other: &Self) -> Result { + match self.tag.der_cmp(&other.tag)? { + Ordering::Equal => self.length.der_cmp(&other.length), + ordering => Ok(ordering), + } + } +} diff --git a/src/rust/vendor/der/src/length.rs b/src/rust/vendor/der/src/length.rs new file mode 100644 index 000000000..d183a69fe --- /dev/null +++ b/src/rust/vendor/der/src/length.rs @@ -0,0 +1,514 @@ +//! Length calculations for encoded ASN.1 DER values + +use crate::{Decode, DerOrd, Encode, Error, ErrorKind, Reader, Result, SliceWriter, Writer}; +use core::{ + cmp::Ordering, + fmt, + ops::{Add, Sub}, +}; + +/// Maximum number of octets in a DER encoding of a [`Length`] using the +/// rules implemented by this crate. +const MAX_DER_OCTETS: usize = 5; + +/// Maximum length as a `u32` (256 MiB). +const MAX_U32: u32 = 0xfff_ffff; + +/// Octet identifying an indefinite length as described in X.690 Section +/// 8.1.3.6.1: +/// +/// > The single octet shall have bit 8 set to one, and bits 7 to +/// > 1 set to zero. +const INDEFINITE_LENGTH_OCTET: u8 = 0b10000000; // 0x80 + +/// ASN.1-encoded length. +/// +/// Maximum length is defined by the [`Length::MAX`] constant (256 MiB). +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] +pub struct Length(u32); + +impl Length { + /// Length of `0` + pub const ZERO: Self = Self(0); + + /// Length of `1` + pub const ONE: Self = Self(1); + + /// Maximum length currently supported: 256 MiB + pub const MAX: Self = Self(MAX_U32); + + /// Create a new [`Length`] for any value which fits inside of a [`u16`]. + /// + /// This function is const-safe and therefore useful for [`Length`] constants. + pub const fn new(value: u16) -> Self { + Self(value as u32) + } + + /// Is this length equal to zero? + pub fn is_zero(self) -> bool { + self == Self::ZERO + } + + /// Get the length of DER Tag-Length-Value (TLV) encoded data if `self` + /// is the length of the inner "value" portion of the message. + pub fn for_tlv(self) -> Result { + Self::ONE + self.encoded_len()? + self + } + + /// Perform saturating addition of two lengths. + pub fn saturating_add(self, rhs: Self) -> Self { + Self(self.0.saturating_add(rhs.0)) + } + + /// Perform saturating subtraction of two lengths. + pub fn saturating_sub(self, rhs: Self) -> Self { + Self(self.0.saturating_sub(rhs.0)) + } + + /// Get initial octet of the encoded length (if one is required). + /// + /// From X.690 Section 8.1.3.5: + /// > In the long form, the length octets shall consist of an initial octet + /// > and one or more subsequent octets. The initial octet shall be encoded + /// > as follows: + /// > + /// > a) bit 8 shall be one; + /// > b) bits 7 to 1 shall encode the number of subsequent octets in the + /// > length octets, as an unsigned binary integer with bit 7 as the + /// > most significant bit; + /// > c) the value 11111111₂ shall not be used. + fn initial_octet(self) -> Option { + match self.0 { + 0x80..=0xFF => Some(0x81), + 0x100..=0xFFFF => Some(0x82), + 0x10000..=0xFFFFFF => Some(0x83), + 0x1000000..=MAX_U32 => Some(0x84), + _ => None, + } + } +} + +impl Add for Length { + type Output = Result; + + fn add(self, other: Self) -> Result { + self.0 + .checked_add(other.0) + .ok_or_else(|| ErrorKind::Overflow.into()) + .and_then(TryInto::try_into) + } +} + +impl Add for Length { + type Output = Result; + + fn add(self, other: u8) -> Result { + self + Length::from(other) + } +} + +impl Add for Length { + type Output = Result; + + fn add(self, other: u16) -> Result { + self + Length::from(other) + } +} + +impl Add for Length { + type Output = Result; + + fn add(self, other: u32) -> Result { + self + Length::try_from(other)? + } +} + +impl Add for Length { + type Output = Result; + + fn add(self, other: usize) -> Result { + self + Length::try_from(other)? + } +} + +impl Add for Result { + type Output = Self; + + fn add(self, other: Length) -> Self { + self? + other + } +} + +impl Sub for Length { + type Output = Result; + + fn sub(self, other: Length) -> Result { + self.0 + .checked_sub(other.0) + .ok_or_else(|| ErrorKind::Overflow.into()) + .and_then(TryInto::try_into) + } +} + +impl Sub for Result { + type Output = Self; + + fn sub(self, other: Length) -> Self { + self? - other + } +} + +impl From for Length { + fn from(len: u8) -> Length { + Length(len.into()) + } +} + +impl From for Length { + fn from(len: u16) -> Length { + Length(len.into()) + } +} + +impl From for u32 { + fn from(length: Length) -> u32 { + length.0 + } +} + +impl TryFrom for Length { + type Error = Error; + + fn try_from(len: u32) -> Result { + if len <= Self::MAX.0 { + Ok(Length(len)) + } else { + Err(ErrorKind::Overflow.into()) + } + } +} + +impl TryFrom for Length { + type Error = Error; + + fn try_from(len: usize) -> Result { + u32::try_from(len) + .map_err(|_| ErrorKind::Overflow)? + .try_into() + } +} + +impl TryFrom for usize { + type Error = Error; + + fn try_from(len: Length) -> Result { + len.0.try_into().map_err(|_| ErrorKind::Overflow.into()) + } +} + +impl<'a> Decode<'a> for Length { + fn decode>(reader: &mut R) -> Result { + match reader.read_byte()? { + // Note: per X.690 Section 8.1.3.6.1 the byte 0x80 encodes indefinite + // lengths, which are not allowed in DER, so disallow that byte. + len if len < INDEFINITE_LENGTH_OCTET => Ok(len.into()), + INDEFINITE_LENGTH_OCTET => Err(ErrorKind::IndefiniteLength.into()), + // 1-4 byte variable-sized length prefix + tag @ 0x81..=0x84 => { + let nbytes = tag.checked_sub(0x80).ok_or(ErrorKind::Overlength)? as usize; + debug_assert!(nbytes <= 4); + + let mut decoded_len = 0u32; + for _ in 0..nbytes { + decoded_len = decoded_len.checked_shl(8).ok_or(ErrorKind::Overflow)? + | u32::from(reader.read_byte()?); + } + + let length = Length::try_from(decoded_len)?; + + // X.690 Section 10.1: DER lengths must be encoded with a minimum + // number of octets + if length.initial_octet() == Some(tag) { + Ok(length) + } else { + Err(ErrorKind::Overlength.into()) + } + } + _ => { + // We specialize to a maximum 4-byte length (including initial octet) + Err(ErrorKind::Overlength.into()) + } + } + } +} + +impl Encode for Length { + fn encoded_len(&self) -> Result { + match self.0 { + 0..=0x7F => Ok(Length(1)), + 0x80..=0xFF => Ok(Length(2)), + 0x100..=0xFFFF => Ok(Length(3)), + 0x10000..=0xFFFFFF => Ok(Length(4)), + 0x1000000..=MAX_U32 => Ok(Length(5)), + _ => Err(ErrorKind::Overflow.into()), + } + } + + fn encode(&self, writer: &mut impl Writer) -> Result<()> { + match self.initial_octet() { + Some(tag_byte) => { + writer.write_byte(tag_byte)?; + + // Strip leading zeroes + match self.0.to_be_bytes() { + [0, 0, 0, byte] => writer.write_byte(byte), + [0, 0, bytes @ ..] => writer.write(&bytes), + [0, bytes @ ..] => writer.write(&bytes), + bytes => writer.write(&bytes), + } + } + #[allow(clippy::cast_possible_truncation)] + None => writer.write_byte(self.0 as u8), + } + } +} + +impl DerOrd for Length { + fn der_cmp(&self, other: &Self) -> Result { + let mut buf1 = [0u8; MAX_DER_OCTETS]; + let mut buf2 = [0u8; MAX_DER_OCTETS]; + + let mut encoder1 = SliceWriter::new(&mut buf1); + encoder1.encode(self)?; + + let mut encoder2 = SliceWriter::new(&mut buf2); + encoder2.encode(other)?; + + Ok(encoder1.finish()?.cmp(encoder2.finish()?)) + } +} + +impl fmt::Display for Length { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +// Implement by hand because the derive would create invalid values. +// Generate a u32 with a valid range. +#[cfg(feature = "arbitrary")] +impl<'a> arbitrary::Arbitrary<'a> for Length { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + Ok(Self(u.int_in_range(0..=MAX_U32)?)) + } + + fn size_hint(depth: usize) -> (usize, Option) { + u32::size_hint(depth) + } +} + +/// Length type with support for indefinite lengths as used by ASN.1 BER, +/// as described in X.690 Section 8.1.3.6: +/// +/// > 8.1.3.6 For the indefinite form, the length octets indicate that the +/// > contents octets are terminated by end-of-contents +/// > octets (see 8.1.5), and shall consist of a single octet. +/// > +/// > 8.1.3.6.1 The single octet shall have bit 8 set to one, and bits 7 to +/// > 1 set to zero. +/// > +/// > 8.1.3.6.2 If this form of length is used, then end-of-contents octets +/// > (see 8.1.5) shall be present in the encoding following the contents +/// > octets. +/// +/// Indefinite lengths are non-canonical and therefore invalid DER, however +/// there are interoperability corner cases where we have little choice but to +/// tolerate some BER productions where this is helpful. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct IndefiniteLength(Option); + +impl IndefiniteLength { + /// Length of `0`. + pub const ZERO: Self = Self(Some(Length::ZERO)); + + /// Length of `1`. + pub const ONE: Self = Self(Some(Length::ONE)); + + /// Indefinite length. + pub const INDEFINITE: Self = Self(None); +} + +impl IndefiniteLength { + /// Create a definite length from a type which can be converted into a + /// `Length`. + pub fn new(length: impl Into) -> Self { + Self(Some(length.into())) + } + + /// Is this length definite? + pub fn is_definite(self) -> bool { + self.0.is_some() + } + /// Is this length indefinite? + pub fn is_indefinite(self) -> bool { + self.0.is_none() + } +} + +impl<'a> Decode<'a> for IndefiniteLength { + fn decode>(reader: &mut R) -> Result { + if reader.peek_byte() == Some(INDEFINITE_LENGTH_OCTET) { + // Consume the byte we already peeked at. + let byte = reader.read_byte()?; + debug_assert_eq!(byte, INDEFINITE_LENGTH_OCTET); + + Ok(Self::INDEFINITE) + } else { + Length::decode(reader).map(Into::into) + } + } +} + +impl Encode for IndefiniteLength { + fn encoded_len(&self) -> Result { + match self.0 { + Some(length) => length.encoded_len(), + None => Ok(Length::ONE), + } + } + + fn encode(&self, writer: &mut impl Writer) -> Result<()> { + match self.0 { + Some(length) => length.encode(writer), + None => writer.write_byte(INDEFINITE_LENGTH_OCTET), + } + } +} + +impl From for IndefiniteLength { + fn from(length: Length) -> IndefiniteLength { + Self(Some(length)) + } +} + +impl From> for IndefiniteLength { + fn from(length: Option) -> IndefiniteLength { + IndefiniteLength(length) + } +} + +impl From for Option { + fn from(length: IndefiniteLength) -> Option { + length.0 + } +} + +impl TryFrom for Length { + type Error = Error; + + fn try_from(length: IndefiniteLength) -> Result { + length.0.ok_or_else(|| ErrorKind::IndefiniteLength.into()) + } +} + +#[cfg(test)] +mod tests { + use super::{IndefiniteLength, Length}; + use crate::{Decode, DerOrd, Encode, ErrorKind}; + use core::cmp::Ordering; + + #[test] + fn decode() { + assert_eq!(Length::ZERO, Length::from_der(&[0x00]).unwrap()); + + assert_eq!(Length::from(0x7Fu8), Length::from_der(&[0x7F]).unwrap()); + + assert_eq!( + Length::from(0x80u8), + Length::from_der(&[0x81, 0x80]).unwrap() + ); + + assert_eq!( + Length::from(0xFFu8), + Length::from_der(&[0x81, 0xFF]).unwrap() + ); + + assert_eq!( + Length::from(0x100u16), + Length::from_der(&[0x82, 0x01, 0x00]).unwrap() + ); + + assert_eq!( + Length::try_from(0x10000u32).unwrap(), + Length::from_der(&[0x83, 0x01, 0x00, 0x00]).unwrap() + ); + } + + #[test] + fn encode() { + let mut buffer = [0u8; 4]; + + assert_eq!(&[0x00], Length::ZERO.encode_to_slice(&mut buffer).unwrap()); + + assert_eq!( + &[0x7F], + Length::from(0x7Fu8).encode_to_slice(&mut buffer).unwrap() + ); + + assert_eq!( + &[0x81, 0x80], + Length::from(0x80u8).encode_to_slice(&mut buffer).unwrap() + ); + + assert_eq!( + &[0x81, 0xFF], + Length::from(0xFFu8).encode_to_slice(&mut buffer).unwrap() + ); + + assert_eq!( + &[0x82, 0x01, 0x00], + Length::from(0x100u16).encode_to_slice(&mut buffer).unwrap() + ); + + assert_eq!( + &[0x83, 0x01, 0x00, 0x00], + Length::try_from(0x10000u32) + .unwrap() + .encode_to_slice(&mut buffer) + .unwrap() + ); + } + + #[test] + fn indefinite_lengths() { + // DER disallows indefinite lengths + assert!(Length::from_der(&[0x80]).is_err()); + + // The `IndefiniteLength` type supports them + let indefinite_length = IndefiniteLength::from_der(&[0x80]).unwrap(); + assert!(indefinite_length.is_indefinite()); + assert_eq!(indefinite_length, IndefiniteLength::INDEFINITE); + + // It also supports definite lengths. + let length = IndefiniteLength::from_der(&[0x83, 0x01, 0x00, 0x00]).unwrap(); + assert!(length.is_definite()); + assert_eq!( + Length::try_from(0x10000u32).unwrap(), + length.try_into().unwrap() + ); + } + + #[test] + fn add_overflows_when_max_length_exceeded() { + let result = Length::MAX + Length::ONE; + assert_eq!( + result.err().map(|err| err.kind()), + Some(ErrorKind::Overflow) + ); + } + + #[test] + fn der_ord() { + assert_eq!(Length::ONE.der_cmp(&Length::MAX).unwrap(), Ordering::Less); + } +} diff --git a/src/rust/vendor/der/src/lib.rs b/src/rust/vendor/der/src/lib.rs new file mode 100644 index 000000000..dcd5097d4 --- /dev/null +++ b/src/rust/vendor/der/src/lib.rs @@ -0,0 +1,402 @@ +#![no_std] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![doc = include_str!("../README.md")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" +)] +#![forbid(unsafe_code)] +#![warn( + clippy::cast_lossless, + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::cast_precision_loss, + clippy::cast_sign_loss, + clippy::checked_conversions, + clippy::implicit_saturating_sub, + clippy::integer_arithmetic, + clippy::mod_module_files, + clippy::panic, + clippy::panic_in_result_fn, + clippy::unwrap_used, + missing_docs, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] + +//! # Usage +//! ## [`Decode`] and [`Encode`] traits +//! The [`Decode`] and [`Encode`] traits provide the decoding/encoding API +//! respectively, and are designed to work in conjunction with concrete ASN.1 +//! types, including all types which impl the [`Sequence`] trait. +//! +//! The traits are impl'd for the following Rust core types: +//! - `()`: ASN.1 `NULL`. See also [`Null`]. +//! - [`bool`]: ASN.1 `BOOLEAN`. +//! - [`i8`], [`i16`], [`i32`], [`i64`], [`i128`]: ASN.1 `INTEGER`. +//! - [`u8`], [`u16`], [`u32`], [`u64`], [`u128`]: ASN.1 `INTEGER`. +//! - [`f64`]: ASN.1 `REAL` (gated on `real` crate feature) +//! - [`str`], [`String`][`alloc::string::String`]: ASN.1 `UTF8String`. +//! `String` requires `alloc` feature. See also [`Utf8StringRef`]. +//! - [`Option`]: ASN.1 `OPTIONAL`. +//! - [`SystemTime`][`std::time::SystemTime`]: ASN.1 `GeneralizedTime`. Requires `std` feature. +//! - [`Vec`][`alloc::vec::Vec`]: ASN.1 `SEQUENCE OF`. Requires `alloc` feature. +//! - `[T; N]`: ASN.1 `SEQUENCE OF`. See also [`SequenceOf`]. +//! +//! The following ASN.1 types provided by this crate also impl these traits: +//! - [`Any`], [`AnyRef`]: ASN.1 `ANY`. +//! - [`BitString`], [`BitStringRef`]: ASN.1 `BIT STRING` +//! - [`GeneralizedTime`]: ASN.1 `GeneralizedTime`. +//! - [`Ia5StringRef`]: ASN.1 `IA5String`. +//! - [`Null`]: ASN.1 `NULL`. +//! - [`ObjectIdentifier`]: ASN.1 `OBJECT IDENTIFIER`. +//! - [`OctetString`], [`OctetStringRef`]: ASN.1 `OCTET STRING`. +//! - [`PrintableStringRef`]: ASN.1 `PrintableString` (ASCII subset). +//! - [`TeletexStringRef`]: ASN.1 `TeletexString`. +//! - [`VideotexStringRef`]: ASN.1 `VideotexString`. +//! - [`SequenceOf`]: ASN.1 `SEQUENCE OF`. +//! - [`SetOf`], [`SetOfVec`]: ASN.1 `SET OF`. +//! - [`UintRef`]: ASN.1 unsigned `INTEGER` with raw access to encoded bytes. +//! - [`UtcTime`]: ASN.1 `UTCTime`. +//! - [`Utf8StringRef`]: ASN.1 `UTF8String`. +//! +//! Context specific fields can be modeled using these generic types: +//! - [`ContextSpecific`]: decoder/encoder for owned context-specific fields +//! - [`ContextSpecificRef`]: encode-only type for references to context-specific fields +//! +//! ## Example +//! The following example implements X.509's `AlgorithmIdentifier` message type +//! as defined in [RFC 5280 Section 4.1.1.2]. +//! +//! The ASN.1 schema for this message type is as follows: +//! +//! ```text +//! AlgorithmIdentifier ::= SEQUENCE { +//! algorithm OBJECT IDENTIFIER, +//! parameters ANY DEFINED BY algorithm OPTIONAL } +//! ``` +//! +//! Structured ASN.1 messages are typically encoded as a `SEQUENCE`, which +//! this crate maps to a Rust struct using the [`Sequence`] trait. This +//! trait is bounded on the [`Decode`] trait and provides a blanket impl +//! of the [`Encode`] trait, so any type which impls [`Sequence`] can be +//! used for both decoding and encoding. +//! +//! The following code example shows how to define a struct which maps to the +//! above schema, as well as impl the [`Sequence`] trait for that struct: +//! +//! ``` +//! # #[cfg(all(feature = "alloc", feature = "oid"))] +//! # { +//! // Note: the following example does not require the `std` feature at all. +//! // It does leverage the `alloc` feature, but also provides instructions for +//! // "heapless" usage when the `alloc` feature is disabled. +//! use der::{ +//! asn1::{AnyRef, ObjectIdentifier}, +//! DecodeValue, Decode, SliceReader, Encode, Header, Reader, Sequence +//! }; +//! +//! /// X.509 `AlgorithmIdentifier`. +//! #[derive(Copy, Clone, Debug, Eq, PartialEq)] +//! pub struct AlgorithmIdentifier<'a> { +//! /// This field contains an ASN.1 `OBJECT IDENTIFIER`, a.k.a. OID. +//! pub algorithm: ObjectIdentifier, +//! +//! /// This field is `OPTIONAL` and contains the ASN.1 `ANY` type, which +//! /// in this example allows arbitrary algorithm-defined parameters. +//! pub parameters: Option> +//! } +//! +//! impl<'a> DecodeValue<'a> for AlgorithmIdentifier<'a> { +//! fn decode_value>(reader: &mut R, _header: Header) -> der::Result { +//! // The `der::Decoder::Decode` method can be used to decode any +//! // type which impls the `Decode` trait, which is impl'd for +//! // all of the ASN.1 built-in types in the `der` crate. +//! // +//! // Note that if your struct's fields don't contain an ASN.1 +//! // built-in type specifically, there are also helper methods +//! // for all of the built-in types supported by this library +//! // which can be used to select a specific type. +//! // +//! // For example, another way of decoding this particular field, +//! // which contains an ASN.1 `OBJECT IDENTIFIER`, is by calling +//! // `decoder.oid()`. Similar methods are defined for other +//! // ASN.1 built-in types. +//! let algorithm = reader.decode()?; +//! +//! // This field contains an ASN.1 `OPTIONAL` type. The `der` crate +//! // maps this directly to Rust's `Option` type and provides +//! // impls of the `Decode` and `Encode` traits for `Option`. +//! // To explicitly request an `OPTIONAL` type be decoded, use the +//! // `decoder.optional()` method. +//! let parameters = reader.decode()?; +//! +//! // The value returned from the provided `FnOnce` will be +//! // returned from the `any.sequence(...)` call above. +//! // Note that the entire sequence body *MUST* be consumed +//! // or an error will be returned. +//! Ok(Self { algorithm, parameters }) +//! } +//! } +//! +//! impl<'a> ::der::EncodeValue for AlgorithmIdentifier<'a> { +//! fn value_len(&self) -> ::der::Result<::der::Length> { +//! self.algorithm.encoded_len()? + self.parameters.encoded_len()? +//! } +//! +//! fn encode_value(&self, writer: &mut impl ::der::Writer) -> ::der::Result<()> { +//! self.algorithm.encode(writer)?; +//! self.parameters.encode(writer)?; +//! Ok(()) +//! } +//! } +//! +//! impl<'a> Sequence<'a> for AlgorithmIdentifier<'a> {} +//! +//! // Example parameters value: OID for the NIST P-256 elliptic curve. +//! let parameters = "1.2.840.10045.3.1.7".parse::().unwrap(); +//! +//! // We need to convert `parameters` into an `Any<'a>` type, which wraps a +//! // `&'a [u8]` byte slice. +//! // +//! // To do that, we need owned DER-encoded data so that we can have +//! // `AnyRef` borrow a reference to it, so we have to serialize the OID. +//! // +//! // When the `alloc` feature of this crate is enabled, any type that impls +//! // the `Encode` trait including all ASN.1 built-in types and any type +//! // which impls `Sequence` can be serialized by calling `Encode::to_der()`. +//! // +//! // If you would prefer to avoid allocations, you can create a byte array +//! // as backing storage instead, pass that to `der::Encoder::new`, and then +//! // encode the `parameters` value using `encoder.encode(parameters)`. +//! let der_encoded_parameters = parameters.to_der().unwrap(); +//! +//! let algorithm_identifier = AlgorithmIdentifier { +//! // OID for `id-ecPublicKey`, if you're curious +//! algorithm: "1.2.840.10045.2.1".parse().unwrap(), +//! +//! // `Any<'a>` impls `TryFrom<&'a [u8]>`, which parses the provided +//! // slice as an ASN.1 DER-encoded message. +//! parameters: Some(der_encoded_parameters.as_slice().try_into().unwrap()) +//! }; +//! +//! // Serialize the `AlgorithmIdentifier` created above as ASN.1 DER, +//! // allocating a `Vec` for storage. +//! // +//! // As mentioned earlier, if you don't have the `alloc` feature enabled you +//! // can create a fix-sized array instead, then call `Encoder::new` with a +//! // reference to it, then encode the message using +//! // `encoder.encode(algorithm_identifier)`, then finally `encoder.finish()` +//! // to obtain a byte slice containing the encoded message. +//! let der_encoded_algorithm_identifier = algorithm_identifier.to_der().unwrap(); +//! +//! // Deserialize the `AlgorithmIdentifier` we just serialized from ASN.1 DER +//! // using `der::Decode::from_bytes`. +//! let decoded_algorithm_identifier = AlgorithmIdentifier::from_der( +//! &der_encoded_algorithm_identifier +//! ).unwrap(); +//! +//! // Ensure the original `AlgorithmIdentifier` is the same as the one we just +//! // decoded from ASN.1 DER. +//! assert_eq!(algorithm_identifier, decoded_algorithm_identifier); +//! # } +//! ``` +//! +//! ## Custom derive support +//! When the `derive` feature of this crate is enabled, the following custom +//! derive macros are available: +//! +//! - [`Choice`]: derive for `CHOICE` enum (see [`der_derive::Choice`]) +//! - [`Enumerated`]: derive for `ENUMERATED` enum (see [`der_derive::Enumerated`]) +//! - [`Sequence`]: derive for `SEQUENCE` struct (see [`der_derive::Sequence`]) +//! +//! ### Derive [`Sequence`] for struct +//! The following is a code example of how to use the [`Sequence`] custom derive: +//! +//! ``` +//! # #[cfg(all(feature = "alloc", feature = "derive", feature = "oid"))] +//! # { +//! use der::{asn1::{AnyRef, ObjectIdentifier}, Encode, Decode, Sequence}; +//! +//! /// X.509 `AlgorithmIdentifier` (same as above) +//! #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence)] // NOTE: added `Sequence` +//! pub struct AlgorithmIdentifier<'a> { +//! /// This field contains an ASN.1 `OBJECT IDENTIFIER`, a.k.a. OID. +//! pub algorithm: ObjectIdentifier, +//! +//! /// This field is `OPTIONAL` and contains the ASN.1 `ANY` type, which +//! /// in this example allows arbitrary algorithm-defined parameters. +//! pub parameters: Option> +//! } +//! +//! // Example parameters value: OID for the NIST P-256 elliptic curve. +//! let parameters_oid = "1.2.840.10045.3.1.7".parse::().unwrap(); +//! +//! let algorithm_identifier = AlgorithmIdentifier { +//! // OID for `id-ecPublicKey`, if you're curious +//! algorithm: "1.2.840.10045.2.1".parse().unwrap(), +//! +//! // `Any<'a>` impls `From<&'a ObjectIdentifier>`, allowing OID constants to +//! // be directly converted to an `AnyRef` type for this use case. +//! parameters: Some(AnyRef::from(¶meters_oid)) +//! }; +//! +//! // Encode +//! let der_encoded_algorithm_identifier = algorithm_identifier.to_der().unwrap(); +//! +//! // Decode +//! let decoded_algorithm_identifier = AlgorithmIdentifier::from_der( +//! &der_encoded_algorithm_identifier +//! ).unwrap(); +//! +//! assert_eq!(algorithm_identifier, decoded_algorithm_identifier); +//! # } +//! ``` +//! +//! For fields which don't directly impl [`Decode`] and [`Encode`], +//! you can add annotations to convert to an intermediate ASN.1 type +//! first, so long as that type impls `TryFrom` and `Into` for the +//! ASN.1 type. +//! +//! For example, structs containing `&'a [u8]` fields may want them encoded +//! as either a `BIT STRING` or `OCTET STRING`. By using the +//! `#[asn1(type = "BIT STRING")]` annotation it's possible to select which +//! ASN.1 type should be used. +//! +//! Building off the above example: +//! +//! ```rust +//! # #[cfg(all(feature = "alloc", feature = "derive", feature = "oid"))] +//! # { +//! # use der::{asn1::{AnyRef, BitStringRef, ObjectIdentifier}, Sequence}; +//! # +//! # #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence)] +//! # pub struct AlgorithmIdentifier<'a> { +//! # pub algorithm: ObjectIdentifier, +//! # pub parameters: Option> +//! # } +//! /// X.509 `SubjectPublicKeyInfo` (SPKI) +//! #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence)] +//! pub struct SubjectPublicKeyInfo<'a> { +//! /// X.509 `AlgorithmIdentifier` +//! pub algorithm: AlgorithmIdentifier<'a>, +//! +//! /// Public key data +//! pub subject_public_key: BitStringRef<'a>, +//! } +//! # } +//! ``` +//! +//! # See also +//! For more information about ASN.1 DER we recommend the following guides: +//! +//! - [A Layman's Guide to a Subset of ASN.1, BER, and DER] (RSA Laboratories) +//! - [A Warm Welcome to ASN.1 and DER] (Let's Encrypt) +//! +//! [RFC 5280 Section 4.1.1.2]: https://tools.ietf.org/html/rfc5280#section-4.1.1.2 +//! [A Layman's Guide to a Subset of ASN.1, BER, and DER]: https://luca.ntop.org/Teaching/Appunti/asn1.html +//! [A Warm Welcome to ASN.1 and DER]: https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/ +//! +//! [`Any`]: asn1::Any +//! [`AnyRef`]: asn1::AnyRef +//! [`ContextSpecific`]: asn1::ContextSpecific +//! [`ContextSpecificRef`]: asn1::ContextSpecificRef +//! [`BitString`]: asn1::BitString +//! [`BitStringRef`]: asn1::BitStringRef +//! [`GeneralizedTime`]: asn1::GeneralizedTime +//! [`Ia5StringRef`]: asn1::Ia5StringRef +//! [`Null`]: asn1::Null +//! [`ObjectIdentifier`]: asn1::ObjectIdentifier +//! [`OctetString`]: asn1::OctetString +//! [`OctetStringRef`]: asn1::OctetStringRef +//! [`PrintableStringRef`]: asn1::PrintableStringRef +//! [`TeletexStringRef`]: asn1::TeletexStringRef +//! [`VideotexStringRef`]: asn1::VideotexStringRef +//! [`SequenceOf`]: asn1::SequenceOf +//! [`SetOf`]: asn1::SetOf +//! [`SetOfVec`]: asn1::SetOfVec +//! [`UintRef`]: asn1::UintRef +//! [`UtcTime`]: asn1::UtcTime +//! [`Utf8StringRef`]: asn1::Utf8StringRef + +#[cfg(feature = "alloc")] +#[allow(unused_imports)] +#[macro_use] +extern crate alloc; +#[cfg(feature = "std")] +extern crate std; + +pub mod asn1; +pub mod referenced; + +pub(crate) mod arrayvec; +mod bytes_ref; +mod datetime; +mod decode; +mod encode; +mod encode_ref; +mod error; +mod header; +mod length; +mod ord; +mod reader; +mod str_ref; +mod tag; +mod writer; + +#[cfg(feature = "alloc")] +mod bytes_owned; +#[cfg(feature = "alloc")] +mod document; +#[cfg(feature = "alloc")] +mod str_owned; + +pub use crate::{ + asn1::{AnyRef, Choice, Sequence}, + datetime::DateTime, + decode::{Decode, DecodeOwned, DecodeValue}, + encode::{Encode, EncodeValue}, + encode_ref::{EncodeRef, EncodeValueRef}, + error::{Error, ErrorKind, Result}, + header::Header, + length::{IndefiniteLength, Length}, + ord::{DerOrd, ValueOrd}, + reader::{nested::NestedReader, slice::SliceReader, Reader}, + tag::{Class, FixedTag, Tag, TagMode, TagNumber, Tagged}, + writer::{slice::SliceWriter, Writer}, +}; + +#[cfg(feature = "alloc")] +pub use crate::{asn1::Any, document::Document}; + +#[cfg(feature = "bigint")] +pub use crypto_bigint as bigint; + +#[cfg(feature = "derive")] +pub use der_derive::{Choice, Enumerated, Sequence, ValueOrd}; + +#[cfg(feature = "flagset")] +pub use flagset; + +#[cfg(feature = "oid")] +pub use const_oid as oid; + +#[cfg(feature = "pem")] +pub use { + crate::{decode::DecodePem, encode::EncodePem, reader::pem::PemReader, writer::pem::PemWriter}, + pem_rfc7468 as pem, +}; + +#[cfg(feature = "time")] +pub use time; + +#[cfg(feature = "zeroize")] +pub use zeroize; + +#[cfg(all(feature = "alloc", feature = "zeroize"))] +pub use crate::document::SecretDocument; + +pub(crate) use crate::{arrayvec::ArrayVec, bytes_ref::BytesRef, str_ref::StrRef}; +#[cfg(feature = "alloc")] +pub(crate) use crate::{bytes_owned::BytesOwned, str_owned::StrOwned}; diff --git a/src/rust/vendor/der/src/ord.rs b/src/rust/vendor/der/src/ord.rs new file mode 100644 index 000000000..42d462340 --- /dev/null +++ b/src/rust/vendor/der/src/ord.rs @@ -0,0 +1,85 @@ +//! Ordering trait. + +use crate::{EncodeValue, Result, Tagged}; +use core::{cmp::Ordering, marker::PhantomData}; + +/// DER ordering trait. +/// +/// Compares the ordering of two values based on their ASN.1 DER +/// serializations. +/// +/// This is used by the DER encoding for `SET OF` in order to establish an +/// ordering for the elements of sets. +pub trait DerOrd { + /// Return an [`Ordering`] between `self` and `other` when serialized as + /// ASN.1 DER. + fn der_cmp(&self, other: &Self) -> Result; +} + +/// DER value ordering trait. +/// +/// Compares the ordering of the value portion of TLV-encoded DER productions. +pub trait ValueOrd { + /// Return an [`Ordering`] between value portion of TLV-encoded `self` and + /// `other` when serialized as ASN.1 DER. + fn value_cmp(&self, other: &Self) -> Result; +} + +impl DerOrd for T +where + T: EncodeValue + ValueOrd + Tagged, +{ + fn der_cmp(&self, other: &Self) -> Result { + match self.header()?.der_cmp(&other.header()?)? { + Ordering::Equal => self.value_cmp(other), + ordering => Ok(ordering), + } + } +} + +/// Marker trait for types whose `Ord` impl can be used as `ValueOrd`. +/// +/// This means the `Ord` impl will sort values in the same order as their DER +/// encodings. +pub trait OrdIsValueOrd: Ord {} + +impl ValueOrd for T +where + T: OrdIsValueOrd, +{ + fn value_cmp(&self, other: &Self) -> Result { + Ok(self.cmp(other)) + } +} + +/// Compare the order of two iterators using [`DerCmp`] on the values. +pub(crate) fn iter_cmp<'a, I, T: 'a>(a: I, b: I) -> Result +where + I: Iterator + ExactSizeIterator, + T: DerOrd, +{ + let length_ord = a.len().cmp(&b.len()); + + for (value1, value2) in a.zip(b) { + match value1.der_cmp(value2)? { + Ordering::Equal => (), + other => return Ok(other), + } + } + + Ok(length_ord) +} + +/// Provide a no-op implementation for PhantomData +impl ValueOrd for PhantomData { + fn value_cmp(&self, _other: &Self) -> Result { + Ok(Ordering::Equal) + } +} + +/// Provide a no-op implementation for PhantomData +impl DerOrd for PhantomData { + fn der_cmp(&self, _other: &Self) -> Result { + Ok(Ordering::Equal) + } +} diff --git a/src/rust/vendor/der/src/reader.rs b/src/rust/vendor/der/src/reader.rs new file mode 100644 index 000000000..ea52f7bde --- /dev/null +++ b/src/rust/vendor/der/src/reader.rs @@ -0,0 +1,167 @@ +//! Reader trait. + +pub(crate) mod nested; +#[cfg(feature = "pem")] +pub(crate) mod pem; +pub(crate) mod slice; + +pub(crate) use nested::NestedReader; + +use crate::{ + asn1::ContextSpecific, Decode, DecodeValue, Encode, Error, ErrorKind, FixedTag, Header, Length, + Result, Tag, TagMode, TagNumber, +}; + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +/// Reader trait which reads DER-encoded input. +pub trait Reader<'r>: Sized { + /// Get the length of the input. + fn input_len(&self) -> Length; + + /// Peek at the next byte of input without modifying the cursor. + fn peek_byte(&self) -> Option; + + /// Peek forward in the input data, attempting to decode a [`Header`] from + /// the data at the current position in the decoder. + /// + /// Does not modify the decoder's state. + fn peek_header(&self) -> Result
; + + /// Get the position within the buffer. + fn position(&self) -> Length; + + /// Attempt to read data borrowed directly from the input as a slice, + /// updating the internal cursor position. + /// + /// # Returns + /// - `Ok(slice)` on success + /// - `Err(ErrorKind::Incomplete)` if there is not enough data + /// - `Err(ErrorKind::Reader)` if the reader can't borrow from the input + fn read_slice(&mut self, len: Length) -> Result<&'r [u8]>; + + /// Attempt to decode an ASN.1 `CONTEXT-SPECIFIC` field with the + /// provided [`TagNumber`]. + fn context_specific(&mut self, tag_number: TagNumber, tag_mode: TagMode) -> Result> + where + T: DecodeValue<'r> + FixedTag, + { + Ok(match tag_mode { + TagMode::Explicit => ContextSpecific::::decode_explicit(self, tag_number)?, + TagMode::Implicit => ContextSpecific::::decode_implicit(self, tag_number)?, + } + .map(|field| field.value)) + } + + /// Decode a value which impls the [`Decode`] trait. + fn decode>(&mut self) -> Result { + T::decode(self).map_err(|e| e.nested(self.position())) + } + + /// Return an error with the given [`ErrorKind`], annotating it with + /// context about where the error occurred. + fn error(&mut self, kind: ErrorKind) -> Error { + kind.at(self.position()) + } + + /// Finish decoding, returning the given value if there is no + /// remaining data, or an error otherwise + fn finish(self, value: T) -> Result { + if !self.is_finished() { + Err(ErrorKind::TrailingData { + decoded: self.position(), + remaining: self.remaining_len(), + } + .at(self.position())) + } else { + Ok(value) + } + } + + /// Have we read all of the input data? + fn is_finished(&self) -> bool { + self.remaining_len().is_zero() + } + + /// Offset within the original input stream. + /// + /// This is used for error reporting, and doesn't need to be overridden + /// by any reader implementations (except for the built-in `NestedReader`, + /// which consumes nested input messages) + fn offset(&self) -> Length { + self.position() + } + + /// Peek at the next byte in the decoder and attempt to decode it as a + /// [`Tag`] value. + /// + /// Does not modify the decoder's state. + fn peek_tag(&self) -> Result { + match self.peek_byte() { + Some(byte) => byte.try_into(), + None => Err(Error::incomplete(self.input_len())), + } + } + + /// Read a single byte. + fn read_byte(&mut self) -> Result { + let mut buf = [0]; + self.read_into(&mut buf)?; + Ok(buf[0]) + } + + /// Attempt to read input data, writing it into the provided buffer, and + /// returning a slice on success. + /// + /// # Returns + /// - `Ok(slice)` if there is sufficient data + /// - `Err(ErrorKind::Incomplete)` if there is not enough data + fn read_into<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> { + let input = self.read_slice(buf.len().try_into()?)?; + buf.copy_from_slice(input); + Ok(buf) + } + + /// Read nested data of the given length. + fn read_nested<'n, T, F>(&'n mut self, len: Length, f: F) -> Result + where + F: FnOnce(&mut NestedReader<'n, Self>) -> Result, + { + let mut reader = NestedReader::new(self, len)?; + let ret = f(&mut reader)?; + reader.finish(ret) + } + + /// Read a byte vector of the given length. + #[cfg(feature = "alloc")] + fn read_vec(&mut self, len: Length) -> Result> { + let mut bytes = vec![0u8; usize::try_from(len)?]; + self.read_into(&mut bytes)?; + Ok(bytes) + } + + /// Get the number of bytes still remaining in the buffer. + fn remaining_len(&self) -> Length { + debug_assert!(self.position() <= self.input_len()); + self.input_len().saturating_sub(self.position()) + } + + /// Read an ASN.1 `SEQUENCE`, creating a nested [`Reader`] for the body and + /// calling the provided closure with it. + fn sequence<'n, F, T>(&'n mut self, f: F) -> Result + where + F: FnOnce(&mut NestedReader<'n, Self>) -> Result, + { + let header = Header::decode(self)?; + header.tag.assert_eq(Tag::Sequence)?; + self.read_nested(header.length, f) + } + + /// Obtain a slice of bytes contain a complete TLV production suitable for parsing later. + fn tlv_bytes(&mut self) -> Result<&'r [u8]> { + let header = self.peek_header()?; + let header_len = header.encoded_len()?; + self.read_slice((header_len + header.length)?) + } +} diff --git a/src/rust/vendor/der/src/reader/nested.rs b/src/rust/vendor/der/src/reader/nested.rs new file mode 100644 index 000000000..40ede69ac --- /dev/null +++ b/src/rust/vendor/der/src/reader/nested.rs @@ -0,0 +1,96 @@ +//! Reader type for consuming nested TLV records within a DER document. + +use crate::{reader::Reader, Error, ErrorKind, Header, Length, Result}; + +/// Reader type used by [`Reader::read_nested`]. +pub struct NestedReader<'i, R> { + /// Inner reader type. + inner: &'i mut R, + + /// Nested input length. + input_len: Length, + + /// Position within the nested input. + position: Length, +} + +impl<'i, 'r, R: Reader<'r>> NestedReader<'i, R> { + /// Create a new nested reader which can read the given [`Length`]. + pub(crate) fn new(inner: &'i mut R, len: Length) -> Result { + if len <= inner.remaining_len() { + Ok(Self { + inner, + input_len: len, + position: Length::ZERO, + }) + } else { + Err(ErrorKind::Incomplete { + expected_len: (inner.offset() + len)?, + actual_len: (inner.offset() + inner.remaining_len())?, + } + .at(inner.offset())) + } + } + + /// Move the position cursor the given length, returning an error if there + /// isn't enough remaining data in the nested input. + fn advance_position(&mut self, len: Length) -> Result<()> { + let new_position = (self.position + len)?; + + if new_position <= self.input_len { + self.position = new_position; + Ok(()) + } else { + Err(ErrorKind::Incomplete { + expected_len: (self.inner.offset() + len)?, + actual_len: (self.inner.offset() + self.remaining_len())?, + } + .at(self.inner.offset())) + } + } +} + +impl<'i, 'r, R: Reader<'r>> Reader<'r> for NestedReader<'i, R> { + fn input_len(&self) -> Length { + self.input_len + } + + fn peek_byte(&self) -> Option { + if self.is_finished() { + None + } else { + self.inner.peek_byte() + } + } + + fn peek_header(&self) -> Result
{ + if self.is_finished() { + Err(Error::incomplete(self.offset())) + } else { + // TODO(tarcieri): handle peeking past nested length + self.inner.peek_header() + } + } + + fn position(&self) -> Length { + self.position + } + + fn read_slice(&mut self, len: Length) -> Result<&'r [u8]> { + self.advance_position(len)?; + self.inner.read_slice(len) + } + + fn error(&mut self, kind: ErrorKind) -> Error { + self.inner.error(kind) + } + + fn offset(&self) -> Length { + self.inner.offset() + } + + fn read_into<'o>(&mut self, out: &'o mut [u8]) -> Result<&'o [u8]> { + self.advance_position(Length::try_from(out.len())?)?; + self.inner.read_into(out) + } +} diff --git a/src/rust/vendor/der/src/reader/pem.rs b/src/rust/vendor/der/src/reader/pem.rs new file mode 100644 index 000000000..f11341aa6 --- /dev/null +++ b/src/rust/vendor/der/src/reader/pem.rs @@ -0,0 +1,206 @@ +//! Streaming PEM reader. + +use super::Reader; +use crate::{Decode, Error, ErrorKind, Header, Length, Result}; +use core::cell::RefCell; + +#[allow(clippy::integer_arithmetic)] +mod utils { + use crate::{Error, Length, Result}; + use pem_rfc7468::Decoder; + + #[derive(Clone)] + pub(super) struct BufReader<'i> { + /// Inner PEM decoder. + decoder: Decoder<'i>, + + /// Remaining after base64 decoding + remaining: usize, + + /// Read buffer + buf: [u8; BufReader::CAPACITY], + + /// Position of the head in the buffer, + pos: usize, + + /// Position of the tail in the buffer, + cap: usize, + } + + impl<'i> BufReader<'i> { + const CAPACITY: usize = 256; + + pub fn new(pem: &'i [u8]) -> Result { + let decoder = Decoder::new(pem)?; + let remaining = decoder.remaining_len(); + + Ok(Self { + decoder, + remaining, + buf: [0u8; 256], + pos: 0, + cap: 0, + }) + } + + pub fn remaining_len(&self) -> usize { + self.decoder.remaining_len() + self.cap - self.pos + } + + fn fill_buffer(&mut self) -> Result<()> { + debug_assert!(self.pos <= self.cap); + + if self.is_empty() { + self.pos = 0; + self.cap = 0; + } + + let end = (self.cap + self.remaining).min(Self::CAPACITY); + let writable_slice = &mut self.buf[self.cap..end]; + if writable_slice.is_empty() { + return Ok(()); + } + + let wrote = self.decoder.decode(writable_slice)?.len(); + if wrote == 0 { + return Err(Error::incomplete(Length::try_from(self.pos)?)); + } + + self.cap += wrote; + self.remaining -= wrote; + debug_assert!(self.cap <= Self::CAPACITY); + + Ok(()) + } + + /// Get the PEM label which will be used in the encapsulation boundaries + /// for this document. + pub fn type_label(&self) -> &'i str { + self.decoder.type_label() + } + + fn is_empty(&self) -> bool { + self.pos == self.cap + } + + fn as_slice(&self) -> &[u8] { + &self.buf[self.pos..self.cap] + } + } + + impl<'i> BufReader<'i> { + pub fn peek_byte(&self) -> Option { + let s = self.as_slice(); + s.first().copied() + } + + pub fn copy_to_slice<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> { + let mut output_pos = 0; + + while output_pos < buf.len() { + if self.is_empty() { + self.fill_buffer()?; + } + + let available = &self.buf[self.pos..self.cap]; + let window_len = (buf.len() - output_pos).min(available.len()); + let window = &mut buf[output_pos..output_pos + window_len]; + + window.copy_from_slice(&available[..window_len]); + self.pos += window_len; + output_pos += window_len; + } + + // Don't leave the read buffer empty for peek_byte() + if self.is_empty() && self.decoder.remaining_len() != 0 { + self.fill_buffer()? + } + + debug_assert_eq!(output_pos, buf.len()); + + Ok(buf) + } + } +} + +/// `Reader` type which decodes PEM on-the-fly. +#[cfg(feature = "pem")] +#[derive(Clone)] +pub struct PemReader<'i> { + /// Inner PEM decoder wrapped in a BufReader. + reader: RefCell>, + + /// Input length (in bytes after Base64 decoding). + input_len: Length, + + /// Position in the input buffer (in bytes after Base64 decoding). + position: Length, +} + +#[cfg(feature = "pem")] +impl<'i> PemReader<'i> { + /// Create a new PEM reader which decodes data on-the-fly. + /// + /// Uses the default 64-character line wrapping. + pub fn new(pem: &'i [u8]) -> Result { + let reader = utils::BufReader::new(pem)?; + let input_len = Length::try_from(reader.remaining_len())?; + + Ok(Self { + reader: RefCell::new(reader), + input_len, + position: Length::ZERO, + }) + } + + /// Get the PEM label which will be used in the encapsulation boundaries + /// for this document. + pub fn type_label(&self) -> &'i str { + self.reader.borrow().type_label() + } +} + +#[cfg(feature = "pem")] +impl<'i> Reader<'i> for PemReader<'i> { + fn input_len(&self) -> Length { + self.input_len + } + + fn peek_byte(&self) -> Option { + if self.is_finished() { + None + } else { + self.reader.borrow().peek_byte() + } + } + + fn peek_header(&self) -> Result
{ + if self.is_finished() { + Err(Error::incomplete(self.offset())) + } else { + Header::decode(&mut self.clone()) + } + } + + fn position(&self) -> Length { + self.position + } + + fn read_slice(&mut self, _len: Length) -> Result<&'i [u8]> { + // Can't borrow from PEM because it requires decoding + Err(ErrorKind::Reader.into()) + } + + fn read_into<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> { + let bytes = self.reader.borrow_mut().copy_to_slice(buf)?; + + self.position = (self.position + bytes.len())?; + + debug_assert_eq!( + self.position, + (self.input_len - Length::try_from(self.reader.borrow().remaining_len())?)? + ); + + Ok(bytes) + } +} diff --git a/src/rust/vendor/der/src/reader/slice.rs b/src/rust/vendor/der/src/reader/slice.rs new file mode 100644 index 000000000..e78468fed --- /dev/null +++ b/src/rust/vendor/der/src/reader/slice.rs @@ -0,0 +1,214 @@ +//! Slice reader. + +use crate::{BytesRef, Decode, Error, ErrorKind, Header, Length, Reader, Result, Tag}; + +/// [`Reader`] which consumes an input byte slice. +#[derive(Clone, Debug)] +pub struct SliceReader<'a> { + /// Byte slice being decoded. + bytes: BytesRef<'a>, + + /// Did the decoding operation fail? + failed: bool, + + /// Position within the decoded slice. + position: Length, +} + +impl<'a> SliceReader<'a> { + /// Create a new slice reader for the given byte slice. + pub fn new(bytes: &'a [u8]) -> Result { + Ok(Self { + bytes: BytesRef::new(bytes)?, + failed: false, + position: Length::ZERO, + }) + } + + /// Return an error with the given [`ErrorKind`], annotating it with + /// context about where the error occurred. + pub fn error(&mut self, kind: ErrorKind) -> Error { + self.failed = true; + kind.at(self.position) + } + + /// Return an error for an invalid value with the given tag. + pub fn value_error(&mut self, tag: Tag) -> Error { + self.error(tag.value_error().kind()) + } + + /// Did the decoding operation fail due to an error? + pub fn is_failed(&self) -> bool { + self.failed + } + + /// Obtain the remaining bytes in this slice reader from the current cursor + /// position. + fn remaining(&self) -> Result<&'a [u8]> { + if self.is_failed() { + Err(ErrorKind::Failed.at(self.position)) + } else { + self.bytes + .as_slice() + .get(self.position.try_into()?..) + .ok_or_else(|| Error::incomplete(self.input_len())) + } + } +} + +impl<'a> Reader<'a> for SliceReader<'a> { + fn input_len(&self) -> Length { + self.bytes.len() + } + + fn peek_byte(&self) -> Option { + self.remaining() + .ok() + .and_then(|bytes| bytes.first().cloned()) + } + + fn peek_header(&self) -> Result
{ + Header::decode(&mut self.clone()) + } + + fn position(&self) -> Length { + self.position + } + + fn read_slice(&mut self, len: Length) -> Result<&'a [u8]> { + if self.is_failed() { + return Err(self.error(ErrorKind::Failed)); + } + + match self.remaining()?.get(..len.try_into()?) { + Some(result) => { + self.position = (self.position + len)?; + Ok(result) + } + None => Err(self.error(ErrorKind::Incomplete { + expected_len: (self.position + len)?, + actual_len: self.input_len(), + })), + } + } + + fn decode>(&mut self) -> Result { + if self.is_failed() { + return Err(self.error(ErrorKind::Failed)); + } + + T::decode(self).map_err(|e| { + self.failed = true; + e.nested(self.position) + }) + } + + fn error(&mut self, kind: ErrorKind) -> Error { + self.failed = true; + kind.at(self.position) + } + + fn finish(self, value: T) -> Result { + if self.is_failed() { + Err(ErrorKind::Failed.at(self.position)) + } else if !self.is_finished() { + Err(ErrorKind::TrailingData { + decoded: self.position, + remaining: self.remaining_len(), + } + .at(self.position)) + } else { + Ok(value) + } + } + + fn remaining_len(&self) -> Length { + debug_assert!(self.position <= self.input_len()); + self.input_len().saturating_sub(self.position) + } +} + +#[cfg(test)] +mod tests { + use super::SliceReader; + use crate::{Decode, ErrorKind, Length, Reader, Tag}; + use hex_literal::hex; + + // INTEGER: 42 + const EXAMPLE_MSG: &[u8] = &hex!("02012A00"); + + #[test] + fn empty_message() { + let mut reader = SliceReader::new(&[]).unwrap(); + let err = bool::decode(&mut reader).err().unwrap(); + assert_eq!(Some(Length::ZERO), err.position()); + + match err.kind() { + ErrorKind::Incomplete { + expected_len, + actual_len, + } => { + assert_eq!(actual_len, 0u8.into()); + assert_eq!(expected_len, 1u8.into()); + } + other => panic!("unexpected error kind: {:?}", other), + } + } + + #[test] + fn invalid_field_length() { + const MSG_LEN: usize = 2; + + let mut reader = SliceReader::new(&EXAMPLE_MSG[..MSG_LEN]).unwrap(); + let err = i8::decode(&mut reader).err().unwrap(); + assert_eq!(Some(Length::from(2u8)), err.position()); + + match err.kind() { + ErrorKind::Incomplete { + expected_len, + actual_len, + } => { + assert_eq!(actual_len, MSG_LEN.try_into().unwrap()); + assert_eq!(expected_len, (MSG_LEN + 1).try_into().unwrap()); + } + other => panic!("unexpected error kind: {:?}", other), + } + } + + #[test] + fn trailing_data() { + let mut reader = SliceReader::new(EXAMPLE_MSG).unwrap(); + let x = i8::decode(&mut reader).unwrap(); + assert_eq!(42i8, x); + + let err = reader.finish(x).err().unwrap(); + assert_eq!(Some(Length::from(3u8)), err.position()); + + assert_eq!( + ErrorKind::TrailingData { + decoded: 3u8.into(), + remaining: 1u8.into() + }, + err.kind() + ); + } + + #[test] + fn peek_tag() { + let reader = SliceReader::new(EXAMPLE_MSG).unwrap(); + assert_eq!(reader.position(), Length::ZERO); + assert_eq!(reader.peek_tag().unwrap(), Tag::Integer); + assert_eq!(reader.position(), Length::ZERO); // Position unchanged + } + + #[test] + fn peek_header() { + let reader = SliceReader::new(EXAMPLE_MSG).unwrap(); + assert_eq!(reader.position(), Length::ZERO); + + let header = reader.peek_header().unwrap(); + assert_eq!(header.tag, Tag::Integer); + assert_eq!(header.length, Length::ONE); + assert_eq!(reader.position(), Length::ZERO); // Position unchanged + } +} diff --git a/src/rust/vendor/der/src/referenced.rs b/src/rust/vendor/der/src/referenced.rs new file mode 100644 index 000000000..b0c8f0325 --- /dev/null +++ b/src/rust/vendor/der/src/referenced.rs @@ -0,0 +1,69 @@ +//! A module for working with referenced data. + +/// A trait for borrowing data from an owned struct +pub trait OwnedToRef { + /// The resulting type referencing back to Self + type Borrowed<'a> + where + Self: 'a; + + /// Creates a new object referencing back to the self for storage + fn owned_to_ref(&self) -> Self::Borrowed<'_>; +} + +/// A trait for cloning a referenced structure and getting owned objects +/// +/// This is the pendant to [`OwnedToRef`] +pub trait RefToOwned<'a> { + /// The resulting type after obtaining ownership. + type Owned: OwnedToRef = Self> + where + Self: 'a; + + /// Creates a new object taking ownership of the data + fn ref_to_owned(&self) -> Self::Owned; +} + +impl OwnedToRef for Option +where + T: OwnedToRef, +{ + type Borrowed<'a> = Option> where T: 'a; + + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + self.as_ref().map(|o| o.owned_to_ref()) + } +} + +impl<'a, T> RefToOwned<'a> for Option +where + T: RefToOwned<'a> + 'a, + T::Owned: OwnedToRef, +{ + type Owned = Option; + fn ref_to_owned(&self) -> Self::Owned { + self.as_ref().map(|o| o.ref_to_owned()) + } +} + +#[cfg(feature = "alloc")] +mod allocating { + use super::{OwnedToRef, RefToOwned}; + use alloc::boxed::Box; + + impl<'a> RefToOwned<'a> for &'a [u8] { + type Owned = Box<[u8]>; + + fn ref_to_owned(&self) -> Self::Owned { + Box::from(*self) + } + } + + impl OwnedToRef for Box<[u8]> { + type Borrowed<'a> = &'a [u8]; + + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + self.as_ref() + } + } +} diff --git a/src/rust/vendor/der/src/str_owned.rs b/src/rust/vendor/der/src/str_owned.rs new file mode 100644 index 000000000..20bfea5bd --- /dev/null +++ b/src/rust/vendor/der/src/str_owned.rs @@ -0,0 +1,104 @@ +//! Common handling for types backed by `String` with enforcement of a +//! library-level length limitation i.e. `Length::max()`. + +use crate::{ + referenced::OwnedToRef, BytesRef, DecodeValue, EncodeValue, Header, Length, Reader, Result, + StrRef, Writer, +}; +use alloc::string::String; +use core::str; + +/// String newtype which respects the [`Length::max`] limit. +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct StrOwned { + /// Inner value + pub(crate) inner: String, + + /// Precomputed `Length` (avoids possible panicking conversions) + pub(crate) length: Length, +} + +impl StrOwned { + /// Create a new [`StrOwned`], ensuring that the byte representation of + /// the provided `str` value is shorter than `Length::max()`. + pub fn new(s: String) -> Result { + let length = Length::try_from(s.as_bytes().len())?; + + Ok(Self { inner: s, length }) + } + + /// Parse a [`String`] from UTF-8 encoded bytes. + pub fn from_bytes(bytes: &[u8]) -> Result { + Ok(Self { + inner: String::from_utf8(bytes.to_vec())?, + length: Length::try_from(bytes.len())?, + }) + } + + /// Borrow the inner `str` + pub fn as_str(&self) -> &str { + &self.inner + } + + /// Borrow the inner byte slice + pub fn as_bytes(&self) -> &[u8] { + self.inner.as_bytes() + } + + /// Get the [`Length`] of this [`StrOwned`] + pub fn len(&self) -> Length { + self.length + } + + /// Is this [`StrOwned`] empty? + pub fn is_empty(&self) -> bool { + self.len() == Length::ZERO + } +} + +impl AsRef for StrOwned { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl AsRef<[u8]> for StrOwned { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<'a> DecodeValue<'a> for StrOwned { + fn decode_value>(reader: &mut R, header: Header) -> Result { + Self::from_bytes(BytesRef::decode_value(reader, header)?.as_slice()) + } +} + +impl EncodeValue for StrOwned { + fn value_len(&self) -> Result { + Ok(self.length) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.as_ref()) + } +} + +impl From> for StrOwned { + fn from(s: StrRef<'_>) -> StrOwned { + Self { + inner: String::from(s.inner), + length: s.length, + } + } +} + +impl OwnedToRef for StrOwned { + type Borrowed<'a> = StrRef<'a>; + fn owned_to_ref(&self) -> Self::Borrowed<'_> { + StrRef { + length: self.length, + inner: self.inner.as_ref(), + } + } +} diff --git a/src/rust/vendor/der/src/str_ref.rs b/src/rust/vendor/der/src/str_ref.rs new file mode 100644 index 000000000..899c7506b --- /dev/null +++ b/src/rust/vendor/der/src/str_ref.rs @@ -0,0 +1,92 @@ +//! Common handling for types backed by `str` slices with enforcement of a +//! library-level length limitation i.e. `Length::max()`. + +use crate::{BytesRef, DecodeValue, EncodeValue, Header, Length, Reader, Result, Writer}; +use core::str; + +/// String slice newtype which respects the [`Length::max`] limit. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct StrRef<'a> { + /// Inner value + pub(crate) inner: &'a str, + + /// Precomputed `Length` (avoids possible panicking conversions) + pub(crate) length: Length, +} + +impl<'a> StrRef<'a> { + /// Create a new [`StrRef`], ensuring that the byte representation of + /// the provided `str` value is shorter than `Length::max()`. + pub fn new(s: &'a str) -> Result { + Ok(Self { + inner: s, + length: Length::try_from(s.as_bytes().len())?, + }) + } + + /// Parse a [`StrRef`] from UTF-8 encoded bytes. + pub fn from_bytes(bytes: &'a [u8]) -> Result { + Self::new(str::from_utf8(bytes)?) + } + + /// Borrow the inner `str` + pub fn as_str(&self) -> &'a str { + self.inner + } + + /// Borrow the inner byte slice + pub fn as_bytes(&self) -> &'a [u8] { + self.inner.as_bytes() + } + + /// Get the [`Length`] of this [`StrRef`] + pub fn len(self) -> Length { + self.length + } + + /// Is this [`StrRef`] empty? + pub fn is_empty(self) -> bool { + self.len() == Length::ZERO + } +} + +impl AsRef for StrRef<'_> { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl AsRef<[u8]> for StrRef<'_> { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<'a> DecodeValue<'a> for StrRef<'a> { + fn decode_value>(reader: &mut R, header: Header) -> Result { + Self::from_bytes(BytesRef::decode_value(reader, header)?.as_slice()) + } +} + +impl<'a> EncodeValue for StrRef<'a> { + fn value_len(&self) -> Result { + Ok(self.length) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.as_ref()) + } +} + +#[cfg(feature = "alloc")] +mod allocating { + use super::StrRef; + use crate::{referenced::RefToOwned, StrOwned}; + + impl<'a> RefToOwned<'a> for StrRef<'a> { + type Owned = StrOwned; + fn ref_to_owned(&self) -> Self::Owned { + StrOwned::from(*self) + } + } +} diff --git a/src/rust/vendor/der/src/tag.rs b/src/rust/vendor/der/src/tag.rs new file mode 100644 index 000000000..7a1fed1b7 --- /dev/null +++ b/src/rust/vendor/der/src/tag.rs @@ -0,0 +1,460 @@ +//! ASN.1 tags. +#![cfg_attr(feature = "arbitrary", allow(clippy::integer_arithmetic))] + +mod class; +mod mode; +mod number; + +pub use self::{class::Class, mode::TagMode, number::TagNumber}; + +use crate::{Decode, DerOrd, Encode, Error, ErrorKind, Length, Reader, Result, Writer}; +use core::{cmp::Ordering, fmt}; + +/// Indicator bit for constructed form encoding (i.e. vs primitive form) +const CONSTRUCTED_FLAG: u8 = 0b100000; + +/// Types which have a constant ASN.1 [`Tag`]. +pub trait FixedTag { + /// ASN.1 tag + const TAG: Tag; +} + +/// Types which have an ASN.1 [`Tag`]. +pub trait Tagged { + /// Get the ASN.1 tag that this type is encoded with. + fn tag(&self) -> Tag; +} + +/// Types which are [`FixedTag`] always have a known [`Tag`] type. +impl Tagged for T { + fn tag(&self) -> Tag { + T::TAG + } +} + +/// ASN.1 tags. +/// +/// Tags are the leading identifier octet of the Tag-Length-Value encoding +/// used by ASN.1 DER and identify the type of the subsequent value. +/// +/// They are described in X.690 Section 8.1.2: Identifier octets, and +/// structured as follows: +/// +/// ```text +/// | Class | P/C | Tag Number | +/// ``` +/// +/// - Bits 8/7: [`Class`] +/// - Bit 6: primitive (0) or constructed (1) +/// - Bits 5-1: tag number +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] +#[non_exhaustive] +pub enum Tag { + /// `BOOLEAN` tag: `1`. + Boolean, + + /// `INTEGER` tag: `2`. + Integer, + + /// `BIT STRING` tag: `3`. + BitString, + + /// `OCTET STRING` tag: `4`. + OctetString, + + /// `NULL` tag: `5`. + Null, + + /// `OBJECT IDENTIFIER` tag: `6`. + ObjectIdentifier, + + /// `REAL` tag: `9`. + Real, + + /// `ENUMERATED` tag: `10`. + Enumerated, + + /// `UTF8String` tag: `12`. + Utf8String, + + /// `SEQUENCE` tag: `16`. + Sequence, + + /// `SET` and `SET OF` tag: `17`. + Set, + + /// `NumericString` tag: `18`. + NumericString, + + /// `PrintableString` tag: `19`. + PrintableString, + + /// `TeletexString` tag: `20`. + TeletexString, + + /// `VideotexString` tag: `21`. + VideotexString, + + /// `IA5String` tag: `22`. + Ia5String, + + /// `UTCTime` tag: `23`. + UtcTime, + + /// `GeneralizedTime` tag: `24`. + GeneralizedTime, + + /// `VisibleString` tag: `26`. + VisibleString, + + /// `BMPString` tag: `30`. + BmpString, + + /// Application tag. + Application { + /// Is this tag constructed? (vs primitive). + constructed: bool, + + /// Tag number. + number: TagNumber, + }, + + /// Context-specific tag. + ContextSpecific { + /// Is this tag constructed? (vs primitive). + constructed: bool, + + /// Tag number. + number: TagNumber, + }, + + /// Private tag number. + Private { + /// Is this tag constructed? (vs primitive). + constructed: bool, + + /// Tag number. + number: TagNumber, + }, +} + +impl Tag { + /// Assert that this [`Tag`] matches the provided expected tag. + /// + /// On mismatch, returns an [`Error`] with [`ErrorKind::TagUnexpected`]. + pub fn assert_eq(self, expected: Tag) -> Result { + if self == expected { + Ok(self) + } else { + Err(self.unexpected_error(Some(expected))) + } + } + + /// Get the [`Class`] that corresponds to this [`Tag`]. + pub fn class(self) -> Class { + match self { + Tag::Application { .. } => Class::Application, + Tag::ContextSpecific { .. } => Class::ContextSpecific, + Tag::Private { .. } => Class::Private, + _ => Class::Universal, + } + } + + /// Get the [`TagNumber`] (lower 6-bits) for this tag. + pub fn number(self) -> TagNumber { + TagNumber(self.octet() & TagNumber::MASK) + } + + /// Does this tag represent a constructed (as opposed to primitive) field? + pub fn is_constructed(self) -> bool { + self.octet() & CONSTRUCTED_FLAG != 0 + } + + /// Is this an application tag? + pub fn is_application(self) -> bool { + self.class() == Class::Application + } + + /// Is this a context-specific tag? + pub fn is_context_specific(self) -> bool { + self.class() == Class::ContextSpecific + } + + /// Is this a private tag? + pub fn is_private(self) -> bool { + self.class() == Class::Private + } + + /// Is this a universal tag? + pub fn is_universal(self) -> bool { + self.class() == Class::Universal + } + + /// Get the octet encoding for this [`Tag`]. + pub fn octet(self) -> u8 { + match self { + Tag::Boolean => 0x01, + Tag::Integer => 0x02, + Tag::BitString => 0x03, + Tag::OctetString => 0x04, + Tag::Null => 0x05, + Tag::ObjectIdentifier => 0x06, + Tag::Real => 0x09, + Tag::Enumerated => 0x0A, + Tag::Utf8String => 0x0C, + Tag::Sequence => 0x10 | CONSTRUCTED_FLAG, + Tag::Set => 0x11 | CONSTRUCTED_FLAG, + Tag::NumericString => 0x12, + Tag::PrintableString => 0x13, + Tag::TeletexString => 0x14, + Tag::VideotexString => 0x15, + Tag::Ia5String => 0x16, + Tag::UtcTime => 0x17, + Tag::GeneralizedTime => 0x18, + Tag::VisibleString => 0x1A, + Tag::BmpString => 0x1E, + Tag::Application { + constructed, + number, + } + | Tag::ContextSpecific { + constructed, + number, + } + | Tag::Private { + constructed, + number, + } => self.class().octet(constructed, number), + } + } + + /// Create an [`Error`] for an invalid [`Length`]. + pub fn length_error(self) -> Error { + ErrorKind::Length { tag: self }.into() + } + + /// Create an [`Error`] for an non-canonical value with the ASN.1 type + /// identified by this tag. + pub fn non_canonical_error(self) -> Error { + ErrorKind::Noncanonical { tag: self }.into() + } + + /// Create an [`Error`] because the current tag was unexpected, with an + /// optional expected tag. + pub fn unexpected_error(self, expected: Option) -> Error { + ErrorKind::TagUnexpected { + expected, + actual: self, + } + .into() + } + + /// Create an [`Error`] for an invalid value with the ASN.1 type identified + /// by this tag. + pub fn value_error(self) -> Error { + ErrorKind::Value { tag: self }.into() + } +} + +impl TryFrom for Tag { + type Error = Error; + + fn try_from(byte: u8) -> Result { + let constructed = byte & CONSTRUCTED_FLAG != 0; + let number = TagNumber::try_from(byte & TagNumber::MASK)?; + + match byte { + 0x01 => Ok(Tag::Boolean), + 0x02 => Ok(Tag::Integer), + 0x03 => Ok(Tag::BitString), + 0x04 => Ok(Tag::OctetString), + 0x05 => Ok(Tag::Null), + 0x06 => Ok(Tag::ObjectIdentifier), + 0x09 => Ok(Tag::Real), + 0x0A => Ok(Tag::Enumerated), + 0x0C => Ok(Tag::Utf8String), + 0x12 => Ok(Tag::NumericString), + 0x13 => Ok(Tag::PrintableString), + 0x14 => Ok(Tag::TeletexString), + 0x15 => Ok(Tag::VideotexString), + 0x16 => Ok(Tag::Ia5String), + 0x17 => Ok(Tag::UtcTime), + 0x18 => Ok(Tag::GeneralizedTime), + 0x1A => Ok(Tag::VisibleString), + 0x1E => Ok(Tag::BmpString), + 0x30 => Ok(Tag::Sequence), // constructed + 0x31 => Ok(Tag::Set), // constructed + 0x40..=0x7E => Ok(Tag::Application { + constructed, + number, + }), + 0x80..=0xBE => Ok(Tag::ContextSpecific { + constructed, + number, + }), + 0xC0..=0xFE => Ok(Tag::Private { + constructed, + number, + }), + _ => Err(ErrorKind::TagUnknown { byte }.into()), + } + } +} + +impl From for u8 { + fn from(tag: Tag) -> u8 { + tag.octet() + } +} + +impl From<&Tag> for u8 { + fn from(tag: &Tag) -> u8 { + u8::from(*tag) + } +} + +impl<'a> Decode<'a> for Tag { + fn decode>(reader: &mut R) -> Result { + reader.read_byte().and_then(Self::try_from) + } +} + +impl Encode for Tag { + fn encoded_len(&self) -> Result { + Ok(Length::ONE) + } + + fn encode(&self, writer: &mut impl Writer) -> Result<()> { + writer.write_byte(self.into()) + } +} + +impl DerOrd for Tag { + fn der_cmp(&self, other: &Self) -> Result { + Ok(self.octet().cmp(&other.octet())) + } +} + +impl fmt::Display for Tag { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + const FIELD_TYPE: [&str; 2] = ["primitive", "constructed"]; + + match *self { + Tag::Boolean => f.write_str("BOOLEAN"), + Tag::Integer => f.write_str("INTEGER"), + Tag::BitString => f.write_str("BIT STRING"), + Tag::OctetString => f.write_str("OCTET STRING"), + Tag::Null => f.write_str("NULL"), + Tag::ObjectIdentifier => f.write_str("OBJECT IDENTIFIER"), + Tag::Real => f.write_str("REAL"), + Tag::Enumerated => f.write_str("ENUMERATED"), + Tag::Utf8String => f.write_str("UTF8String"), + Tag::Set => f.write_str("SET"), + Tag::NumericString => f.write_str("NumericString"), + Tag::PrintableString => f.write_str("PrintableString"), + Tag::TeletexString => f.write_str("TeletexString"), + Tag::VideotexString => f.write_str("VideotexString"), + Tag::Ia5String => f.write_str("IA5String"), + Tag::UtcTime => f.write_str("UTCTime"), + Tag::GeneralizedTime => f.write_str("GeneralizedTime"), + Tag::VisibleString => f.write_str("VisibleString"), + Tag::BmpString => f.write_str("BMPString"), + Tag::Sequence => f.write_str("SEQUENCE"), + Tag::Application { + constructed, + number, + } => write!( + f, + "APPLICATION [{}] ({})", + number, + FIELD_TYPE[usize::from(constructed)] + ), + Tag::ContextSpecific { + constructed, + number, + } => write!( + f, + "CONTEXT-SPECIFIC [{}] ({})", + number, + FIELD_TYPE[usize::from(constructed)] + ), + Tag::Private { + constructed, + number, + } => write!( + f, + "PRIVATE [{}] ({})", + number, + FIELD_TYPE[usize::from(constructed)] + ), + } + } +} + +impl fmt::Debug for Tag { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Tag(0x{:02x}: {})", u8::from(*self), self) + } +} + +#[cfg(test)] +mod tests { + use super::TagNumber; + use super::{Class, Tag}; + + #[test] + fn tag_class() { + assert_eq!(Tag::Boolean.class(), Class::Universal); + assert_eq!(Tag::Integer.class(), Class::Universal); + assert_eq!(Tag::BitString.class(), Class::Universal); + assert_eq!(Tag::OctetString.class(), Class::Universal); + assert_eq!(Tag::Null.class(), Class::Universal); + assert_eq!(Tag::ObjectIdentifier.class(), Class::Universal); + assert_eq!(Tag::Real.class(), Class::Universal); + assert_eq!(Tag::Enumerated.class(), Class::Universal); + assert_eq!(Tag::Utf8String.class(), Class::Universal); + assert_eq!(Tag::Set.class(), Class::Universal); + assert_eq!(Tag::NumericString.class(), Class::Universal); + assert_eq!(Tag::PrintableString.class(), Class::Universal); + assert_eq!(Tag::TeletexString.class(), Class::Universal); + assert_eq!(Tag::VideotexString.class(), Class::Universal); + assert_eq!(Tag::Ia5String.class(), Class::Universal); + assert_eq!(Tag::UtcTime.class(), Class::Universal); + assert_eq!(Tag::GeneralizedTime.class(), Class::Universal); + assert_eq!(Tag::Sequence.class(), Class::Universal); + + for num in 0..=30 { + for &constructed in &[false, true] { + let number = TagNumber::new(num); + + assert_eq!( + Tag::Application { + constructed, + number + } + .class(), + Class::Application + ); + + assert_eq!( + Tag::ContextSpecific { + constructed, + number + } + .class(), + Class::ContextSpecific + ); + + assert_eq!( + Tag::Private { + constructed, + number + } + .class(), + Class::Private + ); + } + } + } +} diff --git a/src/rust/vendor/der/src/tag/class.rs b/src/rust/vendor/der/src/tag/class.rs new file mode 100644 index 000000000..8a3e2ed10 --- /dev/null +++ b/src/rust/vendor/der/src/tag/class.rs @@ -0,0 +1,50 @@ +//! Class of an ASN.1 tag. + +use super::{TagNumber, CONSTRUCTED_FLAG}; +use core::fmt; + +/// Class of an ASN.1 tag. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +#[repr(u8)] +pub enum Class { + /// `UNIVERSAL`: built-in types whose meaning is the same in all + /// applications. + Universal = 0b00000000, + + /// `APPLICATION`: types whose meaning is specific to an application, + /// + /// Types in two different applications may have the same + /// application-specific tag and different meanings. + Application = 0b01000000, + + /// `CONTEXT-SPECIFIC`: types whose meaning is specific to a given + /// structured type. + /// + /// Context-specific tags are used to distinguish between component types + /// with the same underlying tag within the context of a given structured + /// type, and component types in two different structured types may have + /// the same tag and different meanings. + ContextSpecific = 0b10000000, + + /// `PRIVATE`: types whose meaning is specific to a given enterprise. + Private = 0b11000000, +} + +impl Class { + /// Compute the identifier octet for a tag number of this class. + #[allow(clippy::integer_arithmetic)] + pub(super) fn octet(self, constructed: bool, number: TagNumber) -> u8 { + self as u8 | number.value() | (u8::from(constructed) * CONSTRUCTED_FLAG) + } +} + +impl fmt::Display for Class { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Class::Universal => "UNIVERSAL", + Class::Application => "APPLICATION", + Class::ContextSpecific => "CONTEXT-SPECIFIC", + Class::Private => "PRIVATE", + }) + } +} diff --git a/src/rust/vendor/der/src/tag/mode.rs b/src/rust/vendor/der/src/tag/mode.rs new file mode 100644 index 000000000..ecdaf023a --- /dev/null +++ b/src/rust/vendor/der/src/tag/mode.rs @@ -0,0 +1,40 @@ +//! Tag modes. + +use crate::{Error, ErrorKind, Result}; +use core::{fmt, str::FromStr}; + +/// Tagging modes: `EXPLICIT` versus `IMPLICIT`. +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] +pub enum TagMode { + /// `EXPLICIT` tagging. + /// + /// Tag is added in addition to the inner tag of the type. + #[default] + Explicit, + + /// `IMPLICIT` tagging. + /// + /// Tag replaces the existing tag of the inner type. + Implicit, +} + +impl FromStr for TagMode { + type Err = Error; + + fn from_str(s: &str) -> Result { + match s { + "EXPLICIT" | "explicit" => Ok(TagMode::Explicit), + "IMPLICIT" | "implicit" => Ok(TagMode::Implicit), + _ => Err(ErrorKind::TagModeUnknown.into()), + } + } +} + +impl fmt::Display for TagMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TagMode::Explicit => f.write_str("EXPLICIT"), + TagMode::Implicit => f.write_str("IMPLICIT"), + } + } +} diff --git a/src/rust/vendor/der/src/tag/number.rs b/src/rust/vendor/der/src/tag/number.rs new file mode 100644 index 000000000..6a7eaae22 --- /dev/null +++ b/src/rust/vendor/der/src/tag/number.rs @@ -0,0 +1,201 @@ +//! ASN.1 tag numbers + +use super::Tag; +use crate::{Error, ErrorKind, Result}; +use core::fmt; + +/// ASN.1 tag numbers (i.e. lower 5 bits of a [`Tag`]). +/// +/// From X.690 Section 8.1.2.2: +/// +/// > bits 5 to 1 shall encode the number of the tag as a binary integer with +/// > bit 5 as the most significant bit. +/// +/// This library supports tag numbers ranging from zero to 30 (inclusive), +/// which can be represented as a single identifier octet. +/// +/// Section 8.1.2.4 describes how to support multi-byte tag numbers, which are +/// encoded by using a leading tag number of 31 (`0b11111`). This library +/// deliberately does not support this: tag numbers greater than 30 are +/// disallowed. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct TagNumber(pub(super) u8); + +impl TagNumber { + /// Tag number `0` + pub const N0: Self = Self(0); + + /// Tag number `1` + pub const N1: Self = Self(1); + + /// Tag number `2` + pub const N2: Self = Self(2); + + /// Tag number `3` + pub const N3: Self = Self(3); + + /// Tag number `4` + pub const N4: Self = Self(4); + + /// Tag number `5` + pub const N5: Self = Self(5); + + /// Tag number `6` + pub const N6: Self = Self(6); + + /// Tag number `7` + pub const N7: Self = Self(7); + + /// Tag number `8` + pub const N8: Self = Self(8); + + /// Tag number `9` + pub const N9: Self = Self(9); + + /// Tag number `10` + pub const N10: Self = Self(10); + + /// Tag number `11` + pub const N11: Self = Self(11); + + /// Tag number `12` + pub const N12: Self = Self(12); + + /// Tag number `13` + pub const N13: Self = Self(13); + + /// Tag number `14` + pub const N14: Self = Self(14); + + /// Tag number `15` + pub const N15: Self = Self(15); + + /// Tag number `16` + pub const N16: Self = Self(16); + + /// Tag number `17` + pub const N17: Self = Self(17); + + /// Tag number `18` + pub const N18: Self = Self(18); + + /// Tag number `19` + pub const N19: Self = Self(19); + + /// Tag number `20` + pub const N20: Self = Self(20); + + /// Tag number `21` + pub const N21: Self = Self(21); + + /// Tag number `22` + pub const N22: Self = Self(22); + + /// Tag number `23` + pub const N23: Self = Self(23); + + /// Tag number `24` + pub const N24: Self = Self(24); + + /// Tag number `25` + pub const N25: Self = Self(25); + + /// Tag number `26` + pub const N26: Self = Self(26); + + /// Tag number `27` + pub const N27: Self = Self(27); + + /// Tag number `28` + pub const N28: Self = Self(28); + + /// Tag number `29` + pub const N29: Self = Self(29); + + /// Tag number `30` + pub const N30: Self = Self(30); + + /// Mask value used to obtain the tag number from a tag octet. + pub(super) const MASK: u8 = 0b11111; + + /// Maximum tag number supported (inclusive). + const MAX: u8 = 30; + + /// Create a new tag number (const-friendly). + /// + /// Panics if the tag number is greater than `30`. + /// For a fallible conversion, use [`TryFrom`] instead. + pub const fn new(byte: u8) -> Self { + #[allow(clippy::panic)] + if byte > Self::MAX { + panic!("tag number out of range"); + } + + Self(byte) + } + + /// Create an `APPLICATION` tag with this tag number. + pub fn application(self, constructed: bool) -> Tag { + Tag::Application { + constructed, + number: self, + } + } + + /// Create a `CONTEXT-SPECIFIC` tag with this tag number. + pub fn context_specific(self, constructed: bool) -> Tag { + Tag::ContextSpecific { + constructed, + number: self, + } + } + + /// Create a `PRIVATE` tag with this tag number. + pub fn private(self, constructed: bool) -> Tag { + Tag::Private { + constructed, + number: self, + } + } + + /// Get the inner value. + pub fn value(self) -> u8 { + self.0 + } +} + +impl TryFrom for TagNumber { + type Error = Error; + + fn try_from(byte: u8) -> Result { + match byte { + 0..=Self::MAX => Ok(Self(byte)), + _ => Err(ErrorKind::TagNumberInvalid.into()), + } + } +} + +impl From for u8 { + fn from(tag_number: TagNumber) -> u8 { + tag_number.0 + } +} + +impl fmt::Display for TagNumber { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +// Implement by hand because the derive would create invalid values. +// Use the constructor to create a valid value. +#[cfg(feature = "arbitrary")] +impl<'a> arbitrary::Arbitrary<'a> for TagNumber { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + Ok(Self::new(u.int_in_range(0..=Self::MAX)?)) + } + + fn size_hint(depth: usize) -> (usize, Option) { + u8::size_hint(depth) + } +} diff --git a/src/rust/vendor/der/src/writer.rs b/src/rust/vendor/der/src/writer.rs new file mode 100644 index 000000000..164b215f7 --- /dev/null +++ b/src/rust/vendor/der/src/writer.rs @@ -0,0 +1,29 @@ +//! Writer trait. + +#[cfg(feature = "pem")] +pub(crate) mod pem; +pub(crate) mod slice; + +use crate::Result; + +#[cfg(feature = "std")] +use std::io; + +/// Writer trait which outputs encoded DER. +pub trait Writer { + /// Write the given DER-encoded bytes as output. + fn write(&mut self, slice: &[u8]) -> Result<()>; + + /// Write a single byte. + fn write_byte(&mut self, byte: u8) -> Result<()> { + self.write(&[byte]) + } +} + +#[cfg(feature = "std")] +impl Writer for W { + fn write(&mut self, slice: &[u8]) -> Result<()> { + ::write(self, slice)?; + Ok(()) + } +} diff --git a/src/rust/vendor/der/src/writer/pem.rs b/src/rust/vendor/der/src/writer/pem.rs new file mode 100644 index 000000000..87a6f8fd8 --- /dev/null +++ b/src/rust/vendor/der/src/writer/pem.rs @@ -0,0 +1,41 @@ +//! Streaming PEM writer. + +use super::Writer; +use crate::Result; +use pem_rfc7468::{Encoder, LineEnding}; + +/// `Writer` type which outputs PEM-encoded data. +pub struct PemWriter<'w>(Encoder<'static, 'w>); + +impl<'w> PemWriter<'w> { + /// Create a new PEM writer which outputs into the provided buffer. + /// + /// Uses the default 64-character line wrapping. + pub fn new( + type_label: &'static str, + line_ending: LineEnding, + out: &'w mut [u8], + ) -> Result { + Ok(Self(Encoder::new(type_label, line_ending, out)?)) + } + + /// Get the PEM label which will be used in the encapsulation boundaries + /// for this document. + pub fn type_label(&self) -> &'static str { + self.0.type_label() + } + + /// Finish encoding PEM, writing the post-encapsulation boundary. + /// + /// On success, returns the total number of bytes written to the output buffer. + pub fn finish(self) -> Result { + Ok(self.0.finish()?) + } +} + +impl Writer for PemWriter<'_> { + fn write(&mut self, slice: &[u8]) -> Result<()> { + self.0.encode(slice)?; + Ok(()) + } +} diff --git a/src/rust/vendor/der/src/writer/slice.rs b/src/rust/vendor/der/src/writer/slice.rs new file mode 100644 index 000000000..87083ad12 --- /dev/null +++ b/src/rust/vendor/der/src/writer/slice.rs @@ -0,0 +1,149 @@ +//! Slice writer. + +use crate::{ + asn1::*, Encode, EncodeValue, ErrorKind, Header, Length, Result, Tag, TagMode, TagNumber, + Tagged, Writer, +}; + +/// [`Writer`] which encodes DER into a mutable output byte slice. +#[derive(Debug)] +pub struct SliceWriter<'a> { + /// Buffer into which DER-encoded message is written + bytes: &'a mut [u8], + + /// Has the encoding operation failed? + failed: bool, + + /// Total number of bytes written to buffer so far + position: Length, +} + +impl<'a> SliceWriter<'a> { + /// Create a new encoder with the given byte slice as a backing buffer. + pub fn new(bytes: &'a mut [u8]) -> Self { + Self { + bytes, + failed: false, + position: Length::ZERO, + } + } + + /// Encode a value which impls the [`Encode`] trait. + pub fn encode(&mut self, encodable: &T) -> Result<()> { + if self.is_failed() { + self.error(ErrorKind::Failed)? + } + + encodable.encode(self).map_err(|e| { + self.failed = true; + e.nested(self.position) + }) + } + + /// Return an error with the given [`ErrorKind`], annotating it with + /// context about where the error occurred. + pub fn error(&mut self, kind: ErrorKind) -> Result { + self.failed = true; + Err(kind.at(self.position)) + } + + /// Did the decoding operation fail due to an error? + pub fn is_failed(&self) -> bool { + self.failed + } + + /// Finish encoding to the buffer, returning a slice containing the data + /// written to the buffer. + pub fn finish(self) -> Result<&'a [u8]> { + let position = self.position; + + if self.is_failed() { + return Err(ErrorKind::Failed.at(position)); + } + + self.bytes + .get(..usize::try_from(position)?) + .ok_or_else(|| ErrorKind::Overlength.at(position)) + } + + /// Encode a `CONTEXT-SPECIFIC` field with the provided tag number and mode. + pub fn context_specific( + &mut self, + tag_number: TagNumber, + tag_mode: TagMode, + value: &T, + ) -> Result<()> + where + T: EncodeValue + Tagged, + { + ContextSpecificRef { + tag_number, + tag_mode, + value, + } + .encode(self) + } + + /// Encode an ASN.1 `SEQUENCE` of the given length. + /// + /// Spawns a nested slice writer which is expected to be exactly the + /// specified length upon completion. + pub fn sequence(&mut self, length: Length, f: F) -> Result<()> + where + F: FnOnce(&mut SliceWriter<'_>) -> Result<()>, + { + Header::new(Tag::Sequence, length).and_then(|header| header.encode(self))?; + + let mut nested_encoder = SliceWriter::new(self.reserve(length)?); + f(&mut nested_encoder)?; + + if nested_encoder.finish()?.len() == usize::try_from(length)? { + Ok(()) + } else { + self.error(ErrorKind::Length { tag: Tag::Sequence }) + } + } + + /// Reserve a portion of the internal buffer, updating the internal cursor + /// position and returning a mutable slice. + fn reserve(&mut self, len: impl TryInto) -> Result<&mut [u8]> { + if self.is_failed() { + return Err(ErrorKind::Failed.at(self.position)); + } + + let len = len + .try_into() + .or_else(|_| self.error(ErrorKind::Overflow))?; + + let end = (self.position + len).or_else(|e| self.error(e.kind()))?; + let slice = self + .bytes + .get_mut(self.position.try_into()?..end.try_into()?) + .ok_or_else(|| ErrorKind::Overlength.at(end))?; + + self.position = end; + Ok(slice) + } +} + +impl<'a> Writer for SliceWriter<'a> { + fn write(&mut self, slice: &[u8]) -> Result<()> { + self.reserve(slice.len())?.copy_from_slice(slice); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::SliceWriter; + use crate::{Encode, ErrorKind, Length}; + + #[test] + fn overlength_message() { + let mut buffer = []; + let mut writer = SliceWriter::new(&mut buffer); + let err = false.encode(&mut writer).err().unwrap(); + assert_eq!(err.kind(), ErrorKind::Overlength); + assert_eq!(err.position(), Some(Length::ONE)); + } +} diff --git a/src/rust/vendor/der/tests/datetime.proptest-regressions b/src/rust/vendor/der/tests/datetime.proptest-regressions new file mode 100644 index 000000000..f280ac46a --- /dev/null +++ b/src/rust/vendor/der/tests/datetime.proptest-regressions @@ -0,0 +1,8 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc 00dbea7e90761c16aa20e2fbf7ffad420da0c84d4ed4e6df123de03c9b4567e5 # shrinks to year = 1970, month = 1, day = 1, hour = 0, min = 60, sec = 0 +cc 3b0bd01ef4cad6bea0a287f9cdcd56bad186125ec388d204f6afcd193ca12c39 # shrinks to year = 1970, month = 1, day = 1, hour = 0, min = 0, sec = 60 diff --git a/src/rust/vendor/der/tests/datetime.rs b/src/rust/vendor/der/tests/datetime.rs new file mode 100644 index 000000000..454c1f0e4 --- /dev/null +++ b/src/rust/vendor/der/tests/datetime.rs @@ -0,0 +1,64 @@ +//! Tests for the [`DateTime`] type. + +use der::{asn1::UtcTime, DateTime, Decode, Encode}; +use proptest::prelude::*; + +proptest! { + #[test] + fn roundtrip_datetime( + year in 1970u16..=9999, + month in 1u8..=12, + day in 1u8..=31, + hour in 0u8..=23, + min in 0u8..=59, + sec in 0u8..=59, + ) { + let datetime1 = make_datetime(year, month, day, hour, min, sec); + let datetime2 = DateTime::from_unix_duration(datetime1.unix_duration()).unwrap(); + prop_assert_eq!(datetime1, datetime2); + } + + #[test] + fn roundtrip_utctime( + year in 1970u16..=2049, + month in 1u8..=12, + day in 1u8..=31, + hour in 0u8..=23, + min in 0u8..=59, + sec in 0u8..=59, + ) { + let datetime = make_datetime(year, month, day, hour, min, sec); + let utc_time1 = UtcTime::try_from(datetime).unwrap(); + + let mut buf = [0u8; 128]; + let mut encoder = der::SliceWriter::new(&mut buf); + utc_time1.encode(&mut encoder).unwrap(); + let der_bytes = encoder.finish().unwrap(); + + let utc_time2 = UtcTime::from_der(der_bytes).unwrap(); + prop_assert_eq!(utc_time1, utc_time2); + } +} + +fn make_datetime(year: u16, month: u8, day: u8, hour: u8, min: u8, sec: u8) -> DateTime { + let max_day = if month == 2 { + let is_leap_year = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); + + if is_leap_year { + 29 + } else { + 28 + } + } else { + 30 + }; + + let day = if day > max_day { max_day } else { day }; + + DateTime::new(year, month, day, hour, min, sec).unwrap_or_else(|e| { + panic!( + "invalid DateTime: {:02}-{:02}-{:02}T{:02}:{:02}:{:02}: {}", + year, month, day, hour, min, sec, e + ); + }) +} diff --git a/src/rust/vendor/der/tests/derive.rs b/src/rust/vendor/der/tests/derive.rs new file mode 100644 index 000000000..a8c77febc --- /dev/null +++ b/src/rust/vendor/der/tests/derive.rs @@ -0,0 +1,461 @@ +//! Tests for custom derive support. +//! +//! # Debugging with `cargo expand` +//! +//! To expand the Rust code generated by the proc macro when debugging +//! issues related to these tests, run: +//! +//! $ cargo expand --test derive --all-features + +#![cfg(all(feature = "derive", feature = "alloc"))] + +/// Custom derive test cases for the `Choice` macro. +mod choice { + /// `Choice` with `EXPLICIT` tagging. + mod explicit { + use der::{ + asn1::{GeneralizedTime, UtcTime}, + Choice, Decode, Encode, SliceWriter, + }; + use hex_literal::hex; + use std::time::Duration; + + /// Custom derive test case for the `Choice` macro. + /// + /// Based on `Time` as defined in RFC 5280: + /// + /// + /// ```text + /// Time ::= CHOICE { + /// utcTime UTCTime, + /// generalTime GeneralizedTime } + /// ``` + #[derive(Choice)] + pub enum Time { + #[asn1(type = "UTCTime")] + UtcTime(UtcTime), + + #[asn1(type = "GeneralizedTime")] + GeneralTime(GeneralizedTime), + } + + impl Time { + fn to_unix_duration(self) -> Duration { + match self { + Time::UtcTime(t) => t.to_unix_duration(), + Time::GeneralTime(t) => t.to_unix_duration(), + } + } + } + + const UTC_TIMESTAMP_DER: &[u8] = &hex!("17 0d 39 31 30 35 30 36 32 33 34 35 34 30 5a"); + const GENERAL_TIMESTAMP_DER: &[u8] = + &hex!("18 0f 31 39 39 31 30 35 30 36 32 33 34 35 34 30 5a"); + + #[test] + fn decode() { + let utc_time = Time::from_der(UTC_TIMESTAMP_DER).unwrap(); + assert_eq!(utc_time.to_unix_duration().as_secs(), 673573540); + + let general_time = Time::from_der(GENERAL_TIMESTAMP_DER).unwrap(); + assert_eq!(general_time.to_unix_duration().as_secs(), 673573540); + } + + #[test] + fn encode() { + let mut buf = [0u8; 128]; + + let utc_time = Time::from_der(UTC_TIMESTAMP_DER).unwrap(); + let mut encoder = SliceWriter::new(&mut buf); + utc_time.encode(&mut encoder).unwrap(); + assert_eq!(UTC_TIMESTAMP_DER, encoder.finish().unwrap()); + + let general_time = Time::from_der(GENERAL_TIMESTAMP_DER).unwrap(); + let mut encoder = SliceWriter::new(&mut buf); + general_time.encode(&mut encoder).unwrap(); + assert_eq!(GENERAL_TIMESTAMP_DER, encoder.finish().unwrap()); + } + } + + /// `Choice` with `IMPLICIT` tagging. + mod implicit { + use der::{ + asn1::{BitStringRef, GeneralizedTime}, + Choice, Decode, Encode, SliceWriter, + }; + use hex_literal::hex; + + /// `Choice` macro test case for `IMPLICIT` tagging. + #[derive(Choice, Debug, Eq, PartialEq)] + #[asn1(tag_mode = "IMPLICIT")] + pub enum ImplicitChoice<'a> { + #[asn1(context_specific = "0", type = "BIT STRING")] + BitString(BitStringRef<'a>), + + #[asn1(context_specific = "1", type = "GeneralizedTime")] + Time(GeneralizedTime), + + #[asn1(context_specific = "2", type = "UTF8String")] + Utf8String(String), + } + + impl<'a> ImplicitChoice<'a> { + pub fn bit_string(&self) -> Option> { + match self { + Self::BitString(bs) => Some(*bs), + _ => None, + } + } + + pub fn time(&self) -> Option { + match self { + Self::Time(time) => Some(*time), + _ => None, + } + } + } + + const BITSTRING_DER: &[u8] = &hex!("80 04 00 01 02 03"); + const TIME_DER: &[u8] = &hex!("81 0f 31 39 39 31 30 35 30 36 32 33 34 35 34 30 5a"); + + #[test] + fn decode() { + let cs_bit_string = ImplicitChoice::from_der(BITSTRING_DER).unwrap(); + assert_eq!( + cs_bit_string.bit_string().unwrap().as_bytes().unwrap(), + &[1, 2, 3] + ); + + let cs_time = ImplicitChoice::from_der(TIME_DER).unwrap(); + assert_eq!( + cs_time.time().unwrap().to_unix_duration().as_secs(), + 673573540 + ); + } + + #[test] + fn encode() { + let mut buf = [0u8; 128]; + + let cs_bit_string = ImplicitChoice::from_der(BITSTRING_DER).unwrap(); + let mut encoder = SliceWriter::new(&mut buf); + cs_bit_string.encode(&mut encoder).unwrap(); + assert_eq!(BITSTRING_DER, encoder.finish().unwrap()); + + let cs_time = ImplicitChoice::from_der(TIME_DER).unwrap(); + let mut encoder = SliceWriter::new(&mut buf); + cs_time.encode(&mut encoder).unwrap(); + assert_eq!(TIME_DER, encoder.finish().unwrap()); + } + } +} + +/// Custom derive test cases for the `Enumerated` macro. +mod enumerated { + use der::{Decode, Encode, Enumerated, SliceWriter}; + use hex_literal::hex; + + /// X.509 `CRLReason`. + #[derive(Enumerated, Copy, Clone, Debug, Eq, PartialEq)] + #[repr(u32)] + pub enum CrlReason { + Unspecified = 0, + KeyCompromise = 1, + CaCompromise = 2, + AffiliationChanged = 3, + Superseded = 4, + CessationOfOperation = 5, + CertificateHold = 6, + RemoveFromCrl = 8, + PrivilegeWithdrawn = 9, + AaCompromised = 10, + } + + const UNSPECIFIED_DER: &[u8] = &hex!("0a 01 00"); + const KEY_COMPROMISE_DER: &[u8] = &hex!("0a 01 01"); + + #[test] + fn decode() { + let unspecified = CrlReason::from_der(UNSPECIFIED_DER).unwrap(); + assert_eq!(CrlReason::Unspecified, unspecified); + + let key_compromise = CrlReason::from_der(KEY_COMPROMISE_DER).unwrap(); + assert_eq!(CrlReason::KeyCompromise, key_compromise); + } + + #[test] + fn encode() { + let mut buf = [0u8; 128]; + + let mut encoder = SliceWriter::new(&mut buf); + CrlReason::Unspecified.encode(&mut encoder).unwrap(); + assert_eq!(UNSPECIFIED_DER, encoder.finish().unwrap()); + + let mut encoder = SliceWriter::new(&mut buf); + CrlReason::KeyCompromise.encode(&mut encoder).unwrap(); + assert_eq!(KEY_COMPROMISE_DER, encoder.finish().unwrap()); + } +} + +/// Custom derive test cases for the `Sequence` macro. +#[cfg(feature = "oid")] +mod sequence { + use core::marker::PhantomData; + use der::{ + asn1::{AnyRef, ObjectIdentifier, SetOf}, + Decode, Encode, Sequence, ValueOrd, + }; + use hex_literal::hex; + + pub fn default_false_example() -> bool { + false + } + + // Issuing distribution point extension as defined in [RFC 5280 Section 5.2.5] and as identified by the [`PKIX_PE_SUBJECTINFOACCESS`](constant.PKIX_PE_SUBJECTINFOACCESS.html) OID. + // + // ```text + // IssuingDistributionPoint ::= SEQUENCE { + // distributionPoint [0] DistributionPointName OPTIONAL, + // onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, + // onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, + // onlySomeReasons [3] ReasonFlags OPTIONAL, + // indirectCRL [4] BOOLEAN DEFAULT FALSE, + // onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE } + // -- at most one of onlyContainsUserCerts, onlyContainsCACerts, + // -- and onlyContainsAttributeCerts may be set to TRUE. + // ``` + // + // [RFC 5280 Section 5.2.5]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.5 + #[derive(Sequence)] + pub struct IssuingDistributionPointExample { + // Omit distributionPoint and only_some_reasons because corresponding structs are not + // available here and are not germane to the example + // distributionPoint [0] DistributionPointName OPTIONAL, + //#[asn1(context_specific="0", optional="true", tag_mode="IMPLICIT")] + //pub distribution_point: Option>, + /// onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, + #[asn1( + context_specific = "1", + default = "default_false_example", + tag_mode = "IMPLICIT" + )] + pub only_contains_user_certs: bool, + + /// onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, + #[asn1( + context_specific = "2", + default = "default_false_example", + tag_mode = "IMPLICIT" + )] + pub only_contains_cacerts: bool, + + // onlySomeReasons [3] ReasonFlags OPTIONAL, + //#[asn1(context_specific="3", optional="true", tag_mode="IMPLICIT")] + //pub only_some_reasons: Option>, + /// indirectCRL [4] BOOLEAN DEFAULT FALSE, + #[asn1( + context_specific = "4", + default = "default_false_example", + tag_mode = "IMPLICIT" + )] + pub indirect_crl: bool, + + /// onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE + #[asn1( + context_specific = "5", + default = "default_false_example", + tag_mode = "IMPLICIT" + )] + pub only_contains_attribute_certs: bool, + + /// Test handling of PhantomData. + pub phantom: PhantomData<()>, + } + + // Extension as defined in [RFC 5280 Section 4.1.2.9]. + // + // The ASN.1 definition for Extension objects is below. The extnValue type may be further parsed using a decoder corresponding to the extnID value. + // + // ```text + // Extension ::= SEQUENCE { + // extnID OBJECT IDENTIFIER, + // critical BOOLEAN DEFAULT FALSE, + // extnValue OCTET STRING + // -- contains the DER encoding of an ASN.1 value + // -- corresponding to the extension type identified + // -- by extnID + // } + // ``` + // + // [RFC 5280 Section 4.1.2.9]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.9 + #[derive(Clone, Debug, Eq, PartialEq, Sequence)] + pub struct ExtensionExample<'a> { + /// extnID OBJECT IDENTIFIER, + pub extn_id: ObjectIdentifier, + + /// critical BOOLEAN DEFAULT FALSE, + #[asn1(default = "default_false_example")] + pub critical: bool, + + /// extnValue OCTET STRING + #[asn1(type = "OCTET STRING")] + pub extn_value: &'a [u8], + } + + /// X.509 `AlgorithmIdentifier` + #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] + pub struct AlgorithmIdentifier<'a> { + pub algorithm: ObjectIdentifier, + pub parameters: Option>, + } + + /// X.509 `SubjectPublicKeyInfo` (SPKI) + #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] + pub struct SubjectPublicKeyInfo<'a> { + pub algorithm: AlgorithmIdentifier<'a>, + #[asn1(type = "BIT STRING")] + pub subject_public_key: &'a [u8], + } + + /// PKCS#8v2 `OneAsymmetricKey` + #[derive(Sequence)] + pub struct OneAsymmetricKey<'a> { + pub version: u8, + pub private_key_algorithm: AlgorithmIdentifier<'a>, + #[asn1(type = "OCTET STRING")] + pub private_key: &'a [u8], + #[asn1(context_specific = "0", extensible = "true", optional = "true")] + pub attributes: Option, 1>>, + #[asn1( + context_specific = "1", + extensible = "true", + optional = "true", + type = "BIT STRING" + )] + pub public_key: Option<&'a [u8]>, + } + + /// X.509 extension + // TODO(tarcieri): tests for code derived with the `default` attribute + #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] + pub struct Extension<'a> { + extn_id: ObjectIdentifier, + #[asn1(default = "critical_default")] + critical: bool, + #[asn1(type = "OCTET STRING")] + extn_value: &'a [u8], + } + + /// Default value of the `critical` bit + fn critical_default() -> bool { + false + } + + const ID_EC_PUBLIC_KEY_OID: ObjectIdentifier = + ObjectIdentifier::new_unwrap("1.2.840.10045.2.1"); + + const PRIME256V1_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.3.1.7"); + + const ALGORITHM_IDENTIFIER_DER: &[u8] = + &hex!("30 13 06 07 2a 86 48 ce 3d 02 01 06 08 2a 86 48 ce 3d 03 01 07"); + + #[derive(Sequence)] + #[asn1(tag_mode = "IMPLICIT")] + pub struct TypeCheckExpandedSequenceFieldAttributeCombinations<'a> { + pub simple: bool, + #[asn1(type = "BIT STRING")] + pub typed: &'a [u8], + #[asn1(context_specific = "0")] + pub context_specific: bool, + #[asn1(optional = "true")] + pub optional: Option, + #[asn1(default = "default_false_example")] + pub default: bool, + #[asn1(type = "BIT STRING", context_specific = "1")] + pub typed_context_specific: &'a [u8], + #[asn1(context_specific = "2", optional = "true")] + pub context_specific_optional: Option, + #[asn1(context_specific = "3", default = "default_false_example")] + pub context_specific_default: bool, + #[asn1(type = "BIT STRING", context_specific = "4", optional = "true")] + pub typed_context_specific_optional: Option<&'a [u8]>, + } + + #[test] + fn idp_test() { + let idp = IssuingDistributionPointExample::from_der(&hex!("30038101FF")).unwrap(); + assert_eq!(idp.only_contains_user_certs, true); + assert_eq!(idp.only_contains_cacerts, false); + assert_eq!(idp.indirect_crl, false); + assert_eq!(idp.only_contains_attribute_certs, false); + + let idp = IssuingDistributionPointExample::from_der(&hex!("30038201FF")).unwrap(); + assert_eq!(idp.only_contains_user_certs, false); + assert_eq!(idp.only_contains_cacerts, true); + assert_eq!(idp.indirect_crl, false); + assert_eq!(idp.only_contains_attribute_certs, false); + + let idp = IssuingDistributionPointExample::from_der(&hex!("30038401FF")).unwrap(); + assert_eq!(idp.only_contains_user_certs, false); + assert_eq!(idp.only_contains_cacerts, false); + assert_eq!(idp.indirect_crl, true); + assert_eq!(idp.only_contains_attribute_certs, false); + + let idp = IssuingDistributionPointExample::from_der(&hex!("30038501FF")).unwrap(); + assert_eq!(idp.only_contains_user_certs, false); + assert_eq!(idp.only_contains_cacerts, false); + assert_eq!(idp.indirect_crl, false); + assert_eq!(idp.only_contains_attribute_certs, true); + } + + // demonstrates default field that is not context specific + #[test] + fn extension_test() { + let ext1 = ExtensionExample::from_der(&hex!( + "300F" // 0 15: SEQUENCE { + "0603551D13" // 2 3: OBJECT IDENTIFIER basicConstraints (2 5 29 19) + "0101FF" // 7 1: BOOLEAN TRUE + "0405" // 10 5: OCTET STRING, encapsulates { + "3003" // 12 3: SEQUENCE { + "0101FF" // 14 1: BOOLEAN TRUE + )) + .unwrap(); + assert_eq!(ext1.critical, true); + + let ext2 = ExtensionExample::from_der(&hex!( + "301F" // 0 31: SEQUENCE { + "0603551D23" // 2 3: OBJECT IDENTIFIER authorityKeyIdentifier (2 5 29 35) + "0418" // 7 24: OCTET STRING, encapsulates { + "3016" // 9 22: SEQUENCE { + "8014E47D5FD15C9586082C05AEBE75B665A7D95DA866" // 11 20: [0] E4 7D 5F D1 5C 95 86 08 2C 05 AE BE 75 B6 65 A7 D9 5D A8 66 + )) + .unwrap(); + assert_eq!(ext2.critical, false); + } + + #[test] + fn decode() { + let algorithm_identifier = AlgorithmIdentifier::from_der(ALGORITHM_IDENTIFIER_DER).unwrap(); + + assert_eq!(ID_EC_PUBLIC_KEY_OID, algorithm_identifier.algorithm); + assert_eq!( + PRIME256V1_OID, + ObjectIdentifier::try_from(algorithm_identifier.parameters.unwrap()).unwrap() + ); + } + + #[test] + fn encode() { + let parameters_oid = PRIME256V1_OID; + + let algorithm_identifier = AlgorithmIdentifier { + algorithm: ID_EC_PUBLIC_KEY_OID, + parameters: Some(AnyRef::from(¶meters_oid)), + }; + + assert_eq!( + ALGORITHM_IDENTIFIER_DER, + algorithm_identifier.to_der().unwrap() + ); + } +} diff --git a/src/rust/vendor/der/tests/examples/spki.der b/src/rust/vendor/der/tests/examples/spki.der new file mode 100644 index 000000000..1b602ee1f Binary files /dev/null and b/src/rust/vendor/der/tests/examples/spki.der differ diff --git a/src/rust/vendor/der/tests/examples/spki.pem b/src/rust/vendor/der/tests/examples/spki.pem new file mode 100644 index 000000000..6891701f7 --- /dev/null +++ b/src/rust/vendor/der/tests/examples/spki.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEATSkWfz8ZEqb3rfopOgUaFcBexnuPFyZ7HFVQ3OhTvQ0= +-----END PUBLIC KEY----- diff --git a/src/rust/vendor/der/tests/pem.rs b/src/rust/vendor/der/tests/pem.rs new file mode 100644 index 000000000..d2c865463 --- /dev/null +++ b/src/rust/vendor/der/tests/pem.rs @@ -0,0 +1,67 @@ +//! PEM decoding and encoding tests. + +#![cfg(all(feature = "derive", feature = "oid", feature = "pem"))] + +use der::{ + asn1::{BitString, ObjectIdentifier}, + pem::{LineEnding, PemLabel}, + Decode, DecodePem, EncodePem, Sequence, +}; + +/// Example SPKI document encoded as DER. +const SPKI_DER: &[u8] = include_bytes!("examples/spki.der"); + +/// Example SPKI document encoded as PEM. +const SPKI_PEM: &str = include_str!("examples/spki.pem"); + +/// X.509 `AlgorithmIdentifier` +#[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence)] +pub struct AlgorithmIdentifier { + pub algorithm: ObjectIdentifier, + // pub parameters: ... (not used in spki.pem) +} + +/// X.509 `SubjectPublicKeyInfo` (SPKI) in borrowed form +#[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence)] +pub struct SpkiBorrowed<'a> { + pub algorithm: AlgorithmIdentifier, + #[asn1(type = "BIT STRING")] + pub subject_public_key: &'a [u8], +} + +impl PemLabel for SpkiBorrowed<'_> { + const PEM_LABEL: &'static str = "PUBLIC KEY"; +} + +/// X.509 `SubjectPublicKeyInfo` (SPKI) in owned form +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +pub struct SpkiOwned { + pub algorithm: AlgorithmIdentifier, + pub subject_public_key: BitString, +} + +impl PemLabel for SpkiOwned { + const PEM_LABEL: &'static str = "PUBLIC KEY"; +} + +#[test] +fn from_pem() { + // Decode PEM to owned form. + let pem_spki = SpkiOwned::from_pem(SPKI_PEM).unwrap(); + + // Decode DER to borrowed form. + let der_spki = SpkiBorrowed::from_der(SPKI_DER).unwrap(); + + assert_eq!(pem_spki.algorithm, der_spki.algorithm); + assert_eq!( + pem_spki.subject_public_key.raw_bytes(), + der_spki.subject_public_key + ); +} + +#[test] +fn to_pem() { + let spki = SpkiBorrowed::from_der(SPKI_DER).unwrap(); + let pem = spki.to_pem(LineEnding::LF).unwrap(); + assert_eq!(&pem, SPKI_PEM); +} diff --git a/src/rust/vendor/der/tests/set_of.rs b/src/rust/vendor/der/tests/set_of.rs new file mode 100644 index 000000000..d58399198 --- /dev/null +++ b/src/rust/vendor/der/tests/set_of.rs @@ -0,0 +1,65 @@ +//! `SetOf` tests. + +#![cfg(feature = "alloc")] + +use der::{asn1::SetOfVec, DerOrd}; +use proptest::{prelude::*, string::*}; +use std::collections::BTreeSet; + +proptest! { + #[test] + fn sort_equiv(bytes in bytes_regex(".{0,64}").unwrap()) { + let mut uniq = BTreeSet::new(); + + // Ensure there are no duplicates + if bytes.iter().copied().all(move |x| uniq.insert(x)) { + let mut expected = bytes.clone(); + expected.sort_by(|a, b| a.der_cmp(b).unwrap()); + + let set = SetOfVec::try_from(bytes).unwrap(); + prop_assert_eq!(expected.as_slice(), set.as_slice()); + } + } +} + +/// Set ordering tests. +#[cfg(all(feature = "derive", feature = "oid"))] +mod ordering { + use der::{ + asn1::{AnyRef, ObjectIdentifier, SetOf, SetOfVec}, + Decode, Sequence, ValueOrd, + }; + use hex_literal::hex; + + /// X.501 `AttributeTypeAndValue` + #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] + pub struct AttributeTypeAndValue<'a> { + pub oid: ObjectIdentifier, + pub value: AnyRef<'a>, + } + + const OUT_OF_ORDER_RDN_EXAMPLE: &[u8] = + &hex!("311F301106035504030C0A4A4F484E20534D495448300A060355040A0C03313233"); + + /// For compatibility reasons, we allow non-canonical DER with out-of-order + /// sets in order to match the behavior of other implementations. + #[test] + fn allow_out_of_order_setof() { + assert!(SetOf::, 2>::from_der(OUT_OF_ORDER_RDN_EXAMPLE).is_ok()); + } + + /// Same as above, with `SetOfVec` instead of `SetOf`. + #[test] + fn allow_out_of_order_setofvec() { + assert!(SetOfVec::>::from_der(OUT_OF_ORDER_RDN_EXAMPLE).is_ok()); + } + + /// Test to ensure ordering is handled correctly. + #[test] + fn ordering_regression() { + let der_bytes = hex!("3139301906035504030C12546573742055736572393031353734333830301C060A0992268993F22C640101130E3437303031303030303134373333"); + let set = SetOf::, 3>::from_der(&der_bytes).unwrap(); + let attr1 = set.get(0).unwrap(); + assert_eq!(ObjectIdentifier::new("2.5.4.3").unwrap(), attr1.oid); + } +} diff --git a/src/rust/vendor/ecdsa/.cargo-checksum.json b/src/rust/vendor/ecdsa/.cargo-checksum.json new file mode 100644 index 000000000..640ce7fcc --- /dev/null +++ b/src/rust/vendor/ecdsa/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"a6b49a96975d94d85d698369e5e1fc3cea7022c381c0ebe741efcc7a2879ba3c","Cargo.toml":"a1e1f54de247dd373355a433e3f45c657ea9a127a56154efc285a05b0a82ef52","LICENSE-APACHE":"78779d420019e6b4630376af8e86b6b335ee8a2f89ede6e0411e0469a326aaa4","LICENSE-MIT":"bdebaf9156a298f8fdab56dd26cb5144673de522d80f4c0d88e0039145f147f9","README.md":"f99485065d3d5541ef1814ea8d3f75718f08cb78eb5626f9d34941799655b4b9","src/der.rs":"12d336b65d1a9d45a44809746c572084d512812e4a8baad23158127a67c583b6","src/dev.rs":"75d56ac79f04efc018b37eca752c7861579772a758cac94874ccf85aa880602a","src/hazmat.rs":"230f3b337e826188825f76eb26ffc2fa19ce8b2bd45cc7b80f87c34f33cfe13d","src/lib.rs":"aeda83d19f5088920a814f9331f45fd0f1026e18bae384ebfaaaeb00b814cb47","src/normalized.rs":"57d6f3c00fa603a42b6351d29f4cb4a101b79277b3217c2bfa963f289fc475c9","src/recovery.rs":"41141f9f4ffbd155c5167fbe749299496077c55e6b64ed83f65ced1372205623","src/signing.rs":"11842af046b43fe53add72a7fdc78a9555a1dbc37fe6bb0d1139e8b25491538f","src/verifying.rs":"c7441025d4ddcfce2c7701813d84c032364da4bd38bd28895a75d09eaca53ee3","tests/lib.rs":"68922b3fb793f7f64a6fdf8aa59b6fb9432d4706d7ad1d82129a8337c5cf6568"},"package":"ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"} \ No newline at end of file diff --git a/src/rust/vendor/ecdsa/CHANGELOG.md b/src/rust/vendor/ecdsa/CHANGELOG.md new file mode 100644 index 000000000..77609d8f6 --- /dev/null +++ b/src/rust/vendor/ecdsa/CHANGELOG.md @@ -0,0 +1,588 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.16.9 (2023-11-16) +### Changed +- Loosen `signature` bound to `2.0, <2.3` ([#756]) + +[#756]: https://github.com/RustCrypto/signatures/pull/756 + +## 0.16.8 (2023-07-20) +### Added +- `hazmat::{sign_prehashed, verify_prehashed}` ([#731]) + +### Changed +- Refactor `Signature` constructors and improve docs ([#730]) + +[#730]: https://github.com/RustCrypto/signatures/pull/730 +[#731]: https://github.com/RustCrypto/signatures/pull/731 + +## 0.16.7 (2023-05-11) +### Added +- RFC5480 citation for `der::Signature` ([#710]) +- support for the `SignatureBitStringEncoding` trait ([#716]) + +### Changed +- bump `elliptic-curve` from 0.13.3 to 0.13.4 ([#709]) +- `der::Signature` citation to RFC5912 ([#711]) +- make `fmt` impls more consistent ([#713]) + +### Fixed +- `serde` doc fixup ([#712]) + +[#709]: https://github.com/RustCrypto/signatures/pull/709 +[#710]: https://github.com/RustCrypto/signatures/pull/710 +[#711]: https://github.com/RustCrypto/signatures/pull/711 +[#712]: https://github.com/RustCrypto/signatures/pull/712 +[#713]: https://github.com/RustCrypto/signatures/pull/713 +[#716]: https://github.com/RustCrypto/signatures/pull/716 + +## 0.16.6 (2023-04-09) +### Fixed +- Test macro handling of serialized field size ([#707]) + +[#707]: https://github.com/RustCrypto/signatures/pull/707 + +## 0.16.5 (2023-04-08) +### Fixed +- Use `C::FieldBytesSize` instead of `C::Uint::BYTES` ([#705]) + +[#705]: https://github.com/RustCrypto/signatures/pull/705 + +## 0.16.4 (2023-04-05) +### Fixed +- `RecoveryId` computation in `SignPrimitive` ([#702]) + +[#702]: https://github.com/RustCrypto/signatures/pull/702 + +## 0.16.3 (2023-04-04) +### Added +- RFC5758 OID support ([#686]) +- `SignatureAlgorithmIdentifier` impls for `SigningKey`/`VerifyingKey` ([#688]) +- `SignatureWithOid` ([#689], [#690]) +- `AssociatedAlgorithmIdentifier` impls for `SigningKey`/`VerifyingKey` ([#698]) + +### Changed +- Loosen `signature` bound to `2.0, <2.2` ([#697]) + +[#686]: https://github.com/RustCrypto/signatures/pull/686 +[#688]: https://github.com/RustCrypto/signatures/pull/688 +[#689]: https://github.com/RustCrypto/signatures/pull/689 +[#690]: https://github.com/RustCrypto/signatures/pull/690 +[#697]: https://github.com/RustCrypto/signatures/pull/697 +[#698]: https://github.com/RustCrypto/signatures/pull/698 + +## 0.16.2 (2023-03-28) +### Added +- Handle the reduced R.x case in public key recovery ([#680]) +- `Signature::{from_bytes, from_slice}` methods ([#684]) + +[#680]: https://github.com/RustCrypto/signatures/pull/680 +[#684]: https://github.com/RustCrypto/signatures/pull/684 + +## 0.16.1 (2023-03-09) +### Added +- `VerifyingKey::to_sec1_bytes` + more conversions ([#675]) + +[#675]: https://github.com/RustCrypto/signatures/pull/675 + +## 0.16.0 (2023-03-01) +### Added +- `Decode` and `Encode` impls for `der::Signature` ([#666]) + +### Changed +- Use `Scalar::invert_vartime` for faster verification ([#651]) +- Bump `serdect` dependency to 0.2 ([#657]) +- Bump `elliptic-curve` dependency to v0.13; MSRV 1.65 ([#660], [#663]) +- Bump `rfc6979` dependency to v0.4 ([#662]) + +[#651]: https://github.com/RustCrypto/signatures/pull/651 +[#657]: https://github.com/RustCrypto/signatures/pull/657 +[#660]: https://github.com/RustCrypto/signatures/pull/660 +[#662]: https://github.com/RustCrypto/signatures/pull/662 +[#666]: https://github.com/RustCrypto/signatures/pull/666 + +## 0.15.1 (2023-01-23) +### Added +- `SigningKey::*_recoverable` methods ([#635]) + +[#635]: https://github.com/RustCrypto/signatures/pull/635 + +## 0.15.0 (2023-01-15) +### Added +- `DigestPrimitive::Digest` now has bounds that work with RFC6979 ([#568]) +- `*Signer`/`*Verifier` impls for `der::Signature` ([#569]) +- `VerifyingKey` recovery support ([#576]) +- Trial recovery support ([#580]) + +### Changed +- Signature now internally structured with `r` and `s` components ([#565]) +- `SigningKey::verifying_key` now returns a reference ([#567]) +- Refactor `prehash_to_field_bytes` to `bits2field` free function ([#574]) +- Rename `sign` feature to `signing` ([#610]) +- Rename `verify` feature to `verifying` features ([#610]) +- Bump `signature` crate dependency to v2.0 ([#614]) + +[#565]: https://github.com/RustCrypto/signatures/pull/565 +[#567]: https://github.com/RustCrypto/signatures/pull/567 +[#574]: https://github.com/RustCrypto/signatures/pull/574 +[#580]: https://github.com/RustCrypto/signatures/pull/580 +[#568]: https://github.com/RustCrypto/signatures/pull/568 +[#569]: https://github.com/RustCrypto/signatures/pull/569 +[#576]: https://github.com/RustCrypto/signatures/pull/576 +[#580]: https://github.com/RustCrypto/signatures/pull/580 +[#610]: https://github.com/RustCrypto/signatures/pull/610 +[#614]: https://github.com/RustCrypto/signatures/pull/614 + +## 0.14.8 (2022-09-27) +### Added +- Impl `From` for `SecretKey` ([#548]) + +### Fixed +- Prehash must receive zero-pads on left ([#547]) + +[#547]: https://github.com/RustCrypto/signatures/pull/547 +[#548]: https://github.com/RustCrypto/signatures/pull/548 + +## 0.14.7 (2022-09-15) +### Changed +- Relax `Keypair` bounds ([#539]) + +[#539]: https://github.com/RustCrypto/signatures/pull/539 + +## 0.14.6 (2022-09-12) +### Added +- Impl `signature::hazmat::{PrehashSigner, PrehashVerifier}` ([#534]) +- Impl `signature::Keypair` for `SigningKey` ([#535]) + +[#534]: https://github.com/RustCrypto/signatures/pull/534 +[#535]: https://github.com/RustCrypto/signatures/pull/535 + +## 0.14.5 (2022-09-06) +### Added +- Impl `EncodePrivateKey` for `SigningKey` ([#523]) +- `SigningKey::as_nonzero_scalar` ([#528]) +- `VerifyingKey::as_affine` ([#528]) +- `RecoveryId::from_byte` ([#531]) + +### Changed +- Make `RecoveryId` methods `const fn` ([#529]) + +[#523]: https://github.com/RustCrypto/signatures/pull/523 +[#528]: https://github.com/RustCrypto/signatures/pull/528 +[#529]: https://github.com/RustCrypto/signatures/pull/529 +[#531]: https://github.com/RustCrypto/signatures/pull/531 + +## 0.14.4 (2022-08-15) +### Added +- Impl `EncodePublicKey` for `VerifyingKey` ([#505]) +- ZeroizeOnDrop marker for SigningKey ([#509]) + +### Changed +- Restrict `signature` version to v1.5-v1.6 ([#508], [#512]) + +[#505]: https://github.com/RustCrypto/signatures/pull/505 +[#508]: https://github.com/RustCrypto/signatures/pull/508 +[#509]: https://github.com/RustCrypto/signatures/pull/509 +[#512]: https://github.com/RustCrypto/signatures/pull/512 + +## 0.14.3 (2022-06-26) [YANKED] +### Changed +- Simplified digest trait bounds ([#499]) +- Bump `rfc6979` dependency to v0.3 ([#500]) + +[#499]: https://github.com/RustCrypto/signatures/pull/499 +[#500]: https://github.com/RustCrypto/signatures/pull/500 + +## 0.14.2 (2022-06-17) [YANKED] +### Added +- Security warning in README.md ([#486]) + +### Changed +- Use `serdect` for `Signature` types ([#497]) + +[#486]: https://github.com/RustCrypto/signatures/pull/486 +[#497]: https://github.com/RustCrypto/signatures/pull/497 + +## 0.14.1 (2022-05-09) [YANKED] +### Added +- `SignPrimitive::try_sign_digest_rfc6979` ([#475]) +- `VerifyPrimitive::verify_digest` ([#475]) + +[#475]: https://github.com/RustCrypto/signatures/pull/475 + +## 0.14.0 (2022-05-09) [YANKED] +### Added +- `VerifyingKey::from_affine` ([#452]) + +### Changed +- Bump `digest` dependency to v0.10 ([#433]) +- `SignPrimitive` and `VerifyPrimitive` to accept `FieldBytes` rather than `Scalar` ([#460]) +- Replace `hazmat::rfc6979_generate_k` with `SignPrimitive::try_sign_prehashed_rfc6979` ([#460]) +- Bump `der` dependency to v0.6 ([#468]) +- Bump `elliptic-curve` dependency to v0.12 ([#468]) +- Bump `rfc6979` dependency to v0.2 ([#470]) + +[#433]: https://github.com/RustCrypto/signatures/pull/433 +[#452]: https://github.com/RustCrypto/signatures/pull/452 +[#460]: https://github.com/RustCrypto/signatures/pull/460 +[#468]: https://github.com/RustCrypto/signatures/pull/468 +[#470]: https://github.com/RustCrypto/signatures/pull/470 + +## 0.13.4 (2022-01-06) +### Added +- `Signature::to_vec` ([#428]) + +[#428]: https://github.com/RustCrypto/signatures/pull/428 + +## 0.13.3 (2021-12-04) +### Changed +- Use revised `LinearCombination` trait ([#419]) + +[#419]: https://github.com/RustCrypto/signatures/pull/419 + +## 0.13.2 (2021-12-04) [YANKED] +### Changed +- Use `LinearCombination` trait ([#417]) + +[#417]: https://github.com/RustCrypto/signatures/pull/417 + +## 0.13.1 (2021-12-03) [YANKED] +### Added +- `hazmat::rfc6979_generate_k` function ([#414]) + +[#414]: https://github.com/RustCrypto/signatures/pull/414 + +## 0.13.0 (2021-11-21) [YANKED] +### Added +- `RecoveryId` type ([#392]) +- Default generic impl of `SignPrimitive::try_sign_prehashed` ([#396]) +- Default generic impl of `VerifyPrimitive::verify_prehashed` ([#397]) +- `serde` support ([#406]) + +### Changed +- Make `Signature::normalize_s` non-mutating ([#355]) +- Switch from `ScalarBytes` to `ScalarCore` ([#356]) +- Use `PrimeCurve` trait ([#357]) +- Replace `FromDigest` trait with `Reduce` ([#372]) +- 2021 edition upgrade; MSRV 1.56 ([#384]) +- Allow `signature` v1.4 as a dependency ([#385]) +- Bump `der` dependency to v0.5 ([#408]) +- Bump `elliptic-curve` dependency to v0.11 ([#408]) +- Split out `rfc6979` crate ([#409]) + +### Removed +- `NormalizeLow` trait ([#393]) +- `RecoverableSignPrimitive` ([#394]) + +[#355]: https://github.com/RustCrypto/signatures/pull/355 +[#356]: https://github.com/RustCrypto/signatures/pull/356 +[#357]: https://github.com/RustCrypto/signatures/pull/357 +[#372]: https://github.com/RustCrypto/signatures/pull/372 +[#384]: https://github.com/RustCrypto/signatures/pull/384 +[#385]: https://github.com/RustCrypto/signatures/pull/385 +[#392]: https://github.com/RustCrypto/signatures/pull/392 +[#393]: https://github.com/RustCrypto/signatures/pull/393 +[#394]: https://github.com/RustCrypto/signatures/pull/394 +[#396]: https://github.com/RustCrypto/signatures/pull/396 +[#397]: https://github.com/RustCrypto/signatures/pull/397 +[#406]: https://github.com/RustCrypto/signatures/pull/406 +[#408]: https://github.com/RustCrypto/signatures/pull/408 +[#409]: https://github.com/RustCrypto/signatures/pull/409 + +## 0.12.4 (2021-08-12) +### Added +- Impl `Clone`, `Debug`, `*Eq` for `SigningKey` ([#345]) + +[#345]: https://github.com/RustCrypto/signatures/pull/345 + +## 0.12.3 (2021-06-17) +### Added +- Impl `TryFrom<&[u8]>` for `Verifying` ([#329]) +- Impl `TryFrom<&[u8]>` for `SigningKey` ([#330]) + +### Changed +- Use `signature::Result` alias ([#331]) + +[#329]: https://github.com/RustCrypto/signatures/pull/329 +[#330]: https://github.com/RustCrypto/signatures/pull/330 +[#331]: https://github.com/RustCrypto/signatures/pull/331 + +## 0.12.2 (2021-06-18) +### Added +- Zeroization on drop for `SigningKey` ([#321]) + +[#321]: https://github.com/RustCrypto/signatures/pull/321 + +## 0.12.1 (2021-06-09) +### Added +- Explicit `Copy` bounds on `VerifyingKey` ([#318]) + +[#318]: https://github.com/RustCrypto/signatures/pull/318 + +## 0.12.0 (2021-06-07) +### Changed +- Bump `der` crate to v0.4 ([#302], [#315]) +- Bump `elliptic-curve` crate dependency to v0.10 ([#315]) +- MSRV 1.51+ ([#302], [#315]) + +### Removed +- Bounds now expressed via `*Arithmetic` traits ([#303], [#312]) + +[#302]: https://github.com/RustCrypto/signatures/pull/302 +[#303]: https://github.com/RustCrypto/signatures/pull/303 +[#315]: https://github.com/RustCrypto/signatures/pull/315 + +## 0.11.1 (2021-05-24) +### Added +- `Ord` and `PartialOrd` impls on VerifyingKey ([#298], [#299]) + +### Changed +- Bump `elliptic-curve` dependency to v0.9.12 ([#299]) + +[#298]: https://github.com/RustCrypto/signatures/pull/298 +[#299]: https://github.com/RustCrypto/signatures/pull/299 + +## 0.11.0 (2021-04-29) +### Added +- `FromDigest` trait ([#238], [#244]) +- Wycheproof test vector support ([#260]) + +### Changed +- Use `der` crate for decoding/encoding signatures ([#226], [#267]) +- Support `HmacDrbg` with variable output size ([#243]) +- Bump `base64ct` and `pkcs8`; MSRV 1.47+ ([#262]) +- Flatten and simplify public API ([#268]) +- Use `verifying_key` name consistently ([#273]) +- Bound curve implementations on Order trait ([#280]) +- Bump `elliptic-curve` to v0.9.10+; use `ScalarBytes` ([#284]) +- Bump `hmac` crate dependency to v0.11 ([#287]) + +### Removed +- `FieldBytes` bounds ([#227]) +- `CheckSignatureBytes` trait ([#281]) + +[#226]: https://github.com/RustCrypto/signatures/pull/226 +[#227]: https://github.com/RustCrypto/signatures/pull/227 +[#238]: https://github.com/RustCrypto/signatures/pull/238 +[#243]: https://github.com/RustCrypto/signatures/pull/243 +[#244]: https://github.com/RustCrypto/signatures/pull/244 +[#260]: https://github.com/RustCrypto/signatures/pull/260 +[#262]: https://github.com/RustCrypto/signatures/pull/262 +[#267]: https://github.com/RustCrypto/signatures/pull/267 +[#268]: https://github.com/RustCrypto/signatures/pull/268 +[#273]: https://github.com/RustCrypto/signatures/pull/273 +[#280]: https://github.com/RustCrypto/signatures/pull/280 +[#281]: https://github.com/RustCrypto/signatures/pull/281 +[#284]: https://github.com/RustCrypto/signatures/pull/284 +[#287]: https://github.com/RustCrypto/signatures/pull/287 + +## 0.10.2 (2020-12-22) +### Changed +- Bump `elliptic-curve` crate to v0.8.3 ([#218]) +- Use the `dev` module from the `elliptic-curve` crate ([#218]) + +[#218]: https://github.com/RustCrypto/signatures/pull/218 + +## 0.10.1 (2020-12-16) [YANKED] +### Fixed +- Trigger docs.rs rebuild with nightly bugfix ([RustCrypto/traits#412]) + +[RustCrypto/traits#412]: https://github.com/RustCrypto/traits/pull/412 + +## 0.10.0 (2020-12-16) [YANKED] +### Changed +- Bump `elliptic-curve` dependency to v0.8 ([#215]) + +[#215]: https://github.com/RustCrypto/signatures/pull/215 + +## 0.9.0 (2020-12-06) +### Added +- PKCS#8 support ([#203]) + +### Changed +- Bump `elliptic-curve` crate dependency to v0.7; MSRV 1.46+ ([#204]) +- Rename `VerifyKey` to `VerifyingKey` ([#200]) +- Rename `VerifyingKey::new()` to `::from_sec1_bytes()` ([#198]) +- Rename `SigningKey::new()` to `::from_bytes()` ([#205]) + +### Fixed +- Additional validity checks on ASN.1 DER-encoded signatures ([#192]) + +[#205]: https://github.com/RustCrypto/signatures/pull/205 +[#204]: https://github.com/RustCrypto/signatures/pull/204 +[#203]: https://github.com/RustCrypto/signatures/pull/203 +[#200]: https://github.com/RustCrypto/signatures/pull/200 +[#198]: https://github.com/RustCrypto/signatures/pull/198 +[#192]: https://github.com/RustCrypto/signatures/pull/192 + +## 0.8.5 (2020-10-09) +### Fixed +- Bug in default impl of CheckSignatureBytes ([#184]) + +[#184]: https://github.com/RustCrypto/signatures/pull/184 + +## 0.8.4 (2020-10-08) +### Fixed +- Work around `nightly-2020-10-06` breakage ([#180]) + +[#180]: https://github.com/RustCrypto/signatures/pull/180 + +## 0.8.3 (2020-09-28) +### Fixed +- 32-bit builds for the `dev` feature ([#177]) + +[#177]: https://github.com/RustCrypto/signatures/pull/177 + +## 0.8.2 (2020-09-27) +### Added +- `RecoverableSignPrimitive` ([#174], [#175]) + +[#174]: https://github.com/RustCrypto/signatures/pull/174 +[#175]: https://github.com/RustCrypto/signatures/pull/175 + +## 0.8.1 (2020-09-23) +### Added +- Conditional `Copy` impl on `VerifyKey` ([#171]) + +[#171]: https://github.com/RustCrypto/signatures/pull/171 + +## 0.8.0 (2020-09-11) +### Added +- `CheckSignatureBytes` trait ([#151]) +- Add `Signature::r`/`::s` methods which return `NonZeroScalar`values ([#151]) +- `alloc` feature ([#150]) +- Impl `From<&VerifyKey>` for `EncodedPoint` ([#144]) +- Serialization methods for `SigningKey`/`VerifyKey` ([#143]) +- RFC6979-based deterministic signatures ([#133], [#134], [#136]) + +### Changed +- Bump `elliptic-curve` crate dependency to v0.6 ([#165]) +- Use `ProjectiveArithmetic` trait ([#164]) +- Rename `ElementBytes` to `FieldBytes` ([#160]) +- Use `ff` and `group` crates to v0.8 ([#156]) +- MSRV 1.44+ ([#156]) +- Remove `rand` feature; make `rand_core` a hard dependency ([#154]) +- Use `impl Into` bounds on `Signature::from_scalars` ([#149]) +- Derive `Clone`, `Debug`, `Eq`, and `Ord` on `VerifyKey` ([#148]) +- Renamed `{Signer, Verifier}` => `{SigningKey, VerifyKey}` ([#140]) +- Use newly refactored `sec1::EncodedPoint` ([#131]) + +### Removed +- `Generate` trait ([#159]) +- `RecoverableSignPrimitive` ([#146]) + +[#165]: https://github.com/RustCrypto/signatures/pull/165 +[#164]: https://github.com/RustCrypto/signatures/pull/164 +[#160]: https://github.com/RustCrypto/signatures/pull/160 +[#159]: https://github.com/RustCrypto/signatures/pull/159 +[#156]: https://github.com/RustCrypto/signatures/pull/156 +[#154]: https://github.com/RustCrypto/signatures/pull/154 +[#151]: https://github.com/RustCrypto/signatures/pull/151 +[#150]: https://github.com/RustCrypto/signatures/pull/150 +[#149]: https://github.com/RustCrypto/signatures/pull/149 +[#148]: https://github.com/RustCrypto/signatures/pull/148 +[#146]: https://github.com/RustCrypto/signatures/pull/146 +[#144]: https://github.com/RustCrypto/signatures/pull/144 +[#143]: https://github.com/RustCrypto/signatures/pull/143 +[#140]: https://github.com/RustCrypto/signatures/pull/140 +[#136]: https://github.com/RustCrypto/signatures/pull/136 +[#134]: https://github.com/RustCrypto/signatures/pull/134 +[#133]: https://github.com/RustCrypto/signatures/pull/133 +[#131]: https://github.com/RustCrypto/signatures/pull/131 + +## 0.7.2 (2020-08-11) +### Added +- Conditional `PrehashSignature` impl for `asn1::Signature` ([#128]) + +[#128]: https://github.com/RustCrypto/signatures/pull/128 + +## 0.7.1 (2020-08-10) +### Changed +- Use `all-features = true` on docs.rs ([#126]) + +[#126]: https://github.com/RustCrypto/signatures/pull/126 + +## 0.7.0 (2020-08-10) +### Added +- `hazmat` traits: `SignPrimitive`, `RecoverableSignPrimitive`, + `VerifyPrimitive`, `DigestPrimitive` ([#96], [#99], [#107], [#111]) +- `dev` module ([#103]) +- `NormalizeLow` trait ([#115], [#118], [#119]) +- `Copy` impl on `Signature` ([#117]) +- `RecoverableSignPrimitive` ([#120]) + +### Changed +- Bumped `elliptic-curve` crate to v0.5 release ([#123]) +- Renamed `FixedSignature` to `ecdsa::Signature` ([#98]) +- Renamed `Asn1Signature` to `ecdsa::asn1::Signature` ([#98], [#102]) + +### Removed +- Curve-specific types - migrated to `k256`, `p256`, `p384` crates ([#96]) + +[#96]: https://github.com/RustCrypto/signatures/pull/96 +[#98]: https://github.com/RustCrypto/signatures/pull/98 +[#99]: https://github.com/RustCrypto/signatures/pull/99 +[#102]: https://github.com/RustCrypto/signatures/pull/102 +[#103]: https://github.com/RustCrypto/signatures/pull/103 +[#107]: https://github.com/RustCrypto/signatures/pull/107 +[#111]: https://github.com/RustCrypto/signatures/pull/111 +[#115]: https://github.com/RustCrypto/signatures/pull/115 +[#117]: https://github.com/RustCrypto/signatures/pull/117 +[#118]: https://github.com/RustCrypto/signatures/pull/118 +[#119]: https://github.com/RustCrypto/signatures/pull/119 +[#120]: https://github.com/RustCrypto/signatures/pull/120 +[#123]: https://github.com/RustCrypto/signatures/pull/123 + +## 0.6.1 (2020-06-29) +### Added +- `doc_cfg` attributes for https://docs.rs ([#91]) +- `ecdsa::curve::secp256k1::RecoverableSignature` ([#90]) + +[#91]: https://github.com/RustCrypto/signatures/pull/91 +[#90]: https://github.com/RustCrypto/signatures/pull/90 + +## 0.6.0 (2020-06-09) +### Changed +- Upgrade to `signature` ~1.1.0; `sha` v0.9 ([#87]) +- Bump all elliptic curve crates; MSRV 1.41+ ([#86]) + +[#87]: https://github.com/RustCrypto/signatures/pull/87 +[#86]: https://github.com/RustCrypto/signatures/pull/86 + +## 0.5.0 (2020-04-18) +### Changed +- Upgrade `signature` crate to v1.0 final release ([#80]) + +[#80]: https://github.com/RustCrypto/signatures/pull/80 + +## 0.4.0 (2020-01-07) +### Changed +- Upgrade `elliptic-curve` crate to v0.3.0; make curves cargo features ([#68]) + +[#68]: https://github.com/RustCrypto/signatures/pull/68 + +## 0.3.0 (2019-12-11) +### Changed +- Upgrade `elliptic-curve` crate to v0.2.0; MSRV 1.37+ ([#65]) + +[#65]: https://github.com/RustCrypto/signatures/pull/65 + +## 0.2.1 (2019-12-06) +### Added +- Re-export `PublicKey` and `SecretKey` from the `elliptic-curve` crate ([#61]) + +[#61]: https://github.com/RustCrypto/signatures/pull/61 + +## 0.2.0 (2019-12-06) +### Changed +- Use curve types from the `elliptic-curve` crate ([#58]) + +[#58]: https://github.com/RustCrypto/signatures/pull/58 + +## 0.1.0 (2019-10-29) + +- Initial release diff --git a/src/rust/vendor/ecdsa/Cargo.toml b/src/rust/vendor/ecdsa/Cargo.toml new file mode 100644 index 000000000..482299de2 --- /dev/null +++ b/src/rust/vendor/ecdsa/Cargo.toml @@ -0,0 +1,148 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.65" +name = "ecdsa" +version = "0.16.9" +authors = ["RustCrypto Developers"] +description = """ +Pure Rust implementation of the Elliptic Curve Digital Signature Algorithm +(ECDSA) as specified in FIPS 186-4 (Digital Signature Standard), providing +RFC6979 deterministic signatures as well as support for added entropy +""" +readme = "README.md" +keywords = [ + "crypto", + "ecc", + "nist", + "secp256k1", + "signature", +] +categories = [ + "cryptography", + "no-std", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/RustCrypto/signatures/tree/master/ecdsa" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.der] +version = "0.7" +optional = true + +[dependencies.digest] +version = "0.10.7" +features = ["oid"] +optional = true +default-features = false + +[dependencies.elliptic-curve] +version = "0.13.6" +features = [ + "digest", + "sec1", +] +default-features = false + +[dependencies.rfc6979] +version = "0.4" +optional = true + +[dependencies.serdect] +version = "0.2" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.sha2] +version = "0.10" +features = ["oid"] +optional = true +default-features = false + +[dependencies.signature] +version = "2.0, <2.3" +features = ["rand_core"] +default-features = false + +[dependencies.spki] +version = "0.7.2" +optional = true +default-features = false + +[dev-dependencies.elliptic-curve] +version = "0.13" +features = ["dev"] +default-features = false + +[dev-dependencies.hex-literal] +version = "0.4" + +[dev-dependencies.sha2] +version = "0.10" +default-features = false + +[features] +alloc = [ + "elliptic-curve/alloc", + "signature/alloc", + "spki/alloc", +] +arithmetic = ["elliptic-curve/arithmetic"] +default = ["digest"] +dev = [ + "arithmetic", + "digest", + "elliptic-curve/dev", + "hazmat", +] +digest = [ + "dep:digest", + "signature/digest", +] +hazmat = [] +pem = [ + "elliptic-curve/pem", + "pkcs8", +] +pkcs8 = [ + "digest", + "elliptic-curve/pkcs8", + "der", +] +serde = [ + "elliptic-curve/serde", + "serdect", +] +signing = [ + "arithmetic", + "digest", + "hazmat", + "rfc6979", +] +std = [ + "alloc", + "elliptic-curve/std", + "signature/std", +] +verifying = [ + "arithmetic", + "digest", + "hazmat", +] diff --git a/src/rust/vendor/ecdsa/LICENSE-APACHE b/src/rust/vendor/ecdsa/LICENSE-APACHE new file mode 100644 index 000000000..c394d8ad9 --- /dev/null +++ b/src/rust/vendor/ecdsa/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2018-2022 RustCrypto Developers + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/ecdsa/LICENSE-MIT b/src/rust/vendor/ecdsa/LICENSE-MIT new file mode 100644 index 000000000..81a3d57ac --- /dev/null +++ b/src/rust/vendor/ecdsa/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2018-2022 RustCrypto Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/ecdsa/README.md b/src/rust/vendor/ecdsa/README.md new file mode 100644 index 000000000..06ed0dc37 --- /dev/null +++ b/src/rust/vendor/ecdsa/README.md @@ -0,0 +1,93 @@ +# [RustCrypto]: ECDSA + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +[![Build Status][build-image]][build-link] +![Apache2/MIT licensed][license-image] +![MSRV][rustc-image] +[![Project Chat][chat-image]][chat-link] + +[Elliptic Curve Digital Signature Algorithm (ECDSA)][1] as specified in +[FIPS 186-4][2] (Digital Signature Standard). + +[Documentation][docs-link] + +## About + +This crate provides generic ECDSA support which can be used in the following +ways: + +- Generic implementation of ECDSA usable with the following crates: + - [`k256`] (secp256k1) + - [`p256`] (NIST P-256) + - [`p384`] (NIST P-384) +- Other crates which provide their own complete implementations of ECDSA can + also leverage the types from this crate to export ECDSA functionality in a + generic, interoperable way by leveraging [`ecdsa::Signature`] with the + [`signature::Signer`] and [`signature::Verifier`] traits. + +## ⚠️ Security Warning + +The ECDSA implementation contained in this crate has never been independently +audited for security! + +This crate contains a generic implementation of ECDSA which must be +instantiated using a separate crate providing a concrete implementation of +arithmetic for a particular curve. It's possible timing variability can exist +in concrete curve implementations, and thus this crate's security can only be +properly assessed for a specific elliptic curve. + +USE AT YOUR OWN RISK! + +## Minimum Supported Rust Version + +This crate requires **Rust 1.65** at a minimum. + +We may change the MSRV in the future, but it will be accompanied by a minor +version bump. + +## License + +All crates licensed under either of + +- [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) +- [MIT license](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. + +[//]: # (badges) + +[crate-image]: https://buildstats.info/crate/ecdsa +[crate-link]: https://crates.io/crates/ecdsa +[docs-image]: https://docs.rs/ecdsa/badge.svg +[docs-link]: https://docs.rs/ecdsa/ +[build-image]: https://github.com/RustCrypto/signatures/actions/workflows/ecdsa.yml/badge.svg +[build-link]: https://github.com/RustCrypto/signatures/actions/workflows/ecdsa.yml +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260048-signatures + +[//]: # (links) + +[RustCrypto]: https://github.com/RustCrypto + +[//]: # (footnotes) + +[1]: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +[2]: https://csrc.nist.gov/publications/detail/fips/186/4/final + +[//]: # (docs.rs definitions) + +[`ecdsa::Signature`]: https://docs.rs/ecdsa/latest/ecdsa/struct.Signature.html +[`k256`]: https://docs.rs/k256 +[`p256`]: https://docs.rs/p256 +[`p384`]: https://docs.rs/p384 +[`signature::Signer`]: https://docs.rs/signature/latest/signature/trait.Signer.html +[`signature::Verifier`]: https://docs.rs/signature/latest/signature/trait.Verifier.html diff --git a/src/rust/vendor/ecdsa/src/der.rs b/src/rust/vendor/ecdsa/src/der.rs new file mode 100644 index 000000000..b4b03c172 --- /dev/null +++ b/src/rust/vendor/ecdsa/src/der.rs @@ -0,0 +1,464 @@ +//! Support for ASN.1 DER-encoded ECDSA signatures as specified in +//! [RFC5912 Appendix A]. +//! +//! [RFC5912 Appendix A]: https://www.rfc-editor.org/rfc/rfc5912#appendix-A + +use crate::{Error, Result}; +use core::{ + fmt::{self, Debug}, + ops::{Add, Range}, +}; +use der::{asn1::UintRef, Decode, Encode, FixedTag, Length, Reader, Tag, Writer}; +use elliptic_curve::{ + consts::U9, + generic_array::{typenum::Unsigned, ArrayLength, GenericArray}, + FieldBytesSize, PrimeCurve, +}; + +#[cfg(feature = "alloc")] +use { + alloc::{boxed::Box, vec::Vec}, + signature::SignatureEncoding, + spki::{der::asn1::BitString, SignatureBitStringEncoding}, +}; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +/// Maximum overhead of an ASN.1 DER-encoded ECDSA signature for a given curve: +/// 9-bytes. +/// +/// Includes 3-byte ASN.1 DER header: +/// +/// - 1-byte: ASN.1 `SEQUENCE` tag (0x30) +/// - 2-byte: length +/// +/// ...followed by two ASN.1 `INTEGER` values, which each have a header whose +/// maximum length is the following: +/// +/// - 1-byte: ASN.1 `INTEGER` tag (0x02) +/// - 1-byte: length +/// - 1-byte: zero to indicate value is positive (`INTEGER` is signed) +pub type MaxOverhead = U9; + +/// Maximum size of an ASN.1 DER encoded signature for the given elliptic curve. +pub type MaxSize = < as Add>::Output as Add>::Output; + +/// Byte array containing a serialized ASN.1 signature +type SignatureBytes = GenericArray>; + +/// ASN.1 DER-encoded signature as specified in [RFC5912 Appendix A]: +/// +/// ```text +/// ECDSA-Sig-Value ::= SEQUENCE { +/// r INTEGER, +/// s INTEGER +/// } +/// ``` +/// +/// [RFC5912 Appendix A]: https://www.rfc-editor.org/rfc/rfc5912#appendix-A +pub struct Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + /// ASN.1 DER-encoded signature data + bytes: SignatureBytes, + + /// Range of the `r` value within the signature + r_range: Range, + + /// Range of the `s` value within the signature + s_range: Range, +} + +#[allow(clippy::len_without_is_empty)] +impl Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + /// Parse signature from DER-encoded bytes. + pub fn from_bytes(input: &[u8]) -> Result { + let (r, s) = decode_der(input).map_err(|_| Error::new())?; + + if r.as_bytes().len() > C::FieldBytesSize::USIZE + || s.as_bytes().len() > C::FieldBytesSize::USIZE + { + return Err(Error::new()); + } + + let r_range = find_scalar_range(input, r.as_bytes())?; + let s_range = find_scalar_range(input, s.as_bytes())?; + + if s_range.end != input.len() { + return Err(Error::new()); + } + + let mut bytes = SignatureBytes::::default(); + bytes[..s_range.end].copy_from_slice(input); + + Ok(Signature { + bytes, + r_range, + s_range, + }) + } + + /// Create an ASN.1 DER encoded signature from big endian `r` and `s` scalar + /// components. + pub(crate) fn from_components(r: &[u8], s: &[u8]) -> der::Result { + let r = UintRef::new(r)?; + let s = UintRef::new(s)?; + + let mut bytes = SignatureBytes::::default(); + let mut writer = der::SliceWriter::new(&mut bytes); + + writer.sequence((r.encoded_len()? + s.encoded_len()?)?, |seq| { + seq.encode(&r)?; + seq.encode(&s) + })?; + + writer + .finish()? + .try_into() + .map_err(|_| der::Tag::Sequence.value_error()) + } + + /// Borrow this signature as a byte slice + pub fn as_bytes(&self) -> &[u8] { + &self.bytes.as_slice()[..self.len()] + } + + /// Serialize this signature as a boxed byte slice + #[cfg(feature = "alloc")] + pub fn to_bytes(&self) -> Box<[u8]> { + self.as_bytes().to_vec().into_boxed_slice() + } + + /// Get the length of the signature in bytes + pub fn len(&self) -> usize { + self.s_range.end + } + + /// Get the `r` component of the signature (leading zeros removed) + pub(crate) fn r(&self) -> &[u8] { + &self.bytes[self.r_range.clone()] + } + + /// Get the `s` component of the signature (leading zeros removed) + pub(crate) fn s(&self) -> &[u8] { + &self.bytes[self.s_range.clone()] + } +} + +impl AsRef<[u8]> for Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl Clone for Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn clone(&self) -> Self { + Self { + bytes: self.bytes.clone(), + r_range: self.r_range.clone(), + s_range: self.s_range.clone(), + } + } +} + +impl Debug for Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ecdsa::der::Signature<{:?}>(", C::default())?; + + for &byte in self.as_ref() { + write!(f, "{:02X}", byte)?; + } + + write!(f, ")") + } +} + +impl<'a, C> Decode<'a> for Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn decode>(reader: &mut R) -> der::Result { + let header = reader.peek_header()?; + header.tag.assert_eq(Tag::Sequence)?; + + let mut buf = SignatureBytes::::default(); + let len = (header.encoded_len()? + header.length)?; + let slice = buf + .get_mut(..usize::try_from(len)?) + .ok_or_else(|| reader.error(Tag::Sequence.length_error().kind()))?; + + reader.read_into(slice)?; + Self::from_bytes(slice).map_err(|_| Tag::Integer.value_error()) + } +} + +impl Encode for Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn encoded_len(&self) -> der::Result { + Length::try_from(self.len()) + } + + fn encode(&self, writer: &mut impl Writer) -> der::Result<()> { + writer.write(self.as_bytes()) + } +} + +impl FixedTag for Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + const TAG: Tag = Tag::Sequence; +} + +impl From> for Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn from(sig: crate::Signature) -> Signature { + sig.to_der() + } +} + +impl TryFrom<&[u8]> for Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + type Error = Error; + + fn try_from(input: &[u8]) -> Result { + Self::from_bytes(input) + } +} + +impl TryFrom> for crate::Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + type Error = Error; + + fn try_from(sig: Signature) -> Result> { + let mut bytes = super::SignatureBytes::::default(); + let r_begin = C::FieldBytesSize::USIZE.saturating_sub(sig.r().len()); + let s_begin = bytes.len().saturating_sub(sig.s().len()); + bytes[r_begin..C::FieldBytesSize::USIZE].copy_from_slice(sig.r()); + bytes[s_begin..].copy_from_slice(sig.s()); + Self::try_from(bytes.as_slice()) + } +} + +#[cfg(feature = "alloc")] +impl From> for Box<[u8]> +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn from(signature: Signature) -> Box<[u8]> { + signature.to_vec().into_boxed_slice() + } +} + +#[cfg(feature = "alloc")] +impl SignatureEncoding for Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + type Repr = Box<[u8]>; + + fn to_vec(&self) -> Vec { + self.as_bytes().into() + } +} + +#[cfg(feature = "alloc")] +impl SignatureBitStringEncoding for Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn to_bitstring(&self) -> der::Result { + BitString::new(0, self.to_vec()) + } +} + +#[cfg(feature = "serde")] +impl Serialize for Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn serialize(&self, serializer: S) -> core::result::Result + where + S: ser::Serializer, + { + serdect::slice::serialize_hex_upper_or_bin(&self.as_bytes(), serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, C> Deserialize<'de> for Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn deserialize(deserializer: D) -> core::result::Result + where + D: de::Deserializer<'de>, + { + let mut buf = SignatureBytes::::default(); + let slice = serdect::slice::deserialize_hex_or_bin(&mut buf, deserializer)?; + Self::try_from(slice).map_err(de::Error::custom) + } +} + +/// Decode the `r` and `s` components of a DER-encoded ECDSA signature. +fn decode_der(der_bytes: &[u8]) -> der::Result<(UintRef<'_>, UintRef<'_>)> { + let mut reader = der::SliceReader::new(der_bytes)?; + let header = der::Header::decode(&mut reader)?; + header.tag.assert_eq(der::Tag::Sequence)?; + + let ret = reader.read_nested(header.length, |reader| { + let r = UintRef::decode(reader)?; + let s = UintRef::decode(reader)?; + Ok((r, s)) + })?; + + reader.finish(ret) +} + +/// Locate the range within a slice at which a particular subslice is located +fn find_scalar_range(outer: &[u8], inner: &[u8]) -> Result> { + let outer_start = outer.as_ptr() as usize; + let inner_start = inner.as_ptr() as usize; + let start = inner_start + .checked_sub(outer_start) + .ok_or_else(Error::new)?; + let end = start.checked_add(inner.len()).ok_or_else(Error::new)?; + Ok(Range { start, end }) +} + +#[cfg(all(feature = "digest", feature = "hazmat"))] +impl signature::PrehashSignature for Signature +where + C: PrimeCurve + crate::hazmat::DigestPrimitive, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + type Digest = C::Digest; +} + +#[cfg(all(test, feature = "arithmetic"))] +mod tests { + use elliptic_curve::dev::MockCurve; + + type Signature = crate::Signature; + + const EXAMPLE_SIGNATURE: [u8; 64] = [ + 0xf3, 0xac, 0x80, 0x61, 0xb5, 0x14, 0x79, 0x5b, 0x88, 0x43, 0xe3, 0xd6, 0x62, 0x95, 0x27, + 0xed, 0x2a, 0xfd, 0x6b, 0x1f, 0x6a, 0x55, 0x5a, 0x7a, 0xca, 0xbb, 0x5e, 0x6f, 0x79, 0xc8, + 0xc2, 0xac, 0x8b, 0xf7, 0x78, 0x19, 0xca, 0x5, 0xa6, 0xb2, 0x78, 0x6c, 0x76, 0x26, 0x2b, + 0xf7, 0x37, 0x1c, 0xef, 0x97, 0xb2, 0x18, 0xe9, 0x6f, 0x17, 0x5a, 0x3c, 0xcd, 0xda, 0x2a, + 0xcc, 0x5, 0x89, 0x3, + ]; + + #[test] + fn test_fixed_to_asn1_signature_roundtrip() { + let signature1 = Signature::try_from(EXAMPLE_SIGNATURE.as_ref()).unwrap(); + + // Convert to ASN.1 DER and back + let asn1_signature = signature1.to_der(); + let signature2 = Signature::from_der(asn1_signature.as_ref()).unwrap(); + + assert_eq!(signature1, signature2); + } + + #[test] + fn test_asn1_too_short_signature() { + assert!(Signature::from_der(&[]).is_err()); + assert!(Signature::from_der(&[der::Tag::Sequence.into()]).is_err()); + assert!(Signature::from_der(&[der::Tag::Sequence.into(), 0x00]).is_err()); + assert!(Signature::from_der(&[ + der::Tag::Sequence.into(), + 0x03, + der::Tag::Integer.into(), + 0x01, + 0x01 + ]) + .is_err()); + } + + #[test] + fn test_asn1_non_der_signature() { + // A minimal 8-byte ASN.1 signature parses OK. + assert!(Signature::from_der(&[ + der::Tag::Sequence.into(), + 0x06, // length of below + der::Tag::Integer.into(), + 0x01, // length of value + 0x01, // value=1 + der::Tag::Integer.into(), + 0x01, // length of value + 0x01, // value=1 + ]) + .is_ok()); + + // But length fields that are not minimally encoded should be rejected, as they are not + // valid DER, cf. + // https://github.com/google/wycheproof/blob/2196000605e4/testvectors/ecdsa_secp256k1_sha256_test.json#L57-L66 + assert!(Signature::from_der(&[ + der::Tag::Sequence.into(), + 0x81, // extended length: 1 length byte to come + 0x06, // length of below + der::Tag::Integer.into(), + 0x01, // length of value + 0x01, // value=1 + der::Tag::Integer.into(), + 0x01, // length of value + 0x01, // value=1 + ]) + .is_err()); + } +} diff --git a/src/rust/vendor/ecdsa/src/dev.rs b/src/rust/vendor/ecdsa/src/dev.rs new file mode 100644 index 000000000..8c1b7c876 --- /dev/null +++ b/src/rust/vendor/ecdsa/src/dev.rs @@ -0,0 +1,230 @@ +//! Development-related functionality. + +// TODO(tarcieri): implement full set of tests from ECDSA2VS +// + +/// ECDSA test vector +pub struct TestVector { + /// Private scalar + pub d: &'static [u8], + + /// Public key x-coordinate (`Qx`) + pub q_x: &'static [u8], + + /// Public key y-coordinate (`Qy`) + pub q_y: &'static [u8], + + /// Ephemeral scalar (a.k.a. nonce) + pub k: &'static [u8], + + /// Message digest (prehashed) + pub m: &'static [u8], + + /// Signature `r` component + pub r: &'static [u8], + + /// Signature `s` component + pub s: &'static [u8], +} + +/// Define ECDSA signing test. +#[macro_export] +macro_rules! new_signing_test { + ($curve:path, $vectors:expr) => { + use $crate::{ + elliptic_curve::{ + bigint::Encoding, + generic_array::{typenum::Unsigned, GenericArray}, + group::ff::PrimeField, + Curve, CurveArithmetic, Scalar, + }, + hazmat::SignPrimitive, + }; + + fn decode_scalar(bytes: &[u8]) -> Option> { + if bytes.len() == <$curve as Curve>::FieldBytesSize::USIZE { + Scalar::<$curve>::from_repr(GenericArray::clone_from_slice(bytes)).into() + } else { + None + } + } + + #[test] + fn ecdsa_signing() { + for vector in $vectors { + let d = decode_scalar(vector.d).expect("invalid vector.d"); + let k = decode_scalar(vector.k).expect("invalid vector.m"); + + assert_eq!( + <$curve as Curve>::FieldBytesSize::USIZE, + vector.m.len(), + "invalid vector.m (must be field-sized digest)" + ); + let z = GenericArray::clone_from_slice(vector.m); + let sig = d.try_sign_prehashed(k, &z).expect("ECDSA sign failed").0; + + assert_eq!(vector.r, sig.r().to_bytes().as_slice()); + assert_eq!(vector.s, sig.s().to_bytes().as_slice()); + } + } + }; +} + +/// Define ECDSA verification test. +#[macro_export] +macro_rules! new_verification_test { + ($curve:path, $vectors:expr) => { + use $crate::{ + elliptic_curve::{ + generic_array::GenericArray, + group::ff::PrimeField, + sec1::{EncodedPoint, FromEncodedPoint}, + AffinePoint, CurveArithmetic, Scalar, + }, + hazmat::VerifyPrimitive, + Signature, + }; + + #[test] + fn ecdsa_verify_success() { + for vector in $vectors { + let q_encoded = EncodedPoint::<$curve>::from_affine_coordinates( + GenericArray::from_slice(vector.q_x), + GenericArray::from_slice(vector.q_y), + false, + ); + + let q = AffinePoint::<$curve>::from_encoded_point(&q_encoded).unwrap(); + let z = GenericArray::clone_from_slice(vector.m); + + let sig = Signature::from_scalars( + GenericArray::clone_from_slice(vector.r), + GenericArray::clone_from_slice(vector.s), + ) + .unwrap(); + + let result = q.verify_prehashed(&z, &sig); + assert!(result.is_ok()); + } + } + + #[test] + fn ecdsa_verify_invalid_s() { + for vector in $vectors { + let q_encoded = EncodedPoint::<$curve>::from_affine_coordinates( + GenericArray::from_slice(vector.q_x), + GenericArray::from_slice(vector.q_y), + false, + ); + + let q = AffinePoint::<$curve>::from_encoded_point(&q_encoded).unwrap(); + let z = GenericArray::clone_from_slice(vector.m); + + // Flip a bit in `s` + let mut s_tweaked = GenericArray::clone_from_slice(vector.s); + s_tweaked[0] ^= 1; + + let sig = + Signature::from_scalars(GenericArray::clone_from_slice(vector.r), s_tweaked) + .unwrap(); + + let result = q.verify_prehashed(&z, &sig); + assert!(result.is_err()); + } + } + + // TODO(tarcieri): test invalid Q, invalid r, invalid m + }; +} + +/// Define a Wycheproof verification test. +#[macro_export] +macro_rules! new_wycheproof_test { + ($name:ident, $test_name: expr, $curve:path) => { + use $crate::{ + elliptic_curve::{bigint::Integer, sec1::EncodedPoint}, + signature::Verifier, + Signature, + }; + + #[test] + fn $name() { + use blobby::Blob5Iterator; + use elliptic_curve::{bigint::Encoding as _, generic_array::typenum::Unsigned}; + + // Build a field element but allow for too-short input (left pad with zeros) + // or too-long input (check excess leftmost bytes are zeros). + fn element_from_padded_slice( + data: &[u8], + ) -> elliptic_curve::FieldBytes { + let point_len = C::FieldBytesSize::USIZE; + if data.len() >= point_len { + let offset = data.len() - point_len; + for v in data.iter().take(offset) { + assert_eq!(*v, 0, "EcdsaVerifier: point too large"); + } + elliptic_curve::FieldBytes::::clone_from_slice(&data[offset..]) + } else { + // Provided slice is too short and needs to be padded with zeros + // on the left. Build a combined exact iterator to do this. + let iter = core::iter::repeat(0) + .take(point_len - data.len()) + .chain(data.iter().cloned()); + elliptic_curve::FieldBytes::::from_exact_iter(iter).unwrap() + } + } + + fn run_test( + wx: &[u8], + wy: &[u8], + msg: &[u8], + sig: &[u8], + pass: bool, + ) -> Option<&'static str> { + let x = element_from_padded_slice::<$curve>(wx); + let y = element_from_padded_slice::<$curve>(wy); + let q_encoded = EncodedPoint::<$curve>::from_affine_coordinates( + &x, &y, /* compress= */ false, + ); + let verifying_key = + $crate::VerifyingKey::<$curve>::from_encoded_point(&q_encoded).unwrap(); + + let sig = match Signature::from_der(sig) { + Ok(s) => s, + Err(_) if !pass => return None, + Err(_) => return Some("failed to parse signature ASN.1"), + }; + + match verifying_key.verify(msg, &sig) { + Ok(_) if pass => None, + Ok(_) => Some("signature verify unexpectedly succeeded"), + Err(_) if !pass => None, + Err(_) => Some("signature verify failed"), + } + } + + let data = include_bytes!(concat!("test_vectors/data/", $test_name, ".blb")); + + for (i, row) in Blob5Iterator::new(data).unwrap().enumerate() { + let [wx, wy, msg, sig, status] = row.unwrap(); + let pass = match status[0] { + 0 => false, + 1 => true, + _ => panic!("invalid value for pass flag"), + }; + if let Some(desc) = run_test(wx, wy, msg, sig, pass) { + panic!( + "\n\ + Failed test №{}: {}\n\ + wx:\t{:?}\n\ + wy:\t{:?}\n\ + msg:\t{:?}\n\ + sig:\t{:?}\n\ + pass:\t{}\n", + i, desc, wx, wy, msg, sig, pass, + ); + } + } + } + }; +} diff --git a/src/rust/vendor/ecdsa/src/hazmat.rs b/src/rust/vendor/ecdsa/src/hazmat.rs new file mode 100644 index 000000000..0f7ddbf2a --- /dev/null +++ b/src/rust/vendor/ecdsa/src/hazmat.rs @@ -0,0 +1,332 @@ +//! Low-level ECDSA primitives. +//! +//! # ⚠️ Warning: Hazmat! +//! +//! YOU PROBABLY DON'T WANT TO USE THESE! +//! +//! These primitives are easy-to-misuse low-level interfaces. +//! +//! If you are an end user / non-expert in cryptography, do not use these! +//! Failure to use them correctly can lead to catastrophic failures including +//! FULL PRIVATE KEY RECOVERY! + +use crate::{Error, Result}; +use core::cmp; +use elliptic_curve::{generic_array::typenum::Unsigned, FieldBytes, PrimeCurve}; + +#[cfg(feature = "arithmetic")] +use { + crate::{RecoveryId, SignatureSize}, + elliptic_curve::{ + ff::{Field, PrimeField}, + group::{Curve as _, Group}, + ops::{Invert, LinearCombination, MulByGenerator, Reduce}, + point::AffineCoordinates, + scalar::IsHigh, + subtle::CtOption, + CurveArithmetic, ProjectivePoint, Scalar, + }, +}; + +#[cfg(feature = "digest")] +use { + elliptic_curve::FieldBytesSize, + signature::{ + digest::{core_api::BlockSizeUser, Digest, FixedOutput, FixedOutputReset}, + PrehashSignature, + }, +}; + +#[cfg(feature = "rfc6979")] +use elliptic_curve::{FieldBytesEncoding, ScalarPrimitive}; + +#[cfg(any(feature = "arithmetic", feature = "digest"))] +use crate::{elliptic_curve::generic_array::ArrayLength, Signature}; + +/// Try to sign the given prehashed message using ECDSA. +/// +/// This trait is intended to be implemented on a type with access to the +/// secret scalar via `&self`, such as particular curve's `Scalar` type. +#[cfg(feature = "arithmetic")] +pub trait SignPrimitive: + AsRef + + Into> + + IsHigh + + PrimeField> + + Reduce> + + Sized +where + C: PrimeCurve + CurveArithmetic, + SignatureSize: ArrayLength, +{ + /// Try to sign the prehashed message. + /// + /// Accepts the following arguments: + /// + /// - `k`: ephemeral scalar value. MUST BE UNIFORMLY RANDOM!!! + /// - `z`: message digest to be signed. MUST BE OUTPUT OF A CRYPTOGRAPHICALLY + /// SECURE DIGEST ALGORITHM!!! + /// + /// # Returns + /// + /// ECDSA [`Signature`] and, when possible/desired, a [`RecoveryId`] + /// which can be used to recover the verifying key for a given signature. + fn try_sign_prehashed( + &self, + k: K, + z: &FieldBytes, + ) -> Result<(Signature, Option)> + where + K: AsRef + Invert>, + { + sign_prehashed(self, k, z).map(|(sig, recid)| (sig, (Some(recid)))) + } + + /// Try to sign the given message digest deterministically using the method + /// described in [RFC6979] for computing ECDSA ephemeral scalar `k`. + /// + /// Accepts the following parameters: + /// - `z`: message digest to be signed. + /// - `ad`: optional additional data, e.g. added entropy from an RNG + /// + /// [RFC6979]: https://datatracker.ietf.org/doc/html/rfc6979 + #[cfg(feature = "rfc6979")] + fn try_sign_prehashed_rfc6979( + &self, + z: &FieldBytes, + ad: &[u8], + ) -> Result<(Signature, Option)> + where + Self: From> + Invert>, + D: Digest + BlockSizeUser + FixedOutput> + FixedOutputReset, + { + let k = Scalar::::from_repr(rfc6979::generate_k::( + &self.to_repr(), + &C::ORDER.encode_field_bytes(), + z, + ad, + )) + .unwrap(); + + self.try_sign_prehashed::(k, z) + } +} + +/// Verify the given prehashed message using ECDSA. +/// +/// This trait is intended to be implemented on type which can access +/// the affine point represeting the public key via `&self`, such as a +/// particular curve's `AffinePoint` type. +#[cfg(feature = "arithmetic")] +pub trait VerifyPrimitive: AffineCoordinates> + Copy + Sized +where + C: PrimeCurve + CurveArithmetic, + SignatureSize: ArrayLength, +{ + /// Verify the prehashed message against the provided ECDSA signature. + /// + /// Accepts the following arguments: + /// + /// - `z`: message digest to be verified. MUST BE OUTPUT OF A + /// CRYPTOGRAPHICALLY SECURE DIGEST ALGORITHM!!! + /// - `sig`: signature to be verified against the key and message + fn verify_prehashed(&self, z: &FieldBytes, sig: &Signature) -> Result<()> { + verify_prehashed(&ProjectivePoint::::from(*self), z, sig) + } + + /// Verify message digest against the provided signature. + #[cfg(feature = "digest")] + fn verify_digest(&self, msg_digest: D, sig: &Signature) -> Result<()> + where + D: FixedOutput>, + { + self.verify_prehashed(&msg_digest.finalize_fixed(), sig) + } +} + +/// Bind a preferred [`Digest`] algorithm to an elliptic curve type. +/// +/// Generally there is a preferred variety of the SHA-2 family used with ECDSA +/// for a particular elliptic curve. +/// +/// This trait can be used to specify it, and with it receive a blanket impl of +/// [`PrehashSignature`], used by [`signature_derive`][1]) for the [`Signature`] +/// type for a particular elliptic curve. +/// +/// [1]: https://github.com/RustCrypto/traits/tree/master/signature/derive +#[cfg(feature = "digest")] +pub trait DigestPrimitive: PrimeCurve { + /// Preferred digest to use when computing ECDSA signatures for this + /// elliptic curve. This is typically a member of the SHA-2 family. + type Digest: BlockSizeUser + + Digest + + FixedOutput> + + FixedOutputReset; +} + +#[cfg(feature = "digest")] +impl PrehashSignature for Signature +where + C: DigestPrimitive, + as core::ops::Add>::Output: ArrayLength, +{ + type Digest = C::Digest; +} + +/// Partial implementation of the `bits2int` function as defined in +/// [RFC6979 § 2.3.2] as well as [SEC1] § 2.3.8. +/// +/// This is used to convert a message digest whose size may be smaller or +/// larger than the size of the curve's scalar field into a serialized +/// (unreduced) field element. +/// +/// [RFC6979 § 2.3.2]: https://datatracker.ietf.org/doc/html/rfc6979#section-2.3.2 +/// [SEC1]: https://www.secg.org/sec1-v2.pdf +pub fn bits2field(bits: &[u8]) -> Result> { + // Minimum allowed bits size is half the field size + if bits.len() < C::FieldBytesSize::USIZE / 2 { + return Err(Error::new()); + } + + let mut field_bytes = FieldBytes::::default(); + + match bits.len().cmp(&C::FieldBytesSize::USIZE) { + cmp::Ordering::Equal => field_bytes.copy_from_slice(bits), + cmp::Ordering::Less => { + // If bits is smaller than the field size, pad with zeroes on the left + field_bytes[(C::FieldBytesSize::USIZE - bits.len())..].copy_from_slice(bits); + } + cmp::Ordering::Greater => { + // If bits is larger than the field size, truncate + field_bytes.copy_from_slice(&bits[..C::FieldBytesSize::USIZE]); + } + } + + Ok(field_bytes) +} + +/// Sign a prehashed message digest using the provided secret scalar and +/// ephemeral scalar, returning an ECDSA signature. +/// +/// Accepts the following arguments: +/// +/// - `d`: signing key. MUST BE UNIFORMLY RANDOM!!! +/// - `k`: ephemeral scalar value. MUST BE UNIFORMLY RANDOM!!! +/// - `z`: message digest to be signed. MUST BE OUTPUT OF A CRYPTOGRAPHICALLY +/// SECURE DIGEST ALGORITHM!!! +/// +/// # Returns +/// +/// ECDSA [`Signature`] and, when possible/desired, a [`RecoveryId`] +/// which can be used to recover the verifying key for a given signature. +#[cfg(feature = "arithmetic")] +#[allow(non_snake_case)] +pub fn sign_prehashed( + d: &Scalar, + k: K, + z: &FieldBytes, +) -> Result<(Signature, RecoveryId)> +where + C: PrimeCurve + CurveArithmetic, + K: AsRef> + Invert>>, + SignatureSize: ArrayLength, +{ + // TODO(tarcieri): use `NonZeroScalar` for `k`. + if k.as_ref().is_zero().into() { + return Err(Error::new()); + } + + let z = as Reduce>::reduce_bytes(z); + + // Compute scalar inversion of 𝑘 + let k_inv = Option::>::from(k.invert()).ok_or_else(Error::new)?; + + // Compute 𝑹 = 𝑘×𝑮 + let R = ProjectivePoint::::mul_by_generator(k.as_ref()).to_affine(); + + // Lift x-coordinate of 𝑹 (element of base field) into a serialized big + // integer, then reduce it into an element of the scalar field + let r = Scalar::::reduce_bytes(&R.x()); + let x_is_reduced = r.to_repr() != R.x(); + + // Compute 𝒔 as a signature over 𝒓 and 𝒛. + let s = k_inv * (z + (r * d)); + + // NOTE: `Signature::from_scalars` checks that both `r` and `s` are non-zero. + let signature = Signature::from_scalars(r, s)?; + let recovery_id = RecoveryId::new(R.y_is_odd().into(), x_is_reduced); + Ok((signature, recovery_id)) +} + +/// Verify the prehashed message against the provided ECDSA signature. +/// +/// Accepts the following arguments: +/// +/// - `q`: public key with which to verify the signature. +/// - `z`: message digest to be verified. MUST BE OUTPUT OF A +/// CRYPTOGRAPHICALLY SECURE DIGEST ALGORITHM!!! +/// - `sig`: signature to be verified against the key and message. +#[cfg(feature = "arithmetic")] +pub fn verify_prehashed( + q: &ProjectivePoint, + z: &FieldBytes, + sig: &Signature, +) -> Result<()> +where + C: PrimeCurve + CurveArithmetic, + SignatureSize: ArrayLength, +{ + let z = Scalar::::reduce_bytes(z); + let (r, s) = sig.split_scalars(); + let s_inv = *s.invert_vartime(); + let u1 = z * s_inv; + let u2 = *r * s_inv; + let x = ProjectivePoint::::lincomb(&ProjectivePoint::::generator(), &u1, q, &u2) + .to_affine() + .x(); + + if *r == Scalar::::reduce_bytes(&x) { + Ok(()) + } else { + Err(Error::new()) + } +} + +#[cfg(test)] +mod tests { + use super::bits2field; + use elliptic_curve::dev::MockCurve; + use hex_literal::hex; + + #[test] + fn bits2field_too_small() { + assert!(bits2field::(b"").is_err()); + } + + #[test] + fn bits2field_size_less() { + let prehash = hex!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + let field_bytes = bits2field::(&prehash).unwrap(); + assert_eq!( + field_bytes.as_slice(), + &hex!("00000000000000000000000000000000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") + ); + } + + #[test] + fn bits2field_size_eq() { + let prehash = hex!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + let field_bytes = bits2field::(&prehash).unwrap(); + assert_eq!(field_bytes.as_slice(), &prehash); + } + + #[test] + fn bits2field_size_greater() { + let prehash = hex!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"); + let field_bytes = bits2field::(&prehash).unwrap(); + assert_eq!( + field_bytes.as_slice(), + &hex!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") + ); + } +} diff --git a/src/rust/vendor/ecdsa/src/lib.rs b/src/rust/vendor/ecdsa/src/lib.rs new file mode 100644 index 000000000..a449829b5 --- /dev/null +++ b/src/rust/vendor/ecdsa/src/lib.rs @@ -0,0 +1,709 @@ +#![no_std] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![doc = include_str!("../README.md")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg" +)] +#![forbid(unsafe_code)] +#![warn( + clippy::cast_lossless, + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::cast_precision_loss, + clippy::cast_sign_loss, + clippy::checked_conversions, + clippy::implicit_saturating_sub, + clippy::panic, + clippy::panic_in_result_fn, + clippy::unwrap_used, + missing_docs, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] + +//! ## `serde` support +//! +//! When the `serde` feature of this crate is enabled, `Serialize` and +//! `Deserialize` impls are provided for the [`Signature`] and [`VerifyingKey`] +//! types. +//! +//! Please see type-specific documentation for more information. +//! +//! ## Interop +//! +//! Any crates which provide an implementation of ECDSA for a particular +//! elliptic curve can leverage the types from this crate, along with the +//! [`k256`], [`p256`], and/or [`p384`] crates to expose ECDSA functionality in +//! a generic, interoperable way by leveraging the [`Signature`] type with in +//! conjunction with the [`signature::Signer`] and [`signature::Verifier`] +//! traits. +//! +//! For example, the [`ring-compat`] crate implements the [`signature::Signer`] +//! and [`signature::Verifier`] traits in conjunction with the +//! [`p256::ecdsa::Signature`] and [`p384::ecdsa::Signature`] types to +//! wrap the ECDSA implementations from [*ring*] in a generic, interoperable +//! API. +//! +//! [`k256`]: https://docs.rs/k256 +//! [`p256`]: https://docs.rs/p256 +//! [`p256::ecdsa::Signature`]: https://docs.rs/p256/latest/p256/ecdsa/type.Signature.html +//! [`p384`]: https://docs.rs/p384 +//! [`p384::ecdsa::Signature`]: https://docs.rs/p384/latest/p384/ecdsa/type.Signature.html +//! [`ring-compat`]: https://docs.rs/ring-compat +//! [*ring*]: https://docs.rs/ring + +#[cfg(feature = "alloc")] +extern crate alloc; + +mod normalized; +mod recovery; + +#[cfg(feature = "der")] +pub mod der; +#[cfg(feature = "dev")] +pub mod dev; +#[cfg(feature = "hazmat")] +pub mod hazmat; +#[cfg(feature = "signing")] +mod signing; +#[cfg(feature = "verifying")] +mod verifying; + +pub use crate::{normalized::NormalizedSignature, recovery::RecoveryId}; + +// Re-export the `elliptic-curve` crate (and select types) +pub use elliptic_curve::{self, sec1::EncodedPoint, PrimeCurve}; + +// Re-export the `signature` crate (and select types) +pub use signature::{self, Error, Result, SignatureEncoding}; + +#[cfg(feature = "signing")] +pub use crate::signing::SigningKey; +#[cfg(feature = "verifying")] +pub use crate::verifying::VerifyingKey; + +use core::{fmt, ops::Add}; +use elliptic_curve::{ + generic_array::{typenum::Unsigned, ArrayLength, GenericArray}, + FieldBytes, FieldBytesSize, ScalarPrimitive, +}; + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +#[cfg(feature = "arithmetic")] +use { + core::str, + elliptic_curve::{scalar::IsHigh, CurveArithmetic, NonZeroScalar}, +}; + +#[cfg(feature = "digest")] +use digest::{ + const_oid::{AssociatedOid, ObjectIdentifier}, + Digest, +}; + +#[cfg(feature = "pkcs8")] +use elliptic_curve::pkcs8::spki::{ + der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier, +}; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +use elliptic_curve::pkcs8::spki::{ + self, AlgorithmIdentifierOwned, DynAssociatedAlgorithmIdentifier, +}; + +/// OID for ECDSA with SHA-224 digests. +/// +/// ```text +/// ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { iso(1) member-body(2) +/// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 1 } +/// ``` +// TODO(tarcieri): use `ObjectIdentifier::push_arc` when const unwrap is stable +#[cfg(feature = "digest")] +pub const ECDSA_SHA224_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.1"); + +/// OID for ECDSA with SHA-256 digests. +/// +/// ```text +/// ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2) +/// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 } +/// ``` +#[cfg(feature = "digest")] +pub const ECDSA_SHA256_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.2"); + +/// OID for ECDSA with SHA-384 digests. +/// +/// ```text +/// ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2) +/// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 } +/// ``` +#[cfg(feature = "digest")] +pub const ECDSA_SHA384_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.3"); + +/// OID for ECDSA with SHA-512 digests. +/// +/// ```text +/// ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2) +/// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 } +/// ``` +#[cfg(feature = "digest")] +pub const ECDSA_SHA512_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.4"); + +#[cfg(feature = "digest")] +const SHA224_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.4"); +#[cfg(feature = "digest")] +const SHA256_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.1"); +#[cfg(feature = "digest")] +const SHA384_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.2"); +#[cfg(feature = "digest")] +const SHA512_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.3"); + +/// Size of a fixed sized signature for the given elliptic curve. +pub type SignatureSize = as Add>::Output; + +/// Fixed-size byte array containing an ECDSA signature +pub type SignatureBytes = GenericArray>; + +/// ECDSA signature (fixed-size). Generic over elliptic curve types. +/// +/// Serialized as fixed-sized big endian scalar values with no added framing: +/// +/// - `r`: field element size for the given curve, big-endian +/// - `s`: field element size for the given curve, big-endian +/// +/// Both `r` and `s` MUST be non-zero. +/// +/// For example, in a curve with a 256-bit modulus like NIST P-256 or +/// secp256k1, `r` and `s` will both be 32-bytes and serialized as big endian, +/// resulting in a signature with a total of 64-bytes. +/// +/// ASN.1 DER-encoded signatures also supported via the +/// [`Signature::from_der`] and [`Signature::to_der`] methods. +/// +/// # `serde` support +/// +/// When the `serde` feature of this crate is enabled, it provides support for +/// serializing and deserializing ECDSA signatures using the `Serialize` and +/// `Deserialize` traits. +/// +/// The serialization uses a hexadecimal encoding when used with +/// "human readable" text formats, and a binary encoding otherwise. +#[derive(Clone, Eq, PartialEq)] +pub struct Signature { + r: ScalarPrimitive, + s: ScalarPrimitive, +} + +impl Signature +where + C: PrimeCurve, + SignatureSize: ArrayLength, +{ + /// Parse a signature from fixed-width bytes, i.e. 2 * the size of + /// [`FieldBytes`] for a particular curve. + /// + /// # Returns + /// - `Ok(signature)` if the `r` and `s` components are both in the valid + /// range `1..n` when serialized as concatenated big endian integers. + /// - `Err(err)` if the `r` and/or `s` component of the signature is + /// out-of-range when interpreted as a big endian integer. + pub fn from_bytes(bytes: &SignatureBytes) -> Result { + let (r_bytes, s_bytes) = bytes.split_at(C::FieldBytesSize::USIZE); + let r = FieldBytes::::clone_from_slice(r_bytes); + let s = FieldBytes::::clone_from_slice(s_bytes); + Self::from_scalars(r, s) + } + + /// Parse a signature from a byte slice. + pub fn from_slice(slice: &[u8]) -> Result { + if slice.len() == SignatureSize::::USIZE { + Self::from_bytes(SignatureBytes::::from_slice(slice)) + } else { + Err(Error::new()) + } + } + + /// Parse a signature from ASN.1 DER. + #[cfg(feature = "der")] + pub fn from_der(bytes: &[u8]) -> Result + where + der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, + { + der::Signature::::try_from(bytes).and_then(Self::try_from) + } + + /// Create a [`Signature`] from the serialized `r` and `s` scalar values + /// which comprise the signature. + /// + /// # Returns + /// - `Ok(signature)` if the `r` and `s` components are both in the valid + /// range `1..n` when serialized as concatenated big endian integers. + /// - `Err(err)` if the `r` and/or `s` component of the signature is + /// out-of-range when interpreted as a big endian integer. + pub fn from_scalars(r: impl Into>, s: impl Into>) -> Result { + let r = ScalarPrimitive::from_slice(&r.into()).map_err(|_| Error::new())?; + let s = ScalarPrimitive::from_slice(&s.into()).map_err(|_| Error::new())?; + + if r.is_zero().into() || s.is_zero().into() { + return Err(Error::new()); + } + + Ok(Self { r, s }) + } + + /// Split the signature into its `r` and `s` components, represented as bytes. + pub fn split_bytes(&self) -> (FieldBytes, FieldBytes) { + (self.r.to_bytes(), self.s.to_bytes()) + } + + /// Serialize this signature as bytes. + pub fn to_bytes(&self) -> SignatureBytes { + let mut bytes = SignatureBytes::::default(); + let (r_bytes, s_bytes) = bytes.split_at_mut(C::FieldBytesSize::USIZE); + r_bytes.copy_from_slice(&self.r.to_bytes()); + s_bytes.copy_from_slice(&self.s.to_bytes()); + bytes + } + + /// Serialize this signature as ASN.1 DER. + #[cfg(feature = "der")] + pub fn to_der(&self) -> der::Signature + where + der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, + { + let (r, s) = self.split_bytes(); + der::Signature::from_components(&r, &s).expect("DER encoding error") + } + + /// Convert this signature into a byte vector. + #[cfg(feature = "alloc")] + pub fn to_vec(&self) -> Vec { + self.to_bytes().to_vec() + } +} + +#[cfg(feature = "arithmetic")] +impl Signature +where + C: PrimeCurve + CurveArithmetic, + SignatureSize: ArrayLength, +{ + /// Get the `r` component of this signature + pub fn r(&self) -> NonZeroScalar { + NonZeroScalar::new(self.r.into()).unwrap() + } + + /// Get the `s` component of this signature + pub fn s(&self) -> NonZeroScalar { + NonZeroScalar::new(self.s.into()).unwrap() + } + + /// Split the signature into its `r` and `s` scalars. + pub fn split_scalars(&self) -> (NonZeroScalar, NonZeroScalar) { + (self.r(), self.s()) + } + + /// Normalize signature into "low S" form as described in + /// [BIP 0062: Dealing with Malleability][1]. + /// + /// [1]: https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki + pub fn normalize_s(&self) -> Option { + let s = self.s(); + + if s.is_high().into() { + let mut result = self.clone(); + result.s = ScalarPrimitive::from(-s); + Some(result) + } else { + None + } + } +} + +impl Copy for Signature +where + C: PrimeCurve, + SignatureSize: ArrayLength, + as ArrayLength>::ArrayType: Copy, +{ +} + +impl From> for SignatureBytes +where + C: PrimeCurve, + SignatureSize: ArrayLength, +{ + fn from(signature: Signature) -> SignatureBytes { + signature.to_bytes() + } +} + +impl SignatureEncoding for Signature +where + C: PrimeCurve, + SignatureSize: ArrayLength, +{ + type Repr = SignatureBytes; +} + +impl TryFrom<&[u8]> for Signature +where + C: PrimeCurve, + SignatureSize: ArrayLength, +{ + type Error = Error; + + fn try_from(slice: &[u8]) -> Result { + Self::from_slice(slice) + } +} + +impl fmt::Debug for Signature +where + C: PrimeCurve, + SignatureSize: ArrayLength, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ecdsa::Signature<{:?}>(", C::default())?; + + for byte in self.to_bytes() { + write!(f, "{:02X}", byte)?; + } + + write!(f, ")") + } +} + +impl fmt::Display for Signature +where + C: PrimeCurve, + SignatureSize: ArrayLength, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:X}", self) + } +} + +impl fmt::LowerHex for Signature +where + C: PrimeCurve, + SignatureSize: ArrayLength, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for byte in self.to_bytes() { + write!(f, "{:02x}", byte)?; + } + Ok(()) + } +} + +impl fmt::UpperHex for Signature +where + C: PrimeCurve, + SignatureSize: ArrayLength, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for byte in self.to_bytes() { + write!(f, "{:02X}", byte)?; + } + Ok(()) + } +} + +#[cfg(feature = "arithmetic")] +impl str::FromStr for Signature +where + C: PrimeCurve + CurveArithmetic, + SignatureSize: ArrayLength, +{ + type Err = Error; + + fn from_str(hex: &str) -> Result { + if hex.as_bytes().len() != C::FieldBytesSize::USIZE * 4 { + return Err(Error::new()); + } + + // This check is mainly to ensure `hex.split_at` below won't panic + if !hex + .as_bytes() + .iter() + .all(|&byte| matches!(byte, b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z')) + { + return Err(Error::new()); + } + + let (r_hex, s_hex) = hex.split_at(C::FieldBytesSize::USIZE * 2); + + let r = r_hex + .parse::>() + .map_err(|_| Error::new())?; + + let s = s_hex + .parse::>() + .map_err(|_| Error::new())?; + + Self::from_scalars(r, s) + } +} + +/// ECDSA [`ObjectIdentifier`] which identifies the digest used by default +/// with the `Signer` and `Verifier` traits. +/// +/// To support non-default digest algorithms, use the [`SignatureWithOid`] +/// type instead. +#[cfg(all(feature = "digest", feature = "hazmat"))] +impl AssociatedOid for Signature +where + C: hazmat::DigestPrimitive, + C::Digest: AssociatedOid, +{ + const OID: ObjectIdentifier = match ecdsa_oid_for_digest(C::Digest::OID) { + Some(oid) => oid, + None => panic!("no RFC5758 ECDSA OID defined for DigestPrimitive::Digest"), + }; +} + +/// ECDSA `AlgorithmIdentifier` which identifies the digest used by default +/// with the `Signer` and `Verifier` traits. +#[cfg(feature = "pkcs8")] +impl AssociatedAlgorithmIdentifier for Signature +where + C: PrimeCurve, + Self: AssociatedOid, +{ + type Params = AnyRef<'static>; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = AlgorithmIdentifierRef { + oid: Self::OID, + parameters: None, + }; +} + +#[cfg(feature = "serde")] +impl Serialize for Signature +where + C: PrimeCurve, + SignatureSize: ArrayLength, +{ + fn serialize(&self, serializer: S) -> core::result::Result + where + S: ser::Serializer, + { + serdect::array::serialize_hex_upper_or_bin(&self.to_bytes(), serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, C> Deserialize<'de> for Signature +where + C: PrimeCurve, + SignatureSize: ArrayLength, +{ + fn deserialize(deserializer: D) -> core::result::Result + where + D: de::Deserializer<'de>, + { + let mut bytes = SignatureBytes::::default(); + serdect::array::deserialize_hex_or_bin(&mut bytes, deserializer)?; + Self::try_from(bytes.as_slice()).map_err(de::Error::custom) + } +} + +/// An extended [`Signature`] type which is parameterized by an +/// `ObjectIdentifier` which identifies the ECDSA variant used by a +/// particular signature. +/// +/// Valid `ObjectIdentifiers` are defined in [RFC5758 § 3.2]: +/// +/// - SHA-224: [`ECDSA_SHA224_OID`] (1.2.840.10045.4.3.1) +/// - SHA-256: [`ECDSA_SHA256_OID`] (1.2.840.10045.4.3.2) +/// - SHA-384: [`ECDSA_SHA384_OID`] (1.2.840.10045.4.3.3) +/// - SHA-512: [`ECDSA_SHA512_OID`] (1.2.840.10045.4.3.4) +/// +/// [RFC5758 § 3.2]: https://www.rfc-editor.org/rfc/rfc5758#section-3.2 +#[cfg(feature = "digest")] +#[derive(Clone, Eq, PartialEq)] +pub struct SignatureWithOid { + /// Inner signature type. + signature: Signature, + + /// OID which identifies the ECDSA variant used. + /// + /// MUST be one of the ECDSA algorithm variants as defined in RFC5758. + /// + /// These OIDs begin with `1.2.840.10045.4`. + oid: ObjectIdentifier, +} + +#[cfg(feature = "digest")] +impl SignatureWithOid +where + C: PrimeCurve, +{ + /// Create a new signature with an explicitly provided OID. + /// + /// OID must begin with `1.2.840.10045.4`, the [RFC5758] OID prefix for + /// ECDSA variants. + /// + /// [RFC5758]: https://www.rfc-editor.org/rfc/rfc5758#section-3.2 + pub fn new(signature: Signature, oid: ObjectIdentifier) -> Result { + // TODO(tarcieri): use `ObjectIdentifier::starts_with` + for (arc1, arc2) in ObjectIdentifier::new_unwrap("1.2.840.10045.4.3") + .arcs() + .zip(oid.arcs()) + { + if arc1 != arc2 { + return Err(Error::new()); + } + } + + Ok(Self { signature, oid }) + } + + /// Create a new signature, determining the OID from the given digest. + /// + /// Supports SHA-2 family digests as enumerated in [RFC5758 § 3.2], i.e. + /// SHA-224, SHA-256, SHA-384, or SHA-512. + /// + /// [RFC5758 § 3.2]: https://www.rfc-editor.org/rfc/rfc5758#section-3.2 + pub fn new_with_digest(signature: Signature) -> Result + where + D: AssociatedOid + Digest, + { + let oid = ecdsa_oid_for_digest(D::OID).ok_or_else(Error::new)?; + Ok(Self { signature, oid }) + } + + /// Parse a signature from fixed-with bytes. + pub fn from_bytes_with_digest(bytes: &SignatureBytes) -> Result + where + D: AssociatedOid + Digest, + SignatureSize: ArrayLength, + { + Self::new_with_digest::(Signature::::from_bytes(bytes)?) + } + + /// Parse a signature from a byte slice. + pub fn from_slice_with_digest(slice: &[u8]) -> Result + where + D: AssociatedOid + Digest, + SignatureSize: ArrayLength, + { + Self::new_with_digest::(Signature::::from_slice(slice)?) + } + + /// Get the fixed-width ECDSA signature. + pub fn signature(&self) -> &Signature { + &self.signature + } + + /// Get the ECDSA OID for this signature. + pub fn oid(&self) -> ObjectIdentifier { + self.oid + } + + /// Serialize this signature as bytes. + pub fn to_bytes(&self) -> SignatureBytes + where + SignatureSize: ArrayLength, + { + self.signature.to_bytes() + } +} + +#[cfg(feature = "digest")] +impl Copy for SignatureWithOid +where + C: PrimeCurve, + SignatureSize: ArrayLength, + as ArrayLength>::ArrayType: Copy, +{ +} + +#[cfg(feature = "digest")] +impl From> for Signature +where + C: PrimeCurve, +{ + fn from(sig: SignatureWithOid) -> Signature { + sig.signature + } +} + +#[cfg(feature = "digest")] +impl From> for SignatureBytes +where + C: PrimeCurve, + SignatureSize: ArrayLength, +{ + fn from(signature: SignatureWithOid) -> SignatureBytes { + signature.to_bytes() + } +} + +/// NOTE: this implementation assumes the default digest for the given elliptic +/// curve as defined by [`hazmat::DigestPrimitive`]. +/// +/// When working with alternative digests, you will need to use e.g. +/// [`SignatureWithOid::new_with_digest`]. +#[cfg(all(feature = "digest", feature = "hazmat"))] +impl SignatureEncoding for SignatureWithOid +where + C: hazmat::DigestPrimitive, + C::Digest: AssociatedOid, + SignatureSize: ArrayLength, +{ + type Repr = SignatureBytes; +} + +/// NOTE: this implementation assumes the default digest for the given elliptic +/// curve as defined by [`hazmat::DigestPrimitive`]. +/// +/// When working with alternative digests, you will need to use e.g. +/// [`SignatureWithOid::new_with_digest`]. +#[cfg(all(feature = "digest", feature = "hazmat"))] +impl TryFrom<&[u8]> for SignatureWithOid +where + C: hazmat::DigestPrimitive, + C::Digest: AssociatedOid, + SignatureSize: ArrayLength, +{ + type Error = Error; + + fn try_from(slice: &[u8]) -> Result { + Self::new(Signature::::from_slice(slice)?, C::Digest::OID) + } +} + +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +impl DynAssociatedAlgorithmIdentifier for SignatureWithOid +where + C: PrimeCurve, +{ + fn algorithm_identifier(&self) -> spki::Result { + Ok(AlgorithmIdentifierOwned { + oid: self.oid, + parameters: None, + }) + } +} + +/// Get the ECDSA OID for a given digest OID. +#[cfg(feature = "digest")] +const fn ecdsa_oid_for_digest(digest_oid: ObjectIdentifier) -> Option { + match digest_oid { + SHA224_OID => Some(ECDSA_SHA224_OID), + SHA256_OID => Some(ECDSA_SHA256_OID), + SHA384_OID => Some(ECDSA_SHA384_OID), + SHA512_OID => Some(ECDSA_SHA512_OID), + _ => None, + } +} diff --git a/src/rust/vendor/ecdsa/src/normalized.rs b/src/rust/vendor/ecdsa/src/normalized.rs new file mode 100644 index 000000000..6a66a4b74 --- /dev/null +++ b/src/rust/vendor/ecdsa/src/normalized.rs @@ -0,0 +1,11 @@ +//! Support for ECDSA signatures with low-S normalization. + +use crate::Signature; +use elliptic_curve::PrimeCurve; + +/// ECDSA signature with low-S normalization applied. +#[derive(Clone, Eq, PartialEq)] +#[repr(transparent)] +pub struct NormalizedSignature { + inner: Signature, +} diff --git a/src/rust/vendor/ecdsa/src/recovery.rs b/src/rust/vendor/ecdsa/src/recovery.rs new file mode 100644 index 000000000..dd1b6aed5 --- /dev/null +++ b/src/rust/vendor/ecdsa/src/recovery.rs @@ -0,0 +1,357 @@ +//! Public key recovery support. + +use crate::{Error, Result}; + +#[cfg(feature = "signing")] +use { + crate::{hazmat::SignPrimitive, SigningKey}, + elliptic_curve::subtle::CtOption, + signature::{hazmat::PrehashSigner, DigestSigner, Signer}, +}; + +#[cfg(feature = "verifying")] +use { + crate::{hazmat::VerifyPrimitive, VerifyingKey}, + elliptic_curve::{ + bigint::CheckedAdd, + ops::{LinearCombination, Reduce}, + point::DecompressPoint, + sec1::{self, FromEncodedPoint, ToEncodedPoint}, + AffinePoint, FieldBytesEncoding, FieldBytesSize, Group, PrimeField, ProjectivePoint, + }, + signature::hazmat::PrehashVerifier, +}; + +#[cfg(any(feature = "signing", feature = "verifying"))] +use { + crate::{ + hazmat::{bits2field, DigestPrimitive}, + Signature, SignatureSize, + }, + elliptic_curve::{ + generic_array::ArrayLength, ops::Invert, CurveArithmetic, PrimeCurve, Scalar, + }, + signature::digest::Digest, +}; + +/// Recovery IDs, a.k.a. "recid". +/// +/// This is an integer value `0`, `1`, `2`, or `3` included along with a +/// signature which is used during the recovery process to select the correct +/// public key from the signature. +/// +/// It consists of two bits of information: +/// +/// - low bit (0/1): was the y-coordinate of the affine point resulting from +/// the fixed-base multiplication 𝑘×𝑮 odd? This part of the algorithm +/// functions similar to point decompression. +/// - hi bit (3/4): did the affine x-coordinate of 𝑘×𝑮 overflow the order of +/// the scalar field, requiring a reduction when computing `r`? +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct RecoveryId(u8); + +impl RecoveryId { + /// Maximum supported value for the recovery ID (inclusive). + pub const MAX: u8 = 3; + + /// Create a new [`RecoveryId`] from the following 1-bit arguments: + /// + /// - `is_y_odd`: is the affine y-coordinate of 𝑘×𝑮 odd? + /// - `is_x_reduced`: did the affine x-coordinate of 𝑘×𝑮 overflow the curve order? + pub const fn new(is_y_odd: bool, is_x_reduced: bool) -> Self { + Self((is_x_reduced as u8) << 1 | (is_y_odd as u8)) + } + + /// Did the affine x-coordinate of 𝑘×𝑮 overflow the curve order? + pub const fn is_x_reduced(self) -> bool { + (self.0 & 0b10) != 0 + } + + /// Is the affine y-coordinate of 𝑘×𝑮 odd? + pub const fn is_y_odd(self) -> bool { + (self.0 & 1) != 0 + } + + /// Convert a `u8` into a [`RecoveryId`]. + pub const fn from_byte(byte: u8) -> Option { + if byte <= Self::MAX { + Some(Self(byte)) + } else { + None + } + } + + /// Convert this [`RecoveryId`] into a `u8`. + pub const fn to_byte(self) -> u8 { + self.0 + } +} + +#[cfg(feature = "verifying")] +impl RecoveryId { + /// Given a public key, message, and signature, use trial recovery + /// to determine if a suitable recovery ID exists, or return an error + /// otherwise. + pub fn trial_recovery_from_msg( + verifying_key: &VerifyingKey, + msg: &[u8], + signature: &Signature, + ) -> Result + where + C: DigestPrimitive + PrimeCurve + CurveArithmetic, + AffinePoint: + DecompressPoint + FromEncodedPoint + ToEncodedPoint + VerifyPrimitive, + FieldBytesSize: sec1::ModulusSize, + SignatureSize: ArrayLength, + { + Self::trial_recovery_from_digest(verifying_key, C::Digest::new_with_prefix(msg), signature) + } + + /// Given a public key, message digest, and signature, use trial recovery + /// to determine if a suitable recovery ID exists, or return an error + /// otherwise. + pub fn trial_recovery_from_digest( + verifying_key: &VerifyingKey, + digest: D, + signature: &Signature, + ) -> Result + where + C: PrimeCurve + CurveArithmetic, + D: Digest, + AffinePoint: + DecompressPoint + FromEncodedPoint + ToEncodedPoint + VerifyPrimitive, + FieldBytesSize: sec1::ModulusSize, + SignatureSize: ArrayLength, + { + Self::trial_recovery_from_prehash(verifying_key, &digest.finalize(), signature) + } + + /// Given a public key, message digest, and signature, use trial recovery + /// to determine if a suitable recovery ID exists, or return an error + /// otherwise. + pub fn trial_recovery_from_prehash( + verifying_key: &VerifyingKey, + prehash: &[u8], + signature: &Signature, + ) -> Result + where + C: PrimeCurve + CurveArithmetic, + AffinePoint: + DecompressPoint + FromEncodedPoint + ToEncodedPoint + VerifyPrimitive, + FieldBytesSize: sec1::ModulusSize, + SignatureSize: ArrayLength, + { + for id in 0..=Self::MAX { + let recovery_id = RecoveryId(id); + + if let Ok(vk) = VerifyingKey::recover_from_prehash(prehash, signature, recovery_id) { + if verifying_key == &vk { + return Ok(recovery_id); + } + } + } + + Err(Error::new()) + } +} + +impl TryFrom for RecoveryId { + type Error = Error; + + fn try_from(byte: u8) -> Result { + Self::from_byte(byte).ok_or_else(Error::new) + } +} + +impl From for u8 { + fn from(id: RecoveryId) -> u8 { + id.0 + } +} + +#[cfg(feature = "signing")] +impl SigningKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + /// Sign the given message prehash, returning a signature and recovery ID. + pub fn sign_prehash_recoverable(&self, prehash: &[u8]) -> Result<(Signature, RecoveryId)> { + let z = bits2field::(prehash)?; + let (sig, recid) = self + .as_nonzero_scalar() + .try_sign_prehashed_rfc6979::(&z, &[])?; + + Ok((sig, recid.ok_or_else(Error::new)?)) + } + + /// Sign the given message digest, returning a signature and recovery ID. + pub fn sign_digest_recoverable(&self, msg_digest: D) -> Result<(Signature, RecoveryId)> + where + D: Digest, + { + self.sign_prehash_recoverable(&msg_digest.finalize()) + } + + /// Sign the given message, hashing it with the curve's default digest + /// function, and returning a signature and recovery ID. + pub fn sign_recoverable(&self, msg: &[u8]) -> Result<(Signature, RecoveryId)> { + self.sign_digest_recoverable(C::Digest::new_with_prefix(msg)) + } +} + +#[cfg(feature = "signing")] +impl DigestSigner, RecoveryId)> for SigningKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + D: Digest, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn try_sign_digest(&self, msg_digest: D) -> Result<(Signature, RecoveryId)> { + self.sign_digest_recoverable(msg_digest) + } +} + +#[cfg(feature = "signing")] +impl PrehashSigner<(Signature, RecoveryId)> for SigningKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn sign_prehash(&self, prehash: &[u8]) -> Result<(Signature, RecoveryId)> { + self.sign_prehash_recoverable(prehash) + } +} + +#[cfg(feature = "signing")] +impl Signer<(Signature, RecoveryId)> for SigningKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn try_sign(&self, msg: &[u8]) -> Result<(Signature, RecoveryId)> { + self.sign_recoverable(msg) + } +} + +#[cfg(feature = "verifying")] +impl VerifyingKey +where + C: PrimeCurve + CurveArithmetic, + AffinePoint: + DecompressPoint + FromEncodedPoint + ToEncodedPoint + VerifyPrimitive, + FieldBytesSize: sec1::ModulusSize, + SignatureSize: ArrayLength, +{ + /// Recover a [`VerifyingKey`] from the given message, signature, and + /// [`RecoveryId`]. + /// + /// The message is first hashed using this curve's [`DigestPrimitive`]. + pub fn recover_from_msg( + msg: &[u8], + signature: &Signature, + recovery_id: RecoveryId, + ) -> Result + where + C: DigestPrimitive, + { + Self::recover_from_digest(C::Digest::new_with_prefix(msg), signature, recovery_id) + } + + /// Recover a [`VerifyingKey`] from the given message [`Digest`], + /// signature, and [`RecoveryId`]. + pub fn recover_from_digest( + msg_digest: D, + signature: &Signature, + recovery_id: RecoveryId, + ) -> Result + where + D: Digest, + { + Self::recover_from_prehash(&msg_digest.finalize(), signature, recovery_id) + } + + /// Recover a [`VerifyingKey`] from the given `prehash` of a message, the + /// signature over that prehashed message, and a [`RecoveryId`]. + #[allow(non_snake_case)] + pub fn recover_from_prehash( + prehash: &[u8], + signature: &Signature, + recovery_id: RecoveryId, + ) -> Result { + let (r, s) = signature.split_scalars(); + let z = as Reduce>::reduce_bytes(&bits2field::(prehash)?); + + let mut r_bytes = r.to_repr(); + if recovery_id.is_x_reduced() { + match Option::::from( + C::Uint::decode_field_bytes(&r_bytes).checked_add(&C::ORDER), + ) { + Some(restored) => r_bytes = restored.encode_field_bytes(), + // No reduction should happen here if r was reduced + None => return Err(Error::new()), + }; + } + let R = AffinePoint::::decompress(&r_bytes, u8::from(recovery_id.is_y_odd()).into()); + + if R.is_none().into() { + return Err(Error::new()); + } + + let R = ProjectivePoint::::from(R.unwrap()); + let r_inv = *r.invert(); + let u1 = -(r_inv * z); + let u2 = r_inv * *s; + let pk = ProjectivePoint::::lincomb(&ProjectivePoint::::generator(), &u1, &R, &u2); + let vk = Self::from_affine(pk.into())?; + + // Ensure signature verifies with the recovered key + vk.verify_prehash(prehash, signature)?; + + Ok(vk) + } +} + +#[cfg(test)] +mod tests { + use super::RecoveryId; + + #[test] + fn new() { + assert_eq!(RecoveryId::new(false, false).to_byte(), 0); + assert_eq!(RecoveryId::new(true, false).to_byte(), 1); + assert_eq!(RecoveryId::new(false, true).to_byte(), 2); + assert_eq!(RecoveryId::new(true, true).to_byte(), 3); + } + + #[test] + fn try_from() { + for n in 0u8..=3 { + assert_eq!(RecoveryId::try_from(n).unwrap().to_byte(), n); + } + + for n in 4u8..=255 { + assert!(RecoveryId::try_from(n).is_err()); + } + } + + #[test] + fn is_x_reduced() { + assert_eq!(RecoveryId::try_from(0).unwrap().is_x_reduced(), false); + assert_eq!(RecoveryId::try_from(1).unwrap().is_x_reduced(), false); + assert_eq!(RecoveryId::try_from(2).unwrap().is_x_reduced(), true); + assert_eq!(RecoveryId::try_from(3).unwrap().is_x_reduced(), true); + } + + #[test] + fn is_y_odd() { + assert_eq!(RecoveryId::try_from(0).unwrap().is_y_odd(), false); + assert_eq!(RecoveryId::try_from(1).unwrap().is_y_odd(), true); + assert_eq!(RecoveryId::try_from(2).unwrap().is_y_odd(), false); + assert_eq!(RecoveryId::try_from(3).unwrap().is_y_odd(), true); + } +} diff --git a/src/rust/vendor/ecdsa/src/signing.rs b/src/rust/vendor/ecdsa/src/signing.rs new file mode 100644 index 000000000..3a40c6db3 --- /dev/null +++ b/src/rust/vendor/ecdsa/src/signing.rs @@ -0,0 +1,598 @@ +//! ECDSA signing: producing signatures using a [`SigningKey`]. + +use crate::{ + ecdsa_oid_for_digest, + hazmat::{bits2field, DigestPrimitive, SignPrimitive}, + Error, Result, Signature, SignatureSize, SignatureWithOid, +}; +use core::fmt::{self, Debug}; +use digest::{const_oid::AssociatedOid, Digest, FixedOutput}; +use elliptic_curve::{ + generic_array::ArrayLength, + group::ff::PrimeField, + ops::Invert, + subtle::{Choice, ConstantTimeEq, CtOption}, + zeroize::{Zeroize, ZeroizeOnDrop}, + CurveArithmetic, FieldBytes, FieldBytesSize, NonZeroScalar, PrimeCurve, Scalar, SecretKey, +}; +use signature::{ + hazmat::{PrehashSigner, RandomizedPrehashSigner}, + rand_core::CryptoRngCore, + DigestSigner, RandomizedDigestSigner, RandomizedSigner, Signer, +}; + +#[cfg(feature = "der")] +use {crate::der, core::ops::Add}; + +#[cfg(feature = "pem")] +use { + crate::elliptic_curve::pkcs8::{DecodePrivateKey, EncodePrivateKey, SecretDocument}, + core::str::FromStr, +}; + +#[cfg(feature = "pkcs8")] +use crate::elliptic_curve::{ + pkcs8::{ + self, + der::AnyRef, + spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier}, + ObjectIdentifier, + }, + sec1::{self, FromEncodedPoint, ToEncodedPoint}, + AffinePoint, +}; + +#[cfg(feature = "verifying")] +use {crate::VerifyingKey, elliptic_curve::PublicKey, signature::KeypairRef}; + +/// ECDSA secret key used for signing. Generic over prime order elliptic curves +/// (e.g. NIST P-curves) +/// +/// Requires an [`elliptic_curve::CurveArithmetic`] impl on the curve, and a +/// [`SignPrimitive`] impl on its associated `Scalar` type. +/// +/// ## Usage +/// +/// The [`signature`] crate defines the following traits which are the +/// primary API for signing: +/// +/// - [`Signer`]: sign a message using this key +/// - [`DigestSigner`]: sign the output of a [`Digest`] using this key +/// - [`PrehashSigner`]: sign the low-level raw output bytes of a message digest +/// +/// See the [`p256` crate](https://docs.rs/p256/latest/p256/ecdsa/index.html) +/// for examples of using this type with a concrete elliptic curve. +#[derive(Clone)] +pub struct SigningKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + /// ECDSA signing keys are non-zero elements of a given curve's scalar field. + secret_scalar: NonZeroScalar, + + /// Verifying key which corresponds to this signing key. + #[cfg(feature = "verifying")] + verifying_key: VerifyingKey, +} + +impl SigningKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + /// Generate a cryptographically random [`SigningKey`]. + pub fn random(rng: &mut impl CryptoRngCore) -> Self { + NonZeroScalar::::random(rng).into() + } + + /// Initialize signing key from a raw scalar serialized as a byte array. + pub fn from_bytes(bytes: &FieldBytes) -> Result { + SecretKey::::from_bytes(bytes) + .map(Into::into) + .map_err(|_| Error::new()) + } + + /// Initialize signing key from a raw scalar serialized as a byte slice. + pub fn from_slice(bytes: &[u8]) -> Result { + SecretKey::::from_slice(bytes) + .map(Into::into) + .map_err(|_| Error::new()) + } + + /// Serialize this [`SigningKey`] as bytes + pub fn to_bytes(&self) -> FieldBytes { + self.secret_scalar.to_repr() + } + + /// Borrow the secret [`NonZeroScalar`] value for this key. + /// + /// # ⚠️ Warning + /// + /// This value is key material. + /// + /// Please treat it with the care it deserves! + pub fn as_nonzero_scalar(&self) -> &NonZeroScalar { + &self.secret_scalar + } + + /// Get the [`VerifyingKey`] which corresponds to this [`SigningKey`]. + #[cfg(feature = "verifying")] + pub fn verifying_key(&self) -> &VerifyingKey { + &self.verifying_key + } +} + +// +// `*Signer` trait impls +// + +/// Sign message digest using a deterministic ephemeral scalar (`k`) +/// computed using the algorithm described in [RFC6979 § 3.2]. +/// +/// [RFC6979 § 3.2]: https://tools.ietf.org/html/rfc6979#section-3 +impl DigestSigner> for SigningKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + D: Digest + FixedOutput>, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn try_sign_digest(&self, msg_digest: D) -> Result> { + self.sign_prehash(&msg_digest.finalize_fixed()) + } +} + +/// Sign message prehash using a deterministic ephemeral scalar (`k`) +/// computed using the algorithm described in [RFC6979 § 3.2]. +/// +/// [RFC6979 § 3.2]: https://tools.ietf.org/html/rfc6979#section-3 +impl PrehashSigner> for SigningKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn sign_prehash(&self, prehash: &[u8]) -> Result> { + let z = bits2field::(prehash)?; + Ok(self + .secret_scalar + .try_sign_prehashed_rfc6979::(&z, &[])? + .0) + } +} + +/// Sign message using a deterministic ephemeral scalar (`k`) +/// computed using the algorithm described in [RFC6979 § 3.2]. +/// +/// [RFC6979 § 3.2]: https://tools.ietf.org/html/rfc6979#section-3 +impl Signer> for SigningKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn try_sign(&self, msg: &[u8]) -> Result> { + self.try_sign_digest(C::Digest::new_with_prefix(msg)) + } +} + +impl RandomizedDigestSigner> for SigningKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + D: Digest + FixedOutput>, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn try_sign_digest_with_rng( + &self, + rng: &mut impl CryptoRngCore, + msg_digest: D, + ) -> Result> { + self.sign_prehash_with_rng(rng, &msg_digest.finalize_fixed()) + } +} + +impl RandomizedPrehashSigner> for SigningKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn sign_prehash_with_rng( + &self, + rng: &mut impl CryptoRngCore, + prehash: &[u8], + ) -> Result> { + let z = bits2field::(prehash)?; + let mut ad = FieldBytes::::default(); + rng.fill_bytes(&mut ad); + Ok(self + .secret_scalar + .try_sign_prehashed_rfc6979::(&z, &ad)? + .0) + } +} + +impl RandomizedSigner> for SigningKey +where + Self: RandomizedDigestSigner>, + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn try_sign_with_rng(&self, rng: &mut impl CryptoRngCore, msg: &[u8]) -> Result> { + self.try_sign_digest_with_rng(rng, C::Digest::new_with_prefix(msg)) + } +} + +impl DigestSigner> for SigningKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + D: AssociatedOid + Digest + FixedOutput>, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn try_sign_digest(&self, msg_digest: D) -> Result> { + let signature: Signature = self.try_sign_digest(msg_digest)?; + let oid = ecdsa_oid_for_digest(D::OID).ok_or_else(Error::new)?; + SignatureWithOid::new(signature, oid) + } +} + +impl Signer> for SigningKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + C::Digest: AssociatedOid, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn try_sign(&self, msg: &[u8]) -> Result> { + self.try_sign_digest(C::Digest::new_with_prefix(msg)) + } +} + +#[cfg(feature = "der")] +impl PrehashSigner> for SigningKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, + der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn sign_prehash(&self, prehash: &[u8]) -> Result> { + PrehashSigner::>::sign_prehash(self, prehash).map(Into::into) + } +} + +#[cfg(feature = "der")] +impl Signer> for SigningKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, + der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn try_sign(&self, msg: &[u8]) -> Result> { + Signer::>::try_sign(self, msg).map(Into::into) + } +} + +#[cfg(feature = "der")] +impl RandomizedDigestSigner> for SigningKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + D: Digest + FixedOutput>, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, + der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn try_sign_digest_with_rng( + &self, + rng: &mut impl CryptoRngCore, + msg_digest: D, + ) -> Result> { + RandomizedDigestSigner::>::try_sign_digest_with_rng(self, rng, msg_digest) + .map(Into::into) + } +} + +#[cfg(feature = "der")] +impl RandomizedPrehashSigner> for SigningKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, + der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn sign_prehash_with_rng( + &self, + rng: &mut impl CryptoRngCore, + prehash: &[u8], + ) -> Result> { + RandomizedPrehashSigner::>::sign_prehash_with_rng(self, rng, prehash) + .map(Into::into) + } +} + +#[cfg(feature = "der")] +impl RandomizedSigner> for SigningKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, + der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn try_sign_with_rng( + &self, + rng: &mut impl CryptoRngCore, + msg: &[u8], + ) -> Result> { + RandomizedSigner::>::try_sign_with_rng(self, rng, msg).map(Into::into) + } +} + +// +// Other trait impls +// + +#[cfg(feature = "verifying")] +impl AsRef> for SigningKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn as_ref(&self) -> &VerifyingKey { + &self.verifying_key + } +} + +impl ConstantTimeEq for SigningKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.secret_scalar.ct_eq(&other.secret_scalar) + } +} + +impl Debug for SigningKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SigningKey").finish_non_exhaustive() + } +} + +impl Drop for SigningKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn drop(&mut self) { + self.secret_scalar.zeroize(); + } +} + +/// Constant-time comparison +impl Eq for SigningKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ +} +impl PartialEq for SigningKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn eq(&self, other: &SigningKey) -> bool { + self.ct_eq(other).into() + } +} + +impl From> for SigningKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn from(secret_scalar: NonZeroScalar) -> Self { + #[cfg(feature = "verifying")] + let public_key = PublicKey::from_secret_scalar(&secret_scalar); + + Self { + secret_scalar, + #[cfg(feature = "verifying")] + verifying_key: public_key.into(), + } + } +} + +impl From> for SigningKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn from(secret_key: SecretKey) -> Self { + Self::from(&secret_key) + } +} + +impl From<&SecretKey> for SigningKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn from(secret_key: &SecretKey) -> Self { + secret_key.to_nonzero_scalar().into() + } +} + +impl From> for SecretKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn from(key: SigningKey) -> Self { + key.secret_scalar.into() + } +} + +impl From<&SigningKey> for SecretKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn from(secret_key: &SigningKey) -> Self { + secret_key.secret_scalar.into() + } +} + +impl TryFrom<&[u8]> for SigningKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + type Error = Error; + + fn try_from(bytes: &[u8]) -> Result { + Self::from_slice(bytes) + } +} + +impl ZeroizeOnDrop for SigningKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ +} + +#[cfg(feature = "verifying")] +impl From> for VerifyingKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn from(signing_key: SigningKey) -> VerifyingKey { + signing_key.verifying_key + } +} + +#[cfg(feature = "verifying")] +impl From<&SigningKey> for VerifyingKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn from(signing_key: &SigningKey) -> VerifyingKey { + signing_key.verifying_key + } +} + +#[cfg(feature = "verifying")] +impl KeypairRef for SigningKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + type VerifyingKey = VerifyingKey; +} + +#[cfg(feature = "pkcs8")] +impl AssociatedAlgorithmIdentifier for SigningKey +where + C: AssociatedOid + CurveArithmetic + PrimeCurve, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + type Params = ObjectIdentifier; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifier = + SecretKey::::ALGORITHM_IDENTIFIER; +} + +#[cfg(feature = "pkcs8")] +impl SignatureAlgorithmIdentifier for SigningKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, + Signature: AssociatedAlgorithmIdentifier>, +{ + type Params = AnyRef<'static>; + + const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier = + Signature::::ALGORITHM_IDENTIFIER; +} + +#[cfg(feature = "pkcs8")] +impl TryFrom> for SigningKey +where + C: PrimeCurve + AssociatedOid + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + type Error = pkcs8::Error; + + fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result { + SecretKey::try_from(private_key_info).map(Into::into) + } +} + +#[cfg(feature = "pem")] +impl EncodePrivateKey for SigningKey +where + C: AssociatedOid + PrimeCurve + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn to_pkcs8_der(&self) -> pkcs8::Result { + SecretKey::from(self.secret_scalar).to_pkcs8_der() + } +} + +#[cfg(feature = "pem")] +impl FromStr for SigningKey +where + C: PrimeCurve + AssociatedOid + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + type Err = Error; + + fn from_str(s: &str) -> Result { + Self::from_pkcs8_pem(s).map_err(|_| Error::new()) + } +} diff --git a/src/rust/vendor/ecdsa/src/verifying.rs b/src/rust/vendor/ecdsa/src/verifying.rs new file mode 100644 index 000000000..4ac0570ca --- /dev/null +++ b/src/rust/vendor/ecdsa/src/verifying.rs @@ -0,0 +1,482 @@ +//! ECDSA verifying: checking signatures are authentic using a [`VerifyingKey`]. + +use crate::{ + hazmat::{bits2field, DigestPrimitive, VerifyPrimitive}, + Error, Result, Signature, SignatureSize, +}; +use core::{cmp::Ordering, fmt::Debug}; +use elliptic_curve::{ + generic_array::ArrayLength, + point::PointCompression, + sec1::{self, CompressedPoint, EncodedPoint, FromEncodedPoint, ToEncodedPoint}, + AffinePoint, CurveArithmetic, FieldBytesSize, PrimeCurve, PublicKey, +}; +use signature::{ + digest::{Digest, FixedOutput}, + hazmat::PrehashVerifier, + DigestVerifier, Verifier, +}; + +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + +#[cfg(feature = "der")] +use {crate::der, core::ops::Add}; + +#[cfg(feature = "pem")] +use { + core::str::FromStr, + elliptic_curve::pkcs8::{DecodePublicKey, EncodePublicKey}, +}; + +#[cfg(feature = "pkcs8")] +use elliptic_curve::pkcs8::{ + self, + der::AnyRef, + spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier}, + AssociatedOid, ObjectIdentifier, +}; + +#[cfg(feature = "sha2")] +use { + crate::{ + SignatureWithOid, ECDSA_SHA224_OID, ECDSA_SHA256_OID, ECDSA_SHA384_OID, ECDSA_SHA512_OID, + }, + sha2::{Sha224, Sha256, Sha384, Sha512}, +}; + +#[cfg(all(feature = "pem", feature = "serde"))] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +/// ECDSA public key used for verifying signatures. Generic over prime order +/// elliptic curves (e.g. NIST P-curves) +/// +/// Requires an [`elliptic_curve::CurveArithmetic`] impl on the curve, and a +/// [`VerifyPrimitive`] impl on its associated `AffinePoint` type. +/// +/// ## Usage +/// +/// The [`signature`] crate defines the following traits which are the +/// primary API for verifying: +/// +/// - [`Verifier`]: verify a message against a provided key and signature +/// - [`DigestVerifier`]: verify a message [`Digest`] against a provided key and signature +/// - [`PrehashVerifier`]: verify the low-level raw output bytes of a message digest +/// +/// See the [`p256` crate](https://docs.rs/p256/latest/p256/ecdsa/index.html) +/// for examples of using this type with a concrete elliptic curve. +/// +/// # `serde` support +/// +/// When the `serde` feature of this crate is enabled, it provides support for +/// serializing and deserializing ECDSA signatures using the `Serialize` and +/// `Deserialize` traits. +/// +/// The serialization leverages the encoding used by the [`PublicKey`] type, +/// which is a binary-oriented ASN.1 DER encoding. +#[derive(Clone, Debug)] +pub struct VerifyingKey +where + C: PrimeCurve + CurveArithmetic, +{ + pub(crate) inner: PublicKey, +} + +impl VerifyingKey +where + C: PrimeCurve + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, +{ + /// Initialize [`VerifyingKey`] from a SEC1-encoded public key. + pub fn from_sec1_bytes(bytes: &[u8]) -> Result { + PublicKey::from_sec1_bytes(bytes) + .map(|pk| Self { inner: pk }) + .map_err(|_| Error::new()) + } + + /// Initialize [`VerifyingKey`] from an affine point. + /// + /// Returns an [`Error`] if the given affine point is the additive identity + /// (a.k.a. point at infinity). + pub fn from_affine(affine: AffinePoint) -> Result { + Ok(Self { + inner: PublicKey::from_affine(affine).map_err(|_| Error::new())?, + }) + } + + /// Initialize [`VerifyingKey`] from an [`EncodedPoint`]. + pub fn from_encoded_point(public_key: &EncodedPoint) -> Result { + Option::from(PublicKey::::from_encoded_point(public_key)) + .map(|public_key| Self { inner: public_key }) + .ok_or_else(Error::new) + } + + /// Serialize this [`VerifyingKey`] as a SEC1 [`EncodedPoint`], optionally + /// applying point compression. + pub fn to_encoded_point(&self, compress: bool) -> EncodedPoint { + self.inner.to_encoded_point(compress) + } + + /// Convert this [`VerifyingKey`] into the + /// `Elliptic-Curve-Point-to-Octet-String` encoding described in + /// SEC 1: Elliptic Curve Cryptography (Version 2.0) section 2.3.3 + /// (page 10). + /// + /// + #[cfg(feature = "alloc")] + pub fn to_sec1_bytes(&self) -> Box<[u8]> + where + C: PointCompression, + { + self.inner.to_sec1_bytes() + } + + /// Borrow the inner [`AffinePoint`] for this public key. + pub fn as_affine(&self) -> &AffinePoint { + self.inner.as_affine() + } +} + +// +// `*Verifier` trait impls +// + +impl DigestVerifier> for VerifyingKey +where + C: PrimeCurve + CurveArithmetic, + D: Digest + FixedOutput>, + AffinePoint: VerifyPrimitive, + SignatureSize: ArrayLength, +{ + fn verify_digest(&self, msg_digest: D, signature: &Signature) -> Result<()> { + self.inner.as_affine().verify_digest(msg_digest, signature) + } +} + +impl PrehashVerifier> for VerifyingKey +where + C: PrimeCurve + CurveArithmetic, + AffinePoint: VerifyPrimitive, + SignatureSize: ArrayLength, +{ + fn verify_prehash(&self, prehash: &[u8], signature: &Signature) -> Result<()> { + let field = bits2field::(prehash)?; + self.inner.as_affine().verify_prehashed(&field, signature) + } +} + +impl Verifier> for VerifyingKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + AffinePoint: VerifyPrimitive, + SignatureSize: ArrayLength, +{ + fn verify(&self, msg: &[u8], signature: &Signature) -> Result<()> { + self.verify_digest(C::Digest::new_with_prefix(msg), signature) + } +} + +#[cfg(feature = "sha2")] +impl Verifier> for VerifyingKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + AffinePoint: VerifyPrimitive, + SignatureSize: ArrayLength, +{ + fn verify(&self, msg: &[u8], sig: &SignatureWithOid) -> Result<()> { + match sig.oid() { + ECDSA_SHA224_OID => self.verify_prehash(&Sha224::digest(msg), sig.signature()), + ECDSA_SHA256_OID => self.verify_prehash(&Sha256::digest(msg), sig.signature()), + ECDSA_SHA384_OID => self.verify_prehash(&Sha384::digest(msg), sig.signature()), + ECDSA_SHA512_OID => self.verify_prehash(&Sha512::digest(msg), sig.signature()), + _ => Err(Error::new()), + } + } +} + +#[cfg(feature = "der")] +impl DigestVerifier> for VerifyingKey +where + C: PrimeCurve + CurveArithmetic, + D: Digest + FixedOutput>, + AffinePoint: VerifyPrimitive, + SignatureSize: ArrayLength, + der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn verify_digest(&self, msg_digest: D, signature: &der::Signature) -> Result<()> { + let signature = Signature::::try_from(signature.clone())?; + DigestVerifier::>::verify_digest(self, msg_digest, &signature) + } +} + +#[cfg(feature = "der")] +impl PrehashVerifier> for VerifyingKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + AffinePoint: VerifyPrimitive, + SignatureSize: ArrayLength, + der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn verify_prehash(&self, prehash: &[u8], signature: &der::Signature) -> Result<()> { + let signature = Signature::::try_from(signature.clone())?; + PrehashVerifier::>::verify_prehash(self, prehash, &signature) + } +} + +#[cfg(feature = "der")] +impl Verifier> for VerifyingKey +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + AffinePoint: VerifyPrimitive, + SignatureSize: ArrayLength, + der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn verify(&self, msg: &[u8], signature: &der::Signature) -> Result<()> { + let signature = Signature::::try_from(signature.clone())?; + Verifier::>::verify(self, msg, &signature) + } +} + +// +// Other trait impls +// + +impl AsRef> for VerifyingKey +where + C: PrimeCurve + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, +{ + fn as_ref(&self) -> &AffinePoint { + self.as_affine() + } +} + +impl Copy for VerifyingKey where C: PrimeCurve + CurveArithmetic {} + +impl From> for CompressedPoint +where + C: PrimeCurve + CurveArithmetic + PointCompression, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, +{ + fn from(verifying_key: VerifyingKey) -> CompressedPoint { + verifying_key.inner.into() + } +} + +impl From<&VerifyingKey> for CompressedPoint +where + C: PrimeCurve + CurveArithmetic + PointCompression, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, +{ + fn from(verifying_key: &VerifyingKey) -> CompressedPoint { + verifying_key.inner.into() + } +} + +impl From> for EncodedPoint +where + C: PrimeCurve + CurveArithmetic + PointCompression, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, +{ + fn from(verifying_key: VerifyingKey) -> EncodedPoint { + verifying_key.inner.into() + } +} + +impl From<&VerifyingKey> for EncodedPoint +where + C: PrimeCurve + CurveArithmetic + PointCompression, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, +{ + fn from(verifying_key: &VerifyingKey) -> EncodedPoint { + verifying_key.inner.into() + } +} + +impl Eq for VerifyingKey where C: PrimeCurve + CurveArithmetic {} + +impl PartialEq for VerifyingKey +where + C: PrimeCurve + CurveArithmetic, +{ + fn eq(&self, other: &Self) -> bool { + self.inner.eq(&other.inner) + } +} + +impl From> for VerifyingKey +where + C: PrimeCurve + CurveArithmetic, +{ + fn from(public_key: PublicKey) -> VerifyingKey { + VerifyingKey { inner: public_key } + } +} + +impl From<&PublicKey> for VerifyingKey +where + C: PrimeCurve + CurveArithmetic, +{ + fn from(public_key: &PublicKey) -> VerifyingKey { + (*public_key).into() + } +} + +impl From> for PublicKey +where + C: PrimeCurve + CurveArithmetic, +{ + fn from(verifying_key: VerifyingKey) -> PublicKey { + verifying_key.inner + } +} + +impl From<&VerifyingKey> for PublicKey +where + C: PrimeCurve + CurveArithmetic, +{ + fn from(verifying_key: &VerifyingKey) -> PublicKey { + (*verifying_key).into() + } +} + +impl PartialOrd for VerifyingKey +where + C: PrimeCurve + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, +{ + fn partial_cmp(&self, other: &Self) -> Option { + self.inner.partial_cmp(&other.inner) + } +} + +impl Ord for VerifyingKey +where + C: PrimeCurve + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, +{ + fn cmp(&self, other: &Self) -> Ordering { + self.inner.cmp(&other.inner) + } +} + +impl TryFrom<&[u8]> for VerifyingKey +where + C: PrimeCurve + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, +{ + type Error = Error; + + fn try_from(bytes: &[u8]) -> Result { + Self::from_sec1_bytes(bytes) + } +} + +#[cfg(feature = "pkcs8")] +impl AssociatedAlgorithmIdentifier for VerifyingKey +where + C: AssociatedOid + CurveArithmetic + PrimeCurve, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, +{ + type Params = ObjectIdentifier; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifier = + PublicKey::::ALGORITHM_IDENTIFIER; +} + +#[cfg(feature = "pkcs8")] +impl SignatureAlgorithmIdentifier for VerifyingKey +where + C: PrimeCurve + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, + Signature: AssociatedAlgorithmIdentifier>, +{ + type Params = AnyRef<'static>; + + const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier = + Signature::::ALGORITHM_IDENTIFIER; +} + +#[cfg(feature = "pkcs8")] +impl TryFrom> for VerifyingKey +where + C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, +{ + type Error = pkcs8::spki::Error; + + fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result { + PublicKey::try_from(spki).map(|inner| Self { inner }) + } +} + +#[cfg(feature = "pem")] +impl EncodePublicKey for VerifyingKey +where + C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, +{ + fn to_public_key_der(&self) -> pkcs8::spki::Result { + self.inner.to_public_key_der() + } +} + +#[cfg(feature = "pem")] +impl FromStr for VerifyingKey +where + C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, +{ + type Err = Error; + + fn from_str(s: &str) -> Result { + Self::from_public_key_pem(s).map_err(|_| Error::new()) + } +} + +#[cfg(all(feature = "pem", feature = "serde"))] +impl Serialize for VerifyingKey +where + C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, +{ + fn serialize(&self, serializer: S) -> core::result::Result + where + S: ser::Serializer, + { + self.inner.serialize(serializer) + } +} + +#[cfg(all(feature = "pem", feature = "serde"))] +impl<'de, C> Deserialize<'de> for VerifyingKey +where + C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: sec1::ModulusSize, +{ + fn deserialize(deserializer: D) -> core::result::Result + where + D: de::Deserializer<'de>, + { + PublicKey::::deserialize(deserializer).map(Into::into) + } +} diff --git a/src/rust/vendor/ecdsa/tests/lib.rs b/src/rust/vendor/ecdsa/tests/lib.rs new file mode 100644 index 000000000..1b622f8bd --- /dev/null +++ b/src/rust/vendor/ecdsa/tests/lib.rs @@ -0,0 +1,14 @@ +//! Smoke tests which use `MockCurve` + +#![cfg(feature = "dev")] + +use elliptic_curve::dev::MockCurve; + +type Signature = ecdsa::Signature; +type SignatureBytes = ecdsa::SignatureBytes; + +#[test] +fn rejects_all_zero_signature() { + let all_zero_bytes = SignatureBytes::default(); + assert!(Signature::try_from(all_zero_bytes.as_ref()).is_err()); +} diff --git a/src/rust/vendor/elliptic-curve/.cargo-checksum.json b/src/rust/vendor/elliptic-curve/.cargo-checksum.json new file mode 100644 index 000000000..ce4e15004 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"0b10798f0b729a76ffe1799c4ff8eb8264c784207150daac900e470a5d84b48a","Cargo.toml":"ae28aa3db758a5b18bf9e4b1253082b2503067f41be65e0bf3dc89917fda3f76","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"d27687b51f2874822c1530976b7e837eac4f308d94bf3dd42047011b7d437b47","README.md":"1ec3f5114bbba41528da8017c76a5d7f5cd995ae444705c279b776eeea350216","src/arithmetic.rs":"55be3c0cefb168a0768af743974007707ce95e98e89281818db9b69b4ba8f9cd","src/dev.rs":"15883bd44409ec62ab5cf8bb9fe96bca545a950f571487d1a0ddc846e891f2cc","src/ecdh.rs":"5cc59b8a2a5397be43deba006ca9d9fc608be1676d80c1f5c017af66bf72ad98","src/error.rs":"8aedd93298b729ee396bc1a31754119130fbf865cb1e330c65be178cbbb0d1e4","src/field.rs":"ffc3897dfb36f8d27de7ce96269cae4541b4587c4d9c94a9ce6d177819036624","src/hash2curve.rs":"861857145cc973ca64fc765731dada9aa3d7d97f61d324f6dba2aacc2d5e2135","src/hash2curve/group_digest.rs":"b9b52633c72158475bb059a1a36f61f04c8aa56a9188a83bcd6671996e5d4725","src/hash2curve/hash2field.rs":"762f662fa018db76af9bbae04e44a68e1279a638699648448ae1a28a51607150","src/hash2curve/hash2field/expand_msg.rs":"7615b8d2ba958a6d11d0f50143b9c2aa78649ea7c2dd87d16f2da4cf09578e50","src/hash2curve/hash2field/expand_msg/xmd.rs":"5a85d4084395e924bbb2e32640beaba8c8c8476695e70baf0b341155a6a5dd87","src/hash2curve/hash2field/expand_msg/xof.rs":"42bf7796706105e8d521137679a458e0c9e2ed3463adaa0f1c505b5d9bb2804d","src/hash2curve/isogeny.rs":"bd43364cedd8809a51b40c11743cf703d8e18268463dc75562520c8a624b5039","src/hash2curve/map2curve.rs":"fc05c553ccd92de762e083f02079581376e8e4a193acd0d902cfdb33f59ce10a","src/hash2curve/osswu.rs":"184d5bee8669722e9ef20523c064b3a769be49a6b62c4827818894199be94820","src/jwk.rs":"31d5f33bf559eae553a53adfce56cd094103b97482a1daf5224a581bba1fe8e6","src/lib.rs":"24db533221762c4e504428821f79bd3508a2dfaeef21ae3a67ece7d5d65da6c7","src/ops.rs":"23460c86fe3a07e07a446b7bceb164b99551943e4668ae7e04256f5177f3470f","src/point.rs":"f6acdd908cab4bdf399e4274ea76df67c577c4692dd9052bf7e4511c47ac5e24","src/point/non_identity.rs":"80a2b46aa22d5824a6f06d6f7855cb51285b7fa4dfeaa1eb05f3e57e390f33db","src/public_key.rs":"392da0745b3fb931c9072de88d6278729e223e27e2700b93bf50d941bc285ed1","src/scalar.rs":"0702d705b63732f62b6a7eaaf630ee5007b81623c0b0722e9712aa82f762fcd5","src/scalar/blinded.rs":"a6e7656c934eea2048e8047a5b13889b3344f5e54083d90e1d85839471155f26","src/scalar/nonzero.rs":"e485dad71df0e161a354ab9998ed155f3ae19a63be5b41d5c368fe942a21d329","src/scalar/primitive.rs":"19363dfc72b339c06e41ea60a1205fed5f301e7ec144feee22ea05a9c3aa4576","src/sec1.rs":"0e6e89979590ef2c38a006517fd0e5237f1be6682aaad5bae913792a99b34fa6","src/secret_key.rs":"a08c354ea59da20e20628ce66da790822f3f90ee5820ab449ed64229d9270783","src/secret_key/pkcs8.rs":"26b9171c1c7c0321419425188b3d317624040161f29e5521a250299ebcbfd536","src/voprf.rs":"d6a7d8596163bbab3d183526ffa8882bb4de279772f992dc2d261cce6d17efba","src/weierstrass.rs":"b49e30b886ca5ee8a6725fa34d5c58108ee844888b73e5983856c7e2740bc9e2","tests/examples/pkcs8-private-key.der":"8125ab208d2181ed3ef05ff0ab1906e5898c36a858277e5b987e78e505288769","tests/examples/pkcs8-private-key.pem":"e0d0ce22e72577e5d00d7b8d65288f158032402fc9dbcaf63dc771d0eb91ae5f","tests/examples/pkcs8-public-key.der":"b9968d56ed8d6aa3fb43b15fa01e355d7a3a0203b1408b3fd2733637c4d1642c","tests/examples/pkcs8-public-key.pem":"d1ff198dc495da63f5f909db0254d6e49cff519487fcb26d055a762fc3ca47a1","tests/pkcs8.rs":"b69f29997a46fe4be1bf5b7b27b9efa501403b4a9fc8fa9733144f94d9683501","tests/secret_key.rs":"25f79615433b503db00588209bac723d0daea1c76c8a8a52f44b2fbc59b00f5c"},"package":"b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"} \ No newline at end of file diff --git a/src/rust/vendor/elliptic-curve/CHANGELOG.md b/src/rust/vendor/elliptic-curve/CHANGELOG.md new file mode 100644 index 000000000..3f47710eb --- /dev/null +++ b/src/rust/vendor/elliptic-curve/CHANGELOG.md @@ -0,0 +1,811 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.13.8 (2023-11-18) +### Changed +- `SecretKey::from_slice` now allows >=24-bytes ([#1412]) + +[#1412]: https://github.com/RustCrypto/traits/pull/1412 + +## 0.13.7 (2023-11-15) +### Added +- `BatchInvert` and `BatchNormalize` traits ([#1376]) +- `LinearCombinationExt` trait ([#1405]) + +[#1376]: https://github.com/RustCrypto/traits/pull/1376 +[#1405]: https://github.com/RustCrypto/traits/pull/1405 + +## 0.13.6 (2023-10-02) +### Fixed +- Minimum supported `hkdf` version is v0.12.1 ([#1353]) +- Minimum supported `serde_json` version for `jwk` feature is v1.0.47 ([#1354]) +- Minimum supported `tap` version for `bits` feature is v1.0.1 ([#1355]) + +[#1353]: https://github.com/RustCrypto/traits/pull/1353 +[#1354]: https://github.com/RustCrypto/traits/pull/1354 +[#1355]: https://github.com/RustCrypto/traits/pull/1355 + +## 0.13.5 (2023-05-19) +### Changed +- Faster `PublicKey::from_encoded_point` ([#1310]) + +### Fixed +- `alloc`+`arithmetic` features w/o `sec1` feature ([#1301]) + +[#1301]: https://github.com/RustCrypto/traits/pull/1301 +[#1310]: https://github.com/RustCrypto/traits/pull/1310 + +## 0.13.4 (2023-04-08) +### Changed +- Bump `hex-literal` to v0.4 ([#1295]) + +### Fixed +- `NonZeroScalar::from_slice` ([#1296]) +- `ScalarPrimitive::from_slice` ([#1296]) + +[#1295]: https://github.com/RustCrypto/traits/pull/1295 +[#1296]: https://github.com/RustCrypto/traits/pull/1296 + +## 0.13.3 (2023-04-04) +### Added +- Impl `AssociatedAlgorithmIdentifier` for `SecretKey` and `PublicKey` ([#1286]) + +### Changed +- Update OSSWU code ([#1157]) +- Bump `pkcs8` to v0.10.2 ([#1291]) + +### Fixed +- `FieldBytesEncoding` provided impl ([#1287]) + +[#1157]: https://github.com/RustCrypto/traits/pull/1157 +[#1286]: https://github.com/RustCrypto/traits/pull/1286 +[#1287]: https://github.com/RustCrypto/traits/pull/1287 +[#1291]: https://github.com/RustCrypto/traits/pull/1291 + +## 0.13.2 (2023-03-08) +### Added +- Weakly activate `pkcs8?/std` ([#1263]) +- More `PublicKey` <-> SEC1 conversions ([#1272]) + +[#1263]: https://github.com/RustCrypto/traits/pull/1263 +[#1272]: https://github.com/RustCrypto/traits/pull/1272 + +## 0.13.1 (2023-03-01) +### Added +- `SecretKey::from_slice` short input support ([#1256]) + +[#1256]: https://github.com/RustCrypto/traits/pull/1256 + +## 0.13.0 (2023-02-28) +### Added +- `PublicKey::to_sec1_bytes` ([#1102]) +- Forward `std` feature to `sec1` dependency ([#1131]) +- `NonIdentity` wrapper type ([#1176]) +- Impl `serde` traits for `NonZeroScalar` ([#1178]) +- `MulByGenerator` trait ([#1198]) +- `NonZeroScalar::invert_vartime` ([#1207]) +- `BlindedScalar` type ([#1208]) +- `point::Double` trait ([#1218]) +- `FieldBytesEncoding` trait ([#1235]) +- `Invert::invert_vartime` ([#1239]) + +### Changed +- Allow bigger `c1` constant in `OsswuMapParams` ([#1024]) +- Rename `Curve::UInt` => `Curve::Uint` ([#1191]) +- Use weak feature activation ([#1192], [#1194]) +- Consolidate `CurveArithmetic` trait ([#1196]) +- Rename `SecretKey::to_pem` => `::to_sec1_pem` ([#1202]) +- Rename `ScalarCore` to `ScalarPrimitive` ([#1203]) +- Use `CryptoRngCore` trait ([#1206]) +- Refactor field element decoding/encoding ([#1220]) +- Update VOPRF identifier type ([#1175]) +- Rename `SecretKey::as_scalar_core` => `::as_scalar_primitive` ([#1228]) +- Rename `Reduce::from_bytes_reduced` => `::reduce_bytes` ([#1225], [#1229]) +- Consolidate `AffineCoordinates` trait ([#1237]) +- Allow multiple `dst`s in the `hash2curve` API ([#1238]) +- Have `serde` feature activate `pkcs8` ([#1245]) +- Dependency upgrades: + - `base16ct` ([#1254]) + - `crypto-bigint` v0.5 ([#1251]) + - `ff` and `group` v0.13 ([#1166]) + - `pem-rfc7468` v0.7 ([#1251]) + - `pkcs8` v0.10 ([#1251]) + - `sec1` v0.7 ([#1251]) + - `serdect` v0.2 ([#1251]) + +### Removed +- `impl_field_element!` macro ([#1165]) +- Direct `der` crate dependency ([#1195]) +- `AffineArithmetic`, `ProjectiveArithmetic`, `ScalarArithmetic` traits ([#1196]) +- Toplevel re-exports except for `AffinePoint`, `ProjectivePoint`, and `Scalar` ([#1223]) +- `Reduce` methods ([#1225]) +- Blanket impl for `Invert` ([#1242]) + +[#1024]: https://github.com/RustCrypto/traits/pull/1024 +[#1102]: https://github.com/RustCrypto/traits/pull/1102 +[#1131]: https://github.com/RustCrypto/traits/pull/1131 +[#1165]: https://github.com/RustCrypto/traits/pull/1165 +[#1166]: https://github.com/RustCrypto/traits/pull/1166 +[#1175]: https://github.com/RustCrypto/traits/pull/1175 +[#1176]: https://github.com/RustCrypto/traits/pull/1176 +[#1178]: https://github.com/RustCrypto/traits/pull/1178 +[#1191]: https://github.com/RustCrypto/traits/pull/1191 +[#1192]: https://github.com/RustCrypto/traits/pull/1192 +[#1194]: https://github.com/RustCrypto/traits/pull/1194 +[#1195]: https://github.com/RustCrypto/traits/pull/1195 +[#1196]: https://github.com/RustCrypto/traits/pull/1196 +[#1198]: https://github.com/RustCrypto/traits/pull/1198 +[#1202]: https://github.com/RustCrypto/traits/pull/1202 +[#1203]: https://github.com/RustCrypto/traits/pull/1203 +[#1206]: https://github.com/RustCrypto/traits/pull/1206 +[#1207]: https://github.com/RustCrypto/traits/pull/1207 +[#1208]: https://github.com/RustCrypto/traits/pull/1208 +[#1218]: https://github.com/RustCrypto/traits/pull/1218 +[#1220]: https://github.com/RustCrypto/traits/pull/1220 +[#1223]: https://github.com/RustCrypto/traits/pull/1223 +[#1225]: https://github.com/RustCrypto/traits/pull/1225 +[#1228]: https://github.com/RustCrypto/traits/pull/1228 +[#1229]: https://github.com/RustCrypto/traits/pull/1229 +[#1235]: https://github.com/RustCrypto/traits/pull/1235 +[#1237]: https://github.com/RustCrypto/traits/pull/1237 +[#1238]: https://github.com/RustCrypto/traits/pull/1238 +[#1239]: https://github.com/RustCrypto/traits/pull/1239 +[#1242]: https://github.com/RustCrypto/traits/pull/1242 +[#1245]: https://github.com/RustCrypto/traits/pull/1245 +[#1251]: https://github.com/RustCrypto/traits/pull/1251 +[#1254]: https://github.com/RustCrypto/traits/pull/1254 + +## 0.12.3 (2022-08-01) +### Added +- Aliases for SEC1 compressed/uncompressed points ([#1067]) + +### Fixed +- `arithmetic` + `serde` feature combo ([#1066]) + +[#1066]: https://github.com/RustCrypto/traits/pull/1066 +[#1067]: https://github.com/RustCrypto/traits/pull/1067 + +## 0.12.2 (2022-07-01) +### Changed +- Bump `crypto-bigint` to v0.4.8 ([#1039]) + +[#1039]: https://github.com/RustCrypto/traits/pull/1039 + +## 0.12.1 (2022-06-12) +### Added +- `impl_field_element!` macro ([#1021]) +- Generic impl of complete prime order formulas ([#1022]) + +### Changed +- Bump `crypto-bigint` to v0.4.4 ([#1018], [#1020]) + +[#1018]: https://github.com/RustCrypto/traits/pull/1018 +[#1020]: https://github.com/RustCrypto/traits/pull/1020 +[#1021]: https://github.com/RustCrypto/traits/pull/1021 +[#1022]: https://github.com/RustCrypto/traits/pull/1022 + +## 0.12.0 (2022-05-08) +### Added +- `ecdh::SharedSecret::extract` HKDF helper ([#1007]) + +### Changed +- Bump `digest` dependency to v0.10 ([#883], [#904]) +- Make `NonZeroScalar::invert` infallible ([#894]) +- `ToCompactEncodedPoint` now returns `CtOption` ([#895]) +- Move `hash2field` into `hash2curve` module ([#903]) +- Bump `ff` and `group` dependencies to v0.12 ([#994]) +- Use `serdect` crate ([#996]) +- Replace `AlgorithmParamters` with `AssociatedOid` ([#1001]) +- Bump `crypto-bigint` dependency to v0.4 ([#1005]) +- Bump `der` dependency to v0.6 ([#1006]) +- Bump `pkcs8` dependency to v0.9 ([#1006]) +- Bump `sec1` dependency to v0.3 ([#1006]) +- Bump `pem-rfc7468` dependency to v0.6 ([#1009]) + +### Removed +- `Zeroize` impl from `ecdh::SharedSecret` ([#978]) + +[#883]: https://github.com/RustCrypto/traits/pull/883 +[#894]: https://github.com/RustCrypto/traits/pull/894 +[#895]: https://github.com/RustCrypto/traits/pull/895 +[#903]: https://github.com/RustCrypto/traits/pull/903 +[#904]: https://github.com/RustCrypto/traits/pull/904 +[#978]: https://github.com/RustCrypto/traits/pull/978 +[#994]: https://github.com/RustCrypto/traits/pull/994 +[#996]: https://github.com/RustCrypto/traits/pull/996 +[#1001]: https://github.com/RustCrypto/traits/pull/1001 +[#1005]: https://github.com/RustCrypto/traits/pull/1005 +[#1006]: https://github.com/RustCrypto/traits/pull/1006 +[#1007]: https://github.com/RustCrypto/traits/pull/1007 +[#1009]: https://github.com/RustCrypto/traits/pull/1009 + +## 0.11.12 (2022-01-30) +### Changed +- Disable `bits` feature on docs.rs due to nightly breakage ([#927]) + +[#927]: https://github.com/RustCrypto/traits/pull/927 + +## 0.11.11 (2022-01-30) +- No changes; triggering a docs.rs rebuild + +## 0.11.10 (2022-01-27) +### Changed +- Revert [#884] to support a wider range of `zeroize` versions ([#923]) + +[#923]: https://github.com/RustCrypto/traits/pull/891 + +## 0.11.9 (2022-01-17) [YANKED] +### Changed +- Activate `bits`, `hash2curve`, and `voprf` features on docs.rs ([#891]) + +[#891]: https://github.com/RustCrypto/traits/pull/891 + +## 0.11.8 (2022-01-15) [YANKED] +### Added +- Impl `ZeroizeOnDrop` on appropriate items ([#884]) + +### Changed +- Use the `base16ct` crate for hex serialization ([#886], [#887], [#888]) + +[#884]: https://github.com/RustCrypto/traits/pull/884 +[#886]: https://github.com/RustCrypto/traits/pull/886 +[#887]: https://github.com/RustCrypto/traits/pull/887 +[#888]: https://github.com/RustCrypto/traits/pull/888 + +## 0.11.7 (2022-01-14) [YANKED] +### Added +- Initial hash-to-field support ([#854], [#855], [#871], [#874]) +- Initial hash-to-curve support ([#865], [#876]) +- Impl `Mul` for `NonZeroScalar` * `NonZeroScalar` ([#857], [#862]) +- `Reduce::from_*e_digest_reduced` ([#869]) +- `VoprfParameters` trait ([#878]) + +[#854]: https://github.com/RustCrypto/traits/pull/854 +[#855]: https://github.com/RustCrypto/traits/pull/855 +[#857]: https://github.com/RustCrypto/traits/pull/857 +[#862]: https://github.com/RustCrypto/traits/pull/862 +[#865]: https://github.com/RustCrypto/traits/pull/865 +[#869]: https://github.com/RustCrypto/traits/pull/869 +[#871]: https://github.com/RustCrypto/traits/pull/871 +[#874]: https://github.com/RustCrypto/traits/pull/874 +[#876]: https://github.com/RustCrypto/traits/pull/876 +[#878]: https://github.com/RustCrypto/traits/pull/878 + +## 0.11.6 (2021-12-20) +### Added +- Type conversions chart ([#852]) + +[#852]: https://github.com/RustCrypto/traits/pull/852 + +## 0.11.5 (2021-12-05) +### Changed +- Revised `LinearCombination` trait ([#835]) + +[#835]: https://github.com/RustCrypto/traits/pull/835 + +## 0.11.4 (2021-12-04) [YANKED] +### Added +- `LinearCombination` trait ([#832]) + +[#832]: https://github.com/RustCrypto/traits/pull/832 + +## 0.11.3 (2021-12-03) [YANKED] +### Added +- `ReduceNonZero` trait ([#827]) + +[#827]: https://github.com/RustCrypto/traits/pull/827 + +## 0.11.2 (2021-12-03) [YANKED] +### Changed +- Bump `pem-rfc7468` dependency to v0.3 ([#825]) + +[#825]: https://github.com/RustCrypto/traits/pull/825 + +## 0.11.1 (2021-11-21) [YANKED] +### Added +- `NonZeroScalar::from_uint` ([#822]) + +[#822]: https://github.com/RustCrypto/traits/pull/822 + +## 0.11.0 (2021-11-19) [YANKED] +### Added +- `ScalarCore` type ([#732]) +- `PrimeCurveArithmetic` trait ([#739]) +- SEC1 private key support ([#762]) +- `Reduce` trait ([#768]) +- Re-export `ff` and `PrimeField` ([#796]) +- `Encoding` bound on `Curve::UInt` ([#806]) +- `scalar::IsHigh` trait ([#814], [#815]) +- `Neg` impl for `NonZeroScalar` ([#816]) +- `AffineXCoordinate` trait ([#817]) +- `serde` support for scalar and `PublicKey` types ([#818]) + +### Changed +- Bump `ff` + `group` to v0.11 ([#730]) +- Make `SecretKey::to_jwk_string` self-zeroizing ([#742]) +- Use `sec1` crate's `EncodedPoint` ([#771]) +- Make `FromEncodedPoint` return a `CtOption` ([#782]) +- Rust 2021 edition upgrade; MSRV to 1.56 ([#795]) +- Bump `crypto-bigint` dependency to v0.3 ([#807]) +- Use `sec1` crate for `pkcs8` support ([#809]) +- Bump `spki` dependency to v0.5 release ([#810]) +- `NonZeroScalar` is now bounded on `ScalarArithmetic` instead of + `ProjectiveArithmetic` ([#812]) + +### Fixed +- `Zeroize` impl on `NonZeroScalar` ([#785]) + +[#730]: https://github.com/RustCrypto/traits/pull/730 +[#732]: https://github.com/RustCrypto/traits/pull/732 +[#739]: https://github.com/RustCrypto/traits/pull/739 +[#742]: https://github.com/RustCrypto/traits/pull/742 +[#762]: https://github.com/RustCrypto/traits/pull/762 +[#768]: https://github.com/RustCrypto/traits/pull/768 +[#771]: https://github.com/RustCrypto/traits/pull/771 +[#782]: https://github.com/RustCrypto/traits/pull/782 +[#785]: https://github.com/RustCrypto/traits/pull/785 +[#795]: https://github.com/RustCrypto/traits/pull/795 +[#796]: https://github.com/RustCrypto/traits/pull/796 +[#806]: https://github.com/RustCrypto/traits/pull/806 +[#807]: https://github.com/RustCrypto/traits/pull/807 +[#809]: https://github.com/RustCrypto/traits/pull/809 +[#810]: https://github.com/RustCrypto/traits/pull/810 +[#812]: https://github.com/RustCrypto/traits/pull/812 +[#814]: https://github.com/RustCrypto/traits/pull/814 +[#815]: https://github.com/RustCrypto/traits/pull/815 +[#816]: https://github.com/RustCrypto/traits/pull/816 +[#817]: https://github.com/RustCrypto/traits/pull/817 +[#818]: https://github.com/RustCrypto/traits/pull/818 + +## 0.10.6 (2021-08-23) +### Changed +- Bump `crypto-bigint` dependency to v0.2.4 ([#710]) + +[#710]: https://github.com/RustCrypto/traits/pull/710 + +## 0.10.5 (2021-07-20) +### Changed +- Pin `zeroize` dependency to v1.4 and `subtle` to v2.4 ([#689]) + +[#689]: https://github.com/RustCrypto/traits/pull/689 + +## 0.10.4 (2021-07-12) +### Added +- Re-export `rand_core` ([#683]) + +[#683]: https://github.com/RustCrypto/traits/pull/683 + +## 0.10.3 (2021-06-21) +### Changed +- Bump `crypto-bigint` to v0.2.1 ([#673]) + +[#673]: https://github.com/RustCrypto/traits/pull/673 + +## 0.10.2 (2021-06-14) [YANKED] +### Added +- `ConstantTimeEq` impl for `NonZeroScalar` ([#669]) + +[#669]: https://github.com/RustCrypto/traits/pull/669 + +## 0.10.1 (2021-06-09) [YANKED] +### Added +- Explicit `Copy` bounds on `PublicKey` ([#667]) + +[#667]: https://github.com/RustCrypto/traits/pull/667 + +## 0.10.0 (2021-06-07) [YANKED] +### Added +- `ScalarBytes::from_uint` ([#651]) +- `dev::ScalarBytes` ([#652]) +- `ScalarArithmetic` trait ([#654]) +- `AffineArithmetic` trait ([#658]) +- `PointCompaction` trait and SEC1 tag support ([#659]) + +### Changed +- Bump `ff` and `group` to v0.10; MSRV 1.51+ ([#643]) +- Merge `Curve` and `Order` traits ([#644]) +- Use `crypto-bigint` to represent `Curve::ORDER` ([#645]) +- Source `FieldSize` from `C::UInt` type ([#646]) +- Impl `ScalarBytes` using `C::UInt` ([#647]) +- Make `ScalarBytes` the `SecretKey` internal repr ([#649]) +- Bump `crypto-bigint` to v0.2 ([#662]) +- Bump `pkcs8` to v0.7 ([#662]) + +### Removed +- `util` module ([#648]) + +[#643]: https://github.com/RustCrypto/traits/pull/643 +[#644]: https://github.com/RustCrypto/traits/pull/644 +[#645]: https://github.com/RustCrypto/traits/pull/645 +[#646]: https://github.com/RustCrypto/traits/pull/646 +[#647]: https://github.com/RustCrypto/traits/pull/647 +[#648]: https://github.com/RustCrypto/traits/pull/648 +[#649]: https://github.com/RustCrypto/traits/pull/649 +[#651]: https://github.com/RustCrypto/traits/pull/651 +[#652]: https://github.com/RustCrypto/traits/pull/652 +[#654]: https://github.com/RustCrypto/traits/pull/654 +[#658]: https://github.com/RustCrypto/traits/pull/658 +[#659]: https://github.com/RustCrypto/traits/pull/659 +[#662]: https://github.com/RustCrypto/traits/pull/662 + +## 0.9.12 (2021-05-18) +### Added +- `Ord` and `PartialOrd` impls on `PublicKey` ([#637]) + +[#637]: https://github.com/RustCrypto/traits/pull/637 + +## 0.9.11 (2021-04-21) +### Added +- Impl `subtle` traits on `ScalarBytes` ([#612]) + +### Fixed +- Always re-export ScalarBytes ([#613]) + +[#612]: https://github.com/RustCrypto/traits/pull/612 +[#613]: https://github.com/RustCrypto/traits/pull/613 + +## 0.9.10 (2021-04-21) +### Added +- `ScalarBytes` type ([#610]) + +[#610]: https://github.com/RustCrypto/traits/pull/610 + +## 0.9.9 (2021-04-21) [YANKED] +### Added +- `Order::is_scalar_repr_in_range` ([#608]) + +[#608]: https://github.com/RustCrypto/traits/pull/608 + +## 0.9.8 (2021-04-21) +### Added +- Define `Order` for `MockCurve` ([#606]) + +[#606]: https://github.com/RustCrypto/traits/pull/606 + +## 0.9.7 (2021-04-21) +### Added +- `Order` trait ([#603]) + +### Fixed +- Warnings from `pkcs8` imports ([#604]) + +[#603]: https://github.com/RustCrypto/traits/pull/603 +[#604]: https://github.com/RustCrypto/traits/pull/604 + +## 0.9.6 (2021-03-22) +### Changed +- Bump `pkcs8` dependency to v0.6 ([#585]) + +[#585]: https://github.com/RustCrypto/traits/pull/585 + +## 0.9.5 (2021-03-17) [YANKED] +### Added +- Implement `{to,char}_le_bits` for `MockCurve` ([#565]) +- Implement `one()` for mock `Scalar` ([#566]) + +### Changed +- Use string-based OID constants ([#561]) +- Bump `base64ct` dependency to v1.0 ([#581]) + +[#561]: https://github.com/RustCrypto/traits/pull/561 +[#565]: https://github.com/RustCrypto/traits/pull/565 +[#566]: https://github.com/RustCrypto/traits/pull/566 +[#581]: https://github.com/RustCrypto/traits/pull/581 + +## 0.9.4 (2021-02-18) [YANKED] +### Fixed +- Breakage related to the `pkcs8` v0.5.1 crate ([#556]) + +[#556]: https://github.com/RustCrypto/traits/pull/556 + +## 0.9.3 (2021-02-16) [YANKED] +### Changed +- Bump `pkcs8` dependency to v0.5.0 ([#549]) + +### Fixed +- Workaround for bitvecto-rs/bitvec#105 ([#550]) + +[#549]: https://github.com/RustCrypto/traits/pull/549 +[#550]: https://github.com/RustCrypto/traits/pull/550 + +## 0.9.2 (2021-02-12) [YANKED] +### Changed +- Flatten `weierstrass` module ([#542]) + +[#542]: https://github.com/RustCrypto/traits/pull/542 + +## 0.9.1 (2021-02-11) [YANKED] +### Removed +- `BitView` re-export ([#540]) + +[#540]: https://github.com/RustCrypto/traits/pull/540 + +## 0.9.0 (2021-02-10) [YANKED] +### Added +- JWK support ([#483]) +- `sec1::ValidatePublicKey` trait ([#485]) +- `hazmat` crate feature ([#487]) +- `Result` alias ([#534]) + +### Changed +- Bump `ff` and `group` crates to v0.9 ([#452]) +- Simplify ECDH trait bounds ([#475]) +- Flatten API ([#487]) +- Bump `pkcs8` crate dependency to v0.4 ([#493]) + +### Removed +- Direct `bitvec` dependency ([#484]) +- `FromDigest` trait ([#532]) + +[#452]: https://github.com/RustCrypto/traits/pull/452 +[#475]: https://github.com/RustCrypto/traits/pull/475 +[#483]: https://github.com/RustCrypto/traits/pull/483 +[#484]: https://github.com/RustCrypto/traits/pull/484 +[#485]: https://github.com/RustCrypto/traits/pull/485 +[#487]: https://github.com/RustCrypto/traits/pull/487 +[#493]: https://github.com/RustCrypto/traits/pull/493 +[#432]: https://github.com/RustCrypto/traits/pull/432 +[#532]: https://github.com/RustCrypto/traits/pull/532 +[#534]: https://github.com/RustCrypto/traits/pull/534 + +## 0.8.5 (2021-02-17) +### Fixed +- Workaround for bitvecto-rs/bitvec#105 ([#553]) + +[#553]: https://github.com/RustCrypto/traits/pull/553 + +## 0.8.4 (2020-12-23) +### Fixed +- Rust `nightly` regression ([#432]) + +[#432]: https://github.com/RustCrypto/traits/pull/432 + +## 0.8.3 (2020-12-22) +### Fixed +- Regression in combination of `pem`+`zeroize` features ([#429]) + +[#429]: https://github.com/RustCrypto/traits/pull/429 + +## 0.8.2 (2020-12-22) [YANKED] +### Added +- Low-level ECDH API ([#418]) +- `dev` module ([#419]) +- Impl `pkcs8::ToPrivateKey` for `SecretKey` ([#423]) +- Impl `pkcs8::ToPublicKey` for `PublicKey` ([#427]) + +### Changed +- Bump `subtle` dependency to 2.4.0 ([#414]) +- Bump `pkcs8` dependency to v0.3.3 ([#425]) +- Use `der` crate to parse `SecretKey` ([#422]) + +### Fixed +- Make `PublicKey::from_encoded_point` go through `PublicKey::from_affine` ([#416]) + +[#414]: https://github.com/RustCrypto/traits/pull/414 +[#416]: https://github.com/RustCrypto/traits/pull/416 +[#418]: https://github.com/RustCrypto/traits/pull/418 +[#419]: https://github.com/RustCrypto/traits/pull/419 +[#422]: https://github.com/RustCrypto/traits/pull/422 +[#423]: https://github.com/RustCrypto/traits/pull/423 +[#425]: https://github.com/RustCrypto/traits/pull/425 +[#427]: https://github.com/RustCrypto/traits/pull/427 + +## 0.8.1 (2020-12-16) [YANKED] +### Fixed +- Builds on Rust `nightly` compiler ([#412]) + +[#412]: https://github.com/RustCrypto/traits/pull/412 + +## 0.8.0 (2020-12-16) [YANKED] +### Added +- Impl `subtle::ConditionallySelectable` for `sec1::EncodedPoint` ([#409]) +- `sec1::EncodedPoint::identity()` method ([#408]) +- `sec1::Coordinates::tag` method ([#407]) +- Support for SEC1 identity encoding ([#401]) + +### Changed +- Bump `pkcs8` crate dependency to v0.3 ([#405]) +- Ensure `PublicKey` is not the identity point ([#404]) +- Have `SecretKey::secret_scalar` return `NonZeroScalar` ([#402]) + +### Removed +- `SecretKey::secret_value` ([#403]) + +[#409]: https://github.com/RustCrypto/traits/pull/409 +[#408]: https://github.com/RustCrypto/traits/pull/408 +[#407]: https://github.com/RustCrypto/traits/pull/407 +[#405]: https://github.com/RustCrypto/traits/pull/405 +[#404]: https://github.com/RustCrypto/traits/pull/404 +[#403]: https://github.com/RustCrypto/traits/pull/403 +[#402]: https://github.com/RustCrypto/traits/pull/402 +[#401]: https://github.com/RustCrypto/traits/pull/401 + +## 0.7.1 (2020-12-07) +### Changed +- Have `SecretKey::secret_value` always return `NonZeroScalar` ([#390]) + +[#390]: https://github.com/RustCrypto/traits/pull/390 + +## 0.7.0 (2020-12-06) [YANKED] +### Added +- Impl `pkcs8::FromPublicKey` for `PublicKey` ([#385]) +- Impl `pkcs8::FromPrivateKey` trait for `SecretKey` ([#381], [#383]) +- PKCS#8 PEM support ([#382]) +- `SecretKey::secret_value()` method ([#375]) +- `PublicKey` type ([#363], [#366]) + +### Changed +- Rename `PublicKey::from_bytes()` to `::from_sec1_bytes()` ([#376]) +- `sec1::EncodedPoint` uses `Option` instead of `subtle::CtOption` ([#367]) +- Bump `const-oid` to v0.3; MSRV 1.46+ ([#365], [#381]) + +### Fixed +- `ecdh` rustdoc ([#364]) + +[#385]: https://github.com/RustCrypto/traits/pull/385 +[#383]: https://github.com/RustCrypto/traits/pull/383 +[#382]: https://github.com/RustCrypto/traits/pull/382 +[#381]: https://github.com/RustCrypto/traits/pull/381 +[#376]: https://github.com/RustCrypto/traits/pull/376 +[#375]: https://github.com/RustCrypto/traits/pull/375 +[#367]: https://github.com/RustCrypto/traits/pull/367 +[#366]: https://github.com/RustCrypto/traits/pull/366 +[#365]: https://github.com/RustCrypto/traits/pull/365 +[#364]: https://github.com/RustCrypto/traits/pull/364 +[#363]: https://github.com/RustCrypto/traits/pull/363 + +## 0.6.6 (2020-10-08) +### Added +- Derive `Clone` on `SecretBytes` ([#330]) + +[#300]: https://github.com/RustCrypto/traits/pull/300 + +## 0.6.5 (2020-10-08) +### Fixed +- Work around `nightly-2020-10-06` breakage ([#328]) + +[#328]: https://github.com/RustCrypto/traits/pull/328 + +## 0.6.4 (2020-10-08) +### Added +- Impl `From>` for `FieldBytes` ([#326]) + +[#326]: https://github.com/RustCrypto/traits/pull/326 + +## 0.6.3 (2020-10-08) +### Added +- `SecretBytes` newtype ([#324]) + +[#324]: https://github.com/RustCrypto/traits/pull/324 + +## 0.6.2 (2020-09-24) +### Added +- `sec1::EncodedPoint::to_untagged_bytes()` method ([#312]) + +[#312]: https://github.com/RustCrypto/traits/pull/312 + +## 0.6.1 (2020-09-21) +### Fixed +- `sec1::EncodedPoint::decompress` ([#309]) + +[#309]: https://github.com/RustCrypto/traits/pull/309 + +## 0.6.0 (2020-09-11) [YANKED] +### Added +- `arithmetic` feature ([#293]) +- Generic curve/field arithmetic using the `ff` and `group` crates + ([#287], [#291], [#292]) +- `sec1::Coordinates` ([#286]) +- `weierstrass::point::Compression` trait ([#283], [#300]) +- Arithmetic helper functions ([#281]) +- `digest` feature and `FromDigest` trait ([#279]) +- impl `Deref` for `NonZeroScalar` ([#278]) +- Conditionally impl `Invert` for `NonZeroScalar` ([#277]) +- `NonZeroScalar::to_bytes` ([#276]) +- `EncodedPoint::decompress` ([#275]) +- `sec1::Tag` ([#270]) +- `weierstrass::point::Decompress` trait ([#266]) +- `alloc` feature + `EncodedPoint::to_bytes()` ([#265]) + +### Changed +- Renamed `Arithmetic` trait to `point::ProjectiveArithmetic` ([#300]) +- Replaced `Arithmetic::Scalar` and `Arithmetic::AffinePoint` + with `Scalar` and `AffinePoint` ([#300]) +- Made `SecretKey` inner type generic ([#297]) +- Renamed `ElementBytes` to `FieldBytes` ([#296]) +- MSRV 1.44 ([#292]) +- Minimum `subtle` version now v2.3 ([#290]) +- Renamed `Curve::ElementSize` to `::FieldSize` ([#282]) +- Refactor `PublicKey` into `sec1::EncodedPoint` ([#264]) + +### Removed +- `FromBytes` trait ([#300]) +- `Generate` trait ([#295]) + +[#300]: https://github.com/RustCrypto/traits/pull/300 +[#297]: https://github.com/RustCrypto/traits/pull/297 +[#296]: https://github.com/RustCrypto/traits/pull/296 +[#295]: https://github.com/RustCrypto/traits/pull/295 +[#293]: https://github.com/RustCrypto/traits/pull/293 +[#292]: https://github.com/RustCrypto/traits/pull/292 +[#291]: https://github.com/RustCrypto/traits/pull/291 +[#290]: https://github.com/RustCrypto/traits/pull/290 +[#287]: https://github.com/RustCrypto/traits/pull/293 +[#286]: https://github.com/RustCrypto/traits/pull/286 +[#283]: https://github.com/RustCrypto/traits/pull/283 +[#282]: https://github.com/RustCrypto/traits/pull/282 +[#281]: https://github.com/RustCrypto/traits/pull/281 +[#279]: https://github.com/RustCrypto/traits/pull/279 +[#278]: https://github.com/RustCrypto/traits/pull/278 +[#277]: https://github.com/RustCrypto/traits/pull/277 +[#276]: https://github.com/RustCrypto/traits/pull/276 +[#275]: https://github.com/RustCrypto/traits/pull/275 +[#270]: https://github.com/RustCrypto/traits/pull/270 +[#266]: https://github.com/RustCrypto/traits/pull/266 +[#265]: https://github.com/RustCrypto/traits/pull/265 +[#264]: https://github.com/RustCrypto/traits/pull/264 + +## 0.5.0 (2020-08-10) +### Added +- `Arithmetic` trait ([#219]) +- `Generate` trait ([#220], [#226]) +- Toplevel `Curve` trait ([#223]) +- `Invert` trait ([#228]) +- `FromPublicKey` trait ([#229], [#248]) +- Re-export `zeroize` ([#233]) +- OID support ([#240], [#245]) +- `NonZeroScalar` type ([#241]) +- `Generator` trait ([#241]) +- `weierstrass::PublicKey::compress` method ([#243]) +- Derive `Clone` on `SecretKey` ([#244]) +- Generic Elliptic Curve Diffie-Hellman support ([#251]) + +### Changed +- Moved repo to https://github.com/RustCrypto/traits ([#213]) +- Rename `ScalarBytes` to `ElementBytes` ([#246]) +- Rename `CompressedCurvePoint`/`UncompressedCurvePoint` to + `CompressedPoint`/`UncompressedPoint` + +[#213]: https://github.com/RustCrypto/traits/pull/213 +[#219]: https://github.com/RustCrypto/traits/pull/219 +[#220]: https://github.com/RustCrypto/traits/pull/220 +[#223]: https://github.com/RustCrypto/traits/pull/223 +[#226]: https://github.com/RustCrypto/traits/pull/226 +[#228]: https://github.com/RustCrypto/traits/pull/228 +[#229]: https://github.com/RustCrypto/traits/pull/229 +[#233]: https://github.com/RustCrypto/traits/pull/233 +[#240]: https://github.com/RustCrypto/traits/pull/240 +[#241]: https://github.com/RustCrypto/traits/pull/241 +[#243]: https://github.com/RustCrypto/traits/pull/243 +[#244]: https://github.com/RustCrypto/traits/pull/244 +[#245]: https://github.com/RustCrypto/traits/pull/245 +[#246]: https://github.com/RustCrypto/traits/pull/246 +[#248]: https://github.com/RustCrypto/traits/pull/248 +[#251]: https://github.com/RustCrypto/traits/pull/251 + +## 0.4.0 (2020-06-04) +### Changed +- Bump `generic-array` dependency from v0.12 to v0.14 + +## 0.3.0 (2020-01-15) +### Added +- `Scalar` struct type + +### Changed +- Repository moved to + +### Removed +- Curve definitions/arithmetic extracted out into per-curve crates + +## 0.2.0 (2019-12-11) +### Added +- `secp256r1` (P-256) point compression and decompression + +### Changed +- Bump MSRV to 1.37 + +## 0.1.0 (2019-12-06) +- Initial release diff --git a/src/rust/vendor/elliptic-curve/Cargo.toml b/src/rust/vendor/elliptic-curve/Cargo.toml new file mode 100644 index 000000000..ffc77e38c --- /dev/null +++ b/src/rust/vendor/elliptic-curve/Cargo.toml @@ -0,0 +1,220 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.65" +name = "elliptic-curve" +version = "0.13.8" +authors = ["RustCrypto Developers"] +description = """ +General purpose Elliptic Curve Cryptography (ECC) support, including types +and traits for representing various elliptic curve forms, scalars, points, +and public/secret keys composed thereof. +""" +readme = "README.md" +keywords = [ + "crypto", + "ecc", + "elliptic", + "weierstrass", +] +categories = [ + "cryptography", + "no-std", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/RustCrypto/traits/tree/master/elliptic-curve" + +[package.metadata.docs.rs] +features = [ + "bits", + "ecdh", + "hash2curve", + "jwk", + "pem", + "std", + "voprf", +] +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.base16ct] +version = "0.2" + +[dependencies.base64ct] +version = "1" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.crypto-bigint] +version = "0.5" +features = [ + "rand_core", + "generic-array", + "zeroize", +] +default-features = false + +[dependencies.digest] +version = "0.10" +optional = true + +[dependencies.ff] +version = "0.13" +optional = true +default-features = false + +[dependencies.generic-array] +version = "0.14.6" +features = ["zeroize"] +default-features = false + +[dependencies.group] +version = "0.13" +optional = true +default-features = false + +[dependencies.hex-literal] +version = "0.4" +optional = true + +[dependencies.hkdf] +version = "0.12.1" +optional = true +default-features = false + +[dependencies.pem-rfc7468] +version = "0.7" +features = ["alloc"] +optional = true + +[dependencies.pkcs8] +version = "0.10.2" +optional = true +default-features = false + +[dependencies.rand_core] +version = "0.6.4" +default-features = false + +[dependencies.sec1] +version = "0.7.1" +features = [ + "subtle", + "zeroize", +] +optional = true + +[dependencies.serde_json] +version = "1.0.47" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.serdect] +version = "0.2" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.subtle] +version = "2" +default-features = false + +[dependencies.tap] +version = "1.0.1" +optional = true +default-features = false + +[dependencies.zeroize] +version = "1.7" +default-features = false + +[dev-dependencies.hex-literal] +version = "0.4" + +[dev-dependencies.sha2] +version = "0.10" + +[dev-dependencies.sha3] +version = "0.10" + +[features] +alloc = [ + "base16ct/alloc", + "ff?/alloc", + "group?/alloc", + "pkcs8?/alloc", + "sec1?/alloc", + "zeroize/alloc", +] +arithmetic = ["group"] +bits = [ + "arithmetic", + "ff/bits", + "dep:tap", +] +default = ["arithmetic"] +dev = [ + "arithmetic", + "dep:hex-literal", + "pem", + "pkcs8", +] +ecdh = [ + "arithmetic", + "digest", + "dep:hkdf", +] +group = [ + "dep:group", + "ff", +] +hash2curve = [ + "arithmetic", + "digest", +] +hazmat = [] +jwk = [ + "dep:base64ct", + "dep:serde_json", + "alloc", + "serde", + "zeroize/alloc", +] +pem = [ + "dep:pem-rfc7468", + "alloc", + "arithmetic", + "pkcs8", + "sec1/pem", +] +pkcs8 = [ + "dep:pkcs8", + "sec1", +] +serde = [ + "dep:serdect", + "alloc", + "pkcs8", + "sec1/serde", +] +std = [ + "alloc", + "rand_core/std", + "pkcs8?/std", + "sec1?/std", +] +voprf = ["digest"] diff --git a/src/rust/vendor/elliptic-curve/LICENSE-APACHE b/src/rust/vendor/elliptic-curve/LICENSE-APACHE new file mode 100644 index 000000000..78173fa2e --- /dev/null +++ b/src/rust/vendor/elliptic-curve/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/elliptic-curve/LICENSE-MIT b/src/rust/vendor/elliptic-curve/LICENSE-MIT new file mode 100644 index 000000000..d4ce06527 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2020-2022 RustCrypto Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/elliptic-curve/README.md b/src/rust/vendor/elliptic-curve/README.md new file mode 100644 index 000000000..37163a775 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/README.md @@ -0,0 +1,54 @@ +# RustCrypto: Elliptic Curve Traits + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +[![Build Status][build-image]][build-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Project Chat][chat-image]][chat-link] + +General purpose Elliptic Curve Cryptography (ECC) support, including types +and traits for representing various elliptic curve forms, scalars, points, +and public/secret keys composed thereof. + +[Documentation][docs-link] + +## Minimum Supported Rust Version + +Requires Rust **1.65** or higher. + +Minimum supported Rust version can be changed in the future, but it will be +done with a minor version bump. + +## SemVer Policy + +- All on-by-default features of this library are covered by SemVer +- MSRV is considered exempt from SemVer as noted above + +## License + +All crates licensed under either of + + * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + * [MIT license](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. + +[//]: # (badges) + +[crate-image]: https://buildstats.info/crate/elliptic-curve +[crate-link]: https://crates.io/crates/elliptic-curve +[docs-image]: https://docs.rs/elliptic-curve/badge.svg +[docs-link]: https://docs.rs/elliptic-curve/ +[build-image]: https://github.com/RustCrypto/traits/actions/workflows/elliptic-curve.yml/badge.svg +[build-link]: https://github.com/RustCrypto/traits/actions/workflows/elliptic-curve.yml +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260040-elliptic-curves diff --git a/src/rust/vendor/elliptic-curve/src/arithmetic.rs b/src/rust/vendor/elliptic-curve/src/arithmetic.rs new file mode 100644 index 000000000..7ef7fc53d --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/arithmetic.rs @@ -0,0 +1,86 @@ +//! Elliptic curve arithmetic traits. + +use crate::{ + ops::{Invert, LinearCombination, MulByGenerator, Reduce, ShrAssign}, + point::AffineCoordinates, + scalar::{FromUintUnchecked, IsHigh}, + Curve, FieldBytes, PrimeCurve, ScalarPrimitive, +}; +use core::fmt::Debug; +use subtle::{ConditionallySelectable, ConstantTimeEq, CtOption}; +use zeroize::DefaultIsZeroes; + +/// Elliptic curve with an arithmetic implementation. +pub trait CurveArithmetic: Curve { + /// Elliptic curve point in affine coordinates. + type AffinePoint: 'static + + AffineCoordinates> + + Copy + + ConditionallySelectable + + ConstantTimeEq + + Debug + + Default + + DefaultIsZeroes + + Eq + + PartialEq + + Sized + + Send + + Sync; + + /// Elliptic curve point in projective coordinates. + /// + /// Note: the following bounds are provided by [`group::Group`]: + /// - `'static` + /// - [`Copy`] + /// - [`Clone`] + /// - [`Debug`] + /// - [`Eq`] + /// - [`Sized`] + /// - [`Send`] + /// - [`Sync`] + type ProjectivePoint: ConditionallySelectable + + ConstantTimeEq + + Default + + DefaultIsZeroes + + From + + Into + + LinearCombination + + MulByGenerator + + group::Curve + + group::Group; + + /// Scalar field modulo this curve's order. + /// + /// Note: the following bounds are provided by [`ff::Field`]: + /// - `'static` + /// - [`Copy`] + /// - [`Clone`] + /// - [`ConditionallySelectable`] + /// - [`ConstantTimeEq`] + /// - [`Debug`] + /// - [`Default`] + /// - [`Send`] + /// - [`Sync`] + type Scalar: AsRef + + DefaultIsZeroes + + From> + + FromUintUnchecked + + Into> + + Into> + + Into + + Invert> + + IsHigh + + PartialOrd + + Reduce> + + ShrAssign + + ff::Field + + ff::PrimeField>; +} + +/// Prime order elliptic curve with projective arithmetic implementation. +pub trait PrimeCurveArithmetic: + PrimeCurve + CurveArithmetic +{ + /// Prime order elliptic curve group. + type CurveGroup: group::prime::PrimeCurve::AffinePoint>; +} diff --git a/src/rust/vendor/elliptic-curve/src/dev.rs b/src/rust/vendor/elliptic-curve/src/dev.rs new file mode 100644 index 000000000..a2659f1b8 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/dev.rs @@ -0,0 +1,843 @@ +//! Development-related functionality. +//! +//! Helpers and types for writing tests against concrete implementations of +//! the traits in this crate. + +use crate::{ + bigint::{Limb, U256}, + error::{Error, Result}, + generic_array::typenum::U32, + ops::{Invert, LinearCombination, MulByGenerator, Reduce, ShrAssign}, + pkcs8, + point::AffineCoordinates, + rand_core::RngCore, + scalar::{FromUintUnchecked, IsHigh}, + sec1::{CompressedPoint, FromEncodedPoint, ToEncodedPoint}, + subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, + zeroize::DefaultIsZeroes, + Curve, CurveArithmetic, FieldBytesEncoding, PrimeCurve, +}; +use core::{ + iter::{Product, Sum}, + ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, +}; +use ff::{Field, PrimeField}; +use hex_literal::hex; +use pkcs8::AssociatedOid; + +#[cfg(feature = "bits")] +use ff::PrimeFieldBits; + +#[cfg(feature = "jwk")] +use crate::JwkParameters; + +/// Pseudo-coordinate for fixed-based scalar mult output +pub const PSEUDO_COORDINATE_FIXED_BASE_MUL: [u8; 32] = + hex!("deadbeef00000000000000000000000000000000000000000000000000000001"); + +/// SEC1 encoded point. +pub type EncodedPoint = crate::sec1::EncodedPoint; + +/// Field element bytes. +pub type FieldBytes = crate::FieldBytes; + +/// Non-zero scalar value. +pub type NonZeroScalar = crate::NonZeroScalar; + +/// Public key. +pub type PublicKey = crate::PublicKey; + +/// Secret key. +pub type SecretKey = crate::SecretKey; + +/// Scalar primitive type. +// TODO(tarcieri): make this the scalar type when it's more capable +pub type ScalarPrimitive = crate::ScalarPrimitive; + +/// Scalar bits. +#[cfg(feature = "bits")] +pub type ScalarBits = crate::scalar::ScalarBits; + +/// Mock elliptic curve type useful for writing tests which require a concrete +/// curve type. +/// +/// Note: this type is roughly modeled off of NIST P-256, but does not provide +/// an actual cure arithmetic implementation. +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] +pub struct MockCurve; + +impl Curve for MockCurve { + type FieldBytesSize = U32; + type Uint = U256; + + const ORDER: U256 = + U256::from_be_hex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"); +} + +impl PrimeCurve for MockCurve {} + +impl CurveArithmetic for MockCurve { + type AffinePoint = AffinePoint; + type ProjectivePoint = ProjectivePoint; + type Scalar = Scalar; +} + +impl AssociatedOid for MockCurve { + /// OID for NIST P-256 + const OID: pkcs8::ObjectIdentifier = pkcs8::ObjectIdentifier::new_unwrap("1.2.840.10045.3.1.7"); +} + +#[cfg(feature = "jwk")] +impl JwkParameters for MockCurve { + const CRV: &'static str = "P-256"; +} + +/// Example scalar type +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] +pub struct Scalar(ScalarPrimitive); + +impl Field for Scalar { + const ZERO: Self = Self(ScalarPrimitive::ZERO); + const ONE: Self = Self(ScalarPrimitive::ONE); + + fn random(mut rng: impl RngCore) -> Self { + let mut bytes = FieldBytes::default(); + + loop { + rng.fill_bytes(&mut bytes); + if let Some(scalar) = Self::from_repr(bytes).into() { + return scalar; + } + } + } + + fn is_zero(&self) -> Choice { + self.0.is_zero() + } + + #[must_use] + fn square(&self) -> Self { + unimplemented!(); + } + + #[must_use] + fn double(&self) -> Self { + self.add(self) + } + + fn invert(&self) -> CtOption { + unimplemented!(); + } + + fn sqrt(&self) -> CtOption { + unimplemented!(); + } + + fn sqrt_ratio(_num: &Self, _div: &Self) -> (Choice, Self) { + unimplemented!(); + } +} + +impl PrimeField for Scalar { + type Repr = FieldBytes; + + const MODULUS: &'static str = + "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"; + const NUM_BITS: u32 = 256; + const CAPACITY: u32 = 255; + const TWO_INV: Self = Self::ZERO; // BOGUS! + const MULTIPLICATIVE_GENERATOR: Self = Self::ZERO; // BOGUS! Should be 7 + const S: u32 = 4; + const ROOT_OF_UNITY: Self = Self::ZERO; // BOGUS! Should be 0xffc97f062a770992ba807ace842a3dfc1546cad004378daf0592d7fbb41e6602 + const ROOT_OF_UNITY_INV: Self = Self::ZERO; // BOGUS! + const DELTA: Self = Self::ZERO; // BOGUS! + + fn from_repr(bytes: FieldBytes) -> CtOption { + ScalarPrimitive::from_bytes(&bytes).map(Self) + } + + fn to_repr(&self) -> FieldBytes { + self.0.to_bytes() + } + + fn is_odd(&self) -> Choice { + self.0.is_odd() + } +} + +#[cfg(feature = "bits")] +impl PrimeFieldBits for Scalar { + #[cfg(target_pointer_width = "32")] + type ReprBits = [u32; 8]; + + #[cfg(target_pointer_width = "64")] + type ReprBits = [u64; 4]; + + fn to_le_bits(&self) -> ScalarBits { + self.0.as_uint().to_words().into() + } + + fn char_le_bits() -> ScalarBits { + MockCurve::ORDER.to_words().into() + } +} + +impl AsRef for Scalar { + fn as_ref(&self) -> &Scalar { + self + } +} + +impl ConditionallySelectable for Scalar { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self(ScalarPrimitive::conditional_select(&a.0, &b.0, choice)) + } +} + +impl ConstantTimeEq for Scalar { + fn ct_eq(&self, other: &Self) -> Choice { + self.0.ct_eq(&other.0) + } +} + +impl DefaultIsZeroes for Scalar {} + +impl Add for Scalar { + type Output = Scalar; + + fn add(self, other: Scalar) -> Scalar { + self.add(&other) + } +} + +impl Add<&Scalar> for Scalar { + type Output = Scalar; + + fn add(self, other: &Scalar) -> Scalar { + Self(self.0.add(&other.0)) + } +} + +impl AddAssign for Scalar { + fn add_assign(&mut self, other: Scalar) { + *self = *self + other; + } +} + +impl AddAssign<&Scalar> for Scalar { + fn add_assign(&mut self, other: &Scalar) { + *self = *self + other; + } +} + +impl Sub for Scalar { + type Output = Scalar; + + fn sub(self, other: Scalar) -> Scalar { + self.sub(&other) + } +} + +impl Sub<&Scalar> for Scalar { + type Output = Scalar; + + fn sub(self, other: &Scalar) -> Scalar { + Self(self.0.sub(&other.0)) + } +} + +impl SubAssign for Scalar { + fn sub_assign(&mut self, other: Scalar) { + *self = *self - other; + } +} + +impl SubAssign<&Scalar> for Scalar { + fn sub_assign(&mut self, other: &Scalar) { + *self = *self - other; + } +} + +impl Mul for Scalar { + type Output = Scalar; + + fn mul(self, _other: Scalar) -> Scalar { + unimplemented!(); + } +} + +impl Mul<&Scalar> for Scalar { + type Output = Scalar; + + fn mul(self, _other: &Scalar) -> Scalar { + unimplemented!(); + } +} + +impl MulAssign for Scalar { + fn mul_assign(&mut self, _rhs: Scalar) { + unimplemented!(); + } +} + +impl MulAssign<&Scalar> for Scalar { + fn mul_assign(&mut self, _rhs: &Scalar) { + unimplemented!(); + } +} + +impl Neg for Scalar { + type Output = Scalar; + + fn neg(self) -> Scalar { + Self(self.0.neg()) + } +} + +impl ShrAssign for Scalar { + fn shr_assign(&mut self, rhs: usize) { + self.0 >>= rhs; + } +} + +impl Sum for Scalar { + fn sum>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl<'a> Sum<&'a Scalar> for Scalar { + fn sum>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl Product for Scalar { + fn product>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl<'a> Product<&'a Scalar> for Scalar { + fn product>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl Invert for Scalar { + type Output = CtOption; + + fn invert(&self) -> CtOption { + unimplemented!(); + } +} + +impl Reduce for Scalar { + type Bytes = FieldBytes; + + fn reduce(w: U256) -> Self { + let (r, underflow) = w.sbb(&MockCurve::ORDER, Limb::ZERO); + let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8); + let reduced = U256::conditional_select(&w, &r, !underflow); + Self(ScalarPrimitive::new(reduced).unwrap()) + } + + fn reduce_bytes(_: &FieldBytes) -> Self { + todo!() + } +} + +impl FieldBytesEncoding for U256 {} + +impl From for Scalar { + fn from(n: u64) -> Scalar { + Self(n.into()) + } +} + +impl From for Scalar { + fn from(scalar: ScalarPrimitive) -> Scalar { + Self(scalar) + } +} + +impl From for ScalarPrimitive { + fn from(scalar: Scalar) -> ScalarPrimitive { + scalar.0 + } +} + +impl From for U256 { + fn from(scalar: Scalar) -> U256 { + scalar.0.to_uint() + } +} + +impl TryFrom for Scalar { + type Error = Error; + + fn try_from(w: U256) -> Result { + Option::from(ScalarPrimitive::new(w)).map(Self).ok_or(Error) + } +} + +impl FromUintUnchecked for Scalar { + type Uint = U256; + + fn from_uint_unchecked(uint: U256) -> Self { + Self(ScalarPrimitive::from_uint_unchecked(uint)) + } +} + +impl From for FieldBytes { + fn from(scalar: Scalar) -> Self { + Self::from(&scalar) + } +} + +impl From<&Scalar> for FieldBytes { + fn from(scalar: &Scalar) -> Self { + scalar.to_repr() + } +} + +impl IsHigh for Scalar { + fn is_high(&self) -> Choice { + self.0.is_high() + } +} + +/// Example affine point type +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum AffinePoint { + /// Result of fixed-based scalar multiplication. + FixedBaseOutput(Scalar), + + /// Identity. + Identity, + + /// Base point. + Generator, + + /// Point corresponding to a given [`EncodedPoint`]. + Other(EncodedPoint), +} + +impl AffineCoordinates for AffinePoint { + type FieldRepr = FieldBytes; + + fn x(&self) -> FieldBytes { + unimplemented!(); + } + + fn y_is_odd(&self) -> Choice { + unimplemented!(); + } +} + +impl ConstantTimeEq for AffinePoint { + fn ct_eq(&self, other: &Self) -> Choice { + match (self, other) { + (Self::FixedBaseOutput(scalar), Self::FixedBaseOutput(other_scalar)) => { + scalar.ct_eq(other_scalar) + } + (Self::Identity, Self::Identity) | (Self::Generator, Self::Generator) => 1.into(), + (Self::Other(point), Self::Other(other_point)) => u8::from(point == other_point).into(), + _ => 0.into(), + } + } +} + +impl ConditionallySelectable for AffinePoint { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + // Not really constant time, but this is dev code + if choice.into() { + *b + } else { + *a + } + } +} + +impl Default for AffinePoint { + fn default() -> Self { + Self::Identity + } +} + +impl DefaultIsZeroes for AffinePoint {} + +impl FromEncodedPoint for AffinePoint { + fn from_encoded_point(encoded_point: &EncodedPoint) -> CtOption { + let point = if encoded_point.is_identity() { + Self::Identity + } else { + Self::Other(*encoded_point) + }; + + CtOption::new(point, Choice::from(1)) + } +} + +impl ToEncodedPoint for AffinePoint { + fn to_encoded_point(&self, compress: bool) -> EncodedPoint { + match self { + Self::FixedBaseOutput(scalar) => EncodedPoint::from_affine_coordinates( + &scalar.to_repr(), + &PSEUDO_COORDINATE_FIXED_BASE_MUL.into(), + false, + ), + Self::Other(point) => { + if compress == point.is_compressed() { + *point + } else { + unimplemented!(); + } + } + _ => unimplemented!(), + } + } +} + +impl Mul for AffinePoint { + type Output = AffinePoint; + + fn mul(self, _scalar: NonZeroScalar) -> Self { + unimplemented!(); + } +} + +/// Example projective point type +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ProjectivePoint { + /// Result of fixed-based scalar multiplication + FixedBaseOutput(Scalar), + + /// Is this point the identity point? + Identity, + + /// Is this point the generator point? + Generator, + + /// Is this point a different point corresponding to a given [`AffinePoint`] + Other(AffinePoint), +} + +impl ConstantTimeEq for ProjectivePoint { + fn ct_eq(&self, other: &Self) -> Choice { + match (self, other) { + (Self::FixedBaseOutput(scalar), Self::FixedBaseOutput(other_scalar)) => { + scalar.ct_eq(other_scalar) + } + (Self::Identity, Self::Identity) | (Self::Generator, Self::Generator) => 1.into(), + (Self::Other(point), Self::Other(other_point)) => point.ct_eq(other_point), + _ => 0.into(), + } + } +} + +impl ConditionallySelectable for ProjectivePoint { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + if choice.into() { + *b + } else { + *a + } + } +} + +impl Default for ProjectivePoint { + fn default() -> Self { + Self::Identity + } +} + +impl DefaultIsZeroes for ProjectivePoint {} + +impl From for ProjectivePoint { + fn from(point: AffinePoint) -> ProjectivePoint { + match point { + AffinePoint::FixedBaseOutput(scalar) => ProjectivePoint::FixedBaseOutput(scalar), + AffinePoint::Identity => ProjectivePoint::Identity, + AffinePoint::Generator => ProjectivePoint::Generator, + other => ProjectivePoint::Other(other), + } + } +} + +impl From for AffinePoint { + fn from(point: ProjectivePoint) -> AffinePoint { + group::Curve::to_affine(&point) + } +} + +impl FromEncodedPoint for ProjectivePoint { + fn from_encoded_point(_point: &EncodedPoint) -> CtOption { + unimplemented!(); + } +} + +impl ToEncodedPoint for ProjectivePoint { + fn to_encoded_point(&self, _compress: bool) -> EncodedPoint { + unimplemented!(); + } +} + +impl group::Group for ProjectivePoint { + type Scalar = Scalar; + + fn random(_rng: impl RngCore) -> Self { + unimplemented!(); + } + + fn identity() -> Self { + Self::Identity + } + + fn generator() -> Self { + Self::Generator + } + + fn is_identity(&self) -> Choice { + Choice::from(u8::from(self == &Self::Identity)) + } + + #[must_use] + fn double(&self) -> Self { + unimplemented!(); + } +} + +impl group::GroupEncoding for AffinePoint { + type Repr = CompressedPoint; + + fn from_bytes(bytes: &Self::Repr) -> CtOption { + EncodedPoint::from_bytes(bytes) + .map(|point| CtOption::new(point, Choice::from(1))) + .unwrap_or_else(|_| { + let is_identity = bytes.ct_eq(&Self::Repr::default()); + CtOption::new(EncodedPoint::identity(), is_identity) + }) + .and_then(|point| Self::from_encoded_point(&point)) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { + Self::from_bytes(bytes) + } + + fn to_bytes(&self) -> Self::Repr { + let encoded = self.to_encoded_point(true); + let mut result = CompressedPoint::::default(); + result[..encoded.len()].copy_from_slice(encoded.as_bytes()); + result + } +} + +impl group::GroupEncoding for ProjectivePoint { + type Repr = CompressedPoint; + + fn from_bytes(bytes: &Self::Repr) -> CtOption { + ::from_bytes(bytes).map(Into::into) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { + Self::from_bytes(bytes) + } + + fn to_bytes(&self) -> Self::Repr { + group::Curve::to_affine(self).to_bytes() + } +} + +impl group::Curve for ProjectivePoint { + type AffineRepr = AffinePoint; + + fn to_affine(&self) -> AffinePoint { + match self { + Self::FixedBaseOutput(scalar) => AffinePoint::FixedBaseOutput(*scalar), + Self::Other(affine) => *affine, + _ => unimplemented!(), + } + } +} + +impl LinearCombination for ProjectivePoint {} + +impl Add for ProjectivePoint { + type Output = ProjectivePoint; + + fn add(self, _other: ProjectivePoint) -> ProjectivePoint { + unimplemented!(); + } +} + +impl Add<&ProjectivePoint> for ProjectivePoint { + type Output = ProjectivePoint; + + fn add(self, _other: &ProjectivePoint) -> ProjectivePoint { + unimplemented!(); + } +} + +impl AddAssign for ProjectivePoint { + fn add_assign(&mut self, _rhs: ProjectivePoint) { + unimplemented!(); + } +} + +impl AddAssign<&ProjectivePoint> for ProjectivePoint { + fn add_assign(&mut self, _rhs: &ProjectivePoint) { + unimplemented!(); + } +} + +impl Sub for ProjectivePoint { + type Output = ProjectivePoint; + + fn sub(self, _other: ProjectivePoint) -> ProjectivePoint { + unimplemented!(); + } +} + +impl Sub<&ProjectivePoint> for ProjectivePoint { + type Output = ProjectivePoint; + + fn sub(self, _other: &ProjectivePoint) -> ProjectivePoint { + unimplemented!(); + } +} + +impl SubAssign for ProjectivePoint { + fn sub_assign(&mut self, _rhs: ProjectivePoint) { + unimplemented!(); + } +} + +impl SubAssign<&ProjectivePoint> for ProjectivePoint { + fn sub_assign(&mut self, _rhs: &ProjectivePoint) { + unimplemented!(); + } +} + +impl Add for ProjectivePoint { + type Output = ProjectivePoint; + + fn add(self, _other: AffinePoint) -> ProjectivePoint { + unimplemented!(); + } +} + +impl Add<&AffinePoint> for ProjectivePoint { + type Output = ProjectivePoint; + + fn add(self, _other: &AffinePoint) -> ProjectivePoint { + unimplemented!(); + } +} + +impl AddAssign for ProjectivePoint { + fn add_assign(&mut self, _rhs: AffinePoint) { + unimplemented!(); + } +} + +impl AddAssign<&AffinePoint> for ProjectivePoint { + fn add_assign(&mut self, _rhs: &AffinePoint) { + unimplemented!(); + } +} + +impl Sum for ProjectivePoint { + fn sum>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl<'a> Sum<&'a ProjectivePoint> for ProjectivePoint { + fn sum>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl Sub for ProjectivePoint { + type Output = ProjectivePoint; + + fn sub(self, _other: AffinePoint) -> ProjectivePoint { + unimplemented!(); + } +} + +impl Sub<&AffinePoint> for ProjectivePoint { + type Output = ProjectivePoint; + + fn sub(self, _other: &AffinePoint) -> ProjectivePoint { + unimplemented!(); + } +} + +impl SubAssign for ProjectivePoint { + fn sub_assign(&mut self, _rhs: AffinePoint) { + unimplemented!(); + } +} + +impl SubAssign<&AffinePoint> for ProjectivePoint { + fn sub_assign(&mut self, _rhs: &AffinePoint) { + unimplemented!(); + } +} + +impl Mul for ProjectivePoint { + type Output = ProjectivePoint; + + fn mul(self, scalar: Scalar) -> ProjectivePoint { + match self { + Self::Generator => Self::FixedBaseOutput(scalar), + _ => unimplemented!(), + } + } +} + +impl Mul<&Scalar> for ProjectivePoint { + type Output = ProjectivePoint; + + fn mul(self, scalar: &Scalar) -> ProjectivePoint { + self * *scalar + } +} + +impl MulAssign for ProjectivePoint { + fn mul_assign(&mut self, _rhs: Scalar) { + unimplemented!(); + } +} + +impl MulAssign<&Scalar> for ProjectivePoint { + fn mul_assign(&mut self, _rhs: &Scalar) { + unimplemented!(); + } +} + +impl MulByGenerator for ProjectivePoint {} + +impl Neg for ProjectivePoint { + type Output = ProjectivePoint; + + fn neg(self) -> ProjectivePoint { + unimplemented!(); + } +} + +#[cfg(test)] +mod tests { + use super::Scalar; + use ff::PrimeField; + use hex_literal::hex; + + #[test] + fn round_trip() { + let bytes = hex!("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); + let scalar = Scalar::from_repr(bytes.into()).unwrap(); + assert_eq!(&bytes, scalar.to_repr().as_slice()); + } +} diff --git a/src/rust/vendor/elliptic-curve/src/ecdh.rs b/src/rust/vendor/elliptic-curve/src/ecdh.rs new file mode 100644 index 000000000..c64a696aa --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/ecdh.rs @@ -0,0 +1,236 @@ +//! Elliptic Curve Diffie-Hellman Support. +//! +//! This module contains a generic ECDH implementation which is usable with +//! any elliptic curve which implements the [`CurveArithmetic`] trait (presently +//! the `k256` and `p256` crates) +//! +//! # ECDH Ephemeral (ECDHE) Usage +//! +//! Ephemeral Diffie-Hellman provides a one-time key exchange between two peers +//! using a randomly generated set of keys for each exchange. +//! +//! In practice ECDHE is used as part of an [Authenticated Key Exchange (AKE)][AKE] +//! protocol (e.g. [SIGMA]), where an existing cryptographic trust relationship +//! can be used to determine the authenticity of the ephemeral keys, such as +//! a digital signature. Without such an additional step, ECDHE is insecure! +//! (see security warning below) +//! +//! See the documentation for the [`EphemeralSecret`] type for more information +//! on performing ECDH ephemeral key exchanges. +//! +//! # Static ECDH Usage +//! +//! Static ECDH key exchanges are supported via the low-level +//! [`diffie_hellman`] function. +//! +//! [AKE]: https://en.wikipedia.org/wiki/Authenticated_Key_Exchange +//! [SIGMA]: https://webee.technion.ac.il/~hugo/sigma-pdf.pdf + +use crate::{ + point::AffineCoordinates, AffinePoint, Curve, CurveArithmetic, FieldBytes, NonZeroScalar, + ProjectivePoint, PublicKey, +}; +use core::borrow::Borrow; +use digest::{crypto_common::BlockSizeUser, Digest}; +use group::Curve as _; +use hkdf::{hmac::SimpleHmac, Hkdf}; +use rand_core::CryptoRngCore; +use zeroize::{Zeroize, ZeroizeOnDrop}; + +/// Low-level Elliptic Curve Diffie-Hellman (ECDH) function. +/// +/// Whenever possible, we recommend using the high-level ECDH ephemeral API +/// provided by [`EphemeralSecret`]. +/// +/// However, if you are implementing a protocol which requires a static scalar +/// value as part of an ECDH exchange, this API can be used to compute a +/// [`SharedSecret`] from that value. +/// +/// Note that this API operates on the low-level [`NonZeroScalar`] and +/// [`AffinePoint`] types. If you are attempting to use the higher-level +/// [`SecretKey`][`crate::SecretKey`] and [`PublicKey`] types, you will +/// need to use the following conversions: +/// +/// ```ignore +/// let shared_secret = elliptic_curve::ecdh::diffie_hellman( +/// secret_key.to_nonzero_scalar(), +/// public_key.as_affine() +/// ); +/// ``` +pub fn diffie_hellman( + secret_key: impl Borrow>, + public_key: impl Borrow>, +) -> SharedSecret +where + C: CurveArithmetic, +{ + let public_point = ProjectivePoint::::from(*public_key.borrow()); + let secret_point = (public_point * secret_key.borrow().as_ref()).to_affine(); + SharedSecret::new(secret_point) +} + +/// Ephemeral Diffie-Hellman Secret. +/// +/// These are ephemeral "secret key" values which are deliberately designed +/// to avoid being persisted. +/// +/// To perform an ephemeral Diffie-Hellman exchange, do the following: +/// +/// - Have each participant generate an [`EphemeralSecret`] value +/// - Compute the [`PublicKey`] for that value +/// - Have each peer provide their [`PublicKey`] to their counterpart +/// - Use [`EphemeralSecret`] and the other participant's [`PublicKey`] +/// to compute a [`SharedSecret`] value. +/// +/// # ⚠️ SECURITY WARNING ⚠️ +/// +/// Ephemeral Diffie-Hellman exchanges are unauthenticated and without a +/// further authentication step are trivially vulnerable to man-in-the-middle +/// attacks! +/// +/// These exchanges should be performed in the context of a protocol which +/// takes further steps to authenticate the peers in a key exchange. +pub struct EphemeralSecret +where + C: CurveArithmetic, +{ + scalar: NonZeroScalar, +} + +impl EphemeralSecret +where + C: CurveArithmetic, +{ + /// Generate a cryptographically random [`EphemeralSecret`]. + pub fn random(rng: &mut impl CryptoRngCore) -> Self { + Self { + scalar: NonZeroScalar::random(rng), + } + } + + /// Get the public key associated with this ephemeral secret. + /// + /// The `compress` flag enables point compression. + pub fn public_key(&self) -> PublicKey { + PublicKey::from_secret_scalar(&self.scalar) + } + + /// Compute a Diffie-Hellman shared secret from an ephemeral secret and the + /// public key of the other participant in the exchange. + pub fn diffie_hellman(&self, public_key: &PublicKey) -> SharedSecret { + diffie_hellman(self.scalar, public_key.as_affine()) + } +} + +impl From<&EphemeralSecret> for PublicKey +where + C: CurveArithmetic, +{ + fn from(ephemeral_secret: &EphemeralSecret) -> Self { + ephemeral_secret.public_key() + } +} + +impl Zeroize for EphemeralSecret +where + C: CurveArithmetic, +{ + fn zeroize(&mut self) { + self.scalar.zeroize() + } +} + +impl ZeroizeOnDrop for EphemeralSecret where C: CurveArithmetic {} + +impl Drop for EphemeralSecret +where + C: CurveArithmetic, +{ + fn drop(&mut self) { + self.zeroize(); + } +} + +/// Shared secret value computed via ECDH key agreement. +pub struct SharedSecret { + /// Computed secret value + secret_bytes: FieldBytes, +} + +impl SharedSecret { + /// Create a new [`SharedSecret`] from an [`AffinePoint`] for this curve. + #[inline] + fn new(point: AffinePoint) -> Self + where + C: CurveArithmetic, + { + Self { + secret_bytes: point.x(), + } + } + + /// Use [HKDF] (HMAC-based Extract-and-Expand Key Derivation Function) to + /// extract entropy from this shared secret. + /// + /// This method can be used to transform the shared secret into uniformly + /// random values which are suitable as key material. + /// + /// The `D` type parameter is a cryptographic digest function. + /// `sha2::Sha256` is a common choice for use with HKDF. + /// + /// The `salt` parameter can be used to supply additional randomness. + /// Some examples include: + /// + /// - randomly generated (but authenticated) string + /// - fixed application-specific value + /// - previous shared secret used for rekeying (as in TLS 1.3 and Noise) + /// + /// After initializing HKDF, use [`Hkdf::expand`] to obtain output key + /// material. + /// + /// [HKDF]: https://en.wikipedia.org/wiki/HKDF + pub fn extract(&self, salt: Option<&[u8]>) -> Hkdf> + where + D: BlockSizeUser + Clone + Digest, + { + Hkdf::new(salt, &self.secret_bytes) + } + + /// This value contains the raw serialized x-coordinate of the elliptic curve + /// point computed from a Diffie-Hellman exchange, serialized as bytes. + /// + /// When in doubt, use [`SharedSecret::extract`] instead. + /// + /// # ⚠️ WARNING: NOT UNIFORMLY RANDOM! ⚠️ + /// + /// This value is not uniformly random and should not be used directly + /// as a cryptographic key for anything which requires that property + /// (e.g. symmetric ciphers). + /// + /// Instead, the resulting value should be used as input to a Key Derivation + /// Function (KDF) or cryptographic hash function to produce a symmetric key. + /// The [`SharedSecret::extract`] function will do this for you. + pub fn raw_secret_bytes(&self) -> &FieldBytes { + &self.secret_bytes + } +} + +impl From> for SharedSecret { + /// NOTE: this impl is intended to be used by curve implementations to + /// instantiate a [`SharedSecret`] value from their respective + /// [`AffinePoint`] type. + /// + /// Curve implementations should provide the field element representing + /// the affine x-coordinate as `secret_bytes`. + fn from(secret_bytes: FieldBytes) -> Self { + Self { secret_bytes } + } +} + +impl ZeroizeOnDrop for SharedSecret {} + +impl Drop for SharedSecret { + fn drop(&mut self) { + self.secret_bytes.zeroize() + } +} diff --git a/src/rust/vendor/elliptic-curve/src/error.rs b/src/rust/vendor/elliptic-curve/src/error.rs new file mode 100644 index 000000000..53f5b1773 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/error.rs @@ -0,0 +1,42 @@ +//! Error type. + +use core::fmt::{self, Display}; + +#[cfg(feature = "pkcs8")] +use crate::pkcs8; + +/// Result type with the `elliptic-curve` crate's [`Error`] type. +pub type Result = core::result::Result; + +/// Elliptic curve errors. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct Error; + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("crypto error") + } +} + +impl From for Error { + fn from(_: base16ct::Error) -> Error { + Error + } +} + +#[cfg(feature = "pkcs8")] +impl From for Error { + fn from(_: pkcs8::Error) -> Error { + Error + } +} + +#[cfg(feature = "sec1")] +impl From for Error { + fn from(_: sec1::Error) -> Error { + Error + } +} + +#[cfg(feature = "std")] +impl std::error::Error for Error {} diff --git a/src/rust/vendor/elliptic-curve/src/field.rs b/src/rust/vendor/elliptic-curve/src/field.rs new file mode 100644 index 000000000..66055abc2 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/field.rs @@ -0,0 +1,51 @@ +//! Field elements. + +use crate::{ + bigint::{ArrayEncoding, ByteArray, Integer}, + Curve, +}; +use generic_array::{typenum::Unsigned, GenericArray}; + +/// Size of serialized field elements of this elliptic curve. +pub type FieldBytesSize = ::FieldBytesSize; + +/// Byte representation of a base/scalar field element of a given curve. +pub type FieldBytes = GenericArray>; + +/// Trait for decoding/encoding `Curve::Uint` from/to [`FieldBytes`] using +/// curve-specific rules. +/// +/// Namely a curve's modulus may be smaller than the big integer type used to +/// internally represent field elements (since the latter are multiples of the +/// limb size), such as in the case of curves like NIST P-224 and P-521, and so +/// it may need to be padded/truncated to the right length. +/// +/// Additionally, different curves have different endianness conventions, also +/// captured here. +pub trait FieldBytesEncoding: ArrayEncoding + Integer +where + C: Curve, +{ + /// Decode unsigned integer from serialized field element. + /// + /// The default implementation assumes a big endian encoding. + fn decode_field_bytes(field_bytes: &FieldBytes) -> Self { + debug_assert!(field_bytes.len() <= Self::ByteSize::USIZE); + let mut byte_array = ByteArray::::default(); + let offset = Self::ByteSize::USIZE.saturating_sub(field_bytes.len()); + byte_array[offset..].copy_from_slice(field_bytes); + Self::from_be_byte_array(byte_array) + } + + /// Encode unsigned integer into serialized field element. + /// + /// The default implementation assumes a big endian encoding. + fn encode_field_bytes(&self) -> FieldBytes { + let mut field_bytes = FieldBytes::::default(); + debug_assert!(field_bytes.len() <= Self::ByteSize::USIZE); + + let offset = Self::ByteSize::USIZE.saturating_sub(field_bytes.len()); + field_bytes.copy_from_slice(&self.to_be_byte_array()[offset..]); + field_bytes + } +} diff --git a/src/rust/vendor/elliptic-curve/src/hash2curve.rs b/src/rust/vendor/elliptic-curve/src/hash2curve.rs new file mode 100644 index 000000000..3df394f79 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/hash2curve.rs @@ -0,0 +1,15 @@ +//! Traits for hashing byte sequences to curve points. +//! +//! + +mod group_digest; +mod hash2field; +mod isogeny; +mod map2curve; +mod osswu; + +pub use group_digest::*; +pub use hash2field::*; +pub use isogeny::*; +pub use map2curve::*; +pub use osswu::*; diff --git a/src/rust/vendor/elliptic-curve/src/hash2curve/group_digest.rs b/src/rust/vendor/elliptic-curve/src/hash2curve/group_digest.rs new file mode 100644 index 000000000..ea7f0471f --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/hash2curve/group_digest.rs @@ -0,0 +1,123 @@ +//! Traits for handling hash to curve. + +use super::{hash_to_field, ExpandMsg, FromOkm, MapToCurve}; +use crate::{CurveArithmetic, ProjectivePoint, Result}; +use group::cofactor::CofactorGroup; + +/// Adds hashing arbitrary byte sequences to a valid group element +pub trait GroupDigest: CurveArithmetic +where + ProjectivePoint: CofactorGroup, +{ + /// The field element representation for a group value with multiple elements + type FieldElement: FromOkm + MapToCurve> + Default + Copy; + + /// Computes the hash to curve routine. + /// + /// From : + /// + /// > Uniform encoding from byte strings to points in G. + /// > That is, the distribution of its output is statistically close + /// > to uniform in G. + /// > This function is suitable for most applications requiring a random + /// > oracle returning points in G assuming a cryptographically secure + /// > hash function is used. + /// + /// # Examples + /// + /// ## Using a fixed size hash function + /// + /// ```ignore + /// let pt = ProjectivePoint::hash_from_bytes::>(b"test data", b"CURVE_XMD:SHA-256_SSWU_RO_"); + /// ``` + /// + /// ## Using an extendable output function + /// + /// ```ignore + /// let pt = ProjectivePoint::hash_from_bytes::>(b"test data", b"CURVE_XOF:SHAKE-256_SSWU_RO_"); + /// ``` + /// + /// # Errors + /// See implementors of [`ExpandMsg`] for errors: + /// - [`ExpandMsgXmd`] + /// - [`ExpandMsgXof`] + /// + /// `len_in_bytes = ::Length * 2` + /// + /// [`ExpandMsgXmd`]: crate::hash2curve::ExpandMsgXmd + /// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof + fn hash_from_bytes<'a, X: ExpandMsg<'a>>( + msgs: &[&[u8]], + dsts: &'a [&'a [u8]], + ) -> Result> { + let mut u = [Self::FieldElement::default(), Self::FieldElement::default()]; + hash_to_field::(msgs, dsts, &mut u)?; + let q0 = u[0].map_to_curve(); + let q1 = u[1].map_to_curve(); + // Ideally we could add and then clear cofactor once + // thus saving a call but the field elements may not + // add properly due to the underlying implementation + // which could result in an incorrect subgroup. + // This is caused curve coefficients being different than + // what is usually implemented. + // FieldElement expects the `a` and `b` to be the original values + // isogenies are different with curves like k256 and bls12-381. + // This problem doesn't manifest for curves with no isogeny like p256. + // For k256 and p256 clear_cofactor doesn't do anything anyway so it will be a no-op. + Ok(q0.clear_cofactor().into() + q1.clear_cofactor()) + } + + /// Computes the encode to curve routine. + /// + /// From : + /// + /// > Nonuniform encoding from byte strings to + /// > points in G. That is, the distribution of its output is not + /// > uniformly random in G: the set of possible outputs of + /// > encode_to_curve is only a fraction of the points in G, and some + /// > points in this set are more likely to be output than others. + /// + /// # Errors + /// See implementors of [`ExpandMsg`] for errors: + /// - [`ExpandMsgXmd`] + /// - [`ExpandMsgXof`] + /// + /// `len_in_bytes = ::Length` + /// + /// [`ExpandMsgXmd`]: crate::hash2curve::ExpandMsgXmd + /// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof + fn encode_from_bytes<'a, X: ExpandMsg<'a>>( + msgs: &[&[u8]], + dsts: &'a [&'a [u8]], + ) -> Result> { + let mut u = [Self::FieldElement::default()]; + hash_to_field::(msgs, dsts, &mut u)?; + let q0 = u[0].map_to_curve(); + Ok(q0.clear_cofactor().into()) + } + + /// Computes the hash to field routine according to + /// + /// and returns a scalar. + /// + /// # Errors + /// See implementors of [`ExpandMsg`] for errors: + /// - [`ExpandMsgXmd`] + /// - [`ExpandMsgXof`] + /// + /// `len_in_bytes = ::Length` + /// + /// [`ExpandMsgXmd`]: crate::hash2curve::ExpandMsgXmd + /// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof + fn hash_to_scalar<'a, X: ExpandMsg<'a>>( + msgs: &[&[u8]], + dsts: &'a [&'a [u8]], + ) -> Result + where + Self::Scalar: FromOkm, + { + let mut u = [Self::Scalar::default()]; + hash_to_field::(msgs, dsts, &mut u)?; + Ok(u[0]) + } +} diff --git a/src/rust/vendor/elliptic-curve/src/hash2curve/hash2field.rs b/src/rust/vendor/elliptic-curve/src/hash2curve/hash2field.rs new file mode 100644 index 000000000..67ede111c --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/hash2curve/hash2field.rs @@ -0,0 +1,48 @@ +//! Traits for hashing to field elements. +//! +//! + +mod expand_msg; + +pub use expand_msg::{xmd::*, xof::*, *}; + +use crate::{Error, Result}; +use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; + +/// The trait for helping to convert to a field element. +pub trait FromOkm { + /// The number of bytes needed to convert to a field element. + type Length: ArrayLength; + + /// Convert a byte sequence into a field element. + fn from_okm(data: &GenericArray) -> Self; +} + +/// Convert an arbitrary byte sequence into a field element. +/// +/// +/// +/// # Errors +/// See implementors of [`ExpandMsg`] for errors: +/// - [`ExpandMsgXmd`] +/// - [`ExpandMsgXof`] +/// +/// `len_in_bytes = T::Length * out.len()` +/// +/// [`ExpandMsgXmd`]: crate::hash2field::ExpandMsgXmd +/// [`ExpandMsgXof`]: crate::hash2field::ExpandMsgXof +#[doc(hidden)] +pub fn hash_to_field<'a, E, T>(data: &[&[u8]], domain: &'a [&'a [u8]], out: &mut [T]) -> Result<()> +where + E: ExpandMsg<'a>, + T: FromOkm + Default, +{ + let len_in_bytes = T::Length::to_usize().checked_mul(out.len()).ok_or(Error)?; + let mut tmp = GenericArray::::Length>::default(); + let mut expander = E::expand_message(data, domain, len_in_bytes)?; + for o in out.iter_mut() { + expander.fill_bytes(&mut tmp); + *o = T::from_okm(&tmp); + } + Ok(()) +} diff --git a/src/rust/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg.rs b/src/rust/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg.rs new file mode 100644 index 000000000..96a659b9a --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg.rs @@ -0,0 +1,145 @@ +//! `expand_message` interface `for hash_to_field`. + +pub(super) mod xmd; +pub(super) mod xof; + +use crate::{Error, Result}; +use digest::{Digest, ExtendableOutput, Update, XofReader}; +use generic_array::typenum::{IsLess, U256}; +use generic_array::{ArrayLength, GenericArray}; + +/// Salt when the DST is too long +const OVERSIZE_DST_SALT: &[u8] = b"H2C-OVERSIZE-DST-"; +/// Maximum domain separation tag length +const MAX_DST_LEN: usize = 255; + +/// Trait for types implementing expand_message interface for `hash_to_field`. +/// +/// # Errors +/// See implementors of [`ExpandMsg`] for errors. +pub trait ExpandMsg<'a> { + /// Type holding data for the [`Expander`]. + type Expander: Expander + Sized; + + /// Expands `msg` to the required number of bytes. + /// + /// Returns an expander that can be used to call `read` until enough + /// bytes have been consumed + fn expand_message( + msgs: &[&[u8]], + dsts: &'a [&'a [u8]], + len_in_bytes: usize, + ) -> Result; +} + +/// Expander that, call `read` until enough bytes have been consumed. +pub trait Expander { + /// Fill the array with the expanded bytes + fn fill_bytes(&mut self, okm: &mut [u8]); +} + +/// The domain separation tag +/// +/// Implements [section 5.4.3 of `draft-irtf-cfrg-hash-to-curve-13`][dst]. +/// +/// [dst]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-13#section-5.4.3 +pub(crate) enum Domain<'a, L> +where + L: ArrayLength + IsLess, +{ + /// > 255 + Hashed(GenericArray), + /// <= 255 + Array(&'a [&'a [u8]]), +} + +impl<'a, L> Domain<'a, L> +where + L: ArrayLength + IsLess, +{ + pub fn xof(dsts: &'a [&'a [u8]]) -> Result + where + X: Default + ExtendableOutput + Update, + { + if dsts.is_empty() { + Err(Error) + } else if dsts.iter().map(|dst| dst.len()).sum::() > MAX_DST_LEN { + let mut data = GenericArray::::default(); + let mut hash = X::default(); + hash.update(OVERSIZE_DST_SALT); + + for dst in dsts { + hash.update(dst); + } + + hash.finalize_xof().read(&mut data); + + Ok(Self::Hashed(data)) + } else { + Ok(Self::Array(dsts)) + } + } + + pub fn xmd(dsts: &'a [&'a [u8]]) -> Result + where + X: Digest, + { + if dsts.is_empty() { + Err(Error) + } else if dsts.iter().map(|dst| dst.len()).sum::() > MAX_DST_LEN { + Ok(Self::Hashed({ + let mut hash = X::new(); + hash.update(OVERSIZE_DST_SALT); + + for dst in dsts { + hash.update(dst); + } + + hash.finalize() + })) + } else { + Ok(Self::Array(dsts)) + } + } + + pub fn update_hash(&self, hash: &mut HashT) { + match self { + Self::Hashed(d) => hash.update(d), + Self::Array(d) => { + for d in d.iter() { + hash.update(d) + } + } + } + } + + pub fn len(&self) -> u8 { + match self { + // Can't overflow because it's enforced on a type level. + Self::Hashed(_) => L::to_u8(), + // Can't overflow because it's checked on creation. + Self::Array(d) => { + u8::try_from(d.iter().map(|d| d.len()).sum::()).expect("length overflow") + } + } + } + + #[cfg(test)] + pub fn assert(&self, bytes: &[u8]) { + let data = match self { + Domain::Hashed(d) => d.to_vec(), + Domain::Array(d) => d.iter().copied().flatten().copied().collect(), + }; + assert_eq!(data, bytes); + } + + #[cfg(test)] + pub fn assert_dst(&self, bytes: &[u8]) { + let data = match self { + Domain::Hashed(d) => d.to_vec(), + Domain::Array(d) => d.iter().copied().flatten().copied().collect(), + }; + assert_eq!(data, &bytes[..bytes.len() - 1]); + assert_eq!(self.len(), bytes[bytes.len() - 1]); + } +} diff --git a/src/rust/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xmd.rs b/src/rust/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xmd.rs new file mode 100644 index 000000000..9cbd69832 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xmd.rs @@ -0,0 +1,451 @@ +//! `expand_message_xmd` based on a hash function. + +use core::marker::PhantomData; + +use super::{Domain, ExpandMsg, Expander}; +use crate::{Error, Result}; +use digest::{ + core_api::BlockSizeUser, + generic_array::{ + typenum::{IsLess, IsLessOrEqual, Unsigned, U256}, + GenericArray, + }, + FixedOutput, HashMarker, +}; + +/// Placeholder type for implementing `expand_message_xmd` based on a hash function +/// +/// # Errors +/// - `dst.is_empty()` +/// - `len_in_bytes == 0` +/// - `len_in_bytes > u16::MAX` +/// - `len_in_bytes > 255 * HashT::OutputSize` +pub struct ExpandMsgXmd(PhantomData) +where + HashT: BlockSizeUser + Default + FixedOutput + HashMarker, + HashT::OutputSize: IsLess, + HashT::OutputSize: IsLessOrEqual; + +/// ExpandMsgXmd implements expand_message_xmd for the ExpandMsg trait +impl<'a, HashT> ExpandMsg<'a> for ExpandMsgXmd +where + HashT: BlockSizeUser + Default + FixedOutput + HashMarker, + // If `len_in_bytes` is bigger then 256, length of the `DST` will depend on + // the output size of the hash, which is still not allowed to be bigger then 256: + // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#section-5.4.1-6 + HashT::OutputSize: IsLess, + // Constraint set by `expand_message_xmd`: + // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#section-5.4.1-4 + HashT::OutputSize: IsLessOrEqual, +{ + type Expander = ExpanderXmd<'a, HashT>; + + fn expand_message( + msgs: &[&[u8]], + dsts: &'a [&'a [u8]], + len_in_bytes: usize, + ) -> Result { + if len_in_bytes == 0 { + return Err(Error); + } + + let len_in_bytes_u16 = u16::try_from(len_in_bytes).map_err(|_| Error)?; + + let b_in_bytes = HashT::OutputSize::to_usize(); + let ell = u8::try_from((len_in_bytes + b_in_bytes - 1) / b_in_bytes).map_err(|_| Error)?; + + let domain = Domain::xmd::(dsts)?; + let mut b_0 = HashT::default(); + b_0.update(&GenericArray::::default()); + + for msg in msgs { + b_0.update(msg); + } + + b_0.update(&len_in_bytes_u16.to_be_bytes()); + b_0.update(&[0]); + domain.update_hash(&mut b_0); + b_0.update(&[domain.len()]); + let b_0 = b_0.finalize_fixed(); + + let mut b_vals = HashT::default(); + b_vals.update(&b_0[..]); + b_vals.update(&[1u8]); + domain.update_hash(&mut b_vals); + b_vals.update(&[domain.len()]); + let b_vals = b_vals.finalize_fixed(); + + Ok(ExpanderXmd { + b_0, + b_vals, + domain, + index: 1, + offset: 0, + ell, + }) + } +} + +/// [`Expander`] type for [`ExpandMsgXmd`]. +pub struct ExpanderXmd<'a, HashT> +where + HashT: BlockSizeUser + Default + FixedOutput + HashMarker, + HashT::OutputSize: IsLess, + HashT::OutputSize: IsLessOrEqual, +{ + b_0: GenericArray, + b_vals: GenericArray, + domain: Domain<'a, HashT::OutputSize>, + index: u8, + offset: usize, + ell: u8, +} + +impl<'a, HashT> ExpanderXmd<'a, HashT> +where + HashT: BlockSizeUser + Default + FixedOutput + HashMarker, + HashT::OutputSize: IsLess, + HashT::OutputSize: IsLessOrEqual, +{ + fn next(&mut self) -> bool { + if self.index < self.ell { + self.index += 1; + self.offset = 0; + // b_0 XOR b_(idx - 1) + let mut tmp = GenericArray::::default(); + self.b_0 + .iter() + .zip(&self.b_vals[..]) + .enumerate() + .for_each(|(j, (b0val, bi1val))| tmp[j] = b0val ^ bi1val); + let mut b_vals = HashT::default(); + b_vals.update(&tmp); + b_vals.update(&[self.index]); + self.domain.update_hash(&mut b_vals); + b_vals.update(&[self.domain.len()]); + self.b_vals = b_vals.finalize_fixed(); + true + } else { + false + } + } +} + +impl<'a, HashT> Expander for ExpanderXmd<'a, HashT> +where + HashT: BlockSizeUser + Default + FixedOutput + HashMarker, + HashT::OutputSize: IsLess, + HashT::OutputSize: IsLessOrEqual, +{ + fn fill_bytes(&mut self, okm: &mut [u8]) { + for b in okm { + if self.offset == self.b_vals.len() && !self.next() { + return; + } + *b = self.b_vals[self.offset]; + self.offset += 1; + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use core::mem; + use generic_array::{ + typenum::{U128, U32}, + ArrayLength, + }; + use hex_literal::hex; + use sha2::Sha256; + + fn assert_message( + msg: &[u8], + domain: &Domain<'_, HashT::OutputSize>, + len_in_bytes: u16, + bytes: &[u8], + ) where + HashT: BlockSizeUser + Default + FixedOutput + HashMarker, + HashT::OutputSize: IsLess, + { + let block = HashT::BlockSize::to_usize(); + assert_eq!( + GenericArray::::default().as_slice(), + &bytes[..block] + ); + + let msg_len = block + msg.len(); + assert_eq!(msg, &bytes[block..msg_len]); + + let l = msg_len + mem::size_of::(); + assert_eq!(len_in_bytes.to_be_bytes(), &bytes[msg_len..l]); + + let pad = l + mem::size_of::(); + assert_eq!([0], &bytes[l..pad]); + + let dst = pad + usize::from(domain.len()); + domain.assert(&bytes[pad..dst]); + + let dst_len = dst + mem::size_of::(); + assert_eq!([domain.len()], &bytes[dst..dst_len]); + + assert_eq!(dst_len, bytes.len()); + } + + struct TestVector { + msg: &'static [u8], + msg_prime: &'static [u8], + uniform_bytes: &'static [u8], + } + + impl TestVector { + #[allow(clippy::panic_in_result_fn)] + fn assert>( + &self, + dst: &'static [u8], + domain: &Domain<'_, HashT::OutputSize>, + ) -> Result<()> + where + HashT: BlockSizeUser + Default + FixedOutput + HashMarker, + HashT::OutputSize: IsLess + IsLessOrEqual, + { + assert_message::(self.msg, domain, L::to_u16(), self.msg_prime); + + let dst = [dst]; + let mut expander = + ExpandMsgXmd::::expand_message(&[self.msg], &dst, L::to_usize())?; + + let mut uniform_bytes = GenericArray::::default(); + expander.fill_bytes(&mut uniform_bytes); + + assert_eq!(uniform_bytes.as_slice(), self.uniform_bytes); + Ok(()) + } + } + + #[test] + fn expand_message_xmd_sha_256() -> Result<()> { + const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHA256-128"; + const DST_PRIME: &[u8] = + &hex!("515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"); + + let dst_prime = Domain::xmd::(&[DST])?; + dst_prime.assert_dst(DST_PRIME); + + const TEST_VECTORS_32: &[TestVector] = &[ + TestVector { + msg: b"", + msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), + uniform_bytes: &hex!("68a985b87eb6b46952128911f2a4412bbc302a9d759667f87f7a21d803f07235"), + }, + TestVector { + msg: b"abc", + msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), + uniform_bytes: &hex!("d8ccab23b5985ccea865c6c97b6e5b8350e794e603b4b97902f53a8a0d605615"), + }, + TestVector { + msg: b"abcdef0123456789", + msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), + uniform_bytes: &hex!("eff31487c770a893cfb36f912fbfcbff40d5661771ca4b2cb4eafe524333f5c1"), + }, + TestVector { + msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), + uniform_bytes: &hex!("b23a1d2b4d97b2ef7785562a7e8bac7eed54ed6e97e29aa51bfe3f12ddad1ff9"), + }, + TestVector { + msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), + uniform_bytes: &hex!("4623227bcc01293b8c130bf771da8c298dede7383243dc0993d2d94823958c4c"), + }, + ]; + + for test_vector in TEST_VECTORS_32 { + test_vector.assert::(DST, &dst_prime)?; + } + + const TEST_VECTORS_128: &[TestVector] = &[ + TestVector { + msg: b"", + msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), + uniform_bytes: &hex!("af84c27ccfd45d41914fdff5df25293e221afc53d8ad2ac06d5e3e29485dadbee0d121587713a3e0dd4d5e69e93eb7cd4f5df4cd103e188cf60cb02edc3edf18eda8576c412b18ffb658e3dd6ec849469b979d444cf7b26911a08e63cf31f9dcc541708d3491184472c2c29bb749d4286b004ceb5ee6b9a7fa5b646c993f0ced"), + }, TestVector { + msg: b"abc", + msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), + uniform_bytes: &hex!("abba86a6129e366fc877aab32fc4ffc70120d8996c88aee2fe4b32d6c7b6437a647e6c3163d40b76a73cf6a5674ef1d890f95b664ee0afa5359a5c4e07985635bbecbac65d747d3d2da7ec2b8221b17b0ca9dc8a1ac1c07ea6a1e60583e2cb00058e77b7b72a298425cd1b941ad4ec65e8afc50303a22c0f99b0509b4c895f40"), + }, TestVector { + msg: b"abcdef0123456789", + msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), + uniform_bytes: &hex!("ef904a29bffc4cf9ee82832451c946ac3c8f8058ae97d8d629831a74c6572bd9ebd0df635cd1f208e2038e760c4994984ce73f0d55ea9f22af83ba4734569d4bc95e18350f740c07eef653cbb9f87910d833751825f0ebefa1abe5420bb52be14cf489b37fe1a72f7de2d10be453b2c9d9eb20c7e3f6edc5a60629178d9478df"), + }, TestVector { + msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), + uniform_bytes: &hex!("80be107d0884f0d881bb460322f0443d38bd222db8bd0b0a5312a6fedb49c1bbd88fd75d8b9a09486c60123dfa1d73c1cc3169761b17476d3c6b7cbbd727acd0e2c942f4dd96ae3da5de368d26b32286e32de7e5a8cb2949f866a0b80c58116b29fa7fabb3ea7d520ee603e0c25bcaf0b9a5e92ec6a1fe4e0391d1cdbce8c68a"), + }, TestVector { + msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), + uniform_bytes: &hex!("546aff5444b5b79aa6148bd81728704c32decb73a3ba76e9e75885cad9def1d06d6792f8a7d12794e90efed817d96920d728896a4510864370c207f99bd4a608ea121700ef01ed879745ee3e4ceef777eda6d9e5e38b90c86ea6fb0b36504ba4a45d22e86f6db5dd43d98a294bebb9125d5b794e9d2a81181066eb954966a487"), + }, + ]; + + for test_vector in TEST_VECTORS_128 { + test_vector.assert::(DST, &dst_prime)?; + } + + Ok(()) + } + + #[test] + fn expand_message_xmd_sha_256_long() -> Result<()> { + const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHA256-128-long-DST-1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"; + const DST_PRIME: &[u8] = + &hex!("412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"); + + let dst_prime = Domain::xmd::(&[DST])?; + dst_prime.assert_dst(DST_PRIME); + + const TEST_VECTORS_32: &[TestVector] = &[ + TestVector { + msg: b"", + msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), + uniform_bytes: &hex!("e8dc0c8b686b7ef2074086fbdd2f30e3f8bfbd3bdf177f73f04b97ce618a3ed3"), + }, + TestVector { + msg: b"abc", + msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), + uniform_bytes: &hex!("52dbf4f36cf560fca57dedec2ad924ee9c266341d8f3d6afe5171733b16bbb12"), + }, + TestVector { + msg: b"abcdef0123456789", + msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), + uniform_bytes: &hex!("35387dcf22618f3728e6c686490f8b431f76550b0b2c61cbc1ce7001536f4521"), + }, + TestVector { + msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), + uniform_bytes: &hex!("01b637612bb18e840028be900a833a74414140dde0c4754c198532c3a0ba42bc"), + }, + TestVector { + msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), + uniform_bytes: &hex!("20cce7033cabc5460743180be6fa8aac5a103f56d481cf369a8accc0c374431b"), + }, + ]; + + for test_vector in TEST_VECTORS_32 { + test_vector.assert::(DST, &dst_prime)?; + } + + const TEST_VECTORS_128: &[TestVector] = &[ + TestVector { + msg: b"", + msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), + uniform_bytes: &hex!("14604d85432c68b757e485c8894db3117992fc57e0e136f71ad987f789a0abc287c47876978e2388a02af86b1e8d1342e5ce4f7aaa07a87321e691f6fba7e0072eecc1218aebb89fb14a0662322d5edbd873f0eb35260145cd4e64f748c5dfe60567e126604bcab1a3ee2dc0778102ae8a5cfd1429ebc0fa6bf1a53c36f55dfc"), + }, + TestVector { + msg: b"abc", + msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), + uniform_bytes: &hex!("1a30a5e36fbdb87077552b9d18b9f0aee16e80181d5b951d0471d55b66684914aef87dbb3626eaabf5ded8cd0686567e503853e5c84c259ba0efc37f71c839da2129fe81afdaec7fbdc0ccd4c794727a17c0d20ff0ea55e1389d6982d1241cb8d165762dbc39fb0cee4474d2cbbd468a835ae5b2f20e4f959f56ab24cd6fe267"), + }, + TestVector { + msg: b"abcdef0123456789", + msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), + uniform_bytes: &hex!("d2ecef3635d2397f34a9f86438d772db19ffe9924e28a1caf6f1c8f15603d4028f40891044e5c7e39ebb9b31339979ff33a4249206f67d4a1e7c765410bcd249ad78d407e303675918f20f26ce6d7027ed3774512ef5b00d816e51bfcc96c3539601fa48ef1c07e494bdc37054ba96ecb9dbd666417e3de289d4f424f502a982"), + }, + TestVector { + msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), + uniform_bytes: &hex!("ed6e8c036df90111410431431a232d41a32c86e296c05d426e5f44e75b9a50d335b2412bc6c91e0a6dc131de09c43110d9180d0a70f0d6289cb4e43b05f7ee5e9b3f42a1fad0f31bac6a625b3b5c50e3a83316783b649e5ecc9d3b1d9471cb5024b7ccf40d41d1751a04ca0356548bc6e703fca02ab521b505e8e45600508d32"), + }, + TestVector { + msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), + uniform_bytes: &hex!("78b53f2413f3c688f07732c10e5ced29a17c6a16f717179ffbe38d92d6c9ec296502eb9889af83a1928cd162e845b0d3c5424e83280fed3d10cffb2f8431f14e7a23f4c68819d40617589e4c41169d0b56e0e3535be1fd71fbb08bb70c5b5ffed953d6c14bf7618b35fc1f4c4b30538236b4b08c9fbf90462447a8ada60be495"), + }, + ]; + + for test_vector in TEST_VECTORS_128 { + test_vector.assert::(DST, &dst_prime)?; + } + + Ok(()) + } + + #[test] + fn expand_message_xmd_sha_512() -> Result<()> { + use sha2::Sha512; + + const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHA512-256"; + const DST_PRIME: &[u8] = + &hex!("515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"); + + let dst_prime = Domain::xmd::(&[DST])?; + dst_prime.assert_dst(DST_PRIME); + + const TEST_VECTORS_32: &[TestVector] = &[ + TestVector { + msg: b"", + msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), + uniform_bytes: &hex!("6b9a7312411d92f921c6f68ca0b6380730a1a4d982c507211a90964c394179ba"), + }, + TestVector { + msg: b"abc", + msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), + uniform_bytes: &hex!("0da749f12fbe5483eb066a5f595055679b976e93abe9be6f0f6318bce7aca8dc"), + }, + TestVector { + msg: b"abcdef0123456789", + msg_prime: &hex!("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), + uniform_bytes: &hex!("087e45a86e2939ee8b91100af1583c4938e0f5fc6c9db4b107b83346bc967f58"), + }, + TestVector { + msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), + uniform_bytes: &hex!("7336234ee9983902440f6bc35b348352013becd88938d2afec44311caf8356b3"), + }, + TestVector { + msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), + uniform_bytes: &hex!("57b5f7e766d5be68a6bfe1768e3c2b7f1228b3e4b3134956dd73a59b954c66f4"), + }, + ]; + + for test_vector in TEST_VECTORS_32 { + test_vector.assert::(DST, &dst_prime)?; + } + + const TEST_VECTORS_128: &[TestVector] = &[ + TestVector { + msg: b"", + msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), + uniform_bytes: &hex!("41b037d1734a5f8df225dd8c7de38f851efdb45c372887be655212d07251b921b052b62eaed99b46f72f2ef4cc96bfaf254ebbbec091e1a3b9e4fb5e5b619d2e0c5414800a1d882b62bb5cd1778f098b8eb6cb399d5d9d18f5d5842cf5d13d7eb00a7cff859b605da678b318bd0e65ebff70bec88c753b159a805d2c89c55961"), + }, + TestVector { + msg: b"abc", + msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), + uniform_bytes: &hex!("7f1dddd13c08b543f2e2037b14cefb255b44c83cc397c1786d975653e36a6b11bdd7732d8b38adb4a0edc26a0cef4bb45217135456e58fbca1703cd6032cb1347ee720b87972d63fbf232587043ed2901bce7f22610c0419751c065922b488431851041310ad659e4b23520e1772ab29dcdeb2002222a363f0c2b1c972b3efe1"), + }, + TestVector { + msg: b"abcdef0123456789", + msg_prime: &hex!("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), + uniform_bytes: &hex!("3f721f208e6199fe903545abc26c837ce59ac6fa45733f1baaf0222f8b7acb0424814fcb5eecf6c1d38f06e9d0a6ccfbf85ae612ab8735dfdf9ce84c372a77c8f9e1c1e952c3a61b7567dd0693016af51d2745822663d0c2367e3f4f0bed827feecc2aaf98c949b5ed0d35c3f1023d64ad1407924288d366ea159f46287e61ac"), + }, + TestVector { + msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), + uniform_bytes: &hex!("b799b045a58c8d2b4334cf54b78260b45eec544f9f2fb5bd12fb603eaee70db7317bf807c406e26373922b7b8920fa29142703dd52bdf280084fb7ef69da78afdf80b3586395b433dc66cde048a258e476a561e9deba7060af40adf30c64249ca7ddea79806ee5beb9a1422949471d267b21bc88e688e4014087a0b592b695ed"), + }, + TestVector { + msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), + uniform_bytes: &hex!("05b0bfef265dcee87654372777b7c44177e2ae4c13a27f103340d9cd11c86cb2426ffcad5bd964080c2aee97f03be1ca18e30a1f14e27bc11ebbd650f305269cc9fb1db08bf90bfc79b42a952b46daf810359e7bc36452684784a64952c343c52e5124cd1f71d474d5197fefc571a92929c9084ffe1112cf5eea5192ebff330b"), + }, + ]; + + for test_vector in TEST_VECTORS_128 { + test_vector.assert::(DST, &dst_prime)?; + } + + Ok(()) + } +} diff --git a/src/rust/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xof.rs b/src/rust/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xof.rs new file mode 100644 index 000000000..7ffed126b --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xof.rs @@ -0,0 +1,348 @@ +//! `expand_message_xof` for the `ExpandMsg` trait + +use super::{Domain, ExpandMsg, Expander}; +use crate::{Error, Result}; +use digest::{ExtendableOutput, Update, XofReader}; +use generic_array::typenum::U32; + +/// Placeholder type for implementing `expand_message_xof` based on an extendable output function +/// +/// # Errors +/// - `dst.is_empty()` +/// - `len_in_bytes == 0` +/// - `len_in_bytes > u16::MAX` +pub struct ExpandMsgXof +where + HashT: Default + ExtendableOutput + Update, +{ + reader: ::Reader, +} + +/// ExpandMsgXof implements `expand_message_xof` for the [`ExpandMsg`] trait +impl<'a, HashT> ExpandMsg<'a> for ExpandMsgXof +where + HashT: Default + ExtendableOutput + Update, +{ + type Expander = Self; + + fn expand_message( + msgs: &[&[u8]], + dsts: &'a [&'a [u8]], + len_in_bytes: usize, + ) -> Result { + if len_in_bytes == 0 { + return Err(Error); + } + + let len_in_bytes = u16::try_from(len_in_bytes).map_err(|_| Error)?; + + let domain = Domain::::xof::(dsts)?; + let mut reader = HashT::default(); + + for msg in msgs { + reader = reader.chain(msg); + } + + reader.update(&len_in_bytes.to_be_bytes()); + domain.update_hash(&mut reader); + reader.update(&[domain.len()]); + let reader = reader.finalize_xof(); + Ok(Self { reader }) + } +} + +impl Expander for ExpandMsgXof +where + HashT: Default + ExtendableOutput + Update, +{ + fn fill_bytes(&mut self, okm: &mut [u8]) { + self.reader.read(okm); + } +} + +#[cfg(test)] +mod test { + use super::*; + use core::mem; + use generic_array::{ + typenum::{U128, U32}, + ArrayLength, GenericArray, + }; + use hex_literal::hex; + use sha3::Shake128; + + fn assert_message(msg: &[u8], domain: &Domain<'_, U32>, len_in_bytes: u16, bytes: &[u8]) { + let msg_len = msg.len(); + assert_eq!(msg, &bytes[..msg_len]); + + let len_in_bytes_len = msg_len + mem::size_of::(); + assert_eq!( + len_in_bytes.to_be_bytes(), + &bytes[msg_len..len_in_bytes_len] + ); + + let dst = len_in_bytes_len + usize::from(domain.len()); + domain.assert(&bytes[len_in_bytes_len..dst]); + + let dst_len = dst + mem::size_of::(); + assert_eq!([domain.len()], &bytes[dst..dst_len]); + + assert_eq!(dst_len, bytes.len()); + } + + struct TestVector { + msg: &'static [u8], + msg_prime: &'static [u8], + uniform_bytes: &'static [u8], + } + + impl TestVector { + #[allow(clippy::panic_in_result_fn)] + fn assert(&self, dst: &'static [u8], domain: &Domain<'_, U32>) -> Result<()> + where + HashT: Default + ExtendableOutput + Update, + L: ArrayLength, + { + assert_message(self.msg, domain, L::to_u16(), self.msg_prime); + + let mut expander = + ExpandMsgXof::::expand_message(&[self.msg], &[dst], L::to_usize())?; + + let mut uniform_bytes = GenericArray::::default(); + expander.fill_bytes(&mut uniform_bytes); + + assert_eq!(uniform_bytes.as_slice(), self.uniform_bytes); + Ok(()) + } + } + + #[test] + fn expand_message_xof_shake_128() -> Result<()> { + const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHAKE128"; + const DST_PRIME: &[u8] = + &hex!("515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"); + + let dst_prime = Domain::::xof::(&[DST])?; + dst_prime.assert_dst(DST_PRIME); + + const TEST_VECTORS_32: &[TestVector] = &[ + TestVector { + msg: b"", + msg_prime: &hex!("0020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), + uniform_bytes: &hex!("86518c9cd86581486e9485aa74ab35ba150d1c75c88e26b7043e44e2acd735a2"), + }, + TestVector { + msg: b"abc", + msg_prime: &hex!("6162630020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), + uniform_bytes: &hex!("8696af52a4d862417c0763556073f47bc9b9ba43c99b505305cb1ec04a9ab468"), + }, + TestVector { + msg: b"abcdef0123456789", + msg_prime: &hex!("616263646566303132333435363738390020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), + uniform_bytes: &hex!("912c58deac4821c3509dbefa094df54b34b8f5d01a191d1d3108a2c89077acca"), + }, + TestVector { + msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), + uniform_bytes: &hex!("1adbcc448aef2a0cebc71dac9f756b22e51839d348e031e63b33ebb50faeaf3f"), + }, + TestVector { + msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), + uniform_bytes: &hex!("df3447cc5f3e9a77da10f819218ddf31342c310778e0e4ef72bbaecee786a4fe"), + }, + ]; + + for test_vector in TEST_VECTORS_32 { + test_vector.assert::(DST, &dst_prime)?; + } + + const TEST_VECTORS_128: &[TestVector] = &[ + TestVector { + msg: b"", + msg_prime: &hex!("0080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), + uniform_bytes: &hex!("7314ff1a155a2fb99a0171dc71b89ab6e3b2b7d59e38e64419b8b6294d03ffee42491f11370261f436220ef787f8f76f5b26bdcd850071920ce023f3ac46847744f4612b8714db8f5db83205b2e625d95afd7d7b4d3094d3bdde815f52850bb41ead9822e08f22cf41d615a303b0d9dde73263c049a7b9898208003a739a2e57"), + }, + TestVector { + msg: b"abc", + msg_prime: &hex!("6162630080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), + uniform_bytes: &hex!("c952f0c8e529ca8824acc6a4cab0e782fc3648c563ddb00da7399f2ae35654f4860ec671db2356ba7baa55a34a9d7f79197b60ddae6e64768a37d699a78323496db3878c8d64d909d0f8a7de4927dcab0d3dbbc26cb20a49eceb0530b431cdf47bc8c0fa3e0d88f53b318b6739fbed7d7634974f1b5c386d6230c76260d5337a"), + }, + TestVector { + msg: b"abcdef0123456789", + msg_prime: &hex!("616263646566303132333435363738390080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), + uniform_bytes: &hex!("19b65ee7afec6ac06a144f2d6134f08eeec185f1a890fe34e68f0e377b7d0312883c048d9b8a1d6ecc3b541cb4987c26f45e0c82691ea299b5e6889bbfe589153016d8131717ba26f07c3c14ffbef1f3eff9752e5b6183f43871a78219a75e7000fbac6a7072e2b83c790a3a5aecd9d14be79f9fd4fb180960a3772e08680495"), + }, + TestVector { + msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), + uniform_bytes: &hex!("ca1b56861482b16eae0f4a26212112362fcc2d76dcc80c93c4182ed66c5113fe41733ed68be2942a3487394317f3379856f4822a611735e50528a60e7ade8ec8c71670fec6661e2c59a09ed36386513221688b35dc47e3c3111ee8c67ff49579089d661caa29db1ef10eb6eace575bf3dc9806e7c4016bd50f3c0e2a6481ee6d"), + }, + TestVector { + msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), + uniform_bytes: &hex!("9d763a5ce58f65c91531b4100c7266d479a5d9777ba761693d052acd37d149e7ac91c796a10b919cd74a591a1e38719fb91b7203e2af31eac3bff7ead2c195af7d88b8bc0a8adf3d1e90ab9bed6ddc2b7f655dd86c730bdeaea884e73741097142c92f0e3fc1811b699ba593c7fbd81da288a29d423df831652e3a01a9374999"), + }, + ]; + + for test_vector in TEST_VECTORS_128 { + test_vector.assert::(DST, &dst_prime)?; + } + + Ok(()) + } + + #[test] + fn expand_message_xof_shake_128_long() -> Result<()> { + const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHAKE128-long-DST-111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"; + const DST_PRIME: &[u8] = + &hex!("acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"); + + let dst_prime = Domain::::xof::(&[DST])?; + dst_prime.assert_dst(DST_PRIME); + + const TEST_VECTORS_32: &[TestVector] = &[ + TestVector { + msg: b"", + msg_prime: &hex!("0020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), + uniform_bytes: &hex!("827c6216330a122352312bccc0c8d6e7a146c5257a776dbd9ad9d75cd880fc53"), + }, + TestVector { + msg: b"abc", + msg_prime: &hex!("6162630020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), + uniform_bytes: &hex!("690c8d82c7213b4282c6cb41c00e31ea1d3e2005f93ad19bbf6da40f15790c5c"), + }, + TestVector { + msg: b"abcdef0123456789", + msg_prime: &hex!("616263646566303132333435363738390020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), + uniform_bytes: &hex!("979e3a15064afbbcf99f62cc09fa9c85028afcf3f825eb0711894dcfc2f57057"), + }, + TestVector { + msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), + uniform_bytes: &hex!("c5a9220962d9edc212c063f4f65b609755a1ed96e62f9db5d1fd6adb5a8dc52b"), + }, + TestVector { + msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), + uniform_bytes: &hex!("f7b96a5901af5d78ce1d071d9c383cac66a1dfadb508300ec6aeaea0d62d5d62"), + }, + ]; + + for test_vector in TEST_VECTORS_32 { + test_vector.assert::(DST, &dst_prime)?; + } + + const TEST_VECTORS_128: &[TestVector] = &[ + TestVector { + msg: b"", + msg_prime: &hex!("0080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), + uniform_bytes: &hex!("3890dbab00a2830be398524b71c2713bbef5f4884ac2e6f070b092effdb19208c7df943dc5dcbaee3094a78c267ef276632ee2c8ea0c05363c94b6348500fae4208345dd3475fe0c834c2beac7fa7bc181692fb728c0a53d809fc8111495222ce0f38468b11becb15b32060218e285c57a60162c2c8bb5b6bded13973cd41819"), + }, + TestVector { + msg: b"abc", + msg_prime: &hex!("6162630080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), + uniform_bytes: &hex!("41b7ffa7a301b5c1441495ebb9774e2a53dbbf4e54b9a1af6a20fd41eafd69ef7b9418599c5545b1ee422f363642b01d4a53449313f68da3e49dddb9cd25b97465170537d45dcbdf92391b5bdff344db4bd06311a05bca7dcd360b6caec849c299133e5c9194f4e15e3e23cfaab4003fab776f6ac0bfae9144c6e2e1c62e7d57"), + }, + TestVector { + msg: b"abcdef0123456789", + msg_prime: &hex!("616263646566303132333435363738390080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), + uniform_bytes: &hex!("55317e4a21318472cd2290c3082957e1242241d9e0d04f47026f03401643131401071f01aa03038b2783e795bdfa8a3541c194ad5de7cb9c225133e24af6c86e748deb52e560569bd54ef4dac03465111a3a44b0ea490fb36777ff8ea9f1a8a3e8e0de3cf0880b4b2f8dd37d3a85a8b82375aee4fa0e909f9763319b55778e71"), + }, + TestVector { + msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), + uniform_bytes: &hex!("19fdd2639f082e31c77717ac9bb032a22ff0958382b2dbb39020cdc78f0da43305414806abf9a561cb2d0067eb2f7bc544482f75623438ed4b4e39dd9e6e2909dd858bd8f1d57cd0fce2d3150d90aa67b4498bdf2df98c0100dd1a173436ba5d0df6be1defb0b2ce55ccd2f4fc05eb7cb2c019c35d5398b85adc676da4238bc7"), + }, + TestVector { + msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), + uniform_bytes: &hex!("945373f0b3431a103333ba6a0a34f1efab2702efde41754c4cb1d5216d5b0a92a67458d968562bde7fa6310a83f53dda1383680a276a283438d58ceebfa7ab7ba72499d4a3eddc860595f63c93b1c5e823ea41fc490d938398a26db28f61857698553e93f0574eb8c5017bfed6249491f9976aaa8d23d9485339cc85ca329308"), + }, + ]; + + for test_vector in TEST_VECTORS_128 { + test_vector.assert::(DST, &dst_prime)?; + } + + Ok(()) + } + + #[test] + fn expand_message_xof_shake_256() -> Result<()> { + use sha3::Shake256; + + const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHAKE256"; + const DST_PRIME: &[u8] = + &hex!("515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"); + + let dst_prime = Domain::::xof::(&[DST])?; + dst_prime.assert_dst(DST_PRIME); + + const TEST_VECTORS_32: &[TestVector] = &[ + TestVector { + msg: b"", + msg_prime: &hex!("0020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), + uniform_bytes: &hex!("2ffc05c48ed32b95d72e807f6eab9f7530dd1c2f013914c8fed38c5ccc15ad76"), + }, + TestVector { + msg: b"abc", + msg_prime: &hex!("6162630020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), + uniform_bytes: &hex!("b39e493867e2767216792abce1f2676c197c0692aed061560ead251821808e07"), + }, + TestVector { + msg: b"abcdef0123456789", + msg_prime: &hex!("616263646566303132333435363738390020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), + uniform_bytes: &hex!("245389cf44a13f0e70af8665fe5337ec2dcd138890bb7901c4ad9cfceb054b65"), + }, + TestVector { + msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), + uniform_bytes: &hex!("719b3911821e6428a5ed9b8e600f2866bcf23c8f0515e52d6c6c019a03f16f0e"), + }, + TestVector { + msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), + uniform_bytes: &hex!("9181ead5220b1963f1b5951f35547a5ea86a820562287d6ca4723633d17ccbbc"), + }, + ]; + + for test_vector in TEST_VECTORS_32 { + test_vector.assert::(DST, &dst_prime)?; + } + + const TEST_VECTORS_128: &[TestVector] = &[ + TestVector { + msg: b"", + msg_prime: &hex!("0080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), + uniform_bytes: &hex!("7a1361d2d7d82d79e035b8880c5a3c86c5afa719478c007d96e6c88737a3f631dd74a2c88df79a4cb5e5d9f7504957c70d669ec6bfedc31e01e2bacc4ff3fdf9b6a00b17cc18d9d72ace7d6b81c2e481b4f73f34f9a7505dccbe8f5485f3d20c5409b0310093d5d6492dea4e18aa6979c23c8ea5de01582e9689612afbb353df"), + }, + TestVector { + msg: b"abc", + msg_prime: &hex!("6162630080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), + uniform_bytes: &hex!("a54303e6b172909783353ab05ef08dd435a558c3197db0c132134649708e0b9b4e34fb99b92a9e9e28fc1f1d8860d85897a8e021e6382f3eea10577f968ff6df6c45fe624ce65ca25932f679a42a404bc3681efe03fcd45ef73bb3a8f79ba784f80f55ea8a3c367408f30381299617f50c8cf8fbb21d0f1e1d70b0131a7b6fbe"), + }, + TestVector { + msg: b"abcdef0123456789", + msg_prime: &hex!("616263646566303132333435363738390080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), + uniform_bytes: &hex!("e42e4d9538a189316e3154b821c1bafb390f78b2f010ea404e6ac063deb8c0852fcd412e098e231e43427bd2be1330bb47b4039ad57b30ae1fc94e34993b162ff4d695e42d59d9777ea18d3848d9d336c25d2acb93adcad009bcfb9cde12286df267ada283063de0bb1505565b2eb6c90e31c48798ecdc71a71756a9110ff373"), + }, + TestVector { + msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), + uniform_bytes: &hex!("4ac054dda0a38a65d0ecf7afd3c2812300027c8789655e47aecf1ecc1a2426b17444c7482c99e5907afd9c25b991990490bb9c686f43e79b4471a23a703d4b02f23c669737a886a7ec28bddb92c3a98de63ebf878aa363a501a60055c048bea11840c4717beae7eee28c3cfa42857b3d130188571943a7bd747de831bd6444e0"), + }, + TestVector { + msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), + uniform_bytes: &hex!("09afc76d51c2cccbc129c2315df66c2be7295a231203b8ab2dd7f95c2772c68e500bc72e20c602abc9964663b7a03a389be128c56971ce81001a0b875e7fd17822db9d69792ddf6a23a151bf470079c518279aef3e75611f8f828994a9988f4a8a256ddb8bae161e658d5a2a09bcfe839c6396dc06ee5c8ff3c22d3b1f9deb7e"), + }, + ]; + + for test_vector in TEST_VECTORS_128 { + test_vector.assert::(DST, &dst_prime)?; + } + + Ok(()) + } +} diff --git a/src/rust/vendor/elliptic-curve/src/hash2curve/isogeny.rs b/src/rust/vendor/elliptic-curve/src/hash2curve/isogeny.rs new file mode 100644 index 000000000..fc870d010 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/hash2curve/isogeny.rs @@ -0,0 +1,57 @@ +//! Traits for mapping an isogeny to another curve +//! +//! + +use core::ops::{AddAssign, Mul}; +use ff::Field; +use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; + +/// The coefficients for mapping from one isogenous curve to another +pub struct IsogenyCoefficients> { + /// The coefficients for the x numerator + pub xnum: &'static [F], + /// The coefficients for the x denominator + pub xden: &'static [F], + /// The coefficients for the y numerator + pub ynum: &'static [F], + /// The coefficients for the x denominator + pub yden: &'static [F], +} + +/// The [`Isogeny`] methods to map to another curve. +pub trait Isogeny: Field + AddAssign + Mul { + /// The maximum number of coefficients + type Degree: ArrayLength; + /// The isogeny coefficients + const COEFFICIENTS: IsogenyCoefficients; + + /// Map from the isogeny points to the main curve + fn isogeny(x: Self, y: Self) -> (Self, Self) { + let mut xs = GenericArray::::default(); + xs[0] = Self::ONE; + xs[1] = x; + xs[2] = x.square(); + for i in 3..Self::Degree::to_usize() { + xs[i] = xs[i - 1] * x; + } + let x_num = Self::compute_iso(&xs, Self::COEFFICIENTS.xnum); + let x_den = Self::compute_iso(&xs, Self::COEFFICIENTS.xden) + .invert() + .unwrap(); + let y_num = Self::compute_iso(&xs, Self::COEFFICIENTS.ynum) * y; + let y_den = Self::compute_iso(&xs, Self::COEFFICIENTS.yden) + .invert() + .unwrap(); + + (x_num * x_den, y_num * y_den) + } + + /// Compute the ISO transform + fn compute_iso(xxs: &[Self], k: &[Self]) -> Self { + let mut xx = Self::ZERO; + for (xi, ki) in xxs.iter().zip(k.iter()) { + xx += *xi * ki; + } + xx + } +} diff --git a/src/rust/vendor/elliptic-curve/src/hash2curve/map2curve.rs b/src/rust/vendor/elliptic-curve/src/hash2curve/map2curve.rs new file mode 100644 index 000000000..6092e57ba --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/hash2curve/map2curve.rs @@ -0,0 +1,12 @@ +//! Traits for mapping field elements to points on the curve. + +/// Trait for converting field elements into a point +/// via a mapping method like Simplified Shallue-van de Woestijne-Ulas +/// or Elligator +pub trait MapToCurve { + /// The output point + type Output; + + /// Map a field element into a point + fn map_to_curve(&self) -> Self::Output; +} diff --git a/src/rust/vendor/elliptic-curve/src/hash2curve/osswu.rs b/src/rust/vendor/elliptic-curve/src/hash2curve/osswu.rs new file mode 100644 index 000000000..3c3669ac3 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/hash2curve/osswu.rs @@ -0,0 +1,130 @@ +//! Optimized simplified Shallue-van de Woestijne-Ulas methods. +//! +//! + +use ff::Field; +use subtle::Choice; +use subtle::ConditionallySelectable; +use subtle::ConstantTimeEq; + +/// The Optimized Simplified Shallue-van de Woestijne-Ulas parameters +pub struct OsswuMapParams +where + F: Field, +{ + /// The first constant term + pub c1: &'static [u64], + /// The second constant term + pub c2: F, + /// The ISO A variable or Curve A variable + pub map_a: F, + /// The ISO A variable or Curve A variable + pub map_b: F, + /// The Z parameter + pub z: F, +} + +/// Trait for determining the parity of the field +pub trait Sgn0 { + /// Return the parity of the field + /// 1 == negative + /// 0 == non-negative + fn sgn0(&self) -> Choice; +} + +/// The optimized simplified Shallue-van de Woestijne-Ulas method +/// for mapping elliptic curve scalars to affine points. +pub trait OsswuMap: Field + Sgn0 { + /// The OSSWU parameters for mapping the field to affine points. + /// For Weierstrass curves having A==0 or B==0, the parameters + /// should be for isogeny where A≠0 and B≠0. + const PARAMS: OsswuMapParams; + + /// Optimized sqrt_ratio for q = 3 mod 4. + fn sqrt_ratio_3mod4(u: Self, v: Self) -> (Choice, Self) { + // 1. tv1 = v^2 + let tv1 = v.square(); + // 2. tv2 = u * v + let tv2 = u * v; + // 3. tv1 = tv1 * tv2 + let tv1 = tv1 * tv2; + // 4. y1 = tv1^c1 + let y1 = tv1.pow_vartime(Self::PARAMS.c1); + // 5. y1 = y1 * tv2 + let y1 = y1 * tv2; + // 6. y2 = y1 * c2 + let y2 = y1 * Self::PARAMS.c2; + // 7. tv3 = y1^2 + let tv3 = y1.square(); + // 8. tv3 = tv3 * v + let tv3 = tv3 * v; + // 9. isQR = tv3 == u + let is_qr = tv3.ct_eq(&u); + // 10. y = CMOV(y2, y1, isQR) + let y = ConditionallySelectable::conditional_select(&y2, &y1, is_qr); + // 11. return (isQR, y) + (is_qr, y) + } + + /// Convert this field element into an affine point on the elliptic curve + /// returning (X, Y). For Weierstrass curves having A==0 or B==0 + /// the result is a point on an isogeny. + fn osswu(&self) -> (Self, Self) { + // 1. tv1 = u^2 + let tv1 = self.square(); + // 2. tv1 = Z * tv1 + let tv1 = Self::PARAMS.z * tv1; + // 3. tv2 = tv1^2 + let tv2 = tv1.square(); + // 4. tv2 = tv2 + tv1 + let tv2 = tv2 + tv1; + // 5. tv3 = tv2 + 1 + let tv3 = tv2 + Self::ONE; + // 6. tv3 = B * tv3 + let tv3 = Self::PARAMS.map_b * tv3; + // 7. tv4 = CMOV(Z, -tv2, tv2 != 0) + let tv4 = ConditionallySelectable::conditional_select( + &Self::PARAMS.z, + &-tv2, + !Field::is_zero(&tv2), + ); + // 8. tv4 = A * tv4 + let tv4 = Self::PARAMS.map_a * tv4; + // 9. tv2 = tv3^2 + let tv2 = tv3.square(); + // 10. tv6 = tv4^2 + let tv6 = tv4.square(); + // 11. tv5 = A * tv6 + let tv5 = Self::PARAMS.map_a * tv6; + // 12. tv2 = tv2 + tv5 + let tv2 = tv2 + tv5; + // 13. tv2 = tv2 * tv3 + let tv2 = tv2 * tv3; + // 14. tv6 = tv6 * tv4 + let tv6 = tv6 * tv4; + // 15. tv5 = B * tv6 + let tv5 = Self::PARAMS.map_b * tv6; + // 16. tv2 = tv2 + tv5 + let tv2 = tv2 + tv5; + // 17. x = tv1 * tv3 + let x = tv1 * tv3; + // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6) + let (is_gx1_square, y1) = Self::sqrt_ratio_3mod4(tv2, tv6); + // 19. y = tv1 * u + let y = tv1 * self; + // 20. y = y * y1 + let y = y * y1; + // 21. x = CMOV(x, tv3, is_gx1_square) + let x = ConditionallySelectable::conditional_select(&x, &tv3, is_gx1_square); + // 22. y = CMOV(y, y1, is_gx1_square) + let y = ConditionallySelectable::conditional_select(&y, &y1, is_gx1_square); + // 23. e1 = sgn0(u) == sgn0(y) + let e1 = self.sgn0().ct_eq(&y.sgn0()); + // 24. y = CMOV(-y, y, e1) + let y = ConditionallySelectable::conditional_select(&-y, &y, e1); + // 25. x = x / tv4 + let x = x * tv4.invert().unwrap(); + // 26. return (x, y) + (x, y) + } +} diff --git a/src/rust/vendor/elliptic-curve/src/jwk.rs b/src/rust/vendor/elliptic-curve/src/jwk.rs new file mode 100644 index 000000000..58a9e3812 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/jwk.rs @@ -0,0 +1,675 @@ +//! JSON Web Key (JWK) Support. +//! +//! Specified in RFC 7518 Section 6: Cryptographic Algorithms for Keys: +//! + +use crate::{ + sec1::{Coordinates, EncodedPoint, ModulusSize, ValidatePublicKey}, + secret_key::SecretKey, + Curve, Error, FieldBytes, FieldBytesSize, Result, +}; +use alloc::{ + borrow::ToOwned, + format, + string::{String, ToString}, +}; +use base64ct::{Base64UrlUnpadded as Base64Url, Encoding}; +use core::{ + fmt::{self, Debug}, + marker::PhantomData, + str::{self, FromStr}, +}; +use serdect::serde::{de, ser, Deserialize, Serialize}; +use zeroize::{Zeroize, ZeroizeOnDrop}; + +#[cfg(feature = "arithmetic")] +use crate::{ + public_key::PublicKey, + sec1::{FromEncodedPoint, ToEncodedPoint}, + AffinePoint, CurveArithmetic, +}; + +/// Key Type (`kty`) for elliptic curve keys. +pub const EC_KTY: &str = "EC"; + +/// Deserialization error message. +const DE_ERROR_MSG: &str = "struct JwkEcKey with 5 elements"; + +/// Name of the JWK type +const JWK_TYPE_NAME: &str = "JwkEcKey"; + +/// Field names +const FIELDS: &[&str] = &["kty", "crv", "x", "y", "d"]; + +/// Elliptic curve parameters used by JSON Web Keys. +pub trait JwkParameters: Curve { + /// The `crv` parameter which identifies a particular elliptic curve + /// as defined in RFC 7518 Section 6.2.1.1: + /// + /// + /// Curve values are registered in the IANA "JSON Web Key Elliptic Curve" + /// registry defined in RFC 7518 Section 7.6: + /// + const CRV: &'static str; +} + +/// JSON Web Key (JWK) with a `kty` of `"EC"` (elliptic curve). +/// +/// Specified in [RFC 7518 Section 6: Cryptographic Algorithms for Keys][1]. +/// +/// This type can represent either a public/private keypair, or just a +/// public key, depending on whether or not the `d` parameter is present. +/// +/// [1]: https://tools.ietf.org/html/rfc7518#section-6 +// TODO(tarcieri): eagerly decode or validate `x`, `y`, and `d` as Base64 +#[derive(Clone)] +pub struct JwkEcKey { + /// The `crv` parameter which identifies a particular elliptic curve + /// as defined in RFC 7518 Section 6.2.1.1: + /// + crv: String, + + /// The x-coordinate of the elliptic curve point which is the public key + /// value associated with this JWK as defined in RFC 7518 6.2.1.2: + /// + x: String, + + /// The y-coordinate of the elliptic curve point which is the public key + /// value associated with this JWK as defined in RFC 7518 6.2.1.3: + /// + y: String, + + /// The `d` ECC private key parameter as described in RFC 7518 6.2.2.1: + /// + /// + /// Value is optional and if omitted, this JWK represents a private key. + /// + /// Inner value is encoded according to the `Integer-to-Octet-String` + /// conversion as defined in SEC1 section 2.3.7: + /// + d: Option, +} + +impl JwkEcKey { + /// Get the `crv` parameter for this JWK. + pub fn crv(&self) -> &str { + &self.crv + } + + /// Is this JWK a keypair that includes a private key? + pub fn is_keypair(&self) -> bool { + self.d.is_some() + } + + /// Does this JWK contain only a public key? + pub fn is_public_key(&self) -> bool { + self.d.is_none() + } + + /// Decode a JWK into a [`PublicKey`]. + #[cfg(feature = "arithmetic")] + pub fn to_public_key(&self) -> Result> + where + C: CurveArithmetic + JwkParameters, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, + { + PublicKey::from_sec1_bytes(self.to_encoded_point::()?.as_bytes()) + } + + /// Create a JWK from a SEC1 [`EncodedPoint`]. + pub fn from_encoded_point(point: &EncodedPoint) -> Option + where + C: Curve + JwkParameters, + FieldBytesSize: ModulusSize, + { + match point.coordinates() { + Coordinates::Uncompressed { x, y } => Some(JwkEcKey { + crv: C::CRV.to_owned(), + x: Base64Url::encode_string(x), + y: Base64Url::encode_string(y), + d: None, + }), + _ => None, + } + } + + /// Get the public key component of this JWK as a SEC1 [`EncodedPoint`]. + pub fn to_encoded_point(&self) -> Result> + where + C: Curve + JwkParameters, + FieldBytesSize: ModulusSize, + { + if self.crv != C::CRV { + return Err(Error); + } + + let x = decode_base64url_fe::(&self.x)?; + let y = decode_base64url_fe::(&self.y)?; + Ok(EncodedPoint::::from_affine_coordinates(&x, &y, false)) + } + + /// Decode a JWK into a [`SecretKey`]. + #[cfg(feature = "arithmetic")] + pub fn to_secret_key(&self) -> Result> + where + C: Curve + JwkParameters + ValidatePublicKey, + FieldBytesSize: ModulusSize, + { + self.try_into() + } +} + +impl FromStr for JwkEcKey { + type Err = Error; + + fn from_str(s: &str) -> Result { + serde_json::from_str(s).map_err(|_| Error) + } +} + +impl ToString for JwkEcKey { + fn to_string(&self) -> String { + serde_json::to_string(self).expect("JWK encoding error") + } +} + +impl TryFrom for SecretKey +where + C: Curve + JwkParameters + ValidatePublicKey, + FieldBytesSize: ModulusSize, +{ + type Error = Error; + + fn try_from(jwk: JwkEcKey) -> Result> { + (&jwk).try_into() + } +} + +impl TryFrom<&JwkEcKey> for SecretKey +where + C: Curve + JwkParameters + ValidatePublicKey, + FieldBytesSize: ModulusSize, +{ + type Error = Error; + + fn try_from(jwk: &JwkEcKey) -> Result> { + if let Some(d_base64) = &jwk.d { + let pk = jwk.to_encoded_point::()?; + let mut d_bytes = decode_base64url_fe::(d_base64)?; + let result = SecretKey::from_slice(&d_bytes); + d_bytes.zeroize(); + + result.and_then(|secret_key| { + C::validate_public_key(&secret_key, &pk)?; + Ok(secret_key) + }) + } else { + Err(Error) + } + } +} + +#[cfg(feature = "arithmetic")] +impl From> for JwkEcKey +where + C: CurveArithmetic + JwkParameters, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + fn from(sk: SecretKey) -> JwkEcKey { + (&sk).into() + } +} + +#[cfg(feature = "arithmetic")] +impl From<&SecretKey> for JwkEcKey +where + C: CurveArithmetic + JwkParameters, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + fn from(sk: &SecretKey) -> JwkEcKey { + let mut jwk = sk.public_key().to_jwk(); + let mut d = sk.to_bytes(); + jwk.d = Some(Base64Url::encode_string(&d)); + d.zeroize(); + jwk + } +} + +#[cfg(feature = "arithmetic")] +impl TryFrom for PublicKey +where + C: CurveArithmetic + JwkParameters, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + type Error = Error; + + fn try_from(jwk: JwkEcKey) -> Result> { + (&jwk).try_into() + } +} + +#[cfg(feature = "arithmetic")] +impl TryFrom<&JwkEcKey> for PublicKey +where + C: CurveArithmetic + JwkParameters, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + type Error = Error; + + fn try_from(jwk: &JwkEcKey) -> Result> { + PublicKey::from_sec1_bytes(jwk.to_encoded_point::()?.as_bytes()) + } +} + +#[cfg(feature = "arithmetic")] +impl From> for JwkEcKey +where + C: CurveArithmetic + JwkParameters, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + fn from(pk: PublicKey) -> JwkEcKey { + (&pk).into() + } +} + +#[cfg(feature = "arithmetic")] +impl From<&PublicKey> for JwkEcKey +where + C: CurveArithmetic + JwkParameters, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + fn from(pk: &PublicKey) -> JwkEcKey { + Self::from_encoded_point::(&pk.to_encoded_point(false)).expect("JWK encoding error") + } +} + +impl Debug for JwkEcKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let d = if self.d.is_some() { + "Some(...)" + } else { + "None" + }; + + // NOTE: this implementation omits the `d` private key parameter + f.debug_struct(JWK_TYPE_NAME) + .field("crv", &self.crv) + .field("x", &self.x) + .field("y", &self.y) + .field("d", &d) + .finish() + } +} + +impl PartialEq for JwkEcKey { + fn eq(&self, other: &Self) -> bool { + use subtle::ConstantTimeEq; + + // Compare private key in constant time + let d_eq = match &self.d { + Some(d1) => match &other.d { + Some(d2) => d1.as_bytes().ct_eq(d2.as_bytes()).into(), + None => other.d.is_none(), + }, + None => other.d.is_none(), + }; + + self.crv == other.crv && self.x == other.x && self.y == other.y && d_eq + } +} + +impl Eq for JwkEcKey {} + +impl ZeroizeOnDrop for JwkEcKey {} + +impl Drop for JwkEcKey { + fn drop(&mut self) { + self.zeroize(); + } +} + +impl Zeroize for JwkEcKey { + fn zeroize(&mut self) { + if let Some(d) = &mut self.d { + d.zeroize(); + } + } +} + +impl<'de> Deserialize<'de> for JwkEcKey { + fn deserialize(deserializer: D) -> core::result::Result + where + D: de::Deserializer<'de>, + { + /// Field positions + enum Field { + Kty, + Crv, + X, + Y, + D, + } + + /// Field visitor + struct FieldVisitor; + + impl<'de> de::Visitor<'de> for FieldVisitor { + type Value = Field; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Formatter::write_str(formatter, "field identifier") + } + + fn visit_u64(self, value: u64) -> core::result::Result + where + E: de::Error, + { + match value { + 0 => Ok(Field::Kty), + 1 => Ok(Field::Crv), + 2 => Ok(Field::X), + 3 => Ok(Field::Y), + 4 => Ok(Field::D), + _ => Err(de::Error::invalid_value( + de::Unexpected::Unsigned(value), + &"field index 0 <= i < 5", + )), + } + } + + fn visit_str(self, value: &str) -> core::result::Result + where + E: de::Error, + { + self.visit_bytes(value.as_bytes()) + } + + fn visit_bytes(self, value: &[u8]) -> core::result::Result + where + E: de::Error, + { + match value { + b"kty" => Ok(Field::Kty), + b"crv" => Ok(Field::Crv), + b"x" => Ok(Field::X), + b"y" => Ok(Field::Y), + b"d" => Ok(Field::D), + _ => Err(de::Error::unknown_field( + &String::from_utf8_lossy(value), + FIELDS, + )), + } + } + } + + impl<'de> Deserialize<'de> for Field { + #[inline] + fn deserialize(__deserializer: D) -> core::result::Result + where + D: de::Deserializer<'de>, + { + de::Deserializer::deserialize_identifier(__deserializer, FieldVisitor) + } + } + + struct Visitor<'de> { + marker: PhantomData, + lifetime: PhantomData<&'de ()>, + } + + impl<'de> de::Visitor<'de> for Visitor<'de> { + type Value = JwkEcKey; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Formatter::write_str(formatter, "struct JwkEcKey") + } + + #[inline] + fn visit_seq(self, mut seq: A) -> core::result::Result + where + A: de::SeqAccess<'de>, + { + let kty = de::SeqAccess::next_element::(&mut seq)? + .ok_or_else(|| de::Error::invalid_length(0, &DE_ERROR_MSG))?; + + if kty != EC_KTY { + return Err(de::Error::custom(format!("unsupported JWK kty: {kty:?}"))); + } + + let crv = de::SeqAccess::next_element::(&mut seq)? + .ok_or_else(|| de::Error::invalid_length(1, &DE_ERROR_MSG))?; + + let x = de::SeqAccess::next_element::(&mut seq)? + .ok_or_else(|| de::Error::invalid_length(2, &DE_ERROR_MSG))?; + + let y = de::SeqAccess::next_element::(&mut seq)? + .ok_or_else(|| de::Error::invalid_length(3, &DE_ERROR_MSG))?; + + let d = de::SeqAccess::next_element::>(&mut seq)? + .ok_or_else(|| de::Error::invalid_length(4, &DE_ERROR_MSG))?; + + Ok(JwkEcKey { crv, x, y, d }) + } + + #[inline] + fn visit_map(self, mut map: A) -> core::result::Result + where + A: de::MapAccess<'de>, + { + let mut kty: Option = None; + let mut crv: Option = None; + let mut x: Option = None; + let mut y: Option = None; + let mut d: Option = None; + + while let Some(key) = de::MapAccess::next_key::(&mut map)? { + match key { + Field::Kty => { + if kty.is_none() { + kty = Some(de::MapAccess::next_value::(&mut map)?); + } else { + return Err(de::Error::duplicate_field(FIELDS[0])); + } + } + Field::Crv => { + if crv.is_none() { + crv = Some(de::MapAccess::next_value::(&mut map)?); + } else { + return Err(de::Error::duplicate_field(FIELDS[1])); + } + } + Field::X => { + if x.is_none() { + x = Some(de::MapAccess::next_value::(&mut map)?); + } else { + return Err(de::Error::duplicate_field(FIELDS[2])); + } + } + Field::Y => { + if y.is_none() { + y = Some(de::MapAccess::next_value::(&mut map)?); + } else { + return Err(de::Error::duplicate_field(FIELDS[3])); + } + } + Field::D => { + if d.is_none() { + d = de::MapAccess::next_value::>(&mut map)?; + } else { + return Err(de::Error::duplicate_field(FIELDS[4])); + } + } + } + } + + let kty = kty.ok_or_else(|| de::Error::missing_field("kty"))?; + + if kty != EC_KTY { + return Err(de::Error::custom(format!("unsupported JWK kty: {kty}"))); + } + + let crv = crv.ok_or_else(|| de::Error::missing_field("crv"))?; + let x = x.ok_or_else(|| de::Error::missing_field("x"))?; + let y = y.ok_or_else(|| de::Error::missing_field("y"))?; + + Ok(JwkEcKey { crv, x, y, d }) + } + } + + de::Deserializer::deserialize_struct( + deserializer, + JWK_TYPE_NAME, + FIELDS, + Visitor { + marker: PhantomData::, + lifetime: PhantomData, + }, + ) + } +} + +impl Serialize for JwkEcKey { + fn serialize(&self, serializer: S) -> core::result::Result + where + S: ser::Serializer, + { + use ser::SerializeStruct; + + let mut state = serializer.serialize_struct(JWK_TYPE_NAME, 5)?; + + for (i, field) in [EC_KTY, &self.crv, &self.x, &self.y].iter().enumerate() { + state.serialize_field(FIELDS[i], field)?; + } + + if let Some(d) = &self.d { + state.serialize_field("d", d)?; + } + + ser::SerializeStruct::end(state) + } +} + +/// Decode a Base64url-encoded field element +fn decode_base64url_fe(s: &str) -> Result> { + let mut result = FieldBytes::::default(); + Base64Url::decode(s, &mut result).map_err(|_| Error)?; + Ok(result) +} + +#[cfg(test)] +mod tests { + #![allow(clippy::unwrap_used, clippy::panic)] + use super::*; + + #[cfg(feature = "dev")] + use crate::dev::MockCurve; + + /// Example private key. From RFC 7518 Appendix C: + /// + const JWK_PRIVATE_KEY: &str = r#" + { + "kty":"EC", + "crv":"P-256", + "x":"gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0", + "y":"SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps", + "d":"0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo" + } + "#; + + /// Example public key. + const JWK_PUBLIC_KEY: &str = r#" + { + "kty":"EC", + "crv":"P-256", + "x":"gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0", + "y":"SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps" + } + "#; + + /// Example unsupported JWK (RSA key) + const UNSUPPORTED_JWK: &str = r#" + { + "kty":"RSA", + "kid":"cc34c0a0-bd5a-4a3c-a50d-a2a7db7643df", + "use":"sig", + "n":"pjdss8ZaDfEH6K6U7GeW2nxDqR4IP049fk1fK0lndimbMMVBdPv_hSpm8T8EtBDxrUdi1OHZfMhUixGaut-3nQ4GG9nM249oxhCtxqqNvEXrmQRGqczyLxuh-fKn9Fg--hS9UpazHpfVAFnB5aCfXoNhPuI8oByyFKMKaOVgHNqP5NBEqabiLftZD3W_lsFCPGuzr4Vp0YS7zS2hDYScC2oOMu4rGU1LcMZf39p3153Cq7bS2Xh6Y-vw5pwzFYZdjQxDn8x8BG3fJ6j8TGLXQsbKH1218_HcUJRvMwdpbUQG5nvA2GXVqLqdwp054Lzk9_B_f1lVrmOKuHjTNHq48w", + "e":"AQAB", + "d":"ksDmucdMJXkFGZxiomNHnroOZxe8AmDLDGO1vhs-POa5PZM7mtUPonxwjVmthmpbZzla-kg55OFfO7YcXhg-Hm2OWTKwm73_rLh3JavaHjvBqsVKuorX3V3RYkSro6HyYIzFJ1Ek7sLxbjDRcDOj4ievSX0oN9l-JZhaDYlPlci5uJsoqro_YrE0PRRWVhtGynd-_aWgQv1YzkfZuMD-hJtDi1Im2humOWxA4eZrFs9eG-whXcOvaSwO4sSGbS99ecQZHM2TcdXeAs1PvjVgQ_dKnZlGN3lTWoWfQP55Z7Tgt8Nf1q4ZAKd-NlMe-7iqCFfsnFwXjSiaOa2CRGZn-Q", + "p":"4A5nU4ahEww7B65yuzmGeCUUi8ikWzv1C81pSyUKvKzu8CX41hp9J6oRaLGesKImYiuVQK47FhZ--wwfpRwHvSxtNU9qXb8ewo-BvadyO1eVrIk4tNV543QlSe7pQAoJGkxCia5rfznAE3InKF4JvIlchyqs0RQ8wx7lULqwnn0", + "q":"ven83GM6SfrmO-TBHbjTk6JhP_3CMsIvmSdo4KrbQNvp4vHO3w1_0zJ3URkmkYGhz2tgPlfd7v1l2I6QkIh4Bumdj6FyFZEBpxjE4MpfdNVcNINvVj87cLyTRmIcaGxmfylY7QErP8GFA-k4UoH_eQmGKGK44TRzYj5hZYGWIC8", + "dp":"lmmU_AG5SGxBhJqb8wxfNXDPJjf__i92BgJT2Vp4pskBbr5PGoyV0HbfUQVMnw977RONEurkR6O6gxZUeCclGt4kQlGZ-m0_XSWx13v9t9DIbheAtgVJ2mQyVDvK4m7aRYlEceFh0PsX8vYDS5o1txgPwb3oXkPTtrmbAGMUBpE", + "dq":"mxRTU3QDyR2EnCv0Nl0TCF90oliJGAHR9HJmBe__EjuCBbwHfcT8OG3hWOv8vpzokQPRl5cQt3NckzX3fs6xlJN4Ai2Hh2zduKFVQ2p-AF2p6Yfahscjtq-GY9cB85NxLy2IXCC0PF--Sq9LOrTE9QV988SJy_yUrAjcZ5MmECk", + "qi":"ldHXIrEmMZVaNwGzDF9WG8sHj2mOZmQpw9yrjLK9hAsmsNr5LTyqWAqJIYZSwPTYWhY4nu2O0EY9G9uYiqewXfCKw_UngrJt8Xwfq1Zruz0YY869zPN4GiE9-9rzdZB33RBw8kIOquY3MK74FMwCihYx_LiU2YTHkaoJ3ncvtvg" + } + "#; + + #[test] + fn parse_private_key() { + let jwk = JwkEcKey::from_str(JWK_PRIVATE_KEY).unwrap(); + assert_eq!(jwk.crv, "P-256"); + assert_eq!(jwk.x, "gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0"); + assert_eq!(jwk.y, "SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps"); + assert_eq!( + jwk.d.as_ref().unwrap(), + "0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo" + ); + } + + #[test] + fn parse_public_key() { + let jwk = JwkEcKey::from_str(JWK_PUBLIC_KEY).unwrap(); + assert_eq!(jwk.crv, "P-256"); + assert_eq!(jwk.x, "gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0"); + assert_eq!(jwk.y, "SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps"); + assert_eq!(jwk.d, None); + } + + #[test] + fn parse_unsupported() { + assert_eq!(JwkEcKey::from_str(UNSUPPORTED_JWK), Err(Error)); + } + + #[test] + fn serialize_private_key() { + let actual = JwkEcKey::from_str(JWK_PRIVATE_KEY).unwrap().to_string(); + let expected: String = JWK_PRIVATE_KEY.split_whitespace().collect(); + assert_eq!(actual, expected); + } + + #[test] + fn serialize_public_key() { + let actual = JwkEcKey::from_str(JWK_PUBLIC_KEY).unwrap().to_string(); + let expected: String = JWK_PUBLIC_KEY.split_whitespace().collect(); + assert_eq!(actual, expected); + } + + #[cfg(feature = "dev")] + #[test] + fn jwk_into_encoded_point() { + let jwk = JwkEcKey::from_str(JWK_PUBLIC_KEY).unwrap(); + let point = jwk.to_encoded_point::().unwrap(); + let (x, y) = match point.coordinates() { + Coordinates::Uncompressed { x, y } => (x, y), + other => panic!("unexpected coordinates: {other:?}"), + }; + + assert_eq!(&decode_base64url_fe::(&jwk.x).unwrap(), x); + assert_eq!(&decode_base64url_fe::(&jwk.y).unwrap(), y); + } + + #[cfg(feature = "dev")] + #[test] + fn encoded_point_into_jwk() { + let jwk = JwkEcKey::from_str(JWK_PUBLIC_KEY).unwrap(); + let point = jwk.to_encoded_point::().unwrap(); + let jwk2 = JwkEcKey::from_encoded_point::(&point).unwrap(); + assert_eq!(jwk, jwk2); + } +} diff --git a/src/rust/vendor/elliptic-curve/src/lib.rs b/src/rust/vendor/elliptic-curve/src/lib.rs new file mode 100644 index 000000000..f387d2896 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/lib.rs @@ -0,0 +1,196 @@ +#![no_std] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![doc = include_str!("../README.md")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg" +)] +#![forbid(unsafe_code)] +#![warn( + clippy::cast_lossless, + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::cast_precision_loss, + clippy::cast_sign_loss, + clippy::checked_conversions, + clippy::implicit_saturating_sub, + clippy::mod_module_files, + clippy::panic, + clippy::panic_in_result_fn, + clippy::unwrap_used, + missing_docs, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] + +//! ## Usage +//! +//! This crate provides traits for describing elliptic curves, along with +//! types which are generic over elliptic curves which can be used as the +//! basis of curve-agnostic code. +//! +//! It's intended to be used with the following concrete elliptic curve +//! implementations from the [`RustCrypto/elliptic-curves`] project: +//! +//! - [`bp256`]: brainpoolP256r1 and brainpoolP256t1 +//! - [`bp384`]: brainpoolP384r1 and brainpoolP384t1 +//! - [`k256`]: secp256k1 a.k.a. K-256 +//! - [`p224`]: NIST P-224 a.k.a. secp224r1 +//! - [`p256`]: NIST P-256 a.k.a secp256r1, prime256v1 +//! - [`p384`]: NIST P-384 a.k.a. secp384r1 +//! - [`p521`]: NIST P-521 a.k.a. secp521r1 +//! +//! The [`ecdsa`] crate provides a generic implementation of the +//! Elliptic Curve Digital Signature Algorithm which can be used with any of +//! the above crates, either via an external ECDSA implementation, or +//! using native curve arithmetic where applicable. +//! +//! ## Type conversions +//! +//! The following chart illustrates the various conversions possible between +//! the various types defined by this crate. +//! +//! ![Type Conversion Map](https://raw.githubusercontent.com/RustCrypto/media/master/img/elliptic-curve/type-transforms.svg) +//! +//! ## `serde` support +//! +//! When the `serde` feature of this crate is enabled, `Serialize` and +//! `Deserialize` impls are provided for the following types: +//! +//! - [`JwkEcKey`] +//! - [`PublicKey`] +//! - [`ScalarPrimitive`] +//! +//! Please see type-specific documentation for more information. +//! +//! [`RustCrypto/elliptic-curves`]: https://github.com/RustCrypto/elliptic-curves +//! [`bp256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/bp256 +//! [`bp384`]: https://github.com/RustCrypto/elliptic-curves/tree/master/bp384 +//! [`k256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/k256 +//! [`p224`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p224 +//! [`p256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p256 +//! [`p384`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p384 +//! [`p521`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p521 +//! [`ecdsa`]: https://github.com/RustCrypto/signatures/tree/master/ecdsa + +#[cfg(feature = "alloc")] +#[allow(unused_imports)] +#[macro_use] +extern crate alloc; +#[cfg(feature = "std")] +extern crate std; + +pub mod point; +pub mod scalar; + +#[cfg(feature = "dev")] +pub mod dev; +#[cfg(feature = "ecdh")] +pub mod ecdh; +#[cfg(feature = "hash2curve")] +pub mod hash2curve; +#[cfg(feature = "arithmetic")] +pub mod ops; +#[cfg(feature = "sec1")] +pub mod sec1; +#[cfg(feature = "arithmetic")] +pub mod weierstrass; + +mod error; +mod field; +mod secret_key; + +#[cfg(feature = "arithmetic")] +mod arithmetic; +#[cfg(feature = "arithmetic")] +mod public_key; + +#[cfg(feature = "jwk")] +mod jwk; + +#[cfg(feature = "voprf")] +mod voprf; + +pub use crate::{ + error::{Error, Result}, + field::{FieldBytes, FieldBytesEncoding, FieldBytesSize}, + scalar::ScalarPrimitive, + secret_key::SecretKey, +}; +pub use crypto_bigint as bigint; +pub use generic_array::{self, typenum::consts}; +pub use rand_core; +pub use subtle; +pub use zeroize; + +#[cfg(feature = "arithmetic")] +pub use { + crate::{ + arithmetic::{CurveArithmetic, PrimeCurveArithmetic}, + point::{AffinePoint, BatchNormalize, ProjectivePoint}, + public_key::PublicKey, + scalar::{NonZeroScalar, Scalar}, + }, + ff::{self, Field, PrimeField}, + group::{self, Group}, +}; + +#[cfg(feature = "jwk")] +pub use crate::jwk::{JwkEcKey, JwkParameters}; + +#[cfg(feature = "pkcs8")] +pub use pkcs8; + +#[cfg(feature = "voprf")] +pub use crate::voprf::VoprfParameters; + +use core::{ + fmt::Debug, + ops::{Add, ShrAssign}, +}; +use generic_array::ArrayLength; + +/// Algorithm [`ObjectIdentifier`][`pkcs8::ObjectIdentifier`] for elliptic +/// curve public key cryptography (`id-ecPublicKey`). +/// +/// +#[cfg(feature = "pkcs8")] +pub const ALGORITHM_OID: pkcs8::ObjectIdentifier = + pkcs8::ObjectIdentifier::new_unwrap("1.2.840.10045.2.1"); + +/// Elliptic curve. +/// +/// This trait is intended to be impl'd by a ZST which represents a concrete +/// elliptic curve. +/// +/// Other traits in this crate which are bounded by [`Curve`] are intended to +/// be impl'd by these ZSTs, facilitating types which are generic over elliptic +/// curves (e.g. [`SecretKey`]). +pub trait Curve: 'static + Copy + Clone + Debug + Default + Eq + Ord + Send + Sync { + /// Size of a serialized field element in bytes. + /// + /// This is typically the same as `Self::Uint::ByteSize` but for curves + /// with an unusual field modulus (e.g. P-224, P-521) it may be different. + type FieldBytesSize: ArrayLength + Add + Eq; + + /// Integer type used to represent field elements of this elliptic curve. + type Uint: bigint::ArrayEncoding + + bigint::AddMod + + bigint::Encoding + + bigint::Integer + + bigint::NegMod + + bigint::Random + + bigint::RandomMod + + bigint::SubMod + + zeroize::Zeroize + + FieldBytesEncoding + + ShrAssign; + + /// Order of this elliptic curve, i.e. number of elements in the scalar + /// field. + const ORDER: Self::Uint; +} + +/// Marker trait for elliptic curves with prime order. +pub trait PrimeCurve: Curve {} diff --git a/src/rust/vendor/elliptic-curve/src/ops.rs b/src/rust/vendor/elliptic-curve/src/ops.rs new file mode 100644 index 000000000..9043b29c7 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/ops.rs @@ -0,0 +1,229 @@ +//! Traits for arithmetic operations on elliptic curve field elements. + +pub use core::ops::{Add, AddAssign, Mul, Neg, Shr, ShrAssign, Sub, SubAssign}; + +use crypto_bigint::Integer; +use group::Group; +use subtle::{Choice, ConditionallySelectable, CtOption}; + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +/// Perform an inversion on a field element (i.e. base field element or scalar) +pub trait Invert { + /// Field element type + type Output; + + /// Invert a field element. + fn invert(&self) -> Self::Output; + + /// Invert a field element in variable time. + /// + /// ⚠️ WARNING! + /// + /// This method should not be used with secret values, as its variable-time + /// operation can potentially leak secrets through sidechannels. + fn invert_vartime(&self) -> Self::Output { + // Fall back on constant-time implementation by default. + self.invert() + } +} + +/// Perform a batched inversion on a sequence of field elements (i.e. base field elements or scalars) +/// at an amortized cost that should be practically as efficient as a single inversion. +pub trait BatchInvert: Invert + Sized { + /// The output of batch inversion. A container of field elements. + type Output: AsRef<[Self]>; + + /// Invert a batch of field elements. + fn batch_invert( + field_elements: &FieldElements, + ) -> CtOption<>::Output>; +} + +impl BatchInvert<[T; N]> for T +where + T: Invert> + + Mul + + Copy + + Default + + ConditionallySelectable, +{ + type Output = [Self; N]; + + fn batch_invert(field_elements: &[Self; N]) -> CtOption<[Self; N]> { + let mut field_elements_multiples = [Self::default(); N]; + let mut field_elements_multiples_inverses = [Self::default(); N]; + let mut field_elements_inverses = [Self::default(); N]; + + let inversion_succeeded = invert_batch_internal( + field_elements, + &mut field_elements_multiples, + &mut field_elements_multiples_inverses, + &mut field_elements_inverses, + ); + + CtOption::new(field_elements_inverses, inversion_succeeded) + } +} + +#[cfg(feature = "alloc")] +impl BatchInvert<[T]> for T +where + T: Invert> + + Mul + + Copy + + Default + + ConditionallySelectable, +{ + type Output = Vec; + + fn batch_invert(field_elements: &[Self]) -> CtOption> { + let mut field_elements_multiples: Vec = vec![Self::default(); field_elements.len()]; + let mut field_elements_multiples_inverses: Vec = + vec![Self::default(); field_elements.len()]; + let mut field_elements_inverses: Vec = vec![Self::default(); field_elements.len()]; + + let inversion_succeeded = invert_batch_internal( + field_elements, + field_elements_multiples.as_mut(), + field_elements_multiples_inverses.as_mut(), + field_elements_inverses.as_mut(), + ); + + CtOption::new( + field_elements_inverses.into_iter().collect(), + inversion_succeeded, + ) + } +} + +/// Implements "Montgomery's trick", a trick for computing many modular inverses at once. +/// +/// "Montgomery's trick" works by reducing the problem of computing `n` inverses +/// to computing a single inversion, plus some storage and `O(n)` extra multiplications. +/// +/// See: https://iacr.org/archive/pkc2004/29470042/29470042.pdf section 2.2. +fn invert_batch_internal< + T: Invert> + Mul + Default + ConditionallySelectable, +>( + field_elements: &[T], + field_elements_multiples: &mut [T], + field_elements_multiples_inverses: &mut [T], + field_elements_inverses: &mut [T], +) -> Choice { + let batch_size = field_elements.len(); + if batch_size == 0 + || batch_size != field_elements_multiples.len() + || batch_size != field_elements_multiples_inverses.len() + { + return Choice::from(0); + } + + field_elements_multiples[0] = field_elements[0]; + for i in 1..batch_size { + // $ a_n = a_{n-1}*x_n $ + field_elements_multiples[i] = field_elements_multiples[i - 1] * field_elements[i]; + } + + field_elements_multiples[batch_size - 1] + .invert() + .map(|multiple_of_inverses_of_all_field_elements| { + field_elements_multiples_inverses[batch_size - 1] = + multiple_of_inverses_of_all_field_elements; + for i in (1..batch_size).rev() { + // $ a_{n-1} = {a_n}^{-1}*x_n $ + field_elements_multiples_inverses[i - 1] = + field_elements_multiples_inverses[i] * field_elements[i]; + } + + field_elements_inverses[0] = field_elements_multiples_inverses[0]; + for i in 1..batch_size { + // $ {x_n}^{-1} = a_{n}^{-1}*a_{n-1} $ + field_elements_inverses[i] = + field_elements_multiples_inverses[i] * field_elements_multiples[i - 1]; + } + }) + .is_some() +} + +/// Linear combination. +/// +/// This trait enables crates to provide an optimized implementation of +/// linear combinations (e.g. Shamir's Trick), or otherwise provides a default +/// non-optimized implementation. +// TODO(tarcieri): replace this with a trait from the `group` crate? (see zkcrypto/group#25) +pub trait LinearCombination: Group { + /// Calculates `x * k + y * l`. + fn lincomb(x: &Self, k: &Self::Scalar, y: &Self, l: &Self::Scalar) -> Self { + (*x * k) + (*y * l) + } +} + +/// Linear combination (extended version). +/// +/// This trait enables providing an optimized implementation of +/// linear combinations (e.g. Shamir's Trick). +// TODO(tarcieri): replace the current `LinearCombination` with this in the next release +pub trait LinearCombinationExt: group::Curve +where + PointsAndScalars: AsRef<[(Self, Self::Scalar)]> + ?Sized, +{ + /// Calculates `x1 * k1 + ... + xn * kn`. + fn lincomb_ext(points_and_scalars: &PointsAndScalars) -> Self { + points_and_scalars + .as_ref() + .iter() + .copied() + .map(|(point, scalar)| point * scalar) + .sum() + } +} + +/// Blanket impl of the legacy [`LinearCombination`] trait for types which impl the new +/// [`LinearCombinationExt`] trait for 2-element arrays. +impl> LinearCombination for P { + fn lincomb(x: &Self, k: &Self::Scalar, y: &Self, l: &Self::Scalar) -> Self { + Self::lincomb_ext(&[(*x, *k), (*y, *l)]) + } +} + +/// Multiplication by the generator. +/// +/// May use optimizations (e.g. precomputed tables) when available. +// TODO(tarcieri): replace this with `Group::mul_by_generator``? (see zkcrypto/group#44) +pub trait MulByGenerator: Group { + /// Multiply by the generator of the prime-order subgroup. + #[must_use] + fn mul_by_generator(scalar: &Self::Scalar) -> Self { + Self::generator() * scalar + } +} + +/// Modular reduction. +pub trait Reduce: Sized { + /// Bytes used as input to [`Reduce::reduce_bytes`]. + type Bytes: AsRef<[u8]>; + + /// Perform a modular reduction, returning a field element. + fn reduce(n: Uint) -> Self; + + /// Interpret the given bytes as an integer and perform a modular reduction. + fn reduce_bytes(bytes: &Self::Bytes) -> Self; +} + +/// Modular reduction to a non-zero output. +/// +/// This trait is primarily intended for use by curve implementations such +/// as the `k256` and `p256` crates. +/// +/// End users should use the [`Reduce`] impl on +/// [`NonZeroScalar`][`crate::NonZeroScalar`] instead. +pub trait ReduceNonZero: Reduce + Sized { + /// Perform a modular reduction, returning a field element. + fn reduce_nonzero(n: Uint) -> Self; + + /// Interpret the given bytes as an integer and perform a modular reduction + /// to a non-zero output. + fn reduce_nonzero_bytes(bytes: &Self::Bytes) -> Self; +} diff --git a/src/rust/vendor/elliptic-curve/src/point.rs b/src/rust/vendor/elliptic-curve/src/point.rs new file mode 100644 index 000000000..ee4eded44 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/point.rs @@ -0,0 +1,81 @@ +//! Traits for elliptic curve points. + +#[cfg(feature = "arithmetic")] +mod non_identity; + +#[cfg(feature = "arithmetic")] +pub use {self::non_identity::NonIdentity, crate::CurveArithmetic}; + +use crate::{Curve, FieldBytes}; +use subtle::{Choice, CtOption}; + +/// Affine point type for a given curve with a [`CurveArithmetic`] +/// implementation. +#[cfg(feature = "arithmetic")] +pub type AffinePoint = ::AffinePoint; + +/// Projective point type for a given curve with a [`CurveArithmetic`] +/// implementation. +#[cfg(feature = "arithmetic")] +pub type ProjectivePoint = ::ProjectivePoint; + +/// Access to the affine coordinates of an elliptic curve point. +// TODO: use zkcrypto/group#30 coordinate API when available +pub trait AffineCoordinates { + /// Field element representation. + type FieldRepr: AsRef<[u8]>; + + /// Get the affine x-coordinate as a serialized field element. + fn x(&self) -> Self::FieldRepr; + + /// Is the affine y-coordinate odd? + fn y_is_odd(&self) -> Choice; +} + +/// Normalize point(s) in projective representation by converting them to their affine ones. +#[cfg(feature = "arithmetic")] +pub trait BatchNormalize: group::Curve { + /// The output of the batch normalization; a container of affine points. + type Output: AsRef<[Self::AffineRepr]>; + + /// Perform a batched conversion to affine representation on a sequence of projective points + /// at an amortized cost that should be practically as efficient as a single conversion. + /// Internally, implementors should rely upon `InvertBatch`. + fn batch_normalize(points: &Points) -> >::Output; +} + +/// Double a point (i.e. add it to itself) +pub trait Double { + /// Double this point. + fn double(&self) -> Self; +} + +/// Decompress an elliptic curve point. +/// +/// Point decompression recovers an original curve point from its x-coordinate +/// and a boolean flag indicating whether or not the y-coordinate is odd. +pub trait DecompressPoint: Sized { + /// Attempt to decompress an elliptic curve point. + fn decompress(x: &FieldBytes, y_is_odd: Choice) -> CtOption; +} + +/// Decompact an elliptic curve point from an x-coordinate. +/// +/// Decompaction relies on properties of specially-generated keys but provides +/// a more compact representation than standard point compression. +pub trait DecompactPoint: Sized { + /// Attempt to decompact an elliptic curve point + fn decompact(x: &FieldBytes) -> CtOption; +} + +/// Point compression settings. +pub trait PointCompression { + /// Should point compression be applied by default? + const COMPRESS_POINTS: bool; +} + +/// Point compaction settings. +pub trait PointCompaction { + /// Should point compaction be applied by default? + const COMPACT_POINTS: bool; +} diff --git a/src/rust/vendor/elliptic-curve/src/point/non_identity.rs b/src/rust/vendor/elliptic-curve/src/point/non_identity.rs new file mode 100644 index 000000000..81c31cd19 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/point/non_identity.rs @@ -0,0 +1,237 @@ +//! Non-identity point type. + +use core::ops::{Deref, Mul}; + +use group::{prime::PrimeCurveAffine, Curve, GroupEncoding}; +use rand_core::{CryptoRng, RngCore}; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +use crate::{CurveArithmetic, NonZeroScalar, Scalar}; + +/// Non-identity point type. +/// +/// This type ensures that its value is not the identity point, ala `core::num::NonZero*`. +/// +/// In the context of ECC, it's useful for ensuring that certain arithmetic +/// cannot result in the identity point. +#[derive(Clone, Copy)] +pub struct NonIdentity

{ + point: P, +} + +impl

NonIdentity

+where + P: ConditionallySelectable + ConstantTimeEq + Default, +{ + /// Create a [`NonIdentity`] from a point. + pub fn new(point: P) -> CtOption { + CtOption::new(Self { point }, !point.ct_eq(&P::default())) + } + + pub(crate) fn new_unchecked(point: P) -> Self { + Self { point } + } +} + +impl

NonIdentity

+where + P: ConditionallySelectable + ConstantTimeEq + Default + GroupEncoding, +{ + /// Decode a [`NonIdentity`] from its encoding. + pub fn from_repr(repr: &P::Repr) -> CtOption { + Self::from_bytes(repr) + } +} + +impl NonIdentity

{ + /// Return wrapped point. + pub fn to_point(self) -> P { + self.point + } +} + +impl

NonIdentity

+where + P: ConditionallySelectable + ConstantTimeEq + Curve + Default, +{ + /// Generate a random `NonIdentity`. + pub fn random(mut rng: impl CryptoRng + RngCore) -> Self { + loop { + if let Some(point) = Self::new(P::random(&mut rng)).into() { + break point; + } + } + } + + /// Converts this element into its affine representation. + pub fn to_affine(self) -> NonIdentity { + NonIdentity { + point: self.point.to_affine(), + } + } +} + +impl

NonIdentity

+where + P: PrimeCurveAffine, +{ + /// Converts this element to its curve representation. + pub fn to_curve(self) -> NonIdentity { + NonIdentity { + point: self.point.to_curve(), + } + } +} + +impl

AsRef

for NonIdentity

{ + fn as_ref(&self) -> &P { + &self.point + } +} + +impl

ConditionallySelectable for NonIdentity

+where + P: ConditionallySelectable, +{ + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self { + point: P::conditional_select(&a.point, &b.point, choice), + } + } +} + +impl

ConstantTimeEq for NonIdentity

+where + P: ConstantTimeEq, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.point.ct_eq(&other.point) + } +} + +impl

Deref for NonIdentity

{ + type Target = P; + + fn deref(&self) -> &Self::Target { + &self.point + } +} + +impl

GroupEncoding for NonIdentity

+where + P: ConditionallySelectable + ConstantTimeEq + Default + GroupEncoding, +{ + type Repr = P::Repr; + + fn from_bytes(bytes: &Self::Repr) -> CtOption { + let point = P::from_bytes(bytes); + point.and_then(|point| CtOption::new(Self { point }, !point.ct_eq(&P::default()))) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { + P::from_bytes_unchecked(bytes).map(|point| Self { point }) + } + + fn to_bytes(&self) -> Self::Repr { + self.point.to_bytes() + } +} + +impl Mul> for NonIdentity

+where + C: CurveArithmetic, + P: Copy + Mul, Output = P>, +{ + type Output = NonIdentity

; + + fn mul(self, rhs: NonZeroScalar) -> Self::Output { + &self * &rhs + } +} + +impl Mul<&NonZeroScalar> for &NonIdentity

+where + C: CurveArithmetic, + P: Copy + Mul, Output = P>, +{ + type Output = NonIdentity

; + + fn mul(self, rhs: &NonZeroScalar) -> Self::Output { + NonIdentity { + point: self.point * *rhs.as_ref(), + } + } +} + +#[cfg(feature = "serde")] +impl

Serialize for NonIdentity

+where + P: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: ser::Serializer, + { + self.point.serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, P> Deserialize<'de> for NonIdentity

+where + P: ConditionallySelectable + ConstantTimeEq + Default + Deserialize<'de> + GroupEncoding, +{ + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + Option::from(Self::new(P::deserialize(deserializer)?)) + .ok_or_else(|| de::Error::custom("expected non-identity point")) + } +} + +#[cfg(all(test, feature = "dev"))] +mod tests { + use super::NonIdentity; + use crate::dev::{AffinePoint, ProjectivePoint}; + use group::GroupEncoding; + use hex_literal::hex; + + #[test] + fn new_success() { + let point = ProjectivePoint::from_bytes( + &hex!("02c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721").into(), + ) + .unwrap(); + + assert!(bool::from(NonIdentity::new(point).is_some())); + + assert!(bool::from( + NonIdentity::new(AffinePoint::from(point)).is_some() + )); + } + + #[test] + fn new_fail() { + assert!(bool::from( + NonIdentity::new(ProjectivePoint::default()).is_none() + )); + assert!(bool::from( + NonIdentity::new(AffinePoint::default()).is_none() + )); + } + + #[test] + fn round_trip() { + let bytes = hex!("02c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); + let point = NonIdentity::::from_repr(&bytes.into()).unwrap(); + assert_eq!(&bytes, point.to_bytes().as_slice()); + + let bytes = hex!("02c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); + let point = NonIdentity::::from_repr(&bytes.into()).unwrap(); + assert_eq!(&bytes, point.to_bytes().as_slice()); + } +} diff --git a/src/rust/vendor/elliptic-curve/src/public_key.rs b/src/rust/vendor/elliptic-curve/src/public_key.rs new file mode 100644 index 000000000..d2fe6065b --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/public_key.rs @@ -0,0 +1,567 @@ +//! Elliptic curve public keys. + +use crate::{ + point::NonIdentity, AffinePoint, CurveArithmetic, Error, NonZeroScalar, ProjectivePoint, Result, +}; +use core::fmt::Debug; +use group::{Curve, Group}; + +#[cfg(feature = "jwk")] +use crate::{JwkEcKey, JwkParameters}; + +#[cfg(feature = "pkcs8")] +use pkcs8::spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, ObjectIdentifier}; + +#[cfg(feature = "pem")] +use core::str::FromStr; + +#[cfg(feature = "sec1")] +use { + crate::{ + point::PointCompression, + sec1::{CompressedPoint, EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint}, + FieldBytesSize, + }, + core::cmp::Ordering, + subtle::{Choice, CtOption}, +}; + +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +use pkcs8::EncodePublicKey; + +#[cfg(all(feature = "alloc", feature = "sec1"))] +use alloc::boxed::Box; + +#[cfg(any(feature = "jwk", feature = "pem"))] +use alloc::string::{String, ToString}; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +#[cfg(any(feature = "pem", feature = "serde"))] +use pkcs8::DecodePublicKey; + +#[cfg(all(feature = "sec1", feature = "pkcs8"))] +use { + crate::{ + pkcs8::{self, AssociatedOid}, + ALGORITHM_OID, + }, + pkcs8::der, +}; + +/// Elliptic curve public keys. +/// +/// This is a wrapper type for [`AffinePoint`] which ensures an inner +/// non-identity point and provides a common place to handle encoding/decoding. +/// +/// # Parsing "SPKI" Keys +/// +/// X.509 `SubjectPublicKeyInfo` (SPKI) is a commonly used format for encoding +/// public keys, notably public keys corresponding to PKCS#8 private keys. +/// (especially ones generated by OpenSSL). +/// +/// Keys in SPKI format are either binary (ASN.1 BER/DER), or PEM encoded +/// (ASCII) and begin with the following: +/// +/// ```text +/// -----BEGIN PUBLIC KEY----- +/// ``` +/// +/// To decode an elliptic curve public key from SPKI, enable the `pkcs8` +/// feature of this crate (or the `pkcs8` feature of a specific RustCrypto +/// elliptic curve crate) and use the +/// [`elliptic_curve::pkcs8::DecodePublicKey`][`pkcs8::DecodePublicKey`] +/// trait to parse it. +/// +/// When the `pem` feature of this crate (or a specific RustCrypto elliptic +/// curve crate) is enabled, a [`FromStr`] impl is also available. +/// +/// # `serde` support +/// +/// When the optional `serde` feature of this create is enabled, [`Serialize`] +/// and [`Deserialize`] impls are provided for this type. +/// +/// The serialization is binary-oriented and supports ASN.1 DER +/// Subject Public Key Info (SPKI) as the encoding format. +/// +/// For a more text-friendly encoding of public keys, use [`JwkEcKey`] instead. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct PublicKey +where + C: CurveArithmetic, +{ + point: AffinePoint, +} + +impl PublicKey +where + C: CurveArithmetic, +{ + /// Convert an [`AffinePoint`] into a [`PublicKey`] + pub fn from_affine(point: AffinePoint) -> Result { + if ProjectivePoint::::from(point).is_identity().into() { + Err(Error) + } else { + Ok(Self { point }) + } + } + + /// Compute a [`PublicKey`] from a secret [`NonZeroScalar`] value + /// (i.e. a secret key represented as a raw scalar value) + pub fn from_secret_scalar(scalar: &NonZeroScalar) -> Self { + // `NonZeroScalar` ensures the resulting point is not the identity + Self { + point: (C::ProjectivePoint::generator() * scalar.as_ref()).to_affine(), + } + } + + /// Decode [`PublicKey`] (compressed or uncompressed) from the + /// `Elliptic-Curve-Point-to-Octet-String` encoding described in + /// SEC 1: Elliptic Curve Cryptography (Version 2.0) section + /// 2.3.3 (page 10). + /// + /// + #[cfg(feature = "sec1")] + pub fn from_sec1_bytes(bytes: &[u8]) -> Result + where + FieldBytesSize: ModulusSize, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + { + let point = EncodedPoint::::from_bytes(bytes).map_err(|_| Error)?; + Option::from(Self::from_encoded_point(&point)).ok_or(Error) + } + + /// Convert this [`PublicKey`] into the + /// `Elliptic-Curve-Point-to-Octet-String` encoding described in + /// SEC 1: Elliptic Curve Cryptography (Version 2.0) section 2.3.3 + /// (page 10). + /// + /// + #[cfg(all(feature = "alloc", feature = "sec1"))] + pub fn to_sec1_bytes(&self) -> Box<[u8]> + where + C: PointCompression, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, + { + EncodedPoint::::from(self).to_bytes() + } + + /// Borrow the inner [`AffinePoint`] from this [`PublicKey`]. + /// + /// In ECC, public keys are elliptic curve points. + pub fn as_affine(&self) -> &AffinePoint { + &self.point + } + + /// Convert this [`PublicKey`] to a [`ProjectivePoint`] for the given curve + pub fn to_projective(&self) -> ProjectivePoint { + self.point.into() + } + + /// Convert this [`PublicKey`] to a [`NonIdentity`] of the inner [`AffinePoint`] + pub fn to_nonidentity(&self) -> NonIdentity> { + NonIdentity::new_unchecked(self.point) + } + + /// Parse a [`JwkEcKey`] JSON Web Key (JWK) into a [`PublicKey`]. + #[cfg(feature = "jwk")] + pub fn from_jwk(jwk: &JwkEcKey) -> Result + where + C: JwkParameters, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, + { + jwk.to_public_key::() + } + + /// Parse a string containing a JSON Web Key (JWK) into a [`PublicKey`]. + #[cfg(feature = "jwk")] + pub fn from_jwk_str(jwk: &str) -> Result + where + C: JwkParameters, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, + { + jwk.parse::().and_then(|jwk| Self::from_jwk(&jwk)) + } + + /// Serialize this public key as [`JwkEcKey`] JSON Web Key (JWK). + #[cfg(feature = "jwk")] + pub fn to_jwk(&self) -> JwkEcKey + where + C: JwkParameters, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, + { + self.into() + } + + /// Serialize this public key as JSON Web Key (JWK) string. + #[cfg(feature = "jwk")] + pub fn to_jwk_string(&self) -> String + where + C: JwkParameters, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, + { + self.to_jwk().to_string() + } +} + +impl AsRef> for PublicKey +where + C: CurveArithmetic, +{ + fn as_ref(&self) -> &AffinePoint { + self.as_affine() + } +} + +impl Copy for PublicKey where C: CurveArithmetic {} + +#[cfg(feature = "sec1")] +impl FromEncodedPoint for PublicKey +where + C: CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + /// Initialize [`PublicKey`] from an [`EncodedPoint`] + fn from_encoded_point(encoded_point: &EncodedPoint) -> CtOption { + AffinePoint::::from_encoded_point(encoded_point).and_then(|point| { + // Defeating the point of `subtle`, but the use case is specifically a public key + let is_identity = Choice::from(u8::from(encoded_point.is_identity())); + CtOption::new(PublicKey { point }, !is_identity) + }) + } +} + +#[cfg(feature = "sec1")] +impl ToEncodedPoint for PublicKey +where + C: CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + /// Serialize this [`PublicKey`] as a SEC1 [`EncodedPoint`], optionally applying + /// point compression + fn to_encoded_point(&self, compress: bool) -> EncodedPoint { + self.point.to_encoded_point(compress) + } +} + +#[cfg(feature = "sec1")] +impl From> for CompressedPoint +where + C: CurveArithmetic + PointCompression, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + fn from(public_key: PublicKey) -> CompressedPoint { + CompressedPoint::::from(&public_key) + } +} + +#[cfg(feature = "sec1")] +impl From<&PublicKey> for CompressedPoint +where + C: CurveArithmetic + PointCompression, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + fn from(public_key: &PublicKey) -> CompressedPoint { + CompressedPoint::::clone_from_slice(public_key.to_encoded_point(true).as_bytes()) + } +} + +#[cfg(feature = "sec1")] +impl From> for EncodedPoint +where + C: CurveArithmetic + PointCompression, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + fn from(public_key: PublicKey) -> EncodedPoint { + EncodedPoint::::from(&public_key) + } +} + +#[cfg(feature = "sec1")] +impl From<&PublicKey> for EncodedPoint +where + C: CurveArithmetic + PointCompression, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + fn from(public_key: &PublicKey) -> EncodedPoint { + public_key.to_encoded_point(C::COMPRESS_POINTS) + } +} + +impl From> for PublicKey +where + C: CurveArithmetic, + P: Copy + Into>, +{ + fn from(value: NonIdentity

) -> Self { + Self::from(&value) + } +} + +impl From<&NonIdentity

> for PublicKey +where + C: CurveArithmetic, + P: Copy + Into>, +{ + fn from(value: &NonIdentity

) -> Self { + Self { + point: value.to_point().into(), + } + } +} + +impl From> for NonIdentity> +where + C: CurveArithmetic, +{ + fn from(value: PublicKey) -> Self { + Self::from(&value) + } +} + +impl From<&PublicKey> for NonIdentity> +where + C: CurveArithmetic, +{ + fn from(value: &PublicKey) -> Self { + PublicKey::to_nonidentity(value) + } +} + +#[cfg(feature = "sec1")] +impl PartialOrd for PublicKey +where + C: CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +#[cfg(feature = "sec1")] +impl Ord for PublicKey +where + C: CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + fn cmp(&self, other: &Self) -> Ordering { + // TODO(tarcieri): more efficient implementation? + // This is implemented this way to reduce bounds for `AffinePoint` + self.to_encoded_point(false) + .cmp(&other.to_encoded_point(false)) + } +} + +#[cfg(feature = "sec1")] +impl TryFrom> for PublicKey +where + C: CurveArithmetic, + FieldBytesSize: ModulusSize, + AffinePoint: FromEncodedPoint + ToEncodedPoint, +{ + type Error = Error; + + fn try_from(point: CompressedPoint) -> Result { + Self::from_sec1_bytes(&point) + } +} + +#[cfg(feature = "sec1")] +impl TryFrom<&CompressedPoint> for PublicKey +where + C: CurveArithmetic, + FieldBytesSize: ModulusSize, + AffinePoint: FromEncodedPoint + ToEncodedPoint, +{ + type Error = Error; + + fn try_from(point: &CompressedPoint) -> Result { + Self::from_sec1_bytes(point) + } +} + +#[cfg(feature = "sec1")] +impl TryFrom> for PublicKey +where + C: CurveArithmetic, + FieldBytesSize: ModulusSize, + AffinePoint: FromEncodedPoint + ToEncodedPoint, +{ + type Error = Error; + + fn try_from(point: EncodedPoint) -> Result { + Self::from_sec1_bytes(point.as_bytes()) + } +} + +#[cfg(feature = "sec1")] +impl TryFrom<&EncodedPoint> for PublicKey +where + C: CurveArithmetic, + FieldBytesSize: ModulusSize, + AffinePoint: FromEncodedPoint + ToEncodedPoint, +{ + type Error = Error; + + fn try_from(point: &EncodedPoint) -> Result { + Self::from_sec1_bytes(point.as_bytes()) + } +} + +#[cfg(feature = "pkcs8")] +impl AssociatedAlgorithmIdentifier for PublicKey +where + C: AssociatedOid + CurveArithmetic, +{ + type Params = ObjectIdentifier; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifier = AlgorithmIdentifier { + oid: ALGORITHM_OID, + parameters: Some(C::OID), + }; +} + +#[cfg(feature = "pkcs8")] +impl TryFrom> for PublicKey +where + C: AssociatedOid + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + type Error = pkcs8::spki::Error; + + fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result { + Self::try_from(&spki) + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom<&pkcs8::SubjectPublicKeyInfoRef<'_>> for PublicKey +where + C: AssociatedOid + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + type Error = pkcs8::spki::Error; + + fn try_from(spki: &pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result { + spki.algorithm.assert_oids(ALGORITHM_OID, C::OID)?; + + let public_key_bytes = spki + .subject_public_key + .as_bytes() + .ok_or_else(|| der::Tag::BitString.value_error())?; + + Self::from_sec1_bytes(public_key_bytes) + .map_err(|_| der::Tag::BitString.value_error().into()) + } +} + +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +impl EncodePublicKey for PublicKey +where + C: AssociatedOid + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + fn to_public_key_der(&self) -> pkcs8::spki::Result { + let public_key_bytes = self.to_encoded_point(false); + let subject_public_key = der::asn1::BitStringRef::new(0, public_key_bytes.as_bytes())?; + + pkcs8::SubjectPublicKeyInfo { + algorithm: Self::ALGORITHM_IDENTIFIER, + subject_public_key, + } + .try_into() + } +} + +#[cfg(feature = "pem")] +impl FromStr for PublicKey +where + C: AssociatedOid + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + type Err = Error; + + fn from_str(s: &str) -> Result { + Self::from_public_key_pem(s).map_err(|_| Error) + } +} + +#[cfg(feature = "pem")] +impl ToString for PublicKey +where + C: AssociatedOid + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + fn to_string(&self) -> String { + self.to_public_key_pem(Default::default()) + .expect("PEM encoding error") + } +} + +#[cfg(feature = "serde")] +impl Serialize for PublicKey +where + C: AssociatedOid + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + fn serialize(&self, serializer: S) -> core::result::Result + where + S: ser::Serializer, + { + let der = self.to_public_key_der().map_err(ser::Error::custom)?; + serdect::slice::serialize_hex_upper_or_bin(&der, serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, C> Deserialize<'de> for PublicKey +where + C: AssociatedOid + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + fn deserialize(deserializer: D) -> core::result::Result + where + D: de::Deserializer<'de>, + { + let der_bytes = serdect::slice::deserialize_hex_or_bin_vec(deserializer)?; + Self::from_public_key_der(&der_bytes).map_err(de::Error::custom) + } +} + +#[cfg(all(feature = "dev", test))] +mod tests { + use crate::{dev::MockCurve, sec1::FromEncodedPoint}; + + type EncodedPoint = crate::sec1::EncodedPoint; + type PublicKey = super::PublicKey; + + #[test] + fn from_encoded_point_rejects_identity() { + let identity = EncodedPoint::identity(); + assert!(bool::from( + PublicKey::from_encoded_point(&identity).is_none() + )); + } +} diff --git a/src/rust/vendor/elliptic-curve/src/scalar.rs b/src/rust/vendor/elliptic-curve/src/scalar.rs new file mode 100644 index 000000000..eb992493a --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/scalar.rs @@ -0,0 +1,53 @@ +//! Scalar types. + +#[cfg(feature = "arithmetic")] +mod blinded; +#[cfg(feature = "arithmetic")] +mod nonzero; +mod primitive; + +pub use self::primitive::ScalarPrimitive; +#[cfg(feature = "arithmetic")] +pub use self::{blinded::BlindedScalar, nonzero::NonZeroScalar}; + +use crypto_bigint::Integer; +use subtle::Choice; + +#[cfg(feature = "arithmetic")] +use crate::CurveArithmetic; + +/// Scalar field element for a particular elliptic curve. +#[cfg(feature = "arithmetic")] +pub type Scalar = ::Scalar; + +/// Bit representation of a scalar field element of a given curve. +#[cfg(feature = "bits")] +pub type ScalarBits = ff::FieldBits< as ff::PrimeFieldBits>::ReprBits>; + +/// Instantiate a scalar from an unsigned integer without checking for overflow. +pub trait FromUintUnchecked { + /// Unsigned integer type (i.e. `Curve::Uint`) + type Uint: Integer; + + /// Instantiate scalar from an unsigned integer without checking + /// whether the value overflows the field modulus. + /// + /// ⚠️ WARNING! + /// + /// Incorrectly used this can lead to mathematically invalid results, + /// which can lead to potential security vulnerabilities. + /// + /// Use with care! + fn from_uint_unchecked(uint: Self::Uint) -> Self; +} + +/// Is this scalar greater than n / 2? +/// +/// # Returns +/// +/// - For scalars 0 through n / 2: `Choice::from(0)` +/// - For scalars (n / 2) + 1 through n - 1: `Choice::from(1)` +pub trait IsHigh { + /// Is this scalar greater than or equal to n / 2? + fn is_high(&self) -> Choice; +} diff --git a/src/rust/vendor/elliptic-curve/src/scalar/blinded.rs b/src/rust/vendor/elliptic-curve/src/scalar/blinded.rs new file mode 100644 index 000000000..29cfea98c --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/scalar/blinded.rs @@ -0,0 +1,74 @@ +//! Random blinding support for [`Scalar`] + +use super::Scalar; +use crate::{ops::Invert, CurveArithmetic}; +use group::ff::Field; +use rand_core::CryptoRngCore; +use subtle::CtOption; +use zeroize::Zeroize; + +/// Scalar blinded with a randomly generated masking value. +/// +/// This provides a randomly blinded impl of [`Invert`] which is useful for +/// e.g. ECDSA ephemeral (`k`) scalars. +/// +/// It implements masked variable-time inversions using Stein's algorithm, which +/// may be helpful for performance on embedded platforms. +#[derive(Clone)] +pub struct BlindedScalar +where + C: CurveArithmetic, +{ + /// Actual scalar value. + scalar: Scalar, + + /// Mask value. + mask: Scalar, +} + +impl BlindedScalar +where + C: CurveArithmetic, +{ + /// Create a new [`BlindedScalar`] from a scalar and a [`CryptoRngCore`]. + pub fn new(scalar: Scalar, rng: &mut impl CryptoRngCore) -> Self { + Self { + scalar, + mask: Scalar::::random(rng), + } + } +} + +impl AsRef> for BlindedScalar +where + C: CurveArithmetic, +{ + fn as_ref(&self) -> &Scalar { + &self.scalar + } +} + +impl Invert for BlindedScalar +where + C: CurveArithmetic, +{ + type Output = CtOption>; + + fn invert(&self) -> CtOption> { + // prevent side channel analysis of scalar inversion by pre-and-post-multiplying + // with the random masking scalar + (self.scalar * self.mask) + .invert_vartime() + .map(|s| s * self.mask) + } +} + +impl Drop for BlindedScalar +where + C: CurveArithmetic, +{ + fn drop(&mut self) { + self.scalar.zeroize(); + self.mask.zeroize(); + } +} diff --git a/src/rust/vendor/elliptic-curve/src/scalar/nonzero.rs b/src/rust/vendor/elliptic-curve/src/scalar/nonzero.rs new file mode 100644 index 000000000..c0e45740f --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/scalar/nonzero.rs @@ -0,0 +1,405 @@ +//! Non-zero scalar type. + +use crate::{ + ops::{Invert, Reduce, ReduceNonZero}, + scalar::IsHigh, + CurveArithmetic, Error, FieldBytes, PrimeCurve, Scalar, ScalarPrimitive, SecretKey, +}; +use base16ct::HexDisplay; +use core::{ + fmt, + ops::{Deref, Mul, Neg}, + str, +}; +use crypto_bigint::{ArrayEncoding, Integer}; +use ff::{Field, PrimeField}; +use generic_array::{typenum::Unsigned, GenericArray}; +use rand_core::CryptoRngCore; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use zeroize::Zeroize; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +/// Non-zero scalar type. +/// +/// This type ensures that its value is not zero, ala `core::num::NonZero*`. +/// To do this, the generic `S` type must impl both `Default` and +/// `ConstantTimeEq`, with the requirement that `S::default()` returns 0. +/// +/// In the context of ECC, it's useful for ensuring that scalar multiplication +/// cannot result in the point at infinity. +#[derive(Clone)] +pub struct NonZeroScalar +where + C: CurveArithmetic, +{ + scalar: Scalar, +} + +impl NonZeroScalar +where + C: CurveArithmetic, +{ + /// Generate a random `NonZeroScalar`. + pub fn random(mut rng: &mut impl CryptoRngCore) -> Self { + // Use rejection sampling to eliminate zero values. + // While this method isn't constant-time, the attacker shouldn't learn + // anything about unrelated outputs so long as `rng` is a secure `CryptoRng`. + loop { + if let Some(result) = Self::new(Field::random(&mut rng)).into() { + break result; + } + } + } + + /// Create a [`NonZeroScalar`] from a scalar. + pub fn new(scalar: Scalar) -> CtOption { + CtOption::new(Self { scalar }, !scalar.is_zero()) + } + + /// Decode a [`NonZeroScalar`] from a big endian-serialized field element. + pub fn from_repr(repr: FieldBytes) -> CtOption { + Scalar::::from_repr(repr).and_then(Self::new) + } + + /// Create a [`NonZeroScalar`] from a `C::Uint`. + pub fn from_uint(uint: C::Uint) -> CtOption { + ScalarPrimitive::new(uint).and_then(|scalar| Self::new(scalar.into())) + } +} + +impl AsRef> for NonZeroScalar +where + C: CurveArithmetic, +{ + fn as_ref(&self) -> &Scalar { + &self.scalar + } +} + +impl ConditionallySelectable for NonZeroScalar +where + C: CurveArithmetic, +{ + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self { + scalar: Scalar::::conditional_select(&a.scalar, &b.scalar, choice), + } + } +} + +impl ConstantTimeEq for NonZeroScalar +where + C: CurveArithmetic, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.scalar.ct_eq(&other.scalar) + } +} + +impl Copy for NonZeroScalar where C: CurveArithmetic {} + +impl Deref for NonZeroScalar +where + C: CurveArithmetic, +{ + type Target = Scalar; + + fn deref(&self) -> &Scalar { + &self.scalar + } +} + +impl From> for FieldBytes +where + C: CurveArithmetic, +{ + fn from(scalar: NonZeroScalar) -> FieldBytes { + Self::from(&scalar) + } +} + +impl From<&NonZeroScalar> for FieldBytes +where + C: CurveArithmetic, +{ + fn from(scalar: &NonZeroScalar) -> FieldBytes { + scalar.to_repr() + } +} + +impl From> for ScalarPrimitive +where + C: CurveArithmetic, +{ + #[inline] + fn from(scalar: NonZeroScalar) -> ScalarPrimitive { + Self::from(&scalar) + } +} + +impl From<&NonZeroScalar> for ScalarPrimitive +where + C: CurveArithmetic, +{ + fn from(scalar: &NonZeroScalar) -> ScalarPrimitive { + ScalarPrimitive::from_bytes(&scalar.to_repr()).unwrap() + } +} + +impl From> for NonZeroScalar +where + C: CurveArithmetic, +{ + fn from(sk: SecretKey) -> NonZeroScalar { + Self::from(&sk) + } +} + +impl From<&SecretKey> for NonZeroScalar +where + C: CurveArithmetic, +{ + fn from(sk: &SecretKey) -> NonZeroScalar { + let scalar = sk.as_scalar_primitive().to_scalar(); + debug_assert!(!bool::from(scalar.is_zero())); + Self { scalar } + } +} + +impl Invert for NonZeroScalar +where + C: CurveArithmetic, + Scalar: Invert>>, +{ + type Output = Self; + + fn invert(&self) -> Self { + Self { + // This will always succeed since `scalar` will never be 0 + scalar: Invert::invert(&self.scalar).unwrap(), + } + } + + fn invert_vartime(&self) -> Self::Output { + Self { + // This will always succeed since `scalar` will never be 0 + scalar: Invert::invert_vartime(&self.scalar).unwrap(), + } + } +} + +impl IsHigh for NonZeroScalar +where + C: CurveArithmetic, +{ + fn is_high(&self) -> Choice { + self.scalar.is_high() + } +} + +impl Neg for NonZeroScalar +where + C: CurveArithmetic, +{ + type Output = NonZeroScalar; + + fn neg(self) -> NonZeroScalar { + let scalar = -self.scalar; + debug_assert!(!bool::from(scalar.is_zero())); + NonZeroScalar { scalar } + } +} + +impl Mul> for NonZeroScalar +where + C: PrimeCurve + CurveArithmetic, +{ + type Output = Self; + + #[inline] + fn mul(self, other: Self) -> Self { + Self::mul(self, &other) + } +} + +impl Mul<&NonZeroScalar> for NonZeroScalar +where + C: PrimeCurve + CurveArithmetic, +{ + type Output = Self; + + fn mul(self, other: &Self) -> Self { + // Multiplication is modulo a prime, so the product of two non-zero + // scalars is also non-zero. + let scalar = self.scalar * other.scalar; + debug_assert!(!bool::from(scalar.is_zero())); + NonZeroScalar { scalar } + } +} + +/// Note: this is a non-zero reduction, as it's impl'd for [`NonZeroScalar`]. +impl Reduce for NonZeroScalar +where + C: CurveArithmetic, + I: Integer + ArrayEncoding, + Scalar: Reduce + ReduceNonZero, +{ + type Bytes = as Reduce>::Bytes; + + fn reduce(n: I) -> Self { + let scalar = Scalar::::reduce_nonzero(n); + debug_assert!(!bool::from(scalar.is_zero())); + Self { scalar } + } + + fn reduce_bytes(bytes: &Self::Bytes) -> Self { + let scalar = Scalar::::reduce_nonzero_bytes(bytes); + debug_assert!(!bool::from(scalar.is_zero())); + Self { scalar } + } +} + +/// Note: forwards to the [`Reduce`] impl. +impl ReduceNonZero for NonZeroScalar +where + Self: Reduce, + C: CurveArithmetic, + I: Integer + ArrayEncoding, + Scalar: Reduce + ReduceNonZero, +{ + fn reduce_nonzero(n: I) -> Self { + Self::reduce(n) + } + + fn reduce_nonzero_bytes(bytes: &Self::Bytes) -> Self { + Self::reduce_bytes(bytes) + } +} + +impl TryFrom<&[u8]> for NonZeroScalar +where + C: CurveArithmetic, +{ + type Error = Error; + + fn try_from(bytes: &[u8]) -> Result { + if bytes.len() == C::FieldBytesSize::USIZE { + Option::from(NonZeroScalar::from_repr(GenericArray::clone_from_slice( + bytes, + ))) + .ok_or(Error) + } else { + Err(Error) + } + } +} + +impl Zeroize for NonZeroScalar +where + C: CurveArithmetic, +{ + fn zeroize(&mut self) { + // Use zeroize's volatile writes to ensure value is cleared. + self.scalar.zeroize(); + + // Write a 1 instead of a 0 to ensure this type's non-zero invariant + // is upheld. + self.scalar = Scalar::::ONE; + } +} + +impl fmt::Display for NonZeroScalar +where + C: CurveArithmetic, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{self:X}") + } +} + +impl fmt::LowerHex for NonZeroScalar +where + C: CurveArithmetic, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:x}", HexDisplay(&self.to_repr())) + } +} + +impl fmt::UpperHex for NonZeroScalar +where + C: CurveArithmetic, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:}", HexDisplay(&self.to_repr())) + } +} + +impl str::FromStr for NonZeroScalar +where + C: CurveArithmetic, +{ + type Err = Error; + + fn from_str(hex: &str) -> Result { + let mut bytes = FieldBytes::::default(); + + if base16ct::mixed::decode(hex, &mut bytes)?.len() == bytes.len() { + Option::from(Self::from_repr(bytes)).ok_or(Error) + } else { + Err(Error) + } + } +} + +#[cfg(feature = "serde")] +impl Serialize for NonZeroScalar +where + C: CurveArithmetic, +{ + fn serialize(&self, serializer: S) -> Result + where + S: ser::Serializer, + { + ScalarPrimitive::from(self).serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, C> Deserialize<'de> for NonZeroScalar +where + C: CurveArithmetic, +{ + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + let scalar = ScalarPrimitive::deserialize(deserializer)?; + Option::from(Self::new(scalar.into())) + .ok_or_else(|| de::Error::custom("expected non-zero scalar")) + } +} + +#[cfg(all(test, feature = "dev"))] +mod tests { + use crate::dev::{NonZeroScalar, Scalar}; + use ff::{Field, PrimeField}; + use hex_literal::hex; + use zeroize::Zeroize; + + #[test] + fn round_trip() { + let bytes = hex!("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); + let scalar = NonZeroScalar::from_repr(bytes.into()).unwrap(); + assert_eq!(&bytes, scalar.to_repr().as_slice()); + } + + #[test] + fn zeroize() { + let mut scalar = NonZeroScalar::new(Scalar::from(42u64)).unwrap(); + scalar.zeroize(); + assert_eq!(*scalar, Scalar::ONE); + } +} diff --git a/src/rust/vendor/elliptic-curve/src/scalar/primitive.rs b/src/rust/vendor/elliptic-curve/src/scalar/primitive.rs new file mode 100644 index 000000000..a4f64cb58 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/scalar/primitive.rs @@ -0,0 +1,434 @@ +//! Generic scalar type with primitive functionality. + +use crate::{ + bigint::{prelude::*, Limb, NonZero}, + scalar::FromUintUnchecked, + scalar::IsHigh, + Curve, Error, FieldBytes, FieldBytesEncoding, Result, +}; +use base16ct::HexDisplay; +use core::{ + cmp::Ordering, + fmt, + ops::{Add, AddAssign, Neg, ShrAssign, Sub, SubAssign}, + str, +}; +use generic_array::{typenum::Unsigned, GenericArray}; +use rand_core::CryptoRngCore; +use subtle::{ + Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess, + CtOption, +}; +use zeroize::DefaultIsZeroes; + +#[cfg(feature = "arithmetic")] +use super::{CurveArithmetic, Scalar}; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +/// Generic scalar type with primitive functionality. +/// +/// This type provides a baseline level of scalar arithmetic functionality +/// which is always available for all curves, regardless of if they implement +/// any arithmetic traits. +/// +/// # `serde` support +/// +/// When the optional `serde` feature of this create is enabled, [`Serialize`] +/// and [`Deserialize`] impls are provided for this type. +/// +/// The serialization is a fixed-width big endian encoding. When used with +/// textual formats, the binary data is encoded as hexadecimal. +// TODO(tarcieri): use `crypto-bigint`'s `Residue` type, expose more functionality? +#[derive(Copy, Clone, Debug, Default)] +pub struct ScalarPrimitive { + /// Inner unsigned integer type. + inner: C::Uint, +} + +impl ScalarPrimitive +where + C: Curve, +{ + /// Zero scalar. + pub const ZERO: Self = Self { + inner: C::Uint::ZERO, + }; + + /// Multiplicative identity. + pub const ONE: Self = Self { + inner: C::Uint::ONE, + }; + + /// Scalar modulus. + pub const MODULUS: C::Uint = C::ORDER; + + /// Generate a random [`ScalarPrimitive`]. + pub fn random(rng: &mut impl CryptoRngCore) -> Self { + Self { + inner: C::Uint::random_mod(rng, &NonZero::new(Self::MODULUS).unwrap()), + } + } + + /// Create a new scalar from [`Curve::Uint`]. + pub fn new(uint: C::Uint) -> CtOption { + CtOption::new(Self { inner: uint }, uint.ct_lt(&Self::MODULUS)) + } + + /// Decode [`ScalarPrimitive`] from a serialized field element + pub fn from_bytes(bytes: &FieldBytes) -> CtOption { + Self::new(C::Uint::decode_field_bytes(bytes)) + } + + /// Decode [`ScalarPrimitive`] from a big endian byte slice. + pub fn from_slice(slice: &[u8]) -> Result { + if slice.len() == C::FieldBytesSize::USIZE { + Option::from(Self::from_bytes(GenericArray::from_slice(slice))).ok_or(Error) + } else { + Err(Error) + } + } + + /// Borrow the inner `C::Uint`. + pub fn as_uint(&self) -> &C::Uint { + &self.inner + } + + /// Borrow the inner limbs as a slice. + pub fn as_limbs(&self) -> &[Limb] { + self.inner.as_ref() + } + + /// Is this [`ScalarPrimitive`] value equal to zero? + pub fn is_zero(&self) -> Choice { + self.inner.is_zero() + } + + /// Is this [`ScalarPrimitive`] value even? + pub fn is_even(&self) -> Choice { + self.inner.is_even() + } + + /// Is this [`ScalarPrimitive`] value odd? + pub fn is_odd(&self) -> Choice { + self.inner.is_odd() + } + + /// Encode [`ScalarPrimitive`] as a serialized field element. + pub fn to_bytes(&self) -> FieldBytes { + self.inner.encode_field_bytes() + } + + /// Convert to a `C::Uint`. + pub fn to_uint(&self) -> C::Uint { + self.inner + } +} + +impl FromUintUnchecked for ScalarPrimitive +where + C: Curve, +{ + type Uint = C::Uint; + + fn from_uint_unchecked(uint: C::Uint) -> Self { + Self { inner: uint } + } +} + +#[cfg(feature = "arithmetic")] +impl ScalarPrimitive +where + C: CurveArithmetic, +{ + /// Convert [`ScalarPrimitive`] into a given curve's scalar type. + pub(super) fn to_scalar(self) -> Scalar { + Scalar::::from_uint_unchecked(self.inner) + } +} + +// TODO(tarcieri): better encapsulate this? +impl AsRef<[Limb]> for ScalarPrimitive +where + C: Curve, +{ + fn as_ref(&self) -> &[Limb] { + self.as_limbs() + } +} + +impl ConditionallySelectable for ScalarPrimitive +where + C: Curve, +{ + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self { + inner: C::Uint::conditional_select(&a.inner, &b.inner, choice), + } + } +} + +impl ConstantTimeEq for ScalarPrimitive +where + C: Curve, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.inner.ct_eq(&other.inner) + } +} + +impl ConstantTimeLess for ScalarPrimitive +where + C: Curve, +{ + fn ct_lt(&self, other: &Self) -> Choice { + self.inner.ct_lt(&other.inner) + } +} + +impl ConstantTimeGreater for ScalarPrimitive +where + C: Curve, +{ + fn ct_gt(&self, other: &Self) -> Choice { + self.inner.ct_gt(&other.inner) + } +} + +impl DefaultIsZeroes for ScalarPrimitive {} + +impl Eq for ScalarPrimitive {} + +impl PartialEq for ScalarPrimitive +where + C: Curve, +{ + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } +} + +impl PartialOrd for ScalarPrimitive +where + C: Curve, +{ + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for ScalarPrimitive +where + C: Curve, +{ + fn cmp(&self, other: &Self) -> Ordering { + self.inner.cmp(&other.inner) + } +} + +impl From for ScalarPrimitive +where + C: Curve, +{ + fn from(n: u64) -> Self { + Self { + inner: C::Uint::from(n), + } + } +} + +impl Add> for ScalarPrimitive +where + C: Curve, +{ + type Output = Self; + + fn add(self, other: Self) -> Self { + self.add(&other) + } +} + +impl Add<&ScalarPrimitive> for ScalarPrimitive +where + C: Curve, +{ + type Output = Self; + + fn add(self, other: &Self) -> Self { + Self { + inner: self.inner.add_mod(&other.inner, &Self::MODULUS), + } + } +} + +impl AddAssign> for ScalarPrimitive +where + C: Curve, +{ + fn add_assign(&mut self, other: Self) { + *self = *self + other; + } +} + +impl AddAssign<&ScalarPrimitive> for ScalarPrimitive +where + C: Curve, +{ + fn add_assign(&mut self, other: &Self) { + *self = *self + other; + } +} + +impl Sub> for ScalarPrimitive +where + C: Curve, +{ + type Output = Self; + + fn sub(self, other: Self) -> Self { + self.sub(&other) + } +} + +impl Sub<&ScalarPrimitive> for ScalarPrimitive +where + C: Curve, +{ + type Output = Self; + + fn sub(self, other: &Self) -> Self { + Self { + inner: self.inner.sub_mod(&other.inner, &Self::MODULUS), + } + } +} + +impl SubAssign> for ScalarPrimitive +where + C: Curve, +{ + fn sub_assign(&mut self, other: Self) { + *self = *self - other; + } +} + +impl SubAssign<&ScalarPrimitive> for ScalarPrimitive +where + C: Curve, +{ + fn sub_assign(&mut self, other: &Self) { + *self = *self - other; + } +} + +impl Neg for ScalarPrimitive +where + C: Curve, +{ + type Output = Self; + + fn neg(self) -> Self { + Self { + inner: self.inner.neg_mod(&Self::MODULUS), + } + } +} + +impl Neg for &ScalarPrimitive +where + C: Curve, +{ + type Output = ScalarPrimitive; + + fn neg(self) -> ScalarPrimitive { + -*self + } +} + +impl ShrAssign for ScalarPrimitive +where + C: Curve, +{ + fn shr_assign(&mut self, rhs: usize) { + self.inner >>= rhs; + } +} + +impl IsHigh for ScalarPrimitive +where + C: Curve, +{ + fn is_high(&self) -> Choice { + let n_2 = C::ORDER >> 1; + self.inner.ct_gt(&n_2) + } +} + +impl fmt::Display for ScalarPrimitive +where + C: Curve, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{self:X}") + } +} + +impl fmt::LowerHex for ScalarPrimitive +where + C: Curve, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:x}", HexDisplay(&self.to_bytes())) + } +} + +impl fmt::UpperHex for ScalarPrimitive +where + C: Curve, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:X}", HexDisplay(&self.to_bytes())) + } +} + +impl str::FromStr for ScalarPrimitive +where + C: Curve, +{ + type Err = Error; + + fn from_str(hex: &str) -> Result { + let mut bytes = FieldBytes::::default(); + base16ct::lower::decode(hex, &mut bytes)?; + Self::from_slice(&bytes) + } +} + +#[cfg(feature = "serde")] +impl Serialize for ScalarPrimitive +where + C: Curve, +{ + fn serialize(&self, serializer: S) -> core::result::Result + where + S: ser::Serializer, + { + serdect::array::serialize_hex_upper_or_bin(&self.to_bytes(), serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, C> Deserialize<'de> for ScalarPrimitive +where + C: Curve, +{ + fn deserialize(deserializer: D) -> core::result::Result + where + D: de::Deserializer<'de>, + { + let mut bytes = FieldBytes::::default(); + serdect::array::deserialize_hex_or_bin(&mut bytes, deserializer)?; + Self::from_slice(&bytes).map_err(|_| de::Error::custom("scalar out of range")) + } +} diff --git a/src/rust/vendor/elliptic-curve/src/sec1.rs b/src/rust/vendor/elliptic-curve/src/sec1.rs new file mode 100644 index 000000000..5e1c07f96 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/sec1.rs @@ -0,0 +1,114 @@ +//! Support for SEC1 elliptic curve encoding formats. +//! +//! + +pub use sec1::point::{Coordinates, ModulusSize, Tag}; + +use crate::{Curve, FieldBytesSize, Result, SecretKey}; +use generic_array::GenericArray; +use subtle::CtOption; + +#[cfg(feature = "arithmetic")] +use crate::{AffinePoint, CurveArithmetic, Error}; + +/// Encoded elliptic curve point with point compression. +pub type CompressedPoint = GenericArray>; + +/// Size of a compressed elliptic curve point. +pub type CompressedPointSize = as ModulusSize>::CompressedPointSize; + +/// Encoded elliptic curve point sized appropriately for a given curve. +pub type EncodedPoint = sec1::point::EncodedPoint>; + +/// Encoded elliptic curve point *without* point compression. +pub type UncompressedPoint = GenericArray>; + +/// Size of an uncompressed elliptic curve point. +pub type UncompressedPointSize = as ModulusSize>::UncompressedPointSize; + +/// Trait for deserializing a value from a SEC1 encoded curve point. +/// +/// This is intended for use with the `AffinePoint` type for a given elliptic curve. +pub trait FromEncodedPoint +where + Self: Sized, + C: Curve, + FieldBytesSize: ModulusSize, +{ + /// Deserialize the type this trait is impl'd on from an [`EncodedPoint`]. + fn from_encoded_point(point: &EncodedPoint) -> CtOption; +} + +/// Trait for serializing a value to a SEC1 encoded curve point. +/// +/// This is intended for use with the `AffinePoint` type for a given elliptic curve. +pub trait ToEncodedPoint +where + C: Curve, + FieldBytesSize: ModulusSize, +{ + /// Serialize this value as a SEC1 [`EncodedPoint`], optionally applying + /// point compression. + fn to_encoded_point(&self, compress: bool) -> EncodedPoint; +} + +/// Trait for serializing a value to a SEC1 encoded curve point with compaction. +/// +/// This is intended for use with the `AffinePoint` type for a given elliptic curve. +pub trait ToCompactEncodedPoint +where + C: Curve, + FieldBytesSize: ModulusSize, +{ + /// Serialize this value as a SEC1 [`EncodedPoint`], optionally applying + /// point compression. + fn to_compact_encoded_point(&self) -> CtOption>; +} + +/// Validate that the given [`EncodedPoint`] represents the encoded public key +/// value of the given secret. +/// +/// Curve implementations which also impl [`CurveArithmetic`] will receive +/// a blanket default impl of this trait. +pub trait ValidatePublicKey +where + Self: Curve, + FieldBytesSize: ModulusSize, +{ + /// Validate that the given [`EncodedPoint`] is a valid public key for the + /// provided secret value. + #[allow(unused_variables)] + fn validate_public_key( + secret_key: &SecretKey, + public_key: &EncodedPoint, + ) -> Result<()> { + // Provide a default "always succeeds" implementation. + // This is the intended default for curve implementations which + // do not provide an arithmetic implementation, since they have no + // way to verify this. + // + // Implementations with an arithmetic impl will receive a blanket impl + // of this trait. + Ok(()) + } +} + +#[cfg(feature = "arithmetic")] +impl ValidatePublicKey for C +where + C: CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + fn validate_public_key(secret_key: &SecretKey, public_key: &EncodedPoint) -> Result<()> { + let pk = secret_key + .public_key() + .to_encoded_point(public_key.is_compressed()); + + if public_key == &pk { + Ok(()) + } else { + Err(Error) + } + } +} diff --git a/src/rust/vendor/elliptic-curve/src/secret_key.rs b/src/rust/vendor/elliptic-curve/src/secret_key.rs new file mode 100644 index 000000000..198fd66e0 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/secret_key.rs @@ -0,0 +1,386 @@ +//! Secret keys for elliptic curves (i.e. private scalars). +//! +//! The [`SecretKey`] type is a wrapper around a secret scalar value which is +//! designed to prevent unintentional exposure (e.g. via `Debug` or other +//! logging). It also handles zeroing the secret value out of memory securely +//! on drop. + +#[cfg(all(feature = "pkcs8", feature = "sec1"))] +mod pkcs8; + +use crate::{Curve, Error, FieldBytes, Result, ScalarPrimitive}; +use core::fmt::{self, Debug}; +use generic_array::typenum::Unsigned; +use subtle::{Choice, ConstantTimeEq}; +use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing}; + +#[cfg(feature = "arithmetic")] +use crate::{rand_core::CryptoRngCore, CurveArithmetic, NonZeroScalar, PublicKey}; + +#[cfg(feature = "jwk")] +use crate::jwk::{JwkEcKey, JwkParameters}; + +#[cfg(feature = "pem")] +use pem_rfc7468::{self as pem, PemLabel}; + +#[cfg(feature = "sec1")] +use { + crate::{ + sec1::{EncodedPoint, ModulusSize, ValidatePublicKey}, + FieldBytesSize, + }, + sec1::der, +}; + +#[cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1"))] +use { + crate::{ + sec1::{FromEncodedPoint, ToEncodedPoint}, + AffinePoint, + }, + alloc::vec::Vec, + sec1::der::Encode, +}; + +#[cfg(all(feature = "arithmetic", any(feature = "jwk", feature = "pem")))] +use alloc::string::String; + +#[cfg(all(feature = "arithmetic", feature = "jwk"))] +use alloc::string::ToString; + +#[cfg(all(doc, feature = "pkcs8"))] +use {crate::pkcs8::DecodePrivateKey, core::str::FromStr}; + +/// Elliptic curve secret keys. +/// +/// This type wraps a secret scalar value, helping to prevent accidental +/// exposure and securely erasing the value from memory when dropped. +/// +/// # Parsing PKCS#8 Keys +/// +/// PKCS#8 is a commonly used format for encoding secret keys (especially ones +/// generated by OpenSSL). +/// +/// Keys in PKCS#8 format are either binary (ASN.1 BER/DER), or PEM encoded +/// (ASCII) and begin with the following: +/// +/// ```text +/// -----BEGIN PRIVATE KEY----- +/// ``` +/// +/// To decode an elliptic curve private key from PKCS#8, enable the `pkcs8` +/// feature of this crate (or the `pkcs8` feature of a specific RustCrypto +/// elliptic curve crate) and use the [`DecodePrivateKey`] trait to parse it. +/// +/// When the `pem` feature of this crate (or a specific RustCrypto elliptic +/// curve crate) is enabled, a [`FromStr`] impl is also available. +#[derive(Clone)] +pub struct SecretKey { + /// Scalar value + inner: ScalarPrimitive, +} + +impl SecretKey +where + C: Curve, +{ + /// Minimum allowed size of an elliptic curve secret key in bytes. + /// + /// This provides the equivalent of 96-bits of symmetric security. + const MIN_SIZE: usize = 24; + + /// Generate a random [`SecretKey`]. + #[cfg(feature = "arithmetic")] + pub fn random(rng: &mut impl CryptoRngCore) -> Self + where + C: CurveArithmetic, + { + Self { + inner: NonZeroScalar::::random(rng).into(), + } + } + + /// Create a new secret key from a scalar value. + pub fn new(scalar: ScalarPrimitive) -> Self { + Self { inner: scalar } + } + + /// Borrow the inner secret [`ScalarPrimitive`] value. + /// + /// # ⚠️ Warning + /// + /// This value is key material. + /// + /// Please treat it with the care it deserves! + pub fn as_scalar_primitive(&self) -> &ScalarPrimitive { + &self.inner + } + + /// Get the secret [`NonZeroScalar`] value for this key. + /// + /// # ⚠️ Warning + /// + /// This value is key material. + /// + /// Please treat it with the care it deserves! + #[cfg(feature = "arithmetic")] + pub fn to_nonzero_scalar(&self) -> NonZeroScalar + where + C: CurveArithmetic, + { + self.into() + } + + /// Get the [`PublicKey`] which corresponds to this secret key + #[cfg(feature = "arithmetic")] + pub fn public_key(&self) -> PublicKey + where + C: CurveArithmetic, + { + PublicKey::from_secret_scalar(&self.to_nonzero_scalar()) + } + + /// Deserialize secret key from an encoded secret scalar. + pub fn from_bytes(bytes: &FieldBytes) -> Result { + let inner: ScalarPrimitive = + Option::from(ScalarPrimitive::from_bytes(bytes)).ok_or(Error)?; + + if inner.is_zero().into() { + return Err(Error); + } + + Ok(Self { inner }) + } + + /// Deserialize secret key from an encoded secret scalar passed as a byte slice. + /// + /// The slice is expected to be a minimum of 24-bytes (192-byts) and at most `C::FieldBytesSize` + /// bytes in length. + /// + /// Byte slices shorter than the field size are handled by zero padding the input. + pub fn from_slice(slice: &[u8]) -> Result { + if slice.len() == C::FieldBytesSize::USIZE { + Self::from_bytes(FieldBytes::::from_slice(slice)) + } else if (Self::MIN_SIZE..C::FieldBytesSize::USIZE).contains(&slice.len()) { + let mut bytes = Zeroizing::new(FieldBytes::::default()); + let offset = C::FieldBytesSize::USIZE.saturating_sub(slice.len()); + bytes[offset..].copy_from_slice(slice); + Self::from_bytes(&bytes) + } else { + Err(Error) + } + } + + /// Serialize raw secret scalar as a big endian integer. + pub fn to_bytes(&self) -> FieldBytes { + self.inner.to_bytes() + } + + /// Deserialize secret key encoded in the SEC1 ASN.1 DER `ECPrivateKey` format. + #[cfg(feature = "sec1")] + pub fn from_sec1_der(der_bytes: &[u8]) -> Result + where + C: Curve + ValidatePublicKey, + FieldBytesSize: ModulusSize, + { + sec1::EcPrivateKey::try_from(der_bytes)? + .try_into() + .map_err(|_| Error) + } + + /// Serialize secret key in the SEC1 ASN.1 DER `ECPrivateKey` format. + #[cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1"))] + pub fn to_sec1_der(&self) -> der::Result>> + where + C: CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, + { + let private_key_bytes = Zeroizing::new(self.to_bytes()); + let public_key_bytes = self.public_key().to_encoded_point(false); + + let ec_private_key = Zeroizing::new( + sec1::EcPrivateKey { + private_key: &private_key_bytes, + parameters: None, + public_key: Some(public_key_bytes.as_bytes()), + } + .to_der()?, + ); + + Ok(ec_private_key) + } + + /// Parse [`SecretKey`] from PEM-encoded SEC1 `ECPrivateKey` format. + /// + /// PEM-encoded SEC1 keys can be identified by the leading delimiter: + /// + /// ```text + /// -----BEGIN EC PRIVATE KEY----- + /// ``` + #[cfg(feature = "pem")] + pub fn from_sec1_pem(s: &str) -> Result + where + C: Curve + ValidatePublicKey, + FieldBytesSize: ModulusSize, + { + let (label, der_bytes) = pem::decode_vec(s.as_bytes()).map_err(|_| Error)?; + + if label != sec1::EcPrivateKey::PEM_LABEL { + return Err(Error); + } + + Self::from_sec1_der(&der_bytes).map_err(|_| Error) + } + + /// Serialize private key as self-zeroizing PEM-encoded SEC1 `ECPrivateKey` + /// with the given [`pem::LineEnding`]. + /// + /// Pass `Default::default()` to use the OS's native line endings. + #[cfg(feature = "pem")] + pub fn to_sec1_pem(&self, line_ending: pem::LineEnding) -> Result> + where + C: CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, + { + self.to_sec1_der() + .ok() + .and_then(|der| { + pem::encode_string(sec1::EcPrivateKey::PEM_LABEL, line_ending, &der).ok() + }) + .map(Zeroizing::new) + .ok_or(Error) + } + + /// Parse a [`JwkEcKey`] JSON Web Key (JWK) into a [`SecretKey`]. + #[cfg(feature = "jwk")] + pub fn from_jwk(jwk: &JwkEcKey) -> Result + where + C: JwkParameters + ValidatePublicKey, + FieldBytesSize: ModulusSize, + { + Self::try_from(jwk) + } + + /// Parse a string containing a JSON Web Key (JWK) into a [`SecretKey`]. + #[cfg(feature = "jwk")] + pub fn from_jwk_str(jwk: &str) -> Result + where + C: JwkParameters + ValidatePublicKey, + FieldBytesSize: ModulusSize, + { + jwk.parse::().and_then(|jwk| Self::from_jwk(&jwk)) + } + + /// Serialize this secret key as [`JwkEcKey`] JSON Web Key (JWK). + #[cfg(all(feature = "arithmetic", feature = "jwk"))] + pub fn to_jwk(&self) -> JwkEcKey + where + C: CurveArithmetic + JwkParameters, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, + { + self.into() + } + + /// Serialize this secret key as JSON Web Key (JWK) string. + #[cfg(all(feature = "arithmetic", feature = "jwk"))] + pub fn to_jwk_string(&self) -> Zeroizing + where + C: CurveArithmetic + JwkParameters, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, + { + Zeroizing::new(self.to_jwk().to_string()) + } +} + +impl ConstantTimeEq for SecretKey +where + C: Curve, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.inner.ct_eq(&other.inner) + } +} + +impl Debug for SecretKey +where + C: Curve, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct(core::any::type_name::()) + .finish_non_exhaustive() + } +} + +impl ZeroizeOnDrop for SecretKey where C: Curve {} + +impl Drop for SecretKey +where + C: Curve, +{ + fn drop(&mut self) { + self.inner.zeroize(); + } +} + +impl Eq for SecretKey {} + +impl PartialEq for SecretKey +where + C: Curve, +{ + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } +} + +#[cfg(feature = "sec1")] +impl TryFrom> for SecretKey +where + C: Curve + ValidatePublicKey, + FieldBytesSize: ModulusSize, +{ + type Error = der::Error; + + fn try_from(sec1_private_key: sec1::EcPrivateKey<'_>) -> der::Result { + let secret_key = Self::from_slice(sec1_private_key.private_key) + .map_err(|_| der::Tag::Sequence.value_error())?; + + // TODO(tarcieri): validate `sec1_private_key.params`? + if let Some(pk_bytes) = sec1_private_key.public_key { + let pk = EncodedPoint::::from_bytes(pk_bytes) + .map_err(|_| der::Tag::BitString.value_error())?; + + if C::validate_public_key(&secret_key, &pk).is_err() { + return Err(der::Tag::BitString.value_error()); + } + } + + Ok(secret_key) + } +} + +#[cfg(feature = "arithmetic")] +impl From> for SecretKey +where + C: CurveArithmetic, +{ + fn from(scalar: NonZeroScalar) -> SecretKey { + SecretKey::from(&scalar) + } +} + +#[cfg(feature = "arithmetic")] +impl From<&NonZeroScalar> for SecretKey +where + C: CurveArithmetic, +{ + fn from(scalar: &NonZeroScalar) -> SecretKey { + SecretKey { + inner: scalar.into(), + } + } +} diff --git a/src/rust/vendor/elliptic-curve/src/secret_key/pkcs8.rs b/src/rust/vendor/elliptic-curve/src/secret_key/pkcs8.rs new file mode 100644 index 000000000..92c81f18a --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/secret_key/pkcs8.rs @@ -0,0 +1,90 @@ +//! PKCS#8 encoding/decoding support. + +use super::SecretKey; +use crate::{ + pkcs8::{self, der::Decode, AssociatedOid}, + sec1::{ModulusSize, ValidatePublicKey}, + Curve, FieldBytesSize, ALGORITHM_OID, +}; +use pkcs8::spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, ObjectIdentifier}; +use sec1::EcPrivateKey; + +// Imports for the `EncodePrivateKey` impl +#[cfg(all(feature = "alloc", feature = "arithmetic"))] +use { + crate::{ + sec1::{FromEncodedPoint, ToEncodedPoint}, + AffinePoint, CurveArithmetic, + }, + pkcs8::{der, EncodePrivateKey}, +}; + +// Imports for actual PEM support +#[cfg(feature = "pem")] +use { + crate::{error::Error, Result}, + core::str::FromStr, + pkcs8::DecodePrivateKey, +}; + +impl AssociatedAlgorithmIdentifier for SecretKey +where + C: AssociatedOid + Curve, +{ + type Params = ObjectIdentifier; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifier = AlgorithmIdentifier { + oid: ALGORITHM_OID, + parameters: Some(C::OID), + }; +} + +impl TryFrom> for SecretKey +where + C: AssociatedOid + Curve + ValidatePublicKey, + FieldBytesSize: ModulusSize, +{ + type Error = pkcs8::Error; + + fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result { + private_key_info + .algorithm + .assert_oids(ALGORITHM_OID, C::OID)?; + + let ec_private_key = EcPrivateKey::from_der(private_key_info.private_key)?; + Ok(Self::try_from(ec_private_key)?) + } +} + +#[cfg(all(feature = "alloc", feature = "arithmetic"))] +impl EncodePrivateKey for SecretKey +where + C: AssociatedOid + CurveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, +{ + fn to_pkcs8_der(&self) -> pkcs8::Result { + // TODO(tarcieri): make `PrivateKeyInfo` generic around `Params` + let algorithm_identifier = pkcs8::AlgorithmIdentifierRef { + oid: ALGORITHM_OID, + parameters: Some((&C::OID).into()), + }; + + let ec_private_key = self.to_sec1_der()?; + let pkcs8_key = pkcs8::PrivateKeyInfo::new(algorithm_identifier, &ec_private_key); + Ok(der::SecretDocument::encode_msg(&pkcs8_key)?) + } +} + +#[cfg(feature = "pem")] +impl FromStr for SecretKey +where + C: Curve + AssociatedOid + ValidatePublicKey, + FieldBytesSize: ModulusSize, +{ + type Err = Error; + + fn from_str(s: &str) -> Result { + Self::from_pkcs8_pem(s).map_err(|_| Error) + } +} diff --git a/src/rust/vendor/elliptic-curve/src/voprf.rs b/src/rust/vendor/elliptic-curve/src/voprf.rs new file mode 100644 index 000000000..68f2abf18 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/voprf.rs @@ -0,0 +1,20 @@ +//! Verifiable Oblivious Pseudorandom Function (VOPRF) using prime order groups +//! +//! + +use crate::PrimeCurve; + +/// Elliptic curve parameters used by VOPRF. +pub trait VoprfParameters: PrimeCurve { + /// The `ID` parameter which identifies a particular elliptic curve + /// as defined in [section 4 of `draft-irtf-cfrg-voprf-19`][voprf]. + /// + /// [voprf]: https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-19.html#name-ciphersuites-2 + const ID: &'static str; + + /// The `Hash` parameter which assigns a particular hash function to this + /// ciphersuite as defined in [section 4 of `draft-irtf-cfrg-voprf-19`][voprf]. + /// + /// [voprf]: https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-19.html#name-ciphersuites-2 + type Hash: digest::Digest; +} diff --git a/src/rust/vendor/elliptic-curve/src/weierstrass.rs b/src/rust/vendor/elliptic-curve/src/weierstrass.rs new file mode 100644 index 000000000..1782d95e1 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/src/weierstrass.rs @@ -0,0 +1,128 @@ +//! Complete projective formulas for prime order elliptic curves as described +//! in [Renes-Costello-Batina 2015]. +//! +//! [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060 + +#![allow(clippy::op_ref)] + +use ff::Field; + +/// Affine point whose coordinates are represented by the given field element. +pub type AffinePoint = (Fe, Fe); + +/// Projective point whose coordinates are represented by the given field element. +pub type ProjectivePoint = (Fe, Fe, Fe); + +/// Implements the complete addition formula from [Renes-Costello-Batina 2015] +/// (Algorithm 4). +/// +/// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060 +#[inline(always)] +pub fn add( + (ax, ay, az): ProjectivePoint, + (bx, by, bz): ProjectivePoint, + curve_equation_b: Fe, +) -> ProjectivePoint +where + Fe: Field, +{ + // The comments after each line indicate which algorithm steps are being + // performed. + let xx = ax * bx; // 1 + let yy = ay * by; // 2 + let zz = az * bz; // 3 + let xy_pairs = ((ax + ay) * &(bx + by)) - &(xx + &yy); // 4, 5, 6, 7, 8 + let yz_pairs = ((ay + az) * &(by + bz)) - &(yy + &zz); // 9, 10, 11, 12, 13 + let xz_pairs = ((ax + az) * &(bx + bz)) - &(xx + &zz); // 14, 15, 16, 17, 18 + + let bzz_part = xz_pairs - &(curve_equation_b * &zz); // 19, 20 + let bzz3_part = bzz_part.double() + &bzz_part; // 21, 22 + let yy_m_bzz3 = yy - &bzz3_part; // 23 + let yy_p_bzz3 = yy + &bzz3_part; // 24 + + let zz3 = zz.double() + &zz; // 26, 27 + let bxz_part = (curve_equation_b * &xz_pairs) - &(zz3 + &xx); // 25, 28, 29 + let bxz3_part = bxz_part.double() + &bxz_part; // 30, 31 + let xx3_m_zz3 = xx.double() + &xx - &zz3; // 32, 33, 34 + + ( + (yy_p_bzz3 * &xy_pairs) - &(yz_pairs * &bxz3_part), // 35, 39, 40 + (yy_p_bzz3 * &yy_m_bzz3) + &(xx3_m_zz3 * &bxz3_part), // 36, 37, 38 + (yy_m_bzz3 * &yz_pairs) + &(xy_pairs * &xx3_m_zz3), // 41, 42, 43 + ) +} + +/// Implements the complete mixed addition formula from +/// [Renes-Costello-Batina 2015] (Algorithm 5). +/// +/// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060 +#[inline(always)] +pub fn add_mixed( + (ax, ay, az): ProjectivePoint, + (bx, by): AffinePoint, + curve_equation_b: Fe, +) -> ProjectivePoint +where + Fe: Field, +{ + // The comments after each line indicate which algorithm steps are being + // performed. + let xx = ax * &bx; // 1 + let yy = ay * &by; // 2 + let xy_pairs = ((ax + &ay) * &(bx + &by)) - &(xx + &yy); // 3, 4, 5, 6, 7 + let yz_pairs = (by * &az) + &ay; // 8, 9 (t4) + let xz_pairs = (bx * &az) + &ax; // 10, 11 (y3) + + let bz_part = xz_pairs - &(curve_equation_b * &az); // 12, 13 + let bz3_part = bz_part.double() + &bz_part; // 14, 15 + let yy_m_bzz3 = yy - &bz3_part; // 16 + let yy_p_bzz3 = yy + &bz3_part; // 17 + + let z3 = az.double() + &az; // 19, 20 + let bxz_part = (curve_equation_b * &xz_pairs) - &(z3 + &xx); // 18, 21, 22 + let bxz3_part = bxz_part.double() + &bxz_part; // 23, 24 + let xx3_m_zz3 = xx.double() + &xx - &z3; // 25, 26, 27 + + ( + (yy_p_bzz3 * &xy_pairs) - &(yz_pairs * &bxz3_part), // 28, 32, 33 + (yy_p_bzz3 * &yy_m_bzz3) + &(xx3_m_zz3 * &bxz3_part), // 29, 30, 31 + (yy_m_bzz3 * &yz_pairs) + &(xy_pairs * &xx3_m_zz3), // 34, 35, 36 + ) +} + +/// Implements the exception-free point doubling formula from +/// [Renes-Costello-Batina 2015] (Algorithm 6). +/// +/// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060 +#[inline(always)] +pub fn double((x, y, z): ProjectivePoint, curve_equation_b: Fe) -> ProjectivePoint +where + Fe: Field, +{ + // The comments after each line indicate which algorithm steps are being + // performed. + let xx = x.square(); // 1 + let yy = y.square(); // 2 + let zz = z.square(); // 3 + let xy2 = (x * &y).double(); // 4, 5 + let xz2 = (x * &z).double(); // 6, 7 + + let bzz_part = (curve_equation_b * &zz) - &xz2; // 8, 9 + let bzz3_part = bzz_part.double() + &bzz_part; // 10, 11 + let yy_m_bzz3 = yy - &bzz3_part; // 12 + let yy_p_bzz3 = yy + &bzz3_part; // 13 + let y_frag = yy_p_bzz3 * &yy_m_bzz3; // 14 + let x_frag = yy_m_bzz3 * &xy2; // 15 + + let zz3 = zz.double() + &zz; // 16, 17 + let bxz2_part = (curve_equation_b * &xz2) - &(zz3 + &xx); // 18, 19, 20 + let bxz6_part = bxz2_part.double() + &bxz2_part; // 21, 22 + let xx3_m_zz3 = xx.double() + &xx - &zz3; // 23, 24, 25 + + let dy = y_frag + &(xx3_m_zz3 * &bxz6_part); // 26, 27 + let yz2 = (y * &z).double(); // 28, 29 + let dx = x_frag - &(bxz6_part * &yz2); // 30, 31 + let dz = (yz2 * &yy).double().double(); // 32, 33, 34 + + (dx, dy, dz) +} diff --git a/src/rust/vendor/elliptic-curve/tests/examples/pkcs8-private-key.der b/src/rust/vendor/elliptic-curve/tests/examples/pkcs8-private-key.der new file mode 100644 index 000000000..c0de45ef2 Binary files /dev/null and b/src/rust/vendor/elliptic-curve/tests/examples/pkcs8-private-key.der differ diff --git a/src/rust/vendor/elliptic-curve/tests/examples/pkcs8-private-key.pem b/src/rust/vendor/elliptic-curve/tests/examples/pkcs8-private-key.pem new file mode 100644 index 000000000..62f432c74 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/tests/examples/pkcs8-private-key.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgaWJBcVYaYzQN4OfY +afKgVJJVjhoEhotqn4VKhmeIGI2hRANCAAQcrP+1Xy8s79idies3SyaBFSRSgC3u +oJkWBoE32DnPf8SBpESSME1+9mrBF77+g6jQjxVfK1L59hjdRHApBI4P +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/src/rust/vendor/elliptic-curve/tests/examples/pkcs8-public-key.der b/src/rust/vendor/elliptic-curve/tests/examples/pkcs8-public-key.der new file mode 100644 index 000000000..67c719c76 Binary files /dev/null and b/src/rust/vendor/elliptic-curve/tests/examples/pkcs8-public-key.der differ diff --git a/src/rust/vendor/elliptic-curve/tests/examples/pkcs8-public-key.pem b/src/rust/vendor/elliptic-curve/tests/examples/pkcs8-public-key.pem new file mode 100644 index 000000000..ee7e5b612 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/tests/examples/pkcs8-public-key.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHKz/tV8vLO/YnYnrN0smgRUkUoAt +7qCZFgaBN9g5z3/EgaREkjBNfvZqwRe+/oOo0I8VXytS+fYY3URwKQSODw== +-----END PUBLIC KEY----- diff --git a/src/rust/vendor/elliptic-curve/tests/pkcs8.rs b/src/rust/vendor/elliptic-curve/tests/pkcs8.rs new file mode 100644 index 000000000..2a27fc0c7 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/tests/pkcs8.rs @@ -0,0 +1,57 @@ +//! PKCS#8 tests + +#![cfg(all(feature = "dev", feature = "pkcs8"))] + +use elliptic_curve::{ + dev::{PublicKey, SecretKey}, + pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey}, + sec1::ToEncodedPoint, +}; +use hex_literal::hex; +use pkcs8::der; + +/// DER-encoded PKCS#8 public key +const PKCS8_PUBLIC_KEY_DER: &[u8; 91] = include_bytes!("examples/pkcs8-public-key.der"); + +/// PEM-encoded PKCS#8 public key +#[cfg(feature = "pem")] +const PKCS8_PUBLIC_KEY_PEM: &str = include_str!("examples/pkcs8-public-key.pem"); + +/// Example encoded scalar value +const EXAMPLE_SCALAR: [u8; 32] = + hex!("AABBCCDDEEFF0000000000000000000000000000000000000000000000000001"); + +/// Example PKCS#8 private key +fn example_private_key() -> der::SecretDocument { + SecretKey::from_slice(&EXAMPLE_SCALAR) + .unwrap() + .to_pkcs8_der() + .unwrap() +} + +#[test] +fn decode_pkcs8_private_key_from_der() { + dbg!(example_private_key().as_bytes()); + let secret_key = SecretKey::from_pkcs8_der(example_private_key().as_bytes()).unwrap(); + assert_eq!(secret_key.to_bytes().as_slice(), &EXAMPLE_SCALAR); +} + +#[test] +fn decode_pkcs8_public_key_from_der() { + let public_key = PublicKey::from_public_key_der(&PKCS8_PUBLIC_KEY_DER[..]).unwrap(); + let expected_sec1_point = hex!("041CACFFB55F2F2CEFD89D89EB374B2681152452802DEEA09916068137D839CF7FC481A44492304D7EF66AC117BEFE83A8D08F155F2B52F9F618DD447029048E0F"); + assert_eq!( + public_key.to_encoded_point(false).as_bytes(), + &expected_sec1_point[..] + ); +} + +#[test] +#[cfg(feature = "pem")] +fn decode_pkcs8_public_key_from_pem() { + let public_key = PKCS8_PUBLIC_KEY_PEM.parse::().unwrap(); + + // Ensure key parses equivalently to DER + let der_key = PublicKey::from_public_key_der(&PKCS8_PUBLIC_KEY_DER[..]).unwrap(); + assert_eq!(public_key, der_key); +} diff --git a/src/rust/vendor/elliptic-curve/tests/secret_key.rs b/src/rust/vendor/elliptic-curve/tests/secret_key.rs new file mode 100644 index 000000000..7be475143 --- /dev/null +++ b/src/rust/vendor/elliptic-curve/tests/secret_key.rs @@ -0,0 +1,28 @@ +//! Secret key tests + +#![cfg(feature = "dev")] + +use elliptic_curve::dev::SecretKey; + +#[test] +fn from_empty_slice() { + assert!(SecretKey::from_slice(&[]).is_err()); +} + +#[test] +fn from_slice_expected_size() { + let bytes = [1u8; 32]; + assert!(SecretKey::from_slice(&bytes).is_ok()); +} + +#[test] +fn from_slice_allowed_short() { + let bytes = [1u8; 24]; + assert!(SecretKey::from_slice(&bytes).is_ok()); +} + +#[test] +fn from_slice_too_short() { + let bytes = [1u8; 23]; // min 24-bytes + assert!(SecretKey::from_slice(&bytes).is_err()); +} diff --git a/src/rust/vendor/ff/.cargo-checksum.json b/src/rust/vendor/ff/.cargo-checksum.json new file mode 100644 index 000000000..68cbebdc0 --- /dev/null +++ b/src/rust/vendor/ff/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"95147d70e59182c9e0b5dcbaab84a4355a244c3119ce8b5444077f1cc4eb2e0f","Cargo.toml":"ac2c92528fb510384b9d1ccc35bd18ba911d2ee8b31864f93a3af2ae620c6abe","LICENSE-APACHE":"3708458dee7f359ac6c9c5558023ed481be87e5372c43ebd7f2ca7ad23c12026","LICENSE-MIT":"8d0c1d1d4b2bebf5b9211f0e883d5a482b7808f3ed31320da14ddee95811f4ef","README.md":"adca6fa00b585205cb37d9001e560db4610de8bc67c1675622376fad18254070","rust-toolchain":"19f1c71cabd3cb062544023af771fbb2883524775fdaed6ca5855bae359b7b9c","src/batch.rs":"22714992ecdf6ef453072873a39371df42fa52c75810cce164808f1665b2b0d2","src/helpers.rs":"1ef4269d4e1a5c5a66c40df4040854f9964547e2bd78dfa99b52e2121023f161","src/lib.rs":"e4eddbc13cb8776db047b448ea71992f6b2f2f327d9b01ca09e701aa0c6b1a27","tests/derive.rs":"4d8014b8a96fc963ec47f157d38e13d35eda4d04b88ce5b60216dfe59095b880"},"package":"ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"} \ No newline at end of file diff --git a/src/rust/vendor/ff/CHANGELOG.md b/src/rust/vendor/ff/CHANGELOG.md new file mode 100644 index 000000000..9188fcf0c --- /dev/null +++ b/src/rust/vendor/ff/CHANGELOG.md @@ -0,0 +1,143 @@ +# Changelog +All notable changes to this library will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this library adheres to Rust's notion of +[Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.13.0] - 2022-12-06 +### Added +- `ff::Field::{ZERO, ONE}` +- `ff::Field::pow` +- `ff::Field::{sqrt_ratio, sqrt_alt}` +- `core::iter::{Sum, Product}` bounds on `ff::Field` +- `ff::PrimeField::from_u128` +- `ff::PrimeField::{MODULUS, TWO_INV}` +- Constants related to multiplicative generators: + - `ff::PrimeField::MULTIPLICATIVE_GENERATOR` + - `ff::PrimeField::{ROOT_OF_UNITY, ROOT_OF_UNITY_INV}` + - `ff::PrimeField::DELTA` +- `ff::WithSmallOrderMulGroup` +- `ff::FromUniformBytes` +- `ff::helpers`: + - `sqrt_tonelli_shanks` + - `sqrt_ratio_generic` + +### Changed +- `ff::Field::sqrt` is now a provided method that uses the `Field::sqrt_ratio` + method. Implementors of the `Field` trait can choose to implement + `Field::sqrt_ratio` and use the provided `ff::Field::sqrt` method, especially + if it is more efficient in practice, or they can keep their own implementation + of `Field::sqrt` and implement `Field::sqrt_ratio` in terms of that + implementation using the `ff::helpers::sqrt_ratio_generic` helper function. +- `ff::PrimeField` is now documented as representing a non-binary field (i.e. + its prime is not 2). This was always the intention, but is now a concrete + requirement in order for `PrimeField::TWO_INV` to exist. + +### Removed +- `ff::Field::{zero, one}` (use `ff::Field::{ZERO, ONE}` instead). +- `ff::PrimeField::{multiplicative_generator, root_of_unity}` (use + `ff::PrimeField::{MULTIPLICATIVE_GENERATOR, ROOT_OF_UNITY}` instead). + +## [0.12.1] - 2022-10-28 +### Fixed +- `ff_derive` previously generated a `Field::random` implementation that would + overflow for fields that needed a full 64-bit spare limb. + +## [0.12.0] - 2022-05-04 +### Changed + +- MSRV is now 1.56.0. +- Bumped `bitvec` to 1.0. + +## [0.11.1] - 2022-05-04 +### Fixed +- `ff_derive` procedural macro can now be invoked within regular macros. +- Previously, `ff_derive`'s procedural macro would generate implementations of + `PrimeFieldBits` even when the `bits` crate feature was disabled. `ff_derive` + can now be used without a dependency on `bitvec` by disabling feature + features. The new crate feature `derive_bits` can be used to force the + generation of `PrimeFieldBits` implementations. This new crate feature will be + removed once our MSRV is at least 1.60 and we have access to [weak dependency + features](https://blog.rust-lang.org/2022/04/07/Rust-1.60.0.html#new-syntax-for-cargo-features). + +## [0.11.0] - 2021-09-02 +### Added +- `subtle::ConstantTimeEq` bound on `ff::Field` +- `Copy + Send + Sync + 'static` bounds on `ff::PrimeField::Repr` +- `ff::derive` module behind the `derive` feature flag, containing dependencies for the + `PrimeField` derive macro: + - Re-exports of required crates. + - `adc, mac, sbb` constant-time const helper functions. +- `ff::Field::is_zero_vartime` +- `ff::PrimeField::from_repr_vartime` + +### Changed +- `ff::Field::is_zero` now returns `subtle::Choice`. +- `ff::PrimeField::{is_odd, is_even}` now return `subtle::Choice`. +- `ff::PrimeField::from_repr` now return `subtle::CtOption`. +- `ff::PrimeField::from_str` has been renamed to `PrimeField::from_str_vartime`. + +### Removed +- `ff::{adc, mac_with_carry, sbb}` (replaced by `ff::derive::{adc, mac, sbb}`). + +## [0.10.1] - 2021-08-11 +### Added +- `ff::BatchInvert` extension trait, implemented for iterators over mutable field elements + which allows those field elements to be inverted in a batch. This trait is behind the + new `alloc` feature flag. +- `ff::BatchInverter` struct, which provides methods for non-allocating batch inversion of + field elements contained within slices. + +## [0.10.0] - 2021-06-01 +### Added +- `ff::PrimeFieldBits: PrimeField` trait, behind a `bits` feature flag. + +### Changed +- MSRV is now 1.51.0. +- Bumped `bitvec` to 0.22 to enable fixing a performance regression in `ff 0.9`. + The `bitvec::view::BitView` re-export has been replaced by + `bitvec::view::BitViewSized`. +- The `bitvec` dependency and its re-exports have been gated behind the `bits` + feature flag. + +### Removed +- `ff::PrimeField::{ReprBits, char_le_bits, to_le_bits}` (replaced by + `ff::PrimeFieldBits` trait). + +### Fixed +- `#[derive(PrimeField)]` now works on small moduli (that fit in a single `u64` + limb). + +## [0.9.0] - 2021-01-05 +### Added +- Re-export of `bitvec::view::BitView`. +- `ff::FieldBits` type alias for the return type of + `ff::PrimeField::{char_le_bits, to_le_bits}`. + +### Changed +- Bumped `bitvec` to 0.20, `rand_core` to 0.6. + +### Removed +- `From` and `From<&Self>` bounds on `ff::PrimeField::Repr`. + +## [0.8.0] - 2020-09-08 +### Added +- `ff::PrimeField::{ReprBits, char_le_bits, to_le_bits}`, and a public + dependency on `bitvec 0.18`. +- `ff::Field::cube` method with provided implementation. +- `Send + Sync` bounds on `ff::PrimeField::ReprBits` + +### Changed +- MSRV is now 1.44.0. +- `ff::Field::random(rng: &mut R) -> Self` has been changed + to `Field::random(rng: impl RngCore) -> Self`, to aligh with + `group::Group::random`. + +### Removed +- `fmt::Display` bound on `ff::Field`. +- `ff::PrimeField::char` (replaced by `ff::PrimeField::char_le_bits`). +- `ff::{BitIterator, Endianness, PrimeField::ReprEndianness` (replaced by + `ff::PrimeField::to_le_bits`). diff --git a/src/rust/vendor/ff/Cargo.toml b/src/rust/vendor/ff/Cargo.toml new file mode 100644 index 000000000..65758494a --- /dev/null +++ b/src/rust/vendor/ff/Cargo.toml @@ -0,0 +1,67 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "ff" +version = "0.13.0" +authors = ["Sean Bowe ", "Jack Grigg "] +description = "Library for building and interfacing with finite fields" +homepage = "https://github.com/zkcrypto/ff" +documentation = "https://docs.rs/ff/" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/zkcrypto/ff" +resolver = "2" +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[[test]] +name = "derive" +required-features = ["derive"] +[dependencies.bitvec] +version = "1" +optional = true +default-features = false + +[dependencies.byteorder] +version = "1" +optional = true +default-features = false + +[dependencies.ff_derive] +version = "0.13" +optional = true + +[dependencies.rand_core] +version = "0.6" +default-features = false + +[dependencies.subtle] +version = "2.2.1" +features = ["i128"] +default-features = false +[dev-dependencies.blake2b_simd] +version = "1" + +[dev-dependencies.rand] +version = "0.8" + +[features] +alloc = [] +bits = ["bitvec"] +default = ["bits", "std"] +derive = ["byteorder", "ff_derive"] +derive_bits = ["bits", "ff_derive/bits"] +std = ["alloc"] +[badges.maintenance] +status = "actively-developed" diff --git a/src/rust/vendor/ff/LICENSE-APACHE b/src/rust/vendor/ff/LICENSE-APACHE new file mode 100644 index 000000000..1e5006dc1 --- /dev/null +++ b/src/rust/vendor/ff/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + diff --git a/src/rust/vendor/ff/LICENSE-MIT b/src/rust/vendor/ff/LICENSE-MIT new file mode 100644 index 000000000..ed3a13fdd --- /dev/null +++ b/src/rust/vendor/ff/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Sean Bowe + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/rust/vendor/ff/README.md b/src/rust/vendor/ff/README.md new file mode 100644 index 000000000..907c0692a --- /dev/null +++ b/src/rust/vendor/ff/README.md @@ -0,0 +1,75 @@ +# ff + +`ff` is a finite field library written in pure Rust, with no `unsafe{}` code. + +## Disclaimers + +* This library does not provide constant-time guarantees. The traits enable downstream + users to expose constant-time logic, but `#[derive(PrimeField)]` in particular does not + generate constant-time code (even for trait methods that return constant-time-compatible + values). + +## Usage + +Add the `ff` crate to your `Cargo.toml`: + +```toml +[dependencies] +ff = "0.13" +``` + +The `ff` crate contains the `Field` and `PrimeField` traits. +See the **[documentation](https://docs.rs/ff/)** for more. + +### #![derive(PrimeField)] + +If you need an implementation of a prime field, this library also provides a procedural +macro that will expand into an efficient implementation of a prime field when supplied +with the modulus. `PrimeFieldGenerator` must be an element of Fp of p-1 order, that is +also quadratic nonresidue. + +First, enable the `derive` crate feature: + +```toml +[dependencies] +ff = { version = "0.13", features = ["derive"] } +``` + +And then use the macro like so: + +```rust +#[macro_use] +extern crate ff; + +#[derive(PrimeField)] +#[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"] +#[PrimeFieldGenerator = "7"] +#[PrimeFieldReprEndianness = "little"] +struct Fp([u64; 4]); +``` + +And that's it! `Fp` now implements `Field` and `PrimeField`. + +## Minimum Supported Rust Version + +Requires Rust **1.56** or higher. + +Minimum supported Rust version can be changed in the future, but it will be done with a +minor version bump. + +## 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/src/rust/vendor/ff/rust-toolchain b/src/rust/vendor/ff/rust-toolchain new file mode 100644 index 000000000..3ebf789f5 --- /dev/null +++ b/src/rust/vendor/ff/rust-toolchain @@ -0,0 +1 @@ +1.56.0 diff --git a/src/rust/vendor/ff/src/batch.rs b/src/rust/vendor/ff/src/batch.rs new file mode 100644 index 000000000..96ddc5a97 --- /dev/null +++ b/src/rust/vendor/ff/src/batch.rs @@ -0,0 +1,131 @@ +//! Batched field inversion APIs, using [Montgomery's trick]. +//! +//! [Montgomery's trick]: https://zcash.github.io/halo2/background/fields.html#montgomerys-trick + +use subtle::ConstantTimeEq; + +use crate::Field; + +/// Extension trait for iterators over mutable field elements which allows those field +/// elements to be inverted in a batch. +/// +/// `I: IntoIterator` implements this trait when +/// the `alloc` feature flag is enabled. +/// +/// For non-allocating contexts, see the [`BatchInverter`] struct. +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +pub trait BatchInvert { + /// Consumes this iterator and inverts each field element (when nonzero). Zero-valued + /// elements are left as zero. + /// + /// Returns the inverse of the product of all nonzero field elements. + fn batch_invert(self) -> F; +} + +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +impl<'a, F, I> BatchInvert for I +where + F: Field + ConstantTimeEq, + I: IntoIterator, +{ + fn batch_invert(self) -> F { + let mut acc = F::ONE; + let iter = self.into_iter(); + let mut tmp = alloc::vec::Vec::with_capacity(iter.size_hint().0); + for p in iter { + let q = *p; + tmp.push((acc, p)); + acc = F::conditional_select(&(acc * q), &acc, q.is_zero()); + } + acc = acc.invert().unwrap(); + let allinv = acc; + + for (tmp, p) in tmp.into_iter().rev() { + let skip = p.is_zero(); + + let tmp = tmp * acc; + acc = F::conditional_select(&(acc * *p), &acc, skip); + *p = F::conditional_select(&tmp, p, skip); + } + + allinv + } +} + +/// A non-allocating batch inverter. +pub struct BatchInverter {} + +impl BatchInverter { + /// Inverts each field element in `elements` (when nonzero). Zero-valued elements are + /// left as zero. + /// + /// - `scratch_space` is a slice of field elements that can be freely overwritten. + /// + /// Returns the inverse of the product of all nonzero field elements. + /// + /// # Panics + /// + /// This function will panic if `elements.len() != scratch_space.len()`. + pub fn invert_with_external_scratch(elements: &mut [F], scratch_space: &mut [F]) -> F + where + F: Field + ConstantTimeEq, + { + assert_eq!(elements.len(), scratch_space.len()); + + let mut acc = F::ONE; + for (p, scratch) in elements.iter().zip(scratch_space.iter_mut()) { + *scratch = acc; + acc = F::conditional_select(&(acc * *p), &acc, p.is_zero()); + } + acc = acc.invert().unwrap(); + let allinv = acc; + + for (p, scratch) in elements.iter_mut().zip(scratch_space.iter()).rev() { + let tmp = *scratch * acc; + let skip = p.is_zero(); + acc = F::conditional_select(&(acc * *p), &acc, skip); + *p = F::conditional_select(&tmp, &p, skip); + } + + allinv + } + + /// Inverts each field element in `items` (when nonzero). Zero-valued elements are + /// left as zero. + /// + /// - `element` is a function that extracts the element to be inverted from `items`. + /// - `scratch_space` is a function that extracts the scratch space from `items`. + /// + /// Returns the inverse of the product of all nonzero field elements. + pub fn invert_with_internal_scratch( + items: &mut [T], + element: TE, + scratch_space: TS, + ) -> F + where + F: Field + ConstantTimeEq, + TE: Fn(&mut T) -> &mut F, + TS: Fn(&mut T) -> &mut F, + { + let mut acc = F::ONE; + for item in items.iter_mut() { + *(scratch_space)(item) = acc; + let p = (element)(item); + acc = F::conditional_select(&(acc * *p), &acc, p.is_zero()); + } + acc = acc.invert().unwrap(); + let allinv = acc; + + for item in items.iter_mut().rev() { + let tmp = *(scratch_space)(item) * acc; + let p = (element)(item); + let skip = p.is_zero(); + acc = F::conditional_select(&(acc * *p), &acc, skip); + *p = F::conditional_select(&tmp, &p, skip); + } + + allinv + } +} diff --git a/src/rust/vendor/ff/src/helpers.rs b/src/rust/vendor/ff/src/helpers.rs new file mode 100644 index 000000000..d1d6371dd --- /dev/null +++ b/src/rust/vendor/ff/src/helpers.rs @@ -0,0 +1,128 @@ +//! Helper methods for implementing the `ff` traits. + +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +use crate::PrimeField; + +/// Constant-time implementation of Tonelli–Shanks' square-root algorithm for +/// `p mod 16 = 1`. +/// +/// `tm1d2` should be set to `(t - 1) // 2`, where `t = (modulus - 1) >> F::S`. +/// +/// ## Implementing [`Field::sqrt`] +/// +/// This function can be used to implement [`Field::sqrt`] for fields that both implement +/// [`PrimeField`] and satisfy `p mod 16 = 1`. +/// +/// [`Field::sqrt`]: crate::Field::sqrt +pub fn sqrt_tonelli_shanks>(f: &F, tm1d2: S) -> CtOption { + // This is a constant-time version of https://eprint.iacr.org/2012/685.pdf (page 12, + // algorithm 5). Steps 2-5 of the algorithm are omitted because they are only needed + // to detect non-square input; it is more efficient to do that by checking at the end + // whether the square of the result is the input. + + // w = self^((t - 1) // 2) + let w = f.pow_vartime(tm1d2); + + let mut v = F::S; + let mut x = w * f; + let mut b = x * w; + + // Initialize z as the 2^S root of unity. + let mut z = F::ROOT_OF_UNITY; + + for max_v in (1..=F::S).rev() { + let mut k = 1; + let mut b2k = b.square(); + let mut j_less_than_v: Choice = 1.into(); + + // This loop has three phases based on the value of k for algorithm 5: + // - for j <= k, we square b2k in order to calculate b^{2^k}. + // - for k < j <= v, we square z in order to calculate ω. + // - for j > v, we do nothing. + for j in 2..max_v { + let b2k_is_one = b2k.ct_eq(&F::ONE); + let squared = F::conditional_select(&b2k, &z, b2k_is_one).square(); + b2k = F::conditional_select(&squared, &b2k, b2k_is_one); + let new_z = F::conditional_select(&z, &squared, b2k_is_one); + j_less_than_v &= !j.ct_eq(&v); + k = u32::conditional_select(&j, &k, b2k_is_one); + z = F::conditional_select(&z, &new_z, j_less_than_v); + } + + let result = x * z; + x = F::conditional_select(&result, &x, b.ct_eq(&F::ONE)); + z = z.square(); + b *= z; + v = k; + } + + CtOption::new( + x, + (x * x).ct_eq(f), // Only return Some if it's the square root. + ) +} + +/// Computes: +/// +/// - $(\textsf{true}, \sqrt{\textsf{num}/\textsf{div}})$, if $\textsf{num}$ and +/// $\textsf{div}$ are nonzero and $\textsf{num}/\textsf{div}$ is a square in the +/// field; +/// - $(\textsf{true}, 0)$, if $\textsf{num}$ is zero; +/// - $(\textsf{false}, 0)$, if $\textsf{num}$ is nonzero and $\textsf{div}$ is zero; +/// - $(\textsf{false}, \sqrt{G_S \cdot \textsf{num}/\textsf{div}})$, if +/// $\textsf{num}$ and $\textsf{div}$ are nonzero and $\textsf{num}/\textsf{div}$ is +/// a nonsquare in the field; +/// +/// where $G_S$ is a non-square. +/// +/// For this method, $G_S$ is currently [`PrimeField::ROOT_OF_UNITY`], a generator of the +/// order $2^S$ subgroup. Users of this crate should not rely on this generator being +/// fixed; it may be changed in future crate versions to simplify the implementation of +/// the SSWU hash-to-curve algorithm. +/// +/// The choice of root from sqrt is unspecified. +/// +/// ## Implementing [`Field::sqrt_ratio`] +/// +/// This function can be used to implement [`Field::sqrt_ratio`] for fields that also +/// implement [`PrimeField`]. If doing so, the default implementation of [`Field::sqrt`] +/// *MUST* be overridden, or else both functions will recurse in a cycle until a stack +/// overflow occurs. +/// +/// [`Field::sqrt_ratio`]: crate::Field::sqrt_ratio +/// [`Field::sqrt`]: crate::Field::sqrt +pub fn sqrt_ratio_generic(num: &F, div: &F) -> (Choice, F) { + // General implementation: + // + // a = num * inv0(div) + // = { 0 if div is zero + // { num/div otherwise + // + // b = G_S * a + // = { 0 if div is zero + // { G_S*num/div otherwise + // + // Since G_S is non-square, a and b are either both zero (and both square), or + // only one of them is square. We can therefore choose the square root to return + // based on whether a is square, but for the boolean output we need to handle the + // num != 0 && div == 0 case specifically. + + let a = div.invert().unwrap_or(F::ZERO) * num; + let b = a * F::ROOT_OF_UNITY; + let sqrt_a = a.sqrt(); + let sqrt_b = b.sqrt(); + + let num_is_zero = num.is_zero(); + let div_is_zero = div.is_zero(); + let is_square = sqrt_a.is_some(); + let is_nonsquare = sqrt_b.is_some(); + assert!(bool::from( + num_is_zero | div_is_zero | (is_square ^ is_nonsquare) + )); + + ( + is_square & (num_is_zero | !div_is_zero), + CtOption::conditional_select(&sqrt_b, &sqrt_a, is_square).unwrap(), + ) +} diff --git a/src/rust/vendor/ff/src/lib.rs b/src/rust/vendor/ff/src/lib.rs new file mode 100644 index 000000000..96bd3e966 --- /dev/null +++ b/src/rust/vendor/ff/src/lib.rs @@ -0,0 +1,498 @@ +//! This crate provides traits for working with finite fields. + +// Catch documentation errors caused by code changes. +#![no_std] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![deny(rustdoc::broken_intra_doc_links)] +#![forbid(unsafe_code)] + +#[cfg(feature = "alloc")] +extern crate alloc; + +mod batch; +pub use batch::*; + +pub mod helpers; + +#[cfg(feature = "derive")] +#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] +pub use ff_derive::PrimeField; + +#[cfg(feature = "bits")] +#[cfg_attr(docsrs, doc(cfg(feature = "bits")))] +pub use bitvec::view::BitViewSized; + +#[cfg(feature = "bits")] +use bitvec::{array::BitArray, order::Lsb0}; + +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +use rand_core::RngCore; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +/// Bit representation of a field element. +#[cfg(feature = "bits")] +#[cfg_attr(docsrs, doc(cfg(feature = "bits")))] +pub type FieldBits = BitArray; + +/// This trait represents an element of a field. +pub trait Field: + Sized + + Eq + + Copy + + Clone + + Default + + Send + + Sync + + fmt::Debug + + 'static + + ConditionallySelectable + + ConstantTimeEq + + Neg + + Add + + Sub + + Mul + + Sum + + Product + + for<'a> Add<&'a Self, Output = Self> + + for<'a> Sub<&'a Self, Output = Self> + + for<'a> Mul<&'a Self, Output = Self> + + for<'a> Sum<&'a Self> + + for<'a> Product<&'a Self> + + AddAssign + + SubAssign + + MulAssign + + for<'a> AddAssign<&'a Self> + + for<'a> SubAssign<&'a Self> + + for<'a> MulAssign<&'a Self> +{ + /// The zero element of the field, the additive identity. + const ZERO: Self; + + /// The one element of the field, the multiplicative identity. + const ONE: Self; + + /// Returns an element chosen uniformly at random using a user-provided RNG. + fn random(rng: impl RngCore) -> Self; + + /// Returns true iff this element is zero. + fn is_zero(&self) -> Choice { + self.ct_eq(&Self::ZERO) + } + + /// Returns true iff this element is zero. + /// + /// # Security + /// + /// This method provides **no** constant-time guarantees. Implementors of the + /// `Field` trait **may** optimise this method using non-constant-time logic. + fn is_zero_vartime(&self) -> bool { + self.is_zero().into() + } + + /// Squares this element. + #[must_use] + fn square(&self) -> Self; + + /// Cubes this element. + #[must_use] + fn cube(&self) -> Self { + self.square() * self + } + + /// Doubles this element. + #[must_use] + fn double(&self) -> Self; + + /// Computes the multiplicative inverse of this element, + /// failing if the element is zero. + fn invert(&self) -> CtOption; + + /// Computes: + /// + /// - $(\textsf{true}, \sqrt{\textsf{num}/\textsf{div}})$, if $\textsf{num}$ and + /// $\textsf{div}$ are nonzero and $\textsf{num}/\textsf{div}$ is a square in the + /// field; + /// - $(\textsf{true}, 0)$, if $\textsf{num}$ is zero; + /// - $(\textsf{false}, 0)$, if $\textsf{num}$ is nonzero and $\textsf{div}$ is zero; + /// - $(\textsf{false}, \sqrt{G_S \cdot \textsf{num}/\textsf{div}})$, if + /// $\textsf{num}$ and $\textsf{div}$ are nonzero and $\textsf{num}/\textsf{div}$ is + /// a nonsquare in the field; + /// + /// where $G_S$ is a non-square. + /// + /// # Warnings + /// + /// - The choice of root from `sqrt` is unspecified. + /// - The value of $G_S$ is unspecified, and cannot be assumed to have any specific + /// value in a generic context. + fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self); + + /// Equivalent to `Self::sqrt_ratio(self, one())`. + /// + /// The provided method is implemented in terms of [`Self::sqrt_ratio`]. + fn sqrt_alt(&self) -> (Choice, Self) { + Self::sqrt_ratio(self, &Self::ONE) + } + + /// Returns the square root of the field element, if it is + /// quadratic residue. + /// + /// The provided method is implemented in terms of [`Self::sqrt_ratio`]. + fn sqrt(&self) -> CtOption { + let (is_square, res) = Self::sqrt_ratio(self, &Self::ONE); + CtOption::new(res, is_square) + } + + /// Exponentiates `self` by `exp`, where `exp` is a little-endian order integer + /// exponent. + /// + /// # Guarantees + /// + /// This operation is constant time with respect to `self`, for all exponents with the + /// same number of digits (`exp.as_ref().len()`). It is variable time with respect to + /// the number of digits in the exponent. + fn pow>(&self, exp: S) -> Self { + let mut res = Self::ONE; + for e in exp.as_ref().iter().rev() { + for i in (0..64).rev() { + res = res.square(); + let mut tmp = res; + tmp *= self; + res.conditional_assign(&tmp, (((*e >> i) & 1) as u8).into()); + } + } + res + } + + /// Exponentiates `self` by `exp`, where `exp` is a little-endian order integer + /// exponent. + /// + /// # Guarantees + /// + /// **This operation is variable time with respect to `self`, for all exponent.** If + /// the exponent is fixed, this operation is effectively constant time. However, for + /// stronger constant-time guarantees, [`Field::pow`] should be used. + fn pow_vartime>(&self, exp: S) -> Self { + let mut res = Self::ONE; + for e in exp.as_ref().iter().rev() { + for i in (0..64).rev() { + res = res.square(); + + if ((*e >> i) & 1) == 1 { + res.mul_assign(self); + } + } + } + + res + } +} + +/// This represents an element of a non-binary prime field. +pub trait PrimeField: Field + From { + /// The prime field can be converted back and forth into this binary + /// representation. + type Repr: Copy + Default + Send + Sync + 'static + AsRef<[u8]> + AsMut<[u8]>; + + /// Interpret a string of numbers as a (congruent) prime field element. + /// Does not accept unnecessary leading zeroes or a blank string. + /// + /// # Security + /// + /// This method provides **no** constant-time guarantees. + fn from_str_vartime(s: &str) -> Option { + if s.is_empty() { + return None; + } + + if s == "0" { + return Some(Self::ZERO); + } + + let mut res = Self::ZERO; + + let ten = Self::from(10); + + let mut first_digit = true; + + for c in s.chars() { + match c.to_digit(10) { + Some(c) => { + if first_digit { + if c == 0 { + return None; + } + + first_digit = false; + } + + res.mul_assign(&ten); + res.add_assign(&Self::from(u64::from(c))); + } + None => { + return None; + } + } + } + + Some(res) + } + + /// Obtains a field element congruent to the integer `v`. + /// + /// For fields where `Self::CAPACITY >= 128`, this is injective and will produce a + /// unique field element. + /// + /// For fields where `Self::CAPACITY < 128`, this is surjective; some field elements + /// will be produced by multiple values of `v`. + /// + /// If you want to deterministically sample a field element representing a value, use + /// [`FromUniformBytes`] instead. + fn from_u128(v: u128) -> Self { + let lower = v as u64; + let upper = (v >> 64) as u64; + let mut tmp = Self::from(upper); + for _ in 0..64 { + tmp = tmp.double(); + } + tmp + Self::from(lower) + } + + /// Attempts to convert a byte representation of a field element into an element of + /// this prime field, failing if the input is not canonical (is not smaller than the + /// field's modulus). + /// + /// The byte representation is interpreted with the same endianness as elements + /// returned by [`PrimeField::to_repr`]. + fn from_repr(repr: Self::Repr) -> CtOption; + + /// Attempts to convert a byte representation of a field element into an element of + /// this prime field, failing if the input is not canonical (is not smaller than the + /// field's modulus). + /// + /// The byte representation is interpreted with the same endianness as elements + /// returned by [`PrimeField::to_repr`]. + /// + /// # Security + /// + /// This method provides **no** constant-time guarantees. Implementors of the + /// `PrimeField` trait **may** optimise this method using non-constant-time logic. + fn from_repr_vartime(repr: Self::Repr) -> Option { + Self::from_repr(repr).into() + } + + /// Converts an element of the prime field into the standard byte representation for + /// this field. + /// + /// The endianness of the byte representation is implementation-specific. Generic + /// encodings of field elements should be treated as opaque. + fn to_repr(&self) -> Self::Repr; + + /// Returns true iff this element is odd. + fn is_odd(&self) -> Choice; + + /// Returns true iff this element is even. + #[inline(always)] + fn is_even(&self) -> Choice { + !self.is_odd() + } + + /// Modulus of the field written as a string for debugging purposes. + /// + /// The encoding of the modulus is implementation-specific. Generic users of the + /// `PrimeField` trait should treat this string as opaque. + const MODULUS: &'static str; + + /// How many bits are needed to represent an element of this field. + const NUM_BITS: u32; + + /// How many bits of information can be reliably stored in the field element. + /// + /// This is usually `Self::NUM_BITS - 1`. + const CAPACITY: u32; + + /// Inverse of $2$ in the field. + const TWO_INV: Self; + + /// A fixed multiplicative generator of `modulus - 1` order. This element must also be + /// a quadratic nonresidue. + /// + /// It can be calculated using [SageMath] as `GF(modulus).primitive_element()`. + /// + /// Implementations of this trait MUST ensure that this is the generator used to + /// derive `Self::ROOT_OF_UNITY`. + /// + /// [SageMath]: https://www.sagemath.org/ + const MULTIPLICATIVE_GENERATOR: Self; + + /// An integer `s` satisfying the equation `2^s * t = modulus - 1` with `t` odd. + /// + /// This is the number of leading zero bits in the little-endian bit representation of + /// `modulus - 1`. + const S: u32; + + /// The `2^s` root of unity. + /// + /// It can be calculated by exponentiating `Self::MULTIPLICATIVE_GENERATOR` by `t`, + /// where `t = (modulus - 1) >> Self::S`. + const ROOT_OF_UNITY: Self; + + /// Inverse of [`Self::ROOT_OF_UNITY`]. + const ROOT_OF_UNITY_INV: Self; + + /// Generator of the `t-order` multiplicative subgroup. + /// + /// It can be calculated by exponentiating [`Self::MULTIPLICATIVE_GENERATOR`] by `2^s`, + /// where `s` is [`Self::S`]. + const DELTA: Self; +} + +/// The subset of prime-order fields such that `(modulus - 1)` is divisible by `N`. +/// +/// If `N` is prime, there will be `N - 1` valid choices of [`Self::ZETA`]. Similarly to +/// [`PrimeField::MULTIPLICATIVE_GENERATOR`], the specific choice does not matter, as long +/// as the choice is consistent across all uses of the field. +pub trait WithSmallOrderMulGroup: PrimeField { + /// A field element of small multiplicative order $N$. + /// + /// The presense of this element allows you to perform (certain types of) + /// endomorphisms on some elliptic curves. + /// + /// It can be calculated using [SageMath] as + /// `GF(modulus).primitive_element() ^ ((modulus - 1) // N)`. + /// Choosing the element of order $N$ that is smallest, when considered + /// as an integer, may help to ensure consistency. + /// + /// [SageMath]: https://www.sagemath.org/ + const ZETA: Self; +} + +/// Trait for constructing a [`PrimeField`] element from a fixed-length uniform byte +/// array. +/// +/// "Uniform" means that the byte array's contents must be indistinguishable from the +/// [discrete uniform distribution]. Suitable byte arrays can be obtained: +/// - from a cryptographically-secure randomness source (which makes this constructor +/// equivalent to [`Field::random`]). +/// - from a cryptographic hash function output, which enables a "random" field element to +/// be selected deterministically. This is the primary use case for `FromUniformBytes`. +/// +/// The length `N` of the byte array is chosen by the trait implementer such that the loss +/// of uniformity in the mapping from byte arrays to field elements is cryptographically +/// negligible. +/// +/// [discrete uniform distribution]: https://en.wikipedia.org/wiki/Discrete_uniform_distribution +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "derive")] { +/// # // Fake this so we don't actually need a dev-dependency on bls12_381. +/// # mod bls12_381 { +/// # use ff::{Field, PrimeField}; +/// # +/// # #[derive(PrimeField)] +/// # #[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"] +/// # #[PrimeFieldGenerator = "7"] +/// # #[PrimeFieldReprEndianness = "little"] +/// # pub struct Scalar([u64; 4]); +/// # +/// # impl ff::FromUniformBytes<64> for Scalar { +/// # fn from_uniform_bytes(_bytes: &[u8; 64]) -> Self { +/// # // Fake impl for doctest +/// # Scalar::ONE +/// # } +/// # } +/// # } +/// # +/// use blake2b_simd::blake2b; +/// use bls12_381::Scalar; +/// use ff::FromUniformBytes; +/// +/// // `bls12_381::Scalar` implements `FromUniformBytes<64>`, and BLAKE2b (by default) +/// // produces a 64-byte hash. +/// let hash = blake2b(b"Some message"); +/// let val = Scalar::from_uniform_bytes(hash.as_array()); +/// # } +/// ``` +/// +/// # Implementing `FromUniformBytes` +/// +/// [`Self::from_uniform_bytes`] should always be implemented by interpreting the provided +/// byte array as the little endian unsigned encoding of an integer, and then reducing that +/// integer modulo the field modulus. +/// +/// For security, `N` must be chosen so that `N * 8 >= Self::NUM_BITS + 128`. A larger +/// value of `N` may be chosen for convenience; for example, for a field with a 255-bit +/// modulus, `N = 64` is convenient as it matches the output length of several common +/// cryptographic hash functions (such as SHA-512 and BLAKE2b). +/// +/// ## Trait design +/// +/// This trait exists because `PrimeField::from_uniform_bytes([u8; N])` cannot currently +/// exist (trait methods cannot use associated constants in the const positions of their +/// type signature, and we do not want `PrimeField` to require a generic const parameter). +/// However, this has the side-effect that `FromUniformBytes` can be implemented multiple +/// times for different values of `N`. Most implementations of [`PrimeField`] should only +/// need to implement `FromUniformBytes` trait for one value of `N` (chosen following the +/// above considerations); if you find yourself needing to implement it multiple times, +/// please [let us know about your use case](https://github.com/zkcrypto/ff/issues/new) so +/// we can take it into consideration for future evolutions of the `ff` traits. +pub trait FromUniformBytes: PrimeField { + /// Returns a field element that is congruent to the provided little endian unsigned + /// byte representation of an integer. + fn from_uniform_bytes(bytes: &[u8; N]) -> Self; +} + +/// This represents the bits of an element of a prime field. +#[cfg(feature = "bits")] +#[cfg_attr(docsrs, doc(cfg(feature = "bits")))] +pub trait PrimeFieldBits: PrimeField { + /// The backing store for a bit representation of a prime field element. + type ReprBits: BitViewSized + Send + Sync; + + /// Converts an element of the prime field into a little-endian sequence of bits. + fn to_le_bits(&self) -> FieldBits; + + /// Returns the bits of the field characteristic (the modulus) in little-endian order. + fn char_le_bits() -> FieldBits; +} + +/// Functions and re-exported crates used by the [`PrimeField`] derive macro. +#[cfg(feature = "derive")] +#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] +pub mod derive { + pub use crate::arith_impl::*; + + pub use {byteorder, rand_core, subtle}; + + #[cfg(feature = "bits")] + pub use bitvec; +} + +#[cfg(feature = "derive")] +mod arith_impl { + /// Computes `a - (b + borrow)`, returning the result and the new borrow. + #[inline(always)] + pub const fn sbb(a: u64, b: u64, borrow: u64) -> (u64, u64) { + let ret = (a as u128).wrapping_sub((b as u128) + ((borrow >> 63) as u128)); + (ret as u64, (ret >> 64) as u64) + } + + /// Computes `a + b + carry`, returning the result and the new carry over. + #[inline(always)] + pub const fn adc(a: u64, b: u64, carry: u64) -> (u64, u64) { + let ret = (a as u128) + (b as u128) + (carry as u128); + (ret as u64, (ret >> 64) as u64) + } + + /// Computes `a + (b * c) + carry`, returning the result and the new carry over. + #[inline(always)] + pub const fn mac(a: u64, b: u64, c: u64, carry: u64) -> (u64, u64) { + let ret = (a as u128) + ((b as u128) * (c as u128)) + (carry as u128); + (ret as u64, (ret >> 64) as u64) + } +} diff --git a/src/rust/vendor/ff/tests/derive.rs b/src/rust/vendor/ff/tests/derive.rs new file mode 100644 index 000000000..fa6ee20e9 --- /dev/null +++ b/src/rust/vendor/ff/tests/derive.rs @@ -0,0 +1,137 @@ +//! This module exercises the `ff_derive` procedural macros, to ensure that changes to the +//! `ff` crate are reflected in `ff_derive`. It also uses the resulting field to test some +//! of the APIs provided by `ff`, such as batch inversion. + +#[macro_use] +extern crate ff; + +/// The BLS12-381 scalar field. +#[derive(PrimeField)] +#[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"] +#[PrimeFieldGenerator = "7"] +#[PrimeFieldReprEndianness = "little"] +struct Bls381K12Scalar([u64; 4]); + +mod fermat { + /// The largest known Fermat prime, used to test the case `t = 1`. + #[derive(PrimeField)] + #[PrimeFieldModulus = "65537"] + #[PrimeFieldGenerator = "3"] + #[PrimeFieldReprEndianness = "little"] + struct Fermat65537Field([u64; 1]); +} + +mod full_limbs { + #[derive(PrimeField)] + #[PrimeFieldModulus = "39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319"] + #[PrimeFieldGenerator = "19"] + #[PrimeFieldReprEndianness = "little"] + struct F384p([u64; 7]); + + #[test] + fn random_masking_does_not_overflow() { + use ff::Field; + use rand::rngs::OsRng; + + let _ = F384p::random(OsRng); + } +} + +#[test] +fn constants() { + use ff::{Field, PrimeField}; + + assert_eq!( + Bls381K12Scalar::MODULUS, + "0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", + ); + + assert_eq!( + Bls381K12Scalar::from(2) * Bls381K12Scalar::TWO_INV, + Bls381K12Scalar::ONE, + ); + + assert_eq!( + Bls381K12Scalar::ROOT_OF_UNITY * Bls381K12Scalar::ROOT_OF_UNITY_INV, + Bls381K12Scalar::ONE, + ); + + // ROOT_OF_UNITY^{2^s} mod m == 1 + assert_eq!( + Bls381K12Scalar::ROOT_OF_UNITY.pow(&[1u64 << Bls381K12Scalar::S, 0, 0, 0]), + Bls381K12Scalar::ONE, + ); + + // DELTA^{t} mod m == 1 + assert_eq!( + Bls381K12Scalar::DELTA.pow(&[ + 0xfffe5bfeffffffff, + 0x09a1d80553bda402, + 0x299d7d483339d808, + 0x73eda753, + ]), + Bls381K12Scalar::ONE, + ); +} + +#[test] +fn from_u128() { + use ff::{Field, PrimeField}; + + assert_eq!(Bls381K12Scalar::from_u128(1), Bls381K12Scalar::ONE); + assert_eq!(Bls381K12Scalar::from_u128(2), Bls381K12Scalar::from(2)); + assert_eq!( + Bls381K12Scalar::from_u128(u128::MAX), + Bls381K12Scalar::from_str_vartime("340282366920938463463374607431768211455").unwrap(), + ); +} + +#[test] +fn batch_inversion() { + use ff::{BatchInverter, Field}; + + let one = Bls381K12Scalar::ONE; + + // [1, 2, 3, 4] + let values: Vec<_> = (0..4) + .scan(one, |acc, _| { + let ret = *acc; + *acc += &one; + Some(ret) + }) + .collect(); + + // Test BatchInverter::invert_with_external_scratch + { + let mut elements = values.clone(); + let mut scratch_space = vec![Bls381K12Scalar::ZERO; elements.len()]; + BatchInverter::invert_with_external_scratch(&mut elements, &mut scratch_space); + for (a, a_inv) in values.iter().zip(elements.into_iter()) { + assert_eq!(*a * a_inv, one); + } + } + + // Test BatchInverter::invert_with_internal_scratch + { + let mut items: Vec<_> = values.iter().cloned().map(|p| (p, one)).collect(); + BatchInverter::invert_with_internal_scratch( + &mut items, + |item| &mut item.0, + |item| &mut item.1, + ); + for (a, (a_inv, _)) in values.iter().zip(items.into_iter()) { + assert_eq!(*a * a_inv, one); + } + } + + // Test BatchInvert trait + #[cfg(feature = "alloc")] + { + use ff::BatchInvert; + let mut elements = values.clone(); + elements.iter_mut().batch_invert(); + for (a, a_inv) in values.iter().zip(elements.into_iter()) { + assert_eq!(*a * a_inv, one); + } + } +} diff --git a/src/rust/vendor/generic-array/.cargo-checksum.json b/src/rust/vendor/generic-array/.cargo-checksum.json index 9996cc453..7d6b15046 100644 --- a/src/rust/vendor/generic-array/.cargo-checksum.json +++ b/src/rust/vendor/generic-array/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"6fd290755dcbb7da68223425151b556fd76ab9998fe9cee81042acf1a47164e5","Cargo.toml":"a14186cc9cbb4d0446fcb8898439c24b5dd8acccc05dd27e3d829c069da97fa4","DESIGN.md":"8b745d89e634c48646202edfaa2151ee08a04a9c32271f4c2cc4afb63b4e952c","LICENSE":"c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583","README.md":"9e86d03b400dc818f44df68b76dafd1d89e42a51221bcb0de4259a6529ab6d84","build.rs":"08fa30c4a2c1ad24fe5f987e721dfb20131f45ea5b5dc3e836dcf88a8e33248c","rustfmt.toml":"13d771354ddee15d5aa5a168fd6965c3c0ee7aa7ce75cdd5e3b82852cdac5123","src/arr.rs":"a898e3a37910bfc59d9caf71bf22eda02d3a4ad96c75f8a6d49ed1309531aa4e","src/functional.rs":"7dd6ddd5db3000054cbbd76959f745c7de73c8493cbfb745be80509b306e4a83","src/hex.rs":"091fb78f6d373a6ef1c467d85c461472fcdb1e91efc294039f4c870151c3ee9f","src/impl_serde.rs":"f046daba067522b4c3e79437d04f43a001e83353c81e6b2188c37a2e63dba7a3","src/impls.rs":"18b285821421eea0cdbbcfcc896eef67bd55d72f8d85b5827cca6687e9c0fc27","src/iter.rs":"5e5e92e86a18e747f6687f4b3853aa2eaaa1121af43f3833b940f074baa32302","src/lib.rs":"22af14d446ec5f67a99e350d4a0c95e070f4ff9537ac9e84ec1172f654f8b95a","src/sequence.rs":"26679cfec035bae7298f067f37e8d42a1eda8fe241e9cf2c2977ba4bddddab1d","tests/arr.rs":"22d332fcb5e0314980ddc952af0265125cf53bb9cb8b546a9dcaec2e29bfc3b0","tests/generics.rs":"491c9351fd973ff2b7bc72e78d3069cf3ed3fcd2f9180558ab027099605fa147","tests/hex.rs":"fd428c2558da2f1e2cf229af2e40e5b35a2094b3306312ac41943d25a85b7de1","tests/import_name.rs":"c9439c7d7531ce79419b0d413d729ea4321887c091bd9be8b18e6c2413021ed0","tests/iter.rs":"d9f18c7a280a938a63d382086450146206c5805804d4b62c7e55cd60ea0e2d0d","tests/mod.rs":"556a9cb6f6699c523ebfb1b167a18b30d909604339e929e9c874da92aae60bd3"},"package":"501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"} \ No newline at end of file +{"files":{"CHANGELOG.md":"478d33deb9d0c943c20671eed67bc393891aad1679e61f74412f98c9a5017f84","Cargo.toml":"4b5daed75505275d11f4854dd9172f910da61d9856ca2936d95e2e6e0c9040e4","LICENSE":"c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583","README.md":"9e86d03b400dc818f44df68b76dafd1d89e42a51221bcb0de4259a6529ab6d84","build.rs":"08fa30c4a2c1ad24fe5f987e721dfb20131f45ea5b5dc3e836dcf88a8e33248c","src/arr.rs":"c115d6926deb769ced772e9c4e1c84baf1bdea4fe4b9eb2061658a63869eab62","src/functional.rs":"7dd6ddd5db3000054cbbd76959f745c7de73c8493cbfb745be80509b306e4a83","src/hex.rs":"091fb78f6d373a6ef1c467d85c461472fcdb1e91efc294039f4c870151c3ee9f","src/impl_serde.rs":"f046daba067522b4c3e79437d04f43a001e83353c81e6b2188c37a2e63dba7a3","src/impl_zeroize.rs":"dd1af63ef2cba2120c6f775350c98eb12bb1be6ba784d5350d07d4ae5419c292","src/impls.rs":"18b285821421eea0cdbbcfcc896eef67bd55d72f8d85b5827cca6687e9c0fc27","src/iter.rs":"4f50253f4130caa0780984b64467ca1916a881410f631f7eb85a1724b3ab4ced","src/lib.rs":"20b64b4359b0e82a3523fd536ad06de25e174cead734cffd3fa5f7c48f659247","src/sequence.rs":"26679cfec035bae7298f067f37e8d42a1eda8fe241e9cf2c2977ba4bddddab1d"},"package":"85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"} \ No newline at end of file diff --git a/src/rust/vendor/generic-array/CHANGELOG.md b/src/rust/vendor/generic-array/CHANGELOG.md index da20e891a..0c8a9361d 100644 --- a/src/rust/vendor/generic-array/CHANGELOG.md +++ b/src/rust/vendor/generic-array/CHANGELOG.md @@ -1,3 +1,14 @@ +* **`0.14.7`** + * Backport [#133](https://github.com/fizyk20/generic-array/pull/133) and [#134](https://github.com/fizyk20/generic-array/pull/134) + +* **`0.14.6`** + * Add an optional `Zeroize` impl for `GenericArray` ([#126](https://github.com/fizyk20/generic-array/pull/126) and [#112](https://github.com/fizyk20/generic-array/pull/112)) + * Cleanup some unsafe ([#125](https://github.com/fizyk20/generic-array/pull/125)) and typos ([#114](https://github.com/fizyk20/generic-array/pull/114)) + * Use `include` in `Cargo.toml` to reduce package size + +* **`0.14.5`** + * Fix unsoundness behavior in `GenericArrayIter::clone` ([#120](https://github.com/fizyk20/generic-array/pull/120)) + * **`0.14.4`** * Update `typenum` to `1.12.0` * Make `Drop` a no-op when the inner type does not require `Drop` (using `core::mem::needs_drop`) diff --git a/src/rust/vendor/generic-array/Cargo.toml b/src/rust/vendor/generic-array/Cargo.toml index e802b576d..a301cebfb 100644 --- a/src/rust/vendor/generic-array/Cargo.toml +++ b/src/rust/vendor/generic-array/Cargo.toml @@ -3,27 +3,49 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] name = "generic-array" -version = "0.14.4" -authors = ["Bartłomiej Kamiński ", "Aaron Trent "] +version = "0.14.7" +authors = [ + "Bartłomiej Kamiński ", + "Aaron Trent ", +] +include = [ + "src/**/*", + "LICENSE", + "README.md", + "CHANGELOG.md", + "build.rs", +] description = "Generic types implementing functionality of arrays" documentation = "http://fizyk20.github.io/generic-array/generic_array/" readme = "README.md" -keywords = ["generic", "array"] -categories = ["data-structures", "no-std"] +keywords = [ + "generic", + "array", +] +categories = [ + "data-structures", + "no-std", +] license = "MIT" repository = "https://github.com/fizyk20/generic-array.git" +[package.metadata.docs.rs] +features = [ + "serde", + "zeroize", +] + [lib] name = "generic_array" + [dependencies.serde] version = "1.0" optional = true @@ -31,15 +53,23 @@ default-features = false [dependencies.typenum] version = "1.12" + +[dependencies.zeroize] +version = "1" +optional = true +default-features = false + [dev-dependencies.bincode] version = "1.0" [dev-dependencies.serde_json] version = "1.0" + [build-dependencies.version_check] version = "0.9" [features] more_lengths = [] + [badges.travis-ci] repository = "fizyk20/generic-array" diff --git a/src/rust/vendor/generic-array/DESIGN.md b/src/rust/vendor/generic-array/DESIGN.md deleted file mode 100644 index 547bc7bd2..000000000 --- a/src/rust/vendor/generic-array/DESIGN.md +++ /dev/null @@ -1,585 +0,0 @@ -Design and Usage Notes -====================== - -## Sections - -1. [How it Works](#how-it-works) -2. [Initialization](#initialization) -3. [Functional Programming](#functional-programming) -4. [Miscellaneous Utilities](#miscellaneous-utilities) -5. [Safety](#safety) -6. [Optimization](#optimization) -7. [The Future](#the-future) - -**NOTE**: This document uses `

` sections, so look out for collapsible parts with an arrow on the left. - -# How it works - -`generic-array` is a method of achieving fixed-length fixed-size stack-allocated generic arrays without needing const generics in stable Rust. - -That is to say this: - -```rust -struct Foo { - data: [i32; N], -} -``` - -or anything similar is not currently supported. - -However, Rust's type system is sufficiently advanced, and a "hack" for solving this was created in the form of the `typenum` crate, which recursively defines integer values in binary as nested types, and operations which can be applied to those type-numbers, such as `Add`, `Sub`, etc. - -e.g. `6` would be `UInt, B1>, B0>` - -Over time, I've come to see `typenum` as less of a hack and more as an elegant solution. - -The recursive binary nature of `typenum` is what makes `generic-array` possible, so: - -```rust -struct Foo> { - data: GenericArray, -} -``` - -is supported. - -I often see questions about why `ArrayLength` requires the element type `T` in it's signature, even though it's not used in the inner `ArrayType`. - -This is because `GenericArray` itself does not define the actual array. Rather, it is defined as: - -```rust -pub struct GenericArray> { - data: N::ArrayType, -} -``` - -The trait `ArrayLength` does all the real heavy lifting for defining the data, with implementations on `UInt`, `UInt` and `UTerm`, which correspond to even, odd and zero numeric values, respectively. - -`ArrayLength`'s implementations use type-level recursion to peel away each least significant bit and form sort of an opaque binary tree of contiguous data the correct physical size to store `N` elements of `T`. The tree, or block of data, is then stored inside of `GenericArray` to be reinterpreted as the array. - -For example, `GenericArray` more or less expands to (at compile time): - -
-Expand for code - -```rust -GenericArray { - // UInt, B1>, B0> - data: EvenData { - // UInt, B1> - left: OddData { - // UInt - left: OddData { - left: (), // UTerm - right: (), // UTerm - data: T, // Element 0 - }, - // UInt - right: OddData { - left: (), // UTerm - right: (), // UTerm - data: T, // Element 1 - }, - data: T // Element 2 - }, - // UInt, B1> - right: OddData { - // UInt - left: OddData { - left: (), // UTerm - right: (), // UTerm - data: T, // Element 3 - }, - // UInt - right: OddData { - left: (), // UTerm - right: (), // UTerm - data: T, // Element 4 - }, - data: T // Element 5 - } - } -} -``` - -
- -This has the added benefit of only being `log2(N)` deep, which is important for things like `Drop`, which we'll go into later. - -Then, we take `data` and cast it to `*const T` or `*mut T` and use it as a slice like: - -```rust -unsafe { - slice::from_raw_parts( - self as *const Self as *const T, - N::to_usize() - ) -} -``` - -It is useful to note that because `typenum` is compile-time with nested generics, `to_usize`, even if it isn't a `const fn`, *does* expand to effectively `1 + 2 + 4 + 8 + ...` and so forth, which LLVM is smart enough to reduce to a single compile-time constant. This helps hint to the optimizers about things such as bounds checks. - -So, to reiterate, we're working with a raw block of contiguous memory the correct physical size to store `N` elements of `T`. It's really no different from how normal arrays are stored. - -## Pointer Safety - -Of course, casting pointers around and constructing blocks of data out of thin air is normal for C, but here in Rust we try to be a bit less prone to segfaults. Therefore, great care is taken to minimize casual `unsafe` usage and restrict `unsafe` to specific parts of the API, making heavy use those exposed safe APIs internally. - -For example, the above `slice::from_raw_parts` is only used twice in the entire library, once for `&[T]` and `slice::from_raw_parts_mut` once for `&mut [T]`. Everything else goes through those slices. - -# Initialization - -## Constant - -"Constant" initialization, that is to say - without dynamic values, can be done via the `arr![]` macro, which works almost exactly like `vec![]`, but with an additional type parameter. - -Example: - -```rust -let my_arr = arr![i32; 1, 2, 3, 4, 5, 6, 7, 8]; -``` - -## Dynamic - -Although some users have opted to use their own initializers, as of version `0.9` and beyond `generic-array` includes safe methods for initializing elements in the array. - -The `GenericSequence` trait defines a `generate` method which can be used like so: - -```rust -use generic_array::{GenericArray, sequence::GenericSequence}; - -let squares: GenericArray = - GenericArray::generate(|i: usize| i as i32 * 2); -``` - -and `GenericArray` additionally implements `FromIterator`, although `from_iter` ***will*** panic if the number of elements is not *at least* `N`. It will ignore extra items. - -The safety of these operations is described later. - -# Functional Programming - -In addition to `GenericSequence`, this crate provides a `FunctionalSequence`, which allows extremely efficient `map`, `zip` and `fold` operations on `GenericArray`s. - -As described at the end of the [Optimization](#optimization) section, `FunctionalSequence` uses clever specialization tactics to provide optimized methods wherever possible, while remaining perfectly safe. - -Some examples, taken from `tests/generic.rs`: - -
- -and if you really want to go off the deep end and support any arbitrary *`GenericSequence`*: - -
-Expand for code - -```rust -/// Complex example function using generics to pass N-length sequences, zip them, and then map that result. -/// -/// If used with `GenericArray` specifically this isn't necessary -pub fn generic_sequence_zip_sum(a: A, b: B) -> i32 -where - A: FunctionalSequence, // `.zip` - B: FunctionalSequence, // `.zip` - A: MappedGenericSequence, // `i32` -> `i32` - B: MappedGenericSequence>, // `i32` -> `i32`, prove A and B can map to the same output - A::Item: Add, // `l + r` - MappedSequence: MappedGenericSequence + FunctionalSequence, // `.map` - SequenceItem>: Add, // `x + 1` - MappedSequence, i32, i32>: Debug, // `println!` - MappedSequence, i32, i32>: FunctionalSequence, // `.fold` - SequenceItem, i32, i32>>: Add // `x + a`, note the order -{ - let c = a.zip(b, |l, r| l + r).map(|x| x + 1); - - println!("{:?}", c); - - c.fold(0, |a, x| x + a) -} -``` - -of course, as I stated before, that's almost never necessary, especially when you know the concrete types of all the components. - -
- -The [`numeric-array`](https://crates.io/crates/numeric-array) crate uses these to apply numeric operations across all elements in a `GenericArray`, making full use of all the optimizations described in the last section here. - -# Miscellaneous Utilities - -Although not usually advertised, `generic-array` contains traits for lengthening, shortening, splitting and concatenating arrays. - -For example, these snippets are taken from `tests/mod.rs`: - -
-Expand for code - -Appending and prepending elements: - -```rust -use generic_array::sequence::Lengthen; - -#[test] -fn test_append() { - let a = arr![i32; 1, 2, 3]; - - let b = a.append(4); - - assert_eq!(b, arr![i32; 1, 2, 3, 4]); -} - -#[test] -fn test_prepend() { - let a = arr![i32; 1, 2, 3]; - - let b = a.prepend(4); - - assert_eq!(b, arr![i32; 4, 1, 2, 3]); -} -``` - -Popping elements from the front of back of the array: - -```rust -use generic_array::sequence::Shorten; - -let a = arr![i32; 1, 2, 3, 4]; - -let (init, last) = a.pop_back(); - -assert_eq!(init, arr![i32; 1, 2, 3]); -assert_eq!(last, 4); - -let (head, tail) = a.pop_front(); - -assert_eq!(head, 1); -assert_eq!(tail, arr![i32; 2, 3, 4]); -``` - -and of course concatenating and splitting: - -```rust -use generic_array::sequence::{Concat, Split}; - -let a = arr![i32; 1, 2]; -let b = arr![i32; 3, 4]; - -let c = a.concat(b); - -assert_eq!(c, arr![i32; 1, 2, 3, 4]); - -let (d, e) = c.split(); - -assert_eq!(d, arr![i32; 1]); -assert_eq!(e, arr![i32; 2, 3, 4]); -``` -
- -`Split` and `Concat` in these examples use type-inference to determine the lengths of the resulting arrays. - -# Safety - -As stated earlier, for raw reinterpretations such as this, safety is a must even while working with unsafe code. Great care is taken to reduce or eliminate undefined behavior. - -For most of the above code examples, the biggest potential undefined behavior hasn't even been applicable for one simple reason: they were all primitive values. - -The simplest way to lead into this is to post these questions: - -1. What if the element type of the array implements `Drop`? -2. What if `GenericArray::generate` opens a bunch of files? -3. What if halfway through opening each of the files, one is not found? -4. What if the resulting error is unwrapped, causing the generation function to panic? - -For a fully initialized `GenericArray`, the expanded structure as described in the [How It Works](#how-it-works) can implement `Drop` naturally, recursively dropping elements. As it is only `log2(N)` deep, the recursion is very small overall. - -In fact, I tested it while writing this, the size of the array itself overflows the stack before any recursive calls to `drop` can. - -However, ***partially*** initialized arrays, such as described in the above hypothetical, pose an issue where `drop` could be called on uninitialized data, which is undefined behavior. - -To solve this, `GenericArray` implements two components named `ArrayBuilder` and `ArrayConsumer`, which work very similarly. - -`ArrayBuilder` creates a block of wholly uninitialized memory via `mem::unintialized()`, and stores that in a `ManuallyDrop` wrapper. `ManuallyDrop` does exactly what it says on the tin, and simply doesn't drop the value unless manually requested to. - -So, as we're initializing our array, `ArrayBuilder` keeps track of the current position through it, and if something happens, `ArrayBuilder` itself will iteratively and manually `drop` all currently initialized elements, ignoring any uninitialized ones, because those are just raw memory and should be ignored. - -`ArrayConsumer` does almost the same, "moving" values out of the array and into something else, like user code. It uses `ptr::read` to "move" the value out, and increments a counter saying that value is no longer valid in the array. - -If a panic occurs in the user code with that element, it's dropped naturally as it was moved into that scope. `ArrayConsumer` then proceeds to iteratively and manually `drop` all *remaining* elements. - -Combined, these two systems provide a safe system for building and consuming `GenericArray`s. In fact, they are used extensively inside the library itself for `FromIterator`, `GenericSequence` and `FunctionalSequence`, among others. - -Even `GenericArray`s implementation of `Clone` makes use of this via: - -```rust -impl Clone for GenericArray -where - N: ArrayLength, -{ - fn clone(&self) -> GenericArray { - self.map(|x| x.clone()) - } -} -``` - -where `.map` is from the `FunctionalSequence`, and uses those builder and consumer structures to safely move and initialize values. Although, in this particular case, a consumer is not necessary as we're using references. More on how that is automatically deduced is described in the next section. - -# Optimization - -Rust and LLVM is smart. Crazy smart. However, it's not magic. - -In my experience, most of Rust's "zero-cost" abstractions stem more from the type system, rather than explicit optimizations. Most Rust code is very easily optimizable and inlinable by design, so it can be simplified and compacted rather well, as opposed to the spaghetti code of some other languages. - -Unfortunately, unless `rustc` or LLVM can "prove" things about code to simplify it, it must still be run, and can prevent further optimization. - -A great example of this, and why I created the `GenericSequence` and `FunctionalSequence` traits, are iterators. - -Custom iterators are slow. Not terribly slow, but slow enough to prevent some rather important optimizations. - -Take `GenericArrayIter` for example: - -
-Expand for code - -```rust -pub struct GenericArrayIter> { - array: ManuallyDrop>, - index: usize, - index_back: usize, -} - -impl Iterator for GenericArrayIter -where - N: ArrayLength, -{ - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - if self.index < self.index_back { - let p = unsafe { - Some(ptr::read(self.array.get_unchecked(self.index))) - }; - - self.index += 1; - - p - } else { - None - } - } - - //and more -} -``` -
- -Seems simple enough, right? Move an element out of the array with `ptr::read` and increment the index. If the iterator is dropped, the remaining elements are dropped exactly as they would with `ArrayConsumer`. `index_back` is provided for `DoubleEndedIterator`. - -Unfortunately, that single `if` statement is terrible. In my mind, this is one of the biggest flaws of the iterator design. A conditional jump on a mutable variable unrelated to the data we are accessing on each call foils the optimizer and generates suboptimal code for the above iterator, even when we use `get_unchecked`. - -The optimizer is unable to see that we are simply accessing memory sequentially. In fact, almost all iterators are like this. Granted, this is usually fine and, especially if they have to handle errors, it's perfectly acceptable. - -However, there is one iterator in the standard library that is optimized perfectly: the slice iterator. So perfectly in fact that it allows the optimizer to do something even more special: **auto-vectorization**! We'll get to that later. - -It's a bit frustrating as to *why* slice iterators can be so perfectly optimized, and it basically boils down to that the iterator itself does not own the data the slice refers to, so it uses raw pointers to the array/sequence/etc. rather than having to use an index on a stack allocated and always moving array. It can check for if the iterator is empty by comparing some `front` and `back` pointers for equality, and because those directly correspond to the position in memory of the next element, LLVM can see that and make optimizations. - -So, the gist of that is: always use slice iterators where possible. - -Here comes the most important part of all of this: `ArrayBuilder` and `ArrayConsumer` don't iterate the arrays themselves. Instead, we use slice iterators (immutable and mutable), with `zip` or `enumerate`, to apply operations to the entire array, incrementing the position in both `ArrayBuilder` or `ArrayConsumer` to keep track. - -For example, `GenericSequence::generate` for `GenericArray` is: - -
-Expand for code - -```rust -fn generate(mut f: F) -> GenericArray -where - F: FnMut(usize) -> T, -{ - unsafe { - let mut destination = ArrayBuilder::new(); - - { - let (destination_iter, position) = destination.iter_position(); - - for (i, dst) in destination_iter.enumerate() { - ptr::write(dst, f(i)); - - *position += 1; - } - } - - destination.into_inner() - } -} -``` - -where `ArrayBuilder::iter_position` is just an internal convenience function: - -```rust -pub unsafe fn iter_position(&mut self) -> (slice::IterMut, &mut usize) { - (self.array.iter_mut(), &mut self.position) -} -``` -
- -Of course, this may appear to be redundant, if we're using an iterator that keeps track of the position itself, and the builder is also keeping track of the position. However, the two are decoupled. - -If the generation function doesn't have a chance at panicking, and/or the array element type doesn't implement `Drop`, the optimizer deems the `Drop` implementation on `ArrayBuilder` (and `ArrayConsumer`) dead code, and therefore `position` is never actually read from, so it becomes dead code as well, and is removed. - -So for simple non-`Drop`/non-panicking elements and generation functions, `generate` becomes a very simple loop that uses a slice iterator to write values to the array. - -Next, let's take a look at a more complex example where this *really* shines: `.zip` - -To cut down on excessively verbose code, `.zip` uses `FromIterator` for building the array, which has almost identical code to `generate`, so it will be omitted. - -The first implementation of `.zip` is defined as: - -
-Expand for code - -```rust -fn inverted_zip( - self, - lhs: GenericArray, - mut f: F, -) -> MappedSequence, B, U> -where - GenericArray: - GenericSequence + MappedGenericSequence, - Self: MappedGenericSequence, - Self::Length: ArrayLength + ArrayLength, - F: FnMut(B, Self::Item) -> U, -{ - unsafe { - let mut left = ArrayConsumer::new(lhs); - let mut right = ArrayConsumer::new(self); - - let (left_array_iter, left_position) = left.iter_position(); - let (right_array_iter, right_position) = right.iter_position(); - - FromIterator::from_iter(left_array_iter.zip(right_array_iter).map(|(l, r)| { - let left_value = ptr::read(l); - let right_value = ptr::read(r); - - *left_position += 1; - *right_position += 1; - - f(left_value, right_value) - })) - } -} -``` -
- -The gist of this is that we have two `GenericArray` instances that need to be zipped together and mapped to a new sequence. This employs two `ArrayConsumer`s, and more or less use the same pattern as the previous example. - -Again, the position values can be optimized out, and so can the slice iterator adapters. - -We can go a step further with this, however. - -Consider this: - -```rust -let a = arr![i32; 1, 3, 5, 7]; -let b = arr![i32; 2, 4, 6, 8]; - -let c = a.zip(b, |l, r| l + r); - -assert_eq!(c, arr![i32; 3, 7, 11, 15]); -``` - -when compiled with: - -``` -cargo rustc --lib --profile test --release -- -C target-cpu=native -C opt-level=3 --emit asm -``` - -will produce assembly with the following relevant instructions taken from the entire program: - -```asm -; Copy constant to register -vmovaps __xmm@00000007000000050000000300000001(%rip), %xmm0 - -; Copy constant to register -vmovaps __xmm@00000008000000060000000400000002(%rip), %xmm0 - -; Add the two values together -vpaddd 192(%rsp), %xmm0, %xmm1 - -; Copy constant to register -vmovaps __xmm@0000000f0000000b0000000700000003(%rip), %xmm0 - -; Compare result of the addition with the last constant -vpcmpeqb 128(%rsp), %xmm0, %xmm0 -``` - -so, aside from a bunch of obvious hygiene instructions around those selected instructions, -it seriously boils down that `.zip` call to a ***SINGLE*** SIMD instruction. In fact, it continues to do this for even larger arrays. Although it does fall back to individual additions for fewer than four elements, as it can't fit those into an SSE register evenly. - -Using this property of auto-vectorization without sacrificing safety, I created the [`numeric-array`](https://crates.io/crates/numeric-array) crate which makes use of this to wrap `GenericArray` and implement numeric traits so that almost *all* operations can be auto-vectorized, even complex ones like fused multiple-add. - -It doesn't end there, though. You may have noticed that the function name for zip above wasn't `zip`, but `inverted_zip`. - -This is because `generic-array` employs a clever specialization tactic to ensure `.zip` works corrects with: - -1. `a.zip(b, ...)` -2. `(&a).zip(b, ...)` -3. `(&a).zip(&b, ...)` -4. `a.zip(&b, ...)` - -wherein `GenericSequence` and `FunctionalSequence` have default implementations of `zip` variants, with concrete implementations for `GenericArray`. As `GenericSequence` is implemented for `&GenericArray`, where calling `into_iter` on produces a slice iterator, it can use "naive" iterator adapters to the same effect, while the specialized implementations use `ArrayConsumer`. - -The result is that any combination of move or reference calls to `.zip`, `.map` and `.fold` produce code that can be optimized, none of them falling back to slow non-slice iterators. All perfectly safe with the `ArrayBuilder` and `ArrayConsumer` systems. - -Honestly, `GenericArray` is better than standard arrays at this point. - -# The Future - -If/when const generics land in stable Rust, my intention is to reorient this crate or create a new crate to provide traits and wrappers for standard arrays to provide the same safety and performance discussed above. \ No newline at end of file diff --git a/src/rust/vendor/generic-array/rustfmt.toml b/src/rust/vendor/generic-array/rustfmt.toml deleted file mode 100644 index a46e4b2bd..000000000 --- a/src/rust/vendor/generic-array/rustfmt.toml +++ /dev/null @@ -1,3 +0,0 @@ -reorder_imports = true -reorder_imported_names = true -use_try_shorthand = true diff --git a/src/rust/vendor/generic-array/src/arr.rs b/src/rust/vendor/generic-array/src/arr.rs index aed499920..cdcc038a3 100644 --- a/src/rust/vendor/generic-array/src/arr.rs +++ b/src/rust/vendor/generic-array/src/arr.rs @@ -1,125 +1,125 @@ -//! Implementation for `arr!` macro. - -use super::ArrayLength; -use core::ops::Add; -use typenum::U1; - -/// Helper trait for `arr!` macro -pub trait AddLength>: ArrayLength { - /// Resulting length - type Output: ArrayLength; -} - -impl AddLength for N1 -where - N1: ArrayLength + Add, - N2: ArrayLength, - >::Output: ArrayLength, -{ - type Output = >::Output; -} - -/// Helper type for `arr!` macro -pub type Inc = >::Output; - -#[doc(hidden)] -#[macro_export] -macro_rules! arr_impl { - (@replace_expr $e:expr) => { 1 }; - ($T:ty; $N:ty, [$($x:expr),*], []) => ({ - const __ARR_LENGTH: usize = 0 $(+ $crate::arr_impl!(@replace_expr $x) )*; - - #[inline(always)] - fn __do_transmute>(arr: [T; __ARR_LENGTH]) -> $crate::GenericArray { - unsafe { $crate::transmute(arr) } - } - - let _: [(); <$N as $crate::typenum::Unsigned>::USIZE] = [(); __ARR_LENGTH]; - - __do_transmute::<$T, $N>([$($x as $T),*]) - }); - ($T:ty; $N:ty, [], [$x1:expr]) => ( - $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1], []) - ); - ($T:ty; $N:ty, [], [$x1:expr, $($x:expr),+]) => ( - $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1], [$($x),+]) - ); - ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr]) => ( - $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1], []) - ); - ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr, $($x:expr),+]) => ( - $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1], [$($x),+]) - ); -} - -/// Macro allowing for easy generation of Generic Arrays. -/// Example: `let test = arr![u32; 1, 2, 3];` -#[macro_export] -macro_rules! arr { - ($T:ty; $(,)*) => ({ - unsafe { $crate::transmute::<[$T; 0], $crate::GenericArray<$T, $crate::typenum::U0>>([]) } - }); - ($T:ty; $($x:expr),* $(,)*) => ( - $crate::arr_impl!($T; $crate::typenum::U0, [], [$($x),*]) - ); - ($($x:expr,)+) => (arr![$($x),+]); - () => ("""Macro requires a type, e.g. `let array = arr![u32; 1, 2, 3];`") -} - -mod doctests_only { - /// - /// # With ellision - /// - /// Testing that lifetimes aren't transmuted when they're ellided. - /// - /// ```compile_fail - /// #[macro_use] extern crate generic_array; - /// fn main() { - /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A { - /// arr![&A; a][0] - /// } - /// } - /// ``` - /// - /// ```rust - /// #[macro_use] extern crate generic_array; - /// fn main() { - /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'a A { - /// arr![&A; a][0] - /// } - /// } - /// ``` - /// - /// # Without ellision - /// - /// Testing that lifetimes aren't transmuted when they're specified explicitly. - /// - /// ```compile_fail - /// #[macro_use] extern crate generic_array; - /// fn main() { - /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A { - /// arr![&'a A; a][0] - /// } - /// } - /// ``` - /// - /// ```compile_fail - /// #[macro_use] extern crate generic_array; - /// fn main() { - /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A { - /// arr![&'static A; a][0] - /// } - /// } - /// ``` - /// - /// ```rust - /// #[macro_use] extern crate generic_array; - /// fn main() { - /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'a A { - /// arr![&'a A; a][0] - /// } - /// } - /// ``` - #[allow(dead_code)] - pub enum DocTests {} -} +//! Implementation for `arr!` macro. + +use super::ArrayLength; +use core::ops::Add; +use typenum::U1; + +/// Helper trait for `arr!` macro +pub trait AddLength>: ArrayLength { + /// Resulting length + type Output: ArrayLength; +} + +impl AddLength for N1 +where + N1: ArrayLength + Add, + N2: ArrayLength, + >::Output: ArrayLength, +{ + type Output = >::Output; +} + +/// Helper type for `arr!` macro +pub type Inc = >::Output; + +#[doc(hidden)] +#[macro_export] +macro_rules! arr_impl { + (@replace_expr $e:expr) => { 1 }; + ($T:ty; $N:ty, [$($x:expr),*], []) => ({ + const __ARR_LENGTH: usize = 0 $(+ $crate::arr_impl!(@replace_expr $x) )*; + + #[inline(always)] + fn __do_transmute>(arr: [T; __ARR_LENGTH]) -> $crate::GenericArray { + unsafe { $crate::transmute(arr) } + } + + let _: [(); <$N as $crate::typenum::Unsigned>::USIZE] = [(); __ARR_LENGTH]; + + __do_transmute::<$T, $N>([$($x as $T),*]) + }); + ($T:ty; $N:ty, [], [$x1:expr]) => ( + $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1], []) + ); + ($T:ty; $N:ty, [], [$x1:expr, $($x:expr),+]) => ( + $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1], [$($x),+]) + ); + ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr]) => ( + $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1], []) + ); + ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr, $($x:expr),+]) => ( + $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1], [$($x),+]) + ); +} + +/// Macro allowing for easy generation of Generic Arrays. +/// Example: `let test = arr![u32; 1, 2, 3];` +#[macro_export] +macro_rules! arr { + ($T:ty; $(,)*) => ({ + unsafe { $crate::transmute::<[$T; 0], $crate::GenericArray<$T, $crate::typenum::U0>>([]) } + }); + ($T:ty; $($x:expr),* $(,)*) => ( + $crate::arr_impl!($T; $crate::typenum::U0, [], [$($x),*]) + ); + ($($x:expr,)+) => (arr![$($x),+]); + () => ("""Macro requires a type, e.g. `let array = arr![u32; 1, 2, 3];`") +} + +mod doctests_only { + /// + /// # With ellision + /// + /// Testing that lifetimes aren't transmuted when they're ellided. + /// + /// ```compile_fail + /// #[macro_use] extern crate generic_array; + /// fn main() { + /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A { + /// arr![&A; a][0] + /// } + /// } + /// ``` + /// + /// ```rust + /// #[macro_use] extern crate generic_array; + /// fn main() { + /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'a A { + /// arr![&A; a][0] + /// } + /// } + /// ``` + /// + /// # Without ellision + /// + /// Testing that lifetimes aren't transmuted when they're specified explicitly. + /// + /// ```compile_fail + /// #[macro_use] extern crate generic_array; + /// fn main() { + /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A { + /// arr![&'a A; a][0] + /// } + /// } + /// ``` + /// + /// ```compile_fail + /// #[macro_use] extern crate generic_array; + /// fn main() { + /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A { + /// arr![&'static A; a][0] + /// } + /// } + /// ``` + /// + /// ```rust + /// #[macro_use] extern crate generic_array; + /// fn main() { + /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'a A { + /// arr![&'a A; a][0] + /// } + /// } + /// ``` + #[allow(dead_code)] + pub enum DocTests {} +} diff --git a/src/rust/vendor/generic-array/src/impl_zeroize.rs b/src/rust/vendor/generic-array/src/impl_zeroize.rs new file mode 100644 index 000000000..4edf558fc --- /dev/null +++ b/src/rust/vendor/generic-array/src/impl_zeroize.rs @@ -0,0 +1,24 @@ +use crate::{ArrayLength, GenericArray}; + +use zeroize::Zeroize; + +impl> Zeroize for GenericArray { + fn zeroize(&mut self) { + self.as_mut_slice().iter_mut().zeroize() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_zeroize() { + let mut array = GenericArray::::default(); + array[0] = 4; + array[1] = 9; + array.zeroize(); + assert_eq!(array[0], 0); + assert_eq!(array[1], 0); + } +} diff --git a/src/rust/vendor/generic-array/src/iter.rs b/src/rust/vendor/generic-array/src/iter.rs index 90e94fc6c..784ffa906 100644 --- a/src/rust/vendor/generic-array/src/iter.rs +++ b/src/rust/vendor/generic-array/src/iter.rs @@ -2,8 +2,8 @@ use super::{ArrayLength, GenericArray}; use core::iter::FusedIterator; -use core::mem::{MaybeUninit, ManuallyDrop}; -use core::{cmp, fmt, ptr, mem}; +use core::mem::ManuallyDrop; +use core::{cmp, fmt, mem, ptr}; /// An iterator that moves out of a `GenericArray` pub struct GenericArrayIter> { @@ -97,21 +97,19 @@ where fn clone(&self) -> Self { // This places all cloned elements at the start of the new array iterator, // not at their original indices. - unsafe { - let mut array: MaybeUninit> = MaybeUninit::uninit(); - let mut index_back = 0; - for (dst, src) in (&mut *array.as_mut_ptr()).iter_mut().zip(self.as_slice()) { - ptr::write(dst, src.clone()); + let mut array = unsafe { ptr::read(&self.array) }; + let mut index_back = 0; - index_back += 1; - } + for (dst, src) in array.as_mut_slice().into_iter().zip(self.as_slice()) { + unsafe { ptr::write(dst, src.clone()) }; + index_back += 1; + } - GenericArrayIter { - array: ManuallyDrop::new(array.assume_init()), - index: 0, - index_back - } + GenericArrayIter { + array, + index: 0, + index_back, } } } @@ -248,10 +246,6 @@ where } } -impl FusedIterator for GenericArrayIter -where - N: ArrayLength, -{ -} +impl FusedIterator for GenericArrayIter where N: ArrayLength {} // TODO: Implement `TrustedLen` when stabilized diff --git a/src/rust/vendor/generic-array/src/lib.rs b/src/rust/vendor/generic-array/src/lib.rs index 4e634448a..14a2797f8 100644 --- a/src/rust/vendor/generic-array/src/lib.rs +++ b/src/rust/vendor/generic-array/src/lib.rs @@ -68,10 +68,14 @@ #![deny(missing_docs)] #![deny(meta_variable_misuse)] #![no_std] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #[cfg(feature = "serde")] extern crate serde; +#[cfg(feature = "zeroize")] +extern crate zeroize; + #[cfg(test)] extern crate bincode; @@ -83,6 +87,9 @@ mod impls; #[cfg(feature = "serde")] mod impl_serde; +#[cfg(feature = "zeroize")] +mod impl_zeroize; + use core::iter::FromIterator; use core::marker::PhantomData; use core::mem::{MaybeUninit, ManuallyDrop}; @@ -201,7 +208,7 @@ where /// Creates an array one element at a time using a mutable iterator /// you can write to with `ptr::write`. /// -/// Incremenent the position while iterating to mark off created elements, +/// Increment the position while iterating to mark off created elements, /// which will be dropped if `into_inner` is not called. #[doc(hidden)] pub struct ArrayBuilder> { @@ -535,7 +542,9 @@ where /// Converts slice to a generic array reference with inferred length; /// - /// Length of the slice must be equal to the length of the array. + /// # Panics + /// + /// Panics if the slice is not equal to the length of the array. #[inline] pub fn from_slice(slice: &[T]) -> &GenericArray { slice.into() @@ -543,7 +552,9 @@ where /// Converts mutable slice to a mutable generic array reference /// - /// Length of the slice must be equal to the length of the array. + /// # Panics + /// + /// Panics if the slice is not equal to the length of the array. #[inline] pub fn from_mut_slice(slice: &mut [T]) -> &mut GenericArray { slice.into() @@ -553,7 +564,9 @@ where impl<'a, T, N: ArrayLength> From<&'a [T]> for &'a GenericArray { /// Converts slice to a generic array reference with inferred length; /// - /// Length of the slice must be equal to the length of the array. + /// # Panics + /// + /// Panics if the slice is not equal to the length of the array. #[inline] fn from(slice: &[T]) -> &GenericArray { assert_eq!(slice.len(), N::USIZE); @@ -565,7 +578,9 @@ impl<'a, T, N: ArrayLength> From<&'a [T]> for &'a GenericArray { impl<'a, T, N: ArrayLength> From<&'a mut [T]> for &'a mut GenericArray { /// Converts mutable slice to a mutable generic array reference /// - /// Length of the slice must be equal to the length of the array. + /// # Panics + /// + /// Panics if the slice is not equal to the length of the array. #[inline] fn from(slice: &mut [T]) -> &mut GenericArray { assert_eq!(slice.len(), N::USIZE); @@ -580,7 +595,9 @@ where { /// Construct a `GenericArray` from a slice by cloning its content /// - /// Length of the slice must be equal to the length of the array + /// # Panics + /// + /// Panics if the slice is not equal to the length of the array. #[inline] pub fn clone_from_slice(list: &[T]) -> GenericArray { Self::from_exact_iter(list.iter().cloned()) @@ -644,7 +661,7 @@ mod test { // cargo rustc --lib --profile test --release -- // -C target-cpu=native -C opt-level=3 --emit asm // and view the assembly to make sure test_assembly generates - // SIMD instructions instead of a niave loop. + // SIMD instructions instead of a naive loop. #[inline(never)] pub fn black_box(val: T) -> T { diff --git a/src/rust/vendor/generic-array/tests/arr.rs b/src/rust/vendor/generic-array/tests/arr.rs deleted file mode 100644 index 461805a50..000000000 --- a/src/rust/vendor/generic-array/tests/arr.rs +++ /dev/null @@ -1,27 +0,0 @@ -#[macro_use] -extern crate generic_array; -extern crate typenum; - -#[test] -fn empty_without_trailing_comma() { - let ar = arr![u8; ]; - assert_eq!(format!("{:x}", ar), ""); -} - -#[test] -fn empty_with_trailing_comma() { - let ar = arr![u8; , ]; - assert_eq!(format!("{:x}", ar), ""); -} - -#[test] -fn without_trailing_comma() { - let ar = arr![u8; 10, 20, 30]; - assert_eq!(format!("{:x}", ar), "0a141e"); -} - -#[test] -fn with_trailing_comma() { - let ar = arr![u8; 10, 20, 30, ]; - assert_eq!(format!("{:x}", ar), "0a141e"); -} diff --git a/src/rust/vendor/generic-array/tests/generics.rs b/src/rust/vendor/generic-array/tests/generics.rs deleted file mode 100644 index 952867b38..000000000 --- a/src/rust/vendor/generic-array/tests/generics.rs +++ /dev/null @@ -1,98 +0,0 @@ -#![recursion_limit = "128"] - -#[macro_use] -extern crate generic_array; - -use generic_array::typenum::consts::U4; - -use std::fmt::Debug; -use std::ops::Add; - -use generic_array::{GenericArray, ArrayLength}; -use generic_array::sequence::*; -use generic_array::functional::*; - -/// Example function using generics to pass N-length sequences and map them -pub fn generic_map(s: S) -where - S: FunctionalSequence, // `.map` - S::Item: Add, // `x + 1` - S: MappedGenericSequence, // `i32` -> `i32` - MappedSequence: Debug, // println! -{ - let a = s.map(|x| x + 1); - - println!("{:?}", a); -} - -/// Complex example function using generics to pass N-length sequences, zip them, and then map that result. -/// -/// If used with `GenericArray` specifically this isn't necessary -pub fn generic_sequence_zip_sum(a: A, b: B) -> i32 -where - A: FunctionalSequence, // `.zip` - B: FunctionalSequence, // `.zip` - A: MappedGenericSequence, // `i32` -> `i32` - B: MappedGenericSequence>, // `i32` -> `i32`, prove A and B can map to the same output - A::Item: Add, // `l + r` - MappedSequence: MappedGenericSequence + FunctionalSequence, // `.map` - SequenceItem>: Add, // `x + 1` - MappedSequence, i32, i32>: Debug, // `println!` - MappedSequence, i32, i32>: FunctionalSequence, // `.fold` - SequenceItem, i32, i32>>: Add // `x + a`, note the order -{ - let c = a.zip(b, |l, r| l + r).map(|x| x + 1); - - println!("{:?}", c); - - c.fold(0, |a, x| x + a) -} - -/// Super-simple fixed-length i32 `GenericArray`s -pub fn generic_array_plain_zip_sum(a: GenericArray, b: GenericArray) -> i32 { - a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a) -} - -pub fn generic_array_variable_length_zip_sum(a: GenericArray, b: GenericArray) -> i32 -where - N: ArrayLength, -{ - a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a) -} - -pub fn generic_array_same_type_variable_length_zip_sum(a: GenericArray, b: GenericArray) -> i32 -where - N: ArrayLength + ArrayLength<>::Output>, - T: Add, -{ - a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a) -} - -/// Complex example using fully generic `GenericArray`s with the same length. -/// -/// It's mostly just the repeated `Add` traits, which would be present in other systems anyway. -pub fn generic_array_zip_sum + ArrayLength>(a: GenericArray, b: GenericArray) -> i32 -where - A: Add, - N: ArrayLength<
>::Output> + - ArrayLength<<>::Output as Add>::Output>, - >::Output: Add, - <>::Output as Add>::Output: Add, -{ - a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a) -} - -#[test] -fn test_generics() { - generic_map(arr![i32; 1, 2, 3, 4]); - - assert_eq!(generic_sequence_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28); - - assert_eq!(generic_array_plain_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28); - - assert_eq!(generic_array_variable_length_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28); - - assert_eq!(generic_array_same_type_variable_length_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28); - - assert_eq!(generic_array_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28); -} \ No newline at end of file diff --git a/src/rust/vendor/generic-array/tests/hex.rs b/src/rust/vendor/generic-array/tests/hex.rs deleted file mode 100644 index 0c63391a6..000000000 --- a/src/rust/vendor/generic-array/tests/hex.rs +++ /dev/null @@ -1,61 +0,0 @@ -#[macro_use] -extern crate generic_array; -extern crate typenum; - -use generic_array::GenericArray; -use std::str::from_utf8; -use typenum::U2048; - -#[test] -fn short_lower_hex() { - let ar = arr![u8; 10, 20, 30]; - assert_eq!(format!("{:x}", ar), "0a141e"); -} - -#[test] -fn short_upper_hex() { - let ar = arr![u8; 30, 20, 10]; - assert_eq!(format!("{:X}", ar), "1E140A"); -} - -#[test] -fn long_lower_hex() { - let ar = GenericArray::::default(); - assert_eq!(format!("{:x}", ar), from_utf8(&[b'0'; 4096]).unwrap()); -} - -#[test] -fn long_lower_hex_truncated() { - let ar = GenericArray::::default(); - assert_eq!(format!("{:.3001x}", ar), from_utf8(&[b'0'; 3001]).unwrap()); -} - -#[test] -fn long_upper_hex() { - let ar = GenericArray::::default(); - assert_eq!(format!("{:X}", ar), from_utf8(&[b'0'; 4096]).unwrap()); -} - -#[test] -fn long_upper_hex_truncated() { - let ar = GenericArray::::default(); - assert_eq!(format!("{:.2777X}", ar), from_utf8(&[b'0'; 2777]).unwrap()); -} - -#[test] -fn truncated_lower_hex() { - let ar = arr![u8; 10, 20, 30, 40, 50]; - assert_eq!(format!("{:.2x}", ar), "0a"); - assert_eq!(format!("{:.3x}", ar), "0a1"); - assert_eq!(format!("{:.4x}", ar), "0a14"); -} - -#[test] -fn truncated_upper_hex() { - let ar = arr![u8; 30, 20, 10, 17, 0]; - assert_eq!(format!("{:.4X}", ar), "1E14"); - assert_eq!(format!("{:.5X}", ar), "1E140"); - assert_eq!(format!("{:.6X}", ar), "1E140A"); - assert_eq!(format!("{:.7X}", ar), "1E140A1"); - assert_eq!(format!("{:.8X}", ar), "1E140A11"); -} diff --git a/src/rust/vendor/generic-array/tests/import_name.rs b/src/rust/vendor/generic-array/tests/import_name.rs deleted file mode 100644 index f59f1b6c5..000000000 --- a/src/rust/vendor/generic-array/tests/import_name.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[macro_use] -extern crate generic_array as gen_arr; - -use gen_arr::typenum; - -#[test] -fn test_different_crate_name() { - let _: gen_arr::GenericArray = arr![u32; 0, 1, 2, 3]; - let _: gen_arr::GenericArray = arr![u32;]; -} diff --git a/src/rust/vendor/generic-array/tests/iter.rs b/src/rust/vendor/generic-array/tests/iter.rs deleted file mode 100644 index d96f98414..000000000 --- a/src/rust/vendor/generic-array/tests/iter.rs +++ /dev/null @@ -1,199 +0,0 @@ -#[macro_use] -extern crate generic_array; - -use std::cell::Cell; -use std::ops::Drop; - -use generic_array::typenum::consts::U5; -use generic_array::GenericArray; - -#[test] -fn test_from_iterator() { - struct BadExact(usize); - - impl Iterator for BadExact { - type Item = usize; - fn next(&mut self) -> Option { - if self.0 == 1 { - return None; - } - self.0 -= 1; - Some(self.0) - } - } - impl ExactSizeIterator for BadExact { - fn len(&self) -> usize { self.0 } - } - assert!(GenericArray::::from_exact_iter(BadExact(5)).is_none()); -} - -#[test] -fn test_into_iter_as_slice() { - let array = arr![char; 'a', 'b', 'c']; - let mut into_iter = array.into_iter(); - assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); - let _ = into_iter.next().unwrap(); - assert_eq!(into_iter.as_slice(), &['b', 'c']); - let _ = into_iter.next().unwrap(); - let _ = into_iter.next().unwrap(); - assert_eq!(into_iter.as_slice(), &[]); -} - -#[test] -fn test_into_iter_as_mut_slice() { - let array = arr![char; 'a', 'b', 'c']; - let mut into_iter = array.into_iter(); - assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); - into_iter.as_mut_slice()[0] = 'x'; - into_iter.as_mut_slice()[1] = 'y'; - assert_eq!(into_iter.next().unwrap(), 'x'); - assert_eq!(into_iter.as_slice(), &['y', 'c']); -} - -#[test] -fn test_into_iter_debug() { - let array = arr![char; 'a', 'b', 'c']; - let into_iter = array.into_iter(); - let debug = format!("{:?}", into_iter); - assert_eq!(debug, "GenericArrayIter(['a', 'b', 'c'])"); -} - -#[test] -fn test_into_iter_clone() { - fn iter_equal>(it: I, slice: &[i32]) { - let v: Vec = it.collect(); - assert_eq!(&v[..], slice); - } - let mut it = arr![i32; 1, 2, 3].into_iter(); - iter_equal(it.clone(), &[1, 2, 3]); - assert_eq!(it.next(), Some(1)); - let mut it = it.rev(); - iter_equal(it.clone(), &[3, 2]); - assert_eq!(it.next(), Some(3)); - iter_equal(it.clone(), &[2]); - assert_eq!(it.next(), Some(2)); - iter_equal(it.clone(), &[]); - assert_eq!(it.next(), None); -} - -#[test] -fn test_into_iter_nth() { - let v = arr![i32; 0, 1, 2, 3, 4]; - for i in 0..v.len() { - assert_eq!(v.clone().into_iter().nth(i).unwrap(), v[i]); - } - assert_eq!(v.clone().into_iter().nth(v.len()), None); - - let mut iter = v.into_iter(); - assert_eq!(iter.nth(2).unwrap(), v[2]); - assert_eq!(iter.nth(1).unwrap(), v[4]); -} - -#[test] -fn test_into_iter_last() { - let v = arr![i32; 0, 1, 2, 3, 4]; - assert_eq!(v.into_iter().last().unwrap(), 4); - assert_eq!(arr![i32; 0].into_iter().last().unwrap(), 0); -} - -#[test] -fn test_into_iter_count() { - let v = arr![i32; 0, 1, 2, 3, 4]; - assert_eq!(v.clone().into_iter().count(), 5); - - let mut iter2 = v.into_iter(); - iter2.next(); - iter2.next(); - assert_eq!(iter2.count(), 3); -} - -#[test] -fn test_into_iter_flat_map() { - assert!((0..5).flat_map(|i| arr![i32; 2 * i, 2 * i + 1]).eq(0..10)); -} - -#[test] -fn test_into_iter_fold() { - assert_eq!( - arr![i32; 1, 2, 3, 4].into_iter().fold(0, |sum, x| sum + x), - 10 - ); - - let mut iter = arr![i32; 0, 1, 2, 3, 4, 5].into_iter(); - - iter.next(); - iter.next_back(); - - assert_eq!(iter.clone().fold(0, |sum, x| sum + x), 10); - - assert_eq!(iter.rfold(0, |sum, x| sum + x), 10); -} - -#[test] -fn test_into_iter_drops() { - struct R<'a> { - i: &'a Cell, - } - - impl<'a> Drop for R<'a> { - fn drop(&mut self) { - self.i.set(self.i.get() + 1); - } - } - - fn r(i: &Cell) -> R { - R { i: i } - } - - fn v(i: &Cell) -> GenericArray { - arr![R; r(i), r(i), r(i), r(i), r(i)] - } - - let i = Cell::new(0); - { - v(&i).into_iter(); - } - assert_eq!(i.get(), 5); - - let i = Cell::new(0); - { - let mut iter = v(&i).into_iter(); - let _x = iter.next(); - assert_eq!(i.get(), 0); - assert_eq!(iter.count(), 4); - assert_eq!(i.get(), 4); - } - assert_eq!(i.get(), 5); - - let i = Cell::new(0); - { - let mut iter = v(&i).into_iter(); - let _x = iter.nth(2); - assert_eq!(i.get(), 2); - let _y = iter.last(); - assert_eq!(i.get(), 3); - } - assert_eq!(i.get(), 5); - - let i = Cell::new(0); - for (index, _x) in v(&i).into_iter().enumerate() { - assert_eq!(i.get(), index); - } - assert_eq!(i.get(), 5); - - let i = Cell::new(0); - for (index, _x) in v(&i).into_iter().rev().enumerate() { - assert_eq!(i.get(), index); - } - assert_eq!(i.get(), 5); -} - -/* -//TODO: Cover this -#[allow(dead_code)] -fn assert_covariance() { - fn into_iter<'new>(i: GenericArrayIter<&'static str, U10>) -> GenericArrayIter<&'new str, U10> { - i - } -} -*/ diff --git a/src/rust/vendor/generic-array/tests/mod.rs b/src/rust/vendor/generic-array/tests/mod.rs deleted file mode 100644 index fb1a35f2c..000000000 --- a/src/rust/vendor/generic-array/tests/mod.rs +++ /dev/null @@ -1,379 +0,0 @@ -#![recursion_limit = "128"] -#![no_std] -#[macro_use] -extern crate generic_array; -use core::cell::Cell; -use core::ops::{Add, Drop}; -use generic_array::functional::*; -use generic_array::sequence::*; -use generic_array::typenum::{U0, U3, U4, U97}; -use generic_array::GenericArray; - -#[test] -fn test() { - let mut list97 = [0; 97]; - for i in 0..97 { - list97[i] = i as i32; - } - let l: GenericArray = GenericArray::clone_from_slice(&list97); - assert_eq!(l[0], 0); - assert_eq!(l[1], 1); - assert_eq!(l[32], 32); - assert_eq!(l[56], 56); -} - -#[test] -fn test_drop() { - #[derive(Clone)] - struct TestDrop<'a>(&'a Cell); - - impl<'a> Drop for TestDrop<'a> { - fn drop(&mut self) { - self.0.set(self.0.get() + 1); - } - } - - let drop_counter = Cell::new(0); - { - let _: GenericArray = arr![TestDrop; TestDrop(&drop_counter), - TestDrop(&drop_counter), - TestDrop(&drop_counter)]; - } - assert_eq!(drop_counter.get(), 3); -} - -#[test] -fn test_arr() { - let test: GenericArray = arr![u32; 1, 2, 3]; - assert_eq!(test[1], 2); -} - -#[test] -fn test_copy() { - let test = arr![u32; 1, 2, 3]; - let test2 = test; - // if GenericArray is not copy, this should fail as a use of a moved value - assert_eq!(test[1], 2); - assert_eq!(test2[0], 1); -} - -#[derive(Debug, PartialEq, Eq)] -struct NoClone(T); - -#[test] -fn test_from_slice() { - let arr = [1, 2, 3, 4]; - let gen_arr = GenericArray::<_, U3>::from_slice(&arr[..3]); - assert_eq!(&arr[..3], gen_arr.as_slice()); - let arr = [NoClone(1u32), NoClone(2), NoClone(3), NoClone(4)]; - let gen_arr = GenericArray::<_, U3>::from_slice(&arr[..3]); - assert_eq!(&arr[..3], gen_arr.as_slice()); -} - -#[test] -fn test_from_mut_slice() { - let mut arr = [1, 2, 3, 4]; - { - let gen_arr = GenericArray::<_, U3>::from_mut_slice(&mut arr[..3]); - gen_arr[2] = 10; - } - assert_eq!(arr, [1, 2, 10, 4]); - let mut arr = [NoClone(1u32), NoClone(2), NoClone(3), NoClone(4)]; - { - let gen_arr = GenericArray::<_, U3>::from_mut_slice(&mut arr[..3]); - gen_arr[2] = NoClone(10); - } - assert_eq!(arr, [NoClone(1), NoClone(2), NoClone(10), NoClone(4)]); -} - -#[test] -fn test_default() { - let arr = GenericArray::::default(); - assert_eq!(arr.as_slice(), &[0, 0, 0, 0]); -} - -#[test] -fn test_from() { - let data = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]; - let garray: GenericArray<(usize, usize, usize), U3> = data.into(); - assert_eq!(&data, garray.as_slice()); -} - -#[test] -fn test_unit_macro() { - let arr = arr![f32; 3.14]; - assert_eq!(arr[0], 3.14); -} - -#[test] -fn test_empty_macro() { - let _arr = arr![f32;]; -} - -#[test] -fn test_cmp() { - let _ = arr![u8; 0x00].cmp(&arr![u8; 0x00]); -} - -/// This test should cause a helpful compile error if uncommented. -// #[test] -// fn test_empty_macro2(){ -// let arr = arr![]; -// } -#[cfg(feature = "serde")] -mod impl_serde { - extern crate serde_json; - - use generic_array::typenum::U6; - use generic_array::GenericArray; - - #[test] - fn test_serde_implementation() { - let array: GenericArray = arr![f64; 0.0, 5.0, 3.0, 7.07192, 76.0, -9.0]; - let string = serde_json::to_string(&array).unwrap(); - assert_eq!(string, "[0.0,5.0,3.0,7.07192,76.0,-9.0]"); - - let test_array: GenericArray = serde_json::from_str(&string).unwrap(); - assert_eq!(test_array, array); - } -} - -#[test] -fn test_map() { - let b: GenericArray = GenericArray::generate(|i| i as i32 * 4).map(|x| x - 3); - - assert_eq!(b, arr![i32; -3, 1, 5, 9]); -} - -#[test] -fn test_zip() { - let a: GenericArray<_, U4> = GenericArray::generate(|i| i + 1); - let b: GenericArray<_, U4> = GenericArray::generate(|i| i as i32 * 4); - - // Uses reference and non-reference arguments - let c = (&a).zip(b, |r, l| *r as i32 + l); - - assert_eq!(c, arr![i32; 1, 6, 11, 16]); -} - -#[test] -#[should_panic] -fn test_from_iter_short() { - use core::iter::repeat; - - let a: GenericArray<_, U4> = repeat(11).take(3).collect(); - - assert_eq!(a, arr![i32; 11, 11, 11, 0]); -} - -#[test] -fn test_from_iter() { - use core::iter::{once, repeat}; - - let a: GenericArray<_, U4> = repeat(11).take(3).chain(once(0)).collect(); - - assert_eq!(a, arr![i32; 11, 11, 11, 0]); -} - -#[allow(unused)] -#[derive(Debug, Copy, Clone)] -enum E { - V, - V2(i32), - V3 { h: bool, i: i32 }, -} - -#[allow(unused)] -#[derive(Debug, Copy, Clone)] -#[repr(C)] -#[repr(packed)] -struct Test { - t: u16, - s: u32, - mm: bool, - r: u16, - f: u16, - p: (), - o: u32, - ff: *const extern "C" fn(*const char) -> *const core::ffi::c_void, - l: *const core::ffi::c_void, - w: bool, - q: bool, - v: E, -} - -#[test] -fn test_sizes() { - use core::mem::{size_of, size_of_val}; - - assert_eq!(size_of::(), 8); - - assert_eq!(size_of::(), 25 + size_of::() * 2); - - assert_eq!(size_of_val(&arr![u8; 1, 2, 3]), size_of::() * 3); - assert_eq!(size_of_val(&arr![u32; 1]), size_of::() * 1); - assert_eq!(size_of_val(&arr![u64; 1, 2, 3, 4]), size_of::() * 4); - - assert_eq!(size_of::>(), size_of::() * 97); -} - -#[test] -fn test_alignment() { - use core::mem::align_of; - - assert_eq!(align_of::>(), align_of::<[u32; 0]>()); - assert_eq!(align_of::>(), align_of::<[u32; 3]>()); - assert_eq!(align_of::>(), align_of::<[Test; 3]>()); -} - -#[test] -fn test_append() { - let a = arr![i32; 1, 2, 3]; - - let b = a.append(4); - - assert_eq!(b, arr![i32; 1, 2, 3, 4]); -} - -#[test] -fn test_prepend() { - let a = arr![i32; 1, 2, 3]; - - let b = a.prepend(4); - - assert_eq!(b, arr![i32; 4, 1, 2, 3]); -} - -#[test] -fn test_pop() { - let a = arr![i32; 1, 2, 3, 4]; - - let (init, last) = a.pop_back(); - - assert_eq!(init, arr![i32; 1, 2, 3]); - assert_eq!(last, 4); - - let (head, tail) = a.pop_front(); - - assert_eq!(head, 1); - assert_eq!(tail, arr![i32; 2, 3, 4]); -} - -#[test] -fn test_split() { - let a = arr![i32; 1, 2, 3, 4]; - - let (b, c) = a.split(); - - assert_eq!(b, arr![i32; 1]); - assert_eq!(c, arr![i32; 2, 3, 4]); - - let (e, f) = a.split(); - - assert_eq!(e, arr![i32; 1, 2]); - assert_eq!(f, arr![i32; 3, 4]); -} - -#[test] -fn test_split_ref() { - let a = arr![i32; 1, 2, 3, 4]; - let a_ref = &a; - - let (b_ref, c_ref) = a_ref.split(); - - assert_eq!(b_ref, &arr![i32; 1]); - assert_eq!(c_ref, &arr![i32; 2, 3, 4]); - - let (e_ref, f_ref) = a_ref.split(); - - assert_eq!(e_ref, &arr![i32; 1, 2]); - assert_eq!(f_ref, &arr![i32; 3, 4]); -} - -#[test] -fn test_split_mut() { - let mut a = arr![i32; 1, 2, 3, 4]; - let a_ref = &mut a; - - let (b_ref, c_ref) = a_ref.split(); - - assert_eq!(b_ref, &mut arr![i32; 1]); - assert_eq!(c_ref, &mut arr![i32; 2, 3, 4]); - - let (e_ref, f_ref) = a_ref.split(); - - assert_eq!(e_ref, &mut arr![i32; 1, 2]); - assert_eq!(f_ref, &mut arr![i32; 3, 4]); -} - -#[test] -fn test_concat() { - let a = arr![i32; 1, 2]; - let b = arr![i32; 3, 4, 5]; - - let c = a.concat(b); - - assert_eq!(c, arr![i32; 1, 2, 3, 4, 5]); - - let (d, e) = c.split(); - - assert_eq!(d, arr![i32; 1, 2]); - assert_eq!(e, arr![i32; 3, 4, 5]); -} - -#[test] -fn test_fold() { - let a = arr![i32; 1, 2, 3, 4]; - - assert_eq!(10, a.fold(0, |a, x| a + x)); -} - -fn sum_generic(s: S) -> i32 -where - S: FunctionalSequence, - S::Item: Add, // `+` - i32: Add, // reflexive -{ - s.fold(0, |a, x| a + x) -} - -#[test] -fn test_sum() { - let a = sum_generic(arr![i32; 1, 2, 3, 4]); - - assert_eq!(a, 10); -} - -#[test] -fn test_as_ref() { - let a = arr![i32; 1, 2, 3, 4]; - let a_ref: &[i32; 4] = a.as_ref(); - assert_eq!(a_ref, &[1, 2, 3, 4]); -} - -#[test] -fn test_as_mut() { - let mut a = arr![i32; 1, 2, 3, 4]; - let a_mut: &mut [i32; 4] = a.as_mut(); - assert_eq!(a_mut, &mut [1, 2, 3, 4]); - a_mut[2] = 0; - assert_eq!(a_mut, &mut [1, 2, 0, 4]); - assert_eq!(a, arr![i32; 1, 2, 0, 4]); -} - -#[test] -fn test_from_array_ref() { - let a = arr![i32; 1, 2, 3, 4]; - let a_ref: &[i32; 4] = a.as_ref(); - let a_from: &GenericArray = a_ref.into(); - assert_eq!(&a, a_from); -} - -#[test] -fn test_from_array_mut() { - let mut a = arr![i32; 1, 2, 3, 4]; - let mut a_copy = a; - let a_mut: &mut [i32; 4] = a.as_mut(); - let a_from: &mut GenericArray = a_mut.into(); - assert_eq!(&mut a_copy, a_from); -} diff --git a/src/rust/vendor/group/.cargo-checksum.json b/src/rust/vendor/group/.cargo-checksum.json new file mode 100644 index 000000000..ce5ce83d3 --- /dev/null +++ b/src/rust/vendor/group/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"cf3d53107bd2a496c38077226782c468f7ad48e6de4fe73fcc8b187566889dae","COPYRIGHT":"7429802d3e67e3308471b91fbea341e484c4e0a23d0fb230a8636c38184cec79","Cargo.toml":"5bd9c11858db53976ad77e8cfec6142ec515d66bbac254d118dbbe97c6778ede","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"f0a93bc0b7139543f09b54045b4fdc180575d30948ee781beb9771c17b9178ba","rust-toolchain":"19f1c71cabd3cb062544023af771fbb2883524775fdaed6ca5855bae359b7b9c","src/cofactor.rs":"360def02367e55d932493e2b2fbce53e7d817fdaf8acd6a4823d471283f2f825","src/lib.rs":"ef704cbc23b28c24859fd6cfd2050e1298dbb3da79aa38776859231462643d54","src/prime.rs":"886fd7aaa0763912af25bb147264d73caa699cf3c2f9c0794b8230ce4b0675f3","src/tests/mod.rs":"62ce720485ba3eeddcc2a393f845fc2e8c235a28e9b86d31c453d295e7405a95","src/wnaf.rs":"888ad4643521464c1e21efd9e167c08e77e1801c74250c2425eb6e47f7419972"},"package":"f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"} \ No newline at end of file diff --git a/src/rust/vendor/group/CHANGELOG.md b/src/rust/vendor/group/CHANGELOG.md new file mode 100644 index 000000000..aec3f6d2c --- /dev/null +++ b/src/rust/vendor/group/CHANGELOG.md @@ -0,0 +1,77 @@ +# Changelog +All notable changes to this library will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this library adheres to Rust's notion of +[Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.13.0] - 2022-12-06 +### Changed +- Bumped `ff` to `0.13` + +## [0.12.1] - 2022-10-13 +### Added +- `group::{WnafBase, WnafScalar}` structs for caching precomputations of both + bases and scalars, for improved many-base many-scalar multiplication + performance. +- `impl memuse::DynamicUsage for group::{Wnaf WnafBase, WnafScalar}`, behind the + new `wnaf-memuse` feature flag, to enable the heap usage of these types to be + measured at runtime. + +### Changed +- Removed temporary allocations from `Wnaf` internals for improved performance. + +## [0.12.0] - 2022-05-04 +### Changed +- MSRV is now 1.56.0. +- Bumped `ff` to `0.12` + +## [0.11.0] - 2021-09-02 +### Fixed +- The affine scalar multiplication bounds on the following traits had typos that + prevented multiplying by `&Self::Scalar`, which has now been fixed: + - `group::cofactor::{CofactorCurve::Affine, CofactorCurveAffine}` + - `group::prime::{PrimeCurve::Affine, PrimeCurveAffine}` + +### Added +- `Copy + Send + Sync + 'static` bounds on `group::GroupEncoding::Repr`. + +### Changed +- Bumped `ff` to 0.11. + +## [0.10.0] - 2021-06-01 +### Added +- `group::ff`, which re-exports the `ff` crate to make version-matching easier. + +### Changed +- MSRV is now 1.51.0. +- Bumped `ff` to 0.10. + +### Removed +- `group::cofactor::CofactorGroup::is_torsion_free` provided implementation + (trait implementors must now implement this method themselves). This avoids + a hard dependency on the `ff/bits` feature flag. + +## [0.9.0] - 2021-01-06 +### Changed +- Bumped dependencies to `ff 0.9`, `rand_core 0.6`, `rand 0.8`. + +## [0.8.0] - 2020-09-08 +### Added +- `no_std` support. + +### Changed +- MSRV is now 1.44.0. +- Bumped `ff` to 0.8. +- `group::{wnaf, Wnaf, WnafGroup}` are now gated behind the (default-enabled) + `alloc` feature flag. The `byteorder` dependency is now optional. +- `group::tests` is now gated behind the `tests` feature flag. The `rand` and + `rand_xorshift` dependencies are now optional. + +### Removed +- `fmt::Display` bound from the following traits: + - `group::Group` + - `group::cofactor::CofactorCurveAffine` + - `group::prime::PrimeCurveAffine` diff --git a/src/rust/vendor/group/COPYRIGHT b/src/rust/vendor/group/COPYRIGHT new file mode 100644 index 000000000..849e32747 --- /dev/null +++ b/src/rust/vendor/group/COPYRIGHT @@ -0,0 +1,14 @@ +Copyrights in the "group" library are retained by their contributors. No +copyright assignment is required to contribute to the "group" library. + +The "group" library is licensed under either of + + * Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT) + +at your option. + +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/src/rust/vendor/group/Cargo.toml b/src/rust/vendor/group/Cargo.toml new file mode 100644 index 000000000..059f0f761 --- /dev/null +++ b/src/rust/vendor/group/Cargo.toml @@ -0,0 +1,55 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "group" +version = "0.13.0" +authors = ["Sean Bowe ", "Jack Grigg "] +description = "Elliptic curve group traits and utilities" +homepage = "https://github.com/zkcrypto/group" +documentation = "https://docs.rs/group/" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/zkcrypto/group" +resolver = "2" +[dependencies.ff] +version = "0.13" +default-features = false + +[dependencies.memuse] +version = "0.2" +optional = true + +[dependencies.rand] +version = "0.8" +optional = true +default-features = false + +[dependencies.rand_core] +version = "0.6" +default-features = false + +[dependencies.rand_xorshift] +version = "0.3" +optional = true + +[dependencies.subtle] +version = "2.2.1" +default-features = false + +[features] +alloc = [] +default = ["alloc"] +tests = ["alloc", "rand", "rand_xorshift"] +wnaf-memuse = ["alloc", "memuse"] +[badges.maintenance] +status = "actively-developed" diff --git a/src/rust/vendor/group/LICENSE-APACHE b/src/rust/vendor/group/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/src/rust/vendor/group/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/group/LICENSE-MIT b/src/rust/vendor/group/LICENSE-MIT new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/src/rust/vendor/group/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/group/README.md b/src/rust/vendor/group/README.md new file mode 100644 index 000000000..5c2398b2b --- /dev/null +++ b/src/rust/vendor/group/README.md @@ -0,0 +1,20 @@ +# group [![Crates.io](https://img.shields.io/crates/v/group.svg)](https://crates.io/crates/group) # + +`group` is a crate for working with groups over elliptic curves. + +## 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/src/rust/vendor/group/rust-toolchain b/src/rust/vendor/group/rust-toolchain new file mode 100644 index 000000000..3ebf789f5 --- /dev/null +++ b/src/rust/vendor/group/rust-toolchain @@ -0,0 +1 @@ +1.56.0 diff --git a/src/rust/vendor/group/src/cofactor.rs b/src/rust/vendor/group/src/cofactor.rs new file mode 100644 index 000000000..84bfe0a6b --- /dev/null +++ b/src/rust/vendor/group/src/cofactor.rs @@ -0,0 +1,100 @@ +use core::fmt; +use core::ops::{Mul, Neg}; +use ff::PrimeField; +use subtle::{Choice, CtOption}; + +use crate::{prime::PrimeGroup, Curve, Group, GroupEncoding, GroupOps, GroupOpsOwned}; + +/// This trait represents an element of a cryptographic group with a large prime-order +/// subgroup and a comparatively-small cofactor. +pub trait CofactorGroup: + Group + + GroupEncoding + + GroupOps<::Subgroup> + + GroupOpsOwned<::Subgroup> +{ + /// The large prime-order subgroup in which cryptographic operations are performed. + /// If `Self` implements `PrimeGroup`, then `Self::Subgroup` may be `Self`. + type Subgroup: PrimeGroup + Into; + + /// Maps `self` to the prime-order subgroup by multiplying this element by some + /// `k`-multiple of the cofactor. + /// + /// The value `k` does not vary between inputs for a given implementation, but may + /// vary between different implementations of `CofactorGroup` because some groups have + /// more efficient methods of clearing the cofactor when `k` is allowed to be + /// different than `1`. + /// + /// If `Self` implements [`PrimeGroup`], this returns `self`. + fn clear_cofactor(&self) -> Self::Subgroup; + + /// Returns `self` if it is contained in the prime-order subgroup. + /// + /// If `Self` implements [`PrimeGroup`], this returns `Some(self)`. + fn into_subgroup(self) -> CtOption; + + /// Determines if this element is of small order. + /// + /// Returns: + /// - `true` if `self` is in the torsion subgroup. + /// - `false` if `self` is not in the torsion subgroup. + fn is_small_order(&self) -> Choice { + self.clear_cofactor().is_identity() + } + + /// Determines if this element is "torsion free", i.e., is contained in the + /// prime-order subgroup. + /// + /// Returns: + /// - `true` if `self` has trivial torsion and is in the prime-order subgroup. + /// - `false` if `self` has non-zero torsion component and is not in the prime-order + /// subgroup. + fn is_torsion_free(&self) -> Choice; +} + +/// Efficient representation of an elliptic curve point guaranteed to be +/// in the correct prime order subgroup. +pub trait CofactorCurve: + Curve::Affine> + CofactorGroup +{ + type Affine: CofactorCurveAffine + + Mul + + for<'r> Mul<&'r Self::Scalar, Output = Self>; +} + +/// Affine representation of an elliptic curve point guaranteed to be +/// in the correct prime order subgroup. +pub trait CofactorCurveAffine: + GroupEncoding + + Copy + + Clone + + Sized + + Send + + Sync + + fmt::Debug + + PartialEq + + Eq + + 'static + + Neg + + Mul<::Scalar, Output = ::Curve> + + for<'r> Mul< + &'r ::Scalar, + Output = ::Curve, + > +{ + type Scalar: PrimeField; + type Curve: CofactorCurve; + + /// Returns the additive identity. + fn identity() -> Self; + + /// Returns a fixed generator of unknown exponent. + fn generator() -> Self; + + /// Determines if this point represents the point at infinity; the + /// additive identity. + fn is_identity(&self) -> Choice; + + /// Converts this element to its curve representation. + fn to_curve(&self) -> Self::Curve; +} diff --git a/src/rust/vendor/group/src/lib.rs b/src/rust/vendor/group/src/lib.rs new file mode 100644 index 000000000..27ed5c9b1 --- /dev/null +++ b/src/rust/vendor/group/src/lib.rs @@ -0,0 +1,174 @@ +#![no_std] +// Catch documentation errors caused by code changes. +#![deny(rustdoc::broken_intra_doc_links)] + +#[cfg(feature = "alloc")] +#[macro_use] +extern crate alloc; + +// Re-export ff to make version-matching easier. +pub use ff; + +use core::fmt; +use core::iter::Sum; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use ff::PrimeField; +use rand_core::RngCore; +use subtle::{Choice, CtOption}; + +pub mod cofactor; +pub mod prime; +#[cfg(feature = "tests")] +pub mod tests; + +#[cfg(feature = "alloc")] +mod wnaf; +#[cfg(feature = "alloc")] +pub use self::wnaf::{Wnaf, WnafBase, WnafGroup, WnafScalar}; + +/// A helper trait for types with a group operation. +pub trait GroupOps: + Add + Sub + AddAssign + SubAssign +{ +} + +impl GroupOps for T where + T: Add + Sub + AddAssign + SubAssign +{ +} + +/// A helper trait for references with a group operation. +pub trait GroupOpsOwned: for<'r> GroupOps<&'r Rhs, Output> {} +impl GroupOpsOwned for T where T: for<'r> GroupOps<&'r Rhs, Output> {} + +/// A helper trait for types implementing group scalar multiplication. +pub trait ScalarMul: Mul + MulAssign {} + +impl ScalarMul for T where T: Mul + MulAssign +{} + +/// A helper trait for references implementing group scalar multiplication. +pub trait ScalarMulOwned: for<'r> ScalarMul<&'r Rhs, Output> {} +impl ScalarMulOwned for T where T: for<'r> ScalarMul<&'r Rhs, Output> {} + +/// This trait represents an element of a cryptographic group. +pub trait Group: + Clone + + Copy + + fmt::Debug + + Eq + + Sized + + Send + + Sync + + 'static + + Sum + + for<'a> Sum<&'a Self> + + Neg + + GroupOps + + GroupOpsOwned + + ScalarMul<::Scalar> + + ScalarMulOwned<::Scalar> +{ + /// Scalars modulo the order of this group's scalar field. + type Scalar: PrimeField; + + /// Returns an element chosen uniformly at random from the non-identity elements of + /// this group. + /// + /// This function is non-deterministic, and samples from the user-provided RNG. + fn random(rng: impl RngCore) -> Self; + + /// Returns the additive identity, also known as the "neutral element". + fn identity() -> Self; + + /// Returns a fixed generator of the prime-order subgroup. + fn generator() -> Self; + + /// Determines if this point is the identity. + fn is_identity(&self) -> Choice; + + /// Doubles this element. + #[must_use] + fn double(&self) -> Self; +} + +/// Efficient representation of an elliptic curve point guaranteed. +pub trait Curve: + Group + GroupOps<::AffineRepr> + GroupOpsOwned<::AffineRepr> +{ + /// The affine representation for this elliptic curve. + type AffineRepr; + + /// Converts a batch of projective elements into affine elements. This function will + /// panic if `p.len() != q.len()`. + fn batch_normalize(p: &[Self], q: &mut [Self::AffineRepr]) { + assert_eq!(p.len(), q.len()); + + for (p, q) in p.iter().zip(q.iter_mut()) { + *q = p.to_affine(); + } + } + + /// Converts this element into its affine representation. + fn to_affine(&self) -> Self::AffineRepr; +} + +pub trait GroupEncoding: Sized { + /// The encoding of group elements. + /// + /// The `Default` implementation is not required to return a valid point encoding. The + /// bound is present to enable encodings to be constructed generically: + /// ``` + /// # use group::GroupEncoding; + /// # use subtle::CtOption; + /// # struct G; + /// # impl GroupEncoding for G { + /// # type Repr = [u8; 0]; + /// # fn from_bytes(bytes: &Self::Repr) -> CtOption { unimplemented!() } + /// # fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { unimplemented!() } + /// # fn to_bytes(&self) -> Self::Repr { unimplemented!() } + /// # } + /// # let buf = &[0u8; 0][..]; + /// let mut encoding = ::Repr::default(); + /// encoding.as_mut().copy_from_slice(buf); + /// ``` + /// + /// It is recommended that the default should be the all-zeroes encoding. + type Repr: Copy + Default + Send + Sync + 'static + AsRef<[u8]> + AsMut<[u8]>; + + /// Attempts to deserialize a group element from its encoding. + fn from_bytes(bytes: &Self::Repr) -> CtOption; + + /// Attempts to deserialize a group element, not checking if the element is valid. + /// + /// **This is dangerous to call unless you trust the bytes you are reading; otherwise, + /// API invariants may be broken.** Please consider using + /// [`GroupEncoding::from_bytes`] instead. + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption; + + /// Converts this element into its byte encoding. This may or may not support + /// encoding the identity. + // TODO: Figure out how to handle identity encoding generically. + fn to_bytes(&self) -> Self::Repr; +} + +/// Affine representation of a point on an elliptic curve that has a defined uncompressed +/// encoding. +pub trait UncompressedEncoding: Sized { + type Uncompressed: Default + AsRef<[u8]> + AsMut<[u8]>; + + /// Attempts to deserialize an element from its uncompressed encoding. + fn from_uncompressed(bytes: &Self::Uncompressed) -> CtOption; + + /// Attempts to deserialize an uncompressed element, not checking if the element is in + /// the correct subgroup. + /// + /// **This is dangerous to call unless you trust the bytes you are reading; otherwise, + /// API invariants may be broken.** Please consider using + /// [`UncompressedEncoding::from_uncompressed`] instead. + fn from_uncompressed_unchecked(bytes: &Self::Uncompressed) -> CtOption; + + /// Converts this element into its uncompressed encoding, so long as it's not + /// the point at infinity. + fn to_uncompressed(&self) -> Self::Uncompressed; +} diff --git a/src/rust/vendor/group/src/prime.rs b/src/rust/vendor/group/src/prime.rs new file mode 100644 index 000000000..174888eb5 --- /dev/null +++ b/src/rust/vendor/group/src/prime.rs @@ -0,0 +1,50 @@ +use core::fmt; +use core::ops::{Mul, Neg}; +use ff::PrimeField; +use subtle::Choice; + +use crate::{Curve, Group, GroupEncoding}; + +/// This trait represents an element of a prime-order cryptographic group. +pub trait PrimeGroup: Group + GroupEncoding {} + +/// Efficient representation of an elliptic curve point guaranteed to be +/// in the correct prime order subgroup. +pub trait PrimeCurve: Curve::Affine> + PrimeGroup { + type Affine: PrimeCurveAffine + + Mul + + for<'r> Mul<&'r Self::Scalar, Output = Self>; +} + +/// Affine representation of an elliptic curve point guaranteed to be +/// in the correct prime order subgroup. +pub trait PrimeCurveAffine: GroupEncoding + + Copy + + Clone + + Sized + + Send + + Sync + + fmt::Debug + + PartialEq + + Eq + + 'static + + Neg + + Mul<::Scalar, Output = ::Curve> + + for<'r> Mul<&'r ::Scalar, Output = ::Curve> +{ + type Scalar: PrimeField; + type Curve: PrimeCurve; + + /// Returns the additive identity. + fn identity() -> Self; + + /// Returns a fixed generator of unknown exponent. + fn generator() -> Self; + + /// Determines if this point represents the point at infinity; the + /// additive identity. + fn is_identity(&self) -> Choice; + + /// Converts this element to its curve representation. + fn to_curve(&self) -> Self::Curve; +} diff --git a/src/rust/vendor/group/src/tests/mod.rs b/src/rust/vendor/group/src/tests/mod.rs new file mode 100644 index 000000000..ff79a9b8c --- /dev/null +++ b/src/rust/vendor/group/src/tests/mod.rs @@ -0,0 +1,448 @@ +use alloc::vec::Vec; +use core::ops::{Mul, Neg}; +use ff::{Field, PrimeField}; +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; + +use crate::{ + prime::{PrimeCurve, PrimeCurveAffine}, + wnaf::WnafGroup, + GroupEncoding, UncompressedEncoding, +}; + +pub fn curve_tests() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + // Negation edge case with identity. + { + let z = G::identity().neg(); + assert!(bool::from(z.is_identity())); + } + + // Doubling edge case with identity. + { + let z = G::identity().double(); + assert!(bool::from(z.is_identity())); + } + + // Addition edge cases with identity + { + let mut r = G::random(&mut rng); + let rcopy = r; + r.add_assign(&G::identity()); + assert_eq!(r, rcopy); + r.add_assign(&G::Affine::identity()); + assert_eq!(r, rcopy); + + let mut z = G::identity(); + z.add_assign(&G::identity()); + assert!(bool::from(z.is_identity())); + z.add_assign(&G::Affine::identity()); + assert!(bool::from(z.is_identity())); + + let mut z2 = z; + z2.add_assign(&r); + + z.add_assign(&r.to_affine()); + + assert_eq!(z, z2); + assert_eq!(z, r); + } + + // Transformations + { + let a = G::random(&mut rng); + let b = a.to_affine().to_curve(); + let c = a.to_affine().to_curve().to_affine().to_curve(); + assert_eq!(a, b); + assert_eq!(b, c); + } + + random_addition_tests::(); + random_multiplication_tests::(); + random_doubling_tests::(); + random_negation_tests::(); + random_transformation_tests::(); + random_compressed_encoding_tests::(); +} + +pub fn random_wnaf_tests() { + use crate::wnaf::*; + + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + { + let mut table = vec![]; + let mut wnaf = vec![]; + + for w in 2..14 { + for _ in 0..100 { + let g = G::random(&mut rng); + let s = G::Scalar::random(&mut rng); + let mut g1 = g; + g1.mul_assign(s); + + wnaf_table(&mut table, g, w); + wnaf_form(&mut wnaf, s.to_repr(), w); + let g2 = wnaf_exp(&table, &wnaf); + + assert_eq!(g1, g2); + } + } + } + + { + fn only_compiles_if_send(_: &S) {} + + for _ in 0..100 { + let g = G::random(&mut rng); + let s = G::Scalar::random(&mut rng); + let mut g1 = g; + g1.mul_assign(s); + + let g2 = { + let mut wnaf = Wnaf::new(); + wnaf.base(g, 1).scalar(&s) + }; + let g3 = { + let mut wnaf = Wnaf::new(); + wnaf.scalar(&s).base(g) + }; + let g4 = { + let mut wnaf = Wnaf::new(); + let mut shared = wnaf.base(g, 1).shared(); + + only_compiles_if_send(&shared); + + shared.scalar(&s) + }; + let g5 = { + let mut wnaf = Wnaf::new(); + let mut shared = wnaf.scalar(&s).shared(); + + only_compiles_if_send(&shared); + + shared.base(g) + }; + + let g6 = { + let mut wnaf = Wnaf::new(); + { + // Populate the vectors. + wnaf.base(G::random(&mut rng), 1) + .scalar(&G::Scalar::random(&mut rng)); + } + wnaf.base(g, 1).scalar(&s) + }; + let g7 = { + let mut wnaf = Wnaf::new(); + { + // Populate the vectors. + wnaf.base(G::random(&mut rng), 1) + .scalar(&G::Scalar::random(&mut rng)); + } + wnaf.scalar(&s).base(g) + }; + let g8 = { + let mut wnaf = Wnaf::new(); + { + // Populate the vectors. + wnaf.base(G::random(&mut rng), 1) + .scalar(&G::Scalar::random(&mut rng)); + } + let mut shared = wnaf.base(g, 1).shared(); + + only_compiles_if_send(&shared); + + shared.scalar(&s) + }; + let g9 = { + let mut wnaf = Wnaf::new(); + { + // Populate the vectors. + wnaf.base(G::random(&mut rng), 1) + .scalar(&G::Scalar::random(&mut rng)); + } + let mut shared = wnaf.scalar(&s).shared(); + + only_compiles_if_send(&shared); + + shared.base(g) + }; + + assert_eq!(g1, g2); + assert_eq!(g1, g3); + assert_eq!(g1, g4); + assert_eq!(g1, g5); + assert_eq!(g1, g6); + assert_eq!(g1, g7); + assert_eq!(g1, g8); + assert_eq!(g1, g9); + } + } +} + +fn random_negation_tests() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let r = G::random(&mut rng); + + let s = G::Scalar::random(&mut rng); + let sneg = s.neg(); + + let mut t1 = r; + t1.mul_assign(s); + + let mut t2 = r; + t2.mul_assign(sneg); + + let mut t3 = t1; + t3.add_assign(&t2); + assert!(bool::from(t3.is_identity())); + + let mut t4 = t1; + t4.add_assign(&t2.to_affine()); + assert!(bool::from(t4.is_identity())); + + assert_eq!(t1.neg(), t2); + } +} + +fn random_doubling_tests() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let mut a = G::random(&mut rng); + let mut b = G::random(&mut rng); + + // 2(a + b) + let tmp1 = (a + b).double(); + + // 2a + 2b + a = a.double(); + b = b.double(); + + let mut tmp2 = a; + tmp2.add_assign(&b); + + let mut tmp3 = a; + tmp3.add_assign(&b.to_affine()); + + assert_eq!(tmp1, tmp2); + assert_eq!(tmp1, tmp3); + } +} + +fn random_multiplication_tests() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let mut a = G::random(&mut rng); + let mut b = G::random(&mut rng); + let a_affine = a.to_affine(); + let b_affine = b.to_affine(); + + let s = G::Scalar::random(&mut rng); + + // s ( a + b ) + let mut tmp1 = a; + tmp1.add_assign(&b); + tmp1.mul_assign(s); + + // sa + sb + a.mul_assign(s); + b.mul_assign(s); + + let mut tmp2 = a; + tmp2.add_assign(&b); + + // Affine multiplication + let mut tmp3 = Mul::::mul(a_affine, s); + tmp3.add_assign(Mul::::mul(b_affine, s)); + + assert_eq!(tmp1, tmp2); + assert_eq!(tmp1, tmp3); + } +} + +fn random_addition_tests() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let a = G::random(&mut rng); + let b = G::random(&mut rng); + let c = G::random(&mut rng); + let a_affine = a.to_affine(); + let b_affine = b.to_affine(); + let c_affine = c.to_affine(); + + // a + a should equal the doubling + { + let mut aplusa = a; + aplusa.add_assign(&a); + + let mut aplusamixed = a; + aplusamixed.add_assign(&a.to_affine()); + + let adouble = a.double(); + + assert_eq!(aplusa, adouble); + assert_eq!(aplusa, aplusamixed); + } + + let mut tmp = vec![G::identity(); 6]; + + // (a + b) + c + tmp[0] = a; + tmp[0].add_assign(&b); + tmp[0].add_assign(&c); + + // a + (b + c) + tmp[1] = b; + tmp[1].add_assign(&c); + tmp[1].add_assign(&a); + + // (a + c) + b + tmp[2] = a; + tmp[2].add_assign(&c); + tmp[2].add_assign(&b); + + // Mixed addition + + // (a + b) + c + tmp[3] = a_affine.to_curve(); + tmp[3].add_assign(&b_affine); + tmp[3].add_assign(&c_affine); + + // a + (b + c) + tmp[4] = b_affine.to_curve(); + tmp[4].add_assign(&c_affine); + tmp[4].add_assign(&a_affine); + + // (a + c) + b + tmp[5] = a_affine.to_curve(); + tmp[5].add_assign(&c_affine); + tmp[5].add_assign(&b_affine); + + // Comparisons + for i in 0..6 { + for j in 0..6 { + assert_eq!(tmp[i], tmp[j]); + assert_eq!(tmp[i].to_affine(), tmp[j].to_affine()); + } + + assert!(tmp[i] != a); + assert!(tmp[i] != b); + assert!(tmp[i] != c); + + assert!(a != tmp[i]); + assert!(b != tmp[i]); + assert!(c != tmp[i]); + } + } +} + +fn random_transformation_tests() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let g = G::random(&mut rng); + let g_affine = g.to_affine(); + let g_projective = g_affine.to_curve(); + assert_eq!(g, g_projective); + } + + // Batch normalization + for _ in 0..10 { + let mut v = (0..1000).map(|_| G::random(&mut rng)).collect::>(); + + use rand::distributions::{Distribution, Uniform}; + let between = Uniform::new(0, 1000); + // Sprinkle in some normalized points + for _ in 0..5 { + v[between.sample(&mut rng)] = G::identity(); + } + for _ in 0..5 { + let s = between.sample(&mut rng); + v[s] = v[s].to_affine().to_curve(); + } + + let expected_v = v.iter().map(|v| v.to_affine()).collect::>(); + + let mut normalized = vec![G::Affine::identity(); v.len()]; + G::batch_normalize(&v, &mut normalized); + + assert_eq!(normalized, expected_v); + } +} + +fn random_compressed_encoding_tests() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + assert_eq!( + G::Affine::from_bytes(&G::Affine::identity().to_bytes()).unwrap(), + G::Affine::identity() + ); + + for _ in 0..1000 { + let mut r = G::random(&mut rng).to_affine(); + + let compressed = r.to_bytes(); + let de_compressed = G::Affine::from_bytes(&compressed).unwrap(); + assert_eq!(de_compressed, r); + + r = r.neg(); + + let compressed = r.to_bytes(); + let de_compressed = G::Affine::from_bytes(&compressed).unwrap(); + assert_eq!(de_compressed, r); + } +} + +pub fn random_uncompressed_encoding_tests() +where + ::Affine: UncompressedEncoding, +{ + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + assert_eq!( + G::Affine::from_uncompressed(&G::Affine::identity().to_uncompressed()).unwrap(), + G::Affine::identity() + ); + + for _ in 0..1000 { + let r = G::random(&mut rng).to_affine(); + + let uncompressed = r.to_uncompressed(); + let de_uncompressed = G::Affine::from_uncompressed(&uncompressed).unwrap(); + assert_eq!(de_uncompressed, r); + } +} diff --git a/src/rust/vendor/group/src/wnaf.rs b/src/rust/vendor/group/src/wnaf.rs new file mode 100644 index 000000000..175d67663 --- /dev/null +++ b/src/rust/vendor/group/src/wnaf.rs @@ -0,0 +1,506 @@ +use alloc::vec::Vec; +use core::iter; +use core::marker::PhantomData; +use core::ops::Mul; + +use ff::PrimeField; + +use super::Group; + +/// Extension trait on a [`Group`] that provides helpers used by [`Wnaf`]. +pub trait WnafGroup: Group { + /// Recommends a wNAF window size given the number of scalars you intend to multiply + /// a base by. Always returns a number between 2 and 22, inclusive. + fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize; +} + +/// Replaces the contents of `table` with a w-NAF window table for the given window size. +pub(crate) fn wnaf_table(table: &mut Vec, mut base: G, window: usize) { + table.truncate(0); + table.reserve(1 << (window - 1)); + + let dbl = base.double(); + + for _ in 0..(1 << (window - 1)) { + table.push(base); + base.add_assign(&dbl); + } +} + +/// This struct represents a view of a sequence of bytes as a sequence of +/// `u64` limbs in little-endian byte order. It maintains a current index, and +/// allows access to the limb at that index and the one following it. Bytes +/// beyond the end of the original buffer are treated as zero. +struct LimbBuffer<'a> { + buf: &'a [u8], + cur_idx: usize, + cur_limb: u64, + next_limb: u64, +} + +impl<'a> LimbBuffer<'a> { + fn new(buf: &'a [u8]) -> Self { + let mut ret = Self { + buf, + cur_idx: 0, + cur_limb: 0, + next_limb: 0, + }; + + // Initialise the limb buffers. + ret.increment_limb(); + ret.increment_limb(); + ret.cur_idx = 0usize; + + ret + } + + fn increment_limb(&mut self) { + self.cur_idx += 1; + self.cur_limb = self.next_limb; + match self.buf.len() { + // There are no more bytes in the buffer; zero-extend. + 0 => self.next_limb = 0, + + // There are fewer bytes in the buffer than a u64 limb; zero-extend. + x @ 1..=7 => { + let mut next_limb = [0; 8]; + next_limb[..x].copy_from_slice(self.buf); + self.next_limb = u64::from_le_bytes(next_limb); + self.buf = &[]; + } + + // There are at least eight bytes in the buffer; read the next u64 limb. + _ => { + let (next_limb, rest) = self.buf.split_at(8); + self.next_limb = u64::from_le_bytes(next_limb.try_into().unwrap()); + self.buf = rest; + } + } + } + + fn get(&mut self, idx: usize) -> (u64, u64) { + assert!([self.cur_idx, self.cur_idx + 1].contains(&idx)); + if idx > self.cur_idx { + self.increment_limb(); + } + (self.cur_limb, self.next_limb) + } +} + +/// Replaces the contents of `wnaf` with the w-NAF representation of a little-endian +/// scalar. +pub(crate) fn wnaf_form>(wnaf: &mut Vec, c: S, window: usize) { + // Required by the NAF definition + debug_assert!(window >= 2); + // Required so that the NAF digits fit in i64 + debug_assert!(window <= 64); + + let bit_len = c.as_ref().len() * 8; + + wnaf.truncate(0); + wnaf.reserve(bit_len); + + // Initialise the current and next limb buffers. + let mut limbs = LimbBuffer::new(c.as_ref()); + + let width = 1u64 << window; + let window_mask = width - 1; + + let mut pos = 0; + let mut carry = 0; + while pos < bit_len { + // Construct a buffer of bits of the scalar, starting at bit `pos` + let u64_idx = pos / 64; + let bit_idx = pos % 64; + let (cur_u64, next_u64) = limbs.get(u64_idx); + let bit_buf = if bit_idx + window < 64 { + // This window's bits are contained in a single u64 + cur_u64 >> bit_idx + } else { + // Combine the current u64's bits with the bits from the next u64 + (cur_u64 >> bit_idx) | (next_u64 << (64 - bit_idx)) + }; + + // Add the carry into the current window + let window_val = carry + (bit_buf & window_mask); + + if window_val & 1 == 0 { + // If the window value is even, preserve the carry and emit 0. + // Why is the carry preserved? + // If carry == 0 and window_val & 1 == 0, then the next carry should be 0 + // If carry == 1 and window_val & 1 == 0, then bit_buf & 1 == 1 so the next carry should be 1 + wnaf.push(0); + pos += 1; + } else { + wnaf.push(if window_val < width / 2 { + carry = 0; + window_val as i64 + } else { + carry = 1; + (window_val as i64).wrapping_sub(width as i64) + }); + wnaf.extend(iter::repeat(0).take(window - 1)); + pos += window; + } + } +} + +/// Performs w-NAF exponentiation with the provided window table and w-NAF form scalar. +/// +/// This function must be provided a `table` and `wnaf` that were constructed with +/// the same window size; otherwise, it may panic or produce invalid results. +pub(crate) fn wnaf_exp(table: &[G], wnaf: &[i64]) -> G { + let mut result = G::identity(); + + let mut found_one = false; + + for n in wnaf.iter().rev() { + if found_one { + result = result.double(); + } + + if *n != 0 { + found_one = true; + + if *n > 0 { + result += &table[(n / 2) as usize]; + } else { + result -= &table[((-n) / 2) as usize]; + } + } + } + + result +} + +/// A "w-ary non-adjacent form" scalar multiplication (also known as exponentiation) +/// context. +/// +/// # Examples +/// +/// This struct can be used to implement several patterns: +/// +/// ## One base, one scalar +/// +/// For this pattern, you can use a transient `Wnaf` context: +/// +/// ```ignore +/// use group::Wnaf; +/// +/// let result = Wnaf::new().scalar(&scalar).base(base); +/// ``` +/// +/// ## Many bases, one scalar +/// +/// For this pattern, you create a `Wnaf` context, load the scalar into it, and then +/// process each base in turn: +/// +/// ```ignore +/// use group::Wnaf; +/// +/// let mut wnaf = Wnaf::new(); +/// let mut wnaf_scalar = wnaf.scalar(&scalar); +/// let results: Vec<_> = bases +/// .into_iter() +/// .map(|base| wnaf_scalar.base(base)) +/// .collect(); +/// ``` +/// +/// ## One base, many scalars +/// +/// For this pattern, you create a `Wnaf` context, load the base into it, and then process +/// each scalar in turn: +/// +/// ```ignore +/// use group::Wnaf; +/// +/// let mut wnaf = Wnaf::new(); +/// let mut wnaf_base = wnaf.base(base, scalars.len()); +/// let results: Vec<_> = scalars +/// .iter() +/// .map(|scalar| wnaf_base.scalar(scalar)) +/// .collect(); +/// ``` +/// +/// ## Many bases, many scalars +/// +/// Say you have `n` bases and `m` scalars, and want to produce `n * m` results. For this +/// pattern, you need to cache the w-NAF tables for the bases and then compute the w-NAF +/// form of the scalars on the fly for every base, or vice versa: +/// +/// ```ignore +/// use group::Wnaf; +/// +/// let mut wnaf_contexts: Vec<_> = (0..bases.len()).map(|_| Wnaf::new()).collect(); +/// let mut wnaf_bases: Vec<_> = wnaf_contexts +/// .iter_mut() +/// .zip(bases) +/// .map(|(wnaf, base)| wnaf.base(base, scalars.len())) +/// .collect(); +/// let results: Vec<_> = wnaf_bases +/// .iter() +/// .flat_map(|wnaf_base| scalars.iter().map(|scalar| wnaf_base.scalar(scalar))) +/// .collect(); +/// ``` +/// +/// Alternatively, use the [`WnafBase`] and [`WnafScalar`] types, which enable the various +/// tables and w-NAF forms to be cached individually per base and scalar. These types can +/// then be directly multiplied without any additional runtime work, at the cost of fixing +/// a specific window size (rather than choosing the window size dynamically). +#[derive(Debug)] +pub struct Wnaf { + base: B, + scalar: S, + window_size: W, +} + +impl Wnaf<(), Vec, Vec> { + /// Construct a new wNAF context without allocating. + pub fn new() -> Self { + Wnaf { + base: vec![], + scalar: vec![], + window_size: (), + } + } +} + +#[cfg(feature = "wnaf-memuse")] +impl memuse::DynamicUsage for Wnaf<(), Vec, Vec> { + fn dynamic_usage(&self) -> usize { + self.base.dynamic_usage() + self.scalar.dynamic_usage() + } + + fn dynamic_usage_bounds(&self) -> (usize, Option) { + let (base_lower, base_upper) = self.base.dynamic_usage_bounds(); + let (scalar_lower, scalar_upper) = self.scalar.dynamic_usage_bounds(); + + ( + base_lower + scalar_lower, + base_upper.zip(scalar_upper).map(|(a, b)| a + b), + ) + } +} + +impl Wnaf<(), Vec, Vec> { + /// Given a base and a number of scalars, compute a window table and return a `Wnaf` object that + /// can perform exponentiations with `.scalar(..)`. + pub fn base(&mut self, base: G, num_scalars: usize) -> Wnaf> { + // Compute the appropriate window size based on the number of scalars. + let window_size = G::recommended_wnaf_for_num_scalars(num_scalars); + + // Compute a wNAF table for the provided base and window size. + wnaf_table(&mut self.base, base, window_size); + + // Return a Wnaf object that immutably borrows the computed base storage location, + // but mutably borrows the scalar storage location. + Wnaf { + base: &self.base[..], + scalar: &mut self.scalar, + window_size, + } + } + + /// Given a scalar, compute its wNAF representation and return a `Wnaf` object that can perform + /// exponentiations with `.base(..)`. + pub fn scalar(&mut self, scalar: &::Scalar) -> Wnaf, &[i64]> { + // We hard-code a window size of 4. + let window_size = 4; + + // Compute the wNAF form of the scalar. + wnaf_form(&mut self.scalar, scalar.to_repr(), window_size); + + // Return a Wnaf object that mutably borrows the base storage location, but + // immutably borrows the computed wNAF form scalar location. + Wnaf { + base: &mut self.base, + scalar: &self.scalar[..], + window_size, + } + } +} + +impl<'a, G: Group> Wnaf> { + /// Constructs new space for the scalar representation while borrowing + /// the computed window table, for sending the window table across threads. + pub fn shared(&self) -> Wnaf> { + Wnaf { + base: self.base, + scalar: vec![], + window_size: self.window_size, + } + } +} + +#[cfg(feature = "wnaf-memuse")] +impl<'a, G: Group> memuse::DynamicUsage for Wnaf> { + fn dynamic_usage(&self) -> usize { + // The heap memory for the window table is counted in the parent `Wnaf`. + self.scalar.dynamic_usage() + } + + fn dynamic_usage_bounds(&self) -> (usize, Option) { + self.scalar.dynamic_usage_bounds() + } +} + +impl<'a, G: Group> Wnaf, &'a [i64]> { + /// Constructs new space for the window table while borrowing + /// the computed scalar representation, for sending the scalar representation + /// across threads. + pub fn shared(&self) -> Wnaf, &'a [i64]> { + Wnaf { + base: vec![], + scalar: self.scalar, + window_size: self.window_size, + } + } +} + +#[cfg(feature = "wnaf-memuse")] +impl<'a, G: Group + memuse::DynamicUsage> memuse::DynamicUsage for Wnaf, &'a [i64]> { + fn dynamic_usage(&self) -> usize { + // The heap memory for the scalar representation is counted in the parent `Wnaf`. + self.base.dynamic_usage() + } + + fn dynamic_usage_bounds(&self) -> (usize, Option) { + self.base.dynamic_usage_bounds() + } +} + +impl> Wnaf { + /// Performs exponentiation given a base. + pub fn base(&mut self, base: G) -> G + where + B: AsMut>, + { + wnaf_table(self.base.as_mut(), base, self.window_size); + wnaf_exp(self.base.as_mut(), self.scalar.as_ref()) + } +} + +impl>> Wnaf { + /// Performs exponentiation given a scalar. + pub fn scalar(&mut self, scalar: &::Scalar) -> G + where + B: AsRef<[G]>, + { + wnaf_form(self.scalar.as_mut(), scalar.to_repr(), self.window_size); + wnaf_exp(self.base.as_ref(), self.scalar.as_mut()) + } +} + +/// A "w-ary non-adjacent form" scalar, that uses precomputation to improve the speed of +/// scalar multiplication. +/// +/// # Examples +/// +/// See [`WnafBase`] for usage examples. +#[derive(Clone, Debug)] +pub struct WnafScalar { + wnaf: Vec, + field: PhantomData, +} + +#[cfg(feature = "wnaf-memuse")] +impl memuse::DynamicUsage for WnafScalar { + fn dynamic_usage(&self) -> usize { + self.wnaf.dynamic_usage() + } + + fn dynamic_usage_bounds(&self) -> (usize, Option) { + self.wnaf.dynamic_usage_bounds() + } +} + +impl WnafScalar { + /// Computes the w-NAF representation of the given scalar with the specified + /// `WINDOW_SIZE`. + pub fn new(scalar: &F) -> Self { + let mut wnaf = vec![]; + + // Compute the w-NAF form of the scalar. + wnaf_form(&mut wnaf, scalar.to_repr(), WINDOW_SIZE); + + WnafScalar { + wnaf, + field: PhantomData::default(), + } + } +} + +/// A fixed window table for a group element, precomputed to improve the speed of scalar +/// multiplication. +/// +/// This struct is designed for usage patterns that have long-term cached bases and/or +/// scalars, or [Cartesian products] of bases and scalars. The [`Wnaf`] API enables one or +/// the other to be cached, but requires either the base window tables or the scalar w-NAF +/// forms to be computed repeatedly on the fly, which can become a significant performance +/// issue for some use cases. +/// +/// `WnafBase` and [`WnafScalar`] enable an alternative trade-off: by fixing the window +/// size at compile time, the precomputations are guaranteed to only occur once per base +/// and once per scalar. Users should select their window size based on how long the bases +/// are expected to live; a larger window size will consume more memory and take longer to +/// precompute, but result in faster scalar multiplications. +/// +/// [Cartesian products]: https://en.wikipedia.org/wiki/Cartesian_product +/// +/// # Examples +/// +/// ```ignore +/// use group::{WnafBase, WnafScalar}; +/// +/// let wnaf_bases: Vec<_> = bases.into_iter().map(WnafBase::<_, 4>::new).collect(); +/// let wnaf_scalars: Vec<_> = scalars.iter().map(WnafScalar::new).collect(); +/// let results: Vec<_> = wnaf_bases +/// .iter() +/// .flat_map(|base| wnaf_scalars.iter().map(|scalar| base * scalar)) +/// .collect(); +/// ``` +/// +/// Note that this pattern requires specifying a fixed window size (unlike previous +/// patterns that picked a suitable window size internally). This is necessary to ensure +/// in the type system that the base and scalar `Wnaf`s were computed with the same window +/// size, allowing the result to be computed infallibly. +#[derive(Clone, Debug)] +pub struct WnafBase { + table: Vec, +} + +#[cfg(feature = "wnaf-memuse")] +impl memuse::DynamicUsage + for WnafBase +{ + fn dynamic_usage(&self) -> usize { + self.table.dynamic_usage() + } + + fn dynamic_usage_bounds(&self) -> (usize, Option) { + self.table.dynamic_usage_bounds() + } +} + +impl WnafBase { + /// Computes a window table for the given base with the specified `WINDOW_SIZE`. + pub fn new(base: G) -> Self { + let mut table = vec![]; + + // Compute a window table for the provided base and window size. + wnaf_table(&mut table, base, WINDOW_SIZE); + + WnafBase { table } + } +} + +impl Mul<&WnafScalar> + for &WnafBase +{ + type Output = G; + + fn mul(self, rhs: &WnafScalar) -> Self::Output { + wnaf_exp(&self.table, &rhs.wnaf) + } +} diff --git a/src/rust/vendor/p256/.cargo-checksum.json b/src/rust/vendor/p256/.cargo-checksum.json new file mode 100644 index 000000000..b16282488 --- /dev/null +++ b/src/rust/vendor/p256/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"3272f88b47cecbeb331fec729b83de2390cf4dd38115419fa5058b679dc6b38e","Cargo.toml":"7f2c98e9af91a495cf341425f77b782d6c253dba9cf4f63a16d63489ecb9ddfc","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"233b95ccbf90dc67e32f3e8995c489f6312d9191ebd141a931c3b684f1e3be6d","README.md":"853918bdd020ad083277d1334b4a750b2f5171d814c86d4620e5cdbc46313828","benches/field.rs":"ca079736657a3219905fd318eaa92b73d049d2a9f9dccc04731868715f8bf5e2","benches/scalar.rs":"6c42feb64301d2be881e84b5c3dfc0cb7016ac6f457e0819ca9df7ed536251e4","src/arithmetic.rs":"90fc20a835f72da3e7c8c9a7120aefb5468bc31a2d5f097d8f57b2f11f3daf42","src/arithmetic/field.rs":"b7ac34f7f82072e45b86d33bb0c82d87058d65e50b1a4e2037753d1d414dfcac","src/arithmetic/field/field32.rs":"eea276076f53bb6a79d634838c6d1587c72d8f43cd7ad21d58ce9bc249d3b477","src/arithmetic/field/field64.rs":"611bc1c282a22913784ca1fd6364c0aae67b04f800fc6bd00a3268b6d50f5e60","src/arithmetic/hash2curve.rs":"02ca3a1d182c1da967656412886f44a9038b91e510308b4832cabd89ea1af850","src/arithmetic/scalar.rs":"50a38c74863ee5e808faf49354eb5c0f9e86a79cb77c68e5cad43e583c11871a","src/arithmetic/scalar/scalar32.rs":"41d30273f6a701abcdfac710cc4ea17f356575d8c58cdec0ffb70cf924de199e","src/arithmetic/scalar/scalar64.rs":"37c2989a1545fca234149374024ce5d5a5a5b0a7fe4de1ab3e9fbb1d61ffd2fb","src/arithmetic/util.rs":"86fcf1662ed0e73a064fc5aefaa886222ae598939856f4a63f2455e4189a33d1","src/ecdh.rs":"787171546abfd6cc92585b0251338a9a3dd9dc914a984fb60d6ff614ef55ecf2","src/ecdsa.rs":"ca2c1ce78f3368a94f71e15d3f355fe05834cd5de8297429d812bb79293c6b9e","src/lib.rs":"df474e465541a9ec708958ff44ea587d9b8d7832a9727454f15abb2ac58b8857","src/test_vectors.rs":"21b05ff78e574ee8d5823ec0f97a7a618e34dd91d0f29a6cbdbf818cc7b68dbc","src/test_vectors/data/wycheproof.blb":"2086114032e72c195e2c49c61f2377c27b141aac455dff8bac3128eaff048253","src/test_vectors/ecdsa.rs":"607d74f05e1ed43d2aa387af6e6b665ec9b66a82e291630b18642ca1032af684","src/test_vectors/field.rs":"62061f33cc39a4b1e16c233411ba54b03a9daa4bb5e76e5c7eff26510626a492","src/test_vectors/group.rs":"d08c69a1e01933d0bfcdccdf08713b35258b7141767a7bf0485fae64ac5bd95f","tests/affine.rs":"fd4c233b9e37c03c6ca942d9020a7a1d71a00daa0fc797701a28e836749f467f","tests/ecdsa.rs":"5da4d26f15ab98a1da5bb02c6858ba5dcb450e7e2ea00d9b368a8ebebf8980d5","tests/examples/pkcs8-private-key.der":"8125ab208d2181ed3ef05ff0ab1906e5898c36a858277e5b987e78e505288769","tests/examples/pkcs8-private-key.pem":"f4171f5ea72bf95ee444ceb868872f5c5d2bbc5fca038ae801b06fb9ac6b9429","tests/examples/pkcs8-public-key.der":"b9968d56ed8d6aa3fb43b15fa01e355d7a3a0203b1408b3fd2733637c4d1642c","tests/examples/pkcs8-public-key.pem":"d1ff198dc495da63f5f909db0254d6e49cff519487fcb26d055a762fc3ca47a1","tests/pkcs8.rs":"271bf78755ef8e8437788a6c970a8a1f04acf78a57e8d00a86c415c86db2fc4f","tests/projective.rs":"53f39d506645e15c254b089b2364aeb76895baa0d6a8f6118a556d2271a95fad","tests/scalar.rs":"8699445399dc568ee7937608bbd2164eef388b398ad8f20cb6d87eef9ae66b89"},"package":"c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b"} \ No newline at end of file diff --git a/src/rust/vendor/p256/CHANGELOG.md b/src/rust/vendor/p256/CHANGELOG.md new file mode 100644 index 000000000..a8f817282 --- /dev/null +++ b/src/rust/vendor/p256/CHANGELOG.md @@ -0,0 +1,331 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.13.2 (2023-04-15) +### Changed +- Enable `pem` feature by default ([#832]) + +### Fixed +- Have `serde` feature enable `primeorder/serde` ([#851]) + +[#832]: https://github.com/RustCrypto/elliptic-curves/pull/832 +[#851]: https://github.com/RustCrypto/elliptic-curves/pull/851 + +## 0.13.1 (2023-04-10) +### Changed +- Bump `primeorder` to v0.13.1 ([#819]) + +### Fixed +- Correct product definition for empty iterators ([#802]) + +[#802]: https://github.com/RustCrypto/elliptic-curves/pull/802 +[#819]: https://github.com/RustCrypto/elliptic-curves/pull/819 + +## 0.13.0 (2023-03-03) +### Added +- `PrimeField` constants/tests ([#730], [#737], [#738]) +- `const fn` inversions for all field elements ([#736]) + +### Changed +- `FieldBytesEncoding` trait impls ([#732]) +- Update `hash2curve` implementations to new API ([#735]) +- Impl `Invert` trait for `Scalar` types ([#741]) +- Bump `ecdsa` dependency to v0.16 ([#770]) +- Bump `elliptic-curve` dependency to v0.13 ([#770]) +- Bump `primeorder` dependency to v0.13 ([#777]) + +### Fixed +- Point compactabtility check ([#772]) + +[#730]: https://github.com/RustCrypto/elliptic-curves/pull/730 +[#732]: https://github.com/RustCrypto/elliptic-curves/pull/732 +[#735]: https://github.com/RustCrypto/elliptic-curves/pull/735 +[#736]: https://github.com/RustCrypto/elliptic-curves/pull/736 +[#737]: https://github.com/RustCrypto/elliptic-curves/pull/737 +[#738]: https://github.com/RustCrypto/elliptic-curves/pull/738 +[#741]: https://github.com/RustCrypto/elliptic-curves/pull/741 +[#770]: https://github.com/RustCrypto/elliptic-curves/pull/770 +[#772]: https://github.com/RustCrypto/elliptic-curves/pull/772 +[#777]: https://github.com/RustCrypto/elliptic-curves/pull/777 + +## 0.12.0 (2023-01-16) +### Added +- 32-bit scalar backend ([#636]) +- `alloc` feature ([#670]) +- Constructors for `Scalar` from `u128` ([#709]) + +### Changed +- Use generic curve arithmetic implementation from `primeorder` crate ([#631], [#716]) +- Use `U256` as the inner type for `FieldElement` ([#634]) +- Update P-256 VOPRF test vectors ([#693]) +- Use weak feature activation; MSRV 1.60 ([#701]) +- Bump `ecdsa` dependency to v0.15 ([#713]) + +[#631]: https://github.com/RustCrypto/elliptic-curves/pull/631 +[#634]: https://github.com/RustCrypto/elliptic-curves/pull/634 +[#636]: https://github.com/RustCrypto/elliptic-curves/pull/636 +[#670]: https://github.com/RustCrypto/elliptic-curves/pull/670 +[#693]: https://github.com/RustCrypto/elliptic-curves/pull/693 +[#701]: https://github.com/RustCrypto/elliptic-curves/pull/701 +[#709]: https://github.com/RustCrypto/elliptic-curves/pull/709 +[#713]: https://github.com/RustCrypto/elliptic-curves/pull/713 +[#716]: https://github.com/RustCrypto/elliptic-curves/pull/716 + +## 0.11.1 (2022-06-12) +### Added +- Re-export low-level `diffie_hellman` function ([#556]) +- Additional RFC6979 test vectors ([#591]) + +### Changed +- Use a 4-bit window for scalar multiplication ([#563]) +- `invert()`, `sqrt()`: replace exponentiations with addition chains ([#564]) +- Use generic prime order formulas ([#602]) + +[#556]: https://github.com/RustCrypto/elliptic-curves/pull/556 +[#563]: https://github.com/RustCrypto/elliptic-curves/pull/563 +[#564]: https://github.com/RustCrypto/elliptic-curves/pull/564 +[#591]: https://github.com/RustCrypto/elliptic-curves/pull/591 +[#602]: https://github.com/RustCrypto/elliptic-curves/pull/602 + +## 0.11.0 (2022-05-09) +### Changed +- Bump `digest` to v0.10 ([#515]) +- Have `pkcs8` feature activate `ecdsa/pkcs8` ([#538]) +- Bump `elliptic-curve` to v0.12 ([#544]) +- Bump `ecdsa` to v0.14 ([#544]) + +[#515]: https://github.com/RustCrypto/elliptic-curves/pull/515 +[#538]: https://github.com/RustCrypto/elliptic-curves/pull/538 +[#544]: https://github.com/RustCrypto/elliptic-curves/pull/544 + +## 0.10.1 (2022-01-17) +### Added +- Impl `ff::Field` trait for `FieldElement` ([#498]) +- hash2curve support: impl `GroupDigest` trait for `NistP256` ([#503]) +- Impl `VoprfParameters` trait for `NistP256` ([#506]) +- Impl `ReduceNonZero` trait for `Scalar` ([#507]) +- `IDENTITY` and `GENERATOR` point constants ([#509], [#511]) + +[#498]: https://github.com/RustCrypto/elliptic-curves/pull/498 +[#503]: https://github.com/RustCrypto/elliptic-curves/pull/503 +[#506]: https://github.com/RustCrypto/elliptic-curves/pull/506 +[#507]: https://github.com/RustCrypto/elliptic-curves/pull/507 +[#509]: https://github.com/RustCrypto/elliptic-curves/pull/509 +[#511]: https://github.com/RustCrypto/elliptic-curves/pull/511 + +## 0.10.0 (2021-12-14) +### Added +- Implement point compaction support ([#357]) +- Implement `Scalar::sqrt` ([#392]) +- Impl `DefaultIsZeroes` for `ProjectivePoint` ([#414]) +- Impl `PrimeCurveArithmetic` ([#415]) +- Impl `Reduce` for `Scalar` ([#436]) +- `serde` feature ([#463], [#465]) +- Impl `LinearCombination` trait ([#476]) + +### Changed +- Use `PrimeCurve` trait ([#413]) +- Use `sec1` crate for `EncodedPoint` type ([#435]) +- Replace `ecdsa::hazmat::FromDigest` with `Reduce` ([#438]) +- Make `FromEncodedPoint` return a `CtOption` ([#445]) +- Rust 2021 edition upgrade; MSRV 1.56+ ([#453]) +- Leverage generic ECDSA implementation from `ecdsa` crate ([#462]) +- Bump `elliptic-curve` crate dependency to v0.11 ([#466]) +- Bump `ecdsa` crate dependency to v0.13 ([#467]) + +### Fixed +- `ProjectivePoint::to_bytes()` encoding for identity ([#443]) +- Handle identity point in `GroupEncoding` ([#446]) + +[#357]: https://github.com/RustCrypto/elliptic-curves/pull/357 +[#392]: https://github.com/RustCrypto/elliptic-curves/pull/392 +[#413]: https://github.com/RustCrypto/elliptic-curves/pull/413 +[#414]: https://github.com/RustCrypto/elliptic-curves/pull/414 +[#415]: https://github.com/RustCrypto/elliptic-curves/pull/415 +[#435]: https://github.com/RustCrypto/elliptic-curves/pull/435 +[#436]: https://github.com/RustCrypto/elliptic-curves/pull/436 +[#438]: https://github.com/RustCrypto/elliptic-curves/pull/438 +[#443]: https://github.com/RustCrypto/elliptic-curves/pull/443 +[#445]: https://github.com/RustCrypto/elliptic-curves/pull/445 +[#446]: https://github.com/RustCrypto/elliptic-curves/pull/446 +[#453]: https://github.com/RustCrypto/elliptic-curves/pull/453 +[#463]: https://github.com/RustCrypto/elliptic-curves/pull/463 +[#465]: https://github.com/RustCrypto/elliptic-curves/pull/465 +[#466]: https://github.com/RustCrypto/elliptic-curves/pull/466 +[#467]: https://github.com/RustCrypto/elliptic-curves/pull/467 +[#476]: https://github.com/RustCrypto/elliptic-curves/pull/476 + +## 0.9.0 (2021-06-08) +### Added +- `AffineArithmetic` trait impl ([#347]) +- `PrimeCurve` trait impls ([#350]) + +### Changed +- Bump `elliptic-curve` to v0.10; MSRV 1.51+ ([#349]) +- Bump `ecdsa` to v0.12 ([#349]) + +[#347]: https://github.com/RustCrypto/elliptic-curves/pull/347 +[#349]: https://github.com/RustCrypto/elliptic-curves/pull/349 +[#350]: https://github.com/RustCrypto/elliptic-curves/pull/350 + +## 0.8.1 (2021-05-10) +### Fixed +- Mixed coordinate addition with the point at infinity ([#337]) + +[#337]: https://github.com/RustCrypto/elliptic-curves/pull/337 + +## 0.8.0 (2021-04-29) +### Added +- `jwk` feature ([#279]) +- Wycheproof ECDSA P-256 test vectors ([#313]) +- `Order` constant ([#328]) + +### Changed +- Rename `ecdsa::Asn1Signature` to `::DerSignature` ([#288]) +- Migrate to `FromDigest` trait from `ecdsa` crate ([#292]) +- Bump `elliptic-curve` to v0.9.2 ([#296]) +- Bump `pkcs8` to v0.6 ([#319]) +- Bump `ecdsa` crate dependency to v0.11 ([#330]) + +### Fixed +- `DigestPrimitive` feature gating ([#324]) + +[#279]: https://github.com/RustCrypto/elliptic-curves/pull/279 +[#288]: https://github.com/RustCrypto/elliptic-curves/pull/288 +[#292]: https://github.com/RustCrypto/elliptic-curves/pull/292 +[#296]: https://github.com/RustCrypto/elliptic-curves/pull/296 +[#313]: https://github.com/RustCrypto/elliptic-curves/pull/313 +[#319]: https://github.com/RustCrypto/elliptic-curves/pull/319 +[#324]: https://github.com/RustCrypto/elliptic-curves/pull/324 +[#328]: https://github.com/RustCrypto/elliptic-curves/pull/328 +[#330]: https://github.com/RustCrypto/elliptic-curves/pull/330 + +## 0.7.3 (2021-04-16) +### Changed +- Make `ecdsa` a default feature ([#325]) + +[#325]: https://github.com/RustCrypto/elliptic-curves/pull/325 + +## 0.7.2 (2021-01-13) +### Changed +- Have `std` feature activate `ecdsa-core/std` ([#273]) + +[#273]: https://github.com/RustCrypto/elliptic-curves/pull/273 + +## 0.7.1 (2020-12-16) +### Fixed +- Trigger docs.rs rebuild with nightly bugfix ([RustCrypto/traits#412]) + +[RustCrypto/traits#412]: https://github.com/RustCrypto/traits/pull/412 + +## 0.7.0 (2020-12-16) +### Changed +- Bump `elliptic-curve` dependency to v0.8 ([#260]) +- Bump `ecdsa` to v0.10 ([#260]) + +[#260]: https://github.com/RustCrypto/elliptic-curves/pull/260 + +## 0.6.0 (2020-12-06) +### Added +- PKCS#8 support ([#243], [#244], [#245]) +- `PublicKey` type ([#239]) + +### Changed +- Bump `elliptic-curve` crate dependency to v0.7; MSRV 1.46+ ([#247]) +- Bump `ecdsa` crate dependency to v0.9 ([#247]) + +[#247]: https://github.com/RustCrypto/elliptic-curves/pull/247 +[#245]: https://github.com/RustCrypto/elliptic-curves/pull/245 +[#244]: https://github.com/RustCrypto/elliptic-curves/pull/244 +[#243]: https://github.com/RustCrypto/elliptic-curves/pull/243 +[#239]: https://github.com/RustCrypto/elliptic-curves/pull/239 + +## 0.5.2 (2020-10-08) +### Fixed +- Regenerate `rustdoc` on https://docs.rs after nightly breakage + +## 0.5.1 (2020-10-08) +### Added +- `SecretValue` impl when `arithmetic` feature is disabled ([#222]) + +[#222]: https://github.com/RustCrypto/elliptic-curves/pull/222 + +## 0.5.0 (2020-09-18) +### Added +- `ecdsa::Asn1Signature` type alias ([#186]) +- `ff` and `group` crate dependencies; MSRV 1.44+ ([#169], [#174]) +- `AffinePoint::identity()` and `::is_identity()` ([#167]) + +### Changed +- Bump `elliptic-curve` crate to v0.6; `ecdsa` to v0.8 ([#180]) +- Refactor ProjectiveArithmetic trait ([#179]) +- Support generic inner type for `elliptic_curve::SecretKey` ([#177]) +- Rename `ElementBytes` => `FieldBytes` ([#176]) +- Rename `ecdsa::{Signer, Verifier}` => `::{SigningKey, VerifyKey}` ([#153]) +- Rename `Curve::ElementSize` => `FieldSize` ([#150]) +- Implement RFC6979 deterministic ECDSA ([#146], [#147]) +- Rename `PublicKey` to `EncodedPoint` ([#141]) + +### Removed +- `rand` feature ([#162]) + +[#186]: https://github.com/RustCrypto/elliptic-curves/pull/186 +[#180]: https://github.com/RustCrypto/elliptic-curves/pull/180 +[#179]: https://github.com/RustCrypto/elliptic-curves/pull/179 +[#177]: https://github.com/RustCrypto/elliptic-curves/pull/177 +[#176]: https://github.com/RustCrypto/elliptic-curves/pull/176 +[#174]: https://github.com/RustCrypto/elliptic-curves/pull/174 +[#169]: https://github.com/RustCrypto/elliptic-curves/pull/164 +[#167]: https://github.com/RustCrypto/elliptic-curves/pull/167 +[#162]: https://github.com/RustCrypto/elliptic-curves/pull/162 +[#153]: https://github.com/RustCrypto/elliptic-curves/pull/153 +[#150]: https://github.com/RustCrypto/elliptic-curves/pull/150 +[#147]: https://github.com/RustCrypto/elliptic-curves/pull/147 +[#146]: https://github.com/RustCrypto/elliptic-curves/pull/146 +[#141]: https://github.com/RustCrypto/elliptic-curves/pull/141 + +## 0.4.1 (2020-08-11) +### Fixed +- Builds with either `ecdsa-core` or `sha256` in isolation ([#133]) + +[#133]: https://github.com/RustCrypto/elliptic-curves/pull/133 + +## 0.4.0 (2020-08-10) +### Added +- ECDSA support ([#73], [#101], [#104], [#105]) +- ECDSA public key recovery support ([#110]) +- OID support ([#103], [#113]) +- Elliptic Curve Diffie-Hellman ([#120]) + +### Changed +- Bump `elliptic-curve` crate dependency to v0.5 ([#126]) + +[#73]: https://github.com/RustCrypto/elliptic-curves/pull/73 +[#101]: https://github.com/RustCrypto/elliptic-curves/pull/101 +[#103]: https://github.com/RustCrypto/elliptic-curves/pull/103 +[#104]: https://github.com/RustCrypto/elliptic-curves/pull/104 +[#105]: https://github.com/RustCrypto/elliptic-curves/pull/105 +[#110]: https://github.com/RustCrypto/elliptic-curves/pull/110 +[#113]: https://github.com/RustCrypto/elliptic-curves/pull/113 +[#120]: https://github.com/RustCrypto/elliptic-curves/pull/120 +[#126]: https://github.com/RustCrypto/elliptic-curves/pull/126 + +## 0.3.0 (2020-06-08) +### Changed +- Bump `elliptic-curve` crate dependency to v0.4 ([#39]) + +[#39]: https://github.com/RustCrypto/elliptic-curves/pull/39 + +## 0.2.0 (2020-04-30) +### Added +- Constant time scalar multiplication ([#18]) +- Group operation ([#15]) + +[#18]: https://github.com/RustCrypto/elliptic-curves/pull/18 +[#15]: https://github.com/RustCrypto/elliptic-curves/pull/15 + +## 0.1.0 (2020-01-15) +- Initial release diff --git a/src/rust/vendor/p256/Cargo.toml b/src/rust/vendor/p256/Cargo.toml new file mode 100644 index 000000000..b04296e49 --- /dev/null +++ b/src/rust/vendor/p256/Cargo.toml @@ -0,0 +1,181 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.65" +name = "p256" +version = "0.13.2" +authors = ["RustCrypto Developers"] +description = """ +Pure Rust implementation of the NIST P-256 (a.k.a. secp256r1, prime256v1) +elliptic curve as defined in SP 800-186, with support for ECDH, ECDSA +signing/verification, and general purpose curve arithmetic +""" +documentation = "https://docs.rs/p256" +readme = "README.md" +keywords = [ + "crypto", + "ecc", + "nist", + "prime256v1", + "secp256r1", +] +categories = [ + "cryptography", + "no-std", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/RustCrypto/elliptic-curves/tree/master/p256" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[[bench]] +name = "field" +harness = false +required-features = ["expose-field"] + +[[bench]] +name = "scalar" +harness = false + +[dependencies.ecdsa-core] +version = "0.16" +features = ["der"] +optional = true +default-features = false +package = "ecdsa" + +[dependencies.elliptic-curve] +version = "0.13.1" +features = [ + "hazmat", + "sec1", +] +default-features = false + +[dependencies.hex-literal] +version = "0.4" +optional = true + +[dependencies.primeorder] +version = "0.13" +optional = true + +[dependencies.serdect] +version = "0.2" +optional = true +default-features = false + +[dependencies.sha2] +version = "0.10" +optional = true +default-features = false + +[dev-dependencies.blobby] +version = "0.3" + +[dev-dependencies.criterion] +version = "0.4" + +[dev-dependencies.ecdsa-core] +version = "0.16" +features = ["dev"] +default-features = false +package = "ecdsa" + +[dev-dependencies.hex-literal] +version = "0.4" + +[dev-dependencies.primeorder] +version = "0.13" +features = ["dev"] + +[dev-dependencies.proptest] +version = "1" + +[dev-dependencies.rand_core] +version = "0.6" +features = ["getrandom"] + +[features] +alloc = [ + "ecdsa-core?/alloc", + "elliptic-curve/alloc", +] +arithmetic = [ + "dep:primeorder", + "elliptic-curve/arithmetic", +] +bits = [ + "arithmetic", + "elliptic-curve/bits", +] +default = [ + "arithmetic", + "ecdsa", + "pem", + "std", +] +digest = [ + "ecdsa-core/digest", + "ecdsa-core/hazmat", +] +ecdh = [ + "arithmetic", + "elliptic-curve/ecdh", +] +ecdsa = [ + "arithmetic", + "ecdsa-core/signing", + "ecdsa-core/verifying", + "sha256", +] +expose-field = ["arithmetic"] +hash2curve = [ + "arithmetic", + "elliptic-curve/hash2curve", +] +jwk = ["elliptic-curve/jwk"] +pem = [ + "elliptic-curve/pem", + "ecdsa-core/pem", + "pkcs8", +] +pkcs8 = [ + "ecdsa-core?/pkcs8", + "elliptic-curve/pkcs8", +] +serde = [ + "ecdsa-core?/serde", + "elliptic-curve/serde", + "primeorder?/serde", + "serdect", +] +sha256 = [ + "digest", + "sha2", +] +std = [ + "alloc", + "ecdsa-core?/std", + "elliptic-curve/std", +] +test-vectors = ["dep:hex-literal"] +voprf = [ + "elliptic-curve/voprf", + "sha2", +] diff --git a/src/rust/vendor/p256/LICENSE-APACHE b/src/rust/vendor/p256/LICENSE-APACHE new file mode 100644 index 000000000..78173fa2e --- /dev/null +++ b/src/rust/vendor/p256/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/p256/LICENSE-MIT b/src/rust/vendor/p256/LICENSE-MIT new file mode 100644 index 000000000..50b1254c1 --- /dev/null +++ b/src/rust/vendor/p256/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2020-2023 RustCrypto Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/p256/README.md b/src/rust/vendor/p256/README.md new file mode 100644 index 000000000..610910c7e --- /dev/null +++ b/src/rust/vendor/p256/README.md @@ -0,0 +1,91 @@ +# [RustCrypto]: NIST P-256 (secp256r1) elliptic curve + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +[![Build Status][build-image]][build-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Project Chat][chat-image]][chat-link] + +Pure Rust implementation of the NIST P-256 (a.k.a. secp256r1, prime256v1) +elliptic curve with support for ECDH, ECDSA signing/verification, and general +purpose curve arithmetic support implemented in terms of traits from the +[`elliptic-curve`] crate. + +[Documentation][docs-link] + +## ⚠️ Security Warning + +The elliptic curve arithmetic contained in this crate has never been +independently audited! + +This crate has been designed with the goal of ensuring that secret-dependent +operations are performed in constant time (using the `subtle` crate and +constant-time formulas). However, it has not been thoroughly assessed to ensure +that generated assembly is constant time on common CPU architectures. + +USE AT YOUR OWN RISK! + +## Supported Algorithms + +- [Elliptic Curve Diffie-Hellman (ECDH)][ECDH]: gated under the `ecdh` feature. +- [Elliptic Curve Digital Signature Algorithm (ECDSA)][ECDSA]: gated under the + `ecdsa` feature. + +## About NIST P-256 + +NIST P-256 is a Weierstrass curve specified in [SP 800-186]: +Recommendations for Discrete Logarithm-based Cryptography: +Elliptic Curve Domain Parameters. + +Also known as prime256v1 (ANSI X9.62) and secp256r1 (SECG), it's included in +the US National Security Agency's "Suite B" and is widely used in protocols +like TLS and the associated X.509 PKI. + +## Minimum Supported Rust Version + +Rust **1.65** or higher. + +Minimum supported Rust version can be changed in the future, but it will be +done with a minor version bump. + +## SemVer Policy + +- All on-by-default features of this library are covered by SemVer +- MSRV is considered exempt from SemVer as noted above + +## License + +All crates licensed under either of + + * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + * [MIT license](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. + +[//]: # (badges) + +[crate-image]: https://buildstats.info/crate/p256 +[crate-link]: https://crates.io/crates/p256 +[docs-image]: https://docs.rs/p256/badge.svg +[docs-link]: https://docs.rs/p256/ +[build-image]: https://github.com/RustCrypto/elliptic-curves/actions/workflows/p256.yml/badge.svg +[build-link]: https://github.com/RustCrypto/elliptic-curves/actions/workflows/p256.yml +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260040-elliptic-curves + +[//]: # (general links) + +[RustCrypto]: https://github.com/rustcrypto/ +[`elliptic-curve`]: https://github.com/RustCrypto/traits/tree/master/elliptic-curve +[ECDH]: https://en.wikipedia.org/wiki/Elliptic-curve_Diffie-Hellman +[ECDSA]: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm +[SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final diff --git a/src/rust/vendor/p256/benches/field.rs b/src/rust/vendor/p256/benches/field.rs new file mode 100644 index 000000000..43ece839f --- /dev/null +++ b/src/rust/vendor/p256/benches/field.rs @@ -0,0 +1,54 @@ +//! secp256r1 field element benchmarks + +use criterion::{ + criterion_group, criterion_main, measurement::Measurement, BenchmarkGroup, Criterion, +}; +use hex_literal::hex; +use p256::FieldElement; + +fn test_field_element_x() -> FieldElement { + FieldElement::from_bytes( + &hex!("1ccbe91c075fc7f4f033bfa248db8fccd3565de94bbfb12f3c59ff46c271bf83").into(), + ) + .unwrap() +} + +fn test_field_element_y() -> FieldElement { + FieldElement::from_bytes( + &hex!("ce4014c68811f9a21a1fdb2c0e6113e06db7ca93b7404e78dc7ccd5ca89a4ca9").into(), + ) + .unwrap() +} + +fn bench_field_element_mul<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { + let x = test_field_element_x(); + let y = test_field_element_y(); + group.bench_function("mul", |b| b.iter(|| &x * &y)); +} + +fn bench_field_element_square<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { + let x = test_field_element_x(); + group.bench_function("square", |b| b.iter(|| x.square())); +} + +fn bench_field_element_sqrt<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { + let x = test_field_element_x(); + group.bench_function("sqrt", |b| b.iter(|| x.sqrt())); +} + +fn bench_field_element_invert<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { + let x = test_field_element_x(); + group.bench_function("invert", |b| b.iter(|| x.invert())); +} + +fn bench_field_element(c: &mut Criterion) { + let mut group = c.benchmark_group("field element operations"); + bench_field_element_mul(&mut group); + bench_field_element_square(&mut group); + bench_field_element_invert(&mut group); + bench_field_element_sqrt(&mut group); + group.finish(); +} + +criterion_group!(benches, bench_field_element); +criterion_main!(benches); diff --git a/src/rust/vendor/p256/benches/scalar.rs b/src/rust/vendor/p256/benches/scalar.rs new file mode 100644 index 000000000..a8db8d5da --- /dev/null +++ b/src/rust/vendor/p256/benches/scalar.rs @@ -0,0 +1,75 @@ +//! secp256r1 scalar arithmetic benchmarks + +use criterion::{ + criterion_group, criterion_main, measurement::Measurement, BenchmarkGroup, Criterion, +}; +use hex_literal::hex; +use p256::{elliptic_curve::group::ff::PrimeField, ProjectivePoint, Scalar}; + +fn test_scalar_x() -> Scalar { + Scalar::from_repr( + hex!("519b423d715f8b581f4fa8ee59f4771a5b44c8130b4e3eacca54a56dda72b464").into(), + ) + .unwrap() +} + +fn test_scalar_y() -> Scalar { + Scalar::from_repr( + hex!("0f56db78ca460b055c500064824bed999a25aaf48ebb519ac201537b85479813").into(), + ) + .unwrap() +} + +fn bench_point_mul<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { + let p = ProjectivePoint::GENERATOR; + let m = test_scalar_x(); + let s = Scalar::from_repr(m.into()).unwrap(); + group.bench_function("point-scalar mul", |b| b.iter(|| &p * &s)); +} + +fn bench_scalar_sub<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { + let x = test_scalar_x(); + let y = test_scalar_y(); + group.bench_function("sub", |b| b.iter(|| &x - &y)); +} + +fn bench_scalar_add<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { + let x = test_scalar_x(); + let y = test_scalar_y(); + group.bench_function("add", |b| b.iter(|| &x + &y)); +} + +fn bench_scalar_mul<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { + let x = test_scalar_x(); + let y = test_scalar_y(); + group.bench_function("mul", |b| b.iter(|| &x * &y)); +} + +fn bench_scalar_negate<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { + let x = test_scalar_x(); + group.bench_function("negate", |b| b.iter(|| -x)); +} + +fn bench_scalar_invert<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { + let x = test_scalar_x(); + group.bench_function("invert", |b| b.iter(|| x.invert())); +} + +fn bench_point(c: &mut Criterion) { + let mut group = c.benchmark_group("point operations"); + bench_point_mul(&mut group); + group.finish(); +} + +fn bench_scalar(c: &mut Criterion) { + let mut group = c.benchmark_group("scalar operations"); + bench_scalar_sub(&mut group); + bench_scalar_add(&mut group); + bench_scalar_mul(&mut group); + bench_scalar_negate(&mut group); + bench_scalar_invert(&mut group); + group.finish(); +} + +criterion_group!(benches, bench_point, bench_scalar); +criterion_main!(benches); diff --git a/src/rust/vendor/p256/src/arithmetic.rs b/src/rust/vendor/p256/src/arithmetic.rs new file mode 100644 index 000000000..7cdf8b1dd --- /dev/null +++ b/src/rust/vendor/p256/src/arithmetic.rs @@ -0,0 +1,59 @@ +//! Pure Rust implementation of group operations on secp256r1. +//! +//! Curve parameters can be found in [NIST SP 800-186] § G.1.2: Curve P-256. +//! +//! [NIST SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final + +pub(crate) mod field; +#[cfg(feature = "hash2curve")] +mod hash2curve; +pub(crate) mod scalar; +pub(crate) mod util; + +use self::{field::FieldElement, scalar::Scalar}; +use crate::NistP256; +use elliptic_curve::{CurveArithmetic, PrimeCurveArithmetic}; +use primeorder::{point_arithmetic, PrimeCurveParams}; + +/// Elliptic curve point in affine coordinates. +pub type AffinePoint = primeorder::AffinePoint; + +/// Elliptic curve point in projective coordinates. +pub type ProjectivePoint = primeorder::ProjectivePoint; + +impl CurveArithmetic for NistP256 { + type AffinePoint = AffinePoint; + type ProjectivePoint = ProjectivePoint; + type Scalar = Scalar; +} + +impl PrimeCurveArithmetic for NistP256 { + type CurveGroup = ProjectivePoint; +} + +/// Adapted from [NIST SP 800-186] § G.1.2: Curve P-256. +/// +/// [NIST SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final +impl PrimeCurveParams for NistP256 { + type FieldElement = FieldElement; + type PointArithmetic = point_arithmetic::EquationAIsMinusThree; + + /// a = -3 + const EQUATION_A: FieldElement = FieldElement::from_u64(3).neg(); + + const EQUATION_B: FieldElement = + FieldElement::from_hex("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"); + + /// Base point of P-256. + /// + /// Defined in NIST SP 800-186 § G.1.2: + /// + /// ```text + /// Gₓ = 6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296 + /// Gᵧ = 4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5 + /// ``` + const GENERATOR: (FieldElement, FieldElement) = ( + FieldElement::from_hex("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"), + FieldElement::from_hex("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"), + ); +} diff --git a/src/rust/vendor/p256/src/arithmetic/field.rs b/src/rust/vendor/p256/src/arithmetic/field.rs new file mode 100644 index 000000000..735d09f1b --- /dev/null +++ b/src/rust/vendor/p256/src/arithmetic/field.rs @@ -0,0 +1,309 @@ +//! Field arithmetic modulo p = 2^{224}(2^{32} − 1) + 2^{192} + 2^{96} − 1 + +#![allow(clippy::assign_op_pattern, clippy::op_ref)] + +#[cfg_attr(target_pointer_width = "32", path = "field/field32.rs")] +#[cfg_attr(target_pointer_width = "64", path = "field/field64.rs")] +mod field_impl; + +use self::field_impl::*; +use crate::{FieldBytes, NistP256}; +use core::{ + fmt::{self, Debug}, + iter::{Product, Sum}, + ops::{AddAssign, Mul, MulAssign, Neg, SubAssign}, +}; +use elliptic_curve::{ + bigint::U256, + ff::PrimeField, + subtle::{Choice, ConstantTimeEq, CtOption}, +}; + +/// Field modulus serialized as hex. +/// p = 2^{224}(2^{32} − 1) + 2^{192} + 2^{96} − 1 +const MODULUS_HEX: &str = "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff"; + +/// Constant representing the modulus. +pub const MODULUS: U256 = U256::from_be_hex(MODULUS_HEX); + +/// R^2 = 2^512 mod p +const R_2: U256 = + U256::from_be_hex("00000004fffffffdfffffffffffffffefffffffbffffffff0000000000000003"); + +/// An element in the finite field modulo p = 2^{224}(2^{32} − 1) + 2^{192} + 2^{96} − 1. +/// +/// The internal representation is in little-endian order. Elements are always in +/// Montgomery form; i.e., FieldElement(a) = aR mod p, with R = 2^256. +#[derive(Clone, Copy)] +pub struct FieldElement(pub(crate) U256); + +primeorder::impl_mont_field_element!( + NistP256, + FieldElement, + FieldBytes, + U256, + MODULUS, + Fe, + fe_from_montgomery, + fe_to_montgomery, + fe_add, + fe_sub, + fe_mul, + fe_neg, + fe_square +); + +impl FieldElement { + /// Returns the multiplicative inverse of self, if self is non-zero. + pub fn invert(&self) -> CtOption { + CtOption::new(self.invert_unchecked(), !self.is_zero()) + } + + /// Returns the multiplicative inverse of self. + /// + /// Does not check that self is non-zero. + const fn invert_unchecked(&self) -> Self { + // We need to find b such that b * a ≡ 1 mod p. As we are in a prime + // field, we can apply Fermat's Little Theorem: + // + // a^p ≡ a mod p + // a^(p-1) ≡ 1 mod p + // a^(p-2) * a ≡ 1 mod p + // + // Thus inversion can be implemented with a single exponentiation. + + let t111 = self.multiply(&self.multiply(&self.square()).square()); + let t111111 = t111.multiply(&t111.sqn(3)); + let x15 = t111111.sqn(6).multiply(&t111111).sqn(3).multiply(&t111); + let x16 = x15.square().multiply(self); + let i53 = x16.sqn(16).multiply(&x16).sqn(15); + let x47 = x15.multiply(&i53); + x47.multiply(&i53.sqn(17).multiply(self).sqn(143).multiply(&x47).sqn(47)) + .sqn(2) + .multiply(self) + } + + /// Returns the square root of self mod p, or `None` if no square root exists. + pub fn sqrt(&self) -> CtOption { + // We need to find alpha such that alpha^2 = beta mod p. For secp256r1, + // p ≡ 3 mod 4. By Euler's Criterion, beta^(p-1)/2 ≡ 1 mod p. So: + // + // alpha^2 = beta beta^((p - 1) / 2) mod p ≡ beta^((p + 1) / 2) mod p + // alpha = ± beta^((p + 1) / 4) mod p + // + // Thus sqrt can be implemented with a single exponentiation. + + let t11 = self.mul(&self.square()); + let t1111 = t11.mul(&t11.sqn(2)); + let t11111111 = t1111.mul(&t1111.sqn(4)); + let x16 = t11111111.sqn(8).mul(&t11111111); + let sqrt = x16 + .sqn(16) + .mul(&x16) + .sqn(32) + .mul(self) + .sqn(96) + .mul(self) + .sqn(94); + + CtOption::new( + sqrt, + (&sqrt * &sqrt).ct_eq(self), // Only return Some if it's the square root. + ) + } + + /// Returns self^(2^n) mod p + const fn sqn(&self, n: usize) -> Self { + let mut x = *self; + let mut i = 0; + while i < n { + x = x.square(); + i += 1; + } + x + } +} + +impl PrimeField for FieldElement { + type Repr = FieldBytes; + + const MODULUS: &'static str = MODULUS_HEX; + const NUM_BITS: u32 = 256; + const CAPACITY: u32 = 255; + const TWO_INV: Self = Self::from_u64(2).invert_unchecked(); + const MULTIPLICATIVE_GENERATOR: Self = Self::from_u64(6); + const S: u32 = 1; + const ROOT_OF_UNITY: Self = + Self::from_hex("ffffffff00000001000000000000000000000000fffffffffffffffffffffffe"); + const ROOT_OF_UNITY_INV: Self = Self::ROOT_OF_UNITY.invert_unchecked(); + const DELTA: Self = Self::from_u64(36); + + #[inline] + fn from_repr(bytes: FieldBytes) -> CtOption { + Self::from_bytes(&bytes) + } + + #[inline] + fn to_repr(&self) -> FieldBytes { + self.to_bytes() + } + + #[inline] + fn is_odd(&self) -> Choice { + self.is_odd() + } +} + +impl Debug for FieldElement { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "FieldElement(0x{:X})", &self.0) + } +} + +#[cfg(test)] +mod tests { + use super::FieldElement; + use crate::{test_vectors::field::DBL_TEST_VECTORS, FieldBytes}; + use elliptic_curve::{bigint::U256, ff::PrimeField}; + use primeorder::{ + impl_field_identity_tests, impl_field_invert_tests, impl_field_sqrt_tests, + impl_primefield_tests, + }; + use proptest::{num, prelude::*}; + + /// t = (modulus - 1) >> S + const T: [u64; 4] = [ + 0xffffffffffffffff, + 0x000000007fffffff, + 0x8000000000000000, + 0x7fffffff80000000, + ]; + + impl_field_identity_tests!(FieldElement); + impl_field_invert_tests!(FieldElement); + impl_field_sqrt_tests!(FieldElement); + impl_primefield_tests!(FieldElement, T); + + #[test] + fn from_bytes() { + assert_eq!( + FieldElement::from_bytes(&FieldBytes::default()).unwrap(), + FieldElement::ZERO + ); + assert_eq!( + FieldElement::from_bytes( + &[ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1 + ] + .into() + ) + .unwrap(), + FieldElement::ONE + ); + assert!(bool::from( + FieldElement::from_bytes(&[0xff; 32].into()).is_none() + )); + } + + #[test] + fn to_bytes() { + assert_eq!(FieldElement::ZERO.to_bytes(), FieldBytes::default()); + assert_eq!( + FieldElement::ONE.to_bytes(), + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1 + ] + .into() + ); + } + + #[test] + fn repeated_add() { + let mut r = FieldElement::ONE; + for i in 0..DBL_TEST_VECTORS.len() { + assert_eq!(r.to_bytes(), DBL_TEST_VECTORS[i].into()); + r = r + &r; + } + } + + #[test] + fn repeated_double() { + let mut r = FieldElement::ONE; + for i in 0..DBL_TEST_VECTORS.len() { + assert_eq!(r.to_bytes(), DBL_TEST_VECTORS[i].into()); + r = r.double(); + } + } + + #[test] + fn repeated_mul() { + let mut r = FieldElement::ONE; + let two = r + &r; + for i in 0..DBL_TEST_VECTORS.len() { + assert_eq!(r.to_bytes(), DBL_TEST_VECTORS[i].into()); + r = r * &two; + } + } + + #[test] + fn negation() { + let two = FieldElement::ONE.double(); + let neg_two = -two; + assert_eq!(two + &neg_two, FieldElement::ZERO); + assert_eq!(-neg_two, two); + } + + #[test] + fn pow_vartime() { + let one = FieldElement::ONE; + let two = one + &one; + let four = two.square(); + assert_eq!(two.pow_vartime(&[2, 0, 0, 0]), four); + } + + proptest! { + /// This checks behaviour well within the field ranges, because it doesn't set the + /// highest limb. + #[cfg(target_pointer_width = "32")] + #[test] + fn add_then_sub( + a0 in num::u32::ANY, + a1 in num::u32::ANY, + a2 in num::u32::ANY, + a3 in num::u32::ANY, + a4 in num::u32::ANY, + a5 in num::u32::ANY, + a6 in num::u32::ANY, + b0 in num::u32::ANY, + b1 in num::u32::ANY, + b2 in num::u32::ANY, + b3 in num::u32::ANY, + b4 in num::u32::ANY, + b5 in num::u32::ANY, + b6 in num::u32::ANY, + ) { + let a = FieldElement(U256::from_words([a0, a1, a2, a3, a4, a5, a6, 0])); + let b = FieldElement(U256::from_words([b0, b1, b2, b3, b4, b5, b6, 0])); + assert_eq!(a.add(&b).sub(&a), b); + } + + /// This checks behaviour well within the field ranges, because it doesn't set the + /// highest limb. + #[cfg(target_pointer_width = "64")] + #[test] + fn add_then_sub( + a0 in num::u64::ANY, + a1 in num::u64::ANY, + a2 in num::u64::ANY, + b0 in num::u64::ANY, + b1 in num::u64::ANY, + b2 in num::u64::ANY, + ) { + let a = FieldElement(U256::from_words([a0, a1, a2, 0])); + let b = FieldElement(U256::from_words([b0, b1, b2, 0])); + assert_eq!(a.add(&b).sub(&a), b); + } + } +} diff --git a/src/rust/vendor/p256/src/arithmetic/field/field32.rs b/src/rust/vendor/p256/src/arithmetic/field/field32.rs new file mode 100644 index 000000000..bc39b76e5 --- /dev/null +++ b/src/rust/vendor/p256/src/arithmetic/field/field32.rs @@ -0,0 +1,206 @@ +//! 32-bit secp256r1 base field implementation + +// TODO(tarcieri): adapt 64-bit arithmetic to proper 32-bit arithmetic + +use super::{MODULUS, R_2}; +use crate::arithmetic::util::{adc, mac, sbb}; + +/// Raw field element. +pub type Fe = [u32; 8]; + +/// Translate a field element out of the Montgomery domain. +#[inline] +pub const fn fe_from_montgomery(w: &Fe) -> Fe { + let w = fe32_to_fe64(w); + montgomery_reduce(&[w[0], w[1], w[2], w[3], 0, 0, 0, 0]) +} + +/// Translate a field element into the Montgomery domain. +#[inline] +pub const fn fe_to_montgomery(w: &Fe) -> Fe { + fe_mul(w, R_2.as_words()) +} + +/// Returns `a + b mod p`. +pub const fn fe_add(a: &Fe, b: &Fe) -> Fe { + let a = fe32_to_fe64(a); + let b = fe32_to_fe64(b); + + // Bit 256 of p is set, so addition can result in five words. + let (w0, carry) = adc(a[0], b[0], 0); + let (w1, carry) = adc(a[1], b[1], carry); + let (w2, carry) = adc(a[2], b[2], carry); + let (w3, w4) = adc(a[3], b[3], carry); + + // Attempt to subtract the modulus, to ensure the result is in the field. + let modulus = fe32_to_fe64(MODULUS.as_words()); + sub_inner( + &[w0, w1, w2, w3, w4], + &[modulus[0], modulus[1], modulus[2], modulus[3], 0], + ) +} + +/// Returns `a - b mod p`. +pub const fn fe_sub(a: &Fe, b: &Fe) -> Fe { + let a = fe32_to_fe64(a); + let b = fe32_to_fe64(b); + sub_inner(&[a[0], a[1], a[2], a[3], 0], &[b[0], b[1], b[2], b[3], 0]) +} + +/// Returns `a * b mod p`. +pub const fn fe_mul(a: &Fe, b: &Fe) -> Fe { + let a = fe32_to_fe64(a); + let b = fe32_to_fe64(b); + + let (w0, carry) = mac(0, a[0], b[0], 0); + let (w1, carry) = mac(0, a[0], b[1], carry); + let (w2, carry) = mac(0, a[0], b[2], carry); + let (w3, w4) = mac(0, a[0], b[3], carry); + + let (w1, carry) = mac(w1, a[1], b[0], 0); + let (w2, carry) = mac(w2, a[1], b[1], carry); + let (w3, carry) = mac(w3, a[1], b[2], carry); + let (w4, w5) = mac(w4, a[1], b[3], carry); + + let (w2, carry) = mac(w2, a[2], b[0], 0); + let (w3, carry) = mac(w3, a[2], b[1], carry); + let (w4, carry) = mac(w4, a[2], b[2], carry); + let (w5, w6) = mac(w5, a[2], b[3], carry); + + let (w3, carry) = mac(w3, a[3], b[0], 0); + let (w4, carry) = mac(w4, a[3], b[1], carry); + let (w5, carry) = mac(w5, a[3], b[2], carry); + let (w6, w7) = mac(w6, a[3], b[3], carry); + + montgomery_reduce(&[w0, w1, w2, w3, w4, w5, w6, w7]) +} + +/// Returns `-w mod p`. +pub const fn fe_neg(w: &Fe) -> Fe { + fe_sub(&[0; 8], w) +} + +/// Returns `w * w mod p`. +pub const fn fe_square(w: &Fe) -> Fe { + fe_mul(w, w) +} + +/// Montgomery Reduction +/// +/// The general algorithm is: +/// ```text +/// A <- input (2n b-limbs) +/// for i in 0..n { +/// k <- A[i] p' mod b +/// A <- A + k p b^i +/// } +/// A <- A / b^n +/// if A >= p { +/// A <- A - p +/// } +/// ``` +/// +/// For secp256r1, we have the following simplifications: +/// +/// - `p'` is 1, so our multiplicand is simply the first limb of the intermediate A. +/// +/// - The first limb of p is 2^64 - 1; multiplications by this limb can be simplified +/// to a shift and subtraction: +/// ```text +/// a_i * (2^64 - 1) = a_i * 2^64 - a_i = (a_i << 64) - a_i +/// ``` +/// However, because `p' = 1`, the first limb of p is multiplied by limb i of the +/// intermediate A and then immediately added to that same limb, so we simply +/// initialize the carry to limb i of the intermediate. +/// +/// - The third limb of p is zero, so we can ignore any multiplications by it and just +/// add the carry. +/// +/// References: +/// - Handbook of Applied Cryptography, Chapter 14 +/// Algorithm 14.32 +/// http://cacr.uwaterloo.ca/hac/about/chap14.pdf +/// +/// - Efficient and Secure Elliptic Curve Cryptography Implementation of Curve P-256 +/// Algorithm 7) Montgomery Word-by-Word Reduction +/// https://csrc.nist.gov/csrc/media/events/workshop-on-elliptic-curve-cryptography-standards/documents/papers/session6-adalier-mehmet.pdf +#[inline] +#[allow(clippy::too_many_arguments)] +const fn montgomery_reduce(r: &[u64; 8]) -> Fe { + let r0 = r[0]; + let r1 = r[1]; + let r2 = r[2]; + let r3 = r[3]; + let r4 = r[4]; + let r5 = r[5]; + let r6 = r[6]; + let r7 = r[7]; + let modulus = fe32_to_fe64(MODULUS.as_words()); + + let (r1, carry) = mac(r1, r0, modulus[1], r0); + let (r2, carry) = adc(r2, 0, carry); + let (r3, carry) = mac(r3, r0, modulus[3], carry); + let (r4, carry2) = adc(r4, 0, carry); + + let (r2, carry) = mac(r2, r1, modulus[1], r1); + let (r3, carry) = adc(r3, 0, carry); + let (r4, carry) = mac(r4, r1, modulus[3], carry); + let (r5, carry2) = adc(r5, carry2, carry); + + let (r3, carry) = mac(r3, r2, modulus[1], r2); + let (r4, carry) = adc(r4, 0, carry); + let (r5, carry) = mac(r5, r2, modulus[3], carry); + let (r6, carry2) = adc(r6, carry2, carry); + + let (r4, carry) = mac(r4, r3, modulus[1], r3); + let (r5, carry) = adc(r5, 0, carry); + let (r6, carry) = mac(r6, r3, modulus[3], carry); + let (r7, r8) = adc(r7, carry2, carry); + + // Result may be within MODULUS of the correct value + sub_inner( + &[r4, r5, r6, r7, r8], + &[modulus[0], modulus[1], modulus[2], modulus[3], 0], + ) +} + +#[inline] +#[allow(clippy::too_many_arguments)] +const fn sub_inner(l: &[u64; 5], r: &[u64; 5]) -> Fe { + let (w0, borrow) = sbb(l[0], r[0], 0); + let (w1, borrow) = sbb(l[1], r[1], borrow); + let (w2, borrow) = sbb(l[2], r[2], borrow); + let (w3, borrow) = sbb(l[3], r[3], borrow); + let (_, borrow) = sbb(l[4], r[4], borrow); + + // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise + // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the + // modulus. + let modulus = fe32_to_fe64(MODULUS.as_words()); + let (w0, carry) = adc(w0, modulus[0] & borrow, 0); + let (w1, carry) = adc(w1, modulus[1] & borrow, carry); + let (w2, carry) = adc(w2, modulus[2] & borrow, carry); + let (w3, _) = adc(w3, modulus[3] & borrow, carry); + + [ + (w0 & 0xFFFFFFFF) as u32, + (w0 >> 32) as u32, + (w1 & 0xFFFFFFFF) as u32, + (w1 >> 32) as u32, + (w2 & 0xFFFFFFFF) as u32, + (w2 >> 32) as u32, + (w3 & 0xFFFFFFFF) as u32, + (w3 >> 32) as u32, + ] +} + +// TODO(tarcieri): replace this with proper 32-bit arithmetic +#[inline] +const fn fe32_to_fe64(fe32: &Fe) -> [u64; 4] { + [ + (fe32[0] as u64) | ((fe32[1] as u64) << 32), + (fe32[2] as u64) | ((fe32[3] as u64) << 32), + (fe32[4] as u64) | ((fe32[5] as u64) << 32), + (fe32[6] as u64) | ((fe32[7] as u64) << 32), + ] +} diff --git a/src/rust/vendor/p256/src/arithmetic/field/field64.rs b/src/rust/vendor/p256/src/arithmetic/field/field64.rs new file mode 100644 index 000000000..e549cddd0 --- /dev/null +++ b/src/rust/vendor/p256/src/arithmetic/field/field64.rs @@ -0,0 +1,175 @@ +//! 64-bit secp256r1 base field implementation + +use super::{MODULUS, R_2}; +use crate::arithmetic::util::{adc, mac, sbb}; + +/// Raw field element. +pub type Fe = [u64; 4]; + +/// Translate a field element out of the Montgomery domain. +#[inline] +pub const fn fe_from_montgomery(w: &Fe) -> Fe { + montgomery_reduce(&[w[0], w[1], w[2], w[3], 0, 0, 0, 0]) +} + +/// Translate a field element into the Montgomery domain. +#[inline] +pub const fn fe_to_montgomery(w: &Fe) -> Fe { + fe_mul(w, R_2.as_words()) +} + +/// Returns `a + b mod p`. +pub const fn fe_add(a: &Fe, b: &Fe) -> Fe { + // Bit 256 of p is set, so addition can result in five words. + let (w0, carry) = adc(a[0], b[0], 0); + let (w1, carry) = adc(a[1], b[1], carry); + let (w2, carry) = adc(a[2], b[2], carry); + let (w3, w4) = adc(a[3], b[3], carry); + + // Attempt to subtract the modulus, to ensure the result is in the field. + let modulus = MODULUS.as_words(); + sub_inner( + &[w0, w1, w2, w3, w4], + &[modulus[0], modulus[1], modulus[2], modulus[3], 0], + ) +} + +/// Returns `a - b mod p`. +pub const fn fe_sub(a: &Fe, b: &Fe) -> Fe { + sub_inner(&[a[0], a[1], a[2], a[3], 0], &[b[0], b[1], b[2], b[3], 0]) +} + +/// Returns `a * b mod p`. +pub const fn fe_mul(a: &Fe, b: &Fe) -> Fe { + let (w0, carry) = mac(0, a[0], b[0], 0); + let (w1, carry) = mac(0, a[0], b[1], carry); + let (w2, carry) = mac(0, a[0], b[2], carry); + let (w3, w4) = mac(0, a[0], b[3], carry); + + let (w1, carry) = mac(w1, a[1], b[0], 0); + let (w2, carry) = mac(w2, a[1], b[1], carry); + let (w3, carry) = mac(w3, a[1], b[2], carry); + let (w4, w5) = mac(w4, a[1], b[3], carry); + + let (w2, carry) = mac(w2, a[2], b[0], 0); + let (w3, carry) = mac(w3, a[2], b[1], carry); + let (w4, carry) = mac(w4, a[2], b[2], carry); + let (w5, w6) = mac(w5, a[2], b[3], carry); + + let (w3, carry) = mac(w3, a[3], b[0], 0); + let (w4, carry) = mac(w4, a[3], b[1], carry); + let (w5, carry) = mac(w5, a[3], b[2], carry); + let (w6, w7) = mac(w6, a[3], b[3], carry); + + montgomery_reduce(&[w0, w1, w2, w3, w4, w5, w6, w7]) +} + +/// Returns `-w mod p`. +pub const fn fe_neg(w: &Fe) -> Fe { + fe_sub(&[0, 0, 0, 0], w) +} + +/// Returns `w * w mod p`. +pub const fn fe_square(w: &Fe) -> Fe { + fe_mul(w, w) +} + +/// Montgomery Reduction +/// +/// The general algorithm is: +/// ```text +/// A <- input (2n b-limbs) +/// for i in 0..n { +/// k <- A[i] p' mod b +/// A <- A + k p b^i +/// } +/// A <- A / b^n +/// if A >= p { +/// A <- A - p +/// } +/// ``` +/// +/// For secp256r1, we have the following simplifications: +/// +/// - `p'` is 1, so our multiplicand is simply the first limb of the intermediate A. +/// +/// - The first limb of p is 2^64 - 1; multiplications by this limb can be simplified +/// to a shift and subtraction: +/// ```text +/// a_i * (2^64 - 1) = a_i * 2^64 - a_i = (a_i << 64) - a_i +/// ``` +/// However, because `p' = 1`, the first limb of p is multiplied by limb i of the +/// intermediate A and then immediately added to that same limb, so we simply +/// initialize the carry to limb i of the intermediate. +/// +/// - The third limb of p is zero, so we can ignore any multiplications by it and just +/// add the carry. +/// +/// References: +/// - Handbook of Applied Cryptography, Chapter 14 +/// Algorithm 14.32 +/// http://cacr.uwaterloo.ca/hac/about/chap14.pdf +/// +/// - Efficient and Secure Elliptic Curve Cryptography Implementation of Curve P-256 +/// Algorithm 7) Montgomery Word-by-Word Reduction +/// https://csrc.nist.gov/csrc/media/events/workshop-on-elliptic-curve-cryptography-standards/documents/papers/session6-adalier-mehmet.pdf +#[inline] +#[allow(clippy::too_many_arguments)] +const fn montgomery_reduce(r: &[u64; 8]) -> Fe { + let r0 = r[0]; + let r1 = r[1]; + let r2 = r[2]; + let r3 = r[3]; + let r4 = r[4]; + let r5 = r[5]; + let r6 = r[6]; + let r7 = r[7]; + let modulus = MODULUS.as_words(); + + let (r1, carry) = mac(r1, r0, modulus[1], r0); + let (r2, carry) = adc(r2, 0, carry); + let (r3, carry) = mac(r3, r0, modulus[3], carry); + let (r4, carry2) = adc(r4, 0, carry); + + let (r2, carry) = mac(r2, r1, modulus[1], r1); + let (r3, carry) = adc(r3, 0, carry); + let (r4, carry) = mac(r4, r1, modulus[3], carry); + let (r5, carry2) = adc(r5, carry2, carry); + + let (r3, carry) = mac(r3, r2, modulus[1], r2); + let (r4, carry) = adc(r4, 0, carry); + let (r5, carry) = mac(r5, r2, modulus[3], carry); + let (r6, carry2) = adc(r6, carry2, carry); + + let (r4, carry) = mac(r4, r3, modulus[1], r3); + let (r5, carry) = adc(r5, 0, carry); + let (r6, carry) = mac(r6, r3, modulus[3], carry); + let (r7, r8) = adc(r7, carry2, carry); + + // Result may be within MODULUS of the correct value + sub_inner( + &[r4, r5, r6, r7, r8], + &[modulus[0], modulus[1], modulus[2], modulus[3], 0], + ) +} + +#[inline] +#[allow(clippy::too_many_arguments)] +const fn sub_inner(l: &[u64; 5], r: &[u64; 5]) -> Fe { + let (w0, borrow) = sbb(l[0], r[0], 0); + let (w1, borrow) = sbb(l[1], r[1], borrow); + let (w2, borrow) = sbb(l[2], r[2], borrow); + let (w3, borrow) = sbb(l[3], r[3], borrow); + let (_, borrow) = sbb(l[4], r[4], borrow); + + // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise + // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the + // modulus. + let modulus = MODULUS.as_words(); + let (w0, carry) = adc(w0, modulus[0] & borrow, 0); + let (w1, carry) = adc(w1, modulus[1] & borrow, carry); + let (w2, carry) = adc(w2, modulus[2] & borrow, carry); + let (w3, _) = adc(w3, modulus[3] & borrow, carry); + + [w0, w1, w2, w3] +} diff --git a/src/rust/vendor/p256/src/arithmetic/hash2curve.rs b/src/rust/vendor/p256/src/arithmetic/hash2curve.rs new file mode 100644 index 000000000..d638136f4 --- /dev/null +++ b/src/rust/vendor/p256/src/arithmetic/hash2curve.rs @@ -0,0 +1,320 @@ +use super::FieldElement; +use crate::{AffinePoint, FieldBytes, NistP256, ProjectivePoint, Scalar}; +use elliptic_curve::{ + bigint::{ArrayEncoding, U256}, + consts::U48, + generic_array::GenericArray, + hash2curve::{FromOkm, GroupDigest, MapToCurve, OsswuMap, OsswuMapParams, Sgn0}, + point::DecompressPoint, + subtle::Choice, +}; + +impl GroupDigest for NistP256 { + type FieldElement = FieldElement; +} + +impl FromOkm for FieldElement { + type Length = U48; + + fn from_okm(data: &GenericArray) -> Self { + const F_2_192: FieldElement = FieldElement(U256::from_be_hex( + "00000000000000030000000200000000fffffffffffffffefffffffeffffffff", + )); + + let mut d0_bytes = FieldBytes::default(); + d0_bytes[8..].copy_from_slice(&data[..24]); + let d0 = FieldElement::from_uint_unchecked(U256::from_be_byte_array(d0_bytes)); + + let mut d1_bytes = FieldBytes::default(); + d1_bytes[8..].copy_from_slice(&data[24..]); + let d1 = FieldElement::from_uint_unchecked(U256::from_be_byte_array(d1_bytes)); + + d0 * F_2_192 + d1 + } +} + +impl Sgn0 for FieldElement { + fn sgn0(&self) -> Choice { + self.is_odd() + } +} + +impl OsswuMap for FieldElement { + const PARAMS: OsswuMapParams = OsswuMapParams { + c1: &[ + 0xffff_ffff_ffff_ffff, + 0x0000_0000_3fff_ffff, + 0x4000_0000_0000_0000, + 0x3fff_ffff_c000_0000, + ], + c2: FieldElement(U256::from_be_hex( + "a3323851ba997e271ac5d59c3298bf50b2806c63966a1a6653e43951f64fdbe7", + )), + map_a: FieldElement(U256::from_be_hex( + "fffffffc00000004000000000000000000000003fffffffffffffffffffffffc", + )), + map_b: FieldElement(U256::from_be_hex( + "dc30061d04874834e5a220abf7212ed6acf005cd78843090d89cdf6229c4bddf", + )), + z: FieldElement(U256::from_be_hex( + "fffffff50000000b00000000000000000000000afffffffffffffffffffffff5", + )), + }; +} + +impl MapToCurve for FieldElement { + type Output = ProjectivePoint; + + fn map_to_curve(&self) -> Self::Output { + let (qx, qy) = self.osswu(); + + // TODO(tarcieri): assert that `qy` is correct? less circuitous conversion? + AffinePoint::decompress(&qx.to_bytes(), qy.is_odd()) + .unwrap() + .into() + } +} + +impl FromOkm for Scalar { + type Length = U48; + + fn from_okm(data: &GenericArray) -> Self { + const F_2_192: Scalar = Scalar(U256::from_be_hex( + "0000000000000001000000000000000000000000000000000000000000000000", + )); + + let mut d0 = GenericArray::default(); + d0[8..].copy_from_slice(&data[0..24]); + let d0 = Scalar(U256::from_be_byte_array(d0)); + + let mut d1 = GenericArray::default(); + d1[8..].copy_from_slice(&data[24..]); + let d1 = Scalar(U256::from_be_byte_array(d1)); + + d0 * F_2_192 + d1 + } +} + +#[cfg(test)] +mod tests { + use crate::{FieldElement, NistP256, Scalar, U256}; + use elliptic_curve::{ + bigint::{ArrayEncoding, NonZero, U384}, + consts::U48, + generic_array::GenericArray, + group::cofactor::CofactorGroup, + hash2curve::{self, ExpandMsgXmd, FromOkm, GroupDigest, MapToCurve}, + sec1::{self, ToEncodedPoint}, + Curve, Field, + }; + use hex_literal::hex; + use proptest::{num::u64::ANY, prelude::ProptestConfig, proptest}; + use sha2::Sha256; + + #[allow(dead_code)] // TODO(tarcieri): fix commented out code + #[test] + fn hash_to_curve() { + struct TestVector { + msg: &'static [u8], + p_x: [u8; 32], + p_y: [u8; 32], + u_0: [u8; 32], + u_1: [u8; 32], + q0_x: [u8; 32], + q0_y: [u8; 32], + q1_x: [u8; 32], + q1_y: [u8; 32], + } + + const DST: &[u8] = b"QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_RO_"; + + const TEST_VECTORS: &[TestVector] = &[ + TestVector { + msg: b"", + p_x: hex!("2c15230b26dbc6fc9a37051158c95b79656e17a1a920b11394ca91c44247d3e4"), + p_y: hex!("8a7a74985cc5c776cdfe4b1f19884970453912e9d31528c060be9ab5c43e8415"), + u_0: hex!("ad5342c66a6dd0ff080df1da0ea1c04b96e0330dd89406465eeba11582515009"), + u_1: hex!("8c0f1d43204bd6f6ea70ae8013070a1518b43873bcd850aafa0a9e220e2eea5a"), + q0_x: hex!("ab640a12220d3ff283510ff3f4b1953d09fad35795140b1c5d64f313967934d5"), + q0_y: hex!("dccb558863804a881d4fff3455716c836cef230e5209594ddd33d85c565b19b1"), + q1_x: hex!("51cce63c50d972a6e51c61334f0f4875c9ac1cd2d3238412f84e31da7d980ef5"), + q1_y: hex!("b45d1a36d00ad90e5ec7840a60a4de411917fbe7c82c3949a6e699e5a1b66aac"), + }, + TestVector { + msg: b"abc", + p_x: hex!("0bb8b87485551aa43ed54f009230450b492fead5f1cc91658775dac4a3388a0f"), + p_y: hex!("5c41b3d0731a27a7b14bc0bf0ccded2d8751f83493404c84a88e71ffd424212e"), + u_0: hex!("afe47f2ea2b10465cc26ac403194dfb68b7f5ee865cda61e9f3e07a537220af1"), + u_1: hex!("379a27833b0bfe6f7bdca08e1e83c760bf9a338ab335542704edcd69ce9e46e0"), + q0_x: hex!("5219ad0ddef3cc49b714145e91b2f7de6ce0a7a7dc7406c7726c7e373c58cb48"), + q0_y: hex!("7950144e52d30acbec7b624c203b1996c99617d0b61c2442354301b191d93ecf"), + q1_x: hex!("019b7cb4efcfeaf39f738fe638e31d375ad6837f58a852d032ff60c69ee3875f"), + q1_y: hex!("589a62d2b22357fed5449bc38065b760095ebe6aeac84b01156ee4252715446e"), + }, + TestVector { + msg: b"abcdef0123456789", + p_x: hex!("65038ac8f2b1def042a5df0b33b1f4eca6bff7cb0f9c6c1526811864e544ed80"), + p_y: hex!("cad44d40a656e7aff4002a8de287abc8ae0482b5ae825822bb870d6df9b56ca3"), + u_0: hex!("0fad9d125a9477d55cf9357105b0eb3a5c4259809bf87180aa01d651f53d312c"), + u_1: hex!("b68597377392cd3419d8fcc7d7660948c8403b19ea78bbca4b133c9d2196c0fb"), + q0_x: hex!("a17bdf2965eb88074bc01157e644ed409dac97cfcf0c61c998ed0fa45e79e4a2"), + q0_y: hex!("4f1bc80c70d411a3cc1d67aeae6e726f0f311639fee560c7f5a664554e3c9c2e"), + q1_x: hex!("7da48bb67225c1a17d452c983798113f47e438e4202219dd0715f8419b274d66"), + q1_y: hex!("b765696b2913e36db3016c47edb99e24b1da30e761a8a3215dc0ec4d8f96e6f9"), + }, + TestVector { + msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + p_x: hex!("4be61ee205094282ba8a2042bcb48d88dfbb609301c49aa8b078533dc65a0b5d"), + p_y: hex!("98f8df449a072c4721d241a3b1236d3caccba603f916ca680f4539d2bfb3c29e"), + u_0: hex!("3bbc30446f39a7befad080f4d5f32ed116b9534626993d2cc5033f6f8d805919"), + u_1: hex!("76bb02db019ca9d3c1e02f0c17f8baf617bbdae5c393a81d9ce11e3be1bf1d33"), + q0_x: hex!("c76aaa823aeadeb3f356909cb08f97eee46ecb157c1f56699b5efebddf0e6398"), + q0_y: hex!("776a6f45f528a0e8d289a4be12c4fab80762386ec644abf2bffb9b627e4352b1"), + q1_x: hex!("418ac3d85a5ccc4ea8dec14f750a3a9ec8b85176c95a7022f391826794eb5a75"), + q1_y: hex!("fd6604f69e9d9d2b74b072d14ea13050db72c932815523305cb9e807cc900aff"), + }, + TestVector { + msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + p_x: hex!("457ae2981f70ca85d8e24c308b14db22f3e3862c5ea0f652ca38b5e49cd64bc5"), + p_y: hex!("ecb9f0eadc9aeed232dabc53235368c1394c78de05dd96893eefa62b0f4757dc"), + u_0: hex!("4ebc95a6e839b1ae3c63b847798e85cb3c12d3817ec6ebc10af6ee51adb29fec"), + u_1: hex!("4e21af88e22ea80156aff790750121035b3eefaa96b425a8716e0d20b4e269ee"), + q0_x: hex!("d88b989ee9d1295df413d4456c5c850b8b2fb0f5402cc5c4c7e815412e926db8"), + q0_y: hex!("bb4a1edeff506cf16def96afff41b16fc74f6dbd55c2210e5b8f011ba32f4f40"), + q1_x: hex!("a281e34e628f3a4d2a53fa87ff973537d68ad4fbc28d3be5e8d9f6a2571c5a4b"), + q1_y: hex!("f6ed88a7aab56a488100e6f1174fa9810b47db13e86be999644922961206e184"), + }, + ]; + + for test_vector in TEST_VECTORS { + // in parts + let mut u = [FieldElement::default(), FieldElement::default()]; + hash2curve::hash_to_field::, FieldElement>( + &[test_vector.msg], + &[DST], + &mut u, + ) + .unwrap(); + + /// Assert that the provided projective point matches the given test vector. + // TODO(tarcieri): use coordinate APIs. See zkcrypto/group#30 + macro_rules! assert_point_eq { + ($actual:expr, $expected_x:expr, $expected_y:expr) => { + let point = $actual.to_affine().to_encoded_point(false); + let (actual_x, actual_y) = match point.coordinates() { + sec1::Coordinates::Uncompressed { x, y } => (x, y), + _ => unreachable!(), + }; + + assert_eq!(&$expected_x, actual_x.as_slice()); + assert_eq!(&$expected_y, actual_y.as_slice()); + }; + } + + assert_eq!(u[0].to_bytes().as_slice(), test_vector.u_0); + assert_eq!(u[1].to_bytes().as_slice(), test_vector.u_1); + + let q0 = u[0].map_to_curve(); + assert_point_eq!(q0, test_vector.q0_x, test_vector.q0_y); + + let q1 = u[1].map_to_curve(); + assert_point_eq!(q1, test_vector.q1_x, test_vector.q1_y); + + let p = q0.clear_cofactor() + q1.clear_cofactor(); + assert_point_eq!(p, test_vector.p_x, test_vector.p_y); + + // complete run + let pt = NistP256::hash_from_bytes::>(&[test_vector.msg], &[DST]) + .unwrap(); + assert_point_eq!(pt, test_vector.p_x, test_vector.p_y); + } + } + + /// Taken from . + #[test] + fn hash_to_scalar_voprf() { + struct TestVector { + dst: &'static [u8], + key_info: &'static [u8], + seed: &'static [u8], + sk_sm: &'static [u8], + } + + const TEST_VECTORS: &[TestVector] = &[ + TestVector { + dst: b"DeriveKeyPairVOPRF10-\x00\x00\x03", + key_info: b"test key", + seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"), + sk_sm: &hex!("274d7747cf2e26352ecea6bd768c426087da3dfcd466b6841b441ada8412fb33"), + }, + TestVector { + dst: b"DeriveKeyPairVOPRF10-\x01\x00\x03", + key_info: b"test key", + seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"), + sk_sm: &hex!("b3d12edba73e40401fdc27c0094a56337feb3646d1633345af7e7142a6b1559d"), + }, + TestVector { + dst: b"DeriveKeyPairVOPRF10-\x02\x00\x03", + key_info: b"test key", + seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"), + sk_sm: &hex!("59519f6c7da344f340ad35ad895a5b97437673cc3ac8b964b823cdb52c932f86"), + }, + ]; + + 'outer: for test_vector in TEST_VECTORS { + let key_info_len = u16::try_from(test_vector.key_info.len()) + .unwrap() + .to_be_bytes(); + + for counter in 0_u8..=u8::MAX { + let scalar = NistP256::hash_to_scalar::>( + &[ + test_vector.seed, + &key_info_len, + test_vector.key_info, + &counter.to_be_bytes(), + ], + &[test_vector.dst], + ) + .unwrap(); + + if !bool::from(scalar.is_zero()) { + assert_eq!(scalar.to_bytes().as_slice(), test_vector.sk_sm); + continue 'outer; + } + } + + panic!("deriving key failed"); + } + } + + #[test] + fn from_okm_fuzz() { + let mut wide_order = GenericArray::default(); + wide_order[16..].copy_from_slice(&NistP256::ORDER.to_be_byte_array()); + let wide_order = NonZero::new(U384::from_be_byte_array(wide_order)).unwrap(); + + let simple_from_okm = move |data: GenericArray| -> Scalar { + let data = U384::from_be_slice(&data); + + let scalar = data % wide_order; + let reduced_scalar = U256::from_be_slice(&scalar.to_be_byte_array()[16..]); + + Scalar(reduced_scalar) + }; + + proptest!(ProptestConfig::with_cases(1000), |(b0 in ANY, b1 in ANY, b2 in ANY, b3 in ANY, b4 in ANY, b5 in ANY)| { + let mut data = GenericArray::default(); + data[..8].copy_from_slice(&b0.to_be_bytes()); + data[8..16].copy_from_slice(&b1.to_be_bytes()); + data[16..24].copy_from_slice(&b2.to_be_bytes()); + data[24..32].copy_from_slice(&b3.to_be_bytes()); + data[32..40].copy_from_slice(&b4.to_be_bytes()); + data[40..].copy_from_slice(&b5.to_be_bytes()); + + let from_okm = Scalar::from_okm(&data); + let simple_from_okm = simple_from_okm(data); + assert_eq!(from_okm, simple_from_okm); + }); + } +} diff --git a/src/rust/vendor/p256/src/arithmetic/scalar.rs b/src/rust/vendor/p256/src/arithmetic/scalar.rs new file mode 100644 index 000000000..61a331eca --- /dev/null +++ b/src/rust/vendor/p256/src/arithmetic/scalar.rs @@ -0,0 +1,828 @@ +//! Scalar field arithmetic modulo n = 115792089210356248762697446949407573529996955224135760342422259061068512044369 + +#[cfg_attr(target_pointer_width = "32", path = "scalar/scalar32.rs")] +#[cfg_attr(target_pointer_width = "64", path = "scalar/scalar64.rs")] +mod scalar_impl; + +use self::scalar_impl::barrett_reduce; +use crate::{FieldBytes, NistP256, SecretKey, ORDER_HEX}; +use core::{ + fmt::{self, Debug}, + iter::{Product, Sum}, + ops::{Add, AddAssign, Mul, MulAssign, Neg, Shr, ShrAssign, Sub, SubAssign}, +}; +use elliptic_curve::{ + bigint::{prelude::*, Limb, U256}, + group::ff::{self, Field, PrimeField}, + ops::{Invert, Reduce, ReduceNonZero}, + rand_core::RngCore, + scalar::{FromUintUnchecked, IsHigh}, + subtle::{ + Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess, + CtOption, + }, + zeroize::DefaultIsZeroes, + Curve, ScalarPrimitive, +}; + +#[cfg(feature = "bits")] +use {crate::ScalarBits, elliptic_curve::group::ff::PrimeFieldBits}; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +/// Constant representing the modulus +/// n = FFFFFFFF 00000000 FFFFFFFF FFFFFFFF BCE6FAAD A7179E84 F3B9CAC2 FC632551 +pub(crate) const MODULUS: U256 = NistP256::ORDER; + +/// `MODULUS / 2` +const FRAC_MODULUS_2: Scalar = Scalar(MODULUS.shr_vartime(1)); + +/// MU = floor(2^512 / n) +/// = 115792089264276142090721624801893421302707618245269942344307673200490803338238 +/// = 0x100000000fffffffffffffffeffffffff43190552df1a6c21012ffd85eedf9bfe +pub const MU: [u64; 5] = [ + 0x012f_fd85_eedf_9bfe, + 0x4319_0552_df1a_6c21, + 0xffff_fffe_ffff_ffff, + 0x0000_0000_ffff_ffff, + 0x0000_0000_0000_0001, +]; + +/// Scalars are elements in the finite field modulo n. +/// +/// # Trait impls +/// +/// Much of the important functionality of scalars is provided by traits from +/// the [`ff`](https://docs.rs/ff/) crate, which is re-exported as +/// `p256::elliptic_curve::ff`: +/// +/// - [`Field`](https://docs.rs/ff/latest/ff/trait.Field.html) - +/// represents elements of finite fields and provides: +/// - [`Field::random`](https://docs.rs/ff/latest/ff/trait.Field.html#tymethod.random) - +/// generate a random scalar +/// - `double`, `square`, and `invert` operations +/// - Bounds for [`Add`], [`Sub`], [`Mul`], and [`Neg`] (as well as `*Assign` equivalents) +/// - Bounds for [`ConditionallySelectable`] from the `subtle` crate +/// - [`PrimeField`](https://docs.rs/ff/latest/ff/trait.PrimeField.html) - +/// represents elements of prime fields and provides: +/// - `from_repr`/`to_repr` for converting field elements from/to big integers. +/// - `multiplicative_generator` and `root_of_unity` constants. +/// - [`PrimeFieldBits`](https://docs.rs/ff/latest/ff/trait.PrimeFieldBits.html) - +/// operations over field elements represented as bits (requires `bits` feature) +/// +/// Please see the documentation for the relevant traits for more information. +/// +/// # `serde` support +/// +/// When the `serde` feature of this crate is enabled, the `Serialize` and +/// `Deserialize` traits are impl'd for this type. +/// +/// The serialization is a fixed-width big endian encoding. When used with +/// textual formats, the binary data is encoded as hexadecimal. +#[derive(Clone, Copy, Default)] +pub struct Scalar(pub(crate) U256); + +impl Scalar { + /// Zero scalar. + pub const ZERO: Self = Self(U256::ZERO); + + /// Multiplicative identity. + pub const ONE: Self = Self(U256::ONE); + + /// Returns the SEC1 encoding of this scalar. + pub fn to_bytes(&self) -> FieldBytes { + self.0.to_be_byte_array() + } + + /// Returns self + rhs mod n + pub const fn add(&self, rhs: &Self) -> Self { + Self(self.0.add_mod(&rhs.0, &NistP256::ORDER)) + } + + /// Returns 2*self. + pub const fn double(&self) -> Self { + self.add(self) + } + + /// Returns self - rhs mod n. + pub const fn sub(&self, rhs: &Self) -> Self { + Self(self.0.sub_mod(&rhs.0, &NistP256::ORDER)) + } + + /// Returns self * rhs mod n + pub const fn multiply(&self, rhs: &Self) -> Self { + let (lo, hi) = self.0.mul_wide(&rhs.0); + Self(barrett_reduce(lo, hi)) + } + + /// Returns self * self mod p + pub const fn square(&self) -> Self { + // Schoolbook multiplication. + self.multiply(self) + } + + /// Right shifts the scalar. + /// + /// Note: not constant-time with respect to the `shift` parameter. + pub const fn shr_vartime(&self, shift: usize) -> Scalar { + Self(self.0.shr_vartime(shift)) + } + + /// Returns the multiplicative inverse of self, if self is non-zero + pub fn invert(&self) -> CtOption { + CtOption::new(self.invert_unchecked(), !self.is_zero()) + } + + /// Returns the multiplicative inverse of self. + /// + /// Does not check that self is non-zero. + const fn invert_unchecked(&self) -> Self { + // We need to find b such that b * a ≡ 1 mod p. As we are in a prime + // field, we can apply Fermat's Little Theorem: + // + // a^p ≡ a mod p + // a^(p-1) ≡ 1 mod p + // a^(p-2) * a ≡ 1 mod p + // + // Thus inversion can be implemented with a single exponentiation. + // + // This is `n - 2`, so the top right two digits are `4f` instead of `51`. + self.pow_vartime(&[ + 0xf3b9_cac2_fc63_254f, + 0xbce6_faad_a717_9e84, + 0xffff_ffff_ffff_ffff, + 0xffff_ffff_0000_0000, + ]) + } + + /// Exponentiates `self` by `exp`, where `exp` is a little-endian order integer + /// exponent. + pub const fn pow_vartime(&self, exp: &[u64]) -> Self { + let mut res = Self::ONE; + + let mut i = exp.len(); + while i > 0 { + i -= 1; + + let mut j = 64; + while j > 0 { + j -= 1; + res = res.square(); + + if ((exp[i] >> j) & 1) == 1 { + res = res.multiply(self); + } + } + } + + res + } + + /// Is integer representing equivalence class odd? + pub fn is_odd(&self) -> Choice { + self.0.is_odd() + } + + /// Is integer representing equivalence class even? + pub fn is_even(&self) -> Choice { + !self.is_odd() + } +} + +impl AsRef for Scalar { + fn as_ref(&self) -> &Scalar { + self + } +} + +impl Field for Scalar { + const ZERO: Self = Self::ZERO; + const ONE: Self = Self::ONE; + + fn random(mut rng: impl RngCore) -> Self { + let mut bytes = FieldBytes::default(); + + // Generate a uniformly random scalar using rejection sampling, + // which produces a uniformly random distribution of scalars. + // + // This method is not constant time, but should be secure so long as + // rejected RNG outputs are unrelated to future ones (which is a + // necessary property of a `CryptoRng`). + // + // With an unbiased RNG, the probability of failing to complete after 4 + // iterations is vanishingly small. + loop { + rng.fill_bytes(&mut bytes); + if let Some(scalar) = Scalar::from_repr(bytes).into() { + return scalar; + } + } + } + + #[must_use] + fn square(&self) -> Self { + Scalar::square(self) + } + + #[must_use] + fn double(&self) -> Self { + self.add(self) + } + + fn invert(&self) -> CtOption { + Scalar::invert(self) + } + + /// Tonelli-Shank's algorithm for q mod 16 = 1 + /// (page 12, algorithm 5) + #[allow(clippy::many_single_char_names)] + fn sqrt(&self) -> CtOption { + // Note: `pow_vartime` is constant-time with respect to `self` + let w = self.pow_vartime(&[ + 0x279dce5617e3192a, + 0xfde737d56d38bcf4, + 0x07ffffffffffffff, + 0x07fffffff8000000, + ]); + + let mut v = Self::S; + let mut x = *self * w; + let mut b = x * w; + let mut z = Self::ROOT_OF_UNITY; + + for max_v in (1..=Self::S).rev() { + let mut k = 1; + let mut tmp = b.square(); + let mut j_less_than_v = Choice::from(1); + + for j in 2..max_v { + let tmp_is_one = tmp.ct_eq(&Self::ONE); + let squared = Self::conditional_select(&tmp, &z, tmp_is_one).square(); + tmp = Self::conditional_select(&squared, &tmp, tmp_is_one); + let new_z = Self::conditional_select(&z, &squared, tmp_is_one); + j_less_than_v &= !j.ct_eq(&v); + k = u32::conditional_select(&j, &k, tmp_is_one); + z = Self::conditional_select(&z, &new_z, j_less_than_v); + } + + let result = x * z; + x = Self::conditional_select(&result, &x, b.ct_eq(&Self::ONE)); + z = z.square(); + b *= z; + v = k; + } + + CtOption::new(x, x.square().ct_eq(self)) + } + + fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { + ff::helpers::sqrt_ratio_generic(num, div) + } +} + +impl PrimeField for Scalar { + type Repr = FieldBytes; + + const MODULUS: &'static str = ORDER_HEX; + const NUM_BITS: u32 = 256; + const CAPACITY: u32 = 255; + const TWO_INV: Self = Self(U256::from_u8(2)).invert_unchecked(); + const MULTIPLICATIVE_GENERATOR: Self = Self(U256::from_u8(7)); + const S: u32 = 4; + const ROOT_OF_UNITY: Self = Self(U256::from_be_hex( + "ffc97f062a770992ba807ace842a3dfc1546cad004378daf0592d7fbb41e6602", + )); + const ROOT_OF_UNITY_INV: Self = Self::ROOT_OF_UNITY.invert_unchecked(); + const DELTA: Self = Self(U256::from_u64(33232930569601)); + + /// Attempts to parse the given byte array as an SEC1-encoded scalar. + /// + /// Returns None if the byte array does not contain a big-endian integer in the range + /// [0, p). + fn from_repr(bytes: FieldBytes) -> CtOption { + let inner = U256::from_be_byte_array(bytes); + CtOption::new(Self(inner), inner.ct_lt(&NistP256::ORDER)) + } + + fn to_repr(&self) -> FieldBytes { + self.to_bytes() + } + + fn is_odd(&self) -> Choice { + self.0.is_odd() + } +} + +#[cfg(feature = "bits")] +impl PrimeFieldBits for Scalar { + #[cfg(target_pointer_width = "32")] + type ReprBits = [u32; 8]; + + #[cfg(target_pointer_width = "64")] + type ReprBits = [u64; 4]; + + fn to_le_bits(&self) -> ScalarBits { + self.into() + } + + fn char_le_bits() -> ScalarBits { + NistP256::ORDER.to_words().into() + } +} + +impl DefaultIsZeroes for Scalar {} + +impl Eq for Scalar {} + +impl FromUintUnchecked for Scalar { + type Uint = U256; + + fn from_uint_unchecked(uint: Self::Uint) -> Self { + Self(uint) + } +} + +impl Invert for Scalar { + type Output = CtOption; + + fn invert(&self) -> CtOption { + self.invert() + } + + /// Fast variable-time inversion using Stein's algorithm. + /// + /// Returns none if the scalar is zero. + /// + /// + /// + /// ⚠️ WARNING! + /// + /// This method should not be used with (unblinded) secret scalars, as its + /// variable-time operation can potentially leak secrets through + /// sidechannels. + #[allow(non_snake_case)] + fn invert_vartime(&self) -> CtOption { + let mut u = *self; + let mut v = Self(MODULUS); + let mut A = Self::ONE; + let mut C = Self::ZERO; + + while !bool::from(u.is_zero()) { + // u-loop + while bool::from(u.is_even()) { + u >>= 1; + + let was_odd: bool = A.is_odd().into(); + A >>= 1; + + if was_odd { + A += FRAC_MODULUS_2; + A += Self::ONE; + } + } + + // v-loop + while bool::from(v.is_even()) { + v >>= 1; + + let was_odd: bool = C.is_odd().into(); + C >>= 1; + + if was_odd { + C += FRAC_MODULUS_2; + C += Self::ONE; + } + } + + // sub-step + if u >= v { + u -= &v; + A -= &C; + } else { + v -= &u; + C -= &A; + } + } + + CtOption::new(C, !self.is_zero()) + } +} + +impl IsHigh for Scalar { + fn is_high(&self) -> Choice { + self.0.ct_gt(&FRAC_MODULUS_2.0) + } +} + +impl Shr for Scalar { + type Output = Self; + + fn shr(self, rhs: usize) -> Self::Output { + self.shr_vartime(rhs) + } +} + +impl Shr for &Scalar { + type Output = Scalar; + + fn shr(self, rhs: usize) -> Self::Output { + self.shr_vartime(rhs) + } +} + +impl ShrAssign for Scalar { + fn shr_assign(&mut self, rhs: usize) { + *self = *self >> rhs; + } +} + +impl PartialEq for Scalar { + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } +} + +impl PartialOrd for Scalar { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Scalar { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.0.cmp(&other.0) + } +} + +impl From for Scalar { + fn from(k: u32) -> Self { + Scalar(k.into()) + } +} + +impl From for Scalar { + fn from(k: u64) -> Self { + Scalar(k.into()) + } +} + +impl From for Scalar { + fn from(k: u128) -> Self { + Scalar(k.into()) + } +} + +impl From for FieldBytes { + fn from(scalar: Scalar) -> Self { + scalar.to_bytes() + } +} + +impl From<&Scalar> for FieldBytes { + fn from(scalar: &Scalar) -> Self { + scalar.to_bytes() + } +} + +impl From> for Scalar { + fn from(scalar: ScalarPrimitive) -> Scalar { + Scalar(*scalar.as_uint()) + } +} + +impl From<&ScalarPrimitive> for Scalar { + fn from(scalar: &ScalarPrimitive) -> Scalar { + Scalar(*scalar.as_uint()) + } +} + +impl From for ScalarPrimitive { + fn from(scalar: Scalar) -> ScalarPrimitive { + ScalarPrimitive::from(&scalar) + } +} + +impl From<&Scalar> for ScalarPrimitive { + fn from(scalar: &Scalar) -> ScalarPrimitive { + ScalarPrimitive::new(scalar.0).unwrap() + } +} + +impl From<&SecretKey> for Scalar { + fn from(secret_key: &SecretKey) -> Scalar { + *secret_key.to_nonzero_scalar() + } +} + +impl From for U256 { + fn from(scalar: Scalar) -> U256 { + scalar.0 + } +} + +impl From<&Scalar> for U256 { + fn from(scalar: &Scalar) -> U256 { + scalar.0 + } +} + +#[cfg(feature = "bits")] +impl From<&Scalar> for ScalarBits { + fn from(scalar: &Scalar) -> ScalarBits { + scalar.0.to_words().into() + } +} + +impl Add for Scalar { + type Output = Scalar; + + fn add(self, other: Scalar) -> Scalar { + Scalar::add(&self, &other) + } +} + +impl Add<&Scalar> for &Scalar { + type Output = Scalar; + + fn add(self, other: &Scalar) -> Scalar { + Scalar::add(self, other) + } +} + +impl Add<&Scalar> for Scalar { + type Output = Scalar; + + fn add(self, other: &Scalar) -> Scalar { + Scalar::add(&self, other) + } +} + +impl AddAssign for Scalar { + fn add_assign(&mut self, rhs: Scalar) { + *self = Scalar::add(self, &rhs); + } +} + +impl AddAssign<&Scalar> for Scalar { + fn add_assign(&mut self, rhs: &Scalar) { + *self = Scalar::add(self, rhs); + } +} + +impl Sub for Scalar { + type Output = Scalar; + + fn sub(self, other: Scalar) -> Scalar { + Scalar::sub(&self, &other) + } +} + +impl Sub<&Scalar> for &Scalar { + type Output = Scalar; + + fn sub(self, other: &Scalar) -> Scalar { + Scalar::sub(self, other) + } +} + +impl Sub<&Scalar> for Scalar { + type Output = Scalar; + + fn sub(self, other: &Scalar) -> Scalar { + Scalar::sub(&self, other) + } +} + +impl SubAssign for Scalar { + fn sub_assign(&mut self, rhs: Scalar) { + *self = Scalar::sub(self, &rhs); + } +} + +impl SubAssign<&Scalar> for Scalar { + fn sub_assign(&mut self, rhs: &Scalar) { + *self = Scalar::sub(self, rhs); + } +} + +impl Mul for Scalar { + type Output = Scalar; + + fn mul(self, other: Scalar) -> Scalar { + Scalar::multiply(&self, &other) + } +} + +impl Mul<&Scalar> for &Scalar { + type Output = Scalar; + + fn mul(self, other: &Scalar) -> Scalar { + Scalar::multiply(self, other) + } +} + +impl Mul<&Scalar> for Scalar { + type Output = Scalar; + + fn mul(self, other: &Scalar) -> Scalar { + Scalar::multiply(&self, other) + } +} + +impl MulAssign for Scalar { + fn mul_assign(&mut self, rhs: Scalar) { + *self = Scalar::multiply(self, &rhs); + } +} + +impl MulAssign<&Scalar> for Scalar { + fn mul_assign(&mut self, rhs: &Scalar) { + *self = Scalar::multiply(self, rhs); + } +} + +impl Neg for Scalar { + type Output = Scalar; + + fn neg(self) -> Scalar { + Scalar::ZERO - self + } +} + +impl<'a> Neg for &'a Scalar { + type Output = Scalar; + + fn neg(self) -> Scalar { + Scalar::ZERO - self + } +} + +impl Reduce for Scalar { + type Bytes = FieldBytes; + + fn reduce(w: U256) -> Self { + let (r, underflow) = w.sbb(&NistP256::ORDER, Limb::ZERO); + let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8); + Self(U256::conditional_select(&w, &r, !underflow)) + } + + fn reduce_bytes(bytes: &FieldBytes) -> Self { + Self::reduce(U256::from_be_byte_array(*bytes)) + } +} + +impl ReduceNonZero for Scalar { + fn reduce_nonzero(w: U256) -> Self { + const ORDER_MINUS_ONE: U256 = NistP256::ORDER.wrapping_sub(&U256::ONE); + let (r, underflow) = w.sbb(&ORDER_MINUS_ONE, Limb::ZERO); + let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8); + Self(U256::conditional_select(&w, &r, !underflow).wrapping_add(&U256::ONE)) + } + + fn reduce_nonzero_bytes(bytes: &FieldBytes) -> Self { + Self::reduce_nonzero(U256::from_be_byte_array(*bytes)) + } +} + +impl Sum for Scalar { + fn sum>(iter: I) -> Self { + iter.reduce(core::ops::Add::add).unwrap_or(Self::ZERO) + } +} + +impl<'a> Sum<&'a Scalar> for Scalar { + fn sum>(iter: I) -> Self { + iter.copied().sum() + } +} + +impl Product for Scalar { + fn product>(iter: I) -> Self { + iter.reduce(core::ops::Mul::mul).unwrap_or(Self::ONE) + } +} + +impl<'a> Product<&'a Scalar> for Scalar { + fn product>(iter: I) -> Self { + iter.copied().product() + } +} + +impl ConditionallySelectable for Scalar { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self(U256::conditional_select(&a.0, &b.0, choice)) + } +} + +impl ConstantTimeEq for Scalar { + fn ct_eq(&self, other: &Self) -> Choice { + self.0.ct_eq(&other.0) + } +} + +impl Debug for Scalar { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Scalar(0x{:X})", &self.0) + } +} + +#[cfg(feature = "serde")] +impl Serialize for Scalar { + fn serialize(&self, serializer: S) -> Result + where + S: ser::Serializer, + { + ScalarPrimitive::from(self).serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for Scalar { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + Ok(ScalarPrimitive::deserialize(deserializer)?.into()) + } +} + +#[cfg(test)] +mod tests { + use super::Scalar; + use crate::{FieldBytes, SecretKey}; + use elliptic_curve::group::ff::{Field, PrimeField}; + use primeorder::{ + impl_field_identity_tests, impl_field_invert_tests, impl_field_sqrt_tests, + impl_primefield_tests, + }; + + /// t = (modulus - 1) >> S + const T: [u64; 4] = [ + 0x4f3b9cac2fc63255, + 0xfbce6faada7179e8, + 0x0fffffffffffffff, + 0x0ffffffff0000000, + ]; + + impl_field_identity_tests!(Scalar); + impl_field_invert_tests!(Scalar); + impl_field_sqrt_tests!(Scalar); + impl_primefield_tests!(Scalar, T); + + #[test] + fn from_to_bytes_roundtrip() { + let k: u64 = 42; + let mut bytes = FieldBytes::default(); + bytes[24..].copy_from_slice(k.to_be_bytes().as_ref()); + + let scalar = Scalar::from_repr(bytes).unwrap(); + assert_eq!(bytes, scalar.to_bytes()); + } + + /// Basic tests that multiplication works. + #[test] + fn multiply() { + let one = Scalar::ONE; + let two = one + &one; + let three = two + &one; + let six = three + &three; + assert_eq!(six, two * &three); + + let minus_two = -two; + let minus_three = -three; + assert_eq!(two, -minus_two); + + assert_eq!(minus_three * &minus_two, minus_two * &minus_three); + assert_eq!(six, minus_two * &minus_three); + } + + /// Tests that a Scalar can be safely converted to a SecretKey and back + #[test] + fn from_ec_secret() { + let scalar = Scalar::ONE; + let secret = SecretKey::from_bytes(&scalar.to_bytes()).unwrap(); + let rederived_scalar = Scalar::from(&secret); + assert_eq!(scalar.0, rederived_scalar.0); + } + + #[test] + #[cfg(all(feature = "bits", target_pointer_width = "32"))] + fn scalar_into_scalarbits() { + use crate::ScalarBits; + + let minus_one = ScalarBits::from([ + 0xfc63_2550, + 0xf3b9_cac2, + 0xa717_9e84, + 0xbce6_faad, + 0xffff_ffff, + 0xffff_ffff, + 0x0000_0000, + 0xffff_ffff, + ]); + + let scalar_bits = ScalarBits::from(&-Scalar::from(1u32)); + assert_eq!(minus_one, scalar_bits); + } +} diff --git a/src/rust/vendor/p256/src/arithmetic/scalar/scalar32.rs b/src/rust/vendor/p256/src/arithmetic/scalar/scalar32.rs new file mode 100644 index 000000000..dfa5742eb --- /dev/null +++ b/src/rust/vendor/p256/src/arithmetic/scalar/scalar32.rs @@ -0,0 +1,188 @@ +//! 32-bit secp256r1 scalar field algorithms. + +// TODO(tarcieri): adapt 64-bit arithmetic to proper 32-bit arithmetic + +use super::{MODULUS, MU}; +use crate::{ + arithmetic::util::{adc, mac, sbb}, + U256, +}; + +/// Barrett Reduction +/// +/// The general algorithm is: +/// ```text +/// p = n = order of group +/// b = 2^64 = 64bit machine word +/// k = 4 +/// a \in [0, 2^512] +/// mu := floor(b^{2k} / p) +/// q1 := floor(a / b^{k - 1}) +/// q2 := q1 * mu +/// q3 := <- floor(a / b^{k - 1}) +/// r1 := a mod b^{k + 1} +/// r2 := q3 * m mod b^{k + 1} +/// r := r1 - r2 +/// +/// if r < 0: r := r + b^{k + 1} +/// while r >= p: do r := r - p (at most twice) +/// ``` +/// +/// References: +/// - Handbook of Applied Cryptography, Chapter 14 +/// Algorithm 14.42 +/// http://cacr.uwaterloo.ca/hac/about/chap14.pdf +/// +/// - Efficient and Secure Elliptic Curve Cryptography Implementation of Curve P-256 +/// Algorithm 6) Barrett Reduction modulo p +/// https://csrc.nist.gov/csrc/media/events/workshop-on-elliptic-curve-cryptography-standards/documents/papers/session6-adalier-mehmet.pdf +#[inline] +#[allow(clippy::too_many_arguments)] +pub(super) const fn barrett_reduce(lo: U256, hi: U256) -> U256 { + let lo = u256_to_u64x4(lo); + let hi = u256_to_u64x4(hi); + let a0 = lo[0]; + let a1 = lo[1]; + let a2 = lo[2]; + let a3 = lo[3]; + let a4 = hi[0]; + let a5 = hi[1]; + let a6 = hi[2]; + let a7 = hi[3]; + let q1: [u64; 5] = [a3, a4, a5, a6, a7]; + let q3 = q1_times_mu_shift_five(&q1); + + let r1: [u64; 5] = [a0, a1, a2, a3, a4]; + let r2: [u64; 5] = q3_times_n_keep_five(&q3); + let r: [u64; 5] = sub_inner_five(r1, r2); + + // Result is in range (0, 3*n - 1), + // and 90% of the time, no subtraction will be needed. + let r = subtract_n_if_necessary(r[0], r[1], r[2], r[3], r[4]); + let r = subtract_n_if_necessary(r[0], r[1], r[2], r[3], r[4]); + + U256::from_words([ + (r[0] & 0xFFFFFFFF) as u32, + (r[0] >> 32) as u32, + (r[1] & 0xFFFFFFFF) as u32, + (r[1] >> 32) as u32, + (r[2] & 0xFFFFFFFF) as u32, + (r[2] >> 32) as u32, + (r[3] & 0xFFFFFFFF) as u32, + (r[3] >> 32) as u32, + ]) +} + +const fn q1_times_mu_shift_five(q1: &[u64; 5]) -> [u64; 5] { + // Schoolbook multiplication. + + let (_w0, carry) = mac(0, q1[0], MU[0], 0); + let (w1, carry) = mac(0, q1[0], MU[1], carry); + let (w2, carry) = mac(0, q1[0], MU[2], carry); + let (w3, carry) = mac(0, q1[0], MU[3], carry); + let (w4, w5) = mac(0, q1[0], MU[4], carry); + + let (_w1, carry) = mac(w1, q1[1], MU[0], 0); + let (w2, carry) = mac(w2, q1[1], MU[1], carry); + let (w3, carry) = mac(w3, q1[1], MU[2], carry); + let (w4, carry) = mac(w4, q1[1], MU[3], carry); + let (w5, w6) = mac(w5, q1[1], MU[4], carry); + + let (_w2, carry) = mac(w2, q1[2], MU[0], 0); + let (w3, carry) = mac(w3, q1[2], MU[1], carry); + let (w4, carry) = mac(w4, q1[2], MU[2], carry); + let (w5, carry) = mac(w5, q1[2], MU[3], carry); + let (w6, w7) = mac(w6, q1[2], MU[4], carry); + + let (_w3, carry) = mac(w3, q1[3], MU[0], 0); + let (w4, carry) = mac(w4, q1[3], MU[1], carry); + let (w5, carry) = mac(w5, q1[3], MU[2], carry); + let (w6, carry) = mac(w6, q1[3], MU[3], carry); + let (w7, w8) = mac(w7, q1[3], MU[4], carry); + + let (_w4, carry) = mac(w4, q1[4], MU[0], 0); + let (w5, carry) = mac(w5, q1[4], MU[1], carry); + let (w6, carry) = mac(w6, q1[4], MU[2], carry); + let (w7, carry) = mac(w7, q1[4], MU[3], carry); + let (w8, w9) = mac(w8, q1[4], MU[4], carry); + + // let q2 = [_w0, _w1, _w2, _w3, _w4, w5, w6, w7, w8, w9]; + [w5, w6, w7, w8, w9] +} + +const fn q3_times_n_keep_five(q3: &[u64; 5]) -> [u64; 5] { + // Schoolbook multiplication. + + let modulus = u256_to_u64x4(MODULUS); + + let (w0, carry) = mac(0, q3[0], modulus[0], 0); + let (w1, carry) = mac(0, q3[0], modulus[1], carry); + let (w2, carry) = mac(0, q3[0], modulus[2], carry); + let (w3, carry) = mac(0, q3[0], modulus[3], carry); + let (w4, _) = mac(0, q3[0], 0, carry); + + let (w1, carry) = mac(w1, q3[1], modulus[0], 0); + let (w2, carry) = mac(w2, q3[1], modulus[1], carry); + let (w3, carry) = mac(w3, q3[1], modulus[2], carry); + let (w4, _) = mac(w4, q3[1], modulus[3], carry); + + let (w2, carry) = mac(w2, q3[2], modulus[0], 0); + let (w3, carry) = mac(w3, q3[2], modulus[1], carry); + let (w4, _) = mac(w4, q3[2], modulus[2], carry); + + let (w3, carry) = mac(w3, q3[3], modulus[0], 0); + let (w4, _) = mac(w4, q3[3], modulus[1], carry); + + let (w4, _) = mac(w4, q3[4], modulus[0], 0); + + [w0, w1, w2, w3, w4] +} + +#[inline] +#[allow(clippy::too_many_arguments)] +const fn sub_inner_five(l: [u64; 5], r: [u64; 5]) -> [u64; 5] { + let (w0, borrow) = sbb(l[0], r[0], 0); + let (w1, borrow) = sbb(l[1], r[1], borrow); + let (w2, borrow) = sbb(l[2], r[2], borrow); + let (w3, borrow) = sbb(l[3], r[3], borrow); + let (w4, _borrow) = sbb(l[4], r[4], borrow); + + // If underflow occurred on the final limb - don't care (= add b^{k+1}). + [w0, w1, w2, w3, w4] +} + +#[inline] +#[allow(clippy::too_many_arguments)] +const fn subtract_n_if_necessary(r0: u64, r1: u64, r2: u64, r3: u64, r4: u64) -> [u64; 5] { + let modulus = u256_to_u64x4(MODULUS); + + let (w0, borrow) = sbb(r0, modulus[0], 0); + let (w1, borrow) = sbb(r1, modulus[1], borrow); + let (w2, borrow) = sbb(r2, modulus[2], borrow); + let (w3, borrow) = sbb(r3, modulus[3], borrow); + let (w4, borrow) = sbb(r4, 0, borrow); + + // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise + // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the + // modulus. + let (w0, carry) = adc(w0, modulus[0] & borrow, 0); + let (w1, carry) = adc(w1, modulus[1] & borrow, carry); + let (w2, carry) = adc(w2, modulus[2] & borrow, carry); + let (w3, carry) = adc(w3, modulus[3] & borrow, carry); + let (w4, _carry) = adc(w4, 0, carry); + + [w0, w1, w2, w3, w4] +} + +// TODO(tarcieri): replace this with proper 32-bit arithmetic +#[inline] +const fn u256_to_u64x4(u256: U256) -> [u64; 4] { + let words = u256.as_words(); + + [ + (words[0] as u64) | ((words[1] as u64) << 32), + (words[2] as u64) | ((words[3] as u64) << 32), + (words[4] as u64) | ((words[5] as u64) << 32), + (words[6] as u64) | ((words[7] as u64) << 32), + ] +} diff --git a/src/rust/vendor/p256/src/arithmetic/scalar/scalar64.rs b/src/rust/vendor/p256/src/arithmetic/scalar/scalar64.rs new file mode 100644 index 000000000..e15711bc1 --- /dev/null +++ b/src/rust/vendor/p256/src/arithmetic/scalar/scalar64.rs @@ -0,0 +1,163 @@ +//! 64-bit secp256r1 scalar field algorithms. + +use super::{MODULUS, MU}; +use crate::{ + arithmetic::util::{adc, mac, sbb}, + U256, +}; + +/// Barrett Reduction +/// +/// The general algorithm is: +/// ```text +/// p = n = order of group +/// b = 2^64 = 64bit machine word +/// k = 4 +/// a \in [0, 2^512] +/// mu := floor(b^{2k} / p) +/// q1 := floor(a / b^{k - 1}) +/// q2 := q1 * mu +/// q3 := <- floor(a / b^{k - 1}) +/// r1 := a mod b^{k + 1} +/// r2 := q3 * m mod b^{k + 1} +/// r := r1 - r2 +/// +/// if r < 0: r := r + b^{k + 1} +/// while r >= p: do r := r - p (at most twice) +/// ``` +/// +/// References: +/// - Handbook of Applied Cryptography, Chapter 14 +/// Algorithm 14.42 +/// http://cacr.uwaterloo.ca/hac/about/chap14.pdf +/// +/// - Efficient and Secure Elliptic Curve Cryptography Implementation of Curve P-256 +/// Algorithm 6) Barrett Reduction modulo p +/// https://csrc.nist.gov/csrc/media/events/workshop-on-elliptic-curve-cryptography-standards/documents/papers/session6-adalier-mehmet.pdf +#[inline] +#[allow(clippy::too_many_arguments)] +pub(super) const fn barrett_reduce(lo: U256, hi: U256) -> U256 { + let lo = lo.as_words(); + let hi = hi.as_words(); + let a0 = lo[0]; + let a1 = lo[1]; + let a2 = lo[2]; + let a3 = lo[3]; + let a4 = hi[0]; + let a5 = hi[1]; + let a6 = hi[2]; + let a7 = hi[3]; + let q1: [u64; 5] = [a3, a4, a5, a6, a7]; + let q3 = q1_times_mu_shift_five(&q1); + + let r1: [u64; 5] = [a0, a1, a2, a3, a4]; + let r2: [u64; 5] = q3_times_n_keep_five(&q3); + let r: [u64; 5] = sub_inner_five(r1, r2); + + // Result is in range (0, 3*n - 1), + // and 90% of the time, no subtraction will be needed. + let r = subtract_n_if_necessary(r[0], r[1], r[2], r[3], r[4]); + let r = subtract_n_if_necessary(r[0], r[1], r[2], r[3], r[4]); + U256::from_words([r[0], r[1], r[2], r[3]]) +} + +const fn q1_times_mu_shift_five(q1: &[u64; 5]) -> [u64; 5] { + // Schoolbook multiplication. + + let (_w0, carry) = mac(0, q1[0], MU[0], 0); + let (w1, carry) = mac(0, q1[0], MU[1], carry); + let (w2, carry) = mac(0, q1[0], MU[2], carry); + let (w3, carry) = mac(0, q1[0], MU[3], carry); + let (w4, w5) = mac(0, q1[0], MU[4], carry); + + let (_w1, carry) = mac(w1, q1[1], MU[0], 0); + let (w2, carry) = mac(w2, q1[1], MU[1], carry); + let (w3, carry) = mac(w3, q1[1], MU[2], carry); + let (w4, carry) = mac(w4, q1[1], MU[3], carry); + let (w5, w6) = mac(w5, q1[1], MU[4], carry); + + let (_w2, carry) = mac(w2, q1[2], MU[0], 0); + let (w3, carry) = mac(w3, q1[2], MU[1], carry); + let (w4, carry) = mac(w4, q1[2], MU[2], carry); + let (w5, carry) = mac(w5, q1[2], MU[3], carry); + let (w6, w7) = mac(w6, q1[2], MU[4], carry); + + let (_w3, carry) = mac(w3, q1[3], MU[0], 0); + let (w4, carry) = mac(w4, q1[3], MU[1], carry); + let (w5, carry) = mac(w5, q1[3], MU[2], carry); + let (w6, carry) = mac(w6, q1[3], MU[3], carry); + let (w7, w8) = mac(w7, q1[3], MU[4], carry); + + let (_w4, carry) = mac(w4, q1[4], MU[0], 0); + let (w5, carry) = mac(w5, q1[4], MU[1], carry); + let (w6, carry) = mac(w6, q1[4], MU[2], carry); + let (w7, carry) = mac(w7, q1[4], MU[3], carry); + let (w8, w9) = mac(w8, q1[4], MU[4], carry); + + // let q2 = [_w0, _w1, _w2, _w3, _w4, w5, w6, w7, w8, w9]; + [w5, w6, w7, w8, w9] +} + +const fn q3_times_n_keep_five(q3: &[u64; 5]) -> [u64; 5] { + // Schoolbook multiplication. + + let modulus = MODULUS.as_words(); + + let (w0, carry) = mac(0, q3[0], modulus[0], 0); + let (w1, carry) = mac(0, q3[0], modulus[1], carry); + let (w2, carry) = mac(0, q3[0], modulus[2], carry); + let (w3, carry) = mac(0, q3[0], modulus[3], carry); + let (w4, _) = mac(0, q3[0], 0, carry); + + let (w1, carry) = mac(w1, q3[1], modulus[0], 0); + let (w2, carry) = mac(w2, q3[1], modulus[1], carry); + let (w3, carry) = mac(w3, q3[1], modulus[2], carry); + let (w4, _) = mac(w4, q3[1], modulus[3], carry); + + let (w2, carry) = mac(w2, q3[2], modulus[0], 0); + let (w3, carry) = mac(w3, q3[2], modulus[1], carry); + let (w4, _) = mac(w4, q3[2], modulus[2], carry); + + let (w3, carry) = mac(w3, q3[3], modulus[0], 0); + let (w4, _) = mac(w4, q3[3], modulus[1], carry); + + let (w4, _) = mac(w4, q3[4], modulus[0], 0); + + [w0, w1, w2, w3, w4] +} + +#[inline] +#[allow(clippy::too_many_arguments)] +const fn sub_inner_five(l: [u64; 5], r: [u64; 5]) -> [u64; 5] { + let (w0, borrow) = sbb(l[0], r[0], 0); + let (w1, borrow) = sbb(l[1], r[1], borrow); + let (w2, borrow) = sbb(l[2], r[2], borrow); + let (w3, borrow) = sbb(l[3], r[3], borrow); + let (w4, _borrow) = sbb(l[4], r[4], borrow); + + // If underflow occurred on the final limb - don't care (= add b^{k+1}). + [w0, w1, w2, w3, w4] +} + +#[inline] +#[allow(clippy::too_many_arguments)] +const fn subtract_n_if_necessary(r0: u64, r1: u64, r2: u64, r3: u64, r4: u64) -> [u64; 5] { + let modulus = MODULUS.as_words(); + + let (w0, borrow) = sbb(r0, modulus[0], 0); + let (w1, borrow) = sbb(r1, modulus[1], borrow); + let (w2, borrow) = sbb(r2, modulus[2], borrow); + let (w3, borrow) = sbb(r3, modulus[3], borrow); + let (w4, borrow) = sbb(r4, 0, borrow); + + // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise + // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the + // modulus. + let (w0, carry) = adc(w0, modulus[0] & borrow, 0); + let (w1, carry) = adc(w1, modulus[1] & borrow, carry); + let (w2, carry) = adc(w2, modulus[2] & borrow, carry); + let (w3, carry) = adc(w3, modulus[3] & borrow, carry); + let (w4, _carry) = adc(w4, 0, carry); + + [w0, w1, w2, w3, w4] +} diff --git a/src/rust/vendor/p256/src/arithmetic/util.rs b/src/rust/vendor/p256/src/arithmetic/util.rs new file mode 100644 index 000000000..9be7651d0 --- /dev/null +++ b/src/rust/vendor/p256/src/arithmetic/util.rs @@ -0,0 +1,23 @@ +//! Helper functions. +// TODO(tarcieri): replace these with `crypto-bigint` + +/// Computes `a + b + carry`, returning the result along with the new carry. 64-bit version. +#[inline(always)] +pub const fn adc(a: u64, b: u64, carry: u64) -> (u64, u64) { + let ret = (a as u128) + (b as u128) + (carry as u128); + (ret as u64, (ret >> 64) as u64) +} + +/// Computes `a - (b + borrow)`, returning the result along with the new borrow. 64-bit version. +#[inline(always)] +pub const fn sbb(a: u64, b: u64, borrow: u64) -> (u64, u64) { + let ret = (a as u128).wrapping_sub((b as u128) + ((borrow >> 63) as u128)); + (ret as u64, (ret >> 64) as u64) +} + +/// Computes `a + (b * c) + carry`, returning the result along with the new carry. +#[inline(always)] +pub const fn mac(a: u64, b: u64, c: u64, carry: u64) -> (u64, u64) { + let ret = (a as u128) + ((b as u128) * (c as u128)) + (carry as u128); + (ret as u64, (ret >> 64) as u64) +} diff --git a/src/rust/vendor/p256/src/ecdh.rs b/src/rust/vendor/p256/src/ecdh.rs new file mode 100644 index 000000000..ab408dd8e --- /dev/null +++ b/src/rust/vendor/p256/src/ecdh.rs @@ -0,0 +1,47 @@ +//! Elliptic Curve Diffie-Hellman (Ephemeral) Support. +//! +//! This module contains a high-level interface for performing ephemeral +//! Diffie-Hellman key exchanges using the secp256r1 elliptic curve. +//! +//! # Usage +//! +//! This usage example is from the perspective of two participants in the +//! exchange, nicknamed "Alice" and "Bob". +//! +//! ``` +//! use p256::{EncodedPoint, PublicKey, ecdh::EphemeralSecret}; +//! use rand_core::OsRng; // requires 'getrandom' feature +//! +//! // Alice +//! let alice_secret = EphemeralSecret::random(&mut OsRng); +//! let alice_pk_bytes = EncodedPoint::from(alice_secret.public_key()); +//! +//! // Bob +//! let bob_secret = EphemeralSecret::random(&mut OsRng); +//! let bob_pk_bytes = EncodedPoint::from(bob_secret.public_key()); +//! +//! // Alice decodes Bob's serialized public key and computes a shared secret from it +//! let bob_public = PublicKey::from_sec1_bytes(bob_pk_bytes.as_ref()) +//! .expect("bob's public key is invalid!"); // In real usage, don't panic, handle this! +//! +//! let alice_shared = alice_secret.diffie_hellman(&bob_public); +//! +//! // Bob decodes Alice's serialized public key and computes the same shared secret +//! let alice_public = PublicKey::from_sec1_bytes(alice_pk_bytes.as_ref()) +//! .expect("alice's public key is invalid!"); // In real usage, don't panic, handle this! +//! +//! let bob_shared = bob_secret.diffie_hellman(&alice_public); +//! +//! // Both participants arrive on the same shared secret +//! assert_eq!(alice_shared.raw_secret_bytes(), bob_shared.raw_secret_bytes()); +//! ``` + +pub use elliptic_curve::ecdh::diffie_hellman; + +use crate::NistP256; + +/// NIST P-256 Ephemeral Diffie-Hellman Secret. +pub type EphemeralSecret = elliptic_curve::ecdh::EphemeralSecret; + +/// Shared secret value computed via ECDH key agreement. +pub type SharedSecret = elliptic_curve::ecdh::SharedSecret; diff --git a/src/rust/vendor/p256/src/ecdsa.rs b/src/rust/vendor/p256/src/ecdsa.rs new file mode 100644 index 000000000..e5cf3d44d --- /dev/null +++ b/src/rust/vendor/p256/src/ecdsa.rs @@ -0,0 +1,198 @@ +//! Elliptic Curve Digital Signature Algorithm (ECDSA) +//! +//! This module contains support for computing and verifying ECDSA signatures. +//! To use it, you will need to enable one of the two following Cargo features: +//! +//! - `ecdsa-core`: provides only the [`Signature`] type (which represents an +//! ECDSA/P-256 signature). Does not require the `arithmetic` feature. +//! This is useful for 3rd-party crates which wish to use the `Signature` +//! type for interoperability purposes (particularly in conjunction with the +//! [`signature::Signer`] trait. Example use cases for this include other +//! software implementations of ECDSA/P-256 and wrappers for cloud KMS +//! services or hardware devices (HSM or crypto hardware wallet). +//! - `ecdsa`: provides `ecdsa-core` features plus the [`SigningKey`] and +//! [`VerifyingKey`] types which natively implement ECDSA/P-256 signing and +//! verification. +//! +//! ## Signing/Verification Example +//! +//! This example requires the `ecdsa` Cargo feature is enabled: +//! +//! ``` +//! # #[cfg(feature = "ecdsa")] +//! # { +//! use p256::{ +//! ecdsa::{SigningKey, Signature, signature::Signer}, +//! }; +//! use rand_core::OsRng; // requires 'getrandom' feature +//! +//! // Signing +//! let signing_key = SigningKey::random(&mut OsRng); // Serialize with `::to_bytes()` +//! let message = b"ECDSA proves knowledge of a secret number in the context of a single message"; +//! let signature: Signature = signing_key.sign(message); +//! +//! // Verification +//! use p256::ecdsa::{VerifyingKey, signature::Verifier}; +//! +//! let verifying_key = VerifyingKey::from(&signing_key); // Serialize with `::to_encoded_point()` +//! assert!(verifying_key.verify(message, &signature).is_ok()); +//! # } +//! ``` + +pub use ecdsa_core::signature::{self, Error}; + +use super::NistP256; + +#[cfg(feature = "ecdsa")] +use { + crate::{AffinePoint, Scalar}, + ecdsa_core::hazmat::{SignPrimitive, VerifyPrimitive}, +}; + +/// ECDSA/P-256 signature (fixed-size) +pub type Signature = ecdsa_core::Signature; + +/// ECDSA/P-256 signature (ASN.1 DER encoded) +pub type DerSignature = ecdsa_core::der::Signature; + +/// ECDSA/P-256 signing key +#[cfg(feature = "ecdsa")] +pub type SigningKey = ecdsa_core::SigningKey; + +/// ECDSA/P-256 verification key (i.e. public key) +#[cfg(feature = "ecdsa")] +pub type VerifyingKey = ecdsa_core::VerifyingKey; + +#[cfg(feature = "sha256")] +impl ecdsa_core::hazmat::DigestPrimitive for NistP256 { + type Digest = sha2::Sha256; +} + +#[cfg(feature = "ecdsa")] +impl SignPrimitive for Scalar {} + +#[cfg(feature = "ecdsa")] +impl VerifyPrimitive for AffinePoint {} + +#[cfg(all(test, feature = "ecdsa"))] +mod tests { + use crate::{ + ecdsa::{ + signature::hazmat::{PrehashSigner, PrehashVerifier}, + signature::Signer, + Signature, SigningKey, VerifyingKey, + }, + test_vectors::ecdsa::ECDSA_TEST_VECTORS, + AffinePoint, BlindedScalar, EncodedPoint, Scalar, + }; + use ecdsa_core::hazmat::SignPrimitive; + use elliptic_curve::{ + generic_array::GenericArray, group::ff::PrimeField, rand_core::OsRng, + sec1::FromEncodedPoint, + }; + use hex_literal::hex; + use sha2::Digest; + + // Test vector from RFC 6979 Appendix 2.5 (NIST P-256 + SHA-256) + // + #[test] + fn rfc6979() { + let x = hex!("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); + let signer = SigningKey::from_bytes(&x.into()).unwrap(); + let signature: Signature = signer.sign(b"sample"); + assert_eq!( + signature.to_bytes().as_slice(), + &hex!( + "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716 + f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8" + ) + ); + let signature: Signature = signer.sign(b"test"); + assert_eq!( + signature.to_bytes().as_slice(), + &hex!( + "f1abb023518351cd71d881567b1ea663ed3efcf6c5132b354f28d3b0b7d38367 + 019f4113742a2b14bd25926b49c649155f267e60d3814b4c0cc84250e46f0083" + ) + ); + } + + // Test signing with PrehashSigner using SHA-384 which output is larger than P-256 field size. + #[test] + fn prehash_signer_signing_with_sha384() { + let x = hex!("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); + let signer = SigningKey::from_bytes(&x.into()).unwrap(); + let digest = sha2::Sha384::digest(b"test"); + let signature: Signature = signer.sign_prehash(&digest).unwrap(); + assert_eq!( + signature.to_bytes().as_slice(), + &hex!( + "ebde85f1539af67e70dd7a8a6afeeb332aa7f08f01ebb6ab6e04e2a62d2fef75 + 871af45800daddf55619b005a601a7a84f544260f1d2625b2ef5aa7a4f4dd76f" + ) + ); + } + + // Test verifying with PrehashVerifier using SHA-256 which output is larger than P-256 field size. + #[test] + fn prehash_signer_verification_with_sha384() { + // The following test vector adapted from the FIPS 186-4 ECDSA test vectors + // (P-256, SHA-384, from `SigGen.txt` in `186-4ecdsatestvectors.zip`) + // + let verifier = VerifyingKey::from_affine( + AffinePoint::from_encoded_point(&EncodedPoint::from_affine_coordinates( + GenericArray::from_slice(&hex!( + "e0e7b99bc62d8dd67883e39ed9fa0657789c5ff556cc1fd8dd1e2a55e9e3f243" + )), + GenericArray::from_slice(&hex!( + "63fbfd0232b95578075c903a4dbf85ad58f8350516e1ec89b0ee1f5e1362da69" + )), + false, + )) + .unwrap(), + ) + .unwrap(); + let signature = Signature::from_scalars( + GenericArray::clone_from_slice(&hex!( + "f5087878e212b703578f5c66f434883f3ef414dc23e2e8d8ab6a8d159ed5ad83" + )), + GenericArray::clone_from_slice(&hex!( + "306b4c6c20213707982dffbb30fba99b96e792163dd59dbe606e734328dd7c8a" + )), + ) + .unwrap(); + let result = verifier.verify_prehash( + &hex!("d9c83b92fa0979f4a5ddbd8dd22ab9377801c3c31bf50f932ace0d2146e2574da0d5552dbed4b18836280e9f94558ea6"), + &signature, + ); + assert!(result.is_ok()); + } + + #[test] + fn scalar_blinding() { + let vector = &ECDSA_TEST_VECTORS[0]; + let d = Scalar::from_repr(GenericArray::clone_from_slice(vector.d)).unwrap(); + let k = Scalar::from_repr(GenericArray::clone_from_slice(vector.k)).unwrap(); + let k_blinded = BlindedScalar::new(k, &mut OsRng); + let z = GenericArray::clone_from_slice(vector.m); + let sig = d.try_sign_prehashed(k_blinded, &z).unwrap().0; + + assert_eq!(vector.r, sig.r().to_bytes().as_slice()); + assert_eq!(vector.s, sig.s().to_bytes().as_slice()); + } + + mod sign { + use crate::{test_vectors::ecdsa::ECDSA_TEST_VECTORS, NistP256}; + ecdsa_core::new_signing_test!(NistP256, ECDSA_TEST_VECTORS); + } + + mod verify { + use crate::{test_vectors::ecdsa::ECDSA_TEST_VECTORS, NistP256}; + ecdsa_core::new_verification_test!(NistP256, ECDSA_TEST_VECTORS); + } + + mod wycheproof { + use crate::NistP256; + ecdsa_core::new_wycheproof_test!(wycheproof, "wycheproof", NistP256); + } +} diff --git a/src/rust/vendor/p256/src/lib.rs b/src/rust/vendor/p256/src/lib.rs new file mode 100644 index 000000000..656d23298 --- /dev/null +++ b/src/rust/vendor/p256/src/lib.rs @@ -0,0 +1,183 @@ +#![no_std] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![doc = include_str!("../README.md")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" +)] +#![forbid(unsafe_code)] +#![warn( + clippy::mod_module_files, + clippy::unwrap_used, + missing_docs, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] + +//! ## `serde` support +//! +//! When the `serde` feature of this crate is enabled, `Serialize` and +//! `Deserialize` are impl'd for the following types: +//! +//! - [`AffinePoint`] +//! - [`Scalar`] +//! - [`ecdsa::VerifyingKey`] +//! +//! Please see type-specific documentation for more information. + +#[cfg(feature = "arithmetic")] +mod arithmetic; + +#[cfg(feature = "ecdh")] +pub mod ecdh; + +#[cfg(feature = "ecdsa-core")] +pub mod ecdsa; + +#[cfg(any(feature = "test-vectors", test))] +pub mod test_vectors; + +pub use elliptic_curve::{self, bigint::U256, consts::U32}; + +#[cfg(feature = "arithmetic")] +pub use arithmetic::{scalar::Scalar, AffinePoint, ProjectivePoint}; + +#[cfg(feature = "expose-field")] +pub use arithmetic::field::FieldElement; + +#[cfg(feature = "pkcs8")] +pub use elliptic_curve::pkcs8; + +use elliptic_curve::{ + bigint::ArrayEncoding, consts::U33, generic_array::GenericArray, FieldBytesEncoding, +}; + +/// Order of NIST P-256's elliptic curve group (i.e. scalar modulus) serialized +/// as hexadecimal. +/// +/// ```text +/// n = FFFFFFFF 00000000 FFFFFFFF FFFFFFFF BCE6FAAD A7179E84 F3B9CAC2 FC632551 +/// ``` +/// +/// # Calculating the order +/// One way to calculate the order is with `GP/PARI`: +/// +/// ```text +/// p = (2^224) * (2^32 - 1) + 2^192 + 2^96 - 1 +/// b = 41058363725152142129326129780047268409114441015993725554835256314039467401291 +/// E = ellinit([Mod(-3, p), Mod(b, p)]) +/// default(parisize, 120000000) +/// n = ellsea(E) +/// isprime(n) +/// ``` +const ORDER_HEX: &str = "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"; + +/// NIST P-256 elliptic curve. +/// +/// This curve is also known as prime256v1 (ANSI X9.62) and secp256r1 (SECG) +/// and is specified in [NIST SP 800-186]: +/// Recommendations for Discrete Logarithm-based Cryptography: +/// Elliptic Curve Domain Parameters. +/// +/// It's included in the US National Security Agency's "Suite B" and is widely +/// used in protocols like TLS and the associated X.509 PKI. +/// +/// Its equation is `y² = x³ - 3x + b` over a ~256-bit prime field where `b` is +/// the "verifiably random"† constant: +/// +/// ```text +/// b = 41058363725152142129326129780047268409114441015993725554835256314039467401291 +/// ``` +/// +/// † *NOTE: the specific origins of this constant have never been fully disclosed +/// (it is the SHA-1 digest of an unknown NSA-selected constant)* +/// +/// [NIST SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] +pub struct NistP256; + +impl elliptic_curve::Curve for NistP256 { + /// 32-byte serialized field elements. + type FieldBytesSize = U32; + + /// 256-bit integer type used for internally representing field elements. + type Uint = U256; + + /// Order of NIST P-256's elliptic curve group (i.e. scalar modulus). + const ORDER: U256 = U256::from_be_hex(ORDER_HEX); +} + +impl elliptic_curve::PrimeCurve for NistP256 {} + +impl elliptic_curve::point::PointCompression for NistP256 { + /// NIST P-256 points are typically uncompressed. + const COMPRESS_POINTS: bool = false; +} + +impl elliptic_curve::point::PointCompaction for NistP256 { + /// NIST P-256 points are typically uncompressed. + const COMPACT_POINTS: bool = false; +} + +#[cfg(feature = "jwk")] +impl elliptic_curve::JwkParameters for NistP256 { + const CRV: &'static str = "P-256"; +} + +#[cfg(feature = "pkcs8")] +impl pkcs8::AssociatedOid for NistP256 { + const OID: pkcs8::ObjectIdentifier = pkcs8::ObjectIdentifier::new_unwrap("1.2.840.10045.3.1.7"); +} + +/// Blinded scalar. +#[cfg(feature = "arithmetic")] +pub type BlindedScalar = elliptic_curve::scalar::BlindedScalar; + +/// Compressed SEC1-encoded NIST P-256 curve point. +pub type CompressedPoint = GenericArray; + +/// NIST P-256 SEC1 encoded point. +pub type EncodedPoint = elliptic_curve::sec1::EncodedPoint; + +/// NIST P-256 field element serialized as bytes. +/// +/// Byte array containing a serialized field element value (base field or scalar). +pub type FieldBytes = elliptic_curve::FieldBytes; + +impl FieldBytesEncoding for U256 { + fn decode_field_bytes(field_bytes: &FieldBytes) -> Self { + U256::from_be_byte_array(*field_bytes) + } + + fn encode_field_bytes(&self) -> FieldBytes { + self.to_be_byte_array() + } +} + +/// Non-zero NIST P-256 scalar field element. +#[cfg(feature = "arithmetic")] +pub type NonZeroScalar = elliptic_curve::NonZeroScalar; + +/// NIST P-256 public key. +#[cfg(feature = "arithmetic")] +pub type PublicKey = elliptic_curve::PublicKey; + +/// NIST P-256 secret key. +pub type SecretKey = elliptic_curve::SecretKey; + +#[cfg(not(feature = "arithmetic"))] +impl elliptic_curve::sec1::ValidatePublicKey for NistP256 {} + +/// Bit representation of a NIST P-256 scalar field element. +#[cfg(feature = "bits")] +pub type ScalarBits = elliptic_curve::scalar::ScalarBits; + +#[cfg(feature = "voprf")] +impl elliptic_curve::VoprfParameters for NistP256 { + /// See . + const ID: &'static str = "P256-SHA256"; + + /// See . + type Hash = sha2::Sha256; +} diff --git a/src/rust/vendor/p256/src/test_vectors.rs b/src/rust/vendor/p256/src/test_vectors.rs new file mode 100644 index 000000000..b2e5af3a0 --- /dev/null +++ b/src/rust/vendor/p256/src/test_vectors.rs @@ -0,0 +1,6 @@ +//! secp256r1 test vectors. + +#[cfg(test)] +pub mod ecdsa; +pub mod field; +pub mod group; diff --git a/src/rust/vendor/p256/src/test_vectors/data/wycheproof.blb b/src/rust/vendor/p256/src/test_vectors/data/wycheproof.blb new file mode 100644 index 000000000..625438fdd Binary files /dev/null and b/src/rust/vendor/p256/src/test_vectors/data/wycheproof.blb differ diff --git a/src/rust/vendor/p256/src/test_vectors/ecdsa.rs b/src/rust/vendor/p256/src/test_vectors/ecdsa.rs new file mode 100644 index 000000000..aa3d53853 --- /dev/null +++ b/src/rust/vendor/p256/src/test_vectors/ecdsa.rs @@ -0,0 +1,150 @@ +//! ECDSA/secp256r1 test vectors + +use ecdsa_core::dev::TestVector; +use hex_literal::hex; + +/// ECDSA/P-256 test vectors. +/// +/// Adapted from the FIPS 186-4 ECDSA test vectors +/// (P-256, SHA-256, from `SigGen.txt` in `186-4ecdsatestvectors.zip`) +/// +/// +/// The `m` field contains a SHA-256 prehash of the `Msg` field in the +/// original `SigTen.txt`. +pub const ECDSA_TEST_VECTORS: &[TestVector] = &[ + TestVector { + d: &hex!("519b423d715f8b581f4fa8ee59f4771a5b44c8130b4e3eacca54a56dda72b464"), + q_x: &hex!("1ccbe91c075fc7f4f033bfa248db8fccd3565de94bbfb12f3c59ff46c271bf83"), + q_y: &hex!("ce4014c68811f9a21a1fdb2c0e6113e06db7ca93b7404e78dc7ccd5ca89a4ca9"), + k: &hex!("94a1bbb14b906a61a280f245f9e93c7f3b4a6247824f5d33b9670787642a68de"), + m: &hex!("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"), + r: &hex!("f3ac8061b514795b8843e3d6629527ed2afd6b1f6a555a7acabb5e6f79c8c2ac"), + s: &hex!("8bf77819ca05a6b2786c76262bf7371cef97b218e96f175a3ccdda2acc058903"), + }, + TestVector { + d: &hex!("0f56db78ca460b055c500064824bed999a25aaf48ebb519ac201537b85479813"), + q_x: &hex!("e266ddfdc12668db30d4ca3e8f7749432c416044f2d2b8c10bf3d4012aeffa8a"), + q_y: &hex!("bfa86404a2e9ffe67d47c587ef7a97a7f456b863b4d02cfc6928973ab5b1cb39"), + k: &hex!("6d3e71882c3b83b156bb14e0ab184aa9fb728068d3ae9fac421187ae0b2f34c6"), + m: &hex!("9b2db89cb0e8fa3cc7608b4d6cc1dec0114e0b9ff4080bea12b134f489ab2bbc"), + r: &hex!("976d3a4e9d23326dc0baa9fa560b7c4e53f42864f508483a6473b6a11079b2db"), + s: &hex!("1b766e9ceb71ba6c01dcd46e0af462cd4cfa652ae5017d4555b8eeefe36e1932"), + }, + TestVector { + d: &hex!("e283871239837e13b95f789e6e1af63bf61c918c992e62bca040d64cad1fc2ef"), + q_x: &hex!("74ccd8a62fba0e667c50929a53f78c21b8ff0c3c737b0b40b1750b2302b0bde8"), + q_y: &hex!("29074e21f3a0ef88b9efdf10d06aa4c295cc1671f758ca0e4cd108803d0f2614"), + k: &hex!("ad5e887eb2b380b8d8280ad6e5ff8a60f4d26243e0124c2f31a297b5d0835de2"), + m: &hex!("b804cf88af0c2eff8bbbfb3660ebb3294138e9d3ebd458884e19818061dacff0"), + r: &hex!("35fb60f5ca0f3ca08542fb3cc641c8263a2cab7a90ee6a5e1583fac2bb6f6bd1"), + s: &hex!("ee59d81bc9db1055cc0ed97b159d8784af04e98511d0a9a407b99bb292572e96"), + }, + TestVector { + d: &hex!("a3d2d3b7596f6592ce98b4bfe10d41837f10027a90d7bb75349490018cf72d07"), + q_x: &hex!("322f80371bf6e044bc49391d97c1714ab87f990b949bc178cb7c43b7c22d89e1"), + q_y: &hex!("3c15d54a5cc6b9f09de8457e873eb3deb1fceb54b0b295da6050294fae7fd999"), + k: &hex!("24fc90e1da13f17ef9fe84cc96b9471ed1aaac17e3a4bae33a115df4e5834f18"), + m: &hex!("85b957d92766235e7c880ac5447cfbe97f3cb499f486d1e43bcb5c2ff9608a1a"), + r: &hex!("d7c562370af617b581c84a2468cc8bd50bb1cbf322de41b7887ce07c0e5884ca"), + s: &hex!("b46d9f2d8c4bf83546ff178f1d78937c008d64e8ecc5cbb825cb21d94d670d89"), + }, + TestVector { + d: &hex!("53a0e8a8fe93db01e7ae94e1a9882a102ebd079b3a535827d583626c272d280d"), + q_x: &hex!("1bcec4570e1ec2436596b8ded58f60c3b1ebc6a403bc5543040ba82963057244"), + q_y: &hex!("8af62a4c683f096b28558320737bf83b9959a46ad2521004ef74cf85e67494e1"), + k: &hex!("5d833e8d24cc7a402d7ee7ec852a3587cddeb48358cea71b0bedb8fabe84e0c4"), + m: &hex!("3360d699222f21840827cf698d7cb635bee57dc80cd7733b682d41b55b666e22"), + r: &hex!("18caaf7b663507a8bcd992b836dec9dc5703c080af5e51dfa3a9a7c387182604"), + s: &hex!("77c68928ac3b88d985fb43fb615fb7ff45c18ba5c81af796c613dfa98352d29c"), + }, + TestVector { + d: &hex!("4af107e8e2194c830ffb712a65511bc9186a133007855b49ab4b3833aefc4a1d"), + q_x: &hex!("a32e50be3dae2c8ba3f5e4bdae14cf7645420d425ead94036c22dd6c4fc59e00"), + q_y: &hex!("d623bf641160c289d6742c6257ae6ba574446dd1d0e74db3aaa80900b78d4ae9"), + k: &hex!("e18f96f84dfa2fd3cdfaec9159d4c338cd54ad314134f0b31e20591fc238d0ab"), + m: &hex!("c413c4908cd0bc6d8e32001aa103043b2cf5be7fcbd61a5cec9488c3a577ca57"), + r: &hex!("8524c5024e2d9a73bde8c72d9129f57873bbad0ed05215a372a84fdbc78f2e68"), + s: &hex!("d18c2caf3b1072f87064ec5e8953f51301cada03469c640244760328eb5a05cb"), + }, + TestVector { + d: &hex!("78dfaa09f1076850b3e206e477494cddcfb822aaa0128475053592c48ebaf4ab"), + q_x: &hex!("8bcfe2a721ca6d753968f564ec4315be4857e28bef1908f61a366b1f03c97479"), + q_y: &hex!("0f67576a30b8e20d4232d8530b52fb4c89cbc589ede291e499ddd15fe870ab96"), + k: &hex!("295544dbb2da3da170741c9b2c6551d40af7ed4e891445f11a02b66a5c258a77"), + m: &hex!("88fc1e7d849794fc51b135fa135deec0db02b86c3cd8cebdaa79e8689e5b2898"), + r: &hex!("c5a186d72df452015480f7f338970bfe825087f05c0088d95305f87aacc9b254"), + s: &hex!("84a58f9e9d9e735344b316b1aa1ab5185665b85147dc82d92e969d7bee31ca30"), + }, + TestVector { + d: &hex!("80e692e3eb9fcd8c7d44e7de9f7a5952686407f90025a1d87e52c7096a62618a"), + q_x: &hex!("a88bc8430279c8c0400a77d751f26c0abc93e5de4ad9a4166357952fe041e767"), + q_y: &hex!("2d365a1eef25ead579cc9a069b6abc1b16b81c35f18785ce26a10ba6d1381185"), + k: &hex!("7c80fd66d62cc076cef2d030c17c0a69c99611549cb32c4ff662475adbe84b22"), + m: &hex!("41fa8d8b4cd0a5fdf021f4e4829d6d1e996bab6b4a19dcb85585fe76c582d2bc"), + r: &hex!("9d0c6afb6df3bced455b459cc21387e14929392664bb8741a3693a1795ca6902"), + s: &hex!("d7f9ddd191f1f412869429209ee3814c75c72fa46a9cccf804a2f5cc0b7e739f"), + }, + TestVector { + d: &hex!("5e666c0db0214c3b627a8e48541cc84a8b6fd15f300da4dff5d18aec6c55b881"), + q_x: &hex!("1bc487570f040dc94196c9befe8ab2b6de77208b1f38bdaae28f9645c4d2bc3a"), + q_y: &hex!("ec81602abd8345e71867c8210313737865b8aa186851e1b48eaca140320f5d8f"), + k: &hex!("2e7625a48874d86c9e467f890aaa7cd6ebdf71c0102bfdcfa24565d6af3fdce9"), + m: &hex!("2d72947c1731543b3d62490866a893952736757746d9bae13e719079299ae192"), + r: &hex!("2f9e2b4e9f747c657f705bffd124ee178bbc5391c86d056717b140c153570fd9"), + s: &hex!("f5413bfd85949da8d83de83ab0d19b2986613e224d1901d76919de23ccd03199"), + }, + TestVector { + d: &hex!("f73f455271c877c4d5334627e37c278f68d143014b0a05aa62f308b2101c5308"), + q_x: &hex!("b8188bd68701fc396dab53125d4d28ea33a91daf6d21485f4770f6ea8c565dde"), + q_y: &hex!("423f058810f277f8fe076f6db56e9285a1bf2c2a1dae145095edd9c04970bc4a"), + k: &hex!("62f8665fd6e26b3fa069e85281777a9b1f0dfd2c0b9f54a086d0c109ff9fd615"), + m: &hex!("e138bd577c3729d0e24a98a82478bcc7482499c4cdf734a874f7208ddbc3c116"), + r: &hex!("1cc628533d0004b2b20e7f4baad0b8bb5e0673db159bbccf92491aef61fc9620"), + s: &hex!("880e0bbf82a8cf818ed46ba03cf0fc6c898e36fca36cc7fdb1d2db7503634430"), + }, + TestVector { + d: &hex!("b20d705d9bd7c2b8dc60393a5357f632990e599a0975573ac67fd89b49187906"), + q_x: &hex!("51f99d2d52d4a6e734484a018b7ca2f895c2929b6754a3a03224d07ae61166ce"), + q_y: &hex!("4737da963c6ef7247fb88d19f9b0c667cac7fe12837fdab88c66f10d3c14cad1"), + k: &hex!("72b656f6b35b9ccbc712c9f1f3b1a14cbbebaec41c4bca8da18f492a062d6f6f"), + m: &hex!("17b03f9f00f6692ccdde485fc63c4530751ef35da6f71336610944b0894fcfb8"), + r: &hex!("9886ae46c1415c3bc959e82b760ad760aab66885a84e620aa339fdf102465c42"), + s: &hex!("2bf3a80bc04faa35ebecc0f4864ac02d349f6f126e0f988501b8d3075409a26c"), + }, + TestVector { + d: &hex!("d4234bebfbc821050341a37e1240efe5e33763cbbb2ef76a1c79e24724e5a5e7"), + q_x: &hex!("8fb287f0202ad57ae841aea35f29b2e1d53e196d0ddd9aec24813d64c0922fb7"), + q_y: &hex!("1f6daff1aa2dd2d6d3741623eecb5e7b612997a1039aab2e5cf2de969cfea573"), + k: &hex!("d926fe10f1bfd9855610f4f5a3d666b1a149344057e35537373372ead8b1a778"), + m: &hex!("c25beae638ff8dcd370e03a6f89c594c55bed1277ee14d83bbb0ef783a0517c7"), + r: &hex!("490efd106be11fc365c7467eb89b8d39e15d65175356775deab211163c2504cb"), + s: &hex!("644300fc0da4d40fb8c6ead510d14f0bd4e1321a469e9c0a581464c7186b7aa7"), + }, + TestVector { + d: &hex!("b58f5211dff440626bb56d0ad483193d606cf21f36d9830543327292f4d25d8c"), + q_x: &hex!("68229b48c2fe19d3db034e4c15077eb7471a66031f28a980821873915298ba76"), + q_y: &hex!("303e8ee3742a893f78b810991da697083dd8f11128c47651c27a56740a80c24c"), + k: &hex!("e158bf4a2d19a99149d9cdb879294ccb7aaeae03d75ddd616ef8ae51a6dc1071"), + m: &hex!("5eb28029ebf3c7025ff2fc2f6de6f62aecf6a72139e1cba5f20d11bbef036a7f"), + r: &hex!("e67a9717ccf96841489d6541f4f6adb12d17b59a6bef847b6183b8fcf16a32eb"), + s: &hex!("9ae6ba6d637706849a6a9fc388cf0232d85c26ea0d1fe7437adb48de58364333"), + }, + TestVector { + d: &hex!("54c066711cdb061eda07e5275f7e95a9962c6764b84f6f1f3ab5a588e0a2afb1"), + q_x: &hex!("0a7dbb8bf50cb605eb2268b081f26d6b08e012f952c4b70a5a1e6e7d46af98bb"), + q_y: &hex!("f26dd7d799930062480849962ccf5004edcfd307c044f4e8f667c9baa834eeae"), + k: &hex!("646fe933e96c3b8f9f507498e907fdd201f08478d0202c752a7c2cfebf4d061a"), + m: &hex!("12135386c09e0bf6fd5c454a95bcfe9b3edb25c71e455c73a212405694b29002"), + r: &hex!("b53ce4da1aa7c0dc77a1896ab716b921499aed78df725b1504aba1597ba0c64b"), + s: &hex!("d7c246dc7ad0e67700c373edcfdd1c0a0495fc954549ad579df6ed1438840851"), + }, + TestVector { + d: &hex!("34fa4682bf6cb5b16783adcd18f0e6879b92185f76d7c920409f904f522db4b1"), + q_x: &hex!("105d22d9c626520faca13e7ced382dcbe93498315f00cc0ac39c4821d0d73737"), + q_y: &hex!("6c47f3cbbfa97dfcebe16270b8c7d5d3a5900b888c42520d751e8faf3b401ef4"), + k: &hex!("a6f463ee72c9492bc792fe98163112837aebd07bab7a84aaed05be64db3086f4"), + m: &hex!("aea3e069e03c0ff4d6b3fa2235e0053bbedc4c7e40efbc686d4dfb5efba4cfed"), + r: &hex!("542c40a18140a6266d6f0286e24e9a7bad7650e72ef0e2131e629c076d962663"), + s: &hex!("4f7f65305e24a6bbb5cff714ba8f5a2cee5bdc89ba8d75dcbf21966ce38eb66f"), + }, +]; diff --git a/src/rust/vendor/p256/src/test_vectors/field.rs b/src/rust/vendor/p256/src/test_vectors/field.rs new file mode 100644 index 000000000..deccfee85 --- /dev/null +++ b/src/rust/vendor/p256/src/test_vectors/field.rs @@ -0,0 +1,257 @@ +//! Test vectors for the secp256r1 base field. + +use hex_literal::hex; + +/// Repeated doubling of the multiplicative identity. +pub const DBL_TEST_VECTORS: &[[u8; 32]] = &[ + hex!("0000000000000000000000000000000000000000000000000000000000000001"), + hex!("0000000000000000000000000000000000000000000000000000000000000002"), + hex!("0000000000000000000000000000000000000000000000000000000000000004"), + hex!("0000000000000000000000000000000000000000000000000000000000000008"), + hex!("0000000000000000000000000000000000000000000000000000000000000010"), + hex!("0000000000000000000000000000000000000000000000000000000000000020"), + hex!("0000000000000000000000000000000000000000000000000000000000000040"), + hex!("0000000000000000000000000000000000000000000000000000000000000080"), + hex!("0000000000000000000000000000000000000000000000000000000000000100"), + hex!("0000000000000000000000000000000000000000000000000000000000000200"), + hex!("0000000000000000000000000000000000000000000000000000000000000400"), + hex!("0000000000000000000000000000000000000000000000000000000000000800"), + hex!("0000000000000000000000000000000000000000000000000000000000001000"), + hex!("0000000000000000000000000000000000000000000000000000000000002000"), + hex!("0000000000000000000000000000000000000000000000000000000000004000"), + hex!("0000000000000000000000000000000000000000000000000000000000008000"), + hex!("0000000000000000000000000000000000000000000000000000000000010000"), + hex!("0000000000000000000000000000000000000000000000000000000000020000"), + hex!("0000000000000000000000000000000000000000000000000000000000040000"), + hex!("0000000000000000000000000000000000000000000000000000000000080000"), + hex!("0000000000000000000000000000000000000000000000000000000000100000"), + hex!("0000000000000000000000000000000000000000000000000000000000200000"), + hex!("0000000000000000000000000000000000000000000000000000000000400000"), + hex!("0000000000000000000000000000000000000000000000000000000000800000"), + hex!("0000000000000000000000000000000000000000000000000000000001000000"), + hex!("0000000000000000000000000000000000000000000000000000000002000000"), + hex!("0000000000000000000000000000000000000000000000000000000004000000"), + hex!("0000000000000000000000000000000000000000000000000000000008000000"), + hex!("0000000000000000000000000000000000000000000000000000000010000000"), + hex!("0000000000000000000000000000000000000000000000000000000020000000"), + hex!("0000000000000000000000000000000000000000000000000000000040000000"), + hex!("0000000000000000000000000000000000000000000000000000000080000000"), + hex!("0000000000000000000000000000000000000000000000000000000100000000"), + hex!("0000000000000000000000000000000000000000000000000000000200000000"), + hex!("0000000000000000000000000000000000000000000000000000000400000000"), + hex!("0000000000000000000000000000000000000000000000000000000800000000"), + hex!("0000000000000000000000000000000000000000000000000000001000000000"), + hex!("0000000000000000000000000000000000000000000000000000002000000000"), + hex!("0000000000000000000000000000000000000000000000000000004000000000"), + hex!("0000000000000000000000000000000000000000000000000000008000000000"), + hex!("0000000000000000000000000000000000000000000000000000010000000000"), + hex!("0000000000000000000000000000000000000000000000000000020000000000"), + hex!("0000000000000000000000000000000000000000000000000000040000000000"), + hex!("0000000000000000000000000000000000000000000000000000080000000000"), + hex!("0000000000000000000000000000000000000000000000000000100000000000"), + hex!("0000000000000000000000000000000000000000000000000000200000000000"), + hex!("0000000000000000000000000000000000000000000000000000400000000000"), + hex!("0000000000000000000000000000000000000000000000000000800000000000"), + hex!("0000000000000000000000000000000000000000000000000001000000000000"), + hex!("0000000000000000000000000000000000000000000000000002000000000000"), + hex!("0000000000000000000000000000000000000000000000000004000000000000"), + hex!("0000000000000000000000000000000000000000000000000008000000000000"), + hex!("0000000000000000000000000000000000000000000000000010000000000000"), + hex!("0000000000000000000000000000000000000000000000000020000000000000"), + hex!("0000000000000000000000000000000000000000000000000040000000000000"), + hex!("0000000000000000000000000000000000000000000000000080000000000000"), + hex!("0000000000000000000000000000000000000000000000000100000000000000"), + hex!("0000000000000000000000000000000000000000000000000200000000000000"), + hex!("0000000000000000000000000000000000000000000000000400000000000000"), + hex!("0000000000000000000000000000000000000000000000000800000000000000"), + hex!("0000000000000000000000000000000000000000000000001000000000000000"), + hex!("0000000000000000000000000000000000000000000000002000000000000000"), + hex!("0000000000000000000000000000000000000000000000004000000000000000"), + hex!("0000000000000000000000000000000000000000000000008000000000000000"), + hex!("0000000000000000000000000000000000000000000000010000000000000000"), + hex!("0000000000000000000000000000000000000000000000020000000000000000"), + hex!("0000000000000000000000000000000000000000000000040000000000000000"), + hex!("0000000000000000000000000000000000000000000000080000000000000000"), + hex!("0000000000000000000000000000000000000000000000100000000000000000"), + hex!("0000000000000000000000000000000000000000000000200000000000000000"), + hex!("0000000000000000000000000000000000000000000000400000000000000000"), + hex!("0000000000000000000000000000000000000000000000800000000000000000"), + hex!("0000000000000000000000000000000000000000000001000000000000000000"), + hex!("0000000000000000000000000000000000000000000002000000000000000000"), + hex!("0000000000000000000000000000000000000000000004000000000000000000"), + hex!("0000000000000000000000000000000000000000000008000000000000000000"), + hex!("0000000000000000000000000000000000000000000010000000000000000000"), + hex!("0000000000000000000000000000000000000000000020000000000000000000"), + hex!("0000000000000000000000000000000000000000000040000000000000000000"), + hex!("0000000000000000000000000000000000000000000080000000000000000000"), + hex!("0000000000000000000000000000000000000000000100000000000000000000"), + hex!("0000000000000000000000000000000000000000000200000000000000000000"), + hex!("0000000000000000000000000000000000000000000400000000000000000000"), + hex!("0000000000000000000000000000000000000000000800000000000000000000"), + hex!("0000000000000000000000000000000000000000001000000000000000000000"), + hex!("0000000000000000000000000000000000000000002000000000000000000000"), + hex!("0000000000000000000000000000000000000000004000000000000000000000"), + hex!("0000000000000000000000000000000000000000008000000000000000000000"), + hex!("0000000000000000000000000000000000000000010000000000000000000000"), + hex!("0000000000000000000000000000000000000000020000000000000000000000"), + hex!("0000000000000000000000000000000000000000040000000000000000000000"), + hex!("0000000000000000000000000000000000000000080000000000000000000000"), + hex!("0000000000000000000000000000000000000000100000000000000000000000"), + hex!("0000000000000000000000000000000000000000200000000000000000000000"), + hex!("0000000000000000000000000000000000000000400000000000000000000000"), + hex!("0000000000000000000000000000000000000000800000000000000000000000"), + hex!("0000000000000000000000000000000000000001000000000000000000000000"), + hex!("0000000000000000000000000000000000000002000000000000000000000000"), + hex!("0000000000000000000000000000000000000004000000000000000000000000"), + hex!("0000000000000000000000000000000000000008000000000000000000000000"), + hex!("0000000000000000000000000000000000000010000000000000000000000000"), + hex!("0000000000000000000000000000000000000020000000000000000000000000"), + hex!("0000000000000000000000000000000000000040000000000000000000000000"), + hex!("0000000000000000000000000000000000000080000000000000000000000000"), + hex!("0000000000000000000000000000000000000100000000000000000000000000"), + hex!("0000000000000000000000000000000000000200000000000000000000000000"), + hex!("0000000000000000000000000000000000000400000000000000000000000000"), + hex!("0000000000000000000000000000000000000800000000000000000000000000"), + hex!("0000000000000000000000000000000000001000000000000000000000000000"), + hex!("0000000000000000000000000000000000002000000000000000000000000000"), + hex!("0000000000000000000000000000000000004000000000000000000000000000"), + hex!("0000000000000000000000000000000000008000000000000000000000000000"), + hex!("0000000000000000000000000000000000010000000000000000000000000000"), + hex!("0000000000000000000000000000000000020000000000000000000000000000"), + hex!("0000000000000000000000000000000000040000000000000000000000000000"), + hex!("0000000000000000000000000000000000080000000000000000000000000000"), + hex!("0000000000000000000000000000000000100000000000000000000000000000"), + hex!("0000000000000000000000000000000000200000000000000000000000000000"), + hex!("0000000000000000000000000000000000400000000000000000000000000000"), + hex!("0000000000000000000000000000000000800000000000000000000000000000"), + hex!("0000000000000000000000000000000001000000000000000000000000000000"), + hex!("0000000000000000000000000000000002000000000000000000000000000000"), + hex!("0000000000000000000000000000000004000000000000000000000000000000"), + hex!("0000000000000000000000000000000008000000000000000000000000000000"), + hex!("0000000000000000000000000000000010000000000000000000000000000000"), + hex!("0000000000000000000000000000000020000000000000000000000000000000"), + hex!("0000000000000000000000000000000040000000000000000000000000000000"), + hex!("0000000000000000000000000000000080000000000000000000000000000000"), + hex!("0000000000000000000000000000000100000000000000000000000000000000"), + hex!("0000000000000000000000000000000200000000000000000000000000000000"), + hex!("0000000000000000000000000000000400000000000000000000000000000000"), + hex!("0000000000000000000000000000000800000000000000000000000000000000"), + hex!("0000000000000000000000000000001000000000000000000000000000000000"), + hex!("0000000000000000000000000000002000000000000000000000000000000000"), + hex!("0000000000000000000000000000004000000000000000000000000000000000"), + hex!("0000000000000000000000000000008000000000000000000000000000000000"), + hex!("0000000000000000000000000000010000000000000000000000000000000000"), + hex!("0000000000000000000000000000020000000000000000000000000000000000"), + hex!("0000000000000000000000000000040000000000000000000000000000000000"), + hex!("0000000000000000000000000000080000000000000000000000000000000000"), + hex!("0000000000000000000000000000100000000000000000000000000000000000"), + hex!("0000000000000000000000000000200000000000000000000000000000000000"), + hex!("0000000000000000000000000000400000000000000000000000000000000000"), + hex!("0000000000000000000000000000800000000000000000000000000000000000"), + hex!("0000000000000000000000000001000000000000000000000000000000000000"), + hex!("0000000000000000000000000002000000000000000000000000000000000000"), + hex!("0000000000000000000000000004000000000000000000000000000000000000"), + hex!("0000000000000000000000000008000000000000000000000000000000000000"), + hex!("0000000000000000000000000010000000000000000000000000000000000000"), + hex!("0000000000000000000000000020000000000000000000000000000000000000"), + hex!("0000000000000000000000000040000000000000000000000000000000000000"), + hex!("0000000000000000000000000080000000000000000000000000000000000000"), + hex!("0000000000000000000000000100000000000000000000000000000000000000"), + hex!("0000000000000000000000000200000000000000000000000000000000000000"), + hex!("0000000000000000000000000400000000000000000000000000000000000000"), + hex!("0000000000000000000000000800000000000000000000000000000000000000"), + hex!("0000000000000000000000001000000000000000000000000000000000000000"), + hex!("0000000000000000000000002000000000000000000000000000000000000000"), + hex!("0000000000000000000000004000000000000000000000000000000000000000"), + hex!("0000000000000000000000008000000000000000000000000000000000000000"), + hex!("0000000000000000000000010000000000000000000000000000000000000000"), + hex!("0000000000000000000000020000000000000000000000000000000000000000"), + hex!("0000000000000000000000040000000000000000000000000000000000000000"), + hex!("0000000000000000000000080000000000000000000000000000000000000000"), + hex!("0000000000000000000000100000000000000000000000000000000000000000"), + hex!("0000000000000000000000200000000000000000000000000000000000000000"), + hex!("0000000000000000000000400000000000000000000000000000000000000000"), + hex!("0000000000000000000000800000000000000000000000000000000000000000"), + hex!("0000000000000000000001000000000000000000000000000000000000000000"), + hex!("0000000000000000000002000000000000000000000000000000000000000000"), + hex!("0000000000000000000004000000000000000000000000000000000000000000"), + hex!("0000000000000000000008000000000000000000000000000000000000000000"), + hex!("0000000000000000000010000000000000000000000000000000000000000000"), + hex!("0000000000000000000020000000000000000000000000000000000000000000"), + hex!("0000000000000000000040000000000000000000000000000000000000000000"), + hex!("0000000000000000000080000000000000000000000000000000000000000000"), + hex!("0000000000000000000100000000000000000000000000000000000000000000"), + hex!("0000000000000000000200000000000000000000000000000000000000000000"), + hex!("0000000000000000000400000000000000000000000000000000000000000000"), + hex!("0000000000000000000800000000000000000000000000000000000000000000"), + hex!("0000000000000000001000000000000000000000000000000000000000000000"), + hex!("0000000000000000002000000000000000000000000000000000000000000000"), + hex!("0000000000000000004000000000000000000000000000000000000000000000"), + hex!("0000000000000000008000000000000000000000000000000000000000000000"), + hex!("0000000000000000010000000000000000000000000000000000000000000000"), + hex!("0000000000000000020000000000000000000000000000000000000000000000"), + hex!("0000000000000000040000000000000000000000000000000000000000000000"), + hex!("0000000000000000080000000000000000000000000000000000000000000000"), + hex!("0000000000000000100000000000000000000000000000000000000000000000"), + hex!("0000000000000000200000000000000000000000000000000000000000000000"), + hex!("0000000000000000400000000000000000000000000000000000000000000000"), + hex!("0000000000000000800000000000000000000000000000000000000000000000"), + hex!("0000000000000001000000000000000000000000000000000000000000000000"), + hex!("0000000000000002000000000000000000000000000000000000000000000000"), + hex!("0000000000000004000000000000000000000000000000000000000000000000"), + hex!("0000000000000008000000000000000000000000000000000000000000000000"), + hex!("0000000000000010000000000000000000000000000000000000000000000000"), + hex!("0000000000000020000000000000000000000000000000000000000000000000"), + hex!("0000000000000040000000000000000000000000000000000000000000000000"), + hex!("0000000000000080000000000000000000000000000000000000000000000000"), + hex!("0000000000000100000000000000000000000000000000000000000000000000"), + hex!("0000000000000200000000000000000000000000000000000000000000000000"), + hex!("0000000000000400000000000000000000000000000000000000000000000000"), + hex!("0000000000000800000000000000000000000000000000000000000000000000"), + hex!("0000000000001000000000000000000000000000000000000000000000000000"), + hex!("0000000000002000000000000000000000000000000000000000000000000000"), + hex!("0000000000004000000000000000000000000000000000000000000000000000"), + hex!("0000000000008000000000000000000000000000000000000000000000000000"), + hex!("0000000000010000000000000000000000000000000000000000000000000000"), + hex!("0000000000020000000000000000000000000000000000000000000000000000"), + hex!("0000000000040000000000000000000000000000000000000000000000000000"), + hex!("0000000000080000000000000000000000000000000000000000000000000000"), + hex!("0000000000100000000000000000000000000000000000000000000000000000"), + hex!("0000000000200000000000000000000000000000000000000000000000000000"), + hex!("0000000000400000000000000000000000000000000000000000000000000000"), + hex!("0000000000800000000000000000000000000000000000000000000000000000"), + hex!("0000000001000000000000000000000000000000000000000000000000000000"), + hex!("0000000002000000000000000000000000000000000000000000000000000000"), + hex!("0000000004000000000000000000000000000000000000000000000000000000"), + hex!("0000000008000000000000000000000000000000000000000000000000000000"), + hex!("0000000010000000000000000000000000000000000000000000000000000000"), + hex!("0000000020000000000000000000000000000000000000000000000000000000"), + hex!("0000000040000000000000000000000000000000000000000000000000000000"), + hex!("0000000080000000000000000000000000000000000000000000000000000000"), + hex!("0000000100000000000000000000000000000000000000000000000000000000"), + hex!("0000000200000000000000000000000000000000000000000000000000000000"), + hex!("0000000400000000000000000000000000000000000000000000000000000000"), + hex!("0000000800000000000000000000000000000000000000000000000000000000"), + hex!("0000001000000000000000000000000000000000000000000000000000000000"), + hex!("0000002000000000000000000000000000000000000000000000000000000000"), + hex!("0000004000000000000000000000000000000000000000000000000000000000"), + hex!("0000008000000000000000000000000000000000000000000000000000000000"), + hex!("0000010000000000000000000000000000000000000000000000000000000000"), + hex!("0000020000000000000000000000000000000000000000000000000000000000"), + hex!("0000040000000000000000000000000000000000000000000000000000000000"), + hex!("0000080000000000000000000000000000000000000000000000000000000000"), + hex!("0000100000000000000000000000000000000000000000000000000000000000"), + hex!("0000200000000000000000000000000000000000000000000000000000000000"), + hex!("0000400000000000000000000000000000000000000000000000000000000000"), + hex!("0000800000000000000000000000000000000000000000000000000000000000"), + hex!("0001000000000000000000000000000000000000000000000000000000000000"), + hex!("0002000000000000000000000000000000000000000000000000000000000000"), + hex!("0004000000000000000000000000000000000000000000000000000000000000"), + hex!("0008000000000000000000000000000000000000000000000000000000000000"), + hex!("0010000000000000000000000000000000000000000000000000000000000000"), + hex!("0020000000000000000000000000000000000000000000000000000000000000"), + hex!("0040000000000000000000000000000000000000000000000000000000000000"), + hex!("0080000000000000000000000000000000000000000000000000000000000000"), + hex!("0100000000000000000000000000000000000000000000000000000000000000"), + hex!("0200000000000000000000000000000000000000000000000000000000000000"), +]; diff --git a/src/rust/vendor/p256/src/test_vectors/group.rs b/src/rust/vendor/p256/src/test_vectors/group.rs new file mode 100644 index 000000000..77e535ae8 --- /dev/null +++ b/src/rust/vendor/p256/src/test_vectors/group.rs @@ -0,0 +1,256 @@ +//! Test vectors for the secp256r1 group. + +use hex_literal::hex; + +/// Repeated addition of the generator. +/// +/// These are the first 20 test vectors from +pub const ADD_TEST_VECTORS: &[([u8; 32], [u8; 32])] = &[ + ( + hex!("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"), + hex!("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"), + ), + ( + hex!("7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC47669978"), + hex!("07775510DB8ED040293D9AC69F7430DBBA7DADE63CE982299E04B79D227873D1"), + ), + ( + hex!("5ECBE4D1A6330A44C8F7EF951D4BF165E6C6B721EFADA985FB41661BC6E7FD6C"), + hex!("8734640C4998FF7E374B06CE1A64A2ECD82AB036384FB83D9A79B127A27D5032"), + ), + ( + hex!("E2534A3532D08FBBA02DDE659EE62BD0031FE2DB785596EF509302446B030852"), + hex!("E0F1575A4C633CC719DFEE5FDA862D764EFC96C3F30EE0055C42C23F184ED8C6"), + ), + ( + hex!("51590B7A515140D2D784C85608668FDFEF8C82FD1F5BE52421554A0DC3D033ED"), + hex!("E0C17DA8904A727D8AE1BF36BF8A79260D012F00D4D80888D1D0BB44FDA16DA4"), + ), + ( + hex!("B01A172A76A4602C92D3242CB897DDE3024C740DEBB215B4C6B0AAE93C2291A9"), + hex!("E85C10743237DAD56FEC0E2DFBA703791C00F7701C7E16BDFD7C48538FC77FE2"), + ), + ( + hex!("8E533B6FA0BF7B4625BB30667C01FB607EF9F8B8A80FEF5B300628703187B2A3"), + hex!("73EB1DBDE03318366D069F83A6F5900053C73633CB041B21C55E1A86C1F400B4"), + ), + ( + hex!("62D9779DBEE9B0534042742D3AB54CADC1D238980FCE97DBB4DD9DC1DB6FB393"), + hex!("AD5ACCBD91E9D8244FF15D771167CEE0A2ED51F6BBE76A78DA540A6A0F09957E"), + ), + ( + hex!("EA68D7B6FEDF0B71878938D51D71F8729E0ACB8C2C6DF8B3D79E8A4B90949EE0"), + hex!("2A2744C972C9FCE787014A964A8EA0C84D714FEAA4DE823FE85A224A4DD048FA"), + ), + ( + hex!("CEF66D6B2A3A993E591214D1EA223FB545CA6C471C48306E4C36069404C5723F"), + hex!("878662A229AAAE906E123CDD9D3B4C10590DED29FE751EEECA34BBAA44AF0773"), + ), + ( + hex!("3ED113B7883B4C590638379DB0C21CDA16742ED0255048BF433391D374BC21D1"), + hex!("9099209ACCC4C8A224C843AFA4F4C68A090D04DA5E9889DAE2F8EEFCE82A3740"), + ), + ( + hex!("741DD5BDA817D95E4626537320E5D55179983028B2F82C99D500C5EE8624E3C4"), + hex!("0770B46A9C385FDC567383554887B1548EEB912C35BA5CA71995FF22CD4481D3"), + ), + ( + hex!("177C837AE0AC495A61805DF2D85EE2FC792E284B65EAD58A98E15D9D46072C01"), + hex!("63BB58CD4EBEA558A24091ADB40F4E7226EE14C3A1FB4DF39C43BBE2EFC7BFD8"), + ), + ( + hex!("54E77A001C3862B97A76647F4336DF3CF126ACBE7A069C5E5709277324D2920B"), + hex!("F599F1BB29F4317542121F8C05A2E7C37171EA77735090081BA7C82F60D0B375"), + ), + ( + hex!("F0454DC6971ABAE7ADFB378999888265AE03AF92DE3A0EF163668C63E59B9D5F"), + hex!("B5B93EE3592E2D1F4E6594E51F9643E62A3B21CE75B5FA3F47E59CDE0D034F36"), + ), + ( + hex!("76A94D138A6B41858B821C629836315FCD28392EFF6CA038A5EB4787E1277C6E"), + hex!("A985FE61341F260E6CB0A1B5E11E87208599A0040FC78BAA0E9DDD724B8C5110"), + ), + ( + hex!("47776904C0F1CC3A9C0984B66F75301A5FA68678F0D64AF8BA1ABCE34738A73E"), + hex!("AA005EE6B5B957286231856577648E8381B2804428D5733F32F787FF71F1FCDC"), + ), + ( + hex!("1057E0AB5780F470DEFC9378D1C7C87437BB4C6F9EA55C63D936266DBD781FDA"), + hex!("F6F1645A15CBE5DC9FA9B7DFD96EE5A7DCC11B5C5EF4F1F78D83B3393C6A45A2"), + ), + ( + hex!("CB6D2861102C0C25CE39B7C17108C507782C452257884895C1FC7B74AB03ED83"), + hex!("58D7614B24D9EF515C35E7100D6D6CE4A496716E30FA3E03E39150752BCECDAA"), + ), + ( + hex!("83A01A9378395BAB9BCD6A0AD03CC56D56E6B19250465A94A234DC4C6B28DA9A"), + hex!("76E49B6DE2F73234AE6A5EB9D612B75C9F2202BB6923F54FF8240AAA86F640B8"), + ), +]; + +/// Scalar multiplication with the generator. +/// +/// These are the test vectors from that are not +/// part of [`ADD_TEST_VECTORS`]. +pub const MUL_TEST_VECTORS: &[([u8; 32], [u8; 32], [u8; 32])] = &[ + ( + hex!("000000000000000000000000000000000000000000000000018EBBB95EED0E13"), + hex!("339150844EC15234807FE862A86BE77977DBFB3AE3D96F4C22795513AEAAB82F"), + hex!("B1C14DDFDC8EC1B2583F51E85A5EB3A155840F2034730E9B5ADA38B674336A21"), + ), + ( + hex!("0000000000000000000000000000000000159D893D4CDD747246CDCA43590E13"), + hex!("1B7E046A076CC25E6D7FA5003F6729F665CC3241B5ADAB12B498CD32F2803264"), + hex!("BFEA79BE2B666B073DB69A2A241ADAB0738FE9D2DD28B5604EB8C8CF097C457B"), + ), + ( + hex!("41FFC1FFFFFE01FFFC0003FFFE0007C001FFF00003FFF07FFE0007C000000003"), + hex!("9EACE8F4B071E677C5350B02F2BB2B384AAE89D58AA72CA97A170572E0FB222F"), + hex!("1BBDAEC2430B09B93F7CB08678636CE12EAAFD58390699B5FD2F6E1188FC2A78"), + ), + ( + hex!("7FFFFFC03FFFC003FFFFFC007FFF00000000070000100000000E00FFFFFFF3FF"), + hex!("878F22CC6DB6048D2B767268F22FFAD8E56AB8E2DC615F7BD89F1E350500DD8D"), + hex!("714A5D7BB901C9C5853400D12341A892EF45D87FC553786756C4F0C9391D763E"), + ), + ( + hex!("0000FFFFF01FFFF8FFFFC00FFFFFFFFFC000000FFFFFC007FFFFFC000FFFE3FF"), + hex!("659A379625AB122F2512B8DADA02C6348D53B54452DFF67AC7ACE4E8856295CA"), + hex!("49D81AB97B648464D0B4A288BD7818FAB41A16426E943527C4FED8736C53D0F6"), + ), + ( + hex!("4000008000FFFFFC000003F00000FFFFFFFF800003800F8000E0000E000000FF"), + hex!("CBCEAAA8A4DD44BBCE58E8DB7740A5510EC2CB7EA8DA8D8F036B3FB04CDA4DE4"), + hex!("4BD7AA301A80D7F59FD983FEDBE59BB7B2863FE46494935E3745B360E32332FA"), + ), + ( + hex!("003FFFFFF0001F80000003F80003FFFFC0000000000FFE0000007FF818000F80"), + hex!("F0C4A0576154FF3A33A3460D42EAED806E854DFA37125221D37935124BA462A4"), + hex!("5B392FA964434D29EEC6C9DBC261CF116796864AA2FAADB984A2DF38D1AEF7A3"), + ), + ( + hex!("000001C000000000001001F803FFFFFF80000000000007FF0000000000000000"), + hex!("5E6C8524B6369530B12C62D31EC53E0288173BD662BDF680B53A41ECBCAD00CC"), + hex!("447FE742C2BFEF4D0DB14B5B83A2682309B5618E0064A94804E9282179FE089F"), + ), + ( + hex!("7FC0007FFFFFFC0003FFFFFFFFFFFFFE00003FFFFF07FFFFFFFFFFFFC007FFFF"), + hex!("03792E541BC209076A3D7920A915021ECD396A6EB5C3960024BE5575F3223484"), + hex!("FC774AE092403101563B712F68170312304F20C80B40C06282063DB25F268DE4"), + ), + ( + hex!("7FFFFC03FF807FFFE0001FFFFF800FFF800001FFFF0001FFFFFE001FFFC00000"), + hex!("2379FF85AB693CDF901D6CE6F2473F39C04A2FE3DCD842CE7AAB0E002095BCF8"), + hex!("F8B476530A634589D5129E46F322B02FBC610A703D80875EE70D7CE1877436A1"), + ), + ( + hex!("00FFFFFFFE03FFFC07FFFC800070000FC0007FFC00000000000FFFE1FBFF81FF"), + hex!("C1E4072C529BF2F44DA769EFC934472848003B3AF2C0F5AA8F8DDBD53E12ED7C"), + hex!("39A6EE77812BB37E8079CD01ED649D3830FCA46F718C1D3993E4A591824ABCDB"), + ), + ( + hex!("01FFF81FC000000000FF801FFFC0F81F01FFF8001FC005FFFFFF800000FFFFFC"), + hex!("34DFBC09404C21E250A9B40FA8772897AC63A094877DB65862B61BD1507B34F3"), + hex!("CF6F8A876C6F99CEAEC87148F18C7E1E0DA6E165FFC8ED82ABB65955215F77D3"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63253D"), + hex!("83A01A9378395BAB9BCD6A0AD03CC56D56E6B19250465A94A234DC4C6B28DA9A"), + hex!("891B64911D08CDCC5195A14629ED48A360DDFD4596DC0AB007DBF5557909BF47"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63253E"), + hex!("CB6D2861102C0C25CE39B7C17108C507782C452257884895C1FC7B74AB03ED83"), + hex!("A7289EB3DB2610AFA3CA18EFF292931B5B698E92CF05C1FC1C6EAF8AD4313255"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63253F"), + hex!("1057E0AB5780F470DEFC9378D1C7C87437BB4C6F9EA55C63D936266DBD781FDA"), + hex!("090E9BA4EA341A246056482026911A58233EE4A4A10B0E08727C4CC6C395BA5D"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632540"), + hex!("47776904C0F1CC3A9C0984B66F75301A5FA68678F0D64AF8BA1ABCE34738A73E"), + hex!("55FFA1184A46A8D89DCE7A9A889B717C7E4D7FBCD72A8CC0CD0878008E0E0323"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632541"), + hex!("76A94D138A6B41858B821C629836315FCD28392EFF6CA038A5EB4787E1277C6E"), + hex!("567A019DCBE0D9F2934F5E4A1EE178DF7A665FFCF0387455F162228DB473AEEF"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632542"), + hex!("F0454DC6971ABAE7ADFB378999888265AE03AF92DE3A0EF163668C63E59B9D5F"), + hex!("4A46C11BA6D1D2E1B19A6B1AE069BC19D5C4DE328A4A05C0B81A6321F2FCB0C9"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632543"), + hex!("54E77A001C3862B97A76647F4336DF3CF126ACBE7A069C5E5709277324D2920B"), + hex!("0A660E43D60BCE8BBDEDE073FA5D183C8E8E15898CAF6FF7E45837D09F2F4C8A"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632544"), + hex!("177C837AE0AC495A61805DF2D85EE2FC792E284B65EAD58A98E15D9D46072C01"), + hex!("9C44A731B1415AA85DBF6E524BF0B18DD911EB3D5E04B20C63BC441D10384027"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632545"), + hex!("741DD5BDA817D95E4626537320E5D55179983028B2F82C99D500C5EE8624E3C4"), + hex!("F88F4B9463C7A024A98C7CAAB7784EAB71146ED4CA45A358E66A00DD32BB7E2C"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632546"), + hex!("3ED113B7883B4C590638379DB0C21CDA16742ED0255048BF433391D374BC21D1"), + hex!("6F66DF64333B375EDB37BC505B0B3975F6F2FB26A16776251D07110317D5C8BF"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632547"), + hex!("CEF66D6B2A3A993E591214D1EA223FB545CA6C471C48306E4C36069404C5723F"), + hex!("78799D5CD655517091EDC32262C4B3EFA6F212D7018AE11135CB4455BB50F88C"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632548"), + hex!("EA68D7B6FEDF0B71878938D51D71F8729E0ACB8C2C6DF8B3D79E8A4B90949EE0"), + hex!("D5D8BB358D36031978FEB569B5715F37B28EB0165B217DC017A5DDB5B22FB705"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632549"), + hex!("62D9779DBEE9B0534042742D3AB54CADC1D238980FCE97DBB4DD9DC1DB6FB393"), + hex!("52A533416E1627DCB00EA288EE98311F5D12AE0A4418958725ABF595F0F66A81"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254A"), + hex!("8E533B6FA0BF7B4625BB30667C01FB607EF9F8B8A80FEF5B300628703187B2A3"), + hex!("8C14E2411FCCE7CA92F9607C590A6FFFAC38C9CD34FBE4DE3AA1E5793E0BFF4B"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254B"), + hex!("B01A172A76A4602C92D3242CB897DDE3024C740DEBB215B4C6B0AAE93C2291A9"), + hex!("17A3EF8ACDC8252B9013F1D20458FC86E3FF0890E381E9420283B7AC7038801D"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254C"), + hex!("51590B7A515140D2D784C85608668FDFEF8C82FD1F5BE52421554A0DC3D033ED"), + hex!("1F3E82566FB58D83751E40C9407586D9F2FED1002B27F7772E2F44BB025E925B"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254D"), + hex!("E2534A3532D08FBBA02DDE659EE62BD0031FE2DB785596EF509302446B030852"), + hex!("1F0EA8A4B39CC339E62011A02579D289B103693D0CF11FFAA3BD3DC0E7B12739"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254E"), + hex!("5ECBE4D1A6330A44C8F7EF951D4BF165E6C6B721EFADA985FB41661BC6E7FD6C"), + hex!("78CB9BF2B6670082C8B4F931E59B5D1327D54FCAC7B047C265864ED85D82AFCD"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254F"), + hex!("7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC47669978"), + hex!("F888AAEE24712FC0D6C26539608BCF244582521AC3167DD661FB4862DD878C2E"), + ), + ( + hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632550"), + hex!("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"), + hex!("B01CBD1C01E58065711814B583F061E9D431CCA994CEA1313449BF97C840AE0A"), + ), +]; diff --git a/src/rust/vendor/p256/tests/affine.rs b/src/rust/vendor/p256/tests/affine.rs new file mode 100644 index 000000000..8e4bb816d --- /dev/null +++ b/src/rust/vendor/p256/tests/affine.rs @@ -0,0 +1,136 @@ +//! Affine arithmetic tests. + +#![cfg(all(feature = "arithmetic"))] + +use elliptic_curve::{ + group::{prime::PrimeCurveAffine, GroupEncoding}, + sec1::{FromEncodedPoint, ToCompactEncodedPoint, ToEncodedPoint}, +}; +use hex_literal::hex; +use p256::{AffinePoint, EncodedPoint}; + +const UNCOMPRESSED_BASEPOINT: &[u8] = &hex!( + "04 6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296 + 4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5" +); + +const COMPRESSED_BASEPOINT: &[u8] = + &hex!("03 6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"); + +// Tag compact with 05 as the first byte, to trigger tag based compaction +const COMPACT_BASEPOINT: &[u8] = + &hex!("05 8e38fc4ffe677662dde8e1a63fbcd45959d2a4c3004d27e98c4fedf2d0c14c01"); + +// Tag uncompact basepoint with 04 as the first byte as it is uncompressed +const UNCOMPACT_BASEPOINT: &[u8] = &hex!( + "04 8e38fc4ffe677662dde8e1a63fbcd45959d2a4c3004d27e98c4fedf2d0c14c0 + 13ca9d8667de0c07aa71d98b3c8065d2e97ab7bb9cb8776bcc0577a7ac58acd4e" +); + +#[test] +fn uncompressed_round_trip() { + let pubkey = EncodedPoint::from_bytes(UNCOMPRESSED_BASEPOINT).unwrap(); + let point = AffinePoint::from_encoded_point(&pubkey).unwrap(); + assert_eq!(point, AffinePoint::generator()); + + let res: EncodedPoint = point.into(); + assert_eq!(res, pubkey); +} + +#[test] +fn compressed_round_trip() { + let pubkey = EncodedPoint::from_bytes(COMPRESSED_BASEPOINT).unwrap(); + let point = AffinePoint::from_encoded_point(&pubkey).unwrap(); + assert_eq!(point, AffinePoint::generator()); + + let res: EncodedPoint = point.to_encoded_point(true); + assert_eq!(res, pubkey); +} + +#[test] +fn uncompressed_to_compressed() { + let encoded = EncodedPoint::from_bytes(UNCOMPRESSED_BASEPOINT).unwrap(); + + let res = AffinePoint::from_encoded_point(&encoded) + .unwrap() + .to_encoded_point(true); + + assert_eq!(res.as_bytes(), COMPRESSED_BASEPOINT); +} + +#[test] +fn compressed_to_uncompressed() { + let encoded = EncodedPoint::from_bytes(COMPRESSED_BASEPOINT).unwrap(); + + let res = AffinePoint::from_encoded_point(&encoded) + .unwrap() + .to_encoded_point(false); + + assert_eq!(res.as_bytes(), UNCOMPRESSED_BASEPOINT); +} + +#[test] +fn affine_negation() { + let basepoint = AffinePoint::generator(); + assert_eq!(-(-basepoint), basepoint); +} + +#[test] +fn compact_round_trip() { + let pubkey = EncodedPoint::from_bytes(COMPACT_BASEPOINT).unwrap(); + assert!(pubkey.is_compact()); + + let point = AffinePoint::from_encoded_point(&pubkey).unwrap(); + let res = point.to_compact_encoded_point().unwrap(); + assert_eq!(res, pubkey) +} + +#[test] +fn uncompact_to_compact() { + let pubkey = EncodedPoint::from_bytes(UNCOMPACT_BASEPOINT).unwrap(); + assert_eq!(false, pubkey.is_compact()); + + let point = AffinePoint::from_encoded_point(&pubkey).unwrap(); + let res = point.to_compact_encoded_point().unwrap(); + assert_eq!(res.as_bytes(), COMPACT_BASEPOINT) +} + +#[test] +fn compact_to_uncompact() { + let pubkey = EncodedPoint::from_bytes(COMPACT_BASEPOINT).unwrap(); + assert!(pubkey.is_compact()); + + let point = AffinePoint::from_encoded_point(&pubkey).unwrap(); + // Do not do compact encoding as we want to keep uncompressed point + let res = point.to_encoded_point(false); + assert_eq!(res.as_bytes(), UNCOMPACT_BASEPOINT); +} + +#[test] +fn identity_encoding() { + // This is technically an invalid SEC1 encoding, but is preferable to panicking. + assert_eq!([0; 33], AffinePoint::IDENTITY.to_bytes().as_slice()); + assert!(bool::from( + AffinePoint::from_bytes(&AffinePoint::IDENTITY.to_bytes()) + .unwrap() + .is_identity() + )) +} + +#[test] +fn noncompatible_is_none() { + use elliptic_curve::generic_array::GenericArray; + let noncompactable_secret = GenericArray::from([ + 175, 232, 180, 255, 91, 106, 124, 191, 224, 31, 177, 208, 236, 127, 191, 169, 201, 217, 75, + 141, 184, 175, 120, 85, 171, 8, 54, 57, 33, 177, 83, 211, + ]); + let public_key = p256::SecretKey::from_bytes(&noncompactable_secret) + .unwrap() + .public_key(); + let is_compactable = public_key + .as_affine() + .to_compact_encoded_point() + .is_some() + .unwrap_u8(); + assert_eq!(is_compactable, 0); +} diff --git a/src/rust/vendor/p256/tests/ecdsa.rs b/src/rust/vendor/p256/tests/ecdsa.rs new file mode 100644 index 000000000..dfc80ae5b --- /dev/null +++ b/src/rust/vendor/p256/tests/ecdsa.rs @@ -0,0 +1,26 @@ +//! ECDSA tests. + +#![cfg(feature = "arithmetic")] + +use elliptic_curve::ops::Reduce; +use p256::{ + ecdsa::{SigningKey, VerifyingKey}, + NonZeroScalar, U256, +}; +use proptest::prelude::*; + +prop_compose! { + fn signing_key()(bytes in any::<[u8; 32]>()) -> SigningKey { + >::reduce_bytes(&bytes.into()).into() + } +} + +proptest! { + #[test] + fn recover_from_msg(sk in signing_key()) { + let msg = b"example"; + let (signature, v) = sk.sign_recoverable(msg).unwrap(); + let recovered_vk = VerifyingKey::recover_from_msg(msg, &signature, v).unwrap(); + prop_assert_eq!(sk.verifying_key(), &recovered_vk); + } +} diff --git a/src/rust/vendor/p256/tests/examples/pkcs8-private-key.der b/src/rust/vendor/p256/tests/examples/pkcs8-private-key.der new file mode 100644 index 000000000..c0de45ef2 Binary files /dev/null and b/src/rust/vendor/p256/tests/examples/pkcs8-private-key.der differ diff --git a/src/rust/vendor/p256/tests/examples/pkcs8-private-key.pem b/src/rust/vendor/p256/tests/examples/pkcs8-private-key.pem new file mode 100644 index 000000000..09b9343c0 --- /dev/null +++ b/src/rust/vendor/p256/tests/examples/pkcs8-private-key.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgaWJBcVYaYzQN4OfY +afKgVJJVjhoEhotqn4VKhmeIGI2hRANCAAQcrP+1Xy8s79idies3SyaBFSRSgC3u +oJkWBoE32DnPf8SBpESSME1+9mrBF77+g6jQjxVfK1L59hjdRHApBI4P +-----END PRIVATE KEY----- diff --git a/src/rust/vendor/p256/tests/examples/pkcs8-public-key.der b/src/rust/vendor/p256/tests/examples/pkcs8-public-key.der new file mode 100644 index 000000000..67c719c76 Binary files /dev/null and b/src/rust/vendor/p256/tests/examples/pkcs8-public-key.der differ diff --git a/src/rust/vendor/p256/tests/examples/pkcs8-public-key.pem b/src/rust/vendor/p256/tests/examples/pkcs8-public-key.pem new file mode 100644 index 000000000..ee7e5b612 --- /dev/null +++ b/src/rust/vendor/p256/tests/examples/pkcs8-public-key.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHKz/tV8vLO/YnYnrN0smgRUkUoAt +7qCZFgaBN9g5z3/EgaREkjBNfvZqwRe+/oOo0I8VXytS+fYY3URwKQSODw== +-----END PUBLIC KEY----- diff --git a/src/rust/vendor/p256/tests/pkcs8.rs b/src/rust/vendor/p256/tests/pkcs8.rs new file mode 100644 index 000000000..6c3bfecee --- /dev/null +++ b/src/rust/vendor/p256/tests/pkcs8.rs @@ -0,0 +1,99 @@ +//! PKCS#8 tests + +#![cfg(feature = "pkcs8")] + +use hex_literal::hex; +use p256::{ + elliptic_curve::sec1::ToEncodedPoint, + pkcs8::{DecodePrivateKey, DecodePublicKey}, +}; + +#[cfg(feature = "pem")] +use p256::elliptic_curve::pkcs8::{EncodePrivateKey, EncodePublicKey}; + +/// DER-encoded PKCS#8 private key +const PKCS8_PRIVATE_KEY_DER: &[u8; 138] = include_bytes!("examples/pkcs8-private-key.der"); + +/// DER-encoded PKCS#8 public key +const PKCS8_PUBLIC_KEY_DER: &[u8; 91] = include_bytes!("examples/pkcs8-public-key.der"); + +/// PEM-encoded PKCS#8 private key +#[cfg(feature = "pem")] +const PKCS8_PRIVATE_KEY_PEM: &str = include_str!("examples/pkcs8-private-key.pem"); + +/// PEM-encoded PKCS#8 public key +#[cfg(feature = "pem")] +const PKCS8_PUBLIC_KEY_PEM: &str = include_str!("examples/pkcs8-public-key.pem"); + +#[test] +fn decode_pkcs8_private_key_from_der() { + let secret_key = p256::SecretKey::from_pkcs8_der(&PKCS8_PRIVATE_KEY_DER[..]).unwrap(); + let expected_scalar = hex!("69624171561A63340DE0E7D869F2A05492558E1A04868B6A9F854A866788188D"); + assert_eq!(secret_key.to_bytes().as_slice(), &expected_scalar[..]); +} + +#[test] +fn decode_pkcs8_public_key_from_der() { + let public_key = p256::PublicKey::from_public_key_der(&PKCS8_PUBLIC_KEY_DER[..]).unwrap(); + let expected_sec1_point = hex!("041CACFFB55F2F2CEFD89D89EB374B2681152452802DEEA09916068137D839CF7FC481A44492304D7EF66AC117BEFE83A8D08F155F2B52F9F618DD447029048E0F"); + assert_eq!( + public_key.to_encoded_point(false).as_bytes(), + &expected_sec1_point[..] + ); +} + +#[test] +#[cfg(feature = "pem")] +fn decode_pkcs8_private_key_from_pem() { + let secret_key = PKCS8_PRIVATE_KEY_PEM.parse::().unwrap(); + + // Ensure key parses equivalently to DER + let der_key = p256::SecretKey::from_pkcs8_der(&PKCS8_PRIVATE_KEY_DER[..]).unwrap(); + assert_eq!(secret_key.to_bytes(), der_key.to_bytes()); +} + +#[test] +#[cfg(feature = "pem")] +fn decode_pkcs8_public_key_from_pem() { + let public_key = PKCS8_PUBLIC_KEY_PEM.parse::().unwrap(); + + // Ensure key parses equivalently to DER + let der_key = p256::PublicKey::from_public_key_der(&PKCS8_PUBLIC_KEY_DER[..]).unwrap(); + assert_eq!(public_key, der_key); +} + +#[test] +#[cfg(feature = "pem")] +fn encode_pkcs8_private_key_to_der() { + let original_secret_key = p256::SecretKey::from_pkcs8_der(&PKCS8_PRIVATE_KEY_DER[..]).unwrap(); + let reencoded_secret_key = original_secret_key.to_pkcs8_der().unwrap(); + assert_eq!(reencoded_secret_key.as_bytes(), &PKCS8_PRIVATE_KEY_DER[..]); +} + +#[test] +#[cfg(feature = "pem")] +fn encode_pkcs8_public_key_to_der() { + let original_public_key = + p256::PublicKey::from_public_key_der(&PKCS8_PUBLIC_KEY_DER[..]).unwrap(); + let reencoded_public_key = original_public_key.to_public_key_der().unwrap(); + assert_eq!(reencoded_public_key.as_ref(), &PKCS8_PUBLIC_KEY_DER[..]); +} + +#[test] +#[cfg(feature = "pem")] +fn encode_pkcs8_private_key_to_pem() { + let original_secret_key = p256::SecretKey::from_pkcs8_der(&PKCS8_PRIVATE_KEY_DER[..]).unwrap(); + let reencoded_secret_key = original_secret_key + .to_pkcs8_pem(Default::default()) + .unwrap(); + assert_eq!(reencoded_secret_key.as_str(), PKCS8_PRIVATE_KEY_PEM); +} + +#[test] +#[cfg(feature = "pem")] +fn encode_pkcs8_public_key_to_pem() { + let original_public_key = + p256::PublicKey::from_public_key_der(&PKCS8_PUBLIC_KEY_DER[..]).unwrap(); + let reencoded_public_key = original_public_key.to_string(); + assert_eq!(reencoded_public_key.as_str(), PKCS8_PUBLIC_KEY_PEM); +} diff --git a/src/rust/vendor/p256/tests/projective.rs b/src/rust/vendor/p256/tests/projective.rs new file mode 100644 index 000000000..6845f423e --- /dev/null +++ b/src/rust/vendor/p256/tests/projective.rs @@ -0,0 +1,27 @@ +//! Projective arithmetic tests. + +#![cfg(all(feature = "arithmetic", feature = "test-vectors"))] + +use elliptic_curve::{ + group::{ff::PrimeField, GroupEncoding}, + sec1::{self, ToEncodedPoint}, +}; +use p256::{ + test_vectors::group::{ADD_TEST_VECTORS, MUL_TEST_VECTORS}, + AffinePoint, ProjectivePoint, Scalar, +}; +use primeorder::{impl_projective_arithmetic_tests, Double}; + +impl_projective_arithmetic_tests!( + AffinePoint, + ProjectivePoint, + Scalar, + ADD_TEST_VECTORS, + MUL_TEST_VECTORS +); + +#[test] +fn projective_identity_to_bytes() { + // This is technically an invalid SEC1 encoding, but is preferable to panicking. + assert_eq!([0; 33], ProjectivePoint::IDENTITY.to_bytes().as_slice()); +} diff --git a/src/rust/vendor/p256/tests/scalar.rs b/src/rust/vendor/p256/tests/scalar.rs new file mode 100644 index 000000000..cc0c51ce0 --- /dev/null +++ b/src/rust/vendor/p256/tests/scalar.rs @@ -0,0 +1,22 @@ +//! Scalar arithmetic tests. + +#![cfg(feature = "arithmetic")] + +use elliptic_curve::ops::{Invert, Reduce}; +use p256::{Scalar, U256}; +use proptest::prelude::*; + +prop_compose! { + fn scalar()(bytes in any::<[u8; 32]>()) -> Scalar { + >::reduce_bytes(&bytes.into()) + } +} + +proptest! { + #[test] + fn invert_and_invert_vartime_are_equivalent(w in scalar()) { + let inv: Option = w.invert().into(); + let inv_vartime: Option = w.invert_vartime().into(); + prop_assert_eq!(inv, inv_vartime); + } +} diff --git a/src/rust/vendor/primeorder/.cargo-checksum.json b/src/rust/vendor/primeorder/.cargo-checksum.json new file mode 100644 index 000000000..fdf42be7f --- /dev/null +++ b/src/rust/vendor/primeorder/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"6bbfb034a1f59e955e758d9e1d787545b2948b5349a8c7b98b81ce4a40bf2898","Cargo.toml":"b2c33028ef1a7763ac1828c3f3c009e73085773de8adbfc043a6f5ca8ba7dba7","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"233b95ccbf90dc67e32f3e8995c489f6312d9191ebd141a931c3b684f1e3be6d","README.md":"953232a36bb8d90d3aaa82c97314b6e21f5df48637b87fb4d7c39ad40bd085a5","src/affine.rs":"f9071d6eb656a1a98522d3a0bf9f7b8b7954e58bf4e86e90d71843d057a2a576","src/dev.rs":"da64d3e406468cc13156f8378c18d3a68c615a621eb9007939cd340b3d37a19f","src/field.rs":"5a3c9bb09c21cafb56032374d99be8494d7bf482253e701cf745c0d6b4df61a5","src/lib.rs":"1b585e745812d008c554cfb8c52ae88619ca9a3d7c481cf18283a9be3b893990","src/point_arithmetic.rs":"7b65088237a263f7972cf59f88e7f761513d3a0ed9e687d6d429d70fa8974398","src/projective.rs":"4250a404894f3f18f788bdac07c91573ff57070e5a7bea54b8422c49f53b3f15"},"package":"353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6"} \ No newline at end of file diff --git a/src/rust/vendor/primeorder/CHANGELOG.md b/src/rust/vendor/primeorder/CHANGELOG.md new file mode 100644 index 000000000..be0f9ca54 --- /dev/null +++ b/src/rust/vendor/primeorder/CHANGELOG.md @@ -0,0 +1,93 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.13.6 (2023-11-15) +### Removed +- `Invert` bounds on `FieldElement` ([#985]) + +[#985]: https://github.com/RustCrypto/elliptic-curves/pull/985 + +## 0.13.5 (2023-11-15) [YANKED] +### Added +- `alloc` feature ([#982]) + +[#982]: https://github.com/RustCrypto/elliptic-curves/pull/982 + +## 0.13.4 (2023-11-15) [YANKED] +### Added +- `BatchInvert` and `BatchNormalize` impls ([#971]) + +### Changed +- Bump `elliptic-curve` to v0.13.7 ([#979]) + +[#971]: https://github.com/RustCrypto/elliptic-curves/pull/971 +[#979]: https://github.com/RustCrypto/elliptic-curves/pull/979 + +## 0.13.3 (2023-11-02) +### Added +- Inline annotations on `conditional_select` ([#942]) + +### Changed +- Support field elements larger than 64-bytes in `impl_projective_arithmetic_tests!` ([#951]) + +[#942]: https://github.com/RustCrypto/elliptic-curves/pull/942 +[#951]: https://github.com/RustCrypto/elliptic-curves/pull/951 + +## 0.13.2 (2023-05-29) +### Changed +- Improve decoding performance for uncompressed SEC1 points ([#891]) + +[#891]: https://github.com/RustCrypto/elliptic-curves/pull/891 + +## 0.13.1 (2023-04-09) +### Added +- `impl_bernstein_yang_invert!` macro ([#786]) +- `impl_field_invert_tests!` macro ([#786]) +- `impl_field_identity_tests!` macro ([#790]) +- `impl_field_sqrt_tests!` macro ([#790], [#800]) + +### Fixed +- Correct product definition for empty iterators ([#802]) + +[#786]: https://github.com/RustCrypto/elliptic-curves/pull/786 +[#790]: https://github.com/RustCrypto/elliptic-curves/pull/790 +[#800]: https://github.com/RustCrypto/elliptic-curves/pull/800 +[#802]: https://github.com/RustCrypto/elliptic-curves/pull/802 + +## 0.13.0 (2023-03-03) +### Added +- Support curves with any `a`-coefficient ([#728], [#729]) +- `impl_primefield_tests!` macro ([#739]) + +### Changed +- Use `AffineCoordinates` trait ([#734]) +- Rename `impl_field_element!` to `impl_mont_field_element!` ([#762]) +- Bump `elliptic-curve` dependency to v0.13 ([#770]) +- Bump `ecdsa` to v0.16 ([#770]) + +[#728]: https://github.com/RustCrypto/elliptic-curves/pull/728 +[#729]: https://github.com/RustCrypto/elliptic-curves/pull/729 +[#734]: https://github.com/RustCrypto/elliptic-curves/pull/734 +[#739]: https://github.com/RustCrypto/elliptic-curves/pull/739 +[#762]: https://github.com/RustCrypto/elliptic-curves/pull/762 +[#770]: https://github.com/RustCrypto/elliptic-curves/pull/770 + +## 0.12.1 (2023-01-22) +### Added +- Impl `From/ToEncodedPoint` for `ProjectivePoint` ([#722]) + +[#722]: https://github.com/RustCrypto/elliptic-curves/pull/722 + +## 0.12.0 (2023-01-16) + +Initial stable release. + +NOTE: other versions skipped to synchronize version numbers with +`elliptic-curve`, `k256`, `p256`, and `p384`. + +## 0.0.2 (2022-12-29) + +## 0.0.1 (2022-11-06) diff --git a/src/rust/vendor/primeorder/Cargo.toml b/src/rust/vendor/primeorder/Cargo.toml new file mode 100644 index 000000000..4906baab6 --- /dev/null +++ b/src/rust/vendor/primeorder/Cargo.toml @@ -0,0 +1,66 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.65" +name = "primeorder" +version = "0.13.6" +authors = ["RustCrypto Developers"] +description = """ +Pure Rust implementation of complete addition formulas for prime order elliptic +curves (Renes-Costello-Batina 2015). Generic over field elements and curve +equation coefficients +""" +documentation = "https://docs.rs/primeorder" +readme = "README.md" +keywords = [ + "crypto", + "ecc", +] +categories = [ + "cryptography", + "no-std", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/RustCrypto/elliptic-curves/tree/master/primeorder" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.elliptic-curve] +version = "0.13.7" +features = [ + "arithmetic", + "sec1", +] +default-features = false + +[dependencies.serdect] +version = "0.2" +optional = true +default-features = false + +[features] +alloc = ["elliptic-curve/alloc"] +dev = [] +serde = [ + "elliptic-curve/serde", + "serdect", +] +std = [ + "alloc", + "elliptic-curve/std", +] diff --git a/src/rust/vendor/primeorder/LICENSE-APACHE b/src/rust/vendor/primeorder/LICENSE-APACHE new file mode 100644 index 000000000..78173fa2e --- /dev/null +++ b/src/rust/vendor/primeorder/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/primeorder/LICENSE-MIT b/src/rust/vendor/primeorder/LICENSE-MIT new file mode 100644 index 000000000..50b1254c1 --- /dev/null +++ b/src/rust/vendor/primeorder/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2020-2023 RustCrypto Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/primeorder/README.md b/src/rust/vendor/primeorder/README.md new file mode 100644 index 000000000..603090434 --- /dev/null +++ b/src/rust/vendor/primeorder/README.md @@ -0,0 +1,96 @@ +# [RustCrypto]: Prime Order Elliptic Curve Formulas + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +[![Build Status][build-image]][build-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Project Chat][chat-image]][chat-link] + +Pure Rust implementation of complete addition formulas for prime order elliptic +curves ([Renes-Costello-Batina 2015]). Generic over field elements and curve +equation coefficients. + +[Documentation][docs-link] + +## About + +This crate provides a generic implementation of complete formulas for prime +order elliptic curves which are defined by the short [Weierstrass equation]: + +```text +y² = x³ + ax + b +``` + +It's used to implement the following elliptic curves: + +- [`p192`]: NIST P-192 +- [`p224`]: NIST P-224 +- [`p256`]: NIST P-256 +- [`p384`]: NIST P-384 +- [`p521`]: NIST P-521 +- [`sm2`]: ShangMi 2 + +## ⚠️ Security Warning + +The elliptic curve arithmetic contained in this crate has never been +independently audited! + +This crate has been designed with the goal of ensuring that secret-dependent +operations are performed in constant time (using the `subtle` crate and +constant-time formulas). However, it has not been thoroughly assessed to ensure +that generated assembly is constant time on common CPU architectures. + +USE AT YOUR OWN RISK! + +## Minimum Supported Rust Version + +Rust **1.65** or higher. + +Minimum supported Rust version can be changed in the future, but it will be +done with a minor version bump. + +## SemVer Policy + +- All on-by-default features of this library are covered by SemVer +- MSRV is considered exempt from SemVer as noted above + +## License + +All crates licensed under either of: + +- [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) +- [MIT license](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. + +[//]: # (badges) + +[crate-image]: https://buildstats.info/crate/primeorder +[crate-link]: https://crates.io/crates/primeorder +[docs-image]: https://docs.rs/primeorder/badge.svg +[docs-link]: https://docs.rs/primeorder/ +[build-image]: https://github.com/RustCrypto/elliptic-curves/actions/workflows/primeorder.yml/badge.svg +[build-link]: https://github.com/RustCrypto/elliptic-curves/actions/workflows/primeorder.yml +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260040-elliptic-curves + +[//]: # (links) + +[RustCrypto]: https://github.com/rustcrypto/ +[Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060 +[Weierstrass equation]: https://crypto.stanford.edu/pbc/notes/elliptic/weier.html +[`p192`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p192 +[`p224`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p224 +[`p256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p256 +[`p384`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p384 +[`p521`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p384 +[`sm2`]: https://github.com/RustCrypto/elliptic-curves/tree/master/sm2 diff --git a/src/rust/vendor/primeorder/src/affine.rs b/src/rust/vendor/primeorder/src/affine.rs new file mode 100644 index 000000000..6801c5d31 --- /dev/null +++ b/src/rust/vendor/primeorder/src/affine.rs @@ -0,0 +1,489 @@ +//! Affine curve points. + +#![allow(clippy::op_ref)] + +use crate::{PrimeCurveParams, ProjectivePoint}; +use core::{ + borrow::Borrow, + ops::{Mul, Neg}, +}; +use elliptic_curve::{ + ff::{Field, PrimeField}, + generic_array::ArrayLength, + group::{prime::PrimeCurveAffine, GroupEncoding}, + point::{AffineCoordinates, DecompactPoint, DecompressPoint, Double}, + sec1::{ + self, CompressedPoint, EncodedPoint, FromEncodedPoint, ModulusSize, ToCompactEncodedPoint, + ToEncodedPoint, UncompressedPointSize, + }, + subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, CtOption}, + zeroize::DefaultIsZeroes, + Error, FieldBytes, FieldBytesEncoding, FieldBytesSize, PublicKey, Result, Scalar, +}; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +/// Point on a Weierstrass curve in affine coordinates. +#[derive(Clone, Copy, Debug)] +pub struct AffinePoint { + /// x-coordinate + pub(crate) x: C::FieldElement, + + /// y-coordinate + pub(crate) y: C::FieldElement, + + /// Is this point the point at infinity? 0 = no, 1 = yes + /// + /// This is a proxy for [`Choice`], but uses `u8` instead to permit `const` + /// constructors for `IDENTITY` and `GENERATOR`. + pub(crate) infinity: u8, +} + +impl AffinePoint +where + C: PrimeCurveParams, +{ + /// Additive identity of the group a.k.a. the point at infinity. + pub const IDENTITY: Self = Self { + x: C::FieldElement::ZERO, + y: C::FieldElement::ZERO, + infinity: 1, + }; + + /// Base point of the curve. + pub const GENERATOR: Self = Self { + x: C::GENERATOR.0, + y: C::GENERATOR.1, + infinity: 0, + }; + + /// Is this point the point at infinity? + pub fn is_identity(&self) -> Choice { + Choice::from(self.infinity) + } + + /// Conditionally negate [`AffinePoint`] for use with point compaction. + fn to_compact(self) -> Self { + let neg_self = -self; + let choice = C::Uint::decode_field_bytes(&self.y.to_repr()) + .ct_gt(&C::Uint::decode_field_bytes(&neg_self.y.to_repr())); + + Self { + x: self.x, + y: C::FieldElement::conditional_select(&self.y, &neg_self.y, choice), + infinity: self.infinity, + } + } +} + +impl AffineCoordinates for AffinePoint +where + C: PrimeCurveParams, +{ + type FieldRepr = FieldBytes; + + fn x(&self) -> FieldBytes { + self.x.to_repr() + } + + fn y_is_odd(&self) -> Choice { + self.y.is_odd() + } +} + +impl ConditionallySelectable for AffinePoint +where + C: PrimeCurveParams, +{ + #[inline(always)] + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self { + x: C::FieldElement::conditional_select(&a.x, &b.x, choice), + y: C::FieldElement::conditional_select(&a.y, &b.y, choice), + infinity: u8::conditional_select(&a.infinity, &b.infinity, choice), + } + } +} + +impl ConstantTimeEq for AffinePoint +where + C: PrimeCurveParams, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y) & self.infinity.ct_eq(&other.infinity) + } +} + +impl Default for AffinePoint +where + C: PrimeCurveParams, +{ + fn default() -> Self { + Self::IDENTITY + } +} + +impl DefaultIsZeroes for AffinePoint where C: PrimeCurveParams {} + +impl DecompressPoint for AffinePoint +where + C: PrimeCurveParams, + FieldBytes: Copy, +{ + fn decompress(x_bytes: &FieldBytes, y_is_odd: Choice) -> CtOption { + C::FieldElement::from_repr(*x_bytes).and_then(|x| { + let alpha = x * &x * &x + &(C::EQUATION_A * &x) + &C::EQUATION_B; + let beta = alpha.sqrt(); + + beta.map(|beta| { + let y = C::FieldElement::conditional_select( + &-beta, + &beta, + beta.is_odd().ct_eq(&y_is_odd), + ); + + Self { x, y, infinity: 0 } + }) + }) + } +} + +impl DecompactPoint for AffinePoint +where + C: PrimeCurveParams, + FieldBytes: Copy, +{ + fn decompact(x_bytes: &FieldBytes) -> CtOption { + Self::decompress(x_bytes, Choice::from(0)).map(|point| point.to_compact()) + } +} + +impl Eq for AffinePoint where C: PrimeCurveParams {} + +impl FromEncodedPoint for AffinePoint +where + C: PrimeCurveParams, + FieldBytes: Copy, + FieldBytesSize: ModulusSize, + CompressedPoint: Copy, +{ + /// Attempts to parse the given [`EncodedPoint`] as an SEC1-encoded + /// [`AffinePoint`]. + /// + /// # Returns + /// + /// `None` value if `encoded_point` is not on the secp384r1 curve. + fn from_encoded_point(encoded_point: &EncodedPoint) -> CtOption { + match encoded_point.coordinates() { + sec1::Coordinates::Identity => CtOption::new(Self::IDENTITY, 1.into()), + sec1::Coordinates::Compact { x } => Self::decompact(x), + sec1::Coordinates::Compressed { x, y_is_odd } => { + Self::decompress(x, Choice::from(y_is_odd as u8)) + } + sec1::Coordinates::Uncompressed { x, y } => { + C::FieldElement::from_repr(*y).and_then(|y| { + C::FieldElement::from_repr(*x).and_then(|x| { + let lhs = y * &y; + let rhs = x * &x * &x + &(C::EQUATION_A * &x) + &C::EQUATION_B; + CtOption::new(Self { x, y, infinity: 0 }, lhs.ct_eq(&rhs)) + }) + }) + } + } + } +} + +impl From> for AffinePoint +where + C: PrimeCurveParams, +{ + fn from(p: ProjectivePoint) -> AffinePoint { + p.to_affine() + } +} + +impl From<&ProjectivePoint> for AffinePoint +where + C: PrimeCurveParams, +{ + fn from(p: &ProjectivePoint) -> AffinePoint { + p.to_affine() + } +} + +impl From> for AffinePoint +where + C: PrimeCurveParams, +{ + fn from(public_key: PublicKey) -> AffinePoint { + *public_key.as_affine() + } +} + +impl From<&PublicKey> for AffinePoint +where + C: PrimeCurveParams, +{ + fn from(public_key: &PublicKey) -> AffinePoint { + AffinePoint::from(*public_key) + } +} + +impl From> for EncodedPoint +where + C: PrimeCurveParams, + FieldBytesSize: ModulusSize, + CompressedPoint: Copy, + as ArrayLength>::ArrayType: Copy, +{ + fn from(affine: AffinePoint) -> EncodedPoint { + affine.to_encoded_point(false) + } +} + +impl GroupEncoding for AffinePoint +where + C: PrimeCurveParams, + FieldBytes: Copy, + FieldBytesSize: ModulusSize, + CompressedPoint: Copy, + as ArrayLength>::ArrayType: Copy, +{ + type Repr = CompressedPoint; + + /// NOTE: not constant-time with respect to identity point + fn from_bytes(bytes: &Self::Repr) -> CtOption { + EncodedPoint::::from_bytes(bytes) + .map(|point| CtOption::new(point, Choice::from(1))) + .unwrap_or_else(|_| { + // SEC1 identity encoding is technically 1-byte 0x00, but the + // `GroupEncoding` API requires a fixed-width `Repr` + let is_identity = bytes.ct_eq(&Self::Repr::default()); + CtOption::new(EncodedPoint::::identity(), is_identity) + }) + .and_then(|point| Self::from_encoded_point(&point)) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { + // No unchecked conversion possible for compressed points + Self::from_bytes(bytes) + } + + fn to_bytes(&self) -> Self::Repr { + let encoded = self.to_encoded_point(true); + let mut result = CompressedPoint::::default(); + result[..encoded.len()].copy_from_slice(encoded.as_bytes()); + result + } +} + +impl PartialEq for AffinePoint +where + C: PrimeCurveParams, +{ + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } +} + +impl PrimeCurveAffine for AffinePoint +where + C: PrimeCurveParams, + FieldBytes: Copy, + FieldBytesSize: ModulusSize, + ProjectivePoint: Double, + CompressedPoint: Copy, + as ArrayLength>::ArrayType: Copy, +{ + type Curve = ProjectivePoint; + type Scalar = Scalar; + + fn identity() -> AffinePoint { + Self::IDENTITY + } + + fn generator() -> AffinePoint { + Self::GENERATOR + } + + fn is_identity(&self) -> Choice { + self.is_identity() + } + + fn to_curve(&self) -> ProjectivePoint { + ProjectivePoint::from(*self) + } +} + +impl ToCompactEncodedPoint for AffinePoint +where + C: PrimeCurveParams, + FieldBytesSize: ModulusSize, + CompressedPoint: Copy, + as ArrayLength>::ArrayType: Copy, +{ + /// Serialize this value as a SEC1 compact [`EncodedPoint`] + fn to_compact_encoded_point(&self) -> CtOption> { + let point = self.to_compact(); + + let mut bytes = CompressedPoint::::default(); + bytes[0] = sec1::Tag::Compact.into(); + bytes[1..].copy_from_slice(&point.x.to_repr()); + + let encoded = EncodedPoint::::from_bytes(bytes); + let is_some = point.y.ct_eq(&self.y); + CtOption::new(encoded.unwrap_or_default(), is_some) + } +} + +impl ToEncodedPoint for AffinePoint +where + C: PrimeCurveParams, + FieldBytesSize: ModulusSize, + CompressedPoint: Copy, + as ArrayLength>::ArrayType: Copy, +{ + fn to_encoded_point(&self, compress: bool) -> EncodedPoint { + EncodedPoint::::conditional_select( + &EncodedPoint::::from_affine_coordinates( + &self.x.to_repr(), + &self.y.to_repr(), + compress, + ), + &EncodedPoint::::identity(), + self.is_identity(), + ) + } +} + +impl TryFrom> for AffinePoint +where + C: PrimeCurveParams, + FieldBytes: Copy, + FieldBytesSize: ModulusSize, + CompressedPoint: Copy, +{ + type Error = Error; + + fn try_from(point: EncodedPoint) -> Result> { + AffinePoint::try_from(&point) + } +} + +impl TryFrom<&EncodedPoint> for AffinePoint +where + C: PrimeCurveParams, + FieldBytes: Copy, + FieldBytesSize: ModulusSize, + CompressedPoint: Copy, +{ + type Error = Error; + + fn try_from(point: &EncodedPoint) -> Result> { + Option::from(AffinePoint::::from_encoded_point(point)).ok_or(Error) + } +} + +impl TryFrom> for PublicKey +where + C: PrimeCurveParams, +{ + type Error = Error; + + fn try_from(affine_point: AffinePoint) -> Result> { + PublicKey::from_affine(affine_point) + } +} + +impl TryFrom<&AffinePoint> for PublicKey +where + C: PrimeCurveParams, +{ + type Error = Error; + + fn try_from(affine_point: &AffinePoint) -> Result> { + PublicKey::::try_from(*affine_point) + } +} + +// +// Arithmetic trait impls +// + +impl Mul for AffinePoint +where + C: PrimeCurveParams, + S: Borrow>, + ProjectivePoint: Double, +{ + type Output = ProjectivePoint; + + fn mul(self, scalar: S) -> ProjectivePoint { + ProjectivePoint::::from(self) * scalar + } +} + +impl Neg for AffinePoint +where + C: PrimeCurveParams, +{ + type Output = Self; + + fn neg(self) -> Self { + AffinePoint { + x: self.x, + y: -self.y, + infinity: self.infinity, + } + } +} + +impl Neg for &AffinePoint +where + C: PrimeCurveParams, +{ + type Output = AffinePoint; + + fn neg(self) -> AffinePoint { + -(*self) + } +} + +// +// serde support +// + +#[cfg(feature = "serde")] +impl Serialize for AffinePoint +where + C: PrimeCurveParams, + FieldBytesSize: ModulusSize, + CompressedPoint: Copy, + as ArrayLength>::ArrayType: Copy, +{ + fn serialize(&self, serializer: S) -> core::result::Result + where + S: ser::Serializer, + { + self.to_encoded_point(true).serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, C> Deserialize<'de> for AffinePoint +where + C: PrimeCurveParams, + FieldBytes: Copy, + FieldBytesSize: ModulusSize, + CompressedPoint: Copy, +{ + fn deserialize(deserializer: D) -> core::result::Result + where + D: de::Deserializer<'de>, + { + EncodedPoint::::deserialize(deserializer)? + .try_into() + .map_err(de::Error::custom) + } +} diff --git a/src/rust/vendor/primeorder/src/dev.rs b/src/rust/vendor/primeorder/src/dev.rs new file mode 100644 index 000000000..a70027f07 --- /dev/null +++ b/src/rust/vendor/primeorder/src/dev.rs @@ -0,0 +1,157 @@ +//! Development-related functionality. + +// TODO(tarcieri): move all development-related macros into this module + +/// Implement projective arithmetic tests. +#[macro_export] +macro_rules! impl_projective_arithmetic_tests { + ( + $affine:tt, + $projective:tt, + $scalar:ty, + $add_vectors:expr, + $mul_vectors:expr + ) => { + /// Assert that the provided projective point matches the given test vector. + // TODO(tarcieri): use coordinate APIs. See zkcrypto/group#30 + macro_rules! assert_point_eq { + ($actual:expr, $expected:expr) => { + let (expected_x, expected_y) = $expected; + + let point = $actual.to_affine().to_encoded_point(false); + let (actual_x, actual_y) = match point.coordinates() { + sec1::Coordinates::Uncompressed { x, y } => (x, y), + _ => unreachable!(), + }; + + assert_eq!(&expected_x, actual_x.as_slice()); + assert_eq!(&expected_y, actual_y.as_slice()); + }; + } + + #[test] + fn affine_to_projective() { + let basepoint_affine = $affine::GENERATOR; + let basepoint_projective = $projective::GENERATOR; + + assert_eq!($projective::from(basepoint_affine), basepoint_projective,); + assert_eq!(basepoint_projective.to_affine(), basepoint_affine); + assert!(!bool::from(basepoint_projective.to_affine().is_identity())); + + assert!(bool::from($projective::IDENTITY.to_affine().is_identity())); + } + + #[test] + fn projective_identity_addition() { + let identity = $projective::IDENTITY; + let generator = $projective::GENERATOR; + + assert_eq!(identity + &generator, generator); + assert_eq!(generator + &identity, generator); + } + + #[test] + fn projective_mixed_addition() { + let identity = $projective::IDENTITY; + let basepoint_affine = $affine::GENERATOR; + let basepoint_projective = $projective::GENERATOR; + + assert_eq!(identity + &basepoint_affine, basepoint_projective); + assert_eq!( + basepoint_projective + &basepoint_affine, + basepoint_projective + &basepoint_projective + ); + } + + #[test] + fn test_vector_repeated_add() { + let generator = $projective::GENERATOR; + let mut p = generator; + + for i in 0..$add_vectors.len() { + assert_point_eq!(p, $add_vectors[i]); + p += &generator; + } + } + + #[test] + fn test_vector_repeated_add_mixed() { + let generator = $affine::GENERATOR; + let mut p = $projective::GENERATOR; + + for i in 0..$add_vectors.len() { + assert_point_eq!(p, $add_vectors[i]); + p += &generator; + } + } + + #[test] + fn test_vector_add_mixed_identity() { + let generator = $projective::GENERATOR; + let p0 = generator + $projective::IDENTITY; + let p1 = generator + $affine::IDENTITY; + assert_eq!(p0, p1); + } + + #[test] + fn test_vector_double_generator() { + let generator = $projective::GENERATOR; + let mut p = generator; + + for i in 0..2 { + assert_point_eq!(p, $add_vectors[i]); + p = p.double(); + } + } + + #[test] + fn projective_add_vs_double() { + let generator = $projective::GENERATOR; + assert_eq!(generator + &generator, generator.double()); + } + + #[test] + fn projective_add_and_sub() { + let basepoint_affine = $affine::GENERATOR; + let basepoint_projective = $projective::GENERATOR; + + assert_eq!( + (basepoint_projective + &basepoint_projective) - &basepoint_projective, + basepoint_projective + ); + assert_eq!( + (basepoint_projective + &basepoint_affine) - &basepoint_affine, + basepoint_projective + ); + } + + #[test] + fn projective_double_and_sub() { + let generator = $projective::GENERATOR; + assert_eq!(generator.double() - &generator, generator); + } + + #[test] + fn test_vector_scalar_mult() { + let generator = $projective::GENERATOR; + + for (k, coords) in $add_vectors + .iter() + .enumerate() + .map(|(k, coords)| (<$scalar>::from(k as u64 + 1), *coords)) + .chain($mul_vectors.iter().cloned().map(|(k, x, y)| { + ( + <$scalar>::from_repr( + $crate::generic_array::GenericArray::clone_from_slice(&k), + ) + .unwrap(), + (x, y), + ) + })) + { + let p = generator * &k; + assert_point_eq!(p, coords); + } + } + }; +} diff --git a/src/rust/vendor/primeorder/src/field.rs b/src/rust/vendor/primeorder/src/field.rs new file mode 100644 index 000000000..9a3b6eade --- /dev/null +++ b/src/rust/vendor/primeorder/src/field.rs @@ -0,0 +1,660 @@ +/// Implements a field element type whose internal representation is in +/// Montgomery form, providing a combination of trait impls and inherent impls +/// which are `const fn` where possible. +/// +/// Accepts a set of `const fn` arithmetic operation functions as arguments. +/// +/// # Inherent impls +/// - `const ZERO: Self` +/// - `const ONE: Self` (multiplicative identity) +/// - `pub fn from_bytes` +/// - `pub fn from_slice` +/// - `pub fn from_uint` +/// - `fn from_uint_unchecked` +/// - `pub fn to_bytes` +/// - `pub fn to_canonical` +/// - `pub fn is_odd` +/// - `pub fn is_zero` +/// - `pub fn double` +/// +/// NOTE: field implementations must provide their own inherent impls of +/// the following methods in order for the code generated by this macro to +/// compile: +/// +/// - `pub fn invert` +/// - `pub fn sqrt` +/// +/// # Trait impls +/// - `AsRef<$arr>` +/// - `ConditionallySelectable` +/// - `ConstantTimeEq` +/// - `ConstantTimeGreater` +/// - `ConstantTimeLess` +/// - `Default` +/// - `DefaultIsZeroes` +/// - `Eq` +/// - `Field` +/// - `PartialEq` +/// +/// ## Ops +/// - `Add` +/// - `AddAssign` +/// - `Sub` +/// - `SubAssign` +/// - `Mul` +/// - `MulAssign` +/// - `Neg` +#[macro_export] +macro_rules! impl_mont_field_element { + ( + $curve:tt, + $fe:tt, + $bytes:ty, + $uint:ty, + $modulus:expr, + $arr:ty, + $from_mont:ident, + $to_mont:ident, + $add:ident, + $sub:ident, + $mul:ident, + $neg:ident, + $square:ident + ) => { + impl $fe { + /// Zero element. + pub const ZERO: Self = Self(<$uint>::ZERO); + + /// Multiplicative identity. + pub const ONE: Self = Self::from_uint_unchecked(<$uint>::ONE); + + /// Create a [` + #[doc = stringify!($fe)] + /// `] from a canonical big-endian representation. + pub fn from_bytes(repr: &$bytes) -> $crate::elliptic_curve::subtle::CtOption { + use $crate::elliptic_curve::FieldBytesEncoding; + Self::from_uint(FieldBytesEncoding::<$curve>::decode_field_bytes(repr)) + } + + /// Decode [` + #[doc = stringify!($fe)] + /// `] from a big endian byte slice. + pub fn from_slice(slice: &[u8]) -> $crate::elliptic_curve::Result { + use $crate::elliptic_curve::generic_array::{typenum::Unsigned, GenericArray}; + + if slice.len() != <$curve as $crate::elliptic_curve::Curve>::FieldBytesSize::USIZE { + return Err($crate::elliptic_curve::Error); + } + + Option::from(Self::from_bytes(GenericArray::from_slice(slice))) + .ok_or($crate::elliptic_curve::Error) + } + + /// Decode [` + #[doc = stringify!($fe)] + /// `] + /// from [` + #[doc = stringify!($uint)] + /// `] converting it into Montgomery form: + /// + /// ```text + /// w * R^2 * R^-1 mod p = wR mod p + /// ``` + pub fn from_uint(uint: $uint) -> $crate::elliptic_curve::subtle::CtOption { + use $crate::elliptic_curve::subtle::ConstantTimeLess as _; + let is_some = uint.ct_lt(&$modulus); + $crate::elliptic_curve::subtle::CtOption::new( + Self::from_uint_unchecked(uint), + is_some, + ) + } + + /// Parse a [` + #[doc = stringify!($fe)] + /// `] from big endian hex-encoded bytes. + /// + /// Does *not* perform a check that the field element does not overflow the order. + /// + /// This method is primarily intended for defining internal constants. + #[allow(dead_code)] + pub(crate) const fn from_hex(hex: &str) -> Self { + Self::from_uint_unchecked(<$uint>::from_be_hex(hex)) + } + + /// Convert a `u64` into a [` + #[doc = stringify!($fe)] + /// `]. + pub const fn from_u64(w: u64) -> Self { + Self::from_uint_unchecked(<$uint>::from_u64(w)) + } + + /// Decode [` + #[doc = stringify!($fe)] + /// `] from [` + #[doc = stringify!($uint)] + /// `] converting it into Montgomery form. + /// + /// Does *not* perform a check that the field element does not overflow the order. + /// + /// Used incorrectly this can lead to invalid results! + pub(crate) const fn from_uint_unchecked(w: $uint) -> Self { + Self(<$uint>::from_words($to_mont(w.as_words()))) + } + + /// Returns the big-endian encoding of this [` + #[doc = stringify!($fe)] + /// `]. + pub fn to_bytes(self) -> $bytes { + use $crate::elliptic_curve::FieldBytesEncoding; + FieldBytesEncoding::<$curve>::encode_field_bytes(&self.to_canonical()) + } + + /// Translate [` + #[doc = stringify!($fe)] + /// `] out of the Montgomery domain, returning a [` + #[doc = stringify!($uint)] + /// `] in canonical form. + #[inline] + pub const fn to_canonical(self) -> $uint { + <$uint>::from_words($from_mont(self.0.as_words())) + } + + /// Determine if this [` + #[doc = stringify!($fe)] + /// `] is odd in the SEC1 sense: `self mod 2 == 1`. + /// + /// # Returns + /// + /// If odd, return `Choice(1)`. Otherwise, return `Choice(0)`. + pub fn is_odd(&self) -> Choice { + use $crate::elliptic_curve::bigint::Integer; + self.to_canonical().is_odd() + } + + /// Determine if this [` + #[doc = stringify!($fe)] + /// `] is even in the SEC1 sense: `self mod 2 == 0`. + /// + /// # Returns + /// + /// If even, return `Choice(1)`. Otherwise, return `Choice(0)`. + pub fn is_even(&self) -> Choice { + !self.is_odd() + } + + /// Determine if this [` + #[doc = stringify!($fe)] + /// `] is zero. + /// + /// # Returns + /// + /// If zero, return `Choice(1)`. Otherwise, return `Choice(0)`. + pub fn is_zero(&self) -> Choice { + self.ct_eq(&Self::ZERO) + } + + /// Add elements. + pub const fn add(&self, rhs: &Self) -> Self { + Self(<$uint>::from_words($add( + self.0.as_words(), + rhs.0.as_words(), + ))) + } + + /// Double element (add it to itself). + #[must_use] + pub const fn double(&self) -> Self { + self.add(self) + } + + /// Subtract elements. + pub const fn sub(&self, rhs: &Self) -> Self { + Self(<$uint>::from_words($sub( + self.0.as_words(), + rhs.0.as_words(), + ))) + } + + /// Multiply elements. + pub const fn multiply(&self, rhs: &Self) -> Self { + Self(<$uint>::from_words($mul( + self.0.as_words(), + rhs.0.as_words(), + ))) + } + + /// Negate element. + pub const fn neg(&self) -> Self { + Self(<$uint>::from_words($neg(self.0.as_words()))) + } + + /// Compute modular square. + #[must_use] + pub const fn square(&self) -> Self { + Self(<$uint>::from_words($square(self.0.as_words()))) + } + + /// Returns `self^exp`, where `exp` is a little-endian integer exponent. + /// + /// **This operation is variable time with respect to the exponent.** + /// + /// If the exponent is fixed, this operation is effectively constant time. + pub const fn pow_vartime(&self, exp: &[u64]) -> Self { + let mut res = Self::ONE; + let mut i = exp.len(); + + while i > 0 { + i -= 1; + + let mut j = 64; + while j > 0 { + j -= 1; + res = res.square(); + + if ((exp[i] >> j) & 1) == 1 { + res = res.multiply(self); + } + } + } + + res + } + } + + $crate::impl_mont_field_element_arithmetic!( + $fe, $bytes, $uint, $arr, $add, $sub, $mul, $neg + ); + }; +} + +/// Add arithmetic impls to the given field element. +#[macro_export] +macro_rules! impl_mont_field_element_arithmetic { + ( + $fe:tt, + $bytes:ty, + $uint:ty, + $arr:ty, + $add:ident, + $sub:ident, + $mul:ident, + $neg:ident + ) => { + impl AsRef<$arr> for $fe { + fn as_ref(&self) -> &$arr { + self.0.as_ref() + } + } + + impl Default for $fe { + fn default() -> Self { + Self::ZERO + } + } + + impl Eq for $fe {} + impl PartialEq for $fe { + fn eq(&self, rhs: &Self) -> bool { + self.0.ct_eq(&(rhs.0)).into() + } + } + + impl From for $fe { + fn from(n: u32) -> $fe { + Self::from_uint_unchecked(<$uint>::from(n)) + } + } + + impl From for $fe { + fn from(n: u64) -> $fe { + Self::from_uint_unchecked(<$uint>::from(n)) + } + } + + impl From for $fe { + fn from(n: u128) -> $fe { + Self::from_uint_unchecked(<$uint>::from(n)) + } + } + + impl $crate::elliptic_curve::subtle::ConditionallySelectable for $fe { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self(<$uint>::conditional_select(&a.0, &b.0, choice)) + } + } + + impl $crate::elliptic_curve::subtle::ConstantTimeEq for $fe { + fn ct_eq(&self, other: &Self) -> $crate::elliptic_curve::subtle::Choice { + self.0.ct_eq(&other.0) + } + } + + impl $crate::elliptic_curve::subtle::ConstantTimeGreater for $fe { + fn ct_gt(&self, other: &Self) -> $crate::elliptic_curve::subtle::Choice { + self.0.ct_gt(&other.0) + } + } + + impl $crate::elliptic_curve::subtle::ConstantTimeLess for $fe { + fn ct_lt(&self, other: &Self) -> $crate::elliptic_curve::subtle::Choice { + self.0.ct_lt(&other.0) + } + } + + impl $crate::elliptic_curve::zeroize::DefaultIsZeroes for $fe {} + + impl $crate::elliptic_curve::ff::Field for $fe { + const ZERO: Self = Self::ZERO; + const ONE: Self = Self::ONE; + + fn random(mut rng: impl $crate::elliptic_curve::rand_core::RngCore) -> Self { + // NOTE: can't use ScalarPrimitive::random due to CryptoRng bound + let mut bytes = <$bytes>::default(); + + loop { + rng.fill_bytes(&mut bytes); + if let Some(fe) = Self::from_bytes(&bytes).into() { + return fe; + } + } + } + + fn is_zero(&self) -> Choice { + Self::ZERO.ct_eq(self) + } + + #[must_use] + fn square(&self) -> Self { + self.square() + } + + #[must_use] + fn double(&self) -> Self { + self.double() + } + + fn invert(&self) -> CtOption { + self.invert() + } + + fn sqrt(&self) -> CtOption { + self.sqrt() + } + + fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { + $crate::elliptic_curve::ff::helpers::sqrt_ratio_generic(num, div) + } + } + + $crate::impl_field_op!($fe, Add, add, $add); + $crate::impl_field_op!($fe, Sub, sub, $sub); + $crate::impl_field_op!($fe, Mul, mul, $mul); + + impl AddAssign<$fe> for $fe { + #[inline] + fn add_assign(&mut self, other: $fe) { + *self = *self + other; + } + } + + impl AddAssign<&$fe> for $fe { + #[inline] + fn add_assign(&mut self, other: &$fe) { + *self = *self + other; + } + } + + impl SubAssign<$fe> for $fe { + #[inline] + fn sub_assign(&mut self, other: $fe) { + *self = *self - other; + } + } + + impl SubAssign<&$fe> for $fe { + #[inline] + fn sub_assign(&mut self, other: &$fe) { + *self = *self - other; + } + } + + impl MulAssign<&$fe> for $fe { + #[inline] + fn mul_assign(&mut self, other: &$fe) { + *self = *self * other; + } + } + + impl MulAssign for $fe { + #[inline] + fn mul_assign(&mut self, other: $fe) { + *self = *self * other; + } + } + + impl Neg for $fe { + type Output = $fe; + + #[inline] + fn neg(self) -> $fe { + Self($neg(self.as_ref()).into()) + } + } + + impl Sum for $fe { + fn sum>(iter: I) -> Self { + iter.reduce(core::ops::Add::add).unwrap_or(Self::ZERO) + } + } + + impl<'a> Sum<&'a $fe> for $fe { + fn sum>(iter: I) -> Self { + iter.copied().sum() + } + } + + impl Product for $fe { + fn product>(iter: I) -> Self { + iter.reduce(core::ops::Mul::mul).unwrap_or(Self::ONE) + } + } + + impl<'a> Product<&'a $fe> for $fe { + fn product>(iter: I) -> Self { + iter.copied().product() + } + } + }; +} + +/// Emit impls for a `core::ops` trait for all combinations of reference types, +/// which thunk to the given function. +#[macro_export] +macro_rules! impl_field_op { + ($fe:tt, $op:tt, $op_fn:ident, $func:ident) => { + impl ::core::ops::$op for $fe { + type Output = $fe; + + #[inline] + fn $op_fn(self, rhs: $fe) -> $fe { + $fe($func(self.as_ref(), rhs.as_ref()).into()) + } + } + + impl ::core::ops::$op<&$fe> for $fe { + type Output = $fe; + + #[inline] + fn $op_fn(self, rhs: &$fe) -> $fe { + $fe($func(self.as_ref(), rhs.as_ref()).into()) + } + } + + impl ::core::ops::$op<&$fe> for &$fe { + type Output = $fe; + + #[inline] + fn $op_fn(self, rhs: &$fe) -> $fe { + $fe($func(self.as_ref(), rhs.as_ref()).into()) + } + } + }; +} + +/// Implement Bernstein-Yang field element inversion. +#[macro_export] +macro_rules! impl_bernstein_yang_invert { + ( + $a:expr, + $one:expr, + $d:expr, + $nlimbs:expr, + $word:ty, + $from_mont:ident, + $mul:ident, + $neg:ident, + $divstep_precomp:ident, + $divstep:ident, + $msat:ident, + $selectznz:ident, + ) => {{ + // See Bernstein-Yang 2019 p.366 + const ITERATIONS: usize = (49 * $d + 57) / 17; + + let a = $from_mont($a); + let mut d = 1; + let mut f = $msat(); + let mut g = [0; $nlimbs + 1]; + let mut v = [0; $nlimbs]; + let mut r = $one; + let mut i = 0; + let mut j = 0; + + while j < $nlimbs { + g[j] = a[j]; + j += 1; + } + + while i < ITERATIONS - ITERATIONS % 2 { + let (out1, out2, out3, out4, out5) = $divstep(d, &f, &g, &v, &r); + let (out1, out2, out3, out4, out5) = $divstep(out1, &out2, &out3, &out4, &out5); + d = out1; + f = out2; + g = out3; + v = out4; + r = out5; + i += 2; + } + + if ITERATIONS % 2 != 0 { + let (_out1, out2, _out3, out4, _out5) = $divstep(d, &f, &g, &v, &r); + v = out4; + f = out2; + } + + let s = ((f[f.len() - 1] >> <$word>::BITS - 1) & 1) as u8; + let v = $selectznz(s, &v, &$neg(&v)); + $mul(&v, &$divstep_precomp()) + }}; +} + +/// Implement field element identity tests. +#[macro_export] +macro_rules! impl_field_identity_tests { + ($fe:tt) => { + #[test] + fn zero_is_additive_identity() { + let zero = $fe::ZERO; + let one = $fe::ONE; + assert_eq!(zero.add(&zero), zero); + assert_eq!(one.add(&zero), one); + } + + #[test] + fn one_is_multiplicative_identity() { + let one = $fe::ONE; + assert_eq!(one.multiply(&one), one); + } + }; +} + +/// Implement field element inversion tests. +#[macro_export] +macro_rules! impl_field_invert_tests { + ($fe:tt) => { + #[test] + fn invert() { + let one = $fe::ONE; + assert_eq!(one.invert().unwrap(), one); + + let three = one + &one + &one; + let inv_three = three.invert().unwrap(); + assert_eq!(three * &inv_three, one); + + let minus_three = -three; + let inv_minus_three = minus_three.invert().unwrap(); + assert_eq!(inv_minus_three, -inv_three); + assert_eq!(three * &inv_minus_three, -one); + } + }; +} + +/// Implement field element square root tests. +#[macro_export] +macro_rules! impl_field_sqrt_tests { + ($fe:tt) => { + #[test] + fn sqrt() { + for &n in &[1u64, 4, 9, 16, 25, 36, 49, 64] { + let fe = $fe::from(n); + let sqrt = fe.sqrt().unwrap(); + assert_eq!(sqrt.square(), fe); + } + } + }; +} + +/// Implement tests for the `PrimeField` trait. +#[macro_export] +macro_rules! impl_primefield_tests { + ($fe:tt, $t:expr) => { + #[test] + fn two_inv_constant() { + assert_eq!($fe::from(2u32) * $fe::TWO_INV, $fe::ONE); + } + + #[test] + fn root_of_unity_constant() { + assert!($fe::S < 128); + let two_to_s = 1u128 << $fe::S; + + // ROOT_OF_UNITY^{2^s} mod m == 1 + assert_eq!( + $fe::ROOT_OF_UNITY.pow_vartime(&[ + (two_to_s & 0xFFFFFFFFFFFFFFFF) as u64, + (two_to_s >> 64) as u64, + 0, + 0 + ]), + $fe::ONE + ); + + // MULTIPLICATIVE_GENERATOR^{t} mod m == ROOT_OF_UNITY + assert_eq!( + $fe::MULTIPLICATIVE_GENERATOR.pow_vartime(&$t), + $fe::ROOT_OF_UNITY + ) + } + + #[test] + fn root_of_unity_inv_constant() { + assert_eq!($fe::ROOT_OF_UNITY * $fe::ROOT_OF_UNITY_INV, $fe::ONE); + } + + #[test] + fn delta_constant() { + // DELTA^{t} mod m == 1 + assert_eq!($fe::DELTA.pow_vartime(&$t), $fe::ONE); + } + }; +} diff --git a/src/rust/vendor/primeorder/src/lib.rs b/src/rust/vendor/primeorder/src/lib.rs new file mode 100644 index 000000000..46b1860a9 --- /dev/null +++ b/src/rust/vendor/primeorder/src/lib.rs @@ -0,0 +1,53 @@ +#![no_std] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" +)] +#![forbid(unsafe_code)] +#![warn(missing_docs, rust_2018_idioms, unused_qualifications)] +#![doc = include_str!("../README.md")] + +#[cfg(feature = "alloc")] +#[macro_use] +extern crate alloc; + +pub mod point_arithmetic; + +mod affine; +#[cfg(feature = "dev")] +mod dev; +mod field; +mod projective; + +pub use crate::{affine::AffinePoint, projective::ProjectivePoint}; +pub use elliptic_curve::{ + self, generic_array, point::Double, Field, FieldBytes, PrimeCurve, PrimeField, +}; + +use elliptic_curve::CurveArithmetic; + +/// Parameters for elliptic curves of prime order which can be described by the +/// short Weierstrass equation. +pub trait PrimeCurveParams: + PrimeCurve + + CurveArithmetic + + CurveArithmetic> + + CurveArithmetic> +{ + /// Base field element type. + // TODO(tarcieri): add `Invert` bound + type FieldElement: PrimeField>; + + /// [Point arithmetic](point_arithmetic) implementation, might be optimized for this specific curve + type PointArithmetic: point_arithmetic::PointArithmetic; + + /// Coefficient `a` in the curve equation. + const EQUATION_A: Self::FieldElement; + + /// Coefficient `b` in the curve equation. + const EQUATION_B: Self::FieldElement; + + /// Generator point's affine coordinates: (x, y). + const GENERATOR: (Self::FieldElement, Self::FieldElement); +} diff --git a/src/rust/vendor/primeorder/src/point_arithmetic.rs b/src/rust/vendor/primeorder/src/point_arithmetic.rs new file mode 100644 index 000000000..b41308992 --- /dev/null +++ b/src/rust/vendor/primeorder/src/point_arithmetic.rs @@ -0,0 +1,318 @@ +//! Point arithmetic implementation optimised for different curve equations +//! +//! Support for formulas specialized to the short Weierstrass equation's +//! 𝒂-coefficient. + +use elliptic_curve::{subtle::ConditionallySelectable, Field}; + +use crate::{AffinePoint, PrimeCurveParams, ProjectivePoint}; + +mod sealed { + use crate::{AffinePoint, PrimeCurveParams, ProjectivePoint}; + + /// Elliptic point arithmetic implementation + /// + /// Provides implementation of point arithmetic (point addition, point doubling) which + /// might be optimized for the curve. + pub trait PointArithmetic { + /// Returns `lhs + rhs` + fn add(lhs: &ProjectivePoint, rhs: &ProjectivePoint) -> ProjectivePoint; + + /// Returns `lhs + rhs` + fn add_mixed(lhs: &ProjectivePoint, rhs: &AffinePoint) -> ProjectivePoint; + + /// Returns `point + point` + fn double(point: &ProjectivePoint) -> ProjectivePoint; + } +} + +/// Allow crate-local visibility +pub(crate) use sealed::PointArithmetic; + +/// The 𝒂-coefficient of the short Weierstrass equation does not have specific +/// properties which allow for an optimized implementation. +pub struct EquationAIsGeneric {} + +impl PointArithmetic for EquationAIsGeneric { + /// Implements complete addition for any curve + /// + /// Implements the complete addition formula from [Renes-Costello-Batina 2015] + /// (Algorithm 1). The comments after each line indicate which algorithm steps + /// are being performed. + /// + /// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060 + fn add(lhs: &ProjectivePoint, rhs: &ProjectivePoint) -> ProjectivePoint { + let b3 = C::FieldElement::from(3) * C::EQUATION_B; + + let t0 = lhs.x * rhs.x; // 1 + let t1 = lhs.y * rhs.y; // 2 + let t2 = lhs.z * rhs.z; // 3 + let t3 = lhs.x + lhs.y; // 4 + let t4 = rhs.x + rhs.y; // 5 + let t3 = t3 * t4; // 6 + let t4 = t0 + t1; // 7 + let t3 = t3 - t4; // 8 + let t4 = lhs.x + lhs.z; // 9 + let t5 = rhs.x + rhs.z; // 10 + let t4 = t4 * t5; // 11 + let t5 = t0 + t2; // 12 + let t4 = t4 - t5; // 13 + let t5 = lhs.y + lhs.z; // 14 + let x3 = rhs.y + rhs.z; // 15 + let t5 = t5 * x3; // 16 + let x3 = t1 + t2; // 17 + let t5 = t5 - x3; // 18 + let z3 = C::EQUATION_A * t4; // 19 + let x3 = b3 * t2; // 20 + let z3 = x3 + z3; // 21 + let x3 = t1 - z3; // 22 + let z3 = t1 + z3; // 23 + let y3 = x3 * z3; // 24 + let t1 = t0 + t0; // 25 + let t1 = t1 + t0; // 26 + let t2 = C::EQUATION_A * t2; // 27 + let t4 = b3 * t4; // 28 + let t1 = t1 + t2; // 29 + let t2 = t0 - t2; // 30 + let t2 = C::EQUATION_A * t2; // 31 + let t4 = t4 + t2; // 32 + let t0 = t1 * t4; // 33 + let y3 = y3 + t0; // 34 + let t0 = t5 * t4; // 35 + let x3 = t3 * x3; // 36 + let x3 = x3 - t0; // 37 + let t0 = t3 * t1; // 38 + let z3 = t5 * z3; // 39 + let z3 = z3 + t0; // 40 + + ProjectivePoint { + x: x3, + y: y3, + z: z3, + } + } + + /// Implements complete mixed addition for curves with any `a` + /// + /// Implements the complete mixed addition formula from [Renes-Costello-Batina 2015] + /// (Algorithm 2). The comments after each line indicate which algorithm + /// steps are being performed. + /// + /// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060 + fn add_mixed(lhs: &ProjectivePoint, rhs: &AffinePoint) -> ProjectivePoint { + let b3 = C::EQUATION_B * C::FieldElement::from(3); + + let t0 = lhs.x * rhs.x; // 1 + let t1 = lhs.y * rhs.y; // 2 + let t3 = rhs.x + rhs.y; // 3 + let t4 = lhs.x + lhs.y; // 4 + let t3 = t3 * t4; // 5 + let t4 = t0 + t1; // 6 + let t3 = t3 - t4; // 7 + let t4 = rhs.x * lhs.z; // 8 + let t4 = t4 + lhs.x; // 9 + let t5 = rhs.y * lhs.z; // 10 + let t5 = t5 + lhs.y; // 11 + let z3 = C::EQUATION_A * t4; // 12 + let x3 = b3 * lhs.z; // 13 + let z3 = x3 + z3; // 14 + let x3 = t1 - z3; // 15 + let z3 = t1 + z3; // 16 + let y3 = x3 * z3; // 17 + let t1 = t0 + t0; // 18 + let t1 = t1 + t0; // 19 + let t2 = C::EQUATION_A * lhs.z; // 20 + let t4 = b3 * t4; // 21 + let t1 = t1 + t2; // 22 + let t2 = t0 - t2; // 23 + let t2 = C::EQUATION_A * t2; // 24 + let t4 = t4 + t2; // 25 + let t0 = t1 * t4; // 26 + let y3 = y3 + t0; // 27 + let t0 = t5 * t4; // 28 + let x3 = t3 * x3; // 29 + let x3 = x3 - t0; // 30 + let t0 = t3 * t1; // 31 + let z3 = t5 * z3; // 32 + let z3 = z3 + t0; // 33 + + let mut ret = ProjectivePoint { + x: x3, + y: y3, + z: z3, + }; + ret.conditional_assign(lhs, rhs.is_identity()); + ret + } + + /// Implements point doubling for curves with any `a` + /// + /// Implements the exception-free point doubling formula from [Renes-Costello-Batina 2015] + /// (Algorithm 3). The comments after each line indicate which algorithm + /// steps are being performed. + /// + /// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060 + fn double(point: &ProjectivePoint) -> ProjectivePoint { + let b3 = C::EQUATION_B * C::FieldElement::from(3); + + let t0 = point.x * point.x; // 1 + let t1 = point.y * point.y; // 2 + let t2 = point.z * point.z; // 3 + let t3 = point.x * point.y; // 4 + let t3 = t3 + t3; // 5 + let z3 = point.x * point.z; // 6 + let z3 = z3 + z3; // 7 + let x3 = C::EQUATION_A * z3; // 8 + let y3 = b3 * t2; // 9 + let y3 = x3 + y3; // 10 + let x3 = t1 - y3; // 11 + let y3 = t1 + y3; // 12 + let y3 = x3 * y3; // 13 + let x3 = t3 * x3; // 14 + let z3 = b3 * z3; // 15 + let t2 = C::EQUATION_A * t2; // 16 + let t3 = t0 - t2; // 17 + let t3 = C::EQUATION_A * t3; // 18 + let t3 = t3 + z3; // 19 + let z3 = t0 + t0; // 20 + let t0 = z3 + t0; // 21 + let t0 = t0 + t2; // 22 + let t0 = t0 * t3; // 23 + let y3 = y3 + t0; // 24 + let t2 = point.y * point.z; // 25 + let t2 = t2 + t2; // 26 + let t0 = t2 * t3; // 27 + let x3 = x3 - t0; // 28 + let z3 = t2 * t1; // 29 + let z3 = z3 + z3; // 30 + let z3 = z3 + z3; // 31 + + ProjectivePoint { + x: x3, + y: y3, + z: z3, + } + } +} + +/// The 𝒂-coefficient of the short Weierstrass equation is -3. +pub struct EquationAIsMinusThree {} + +impl PointArithmetic for EquationAIsMinusThree { + /// Implements complete addition for curves with `a = -3` + /// + /// Implements the complete addition formula from [Renes-Costello-Batina 2015] + /// (Algorithm 4). The comments after each line indicate which algorithm steps + /// are being performed. + /// + /// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060 + fn add(lhs: &ProjectivePoint, rhs: &ProjectivePoint) -> ProjectivePoint { + debug_assert_eq!( + C::EQUATION_A, + -C::FieldElement::from(3), + "this implementation is only valid for C::EQUATION_A = -3" + ); + + let xx = lhs.x * rhs.x; // 1 + let yy = lhs.y * rhs.y; // 2 + let zz = lhs.z * rhs.z; // 3 + let xy_pairs = ((lhs.x + lhs.y) * (rhs.x + rhs.y)) - (xx + yy); // 4, 5, 6, 7, 8 + let yz_pairs = ((lhs.y + lhs.z) * (rhs.y + rhs.z)) - (yy + zz); // 9, 10, 11, 12, 13 + let xz_pairs = ((lhs.x + lhs.z) * (rhs.x + rhs.z)) - (xx + zz); // 14, 15, 16, 17, 18 + + let bzz_part = xz_pairs - (C::EQUATION_B * zz); // 19, 20 + let bzz3_part = bzz_part.double() + bzz_part; // 21, 22 + let yy_m_bzz3 = yy - bzz3_part; // 23 + let yy_p_bzz3 = yy + bzz3_part; // 24 + + let zz3 = zz.double() + zz; // 26, 27 + let bxz_part = (C::EQUATION_B * xz_pairs) - (zz3 + xx); // 25, 28, 29 + let bxz3_part = bxz_part.double() + bxz_part; // 30, 31 + let xx3_m_zz3 = xx.double() + xx - zz3; // 32, 33, 34 + + ProjectivePoint { + x: (yy_p_bzz3 * xy_pairs) - (yz_pairs * bxz3_part), // 35, 39, 40 + y: (yy_p_bzz3 * yy_m_bzz3) + (xx3_m_zz3 * bxz3_part), // 36, 37, 38 + z: (yy_m_bzz3 * yz_pairs) + (xy_pairs * xx3_m_zz3), // 41, 42, 43 + } + } + + /// Implements complete mixed addition for curves with `a = -3` + /// + /// Implements the complete mixed addition formula from [Renes-Costello-Batina 2015] + /// (Algorithm 5). The comments after each line indicate which algorithm + /// steps are being performed. + /// + /// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060 + fn add_mixed(lhs: &ProjectivePoint, rhs: &AffinePoint) -> ProjectivePoint { + debug_assert_eq!( + C::EQUATION_A, + -C::FieldElement::from(3), + "this implementation is only valid for C::EQUATION_A = -3" + ); + + let xx = lhs.x * rhs.x; // 1 + let yy = lhs.y * rhs.y; // 2 + let xy_pairs = ((lhs.x + lhs.y) * (rhs.x + rhs.y)) - (xx + yy); // 3, 4, 5, 6, 7 + let yz_pairs = (rhs.y * lhs.z) + lhs.y; // 8, 9 (t4) + let xz_pairs = (rhs.x * lhs.z) + lhs.x; // 10, 11 (y3) + + let bz_part = xz_pairs - (C::EQUATION_B * lhs.z); // 12, 13 + let bz3_part = bz_part.double() + bz_part; // 14, 15 + let yy_m_bzz3 = yy - bz3_part; // 16 + let yy_p_bzz3 = yy + bz3_part; // 17 + + let z3 = lhs.z.double() + lhs.z; // 19, 20 + let bxz_part = (C::EQUATION_B * xz_pairs) - (z3 + xx); // 18, 21, 22 + let bxz3_part = bxz_part.double() + bxz_part; // 23, 24 + let xx3_m_zz3 = xx.double() + xx - z3; // 25, 26, 27 + + let mut ret = ProjectivePoint { + x: (yy_p_bzz3 * xy_pairs) - (yz_pairs * bxz3_part), // 28, 32, 33 + y: (yy_p_bzz3 * yy_m_bzz3) + (xx3_m_zz3 * bxz3_part), // 29, 30, 31 + z: (yy_m_bzz3 * yz_pairs) + (xy_pairs * xx3_m_zz3), // 34, 35, 36 + }; + ret.conditional_assign(lhs, rhs.is_identity()); + ret + } + + /// Implements point doubling for curves with `a = -3` + /// + /// Implements the exception-free point doubling formula from [Renes-Costello-Batina 2015] + /// (Algorithm 6). The comments after each line indicate which algorithm + /// steps are being performed. + /// + /// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060 + fn double(point: &ProjectivePoint) -> ProjectivePoint { + debug_assert_eq!( + C::EQUATION_A, + -C::FieldElement::from(3), + "this implementation is only valid for C::EQUATION_A = -3" + ); + + let xx = point.x.square(); // 1 + let yy = point.y.square(); // 2 + let zz = point.z.square(); // 3 + let xy2 = (point.x * point.y).double(); // 4, 5 + let xz2 = (point.x * point.z).double(); // 6, 7 + + let bzz_part = (C::EQUATION_B * zz) - xz2; // 8, 9 + let bzz3_part = bzz_part.double() + bzz_part; // 10, 11 + let yy_m_bzz3 = yy - bzz3_part; // 12 + let yy_p_bzz3 = yy + bzz3_part; // 13 + let y_frag = yy_p_bzz3 * yy_m_bzz3; // 14 + let x_frag = yy_m_bzz3 * xy2; // 15 + + let zz3 = zz.double() + zz; // 16, 17 + let bxz2_part = (C::EQUATION_B * xz2) - (zz3 + xx); // 18, 19, 20 + let bxz6_part = bxz2_part.double() + bxz2_part; // 21, 22 + let xx3_m_zz3 = xx.double() + xx - zz3; // 23, 24, 25 + + let y = y_frag + (xx3_m_zz3 * bxz6_part); // 26, 27 + let yz2 = (point.y * point.z).double(); // 28, 29 + let x = x_frag - (bxz6_part * yz2); // 30, 31 + let z = (yz2 * yy).double().double(); // 32, 33, 34 + + ProjectivePoint { x, y, z } + } +} diff --git a/src/rust/vendor/primeorder/src/projective.rs b/src/rust/vendor/primeorder/src/projective.rs new file mode 100644 index 000000000..884b13745 --- /dev/null +++ b/src/rust/vendor/primeorder/src/projective.rs @@ -0,0 +1,781 @@ +//! Projective curve points. + +#![allow(clippy::needless_range_loop, clippy::op_ref)] + +use crate::{point_arithmetic::PointArithmetic, AffinePoint, Field, PrimeCurveParams}; +use core::{ + borrow::Borrow, + iter::Sum, + ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, +}; +use elliptic_curve::{ + bigint::{ArrayEncoding, Integer}, + generic_array::ArrayLength, + group::{ + self, + cofactor::CofactorGroup, + prime::{PrimeCurve, PrimeGroup}, + Group, GroupEncoding, + }, + ops::{BatchInvert, Invert, LinearCombination, MulByGenerator}, + point::Double, + rand_core::RngCore, + sec1::{ + CompressedPoint, EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint, + UncompressedPointSize, + }, + subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, + zeroize::DefaultIsZeroes, + BatchNormalize, Error, FieldBytes, FieldBytesSize, PublicKey, Result, Scalar, +}; + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +/// Point on a Weierstrass curve in projective coordinates. +#[derive(Clone, Copy, Debug)] +pub struct ProjectivePoint { + pub(crate) x: C::FieldElement, + pub(crate) y: C::FieldElement, + pub(crate) z: C::FieldElement, +} + +impl ProjectivePoint +where + C: PrimeCurveParams, +{ + /// Additive identity of the group a.k.a. the point at infinity. + pub const IDENTITY: Self = Self { + x: C::FieldElement::ZERO, + y: C::FieldElement::ONE, + z: C::FieldElement::ZERO, + }; + + /// Base point of the curve. + pub const GENERATOR: Self = Self { + x: C::GENERATOR.0, + y: C::GENERATOR.1, + z: C::FieldElement::ONE, + }; + + /// Returns the affine representation of this point, or `None` if it is the identity. + pub fn to_affine(&self) -> AffinePoint { + ::invert(&self.z) + .map(|zinv| self.to_affine_internal(zinv)) + .unwrap_or(AffinePoint::IDENTITY) + } + + pub(super) fn to_affine_internal(self, zinv: C::FieldElement) -> AffinePoint { + AffinePoint { + x: self.x * &zinv, + y: self.y * &zinv, + infinity: 0, + } + } + + /// Returns `-self`. + pub fn neg(&self) -> Self { + Self { + x: self.x, + y: -self.y, + z: self.z, + } + } + + /// Returns `self + other`. + pub fn add(&self, other: &Self) -> Self { + C::PointArithmetic::add(self, other) + } + + /// Returns `self + other`. + fn add_mixed(&self, other: &AffinePoint) -> Self { + C::PointArithmetic::add_mixed(self, other) + } + + /// Returns `self - other`. + pub fn sub(&self, other: &Self) -> Self { + self.add(&other.neg()) + } + + /// Returns `self - other`. + fn sub_mixed(&self, other: &AffinePoint) -> Self { + self.add_mixed(&other.neg()) + } + + /// Returns `[k] self`. + fn mul(&self, k: &Scalar) -> Self + where + Self: Double, + { + let k = Into::::into(*k).to_le_byte_array(); + + let mut pc = [Self::default(); 16]; + pc[0] = Self::IDENTITY; + pc[1] = *self; + + for i in 2..16 { + pc[i] = if i % 2 == 0 { + Double::double(&pc[i / 2]) + } else { + pc[i - 1].add(self) + }; + } + + let mut q = Self::IDENTITY; + let mut pos = C::Uint::BITS - 4; + + loop { + let slot = (k[pos >> 3] >> (pos & 7)) & 0xf; + + let mut t = ProjectivePoint::IDENTITY; + + for i in 1..16 { + t.conditional_assign( + &pc[i], + Choice::from(((slot as usize ^ i).wrapping_sub(1) >> 8) as u8 & 1), + ); + } + + q = q.add(&t); + + if pos == 0 { + break; + } + + q = Double::double(&Double::double(&Double::double(&Double::double(&q)))); + pos -= 4; + } + + q + } +} + +impl CofactorGroup for ProjectivePoint +where + Self: Double, + C: PrimeCurveParams, + FieldBytes: Copy, + FieldBytesSize: ModulusSize, + CompressedPoint: Copy, + as ArrayLength>::ArrayType: Copy, +{ + type Subgroup = Self; + + fn clear_cofactor(&self) -> Self::Subgroup { + *self + } + + fn into_subgroup(self) -> CtOption { + CtOption::new(self, 1.into()) + } + + fn is_torsion_free(&self) -> Choice { + 1.into() + } +} + +impl ConditionallySelectable for ProjectivePoint +where + C: PrimeCurveParams, +{ + #[inline(always)] + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self { + x: C::FieldElement::conditional_select(&a.x, &b.x, choice), + y: C::FieldElement::conditional_select(&a.y, &b.y, choice), + z: C::FieldElement::conditional_select(&a.z, &b.z, choice), + } + } +} + +impl ConstantTimeEq for ProjectivePoint +where + C: PrimeCurveParams, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.to_affine().ct_eq(&other.to_affine()) + } +} + +impl Default for ProjectivePoint +where + C: PrimeCurveParams, +{ + fn default() -> Self { + Self::IDENTITY + } +} + +impl DefaultIsZeroes for ProjectivePoint where C: PrimeCurveParams {} + +impl Double for ProjectivePoint { + fn double(&self) -> Self { + C::PointArithmetic::double(self) + } +} + +impl Eq for ProjectivePoint where C: PrimeCurveParams {} + +impl From> for ProjectivePoint +where + C: PrimeCurveParams, +{ + fn from(p: AffinePoint) -> Self { + let projective = ProjectivePoint { + x: p.x, + y: p.y, + z: C::FieldElement::ONE, + }; + Self::conditional_select(&projective, &Self::IDENTITY, p.is_identity()) + } +} + +impl From<&AffinePoint> for ProjectivePoint +where + C: PrimeCurveParams, +{ + fn from(p: &AffinePoint) -> Self { + Self::from(*p) + } +} + +impl From> for ProjectivePoint +where + C: PrimeCurveParams, +{ + fn from(public_key: PublicKey) -> ProjectivePoint { + AffinePoint::from(public_key).into() + } +} + +impl From<&PublicKey> for ProjectivePoint +where + C: PrimeCurveParams, +{ + fn from(public_key: &PublicKey) -> ProjectivePoint { + AffinePoint::::from(public_key).into() + } +} + +impl FromEncodedPoint for ProjectivePoint +where + C: PrimeCurveParams, + FieldBytes: Copy, + FieldBytesSize: ModulusSize, + CompressedPoint: Copy, +{ + fn from_encoded_point(p: &EncodedPoint) -> CtOption { + AffinePoint::::from_encoded_point(p).map(Self::from) + } +} + +impl Group for ProjectivePoint +where + Self: Double, + C: PrimeCurveParams, +{ + type Scalar = Scalar; + + fn random(mut rng: impl RngCore) -> Self { + Self::GENERATOR * as Field>::random(&mut rng) + } + + fn identity() -> Self { + Self::IDENTITY + } + + fn generator() -> Self { + Self::GENERATOR + } + + fn is_identity(&self) -> Choice { + self.ct_eq(&Self::IDENTITY) + } + + #[must_use] + fn double(&self) -> Self { + Double::double(self) + } +} + +impl GroupEncoding for ProjectivePoint +where + C: PrimeCurveParams, + FieldBytes: Copy, + FieldBytesSize: ModulusSize, + CompressedPoint: Copy, + as ArrayLength>::ArrayType: Copy, +{ + type Repr = CompressedPoint; + + fn from_bytes(bytes: &Self::Repr) -> CtOption { + as GroupEncoding>::from_bytes(bytes).map(Into::into) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { + // No unchecked conversion possible for compressed points + Self::from_bytes(bytes) + } + + fn to_bytes(&self) -> Self::Repr { + self.to_affine().to_bytes() + } +} + +impl group::Curve for ProjectivePoint +where + Self: Double, + C: PrimeCurveParams, +{ + type AffineRepr = AffinePoint; + + fn to_affine(&self) -> AffinePoint { + ProjectivePoint::to_affine(self) + } + + // TODO(tarcieri): re-enable when we can add `Invert` bounds on `FieldElement` + // #[cfg(feature = "alloc")] + // #[inline] + // fn batch_normalize(projective: &[Self], affine: &mut [Self::AffineRepr]) { + // assert_eq!(projective.len(), affine.len()); + // let mut zs = vec![C::FieldElement::ONE; projective.len()]; + // batch_normalize_generic(projective, zs.as_mut_slice(), affine); + // } +} + +impl BatchNormalize<[ProjectivePoint; N]> for ProjectivePoint +where + Self: Double, + C: PrimeCurveParams, + C::FieldElement: Invert>, +{ + type Output = [Self::AffineRepr; N]; + + #[inline] + fn batch_normalize(points: &[Self; N]) -> [Self::AffineRepr; N] { + let mut zs = [C::FieldElement::ONE; N]; + let mut affine_points = [C::AffinePoint::IDENTITY; N]; + batch_normalize_generic(points, &mut zs, &mut affine_points); + affine_points + } +} + +#[cfg(feature = "alloc")] +impl BatchNormalize<[ProjectivePoint]> for ProjectivePoint +where + Self: Double, + C: PrimeCurveParams, + C::FieldElement: Invert>, +{ + type Output = Vec; + + #[inline] + fn batch_normalize(points: &[Self]) -> Vec { + let mut zs = vec![C::FieldElement::ONE; points.len()]; + let mut affine_points = vec![AffinePoint::IDENTITY; points.len()]; + batch_normalize_generic(points, zs.as_mut_slice(), &mut affine_points); + affine_points + } +} + +/// Generic implementation of batch normalization. +fn batch_normalize_generic(points: &P, zs: &mut Z, out: &mut O) +where + C: PrimeCurveParams, + C::FieldElement: BatchInvert, + C::ProjectivePoint: Double, + P: AsRef<[ProjectivePoint]> + ?Sized, + Z: AsMut<[C::FieldElement]> + ?Sized, + O: AsMut<[AffinePoint]> + ?Sized, +{ + let points = points.as_ref(); + let out = out.as_mut(); + + for i in 0..points.len() { + // Even a single zero value will fail inversion for the entire batch. + // Put a dummy value (above `FieldElement::ONE`) so inversion succeeds + // and treat that case specially later-on. + zs.as_mut()[i].conditional_assign(&points[i].z, !points[i].z.ct_eq(&C::FieldElement::ZERO)); + } + + // This is safe to unwrap since we assured that all elements are non-zero + let zs_inverses = >::batch_invert(zs).unwrap(); + + for i in 0..out.len() { + // If the `z` coordinate is non-zero, we can use it to invert; + // otherwise it defaults to the `IDENTITY` value. + out[i] = C::AffinePoint::conditional_select( + &points[i].to_affine_internal(zs_inverses.as_ref()[i]), + &C::AffinePoint::IDENTITY, + points[i].z.ct_eq(&C::FieldElement::ZERO), + ); + } +} + +impl LinearCombination for ProjectivePoint +where + Self: Double, + C: PrimeCurveParams, +{ +} + +impl MulByGenerator for ProjectivePoint +where + Self: Double, + C: PrimeCurveParams, +{ + fn mul_by_generator(scalar: &Self::Scalar) -> Self { + // TODO(tarcieri): precomputed basepoint tables + Self::generator() * scalar + } +} + +impl PrimeGroup for ProjectivePoint +where + Self: Double, + C: PrimeCurveParams, + FieldBytes: Copy, + FieldBytesSize: ModulusSize, + CompressedPoint: Copy, + as ArrayLength>::ArrayType: Copy, +{ +} + +impl PrimeCurve for ProjectivePoint +where + Self: Double, + C: PrimeCurveParams, + FieldBytes: Copy, + FieldBytesSize: ModulusSize, + CompressedPoint: Copy, + as ArrayLength>::ArrayType: Copy, +{ + type Affine = AffinePoint; +} + +impl PartialEq for ProjectivePoint +where + C: PrimeCurveParams, +{ + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } +} + +impl ToEncodedPoint for ProjectivePoint +where + C: PrimeCurveParams, + FieldBytesSize: ModulusSize, + CompressedPoint: Copy, + as ArrayLength>::ArrayType: Copy, +{ + fn to_encoded_point(&self, compress: bool) -> EncodedPoint { + self.to_affine().to_encoded_point(compress) + } +} + +impl TryFrom> for PublicKey +where + C: PrimeCurveParams, +{ + type Error = Error; + + fn try_from(point: ProjectivePoint) -> Result> { + AffinePoint::::from(point).try_into() + } +} + +impl TryFrom<&ProjectivePoint> for PublicKey +where + C: PrimeCurveParams, +{ + type Error = Error; + + fn try_from(point: &ProjectivePoint) -> Result> { + AffinePoint::::from(point).try_into() + } +} + +// +// Arithmetic trait impls +// + +impl Add> for ProjectivePoint +where + C: PrimeCurveParams, +{ + type Output = ProjectivePoint; + + fn add(self, other: ProjectivePoint) -> ProjectivePoint { + ProjectivePoint::add(&self, &other) + } +} + +impl Add<&ProjectivePoint> for &ProjectivePoint +where + C: PrimeCurveParams, +{ + type Output = ProjectivePoint; + + fn add(self, other: &ProjectivePoint) -> ProjectivePoint { + ProjectivePoint::add(self, other) + } +} + +impl Add<&ProjectivePoint> for ProjectivePoint +where + C: PrimeCurveParams, +{ + type Output = ProjectivePoint; + + fn add(self, other: &ProjectivePoint) -> ProjectivePoint { + ProjectivePoint::add(&self, other) + } +} + +impl AddAssign> for ProjectivePoint +where + C: PrimeCurveParams, +{ + fn add_assign(&mut self, rhs: ProjectivePoint) { + *self = ProjectivePoint::add(self, &rhs); + } +} + +impl AddAssign<&ProjectivePoint> for ProjectivePoint +where + C: PrimeCurveParams, +{ + fn add_assign(&mut self, rhs: &ProjectivePoint) { + *self = ProjectivePoint::add(self, rhs); + } +} + +impl Add> for ProjectivePoint +where + C: PrimeCurveParams, +{ + type Output = ProjectivePoint; + + fn add(self, other: AffinePoint) -> ProjectivePoint { + ProjectivePoint::add_mixed(&self, &other) + } +} + +impl Add<&AffinePoint> for &ProjectivePoint +where + C: PrimeCurveParams, +{ + type Output = ProjectivePoint; + + fn add(self, other: &AffinePoint) -> ProjectivePoint { + ProjectivePoint::add_mixed(self, other) + } +} + +impl Add<&AffinePoint> for ProjectivePoint +where + C: PrimeCurveParams, +{ + type Output = ProjectivePoint; + + fn add(self, other: &AffinePoint) -> ProjectivePoint { + ProjectivePoint::add_mixed(&self, other) + } +} + +impl AddAssign> for ProjectivePoint +where + C: PrimeCurveParams, +{ + fn add_assign(&mut self, rhs: AffinePoint) { + *self = ProjectivePoint::add_mixed(self, &rhs); + } +} + +impl AddAssign<&AffinePoint> for ProjectivePoint +where + C: PrimeCurveParams, +{ + fn add_assign(&mut self, rhs: &AffinePoint) { + *self = ProjectivePoint::add_mixed(self, rhs); + } +} + +impl Sum for ProjectivePoint +where + C: PrimeCurveParams, +{ + fn sum>(iter: I) -> Self { + iter.fold(ProjectivePoint::IDENTITY, |a, b| a + b) + } +} + +impl<'a, C> Sum<&'a ProjectivePoint> for ProjectivePoint +where + C: PrimeCurveParams, +{ + fn sum>>(iter: I) -> Self { + iter.cloned().sum() + } +} + +impl Sub> for ProjectivePoint +where + C: PrimeCurveParams, +{ + type Output = ProjectivePoint; + + fn sub(self, other: ProjectivePoint) -> ProjectivePoint { + ProjectivePoint::sub(&self, &other) + } +} + +impl Sub<&ProjectivePoint> for &ProjectivePoint +where + C: PrimeCurveParams, +{ + type Output = ProjectivePoint; + + fn sub(self, other: &ProjectivePoint) -> ProjectivePoint { + ProjectivePoint::sub(self, other) + } +} + +impl Sub<&ProjectivePoint> for ProjectivePoint +where + C: PrimeCurveParams, +{ + type Output = ProjectivePoint; + + fn sub(self, other: &ProjectivePoint) -> ProjectivePoint { + ProjectivePoint::sub(&self, other) + } +} + +impl SubAssign> for ProjectivePoint +where + C: PrimeCurveParams, +{ + fn sub_assign(&mut self, rhs: ProjectivePoint) { + *self = ProjectivePoint::sub(self, &rhs); + } +} + +impl SubAssign<&ProjectivePoint> for ProjectivePoint +where + C: PrimeCurveParams, +{ + fn sub_assign(&mut self, rhs: &ProjectivePoint) { + *self = ProjectivePoint::sub(self, rhs); + } +} + +impl Sub> for ProjectivePoint +where + C: PrimeCurveParams, +{ + type Output = ProjectivePoint; + + fn sub(self, other: AffinePoint) -> ProjectivePoint { + ProjectivePoint::sub_mixed(&self, &other) + } +} + +impl Sub<&AffinePoint> for &ProjectivePoint +where + C: PrimeCurveParams, +{ + type Output = ProjectivePoint; + + fn sub(self, other: &AffinePoint) -> ProjectivePoint { + ProjectivePoint::sub_mixed(self, other) + } +} + +impl Sub<&AffinePoint> for ProjectivePoint +where + C: PrimeCurveParams, +{ + type Output = ProjectivePoint; + + fn sub(self, other: &AffinePoint) -> ProjectivePoint { + ProjectivePoint::sub_mixed(&self, other) + } +} + +impl SubAssign> for ProjectivePoint +where + C: PrimeCurveParams, +{ + fn sub_assign(&mut self, rhs: AffinePoint) { + *self = ProjectivePoint::sub_mixed(self, &rhs); + } +} + +impl SubAssign<&AffinePoint> for ProjectivePoint +where + C: PrimeCurveParams, +{ + fn sub_assign(&mut self, rhs: &AffinePoint) { + *self = ProjectivePoint::sub_mixed(self, rhs); + } +} + +impl Mul for ProjectivePoint +where + Self: Double, + C: PrimeCurveParams, + S: Borrow>, +{ + type Output = Self; + + fn mul(self, scalar: S) -> Self { + ProjectivePoint::mul(&self, scalar.borrow()) + } +} + +impl Mul<&Scalar> for &ProjectivePoint +where + C: PrimeCurveParams, + ProjectivePoint: Double, +{ + type Output = ProjectivePoint; + + fn mul(self, scalar: &Scalar) -> ProjectivePoint { + ProjectivePoint::mul(self, scalar) + } +} + +impl MulAssign for ProjectivePoint +where + Self: Double, + C: PrimeCurveParams, + S: Borrow>, +{ + fn mul_assign(&mut self, scalar: S) { + *self = ProjectivePoint::mul(self, scalar.borrow()); + } +} + +impl Neg for ProjectivePoint +where + C: PrimeCurveParams, +{ + type Output = ProjectivePoint; + + fn neg(self) -> ProjectivePoint { + ProjectivePoint::neg(&self) + } +} + +impl<'a, C> Neg for &'a ProjectivePoint +where + C: PrimeCurveParams, +{ + type Output = ProjectivePoint; + + fn neg(self) -> ProjectivePoint { + ProjectivePoint::neg(self) + } +} diff --git a/src/rust/vendor/rfc6979/.cargo-checksum.json b/src/rust/vendor/rfc6979/.cargo-checksum.json new file mode 100644 index 000000000..0a24f6331 --- /dev/null +++ b/src/rust/vendor/rfc6979/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"b125a8cdeeec71a6b1ddc137226634b3073b53715eb59ac914a531cb66dfbabc","Cargo.toml":"48f7844dac3a7959ce8ff71ac9cb65073abdcf3940cbb3fe38e36942fe10fbe1","LICENSE-APACHE":"78779d420019e6b4630376af8e86b6b335ee8a2f89ede6e0411e0469a326aaa4","LICENSE-MIT":"bdebaf9156a298f8fdab56dd26cb5144673de522d80f4c0d88e0039145f147f9","README.md":"f60a1275e4f5f04a5ab10611993489395adc32a2072dc75457a183312ff9f6ad","src/ct_cmp.rs":"b10bca722d370ce63f60456f0ff76e2af0a8a021a291a7f03e033ca1f5f9ece8","src/lib.rs":"1d84380071c054531c51a2ccd3b6b9d9e40dfc08b374df9113f964c1c5f00edb","tests/lib.rs":"68922b3fb793f7f64a6fdf8aa59b6fb9432d4706d7ad1d82129a8337c5cf6568"},"package":"f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"} \ No newline at end of file diff --git a/src/rust/vendor/rfc6979/CHANGELOG.md b/src/rust/vendor/rfc6979/CHANGELOG.md new file mode 100644 index 000000000..8cc1a0d83 --- /dev/null +++ b/src/rust/vendor/rfc6979/CHANGELOG.md @@ -0,0 +1,40 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.4.0 (2023-02-28) +### Changed +- MSRV 1.60 ([#628]) +- Decouple from `crypto-bigint` ([#639]) + +[#628]: https://github.com/RustCrypto/signatures/pull/628 +[#639]: https://github.com/RustCrypto/signatures/pull/639 + +## 0.3.1 (2022-11-03) +### Added +- Usage example ([#577]) + +[#577]: https://github.com/RustCrypto/signatures/pull/577 + +## 0.3.0 (2022-06-26) +### Changed +- Use `SimpleHmac` to implement `HmacDrbg` ([#499]) + +[#499]: https://github.com/RustCrypto/signatures/pull/499 + +## 0.2.0 (2022-05-08) +### Added +- License files ([#447]) + +### Changed +- Bump `hmac` dependency to v0.12 ([#433]) +- Bump `crypto-bigint` dependency to v0.4 ([#469]) + +[#433]: https://github.com/RustCrypto/signatures/pull/433 +[#447]: https://github.com/RustCrypto/signatures/pull/447 +[#469]: https://github.com/RustCrypto/signatures/pull/469 + +### 0.1.0 (2021-11-21) +- Initial release diff --git a/src/rust/vendor/rfc6979/Cargo.toml b/src/rust/vendor/rfc6979/Cargo.toml new file mode 100644 index 000000000..3a81265ee --- /dev/null +++ b/src/rust/vendor/rfc6979/Cargo.toml @@ -0,0 +1,48 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.61" +name = "rfc6979" +version = "0.4.0" +authors = ["RustCrypto Developers"] +description = """ +Pure Rust implementation of RFC6979: Deterministic Usage of the +Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA) +""" +readme = "README.md" +keywords = [ + "dsa", + "ecdsa", + "signature", +] +categories = [ + "cryptography", + "no-std", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/RustCrypto/signatures/tree/master/rfc6979" + +[dependencies.hmac] +version = "0.12" +features = ["reset"] +default-features = false + +[dependencies.subtle] +version = "2" +default-features = false + +[dev-dependencies.hex-literal] +version = "0.3" + +[dev-dependencies.sha2] +version = "0.10" diff --git a/src/rust/vendor/rfc6979/LICENSE-APACHE b/src/rust/vendor/rfc6979/LICENSE-APACHE new file mode 100644 index 000000000..c394d8ad9 --- /dev/null +++ b/src/rust/vendor/rfc6979/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2018-2022 RustCrypto Developers + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/rfc6979/LICENSE-MIT b/src/rust/vendor/rfc6979/LICENSE-MIT new file mode 100644 index 000000000..81a3d57ac --- /dev/null +++ b/src/rust/vendor/rfc6979/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2018-2022 RustCrypto Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/rfc6979/README.md b/src/rust/vendor/rfc6979/README.md new file mode 100644 index 000000000..de70e3d57 --- /dev/null +++ b/src/rust/vendor/rfc6979/README.md @@ -0,0 +1,55 @@ +# [RustCrypto]: RFC6979 Deterministic Signatures + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +[![Build Status][build-image]][build-link] +![Apache2/MIT licensed][license-image] +![MSRV][rustc-image] +[![Project Chat][chat-image]][chat-link] + +Pure Rust implementation of RFC6979: Deterministic Usage of the +Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA). + +Algorithm described in RFC 6979 § 3.2: + + +[Documentation][docs-link] + +## Minimum Supported Rust Version + +This crate requires **Rust 1.61** at a minimum. + +We may change the MSRV in the future, but it will be accompanied by a minor +version bump. + +## License + +All crates licensed under either of + + * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + * [MIT license](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. + +[//]: # (badges) + +[crate-image]: https://buildstats.info/crate/rfc6979 +[crate-link]: https://crates.io/crates/rfc6979 +[docs-image]: https://docs.rs/rfc6979/badge.svg +[docs-link]: https://docs.rs/rfc6979/ +[build-image]: https://github.com/RustCrypto/signatures/actions/workflows/rfc6979.yml/badge.svg +[build-link]: https://github.com/RustCrypto/signatures/actions/workflows/rfc6979.yml +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.61+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260048-signatures + +[//]: # (links) + +[RustCrypto]: https://github.com/RustCrypto diff --git a/src/rust/vendor/rfc6979/src/ct_cmp.rs b/src/rust/vendor/rfc6979/src/ct_cmp.rs new file mode 100644 index 000000000..8b216e6ff --- /dev/null +++ b/src/rust/vendor/rfc6979/src/ct_cmp.rs @@ -0,0 +1,87 @@ +//! Constant-time comparison helpers for [`ByteArray`]. + +use crate::{ArrayLength, ByteArray}; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; + +/// Constant-time equals. +pub(crate) fn ct_eq>(a: &ByteArray, b: &ByteArray) -> Choice { + let mut ret = Choice::from(1); + + for (a, b) in a.iter().zip(b.iter()) { + ret.conditional_assign(&Choice::from(0), !a.ct_eq(b)); + } + + ret +} + +/// Constant-time less than. +/// +/// Inputs are interpreted as big endian integers. +pub(crate) fn ct_lt>(a: &ByteArray, b: &ByteArray) -> Choice { + let mut borrow = 0; + + // Perform subtraction with borrow a byte-at-a-time, interpreting a + // no-borrow condition as the less-than case + for (&a, &b) in a.iter().zip(b.iter()).rev() { + let c = (b as u16).wrapping_add(borrow >> (u8::BITS - 1)); + borrow = (a as u16).wrapping_sub(c) >> u8::BITS as u8; + } + + !borrow.ct_eq(&0) +} + +#[cfg(test)] +mod tests { + const A: [u8; 4] = [0, 0, 0, 0]; + const B: [u8; 4] = [0, 0, 0, 1]; + const C: [u8; 4] = [0xFF, 0, 0, 0]; + const D: [u8; 4] = [0xFF, 0, 0, 1]; + const E: [u8; 4] = [0xFF, 0xFF, 0xFF, 0xFE]; + const F: [u8; 4] = [0xFF, 0xFF, 0xFF, 0xFF]; + + #[test] + fn ct_eq() { + use super::ct_eq; + + assert_eq!(ct_eq(&A.into(), &A.into()).unwrap_u8(), 1); + assert_eq!(ct_eq(&B.into(), &B.into()).unwrap_u8(), 1); + assert_eq!(ct_eq(&C.into(), &C.into()).unwrap_u8(), 1); + assert_eq!(ct_eq(&D.into(), &D.into()).unwrap_u8(), 1); + assert_eq!(ct_eq(&E.into(), &E.into()).unwrap_u8(), 1); + assert_eq!(ct_eq(&F.into(), &F.into()).unwrap_u8(), 1); + + assert_eq!(ct_eq(&A.into(), &B.into()).unwrap_u8(), 0); + assert_eq!(ct_eq(&C.into(), &D.into()).unwrap_u8(), 0); + assert_eq!(ct_eq(&E.into(), &F.into()).unwrap_u8(), 0); + } + + #[test] + fn ct_lt() { + use super::ct_lt; + + assert_eq!(ct_lt(&A.into(), &A.into()).unwrap_u8(), 0); + assert_eq!(ct_lt(&B.into(), &B.into()).unwrap_u8(), 0); + assert_eq!(ct_lt(&C.into(), &C.into()).unwrap_u8(), 0); + assert_eq!(ct_lt(&D.into(), &D.into()).unwrap_u8(), 0); + assert_eq!(ct_lt(&E.into(), &E.into()).unwrap_u8(), 0); + assert_eq!(ct_lt(&F.into(), &F.into()).unwrap_u8(), 0); + + assert_eq!(ct_lt(&A.into(), &B.into()).unwrap_u8(), 1); + assert_eq!(ct_lt(&A.into(), &C.into()).unwrap_u8(), 1); + assert_eq!(ct_lt(&B.into(), &A.into()).unwrap_u8(), 0); + assert_eq!(ct_lt(&C.into(), &A.into()).unwrap_u8(), 0); + + assert_eq!(ct_lt(&B.into(), &C.into()).unwrap_u8(), 1); + assert_eq!(ct_lt(&B.into(), &D.into()).unwrap_u8(), 1); + assert_eq!(ct_lt(&C.into(), &B.into()).unwrap_u8(), 0); + assert_eq!(ct_lt(&D.into(), &B.into()).unwrap_u8(), 0); + + assert_eq!(ct_lt(&C.into(), &D.into()).unwrap_u8(), 1); + assert_eq!(ct_lt(&C.into(), &E.into()).unwrap_u8(), 1); + assert_eq!(ct_lt(&D.into(), &C.into()).unwrap_u8(), 0); + assert_eq!(ct_lt(&E.into(), &C.into()).unwrap_u8(), 0); + + assert_eq!(ct_lt(&E.into(), &F.into()).unwrap_u8(), 1); + assert_eq!(ct_lt(&F.into(), &E.into()).unwrap_u8(), 0); + } +} diff --git a/src/rust/vendor/rfc6979/src/lib.rs b/src/rust/vendor/rfc6979/src/lib.rs new file mode 100644 index 000000000..817dda12d --- /dev/null +++ b/src/rust/vendor/rfc6979/src/lib.rs @@ -0,0 +1,149 @@ +#![no_std] +#![doc = include_str!("../README.md")] +#![forbid(unsafe_code, clippy::unwrap_used)] +#![warn(missing_docs, rust_2018_idioms)] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg" +)] + +//! ## Usage +//! +//! See also: the documentation for the [`generate_k`] function. +//! +//! ``` +//! use hex_literal::hex; +//! use rfc6979::consts::U32; +//! use sha2::{Digest, Sha256}; +//! +//! // NIST P-256 field modulus +//! const NIST_P256_MODULUS: [u8; 32] = +//! hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"); +//! +//! // Public key for RFC6979 NIST P256/SHA256 test case +//! const RFC6979_KEY: [u8; 32] = +//! hex!("C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721"); +//! +//! // Test message for RFC6979 NIST P256/SHA256 test case +//! const RFC6979_MSG: &[u8; 6] = b"sample"; +//! +//! // Expected K for RFC6979 NIST P256/SHA256 test case +//! const RFC6979_EXPECTED_K: [u8; 32] = +//! hex!("A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60"); +//! +//! let h = Sha256::digest(RFC6979_MSG); +//! let aad = b""; +//! let k = rfc6979::generate_k::(&RFC6979_KEY.into(), &NIST_P256_MODULUS.into(), &h, aad); +//! assert_eq!(k.as_slice(), &RFC6979_EXPECTED_K); +//! ``` + +mod ct_cmp; + +pub use hmac::digest::generic_array::typenum::consts; + +use hmac::{ + digest::{ + core_api::BlockSizeUser, + generic_array::{ArrayLength, GenericArray}, + Digest, FixedOutput, FixedOutputReset, Mac, + }, + SimpleHmac, +}; + +/// Array of bytes representing a scalar serialized as a big endian integer. +pub type ByteArray = GenericArray; + +/// Deterministically generate ephemeral scalar `k`. +/// +/// Accepts the following parameters and inputs: +/// +/// - `x`: secret key +/// - `n`: field modulus +/// - `h`: hash/digest of input message: must be reduced modulo `n` in advance +/// - `data`: additional associated data, e.g. CSRNG output used as added entropy +#[inline] +pub fn generate_k( + x: &ByteArray, + n: &ByteArray, + h: &ByteArray, + data: &[u8], +) -> ByteArray +where + D: Digest + BlockSizeUser + FixedOutput + FixedOutputReset, + N: ArrayLength, +{ + let mut hmac_drbg = HmacDrbg::::new(x, h, data); + + loop { + let mut k = ByteArray::::default(); + hmac_drbg.fill_bytes(&mut k); + + let k_is_zero = ct_cmp::ct_eq(&k, &ByteArray::default()); + if (!k_is_zero & ct_cmp::ct_lt(&k, n)).into() { + return k; + } + } +} + +/// Internal implementation of `HMAC_DRBG` as described in NIST SP800-90A. +/// +/// +/// +/// This is a HMAC-based deterministic random bit generator used compute a +/// deterministic ephemeral scalar `k`. +pub struct HmacDrbg +where + D: Digest + BlockSizeUser + FixedOutputReset, +{ + /// HMAC key `K` (see RFC 6979 Section 3.2.c) + k: SimpleHmac, + + /// Chaining value `V` (see RFC 6979 Section 3.2.c) + v: GenericArray, +} + +impl HmacDrbg +where + D: Digest + BlockSizeUser + FixedOutputReset, +{ + /// Initialize `HMAC_DRBG` + pub fn new(entropy_input: &[u8], nonce: &[u8], additional_data: &[u8]) -> Self { + let mut k = SimpleHmac::new(&Default::default()); + let mut v = GenericArray::default(); + + for b in &mut v { + *b = 0x01; + } + + for i in 0..=1 { + k.update(&v); + k.update(&[i]); + k.update(entropy_input); + k.update(nonce); + k.update(additional_data); + k = SimpleHmac::new_from_slice(&k.finalize().into_bytes()).expect("HMAC error"); + + // Steps 3.2.e,g: v = HMAC_k(v) + k.update(&v); + v = k.finalize_reset().into_bytes(); + } + + Self { k, v } + } + + /// Write the next `HMAC_DRBG` output to the given byte slice. + pub fn fill_bytes(&mut self, out: &mut [u8]) { + for out_chunk in out.chunks_mut(self.v.len()) { + self.k.update(&self.v); + self.v = self.k.finalize_reset().into_bytes(); + out_chunk.copy_from_slice(&self.v[..out_chunk.len()]); + } + + self.k.update(&self.v); + self.k.update(&[0x00]); + self.k = + SimpleHmac::new_from_slice(&self.k.finalize_reset().into_bytes()).expect("HMAC error"); + self.k.update(&self.v); + self.v = self.k.finalize_reset().into_bytes(); + } +} diff --git a/src/rust/vendor/rfc6979/tests/lib.rs b/src/rust/vendor/rfc6979/tests/lib.rs new file mode 100644 index 000000000..1b622f8bd --- /dev/null +++ b/src/rust/vendor/rfc6979/tests/lib.rs @@ -0,0 +1,14 @@ +//! Smoke tests which use `MockCurve` + +#![cfg(feature = "dev")] + +use elliptic_curve::dev::MockCurve; + +type Signature = ecdsa::Signature; +type SignatureBytes = ecdsa::SignatureBytes; + +#[test] +fn rejects_all_zero_signature() { + let all_zero_bytes = SignatureBytes::default(); + assert!(Signature::try_from(all_zero_bytes.as_ref()).is_err()); +} diff --git a/src/rust/vendor/rustc-std-workspace-alloc/.cargo-checksum.json b/src/rust/vendor/rustc-std-workspace-alloc/.cargo-checksum.json index ce1535e33..1facd4319 100644 --- a/src/rust/vendor/rustc-std-workspace-alloc/.cargo-checksum.json +++ b/src/rust/vendor/rustc-std-workspace-alloc/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"32df7c9030f058cde971d4fa46f775fe8498948995ef31197712dfb44bbc5a2e","src/lib.rs":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},"package":"ff66d57013a5686e1917ed6a025d54dd591fcda71a41fe07edf4d16726aefa86"} \ No newline at end of file +{"files":{"Cargo.toml":"fcf31f07045ef33a614ef32be6a21f5e19c4c9308ab0eb6547aa533e268dbd44","src/lib.rs":"d3133155f040a09a74660f4fcf9b64e51a252e385b3483286fc5eed1b3cca4ec"},"package":"f9d441c3b2ebf55cebf796bfdc265d67fa09db17b7bb6bd4be75c509e1e8fec3"} \ No newline at end of file diff --git a/src/rust/vendor/rustc-std-workspace-alloc/Cargo.toml b/src/rust/vendor/rustc-std-workspace-alloc/Cargo.toml index 4075e82bf..98f52591f 100644 --- a/src/rust/vendor/rustc-std-workspace-alloc/Cargo.toml +++ b/src/rust/vendor/rustc-std-workspace-alloc/Cargo.toml @@ -3,19 +3,29 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] -edition = "2018" +edition = "2021" name = "rustc-std-workspace-alloc" -version = "1.0.0" +version = "1.0.1" authors = ["Alex Crichton "] -description = "workspace hack" +build = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = """ +crate for integration of crates.io crates into rust-lang/rust standard library workspace +""" +readme = false license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang/rust/tree/master/src/rustc-std-workspace" -[dependencies] +[lib] +name = "rustc_std_workspace_alloc" +path = "src/lib.rs" diff --git a/src/rust/vendor/rustc-std-workspace-alloc/src/lib.rs b/src/rust/vendor/rustc-std-workspace-alloc/src/lib.rs index e69de29bb..938b8bb29 100644 --- a/src/rust/vendor/rustc-std-workspace-alloc/src/lib.rs +++ b/src/rust/vendor/rustc-std-workspace-alloc/src/lib.rs @@ -0,0 +1,3 @@ +#![no_std] +extern crate alloc as the_alloc; +pub use the_alloc::*; diff --git a/src/rust/vendor/rustc-std-workspace-core/.cargo-checksum.json b/src/rust/vendor/rustc-std-workspace-core/.cargo-checksum.json index 6ec3d59c0..7bda8d07e 100644 --- a/src/rust/vendor/rustc-std-workspace-core/.cargo-checksum.json +++ b/src/rust/vendor/rustc-std-workspace-core/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"ac7ce15b820ee532ba739d5fc54f1b22f3052ed794ce72534655fd4a3688655f","src/lib.rs":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},"package":"1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c"} \ No newline at end of file +{"files":{"Cargo.toml":"c41de1976263e57febc55cdb8b59c2b2671530e708a07aee0c8234b034fb1f94","src/lib.rs":"ed0e785d71613f3e0aa475f90ee873eab8063e388ef9fde9bad92b1270ecc0c4"},"package":"aa9c45b374136f52f2d6311062c7146bff20fec063c3f5d46a410bd937746955"} \ No newline at end of file diff --git a/src/rust/vendor/rustc-std-workspace-core/Cargo.toml b/src/rust/vendor/rustc-std-workspace-core/Cargo.toml index 7a5a96154..b01ae5fb4 100644 --- a/src/rust/vendor/rustc-std-workspace-core/Cargo.toml +++ b/src/rust/vendor/rustc-std-workspace-core/Cargo.toml @@ -3,18 +3,29 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] +edition = "2021" name = "rustc-std-workspace-core" -version = "1.0.0" +version = "1.0.1" authors = ["Alex Crichton "] -description = "Explicitly empty crate for rust-lang/rust integration\n" +build = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = """ +crate for integration of crates.io crates into rust-lang/rust standard library workspace +""" +readme = false license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang/rust/tree/master/src/rustc-std-workspace" -[dependencies] +[lib] +name = "rustc_std_workspace_core" +path = "src/lib.rs" diff --git a/src/rust/vendor/rustc-std-workspace-core/src/lib.rs b/src/rust/vendor/rustc-std-workspace-core/src/lib.rs index e69de29bb..38b1615a0 100644 --- a/src/rust/vendor/rustc-std-workspace-core/src/lib.rs +++ b/src/rust/vendor/rustc-std-workspace-core/src/lib.rs @@ -0,0 +1,3 @@ +#![no_std] +extern crate core as the_core; +pub use the_core::*; diff --git a/src/rust/vendor/sec1/.cargo-checksum.json b/src/rust/vendor/sec1/.cargo-checksum.json new file mode 100644 index 000000000..ab3fe6313 --- /dev/null +++ b/src/rust/vendor/sec1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"2b3e288a2da4733e1286829facc55fef0466ec25dd896079855d7cb930ce624b","Cargo.toml":"24a70b7095f9fd000e904aea11d5c67846e1aa252962d73c2d85085da49593aa","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"4a883ecc3bb1010faed542bf63d53e530fea5e5e12cf676aed588784298ba929","README.md":"f4cb78d53d52f2a44d2336e4c3dc29f10f62f2636f6db0757e0b6edb94d6e52b","src/error.rs":"a59b7e2881f9caf4f932d11eedaedaa9eb34797e652c6d363b11b604848f7d2d","src/lib.rs":"43415382857e83d425069163323a341624ae80a7282ab01c2a43519aee4472db","src/parameters.rs":"f186cde9c122319b4d408b1ad8090cbc9f6bc817ee7c761c0dbf6868131e2259","src/point.rs":"9bb2bcf504594606ae21914349f3e78e1c63c174a8f4b9312f22a6069ee226ac","src/private_key.rs":"daac1e9b5e87af5f7bcde728b6711cae5b04188ae683aea43478a85e53b76276","src/traits.rs":"b554960b3ceb586871f2febd403288bbc4c104fa1ad3a14b67b3f91a9dfb2f3b","tests/examples/p256-priv.der":"36186d76a14000b87c31162269207a757dc147668219c1adcdcdc25fa6f04a8d","tests/examples/p256-priv.pem":"7f9b6b52c303da1ad081a416e3b159109d158338374de902099877dbd1102dc8","tests/private_key.rs":"9a43eb7673d0acde453c47581eec93463b7b2adca41bf210154695a971966de1","tests/traits.rs":"837859875b3d6cabd6d2e1d16c6bb686be0be838f11b924adbfad0793b54f6fb"},"package":"d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"} \ No newline at end of file diff --git a/src/rust/vendor/sec1/CHANGELOG.md b/src/rust/vendor/sec1/CHANGELOG.md new file mode 100644 index 000000000..44a0fc9d5 --- /dev/null +++ b/src/rust/vendor/sec1/CHANGELOG.md @@ -0,0 +1,92 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.7.3 (2023-07-16) +### Added +- Impl `Hash` for `EncodedPoint` ([#1102]) + +[#1102]: https://github.com/RustCrypto/formats/pull/1102 + +## 0.7.2 (2023-04-09) +### Added +- Impl `ModulusSize` for `U24` ([#995]) + +[#995]: https://github.com/RustCrypto/formats/pull/995 + +## 0.7.1 (2023-02-27) +### Fixed +- Encode `ECPrivateKey` version ([#908]) + +[#908]: https://github.com/RustCrypto/formats/pull/908 + +## 0.7.0 (2023-02-26) [YANKED] +### Changed +- MSRV 1.65 ([#805]) +- Bump `serdect` to v0.2 ([#893]) +- Bump `der` dependency to v0.7 ([#899]) +- Bump `spki` dependency to v0.7 ([#900]) +- Bump `pkcs8` to v0.10 ([#902]) + +[#805]: https://github.com/RustCrypto/formats/pull/805 +[#893]: https://github.com/RustCrypto/formats/pull/893 +[#899]: https://github.com/RustCrypto/formats/pull/899 +[#900]: https://github.com/RustCrypto/formats/pull/900 +[#902]: https://github.com/RustCrypto/formats/pull/902 + +## 0.6.0 (Skipped) +- Skipped to synchronize version number with `der` and `spki` + +## 0.5.0 (Skipped) +- Skipped to synchronize version number with `der` and `spki` + +## 0.4.0 (Skipped) +- Skipped to synchronize version number with `der` and `spki` + +## 0.3.0 (2022-05-08) +### Added +- Make `der` feature optional but on-by-default ([#497]) +- Make `point` feature optional but on-by-default ([#516]) + +### Changed +- Use `base16ct` and `serdect` crates ([#648]) +- Bump `der` to v0.6 ([#653]) +- Bump `pkcs8` to v0.9 ([#656]) + +[#497]: https://github.com/RustCrypto/formats/pull/497 +[#516]: https://github.com/RustCrypto/formats/pull/516 +[#648]: https://github.com/RustCrypto/formats/pull/648 +[#653]: https://github.com/RustCrypto/formats/pull/653 +[#656]: https://github.com/RustCrypto/formats/pull/656 + +## 0.2.1 (2021-11-18) +### Added +- `serde` feature ([#248]) +- Hexadecimal serialization/deserialization support for `EncodedPoint` ([#248]) + +[#248]: https://github.com/RustCrypto/formats/pull/248 + +## 0.2.0 (2021-11-17) [YANKED] +### Added +- `pkcs8` feature ([#229]) + +### Changed +- Rename `From/ToEcPrivateKey` => `DecodeEcPrivateKey`/`EncodeEcPrivateKey` ([#122]) +- Use `der::Document` to impl `EcPrivateKeyDocument` ([#133]) +- Rust 2021 edition upgrade; MSRV 1.56 ([#136]) +- Bump `der` crate dependency to v0.5 ([#222]) + +### Removed +- I/O related errors ([#158]) + +[#122]: https://github.com/RustCrypto/formats/pull/122 +[#133]: https://github.com/RustCrypto/formats/pull/133 +[#136]: https://github.com/RustCrypto/formats/pull/136 +[#158]: https://github.com/RustCrypto/formats/pull/158 +[#222]: https://github.com/RustCrypto/formats/pull/222 +[#229]: https://github.com/RustCrypto/formats/pull/229 + +## 0.1.0 (2021-09-22) +- Initial release diff --git a/src/rust/vendor/sec1/Cargo.toml b/src/rust/vendor/sec1/Cargo.toml new file mode 100644 index 000000000..c640dea2f --- /dev/null +++ b/src/rust/vendor/sec1/Cargo.toml @@ -0,0 +1,120 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.65" +name = "sec1" +version = "0.7.3" +authors = ["RustCrypto Developers"] +description = """ +Pure Rust implementation of SEC1: Elliptic Curve Cryptography encoding formats +including ASN.1 DER-serialized private keys as well as the +Elliptic-Curve-Point-to-Octet-String encoding +""" +readme = "README.md" +keywords = [ + "crypto", + "key", + "elliptic-curve", + "secg", +] +categories = [ + "cryptography", + "data-structures", + "encoding", + "no-std", + "parser-implementations", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/RustCrypto/formats/tree/master/sec1" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.base16ct] +version = "0.2" +optional = true +default-features = false + +[dependencies.der] +version = "0.7" +features = ["oid"] +optional = true + +[dependencies.generic-array] +version = "0.14.7" +optional = true +default-features = false + +[dependencies.pkcs8] +version = "0.10" +optional = true +default-features = false + +[dependencies.serdect] +version = "0.2" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.subtle] +version = "2" +optional = true +default-features = false + +[dependencies.zeroize] +version = "1" +optional = true +default-features = false + +[dev-dependencies.hex-literal] +version = "0.4" + +[dev-dependencies.tempfile] +version = "3" + +[features] +alloc = [ + "der?/alloc", + "pkcs8?/alloc", + "zeroize?/alloc", +] +default = [ + "der", + "point", +] +der = [ + "dep:der", + "zeroize", +] +pem = [ + "alloc", + "der/pem", + "pkcs8/pem", +] +point = [ + "dep:base16ct", + "dep:generic-array", +] +serde = ["dep:serdect"] +std = [ + "alloc", + "der?/std", +] +zeroize = [ + "dep:zeroize", + "der?/zeroize", +] diff --git a/src/rust/vendor/sec1/LICENSE-APACHE b/src/rust/vendor/sec1/LICENSE-APACHE new file mode 100644 index 000000000..78173fa2e --- /dev/null +++ b/src/rust/vendor/sec1/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/rust/vendor/sec1/LICENSE-MIT b/src/rust/vendor/sec1/LICENSE-MIT new file mode 100644 index 000000000..68ddaa3c9 --- /dev/null +++ b/src/rust/vendor/sec1/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2021-2022 The RustCrypto Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/rust/vendor/sec1/README.md b/src/rust/vendor/sec1/README.md new file mode 100644 index 000000000..5678de673 --- /dev/null +++ b/src/rust/vendor/sec1/README.md @@ -0,0 +1,58 @@ +# [RustCrypto]: SEC1 Elliptic Curve Cryptography Formats + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +[![Build Status][build-image]][build-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Project Chat][chat-image]][chat-link] + +[Documentation][docs-link] + +## About + +Pure Rust implementation of [SEC1: Elliptic Curve Cryptography] encoding +formats including ASN.1 DER-serialized private keys (also described in +[RFC5915]) as well as the `Elliptic-Curve-Point-to-Octet-String` and +`Octet-String-to-Elliptic-Curve-Point` encoding algorithms. + +## Minimum Supported Rust Version + +This crate requires **Rust 1.65** at a minimum. + +We may change the MSRV in the future, but it will be accompanied by a minor +version bump. + +## License + +Licensed under either of: + + * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + * [MIT license](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. + +[//]: # (badges) + +[crate-image]: https://buildstats.info/crate/sec1 +[crate-link]: https://crates.io/crates/sec1 +[docs-image]: https://docs.rs/sec1/badge.svg +[docs-link]: https://docs.rs/sec1/ +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/300570-formats +[build-image]: https://github.com/RustCrypto/formats/workflows/sec1/badge.svg?branch=master&event=push +[build-link]: https://github.com/RustCrypto/formats/actions + +[//]: # (links) + +[RustCrypto]: https://github.com/rustcrypto +[SEC1: Elliptic Curve Cryptography]: https://www.secg.org/sec1-v2.pdf +[RFC5915]: https://datatracker.ietf.org/doc/html/rfc5915 diff --git a/src/rust/vendor/sec1/src/error.rs b/src/rust/vendor/sec1/src/error.rs new file mode 100644 index 000000000..0d8bc8b70 --- /dev/null +++ b/src/rust/vendor/sec1/src/error.rs @@ -0,0 +1,82 @@ +//! Error types + +use core::fmt; + +#[cfg(feature = "pem")] +use der::pem; + +/// Result type with `sec1` crate's [`Error`] type. +pub type Result = core::result::Result; + +/// Error type +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[non_exhaustive] +pub enum Error { + /// ASN.1 DER-related errors. + #[cfg(feature = "der")] + Asn1(der::Error), + + /// Cryptographic errors. + /// + /// These can be used by EC implementations to signal that a key is + /// invalid for cryptographic reasons. This means the document parsed + /// correctly, but one of the values contained within was invalid, e.g. + /// a number expected to be a prime was not a prime. + Crypto, + + /// PKCS#8 errors. + #[cfg(feature = "pkcs8")] + Pkcs8(pkcs8::Error), + + /// Errors relating to the `Elliptic-Curve-Point-to-Octet-String` or + /// `Octet-String-to-Elliptic-Curve-Point` encodings. + PointEncoding, + + /// Version errors + Version, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + #[cfg(feature = "der")] + Error::Asn1(err) => write!(f, "SEC1 ASN.1 error: {}", err), + Error::Crypto => f.write_str("SEC1 cryptographic error"), + #[cfg(feature = "pkcs8")] + Error::Pkcs8(err) => write!(f, "{}", err), + Error::PointEncoding => f.write_str("elliptic curve point encoding error"), + Error::Version => f.write_str("SEC1 version error"), + } + } +} + +#[cfg(feature = "der")] +impl From for Error { + fn from(err: der::Error) -> Error { + Error::Asn1(err) + } +} + +#[cfg(feature = "pem")] +impl From for Error { + fn from(err: pem::Error) -> Error { + der::Error::from(err).into() + } +} + +#[cfg(feature = "pkcs8")] +impl From for Error { + fn from(err: pkcs8::Error) -> Error { + Error::Pkcs8(err) + } +} + +#[cfg(feature = "pkcs8")] +impl From for Error { + fn from(err: pkcs8::spki::Error) -> Error { + Error::Pkcs8(pkcs8::Error::PublicKey(err)) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for Error {} diff --git a/src/rust/vendor/sec1/src/lib.rs b/src/rust/vendor/sec1/src/lib.rs new file mode 100644 index 000000000..f6b419081 --- /dev/null +++ b/src/rust/vendor/sec1/src/lib.rs @@ -0,0 +1,77 @@ +#![no_std] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![doc = include_str!("../README.md")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" +)] +#![forbid(unsafe_code)] +#![warn( + clippy::mod_module_files, + clippy::unwrap_used, + missing_docs, + rust_2018_idioms, + unused_qualifications +)] + +//! ## `serde` support +//! +//! When the `serde` feature of this crate is enabled, the [`EncodedPoint`] +//! type receives impls of [`serde::Serialize`] and [`serde::Deserialize`]. +//! +//! Additionally, when both the `alloc` and `serde` features are enabled, the +//! serializers/deserializers will autodetect if a "human friendly" textual +//! encoding is being used, and if so encode the points as hexadecimal. + +#[cfg(feature = "alloc")] +#[allow(unused_extern_crates)] +extern crate alloc; +#[cfg(feature = "std")] +extern crate std; + +#[cfg(feature = "point")] +pub mod point; + +mod error; +#[cfg(feature = "der")] +mod parameters; +#[cfg(feature = "der")] +mod private_key; +#[cfg(feature = "der")] +mod traits; + +#[cfg(feature = "der")] +pub use der; + +pub use crate::error::{Error, Result}; + +#[cfg(feature = "point")] +pub use crate::point::EncodedPoint; + +#[cfg(feature = "point")] +pub use generic_array::typenum::consts; + +#[cfg(feature = "der")] +pub use crate::{parameters::EcParameters, private_key::EcPrivateKey, traits::DecodeEcPrivateKey}; + +#[cfg(all(feature = "alloc", feature = "der"))] +pub use crate::traits::EncodeEcPrivateKey; + +#[cfg(feature = "pem")] +pub use der::pem::{self, LineEnding}; + +#[cfg(feature = "pkcs8")] +pub use pkcs8; + +#[cfg(feature = "pkcs8")] +use pkcs8::ObjectIdentifier; + +#[cfg(all(doc, feature = "serde"))] +use serdect::serde; + +/// Algorithm [`ObjectIdentifier`] for elliptic curve public key cryptography +/// (`id-ecPublicKey`). +/// +/// +#[cfg(feature = "pkcs8")] +pub const ALGORITHM_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.2.1"); diff --git a/src/rust/vendor/sec1/src/parameters.rs b/src/rust/vendor/sec1/src/parameters.rs new file mode 100644 index 000000000..20458e6e9 --- /dev/null +++ b/src/rust/vendor/sec1/src/parameters.rs @@ -0,0 +1,75 @@ +use der::{ + asn1::{AnyRef, ObjectIdentifier}, + DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, Tag, Writer, +}; + +/// Elliptic curve parameters as described in +/// [RFC5480 Section 2.1.1](https://datatracker.ietf.org/doc/html/rfc5480#section-2.1.1): +/// +/// ```text +/// ECParameters ::= CHOICE { +/// namedCurve OBJECT IDENTIFIER +/// -- implicitCurve NULL +/// -- specifiedCurve SpecifiedECDomain +/// } +/// -- implicitCurve and specifiedCurve MUST NOT be used in PKIX. +/// -- Details for SpecifiedECDomain can be found in [X9.62]. +/// -- Any future additions to this CHOICE should be coordinated +/// -- with ANSI X9. +/// ``` +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum EcParameters { + /// Elliptic curve named by a particular OID. + /// + /// > namedCurve identifies all the required values for a particular + /// > set of elliptic curve domain parameters to be represented by an + /// > object identifier. + NamedCurve(ObjectIdentifier), +} + +impl<'a> DecodeValue<'a> for EcParameters { + fn decode_value>(decoder: &mut R, header: Header) -> der::Result { + ObjectIdentifier::decode_value(decoder, header).map(Self::NamedCurve) + } +} + +impl EncodeValue for EcParameters { + fn value_len(&self) -> der::Result { + match self { + Self::NamedCurve(oid) => oid.value_len(), + } + } + + fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { + match self { + Self::NamedCurve(oid) => oid.encode_value(writer), + } + } +} + +impl EcParameters { + /// Obtain the `namedCurve` OID. + pub fn named_curve(self) -> Option { + match self { + Self::NamedCurve(oid) => Some(oid), + } + } +} + +impl<'a> From<&'a EcParameters> for AnyRef<'a> { + fn from(params: &'a EcParameters) -> AnyRef<'a> { + match params { + EcParameters::NamedCurve(oid) => oid.into(), + } + } +} + +impl From for EcParameters { + fn from(oid: ObjectIdentifier) -> EcParameters { + EcParameters::NamedCurve(oid) + } +} + +impl FixedTag for EcParameters { + const TAG: Tag = Tag::ObjectIdentifier; +} diff --git a/src/rust/vendor/sec1/src/point.rs b/src/rust/vendor/sec1/src/point.rs new file mode 100644 index 000000000..818f5bda7 --- /dev/null +++ b/src/rust/vendor/sec1/src/point.rs @@ -0,0 +1,776 @@ +//! Support for the SEC1 `Elliptic-Curve-Point-to-Octet-String` and +//! `Octet-String-to-Elliptic-Curve-Point` encoding algorithms. +//! +//! Described in [SEC1: Elliptic Curve Cryptography] (Version 2.0) section 2.3.3 (p.10). +//! +//! [SEC1: Elliptic Curve Cryptography]: https://www.secg.org/sec1-v2.pdf + +use crate::{Error, Result}; +use base16ct::HexDisplay; +use core::{ + cmp::Ordering, + fmt::{self, Debug}, + hash::{Hash, Hasher}, + ops::Add, + str, +}; +use generic_array::{ + typenum::{U1, U24, U28, U32, U48, U66}, + ArrayLength, GenericArray, +}; + +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +#[cfg(feature = "subtle")] +use subtle::{Choice, ConditionallySelectable}; + +#[cfg(feature = "zeroize")] +use zeroize::Zeroize; + +/// Trait for supported modulus sizes which precomputes the typenums for +/// various point encodings so they don't need to be included as bounds. +// TODO(tarcieri): replace this all with const generic expressions. +pub trait ModulusSize: 'static + ArrayLength + Copy + Debug { + /// Size of a compressed point for the given elliptic curve when encoded + /// using the SEC1 `Elliptic-Curve-Point-to-Octet-String` algorithm + /// (including leading `0x02` or `0x03` tag byte). + type CompressedPointSize: 'static + ArrayLength + Copy + Debug; + + /// Size of an uncompressed point for the given elliptic curve when encoded + /// using the SEC1 `Elliptic-Curve-Point-to-Octet-String` algorithm + /// (including leading `0x04` tag byte). + type UncompressedPointSize: 'static + ArrayLength + Copy + Debug; + + /// Size of an untagged point for given elliptic curve, i.e. size of two + /// serialized base field elements. + type UntaggedPointSize: 'static + ArrayLength + Copy + Debug; +} + +macro_rules! impl_modulus_size { + ($($size:ty),+) => { + $(impl ModulusSize for $size { + type CompressedPointSize = <$size as Add>::Output; + type UncompressedPointSize = >::Output; + type UntaggedPointSize = <$size as Add>::Output; + })+ + } +} + +impl_modulus_size!(U24, U28, U32, U48, U66); + +/// SEC1 encoded curve point. +/// +/// This type is an enum over the compressed and uncompressed encodings, +/// useful for cases where either encoding can be supported, or conversions +/// between the two forms. +#[derive(Clone, Default)] +pub struct EncodedPoint +where + Size: ModulusSize, +{ + bytes: GenericArray, +} + +#[allow(clippy::len_without_is_empty)] +impl EncodedPoint +where + Size: ModulusSize, +{ + /// Decode elliptic curve point (compressed or uncompressed) from the + /// `Elliptic-Curve-Point-to-Octet-String` encoding described in + /// SEC 1: Elliptic Curve Cryptography (Version 2.0) section + /// 2.3.3 (page 10). + /// + /// + pub fn from_bytes(input: impl AsRef<[u8]>) -> Result { + let input = input.as_ref(); + + // Validate tag + let tag = input + .first() + .cloned() + .ok_or(Error::PointEncoding) + .and_then(Tag::from_u8)?; + + // Validate length + let expected_len = tag.message_len(Size::to_usize()); + + if input.len() != expected_len { + return Err(Error::PointEncoding); + } + + let mut bytes = GenericArray::default(); + bytes[..expected_len].copy_from_slice(input); + Ok(Self { bytes }) + } + + /// Decode elliptic curve point from raw uncompressed coordinates, i.e. + /// encoded as the concatenated `x || y` coordinates with no leading SEC1 + /// tag byte (which would otherwise be `0x04` for an uncompressed point). + pub fn from_untagged_bytes(bytes: &GenericArray) -> Self { + let (x, y) = bytes.split_at(Size::to_usize()); + Self::from_affine_coordinates(x.into(), y.into(), false) + } + + /// Encode an elliptic curve point from big endian serialized coordinates + /// (with optional point compression) + pub fn from_affine_coordinates( + x: &GenericArray, + y: &GenericArray, + compress: bool, + ) -> Self { + let tag = if compress { + Tag::compress_y(y.as_slice()) + } else { + Tag::Uncompressed + }; + + let mut bytes = GenericArray::default(); + bytes[0] = tag.into(); + bytes[1..(Size::to_usize() + 1)].copy_from_slice(x); + + if !compress { + bytes[(Size::to_usize() + 1)..].copy_from_slice(y); + } + + Self { bytes } + } + + /// Return [`EncodedPoint`] representing the additive identity + /// (a.k.a. point at infinity) + pub fn identity() -> Self { + Self::default() + } + + /// Get the length of the encoded point in bytes + pub fn len(&self) -> usize { + self.tag().message_len(Size::to_usize()) + } + + /// Get byte slice containing the serialized [`EncodedPoint`]. + pub fn as_bytes(&self) -> &[u8] { + &self.bytes[..self.len()] + } + + /// Get boxed byte slice containing the serialized [`EncodedPoint`] + #[cfg(feature = "alloc")] + pub fn to_bytes(&self) -> Box<[u8]> { + self.as_bytes().to_vec().into_boxed_slice() + } + + /// Is this [`EncodedPoint`] compact? + pub fn is_compact(&self) -> bool { + self.tag().is_compact() + } + + /// Is this [`EncodedPoint`] compressed? + pub fn is_compressed(&self) -> bool { + self.tag().is_compressed() + } + + /// Is this [`EncodedPoint`] the additive identity? (a.k.a. point at infinity) + pub fn is_identity(&self) -> bool { + self.tag().is_identity() + } + + /// Compress this [`EncodedPoint`], returning a new [`EncodedPoint`]. + pub fn compress(&self) -> Self { + match self.coordinates() { + Coordinates::Compressed { .. } + | Coordinates::Compact { .. } + | Coordinates::Identity => self.clone(), + Coordinates::Uncompressed { x, y } => Self::from_affine_coordinates(x, y, true), + } + } + + /// Get the SEC1 tag for this [`EncodedPoint`] + pub fn tag(&self) -> Tag { + // Tag is ensured valid by the constructor + Tag::from_u8(self.bytes[0]).expect("invalid tag") + } + + /// Get the [`Coordinates`] for this [`EncodedPoint`]. + #[inline] + pub fn coordinates(&self) -> Coordinates<'_, Size> { + if self.is_identity() { + return Coordinates::Identity; + } + + let (x, y) = self.bytes[1..].split_at(Size::to_usize()); + + if self.is_compressed() { + Coordinates::Compressed { + x: x.into(), + y_is_odd: self.tag() as u8 & 1 == 1, + } + } else if self.is_compact() { + Coordinates::Compact { x: x.into() } + } else { + Coordinates::Uncompressed { + x: x.into(), + y: y.into(), + } + } + } + + /// Get the x-coordinate for this [`EncodedPoint`]. + /// + /// Returns `None` if this point is the identity point. + pub fn x(&self) -> Option<&GenericArray> { + match self.coordinates() { + Coordinates::Identity => None, + Coordinates::Compressed { x, .. } => Some(x), + Coordinates::Uncompressed { x, .. } => Some(x), + Coordinates::Compact { x } => Some(x), + } + } + + /// Get the y-coordinate for this [`EncodedPoint`]. + /// + /// Returns `None` if this point is compressed or the identity point. + pub fn y(&self) -> Option<&GenericArray> { + match self.coordinates() { + Coordinates::Compressed { .. } | Coordinates::Identity => None, + Coordinates::Uncompressed { y, .. } => Some(y), + Coordinates::Compact { .. } => None, + } + } +} + +impl AsRef<[u8]> for EncodedPoint +where + Size: ModulusSize, +{ + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +#[cfg(feature = "subtle")] +impl ConditionallySelectable for EncodedPoint +where + Size: ModulusSize, + >::ArrayType: Copy, +{ + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + let mut bytes = GenericArray::default(); + + for (i, byte) in bytes.iter_mut().enumerate() { + *byte = u8::conditional_select(&a.bytes[i], &b.bytes[i], choice); + } + + Self { bytes } + } +} + +impl Copy for EncodedPoint +where + Size: ModulusSize, + >::ArrayType: Copy, +{ +} + +impl Debug for EncodedPoint +where + Size: ModulusSize, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "EncodedPoint({:?})", self.coordinates()) + } +} + +impl Eq for EncodedPoint {} + +impl PartialEq for EncodedPoint +where + Size: ModulusSize, +{ + fn eq(&self, other: &Self) -> bool { + self.as_bytes() == other.as_bytes() + } +} + +impl Hash for EncodedPoint +where + Size: ModulusSize, +{ + fn hash(&self, state: &mut H) { + self.as_bytes().hash(state) + } +} + +impl PartialOrd for EncodedPoint +where + Size: ModulusSize, +{ + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for EncodedPoint +where + Size: ModulusSize, +{ + fn cmp(&self, other: &Self) -> Ordering { + self.as_bytes().cmp(other.as_bytes()) + } +} + +impl TryFrom<&[u8]> for EncodedPoint +where + Size: ModulusSize, +{ + type Error = Error; + + fn try_from(bytes: &[u8]) -> Result { + Self::from_bytes(bytes) + } +} + +#[cfg(feature = "zeroize")] +impl Zeroize for EncodedPoint +where + Size: ModulusSize, +{ + fn zeroize(&mut self) { + self.bytes.zeroize(); + *self = Self::identity(); + } +} + +impl fmt::Display for EncodedPoint +where + Size: ModulusSize, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:X}", self) + } +} + +impl fmt::LowerHex for EncodedPoint +where + Size: ModulusSize, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:x}", HexDisplay(self.as_bytes())) + } +} + +impl fmt::UpperHex for EncodedPoint +where + Size: ModulusSize, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:X}", HexDisplay(self.as_bytes())) + } +} + +/// Decode a SEC1-encoded point from hexadecimal. +/// +/// Upper and lower case hexadecimal are both accepted, however mixed case is +/// rejected. +impl str::FromStr for EncodedPoint +where + Size: ModulusSize, +{ + type Err = Error; + + fn from_str(hex: &str) -> Result { + let mut buf = GenericArray::::default(); + base16ct::mixed::decode(hex, &mut buf) + .map_err(|_| Error::PointEncoding) + .and_then(Self::from_bytes) + } +} + +#[cfg(feature = "serde")] +impl Serialize for EncodedPoint +where + Size: ModulusSize, +{ + fn serialize(&self, serializer: S) -> core::result::Result + where + S: ser::Serializer, + { + serdect::slice::serialize_hex_upper_or_bin(&self.as_bytes(), serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, Size> Deserialize<'de> for EncodedPoint +where + Size: ModulusSize, +{ + fn deserialize(deserializer: D) -> core::result::Result + where + D: de::Deserializer<'de>, + { + let bytes = serdect::slice::deserialize_hex_or_bin_vec(deserializer)?; + Self::from_bytes(bytes).map_err(de::Error::custom) + } +} + +/// Enum representing the coordinates of either compressed or uncompressed +/// SEC1-encoded elliptic curve points. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Coordinates<'a, Size: ModulusSize> { + /// Identity point (a.k.a. point at infinity) + Identity, + + /// Compact curve point + Compact { + /// x-coordinate + x: &'a GenericArray, + }, + + /// Compressed curve point + Compressed { + /// x-coordinate + x: &'a GenericArray, + + /// Is the y-coordinate odd? + y_is_odd: bool, + }, + + /// Uncompressed curve point + Uncompressed { + /// x-coordinate + x: &'a GenericArray, + + /// y-coordinate + y: &'a GenericArray, + }, +} + +impl<'a, Size: ModulusSize> Coordinates<'a, Size> { + /// Get the tag octet needed to encode this set of [`Coordinates`] + pub fn tag(&self) -> Tag { + match self { + Coordinates::Compact { .. } => Tag::Compact, + Coordinates::Compressed { y_is_odd, .. } => { + if *y_is_odd { + Tag::CompressedOddY + } else { + Tag::CompressedEvenY + } + } + Coordinates::Identity => Tag::Identity, + Coordinates::Uncompressed { .. } => Tag::Uncompressed, + } + } +} + +/// Tag byte used by the `Elliptic-Curve-Point-to-Octet-String` encoding. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(u8)] +pub enum Tag { + /// Identity point (`0x00`) + Identity = 0, + + /// Compressed point with even y-coordinate (`0x02`) + CompressedEvenY = 2, + + /// Compressed point with odd y-coordinate (`0x03`) + CompressedOddY = 3, + + /// Uncompressed point (`0x04`) + Uncompressed = 4, + + /// Compact point (`0x05`) + Compact = 5, +} + +impl Tag { + /// Parse a tag value from a byte + pub fn from_u8(byte: u8) -> Result { + match byte { + 0 => Ok(Tag::Identity), + 2 => Ok(Tag::CompressedEvenY), + 3 => Ok(Tag::CompressedOddY), + 4 => Ok(Tag::Uncompressed), + 5 => Ok(Tag::Compact), + _ => Err(Error::PointEncoding), + } + } + + /// Is this point compact? + pub fn is_compact(self) -> bool { + matches!(self, Tag::Compact) + } + + /// Is this point compressed? + pub fn is_compressed(self) -> bool { + matches!(self, Tag::CompressedEvenY | Tag::CompressedOddY) + } + + /// Is this point the identity point? + pub fn is_identity(self) -> bool { + self == Tag::Identity + } + + /// Compute the expected total message length for a message prefixed + /// with this tag (including the tag byte), given the field element size + /// (in bytes) for a particular elliptic curve. + pub fn message_len(self, field_element_size: usize) -> usize { + 1 + match self { + Tag::Identity => 0, + Tag::CompressedEvenY | Tag::CompressedOddY => field_element_size, + Tag::Uncompressed => field_element_size * 2, + Tag::Compact => field_element_size, + } + } + + /// Compress the given y-coordinate, returning a `Tag::Compressed*` value + fn compress_y(y: &[u8]) -> Self { + // Is the y-coordinate odd in the SEC1 sense: `self mod 2 == 1`? + if y.as_ref().last().expect("empty y-coordinate") & 1 == 1 { + Tag::CompressedOddY + } else { + Tag::CompressedEvenY + } + } +} + +impl TryFrom for Tag { + type Error = Error; + + fn try_from(byte: u8) -> Result { + Self::from_u8(byte) + } +} + +impl From for u8 { + fn from(tag: Tag) -> u8 { + tag as u8 + } +} + +#[cfg(test)] +mod tests { + use super::{Coordinates, Tag}; + use core::str::FromStr; + use generic_array::{typenum::U32, GenericArray}; + use hex_literal::hex; + + #[cfg(feature = "alloc")] + use alloc::string::ToString; + + #[cfg(feature = "subtle")] + use subtle::ConditionallySelectable; + + type EncodedPoint = super::EncodedPoint; + + /// Identity point + const IDENTITY_BYTES: [u8; 1] = [0]; + + /// Example uncompressed point + const UNCOMPRESSED_BYTES: [u8; 65] = hex!("0411111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222"); + + /// Example compressed point: `UNCOMPRESSED_BYTES` after point compression + const COMPRESSED_BYTES: [u8; 33] = + hex!("021111111111111111111111111111111111111111111111111111111111111111"); + + #[test] + fn decode_compressed_point() { + // Even y-coordinate + let compressed_even_y_bytes = + hex!("020100000000000000000000000000000000000000000000000000000000000000"); + + let compressed_even_y = EncodedPoint::from_bytes(&compressed_even_y_bytes[..]).unwrap(); + + assert!(compressed_even_y.is_compressed()); + assert_eq!(compressed_even_y.tag(), Tag::CompressedEvenY); + assert_eq!(compressed_even_y.len(), 33); + assert_eq!(compressed_even_y.as_bytes(), &compressed_even_y_bytes[..]); + + assert_eq!( + compressed_even_y.coordinates(), + Coordinates::Compressed { + x: &hex!("0100000000000000000000000000000000000000000000000000000000000000").into(), + y_is_odd: false + } + ); + + assert_eq!( + compressed_even_y.x().unwrap(), + &hex!("0100000000000000000000000000000000000000000000000000000000000000").into() + ); + assert_eq!(compressed_even_y.y(), None); + + // Odd y-coordinate + let compressed_odd_y_bytes = + hex!("030200000000000000000000000000000000000000000000000000000000000000"); + + let compressed_odd_y = EncodedPoint::from_bytes(&compressed_odd_y_bytes[..]).unwrap(); + + assert!(compressed_odd_y.is_compressed()); + assert_eq!(compressed_odd_y.tag(), Tag::CompressedOddY); + assert_eq!(compressed_odd_y.len(), 33); + assert_eq!(compressed_odd_y.as_bytes(), &compressed_odd_y_bytes[..]); + + assert_eq!( + compressed_odd_y.coordinates(), + Coordinates::Compressed { + x: &hex!("0200000000000000000000000000000000000000000000000000000000000000").into(), + y_is_odd: true + } + ); + + assert_eq!( + compressed_odd_y.x().unwrap(), + &hex!("0200000000000000000000000000000000000000000000000000000000000000").into() + ); + assert_eq!(compressed_odd_y.y(), None); + } + + #[test] + fn decode_uncompressed_point() { + let uncompressed_point = EncodedPoint::from_bytes(&UNCOMPRESSED_BYTES[..]).unwrap(); + + assert!(!uncompressed_point.is_compressed()); + assert_eq!(uncompressed_point.tag(), Tag::Uncompressed); + assert_eq!(uncompressed_point.len(), 65); + assert_eq!(uncompressed_point.as_bytes(), &UNCOMPRESSED_BYTES[..]); + + assert_eq!( + uncompressed_point.coordinates(), + Coordinates::Uncompressed { + x: &hex!("1111111111111111111111111111111111111111111111111111111111111111").into(), + y: &hex!("2222222222222222222222222222222222222222222222222222222222222222").into() + } + ); + + assert_eq!( + uncompressed_point.x().unwrap(), + &hex!("1111111111111111111111111111111111111111111111111111111111111111").into() + ); + assert_eq!( + uncompressed_point.y().unwrap(), + &hex!("2222222222222222222222222222222222222222222222222222222222222222").into() + ); + } + + #[test] + fn decode_identity() { + let identity_point = EncodedPoint::from_bytes(&IDENTITY_BYTES[..]).unwrap(); + assert!(identity_point.is_identity()); + assert_eq!(identity_point.tag(), Tag::Identity); + assert_eq!(identity_point.len(), 1); + assert_eq!(identity_point.as_bytes(), &IDENTITY_BYTES[..]); + assert_eq!(identity_point.coordinates(), Coordinates::Identity); + assert_eq!(identity_point.x(), None); + assert_eq!(identity_point.y(), None); + } + + #[test] + fn decode_invalid_tag() { + let mut compressed_bytes = COMPRESSED_BYTES; + let mut uncompressed_bytes = UNCOMPRESSED_BYTES; + + for bytes in &mut [&mut compressed_bytes[..], &mut uncompressed_bytes[..]] { + for tag in 0..=0xFF { + // valid tags + if tag == 2 || tag == 3 || tag == 4 || tag == 5 { + continue; + } + + (*bytes)[0] = tag; + let decode_result = EncodedPoint::from_bytes(&*bytes); + assert!(decode_result.is_err()); + } + } + } + + #[test] + fn decode_truncated_point() { + for bytes in &[&COMPRESSED_BYTES[..], &UNCOMPRESSED_BYTES[..]] { + for len in 0..bytes.len() { + let decode_result = EncodedPoint::from_bytes(&bytes[..len]); + assert!(decode_result.is_err()); + } + } + } + + #[test] + fn from_untagged_point() { + let untagged_bytes = hex!("11111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222"); + let uncompressed_point = + EncodedPoint::from_untagged_bytes(GenericArray::from_slice(&untagged_bytes[..])); + assert_eq!(uncompressed_point.as_bytes(), &UNCOMPRESSED_BYTES[..]); + } + + #[test] + fn from_affine_coordinates() { + let x = hex!("1111111111111111111111111111111111111111111111111111111111111111"); + let y = hex!("2222222222222222222222222222222222222222222222222222222222222222"); + + let uncompressed_point = EncodedPoint::from_affine_coordinates(&x.into(), &y.into(), false); + assert_eq!(uncompressed_point.as_bytes(), &UNCOMPRESSED_BYTES[..]); + + let compressed_point = EncodedPoint::from_affine_coordinates(&x.into(), &y.into(), true); + assert_eq!(compressed_point.as_bytes(), &COMPRESSED_BYTES[..]); + } + + #[test] + fn compress() { + let uncompressed_point = EncodedPoint::from_bytes(&UNCOMPRESSED_BYTES[..]).unwrap(); + let compressed_point = uncompressed_point.compress(); + assert_eq!(compressed_point.as_bytes(), &COMPRESSED_BYTES[..]); + } + + #[cfg(feature = "subtle")] + #[test] + fn conditional_select() { + let a = EncodedPoint::from_bytes(&COMPRESSED_BYTES[..]).unwrap(); + let b = EncodedPoint::from_bytes(&UNCOMPRESSED_BYTES[..]).unwrap(); + + let a_selected = EncodedPoint::conditional_select(&a, &b, 0.into()); + assert_eq!(a, a_selected); + + let b_selected = EncodedPoint::conditional_select(&a, &b, 1.into()); + assert_eq!(b, b_selected); + } + + #[test] + fn identity() { + let identity_point = EncodedPoint::identity(); + assert_eq!(identity_point.tag(), Tag::Identity); + assert_eq!(identity_point.len(), 1); + assert_eq!(identity_point.as_bytes(), &IDENTITY_BYTES[..]); + + // identity is default + assert_eq!(identity_point, EncodedPoint::default()); + } + + #[test] + fn decode_hex() { + let point = EncodedPoint::from_str( + "021111111111111111111111111111111111111111111111111111111111111111", + ) + .unwrap(); + assert_eq!(point.as_bytes(), COMPRESSED_BYTES); + } + + #[cfg(feature = "alloc")] + #[test] + fn to_bytes() { + let uncompressed_point = EncodedPoint::from_bytes(&UNCOMPRESSED_BYTES[..]).unwrap(); + assert_eq!(&*uncompressed_point.to_bytes(), &UNCOMPRESSED_BYTES[..]); + } + + #[cfg(feature = "alloc")] + #[test] + fn to_string() { + let point = EncodedPoint::from_bytes(&COMPRESSED_BYTES[..]).unwrap(); + assert_eq!( + point.to_string(), + "021111111111111111111111111111111111111111111111111111111111111111" + ); + } +} diff --git a/src/rust/vendor/sec1/src/private_key.rs b/src/rust/vendor/sec1/src/private_key.rs new file mode 100644 index 000000000..531579936 --- /dev/null +++ b/src/rust/vendor/sec1/src/private_key.rs @@ -0,0 +1,177 @@ +//! SEC1 elliptic curve private key support. +//! +//! Support for ASN.1 DER-encoded elliptic curve private keys as described in +//! SEC1: Elliptic Curve Cryptography (Version 2.0) Appendix C.4 (p.108): +//! +//! + +use crate::{EcParameters, Error, Result}; +use core::fmt; +use der::{ + asn1::{BitStringRef, ContextSpecific, ContextSpecificRef, OctetStringRef}, + Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag, TagMode, + TagNumber, Writer, +}; + +#[cfg(all(feature = "alloc", feature = "zeroize"))] +use der::SecretDocument; + +#[cfg(feature = "pem")] +use der::pem::PemLabel; + +/// `ECPrivateKey` version. +/// +/// From [RFC5913 Section 3]: +/// > version specifies the syntax version number of the elliptic curve +/// > private key structure. For this version of the document, it SHALL +/// > be set to ecPrivkeyVer1, which is of type INTEGER and whose value +/// > is one (1). +/// +/// [RFC5915 Section 3]: https://datatracker.ietf.org/doc/html/rfc5915#section-3 +const VERSION: u8 = 1; + +/// Context-specific tag number for the elliptic curve parameters. +const EC_PARAMETERS_TAG: TagNumber = TagNumber::new(0); + +/// Context-specific tag number for the public key. +const PUBLIC_KEY_TAG: TagNumber = TagNumber::new(1); + +/// SEC1 elliptic curve private key. +/// +/// Described in [SEC1: Elliptic Curve Cryptography (Version 2.0)] +/// Appendix C.4 (p.108) and also [RFC5915 Section 3]: +/// +/// ```text +/// ECPrivateKey ::= SEQUENCE { +/// version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), +/// privateKey OCTET STRING, +/// parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, +/// publicKey [1] BIT STRING OPTIONAL +/// } +/// ``` +/// +/// When encoded as PEM (text), keys in this format begin with the following: +/// +/// ```text +/// -----BEGIN EC PRIVATE KEY----- +/// ``` +/// +/// [SEC1: Elliptic Curve Cryptography (Version 2.0)]: https://www.secg.org/sec1-v2.pdf +/// [RFC5915 Section 3]: https://datatracker.ietf.org/doc/html/rfc5915#section-3 +#[derive(Clone)] +pub struct EcPrivateKey<'a> { + /// Private key data. + pub private_key: &'a [u8], + + /// Elliptic curve parameters. + pub parameters: Option, + + /// Public key data, optionally available if version is V2. + pub public_key: Option<&'a [u8]>, +} + +impl<'a> EcPrivateKey<'a> { + fn context_specific_parameters(&self) -> Option> { + self.parameters.as_ref().map(|params| ContextSpecificRef { + tag_number: EC_PARAMETERS_TAG, + tag_mode: TagMode::Explicit, + value: params, + }) + } + + fn context_specific_public_key( + &self, + ) -> der::Result>>> { + self.public_key + .map(|pk| { + BitStringRef::from_bytes(pk).map(|value| ContextSpecific { + tag_number: PUBLIC_KEY_TAG, + tag_mode: TagMode::Explicit, + value, + }) + }) + .transpose() + } +} + +impl<'a> DecodeValue<'a> for EcPrivateKey<'a> { + fn decode_value>(reader: &mut R, header: Header) -> der::Result { + reader.read_nested(header.length, |reader| { + if u8::decode(reader)? != VERSION { + return Err(der::Tag::Integer.value_error()); + } + + let private_key = OctetStringRef::decode(reader)?.as_bytes(); + let parameters = reader.context_specific(EC_PARAMETERS_TAG, TagMode::Explicit)?; + let public_key = reader + .context_specific::>(PUBLIC_KEY_TAG, TagMode::Explicit)? + .map(|bs| bs.as_bytes().ok_or_else(|| Tag::BitString.value_error())) + .transpose()?; + + Ok(EcPrivateKey { + private_key, + parameters, + public_key, + }) + }) + } +} + +impl EncodeValue for EcPrivateKey<'_> { + fn value_len(&self) -> der::Result { + VERSION.encoded_len()? + + OctetStringRef::new(self.private_key)?.encoded_len()? + + self.context_specific_parameters().encoded_len()? + + self.context_specific_public_key()?.encoded_len()? + } + + fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { + VERSION.encode(writer)?; + OctetStringRef::new(self.private_key)?.encode(writer)?; + self.context_specific_parameters().encode(writer)?; + self.context_specific_public_key()?.encode(writer)?; + Ok(()) + } +} + +impl<'a> Sequence<'a> for EcPrivateKey<'a> {} + +impl<'a> TryFrom<&'a [u8]> for EcPrivateKey<'a> { + type Error = Error; + + fn try_from(bytes: &'a [u8]) -> Result> { + Ok(Self::from_der(bytes)?) + } +} + +impl<'a> fmt::Debug for EcPrivateKey<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("EcPrivateKey") + .field("parameters", &self.parameters) + .field("public_key", &self.public_key) + .finish_non_exhaustive() + } +} + +#[cfg(feature = "alloc")] +impl TryFrom> for SecretDocument { + type Error = Error; + + fn try_from(private_key: EcPrivateKey<'_>) -> Result { + SecretDocument::try_from(&private_key) + } +} + +#[cfg(feature = "alloc")] +impl TryFrom<&EcPrivateKey<'_>> for SecretDocument { + type Error = Error; + + fn try_from(private_key: &EcPrivateKey<'_>) -> Result { + Ok(Self::encode_msg(private_key)?) + } +} + +#[cfg(feature = "pem")] +impl PemLabel for EcPrivateKey<'_> { + const PEM_LABEL: &'static str = "EC PRIVATE KEY"; +} diff --git a/src/rust/vendor/sec1/src/traits.rs b/src/rust/vendor/sec1/src/traits.rs new file mode 100644 index 000000000..304019e3c --- /dev/null +++ b/src/rust/vendor/sec1/src/traits.rs @@ -0,0 +1,122 @@ +//! Traits for parsing objects from SEC1 encoded documents + +use crate::Result; + +#[cfg(feature = "alloc")] +use der::SecretDocument; + +#[cfg(feature = "pem")] +use {crate::LineEnding, alloc::string::String, der::pem::PemLabel}; + +#[cfg(feature = "pkcs8")] +use { + crate::{EcPrivateKey, ALGORITHM_OID}, + der::Decode, +}; + +#[cfg(feature = "std")] +use std::path::Path; + +#[cfg(feature = "pem")] +use zeroize::Zeroizing; + +/// Parse an [`EcPrivateKey`] from a SEC1-encoded document. +pub trait DecodeEcPrivateKey: Sized { + /// Deserialize SEC1 private key from ASN.1 DER-encoded data + /// (binary format). + fn from_sec1_der(bytes: &[u8]) -> Result; + + /// Deserialize SEC1-encoded private key from PEM. + /// + /// Keys in this format begin with the following: + /// + /// ```text + /// -----BEGIN EC PRIVATE KEY----- + /// ``` + #[cfg(feature = "pem")] + fn from_sec1_pem(s: &str) -> Result { + let (label, doc) = SecretDocument::from_pem(s)?; + EcPrivateKey::validate_pem_label(label)?; + Self::from_sec1_der(doc.as_bytes()) + } + + /// Load SEC1 private key from an ASN.1 DER-encoded file on the local + /// filesystem (binary format). + #[cfg(feature = "std")] + fn read_sec1_der_file(path: impl AsRef) -> Result { + Self::from_sec1_der(SecretDocument::read_der_file(path)?.as_bytes()) + } + + /// Load SEC1 private key from a PEM-encoded file on the local filesystem. + #[cfg(all(feature = "pem", feature = "std"))] + fn read_sec1_pem_file(path: impl AsRef) -> Result { + let (label, doc) = SecretDocument::read_pem_file(path)?; + EcPrivateKey::validate_pem_label(&label)?; + Self::from_sec1_der(doc.as_bytes()) + } +} + +/// Serialize a [`EcPrivateKey`] to a SEC1 encoded document. +#[cfg(feature = "alloc")] +pub trait EncodeEcPrivateKey { + /// Serialize a [`SecretDocument`] containing a SEC1-encoded private key. + fn to_sec1_der(&self) -> Result; + + /// Serialize this private key as PEM-encoded SEC1 with the given [`LineEnding`]. + /// + /// To use the OS's native line endings, pass `Default::default()`. + #[cfg(feature = "pem")] + fn to_sec1_pem(&self, line_ending: LineEnding) -> Result> { + let doc = self.to_sec1_der()?; + Ok(doc.to_pem(EcPrivateKey::PEM_LABEL, line_ending)?) + } + + /// Write ASN.1 DER-encoded SEC1 private key to the given path. + #[cfg(feature = "std")] + fn write_sec1_der_file(&self, path: impl AsRef) -> Result<()> { + Ok(self.to_sec1_der()?.write_der_file(path)?) + } + + /// Write ASN.1 DER-encoded SEC1 private key to the given path. + #[cfg(all(feature = "pem", feature = "std"))] + fn write_sec1_pem_file(&self, path: impl AsRef, line_ending: LineEnding) -> Result<()> { + let doc = self.to_sec1_der()?; + Ok(doc.write_pem_file(path, EcPrivateKey::PEM_LABEL, line_ending)?) + } +} + +#[cfg(feature = "pkcs8")] +impl DecodeEcPrivateKey for T +where + T: for<'a> TryFrom, Error = pkcs8::Error>, +{ + fn from_sec1_der(private_key: &[u8]) -> Result { + let params_oid = EcPrivateKey::from_der(private_key)? + .parameters + .and_then(|params| params.named_curve()); + + let algorithm = pkcs8::AlgorithmIdentifierRef { + oid: ALGORITHM_OID, + parameters: params_oid.as_ref().map(Into::into), + }; + + Ok(Self::try_from(pkcs8::PrivateKeyInfo { + algorithm, + private_key, + public_key: None, + })?) + } +} + +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +impl EncodeEcPrivateKey for T { + fn to_sec1_der(&self) -> Result { + let doc = self.to_pkcs8_der()?; + let pkcs8_key = pkcs8::PrivateKeyInfo::from_der(doc.as_bytes())?; + pkcs8_key.algorithm.assert_algorithm_oid(ALGORITHM_OID)?; + + let mut pkcs1_key = EcPrivateKey::from_der(pkcs8_key.private_key)?; + pkcs1_key.parameters = Some(pkcs8_key.algorithm.parameters_oid()?.into()); + pkcs1_key.try_into() + } +} diff --git a/src/rust/vendor/sec1/tests/examples/p256-priv.der b/src/rust/vendor/sec1/tests/examples/p256-priv.der new file mode 100644 index 000000000..c8528c30f Binary files /dev/null and b/src/rust/vendor/sec1/tests/examples/p256-priv.der differ diff --git a/src/rust/vendor/sec1/tests/examples/p256-priv.pem b/src/rust/vendor/sec1/tests/examples/p256-priv.pem new file mode 100644 index 000000000..d5a1c1aea --- /dev/null +++ b/src/rust/vendor/sec1/tests/examples/p256-priv.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIGliQXFWGmM0DeDn2GnyoFSSVY4aBIaLap+FSoZniBiNoAoGCCqGSM49 +AwEHoUQDQgAEHKz/tV8vLO/YnYnrN0smgRUkUoAt7qCZFgaBN9g5z3/EgaREkjBN +fvZqwRe+/oOo0I8VXytS+fYY3URwKQSODw== +-----END EC PRIVATE KEY----- diff --git a/src/rust/vendor/sec1/tests/private_key.rs b/src/rust/vendor/sec1/tests/private_key.rs new file mode 100644 index 000000000..224a947e7 --- /dev/null +++ b/src/rust/vendor/sec1/tests/private_key.rs @@ -0,0 +1,43 @@ +//! SEC1 private key tests + +#![cfg(feature = "der")] + +use der::asn1::ObjectIdentifier; +use hex_literal::hex; +use sec1::{EcParameters, EcPrivateKey}; + +#[cfg(feature = "alloc")] +use der::Encode; + +/// NIST P-256 SEC1 private key encoded as ASN.1 DER. +/// +/// Note: this key is extracted from the corresponding `p256-priv.der` +/// example key in the `pkcs8` crate. +const P256_DER_EXAMPLE: &[u8] = include_bytes!("examples/p256-priv.der"); + +#[test] +fn decode_p256_der() { + let key = EcPrivateKey::try_from(P256_DER_EXAMPLE).unwrap(); + + // Extracted using: + // $ openssl asn1parse -in tests/examples/p256-priv.pem + assert_eq!( + key.private_key, + hex!("69624171561A63340DE0E7D869F2A05492558E1A04868B6A9F854A866788188D") + ); + assert_eq!( + key.parameters, + Some(EcParameters::NamedCurve( + ObjectIdentifier::new("1.2.840.10045.3.1.7").unwrap() + )) + ); + assert_eq!(key.public_key, Some(hex!("041CACFFB55F2F2CEFD89D89EB374B2681152452802DEEA09916068137D839CF7FC481A44492304D7EF66AC117BEFE83A8D08F155F2B52F9F618DD447029048E0F").as_ref())); +} + +#[cfg(feature = "alloc")] +#[test] +fn encode_p256_der() { + let key = EcPrivateKey::try_from(P256_DER_EXAMPLE).unwrap(); + let key_encoded = key.to_der().unwrap(); + assert_eq!(P256_DER_EXAMPLE, key_encoded); +} diff --git a/src/rust/vendor/sec1/tests/traits.rs b/src/rust/vendor/sec1/tests/traits.rs new file mode 100644 index 000000000..ab6e09a20 --- /dev/null +++ b/src/rust/vendor/sec1/tests/traits.rs @@ -0,0 +1,100 @@ +//! Tests for SEC1 encoding/decoding traits. + +#![cfg(any(feature = "pem", all(feature = "der", feature = "std")))] + +use der::SecretDocument; +use sec1::{DecodeEcPrivateKey, EncodeEcPrivateKey, Result}; + +#[cfg(feature = "pem")] +use sec1::der::pem::LineEnding; + +#[cfg(feature = "std")] +use tempfile::tempdir; + +#[cfg(all(feature = "pem", feature = "std"))] +use std::fs; + +/// SEC1 `EcPrivateKey` encoded as ASN.1 DER +const P256_DER_EXAMPLE: &[u8] = include_bytes!("examples/p256-priv.der"); + +/// SEC1 `EcPrivateKey` encoded as PEM +#[cfg(feature = "pem")] +const P256_PEM_EXAMPLE: &str = include_str!("examples/p256-priv.pem"); + +/// Mock private key type for testing trait impls against. +pub struct MockPrivateKey(Vec); + +impl AsRef<[u8]> for MockPrivateKey { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +impl DecodeEcPrivateKey for MockPrivateKey { + fn from_sec1_der(bytes: &[u8]) -> Result { + Ok(MockPrivateKey(bytes.to_vec())) + } +} + +impl EncodeEcPrivateKey for MockPrivateKey { + fn to_sec1_der(&self) -> Result { + Ok(SecretDocument::try_from(self.as_ref())?) + } +} + +#[cfg(feature = "pem")] +#[test] +fn from_sec1_pem() { + let key = MockPrivateKey::from_sec1_pem(P256_PEM_EXAMPLE).unwrap(); + assert_eq!(key.as_ref(), P256_DER_EXAMPLE); +} + +#[cfg(feature = "std")] +#[test] +fn read_sec1_der_file() { + let key = MockPrivateKey::read_sec1_der_file("tests/examples/p256-priv.der").unwrap(); + assert_eq!(key.as_ref(), P256_DER_EXAMPLE); +} + +#[cfg(all(feature = "pem", feature = "std"))] +#[test] +fn read_sec1_pem_file() { + let key = MockPrivateKey::read_sec1_pem_file("tests/examples/p256-priv.pem").unwrap(); + assert_eq!(key.as_ref(), P256_DER_EXAMPLE); +} + +#[cfg(feature = "pem")] +#[test] +fn to_sec1_pem() { + let pem = MockPrivateKey(P256_DER_EXAMPLE.to_vec()) + .to_sec1_pem(LineEnding::LF) + .unwrap(); + + assert_eq!(&*pem, P256_PEM_EXAMPLE); +} + +#[cfg(feature = "std")] +#[test] +fn write_sec1_der_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("example.der"); + MockPrivateKey(P256_DER_EXAMPLE.to_vec()) + .write_sec1_der_file(&path) + .unwrap(); + + let key = MockPrivateKey::read_sec1_der_file(&path).unwrap(); + assert_eq!(key.as_ref(), P256_DER_EXAMPLE); +} + +#[cfg(all(feature = "pem", feature = "std"))] +#[test] +fn write_sec1_pem_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("example.pem"); + MockPrivateKey(P256_DER_EXAMPLE.to_vec()) + .write_sec1_pem_file(&path, LineEnding::LF) + .unwrap(); + + let pem = fs::read_to_string(path).unwrap(); + assert_eq!(&pem, P256_PEM_EXAMPLE); +} diff --git a/src/securechip/securechip.c b/src/securechip/securechip.c index 155a4a978..110cafba3 100644 --- a/src/securechip/securechip.c +++ b/src/securechip/securechip.c @@ -26,8 +26,6 @@ typedef struct { bool (*attestation_sign)(const uint8_t* challenge, uint8_t* signature_out); bool (*monotonic_increments_remaining)(uint32_t* remaining_out); bool (*random)(uint8_t* rand_out); - bool (*ecc_generate_public_key)(uint8_t* priv_key, uint8_t* pub_key); - bool (*ecc_unsafe_sign)(const uint8_t* priv_key, const uint8_t* msg, uint8_t* sig); #if APP_U2F == 1 || FACTORYSETUP == 1 bool (*u2f_counter_set)(uint32_t counter); #endif @@ -56,8 +54,6 @@ bool securechip_init(void) _fns.attestation_sign = atecc_attestation_sign; _fns.monotonic_increments_remaining = atecc_monotonic_increments_remaining; _fns.random = atecc_random; - _fns.ecc_generate_public_key = atecc_ecc_generate_public_key; - _fns.ecc_unsafe_sign = atecc_ecc_unsafe_sign; #if APP_U2F == 1 || FACTORYSETUP == 1 _fns.u2f_counter_set = atecc_u2f_counter_set; #endif @@ -125,18 +121,6 @@ bool securechip_random(uint8_t* rand_out) return _fns.random(rand_out); } -bool securechip_ecc_generate_public_key(uint8_t* priv_key, uint8_t* pub_key) -{ - ABORT_IF_NULL(ecc_generate_public_key); - return _fns.ecc_generate_public_key(priv_key, pub_key); -} - -bool securechip_ecc_unsafe_sign(const uint8_t* priv_key, const uint8_t* msg, uint8_t* sig) -{ - ABORT_IF_NULL(ecc_unsafe_sign); - return _fns.ecc_unsafe_sign(priv_key, msg, sig); -} - #if APP_U2F == 1 || FACTORYSETUP == 1 bool securechip_u2f_counter_set(uint32_t counter) { diff --git a/src/securechip/securechip.h b/src/securechip/securechip.h index 6def21c8e..ca26ae05c 100644 --- a/src/securechip/securechip.h +++ b/src/securechip/securechip.h @@ -120,27 +120,6 @@ USE_RESULT bool securechip_monotonic_increments_remaining(uint32_t* remaining_ou */ USE_RESULT bool securechip_random(uint8_t* rand_out); -/** - * Generates the matching public key to the provided private key. Will put private key in unsafe - * ECC slot. - * @param[in] priv_key Private key (32 bytes). - * @param[out] pub_key Public key. Format will be the X and Y coordinates in big-endian (64 bytes). - * @return True if success - */ -USE_RESULT bool securechip_ecc_generate_public_key(uint8_t* priv_key, uint8_t* pub_key); - -/** - * Sign hash with private key. Will put private key in unsafe ECC slot. - * @param[in] priv_key Private key to use for signing (32 bytes) - * @param[in] msg Message to sign (32 bytes) - * @param[out] sig Signature (64 bytes) - * @return True if success - */ -USE_RESULT bool securechip_ecc_unsafe_sign( - const uint8_t* priv_key, - const uint8_t* msg, - uint8_t* sig); - #if APP_U2F == 1 || FACTORYSETUP == 1 /** * Set the u2f counter to `counter`. Should only be used for initialization. diff --git a/src/u2f.c b/src/u2f.c index 2f1ea1d04..c3fb1aad6 100644 --- a/src/u2f.c +++ b/src/u2f.c @@ -13,7 +13,6 @@ // limitations under the License. #include "u2f.h" #include "u2f/u2f_app.h" - #include #include @@ -480,9 +479,10 @@ static void _register_continue(const USB_APDU* apdu, Packet* out_packet) if (!_keyhandle_gen(reg_request->appId, nonce, privkey, mac)) { continue; } - if (securechip_ecc_generate_public_key(privkey, (uint8_t*)&response->pubKey.x)) { - break; - } + rust_p256_pubkey( + rust_util_bytes(privkey, sizeof(privkey)), + rust_util_bytes_mut((uint8_t*)&response->pubKey.x, 64)); + break; } response->pubKey.format = U2F_UNCOMPRESSED_POINT; @@ -504,10 +504,10 @@ static void _register_continue(const USB_APDU* apdu, Packet* out_packet) uint8_t hash[SHA256_LEN] = {0}; wally_sha256((uint8_t*)&sig_base, sizeof(sig_base), hash, SHA256_LEN); - if (!securechip_ecc_unsafe_sign(U2F_ATT_PRIV_KEY, hash, sig)) { - _error(U2F_SW_CONDITIONS_NOT_SATISFIED, out_packet); - return; - } + rust_p256_sign( + rust_util_bytes(U2F_ATT_PRIV_KEY, sizeof(U2F_ATT_PRIV_KEY)), + rust_util_bytes(hash, sizeof(hash)), + rust_util_bytes_mut(sig, sizeof(sig))); uint8_t* resp_sig = response->keyHandleCertSig + response->keyHandleLen + sizeof(U2F_ATT_CERT); int der_len = _sig_to_der(sig, resp_sig); @@ -687,11 +687,10 @@ static void _authenticate_continue(const USB_APDU* apdu, Packet* out_packet) uint8_t hash[SHA256_LEN] = {0}; wally_sha256((uint8_t*)&sig_base, sizeof(sig_base), hash, SHA256_LEN); - if (!securechip_ecc_unsafe_sign(privkey, hash, sig)) { - _error(U2F_SW_WRONG_DATA, out_packet); - return; - } - + rust_p256_sign( + rust_util_bytes(privkey, sizeof(privkey)), + rust_util_bytes(hash, sizeof(hash)), + rust_util_bytes_mut(sig, sizeof(sig))); int der_len = _sig_to_der(sig, response->sig); size_t auth_packet_len = sizeof(U2F_AUTHENTICATE_RESP) - U2F_MAX_EC_SIG_SIZE + der_len; diff --git a/test/simulator/framework/mock_securechip.c b/test/simulator/framework/mock_securechip.c index 608db8c78..42bebb063 100644 --- a/test/simulator/framework/mock_securechip.c +++ b/test/simulator/framework/mock_securechip.c @@ -81,16 +81,6 @@ bool securechip_u2f_counter_inc(uint32_t* counter) return true; } -bool securechip_ecc_unsafe_sign(const uint8_t* priv_key, const uint8_t* msg, uint8_t* sig) -{ - return false; -} - -bool securechip_ecc_generate_public_key(uint8_t* priv_key, uint8_t* pub_key) -{ - return false; -} - bool securechip_attestation_sign(const uint8_t* msg, uint8_t* signature_out) { return false; diff --git a/test/unit-test/framework/mock_securechip.c b/test/unit-test/framework/mock_securechip.c index cefeb6932..f0fbf3e47 100644 --- a/test/unit-test/framework/mock_securechip.c +++ b/test/unit-test/framework/mock_securechip.c @@ -82,16 +82,6 @@ bool securechip_u2f_counter_inc(uint32_t* counter) return true; } -bool securechip_ecc_unsafe_sign(const uint8_t* priv_key, const uint8_t* msg, uint8_t* sig) -{ - return false; -} - -bool securechip_ecc_generate_public_key(uint8_t* priv_key, uint8_t* pub_key) -{ - return false; -} - bool securechip_attestation_sign(const uint8_t* msg, uint8_t* signature_out) { return false;
-Expand for code - -This is so extensive to show how you can build up to processing totally arbitrary sequences, but for the most part these can be used on `GenericArray` instances without much added complexity. - -```rust -/// Super-simple fixed-length i32 `GenericArray`s -pub fn generic_array_plain_zip_sum(a: GenericArray, b: GenericArray) -> i32 { - a.zip(b, |l, r| l + r) - .map(|x| x + 1) - .fold(0, |a, x| x + a) -} - -pub fn generic_array_variable_length_zip_sum(a: GenericArray, b: GenericArray) -> i32 -where - N: ArrayLength, -{ - a.zip(b, |l, r| l + r) - .map(|x| x + 1) - .fold(0, |a, x| x + a) -} - -pub fn generic_array_same_type_variable_length_zip_sum(a: GenericArray, b: GenericArray) -> i32 -where - N: ArrayLength + ArrayLength<>::Output>, - T: Add, -{ - a.zip(b, |l, r| l + r) - .map(|x| x + 1) - .fold(0, |a, x| x + a) -} - -/// Complex example using fully generic `GenericArray`s with the same length. -/// -/// It's mostly just the repeated `Add` traits, which would be present in other systems anyway. -pub fn generic_array_zip_sum + ArrayLength>(a: GenericArray, b: GenericArray) -> i32 -where - A: Add, - N: ArrayLength<>::Output> + - ArrayLength<<>::Output as Add>::Output>, - >::Output: Add, - <>::Output as Add>::Output: Add, -{ - a.zip(b, |l, r| l + r) - .map(|x| x + 1) - .fold(0, |a, x| x + a) -} -``` -