diff options
Diffstat (limited to 'vendor/elliptic-curve')
38 files changed, 7083 insertions, 0 deletions
diff --git a/vendor/elliptic-curve/.cargo-checksum.json b/vendor/elliptic-curve/.cargo-checksum.json new file mode 100644 index 000000000..bd44426f4 --- /dev/null +++ b/vendor/elliptic-curve/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"0c64ef00c74dfb3135bf6c48b6a7a34ac9552653fcff3c40c6481e9c71b20e77","Cargo.toml":"c25efca1464e5c7af224e242922865cdf9b310476fefa80eb350cb72afd21e54","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"d27687b51f2874822c1530976b7e837eac4f308d94bf3dd42047011b7d437b47","README.md":"564ad8f9f8b80adeac3a961778857336a8ec6a77c54c07c7e9038cd0d36fad48","src/arithmetic.rs":"a4c7a7b350eaf75898dc412e0d6224b9e285a6fa20908c9e5150a4e31eed6bc2","src/dev.rs":"a9cb4426a348d2dedb4bbb0813f54a5715c7d3f50473c9668e11d73df65e35cf","src/ecdh.rs":"f4e0d9bfa7c4d5535261eefae0f4a85d96a155427b70d49f9b2ae43cf82a4949","src/error.rs":"8aedd93298b729ee396bc1a31754119130fbf865cb1e330c65be178cbbb0d1e4","src/hash2curve.rs":"861857145cc973ca64fc765731dada9aa3d7d97f61d324f6dba2aacc2d5e2135","src/hash2curve/group_digest.rs":"0557858097e159f98d8f6f0bd2dc03dd7e6e296da331db811cdad622c7f72834","src/hash2curve/hash2field.rs":"f4649686071bdf8fd4652d176878fc90bdd58111834f0f145b1b18009d53678b","src/hash2curve/hash2field/expand_msg.rs":"b92d8b959497cccd9cfa510dc257f2e7aab37331033498ac69946a6ec56bc81c","src/hash2curve/hash2field/expand_msg/xmd.rs":"ecac9f50043e5388f749528e7bed69f0b8686f8e62921ff272d6b87232efaf47","src/hash2curve/hash2field/expand_msg/xof.rs":"6cf5475e5bc6eda79c401e3855db67f59be4e6231af4bd22a6dedb0961d196cb","src/hash2curve/isogeny.rs":"7dcfc4f4263432ea1903f1580c28771b1082b8c4e344993b709e9995eaeaa674","src/hash2curve/map2curve.rs":"fc05c553ccd92de762e083f02079581376e8e4a193acd0d902cfdb33f59ce10a","src/hash2curve/osswu.rs":"9a300863c3c1f6893edcc612483228177a342e1c955407353fba24bf2676b34d","src/jwk.rs":"f701055c5af1bc8049ad3a3d5d3c47684f89fc0f90afae773e17de1ad2a413c0","src/lib.rs":"0fe6f10f2a0cb9480f8a42fcafad95fa47f9f2b5696eb8f078e0c377cabba9d9","src/macros.rs":"647f46540b407e12f633f635ed5d986c1be139d43a11ebff3edcce8295e1945c","src/ops.rs":"815f0c6f00e8d9b26f7bdde630cbc055cb6842599c3698fe55df66b1cddc6c99","src/point.rs":"19e92d2b64d1856fc12ff1d3d67940fc9801488f7ccbe488d318f5d06caeeb7e","src/public_key.rs":"5620b669b3a7aa00b7ad12732b171b042372d7d0e88e3e7d039771e0d13672c6","src/scalar.rs":"222680eb4f0e2fff8abf1dc4bdb82252bf71bb6060fdb00963627b1e5b2a40fa","src/scalar/core.rs":"8816c955ea0c89930dce42a2f5a7f0bcb6f1ed76a75ac5f663bd5100927eea34","src/scalar/nonzero.rs":"dec1a3fa2b4e2dcbe1c31504cd4b71ed64f06f98ac9676e7bb252013f4c2b61e","src/sec1.rs":"7c328e84d5cdf966114921bd23af53c2ab8ad335cf0d8bcf48d9def6354be474","src/secret_key.rs":"5da9d77b1483920e4dd1d9da42660c5bd0db560d195aaa2f5e07e8ed0c8d010e","src/secret_key/pkcs8.rs":"d049371aae570dc1519397d79772b676d549b81e91ca2e7fc33d270b352efdd5","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":"e99adb4b5282323911c6e0e89a126e7a32f930882d03d56013b2efab4abee15c","tests/secret_key.rs":"83fe5172364fb915ce54a47eee4579873a1b38ed9d6510f520c857f990d26027"},"package":"e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3"}
\ No newline at end of file diff --git a/vendor/elliptic-curve/CHANGELOG.md b/vendor/elliptic-curve/CHANGELOG.md new file mode 100644 index 000000000..975e749d4 --- /dev/null +++ b/vendor/elliptic-curve/CHANGELOG.md @@ -0,0 +1,657 @@ +# 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.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<C>` 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<C>` ([#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<C>` from `C::UInt` type ([#646]) +- Impl `ScalarBytes<C>` using `C::UInt` ([#647]) +- Make `ScalarBytes<C>` the `SecretKey<C>` 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<C>` ([#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<C>` ([#423]) +- Impl `pkcs8::ToPublicKey` for `PublicKey<C>` ([#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<C>` 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<C>` ([#385]) +- Impl `pkcs8::FromPrivateKey` trait for `SecretKey<C>` ([#381], [#383]) +- PKCS#8 PEM support ([#382]) +- `SecretKey::secret_value()` method ([#375]) +- `PublicKey<C>` 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<SecretBytes<C>>` for `FieldBytes<C>` ([#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<C>` and `AffinePoint<C>` ([#300]) +- Made `SecretKey<C>` inner type generic ([#297]) +- Renamed `ElementBytes<C>` to `FieldBytes<C>` ([#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 <https://github.com/RustCrypto/elliptic-curves> + +### 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/vendor/elliptic-curve/Cargo.toml b/vendor/elliptic-curve/Cargo.toml new file mode 100644 index 000000000..906ac569a --- /dev/null +++ b/vendor/elliptic-curve/Cargo.toml @@ -0,0 +1,209 @@ +# 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 = "elliptic-curve" +version = "0.12.3" +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" +resolver = "2" + +[package.metadata.docs.rs] +features = [ + "bits", + "ecdh", + "hash2curve", + "jwk", + "pem", + "std", + "voprf", +] +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.base16ct] +version = "0.1.1" + +[dependencies.base64ct] +version = "1" +optional = true +default-features = false + +[dependencies.crypto-bigint] +version = "0.4.8" +features = [ + "rand_core", + "generic-array", + "zeroize", +] +default-features = false + +[dependencies.der] +version = "0.6" +features = ["oid"] +default-features = false + +[dependencies.digest] +version = "0.10" +optional = true + +[dependencies.ff] +version = "0.12" +optional = true +default-features = false + +[dependencies.generic-array] +version = "0.14" +default-features = false + +[dependencies.group] +version = "0.12" +optional = true +default-features = false + +[dependencies.hex-literal] +version = "0.3" +optional = true + +[dependencies.hkdf] +version = "0.12" +optional = true +default-features = false + +[dependencies.pem-rfc7468] +version = "0.6" +optional = true + +[dependencies.pkcs8] +version = "0.9" +optional = true +default-features = false + +[dependencies.rand_core] +version = "0.6" +default-features = false + +[dependencies.sec1] +version = "0.3" +features = [ + "subtle", + "zeroize", +] +optional = true + +[dependencies.serde_json] +version = "1" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.serdect] +version = "0.1" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.subtle] +version = "2" +default-features = false + +[dependencies.zeroize] +version = "1.5" +default-features = false + +[dev-dependencies.hex-literal] +version = "0.3" + +[dev-dependencies.sha2] +version = "0.10" + +[dev-dependencies.sha3] +version = "0.10" + +[features] +alloc = [ + "base16ct/alloc", + "der/alloc", + "sec1/alloc", + "zeroize/alloc", +] +arithmetic = [ + "ff", + "group", +] +bits = [ + "arithmetic", + "ff/bits", +] +default = ["arithmetic"] +dev = [ + "arithmetic", + "hex-literal", + "pem", + "pkcs8", +] +ecdh = [ + "arithmetic", + "digest", + "hkdf", +] +hash2curve = [ + "arithmetic", + "digest", +] +hazmat = [] +jwk = [ + "alloc", + "base64ct/alloc", + "serde", + "serde_json", + "zeroize/alloc", +] +pem = [ + "alloc", + "arithmetic", + "der/pem", + "pem-rfc7468/alloc", + "pkcs8", + "sec1/pem", +] +serde = [ + "alloc", + "pkcs8", + "sec1/serde", + "serdect", +] +std = [ + "alloc", + "rand_core/std", +] +voprf = ["digest"] diff --git a/vendor/elliptic-curve/LICENSE-APACHE b/vendor/elliptic-curve/LICENSE-APACHE new file mode 100644 index 000000000..78173fa2e --- /dev/null +++ b/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/vendor/elliptic-curve/LICENSE-MIT b/vendor/elliptic-curve/LICENSE-MIT new file mode 100644 index 000000000..d4ce06527 --- /dev/null +++ b/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/vendor/elliptic-curve/README.md b/vendor/elliptic-curve/README.md new file mode 100644 index 000000000..254a99433 --- /dev/null +++ b/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.57** 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.57+-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/vendor/elliptic-curve/src/arithmetic.rs b/vendor/elliptic-curve/src/arithmetic.rs new file mode 100644 index 000000000..fa445f1bc --- /dev/null +++ b/vendor/elliptic-curve/src/arithmetic.rs @@ -0,0 +1,87 @@ +//! Elliptic curve arithmetic traits. + +use crate::{ + ops::LinearCombination, AffineXCoordinate, Curve, FieldBytes, IsHigh, PrimeCurve, ScalarCore, +}; +use core::fmt::Debug; +use subtle::{ConditionallySelectable, ConstantTimeEq}; +use zeroize::DefaultIsZeroes; + +/// Elliptic curve with affine arithmetic implementation. +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +pub trait AffineArithmetic: Curve + ScalarArithmetic { + /// Elliptic curve point in affine coordinates. + type AffinePoint: 'static + + AffineXCoordinate<Self> + + Copy + + Clone + + ConditionallySelectable + + ConstantTimeEq + + Debug + + Default + + DefaultIsZeroes + + Eq + + PartialEq + + Sized + + Send + + Sync; +} + +/// Prime order elliptic curve with projective arithmetic implementation. +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +pub trait PrimeCurveArithmetic: + PrimeCurve + ProjectiveArithmetic<ProjectivePoint = Self::CurveGroup> +{ + /// Prime order elliptic curve group. + type CurveGroup: group::prime::PrimeCurve<Affine = <Self as AffineArithmetic>::AffinePoint>; +} + +/// Elliptic curve with projective arithmetic implementation. +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +pub trait ProjectiveArithmetic: Curve + AffineArithmetic { + /// 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<Self::AffinePoint> + + Into<Self::AffinePoint> + + LinearCombination + + group::Curve<AffineRepr = Self::AffinePoint> + + group::Group<Scalar = Self::Scalar>; +} + +/// Scalar arithmetic. +#[cfg(feature = "arithmetic")] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +pub trait ScalarArithmetic: Curve { + /// Scalar field type. + /// + /// Note: the following bounds are provided by [`ff::Field`]: + /// - `'static` + /// - [`Copy`] + /// - [`Clone`] + /// - [`ConditionallySelectable`] + /// - [`ConstantTimeEq`] + /// - [`Debug`] + /// - [`Default`] + /// - [`Send`] + /// - [`Sync`] + type Scalar: DefaultIsZeroes + + From<ScalarCore<Self>> + + Into<FieldBytes<Self>> + + Into<Self::UInt> + + IsHigh + + ff::Field + + ff::PrimeField<Repr = FieldBytes<Self>>; +} diff --git a/vendor/elliptic-curve/src/dev.rs b/vendor/elliptic-curve/src/dev.rs new file mode 100644 index 000000000..be0c156e5 --- /dev/null +++ b/vendor/elliptic-curve/src/dev.rs @@ -0,0 +1,794 @@ +//! 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}, + ops::{LinearCombination, Reduce}, + pkcs8, + rand_core::RngCore, + sec1::{FromEncodedPoint, ToEncodedPoint}, + subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, + zeroize::DefaultIsZeroes, + AffineArithmetic, AffineXCoordinate, Curve, IsHigh, PrimeCurve, ProjectiveArithmetic, + ScalarArithmetic, +}; +use core::{ + iter::Sum, + ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, +}; +use ff::{Field, PrimeField}; +use generic_array::arr; +use hex_literal::hex; +use pkcs8::AssociatedOid; + +#[cfg(feature = "bits")] +use crate::group::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<MockCurve>; + +/// Field element bytes. +pub type FieldBytes = crate::FieldBytes<MockCurve>; + +/// Non-zero scalar value. +pub type NonZeroScalar = crate::NonZeroScalar<MockCurve>; + +/// Public key. +pub type PublicKey = crate::PublicKey<MockCurve>; + +/// Secret key. +pub type SecretKey = crate::SecretKey<MockCurve>; + +/// Scalar core. +// TODO(tarcieri): make this the scalar type +pub type ScalarCore = crate::ScalarCore<MockCurve>; + +/// Scalar bits. +#[cfg(feature = "bits")] +pub type ScalarBits = crate::ScalarBits<MockCurve>; + +/// 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 UInt = U256; + + const ORDER: U256 = + U256::from_be_hex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"); +} + +impl PrimeCurve for MockCurve {} + +impl AffineArithmetic for MockCurve { + type AffinePoint = AffinePoint; +} + +impl ProjectiveArithmetic for MockCurve { + type ProjectivePoint = ProjectivePoint; +} + +impl ScalarArithmetic for MockCurve { + 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")] +#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] +impl JwkParameters for MockCurve { + const CRV: &'static str = "P-256"; +} + +/// Example scalar type +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +pub struct Scalar(ScalarCore); + +impl Field for Scalar { + 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 zero() -> Self { + Self(ScalarCore::ZERO) + } + + fn one() -> Self { + Self(ScalarCore::ONE) + } + + 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<Self> { + unimplemented!(); + } + + fn sqrt(&self) -> CtOption<Self> { + unimplemented!(); + } +} + +impl PrimeField for Scalar { + type Repr = FieldBytes; + + const NUM_BITS: u32 = 256; + const CAPACITY: u32 = 255; + const S: u32 = 4; + + fn from_repr(bytes: FieldBytes) -> CtOption<Self> { + ScalarCore::from_be_bytes(bytes).map(Self) + } + + fn to_repr(&self) -> FieldBytes { + self.0.to_be_bytes() + } + + fn is_odd(&self) -> Choice { + self.0.is_odd() + } + + fn multiplicative_generator() -> Self { + 7u64.into() + } + + fn root_of_unity() -> Self { + Self::from_repr(arr![u8; + 0xff, 0xc9, 0x7f, 0x06, 0x2a, 0x77, 0x09, 0x92, 0xba, 0x80, 0x7a, 0xce, 0x84, 0x2a, + 0x3d, 0xfc, 0x15, 0x46, 0xca, 0xd0, 0x04, 0x37, 0x8d, 0xaf, 0x05, 0x92, 0xd7, 0xfb, + 0xb4, 0x1e, 0x66, 0x02, + ]) + .unwrap() + } +} + +#[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 TryFrom<U256> for Scalar { + type Error = Error; + + fn try_from(w: U256) -> Result<Self> { + Option::from(ScalarCore::new(w)).map(Self).ok_or(Error) + } +} + +impl From<Scalar> for U256 { + fn from(scalar: Scalar) -> U256 { + *scalar.0.as_uint() + } +} + +impl ConditionallySelectable for Scalar { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self(ScalarCore::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<Scalar> 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<Scalar> 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<Scalar> 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<Scalar> 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<Scalar> 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<Scalar> 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 Reduce<U256> for Scalar { + fn from_uint_reduced(w: U256) -> Self { + let (r, underflow) = w.sbb(&MockCurve::ORDER, Limb::ZERO); + let underflow = Choice::from((underflow.0 >> (Limb::BIT_SIZE - 1)) as u8); + let reduced = U256::conditional_select(&w, &r, !underflow); + Self(ScalarCore::new(reduced).unwrap()) + } +} + +impl From<u64> for Scalar { + fn from(n: u64) -> Scalar { + Self(n.into()) + } +} + +impl From<ScalarCore> for Scalar { + fn from(scalar: ScalarCore) -> Scalar { + Self(scalar) + } +} + +impl From<Scalar> 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 AffineXCoordinate<MockCurve> for AffinePoint { + fn x(&self) -> FieldBytes { + unimplemented!(); + } +} + +impl ConstantTimeEq for AffinePoint { + fn ct_eq(&self, _other: &Self) -> Choice { + unimplemented!(); + } +} + +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<MockCurve> for AffinePoint { + fn from_encoded_point(encoded_point: &EncodedPoint) -> CtOption<Self> { + let point = if encoded_point.is_identity() { + Self::Identity + } else { + Self::Other(*encoded_point) + }; + + CtOption::new(point, Choice::from(1)) + } +} + +impl ToEncodedPoint<MockCurve> 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<NonZeroScalar> 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 { + unimplemented!(); + } +} + +impl ConditionallySelectable for ProjectivePoint { + fn conditional_select(_a: &Self, _b: &Self, _choice: Choice) -> Self { + unimplemented!(); + } +} + +impl Default for ProjectivePoint { + fn default() -> Self { + Self::Identity + } +} + +impl DefaultIsZeroes for ProjectivePoint {} + +impl From<AffinePoint> 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<ProjectivePoint> for AffinePoint { + fn from(point: ProjectivePoint) -> AffinePoint { + group::Curve::to_affine(&point) + } +} + +impl FromEncodedPoint<MockCurve> for ProjectivePoint { + fn from_encoded_point(_point: &EncodedPoint) -> CtOption<Self> { + unimplemented!(); + } +} + +impl ToEncodedPoint<MockCurve> 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((self == &Self::Identity) as u8) + } + + #[must_use] + fn double(&self) -> Self { + unimplemented!(); + } +} + +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<ProjectivePoint> 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<ProjectivePoint> 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<ProjectivePoint> 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<ProjectivePoint> 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<AffinePoint> 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<AffinePoint> 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<I: Iterator<Item = Self>>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl<'a> Sum<&'a ProjectivePoint> for ProjectivePoint { + fn sum<I: Iterator<Item = &'a ProjectivePoint>>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl Sub<AffinePoint> 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<AffinePoint> 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<Scalar> 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<Scalar> for ProjectivePoint { + fn mul_assign(&mut self, _rhs: Scalar) { + unimplemented!(); + } +} + +impl MulAssign<&Scalar> for ProjectivePoint { + fn mul_assign(&mut self, _rhs: &Scalar) { + unimplemented!(); + } +} + +impl Neg for ProjectivePoint { + type Output = ProjectivePoint; + + fn neg(self) -> ProjectivePoint { + unimplemented!(); + } +} + +/// Constant representing the base field modulus +/// p = 2^{224}(2^{32} − 1) + 2^{192} + 2^{96} − 1 +pub const MODULUS: U256 = + U256::from_be_hex("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff"); + +/// Example base field element. +#[derive(Clone, Copy, Debug)] +pub struct FieldElement(pub(crate) U256); + +/// Internal field element representation. +#[cfg(target_pointer_width = "32")] +type FeWords = [u32; 8]; + +/// Internal field element representation. +#[cfg(target_pointer_width = "64")] +type FeWords = [u64; 4]; + +impl_field_element!( + FieldElement, + FieldBytes, + U256, + MODULUS, + FeWords, + p256_from_montgomery, + p256_to_montgomery, + p256_add, + p256_sub, + p256_mul, + p256_opp, + p256_square +); + +impl FieldElement { + /// Returns the multiplicative inverse of self, if self is non-zero. + pub fn invert(&self) -> CtOption<Self> { + unimplemented!() + } + + /// Returns the square root of self mod p, or `None` if no square root exists. + pub fn sqrt(&self) -> CtOption<Self> { + unimplemented!() + } +} + +const fn p256_from_montgomery(_: &FeWords) -> FeWords { + unimplemented!() +} + +const fn p256_to_montgomery(w: &FeWords) -> FeWords { + *w +} + +const fn p256_add(_: &FeWords, _: &FeWords) -> FeWords { + unimplemented!() +} + +const fn p256_sub(_: &FeWords, _: &FeWords) -> FeWords { + unimplemented!() +} + +const fn p256_mul(_: &FeWords, _: &FeWords) -> FeWords { + unimplemented!() +} + +const fn p256_opp(_: &FeWords) -> FeWords { + unimplemented!() +} + +const fn p256_square(_: &FeWords) -> FeWords { + 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/vendor/elliptic-curve/src/ecdh.rs b/vendor/elliptic-curve/src/ecdh.rs new file mode 100644 index 000000000..1e9f7bc31 --- /dev/null +++ b/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 [`ProjectiveArithmetic`] 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::{ + AffineArithmetic, AffinePoint, AffineXCoordinate, Curve, FieldBytes, NonZeroScalar, + ProjectiveArithmetic, ProjectivePoint, PublicKey, +}; +use core::borrow::Borrow; +use digest::{crypto_common::BlockSizeUser, Digest}; +use group::Curve as _; +use hkdf::{hmac::SimpleHmac, Hkdf}; +use rand_core::{CryptoRng, RngCore}; +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<C>( + secret_key: impl Borrow<NonZeroScalar<C>>, + public_key: impl Borrow<AffinePoint<C>>, +) -> SharedSecret<C> +where + C: Curve + ProjectiveArithmetic, +{ + let public_point = ProjectivePoint::<C>::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<C> +where + C: Curve + ProjectiveArithmetic, +{ + scalar: NonZeroScalar<C>, +} + +impl<C> EphemeralSecret<C> +where + C: Curve + ProjectiveArithmetic, +{ + /// Generate a cryptographically random [`EphemeralSecret`]. + pub fn random(rng: impl CryptoRng + RngCore) -> 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<C> { + 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<C>) -> SharedSecret<C> { + diffie_hellman(&self.scalar, public_key.as_affine()) + } +} + +impl<C> From<&EphemeralSecret<C>> for PublicKey<C> +where + C: Curve + ProjectiveArithmetic, +{ + fn from(ephemeral_secret: &EphemeralSecret<C>) -> Self { + ephemeral_secret.public_key() + } +} + +impl<C> Zeroize for EphemeralSecret<C> +where + C: Curve + ProjectiveArithmetic, +{ + fn zeroize(&mut self) { + self.scalar.zeroize() + } +} + +impl<C> ZeroizeOnDrop for EphemeralSecret<C> where C: Curve + ProjectiveArithmetic {} + +impl<C> Drop for EphemeralSecret<C> +where + C: Curve + ProjectiveArithmetic, +{ + fn drop(&mut self) { + self.zeroize(); + } +} + +/// Shared secret value computed via ECDH key agreement. +pub struct SharedSecret<C: Curve> { + /// Computed secret value + secret_bytes: FieldBytes<C>, +} + +impl<C: Curve> SharedSecret<C> { + /// Create a new [`SharedSecret`] from an [`AffinePoint`] for this curve. + #[inline] + fn new(point: AffinePoint<C>) -> Self + where + C: AffineArithmetic, + { + 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<D>(&self, salt: Option<&[u8]>) -> Hkdf<D, SimpleHmac<D>> + 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<C> { + &self.secret_bytes + } +} + +impl<C: Curve> From<FieldBytes<C>> for SharedSecret<C> { + /// 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<C>) -> Self { + Self { secret_bytes } + } +} + +impl<C: Curve> ZeroizeOnDrop for SharedSecret<C> {} + +impl<C: Curve> Drop for SharedSecret<C> { + fn drop(&mut self) { + self.secret_bytes.zeroize() + } +} diff --git a/vendor/elliptic-curve/src/error.rs b/vendor/elliptic-curve/src/error.rs new file mode 100644 index 000000000..53f5b1773 --- /dev/null +++ b/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<T> = core::result::Result<T, Error>; + +/// 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<base16ct::Error> for Error { + fn from(_: base16ct::Error) -> Error { + Error + } +} + +#[cfg(feature = "pkcs8")] +impl From<pkcs8::Error> for Error { + fn from(_: pkcs8::Error) -> Error { + Error + } +} + +#[cfg(feature = "sec1")] +impl From<sec1::Error> for Error { + fn from(_: sec1::Error) -> Error { + Error + } +} + +#[cfg(feature = "std")] +impl std::error::Error for Error {} diff --git a/vendor/elliptic-curve/src/hash2curve.rs b/vendor/elliptic-curve/src/hash2curve.rs new file mode 100644 index 000000000..3df394f79 --- /dev/null +++ b/vendor/elliptic-curve/src/hash2curve.rs @@ -0,0 +1,15 @@ +//! Traits for hashing byte sequences to curve points. +//! +//! <https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve> + +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/vendor/elliptic-curve/src/hash2curve/group_digest.rs b/vendor/elliptic-curve/src/hash2curve/group_digest.rs new file mode 100644 index 000000000..dbcb1512b --- /dev/null +++ b/vendor/elliptic-curve/src/hash2curve/group_digest.rs @@ -0,0 +1,120 @@ +//! Traits for handling hash to curve. + +use super::{hash_to_field, ExpandMsg, FromOkm, MapToCurve}; +use crate::{ProjectiveArithmetic, ProjectivePoint, Result}; +use group::cofactor::CofactorGroup; + +/// Adds hashing arbitrary byte sequences to a valid group element +pub trait GroupDigest: ProjectiveArithmetic +where + ProjectivePoint<Self>: CofactorGroup, +{ + /// The field element representation for a group value with multiple elements + type FieldElement: FromOkm + MapToCurve<Output = ProjectivePoint<Self>> + Default + Copy; + + /// Computes the hash to curve routine. + /// + /// From <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html>: + /// + /// > 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::<ExpandMsgXmd<sha2::Sha256>>(b"test data", b"CURVE_XMD:SHA-256_SSWU_RO_"); + /// ``` + /// + /// ## Using an extendable output function + /// + /// ```ignore + /// let pt = ProjectivePoint::hash_from_bytes::<ExpandMsgXof<sha3::Shake256>>(b"test data", b"CURVE_XOF:SHAKE-256_SSWU_RO_"); + /// ``` + /// + /// # Errors + /// See implementors of [`ExpandMsg`] for errors: + /// - [`ExpandMsgXmd`] + /// - [`ExpandMsgXof`] + /// + /// `len_in_bytes = <Self::FieldElement as FromOkm>::Length * 2` + /// + /// [`ExpandMsgXmd`]: crate::hash2curve::ExpandMsgXmd + /// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof + fn hash_from_bytes<'a, X: ExpandMsg<'a>>( + msgs: &[&[u8]], + dst: &'a [u8], + ) -> Result<ProjectivePoint<Self>> { + let mut u = [Self::FieldElement::default(), Self::FieldElement::default()]; + hash_to_field::<X, _>(msgs, dst, &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 <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html>: + /// + /// > 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 = <Self::FieldElement as FromOkm>::Length` + /// + /// [`ExpandMsgXmd`]: crate::hash2curve::ExpandMsgXmd + /// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof + fn encode_from_bytes<'a, X: ExpandMsg<'a>>( + msgs: &[&[u8]], + dst: &'a [u8], + ) -> Result<ProjectivePoint<Self>> { + let mut u = [Self::FieldElement::default()]; + hash_to_field::<X, _>(msgs, dst, &mut u)?; + let q0 = u[0].map_to_curve(); + Ok(q0.clear_cofactor().into()) + } + + /// Computes the hash to field routine according to + /// <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#section-5> + /// and returns a scalar. + /// + /// # Errors + /// See implementors of [`ExpandMsg`] for errors: + /// - [`ExpandMsgXmd`] + /// - [`ExpandMsgXof`] + /// + /// `len_in_bytes = <Self::Scalar as FromOkm>::Length` + /// + /// [`ExpandMsgXmd`]: crate::hash2curve::ExpandMsgXmd + /// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof + fn hash_to_scalar<'a, X: ExpandMsg<'a>>(msgs: &[&[u8]], dst: &'a [u8]) -> Result<Self::Scalar> + where + Self::Scalar: FromOkm, + { + let mut u = [Self::Scalar::default()]; + hash_to_field::<X, _>(msgs, dst, &mut u)?; + Ok(u[0]) + } +} diff --git a/vendor/elliptic-curve/src/hash2curve/hash2field.rs b/vendor/elliptic-curve/src/hash2curve/hash2field.rs new file mode 100644 index 000000000..6cd0723aa --- /dev/null +++ b/vendor/elliptic-curve/src/hash2curve/hash2field.rs @@ -0,0 +1,48 @@ +//! Traits for hashing to field elements. +//! +//! <https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve> + +mod expand_msg; + +pub use expand_msg::{xmd::*, xof::*, *}; + +use crate::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<u8>; + + /// Convert a byte sequence into a field element. + fn from_okm(data: &GenericArray<u8, Self::Length>) -> Self; +} + +/// Convert an arbitrary byte sequence into a field element. +/// +/// <https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3> +/// +/// # 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 [u8], out: &mut [T]) -> Result<()> +where + E: ExpandMsg<'a>, + T: FromOkm + Default, +{ + let len_in_bytes = T::Length::to_usize() * out.len(); + let mut tmp = GenericArray::<u8, <T as FromOkm>::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/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg.rs b/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg.rs new file mode 100644 index 000000000..dfb3bab9c --- /dev/null +++ b/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg.rs @@ -0,0 +1,115 @@ +//! `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]], dst: &'a [u8], len_in_bytes: usize) + -> Result<Self::Expander>; +} + +/// 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<u8> + IsLess<U256>, +{ + /// > 255 + Hashed(GenericArray<u8, L>), + /// <= 255 + Array(&'a [u8]), +} + +impl<'a, L> Domain<'a, L> +where + L: ArrayLength<u8> + IsLess<U256>, +{ + pub fn xof<X>(dst: &'a [u8]) -> Result<Self> + where + X: Default + ExtendableOutput + Update, + { + if dst.is_empty() { + Err(Error) + } else if dst.len() > MAX_DST_LEN { + let mut data = GenericArray::<u8, L>::default(); + X::default() + .chain(OVERSIZE_DST_SALT) + .chain(dst) + .finalize_xof() + .read(&mut data); + Ok(Self::Hashed(data)) + } else { + Ok(Self::Array(dst)) + } + } + + pub fn xmd<X>(dst: &'a [u8]) -> Result<Self> + where + X: Digest<OutputSize = L>, + { + if dst.is_empty() { + Err(Error) + } else if dst.len() > MAX_DST_LEN { + Ok(Self::Hashed({ + let mut hash = X::new(); + hash.update(OVERSIZE_DST_SALT); + hash.update(dst); + hash.finalize() + })) + } else { + Ok(Self::Array(dst)) + } + } + + pub fn data(&self) -> &[u8] { + match self { + Self::Hashed(d) => &d[..], + Self::Array(d) => *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.len()).expect("length overflow"), + } + } + + #[cfg(test)] + pub fn assert(&self, bytes: &[u8]) { + assert_eq!(self.data(), &bytes[..bytes.len() - 1]); + assert_eq!(self.len(), bytes[bytes.len() - 1]); + } +} diff --git a/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xmd.rs b/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xmd.rs new file mode 100644 index 000000000..876b012f5 --- /dev/null +++ b/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xmd.rs @@ -0,0 +1,449 @@ +//! `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, + }, + Digest, +}; + +/// 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<HashT>(PhantomData<HashT>) +where + HashT: Digest + BlockSizeUser, + HashT::OutputSize: IsLess<U256>, + HashT::OutputSize: IsLessOrEqual<HashT::BlockSize>; + +/// ExpandMsgXmd implements expand_message_xmd for the ExpandMsg trait +impl<'a, HashT> ExpandMsg<'a> for ExpandMsgXmd<HashT> +where + HashT: Digest + BlockSizeUser, + // 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<U256>, + // 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<HashT::BlockSize>, +{ + type Expander = ExpanderXmd<'a, HashT>; + + fn expand_message( + msgs: &[&[u8]], + dst: &'a [u8], + len_in_bytes: usize, + ) -> Result<Self::Expander> { + 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::<HashT>(dst)?; + let mut b_0 = HashT::new(); + b_0.update(GenericArray::<u8, HashT::BlockSize>::default()); + + for msg in msgs { + b_0.update(msg); + } + + b_0.update(len_in_bytes_u16.to_be_bytes()); + b_0.update([0]); + b_0.update(domain.data()); + b_0.update([domain.len()]); + let b_0 = b_0.finalize(); + + let mut b_vals = HashT::new(); + b_vals.update(&b_0[..]); + b_vals.update([1u8]); + b_vals.update(domain.data()); + b_vals.update([domain.len()]); + let b_vals = b_vals.finalize(); + + Ok(ExpanderXmd { + b_0, + b_vals, + domain, + index: 1, + offset: 0, + ell, + }) + } +} + +/// [`Expander`] type for [`ExpandMsgXmd`]. +pub struct ExpanderXmd<'a, HashT> +where + HashT: Digest + BlockSizeUser, + HashT::OutputSize: IsLess<U256>, + HashT::OutputSize: IsLessOrEqual<HashT::BlockSize>, +{ + b_0: GenericArray<u8, HashT::OutputSize>, + b_vals: GenericArray<u8, HashT::OutputSize>, + domain: Domain<'a, HashT::OutputSize>, + index: u8, + offset: usize, + ell: u8, +} + +impl<'a, HashT> ExpanderXmd<'a, HashT> +where + HashT: Digest + BlockSizeUser, + HashT::OutputSize: IsLess<U256>, + HashT::OutputSize: IsLessOrEqual<HashT::BlockSize>, +{ + 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::<u8, HashT::OutputSize>::default(); + self.b_0 + .iter() + .zip(&self.b_vals[..]) + .enumerate() + .for_each(|(j, (b0val, bi1val))| tmp[j] = b0val ^ bi1val); + let mut b_vals = HashT::new(); + b_vals.update(tmp); + b_vals.update([self.index]); + b_vals.update(self.domain.data()); + b_vals.update([self.domain.len()]); + self.b_vals = b_vals.finalize(); + true + } else { + false + } + } +} + +impl<'a, HashT> Expander for ExpanderXmd<'a, HashT> +where + HashT: Digest + BlockSizeUser, + HashT::OutputSize: IsLess<U256>, + HashT::OutputSize: IsLessOrEqual<HashT::BlockSize>, +{ + 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<HashT>( + msg: &[u8], + domain: &Domain<'_, HashT::OutputSize>, + len_in_bytes: u16, + bytes: &[u8], + ) where + HashT: Digest + BlockSizeUser, + HashT::OutputSize: IsLess<U256>, + { + let block = HashT::BlockSize::to_usize(); + assert_eq!( + GenericArray::<u8, HashT::BlockSize>::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::<u16>(); + assert_eq!(len_in_bytes.to_be_bytes(), &bytes[msg_len..l]); + + let pad = l + mem::size_of::<u8>(); + assert_eq!([0], &bytes[l..pad]); + + let dst = pad + domain.data().len(); + assert_eq!(domain.data(), &bytes[pad..dst]); + + let dst_len = dst + mem::size_of::<u8>(); + 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 { + fn assert<HashT, L: ArrayLength<u8>>( + &self, + dst: &'static [u8], + domain: &Domain<'_, HashT::OutputSize>, + ) -> Result<()> + where + HashT: Digest + BlockSizeUser, + HashT::OutputSize: IsLess<U256> + IsLessOrEqual<HashT::BlockSize>, + { + assert_message::<HashT>(self.msg, domain, L::to_u16(), self.msg_prime); + + let mut expander = + ExpandMsgXmd::<HashT>::expand_message(&[self.msg], dst, L::to_usize())?; + + let mut uniform_bytes = GenericArray::<u8, L>::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::<Sha256>(DST)?; + dst_prime.assert(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::<Sha256, U32>(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::<Sha256, U128>(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::<Sha256>(DST)?; + dst_prime.assert(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::<Sha256, U32>(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::<Sha256, U128>(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::<Sha512>(DST)?; + dst_prime.assert(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::<Sha512, U32>(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::<Sha512, U128>(DST, &dst_prime)?; + } + + Ok(()) + } +} diff --git a/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xof.rs b/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xof.rs new file mode 100644 index 000000000..107ac5e06 --- /dev/null +++ b/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xof.rs @@ -0,0 +1,353 @@ +//! `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<HashT> +where + HashT: Default + ExtendableOutput + Update, +{ + reader: <HashT as ExtendableOutput>::Reader, +} + +/// ExpandMsgXof implements `expand_message_xof` for the [`ExpandMsg`] trait +impl<'a, HashT> ExpandMsg<'a> for ExpandMsgXof<HashT> +where + HashT: Default + ExtendableOutput + Update, +{ + type Expander = Self; + + fn expand_message( + msgs: &[&[u8]], + dst: &'a [u8], + len_in_bytes: usize, + ) -> Result<Self::Expander> { + if len_in_bytes == 0 { + return Err(Error); + } + + let len_in_bytes = u16::try_from(len_in_bytes).map_err(|_| Error)?; + + let domain = Domain::<U32>::xof::<HashT>(dst)?; + let mut reader = HashT::default(); + + for msg in msgs { + reader = reader.chain(msg); + } + + let reader = reader + .chain(len_in_bytes.to_be_bytes()) + .chain(domain.data()) + .chain([domain.len()]) + .finalize_xof(); + Ok(Self { reader }) + } +} + +impl<HashT> Expander for ExpandMsgXof<HashT> +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<HashT>( + 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::<u16>(); + assert_eq!( + len_in_bytes.to_be_bytes(), + &bytes[msg_len..len_in_bytes_len] + ); + + let dst = len_in_bytes_len + domain.data().len(); + assert_eq!(domain.data(), &bytes[len_in_bytes_len..dst]); + + let dst_len = dst + mem::size_of::<u8>(); + 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 { + fn assert<HashT, L>(&self, dst: &'static [u8], domain: &Domain<'_, U32>) -> Result<()> + where + HashT: Default + ExtendableOutput + Update, + L: ArrayLength<u8>, + { + assert_message::<HashT>(self.msg, domain, L::to_u16(), self.msg_prime); + + let mut expander = + ExpandMsgXof::<HashT>::expand_message(&[self.msg], dst, L::to_usize())?; + + let mut uniform_bytes = GenericArray::<u8, L>::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::<U32>::xof::<Shake128>(DST)?; + dst_prime.assert(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::<Shake128, U32>(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::<Shake128, U128>(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::<U32>::xof::<Shake128>(DST)?; + dst_prime.assert(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::<Shake128, U32>(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::<Shake128, U128>(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::<U32>::xof::<Shake256>(DST)?; + dst_prime.assert(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::<Shake256, U32>(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::<Shake256, U128>(DST, &dst_prime)?; + } + + Ok(()) + } +} diff --git a/vendor/elliptic-curve/src/hash2curve/isogeny.rs b/vendor/elliptic-curve/src/hash2curve/isogeny.rs new file mode 100644 index 000000000..fc197246a --- /dev/null +++ b/vendor/elliptic-curve/src/hash2curve/isogeny.rs @@ -0,0 +1,57 @@ +//! Traits for mapping an isogeny to another curve +//! +//! <https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-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<F: Field + AddAssign + Mul<Output = F>> { + /// 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<Output = Self> { + /// The maximum number of coefficients + type Degree: ArrayLength<Self>; + /// The isogeny coefficients + const COEFFICIENTS: IsogenyCoefficients<Self>; + + /// Map from the isogeny points to the main curve + fn isogeny(x: Self, y: Self) -> (Self, Self) { + let mut xs = GenericArray::<Self, Self::Degree>::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/vendor/elliptic-curve/src/hash2curve/map2curve.rs b/vendor/elliptic-curve/src/hash2curve/map2curve.rs new file mode 100644 index 000000000..6092e57ba --- /dev/null +++ b/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/vendor/elliptic-curve/src/hash2curve/osswu.rs b/vendor/elliptic-curve/src/hash2curve/osswu.rs new file mode 100644 index 000000000..f803863b1 --- /dev/null +++ b/vendor/elliptic-curve/src/hash2curve/osswu.rs @@ -0,0 +1,87 @@ +//! Optimized simplified Shallue-van de Woestijne-Ulas methods. +//! +//! <https://eprint.iacr.org/2009/340.pdf> + +use ff::Field; +use subtle::Choice; + +/// The Optimized Simplified Shallue-van de Woestijne-Ulas parameters +pub struct OsswuMapParams<F> +where + F: Field, +{ + /// The first constant term + pub c1: [u64; 4], + /// 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<Self>; + + /// 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) { + let tv1 = self.square(); // u^2 + let tv3 = Self::PARAMS.z * tv1; // Z * u^2 + let mut tv2 = tv3.square(); // tv3^2 + let mut xd = tv2 + tv3; // tv3^2 + tv3 + let x1n = Self::PARAMS.map_b * (xd + Self::one()); // B * (xd + 1) + xd *= -Self::PARAMS.map_a; // -A * xd + + let tv = Self::PARAMS.z * Self::PARAMS.map_a; + xd.conditional_assign(&tv, xd.is_zero()); + + tv2 = xd.square(); //xd^2 + let gxd = tv2 * xd; // xd^3 + tv2 *= Self::PARAMS.map_a; // A * tv2 + + let mut gx1 = x1n * (tv2 + x1n.square()); //x1n *(tv2 + x1n^2) + tv2 = gxd * Self::PARAMS.map_b; // B * gxd + gx1 += tv2; // gx1 + tv2 + + let mut tv4 = gxd.square(); // gxd^2 + tv2 = gx1 * gxd; // gx1 * gxd + tv4 *= tv2; + + let y1 = tv4.pow_vartime(&Self::PARAMS.c1) * tv2; // tv4^C1 * tv2 + let x2n = tv3 * x1n; // tv3 * x1n + + let y2 = y1 * Self::PARAMS.c2 * tv1 * self; // y1 * c2 * tv1 * u + + tv2 = y1.square() * gxd; //y1^2 * gxd + + let e2 = tv2.ct_eq(&gx1); + + // if e2 , x = x1, else x = x2 + let mut x = Self::conditional_select(&x2n, &x1n, e2); + // xn / xd + x *= xd.invert().unwrap(); + + // if e2, y = y1, else y = y2 + let mut y = Self::conditional_select(&y2, &y1, e2); + + y.conditional_assign(&-y, self.sgn0() ^ y.sgn0()); + (x, y) + } +} diff --git a/vendor/elliptic-curve/src/jwk.rs b/vendor/elliptic-curve/src/jwk.rs new file mode 100644 index 000000000..ff5e6e638 --- /dev/null +++ b/vendor/elliptic-curve/src/jwk.rs @@ -0,0 +1,692 @@ +//! JSON Web Key (JWK) Support. +//! +//! Specified in RFC 7518 Section 6: Cryptographic Algorithms for Keys: +//! <https://tools.ietf.org/html/rfc7518#section-6> + +use crate::{ + sec1::{Coordinates, EncodedPoint, ModulusSize, ValidatePublicKey}, + secret_key::SecretKey, + Curve, Error, FieldBytes, FieldSize, 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, ProjectiveArithmetic, +}; + +/// 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. +#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] +pub trait JwkParameters: Curve { + /// The `crv` parameter which identifies a particular elliptic curve + /// as defined in RFC 7518 Section 6.2.1.1: + /// <https://tools.ietf.org/html/rfc7518#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: + /// <https://tools.ietf.org/html/rfc7518#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)] +#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] +pub struct JwkEcKey { + /// The `crv` parameter which identifies a particular elliptic curve + /// as defined in RFC 7518 Section 6.2.1.1: + /// <https://tools.ietf.org/html/rfc7518#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: + /// <https://tools.ietf.org/html/rfc7518#section-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: + /// <https://tools.ietf.org/html/rfc7518#section-6.2.1.3> + y: String, + + /// The `d` ECC private key parameter as described in RFC 7518 6.2.2.1: + /// <https://tools.ietf.org/html/rfc7518#section-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: + /// <https://www.secg.org/sec1-v2.pdf> + d: Option<String>, +} + +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")] + #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] + pub fn to_public_key<C>(&self) -> Result<PublicKey<C>> + where + C: Curve + JwkParameters + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, + { + PublicKey::from_sec1_bytes(self.to_encoded_point::<C>()?.as_bytes()) + } + + /// Create a JWK from a SEC1 [`EncodedPoint`]. + pub fn from_encoded_point<C>(point: &EncodedPoint<C>) -> Option<Self> + where + C: Curve + JwkParameters, + FieldSize<C>: 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<C>(&self) -> Result<EncodedPoint<C>> + where + C: Curve + JwkParameters, + FieldSize<C>: ModulusSize, + { + if self.crv != C::CRV { + return Err(Error); + } + + let x = decode_base64url_fe::<C>(&self.x)?; + let y = decode_base64url_fe::<C>(&self.y)?; + Ok(EncodedPoint::<C>::from_affine_coordinates(&x, &y, false)) + } + + /// Decode a JWK into a [`SecretKey`]. + #[cfg(feature = "arithmetic")] + #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] + pub fn to_secret_key<C>(&self) -> Result<SecretKey<C>> + where + C: Curve + JwkParameters + ValidatePublicKey, + FieldSize<C>: ModulusSize, + { + self.try_into() + } +} + +impl FromStr for JwkEcKey { + type Err = Error; + + fn from_str(s: &str) -> Result<Self> { + 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") + } +} + +#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] +impl<C> TryFrom<JwkEcKey> for SecretKey<C> +where + C: Curve + JwkParameters + ValidatePublicKey, + FieldSize<C>: ModulusSize, +{ + type Error = Error; + + fn try_from(jwk: JwkEcKey) -> Result<SecretKey<C>> { + (&jwk).try_into() + } +} + +#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] +impl<C> TryFrom<&JwkEcKey> for SecretKey<C> +where + C: Curve + JwkParameters + ValidatePublicKey, + FieldSize<C>: ModulusSize, +{ + type Error = Error; + + fn try_from(jwk: &JwkEcKey) -> Result<SecretKey<C>> { + if let Some(d_base64) = &jwk.d { + let pk = jwk.to_encoded_point::<C>()?; + let mut d_bytes = decode_base64url_fe::<C>(d_base64)?; + let result = SecretKey::from_be_bytes(&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")] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] +impl<C> From<SecretKey<C>> for JwkEcKey +where + C: Curve + JwkParameters + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + fn from(sk: SecretKey<C>) -> JwkEcKey { + (&sk).into() + } +} + +#[cfg(feature = "arithmetic")] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] +impl<C> From<&SecretKey<C>> for JwkEcKey +where + C: Curve + JwkParameters + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + fn from(sk: &SecretKey<C>) -> JwkEcKey { + let mut jwk = sk.public_key().to_jwk(); + let mut d = sk.to_be_bytes(); + jwk.d = Some(Base64Url::encode_string(&d)); + d.zeroize(); + jwk + } +} + +#[cfg(feature = "arithmetic")] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] +impl<C> TryFrom<JwkEcKey> for PublicKey<C> +where + C: Curve + JwkParameters + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + type Error = Error; + + fn try_from(jwk: JwkEcKey) -> Result<PublicKey<C>> { + (&jwk).try_into() + } +} + +#[cfg(feature = "arithmetic")] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] +impl<C> TryFrom<&JwkEcKey> for PublicKey<C> +where + C: Curve + JwkParameters + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + type Error = Error; + + fn try_from(jwk: &JwkEcKey) -> Result<PublicKey<C>> { + PublicKey::from_sec1_bytes(jwk.to_encoded_point::<C>()?.as_bytes()) + } +} + +#[cfg(feature = "arithmetic")] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] +impl<C> From<PublicKey<C>> for JwkEcKey +where + C: Curve + JwkParameters + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + fn from(pk: PublicKey<C>) -> JwkEcKey { + (&pk).into() + } +} + +#[cfg(feature = "arithmetic")] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] +impl<C> From<&PublicKey<C>> for JwkEcKey +where + C: Curve + JwkParameters + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + fn from(pk: &PublicKey<C>) -> JwkEcKey { + Self::from_encoded_point::<C>(&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<D>(deserializer: D) -> core::result::Result<Self, D::Error> + 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<E>(self, value: u64) -> core::result::Result<Self::Value, E> + 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<E>(self, value: &str) -> core::result::Result<Self::Value, E> + where + E: de::Error, + { + self.visit_bytes(value.as_bytes()) + } + + fn visit_bytes<E>(self, value: &[u8]) -> core::result::Result<Self::Value, E> + 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<D>(__deserializer: D) -> core::result::Result<Self, D::Error> + where + D: de::Deserializer<'de>, + { + de::Deserializer::deserialize_identifier(__deserializer, FieldVisitor) + } + } + + struct Visitor<'de> { + marker: PhantomData<JwkEcKey>, + 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<A>(self, mut seq: A) -> core::result::Result<Self::Value, A::Error> + where + A: de::SeqAccess<'de>, + { + let kty = de::SeqAccess::next_element::<String>(&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::<String>(&mut seq)? + .ok_or_else(|| de::Error::invalid_length(1, &DE_ERROR_MSG))?; + + let x = de::SeqAccess::next_element::<String>(&mut seq)? + .ok_or_else(|| de::Error::invalid_length(2, &DE_ERROR_MSG))?; + + let y = de::SeqAccess::next_element::<String>(&mut seq)? + .ok_or_else(|| de::Error::invalid_length(3, &DE_ERROR_MSG))?; + + let d = de::SeqAccess::next_element::<Option<String>>(&mut seq)? + .ok_or_else(|| de::Error::invalid_length(4, &DE_ERROR_MSG))?; + + Ok(JwkEcKey { crv, x, y, d }) + } + + #[inline] + fn visit_map<A>(self, mut map: A) -> core::result::Result<Self::Value, A::Error> + where + A: de::MapAccess<'de>, + { + let mut kty: Option<String> = None; + let mut crv: Option<String> = None; + let mut x: Option<String> = None; + let mut y: Option<String> = None; + let mut d: Option<String> = None; + + while let Some(key) = de::MapAccess::next_key::<Field>(&mut map)? { + match key { + Field::Kty => { + if kty.is_none() { + kty = Some(de::MapAccess::next_value::<String>(&mut map)?); + } else { + return Err(de::Error::duplicate_field(FIELDS[0])); + } + } + Field::Crv => { + if crv.is_none() { + crv = Some(de::MapAccess::next_value::<String>(&mut map)?); + } else { + return Err(de::Error::duplicate_field(FIELDS[1])); + } + } + Field::X => { + if x.is_none() { + x = Some(de::MapAccess::next_value::<String>(&mut map)?); + } else { + return Err(de::Error::duplicate_field(FIELDS[2])); + } + } + Field::Y => { + if y.is_none() { + y = Some(de::MapAccess::next_value::<String>(&mut map)?); + } else { + return Err(de::Error::duplicate_field(FIELDS[3])); + } + } + Field::D => { + if d.is_none() { + d = de::MapAccess::next_value::<Option<String>>(&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::<JwkEcKey>, + lifetime: PhantomData, + }, + ) + } +} + +impl Serialize for JwkEcKey { + fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error> + 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<C: Curve>(s: &str) -> Result<FieldBytes<C>> { + let mut result = FieldBytes::<C>::default(); + Base64Url::decode(s, &mut result).map_err(|_| Error)?; + Ok(result) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[cfg(feature = "dev")] + use crate::dev::MockCurve; + + /// Example private key. From RFC 7518 Appendix C: + /// <https://tools.ietf.org/html/rfc7518#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::<MockCurve>().unwrap(); + let (x, y) = match point.coordinates() { + Coordinates::Uncompressed { x, y } => (x, y), + other => panic!("unexpected coordinates: {:?}", other), + }; + + assert_eq!(&decode_base64url_fe::<MockCurve>(&jwk.x).unwrap(), x); + assert_eq!(&decode_base64url_fe::<MockCurve>(&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::<MockCurve>().unwrap(); + let jwk2 = JwkEcKey::from_encoded_point::<MockCurve>(&point).unwrap(); + assert_eq!(jwk, jwk2); + } +} diff --git a/vendor/elliptic-curve/src/lib.rs b/vendor/elliptic-curve/src/lib.rs new file mode 100644 index 000000000..62ac7856b --- /dev/null +++ b/vendor/elliptic-curve/src/lib.rs @@ -0,0 +1,220 @@ +#![no_std] +#![cfg_attr(docsrs, feature(doc_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, clippy::unwrap_used)] +#![warn(missing_docs, rust_2018_idioms, 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 +//! - [`p256`]: NIST P-256 a.k.a secp256r1, prime256v1 +//! - [`p384`]: NIST P-384 a.k.a. secp384r1 +//! +//! 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`] +//! - [`ScalarCore`] +//! +//! 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 +//! [`p256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p256 +//! [`p384`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p384 +//! [`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; + +#[cfg(feature = "rand_core")] +#[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] +pub use rand_core; + +#[macro_use] +mod macros; + +pub mod ops; + +#[cfg(feature = "dev")] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +pub mod dev; + +#[cfg(feature = "ecdh")] +#[cfg_attr(docsrs, doc(cfg(feature = "ecdh")))] +pub mod ecdh; + +#[cfg(feature = "hash2curve")] +#[cfg_attr(docsrs, doc(cfg(feature = "hash2curve")))] +pub mod hash2curve; + +#[cfg(feature = "sec1")] +#[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] +pub mod sec1; + +#[cfg(feature = "arithmetic")] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +pub mod weierstrass; + +mod error; +mod point; +mod scalar; +mod secret_key; + +#[cfg(feature = "arithmetic")] +mod arithmetic; +#[cfg(feature = "arithmetic")] +mod public_key; + +#[cfg(feature = "jwk")] +mod jwk; + +pub use crate::{ + error::{Error, Result}, + point::{ + AffineXCoordinate, DecompactPoint, DecompressPoint, PointCompaction, PointCompression, + }, + scalar::{core::ScalarCore, IsHigh}, + 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::{ + AffineArithmetic, PrimeCurveArithmetic, ProjectiveArithmetic, ScalarArithmetic, + }, + public_key::PublicKey, + scalar::{nonzero::NonZeroScalar, Scalar}, + }, + ff::{self, Field, PrimeField}, + group::{self, Group}, +}; + +#[cfg(feature = "bits")] +pub use crate::scalar::ScalarBits; + +#[cfg(feature = "jwk")] +pub use crate::jwk::{JwkEcKey, JwkParameters}; + +#[cfg(feature = "pkcs8")] +pub use pkcs8; + +use core::fmt::Debug; +use generic_array::GenericArray; + +/// Algorithm [`ObjectIdentifier`][`pkcs8::ObjectIdentifier`] for elliptic +/// curve public key cryptography (`id-ecPublicKey`). +/// +/// <http://oid-info.com/get/1.2.840.10045.2.1> +#[cfg(feature = "pkcs8")] +#[cfg_attr(docsrs, doc(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 { + /// Integer type used to represent field elements of this elliptic curve. + // TODO(tarcieri): replace this with an e.g. `const Curve::MODULUS: UInt`. + // Requires rust-lang/rust#60551, i.e. `const_evaluatable_checked` + type UInt: bigint::AddMod<Output = Self::UInt> + + bigint::ArrayEncoding + + bigint::Encoding + + bigint::Integer + + bigint::NegMod<Output = Self::UInt> + + bigint::Random + + bigint::RandomMod + + bigint::SubMod<Output = Self::UInt> + + zeroize::Zeroize; + + /// Order constant. + /// + /// Subdivided into either 32-bit or 64-bit "limbs" (depending on the + /// target CPU's word size), specified from least to most significant. + const ORDER: Self::UInt; +} + +/// Marker trait for elliptic curves with prime order. +pub trait PrimeCurve: Curve {} + +/// Size of field elements of this elliptic curve. +pub type FieldSize<C> = <<C as Curve>::UInt as bigint::ArrayEncoding>::ByteSize; + +/// Byte representation of a base/scalar field element of a given curve. +pub type FieldBytes<C> = GenericArray<u8, FieldSize<C>>; + +/// Affine point type for a given curve with a [`ProjectiveArithmetic`] +/// implementation. +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +#[cfg(feature = "arithmetic")] +pub type AffinePoint<C> = <C as AffineArithmetic>::AffinePoint; + +/// Projective point type for a given curve with a [`ProjectiveArithmetic`] +/// implementation. +#[cfg(feature = "arithmetic")] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +pub type ProjectivePoint<C> = <C as ProjectiveArithmetic>::ProjectivePoint; + +/// Elliptic curve parameters used by VOPRF. +#[cfg(feature = "voprf")] +#[cfg_attr(docsrs, doc(cfg(feature = "voprf")))] +pub trait VoprfParameters: Curve { + /// The `ID` parameter which identifies a particular elliptic curve + /// as defined in [section 4 of `draft-irtf-cfrg-voprf-08`][voprf]. + /// + /// [voprf]: https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-4 + const ID: u16; + + /// The `Hash` parameter which assigns a particular hash function to this + /// ciphersuite as defined in [section 4 of `draft-irtf-cfrg-voprf-08`][voprf]. + /// + /// [voprf]: https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-4 + type Hash: digest::Digest; +} diff --git a/vendor/elliptic-curve/src/macros.rs b/vendor/elliptic-curve/src/macros.rs new file mode 100644 index 000000000..6ceadc833 --- /dev/null +++ b/vendor/elliptic-curve/src/macros.rs @@ -0,0 +1,440 @@ +/// Provides both inherent and trait impls for a field element type which are +/// backed by a core set of arithmetic functions specified as macro arguments. +/// +/// # Inherent impls +/// - `const ZERO: Self` +/// - `const ONE: Self` (multiplicative identity) +/// - `pub fn from_be_bytes` +/// - `pub fn from_be_slice` +/// - `pub fn from_le_bytes` +/// - `pub fn from_le_slice` +/// - `pub fn from_uint` +/// - `fn from_uint_unchecked` +/// - `pub fn to_be_bytes` +/// - `pub fn to_le_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_field_element { + ( + $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_be_bytes(repr: $bytes) -> $crate::subtle::CtOption<Self> { + use $crate::bigint::ArrayEncoding as _; + Self::from_uint(<$uint>::from_be_byte_array(repr)) + } + + /// Decode [` + #[doc = stringify!($fe)] + /// `] from a big endian byte slice. + pub fn from_be_slice(slice: &[u8]) -> $crate::Result<Self> { + <$uint as $crate::bigint::Encoding>::Repr::try_from(slice) + .ok() + .and_then(|array| Self::from_be_bytes(array.into()).into()) + .ok_or($crate::Error) + } + + /// Create a [` + #[doc = stringify!($fe)] + /// `] from a canonical little-endian representation. + pub fn from_le_bytes(repr: $bytes) -> $crate::subtle::CtOption<Self> { + use $crate::bigint::ArrayEncoding as _; + Self::from_uint(<$uint>::from_le_byte_array(repr)) + } + + /// Decode [` + #[doc = stringify!($fe)] + /// `] from a little endian byte slice. + pub fn from_le_slice(slice: &[u8]) -> $crate::Result<Self> { + <$uint as $crate::bigint::Encoding>::Repr::try_from(slice) + .ok() + .and_then(|array| Self::from_le_bytes(array.into()).into()) + .ok_or($crate::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::subtle::CtOption<Self> { + use $crate::subtle::ConstantTimeLess as _; + let is_some = uint.ct_lt(&$modulus); + $crate::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_be_hex(hex: &str) -> Self { + Self::from_uint_unchecked(<$uint>::from_be_hex(hex)) + } + + /// Parse a [` + #[doc = stringify!($fe)] + /// `] from little 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_le_hex(hex: &str) -> Self { + Self::from_uint_unchecked(<$uint>::from_le_hex(hex)) + } + + /// 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_be_bytes(self) -> $bytes { + use $crate::bigint::ArrayEncoding as _; + self.to_canonical().to_be_byte_array() + } + + /// Returns the little-endian encoding of this [` + #[doc = stringify!($fe)] + /// `]. + pub fn to_le_bytes(self) -> $bytes { + use $crate::bigint::ArrayEncoding as _; + self.to_canonical().to_le_byte_array() + } + + /// 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::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 mul(&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()))) + } + } + + 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 $crate::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::subtle::ConstantTimeEq for $fe { + fn ct_eq(&self, other: &Self) -> $crate::subtle::Choice { + self.0.ct_eq(&other.0) + } + } + + impl $crate::subtle::ConstantTimeGreater for $fe { + fn ct_gt(&self, other: &Self) -> $crate::subtle::Choice { + self.0.ct_gt(&other.0) + } + } + + impl $crate::subtle::ConstantTimeLess for $fe { + fn ct_lt(&self, other: &Self) -> $crate::subtle::Choice { + self.0.ct_lt(&other.0) + } + } + + impl $crate::zeroize::DefaultIsZeroes for $fe {} + + impl $crate::ff::Field for $fe { + fn random(mut rng: impl $crate::rand_core::RngCore) -> Self { + // NOTE: can't use ScalarCore::random due to CryptoRng bound + let mut bytes = <$bytes>::default(); + + loop { + rng.fill_bytes(&mut bytes); + if let Some(fe) = Self::from_be_bytes(bytes).into() { + return fe; + } + } + } + + fn zero() -> Self { + Self::ZERO + } + + fn one() -> Self { + Self::ONE + } + + 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> { + self.invert() + } + + fn sqrt(&self) -> CtOption<Self> { + self.sqrt() + } + } + + $crate::impl_field_op!($fe, $uint, Add, add, $add); + $crate::impl_field_op!($fe, $uint, Sub, sub, $sub); + $crate::impl_field_op!($fe, $uint, 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()) + } + } + }; +} + +/// 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, $uint:ty, $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()) + } + } + }; +} diff --git a/vendor/elliptic-curve/src/ops.rs b/vendor/elliptic-curve/src/ops.rs new file mode 100644 index 000000000..580c5aefc --- /dev/null +++ b/vendor/elliptic-curve/src/ops.rs @@ -0,0 +1,96 @@ +//! Traits for arithmetic operations on elliptic curve field elements. + +pub use core::ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign}; + +use crypto_bigint::{ArrayEncoding, ByteArray, Integer}; + +#[cfg(feature = "arithmetic")] +use {group::Group, subtle::CtOption}; + +#[cfg(feature = "digest")] +use digest::FixedOutput; + +/// 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; +} + +#[cfg(feature = "arithmetic")] +impl<F: ff::Field> Invert for F { + type Output = CtOption<F>; + + fn invert(&self) -> CtOption<F> { + ff::Field::invert(self) + } +} + +/// 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) +#[cfg(feature = "arithmetic")] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +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) + } +} + +/// Modular reduction. +pub trait Reduce<UInt: Integer + ArrayEncoding>: Sized { + /// Perform a modular reduction, returning a field element. + fn from_uint_reduced(n: UInt) -> Self; + + /// Interpret the given byte array as a big endian integer and perform + /// a modular reduction. + fn from_be_bytes_reduced(bytes: ByteArray<UInt>) -> Self { + Self::from_uint_reduced(UInt::from_be_byte_array(bytes)) + } + + /// Interpret the given byte array as a little endian integer and perform a + /// modular reduction. + fn from_le_bytes_reduced(bytes: ByteArray<UInt>) -> Self { + Self::from_uint_reduced(UInt::from_le_byte_array(bytes)) + } + + /// Interpret a digest as a big endian integer and perform a modular + /// reduction. + #[cfg(feature = "digest")] + #[cfg_attr(docsrs, doc(cfg(feature = "digest")))] + fn from_be_digest_reduced<D>(digest: D) -> Self + where + D: FixedOutput<OutputSize = UInt::ByteSize>, + { + Self::from_be_bytes_reduced(digest.finalize_fixed()) + } + + /// Interpret a digest as a little endian integer and perform a modular + /// reduction. + #[cfg(feature = "digest")] + #[cfg_attr(docsrs, doc(cfg(feature = "digest")))] + fn from_le_digest_reduced<D>(digest: D) -> Self + where + D: FixedOutput<OutputSize = UInt::ByteSize>, + { + Self::from_le_bytes_reduced(digest.finalize_fixed()) + } +} + +/// 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<UInt: Integer + ArrayEncoding>: Sized { + /// Perform a modular reduction, returning a field element. + fn from_uint_reduced_nonzero(n: UInt) -> Self; +} diff --git a/vendor/elliptic-curve/src/point.rs b/vendor/elliptic-curve/src/point.rs new file mode 100644 index 000000000..7257be66c --- /dev/null +++ b/vendor/elliptic-curve/src/point.rs @@ -0,0 +1,40 @@ +//! Traits for elliptic curve points. + +use crate::{Curve, FieldBytes}; +use subtle::{Choice, CtOption}; + +/// Obtain the affine x-coordinate of an elliptic curve point. +pub trait AffineXCoordinate<C: Curve> { + /// Get the affine x-coordinate as a serialized field element. + fn x(&self) -> FieldBytes<C>; +} + +/// 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<C: Curve>: Sized { + /// Attempt to decompress an elliptic curve point. + fn decompress(x: &FieldBytes<C>, y_is_odd: Choice) -> CtOption<Self>; +} + +/// 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<C: Curve>: Sized { + /// Attempt to decompact an elliptic curve point + fn decompact(x: &FieldBytes<C>) -> CtOption<Self>; +} + +/// 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/vendor/elliptic-curve/src/public_key.rs b/vendor/elliptic-curve/src/public_key.rs new file mode 100644 index 000000000..1dc858581 --- /dev/null +++ b/vendor/elliptic-curve/src/public_key.rs @@ -0,0 +1,411 @@ +//! Elliptic curve public keys. + +use crate::{ + AffinePoint, Curve, Error, NonZeroScalar, ProjectiveArithmetic, ProjectivePoint, Result, +}; +use core::fmt::Debug; +use group::{Curve as _, Group}; + +#[cfg(feature = "jwk")] +use crate::{JwkEcKey, JwkParameters}; + +#[cfg(all(feature = "sec1", feature = "pkcs8"))] +use crate::{ + pkcs8::{self, AssociatedOid, DecodePublicKey}, + ALGORITHM_OID, +}; + +#[cfg(feature = "pem")] +use core::str::FromStr; + +#[cfg(feature = "sec1")] +use { + crate::{ + sec1::{EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint}, + FieldSize, PointCompression, + }, + core::cmp::Ordering, + subtle::CtOption, +}; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +use pkcs8::EncodePublicKey; + +#[cfg(any(feature = "jwk", feature = "pem"))] +use alloc::string::{String, ToString}; + +/// 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. +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct PublicKey<C> +where + C: Curve + ProjectiveArithmetic, +{ + point: AffinePoint<C>, +} + +impl<C> PublicKey<C> +where + C: Curve + ProjectiveArithmetic, +{ + /// Convert an [`AffinePoint`] into a [`PublicKey`] + pub fn from_affine(point: AffinePoint<C>) -> Result<Self> { + if ProjectivePoint::<C>::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<C>) -> 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). + /// + /// <http://www.secg.org/sec1-v2.pdf> + #[cfg(feature = "sec1")] + pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> + where + C: Curve, + FieldSize<C>: ModulusSize, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + { + let point = EncodedPoint::<C>::from_bytes(bytes).map_err(|_| Error)?; + Option::from(Self::from_encoded_point(&point)).ok_or(Error) + } + + /// Borrow the inner [`AffinePoint`] from this [`PublicKey`]. + /// + /// In ECC, public keys are elliptic curve points. + pub fn as_affine(&self) -> &AffinePoint<C> { + &self.point + } + + /// Convert this [`PublicKey`] to a [`ProjectivePoint`] for the given curve + pub fn to_projective(&self) -> ProjectivePoint<C> { + self.point.into() + } + + /// Parse a [`JwkEcKey`] JSON Web Key (JWK) into a [`PublicKey`]. + #[cfg(feature = "jwk")] + #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] + pub fn from_jwk(jwk: &JwkEcKey) -> Result<Self> + where + C: Curve + JwkParameters, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, + { + jwk.to_public_key::<C>() + } + + /// Parse a string containing a JSON Web Key (JWK) into a [`PublicKey`]. + #[cfg(feature = "jwk")] + #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] + pub fn from_jwk_str(jwk: &str) -> Result<Self> + where + C: Curve + JwkParameters, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, + { + jwk.parse::<JwkEcKey>().and_then(|jwk| Self::from_jwk(&jwk)) + } + + /// Serialize this public key as [`JwkEcKey`] JSON Web Key (JWK). + #[cfg(feature = "jwk")] + #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] + pub fn to_jwk(&self) -> JwkEcKey + where + C: Curve + JwkParameters, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, + { + self.into() + } + + /// Serialize this public key as JSON Web Key (JWK) string. + #[cfg(feature = "jwk")] + #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] + pub fn to_jwk_string(&self) -> String + where + C: Curve + JwkParameters, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, + { + self.to_jwk().to_string() + } +} + +impl<C> AsRef<AffinePoint<C>> for PublicKey<C> +where + C: Curve + ProjectiveArithmetic, +{ + fn as_ref(&self) -> &AffinePoint<C> { + self.as_affine() + } +} + +impl<C> Copy for PublicKey<C> where C: Curve + ProjectiveArithmetic {} + +#[cfg(feature = "sec1")] +#[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] +impl<C> FromEncodedPoint<C> for PublicKey<C> +where + C: Curve + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + /// Initialize [`PublicKey`] from an [`EncodedPoint`] + fn from_encoded_point(encoded_point: &EncodedPoint<C>) -> CtOption<Self> { + AffinePoint::<C>::from_encoded_point(encoded_point).and_then(|point| { + let is_identity = ProjectivePoint::<C>::from(point).is_identity(); + CtOption::new(PublicKey { point }, !is_identity) + }) + } +} + +#[cfg(feature = "sec1")] +#[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] +impl<C> ToEncodedPoint<C> for PublicKey<C> +where + C: Curve + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + /// Serialize this [`PublicKey`] as a SEC1 [`EncodedPoint`], optionally applying + /// point compression + fn to_encoded_point(&self, compress: bool) -> EncodedPoint<C> { + self.point.to_encoded_point(compress) + } +} + +#[cfg(feature = "sec1")] +#[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] +impl<C> From<PublicKey<C>> for EncodedPoint<C> +where + C: Curve + ProjectiveArithmetic + PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + fn from(public_key: PublicKey<C>) -> EncodedPoint<C> { + EncodedPoint::<C>::from(&public_key) + } +} + +#[cfg(feature = "sec1")] +#[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] +impl<C> From<&PublicKey<C>> for EncodedPoint<C> +where + C: Curve + ProjectiveArithmetic + PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + fn from(public_key: &PublicKey<C>) -> EncodedPoint<C> { + public_key.to_encoded_point(C::COMPRESS_POINTS) + } +} + +#[cfg(feature = "sec1")] +#[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] +impl<C> PartialOrd for PublicKey<C> +where + C: Curve + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +#[cfg(feature = "sec1")] +#[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] +impl<C> Ord for PublicKey<C> +where + C: Curve + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + fn cmp(&self, other: &Self) -> Ordering { + // TODO(tarcieri): more efficient implementation? + // This is implemented this way to reduce bounds for `AffinePoint<C>` + self.to_encoded_point(false) + .cmp(&other.to_encoded_point(false)) + } +} + +#[cfg(all(feature = "pkcs8", feature = "sec1"))] +#[cfg_attr(docsrs, doc(cfg(all(feature = "pkcs8", feature = "sec1"))))] +impl<C> TryFrom<pkcs8::SubjectPublicKeyInfo<'_>> for PublicKey<C> +where + C: Curve + AssociatedOid + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + type Error = pkcs8::spki::Error; + + fn try_from(spki: pkcs8::SubjectPublicKeyInfo<'_>) -> pkcs8::spki::Result<Self> { + spki.algorithm.assert_oids(ALGORITHM_OID, C::OID)?; + Self::from_sec1_bytes(spki.subject_public_key) + .map_err(|_| der::Tag::BitString.value_error().into()) + } +} + +#[cfg(all(feature = "pkcs8", feature = "sec1"))] +#[cfg_attr(docsrs, doc(cfg(all(feature = "pkcs8", feature = "sec1"))))] +impl<C> DecodePublicKey for PublicKey<C> +where + C: Curve + AssociatedOid + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ +} + +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "pkcs8"))))] +impl<C> EncodePublicKey for PublicKey<C> +where + C: Curve + AssociatedOid + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + fn to_public_key_der(&self) -> pkcs8::spki::Result<der::Document> { + let algorithm = pkcs8::AlgorithmIdentifier { + oid: ALGORITHM_OID, + parameters: Some((&C::OID).into()), + }; + + let public_key_bytes = self.to_encoded_point(false); + + pkcs8::SubjectPublicKeyInfo { + algorithm, + subject_public_key: public_key_bytes.as_ref(), + } + .try_into() + } +} + +#[cfg(feature = "pem")] +#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] +impl<C> FromStr for PublicKey<C> +where + C: Curve + AssociatedOid + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + type Err = Error; + + fn from_str(s: &str) -> Result<Self> { + Self::from_public_key_pem(s).map_err(|_| Error) + } +} + +#[cfg(feature = "pem")] +#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] +impl<C> ToString for PublicKey<C> +where + C: Curve + AssociatedOid + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + fn to_string(&self) -> String { + self.to_public_key_pem(Default::default()) + .expect("PEM encoding error") + } +} + +#[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] +impl<C> Serialize for PublicKey<C> +where + C: Curve + AssociatedOid + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error> + 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")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] +impl<'de, C> Deserialize<'de> for PublicKey<C> +where + C: Curve + AssociatedOid + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error> + 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<MockCurve>; + type PublicKey = super::PublicKey<MockCurve>; + + #[test] + fn from_encoded_point_rejects_identity() { + let identity = EncodedPoint::identity(); + assert!(bool::from( + PublicKey::from_encoded_point(&identity).is_none() + )); + } +} diff --git a/vendor/elliptic-curve/src/scalar.rs b/vendor/elliptic-curve/src/scalar.rs new file mode 100644 index 000000000..72d796847 --- /dev/null +++ b/vendor/elliptic-curve/src/scalar.rs @@ -0,0 +1,32 @@ +//! Scalar types. + +use subtle::Choice; + +pub(crate) mod core; + +#[cfg(feature = "arithmetic")] +pub(crate) mod nonzero; + +#[cfg(feature = "arithmetic")] +use crate::ScalarArithmetic; + +/// Scalar field element for a particular elliptic curve. +#[cfg(feature = "arithmetic")] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +pub type Scalar<C> = <C as ScalarArithmetic>::Scalar; + +/// Bit representation of a scalar field element of a given curve. +#[cfg(feature = "bits")] +#[cfg_attr(docsrs, doc(cfg(feature = "bits")))] +pub type ScalarBits<C> = ff::FieldBits<<Scalar<C> as ff::PrimeFieldBits>::ReprBits>; + +/// 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/vendor/elliptic-curve/src/scalar/core.rs b/vendor/elliptic-curve/src/scalar/core.rs new file mode 100644 index 000000000..6a088ca55 --- /dev/null +++ b/vendor/elliptic-curve/src/scalar/core.rs @@ -0,0 +1,434 @@ +//! Generic scalar type with core functionality. + +use crate::{ + bigint::{prelude::*, Limb, NonZero}, + rand_core::{CryptoRng, RngCore}, + subtle::{ + Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess, + CtOption, + }, + Curve, Error, FieldBytes, IsHigh, Result, +}; +use base16ct::HexDisplay; +use core::{ + cmp::Ordering, + fmt, + ops::{Add, AddAssign, Neg, Sub, SubAssign}, + str, +}; +use generic_array::GenericArray; +use zeroize::DefaultIsZeroes; + +#[cfg(feature = "arithmetic")] +use { + super::{Scalar, ScalarArithmetic}, + group::ff::PrimeField, +}; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +/// Generic scalar type with core 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): make this a fully generic `Scalar` type and use it for `ScalarArithmetic` +#[derive(Copy, Clone, Debug, Default)] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +pub struct ScalarCore<C: Curve> { + /// Inner unsigned integer type. + inner: C::UInt, +} + +impl<C> ScalarCore<C> +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 [`ScalarCore`]. + pub fn random(rng: impl CryptoRng + RngCore) -> 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<Self> { + CtOption::new(Self { inner: uint }, uint.ct_lt(&Self::MODULUS)) + } + + /// Decode [`ScalarCore`] from big endian bytes. + pub fn from_be_bytes(bytes: FieldBytes<C>) -> CtOption<Self> { + Self::new(C::UInt::from_be_byte_array(bytes)) + } + + /// Decode [`ScalarCore`] from a big endian byte slice. + pub fn from_be_slice(slice: &[u8]) -> Result<Self> { + if slice.len() == C::UInt::BYTE_SIZE { + Option::from(Self::from_be_bytes(GenericArray::clone_from_slice(slice))).ok_or(Error) + } else { + Err(Error) + } + } + + /// Decode [`ScalarCore`] from little endian bytes. + pub fn from_le_bytes(bytes: FieldBytes<C>) -> CtOption<Self> { + Self::new(C::UInt::from_le_byte_array(bytes)) + } + + /// Decode [`ScalarCore`] from a little endian byte slice. + pub fn from_le_slice(slice: &[u8]) -> Result<Self> { + if slice.len() == C::UInt::BYTE_SIZE { + Option::from(Self::from_le_bytes(GenericArray::clone_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 [`ScalarCore`] value equal to zero? + pub fn is_zero(&self) -> Choice { + self.inner.is_zero() + } + + /// Is this [`ScalarCore`] value even? + pub fn is_even(&self) -> Choice { + self.inner.is_even() + } + + /// Is this [`ScalarCore`] value odd? + pub fn is_odd(&self) -> Choice { + self.inner.is_odd() + } + + /// Encode [`ScalarCore`] as big endian bytes. + pub fn to_be_bytes(self) -> FieldBytes<C> { + self.inner.to_be_byte_array() + } + + /// Encode [`ScalarCore`] as little endian bytes. + pub fn to_le_bytes(self) -> FieldBytes<C> { + self.inner.to_le_byte_array() + } +} + +#[cfg(feature = "arithmetic")] +impl<C> ScalarCore<C> +where + C: Curve + ScalarArithmetic, +{ + /// Convert [`ScalarCore`] into a given curve's scalar type + // TODO(tarcieri): replace curve-specific scalars with `ScalarCore` + pub(super) fn to_scalar(self) -> Scalar<C> { + Scalar::<C>::from_repr(self.to_be_bytes()).unwrap() + } +} + +// TODO(tarcieri): better encapsulate this? +impl<C> AsRef<[Limb]> for ScalarCore<C> +where + C: Curve, +{ + fn as_ref(&self) -> &[Limb] { + self.as_limbs() + } +} + +impl<C> ConditionallySelectable for ScalarCore<C> +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<C> ConstantTimeEq for ScalarCore<C> +where + C: Curve, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.inner.ct_eq(&other.inner) + } +} + +impl<C> ConstantTimeLess for ScalarCore<C> +where + C: Curve, +{ + fn ct_lt(&self, other: &Self) -> Choice { + self.inner.ct_lt(&other.inner) + } +} + +impl<C> ConstantTimeGreater for ScalarCore<C> +where + C: Curve, +{ + fn ct_gt(&self, other: &Self) -> Choice { + self.inner.ct_gt(&other.inner) + } +} + +impl<C: Curve> DefaultIsZeroes for ScalarCore<C> {} + +impl<C: Curve> Eq for ScalarCore<C> {} + +impl<C> PartialEq for ScalarCore<C> +where + C: Curve, +{ + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } +} + +impl<C> PartialOrd for ScalarCore<C> +where + C: Curve, +{ + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl<C> Ord for ScalarCore<C> +where + C: Curve, +{ + fn cmp(&self, other: &Self) -> Ordering { + self.inner.cmp(&other.inner) + } +} + +impl<C> From<u64> for ScalarCore<C> +where + C: Curve, +{ + fn from(n: u64) -> Self { + Self { + inner: C::UInt::from(n), + } + } +} + +impl<C> Add<ScalarCore<C>> for ScalarCore<C> +where + C: Curve, +{ + type Output = Self; + + fn add(self, other: Self) -> Self { + self.add(&other) + } +} + +impl<C> Add<&ScalarCore<C>> for ScalarCore<C> +where + C: Curve, +{ + type Output = Self; + + fn add(self, other: &Self) -> Self { + Self { + inner: self.inner.add_mod(&other.inner, &Self::MODULUS), + } + } +} + +impl<C> AddAssign<ScalarCore<C>> for ScalarCore<C> +where + C: Curve, +{ + fn add_assign(&mut self, other: Self) { + *self = *self + other; + } +} + +impl<C> AddAssign<&ScalarCore<C>> for ScalarCore<C> +where + C: Curve, +{ + fn add_assign(&mut self, other: &Self) { + *self = *self + other; + } +} + +impl<C> Sub<ScalarCore<C>> for ScalarCore<C> +where + C: Curve, +{ + type Output = Self; + + fn sub(self, other: Self) -> Self { + self.sub(&other) + } +} + +impl<C> Sub<&ScalarCore<C>> for ScalarCore<C> +where + C: Curve, +{ + type Output = Self; + + fn sub(self, other: &Self) -> Self { + Self { + inner: self.inner.sub_mod(&other.inner, &Self::MODULUS), + } + } +} + +impl<C> SubAssign<ScalarCore<C>> for ScalarCore<C> +where + C: Curve, +{ + fn sub_assign(&mut self, other: Self) { + *self = *self - other; + } +} + +impl<C> SubAssign<&ScalarCore<C>> for ScalarCore<C> +where + C: Curve, +{ + fn sub_assign(&mut self, other: &Self) { + *self = *self - other; + } +} + +impl<C> Neg for ScalarCore<C> +where + C: Curve, +{ + type Output = Self; + + fn neg(self) -> Self { + Self { + inner: self.inner.neg_mod(&Self::MODULUS), + } + } +} + +impl<C> Neg for &ScalarCore<C> +where + C: Curve, +{ + type Output = ScalarCore<C>; + + fn neg(self) -> ScalarCore<C> { + -*self + } +} + +impl<C> IsHigh for ScalarCore<C> +where + C: Curve, +{ + fn is_high(&self) -> Choice { + let n_2 = C::ORDER >> 1; + self.inner.ct_gt(&n_2) + } +} + +impl<C> fmt::Display for ScalarCore<C> +where + C: Curve, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:X}", self) + } +} + +impl<C> fmt::LowerHex for ScalarCore<C> +where + C: Curve, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:x}", HexDisplay(&self.to_be_bytes())) + } +} + +impl<C> fmt::UpperHex for ScalarCore<C> +where + C: Curve, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:X}", HexDisplay(&self.to_be_bytes())) + } +} + +impl<C> str::FromStr for ScalarCore<C> +where + C: Curve, +{ + type Err = Error; + + fn from_str(hex: &str) -> Result<Self> { + let mut bytes = FieldBytes::<C>::default(); + base16ct::lower::decode(hex, &mut bytes)?; + Option::from(Self::from_be_bytes(bytes)).ok_or(Error) + } +} + +#[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] +impl<C> Serialize for ScalarCore<C> +where + C: Curve, +{ + fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error> + where + S: ser::Serializer, + { + serdect::array::serialize_hex_upper_or_bin(&self.to_be_bytes(), serializer) + } +} + +#[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] +impl<'de, C> Deserialize<'de> for ScalarCore<C> +where + C: Curve, +{ + fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error> + where + D: de::Deserializer<'de>, + { + let mut bytes = FieldBytes::<C>::default(); + serdect::array::deserialize_hex_or_bin(&mut bytes, deserializer)?; + Option::from(Self::from_be_bytes(bytes)) + .ok_or_else(|| de::Error::custom("scalar out of range")) + } +} diff --git a/vendor/elliptic-curve/src/scalar/nonzero.rs b/vendor/elliptic-curve/src/scalar/nonzero.rs new file mode 100644 index 000000000..7450537a9 --- /dev/null +++ b/vendor/elliptic-curve/src/scalar/nonzero.rs @@ -0,0 +1,353 @@ +//! Non-zero scalar type. + +use crate::{ + bigint::Encoding as _, + ops::{Invert, Reduce, ReduceNonZero}, + rand_core::{CryptoRng, RngCore}, + Curve, Error, FieldBytes, IsHigh, PrimeCurve, Result, Scalar, ScalarArithmetic, ScalarCore, + SecretKey, +}; +use base16ct::HexDisplay; +use core::{ + fmt, + ops::{Deref, Mul, Neg}, + str, +}; +use crypto_bigint::{ArrayEncoding, Integer}; +use ff::{Field, PrimeField}; +use generic_array::GenericArray; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use zeroize::Zeroize; + +/// 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. +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +#[derive(Clone)] +pub struct NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, +{ + scalar: Scalar<C>, +} + +impl<C> NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, +{ + /// Generate a random `NonZeroScalar`. + pub fn random(mut rng: impl CryptoRng + RngCore) -> 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<C>) -> CtOption<Self> { + CtOption::new(Self { scalar }, !scalar.is_zero()) + } + + /// Decode a [`NonZeroScalar`] from a big endian-serialized field element. + pub fn from_repr(repr: FieldBytes<C>) -> CtOption<Self> { + Scalar::<C>::from_repr(repr).and_then(Self::new) + } + + /// Create a [`NonZeroScalar`] from a `C::UInt`. + pub fn from_uint(uint: C::UInt) -> CtOption<Self> { + ScalarCore::new(uint).and_then(|scalar| Self::new(scalar.into())) + } +} + +impl<C> AsRef<Scalar<C>> for NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, +{ + fn as_ref(&self) -> &Scalar<C> { + &self.scalar + } +} + +impl<C> ConditionallySelectable for NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, +{ + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self { + scalar: Scalar::<C>::conditional_select(&a.scalar, &b.scalar, choice), + } + } +} + +impl<C> ConstantTimeEq for NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.scalar.ct_eq(&other.scalar) + } +} + +impl<C> Copy for NonZeroScalar<C> where C: Curve + ScalarArithmetic {} + +impl<C> Deref for NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, +{ + type Target = Scalar<C>; + + fn deref(&self) -> &Scalar<C> { + &self.scalar + } +} + +impl<C> From<NonZeroScalar<C>> for FieldBytes<C> +where + C: Curve + ScalarArithmetic, +{ + fn from(scalar: NonZeroScalar<C>) -> FieldBytes<C> { + Self::from(&scalar) + } +} + +impl<C> From<&NonZeroScalar<C>> for FieldBytes<C> +where + C: Curve + ScalarArithmetic, +{ + fn from(scalar: &NonZeroScalar<C>) -> FieldBytes<C> { + scalar.to_repr() + } +} + +impl<C> From<NonZeroScalar<C>> for ScalarCore<C> +where + C: Curve + ScalarArithmetic, +{ + fn from(scalar: NonZeroScalar<C>) -> ScalarCore<C> { + ScalarCore::from_be_bytes(scalar.to_repr()).unwrap() + } +} + +impl<C> From<&NonZeroScalar<C>> for ScalarCore<C> +where + C: Curve + ScalarArithmetic, +{ + fn from(scalar: &NonZeroScalar<C>) -> ScalarCore<C> { + ScalarCore::from_be_bytes(scalar.to_repr()).unwrap() + } +} + +impl<C> From<SecretKey<C>> for NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, +{ + fn from(sk: SecretKey<C>) -> NonZeroScalar<C> { + Self::from(&sk) + } +} + +impl<C> From<&SecretKey<C>> for NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, +{ + fn from(sk: &SecretKey<C>) -> NonZeroScalar<C> { + let scalar = sk.as_scalar_core().to_scalar(); + debug_assert!(!bool::from(scalar.is_zero())); + Self { scalar } + } +} + +impl<C> Invert for NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, +{ + type Output = Self; + + fn invert(&self) -> Self { + Self { + // This will always succeed since `scalar` will never be 0 + scalar: ff::Field::invert(&self.scalar).unwrap(), + } + } +} + +impl<C> IsHigh for NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, +{ + fn is_high(&self) -> Choice { + self.scalar.is_high() + } +} + +impl<C> Neg for NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, +{ + type Output = NonZeroScalar<C>; + + fn neg(self) -> NonZeroScalar<C> { + let scalar = -self.scalar; + debug_assert!(!bool::from(scalar.is_zero())); + NonZeroScalar { scalar } + } +} + +impl<C> Mul<NonZeroScalar<C>> for NonZeroScalar<C> +where + C: PrimeCurve + ScalarArithmetic, +{ + type Output = Self; + + #[inline] + fn mul(self, other: Self) -> Self { + Self::mul(self, &other) + } +} + +impl<C> Mul<&NonZeroScalar<C>> for NonZeroScalar<C> +where + C: PrimeCurve + ScalarArithmetic, +{ + 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: implementation is the same as `ReduceNonZero` +impl<C, I> Reduce<I> for NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, + I: Integer + ArrayEncoding, + Scalar<C>: ReduceNonZero<I>, +{ + fn from_uint_reduced(n: I) -> Self { + Self::from_uint_reduced_nonzero(n) + } +} + +impl<C, I> ReduceNonZero<I> for NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, + I: Integer + ArrayEncoding, + Scalar<C>: ReduceNonZero<I>, +{ + fn from_uint_reduced_nonzero(n: I) -> Self { + let scalar = Scalar::<C>::from_uint_reduced_nonzero(n); + debug_assert!(!bool::from(scalar.is_zero())); + Self::new(scalar).unwrap() + } +} + +impl<C> TryFrom<&[u8]> for NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, +{ + type Error = Error; + + fn try_from(bytes: &[u8]) -> Result<Self> { + if bytes.len() == C::UInt::BYTE_SIZE { + Option::from(NonZeroScalar::from_repr(GenericArray::clone_from_slice( + bytes, + ))) + .ok_or(Error) + } else { + Err(Error) + } + } +} + +impl<C> Zeroize for NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, +{ + 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::<C>::one(); + } +} + +impl<C> fmt::Display for NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:X}", self) + } +} + +impl<C> fmt::LowerHex for NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:x}", HexDisplay(&self.to_repr())) + } +} + +impl<C> fmt::UpperHex for NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:}", HexDisplay(&self.to_repr())) + } +} + +impl<C> str::FromStr for NonZeroScalar<C> +where + C: Curve + ScalarArithmetic, +{ + type Err = Error; + + fn from_str(hex: &str) -> Result<Self> { + let mut bytes = FieldBytes::<C>::default(); + + if base16ct::mixed::decode(hex, &mut bytes)?.len() == bytes.len() { + Option::from(Self::from_repr(bytes)).ok_or(Error) + } else { + Err(Error) + } + } +} + +#[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/vendor/elliptic-curve/src/sec1.rs b/vendor/elliptic-curve/src/sec1.rs new file mode 100644 index 000000000..3e1635941 --- /dev/null +++ b/vendor/elliptic-curve/src/sec1.rs @@ -0,0 +1,114 @@ +//! Support for SEC1 elliptic curve encoding formats. +//! +//! <https://www.secg.org/sec1-v2.pdf> + +pub use sec1::point::{Coordinates, ModulusSize, Tag}; + +use crate::{Curve, FieldSize, Result, SecretKey}; +use generic_array::GenericArray; +use subtle::CtOption; + +#[cfg(feature = "arithmetic")] +use crate::{AffinePoint, Error, ProjectiveArithmetic}; + +/// Encoded elliptic curve point with point compression. +pub type CompressedPoint<C> = GenericArray<u8, CompressedPointSize<C>>; + +/// Size of a compressed elliptic curve point. +pub type CompressedPointSize<C> = <FieldSize<C> as ModulusSize>::CompressedPointSize; + +/// Encoded elliptic curve point sized appropriately for a given curve. +pub type EncodedPoint<C> = sec1::point::EncodedPoint<FieldSize<C>>; + +/// Encoded elliptic curve point *without* point compression. +pub type UncompressedPoint<C> = GenericArray<u8, UncompressedPointSize<C>>; + +/// Size of an uncompressed elliptic curve point. +pub type UncompressedPointSize<C> = <FieldSize<C> 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<C> +where + Self: Sized, + C: Curve, + FieldSize<C>: ModulusSize, +{ + /// Deserialize the type this trait is impl'd on from an [`EncodedPoint`]. + fn from_encoded_point(point: &EncodedPoint<C>) -> CtOption<Self>; +} + +/// 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<C> +where + C: Curve, + FieldSize<C>: ModulusSize, +{ + /// Serialize this value as a SEC1 [`EncodedPoint`], optionally applying + /// point compression. + fn to_encoded_point(&self, compress: bool) -> EncodedPoint<C>; +} + +/// 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<C> +where + C: Curve, + FieldSize<C>: ModulusSize, +{ + /// Serialize this value as a SEC1 [`EncodedPoint`], optionally applying + /// point compression. + fn to_compact_encoded_point(&self) -> CtOption<EncodedPoint<C>>; +} + +/// Validate that the given [`EncodedPoint`] represents the encoded public key +/// value of the given secret. +/// +/// Curve implementations which also impl [`ProjectiveArithmetic`] will receive +/// a blanket default impl of this trait. +pub trait ValidatePublicKey +where + Self: Curve, + FieldSize<Self>: 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<Self>, + public_key: &EncodedPoint<Self>, + ) -> 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(all(feature = "arithmetic"))] +impl<C> ValidatePublicKey for C +where + C: Curve + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + fn validate_public_key(secret_key: &SecretKey<C>, public_key: &EncodedPoint<C>) -> 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/vendor/elliptic-curve/src/secret_key.rs b/vendor/elliptic-curve/src/secret_key.rs new file mode 100644 index 000000000..0fc3dafb1 --- /dev/null +++ b/vendor/elliptic-curve/src/secret_key.rs @@ -0,0 +1,395 @@ +//! 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, ScalarCore}; +use core::fmt::{self, Debug}; +use crypto_bigint::Encoding; +use generic_array::GenericArray; +use subtle::{Choice, ConstantTimeEq}; +use zeroize::{Zeroize, ZeroizeOnDrop}; + +#[cfg(all(feature = "alloc", feature = "arithmetic"))] +use { + crate::{ + sec1::{FromEncodedPoint, ToEncodedPoint}, + AffinePoint, + }, + alloc::vec::Vec, + der::Encode, + zeroize::Zeroizing, +}; + +#[cfg(feature = "arithmetic")] +use crate::{ + rand_core::{CryptoRng, RngCore}, + NonZeroScalar, ProjectiveArithmetic, PublicKey, +}; + +#[cfg(feature = "jwk")] +use crate::jwk::{JwkEcKey, JwkParameters}; + +#[cfg(all(feature = "arithmetic", any(feature = "jwk", feature = "pem")))] +use alloc::string::String; + +#[cfg(all(feature = "arithmetic", feature = "jwk"))] +use alloc::string::ToString; + +#[cfg(feature = "pem")] +use pem_rfc7468 as pem; + +#[cfg(feature = "sec1")] +use crate::{ + sec1::{EncodedPoint, ModulusSize, ValidatePublicKey}, + FieldSize, +}; + +#[cfg(all(docsrs, feature = "pkcs8"))] +use {crate::pkcs8::DecodePrivateKey, core::str::FromStr}; + +/// Type label for PEM-encoded SEC1 private keys. +#[cfg(feature = "pem")] +pub(crate) const SEC1_PEM_TYPE_LABEL: &str = "EC PRIVATE KEY"; + +/// 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<C: Curve> { + /// Scalar value + inner: ScalarCore<C>, +} + +impl<C> SecretKey<C> +where + C: Curve, +{ + /// Generate a random [`SecretKey`]. + #[cfg(feature = "arithmetic")] + #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] + pub fn random(rng: impl CryptoRng + RngCore) -> Self + where + C: ProjectiveArithmetic, + { + Self { + inner: NonZeroScalar::<C>::random(rng).into(), + } + } + + /// Create a new secret key from a scalar value. + pub fn new(scalar: ScalarCore<C>) -> Self { + Self { inner: scalar } + } + + /// Borrow the inner secret [`ScalarCore`] value. + /// + /// # ⚠️ Warning + /// + /// This value is key material. + /// + /// Please treat it with the care it deserves! + pub fn as_scalar_core(&self) -> &ScalarCore<C> { + &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")] + #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] + pub fn to_nonzero_scalar(&self) -> NonZeroScalar<C> + where + C: Curve + ProjectiveArithmetic, + { + self.into() + } + + /// Get the [`PublicKey`] which corresponds to this secret key + #[cfg(feature = "arithmetic")] + #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] + pub fn public_key(&self) -> PublicKey<C> + where + C: Curve + ProjectiveArithmetic, + { + PublicKey::from_secret_scalar(&self.to_nonzero_scalar()) + } + + /// Deserialize raw secret scalar as a big endian integer. + pub fn from_be_bytes(bytes: &[u8]) -> Result<Self> { + if bytes.len() != C::UInt::BYTE_SIZE { + return Err(Error); + } + + let inner: ScalarCore<C> = Option::from(ScalarCore::from_be_bytes( + GenericArray::clone_from_slice(bytes), + )) + .ok_or(Error)?; + + if inner.is_zero().into() { + return Err(Error); + } + + Ok(Self { inner }) + } + + /// Serialize raw secret scalar as a big endian integer. + pub fn to_be_bytes(&self) -> FieldBytes<C> { + self.inner.to_be_bytes() + } + + /// Deserialize secret key encoded in the SEC1 ASN.1 DER `ECPrivateKey` format. + #[cfg(all(feature = "sec1"))] + #[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] + pub fn from_sec1_der(der_bytes: &[u8]) -> Result<Self> + where + C: Curve + ValidatePublicKey, + FieldSize<C>: 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"))] + #[cfg_attr( + docsrs, + doc(cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1"))) + )] + pub fn to_sec1_der(&self) -> der::Result<Zeroizing<Vec<u8>>> + where + C: Curve + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, + { + // TODO(tarcieri): wrap `secret_key_bytes` in `Zeroizing` + let mut private_key_bytes = self.to_be_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_vec()?, + ); + + // TODO(tarcieri): wrap `private_key_bytes` in `Zeroizing` + private_key_bytes.zeroize(); + + 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")] + #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] + pub fn from_sec1_pem(s: &str) -> Result<Self> + where + C: Curve + ValidatePublicKey, + FieldSize<C>: ModulusSize, + { + let (label, der_bytes) = pem::decode_vec(s.as_bytes()).map_err(|_| Error)?; + + if label != SEC1_PEM_TYPE_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")] + #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] + pub fn to_pem(&self, line_ending: pem::LineEnding) -> Result<Zeroizing<String>> + where + C: Curve + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, + { + self.to_sec1_der() + .ok() + .and_then(|der| pem::encode_string(SEC1_PEM_TYPE_LABEL, line_ending, &der).ok()) + .map(Zeroizing::new) + .ok_or(Error) + } + + /// Parse a [`JwkEcKey`] JSON Web Key (JWK) into a [`SecretKey`]. + #[cfg(feature = "jwk")] + #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] + pub fn from_jwk(jwk: &JwkEcKey) -> Result<Self> + where + C: JwkParameters + ValidatePublicKey, + FieldSize<C>: ModulusSize, + { + Self::try_from(jwk) + } + + /// Parse a string containing a JSON Web Key (JWK) into a [`SecretKey`]. + #[cfg(feature = "jwk")] + #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] + pub fn from_jwk_str(jwk: &str) -> Result<Self> + where + C: JwkParameters + ValidatePublicKey, + FieldSize<C>: ModulusSize, + { + jwk.parse::<JwkEcKey>().and_then(|jwk| Self::from_jwk(&jwk)) + } + + /// Serialize this secret key as [`JwkEcKey`] JSON Web Key (JWK). + #[cfg(all(feature = "arithmetic", feature = "jwk"))] + #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] + #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] + pub fn to_jwk(&self) -> JwkEcKey + where + C: Curve + JwkParameters + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, + { + self.into() + } + + /// Serialize this secret key as JSON Web Key (JWK) string. + #[cfg(all(feature = "arithmetic", feature = "jwk"))] + #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] + #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] + pub fn to_jwk_string(&self) -> Zeroizing<String> + where + C: Curve + JwkParameters + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, + { + Zeroizing::new(self.to_jwk().to_string()) + } +} + +impl<C> ConstantTimeEq for SecretKey<C> +where + C: Curve, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.inner.ct_eq(&other.inner) + } +} + +impl<C> Debug for SecretKey<C> +where + C: Curve, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // TODO(tarcieri): use `debug_struct` and `finish_non_exhaustive` when stable + write!(f, "SecretKey<{:?}>{{ ... }}", C::default()) + } +} + +impl<C> ZeroizeOnDrop for SecretKey<C> where C: Curve {} + +impl<C> Drop for SecretKey<C> +where + C: Curve, +{ + fn drop(&mut self) { + self.inner.zeroize(); + } +} + +impl<C: Curve> Eq for SecretKey<C> {} + +impl<C> PartialEq for SecretKey<C> +where + C: Curve, +{ + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } +} + +#[cfg(all(feature = "sec1"))] +#[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] +impl<C> TryFrom<sec1::EcPrivateKey<'_>> for SecretKey<C> +where + C: Curve + ValidatePublicKey, + FieldSize<C>: ModulusSize, +{ + type Error = der::Error; + + fn try_from(sec1_private_key: sec1::EcPrivateKey<'_>) -> der::Result<Self> { + let secret_key = Self::from_be_bytes(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::<C>::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")] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +impl<C> From<NonZeroScalar<C>> for SecretKey<C> +where + C: Curve + ProjectiveArithmetic, +{ + fn from(scalar: NonZeroScalar<C>) -> SecretKey<C> { + SecretKey::from(&scalar) + } +} + +#[cfg(feature = "arithmetic")] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +impl<C> From<&NonZeroScalar<C>> for SecretKey<C> +where + C: Curve + ProjectiveArithmetic, +{ + fn from(scalar: &NonZeroScalar<C>) -> SecretKey<C> { + SecretKey { + inner: scalar.into(), + } + } +} diff --git a/vendor/elliptic-curve/src/secret_key/pkcs8.rs b/vendor/elliptic-curve/src/secret_key/pkcs8.rs new file mode 100644 index 000000000..3c1a509bf --- /dev/null +++ b/vendor/elliptic-curve/src/secret_key/pkcs8.rs @@ -0,0 +1,92 @@ +//! PKCS#8 encoding/decoding support. + +use super::SecretKey; +use crate::{ + pkcs8::{self, AssociatedOid, DecodePrivateKey}, + sec1::{ModulusSize, ValidatePublicKey}, + Curve, FieldSize, ALGORITHM_OID, +}; +use der::Decode; +use sec1::EcPrivateKey; + +// Imports for the `EncodePrivateKey` impl +// TODO(tarcieri): use weak activation of `pkcs8/alloc` for gating `EncodePrivateKey` impl +#[cfg(all(feature = "arithmetic", feature = "pem"))] +use { + crate::{ + sec1::{FromEncodedPoint, ToEncodedPoint}, + AffinePoint, ProjectiveArithmetic, + }, + pkcs8::EncodePrivateKey, +}; + +// Imports for actual PEM support +#[cfg(feature = "pem")] +use { + crate::{error::Error, Result}, + core::str::FromStr, +}; + +#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))] +impl<C> TryFrom<pkcs8::PrivateKeyInfo<'_>> for SecretKey<C> +where + C: Curve + AssociatedOid + ValidatePublicKey, + FieldSize<C>: ModulusSize, +{ + type Error = pkcs8::Error; + + fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result<Self> { + 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_attr(docsrs, doc(cfg(feature = "pkcs8")))] +impl<C> DecodePrivateKey for SecretKey<C> +where + C: Curve + AssociatedOid + ValidatePublicKey, + FieldSize<C>: ModulusSize, +{ +} + +// TODO(tarcieri): use weak activation of `pkcs8/alloc` for this when possible +// It doesn't strictly depend on `pkcs8/pem` but we can't easily activate `pkcs8/alloc` +// without adding a separate crate feature just for this functionality. +#[cfg(all(feature = "arithmetic", feature = "pem"))] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] +impl<C> EncodePrivateKey for SecretKey<C> +where + C: Curve + AssociatedOid + ProjectiveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldSize<C>: ModulusSize, +{ + fn to_pkcs8_der(&self) -> pkcs8::Result<der::SecretDocument> { + let algorithm_identifier = pkcs8::AlgorithmIdentifier { + 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")] +#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] +impl<C> FromStr for SecretKey<C> +where + C: Curve + AssociatedOid + ValidatePublicKey, + FieldSize<C>: ModulusSize, +{ + type Err = Error; + + fn from_str(s: &str) -> Result<Self> { + Self::from_pkcs8_pem(s).map_err(|_| Error) + } +} diff --git a/vendor/elliptic-curve/src/weierstrass.rs b/vendor/elliptic-curve/src/weierstrass.rs new file mode 100644 index 000000000..1782d95e1 --- /dev/null +++ b/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, Fe); + +/// Projective point whose coordinates are represented by the given field element. +pub type ProjectivePoint<Fe> = (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<Fe>( + (ax, ay, az): ProjectivePoint<Fe>, + (bx, by, bz): ProjectivePoint<Fe>, + curve_equation_b: Fe, +) -> ProjectivePoint<Fe> +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<Fe>( + (ax, ay, az): ProjectivePoint<Fe>, + (bx, by): AffinePoint<Fe>, + curve_equation_b: Fe, +) -> ProjectivePoint<Fe> +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<Fe>((x, y, z): ProjectivePoint<Fe>, curve_equation_b: Fe) -> ProjectivePoint<Fe> +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/vendor/elliptic-curve/tests/examples/pkcs8-private-key.der b/vendor/elliptic-curve/tests/examples/pkcs8-private-key.der Binary files differnew file mode 100644 index 000000000..c0de45ef2 --- /dev/null +++ b/vendor/elliptic-curve/tests/examples/pkcs8-private-key.der diff --git a/vendor/elliptic-curve/tests/examples/pkcs8-private-key.pem b/vendor/elliptic-curve/tests/examples/pkcs8-private-key.pem new file mode 100644 index 000000000..62f432c74 --- /dev/null +++ b/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/vendor/elliptic-curve/tests/examples/pkcs8-public-key.der b/vendor/elliptic-curve/tests/examples/pkcs8-public-key.der Binary files differnew file mode 100644 index 000000000..67c719c76 --- /dev/null +++ b/vendor/elliptic-curve/tests/examples/pkcs8-public-key.der diff --git a/vendor/elliptic-curve/tests/examples/pkcs8-public-key.pem b/vendor/elliptic-curve/tests/examples/pkcs8-public-key.pem new file mode 100644 index 000000000..ee7e5b612 --- /dev/null +++ b/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/vendor/elliptic-curve/tests/pkcs8.rs b/vendor/elliptic-curve/tests/pkcs8.rs new file mode 100644 index 000000000..cffb06802 --- /dev/null +++ b/vendor/elliptic-curve/tests/pkcs8.rs @@ -0,0 +1,55 @@ +//! 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; + +/// 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_be_bytes(&EXAMPLE_SCALAR) + .unwrap() + .to_pkcs8_der() + .unwrap() +} + +#[test] +fn decode_pkcs8_private_key_from_der() { + let secret_key = SecretKey::from_pkcs8_der(example_private_key().as_bytes()).unwrap(); + assert_eq!(secret_key.to_be_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::<PublicKey>().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/vendor/elliptic-curve/tests/secret_key.rs b/vendor/elliptic-curve/tests/secret_key.rs new file mode 100644 index 000000000..50e5a95cb --- /dev/null +++ b/vendor/elliptic-curve/tests/secret_key.rs @@ -0,0 +1,10 @@ +//! Secret key tests + +#![cfg(feature = "dev")] + +use elliptic_curve::dev::SecretKey; + +#[test] +fn undersize_secret_key() { + assert!(SecretKey::from_be_bytes(&[]).is_err()); +} |