k256-0.13.3/.cargo_vcs_info.json0000644000000001420000000000100116040ustar { "git": { "sha1": "3787e4cd5b4223cae8bed05d087d6ff2f1d9430b" }, "path_in_vcs": "k256" }k256-0.13.3/CHANGELOG.md000064400000000000000000000477241046102023000122260ustar 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.3 (2024-01-08) ### Added - More inlines for better efficiency ([#999]) [#999]: https://github.com/RustCrypto/elliptic-curves/pull/999 ## 0.13.2 (2023-11-15) ### Added - `#[inline]` annotations on `conditional_select` ([#942]) - `BatchInvert` and `BatchNormalize` impls ([#971]) - Optimized implementation of `LinearCombinationExt` trait ([#974]) ### Changed - Use generic signing implementation from `ecdsa` crate ([#911]) - Simplify internal helper functions in the scalar arithmetic ([#917]) - Bump `elliptic-curve` to v0.13.7 ([#979]) ### Fixed - Reject signatures which aren't low-`S` normalized ([#914]) - Check for `R` being the identity point on Schnorr verification ([#916]) [#911]: https://github.com/RustCrypto/elliptic-curves/pull/911 [#914]: https://github.com/RustCrypto/elliptic-curves/pull/914 [#916]: https://github.com/RustCrypto/elliptic-curves/pull/916 [#917]: https://github.com/RustCrypto/elliptic-curves/pull/917 [#942]: https://github.com/RustCrypto/elliptic-curves/pull/942 [#971]: https://github.com/RustCrypto/elliptic-curves/pull/971 [#974]: https://github.com/RustCrypto/elliptic-curves/pull/974 [#979]: https://github.com/RustCrypto/elliptic-curves/pull/979 ## 0.13.1 (2023-04-09) ### Fixed - Correct product definition for empty iterators ([#802]) [#802]: https://github.com/RustCrypto/elliptic-curves/pull/802 ## 0.13.0 (2023-03-02) ### Added - `FieldBytesEncoding` trait impls ([#732]) - Fast `invert_vartime` using Stein's algorithm ([#743]) - `serde` support for `schnorr` types ([#748]) ### Changed - `AffineCoordinates` trait ([#734]) - Bump `elliptic-curve` dependency to v0.13 ([#770]) - Bump `ecdsa` to v0.16 ([#770]) [#732]: https://github.com/RustCrypto/elliptic-curves/pull/732 [#734]: https://github.com/RustCrypto/elliptic-curves/pull/734 [#743]: https://github.com/RustCrypto/elliptic-curves/pull/743 [#748]: https://github.com/RustCrypto/elliptic-curves/pull/748 [#770]: https://github.com/RustCrypto/elliptic-curves/pull/770 ## 0.12.0 (2023-01-16) ### Added - `alloc` feature ([#670]) - Impl `FromOkm` for `Scalar` ([#673]) - Impl `Prehash*` and `KeypairRef` for Schnorr keys ([#689]) - `schnorr::SigningKey::as_nonzero_scalar` ([#690]) - Impl `From` for `schnorr::SigningKey` ([#703]) - Impl `From` for `schnorr::SigningKey` ([#704]) - `precomputed-tables` feature ([#697], [#705], [#707]) - Constructors for `Scalar` from `u128` ([#709]) ### Changed - Use weak feature activation; MSRV 1.60 ([#701]) - Bump `ecdsa` dependency to v0.15 ([#713]) ### Removed - `ecdsa::recoverable` module; see documentation for replacements ([#675]) [#670]: https://github.com/RustCrypto/elliptic-curves/pull/670 [#673]: https://github.com/RustCrypto/elliptic-curves/pull/673 [#675]: https://github.com/RustCrypto/elliptic-curves/pull/675 [#689]: https://github.com/RustCrypto/elliptic-curves/pull/689 [#690]: https://github.com/RustCrypto/elliptic-curves/pull/690 [#697]: https://github.com/RustCrypto/elliptic-curves/pull/697 [#701]: https://github.com/RustCrypto/elliptic-curves/pull/701 [#703]: https://github.com/RustCrypto/elliptic-curves/pull/703 [#704]: https://github.com/RustCrypto/elliptic-curves/pull/704 [#705]: https://github.com/RustCrypto/elliptic-curves/pull/705 [#707]: https://github.com/RustCrypto/elliptic-curves/pull/707 [#709]: https://github.com/RustCrypto/elliptic-curves/pull/709 [#713]: https://github.com/RustCrypto/elliptic-curves/pull/713 ## 0.11.6 (2022-09-27) ### Added - `ecdsa::recoverable::Signature::from_digest_bytes_trial_recovery` ([#660]) ### Changed - Make `ProjectivePoint` equality and `is_identity` faster ([#650]) [#650]: https://github.com/RustCrypto/elliptic-curves/pull/650 [#660]: https://github.com/RustCrypto/elliptic-curves/pull/660 ## 0.11.5 (2022-09-14) ### Added - Impl `PrehashSigner` and `PrehashVerifier` traits for ECDSA keys ([#653]) - Impl `Keypair` for `SigningKey` ([#654]) [#653]: https://github.com/RustCrypto/elliptic-curves/pull/653 [#654]: https://github.com/RustCrypto/elliptic-curves/pull/654 ## 0.11.4 (2022-08-13) ### Added - Impl `ZeroizeOnDrop` for `ecdsa::SigningKey` and `schnorr::SigningKey` ([#630]) ### Changed - Get rid of eager computation in `mul_shift_vartime()` ([#638]) - Bump the precision of precomputed division for the scalar decomposition ([#639]) [#630]: https://github.com/RustCrypto/elliptic-curves/pull/630 [#638]: https://github.com/RustCrypto/elliptic-curves/pull/638 [#639]: https://github.com/RustCrypto/elliptic-curves/pull/639 ## 0.11.3 (2022-07-02) ### Changed - Relax `DigestSigner` trait bounds ([#613]) - Bump `elliptic-curve` to v0.12.2 ([#616]) [#613]: https://github.com/RustCrypto/elliptic-curves/pull/613 [#616]: https://github.com/RustCrypto/elliptic-curves/pull/616 ## 0.11.2 (2022-05-24) ### Changed - Enable `schnorr` feature by default ([#561]) [#561]: https://github.com/RustCrypto/elliptic-curves/pull/561 ## 0.11.1 (2022-05-24) ### Added - Taproot Schnorr as defined in BIP 340 ([#554], [#557], [#558]) - Re-export low-level `diffie_hellman` function ([#556]) ### Changed - Use SHA-256 for computing RFC6979 for `recoverable::Signature` ([#552]) [#552]: https://github.com/RustCrypto/elliptic-curves/pull/552 [#554]: https://github.com/RustCrypto/elliptic-curves/pull/554 [#556]: https://github.com/RustCrypto/elliptic-curves/pull/556 [#557]: https://github.com/RustCrypto/elliptic-curves/pull/557 [#558]: https://github.com/RustCrypto/elliptic-curves/pull/558 ## 0.11.0 (2022-05-09) ### Changed - Bump `digest` to v0.10 ([#515]) - Make `AffinePoint` to `VerifyingKey` conversion fallible ([#535]) - Rename `recover_verify_key` => `recover_verifying_key` ([#537]) - Rename `recover_verify_key_from_digest` => `recover_verifying_key_from_digest` ([#537]) - Have `pkcs8` feature activate `ecdsa/pkcs8` ([#538]) - Bump `elliptic-curve` to v0.12 ([#544]) - Bump `ecdsa` to v0.14 ([#544]) ### Fixed - `hash2curve` crate feature ([#519]) [#515]: https://github.com/RustCrypto/elliptic-curves/pull/515 [#519]: https://github.com/RustCrypto/elliptic-curves/pull/519 [#535]: https://github.com/RustCrypto/elliptic-curves/pull/535 [#537]: https://github.com/RustCrypto/elliptic-curves/pull/537 [#538]: https://github.com/RustCrypto/elliptic-curves/pull/538 [#544]: https://github.com/RustCrypto/elliptic-curves/pull/544 ## 0.10.4 (2022-03-15) ### Fixed - Normalize before calling `is_odd()` in `sng0()` ([#533]) [#533]: https://github.com/RustCrypto/elliptic-curves/pull/533 ## 0.10.3 (2022-03-14) ### Fixed - Do not normalize the argument in `FieldElementImpl::is_odd()` ([#530]) [#530]: https://github.com/RustCrypto/elliptic-curves/pull/530 ## 0.10.2 (2022-01-17) ### Added - hash2curve support: impl `GroupDigest` for `Secp256k1` ([#503]) - `IDENTITY` and `GENERATOR` point constants ([#511]) [#503]: https://github.com/RustCrypto/elliptic-curves/pull/503 [#511]: https://github.com/RustCrypto/elliptic-curves/pull/511 ## 0.10.1 (2022-01-04) ### Added - Impl `ff::Field` trait for `FieldElement` ([#498]) - Impl `ReduceNonZero` for `Scalar` ([#501]) [#498]: https://github.com/RustCrypto/elliptic-curves/pull/498 [#501]: https://github.com/RustCrypto/elliptic-curves/pull/501 ## 0.10.0 (2021-12-14) ### Added - Implement `Scalar::sqrt` ([#400]) - Impl `PrimeCurveArithmetic` ([#415]) - Impl `Reduce` for `Scalar` ([#436]) - Impl `Drop` for `ecdsa::SigningKey` ([#449]) - `serde` feature ([#463], [#464]) - Impl `Reduce` for `Scalar` ([#472]) - Impl `ReduceNonZero` for `Scalar` ([#474]) - Impl `LinearCombination` trait ([#476]) ### Changed - Make `ecdsa::Signature::normalize_s` non-mutating ([#405]) - Use `PrimeCurve` trait ([#413]) - Use `sec1` crate for `EncodedPoint` type ([#435]) - Replace `ecdsa::hazmat::FromDigest` with `Reduce` ([#438]) - Make `FromEncodedPoint` return a `CtOption` ([#445]) - Rust 2021 edition upgrade; MSRV 1.56+ ([#453]) - Bump `elliptic-curve` crate dependency to v0.11 ([#466]) - Bump `ecdsa` crate dependency to v0.13 ([#467]) ### Fixed - Handle identity point in `GroupEncoding` ([#446]) ### Removed - `force-32-bit` feature ([#399]) - `field-montgomery` feature ([#404]) - `Scalar::conditional_add_bit` ([#431]) - Deprecated `SigningKey::verify_key` method ([#461]) [#399]: https://github.com/RustCrypto/elliptic-curves/pull/399 [#400]: https://github.com/RustCrypto/elliptic-curves/pull/400 [#404]: https://github.com/RustCrypto/elliptic-curves/pull/404 [#405]: https://github.com/RustCrypto/elliptic-curves/pull/405 [#413]: https://github.com/RustCrypto/elliptic-curves/pull/413 [#415]: https://github.com/RustCrypto/elliptic-curves/pull/415 [#431]: https://github.com/RustCrypto/elliptic-curves/pull/431 [#435]: https://github.com/RustCrypto/elliptic-curves/pull/435 [#436]: https://github.com/RustCrypto/elliptic-curves/pull/436 [#438]: https://github.com/RustCrypto/elliptic-curves/pull/438 [#445]: https://github.com/RustCrypto/elliptic-curves/pull/445 [#446]: https://github.com/RustCrypto/elliptic-curves/pull/446 [#449]: https://github.com/RustCrypto/elliptic-curves/pull/449 [#453]: https://github.com/RustCrypto/elliptic-curves/pull/453 [#461]: https://github.com/RustCrypto/elliptic-curves/pull/461 [#463]: https://github.com/RustCrypto/elliptic-curves/pull/463 [#464]: https://github.com/RustCrypto/elliptic-curves/pull/464 [#466]: https://github.com/RustCrypto/elliptic-curves/pull/466 [#467]: https://github.com/RustCrypto/elliptic-curves/pull/467 [#472]: https://github.com/RustCrypto/elliptic-curves/pull/472 [#474]: https://github.com/RustCrypto/elliptic-curves/pull/474 [#476]: https://github.com/RustCrypto/elliptic-curves/pull/476 ## 0.9.6 (2021-07-22) ### Added - Wycheproof test vectors ([#384]) ### Fixed - Edge case in `Scalar::is_high` ([#385]) - Bug in overflow check during 32-bit multiplication ([#388]) [#384]: https://github.com/RustCrypto/elliptic-curves/pull/384 [#385]: https://github.com/RustCrypto/elliptic-curves/pull/385 [#388]: https://github.com/RustCrypto/elliptic-curves/pull/388 ## 0.9.5 (2021-07-18) ### Changed - Optimize ECDSA using linear combination of points ([#380]) [#380]: https://github.com/RustCrypto/elliptic-curves/pull/380 ## 0.9.4 (2021-06-23) ### Added - Derive `Clone` for `ecdsa::SigningKey` ([#374]) [#374]: https://github.com/RustCrypto/elliptic-curves/pull/374 ## 0.9.3 (2021-06-21) ### Added - `ecdsa::SigningKey::verifying_key()` method ([#363]) ### Changed - Deprecate `SigningKey::verify_key()` - use `verifying_key` instead ([#363]) - Bump `elliptic-curve` dependency to v0.10.3 ([#371]) [#363]: https://github.com/RustCrypto/elliptic-curves/pull/363 [#371]: https://github.com/RustCrypto/elliptic-curves/pull/371 ## 0.9.2 (2021-06-14) [YANKED] ### Added - `Debug` impl for `ecdsa::SigningKey` ([#358]) - `ConstantTimeEq`/`Eq`/`PartialEq` impls for `ecdsa::SigningKey` ([#359]) [#358]: https://github.com/RustCrypto/elliptic-curves/pull/358 [#359]: https://github.com/RustCrypto/elliptic-curves/pull/359 ## 0.9.1 (2021-06-09) [YANKED] ### Added - `Copy` impl for `ecdsa::VerifyingKey` ([#355]) [#355]: https://github.com/RustCrypto/elliptic-curves/pull/355 ## 0.9.0 (2021-06-08) [YANKED] ### Added - Derive `Ord` on `ecdsa::VerifyingKey` ([#343]) - `AffineArithmetic` trait impl ([#347]) - `PrimeCurve` trait impls ([#350]) ### Changed - Bump `elliptic-curve` to v0.10; MSRV 1.51+ ([#349]) - Bump `ecdsa` to v0.12 ([#349]) [#343]: https://github.com/RustCrypto/elliptic-curves/pull/343 [#347]: https://github.com/RustCrypto/elliptic-curves/pull/347 [#349]: https://github.com/RustCrypto/elliptic-curves/pull/349 [#350]: https://github.com/RustCrypto/elliptic-curves/pull/350 ## 0.8.1 (2021-05-10) ### Fixed - Mixed coordinate addition with the point at infinity ([#337]) [#337]: https://github.com/RustCrypto/elliptic-curves/pull/337 ## 0.8.0 (2021-04-29) ### Added - `jwk` feature ([#295]) - `Order` constant ([#328]) ### Changed - Rename `ecdsa::Asn1Signature` to `::DerSignature` ([#288]) - Migrate to `FromDigest` trait from `ecdsa` crate ([#292]) - Bump `elliptic-curve` to v0.9.2 ([#296]) - Bump `pkcs8` to v0.6 ([#319]) - Bump `ecdsa` crate dependency to v0.11 ([#330]) ### Fixed - `DigestPrimitive` feature gating ([#324]) [#288]: https://github.com/RustCrypto/elliptic-curves/pull/288 [#292]: https://github.com/RustCrypto/elliptic-curves/pull/292 [#295]: https://github.com/RustCrypto/elliptic-curves/pull/295 [#296]: https://github.com/RustCrypto/elliptic-curves/pull/296 [#319]: https://github.com/RustCrypto/elliptic-curves/pull/319 [#324]: https://github.com/RustCrypto/elliptic-curves/pull/324 [#328]: https://github.com/RustCrypto/elliptic-curves/pull/328 [#330]: https://github.com/RustCrypto/elliptic-curves/pull/330 ## 0.7.3 (2021-04-16) ### Changed - Make `ecdsa` a default feature ([#325]) [#325]: https://github.com/RustCrypto/elliptic-curves/pull/325 ## 0.7.2 (2021-01-13) ### Changed - Have `std` feature activate `ecdsa-core/std` ([#273]) [#273]: https://github.com/RustCrypto/elliptic-curves/pull/273 ## 0.7.1 (2020-12-16) ### Fixed - Trigger docs.rs rebuild with nightly bugfix ([RustCrypto/traits#412]) [RustCrypto/traits#412]: https://github.com/RustCrypto/traits/pull/412 ## 0.7.0 (2020-12-16) ### Changed - Bump `elliptic-curve` dependency to v0.8 ([#260]) - Bump `ecdsa` to v0.10 ([#260]) [#260]: https://github.com/RustCrypto/elliptic-curves/pull/260 ## 0.6.0 (2020-12-06) ### Added - PKCS#8 support ([#243], [#244], [#251]) - `PublicKey` type ([#239]) ### Changed - Bump `elliptic-curve` crate dependency to v0.7; MSRV 1.46+ ([#247]) - Bump `ecdsa` crate dependency to v0.9 ([#247]) - Make `SigningKey` a newtype of `elliptic_curve::SecretKey` ([#242]) [#251]: https://github.com/RustCrypto/elliptic-curves/pull/251 [#247]: https://github.com/RustCrypto/elliptic-curves/pull/247 [#244]: https://github.com/RustCrypto/elliptic-curves/pull/244 [#243]: https://github.com/RustCrypto/elliptic-curves/pull/243 [#242]: https://github.com/RustCrypto/elliptic-curves/pull/242 [#239]: https://github.com/RustCrypto/elliptic-curves/pull/239 ## 0.5.10 (2020-10-25) ### Changed - Expand README.md ([#233]) [#233]: https://github.com/RustCrypto/elliptic-curves/pull/233 ## 0.5.9 (2020-10-08) ### Changed - Bump `cfg-if` from 0.1.10 to 1.0.0 ([#220]) [#220]: https://github.com/RustCrypto/elliptic-curves/pull/220 ## 0.5.8 (2020-10-08) ### Fixed - Regenerate `rustdoc` on https://docs.rs after nightly breakage ## 0.5.7 (2020-10-08) ### Added - `SecretValue` impl when `arithmetic` feature is disabled ([#222]) [#222]: https://github.com/RustCrypto/elliptic-curves/pull/222 ## 0.5.6 (2020-09-28) ### Added - Enable `endomorphism-mul` optimizations by default ([#213]) [#213]: https://github.com/RustCrypto/elliptic-curves/pull/213 ## 0.5.5 (2020-09-27) ### Added - Impl `FromEncodedPoint` for `ProjectivePoint` ([#210]) - Impl `ToEncodedPoint` for `ecdsa::VerifyKey` ([#209]) [#210]: https://github.com/RustCrypto/elliptic-curves/pull/210 [#209]: https://github.com/RustCrypto/elliptic-curves/pull/209 ## 0.5.4 (2020-09-27) ### Added - Impl `RecoverableSignPrimtive` on `Scalar` ([#206]) - `recoverable::Signature::recover_verify_key_from_digest_bytes` ([#205]) [#206]: https://github.com/RustCrypto/elliptic-curves/pull/206 [#205]: https://github.com/RustCrypto/elliptic-curves/pull/205 ## 0.5.3 (2020-09-23) ### Added - Derive `Copy` on `VerifyKey` ([#202]) [#202]: https://github.com/RustCrypto/elliptic-curves/pull/202 ## 0.5.2 (2020-09-22) ### Fixed - Corrected imports when using `ecdsa` + `keccak256` features ([#199]) [#199]: https://github.com/RustCrypto/elliptic-curves/pull/199 ## 0.5.1 (2020-09-21) ### Added - Documentation for `sha256` feature ([#197]) - `sec1::EncodedPoint::decompress` test ([#194]) - Impl `RandomizedSigner` on `SigningKey` ([#193]) ### Changed - Gate ecdsa::{Signer, Verifier} impls on `sha256` feature ([#192]) [#197]: https://github.com/RustCrypto/elliptic-curves/pull/197 [#194]: https://github.com/RustCrypto/elliptic-curves/pull/194 [#193]: https://github.com/RustCrypto/elliptic-curves/pull/193 [#192]: https://github.com/RustCrypto/elliptic-curves/pull/192 ## 0.5.0 (2020-09-17) ### Added - `ecdsa::Asn1Signature` type alias ([#186]) - `ff` and `group` crate dependencies; MSRV 1.44+ ([#164], [#174]) - `AffinePoint::identity()` and `::is_identity()` ([#165]) - `expose-field` feature ([#161]) - `keccak256` feature ([#142]) ### Changed - Bump `elliptic-curve` crate to v0.6; `ecdsa` to v0.8 ([#180]) - Refactor ProjectiveArithmetic trait ([#179]) - Support generic inner type for `elliptic_curve::SecretKey` ([#177]) - Rename `ElementBytes` => `FieldBytes` ([#176]) - Factor out a `from_digest_trial_recovery` method ([#168]) - Rename `ecdsa::{Signer, Verifier}` => `::{SigningKey, VerifyKey}` ([#153]) - Rename `Curve::ElementSize` => `FieldSize` ([#150]) - Implement RFC6979 deterministic ECDSA ([#146]) - Use `NonZeroScalar` for ECDSA signature components ([#144]) - Eagerly verify ECDSA scalars are in range ([#143]) - Rename `PublicKey` to `EncodedPoint` ([#141]) ### Removed - `rand` feature ([#162]) [#186]: https://github.com/RustCrypto/elliptic-curves/pull/186 [#180]: https://github.com/RustCrypto/elliptic-curves/pull/180 [#179]: https://github.com/RustCrypto/elliptic-curves/pull/179 [#177]: https://github.com/RustCrypto/elliptic-curves/pull/177 [#176]: https://github.com/RustCrypto/elliptic-curves/pull/176 [#174]: https://github.com/RustCrypto/elliptic-curves/pull/174 [#168]: https://github.com/RustCrypto/elliptic-curves/pull/168 [#165]: https://github.com/RustCrypto/elliptic-curves/pull/165 [#164]: https://github.com/RustCrypto/elliptic-curves/pull/164 [#162]: https://github.com/RustCrypto/elliptic-curves/pull/162 [#161]: https://github.com/RustCrypto/elliptic-curves/pull/161 [#153]: https://github.com/RustCrypto/elliptic-curves/pull/153 [#150]: https://github.com/RustCrypto/elliptic-curves/pull/150 [#146]: https://github.com/RustCrypto/elliptic-curves/pull/146 [#144]: https://github.com/RustCrypto/elliptic-curves/pull/144 [#143]: https://github.com/RustCrypto/elliptic-curves/pull/143 [#142]: https://github.com/RustCrypto/elliptic-curves/pull/142 [#141]: https://github.com/RustCrypto/elliptic-curves/pull/141 ## 0.4.2 (2020-08-11) ### Fixed - Builds with either `ecdsa-core` or `sha256` in isolation ([#133]) [#133]: https://github.com/RustCrypto/elliptic-curves/pull/133 ## 0.4.1 (2020-08-10) ### Fixed - secp256k1 rustdoc link ([#131]) [#131]: https://github.com/RustCrypto/elliptic-curves/pull/131 ## 0.4.0 (2020-08-10) ### Added - ECDSA support ([#73], [#101], [#104], [#105]) - ECDSA public key recovery support ([#110]) - OID support ([#103], [#113]) - Elliptic Curve Diffie-Hellman ([#120]) - `Zeroize` impl for `AffinePoint` and `FieldElement` types ([#124]) ### Changed - Optimized field arithmetic with 32-bit and 64-bit backends ([#59], [#82]) - Bump `elliptic-curve` crate dependency to v0.5 ([#126]) [#59]: https://github.com/RustCrypto/elliptic-curves/pull/59 [#73]: https://github.com/RustCrypto/elliptic-curves/pull/73 [#82]: https://github.com/RustCrypto/elliptic-curves/pull/82 [#101]: https://github.com/RustCrypto/elliptic-curves/pull/101 [#103]: https://github.com/RustCrypto/elliptic-curves/pull/103 [#104]: https://github.com/RustCrypto/elliptic-curves/pull/104 [#105]: https://github.com/RustCrypto/elliptic-curves/pull/105 [#110]: https://github.com/RustCrypto/elliptic-curves/pull/110 [#113]: https://github.com/RustCrypto/elliptic-curves/pull/113 [#120]: https://github.com/RustCrypto/elliptic-curves/pull/120 [#124]: https://github.com/RustCrypto/elliptic-curves/pull/124 [#126]: https://github.com/RustCrypto/elliptic-curves/pull/126 ## 0.3.0 (2020-06-08) ### Changed - Bump `elliptic-curve` crate dependency to v0.4 ([#39]) [#39]: https://github.com/RustCrypto/elliptic-curves/pull/39 ## 0.2.0 (2020-04-30) ### Added - Field arithmetic, point addition/doubling, and scalar multiplication ([#19]) [#19]: https://github.com/RustCrypto/elliptic-curves/pull/19 ## 0.1.1 (2020-04-20) ### Fixed - README.md: fix typo in crate name ([#16]) [#16]: https://github.com/RustCrypto/elliptic-curves/pull/16 ## 0.1.0 (2020-01-15) - Initial release k256-0.13.3/Cargo.toml0000644000000076140000000000100076150ustar # 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 = "k256" version = "0.13.3" authors = ["RustCrypto Developers"] description = """ secp256k1 elliptic curve library written in pure Rust with support for ECDSA signing/verification/public-key recovery, Taproot Schnorr signatures (BIP340), Elliptic Curve Diffie-Hellman (ECDH), and general-purpose secp256k1 elliptic curve group operations which can be used to implement arbitrary protocols """ documentation = "https://docs.rs/k256" readme = "README.md" keywords = [ "bitcoin", "crypto", "ecc", "ethereum", "secp256k1", ] categories = [ "cryptography", "cryptography::cryptocurrencies", "no-std", ] license = "Apache-2.0 OR MIT" repository = "https://github.com/RustCrypto/elliptic-curves/tree/master/k256" [package.metadata.docs.rs] features = [ "ecdh", "ecdsa", "schnorr", ] rustdoc-args = [ "--cfg", "docsrs", ] [[bench]] name = "ecdsa" harness = false required-features = [ "ecdsa", "sha256", ] [[bench]] name = "field" harness = false required-features = ["expose-field"] [[bench]] name = "scalar" harness = false [dependencies.cfg-if] version = "1.0" [dependencies.ecdsa-core] version = "0.16.8" features = ["der"] optional = true default-features = false package = "ecdsa" [dependencies.elliptic-curve] version = "0.13.8" features = [ "hazmat", "sec1", ] default-features = false [dependencies.hex-literal] version = "0.4" optional = true [dependencies.once_cell] version = "1.19" optional = true default-features = false [dependencies.serdect] version = "0.2" optional = true default-features = false [dependencies.sha2] version = "0.10" optional = true default-features = false [dependencies.signature] version = "2" optional = true [dev-dependencies.blobby] version = "0.3" [dev-dependencies.criterion] version = "0.5" [dev-dependencies.ecdsa-core] version = "0.16" features = ["dev"] default-features = false package = "ecdsa" [dev-dependencies.hex-literal] version = "0.4" [dev-dependencies.num-bigint] version = "0.4" [dev-dependencies.num-traits] version = "0.2" [dev-dependencies.proptest] version = "1.4" [dev-dependencies.rand_core] version = "0.6" features = ["getrandom"] [dev-dependencies.sha3] version = "0.10" default-features = false [features] alloc = [ "ecdsa-core?/alloc", "elliptic-curve/alloc", ] arithmetic = ["elliptic-curve/arithmetic"] bits = [ "arithmetic", "elliptic-curve/bits", ] critical-section = [ "once_cell/critical-section", "precomputed-tables", ] default = [ "arithmetic", "ecdsa", "pkcs8", "precomputed-tables", "schnorr", "std", ] digest = [ "ecdsa-core/digest", "ecdsa-core/hazmat", ] ecdh = [ "arithmetic", "elliptic-curve/ecdh", ] ecdsa = [ "arithmetic", "ecdsa-core/signing", "ecdsa-core/verifying", "sha256", ] expose-field = ["arithmetic"] hash2curve = [ "arithmetic", "elliptic-curve/hash2curve", ] jwk = ["elliptic-curve/jwk"] pem = [ "ecdsa-core/pem", "elliptic-curve/pem", "pkcs8", ] pkcs8 = [ "ecdsa-core/pkcs8", "elliptic-curve/pkcs8", ] precomputed-tables = [ "arithmetic", "once_cell", ] schnorr = [ "arithmetic", "sha256", "signature", ] serde = [ "ecdsa-core/serde", "elliptic-curve/serde", "serdect", ] sha256 = [ "digest", "sha2", ] std = [ "alloc", "ecdsa-core?/std", "elliptic-curve/std", "once_cell?/std", ] test-vectors = ["hex-literal"] k256-0.13.3/Cargo.toml.orig000064400000000000000000000056631046102023000133000ustar 00000000000000[package] name = "k256" version = "0.13.3" description = """ secp256k1 elliptic curve library written in pure Rust with support for ECDSA signing/verification/public-key recovery, Taproot Schnorr signatures (BIP340), Elliptic Curve Diffie-Hellman (ECDH), and general-purpose secp256k1 elliptic curve group operations which can be used to implement arbitrary protocols """ authors = ["RustCrypto Developers"] license = "Apache-2.0 OR MIT" documentation = "https://docs.rs/k256" repository = "https://github.com/RustCrypto/elliptic-curves/tree/master/k256" readme = "README.md" categories = ["cryptography", "cryptography::cryptocurrencies", "no-std"] keywords = ["bitcoin", "crypto", "ecc", "ethereum", "secp256k1"] edition = "2021" rust-version = "1.65" [dependencies] cfg-if = "1.0" elliptic-curve = { version = "0.13.8", default-features = false, features = ["hazmat", "sec1"] } # optional dependencies once_cell = { version = "1.19", optional = true, default-features = false } ecdsa-core = { version = "0.16.8", package = "ecdsa", optional = true, default-features = false, features = ["der"] } hex-literal = { version = "0.4", optional = true } serdect = { version = "0.2", optional = true, default-features = false } sha2 = { version = "0.10", optional = true, default-features = false } signature = { version = "2", optional = true } [dev-dependencies] blobby = "0.3" criterion = "0.5" ecdsa-core = { version = "0.16", package = "ecdsa", default-features = false, features = ["dev"] } hex-literal = "0.4" num-bigint = "0.4" num-traits = "0.2" proptest = "1.4" rand_core = { version = "0.6", features = ["getrandom"] } sha3 = { version = "0.10", default-features = false } [features] default = ["arithmetic", "ecdsa", "pkcs8", "precomputed-tables", "schnorr", "std"] alloc = ["ecdsa-core?/alloc", "elliptic-curve/alloc"] std = ["alloc", "ecdsa-core?/std", "elliptic-curve/std", "once_cell?/std"] arithmetic = ["elliptic-curve/arithmetic"] bits = ["arithmetic", "elliptic-curve/bits"] critical-section = ["once_cell/critical-section", "precomputed-tables"] digest = ["ecdsa-core/digest", "ecdsa-core/hazmat"] ecdh = ["arithmetic", "elliptic-curve/ecdh"] ecdsa = ["arithmetic", "ecdsa-core/signing", "ecdsa-core/verifying", "sha256"] expose-field = ["arithmetic"] hash2curve = ["arithmetic", "elliptic-curve/hash2curve"] jwk = ["elliptic-curve/jwk"] pem = ["ecdsa-core/pem", "elliptic-curve/pem", "pkcs8"] pkcs8 = ["ecdsa-core/pkcs8", "elliptic-curve/pkcs8"] precomputed-tables = ["arithmetic", "once_cell"] schnorr = ["arithmetic", "sha256", "signature"] serde = ["ecdsa-core/serde", "elliptic-curve/serde", "serdect"] sha256 = ["digest", "sha2"] test-vectors = ["hex-literal"] [package.metadata.docs.rs] features = ["ecdh", "ecdsa", "schnorr"] rustdoc-args = ["--cfg", "docsrs"] [[bench]] name = "ecdsa" harness = false required-features = ["ecdsa", "sha256"] [[bench]] name = "field" harness = false required-features = ["expose-field"] [[bench]] name = "scalar" harness = false k256-0.13.3/LICENSE-APACHE000064400000000000000000000251411046102023000123260ustar 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. k256-0.13.3/LICENSE-MIT000064400000000000000000000020561046102023000120360ustar 00000000000000Copyright (c) 2020-2024 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. k256-0.13.3/README.md000064400000000000000000000124741046102023000116660ustar 00000000000000# [RustCrypto]: secp256k1 (K-256) elliptic curve [![crate][crate-image]][crate-link] [![Docs][docs-image]][docs-link] [![Build Status][build-image]][build-link] ![Apache2/MIT licensed][license-image] ![Rust Version][rustc-image] [![Project Chat][chat-image]][chat-link] [secp256k1] (a.k.a. K-256) elliptic curve library written in pure Rust with support for [ECDSA] signing/verification/public-key recovery, Taproot [Schnorr signatures] as defined in BIP340, Elliptic Curve Diffie-Hellman (ECDH), and general-purpose secp256k1 elliptic curve group operations which can be used to implement arbitrary group-based protocols. Uses traits and base types from the [`elliptic-curve`] crate. Optionally includes a secp256k1 [`arithmetic`] feature providing scalar and point types (projective/affine) with support for constant-time scalar multiplication. Additionally, implements traits from the [`group`] crate which can be used to generically construct group-based protocols. [Documentation][docs-link] ## Security Notes This crate has been [audited by NCC Group], which found a high severity issue in the ECDSA/secp256k1 implementation and another high severity issue in the Schnorr/secp256k1 signature implementation, both of which have since been corrected. We would like to thank [Entropy] for funding the audit. This crate has been designed with the goal of ensuring that secret-dependent secp256k1 operations are performed in constant time (using the `subtle` crate and constant-time formulas). However, it is not suitable for use on processors with a variable-time multiplication operation (e.g. short circuit on multiply-by-zero / multiply-by-one, such as certain 32-bit PowerPC CPUs and some non-ARM microcontrollers). USE AT YOUR OWN RISK! ## Supported Algorithms - [Elliptic Curve Diffie-Hellman (ECDH)][ECDH]: gated under the `ecdh` feature. Note that this is technically ephemeral secp256k1 Diffie-Hellman (a.k.a. ECDHE) - [Elliptic Curve Digital Signature Algorithm (ECDSA)][ECDSA]: gated under the `ecdsa` feature. Support for ECDSA/secp256k1 signing and verification, applying [low-S normalization (BIP 0062)][BIP0062] as used in consensus-critical applications, and additionally supports secp256k1 public-key recovery from ECDSA signatures (as used by e.g. Ethereum) - Taproot [Schnorr signatures] (as defined in [BIP0340]): next-generation signature algorithm based on group operations enabling elegant higher-level constructions like multisignatures. ## About secp256k1 (K-256) [secp256k1] is a Koblitz curve commonly used in cryptocurrency applications. The "K-256" name follows NIST notation where P = prime fields, B = binary fields, and K = Koblitz curves. The curve is specified as `secp256k1` by Certicom's SECG in "SEC 2: Recommended Elliptic Curve Domain Parameters": secp256k1 is primarily notable for usage in Bitcoin and other cryptocurrencies, particularly in conjunction with the [Elliptic Curve Digital Signature Algorithm (ECDSA)][ECDSA]. Owing to its wide deployment in these applications, secp256k1 is one of the most popular and commonly used elliptic curves. ## Minimum Supported Rust Version Rust **1.65** or higher. Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump. ## SemVer Policy - All on-by-default features of this library are covered by SemVer - MSRV is considered exempt from SemVer as noted above ## License All crates licensed under either of * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) * [MIT license](http://opensource.org/licenses/MIT) at your option. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. [//]: # (badges) [crate-image]: https://buildstats.info/crate/k256 [crate-link]: https://crates.io/crates/k256 [docs-image]: https://docs.rs/k256/badge.svg [docs-link]: https://docs.rs/k256/ [build-image]: https://github.com/RustCrypto/elliptic-curves/workflows/k256/badge.svg?branch=master&event=push [build-link]: https://github.com/RustCrypto/elliptic-curves/actions?query=workflow%3Ak256 [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg [rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260040-elliptic-curves [//]: # (general links) [RustCrypto]: https://github.com/RustCrypto/ [secp256k1]: https://en.bitcoin.it/wiki/Secp256k1 [`elliptic-curve`]: https://github.com/RustCrypto/traits/tree/master/elliptic-curve [`arithmetic`]: https://docs.rs/k256/latest/k256/arithmetic/index.html [`group`]: https://github.com/zkcrypto/group [ECDH]: https://en.wikipedia.org/wiki/Elliptic-curve_Diffie-Hellman [ECDSA]: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm [Schnorr signatures]: https://en.wikipedia.org/wiki/Schnorr_signature [audited by NCC Group]: https://research.nccgroup.com/2023/08/30/public-report-entropy-rust-cryptography-review/ [Entropy]: https://entropy.xyz/ [BIP0062]: https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki [BIP0340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki k256-0.13.3/benches/ecdsa.rs000064400000000000000000000037371046102023000134450ustar 00000000000000//! secp256k1 scalar arithmetic benchmarks use criterion::{black_box, criterion_group, criterion_main, Criterion}; use ecdsa_core::{ elliptic_curve::group::prime::PrimeCurveAffine, hazmat::{SignPrimitive, VerifyPrimitive}, }; use k256::{ elliptic_curve::{generic_array::arr, group::ff::PrimeField}, AffinePoint, FieldBytes, Scalar, }; fn test_scalar_d() -> Scalar { Scalar::from_repr(arr![u8; 0xbb, 0x48, 0x8a, 0xef, 0x41, 0x6a, 0x41, 0xd7, 0x68, 0x0d, 0x1c, 0xf0, 0x1d, 0x70, 0xf5, 0x9b, 0x60, 0xd7, 0xf5, 0xf7, 0x7e, 0x30, 0xe7, 0x8b, 0x8b, 0xf9, 0xd2, 0xd8, 0x82, 0xf1, 0x56, 0xa6, ]) .unwrap() } fn test_scalar_k() -> Scalar { Scalar::from_repr(arr![u8; 0x67, 0xe2, 0xf6, 0x80, 0x71, 0xed, 0x82, 0x81, 0xe8, 0xae, 0xd6, 0xbc, 0xf1, 0xc5, 0x20, 0x7c, 0x5e, 0x63, 0x37, 0x22, 0xd9, 0x20, 0xaf, 0xd6, 0xae, 0x22, 0xd0, 0x6e, 0xeb, 0x80, 0x35, 0xe3, ]) .unwrap() } fn test_scalar_z() -> FieldBytes { arr![u8; 0xe3, 0x35, 0x80, 0xeb, 0x6e, 0xd0, 0x22, 0xae, 0xd6, 0xaf, 0x20, 0xd9, 0x22, 0x37, 0x63, 0x5e, 0x7c, 0x20, 0xc5, 0xf1, 0xbc, 0xd6, 0xae, 0xe8, 0x81, 0x82, 0xed, 0x71, 0x80, 0xf6, 0xe2, 0x67 ] } fn bench_ecdsa(c: &mut Criterion) { let mut group = c.benchmark_group("ecdsa"); let d = test_scalar_d(); let k = test_scalar_k(); let z = test_scalar_z(); group.bench_function("try_sign_prehashed", |b| { b.iter(|| { black_box(d) .try_sign_prehashed(black_box(k), &black_box(z)) .unwrap() }) }); let q = (AffinePoint::generator() * d).to_affine(); let s = d.try_sign_prehashed(k, &z).unwrap().0; group.bench_function("verify_prehashed", |b| { b.iter(|| { black_box(q) .verify_prehashed(&black_box(z), &black_box(s)) .unwrap() }) }); group.finish(); } criterion_group!(benches, bench_ecdsa); criterion_main!(benches); k256-0.13.3/benches/field.rs000064400000000000000000000051571046102023000134470ustar 00000000000000//! secp256k1 field element benchmarks use criterion::{ black_box, criterion_group, criterion_main, measurement::Measurement, BenchmarkGroup, Criterion, }; use k256::FieldElement; fn test_field_element_x() -> FieldElement { FieldElement::from_bytes( &[ 0xbb, 0x48, 0x8a, 0xef, 0x41, 0x6a, 0x41, 0xd7, 0x68, 0x0d, 0x1c, 0xf0, 0x1d, 0x70, 0xf5, 0x9b, 0x60, 0xd7, 0xf5, 0xf7, 0x7e, 0x30, 0xe7, 0x8b, 0x8b, 0xf9, 0xd2, 0xd8, 0x82, 0xf1, 0x56, 0xa6, ] .into(), ) .unwrap() } fn test_field_element_y() -> FieldElement { FieldElement::from_bytes( &[ 0x67, 0xe2, 0xf6, 0x80, 0x71, 0xed, 0x82, 0x81, 0xe8, 0xae, 0xd6, 0xbc, 0xf1, 0xc5, 0x20, 0x7c, 0x5e, 0x63, 0x37, 0x22, 0xd9, 0x20, 0xaf, 0xd6, 0xae, 0x22, 0xd0, 0x6e, 0xeb, 0x80, 0x35, 0xe3, ] .into(), ) .unwrap() } fn bench_field_element_normalize_weak<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { let x = test_field_element_x(); group.bench_function("normalize_weak", |b| { b.iter(|| black_box(x).normalize_weak()) }); } fn bench_field_element_normalize<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { let x = test_field_element_x(); group.bench_function("normalize", |b| b.iter(|| black_box(x).normalize())); } fn bench_field_element_mul<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { let x = test_field_element_x(); let y = test_field_element_y(); group.bench_function("mul", |b| b.iter(|| &black_box(x) * &black_box(y))); } fn bench_field_element_square<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { let x = test_field_element_x(); group.bench_function("square", |b| b.iter(|| black_box(x).square())); } fn bench_field_element_sqrt<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { let x = test_field_element_x(); group.bench_function("sqrt", |b| b.iter(|| black_box(x).sqrt())); } fn bench_field_element_invert<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { let x = test_field_element_x(); group.bench_function("invert", |b| b.iter(|| black_box(x).invert())); } fn bench_field_element(c: &mut Criterion) { let mut group = c.benchmark_group("field element operations"); bench_field_element_normalize_weak(&mut group); bench_field_element_normalize(&mut group); bench_field_element_mul(&mut group); bench_field_element_square(&mut group); bench_field_element_invert(&mut group); bench_field_element_sqrt(&mut group); group.finish(); } criterion_group!(benches, bench_field_element); criterion_main!(benches); k256-0.13.3/benches/scalar.rs000064400000000000000000000075721046102023000136340ustar 00000000000000//! secp256k1 scalar arithmetic benchmarks use criterion::{ black_box, criterion_group, criterion_main, measurement::Measurement, BenchmarkGroup, Criterion, }; use hex_literal::hex; use k256::{ elliptic_curve::{ generic_array::arr, group::ff::PrimeField, ops::LinearCombination, ops::MulByGenerator, }, ProjectivePoint, Scalar, }; fn test_scalar_x() -> Scalar { Scalar::from_repr(arr![u8; 0xbb, 0x48, 0x8a, 0xef, 0x41, 0x6a, 0x41, 0xd7, 0x68, 0x0d, 0x1c, 0xf0, 0x1d, 0x70, 0xf5, 0x9b, 0x60, 0xd7, 0xf5, 0xf7, 0x7e, 0x30, 0xe7, 0x8b, 0x8b, 0xf9, 0xd2, 0xd8, 0x82, 0xf1, 0x56, 0xa6, ]) .unwrap() } fn test_scalar_y() -> Scalar { Scalar::from_repr(arr![u8; 0x67, 0xe2, 0xf6, 0x80, 0x71, 0xed, 0x82, 0x81, 0xe8, 0xae, 0xd6, 0xbc, 0xf1, 0xc5, 0x20, 0x7c, 0x5e, 0x63, 0x37, 0x22, 0xd9, 0x20, 0xaf, 0xd6, 0xae, 0x22, 0xd0, 0x6e, 0xeb, 0x80, 0x35, 0xe3, ]) .unwrap() } fn bench_point_mul<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { let p = ProjectivePoint::GENERATOR; let m = hex!("AA5E28D6A97A2479A65527F7290311A3624D4CC0FA1578598EE3C2613BF99522"); let s = Scalar::from_repr(m.into()).unwrap(); group.bench_function("point-scalar mul", |b| { b.iter(|| &black_box(p) * &black_box(s)) }); } fn bench_point_lincomb<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { let p = ProjectivePoint::GENERATOR; let m = hex!("AA5E28D6A97A2479A65527F7290311A3624D4CC0FA1578598EE3C2613BF99522"); let s = Scalar::from_repr(m.into()).unwrap(); group.bench_function("lincomb via mul+add", |b| { b.iter(|| &black_box(p) * &black_box(s) + &black_box(p) * &black_box(s)) }); group.bench_function("lincomb()", |b| { b.iter(|| { ProjectivePoint::lincomb(&black_box(p), &black_box(s), &black_box(p), &black_box(s)) }) }); } fn bench_point_mul_by_generator<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { let p = ProjectivePoint::GENERATOR; let x = test_scalar_x(); group.bench_function("mul_by_generator naive", |b| { b.iter(|| &black_box(p) * &black_box(x)) }); group.bench_function("mul_by_generator precomputed", |b| { b.iter(|| ProjectivePoint::mul_by_generator(&black_box(x))) }); } fn bench_high_level(c: &mut Criterion) { let mut group = c.benchmark_group("high-level operations"); bench_point_mul(&mut group); bench_point_mul_by_generator(&mut group); bench_point_lincomb(&mut group); group.finish(); } fn bench_scalar_sub<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { let x = test_scalar_x(); let y = test_scalar_y(); group.bench_function("sub", |b| b.iter(|| &black_box(x) - &black_box(y))); } fn bench_scalar_add<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { let x = test_scalar_x(); let y = test_scalar_y(); group.bench_function("add", |b| b.iter(|| &black_box(x) + &black_box(y))); } fn bench_scalar_mul<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { let x = test_scalar_x(); let y = test_scalar_y(); group.bench_function("mul", |b| b.iter(|| &black_box(x) * &black_box(y))); } fn bench_scalar_negate<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { let x = test_scalar_x(); group.bench_function("negate", |b| b.iter(|| -black_box(x))); } fn bench_scalar_invert<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { let x = test_scalar_x(); group.bench_function("invert", |b| b.iter(|| black_box(x).invert())); } fn bench_scalar(c: &mut Criterion) { let mut group = c.benchmark_group("scalar operations"); bench_scalar_sub(&mut group); bench_scalar_add(&mut group); bench_scalar_mul(&mut group); bench_scalar_negate(&mut group); bench_scalar_invert(&mut group); group.finish(); } criterion_group!(benches, bench_high_level, bench_scalar); criterion_main!(benches); k256-0.13.3/src/arithmetic/affine.rs000064400000000000000000000316021046102023000151170ustar 00000000000000//! Affine points #![allow(clippy::op_ref)] use super::{FieldElement, ProjectivePoint, CURVE_EQUATION_B}; use crate::{CompressedPoint, EncodedPoint, FieldBytes, PublicKey, Scalar, Secp256k1}; use core::ops::{Mul, Neg}; use elliptic_curve::{ group::{prime::PrimeCurveAffine, GroupEncoding}, point::{AffineCoordinates, DecompactPoint, DecompressPoint}, sec1::{self, FromEncodedPoint, ToEncodedPoint}, subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, zeroize::DefaultIsZeroes, Error, Result, }; #[cfg(feature = "serde")] use serdect::serde::{de, ser, Deserialize, Serialize}; /// secp256k1 curve point expressed in affine coordinates. /// /// # `serde` support /// /// When the `serde` feature of this crate is enabled, the `Serialize` and /// `Deserialize` traits are impl'd for this type. /// /// The serialization uses the [SEC1] `Elliptic-Curve-Point-to-Octet-String` /// encoding, serialized as binary. /// /// When serialized with a text-based format, the SEC1 representation is /// subsequently hex encoded. /// /// [SEC1]: https://www.secg.org/sec1-v2.pdf #[derive(Clone, Copy, Debug)] pub struct AffinePoint { /// x-coordinate pub(crate) x: FieldElement, /// y-coordinate pub(crate) y: FieldElement, /// Is this point the point at infinity? 0 = no, 1 = yes /// /// This is a proxy for [`Choice`], but uses `u8` instead to permit `const` /// constructors for `IDENTITY` and `GENERATOR`. pub(super) infinity: u8, } impl AffinePoint { /// Additive identity of the group: the point at infinity. pub const IDENTITY: Self = Self { x: FieldElement::ZERO, y: FieldElement::ZERO, infinity: 1, }; /// Base point of secp256k1. /// /// ```text /// Gₓ = 79be667e f9dcbbac 55a06295 ce870b07 029bfcdb 2dce28d9 59f2815b 16f81798 /// Gᵧ = 483ada77 26a3c465 5da4fbfc 0e1108a8 fd17b448 a6855419 9c47d08f fb10d4b8 /// ``` pub const GENERATOR: Self = Self { x: FieldElement::from_bytes_unchecked(&[ 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce, 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81, 0x5b, 0x16, 0xf8, 0x17, 0x98, ]), y: FieldElement::from_bytes_unchecked(&[ 0x48, 0x3a, 0xda, 0x77, 0x26, 0xa3, 0xc4, 0x65, 0x5d, 0xa4, 0xfb, 0xfc, 0x0e, 0x11, 0x08, 0xa8, 0xfd, 0x17, 0xb4, 0x48, 0xa6, 0x85, 0x54, 0x19, 0x9c, 0x47, 0xd0, 0x8f, 0xfb, 0x10, 0xd4, 0xb8, ]), infinity: 0, }; } impl AffinePoint { /// Create a new [`AffinePoint`] with the given coordinates. pub(crate) const fn new(x: FieldElement, y: FieldElement) -> Self { Self { x, y, infinity: 0 } } } impl PrimeCurveAffine for AffinePoint { type Scalar = Scalar; type Curve = ProjectivePoint; /// Returns the identity of the group: the point at infinity. fn identity() -> Self { Self::IDENTITY } /// Returns the base point of secp256k1. fn generator() -> Self { Self::GENERATOR } /// Is this point the identity point? fn is_identity(&self) -> Choice { Choice::from(self.infinity) } /// Convert to curve representation. fn to_curve(&self) -> ProjectivePoint { ProjectivePoint::from(*self) } } impl AffineCoordinates for AffinePoint { type FieldRepr = FieldBytes; fn x(&self) -> FieldBytes { self.x.to_bytes() } fn y_is_odd(&self) -> Choice { self.y.normalize().is_odd() } } impl ConditionallySelectable for AffinePoint { fn conditional_select(a: &AffinePoint, b: &AffinePoint, choice: Choice) -> AffinePoint { AffinePoint { x: FieldElement::conditional_select(&a.x, &b.x, choice), y: FieldElement::conditional_select(&a.y, &b.y, choice), infinity: u8::conditional_select(&a.infinity, &b.infinity, choice), } } } impl ConstantTimeEq for AffinePoint { fn ct_eq(&self, other: &AffinePoint) -> Choice { (self.x.negate(1) + &other.x).normalizes_to_zero() & (self.y.negate(1) + &other.y).normalizes_to_zero() & self.infinity.ct_eq(&other.infinity) } } impl Default for AffinePoint { fn default() -> Self { Self::IDENTITY } } impl DefaultIsZeroes for AffinePoint {} impl PartialEq for AffinePoint { fn eq(&self, other: &AffinePoint) -> bool { self.ct_eq(other).into() } } impl Eq for AffinePoint {} impl Mul for AffinePoint { type Output = ProjectivePoint; fn mul(self, scalar: Scalar) -> ProjectivePoint { ProjectivePoint::from(self) * scalar } } impl Mul<&Scalar> for AffinePoint { type Output = ProjectivePoint; fn mul(self, scalar: &Scalar) -> ProjectivePoint { ProjectivePoint::from(self) * scalar } } impl Neg for AffinePoint { type Output = AffinePoint; fn neg(self) -> Self::Output { AffinePoint { x: self.x, y: self.y.negate(1).normalize_weak(), infinity: self.infinity, } } } impl DecompressPoint for AffinePoint { fn decompress(x_bytes: &FieldBytes, y_is_odd: Choice) -> CtOption { FieldElement::from_bytes(x_bytes).and_then(|x| { let alpha = (x * &x * &x) + &CURVE_EQUATION_B; let beta = alpha.sqrt(); beta.map(|beta| { let beta = beta.normalize(); // Need to normalize for is_odd() to be consistent let y = FieldElement::conditional_select( &beta.negate(1), &beta, beta.is_odd().ct_eq(&y_is_odd), ); Self::new(x, y.normalize()) }) }) } } /// Decompaction using Taproot conventions as described in [BIP 340]. /// /// [BIP 340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki impl DecompactPoint for AffinePoint { fn decompact(x_bytes: &FieldBytes) -> CtOption { Self::decompress(x_bytes, Choice::from(0)) } } impl 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(|_| { // SEC1 identity encoding is technically 1-byte 0x00, but the // `GroupEncoding` API requires a fixed-width `Repr` let is_identity = bytes.ct_eq(&Self::Repr::default()); CtOption::new(EncodedPoint::identity(), is_identity) }) .and_then(|point| Self::from_encoded_point(&point)) } fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { // No unchecked conversion possible for compressed points Self::from_bytes(bytes) } fn to_bytes(&self) -> Self::Repr { let encoded = self.to_encoded_point(true); let mut result = CompressedPoint::default(); result[..encoded.len()].copy_from_slice(encoded.as_bytes()); result } } impl FromEncodedPoint for AffinePoint { /// Attempts to parse the given [`EncodedPoint`] as an SEC1-encoded [`AffinePoint`]. /// /// # Returns /// /// `None` value if `encoded_point` is not on the secp256k1 curve. fn from_encoded_point(encoded_point: &EncodedPoint) -> CtOption { match encoded_point.coordinates() { sec1::Coordinates::Identity => CtOption::new(Self::IDENTITY, 1.into()), sec1::Coordinates::Compact { x } => Self::decompact(x), sec1::Coordinates::Compressed { x, y_is_odd } => { AffinePoint::decompress(x, Choice::from(y_is_odd as u8)) } sec1::Coordinates::Uncompressed { x, y } => { let x = FieldElement::from_bytes(x); let y = FieldElement::from_bytes(y); x.and_then(|x| { y.and_then(|y| { // Check that the point is on the curve let lhs = (y * &y).negate(1); let rhs = x * &x * &x + &CURVE_EQUATION_B; let point = Self::new(x, y); CtOption::new(point, (lhs + &rhs).normalizes_to_zero()) }) }) } } } } impl ToEncodedPoint for AffinePoint { fn to_encoded_point(&self, compress: bool) -> EncodedPoint { EncodedPoint::conditional_select( &EncodedPoint::from_affine_coordinates( &self.x.to_bytes(), &self.y.to_bytes(), compress, ), &EncodedPoint::identity(), self.is_identity(), ) } } impl TryFrom for AffinePoint { type Error = Error; fn try_from(point: EncodedPoint) -> Result { AffinePoint::try_from(&point) } } impl TryFrom<&EncodedPoint> for AffinePoint { type Error = Error; fn try_from(point: &EncodedPoint) -> Result { Option::from(AffinePoint::from_encoded_point(point)).ok_or(Error) } } impl From for EncodedPoint { fn from(affine_point: AffinePoint) -> EncodedPoint { EncodedPoint::from(&affine_point) } } impl From<&AffinePoint> for EncodedPoint { fn from(affine_point: &AffinePoint) -> EncodedPoint { affine_point.to_encoded_point(true) } } impl From for AffinePoint { fn from(public_key: PublicKey) -> AffinePoint { *public_key.as_affine() } } impl From<&PublicKey> for AffinePoint { fn from(public_key: &PublicKey) -> AffinePoint { AffinePoint::from(*public_key) } } impl TryFrom for PublicKey { type Error = Error; fn try_from(affine_point: AffinePoint) -> Result { PublicKey::from_affine(affine_point) } } impl TryFrom<&AffinePoint> for PublicKey { type Error = Error; fn try_from(affine_point: &AffinePoint) -> Result { PublicKey::try_from(*affine_point) } } #[cfg(feature = "serde")] impl Serialize for AffinePoint { fn serialize(&self, serializer: S) -> core::result::Result where S: ser::Serializer, { self.to_encoded_point(true).serialize(serializer) } } #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for AffinePoint { fn deserialize(deserializer: D) -> core::result::Result where D: de::Deserializer<'de>, { EncodedPoint::deserialize(deserializer)? .try_into() .map_err(de::Error::custom) } } #[cfg(test)] mod tests { use super::AffinePoint; use crate::EncodedPoint; use elliptic_curve::{ group::{prime::PrimeCurveAffine, GroupEncoding}, sec1::{FromEncodedPoint, ToEncodedPoint}, }; use hex_literal::hex; const UNCOMPRESSED_BASEPOINT: &[u8] = &hex!( "0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8" ); const COMPRESSED_BASEPOINT: &[u8] = &hex!("0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"); #[test] fn uncompressed_round_trip() { let pubkey = EncodedPoint::from_bytes(UNCOMPRESSED_BASEPOINT).unwrap(); let res: EncodedPoint = AffinePoint::from_encoded_point(&pubkey) .unwrap() .to_encoded_point(false); assert_eq!(res, pubkey); } #[test] fn compressed_round_trip() { let pubkey = EncodedPoint::from_bytes(COMPRESSED_BASEPOINT).unwrap(); let res: EncodedPoint = AffinePoint::from_encoded_point(&pubkey) .unwrap() .to_encoded_point(true); assert_eq!(res, pubkey); } #[test] fn uncompressed_to_compressed() { let encoded = EncodedPoint::from_bytes(UNCOMPRESSED_BASEPOINT).unwrap(); let res = AffinePoint::from_encoded_point(&encoded) .unwrap() .to_encoded_point(true); assert_eq!(res.as_bytes(), COMPRESSED_BASEPOINT); } #[test] fn compressed_to_uncompressed() { let encoded = EncodedPoint::from_bytes(COMPRESSED_BASEPOINT).unwrap(); let res = AffinePoint::from_encoded_point(&encoded) .unwrap() .to_encoded_point(false); assert_eq!(res.as_bytes(), UNCOMPRESSED_BASEPOINT); } #[test] fn affine_negation() { let basepoint = AffinePoint::GENERATOR; assert_eq!((-(-basepoint)), basepoint); } #[test] fn identity_encoding() { // This is technically an invalid SEC1 encoding, but is preferable to panicking. assert_eq!([0; 33], AffinePoint::IDENTITY.to_bytes().as_slice()); assert!(bool::from( AffinePoint::from_bytes(&AffinePoint::IDENTITY.to_bytes()) .unwrap() .is_identity() )) } } k256-0.13.3/src/arithmetic/dev.rs000064400000000000000000000011761046102023000144500ustar 00000000000000//! Development helper functions. use num_bigint::{BigUint, ToBigUint}; use num_traits::cast::ToPrimitive; /// Converts a byte array (big-endian) to BigUint. pub fn bytes_to_biguint(bytes: &[u8; 32]) -> BigUint { bytes .iter() .enumerate() .map(|(i, w)| w.to_biguint().unwrap() << ((31 - i) * 8)) .sum() } /// Converts a BigUint to a byte array (big-endian). pub fn biguint_to_bytes(x: &BigUint) -> [u8; 32] { let mask = BigUint::from(u8::MAX); let mut bytes = [0u8; 32]; for i in 0..32 { bytes[i] = ((x >> ((31 - i) * 8)) as BigUint & &mask).to_u8().unwrap(); } bytes } k256-0.13.3/src/arithmetic/field/field_10x26.rs000064400000000000000000000755441046102023000167120ustar 00000000000000//! Field element modulo the curve internal modulus using 32-bit limbs. //! Inspired by the implementation in use crate::FieldBytes; use elliptic_curve::{ subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, zeroize::Zeroize, }; /// Scalars modulo SECP256k1 modulus (2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1). /// Uses 10 32-bit limbs (little-endian), where in the normalized form /// first 9 contain 26 bits of the value each, and the last one contains 22 bits. /// CurveArithmetic operations can be done without modulo reduction for some time, /// using the remaining overflow bits. #[derive(Clone, Copy, Debug)] pub struct FieldElement10x26(pub(crate) [u32; 10]); impl FieldElement10x26 { /// Zero element. pub const ZERO: Self = Self([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); /// Multiplicative identity. pub const ONE: Self = Self([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]); /// Attempts to parse the given byte array as an SEC1-encoded field element. /// Does not check the result for being in the correct range. pub(crate) const fn from_bytes_unchecked(bytes: &[u8; 32]) -> Self { let w0 = (bytes[31] as u32) | ((bytes[30] as u32) << 8) | ((bytes[29] as u32) << 16) | (((bytes[28] & 0x3) as u32) << 24); let w1 = (((bytes[28] >> 2) as u32) & 0x3f) | ((bytes[27] as u32) << 6) | ((bytes[26] as u32) << 14) | (((bytes[25] & 0xf) as u32) << 22); let w2 = (((bytes[25] >> 4) as u32) & 0xf) | ((bytes[24] as u32) << 4) | ((bytes[23] as u32) << 12) | (((bytes[22] & 0x3f) as u32) << 20); let w3 = (((bytes[22] >> 6) as u32) & 0x3) | ((bytes[21] as u32) << 2) | ((bytes[20] as u32) << 10) | ((bytes[19] as u32) << 18); let w4 = (bytes[18] as u32) | ((bytes[17] as u32) << 8) | ((bytes[16] as u32) << 16) | (((bytes[15] & 0x3) as u32) << 24); let w5 = (((bytes[15] >> 2) as u32) & 0x3f) | ((bytes[14] as u32) << 6) | ((bytes[13] as u32) << 14) | (((bytes[12] & 0xf) as u32) << 22); let w6 = (((bytes[12] >> 4) as u32) & 0xf) | ((bytes[11] as u32) << 4) | ((bytes[10] as u32) << 12) | (((bytes[9] & 0x3f) as u32) << 20); let w7 = (((bytes[9] >> 6) as u32) & 0x3) | ((bytes[8] as u32) << 2) | ((bytes[7] as u32) << 10) | ((bytes[6] as u32) << 18); let w8 = (bytes[5] as u32) | ((bytes[4] as u32) << 8) | ((bytes[3] as u32) << 16) | (((bytes[2] & 0x3) as u32) << 24); let w9 = (((bytes[2] >> 2) as u32) & 0x3f) | ((bytes[1] as u32) << 6) | ((bytes[0] as u32) << 14); Self([w0, w1, w2, w3, w4, w5, w6, w7, w8, w9]) } /// Attempts to parse the given byte array as an SEC1-encoded field element. /// /// Returns None if the byte array does not contain a big-endian integer in the range /// [0, p). pub fn from_bytes(bytes: &FieldBytes) -> CtOption { let res = Self::from_bytes_unchecked(bytes.as_ref()); let overflow = res.get_overflow(); CtOption::new(res, !overflow) } pub const fn from_u64(val: u64) -> Self { let w0 = (val as u32) & 0x3FFFFFF; let val = val >> 26; let w1 = (val as u32) & 0x3FFFFFF; let w2 = (val >> 26) as u32; Self([w0, w1, w2, 0, 0, 0, 0, 0, 0, 0]) } /// Returns the SEC1 encoding of this field element. pub fn to_bytes(self) -> FieldBytes { let mut r = FieldBytes::default(); r[0] = (self.0[9] >> 14) as u8; r[1] = (self.0[9] >> 6) as u8; r[2] = ((self.0[9] as u8 & 0x3Fu8) << 2) | ((self.0[8] >> 24) as u8 & 0x3); r[3] = (self.0[8] >> 16) as u8; r[4] = (self.0[8] >> 8) as u8; r[5] = self.0[8] as u8; r[6] = (self.0[7] >> 18) as u8; r[7] = (self.0[7] >> 10) as u8; r[8] = (self.0[7] >> 2) as u8; r[9] = ((self.0[7] as u8 & 0x3u8) << 6) | ((self.0[6] >> 20) as u8 & 0x3fu8); r[10] = (self.0[6] >> 12) as u8; r[11] = (self.0[6] >> 4) as u8; r[12] = ((self.0[6] as u8 & 0xfu8) << 4) | ((self.0[5] >> 22) as u8 & 0xfu8); r[13] = (self.0[5] >> 14) as u8; r[14] = (self.0[5] >> 6) as u8; r[15] = ((self.0[5] as u8 & 0x3fu8) << 2) | ((self.0[4] >> 24) as u8 & 0x3u8); r[16] = (self.0[4] >> 16) as u8; r[17] = (self.0[4] >> 8) as u8; r[18] = self.0[4] as u8; r[19] = (self.0[3] >> 18) as u8; r[20] = (self.0[3] >> 10) as u8; r[21] = (self.0[3] >> 2) as u8; r[22] = ((self.0[3] as u8 & 0x3u8) << 6) | ((self.0[2] >> 20) as u8 & 0x3fu8); r[23] = (self.0[2] >> 12) as u8; r[24] = (self.0[2] >> 4) as u8; r[25] = ((self.0[2] as u8 & 0xfu8) << 4) | ((self.0[1] >> 22) as u8 & 0xfu8); r[26] = (self.0[1] >> 14) as u8; r[27] = (self.0[1] >> 6) as u8; r[28] = ((self.0[1] as u8 & 0x3fu8) << 2) | ((self.0[0] >> 24) as u8 & 0x3u8); r[29] = (self.0[0] >> 16) as u8; r[30] = (self.0[0] >> 8) as u8; r[31] = self.0[0] as u8; r } /// Adds `x * (2^256 - modulus)`. fn add_modulus_correction(&self, x: u32) -> Self { // add (2^256 - modulus) * x to the first limb let t0 = self.0[0] + x * 0x3D1u32; // Propagate excess bits up the limbs let t1 = self.0[1] + (x << 6); // add `x` times the high bit of correction (2^32) let t1 = t1 + (t0 >> 26); let t0 = t0 & 0x3FFFFFFu32; let t2 = self.0[2] + (t1 >> 26); let t1 = t1 & 0x3FFFFFFu32; let t3 = self.0[3] + (t2 >> 26); let t2 = t2 & 0x3FFFFFFu32; let t4 = self.0[4] + (t3 >> 26); let t3 = t3 & 0x3FFFFFFu32; let t5 = self.0[5] + (t4 >> 26); let t4 = t4 & 0x3FFFFFFu32; let t6 = self.0[6] + (t5 >> 26); let t5 = t5 & 0x3FFFFFFu32; let t7 = self.0[7] + (t6 >> 26); let t6 = t6 & 0x3FFFFFFu32; let t8 = self.0[8] + (t7 >> 26); let t7 = t7 & 0x3FFFFFFu32; let t9 = self.0[9] + (t8 >> 26); let t8 = t8 & 0x3FFFFFFu32; Self([t0, t1, t2, t3, t4, t5, t6, t7, t8, t9]) } /// Subtracts the overflow in the last limb and return it with the new field element. /// Equivalent to subtracting a multiple of 2^256. fn subtract_modulus_approximation(&self) -> (Self, u32) { let x = self.0[9] >> 22; let t9 = self.0[9] & 0x03FFFFFu32; // equivalent to self -= 2^256 * x ( Self([ self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], self.0[7], self.0[8], t9, ]), x, ) } /// Checks if the field element is greater or equal to the modulus. fn get_overflow(&self) -> Choice { let m = self.0[2] & self.0[3] & self.0[4] & self.0[5] & self.0[6] & self.0[7] & self.0[8]; let x = (self.0[9] >> 22 != 0) | ((self.0[9] == 0x3FFFFFu32) & (m == 0x3FFFFFFu32) & ((self.0[1] + 0x40u32 + ((self.0[0] + 0x3D1u32) >> 26)) > 0x3FFFFFFu32)); Choice::from(x as u8) } /// Brings the field element's magnitude to 1, but does not necessarily normalize it. pub fn normalize_weak(&self) -> Self { // Reduce t9 at the start so there will be at most a single carry from the first pass let (t, x) = self.subtract_modulus_approximation(); // The first pass ensures the magnitude is 1, ... let res = t.add_modulus_correction(x); // ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) debug_assert!(res.0[9] >> 23 == 0); res } /// Fully normalizes the field element. /// That is, first nine limbs are at most 26 bit large, the last limb is at most 22 bit large, /// and the value is less than the modulus. pub fn normalize(&self) -> Self { let res = self.normalize_weak(); // At most a single final reduction is needed; // check if the value is >= the field characteristic let overflow = res.get_overflow(); // Apply the final reduction (for constant-time behaviour, we do it always) let res_corrected = res.add_modulus_correction(1u32); // Mask off the possible multiple of 2^256 from the final reduction let (res_corrected, x) = res_corrected.subtract_modulus_approximation(); // If the last limb didn't carry to bit 23 already, // then it should have after any final reduction debug_assert!(x == (overflow.unwrap_u8() as u32)); Self::conditional_select(&res, &res_corrected, overflow) } /// Checks if the field element becomes zero if normalized. pub fn normalizes_to_zero(&self) -> Choice { let res = self.normalize_weak(); let t0 = res.0[0]; let t1 = res.0[1]; let t2 = res.0[2]; let t3 = res.0[3]; let t4 = res.0[4]; let t5 = res.0[5]; let t6 = res.0[6]; let t7 = res.0[7]; let t8 = res.0[8]; let t9 = res.0[9]; // z0 tracks a possible raw value of 0, z1 tracks a possible raw value of the modulus let z0 = t0 | t1 | t2 | t3 | t4 | t5 | t6 | t7 | t8 | t9; let z1 = (t0 ^ 0x3D0u32) & (t1 ^ 0x40u32) & t2 & t3 & t4 & t5 & t6 & t7 & t8 & (t9 ^ 0x3C00000u32); Choice::from(((z0 == 0) | (z1 == 0x3FFFFFFu32)) as u8) } /// Determine if this `FieldElement10x26` is zero. /// /// # Returns /// /// If zero, return `Choice(1)`. Otherwise, return `Choice(0)`. pub fn is_zero(&self) -> Choice { Choice::from( ((self.0[0] | self.0[1] | self.0[2] | self.0[3] | self.0[4] | self.0[5] | self.0[6] | self.0[7] | self.0[8] | self.0[9]) == 0) as u8, ) } /// Determine if this `FieldElement10x26` is odd in the SEC1 sense: `self mod 2 == 1`. /// /// # Returns /// /// If odd, return `Choice(1)`. Otherwise, return `Choice(0)`. pub fn is_odd(&self) -> Choice { (self.0[0] as u8 & 1).into() } // The maximum number `m` for which `0x3FFFFFF * 2 * (m + 1) < 2^32` #[cfg(debug_assertions)] pub const fn max_magnitude() -> u32 { 31u32 } /// Returns -self, treating it as a value of given magnitude. /// The provided magnitude must be equal or greater than the actual magnitude of `self`. pub const fn negate(&self, magnitude: u32) -> Self { let m: u32 = magnitude + 1; let r0 = 0x3FFFC2Fu32 * 2 * m - self.0[0]; let r1 = 0x3FFFFBFu32 * 2 * m - self.0[1]; let r2 = 0x3FFFFFFu32 * 2 * m - self.0[2]; let r3 = 0x3FFFFFFu32 * 2 * m - self.0[3]; let r4 = 0x3FFFFFFu32 * 2 * m - self.0[4]; let r5 = 0x3FFFFFFu32 * 2 * m - self.0[5]; let r6 = 0x3FFFFFFu32 * 2 * m - self.0[6]; let r7 = 0x3FFFFFFu32 * 2 * m - self.0[7]; let r8 = 0x3FFFFFFu32 * 2 * m - self.0[8]; let r9 = 0x03FFFFFu32 * 2 * m - self.0[9]; Self([r0, r1, r2, r3, r4, r5, r6, r7, r8, r9]) } /// Returns self + rhs mod p. /// Sums the magnitudes. pub const fn add(&self, rhs: &Self) -> Self { Self([ self.0[0] + rhs.0[0], self.0[1] + rhs.0[1], self.0[2] + rhs.0[2], self.0[3] + rhs.0[3], self.0[4] + rhs.0[4], self.0[5] + rhs.0[5], self.0[6] + rhs.0[6], self.0[7] + rhs.0[7], self.0[8] + rhs.0[8], self.0[9] + rhs.0[9], ]) } /// Multiplies by a single-limb integer. /// Multiplies the magnitude by the same value. pub const fn mul_single(&self, rhs: u32) -> Self { Self([ self.0[0] * rhs, self.0[1] * rhs, self.0[2] * rhs, self.0[3] * rhs, self.0[4] * rhs, self.0[5] * rhs, self.0[6] * rhs, self.0[7] * rhs, self.0[8] * rhs, self.0[9] * rhs, ]) } #[inline(always)] fn mul_inner(&self, rhs: &Self) -> Self { /* `square()` is just `mul()` with equal arguments. Rust compiler is smart enough to do all the necessary optimizations for this case, but it needs to have this information inside a function. If a function is just *called* with the same arguments, this information cannot be used, so the function must be inlined while using the same arguments. Now `mul()` is quite long and therefore expensive to inline. So we have an inner (inlined) function, that is used inside `mul()` and `square()`, and when it is used with the same arguments in `square()`, compiler is able to use that fact after inlining. */ let m = 0x3FFFFFFu64; let rr0 = 0x3D10u64; let rr1 = 0x400u64; let a0 = self.0[0] as u64; let a1 = self.0[1] as u64; let a2 = self.0[2] as u64; let a3 = self.0[3] as u64; let a4 = self.0[4] as u64; let a5 = self.0[5] as u64; let a6 = self.0[6] as u64; let a7 = self.0[7] as u64; let a8 = self.0[8] as u64; let a9 = self.0[9] as u64; let b0 = rhs.0[0] as u64; let b1 = rhs.0[1] as u64; let b2 = rhs.0[2] as u64; let b3 = rhs.0[3] as u64; let b4 = rhs.0[4] as u64; let b5 = rhs.0[5] as u64; let b6 = rhs.0[6] as u64; let b7 = rhs.0[7] as u64; let b8 = rhs.0[8] as u64; let b9 = rhs.0[9] as u64; // [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n. // for 0 <= x <= 9, px is a shorthand for sum(a[i]*b[x-i], i=0..x). // for 9 <= x <= 18, px is a shorthand for sum(a[i]*b[x-i], i=(x-9)..9) // Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*rr1 x*rr0]. let mut c: u64; let mut d: u64; d = a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0; // [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] let t9 = (d & m) as u32; d >>= 26; debug_assert!(t9 >> 26 == 0); debug_assert!(d >> 38 == 0); // [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] c = a0 * b0; debug_assert!(c >> 60 == 0); // [d t9 0 0 0 0 0 0 0 0 c] = [p9 0 0 0 0 0 0 0 0 p0] d += a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1; debug_assert!(d >> 63 == 0); // [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] let u0 = (d & m) as u32; d >>= 26; c += u0 as u64 * rr0; debug_assert!(u0 >> 26 == 0); debug_assert!(d >> 37 == 0); debug_assert!(c >> 61 == 0); // [d u0 t9 0 0 0 0 0 0 0 0 c-u0*rr0] = [p10 p9 0 0 0 0 0 0 0 0 p0] let t0 = (c & m) as u32; c >>= 26; c += u0 as u64 * rr1; debug_assert!(t0 >> 26 == 0); debug_assert!(c >> 37 == 0); // [d u0 t9 0 0 0 0 0 0 0 c-u0*rr1 t0-u0*rr0] = [p10 p9 0 0 0 0 0 0 0 0 p0] // [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 0 p0] c += a0 * b1 + a1 * b0; debug_assert!(c >> 62 == 0); // [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 p1 p0] d += a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 + a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2; debug_assert!(d >> 63 == 0); // [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] let u1 = (d & m) as u32; d >>= 26; c += u1 as u64 * rr0; debug_assert!(u1 >> 26 == 0); debug_assert!(d >> 37 == 0); debug_assert!(c >> 63 == 0); // [d u1 0 t9 0 0 0 0 0 0 0 c-u1*rr0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] let t1 = (c & m) as u32; c >>= 26; c += u1 as u64 * rr1; debug_assert!(t1 >> 26 == 0); debug_assert!(c >> 38 == 0); // [d u1 0 t9 0 0 0 0 0 0 c-u1*rr1 t1-u1*rr0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] // [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] c += a0 * b2 + a1 * b1 + a2 * b0; debug_assert!(c >> 62 == 0); // [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] d += a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + a7 * b5 + a8 * b4 + a9 * b3; debug_assert!(d >> 63 == 0); // [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] let u2 = (d & m) as u32; d >>= 26; c += u2 as u64 * rr0; debug_assert!(u2 >> 26 == 0); debug_assert!(d >> 37 == 0); debug_assert!(c >> 63 == 0); // [d u2 0 0 t9 0 0 0 0 0 0 c-u2*rr0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] let t2 = (c & m) as u32; c >>= 26; c += u2 as u64 * rr1; debug_assert!(t2 >> 26 == 0); debug_assert!(c >> 38 == 0); // [d u2 0 0 t9 0 0 0 0 0 c-u2*rr1 t2-u2*rr0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] // [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] c += a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0; debug_assert!(c >> 63 == 0); // [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] d += a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + a8 * b5 + a9 * b4; debug_assert!(d >> 63 == 0); // [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] let u3 = (d & m) as u32; d >>= 26; c += u3 as u64 * rr0; debug_assert!(u3 >> 26 == 0); debug_assert!(d >> 37 == 0); // [d u3 0 0 0 t9 0 0 0 0 0 c-u3*rr0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] let t3 = (c & m) as u32; c >>= 26; c += u3 as u64 * rr1; debug_assert!(t3 >> 26 == 0); debug_assert!(c >> 39 == 0); // [d u3 0 0 0 t9 0 0 0 0 c-u3*rr1 t3-u3*rr0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] // [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] c += a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0; debug_assert!(c >> 63 == 0); // [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] d += a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + a9 * b5; debug_assert!(d >> 62 == 0); // [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] let u4 = (d & m) as u32; d >>= 26; c += u4 as u64 * rr0; debug_assert!(u4 >> 26 == 0); debug_assert!(d >> 36 == 0); // [d u4 0 0 0 0 t9 0 0 0 0 c-u4*rr0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] let t4 = (c & m) as u32; c >>= 26; c += u4 as u64 * rr1; debug_assert!(t4 >> 26 == 0); debug_assert!(c >> 39 == 0); // [d u4 0 0 0 0 t9 0 0 0 c-u4*rr1 t4-u4*rr0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] // [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] c += a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0; debug_assert!(c >> 63 == 0); // [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] d += a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6; debug_assert!(d >> 62 == 0); // [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] let u5 = (d & m) as u32; d >>= 26; c += u5 as u64 * rr0; debug_assert!(u5 >> 26 == 0); debug_assert!(d >> 36 == 0); // [d u5 0 0 0 0 0 t9 0 0 0 c-u5*rr0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] let t5 = (c & m) as u32; c >>= 26; c += u5 as u64 * rr1; debug_assert!(t5 >> 26 == 0); debug_assert!(c >> 39 == 0); // [d u5 0 0 0 0 0 t9 0 0 c-u5*rr1 t5-u5*rr0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] // [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] c += a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0; debug_assert!(c >> 63 == 0); // [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] d += a7 * b9 + a8 * b8 + a9 * b7; debug_assert!(d >> 61 == 0); // [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] let u6 = (d & m) as u32; d >>= 26; c += u6 as u64 * rr0; debug_assert!(u6 >> 26 == 0); debug_assert!(d >> 35 == 0); // [d u6 0 0 0 0 0 0 t9 0 0 c-u6*rr0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] let t6 = (c & m) as u32; c >>= 26; c += u6 as u64 * rr1; debug_assert!(t6 >> 26 == 0); debug_assert!(c >> 39 == 0); // [d u6 0 0 0 0 0 0 t9 0 c-u6*rr1 t6-u6*rr0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] // [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] c += a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1 + a7 * b0; debug_assert!(c <= 0x8000007C00000007u64); // [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] d += a8 * b9 + a9 * b8; debug_assert!(d >> 58 == 0); // [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] let u7 = (d & m) as u32; d >>= 26; c += u7 as u64 * rr0; debug_assert!(u7 >> 26 == 0); debug_assert!(d >> 32 == 0); let d32 = d as u32; debug_assert!(c <= 0x800001703FFFC2F7u64); // [d u7 0 0 0 0 0 0 0 t9 0 c-u7*rr0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] let t7 = (c & m) as u32; c >>= 26; c += u7 as u64 * rr1; debug_assert!(t7 >> 26 == 0); debug_assert!(c >> 38 == 0); // [d u7 0 0 0 0 0 0 0 t9 c-u7*rr1 t7-u7*rr0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] // [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] c += a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1 + a8 * b0; debug_assert!(c <= 0x9000007B80000008u64); // [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] d = d32 as u64 + a9 * b9; debug_assert!(d >> 57 == 0); // [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] let u8 = (d & m) as u32; d >>= 26; c += u8 as u64 * rr0; debug_assert!(u8 >> 26 == 0); debug_assert!(d >> 31 == 0); let d32 = d as u32; debug_assert!(c <= 0x9000016FBFFFC2F8u64); // [d u8 0 0 0 0 0 0 0 0 t9 c-u8*rr0 t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] let r3 = t3; debug_assert!(r3 >> 26 == 0); // [d u8 0 0 0 0 0 0 0 0 t9 c-u8*rr0 t7 t6 t5 t4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] let r4 = t4; debug_assert!(r4 >> 26 == 0); // [d u8 0 0 0 0 0 0 0 0 t9 c-u8*rr0 t7 t6 t5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] let r5 = t5; debug_assert!(r5 >> 26 == 0); // [d u8 0 0 0 0 0 0 0 0 t9 c-u8*rr0 t7 t6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] let r6 = t6; debug_assert!(r6 >> 26 == 0); // [d u8 0 0 0 0 0 0 0 0 t9 c-u8*rr0 t7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] let r7 = t7; debug_assert!(r7 >> 26 == 0); // [d u8 0 0 0 0 0 0 0 0 t9 c-u8*rr0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] let r8 = (c & m) as u32; c >>= 26; c += u8 as u64 * rr1; debug_assert!(r8 >> 26 == 0); debug_assert!(c >> 39 == 0); // [d u8 0 0 0 0 0 0 0 0 t9+c-u8*rr1 r8-u8*rr0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] // [d 0 0 0 0 0 0 0 0 0 t9+c r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] c += d32 as u64 * rr0 + t9 as u64; debug_assert!(c >> 45 == 0); // [d 0 0 0 0 0 0 0 0 0 c-d*rr0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] let r9 = (c & (m >> 4)) as u32; c >>= 22; c += d * (rr1 << 4); debug_assert!(r9 >> 22 == 0); debug_assert!(c >> 46 == 0); // [d 0 0 0 0 0 0 0 0 r9+((c-d*rr1<<4)<<22)-d*rr0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] // [d 0 0 0 0 0 0 0 -d*rr1 r9+(c<<22)-d*rr0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] // [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] d = c * (rr0 >> 4) + t0 as u64; debug_assert!(d >> 56 == 0); // [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 d-c*rr0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] let r0 = (d & m) as u32; d >>= 26; debug_assert!(r0 >> 26 == 0); debug_assert!(d >> 30 == 0); let d32 = d as u32; // [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1+d r0-c*rr0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] d = d32 as u64 + c * (rr1 >> 4) + t1 as u64; debug_assert!(d >> 53 == 0); debug_assert!(d <= 0x10000003FFFFBFu64); // [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 d-c*rr1>>4 r0-c*rr0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] // [r9 r8 r7 r6 r5 r4 r3 t2 d r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] let r1 = (d & m) as u32; d >>= 26; debug_assert!(r1 >> 26 == 0); debug_assert!(d >> 27 == 0); let d32 = d as u32; debug_assert!(d <= 0x4000000u64); // [r9 r8 r7 r6 r5 r4 r3 t2+d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] d = d32 as u64 + t2 as u64; debug_assert!(d >> 27 == 0); // [r9 r8 r7 r6 r5 r4 r3 d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] let r2 = d as u32; debug_assert!(r2 >> 27 == 0); // [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] Self([r0, r1, r2, r3, r4, r5, r6, r7, r8, r9]) } /// Returns self * rhs mod p /// Brings the magnitude to 1 (but doesn't normalize the result). /// The magnitudes of arguments should be <= 8. pub fn mul(&self, rhs: &Self) -> Self { self.mul_inner(rhs) } /// Returns self * self /// Brings the magnitude to 1 (but doesn't normalize the result). /// The magnitudes of arguments should be <= 8. pub fn square(&self) -> Self { self.mul_inner(self) } } impl Default for FieldElement10x26 { fn default() -> Self { Self::ZERO } } impl ConditionallySelectable for FieldElement10x26 { #[inline(always)] fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Self([ u32::conditional_select(&a.0[0], &b.0[0], choice), u32::conditional_select(&a.0[1], &b.0[1], choice), u32::conditional_select(&a.0[2], &b.0[2], choice), u32::conditional_select(&a.0[3], &b.0[3], choice), u32::conditional_select(&a.0[4], &b.0[4], choice), u32::conditional_select(&a.0[5], &b.0[5], choice), u32::conditional_select(&a.0[6], &b.0[6], choice), u32::conditional_select(&a.0[7], &b.0[7], choice), u32::conditional_select(&a.0[8], &b.0[8], choice), u32::conditional_select(&a.0[9], &b.0[9], choice), ]) } } impl ConstantTimeEq for FieldElement10x26 { fn ct_eq(&self, other: &Self) -> Choice { self.0[0].ct_eq(&other.0[0]) & self.0[1].ct_eq(&other.0[1]) & self.0[2].ct_eq(&other.0[2]) & self.0[3].ct_eq(&other.0[3]) & self.0[4].ct_eq(&other.0[4]) & self.0[5].ct_eq(&other.0[5]) & self.0[6].ct_eq(&other.0[6]) & self.0[7].ct_eq(&other.0[7]) & self.0[8].ct_eq(&other.0[8]) & self.0[9].ct_eq(&other.0[9]) } } impl Zeroize for FieldElement10x26 { fn zeroize(&mut self) { self.0.zeroize(); } } #[cfg(test)] mod tests { use super::FieldElement10x26; #[test] fn overflow_check_after_weak_normalize() { // A regression test for a missing condition in `get_overflow()`. // // In `normalize()`, after the `normalize_weak()` call, // the excess bit from the limb 0 is propagated all the way to the last limb. // This constitutes an overflow, since the last bit becomes equal to (1 << 22), // that is 23 bits in total. // When `get_overflow()` is called afterwards, this was not detected, // since the corresponding condition (checking for the last limb being > 22 bits) // was missing. // This resulted in a debug assert firing later. // // This is essentially 2^256 let z = FieldElement10x26([ (1 << 26), // an excess bit here // the remaining full-sized limbs are at top normalized capacity (1 << 26) - 1, (1 << 26) - 1, (1 << 26) - 1, (1 << 26) - 1, (1 << 26) - 1, (1 << 26) - 1, (1 << 26) - 1, (1 << 26) - 1, // the last limb is also at top normalized capacity (1 << 22) - 1, ]); // Used to fail here (debug_assert firing because overflow happened at an unexpected place): let z_normalized = z.normalize(); // Properly normalized result, just to be sure // The initial number is 2^256, so the result is 0x1000003d1 let z_reference = FieldElement10x26([0x3d1, 0x40, 0, 0, 0, 0, 0, 0, 0, 0]); assert_eq!(z_normalized.0, z_reference.0); } } k256-0.13.3/src/arithmetic/field/field_5x52.rs000064400000000000000000000470321046102023000166240ustar 00000000000000//! Field element modulo the curve internal modulus using 64-bit limbs. //! Inspired by the implementation in use crate::FieldBytes; use elliptic_curve::{ subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, zeroize::Zeroize, }; /// Scalars modulo SECP256k1 modulus (2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1). /// Uses 5 64-bit limbs (little-endian), where in the normalized form /// first 4 contain 52 bits of the value each, and the last one contains 48 bits. /// CurveArithmetic operations can be done without modulo reduction for some time, /// using the remaining overflow bits. #[derive(Clone, Copy, Debug)] pub struct FieldElement5x52(pub(crate) [u64; 5]); impl FieldElement5x52 { /// Zero element. pub const ZERO: Self = Self([0, 0, 0, 0, 0]); /// Multiplicative identity. pub const ONE: Self = Self([1, 0, 0, 0, 0]); /// Attempts to parse the given byte array as an SEC1-encoded field element. /// Does not check the result for being in the correct range. pub(crate) const fn from_bytes_unchecked(bytes: &[u8; 32]) -> Self { let w0 = (bytes[31] as u64) | ((bytes[30] as u64) << 8) | ((bytes[29] as u64) << 16) | ((bytes[28] as u64) << 24) | ((bytes[27] as u64) << 32) | ((bytes[26] as u64) << 40) | (((bytes[25] & 0xFu8) as u64) << 48); let w1 = ((bytes[25] >> 4) as u64) | ((bytes[24] as u64) << 4) | ((bytes[23] as u64) << 12) | ((bytes[22] as u64) << 20) | ((bytes[21] as u64) << 28) | ((bytes[20] as u64) << 36) | ((bytes[19] as u64) << 44); let w2 = (bytes[18] as u64) | ((bytes[17] as u64) << 8) | ((bytes[16] as u64) << 16) | ((bytes[15] as u64) << 24) | ((bytes[14] as u64) << 32) | ((bytes[13] as u64) << 40) | (((bytes[12] & 0xFu8) as u64) << 48); let w3 = ((bytes[12] >> 4) as u64) | ((bytes[11] as u64) << 4) | ((bytes[10] as u64) << 12) | ((bytes[9] as u64) << 20) | ((bytes[8] as u64) << 28) | ((bytes[7] as u64) << 36) | ((bytes[6] as u64) << 44); let w4 = (bytes[5] as u64) | ((bytes[4] as u64) << 8) | ((bytes[3] as u64) << 16) | ((bytes[2] as u64) << 24) | ((bytes[1] as u64) << 32) | ((bytes[0] as u64) << 40); Self([w0, w1, w2, w3, w4]) } /// Attempts to parse the given byte array as an SEC1-encoded field element. /// /// Returns None if the byte array does not contain a big-endian integer in the range /// [0, p). #[inline] pub fn from_bytes(bytes: &FieldBytes) -> CtOption { let res = Self::from_bytes_unchecked(bytes.as_ref()); let overflow = res.get_overflow(); CtOption::new(res, !overflow) } pub const fn from_u64(val: u64) -> Self { let w0 = val & 0xFFFFFFFFFFFFF; let w1 = val >> 52; Self([w0, w1, 0, 0, 0]) } /// Returns the SEC1 encoding of this field element. pub fn to_bytes(self) -> FieldBytes { let mut ret = FieldBytes::default(); ret[0] = (self.0[4] >> 40) as u8; ret[1] = (self.0[4] >> 32) as u8; ret[2] = (self.0[4] >> 24) as u8; ret[3] = (self.0[4] >> 16) as u8; ret[4] = (self.0[4] >> 8) as u8; ret[5] = self.0[4] as u8; ret[6] = (self.0[3] >> 44) as u8; ret[7] = (self.0[3] >> 36) as u8; ret[8] = (self.0[3] >> 28) as u8; ret[9] = (self.0[3] >> 20) as u8; ret[10] = (self.0[3] >> 12) as u8; ret[11] = (self.0[3] >> 4) as u8; ret[12] = ((self.0[2] >> 48) as u8 & 0xFu8) | ((self.0[3] as u8 & 0xFu8) << 4); ret[13] = (self.0[2] >> 40) as u8; ret[14] = (self.0[2] >> 32) as u8; ret[15] = (self.0[2] >> 24) as u8; ret[16] = (self.0[2] >> 16) as u8; ret[17] = (self.0[2] >> 8) as u8; ret[18] = self.0[2] as u8; ret[19] = (self.0[1] >> 44) as u8; ret[20] = (self.0[1] >> 36) as u8; ret[21] = (self.0[1] >> 28) as u8; ret[22] = (self.0[1] >> 20) as u8; ret[23] = (self.0[1] >> 12) as u8; ret[24] = (self.0[1] >> 4) as u8; ret[25] = ((self.0[0] >> 48) as u8 & 0xFu8) | ((self.0[1] as u8 & 0xFu8) << 4); ret[26] = (self.0[0] >> 40) as u8; ret[27] = (self.0[0] >> 32) as u8; ret[28] = (self.0[0] >> 24) as u8; ret[29] = (self.0[0] >> 16) as u8; ret[30] = (self.0[0] >> 8) as u8; ret[31] = self.0[0] as u8; ret } /// Adds `x * (2^256 - modulus)`. fn add_modulus_correction(&self, x: u64) -> Self { // add (2^256 - modulus) * x to the first limb let t0 = self.0[0] + x * 0x1000003D1u64; // Propagate excess bits up the limbs let t1 = self.0[1] + (t0 >> 52); let t0 = t0 & 0xFFFFFFFFFFFFFu64; let t2 = self.0[2] + (t1 >> 52); let t1 = t1 & 0xFFFFFFFFFFFFFu64; let t3 = self.0[3] + (t2 >> 52); let t2 = t2 & 0xFFFFFFFFFFFFFu64; let t4 = self.0[4] + (t3 >> 52); let t3 = t3 & 0xFFFFFFFFFFFFFu64; Self([t0, t1, t2, t3, t4]) } /// Subtracts the overflow in the last limb and return it with the new field element. /// Equivalent to subtracting a multiple of 2^256. fn subtract_modulus_approximation(&self) -> (Self, u64) { let x = self.0[4] >> 48; let t4 = self.0[4] & 0x0FFFFFFFFFFFFu64; // equivalent to self -= 2^256 * x (Self([self.0[0], self.0[1], self.0[2], self.0[3], t4]), x) } /// Checks if the field element is greater or equal to the modulus. fn get_overflow(&self) -> Choice { let m = self.0[1] & self.0[2] & self.0[3]; let x = (self.0[4] >> 48 != 0) | ((self.0[4] == 0x0FFFFFFFFFFFFu64) & (m == 0xFFFFFFFFFFFFFu64) & (self.0[0] >= 0xFFFFEFFFFFC2Fu64)); Choice::from(x as u8) } /// Brings the field element's magnitude to 1, but does not necessarily normalize it. pub fn normalize_weak(&self) -> Self { // Reduce t4 at the start so there will be at most a single carry from the first pass let (t, x) = self.subtract_modulus_approximation(); // The first pass ensures the magnitude is 1, ... let res = t.add_modulus_correction(x); // ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) debug_assert!(res.0[4] >> 49 == 0); res } /// Fully normalizes the field element. /// That is, first four limbs are at most 52 bit large, the last limb is at most 48 bit large, /// and the value is less than the modulus. pub fn normalize(&self) -> Self { let res = self.normalize_weak(); // At most a single final reduction is needed; // check if the value is >= the field characteristic let overflow = res.get_overflow(); // Apply the final reduction (for constant-time behaviour, we do it always) let res_corrected = res.add_modulus_correction(1u64); // Mask off the possible multiple of 2^256 from the final reduction let (res_corrected, x) = res_corrected.subtract_modulus_approximation(); // If the last limb didn't carry to bit 48 already, // then it should have after any final reduction debug_assert!(x == (overflow.unwrap_u8() as u64)); Self::conditional_select(&res, &res_corrected, overflow) } /// Checks if the field element becomes zero if normalized. pub fn normalizes_to_zero(&self) -> Choice { let res = self.normalize_weak(); let t0 = res.0[0]; let t1 = res.0[1]; let t2 = res.0[2]; let t3 = res.0[3]; let t4 = res.0[4]; // z0 tracks a possible raw value of 0, z1 tracks a possible raw value of the modulus let z0 = t0 | t1 | t2 | t3 | t4; let z1 = (t0 ^ 0x1000003D0u64) & t1 & t2 & t3 & (t4 ^ 0xF000000000000u64); Choice::from(((z0 == 0) | (z1 == 0xFFFFFFFFFFFFFu64)) as u8) } /// Determine if this `FieldElement5x52` is zero. /// /// # Returns /// /// If zero, return `Choice(1)`. Otherwise, return `Choice(0)`. pub fn is_zero(&self) -> Choice { Choice::from(((self.0[0] | self.0[1] | self.0[2] | self.0[3] | self.0[4]) == 0) as u8) } /// Determine if this `FieldElement5x52` is odd in the SEC1 sense: `self mod 2 == 1`. /// /// # Returns /// /// If odd, return `Choice(1)`. Otherwise, return `Choice(0)`. pub fn is_odd(&self) -> Choice { (self.0[0] as u8 & 1).into() } /// The maximum number `m` for which `0xFFFFFFFFFFFFF * 2 * (m + 1) < 2^64` #[cfg(debug_assertions)] pub const fn max_magnitude() -> u32 { 2047u32 } /// Returns -self, treating it as a value of given magnitude. /// The provided magnitude must be equal or greater than the actual magnitude of `self`. /// Raises the magnitude by 1. pub const fn negate(&self, magnitude: u32) -> Self { let m = (magnitude + 1) as u64; let r0 = 0xFFFFEFFFFFC2Fu64 * 2 * m - self.0[0]; let r1 = 0xFFFFFFFFFFFFFu64 * 2 * m - self.0[1]; let r2 = 0xFFFFFFFFFFFFFu64 * 2 * m - self.0[2]; let r3 = 0xFFFFFFFFFFFFFu64 * 2 * m - self.0[3]; let r4 = 0x0FFFFFFFFFFFFu64 * 2 * m - self.0[4]; Self([r0, r1, r2, r3, r4]) } /// Returns self + rhs mod p. /// Sums the magnitudes. pub const fn add(&self, rhs: &Self) -> Self { Self([ self.0[0] + rhs.0[0], self.0[1] + rhs.0[1], self.0[2] + rhs.0[2], self.0[3] + rhs.0[3], self.0[4] + rhs.0[4], ]) } /// Multiplies by a single-limb integer. /// Multiplies the magnitude by the same value. pub const fn mul_single(&self, rhs: u32) -> Self { let rhs_u64 = rhs as u64; Self([ self.0[0] * rhs_u64, self.0[1] * rhs_u64, self.0[2] * rhs_u64, self.0[3] * rhs_u64, self.0[4] * rhs_u64, ]) } #[inline(always)] fn mul_inner(&self, rhs: &Self) -> Self { /* `square()` is just `mul()` with equal arguments. Rust compiler is smart enough to do all the necessary optimizations for this case, but it needs to have this information inside a function. If a function is just *called* with the same arguments, this information cannot be used, so the function must be inlined while using the same arguments. Now `mul()` is quite long and therefore expensive to inline. So we have an inner (inlined) function, that is used inside `mul()` and `square()`, and when it is used with the same arguments in `square()`, compiler is able to use that fact after inlining. */ let a0 = self.0[0] as u128; let a1 = self.0[1] as u128; let a2 = self.0[2] as u128; let a3 = self.0[3] as u128; let a4 = self.0[4] as u128; let b0 = rhs.0[0] as u128; let b1 = rhs.0[1] as u128; let b2 = rhs.0[2] as u128; let b3 = rhs.0[3] as u128; let b4 = rhs.0[4] as u128; let m = 0xFFFFFFFFFFFFFu128; let r = 0x1000003D10u128; debug_assert!(a0 >> 56 == 0); debug_assert!(a1 >> 56 == 0); debug_assert!(a2 >> 56 == 0); debug_assert!(a3 >> 56 == 0); debug_assert!(a4 >> 52 == 0); debug_assert!(b0 >> 56 == 0); debug_assert!(b1 >> 56 == 0); debug_assert!(b2 >> 56 == 0); debug_assert!(b3 >> 56 == 0); debug_assert!(b4 >> 52 == 0); // [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. // for 0 <= x <= 4, px is a shorthand for sum(a[i]*b[x-i], i=0..x). // for 4 <= x <= 8, px is a shorthand for sum(a[i]*b[x-i], i=(x-4)..4) // Note that [x 0 0 0 0 0] = [x*r]. let mut d = a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0; debug_assert!(d >> 114 == 0); // [d 0 0 0] = [p3 0 0 0] let mut c = a4 * b4; debug_assert!(c >> 112 == 0); // [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] d += (c & m) * r; c >>= 52; debug_assert!(d >> 115 == 0); debug_assert!(c >> 60 == 0); let c64 = c as u64; // [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] let t3 = (d & m) as u64; d >>= 52; debug_assert!(t3 >> 52 == 0); debug_assert!(d >> 63 == 0); let d64 = d as u64; // [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] d = d64 as u128 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0; debug_assert!(d >> 115 == 0); // [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] d += c64 as u128 * r; debug_assert!(d >> 116 == 0); // [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] let t4 = (d & m) as u64; d >>= 52; debug_assert!(t4 >> 52 == 0); debug_assert!(d >> 64 == 0); let d64 = d as u64; // [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] let tx = t4 >> 48; let t4 = t4 & ((m as u64) >> 4); debug_assert!(tx >> 4 == 0); debug_assert!(t4 >> 48 == 0); // [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] c = a0 * b0; debug_assert!(c >> 112 == 0); // [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] d = d64 as u128 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1; debug_assert!(d >> 115 == 0); // [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] let u0 = (d & m) as u64; d >>= 52; debug_assert!(u0 >> 52 == 0); debug_assert!(d >> 63 == 0); let d64 = d as u64; // [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] // [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] let u0 = (u0 << 4) | tx; debug_assert!(u0 >> 56 == 0); // [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] c += u0 as u128 * ((r as u64) >> 4) as u128; debug_assert!(c >> 115 == 0); // [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] let r0 = (c & m) as u64; c >>= 52; debug_assert!(r0 >> 52 == 0); debug_assert!(c >> 61 == 0); let c64 = c as u64; // [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] c = c64 as u128 + a0 * b1 + a1 * b0; debug_assert!(c >> 114 == 0); // [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] d = d64 as u128 + a2 * b4 + a3 * b3 + a4 * b2; debug_assert!(d >> 114 == 0); // [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] c += (d & m) * r; d >>= 52; debug_assert!(c >> 115 == 0); debug_assert!(d >> 62 == 0); let d64 = d as u64; // [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] let r1 = (c & m) as u64; c >>= 52; debug_assert!(r1 >> 52 == 0); debug_assert!(c >> 63 == 0); let c64 = c as u64; // [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] c = c64 as u128 + a0 * b2 + a1 * b1 + a2 * b0; debug_assert!(c >> 114 == 0); // [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] d = d64 as u128 + a3 * b4 + a4 * b3; debug_assert!(d >> 114 == 0); // [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] c += (d & m) * r; d >>= 52; debug_assert!(c >> 115 == 0); debug_assert!(d >> 62 == 0); let d64 = d as u64; // [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] // [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] let r2 = (c & m) as u64; c >>= 52; debug_assert!(r2 >> 52 == 0); debug_assert!(c >> 63 == 0); let c64 = c as u64; // [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] c = c64 as u128 + (d64 as u128) * r + t3 as u128; debug_assert!(c >> 100 == 0); // [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] let r3 = (c & m) as u64; c >>= 52; debug_assert!(r3 >> 52 == 0); debug_assert!(c >> 48 == 0); let c64 = c as u64; // [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] c = c64 as u128 + t4 as u128; debug_assert!(c >> 49 == 0); // [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] let r4 = c as u64; debug_assert!(r4 >> 49 == 0); // [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] Self([r0, r1, r2, r3, r4]) } /// Returns self * rhs mod p /// Brings the magnitude to 1 (but doesn't normalize the result). /// The magnitudes of arguments should be <= 8. #[inline(always)] pub fn mul(&self, rhs: &Self) -> Self { self.mul_inner(rhs) } /// Returns self * self /// Brings the magnitude to 1 (but doesn't normalize the result). /// The magnitudes of arguments should be <= 8. pub fn square(&self) -> Self { self.mul_inner(self) } } impl Default for FieldElement5x52 { fn default() -> Self { Self::ZERO } } impl ConditionallySelectable for FieldElement5x52 { #[inline(always)] fn conditional_select( a: &FieldElement5x52, b: &FieldElement5x52, choice: Choice, ) -> FieldElement5x52 { FieldElement5x52([ u64::conditional_select(&a.0[0], &b.0[0], choice), u64::conditional_select(&a.0[1], &b.0[1], choice), u64::conditional_select(&a.0[2], &b.0[2], choice), u64::conditional_select(&a.0[3], &b.0[3], choice), u64::conditional_select(&a.0[4], &b.0[4], choice), ]) } } impl ConstantTimeEq for FieldElement5x52 { fn ct_eq(&self, other: &Self) -> Choice { self.0[0].ct_eq(&other.0[0]) & self.0[1].ct_eq(&other.0[1]) & self.0[2].ct_eq(&other.0[2]) & self.0[3].ct_eq(&other.0[3]) & self.0[4].ct_eq(&other.0[4]) } } impl Zeroize for FieldElement5x52 { fn zeroize(&mut self) { self.0.zeroize(); } } #[cfg(test)] mod tests { use super::FieldElement5x52; #[test] fn overflow_check_after_weak_normalize() { // A regression test for a missing condition in `get_overflow()`. // The condition was only missing in the 32-bit case, // but we're adding a 64-bit testcase nevertheless. // // In `normalize()`, after the `normalize_weak()` call, // the excess bit from the limb 0 is propagated all the way to the last limb. // This constitutes an overflow, since the last bit becomes equal to (1 << 22), // that is 23 bits in total. // When `get_overflow()` is called afterwards, this was not detected, // since the corresponding condition (checking for the last limb being > 22 bits) // was missing. // This resulted in a debug assert firing later. // // This is essentially 2^256 let z = FieldElement5x52([ (1 << 52), // an excess bit here // the remaining full-sized limbs are at top normalized capacity (1 << 52) - 1, (1 << 52) - 1, (1 << 52) - 1, // the last limb is also at top normalized capacity (1 << 48) - 1, ]); // Used to fail here (debug_assert firing because overflow happened at an unexpected place): let z_normalized = z.normalize(); // Properly normalized result, just to be sure // The initial number is 2^256, so the result is 0x1000003d1 let z_reference = FieldElement5x52([0x1000003d1, 0, 0, 0, 0]); assert_eq!(z_normalized.0, z_reference.0); } } k256-0.13.3/src/arithmetic/field/field_impl.rs000064400000000000000000000124421046102023000170570ustar 00000000000000//! A debug layer for lazy-reduction field elements making sure //! they are not misused. Ensures the correct normalization and checks magnitudes in operations. //! Only enabled when `debug_assertions` feature is on. use crate::FieldBytes; use elliptic_curve::{ subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, zeroize::Zeroize, }; #[cfg(target_pointer_width = "32")] use super::field_10x26::FieldElement10x26 as FieldElementUnsafeImpl; #[cfg(target_pointer_width = "64")] use super::field_5x52::FieldElement5x52 as FieldElementUnsafeImpl; #[derive(Clone, Copy, Debug)] pub struct FieldElementImpl { value: FieldElementUnsafeImpl, magnitude: u32, normalized: bool, } impl FieldElementImpl { /// Zero element. pub const ZERO: Self = Self { value: FieldElementUnsafeImpl::ZERO, magnitude: 1, normalized: true, }; /// Multiplicative identity. pub const ONE: Self = Self { value: FieldElementUnsafeImpl::ONE, magnitude: 1, normalized: true, }; const fn new_normalized(value: &FieldElementUnsafeImpl) -> Self { Self { value: *value, magnitude: 1, normalized: true, } } const fn new_weak_normalized(value: &FieldElementUnsafeImpl) -> Self { Self { value: *value, magnitude: 1, normalized: false, } } fn new(value: &FieldElementUnsafeImpl, magnitude: u32) -> Self { debug_assert!(magnitude <= FieldElementUnsafeImpl::max_magnitude()); Self { value: *value, magnitude, normalized: false, } } pub(crate) const fn from_bytes_unchecked(bytes: &[u8; 32]) -> Self { let value = FieldElementUnsafeImpl::from_bytes_unchecked(bytes); Self::new_normalized(&value) } pub(crate) const fn from_u64(val: u64) -> Self { Self::new_normalized(&FieldElementUnsafeImpl::from_u64(val)) } pub fn from_bytes(bytes: &FieldBytes) -> CtOption { let value = FieldElementUnsafeImpl::from_bytes(bytes); CtOption::map(value, |x| Self::new_normalized(&x)) } pub fn to_bytes(self) -> FieldBytes { debug_assert!(self.normalized); self.value.to_bytes() } pub fn normalize_weak(&self) -> Self { Self::new_weak_normalized(&self.value.normalize_weak()) } pub fn normalize(&self) -> Self { Self::new_normalized(&self.value.normalize()) } pub fn normalizes_to_zero(&self) -> Choice { self.value.normalizes_to_zero() } pub fn is_zero(&self) -> Choice { debug_assert!(self.normalized); self.value.is_zero() } pub fn is_odd(&self) -> Choice { debug_assert!(self.normalized); self.value.is_odd() } pub fn negate(&self, magnitude: u32) -> Self { debug_assert!(self.magnitude <= magnitude); let new_magnitude = magnitude + 1; debug_assert!(new_magnitude <= FieldElementUnsafeImpl::max_magnitude()); Self::new(&(self.value.negate(magnitude)), new_magnitude) } pub fn add(&self, rhs: &Self) -> Self { let new_magnitude = self.magnitude + rhs.magnitude; debug_assert!(new_magnitude <= FieldElementUnsafeImpl::max_magnitude()); Self::new(&(self.value.add(&(rhs.value))), new_magnitude) } pub fn mul_single(&self, rhs: u32) -> Self { let new_magnitude = self.magnitude * rhs; debug_assert!(new_magnitude <= FieldElementUnsafeImpl::max_magnitude()); Self::new(&(self.value.mul_single(rhs)), new_magnitude) } /// Returns self * rhs mod p pub fn mul(&self, rhs: &Self) -> Self { debug_assert!(self.magnitude <= 8); debug_assert!(rhs.magnitude <= 8); Self::new_weak_normalized(&(self.value.mul(&(rhs.value)))) } /// Returns self * self mod p pub fn square(&self) -> Self { debug_assert!(self.magnitude <= 8); Self::new_weak_normalized(&(self.value.square())) } } impl Default for FieldElementImpl { fn default() -> Self { Self::ZERO } } impl ConditionallySelectable for FieldElementImpl { #[inline(always)] fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { // 1. It's debug only, so it shouldn't present a security risk // 2. Being normalized does is independent from the field element value; // elements must be normalized explicitly. let new_normalized = if bool::from(choice) { b.normalized } else { a.normalized }; Self { value: FieldElementUnsafeImpl::conditional_select(&(a.value), &(b.value), choice), magnitude: u32::conditional_select(&(a.magnitude), &(b.magnitude), choice), normalized: new_normalized, } } } impl ConstantTimeEq for FieldElementImpl { fn ct_eq(&self, other: &Self) -> Choice { self.value.ct_eq(&(other.value)) & self.magnitude.ct_eq(&(other.magnitude)) // See the comment in `conditional_select()` & Choice::from((self.normalized == other.normalized) as u8) } } impl Zeroize for FieldElementImpl { fn zeroize(&mut self) { self.value.zeroize(); self.magnitude.zeroize(); self.normalized.zeroize(); } } k256-0.13.3/src/arithmetic/field.rs000064400000000000000000000604121046102023000147530ustar 00000000000000//! Field arithmetic modulo p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 #![allow(clippy::assign_op_pattern, clippy::op_ref)] use cfg_if::cfg_if; cfg_if! { if #[cfg(target_pointer_width = "32")] { mod field_10x26; } else if #[cfg(target_pointer_width = "64")] { mod field_5x52; } else { compile_error!("unsupported target word size (i.e. target_pointer_width)"); } } cfg_if! { if #[cfg(debug_assertions)] { mod field_impl; use field_impl::FieldElementImpl; } else { cfg_if! { if #[cfg(target_pointer_width = "32")] { use field_10x26::FieldElement10x26 as FieldElementImpl; } else if #[cfg(target_pointer_width = "64")] { use field_5x52::FieldElement5x52 as FieldElementImpl; } else { compile_error!("unsupported target word size (i.e. target_pointer_width)"); } } } } use crate::FieldBytes; use core::{ iter::{Product, Sum}, ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, }; use elliptic_curve::{ ff::{self, Field, PrimeField}, ops::Invert, rand_core::RngCore, subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, zeroize::DefaultIsZeroes, }; #[cfg(test)] use num_bigint::{BigUint, ToBigUint}; /// An element in the finite field used for curve coordinates. #[derive(Clone, Copy, Debug)] pub struct FieldElement(FieldElementImpl); impl FieldElement { /// Zero element. pub const ZERO: Self = Self(FieldElementImpl::ZERO); /// Multiplicative identity. pub const ONE: Self = Self(FieldElementImpl::ONE); /// Determine if this `FieldElement` is zero. /// /// # Returns /// /// If zero, return `Choice(1)`. Otherwise, return `Choice(0)`. pub fn is_zero(&self) -> Choice { self.0.is_zero() } /// Determine if this `FieldElement` is even in the SEC1 sense: `self mod 2 == 0`. /// /// # Returns /// /// If even, return `Choice(1)`. Otherwise, return `Choice(0)`. pub fn is_even(&self) -> Choice { !self.0.is_odd() } /// Determine if this `FieldElement` is odd in the SEC1 sense: `self mod 2 == 1`. /// /// # Returns /// /// If odd, return `Choice(1)`. Otherwise, return `Choice(0)`. pub fn is_odd(&self) -> Choice { self.0.is_odd() } /// Attempts to parse the given byte array as an SEC1-encoded field element. /// Does not check the result for being in the correct range. pub(crate) const fn from_bytes_unchecked(bytes: &[u8; 32]) -> Self { Self(FieldElementImpl::from_bytes_unchecked(bytes)) } /// Attempts to parse the given byte array as an SEC1-encoded field element. /// /// Returns None if the byte array does not contain a big-endian integer in the range /// [0, p). pub fn from_bytes(bytes: &FieldBytes) -> CtOption { FieldElementImpl::from_bytes(bytes).map(Self) } /// Convert a `u64` to a field element. pub const fn from_u64(w: u64) -> Self { Self(FieldElementImpl::from_u64(w)) } /// Returns the SEC1 encoding of this field element. pub fn to_bytes(self) -> FieldBytes { self.0.normalize().to_bytes() } /// Returns -self, treating it as a value of given magnitude. /// The provided magnitude must be equal or greater than the actual magnitude of `self`. pub fn negate(&self, magnitude: u32) -> Self { Self(self.0.negate(magnitude)) } /// Fully normalizes the field element. /// Brings the magnitude to 1 and modulo reduces the value. pub fn normalize(&self) -> Self { Self(self.0.normalize()) } /// Weakly normalizes the field element. /// Brings the magnitude to 1, but does not guarantee the value to be less than the modulus. pub fn normalize_weak(&self) -> Self { Self(self.0.normalize_weak()) } /// Checks if the field element becomes zero if normalized. pub fn normalizes_to_zero(&self) -> Choice { self.0.normalizes_to_zero() } /// Multiplies by a single-limb integer. /// Multiplies the magnitude by the same value. pub fn mul_single(&self, rhs: u32) -> Self { Self(self.0.mul_single(rhs)) } /// Returns 2*self. /// Doubles the magnitude. pub fn double(&self) -> Self { Self(self.0.add(&(self.0))) } /// Returns self * rhs mod p /// Brings the magnitude to 1 (but doesn't normalize the result). /// The magnitudes of arguments should be <= 8. pub fn mul(&self, rhs: &Self) -> Self { Self(self.0.mul(&(rhs.0))) } /// Returns self * self. /// /// Brings the magnitude to 1 (but doesn't normalize the result). /// The magnitudes of arguments should be <= 8. pub fn square(&self) -> Self { Self(self.0.square()) } /// Raises the scalar to the power `2^k` fn pow2k(&self, k: usize) -> Self { let mut x = *self; for _j in 0..k { x = x.square(); } x } /// Returns the multiplicative inverse of self, if self is non-zero. /// The result has magnitude 1, but is not normalized. pub fn invert(&self) -> CtOption { // The binary representation of (p - 2) has 5 blocks of 1s, with lengths in // { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: // [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] let x2 = self.pow2k(1).mul(self); let x3 = x2.pow2k(1).mul(self); let x6 = x3.pow2k(3).mul(&x3); let x9 = x6.pow2k(3).mul(&x3); let x11 = x9.pow2k(2).mul(&x2); let x22 = x11.pow2k(11).mul(&x11); let x44 = x22.pow2k(22).mul(&x22); let x88 = x44.pow2k(44).mul(&x44); let x176 = x88.pow2k(88).mul(&x88); let x220 = x176.pow2k(44).mul(&x44); let x223 = x220.pow2k(3).mul(&x3); // The final result is then assembled using a sliding window over the blocks. let res = x223 .pow2k(23) .mul(&x22) .pow2k(5) .mul(self) .pow2k(3) .mul(&x2) .pow2k(2) .mul(self); CtOption::new(res, !self.normalizes_to_zero()) } /// Returns the square root of self mod p, or `None` if no square root exists. /// The result has magnitude 1, but is not normalized. pub fn sqrt(&self) -> CtOption { /* Given that p is congruent to 3 mod 4, we can compute the square root of a mod p as the (p+1)/4'th power of a. As (p+1)/4 is an even number, it will have the same result for a and for (-a). Only one of these two numbers actually has a square root however, so we test at the end by squaring and comparing to the input. Also because (p+1)/4 is an even number, the computed square root is itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)). */ // The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in // { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: // 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] let x2 = self.pow2k(1).mul(self); let x3 = x2.pow2k(1).mul(self); let x6 = x3.pow2k(3).mul(&x3); let x9 = x6.pow2k(3).mul(&x3); let x11 = x9.pow2k(2).mul(&x2); let x22 = x11.pow2k(11).mul(&x11); let x44 = x22.pow2k(22).mul(&x22); let x88 = x44.pow2k(44).mul(&x44); let x176 = x88.pow2k(88).mul(&x88); let x220 = x176.pow2k(44).mul(&x44); let x223 = x220.pow2k(3).mul(&x3); // The final result is then assembled using a sliding window over the blocks. let res = x223.pow2k(23).mul(&x22).pow2k(6).mul(&x2).pow2k(2); let is_root = (res.mul(&res).negate(1) + self).normalizes_to_zero(); // Only return Some if it's the square root. CtOption::new(res, is_root) } #[cfg(test)] pub fn modulus_as_biguint() -> BigUint { Self::ONE.negate(1).to_biguint().unwrap() + 1.to_biguint().unwrap() } } impl Invert for FieldElement { type Output = CtOption; fn invert(&self) -> CtOption { self.invert() } } impl Field for FieldElement { const ZERO: Self = Self::ZERO; const ONE: Self = Self::ONE; fn random(mut rng: impl RngCore) -> Self { let mut bytes = FieldBytes::default(); loop { rng.fill_bytes(&mut bytes); if let Some(fe) = Self::from_bytes(&bytes).into() { return fe; } } } #[must_use] fn square(&self) -> Self { self.square() } #[must_use] fn double(&self) -> Self { self.double() } fn invert(&self) -> CtOption { self.invert() } fn sqrt(&self) -> CtOption { self.sqrt() } fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { ff::helpers::sqrt_ratio_generic(num, div) } } impl PrimeField for FieldElement { type Repr = FieldBytes; const MODULUS: &'static str = "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"; const NUM_BITS: u32 = 256; const CAPACITY: u32 = 255; const TWO_INV: Self = Self(FieldElementImpl::from_bytes_unchecked(&[ 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xfe, 0x18, ])); const MULTIPLICATIVE_GENERATOR: Self = Self::from_u64(3); const S: u32 = 1; const ROOT_OF_UNITY: Self = Self(FieldElementImpl::from_bytes_unchecked(&[ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, ])); const ROOT_OF_UNITY_INV: Self = Self(FieldElementImpl::from_bytes_unchecked(&[ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, ])); const DELTA: Self = Self::from_u64(9); fn from_repr(repr: Self::Repr) -> CtOption { Self::from_bytes(&repr) } fn to_repr(&self) -> Self::Repr { self.to_bytes() } fn is_odd(&self) -> Choice { self.is_odd() } } impl ConditionallySelectable for FieldElement { #[inline(always)] fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Self(FieldElementImpl::conditional_select(&(a.0), &(b.0), choice)) } } impl ConstantTimeEq for FieldElement { fn ct_eq(&self, other: &Self) -> Choice { self.0.ct_eq(&(other.0)) } } impl Default for FieldElement { fn default() -> Self { Self::ZERO } } impl DefaultIsZeroes for FieldElement {} impl Eq for FieldElement {} impl From for FieldElement { fn from(k: u64) -> Self { Self(FieldElementImpl::from_u64(k)) } } impl PartialEq for FieldElement { fn eq(&self, other: &Self) -> bool { self.0.ct_eq(&(other.0)).into() } } impl Add for FieldElement { type Output = FieldElement; fn add(self, other: FieldElement) -> FieldElement { FieldElement(self.0.add(&(other.0))) } } impl Add<&FieldElement> for FieldElement { type Output = FieldElement; fn add(self, other: &FieldElement) -> FieldElement { FieldElement(self.0.add(&(other.0))) } } impl Add<&FieldElement> for &FieldElement { type Output = FieldElement; fn add(self, other: &FieldElement) -> FieldElement { FieldElement(self.0.add(&(other.0))) } } impl AddAssign for FieldElement { fn add_assign(&mut self, other: FieldElement) { *self = *self + &other; } } impl AddAssign<&FieldElement> for FieldElement { fn add_assign(&mut self, other: &FieldElement) { *self = *self + other; } } impl Sub for FieldElement { type Output = FieldElement; fn sub(self, other: FieldElement) -> FieldElement { self + -other } } impl Sub<&FieldElement> for FieldElement { type Output = FieldElement; fn sub(self, other: &FieldElement) -> FieldElement { self + -other } } impl SubAssign for FieldElement { fn sub_assign(&mut self, other: FieldElement) { *self = *self + -other; } } impl SubAssign<&FieldElement> for FieldElement { fn sub_assign(&mut self, other: &FieldElement) { *self = *self + -other; } } impl Mul for FieldElement { type Output = FieldElement; fn mul(self, other: FieldElement) -> FieldElement { FieldElement(self.0.mul(&(other.0))) } } impl Mul<&FieldElement> for FieldElement { type Output = FieldElement; #[inline(always)] fn mul(self, other: &FieldElement) -> FieldElement { FieldElement(self.0.mul(&(other.0))) } } impl Mul<&FieldElement> for &FieldElement { type Output = FieldElement; fn mul(self, other: &FieldElement) -> FieldElement { FieldElement(self.0.mul(&(other.0))) } } impl MulAssign for FieldElement { fn mul_assign(&mut self, rhs: FieldElement) { *self = *self * &rhs; } } impl MulAssign<&FieldElement> for FieldElement { fn mul_assign(&mut self, rhs: &FieldElement) { *self = *self * rhs; } } impl Neg for FieldElement { type Output = FieldElement; fn neg(self) -> FieldElement { self.negate(1) } } impl Neg for &FieldElement { type Output = FieldElement; fn neg(self) -> FieldElement { self.negate(1) } } impl Sum for FieldElement { fn sum>(iter: I) -> Self { iter.reduce(core::ops::Add::add).unwrap_or(Self::ZERO) } } impl<'a> Sum<&'a FieldElement> for FieldElement { #[inline] fn sum>(iter: I) -> Self { iter.copied().sum() } } impl Product for FieldElement { fn product>(iter: I) -> Self { iter.reduce(core::ops::Mul::mul).unwrap_or(Self::ONE) } } impl<'a> Product<&'a FieldElement> for FieldElement { fn product>(iter: I) -> Self { iter.copied().product() } } #[cfg(test)] mod tests { use elliptic_curve::ff::{Field, PrimeField}; use elliptic_curve::ops::BatchInvert; use num_bigint::{BigUint, ToBigUint}; use proptest::prelude::*; use rand_core::OsRng; use super::FieldElement; use crate::{ arithmetic::dev::{biguint_to_bytes, bytes_to_biguint}, test_vectors::field::DBL_TEST_VECTORS, FieldBytes, }; #[cfg(feature = "alloc")] use alloc::vec::Vec; impl From<&BigUint> for FieldElement { fn from(x: &BigUint) -> Self { let bytes = biguint_to_bytes(x); Self::from_bytes(&bytes.into()).unwrap() } } impl ToBigUint for FieldElement { fn to_biguint(&self) -> Option { Some(bytes_to_biguint(self.to_bytes().as_ref())) } } /// t = (modulus - 1) >> S const T: [u64; 4] = [ 0xffffffff7ffffe17, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff, ]; #[test] fn two_inv_constant() { assert_eq!( (FieldElement::from(2u64) * FieldElement::TWO_INV).normalize(), FieldElement::ONE ); } #[test] fn root_of_unity_constant() { // ROOT_OF_UNITY^{2^s} mod m == 1 assert_eq!( FieldElement::ROOT_OF_UNITY .pow_vartime(&[1u64 << FieldElement::S, 0, 0, 0]) .normalize(), FieldElement::ONE ); // MULTIPLICATIVE_GENERATOR^{t} mod m == ROOT_OF_UNITY assert_eq!( FieldElement::MULTIPLICATIVE_GENERATOR .pow_vartime(&T) .normalize(), FieldElement::ROOT_OF_UNITY ) } #[test] fn root_of_unity_inv_constant() { assert_eq!( (FieldElement::ROOT_OF_UNITY * FieldElement::ROOT_OF_UNITY_INV).normalize(), FieldElement::ONE ); } #[test] fn delta_constant() { // DELTA^{t} mod m == 1 assert_eq!( FieldElement::DELTA.pow_vartime(&T).normalize(), FieldElement::ONE ); } #[test] fn zero_is_additive_identity() { let zero = FieldElement::ZERO; let one = FieldElement::ONE; assert_eq!((zero + &zero).normalize(), zero); assert_eq!((one + &zero).normalize(), one); } #[test] fn one_is_multiplicative_identity() { let one = FieldElement::ONE; assert_eq!((one * &one).normalize(), one); } #[test] fn from_bytes() { assert_eq!( FieldElement::from_bytes(&FieldBytes::default()).unwrap(), FieldElement::ZERO ); assert_eq!( FieldElement::from_bytes( &[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ] .into() ) .unwrap(), FieldElement::ONE ); assert!(bool::from( FieldElement::from_bytes(&[0xff; 32].into()).is_none() )); } #[test] fn to_bytes() { assert_eq!(FieldElement::ZERO.to_bytes(), [0; 32].into()); assert_eq!( FieldElement::ONE.to_bytes(), [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ] .into() ); } #[test] fn repeated_add() { let mut r = FieldElement::ONE; for i in 0..DBL_TEST_VECTORS.len() { assert_eq!(r.to_bytes(), DBL_TEST_VECTORS[i].into()); r = (r + &r).normalize(); } } #[test] fn repeated_double() { let mut r = FieldElement::ONE; for i in 0..DBL_TEST_VECTORS.len() { assert_eq!(r.to_bytes(), DBL_TEST_VECTORS[i].into()); r = r.double().normalize(); } } #[test] fn repeated_mul() { let mut r = FieldElement::ONE; let two = r + &r; for i in 0..DBL_TEST_VECTORS.len() { assert_eq!(r.normalize().to_bytes(), DBL_TEST_VECTORS[i].into()); r = r * &two; } } #[test] fn negation() { let two = FieldElement::ONE.double(); let neg_two = two.negate(2); assert_eq!((two + &neg_two).normalize(), FieldElement::ZERO); assert_eq!(neg_two.negate(3).normalize(), two.normalize()); } #[test] fn invert() { assert!(bool::from(FieldElement::ZERO.invert().is_none())); let one = FieldElement::ONE; assert_eq!(one.invert().unwrap().normalize(), one); let two = one + &one; let inv_two = two.invert().unwrap(); assert_eq!((two * &inv_two).normalize(), one); } #[test] fn batch_invert_array() { let k: FieldElement = FieldElement::random(&mut OsRng); let l: FieldElement = FieldElement::random(&mut OsRng); let expected = [k.invert().unwrap(), l.invert().unwrap()]; assert_eq!( >::batch_invert(&[k, l]).unwrap(), expected ); } #[test] #[cfg(feature = "alloc")] fn batch_invert() { let k: FieldElement = FieldElement::random(&mut OsRng); let l: FieldElement = FieldElement::random(&mut OsRng); let expected = vec![k.invert().unwrap(), l.invert().unwrap()]; let field_elements = vec![k, l]; let res: Vec<_> = >::batch_invert(field_elements.as_slice()).unwrap(); assert_eq!(res, expected); } #[test] fn sqrt() { let one = FieldElement::ONE; let two = one + &one; let four = two.square(); assert_eq!(four.sqrt().unwrap().normalize(), two.normalize()); } #[test] #[cfg_attr( debug_assertions, should_panic(expected = "assertion failed: self.normalized") )] fn unnormalized_is_odd() { // This is a regression test for https://github.com/RustCrypto/elliptic-curves/issues/529 // where `is_odd()` in debug mode force-normalized its argument // instead of checking that it is already normalized. // As a result, in release (where normalization didn't happen) `is_odd()` // could return an incorrect value. let x = FieldElement::from_bytes_unchecked(&[ 61, 128, 156, 189, 241, 12, 174, 4, 80, 52, 238, 78, 188, 251, 9, 188, 95, 115, 38, 6, 212, 168, 175, 174, 211, 232, 208, 14, 182, 45, 59, 122, ]); // Produces an unnormalized FieldElement with magnitude 1 // (we cannot create one directly). let y = x.sqrt().unwrap(); // This is fine. assert!(y.normalize().is_odd().unwrap_u8() == 0); // This panics since `y` is not normalized. let _result = y.is_odd(); } prop_compose! { fn field_element()(bytes in any::<[u8; 32]>()) -> FieldElement { let mut res = bytes_to_biguint(&bytes); let m = FieldElement::modulus_as_biguint(); // Modulus is 256 bit long, same as the maximum `res`, // so this is guaranteed to land us in the correct range. if res >= m { res -= m; } FieldElement::from(&res) } } proptest! { #[test] fn fuzzy_add( a in field_element(), b in field_element() ) { let a_bi = a.to_biguint().unwrap(); let b_bi = b.to_biguint().unwrap(); let res_bi = (&a_bi + &b_bi) % FieldElement::modulus_as_biguint(); let res_ref = FieldElement::from(&res_bi); let res_test = (&a + &b).normalize(); assert_eq!(res_test, res_ref); } #[test] fn fuzzy_mul( a in field_element(), b in field_element() ) { let a_bi = a.to_biguint().unwrap(); let b_bi = b.to_biguint().unwrap(); let res_bi = (&a_bi * &b_bi) % FieldElement::modulus_as_biguint(); let res_ref = FieldElement::from(&res_bi); let res_test = (&a * &b).normalize(); assert_eq!(res_test, res_ref); } #[test] fn fuzzy_square( a in field_element() ) { let a_bi = a.to_biguint().unwrap(); let res_bi = (&a_bi * &a_bi) % FieldElement::modulus_as_biguint(); let res_ref = FieldElement::from(&res_bi); let res_test = a.square().normalize(); assert_eq!(res_test, res_ref); } #[test] fn fuzzy_negate( a in field_element() ) { let m = FieldElement::modulus_as_biguint(); let a_bi = a.to_biguint().unwrap(); let res_bi = (&m - &a_bi) % &m; let res_ref = FieldElement::from(&res_bi); let res_test = a.negate(1).normalize(); assert_eq!(res_test, res_ref); } #[test] fn fuzzy_sqrt( a in field_element() ) { let m = FieldElement::modulus_as_biguint(); let a_bi = a.to_biguint().unwrap(); let sqr_bi = (&a_bi * &a_bi) % &m; let sqr = FieldElement::from(&sqr_bi); let res_ref1 = a; let possible_sqrt = (&m - &a_bi) % &m; let res_ref2 = FieldElement::from(&possible_sqrt); let res_test = sqr.sqrt().unwrap().normalize(); // FIXME: is there a rule which square root is returned? assert!(res_test == res_ref1 || res_test == res_ref2); } #[test] fn fuzzy_invert( a in field_element() ) { let a = if bool::from(a.is_zero()) { FieldElement::ONE } else { a }; let a_bi = a.to_biguint().unwrap(); let inv = a.invert().unwrap().normalize(); let inv_bi = inv.to_biguint().unwrap(); let m = FieldElement::modulus_as_biguint(); assert_eq!((&inv_bi * &a_bi) % &m, 1.to_biguint().unwrap()); } } } k256-0.13.3/src/arithmetic/hash2curve.rs000064400000000000000000000472361046102023000157530ustar 00000000000000use elliptic_curve::bigint::{ArrayEncoding, U256}; use elliptic_curve::consts::{U4, U48}; use elliptic_curve::generic_array::GenericArray; use elliptic_curve::group::cofactor::CofactorGroup; use elliptic_curve::hash2curve::{ FromOkm, GroupDigest, Isogeny, IsogenyCoefficients, MapToCurve, OsswuMap, OsswuMapParams, Sgn0, }; use elliptic_curve::subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; use elliptic_curve::Field; use crate::{AffinePoint, ProjectivePoint, Scalar, Secp256k1}; use super::FieldElement; impl GroupDigest for Secp256k1 { type FieldElement = FieldElement; } impl FromOkm for FieldElement { type Length = U48; fn from_okm(data: &GenericArray) -> Self { // 0x0000000000000001000000000000000000000000000000000000000000000000 const F_2_192: FieldElement = FieldElement::from_bytes_unchecked(&[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]); let d0 = FieldElement::from_bytes_unchecked(&[ 0, 0, 0, 0, 0, 0, 0, 0, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23], ]); let d1 = FieldElement::from_bytes_unchecked(&[ 0, 0, 0, 0, 0, 0, 0, 0, data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], data[32], data[33], data[34], data[35], data[36], data[37], data[38], data[39], data[40], data[41], data[42], data[43], data[44], data[45], data[46], data[47], ]); d0 * F_2_192 + d1 } } impl Sgn0 for FieldElement { fn sgn0(&self) -> Choice { self.normalize().is_odd() } } impl OsswuMap for FieldElement { const PARAMS: OsswuMapParams = OsswuMapParams { // See section 8.7 in // c1: &[ 0xffff_ffff_bfff_ff0b, 0xffff_ffff_ffff_ffff, 0xffff_ffff_ffff_ffff, 0x3fff_ffff_ffff_ffff, ], // 0x25e9711ae8c0dadc 0x46fdbcb72aadd8f4 0x250b65073012ec80 0xbc6ecb9c12973975 c2: FieldElement::from_bytes_unchecked(&[ 0x25, 0xe9, 0x71, 0x1a, 0xe8, 0xc0, 0xda, 0xdc, 0x46, 0xfd, 0xbc, 0xb7, 0x2a, 0xad, 0xd8, 0xf4, 0x25, 0x0b, 0x65, 0x07, 0x30, 0x12, 0xec, 0x80, 0xbc, 0x6e, 0xcb, 0x9c, 0x12, 0x97, 0x39, 0x75, ]), // 0x3f8731abdd661adc 0xa08a5558f0f5d272 0xe953d363cb6f0e5d 0x405447c01a444533 map_a: FieldElement::from_bytes_unchecked(&[ 0x3f, 0x87, 0x31, 0xab, 0xdd, 0x66, 0x1a, 0xdc, 0xa0, 0x8a, 0x55, 0x58, 0xf0, 0xf5, 0xd2, 0x72, 0xe9, 0x53, 0xd3, 0x63, 0xcb, 0x6f, 0x0e, 0x5d, 0x40, 0x54, 0x47, 0xc0, 0x1a, 0x44, 0x45, 0x33, ]), // 0x00000000000006eb map_b: FieldElement::from_bytes_unchecked(&[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xeb, ]), // 0xffffffffffffffff 0xffffffffffffffff 0xffffffffffffffff 0xfffffffefffffc24 z: FieldElement::from_bytes_unchecked(&[ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x24, ]), }; fn osswu(&self) -> (Self, Self) { let tv1 = self.square(); // u^2 let tv3 = Self::PARAMS.z * tv1; // Z * u^2 let mut tv2 = tv3.square(); // tv3^2 let mut xd = tv2 + tv3; // tv3^2 + tv3 let x1n = Self::PARAMS.map_b * (xd + Self::ONE); // B * (xd + 1) xd = (xd * Self::PARAMS.map_a.negate(1)).normalize(); // -A * xd let tv = Self::PARAMS.z * Self::PARAMS.map_a; xd.conditional_assign(&tv, xd.is_zero()); tv2 = xd.square(); //xd^2 let gxd = tv2 * xd; // xd^3 tv2 *= Self::PARAMS.map_a; // A * tv2 let mut gx1 = x1n * (tv2 + x1n.square()); //x1n *(tv2 + x1n^2) tv2 = gxd * Self::PARAMS.map_b; // B * gxd gx1 += tv2; // gx1 + tv2 let mut tv4 = gxd.square(); // gxd^2 tv2 = gx1 * gxd; // gx1 * gxd tv4 *= tv2; let y1 = tv4.pow_vartime(Self::PARAMS.c1) * tv2; // tv4^C1 * tv2 let x2n = tv3 * x1n; // tv3 * x1n let y2 = y1 * Self::PARAMS.c2 * tv1 * self; // y1 * c2 * tv1 * u tv2 = y1.square() * gxd; //y1^2 * gxd let e2 = tv2.normalize().ct_eq(&gx1.normalize()); // if e2 , x = x1, else x = x2 let mut x = Self::conditional_select(&x2n, &x1n, e2); // xn / xd x *= xd.invert().unwrap(); // if e2, y = y1, else y = y2 let mut y = Self::conditional_select(&y2, &y1, e2); y.conditional_assign(&-y, self.sgn0() ^ y.sgn0()); (x, y) } } impl MapToCurve for FieldElement { type Output = ProjectivePoint; fn map_to_curve(&self) -> Self::Output { let (rx, ry) = self.osswu(); let (qx, qy) = FieldElement::isogeny(rx, ry); AffinePoint { x: qx, y: qy, infinity: 0, } .into() } } impl FromOkm for Scalar { type Length = U48; fn from_okm(data: &GenericArray) -> Self { const F_2_192: Scalar = Scalar(U256::from_be_hex( "0000000000000001000000000000000000000000000000000000000000000000", )); let mut d0 = GenericArray::default(); d0[8..].copy_from_slice(&data[0..24]); let d0 = Scalar(U256::from_be_byte_array(d0)); let mut d1 = GenericArray::default(); d1[8..].copy_from_slice(&data[24..]); let d1 = Scalar(U256::from_be_byte_array(d1)); d0 * F_2_192 + d1 } } impl Isogeny for FieldElement { type Degree = U4; // See section E.1 in // const COEFFICIENTS: IsogenyCoefficients = IsogenyCoefficients { xnum: &[ FieldElement::from_bytes_unchecked(&[ 0x8e, 0x38, 0xe3, 0x8e, 0x38, 0xe3, 0x8e, 0x38, 0xe3, 0x8e, 0x38, 0xe3, 0x8e, 0x38, 0xe3, 0x8e, 0x38, 0xe3, 0x8e, 0x38, 0xe3, 0x8e, 0x38, 0xe3, 0x8e, 0x38, 0xe3, 0x8d, 0xaa, 0xaa, 0xa8, 0xc7, ]), FieldElement::from_bytes_unchecked(&[ 0x07, 0xd3, 0xd4, 0xc8, 0x0b, 0xc3, 0x21, 0xd5, 0xb9, 0xf3, 0x15, 0xce, 0xa7, 0xfd, 0x44, 0xc5, 0xd5, 0x95, 0xd2, 0xfc, 0x0b, 0xf6, 0x3b, 0x92, 0xdf, 0xff, 0x10, 0x44, 0xf1, 0x7c, 0x65, 0x81, ]), FieldElement::from_bytes_unchecked(&[ 0x53, 0x4c, 0x32, 0x8d, 0x23, 0xf2, 0x34, 0xe6, 0xe2, 0xa4, 0x13, 0xde, 0xca, 0x25, 0xca, 0xec, 0xe4, 0x50, 0x61, 0x44, 0x03, 0x7c, 0x40, 0x31, 0x4e, 0xcb, 0xd0, 0xb5, 0x3d, 0x9d, 0xd2, 0x62, ]), FieldElement::from_bytes_unchecked(&[ 0x8e, 0x38, 0xe3, 0x8e, 0x38, 0xe3, 0x8e, 0x38, 0xe3, 0x8e, 0x38, 0xe3, 0x8e, 0x38, 0xe3, 0x8e, 0x38, 0xe3, 0x8e, 0x38, 0xe3, 0x8e, 0x38, 0xe3, 0x8e, 0x38, 0xe3, 0x8d, 0xaa, 0xaa, 0xa8, 0x8c, ]), ], xden: &[ FieldElement::from_bytes_unchecked(&[ 0xd3, 0x57, 0x71, 0x19, 0x3d, 0x94, 0x91, 0x8a, 0x9c, 0xa3, 0x4c, 0xcb, 0xb7, 0xb6, 0x40, 0xdd, 0x86, 0xcd, 0x40, 0x95, 0x42, 0xf8, 0x48, 0x7d, 0x9f, 0xe6, 0xb7, 0x45, 0x78, 0x1e, 0xb4, 0x9b, ]), FieldElement::from_bytes_unchecked(&[ 0xed, 0xad, 0xc6, 0xf6, 0x43, 0x83, 0xdc, 0x1d, 0xf7, 0xc4, 0xb2, 0xd5, 0x1b, 0x54, 0x22, 0x54, 0x06, 0xd3, 0x6b, 0x64, 0x1f, 0x5e, 0x41, 0xbb, 0xc5, 0x2a, 0x56, 0x61, 0x2a, 0x8c, 0x6d, 0x14, ]), FieldElement::from_bytes_unchecked(&[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ]), ], ynum: &[ FieldElement::from_bytes_unchecked(&[ 0x4b, 0xda, 0x12, 0xf6, 0x84, 0xbd, 0xa1, 0x2f, 0x68, 0x4b, 0xda, 0x12, 0xf6, 0x84, 0xbd, 0xa1, 0x2f, 0x68, 0x4b, 0xda, 0x12, 0xf6, 0x84, 0xbd, 0xa1, 0x2f, 0x68, 0x4b, 0x8e, 0x38, 0xe2, 0x3c, ]), FieldElement::from_bytes_unchecked(&[ 0xc7, 0x5e, 0x0c, 0x32, 0xd5, 0xcb, 0x7c, 0x0f, 0xa9, 0xd0, 0xa5, 0x4b, 0x12, 0xa0, 0xa6, 0xd5, 0x64, 0x7a, 0xb0, 0x46, 0xd6, 0x86, 0xda, 0x6f, 0xdf, 0xfc, 0x90, 0xfc, 0x20, 0x1d, 0x71, 0xa3, ]), FieldElement::from_bytes_unchecked(&[ 0x29, 0xa6, 0x19, 0x46, 0x91, 0xf9, 0x1a, 0x73, 0x71, 0x52, 0x09, 0xef, 0x65, 0x12, 0xe5, 0x76, 0x72, 0x28, 0x30, 0xa2, 0x01, 0xbe, 0x20, 0x18, 0xa7, 0x65, 0xe8, 0x5a, 0x9e, 0xce, 0xe9, 0x31, ]), FieldElement::from_bytes_unchecked(&[ 0x2f, 0x68, 0x4b, 0xda, 0x12, 0xf6, 0x84, 0xbd, 0xa1, 0x2f, 0x68, 0x4b, 0xda, 0x12, 0xf6, 0x84, 0xbd, 0xa1, 0x2f, 0x68, 0x4b, 0xda, 0x12, 0xf6, 0x84, 0xbd, 0xa1, 0x2f, 0x38, 0xe3, 0x8d, 0x84, ]), ], yden: &[ FieldElement::from_bytes_unchecked(&[ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xf9, 0x3b, ]), FieldElement::from_bytes_unchecked(&[ 0x7a, 0x06, 0x53, 0x4b, 0xb8, 0xbd, 0xb4, 0x9f, 0xd5, 0xe9, 0xe6, 0x63, 0x27, 0x22, 0xc2, 0x98, 0x94, 0x67, 0xc1, 0xbf, 0xc8, 0xe8, 0xd9, 0x78, 0xdf, 0xb4, 0x25, 0xd2, 0x68, 0x5c, 0x25, 0x73, ]), FieldElement::from_bytes_unchecked(&[ 0x64, 0x84, 0xaa, 0x71, 0x65, 0x45, 0xca, 0x2c, 0xf3, 0xa7, 0x0c, 0x3f, 0xa8, 0xfe, 0x33, 0x7e, 0x0a, 0x3d, 0x21, 0x16, 0x2f, 0x0d, 0x62, 0x99, 0xa7, 0xbf, 0x81, 0x92, 0xbf, 0xd2, 0xa7, 0x6f, ]), FieldElement::from_bytes_unchecked(&[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ]), ], }; } impl CofactorGroup for ProjectivePoint { type Subgroup = ProjectivePoint; fn clear_cofactor(&self) -> Self::Subgroup { *self } fn into_subgroup(self) -> CtOption { CtOption::new(self, 1.into()) } fn is_torsion_free(&self) -> Choice { 1.into() } } #[cfg(test)] mod tests { use crate::{FieldElement, Scalar, Secp256k1, U256}; use elliptic_curve::{ bigint::{ArrayEncoding, NonZero, U384}, consts::U48, generic_array::GenericArray, group::cofactor::CofactorGroup, hash2curve::{FromOkm, GroupDigest, MapToCurve}, Curve, }; use hex_literal::hex; use proptest::{num::u64::ANY, prelude::ProptestConfig, proptest}; #[test] fn hash_to_curve() { use elliptic_curve::hash2curve::{self, ExpandMsgXmd}; use hex_literal::hex; use sha2::Sha256; struct TestVector { msg: &'static [u8], p_x: [u8; 32], p_y: [u8; 32], u_0: [u8; 32], u_1: [u8; 32], q0_x: [u8; 32], q0_y: [u8; 32], q1_x: [u8; 32], q1_y: [u8; 32], } const DST: &[u8] = b"QUUX-V01-CS02-with-secp256k1_XMD:SHA-256_SSWU_RO_"; const TEST_VECTORS: [TestVector; 5] = [ TestVector { msg: b"", p_x: hex!("c1cae290e291aee617ebaef1be6d73861479c48b841eaba9b7b5852ddfeb1346"), p_y: hex!("64fa678e07ae116126f08b022a94af6de15985c996c3a91b64c406a960e51067"), u_0: hex!("6b0f9910dd2ba71c78f2ee9f04d73b5f4c5f7fc773a701abea1e573cab002fb3"), u_1: hex!("1ae6c212e08fe1a5937f6202f929a2cc8ef4ee5b9782db68b0d5799fd8f09e16"), q0_x: hex!("74519ef88b32b425a095e4ebcc84d81b64e9e2c2675340a720bb1a1857b99f1e"), q0_y: hex!("c174fa322ab7c192e11748beed45b508e9fdb1ce046dee9c2cd3a2a86b410936"), q1_x: hex!("44548adb1b399263ded3510554d28b4bead34b8cf9a37b4bd0bd2ba4db87ae63"), q1_y: hex!("96eb8e2faf05e368efe5957c6167001760233e6dd2487516b46ae725c4cce0c6"), }, TestVector { msg: b"abc", p_x: hex!("3377e01eab42db296b512293120c6cee72b6ecf9f9205760bd9ff11fb3cb2c4b"), p_y: hex!("7f95890f33efebd1044d382a01b1bee0900fb6116f94688d487c6c7b9c8371f6"), u_0: hex!("128aab5d3679a1f7601e3bdf94ced1f43e491f544767e18a4873f397b08a2b61"), u_1: hex!("5897b65da3b595a813d0fdcc75c895dc531be76a03518b044daaa0f2e4689e00"), q0_x: hex!("07dd9432d426845fb19857d1b3a91722436604ccbbbadad8523b8fc38a5322d7"), q0_y: hex!("604588ef5138cffe3277bbd590b8550bcbe0e523bbaf1bed4014a467122eb33f"), q1_x: hex!("e9ef9794d15d4e77dde751e06c182782046b8dac05f8491eb88764fc65321f78"), q1_y: hex!("cb07ce53670d5314bf236ee2c871455c562dd76314aa41f012919fe8e7f717b3"), }, TestVector { msg: b"abcdef0123456789", p_x: hex!("bac54083f293f1fe08e4a70137260aa90783a5cb84d3f35848b324d0674b0e3a"), p_y: hex!("4436476085d4c3c4508b60fcf4389c40176adce756b398bdee27bca19758d828"), u_0: hex!("ea67a7c02f2cd5d8b87715c169d055a22520f74daeb080e6180958380e2f98b9"), u_1: hex!("7434d0d1a500d38380d1f9615c021857ac8d546925f5f2355319d823a478da18"), q0_x: hex!("576d43ab0260275adf11af990d130a5752704f79478628761720808862544b5d"), q0_y: hex!("643c4a7fb68ae6cff55edd66b809087434bbaff0c07f3f9ec4d49bb3c16623c3"), q1_x: hex!("f89d6d261a5e00fe5cf45e827b507643e67c2a947a20fd9ad71039f8b0e29ff8"), q1_y: hex!("b33855e0cc34a9176ead91c6c3acb1aacb1ce936d563bc1cee1dcffc806caf57"), }, TestVector { msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", p_x: hex!("e2167bc785333a37aa562f021f1e881defb853839babf52a7f72b102e41890e9"), p_y: hex!("f2401dd95cc35867ffed4f367cd564763719fbc6a53e969fb8496a1e6685d873"), u_0: hex!("eda89a5024fac0a8207a87e8cc4e85aa3bce10745d501a30deb87341b05bcdf5"), u_1: hex!("dfe78cd116818fc2c16f3837fedbe2639fab012c407eac9dfe9245bf650ac51d"), q0_x: hex!("9c91513ccfe9520c9c645588dff5f9b4e92eaf6ad4ab6f1cd720d192eb58247a"), q0_y: hex!("c7371dcd0134412f221e386f8d68f49e7fa36f9037676e163d4a063fbf8a1fb8"), q1_x: hex!("10fee3284d7be6bd5912503b972fc52bf4761f47141a0015f1c6ae36848d869b"), q1_y: hex!("0b163d9b4bf21887364332be3eff3c870fa053cf508732900fc69a6eb0e1b672"), }, TestVector { msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", p_x: hex!("e3c8d35aaaf0b9b647e88a0a0a7ee5d5bed5ad38238152e4e6fd8c1f8cb7c998"), p_y: hex!("8446eeb6181bf12f56a9d24e262221cc2f0c4725c7e3803024b5888ee5823aa6"), u_0: hex!("8d862e7e7e23d7843fe16d811d46d7e6480127a6b78838c277bca17df6900e9f"), u_1: hex!("68071d2530f040f081ba818d3c7188a94c900586761e9115efa47ae9bd847938"), q0_x: hex!("b32b0ab55977b936f1e93fdc68cec775e13245e161dbfe556bbb1f72799b4181"), q0_y: hex!("2f5317098360b722f132d7156a94822641b615c91f8663be69169870a12af9e8"), q1_x: hex!("148f98780f19388b9fa93e7dc567b5a673e5fca7079cd9cdafd71982ec4c5e12"), q1_y: hex!("3989645d83a433bc0c001f3dac29af861f33a6fd1e04f4b36873f5bff497298a"), }, ]; for test_vector in TEST_VECTORS { // in parts let mut u = [FieldElement::default(), FieldElement::default()]; hash2curve::hash_to_field::, FieldElement>( &[test_vector.msg], &[DST], &mut u, ) .unwrap(); assert_eq!(u[0].to_bytes().as_slice(), test_vector.u_0); assert_eq!(u[1].to_bytes().as_slice(), test_vector.u_1); let q0 = u[0].map_to_curve(); let aq0 = q0.to_affine(); assert_eq!(aq0.x.to_bytes().as_slice(), test_vector.q0_x); assert_eq!(aq0.y.to_bytes().as_slice(), test_vector.q0_y); let q1 = u[1].map_to_curve(); let aq1 = q1.to_affine(); assert_eq!(aq1.x.to_bytes().as_slice(), test_vector.q1_x); assert_eq!(aq1.y.to_bytes().as_slice(), test_vector.q1_y); let p = q0.clear_cofactor() + q1.clear_cofactor(); let ap = p.to_affine(); assert_eq!(ap.x.to_bytes().as_slice(), test_vector.p_x); assert_eq!(ap.y.to_bytes().as_slice(), test_vector.p_y); // complete run let pt = Secp256k1::hash_from_bytes::>(&[test_vector.msg], &[DST]) .unwrap(); let apt = pt.to_affine(); assert_eq!(apt.x.to_bytes().as_slice(), test_vector.p_x); assert_eq!(apt.y.to_bytes().as_slice(), test_vector.p_y); } } #[test] fn from_okm_fuzz() { let mut wide_order = GenericArray::default(); wide_order[16..].copy_from_slice(&Secp256k1::ORDER.to_be_byte_array()); let wide_order = NonZero::new(U384::from_be_byte_array(wide_order)).unwrap(); let simple_from_okm = move |data: GenericArray| -> Scalar { let data = U384::from_be_slice(&data); let scalar = data % wide_order; let reduced_scalar = U256::from_be_slice(&scalar.to_be_byte_array()[16..]); Scalar(reduced_scalar) }; proptest!(ProptestConfig::with_cases(1000), |(b0 in ANY, b1 in ANY, b2 in ANY, b3 in ANY, b4 in ANY, b5 in ANY)| { let mut data = GenericArray::default(); data[..8].copy_from_slice(&b0.to_be_bytes()); data[8..16].copy_from_slice(&b1.to_be_bytes()); data[16..24].copy_from_slice(&b2.to_be_bytes()); data[24..32].copy_from_slice(&b3.to_be_bytes()); data[32..40].copy_from_slice(&b4.to_be_bytes()); data[40..].copy_from_slice(&b5.to_be_bytes()); let from_okm = Scalar::from_okm(&data); let simple_from_okm = simple_from_okm(data); assert_eq!(from_okm, simple_from_okm); }); } } k256-0.13.3/src/arithmetic/mul.rs000064400000000000000000000375661046102023000145030ustar 00000000000000//! From libsecp256k1: //! //! The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where //! lambda is {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a, //! 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72} //! //! "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm //! (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1 //! and k2 have a small size. //! It relies on constants a1, b1, a2, b2. These constants for the value of lambda above are: //! //! - a1 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} //! - b1 = -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3} //! - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8} //! - b2 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} //! //! The algorithm then computes c1 = round(b1 * k / n) and c2 = round(b2 * k / n), and gives //! k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and //! compute k1 as k - k2 * lambda, avoiding the need for constants a1 and a2. //! //! g1, g2 are precomputed constants used to replace division with a rounded multiplication //! when decomposing the scalar for an endomorphism-based point multiplication. //! //! The possibility of using precomputed estimates is mentioned in "Guide to Elliptic Curve //! Cryptography" (Hankerson, Menezes, Vanstone) in section 3.5. //! //! The derivation is described in the paper "Efficient Software Implementation of Public-Key //! Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez), //! Section 4.3 (here we use a somewhat higher-precision estimate): //! d = a1*b2 - b1*a2 //! g1 = round((2^384)*b2/d) //! g2 = round((2^384)*(-b1)/d) //! //! (Note that 'd' is also equal to the curve order here because `[a1,b1]` and `[a2,b2]` are found //! as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda'). #[cfg(all( feature = "precomputed-tables", not(any(feature = "critical-section", feature = "std")) ))] compile_error!("`precomputed-tables` feature requires either `critical-section` or `std`"); use crate::arithmetic::{ scalar::{Scalar, WideScalar}, ProjectivePoint, }; use core::ops::{Mul, MulAssign}; use elliptic_curve::ops::LinearCombinationExt as LinearCombination; use elliptic_curve::{ ops::MulByGenerator, scalar::IsHigh, subtle::{Choice, ConditionallySelectable, ConstantTimeEq}, }; #[cfg(feature = "precomputed-tables")] use once_cell::sync::Lazy; /// Lookup table containing precomputed values `[p, 2p, 3p, ..., 8p]` #[derive(Copy, Clone, Default)] struct LookupTable([ProjectivePoint; 8]); impl From<&ProjectivePoint> for LookupTable { fn from(p: &ProjectivePoint) -> Self { let mut points = [*p; 8]; for j in 0..7 { points[j + 1] = p + &points[j]; } LookupTable(points) } } impl LookupTable { /// Given -8 <= x <= 8, returns x * p in constant time. fn select(&self, x: i8) -> ProjectivePoint { debug_assert!(x >= -8); debug_assert!(x <= 8); // Compute xabs = |x| let xmask = x >> 7; let xabs = (x + xmask) ^ xmask; // Get an array element in constant time let mut t = ProjectivePoint::IDENTITY; for j in 1..9 { let c = (xabs as u8).ct_eq(&(j as u8)); t.conditional_assign(&self.0[j - 1], c); } // Now t == |x| * p. let neg_mask = Choice::from((xmask & 1) as u8); t.conditional_assign(&-t, neg_mask); // Now t == x * p. t } } const MINUS_LAMBDA: Scalar = Scalar::from_bytes_unchecked(&[ 0xac, 0x9c, 0x52, 0xb3, 0x3f, 0xa3, 0xcf, 0x1f, 0x5a, 0xd9, 0xe3, 0xfd, 0x77, 0xed, 0x9b, 0xa4, 0xa8, 0x80, 0xb9, 0xfc, 0x8e, 0xc7, 0x39, 0xc2, 0xe0, 0xcf, 0xc8, 0x10, 0xb5, 0x12, 0x83, 0xcf, ]); const MINUS_B1: Scalar = Scalar::from_bytes_unchecked(&[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x43, 0x7e, 0xd6, 0x01, 0x0e, 0x88, 0x28, 0x6f, 0x54, 0x7f, 0xa9, 0x0a, 0xbf, 0xe4, 0xc3, ]); const MINUS_B2: Scalar = Scalar::from_bytes_unchecked(&[ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x8a, 0x28, 0x0a, 0xc5, 0x07, 0x74, 0x34, 0x6d, 0xd7, 0x65, 0xcd, 0xa8, 0x3d, 0xb1, 0x56, 0x2c, ]); const G1: Scalar = Scalar::from_bytes_unchecked(&[ 0x30, 0x86, 0xd2, 0x21, 0xa7, 0xd4, 0x6b, 0xcd, 0xe8, 0x6c, 0x90, 0xe4, 0x92, 0x84, 0xeb, 0x15, 0x3d, 0xaa, 0x8a, 0x14, 0x71, 0xe8, 0xca, 0x7f, 0xe8, 0x93, 0x20, 0x9a, 0x45, 0xdb, 0xb0, 0x31, ]); const G2: Scalar = Scalar::from_bytes_unchecked(&[ 0xe4, 0x43, 0x7e, 0xd6, 0x01, 0x0e, 0x88, 0x28, 0x6f, 0x54, 0x7f, 0xa9, 0x0a, 0xbf, 0xe4, 0xc4, 0x22, 0x12, 0x08, 0xac, 0x9d, 0xf5, 0x06, 0xc6, 0x15, 0x71, 0xb4, 0xae, 0x8a, 0xc4, 0x7f, 0x71, ]); /* * Proof for decompose_scalar's bounds. * * Let * - epsilon1 = 2^256 * |g1/2^384 - b2/d| * - epsilon2 = 2^256 * |g2/2^384 - (-b1)/d| * - c1 = round(k*g1/2^384) * - c2 = round(k*g2/2^384) * * Lemma 1: |c1 - k*b2/d| < 2^-1 + epsilon1 * * |c1 - k*b2/d| * = * |c1 - k*g1/2^384 + k*g1/2^384 - k*b2/d| * <= {triangle inequality} * |c1 - k*g1/2^384| + |k*g1/2^384 - k*b2/d| * = * |c1 - k*g1/2^384| + k*|g1/2^384 - b2/d| * < {rounding in c1 and 0 <= k < 2^256} * 2^-1 + 2^256 * |g1/2^384 - b2/d| * = {definition of epsilon1} * 2^-1 + epsilon1 * * Lemma 2: |c2 - k*(-b1)/d| < 2^-1 + epsilon2 * * |c2 - k*(-b1)/d| * = * |c2 - k*g2/2^384 + k*g2/2^384 - k*(-b1)/d| * <= {triangle inequality} * |c2 - k*g2/2^384| + |k*g2/2^384 - k*(-b1)/d| * = * |c2 - k*g2/2^384| + k*|g2/2^384 - (-b1)/d| * < {rounding in c2 and 0 <= k < 2^256} * 2^-1 + 2^256 * |g2/2^384 - (-b1)/d| * = {definition of epsilon2} * 2^-1 + epsilon2 * * Let * - k1 = k - c1*a1 - c2*a2 * - k2 = - c1*b1 - c2*b2 * * Lemma 3: |k1| < (a1 + a2 + 1)/2 < 2^128 * * |k1| * = {definition of k1} * |k - c1*a1 - c2*a2| * = {(a1*b2 - b1*a2)/n = 1} * |k*(a1*b2 - b1*a2)/n - c1*a1 - c2*a2| * = * |a1*(k*b2/n - c1) + a2*(k*(-b1)/n - c2)| * <= {triangle inequality} * a1*|k*b2/n - c1| + a2*|k*(-b1)/n - c2| * < {Lemma 1 and Lemma 2} * a1*(2^-1 + epslion1) + a2*(2^-1 + epsilon2) * < {rounding up to an integer} * (a1 + a2 + 1)/2 * < {rounding up to a power of 2} * 2^128 * * Lemma 4: |k2| < (-b1 + b2)/2 + 1 < 2^128 * * |k2| * = {definition of k2} * |- c1*a1 - c2*a2| * = {(b1*b2 - b1*b2)/n = 0} * |k*(b1*b2 - b1*b2)/n - c1*b1 - c2*b2| * = * |b1*(k*b2/n - c1) + b2*(k*(-b1)/n - c2)| * <= {triangle inequality} * (-b1)*|k*b2/n - c1| + b2*|k*(-b1)/n - c2| * < {Lemma 1 and Lemma 2} * (-b1)*(2^-1 + epslion1) + b2*(2^-1 + epsilon2) * < {rounding up to an integer} * (-b1 + b2)/2 + 1 * < {rounding up to a power of 2} * 2^128 * * Let * - r2 = k2 mod n * - r1 = k - r2*lambda mod n. * * Notice that r1 is defined such that r1 + r2 * lambda == k (mod n). * * Lemma 5: r1 == k1 mod n. * * r1 * == {definition of r1 and r2} * k - k2*lambda * == {definition of k2} * k - (- c1*b1 - c2*b2)*lambda * == * k + c1*b1*lambda + c2*b2*lambda * == {a1 + b1*lambda == 0 mod n and a2 + b2*lambda == 0 mod n} * k - c1*a1 - c2*a2 * == {definition of k1} * k1 * * From Lemma 3, Lemma 4, Lemma 5 and the definition of r2, we can conclude that * * - either r1 < 2^128 or -r1 mod n < 2^128 * - either r2 < 2^128 or -r2 mod n < 2^128. * * Q.E.D. */ /// Find r1 and r2 given k, such that r1 + r2 * lambda == k mod n. fn decompose_scalar(k: &Scalar) -> (Scalar, Scalar) { // these _vartime calls are constant time since the shift amount is constant let c1 = WideScalar::mul_shift_vartime(k, &G1, 384) * MINUS_B1; let c2 = WideScalar::mul_shift_vartime(k, &G2, 384) * MINUS_B2; let r2 = c1 + c2; let r1 = k + r2 * MINUS_LAMBDA; (r1, r2) } // This needs to be an object to have Default implemented for it // (required because it's used in static_map later) // Otherwise we could just have a function returning an array. #[derive(Copy, Clone)] struct Radix16Decomposition([i8; D]); impl Radix16Decomposition { /// Returns an object containing a decomposition /// `[a_0, ..., a_D]` such that `sum(a_j * 2^(j * 4)) == x`, /// and `-8 <= a_j <= 7`. /// Assumes `x < 2^(4*(D-1))`. fn new(x: &Scalar) -> Self { debug_assert!((x >> (4 * (D - 1))).is_zero().unwrap_u8() == 1); // The resulting decomposition can be negative, so, despite the limit on `x`, // we need an additional byte to store the carry. let mut output = [0i8; D]; // Step 1: change radix. // Convert from radix 256 (bytes) to radix 16 (nibbles) let bytes = x.to_bytes(); for i in 0..(D - 1) / 2 { output[2 * i] = (bytes[31 - i] & 0xf) as i8; output[2 * i + 1] = ((bytes[31 - i] >> 4) & 0xf) as i8; } // Step 2: recenter coefficients from [0,16) to [-8,8) for i in 0..(D - 1) { let carry = (output[i] + 8) >> 4; output[i] -= carry << 4; output[i + 1] += carry; } Self(output) } } impl Default for Radix16Decomposition { fn default() -> Self { Self([0i8; D]) } } impl LinearCombination<[(ProjectivePoint, Scalar); N]> for ProjectivePoint { fn lincomb_ext(points_and_scalars: &[(ProjectivePoint, Scalar); N]) -> Self { let mut tables = [(LookupTable::default(), LookupTable::default()); N]; let mut digits = [( Radix16Decomposition::<33>::default(), Radix16Decomposition::<33>::default(), ); N]; lincomb(points_and_scalars, &mut tables, &mut digits) } } #[cfg(feature = "alloc")] impl LinearCombination<[(ProjectivePoint, Scalar)]> for ProjectivePoint { fn lincomb_ext(points_and_scalars: &[(ProjectivePoint, Scalar)]) -> Self { let mut tables = vec![(LookupTable::default(), LookupTable::default()); points_and_scalars.len()]; let mut digits = vec![ ( Radix16Decomposition::<33>::default(), Radix16Decomposition::<33>::default(), ); points_and_scalars.len() ]; lincomb(points_and_scalars, &mut tables, &mut digits) } } fn lincomb( xks: &[(ProjectivePoint, Scalar)], tables: &mut [(LookupTable, LookupTable)], digits: &mut [(Radix16Decomposition<33>, Radix16Decomposition<33>)], ) -> ProjectivePoint { xks.iter().enumerate().for_each(|(i, (x, k))| { let (r1, r2) = decompose_scalar(k); let x_beta = x.endomorphism(); let (r1_sign, r2_sign) = (r1.is_high(), r2.is_high()); let (r1_c, r2_c) = ( Scalar::conditional_select(&r1, &-r1, r1_sign), Scalar::conditional_select(&r2, &-r2, r2_sign), ); tables[i] = ( LookupTable::from(&ProjectivePoint::conditional_select(x, &-*x, r1_sign)), LookupTable::from(&ProjectivePoint::conditional_select( &x_beta, &-x_beta, r2_sign, )), ); digits[i] = ( Radix16Decomposition::<33>::new(&r1_c), Radix16Decomposition::<33>::new(&r2_c), ) }); let mut acc = ProjectivePoint::IDENTITY; for component in 0..xks.len() { let (digit1, digit2) = digits[component]; let (table1, table2) = tables[component]; acc += &table1.select(digit1.0[32]); acc += &table2.select(digit2.0[32]); } for i in (0..32).rev() { for _j in 0..4 { acc = acc.double(); } for component in 0..xks.len() { let (digit1, digit2) = digits[component]; let (table1, table2) = tables[component]; acc += &table1.select(digit1.0[i]); acc += &table2.select(digit2.0[i]); } } acc } /// Lazily computed basepoint table. #[cfg(feature = "precomputed-tables")] static GEN_LOOKUP_TABLE: Lazy<[LookupTable; 33]> = Lazy::new(precompute_gen_lookup_table); #[cfg(feature = "precomputed-tables")] fn precompute_gen_lookup_table() -> [LookupTable; 33] { let mut gen = ProjectivePoint::GENERATOR; let mut res = [LookupTable::default(); 33]; for i in 0..33 { res[i] = LookupTable::from(&gen); // We are storing tables spaced by two radix steps, // to decrease the size of the precomputed data. for _ in 0..8 { gen = gen.double(); } } res } impl MulByGenerator for ProjectivePoint { /// Calculates `k * G`, where `G` is the generator. #[cfg(not(feature = "precomputed-tables"))] fn mul_by_generator(k: &Scalar) -> ProjectivePoint { ProjectivePoint::GENERATOR * k } /// Calculates `k * G`, where `G` is the generator. #[cfg(feature = "precomputed-tables")] fn mul_by_generator(k: &Scalar) -> ProjectivePoint { let digits = Radix16Decomposition::<65>::new(k); let table = *GEN_LOOKUP_TABLE; let mut acc = table[32].select(digits.0[64]); let mut acc2 = ProjectivePoint::IDENTITY; for i in (0..32).rev() { acc2 += &table[i].select(digits.0[i * 2 + 1]); acc += &table[i].select(digits.0[i * 2]); } // This is the price of halving the precomputed table size (from 60kb to 30kb) // The performance hit is minor, about 3%. for _ in 0..4 { acc2 = acc2.double(); } acc + acc2 } } #[inline(always)] fn mul(x: &ProjectivePoint, k: &Scalar) -> ProjectivePoint { ProjectivePoint::lincomb_ext(&[(*x, *k)]) } impl Mul for ProjectivePoint { type Output = ProjectivePoint; fn mul(self, other: Scalar) -> ProjectivePoint { mul(&self, &other) } } impl Mul<&Scalar> for &ProjectivePoint { type Output = ProjectivePoint; fn mul(self, other: &Scalar) -> ProjectivePoint { mul(self, other) } } impl Mul<&Scalar> for ProjectivePoint { type Output = ProjectivePoint; fn mul(self, other: &Scalar) -> ProjectivePoint { mul(&self, other) } } impl MulAssign for ProjectivePoint { fn mul_assign(&mut self, rhs: Scalar) { *self = mul(self, &rhs); } } impl MulAssign<&Scalar> for ProjectivePoint { fn mul_assign(&mut self, rhs: &Scalar) { *self = mul(self, rhs); } } #[cfg(test)] mod tests { use super::*; use crate::arithmetic::{ProjectivePoint, Scalar}; use elliptic_curve::{ ops::{LinearCombination as _, MulByGenerator}, rand_core::OsRng, Field, Group, }; #[test] fn test_lincomb() { let x = ProjectivePoint::random(&mut OsRng); let y = ProjectivePoint::random(&mut OsRng); let k = Scalar::random(&mut OsRng); let l = Scalar::random(&mut OsRng); let reference = &x * &k + &y * &l; let test = ProjectivePoint::lincomb(&x, &k, &y, &l); assert_eq!(reference, test); } #[test] fn test_mul_by_generator() { let k = Scalar::random(&mut OsRng); let reference = &ProjectivePoint::GENERATOR * &k; let test = ProjectivePoint::mul_by_generator(&k); assert_eq!(reference, test); } #[cfg(feature = "alloc")] #[test] fn test_lincomb_slice() { let x = ProjectivePoint::random(&mut OsRng); let y = ProjectivePoint::random(&mut OsRng); let k = Scalar::random(&mut OsRng); let l = Scalar::random(&mut OsRng); let reference = &x * &k + &y * &l; let points_and_scalars = vec![(x, k), (y, l)]; let test = ProjectivePoint::lincomb_ext(points_and_scalars.as_slice()); assert_eq!(reference, test); } } k256-0.13.3/src/arithmetic/projective.rs000064400000000000000000000700421046102023000160420ustar 00000000000000//! Projective points #![allow(clippy::op_ref)] use super::{AffinePoint, FieldElement, Scalar, CURVE_EQUATION_B_SINGLE}; use crate::{CompressedPoint, EncodedPoint, PublicKey, Secp256k1}; use core::{ iter::Sum, ops::{Add, AddAssign, Neg, Sub, SubAssign}, }; use elliptic_curve::ops::BatchInvert; use elliptic_curve::{ group::{ ff::Field, prime::{PrimeCurve, PrimeCurveAffine, PrimeGroup}, Curve, Group, GroupEncoding, }, rand_core::RngCore, sec1::{FromEncodedPoint, ToEncodedPoint}, subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, zeroize::DefaultIsZeroes, BatchNormalize, Error, Result, }; #[cfg(feature = "alloc")] use alloc::vec::Vec; #[rustfmt::skip] const ENDOMORPHISM_BETA: FieldElement = FieldElement::from_bytes_unchecked(&[ 0x7a, 0xe9, 0x6a, 0x2b, 0x65, 0x7c, 0x07, 0x10, 0x6e, 0x64, 0x47, 0x9e, 0xac, 0x34, 0x34, 0xe9, 0x9c, 0xf0, 0x49, 0x75, 0x12, 0xf5, 0x89, 0x95, 0xc1, 0x39, 0x6c, 0x28, 0x71, 0x95, 0x01, 0xee, ]); /// A point on the secp256k1 curve in projective coordinates. #[derive(Clone, Copy, Debug)] pub struct ProjectivePoint { x: FieldElement, y: FieldElement, pub(super) z: FieldElement, } impl ProjectivePoint { /// Additive identity of the group: the point at infinity. pub const IDENTITY: Self = Self { x: FieldElement::ZERO, y: FieldElement::ONE, z: FieldElement::ZERO, }; /// Base point of secp256k1. pub const GENERATOR: Self = Self { x: AffinePoint::GENERATOR.x, y: AffinePoint::GENERATOR.y, z: FieldElement::ONE, }; /// Returns the additive identity of SECP256k1, also known as the "neutral element" or /// "point at infinity". #[deprecated(since = "0.10.2", note = "use `ProjectivePoint::IDENTITY` instead")] pub const fn identity() -> ProjectivePoint { Self::IDENTITY } /// Returns the base point of SECP256k1. #[deprecated(since = "0.10.2", note = "use `ProjectivePoint::GENERATOR` instead")] pub fn generator() -> ProjectivePoint { Self::GENERATOR } /// Returns the affine representation of this point. pub fn to_affine(&self) -> AffinePoint { self.z .invert() .map(|zinv| self.to_affine_internal(zinv)) .unwrap_or_else(|| AffinePoint::IDENTITY) } pub(super) fn to_affine_internal(self, zinv: FieldElement) -> AffinePoint { let x = self.x * &zinv; let y = self.y * &zinv; AffinePoint::new(x.normalize(), y.normalize()) } /// Returns `-self`. fn neg(&self) -> ProjectivePoint { ProjectivePoint { x: self.x, y: self.y.negate(1).normalize_weak(), z: self.z, } } /// Returns `self + other`. fn add(&self, other: &ProjectivePoint) -> ProjectivePoint { // We implement the complete addition formula from Renes-Costello-Batina 2015 // (https://eprint.iacr.org/2015/1060 Algorithm 7). let xx = self.x * &other.x; let yy = self.y * &other.y; let zz = self.z * &other.z; let n_xx_yy = (xx + &yy).negate(2); let n_yy_zz = (yy + &zz).negate(2); let n_xx_zz = (xx + &zz).negate(2); let xy_pairs = ((self.x + &self.y) * &(other.x + &other.y)) + &n_xx_yy; let yz_pairs = ((self.y + &self.z) * &(other.y + &other.z)) + &n_yy_zz; let xz_pairs = ((self.x + &self.z) * &(other.x + &other.z)) + &n_xx_zz; let bzz = zz.mul_single(CURVE_EQUATION_B_SINGLE); let bzz3 = (bzz.double() + &bzz).normalize_weak(); let yy_m_bzz3 = yy + &bzz3.negate(1); let yy_p_bzz3 = yy + &bzz3; let byz = &yz_pairs .mul_single(CURVE_EQUATION_B_SINGLE) .normalize_weak(); let byz3 = (byz.double() + byz).normalize_weak(); let xx3 = xx.double() + &xx; let bxx9 = (xx3.double() + &xx3) .normalize_weak() .mul_single(CURVE_EQUATION_B_SINGLE) .normalize_weak(); let new_x = ((xy_pairs * &yy_m_bzz3) + &(byz3 * &xz_pairs).negate(1)).normalize_weak(); // m1 let new_y = ((yy_p_bzz3 * &yy_m_bzz3) + &(bxx9 * &xz_pairs)).normalize_weak(); let new_z = ((yz_pairs * &yy_p_bzz3) + &(xx3 * &xy_pairs)).normalize_weak(); ProjectivePoint { x: new_x, y: new_y, z: new_z, } } /// Returns `self + other`. fn add_mixed(&self, other: &AffinePoint) -> ProjectivePoint { // We implement the complete addition formula from Renes-Costello-Batina 2015 // (https://eprint.iacr.org/2015/1060 Algorithm 8). let xx = self.x * &other.x; let yy = self.y * &other.y; let xy_pairs = ((self.x + &self.y) * &(other.x + &other.y)) + &(xx + &yy).negate(2); let yz_pairs = (other.y * &self.z) + &self.y; let xz_pairs = (other.x * &self.z) + &self.x; let bzz = &self.z.mul_single(CURVE_EQUATION_B_SINGLE); let bzz3 = (bzz.double() + bzz).normalize_weak(); let yy_m_bzz3 = yy + &bzz3.negate(1); let yy_p_bzz3 = yy + &bzz3; let byz = &yz_pairs .mul_single(CURVE_EQUATION_B_SINGLE) .normalize_weak(); let byz3 = (byz.double() + byz).normalize_weak(); let xx3 = xx.double() + &xx; let bxx9 = &(xx3.double() + &xx3) .normalize_weak() .mul_single(CURVE_EQUATION_B_SINGLE) .normalize_weak(); let mut ret = ProjectivePoint { x: ((xy_pairs * &yy_m_bzz3) + &(byz3 * &xz_pairs).negate(1)).normalize_weak(), y: ((yy_p_bzz3 * &yy_m_bzz3) + &(bxx9 * &xz_pairs)).normalize_weak(), z: ((yz_pairs * &yy_p_bzz3) + &(xx3 * &xy_pairs)).normalize_weak(), }; ret.conditional_assign(self, other.is_identity()); ret } /// Doubles this point. #[inline] pub fn double(&self) -> ProjectivePoint { // We implement the complete addition formula from Renes-Costello-Batina 2015 // (https://eprint.iacr.org/2015/1060 Algorithm 9). let yy = self.y.square(); let zz = self.z.square(); let xy2 = (self.x * &self.y).double(); let bzz = &zz.mul_single(CURVE_EQUATION_B_SINGLE); let bzz3 = (bzz.double() + bzz).normalize_weak(); let bzz9 = (bzz3.double() + &bzz3).normalize_weak(); let yy_m_bzz9 = yy + &bzz9.negate(1); let yy_p_bzz3 = yy + &bzz3; let yy_zz = yy * &zz; let yy_zz8 = yy_zz.double().double().double(); let t = (yy_zz8.double() + &yy_zz8) .normalize_weak() .mul_single(CURVE_EQUATION_B_SINGLE); ProjectivePoint { x: xy2 * &yy_m_bzz9, y: ((yy_m_bzz9 * &yy_p_bzz3) + &t).normalize_weak(), z: ((yy * &self.y) * &self.z) .double() .double() .double() .normalize_weak(), } } /// Returns `self - other`. fn sub(&self, other: &ProjectivePoint) -> ProjectivePoint { self.add(&other.neg()) } /// Returns `self - other`. fn sub_mixed(&self, other: &AffinePoint) -> ProjectivePoint { self.add_mixed(&other.neg()) } /// Calculates SECP256k1 endomorphism: `self * lambda`. pub fn endomorphism(&self) -> Self { Self { x: self.x * &ENDOMORPHISM_BETA, y: self.y, z: self.z, } } /// Check whether `self` is equal to an affine point. /// /// This is a lot faster than first converting `self` to an `AffinePoint` and then doing the /// comparison. It is a little bit faster than converting `other` to a `ProjectivePoint` first. pub fn eq_affine(&self, other: &AffinePoint) -> Choice { // For understanding of this algorithm see Projective equality comment. It's the same except // that we know z = 1 for rhs and we have to check identity as a separate case. let both_identity = self.is_identity() & other.is_identity(); let rhs_identity = other.is_identity(); let rhs_x = &other.x * &self.z; let x_eq = rhs_x.negate(1).add(&self.x).normalizes_to_zero(); let rhs_y = &other.y * &self.z; let y_eq = rhs_y.negate(1).add(&self.y).normalizes_to_zero(); both_identity | (!rhs_identity & x_eq & y_eq) } } impl From for ProjectivePoint { fn from(p: AffinePoint) -> Self { let projective = ProjectivePoint { x: p.x, y: p.y, z: FieldElement::ONE, }; Self::conditional_select(&projective, &Self::IDENTITY, p.is_identity()) } } impl BatchNormalize<[ProjectivePoint; N]> for ProjectivePoint { type Output = [Self::AffineRepr; N]; #[inline] fn batch_normalize(points: &[Self; N]) -> [Self::AffineRepr; N] { let mut zs = [FieldElement::ONE; N]; let mut affine_points = [AffinePoint::IDENTITY; N]; batch_normalize_generic(points, &mut zs, &mut affine_points); affine_points } } #[cfg(feature = "alloc")] impl BatchNormalize<[ProjectivePoint]> for ProjectivePoint { type Output = Vec; #[inline] fn batch_normalize(points: &[Self]) -> Vec { let mut zs = vec![FieldElement::ONE; points.len()]; let mut affine_points = vec![AffinePoint::IDENTITY; points.len()]; batch_normalize_generic(points, zs.as_mut_slice(), &mut affine_points); affine_points } } fn batch_normalize_generic(points: &P, zs: &mut Z, out: &mut O) where FieldElement: BatchInvert, P: AsRef<[ProjectivePoint]> + ?Sized, Z: AsMut<[FieldElement]> + ?Sized, O: AsMut<[AffinePoint]> + ?Sized, { let points = points.as_ref(); let out = out.as_mut(); for i in 0..points.len() { // Even a single zero value will fail inversion for the entire batch. // Put a dummy value (above `FieldElement::ONE`) so inversion succeeds // and treat that case specially later-on. zs.as_mut()[i].conditional_assign(&points[i].z, !points[i].z.ct_eq(&FieldElement::ZERO)); } // This is safe to unwrap since we assured that all elements are non-zero let zs_inverses = >::batch_invert(zs).unwrap(); for i in 0..out.len() { // If the `z` coordinate is non-zero, we can use it to invert; // otherwise it defaults to the `IDENTITY` value. out[i] = AffinePoint::conditional_select( &points[i].to_affine_internal(zs_inverses.as_ref()[i]), &AffinePoint::IDENTITY, points[i].z.ct_eq(&FieldElement::ZERO), ); } } impl From<&AffinePoint> for ProjectivePoint { fn from(p: &AffinePoint) -> Self { Self::from(*p) } } impl From for AffinePoint { fn from(p: ProjectivePoint) -> AffinePoint { p.to_affine() } } impl From<&ProjectivePoint> for AffinePoint { fn from(p: &ProjectivePoint) -> AffinePoint { p.to_affine() } } impl FromEncodedPoint for ProjectivePoint { fn from_encoded_point(p: &EncodedPoint) -> CtOption { AffinePoint::from_encoded_point(p).map(ProjectivePoint::from) } } impl ToEncodedPoint for ProjectivePoint { fn to_encoded_point(&self, compress: bool) -> EncodedPoint { self.to_affine().to_encoded_point(compress) } } impl ConditionallySelectable for ProjectivePoint { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { ProjectivePoint { x: FieldElement::conditional_select(&a.x, &b.x, choice), y: FieldElement::conditional_select(&a.y, &b.y, choice), z: FieldElement::conditional_select(&a.z, &b.z, choice), } } } impl ConstantTimeEq for ProjectivePoint { fn ct_eq(&self, other: &Self) -> Choice { // If both points are not equal to inifinity then they are in the form: // // lhs: (x₁z₁, y₁z₁, z₁), rhs: (x₂z₂, y₂z₂, z₂) where z₁ ≠ 0 and z₂ ≠ 0. // we want to know if x₁ == x₂ and y₁ == y₂ // So we multiply the x and y by the opposing z to get: // lhs: (x₁z₁z₂, y₁z₁z₂) rhs: (x₂z₁z₂, y₂z₁z₂) // and check lhs == rhs which implies x₁ == x₂ and y₁ == y₂. // // If one point is infinity it is always in the form (0, y, 0). Note that the above // algorithm still works here. If They are both infinity then they'll both evaluate to (0,0). // If for example the first point is infinity then the above will evaluate to (z₂ * 0, z₂ * // y₂) = (0, z₂y₂) for the first point and (0 * x₂z₂, 0 * y₂z₂) = (0, 0) for the second. // // Since z₂y₂ will never be 0 they will not be equal in this case either. let lhs_x = self.x * &other.z; let rhs_x = other.x * &self.z; let x_eq = rhs_x.negate(1).add(&lhs_x).normalizes_to_zero(); let lhs_y = self.y * &other.z; let rhs_y = other.y * &self.z; let y_eq = rhs_y.negate(1).add(&lhs_y).normalizes_to_zero(); x_eq & y_eq } } impl PartialEq for ProjectivePoint { fn eq(&self, other: &Self) -> bool { self.ct_eq(other).into() } } impl PartialEq for ProjectivePoint { fn eq(&self, other: &AffinePoint) -> bool { self.eq_affine(other).into() } } impl PartialEq for AffinePoint { fn eq(&self, other: &ProjectivePoint) -> bool { other.eq_affine(self).into() } } impl Eq for ProjectivePoint {} impl Group for ProjectivePoint { type Scalar = Scalar; fn random(mut rng: impl RngCore) -> Self { Self::GENERATOR * Scalar::random(&mut rng) } fn identity() -> Self { Self::IDENTITY } fn generator() -> Self { Self::GENERATOR } fn is_identity(&self) -> Choice { self.z.normalizes_to_zero() } #[must_use] fn double(&self) -> Self { Self::double(self) } } impl 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 { // No unchecked conversion possible for compressed points Self::from_bytes(bytes) } fn to_bytes(&self) -> Self::Repr { self.to_affine().to_bytes() } } impl PrimeGroup for ProjectivePoint {} impl Curve for ProjectivePoint { type AffineRepr = AffinePoint; fn to_affine(&self) -> AffinePoint { ProjectivePoint::to_affine(self) } #[cfg(feature = "alloc")] #[inline] fn batch_normalize(projective: &[Self], affine: &mut [Self::AffineRepr]) { assert_eq!(projective.len(), affine.len()); let mut zs = vec![FieldElement::ONE; projective.len()]; batch_normalize_generic(projective, zs.as_mut_slice(), affine); } } impl PrimeCurve for ProjectivePoint { type Affine = AffinePoint; } impl Default for ProjectivePoint { fn default() -> Self { Self::IDENTITY } } impl DefaultIsZeroes for ProjectivePoint {} impl Add<&ProjectivePoint> for &ProjectivePoint { type Output = ProjectivePoint; fn add(self, other: &ProjectivePoint) -> ProjectivePoint { ProjectivePoint::add(self, other) } } impl Add for ProjectivePoint { type Output = ProjectivePoint; fn add(self, other: ProjectivePoint) -> ProjectivePoint { ProjectivePoint::add(&self, &other) } } impl Add<&ProjectivePoint> for ProjectivePoint { type Output = ProjectivePoint; fn add(self, other: &ProjectivePoint) -> ProjectivePoint { ProjectivePoint::add(&self, other) } } impl AddAssign for ProjectivePoint { fn add_assign(&mut self, rhs: ProjectivePoint) { *self = ProjectivePoint::add(self, &rhs); } } impl AddAssign<&ProjectivePoint> for ProjectivePoint { fn add_assign(&mut self, rhs: &ProjectivePoint) { *self = ProjectivePoint::add(self, rhs); } } impl Add for ProjectivePoint { type Output = ProjectivePoint; fn add(self, other: AffinePoint) -> ProjectivePoint { ProjectivePoint::add_mixed(&self, &other) } } impl Add<&AffinePoint> for &ProjectivePoint { type Output = ProjectivePoint; fn add(self, other: &AffinePoint) -> ProjectivePoint { ProjectivePoint::add_mixed(self, other) } } impl Add<&AffinePoint> for ProjectivePoint { type Output = ProjectivePoint; fn add(self, other: &AffinePoint) -> ProjectivePoint { ProjectivePoint::add_mixed(&self, other) } } impl AddAssign for ProjectivePoint { fn add_assign(&mut self, rhs: AffinePoint) { *self = ProjectivePoint::add_mixed(self, &rhs); } } impl AddAssign<&AffinePoint> for ProjectivePoint { fn add_assign(&mut self, rhs: &AffinePoint) { *self = ProjectivePoint::add_mixed(self, rhs); } } impl Sum for ProjectivePoint { fn sum>(iter: I) -> Self { iter.fold(ProjectivePoint::IDENTITY, |a, b| a + b) } } impl<'a> Sum<&'a ProjectivePoint> for ProjectivePoint { fn sum>(iter: I) -> Self { iter.cloned().sum() } } impl Sub for ProjectivePoint { type Output = ProjectivePoint; fn sub(self, other: ProjectivePoint) -> ProjectivePoint { ProjectivePoint::sub(&self, &other) } } impl Sub<&ProjectivePoint> for &ProjectivePoint { type Output = ProjectivePoint; fn sub(self, other: &ProjectivePoint) -> ProjectivePoint { ProjectivePoint::sub(self, other) } } impl Sub<&ProjectivePoint> for ProjectivePoint { type Output = ProjectivePoint; fn sub(self, other: &ProjectivePoint) -> ProjectivePoint { ProjectivePoint::sub(&self, other) } } impl SubAssign for ProjectivePoint { fn sub_assign(&mut self, rhs: ProjectivePoint) { *self = ProjectivePoint::sub(self, &rhs); } } impl SubAssign<&ProjectivePoint> for ProjectivePoint { fn sub_assign(&mut self, rhs: &ProjectivePoint) { *self = ProjectivePoint::sub(self, rhs); } } impl Sub for ProjectivePoint { type Output = ProjectivePoint; fn sub(self, other: AffinePoint) -> ProjectivePoint { ProjectivePoint::sub_mixed(&self, &other) } } impl Sub<&AffinePoint> for &ProjectivePoint { type Output = ProjectivePoint; fn sub(self, other: &AffinePoint) -> ProjectivePoint { ProjectivePoint::sub_mixed(self, other) } } impl Sub<&AffinePoint> for ProjectivePoint { type Output = ProjectivePoint; fn sub(self, other: &AffinePoint) -> ProjectivePoint { ProjectivePoint::sub_mixed(&self, other) } } impl SubAssign for ProjectivePoint { fn sub_assign(&mut self, rhs: AffinePoint) { *self = ProjectivePoint::sub_mixed(self, &rhs); } } impl SubAssign<&AffinePoint> for ProjectivePoint { fn sub_assign(&mut self, rhs: &AffinePoint) { *self = ProjectivePoint::sub_mixed(self, rhs); } } impl Neg for ProjectivePoint { type Output = ProjectivePoint; fn neg(self) -> ProjectivePoint { ProjectivePoint::neg(&self) } } impl<'a> Neg for &'a ProjectivePoint { type Output = ProjectivePoint; fn neg(self) -> ProjectivePoint { ProjectivePoint::neg(self) } } impl From for ProjectivePoint { fn from(public_key: PublicKey) -> ProjectivePoint { AffinePoint::from(public_key).into() } } impl From<&PublicKey> for ProjectivePoint { fn from(public_key: &PublicKey) -> ProjectivePoint { AffinePoint::from(public_key).into() } } impl TryFrom for PublicKey { type Error = Error; fn try_from(point: ProjectivePoint) -> Result { AffinePoint::from(point).try_into() } } impl TryFrom<&ProjectivePoint> for PublicKey { type Error = Error; fn try_from(point: &ProjectivePoint) -> Result { AffinePoint::from(point).try_into() } } #[cfg(test)] mod tests { use super::{AffinePoint, ProjectivePoint}; use crate::{ test_vectors::group::{ADD_TEST_VECTORS, MUL_TEST_VECTORS}, Scalar, }; use elliptic_curve::group::{ff::PrimeField, prime::PrimeCurveAffine}; use elliptic_curve::ops::MulByGenerator; use elliptic_curve::Field; use elliptic_curve::{group, BatchNormalize}; use rand_core::OsRng; #[cfg(feature = "alloc")] use alloc::vec::Vec; #[test] fn affine_to_projective() { let basepoint_affine = AffinePoint::GENERATOR; let basepoint_projective = ProjectivePoint::GENERATOR; assert_eq!( ProjectivePoint::from(basepoint_affine), basepoint_projective, ); assert_eq!(basepoint_projective.to_affine(), basepoint_affine); assert!(!bool::from(basepoint_projective.to_affine().is_identity())); assert!(bool::from( ProjectivePoint::IDENTITY.to_affine().is_identity() )); } #[test] fn batch_normalize_array() { let k: Scalar = Scalar::random(&mut OsRng); let l: Scalar = Scalar::random(&mut OsRng); let g = ProjectivePoint::mul_by_generator(&k); let h = ProjectivePoint::mul_by_generator(&l); let mut res = [AffinePoint::IDENTITY; 2]; let expected = [g.to_affine(), h.to_affine()]; assert_eq!( >::batch_normalize(&[g, h]), expected ); ::batch_normalize(&[g, h], &mut res); assert_eq!(res, expected); let expected = [g.to_affine(), AffinePoint::IDENTITY]; assert_eq!( >::batch_normalize(&[ g, ProjectivePoint::IDENTITY ]), expected ); ::batch_normalize( &[g, ProjectivePoint::IDENTITY], &mut res, ); assert_eq!(res, expected); } #[test] #[cfg(feature = "alloc")] fn batch_normalize_slice() { let k: Scalar = Scalar::random(&mut OsRng); let l: Scalar = Scalar::random(&mut OsRng); let g = ProjectivePoint::mul_by_generator(&k); let h = ProjectivePoint::mul_by_generator(&l); let expected = vec![g.to_affine(), h.to_affine()]; let scalars = vec![g, h]; let mut res: Vec<_> = >::batch_normalize(scalars.as_slice()); assert_eq!(res, expected); ::batch_normalize(&[g, h], res.as_mut()); assert_eq!(res.to_vec(), expected); let expected = vec![g.to_affine(), AffinePoint::IDENTITY]; let scalars = vec![g, ProjectivePoint::IDENTITY]; res = >::batch_normalize(scalars.as_slice()); assert_eq!(res, expected); ::batch_normalize( &[g, ProjectivePoint::IDENTITY], res.as_mut(), ); assert_eq!(res.to_vec(), expected); } #[test] fn projective_identity_addition() { let identity = ProjectivePoint::IDENTITY; let generator = ProjectivePoint::GENERATOR; assert_eq!(identity + &generator, generator); assert_eq!(generator + &identity, generator); } #[test] fn projective_mixed_addition() { let identity = ProjectivePoint::IDENTITY; let basepoint_affine = AffinePoint::GENERATOR; let basepoint_projective = ProjectivePoint::GENERATOR; assert_eq!(identity + &basepoint_affine, basepoint_projective); assert_eq!( basepoint_projective + &basepoint_affine, basepoint_projective + &basepoint_projective ); } #[test] fn test_vector_repeated_add() { let generator = ProjectivePoint::GENERATOR; let mut p = generator; for i in 0..ADD_TEST_VECTORS.len() { let affine = p.to_affine(); let (expected_x, expected_y) = ADD_TEST_VECTORS[i]; assert_eq!(affine.x.to_bytes(), expected_x.into()); assert_eq!(affine.y.to_bytes(), expected_y.into()); p += &generator; } } #[test] fn test_vector_repeated_add_mixed() { let generator = AffinePoint::GENERATOR; let mut p = ProjectivePoint::GENERATOR; for i in 0..ADD_TEST_VECTORS.len() { let affine = p.to_affine(); let (expected_x, expected_y) = ADD_TEST_VECTORS[i]; assert_eq!(affine.x.to_bytes(), expected_x.into()); assert_eq!(affine.y.to_bytes(), expected_y.into()); p += &generator; } } #[test] fn test_vector_add_mixed_identity() { let generator = ProjectivePoint::GENERATOR; let p0 = generator + ProjectivePoint::IDENTITY; let p1 = generator + AffinePoint::IDENTITY; assert_eq!(p0, p1); } #[test] fn test_vector_double_generator() { let generator = ProjectivePoint::GENERATOR; let mut p = generator; for i in 0..2 { let affine = p.to_affine(); let (expected_x, expected_y) = ADD_TEST_VECTORS[i]; assert_eq!(affine.x.to_bytes(), expected_x.into()); assert_eq!(affine.y.to_bytes(), expected_y.into()); p = p.double(); } } #[test] fn projective_add_vs_double() { let generator = ProjectivePoint::GENERATOR; let r1 = generator + &generator; let r2 = generator.double(); assert_eq!(r1, r2); let r1 = (generator + &generator) + &(generator + &generator); let r2 = generator.double().double(); assert_eq!(r1, r2); } #[test] fn projective_add_and_sub() { let basepoint_affine = AffinePoint::GENERATOR; let basepoint_projective = ProjectivePoint::GENERATOR; assert_eq!( (basepoint_projective + &basepoint_projective) - &basepoint_projective, basepoint_projective ); assert_eq!( (basepoint_projective + &basepoint_affine) - &basepoint_affine, basepoint_projective ); } #[test] fn projective_double_and_sub() { let generator = ProjectivePoint::GENERATOR; assert_eq!(generator.double() - &generator, generator); } #[test] fn test_vector_scalar_mult() { let generator = ProjectivePoint::GENERATOR; for (k, coords) in ADD_TEST_VECTORS .iter() .enumerate() .map(|(k, coords)| (Scalar::from(k as u32 + 1), *coords)) .chain( MUL_TEST_VECTORS .iter() .cloned() .map(|(k, x, y)| (Scalar::from_repr(k.into()).unwrap(), (x, y))), ) { let res = (generator * &k).to_affine(); assert_eq!(res.x.to_bytes(), coords.0.into()); assert_eq!(res.y.to_bytes(), coords.1.into()); } } #[test] fn projective_equality() { use core::ops::Neg; assert_ne!(ProjectivePoint::GENERATOR, ProjectivePoint::IDENTITY); assert_ne!(ProjectivePoint::IDENTITY, ProjectivePoint::GENERATOR); assert_eq!(ProjectivePoint::IDENTITY, ProjectivePoint::IDENTITY); assert_eq!(ProjectivePoint::IDENTITY.neg(), ProjectivePoint::IDENTITY); assert_eq!(ProjectivePoint::GENERATOR, ProjectivePoint::GENERATOR); assert_ne!(ProjectivePoint::GENERATOR, ProjectivePoint::GENERATOR.neg()); assert_ne!(ProjectivePoint::GENERATOR, AffinePoint::IDENTITY); assert_ne!(ProjectivePoint::IDENTITY, AffinePoint::GENERATOR); assert_eq!(ProjectivePoint::IDENTITY, AffinePoint::IDENTITY); assert_eq!(ProjectivePoint::IDENTITY.neg(), AffinePoint::IDENTITY); assert_eq!(ProjectivePoint::GENERATOR, AffinePoint::GENERATOR); assert_ne!(ProjectivePoint::GENERATOR.neg(), AffinePoint::GENERATOR); assert_eq!( ProjectivePoint::GENERATOR.neg(), AffinePoint::GENERATOR.neg() ); } } k256-0.13.3/src/arithmetic/scalar/wide32.rs000064400000000000000000000442431046102023000162360ustar 00000000000000//! Wide scalar (32-bit limbs) use super::{Scalar, MODULUS}; use crate::ORDER; use elliptic_curve::{ bigint::{Limb, U256, U512}, subtle::{Choice, ConditionallySelectable}, }; /// Limbs of 2^256 minus the secp256k1 order. const NEG_MODULUS: [u32; 8] = [ !MODULUS[0] + 1, !MODULUS[1], !MODULUS[2], !MODULUS[3], !MODULUS[4], !MODULUS[5], !MODULUS[6], !MODULUS[7], ]; #[derive(Clone, Copy, Debug, Default)] pub(crate) struct WideScalar(pub(super) U512); impl WideScalar { pub const fn from_bytes(bytes: &[u8; 64]) -> Self { Self(U512::from_be_slice(bytes)) } /// Multiplies two scalars without modulo reduction, producing up to a 512-bit scalar. #[inline(always)] // only used in Scalar::mul(), so won't cause binary bloat pub fn mul_wide(a: &Scalar, b: &Scalar) -> Self { let a = a.0.to_words(); let b = b.0.to_words(); // 96 bit accumulator. let c0 = 0; let c1 = 0; let c2 = 0; // l[0..15] = a[0..7] * b[0..7]. let (c0, c1) = muladd_fast(a[0], b[0], c0, c1); let (l0, c0, c1) = (c0, c1, 0); let (c0, c1, c2) = muladd(a[0], b[1], c0, c1, c2); let (c0, c1, c2) = muladd(a[1], b[0], c0, c1, c2); let (l1, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(a[0], b[2], c0, c1, c2); let (c0, c1, c2) = muladd(a[1], b[1], c0, c1, c2); let (c0, c1, c2) = muladd(a[2], b[0], c0, c1, c2); let (l2, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(a[0], b[3], c0, c1, c2); let (c0, c1, c2) = muladd(a[1], b[2], c0, c1, c2); let (c0, c1, c2) = muladd(a[2], b[1], c0, c1, c2); let (c0, c1, c2) = muladd(a[3], b[0], c0, c1, c2); let (l3, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(a[0], b[4], c0, c1, c2); let (c0, c1, c2) = muladd(a[1], b[3], c0, c1, c2); let (c0, c1, c2) = muladd(a[2], b[2], c0, c1, c2); let (c0, c1, c2) = muladd(a[3], b[1], c0, c1, c2); let (c0, c1, c2) = muladd(a[4], b[0], c0, c1, c2); let (l4, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(a[0], b[5], c0, c1, c2); let (c0, c1, c2) = muladd(a[1], b[4], c0, c1, c2); let (c0, c1, c2) = muladd(a[2], b[3], c0, c1, c2); let (c0, c1, c2) = muladd(a[3], b[2], c0, c1, c2); let (c0, c1, c2) = muladd(a[4], b[1], c0, c1, c2); let (c0, c1, c2) = muladd(a[5], b[0], c0, c1, c2); let (l5, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(a[0], b[6], c0, c1, c2); let (c0, c1, c2) = muladd(a[1], b[5], c0, c1, c2); let (c0, c1, c2) = muladd(a[2], b[4], c0, c1, c2); let (c0, c1, c2) = muladd(a[3], b[3], c0, c1, c2); let (c0, c1, c2) = muladd(a[4], b[2], c0, c1, c2); let (c0, c1, c2) = muladd(a[5], b[1], c0, c1, c2); let (c0, c1, c2) = muladd(a[6], b[0], c0, c1, c2); let (l6, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(a[0], b[7], c0, c1, c2); let (c0, c1, c2) = muladd(a[1], b[6], c0, c1, c2); let (c0, c1, c2) = muladd(a[2], b[5], c0, c1, c2); let (c0, c1, c2) = muladd(a[3], b[4], c0, c1, c2); let (c0, c1, c2) = muladd(a[4], b[3], c0, c1, c2); let (c0, c1, c2) = muladd(a[5], b[2], c0, c1, c2); let (c0, c1, c2) = muladd(a[6], b[1], c0, c1, c2); let (c0, c1, c2) = muladd(a[7], b[0], c0, c1, c2); let (l7, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(a[1], b[7], c0, c1, c2); let (c0, c1, c2) = muladd(a[2], b[6], c0, c1, c2); let (c0, c1, c2) = muladd(a[3], b[5], c0, c1, c2); let (c0, c1, c2) = muladd(a[4], b[4], c0, c1, c2); let (c0, c1, c2) = muladd(a[5], b[3], c0, c1, c2); let (c0, c1, c2) = muladd(a[6], b[2], c0, c1, c2); let (c0, c1, c2) = muladd(a[7], b[1], c0, c1, c2); let (l8, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(a[2], b[7], c0, c1, c2); let (c0, c1, c2) = muladd(a[3], b[6], c0, c1, c2); let (c0, c1, c2) = muladd(a[4], b[5], c0, c1, c2); let (c0, c1, c2) = muladd(a[5], b[4], c0, c1, c2); let (c0, c1, c2) = muladd(a[6], b[3], c0, c1, c2); let (c0, c1, c2) = muladd(a[7], b[2], c0, c1, c2); let (l9, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(a[3], b[7], c0, c1, c2); let (c0, c1, c2) = muladd(a[4], b[6], c0, c1, c2); let (c0, c1, c2) = muladd(a[5], b[5], c0, c1, c2); let (c0, c1, c2) = muladd(a[6], b[4], c0, c1, c2); let (c0, c1, c2) = muladd(a[7], b[3], c0, c1, c2); let (l10, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(a[4], b[7], c0, c1, c2); let (c0, c1, c2) = muladd(a[5], b[6], c0, c1, c2); let (c0, c1, c2) = muladd(a[6], b[5], c0, c1, c2); let (c0, c1, c2) = muladd(a[7], b[4], c0, c1, c2); let (l11, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(a[5], b[7], c0, c1, c2); let (c0, c1, c2) = muladd(a[6], b[6], c0, c1, c2); let (c0, c1, c2) = muladd(a[7], b[5], c0, c1, c2); let (l12, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(a[6], b[7], c0, c1, c2); let (c0, c1, c2) = muladd(a[7], b[6], c0, c1, c2); let (l13, c0, c1, _c2) = (c0, c1, c2, 0); let (c0, c1) = muladd_fast(a[7], b[7], c0, c1); let (l14, c0, c1) = (c0, c1, 0); debug_assert!(c1 == 0); let l15 = c0; Self(U512::from_words([ l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, ])) } /// Multiplies `a` by `b` (without modulo reduction) divide the result by `2^shift` /// (rounding to the nearest integer). /// Variable time in respect to `shift`. pub(crate) fn mul_shift_vartime(a: &Scalar, b: &Scalar, shift: usize) -> Scalar { debug_assert!(shift >= 256); let l = Self::mul_wide(a, b).0.to_words(); let shiftlimbs = shift >> 5; let shiftlow = shift & 0x1F; let shifthigh = 32 - shiftlow; let r0 = if shift < 512 { let lo = l[shiftlimbs] >> shiftlow; let hi = if shift < 480 && shiftlow != 0 { l[1 + shiftlimbs] << shifthigh } else { 0 }; hi | lo } else { 0 }; let r1 = if shift < 480 { let lo = l[1 + shiftlimbs] >> shiftlow; let hi = if shift < 448 && shiftlow != 0 { l[2 + shiftlimbs] << shifthigh } else { 0 }; hi | lo } else { 0 }; let r2 = if shift < 448 { let lo = l[2 + shiftlimbs] >> shiftlow; let hi = if shift < 416 && shiftlow != 0 { l[3 + shiftlimbs] << shifthigh } else { 0 }; hi | lo } else { 0 }; let r3 = if shift < 416 { let lo = l[3 + shiftlimbs] >> shiftlow; let hi = if shift < 384 && shiftlow != 0 { l[4 + shiftlimbs] << shifthigh } else { 0 }; hi | lo } else { 0 }; let r4 = if shift < 384 { let lo = l[4 + shiftlimbs] >> shiftlow; let hi = if shift < 352 && shiftlow != 0 { l[5 + shiftlimbs] << shifthigh } else { 0 }; hi | lo } else { 0 }; let r5 = if shift < 352 { let lo = l[5 + shiftlimbs] >> shiftlow; let hi = if shift < 320 && shiftlow != 0 { l[6 + shiftlimbs] << shifthigh } else { 0 }; hi | lo } else { 0 }; let r6 = if shift < 320 { let lo = l[6 + shiftlimbs] >> shiftlow; let hi = if shift < 288 && shiftlow != 0 { l[7 + shiftlimbs] << shifthigh } else { 0 }; hi | lo } else { 0 }; let r7 = if shift < 288 { l[7 + shiftlimbs] >> shiftlow } else { 0 }; let res = Scalar(U256::from_words([r0, r1, r2, r3, r4, r5, r6, r7])); // Check the highmost discarded bit and round up if it is set. let c = (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1; Scalar::conditional_select(&res, &res.add(&Scalar::ONE), Choice::from(c as u8)) } pub(super) fn reduce_impl(&self, modulus_minus_one: bool) -> Scalar { let neg_modulus0 = if modulus_minus_one { NEG_MODULUS[0] + 1 } else { NEG_MODULUS[0] }; let modulus = if modulus_minus_one { ORDER.wrapping_sub(&U256::ONE) } else { ORDER }; let w = self.0.to_words(); let n0 = w[8]; let n1 = w[9]; let n2 = w[10]; let n3 = w[11]; let n4 = w[12]; let n5 = w[13]; let n6 = w[14]; let n7 = w[15]; // 96 bit accumulator. // // Reduce 512 bits into 385. // m[0..12] = l[0..7] + n[0..7] * NEG_MODULUS. let c0 = w[0]; let c1 = 0; let c2 = 0; let (c0, c1) = muladd_fast(n0, neg_modulus0, c0, c1); let (m0, c0, c1) = (c0, c1, 0); let (c0, c1) = sumadd_fast(w[1], c0, c1); let (c0, c1, c2) = muladd(n1, neg_modulus0, c0, c1, c2); let (c0, c1, c2) = muladd(n0, NEG_MODULUS[1], c0, c1, c2); let (m1, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = sumadd(w[2], c0, c1, c2); let (c0, c1, c2) = muladd(n2, neg_modulus0, c0, c1, c2); let (c0, c1, c2) = muladd(n1, NEG_MODULUS[1], c0, c1, c2); let (c0, c1, c2) = muladd(n0, NEG_MODULUS[2], c0, c1, c2); let (m2, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = sumadd(w[3], c0, c1, c2); let (c0, c1, c2) = muladd(n3, neg_modulus0, c0, c1, c2); let (c0, c1, c2) = muladd(n2, NEG_MODULUS[1], c0, c1, c2); let (c0, c1, c2) = muladd(n1, NEG_MODULUS[2], c0, c1, c2); let (c0, c1, c2) = muladd(n0, NEG_MODULUS[3], c0, c1, c2); let (m3, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = sumadd(w[4], c0, c1, c2); let (c0, c1, c2) = muladd(n4, neg_modulus0, c0, c1, c2); let (c0, c1, c2) = muladd(n3, NEG_MODULUS[1], c0, c1, c2); let (c0, c1, c2) = muladd(n2, NEG_MODULUS[2], c0, c1, c2); let (c0, c1, c2) = muladd(n1, NEG_MODULUS[3], c0, c1, c2); let (c0, c1, c2) = sumadd(n0, c0, c1, c2); let (m4, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = sumadd(w[5], c0, c1, c2); let (c0, c1, c2) = muladd(n5, neg_modulus0, c0, c1, c2); let (c0, c1, c2) = muladd(n4, NEG_MODULUS[1], c0, c1, c2); let (c0, c1, c2) = muladd(n3, NEG_MODULUS[2], c0, c1, c2); let (c0, c1, c2) = muladd(n2, NEG_MODULUS[3], c0, c1, c2); let (c0, c1, c2) = sumadd(n1, c0, c1, c2); let (m5, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = sumadd(w[6], c0, c1, c2); let (c0, c1, c2) = muladd(n6, neg_modulus0, c0, c1, c2); let (c0, c1, c2) = muladd(n5, NEG_MODULUS[1], c0, c1, c2); let (c0, c1, c2) = muladd(n4, NEG_MODULUS[2], c0, c1, c2); let (c0, c1, c2) = muladd(n3, NEG_MODULUS[3], c0, c1, c2); let (c0, c1, c2) = sumadd(n2, c0, c1, c2); let (m6, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = sumadd(w[7], c0, c1, c2); let (c0, c1, c2) = muladd(n7, neg_modulus0, c0, c1, c2); let (c0, c1, c2) = muladd(n6, NEG_MODULUS[1], c0, c1, c2); let (c0, c1, c2) = muladd(n5, NEG_MODULUS[2], c0, c1, c2); let (c0, c1, c2) = muladd(n4, NEG_MODULUS[3], c0, c1, c2); let (c0, c1, c2) = sumadd(n3, c0, c1, c2); let (m7, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(n7, NEG_MODULUS[1], c0, c1, c2); let (c0, c1, c2) = muladd(n6, NEG_MODULUS[2], c0, c1, c2); let (c0, c1, c2) = muladd(n5, NEG_MODULUS[3], c0, c1, c2); let (c0, c1, c2) = sumadd(n4, c0, c1, c2); let (m8, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(n7, NEG_MODULUS[2], c0, c1, c2); let (c0, c1, c2) = muladd(n6, NEG_MODULUS[3], c0, c1, c2); let (c0, c1, c2) = sumadd(n5, c0, c1, c2); let (m9, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(n7, NEG_MODULUS[3], c0, c1, c2); let (c0, c1, c2) = sumadd(n6, c0, c1, c2); let (m10, c0, c1, _c2) = (c0, c1, c2, 0); let (c0, c1) = sumadd_fast(n7, c0, c1); let (m11, c0, _c1) = (c0, c1, 0); debug_assert!(c0 <= 1); let m12 = c0; // Reduce 385 bits into 258. // p[0..8] = m[0..7] + m[8..12] * NEG_MODULUS. let c0 = m0; let c1 = 0; let c2 = 0; let (c0, c1) = muladd_fast(m8, neg_modulus0, c0, c1); let (p0, c0, c1) = (c0, c1, 0); let (c0, c1) = sumadd_fast(m1, c0, c1); let (c0, c1, c2) = muladd(m9, neg_modulus0, c0, c1, c2); let (c0, c1, c2) = muladd(m8, NEG_MODULUS[1], c0, c1, c2); let (p1, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = sumadd(m2, c0, c1, c2); let (c0, c1, c2) = muladd(m10, neg_modulus0, c0, c1, c2); let (c0, c1, c2) = muladd(m9, NEG_MODULUS[1], c0, c1, c2); let (c0, c1, c2) = muladd(m8, NEG_MODULUS[2], c0, c1, c2); let (p2, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = sumadd(m3, c0, c1, c2); let (c0, c1, c2) = muladd(m11, neg_modulus0, c0, c1, c2); let (c0, c1, c2) = muladd(m10, NEG_MODULUS[1], c0, c1, c2); let (c0, c1, c2) = muladd(m9, NEG_MODULUS[2], c0, c1, c2); let (c0, c1, c2) = muladd(m8, NEG_MODULUS[3], c0, c1, c2); let (p3, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = sumadd(m4, c0, c1, c2); let (c0, c1, c2) = muladd(m12, neg_modulus0, c0, c1, c2); let (c0, c1, c2) = muladd(m11, NEG_MODULUS[1], c0, c1, c2); let (c0, c1, c2) = muladd(m10, NEG_MODULUS[2], c0, c1, c2); let (c0, c1, c2) = muladd(m9, NEG_MODULUS[3], c0, c1, c2); let (c0, c1, c2) = sumadd(m8, c0, c1, c2); let (p4, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = sumadd(m5, c0, c1, c2); let (c0, c1, c2) = muladd(m12, NEG_MODULUS[1], c0, c1, c2); let (c0, c1, c2) = muladd(m11, NEG_MODULUS[2], c0, c1, c2); let (c0, c1, c2) = muladd(m10, NEG_MODULUS[3], c0, c1, c2); let (c0, c1, c2) = sumadd(m9, c0, c1, c2); let (p5, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = sumadd(m6, c0, c1, c2); let (c0, c1, c2) = muladd(m12, NEG_MODULUS[2], c0, c1, c2); let (c0, c1, c2) = muladd(m11, NEG_MODULUS[3], c0, c1, c2); let (c0, c1, c2) = sumadd(m10, c0, c1, c2); let (p6, c0, c1, _c2) = (c0, c1, c2, 0); let (c0, c1) = sumadd_fast(m7, c0, c1); let (c0, c1) = muladd_fast(m12, NEG_MODULUS[3], c0, c1); let (c0, c1) = sumadd_fast(m11, c0, c1); let (p7, c0, _c1) = (c0, c1, 0); let p8 = c0 + m12; debug_assert!(p8 <= 2); // Reduce 258 bits into 256. // r[0..7] = p[0..7] + p[8] * NEG_MODULUS. let mut c = p0 as u64 + (neg_modulus0 as u64) * (p8 as u64); let r0 = (c & 0xFFFFFFFFu64) as u32; c >>= 32; c += p1 as u64 + (NEG_MODULUS[1] as u64) * (p8 as u64); let r1 = (c & 0xFFFFFFFFu64) as u32; c >>= 32; c += p2 as u64 + (NEG_MODULUS[2] as u64) * (p8 as u64); let r2 = (c & 0xFFFFFFFFu64) as u32; c >>= 32; c += p3 as u64 + (NEG_MODULUS[3] as u64) * (p8 as u64); let r3 = (c & 0xFFFFFFFFu64) as u32; c >>= 32; c += p4 as u64 + p8 as u64; let r4 = (c & 0xFFFFFFFFu64) as u32; c >>= 32; c += p5 as u64; let r5 = (c & 0xFFFFFFFFu64) as u32; c >>= 32; c += p6 as u64; let r6 = (c & 0xFFFFFFFFu64) as u32; c >>= 32; c += p7 as u64; let r7 = (c & 0xFFFFFFFFu64) as u32; c >>= 32; // Final reduction of r. let r = U256::from([r0, r1, r2, r3, r4, r5, r6, r7]); let (r2, underflow) = r.sbb(&modulus, Limb::ZERO); let high_bit = Choice::from(c as u8); let underflow = Choice::from((underflow.0 >> 31) as u8); Scalar(U256::conditional_select(&r, &r2, !underflow | high_bit)) } #[inline(always)] // only used in Scalar::mul(), so won't cause binary bloat pub(super) fn reduce(&self) -> Scalar { self.reduce_impl(false) } pub(super) fn reduce_nonzero(&self) -> Scalar { self.reduce_impl(true) + Scalar::ONE } } /// Add a to the number defined by (c0,c1,c2). c2 must never overflow. fn sumadd(a: u32, c0: u32, c1: u32, c2: u32) -> (u32, u32, u32) { let (new_c0, carry0) = c0.overflowing_add(a); let (new_c1, carry1) = c1.overflowing_add(carry0 as u32); let new_c2 = c2 + (carry1 as u32); (new_c0, new_c1, new_c2) } /// Add a to the number defined by (c0,c1). c1 must never overflow. fn sumadd_fast(a: u32, c0: u32, c1: u32) -> (u32, u32) { let (new_c0, carry0) = c0.overflowing_add(a); let new_c1 = c1 + (carry0 as u32); (new_c0, new_c1) } /// Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. fn muladd(a: u32, b: u32, c0: u32, c1: u32, c2: u32) -> (u32, u32, u32) { let t = (a as u64) * (b as u64); let th = (t >> 32) as u32; // at most 0xFFFFFFFFFFFFFFFE let tl = t as u32; let (new_c0, carry0) = c0.overflowing_add(tl); let new_th = th.wrapping_add(carry0 as u32); // at most 0xFFFFFFFFFFFFFFFF let (new_c1, carry1) = c1.overflowing_add(new_th); let new_c2 = c2 + (carry1 as u32); (new_c0, new_c1, new_c2) } /// Add a*b to the number defined by (c0,c1). c1 must never overflow. fn muladd_fast(a: u32, b: u32, c0: u32, c1: u32) -> (u32, u32) { let t = (a as u64) * (b as u64); let th = (t >> 32) as u32; // at most 0xFFFFFFFFFFFFFFFE let tl = t as u32; let (new_c0, carry0) = c0.overflowing_add(tl); let new_th = th.wrapping_add(carry0 as u32); // at most 0xFFFFFFFFFFFFFFFF let new_c1 = c1 + new_th; (new_c0, new_c1) } k256-0.13.3/src/arithmetic/scalar/wide64.rs000064400000000000000000000226601046102023000162420ustar 00000000000000//! Wide scalar (64-bit limbs) use super::{Scalar, MODULUS}; use crate::ORDER; use elliptic_curve::{ bigint::{Limb, U256, U512}, subtle::{Choice, ConditionallySelectable}, }; /// Limbs of 2^256 minus the secp256k1 order. const NEG_MODULUS: [u64; 4] = [!MODULUS[0] + 1, !MODULUS[1], !MODULUS[2], !MODULUS[3]]; #[derive(Clone, Copy, Debug, Default)] pub(crate) struct WideScalar(pub(super) U512); impl WideScalar { pub const fn from_bytes(bytes: &[u8; 64]) -> Self { Self(U512::from_be_slice(bytes)) } /// Multiplies two scalars without modulo reduction, producing up to a 512-bit scalar. #[inline(always)] // only used in Scalar::mul(), so won't cause binary bloat pub fn mul_wide(a: &Scalar, b: &Scalar) -> Self { let a = a.0.to_words(); let b = b.0.to_words(); // 160 bit accumulator. let c0 = 0; let c1 = 0; let c2 = 0; // l[0..7] = a[0..3] * b[0..3]. let (c0, c1) = muladd_fast(a[0], b[0], c0, c1); let (l0, c0, c1) = (c0, c1, 0); let (c0, c1, c2) = muladd(a[0], b[1], c0, c1, c2); let (c0, c1, c2) = muladd(a[1], b[0], c0, c1, c2); let (l1, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(a[0], b[2], c0, c1, c2); let (c0, c1, c2) = muladd(a[1], b[1], c0, c1, c2); let (c0, c1, c2) = muladd(a[2], b[0], c0, c1, c2); let (l2, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(a[0], b[3], c0, c1, c2); let (c0, c1, c2) = muladd(a[1], b[2], c0, c1, c2); let (c0, c1, c2) = muladd(a[2], b[1], c0, c1, c2); let (c0, c1, c2) = muladd(a[3], b[0], c0, c1, c2); let (l3, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(a[1], b[3], c0, c1, c2); let (c0, c1, c2) = muladd(a[2], b[2], c0, c1, c2); let (c0, c1, c2) = muladd(a[3], b[1], c0, c1, c2); let (l4, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(a[2], b[3], c0, c1, c2); let (c0, c1, c2) = muladd(a[3], b[2], c0, c1, c2); let (l5, c0, c1, _c2) = (c0, c1, c2, 0); let (c0, c1) = muladd_fast(a[3], b[3], c0, c1); let (l6, c0, _c1) = (c0, c1, 0); let l7 = c0; Self(U512::from_words([l0, l1, l2, l3, l4, l5, l6, l7])) } /// Multiplies `a` by `b` (without modulo reduction) divide the result by `2^shift` /// (rounding to the nearest integer). /// Variable time in `shift`. pub(crate) fn mul_shift_vartime(a: &Scalar, b: &Scalar, shift: usize) -> Scalar { debug_assert!(shift >= 256); let l = Self::mul_wide(a, b).0.to_words(); let shiftlimbs = shift >> 6; let shiftlow = shift & 0x3F; let shifthigh = 64 - shiftlow; let r0 = if shift < 512 { let lo = l[shiftlimbs] >> shiftlow; let hi = if shift < 448 && shiftlow != 0 { l[1 + shiftlimbs] << shifthigh } else { 0 }; hi | lo } else { 0 }; let r1 = if shift < 448 { let lo = l[1 + shiftlimbs] >> shiftlow; let hi = if shift < 384 && shiftlow != 0 { l[2 + shiftlimbs] << shifthigh } else { 0 }; hi | lo } else { 0 }; let r2 = if shift < 384 { let lo = l[2 + shiftlimbs] >> shiftlow; let hi = if shift < 320 && shiftlow != 0 { l[3 + shiftlimbs] << shifthigh } else { 0 }; hi | lo } else { 0 }; let r3 = if shift < 320 { l[3 + shiftlimbs] >> shiftlow } else { 0 }; let res = Scalar(U256::from_words([r0, r1, r2, r3])); // Check the highmost discarded bit and round up if it is set. let c = (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1; Scalar::conditional_select(&res, &res.add(&Scalar::ONE), Choice::from(c as u8)) } fn reduce_impl(&self, modulus_minus_one: bool) -> Scalar { let neg_modulus0 = if modulus_minus_one { NEG_MODULUS[0] + 1 } else { NEG_MODULUS[0] }; let modulus = if modulus_minus_one { ORDER.wrapping_sub(&U256::ONE) } else { ORDER }; let w = self.0.to_words(); let n0 = w[4]; let n1 = w[5]; let n2 = w[6]; let n3 = w[7]; // Reduce 512 bits into 385. // m[0..6] = self[0..3] + n[0..3] * neg_modulus. let c0 = w[0]; let c1 = 0; let c2 = 0; let (c0, c1) = muladd_fast(n0, neg_modulus0, c0, c1); let (m0, c0, c1) = (c0, c1, 0); let (c0, c1) = sumadd_fast(w[1], c0, c1); let (c0, c1, c2) = muladd(n1, neg_modulus0, c0, c1, c2); let (c0, c1, c2) = muladd(n0, NEG_MODULUS[1], c0, c1, c2); let (m1, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = sumadd(w[2], c0, c1, c2); let (c0, c1, c2) = muladd(n2, neg_modulus0, c0, c1, c2); let (c0, c1, c2) = muladd(n1, NEG_MODULUS[1], c0, c1, c2); let (c0, c1, c2) = sumadd(n0, c0, c1, c2); let (m2, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = sumadd(w[3], c0, c1, c2); let (c0, c1, c2) = muladd(n3, neg_modulus0, c0, c1, c2); let (c0, c1, c2) = muladd(n2, NEG_MODULUS[1], c0, c1, c2); let (c0, c1, c2) = sumadd(n1, c0, c1, c2); let (m3, c0, c1, c2) = (c0, c1, c2, 0); let (c0, c1, c2) = muladd(n3, NEG_MODULUS[1], c0, c1, c2); let (c0, c1, c2) = sumadd(n2, c0, c1, c2); let (m4, c0, c1, _c2) = (c0, c1, c2, 0); let (c0, c1) = sumadd_fast(n3, c0, c1); let (m5, c0, _c1) = (c0, c1, 0); debug_assert!(c0 <= 1); let m6 = c0; // Reduce 385 bits into 258. // p[0..4] = m[0..3] + m[4..6] * neg_modulus. let c0 = m0; let c1 = 0; let c2 = 0; let (c0, c1) = muladd_fast(m4, neg_modulus0, c0, c1); let (p0, c0, c1) = (c0, c1, 0); let (c0, c1) = sumadd_fast(m1, c0, c1); let (c0, c1, c2) = muladd(m5, neg_modulus0, c0, c1, c2); let (c0, c1, c2) = muladd(m4, NEG_MODULUS[1], c0, c1, c2); let (p1, c0, c1) = (c0, c1, 0); let (c0, c1, c2) = sumadd(m2, c0, c1, c2); let (c0, c1, c2) = muladd(m6, neg_modulus0, c0, c1, c2); let (c0, c1, c2) = muladd(m5, NEG_MODULUS[1], c0, c1, c2); let (c0, c1, c2) = sumadd(m4, c0, c1, c2); let (p2, c0, c1, _c2) = (c0, c1, c2, 0); let (c0, c1) = sumadd_fast(m3, c0, c1); let (c0, c1) = muladd_fast(m6, NEG_MODULUS[1], c0, c1); let (c0, c1) = sumadd_fast(m5, c0, c1); let (p3, c0, _c1) = (c0, c1, 0); let p4 = c0 + m6; debug_assert!(p4 <= 2); // Reduce 258 bits into 256. // r[0..3] = p[0..3] + p[4] * neg_modulus. let mut c = (p0 as u128) + (neg_modulus0 as u128) * (p4 as u128); let r0 = (c & 0xFFFFFFFFFFFFFFFFu128) as u64; c >>= 64; c += (p1 as u128) + (NEG_MODULUS[1] as u128) * (p4 as u128); let r1 = (c & 0xFFFFFFFFFFFFFFFFu128) as u64; c >>= 64; c += (p2 as u128) + (p4 as u128); let r2 = (c & 0xFFFFFFFFFFFFFFFFu128) as u64; c >>= 64; c += p3 as u128; let r3 = (c & 0xFFFFFFFFFFFFFFFFu128) as u64; c >>= 64; // Final reduction of r. let r = U256::from([r0, r1, r2, r3]); let (r2, underflow) = r.sbb(&modulus, Limb::ZERO); let high_bit = Choice::from(c as u8); let underflow = Choice::from((underflow.0 >> 63) as u8); Scalar(U256::conditional_select(&r, &r2, !underflow | high_bit)) } #[inline(always)] // only used in Scalar::mul(), so won't cause binary bloat pub(super) fn reduce(&self) -> Scalar { self.reduce_impl(false) } pub(super) fn reduce_nonzero(&self) -> Scalar { self.reduce_impl(true) + Scalar::ONE } } /// Add a to the number defined by (c0,c1,c2). c2 must never overflow. fn sumadd(a: u64, c0: u64, c1: u64, c2: u64) -> (u64, u64, u64) { let (new_c0, carry0) = c0.overflowing_add(a); let (new_c1, carry1) = c1.overflowing_add(carry0 as u64); let new_c2 = c2 + (carry1 as u64); (new_c0, new_c1, new_c2) } /// Add a to the number defined by (c0,c1). c1 must never overflow. fn sumadd_fast(a: u64, c0: u64, c1: u64) -> (u64, u64) { let (new_c0, carry0) = c0.overflowing_add(a); let new_c1 = c1 + (carry0 as u64); (new_c0, new_c1) } /// Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. fn muladd(a: u64, b: u64, c0: u64, c1: u64, c2: u64) -> (u64, u64, u64) { let t = (a as u128) * (b as u128); let th = (t >> 64) as u64; // at most 0xFFFFFFFFFFFFFFFE let tl = t as u64; let (new_c0, carry0) = c0.overflowing_add(tl); let new_th = th.wrapping_add(carry0 as u64); // at most 0xFFFFFFFFFFFFFFFF let (new_c1, carry1) = c1.overflowing_add(new_th); let new_c2 = c2 + (carry1 as u64); (new_c0, new_c1, new_c2) } /// Add a*b to the number defined by (c0,c1). c1 must never overflow. fn muladd_fast(a: u64, b: u64, c0: u64, c1: u64) -> (u64, u64) { let t = (a as u128) * (b as u128); let th = (t >> 64) as u64; // at most 0xFFFFFFFFFFFFFFFE let tl = t as u64; let (new_c0, carry0) = c0.overflowing_add(tl); let new_th = th.wrapping_add(carry0 as u64); // at most 0xFFFFFFFFFFFFFFFF let new_c1 = c1 + new_th; (new_c0, new_c1) } k256-0.13.3/src/arithmetic/scalar.rs000064400000000000000000001035631046102023000151420ustar 00000000000000//! Scalar field arithmetic. #[cfg_attr(not(target_pointer_width = "64"), path = "scalar/wide32.rs")] #[cfg_attr(target_pointer_width = "64", path = "scalar/wide64.rs")] mod wide; pub(crate) use self::wide::WideScalar; use crate::{FieldBytes, Secp256k1, WideBytes, ORDER, ORDER_HEX}; use core::{ iter::{Product, Sum}, ops::{Add, AddAssign, Mul, MulAssign, Neg, Shr, ShrAssign, Sub, SubAssign}, }; use elliptic_curve::{ bigint::{prelude::*, Limb, Word, U256, U512}, ff::{self, Field, PrimeField}, ops::{Invert, Reduce, ReduceNonZero}, rand_core::{CryptoRngCore, RngCore}, scalar::{FromUintUnchecked, IsHigh}, subtle::{ Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess, CtOption, }, zeroize::DefaultIsZeroes, Curve, ScalarPrimitive, }; #[cfg(feature = "bits")] use {crate::ScalarBits, elliptic_curve::group::ff::PrimeFieldBits}; #[cfg(feature = "serde")] use serdect::serde::{de, ser, Deserialize, Serialize}; #[cfg(test)] use num_bigint::{BigUint, ToBigUint}; /// Constant representing the modulus /// n = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141 const MODULUS: [Word; U256::LIMBS] = ORDER.to_words(); /// Constant representing the modulus / 2 const FRAC_MODULUS_2: U256 = ORDER.shr_vartime(1); /// Scalars are elements in the finite field modulo n. /// /// # Trait impls /// /// Much of the important functionality of scalars is provided by traits from /// the [`ff`](https://docs.rs/ff/) crate, which is re-exported as /// `k256::elliptic_curve::ff`: /// /// - [`Field`](https://docs.rs/ff/latest/ff/trait.Field.html) - /// represents elements of finite fields and provides: /// - [`Field::random`](https://docs.rs/ff/latest/ff/trait.Field.html#tymethod.random) - /// generate a random scalar /// - `double`, `square`, and `invert` operations /// - Bounds for [`Add`], [`Sub`], [`Mul`], and [`Neg`] (as well as `*Assign` equivalents) /// - Bounds for [`ConditionallySelectable`] from the `subtle` crate /// - [`PrimeField`](https://docs.rs/ff/latest/ff/trait.PrimeField.html) - /// represents elements of prime fields and provides: /// - `from_repr`/`to_repr` for converting field elements from/to big integers. /// - `multiplicative_generator` and `root_of_unity` constants. /// - [`PrimeFieldBits`](https://docs.rs/ff/latest/ff/trait.PrimeFieldBits.html) - /// operations over field elements represented as bits (requires `bits` feature) /// /// Please see the documentation for the relevant traits for more information. /// /// # `serde` support /// /// When the `serde` feature of this crate is enabled, the `Serialize` and /// `Deserialize` traits are impl'd for this type. /// /// The serialization is a fixed-width big endian encoding. When used with /// textual formats, the binary data is encoded as hexadecimal. #[derive(Clone, Copy, Debug, Default, PartialOrd, Ord)] pub struct Scalar(pub(crate) U256); impl Scalar { /// Zero scalar. pub const ZERO: Self = Self(U256::ZERO); /// Multiplicative identity. pub const ONE: Self = Self(U256::ONE); /// Checks if the scalar is zero. pub fn is_zero(&self) -> Choice { self.0.is_zero() } /// Returns the SEC1 encoding of this scalar. pub fn to_bytes(&self) -> FieldBytes { self.0.to_be_byte_array() } /// Negates the scalar. pub const fn negate(&self) -> Self { Self(self.0.neg_mod(&ORDER)) } /// Returns self + rhs mod n. pub const fn add(&self, rhs: &Self) -> Self { Self(self.0.add_mod(&rhs.0, &ORDER)) } /// Returns self - rhs mod n. pub const fn sub(&self, rhs: &Self) -> Self { Self(self.0.sub_mod(&rhs.0, &ORDER)) } /// Modulo multiplies two scalars. pub fn mul(&self, rhs: &Scalar) -> Scalar { WideScalar::mul_wide(self, rhs).reduce() } /// Modulo squares the scalar. pub fn square(&self) -> Self { self.mul(self) } /// Right shifts the scalar. /// /// Note: not constant-time with respect to the `shift` parameter. pub fn shr_vartime(&self, shift: usize) -> Scalar { Self(self.0.shr_vartime(shift)) } /// Inverts the scalar. pub fn invert(&self) -> CtOption { // Using an addition chain from // https://briansmith.org/ecc-inversion-addition-chains-01#secp256k1_scalar_inversion let x_1 = *self; let x_10 = self.pow2k(1); let x_11 = x_10.mul(&x_1); let x_101 = x_10.mul(&x_11); let x_111 = x_10.mul(&x_101); let x_1001 = x_10.mul(&x_111); let x_1011 = x_10.mul(&x_1001); let x_1101 = x_10.mul(&x_1011); let x6 = x_1101.pow2k(2).mul(&x_1011); let x8 = x6.pow2k(2).mul(&x_11); let x14 = x8.pow2k(6).mul(&x6); let x28 = x14.pow2k(14).mul(&x14); let x56 = x28.pow2k(28).mul(&x28); #[rustfmt::skip] let res = x56 .pow2k(56).mul(&x56) .pow2k(14).mul(&x14) .pow2k(3).mul(&x_101) .pow2k(4).mul(&x_111) .pow2k(4).mul(&x_101) .pow2k(5).mul(&x_1011) .pow2k(4).mul(&x_1011) .pow2k(4).mul(&x_111) .pow2k(5).mul(&x_111) .pow2k(6).mul(&x_1101) .pow2k(4).mul(&x_101) .pow2k(3).mul(&x_111) .pow2k(5).mul(&x_1001) .pow2k(6).mul(&x_101) .pow2k(10).mul(&x_111) .pow2k(4).mul(&x_111) .pow2k(9).mul(&x8) .pow2k(5).mul(&x_1001) .pow2k(6).mul(&x_1011) .pow2k(4).mul(&x_1101) .pow2k(5).mul(&x_11) .pow2k(6).mul(&x_1101) .pow2k(10).mul(&x_1101) .pow2k(4).mul(&x_1001) .pow2k(6).mul(&x_1) .pow2k(8).mul(&x6); CtOption::new(res, !self.is_zero()) } /// Returns the scalar modulus as a `BigUint` object. #[cfg(test)] pub fn modulus_as_biguint() -> BigUint { Self::ONE.negate().to_biguint().unwrap() + 1.to_biguint().unwrap() } /// Returns a (nearly) uniformly-random scalar, generated in constant time. pub fn generate_biased(rng: &mut impl CryptoRngCore) -> Self { // We reduce a random 512-bit value into a 256-bit field, which results in a // negligible bias from the uniform distribution, but the process is constant-time. let mut buf = [0u8; 64]; rng.fill_bytes(&mut buf); WideScalar::from_bytes(&buf).reduce() } /// Returns a uniformly-random scalar, generated using rejection sampling. // TODO(tarcieri): make this a `CryptoRng` when `ff` allows it pub fn generate_vartime(rng: &mut impl RngCore) -> Self { let mut bytes = FieldBytes::default(); // TODO: pre-generate several scalars to bring the probability of non-constant-timeness down? loop { rng.fill_bytes(&mut bytes); if let Some(scalar) = Scalar::from_repr(bytes).into() { return scalar; } } } /// Attempts to parse the given byte array as a scalar. /// Does not check the result for being in the correct range. pub(crate) const fn from_bytes_unchecked(bytes: &[u8; 32]) -> Self { Self(U256::from_be_slice(bytes)) } /// Raises the scalar to the power `2^k`. fn pow2k(&self, k: usize) -> Self { let mut x = *self; for _j in 0..k { x = x.square(); } x } } impl Field for Scalar { const ZERO: Self = Self::ZERO; const ONE: Self = Self::ONE; fn random(mut rng: impl RngCore) -> Self { // Uses rejection sampling as the default random generation method, // which produces a uniformly random distribution of scalars. // // This method is not constant time, but should be secure so long as // rejected RNG outputs are unrelated to future ones (which is a // necessary property of a `CryptoRng`). // // With an unbiased RNG, the probability of failing to complete after 4 // iterations is vanishingly small. Self::generate_vartime(&mut rng) } #[must_use] fn square(&self) -> Self { Scalar::square(self) } #[must_use] fn double(&self) -> Self { self.add(self) } fn invert(&self) -> CtOption { Scalar::invert(self) } /// Tonelli-Shank's algorithm for q mod 16 = 1 /// (page 12, algorithm 5) #[allow(clippy::many_single_char_names)] fn sqrt(&self) -> CtOption { // Note: `pow_vartime` is constant-time with respect to `self` let w = self.pow_vartime([ 0x777fa4bd19a06c82, 0xfd755db9cd5e9140, 0xffffffffffffffff, 0x1ffffffffffffff, ]); let mut v = Self::S; let mut x = *self * w; let mut b = x * w; let mut z = Self::ROOT_OF_UNITY; for max_v in (1..=Self::S).rev() { let mut k = 1; let mut tmp = b.square(); let mut j_less_than_v = Choice::from(1); for j in 2..max_v { let tmp_is_one = tmp.ct_eq(&Self::ONE); let squared = Self::conditional_select(&tmp, &z, tmp_is_one).square(); tmp = Self::conditional_select(&squared, &tmp, tmp_is_one); let new_z = Self::conditional_select(&z, &squared, tmp_is_one); j_less_than_v &= !j.ct_eq(&v); k = u32::conditional_select(&j, &k, tmp_is_one); z = Self::conditional_select(&z, &new_z, j_less_than_v); } let result = x * z; x = Self::conditional_select(&result, &x, b.ct_eq(&Self::ONE)); z = z.square(); b *= z; v = k; } CtOption::new(x, x.square().ct_eq(self)) } fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { ff::helpers::sqrt_ratio_generic(num, div) } } impl AsRef for Scalar { fn as_ref(&self) -> &Scalar { self } } impl PrimeField for Scalar { type Repr = FieldBytes; const MODULUS: &'static str = ORDER_HEX; const NUM_BITS: u32 = 256; const CAPACITY: u32 = 255; const TWO_INV: Self = Self(U256::from_be_hex( "7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1", )); const MULTIPLICATIVE_GENERATOR: Self = Self(U256::from_u8(7)); const S: u32 = 6; const ROOT_OF_UNITY: Self = Self(U256::from_be_hex( "0c1dc060e7a91986df9879a3fbc483a898bdeab680756045992f4b5402b052f2", )); const ROOT_OF_UNITY_INV: Self = Self(U256::from_be_hex( "fd3ae181f12d7096efc7b0c75b8cbb7277a275910aa413c3b6fb30a0884f0d1c", )); const DELTA: Self = Self(U256::from_be_hex( "0000000000000000000cbc21fe4561c8d63b78e780e1341e199417c8c0bb7601", )); /// Attempts to parse the given byte array as an SEC1-encoded scalar. /// /// Returns None if the byte array does not contain a big-endian integer in the range /// [0, p). fn from_repr(bytes: FieldBytes) -> CtOption { let inner = U256::from_be_byte_array(bytes); CtOption::new(Self(inner), inner.ct_lt(&Secp256k1::ORDER)) } fn to_repr(&self) -> FieldBytes { self.to_bytes() } fn is_odd(&self) -> Choice { self.0.is_odd() } } #[cfg(feature = "bits")] impl PrimeFieldBits for Scalar { #[cfg(target_pointer_width = "32")] type ReprBits = [u32; 8]; #[cfg(target_pointer_width = "64")] type ReprBits = [u64; 4]; fn to_le_bits(&self) -> ScalarBits { self.into() } fn char_le_bits() -> ScalarBits { ORDER.to_words().into() } } impl DefaultIsZeroes for Scalar {} impl From for Scalar { fn from(k: u32) -> Self { Self(k.into()) } } impl From for Scalar { fn from(k: u64) -> Self { Self(k.into()) } } impl From for Scalar { fn from(k: u128) -> Self { Self(k.into()) } } impl From> for Scalar { fn from(scalar: ScalarPrimitive) -> Scalar { Scalar(*scalar.as_uint()) } } impl From<&ScalarPrimitive> for Scalar { fn from(scalar: &ScalarPrimitive) -> Scalar { Scalar(*scalar.as_uint()) } } impl From for ScalarPrimitive { fn from(scalar: Scalar) -> ScalarPrimitive { ScalarPrimitive::from(&scalar) } } impl From<&Scalar> for ScalarPrimitive { fn from(scalar: &Scalar) -> ScalarPrimitive { ScalarPrimitive::new(scalar.0).unwrap() } } impl FromUintUnchecked for Scalar { type Uint = U256; fn from_uint_unchecked(uint: Self::Uint) -> Self { Self(uint) } } impl Invert for Scalar { type Output = CtOption; fn invert(&self) -> CtOption { self.invert() } /// Fast variable-time inversion using Stein's algorithm. /// /// Returns none if the scalar is zero. /// /// /// /// ⚠️ WARNING! /// /// This method should not be used with (unblinded) secret scalars, as its /// variable-time operation can potentially leak secrets through /// sidechannels. #[allow(non_snake_case)] fn invert_vartime(&self) -> CtOption { let mut u = *self; let mut v = Self::from_uint_unchecked(Secp256k1::ORDER); let mut A = Self::ONE; let mut C = Self::ZERO; while !bool::from(u.is_zero()) { // u-loop while bool::from(u.is_even()) { u >>= 1; let was_odd: bool = A.is_odd().into(); A >>= 1; if was_odd { A += Self::from_uint_unchecked(FRAC_MODULUS_2); A += Self::ONE; } } // v-loop while bool::from(v.is_even()) { v >>= 1; let was_odd: bool = C.is_odd().into(); C >>= 1; if was_odd { C += Self::from_uint_unchecked(FRAC_MODULUS_2); C += Self::ONE; } } // sub-step if u >= v { u -= &v; A -= &C; } else { v -= &u; C -= &A; } } CtOption::new(C, !self.is_zero()) } } impl IsHigh for Scalar { fn is_high(&self) -> Choice { self.0.ct_gt(&FRAC_MODULUS_2) } } impl Shr for Scalar { type Output = Self; fn shr(self, rhs: usize) -> Self::Output { self.shr_vartime(rhs) } } impl Shr for &Scalar { type Output = Scalar; fn shr(self, rhs: usize) -> Self::Output { self.shr_vartime(rhs) } } impl ShrAssign for Scalar { fn shr_assign(&mut self, rhs: usize) { *self = *self >> rhs; } } impl ConditionallySelectable for Scalar { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Self(U256::conditional_select(&a.0, &b.0, choice)) } } impl ConstantTimeEq for Scalar { fn ct_eq(&self, other: &Self) -> Choice { self.0.ct_eq(&(other.0)) } } impl PartialEq for Scalar { fn eq(&self, other: &Self) -> bool { self.ct_eq(other).into() } } impl Eq for Scalar {} impl Neg for Scalar { type Output = Scalar; fn neg(self) -> Scalar { self.negate() } } impl Neg for &Scalar { type Output = Scalar; fn neg(self) -> Scalar { self.negate() } } impl Add for Scalar { type Output = Scalar; fn add(self, other: Scalar) -> Scalar { Scalar::add(&self, &other) } } impl Add<&Scalar> for &Scalar { type Output = Scalar; fn add(self, other: &Scalar) -> Scalar { Scalar::add(self, other) } } impl Add for &Scalar { type Output = Scalar; fn add(self, other: Scalar) -> Scalar { Scalar::add(self, &other) } } impl Add<&Scalar> for Scalar { type Output = Scalar; fn add(self, other: &Scalar) -> Scalar { Scalar::add(&self, other) } } impl AddAssign for Scalar { #[inline] fn add_assign(&mut self, rhs: Scalar) { *self = Scalar::add(self, &rhs); } } impl AddAssign<&Scalar> for Scalar { fn add_assign(&mut self, rhs: &Scalar) { *self = Scalar::add(self, rhs); } } impl Sub for Scalar { type Output = Scalar; fn sub(self, other: Scalar) -> Scalar { Scalar::sub(&self, &other) } } impl Sub<&Scalar> for &Scalar { type Output = Scalar; fn sub(self, other: &Scalar) -> Scalar { Scalar::sub(self, other) } } impl Sub<&Scalar> for Scalar { type Output = Scalar; fn sub(self, other: &Scalar) -> Scalar { Scalar::sub(&self, other) } } impl SubAssign for Scalar { fn sub_assign(&mut self, rhs: Scalar) { *self = Scalar::sub(self, &rhs); } } impl SubAssign<&Scalar> for Scalar { fn sub_assign(&mut self, rhs: &Scalar) { *self = Scalar::sub(self, rhs); } } impl Mul for Scalar { type Output = Scalar; fn mul(self, other: Scalar) -> Scalar { Scalar::mul(&self, &other) } } impl Mul<&Scalar> for &Scalar { type Output = Scalar; fn mul(self, other: &Scalar) -> Scalar { Scalar::mul(self, other) } } impl Mul<&Scalar> for Scalar { type Output = Scalar; fn mul(self, other: &Scalar) -> Scalar { Scalar::mul(&self, other) } } impl MulAssign for Scalar { fn mul_assign(&mut self, rhs: Scalar) { *self = Scalar::mul(self, &rhs); } } impl MulAssign<&Scalar> for Scalar { fn mul_assign(&mut self, rhs: &Scalar) { *self = Scalar::mul(self, rhs); } } impl Reduce for Scalar { type Bytes = FieldBytes; fn reduce(w: U256) -> Self { let (r, underflow) = w.sbb(&ORDER, Limb::ZERO); let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8); Self(U256::conditional_select(&w, &r, !underflow)) } #[inline] fn reduce_bytes(bytes: &FieldBytes) -> Self { Self::reduce(U256::from_be_byte_array(*bytes)) } } impl Reduce for Scalar { type Bytes = WideBytes; fn reduce(w: U512) -> Self { WideScalar(w).reduce() } fn reduce_bytes(bytes: &WideBytes) -> Self { Self::reduce(U512::from_be_byte_array(*bytes)) } } impl ReduceNonZero for Scalar { fn reduce_nonzero(w: U256) -> Self { const ORDER_MINUS_ONE: U256 = ORDER.wrapping_sub(&U256::ONE); let (r, underflow) = w.sbb(&ORDER_MINUS_ONE, Limb::ZERO); let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8); Self(U256::conditional_select(&w, &r, !underflow).wrapping_add(&U256::ONE)) } #[inline] fn reduce_nonzero_bytes(bytes: &FieldBytes) -> Self { Self::reduce_nonzero(U256::from_be_byte_array(*bytes)) } } impl ReduceNonZero for Scalar { fn reduce_nonzero(w: U512) -> Self { WideScalar(w).reduce_nonzero() } #[inline] fn reduce_nonzero_bytes(bytes: &WideBytes) -> Self { Self::reduce_nonzero(U512::from_be_byte_array(*bytes)) } } impl Sum for Scalar { fn sum>(iter: I) -> Self { iter.reduce(core::ops::Add::add).unwrap_or(Self::ZERO) } } impl<'a> Sum<&'a Scalar> for Scalar { fn sum>(iter: I) -> Self { iter.copied().sum() } } impl Product for Scalar { fn product>(iter: I) -> Self { iter.reduce(core::ops::Mul::mul).unwrap_or(Self::ONE) } } impl<'a> Product<&'a Scalar> for Scalar { fn product>(iter: I) -> Self { iter.copied().product() } } #[cfg(feature = "bits")] impl From<&Scalar> for ScalarBits { fn from(scalar: &Scalar) -> ScalarBits { scalar.0.to_words().into() } } impl From for FieldBytes { fn from(scalar: Scalar) -> Self { scalar.to_bytes() } } impl From<&Scalar> for FieldBytes { fn from(scalar: &Scalar) -> Self { scalar.to_bytes() } } impl From for U256 { fn from(scalar: Scalar) -> Self { scalar.0 } } impl From<&Scalar> for U256 { fn from(scalar: &Scalar) -> Self { scalar.0 } } #[cfg(feature = "serde")] impl Serialize for Scalar { fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, { ScalarPrimitive::from(self).serialize(serializer) } } #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for Scalar { fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, { Ok(ScalarPrimitive::deserialize(deserializer)?.into()) } } #[cfg(test)] mod tests { use super::Scalar; use crate::{ arithmetic::dev::{biguint_to_bytes, bytes_to_biguint}, FieldBytes, NonZeroScalar, WideBytes, ORDER, }; use elliptic_curve::{ bigint::{ArrayEncoding, U256, U512}, ff::{Field, PrimeField}, generic_array::GenericArray, ops::{Invert, Reduce}, scalar::IsHigh, }; use num_bigint::{BigUint, ToBigUint}; use num_traits::Zero; use proptest::prelude::*; use rand_core::OsRng; #[cfg(feature = "alloc")] use alloc::vec::Vec; use elliptic_curve::ops::BatchInvert; impl From<&BigUint> for Scalar { fn from(x: &BigUint) -> Self { debug_assert!(x < &Scalar::modulus_as_biguint()); let bytes = biguint_to_bytes(x); Self::from_repr(bytes.into()).unwrap() } } impl From for Scalar { fn from(x: BigUint) -> Self { Self::from(&x) } } impl ToBigUint for Scalar { fn to_biguint(&self) -> Option { Some(bytes_to_biguint(self.to_bytes().as_ref())) } } /// t = (modulus - 1) >> S const T: [u64; 4] = [ 0xeeff497a3340d905, 0xfaeabb739abd2280, 0xffffffffffffffff, 0x03ffffffffffffff, ]; #[test] fn two_inv_constant() { assert_eq!(Scalar::from(2u32) * Scalar::TWO_INV, Scalar::ONE); } #[test] fn root_of_unity_constant() { // ROOT_OF_UNITY^{2^s} mod m == 1 assert_eq!( Scalar::ROOT_OF_UNITY.pow_vartime(&[1u64 << Scalar::S, 0, 0, 0]), Scalar::ONE ); // MULTIPLICATIVE_GENERATOR^{t} mod m == ROOT_OF_UNITY assert_eq!( Scalar::MULTIPLICATIVE_GENERATOR.pow_vartime(&T), Scalar::ROOT_OF_UNITY ) } #[test] fn root_of_unity_inv_constant() { assert_eq!( Scalar::ROOT_OF_UNITY * Scalar::ROOT_OF_UNITY_INV, Scalar::ONE ); } #[test] fn delta_constant() { // DELTA^{t} mod m == 1 assert_eq!(Scalar::DELTA.pow_vartime(&T), Scalar::ONE); } #[test] fn is_high() { // 0 is not high let high: bool = Scalar::ZERO.is_high().into(); assert!(!high); // 1 is not high let one = 1.to_biguint().unwrap(); let high: bool = Scalar::from(&one).is_high().into(); assert!(!high); let m = Scalar::modulus_as_biguint(); let m_by_2 = &m >> 1; // M / 2 is not high let high: bool = Scalar::from(&m_by_2).is_high().into(); assert!(!high); // M / 2 + 1 is high let high: bool = Scalar::from(&m_by_2 + &one).is_high().into(); assert!(high); // MODULUS - 1 is high let high: bool = Scalar::from(&m - &one).is_high().into(); assert!(high); } /// Basic tests that sqrt works. #[test] fn sqrt() { for &n in &[1u64, 4, 9, 16, 25, 36, 49, 64] { let scalar = Scalar::from(n); let sqrt = scalar.sqrt().unwrap(); assert_eq!(sqrt.square(), scalar); } } /// Basic tests that `invert` works. #[test] fn invert() { assert_eq!(Scalar::ONE, Scalar::ONE.invert().unwrap()); let three = Scalar::from(3u64); let inv_three = three.invert().unwrap(); assert_eq!(three * inv_three, Scalar::ONE); let minus_three = -three; let inv_minus_three = minus_three.invert().unwrap(); assert_eq!(inv_minus_three, -inv_three); assert_eq!(three * inv_minus_three, -Scalar::ONE); assert!(bool::from(Scalar::ZERO.invert().is_none())); assert_eq!(Scalar::from(2u64).invert().unwrap(), Scalar::TWO_INV); assert_eq!( Scalar::ROOT_OF_UNITY.invert_vartime().unwrap(), Scalar::ROOT_OF_UNITY_INV ); } /// Basic tests that `invert_vartime` works. #[test] fn invert_vartime() { assert_eq!(Scalar::ONE, Scalar::ONE.invert_vartime().unwrap()); let three = Scalar::from(3u64); let inv_three = three.invert_vartime().unwrap(); assert_eq!(three * inv_three, Scalar::ONE); let minus_three = -three; let inv_minus_three = minus_three.invert_vartime().unwrap(); assert_eq!(inv_minus_three, -inv_three); assert_eq!(three * inv_minus_three, -Scalar::ONE); assert!(bool::from(Scalar::ZERO.invert_vartime().is_none())); assert_eq!( Scalar::from(2u64).invert_vartime().unwrap(), Scalar::TWO_INV ); assert_eq!( Scalar::ROOT_OF_UNITY.invert_vartime().unwrap(), Scalar::ROOT_OF_UNITY_INV ); } #[test] fn batch_invert_array() { let k: Scalar = Scalar::random(&mut OsRng); let l: Scalar = Scalar::random(&mut OsRng); let expected = [k.invert().unwrap(), l.invert().unwrap()]; assert_eq!( >::batch_invert(&[k, l]).unwrap(), expected ); } #[test] #[cfg(feature = "alloc")] fn batch_invert() { let k: Scalar = Scalar::random(&mut OsRng); let l: Scalar = Scalar::random(&mut OsRng); let expected = vec![k.invert().unwrap(), l.invert().unwrap()]; let scalars = vec![k, l]; let res: Vec<_> = >::batch_invert(scalars.as_slice()).unwrap(); assert_eq!(res, expected); } #[test] fn negate() { let zero_neg = -Scalar::ZERO; assert_eq!(zero_neg, Scalar::ZERO); let m = Scalar::modulus_as_biguint(); let one = 1.to_biguint().unwrap(); let m_minus_one = &m - &one; let m_by_2 = &m >> 1; let one_neg = -Scalar::ONE; assert_eq!(one_neg, Scalar::from(&m_minus_one)); let frac_modulus_2_neg = -Scalar::from(&m_by_2); let frac_modulus_2_plus_one = Scalar::from(&m_by_2 + &one); assert_eq!(frac_modulus_2_neg, frac_modulus_2_plus_one); let modulus_minus_one_neg = -Scalar::from(&m - &one); assert_eq!(modulus_minus_one_neg, Scalar::ONE); } #[test] fn add_result_within_256_bits() { // A regression for a bug where reduction was not applied // when the unreduced result of addition was in the range `[modulus, 2^256)`. let t = 1.to_biguint().unwrap() << 255; let one = 1.to_biguint().unwrap(); let a = Scalar::from(&t - &one); let b = Scalar::from(&t); let res = &a + &b; let m = Scalar::modulus_as_biguint(); let res_ref = Scalar::from((&t + &t - &one) % &m); assert_eq!(res, res_ref); } #[test] fn generate_biased() { use elliptic_curve::rand_core::OsRng; let a = Scalar::generate_biased(&mut OsRng); // just to make sure `a` is not optimized out by the compiler assert_eq!((a - &a).is_zero().unwrap_u8(), 1); } #[test] fn generate_vartime() { use elliptic_curve::rand_core::OsRng; let a = Scalar::generate_vartime(&mut OsRng); // just to make sure `a` is not optimized out by the compiler assert_eq!((a - &a).is_zero().unwrap_u8(), 1); } #[test] fn from_bytes_reduced() { let m = Scalar::modulus_as_biguint(); fn reduce>(arr: &[u8]) -> T { T::reduce_bytes(GenericArray::from_slice(arr)) } // Regular reduction let s = reduce::(&[0xffu8; 32]).to_biguint().unwrap(); assert!(s < m); let s = reduce::(&[0u8; 32]).to_biguint().unwrap(); assert!(s.is_zero()); let s = reduce::(&ORDER.to_be_byte_array()) .to_biguint() .unwrap(); assert!(s.is_zero()); // Reduction to a non-zero scalar let s = reduce::(&[0xffu8; 32]).to_biguint().unwrap(); assert!(s < m); let s = reduce::(&[0u8; 32]).to_biguint().unwrap(); assert!(s < m); assert!(!s.is_zero()); let s = reduce::(&ORDER.to_be_byte_array()) .to_biguint() .unwrap(); assert!(s < m); assert!(!s.is_zero()); let s = reduce::(&(ORDER.wrapping_sub(&U256::ONE)).to_be_byte_array()) .to_biguint() .unwrap(); assert!(s < m); assert!(!s.is_zero()); } #[test] fn from_wide_bytes_reduced() { let m = Scalar::modulus_as_biguint(); fn reduce>(slice: &[u8]) -> T { let mut bytes = WideBytes::default(); bytes[(64 - slice.len())..].copy_from_slice(slice); T::reduce_bytes(&bytes) } // Regular reduction let s = reduce::(&[0xffu8; 64]).to_biguint().unwrap(); assert!(s < m); let s = reduce::(&[0u8; 64]).to_biguint().unwrap(); assert!(s.is_zero()); let s = reduce::(&ORDER.to_be_byte_array()) .to_biguint() .unwrap(); assert!(s.is_zero()); // Reduction to a non-zero scalar let s = reduce::(&[0xffu8; 64]).to_biguint().unwrap(); assert!(s < m); let s = reduce::(&[0u8; 64]).to_biguint().unwrap(); assert!(s < m); assert!(!s.is_zero()); let s = reduce::(&ORDER.to_be_byte_array()) .to_biguint() .unwrap(); assert!(s < m); assert!(!s.is_zero()); let s = reduce::(&(ORDER.wrapping_sub(&U256::ONE)).to_be_byte_array()) .to_biguint() .unwrap(); assert!(s < m); assert!(!s.is_zero()); } prop_compose! { fn scalar()(bytes in any::<[u8; 32]>()) -> Scalar { >::reduce_bytes(&bytes.into()) } } proptest! { #[test] fn fuzzy_roundtrip_to_bytes(a in scalar()) { let a_back = Scalar::from_repr(a.to_bytes()).unwrap(); assert_eq!(a, a_back); } #[test] fn fuzzy_roundtrip_to_bytes_unchecked(a in scalar()) { let bytes = a.to_bytes(); let a_back = Scalar::from_bytes_unchecked(bytes.as_ref()); assert_eq!(a, a_back); } #[test] fn fuzzy_add(a in scalar(), b in scalar()) { let a_bi = a.to_biguint().unwrap(); let b_bi = b.to_biguint().unwrap(); let res_bi = (&a_bi + &b_bi) % &Scalar::modulus_as_biguint(); let res_ref = Scalar::from(&res_bi); let res_test = a.add(&b); assert_eq!(res_ref, res_test); } #[test] fn fuzzy_sub(a in scalar(), b in scalar()) { let a_bi = a.to_biguint().unwrap(); let b_bi = b.to_biguint().unwrap(); let m = Scalar::modulus_as_biguint(); let res_bi = (&m + &a_bi - &b_bi) % &m; let res_ref = Scalar::from(&res_bi); let res_test = a.sub(&b); assert_eq!(res_ref, res_test); } #[test] fn fuzzy_neg(a in scalar()) { let a_bi = a.to_biguint().unwrap(); let m = Scalar::modulus_as_biguint(); let res_bi = (&m - &a_bi) % &m; let res_ref = Scalar::from(&res_bi); let res_test = -a; assert_eq!(res_ref, res_test); } #[test] fn fuzzy_mul(a in scalar(), b in scalar()) { let a_bi = a.to_biguint().unwrap(); let b_bi = b.to_biguint().unwrap(); let res_bi = (&a_bi * &b_bi) % &Scalar::modulus_as_biguint(); let res_ref = Scalar::from(&res_bi); let res_test = a.mul(&b); assert_eq!(res_ref, res_test); } #[test] fn fuzzy_rshift(a in scalar(), b in 0usize..512) { let a_bi = a.to_biguint().unwrap(); let res_bi = &a_bi >> b; let res_ref = Scalar::from(&res_bi); let res_test = a >> b; assert_eq!(res_ref, res_test); } #[test] fn fuzzy_invert( a in scalar() ) { let a = if bool::from(a.is_zero()) { Scalar::ONE } else { a }; let a_bi = a.to_biguint().unwrap(); let inv = a.invert().unwrap(); let inv_bi = inv.to_biguint().unwrap(); let m = Scalar::modulus_as_biguint(); assert_eq!((&inv_bi * &a_bi) % &m, 1.to_biguint().unwrap()); } #[test] fn fuzzy_invert_vartime(w in scalar()) { let inv: Option = w.invert().into(); let inv_vartime: Option = w.invert_vartime().into(); assert_eq!(inv, inv_vartime); } #[test] fn fuzzy_from_wide_bytes_reduced(bytes_hi in any::<[u8; 32]>(), bytes_lo in any::<[u8; 32]>()) { let m = Scalar::modulus_as_biguint(); let mut bytes = [0u8; 64]; bytes[0..32].clone_from_slice(&bytes_hi); bytes[32..64].clone_from_slice(&bytes_lo); let s = >::reduce(U512::from_be_slice(&bytes)); let s_bu = s.to_biguint().unwrap(); assert!(s_bu < m); } } } k256-0.13.3/src/arithmetic.rs000064400000000000000000000026341046102023000136720ustar 00000000000000//! A pure-Rust implementation of group operations on secp256k1. pub(crate) mod affine; mod field; #[cfg(feature = "hash2curve")] mod hash2curve; mod mul; pub(crate) mod projective; pub(crate) mod scalar; #[cfg(test)] mod dev; pub use field::FieldElement; use self::{affine::AffinePoint, projective::ProjectivePoint, scalar::Scalar}; use crate::Secp256k1; use elliptic_curve::CurveArithmetic; impl CurveArithmetic for Secp256k1 { type AffinePoint = AffinePoint; type ProjectivePoint = ProjectivePoint; type Scalar = Scalar; } const CURVE_EQUATION_B_SINGLE: u32 = 7u32; #[rustfmt::skip] pub(crate) const CURVE_EQUATION_B: FieldElement = FieldElement::from_bytes_unchecked(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CURVE_EQUATION_B_SINGLE as u8, ]); #[cfg(test)] mod tests { use super::CURVE_EQUATION_B; use hex_literal::hex; const CURVE_EQUATION_B_BYTES: [u8; 32] = hex!("0000000000000000000000000000000000000000000000000000000000000007"); #[test] fn verify_constants() { assert_eq!(CURVE_EQUATION_B.to_bytes(), CURVE_EQUATION_B_BYTES.into()); } #[test] fn generate_secret_key() { use crate::SecretKey; use elliptic_curve::rand_core::OsRng; let key = SecretKey::random(&mut OsRng); // Sanity check assert!(!key.to_bytes().iter().all(|b| *b == 0)) } } k256-0.13.3/src/ecdh.rs000064400000000000000000000037671046102023000124540ustar 00000000000000//! Elliptic Curve Diffie-Hellman (Ephemeral) Support. //! //! This module contains a high-level interface for performing ephemeral //! Diffie-Hellman key exchanges using the secp256k1 elliptic curve. //! //! # Usage //! //! This usage example is from the perspective of two participants in the //! exchange, nicknamed "Alice" and "Bob". //! //! ``` //! use k256::{EncodedPoint, PublicKey, ecdh::EphemeralSecret}; //! use rand_core::OsRng; // requires 'getrandom' feature //! //! // Alice //! let alice_secret = EphemeralSecret::random(&mut OsRng); //! let alice_pk_bytes = EncodedPoint::from(alice_secret.public_key()); //! //! // Bob //! let bob_secret = EphemeralSecret::random(&mut OsRng); //! let bob_pk_bytes = EncodedPoint::from(bob_secret.public_key()); //! //! // Alice decodes Bob's serialized public key and computes a shared secret from it //! let bob_public = PublicKey::from_sec1_bytes(bob_pk_bytes.as_ref()) //! .expect("bob's public key is invalid!"); // In real usage, don't panic, handle this! //! //! let alice_shared = alice_secret.diffie_hellman(&bob_public); //! //! // Bob decodes Alice's serialized public key and computes the same shared secret //! let alice_public = PublicKey::from_sec1_bytes(alice_pk_bytes.as_ref()) //! .expect("alice's public key is invalid!"); // In real usage, don't panic, handle this! //! //! let bob_shared = bob_secret.diffie_hellman(&alice_public); //! //! // Both participants arrive on the same shared secret //! assert_eq!(alice_shared.raw_secret_bytes(), bob_shared.raw_secret_bytes()); //! ``` pub use elliptic_curve::ecdh::diffie_hellman; use crate::{AffinePoint, Secp256k1}; /// secp256k1 Ephemeral Diffie-Hellman Secret. pub type EphemeralSecret = elliptic_curve::ecdh::EphemeralSecret; /// Shared secret value computed via ECDH key agreement. pub type SharedSecret = elliptic_curve::ecdh::SharedSecret; impl From<&AffinePoint> for SharedSecret { fn from(affine: &AffinePoint) -> SharedSecret { affine.x.to_bytes().into() } } k256-0.13.3/src/ecdsa.rs000064400000000000000000000406471046102023000126260ustar 00000000000000//! Elliptic Curve Digital Signature Algorithm (ECDSA). //! //! This module contains support for computing and verifying ECDSA signatures. //! To use it, you will need to enable one of the two following Cargo features: //! //! - `ecdsa-core`: provides only the [`Signature`] type (which represents an //! ECDSA/secp256k1 signature). Does not require the `arithmetic` feature. //! This is useful for 3rd-party crates which wish to use the `Signature` //! type for interoperability purposes (particularly in conjunction with the //! [`signature::Signer`] trait). Example use cases for this include other //! software implementations of ECDSA/secp256k1 and wrappers for cloud KMS //! services or hardware devices (HSM or crypto hardware wallet). //! - `ecdsa`: provides `ecdsa-core` features plus the [`SigningKey`] and //! [`VerifyingKey`] types which natively implement ECDSA/secp256k1 signing and //! verification. //! //! Most users of this library who want to sign/verify signatures will want to //! enable the `ecdsa` and `sha256` Cargo features. //! //! ## Signing and Verifying Signatures //! //! This example requires the `ecdsa` and `sha256` Cargo features are enabled: //! //! ``` //! # #[cfg(all(feature = "ecdsa", feature = "sha256"))] //! # { //! use k256::{ //! ecdsa::{SigningKey, Signature, signature::Signer}, //! SecretKey, //! }; //! use rand_core::OsRng; // requires 'getrandom' feature //! //! // Signing //! let signing_key = SigningKey::random(&mut OsRng); // Serialize with `::to_bytes()` //! let message = b"ECDSA proves knowledge of a secret number in the context of a single message"; //! //! // Note: The signature type must be annotated or otherwise inferable as //! // `Signer` has many impls of the `Signer` trait (for both regular and //! // recoverable signature types). //! let signature: Signature = signing_key.sign(message); //! //! // Verification //! use k256::{EncodedPoint, ecdsa::{VerifyingKey, signature::Verifier}}; //! //! let verifying_key = VerifyingKey::from(&signing_key); // Serialize with `::to_encoded_point()` //! assert!(verifying_key.verify(message, &signature).is_ok()); //! # } //! ``` //! //! ## Recovering [`VerifyingKey`] from [`Signature`] //! //! ECDSA makes it possible to recover the public key used to verify a //! signature with the assistance of 2-bits of additional information. //! //! This is helpful when there is already a trust relationship for a particular //! key, and it's desirable to omit the full public key used to sign a //! particular message. //! //! One common application of signature recovery with secp256k1 is Ethereum. //! //! ### Upgrading recoverable signature code from earlier versions of `k256` //! //! The v0.12 release of `k256` contains a brand new recoverable signature API //! from previous releases. Functionality has been upstreamed from `k256` to a //! generic implementation in the [`ecdsa`](`ecdsa_core`) crate. //! //! If you previously used `k256::ecdsa::recoverable::Signature`, the old //! functionality now uses a "detached" [`Signature`] and [`RecoveryId`]. //! Here is where the various functionality went: //! //! - Signing now requires the use of the [`hazmat::SignPrimitive`] trait //! (see examples immediately below). //! - Signature recovery is now implemented as methods of the [`VerifyingKey`] //! type (i.e. `::recover_from_*`). //! - Trial recovery is now defined on the [`RecoveryId`] type //! (i.e. `::trial_recovery_from_*`). //! //! ### Computing a signature with a [`RecoveryId`]. //! //! This example shows how to compute a signature and its associated //! [`RecoveryId`] in a manner which is byte-for-byte compatible with //! Ethereum libraries, leveraging the [`SigningKey::sign_digest_recoverable`] //! API: //! #![cfg_attr(feature = "std", doc = "```")] #![cfg_attr(not(feature = "std"), doc = "```ignore")] //! # fn main() -> Result<(), Box> { //! use hex_literal::hex; //! use k256::ecdsa::{hazmat::SignPrimitive, RecoveryId, Signature, SigningKey}; //! use sha2::Sha256; //! use sha3::{Keccak256, Digest}; //! //! let signing_key = SigningKey::from_bytes(&hex!( //! "4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318" //! ).into())?; //! //! let msg = hex!("e9808504e3b29200831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca0080018080"); //! let digest = Keccak256::new_with_prefix(msg); //! let (signature, recid) = signing_key.sign_digest_recoverable(digest)?; //! //! assert_eq!( //! signature.to_bytes().as_slice(), //! &hex!("c9cf86333bcb065d140032ecaab5d9281bde80f21b9687b3e94161de42d51895727a108a0b8d101465414033c3f705a9c7b826e596766046ee1183dbc8aeaa68") //! ); //! //! assert_eq!(recid, RecoveryId::try_from(0u8).unwrap()); //! # Ok(()) //! # } //! ``` //! //! ### Recovering a [`VerifyingKey`] from a signature //! #![cfg_attr(feature = "std", doc = "```")] #![cfg_attr(not(feature = "std"), doc = "```ignore")] //! # fn main() -> Result<(), Box> { //! use hex_literal::hex; //! use k256::ecdsa::{RecoveryId, Signature, VerifyingKey}; //! use sha3::{Keccak256, Digest}; //! use elliptic_curve::sec1::ToEncodedPoint; //! //! let msg = b"example message"; //! //! let signature = Signature::try_from(hex!( //! "46c05b6368a44b8810d79859441d819b8e7cdc8bfd371e35c53196f4bcacdb51 //! 35c7facce2a97b95eacba8a586d87b7958aaf8368ab29cee481f76e871dbd9cb" //! ).as_slice())?; //! //! let recid = RecoveryId::try_from(1u8)?; //! //! let recovered_key = VerifyingKey::recover_from_digest( //! Keccak256::new_with_prefix(msg), //! &signature, //! recid //! )?; //! //! let expected_key = VerifyingKey::from_sec1_bytes( //! &hex!("0200866db99873b09fc2fb1e3ba549b156e96d1a567e3284f5f0e859a83320cb8b") //! )?; //! //! assert_eq!(recovered_key, expected_key); //! # Ok(()) //! # } //! ``` pub use ecdsa_core::{ signature::{self, Error}, RecoveryId, }; #[cfg(any(feature = "ecdsa", feature = "sha256"))] pub use ecdsa_core::hazmat; use crate::Secp256k1; #[cfg(feature = "ecdsa")] use { crate::{AffinePoint, FieldBytes, Scalar}, ecdsa_core::hazmat::{SignPrimitive, VerifyPrimitive}, elliptic_curve::{ops::Invert, scalar::IsHigh, subtle::CtOption}, }; /// ECDSA/secp256k1 signature (fixed-size) pub type Signature = ecdsa_core::Signature; /// ECDSA/secp256k1 signature (ASN.1 DER encoded) pub type DerSignature = ecdsa_core::der::Signature; /// ECDSA/secp256k1 signing key #[cfg(feature = "ecdsa")] pub type SigningKey = ecdsa_core::SigningKey; /// ECDSA/secp256k1 verification key (i.e. public key) #[cfg(feature = "ecdsa")] pub type VerifyingKey = ecdsa_core::VerifyingKey; #[cfg(feature = "sha256")] impl hazmat::DigestPrimitive for Secp256k1 { type Digest = sha2::Sha256; } #[cfg(feature = "ecdsa")] impl SignPrimitive for Scalar { #[allow(non_snake_case, clippy::many_single_char_names)] fn try_sign_prehashed( &self, k: K, z: &FieldBytes, ) -> Result<(Signature, Option), Error> where K: AsRef + Invert>, { let (sig, recid) = hazmat::sign_prehashed::(self, k, z)?; let is_y_odd = recid.is_y_odd() ^ bool::from(sig.s().is_high()); let sig_low = sig.normalize_s().unwrap_or(sig); let recid = RecoveryId::new(is_y_odd, recid.is_x_reduced()); Ok((sig_low, Some(recid))) } } #[cfg(feature = "ecdsa")] impl VerifyPrimitive for AffinePoint { fn verify_prehashed(&self, z: &FieldBytes, sig: &Signature) -> Result<(), Error> { if sig.s().is_high().into() { return Err(Error::new()); } hazmat::verify_prehashed(&self.into(), z, sig) } } #[cfg(all(test, feature = "ecdsa", feature = "arithmetic"))] mod tests { mod normalize { use crate::ecdsa::Signature; // Test vectors generated using rust-secp256k1 #[test] #[rustfmt::skip] fn s_high() { let sig_hi = Signature::try_from([ 0x20, 0xc0, 0x1a, 0x91, 0x0e, 0xbb, 0x26, 0x10, 0xaf, 0x2d, 0x76, 0x3f, 0xa0, 0x9b, 0x3b, 0x30, 0x92, 0x3c, 0x8e, 0x40, 0x8b, 0x11, 0xdf, 0x2c, 0x61, 0xad, 0x76, 0xd9, 0x70, 0xa2, 0xf1, 0xbc, 0xee, 0x2f, 0x11, 0xef, 0x8c, 0xb0, 0x0a, 0x49, 0x61, 0x7d, 0x13, 0x57, 0xf4, 0xd5, 0x56, 0x41, 0x09, 0x0a, 0x48, 0xf2, 0x01, 0xe9, 0xb9, 0x59, 0xc4, 0x8f, 0x6f, 0x6b, 0xec, 0x6f, 0x93, 0x8f, ].as_slice()).unwrap(); let sig_lo = Signature::try_from([ 0x20, 0xc0, 0x1a, 0x91, 0x0e, 0xbb, 0x26, 0x10, 0xaf, 0x2d, 0x76, 0x3f, 0xa0, 0x9b, 0x3b, 0x30, 0x92, 0x3c, 0x8e, 0x40, 0x8b, 0x11, 0xdf, 0x2c, 0x61, 0xad, 0x76, 0xd9, 0x70, 0xa2, 0xf1, 0xbc, 0x11, 0xd0, 0xee, 0x10, 0x73, 0x4f, 0xf5, 0xb6, 0x9e, 0x82, 0xec, 0xa8, 0x0b, 0x2a, 0xa9, 0xbd, 0xb1, 0xa4, 0x93, 0xf4, 0xad, 0x5e, 0xe6, 0xe1, 0xfb, 0x42, 0xef, 0x20, 0xe3, 0xc6, 0xad, 0xb2, ].as_slice()).unwrap(); let sig_normalized = sig_hi.normalize_s().unwrap(); assert_eq!(sig_lo, sig_normalized); } #[test] fn s_low() { #[rustfmt::skip] let sig = Signature::try_from([ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ].as_slice()).unwrap(); assert_eq!(sig.normalize_s(), None); } } #[cfg(feature = "sha256")] mod recovery { use crate::{ ecdsa::{signature::DigestVerifier, RecoveryId, Signature, SigningKey, VerifyingKey}, EncodedPoint, }; use hex_literal::hex; use sha2::{Digest, Sha256}; use sha3::Keccak256; /// Signature recovery test vectors struct RecoveryTestVector { pk: [u8; 33], msg: &'static [u8], sig: [u8; 64], recid: RecoveryId, } const RECOVERY_TEST_VECTORS: &[RecoveryTestVector] = &[ // Recovery ID 0 RecoveryTestVector { pk: hex!("021a7a569e91dbf60581509c7fc946d1003b60c7dee85299538db6353538d59574"), msg: b"example message", sig: hex!( "ce53abb3721bafc561408ce8ff99c909f7f0b18a2f788649d6470162ab1aa032 3971edc523a6d6453f3fb6128d318d9db1a5ff3386feb1047d9816e780039d52" ), recid: RecoveryId::new(false, false), }, // Recovery ID 1 RecoveryTestVector { pk: hex!("036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2"), msg: b"example message", sig: hex!( "46c05b6368a44b8810d79859441d819b8e7cdc8bfd371e35c53196f4bcacdb51 35c7facce2a97b95eacba8a586d87b7958aaf8368ab29cee481f76e871dbd9cb" ), recid: RecoveryId::new(true, false), }, ]; #[test] fn public_key_recovery() { for vector in RECOVERY_TEST_VECTORS { let digest = Sha256::new_with_prefix(vector.msg); let sig = Signature::try_from(vector.sig.as_slice()).unwrap(); let recid = vector.recid; let pk = VerifyingKey::recover_from_digest(digest, &sig, recid).unwrap(); assert_eq!(&vector.pk[..], EncodedPoint::from(&pk).as_bytes()); } } /// End-to-end example which ensures RFC6979 is implemented in the same /// way as other Ethereum libraries, using HMAC-DRBG-SHA-256 for RFC6979, /// and Keccak256 for hashing the message. /// /// Test vectors adapted from: /// #[test] fn ethereum_end_to_end_example() { let signing_key = SigningKey::from_bytes( &hex!("4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318").into(), ) .unwrap(); let msg = hex!( "e9808504e3b29200831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca0080018080" ); let digest = Keccak256::new_with_prefix(msg); let (sig, recid) = signing_key.sign_digest_recoverable(digest.clone()).unwrap(); assert_eq!( sig.to_bytes().as_slice(), &hex!("c9cf86333bcb065d140032ecaab5d9281bde80f21b9687b3e94161de42d51895727a108a0b8d101465414033c3f705a9c7b826e596766046ee1183dbc8aeaa68") ); assert_eq!(recid, RecoveryId::from_byte(0).unwrap()); let verifying_key = VerifyingKey::recover_from_digest(digest.clone(), &sig, recid).unwrap(); assert_eq!(signing_key.verifying_key(), &verifying_key); assert!(verifying_key.verify_digest(digest, &sig).is_ok()); } } mod wycheproof { use crate::{EncodedPoint, Secp256k1}; use ecdsa_core::{signature::Verifier, Signature}; use elliptic_curve::generic_array::typenum::Unsigned; #[test] fn wycheproof() { use blobby::Blob5Iterator; // Build a field element but allow for too-short input (left pad with zeros) // or too-long input (check excess leftmost bytes are zeros). fn element_from_padded_slice( data: &[u8], ) -> elliptic_curve::FieldBytes { let point_len = C::FieldBytesSize::USIZE; if data.len() >= point_len { let offset = data.len() - point_len; for v in data.iter().take(offset) { assert_eq!(*v, 0, "EcdsaVerifier: point too large"); } elliptic_curve::FieldBytes::::clone_from_slice(&data[offset..]) } else { let iter = core::iter::repeat(0) .take(point_len - data.len()) .chain(data.iter().cloned()); elliptic_curve::FieldBytes::::from_exact_iter(iter).unwrap() } } fn run_test( wx: &[u8], wy: &[u8], msg: &[u8], sig: &[u8], pass: bool, ) -> Option<&'static str> { let x = element_from_padded_slice::(wx); let y = element_from_padded_slice::(wy); let q_encoded = EncodedPoint::from_affine_coordinates(&x, &y, /* compress= */ false); let verifying_key = ecdsa_core::VerifyingKey::from_encoded_point(&q_encoded).unwrap(); let sig = match Signature::::from_der(sig) { Ok(s) => s.normalize_s().unwrap_or(s), Err(_) if !pass => return None, Err(_) => return Some("failed to parse signature ASN.1"), }; match verifying_key.verify(msg, &sig) { Ok(_) if pass => None, Ok(_) => Some("signature verify unexpectedly succeeded"), Err(_) if !pass => None, Err(_) => Some("signature verify failed"), } } let data = include_bytes!(concat!("test_vectors/data/", "wycheproof", ".blb")); for (i, row) in Blob5Iterator::new(data).unwrap().enumerate() { let [wx, wy, msg, sig, status] = row.unwrap(); let pass = match status[0] { 0 => false, 1 => true, _ => panic!("invalid value for pass flag"), }; if let Some(desc) = run_test(wx, wy, msg, sig, pass) { panic!( "\n\ Failed test №{}: {}\n\ wx:\t{:?}\n\ wy:\t{:?}\n\ msg:\t{:?}\n\ sig:\t{:?}\n\ pass:\t{}\n", i, desc, wx, wy, msg, sig, pass, ); } } } } } k256-0.13.3/src/lib.rs000064400000000000000000000106571046102023000123130ustar 00000000000000#![no_std] #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc = include_str!("../README.md")] #![doc( html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" )] #![allow(clippy::needless_range_loop)] #![forbid(unsafe_code)] #![warn( clippy::mod_module_files, clippy::unwrap_used, missing_docs, rust_2018_idioms, unused_lifetimes, unused_qualifications )] //! ## `serde` support //! //! When the `serde` feature of this crate is enabled, `Serialize` and //! `Deserialize` are impl'd for the following types: //! //! - [`AffinePoint`] //! - [`Scalar`] //! - [`ecdsa::VerifyingKey`] //! //! Please see type-specific documentation for more information. #[cfg(feature = "alloc")] #[allow(unused_imports)] #[macro_use] extern crate alloc; #[cfg(feature = "arithmetic")] mod arithmetic; #[cfg(feature = "ecdh")] pub mod ecdh; #[cfg(feature = "ecdsa-core")] pub mod ecdsa; #[cfg(feature = "schnorr")] pub mod schnorr; #[cfg(any(feature = "test-vectors", test))] pub mod test_vectors; pub use elliptic_curve::{self, bigint::U256}; #[cfg(feature = "arithmetic")] pub use arithmetic::{affine::AffinePoint, projective::ProjectivePoint, scalar::Scalar}; #[cfg(feature = "expose-field")] pub use arithmetic::FieldElement; #[cfg(feature = "pkcs8")] pub use elliptic_curve::pkcs8; #[cfg(feature = "sha2")] pub use sha2; use elliptic_curve::{ bigint::ArrayEncoding, consts::{U32, U33, U64}, generic_array::GenericArray, FieldBytesEncoding, }; /// Order of the secp256k1 elliptic curve in hexadecimal. const ORDER_HEX: &str = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"; /// Order of the secp256k1 elliptic curve. const ORDER: U256 = U256::from_be_hex(ORDER_HEX); /// secp256k1 (K-256) elliptic curve. /// /// Specified in Certicom's SECG in "SEC 2: Recommended Elliptic Curve Domain Parameters": /// /// /// /// The curve's equation is `y² = x³ + 7` over a ~256-bit prime field. /// /// It's primarily notable for usage in Bitcoin and other cryptocurrencies, /// particularly in conjunction with the Elliptic Curve Digital Signature /// Algorithm (ECDSA). #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] pub struct Secp256k1; impl elliptic_curve::Curve for Secp256k1 { /// 32-byte serialized field elements. type FieldBytesSize = U32; /// 256-bit field modulus. type Uint = U256; /// Curve order. const ORDER: U256 = ORDER; } impl elliptic_curve::PrimeCurve for Secp256k1 {} impl elliptic_curve::point::PointCompression for Secp256k1 { /// secp256k1 points are typically compressed. const COMPRESS_POINTS: bool = true; } #[cfg(feature = "jwk")] impl elliptic_curve::JwkParameters for Secp256k1 { const CRV: &'static str = "secp256k1"; } #[cfg(feature = "pkcs8")] impl pkcs8::AssociatedOid for Secp256k1 { const OID: pkcs8::ObjectIdentifier = pkcs8::ObjectIdentifier::new_unwrap("1.3.132.0.10"); } /// Compressed SEC1-encoded secp256k1 (K-256) curve point. pub type CompressedPoint = GenericArray; /// SEC1-encoded secp256k1 (K-256) curve point. pub type EncodedPoint = elliptic_curve::sec1::EncodedPoint; /// secp256k1 (K-256) field element serialized as bytes. /// /// Byte array containing a serialized field element value (base field or scalar). pub type FieldBytes = elliptic_curve::FieldBytes; impl FieldBytesEncoding for U256 { fn decode_field_bytes(field_bytes: &FieldBytes) -> Self { U256::from_be_byte_array(*field_bytes) } fn encode_field_bytes(&self) -> FieldBytes { self.to_be_byte_array() } } /// Bytes used by a wide reduction: twice the width of [`FieldBytes`]. pub type WideBytes = GenericArray; /// Non-zero secp256k1 (K-256) scalar field element. #[cfg(feature = "arithmetic")] pub type NonZeroScalar = elliptic_curve::NonZeroScalar; /// secp256k1 (K-256) public key. #[cfg(feature = "arithmetic")] pub type PublicKey = elliptic_curve::PublicKey; /// secp256k1 (K-256) secret key. pub type SecretKey = elliptic_curve::SecretKey; #[cfg(not(feature = "arithmetic"))] impl elliptic_curve::sec1::ValidatePublicKey for Secp256k1 {} /// Bit representation of a secp256k1 (K-256) scalar field element. #[cfg(feature = "bits")] pub type ScalarBits = elliptic_curve::scalar::ScalarBits; k256-0.13.3/src/schnorr/signing.rs000064400000000000000000000156741046102023000146650ustar 00000000000000//! Taproot Schnorr signing key. use super::{tagged_hash, Signature, VerifyingKey, AUX_TAG, CHALLENGE_TAG, NONCE_TAG}; use crate::{ AffinePoint, FieldBytes, NonZeroScalar, ProjectivePoint, PublicKey, Scalar, SecretKey, }; use elliptic_curve::{ bigint::U256, ops::Reduce, rand_core::CryptoRngCore, subtle::ConditionallySelectable, zeroize::{Zeroize, ZeroizeOnDrop}, }; use sha2::{Digest, Sha256}; use signature::{ digest::{consts::U32, FixedOutput}, hazmat::{PrehashSigner, RandomizedPrehashSigner}, DigestSigner, Error, KeypairRef, RandomizedDigestSigner, RandomizedSigner, Result, Signer, }; #[cfg(feature = "serde")] use serdect::serde::{de, ser, Deserialize, Serialize}; #[cfg(debug_assertions)] use signature::hazmat::PrehashVerifier; /// Taproot Schnorr signing key. #[derive(Clone)] pub struct SigningKey { /// Secret key material secret_key: NonZeroScalar, /// Verifying key verifying_key: VerifyingKey, } impl SigningKey { /// Generate a cryptographically random [`SigningKey`]. pub fn random(rng: &mut impl CryptoRngCore) -> Self { NonZeroScalar::random(rng).into() } /// Parse signing key from big endian-encoded bytes. pub fn from_bytes(bytes: &[u8]) -> Result { NonZeroScalar::try_from(bytes) .map(Into::into) .map_err(|_| Error::new()) } /// Serialize as bytes. pub fn to_bytes(&self) -> FieldBytes { self.secret_key.to_bytes() } /// Get the [`VerifyingKey`] that corresponds to this signing key. pub fn verifying_key(&self) -> &VerifyingKey { &self.verifying_key } /// Borrow the secret [`NonZeroScalar`] value for this key. /// /// # ⚠️ Warning /// /// This value is key material. /// /// Please treat it with the care it deserves! pub fn as_nonzero_scalar(&self) -> &NonZeroScalar { &self.secret_key } /// Compute Schnorr signature. /// /// # ⚠️ Warning /// /// This is a low-level interface intended only for unusual use cases /// involving signing pre-hashed messages. /// /// The preferred interfaces are the [`Signer`] or [`RandomizedSigner`] traits. pub fn sign_prehash_with_aux_rand( &self, msg_digest: &[u8; 32], aux_rand: &[u8; 32], ) -> Result { let mut t = tagged_hash(AUX_TAG).chain_update(aux_rand).finalize(); for (a, b) in t.iter_mut().zip(self.secret_key.to_bytes().iter()) { *a ^= b } let rand = tagged_hash(NONCE_TAG) .chain_update(t) .chain_update(self.verifying_key.as_affine().x.to_bytes()) .chain_update(msg_digest) .finalize(); let k = NonZeroScalar::try_from(&*rand) .map(Self::from) .map_err(|_| Error::new())?; let secret_key = k.secret_key; let verifying_point = AffinePoint::from(k.verifying_key); let r = verifying_point.x.normalize(); let e = >::reduce_bytes( &tagged_hash(CHALLENGE_TAG) .chain_update(r.to_bytes()) .chain_update(self.verifying_key.to_bytes()) .chain_update(msg_digest) .finalize(), ); let s = *secret_key + e * *self.secret_key; let s = Option::from(NonZeroScalar::new(s)).ok_or_else(Error::new)?; let sig = Signature { r, s }; #[cfg(debug_assertions)] self.verifying_key.verify_prehash(msg_digest, &sig)?; Ok(sig) } } impl From for SigningKey { #[inline] fn from(mut secret_key: NonZeroScalar) -> SigningKey { let odd = (ProjectivePoint::GENERATOR * *secret_key) .to_affine() .y .normalize() .is_odd(); secret_key.conditional_assign(&-secret_key, odd); let verifying_key = VerifyingKey { inner: PublicKey::from_secret_scalar(&secret_key), }; SigningKey { secret_key, verifying_key, } } } impl From for SigningKey { #[inline] fn from(secret_key: SecretKey) -> SigningKey { SigningKey::from(&secret_key) } } impl From<&SecretKey> for SigningKey { fn from(secret_key: &SecretKey) -> SigningKey { secret_key.to_nonzero_scalar().into() } } // // `*Signer` trait impls // impl DigestSigner for SigningKey where D: Digest + FixedOutput, { fn try_sign_digest(&self, digest: D) -> Result { self.sign_prehash_with_aux_rand(&digest.finalize_fixed().into(), &Default::default()) } } impl PrehashSigner for SigningKey { fn sign_prehash(&self, prehash: &[u8]) -> Result { let prehash = prehash.try_into().map_err(|_| Error::new())?; self.sign_prehash_with_aux_rand(&prehash, &Default::default()) } } impl RandomizedDigestSigner for SigningKey where D: Digest + FixedOutput, { fn try_sign_digest_with_rng( &self, rng: &mut impl CryptoRngCore, digest: D, ) -> Result { let mut aux_rand = [0u8; 32]; rng.fill_bytes(&mut aux_rand); self.sign_prehash_with_aux_rand(&digest.finalize_fixed().into(), &aux_rand) } } impl RandomizedSigner for SigningKey { fn try_sign_with_rng(&self, rng: &mut impl CryptoRngCore, msg: &[u8]) -> Result { self.try_sign_digest_with_rng(rng, Sha256::new_with_prefix(msg)) } } impl RandomizedPrehashSigner for SigningKey { fn sign_prehash_with_rng( &self, rng: &mut impl CryptoRngCore, prehash: &[u8], ) -> Result { let prehash = prehash.try_into().map_err(|_| Error::new())?; let mut aux_rand = [0u8; 32]; rng.fill_bytes(&mut aux_rand); self.sign_prehash_with_aux_rand(&prehash, &aux_rand) } } impl Signer for SigningKey { fn try_sign(&self, msg: &[u8]) -> Result { self.try_sign_digest(Sha256::new_with_prefix(msg)) } } // // Other trait impls // impl AsRef for SigningKey { fn as_ref(&self) -> &VerifyingKey { &self.verifying_key } } impl Drop for SigningKey { fn drop(&mut self) { self.secret_key.zeroize(); } } impl KeypairRef for SigningKey { type VerifyingKey = VerifyingKey; } impl ZeroizeOnDrop for SigningKey {} #[cfg(feature = "serde")] impl Serialize for SigningKey { fn serialize(&self, serializer: S) -> core::result::Result where S: ser::Serializer, { self.secret_key.serialize(serializer) } } #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for SigningKey { fn deserialize(deserializer: D) -> core::result::Result where D: de::Deserializer<'de>, { Ok(SigningKey::from(NonZeroScalar::deserialize(deserializer)?)) } } k256-0.13.3/src/schnorr/verifying.rs000064400000000000000000000104251046102023000152160ustar 00000000000000//! Taproot Schnorr verifying key. use super::{tagged_hash, Signature, CHALLENGE_TAG}; use crate::{AffinePoint, FieldBytes, ProjectivePoint, PublicKey, Scalar}; use elliptic_curve::{ bigint::U256, group::prime::PrimeCurveAffine, ops::{LinearCombination, Reduce}, point::DecompactPoint, }; use sha2::{ digest::{consts::U32, FixedOutput}, Digest, Sha256, }; use signature::{hazmat::PrehashVerifier, DigestVerifier, Error, Result, Verifier}; #[cfg(feature = "serde")] use serdect::serde::{de, ser, Deserialize, Serialize}; /// Taproot Schnorr verifying key. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct VerifyingKey { /// Inner public key pub(super) inner: PublicKey, } impl VerifyingKey { /// Borrow the inner [`AffinePoint`] this type wraps. pub fn as_affine(&self) -> &AffinePoint { self.inner.as_affine() } /// Serialize as bytes. pub fn to_bytes(&self) -> FieldBytes { self.as_affine().x.to_bytes() } /// Parse verifying key from big endian-encoded x-coordinate. pub fn from_bytes(bytes: &[u8]) -> Result { let maybe_affine_point = AffinePoint::decompact(FieldBytes::from_slice(bytes)); let affine_point = Option::from(maybe_affine_point).ok_or_else(Error::new)?; PublicKey::from_affine(affine_point) .map_err(|_| Error::new())? .try_into() } } // // `*Verifier` trait impls // impl DigestVerifier for VerifyingKey where D: Digest + FixedOutput, { fn verify_digest(&self, digest: D, signature: &Signature) -> Result<()> { self.verify_prehash(digest.finalize_fixed().as_slice(), signature) } } impl PrehashVerifier for VerifyingKey { fn verify_prehash( &self, prehash: &[u8], signature: &Signature, ) -> core::result::Result<(), Error> { let prehash: [u8; 32] = prehash.try_into().map_err(|_| Error::new())?; let (r, s) = signature.split(); let e = >::reduce_bytes( &tagged_hash(CHALLENGE_TAG) .chain_update(signature.r.to_bytes()) .chain_update(self.to_bytes()) .chain_update(prehash) .finalize(), ); let R = ProjectivePoint::lincomb( &ProjectivePoint::GENERATOR, s, &self.inner.to_projective(), &-e, ) .to_affine(); if R.is_identity().into() || R.y.normalize().is_odd().into() || R.x.normalize() != *r { return Err(Error::new()); } Ok(()) } } impl Verifier for VerifyingKey { fn verify(&self, msg: &[u8], signature: &Signature) -> Result<()> { self.verify_digest(Sha256::new_with_prefix(msg), signature) } } // // Other trait impls // impl From for AffinePoint { fn from(vk: VerifyingKey) -> AffinePoint { *vk.as_affine() } } impl From<&VerifyingKey> for AffinePoint { fn from(vk: &VerifyingKey) -> AffinePoint { *vk.as_affine() } } impl From for PublicKey { fn from(vk: VerifyingKey) -> PublicKey { vk.inner } } impl From<&VerifyingKey> for PublicKey { fn from(vk: &VerifyingKey) -> PublicKey { vk.inner } } impl TryFrom for VerifyingKey { type Error = Error; fn try_from(public_key: PublicKey) -> Result { if public_key.as_affine().y.normalize().is_even().into() { Ok(Self { inner: public_key }) } else { Err(Error::new()) } } } impl TryFrom<&PublicKey> for VerifyingKey { type Error = Error; fn try_from(public_key: &PublicKey) -> Result { Self::try_from(*public_key) } } #[cfg(feature = "serde")] impl Serialize for VerifyingKey { fn serialize(&self, serializer: S) -> core::result::Result where S: ser::Serializer, { self.inner.serialize(serializer) } } #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for VerifyingKey { fn deserialize(deserializer: D) -> core::result::Result where D: de::Deserializer<'de>, { VerifyingKey::try_from(PublicKey::deserialize(deserializer)?).map_err(de::Error::custom) } } k256-0.13.3/src/schnorr.rs000064400000000000000000000410321046102023000132120ustar 00000000000000//! Taproot Schnorr signatures as defined in [BIP340]. //! //! # About //! //! [Schnorr signatures] are a simple group-based digital signature scheme with //! a number of desirable properties relating to security and composability: //! //! - Provably secure: strongly unforgable under chosen message attack (SUF-CMA). //! - Non-malleable: signatures cannot be altered by an attacker and still verify. //! - Linear: multiple parties can collaborate to produce a valid signature //! a.k.a. multisignatures. //! //! Originally described in the late 1980s by their eponymous creator Claus //! Schnorr, they were patent-encumbered and thus lingered in obscurity until //! the [relevant patents] expired in 2010. //! //! Since then, Schnorr signatures have seen something of a resurgence, with //! [EdDSA] and its concrete instantiation Ed25519 over the Curve25519 elliptic //! curve becoming the first Schnorr variant to see mainstream standardization. //! //! The Taproot upgrade to Bitcoin includes a variant of Schnorr which operates //! over the secp256k1 elliptic curve, and is specified in [BIP340]. //! That is the variant which is implemented by this crate. //! //! Because Taproot Schnorr is intended for use in consensus-critical //! applications (e.g. Bitcoin), it is fully specified such that no two //! implementations should disagree on the validity of a signature. //! //! # Usage //! #![cfg_attr(feature = "std", doc = "```")] #![cfg_attr(not(feature = "std"), doc = "```ignore")] //! # fn main() -> Result<(), Box> { //! use k256::schnorr::{ //! signature::{Signer, Verifier}, //! SigningKey, VerifyingKey //! }; //! use rand_core::OsRng; // requires 'getrandom' feature //! //! // //! // Signing //! // //! let signing_key = SigningKey::random(&mut OsRng); // serialize with `.to_bytes()` //! let verifying_key_bytes = signing_key.verifying_key().to_bytes(); // 32-bytes //! //! let message = b"Schnorr signatures prove knowledge of a secret in the random oracle model"; //! let signature = signing_key.sign(message); // returns `k256::schnorr::Signature` //! //! // //! // Verification //! // //! let verifying_key = VerifyingKey::from_bytes(&verifying_key_bytes)?; //! verifying_key.verify(message, &signature)?; //! # Ok(()) //! # } //! ``` //! //! [Schnorr signatures]: https://en.wikipedia.org/wiki/Schnorr_signature //! [BIP340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki //! [relevant patents]: https://patents.google.com/patent/US4995082 //! [EdDSA]: https://en.wikipedia.org/wiki/EdDSA #![allow(non_snake_case, clippy::many_single_char_names)] mod signing; mod verifying; pub use self::{signing::SigningKey, verifying::VerifyingKey}; pub use signature::{self, rand_core::CryptoRngCore, Error}; use crate::{arithmetic::FieldElement, NonZeroScalar}; use core::fmt; use elliptic_curve::subtle::ConstantTimeEq; use sha2::{Digest, Sha256}; use signature::Result; const AUX_TAG: &[u8] = b"BIP0340/aux"; const NONCE_TAG: &[u8] = b"BIP0340/nonce"; const CHALLENGE_TAG: &[u8] = b"BIP0340/challenge"; /// Taproot Schnorr signature serialized as bytes. pub type SignatureBytes = [u8; Signature::BYTE_SIZE]; /// Taproot Schnorr signature as defined in [BIP340]. /// /// [BIP340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki #[derive(Copy, Clone)] pub struct Signature { r: FieldElement, s: NonZeroScalar, } impl Signature { /// Size of a Taproot Schnorr signature in bytes. pub const BYTE_SIZE: usize = 64; /// Serialize this signature as bytes. pub fn to_bytes(&self) -> SignatureBytes { let mut ret = [0; Self::BYTE_SIZE]; let (r_bytes, s_bytes) = ret.split_at_mut(Self::BYTE_SIZE / 2); r_bytes.copy_from_slice(&self.r.to_bytes()); s_bytes.copy_from_slice(&self.s.to_bytes()); ret } /// Get the `r` component of this signature. fn r(&self) -> &FieldElement { &self.r } /// Get the `s` component of this signature. fn s(&self) -> &NonZeroScalar { &self.s } /// Split this signature into its `r` and `s` components. fn split(&self) -> (&FieldElement, &NonZeroScalar) { (self.r(), self.s()) } } impl Eq for Signature {} impl From for SignatureBytes { fn from(signature: Signature) -> SignatureBytes { signature.to_bytes() } } impl From<&Signature> for SignatureBytes { fn from(signature: &Signature) -> SignatureBytes { signature.to_bytes() } } impl PartialEq for Signature { fn eq(&self, other: &Self) -> bool { (self.r == other.r) && (self.s.ct_eq(&other.s).into()) } } impl TryFrom<&[u8]> for Signature { type Error = Error; fn try_from(bytes: &[u8]) -> Result { let (r_bytes, s_bytes) = bytes.split_at(Self::BYTE_SIZE / 2); let r: FieldElement = Option::from(FieldElement::from_bytes(r_bytes.into())).ok_or_else(Error::new)?; // one of the rules for valid signatures: !is_infinite(R); if r.is_zero().into() { return Err(Error::new()); } let s = NonZeroScalar::try_from(s_bytes).map_err(|_| Error::new())?; Ok(Self { r, s }) } } impl fmt::Debug for Signature { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self.to_bytes()) } } impl signature::SignatureEncoding for Signature { type Repr = SignatureBytes; fn to_bytes(&self) -> Self::Repr { self.into() } } impl signature::PrehashSignature for Signature { type Digest = Sha256; } fn tagged_hash(tag: &[u8]) -> Sha256 { let tag_hash = Sha256::digest(tag); let mut digest = Sha256::new(); digest.update(tag_hash); digest.update(tag_hash); digest } // Test vectors from: // https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv #[cfg(test)] mod tests { use super::{Signature, SigningKey, VerifyingKey}; use hex_literal::hex; use signature::hazmat::PrehashVerifier; /// Signing test vector struct SignVector { /// Index of test case index: u8, /// Signing key secret_key: [u8; 32], /// Verifying key public_key: [u8; 32], /// Auxiliary randomness value aux_rand: [u8; 32], /// Message digest message: [u8; 32], /// Expected signature signature: [u8; 64], } /// BIP340 signing test vectors: index 0-3 const BIP340_SIGN_VECTORS: &[SignVector] = &[ SignVector { index: 0, secret_key: hex!("0000000000000000000000000000000000000000000000000000000000000003"), public_key: hex!("F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9"), aux_rand: hex!("0000000000000000000000000000000000000000000000000000000000000000"), message: hex!("0000000000000000000000000000000000000000000000000000000000000000"), signature: hex!( "E907831F80848D1069A5371B402410364BDF1C5F8307B0084C55F1CE2DCA8215 25F66A4A85EA8B71E482A74F382D2CE5EBEEE8FDB2172F477DF4900D310536C0" ), }, SignVector { index: 1, secret_key: hex!("B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF"), public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), aux_rand: hex!("0000000000000000000000000000000000000000000000000000000000000001"), message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), signature: hex!( "6896BD60EEAE296DB48A229FF71DFE071BDE413E6D43F917DC8DCF8C78DE3341 8906D11AC976ABCCB20B091292BFF4EA897EFCB639EA871CFA95F6DE339E4B0A" ), }, SignVector { index: 2, secret_key: hex!("C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C9"), public_key: hex!("DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8"), aux_rand: hex!("C87AA53824B4D7AE2EB035A2B5BBBCCC080E76CDC6D1692C4B0B62D798E6D906"), message: hex!("7E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C"), signature: hex!( "5831AAEED7B44BB74E5EAB94BA9D4294C49BCF2A60728D8B4C200F50DD313C1B AB745879A5AD954A72C45A91C3A51D3C7ADEA98D82F8481E0E1E03674A6F3FB7" ), }, // test fails if msg is reduced modulo p or n SignVector { index: 3, secret_key: hex!("0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710"), public_key: hex!("25D1DFF95105F5253C4022F628A996AD3A0D95FBF21D468A1B33F8C160D8F517"), aux_rand: hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), message: hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), signature: hex!( "7EB0509757E246F19449885651611CB965ECC1A187DD51B64FDA1EDC9637D5EC 97582B9CB13DB3933705B32BA982AF5AF25FD78881EBB32771FC5922EFC66EA3" ), }, ]; #[test] fn bip340_sign_vectors() { for vector in BIP340_SIGN_VECTORS { let sk = SigningKey::from_bytes(&vector.secret_key).unwrap(); assert_eq!(sk.verifying_key().to_bytes().as_slice(), &vector.public_key); let sig = sk .sign_prehash_with_aux_rand(&vector.message, &vector.aux_rand) .unwrap_or_else(|_| { panic!( "low-level Schnorr signing failure for index {}", vector.index ) }); assert_eq!( vector.signature, sig.to_bytes(), "wrong signature for index {}", vector.index ); } } /// Verification test vector struct VerifyVector { /// Index of test case index: u8, /// Verifying key public_key: [u8; 32], /// Message digest message: [u8; 32], /// Claimed signature signature: [u8; 64], /// Is signature valid valid: bool, } /// BIP340 verification test vectors: index 4-14 const BIP340_VERIFY_VECTORS: &[VerifyVector] = &[ VerifyVector { index: 4, public_key: hex!("D69C3509BB99E412E68B0FE8544E72837DFA30746D8BE2AA65975F29D22DC7B9"), message: hex!("4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703"), signature: hex!( "00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C63 76AFB1548AF603B3EB45C9F8207DEE1060CB71C04E80F593060B07D28308D7F4" ), valid: true, }, // public key not on curve VerifyVector { index: 5, public_key: hex!("EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34"), message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), signature: hex!( "6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769 69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B" ), valid: false, }, // has_even_y(R) is false VerifyVector { index: 6, public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), signature: hex!( "FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A1460297556 3CC27944640AC607CD107AE10923D9EF7A73C643E166BE5EBEAFA34B1AC553E2" ), valid: false, }, // negated message VerifyVector { index: 7, public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), signature: hex!( "1FA62E331EDBC21C394792D2AB1100A7B432B013DF3F6FF4F99FCB33E0E1515F 28890B3EDB6E7189B630448B515CE4F8622A954CFE545735AAEA5134FCCDB2BD" ), valid: false, }, // negated s value VerifyVector { index: 8, public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), signature: hex!( "6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769 961764B3AA9B2FFCB6EF947B6887A226E8D7C93E00C5ED0C1834FF0D0C2E6DA6" ), valid: false, }, // sG - eP is infinite. Test fails in single verification if has_even_y(inf) is defined as true and x(inf) as 0 VerifyVector { index: 9, public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), signature: hex!( "0000000000000000000000000000000000000000000000000000000000000000 123DDA8328AF9C23A94C1FEECFD123BA4FB73476F0D594DCB65C6425BD186051" ), valid: false, }, // sG - eP is infinite. Test fails in single verification if has_even_y(inf) is defined as true and x(inf) as 1 VerifyVector { index: 10, public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), signature: hex!( "0000000000000000000000000000000000000000000000000000000000000001 7615FBAF5AE28864013C099742DEADB4DBA87F11AC6754F93780D5A1837CF197" ), valid: false, }, // sig[0:32] is not an X coordinate on the curve VerifyVector { index: 11, public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), signature: hex!( "4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D 69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B" ), valid: false, }, // sig[0:32] is equal to field size VerifyVector { index: 12, public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), signature: hex!( "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F 69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B" ), valid: false, }, // sig[32:64] is equal to curve order VerifyVector { index: 13, public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"), message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), signature: hex!( "6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141" ), valid: false, }, // public key is not a valid X coordinate because it exceeds the field size VerifyVector { index: 14, public_key: hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30"), message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"), signature: hex!( "6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769 69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B" ), valid: false, }, ]; #[test] fn bip340_verify_vectors() { for vector in BIP340_VERIFY_VECTORS { let valid = match ( VerifyingKey::from_bytes(&vector.public_key), Signature::try_from(vector.signature.as_slice()), ) { (Ok(pk), Ok(sig)) => pk.verify_prehash(&vector.message, &sig).is_ok(), _ => false, }; assert_eq!( vector.valid, valid, "incorrect validation for index {}", vector.index ); } } } k256-0.13.3/src/test_vectors/data/wycheproof.blb000064400000000000000000000742641046102023000175060ustar 00000000000000!123400![ktInV5pq]ıڠ2!8D{v`2&vq ~ oMessage n5UE) ƲҍP,ụA@ yf~ܻUb· -(Y[ x,~;*x;Td; e*qx^f:=c!B/N$^8A֪aR mJ`wJO ە<~y @~1duVd( ?[smnP|Xfz q! %։|)mPqF,m?"HM<)1 F_pեg>%ImF!iU=@!m*Z'*Hs'+ޖU»N!FnR"߼It N=m<5K|5!z;%&Aݝ ܖ#C8q}!YNM󍞌ߺ6a,vz?6S!.lfw4M&]5 ~'c JOt; H:w&e]HTGЏԸG0E!ZR/aCa"6+' `P# $I$I$I$I$I$cj ` Ԛ RG0E 2 MM'|ɴ\ s&]!˜L*Aj*HmJ&l[srxhF0D D cm k^w#!.D $I$I$I$I$I$cj ` Ԛ R0 .423i&r-_3@ 6GW .FkL :$7 K¬\ &zma` v}kY1l `6l1.r&Lҵhkw 1IAB{ٽlv}b I5#%4d,;8 aZ#Ѥ4ϟ!yWC Cw%iiQY=Hþl!%\;[WKYzc/o'w 0F!>V_G_ g <Ƀ#e!u#?̐ Y"d}|! :JyK 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0F!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0D!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1  0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#eoR3oz$ݛ2uV1  0 0G!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0G!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0G!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0JIw0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0I%0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0G0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1ޭ 0J"&Iw!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0I"%%!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0M"#!>V_G_ g <Ƀ#eޭ oR3oz$ݛ2uV1 0J!>V_G_ g <Ƀ#e"%Iw oR3oz$ݛ2uV1 0I!>V_G_ g <Ƀ#e"$% oR3oz$ݛ2uV1 0M!>V_G_ g <Ƀ#e"" oR3oz$ݛ2uV1ޭ 0M0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0K0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0M")!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0K"'!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0M!>V_G_ g <Ƀ#e"( oR3oz$ݛ2uV1 0K!>V_G_ g <Ƀ#e"& oR3oz$ݛ2uV1 0 00E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0I"!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0I!>V_G_ g <Ƀ#e" oR3oz$ݛ2uV1 01E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0I"!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0I!>V_G_ g <Ƀ#e" oR3oz$ݛ2uV1  .E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 /E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 1E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 2E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0 0I00D!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1  0D!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1  0D!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1" 0!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0G0!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0G!>V_G_ g <Ƀ#e oR3oz$ݛ2uV10 0H!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0G0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 J0#!>V_G_ g <Ƀ#e R0g!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 oR3oz$ݛ2uV1 0F!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0F!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0G!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0G!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E">V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E >V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e!oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#eoR3oz$ݛ2uV1 0J!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0J!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1  0N!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1  0N!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0I>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0I!>V_G_ g <Ƀ#eoR3oz$ݛ2uV1 0I>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0I!>V_G_ g <Ƀ#eoR3oz$ݛ2uV1 0J>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0J!>V_G_ g <Ƀ#eoR3oz$ݛ2uV1 0M>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0M!>V_G_ g <Ƀ#eoR3oz$ݛ2uV1 0E>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#eoR3oz$ݛ2uV1 H0" oR3oz$ݛ2uV1 J0# oR3oz$ݛ2uV1 L0$!>V_G_ g <Ƀ#e 0G#>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0G!>V_G_ g <Ƀ#e"oR3oz$ݛ2uV1 0G#>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0G!>V_G_ g <Ƀ#e"oR3oz$ݛ2uV1 0G!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0G#>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0G!>V_G_ g <Ƀ#e"oR3oz$ݛ2uV1 L0$ oR3oz$ݛ2uV1 N0%!>V_G_ g <Ƀ#e L0$ oR3oz$ݛ2uV1 N0%!>V_G_ g <Ƀ#e 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 L0$ oR3oz$ݛ2uV1 N0%!>V_G_ g <Ƀ#e 0I"% >V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0I!>V_G_ g <Ƀ#e"$oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e mR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ# oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1:  0D >V_G_ g <Ƀ# oR3oz$ݛ2uV1  0D!>V_G_ g <Ƀ#eoR3oz$ݛ2uV1  0D!>V_G_ g <Ƀ#eR3oz$ݛ2uV1 0F">V_G_ g <Ƀ#e oR3oz$ݛ2uV1 0F!>V_G_ g <Ƀ#e!oR3oz$ݛ2uV1 N0%  oR3oz$ݛ2uV1 P0&!>V_G_ g <Ƀ#e  N0% oR3oz$ݛ2uV1 P0&!>V_G_ g <Ƀ#e 0E!>V_G 꼤\EtXd oR3oz$ݛ2uV1  0D >V_GC0F?>L$ oR3oz$ݛ2uV1 0E!~c1eEz{* CJ46|ܛ oR3oz$ݛ2uV1  0D ~c1eEzyO2 ! oR3oz$ݛ2uV1 0E!~c1eEz|FC[OdfFZ oR3oz$ݛ2uV1 0E!>V_G_ g <Ƀ#e oR3oz$ݛ2uV1  0D ~c1eEz{* CJ46|ܛ oR3oz$ݛ2uV1 0F!>V_G_ g <Ƀ#e!oR3oz$ݛخ V_G_ g <Ƀ#e!oR3oz$ݛL P,#y 0E!>V_G_ g <Ƀ#e u#?̐ Y"d~E) ZF 0F!>V_G_ g <Ƀ#e!u#?̐ Y"d>h'QAi7ލ 0F!>V_G_ g <Ƀ#e!oR3oz$ݛ2uV1 0F!>V_G_ g <Ƀ#e!u#?̐ Y"d~E) ZF 0 0 0 P0&!H;^6AA P0&!H;^6A@ P0&!H;^6AB P0&!/ P0&!0 0  0 B 0 1 0 P0&!H;^6AA P0&!H;^6A@ P0&!H;^6AB P0&!/ P0&!0 0  0 B 0 0 0 P0&!H;^6AA P0&!H;^6A@ P0&!H;^6AB P0&!/ P0&!0 0  0 B P0&!H;^6AA P0&!H;^6AA P0&!H;^6AA 0F!H;^6AA!H;^6AA 0F!H;^6AA!H;^6A@ 0F!H;^6AA!H;^6AB 0F!H;^6AA!/ 0F!H;^6AA!0 T0(!H;^6AA  P0&!H;^6AA B P0&!H;^6A@ P0&!H;^6A@ P0&!H;^6A@ 0F!H;^6A@!H;^6AA 0F!H;^6A@!H;^6A@ 0F!H;^6A@!H;^6AB 0F!H;^6A@!/ 0F!H;^6A@!0 T0(!H;^6A@  P0&!H;^6A@ B P0&!H;^6AB P0&!H;^6AB P0&!H;^6AB 0F!H;^6AB!H;^6AA 0F!H;^6AB!H;^6A@ 0F!H;^6AB!H;^6AB 0F!H;^6AB!/ 0F!H;^6AB!0 T0(!H;^6AB  P0&!H;^6AB B P0&!/ P0&!/ P0&!/ 0F!/!H;^6AA 0F!/!H;^6A@ 0F!/!H;^6AB 0F!/!/ 0F!/!0 T0(!/  P0&!/ B P0&!0 P0&!0 P0&!0 0F!0!H;^6AA 0F!0!H;^6A@ 0F!0!H;^6AB 0F!0!/ 0F!0!0 T0(!0  P0&!0 B 0 0 0  0 %s s%s 00  0 0  255850E!} 4S M%Xz^ 5@I=e/+ChstEH5B~ 4264797240E!’grCU"EF"+4?&*3a0V ngo(e?W)q.^4h+$gk&@ 71386848910E (JNFEf>P3ZU%!i+Zn' y%L! oNq# 103593316680F!&IARSk' TRzz!>+c/7W*F?+2[LJTM 39494012150F!Ge>"]?-K .Kt!e\ϳ>0Mo{P>"Qiࢅ`+ 1344293079 0D 2S2aq*%-7ڊKq @aH]JfH 37062117120F!:эm  E:ULLSg툠!?X5Pxo#ZLz 13515303700F!v*$ Vwyڰ>S܎ 109532613510E -ũ@giqOlaZ/6=¤X! kZA/: Qem[4;1e 59873500410E!%#t=P"q-X?Cy͂Ac^QO '"s,hacm+ P  34630068780F!D|:&nD}R97 !𡇋,Snp7z^n䀢+.q s 98173202870E S 2 V< qh'Xœkr!vLϟsp h7F?SN 32220410460F!TU-rH=H/6T)LM疶%^Պw!9J6 Iܽ&dIΐ 66663071040E!琝AC/j64d+ [dppǢa Bׂ26ȋ|=gJ]̬u~= P 10359518980E Y$2 Y15{"KjO!Np[eFDm.61 18465971950E!ɲb#8Iud߈:q=) !:cyCLL#+#ǘ 31360461890E!46 +e6]KПfL( :>˜SpNRXz Ssr˾MI 26637842540F!וuΥ4A ֽ!"?=Zfph !'~4F5@$aL ǩ 1652100524 0D $x<2YVD&Uc楦a~B JYr!eΣkuZxP 57480816960F! JYlhXΟe=S.RiYR!n&lõ~a:vD^`t?T* 63439134680E!n ?Yc1'zb (y"LfbI, hj:AI*R 15411035980F!wcW4 9539041050F!˶CPFdP ~Y7*?.m֮!͜9JeЪ2.9k*h Gz 9788480390F!G- %̤5#8\Ԟ!S(k6jz IjRhK  36106724420F!N1Kۗcߤśg XL!'wubL+$'RO>(@J 10542407050E!O P-YԄrx L#v zk O|ΓXցOC| 5174448197 0D ][87I"'3&ʇ\| aM  dꙑ.˸4\FzO`hTC& 1967561251 0D @4-eӃMr3vڂdw W\'xHz4SFY 34472533430E!y5$k{]Vb =n`y,[ _#' x-JY^Ibp(fd 3682643180E 4̼ȂEI3DAry_yjgTp!'o@w ~Z+;C{ 32611986080E .G!6:ә,Z&9],-wx$$u8q0!+Їէ~rkJ,n7l& 96787810940E hR͟sygeVp{hBF !w{7#4[ E9L! y"qM 4958823823 0D VHy+Th__c\[L1 66 W^hlpNf 68241894360F!1%]c Yӣ!cǸ%zG}qM7=(  484245425 0D RƃND7IԖNu 'm8i= 4yg@E &N'KAb;7p06EQ#P_@-r/ɺ!H;^6A>;70F!,!H;^6A>BX^Hf@p h?pԳYO,N"@pYiNNKQ툍(؝V*0F!H;^6A?!H;^6A>@D3{`*\575 1 ݂2RB?wGp"/CNȌm}Vc 0D  >u`/@;CAaAw@`,$Nî#M|Yh7݇@\ vszjx9jr)̵R 0D  $#p1N&iKwIP?Ɛ_u@ޣ@w[]4`\dZ*T7l\*3RBS,umA֫N>DF4xjyAY1@ET9ޮ`0O6. jPBÏ!ш|{"-уF4rc1Z6 Ow05=05=P0&!H;^6ABBݩ]{]- O4[PxJj%0@Z֦=nuȡӝ@FOOrPr;[g^ )CܼBҝ1pC;-q/C- \0,-M4yR!Q&twya*K1y֚@s_IظSϑ}f\5"}8ݷLBޭHt 0 e@J G--Ȟ²0ⅅref01 %"|9>|& x2fC\ٳ"ރg}Pq:F/]WB)}rKՍ,^TMT[@)ɦ=^0i0'jAdd~Y:O)0E!H;^6@ UUUUUUUUUUUUUUUTL5i?.?9N0% UUUUUUUUUUUUUUUTL5i?.?9N0% UUUUUUUUUUUUUUUTL5i?.B3*X*PIt@>vJa{‰f)Lz 0D ]WnsWP/Fh  UUUUUUUUUUUUUUUTL5i?.@:1Pyn:E@+20OIU@"B^Mqe9$*E ^wǂ4: 0D ]WnsWP/Fh  ]WnsWP/Fh @;7_Gƚ\ |76:^=@ !T53 /kJcNSp& 0D ]WnsWP/Fh  ]WnsWP/Fh B;0>\C/5IBoɝ ,B}^ὠHreKC9߉~0E UUUUUUUUUUUUUUUTL5i?.!ZR/aCa"6+' `P#@#+S.܉ BAI"v@@h=0d8@ A};pO„ 0D UUUUUUUUUUUUUUUTL5i?. D cm k^w#!.DBHlQsl/Ifg^BсhϾp#t#+-֑aŠ' 0D UUUUUUUUUUUUUUUTL5i?. UUUUUUUUUUUUUUUTL5i?.@h|]'B d疆}˂@R`w7l y9U|2u5.˜k0E UUUUUUUUUUUUUUUTL5i?.!0j]$+@ZmT3%לnBfһ3K1ByI33mN/\ő]0E ! kQ J5ؒU-GDF7>'w[+9Y /9*lT @d3 :Ȓמ.3ET'2XM.A0E !km2/t # lo @@n +hޔ`Z_nhp!Nԝ}&@[QJ!'Jp yLS3Q14P0E !UUUUUUUUUUUUUUT|tDt}*?*B6wX)Ud5?w1Ĕn4@%/l=*YӱYZh+QP0E !w|SSb$d6  ulbN#/1@ y4q?Ӧ=)$9o`BGD1:wDnsr6 0D  0Xcy _ϝъC+k,B<{b,۝8\JH ^$l 0D  DAAAAAxS;}?Q%8/%Bڑsj ˔3x遤6f[51VB&uQxɵ! H)EؕrOS 0D  '9s9s9sV':[T@0,97ydߣ[~* Ap=@ZuFR{ ^,nc"iqsKM0E !wwwwwwwwwwwwwwvHg"c@`4V$uc֮dNΛB :2l˻,nspܙGM}ug 0D  dI$I$I$I$I$:R5:I:mFEgkBwܕREH#bp5!C/9B=)ToH J]0E !H;^6AC@\+<I0&}%] PxwB肣^j7<9\CS/6{ 1 0D  ]mA<`Rtfk^ 3@5GD^pބ_g^k>ĵ̄-3Bʸ}gq$!{2NSjEpIul:J3wc-BOCuc HԌR6vG.@C\h`;9՘PA~i+Q 0D UUUUUUUUUUUUUUUTL5i?. 3333333333333332"S?&]F)ss@9'~J}b ^eIBf$4:ه!埄/l rjƴƽ0E!A}m0E@n|\wK< \p UUUUUUUUUUUUUUUTL5i?.Bb!ǩEё8xz4BS>A7n 1ihycEu0F!A}m0E@n|\wK< \p!mmmmm0}3*C'.BҁNi0^Ho:œPRBoc3Y͂k [wkAq?u0F!A}m0E@n|\wK< \p!hϑsT|ZZBEbb`䋟cmG3@O͋nxzeJi=<"0E!A}m0E@n|\wK< \p fffffffffffffffeE߶~L8SH@W[cO& (ho F= 2BW$:.smJmSmf0E!A}m0E@n|\wK< \p I$I$I$I$I$Hǟ2<4B3NB#,~H,5!}9\@(քҪcw\b9&Ɠ{`P0E!A}m0E@n|\wK< \p Z_/'SH*ה uXC{@?9Rt9fB& 8E3;H@^~>3Y&Y }c  'W 9󲅋>4tP+OqlL>( 0D O?V:Kt4Y.#gլ~8 MKڠqw=c_tKUp   0D mjOUlTl==Y*NhYe St>DlVM>'N sq_  0F!ޛkYo e&V^d!#vTGDz?1$D"/ */  0F!ν;W.qt9r KCb2%!g_-h.x#c   0E 8T-(AF,LJ9!,Bin!, G\w/ Qc+r~J>TP;  0F!MÇ\Miӵ]- m\S~6!k>hDu ~ 8y'x  0D I*GX,#?-,% [,9p9ֽ$)2j # 0E AZg_ˑEƓK4Ys1z!RYl)lܒ~fRY7E|g# 0F!i55 ؃%V9p7pL! ͔w{*kz8Xmm# 0F!ό-D`TWӪ"aZg+!"L\g`UX'MAɼCn! 0E b'ZMH^ӱG!W v;!%dʢV]r( S! 0F! 7CCDzlKaLr!7"}L#p HmG8N[c2! 0E! F;6}cKNX$ XPW FgT`)@șf_xlPw, <^wd' 0E Y,Ae/ʽ&vtt]5@l{!_&U r+Ď"d\ ' 0F! p}^@aGN=MKUXY2!fpD쬱L #14s U}` cTJ' 0F!-9-' s&{9<Ҟ&; j!d\`U, K*Qjr>`D.D4+% 0E j%WVoQ"f xWׯC!n *qC()Fdeo!}% 0E ` b4gbK]0-&@!wbnBYV`N3/fY~'o\% 0F! pub const ADD_TEST_VECTORS: &[([u8; 32], [u8; 32])] = &[ ( hex!("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"), hex!("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"), ), ( hex!("C6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE5"), hex!("1AE168FEA63DC339A3C58419466CEAEEF7F632653266D0E1236431A950CFE52A"), ), ( hex!("F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9"), hex!("388F7B0F632DE8140FE337E62A37F3566500A99934C2231B6CB9FD7584B8E672"), ), ( hex!("E493DBF1C10D80F3581E4904930B1404CC6C13900EE0758474FA94ABE8C4CD13"), hex!("51ED993EA0D455B75642E2098EA51448D967AE33BFBDFE40CFE97BDC47739922"), ), ( hex!("2F8BDE4D1A07209355B4A7250A5C5128E88B84BDDC619AB7CBA8D569B240EFE4"), hex!("D8AC222636E5E3D6D4DBA9DDA6C9C426F788271BAB0D6840DCA87D3AA6AC62D6"), ), ( hex!("FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A1460297556"), hex!("AE12777AACFBB620F3BE96017F45C560DE80F0F6518FE4A03C870C36B075F297"), ), ( hex!("5CBDF0646E5DB4EAA398F365F2EA7A0E3D419B7E0330E39CE92BDDEDCAC4F9BC"), hex!("6AEBCA40BA255960A3178D6D861A54DBA813D0B813FDE7B5A5082628087264DA"), ), ( hex!("2F01E5E15CCA351DAFF3843FB70F3C2F0A1BDD05E5AF888A67784EF3E10A2A01"), hex!("5C4DA8A741539949293D082A132D13B4C2E213D6BA5B7617B5DA2CB76CBDE904"), ), ( hex!("ACD484E2F0C7F65309AD178A9F559ABDE09796974C57E714C35F110DFC27CCBE"), hex!("CC338921B0A7D9FD64380971763B61E9ADD888A4375F8E0F05CC262AC64F9C37"), ), ( hex!("A0434D9E47F3C86235477C7B1AE6AE5D3442D49B1943C2B752A68E2A47E247C7"), hex!("893ABA425419BC27A3B6C7E693A24C696F794C2ED877A1593CBEE53B037368D7"), ), ( hex!("774AE7F858A9411E5EF4246B70C65AAC5649980BE5C17891BBEC17895DA008CB"), hex!("D984A032EB6B5E190243DD56D7B7B365372DB1E2DFF9D6A8301D74C9C953C61B"), ), ( hex!("D01115D548E7561B15C38F004D734633687CF4419620095BC5B0F47070AFE85A"), hex!("A9F34FFDC815E0D7A8B64537E17BD81579238C5DD9A86D526B051B13F4062327"), ), ( hex!("F28773C2D975288BC7D1D205C3748651B075FBC6610E58CDDEEDDF8F19405AA8"), hex!("0AB0902E8D880A89758212EB65CDAF473A1A06DA521FA91F29B5CB52DB03ED81"), ), ( hex!("499FDF9E895E719CFD64E67F07D38E3226AA7B63678949E6E49B241A60E823E4"), hex!("CAC2F6C4B54E855190F044E4A7B3D464464279C27A3F95BCC65F40D403A13F5B"), ), ( hex!("D7924D4F7D43EA965A465AE3095FF41131E5946F3C85F79E44ADBCF8E27E080E"), hex!("581E2872A86C72A683842EC228CC6DEFEA40AF2BD896D3A5C504DC9FF6A26B58"), ), ( hex!("E60FCE93B59E9EC53011AABC21C23E97B2A31369B87A5AE9C44EE89E2A6DEC0A"), hex!("F7E3507399E595929DB99F34F57937101296891E44D23F0BE1F32CCE69616821"), ), ( hex!("DEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34"), hex!("4211AB0694635168E997B0EAD2A93DAECED1F4A04A95C0F6CFB199F69E56EB77"), ), ( hex!("5601570CB47F238D2B0286DB4A990FA0F3BA28D1A319F5E7CF55C2A2444DA7CC"), hex!("C136C1DC0CBEB930E9E298043589351D81D8E0BC736AE2A1F5192E5E8B061D58"), ), ( hex!("2B4EA0A797A443D293EF5CFF444F4979F06ACFEBD7E86D277475656138385B6C"), hex!("85E89BC037945D93B343083B5A1C86131A01F60C50269763B570C854E5C09B7A"), ), ( hex!("4CE119C96E2FA357200B559B2F7DD5A5F02D5290AFF74B03F3E471B273211C97"), hex!("12BA26DCB10EC1625DA61FA10A844C676162948271D96967450288EE9233DC3A"), ), ]; /// Scalar multiplication with the generator. /// /// Vectors for secp256k1 are difficult to find. These are the vectors from: /// pub const MUL_TEST_VECTORS: &[([u8; 32], [u8; 32], [u8; 32])] = &[ ( hex!("000000000000000000000000000000000000000000000000018EBBB95EED0E13"), hex!("A90CC3D3F3E146DAADFC74CA1372207CB4B725AE708CEF713A98EDD73D99EF29"), hex!("5A79D6B289610C68BC3B47F3D72F9788A26A06868B4D8E433E1E2AD76FB7DC76"), ), ( hex!("0000000000000000000000000000000000159D893D4CDD747246CDCA43590E13"), hex!("E5A2636BCFD412EBF36EC45B19BFB68A1BC5F8632E678132B885F7DF99C5E9B3"), hex!("736C1CE161AE27B405CAFD2A7520370153C2C861AC51D6C1D5985D9606B45F39"), ), ( hex!("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAEABB739ABD2280EEFF497A3340D9050"), hex!("A6B594B38FB3E77C6EDF78161FADE2041F4E09FD8497DB776E546C41567FEB3C"), hex!("71444009192228730CD8237A490FEBA2AFE3D27D7CC1136BC97E439D13330D55"), ), ( hex!("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0"), hex!("00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C63"), hex!("3F3979BF72AE8202983DC989AEC7F2FF2ED91BDD69CE02FC0700CA100E59DDF3"), ), ( hex!("BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0C0325AD0376782CCFDDC6E99C28B0F0"), hex!("E24CE4BEEE294AA6350FAA67512B99D388693AE4E7F53D19882A6EA169FC1CE1"), hex!("8B71E83545FC2B5872589F99D948C03108D36797C4DE363EBD3FF6A9E1A95B10"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036412D"), hex!("4CE119C96E2FA357200B559B2F7DD5A5F02D5290AFF74B03F3E471B273211C97"), hex!("ED45D9234EF13E9DA259E05EF57BB3989E9D6B7D8E269698BAFD77106DCC1FF5"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036412E"), hex!("2B4EA0A797A443D293EF5CFF444F4979F06ACFEBD7E86D277475656138385B6C"), hex!("7A17643FC86BA26C4CBCF7C4A5E379ECE5FE09F3AFD9689C4A8F37AA1A3F60B5"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036412F"), hex!("5601570CB47F238D2B0286DB4A990FA0F3BA28D1A319F5E7CF55C2A2444DA7CC"), hex!("3EC93E23F34146CF161D67FBCA76CAE27E271F438C951D5E0AE6D1A074F9DED7"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364130"), hex!("DEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34"), hex!("BDEE54F96B9CAE9716684F152D56C251312E0B5FB56A3F09304E660861A910B8"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364131"), hex!("E60FCE93B59E9EC53011AABC21C23E97B2A31369B87A5AE9C44EE89E2A6DEC0A"), hex!("081CAF8C661A6A6D624660CB0A86C8EFED6976E1BB2DC0F41E0CD330969E940E"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364132"), hex!("D7924D4F7D43EA965A465AE3095FF41131E5946F3C85F79E44ADBCF8E27E080E"), hex!("A7E1D78D57938D597C7BD13DD733921015BF50D427692C5A3AFB235F095D90D7"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364133"), hex!("499FDF9E895E719CFD64E67F07D38E3226AA7B63678949E6E49B241A60E823E4"), hex!("353D093B4AB17AAE6F0FBB1B584C2B9BB9BD863D85C06A4339A0BF2AFC5EBCD4"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364134"), hex!("F28773C2D975288BC7D1D205C3748651B075FBC6610E58CDDEEDDF8F19405AA8"), hex!("F54F6FD17277F5768A7DED149A3250B8C5E5F925ADE056E0D64A34AC24FC0EAE"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364135"), hex!("D01115D548E7561B15C38F004D734633687CF4419620095BC5B0F47070AFE85A"), hex!("560CB00237EA1F285749BAC81E8427EA86DC73A2265792AD94FAE4EB0BF9D908"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364136"), hex!("774AE7F858A9411E5EF4246B70C65AAC5649980BE5C17891BBEC17895DA008CB"), hex!("267B5FCD1494A1E6FDBC22A928484C9AC8D24E1D20062957CFE28B3536AC3614"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364137"), hex!("A0434D9E47F3C86235477C7B1AE6AE5D3442D49B1943C2B752A68E2A47E247C7"), hex!("76C545BDABE643D85C4938196C5DB3969086B3D127885EA6C3411AC3FC8C9358"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364138"), hex!("ACD484E2F0C7F65309AD178A9F559ABDE09796974C57E714C35F110DFC27CCBE"), hex!("33CC76DE4F5826029BC7F68E89C49E165227775BC8A071F0FA33D9D439B05FF8"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364139"), hex!("2F01E5E15CCA351DAFF3843FB70F3C2F0A1BDD05E5AF888A67784EF3E10A2A01"), hex!("A3B25758BEAC66B6D6C2F7D5ECD2EC4B3D1DEC2945A489E84A25D3479342132B"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036413A"), hex!("5CBDF0646E5DB4EAA398F365F2EA7A0E3D419B7E0330E39CE92BDDEDCAC4F9BC"), hex!("951435BF45DAA69F5CE8729279E5AB2457EC2F47EC02184A5AF7D9D6F78D9755"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036413B"), hex!("FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A1460297556"), hex!("51ED8885530449DF0C4169FE80BA3A9F217F0F09AE701B5FC378F3C84F8A0998"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036413C"), hex!("2F8BDE4D1A07209355B4A7250A5C5128E88B84BDDC619AB7CBA8D569B240EFE4"), hex!("2753DDD9C91A1C292B24562259363BD90877D8E454F297BF235782C459539959"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036413D"), hex!("E493DBF1C10D80F3581E4904930B1404CC6C13900EE0758474FA94ABE8C4CD13"), hex!("AE1266C15F2BAA48A9BD1DF6715AEBB7269851CC404201BF30168422B88C630D"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036413E"), hex!("F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9"), hex!("C77084F09CD217EBF01CC819D5C80CA99AFF5666CB3DDCE4934602897B4715BD"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036413F"), hex!("C6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE5"), hex!("E51E970159C23CC65C3A7BE6B99315110809CD9ACD992F1EDC9BCE55AF301705"), ), ( hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140"), hex!("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"), hex!("B7C52588D95C3B9AA25B0403F1EEF75702E84BB7597AABE663B82F6F04EF2777"), ), ]; k256-0.13.3/src/test_vectors.rs000064400000000000000000000001261046102023000142570ustar 00000000000000//! secp256k1 test vectors #[cfg(test)] pub mod ecdsa; pub mod field; pub mod group;