diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
commit | 2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4 (patch) | |
tree | 033cc839730fda84ff08db877037977be94e5e3a /vendor/elliptic-curve | |
parent | Initial commit. (diff) | |
download | cargo-upstream.tar.xz cargo-upstream.zip |
Adding upstream version 0.70.1+ds1.upstream/0.70.1+ds1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/elliptic-curve')
41 files changed, 7520 insertions, 0 deletions
diff --git a/vendor/elliptic-curve/.cargo-checksum.json b/vendor/elliptic-curve/.cargo-checksum.json new file mode 100644 index 0000000..432684f --- /dev/null +++ b/vendor/elliptic-curve/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"d97ca172ae9dc9f9b779a6e3a65d308f2af74e5b8c921299075bdb4a0370e914"}
\ 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 0000000..1e5a552 --- /dev/null +++ b/vendor/elliptic-curve/CHANGELOG.md @@ -0,0 +1,797 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.13.6 (2023-10-02) +### Fixed +- Minimum supported `hkdf` version is v0.12.1 ([#1353]) +- Minimum supported `serde_json` version for `jwk` feature is v1.0.47 ([#1354]) +- Minimum supported `tap` version for `bits` feature is v1.0.1 ([#1355]) + +[#1353]: https://github.com/RustCrypto/traits/pull/1353 +[#1354]: https://github.com/RustCrypto/traits/pull/1354 +[#1355]: https://github.com/RustCrypto/traits/pull/1355 + +## 0.13.5 (2023-05-19) +### Changed +- Faster `PublicKey::from_encoded_point` ([#1310]) + +### Fixed +- `alloc`+`arithmetic` features w/o `sec1` feature ([#1301]) + +[#1301]: https://github.com/RustCrypto/traits/pull/1301 +[#1310]: https://github.com/RustCrypto/traits/pull/1310 + +## 0.13.4 (2023-04-08) +### Changed +- Bump `hex-literal` to v0.4 ([#1295]) + +### Fixed +- `NonZeroScalar::from_slice` ([#1296]) +- `ScalarPrimitive::from_slice` ([#1296]) + +[#1295]: https://github.com/RustCrypto/traits/pull/1295 +[#1296]: https://github.com/RustCrypto/traits/pull/1296 + +## 0.13.3 (2023-04-04) +### Added +- Impl `AssociatedAlgorithmIdentifier` for `SecretKey` and `PublicKey` ([#1286]) + +### Changed +- Update OSSWU code ([#1157]) +- Bump `pkcs8` to v0.10.2 ([#1291]) + +### Fixed +- `FieldBytesEncoding` provided impl ([#1287]) + +[#1157]: https://github.com/RustCrypto/traits/pull/1157 +[#1286]: https://github.com/RustCrypto/traits/pull/1286 +[#1287]: https://github.com/RustCrypto/traits/pull/1287 +[#1291]: https://github.com/RustCrypto/traits/pull/1291 + +## 0.13.2 (2023-03-08) +### Added +- Weakly activate `pkcs8?/std` ([#1263]) +- More `PublicKey` <-> SEC1 conversions ([#1272]) + +[#1263]: https://github.com/RustCrypto/traits/pull/1263 +[#1272]: https://github.com/RustCrypto/traits/pull/1272 + +## 0.13.1 (2023-03-01) +### Added +- `SecretKey::from_slice` short input support ([#1256]) + +[#1256]: https://github.com/RustCrypto/traits/pull/1256 + +## 0.13.0 (2023-02-28) +### Added +- `PublicKey::to_sec1_bytes` ([#1102]) +- Forward `std` feature to `sec1` dependency ([#1131]) +- `NonIdentity` wrapper type ([#1176]) +- Impl `serde` traits for `NonZeroScalar` ([#1178]) +- `MulByGenerator` trait ([#1198]) +- `NonZeroScalar::invert_vartime` ([#1207]) +- `BlindedScalar` type ([#1208]) +- `point::Double` trait ([#1218]) +- `FieldBytesEncoding` trait ([#1235]) +- `Invert::invert_vartime` ([#1239]) + +### Changed +- Allow bigger `c1` constant in `OsswuMapParams` ([#1024]) +- Rename `Curve::UInt` => `Curve::Uint` ([#1191]) +- Use weak feature activation ([#1192], [#1194]) +- Consolidate `CurveArithmetic` trait ([#1196]) +- Rename `SecretKey::to_pem` => `::to_sec1_pem` ([#1202]) +- Rename `ScalarCore` to `ScalarPrimitive` ([#1203]) +- Use `CryptoRngCore` trait ([#1206]) +- Refactor field element decoding/encoding ([#1220]) +- Update VOPRF identifier type ([#1175]) +- Rename `SecretKey::as_scalar_core` => `::as_scalar_primitive` ([#1228]) +- Rename `Reduce::from_bytes_reduced` => `::reduce_bytes` ([#1225], [#1229]) +- Consolidate `AffineCoordinates` trait ([#1237]) +- Allow multiple `dst`s in the `hash2curve` API ([#1238]) +- Have `serde` feature activate `pkcs8` ([#1245]) +- Dependency upgrades: + - `base16ct` ([#1254]) + - `crypto-bigint` v0.5 ([#1251]) + - `ff` and `group` v0.13 ([#1166]) + - `pem-rfc7468` v0.7 ([#1251]) + - `pkcs8` v0.10 ([#1251]) + - `sec1` v0.7 ([#1251]) + - `serdect` v0.2 ([#1251]) + +### Removed +- `impl_field_element!` macro ([#1165]) +- Direct `der` crate dependency ([#1195]) +- `AffineArithmetic`, `ProjectiveArithmetic`, `ScalarArithmetic` traits ([#1196]) +- Toplevel re-exports except for `AffinePoint`, `ProjectivePoint`, and `Scalar` ([#1223]) +- `Reduce` methods ([#1225]) +- Blanket impl for `Invert` ([#1242]) + +[#1024]: https://github.com/RustCrypto/traits/pull/1024 +[#1102]: https://github.com/RustCrypto/traits/pull/1102 +[#1131]: https://github.com/RustCrypto/traits/pull/1131 +[#1165]: https://github.com/RustCrypto/traits/pull/1165 +[#1166]: https://github.com/RustCrypto/traits/pull/1166 +[#1175]: https://github.com/RustCrypto/traits/pull/1175 +[#1176]: https://github.com/RustCrypto/traits/pull/1176 +[#1178]: https://github.com/RustCrypto/traits/pull/1178 +[#1191]: https://github.com/RustCrypto/traits/pull/1191 +[#1192]: https://github.com/RustCrypto/traits/pull/1192 +[#1194]: https://github.com/RustCrypto/traits/pull/1194 +[#1195]: https://github.com/RustCrypto/traits/pull/1195 +[#1196]: https://github.com/RustCrypto/traits/pull/1196 +[#1198]: https://github.com/RustCrypto/traits/pull/1198 +[#1202]: https://github.com/RustCrypto/traits/pull/1202 +[#1203]: https://github.com/RustCrypto/traits/pull/1203 +[#1206]: https://github.com/RustCrypto/traits/pull/1206 +[#1207]: https://github.com/RustCrypto/traits/pull/1207 +[#1208]: https://github.com/RustCrypto/traits/pull/1208 +[#1218]: https://github.com/RustCrypto/traits/pull/1218 +[#1220]: https://github.com/RustCrypto/traits/pull/1220 +[#1223]: https://github.com/RustCrypto/traits/pull/1223 +[#1225]: https://github.com/RustCrypto/traits/pull/1225 +[#1228]: https://github.com/RustCrypto/traits/pull/1228 +[#1229]: https://github.com/RustCrypto/traits/pull/1229 +[#1235]: https://github.com/RustCrypto/traits/pull/1235 +[#1237]: https://github.com/RustCrypto/traits/pull/1237 +[#1238]: https://github.com/RustCrypto/traits/pull/1238 +[#1239]: https://github.com/RustCrypto/traits/pull/1239 +[#1242]: https://github.com/RustCrypto/traits/pull/1242 +[#1245]: https://github.com/RustCrypto/traits/pull/1245 +[#1251]: https://github.com/RustCrypto/traits/pull/1251 +[#1254]: https://github.com/RustCrypto/traits/pull/1254 + +## 0.12.3 (2022-08-01) +### Added +- Aliases for SEC1 compressed/uncompressed points ([#1067]) + +### Fixed +- `arithmetic` + `serde` feature combo ([#1066]) + +[#1066]: https://github.com/RustCrypto/traits/pull/1066 +[#1067]: https://github.com/RustCrypto/traits/pull/1067 + +## 0.12.2 (2022-07-01) +### Changed +- Bump `crypto-bigint` to v0.4.8 ([#1039]) + +[#1039]: https://github.com/RustCrypto/traits/pull/1039 + +## 0.12.1 (2022-06-12) +### Added +- `impl_field_element!` macro ([#1021]) +- Generic impl of complete prime order formulas ([#1022]) + +### Changed +- Bump `crypto-bigint` to v0.4.4 ([#1018], [#1020]) + +[#1018]: https://github.com/RustCrypto/traits/pull/1018 +[#1020]: https://github.com/RustCrypto/traits/pull/1020 +[#1021]: https://github.com/RustCrypto/traits/pull/1021 +[#1022]: https://github.com/RustCrypto/traits/pull/1022 + +## 0.12.0 (2022-05-08) +### Added +- `ecdh::SharedSecret::extract` HKDF helper ([#1007]) + +### Changed +- Bump `digest` dependency to v0.10 ([#883], [#904]) +- Make `NonZeroScalar::invert` infallible ([#894]) +- `ToCompactEncodedPoint` now returns `CtOption` ([#895]) +- Move `hash2field` into `hash2curve` module ([#903]) +- Bump `ff` and `group` dependencies to v0.12 ([#994]) +- Use `serdect` crate ([#996]) +- Replace `AlgorithmParamters` with `AssociatedOid` ([#1001]) +- Bump `crypto-bigint` dependency to v0.4 ([#1005]) +- Bump `der` dependency to v0.6 ([#1006]) +- Bump `pkcs8` dependency to v0.9 ([#1006]) +- Bump `sec1` dependency to v0.3 ([#1006]) +- Bump `pem-rfc7468` dependency to v0.6 ([#1009]) + +### Removed +- `Zeroize` impl from `ecdh::SharedSecret` ([#978]) + +[#883]: https://github.com/RustCrypto/traits/pull/883 +[#894]: https://github.com/RustCrypto/traits/pull/894 +[#895]: https://github.com/RustCrypto/traits/pull/895 +[#903]: https://github.com/RustCrypto/traits/pull/903 +[#904]: https://github.com/RustCrypto/traits/pull/904 +[#978]: https://github.com/RustCrypto/traits/pull/978 +[#994]: https://github.com/RustCrypto/traits/pull/994 +[#996]: https://github.com/RustCrypto/traits/pull/996 +[#1001]: https://github.com/RustCrypto/traits/pull/1001 +[#1005]: https://github.com/RustCrypto/traits/pull/1005 +[#1006]: https://github.com/RustCrypto/traits/pull/1006 +[#1007]: https://github.com/RustCrypto/traits/pull/1007 +[#1009]: https://github.com/RustCrypto/traits/pull/1009 + +## 0.11.12 (2022-01-30) +### Changed +- Disable `bits` feature on docs.rs due to nightly breakage ([#927]) + +[#927]: https://github.com/RustCrypto/traits/pull/927 + +## 0.11.11 (2022-01-30) +- No changes; triggering a docs.rs rebuild + +## 0.11.10 (2022-01-27) +### Changed +- Revert [#884] to support a wider range of `zeroize` versions ([#923]) + +[#923]: https://github.com/RustCrypto/traits/pull/891 + +## 0.11.9 (2022-01-17) [YANKED] +### Changed +- Activate `bits`, `hash2curve`, and `voprf` features on docs.rs ([#891]) + +[#891]: https://github.com/RustCrypto/traits/pull/891 + +## 0.11.8 (2022-01-15) [YANKED] +### Added +- Impl `ZeroizeOnDrop` on appropriate items ([#884]) + +### Changed +- Use the `base16ct` crate for hex serialization ([#886], [#887], [#888]) + +[#884]: https://github.com/RustCrypto/traits/pull/884 +[#886]: https://github.com/RustCrypto/traits/pull/886 +[#887]: https://github.com/RustCrypto/traits/pull/887 +[#888]: https://github.com/RustCrypto/traits/pull/888 + +## 0.11.7 (2022-01-14) [YANKED] +### Added +- Initial hash-to-field support ([#854], [#855], [#871], [#874]) +- Initial hash-to-curve support ([#865], [#876]) +- Impl `Mul` for `NonZeroScalar` * `NonZeroScalar` ([#857], [#862]) +- `Reduce::from_*e_digest_reduced` ([#869]) +- `VoprfParameters` trait ([#878]) + +[#854]: https://github.com/RustCrypto/traits/pull/854 +[#855]: https://github.com/RustCrypto/traits/pull/855 +[#857]: https://github.com/RustCrypto/traits/pull/857 +[#862]: https://github.com/RustCrypto/traits/pull/862 +[#865]: https://github.com/RustCrypto/traits/pull/865 +[#869]: https://github.com/RustCrypto/traits/pull/869 +[#871]: https://github.com/RustCrypto/traits/pull/871 +[#874]: https://github.com/RustCrypto/traits/pull/874 +[#876]: https://github.com/RustCrypto/traits/pull/876 +[#878]: https://github.com/RustCrypto/traits/pull/878 + +## 0.11.6 (2021-12-20) +### Added +- Type conversions chart ([#852]) + +[#852]: https://github.com/RustCrypto/traits/pull/852 + +## 0.11.5 (2021-12-05) +### Changed +- Revised `LinearCombination` trait ([#835]) + +[#835]: https://github.com/RustCrypto/traits/pull/835 + +## 0.11.4 (2021-12-04) [YANKED] +### Added +- `LinearCombination` trait ([#832]) + +[#832]: https://github.com/RustCrypto/traits/pull/832 + +## 0.11.3 (2021-12-03) [YANKED] +### Added +- `ReduceNonZero` trait ([#827]) + +[#827]: https://github.com/RustCrypto/traits/pull/827 + +## 0.11.2 (2021-12-03) [YANKED] +### Changed +- Bump `pem-rfc7468` dependency to v0.3 ([#825]) + +[#825]: https://github.com/RustCrypto/traits/pull/825 + +## 0.11.1 (2021-11-21) [YANKED] +### Added +- `NonZeroScalar::from_uint` ([#822]) + +[#822]: https://github.com/RustCrypto/traits/pull/822 + +## 0.11.0 (2021-11-19) [YANKED] +### Added +- `ScalarCore<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 0000000..3ce6bb7 --- /dev/null +++ b/vendor/elliptic-curve/Cargo.toml @@ -0,0 +1,220 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.65" +name = "elliptic-curve" +version = "0.13.6" +authors = ["RustCrypto Developers"] +description = """ +General purpose Elliptic Curve Cryptography (ECC) support, including types +and traits for representing various elliptic curve forms, scalars, points, +and public/secret keys composed thereof. +""" +readme = "README.md" +keywords = [ + "crypto", + "ecc", + "elliptic", + "weierstrass", +] +categories = [ + "cryptography", + "no-std", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/RustCrypto/traits/tree/master/elliptic-curve" + +[package.metadata.docs.rs] +features = [ + "bits", + "ecdh", + "hash2curve", + "jwk", + "pem", + "std", + "voprf", +] +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.base16ct] +version = "0.2" + +[dependencies.base64ct] +version = "1" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.crypto-bigint] +version = "0.5" +features = [ + "rand_core", + "generic-array", + "zeroize", +] +default-features = false + +[dependencies.digest] +version = "0.10" +optional = true + +[dependencies.ff] +version = "0.13" +optional = true +default-features = false + +[dependencies.generic-array] +version = "0.14.6" +features = ["zeroize"] +default-features = false + +[dependencies.group] +version = "0.13" +optional = true +default-features = false + +[dependencies.hex-literal] +version = "0.4" +optional = true + +[dependencies.hkdf] +version = "0.12.1" +optional = true +default-features = false + +[dependencies.pem-rfc7468] +version = "0.7" +features = ["alloc"] +optional = true + +[dependencies.pkcs8] +version = "0.10.2" +optional = true +default-features = false + +[dependencies.rand_core] +version = "0.6.4" +default-features = false + +[dependencies.sec1] +version = "0.7.1" +features = [ + "subtle", + "zeroize", +] +optional = true + +[dependencies.serde_json] +version = "1.0.47" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.serdect] +version = "0.2" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.subtle] +version = "2" +default-features = false + +[dependencies.tap] +version = "1.0.1" +optional = true +default-features = false + +[dependencies.zeroize] +version = "1.5" +default-features = false + +[dev-dependencies.hex-literal] +version = "0.4" + +[dev-dependencies.sha2] +version = "0.10" + +[dev-dependencies.sha3] +version = "0.10" + +[features] +alloc = [ + "base16ct/alloc", + "ff?/alloc", + "group?/alloc", + "pkcs8?/alloc", + "sec1?/alloc", + "zeroize/alloc", +] +arithmetic = ["group"] +bits = [ + "arithmetic", + "ff/bits", + "dep:tap", +] +default = ["arithmetic"] +dev = [ + "arithmetic", + "dep:hex-literal", + "pem", + "pkcs8", +] +ecdh = [ + "arithmetic", + "digest", + "dep:hkdf", +] +group = [ + "dep:group", + "ff", +] +hash2curve = [ + "arithmetic", + "digest", +] +hazmat = [] +jwk = [ + "dep:base64ct", + "dep:serde_json", + "alloc", + "serde", + "zeroize/alloc", +] +pem = [ + "dep:pem-rfc7468", + "alloc", + "arithmetic", + "pkcs8", + "sec1/pem", +] +pkcs8 = [ + "dep:pkcs8", + "sec1", +] +serde = [ + "dep:serdect", + "alloc", + "pkcs8", + "sec1/serde", +] +std = [ + "alloc", + "rand_core/std", + "pkcs8?/std", + "sec1?/std", +] +voprf = ["digest"] diff --git a/vendor/elliptic-curve/LICENSE-APACHE b/vendor/elliptic-curve/LICENSE-APACHE new file mode 100644 index 0000000..78173fa --- /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 0000000..d4ce065 --- /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 0000000..37163a7 --- /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.65** or higher. + +Minimum supported Rust version can be changed in the future, but it will be +done with a minor version bump. + +## SemVer Policy + +- All on-by-default features of this library are covered by SemVer +- MSRV is considered exempt from SemVer as noted above + +## License + +All crates licensed under either of + + * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + * [MIT license](http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +[//]: # (badges) + +[crate-image]: https://buildstats.info/crate/elliptic-curve +[crate-link]: https://crates.io/crates/elliptic-curve +[docs-image]: https://docs.rs/elliptic-curve/badge.svg +[docs-link]: https://docs.rs/elliptic-curve/ +[build-image]: https://github.com/RustCrypto/traits/actions/workflows/elliptic-curve.yml/badge.svg +[build-link]: https://github.com/RustCrypto/traits/actions/workflows/elliptic-curve.yml +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260040-elliptic-curves diff --git a/vendor/elliptic-curve/src/arithmetic.rs b/vendor/elliptic-curve/src/arithmetic.rs new file mode 100644 index 0000000..7ef7fc5 --- /dev/null +++ b/vendor/elliptic-curve/src/arithmetic.rs @@ -0,0 +1,86 @@ +//! Elliptic curve arithmetic traits. + +use crate::{ + ops::{Invert, LinearCombination, MulByGenerator, Reduce, ShrAssign}, + point::AffineCoordinates, + scalar::{FromUintUnchecked, IsHigh}, + Curve, FieldBytes, PrimeCurve, ScalarPrimitive, +}; +use core::fmt::Debug; +use subtle::{ConditionallySelectable, ConstantTimeEq, CtOption}; +use zeroize::DefaultIsZeroes; + +/// Elliptic curve with an arithmetic implementation. +pub trait CurveArithmetic: Curve { + /// Elliptic curve point in affine coordinates. + type AffinePoint: 'static + + AffineCoordinates<FieldRepr = FieldBytes<Self>> + + Copy + + ConditionallySelectable + + ConstantTimeEq + + Debug + + Default + + DefaultIsZeroes + + Eq + + PartialEq + + Sized + + Send + + Sync; + + /// Elliptic curve point in projective coordinates. + /// + /// Note: the following bounds are provided by [`group::Group`]: + /// - `'static` + /// - [`Copy`] + /// - [`Clone`] + /// - [`Debug`] + /// - [`Eq`] + /// - [`Sized`] + /// - [`Send`] + /// - [`Sync`] + type ProjectivePoint: ConditionallySelectable + + ConstantTimeEq + + Default + + DefaultIsZeroes + + From<Self::AffinePoint> + + Into<Self::AffinePoint> + + LinearCombination + + MulByGenerator + + group::Curve<AffineRepr = Self::AffinePoint> + + group::Group<Scalar = Self::Scalar>; + + /// Scalar field modulo this curve's order. + /// + /// Note: the following bounds are provided by [`ff::Field`]: + /// - `'static` + /// - [`Copy`] + /// - [`Clone`] + /// - [`ConditionallySelectable`] + /// - [`ConstantTimeEq`] + /// - [`Debug`] + /// - [`Default`] + /// - [`Send`] + /// - [`Sync`] + type Scalar: AsRef<Self::Scalar> + + DefaultIsZeroes + + From<ScalarPrimitive<Self>> + + FromUintUnchecked<Uint = Self::Uint> + + Into<FieldBytes<Self>> + + Into<ScalarPrimitive<Self>> + + Into<Self::Uint> + + Invert<Output = CtOption<Self::Scalar>> + + IsHigh + + PartialOrd + + Reduce<Self::Uint, Bytes = FieldBytes<Self>> + + ShrAssign<usize> + + ff::Field + + ff::PrimeField<Repr = FieldBytes<Self>>; +} + +/// Prime order elliptic curve with projective arithmetic implementation. +pub trait PrimeCurveArithmetic: + PrimeCurve + CurveArithmetic<ProjectivePoint = Self::CurveGroup> +{ + /// Prime order elliptic curve group. + type CurveGroup: group::prime::PrimeCurve<Affine = <Self as CurveArithmetic>::AffinePoint>; +} diff --git a/vendor/elliptic-curve/src/dev.rs b/vendor/elliptic-curve/src/dev.rs new file mode 100644 index 0000000..36c684a --- /dev/null +++ b/vendor/elliptic-curve/src/dev.rs @@ -0,0 +1,844 @@ +//! Development-related functionality. +//! +//! Helpers and types for writing tests against concrete implementations of +//! the traits in this crate. + +use crate::{ + bigint::{Limb, U256}, + error::{Error, Result}, + generic_array::typenum::U32, + ops::{Invert, LinearCombination, MulByGenerator, Reduce, ShrAssign}, + pkcs8, + point::AffineCoordinates, + rand_core::RngCore, + scalar::{FromUintUnchecked, IsHigh}, + sec1::{CompressedPoint, FromEncodedPoint, ToEncodedPoint}, + subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, + zeroize::DefaultIsZeroes, + Curve, CurveArithmetic, FieldBytesEncoding, PrimeCurve, +}; +use core::{ + iter::{Product, Sum}, + ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, +}; +use ff::{Field, PrimeField}; +use hex_literal::hex; +use pkcs8::AssociatedOid; + +#[cfg(feature = "bits")] +use ff::PrimeFieldBits; + +#[cfg(feature = "jwk")] +use crate::JwkParameters; + +/// Pseudo-coordinate for fixed-based scalar mult output +pub const PSEUDO_COORDINATE_FIXED_BASE_MUL: [u8; 32] = + hex!("deadbeef00000000000000000000000000000000000000000000000000000001"); + +/// SEC1 encoded point. +pub type EncodedPoint = crate::sec1::EncodedPoint<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 primitive type. +// TODO(tarcieri): make this the scalar type when it's more capable +pub type ScalarPrimitive = crate::ScalarPrimitive<MockCurve>; + +/// Scalar bits. +#[cfg(feature = "bits")] +pub type ScalarBits = crate::scalar::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 FieldBytesSize = U32; + type Uint = U256; + + const ORDER: U256 = + U256::from_be_hex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"); +} + +impl PrimeCurve for MockCurve {} + +impl CurveArithmetic for MockCurve { + type AffinePoint = AffinePoint; + type ProjectivePoint = ProjectivePoint; + type Scalar = Scalar; +} + +impl AssociatedOid for MockCurve { + /// OID for NIST P-256 + const OID: pkcs8::ObjectIdentifier = pkcs8::ObjectIdentifier::new_unwrap("1.2.840.10045.3.1.7"); +} + +#[cfg(feature = "jwk")] +impl JwkParameters for MockCurve { + const CRV: &'static str = "P-256"; +} + +/// Example scalar type +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] +pub struct Scalar(ScalarPrimitive); + +impl Field for Scalar { + const ZERO: Self = Self(ScalarPrimitive::ZERO); + const ONE: Self = Self(ScalarPrimitive::ONE); + + fn random(mut rng: impl RngCore) -> Self { + let mut bytes = FieldBytes::default(); + + loop { + rng.fill_bytes(&mut bytes); + if let Some(scalar) = Self::from_repr(bytes).into() { + return scalar; + } + } + } + + fn is_zero(&self) -> Choice { + self.0.is_zero() + } + + #[must_use] + fn square(&self) -> Self { + unimplemented!(); + } + + #[must_use] + fn double(&self) -> Self { + self.add(self) + } + + fn invert(&self) -> CtOption<Self> { + unimplemented!(); + } + + fn sqrt(&self) -> CtOption<Self> { + unimplemented!(); + } + + fn sqrt_ratio(_num: &Self, _div: &Self) -> (Choice, Self) { + unimplemented!(); + } +} + +impl PrimeField for Scalar { + type Repr = FieldBytes; + + const MODULUS: &'static str = + "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"; + const NUM_BITS: u32 = 256; + const CAPACITY: u32 = 255; + const TWO_INV: Self = Self::ZERO; // BOGUS! + const MULTIPLICATIVE_GENERATOR: Self = Self::ZERO; // BOGUS! Should be 7 + const S: u32 = 4; + const ROOT_OF_UNITY: Self = Self::ZERO; // BOGUS! Should be 0xffc97f062a770992ba807ace842a3dfc1546cad004378daf0592d7fbb41e6602 + const ROOT_OF_UNITY_INV: Self = Self::ZERO; // BOGUS! + const DELTA: Self = Self::ZERO; // BOGUS! + + fn from_repr(bytes: FieldBytes) -> CtOption<Self> { + ScalarPrimitive::from_bytes(&bytes).map(Self) + } + + fn to_repr(&self) -> FieldBytes { + self.0.to_bytes() + } + + fn is_odd(&self) -> Choice { + self.0.is_odd() + } +} + +#[cfg(feature = "bits")] +impl PrimeFieldBits for Scalar { + #[cfg(target_pointer_width = "32")] + type ReprBits = [u32; 8]; + + #[cfg(target_pointer_width = "64")] + type ReprBits = [u64; 4]; + + fn to_le_bits(&self) -> ScalarBits { + self.0.as_uint().to_words().into() + } + + fn char_le_bits() -> ScalarBits { + MockCurve::ORDER.to_words().into() + } +} + +impl AsRef<Scalar> for Scalar { + fn as_ref(&self) -> &Scalar { + self + } +} + +impl ConditionallySelectable for Scalar { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self(ScalarPrimitive::conditional_select(&a.0, &b.0, choice)) + } +} + +impl ConstantTimeEq for Scalar { + fn ct_eq(&self, other: &Self) -> Choice { + self.0.ct_eq(&other.0) + } +} + +impl DefaultIsZeroes for Scalar {} + +impl Add<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 ShrAssign<usize> for Scalar { + fn shr_assign(&mut self, rhs: usize) { + self.0 >>= rhs; + } +} + +impl Sum for Scalar { + fn sum<I: Iterator<Item = Self>>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl<'a> Sum<&'a Scalar> for Scalar { + fn sum<I: Iterator<Item = &'a Scalar>>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl Product for Scalar { + fn product<I: Iterator<Item = Self>>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl<'a> Product<&'a Scalar> for Scalar { + fn product<I: Iterator<Item = &'a Scalar>>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl Invert for Scalar { + type Output = CtOption<Scalar>; + + fn invert(&self) -> CtOption<Scalar> { + unimplemented!(); + } +} + +impl Reduce<U256> for Scalar { + type Bytes = FieldBytes; + + #[allow(clippy::integer_arithmetic)] + fn reduce(w: U256) -> Self { + let (r, underflow) = w.sbb(&MockCurve::ORDER, Limb::ZERO); + let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8); + let reduced = U256::conditional_select(&w, &r, !underflow); + Self(ScalarPrimitive::new(reduced).unwrap()) + } + + fn reduce_bytes(_: &FieldBytes) -> Self { + todo!() + } +} + +impl FieldBytesEncoding<MockCurve> for U256 {} + +impl From<u64> for Scalar { + fn from(n: u64) -> Scalar { + Self(n.into()) + } +} + +impl From<ScalarPrimitive> for Scalar { + fn from(scalar: ScalarPrimitive) -> Scalar { + Self(scalar) + } +} + +impl From<Scalar> for ScalarPrimitive { + fn from(scalar: Scalar) -> ScalarPrimitive { + scalar.0 + } +} + +impl From<Scalar> for U256 { + fn from(scalar: Scalar) -> U256 { + scalar.0.to_uint() + } +} + +impl TryFrom<U256> for Scalar { + type Error = Error; + + fn try_from(w: U256) -> Result<Self> { + Option::from(ScalarPrimitive::new(w)).map(Self).ok_or(Error) + } +} + +impl FromUintUnchecked for Scalar { + type Uint = U256; + + fn from_uint_unchecked(uint: U256) -> Self { + Self(ScalarPrimitive::from_uint_unchecked(uint)) + } +} + +impl From<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 AffineCoordinates for AffinePoint { + type FieldRepr = FieldBytes; + + fn x(&self) -> FieldBytes { + unimplemented!(); + } + + fn y_is_odd(&self) -> Choice { + unimplemented!(); + } +} + +impl ConstantTimeEq for AffinePoint { + fn ct_eq(&self, other: &Self) -> Choice { + match (self, other) { + (Self::FixedBaseOutput(scalar), Self::FixedBaseOutput(other_scalar)) => { + scalar.ct_eq(other_scalar) + } + (Self::Identity, Self::Identity) | (Self::Generator, Self::Generator) => 1.into(), + (Self::Other(point), Self::Other(other_point)) => u8::from(point == other_point).into(), + _ => 0.into(), + } + } +} + +impl ConditionallySelectable for AffinePoint { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + // Not really constant time, but this is dev code + if choice.into() { + *b + } else { + *a + } + } +} + +impl Default for AffinePoint { + fn default() -> Self { + Self::Identity + } +} + +impl DefaultIsZeroes for AffinePoint {} + +impl FromEncodedPoint<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 { + match (self, other) { + (Self::FixedBaseOutput(scalar), Self::FixedBaseOutput(other_scalar)) => { + scalar.ct_eq(other_scalar) + } + (Self::Identity, Self::Identity) | (Self::Generator, Self::Generator) => 1.into(), + (Self::Other(point), Self::Other(other_point)) => point.ct_eq(other_point), + _ => 0.into(), + } + } +} + +impl ConditionallySelectable for ProjectivePoint { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + if choice.into() { + *b + } else { + *a + } + } +} + +impl Default for ProjectivePoint { + fn default() -> Self { + Self::Identity + } +} + +impl DefaultIsZeroes for ProjectivePoint {} + +impl From<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(u8::from(self == &Self::Identity)) + } + + #[must_use] + fn double(&self) -> Self { + unimplemented!(); + } +} + +impl group::GroupEncoding for AffinePoint { + type Repr = CompressedPoint<MockCurve>; + + fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> { + EncodedPoint::from_bytes(bytes) + .map(|point| CtOption::new(point, Choice::from(1))) + .unwrap_or_else(|_| { + let is_identity = bytes.ct_eq(&Self::Repr::default()); + CtOption::new(EncodedPoint::identity(), is_identity) + }) + .and_then(|point| Self::from_encoded_point(&point)) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> { + Self::from_bytes(bytes) + } + + fn to_bytes(&self) -> Self::Repr { + let encoded = self.to_encoded_point(true); + let mut result = CompressedPoint::<MockCurve>::default(); + result[..encoded.len()].copy_from_slice(encoded.as_bytes()); + result + } +} + +impl group::GroupEncoding for ProjectivePoint { + type Repr = CompressedPoint<MockCurve>; + + fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> { + <AffinePoint as group::GroupEncoding>::from_bytes(bytes).map(Into::into) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> { + Self::from_bytes(bytes) + } + + fn to_bytes(&self) -> Self::Repr { + group::Curve::to_affine(self).to_bytes() + } +} + +impl group::Curve for ProjectivePoint { + type AffineRepr = AffinePoint; + + fn to_affine(&self) -> AffinePoint { + match self { + Self::FixedBaseOutput(scalar) => AffinePoint::FixedBaseOutput(*scalar), + Self::Other(affine) => *affine, + _ => unimplemented!(), + } + } +} + +impl LinearCombination for ProjectivePoint {} + +impl Add<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 MulByGenerator for ProjectivePoint {} + +impl Neg for ProjectivePoint { + type Output = ProjectivePoint; + + fn neg(self) -> ProjectivePoint { + unimplemented!(); + } +} + +#[cfg(test)] +mod tests { + use super::Scalar; + use ff::PrimeField; + use hex_literal::hex; + + #[test] + fn round_trip() { + let bytes = hex!("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); + let scalar = Scalar::from_repr(bytes.into()).unwrap(); + assert_eq!(&bytes, scalar.to_repr().as_slice()); + } +} diff --git a/vendor/elliptic-curve/src/ecdh.rs b/vendor/elliptic-curve/src/ecdh.rs new file mode 100644 index 0000000..c64a696 --- /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 [`CurveArithmetic`] trait (presently +//! the `k256` and `p256` crates) +//! +//! # ECDH Ephemeral (ECDHE) Usage +//! +//! Ephemeral Diffie-Hellman provides a one-time key exchange between two peers +//! using a randomly generated set of keys for each exchange. +//! +//! In practice ECDHE is used as part of an [Authenticated Key Exchange (AKE)][AKE] +//! protocol (e.g. [SIGMA]), where an existing cryptographic trust relationship +//! can be used to determine the authenticity of the ephemeral keys, such as +//! a digital signature. Without such an additional step, ECDHE is insecure! +//! (see security warning below) +//! +//! See the documentation for the [`EphemeralSecret`] type for more information +//! on performing ECDH ephemeral key exchanges. +//! +//! # Static ECDH Usage +//! +//! Static ECDH key exchanges are supported via the low-level +//! [`diffie_hellman`] function. +//! +//! [AKE]: https://en.wikipedia.org/wiki/Authenticated_Key_Exchange +//! [SIGMA]: https://webee.technion.ac.il/~hugo/sigma-pdf.pdf + +use crate::{ + point::AffineCoordinates, AffinePoint, Curve, CurveArithmetic, FieldBytes, NonZeroScalar, + ProjectivePoint, PublicKey, +}; +use core::borrow::Borrow; +use digest::{crypto_common::BlockSizeUser, Digest}; +use group::Curve as _; +use hkdf::{hmac::SimpleHmac, Hkdf}; +use rand_core::CryptoRngCore; +use zeroize::{Zeroize, ZeroizeOnDrop}; + +/// Low-level Elliptic Curve Diffie-Hellman (ECDH) function. +/// +/// Whenever possible, we recommend using the high-level ECDH ephemeral API +/// provided by [`EphemeralSecret`]. +/// +/// However, if you are implementing a protocol which requires a static scalar +/// value as part of an ECDH exchange, this API can be used to compute a +/// [`SharedSecret`] from that value. +/// +/// Note that this API operates on the low-level [`NonZeroScalar`] and +/// [`AffinePoint`] types. If you are attempting to use the higher-level +/// [`SecretKey`][`crate::SecretKey`] and [`PublicKey`] types, you will +/// need to use the following conversions: +/// +/// ```ignore +/// let shared_secret = elliptic_curve::ecdh::diffie_hellman( +/// secret_key.to_nonzero_scalar(), +/// public_key.as_affine() +/// ); +/// ``` +pub fn diffie_hellman<C>( + secret_key: impl Borrow<NonZeroScalar<C>>, + public_key: impl Borrow<AffinePoint<C>>, +) -> SharedSecret<C> +where + C: CurveArithmetic, +{ + 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: CurveArithmetic, +{ + scalar: NonZeroScalar<C>, +} + +impl<C> EphemeralSecret<C> +where + C: CurveArithmetic, +{ + /// Generate a cryptographically random [`EphemeralSecret`]. + pub fn random(rng: &mut impl CryptoRngCore) -> Self { + Self { + scalar: NonZeroScalar::random(rng), + } + } + + /// Get the public key associated with this ephemeral secret. + /// + /// The `compress` flag enables point compression. + pub fn public_key(&self) -> PublicKey<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: CurveArithmetic, +{ + fn from(ephemeral_secret: &EphemeralSecret<C>) -> Self { + ephemeral_secret.public_key() + } +} + +impl<C> Zeroize for EphemeralSecret<C> +where + C: CurveArithmetic, +{ + fn zeroize(&mut self) { + self.scalar.zeroize() + } +} + +impl<C> ZeroizeOnDrop for EphemeralSecret<C> where C: CurveArithmetic {} + +impl<C> Drop for EphemeralSecret<C> +where + C: CurveArithmetic, +{ + 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: CurveArithmetic, + { + Self { + secret_bytes: point.x(), + } + } + + /// Use [HKDF] (HMAC-based Extract-and-Expand Key Derivation Function) to + /// extract entropy from this shared secret. + /// + /// This method can be used to transform the shared secret into uniformly + /// random values which are suitable as key material. + /// + /// The `D` type parameter is a cryptographic digest function. + /// `sha2::Sha256` is a common choice for use with HKDF. + /// + /// The `salt` parameter can be used to supply additional randomness. + /// Some examples include: + /// + /// - randomly generated (but authenticated) string + /// - fixed application-specific value + /// - previous shared secret used for rekeying (as in TLS 1.3 and Noise) + /// + /// After initializing HKDF, use [`Hkdf::expand`] to obtain output key + /// material. + /// + /// [HKDF]: https://en.wikipedia.org/wiki/HKDF + pub fn extract<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 0000000..53f5b17 --- /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/field.rs b/vendor/elliptic-curve/src/field.rs new file mode 100644 index 0000000..66055ab --- /dev/null +++ b/vendor/elliptic-curve/src/field.rs @@ -0,0 +1,51 @@ +//! Field elements. + +use crate::{ + bigint::{ArrayEncoding, ByteArray, Integer}, + Curve, +}; +use generic_array::{typenum::Unsigned, GenericArray}; + +/// Size of serialized field elements of this elliptic curve. +pub type FieldBytesSize<C> = <C as Curve>::FieldBytesSize; + +/// Byte representation of a base/scalar field element of a given curve. +pub type FieldBytes<C> = GenericArray<u8, FieldBytesSize<C>>; + +/// Trait for decoding/encoding `Curve::Uint` from/to [`FieldBytes`] using +/// curve-specific rules. +/// +/// Namely a curve's modulus may be smaller than the big integer type used to +/// internally represent field elements (since the latter are multiples of the +/// limb size), such as in the case of curves like NIST P-224 and P-521, and so +/// it may need to be padded/truncated to the right length. +/// +/// Additionally, different curves have different endianness conventions, also +/// captured here. +pub trait FieldBytesEncoding<C>: ArrayEncoding + Integer +where + C: Curve, +{ + /// Decode unsigned integer from serialized field element. + /// + /// The default implementation assumes a big endian encoding. + fn decode_field_bytes(field_bytes: &FieldBytes<C>) -> Self { + debug_assert!(field_bytes.len() <= Self::ByteSize::USIZE); + let mut byte_array = ByteArray::<Self>::default(); + let offset = Self::ByteSize::USIZE.saturating_sub(field_bytes.len()); + byte_array[offset..].copy_from_slice(field_bytes); + Self::from_be_byte_array(byte_array) + } + + /// Encode unsigned integer into serialized field element. + /// + /// The default implementation assumes a big endian encoding. + fn encode_field_bytes(&self) -> FieldBytes<C> { + let mut field_bytes = FieldBytes::<C>::default(); + debug_assert!(field_bytes.len() <= Self::ByteSize::USIZE); + + let offset = Self::ByteSize::USIZE.saturating_sub(field_bytes.len()); + field_bytes.copy_from_slice(&self.to_be_byte_array()[offset..]); + field_bytes + } +} diff --git a/vendor/elliptic-curve/src/hash2curve.rs b/vendor/elliptic-curve/src/hash2curve.rs new file mode 100644 index 0000000..3df394f --- /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 0000000..ea7f047 --- /dev/null +++ b/vendor/elliptic-curve/src/hash2curve/group_digest.rs @@ -0,0 +1,123 @@ +//! Traits for handling hash to curve. + +use super::{hash_to_field, ExpandMsg, FromOkm, MapToCurve}; +use crate::{CurveArithmetic, ProjectivePoint, Result}; +use group::cofactor::CofactorGroup; + +/// Adds hashing arbitrary byte sequences to a valid group element +pub trait GroupDigest: CurveArithmetic +where + ProjectivePoint<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]], + dsts: &'a [&'a [u8]], + ) -> Result<ProjectivePoint<Self>> { + let mut u = [Self::FieldElement::default(), Self::FieldElement::default()]; + hash_to_field::<X, _>(msgs, dsts, &mut u)?; + let q0 = u[0].map_to_curve(); + let q1 = u[1].map_to_curve(); + // Ideally we could add and then clear cofactor once + // thus saving a call but the field elements may not + // add properly due to the underlying implementation + // which could result in an incorrect subgroup. + // This is caused curve coefficients being different than + // what is usually implemented. + // FieldElement expects the `a` and `b` to be the original values + // isogenies are different with curves like k256 and bls12-381. + // This problem doesn't manifest for curves with no isogeny like p256. + // For k256 and p256 clear_cofactor doesn't do anything anyway so it will be a no-op. + Ok(q0.clear_cofactor().into() + q1.clear_cofactor()) + } + + /// Computes the encode to curve routine. + /// + /// From <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]], + dsts: &'a [&'a [u8]], + ) -> Result<ProjectivePoint<Self>> { + let mut u = [Self::FieldElement::default()]; + hash_to_field::<X, _>(msgs, dsts, &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]], + dsts: &'a [&'a [u8]], + ) -> Result<Self::Scalar> + where + Self::Scalar: FromOkm, + { + let mut u = [Self::Scalar::default()]; + hash_to_field::<X, _>(msgs, dsts, &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 0000000..67ede11 --- /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::{Error, Result}; +use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; + +/// The trait for helping to convert to a field element. +pub trait FromOkm { + /// The number of bytes needed to convert to a field element. + type Length: ArrayLength<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 [&'a [u8]], out: &mut [T]) -> Result<()> +where + E: ExpandMsg<'a>, + T: FromOkm + Default, +{ + let len_in_bytes = T::Length::to_usize().checked_mul(out.len()).ok_or(Error)?; + let mut tmp = GenericArray::<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 0000000..96a659b --- /dev/null +++ b/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg.rs @@ -0,0 +1,145 @@ +//! `expand_message` interface `for hash_to_field`. + +pub(super) mod xmd; +pub(super) mod xof; + +use crate::{Error, Result}; +use digest::{Digest, ExtendableOutput, Update, XofReader}; +use generic_array::typenum::{IsLess, U256}; +use generic_array::{ArrayLength, GenericArray}; + +/// Salt when the DST is too long +const OVERSIZE_DST_SALT: &[u8] = b"H2C-OVERSIZE-DST-"; +/// Maximum domain separation tag length +const MAX_DST_LEN: usize = 255; + +/// Trait for types implementing expand_message interface for `hash_to_field`. +/// +/// # Errors +/// See implementors of [`ExpandMsg`] for errors. +pub trait ExpandMsg<'a> { + /// Type holding data for the [`Expander`]. + type Expander: Expander + Sized; + + /// Expands `msg` to the required number of bytes. + /// + /// Returns an expander that can be used to call `read` until enough + /// bytes have been consumed + fn expand_message( + msgs: &[&[u8]], + dsts: &'a [&'a [u8]], + len_in_bytes: usize, + ) -> Result<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 [&'a [u8]]), +} + +impl<'a, L> Domain<'a, L> +where + L: ArrayLength<u8> + IsLess<U256>, +{ + pub fn xof<X>(dsts: &'a [&'a [u8]]) -> Result<Self> + where + X: Default + ExtendableOutput + Update, + { + if dsts.is_empty() { + Err(Error) + } else if dsts.iter().map(|dst| dst.len()).sum::<usize>() > MAX_DST_LEN { + let mut data = GenericArray::<u8, L>::default(); + let mut hash = X::default(); + hash.update(OVERSIZE_DST_SALT); + + for dst in dsts { + hash.update(dst); + } + + hash.finalize_xof().read(&mut data); + + Ok(Self::Hashed(data)) + } else { + Ok(Self::Array(dsts)) + } + } + + pub fn xmd<X>(dsts: &'a [&'a [u8]]) -> Result<Self> + where + X: Digest<OutputSize = L>, + { + if dsts.is_empty() { + Err(Error) + } else if dsts.iter().map(|dst| dst.len()).sum::<usize>() > MAX_DST_LEN { + Ok(Self::Hashed({ + let mut hash = X::new(); + hash.update(OVERSIZE_DST_SALT); + + for dst in dsts { + hash.update(dst); + } + + hash.finalize() + })) + } else { + Ok(Self::Array(dsts)) + } + } + + pub fn update_hash<HashT: Update>(&self, hash: &mut HashT) { + match self { + Self::Hashed(d) => hash.update(d), + Self::Array(d) => { + for d in d.iter() { + hash.update(d) + } + } + } + } + + pub fn len(&self) -> u8 { + match self { + // Can't overflow because it's enforced on a type level. + Self::Hashed(_) => L::to_u8(), + // Can't overflow because it's checked on creation. + Self::Array(d) => { + u8::try_from(d.iter().map(|d| d.len()).sum::<usize>()).expect("length overflow") + } + } + } + + #[cfg(test)] + pub fn assert(&self, bytes: &[u8]) { + let data = match self { + Domain::Hashed(d) => d.to_vec(), + Domain::Array(d) => d.iter().copied().flatten().copied().collect(), + }; + assert_eq!(data, bytes); + } + + #[cfg(test)] + pub fn assert_dst(&self, bytes: &[u8]) { + let data = match self { + Domain::Hashed(d) => d.to_vec(), + Domain::Array(d) => d.iter().copied().flatten().copied().collect(), + }; + assert_eq!(data, &bytes[..bytes.len() - 1]); + assert_eq!(self.len(), bytes[bytes.len() - 1]); + } +} diff --git a/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 0000000..50edb64 --- /dev/null +++ b/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xmd.rs @@ -0,0 +1,453 @@ +//! `expand_message_xmd` based on a hash function. + +// TODO(tarcieri): checked arithmetic +#![allow(clippy::integer_arithmetic)] + +use core::marker::PhantomData; + +use super::{Domain, ExpandMsg, Expander}; +use crate::{Error, Result}; +use digest::{ + core_api::BlockSizeUser, + generic_array::{ + typenum::{IsLess, IsLessOrEqual, Unsigned, U256}, + GenericArray, + }, + FixedOutput, HashMarker, +}; + +/// Placeholder type for implementing `expand_message_xmd` based on a hash function +/// +/// # Errors +/// - `dst.is_empty()` +/// - `len_in_bytes == 0` +/// - `len_in_bytes > u16::MAX` +/// - `len_in_bytes > 255 * HashT::OutputSize` +pub struct ExpandMsgXmd<HashT>(PhantomData<HashT>) +where + HashT: BlockSizeUser + Default + FixedOutput + HashMarker, + 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: BlockSizeUser + Default + FixedOutput + HashMarker, + // If `len_in_bytes` is bigger then 256, length of the `DST` will depend on + // the output size of the hash, which is still not allowed to be bigger then 256: + // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#section-5.4.1-6 + HashT::OutputSize: IsLess<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]], + dsts: &'a [&'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>(dsts)?; + let mut b_0 = HashT::default(); + 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]); + domain.update_hash(&mut b_0); + b_0.update(&[domain.len()]); + let b_0 = b_0.finalize_fixed(); + + let mut b_vals = HashT::default(); + b_vals.update(&b_0[..]); + b_vals.update(&[1u8]); + domain.update_hash(&mut b_vals); + b_vals.update(&[domain.len()]); + let b_vals = b_vals.finalize_fixed(); + + Ok(ExpanderXmd { + b_0, + b_vals, + domain, + index: 1, + offset: 0, + ell, + }) + } +} + +/// [`Expander`] type for [`ExpandMsgXmd`]. +pub struct ExpanderXmd<'a, HashT> +where + HashT: BlockSizeUser + Default + FixedOutput + HashMarker, + HashT::OutputSize: IsLess<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: BlockSizeUser + Default + FixedOutput + HashMarker, + 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::default(); + b_vals.update(&tmp); + b_vals.update(&[self.index]); + self.domain.update_hash(&mut b_vals); + b_vals.update(&[self.domain.len()]); + self.b_vals = b_vals.finalize_fixed(); + true + } else { + false + } + } +} + +impl<'a, HashT> Expander for ExpanderXmd<'a, HashT> +where + HashT: BlockSizeUser + Default + FixedOutput + HashMarker, + HashT::OutputSize: IsLess<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: BlockSizeUser + Default + FixedOutput + HashMarker, + 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 + usize::from(domain.len()); + domain.assert(&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: BlockSizeUser + Default + FixedOutput + HashMarker, + HashT::OutputSize: IsLess<U256> + IsLessOrEqual<HashT::BlockSize>, + { + assert_message::<HashT>(self.msg, domain, L::to_u16(), self.msg_prime); + + let dst = [dst]; + 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(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(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(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 0000000..9a5ff19 --- /dev/null +++ b/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xof.rs @@ -0,0 +1,352 @@ +//! `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]], + dsts: &'a [&'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>(dsts)?; + let mut reader = HashT::default(); + + for msg in msgs { + reader = reader.chain(msg); + } + + reader.update(&len_in_bytes.to_be_bytes()); + domain.update_hash(&mut reader); + reader.update(&[domain.len()]); + let reader = reader.finalize_xof(); + Ok(Self { reader }) + } +} + +impl<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 + usize::from(domain.len()); + domain.assert(&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(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(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(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 0000000..7a28983 --- /dev/null +++ b/vendor/elliptic-curve/src/hash2curve/isogeny.rs @@ -0,0 +1,58 @@ +//! 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 + #[allow(clippy::integer_arithmetic)] + 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 0000000..6092e57 --- /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 0000000..3c3669a --- /dev/null +++ b/vendor/elliptic-curve/src/hash2curve/osswu.rs @@ -0,0 +1,130 @@ +//! Optimized simplified Shallue-van de Woestijne-Ulas methods. +//! +//! <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#straightline-sswu> + +use ff::Field; +use subtle::Choice; +use subtle::ConditionallySelectable; +use subtle::ConstantTimeEq; + +/// The Optimized Simplified Shallue-van de Woestijne-Ulas parameters +pub struct OsswuMapParams<F> +where + F: Field, +{ + /// The first constant term + pub c1: &'static [u64], + /// The second constant term + pub c2: F, + /// The ISO A variable or Curve A variable + pub map_a: F, + /// The ISO A variable or Curve A variable + pub map_b: F, + /// The Z parameter + pub z: F, +} + +/// Trait for determining the parity of the field +pub trait Sgn0 { + /// Return the parity of the field + /// 1 == negative + /// 0 == non-negative + fn sgn0(&self) -> Choice; +} + +/// The optimized simplified Shallue-van de Woestijne-Ulas method +/// for mapping elliptic curve scalars to affine points. +pub trait OsswuMap: Field + Sgn0 { + /// The OSSWU parameters for mapping the field to affine points. + /// For Weierstrass curves having A==0 or B==0, the parameters + /// should be for isogeny where A≠0 and B≠0. + const PARAMS: OsswuMapParams<Self>; + + /// Optimized sqrt_ratio for q = 3 mod 4. + fn sqrt_ratio_3mod4(u: Self, v: Self) -> (Choice, Self) { + // 1. tv1 = v^2 + let tv1 = v.square(); + // 2. tv2 = u * v + let tv2 = u * v; + // 3. tv1 = tv1 * tv2 + let tv1 = tv1 * tv2; + // 4. y1 = tv1^c1 + let y1 = tv1.pow_vartime(Self::PARAMS.c1); + // 5. y1 = y1 * tv2 + let y1 = y1 * tv2; + // 6. y2 = y1 * c2 + let y2 = y1 * Self::PARAMS.c2; + // 7. tv3 = y1^2 + let tv3 = y1.square(); + // 8. tv3 = tv3 * v + let tv3 = tv3 * v; + // 9. isQR = tv3 == u + let is_qr = tv3.ct_eq(&u); + // 10. y = CMOV(y2, y1, isQR) + let y = ConditionallySelectable::conditional_select(&y2, &y1, is_qr); + // 11. return (isQR, y) + (is_qr, y) + } + + /// Convert this field element into an affine point on the elliptic curve + /// returning (X, Y). For Weierstrass curves having A==0 or B==0 + /// the result is a point on an isogeny. + fn osswu(&self) -> (Self, Self) { + // 1. tv1 = u^2 + let tv1 = self.square(); + // 2. tv1 = Z * tv1 + let tv1 = Self::PARAMS.z * tv1; + // 3. tv2 = tv1^2 + let tv2 = tv1.square(); + // 4. tv2 = tv2 + tv1 + let tv2 = tv2 + tv1; + // 5. tv3 = tv2 + 1 + let tv3 = tv2 + Self::ONE; + // 6. tv3 = B * tv3 + let tv3 = Self::PARAMS.map_b * tv3; + // 7. tv4 = CMOV(Z, -tv2, tv2 != 0) + let tv4 = ConditionallySelectable::conditional_select( + &Self::PARAMS.z, + &-tv2, + !Field::is_zero(&tv2), + ); + // 8. tv4 = A * tv4 + let tv4 = Self::PARAMS.map_a * tv4; + // 9. tv2 = tv3^2 + let tv2 = tv3.square(); + // 10. tv6 = tv4^2 + let tv6 = tv4.square(); + // 11. tv5 = A * tv6 + let tv5 = Self::PARAMS.map_a * tv6; + // 12. tv2 = tv2 + tv5 + let tv2 = tv2 + tv5; + // 13. tv2 = tv2 * tv3 + let tv2 = tv2 * tv3; + // 14. tv6 = tv6 * tv4 + let tv6 = tv6 * tv4; + // 15. tv5 = B * tv6 + let tv5 = Self::PARAMS.map_b * tv6; + // 16. tv2 = tv2 + tv5 + let tv2 = tv2 + tv5; + // 17. x = tv1 * tv3 + let x = tv1 * tv3; + // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6) + let (is_gx1_square, y1) = Self::sqrt_ratio_3mod4(tv2, tv6); + // 19. y = tv1 * u + let y = tv1 * self; + // 20. y = y * y1 + let y = y * y1; + // 21. x = CMOV(x, tv3, is_gx1_square) + let x = ConditionallySelectable::conditional_select(&x, &tv3, is_gx1_square); + // 22. y = CMOV(y, y1, is_gx1_square) + let y = ConditionallySelectable::conditional_select(&y, &y1, is_gx1_square); + // 23. e1 = sgn0(u) == sgn0(y) + let e1 = self.sgn0().ct_eq(&y.sgn0()); + // 24. y = CMOV(-y, y, e1) + let y = ConditionallySelectable::conditional_select(&-y, &y, e1); + // 25. x = x / tv4 + let x = x * tv4.invert().unwrap(); + // 26. return (x, y) + (x, y) + } +} diff --git a/vendor/elliptic-curve/src/jwk.rs b/vendor/elliptic-curve/src/jwk.rs new file mode 100644 index 0000000..e0233cc --- /dev/null +++ b/vendor/elliptic-curve/src/jwk.rs @@ -0,0 +1,674 @@ +//! 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, FieldBytesSize, Result, +}; +use alloc::{ + borrow::ToOwned, + format, + string::{String, ToString}, +}; +use base64ct::{Base64UrlUnpadded as Base64Url, Encoding}; +use core::{ + fmt::{self, Debug}, + marker::PhantomData, + str::{self, FromStr}, +}; +use serdect::serde::{de, ser, Deserialize, Serialize}; +use zeroize::{Zeroize, ZeroizeOnDrop}; + +#[cfg(feature = "arithmetic")] +use crate::{ + public_key::PublicKey, + sec1::{FromEncodedPoint, ToEncodedPoint}, + AffinePoint, CurveArithmetic, +}; + +/// Key Type (`kty`) for elliptic curve keys. +pub const EC_KTY: &str = "EC"; + +/// Deserialization error message. +const DE_ERROR_MSG: &str = "struct JwkEcKey with 5 elements"; + +/// Name of the JWK type +const JWK_TYPE_NAME: &str = "JwkEcKey"; + +/// Field names +const FIELDS: &[&str] = &["kty", "crv", "x", "y", "d"]; + +/// Elliptic curve parameters used by JSON Web Keys. +pub trait JwkParameters: Curve { + /// The `crv` parameter which identifies a particular elliptic curve + /// as defined in RFC 7518 Section 6.2.1.1: + /// <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)] +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")] + pub fn to_public_key<C>(&self) -> Result<PublicKey<C>> + where + C: CurveArithmetic + JwkParameters, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<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, + FieldBytesSize<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, + FieldBytesSize<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")] + pub fn to_secret_key<C>(&self) -> Result<SecretKey<C>> + where + C: Curve + JwkParameters + ValidatePublicKey, + FieldBytesSize<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") + } +} + +impl<C> TryFrom<JwkEcKey> for SecretKey<C> +where + C: Curve + JwkParameters + ValidatePublicKey, + FieldBytesSize<C>: ModulusSize, +{ + type Error = Error; + + fn try_from(jwk: JwkEcKey) -> Result<SecretKey<C>> { + (&jwk).try_into() + } +} + +impl<C> TryFrom<&JwkEcKey> for SecretKey<C> +where + C: Curve + JwkParameters + ValidatePublicKey, + FieldBytesSize<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_slice(&d_bytes); + d_bytes.zeroize(); + + result.and_then(|secret_key| { + C::validate_public_key(&secret_key, &pk)?; + Ok(secret_key) + }) + } else { + Err(Error) + } + } +} + +#[cfg(feature = "arithmetic")] +impl<C> From<SecretKey<C>> for JwkEcKey +where + C: CurveArithmetic + JwkParameters, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, +{ + fn from(sk: SecretKey<C>) -> JwkEcKey { + (&sk).into() + } +} + +#[cfg(feature = "arithmetic")] +impl<C> From<&SecretKey<C>> for JwkEcKey +where + C: CurveArithmetic + JwkParameters, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, +{ + fn from(sk: &SecretKey<C>) -> JwkEcKey { + let mut jwk = sk.public_key().to_jwk(); + let mut d = sk.to_bytes(); + jwk.d = Some(Base64Url::encode_string(&d)); + d.zeroize(); + jwk + } +} + +#[cfg(feature = "arithmetic")] +impl<C> TryFrom<JwkEcKey> for PublicKey<C> +where + C: CurveArithmetic + JwkParameters, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, +{ + type Error = Error; + + fn try_from(jwk: JwkEcKey) -> Result<PublicKey<C>> { + (&jwk).try_into() + } +} + +#[cfg(feature = "arithmetic")] +impl<C> TryFrom<&JwkEcKey> for PublicKey<C> +where + C: CurveArithmetic + JwkParameters, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<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")] +impl<C> From<PublicKey<C>> for JwkEcKey +where + C: CurveArithmetic + JwkParameters, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, +{ + fn from(pk: PublicKey<C>) -> JwkEcKey { + (&pk).into() + } +} + +#[cfg(feature = "arithmetic")] +impl<C> From<&PublicKey<C>> for JwkEcKey +where + C: CurveArithmetic + JwkParameters, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<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 0000000..5f2a6c6 --- /dev/null +++ b/vendor/elliptic-curve/src/lib.rs @@ -0,0 +1,197 @@ +#![no_std] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![doc = include_str!("../README.md")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg" +)] +#![forbid(unsafe_code)] +#![warn( + clippy::cast_lossless, + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::cast_precision_loss, + clippy::cast_sign_loss, + clippy::checked_conversions, + clippy::implicit_saturating_sub, + clippy::integer_arithmetic, + clippy::mod_module_files, + clippy::panic, + clippy::panic_in_result_fn, + clippy::unwrap_used, + missing_docs, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] + +//! ## Usage +//! +//! This crate provides traits for describing elliptic curves, along with +//! types which are generic over elliptic curves which can be used as the +//! basis of curve-agnostic code. +//! +//! It's intended to be used with the following concrete elliptic curve +//! implementations from the [`RustCrypto/elliptic-curves`] project: +//! +//! - [`bp256`]: brainpoolP256r1 and brainpoolP256t1 +//! - [`bp384`]: brainpoolP384r1 and brainpoolP384t1 +//! - [`k256`]: secp256k1 a.k.a. K-256 +//! - [`p224`]: NIST P-224 a.k.a. secp224r1 +//! - [`p256`]: NIST P-256 a.k.a secp256r1, prime256v1 +//! - [`p384`]: NIST P-384 a.k.a. secp384r1 +//! - [`p521`]: NIST P-521 a.k.a. secp521r1 +//! +//! The [`ecdsa`] crate provides a generic implementation of the +//! Elliptic Curve Digital Signature Algorithm which can be used with any of +//! the above crates, either via an external ECDSA implementation, or +//! using native curve arithmetic where applicable. +//! +//! ## Type conversions +//! +//! The following chart illustrates the various conversions possible between +//! the various types defined by this crate. +//! +//! ![Type Conversion Map](https://raw.githubusercontent.com/RustCrypto/media/master/img/elliptic-curve/type-transforms.svg) +//! +//! ## `serde` support +//! +//! When the `serde` feature of this crate is enabled, `Serialize` and +//! `Deserialize` impls are provided for the following types: +//! +//! - [`JwkEcKey`] +//! - [`PublicKey`] +//! - [`ScalarPrimitive`] +//! +//! Please see type-specific documentation for more information. +//! +//! [`RustCrypto/elliptic-curves`]: https://github.com/RustCrypto/elliptic-curves +//! [`bp256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/bp256 +//! [`bp384`]: https://github.com/RustCrypto/elliptic-curves/tree/master/bp384 +//! [`k256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/k256 +//! [`p224`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p224 +//! [`p256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p256 +//! [`p384`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p384 +//! [`p521`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p521 +//! [`ecdsa`]: https://github.com/RustCrypto/signatures/tree/master/ecdsa + +#[cfg(feature = "alloc")] +#[allow(unused_imports)] +#[macro_use] +extern crate alloc; +#[cfg(feature = "std")] +extern crate std; + +pub mod point; +pub mod scalar; + +#[cfg(feature = "dev")] +pub mod dev; +#[cfg(feature = "ecdh")] +pub mod ecdh; +#[cfg(feature = "hash2curve")] +pub mod hash2curve; +#[cfg(feature = "arithmetic")] +pub mod ops; +#[cfg(feature = "sec1")] +pub mod sec1; +#[cfg(feature = "arithmetic")] +pub mod weierstrass; + +mod error; +mod field; +mod secret_key; + +#[cfg(feature = "arithmetic")] +mod arithmetic; +#[cfg(feature = "arithmetic")] +mod public_key; + +#[cfg(feature = "jwk")] +mod jwk; + +#[cfg(feature = "voprf")] +mod voprf; + +pub use crate::{ + error::{Error, Result}, + field::{FieldBytes, FieldBytesEncoding, FieldBytesSize}, + scalar::ScalarPrimitive, + secret_key::SecretKey, +}; +pub use crypto_bigint as bigint; +pub use generic_array::{self, typenum::consts}; +pub use rand_core; +pub use subtle; +pub use zeroize; + +#[cfg(feature = "arithmetic")] +pub use { + crate::{ + arithmetic::{CurveArithmetic, PrimeCurveArithmetic}, + point::{AffinePoint, ProjectivePoint}, + public_key::PublicKey, + scalar::{NonZeroScalar, Scalar}, + }, + ff::{self, Field, PrimeField}, + group::{self, Group}, +}; + +#[cfg(feature = "jwk")] +pub use crate::jwk::{JwkEcKey, JwkParameters}; + +#[cfg(feature = "pkcs8")] +pub use pkcs8; + +#[cfg(feature = "voprf")] +pub use crate::voprf::VoprfParameters; + +use core::{ + fmt::Debug, + ops::{Add, ShrAssign}, +}; +use generic_array::ArrayLength; + +/// Algorithm [`ObjectIdentifier`][`pkcs8::ObjectIdentifier`] for elliptic +/// curve public key cryptography (`id-ecPublicKey`). +/// +/// <http://oid-info.com/get/1.2.840.10045.2.1> +#[cfg(feature = "pkcs8")] +pub const ALGORITHM_OID: pkcs8::ObjectIdentifier = + pkcs8::ObjectIdentifier::new_unwrap("1.2.840.10045.2.1"); + +/// Elliptic curve. +/// +/// This trait is intended to be impl'd by a ZST which represents a concrete +/// elliptic curve. +/// +/// Other traits in this crate which are bounded by [`Curve`] are intended to +/// be impl'd by these ZSTs, facilitating types which are generic over elliptic +/// curves (e.g. [`SecretKey`]). +pub trait Curve: 'static + Copy + Clone + Debug + Default + Eq + Ord + Send + Sync { + /// Size of a serialized field element in bytes. + /// + /// This is typically the same as `Self::Uint::ByteSize` but for curves + /// with an unusual field modulus (e.g. P-224, P-521) it may be different. + type FieldBytesSize: ArrayLength<u8> + Add + Eq; + + /// Integer type used to represent field elements of this elliptic curve. + type Uint: bigint::ArrayEncoding + + bigint::AddMod<Output = Self::Uint> + + bigint::Encoding + + bigint::Integer + + bigint::NegMod<Output = Self::Uint> + + bigint::Random + + bigint::RandomMod + + bigint::SubMod<Output = Self::Uint> + + zeroize::Zeroize + + FieldBytesEncoding<Self> + + ShrAssign<usize>; + + /// Order of this elliptic curve, i.e. number of elements in the scalar + /// field. + const ORDER: Self::Uint; +} + +/// Marker trait for elliptic curves with prime order. +pub trait PrimeCurve: Curve {} diff --git a/vendor/elliptic-curve/src/ops.rs b/vendor/elliptic-curve/src/ops.rs new file mode 100644 index 0000000..b7e9e3d --- /dev/null +++ b/vendor/elliptic-curve/src/ops.rs @@ -0,0 +1,79 @@ +//! Traits for arithmetic operations on elliptic curve field elements. + +pub use core::ops::{Add, AddAssign, Mul, Neg, Shr, ShrAssign, Sub, SubAssign}; + +use crypto_bigint::Integer; +use group::Group; + +/// Perform an inversion on a field element (i.e. base field element or scalar) +pub trait Invert { + /// Field element type + type Output; + + /// Invert a field element. + fn invert(&self) -> Self::Output; + + /// Invert a field element in variable time. + /// + /// ⚠️ WARNING! + /// + /// This method should not be used with secret values, as its variable-time + /// operation can potentially leak secrets through sidechannels. + fn invert_vartime(&self) -> Self::Output { + // Fall back on constant-time implementation by default. + self.invert() + } +} + +/// Linear combination. +/// +/// This trait enables crates to provide an optimized implementation of +/// linear combinations (e.g. Shamir's Trick), or otherwise provides a default +/// non-optimized implementation. +// TODO(tarcieri): replace this with a trait from the `group` crate? (see zkcrypto/group#25) +pub trait LinearCombination: Group { + /// Calculates `x * k + y * l`. + fn lincomb(x: &Self, k: &Self::Scalar, y: &Self, l: &Self::Scalar) -> Self { + (*x * k) + (*y * l) + } +} + +/// Multiplication by the generator. +/// +/// May use optimizations (e.g. precomputed tables) when available. +// TODO(tarcieri): replace this with `Group::mul_by_generator``? (see zkcrypto/group#44) +pub trait MulByGenerator: Group { + /// Multiply by the generator of the prime-order subgroup. + #[must_use] + fn mul_by_generator(scalar: &Self::Scalar) -> Self { + Self::generator() * scalar + } +} + +/// Modular reduction. +pub trait Reduce<Uint: Integer>: Sized { + /// Bytes used as input to [`Reduce::reduce_bytes`]. + type Bytes: AsRef<[u8]>; + + /// Perform a modular reduction, returning a field element. + fn reduce(n: Uint) -> Self; + + /// Interpret the given bytes as an integer and perform a modular reduction. + fn reduce_bytes(bytes: &Self::Bytes) -> Self; +} + +/// Modular reduction to a non-zero output. +/// +/// This trait is primarily intended for use by curve implementations such +/// as the `k256` and `p256` crates. +/// +/// End users should use the [`Reduce`] impl on +/// [`NonZeroScalar`][`crate::NonZeroScalar`] instead. +pub trait ReduceNonZero<Uint: Integer>: Reduce<Uint> + Sized { + /// Perform a modular reduction, returning a field element. + fn reduce_nonzero(n: Uint) -> Self; + + /// Interpret the given bytes as an integer and perform a modular reduction + /// to a non-zero output. + fn reduce_nonzero_bytes(bytes: &Self::Bytes) -> Self; +} diff --git a/vendor/elliptic-curve/src/point.rs b/vendor/elliptic-curve/src/point.rs new file mode 100644 index 0000000..25b872a --- /dev/null +++ b/vendor/elliptic-curve/src/point.rs @@ -0,0 +1,69 @@ +//! Traits for elliptic curve points. + +#[cfg(feature = "arithmetic")] +mod non_identity; + +#[cfg(feature = "arithmetic")] +pub use {self::non_identity::NonIdentity, crate::CurveArithmetic}; + +use crate::{Curve, FieldBytes}; +use subtle::{Choice, CtOption}; + +/// Affine point type for a given curve with a [`CurveArithmetic`] +/// implementation. +#[cfg(feature = "arithmetic")] +pub type AffinePoint<C> = <C as CurveArithmetic>::AffinePoint; + +/// Projective point type for a given curve with a [`CurveArithmetic`] +/// implementation. +#[cfg(feature = "arithmetic")] +pub type ProjectivePoint<C> = <C as CurveArithmetic>::ProjectivePoint; + +/// Access to the affine coordinates of an elliptic curve point. +// TODO: use zkcrypto/group#30 coordinate API when available +pub trait AffineCoordinates { + /// Field element representation. + type FieldRepr: AsRef<[u8]>; + + /// Get the affine x-coordinate as a serialized field element. + fn x(&self) -> Self::FieldRepr; + + /// Is the affine y-coordinate odd? + fn y_is_odd(&self) -> Choice; +} + +/// Double a point (i.e. add it to itself) +pub trait Double { + /// Double this point. + fn double(&self) -> Self; +} + +/// Decompress an elliptic curve point. +/// +/// Point decompression recovers an original curve point from its x-coordinate +/// and a boolean flag indicating whether or not the y-coordinate is odd. +pub trait DecompressPoint<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/point/non_identity.rs b/vendor/elliptic-curve/src/point/non_identity.rs new file mode 100644 index 0000000..81c31cd --- /dev/null +++ b/vendor/elliptic-curve/src/point/non_identity.rs @@ -0,0 +1,237 @@ +//! Non-identity point type. + +use core::ops::{Deref, Mul}; + +use group::{prime::PrimeCurveAffine, Curve, GroupEncoding}; +use rand_core::{CryptoRng, RngCore}; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +use crate::{CurveArithmetic, NonZeroScalar, Scalar}; + +/// Non-identity point type. +/// +/// This type ensures that its value is not the identity point, ala `core::num::NonZero*`. +/// +/// In the context of ECC, it's useful for ensuring that certain arithmetic +/// cannot result in the identity point. +#[derive(Clone, Copy)] +pub struct NonIdentity<P> { + point: P, +} + +impl<P> NonIdentity<P> +where + P: ConditionallySelectable + ConstantTimeEq + Default, +{ + /// Create a [`NonIdentity`] from a point. + pub fn new(point: P) -> CtOption<Self> { + CtOption::new(Self { point }, !point.ct_eq(&P::default())) + } + + pub(crate) fn new_unchecked(point: P) -> Self { + Self { point } + } +} + +impl<P> NonIdentity<P> +where + P: ConditionallySelectable + ConstantTimeEq + Default + GroupEncoding, +{ + /// Decode a [`NonIdentity`] from its encoding. + pub fn from_repr(repr: &P::Repr) -> CtOption<Self> { + Self::from_bytes(repr) + } +} + +impl<P: Copy> NonIdentity<P> { + /// Return wrapped point. + pub fn to_point(self) -> P { + self.point + } +} + +impl<P> NonIdentity<P> +where + P: ConditionallySelectable + ConstantTimeEq + Curve + Default, +{ + /// Generate a random `NonIdentity<ProjectivePoint>`. + pub fn random(mut rng: impl CryptoRng + RngCore) -> Self { + loop { + if let Some(point) = Self::new(P::random(&mut rng)).into() { + break point; + } + } + } + + /// Converts this element into its affine representation. + pub fn to_affine(self) -> NonIdentity<P::AffineRepr> { + NonIdentity { + point: self.point.to_affine(), + } + } +} + +impl<P> NonIdentity<P> +where + P: PrimeCurveAffine, +{ + /// Converts this element to its curve representation. + pub fn to_curve(self) -> NonIdentity<P::Curve> { + NonIdentity { + point: self.point.to_curve(), + } + } +} + +impl<P> AsRef<P> for NonIdentity<P> { + fn as_ref(&self) -> &P { + &self.point + } +} + +impl<P> ConditionallySelectable for NonIdentity<P> +where + P: ConditionallySelectable, +{ + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self { + point: P::conditional_select(&a.point, &b.point, choice), + } + } +} + +impl<P> ConstantTimeEq for NonIdentity<P> +where + P: ConstantTimeEq, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.point.ct_eq(&other.point) + } +} + +impl<P> Deref for NonIdentity<P> { + type Target = P; + + fn deref(&self) -> &Self::Target { + &self.point + } +} + +impl<P> GroupEncoding for NonIdentity<P> +where + P: ConditionallySelectable + ConstantTimeEq + Default + GroupEncoding, +{ + type Repr = P::Repr; + + fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> { + let point = P::from_bytes(bytes); + point.and_then(|point| CtOption::new(Self { point }, !point.ct_eq(&P::default()))) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> { + P::from_bytes_unchecked(bytes).map(|point| Self { point }) + } + + fn to_bytes(&self) -> Self::Repr { + self.point.to_bytes() + } +} + +impl<C, P> Mul<NonZeroScalar<C>> for NonIdentity<P> +where + C: CurveArithmetic, + P: Copy + Mul<Scalar<C>, Output = P>, +{ + type Output = NonIdentity<P>; + + fn mul(self, rhs: NonZeroScalar<C>) -> Self::Output { + &self * &rhs + } +} + +impl<C, P> Mul<&NonZeroScalar<C>> for &NonIdentity<P> +where + C: CurveArithmetic, + P: Copy + Mul<Scalar<C>, Output = P>, +{ + type Output = NonIdentity<P>; + + fn mul(self, rhs: &NonZeroScalar<C>) -> Self::Output { + NonIdentity { + point: self.point * *rhs.as_ref(), + } + } +} + +#[cfg(feature = "serde")] +impl<P> Serialize for NonIdentity<P> +where + P: Serialize, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: ser::Serializer, + { + self.point.serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, P> Deserialize<'de> for NonIdentity<P> +where + P: ConditionallySelectable + ConstantTimeEq + Default + Deserialize<'de> + GroupEncoding, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: de::Deserializer<'de>, + { + Option::from(Self::new(P::deserialize(deserializer)?)) + .ok_or_else(|| de::Error::custom("expected non-identity point")) + } +} + +#[cfg(all(test, feature = "dev"))] +mod tests { + use super::NonIdentity; + use crate::dev::{AffinePoint, ProjectivePoint}; + use group::GroupEncoding; + use hex_literal::hex; + + #[test] + fn new_success() { + let point = ProjectivePoint::from_bytes( + &hex!("02c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721").into(), + ) + .unwrap(); + + assert!(bool::from(NonIdentity::new(point).is_some())); + + assert!(bool::from( + NonIdentity::new(AffinePoint::from(point)).is_some() + )); + } + + #[test] + fn new_fail() { + assert!(bool::from( + NonIdentity::new(ProjectivePoint::default()).is_none() + )); + assert!(bool::from( + NonIdentity::new(AffinePoint::default()).is_none() + )); + } + + #[test] + fn round_trip() { + let bytes = hex!("02c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); + let point = NonIdentity::<ProjectivePoint>::from_repr(&bytes.into()).unwrap(); + assert_eq!(&bytes, point.to_bytes().as_slice()); + + let bytes = hex!("02c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); + let point = NonIdentity::<AffinePoint>::from_repr(&bytes.into()).unwrap(); + assert_eq!(&bytes, point.to_bytes().as_slice()); + } +} diff --git a/vendor/elliptic-curve/src/public_key.rs b/vendor/elliptic-curve/src/public_key.rs new file mode 100644 index 0000000..485b0ec --- /dev/null +++ b/vendor/elliptic-curve/src/public_key.rs @@ -0,0 +1,566 @@ +//! Elliptic curve public keys. + +use crate::{ + point::NonIdentity, AffinePoint, CurveArithmetic, Error, NonZeroScalar, ProjectivePoint, Result, +}; +use core::fmt::Debug; +use group::{Curve, Group}; + +#[cfg(feature = "jwk")] +use crate::{JwkEcKey, JwkParameters}; + +#[cfg(feature = "pkcs8")] +use pkcs8::spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, ObjectIdentifier}; + +#[cfg(feature = "pem")] +use core::str::FromStr; + +#[cfg(feature = "sec1")] +use { + crate::{ + point::PointCompression, + sec1::{CompressedPoint, EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint}, + FieldBytesSize, + }, + core::cmp::Ordering, + subtle::{Choice, CtOption}, +}; + +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +use pkcs8::EncodePublicKey; + +#[cfg(all(feature = "alloc", feature = "sec1"))] +use alloc::boxed::Box; + +#[cfg(any(feature = "jwk", feature = "pem"))] +use alloc::string::{String, ToString}; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +#[cfg(any(feature = "pem", feature = "serde"))] +use pkcs8::DecodePublicKey; + +#[cfg(all(feature = "sec1", feature = "pkcs8"))] +use { + crate::{ + pkcs8::{self, AssociatedOid}, + ALGORITHM_OID, + }, + pkcs8::der, +}; + +/// Elliptic curve public keys. +/// +/// This is a wrapper type for [`AffinePoint`] which ensures an inner +/// non-identity point and provides a common place to handle encoding/decoding. +/// +/// # Parsing "SPKI" Keys +/// +/// X.509 `SubjectPublicKeyInfo` (SPKI) is a commonly used format for encoding +/// public keys, notably public keys corresponding to PKCS#8 private keys. +/// (especially ones generated by OpenSSL). +/// +/// Keys in SPKI format are either binary (ASN.1 BER/DER), or PEM encoded +/// (ASCII) and begin with the following: +/// +/// ```text +/// -----BEGIN PUBLIC KEY----- +/// ``` +/// +/// To decode an elliptic curve public key from SPKI, enable the `pkcs8` +/// feature of this crate (or the `pkcs8` feature of a specific RustCrypto +/// elliptic curve crate) and use the +/// [`elliptic_curve::pkcs8::DecodePublicKey`][`pkcs8::DecodePublicKey`] +/// trait to parse it. +/// +/// When the `pem` feature of this crate (or a specific RustCrypto elliptic +/// curve crate) is enabled, a [`FromStr`] impl is also available. +/// +/// # `serde` support +/// +/// When the optional `serde` feature of this create is enabled, [`Serialize`] +/// and [`Deserialize`] impls are provided for this type. +/// +/// The serialization is binary-oriented and supports ASN.1 DER +/// Subject Public Key Info (SPKI) as the encoding format. +/// +/// For a more text-friendly encoding of public keys, use [`JwkEcKey`] instead. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct PublicKey<C> +where + C: CurveArithmetic, +{ + point: AffinePoint<C>, +} + +impl<C> PublicKey<C> +where + C: CurveArithmetic, +{ + /// 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 + FieldBytesSize<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) + } + + /// Convert this [`PublicKey`] into the + /// `Elliptic-Curve-Point-to-Octet-String` encoding described in + /// SEC 1: Elliptic Curve Cryptography (Version 2.0) section 2.3.3 + /// (page 10). + /// + /// <http://www.secg.org/sec1-v2.pdf> + #[cfg(all(feature = "alloc", feature = "sec1"))] + pub fn to_sec1_bytes(&self) -> Box<[u8]> + where + C: PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, + { + EncodedPoint::<C>::from(self).to_bytes() + } + + /// Borrow the inner [`AffinePoint`] from this [`PublicKey`]. + /// + /// In ECC, public keys are elliptic curve points. + pub fn as_affine(&self) -> &AffinePoint<C> { + &self.point + } + + /// Convert this [`PublicKey`] to a [`ProjectivePoint`] for the given curve + pub fn to_projective(&self) -> ProjectivePoint<C> { + self.point.into() + } + + /// Convert this [`PublicKey`] to a [`NonIdentity`] of the inner [`AffinePoint`] + pub fn to_nonidentity(&self) -> NonIdentity<AffinePoint<C>> { + NonIdentity::new_unchecked(self.point) + } + + /// Parse a [`JwkEcKey`] JSON Web Key (JWK) into a [`PublicKey`]. + #[cfg(feature = "jwk")] + pub fn from_jwk(jwk: &JwkEcKey) -> Result<Self> + where + C: JwkParameters, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, + { + jwk.to_public_key::<C>() + } + + /// Parse a string containing a JSON Web Key (JWK) into a [`PublicKey`]. + #[cfg(feature = "jwk")] + pub fn from_jwk_str(jwk: &str) -> Result<Self> + where + C: JwkParameters, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<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")] + pub fn to_jwk(&self) -> JwkEcKey + where + C: JwkParameters, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, + { + self.into() + } + + /// Serialize this public key as JSON Web Key (JWK) string. + #[cfg(feature = "jwk")] + pub fn to_jwk_string(&self) -> String + where + C: JwkParameters, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, + { + self.to_jwk().to_string() + } +} + +impl<C> AsRef<AffinePoint<C>> for PublicKey<C> +where + C: CurveArithmetic, +{ + fn as_ref(&self) -> &AffinePoint<C> { + self.as_affine() + } +} + +impl<C> Copy for PublicKey<C> where C: CurveArithmetic {} + +#[cfg(feature = "sec1")] +impl<C> FromEncodedPoint<C> for PublicKey<C> +where + C: CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<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 = Choice::from(encoded_point.is_identity() as u8); + CtOption::new(PublicKey { point }, !is_identity) + }) + } +} + +#[cfg(feature = "sec1")] +impl<C> ToEncodedPoint<C> for PublicKey<C> +where + C: CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<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")] +impl<C> From<PublicKey<C>> for CompressedPoint<C> +where + C: CurveArithmetic + PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, +{ + fn from(public_key: PublicKey<C>) -> CompressedPoint<C> { + CompressedPoint::<C>::from(&public_key) + } +} + +#[cfg(feature = "sec1")] +impl<C> From<&PublicKey<C>> for CompressedPoint<C> +where + C: CurveArithmetic + PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, +{ + fn from(public_key: &PublicKey<C>) -> CompressedPoint<C> { + CompressedPoint::<C>::clone_from_slice(public_key.to_encoded_point(true).as_bytes()) + } +} + +#[cfg(feature = "sec1")] +impl<C> From<PublicKey<C>> for EncodedPoint<C> +where + C: CurveArithmetic + PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, +{ + fn from(public_key: PublicKey<C>) -> EncodedPoint<C> { + EncodedPoint::<C>::from(&public_key) + } +} + +#[cfg(feature = "sec1")] +impl<C> From<&PublicKey<C>> for EncodedPoint<C> +where + C: CurveArithmetic + PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, +{ + fn from(public_key: &PublicKey<C>) -> EncodedPoint<C> { + public_key.to_encoded_point(C::COMPRESS_POINTS) + } +} + +impl<C, P> From<NonIdentity<P>> for PublicKey<C> +where + C: CurveArithmetic, + P: Copy + Into<AffinePoint<C>>, +{ + fn from(value: NonIdentity<P>) -> Self { + Self::from(&value) + } +} + +impl<C, P> From<&NonIdentity<P>> for PublicKey<C> +where + C: CurveArithmetic, + P: Copy + Into<AffinePoint<C>>, +{ + fn from(value: &NonIdentity<P>) -> Self { + Self { + point: value.to_point().into(), + } + } +} + +impl<C> From<PublicKey<C>> for NonIdentity<AffinePoint<C>> +where + C: CurveArithmetic, +{ + fn from(value: PublicKey<C>) -> Self { + Self::from(&value) + } +} + +impl<C> From<&PublicKey<C>> for NonIdentity<AffinePoint<C>> +where + C: CurveArithmetic, +{ + fn from(value: &PublicKey<C>) -> Self { + PublicKey::to_nonidentity(value) + } +} + +#[cfg(feature = "sec1")] +impl<C> PartialOrd for PublicKey<C> +where + C: CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, +{ + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +#[cfg(feature = "sec1")] +impl<C> Ord for PublicKey<C> +where + C: CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<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(feature = "sec1")] +impl<C> TryFrom<CompressedPoint<C>> for PublicKey<C> +where + C: CurveArithmetic, + FieldBytesSize<C>: ModulusSize, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, +{ + type Error = Error; + + fn try_from(point: CompressedPoint<C>) -> Result<Self> { + Self::from_sec1_bytes(&point) + } +} + +#[cfg(feature = "sec1")] +impl<C> TryFrom<&CompressedPoint<C>> for PublicKey<C> +where + C: CurveArithmetic, + FieldBytesSize<C>: ModulusSize, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, +{ + type Error = Error; + + fn try_from(point: &CompressedPoint<C>) -> Result<Self> { + Self::from_sec1_bytes(point) + } +} + +#[cfg(feature = "sec1")] +impl<C> TryFrom<EncodedPoint<C>> for PublicKey<C> +where + C: CurveArithmetic, + FieldBytesSize<C>: ModulusSize, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, +{ + type Error = Error; + + fn try_from(point: EncodedPoint<C>) -> Result<Self> { + Self::from_sec1_bytes(point.as_bytes()) + } +} + +#[cfg(feature = "sec1")] +impl<C> TryFrom<&EncodedPoint<C>> for PublicKey<C> +where + C: CurveArithmetic, + FieldBytesSize<C>: ModulusSize, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, +{ + type Error = Error; + + fn try_from(point: &EncodedPoint<C>) -> Result<Self> { + Self::from_sec1_bytes(point.as_bytes()) + } +} + +#[cfg(feature = "pkcs8")] +impl<C> AssociatedAlgorithmIdentifier for PublicKey<C> +where + C: AssociatedOid + CurveArithmetic, +{ + type Params = ObjectIdentifier; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<ObjectIdentifier> = AlgorithmIdentifier { + oid: ALGORITHM_OID, + parameters: Some(C::OID), + }; +} + +#[cfg(feature = "pkcs8")] +impl<C> TryFrom<pkcs8::SubjectPublicKeyInfoRef<'_>> for PublicKey<C> +where + C: AssociatedOid + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, +{ + type Error = pkcs8::spki::Error; + + fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result<Self> { + Self::try_from(&spki) + } +} + +#[cfg(feature = "pkcs8")] +impl<C> TryFrom<&pkcs8::SubjectPublicKeyInfoRef<'_>> for PublicKey<C> +where + C: AssociatedOid + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, +{ + type Error = pkcs8::spki::Error; + + fn try_from(spki: &pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result<Self> { + spki.algorithm.assert_oids(ALGORITHM_OID, C::OID)?; + + let public_key_bytes = spki + .subject_public_key + .as_bytes() + .ok_or_else(|| der::Tag::BitString.value_error())?; + + Self::from_sec1_bytes(public_key_bytes) + .map_err(|_| der::Tag::BitString.value_error().into()) + } +} + +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +impl<C> EncodePublicKey for PublicKey<C> +where + C: AssociatedOid + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, +{ + fn to_public_key_der(&self) -> pkcs8::spki::Result<der::Document> { + let public_key_bytes = self.to_encoded_point(false); + let subject_public_key = der::asn1::BitStringRef::new(0, public_key_bytes.as_bytes())?; + + pkcs8::SubjectPublicKeyInfo { + algorithm: Self::ALGORITHM_IDENTIFIER, + subject_public_key, + } + .try_into() + } +} + +#[cfg(feature = "pem")] +impl<C> FromStr for PublicKey<C> +where + C: AssociatedOid + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, +{ + type Err = Error; + + fn from_str(s: &str) -> Result<Self> { + Self::from_public_key_pem(s).map_err(|_| Error) + } +} + +#[cfg(feature = "pem")] +impl<C> ToString for PublicKey<C> +where + C: AssociatedOid + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, +{ + fn to_string(&self) -> String { + self.to_public_key_pem(Default::default()) + .expect("PEM encoding error") + } +} + +#[cfg(feature = "serde")] +impl<C> Serialize for PublicKey<C> +where + C: AssociatedOid + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<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")] +impl<'de, C> Deserialize<'de> for PublicKey<C> +where + C: AssociatedOid + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<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 0000000..eb99249 --- /dev/null +++ b/vendor/elliptic-curve/src/scalar.rs @@ -0,0 +1,53 @@ +//! Scalar types. + +#[cfg(feature = "arithmetic")] +mod blinded; +#[cfg(feature = "arithmetic")] +mod nonzero; +mod primitive; + +pub use self::primitive::ScalarPrimitive; +#[cfg(feature = "arithmetic")] +pub use self::{blinded::BlindedScalar, nonzero::NonZeroScalar}; + +use crypto_bigint::Integer; +use subtle::Choice; + +#[cfg(feature = "arithmetic")] +use crate::CurveArithmetic; + +/// Scalar field element for a particular elliptic curve. +#[cfg(feature = "arithmetic")] +pub type Scalar<C> = <C as CurveArithmetic>::Scalar; + +/// Bit representation of a scalar field element of a given curve. +#[cfg(feature = "bits")] +pub type ScalarBits<C> = ff::FieldBits<<Scalar<C> as ff::PrimeFieldBits>::ReprBits>; + +/// Instantiate a scalar from an unsigned integer without checking for overflow. +pub trait FromUintUnchecked { + /// Unsigned integer type (i.e. `Curve::Uint`) + type Uint: Integer; + + /// Instantiate scalar from an unsigned integer without checking + /// whether the value overflows the field modulus. + /// + /// ⚠️ WARNING! + /// + /// Incorrectly used this can lead to mathematically invalid results, + /// which can lead to potential security vulnerabilities. + /// + /// Use with care! + fn from_uint_unchecked(uint: Self::Uint) -> Self; +} + +/// Is this scalar greater than n / 2? +/// +/// # Returns +/// +/// - For scalars 0 through n / 2: `Choice::from(0)` +/// - For scalars (n / 2) + 1 through n - 1: `Choice::from(1)` +pub trait IsHigh { + /// Is this scalar greater than or equal to n / 2? + fn is_high(&self) -> Choice; +} diff --git a/vendor/elliptic-curve/src/scalar/blinded.rs b/vendor/elliptic-curve/src/scalar/blinded.rs new file mode 100644 index 0000000..29cfea9 --- /dev/null +++ b/vendor/elliptic-curve/src/scalar/blinded.rs @@ -0,0 +1,74 @@ +//! Random blinding support for [`Scalar`] + +use super::Scalar; +use crate::{ops::Invert, CurveArithmetic}; +use group::ff::Field; +use rand_core::CryptoRngCore; +use subtle::CtOption; +use zeroize::Zeroize; + +/// Scalar blinded with a randomly generated masking value. +/// +/// This provides a randomly blinded impl of [`Invert`] which is useful for +/// e.g. ECDSA ephemeral (`k`) scalars. +/// +/// It implements masked variable-time inversions using Stein's algorithm, which +/// may be helpful for performance on embedded platforms. +#[derive(Clone)] +pub struct BlindedScalar<C> +where + C: CurveArithmetic, +{ + /// Actual scalar value. + scalar: Scalar<C>, + + /// Mask value. + mask: Scalar<C>, +} + +impl<C> BlindedScalar<C> +where + C: CurveArithmetic, +{ + /// Create a new [`BlindedScalar`] from a scalar and a [`CryptoRngCore`]. + pub fn new(scalar: Scalar<C>, rng: &mut impl CryptoRngCore) -> Self { + Self { + scalar, + mask: Scalar::<C>::random(rng), + } + } +} + +impl<C> AsRef<Scalar<C>> for BlindedScalar<C> +where + C: CurveArithmetic, +{ + fn as_ref(&self) -> &Scalar<C> { + &self.scalar + } +} + +impl<C> Invert for BlindedScalar<C> +where + C: CurveArithmetic, +{ + type Output = CtOption<Scalar<C>>; + + fn invert(&self) -> CtOption<Scalar<C>> { + // prevent side channel analysis of scalar inversion by pre-and-post-multiplying + // with the random masking scalar + (self.scalar * self.mask) + .invert_vartime() + .map(|s| s * self.mask) + } +} + +impl<C> Drop for BlindedScalar<C> +where + C: CurveArithmetic, +{ + fn drop(&mut self) { + self.scalar.zeroize(); + self.mask.zeroize(); + } +} diff --git a/vendor/elliptic-curve/src/scalar/nonzero.rs b/vendor/elliptic-curve/src/scalar/nonzero.rs new file mode 100644 index 0000000..c0e4574 --- /dev/null +++ b/vendor/elliptic-curve/src/scalar/nonzero.rs @@ -0,0 +1,405 @@ +//! Non-zero scalar type. + +use crate::{ + ops::{Invert, Reduce, ReduceNonZero}, + scalar::IsHigh, + CurveArithmetic, Error, FieldBytes, PrimeCurve, Scalar, ScalarPrimitive, SecretKey, +}; +use base16ct::HexDisplay; +use core::{ + fmt, + ops::{Deref, Mul, Neg}, + str, +}; +use crypto_bigint::{ArrayEncoding, Integer}; +use ff::{Field, PrimeField}; +use generic_array::{typenum::Unsigned, GenericArray}; +use rand_core::CryptoRngCore; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use zeroize::Zeroize; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +/// Non-zero scalar type. +/// +/// This type ensures that its value is not zero, ala `core::num::NonZero*`. +/// To do this, the generic `S` type must impl both `Default` and +/// `ConstantTimeEq`, with the requirement that `S::default()` returns 0. +/// +/// In the context of ECC, it's useful for ensuring that scalar multiplication +/// cannot result in the point at infinity. +#[derive(Clone)] +pub struct NonZeroScalar<C> +where + C: CurveArithmetic, +{ + scalar: Scalar<C>, +} + +impl<C> NonZeroScalar<C> +where + C: CurveArithmetic, +{ + /// Generate a random `NonZeroScalar`. + pub fn random(mut rng: &mut impl CryptoRngCore) -> Self { + // Use rejection sampling to eliminate zero values. + // While this method isn't constant-time, the attacker shouldn't learn + // anything about unrelated outputs so long as `rng` is a secure `CryptoRng`. + loop { + if let Some(result) = Self::new(Field::random(&mut rng)).into() { + break result; + } + } + } + + /// Create a [`NonZeroScalar`] from a scalar. + pub fn new(scalar: Scalar<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> { + ScalarPrimitive::new(uint).and_then(|scalar| Self::new(scalar.into())) + } +} + +impl<C> AsRef<Scalar<C>> for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn as_ref(&self) -> &Scalar<C> { + &self.scalar + } +} + +impl<C> ConditionallySelectable for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + 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: CurveArithmetic, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.scalar.ct_eq(&other.scalar) + } +} + +impl<C> Copy for NonZeroScalar<C> where C: CurveArithmetic {} + +impl<C> Deref for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + type Target = Scalar<C>; + + fn deref(&self) -> &Scalar<C> { + &self.scalar + } +} + +impl<C> From<NonZeroScalar<C>> for FieldBytes<C> +where + C: CurveArithmetic, +{ + fn from(scalar: NonZeroScalar<C>) -> FieldBytes<C> { + Self::from(&scalar) + } +} + +impl<C> From<&NonZeroScalar<C>> for FieldBytes<C> +where + C: CurveArithmetic, +{ + fn from(scalar: &NonZeroScalar<C>) -> FieldBytes<C> { + scalar.to_repr() + } +} + +impl<C> From<NonZeroScalar<C>> for ScalarPrimitive<C> +where + C: CurveArithmetic, +{ + #[inline] + fn from(scalar: NonZeroScalar<C>) -> ScalarPrimitive<C> { + Self::from(&scalar) + } +} + +impl<C> From<&NonZeroScalar<C>> for ScalarPrimitive<C> +where + C: CurveArithmetic, +{ + fn from(scalar: &NonZeroScalar<C>) -> ScalarPrimitive<C> { + ScalarPrimitive::from_bytes(&scalar.to_repr()).unwrap() + } +} + +impl<C> From<SecretKey<C>> for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn from(sk: SecretKey<C>) -> NonZeroScalar<C> { + Self::from(&sk) + } +} + +impl<C> From<&SecretKey<C>> for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn from(sk: &SecretKey<C>) -> NonZeroScalar<C> { + let scalar = sk.as_scalar_primitive().to_scalar(); + debug_assert!(!bool::from(scalar.is_zero())); + Self { scalar } + } +} + +impl<C> Invert for NonZeroScalar<C> +where + C: CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>>, +{ + type Output = Self; + + fn invert(&self) -> Self { + Self { + // This will always succeed since `scalar` will never be 0 + scalar: Invert::invert(&self.scalar).unwrap(), + } + } + + fn invert_vartime(&self) -> Self::Output { + Self { + // This will always succeed since `scalar` will never be 0 + scalar: Invert::invert_vartime(&self.scalar).unwrap(), + } + } +} + +impl<C> IsHigh for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn is_high(&self) -> Choice { + self.scalar.is_high() + } +} + +impl<C> Neg for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + 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 + CurveArithmetic, +{ + 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 + CurveArithmetic, +{ + type Output = Self; + + fn mul(self, other: &Self) -> Self { + // Multiplication is modulo a prime, so the product of two non-zero + // scalars is also non-zero. + let scalar = self.scalar * other.scalar; + debug_assert!(!bool::from(scalar.is_zero())); + NonZeroScalar { scalar } + } +} + +/// Note: this is a non-zero reduction, as it's impl'd for [`NonZeroScalar`]. +impl<C, I> Reduce<I> for NonZeroScalar<C> +where + C: CurveArithmetic, + I: Integer + ArrayEncoding, + Scalar<C>: Reduce<I> + ReduceNonZero<I>, +{ + type Bytes = <Scalar<C> as Reduce<I>>::Bytes; + + fn reduce(n: I) -> Self { + let scalar = Scalar::<C>::reduce_nonzero(n); + debug_assert!(!bool::from(scalar.is_zero())); + Self { scalar } + } + + fn reduce_bytes(bytes: &Self::Bytes) -> Self { + let scalar = Scalar::<C>::reduce_nonzero_bytes(bytes); + debug_assert!(!bool::from(scalar.is_zero())); + Self { scalar } + } +} + +/// Note: forwards to the [`Reduce`] impl. +impl<C, I> ReduceNonZero<I> for NonZeroScalar<C> +where + Self: Reduce<I>, + C: CurveArithmetic, + I: Integer + ArrayEncoding, + Scalar<C>: Reduce<I, Bytes = Self::Bytes> + ReduceNonZero<I>, +{ + fn reduce_nonzero(n: I) -> Self { + Self::reduce(n) + } + + fn reduce_nonzero_bytes(bytes: &Self::Bytes) -> Self { + Self::reduce_bytes(bytes) + } +} + +impl<C> TryFrom<&[u8]> for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + type Error = Error; + + fn try_from(bytes: &[u8]) -> Result<Self, Error> { + if bytes.len() == C::FieldBytesSize::USIZE { + Option::from(NonZeroScalar::from_repr(GenericArray::clone_from_slice( + bytes, + ))) + .ok_or(Error) + } else { + Err(Error) + } + } +} + +impl<C> Zeroize for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn zeroize(&mut self) { + // Use zeroize's volatile writes to ensure value is cleared. + self.scalar.zeroize(); + + // Write a 1 instead of a 0 to ensure this type's non-zero invariant + // is upheld. + self.scalar = Scalar::<C>::ONE; + } +} + +impl<C> fmt::Display for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{self:X}") + } +} + +impl<C> fmt::LowerHex for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + 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: CurveArithmetic, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:}", HexDisplay(&self.to_repr())) + } +} + +impl<C> str::FromStr for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + type Err = Error; + + fn from_str(hex: &str) -> Result<Self, Error> { + 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(feature = "serde")] +impl<C> Serialize for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: ser::Serializer, + { + ScalarPrimitive::from(self).serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, C> Deserialize<'de> for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: de::Deserializer<'de>, + { + let scalar = ScalarPrimitive::deserialize(deserializer)?; + Option::from(Self::new(scalar.into())) + .ok_or_else(|| de::Error::custom("expected non-zero scalar")) + } +} + +#[cfg(all(test, feature = "dev"))] +mod tests { + use crate::dev::{NonZeroScalar, Scalar}; + use ff::{Field, PrimeField}; + use hex_literal::hex; + use zeroize::Zeroize; + + #[test] + fn round_trip() { + let bytes = hex!("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); + let scalar = NonZeroScalar::from_repr(bytes.into()).unwrap(); + assert_eq!(&bytes, scalar.to_repr().as_slice()); + } + + #[test] + fn zeroize() { + let mut scalar = NonZeroScalar::new(Scalar::from(42u64)).unwrap(); + scalar.zeroize(); + assert_eq!(*scalar, Scalar::ONE); + } +} diff --git a/vendor/elliptic-curve/src/scalar/primitive.rs b/vendor/elliptic-curve/src/scalar/primitive.rs new file mode 100644 index 0000000..a4f64cb --- /dev/null +++ b/vendor/elliptic-curve/src/scalar/primitive.rs @@ -0,0 +1,434 @@ +//! Generic scalar type with primitive functionality. + +use crate::{ + bigint::{prelude::*, Limb, NonZero}, + scalar::FromUintUnchecked, + scalar::IsHigh, + Curve, Error, FieldBytes, FieldBytesEncoding, Result, +}; +use base16ct::HexDisplay; +use core::{ + cmp::Ordering, + fmt, + ops::{Add, AddAssign, Neg, ShrAssign, Sub, SubAssign}, + str, +}; +use generic_array::{typenum::Unsigned, GenericArray}; +use rand_core::CryptoRngCore; +use subtle::{ + Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess, + CtOption, +}; +use zeroize::DefaultIsZeroes; + +#[cfg(feature = "arithmetic")] +use super::{CurveArithmetic, Scalar}; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +/// Generic scalar type with primitive functionality. +/// +/// This type provides a baseline level of scalar arithmetic functionality +/// which is always available for all curves, regardless of if they implement +/// any arithmetic traits. +/// +/// # `serde` support +/// +/// When the optional `serde` feature of this create is enabled, [`Serialize`] +/// and [`Deserialize`] impls are provided for this type. +/// +/// The serialization is a fixed-width big endian encoding. When used with +/// textual formats, the binary data is encoded as hexadecimal. +// TODO(tarcieri): use `crypto-bigint`'s `Residue` type, expose more functionality? +#[derive(Copy, Clone, Debug, Default)] +pub struct ScalarPrimitive<C: Curve> { + /// Inner unsigned integer type. + inner: C::Uint, +} + +impl<C> ScalarPrimitive<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 [`ScalarPrimitive`]. + pub fn random(rng: &mut impl CryptoRngCore) -> Self { + Self { + inner: C::Uint::random_mod(rng, &NonZero::new(Self::MODULUS).unwrap()), + } + } + + /// Create a new scalar from [`Curve::Uint`]. + pub fn new(uint: C::Uint) -> CtOption<Self> { + CtOption::new(Self { inner: uint }, uint.ct_lt(&Self::MODULUS)) + } + + /// Decode [`ScalarPrimitive`] from a serialized field element + pub fn from_bytes(bytes: &FieldBytes<C>) -> CtOption<Self> { + Self::new(C::Uint::decode_field_bytes(bytes)) + } + + /// Decode [`ScalarPrimitive`] from a big endian byte slice. + pub fn from_slice(slice: &[u8]) -> Result<Self> { + if slice.len() == C::FieldBytesSize::USIZE { + Option::from(Self::from_bytes(GenericArray::from_slice(slice))).ok_or(Error) + } else { + Err(Error) + } + } + + /// Borrow the inner `C::Uint`. + pub fn as_uint(&self) -> &C::Uint { + &self.inner + } + + /// Borrow the inner limbs as a slice. + pub fn as_limbs(&self) -> &[Limb] { + self.inner.as_ref() + } + + /// Is this [`ScalarPrimitive`] value equal to zero? + pub fn is_zero(&self) -> Choice { + self.inner.is_zero() + } + + /// Is this [`ScalarPrimitive`] value even? + pub fn is_even(&self) -> Choice { + self.inner.is_even() + } + + /// Is this [`ScalarPrimitive`] value odd? + pub fn is_odd(&self) -> Choice { + self.inner.is_odd() + } + + /// Encode [`ScalarPrimitive`] as a serialized field element. + pub fn to_bytes(&self) -> FieldBytes<C> { + self.inner.encode_field_bytes() + } + + /// Convert to a `C::Uint`. + pub fn to_uint(&self) -> C::Uint { + self.inner + } +} + +impl<C> FromUintUnchecked for ScalarPrimitive<C> +where + C: Curve, +{ + type Uint = C::Uint; + + fn from_uint_unchecked(uint: C::Uint) -> Self { + Self { inner: uint } + } +} + +#[cfg(feature = "arithmetic")] +impl<C> ScalarPrimitive<C> +where + C: CurveArithmetic, +{ + /// Convert [`ScalarPrimitive`] into a given curve's scalar type. + pub(super) fn to_scalar(self) -> Scalar<C> { + Scalar::<C>::from_uint_unchecked(self.inner) + } +} + +// TODO(tarcieri): better encapsulate this? +impl<C> AsRef<[Limb]> for ScalarPrimitive<C> +where + C: Curve, +{ + fn as_ref(&self) -> &[Limb] { + self.as_limbs() + } +} + +impl<C> ConditionallySelectable for ScalarPrimitive<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 ScalarPrimitive<C> +where + C: Curve, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.inner.ct_eq(&other.inner) + } +} + +impl<C> ConstantTimeLess for ScalarPrimitive<C> +where + C: Curve, +{ + fn ct_lt(&self, other: &Self) -> Choice { + self.inner.ct_lt(&other.inner) + } +} + +impl<C> ConstantTimeGreater for ScalarPrimitive<C> +where + C: Curve, +{ + fn ct_gt(&self, other: &Self) -> Choice { + self.inner.ct_gt(&other.inner) + } +} + +impl<C: Curve> DefaultIsZeroes for ScalarPrimitive<C> {} + +impl<C: Curve> Eq for ScalarPrimitive<C> {} + +impl<C> PartialEq for ScalarPrimitive<C> +where + C: Curve, +{ + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } +} + +impl<C> PartialOrd for ScalarPrimitive<C> +where + C: Curve, +{ + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl<C> Ord for ScalarPrimitive<C> +where + C: Curve, +{ + fn cmp(&self, other: &Self) -> Ordering { + self.inner.cmp(&other.inner) + } +} + +impl<C> From<u64> for ScalarPrimitive<C> +where + C: Curve, +{ + fn from(n: u64) -> Self { + Self { + inner: C::Uint::from(n), + } + } +} + +impl<C> Add<ScalarPrimitive<C>> for ScalarPrimitive<C> +where + C: Curve, +{ + type Output = Self; + + fn add(self, other: Self) -> Self { + self.add(&other) + } +} + +impl<C> Add<&ScalarPrimitive<C>> for ScalarPrimitive<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<ScalarPrimitive<C>> for ScalarPrimitive<C> +where + C: Curve, +{ + fn add_assign(&mut self, other: Self) { + *self = *self + other; + } +} + +impl<C> AddAssign<&ScalarPrimitive<C>> for ScalarPrimitive<C> +where + C: Curve, +{ + fn add_assign(&mut self, other: &Self) { + *self = *self + other; + } +} + +impl<C> Sub<ScalarPrimitive<C>> for ScalarPrimitive<C> +where + C: Curve, +{ + type Output = Self; + + fn sub(self, other: Self) -> Self { + self.sub(&other) + } +} + +impl<C> Sub<&ScalarPrimitive<C>> for ScalarPrimitive<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<ScalarPrimitive<C>> for ScalarPrimitive<C> +where + C: Curve, +{ + fn sub_assign(&mut self, other: Self) { + *self = *self - other; + } +} + +impl<C> SubAssign<&ScalarPrimitive<C>> for ScalarPrimitive<C> +where + C: Curve, +{ + fn sub_assign(&mut self, other: &Self) { + *self = *self - other; + } +} + +impl<C> Neg for ScalarPrimitive<C> +where + C: Curve, +{ + type Output = Self; + + fn neg(self) -> Self { + Self { + inner: self.inner.neg_mod(&Self::MODULUS), + } + } +} + +impl<C> Neg for &ScalarPrimitive<C> +where + C: Curve, +{ + type Output = ScalarPrimitive<C>; + + fn neg(self) -> ScalarPrimitive<C> { + -*self + } +} + +impl<C> ShrAssign<usize> for ScalarPrimitive<C> +where + C: Curve, +{ + fn shr_assign(&mut self, rhs: usize) { + self.inner >>= rhs; + } +} + +impl<C> IsHigh for ScalarPrimitive<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 ScalarPrimitive<C> +where + C: Curve, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{self:X}") + } +} + +impl<C> fmt::LowerHex for ScalarPrimitive<C> +where + C: Curve, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:x}", HexDisplay(&self.to_bytes())) + } +} + +impl<C> fmt::UpperHex for ScalarPrimitive<C> +where + C: Curve, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:X}", HexDisplay(&self.to_bytes())) + } +} + +impl<C> str::FromStr for ScalarPrimitive<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)?; + Self::from_slice(&bytes) + } +} + +#[cfg(feature = "serde")] +impl<C> Serialize for ScalarPrimitive<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_bytes(), serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, C> Deserialize<'de> for ScalarPrimitive<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)?; + Self::from_slice(&bytes).map_err(|_| de::Error::custom("scalar out of range")) + } +} diff --git a/vendor/elliptic-curve/src/sec1.rs b/vendor/elliptic-curve/src/sec1.rs new file mode 100644 index 0000000..7673386 --- /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, FieldBytesSize, Result, SecretKey}; +use generic_array::GenericArray; +use subtle::CtOption; + +#[cfg(feature = "arithmetic")] +use crate::{AffinePoint, CurveArithmetic, Error}; + +/// Encoded elliptic curve point with point compression. +pub type CompressedPoint<C> = GenericArray<u8, CompressedPointSize<C>>; + +/// Size of a compressed elliptic curve point. +pub type CompressedPointSize<C> = <FieldBytesSize<C> as ModulusSize>::CompressedPointSize; + +/// Encoded elliptic curve point sized appropriately for a given curve. +pub type EncodedPoint<C> = sec1::point::EncodedPoint<FieldBytesSize<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> = <FieldBytesSize<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, + FieldBytesSize<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, + FieldBytesSize<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, + FieldBytesSize<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 [`CurveArithmetic`] will receive +/// a blanket default impl of this trait. +pub trait ValidatePublicKey +where + Self: Curve, + FieldBytesSize<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: CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<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 0000000..607589a --- /dev/null +++ b/vendor/elliptic-curve/src/secret_key.rs @@ -0,0 +1,393 @@ +//! Secret keys for elliptic curves (i.e. private scalars). +//! +//! The [`SecretKey`] type is a wrapper around a secret scalar value which is +//! designed to prevent unintentional exposure (e.g. via `Debug` or other +//! logging). It also handles zeroing the secret value out of memory securely +//! on drop. + +#[cfg(all(feature = "pkcs8", feature = "sec1"))] +mod pkcs8; + +use crate::{Curve, Error, FieldBytes, Result, ScalarPrimitive}; +use core::fmt::{self, Debug}; +use generic_array::typenum::Unsigned; +use subtle::{Choice, ConstantTimeEq}; +use zeroize::{Zeroize, ZeroizeOnDrop}; + +#[cfg(feature = "arithmetic")] +use crate::{rand_core::CryptoRngCore, CurveArithmetic, NonZeroScalar, PublicKey}; + +#[cfg(feature = "jwk")] +use crate::jwk::{JwkEcKey, JwkParameters}; + +#[cfg(feature = "pem")] +use pem_rfc7468::{self as pem, PemLabel}; + +#[cfg(feature = "sec1")] +use { + crate::{ + sec1::{EncodedPoint, ModulusSize, ValidatePublicKey}, + FieldBytesSize, + }, + sec1::der, +}; + +#[cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1"))] +use { + crate::{ + sec1::{FromEncodedPoint, ToEncodedPoint}, + AffinePoint, + }, + alloc::vec::Vec, + sec1::der::Encode, + zeroize::Zeroizing, +}; + +#[cfg(all(feature = "arithmetic", any(feature = "jwk", feature = "pem")))] +use alloc::string::String; + +#[cfg(all(feature = "arithmetic", feature = "jwk"))] +use alloc::string::ToString; + +#[cfg(all(doc, feature = "pkcs8"))] +use {crate::pkcs8::DecodePrivateKey, core::str::FromStr}; + +/// Elliptic curve secret keys. +/// +/// This type wraps a secret scalar value, helping to prevent accidental +/// exposure and securely erasing the value from memory when dropped. +/// +/// # Parsing PKCS#8 Keys +/// +/// PKCS#8 is a commonly used format for encoding secret keys (especially ones +/// generated by OpenSSL). +/// +/// Keys in PKCS#8 format are either binary (ASN.1 BER/DER), or PEM encoded +/// (ASCII) and begin with the following: +/// +/// ```text +/// -----BEGIN PRIVATE KEY----- +/// ``` +/// +/// To decode an elliptic curve private key from PKCS#8, enable the `pkcs8` +/// feature of this crate (or the `pkcs8` feature of a specific RustCrypto +/// elliptic curve crate) and use the [`DecodePrivateKey`] trait to parse it. +/// +/// When the `pem` feature of this crate (or a specific RustCrypto elliptic +/// curve crate) is enabled, a [`FromStr`] impl is also available. +#[derive(Clone)] +pub struct SecretKey<C: Curve> { + /// Scalar value + inner: ScalarPrimitive<C>, +} + +impl<C> SecretKey<C> +where + C: Curve, +{ + /// Generate a random [`SecretKey`]. + #[cfg(feature = "arithmetic")] + pub fn random(rng: &mut impl CryptoRngCore) -> Self + where + C: CurveArithmetic, + { + Self { + inner: NonZeroScalar::<C>::random(rng).into(), + } + } + + /// Create a new secret key from a scalar value. + pub fn new(scalar: ScalarPrimitive<C>) -> Self { + Self { inner: scalar } + } + + /// Borrow the inner secret [`ScalarPrimitive`] value. + /// + /// # ⚠️ Warning + /// + /// This value is key material. + /// + /// Please treat it with the care it deserves! + pub fn as_scalar_primitive(&self) -> &ScalarPrimitive<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")] + pub fn to_nonzero_scalar(&self) -> NonZeroScalar<C> + where + C: CurveArithmetic, + { + self.into() + } + + /// Get the [`PublicKey`] which corresponds to this secret key + #[cfg(feature = "arithmetic")] + pub fn public_key(&self) -> PublicKey<C> + where + C: CurveArithmetic, + { + PublicKey::from_secret_scalar(&self.to_nonzero_scalar()) + } + + /// Deserialize secret key from an encoded secret scalar. + pub fn from_bytes(bytes: &FieldBytes<C>) -> Result<Self> { + let inner: ScalarPrimitive<C> = + Option::from(ScalarPrimitive::from_bytes(bytes)).ok_or(Error)?; + + if inner.is_zero().into() { + return Err(Error); + } + + Ok(Self { inner }) + } + + /// Deserialize secret key from an encoded secret scalar passed as a + /// byte slice. + /// + /// The slice is expected to be at most `C::FieldBytesSize` bytes in + /// length but may be up to 4-bytes shorter than that, which is handled by + /// zero-padding the value. + pub fn from_slice(slice: &[u8]) -> Result<Self> { + if slice.len() > C::FieldBytesSize::USIZE { + return Err(Error); + } + + /// Maximum number of "missing" bytes to interpret as zeroes. + const MAX_LEADING_ZEROES: usize = 4; + + let offset = C::FieldBytesSize::USIZE.saturating_sub(slice.len()); + + if offset == 0 { + Self::from_bytes(FieldBytes::<C>::from_slice(slice)) + } else if offset <= MAX_LEADING_ZEROES { + let mut bytes = FieldBytes::<C>::default(); + bytes[offset..].copy_from_slice(slice); + + let ret = Self::from_bytes(&bytes); + bytes.zeroize(); + ret + } else { + Err(Error) + } + } + + /// Serialize raw secret scalar as a big endian integer. + pub fn to_bytes(&self) -> FieldBytes<C> { + self.inner.to_bytes() + } + + /// Deserialize secret key encoded in the SEC1 ASN.1 DER `ECPrivateKey` format. + #[cfg(all(feature = "sec1"))] + pub fn from_sec1_der(der_bytes: &[u8]) -> Result<Self> + where + C: Curve + ValidatePublicKey, + FieldBytesSize<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"))] + pub fn to_sec1_der(&self) -> der::Result<Zeroizing<Vec<u8>>> + where + C: CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, + { + let private_key_bytes = Zeroizing::new(self.to_bytes()); + let public_key_bytes = self.public_key().to_encoded_point(false); + + let ec_private_key = Zeroizing::new( + sec1::EcPrivateKey { + private_key: &private_key_bytes, + parameters: None, + public_key: Some(public_key_bytes.as_bytes()), + } + .to_der()?, + ); + + Ok(ec_private_key) + } + + /// Parse [`SecretKey`] from PEM-encoded SEC1 `ECPrivateKey` format. + /// + /// PEM-encoded SEC1 keys can be identified by the leading delimiter: + /// + /// ```text + /// -----BEGIN EC PRIVATE KEY----- + /// ``` + #[cfg(feature = "pem")] + pub fn from_sec1_pem(s: &str) -> Result<Self> + where + C: Curve + ValidatePublicKey, + FieldBytesSize<C>: ModulusSize, + { + let (label, der_bytes) = pem::decode_vec(s.as_bytes()).map_err(|_| Error)?; + + if label != sec1::EcPrivateKey::PEM_LABEL { + return Err(Error); + } + + Self::from_sec1_der(&der_bytes).map_err(|_| Error) + } + + /// Serialize private key as self-zeroizing PEM-encoded SEC1 `ECPrivateKey` + /// with the given [`pem::LineEnding`]. + /// + /// Pass `Default::default()` to use the OS's native line endings. + #[cfg(feature = "pem")] + pub fn to_sec1_pem(&self, line_ending: pem::LineEnding) -> Result<Zeroizing<String>> + where + C: CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, + { + self.to_sec1_der() + .ok() + .and_then(|der| { + pem::encode_string(sec1::EcPrivateKey::PEM_LABEL, line_ending, &der).ok() + }) + .map(Zeroizing::new) + .ok_or(Error) + } + + /// Parse a [`JwkEcKey`] JSON Web Key (JWK) into a [`SecretKey`]. + #[cfg(feature = "jwk")] + pub fn from_jwk(jwk: &JwkEcKey) -> Result<Self> + where + C: JwkParameters + ValidatePublicKey, + FieldBytesSize<C>: ModulusSize, + { + Self::try_from(jwk) + } + + /// Parse a string containing a JSON Web Key (JWK) into a [`SecretKey`]. + #[cfg(feature = "jwk")] + pub fn from_jwk_str(jwk: &str) -> Result<Self> + where + C: JwkParameters + ValidatePublicKey, + FieldBytesSize<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"))] + pub fn to_jwk(&self) -> JwkEcKey + where + C: CurveArithmetic + JwkParameters, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, + { + self.into() + } + + /// Serialize this secret key as JSON Web Key (JWK) string. + #[cfg(all(feature = "arithmetic", feature = "jwk"))] + pub fn to_jwk_string(&self) -> Zeroizing<String> + where + C: CurveArithmetic + JwkParameters, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<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 { + f.debug_struct(core::any::type_name::<Self>()) + .finish_non_exhaustive() + } +} + +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"))] +impl<C> TryFrom<sec1::EcPrivateKey<'_>> for SecretKey<C> +where + C: Curve + ValidatePublicKey, + FieldBytesSize<C>: ModulusSize, +{ + type Error = der::Error; + + fn try_from(sec1_private_key: sec1::EcPrivateKey<'_>) -> der::Result<Self> { + let secret_key = Self::from_slice(sec1_private_key.private_key) + .map_err(|_| der::Tag::Sequence.value_error())?; + + // TODO(tarcieri): validate `sec1_private_key.params`? + if let Some(pk_bytes) = sec1_private_key.public_key { + let pk = EncodedPoint::<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")] +impl<C> From<NonZeroScalar<C>> for SecretKey<C> +where + C: CurveArithmetic, +{ + fn from(scalar: NonZeroScalar<C>) -> SecretKey<C> { + SecretKey::from(&scalar) + } +} + +#[cfg(feature = "arithmetic")] +impl<C> From<&NonZeroScalar<C>> for SecretKey<C> +where + C: CurveArithmetic, +{ + 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 0000000..92c81f1 --- /dev/null +++ b/vendor/elliptic-curve/src/secret_key/pkcs8.rs @@ -0,0 +1,90 @@ +//! PKCS#8 encoding/decoding support. + +use super::SecretKey; +use crate::{ + pkcs8::{self, der::Decode, AssociatedOid}, + sec1::{ModulusSize, ValidatePublicKey}, + Curve, FieldBytesSize, ALGORITHM_OID, +}; +use pkcs8::spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, ObjectIdentifier}; +use sec1::EcPrivateKey; + +// Imports for the `EncodePrivateKey` impl +#[cfg(all(feature = "alloc", feature = "arithmetic"))] +use { + crate::{ + sec1::{FromEncodedPoint, ToEncodedPoint}, + AffinePoint, CurveArithmetic, + }, + pkcs8::{der, EncodePrivateKey}, +}; + +// Imports for actual PEM support +#[cfg(feature = "pem")] +use { + crate::{error::Error, Result}, + core::str::FromStr, + pkcs8::DecodePrivateKey, +}; + +impl<C> AssociatedAlgorithmIdentifier for SecretKey<C> +where + C: AssociatedOid + Curve, +{ + type Params = ObjectIdentifier; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<ObjectIdentifier> = AlgorithmIdentifier { + oid: ALGORITHM_OID, + parameters: Some(C::OID), + }; +} + +impl<C> TryFrom<pkcs8::PrivateKeyInfo<'_>> for SecretKey<C> +where + C: AssociatedOid + Curve + ValidatePublicKey, + FieldBytesSize<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(all(feature = "alloc", feature = "arithmetic"))] +impl<C> EncodePrivateKey for SecretKey<C> +where + C: AssociatedOid + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, +{ + fn to_pkcs8_der(&self) -> pkcs8::Result<der::SecretDocument> { + // TODO(tarcieri): make `PrivateKeyInfo` generic around `Params` + let algorithm_identifier = pkcs8::AlgorithmIdentifierRef { + oid: ALGORITHM_OID, + parameters: Some((&C::OID).into()), + }; + + let ec_private_key = self.to_sec1_der()?; + let pkcs8_key = pkcs8::PrivateKeyInfo::new(algorithm_identifier, &ec_private_key); + Ok(der::SecretDocument::encode_msg(&pkcs8_key)?) + } +} + +#[cfg(feature = "pem")] +impl<C> FromStr for SecretKey<C> +where + C: Curve + AssociatedOid + ValidatePublicKey, + FieldBytesSize<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/voprf.rs b/vendor/elliptic-curve/src/voprf.rs new file mode 100644 index 0000000..68f2abf --- /dev/null +++ b/vendor/elliptic-curve/src/voprf.rs @@ -0,0 +1,20 @@ +//! Verifiable Oblivious Pseudorandom Function (VOPRF) using prime order groups +//! +//! <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/> + +use crate::PrimeCurve; + +/// Elliptic curve parameters used by VOPRF. +pub trait VoprfParameters: PrimeCurve { + /// The `ID` parameter which identifies a particular elliptic curve + /// as defined in [section 4 of `draft-irtf-cfrg-voprf-19`][voprf]. + /// + /// [voprf]: https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-19.html#name-ciphersuites-2 + const ID: &'static str; + + /// The `Hash` parameter which assigns a particular hash function to this + /// ciphersuite as defined in [section 4 of `draft-irtf-cfrg-voprf-19`][voprf]. + /// + /// [voprf]: https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-19.html#name-ciphersuites-2 + type Hash: digest::Digest; +} diff --git a/vendor/elliptic-curve/src/weierstrass.rs b/vendor/elliptic-curve/src/weierstrass.rs new file mode 100644 index 0000000..1782d95 --- /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 0000000..c0de45e --- /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 0000000..62f432c --- /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 0000000..67c719c --- /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 0000000..ee7e5b6 --- /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 0000000..2a27fc0 --- /dev/null +++ b/vendor/elliptic-curve/tests/pkcs8.rs @@ -0,0 +1,57 @@ +//! PKCS#8 tests + +#![cfg(all(feature = "dev", feature = "pkcs8"))] + +use elliptic_curve::{ + dev::{PublicKey, SecretKey}, + pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey}, + sec1::ToEncodedPoint, +}; +use hex_literal::hex; +use pkcs8::der; + +/// DER-encoded PKCS#8 public key +const PKCS8_PUBLIC_KEY_DER: &[u8; 91] = include_bytes!("examples/pkcs8-public-key.der"); + +/// PEM-encoded PKCS#8 public key +#[cfg(feature = "pem")] +const PKCS8_PUBLIC_KEY_PEM: &str = include_str!("examples/pkcs8-public-key.pem"); + +/// Example encoded scalar value +const EXAMPLE_SCALAR: [u8; 32] = + hex!("AABBCCDDEEFF0000000000000000000000000000000000000000000000000001"); + +/// Example PKCS#8 private key +fn example_private_key() -> der::SecretDocument { + SecretKey::from_slice(&EXAMPLE_SCALAR) + .unwrap() + .to_pkcs8_der() + .unwrap() +} + +#[test] +fn decode_pkcs8_private_key_from_der() { + dbg!(example_private_key().as_bytes()); + let secret_key = SecretKey::from_pkcs8_der(example_private_key().as_bytes()).unwrap(); + assert_eq!(secret_key.to_bytes().as_slice(), &EXAMPLE_SCALAR); +} + +#[test] +fn decode_pkcs8_public_key_from_der() { + let public_key = PublicKey::from_public_key_der(&PKCS8_PUBLIC_KEY_DER[..]).unwrap(); + let expected_sec1_point = hex!("041CACFFB55F2F2CEFD89D89EB374B2681152452802DEEA09916068137D839CF7FC481A44492304D7EF66AC117BEFE83A8D08F155F2B52F9F618DD447029048E0F"); + assert_eq!( + public_key.to_encoded_point(false).as_bytes(), + &expected_sec1_point[..] + ); +} + +#[test] +#[cfg(feature = "pem")] +fn decode_pkcs8_public_key_from_pem() { + let public_key = PKCS8_PUBLIC_KEY_PEM.parse::<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 0000000..a01de90 --- /dev/null +++ b/vendor/elliptic-curve/tests/secret_key.rs @@ -0,0 +1,28 @@ +//! Secret key tests + +#![cfg(feature = "dev")] + +use elliptic_curve::dev::SecretKey; + +#[test] +fn from_slice_undersize() { + assert!(SecretKey::from_slice(&[]).is_err()); +} + +#[test] +fn from_slice_expected_size() { + let bytes = [1u8; 32]; + assert!(SecretKey::from_slice(&bytes).is_ok()); +} + +#[test] +fn from_slice_allowed_short() { + let bytes = [1u8; 28]; + assert!(SecretKey::from_slice(&bytes).is_ok()); +} + +#[test] +fn from_slice_too_short() { + let bytes = [1u8; 27]; + assert!(SecretKey::from_slice(&bytes).is_err()); +} |