chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

View File

@@ -0,0 +1 @@
{"files":{".cargo_vcs_info.json":"74b6e164fec5005e4ab2780220a4137f13b2363b7f2997b06c5e54b77204ddb4","CHANGELOG.md":"0b10798f0b729a76ffe1799c4ff8eb8264c784207150daac900e470a5d84b48a","Cargo.toml":"ae28aa3db758a5b18bf9e4b1253082b2503067f41be65e0bf3dc89917fda3f76","Cargo.toml.orig":"580f6b2aacbaec0f3e208c62156c2f691c28d26024ff14bfd2b2079ed7dc7f75","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"d27687b51f2874822c1530976b7e837eac4f308d94bf3dd42047011b7d437b47","README.md":"1ec3f5114bbba41528da8017c76a5d7f5cd995ae444705c279b776eeea350216","src/arithmetic.rs":"55be3c0cefb168a0768af743974007707ce95e98e89281818db9b69b4ba8f9cd","src/dev.rs":"15883bd44409ec62ab5cf8bb9fe96bca545a950f571487d1a0ddc846e891f2cc","src/ecdh.rs":"5cc59b8a2a5397be43deba006ca9d9fc608be1676d80c1f5c017af66bf72ad98","src/error.rs":"8aedd93298b729ee396bc1a31754119130fbf865cb1e330c65be178cbbb0d1e4","src/field.rs":"ffc3897dfb36f8d27de7ce96269cae4541b4587c4d9c94a9ce6d177819036624","src/hash2curve.rs":"861857145cc973ca64fc765731dada9aa3d7d97f61d324f6dba2aacc2d5e2135","src/hash2curve/group_digest.rs":"b9b52633c72158475bb059a1a36f61f04c8aa56a9188a83bcd6671996e5d4725","src/hash2curve/hash2field.rs":"762f662fa018db76af9bbae04e44a68e1279a638699648448ae1a28a51607150","src/hash2curve/hash2field/expand_msg.rs":"7615b8d2ba958a6d11d0f50143b9c2aa78649ea7c2dd87d16f2da4cf09578e50","src/hash2curve/hash2field/expand_msg/xmd.rs":"5a85d4084395e924bbb2e32640beaba8c8c8476695e70baf0b341155a6a5dd87","src/hash2curve/hash2field/expand_msg/xof.rs":"42bf7796706105e8d521137679a458e0c9e2ed3463adaa0f1c505b5d9bb2804d","src/hash2curve/isogeny.rs":"bd43364cedd8809a51b40c11743cf703d8e18268463dc75562520c8a624b5039","src/hash2curve/map2curve.rs":"fc05c553ccd92de762e083f02079581376e8e4a193acd0d902cfdb33f59ce10a","src/hash2curve/osswu.rs":"184d5bee8669722e9ef20523c064b3a769be49a6b62c4827818894199be94820","src/jwk.rs":"31d5f33bf559eae553a53adfce56cd094103b97482a1daf5224a581bba1fe8e6","src/lib.rs":"24db533221762c4e504428821f79bd3508a2dfaeef21ae3a67ece7d5d65da6c7","src/ops.rs":"23460c86fe3a07e07a446b7bceb164b99551943e4668ae7e04256f5177f3470f","src/point.rs":"f6acdd908cab4bdf399e4274ea76df67c577c4692dd9052bf7e4511c47ac5e24","src/point/non_identity.rs":"80a2b46aa22d5824a6f06d6f7855cb51285b7fa4dfeaa1eb05f3e57e390f33db","src/public_key.rs":"392da0745b3fb931c9072de88d6278729e223e27e2700b93bf50d941bc285ed1","src/scalar.rs":"0702d705b63732f62b6a7eaaf630ee5007b81623c0b0722e9712aa82f762fcd5","src/scalar/blinded.rs":"a6e7656c934eea2048e8047a5b13889b3344f5e54083d90e1d85839471155f26","src/scalar/nonzero.rs":"e485dad71df0e161a354ab9998ed155f3ae19a63be5b41d5c368fe942a21d329","src/scalar/primitive.rs":"19363dfc72b339c06e41ea60a1205fed5f301e7ec144feee22ea05a9c3aa4576","src/sec1.rs":"0e6e89979590ef2c38a006517fd0e5237f1be6682aaad5bae913792a99b34fa6","src/secret_key.rs":"a08c354ea59da20e20628ce66da790822f3f90ee5820ab449ed64229d9270783","src/secret_key/pkcs8.rs":"26b9171c1c7c0321419425188b3d317624040161f29e5521a250299ebcbfd536","src/voprf.rs":"d6a7d8596163bbab3d183526ffa8882bb4de279772f992dc2d261cce6d17efba","src/weierstrass.rs":"b49e30b886ca5ee8a6725fa34d5c58108ee844888b73e5983856c7e2740bc9e2","tests/examples/pkcs8-private-key.der":"8125ab208d2181ed3ef05ff0ab1906e5898c36a858277e5b987e78e505288769","tests/examples/pkcs8-private-key.pem":"e0d0ce22e72577e5d00d7b8d65288f158032402fc9dbcaf63dc771d0eb91ae5f","tests/examples/pkcs8-public-key.der":"b9968d56ed8d6aa3fb43b15fa01e355d7a3a0203b1408b3fd2733637c4d1642c","tests/examples/pkcs8-public-key.pem":"d1ff198dc495da63f5f909db0254d6e49cff519487fcb26d055a762fc3ca47a1","tests/pkcs8.rs":"b69f29997a46fe4be1bf5b7b27b9efa501403b4a9fc8fa9733144f94d9683501","tests/secret_key.rs":"25f79615433b503db00588209bac723d0daea1c76c8a8a52f44b2fbc59b00f5c"},"package":"b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"}

View File

@@ -0,0 +1,6 @@
{
"git": {
"sha1": "5ddf0f52f07f65f319ffd423c52e696406924d90"
},
"path_in_vcs": "elliptic-curve"
}

811
vendor/elliptic-curve/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,811 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 0.13.8 (2023-11-18)
### Changed
- `SecretKey::from_slice` now allows >=24-bytes ([#1412])
[#1412]: https://github.com/RustCrypto/traits/pull/1412
## 0.13.7 (2023-11-15)
### Added
- `BatchInvert` and `BatchNormalize` traits ([#1376])
- `LinearCombinationExt` trait ([#1405])
[#1376]: https://github.com/RustCrypto/traits/pull/1376
[#1405]: https://github.com/RustCrypto/traits/pull/1405
## 0.13.6 (2023-10-02)
### Fixed
- Minimum supported `hkdf` version is v0.12.1 ([#1353])
- Minimum supported `serde_json` version for `jwk` feature is v1.0.47 ([#1354])
- Minimum supported `tap` version for `bits` feature is v1.0.1 ([#1355])
[#1353]: https://github.com/RustCrypto/traits/pull/1353
[#1354]: https://github.com/RustCrypto/traits/pull/1354
[#1355]: https://github.com/RustCrypto/traits/pull/1355
## 0.13.5 (2023-05-19)
### Changed
- Faster `PublicKey::from_encoded_point` ([#1310])
### Fixed
- `alloc`+`arithmetic` features w/o `sec1` feature ([#1301])
[#1301]: https://github.com/RustCrypto/traits/pull/1301
[#1310]: https://github.com/RustCrypto/traits/pull/1310
## 0.13.4 (2023-04-08)
### Changed
- Bump `hex-literal` to v0.4 ([#1295])
### Fixed
- `NonZeroScalar::from_slice` ([#1296])
- `ScalarPrimitive::from_slice` ([#1296])
[#1295]: https://github.com/RustCrypto/traits/pull/1295
[#1296]: https://github.com/RustCrypto/traits/pull/1296
## 0.13.3 (2023-04-04)
### Added
- Impl `AssociatedAlgorithmIdentifier` for `SecretKey` and `PublicKey` ([#1286])
### Changed
- Update OSSWU code ([#1157])
- Bump `pkcs8` to v0.10.2 ([#1291])
### Fixed
- `FieldBytesEncoding` provided impl ([#1287])
[#1157]: https://github.com/RustCrypto/traits/pull/1157
[#1286]: https://github.com/RustCrypto/traits/pull/1286
[#1287]: https://github.com/RustCrypto/traits/pull/1287
[#1291]: https://github.com/RustCrypto/traits/pull/1291
## 0.13.2 (2023-03-08)
### Added
- Weakly activate `pkcs8?/std` ([#1263])
- More `PublicKey` <-> SEC1 conversions ([#1272])
[#1263]: https://github.com/RustCrypto/traits/pull/1263
[#1272]: https://github.com/RustCrypto/traits/pull/1272
## 0.13.1 (2023-03-01)
### Added
- `SecretKey::from_slice` short input support ([#1256])
[#1256]: https://github.com/RustCrypto/traits/pull/1256
## 0.13.0 (2023-02-28)
### Added
- `PublicKey::to_sec1_bytes` ([#1102])
- Forward `std` feature to `sec1` dependency ([#1131])
- `NonIdentity` wrapper type ([#1176])
- Impl `serde` traits for `NonZeroScalar` ([#1178])
- `MulByGenerator` trait ([#1198])
- `NonZeroScalar::invert_vartime` ([#1207])
- `BlindedScalar` type ([#1208])
- `point::Double` trait ([#1218])
- `FieldBytesEncoding` trait ([#1235])
- `Invert::invert_vartime` ([#1239])
### Changed
- Allow bigger `c1` constant in `OsswuMapParams` ([#1024])
- Rename `Curve::UInt` => `Curve::Uint` ([#1191])
- Use weak feature activation ([#1192], [#1194])
- Consolidate `CurveArithmetic` trait ([#1196])
- Rename `SecretKey::to_pem` => `::to_sec1_pem` ([#1202])
- Rename `ScalarCore` to `ScalarPrimitive` ([#1203])
- Use `CryptoRngCore` trait ([#1206])
- Refactor field element decoding/encoding ([#1220])
- Update VOPRF identifier type ([#1175])
- Rename `SecretKey::as_scalar_core` => `::as_scalar_primitive` ([#1228])
- Rename `Reduce::from_bytes_reduced` => `::reduce_bytes` ([#1225], [#1229])
- Consolidate `AffineCoordinates` trait ([#1237])
- Allow multiple `dst`s in the `hash2curve` API ([#1238])
- Have `serde` feature activate `pkcs8` ([#1245])
- Dependency upgrades:
- `base16ct` ([#1254])
- `crypto-bigint` v0.5 ([#1251])
- `ff` and `group` v0.13 ([#1166])
- `pem-rfc7468` v0.7 ([#1251])
- `pkcs8` v0.10 ([#1251])
- `sec1` v0.7 ([#1251])
- `serdect` v0.2 ([#1251])
### Removed
- `impl_field_element!` macro ([#1165])
- Direct `der` crate dependency ([#1195])
- `AffineArithmetic`, `ProjectiveArithmetic`, `ScalarArithmetic` traits ([#1196])
- Toplevel re-exports except for `AffinePoint`, `ProjectivePoint`, and `Scalar` ([#1223])
- `Reduce` methods ([#1225])
- Blanket impl for `Invert` ([#1242])
[#1024]: https://github.com/RustCrypto/traits/pull/1024
[#1102]: https://github.com/RustCrypto/traits/pull/1102
[#1131]: https://github.com/RustCrypto/traits/pull/1131
[#1165]: https://github.com/RustCrypto/traits/pull/1165
[#1166]: https://github.com/RustCrypto/traits/pull/1166
[#1175]: https://github.com/RustCrypto/traits/pull/1175
[#1176]: https://github.com/RustCrypto/traits/pull/1176
[#1178]: https://github.com/RustCrypto/traits/pull/1178
[#1191]: https://github.com/RustCrypto/traits/pull/1191
[#1192]: https://github.com/RustCrypto/traits/pull/1192
[#1194]: https://github.com/RustCrypto/traits/pull/1194
[#1195]: https://github.com/RustCrypto/traits/pull/1195
[#1196]: https://github.com/RustCrypto/traits/pull/1196
[#1198]: https://github.com/RustCrypto/traits/pull/1198
[#1202]: https://github.com/RustCrypto/traits/pull/1202
[#1203]: https://github.com/RustCrypto/traits/pull/1203
[#1206]: https://github.com/RustCrypto/traits/pull/1206
[#1207]: https://github.com/RustCrypto/traits/pull/1207
[#1208]: https://github.com/RustCrypto/traits/pull/1208
[#1218]: https://github.com/RustCrypto/traits/pull/1218
[#1220]: https://github.com/RustCrypto/traits/pull/1220
[#1223]: https://github.com/RustCrypto/traits/pull/1223
[#1225]: https://github.com/RustCrypto/traits/pull/1225
[#1228]: https://github.com/RustCrypto/traits/pull/1228
[#1229]: https://github.com/RustCrypto/traits/pull/1229
[#1235]: https://github.com/RustCrypto/traits/pull/1235
[#1237]: https://github.com/RustCrypto/traits/pull/1237
[#1238]: https://github.com/RustCrypto/traits/pull/1238
[#1239]: https://github.com/RustCrypto/traits/pull/1239
[#1242]: https://github.com/RustCrypto/traits/pull/1242
[#1245]: https://github.com/RustCrypto/traits/pull/1245
[#1251]: https://github.com/RustCrypto/traits/pull/1251
[#1254]: https://github.com/RustCrypto/traits/pull/1254
## 0.12.3 (2022-08-01)
### Added
- Aliases for SEC1 compressed/uncompressed points ([#1067])
### Fixed
- `arithmetic` + `serde` feature combo ([#1066])
[#1066]: https://github.com/RustCrypto/traits/pull/1066
[#1067]: https://github.com/RustCrypto/traits/pull/1067
## 0.12.2 (2022-07-01)
### Changed
- Bump `crypto-bigint` to v0.4.8 ([#1039])
[#1039]: https://github.com/RustCrypto/traits/pull/1039
## 0.12.1 (2022-06-12)
### Added
- `impl_field_element!` macro ([#1021])
- Generic impl of complete prime order formulas ([#1022])
### Changed
- Bump `crypto-bigint` to v0.4.4 ([#1018], [#1020])
[#1018]: https://github.com/RustCrypto/traits/pull/1018
[#1020]: https://github.com/RustCrypto/traits/pull/1020
[#1021]: https://github.com/RustCrypto/traits/pull/1021
[#1022]: https://github.com/RustCrypto/traits/pull/1022
## 0.12.0 (2022-05-08)
### Added
- `ecdh::SharedSecret::extract` HKDF helper ([#1007])
### Changed
- Bump `digest` dependency to v0.10 ([#883], [#904])
- Make `NonZeroScalar::invert` infallible ([#894])
- `ToCompactEncodedPoint` now returns `CtOption` ([#895])
- Move `hash2field` into `hash2curve` module ([#903])
- Bump `ff` and `group` dependencies to v0.12 ([#994])
- Use `serdect` crate ([#996])
- Replace `AlgorithmParamters` with `AssociatedOid` ([#1001])
- Bump `crypto-bigint` dependency to v0.4 ([#1005])
- Bump `der` dependency to v0.6 ([#1006])
- Bump `pkcs8` dependency to v0.9 ([#1006])
- Bump `sec1` dependency to v0.3 ([#1006])
- Bump `pem-rfc7468` dependency to v0.6 ([#1009])
### Removed
- `Zeroize` impl from `ecdh::SharedSecret` ([#978])
[#883]: https://github.com/RustCrypto/traits/pull/883
[#894]: https://github.com/RustCrypto/traits/pull/894
[#895]: https://github.com/RustCrypto/traits/pull/895
[#903]: https://github.com/RustCrypto/traits/pull/903
[#904]: https://github.com/RustCrypto/traits/pull/904
[#978]: https://github.com/RustCrypto/traits/pull/978
[#994]: https://github.com/RustCrypto/traits/pull/994
[#996]: https://github.com/RustCrypto/traits/pull/996
[#1001]: https://github.com/RustCrypto/traits/pull/1001
[#1005]: https://github.com/RustCrypto/traits/pull/1005
[#1006]: https://github.com/RustCrypto/traits/pull/1006
[#1007]: https://github.com/RustCrypto/traits/pull/1007
[#1009]: https://github.com/RustCrypto/traits/pull/1009
## 0.11.12 (2022-01-30)
### Changed
- Disable `bits` feature on docs.rs due to nightly breakage ([#927])
[#927]: https://github.com/RustCrypto/traits/pull/927
## 0.11.11 (2022-01-30)
- No changes; triggering a docs.rs rebuild
## 0.11.10 (2022-01-27)
### Changed
- Revert [#884] to support a wider range of `zeroize` versions ([#923])
[#923]: https://github.com/RustCrypto/traits/pull/891
## 0.11.9 (2022-01-17) [YANKED]
### Changed
- Activate `bits`, `hash2curve`, and `voprf` features on docs.rs ([#891])
[#891]: https://github.com/RustCrypto/traits/pull/891
## 0.11.8 (2022-01-15) [YANKED]
### Added
- Impl `ZeroizeOnDrop` on appropriate items ([#884])
### Changed
- Use the `base16ct` crate for hex serialization ([#886], [#887], [#888])
[#884]: https://github.com/RustCrypto/traits/pull/884
[#886]: https://github.com/RustCrypto/traits/pull/886
[#887]: https://github.com/RustCrypto/traits/pull/887
[#888]: https://github.com/RustCrypto/traits/pull/888
## 0.11.7 (2022-01-14) [YANKED]
### Added
- Initial hash-to-field support ([#854], [#855], [#871], [#874])
- Initial hash-to-curve support ([#865], [#876])
- Impl `Mul` for `NonZeroScalar` * `NonZeroScalar` ([#857], [#862])
- `Reduce::from_*e_digest_reduced` ([#869])
- `VoprfParameters` trait ([#878])
[#854]: https://github.com/RustCrypto/traits/pull/854
[#855]: https://github.com/RustCrypto/traits/pull/855
[#857]: https://github.com/RustCrypto/traits/pull/857
[#862]: https://github.com/RustCrypto/traits/pull/862
[#865]: https://github.com/RustCrypto/traits/pull/865
[#869]: https://github.com/RustCrypto/traits/pull/869
[#871]: https://github.com/RustCrypto/traits/pull/871
[#874]: https://github.com/RustCrypto/traits/pull/874
[#876]: https://github.com/RustCrypto/traits/pull/876
[#878]: https://github.com/RustCrypto/traits/pull/878
## 0.11.6 (2021-12-20)
### Added
- Type conversions chart ([#852])
[#852]: https://github.com/RustCrypto/traits/pull/852
## 0.11.5 (2021-12-05)
### Changed
- Revised `LinearCombination` trait ([#835])
[#835]: https://github.com/RustCrypto/traits/pull/835
## 0.11.4 (2021-12-04) [YANKED]
### Added
- `LinearCombination` trait ([#832])
[#832]: https://github.com/RustCrypto/traits/pull/832
## 0.11.3 (2021-12-03) [YANKED]
### Added
- `ReduceNonZero` trait ([#827])
[#827]: https://github.com/RustCrypto/traits/pull/827
## 0.11.2 (2021-12-03) [YANKED]
### Changed
- Bump `pem-rfc7468` dependency to v0.3 ([#825])
[#825]: https://github.com/RustCrypto/traits/pull/825
## 0.11.1 (2021-11-21) [YANKED]
### Added
- `NonZeroScalar::from_uint` ([#822])
[#822]: https://github.com/RustCrypto/traits/pull/822
## 0.11.0 (2021-11-19) [YANKED]
### Added
- `ScalarCore<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

220
vendor/elliptic-curve/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,220 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
rust-version = "1.65"
name = "elliptic-curve"
version = "0.13.8"
authors = ["RustCrypto Developers"]
description = """
General purpose Elliptic Curve Cryptography (ECC) support, including types
and traits for representing various elliptic curve forms, scalars, points,
and public/secret keys composed thereof.
"""
readme = "README.md"
keywords = [
"crypto",
"ecc",
"elliptic",
"weierstrass",
]
categories = [
"cryptography",
"no-std",
]
license = "Apache-2.0 OR MIT"
repository = "https://github.com/RustCrypto/traits/tree/master/elliptic-curve"
[package.metadata.docs.rs]
features = [
"bits",
"ecdh",
"hash2curve",
"jwk",
"pem",
"std",
"voprf",
]
rustdoc-args = [
"--cfg",
"docsrs",
]
[dependencies.base16ct]
version = "0.2"
[dependencies.base64ct]
version = "1"
features = ["alloc"]
optional = true
default-features = false
[dependencies.crypto-bigint]
version = "0.5"
features = [
"rand_core",
"generic-array",
"zeroize",
]
default-features = false
[dependencies.digest]
version = "0.10"
optional = true
[dependencies.ff]
version = "0.13"
optional = true
default-features = false
[dependencies.generic-array]
version = "0.14.6"
features = ["zeroize"]
default-features = false
[dependencies.group]
version = "0.13"
optional = true
default-features = false
[dependencies.hex-literal]
version = "0.4"
optional = true
[dependencies.hkdf]
version = "0.12.1"
optional = true
default-features = false
[dependencies.pem-rfc7468]
version = "0.7"
features = ["alloc"]
optional = true
[dependencies.pkcs8]
version = "0.10.2"
optional = true
default-features = false
[dependencies.rand_core]
version = "0.6.4"
default-features = false
[dependencies.sec1]
version = "0.7.1"
features = [
"subtle",
"zeroize",
]
optional = true
[dependencies.serde_json]
version = "1.0.47"
features = ["alloc"]
optional = true
default-features = false
[dependencies.serdect]
version = "0.2"
features = ["alloc"]
optional = true
default-features = false
[dependencies.subtle]
version = "2"
default-features = false
[dependencies.tap]
version = "1.0.1"
optional = true
default-features = false
[dependencies.zeroize]
version = "1.7"
default-features = false
[dev-dependencies.hex-literal]
version = "0.4"
[dev-dependencies.sha2]
version = "0.10"
[dev-dependencies.sha3]
version = "0.10"
[features]
alloc = [
"base16ct/alloc",
"ff?/alloc",
"group?/alloc",
"pkcs8?/alloc",
"sec1?/alloc",
"zeroize/alloc",
]
arithmetic = ["group"]
bits = [
"arithmetic",
"ff/bits",
"dep:tap",
]
default = ["arithmetic"]
dev = [
"arithmetic",
"dep:hex-literal",
"pem",
"pkcs8",
]
ecdh = [
"arithmetic",
"digest",
"dep:hkdf",
]
group = [
"dep:group",
"ff",
]
hash2curve = [
"arithmetic",
"digest",
]
hazmat = []
jwk = [
"dep:base64ct",
"dep:serde_json",
"alloc",
"serde",
"zeroize/alloc",
]
pem = [
"dep:pem-rfc7468",
"alloc",
"arithmetic",
"pkcs8",
"sec1/pem",
]
pkcs8 = [
"dep:pkcs8",
"sec1",
]
serde = [
"dep:serdect",
"alloc",
"pkcs8",
"sec1/serde",
]
std = [
"alloc",
"rand_core/std",
"pkcs8?/std",
"sec1?/std",
]
voprf = ["digest"]

201
vendor/elliptic-curve/LICENSE-APACHE vendored Normal file
View File

@@ -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.

25
vendor/elliptic-curve/LICENSE-MIT vendored Normal file
View File

@@ -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.

54
vendor/elliptic-curve/README.md vendored Normal file
View File

@@ -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

86
vendor/elliptic-curve/src/arithmetic.rs vendored Normal file
View File

@@ -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>;
}

843
vendor/elliptic-curve/src/dev.rs vendored Normal file
View File

@@ -0,0 +1,843 @@
//! Development-related functionality.
//!
//! Helpers and types for writing tests against concrete implementations of
//! the traits in this crate.
use crate::{
bigint::{Limb, U256},
error::{Error, Result},
generic_array::typenum::U32,
ops::{Invert, LinearCombination, MulByGenerator, Reduce, ShrAssign},
pkcs8,
point::AffineCoordinates,
rand_core::RngCore,
scalar::{FromUintUnchecked, IsHigh},
sec1::{CompressedPoint, FromEncodedPoint, ToEncodedPoint},
subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
zeroize::DefaultIsZeroes,
Curve, CurveArithmetic, FieldBytesEncoding, PrimeCurve,
};
use core::{
iter::{Product, Sum},
ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use ff::{Field, PrimeField};
use hex_literal::hex;
use pkcs8::AssociatedOid;
#[cfg(feature = "bits")]
use ff::PrimeFieldBits;
#[cfg(feature = "jwk")]
use crate::JwkParameters;
/// Pseudo-coordinate for fixed-based scalar mult output
pub const PSEUDO_COORDINATE_FIXED_BASE_MUL: [u8; 32] =
hex!("deadbeef00000000000000000000000000000000000000000000000000000001");
/// SEC1 encoded point.
pub type EncodedPoint = crate::sec1::EncodedPoint<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;
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());
}
}

236
vendor/elliptic-curve/src/ecdh.rs vendored Normal file
View File

@@ -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()
}
}

42
vendor/elliptic-curve/src/error.rs vendored Normal file
View File

@@ -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 {}

51
vendor/elliptic-curve/src/field.rs vendored Normal file
View File

@@ -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
}
}

15
vendor/elliptic-curve/src/hash2curve.rs vendored Normal file
View File

@@ -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::*;

View File

@@ -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])
}
}

View File

@@ -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(())
}

View File

@@ -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]);
}
}

View File

@@ -0,0 +1,451 @@
//! `expand_message_xmd` based on a hash function.
use core::marker::PhantomData;
use super::{Domain, ExpandMsg, Expander};
use crate::{Error, Result};
use digest::{
core_api::BlockSizeUser,
generic_array::{
typenum::{IsLess, IsLessOrEqual, Unsigned, U256},
GenericArray,
},
FixedOutput, HashMarker,
};
/// Placeholder type for implementing `expand_message_xmd` based on a hash function
///
/// # Errors
/// - `dst.is_empty()`
/// - `len_in_bytes == 0`
/// - `len_in_bytes > u16::MAX`
/// - `len_in_bytes > 255 * HashT::OutputSize`
pub struct ExpandMsgXmd<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 {
#[allow(clippy::panic_in_result_fn)]
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(())
}
}

View File

@@ -0,0 +1,348 @@
//! `expand_message_xof` for the `ExpandMsg` trait
use super::{Domain, ExpandMsg, Expander};
use crate::{Error, Result};
use digest::{ExtendableOutput, Update, XofReader};
use generic_array::typenum::U32;
/// Placeholder type for implementing `expand_message_xof` based on an extendable output function
///
/// # Errors
/// - `dst.is_empty()`
/// - `len_in_bytes == 0`
/// - `len_in_bytes > u16::MAX`
pub struct ExpandMsgXof<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(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 {
#[allow(clippy::panic_in_result_fn)]
fn assert<HashT, L>(&self, dst: &'static [u8], domain: &Domain<'_, U32>) -> Result<()>
where
HashT: Default + ExtendableOutput + Update,
L: ArrayLength<u8>,
{
assert_message(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(())
}
}

View File

@@ -0,0 +1,57 @@
//! Traits for mapping an isogeny to another curve
//!
//! <https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve>
use core::ops::{AddAssign, Mul};
use ff::Field;
use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
/// The coefficients for mapping from one isogenous curve to another
pub struct IsogenyCoefficients<F: Field + AddAssign + Mul<Output = F>> {
/// The coefficients for the x numerator
pub xnum: &'static [F],
/// The coefficients for the x denominator
pub xden: &'static [F],
/// The coefficients for the y numerator
pub ynum: &'static [F],
/// The coefficients for the x denominator
pub yden: &'static [F],
}
/// The [`Isogeny`] methods to map to another curve.
pub trait Isogeny: Field + AddAssign + Mul<Output = Self> {
/// The maximum number of coefficients
type Degree: ArrayLength<Self>;
/// The isogeny coefficients
const COEFFICIENTS: IsogenyCoefficients<Self>;
/// Map from the isogeny points to the main curve
fn isogeny(x: Self, y: Self) -> (Self, Self) {
let mut xs = GenericArray::<Self, Self::Degree>::default();
xs[0] = Self::ONE;
xs[1] = x;
xs[2] = x.square();
for i in 3..Self::Degree::to_usize() {
xs[i] = xs[i - 1] * x;
}
let x_num = Self::compute_iso(&xs, Self::COEFFICIENTS.xnum);
let x_den = Self::compute_iso(&xs, Self::COEFFICIENTS.xden)
.invert()
.unwrap();
let y_num = Self::compute_iso(&xs, Self::COEFFICIENTS.ynum) * y;
let y_den = Self::compute_iso(&xs, Self::COEFFICIENTS.yden)
.invert()
.unwrap();
(x_num * x_den, y_num * y_den)
}
/// Compute the ISO transform
fn compute_iso(xxs: &[Self], k: &[Self]) -> Self {
let mut xx = Self::ZERO;
for (xi, ki) in xxs.iter().zip(k.iter()) {
xx += *xi * ki;
}
xx
}
}

View File

@@ -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;
}

View File

@@ -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)
}
}

675
vendor/elliptic-curve/src/jwk.rs vendored Normal file
View File

@@ -0,0 +1,675 @@
//! 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 {
#![allow(clippy::unwrap_used, clippy::panic)]
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);
}
}

196
vendor/elliptic-curve/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,196 @@
#![no_std]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc = include_str!("../README.md")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
)]
#![forbid(unsafe_code)]
#![warn(
clippy::cast_lossless,
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
clippy::cast_precision_loss,
clippy::cast_sign_loss,
clippy::checked_conversions,
clippy::implicit_saturating_sub,
clippy::mod_module_files,
clippy::panic,
clippy::panic_in_result_fn,
clippy::unwrap_used,
missing_docs,
rust_2018_idioms,
unused_lifetimes,
unused_qualifications
)]
//! ## Usage
//!
//! This crate provides traits for describing elliptic curves, along with
//! types which are generic over elliptic curves which can be used as the
//! basis of curve-agnostic code.
//!
//! It's intended to be used with the following concrete elliptic curve
//! implementations from the [`RustCrypto/elliptic-curves`] project:
//!
//! - [`bp256`]: brainpoolP256r1 and brainpoolP256t1
//! - [`bp384`]: brainpoolP384r1 and brainpoolP384t1
//! - [`k256`]: secp256k1 a.k.a. K-256
//! - [`p224`]: NIST P-224 a.k.a. secp224r1
//! - [`p256`]: NIST P-256 a.k.a secp256r1, prime256v1
//! - [`p384`]: NIST P-384 a.k.a. secp384r1
//! - [`p521`]: NIST P-521 a.k.a. secp521r1
//!
//! The [`ecdsa`] crate provides a generic implementation of the
//! Elliptic Curve Digital Signature Algorithm which can be used with any of
//! the above crates, either via an external ECDSA implementation, or
//! using native curve arithmetic where applicable.
//!
//! ## Type conversions
//!
//! The following chart illustrates the various conversions possible between
//! the various types defined by this crate.
//!
//! ![Type Conversion Map](https://raw.githubusercontent.com/RustCrypto/media/master/img/elliptic-curve/type-transforms.svg)
//!
//! ## `serde` support
//!
//! When the `serde` feature of this crate is enabled, `Serialize` and
//! `Deserialize` impls are provided for the following types:
//!
//! - [`JwkEcKey`]
//! - [`PublicKey`]
//! - [`ScalarPrimitive`]
//!
//! Please see type-specific documentation for more information.
//!
//! [`RustCrypto/elliptic-curves`]: https://github.com/RustCrypto/elliptic-curves
//! [`bp256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/bp256
//! [`bp384`]: https://github.com/RustCrypto/elliptic-curves/tree/master/bp384
//! [`k256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/k256
//! [`p224`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p224
//! [`p256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p256
//! [`p384`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p384
//! [`p521`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p521
//! [`ecdsa`]: https://github.com/RustCrypto/signatures/tree/master/ecdsa
#[cfg(feature = "alloc")]
#[allow(unused_imports)]
#[macro_use]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
pub mod point;
pub mod scalar;
#[cfg(feature = "dev")]
pub mod dev;
#[cfg(feature = "ecdh")]
pub mod ecdh;
#[cfg(feature = "hash2curve")]
pub mod hash2curve;
#[cfg(feature = "arithmetic")]
pub mod ops;
#[cfg(feature = "sec1")]
pub mod sec1;
#[cfg(feature = "arithmetic")]
pub mod weierstrass;
mod error;
mod field;
mod secret_key;
#[cfg(feature = "arithmetic")]
mod arithmetic;
#[cfg(feature = "arithmetic")]
mod public_key;
#[cfg(feature = "jwk")]
mod jwk;
#[cfg(feature = "voprf")]
mod voprf;
pub use crate::{
error::{Error, Result},
field::{FieldBytes, FieldBytesEncoding, FieldBytesSize},
scalar::ScalarPrimitive,
secret_key::SecretKey,
};
pub use crypto_bigint as bigint;
pub use generic_array::{self, typenum::consts};
pub use rand_core;
pub use subtle;
pub use zeroize;
#[cfg(feature = "arithmetic")]
pub use {
crate::{
arithmetic::{CurveArithmetic, PrimeCurveArithmetic},
point::{AffinePoint, BatchNormalize, ProjectivePoint},
public_key::PublicKey,
scalar::{NonZeroScalar, Scalar},
},
ff::{self, Field, PrimeField},
group::{self, Group},
};
#[cfg(feature = "jwk")]
pub use crate::jwk::{JwkEcKey, JwkParameters};
#[cfg(feature = "pkcs8")]
pub use pkcs8;
#[cfg(feature = "voprf")]
pub use crate::voprf::VoprfParameters;
use core::{
fmt::Debug,
ops::{Add, ShrAssign},
};
use generic_array::ArrayLength;
/// Algorithm [`ObjectIdentifier`][`pkcs8::ObjectIdentifier`] for elliptic
/// curve public key cryptography (`id-ecPublicKey`).
///
/// <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 {}

229
vendor/elliptic-curve/src/ops.rs vendored Normal file
View File

@@ -0,0 +1,229 @@
//! Traits for arithmetic operations on elliptic curve field elements.
pub use core::ops::{Add, AddAssign, Mul, Neg, Shr, ShrAssign, Sub, SubAssign};
use crypto_bigint::Integer;
use group::Group;
use subtle::{Choice, ConditionallySelectable, CtOption};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
/// Perform an inversion on a field element (i.e. base field element or scalar)
pub trait Invert {
/// Field element type
type Output;
/// Invert a field element.
fn invert(&self) -> Self::Output;
/// Invert a field element in variable time.
///
/// ⚠️ WARNING!
///
/// This method should not be used with secret values, as its variable-time
/// operation can potentially leak secrets through sidechannels.
fn invert_vartime(&self) -> Self::Output {
// Fall back on constant-time implementation by default.
self.invert()
}
}
/// Perform a batched inversion on a sequence of field elements (i.e. base field elements or scalars)
/// at an amortized cost that should be practically as efficient as a single inversion.
pub trait BatchInvert<FieldElements: ?Sized>: Invert + Sized {
/// The output of batch inversion. A container of field elements.
type Output: AsRef<[Self]>;
/// Invert a batch of field elements.
fn batch_invert(
field_elements: &FieldElements,
) -> CtOption<<Self as BatchInvert<FieldElements>>::Output>;
}
impl<const N: usize, T> BatchInvert<[T; N]> for T
where
T: Invert<Output = CtOption<Self>>
+ Mul<Self, Output = Self>
+ Copy
+ Default
+ ConditionallySelectable,
{
type Output = [Self; N];
fn batch_invert(field_elements: &[Self; N]) -> CtOption<[Self; N]> {
let mut field_elements_multiples = [Self::default(); N];
let mut field_elements_multiples_inverses = [Self::default(); N];
let mut field_elements_inverses = [Self::default(); N];
let inversion_succeeded = invert_batch_internal(
field_elements,
&mut field_elements_multiples,
&mut field_elements_multiples_inverses,
&mut field_elements_inverses,
);
CtOption::new(field_elements_inverses, inversion_succeeded)
}
}
#[cfg(feature = "alloc")]
impl<T> BatchInvert<[T]> for T
where
T: Invert<Output = CtOption<Self>>
+ Mul<Self, Output = Self>
+ Copy
+ Default
+ ConditionallySelectable,
{
type Output = Vec<Self>;
fn batch_invert(field_elements: &[Self]) -> CtOption<Vec<Self>> {
let mut field_elements_multiples: Vec<Self> = vec![Self::default(); field_elements.len()];
let mut field_elements_multiples_inverses: Vec<Self> =
vec![Self::default(); field_elements.len()];
let mut field_elements_inverses: Vec<Self> = vec![Self::default(); field_elements.len()];
let inversion_succeeded = invert_batch_internal(
field_elements,
field_elements_multiples.as_mut(),
field_elements_multiples_inverses.as_mut(),
field_elements_inverses.as_mut(),
);
CtOption::new(
field_elements_inverses.into_iter().collect(),
inversion_succeeded,
)
}
}
/// Implements "Montgomery's trick", a trick for computing many modular inverses at once.
///
/// "Montgomery's trick" works by reducing the problem of computing `n` inverses
/// to computing a single inversion, plus some storage and `O(n)` extra multiplications.
///
/// See: https://iacr.org/archive/pkc2004/29470042/29470042.pdf section 2.2.
fn invert_batch_internal<
T: Invert<Output = CtOption<T>> + Mul<T, Output = T> + Default + ConditionallySelectable,
>(
field_elements: &[T],
field_elements_multiples: &mut [T],
field_elements_multiples_inverses: &mut [T],
field_elements_inverses: &mut [T],
) -> Choice {
let batch_size = field_elements.len();
if batch_size == 0
|| batch_size != field_elements_multiples.len()
|| batch_size != field_elements_multiples_inverses.len()
{
return Choice::from(0);
}
field_elements_multiples[0] = field_elements[0];
for i in 1..batch_size {
// $ a_n = a_{n-1}*x_n $
field_elements_multiples[i] = field_elements_multiples[i - 1] * field_elements[i];
}
field_elements_multiples[batch_size - 1]
.invert()
.map(|multiple_of_inverses_of_all_field_elements| {
field_elements_multiples_inverses[batch_size - 1] =
multiple_of_inverses_of_all_field_elements;
for i in (1..batch_size).rev() {
// $ a_{n-1} = {a_n}^{-1}*x_n $
field_elements_multiples_inverses[i - 1] =
field_elements_multiples_inverses[i] * field_elements[i];
}
field_elements_inverses[0] = field_elements_multiples_inverses[0];
for i in 1..batch_size {
// $ {x_n}^{-1} = a_{n}^{-1}*a_{n-1} $
field_elements_inverses[i] =
field_elements_multiples_inverses[i] * field_elements_multiples[i - 1];
}
})
.is_some()
}
/// Linear combination.
///
/// This trait enables crates to provide an optimized implementation of
/// linear combinations (e.g. Shamir's Trick), or otherwise provides a default
/// non-optimized implementation.
// TODO(tarcieri): replace this with a trait from the `group` crate? (see zkcrypto/group#25)
pub trait LinearCombination: Group {
/// Calculates `x * k + y * l`.
fn lincomb(x: &Self, k: &Self::Scalar, y: &Self, l: &Self::Scalar) -> Self {
(*x * k) + (*y * l)
}
}
/// Linear combination (extended version).
///
/// This trait enables providing an optimized implementation of
/// linear combinations (e.g. Shamir's Trick).
// TODO(tarcieri): replace the current `LinearCombination` with this in the next release
pub trait LinearCombinationExt<PointsAndScalars>: group::Curve
where
PointsAndScalars: AsRef<[(Self, Self::Scalar)]> + ?Sized,
{
/// Calculates `x1 * k1 + ... + xn * kn`.
fn lincomb_ext(points_and_scalars: &PointsAndScalars) -> Self {
points_and_scalars
.as_ref()
.iter()
.copied()
.map(|(point, scalar)| point * scalar)
.sum()
}
}
/// Blanket impl of the legacy [`LinearCombination`] trait for types which impl the new
/// [`LinearCombinationExt`] trait for 2-element arrays.
impl<P: LinearCombinationExt<[(P, Self::Scalar); 2]>> LinearCombination for P {
fn lincomb(x: &Self, k: &Self::Scalar, y: &Self, l: &Self::Scalar) -> Self {
Self::lincomb_ext(&[(*x, *k), (*y, *l)])
}
}
/// Multiplication by the generator.
///
/// May use optimizations (e.g. precomputed tables) when available.
// TODO(tarcieri): replace this with `Group::mul_by_generator``? (see zkcrypto/group#44)
pub trait MulByGenerator: Group {
/// Multiply by the generator of the prime-order subgroup.
#[must_use]
fn mul_by_generator(scalar: &Self::Scalar) -> Self {
Self::generator() * scalar
}
}
/// Modular reduction.
pub trait Reduce<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;
}

81
vendor/elliptic-curve/src/point.rs vendored Normal file
View File

@@ -0,0 +1,81 @@
//! Traits for elliptic curve points.
#[cfg(feature = "arithmetic")]
mod non_identity;
#[cfg(feature = "arithmetic")]
pub use {self::non_identity::NonIdentity, crate::CurveArithmetic};
use crate::{Curve, FieldBytes};
use subtle::{Choice, CtOption};
/// Affine point type for a given curve with a [`CurveArithmetic`]
/// implementation.
#[cfg(feature = "arithmetic")]
pub type AffinePoint<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;
}
/// Normalize point(s) in projective representation by converting them to their affine ones.
#[cfg(feature = "arithmetic")]
pub trait BatchNormalize<Points: ?Sized>: group::Curve {
/// The output of the batch normalization; a container of affine points.
type Output: AsRef<[Self::AffineRepr]>;
/// Perform a batched conversion to affine representation on a sequence of projective points
/// at an amortized cost that should be practically as efficient as a single conversion.
/// Internally, implementors should rely upon `InvertBatch`.
fn batch_normalize(points: &Points) -> <Self as BatchNormalize<Points>>::Output;
}
/// Double a point (i.e. add it to itself)
pub trait Double {
/// Double this point.
fn double(&self) -> Self;
}
/// Decompress an elliptic curve point.
///
/// Point decompression recovers an original curve point from its x-coordinate
/// and a boolean flag indicating whether or not the y-coordinate is odd.
pub trait DecompressPoint<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;
}

View File

@@ -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());
}
}

567
vendor/elliptic-curve/src/public_key.rs vendored Normal file
View File

@@ -0,0 +1,567 @@
//! Elliptic curve public keys.
use crate::{
point::NonIdentity, AffinePoint, CurveArithmetic, Error, NonZeroScalar, ProjectivePoint, Result,
};
use core::fmt::Debug;
use group::{Curve, Group};
#[cfg(feature = "jwk")]
use crate::{JwkEcKey, JwkParameters};
#[cfg(feature = "pkcs8")]
use pkcs8::spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, ObjectIdentifier};
#[cfg(feature = "pem")]
use core::str::FromStr;
#[cfg(feature = "sec1")]
use {
crate::{
point::PointCompression,
sec1::{CompressedPoint, EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint},
FieldBytesSize,
},
core::cmp::Ordering,
subtle::{Choice, CtOption},
};
#[cfg(all(feature = "alloc", feature = "pkcs8"))]
use pkcs8::EncodePublicKey;
#[cfg(all(feature = "alloc", feature = "sec1"))]
use alloc::boxed::Box;
#[cfg(any(feature = "jwk", feature = "pem"))]
use alloc::string::{String, ToString};
#[cfg(feature = "serde")]
use serdect::serde::{de, ser, Deserialize, Serialize};
#[cfg(any(feature = "pem", feature = "serde"))]
use pkcs8::DecodePublicKey;
#[cfg(all(feature = "sec1", feature = "pkcs8"))]
use {
crate::{
pkcs8::{self, AssociatedOid},
ALGORITHM_OID,
},
pkcs8::der,
};
/// Elliptic curve public keys.
///
/// This is a wrapper type for [`AffinePoint`] which ensures an inner
/// non-identity point and provides a common place to handle encoding/decoding.
///
/// # Parsing "SPKI" Keys
///
/// X.509 `SubjectPublicKeyInfo` (SPKI) is a commonly used format for encoding
/// public keys, notably public keys corresponding to PKCS#8 private keys.
/// (especially ones generated by OpenSSL).
///
/// Keys in SPKI format are either binary (ASN.1 BER/DER), or PEM encoded
/// (ASCII) and begin with the following:
///
/// ```text
/// -----BEGIN PUBLIC KEY-----
/// ```
///
/// To decode an elliptic curve public key from SPKI, enable the `pkcs8`
/// feature of this crate (or the `pkcs8` feature of a specific RustCrypto
/// elliptic curve crate) and use the
/// [`elliptic_curve::pkcs8::DecodePublicKey`][`pkcs8::DecodePublicKey`]
/// trait to parse it.
///
/// When the `pem` feature of this crate (or a specific RustCrypto elliptic
/// curve crate) is enabled, a [`FromStr`] impl is also available.
///
/// # `serde` support
///
/// When the optional `serde` feature of this create is enabled, [`Serialize`]
/// and [`Deserialize`] impls are provided for this type.
///
/// The serialization is binary-oriented and supports ASN.1 DER
/// Subject Public Key Info (SPKI) as the encoding format.
///
/// For a more text-friendly encoding of public keys, use [`JwkEcKey`] instead.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PublicKey<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| {
// Defeating the point of `subtle`, but the use case is specifically a public key
let is_identity = Choice::from(u8::from(encoded_point.is_identity()));
CtOption::new(PublicKey { point }, !is_identity)
})
}
}
#[cfg(feature = "sec1")]
impl<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()
));
}
}

53
vendor/elliptic-curve/src/scalar.rs vendored Normal file
View File

@@ -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;
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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"))
}
}

114
vendor/elliptic-curve/src/sec1.rs vendored Normal file
View File

@@ -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(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)
}
}
}

386
vendor/elliptic-curve/src/secret_key.rs vendored Normal file
View File

@@ -0,0 +1,386 @@
//! Secret keys for elliptic curves (i.e. private scalars).
//!
//! The [`SecretKey`] type is a wrapper around a secret scalar value which is
//! designed to prevent unintentional exposure (e.g. via `Debug` or other
//! logging). It also handles zeroing the secret value out of memory securely
//! on drop.
#[cfg(all(feature = "pkcs8", feature = "sec1"))]
mod pkcs8;
use crate::{Curve, Error, FieldBytes, Result, ScalarPrimitive};
use core::fmt::{self, Debug};
use generic_array::typenum::Unsigned;
use subtle::{Choice, ConstantTimeEq};
use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
#[cfg(feature = "arithmetic")]
use crate::{rand_core::CryptoRngCore, CurveArithmetic, NonZeroScalar, PublicKey};
#[cfg(feature = "jwk")]
use crate::jwk::{JwkEcKey, JwkParameters};
#[cfg(feature = "pem")]
use pem_rfc7468::{self as pem, PemLabel};
#[cfg(feature = "sec1")]
use {
crate::{
sec1::{EncodedPoint, ModulusSize, ValidatePublicKey},
FieldBytesSize,
},
sec1::der,
};
#[cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1"))]
use {
crate::{
sec1::{FromEncodedPoint, ToEncodedPoint},
AffinePoint,
},
alloc::vec::Vec,
sec1::der::Encode,
};
#[cfg(all(feature = "arithmetic", any(feature = "jwk", feature = "pem")))]
use alloc::string::String;
#[cfg(all(feature = "arithmetic", feature = "jwk"))]
use alloc::string::ToString;
#[cfg(all(doc, feature = "pkcs8"))]
use {crate::pkcs8::DecodePrivateKey, core::str::FromStr};
/// Elliptic curve secret keys.
///
/// This type wraps a secret scalar value, helping to prevent accidental
/// exposure and securely erasing the value from memory when dropped.
///
/// # Parsing PKCS#8 Keys
///
/// PKCS#8 is a commonly used format for encoding secret keys (especially ones
/// generated by OpenSSL).
///
/// Keys in PKCS#8 format are either binary (ASN.1 BER/DER), or PEM encoded
/// (ASCII) and begin with the following:
///
/// ```text
/// -----BEGIN PRIVATE KEY-----
/// ```
///
/// To decode an elliptic curve private key from PKCS#8, enable the `pkcs8`
/// feature of this crate (or the `pkcs8` feature of a specific RustCrypto
/// elliptic curve crate) and use the [`DecodePrivateKey`] trait to parse it.
///
/// When the `pem` feature of this crate (or a specific RustCrypto elliptic
/// curve crate) is enabled, a [`FromStr`] impl is also available.
#[derive(Clone)]
pub struct SecretKey<C: Curve> {
/// Scalar value
inner: ScalarPrimitive<C>,
}
impl<C> SecretKey<C>
where
C: Curve,
{
/// Minimum allowed size of an elliptic curve secret key in bytes.
///
/// This provides the equivalent of 96-bits of symmetric security.
const MIN_SIZE: usize = 24;
/// Generate a random [`SecretKey`].
#[cfg(feature = "arithmetic")]
pub fn random(rng: &mut impl CryptoRngCore) -> Self
where
C: CurveArithmetic,
{
Self {
inner: NonZeroScalar::<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 a minimum of 24-bytes (192-byts) and at most `C::FieldBytesSize`
/// bytes in length.
///
/// Byte slices shorter than the field size are handled by zero padding the input.
pub fn from_slice(slice: &[u8]) -> Result<Self> {
if slice.len() == C::FieldBytesSize::USIZE {
Self::from_bytes(FieldBytes::<C>::from_slice(slice))
} else if (Self::MIN_SIZE..C::FieldBytesSize::USIZE).contains(&slice.len()) {
let mut bytes = Zeroizing::new(FieldBytes::<C>::default());
let offset = C::FieldBytesSize::USIZE.saturating_sub(slice.len());
bytes[offset..].copy_from_slice(slice);
Self::from_bytes(&bytes)
} else {
Err(Error)
}
}
/// Serialize raw secret scalar as a big endian integer.
pub fn to_bytes(&self) -> FieldBytes<C> {
self.inner.to_bytes()
}
/// Deserialize secret key encoded in the SEC1 ASN.1 DER `ECPrivateKey` format.
#[cfg(feature = "sec1")]
pub fn from_sec1_der(der_bytes: &[u8]) -> Result<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(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(),
}
}
}

View File

@@ -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)
}
}

20
vendor/elliptic-curve/src/voprf.rs vendored Normal file
View File

@@ -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;
}

128
vendor/elliptic-curve/src/weierstrass.rs vendored Normal file
View File

@@ -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)
}

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgaWJBcVYaYzQN4OfY
afKgVJJVjhoEhotqn4VKhmeIGI2hRANCAAQcrP+1Xy8s79idies3SyaBFSRSgC3u
oJkWBoE32DnPf8SBpESSME1+9mrBF77+g6jQjxVfK1L59hjdRHApBI4P
-----END PRIVATE KEY-----

Binary file not shown.

View File

@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHKz/tV8vLO/YnYnrN0smgRUkUoAt
7qCZFgaBN9g5z3/EgaREkjBNfvZqwRe+/oOo0I8VXytS+fYY3URwKQSODw==
-----END PUBLIC KEY-----

57
vendor/elliptic-curve/tests/pkcs8.rs vendored Normal file
View File

@@ -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);
}

View File

@@ -0,0 +1,28 @@
//! Secret key tests
#![cfg(feature = "dev")]
use elliptic_curve::dev::SecretKey;
#[test]
fn from_empty_slice() {
assert!(SecretKey::from_slice(&[]).is_err());
}
#[test]
fn from_slice_expected_size() {
let bytes = [1u8; 32];
assert!(SecretKey::from_slice(&bytes).is_ok());
}
#[test]
fn from_slice_allowed_short() {
let bytes = [1u8; 24];
assert!(SecretKey::from_slice(&bytes).is_ok());
}
#[test]
fn from_slice_too_short() {
let bytes = [1u8; 23]; // min 24-bytes
assert!(SecretKey::from_slice(&bytes).is_err());
}