elliptic-curve-0.13.8/.cargo_vcs_info.json0000644000000001540000000000100140540ustar { "git": { "sha1": "5ddf0f52f07f65f319ffd423c52e696406924d90" }, "path_in_vcs": "elliptic-curve" }elliptic-curve-0.13.8/CHANGELOG.md000064400000000000000000000656671046102023000145010ustar 00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## 0.13.8 (2023-11-18) ### Changed - `SecretKey::from_slice` now allows >=24-bytes ([#1412]) [#1412]: https://github.com/RustCrypto/traits/pull/1412 ## 0.13.7 (2023-11-15) ### Added - `BatchInvert` and `BatchNormalize` traits ([#1376]) - `LinearCombinationExt` trait ([#1405]) [#1376]: https://github.com/RustCrypto/traits/pull/1376 [#1405]: https://github.com/RustCrypto/traits/pull/1405 ## 0.13.6 (2023-10-02) ### Fixed - Minimum supported `hkdf` version is v0.12.1 ([#1353]) - Minimum supported `serde_json` version for `jwk` feature is v1.0.47 ([#1354]) - Minimum supported `tap` version for `bits` feature is v1.0.1 ([#1355]) [#1353]: https://github.com/RustCrypto/traits/pull/1353 [#1354]: https://github.com/RustCrypto/traits/pull/1354 [#1355]: https://github.com/RustCrypto/traits/pull/1355 ## 0.13.5 (2023-05-19) ### Changed - Faster `PublicKey::from_encoded_point` ([#1310]) ### Fixed - `alloc`+`arithmetic` features w/o `sec1` feature ([#1301]) [#1301]: https://github.com/RustCrypto/traits/pull/1301 [#1310]: https://github.com/RustCrypto/traits/pull/1310 ## 0.13.4 (2023-04-08) ### Changed - Bump `hex-literal` to v0.4 ([#1295]) ### Fixed - `NonZeroScalar::from_slice` ([#1296]) - `ScalarPrimitive::from_slice` ([#1296]) [#1295]: https://github.com/RustCrypto/traits/pull/1295 [#1296]: https://github.com/RustCrypto/traits/pull/1296 ## 0.13.3 (2023-04-04) ### Added - Impl `AssociatedAlgorithmIdentifier` for `SecretKey` and `PublicKey` ([#1286]) ### Changed - Update OSSWU code ([#1157]) - Bump `pkcs8` to v0.10.2 ([#1291]) ### Fixed - `FieldBytesEncoding` provided impl ([#1287]) [#1157]: https://github.com/RustCrypto/traits/pull/1157 [#1286]: https://github.com/RustCrypto/traits/pull/1286 [#1287]: https://github.com/RustCrypto/traits/pull/1287 [#1291]: https://github.com/RustCrypto/traits/pull/1291 ## 0.13.2 (2023-03-08) ### Added - Weakly activate `pkcs8?/std` ([#1263]) - More `PublicKey` <-> SEC1 conversions ([#1272]) [#1263]: https://github.com/RustCrypto/traits/pull/1263 [#1272]: https://github.com/RustCrypto/traits/pull/1272 ## 0.13.1 (2023-03-01) ### Added - `SecretKey::from_slice` short input support ([#1256]) [#1256]: https://github.com/RustCrypto/traits/pull/1256 ## 0.13.0 (2023-02-28) ### Added - `PublicKey::to_sec1_bytes` ([#1102]) - Forward `std` feature to `sec1` dependency ([#1131]) - `NonIdentity` wrapper type ([#1176]) - Impl `serde` traits for `NonZeroScalar` ([#1178]) - `MulByGenerator` trait ([#1198]) - `NonZeroScalar::invert_vartime` ([#1207]) - `BlindedScalar` type ([#1208]) - `point::Double` trait ([#1218]) - `FieldBytesEncoding` trait ([#1235]) - `Invert::invert_vartime` ([#1239]) ### Changed - Allow bigger `c1` constant in `OsswuMapParams` ([#1024]) - Rename `Curve::UInt` => `Curve::Uint` ([#1191]) - Use weak feature activation ([#1192], [#1194]) - Consolidate `CurveArithmetic` trait ([#1196]) - Rename `SecretKey::to_pem` => `::to_sec1_pem` ([#1202]) - Rename `ScalarCore` to `ScalarPrimitive` ([#1203]) - Use `CryptoRngCore` trait ([#1206]) - Refactor field element decoding/encoding ([#1220]) - Update VOPRF identifier type ([#1175]) - Rename `SecretKey::as_scalar_core` => `::as_scalar_primitive` ([#1228]) - Rename `Reduce::from_bytes_reduced` => `::reduce_bytes` ([#1225], [#1229]) - Consolidate `AffineCoordinates` trait ([#1237]) - Allow multiple `dst`s in the `hash2curve` API ([#1238]) - Have `serde` feature activate `pkcs8` ([#1245]) - Dependency upgrades: - `base16ct` ([#1254]) - `crypto-bigint` v0.5 ([#1251]) - `ff` and `group` v0.13 ([#1166]) - `pem-rfc7468` v0.7 ([#1251]) - `pkcs8` v0.10 ([#1251]) - `sec1` v0.7 ([#1251]) - `serdect` v0.2 ([#1251]) ### Removed - `impl_field_element!` macro ([#1165]) - Direct `der` crate dependency ([#1195]) - `AffineArithmetic`, `ProjectiveArithmetic`, `ScalarArithmetic` traits ([#1196]) - Toplevel re-exports except for `AffinePoint`, `ProjectivePoint`, and `Scalar` ([#1223]) - `Reduce` methods ([#1225]) - Blanket impl for `Invert` ([#1242]) [#1024]: https://github.com/RustCrypto/traits/pull/1024 [#1102]: https://github.com/RustCrypto/traits/pull/1102 [#1131]: https://github.com/RustCrypto/traits/pull/1131 [#1165]: https://github.com/RustCrypto/traits/pull/1165 [#1166]: https://github.com/RustCrypto/traits/pull/1166 [#1175]: https://github.com/RustCrypto/traits/pull/1175 [#1176]: https://github.com/RustCrypto/traits/pull/1176 [#1178]: https://github.com/RustCrypto/traits/pull/1178 [#1191]: https://github.com/RustCrypto/traits/pull/1191 [#1192]: https://github.com/RustCrypto/traits/pull/1192 [#1194]: https://github.com/RustCrypto/traits/pull/1194 [#1195]: https://github.com/RustCrypto/traits/pull/1195 [#1196]: https://github.com/RustCrypto/traits/pull/1196 [#1198]: https://github.com/RustCrypto/traits/pull/1198 [#1202]: https://github.com/RustCrypto/traits/pull/1202 [#1203]: https://github.com/RustCrypto/traits/pull/1203 [#1206]: https://github.com/RustCrypto/traits/pull/1206 [#1207]: https://github.com/RustCrypto/traits/pull/1207 [#1208]: https://github.com/RustCrypto/traits/pull/1208 [#1218]: https://github.com/RustCrypto/traits/pull/1218 [#1220]: https://github.com/RustCrypto/traits/pull/1220 [#1223]: https://github.com/RustCrypto/traits/pull/1223 [#1225]: https://github.com/RustCrypto/traits/pull/1225 [#1228]: https://github.com/RustCrypto/traits/pull/1228 [#1229]: https://github.com/RustCrypto/traits/pull/1229 [#1235]: https://github.com/RustCrypto/traits/pull/1235 [#1237]: https://github.com/RustCrypto/traits/pull/1237 [#1238]: https://github.com/RustCrypto/traits/pull/1238 [#1239]: https://github.com/RustCrypto/traits/pull/1239 [#1242]: https://github.com/RustCrypto/traits/pull/1242 [#1245]: https://github.com/RustCrypto/traits/pull/1245 [#1251]: https://github.com/RustCrypto/traits/pull/1251 [#1254]: https://github.com/RustCrypto/traits/pull/1254 ## 0.12.3 (2022-08-01) ### Added - Aliases for SEC1 compressed/uncompressed points ([#1067]) ### Fixed - `arithmetic` + `serde` feature combo ([#1066]) [#1066]: https://github.com/RustCrypto/traits/pull/1066 [#1067]: https://github.com/RustCrypto/traits/pull/1067 ## 0.12.2 (2022-07-01) ### Changed - Bump `crypto-bigint` to v0.4.8 ([#1039]) [#1039]: https://github.com/RustCrypto/traits/pull/1039 ## 0.12.1 (2022-06-12) ### Added - `impl_field_element!` macro ([#1021]) - Generic impl of complete prime order formulas ([#1022]) ### Changed - Bump `crypto-bigint` to v0.4.4 ([#1018], [#1020]) [#1018]: https://github.com/RustCrypto/traits/pull/1018 [#1020]: https://github.com/RustCrypto/traits/pull/1020 [#1021]: https://github.com/RustCrypto/traits/pull/1021 [#1022]: https://github.com/RustCrypto/traits/pull/1022 ## 0.12.0 (2022-05-08) ### Added - `ecdh::SharedSecret::extract` HKDF helper ([#1007]) ### Changed - Bump `digest` dependency to v0.10 ([#883], [#904]) - Make `NonZeroScalar::invert` infallible ([#894]) - `ToCompactEncodedPoint` now returns `CtOption` ([#895]) - Move `hash2field` into `hash2curve` module ([#903]) - Bump `ff` and `group` dependencies to v0.12 ([#994]) - Use `serdect` crate ([#996]) - Replace `AlgorithmParamters` with `AssociatedOid` ([#1001]) - Bump `crypto-bigint` dependency to v0.4 ([#1005]) - Bump `der` dependency to v0.6 ([#1006]) - Bump `pkcs8` dependency to v0.9 ([#1006]) - Bump `sec1` dependency to v0.3 ([#1006]) - Bump `pem-rfc7468` dependency to v0.6 ([#1009]) ### Removed - `Zeroize` impl from `ecdh::SharedSecret` ([#978]) [#883]: https://github.com/RustCrypto/traits/pull/883 [#894]: https://github.com/RustCrypto/traits/pull/894 [#895]: https://github.com/RustCrypto/traits/pull/895 [#903]: https://github.com/RustCrypto/traits/pull/903 [#904]: https://github.com/RustCrypto/traits/pull/904 [#978]: https://github.com/RustCrypto/traits/pull/978 [#994]: https://github.com/RustCrypto/traits/pull/994 [#996]: https://github.com/RustCrypto/traits/pull/996 [#1001]: https://github.com/RustCrypto/traits/pull/1001 [#1005]: https://github.com/RustCrypto/traits/pull/1005 [#1006]: https://github.com/RustCrypto/traits/pull/1006 [#1007]: https://github.com/RustCrypto/traits/pull/1007 [#1009]: https://github.com/RustCrypto/traits/pull/1009 ## 0.11.12 (2022-01-30) ### Changed - Disable `bits` feature on docs.rs due to nightly breakage ([#927]) [#927]: https://github.com/RustCrypto/traits/pull/927 ## 0.11.11 (2022-01-30) - No changes; triggering a docs.rs rebuild ## 0.11.10 (2022-01-27) ### Changed - Revert [#884] to support a wider range of `zeroize` versions ([#923]) [#923]: https://github.com/RustCrypto/traits/pull/891 ## 0.11.9 (2022-01-17) [YANKED] ### Changed - Activate `bits`, `hash2curve`, and `voprf` features on docs.rs ([#891]) [#891]: https://github.com/RustCrypto/traits/pull/891 ## 0.11.8 (2022-01-15) [YANKED] ### Added - Impl `ZeroizeOnDrop` on appropriate items ([#884]) ### Changed - Use the `base16ct` crate for hex serialization ([#886], [#887], [#888]) [#884]: https://github.com/RustCrypto/traits/pull/884 [#886]: https://github.com/RustCrypto/traits/pull/886 [#887]: https://github.com/RustCrypto/traits/pull/887 [#888]: https://github.com/RustCrypto/traits/pull/888 ## 0.11.7 (2022-01-14) [YANKED] ### Added - Initial hash-to-field support ([#854], [#855], [#871], [#874]) - Initial hash-to-curve support ([#865], [#876]) - Impl `Mul` for `NonZeroScalar` * `NonZeroScalar` ([#857], [#862]) - `Reduce::from_*e_digest_reduced` ([#869]) - `VoprfParameters` trait ([#878]) [#854]: https://github.com/RustCrypto/traits/pull/854 [#855]: https://github.com/RustCrypto/traits/pull/855 [#857]: https://github.com/RustCrypto/traits/pull/857 [#862]: https://github.com/RustCrypto/traits/pull/862 [#865]: https://github.com/RustCrypto/traits/pull/865 [#869]: https://github.com/RustCrypto/traits/pull/869 [#871]: https://github.com/RustCrypto/traits/pull/871 [#874]: https://github.com/RustCrypto/traits/pull/874 [#876]: https://github.com/RustCrypto/traits/pull/876 [#878]: https://github.com/RustCrypto/traits/pull/878 ## 0.11.6 (2021-12-20) ### Added - Type conversions chart ([#852]) [#852]: https://github.com/RustCrypto/traits/pull/852 ## 0.11.5 (2021-12-05) ### Changed - Revised `LinearCombination` trait ([#835]) [#835]: https://github.com/RustCrypto/traits/pull/835 ## 0.11.4 (2021-12-04) [YANKED] ### Added - `LinearCombination` trait ([#832]) [#832]: https://github.com/RustCrypto/traits/pull/832 ## 0.11.3 (2021-12-03) [YANKED] ### Added - `ReduceNonZero` trait ([#827]) [#827]: https://github.com/RustCrypto/traits/pull/827 ## 0.11.2 (2021-12-03) [YANKED] ### Changed - Bump `pem-rfc7468` dependency to v0.3 ([#825]) [#825]: https://github.com/RustCrypto/traits/pull/825 ## 0.11.1 (2021-11-21) [YANKED] ### Added - `NonZeroScalar::from_uint` ([#822]) [#822]: https://github.com/RustCrypto/traits/pull/822 ## 0.11.0 (2021-11-19) [YANKED] ### Added - `ScalarCore` type ([#732]) - `PrimeCurveArithmetic` trait ([#739]) - SEC1 private key support ([#762]) - `Reduce` trait ([#768]) - Re-export `ff` and `PrimeField` ([#796]) - `Encoding` bound on `Curve::UInt` ([#806]) - `scalar::IsHigh` trait ([#814], [#815]) - `Neg` impl for `NonZeroScalar` ([#816]) - `AffineXCoordinate` trait ([#817]) - `serde` support for scalar and `PublicKey` types ([#818]) ### Changed - Bump `ff` + `group` to v0.11 ([#730]) - Make `SecretKey::to_jwk_string` self-zeroizing ([#742]) - Use `sec1` crate's `EncodedPoint` ([#771]) - Make `FromEncodedPoint` return a `CtOption` ([#782]) - Rust 2021 edition upgrade; MSRV to 1.56 ([#795]) - Bump `crypto-bigint` dependency to v0.3 ([#807]) - Use `sec1` crate for `pkcs8` support ([#809]) - Bump `spki` dependency to v0.5 release ([#810]) - `NonZeroScalar` is now bounded on `ScalarArithmetic` instead of `ProjectiveArithmetic` ([#812]) ### Fixed - `Zeroize` impl on `NonZeroScalar` ([#785]) [#730]: https://github.com/RustCrypto/traits/pull/730 [#732]: https://github.com/RustCrypto/traits/pull/732 [#739]: https://github.com/RustCrypto/traits/pull/739 [#742]: https://github.com/RustCrypto/traits/pull/742 [#762]: https://github.com/RustCrypto/traits/pull/762 [#768]: https://github.com/RustCrypto/traits/pull/768 [#771]: https://github.com/RustCrypto/traits/pull/771 [#782]: https://github.com/RustCrypto/traits/pull/782 [#785]: https://github.com/RustCrypto/traits/pull/785 [#795]: https://github.com/RustCrypto/traits/pull/795 [#796]: https://github.com/RustCrypto/traits/pull/796 [#806]: https://github.com/RustCrypto/traits/pull/806 [#807]: https://github.com/RustCrypto/traits/pull/807 [#809]: https://github.com/RustCrypto/traits/pull/809 [#810]: https://github.com/RustCrypto/traits/pull/810 [#812]: https://github.com/RustCrypto/traits/pull/812 [#814]: https://github.com/RustCrypto/traits/pull/814 [#815]: https://github.com/RustCrypto/traits/pull/815 [#816]: https://github.com/RustCrypto/traits/pull/816 [#817]: https://github.com/RustCrypto/traits/pull/817 [#818]: https://github.com/RustCrypto/traits/pull/818 ## 0.10.6 (2021-08-23) ### Changed - Bump `crypto-bigint` dependency to v0.2.4 ([#710]) [#710]: https://github.com/RustCrypto/traits/pull/710 ## 0.10.5 (2021-07-20) ### Changed - Pin `zeroize` dependency to v1.4 and `subtle` to v2.4 ([#689]) [#689]: https://github.com/RustCrypto/traits/pull/689 ## 0.10.4 (2021-07-12) ### Added - Re-export `rand_core` ([#683]) [#683]: https://github.com/RustCrypto/traits/pull/683 ## 0.10.3 (2021-06-21) ### Changed - Bump `crypto-bigint` to v0.2.1 ([#673]) [#673]: https://github.com/RustCrypto/traits/pull/673 ## 0.10.2 (2021-06-14) [YANKED] ### Added - `ConstantTimeEq` impl for `NonZeroScalar` ([#669]) [#669]: https://github.com/RustCrypto/traits/pull/669 ## 0.10.1 (2021-06-09) [YANKED] ### Added - Explicit `Copy` bounds on `PublicKey` ([#667]) [#667]: https://github.com/RustCrypto/traits/pull/667 ## 0.10.0 (2021-06-07) [YANKED] ### Added - `ScalarBytes::from_uint` ([#651]) - `dev::ScalarBytes` ([#652]) - `ScalarArithmetic` trait ([#654]) - `AffineArithmetic` trait ([#658]) - `PointCompaction` trait and SEC1 tag support ([#659]) ### Changed - Bump `ff` and `group` to v0.10; MSRV 1.51+ ([#643]) - Merge `Curve` and `Order` traits ([#644]) - Use `crypto-bigint` to represent `Curve::ORDER` ([#645]) - Source `FieldSize` from `C::UInt` type ([#646]) - Impl `ScalarBytes` using `C::UInt` ([#647]) - Make `ScalarBytes` the `SecretKey` internal repr ([#649]) - Bump `crypto-bigint` to v0.2 ([#662]) - Bump `pkcs8` to v0.7 ([#662]) ### Removed - `util` module ([#648]) [#643]: https://github.com/RustCrypto/traits/pull/643 [#644]: https://github.com/RustCrypto/traits/pull/644 [#645]: https://github.com/RustCrypto/traits/pull/645 [#646]: https://github.com/RustCrypto/traits/pull/646 [#647]: https://github.com/RustCrypto/traits/pull/647 [#648]: https://github.com/RustCrypto/traits/pull/648 [#649]: https://github.com/RustCrypto/traits/pull/649 [#651]: https://github.com/RustCrypto/traits/pull/651 [#652]: https://github.com/RustCrypto/traits/pull/652 [#654]: https://github.com/RustCrypto/traits/pull/654 [#658]: https://github.com/RustCrypto/traits/pull/658 [#659]: https://github.com/RustCrypto/traits/pull/659 [#662]: https://github.com/RustCrypto/traits/pull/662 ## 0.9.12 (2021-05-18) ### Added - `Ord` and `PartialOrd` impls on `PublicKey` ([#637]) [#637]: https://github.com/RustCrypto/traits/pull/637 ## 0.9.11 (2021-04-21) ### Added - Impl `subtle` traits on `ScalarBytes` ([#612]) ### Fixed - Always re-export ScalarBytes ([#613]) [#612]: https://github.com/RustCrypto/traits/pull/612 [#613]: https://github.com/RustCrypto/traits/pull/613 ## 0.9.10 (2021-04-21) ### Added - `ScalarBytes` type ([#610]) [#610]: https://github.com/RustCrypto/traits/pull/610 ## 0.9.9 (2021-04-21) [YANKED] ### Added - `Order::is_scalar_repr_in_range` ([#608]) [#608]: https://github.com/RustCrypto/traits/pull/608 ## 0.9.8 (2021-04-21) ### Added - Define `Order` for `MockCurve` ([#606]) [#606]: https://github.com/RustCrypto/traits/pull/606 ## 0.9.7 (2021-04-21) ### Added - `Order` trait ([#603]) ### Fixed - Warnings from `pkcs8` imports ([#604]) [#603]: https://github.com/RustCrypto/traits/pull/603 [#604]: https://github.com/RustCrypto/traits/pull/604 ## 0.9.6 (2021-03-22) ### Changed - Bump `pkcs8` dependency to v0.6 ([#585]) [#585]: https://github.com/RustCrypto/traits/pull/585 ## 0.9.5 (2021-03-17) [YANKED] ### Added - Implement `{to,char}_le_bits` for `MockCurve` ([#565]) - Implement `one()` for mock `Scalar` ([#566]) ### Changed - Use string-based OID constants ([#561]) - Bump `base64ct` dependency to v1.0 ([#581]) [#561]: https://github.com/RustCrypto/traits/pull/561 [#565]: https://github.com/RustCrypto/traits/pull/565 [#566]: https://github.com/RustCrypto/traits/pull/566 [#581]: https://github.com/RustCrypto/traits/pull/581 ## 0.9.4 (2021-02-18) [YANKED] ### Fixed - Breakage related to the `pkcs8` v0.5.1 crate ([#556]) [#556]: https://github.com/RustCrypto/traits/pull/556 ## 0.9.3 (2021-02-16) [YANKED] ### Changed - Bump `pkcs8` dependency to v0.5.0 ([#549]) ### Fixed - Workaround for bitvecto-rs/bitvec#105 ([#550]) [#549]: https://github.com/RustCrypto/traits/pull/549 [#550]: https://github.com/RustCrypto/traits/pull/550 ## 0.9.2 (2021-02-12) [YANKED] ### Changed - Flatten `weierstrass` module ([#542]) [#542]: https://github.com/RustCrypto/traits/pull/542 ## 0.9.1 (2021-02-11) [YANKED] ### Removed - `BitView` re-export ([#540]) [#540]: https://github.com/RustCrypto/traits/pull/540 ## 0.9.0 (2021-02-10) [YANKED] ### Added - JWK support ([#483]) - `sec1::ValidatePublicKey` trait ([#485]) - `hazmat` crate feature ([#487]) - `Result` alias ([#534]) ### Changed - Bump `ff` and `group` crates to v0.9 ([#452]) - Simplify ECDH trait bounds ([#475]) - Flatten API ([#487]) - Bump `pkcs8` crate dependency to v0.4 ([#493]) ### Removed - Direct `bitvec` dependency ([#484]) - `FromDigest` trait ([#532]) [#452]: https://github.com/RustCrypto/traits/pull/452 [#475]: https://github.com/RustCrypto/traits/pull/475 [#483]: https://github.com/RustCrypto/traits/pull/483 [#484]: https://github.com/RustCrypto/traits/pull/484 [#485]: https://github.com/RustCrypto/traits/pull/485 [#487]: https://github.com/RustCrypto/traits/pull/487 [#493]: https://github.com/RustCrypto/traits/pull/493 [#432]: https://github.com/RustCrypto/traits/pull/432 [#532]: https://github.com/RustCrypto/traits/pull/532 [#534]: https://github.com/RustCrypto/traits/pull/534 ## 0.8.5 (2021-02-17) ### Fixed - Workaround for bitvecto-rs/bitvec#105 ([#553]) [#553]: https://github.com/RustCrypto/traits/pull/553 ## 0.8.4 (2020-12-23) ### Fixed - Rust `nightly` regression ([#432]) [#432]: https://github.com/RustCrypto/traits/pull/432 ## 0.8.3 (2020-12-22) ### Fixed - Regression in combination of `pem`+`zeroize` features ([#429]) [#429]: https://github.com/RustCrypto/traits/pull/429 ## 0.8.2 (2020-12-22) [YANKED] ### Added - Low-level ECDH API ([#418]) - `dev` module ([#419]) - Impl `pkcs8::ToPrivateKey` for `SecretKey` ([#423]) - Impl `pkcs8::ToPublicKey` for `PublicKey` ([#427]) ### Changed - Bump `subtle` dependency to 2.4.0 ([#414]) - Bump `pkcs8` dependency to v0.3.3 ([#425]) - Use `der` crate to parse `SecretKey` ([#422]) ### Fixed - Make `PublicKey::from_encoded_point` go through `PublicKey::from_affine` ([#416]) [#414]: https://github.com/RustCrypto/traits/pull/414 [#416]: https://github.com/RustCrypto/traits/pull/416 [#418]: https://github.com/RustCrypto/traits/pull/418 [#419]: https://github.com/RustCrypto/traits/pull/419 [#422]: https://github.com/RustCrypto/traits/pull/422 [#423]: https://github.com/RustCrypto/traits/pull/423 [#425]: https://github.com/RustCrypto/traits/pull/425 [#427]: https://github.com/RustCrypto/traits/pull/427 ## 0.8.1 (2020-12-16) [YANKED] ### Fixed - Builds on Rust `nightly` compiler ([#412]) [#412]: https://github.com/RustCrypto/traits/pull/412 ## 0.8.0 (2020-12-16) [YANKED] ### Added - Impl `subtle::ConditionallySelectable` for `sec1::EncodedPoint` ([#409]) - `sec1::EncodedPoint::identity()` method ([#408]) - `sec1::Coordinates::tag` method ([#407]) - Support for SEC1 identity encoding ([#401]) ### Changed - Bump `pkcs8` crate dependency to v0.3 ([#405]) - Ensure `PublicKey` is not the identity point ([#404]) - Have `SecretKey::secret_scalar` return `NonZeroScalar` ([#402]) ### Removed - `SecretKey::secret_value` ([#403]) [#409]: https://github.com/RustCrypto/traits/pull/409 [#408]: https://github.com/RustCrypto/traits/pull/408 [#407]: https://github.com/RustCrypto/traits/pull/407 [#405]: https://github.com/RustCrypto/traits/pull/405 [#404]: https://github.com/RustCrypto/traits/pull/404 [#403]: https://github.com/RustCrypto/traits/pull/403 [#402]: https://github.com/RustCrypto/traits/pull/402 [#401]: https://github.com/RustCrypto/traits/pull/401 ## 0.7.1 (2020-12-07) ### Changed - Have `SecretKey::secret_value` always return `NonZeroScalar` ([#390]) [#390]: https://github.com/RustCrypto/traits/pull/390 ## 0.7.0 (2020-12-06) [YANKED] ### Added - Impl `pkcs8::FromPublicKey` for `PublicKey` ([#385]) - Impl `pkcs8::FromPrivateKey` trait for `SecretKey` ([#381], [#383]) - PKCS#8 PEM support ([#382]) - `SecretKey::secret_value()` method ([#375]) - `PublicKey` type ([#363], [#366]) ### Changed - Rename `PublicKey::from_bytes()` to `::from_sec1_bytes()` ([#376]) - `sec1::EncodedPoint` uses `Option` instead of `subtle::CtOption` ([#367]) - Bump `const-oid` to v0.3; MSRV 1.46+ ([#365], [#381]) ### Fixed - `ecdh` rustdoc ([#364]) [#385]: https://github.com/RustCrypto/traits/pull/385 [#383]: https://github.com/RustCrypto/traits/pull/383 [#382]: https://github.com/RustCrypto/traits/pull/382 [#381]: https://github.com/RustCrypto/traits/pull/381 [#376]: https://github.com/RustCrypto/traits/pull/376 [#375]: https://github.com/RustCrypto/traits/pull/375 [#367]: https://github.com/RustCrypto/traits/pull/367 [#366]: https://github.com/RustCrypto/traits/pull/366 [#365]: https://github.com/RustCrypto/traits/pull/365 [#364]: https://github.com/RustCrypto/traits/pull/364 [#363]: https://github.com/RustCrypto/traits/pull/363 ## 0.6.6 (2020-10-08) ### Added - Derive `Clone` on `SecretBytes` ([#330]) [#300]: https://github.com/RustCrypto/traits/pull/300 ## 0.6.5 (2020-10-08) ### Fixed - Work around `nightly-2020-10-06` breakage ([#328]) [#328]: https://github.com/RustCrypto/traits/pull/328 ## 0.6.4 (2020-10-08) ### Added - Impl `From>` for `FieldBytes` ([#326]) [#326]: https://github.com/RustCrypto/traits/pull/326 ## 0.6.3 (2020-10-08) ### Added - `SecretBytes` newtype ([#324]) [#324]: https://github.com/RustCrypto/traits/pull/324 ## 0.6.2 (2020-09-24) ### Added - `sec1::EncodedPoint::to_untagged_bytes()` method ([#312]) [#312]: https://github.com/RustCrypto/traits/pull/312 ## 0.6.1 (2020-09-21) ### Fixed - `sec1::EncodedPoint::decompress` ([#309]) [#309]: https://github.com/RustCrypto/traits/pull/309 ## 0.6.0 (2020-09-11) [YANKED] ### Added - `arithmetic` feature ([#293]) - Generic curve/field arithmetic using the `ff` and `group` crates ([#287], [#291], [#292]) - `sec1::Coordinates` ([#286]) - `weierstrass::point::Compression` trait ([#283], [#300]) - Arithmetic helper functions ([#281]) - `digest` feature and `FromDigest` trait ([#279]) - impl `Deref` for `NonZeroScalar` ([#278]) - Conditionally impl `Invert` for `NonZeroScalar` ([#277]) - `NonZeroScalar::to_bytes` ([#276]) - `EncodedPoint::decompress` ([#275]) - `sec1::Tag` ([#270]) - `weierstrass::point::Decompress` trait ([#266]) - `alloc` feature + `EncodedPoint::to_bytes()` ([#265]) ### Changed - Renamed `Arithmetic` trait to `point::ProjectiveArithmetic` ([#300]) - Replaced `Arithmetic::Scalar` and `Arithmetic::AffinePoint` with `Scalar` and `AffinePoint` ([#300]) - Made `SecretKey` inner type generic ([#297]) - Renamed `ElementBytes` to `FieldBytes` ([#296]) - MSRV 1.44 ([#292]) - Minimum `subtle` version now v2.3 ([#290]) - Renamed `Curve::ElementSize` to `::FieldSize` ([#282]) - Refactor `PublicKey` into `sec1::EncodedPoint` ([#264]) ### Removed - `FromBytes` trait ([#300]) - `Generate` trait ([#295]) [#300]: https://github.com/RustCrypto/traits/pull/300 [#297]: https://github.com/RustCrypto/traits/pull/297 [#296]: https://github.com/RustCrypto/traits/pull/296 [#295]: https://github.com/RustCrypto/traits/pull/295 [#293]: https://github.com/RustCrypto/traits/pull/293 [#292]: https://github.com/RustCrypto/traits/pull/292 [#291]: https://github.com/RustCrypto/traits/pull/291 [#290]: https://github.com/RustCrypto/traits/pull/290 [#287]: https://github.com/RustCrypto/traits/pull/293 [#286]: https://github.com/RustCrypto/traits/pull/286 [#283]: https://github.com/RustCrypto/traits/pull/283 [#282]: https://github.com/RustCrypto/traits/pull/282 [#281]: https://github.com/RustCrypto/traits/pull/281 [#279]: https://github.com/RustCrypto/traits/pull/279 [#278]: https://github.com/RustCrypto/traits/pull/278 [#277]: https://github.com/RustCrypto/traits/pull/277 [#276]: https://github.com/RustCrypto/traits/pull/276 [#275]: https://github.com/RustCrypto/traits/pull/275 [#270]: https://github.com/RustCrypto/traits/pull/270 [#266]: https://github.com/RustCrypto/traits/pull/266 [#265]: https://github.com/RustCrypto/traits/pull/265 [#264]: https://github.com/RustCrypto/traits/pull/264 ## 0.5.0 (2020-08-10) ### Added - `Arithmetic` trait ([#219]) - `Generate` trait ([#220], [#226]) - Toplevel `Curve` trait ([#223]) - `Invert` trait ([#228]) - `FromPublicKey` trait ([#229], [#248]) - Re-export `zeroize` ([#233]) - OID support ([#240], [#245]) - `NonZeroScalar` type ([#241]) - `Generator` trait ([#241]) - `weierstrass::PublicKey::compress` method ([#243]) - Derive `Clone` on `SecretKey` ([#244]) - Generic Elliptic Curve Diffie-Hellman support ([#251]) ### Changed - Moved repo to https://github.com/RustCrypto/traits ([#213]) - Rename `ScalarBytes` to `ElementBytes` ([#246]) - Rename `CompressedCurvePoint`/`UncompressedCurvePoint` to `CompressedPoint`/`UncompressedPoint` [#213]: https://github.com/RustCrypto/traits/pull/213 [#219]: https://github.com/RustCrypto/traits/pull/219 [#220]: https://github.com/RustCrypto/traits/pull/220 [#223]: https://github.com/RustCrypto/traits/pull/223 [#226]: https://github.com/RustCrypto/traits/pull/226 [#228]: https://github.com/RustCrypto/traits/pull/228 [#229]: https://github.com/RustCrypto/traits/pull/229 [#233]: https://github.com/RustCrypto/traits/pull/233 [#240]: https://github.com/RustCrypto/traits/pull/240 [#241]: https://github.com/RustCrypto/traits/pull/241 [#243]: https://github.com/RustCrypto/traits/pull/243 [#244]: https://github.com/RustCrypto/traits/pull/244 [#245]: https://github.com/RustCrypto/traits/pull/245 [#246]: https://github.com/RustCrypto/traits/pull/246 [#248]: https://github.com/RustCrypto/traits/pull/248 [#251]: https://github.com/RustCrypto/traits/pull/251 ## 0.4.0 (2020-06-04) ### Changed - Bump `generic-array` dependency from v0.12 to v0.14 ## 0.3.0 (2020-01-15) ### Added - `Scalar` struct type ### Changed - Repository moved to ### Removed - Curve definitions/arithmetic extracted out into per-curve crates ## 0.2.0 (2019-12-11) ### Added - `secp256r1` (P-256) point compression and decompression ### Changed - Bump MSRV to 1.37 ## 0.1.0 (2019-12-06) - Initial release elliptic-curve-0.13.8/Cargo.toml0000644000000072360000000000100120620ustar # 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"] elliptic-curve-0.13.8/Cargo.toml.orig000064400000000000000000000055131046102023000155370ustar 00000000000000[package] name = "elliptic-curve" version = "0.13.8" 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. """ authors = ["RustCrypto Developers"] license = "Apache-2.0 OR MIT" repository = "https://github.com/RustCrypto/traits/tree/master/elliptic-curve" readme = "README.md" categories = ["cryptography", "no-std"] keywords = ["crypto", "ecc", "elliptic", "weierstrass"] edition = "2021" rust-version = "1.65" [dependencies] base16ct = "0.2" crypto-bigint = { version = "0.5", default-features = false, features = ["rand_core", "generic-array", "zeroize"] } generic-array = { version = "0.14.6", default-features = false, features = ["zeroize"] } rand_core = { version = "0.6.4", default-features = false } subtle = { version = "2", default-features = false } zeroize = { version = "1.7", default-features = false } # optional dependencies base64ct = { version = "1", optional = true, default-features = false, features = ["alloc"] } digest = { version = "0.10", optional = true } ff = { version = "0.13", optional = true, default-features = false } group = { version = "0.13", optional = true, default-features = false } hkdf = { version = "0.12.1", optional = true, default-features = false } hex-literal = { version = "0.4", optional = true } pem-rfc7468 = { version = "0.7", optional = true, features = ["alloc"] } pkcs8 = { version = "0.10.2", optional = true, default-features = false } sec1 = { version = "0.7.1", optional = true, features = ["subtle", "zeroize"] } serdect = { version = "0.2", optional = true, default-features = false, features = ["alloc"] } serde_json = { version = "1.0.47", optional = true, default-features = false, features = ["alloc"] } tap = { version = "1.0.1", optional = true, default-features = false } # hack for minimal-versions support for `bits` [dev-dependencies] hex-literal = "0.4" sha2 = "0.10" sha3 = "0.10" [features] default = ["arithmetic"] alloc = [ "base16ct/alloc", "ff?/alloc", "group?/alloc", "pkcs8?/alloc", "sec1?/alloc", "zeroize/alloc" ] std = [ "alloc", "rand_core/std", "pkcs8?/std", "sec1?/std" ] arithmetic = ["group"] bits = ["arithmetic", "ff/bits", "dep:tap"] dev = ["arithmetic", "dep:hex-literal", "pem", "pkcs8"] hash2curve = ["arithmetic", "digest"] ecdh = ["arithmetic", "digest", "dep:hkdf"] group = ["dep:group", "ff"] hazmat = [] jwk = ["dep:base64ct", "dep:serde_json", "alloc", "serde", "zeroize/alloc"] pkcs8 = ["dep:pkcs8", "sec1"] pem = ["dep:pem-rfc7468", "alloc", "arithmetic", "pkcs8", "sec1/pem"] serde = ["dep:serdect", "alloc", "pkcs8", "sec1/serde"] voprf = ["digest"] [package.metadata.docs.rs] features = ["bits", "ecdh", "hash2curve", "jwk", "pem", "std", "voprf"] rustdoc-args = ["--cfg", "docsrs"] elliptic-curve-0.13.8/LICENSE-APACHE000064400000000000000000000251411046102023000145730ustar 00000000000000 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. elliptic-curve-0.13.8/LICENSE-MIT000064400000000000000000000020561046102023000143030ustar 00000000000000Copyright (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. elliptic-curve-0.13.8/README.md000064400000000000000000000036451046102023000141330ustar 00000000000000# 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 elliptic-curve-0.13.8/src/arithmetic.rs000064400000000000000000000050221046102023000161310ustar 00000000000000//! Elliptic curve arithmetic traits. use crate::{ ops::{Invert, LinearCombination, MulByGenerator, Reduce, ShrAssign}, point::AffineCoordinates, scalar::{FromUintUnchecked, IsHigh}, Curve, FieldBytes, PrimeCurve, ScalarPrimitive, }; use core::fmt::Debug; use subtle::{ConditionallySelectable, ConstantTimeEq, CtOption}; use zeroize::DefaultIsZeroes; /// Elliptic curve with an arithmetic implementation. pub trait CurveArithmetic: Curve { /// Elliptic curve point in affine coordinates. type AffinePoint: 'static + AffineCoordinates> + Copy + ConditionallySelectable + ConstantTimeEq + Debug + Default + DefaultIsZeroes + Eq + PartialEq + Sized + Send + Sync; /// Elliptic curve point in projective coordinates. /// /// Note: the following bounds are provided by [`group::Group`]: /// - `'static` /// - [`Copy`] /// - [`Clone`] /// - [`Debug`] /// - [`Eq`] /// - [`Sized`] /// - [`Send`] /// - [`Sync`] type ProjectivePoint: ConditionallySelectable + ConstantTimeEq + Default + DefaultIsZeroes + From + Into + LinearCombination + MulByGenerator + group::Curve + group::Group; /// Scalar field modulo this curve's order. /// /// Note: the following bounds are provided by [`ff::Field`]: /// - `'static` /// - [`Copy`] /// - [`Clone`] /// - [`ConditionallySelectable`] /// - [`ConstantTimeEq`] /// - [`Debug`] /// - [`Default`] /// - [`Send`] /// - [`Sync`] type Scalar: AsRef + DefaultIsZeroes + From> + FromUintUnchecked + Into> + Into> + Into + Invert> + IsHigh + PartialOrd + Reduce> + ShrAssign + ff::Field + ff::PrimeField>; } /// Prime order elliptic curve with projective arithmetic implementation. pub trait PrimeCurveArithmetic: PrimeCurve + CurveArithmetic { /// Prime order elliptic curve group. type CurveGroup: group::prime::PrimeCurve::AffinePoint>; } elliptic-curve-0.13.8/src/dev.rs000064400000000000000000000475521046102023000145740ustar 00000000000000//! Development-related functionality. //! //! Helpers and types for writing tests against concrete implementations of //! the traits in this crate. use crate::{ bigint::{Limb, U256}, error::{Error, Result}, generic_array::typenum::U32, ops::{Invert, LinearCombination, MulByGenerator, Reduce, ShrAssign}, pkcs8, point::AffineCoordinates, rand_core::RngCore, scalar::{FromUintUnchecked, IsHigh}, sec1::{CompressedPoint, FromEncodedPoint, ToEncodedPoint}, subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, zeroize::DefaultIsZeroes, Curve, CurveArithmetic, FieldBytesEncoding, PrimeCurve, }; use core::{ iter::{Product, Sum}, ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, }; use ff::{Field, PrimeField}; use hex_literal::hex; use pkcs8::AssociatedOid; #[cfg(feature = "bits")] use ff::PrimeFieldBits; #[cfg(feature = "jwk")] use crate::JwkParameters; /// Pseudo-coordinate for fixed-based scalar mult output pub const PSEUDO_COORDINATE_FIXED_BASE_MUL: [u8; 32] = hex!("deadbeef00000000000000000000000000000000000000000000000000000001"); /// SEC1 encoded point. pub type EncodedPoint = crate::sec1::EncodedPoint; /// Field element bytes. pub type FieldBytes = crate::FieldBytes; /// Non-zero scalar value. pub type NonZeroScalar = crate::NonZeroScalar; /// Public key. pub type PublicKey = crate::PublicKey; /// Secret key. pub type SecretKey = crate::SecretKey; /// Scalar primitive type. // TODO(tarcieri): make this the scalar type when it's more capable pub type ScalarPrimitive = crate::ScalarPrimitive; /// Scalar bits. #[cfg(feature = "bits")] pub type ScalarBits = crate::scalar::ScalarBits; /// Mock elliptic curve type useful for writing tests which require a concrete /// curve type. /// /// Note: this type is roughly modeled off of NIST P-256, but does not provide /// an actual cure arithmetic implementation. #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] pub struct MockCurve; impl Curve for MockCurve { type FieldBytesSize = U32; type Uint = U256; const ORDER: U256 = U256::from_be_hex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"); } impl PrimeCurve for MockCurve {} impl CurveArithmetic for MockCurve { type AffinePoint = AffinePoint; type ProjectivePoint = ProjectivePoint; type Scalar = Scalar; } impl AssociatedOid for MockCurve { /// OID for NIST P-256 const OID: pkcs8::ObjectIdentifier = pkcs8::ObjectIdentifier::new_unwrap("1.2.840.10045.3.1.7"); } #[cfg(feature = "jwk")] impl JwkParameters for MockCurve { const CRV: &'static str = "P-256"; } /// Example scalar type #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] pub struct Scalar(ScalarPrimitive); impl Field for Scalar { const ZERO: Self = Self(ScalarPrimitive::ZERO); const ONE: Self = Self(ScalarPrimitive::ONE); fn random(mut rng: impl RngCore) -> Self { let mut bytes = FieldBytes::default(); loop { rng.fill_bytes(&mut bytes); if let Some(scalar) = Self::from_repr(bytes).into() { return scalar; } } } fn is_zero(&self) -> Choice { self.0.is_zero() } #[must_use] fn square(&self) -> Self { unimplemented!(); } #[must_use] fn double(&self) -> Self { self.add(self) } fn invert(&self) -> CtOption { unimplemented!(); } fn sqrt(&self) -> CtOption { unimplemented!(); } fn sqrt_ratio(_num: &Self, _div: &Self) -> (Choice, Self) { unimplemented!(); } } impl PrimeField for Scalar { type Repr = FieldBytes; const MODULUS: &'static str = "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"; const NUM_BITS: u32 = 256; const CAPACITY: u32 = 255; const TWO_INV: Self = Self::ZERO; // BOGUS! const MULTIPLICATIVE_GENERATOR: Self = Self::ZERO; // BOGUS! Should be 7 const S: u32 = 4; const ROOT_OF_UNITY: Self = Self::ZERO; // BOGUS! Should be 0xffc97f062a770992ba807ace842a3dfc1546cad004378daf0592d7fbb41e6602 const ROOT_OF_UNITY_INV: Self = Self::ZERO; // BOGUS! const DELTA: Self = Self::ZERO; // BOGUS! fn from_repr(bytes: FieldBytes) -> CtOption { ScalarPrimitive::from_bytes(&bytes).map(Self) } fn to_repr(&self) -> FieldBytes { self.0.to_bytes() } fn is_odd(&self) -> Choice { self.0.is_odd() } } #[cfg(feature = "bits")] impl PrimeFieldBits for Scalar { #[cfg(target_pointer_width = "32")] type ReprBits = [u32; 8]; #[cfg(target_pointer_width = "64")] type ReprBits = [u64; 4]; fn to_le_bits(&self) -> ScalarBits { self.0.as_uint().to_words().into() } fn char_le_bits() -> ScalarBits { MockCurve::ORDER.to_words().into() } } impl AsRef for Scalar { fn as_ref(&self) -> &Scalar { self } } impl ConditionallySelectable for Scalar { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Self(ScalarPrimitive::conditional_select(&a.0, &b.0, choice)) } } impl ConstantTimeEq for Scalar { fn ct_eq(&self, other: &Self) -> Choice { self.0.ct_eq(&other.0) } } impl DefaultIsZeroes for Scalar {} impl Add for Scalar { type Output = Scalar; fn add(self, other: Scalar) -> Scalar { self.add(&other) } } impl Add<&Scalar> for Scalar { type Output = Scalar; fn add(self, other: &Scalar) -> Scalar { Self(self.0.add(&other.0)) } } impl AddAssign for Scalar { fn add_assign(&mut self, other: Scalar) { *self = *self + other; } } impl AddAssign<&Scalar> for Scalar { fn add_assign(&mut self, other: &Scalar) { *self = *self + other; } } impl Sub for Scalar { type Output = Scalar; fn sub(self, other: Scalar) -> Scalar { self.sub(&other) } } impl Sub<&Scalar> for Scalar { type Output = Scalar; fn sub(self, other: &Scalar) -> Scalar { Self(self.0.sub(&other.0)) } } impl SubAssign for Scalar { fn sub_assign(&mut self, other: Scalar) { *self = *self - other; } } impl SubAssign<&Scalar> for Scalar { fn sub_assign(&mut self, other: &Scalar) { *self = *self - other; } } impl Mul for Scalar { type Output = Scalar; fn mul(self, _other: Scalar) -> Scalar { unimplemented!(); } } impl Mul<&Scalar> for Scalar { type Output = Scalar; fn mul(self, _other: &Scalar) -> Scalar { unimplemented!(); } } impl MulAssign for Scalar { fn mul_assign(&mut self, _rhs: Scalar) { unimplemented!(); } } impl MulAssign<&Scalar> for Scalar { fn mul_assign(&mut self, _rhs: &Scalar) { unimplemented!(); } } impl Neg for Scalar { type Output = Scalar; fn neg(self) -> Scalar { Self(self.0.neg()) } } impl ShrAssign for Scalar { fn shr_assign(&mut self, rhs: usize) { self.0 >>= rhs; } } impl Sum for Scalar { fn sum>(_iter: I) -> Self { unimplemented!(); } } impl<'a> Sum<&'a Scalar> for Scalar { fn sum>(_iter: I) -> Self { unimplemented!(); } } impl Product for Scalar { fn product>(_iter: I) -> Self { unimplemented!(); } } impl<'a> Product<&'a Scalar> for Scalar { fn product>(_iter: I) -> Self { unimplemented!(); } } impl Invert for Scalar { type Output = CtOption; fn invert(&self) -> CtOption { unimplemented!(); } } impl Reduce for Scalar { type Bytes = FieldBytes; fn reduce(w: U256) -> Self { let (r, underflow) = w.sbb(&MockCurve::ORDER, Limb::ZERO); let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8); let reduced = U256::conditional_select(&w, &r, !underflow); Self(ScalarPrimitive::new(reduced).unwrap()) } fn reduce_bytes(_: &FieldBytes) -> Self { todo!() } } impl FieldBytesEncoding for U256 {} impl From for Scalar { fn from(n: u64) -> Scalar { Self(n.into()) } } impl From for Scalar { fn from(scalar: ScalarPrimitive) -> Scalar { Self(scalar) } } impl From for ScalarPrimitive { fn from(scalar: Scalar) -> ScalarPrimitive { scalar.0 } } impl From for U256 { fn from(scalar: Scalar) -> U256 { scalar.0.to_uint() } } impl TryFrom for Scalar { type Error = Error; fn try_from(w: U256) -> Result { Option::from(ScalarPrimitive::new(w)).map(Self).ok_or(Error) } } impl FromUintUnchecked for Scalar { type Uint = U256; fn from_uint_unchecked(uint: U256) -> Self { Self(ScalarPrimitive::from_uint_unchecked(uint)) } } impl From for FieldBytes { fn from(scalar: Scalar) -> Self { Self::from(&scalar) } } impl From<&Scalar> for FieldBytes { fn from(scalar: &Scalar) -> Self { scalar.to_repr() } } impl IsHigh for Scalar { fn is_high(&self) -> Choice { self.0.is_high() } } /// Example affine point type #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum AffinePoint { /// Result of fixed-based scalar multiplication. FixedBaseOutput(Scalar), /// Identity. Identity, /// Base point. Generator, /// Point corresponding to a given [`EncodedPoint`]. Other(EncodedPoint), } impl AffineCoordinates for AffinePoint { type FieldRepr = FieldBytes; fn x(&self) -> FieldBytes { unimplemented!(); } fn y_is_odd(&self) -> Choice { unimplemented!(); } } impl ConstantTimeEq for AffinePoint { fn ct_eq(&self, other: &Self) -> Choice { match (self, other) { (Self::FixedBaseOutput(scalar), Self::FixedBaseOutput(other_scalar)) => { scalar.ct_eq(other_scalar) } (Self::Identity, Self::Identity) | (Self::Generator, Self::Generator) => 1.into(), (Self::Other(point), Self::Other(other_point)) => u8::from(point == other_point).into(), _ => 0.into(), } } } impl ConditionallySelectable for AffinePoint { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { // Not really constant time, but this is dev code if choice.into() { *b } else { *a } } } impl Default for AffinePoint { fn default() -> Self { Self::Identity } } impl DefaultIsZeroes for AffinePoint {} impl FromEncodedPoint for AffinePoint { fn from_encoded_point(encoded_point: &EncodedPoint) -> CtOption { let point = if encoded_point.is_identity() { Self::Identity } else { Self::Other(*encoded_point) }; CtOption::new(point, Choice::from(1)) } } impl ToEncodedPoint for AffinePoint { fn to_encoded_point(&self, compress: bool) -> EncodedPoint { match self { Self::FixedBaseOutput(scalar) => EncodedPoint::from_affine_coordinates( &scalar.to_repr(), &PSEUDO_COORDINATE_FIXED_BASE_MUL.into(), false, ), Self::Other(point) => { if compress == point.is_compressed() { *point } else { unimplemented!(); } } _ => unimplemented!(), } } } impl Mul for AffinePoint { type Output = AffinePoint; fn mul(self, _scalar: NonZeroScalar) -> Self { unimplemented!(); } } /// Example projective point type #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum ProjectivePoint { /// Result of fixed-based scalar multiplication FixedBaseOutput(Scalar), /// Is this point the identity point? Identity, /// Is this point the generator point? Generator, /// Is this point a different point corresponding to a given [`AffinePoint`] Other(AffinePoint), } impl ConstantTimeEq for ProjectivePoint { fn ct_eq(&self, other: &Self) -> Choice { match (self, other) { (Self::FixedBaseOutput(scalar), Self::FixedBaseOutput(other_scalar)) => { scalar.ct_eq(other_scalar) } (Self::Identity, Self::Identity) | (Self::Generator, Self::Generator) => 1.into(), (Self::Other(point), Self::Other(other_point)) => point.ct_eq(other_point), _ => 0.into(), } } } impl ConditionallySelectable for ProjectivePoint { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { if choice.into() { *b } else { *a } } } impl Default for ProjectivePoint { fn default() -> Self { Self::Identity } } impl DefaultIsZeroes for ProjectivePoint {} impl From for ProjectivePoint { fn from(point: AffinePoint) -> ProjectivePoint { match point { AffinePoint::FixedBaseOutput(scalar) => ProjectivePoint::FixedBaseOutput(scalar), AffinePoint::Identity => ProjectivePoint::Identity, AffinePoint::Generator => ProjectivePoint::Generator, other => ProjectivePoint::Other(other), } } } impl From for AffinePoint { fn from(point: ProjectivePoint) -> AffinePoint { group::Curve::to_affine(&point) } } impl FromEncodedPoint for ProjectivePoint { fn from_encoded_point(_point: &EncodedPoint) -> CtOption { unimplemented!(); } } impl ToEncodedPoint for ProjectivePoint { fn to_encoded_point(&self, _compress: bool) -> EncodedPoint { unimplemented!(); } } impl group::Group for ProjectivePoint { type Scalar = Scalar; fn random(_rng: impl RngCore) -> Self { unimplemented!(); } fn identity() -> Self { Self::Identity } fn generator() -> Self { Self::Generator } fn is_identity(&self) -> Choice { Choice::from(u8::from(self == &Self::Identity)) } #[must_use] fn double(&self) -> Self { unimplemented!(); } } impl group::GroupEncoding for AffinePoint { type Repr = CompressedPoint; fn from_bytes(bytes: &Self::Repr) -> CtOption { EncodedPoint::from_bytes(bytes) .map(|point| CtOption::new(point, Choice::from(1))) .unwrap_or_else(|_| { let is_identity = bytes.ct_eq(&Self::Repr::default()); CtOption::new(EncodedPoint::identity(), is_identity) }) .and_then(|point| Self::from_encoded_point(&point)) } fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { Self::from_bytes(bytes) } fn to_bytes(&self) -> Self::Repr { let encoded = self.to_encoded_point(true); let mut result = CompressedPoint::::default(); result[..encoded.len()].copy_from_slice(encoded.as_bytes()); result } } impl group::GroupEncoding for ProjectivePoint { type Repr = CompressedPoint; fn from_bytes(bytes: &Self::Repr) -> CtOption { ::from_bytes(bytes).map(Into::into) } fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { Self::from_bytes(bytes) } fn to_bytes(&self) -> Self::Repr { group::Curve::to_affine(self).to_bytes() } } impl group::Curve for ProjectivePoint { type AffineRepr = AffinePoint; fn to_affine(&self) -> AffinePoint { match self { Self::FixedBaseOutput(scalar) => AffinePoint::FixedBaseOutput(*scalar), Self::Other(affine) => *affine, _ => unimplemented!(), } } } impl LinearCombination for ProjectivePoint {} impl Add for ProjectivePoint { type Output = ProjectivePoint; fn add(self, _other: ProjectivePoint) -> ProjectivePoint { unimplemented!(); } } impl Add<&ProjectivePoint> for ProjectivePoint { type Output = ProjectivePoint; fn add(self, _other: &ProjectivePoint) -> ProjectivePoint { unimplemented!(); } } impl AddAssign for ProjectivePoint { fn add_assign(&mut self, _rhs: ProjectivePoint) { unimplemented!(); } } impl AddAssign<&ProjectivePoint> for ProjectivePoint { fn add_assign(&mut self, _rhs: &ProjectivePoint) { unimplemented!(); } } impl Sub for ProjectivePoint { type Output = ProjectivePoint; fn sub(self, _other: ProjectivePoint) -> ProjectivePoint { unimplemented!(); } } impl Sub<&ProjectivePoint> for ProjectivePoint { type Output = ProjectivePoint; fn sub(self, _other: &ProjectivePoint) -> ProjectivePoint { unimplemented!(); } } impl SubAssign for ProjectivePoint { fn sub_assign(&mut self, _rhs: ProjectivePoint) { unimplemented!(); } } impl SubAssign<&ProjectivePoint> for ProjectivePoint { fn sub_assign(&mut self, _rhs: &ProjectivePoint) { unimplemented!(); } } impl Add for ProjectivePoint { type Output = ProjectivePoint; fn add(self, _other: AffinePoint) -> ProjectivePoint { unimplemented!(); } } impl Add<&AffinePoint> for ProjectivePoint { type Output = ProjectivePoint; fn add(self, _other: &AffinePoint) -> ProjectivePoint { unimplemented!(); } } impl AddAssign for ProjectivePoint { fn add_assign(&mut self, _rhs: AffinePoint) { unimplemented!(); } } impl AddAssign<&AffinePoint> for ProjectivePoint { fn add_assign(&mut self, _rhs: &AffinePoint) { unimplemented!(); } } impl Sum for ProjectivePoint { fn sum>(_iter: I) -> Self { unimplemented!(); } } impl<'a> Sum<&'a ProjectivePoint> for ProjectivePoint { fn sum>(_iter: I) -> Self { unimplemented!(); } } impl Sub for ProjectivePoint { type Output = ProjectivePoint; fn sub(self, _other: AffinePoint) -> ProjectivePoint { unimplemented!(); } } impl Sub<&AffinePoint> for ProjectivePoint { type Output = ProjectivePoint; fn sub(self, _other: &AffinePoint) -> ProjectivePoint { unimplemented!(); } } impl SubAssign for ProjectivePoint { fn sub_assign(&mut self, _rhs: AffinePoint) { unimplemented!(); } } impl SubAssign<&AffinePoint> for ProjectivePoint { fn sub_assign(&mut self, _rhs: &AffinePoint) { unimplemented!(); } } impl Mul for ProjectivePoint { type Output = ProjectivePoint; fn mul(self, scalar: Scalar) -> ProjectivePoint { match self { Self::Generator => Self::FixedBaseOutput(scalar), _ => unimplemented!(), } } } impl Mul<&Scalar> for ProjectivePoint { type Output = ProjectivePoint; fn mul(self, scalar: &Scalar) -> ProjectivePoint { self * *scalar } } impl MulAssign for ProjectivePoint { fn mul_assign(&mut self, _rhs: Scalar) { unimplemented!(); } } impl MulAssign<&Scalar> for ProjectivePoint { fn mul_assign(&mut self, _rhs: &Scalar) { unimplemented!(); } } impl MulByGenerator for ProjectivePoint {} impl Neg for ProjectivePoint { type Output = ProjectivePoint; fn neg(self) -> ProjectivePoint { unimplemented!(); } } #[cfg(test)] mod tests { use super::Scalar; use ff::PrimeField; use hex_literal::hex; #[test] fn round_trip() { let bytes = hex!("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); let scalar = Scalar::from_repr(bytes.into()).unwrap(); assert_eq!(&bytes, scalar.to_repr().as_slice()); } } elliptic-curve-0.13.8/src/ecdh.rs000064400000000000000000000173331046102023000147130ustar 00000000000000//! Elliptic Curve Diffie-Hellman Support. //! //! This module contains a generic ECDH implementation which is usable with //! any elliptic curve which implements the [`CurveArithmetic`] trait (presently //! the `k256` and `p256` crates) //! //! # ECDH Ephemeral (ECDHE) Usage //! //! Ephemeral Diffie-Hellman provides a one-time key exchange between two peers //! using a randomly generated set of keys for each exchange. //! //! In practice ECDHE is used as part of an [Authenticated Key Exchange (AKE)][AKE] //! protocol (e.g. [SIGMA]), where an existing cryptographic trust relationship //! can be used to determine the authenticity of the ephemeral keys, such as //! a digital signature. Without such an additional step, ECDHE is insecure! //! (see security warning below) //! //! See the documentation for the [`EphemeralSecret`] type for more information //! on performing ECDH ephemeral key exchanges. //! //! # Static ECDH Usage //! //! Static ECDH key exchanges are supported via the low-level //! [`diffie_hellman`] function. //! //! [AKE]: https://en.wikipedia.org/wiki/Authenticated_Key_Exchange //! [SIGMA]: https://webee.technion.ac.il/~hugo/sigma-pdf.pdf use crate::{ point::AffineCoordinates, AffinePoint, Curve, CurveArithmetic, FieldBytes, NonZeroScalar, ProjectivePoint, PublicKey, }; use core::borrow::Borrow; use digest::{crypto_common::BlockSizeUser, Digest}; use group::Curve as _; use hkdf::{hmac::SimpleHmac, Hkdf}; use rand_core::CryptoRngCore; use zeroize::{Zeroize, ZeroizeOnDrop}; /// Low-level Elliptic Curve Diffie-Hellman (ECDH) function. /// /// Whenever possible, we recommend using the high-level ECDH ephemeral API /// provided by [`EphemeralSecret`]. /// /// However, if you are implementing a protocol which requires a static scalar /// value as part of an ECDH exchange, this API can be used to compute a /// [`SharedSecret`] from that value. /// /// Note that this API operates on the low-level [`NonZeroScalar`] and /// [`AffinePoint`] types. If you are attempting to use the higher-level /// [`SecretKey`][`crate::SecretKey`] and [`PublicKey`] types, you will /// need to use the following conversions: /// /// ```ignore /// let shared_secret = elliptic_curve::ecdh::diffie_hellman( /// secret_key.to_nonzero_scalar(), /// public_key.as_affine() /// ); /// ``` pub fn diffie_hellman( secret_key: impl Borrow>, public_key: impl Borrow>, ) -> SharedSecret where C: CurveArithmetic, { let public_point = ProjectivePoint::::from(*public_key.borrow()); let secret_point = (public_point * secret_key.borrow().as_ref()).to_affine(); SharedSecret::new(secret_point) } /// Ephemeral Diffie-Hellman Secret. /// /// These are ephemeral "secret key" values which are deliberately designed /// to avoid being persisted. /// /// To perform an ephemeral Diffie-Hellman exchange, do the following: /// /// - Have each participant generate an [`EphemeralSecret`] value /// - Compute the [`PublicKey`] for that value /// - Have each peer provide their [`PublicKey`] to their counterpart /// - Use [`EphemeralSecret`] and the other participant's [`PublicKey`] /// to compute a [`SharedSecret`] value. /// /// # ⚠️ SECURITY WARNING ⚠️ /// /// Ephemeral Diffie-Hellman exchanges are unauthenticated and without a /// further authentication step are trivially vulnerable to man-in-the-middle /// attacks! /// /// These exchanges should be performed in the context of a protocol which /// takes further steps to authenticate the peers in a key exchange. pub struct EphemeralSecret where C: CurveArithmetic, { scalar: NonZeroScalar, } impl EphemeralSecret where C: CurveArithmetic, { /// Generate a cryptographically random [`EphemeralSecret`]. pub fn random(rng: &mut impl CryptoRngCore) -> Self { Self { scalar: NonZeroScalar::random(rng), } } /// Get the public key associated with this ephemeral secret. /// /// The `compress` flag enables point compression. pub fn public_key(&self) -> PublicKey { PublicKey::from_secret_scalar(&self.scalar) } /// Compute a Diffie-Hellman shared secret from an ephemeral secret and the /// public key of the other participant in the exchange. pub fn diffie_hellman(&self, public_key: &PublicKey) -> SharedSecret { diffie_hellman(self.scalar, public_key.as_affine()) } } impl From<&EphemeralSecret> for PublicKey where C: CurveArithmetic, { fn from(ephemeral_secret: &EphemeralSecret) -> Self { ephemeral_secret.public_key() } } impl Zeroize for EphemeralSecret where C: CurveArithmetic, { fn zeroize(&mut self) { self.scalar.zeroize() } } impl ZeroizeOnDrop for EphemeralSecret where C: CurveArithmetic {} impl Drop for EphemeralSecret where C: CurveArithmetic, { fn drop(&mut self) { self.zeroize(); } } /// Shared secret value computed via ECDH key agreement. pub struct SharedSecret { /// Computed secret value secret_bytes: FieldBytes, } impl SharedSecret { /// Create a new [`SharedSecret`] from an [`AffinePoint`] for this curve. #[inline] fn new(point: AffinePoint) -> Self where C: CurveArithmetic, { Self { secret_bytes: point.x(), } } /// Use [HKDF] (HMAC-based Extract-and-Expand Key Derivation Function) to /// extract entropy from this shared secret. /// /// This method can be used to transform the shared secret into uniformly /// random values which are suitable as key material. /// /// The `D` type parameter is a cryptographic digest function. /// `sha2::Sha256` is a common choice for use with HKDF. /// /// The `salt` parameter can be used to supply additional randomness. /// Some examples include: /// /// - randomly generated (but authenticated) string /// - fixed application-specific value /// - previous shared secret used for rekeying (as in TLS 1.3 and Noise) /// /// After initializing HKDF, use [`Hkdf::expand`] to obtain output key /// material. /// /// [HKDF]: https://en.wikipedia.org/wiki/HKDF pub fn extract(&self, salt: Option<&[u8]>) -> Hkdf> where D: BlockSizeUser + Clone + Digest, { Hkdf::new(salt, &self.secret_bytes) } /// This value contains the raw serialized x-coordinate of the elliptic curve /// point computed from a Diffie-Hellman exchange, serialized as bytes. /// /// When in doubt, use [`SharedSecret::extract`] instead. /// /// # ⚠️ WARNING: NOT UNIFORMLY RANDOM! ⚠️ /// /// This value is not uniformly random and should not be used directly /// as a cryptographic key for anything which requires that property /// (e.g. symmetric ciphers). /// /// Instead, the resulting value should be used as input to a Key Derivation /// Function (KDF) or cryptographic hash function to produce a symmetric key. /// The [`SharedSecret::extract`] function will do this for you. pub fn raw_secret_bytes(&self) -> &FieldBytes { &self.secret_bytes } } impl From> for SharedSecret { /// NOTE: this impl is intended to be used by curve implementations to /// instantiate a [`SharedSecret`] value from their respective /// [`AffinePoint`] type. /// /// Curve implementations should provide the field element representing /// the affine x-coordinate as `secret_bytes`. fn from(secret_bytes: FieldBytes) -> Self { Self { secret_bytes } } } impl ZeroizeOnDrop for SharedSecret {} impl Drop for SharedSecret { fn drop(&mut self) { self.secret_bytes.zeroize() } } elliptic-curve-0.13.8/src/error.rs000064400000000000000000000015231046102023000151330ustar 00000000000000//! Error type. use core::fmt::{self, Display}; #[cfg(feature = "pkcs8")] use crate::pkcs8; /// Result type with the `elliptic-curve` crate's [`Error`] type. pub type Result = core::result::Result; /// Elliptic curve errors. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct Error; impl Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("crypto error") } } impl From for Error { fn from(_: base16ct::Error) -> Error { Error } } #[cfg(feature = "pkcs8")] impl From for Error { fn from(_: pkcs8::Error) -> Error { Error } } #[cfg(feature = "sec1")] impl From for Error { fn from(_: sec1::Error) -> Error { Error } } #[cfg(feature = "std")] impl std::error::Error for Error {} elliptic-curve-0.13.8/src/field.rs000064400000000000000000000037241046102023000150720ustar 00000000000000//! Field elements. use crate::{ bigint::{ArrayEncoding, ByteArray, Integer}, Curve, }; use generic_array::{typenum::Unsigned, GenericArray}; /// Size of serialized field elements of this elliptic curve. pub type FieldBytesSize = ::FieldBytesSize; /// Byte representation of a base/scalar field element of a given curve. pub type FieldBytes = GenericArray>; /// Trait for decoding/encoding `Curve::Uint` from/to [`FieldBytes`] using /// curve-specific rules. /// /// Namely a curve's modulus may be smaller than the big integer type used to /// internally represent field elements (since the latter are multiples of the /// limb size), such as in the case of curves like NIST P-224 and P-521, and so /// it may need to be padded/truncated to the right length. /// /// Additionally, different curves have different endianness conventions, also /// captured here. pub trait FieldBytesEncoding: ArrayEncoding + Integer where C: Curve, { /// Decode unsigned integer from serialized field element. /// /// The default implementation assumes a big endian encoding. fn decode_field_bytes(field_bytes: &FieldBytes) -> Self { debug_assert!(field_bytes.len() <= Self::ByteSize::USIZE); let mut byte_array = ByteArray::::default(); let offset = Self::ByteSize::USIZE.saturating_sub(field_bytes.len()); byte_array[offset..].copy_from_slice(field_bytes); Self::from_be_byte_array(byte_array) } /// Encode unsigned integer into serialized field element. /// /// The default implementation assumes a big endian encoding. fn encode_field_bytes(&self) -> FieldBytes { let mut field_bytes = FieldBytes::::default(); debug_assert!(field_bytes.len() <= Self::ByteSize::USIZE); let offset = Self::ByteSize::USIZE.saturating_sub(field_bytes.len()); field_bytes.copy_from_slice(&self.to_be_byte_array()[offset..]); field_bytes } } elliptic-curve-0.13.8/src/hash2curve/group_digest.rs000064400000000000000000000113521046102023000205500ustar 00000000000000//! Traits for handling hash to curve. use super::{hash_to_field, ExpandMsg, FromOkm, MapToCurve}; use crate::{CurveArithmetic, ProjectivePoint, Result}; use group::cofactor::CofactorGroup; /// Adds hashing arbitrary byte sequences to a valid group element pub trait GroupDigest: CurveArithmetic where ProjectivePoint: CofactorGroup, { /// The field element representation for a group value with multiple elements type FieldElement: FromOkm + MapToCurve> + Default + Copy; /// Computes the hash to curve routine. /// /// From : /// /// > Uniform encoding from byte strings to points in G. /// > That is, the distribution of its output is statistically close /// > to uniform in G. /// > This function is suitable for most applications requiring a random /// > oracle returning points in G assuming a cryptographically secure /// > hash function is used. /// /// # Examples /// /// ## Using a fixed size hash function /// /// ```ignore /// let pt = ProjectivePoint::hash_from_bytes::>(b"test data", b"CURVE_XMD:SHA-256_SSWU_RO_"); /// ``` /// /// ## Using an extendable output function /// /// ```ignore /// let pt = ProjectivePoint::hash_from_bytes::>(b"test data", b"CURVE_XOF:SHAKE-256_SSWU_RO_"); /// ``` /// /// # Errors /// See implementors of [`ExpandMsg`] for errors: /// - [`ExpandMsgXmd`] /// - [`ExpandMsgXof`] /// /// `len_in_bytes = ::Length * 2` /// /// [`ExpandMsgXmd`]: crate::hash2curve::ExpandMsgXmd /// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof fn hash_from_bytes<'a, X: ExpandMsg<'a>>( msgs: &[&[u8]], dsts: &'a [&'a [u8]], ) -> Result> { let mut u = [Self::FieldElement::default(), Self::FieldElement::default()]; hash_to_field::(msgs, dsts, &mut u)?; let q0 = u[0].map_to_curve(); let q1 = u[1].map_to_curve(); // Ideally we could add and then clear cofactor once // thus saving a call but the field elements may not // add properly due to the underlying implementation // which could result in an incorrect subgroup. // This is caused curve coefficients being different than // what is usually implemented. // FieldElement expects the `a` and `b` to be the original values // isogenies are different with curves like k256 and bls12-381. // This problem doesn't manifest for curves with no isogeny like p256. // For k256 and p256 clear_cofactor doesn't do anything anyway so it will be a no-op. Ok(q0.clear_cofactor().into() + q1.clear_cofactor()) } /// Computes the encode to curve routine. /// /// From : /// /// > Nonuniform encoding from byte strings to /// > points in G. That is, the distribution of its output is not /// > uniformly random in G: the set of possible outputs of /// > encode_to_curve is only a fraction of the points in G, and some /// > points in this set are more likely to be output than others. /// /// # Errors /// See implementors of [`ExpandMsg`] for errors: /// - [`ExpandMsgXmd`] /// - [`ExpandMsgXof`] /// /// `len_in_bytes = ::Length` /// /// [`ExpandMsgXmd`]: crate::hash2curve::ExpandMsgXmd /// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof fn encode_from_bytes<'a, X: ExpandMsg<'a>>( msgs: &[&[u8]], dsts: &'a [&'a [u8]], ) -> Result> { let mut u = [Self::FieldElement::default()]; hash_to_field::(msgs, dsts, &mut u)?; let q0 = u[0].map_to_curve(); Ok(q0.clear_cofactor().into()) } /// Computes the hash to field routine according to /// /// and returns a scalar. /// /// # Errors /// See implementors of [`ExpandMsg`] for errors: /// - [`ExpandMsgXmd`] /// - [`ExpandMsgXof`] /// /// `len_in_bytes = ::Length` /// /// [`ExpandMsgXmd`]: crate::hash2curve::ExpandMsgXmd /// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof fn hash_to_scalar<'a, X: ExpandMsg<'a>>( msgs: &[&[u8]], dsts: &'a [&'a [u8]], ) -> Result where Self::Scalar: FromOkm, { let mut u = [Self::Scalar::default()]; hash_to_field::(msgs, dsts, &mut u)?; Ok(u[0]) } } elliptic-curve-0.13.8/src/hash2curve/hash2field/expand_msg/xmd.rs000064400000000000000000001123531046102023000230060ustar 00000000000000//! `expand_message_xmd` based on a hash function. use core::marker::PhantomData; use super::{Domain, ExpandMsg, Expander}; use crate::{Error, Result}; use digest::{ core_api::BlockSizeUser, generic_array::{ typenum::{IsLess, IsLessOrEqual, Unsigned, U256}, GenericArray, }, FixedOutput, HashMarker, }; /// Placeholder type for implementing `expand_message_xmd` based on a hash function /// /// # Errors /// - `dst.is_empty()` /// - `len_in_bytes == 0` /// - `len_in_bytes > u16::MAX` /// - `len_in_bytes > 255 * HashT::OutputSize` pub struct ExpandMsgXmd(PhantomData) where HashT: BlockSizeUser + Default + FixedOutput + HashMarker, HashT::OutputSize: IsLess, HashT::OutputSize: IsLessOrEqual; /// ExpandMsgXmd implements expand_message_xmd for the ExpandMsg trait impl<'a, HashT> ExpandMsg<'a> for ExpandMsgXmd where HashT: BlockSizeUser + Default + FixedOutput + HashMarker, // If `len_in_bytes` is bigger then 256, length of the `DST` will depend on // the output size of the hash, which is still not allowed to be bigger then 256: // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#section-5.4.1-6 HashT::OutputSize: IsLess, // Constraint set by `expand_message_xmd`: // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#section-5.4.1-4 HashT::OutputSize: IsLessOrEqual, { type Expander = ExpanderXmd<'a, HashT>; fn expand_message( msgs: &[&[u8]], dsts: &'a [&'a [u8]], len_in_bytes: usize, ) -> Result { if len_in_bytes == 0 { return Err(Error); } let len_in_bytes_u16 = u16::try_from(len_in_bytes).map_err(|_| Error)?; let b_in_bytes = HashT::OutputSize::to_usize(); let ell = u8::try_from((len_in_bytes + b_in_bytes - 1) / b_in_bytes).map_err(|_| Error)?; let domain = Domain::xmd::(dsts)?; let mut b_0 = HashT::default(); b_0.update(&GenericArray::::default()); for msg in msgs { b_0.update(msg); } b_0.update(&len_in_bytes_u16.to_be_bytes()); b_0.update(&[0]); domain.update_hash(&mut b_0); b_0.update(&[domain.len()]); let b_0 = b_0.finalize_fixed(); let mut b_vals = HashT::default(); b_vals.update(&b_0[..]); b_vals.update(&[1u8]); domain.update_hash(&mut b_vals); b_vals.update(&[domain.len()]); let b_vals = b_vals.finalize_fixed(); Ok(ExpanderXmd { b_0, b_vals, domain, index: 1, offset: 0, ell, }) } } /// [`Expander`] type for [`ExpandMsgXmd`]. pub struct ExpanderXmd<'a, HashT> where HashT: BlockSizeUser + Default + FixedOutput + HashMarker, HashT::OutputSize: IsLess, HashT::OutputSize: IsLessOrEqual, { b_0: GenericArray, b_vals: GenericArray, domain: Domain<'a, HashT::OutputSize>, index: u8, offset: usize, ell: u8, } impl<'a, HashT> ExpanderXmd<'a, HashT> where HashT: BlockSizeUser + Default + FixedOutput + HashMarker, HashT::OutputSize: IsLess, HashT::OutputSize: IsLessOrEqual, { fn next(&mut self) -> bool { if self.index < self.ell { self.index += 1; self.offset = 0; // b_0 XOR b_(idx - 1) let mut tmp = GenericArray::::default(); self.b_0 .iter() .zip(&self.b_vals[..]) .enumerate() .for_each(|(j, (b0val, bi1val))| tmp[j] = b0val ^ bi1val); let mut b_vals = HashT::default(); b_vals.update(&tmp); b_vals.update(&[self.index]); self.domain.update_hash(&mut b_vals); b_vals.update(&[self.domain.len()]); self.b_vals = b_vals.finalize_fixed(); true } else { false } } } impl<'a, HashT> Expander for ExpanderXmd<'a, HashT> where HashT: BlockSizeUser + Default + FixedOutput + HashMarker, HashT::OutputSize: IsLess, HashT::OutputSize: IsLessOrEqual, { fn fill_bytes(&mut self, okm: &mut [u8]) { for b in okm { if self.offset == self.b_vals.len() && !self.next() { return; } *b = self.b_vals[self.offset]; self.offset += 1; } } } #[cfg(test)] mod test { use super::*; use core::mem; use generic_array::{ typenum::{U128, U32}, ArrayLength, }; use hex_literal::hex; use sha2::Sha256; fn assert_message( msg: &[u8], domain: &Domain<'_, HashT::OutputSize>, len_in_bytes: u16, bytes: &[u8], ) where HashT: BlockSizeUser + Default + FixedOutput + HashMarker, HashT::OutputSize: IsLess, { let block = HashT::BlockSize::to_usize(); assert_eq!( GenericArray::::default().as_slice(), &bytes[..block] ); let msg_len = block + msg.len(); assert_eq!(msg, &bytes[block..msg_len]); let l = msg_len + mem::size_of::(); assert_eq!(len_in_bytes.to_be_bytes(), &bytes[msg_len..l]); let pad = l + mem::size_of::(); assert_eq!([0], &bytes[l..pad]); let dst = pad + usize::from(domain.len()); domain.assert(&bytes[pad..dst]); let dst_len = dst + mem::size_of::(); assert_eq!([domain.len()], &bytes[dst..dst_len]); assert_eq!(dst_len, bytes.len()); } struct TestVector { msg: &'static [u8], msg_prime: &'static [u8], uniform_bytes: &'static [u8], } impl TestVector { #[allow(clippy::panic_in_result_fn)] fn assert>( &self, dst: &'static [u8], domain: &Domain<'_, HashT::OutputSize>, ) -> Result<()> where HashT: BlockSizeUser + Default + FixedOutput + HashMarker, HashT::OutputSize: IsLess + IsLessOrEqual, { assert_message::(self.msg, domain, L::to_u16(), self.msg_prime); let dst = [dst]; let mut expander = ExpandMsgXmd::::expand_message(&[self.msg], &dst, L::to_usize())?; let mut uniform_bytes = GenericArray::::default(); expander.fill_bytes(&mut uniform_bytes); assert_eq!(uniform_bytes.as_slice(), self.uniform_bytes); Ok(()) } } #[test] fn expand_message_xmd_sha_256() -> Result<()> { const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHA256-128"; const DST_PRIME: &[u8] = &hex!("515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"); let dst_prime = Domain::xmd::(&[DST])?; dst_prime.assert_dst(DST_PRIME); const TEST_VECTORS_32: &[TestVector] = &[ TestVector { msg: b"", msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), uniform_bytes: &hex!("68a985b87eb6b46952128911f2a4412bbc302a9d759667f87f7a21d803f07235"), }, TestVector { msg: b"abc", msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), uniform_bytes: &hex!("d8ccab23b5985ccea865c6c97b6e5b8350e794e603b4b97902f53a8a0d605615"), }, TestVector { msg: b"abcdef0123456789", msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), uniform_bytes: &hex!("eff31487c770a893cfb36f912fbfcbff40d5661771ca4b2cb4eafe524333f5c1"), }, TestVector { msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), uniform_bytes: &hex!("b23a1d2b4d97b2ef7785562a7e8bac7eed54ed6e97e29aa51bfe3f12ddad1ff9"), }, TestVector { msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), uniform_bytes: &hex!("4623227bcc01293b8c130bf771da8c298dede7383243dc0993d2d94823958c4c"), }, ]; for test_vector in TEST_VECTORS_32 { test_vector.assert::(DST, &dst_prime)?; } const TEST_VECTORS_128: &[TestVector] = &[ TestVector { msg: b"", msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), uniform_bytes: &hex!("af84c27ccfd45d41914fdff5df25293e221afc53d8ad2ac06d5e3e29485dadbee0d121587713a3e0dd4d5e69e93eb7cd4f5df4cd103e188cf60cb02edc3edf18eda8576c412b18ffb658e3dd6ec849469b979d444cf7b26911a08e63cf31f9dcc541708d3491184472c2c29bb749d4286b004ceb5ee6b9a7fa5b646c993f0ced"), }, TestVector { msg: b"abc", msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), uniform_bytes: &hex!("abba86a6129e366fc877aab32fc4ffc70120d8996c88aee2fe4b32d6c7b6437a647e6c3163d40b76a73cf6a5674ef1d890f95b664ee0afa5359a5c4e07985635bbecbac65d747d3d2da7ec2b8221b17b0ca9dc8a1ac1c07ea6a1e60583e2cb00058e77b7b72a298425cd1b941ad4ec65e8afc50303a22c0f99b0509b4c895f40"), }, TestVector { msg: b"abcdef0123456789", msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), uniform_bytes: &hex!("ef904a29bffc4cf9ee82832451c946ac3c8f8058ae97d8d629831a74c6572bd9ebd0df635cd1f208e2038e760c4994984ce73f0d55ea9f22af83ba4734569d4bc95e18350f740c07eef653cbb9f87910d833751825f0ebefa1abe5420bb52be14cf489b37fe1a72f7de2d10be453b2c9d9eb20c7e3f6edc5a60629178d9478df"), }, TestVector { msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), uniform_bytes: &hex!("80be107d0884f0d881bb460322f0443d38bd222db8bd0b0a5312a6fedb49c1bbd88fd75d8b9a09486c60123dfa1d73c1cc3169761b17476d3c6b7cbbd727acd0e2c942f4dd96ae3da5de368d26b32286e32de7e5a8cb2949f866a0b80c58116b29fa7fabb3ea7d520ee603e0c25bcaf0b9a5e92ec6a1fe4e0391d1cdbce8c68a"), }, TestVector { msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"), uniform_bytes: &hex!("546aff5444b5b79aa6148bd81728704c32decb73a3ba76e9e75885cad9def1d06d6792f8a7d12794e90efed817d96920d728896a4510864370c207f99bd4a608ea121700ef01ed879745ee3e4ceef777eda6d9e5e38b90c86ea6fb0b36504ba4a45d22e86f6db5dd43d98a294bebb9125d5b794e9d2a81181066eb954966a487"), }, ]; for test_vector in TEST_VECTORS_128 { test_vector.assert::(DST, &dst_prime)?; } Ok(()) } #[test] fn expand_message_xmd_sha_256_long() -> Result<()> { const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHA256-128-long-DST-1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"; const DST_PRIME: &[u8] = &hex!("412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"); let dst_prime = Domain::xmd::(&[DST])?; dst_prime.assert_dst(DST_PRIME); const TEST_VECTORS_32: &[TestVector] = &[ TestVector { msg: b"", msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), uniform_bytes: &hex!("e8dc0c8b686b7ef2074086fbdd2f30e3f8bfbd3bdf177f73f04b97ce618a3ed3"), }, TestVector { msg: b"abc", msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), uniform_bytes: &hex!("52dbf4f36cf560fca57dedec2ad924ee9c266341d8f3d6afe5171733b16bbb12"), }, TestVector { msg: b"abcdef0123456789", msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), uniform_bytes: &hex!("35387dcf22618f3728e6c686490f8b431f76550b0b2c61cbc1ce7001536f4521"), }, TestVector { msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), uniform_bytes: &hex!("01b637612bb18e840028be900a833a74414140dde0c4754c198532c3a0ba42bc"), }, TestVector { msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), uniform_bytes: &hex!("20cce7033cabc5460743180be6fa8aac5a103f56d481cf369a8accc0c374431b"), }, ]; for test_vector in TEST_VECTORS_32 { test_vector.assert::(DST, &dst_prime)?; } const TEST_VECTORS_128: &[TestVector] = &[ TestVector { msg: b"", msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), uniform_bytes: &hex!("14604d85432c68b757e485c8894db3117992fc57e0e136f71ad987f789a0abc287c47876978e2388a02af86b1e8d1342e5ce4f7aaa07a87321e691f6fba7e0072eecc1218aebb89fb14a0662322d5edbd873f0eb35260145cd4e64f748c5dfe60567e126604bcab1a3ee2dc0778102ae8a5cfd1429ebc0fa6bf1a53c36f55dfc"), }, TestVector { msg: b"abc", msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), uniform_bytes: &hex!("1a30a5e36fbdb87077552b9d18b9f0aee16e80181d5b951d0471d55b66684914aef87dbb3626eaabf5ded8cd0686567e503853e5c84c259ba0efc37f71c839da2129fe81afdaec7fbdc0ccd4c794727a17c0d20ff0ea55e1389d6982d1241cb8d165762dbc39fb0cee4474d2cbbd468a835ae5b2f20e4f959f56ab24cd6fe267"), }, TestVector { msg: b"abcdef0123456789", msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), uniform_bytes: &hex!("d2ecef3635d2397f34a9f86438d772db19ffe9924e28a1caf6f1c8f15603d4028f40891044e5c7e39ebb9b31339979ff33a4249206f67d4a1e7c765410bcd249ad78d407e303675918f20f26ce6d7027ed3774512ef5b00d816e51bfcc96c3539601fa48ef1c07e494bdc37054ba96ecb9dbd666417e3de289d4f424f502a982"), }, TestVector { msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), uniform_bytes: &hex!("ed6e8c036df90111410431431a232d41a32c86e296c05d426e5f44e75b9a50d335b2412bc6c91e0a6dc131de09c43110d9180d0a70f0d6289cb4e43b05f7ee5e9b3f42a1fad0f31bac6a625b3b5c50e3a83316783b649e5ecc9d3b1d9471cb5024b7ccf40d41d1751a04ca0356548bc6e703fca02ab521b505e8e45600508d32"), }, TestVector { msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", msg_prime: &hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"), uniform_bytes: &hex!("78b53f2413f3c688f07732c10e5ced29a17c6a16f717179ffbe38d92d6c9ec296502eb9889af83a1928cd162e845b0d3c5424e83280fed3d10cffb2f8431f14e7a23f4c68819d40617589e4c41169d0b56e0e3535be1fd71fbb08bb70c5b5ffed953d6c14bf7618b35fc1f4c4b30538236b4b08c9fbf90462447a8ada60be495"), }, ]; for test_vector in TEST_VECTORS_128 { test_vector.assert::(DST, &dst_prime)?; } Ok(()) } #[test] fn expand_message_xmd_sha_512() -> Result<()> { use sha2::Sha512; const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHA512-256"; const DST_PRIME: &[u8] = &hex!("515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"); let dst_prime = Domain::xmd::(&[DST])?; dst_prime.assert_dst(DST_PRIME); const TEST_VECTORS_32: &[TestVector] = &[ TestVector { msg: b"", msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), uniform_bytes: &hex!("6b9a7312411d92f921c6f68ca0b6380730a1a4d982c507211a90964c394179ba"), }, TestVector { msg: b"abc", msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), uniform_bytes: &hex!("0da749f12fbe5483eb066a5f595055679b976e93abe9be6f0f6318bce7aca8dc"), }, TestVector { msg: b"abcdef0123456789", msg_prime: &hex!("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), uniform_bytes: &hex!("087e45a86e2939ee8b91100af1583c4938e0f5fc6c9db4b107b83346bc967f58"), }, TestVector { msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), uniform_bytes: &hex!("7336234ee9983902440f6bc35b348352013becd88938d2afec44311caf8356b3"), }, TestVector { msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), uniform_bytes: &hex!("57b5f7e766d5be68a6bfe1768e3c2b7f1228b3e4b3134956dd73a59b954c66f4"), }, ]; for test_vector in TEST_VECTORS_32 { test_vector.assert::(DST, &dst_prime)?; } const TEST_VECTORS_128: &[TestVector] = &[ TestVector { msg: b"", msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), uniform_bytes: &hex!("41b037d1734a5f8df225dd8c7de38f851efdb45c372887be655212d07251b921b052b62eaed99b46f72f2ef4cc96bfaf254ebbbec091e1a3b9e4fb5e5b619d2e0c5414800a1d882b62bb5cd1778f098b8eb6cb399d5d9d18f5d5842cf5d13d7eb00a7cff859b605da678b318bd0e65ebff70bec88c753b159a805d2c89c55961"), }, TestVector { msg: b"abc", msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), uniform_bytes: &hex!("7f1dddd13c08b543f2e2037b14cefb255b44c83cc397c1786d975653e36a6b11bdd7732d8b38adb4a0edc26a0cef4bb45217135456e58fbca1703cd6032cb1347ee720b87972d63fbf232587043ed2901bce7f22610c0419751c065922b488431851041310ad659e4b23520e1772ab29dcdeb2002222a363f0c2b1c972b3efe1"), }, TestVector { msg: b"abcdef0123456789", msg_prime: &hex!("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), uniform_bytes: &hex!("3f721f208e6199fe903545abc26c837ce59ac6fa45733f1baaf0222f8b7acb0424814fcb5eecf6c1d38f06e9d0a6ccfbf85ae612ab8735dfdf9ce84c372a77c8f9e1c1e952c3a61b7567dd0693016af51d2745822663d0c2367e3f4f0bed827feecc2aaf98c949b5ed0d35c3f1023d64ad1407924288d366ea159f46287e61ac"), }, TestVector { msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), uniform_bytes: &hex!("b799b045a58c8d2b4334cf54b78260b45eec544f9f2fb5bd12fb603eaee70db7317bf807c406e26373922b7b8920fa29142703dd52bdf280084fb7ef69da78afdf80b3586395b433dc66cde048a258e476a561e9deba7060af40adf30c64249ca7ddea79806ee5beb9a1422949471d267b21bc88e688e4014087a0b592b695ed"), }, TestVector { msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", msg_prime: &hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"), uniform_bytes: &hex!("05b0bfef265dcee87654372777b7c44177e2ae4c13a27f103340d9cd11c86cb2426ffcad5bd964080c2aee97f03be1ca18e30a1f14e27bc11ebbd650f305269cc9fb1db08bf90bfc79b42a952b46daf810359e7bc36452684784a64952c343c52e5124cd1f71d474d5197fefc571a92929c9084ffe1112cf5eea5192ebff330b"), }, ]; for test_vector in TEST_VECTORS_128 { test_vector.assert::(DST, &dst_prime)?; } Ok(()) } } elliptic-curve-0.13.8/src/hash2curve/hash2field/expand_msg/xof.rs000064400000000000000000000712241046102023000230130ustar 00000000000000//! `expand_message_xof` for the `ExpandMsg` trait use super::{Domain, ExpandMsg, Expander}; use crate::{Error, Result}; use digest::{ExtendableOutput, Update, XofReader}; use generic_array::typenum::U32; /// Placeholder type for implementing `expand_message_xof` based on an extendable output function /// /// # Errors /// - `dst.is_empty()` /// - `len_in_bytes == 0` /// - `len_in_bytes > u16::MAX` pub struct ExpandMsgXof where HashT: Default + ExtendableOutput + Update, { reader: ::Reader, } /// ExpandMsgXof implements `expand_message_xof` for the [`ExpandMsg`] trait impl<'a, HashT> ExpandMsg<'a> for ExpandMsgXof where HashT: Default + ExtendableOutput + Update, { type Expander = Self; fn expand_message( msgs: &[&[u8]], dsts: &'a [&'a [u8]], len_in_bytes: usize, ) -> Result { if len_in_bytes == 0 { return Err(Error); } let len_in_bytes = u16::try_from(len_in_bytes).map_err(|_| Error)?; let domain = Domain::::xof::(dsts)?; let mut reader = HashT::default(); for msg in msgs { reader = reader.chain(msg); } reader.update(&len_in_bytes.to_be_bytes()); domain.update_hash(&mut reader); reader.update(&[domain.len()]); let reader = reader.finalize_xof(); Ok(Self { reader }) } } impl Expander for ExpandMsgXof where HashT: Default + ExtendableOutput + Update, { fn fill_bytes(&mut self, okm: &mut [u8]) { self.reader.read(okm); } } #[cfg(test)] mod test { use super::*; use core::mem; use generic_array::{ typenum::{U128, U32}, ArrayLength, GenericArray, }; use hex_literal::hex; use sha3::Shake128; fn assert_message(msg: &[u8], domain: &Domain<'_, U32>, len_in_bytes: u16, bytes: &[u8]) { let msg_len = msg.len(); assert_eq!(msg, &bytes[..msg_len]); let len_in_bytes_len = msg_len + mem::size_of::(); assert_eq!( len_in_bytes.to_be_bytes(), &bytes[msg_len..len_in_bytes_len] ); let dst = len_in_bytes_len + usize::from(domain.len()); domain.assert(&bytes[len_in_bytes_len..dst]); let dst_len = dst + mem::size_of::(); assert_eq!([domain.len()], &bytes[dst..dst_len]); assert_eq!(dst_len, bytes.len()); } struct TestVector { msg: &'static [u8], msg_prime: &'static [u8], uniform_bytes: &'static [u8], } impl TestVector { #[allow(clippy::panic_in_result_fn)] fn assert(&self, dst: &'static [u8], domain: &Domain<'_, U32>) -> Result<()> where HashT: Default + ExtendableOutput + Update, L: ArrayLength, { assert_message(self.msg, domain, L::to_u16(), self.msg_prime); let mut expander = ExpandMsgXof::::expand_message(&[self.msg], &[dst], L::to_usize())?; let mut uniform_bytes = GenericArray::::default(); expander.fill_bytes(&mut uniform_bytes); assert_eq!(uniform_bytes.as_slice(), self.uniform_bytes); Ok(()) } } #[test] fn expand_message_xof_shake_128() -> Result<()> { const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHAKE128"; const DST_PRIME: &[u8] = &hex!("515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"); let dst_prime = Domain::::xof::(&[DST])?; dst_prime.assert_dst(DST_PRIME); const TEST_VECTORS_32: &[TestVector] = &[ TestVector { msg: b"", msg_prime: &hex!("0020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), uniform_bytes: &hex!("86518c9cd86581486e9485aa74ab35ba150d1c75c88e26b7043e44e2acd735a2"), }, TestVector { msg: b"abc", msg_prime: &hex!("6162630020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), uniform_bytes: &hex!("8696af52a4d862417c0763556073f47bc9b9ba43c99b505305cb1ec04a9ab468"), }, TestVector { msg: b"abcdef0123456789", msg_prime: &hex!("616263646566303132333435363738390020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), uniform_bytes: &hex!("912c58deac4821c3509dbefa094df54b34b8f5d01a191d1d3108a2c89077acca"), }, TestVector { msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), uniform_bytes: &hex!("1adbcc448aef2a0cebc71dac9f756b22e51839d348e031e63b33ebb50faeaf3f"), }, TestVector { msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), uniform_bytes: &hex!("df3447cc5f3e9a77da10f819218ddf31342c310778e0e4ef72bbaecee786a4fe"), }, ]; for test_vector in TEST_VECTORS_32 { test_vector.assert::(DST, &dst_prime)?; } const TEST_VECTORS_128: &[TestVector] = &[ TestVector { msg: b"", msg_prime: &hex!("0080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), uniform_bytes: &hex!("7314ff1a155a2fb99a0171dc71b89ab6e3b2b7d59e38e64419b8b6294d03ffee42491f11370261f436220ef787f8f76f5b26bdcd850071920ce023f3ac46847744f4612b8714db8f5db83205b2e625d95afd7d7b4d3094d3bdde815f52850bb41ead9822e08f22cf41d615a303b0d9dde73263c049a7b9898208003a739a2e57"), }, TestVector { msg: b"abc", msg_prime: &hex!("6162630080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), uniform_bytes: &hex!("c952f0c8e529ca8824acc6a4cab0e782fc3648c563ddb00da7399f2ae35654f4860ec671db2356ba7baa55a34a9d7f79197b60ddae6e64768a37d699a78323496db3878c8d64d909d0f8a7de4927dcab0d3dbbc26cb20a49eceb0530b431cdf47bc8c0fa3e0d88f53b318b6739fbed7d7634974f1b5c386d6230c76260d5337a"), }, TestVector { msg: b"abcdef0123456789", msg_prime: &hex!("616263646566303132333435363738390080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), uniform_bytes: &hex!("19b65ee7afec6ac06a144f2d6134f08eeec185f1a890fe34e68f0e377b7d0312883c048d9b8a1d6ecc3b541cb4987c26f45e0c82691ea299b5e6889bbfe589153016d8131717ba26f07c3c14ffbef1f3eff9752e5b6183f43871a78219a75e7000fbac6a7072e2b83c790a3a5aecd9d14be79f9fd4fb180960a3772e08680495"), }, TestVector { msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), uniform_bytes: &hex!("ca1b56861482b16eae0f4a26212112362fcc2d76dcc80c93c4182ed66c5113fe41733ed68be2942a3487394317f3379856f4822a611735e50528a60e7ade8ec8c71670fec6661e2c59a09ed36386513221688b35dc47e3c3111ee8c67ff49579089d661caa29db1ef10eb6eace575bf3dc9806e7c4016bd50f3c0e2a6481ee6d"), }, TestVector { msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"), uniform_bytes: &hex!("9d763a5ce58f65c91531b4100c7266d479a5d9777ba761693d052acd37d149e7ac91c796a10b919cd74a591a1e38719fb91b7203e2af31eac3bff7ead2c195af7d88b8bc0a8adf3d1e90ab9bed6ddc2b7f655dd86c730bdeaea884e73741097142c92f0e3fc1811b699ba593c7fbd81da288a29d423df831652e3a01a9374999"), }, ]; for test_vector in TEST_VECTORS_128 { test_vector.assert::(DST, &dst_prime)?; } Ok(()) } #[test] fn expand_message_xof_shake_128_long() -> Result<()> { const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHAKE128-long-DST-111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"; const DST_PRIME: &[u8] = &hex!("acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"); let dst_prime = Domain::::xof::(&[DST])?; dst_prime.assert_dst(DST_PRIME); const TEST_VECTORS_32: &[TestVector] = &[ TestVector { msg: b"", msg_prime: &hex!("0020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), uniform_bytes: &hex!("827c6216330a122352312bccc0c8d6e7a146c5257a776dbd9ad9d75cd880fc53"), }, TestVector { msg: b"abc", msg_prime: &hex!("6162630020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), uniform_bytes: &hex!("690c8d82c7213b4282c6cb41c00e31ea1d3e2005f93ad19bbf6da40f15790c5c"), }, TestVector { msg: b"abcdef0123456789", msg_prime: &hex!("616263646566303132333435363738390020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), uniform_bytes: &hex!("979e3a15064afbbcf99f62cc09fa9c85028afcf3f825eb0711894dcfc2f57057"), }, TestVector { msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), uniform_bytes: &hex!("c5a9220962d9edc212c063f4f65b609755a1ed96e62f9db5d1fd6adb5a8dc52b"), }, TestVector { msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), uniform_bytes: &hex!("f7b96a5901af5d78ce1d071d9c383cac66a1dfadb508300ec6aeaea0d62d5d62"), }, ]; for test_vector in TEST_VECTORS_32 { test_vector.assert::(DST, &dst_prime)?; } const TEST_VECTORS_128: &[TestVector] = &[ TestVector { msg: b"", msg_prime: &hex!("0080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), uniform_bytes: &hex!("3890dbab00a2830be398524b71c2713bbef5f4884ac2e6f070b092effdb19208c7df943dc5dcbaee3094a78c267ef276632ee2c8ea0c05363c94b6348500fae4208345dd3475fe0c834c2beac7fa7bc181692fb728c0a53d809fc8111495222ce0f38468b11becb15b32060218e285c57a60162c2c8bb5b6bded13973cd41819"), }, TestVector { msg: b"abc", msg_prime: &hex!("6162630080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), uniform_bytes: &hex!("41b7ffa7a301b5c1441495ebb9774e2a53dbbf4e54b9a1af6a20fd41eafd69ef7b9418599c5545b1ee422f363642b01d4a53449313f68da3e49dddb9cd25b97465170537d45dcbdf92391b5bdff344db4bd06311a05bca7dcd360b6caec849c299133e5c9194f4e15e3e23cfaab4003fab776f6ac0bfae9144c6e2e1c62e7d57"), }, TestVector { msg: b"abcdef0123456789", msg_prime: &hex!("616263646566303132333435363738390080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), uniform_bytes: &hex!("55317e4a21318472cd2290c3082957e1242241d9e0d04f47026f03401643131401071f01aa03038b2783e795bdfa8a3541c194ad5de7cb9c225133e24af6c86e748deb52e560569bd54ef4dac03465111a3a44b0ea490fb36777ff8ea9f1a8a3e8e0de3cf0880b4b2f8dd37d3a85a8b82375aee4fa0e909f9763319b55778e71"), }, TestVector { msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), uniform_bytes: &hex!("19fdd2639f082e31c77717ac9bb032a22ff0958382b2dbb39020cdc78f0da43305414806abf9a561cb2d0067eb2f7bc544482f75623438ed4b4e39dd9e6e2909dd858bd8f1d57cd0fce2d3150d90aa67b4498bdf2df98c0100dd1a173436ba5d0df6be1defb0b2ce55ccd2f4fc05eb7cb2c019c35d5398b85adc676da4238bc7"), }, TestVector { msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"), uniform_bytes: &hex!("945373f0b3431a103333ba6a0a34f1efab2702efde41754c4cb1d5216d5b0a92a67458d968562bde7fa6310a83f53dda1383680a276a283438d58ceebfa7ab7ba72499d4a3eddc860595f63c93b1c5e823ea41fc490d938398a26db28f61857698553e93f0574eb8c5017bfed6249491f9976aaa8d23d9485339cc85ca329308"), }, ]; for test_vector in TEST_VECTORS_128 { test_vector.assert::(DST, &dst_prime)?; } Ok(()) } #[test] fn expand_message_xof_shake_256() -> Result<()> { use sha3::Shake256; const DST: &[u8] = b"QUUX-V01-CS02-with-expander-SHAKE256"; const DST_PRIME: &[u8] = &hex!("515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"); let dst_prime = Domain::::xof::(&[DST])?; dst_prime.assert_dst(DST_PRIME); const TEST_VECTORS_32: &[TestVector] = &[ TestVector { msg: b"", msg_prime: &hex!("0020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), uniform_bytes: &hex!("2ffc05c48ed32b95d72e807f6eab9f7530dd1c2f013914c8fed38c5ccc15ad76"), }, TestVector { msg: b"abc", msg_prime: &hex!("6162630020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), uniform_bytes: &hex!("b39e493867e2767216792abce1f2676c197c0692aed061560ead251821808e07"), }, TestVector { msg: b"abcdef0123456789", msg_prime: &hex!("616263646566303132333435363738390020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), uniform_bytes: &hex!("245389cf44a13f0e70af8665fe5337ec2dcd138890bb7901c4ad9cfceb054b65"), }, TestVector { msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), uniform_bytes: &hex!("719b3911821e6428a5ed9b8e600f2866bcf23c8f0515e52d6c6c019a03f16f0e"), }, TestVector { msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), uniform_bytes: &hex!("9181ead5220b1963f1b5951f35547a5ea86a820562287d6ca4723633d17ccbbc"), }, ]; for test_vector in TEST_VECTORS_32 { test_vector.assert::(DST, &dst_prime)?; } const TEST_VECTORS_128: &[TestVector] = &[ TestVector { msg: b"", msg_prime: &hex!("0080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), uniform_bytes: &hex!("7a1361d2d7d82d79e035b8880c5a3c86c5afa719478c007d96e6c88737a3f631dd74a2c88df79a4cb5e5d9f7504957c70d669ec6bfedc31e01e2bacc4ff3fdf9b6a00b17cc18d9d72ace7d6b81c2e481b4f73f34f9a7505dccbe8f5485f3d20c5409b0310093d5d6492dea4e18aa6979c23c8ea5de01582e9689612afbb353df"), }, TestVector { msg: b"abc", msg_prime: &hex!("6162630080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), uniform_bytes: &hex!("a54303e6b172909783353ab05ef08dd435a558c3197db0c132134649708e0b9b4e34fb99b92a9e9e28fc1f1d8860d85897a8e021e6382f3eea10577f968ff6df6c45fe624ce65ca25932f679a42a404bc3681efe03fcd45ef73bb3a8f79ba784f80f55ea8a3c367408f30381299617f50c8cf8fbb21d0f1e1d70b0131a7b6fbe"), }, TestVector { msg: b"abcdef0123456789", msg_prime: &hex!("616263646566303132333435363738390080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), uniform_bytes: &hex!("e42e4d9538a189316e3154b821c1bafb390f78b2f010ea404e6ac063deb8c0852fcd412e098e231e43427bd2be1330bb47b4039ad57b30ae1fc94e34993b162ff4d695e42d59d9777ea18d3848d9d336c25d2acb93adcad009bcfb9cde12286df267ada283063de0bb1505565b2eb6c90e31c48798ecdc71a71756a9110ff373"), }, TestVector { msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", msg_prime: &hex!("713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), uniform_bytes: &hex!("4ac054dda0a38a65d0ecf7afd3c2812300027c8789655e47aecf1ecc1a2426b17444c7482c99e5907afd9c25b991990490bb9c686f43e79b4471a23a703d4b02f23c669737a886a7ec28bddb92c3a98de63ebf878aa363a501a60055c048bea11840c4717beae7eee28c3cfa42857b3d130188571943a7bd747de831bd6444e0"), }, TestVector { msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", msg_prime: &hex!("613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"), uniform_bytes: &hex!("09afc76d51c2cccbc129c2315df66c2be7295a231203b8ab2dd7f95c2772c68e500bc72e20c602abc9964663b7a03a389be128c56971ce81001a0b875e7fd17822db9d69792ddf6a23a151bf470079c518279aef3e75611f8f828994a9988f4a8a256ddb8bae161e658d5a2a09bcfe839c6396dc06ee5c8ff3c22d3b1f9deb7e"), }, ]; for test_vector in TEST_VECTORS_128 { test_vector.assert::(DST, &dst_prime)?; } Ok(()) } } elliptic-curve-0.13.8/src/hash2curve/hash2field/expand_msg.rs000064400000000000000000000100421046102023000222060ustar 00000000000000//! `expand_message` interface `for hash_to_field`. pub(super) mod xmd; pub(super) mod xof; use crate::{Error, Result}; use digest::{Digest, ExtendableOutput, Update, XofReader}; use generic_array::typenum::{IsLess, U256}; use generic_array::{ArrayLength, GenericArray}; /// Salt when the DST is too long const OVERSIZE_DST_SALT: &[u8] = b"H2C-OVERSIZE-DST-"; /// Maximum domain separation tag length const MAX_DST_LEN: usize = 255; /// Trait for types implementing expand_message interface for `hash_to_field`. /// /// # Errors /// See implementors of [`ExpandMsg`] for errors. pub trait ExpandMsg<'a> { /// Type holding data for the [`Expander`]. type Expander: Expander + Sized; /// Expands `msg` to the required number of bytes. /// /// Returns an expander that can be used to call `read` until enough /// bytes have been consumed fn expand_message( msgs: &[&[u8]], dsts: &'a [&'a [u8]], len_in_bytes: usize, ) -> Result; } /// Expander that, call `read` until enough bytes have been consumed. pub trait Expander { /// Fill the array with the expanded bytes fn fill_bytes(&mut self, okm: &mut [u8]); } /// The domain separation tag /// /// Implements [section 5.4.3 of `draft-irtf-cfrg-hash-to-curve-13`][dst]. /// /// [dst]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-13#section-5.4.3 pub(crate) enum Domain<'a, L> where L: ArrayLength + IsLess, { /// > 255 Hashed(GenericArray), /// <= 255 Array(&'a [&'a [u8]]), } impl<'a, L> Domain<'a, L> where L: ArrayLength + IsLess, { pub fn xof(dsts: &'a [&'a [u8]]) -> Result where X: Default + ExtendableOutput + Update, { if dsts.is_empty() { Err(Error) } else if dsts.iter().map(|dst| dst.len()).sum::() > MAX_DST_LEN { let mut data = GenericArray::::default(); let mut hash = X::default(); hash.update(OVERSIZE_DST_SALT); for dst in dsts { hash.update(dst); } hash.finalize_xof().read(&mut data); Ok(Self::Hashed(data)) } else { Ok(Self::Array(dsts)) } } pub fn xmd(dsts: &'a [&'a [u8]]) -> Result where X: Digest, { if dsts.is_empty() { Err(Error) } else if dsts.iter().map(|dst| dst.len()).sum::() > MAX_DST_LEN { Ok(Self::Hashed({ let mut hash = X::new(); hash.update(OVERSIZE_DST_SALT); for dst in dsts { hash.update(dst); } hash.finalize() })) } else { Ok(Self::Array(dsts)) } } pub fn update_hash(&self, hash: &mut HashT) { match self { Self::Hashed(d) => hash.update(d), Self::Array(d) => { for d in d.iter() { hash.update(d) } } } } pub fn len(&self) -> u8 { match self { // Can't overflow because it's enforced on a type level. Self::Hashed(_) => L::to_u8(), // Can't overflow because it's checked on creation. Self::Array(d) => { u8::try_from(d.iter().map(|d| d.len()).sum::()).expect("length overflow") } } } #[cfg(test)] pub fn assert(&self, bytes: &[u8]) { let data = match self { Domain::Hashed(d) => d.to_vec(), Domain::Array(d) => d.iter().copied().flatten().copied().collect(), }; assert_eq!(data, bytes); } #[cfg(test)] pub fn assert_dst(&self, bytes: &[u8]) { let data = match self { Domain::Hashed(d) => d.to_vec(), Domain::Array(d) => d.iter().copied().flatten().copied().collect(), }; assert_eq!(data, &bytes[..bytes.len() - 1]); assert_eq!(self.len(), bytes[bytes.len() - 1]); } } elliptic-curve-0.13.8/src/hash2curve/hash2field.rs000064400000000000000000000027401046102023000200670ustar 00000000000000//! Traits for hashing to field elements. //! //! mod expand_msg; pub use expand_msg::{xmd::*, xof::*, *}; use crate::{Error, Result}; use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; /// The trait for helping to convert to a field element. pub trait FromOkm { /// The number of bytes needed to convert to a field element. type Length: ArrayLength; /// Convert a byte sequence into a field element. fn from_okm(data: &GenericArray) -> Self; } /// Convert an arbitrary byte sequence into a field element. /// /// /// /// # Errors /// See implementors of [`ExpandMsg`] for errors: /// - [`ExpandMsgXmd`] /// - [`ExpandMsgXof`] /// /// `len_in_bytes = T::Length * out.len()` /// /// [`ExpandMsgXmd`]: crate::hash2field::ExpandMsgXmd /// [`ExpandMsgXof`]: crate::hash2field::ExpandMsgXof #[doc(hidden)] pub fn hash_to_field<'a, E, T>(data: &[&[u8]], domain: &'a [&'a [u8]], out: &mut [T]) -> Result<()> where E: ExpandMsg<'a>, T: FromOkm + Default, { let len_in_bytes = T::Length::to_usize().checked_mul(out.len()).ok_or(Error)?; let mut tmp = GenericArray::::Length>::default(); let mut expander = E::expand_message(data, domain, len_in_bytes)?; for o in out.iter_mut() { expander.fill_bytes(&mut tmp); *o = T::from_okm(&tmp); } Ok(()) } elliptic-curve-0.13.8/src/hash2curve/isogeny.rs000064400000000000000000000036271046102023000175400ustar 00000000000000//! Traits for mapping an isogeny to another curve //! //! use core::ops::{AddAssign, Mul}; use ff::Field; use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; /// The coefficients for mapping from one isogenous curve to another pub struct IsogenyCoefficients> { /// The coefficients for the x numerator pub xnum: &'static [F], /// The coefficients for the x denominator pub xden: &'static [F], /// The coefficients for the y numerator pub ynum: &'static [F], /// The coefficients for the x denominator pub yden: &'static [F], } /// The [`Isogeny`] methods to map to another curve. pub trait Isogeny: Field + AddAssign + Mul { /// The maximum number of coefficients type Degree: ArrayLength; /// The isogeny coefficients const COEFFICIENTS: IsogenyCoefficients; /// Map from the isogeny points to the main curve fn isogeny(x: Self, y: Self) -> (Self, Self) { let mut xs = GenericArray::::default(); xs[0] = Self::ONE; xs[1] = x; xs[2] = x.square(); for i in 3..Self::Degree::to_usize() { xs[i] = xs[i - 1] * x; } let x_num = Self::compute_iso(&xs, Self::COEFFICIENTS.xnum); let x_den = Self::compute_iso(&xs, Self::COEFFICIENTS.xden) .invert() .unwrap(); let y_num = Self::compute_iso(&xs, Self::COEFFICIENTS.ynum) * y; let y_den = Self::compute_iso(&xs, Self::COEFFICIENTS.yden) .invert() .unwrap(); (x_num * x_den, y_num * y_den) } /// Compute the ISO transform fn compute_iso(xxs: &[Self], k: &[Self]) -> Self { let mut xx = Self::ZERO; for (xi, ki) in xxs.iter().zip(k.iter()) { xx += *xi * ki; } xx } } elliptic-curve-0.13.8/src/hash2curve/map2curve.rs000064400000000000000000000005451046102023000177630ustar 00000000000000//! 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; } elliptic-curve-0.13.8/src/hash2curve/osswu.rs000064400000000000000000000103561046102023000172400ustar 00000000000000//! Optimized simplified Shallue-van de Woestijne-Ulas methods. //! //! use ff::Field; use subtle::Choice; use subtle::ConditionallySelectable; use subtle::ConstantTimeEq; /// The Optimized Simplified Shallue-van de Woestijne-Ulas parameters pub struct OsswuMapParams where F: Field, { /// The first constant term pub c1: &'static [u64], /// The second constant term pub c2: F, /// The ISO A variable or Curve A variable pub map_a: F, /// The ISO A variable or Curve A variable pub map_b: F, /// The Z parameter pub z: F, } /// Trait for determining the parity of the field pub trait Sgn0 { /// Return the parity of the field /// 1 == negative /// 0 == non-negative fn sgn0(&self) -> Choice; } /// The optimized simplified Shallue-van de Woestijne-Ulas method /// for mapping elliptic curve scalars to affine points. pub trait OsswuMap: Field + Sgn0 { /// The OSSWU parameters for mapping the field to affine points. /// For Weierstrass curves having A==0 or B==0, the parameters /// should be for isogeny where A≠0 and B≠0. const PARAMS: OsswuMapParams; /// Optimized sqrt_ratio for q = 3 mod 4. fn sqrt_ratio_3mod4(u: Self, v: Self) -> (Choice, Self) { // 1. tv1 = v^2 let tv1 = v.square(); // 2. tv2 = u * v let tv2 = u * v; // 3. tv1 = tv1 * tv2 let tv1 = tv1 * tv2; // 4. y1 = tv1^c1 let y1 = tv1.pow_vartime(Self::PARAMS.c1); // 5. y1 = y1 * tv2 let y1 = y1 * tv2; // 6. y2 = y1 * c2 let y2 = y1 * Self::PARAMS.c2; // 7. tv3 = y1^2 let tv3 = y1.square(); // 8. tv3 = tv3 * v let tv3 = tv3 * v; // 9. isQR = tv3 == u let is_qr = tv3.ct_eq(&u); // 10. y = CMOV(y2, y1, isQR) let y = ConditionallySelectable::conditional_select(&y2, &y1, is_qr); // 11. return (isQR, y) (is_qr, y) } /// Convert this field element into an affine point on the elliptic curve /// returning (X, Y). For Weierstrass curves having A==0 or B==0 /// the result is a point on an isogeny. fn osswu(&self) -> (Self, Self) { // 1. tv1 = u^2 let tv1 = self.square(); // 2. tv1 = Z * tv1 let tv1 = Self::PARAMS.z * tv1; // 3. tv2 = tv1^2 let tv2 = tv1.square(); // 4. tv2 = tv2 + tv1 let tv2 = tv2 + tv1; // 5. tv3 = tv2 + 1 let tv3 = tv2 + Self::ONE; // 6. tv3 = B * tv3 let tv3 = Self::PARAMS.map_b * tv3; // 7. tv4 = CMOV(Z, -tv2, tv2 != 0) let tv4 = ConditionallySelectable::conditional_select( &Self::PARAMS.z, &-tv2, !Field::is_zero(&tv2), ); // 8. tv4 = A * tv4 let tv4 = Self::PARAMS.map_a * tv4; // 9. tv2 = tv3^2 let tv2 = tv3.square(); // 10. tv6 = tv4^2 let tv6 = tv4.square(); // 11. tv5 = A * tv6 let tv5 = Self::PARAMS.map_a * tv6; // 12. tv2 = tv2 + tv5 let tv2 = tv2 + tv5; // 13. tv2 = tv2 * tv3 let tv2 = tv2 * tv3; // 14. tv6 = tv6 * tv4 let tv6 = tv6 * tv4; // 15. tv5 = B * tv6 let tv5 = Self::PARAMS.map_b * tv6; // 16. tv2 = tv2 + tv5 let tv2 = tv2 + tv5; // 17. x = tv1 * tv3 let x = tv1 * tv3; // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6) let (is_gx1_square, y1) = Self::sqrt_ratio_3mod4(tv2, tv6); // 19. y = tv1 * u let y = tv1 * self; // 20. y = y * y1 let y = y * y1; // 21. x = CMOV(x, tv3, is_gx1_square) let x = ConditionallySelectable::conditional_select(&x, &tv3, is_gx1_square); // 22. y = CMOV(y, y1, is_gx1_square) let y = ConditionallySelectable::conditional_select(&y, &y1, is_gx1_square); // 23. e1 = sgn0(u) == sgn0(y) let e1 = self.sgn0().ct_eq(&y.sgn0()); // 24. y = CMOV(-y, y, e1) let y = ConditionallySelectable::conditional_select(&-y, &y, e1); // 25. x = x / tv4 let x = x * tv4.invert().unwrap(); // 26. return (x, y) (x, y) } } elliptic-curve-0.13.8/src/hash2curve.rs000064400000000000000000000004671046102023000160620ustar 00000000000000//! Traits for hashing byte sequences to curve points. //! //! mod group_digest; mod hash2field; mod isogeny; mod map2curve; mod osswu; pub use group_digest::*; pub use hash2field::*; pub use isogeny::*; pub use map2curve::*; pub use osswu::*; elliptic-curve-0.13.8/src/jwk.rs000064400000000000000000000542121046102023000146000ustar 00000000000000//! JSON Web Key (JWK) Support. //! //! Specified in RFC 7518 Section 6: Cryptographic Algorithms for Keys: //! use crate::{ sec1::{Coordinates, EncodedPoint, ModulusSize, ValidatePublicKey}, secret_key::SecretKey, Curve, Error, FieldBytes, FieldBytesSize, Result, }; use alloc::{ borrow::ToOwned, format, string::{String, ToString}, }; use base64ct::{Base64UrlUnpadded as Base64Url, Encoding}; use core::{ fmt::{self, Debug}, marker::PhantomData, str::{self, FromStr}, }; use serdect::serde::{de, ser, Deserialize, Serialize}; use zeroize::{Zeroize, ZeroizeOnDrop}; #[cfg(feature = "arithmetic")] use crate::{ public_key::PublicKey, sec1::{FromEncodedPoint, ToEncodedPoint}, AffinePoint, CurveArithmetic, }; /// Key Type (`kty`) for elliptic curve keys. pub const EC_KTY: &str = "EC"; /// Deserialization error message. const DE_ERROR_MSG: &str = "struct JwkEcKey with 5 elements"; /// Name of the JWK type const JWK_TYPE_NAME: &str = "JwkEcKey"; /// Field names const FIELDS: &[&str] = &["kty", "crv", "x", "y", "d"]; /// Elliptic curve parameters used by JSON Web Keys. pub trait JwkParameters: Curve { /// The `crv` parameter which identifies a particular elliptic curve /// as defined in RFC 7518 Section 6.2.1.1: /// /// /// Curve values are registered in the IANA "JSON Web Key Elliptic Curve" /// registry defined in RFC 7518 Section 7.6: /// const CRV: &'static str; } /// JSON Web Key (JWK) with a `kty` of `"EC"` (elliptic curve). /// /// Specified in [RFC 7518 Section 6: Cryptographic Algorithms for Keys][1]. /// /// This type can represent either a public/private keypair, or just a /// public key, depending on whether or not the `d` parameter is present. /// /// [1]: https://tools.ietf.org/html/rfc7518#section-6 // TODO(tarcieri): eagerly decode or validate `x`, `y`, and `d` as Base64 #[derive(Clone)] pub struct JwkEcKey { /// The `crv` parameter which identifies a particular elliptic curve /// as defined in RFC 7518 Section 6.2.1.1: /// crv: String, /// The x-coordinate of the elliptic curve point which is the public key /// value associated with this JWK as defined in RFC 7518 6.2.1.2: /// x: String, /// The y-coordinate of the elliptic curve point which is the public key /// value associated with this JWK as defined in RFC 7518 6.2.1.3: /// y: String, /// The `d` ECC private key parameter as described in RFC 7518 6.2.2.1: /// /// /// Value is optional and if omitted, this JWK represents a private key. /// /// Inner value is encoded according to the `Integer-to-Octet-String` /// conversion as defined in SEC1 section 2.3.7: /// d: Option, } impl JwkEcKey { /// Get the `crv` parameter for this JWK. pub fn crv(&self) -> &str { &self.crv } /// Is this JWK a keypair that includes a private key? pub fn is_keypair(&self) -> bool { self.d.is_some() } /// Does this JWK contain only a public key? pub fn is_public_key(&self) -> bool { self.d.is_none() } /// Decode a JWK into a [`PublicKey`]. #[cfg(feature = "arithmetic")] pub fn to_public_key(&self) -> Result> where C: CurveArithmetic + JwkParameters, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { PublicKey::from_sec1_bytes(self.to_encoded_point::()?.as_bytes()) } /// Create a JWK from a SEC1 [`EncodedPoint`]. pub fn from_encoded_point(point: &EncodedPoint) -> Option where C: Curve + JwkParameters, FieldBytesSize: ModulusSize, { match point.coordinates() { Coordinates::Uncompressed { x, y } => Some(JwkEcKey { crv: C::CRV.to_owned(), x: Base64Url::encode_string(x), y: Base64Url::encode_string(y), d: None, }), _ => None, } } /// Get the public key component of this JWK as a SEC1 [`EncodedPoint`]. pub fn to_encoded_point(&self) -> Result> where C: Curve + JwkParameters, FieldBytesSize: ModulusSize, { if self.crv != C::CRV { return Err(Error); } let x = decode_base64url_fe::(&self.x)?; let y = decode_base64url_fe::(&self.y)?; Ok(EncodedPoint::::from_affine_coordinates(&x, &y, false)) } /// Decode a JWK into a [`SecretKey`]. #[cfg(feature = "arithmetic")] pub fn to_secret_key(&self) -> Result> where C: Curve + JwkParameters + ValidatePublicKey, FieldBytesSize: ModulusSize, { self.try_into() } } impl FromStr for JwkEcKey { type Err = Error; fn from_str(s: &str) -> Result { serde_json::from_str(s).map_err(|_| Error) } } impl ToString for JwkEcKey { fn to_string(&self) -> String { serde_json::to_string(self).expect("JWK encoding error") } } impl TryFrom for SecretKey where C: Curve + JwkParameters + ValidatePublicKey, FieldBytesSize: ModulusSize, { type Error = Error; fn try_from(jwk: JwkEcKey) -> Result> { (&jwk).try_into() } } impl TryFrom<&JwkEcKey> for SecretKey where C: Curve + JwkParameters + ValidatePublicKey, FieldBytesSize: ModulusSize, { type Error = Error; fn try_from(jwk: &JwkEcKey) -> Result> { if let Some(d_base64) = &jwk.d { let pk = jwk.to_encoded_point::()?; let mut d_bytes = decode_base64url_fe::(d_base64)?; let result = SecretKey::from_slice(&d_bytes); d_bytes.zeroize(); result.and_then(|secret_key| { C::validate_public_key(&secret_key, &pk)?; Ok(secret_key) }) } else { Err(Error) } } } #[cfg(feature = "arithmetic")] impl From> for JwkEcKey where C: CurveArithmetic + JwkParameters, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { fn from(sk: SecretKey) -> JwkEcKey { (&sk).into() } } #[cfg(feature = "arithmetic")] impl From<&SecretKey> for JwkEcKey where C: CurveArithmetic + JwkParameters, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { fn from(sk: &SecretKey) -> JwkEcKey { let mut jwk = sk.public_key().to_jwk(); let mut d = sk.to_bytes(); jwk.d = Some(Base64Url::encode_string(&d)); d.zeroize(); jwk } } #[cfg(feature = "arithmetic")] impl TryFrom for PublicKey where C: CurveArithmetic + JwkParameters, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { type Error = Error; fn try_from(jwk: JwkEcKey) -> Result> { (&jwk).try_into() } } #[cfg(feature = "arithmetic")] impl TryFrom<&JwkEcKey> for PublicKey where C: CurveArithmetic + JwkParameters, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { type Error = Error; fn try_from(jwk: &JwkEcKey) -> Result> { PublicKey::from_sec1_bytes(jwk.to_encoded_point::()?.as_bytes()) } } #[cfg(feature = "arithmetic")] impl From> for JwkEcKey where C: CurveArithmetic + JwkParameters, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { fn from(pk: PublicKey) -> JwkEcKey { (&pk).into() } } #[cfg(feature = "arithmetic")] impl From<&PublicKey> for JwkEcKey where C: CurveArithmetic + JwkParameters, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { fn from(pk: &PublicKey) -> JwkEcKey { Self::from_encoded_point::(&pk.to_encoded_point(false)).expect("JWK encoding error") } } impl Debug for JwkEcKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let d = if self.d.is_some() { "Some(...)" } else { "None" }; // NOTE: this implementation omits the `d` private key parameter f.debug_struct(JWK_TYPE_NAME) .field("crv", &self.crv) .field("x", &self.x) .field("y", &self.y) .field("d", &d) .finish() } } impl PartialEq for JwkEcKey { fn eq(&self, other: &Self) -> bool { use subtle::ConstantTimeEq; // Compare private key in constant time let d_eq = match &self.d { Some(d1) => match &other.d { Some(d2) => d1.as_bytes().ct_eq(d2.as_bytes()).into(), None => other.d.is_none(), }, None => other.d.is_none(), }; self.crv == other.crv && self.x == other.x && self.y == other.y && d_eq } } impl Eq for JwkEcKey {} impl ZeroizeOnDrop for JwkEcKey {} impl Drop for JwkEcKey { fn drop(&mut self) { self.zeroize(); } } impl Zeroize for JwkEcKey { fn zeroize(&mut self) { if let Some(d) = &mut self.d { d.zeroize(); } } } impl<'de> Deserialize<'de> for JwkEcKey { fn deserialize(deserializer: D) -> core::result::Result where D: de::Deserializer<'de>, { /// Field positions enum Field { Kty, Crv, X, Y, D, } /// Field visitor struct FieldVisitor; impl<'de> de::Visitor<'de> for FieldVisitor { type Value = Field; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Formatter::write_str(formatter, "field identifier") } fn visit_u64(self, value: u64) -> core::result::Result where E: de::Error, { match value { 0 => Ok(Field::Kty), 1 => Ok(Field::Crv), 2 => Ok(Field::X), 3 => Ok(Field::Y), 4 => Ok(Field::D), _ => Err(de::Error::invalid_value( de::Unexpected::Unsigned(value), &"field index 0 <= i < 5", )), } } fn visit_str(self, value: &str) -> core::result::Result where E: de::Error, { self.visit_bytes(value.as_bytes()) } fn visit_bytes(self, value: &[u8]) -> core::result::Result where E: de::Error, { match value { b"kty" => Ok(Field::Kty), b"crv" => Ok(Field::Crv), b"x" => Ok(Field::X), b"y" => Ok(Field::Y), b"d" => Ok(Field::D), _ => Err(de::Error::unknown_field( &String::from_utf8_lossy(value), FIELDS, )), } } } impl<'de> Deserialize<'de> for Field { #[inline] fn deserialize(__deserializer: D) -> core::result::Result where D: de::Deserializer<'de>, { de::Deserializer::deserialize_identifier(__deserializer, FieldVisitor) } } struct Visitor<'de> { marker: PhantomData, lifetime: PhantomData<&'de ()>, } impl<'de> de::Visitor<'de> for Visitor<'de> { type Value = JwkEcKey; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Formatter::write_str(formatter, "struct JwkEcKey") } #[inline] fn visit_seq(self, mut seq: A) -> core::result::Result where A: de::SeqAccess<'de>, { let kty = de::SeqAccess::next_element::(&mut seq)? .ok_or_else(|| de::Error::invalid_length(0, &DE_ERROR_MSG))?; if kty != EC_KTY { return Err(de::Error::custom(format!("unsupported JWK kty: {kty:?}"))); } let crv = de::SeqAccess::next_element::(&mut seq)? .ok_or_else(|| de::Error::invalid_length(1, &DE_ERROR_MSG))?; let x = de::SeqAccess::next_element::(&mut seq)? .ok_or_else(|| de::Error::invalid_length(2, &DE_ERROR_MSG))?; let y = de::SeqAccess::next_element::(&mut seq)? .ok_or_else(|| de::Error::invalid_length(3, &DE_ERROR_MSG))?; let d = de::SeqAccess::next_element::>(&mut seq)? .ok_or_else(|| de::Error::invalid_length(4, &DE_ERROR_MSG))?; Ok(JwkEcKey { crv, x, y, d }) } #[inline] fn visit_map(self, mut map: A) -> core::result::Result where A: de::MapAccess<'de>, { let mut kty: Option = None; let mut crv: Option = None; let mut x: Option = None; let mut y: Option = None; let mut d: Option = None; while let Some(key) = de::MapAccess::next_key::(&mut map)? { match key { Field::Kty => { if kty.is_none() { kty = Some(de::MapAccess::next_value::(&mut map)?); } else { return Err(de::Error::duplicate_field(FIELDS[0])); } } Field::Crv => { if crv.is_none() { crv = Some(de::MapAccess::next_value::(&mut map)?); } else { return Err(de::Error::duplicate_field(FIELDS[1])); } } Field::X => { if x.is_none() { x = Some(de::MapAccess::next_value::(&mut map)?); } else { return Err(de::Error::duplicate_field(FIELDS[2])); } } Field::Y => { if y.is_none() { y = Some(de::MapAccess::next_value::(&mut map)?); } else { return Err(de::Error::duplicate_field(FIELDS[3])); } } Field::D => { if d.is_none() { d = de::MapAccess::next_value::>(&mut map)?; } else { return Err(de::Error::duplicate_field(FIELDS[4])); } } } } let kty = kty.ok_or_else(|| de::Error::missing_field("kty"))?; if kty != EC_KTY { return Err(de::Error::custom(format!("unsupported JWK kty: {kty}"))); } let crv = crv.ok_or_else(|| de::Error::missing_field("crv"))?; let x = x.ok_or_else(|| de::Error::missing_field("x"))?; let y = y.ok_or_else(|| de::Error::missing_field("y"))?; Ok(JwkEcKey { crv, x, y, d }) } } de::Deserializer::deserialize_struct( deserializer, JWK_TYPE_NAME, FIELDS, Visitor { marker: PhantomData::, lifetime: PhantomData, }, ) } } impl Serialize for JwkEcKey { fn serialize(&self, serializer: S) -> core::result::Result where S: ser::Serializer, { use ser::SerializeStruct; let mut state = serializer.serialize_struct(JWK_TYPE_NAME, 5)?; for (i, field) in [EC_KTY, &self.crv, &self.x, &self.y].iter().enumerate() { state.serialize_field(FIELDS[i], field)?; } if let Some(d) = &self.d { state.serialize_field("d", d)?; } ser::SerializeStruct::end(state) } } /// Decode a Base64url-encoded field element fn decode_base64url_fe(s: &str) -> Result> { let mut result = FieldBytes::::default(); Base64Url::decode(s, &mut result).map_err(|_| Error)?; Ok(result) } #[cfg(test)] mod tests { #![allow(clippy::unwrap_used, clippy::panic)] use super::*; #[cfg(feature = "dev")] use crate::dev::MockCurve; /// Example private key. From RFC 7518 Appendix C: /// const JWK_PRIVATE_KEY: &str = r#" { "kty":"EC", "crv":"P-256", "x":"gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0", "y":"SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps", "d":"0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo" } "#; /// Example public key. const JWK_PUBLIC_KEY: &str = r#" { "kty":"EC", "crv":"P-256", "x":"gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0", "y":"SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps" } "#; /// Example unsupported JWK (RSA key) const UNSUPPORTED_JWK: &str = r#" { "kty":"RSA", "kid":"cc34c0a0-bd5a-4a3c-a50d-a2a7db7643df", "use":"sig", "n":"pjdss8ZaDfEH6K6U7GeW2nxDqR4IP049fk1fK0lndimbMMVBdPv_hSpm8T8EtBDxrUdi1OHZfMhUixGaut-3nQ4GG9nM249oxhCtxqqNvEXrmQRGqczyLxuh-fKn9Fg--hS9UpazHpfVAFnB5aCfXoNhPuI8oByyFKMKaOVgHNqP5NBEqabiLftZD3W_lsFCPGuzr4Vp0YS7zS2hDYScC2oOMu4rGU1LcMZf39p3153Cq7bS2Xh6Y-vw5pwzFYZdjQxDn8x8BG3fJ6j8TGLXQsbKH1218_HcUJRvMwdpbUQG5nvA2GXVqLqdwp054Lzk9_B_f1lVrmOKuHjTNHq48w", "e":"AQAB", "d":"ksDmucdMJXkFGZxiomNHnroOZxe8AmDLDGO1vhs-POa5PZM7mtUPonxwjVmthmpbZzla-kg55OFfO7YcXhg-Hm2OWTKwm73_rLh3JavaHjvBqsVKuorX3V3RYkSro6HyYIzFJ1Ek7sLxbjDRcDOj4ievSX0oN9l-JZhaDYlPlci5uJsoqro_YrE0PRRWVhtGynd-_aWgQv1YzkfZuMD-hJtDi1Im2humOWxA4eZrFs9eG-whXcOvaSwO4sSGbS99ecQZHM2TcdXeAs1PvjVgQ_dKnZlGN3lTWoWfQP55Z7Tgt8Nf1q4ZAKd-NlMe-7iqCFfsnFwXjSiaOa2CRGZn-Q", "p":"4A5nU4ahEww7B65yuzmGeCUUi8ikWzv1C81pSyUKvKzu8CX41hp9J6oRaLGesKImYiuVQK47FhZ--wwfpRwHvSxtNU9qXb8ewo-BvadyO1eVrIk4tNV543QlSe7pQAoJGkxCia5rfznAE3InKF4JvIlchyqs0RQ8wx7lULqwnn0", "q":"ven83GM6SfrmO-TBHbjTk6JhP_3CMsIvmSdo4KrbQNvp4vHO3w1_0zJ3URkmkYGhz2tgPlfd7v1l2I6QkIh4Bumdj6FyFZEBpxjE4MpfdNVcNINvVj87cLyTRmIcaGxmfylY7QErP8GFA-k4UoH_eQmGKGK44TRzYj5hZYGWIC8", "dp":"lmmU_AG5SGxBhJqb8wxfNXDPJjf__i92BgJT2Vp4pskBbr5PGoyV0HbfUQVMnw977RONEurkR6O6gxZUeCclGt4kQlGZ-m0_XSWx13v9t9DIbheAtgVJ2mQyVDvK4m7aRYlEceFh0PsX8vYDS5o1txgPwb3oXkPTtrmbAGMUBpE", "dq":"mxRTU3QDyR2EnCv0Nl0TCF90oliJGAHR9HJmBe__EjuCBbwHfcT8OG3hWOv8vpzokQPRl5cQt3NckzX3fs6xlJN4Ai2Hh2zduKFVQ2p-AF2p6Yfahscjtq-GY9cB85NxLy2IXCC0PF--Sq9LOrTE9QV988SJy_yUrAjcZ5MmECk", "qi":"ldHXIrEmMZVaNwGzDF9WG8sHj2mOZmQpw9yrjLK9hAsmsNr5LTyqWAqJIYZSwPTYWhY4nu2O0EY9G9uYiqewXfCKw_UngrJt8Xwfq1Zruz0YY869zPN4GiE9-9rzdZB33RBw8kIOquY3MK74FMwCihYx_LiU2YTHkaoJ3ncvtvg" } "#; #[test] fn parse_private_key() { let jwk = JwkEcKey::from_str(JWK_PRIVATE_KEY).unwrap(); assert_eq!(jwk.crv, "P-256"); assert_eq!(jwk.x, "gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0"); assert_eq!(jwk.y, "SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps"); assert_eq!( jwk.d.as_ref().unwrap(), "0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo" ); } #[test] fn parse_public_key() { let jwk = JwkEcKey::from_str(JWK_PUBLIC_KEY).unwrap(); assert_eq!(jwk.crv, "P-256"); assert_eq!(jwk.x, "gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0"); assert_eq!(jwk.y, "SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps"); assert_eq!(jwk.d, None); } #[test] fn parse_unsupported() { assert_eq!(JwkEcKey::from_str(UNSUPPORTED_JWK), Err(Error)); } #[test] fn serialize_private_key() { let actual = JwkEcKey::from_str(JWK_PRIVATE_KEY).unwrap().to_string(); let expected: String = JWK_PRIVATE_KEY.split_whitespace().collect(); assert_eq!(actual, expected); } #[test] fn serialize_public_key() { let actual = JwkEcKey::from_str(JWK_PUBLIC_KEY).unwrap().to_string(); let expected: String = JWK_PUBLIC_KEY.split_whitespace().collect(); assert_eq!(actual, expected); } #[cfg(feature = "dev")] #[test] fn jwk_into_encoded_point() { let jwk = JwkEcKey::from_str(JWK_PUBLIC_KEY).unwrap(); let point = jwk.to_encoded_point::().unwrap(); let (x, y) = match point.coordinates() { Coordinates::Uncompressed { x, y } => (x, y), other => panic!("unexpected coordinates: {other:?}"), }; assert_eq!(&decode_base64url_fe::(&jwk.x).unwrap(), x); assert_eq!(&decode_base64url_fe::(&jwk.y).unwrap(), y); } #[cfg(feature = "dev")] #[test] fn encoded_point_into_jwk() { let jwk = JwkEcKey::from_str(JWK_PUBLIC_KEY).unwrap(); let point = jwk.to_encoded_point::().unwrap(); let jwk2 = JwkEcKey::from_encoded_point::(&point).unwrap(); assert_eq!(jwk, jwk2); } } elliptic-curve-0.13.8/src/lib.rs000064400000000000000000000140161046102023000145510ustar 00000000000000#![no_std] #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc = include_str!("../README.md")] #![doc( html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg", html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg" )] #![forbid(unsafe_code)] #![warn( clippy::cast_lossless, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::cast_sign_loss, clippy::checked_conversions, clippy::implicit_saturating_sub, clippy::mod_module_files, clippy::panic, clippy::panic_in_result_fn, clippy::unwrap_used, missing_docs, rust_2018_idioms, unused_lifetimes, unused_qualifications )] //! ## Usage //! //! This crate provides traits for describing elliptic curves, along with //! types which are generic over elliptic curves which can be used as the //! basis of curve-agnostic code. //! //! It's intended to be used with the following concrete elliptic curve //! implementations from the [`RustCrypto/elliptic-curves`] project: //! //! - [`bp256`]: brainpoolP256r1 and brainpoolP256t1 //! - [`bp384`]: brainpoolP384r1 and brainpoolP384t1 //! - [`k256`]: secp256k1 a.k.a. K-256 //! - [`p224`]: NIST P-224 a.k.a. secp224r1 //! - [`p256`]: NIST P-256 a.k.a secp256r1, prime256v1 //! - [`p384`]: NIST P-384 a.k.a. secp384r1 //! - [`p521`]: NIST P-521 a.k.a. secp521r1 //! //! The [`ecdsa`] crate provides a generic implementation of the //! Elliptic Curve Digital Signature Algorithm which can be used with any of //! the above crates, either via an external ECDSA implementation, or //! using native curve arithmetic where applicable. //! //! ## Type conversions //! //! The following chart illustrates the various conversions possible between //! the various types defined by this crate. //! //! ![Type Conversion Map](https://raw.githubusercontent.com/RustCrypto/media/master/img/elliptic-curve/type-transforms.svg) //! //! ## `serde` support //! //! When the `serde` feature of this crate is enabled, `Serialize` and //! `Deserialize` impls are provided for the following types: //! //! - [`JwkEcKey`] //! - [`PublicKey`] //! - [`ScalarPrimitive`] //! //! Please see type-specific documentation for more information. //! //! [`RustCrypto/elliptic-curves`]: https://github.com/RustCrypto/elliptic-curves //! [`bp256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/bp256 //! [`bp384`]: https://github.com/RustCrypto/elliptic-curves/tree/master/bp384 //! [`k256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/k256 //! [`p224`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p224 //! [`p256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p256 //! [`p384`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p384 //! [`p521`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p521 //! [`ecdsa`]: https://github.com/RustCrypto/signatures/tree/master/ecdsa #[cfg(feature = "alloc")] #[allow(unused_imports)] #[macro_use] extern crate alloc; #[cfg(feature = "std")] extern crate std; pub mod point; pub mod scalar; #[cfg(feature = "dev")] pub mod dev; #[cfg(feature = "ecdh")] pub mod ecdh; #[cfg(feature = "hash2curve")] pub mod hash2curve; #[cfg(feature = "arithmetic")] pub mod ops; #[cfg(feature = "sec1")] pub mod sec1; #[cfg(feature = "arithmetic")] pub mod weierstrass; mod error; mod field; mod secret_key; #[cfg(feature = "arithmetic")] mod arithmetic; #[cfg(feature = "arithmetic")] mod public_key; #[cfg(feature = "jwk")] mod jwk; #[cfg(feature = "voprf")] mod voprf; pub use crate::{ error::{Error, Result}, field::{FieldBytes, FieldBytesEncoding, FieldBytesSize}, scalar::ScalarPrimitive, secret_key::SecretKey, }; pub use crypto_bigint as bigint; pub use generic_array::{self, typenum::consts}; pub use rand_core; pub use subtle; pub use zeroize; #[cfg(feature = "arithmetic")] pub use { crate::{ arithmetic::{CurveArithmetic, PrimeCurveArithmetic}, point::{AffinePoint, BatchNormalize, ProjectivePoint}, public_key::PublicKey, scalar::{NonZeroScalar, Scalar}, }, ff::{self, Field, PrimeField}, group::{self, Group}, }; #[cfg(feature = "jwk")] pub use crate::jwk::{JwkEcKey, JwkParameters}; #[cfg(feature = "pkcs8")] pub use pkcs8; #[cfg(feature = "voprf")] pub use crate::voprf::VoprfParameters; use core::{ fmt::Debug, ops::{Add, ShrAssign}, }; use generic_array::ArrayLength; /// Algorithm [`ObjectIdentifier`][`pkcs8::ObjectIdentifier`] for elliptic /// curve public key cryptography (`id-ecPublicKey`). /// /// #[cfg(feature = "pkcs8")] pub const ALGORITHM_OID: pkcs8::ObjectIdentifier = pkcs8::ObjectIdentifier::new_unwrap("1.2.840.10045.2.1"); /// Elliptic curve. /// /// This trait is intended to be impl'd by a ZST which represents a concrete /// elliptic curve. /// /// Other traits in this crate which are bounded by [`Curve`] are intended to /// be impl'd by these ZSTs, facilitating types which are generic over elliptic /// curves (e.g. [`SecretKey`]). pub trait Curve: 'static + Copy + Clone + Debug + Default + Eq + Ord + Send + Sync { /// Size of a serialized field element in bytes. /// /// This is typically the same as `Self::Uint::ByteSize` but for curves /// with an unusual field modulus (e.g. P-224, P-521) it may be different. type FieldBytesSize: ArrayLength + Add + Eq; /// Integer type used to represent field elements of this elliptic curve. type Uint: bigint::ArrayEncoding + bigint::AddMod + bigint::Encoding + bigint::Integer + bigint::NegMod + bigint::Random + bigint::RandomMod + bigint::SubMod + zeroize::Zeroize + FieldBytesEncoding + ShrAssign; /// Order of this elliptic curve, i.e. number of elements in the scalar /// field. const ORDER: Self::Uint; } /// Marker trait for elliptic curves with prime order. pub trait PrimeCurve: Curve {} elliptic-curve-0.13.8/src/ops.rs000064400000000000000000000176461046102023000146200ustar 00000000000000//! Traits for arithmetic operations on elliptic curve field elements. pub use core::ops::{Add, AddAssign, Mul, Neg, Shr, ShrAssign, Sub, SubAssign}; use crypto_bigint::Integer; use group::Group; use subtle::{Choice, ConditionallySelectable, CtOption}; #[cfg(feature = "alloc")] use alloc::vec::Vec; /// Perform an inversion on a field element (i.e. base field element or scalar) pub trait Invert { /// Field element type type Output; /// Invert a field element. fn invert(&self) -> Self::Output; /// Invert a field element in variable time. /// /// ⚠️ WARNING! /// /// This method should not be used with secret values, as its variable-time /// operation can potentially leak secrets through sidechannels. fn invert_vartime(&self) -> Self::Output { // Fall back on constant-time implementation by default. self.invert() } } /// Perform a batched inversion on a sequence of field elements (i.e. base field elements or scalars) /// at an amortized cost that should be practically as efficient as a single inversion. pub trait BatchInvert: Invert + Sized { /// The output of batch inversion. A container of field elements. type Output: AsRef<[Self]>; /// Invert a batch of field elements. fn batch_invert( field_elements: &FieldElements, ) -> CtOption<>::Output>; } impl BatchInvert<[T; N]> for T where T: Invert> + Mul + Copy + Default + ConditionallySelectable, { type Output = [Self; N]; fn batch_invert(field_elements: &[Self; N]) -> CtOption<[Self; N]> { let mut field_elements_multiples = [Self::default(); N]; let mut field_elements_multiples_inverses = [Self::default(); N]; let mut field_elements_inverses = [Self::default(); N]; let inversion_succeeded = invert_batch_internal( field_elements, &mut field_elements_multiples, &mut field_elements_multiples_inverses, &mut field_elements_inverses, ); CtOption::new(field_elements_inverses, inversion_succeeded) } } #[cfg(feature = "alloc")] impl BatchInvert<[T]> for T where T: Invert> + Mul + Copy + Default + ConditionallySelectable, { type Output = Vec; fn batch_invert(field_elements: &[Self]) -> CtOption> { let mut field_elements_multiples: Vec = vec![Self::default(); field_elements.len()]; let mut field_elements_multiples_inverses: Vec = vec![Self::default(); field_elements.len()]; let mut field_elements_inverses: Vec = vec![Self::default(); field_elements.len()]; let inversion_succeeded = invert_batch_internal( field_elements, field_elements_multiples.as_mut(), field_elements_multiples_inverses.as_mut(), field_elements_inverses.as_mut(), ); CtOption::new( field_elements_inverses.into_iter().collect(), inversion_succeeded, ) } } /// Implements "Montgomery's trick", a trick for computing many modular inverses at once. /// /// "Montgomery's trick" works by reducing the problem of computing `n` inverses /// to computing a single inversion, plus some storage and `O(n)` extra multiplications. /// /// See: https://iacr.org/archive/pkc2004/29470042/29470042.pdf section 2.2. fn invert_batch_internal< T: Invert> + Mul + Default + ConditionallySelectable, >( field_elements: &[T], field_elements_multiples: &mut [T], field_elements_multiples_inverses: &mut [T], field_elements_inverses: &mut [T], ) -> Choice { let batch_size = field_elements.len(); if batch_size == 0 || batch_size != field_elements_multiples.len() || batch_size != field_elements_multiples_inverses.len() { return Choice::from(0); } field_elements_multiples[0] = field_elements[0]; for i in 1..batch_size { // $ a_n = a_{n-1}*x_n $ field_elements_multiples[i] = field_elements_multiples[i - 1] * field_elements[i]; } field_elements_multiples[batch_size - 1] .invert() .map(|multiple_of_inverses_of_all_field_elements| { field_elements_multiples_inverses[batch_size - 1] = multiple_of_inverses_of_all_field_elements; for i in (1..batch_size).rev() { // $ a_{n-1} = {a_n}^{-1}*x_n $ field_elements_multiples_inverses[i - 1] = field_elements_multiples_inverses[i] * field_elements[i]; } field_elements_inverses[0] = field_elements_multiples_inverses[0]; for i in 1..batch_size { // $ {x_n}^{-1} = a_{n}^{-1}*a_{n-1} $ field_elements_inverses[i] = field_elements_multiples_inverses[i] * field_elements_multiples[i - 1]; } }) .is_some() } /// Linear combination. /// /// This trait enables crates to provide an optimized implementation of /// linear combinations (e.g. Shamir's Trick), or otherwise provides a default /// non-optimized implementation. // TODO(tarcieri): replace this with a trait from the `group` crate? (see zkcrypto/group#25) pub trait LinearCombination: Group { /// Calculates `x * k + y * l`. fn lincomb(x: &Self, k: &Self::Scalar, y: &Self, l: &Self::Scalar) -> Self { (*x * k) + (*y * l) } } /// Linear combination (extended version). /// /// This trait enables providing an optimized implementation of /// linear combinations (e.g. Shamir's Trick). // TODO(tarcieri): replace the current `LinearCombination` with this in the next release pub trait LinearCombinationExt: group::Curve where PointsAndScalars: AsRef<[(Self, Self::Scalar)]> + ?Sized, { /// Calculates `x1 * k1 + ... + xn * kn`. fn lincomb_ext(points_and_scalars: &PointsAndScalars) -> Self { points_and_scalars .as_ref() .iter() .copied() .map(|(point, scalar)| point * scalar) .sum() } } /// Blanket impl of the legacy [`LinearCombination`] trait for types which impl the new /// [`LinearCombinationExt`] trait for 2-element arrays. impl> LinearCombination for P { fn lincomb(x: &Self, k: &Self::Scalar, y: &Self, l: &Self::Scalar) -> Self { Self::lincomb_ext(&[(*x, *k), (*y, *l)]) } } /// Multiplication by the generator. /// /// May use optimizations (e.g. precomputed tables) when available. // TODO(tarcieri): replace this with `Group::mul_by_generator``? (see zkcrypto/group#44) pub trait MulByGenerator: Group { /// Multiply by the generator of the prime-order subgroup. #[must_use] fn mul_by_generator(scalar: &Self::Scalar) -> Self { Self::generator() * scalar } } /// Modular reduction. pub trait Reduce: Sized { /// Bytes used as input to [`Reduce::reduce_bytes`]. type Bytes: AsRef<[u8]>; /// Perform a modular reduction, returning a field element. fn reduce(n: Uint) -> Self; /// Interpret the given bytes as an integer and perform a modular reduction. fn reduce_bytes(bytes: &Self::Bytes) -> Self; } /// Modular reduction to a non-zero output. /// /// This trait is primarily intended for use by curve implementations such /// as the `k256` and `p256` crates. /// /// End users should use the [`Reduce`] impl on /// [`NonZeroScalar`][`crate::NonZeroScalar`] instead. pub trait ReduceNonZero: Reduce + Sized { /// Perform a modular reduction, returning a field element. fn reduce_nonzero(n: Uint) -> Self; /// Interpret the given bytes as an integer and perform a modular reduction /// to a non-zero output. fn reduce_nonzero_bytes(bytes: &Self::Bytes) -> Self; } elliptic-curve-0.13.8/src/point/non_identity.rs000064400000000000000000000136221046102023000176410ustar 00000000000000//! Non-identity point type. use core::ops::{Deref, Mul}; use group::{prime::PrimeCurveAffine, Curve, GroupEncoding}; use rand_core::{CryptoRng, RngCore}; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; #[cfg(feature = "serde")] use serdect::serde::{de, ser, Deserialize, Serialize}; use crate::{CurveArithmetic, NonZeroScalar, Scalar}; /// Non-identity point type. /// /// This type ensures that its value is not the identity point, ala `core::num::NonZero*`. /// /// In the context of ECC, it's useful for ensuring that certain arithmetic /// cannot result in the identity point. #[derive(Clone, Copy)] pub struct NonIdentity

{ point: P, } impl

NonIdentity

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

NonIdentity

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

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

NonIdentity

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

NonIdentity

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

AsRef

for NonIdentity

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

ConditionallySelectable for NonIdentity

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

ConstantTimeEq for NonIdentity

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

Deref for NonIdentity

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

GroupEncoding for NonIdentity

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

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

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

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

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

Serialize for NonIdentity

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

where P: ConditionallySelectable + ConstantTimeEq + Default + Deserialize<'de> + GroupEncoding, { fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, { Option::from(Self::new(P::deserialize(deserializer)?)) .ok_or_else(|| de::Error::custom("expected non-identity point")) } } #[cfg(all(test, feature = "dev"))] mod tests { use super::NonIdentity; use crate::dev::{AffinePoint, ProjectivePoint}; use group::GroupEncoding; use hex_literal::hex; #[test] fn new_success() { let point = ProjectivePoint::from_bytes( &hex!("02c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721").into(), ) .unwrap(); assert!(bool::from(NonIdentity::new(point).is_some())); assert!(bool::from( NonIdentity::new(AffinePoint::from(point)).is_some() )); } #[test] fn new_fail() { assert!(bool::from( NonIdentity::new(ProjectivePoint::default()).is_none() )); assert!(bool::from( NonIdentity::new(AffinePoint::default()).is_none() )); } #[test] fn round_trip() { let bytes = hex!("02c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); let point = NonIdentity::::from_repr(&bytes.into()).unwrap(); assert_eq!(&bytes, point.to_bytes().as_slice()); let bytes = hex!("02c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); let point = NonIdentity::::from_repr(&bytes.into()).unwrap(); assert_eq!(&bytes, point.to_bytes().as_slice()); } } elliptic-curve-0.13.8/src/point.rs000064400000000000000000000054361046102023000151420ustar 00000000000000//! Traits for elliptic curve points. #[cfg(feature = "arithmetic")] mod non_identity; #[cfg(feature = "arithmetic")] pub use {self::non_identity::NonIdentity, crate::CurveArithmetic}; use crate::{Curve, FieldBytes}; use subtle::{Choice, CtOption}; /// Affine point type for a given curve with a [`CurveArithmetic`] /// implementation. #[cfg(feature = "arithmetic")] pub type AffinePoint = ::AffinePoint; /// Projective point type for a given curve with a [`CurveArithmetic`] /// implementation. #[cfg(feature = "arithmetic")] pub type ProjectivePoint = ::ProjectivePoint; /// Access to the affine coordinates of an elliptic curve point. // TODO: use zkcrypto/group#30 coordinate API when available pub trait AffineCoordinates { /// Field element representation. type FieldRepr: AsRef<[u8]>; /// Get the affine x-coordinate as a serialized field element. fn x(&self) -> Self::FieldRepr; /// Is the affine y-coordinate odd? fn y_is_odd(&self) -> Choice; } /// Normalize point(s) in projective representation by converting them to their affine ones. #[cfg(feature = "arithmetic")] pub trait BatchNormalize: group::Curve { /// The output of the batch normalization; a container of affine points. type Output: AsRef<[Self::AffineRepr]>; /// Perform a batched conversion to affine representation on a sequence of projective points /// at an amortized cost that should be practically as efficient as a single conversion. /// Internally, implementors should rely upon `InvertBatch`. fn batch_normalize(points: &Points) -> >::Output; } /// Double a point (i.e. add it to itself) pub trait Double { /// Double this point. fn double(&self) -> Self; } /// Decompress an elliptic curve point. /// /// Point decompression recovers an original curve point from its x-coordinate /// and a boolean flag indicating whether or not the y-coordinate is odd. pub trait DecompressPoint: Sized { /// Attempt to decompress an elliptic curve point. fn decompress(x: &FieldBytes, y_is_odd: Choice) -> CtOption; } /// Decompact an elliptic curve point from an x-coordinate. /// /// Decompaction relies on properties of specially-generated keys but provides /// a more compact representation than standard point compression. pub trait DecompactPoint: Sized { /// Attempt to decompact an elliptic curve point fn decompact(x: &FieldBytes) -> CtOption; } /// Point compression settings. pub trait PointCompression { /// Should point compression be applied by default? const COMPRESS_POINTS: bool; } /// Point compaction settings. pub trait PointCompaction { /// Should point compaction be applied by default? const COMPACT_POINTS: bool; } elliptic-curve-0.13.8/src/public_key.rs000064400000000000000000000400711046102023000161310ustar 00000000000000//! Elliptic curve public keys. use crate::{ point::NonIdentity, AffinePoint, CurveArithmetic, Error, NonZeroScalar, ProjectivePoint, Result, }; use core::fmt::Debug; use group::{Curve, Group}; #[cfg(feature = "jwk")] use crate::{JwkEcKey, JwkParameters}; #[cfg(feature = "pkcs8")] use pkcs8::spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, ObjectIdentifier}; #[cfg(feature = "pem")] use core::str::FromStr; #[cfg(feature = "sec1")] use { crate::{ point::PointCompression, sec1::{CompressedPoint, EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint}, FieldBytesSize, }, core::cmp::Ordering, subtle::{Choice, CtOption}, }; #[cfg(all(feature = "alloc", feature = "pkcs8"))] use pkcs8::EncodePublicKey; #[cfg(all(feature = "alloc", feature = "sec1"))] use alloc::boxed::Box; #[cfg(any(feature = "jwk", feature = "pem"))] use alloc::string::{String, ToString}; #[cfg(feature = "serde")] use serdect::serde::{de, ser, Deserialize, Serialize}; #[cfg(any(feature = "pem", feature = "serde"))] use pkcs8::DecodePublicKey; #[cfg(all(feature = "sec1", feature = "pkcs8"))] use { crate::{ pkcs8::{self, AssociatedOid}, ALGORITHM_OID, }, pkcs8::der, }; /// Elliptic curve public keys. /// /// This is a wrapper type for [`AffinePoint`] which ensures an inner /// non-identity point and provides a common place to handle encoding/decoding. /// /// # Parsing "SPKI" Keys /// /// X.509 `SubjectPublicKeyInfo` (SPKI) is a commonly used format for encoding /// public keys, notably public keys corresponding to PKCS#8 private keys. /// (especially ones generated by OpenSSL). /// /// Keys in SPKI format are either binary (ASN.1 BER/DER), or PEM encoded /// (ASCII) and begin with the following: /// /// ```text /// -----BEGIN PUBLIC KEY----- /// ``` /// /// To decode an elliptic curve public key from SPKI, enable the `pkcs8` /// feature of this crate (or the `pkcs8` feature of a specific RustCrypto /// elliptic curve crate) and use the /// [`elliptic_curve::pkcs8::DecodePublicKey`][`pkcs8::DecodePublicKey`] /// trait to parse it. /// /// When the `pem` feature of this crate (or a specific RustCrypto elliptic /// curve crate) is enabled, a [`FromStr`] impl is also available. /// /// # `serde` support /// /// When the optional `serde` feature of this create is enabled, [`Serialize`] /// and [`Deserialize`] impls are provided for this type. /// /// The serialization is binary-oriented and supports ASN.1 DER /// Subject Public Key Info (SPKI) as the encoding format. /// /// For a more text-friendly encoding of public keys, use [`JwkEcKey`] instead. #[derive(Clone, Debug, Eq, PartialEq)] pub struct PublicKey where C: CurveArithmetic, { point: AffinePoint, } impl PublicKey where C: CurveArithmetic, { /// Convert an [`AffinePoint`] into a [`PublicKey`] pub fn from_affine(point: AffinePoint) -> Result { if ProjectivePoint::::from(point).is_identity().into() { Err(Error) } else { Ok(Self { point }) } } /// Compute a [`PublicKey`] from a secret [`NonZeroScalar`] value /// (i.e. a secret key represented as a raw scalar value) pub fn from_secret_scalar(scalar: &NonZeroScalar) -> Self { // `NonZeroScalar` ensures the resulting point is not the identity Self { point: (C::ProjectivePoint::generator() * scalar.as_ref()).to_affine(), } } /// Decode [`PublicKey`] (compressed or uncompressed) from the /// `Elliptic-Curve-Point-to-Octet-String` encoding described in /// SEC 1: Elliptic Curve Cryptography (Version 2.0) section /// 2.3.3 (page 10). /// /// #[cfg(feature = "sec1")] pub fn from_sec1_bytes(bytes: &[u8]) -> Result where FieldBytesSize: ModulusSize, AffinePoint: FromEncodedPoint + ToEncodedPoint, { let point = EncodedPoint::::from_bytes(bytes).map_err(|_| Error)?; Option::from(Self::from_encoded_point(&point)).ok_or(Error) } /// Convert this [`PublicKey`] into the /// `Elliptic-Curve-Point-to-Octet-String` encoding described in /// SEC 1: Elliptic Curve Cryptography (Version 2.0) section 2.3.3 /// (page 10). /// /// #[cfg(all(feature = "alloc", feature = "sec1"))] pub fn to_sec1_bytes(&self) -> Box<[u8]> where C: PointCompression, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { EncodedPoint::::from(self).to_bytes() } /// Borrow the inner [`AffinePoint`] from this [`PublicKey`]. /// /// In ECC, public keys are elliptic curve points. pub fn as_affine(&self) -> &AffinePoint { &self.point } /// Convert this [`PublicKey`] to a [`ProjectivePoint`] for the given curve pub fn to_projective(&self) -> ProjectivePoint { self.point.into() } /// Convert this [`PublicKey`] to a [`NonIdentity`] of the inner [`AffinePoint`] pub fn to_nonidentity(&self) -> NonIdentity> { NonIdentity::new_unchecked(self.point) } /// Parse a [`JwkEcKey`] JSON Web Key (JWK) into a [`PublicKey`]. #[cfg(feature = "jwk")] pub fn from_jwk(jwk: &JwkEcKey) -> Result where C: JwkParameters, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { jwk.to_public_key::() } /// Parse a string containing a JSON Web Key (JWK) into a [`PublicKey`]. #[cfg(feature = "jwk")] pub fn from_jwk_str(jwk: &str) -> Result where C: JwkParameters, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { jwk.parse::().and_then(|jwk| Self::from_jwk(&jwk)) } /// Serialize this public key as [`JwkEcKey`] JSON Web Key (JWK). #[cfg(feature = "jwk")] pub fn to_jwk(&self) -> JwkEcKey where C: JwkParameters, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { self.into() } /// Serialize this public key as JSON Web Key (JWK) string. #[cfg(feature = "jwk")] pub fn to_jwk_string(&self) -> String where C: JwkParameters, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { self.to_jwk().to_string() } } impl AsRef> for PublicKey where C: CurveArithmetic, { fn as_ref(&self) -> &AffinePoint { self.as_affine() } } impl Copy for PublicKey where C: CurveArithmetic {} #[cfg(feature = "sec1")] impl FromEncodedPoint for PublicKey where C: CurveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { /// Initialize [`PublicKey`] from an [`EncodedPoint`] fn from_encoded_point(encoded_point: &EncodedPoint) -> CtOption { AffinePoint::::from_encoded_point(encoded_point).and_then(|point| { // Defeating the point of `subtle`, but the use case is specifically a public key let is_identity = Choice::from(u8::from(encoded_point.is_identity())); CtOption::new(PublicKey { point }, !is_identity) }) } } #[cfg(feature = "sec1")] impl ToEncodedPoint for PublicKey where C: CurveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { /// Serialize this [`PublicKey`] as a SEC1 [`EncodedPoint`], optionally applying /// point compression fn to_encoded_point(&self, compress: bool) -> EncodedPoint { self.point.to_encoded_point(compress) } } #[cfg(feature = "sec1")] impl From> for CompressedPoint where C: CurveArithmetic + PointCompression, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { fn from(public_key: PublicKey) -> CompressedPoint { CompressedPoint::::from(&public_key) } } #[cfg(feature = "sec1")] impl From<&PublicKey> for CompressedPoint where C: CurveArithmetic + PointCompression, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { fn from(public_key: &PublicKey) -> CompressedPoint { CompressedPoint::::clone_from_slice(public_key.to_encoded_point(true).as_bytes()) } } #[cfg(feature = "sec1")] impl From> for EncodedPoint where C: CurveArithmetic + PointCompression, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { fn from(public_key: PublicKey) -> EncodedPoint { EncodedPoint::::from(&public_key) } } #[cfg(feature = "sec1")] impl From<&PublicKey> for EncodedPoint where C: CurveArithmetic + PointCompression, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { fn from(public_key: &PublicKey) -> EncodedPoint { public_key.to_encoded_point(C::COMPRESS_POINTS) } } impl From> for PublicKey where C: CurveArithmetic, P: Copy + Into>, { fn from(value: NonIdentity

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

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

) -> Self { Self { point: value.to_point().into(), } } } impl From> for NonIdentity> where C: CurveArithmetic, { fn from(value: PublicKey) -> Self { Self::from(&value) } } impl From<&PublicKey> for NonIdentity> where C: CurveArithmetic, { fn from(value: &PublicKey) -> Self { PublicKey::to_nonidentity(value) } } #[cfg(feature = "sec1")] impl PartialOrd for PublicKey where C: CurveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } #[cfg(feature = "sec1")] impl Ord for PublicKey where C: CurveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { fn cmp(&self, other: &Self) -> Ordering { // TODO(tarcieri): more efficient implementation? // This is implemented this way to reduce bounds for `AffinePoint` self.to_encoded_point(false) .cmp(&other.to_encoded_point(false)) } } #[cfg(feature = "sec1")] impl TryFrom> for PublicKey where C: CurveArithmetic, FieldBytesSize: ModulusSize, AffinePoint: FromEncodedPoint + ToEncodedPoint, { type Error = Error; fn try_from(point: CompressedPoint) -> Result { Self::from_sec1_bytes(&point) } } #[cfg(feature = "sec1")] impl TryFrom<&CompressedPoint> for PublicKey where C: CurveArithmetic, FieldBytesSize: ModulusSize, AffinePoint: FromEncodedPoint + ToEncodedPoint, { type Error = Error; fn try_from(point: &CompressedPoint) -> Result { Self::from_sec1_bytes(point) } } #[cfg(feature = "sec1")] impl TryFrom> for PublicKey where C: CurveArithmetic, FieldBytesSize: ModulusSize, AffinePoint: FromEncodedPoint + ToEncodedPoint, { type Error = Error; fn try_from(point: EncodedPoint) -> Result { Self::from_sec1_bytes(point.as_bytes()) } } #[cfg(feature = "sec1")] impl TryFrom<&EncodedPoint> for PublicKey where C: CurveArithmetic, FieldBytesSize: ModulusSize, AffinePoint: FromEncodedPoint + ToEncodedPoint, { type Error = Error; fn try_from(point: &EncodedPoint) -> Result { Self::from_sec1_bytes(point.as_bytes()) } } #[cfg(feature = "pkcs8")] impl AssociatedAlgorithmIdentifier for PublicKey where C: AssociatedOid + CurveArithmetic, { type Params = ObjectIdentifier; const ALGORITHM_IDENTIFIER: AlgorithmIdentifier = AlgorithmIdentifier { oid: ALGORITHM_OID, parameters: Some(C::OID), }; } #[cfg(feature = "pkcs8")] impl TryFrom> for PublicKey where C: AssociatedOid + CurveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { type Error = pkcs8::spki::Error; fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result { Self::try_from(&spki) } } #[cfg(feature = "pkcs8")] impl TryFrom<&pkcs8::SubjectPublicKeyInfoRef<'_>> for PublicKey where C: AssociatedOid + CurveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { type Error = pkcs8::spki::Error; fn try_from(spki: &pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result { spki.algorithm.assert_oids(ALGORITHM_OID, C::OID)?; let public_key_bytes = spki .subject_public_key .as_bytes() .ok_or_else(|| der::Tag::BitString.value_error())?; Self::from_sec1_bytes(public_key_bytes) .map_err(|_| der::Tag::BitString.value_error().into()) } } #[cfg(all(feature = "alloc", feature = "pkcs8"))] impl EncodePublicKey for PublicKey where C: AssociatedOid + CurveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { fn to_public_key_der(&self) -> pkcs8::spki::Result { let public_key_bytes = self.to_encoded_point(false); let subject_public_key = der::asn1::BitStringRef::new(0, public_key_bytes.as_bytes())?; pkcs8::SubjectPublicKeyInfo { algorithm: Self::ALGORITHM_IDENTIFIER, subject_public_key, } .try_into() } } #[cfg(feature = "pem")] impl FromStr for PublicKey where C: AssociatedOid + CurveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { type Err = Error; fn from_str(s: &str) -> Result { Self::from_public_key_pem(s).map_err(|_| Error) } } #[cfg(feature = "pem")] impl ToString for PublicKey where C: AssociatedOid + CurveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { fn to_string(&self) -> String { self.to_public_key_pem(Default::default()) .expect("PEM encoding error") } } #[cfg(feature = "serde")] impl Serialize for PublicKey where C: AssociatedOid + CurveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { fn serialize(&self, serializer: S) -> core::result::Result where S: ser::Serializer, { let der = self.to_public_key_der().map_err(ser::Error::custom)?; serdect::slice::serialize_hex_upper_or_bin(&der, serializer) } } #[cfg(feature = "serde")] impl<'de, C> Deserialize<'de> for PublicKey where C: AssociatedOid + CurveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { fn deserialize(deserializer: D) -> core::result::Result where D: de::Deserializer<'de>, { let der_bytes = serdect::slice::deserialize_hex_or_bin_vec(deserializer)?; Self::from_public_key_der(&der_bytes).map_err(de::Error::custom) } } #[cfg(all(feature = "dev", test))] mod tests { use crate::{dev::MockCurve, sec1::FromEncodedPoint}; type EncodedPoint = crate::sec1::EncodedPoint; type PublicKey = super::PublicKey; #[test] fn from_encoded_point_rejects_identity() { let identity = EncodedPoint::identity(); assert!(bool::from( PublicKey::from_encoded_point(&identity).is_none() )); } } elliptic-curve-0.13.8/src/scalar/blinded.rs000064400000000000000000000032511046102023000166500ustar 00000000000000//! Random blinding support for [`Scalar`] use super::Scalar; use crate::{ops::Invert, CurveArithmetic}; use group::ff::Field; use rand_core::CryptoRngCore; use subtle::CtOption; use zeroize::Zeroize; /// Scalar blinded with a randomly generated masking value. /// /// This provides a randomly blinded impl of [`Invert`] which is useful for /// e.g. ECDSA ephemeral (`k`) scalars. /// /// It implements masked variable-time inversions using Stein's algorithm, which /// may be helpful for performance on embedded platforms. #[derive(Clone)] pub struct BlindedScalar where C: CurveArithmetic, { /// Actual scalar value. scalar: Scalar, /// Mask value. mask: Scalar, } impl BlindedScalar where C: CurveArithmetic, { /// Create a new [`BlindedScalar`] from a scalar and a [`CryptoRngCore`]. pub fn new(scalar: Scalar, rng: &mut impl CryptoRngCore) -> Self { Self { scalar, mask: Scalar::::random(rng), } } } impl AsRef> for BlindedScalar where C: CurveArithmetic, { fn as_ref(&self) -> &Scalar { &self.scalar } } impl Invert for BlindedScalar where C: CurveArithmetic, { type Output = CtOption>; fn invert(&self) -> CtOption> { // prevent side channel analysis of scalar inversion by pre-and-post-multiplying // with the random masking scalar (self.scalar * self.mask) .invert_vartime() .map(|s| s * self.mask) } } impl Drop for BlindedScalar where C: CurveArithmetic, { fn drop(&mut self) { self.scalar.zeroize(); self.mask.zeroize(); } } elliptic-curve-0.13.8/src/scalar/nonzero.rs000064400000000000000000000233571046102023000167520ustar 00000000000000//! Non-zero scalar type. use crate::{ ops::{Invert, Reduce, ReduceNonZero}, scalar::IsHigh, CurveArithmetic, Error, FieldBytes, PrimeCurve, Scalar, ScalarPrimitive, SecretKey, }; use base16ct::HexDisplay; use core::{ fmt, ops::{Deref, Mul, Neg}, str, }; use crypto_bigint::{ArrayEncoding, Integer}; use ff::{Field, PrimeField}; use generic_array::{typenum::Unsigned, GenericArray}; use rand_core::CryptoRngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; use zeroize::Zeroize; #[cfg(feature = "serde")] use serdect::serde::{de, ser, Deserialize, Serialize}; /// Non-zero scalar type. /// /// This type ensures that its value is not zero, ala `core::num::NonZero*`. /// To do this, the generic `S` type must impl both `Default` and /// `ConstantTimeEq`, with the requirement that `S::default()` returns 0. /// /// In the context of ECC, it's useful for ensuring that scalar multiplication /// cannot result in the point at infinity. #[derive(Clone)] pub struct NonZeroScalar where C: CurveArithmetic, { scalar: Scalar, } impl NonZeroScalar where C: CurveArithmetic, { /// Generate a random `NonZeroScalar`. pub fn random(mut rng: &mut impl CryptoRngCore) -> Self { // Use rejection sampling to eliminate zero values. // While this method isn't constant-time, the attacker shouldn't learn // anything about unrelated outputs so long as `rng` is a secure `CryptoRng`. loop { if let Some(result) = Self::new(Field::random(&mut rng)).into() { break result; } } } /// Create a [`NonZeroScalar`] from a scalar. pub fn new(scalar: Scalar) -> CtOption { CtOption::new(Self { scalar }, !scalar.is_zero()) } /// Decode a [`NonZeroScalar`] from a big endian-serialized field element. pub fn from_repr(repr: FieldBytes) -> CtOption { Scalar::::from_repr(repr).and_then(Self::new) } /// Create a [`NonZeroScalar`] from a `C::Uint`. pub fn from_uint(uint: C::Uint) -> CtOption { ScalarPrimitive::new(uint).and_then(|scalar| Self::new(scalar.into())) } } impl AsRef> for NonZeroScalar where C: CurveArithmetic, { fn as_ref(&self) -> &Scalar { &self.scalar } } impl ConditionallySelectable for NonZeroScalar where C: CurveArithmetic, { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Self { scalar: Scalar::::conditional_select(&a.scalar, &b.scalar, choice), } } } impl ConstantTimeEq for NonZeroScalar where C: CurveArithmetic, { fn ct_eq(&self, other: &Self) -> Choice { self.scalar.ct_eq(&other.scalar) } } impl Copy for NonZeroScalar where C: CurveArithmetic {} impl Deref for NonZeroScalar where C: CurveArithmetic, { type Target = Scalar; fn deref(&self) -> &Scalar { &self.scalar } } impl From> for FieldBytes where C: CurveArithmetic, { fn from(scalar: NonZeroScalar) -> FieldBytes { Self::from(&scalar) } } impl From<&NonZeroScalar> for FieldBytes where C: CurveArithmetic, { fn from(scalar: &NonZeroScalar) -> FieldBytes { scalar.to_repr() } } impl From> for ScalarPrimitive where C: CurveArithmetic, { #[inline] fn from(scalar: NonZeroScalar) -> ScalarPrimitive { Self::from(&scalar) } } impl From<&NonZeroScalar> for ScalarPrimitive where C: CurveArithmetic, { fn from(scalar: &NonZeroScalar) -> ScalarPrimitive { ScalarPrimitive::from_bytes(&scalar.to_repr()).unwrap() } } impl From> for NonZeroScalar where C: CurveArithmetic, { fn from(sk: SecretKey) -> NonZeroScalar { Self::from(&sk) } } impl From<&SecretKey> for NonZeroScalar where C: CurveArithmetic, { fn from(sk: &SecretKey) -> NonZeroScalar { let scalar = sk.as_scalar_primitive().to_scalar(); debug_assert!(!bool::from(scalar.is_zero())); Self { scalar } } } impl Invert for NonZeroScalar where C: CurveArithmetic, Scalar: Invert>>, { type Output = Self; fn invert(&self) -> Self { Self { // This will always succeed since `scalar` will never be 0 scalar: Invert::invert(&self.scalar).unwrap(), } } fn invert_vartime(&self) -> Self::Output { Self { // This will always succeed since `scalar` will never be 0 scalar: Invert::invert_vartime(&self.scalar).unwrap(), } } } impl IsHigh for NonZeroScalar where C: CurveArithmetic, { fn is_high(&self) -> Choice { self.scalar.is_high() } } impl Neg for NonZeroScalar where C: CurveArithmetic, { type Output = NonZeroScalar; fn neg(self) -> NonZeroScalar { let scalar = -self.scalar; debug_assert!(!bool::from(scalar.is_zero())); NonZeroScalar { scalar } } } impl Mul> for NonZeroScalar where C: PrimeCurve + CurveArithmetic, { type Output = Self; #[inline] fn mul(self, other: Self) -> Self { Self::mul(self, &other) } } impl Mul<&NonZeroScalar> for NonZeroScalar where C: PrimeCurve + CurveArithmetic, { type Output = Self; fn mul(self, other: &Self) -> Self { // Multiplication is modulo a prime, so the product of two non-zero // scalars is also non-zero. let scalar = self.scalar * other.scalar; debug_assert!(!bool::from(scalar.is_zero())); NonZeroScalar { scalar } } } /// Note: this is a non-zero reduction, as it's impl'd for [`NonZeroScalar`]. impl Reduce for NonZeroScalar where C: CurveArithmetic, I: Integer + ArrayEncoding, Scalar: Reduce + ReduceNonZero, { type Bytes = as Reduce>::Bytes; fn reduce(n: I) -> Self { let scalar = Scalar::::reduce_nonzero(n); debug_assert!(!bool::from(scalar.is_zero())); Self { scalar } } fn reduce_bytes(bytes: &Self::Bytes) -> Self { let scalar = Scalar::::reduce_nonzero_bytes(bytes); debug_assert!(!bool::from(scalar.is_zero())); Self { scalar } } } /// Note: forwards to the [`Reduce`] impl. impl ReduceNonZero for NonZeroScalar where Self: Reduce, C: CurveArithmetic, I: Integer + ArrayEncoding, Scalar: Reduce + ReduceNonZero, { fn reduce_nonzero(n: I) -> Self { Self::reduce(n) } fn reduce_nonzero_bytes(bytes: &Self::Bytes) -> Self { Self::reduce_bytes(bytes) } } impl TryFrom<&[u8]> for NonZeroScalar where C: CurveArithmetic, { type Error = Error; fn try_from(bytes: &[u8]) -> Result { if bytes.len() == C::FieldBytesSize::USIZE { Option::from(NonZeroScalar::from_repr(GenericArray::clone_from_slice( bytes, ))) .ok_or(Error) } else { Err(Error) } } } impl Zeroize for NonZeroScalar where C: CurveArithmetic, { fn zeroize(&mut self) { // Use zeroize's volatile writes to ensure value is cleared. self.scalar.zeroize(); // Write a 1 instead of a 0 to ensure this type's non-zero invariant // is upheld. self.scalar = Scalar::::ONE; } } impl fmt::Display for NonZeroScalar where C: CurveArithmetic, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{self:X}") } } impl fmt::LowerHex for NonZeroScalar where C: CurveArithmetic, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:x}", HexDisplay(&self.to_repr())) } } impl fmt::UpperHex for NonZeroScalar where C: CurveArithmetic, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:}", HexDisplay(&self.to_repr())) } } impl str::FromStr for NonZeroScalar where C: CurveArithmetic, { type Err = Error; fn from_str(hex: &str) -> Result { let mut bytes = FieldBytes::::default(); if base16ct::mixed::decode(hex, &mut bytes)?.len() == bytes.len() { Option::from(Self::from_repr(bytes)).ok_or(Error) } else { Err(Error) } } } #[cfg(feature = "serde")] impl Serialize for NonZeroScalar where C: CurveArithmetic, { fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, { ScalarPrimitive::from(self).serialize(serializer) } } #[cfg(feature = "serde")] impl<'de, C> Deserialize<'de> for NonZeroScalar where C: CurveArithmetic, { fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, { let scalar = ScalarPrimitive::deserialize(deserializer)?; Option::from(Self::new(scalar.into())) .ok_or_else(|| de::Error::custom("expected non-zero scalar")) } } #[cfg(all(test, feature = "dev"))] mod tests { use crate::dev::{NonZeroScalar, Scalar}; use ff::{Field, PrimeField}; use hex_literal::hex; use zeroize::Zeroize; #[test] fn round_trip() { let bytes = hex!("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); let scalar = NonZeroScalar::from_repr(bytes.into()).unwrap(); assert_eq!(&bytes, scalar.to_repr().as_slice()); } #[test] fn zeroize() { let mut scalar = NonZeroScalar::new(Scalar::from(42u64)).unwrap(); scalar.zeroize(); assert_eq!(*scalar, Scalar::ONE); } } elliptic-curve-0.13.8/src/scalar/primitive.rs000064400000000000000000000224321046102023000172610ustar 00000000000000//! Generic scalar type with primitive functionality. use crate::{ bigint::{prelude::*, Limb, NonZero}, scalar::FromUintUnchecked, scalar::IsHigh, Curve, Error, FieldBytes, FieldBytesEncoding, Result, }; use base16ct::HexDisplay; use core::{ cmp::Ordering, fmt, ops::{Add, AddAssign, Neg, ShrAssign, Sub, SubAssign}, str, }; use generic_array::{typenum::Unsigned, GenericArray}; use rand_core::CryptoRngCore; use subtle::{ Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess, CtOption, }; use zeroize::DefaultIsZeroes; #[cfg(feature = "arithmetic")] use super::{CurveArithmetic, Scalar}; #[cfg(feature = "serde")] use serdect::serde::{de, ser, Deserialize, Serialize}; /// Generic scalar type with primitive functionality. /// /// This type provides a baseline level of scalar arithmetic functionality /// which is always available for all curves, regardless of if they implement /// any arithmetic traits. /// /// # `serde` support /// /// When the optional `serde` feature of this create is enabled, [`Serialize`] /// and [`Deserialize`] impls are provided for this type. /// /// The serialization is a fixed-width big endian encoding. When used with /// textual formats, the binary data is encoded as hexadecimal. // TODO(tarcieri): use `crypto-bigint`'s `Residue` type, expose more functionality? #[derive(Copy, Clone, Debug, Default)] pub struct ScalarPrimitive { /// Inner unsigned integer type. inner: C::Uint, } impl ScalarPrimitive where C: Curve, { /// Zero scalar. pub const ZERO: Self = Self { inner: C::Uint::ZERO, }; /// Multiplicative identity. pub const ONE: Self = Self { inner: C::Uint::ONE, }; /// Scalar modulus. pub const MODULUS: C::Uint = C::ORDER; /// Generate a random [`ScalarPrimitive`]. pub fn random(rng: &mut impl CryptoRngCore) -> Self { Self { inner: C::Uint::random_mod(rng, &NonZero::new(Self::MODULUS).unwrap()), } } /// Create a new scalar from [`Curve::Uint`]. pub fn new(uint: C::Uint) -> CtOption { CtOption::new(Self { inner: uint }, uint.ct_lt(&Self::MODULUS)) } /// Decode [`ScalarPrimitive`] from a serialized field element pub fn from_bytes(bytes: &FieldBytes) -> CtOption { Self::new(C::Uint::decode_field_bytes(bytes)) } /// Decode [`ScalarPrimitive`] from a big endian byte slice. pub fn from_slice(slice: &[u8]) -> Result { if slice.len() == C::FieldBytesSize::USIZE { Option::from(Self::from_bytes(GenericArray::from_slice(slice))).ok_or(Error) } else { Err(Error) } } /// Borrow the inner `C::Uint`. pub fn as_uint(&self) -> &C::Uint { &self.inner } /// Borrow the inner limbs as a slice. pub fn as_limbs(&self) -> &[Limb] { self.inner.as_ref() } /// Is this [`ScalarPrimitive`] value equal to zero? pub fn is_zero(&self) -> Choice { self.inner.is_zero() } /// Is this [`ScalarPrimitive`] value even? pub fn is_even(&self) -> Choice { self.inner.is_even() } /// Is this [`ScalarPrimitive`] value odd? pub fn is_odd(&self) -> Choice { self.inner.is_odd() } /// Encode [`ScalarPrimitive`] as a serialized field element. pub fn to_bytes(&self) -> FieldBytes { self.inner.encode_field_bytes() } /// Convert to a `C::Uint`. pub fn to_uint(&self) -> C::Uint { self.inner } } impl FromUintUnchecked for ScalarPrimitive where C: Curve, { type Uint = C::Uint; fn from_uint_unchecked(uint: C::Uint) -> Self { Self { inner: uint } } } #[cfg(feature = "arithmetic")] impl ScalarPrimitive where C: CurveArithmetic, { /// Convert [`ScalarPrimitive`] into a given curve's scalar type. pub(super) fn to_scalar(self) -> Scalar { Scalar::::from_uint_unchecked(self.inner) } } // TODO(tarcieri): better encapsulate this? impl AsRef<[Limb]> for ScalarPrimitive where C: Curve, { fn as_ref(&self) -> &[Limb] { self.as_limbs() } } impl ConditionallySelectable for ScalarPrimitive where C: Curve, { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Self { inner: C::Uint::conditional_select(&a.inner, &b.inner, choice), } } } impl ConstantTimeEq for ScalarPrimitive where C: Curve, { fn ct_eq(&self, other: &Self) -> Choice { self.inner.ct_eq(&other.inner) } } impl ConstantTimeLess for ScalarPrimitive where C: Curve, { fn ct_lt(&self, other: &Self) -> Choice { self.inner.ct_lt(&other.inner) } } impl ConstantTimeGreater for ScalarPrimitive where C: Curve, { fn ct_gt(&self, other: &Self) -> Choice { self.inner.ct_gt(&other.inner) } } impl DefaultIsZeroes for ScalarPrimitive {} impl Eq for ScalarPrimitive {} impl PartialEq for ScalarPrimitive where C: Curve, { fn eq(&self, other: &Self) -> bool { self.ct_eq(other).into() } } impl PartialOrd for ScalarPrimitive where C: Curve, { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for ScalarPrimitive where C: Curve, { fn cmp(&self, other: &Self) -> Ordering { self.inner.cmp(&other.inner) } } impl From for ScalarPrimitive where C: Curve, { fn from(n: u64) -> Self { Self { inner: C::Uint::from(n), } } } impl Add> for ScalarPrimitive where C: Curve, { type Output = Self; fn add(self, other: Self) -> Self { self.add(&other) } } impl Add<&ScalarPrimitive> for ScalarPrimitive where C: Curve, { type Output = Self; fn add(self, other: &Self) -> Self { Self { inner: self.inner.add_mod(&other.inner, &Self::MODULUS), } } } impl AddAssign> for ScalarPrimitive where C: Curve, { fn add_assign(&mut self, other: Self) { *self = *self + other; } } impl AddAssign<&ScalarPrimitive> for ScalarPrimitive where C: Curve, { fn add_assign(&mut self, other: &Self) { *self = *self + other; } } impl Sub> for ScalarPrimitive where C: Curve, { type Output = Self; fn sub(self, other: Self) -> Self { self.sub(&other) } } impl Sub<&ScalarPrimitive> for ScalarPrimitive where C: Curve, { type Output = Self; fn sub(self, other: &Self) -> Self { Self { inner: self.inner.sub_mod(&other.inner, &Self::MODULUS), } } } impl SubAssign> for ScalarPrimitive where C: Curve, { fn sub_assign(&mut self, other: Self) { *self = *self - other; } } impl SubAssign<&ScalarPrimitive> for ScalarPrimitive where C: Curve, { fn sub_assign(&mut self, other: &Self) { *self = *self - other; } } impl Neg for ScalarPrimitive where C: Curve, { type Output = Self; fn neg(self) -> Self { Self { inner: self.inner.neg_mod(&Self::MODULUS), } } } impl Neg for &ScalarPrimitive where C: Curve, { type Output = ScalarPrimitive; fn neg(self) -> ScalarPrimitive { -*self } } impl ShrAssign for ScalarPrimitive where C: Curve, { fn shr_assign(&mut self, rhs: usize) { self.inner >>= rhs; } } impl IsHigh for ScalarPrimitive where C: Curve, { fn is_high(&self) -> Choice { let n_2 = C::ORDER >> 1; self.inner.ct_gt(&n_2) } } impl fmt::Display for ScalarPrimitive where C: Curve, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{self:X}") } } impl fmt::LowerHex for ScalarPrimitive where C: Curve, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:x}", HexDisplay(&self.to_bytes())) } } impl fmt::UpperHex for ScalarPrimitive where C: Curve, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:X}", HexDisplay(&self.to_bytes())) } } impl str::FromStr for ScalarPrimitive where C: Curve, { type Err = Error; fn from_str(hex: &str) -> Result { let mut bytes = FieldBytes::::default(); base16ct::lower::decode(hex, &mut bytes)?; Self::from_slice(&bytes) } } #[cfg(feature = "serde")] impl Serialize for ScalarPrimitive where C: Curve, { fn serialize(&self, serializer: S) -> core::result::Result where S: ser::Serializer, { serdect::array::serialize_hex_upper_or_bin(&self.to_bytes(), serializer) } } #[cfg(feature = "serde")] impl<'de, C> Deserialize<'de> for ScalarPrimitive where C: Curve, { fn deserialize(deserializer: D) -> core::result::Result where D: de::Deserializer<'de>, { let mut bytes = FieldBytes::::default(); serdect::array::deserialize_hex_or_bin(&mut bytes, deserializer)?; Self::from_slice(&bytes).map_err(|_| de::Error::custom("scalar out of range")) } } elliptic-curve-0.13.8/src/scalar.rs000064400000000000000000000030201046102023000152410ustar 00000000000000//! Scalar types. #[cfg(feature = "arithmetic")] mod blinded; #[cfg(feature = "arithmetic")] mod nonzero; mod primitive; pub use self::primitive::ScalarPrimitive; #[cfg(feature = "arithmetic")] pub use self::{blinded::BlindedScalar, nonzero::NonZeroScalar}; use crypto_bigint::Integer; use subtle::Choice; #[cfg(feature = "arithmetic")] use crate::CurveArithmetic; /// Scalar field element for a particular elliptic curve. #[cfg(feature = "arithmetic")] pub type Scalar = ::Scalar; /// Bit representation of a scalar field element of a given curve. #[cfg(feature = "bits")] pub type ScalarBits = ff::FieldBits< as ff::PrimeFieldBits>::ReprBits>; /// Instantiate a scalar from an unsigned integer without checking for overflow. pub trait FromUintUnchecked { /// Unsigned integer type (i.e. `Curve::Uint`) type Uint: Integer; /// Instantiate scalar from an unsigned integer without checking /// whether the value overflows the field modulus. /// /// ⚠️ WARNING! /// /// Incorrectly used this can lead to mathematically invalid results, /// which can lead to potential security vulnerabilities. /// /// Use with care! fn from_uint_unchecked(uint: Self::Uint) -> Self; } /// Is this scalar greater than n / 2? /// /// # Returns /// /// - For scalars 0 through n / 2: `Choice::from(0)` /// - For scalars (n / 2) + 1 through n - 1: `Choice::from(1)` pub trait IsHigh { /// Is this scalar greater than or equal to n / 2? fn is_high(&self) -> Choice; } elliptic-curve-0.13.8/src/sec1.rs000064400000000000000000000073321046102023000146410ustar 00000000000000//! Support for SEC1 elliptic curve encoding formats. //! //! pub use sec1::point::{Coordinates, ModulusSize, Tag}; use crate::{Curve, FieldBytesSize, Result, SecretKey}; use generic_array::GenericArray; use subtle::CtOption; #[cfg(feature = "arithmetic")] use crate::{AffinePoint, CurveArithmetic, Error}; /// Encoded elliptic curve point with point compression. pub type CompressedPoint = GenericArray>; /// Size of a compressed elliptic curve point. pub type CompressedPointSize = as ModulusSize>::CompressedPointSize; /// Encoded elliptic curve point sized appropriately for a given curve. pub type EncodedPoint = sec1::point::EncodedPoint>; /// Encoded elliptic curve point *without* point compression. pub type UncompressedPoint = GenericArray>; /// Size of an uncompressed elliptic curve point. pub type UncompressedPointSize = as ModulusSize>::UncompressedPointSize; /// Trait for deserializing a value from a SEC1 encoded curve point. /// /// This is intended for use with the `AffinePoint` type for a given elliptic curve. pub trait FromEncodedPoint where Self: Sized, C: Curve, FieldBytesSize: ModulusSize, { /// Deserialize the type this trait is impl'd on from an [`EncodedPoint`]. fn from_encoded_point(point: &EncodedPoint) -> CtOption; } /// Trait for serializing a value to a SEC1 encoded curve point. /// /// This is intended for use with the `AffinePoint` type for a given elliptic curve. pub trait ToEncodedPoint where C: Curve, FieldBytesSize: ModulusSize, { /// Serialize this value as a SEC1 [`EncodedPoint`], optionally applying /// point compression. fn to_encoded_point(&self, compress: bool) -> EncodedPoint; } /// Trait for serializing a value to a SEC1 encoded curve point with compaction. /// /// This is intended for use with the `AffinePoint` type for a given elliptic curve. pub trait ToCompactEncodedPoint where C: Curve, FieldBytesSize: ModulusSize, { /// Serialize this value as a SEC1 [`EncodedPoint`], optionally applying /// point compression. fn to_compact_encoded_point(&self) -> CtOption>; } /// Validate that the given [`EncodedPoint`] represents the encoded public key /// value of the given secret. /// /// Curve implementations which also impl [`CurveArithmetic`] will receive /// a blanket default impl of this trait. pub trait ValidatePublicKey where Self: Curve, FieldBytesSize: ModulusSize, { /// Validate that the given [`EncodedPoint`] is a valid public key for the /// provided secret value. #[allow(unused_variables)] fn validate_public_key( secret_key: &SecretKey, public_key: &EncodedPoint, ) -> Result<()> { // Provide a default "always succeeds" implementation. // This is the intended default for curve implementations which // do not provide an arithmetic implementation, since they have no // way to verify this. // // Implementations with an arithmetic impl will receive a blanket impl // of this trait. Ok(()) } } #[cfg(feature = "arithmetic")] impl ValidatePublicKey for C where C: CurveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { fn validate_public_key(secret_key: &SecretKey, public_key: &EncodedPoint) -> Result<()> { let pk = secret_key .public_key() .to_encoded_point(public_key.is_compressed()); if public_key == &pk { Ok(()) } else { Err(Error) } } } elliptic-curve-0.13.8/src/secret_key/pkcs8.rs000064400000000000000000000050001046102023000171610ustar 00000000000000//! PKCS#8 encoding/decoding support. use super::SecretKey; use crate::{ pkcs8::{self, der::Decode, AssociatedOid}, sec1::{ModulusSize, ValidatePublicKey}, Curve, FieldBytesSize, ALGORITHM_OID, }; use pkcs8::spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, ObjectIdentifier}; use sec1::EcPrivateKey; // Imports for the `EncodePrivateKey` impl #[cfg(all(feature = "alloc", feature = "arithmetic"))] use { crate::{ sec1::{FromEncodedPoint, ToEncodedPoint}, AffinePoint, CurveArithmetic, }, pkcs8::{der, EncodePrivateKey}, }; // Imports for actual PEM support #[cfg(feature = "pem")] use { crate::{error::Error, Result}, core::str::FromStr, pkcs8::DecodePrivateKey, }; impl AssociatedAlgorithmIdentifier for SecretKey where C: AssociatedOid + Curve, { type Params = ObjectIdentifier; const ALGORITHM_IDENTIFIER: AlgorithmIdentifier = AlgorithmIdentifier { oid: ALGORITHM_OID, parameters: Some(C::OID), }; } impl TryFrom> for SecretKey where C: AssociatedOid + Curve + ValidatePublicKey, FieldBytesSize: ModulusSize, { type Error = pkcs8::Error; fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result { private_key_info .algorithm .assert_oids(ALGORITHM_OID, C::OID)?; let ec_private_key = EcPrivateKey::from_der(private_key_info.private_key)?; Ok(Self::try_from(ec_private_key)?) } } #[cfg(all(feature = "alloc", feature = "arithmetic"))] impl EncodePrivateKey for SecretKey where C: AssociatedOid + CurveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { fn to_pkcs8_der(&self) -> pkcs8::Result { // TODO(tarcieri): make `PrivateKeyInfo` generic around `Params` let algorithm_identifier = pkcs8::AlgorithmIdentifierRef { oid: ALGORITHM_OID, parameters: Some((&C::OID).into()), }; let ec_private_key = self.to_sec1_der()?; let pkcs8_key = pkcs8::PrivateKeyInfo::new(algorithm_identifier, &ec_private_key); Ok(der::SecretDocument::encode_msg(&pkcs8_key)?) } } #[cfg(feature = "pem")] impl FromStr for SecretKey where C: Curve + AssociatedOid + ValidatePublicKey, FieldBytesSize: ModulusSize, { type Err = Error; fn from_str(s: &str) -> Result { Self::from_pkcs8_pem(s).map_err(|_| Error) } } elliptic-curve-0.13.8/src/secret_key.rs000064400000000000000000000261111046102023000161370ustar 00000000000000//! Secret keys for elliptic curves (i.e. private scalars). //! //! The [`SecretKey`] type is a wrapper around a secret scalar value which is //! designed to prevent unintentional exposure (e.g. via `Debug` or other //! logging). It also handles zeroing the secret value out of memory securely //! on drop. #[cfg(all(feature = "pkcs8", feature = "sec1"))] mod pkcs8; use crate::{Curve, Error, FieldBytes, Result, ScalarPrimitive}; use core::fmt::{self, Debug}; use generic_array::typenum::Unsigned; use subtle::{Choice, ConstantTimeEq}; use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing}; #[cfg(feature = "arithmetic")] use crate::{rand_core::CryptoRngCore, CurveArithmetic, NonZeroScalar, PublicKey}; #[cfg(feature = "jwk")] use crate::jwk::{JwkEcKey, JwkParameters}; #[cfg(feature = "pem")] use pem_rfc7468::{self as pem, PemLabel}; #[cfg(feature = "sec1")] use { crate::{ sec1::{EncodedPoint, ModulusSize, ValidatePublicKey}, FieldBytesSize, }, sec1::der, }; #[cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1"))] use { crate::{ sec1::{FromEncodedPoint, ToEncodedPoint}, AffinePoint, }, alloc::vec::Vec, sec1::der::Encode, }; #[cfg(all(feature = "arithmetic", any(feature = "jwk", feature = "pem")))] use alloc::string::String; #[cfg(all(feature = "arithmetic", feature = "jwk"))] use alloc::string::ToString; #[cfg(all(doc, feature = "pkcs8"))] use {crate::pkcs8::DecodePrivateKey, core::str::FromStr}; /// Elliptic curve secret keys. /// /// This type wraps a secret scalar value, helping to prevent accidental /// exposure and securely erasing the value from memory when dropped. /// /// # Parsing PKCS#8 Keys /// /// PKCS#8 is a commonly used format for encoding secret keys (especially ones /// generated by OpenSSL). /// /// Keys in PKCS#8 format are either binary (ASN.1 BER/DER), or PEM encoded /// (ASCII) and begin with the following: /// /// ```text /// -----BEGIN PRIVATE KEY----- /// ``` /// /// To decode an elliptic curve private key from PKCS#8, enable the `pkcs8` /// feature of this crate (or the `pkcs8` feature of a specific RustCrypto /// elliptic curve crate) and use the [`DecodePrivateKey`] trait to parse it. /// /// When the `pem` feature of this crate (or a specific RustCrypto elliptic /// curve crate) is enabled, a [`FromStr`] impl is also available. #[derive(Clone)] pub struct SecretKey { /// Scalar value inner: ScalarPrimitive, } impl SecretKey where C: Curve, { /// Minimum allowed size of an elliptic curve secret key in bytes. /// /// This provides the equivalent of 96-bits of symmetric security. const MIN_SIZE: usize = 24; /// Generate a random [`SecretKey`]. #[cfg(feature = "arithmetic")] pub fn random(rng: &mut impl CryptoRngCore) -> Self where C: CurveArithmetic, { Self { inner: NonZeroScalar::::random(rng).into(), } } /// Create a new secret key from a scalar value. pub fn new(scalar: ScalarPrimitive) -> Self { Self { inner: scalar } } /// Borrow the inner secret [`ScalarPrimitive`] value. /// /// # ⚠️ Warning /// /// This value is key material. /// /// Please treat it with the care it deserves! pub fn as_scalar_primitive(&self) -> &ScalarPrimitive { &self.inner } /// Get the secret [`NonZeroScalar`] value for this key. /// /// # ⚠️ Warning /// /// This value is key material. /// /// Please treat it with the care it deserves! #[cfg(feature = "arithmetic")] pub fn to_nonzero_scalar(&self) -> NonZeroScalar where C: CurveArithmetic, { self.into() } /// Get the [`PublicKey`] which corresponds to this secret key #[cfg(feature = "arithmetic")] pub fn public_key(&self) -> PublicKey where C: CurveArithmetic, { PublicKey::from_secret_scalar(&self.to_nonzero_scalar()) } /// Deserialize secret key from an encoded secret scalar. pub fn from_bytes(bytes: &FieldBytes) -> Result { let inner: ScalarPrimitive = Option::from(ScalarPrimitive::from_bytes(bytes)).ok_or(Error)?; if inner.is_zero().into() { return Err(Error); } Ok(Self { inner }) } /// Deserialize secret key from an encoded secret scalar passed as a byte slice. /// /// The slice is expected to be a minimum of 24-bytes (192-byts) and at most `C::FieldBytesSize` /// bytes in length. /// /// Byte slices shorter than the field size are handled by zero padding the input. pub fn from_slice(slice: &[u8]) -> Result { if slice.len() == C::FieldBytesSize::USIZE { Self::from_bytes(FieldBytes::::from_slice(slice)) } else if (Self::MIN_SIZE..C::FieldBytesSize::USIZE).contains(&slice.len()) { let mut bytes = Zeroizing::new(FieldBytes::::default()); let offset = C::FieldBytesSize::USIZE.saturating_sub(slice.len()); bytes[offset..].copy_from_slice(slice); Self::from_bytes(&bytes) } else { Err(Error) } } /// Serialize raw secret scalar as a big endian integer. pub fn to_bytes(&self) -> FieldBytes { self.inner.to_bytes() } /// Deserialize secret key encoded in the SEC1 ASN.1 DER `ECPrivateKey` format. #[cfg(feature = "sec1")] pub fn from_sec1_der(der_bytes: &[u8]) -> Result where C: Curve + ValidatePublicKey, FieldBytesSize: ModulusSize, { sec1::EcPrivateKey::try_from(der_bytes)? .try_into() .map_err(|_| Error) } /// Serialize secret key in the SEC1 ASN.1 DER `ECPrivateKey` format. #[cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1"))] pub fn to_sec1_der(&self) -> der::Result>> where C: CurveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { let private_key_bytes = Zeroizing::new(self.to_bytes()); let public_key_bytes = self.public_key().to_encoded_point(false); let ec_private_key = Zeroizing::new( sec1::EcPrivateKey { private_key: &private_key_bytes, parameters: None, public_key: Some(public_key_bytes.as_bytes()), } .to_der()?, ); Ok(ec_private_key) } /// Parse [`SecretKey`] from PEM-encoded SEC1 `ECPrivateKey` format. /// /// PEM-encoded SEC1 keys can be identified by the leading delimiter: /// /// ```text /// -----BEGIN EC PRIVATE KEY----- /// ``` #[cfg(feature = "pem")] pub fn from_sec1_pem(s: &str) -> Result where C: Curve + ValidatePublicKey, FieldBytesSize: ModulusSize, { let (label, der_bytes) = pem::decode_vec(s.as_bytes()).map_err(|_| Error)?; if label != sec1::EcPrivateKey::PEM_LABEL { return Err(Error); } Self::from_sec1_der(&der_bytes).map_err(|_| Error) } /// Serialize private key as self-zeroizing PEM-encoded SEC1 `ECPrivateKey` /// with the given [`pem::LineEnding`]. /// /// Pass `Default::default()` to use the OS's native line endings. #[cfg(feature = "pem")] pub fn to_sec1_pem(&self, line_ending: pem::LineEnding) -> Result> where C: CurveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { self.to_sec1_der() .ok() .and_then(|der| { pem::encode_string(sec1::EcPrivateKey::PEM_LABEL, line_ending, &der).ok() }) .map(Zeroizing::new) .ok_or(Error) } /// Parse a [`JwkEcKey`] JSON Web Key (JWK) into a [`SecretKey`]. #[cfg(feature = "jwk")] pub fn from_jwk(jwk: &JwkEcKey) -> Result where C: JwkParameters + ValidatePublicKey, FieldBytesSize: ModulusSize, { Self::try_from(jwk) } /// Parse a string containing a JSON Web Key (JWK) into a [`SecretKey`]. #[cfg(feature = "jwk")] pub fn from_jwk_str(jwk: &str) -> Result where C: JwkParameters + ValidatePublicKey, FieldBytesSize: ModulusSize, { jwk.parse::().and_then(|jwk| Self::from_jwk(&jwk)) } /// Serialize this secret key as [`JwkEcKey`] JSON Web Key (JWK). #[cfg(all(feature = "arithmetic", feature = "jwk"))] pub fn to_jwk(&self) -> JwkEcKey where C: CurveArithmetic + JwkParameters, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { self.into() } /// Serialize this secret key as JSON Web Key (JWK) string. #[cfg(all(feature = "arithmetic", feature = "jwk"))] pub fn to_jwk_string(&self) -> Zeroizing where C: CurveArithmetic + JwkParameters, AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, { Zeroizing::new(self.to_jwk().to_string()) } } impl ConstantTimeEq for SecretKey where C: Curve, { fn ct_eq(&self, other: &Self) -> Choice { self.inner.ct_eq(&other.inner) } } impl Debug for SecretKey where C: Curve, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct(core::any::type_name::()) .finish_non_exhaustive() } } impl ZeroizeOnDrop for SecretKey where C: Curve {} impl Drop for SecretKey where C: Curve, { fn drop(&mut self) { self.inner.zeroize(); } } impl Eq for SecretKey {} impl PartialEq for SecretKey where C: Curve, { fn eq(&self, other: &Self) -> bool { self.ct_eq(other).into() } } #[cfg(feature = "sec1")] impl TryFrom> for SecretKey where C: Curve + ValidatePublicKey, FieldBytesSize: ModulusSize, { type Error = der::Error; fn try_from(sec1_private_key: sec1::EcPrivateKey<'_>) -> der::Result { let secret_key = Self::from_slice(sec1_private_key.private_key) .map_err(|_| der::Tag::Sequence.value_error())?; // TODO(tarcieri): validate `sec1_private_key.params`? if let Some(pk_bytes) = sec1_private_key.public_key { let pk = EncodedPoint::::from_bytes(pk_bytes) .map_err(|_| der::Tag::BitString.value_error())?; if C::validate_public_key(&secret_key, &pk).is_err() { return Err(der::Tag::BitString.value_error()); } } Ok(secret_key) } } #[cfg(feature = "arithmetic")] impl From> for SecretKey where C: CurveArithmetic, { fn from(scalar: NonZeroScalar) -> SecretKey { SecretKey::from(&scalar) } } #[cfg(feature = "arithmetic")] impl From<&NonZeroScalar> for SecretKey where C: CurveArithmetic, { fn from(scalar: &NonZeroScalar) -> SecretKey { SecretKey { inner: scalar.into(), } } } elliptic-curve-0.13.8/src/voprf.rs000064400000000000000000000015061046102023000151370ustar 00000000000000//! Verifiable Oblivious Pseudorandom Function (VOPRF) using prime order groups //! //! use crate::PrimeCurve; /// Elliptic curve parameters used by VOPRF. pub trait VoprfParameters: PrimeCurve { /// The `ID` parameter which identifies a particular elliptic curve /// as defined in [section 4 of `draft-irtf-cfrg-voprf-19`][voprf]. /// /// [voprf]: https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-19.html#name-ciphersuites-2 const ID: &'static str; /// The `Hash` parameter which assigns a particular hash function to this /// ciphersuite as defined in [section 4 of `draft-irtf-cfrg-voprf-19`][voprf]. /// /// [voprf]: https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-19.html#name-ciphersuites-2 type Hash: digest::Digest; } elliptic-curve-0.13.8/src/weierstrass.rs000064400000000000000000000111161046102023000163540ustar 00000000000000//! Complete projective formulas for prime order elliptic curves as described //! in [Renes-Costello-Batina 2015]. //! //! [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060 #![allow(clippy::op_ref)] use ff::Field; /// Affine point whose coordinates are represented by the given field element. pub type AffinePoint = (Fe, Fe); /// Projective point whose coordinates are represented by the given field element. pub type ProjectivePoint = (Fe, Fe, Fe); /// Implements the complete addition formula from [Renes-Costello-Batina 2015] /// (Algorithm 4). /// /// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060 #[inline(always)] pub fn add( (ax, ay, az): ProjectivePoint, (bx, by, bz): ProjectivePoint, curve_equation_b: Fe, ) -> ProjectivePoint where Fe: Field, { // The comments after each line indicate which algorithm steps are being // performed. let xx = ax * bx; // 1 let yy = ay * by; // 2 let zz = az * bz; // 3 let xy_pairs = ((ax + ay) * &(bx + by)) - &(xx + &yy); // 4, 5, 6, 7, 8 let yz_pairs = ((ay + az) * &(by + bz)) - &(yy + &zz); // 9, 10, 11, 12, 13 let xz_pairs = ((ax + az) * &(bx + bz)) - &(xx + &zz); // 14, 15, 16, 17, 18 let bzz_part = xz_pairs - &(curve_equation_b * &zz); // 19, 20 let bzz3_part = bzz_part.double() + &bzz_part; // 21, 22 let yy_m_bzz3 = yy - &bzz3_part; // 23 let yy_p_bzz3 = yy + &bzz3_part; // 24 let zz3 = zz.double() + &zz; // 26, 27 let bxz_part = (curve_equation_b * &xz_pairs) - &(zz3 + &xx); // 25, 28, 29 let bxz3_part = bxz_part.double() + &bxz_part; // 30, 31 let xx3_m_zz3 = xx.double() + &xx - &zz3; // 32, 33, 34 ( (yy_p_bzz3 * &xy_pairs) - &(yz_pairs * &bxz3_part), // 35, 39, 40 (yy_p_bzz3 * &yy_m_bzz3) + &(xx3_m_zz3 * &bxz3_part), // 36, 37, 38 (yy_m_bzz3 * &yz_pairs) + &(xy_pairs * &xx3_m_zz3), // 41, 42, 43 ) } /// Implements the complete mixed addition formula from /// [Renes-Costello-Batina 2015] (Algorithm 5). /// /// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060 #[inline(always)] pub fn add_mixed( (ax, ay, az): ProjectivePoint, (bx, by): AffinePoint, curve_equation_b: Fe, ) -> ProjectivePoint where Fe: Field, { // The comments after each line indicate which algorithm steps are being // performed. let xx = ax * &bx; // 1 let yy = ay * &by; // 2 let xy_pairs = ((ax + &ay) * &(bx + &by)) - &(xx + &yy); // 3, 4, 5, 6, 7 let yz_pairs = (by * &az) + &ay; // 8, 9 (t4) let xz_pairs = (bx * &az) + &ax; // 10, 11 (y3) let bz_part = xz_pairs - &(curve_equation_b * &az); // 12, 13 let bz3_part = bz_part.double() + &bz_part; // 14, 15 let yy_m_bzz3 = yy - &bz3_part; // 16 let yy_p_bzz3 = yy + &bz3_part; // 17 let z3 = az.double() + &az; // 19, 20 let bxz_part = (curve_equation_b * &xz_pairs) - &(z3 + &xx); // 18, 21, 22 let bxz3_part = bxz_part.double() + &bxz_part; // 23, 24 let xx3_m_zz3 = xx.double() + &xx - &z3; // 25, 26, 27 ( (yy_p_bzz3 * &xy_pairs) - &(yz_pairs * &bxz3_part), // 28, 32, 33 (yy_p_bzz3 * &yy_m_bzz3) + &(xx3_m_zz3 * &bxz3_part), // 29, 30, 31 (yy_m_bzz3 * &yz_pairs) + &(xy_pairs * &xx3_m_zz3), // 34, 35, 36 ) } /// Implements the exception-free point doubling formula from /// [Renes-Costello-Batina 2015] (Algorithm 6). /// /// [Renes-Costello-Batina 2015]: https://eprint.iacr.org/2015/1060 #[inline(always)] pub fn double((x, y, z): ProjectivePoint, curve_equation_b: Fe) -> ProjectivePoint where Fe: Field, { // The comments after each line indicate which algorithm steps are being // performed. let xx = x.square(); // 1 let yy = y.square(); // 2 let zz = z.square(); // 3 let xy2 = (x * &y).double(); // 4, 5 let xz2 = (x * &z).double(); // 6, 7 let bzz_part = (curve_equation_b * &zz) - &xz2; // 8, 9 let bzz3_part = bzz_part.double() + &bzz_part; // 10, 11 let yy_m_bzz3 = yy - &bzz3_part; // 12 let yy_p_bzz3 = yy + &bzz3_part; // 13 let y_frag = yy_p_bzz3 * &yy_m_bzz3; // 14 let x_frag = yy_m_bzz3 * &xy2; // 15 let zz3 = zz.double() + &zz; // 16, 17 let bxz2_part = (curve_equation_b * &xz2) - &(zz3 + &xx); // 18, 19, 20 let bxz6_part = bxz2_part.double() + &bxz2_part; // 21, 22 let xx3_m_zz3 = xx.double() + &xx - &zz3; // 23, 24, 25 let dy = y_frag + &(xx3_m_zz3 * &bxz6_part); // 26, 27 let yz2 = (y * &z).double(); // 28, 29 let dx = x_frag - &(bxz6_part * &yz2); // 30, 31 let dz = (yz2 * &yy).double().double(); // 32, 33, 34 (dx, dy, dz) } elliptic-curve-0.13.8/tests/examples/pkcs8-private-key.der000064400000000000000000000002121046102023000216010ustar 0000000000000000*H=*H=m0k ibAqVc4 iTUjJgDB_/,؝7K&$R-79āD0M~jЏ_+RDp)elliptic-curve-0.13.8/tests/examples/pkcs8-private-key.pem000064400000000000000000000003601046102023000216140ustar 00000000000000-----BEGIN PRIVATE KEY----- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgaWJBcVYaYzQN4OfY afKgVJJVjhoEhotqn4VKhmeIGI2hRANCAAQcrP+1Xy8s79idies3SyaBFSRSgC3u oJkWBoE32DnPf8SBpESSME1+9mrBF77+g6jQjxVfK1L59hjdRHApBI4P -----END PRIVATE KEY-----elliptic-curve-0.13.8/tests/examples/pkcs8-public-key.der000064400000000000000000000001331046102023000214070ustar 000000000000000Y0*H=*H=B_/,؝7K&$R-79āD0M~jЏ_+RDp)elliptic-curve-0.13.8/tests/examples/pkcs8-public-key.pem000064400000000000000000000002621046102023000214210ustar 00000000000000-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHKz/tV8vLO/YnYnrN0smgRUkUoAt 7qCZFgaBN9g5z3/EgaREkjBNfvZqwRe+/oOo0I8VXytS+fYY3URwKQSODw== -----END PUBLIC KEY----- elliptic-curve-0.13.8/tests/pkcs8.rs000064400000000000000000000034651046102023000154140ustar 00000000000000//! PKCS#8 tests #![cfg(all(feature = "dev", feature = "pkcs8"))] use elliptic_curve::{ dev::{PublicKey, SecretKey}, pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey}, sec1::ToEncodedPoint, }; use hex_literal::hex; use pkcs8::der; /// DER-encoded PKCS#8 public key const PKCS8_PUBLIC_KEY_DER: &[u8; 91] = include_bytes!("examples/pkcs8-public-key.der"); /// PEM-encoded PKCS#8 public key #[cfg(feature = "pem")] const PKCS8_PUBLIC_KEY_PEM: &str = include_str!("examples/pkcs8-public-key.pem"); /// Example encoded scalar value const EXAMPLE_SCALAR: [u8; 32] = hex!("AABBCCDDEEFF0000000000000000000000000000000000000000000000000001"); /// Example PKCS#8 private key fn example_private_key() -> der::SecretDocument { SecretKey::from_slice(&EXAMPLE_SCALAR) .unwrap() .to_pkcs8_der() .unwrap() } #[test] fn decode_pkcs8_private_key_from_der() { dbg!(example_private_key().as_bytes()); let secret_key = SecretKey::from_pkcs8_der(example_private_key().as_bytes()).unwrap(); assert_eq!(secret_key.to_bytes().as_slice(), &EXAMPLE_SCALAR); } #[test] fn decode_pkcs8_public_key_from_der() { let public_key = PublicKey::from_public_key_der(&PKCS8_PUBLIC_KEY_DER[..]).unwrap(); let expected_sec1_point = hex!("041CACFFB55F2F2CEFD89D89EB374B2681152452802DEEA09916068137D839CF7FC481A44492304D7EF66AC117BEFE83A8D08F155F2B52F9F618DD447029048E0F"); assert_eq!( public_key.to_encoded_point(false).as_bytes(), &expected_sec1_point[..] ); } #[test] #[cfg(feature = "pem")] fn decode_pkcs8_public_key_from_pem() { let public_key = PKCS8_PUBLIC_KEY_PEM.parse::().unwrap(); // Ensure key parses equivalently to DER let der_key = PublicKey::from_public_key_der(&PKCS8_PUBLIC_KEY_DER[..]).unwrap(); assert_eq!(public_key, der_key); } elliptic-curve-0.13.8/tests/secret_key.rs000064400000000000000000000010441046102023000165100ustar 00000000000000//! 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()); }