crypto-bigint-0.5.2/.cargo_vcs_info.json0000644000000001360000000000100136320ustar { "git": { "sha1": "074497f66463f23a3feade1556b9bb8f3f544b82" }, "path_in_vcs": "" }crypto-bigint-0.5.2/.github/dependabot.yml000064400000000000000000000003641046102023000166150ustar 00000000000000version: 2 updates: - package-ecosystem: cargo directory: "/" schedule: interval: daily open-pull-requests-limit: 10 - package-ecosystem: github-actions directory: "/" schedule: interval: weekly open-pull-requests-limit: 10 crypto-bigint-0.5.2/.github/workflows/crypto-bigint.yml000064400000000000000000000111421046102023000213330ustar 00000000000000name: crypto-bigint on: pull_request: paths-ignore: - README.md push: branches: master paths-ignore: - README.md env: CARGO_INCREMENTAL: 0 RUSTFLAGS: "-Dwarnings" RUSTDOCFLAGS: "-Dwarnings" jobs: build: runs-on: ubuntu-latest strategy: matrix: rust: - 1.65.0 # MSRV - stable target: - thumbv7em-none-eabi - wasm32-unknown-unknown steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} targets: ${{ matrix.target }} - run: cargo build --target ${{ matrix.target }} --release --no-default-features - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features alloc - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features der - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features generic-array - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features rand_core - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features rlp - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features serde - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features zeroize - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features alloc,der,generic-array,rand_core,rlp,serde,zeroize test: runs-on: ubuntu-latest strategy: matrix: include: # 32-bit Linux - target: i686-unknown-linux-gnu rust: 1.65.0 # MSRV deps: sudo apt update && sudo apt install gcc-multilib - target: i686-unknown-linux-gnu rust: stable deps: sudo apt update && sudo apt install gcc-multilib # 64-bit Linux - target: x86_64-unknown-linux-gnu rust: 1.65.0 # MSRV - target: x86_64-unknown-linux-gnu rust: stable steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} targets: ${{ matrix.target }} - run: ${{ matrix.deps }} - run: cargo test --target ${{ matrix.target }} --release --no-default-features - run: cargo test --target ${{ matrix.target }} --release - run: cargo test --target ${{ matrix.target }} --release --all-features # Cross-compiled tests cross: strategy: matrix: include: # ARM64 - target: aarch64-unknown-linux-gnu rust: stable # PPC32 (big endian) - target: powerpc-unknown-linux-gnu rust: stable runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - run: ${{ matrix.deps }} - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} targets: ${{ matrix.target }} - run: cargo install cross - run: cross test --target ${{ matrix.target }} --release --no-default-features - run: cross test --target ${{ matrix.target }} --release - run: cross test --target ${{ matrix.target }} --release --all-features # dudect benchmarks: check for constant-time operation dudect: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@master with: toolchain: stable - run: cargo run --release | tee /dev/stderr | perl -n -e '/max t = [+-](\d*\.?\d*)/; if ($1 >= 100) { exit 1 }' working-directory: dudect clippy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@master with: toolchain: 1.65.0 components: clippy - run: cargo clippy --all --all-features -- -D warnings rustfmt: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@master with: toolchain: stable components: rustfmt - run: cargo fmt --all -- --check build-benchmarks: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@master with: toolchain: 1.65.0 - run: cargo build --all-features --benches doc: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@master with: toolchain: stable - run: cargo doc --all-features crypto-bigint-0.5.2/.github/workflows/security-audit.yml000064400000000000000000000010171046102023000215140ustar 00000000000000name: Security Audit on: pull_request: paths: Cargo.lock push: branches: master paths: Cargo.lock schedule: - cron: "0 0 * * *" jobs: security_audit: name: Security Audit runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Cache cargo bin uses: actions/cache@v3 with: path: ~/.cargo/bin key: ${{ runner.os }}-cargo-audit-v0.13.0 - uses: actions-rs/audit-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} crypto-bigint-0.5.2/.gitignore000064400000000000000000000000341046102023000144070ustar 00000000000000target proptest-regressions crypto-bigint-0.5.2/CHANGELOG.md000064400000000000000000000264641046102023000142470ustar 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.5.2 (2023-04-26) ### Added - Expose residue params and modulus in `DynResidue` ([#197]) - Impl `DefaultIsZeroes` for `Residue` ([#210]) - `div_by_2()` method for integers in Montgomery form ([#211], [#212]) ### Changed - Montgomery multiplication improvements ([#203]) [#197]: https://github.com/RustCrypto/crypto-bigint/pull/197 [#203]: https://github.com/RustCrypto/crypto-bigint/pull/203 [#210]: https://github.com/RustCrypto/crypto-bigint/pull/210 [#211]: https://github.com/RustCrypto/crypto-bigint/pull/211 [#212]: https://github.com/RustCrypto/crypto-bigint/pull/212 ## 0.5.1 (2023-03-13) ### Changed - Improve `Debug` impls on `Limb` and `Uint` ([#195]) ### Fixed - `const_residue` macro accessibility bug ([#193]) [#193]: https://github.com/RustCrypto/crypto-bigint/pull/193 [#195]: https://github.com/RustCrypto/crypto-bigint/pull/195 ## 0.5.0 (2023-02-27) ### Added - `Residue`: modular arithmetic with static compile-time moduli ([#130]) - `DynResidue`: modular arithmetic with dynamic runtime moduli ([#134]) - Constant-time division by a single `Limb` ([#141]) - Windowed exponentiation for `(Dyn)Residue` ([#147]) - `SubResidue` trait and impls for `Residue` and `DynResidue` ([#149]) - `Pow`, `Invert` and `Square` ([#155]) - `CtChoice` type ([#159]) - `BITS`, `BYTES`, and `LIMBS` to `Integer` trait ([#161]) - Impl `Random` for `Wrapping` ([#168]) - Support to concat `U320` and `U640` ([#173]) - Define `U224` and `U544` on 32-bit platforms ([#179], [#180]) ### Changed - Rename `UInt` -> `Uint` ([#143]) - Rename `Uint` methods ([#144]) - `limbs` -> `as_limbs` - `limbs_mut` -> `as_limbs_mut` - `into_limbs` -> `to_limbs` - Faster `random_mod` ([#146]) - Constant-time `leading_zeros()`, `trailing_zeros()`, `bits()`, and `bit()` for `Uint` ([#153]) - Rename `BIT_SIZE` -> `BITS`, `BYTE_SIZE` -> `BYTES` ([#157]) - More efficient squaring operation ([#133]) - Use `CryptoRngCore` ([#164]) - Bump `serdect` to 0.2 ([#185]) - Bump `der` dependency to v0.7; MSRV 1.65 ([#187]) ### Fixed - Integer overflow in `div2by1()` ([#156]) - Convert from tuple element ordering ([#183]) [#130]: https://github.com/RustCrypto/crypto-bigint/pull/130 [#134]: https://github.com/RustCrypto/crypto-bigint/pull/134 [#141]: https://github.com/RustCrypto/crypto-bigint/pull/141 [#143]: https://github.com/RustCrypto/crypto-bigint/pull/143 [#144]: https://github.com/RustCrypto/crypto-bigint/pull/144 [#146]: https://github.com/RustCrypto/crypto-bigint/pull/146 [#147]: https://github.com/RustCrypto/crypto-bigint/pull/147 [#149]: https://github.com/RustCrypto/crypto-bigint/pull/149 [#153]: https://github.com/RustCrypto/crypto-bigint/pull/153 [#155]: https://github.com/RustCrypto/crypto-bigint/pull/155 [#156]: https://github.com/RustCrypto/crypto-bigint/pull/156 [#157]: https://github.com/RustCrypto/crypto-bigint/pull/157 [#159]: https://github.com/RustCrypto/crypto-bigint/pull/159 [#161]: https://github.com/RustCrypto/crypto-bigint/pull/161 [#164]: https://github.com/RustCrypto/crypto-bigint/pull/164 [#168]: https://github.com/RustCrypto/crypto-bigint/pull/168 [#173]: https://github.com/RustCrypto/crypto-bigint/pull/173 [#179]: https://github.com/RustCrypto/crypto-bigint/pull/179 [#180]: https://github.com/RustCrypto/crypto-bigint/pull/180 [#183]: https://github.com/RustCrypto/crypto-bigint/pull/183 [#185]: https://github.com/RustCrypto/crypto-bigint/pull/185 [#187]: https://github.com/RustCrypto/crypto-bigint/pull/187 ## 0.4.9 (2022-10-11) ### Added - `UInt::from_word` and `::from_wide_word` ([#105]) - `UInt` modulo operations for special moduli ([#108]) - Non-const `UInt` decoding from an array ([#110]) - `const fn` impls of `concat` and `split` ([#111]) - `Limb` left/right bitshifts ([#112]) - `UInt::LIMBS` constant ([#114]) ### Changed - Optimize `UInt::neg_mod` by simply calling `::sub_mod` ([#106]) - Relax bounds for `UInt::add_mod` and `::sub_mod` ([#104]) - Always inline `Limb::bitand` ([#109]) - Faster const decoding of UInt ([#113]) - Optimize `UInt::neg_mod` ([#127]) - Faster comparisons ([#128]) - `UInt::resize` ([#129]) - `UInt::bit` accessor methods ([#122]) ### Fixed - Constant-time behaviour for `ct_reduce`/`ct_div_rem` ([#117]) [#104]: https://github.com/RustCrypto/crypto-bigint/pull/104 [#105]: https://github.com/RustCrypto/crypto-bigint/pull/105 [#106]: https://github.com/RustCrypto/crypto-bigint/pull/106 [#108]: https://github.com/RustCrypto/crypto-bigint/pull/108 [#109]: https://github.com/RustCrypto/crypto-bigint/pull/109 [#110]: https://github.com/RustCrypto/crypto-bigint/pull/110 [#111]: https://github.com/RustCrypto/crypto-bigint/pull/111 [#112]: https://github.com/RustCrypto/crypto-bigint/pull/112 [#113]: https://github.com/RustCrypto/crypto-bigint/pull/113 [#114]: https://github.com/RustCrypto/crypto-bigint/pull/114 [#117]: https://github.com/RustCrypto/crypto-bigint/pull/117 [#122]: https://github.com/RustCrypto/crypto-bigint/pull/122 [#127]: https://github.com/RustCrypto/crypto-bigint/pull/127 [#128]: https://github.com/RustCrypto/crypto-bigint/pull/128 [#129]: https://github.com/RustCrypto/crypto-bigint/pull/129 ## 0.4.8 (2022-06-30) ### Added - `Word` as a replacement for `LimbUInt` ([#88]) - `WideWord` as a replacement for `WideLimbUInt` ([#88]) - `UInt::*_words` as a replacement for `UInt::*_uint_array` ([#88]) ### Changed - Deprecated `*LimbUInt` and `UInt::*_uint_array` ([#88]) [#88]: https://github.com/RustCrypto/crypto-bigint/pull/88 ## 0.4.7 (2022-06-12) ### Added - `Encoding` tests ([#93]) ### Changed - Use const generic impls of `*Mod` traits ([#98]) [#93]: https://github.com/RustCrypto/crypto-bigint/pull/93 [#98]: https://github.com/RustCrypto/crypto-bigint/pull/98 ## 0.4.6 (2022-06-12) ### Added - Impl `ArrayEncoding` for `U576` ([#96]) [#96]: https://github.com/RustCrypto/crypto-bigint/pull/96 ## 0.4.5 (2022-06-12) ### Added - `serde` support ([#73]) - `U576` type alias ([#94]) [#73]: https://github.com/RustCrypto/crypto-bigint/pull/73 [#94]: https://github.com/RustCrypto/crypto-bigint/pull/94 ## 0.4.4 (2022-06-02) ### Added - `UInt::as_uint_array` ([#91]) [#91]: https://github.com/RustCrypto/crypto-bigint/pull/91 ## 0.4.3 (2022-05-31) ### Added - Impl `AsRef`/`AsMut<[LimbUInt]>` for `UInt` ([#89]) [#89]: https://github.com/RustCrypto/crypto-bigint/pull/89 ## 0.4.2 (2022-05-18) ### Added - `UInt::inv_mod2k` ([#86]) ### Fixed - Wrong results for remainder ([#84]) [#84]: https://github.com/RustCrypto/crypto-bigint/pull/84 [#86]: https://github.com/RustCrypto/crypto-bigint/pull/86 ## 0.4.1 (2022-05-10) ### Fixed - Bug in `from_le_slice` ([#82]) [#82]: https://github.com/RustCrypto/crypto-bigint/pull/82 ## 0.4.0 (2022-05-08) [YANKED] NOTE: this release was yanked due to [#82]. ### Added - Const-friendly `NonZero` from `UInt` ([#56]) - Optional `der` feature ([#61], [#80]) ### Changed - Use `const_panic`; MSRV 1.57 ([#60]) - 2021 edition ([#60]) ### Fixed - Pad limbs with zeros when displaying hexadecimal representation ([#74]) [#56]: https://github.com/RustCrypto/crypto-bigint/pull/56 [#60]: https://github.com/RustCrypto/crypto-bigint/pull/60 [#61]: https://github.com/RustCrypto/crypto-bigint/pull/61 [#74]: https://github.com/RustCrypto/crypto-bigint/pull/74 [#80]: https://github.com/RustCrypto/crypto-bigint/pull/80 ## 0.3.2 (2021-11-17) ### Added - `Output = Self` to all bitwise ops on `Integer` trait ([#53]) [#53]: https://github.com/RustCrypto/crypto-bigint/pull/53 ## 0.3.1 (2021-11-17) ### Added - Bitwise ops to `Integer` trait ([#51]) [#51]: https://github.com/RustCrypto/crypto-bigint/pull/51 ## 0.3.0 (2021-11-14) [YANKED] ### Added - Bitwise `Xor`/`Not` operations ([#27]) - `Zero` trait ([#35]) - `Checked*` traits ([#41]) - `prelude` module ([#45]) - `saturating_*` ops ([#47]) ### Changed - Rust 2021 edition upgrade; MSRV 1.56 ([#33]) - Reverse ordering of `UInt::mul_wide` return tuple ([#34]) - Have `Div` and `Rem` impls always take `NonZero` args ([#39]) - Rename `limb::Inner` to `LimbUInt` ([#40]) - Make `limb` module private ([#40]) - Use `Zero`/`Integer` traits for `is_zero`, `is_odd`, and `is_even` ([#46]) ### Fixed - `random_mod` performance for small moduli ([#36]) - `NonZero` moduli ([#36]) ### Removed - Deprecated `LIMB_BYTES` constant ([#43]) [#27]: https://github.com/RustCrypto/crypto-bigint/pull/27 [#33]: https://github.com/RustCrypto/crypto-bigint/pull/33 [#34]: https://github.com/RustCrypto/crypto-bigint/pull/34 [#35]: https://github.com/RustCrypto/crypto-bigint/pull/35 [#36]: https://github.com/RustCrypto/crypto-bigint/pull/36 [#39]: https://github.com/RustCrypto/crypto-bigint/pull/39 [#40]: https://github.com/RustCrypto/crypto-bigint/pull/40 [#41]: https://github.com/RustCrypto/crypto-bigint/pull/41 [#43]: https://github.com/RustCrypto/crypto-bigint/pull/43 [#45]: https://github.com/RustCrypto/crypto-bigint/pull/45 [#46]: https://github.com/RustCrypto/crypto-bigint/pull/46 [#47]: https://github.com/RustCrypto/crypto-bigint/pull/47 ## 0.2.11 (2021-10-16) ### Added - `AddMod` proptests ([#24]) - Bitwise `And`/`Or` operations ([#25]) [#24]: https://github.com/RustCrypto/crypto-bigint/pull/24 [#25]: https://github.com/RustCrypto/crypto-bigint/pull/25 ## 0.2.10 (2021-09-21) ### Added - `ArrayDecoding` trait ([#12]) - `NonZero` wrapper ([#13], [#16]) - Impl `Div`/`Rem` for `NonZero` ([#14]) [#12]: https://github.com/RustCrypto/crypto-bigint/pull/12 [#13]: https://github.com/RustCrypto/crypto-bigint/pull/13 [#14]: https://github.com/RustCrypto/crypto-bigint/pull/14 [#16]: https://github.com/RustCrypto/crypto-bigint/pull/16 ## 0.2.9 (2021-09-16) ### Added - `UInt::sqrt` ([#9]) ### Changed - Make `UInt` division similar to other interfaces ([#8]) [#8]: https://github.com/RustCrypto/crypto-bigint/pull/8 [#9]: https://github.com/RustCrypto/crypto-bigint/pull/9 ## 0.2.8 (2021-09-14) [YANKED] ### Added - Implement constant-time division and modulo operations ### Changed - Moved from RustCrypto/utils to RustCrypto/crypto-bigint repo ([#2]) [#2]: https://github.com/RustCrypto/crypto-bigint/pull/2 ## 0.2.7 (2021-09-12) ### Added - `UInt::shl_vartime` ### Fixed - `add_mod` overflow handling ## 0.2.6 (2021-09-08) ### Added - `Integer` trait - `ShrAssign` impl for `UInt` - Recursive Length Prefix (RLP) encoding support for `UInt` ## 0.2.5 (2021-09-02) ### Fixed - `ConditionallySelectable` impl for `UInt` ## 0.2.4 (2021-08-23) [YANKED] ### Added - Expose `limb` module - `[limb::Inner; LIMBS]` conversions for `UInt` - Bitwise right shift support for `UInt` ([#586], [#590]) ## 0.2.3 (2021-08-16) [YANKED] ### Fixed - `UInt::wrapping_mul` ### Added - Implement the `Hash` trait for `UInt` and `Limb` ## 0.2.2 (2021-06-26) [YANKED] ### Added - `Limb::is_odd` and `UInt::is_odd` - `UInt::new` - `rand` feature ### Changed - Deprecate `LIMB_BYTES` constant - Make `Limb`'s `Inner` value public ## 0.2.1 (2021-06-21) [YANKED] ### Added - `Limb` newtype - Target-specific rustdocs ## 0.2.0 (2021-06-07) [YANKED] ### Added - `ConstantTimeGreater`/`ConstantTimeLess` impls for UInt - `From` conversions between `UInt` and limb arrays - `zeroize` feature - Additional `ArrayEncoding::ByteSize` bounds - `UInt::into_limbs` - `Encoding` trait ### Removed - `NumBits`/`NumBytes` traits; use `Encoding` instead ## 0.1.0 (2021-05-30) - Initial release crypto-bigint-0.5.2/Cargo.toml0000644000000044720000000000100116370ustar # 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 = "crypto-bigint" version = "0.5.2" authors = ["RustCrypto Developers"] description = """ Pure Rust implementation of a big integer library which has been designed from the ground-up for use in cryptographic applications. Provides constant-time, no_std-friendly implementations of modern formulas using const generics. """ readme = "README.md" keywords = [ "arbitrary", "crypto", "bignum", "integer", "precision", ] categories = [ "algorithms", "cryptography", "data-structures", "mathematics", "no-std", ] license = "Apache-2.0 OR MIT" repository = "https://github.com/RustCrypto/crypto-bigint" resolver = "2" [package.metadata.docs.rs] all-features = true rustdoc-args = [ "--cfg", "docsrs", ] [[bench]] name = "bench" harness = false [dependencies.der] version = "0.7" optional = true default-features = false [dependencies.generic-array] version = "0.14" optional = true [dependencies.rand_core] version = "0.6.4" optional = true [dependencies.rlp] version = "0.5" optional = true default-features = false [dependencies.serdect] version = "0.2" optional = true default-features = false [dependencies.subtle] version = "2.4" default-features = false [dependencies.zeroize] version = "1" optional = true default-features = false [dev-dependencies.bincode] version = "1" [dev-dependencies.criterion] version = "0.4" features = ["html_reports"] [dev-dependencies.hex-literal] version = "0.4" [dev-dependencies.num-bigint] version = "0.4" [dev-dependencies.num-integer] version = "0.1" [dev-dependencies.num-traits] version = "0.2" [dev-dependencies.proptest] version = "1" [dev-dependencies.rand_chacha] version = "0.3" [dev-dependencies.rand_core] version = "0.6" features = ["std"] [features] alloc = [] default = ["rand"] rand = ["rand_core/std"] serde = ["dep:serdect"] crypto-bigint-0.5.2/Cargo.toml.orig000064400000000000000000000031231046102023000153100ustar 00000000000000[package] name = "crypto-bigint" version = "0.5.2" description = """ Pure Rust implementation of a big integer library which has been designed from the ground-up for use in cryptographic applications. Provides constant-time, no_std-friendly implementations of modern formulas using const generics. """ authors = ["RustCrypto Developers"] license = "Apache-2.0 OR MIT" repository = "https://github.com/RustCrypto/crypto-bigint" categories = ["algorithms", "cryptography", "data-structures", "mathematics", "no-std"] keywords = ["arbitrary", "crypto", "bignum", "integer", "precision"] readme = "README.md" resolver = "2" edition = "2021" rust-version = "1.65" [dependencies] subtle = { version = "2.4", default-features = false } # optional dependencies der = { version = "0.7", optional = true, default-features = false } generic-array = { version = "0.14", optional = true } rand_core = { version = "0.6.4", optional = true } rlp = { version = "0.5", optional = true, default-features = false } serdect = { version = "0.2", optional = true, default-features = false } zeroize = { version = "1", optional = true, default-features = false } [dev-dependencies] bincode = "1" criterion = { version = "0.4", features = ["html_reports"] } hex-literal = "0.4" num-bigint = "0.4" num-integer = "0.1" num-traits = "0.2" proptest = "1" rand_core = { version = "0.6", features = ["std"] } rand_chacha = "0.3" [features] default = ["rand"] alloc = [] rand = ["rand_core/std"] serde = ["dep:serdect"] [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] [[bench]] name = "bench" harness = false crypto-bigint-0.5.2/LICENSE-APACHE000064400000000000000000000251411046102023000143510ustar 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. crypto-bigint-0.5.2/LICENSE-MIT000064400000000000000000000020651046102023000140610ustar 00000000000000Copyright (c) 2021 The RustCrypto Project 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. crypto-bigint-0.5.2/README.md000064400000000000000000000044261046102023000137070ustar 00000000000000# [RustCrypto]: Cryptographic Big Integers [![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] Pure Rust implementation of a big integer library which has been designed from the ground-up for use in cryptographic applications. Provides constant-time, `no_std`-friendly implementations of modern formulas using const generics. [Documentation][docs-link] ## Goals - No heap allocations. `no_std`-friendly. - Constant-time by default. Variable-time functions are explicitly marked as such. - Leverage what is possible today with const generics on `stable` rust. - Support `const fn` as much as possible, including decoding big integers from bytes/hex and performing arithmetic operations on them, with the goal of being able to compute values at compile-time. ## Minimum Supported Rust Version This crate requires **Rust 1.65** at a minimum. We may change the MSRV in the future, but it will be accompanied by a minor version bump. ## License 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/crypto-bigint [crate-link]: https://crates.io/crates/crypto-bigint [docs-image]: https://docs.rs/crypto-bigint/badge.svg [docs-link]: https://docs.rs/crypto-bigint/ [build-image]: https://github.com/RustCrypto/crypto-bigint/actions/workflows/crypto-bigint.yml/badge.svg [build-link]: https://github.com/RustCrypto/crypto-bigint/actions/workflows/crypto-bigint.yml [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg [rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/300602-crypto-bigint [//]: # (links) [RustCrypto]: https://github.com/rustcrypto crypto-bigint-0.5.2/SECURITY.md000064400000000000000000000012761046102023000142210ustar 00000000000000# Security Policy ## Supported Versions Security updates are applied only to the most recent release. ## Reporting a Vulnerability If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released. Please disclose it at [security advisory](https://github.com/RustCrypto/crypto-bigint/security/advisories/new). This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure. crypto-bigint-0.5.2/benches/bench.rs000064400000000000000000000113051046102023000154560ustar 00000000000000use criterion::{ criterion_group, criterion_main, measurement::Measurement, BatchSize, BenchmarkGroup, Criterion, }; use crypto_bigint::{ modular::runtime_mod::{DynResidue, DynResidueParams}, Limb, NonZero, Random, Reciprocal, U128, U256, }; use rand_core::OsRng; fn bench_division(group: &mut BenchmarkGroup<'_, M>) { group.bench_function("div/rem, U256/U128, full size", |b| { b.iter_batched( || { let x = U256::random(&mut OsRng); let y_half = U128::random(&mut OsRng); let y: U256 = (y_half, U128::ZERO).into(); (x, NonZero::new(y).unwrap()) }, |(x, y)| x.div_rem(&y), BatchSize::SmallInput, ) }); group.bench_function("rem, U256/U128, full size", |b| { b.iter_batched( || { let x = U256::random(&mut OsRng); let y_half = U128::random(&mut OsRng); let y: U256 = (y_half, U128::ZERO).into(); (x, NonZero::new(y).unwrap()) }, |(x, y)| x.rem(&y), BatchSize::SmallInput, ) }); group.bench_function("div/rem, U256/Limb, full size", |b| { b.iter_batched( || { let x = U256::random(&mut OsRng); let y_small = Limb::random(&mut OsRng); let y = U256::from_word(y_small.0); (x, NonZero::new(y).unwrap()) }, |(x, y)| x.div_rem(&y), BatchSize::SmallInput, ) }); group.bench_function("div/rem, U256/Limb, single limb", |b| { b.iter_batched( || { let x = U256::random(&mut OsRng); let y = Limb::random(&mut OsRng); (x, NonZero::new(y).unwrap()) }, |(x, y)| x.div_rem_limb(y), BatchSize::SmallInput, ) }); group.bench_function("div/rem, U256/Limb, single limb with reciprocal", |b| { b.iter_batched( || { let x = U256::random(&mut OsRng); let y = Limb::random(&mut OsRng); let r = Reciprocal::new(y); (x, r) }, |(x, r)| x.div_rem_limb_with_reciprocal(&r), BatchSize::SmallInput, ) }); } fn bench_montgomery_ops(group: &mut BenchmarkGroup<'_, M>) { let params = DynResidueParams::new(&(U256::random(&mut OsRng) | U256::ONE)); group.bench_function("multiplication, U256*U256", |b| { b.iter_batched( || { let x = DynResidue::new(&U256::random(&mut OsRng), params); let y = DynResidue::new(&U256::random(&mut OsRng), params); (x, y) }, |(x, y)| x * y, BatchSize::SmallInput, ) }); let m = U256::random(&mut OsRng) | U256::ONE; let params = DynResidueParams::new(&m); group.bench_function("modpow, U256^U256", |b| { b.iter_batched( || { let x = U256::random(&mut OsRng); let x_m = DynResidue::new(&x, params); let p = U256::random(&mut OsRng) | (U256::ONE << (U256::BITS - 1)); (x_m, p) }, |(x, p)| x.pow(&p), BatchSize::SmallInput, ) }); } fn bench_montgomery_conversion(group: &mut BenchmarkGroup<'_, M>) { group.bench_function("DynResidueParams creation", |b| { b.iter_batched( || U256::random(&mut OsRng) | U256::ONE, |modulus| DynResidueParams::new(&modulus), BatchSize::SmallInput, ) }); let params = DynResidueParams::new(&(U256::random(&mut OsRng) | U256::ONE)); group.bench_function("DynResidue creation", |b| { b.iter_batched( || U256::random(&mut OsRng), |x| DynResidue::new(&x, params), BatchSize::SmallInput, ) }); let params = DynResidueParams::new(&(U256::random(&mut OsRng) | U256::ONE)); group.bench_function("DynResidue retrieve", |b| { b.iter_batched( || DynResidue::new(&U256::random(&mut OsRng), params), |x| x.retrieve(), BatchSize::SmallInput, ) }); } fn bench_wrapping_ops(c: &mut Criterion) { let mut group = c.benchmark_group("wrapping ops"); bench_division(&mut group); group.finish(); } fn bench_montgomery(c: &mut Criterion) { let mut group = c.benchmark_group("Montgomery arithmetic"); bench_montgomery_conversion(&mut group); bench_montgomery_ops(&mut group); group.finish(); } criterion_group!(benches, bench_wrapping_ops, bench_montgomery); criterion_main!(benches); crypto-bigint-0.5.2/src/array.rs000064400000000000000000000024751046102023000147050ustar 00000000000000//! Interop support for `generic-array` use crate::{Encoding, Integer}; use core::ops::Add; use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; /// Alias for a byte array whose size is defined by [`ArrayEncoding::ByteSize`]. pub type ByteArray = GenericArray::ByteSize>; /// Support for encoding a big integer as a `GenericArray`. pub trait ArrayEncoding: Encoding { /// Size of a byte array which encodes a big integer. type ByteSize: ArrayLength + Add + Eq + Ord + Unsigned; /// Deserialize from a big-endian byte array. fn from_be_byte_array(bytes: ByteArray) -> Self; /// Deserialize from a little-endian byte array. fn from_le_byte_array(bytes: ByteArray) -> Self; /// Serialize to a big-endian byte array. fn to_be_byte_array(&self) -> ByteArray; /// Serialize to a little-endian byte array. fn to_le_byte_array(&self) -> ByteArray; } /// Support for decoding a `GenericArray` as a big integer. pub trait ArrayDecoding { /// Big integer which decodes a `GenericArray`. type Output: ArrayEncoding + Integer; /// Deserialize from a big-endian `GenericArray`. fn into_uint_be(self) -> Self::Output; /// Deserialize from a little-endian `GenericArray`. fn into_uint_le(self) -> Self::Output; } crypto-bigint-0.5.2/src/checked.rs000064400000000000000000000072401046102023000151500ustar 00000000000000//! Checked arithmetic. use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; #[cfg(feature = "serde")] use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer}; /// Provides intentionally-checked arithmetic on `T`. /// /// Internally this leverages the [`CtOption`] type from the [`subtle`] crate /// in order to handle overflows in constant time. #[derive(Copy, Clone, Debug)] pub struct Checked(pub CtOption); impl Checked { /// Create a new checked arithmetic wrapper for the given value. pub fn new(val: T) -> Self { Self(CtOption::new(val, Choice::from(1))) } } impl Default for Checked where T: Default, { fn default() -> Self { Self::new(T::default()) } } impl ConditionallySelectable for Checked { #[inline] fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Self(CtOption::conditional_select(&a.0, &b.0, choice)) } } impl ConstantTimeEq for Checked { #[inline] fn ct_eq(&self, rhs: &Self) -> Choice { self.0.ct_eq(&rhs.0) } } impl From> for CtOption { fn from(checked: Checked) -> CtOption { checked.0 } } impl From> for Checked { fn from(ct_option: CtOption) -> Checked { Checked(ct_option) } } impl From> for Option { fn from(checked: Checked) -> Option { checked.0.into() } } #[cfg(feature = "serde")] impl<'de, T: Default + Deserialize<'de>> Deserialize<'de> for Checked { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let value = Option::::deserialize(deserializer)?; let choice = Choice::from(value.is_some() as u8); Ok(Self(CtOption::new(value.unwrap_or_default(), choice))) } } #[cfg(feature = "serde")] impl Serialize for Checked { fn serialize(&self, serializer: S) -> Result where S: Serializer, { Option::::from(self.0).serialize(serializer) } } #[cfg(all(test, feature = "serde"))] mod tests { use crate::{Checked, U64}; use subtle::{Choice, ConstantTimeEq, CtOption}; #[test] fn serde() { let test = Checked::new(U64::from_u64(0x0011223344556677)); let serialized = bincode::serialize(&test).unwrap(); let deserialized: Checked = bincode::deserialize(&serialized).unwrap(); assert!(bool::from(test.ct_eq(&deserialized))); let test = Checked::new(U64::ZERO) - Checked::new(U64::ONE); assert!(bool::from( test.ct_eq(&Checked(CtOption::new(U64::ZERO, Choice::from(0)))) )); let serialized = bincode::serialize(&test).unwrap(); let deserialized: Checked = bincode::deserialize(&serialized).unwrap(); assert!(bool::from(test.ct_eq(&deserialized))); } #[test] fn serde_owned() { let test = Checked::new(U64::from_u64(0x0011223344556677)); let serialized = bincode::serialize(&test).unwrap(); let deserialized: Checked = bincode::deserialize_from(serialized.as_slice()).unwrap(); assert!(bool::from(test.ct_eq(&deserialized))); let test = Checked::new(U64::ZERO) - Checked::new(U64::ONE); assert!(bool::from( test.ct_eq(&Checked(CtOption::new(U64::ZERO, Choice::from(0)))) )); let serialized = bincode::serialize(&test).unwrap(); let deserialized: Checked = bincode::deserialize_from(serialized.as_slice()).unwrap(); assert!(bool::from(test.ct_eq(&deserialized))); } } crypto-bigint-0.5.2/src/ct_choice.rs000064400000000000000000000037771046102023000155150ustar 00000000000000use subtle::Choice; use crate::Word; /// A boolean value returned by constant-time `const fn`s. // TODO: should be replaced by `subtle::Choice` or `CtOption` // when `subtle` starts supporting const fns. #[derive(Debug, Copy, Clone)] pub struct CtChoice(Word); impl CtChoice { /// The falsy value. pub const FALSE: Self = Self(0); /// The truthy value. pub const TRUE: Self = Self(Word::MAX); /// Returns the truthy value if `value == Word::MAX`, and the falsy value if `value == 0`. /// Panics for other values. pub(crate) const fn from_mask(value: Word) -> Self { debug_assert!(value == Self::FALSE.0 || value == Self::TRUE.0); Self(value) } /// Returns the truthy value if `value == 1`, and the falsy value if `value == 0`. /// Panics for other values. pub(crate) const fn from_lsb(value: Word) -> Self { debug_assert!(value == 0 || value == 1); Self(value.wrapping_neg()) } pub(crate) const fn not(&self) -> Self { Self(!self.0) } pub(crate) const fn and(&self, other: Self) -> Self { Self(self.0 & other.0) } /// Return `b` if `self` is truthy, otherwise return `a`. pub(crate) const fn select(&self, a: Word, b: Word) -> Word { a ^ (self.0 & (a ^ b)) } /// Return `x` if `self` is truthy, otherwise return 0. pub(crate) const fn if_true(&self, x: Word) -> Word { x & self.0 } pub(crate) const fn is_true_vartime(&self) -> bool { self.0 == CtChoice::TRUE.0 } } impl From for Choice { fn from(choice: CtChoice) -> Self { Choice::from(choice.0 as u8 & 1) } } impl From for bool { fn from(choice: CtChoice) -> Self { choice.is_true_vartime() } } #[cfg(test)] mod tests { use super::CtChoice; use crate::Word; #[test] fn select() { let a: Word = 1; let b: Word = 2; assert_eq!(CtChoice::TRUE.select(a, b), b); assert_eq!(CtChoice::FALSE.select(a, b), a); } } crypto-bigint-0.5.2/src/lib.rs000064400000000000000000000135231046102023000143310ustar 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" )] #![deny(unsafe_code)] #![warn( clippy::mod_module_files, clippy::unwrap_used, missing_docs, missing_debug_implementations, missing_copy_implementations, rust_2018_idioms, trivial_casts, trivial_numeric_casts, unused_qualifications )] //! ## Usage //! //! This crate defines a [`Uint`] type which is const generic around an inner //! [`Limb`] array, where a [`Limb`] is a newtype for a word-sized integer. //! Thus large integers are represented as arrays of smaller integers which //! are sized appropriately for the CPU, giving us some assurances of how //! arithmetic operations over those smaller integers will behave. //! //! To obtain appropriately sized integers regardless of what a given CPU's //! word size happens to be, a number of portable type aliases are provided for //! integer sizes commonly used in cryptography, for example: //! [`U128`], [`U384`], [`U256`], [`U2048`], [`U3072`], [`U4096`]. //! //! ### `const fn` usage //! //! The [`Uint`] type provides a number of `const fn` inherent methods which //! can be used for initializing and performing arithmetic on big integers in //! const contexts: //! //! ``` //! use crypto_bigint::U256; //! //! // Parse a constant from a big endian hexadecimal string. //! pub const MODULUS: U256 = //! U256::from_be_hex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"); //! //! // Compute `MODULUS` shifted right by 1 at compile time //! pub const MODULUS_SHR1: U256 = MODULUS.shr_vartime(1); //! ``` //! //! Note that large constant computations may accidentally trigger a the `const_eval_limit` of the compiler. //! The current way to deal with this problem is to either simplify this computation, //! or increase the compiler's limit (currently a nightly feature). //! One can completely remove the compiler's limit using: //! ```ignore //! #![feature(const_eval_limit)] //! #![const_eval_limit = "0"] //! ``` //! //! ### Trait-based usage //! //! The [`Uint`] type itself does not implement the standard arithmetic traits //! such as [`Add`], [`Sub`], [`Mul`], and [`Div`]. //! //! To use these traits you must first pick a wrapper type which determines //! overflow behavior: [`Wrapping`] or [`Checked`]. //! //! #### Wrapping arithmetic //! //! ``` //! use crypto_bigint::{U256, Wrapping}; //! //! let a = Wrapping(U256::MAX); //! let b = Wrapping(U256::ONE); //! let c = a + b; //! //! // `MAX` + 1 wraps back around to zero //! assert_eq!(c.0, U256::ZERO); //! ``` //! //! #### Checked arithmetic //! //! ``` //! use crypto_bigint::{U256, Checked}; //! //! let a = Checked::new(U256::ONE); //! let b = Checked::new(U256::from(2u8)); //! let c = a + b; //! assert_eq!(c.0.unwrap(), U256::from(3u8)) //! ``` //! //! ### Modular arithmetic //! //! This library has initial support for modular arithmetic in the form of the //! [`AddMod`], [`SubMod`], [`NegMod`], and [`MulMod`] traits, as well as the //! support for the [`Rem`] trait when used with a [`NonZero`] operand. //! //! ``` //! use crypto_bigint::{AddMod, U256}; //! //! // mod 3 //! let modulus = U256::from(3u8); //! //! // 1 + 1 mod 3 = 2 //! let a = U256::ONE.add_mod(&U256::ONE, &modulus); //! assert_eq!(a, U256::from(2u8)); //! //! // 2 + 1 mod 3 = 0 //! let b = a.add_mod(&U256::ONE, &modulus); //! assert_eq!(b, U256::ZERO); //! ``` //! //! It also supports modular arithmetic over constant moduli using `Residue`, //! and over moduli set at runtime using `DynResidue`. //! That includes modular exponentiation and multiplicative inverses. //! These features are described in the [`modular`] module. //! //! ### Random number generation //! //! When the `rand_core` or `rand` features of this crate are enabled, it's //! possible to generate random numbers using any CSRNG by using the //! [`Random`] trait: //! //! ``` //! # #[cfg(feature = "rand")] //! # { //! use crypto_bigint::{Random, U256, rand_core::OsRng}; //! //! let n = U256::random(&mut OsRng); //! # } //! ``` //! //! #### Modular random number generation //! //! The [`RandomMod`] trait supports generating random numbers with a uniform //! distribution around a given [`NonZero`] modulus. //! //! ``` //! # #[cfg(feature = "rand")] //! # { //! use crypto_bigint::{NonZero, RandomMod, U256, rand_core::OsRng}; //! //! let modulus = NonZero::new(U256::from(3u8)).unwrap(); //! let n = U256::random_mod(&mut OsRng, &modulus); //! # } //! ``` //! //! [`Add`]: core::ops::Add //! [`Div`]: core::ops::Div //! [`Mul`]: core::ops::Mul //! [`Rem`]: core::ops::Rem //! [`Sub`]: core::ops::Sub #[cfg(all(feature = "alloc", test))] extern crate alloc; #[macro_use] mod nlimbs; #[cfg(feature = "generic-array")] mod array; mod checked; mod ct_choice; mod limb; mod non_zero; mod traits; mod uint; mod wrapping; pub use crate::{ checked::Checked, ct_choice::CtChoice, limb::{Limb, WideWord, Word}, non_zero::NonZero, traits::*, uint::div_limb::Reciprocal, uint::*, wrapping::Wrapping, }; pub use subtle; #[cfg(feature = "generic-array")] pub use { crate::array::{ArrayDecoding, ArrayEncoding, ByteArray}, generic_array::{self, typenum::consts}, }; #[cfg(feature = "rand_core")] pub use rand_core; #[cfg(feature = "rlp")] pub use rlp; #[cfg(feature = "zeroize")] pub use zeroize; /// Import prelude for this crate: includes important traits. pub mod prelude { pub use crate::traits::*; #[cfg(feature = "generic-array")] pub use crate::array::{ArrayDecoding, ArrayEncoding}; } #[cfg(sidefuzz)] #[no_mangle] pub extern "C" fn fuzz() { let input = sidefuzz::fetch_input(32); // 32 bytes of of fuzzing input as a &[u8] sidefuzz::black_box(my_hopefully_constant_fn(input)); } crypto-bigint-0.5.2/src/limb/add.rs000064400000000000000000000104601046102023000152330ustar 00000000000000//! Limb addition use crate::{Checked, CheckedAdd, Limb, WideWord, Word, Wrapping, Zero}; use core::ops::{Add, AddAssign}; use subtle::CtOption; impl Limb { /// Computes `self + rhs + carry`, returning the result along with the new carry. #[inline(always)] pub const fn adc(self, rhs: Limb, carry: Limb) -> (Limb, Limb) { let a = self.0 as WideWord; let b = rhs.0 as WideWord; let carry = carry.0 as WideWord; let ret = a + b + carry; (Limb(ret as Word), Limb((ret >> Self::BITS) as Word)) } /// Perform saturating addition. #[inline] pub const fn saturating_add(&self, rhs: Self) -> Self { Limb(self.0.saturating_add(rhs.0)) } /// Perform wrapping addition, discarding overflow. #[inline(always)] pub const fn wrapping_add(&self, rhs: Self) -> Self { Limb(self.0.wrapping_add(rhs.0)) } } impl CheckedAdd for Limb { type Output = Self; #[inline] fn checked_add(&self, rhs: Self) -> CtOption { let (result, carry) = self.adc(rhs, Limb::ZERO); CtOption::new(result, carry.is_zero()) } } impl Add for Wrapping { type Output = Self; fn add(self, rhs: Self) -> Wrapping { Wrapping(self.0.wrapping_add(rhs.0)) } } impl Add<&Wrapping> for Wrapping { type Output = Wrapping; fn add(self, rhs: &Wrapping) -> Wrapping { Wrapping(self.0.wrapping_add(rhs.0)) } } impl Add> for &Wrapping { type Output = Wrapping; fn add(self, rhs: Wrapping) -> Wrapping { Wrapping(self.0.wrapping_add(rhs.0)) } } impl Add<&Wrapping> for &Wrapping { type Output = Wrapping; fn add(self, rhs: &Wrapping) -> Wrapping { Wrapping(self.0.wrapping_add(rhs.0)) } } impl AddAssign for Wrapping { fn add_assign(&mut self, other: Self) { *self = *self + other; } } impl AddAssign<&Wrapping> for Wrapping { fn add_assign(&mut self, other: &Self) { *self = *self + other; } } impl Add for Checked { type Output = Self; fn add(self, rhs: Self) -> Checked { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(rhs))), ) } } impl Add<&Checked> for Checked { type Output = Checked; fn add(self, rhs: &Checked) -> Checked { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(rhs))), ) } } impl Add> for &Checked { type Output = Checked; fn add(self, rhs: Checked) -> Checked { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(rhs))), ) } } impl Add<&Checked> for &Checked { type Output = Checked; fn add(self, rhs: &Checked) -> Checked { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(rhs))), ) } } impl AddAssign for Checked { fn add_assign(&mut self, other: Self) { *self = *self + other; } } impl AddAssign<&Checked> for Checked { fn add_assign(&mut self, other: &Self) { *self = *self + other; } } #[cfg(test)] mod tests { use crate::{CheckedAdd, Limb}; #[test] fn adc_no_carry() { let (res, carry) = Limb::ZERO.adc(Limb::ONE, Limb::ZERO); assert_eq!(res, Limb::ONE); assert_eq!(carry, Limb::ZERO); } #[test] fn adc_with_carry() { let (res, carry) = Limb::MAX.adc(Limb::ONE, Limb::ZERO); assert_eq!(res, Limb::ZERO); assert_eq!(carry, Limb::ONE); } #[test] fn wrapping_add_no_carry() { assert_eq!(Limb::ZERO.wrapping_add(Limb::ONE), Limb::ONE); } #[test] fn wrapping_add_with_carry() { assert_eq!(Limb::MAX.wrapping_add(Limb::ONE), Limb::ZERO); } #[test] fn checked_add_ok() { let result = Limb::ZERO.checked_add(Limb::ONE); assert_eq!(result.unwrap(), Limb::ONE); } #[test] fn checked_add_overflow() { let result = Limb::MAX.checked_add(Limb::ONE); assert!(!bool::from(result.is_some())); } } crypto-bigint-0.5.2/src/limb/bit_and.rs000064400000000000000000000005661046102023000161110ustar 00000000000000//! Limb bit and operations. use super::Limb; use core::ops::BitAnd; impl Limb { /// Calculates `a & b`. #[inline(always)] pub const fn bitand(self, rhs: Self) -> Self { Limb(self.0 & rhs.0) } } impl BitAnd for Limb { type Output = Limb; #[inline(always)] fn bitand(self, rhs: Self) -> Self::Output { self.bitand(rhs) } } crypto-bigint-0.5.2/src/limb/bit_not.rs000064400000000000000000000004411046102023000161370ustar 00000000000000//! Limb bit not operations. use super::Limb; use core::ops::Not; impl Limb { /// Calculates `!a`. pub const fn not(self) -> Self { Limb(!self.0) } } impl Not for Limb { type Output = Limb; fn not(self) -> ::Output { self.not() } } crypto-bigint-0.5.2/src/limb/bit_or.rs000064400000000000000000000005041046102023000157570ustar 00000000000000//! Limb bit or operations. use super::Limb; use core::ops::BitOr; impl Limb { /// Calculates `a | b`. pub const fn bitor(self, rhs: Self) -> Self { Limb(self.0 | rhs.0) } } impl BitOr for Limb { type Output = Limb; fn bitor(self, rhs: Self) -> Self::Output { self.bitor(rhs) } } crypto-bigint-0.5.2/src/limb/bit_xor.rs000064400000000000000000000005121046102023000161460ustar 00000000000000//! Limb bit xor operations. use super::Limb; use core::ops::BitXor; impl Limb { /// Calculates `a ^ b`. pub const fn bitxor(self, rhs: Self) -> Self { Limb(self.0 ^ rhs.0) } } impl BitXor for Limb { type Output = Limb; fn bitxor(self, rhs: Self) -> Self::Output { self.bitxor(rhs) } } crypto-bigint-0.5.2/src/limb/bits.rs000064400000000000000000000011011046102023000154340ustar 00000000000000use super::Limb; impl Limb { /// Calculate the number of bits needed to represent this number. pub const fn bits(self) -> usize { Limb::BITS - (self.0.leading_zeros() as usize) } /// Calculate the number of leading zeros in the binary representation of this number. pub const fn leading_zeros(self) -> usize { self.0.leading_zeros() as usize } /// Calculate the number of trailing zeros in the binary representation of this number. pub const fn trailing_zeros(self) -> usize { self.0.trailing_zeros() as usize } } crypto-bigint-0.5.2/src/limb/cmp.rs000064400000000000000000000123451046102023000152660ustar 00000000000000//! Limb comparisons use super::HI_BIT; use crate::{CtChoice, Limb}; use core::cmp::Ordering; use subtle::{Choice, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess}; impl Limb { /// Is this limb an odd number? #[inline] pub fn is_odd(&self) -> Choice { Choice::from(self.0 as u8 & 1) } /// Perform a comparison of the inner value in variable-time. /// /// Note that the [`PartialOrd`] and [`Ord`] impls wrap constant-time /// comparisons using the `subtle` crate. pub fn cmp_vartime(&self, other: &Self) -> Ordering { self.0.cmp(&other.0) } /// Performs an equality check in variable-time. pub const fn eq_vartime(&self, other: &Self) -> bool { self.0 == other.0 } /// Return `b` if `c` is truthy, otherwise return `a`. #[inline] pub(crate) const fn ct_select(a: Self, b: Self, c: CtChoice) -> Self { Self(c.select(a.0, b.0)) } /// Returns the truthy value if `self != 0` and the falsy value otherwise. #[inline] pub(crate) const fn ct_is_nonzero(&self) -> CtChoice { let inner = self.0; CtChoice::from_lsb((inner | inner.wrapping_neg()) >> HI_BIT) } /// Returns the truthy value if `lhs == rhs` and the falsy value otherwise. #[inline] pub(crate) const fn ct_eq(lhs: Self, rhs: Self) -> CtChoice { let x = lhs.0; let y = rhs.0; // x ^ y == 0 if and only if x == y Self(x ^ y).ct_is_nonzero().not() } /// Returns the truthy value if `lhs < rhs` and the falsy value otherwise. #[inline] pub(crate) const fn ct_lt(lhs: Self, rhs: Self) -> CtChoice { let x = lhs.0; let y = rhs.0; let bit = (((!x) & y) | (((!x) | y) & (x.wrapping_sub(y)))) >> (Limb::BITS - 1); CtChoice::from_lsb(bit) } /// Returns the truthy value if `lhs <= rhs` and the falsy value otherwise. #[inline] pub(crate) const fn ct_le(lhs: Self, rhs: Self) -> CtChoice { let x = lhs.0; let y = rhs.0; let bit = (((!x) | y) & ((x ^ y) | !(y.wrapping_sub(x)))) >> (Limb::BITS - 1); CtChoice::from_lsb(bit) } } impl ConstantTimeEq for Limb { #[inline] fn ct_eq(&self, other: &Self) -> Choice { self.0.ct_eq(&other.0) } } impl ConstantTimeGreater for Limb { #[inline] fn ct_gt(&self, other: &Self) -> Choice { self.0.ct_gt(&other.0) } } impl ConstantTimeLess for Limb { #[inline] fn ct_lt(&self, other: &Self) -> Choice { self.0.ct_lt(&other.0) } } impl Eq for Limb {} impl Ord for Limb { fn cmp(&self, other: &Self) -> Ordering { let mut n = 0i8; n -= self.ct_lt(other).unwrap_u8() as i8; n += self.ct_gt(other).unwrap_u8() as i8; match n { -1 => Ordering::Less, 1 => Ordering::Greater, _ => { debug_assert_eq!(n, 0); debug_assert!(bool::from(self.ct_eq(other))); Ordering::Equal } } } } impl PartialOrd for Limb { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl PartialEq for Limb { #[inline] fn eq(&self, other: &Self) -> bool { self.ct_eq(other).into() } } #[cfg(test)] mod tests { use crate::{Limb, Zero}; use core::cmp::Ordering; use subtle::{ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess}; #[test] fn is_zero() { assert!(bool::from(Limb::ZERO.is_zero())); assert!(!bool::from(Limb::ONE.is_zero())); assert!(!bool::from(Limb::MAX.is_zero())); } #[test] fn is_odd() { assert!(!bool::from(Limb::ZERO.is_odd())); assert!(bool::from(Limb::ONE.is_odd())); assert!(bool::from(Limb::MAX.is_odd())); } #[test] fn ct_eq() { let a = Limb::ZERO; let b = Limb::MAX; assert!(bool::from(a.ct_eq(&a))); assert!(!bool::from(a.ct_eq(&b))); assert!(!bool::from(b.ct_eq(&a))); assert!(bool::from(b.ct_eq(&b))); } #[test] fn ct_gt() { let a = Limb::ZERO; let b = Limb::ONE; let c = Limb::MAX; assert!(bool::from(b.ct_gt(&a))); assert!(bool::from(c.ct_gt(&a))); assert!(bool::from(c.ct_gt(&b))); assert!(!bool::from(a.ct_gt(&a))); assert!(!bool::from(b.ct_gt(&b))); assert!(!bool::from(c.ct_gt(&c))); assert!(!bool::from(a.ct_gt(&b))); assert!(!bool::from(a.ct_gt(&c))); assert!(!bool::from(b.ct_gt(&c))); } #[test] fn ct_lt() { let a = Limb::ZERO; let b = Limb::ONE; let c = Limb::MAX; assert!(bool::from(a.ct_lt(&b))); assert!(bool::from(a.ct_lt(&c))); assert!(bool::from(b.ct_lt(&c))); assert!(!bool::from(a.ct_lt(&a))); assert!(!bool::from(b.ct_lt(&b))); assert!(!bool::from(c.ct_lt(&c))); assert!(!bool::from(b.ct_lt(&a))); assert!(!bool::from(c.ct_lt(&a))); assert!(!bool::from(c.ct_lt(&b))); } #[test] fn cmp() { assert_eq!(Limb::ZERO.cmp(&Limb::ONE), Ordering::Less); assert_eq!(Limb::ONE.cmp(&Limb::ONE), Ordering::Equal); assert_eq!(Limb::MAX.cmp(&Limb::ONE), Ordering::Greater); } } crypto-bigint-0.5.2/src/limb/encoding.rs000064400000000000000000000025401046102023000162710ustar 00000000000000//! Limb encoding use super::{Limb, Word}; use crate::Encoding; impl Encoding for Limb { #[cfg(target_pointer_width = "32")] type Repr = [u8; 4]; #[cfg(target_pointer_width = "64")] type Repr = [u8; 8]; #[inline] fn from_be_bytes(bytes: Self::Repr) -> Self { Limb(Word::from_be_bytes(bytes)) } #[inline] fn from_le_bytes(bytes: Self::Repr) -> Self { Limb(Word::from_le_bytes(bytes)) } #[inline] fn to_be_bytes(&self) -> Self::Repr { self.0.to_be_bytes() } #[inline] fn to_le_bytes(&self) -> Self::Repr { self.0.to_le_bytes() } } #[cfg(test)] mod test { use super::*; use proptest::prelude::*; prop_compose! { fn limb()(inner in any::()) -> Limb { Limb(inner) } } proptest! { #[test] fn roundtrip(a in limb()) { assert_eq!(a, Limb::from_be_bytes(a.to_be_bytes())); assert_eq!(a, Limb::from_le_bytes(a.to_le_bytes())); } } proptest! { #[test] fn reverse(a in limb()) { let mut bytes = a.to_be_bytes(); bytes.reverse(); assert_eq!(a, Limb::from_le_bytes(bytes)); let mut bytes = a.to_le_bytes(); bytes.reverse(); assert_eq!(a, Limb::from_be_bytes(bytes)); } } } crypto-bigint-0.5.2/src/limb/from.rs000064400000000000000000000031601046102023000154450ustar 00000000000000//! `From`-like conversions for [`Limb`]. use super::{Limb, WideWord, Word}; impl Limb { /// Create a [`Limb`] from a `u8` integer (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable pub const fn from_u8(n: u8) -> Self { Limb(n as Word) } /// Create a [`Limb`] from a `u16` integer (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable pub const fn from_u16(n: u16) -> Self { Limb(n as Word) } /// Create a [`Limb`] from a `u32` integer (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable pub const fn from_u32(n: u32) -> Self { #[allow(trivial_numeric_casts)] Limb(n as Word) } /// Create a [`Limb`] from a `u64` integer (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable #[cfg(target_pointer_width = "64")] pub const fn from_u64(n: u64) -> Self { Limb(n) } } impl From for Limb { #[inline] fn from(n: u8) -> Limb { Limb(n.into()) } } impl From for Limb { #[inline] fn from(n: u16) -> Limb { Limb(n.into()) } } impl From for Limb { #[inline] fn from(n: u32) -> Limb { Limb(n.into()) } } #[cfg(target_pointer_width = "64")] impl From for Limb { #[inline] fn from(n: u64) -> Limb { Limb(n) } } impl From for Word { #[inline] fn from(limb: Limb) -> Word { limb.0 } } impl From for WideWord { #[inline] fn from(limb: Limb) -> WideWord { limb.0.into() } } crypto-bigint-0.5.2/src/limb/mul.rs000064400000000000000000000117221046102023000153020ustar 00000000000000//! Limb multiplication use crate::{Checked, CheckedMul, Limb, WideWord, Word, Wrapping, Zero}; use core::ops::{Mul, MulAssign}; use subtle::CtOption; impl Limb { /// Computes `self + (b * c) + carry`, returning the result along with the new carry. #[inline(always)] pub const fn mac(self, b: Limb, c: Limb, carry: Limb) -> (Limb, Limb) { let a = self.0 as WideWord; let b = b.0 as WideWord; let c = c.0 as WideWord; let carry = carry.0 as WideWord; let ret = a + (b * c) + carry; (Limb(ret as Word), Limb((ret >> Self::BITS) as Word)) } /// Perform saturating multiplication. #[inline] pub const fn saturating_mul(&self, rhs: Self) -> Self { Limb(self.0.saturating_mul(rhs.0)) } /// Perform wrapping multiplication, discarding overflow. #[inline(always)] pub const fn wrapping_mul(&self, rhs: Self) -> Self { Limb(self.0.wrapping_mul(rhs.0)) } /// Compute "wide" multiplication, with a product twice the size of the input. pub(crate) const fn mul_wide(&self, rhs: Self) -> WideWord { (self.0 as WideWord) * (rhs.0 as WideWord) } } impl CheckedMul for Limb { type Output = Self; #[inline] fn checked_mul(&self, rhs: Self) -> CtOption { let result = self.mul_wide(rhs); let overflow = Limb((result >> Self::BITS) as Word); CtOption::new(Limb(result as Word), overflow.is_zero()) } } impl Mul for Wrapping { type Output = Self; fn mul(self, rhs: Self) -> Wrapping { Wrapping(self.0.wrapping_mul(rhs.0)) } } impl Mul<&Wrapping> for Wrapping { type Output = Wrapping; fn mul(self, rhs: &Wrapping) -> Wrapping { Wrapping(self.0.wrapping_mul(rhs.0)) } } impl Mul> for &Wrapping { type Output = Wrapping; fn mul(self, rhs: Wrapping) -> Wrapping { Wrapping(self.0.wrapping_mul(rhs.0)) } } impl Mul<&Wrapping> for &Wrapping { type Output = Wrapping; fn mul(self, rhs: &Wrapping) -> Wrapping { Wrapping(self.0.wrapping_mul(rhs.0)) } } impl MulAssign for Wrapping { fn mul_assign(&mut self, other: Self) { *self = *self * other; } } impl MulAssign<&Wrapping> for Wrapping { fn mul_assign(&mut self, other: &Self) { *self = *self * other; } } impl Mul for Checked { type Output = Self; fn mul(self, rhs: Self) -> Checked { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(rhs))), ) } } impl Mul<&Checked> for Checked { type Output = Checked; fn mul(self, rhs: &Checked) -> Checked { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(rhs))), ) } } impl Mul> for &Checked { type Output = Checked; fn mul(self, rhs: Checked) -> Checked { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(rhs))), ) } } impl Mul<&Checked> for &Checked { type Output = Checked; fn mul(self, rhs: &Checked) -> Checked { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(rhs))), ) } } impl MulAssign for Checked { fn mul_assign(&mut self, other: Self) { *self = *self * other; } } impl MulAssign<&Checked> for Checked { fn mul_assign(&mut self, other: &Self) { *self = *self * other; } } #[cfg(test)] mod tests { use super::{CheckedMul, Limb, WideWord}; #[test] fn mul_wide_zero_and_one() { assert_eq!(Limb::ZERO.mul_wide(Limb::ZERO), 0); assert_eq!(Limb::ZERO.mul_wide(Limb::ONE), 0); assert_eq!(Limb::ONE.mul_wide(Limb::ZERO), 0); assert_eq!(Limb::ONE.mul_wide(Limb::ONE), 1); } #[test] fn mul_wide() { let primes: &[u32] = &[3, 5, 17, 257, 65537]; for &a_int in primes { for &b_int in primes { let actual = Limb::from_u32(a_int).mul_wide(Limb::from_u32(b_int)); let expected = a_int as WideWord * b_int as WideWord; assert_eq!(actual, expected); } } } #[test] #[cfg(target_pointer_width = "32")] fn checked_mul_ok() { let n = Limb::from_u16(0xffff); assert_eq!(n.checked_mul(n).unwrap(), Limb::from_u32(0xfffe_0001)); } #[test] #[cfg(target_pointer_width = "64")] fn checked_mul_ok() { let n = Limb::from_u32(0xffff_ffff); assert_eq!( n.checked_mul(n).unwrap(), Limb::from_u64(0xffff_fffe_0000_0001) ); } #[test] fn checked_mul_overflow() { let n = Limb::MAX; assert!(bool::from(n.checked_mul(n).is_none())); } } crypto-bigint-0.5.2/src/limb/rand.rs000064400000000000000000000017551046102023000154360ustar 00000000000000//! Random number generator support use super::Limb; use crate::{Encoding, NonZero, Random, RandomMod}; use rand_core::CryptoRngCore; use subtle::ConstantTimeLess; impl Random for Limb { #[cfg(target_pointer_width = "32")] fn random(rng: &mut impl CryptoRngCore) -> Self { Self(rng.next_u32()) } #[cfg(target_pointer_width = "64")] fn random(rng: &mut impl CryptoRngCore) -> Self { Self(rng.next_u64()) } } impl RandomMod for Limb { fn random_mod(rng: &mut impl CryptoRngCore, modulus: &NonZero) -> Self { let mut bytes = ::Repr::default(); let n_bits = modulus.bits(); let n_bytes = (n_bits + 7) / 8; let mask = 0xff >> (8 * n_bytes - n_bits); loop { rng.fill_bytes(&mut bytes[..n_bytes]); bytes[n_bytes - 1] &= mask; let n = Limb::from_le_bytes(bytes); if n.ct_lt(modulus).into() { return n; } } } } crypto-bigint-0.5.2/src/limb/shl.rs000064400000000000000000000024001046102023000152640ustar 00000000000000//! Limb left bitshift use crate::{Limb, Word}; use core::ops::{Shl, ShlAssign}; impl Limb { /// Computes `self << rhs`. #[inline(always)] pub const fn shl(self, rhs: Self) -> Self { Limb(self.0 << rhs.0) } } impl Shl for Limb { type Output = Self; #[inline(always)] fn shl(self, rhs: Self) -> Self::Output { self.shl(rhs) } } impl Shl for Limb { type Output = Self; #[inline(always)] fn shl(self, rhs: usize) -> Self::Output { self.shl(Limb(rhs as Word)) } } impl ShlAssign for Limb { #[inline(always)] fn shl_assign(&mut self, other: Self) { *self = self.shl(other); } } impl ShlAssign for Limb { #[inline(always)] fn shl_assign(&mut self, other: usize) { *self = self.shl(Limb(other as Word)); } } #[cfg(test)] mod tests { use crate::Limb; #[test] fn shl1() { assert_eq!(Limb(1) << 1, Limb(2)); } #[test] fn shl2() { assert_eq!(Limb(1) << 2, Limb(4)); } #[test] fn shl_assign1() { let mut l = Limb(1); l <<= 1; assert_eq!(l, Limb(2)); } #[test] fn shl_assign2() { let mut l = Limb(1); l <<= 2; assert_eq!(l, Limb(4)); } } crypto-bigint-0.5.2/src/limb/shr.rs000064400000000000000000000024101046102023000152730ustar 00000000000000//! Limb right bitshift use crate::{Limb, Word}; use core::ops::{Shr, ShrAssign}; impl Limb { /// Computes `self >> rhs`. #[inline(always)] pub const fn shr(self, rhs: Self) -> Self { Limb(self.0 >> rhs.0) } } impl Shr for Limb { type Output = Self; #[inline(always)] fn shr(self, rhs: Self) -> Self::Output { self.shr(rhs) } } impl Shr for Limb { type Output = Self; #[inline(always)] fn shr(self, rhs: usize) -> Self::Output { self.shr(Limb(rhs as Word)) } } impl ShrAssign for Limb { #[inline(always)] fn shr_assign(&mut self, other: Self) { *self = self.shr(other); } } impl ShrAssign for Limb { #[inline(always)] fn shr_assign(&mut self, other: usize) { *self = self.shr(Limb(other as Word)); } } #[cfg(test)] mod tests { use crate::Limb; #[test] fn shr1() { assert_eq!(Limb(2) >> 1, Limb(1)); } #[test] fn shr2() { assert_eq!(Limb(16) >> 2, Limb(4)); } #[test] fn shr_assign1() { let mut l = Limb::ONE; l >>= 1; assert_eq!(l, Limb::ZERO); } #[test] fn shr_assign2() { let mut l = Limb(32); l >>= 2; assert_eq!(l, Limb(8)); } } crypto-bigint-0.5.2/src/limb/sub.rs000064400000000000000000000106531046102023000153000ustar 00000000000000//! Limb subtraction use crate::{Checked, CheckedSub, Limb, WideWord, Word, Wrapping, Zero}; use core::ops::{Sub, SubAssign}; use subtle::CtOption; impl Limb { /// Computes `self - (rhs + borrow)`, returning the result along with the new borrow. #[inline(always)] pub const fn sbb(self, rhs: Limb, borrow: Limb) -> (Limb, Limb) { let a = self.0 as WideWord; let b = rhs.0 as WideWord; let borrow = (borrow.0 >> (Self::BITS - 1)) as WideWord; let ret = a.wrapping_sub(b + borrow); (Limb(ret as Word), Limb((ret >> Self::BITS) as Word)) } /// Perform saturating subtraction. #[inline] pub const fn saturating_sub(&self, rhs: Self) -> Self { Limb(self.0.saturating_sub(rhs.0)) } /// Perform wrapping subtraction, discarding underflow and wrapping around /// the boundary of the type. #[inline(always)] pub const fn wrapping_sub(&self, rhs: Self) -> Self { Limb(self.0.wrapping_sub(rhs.0)) } } impl CheckedSub for Limb { type Output = Self; #[inline] fn checked_sub(&self, rhs: Self) -> CtOption { let (result, underflow) = self.sbb(rhs, Limb::ZERO); CtOption::new(result, underflow.is_zero()) } } impl Sub for Wrapping { type Output = Self; fn sub(self, rhs: Self) -> Wrapping { Wrapping(self.0.wrapping_sub(rhs.0)) } } impl Sub<&Wrapping> for Wrapping { type Output = Wrapping; fn sub(self, rhs: &Wrapping) -> Wrapping { Wrapping(self.0.wrapping_sub(rhs.0)) } } impl Sub> for &Wrapping { type Output = Wrapping; fn sub(self, rhs: Wrapping) -> Wrapping { Wrapping(self.0.wrapping_sub(rhs.0)) } } impl Sub<&Wrapping> for &Wrapping { type Output = Wrapping; fn sub(self, rhs: &Wrapping) -> Wrapping { Wrapping(self.0.wrapping_sub(rhs.0)) } } impl SubAssign for Wrapping { fn sub_assign(&mut self, other: Self) { *self = *self - other; } } impl SubAssign<&Wrapping> for Wrapping { fn sub_assign(&mut self, other: &Self) { *self = *self - other; } } impl Sub for Checked { type Output = Self; fn sub(self, rhs: Self) -> Checked { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))), ) } } impl Sub<&Checked> for Checked { type Output = Checked; fn sub(self, rhs: &Checked) -> Checked { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))), ) } } impl Sub> for &Checked { type Output = Checked; fn sub(self, rhs: Checked) -> Checked { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))), ) } } impl Sub<&Checked> for &Checked { type Output = Checked; fn sub(self, rhs: &Checked) -> Checked { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))), ) } } impl SubAssign for Checked { fn sub_assign(&mut self, other: Self) { *self = *self - other; } } impl SubAssign<&Checked> for Checked { fn sub_assign(&mut self, other: &Self) { *self = *self - other; } } #[cfg(test)] mod tests { use crate::{CheckedSub, Limb}; #[test] fn sbb_no_borrow() { let (res, borrow) = Limb::ONE.sbb(Limb::ONE, Limb::ZERO); assert_eq!(res, Limb::ZERO); assert_eq!(borrow, Limb::ZERO); } #[test] fn sbb_with_borrow() { let (res, borrow) = Limb::ZERO.sbb(Limb::ONE, Limb::ZERO); assert_eq!(res, Limb::MAX); assert_eq!(borrow, Limb::MAX); } #[test] fn wrapping_sub_no_borrow() { assert_eq!(Limb::ONE.wrapping_sub(Limb::ONE), Limb::ZERO); } #[test] fn wrapping_sub_with_borrow() { assert_eq!(Limb::ZERO.wrapping_sub(Limb::ONE), Limb::MAX); } #[test] fn checked_sub_ok() { let result = Limb::ONE.checked_sub(Limb::ONE); assert_eq!(result.unwrap(), Limb::ZERO); } #[test] fn checked_sub_overflow() { let result = Limb::ZERO.checked_sub(Limb::ONE); assert!(!bool::from(result.is_some())); } } crypto-bigint-0.5.2/src/limb.rs000064400000000000000000000077671046102023000145230ustar 00000000000000//! Big integers are represented as an array of smaller CPU word-size integers //! called "limbs". #![allow(clippy::derive_hash_xor_eq)] mod add; mod bit_and; mod bit_not; mod bit_or; mod bit_xor; mod bits; mod cmp; mod encoding; mod from; mod mul; mod shl; mod shr; mod sub; #[cfg(feature = "rand_core")] mod rand; use crate::{Bounded, Zero}; use core::fmt; use subtle::{Choice, ConditionallySelectable}; #[cfg(feature = "serde")] use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] compile_error!("this crate builds on 32-bit and 64-bit platforms only"); // // 32-bit definitions // /// Inner integer type that the [`Limb`] newtype wraps. #[cfg(target_pointer_width = "32")] pub type Word = u32; /// Unsigned wide integer type: double the width of [`Word`]. #[cfg(target_pointer_width = "32")] pub type WideWord = u64; // // 64-bit definitions // /// Unsigned integer type that the [`Limb`] newtype wraps. #[cfg(target_pointer_width = "64")] pub type Word = u64; /// Wide integer type: double the width of [`Word`]. #[cfg(target_pointer_width = "64")] pub type WideWord = u128; /// Highest bit in a [`Limb`]. pub(crate) const HI_BIT: usize = Limb::BITS - 1; /// Big integers are represented as an array of smaller CPU word-size integers /// called "limbs". #[derive(Copy, Clone, Default, Hash)] #[repr(transparent)] pub struct Limb(pub Word); impl Limb { /// The value `0`. pub const ZERO: Self = Limb(0); /// The value `1`. pub const ONE: Self = Limb(1); /// Maximum value this [`Limb`] can express. pub const MAX: Self = Limb(Word::MAX); // 32-bit /// Size of the inner integer in bits. #[cfg(target_pointer_width = "32")] pub const BITS: usize = 32; /// Size of the inner integer in bytes. #[cfg(target_pointer_width = "32")] pub const BYTES: usize = 4; // 64-bit /// Size of the inner integer in bits. #[cfg(target_pointer_width = "64")] pub const BITS: usize = 64; /// Size of the inner integer in bytes. #[cfg(target_pointer_width = "64")] pub const BYTES: usize = 8; } impl Bounded for Limb { const BITS: usize = Self::BITS; const BYTES: usize = Self::BYTES; } impl ConditionallySelectable for Limb { #[inline] fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Self(Word::conditional_select(&a.0, &b.0, choice)) } } impl Zero for Limb { const ZERO: Self = Self::ZERO; } impl fmt::Debug for Limb { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Limb(0x{self:X})") } } impl fmt::Display for Limb { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::UpperHex::fmt(self, f) } } impl fmt::LowerHex for Limb { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:0width$x}", &self.0, width = Self::BYTES * 2) } } impl fmt::UpperHex for Limb { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:0width$X}", &self.0, width = Self::BYTES * 2) } } #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for Limb { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { Ok(Self(Word::deserialize(deserializer)?)) } } #[cfg(feature = "serde")] impl Serialize for Limb { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.0.serialize(serializer) } } #[cfg(feature = "zeroize")] impl zeroize::DefaultIsZeroes for Limb {} #[cfg(test)] mod tests { #[cfg(feature = "alloc")] use {super::Limb, alloc::format}; #[cfg(feature = "alloc")] #[test] fn debug() { #[cfg(target_pointer_width = "32")] assert_eq!(format!("{:?}", Limb(42)), "Limb(0x0000002A)"); #[cfg(target_pointer_width = "64")] assert_eq!(format!("{:?}", Limb(42)), "Limb(0x000000000000002A)"); } } crypto-bigint-0.5.2/src/nlimbs.rs000064400000000000000000000014141046102023000150430ustar 00000000000000/// Calculate the number of limbs required to represent the given number of bits. // TODO(tarcieri): replace with `generic_const_exprs` (rust-lang/rust#76560) when stable #[macro_export] macro_rules! nlimbs { ($bits:expr) => { $bits / $crate::Limb::BITS }; } #[cfg(test)] mod tests { #[cfg(target_pointer_width = "32")] #[test] fn nlimbs_for_bits_macro() { assert_eq!(nlimbs!(64), 2); assert_eq!(nlimbs!(128), 4); assert_eq!(nlimbs!(192), 6); assert_eq!(nlimbs!(256), 8); } #[cfg(target_pointer_width = "64")] #[test] fn nlimbs_for_bits_macro() { assert_eq!(nlimbs!(64), 1); assert_eq!(nlimbs!(128), 2); assert_eq!(nlimbs!(192), 3); assert_eq!(nlimbs!(256), 4); } } crypto-bigint-0.5.2/src/non_zero.rs000064400000000000000000000236771046102023000154270ustar 00000000000000//! Wrapper type for non-zero integers. use crate::{Encoding, Integer, Limb, Uint, Zero}; use core::{ fmt, num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8}, ops::Deref, }; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; #[cfg(feature = "generic-array")] use crate::{ArrayEncoding, ByteArray}; #[cfg(feature = "rand_core")] use {crate::Random, rand_core::CryptoRngCore}; #[cfg(feature = "serde")] use serdect::serde::{ de::{Error, Unexpected}, Deserialize, Deserializer, Serialize, Serializer, }; /// Wrapper type for non-zero integers. #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] pub struct NonZero(T); impl NonZero where T: Zero, { /// Create a new non-zero integer. pub fn new(n: T) -> CtOption { let is_zero = n.is_zero(); CtOption::new(Self(n), !is_zero) } } impl NonZero where T: Integer, { /// The value `1`. pub const ONE: Self = Self(T::ONE); /// Maximum value this integer can express. pub const MAX: Self = Self(T::MAX); } impl NonZero where T: Encoding + Zero, { /// Decode from big endian bytes. pub fn from_be_bytes(bytes: T::Repr) -> CtOption { Self::new(T::from_be_bytes(bytes)) } /// Decode from little endian bytes. pub fn from_le_bytes(bytes: T::Repr) -> CtOption { Self::new(T::from_le_bytes(bytes)) } } #[cfg(feature = "generic-array")] impl NonZero where T: ArrayEncoding + Zero, { /// Decode a non-zero integer from big endian bytes. pub fn from_be_byte_array(bytes: ByteArray) -> CtOption { Self::new(T::from_be_byte_array(bytes)) } /// Decode a non-zero integer from big endian bytes. pub fn from_le_byte_array(bytes: ByteArray) -> CtOption { Self::new(T::from_be_byte_array(bytes)) } } impl AsRef for NonZero where T: Zero, { fn as_ref(&self) -> &T { &self.0 } } impl ConditionallySelectable for NonZero where T: ConditionallySelectable + Zero, { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Self(T::conditional_select(&a.0, &b.0, choice)) } } impl ConstantTimeEq for NonZero where T: Zero, { fn ct_eq(&self, other: &Self) -> Choice { self.0.ct_eq(&other.0) } } impl Deref for NonZero where T: Zero, { type Target = T; fn deref(&self) -> &T { &self.0 } } #[cfg(feature = "rand_core")] impl Random for NonZero where T: Random + Zero, { /// Generate a random `NonZero`. fn random(mut rng: &mut impl CryptoRngCore) -> Self { // Use rejection sampling to eliminate zero values. // While this method isn't constant-time, the attacker shouldn't learn // anything about unrelated outputs so long as `rng` is a CSRNG. loop { if let Some(result) = Self::new(T::random(&mut rng)).into() { break result; } } } } impl fmt::Display for NonZero where T: fmt::Display + Zero, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.0, f) } } impl fmt::Binary for NonZero where T: fmt::Binary + Zero, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Binary::fmt(&self.0, f) } } impl fmt::Octal for NonZero where T: fmt::Octal + Zero, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Octal::fmt(&self.0, f) } } impl fmt::LowerHex for NonZero where T: fmt::LowerHex + Zero, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) } } impl fmt::UpperHex for NonZero where T: fmt::UpperHex + Zero, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::UpperHex::fmt(&self.0, f) } } impl NonZero { /// Create a [`NonZero`] from a [`NonZeroU8`] (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable pub const fn from_u8(n: NonZeroU8) -> Self { Self(Limb::from_u8(n.get())) } /// Create a [`NonZero`] from a [`NonZeroU16`] (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable pub const fn from_u16(n: NonZeroU16) -> Self { Self(Limb::from_u16(n.get())) } /// Create a [`NonZero`] from a [`NonZeroU32`] (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable pub const fn from_u32(n: NonZeroU32) -> Self { Self(Limb::from_u32(n.get())) } /// Create a [`NonZero`] from a [`NonZeroU64`] (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable #[cfg(target_pointer_width = "64")] pub const fn from_u64(n: NonZeroU64) -> Self { Self(Limb::from_u64(n.get())) } } impl From for NonZero { fn from(integer: NonZeroU8) -> Self { Self::from_u8(integer) } } impl From for NonZero { fn from(integer: NonZeroU16) -> Self { Self::from_u16(integer) } } impl From for NonZero { fn from(integer: NonZeroU32) -> Self { Self::from_u32(integer) } } #[cfg(target_pointer_width = "64")] impl From for NonZero { fn from(integer: NonZeroU64) -> Self { Self::from_u64(integer) } } impl NonZero> { /// Create a [`NonZero`] from a [`Uint`] (const-friendly) pub const fn from_uint(n: Uint) -> Self { let mut i = 0; let mut found_non_zero = false; while i < LIMBS { if n.as_limbs()[i].0 != 0 { found_non_zero = true; } i += 1; } assert!(found_non_zero, "found zero"); Self(n) } /// Create a [`NonZero`] from a [`NonZeroU8`] (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable pub const fn from_u8(n: NonZeroU8) -> Self { Self(Uint::from_u8(n.get())) } /// Create a [`NonZero`] from a [`NonZeroU16`] (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable pub const fn from_u16(n: NonZeroU16) -> Self { Self(Uint::from_u16(n.get())) } /// Create a [`NonZero`] from a [`NonZeroU32`] (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable pub const fn from_u32(n: NonZeroU32) -> Self { Self(Uint::from_u32(n.get())) } /// Create a [`NonZero`] from a [`NonZeroU64`] (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable pub const fn from_u64(n: NonZeroU64) -> Self { Self(Uint::from_u64(n.get())) } /// Create a [`NonZero`] from a [`NonZeroU128`] (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable pub const fn from_u128(n: NonZeroU128) -> Self { Self(Uint::from_u128(n.get())) } } impl From for NonZero> { fn from(integer: NonZeroU8) -> Self { Self::from_u8(integer) } } impl From for NonZero> { fn from(integer: NonZeroU16) -> Self { Self::from_u16(integer) } } impl From for NonZero> { fn from(integer: NonZeroU32) -> Self { Self::from_u32(integer) } } impl From for NonZero> { fn from(integer: NonZeroU64) -> Self { Self::from_u64(integer) } } impl From for NonZero> { fn from(integer: NonZeroU128) -> Self { Self::from_u128(integer) } } #[cfg(feature = "serde")] impl<'de, T: Deserialize<'de> + Zero> Deserialize<'de> for NonZero { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let value: T = T::deserialize(deserializer)?; if bool::from(value.is_zero()) { Err(D::Error::invalid_value( Unexpected::Other("zero"), &"a non-zero value", )) } else { Ok(Self(value)) } } } #[cfg(feature = "serde")] impl Serialize for NonZero { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.0.serialize(serializer) } } #[cfg(all(test, feature = "serde"))] mod tests { use crate::{NonZero, U64}; use bincode::ErrorKind; #[test] fn serde() { let test = Option::>::from(NonZero::new(U64::from_u64(0x0011223344556677))).unwrap(); let serialized = bincode::serialize(&test).unwrap(); let deserialized: NonZero = bincode::deserialize(&serialized).unwrap(); assert_eq!(test, deserialized); let serialized = bincode::serialize(&U64::ZERO).unwrap(); assert!(matches!( *bincode::deserialize::>(&serialized).unwrap_err(), ErrorKind::Custom(message) if message == "invalid value: zero, expected a non-zero value" )); } #[test] fn serde_owned() { let test = Option::>::from(NonZero::new(U64::from_u64(0x0011223344556677))).unwrap(); let serialized = bincode::serialize(&test).unwrap(); let deserialized: NonZero = bincode::deserialize_from(serialized.as_slice()).unwrap(); assert_eq!(test, deserialized); let serialized = bincode::serialize(&U64::ZERO).unwrap(); assert!(matches!( *bincode::deserialize_from::<_, NonZero>(serialized.as_slice()).unwrap_err(), ErrorKind::Custom(message) if message == "invalid value: zero, expected a non-zero value" )); } } crypto-bigint-0.5.2/src/traits.rs000064400000000000000000000171061046102023000150720ustar 00000000000000//! Traits provided by this crate use crate::{Limb, NonZero}; use core::fmt::Debug; use core::ops::{BitAnd, BitOr, BitXor, Div, Not, Rem, Shl, Shr}; use subtle::{ Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess, CtOption, }; #[cfg(feature = "rand_core")] use rand_core::CryptoRngCore; /// Integer type. pub trait Integer: 'static + AsRef<[Limb]> + BitAnd + BitOr + BitXor + for<'a> CheckedAdd<&'a Self, Output = Self> + for<'a> CheckedSub<&'a Self, Output = Self> + for<'a> CheckedMul<&'a Self, Output = Self> + Copy + ConditionallySelectable + ConstantTimeEq + ConstantTimeGreater + ConstantTimeLess + Debug + Default + Div, Output = Self> + Eq + From + Not + Ord + Rem, Output = Self> + Send + Sized + Shl + Shr + Sync + Zero { /// The value `1`. const ONE: Self; /// Maximum value this integer can express. const MAX: Self; /// Total size of the represented integer in bits. const BITS: usize; /// Total size of the represented integer in bytes. const BYTES: usize; /// The number of limbs used on this platform. const LIMBS: usize; /// Is this integer value an odd number? /// /// # Returns /// /// If odd, returns `Choice(1)`. Otherwise, returns `Choice(0)`. fn is_odd(&self) -> Choice; /// Is this integer value an even number? /// /// # Returns /// /// If even, returns `Choice(1)`. Otherwise, returns `Choice(0)`. fn is_even(&self) -> Choice { !self.is_odd() } } /// Zero values. pub trait Zero: ConstantTimeEq + Sized { /// The value `0`. const ZERO: Self; /// Determine if this value is equal to zero. /// /// # Returns /// /// If zero, returns `Choice(1)`. Otherwise, returns `Choice(0)`. fn is_zero(&self) -> Choice { self.ct_eq(&Self::ZERO) } } /// Random number generation support. #[cfg(feature = "rand_core")] pub trait Random: Sized { /// Generate a cryptographically secure random value. fn random(rng: &mut impl CryptoRngCore) -> Self; } /// Modular random number generation support. #[cfg(feature = "rand_core")] pub trait RandomMod: Sized + Zero { /// Generate a cryptographically secure random number which is less than /// a given `modulus`. /// /// This function uses rejection sampling, a method which produces an /// unbiased distribution of in-range values provided the underlying /// CSRNG is unbiased, but runs in variable-time. /// /// The variable-time nature of the algorithm should not pose a security /// issue so long as the underlying random number generator is truly a /// CSRNG, where previous outputs are unrelated to subsequent /// outputs and do not reveal information about the RNG's internal state. fn random_mod(rng: &mut impl CryptoRngCore, modulus: &NonZero) -> Self; } /// Compute `self + rhs mod p`. pub trait AddMod { /// Output type. type Output; /// Compute `self + rhs mod p`. /// /// Assumes `self` and `rhs` are `< p`. fn add_mod(&self, rhs: &Rhs, p: &Self) -> Self::Output; } /// Compute `self - rhs mod p`. pub trait SubMod { /// Output type. type Output; /// Compute `self - rhs mod p`. /// /// Assumes `self` and `rhs` are `< p`. fn sub_mod(&self, rhs: &Rhs, p: &Self) -> Self::Output; } /// Compute `-self mod p`. pub trait NegMod { /// Output type. type Output; /// Compute `-self mod p`. #[must_use] fn neg_mod(&self, p: &Self) -> Self::Output; } /// Compute `self * rhs mod p`. /// /// Requires `p_inv = -(p^{-1} mod 2^{BITS}) mod 2^{BITS}` to be provided for efficiency. pub trait MulMod { /// Output type. type Output; /// Compute `self * rhs mod p`. /// /// Requires `p_inv = -(p^{-1} mod 2^{BITS}) mod 2^{BITS}` to be provided for efficiency. fn mul_mod(&self, rhs: &Rhs, p: &Self, p_inv: Limb) -> Self::Output; } /// Checked addition. pub trait CheckedAdd: Sized { /// Output type. type Output; /// Perform checked subtraction, returning a [`CtOption`] which `is_some` /// only if the operation did not overflow. fn checked_add(&self, rhs: Rhs) -> CtOption; } /// Checked multiplication. pub trait CheckedMul: Sized { /// Output type. type Output; /// Perform checked multiplication, returning a [`CtOption`] which `is_some` /// only if the operation did not overflow. fn checked_mul(&self, rhs: Rhs) -> CtOption; } /// Checked subtraction. pub trait CheckedSub: Sized { /// Output type. type Output; /// Perform checked subtraction, returning a [`CtOption`] which `is_some` /// only if the operation did not underflow. fn checked_sub(&self, rhs: Rhs) -> CtOption; } /// Concatenate two numbers into a "wide" twice-width value, using the `rhs` /// value as the least significant value. pub trait Concat { /// Concatenated output: twice the width of `Self`. type Output; /// Concatenate the two values, with `self` as most significant and `rhs` /// as the least significant. fn concat(&self, rhs: &Self) -> Self::Output; } /// Split a number in half, returning the most significant half followed by /// the least significant. pub trait Split { /// Split output: high/low components of the value. type Output; /// Split this number in half, returning its high and low components /// respectively. fn split(&self) -> (Self::Output, Self::Output); } /// Integers whose representation takes a bounded amount of space. pub trait Bounded { /// Size of this integer in bits. const BITS: usize; /// Size of this integer in bytes. const BYTES: usize; } /// Encoding support. pub trait Encoding: Sized { /// Byte array representation. type Repr: AsRef<[u8]> + AsMut<[u8]> + Copy + Clone + Sized; /// Decode from big endian bytes. fn from_be_bytes(bytes: Self::Repr) -> Self; /// Decode from little endian bytes. fn from_le_bytes(bytes: Self::Repr) -> Self; /// Encode to big endian bytes. fn to_be_bytes(&self) -> Self::Repr; /// Encode to little endian bytes. fn to_le_bytes(&self) -> Self::Repr; } /// Support for optimized squaring pub trait Square: Sized where for<'a> &'a Self: core::ops::Mul<&'a Self, Output = Self>, { /// Computes the same as `self.mul(self)`, but may be more efficient. fn square(&self) -> Self { self * self } } /// Constant-time exponentiation. pub trait Pow { /// Raises to the `exponent` power. fn pow(&self, exponent: &Exponent) -> Self; } impl, Exponent: Bounded> Pow for T { fn pow(&self, exponent: &Exponent) -> Self { self.pow_bounded_exp(exponent, Exponent::BITS) } } /// Constant-time exponentiation with exponent of a bounded bit size. pub trait PowBoundedExp { /// Raises to the `exponent` power, /// with `exponent_bits` representing the number of (least significant) bits /// to take into account for the exponent. /// /// NOTE: `exponent_bits` may be leaked in the time pattern. fn pow_bounded_exp(&self, exponent: &Exponent, exponent_bits: usize) -> Self; } /// Constant-time inversion. pub trait Invert: Sized { /// Output of the inversion. type Output; /// Computes the inverse. fn invert(&self) -> Self::Output; } crypto-bigint-0.5.2/src/uint/add.rs000064400000000000000000000127741046102023000153010ustar 00000000000000//! [`Uint`] addition operations. use crate::{Checked, CheckedAdd, CtChoice, Limb, Uint, Wrapping, Zero}; use core::ops::{Add, AddAssign}; use subtle::CtOption; impl Uint { /// Computes `a + b + carry`, returning the result along with the new carry. #[inline(always)] pub const fn adc(&self, rhs: &Self, mut carry: Limb) -> (Self, Limb) { let mut limbs = [Limb::ZERO; LIMBS]; let mut i = 0; while i < LIMBS { let (w, c) = self.limbs[i].adc(rhs.limbs[i], carry); limbs[i] = w; carry = c; i += 1; } (Self { limbs }, carry) } /// Perform saturating addition, returning `MAX` on overflow. pub const fn saturating_add(&self, rhs: &Self) -> Self { let (res, overflow) = self.adc(rhs, Limb::ZERO); if overflow.0 == 0 { res } else { Self::MAX } } /// Perform wrapping addition, discarding overflow. pub const fn wrapping_add(&self, rhs: &Self) -> Self { self.adc(rhs, Limb::ZERO).0 } /// Perform wrapping addition, returning the truthy value as the second element of the tuple /// if an overflow has occurred. pub(crate) const fn conditional_wrapping_add( &self, rhs: &Self, choice: CtChoice, ) -> (Self, CtChoice) { let actual_rhs = Uint::ct_select(&Uint::ZERO, rhs, choice); let (sum, carry) = self.adc(&actual_rhs, Limb::ZERO); (sum, CtChoice::from_lsb(carry.0)) } } impl CheckedAdd<&Uint> for Uint { type Output = Self; fn checked_add(&self, rhs: &Self) -> CtOption { let (result, carry) = self.adc(rhs, Limb::ZERO); CtOption::new(result, carry.is_zero()) } } impl Add for Wrapping> { type Output = Self; fn add(self, rhs: Self) -> Wrapping> { Wrapping(self.0.wrapping_add(&rhs.0)) } } impl Add<&Wrapping>> for Wrapping> { type Output = Wrapping>; fn add(self, rhs: &Wrapping>) -> Wrapping> { Wrapping(self.0.wrapping_add(&rhs.0)) } } impl Add>> for &Wrapping> { type Output = Wrapping>; fn add(self, rhs: Wrapping>) -> Wrapping> { Wrapping(self.0.wrapping_add(&rhs.0)) } } impl Add<&Wrapping>> for &Wrapping> { type Output = Wrapping>; fn add(self, rhs: &Wrapping>) -> Wrapping> { Wrapping(self.0.wrapping_add(&rhs.0)) } } impl AddAssign for Wrapping> { fn add_assign(&mut self, other: Self) { *self = *self + other; } } impl AddAssign<&Wrapping>> for Wrapping> { fn add_assign(&mut self, other: &Self) { *self = *self + other; } } impl Add for Checked> { type Output = Self; fn add(self, rhs: Self) -> Checked> { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))), ) } } impl Add<&Checked>> for Checked> { type Output = Checked>; fn add(self, rhs: &Checked>) -> Checked> { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))), ) } } impl Add>> for &Checked> { type Output = Checked>; fn add(self, rhs: Checked>) -> Checked> { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))), ) } } impl Add<&Checked>> for &Checked> { type Output = Checked>; fn add(self, rhs: &Checked>) -> Checked> { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))), ) } } impl AddAssign for Checked> { fn add_assign(&mut self, other: Self) { *self = *self + other; } } impl AddAssign<&Checked>> for Checked> { fn add_assign(&mut self, other: &Self) { *self = *self + other; } } #[cfg(test)] mod tests { use crate::{CheckedAdd, Limb, U128}; #[test] fn adc_no_carry() { let (res, carry) = U128::ZERO.adc(&U128::ONE, Limb::ZERO); assert_eq!(res, U128::ONE); assert_eq!(carry, Limb::ZERO); } #[test] fn adc_with_carry() { let (res, carry) = U128::MAX.adc(&U128::ONE, Limb::ZERO); assert_eq!(res, U128::ZERO); assert_eq!(carry, Limb::ONE); } #[test] fn wrapping_add_no_carry() { assert_eq!(U128::ZERO.wrapping_add(&U128::ONE), U128::ONE); } #[test] fn wrapping_add_with_carry() { assert_eq!(U128::MAX.wrapping_add(&U128::ONE), U128::ZERO); } #[test] fn checked_add_ok() { let result = U128::ZERO.checked_add(&U128::ONE); assert_eq!(result.unwrap(), U128::ONE); } #[test] fn checked_add_overflow() { let result = U128::MAX.checked_add(&U128::ONE); assert!(!bool::from(result.is_some())); } } crypto-bigint-0.5.2/src/uint/add_mod.rs000064400000000000000000000114621046102023000161310ustar 00000000000000//! [`Uint`] addition modulus operations. use crate::{AddMod, Limb, Uint}; impl Uint { /// Computes `self + rhs mod p` in constant time. /// /// Assumes `self + rhs` as unbounded integer is `< 2p`. pub const fn add_mod(&self, rhs: &Uint, p: &Uint) -> Uint { let (w, carry) = self.adc(rhs, Limb::ZERO); // Attempt to subtract the modulus, to ensure the result is in the field. let (w, borrow) = w.sbb(p, Limb::ZERO); let (_, borrow) = carry.sbb(Limb::ZERO, borrow); // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the // modulus. let mask = Uint::from_words([borrow.0; LIMBS]); w.wrapping_add(&p.bitand(&mask)) } /// Computes `self + rhs mod p` in constant time for the special modulus /// `p = MAX+1-c` where `c` is small enough to fit in a single [`Limb`]. /// /// Assumes `self + rhs` as unbounded integer is `< 2p`. pub const fn add_mod_special(&self, rhs: &Self, c: Limb) -> Self { // `Uint::adc` also works with a carry greater than 1. let (out, carry) = self.adc(rhs, c); // If overflow occurred, then above addition of `c` already accounts // for the overflow. Otherwise, we need to subtract `c` again, which // in that case cannot underflow. let l = carry.0.wrapping_sub(1) & c.0; out.wrapping_sub(&Uint::from_word(l)) } } impl AddMod for Uint { type Output = Self; fn add_mod(&self, rhs: &Self, p: &Self) -> Self { debug_assert!(self < p); debug_assert!(rhs < p); self.add_mod(rhs, p) } } #[cfg(all(test, feature = "rand"))] mod tests { use crate::{Limb, NonZero, Random, RandomMod, Uint, U256}; use rand_core::SeedableRng; // TODO(tarcieri): additional tests + proptests #[test] fn add_mod_nist_p256() { let a = U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); let b = U256::from_be_hex("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"); let n = U256::from_be_hex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"); let actual = a.add_mod(&b, &n); let expected = U256::from_be_hex("1a2472fde50286541d97ca6a3592dd75beb9c9646e40c511b82496cfc3926956"); assert_eq!(expected, actual); } macro_rules! test_add_mod_special { ($size:expr, $test_name:ident) => { #[test] fn $test_name() { let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); let moduli = [ NonZero::::random(&mut rng), NonZero::::random(&mut rng), ]; for special in &moduli { let p = &NonZero::new(Uint::ZERO.wrapping_sub(&Uint::from_word(special.0))) .unwrap(); let minus_one = p.wrapping_sub(&Uint::ONE); let base_cases = [ (Uint::ZERO, Uint::ZERO, Uint::ZERO), (Uint::ONE, Uint::ZERO, Uint::ONE), (Uint::ZERO, Uint::ONE, Uint::ONE), (minus_one, Uint::ONE, Uint::ZERO), (Uint::ONE, minus_one, Uint::ZERO), ]; for (a, b, c) in &base_cases { let x = a.add_mod_special(b, *special.as_ref()); assert_eq!(*c, x, "{} + {} mod {} = {} != {}", a, b, p, x, c); } for _i in 0..100 { let a = Uint::<$size>::random_mod(&mut rng, p); let b = Uint::<$size>::random_mod(&mut rng, p); let c = a.add_mod_special(&b, *special.as_ref()); assert!(c < **p, "not reduced: {} >= {} ", c, p); let expected = a.add_mod(&b, p); assert_eq!(c, expected, "incorrect result"); } } } }; } test_add_mod_special!(1, add_mod_special_1); test_add_mod_special!(2, add_mod_special_2); test_add_mod_special!(3, add_mod_special_3); test_add_mod_special!(4, add_mod_special_4); test_add_mod_special!(5, add_mod_special_5); test_add_mod_special!(6, add_mod_special_6); test_add_mod_special!(7, add_mod_special_7); test_add_mod_special!(8, add_mod_special_8); test_add_mod_special!(9, add_mod_special_9); test_add_mod_special!(10, add_mod_special_10); test_add_mod_special!(11, add_mod_special_11); test_add_mod_special!(12, add_mod_special_12); } crypto-bigint-0.5.2/src/uint/array.rs000064400000000000000000000142261046102023000156610ustar 00000000000000//! `generic-array` integration with `Uint`. // TODO(tarcieri): completely phase out `generic-array` when const generics are powerful enough use crate::{ArrayDecoding, ArrayEncoding, ByteArray}; use generic_array::{typenum, GenericArray}; macro_rules! impl_uint_array_encoding { ($(($uint:ident, $bytes:path)),+) => { $( impl ArrayEncoding for super::$uint { type ByteSize = $bytes; #[inline] fn from_be_byte_array(bytes: ByteArray) -> Self { Self::from_be_slice(&bytes) } #[inline] fn from_le_byte_array(bytes: ByteArray) -> Self { Self::from_le_slice(&bytes) } #[inline] fn to_be_byte_array(&self) -> ByteArray { let mut result = GenericArray::default(); self.write_be_bytes(&mut result); result } #[inline] fn to_le_byte_array(&self) -> ByteArray { let mut result = GenericArray::default(); self.write_le_bytes(&mut result); result } } impl ArrayDecoding for GenericArray { type Output = super::$uint; fn into_uint_be(self) -> Self::Output { Self::Output::from_be_byte_array(self) } fn into_uint_le(self) -> Self::Output { Self::Output::from_le_byte_array(self) } } )+ }; } // TODO(tarcieri): use `const_evaluatable_checked` when stable to make generic around bits. impl_uint_array_encoding! { (U64, typenum::U8), (U128, typenum::U16), (U192, typenum::U24), (U256, typenum::U32), (U384, typenum::U48), (U448, typenum::U56), (U512, typenum::U64), (U576, typenum::U72), (U768, typenum::U96), (U896, typenum::U112), (U1024, typenum::U128), (U1536, typenum::U192), (U1792, typenum::U224), (U2048, typenum::U256), (U3072, typenum::U384), (U3584, typenum::U448), (U4096, typenum::U512), (U6144, typenum::U768), (U8192, typenum::U1024) } #[cfg(target_pointer_width = "32")] impl_uint_array_encoding! { (U224, typenum::U28), // For NIST P-224 (U544, typenum::U68) // For NIST P-521 } #[cfg(test)] mod tests { use crate::{ArrayDecoding, ArrayEncoding, Limb}; use hex_literal::hex; #[cfg(target_pointer_width = "32")] use crate::U64 as UintEx; #[cfg(target_pointer_width = "64")] use crate::U128 as UintEx; /// Byte array that corresponds to `UintEx` type ByteArray = crate::ByteArray; #[test] #[cfg(target_pointer_width = "32")] fn from_be_byte_array() { let n = UintEx::from_be_byte_array(hex!("0011223344556677").into()); assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]); } #[test] #[cfg(target_pointer_width = "64")] fn from_be_byte_array() { let n = UintEx::from_be_byte_array(hex!("00112233445566778899aabbccddeeff").into()); assert_eq!( n.as_limbs(), &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)] ); } #[test] #[cfg(target_pointer_width = "32")] fn from_le_byte_array() { let n = UintEx::from_le_byte_array(hex!("7766554433221100").into()); assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]); } #[test] #[cfg(target_pointer_width = "64")] fn from_le_byte_array() { let n = UintEx::from_le_byte_array(hex!("ffeeddccbbaa99887766554433221100").into()); assert_eq!( n.as_limbs(), &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)] ); } #[test] #[cfg(target_pointer_width = "32")] fn to_be_byte_array() { let expected_bytes = ByteArray::from(hex!("0011223344556677")); let actual_bytes = UintEx::from_be_byte_array(expected_bytes).to_be_byte_array(); assert_eq!(expected_bytes, actual_bytes); } #[test] #[cfg(target_pointer_width = "64")] fn to_be_byte_array() { let expected_bytes = ByteArray::from(hex!("00112233445566778899aabbccddeeff")); let actual_bytes = UintEx::from_be_byte_array(expected_bytes).to_be_byte_array(); assert_eq!(expected_bytes, actual_bytes); } #[test] #[cfg(target_pointer_width = "32")] fn to_le_byte_array() { let expected_bytes = ByteArray::from(hex!("7766554433221100")); let actual_bytes = UintEx::from_le_byte_array(expected_bytes).to_le_byte_array(); assert_eq!(expected_bytes, actual_bytes); } #[test] #[cfg(target_pointer_width = "64")] fn to_le_byte_array() { let expected_bytes = ByteArray::from(hex!("ffeeddccbbaa99887766554433221100")); let actual_bytes = UintEx::from_le_byte_array(expected_bytes).to_le_byte_array(); assert_eq!(expected_bytes, actual_bytes); } #[test] #[cfg(target_pointer_width = "32")] fn into_uint_be() { let expected_bytes = ByteArray::from(hex!("0011223344556677")); let actual_bytes = expected_bytes.into_uint_be().to_be_byte_array(); assert_eq!(expected_bytes, actual_bytes); } #[test] #[cfg(target_pointer_width = "64")] fn into_uint_be() { let expected_bytes = ByteArray::from(hex!("00112233445566778899aabbccddeeff")); let actual_bytes = expected_bytes.into_uint_be().to_be_byte_array(); assert_eq!(expected_bytes, actual_bytes); } #[test] #[cfg(target_pointer_width = "32")] fn into_uint_le() { let expected_bytes = ByteArray::from(hex!("7766554433221100")); let actual_bytes = expected_bytes.into_uint_le().to_le_byte_array(); assert_eq!(expected_bytes, actual_bytes); } #[test] #[cfg(target_pointer_width = "64")] fn into_uint_le() { let expected_bytes = ByteArray::from(hex!("ffeeddccbbaa99887766554433221100")); let actual_bytes = expected_bytes.into_uint_le().to_le_byte_array(); assert_eq!(expected_bytes, actual_bytes); } } crypto-bigint-0.5.2/src/uint/bit_and.rs000064400000000000000000000074611046102023000161460ustar 00000000000000//! [`Uint`] bitwise and operations. use super::Uint; use crate::{Limb, Wrapping}; use core::ops::{BitAnd, BitAndAssign}; use subtle::{Choice, CtOption}; impl Uint { /// Computes bitwise `a & b`. #[inline(always)] pub const fn bitand(&self, rhs: &Self) -> Self { let mut limbs = [Limb::ZERO; LIMBS]; let mut i = 0; while i < LIMBS { limbs[i] = self.limbs[i].bitand(rhs.limbs[i]); i += 1; } Self { limbs } } /// Perform wrapping bitwise `AND`. /// /// There's no way wrapping could ever happen. /// This function exists so that all operations are accounted for in the wrapping operations pub const fn wrapping_and(&self, rhs: &Self) -> Self { self.bitand(rhs) } /// Perform checked bitwise `AND`, returning a [`CtOption`] which `is_some` always pub fn checked_and(&self, rhs: &Self) -> CtOption { let result = self.bitand(rhs); CtOption::new(result, Choice::from(1)) } } impl BitAnd for Uint { type Output = Self; fn bitand(self, rhs: Self) -> Uint { self.bitand(&rhs) } } impl BitAnd<&Uint> for Uint { type Output = Uint; #[allow(clippy::needless_borrow)] fn bitand(self, rhs: &Uint) -> Uint { (&self).bitand(rhs) } } impl BitAnd> for &Uint { type Output = Uint; fn bitand(self, rhs: Uint) -> Uint { self.bitand(&rhs) } } impl BitAnd<&Uint> for &Uint { type Output = Uint; fn bitand(self, rhs: &Uint) -> Uint { self.bitand(rhs) } } impl BitAndAssign for Uint { #[allow(clippy::assign_op_pattern)] fn bitand_assign(&mut self, other: Self) { *self = *self & other; } } impl BitAndAssign<&Uint> for Uint { #[allow(clippy::assign_op_pattern)] fn bitand_assign(&mut self, other: &Self) { *self = *self & other; } } impl BitAnd for Wrapping> { type Output = Self; fn bitand(self, rhs: Self) -> Wrapping> { Wrapping(self.0.bitand(&rhs.0)) } } impl BitAnd<&Wrapping>> for Wrapping> { type Output = Wrapping>; fn bitand(self, rhs: &Wrapping>) -> Wrapping> { Wrapping(self.0.bitand(&rhs.0)) } } impl BitAnd>> for &Wrapping> { type Output = Wrapping>; fn bitand(self, rhs: Wrapping>) -> Wrapping> { Wrapping(self.0.bitand(&rhs.0)) } } impl BitAnd<&Wrapping>> for &Wrapping> { type Output = Wrapping>; fn bitand(self, rhs: &Wrapping>) -> Wrapping> { Wrapping(self.0.bitand(&rhs.0)) } } impl BitAndAssign for Wrapping> { #[allow(clippy::assign_op_pattern)] fn bitand_assign(&mut self, other: Self) { *self = *self & other; } } impl BitAndAssign<&Wrapping>> for Wrapping> { #[allow(clippy::assign_op_pattern)] fn bitand_assign(&mut self, other: &Self) { *self = *self & other; } } #[cfg(test)] mod tests { use crate::U128; #[test] fn checked_and_ok() { let result = U128::ZERO.checked_and(&U128::ONE); assert_eq!(result.unwrap(), U128::ZERO); } #[test] fn overlapping_and_ok() { let result = U128::MAX.wrapping_and(&U128::ONE); assert_eq!(result, U128::ONE); } } crypto-bigint-0.5.2/src/uint/bit_not.rs000064400000000000000000000017161046102023000162010ustar 00000000000000//! [`Uint`] bitwise not operations. use super::Uint; use crate::{Limb, Wrapping}; use core::ops::Not; impl Uint { /// Computes bitwise `!a`. #[inline(always)] pub const fn not(&self) -> Self { let mut limbs = [Limb::ZERO; LIMBS]; let mut i = 0; while i < LIMBS { limbs[i] = self.limbs[i].not(); i += 1; } Self { limbs } } } impl Not for Uint { type Output = Self; #[allow(clippy::needless_borrow)] fn not(self) -> ::Output { (&self).not() } } impl Not for Wrapping> { type Output = Self; fn not(self) -> ::Output { Wrapping(self.0.not()) } } #[cfg(test)] mod tests { use crate::U128; #[test] fn bitnot_ok() { assert_eq!(U128::ZERO.not(), U128::MAX); assert_eq!(U128::MAX.not(), U128::ZERO); } } crypto-bigint-0.5.2/src/uint/bit_or.rs000064400000000000000000000071411046102023000160170ustar 00000000000000//! [`Uint`] bitwise or operations. use super::Uint; use crate::{Limb, Wrapping}; use core::ops::{BitOr, BitOrAssign}; use subtle::{Choice, CtOption}; impl Uint { /// Computes bitwise `a & b`. #[inline(always)] pub const fn bitor(&self, rhs: &Self) -> Self { let mut limbs = [Limb::ZERO; LIMBS]; let mut i = 0; while i < LIMBS { limbs[i] = self.limbs[i].bitor(rhs.limbs[i]); i += 1; } Self { limbs } } /// Perform wrapping bitwise `OR`. /// /// There's no way wrapping could ever happen. /// This function exists so that all operations are accounted for in the wrapping operations pub const fn wrapping_or(&self, rhs: &Self) -> Self { self.bitor(rhs) } /// Perform checked bitwise `OR`, returning a [`CtOption`] which `is_some` always pub fn checked_or(&self, rhs: &Self) -> CtOption { let result = self.bitor(rhs); CtOption::new(result, Choice::from(1)) } } impl BitOr for Uint { type Output = Self; fn bitor(self, rhs: Self) -> Uint { self.bitor(&rhs) } } impl BitOr<&Uint> for Uint { type Output = Uint; #[allow(clippy::needless_borrow)] fn bitor(self, rhs: &Uint) -> Uint { (&self).bitor(rhs) } } impl BitOr> for &Uint { type Output = Uint; fn bitor(self, rhs: Uint) -> Uint { self.bitor(&rhs) } } impl BitOr<&Uint> for &Uint { type Output = Uint; fn bitor(self, rhs: &Uint) -> Uint { self.bitor(rhs) } } impl BitOrAssign for Uint { fn bitor_assign(&mut self, other: Self) { *self = *self | other; } } impl BitOrAssign<&Uint> for Uint { fn bitor_assign(&mut self, other: &Self) { *self = *self | other; } } impl BitOr for Wrapping> { type Output = Self; fn bitor(self, rhs: Self) -> Wrapping> { Wrapping(self.0.bitor(&rhs.0)) } } impl BitOr<&Wrapping>> for Wrapping> { type Output = Wrapping>; fn bitor(self, rhs: &Wrapping>) -> Wrapping> { Wrapping(self.0.bitor(&rhs.0)) } } impl BitOr>> for &Wrapping> { type Output = Wrapping>; fn bitor(self, rhs: Wrapping>) -> Wrapping> { Wrapping(self.0.bitor(&rhs.0)) } } impl BitOr<&Wrapping>> for &Wrapping> { type Output = Wrapping>; fn bitor(self, rhs: &Wrapping>) -> Wrapping> { Wrapping(self.0.bitor(&rhs.0)) } } impl BitOrAssign for Wrapping> { fn bitor_assign(&mut self, other: Self) { *self = *self | other; } } impl BitOrAssign<&Wrapping>> for Wrapping> { fn bitor_assign(&mut self, other: &Self) { *self = *self | other; } } #[cfg(test)] mod tests { use crate::U128; #[test] fn checked_or_ok() { let result = U128::ZERO.checked_or(&U128::ONE); assert_eq!(result.unwrap(), U128::ONE); } #[test] fn overlapping_or_ok() { let result = U128::MAX.wrapping_or(&U128::ONE); assert_eq!(result, U128::MAX); } } crypto-bigint-0.5.2/src/uint/bit_xor.rs000064400000000000000000000072221046102023000162070ustar 00000000000000//! [`Uint`] bitwise xor operations. use super::Uint; use crate::{Limb, Wrapping}; use core::ops::{BitXor, BitXorAssign}; use subtle::{Choice, CtOption}; impl Uint { /// Computes bitwise `a ^ b`. #[inline(always)] pub const fn bitxor(&self, rhs: &Self) -> Self { let mut limbs = [Limb::ZERO; LIMBS]; let mut i = 0; while i < LIMBS { limbs[i] = self.limbs[i].bitxor(rhs.limbs[i]); i += 1; } Self { limbs } } /// Perform wrapping bitwise `XOR``. /// /// There's no way wrapping could ever happen. /// This function exists so that all operations are accounted for in the wrapping operations pub const fn wrapping_xor(&self, rhs: &Self) -> Self { self.bitxor(rhs) } /// Perform checked bitwise `XOR`, returning a [`CtOption`] which `is_some` always pub fn checked_xor(&self, rhs: &Self) -> CtOption { let result = self.bitxor(rhs); CtOption::new(result, Choice::from(1)) } } impl BitXor for Uint { type Output = Self; fn bitxor(self, rhs: Self) -> Uint { self.bitxor(&rhs) } } impl BitXor<&Uint> for Uint { type Output = Uint; #[allow(clippy::needless_borrow)] fn bitxor(self, rhs: &Uint) -> Uint { (&self).bitxor(rhs) } } impl BitXor> for &Uint { type Output = Uint; fn bitxor(self, rhs: Uint) -> Uint { self.bitxor(&rhs) } } impl BitXor<&Uint> for &Uint { type Output = Uint; fn bitxor(self, rhs: &Uint) -> Uint { self.bitxor(rhs) } } impl BitXorAssign for Uint { fn bitxor_assign(&mut self, other: Self) { *self = *self ^ other; } } impl BitXorAssign<&Uint> for Uint { fn bitxor_assign(&mut self, other: &Self) { *self = *self ^ other; } } impl BitXor for Wrapping> { type Output = Self; fn bitxor(self, rhs: Self) -> Wrapping> { Wrapping(self.0.bitxor(&rhs.0)) } } impl BitXor<&Wrapping>> for Wrapping> { type Output = Wrapping>; fn bitxor(self, rhs: &Wrapping>) -> Wrapping> { Wrapping(self.0.bitxor(&rhs.0)) } } impl BitXor>> for &Wrapping> { type Output = Wrapping>; fn bitxor(self, rhs: Wrapping>) -> Wrapping> { Wrapping(self.0.bitxor(&rhs.0)) } } impl BitXor<&Wrapping>> for &Wrapping> { type Output = Wrapping>; fn bitxor(self, rhs: &Wrapping>) -> Wrapping> { Wrapping(self.0.bitxor(&rhs.0)) } } impl BitXorAssign for Wrapping> { fn bitxor_assign(&mut self, other: Self) { *self = *self ^ other; } } impl BitXorAssign<&Wrapping>> for Wrapping> { fn bitxor_assign(&mut self, other: &Self) { *self = *self ^ other; } } #[cfg(test)] mod tests { use crate::U128; #[test] fn checked_xor_ok() { let result = U128::ZERO.checked_xor(&U128::ONE); assert_eq!(result.unwrap(), U128::ONE); } #[test] fn overlapping_xor_ok() { let result = U128::ZERO.wrapping_xor(&U128::ONE); assert_eq!(result, U128::ONE); } } crypto-bigint-0.5.2/src/uint/bits.rs000064400000000000000000000117261046102023000155060ustar 00000000000000use crate::{CtChoice, Limb, Uint, Word}; impl Uint { /// Returns `true` if the bit at position `index` is set, `false` otherwise. #[inline(always)] pub const fn bit_vartime(self, index: usize) -> bool { if index >= Self::BITS { false } else { (self.limbs[index / Limb::BITS].0 >> (index % Limb::BITS)) & 1 == 1 } } /// Calculate the number of bits needed to represent this number. #[allow(trivial_numeric_casts)] pub const fn bits_vartime(self) -> usize { let mut i = LIMBS - 1; while i > 0 && self.limbs[i].0 == 0 { i -= 1; } let limb = self.limbs[i].0; Limb::BITS * (i + 1) - limb.leading_zeros() as usize } /// Calculate the number of leading zeros in the binary representation of this number. pub const fn leading_zeros(self) -> usize { let limbs = self.as_limbs(); let mut count: Word = 0; let mut i = LIMBS; let mut nonzero_limb_not_encountered = CtChoice::TRUE; while i > 0 { i -= 1; let l = limbs[i]; let z = l.leading_zeros() as Word; count += nonzero_limb_not_encountered.if_true(z); nonzero_limb_not_encountered = nonzero_limb_not_encountered.and(l.ct_is_nonzero().not()); } count as usize } /// Calculate the number of trailing zeros in the binary representation of this number. pub const fn trailing_zeros(self) -> usize { let limbs = self.as_limbs(); let mut count: Word = 0; let mut i = 0; let mut nonzero_limb_not_encountered = CtChoice::TRUE; while i < LIMBS { let l = limbs[i]; let z = l.trailing_zeros() as Word; count += nonzero_limb_not_encountered.if_true(z); nonzero_limb_not_encountered = nonzero_limb_not_encountered.and(l.ct_is_nonzero().not()); i += 1; } count as usize } /// Calculate the number of bits needed to represent this number. pub const fn bits(self) -> usize { Self::BITS - self.leading_zeros() } /// Get the value of the bit at position `index`, as a truthy or falsy `CtChoice`. /// Returns the falsy value for indices out of range. pub const fn bit(self, index: usize) -> CtChoice { let limb_num = Limb((index / Limb::BITS) as Word); let index_in_limb = index % Limb::BITS; let index_mask = 1 << index_in_limb; let limbs = self.as_words(); let mut result: Word = 0; let mut i = 0; while i < LIMBS { let bit = limbs[i] & index_mask; let is_right_limb = Limb::ct_eq(limb_num, Limb(i as Word)); result |= is_right_limb.if_true(bit); i += 1; } CtChoice::from_lsb(result >> index_in_limb) } } #[cfg(test)] mod tests { use crate::U256; fn uint_with_bits_at(positions: &[usize]) -> U256 { let mut result = U256::ZERO; for pos in positions { result |= U256::ONE << *pos; } result } #[test] fn bit_vartime() { let u = uint_with_bits_at(&[16, 48, 112, 127, 255]); assert!(!u.bit_vartime(0)); assert!(!u.bit_vartime(1)); assert!(u.bit_vartime(16)); assert!(u.bit_vartime(127)); assert!(u.bit_vartime(255)); assert!(!u.bit_vartime(256)); assert!(!u.bit_vartime(260)); } #[test] fn bit() { let u = uint_with_bits_at(&[16, 48, 112, 127, 255]); assert!(!u.bit(0).is_true_vartime()); assert!(!u.bit(1).is_true_vartime()); assert!(u.bit(16).is_true_vartime()); assert!(u.bit(127).is_true_vartime()); assert!(u.bit(255).is_true_vartime()); assert!(!u.bit(256).is_true_vartime()); assert!(!u.bit(260).is_true_vartime()); } #[test] fn leading_zeros() { let u = uint_with_bits_at(&[256 - 16, 256 - 79, 256 - 207]); assert_eq!(u.leading_zeros() as u32, 15); let u = uint_with_bits_at(&[256 - 79, 256 - 207]); assert_eq!(u.leading_zeros() as u32, 78); let u = uint_with_bits_at(&[256 - 207]); assert_eq!(u.leading_zeros() as u32, 206); let u = uint_with_bits_at(&[256 - 1, 256 - 75, 256 - 150]); assert_eq!(u.leading_zeros() as u32, 0); let u = U256::ZERO; assert_eq!(u.leading_zeros() as u32, 256); } #[test] fn trailing_zeros() { let u = uint_with_bits_at(&[16, 79, 150]); assert_eq!(u.trailing_zeros() as u32, 16); let u = uint_with_bits_at(&[79, 150]); assert_eq!(u.trailing_zeros() as u32, 79); let u = uint_with_bits_at(&[150, 207]); assert_eq!(u.trailing_zeros() as u32, 150); let u = uint_with_bits_at(&[0, 150, 207]); assert_eq!(u.trailing_zeros() as u32, 0); let u = U256::ZERO; assert_eq!(u.trailing_zeros() as u32, 256); } } crypto-bigint-0.5.2/src/uint/cmp.rs000064400000000000000000000126461046102023000153260ustar 00000000000000//! [`Uint`] comparisons. //! //! By default these are all constant-time and use the `subtle` crate. use super::Uint; use crate::{CtChoice, Limb}; use core::cmp::Ordering; use subtle::{Choice, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess}; impl Uint { /// Return `b` if `c` is truthy, otherwise return `a`. #[inline] pub(crate) const fn ct_select(a: &Self, b: &Self, c: CtChoice) -> Self { let mut limbs = [Limb::ZERO; LIMBS]; let mut i = 0; while i < LIMBS { limbs[i] = Limb::ct_select(a.limbs[i], b.limbs[i], c); i += 1; } Uint { limbs } } #[inline] pub(crate) const fn ct_swap(a: &Self, b: &Self, c: CtChoice) -> (Self, Self) { let new_a = Self::ct_select(a, b, c); let new_b = Self::ct_select(b, a, c); (new_a, new_b) } /// Returns the truthy value if `self`!=0 or the falsy value otherwise. #[inline] pub(crate) const fn ct_is_nonzero(&self) -> CtChoice { let mut b = 0; let mut i = 0; while i < LIMBS { b |= self.limbs[i].0; i += 1; } Limb(b).ct_is_nonzero() } /// Returns the truthy value if `self` is odd or the falsy value otherwise. pub(crate) const fn ct_is_odd(&self) -> CtChoice { CtChoice::from_lsb(self.limbs[0].0 & 1) } /// Returns the truthy value if `self == rhs` or the falsy value otherwise. #[inline] pub(crate) const fn ct_eq(lhs: &Self, rhs: &Self) -> CtChoice { let mut acc = 0; let mut i = 0; while i < LIMBS { acc |= lhs.limbs[i].0 ^ rhs.limbs[i].0; i += 1; } // acc == 0 if and only if self == rhs Limb(acc).ct_is_nonzero().not() } /// Returns the truthy value if `self <= rhs` and the falsy value otherwise. #[inline] pub(crate) const fn ct_lt(lhs: &Self, rhs: &Self) -> CtChoice { // We could use the same approach as in Limb::ct_lt(), // but since we have to use Uint::wrapping_sub(), which calls `sbb()`, // there are no savings compared to just calling `sbb()` directly. let (_res, borrow) = lhs.sbb(rhs, Limb::ZERO); CtChoice::from_mask(borrow.0) } /// Returns the truthy value if `self <= rhs` and the falsy value otherwise. #[inline] pub(crate) const fn ct_gt(lhs: &Self, rhs: &Self) -> CtChoice { let (_res, borrow) = rhs.sbb(lhs, Limb::ZERO); CtChoice::from_mask(borrow.0) } } impl ConstantTimeEq for Uint { #[inline] fn ct_eq(&self, other: &Self) -> Choice { Uint::ct_eq(self, other).into() } } impl ConstantTimeGreater for Uint { #[inline] fn ct_gt(&self, other: &Self) -> Choice { Uint::ct_gt(self, other).into() } } impl ConstantTimeLess for Uint { #[inline] fn ct_lt(&self, other: &Self) -> Choice { Uint::ct_lt(self, other).into() } } impl Eq for Uint {} impl Ord for Uint { fn cmp(&self, other: &Self) -> Ordering { let is_lt = self.ct_lt(other); let is_eq = self.ct_eq(other); if is_lt.into() { Ordering::Less } else if is_eq.into() { Ordering::Equal } else { Ordering::Greater } } } impl PartialOrd for Uint { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl PartialEq for Uint { fn eq(&self, other: &Self) -> bool { self.ct_eq(other).into() } } #[cfg(test)] mod tests { use crate::{Integer, Zero, U128}; use subtle::{ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess}; #[test] fn is_zero() { assert!(bool::from(U128::ZERO.is_zero())); assert!(!bool::from(U128::ONE.is_zero())); assert!(!bool::from(U128::MAX.is_zero())); } #[test] fn is_odd() { assert!(!bool::from(U128::ZERO.is_odd())); assert!(bool::from(U128::ONE.is_odd())); assert!(bool::from(U128::MAX.is_odd())); } #[test] fn ct_eq() { let a = U128::ZERO; let b = U128::MAX; assert!(bool::from(a.ct_eq(&a))); assert!(!bool::from(a.ct_eq(&b))); assert!(!bool::from(b.ct_eq(&a))); assert!(bool::from(b.ct_eq(&b))); } #[test] fn ct_gt() { let a = U128::ZERO; let b = U128::ONE; let c = U128::MAX; assert!(bool::from(b.ct_gt(&a))); assert!(bool::from(c.ct_gt(&a))); assert!(bool::from(c.ct_gt(&b))); assert!(!bool::from(a.ct_gt(&a))); assert!(!bool::from(b.ct_gt(&b))); assert!(!bool::from(c.ct_gt(&c))); assert!(!bool::from(a.ct_gt(&b))); assert!(!bool::from(a.ct_gt(&c))); assert!(!bool::from(b.ct_gt(&c))); } #[test] fn ct_lt() { let a = U128::ZERO; let b = U128::ONE; let c = U128::MAX; assert!(bool::from(a.ct_lt(&b))); assert!(bool::from(a.ct_lt(&c))); assert!(bool::from(b.ct_lt(&c))); assert!(!bool::from(a.ct_lt(&a))); assert!(!bool::from(b.ct_lt(&b))); assert!(!bool::from(c.ct_lt(&c))); assert!(!bool::from(b.ct_lt(&a))); assert!(!bool::from(c.ct_lt(&a))); assert!(!bool::from(c.ct_lt(&b))); } } crypto-bigint-0.5.2/src/uint/concat.rs000064400000000000000000000037751046102023000160210ustar 00000000000000// TODO(tarcieri): use `const_evaluatable_checked` when stable to make generic around bits. macro_rules! impl_concat { ($(($name:ident, $bits:expr)),+) => { $( impl $name { /// Concatenate the two values, with `self` as most significant and `rhs` /// as the least significant. pub const fn concat(&self, rhs: &Self) -> Uint<{nlimbs!($bits) * 2}> { let mut limbs = [Limb::ZERO; nlimbs!($bits) * 2]; let mut i = 0; let mut j = 0; while j < nlimbs!($bits) { limbs[i] = rhs.limbs[j]; i += 1; j += 1; } j = 0; while j < nlimbs!($bits) { limbs[i] = self.limbs[j]; i += 1; j += 1; } Uint { limbs } } } impl Concat for $name { type Output = Uint<{nlimbs!($bits) * 2}>; fn concat(&self, rhs: &Self) -> Self::Output { self.concat(rhs) } } impl From<($name, $name)> for Uint<{nlimbs!($bits) * 2}> { fn from(nums: ($name, $name)) -> Uint<{nlimbs!($bits) * 2}> { nums.1.concat(&nums.0) } } )+ }; } #[cfg(test)] mod tests { use crate::{U128, U64}; #[test] fn concat() { let hi = U64::from_u64(0x0011223344556677); let lo = U64::from_u64(0x8899aabbccddeeff); assert_eq!( hi.concat(&lo), U128::from_be_hex("00112233445566778899aabbccddeeff") ); } #[test] fn convert() { let res: U128 = U64::ONE.mul_wide(&U64::ONE).into(); assert_eq!(res, U128::ONE); let res: U128 = U64::ONE.square_wide().into(); assert_eq!(res, U128::ONE); } } crypto-bigint-0.5.2/src/uint/div.rs000064400000000000000000000534201046102023000153240ustar 00000000000000//! [`Uint`] division operations. use super::div_limb::{div_rem_limb_with_reciprocal, Reciprocal}; use crate::{CtChoice, Limb, NonZero, Uint, Word, Wrapping}; use core::ops::{Div, DivAssign, Rem, RemAssign}; use subtle::CtOption; impl Uint { /// Computes `self` / `rhs` using a pre-made reciprocal, /// returns the quotient (q) and remainder (r). #[inline(always)] pub const fn ct_div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) { div_rem_limb_with_reciprocal(self, reciprocal) } /// Computes `self` / `rhs` using a pre-made reciprocal, /// returns the quotient (q) and remainder (r). #[inline(always)] pub fn div_rem_limb_with_reciprocal( &self, reciprocal: &CtOption, ) -> CtOption<(Self, Limb)> { reciprocal.map(|r| div_rem_limb_with_reciprocal(self, &r)) } /// Computes `self` / `rhs`, returns the quotient (q) and remainder (r). /// Returns the truthy value as the third element of the tuple if `rhs != 0`, /// and the falsy value otherwise. #[inline(always)] pub(crate) const fn ct_div_rem_limb(&self, rhs: Limb) -> (Self, Limb, CtChoice) { let (reciprocal, is_some) = Reciprocal::ct_new(rhs); let (quo, rem) = div_rem_limb_with_reciprocal(self, &reciprocal); (quo, rem, is_some) } /// Computes `self` / `rhs`, returns the quotient (q) and remainder (r). #[inline(always)] pub fn div_rem_limb(&self, rhs: NonZero) -> (Self, Limb) { // Guaranteed to succeed since `rhs` is nonzero. let (quo, rem, _is_some) = self.ct_div_rem_limb(*rhs); (quo, rem) } /// Computes `self` / `rhs`, returns the quotient (q), remainder (r) /// and the truthy value for is_some or the falsy value for is_none. /// /// NOTE: Use only if you need to access const fn. Otherwise use [`Self::div_rem`] because /// the value for is_some needs to be checked before using `q` and `r`. /// /// This is variable only with respect to `rhs`. /// /// When used with a fixed `rhs`, this function is constant-time with respect /// to `self`. pub(crate) const fn ct_div_rem(&self, rhs: &Self) -> (Self, Self, CtChoice) { let mb = rhs.bits_vartime(); let mut bd = Self::BITS - mb; let mut rem = *self; let mut quo = Self::ZERO; let mut c = rhs.shl_vartime(bd); loop { let (mut r, borrow) = rem.sbb(&c, Limb::ZERO); rem = Self::ct_select(&r, &rem, CtChoice::from_mask(borrow.0)); r = quo.bitor(&Self::ONE); quo = Self::ct_select(&r, &quo, CtChoice::from_mask(borrow.0)); if bd == 0 { break; } bd -= 1; c = c.shr_vartime(1); quo = quo.shl_vartime(1); } let is_some = Limb(mb as Word).ct_is_nonzero(); quo = Self::ct_select(&Self::ZERO, &quo, is_some); (quo, rem, is_some) } /// Computes `self` % `rhs`, returns the remainder and /// and the truthy value for is_some or the falsy value for is_none. /// /// NOTE: Use only if you need to access const fn. Otherwise use [`Self::rem`]. /// This is variable only with respect to `rhs`. /// /// When used with a fixed `rhs`, this function is constant-time with respect /// to `self`. pub const fn const_rem(&self, rhs: &Self) -> (Self, CtChoice) { let mb = rhs.bits_vartime(); let mut bd = Self::BITS - mb; let mut rem = *self; let mut c = rhs.shl_vartime(bd); loop { let (r, borrow) = rem.sbb(&c, Limb::ZERO); rem = Self::ct_select(&r, &rem, CtChoice::from_mask(borrow.0)); if bd == 0 { break; } bd -= 1; c = c.shr_vartime(1); } let is_some = Limb(mb as Word).ct_is_nonzero(); (rem, is_some) } /// Computes `self` % `rhs`, returns the remainder and /// and the truthy value for is_some or the falsy value for is_none. /// /// This is variable only with respect to `rhs`. /// /// When used with a fixed `rhs`, this function is constant-time with respect /// to `self`. pub const fn const_rem_wide(lower_upper: (Self, Self), rhs: &Self) -> (Self, CtChoice) { let mb = rhs.bits_vartime(); // The number of bits to consider is two sets of limbs * BITS - mb (modulus bitcount) let mut bd = (2 * Self::BITS) - mb; // The wide integer to reduce, split into two halves let (mut lower, mut upper) = lower_upper; // Factor of the modulus, split into two halves let mut c = Self::shl_vartime_wide((*rhs, Uint::ZERO), bd); loop { let (lower_sub, borrow) = lower.sbb(&c.0, Limb::ZERO); let (upper_sub, borrow) = upper.sbb(&c.1, borrow); lower = Self::ct_select(&lower_sub, &lower, CtChoice::from_mask(borrow.0)); upper = Self::ct_select(&upper_sub, &upper, CtChoice::from_mask(borrow.0)); if bd == 0 { break; } bd -= 1; c = Self::shr_vartime_wide(c, 1); } let is_some = Limb(mb as Word).ct_is_nonzero(); (lower, is_some) } /// Computes `self` % 2^k. Faster than reduce since its a power of 2. /// Limited to 2^16-1 since Uint doesn't support higher. pub const fn rem2k(&self, k: usize) -> Self { let highest = (LIMBS - 1) as u32; let index = k as u32 / (Limb::BITS as u32); let le = Limb::ct_le(Limb::from_u32(index), Limb::from_u32(highest)); let word = Limb::ct_select(Limb::from_u32(highest), Limb::from_u32(index), le).0 as usize; let base = k % Limb::BITS; let mask = (1 << base) - 1; let mut out = *self; let outmask = Limb(out.limbs[word].0 & mask); out.limbs[word] = Limb::ct_select(out.limbs[word], outmask, le); let mut i = word + 1; while i < LIMBS { out.limbs[i] = Limb::ZERO; i += 1; } out } /// Computes self / rhs, returns the quotient, remainder. pub fn div_rem(&self, rhs: &NonZero) -> (Self, Self) { // Since `rhs` is nonzero, this should always hold. let (q, r, _c) = self.ct_div_rem(rhs); (q, r) } /// Computes self % rhs, returns the remainder. pub fn rem(&self, rhs: &NonZero) -> Self { // Since `rhs` is nonzero, this should always hold. let (r, _c) = self.const_rem(rhs); r } /// Wrapped division is just normal division i.e. `self` / `rhs` /// There’s no way wrapping could ever happen. /// This function exists, so that all operations are accounted for in the wrapping operations. /// /// Panics if `rhs == 0`. pub const fn wrapping_div(&self, rhs: &Self) -> Self { let (q, _, c) = self.ct_div_rem(rhs); assert!(c.is_true_vartime(), "divide by zero"); q } /// Perform checked division, returning a [`CtOption`] which `is_some` /// only if the rhs != 0 pub fn checked_div(&self, rhs: &Self) -> CtOption { NonZero::new(*rhs).map(|rhs| { let (q, _r) = self.div_rem(&rhs); q }) } /// Wrapped (modular) remainder calculation is just `self` % `rhs`. /// There’s no way wrapping could ever happen. /// This function exists, so that all operations are accounted for in the wrapping operations. /// /// Panics if `rhs == 0`. pub const fn wrapping_rem(&self, rhs: &Self) -> Self { let (r, c) = self.const_rem(rhs); assert!(c.is_true_vartime(), "modulo zero"); r } /// Perform checked reduction, returning a [`CtOption`] which `is_some` /// only if the rhs != 0 pub fn checked_rem(&self, rhs: &Self) -> CtOption { NonZero::new(*rhs).map(|rhs| self.rem(&rhs)) } } // // Division by a single limb // impl Div<&NonZero> for &Uint { type Output = Uint; fn div(self, rhs: &NonZero) -> Self::Output { *self / *rhs } } impl Div<&NonZero> for Uint { type Output = Uint; fn div(self, rhs: &NonZero) -> Self::Output { self / *rhs } } impl Div> for &Uint { type Output = Uint; fn div(self, rhs: NonZero) -> Self::Output { *self / rhs } } impl Div> for Uint { type Output = Uint; fn div(self, rhs: NonZero) -> Self::Output { let (q, _, _) = self.ct_div_rem_limb(*rhs); q } } impl DivAssign<&NonZero> for Uint { fn div_assign(&mut self, rhs: &NonZero) { *self /= *rhs; } } impl DivAssign> for Uint { fn div_assign(&mut self, rhs: NonZero) { *self = *self / rhs; } } impl Div> for Wrapping> { type Output = Wrapping>; fn div(self, rhs: NonZero) -> Self::Output { Wrapping(self.0 / rhs) } } impl Div> for &Wrapping> { type Output = Wrapping>; fn div(self, rhs: NonZero) -> Self::Output { *self / rhs } } impl Div<&NonZero> for &Wrapping> { type Output = Wrapping>; fn div(self, rhs: &NonZero) -> Self::Output { *self / *rhs } } impl Div<&NonZero> for Wrapping> { type Output = Wrapping>; fn div(self, rhs: &NonZero) -> Self::Output { self / *rhs } } impl DivAssign<&NonZero> for Wrapping> { fn div_assign(&mut self, rhs: &NonZero) { *self = Wrapping(self.0 / rhs) } } impl DivAssign> for Wrapping> { fn div_assign(&mut self, rhs: NonZero) { *self /= &rhs; } } impl Rem<&NonZero> for &Uint { type Output = Limb; fn rem(self, rhs: &NonZero) -> Self::Output { *self % *rhs } } impl Rem<&NonZero> for Uint { type Output = Limb; fn rem(self, rhs: &NonZero) -> Self::Output { self % *rhs } } impl Rem> for &Uint { type Output = Limb; fn rem(self, rhs: NonZero) -> Self::Output { *self % rhs } } impl Rem> for Uint { type Output = Limb; fn rem(self, rhs: NonZero) -> Self::Output { let (_, r, _) = self.ct_div_rem_limb(*rhs); r } } impl RemAssign<&NonZero> for Uint { fn rem_assign(&mut self, rhs: &NonZero) { *self = (*self % rhs).into(); } } impl RemAssign> for Uint { fn rem_assign(&mut self, rhs: NonZero) { *self %= &rhs; } } impl Rem> for Wrapping> { type Output = Wrapping; fn rem(self, rhs: NonZero) -> Self::Output { Wrapping(self.0 % rhs) } } impl Rem> for &Wrapping> { type Output = Wrapping; fn rem(self, rhs: NonZero) -> Self::Output { *self % rhs } } impl Rem<&NonZero> for &Wrapping> { type Output = Wrapping; fn rem(self, rhs: &NonZero) -> Self::Output { *self % *rhs } } impl Rem<&NonZero> for Wrapping> { type Output = Wrapping; fn rem(self, rhs: &NonZero) -> Self::Output { self % *rhs } } impl RemAssign> for Wrapping> { fn rem_assign(&mut self, rhs: NonZero) { *self %= &rhs; } } impl RemAssign<&NonZero> for Wrapping> { fn rem_assign(&mut self, rhs: &NonZero) { *self = Wrapping((self.0 % rhs).into()) } } // // Division by an Uint // impl Div<&NonZero>> for &Uint { type Output = Uint; fn div(self, rhs: &NonZero>) -> Self::Output { *self / *rhs } } impl Div<&NonZero>> for Uint { type Output = Uint; fn div(self, rhs: &NonZero>) -> Self::Output { self / *rhs } } impl Div>> for &Uint { type Output = Uint; fn div(self, rhs: NonZero>) -> Self::Output { *self / rhs } } impl Div>> for Uint { type Output = Uint; fn div(self, rhs: NonZero>) -> Self::Output { let (q, _) = self.div_rem(&rhs); q } } impl DivAssign<&NonZero>> for Uint { fn div_assign(&mut self, rhs: &NonZero>) { *self /= *rhs } } impl DivAssign>> for Uint { fn div_assign(&mut self, rhs: NonZero>) { *self = *self / rhs; } } impl Div>> for Wrapping> { type Output = Wrapping>; fn div(self, rhs: NonZero>) -> Self::Output { Wrapping(self.0 / rhs) } } impl Div>> for &Wrapping> { type Output = Wrapping>; fn div(self, rhs: NonZero>) -> Self::Output { *self / rhs } } impl Div<&NonZero>> for &Wrapping> { type Output = Wrapping>; fn div(self, rhs: &NonZero>) -> Self::Output { *self / *rhs } } impl Div<&NonZero>> for Wrapping> { type Output = Wrapping>; fn div(self, rhs: &NonZero>) -> Self::Output { self / *rhs } } impl DivAssign<&NonZero>> for Wrapping> { fn div_assign(&mut self, rhs: &NonZero>) { *self = Wrapping(self.0 / rhs); } } impl DivAssign>> for Wrapping> { fn div_assign(&mut self, rhs: NonZero>) { *self /= &rhs; } } impl Rem<&NonZero>> for &Uint { type Output = Uint; fn rem(self, rhs: &NonZero>) -> Self::Output { *self % *rhs } } impl Rem<&NonZero>> for Uint { type Output = Uint; fn rem(self, rhs: &NonZero>) -> Self::Output { self % *rhs } } impl Rem>> for &Uint { type Output = Uint; fn rem(self, rhs: NonZero>) -> Self::Output { *self % rhs } } impl Rem>> for Uint { type Output = Uint; fn rem(self, rhs: NonZero>) -> Self::Output { Self::rem(&self, &rhs) } } impl RemAssign<&NonZero>> for Uint { fn rem_assign(&mut self, rhs: &NonZero>) { *self %= *rhs } } impl RemAssign>> for Uint { fn rem_assign(&mut self, rhs: NonZero>) { *self = *self % rhs; } } impl Rem>> for Wrapping> { type Output = Wrapping>; fn rem(self, rhs: NonZero>) -> Self::Output { Wrapping(self.0 % rhs) } } impl Rem>> for &Wrapping> { type Output = Wrapping>; fn rem(self, rhs: NonZero>) -> Self::Output { *self % rhs } } impl Rem<&NonZero>> for &Wrapping> { type Output = Wrapping>; fn rem(self, rhs: &NonZero>) -> Self::Output { *self % *rhs } } impl Rem<&NonZero>> for Wrapping> { type Output = Wrapping>; fn rem(self, rhs: &NonZero>) -> Self::Output { self % *rhs } } impl RemAssign>> for Wrapping> { fn rem_assign(&mut self, rhs: NonZero>) { *self %= &rhs; } } impl RemAssign<&NonZero>> for Wrapping> { fn rem_assign(&mut self, rhs: &NonZero>) { *self = Wrapping(self.0 % rhs) } } #[cfg(test)] mod tests { use super::*; use crate::{limb::HI_BIT, Limb, U256}; #[cfg(feature = "rand")] use { crate::{CheckedMul, Random}, rand_chacha::ChaChaRng, rand_core::RngCore, rand_core::SeedableRng, }; #[test] fn div_word() { for (n, d, e, ee) in &[ (200u64, 2u64, 100u64, 0), (100u64, 25u64, 4u64, 0), (100u64, 10u64, 10u64, 0), (1024u64, 8u64, 128u64, 0), (27u64, 13u64, 2u64, 1u64), (26u64, 13u64, 2u64, 0u64), (14u64, 13u64, 1u64, 1u64), (13u64, 13u64, 1u64, 0u64), (12u64, 13u64, 0u64, 12u64), (1u64, 13u64, 0u64, 1u64), ] { let lhs = U256::from(*n); let rhs = U256::from(*d); let (q, r, is_some) = lhs.ct_div_rem(&rhs); assert!(is_some.is_true_vartime()); assert_eq!(U256::from(*e), q); assert_eq!(U256::from(*ee), r); } } #[cfg(feature = "rand")] #[test] fn div() { let mut rng = ChaChaRng::from_seed([7u8; 32]); for _ in 0..25 { let num = U256::random(&mut rng).shr_vartime(128); let den = U256::random(&mut rng).shr_vartime(128); let n = num.checked_mul(&den); if n.is_some().into() { let (q, _, is_some) = n.unwrap().ct_div_rem(&den); assert!(is_some.is_true_vartime()); assert_eq!(q, num); } } } #[test] fn div_max() { let mut a = U256::ZERO; let mut b = U256::ZERO; b.limbs[b.limbs.len() - 1] = Limb(Word::MAX); let q = a.wrapping_div(&b); assert_eq!(q, Uint::ZERO); a.limbs[a.limbs.len() - 1] = Limb(1 << (HI_BIT - 7)); b.limbs[b.limbs.len() - 1] = Limb(0x82 << (HI_BIT - 7)); let q = a.wrapping_div(&b); assert_eq!(q, Uint::ZERO); } #[test] fn div_zero() { let (q, r, is_some) = U256::ONE.ct_div_rem(&U256::ZERO); assert!(!is_some.is_true_vartime()); assert_eq!(q, U256::ZERO); assert_eq!(r, U256::ONE); } #[test] fn div_one() { let (q, r, is_some) = U256::from(10u8).ct_div_rem(&U256::ONE); assert!(is_some.is_true_vartime()); assert_eq!(q, U256::from(10u8)); assert_eq!(r, U256::ZERO); } #[test] fn reduce_one() { let (r, is_some) = U256::from(10u8).const_rem(&U256::ONE); assert!(is_some.is_true_vartime()); assert_eq!(r, U256::ZERO); } #[test] fn reduce_zero() { let u = U256::from(10u8); let (r, is_some) = u.const_rem(&U256::ZERO); assert!(!is_some.is_true_vartime()); assert_eq!(r, u); } #[test] fn reduce_tests() { let (r, is_some) = U256::from(10u8).const_rem(&U256::from(2u8)); assert!(is_some.is_true_vartime()); assert_eq!(r, U256::ZERO); let (r, is_some) = U256::from(10u8).const_rem(&U256::from(3u8)); assert!(is_some.is_true_vartime()); assert_eq!(r, U256::ONE); let (r, is_some) = U256::from(10u8).const_rem(&U256::from(7u8)); assert!(is_some.is_true_vartime()); assert_eq!(r, U256::from(3u8)); } #[test] fn reduce_tests_wide_zero_padded() { let (r, is_some) = U256::const_rem_wide((U256::from(10u8), U256::ZERO), &U256::from(2u8)); assert!(is_some.is_true_vartime()); assert_eq!(r, U256::ZERO); let (r, is_some) = U256::const_rem_wide((U256::from(10u8), U256::ZERO), &U256::from(3u8)); assert!(is_some.is_true_vartime()); assert_eq!(r, U256::ONE); let (r, is_some) = U256::const_rem_wide((U256::from(10u8), U256::ZERO), &U256::from(7u8)); assert!(is_some.is_true_vartime()); assert_eq!(r, U256::from(3u8)); } #[test] fn reduce_max() { let mut a = U256::ZERO; let mut b = U256::ZERO; b.limbs[b.limbs.len() - 1] = Limb(Word::MAX); let r = a.wrapping_rem(&b); assert_eq!(r, Uint::ZERO); a.limbs[a.limbs.len() - 1] = Limb(1 << (HI_BIT - 7)); b.limbs[b.limbs.len() - 1] = Limb(0x82 << (HI_BIT - 7)); let r = a.wrapping_rem(&b); assert_eq!(r, a); } #[cfg(feature = "rand")] #[test] fn rem2krand() { let mut rng = ChaChaRng::from_seed([7u8; 32]); for _ in 0..25 { let num = U256::random(&mut rng); let k = (rng.next_u32() % 256) as usize; let den = U256::ONE.shl_vartime(k); let a = num.rem2k(k); let e = num.wrapping_rem(&den); assert_eq!(a, e); } } #[test] fn rem_trait() { let a = U256::from(10u64); let b = NonZero::new(U256::from(3u64)).unwrap(); let c = U256::from(1u64); assert_eq!(a % b, c); assert_eq!(a % &b, c); assert_eq!(&a % b, c); assert_eq!(&a % &b, c); } } crypto-bigint-0.5.2/src/uint/div_limb.rs000064400000000000000000000254251046102023000163330ustar 00000000000000//! Implementation of constant-time division via reciprocal precomputation, as described in //! "Improved Division by Invariant Integers" by Niels Möller and Torbjorn Granlund //! (DOI: 10.1109/TC.2010.143, ). use subtle::{Choice, ConditionallySelectable, CtOption}; use crate::{CtChoice, Limb, Uint, WideWord, Word}; /// Calculates the reciprocal of the given 32-bit divisor with the highmost bit set. #[cfg(target_pointer_width = "32")] pub const fn reciprocal(d: Word) -> Word { debug_assert!(d >= (1 << (Word::BITS - 1))); let d0 = d & 1; let d10 = d >> 22; let d21 = (d >> 11) + 1; let d31 = (d >> 1) + d0; let v0 = short_div((1 << 24) - (1 << 14) + (1 << 9), 24, d10, 10); let (hi, _lo) = mulhilo(v0 * v0, d21); let v1 = (v0 << 4) - hi - 1; // Checks that the expression for `e` can be simplified in the way we did below. debug_assert!(mulhilo(v1, d31).0 == (1 << 16) - 1); let e = Word::MAX - v1.wrapping_mul(d31) + 1 + (v1 >> 1) * d0; let (hi, _lo) = mulhilo(v1, e); // Note: the paper does not mention a wrapping add here, // but the 64-bit version has it at this stage, and the function panics without it // when calculating a reciprocal for `Word::MAX`. let v2 = (v1 << 15).wrapping_add(hi >> 1); // The paper has `(v2 + 1) * d / 2^32` (there's another 2^32, but it's accounted for later). // If `v2 == 2^32-1` this should give `d`, but we can't achieve this in our wrapping arithmetic. // Hence the `ct_select()`. let x = v2.wrapping_add(1); let (hi, _lo) = mulhilo(x, d); let hi = Limb::ct_select(Limb(d), Limb(hi), Limb(x).ct_is_nonzero()).0; v2.wrapping_sub(hi).wrapping_sub(d) } /// Calculates the reciprocal of the given 64-bit divisor with the highmost bit set. #[cfg(target_pointer_width = "64")] pub const fn reciprocal(d: Word) -> Word { debug_assert!(d >= (1 << (Word::BITS - 1))); let d0 = d & 1; let d9 = d >> 55; let d40 = (d >> 24) + 1; let d63 = (d >> 1) + d0; let v0 = short_div((1 << 19) - 3 * (1 << 8), 19, d9 as u32, 9) as u64; let v1 = (v0 << 11) - ((v0 * v0 * d40) >> 40) - 1; let v2 = (v1 << 13) + ((v1 * ((1 << 60) - v1 * d40)) >> 47); // Checks that the expression for `e` can be simplified in the way we did below. debug_assert!(mulhilo(v2, d63).0 == (1 << 32) - 1); let e = Word::MAX - v2.wrapping_mul(d63) + 1 + (v2 >> 1) * d0; let (hi, _lo) = mulhilo(v2, e); let v3 = (v2 << 31).wrapping_add(hi >> 1); // The paper has `(v3 + 1) * d / 2^64` (there's another 2^64, but it's accounted for later). // If `v3 == 2^64-1` this should give `d`, but we can't achieve this in our wrapping arithmetic. // Hence the `ct_select()`. let x = v3.wrapping_add(1); let (hi, _lo) = mulhilo(x, d); let hi = Limb::ct_select(Limb(d), Limb(hi), Limb(x).ct_is_nonzero()).0; v3.wrapping_sub(hi).wrapping_sub(d) } /// Returns `u32::MAX` if `a < b` and `0` otherwise. #[inline] const fn ct_lt(a: u32, b: u32) -> u32 { let bit = (((!a) & b) | (((!a) | b) & (a.wrapping_sub(b)))) >> (u32::BITS - 1); bit.wrapping_neg() } /// Returns `a` if `c == 0` and `b` if `c == u32::MAX`. #[inline(always)] const fn ct_select(a: u32, b: u32, c: u32) -> u32 { a ^ (c & (a ^ b)) } /// Calculates `dividend / divisor` in constant time, given `dividend` and `divisor` /// along with their maximum bitsizes. #[inline(always)] const fn short_div(dividend: u32, dividend_bits: u32, divisor: u32, divisor_bits: u32) -> u32 { // TODO: this may be sped up even more using the fact that `dividend` is a known constant. // In the paper this is a table lookup, but since we want it to be constant-time, // we have to access all the elements of the table, which is quite large. // So this shift-and-subtract approach is actually faster. // Passing `dividend_bits` and `divisor_bits` because calling `.leading_zeros()` // causes a significant slowdown, and we know those values anyway. let mut dividend = dividend; let mut divisor = divisor << (dividend_bits - divisor_bits); let mut quotient: u32 = 0; let mut i = dividend_bits - divisor_bits + 1; while i > 0 { i -= 1; let bit = ct_lt(dividend, divisor); dividend = ct_select(dividend.wrapping_sub(divisor), dividend, bit); divisor >>= 1; let inv_bit = !bit; quotient |= (inv_bit >> (u32::BITS - 1)) << i; } quotient } /// Multiplies `x` and `y`, returning the most significant /// and the least significant words as `(hi, lo)`. #[inline(always)] const fn mulhilo(x: Word, y: Word) -> (Word, Word) { let res = (x as WideWord) * (y as WideWord); ((res >> Word::BITS) as Word, res as Word) } /// Adds wide numbers represented by pairs of (most significant word, least significant word) /// and returns the result in the same format `(hi, lo)`. #[inline(always)] const fn addhilo(x_hi: Word, x_lo: Word, y_hi: Word, y_lo: Word) -> (Word, Word) { let res = (((x_hi as WideWord) << Word::BITS) | (x_lo as WideWord)) + (((y_hi as WideWord) << Word::BITS) | (y_lo as WideWord)); ((res >> Word::BITS) as Word, res as Word) } /// Calculate the quotient and the remainder of the division of a wide word /// (supplied as high and low words) by `d`, with a precalculated reciprocal `v`. #[inline(always)] const fn div2by1(u1: Word, u0: Word, reciprocal: &Reciprocal) -> (Word, Word) { let d = reciprocal.divisor_normalized; debug_assert!(d >= (1 << (Word::BITS - 1))); debug_assert!(u1 < d); let (q1, q0) = mulhilo(reciprocal.reciprocal, u1); let (q1, q0) = addhilo(q1, q0, u1, u0); let q1 = q1.wrapping_add(1); let r = u0.wrapping_sub(q1.wrapping_mul(d)); let r_gt_q0 = Limb::ct_lt(Limb(q0), Limb(r)); let q1 = Limb::ct_select(Limb(q1), Limb(q1.wrapping_sub(1)), r_gt_q0).0; let r = Limb::ct_select(Limb(r), Limb(r.wrapping_add(d)), r_gt_q0).0; // If this was a normal `if`, we wouldn't need wrapping ops, because there would be no overflow. // But since we calculate both results either way, we have to wrap. // Added an assert to still check the lack of overflow in debug mode. debug_assert!(r < d || q1 < Word::MAX); let r_ge_d = Limb::ct_le(Limb(d), Limb(r)); let q1 = Limb::ct_select(Limb(q1), Limb(q1.wrapping_add(1)), r_ge_d).0; let r = Limb::ct_select(Limb(r), Limb(r.wrapping_sub(d)), r_ge_d).0; (q1, r) } /// A pre-calculated reciprocal for division by a single limb. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Reciprocal { divisor_normalized: Word, shift: u32, reciprocal: Word, } impl Reciprocal { /// Pre-calculates a reciprocal for a known divisor, /// to be used in the single-limb division later. /// Returns the reciprocal, and the truthy value if `divisor != 0` /// and the falsy value otherwise. /// /// Note: if the returned flag is falsy, the returned reciprocal object is still self-consistent /// and can be passed to functions here without causing them to panic, /// but the results are naturally not to be used. pub const fn ct_new(divisor: Limb) -> (Self, CtChoice) { // Assuming this is constant-time for primitive types. let shift = divisor.0.leading_zeros(); #[allow(trivial_numeric_casts)] let is_some = Limb((Word::BITS - shift) as Word).ct_is_nonzero(); // If `divisor = 0`, shifting `divisor` by `leading_zeros == Word::BITS` will cause a panic. // Have to substitute a "bogus" shift in that case. #[allow(trivial_numeric_casts)] let shift_limb = Limb::ct_select(Limb::ZERO, Limb(shift as Word), is_some); // Need to provide bogus normalized divisor and reciprocal too, // so that we don't get a panic in low-level functions. let divisor_normalized = divisor.shl(shift_limb); let divisor_normalized = Limb::ct_select(Limb::MAX, divisor_normalized, is_some).0; #[allow(trivial_numeric_casts)] let shift = shift_limb.0 as u32; ( Self { divisor_normalized, shift, reciprocal: reciprocal(divisor_normalized), }, is_some, ) } /// Returns a default instance of this object. /// It is a self-consistent `Reciprocal` that will not cause panics in functions that take it. /// /// NOTE: intended for using it as a placeholder during compile-time array generation, /// don't rely on the contents. pub const fn default() -> Self { Self { divisor_normalized: Word::MAX, shift: 0, // The result of calling `reciprocal(Word::MAX)` // This holds both for 32- and 64-bit versions. reciprocal: 1, } } /// A non-const-fn version of `new_const()`, wrapping the result in a `CtOption`. pub fn new(divisor: Limb) -> CtOption { let (rec, is_some) = Self::ct_new(divisor); CtOption::new(rec, is_some.into()) } } impl ConditionallySelectable for Reciprocal { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Self { divisor_normalized: Word::conditional_select( &a.divisor_normalized, &b.divisor_normalized, choice, ), shift: u32::conditional_select(&a.shift, &b.shift, choice), reciprocal: Word::conditional_select(&a.reciprocal, &b.reciprocal, choice), } } } // `CtOption.map()` needs this; for some reason it doesn't use the value it already has // for the `None` branch. impl Default for Reciprocal { fn default() -> Self { Self::default() } } /// Divides `u` by the divisor encoded in the `reciprocal`, and returns /// the quotient and the remainder. #[inline(always)] pub(crate) const fn div_rem_limb_with_reciprocal( u: &Uint, reciprocal: &Reciprocal, ) -> (Uint, Limb) { let (u_shifted, u_hi) = u.shl_limb(reciprocal.shift as usize); let mut r = u_hi.0; let mut q = [Limb::ZERO; L]; let mut j = L; while j > 0 { j -= 1; let (qj, rj) = div2by1(r, u_shifted.as_limbs()[j].0, reciprocal); q[j] = Limb(qj); r = rj; } (Uint::::new(q), Limb(r >> reciprocal.shift)) } #[cfg(test)] mod tests { use super::{div2by1, Reciprocal}; use crate::{Limb, Word}; #[test] fn div2by1_overflow() { // A regression test for a situation when in div2by1() an operation (`q1 + 1`) // that is protected from overflowing by a condition in the original paper (`r >= d`) // still overflows because we're calculating the results for both branches. let r = Reciprocal::new(Limb(Word::MAX - 1)).unwrap(); assert_eq!( div2by1(Word::MAX - 2, Word::MAX - 63, &r), (Word::MAX, Word::MAX - 65) ); } } crypto-bigint-0.5.2/src/uint/encoding/der.rs000064400000000000000000000034061046102023000171010ustar 00000000000000//! Support for decoding/encoding [`Uint`] as an ASN.1 DER `INTEGER`. use crate::{generic_array::GenericArray, ArrayEncoding, Uint}; use ::der::{ asn1::{AnyRef, UintRef}, DecodeValue, EncodeValue, FixedTag, Length, Tag, }; impl<'a, const LIMBS: usize> TryFrom> for Uint where Uint: ArrayEncoding, { type Error = der::Error; fn try_from(any: AnyRef<'a>) -> der::Result> { UintRef::try_from(any)?.try_into() } } impl<'a, const LIMBS: usize> TryFrom> for Uint where Uint: ArrayEncoding, { type Error = der::Error; fn try_from(bytes: UintRef<'a>) -> der::Result> { let mut array = GenericArray::default(); let offset = array.len().saturating_sub(bytes.len().try_into()?); array[offset..].copy_from_slice(bytes.as_bytes()); Ok(Uint::from_be_byte_array(array)) } } impl<'a, const LIMBS: usize> DecodeValue<'a> for Uint where Uint: ArrayEncoding, { fn decode_value>(reader: &mut R, header: der::Header) -> der::Result { UintRef::decode_value(reader, header)?.try_into() } } impl EncodeValue for Uint where Uint: ArrayEncoding, { fn value_len(&self) -> der::Result { // TODO(tarcieri): more efficient length calculation let array = self.to_be_byte_array(); UintRef::new(&array)?.value_len() } fn encode_value(&self, encoder: &mut impl der::Writer) -> der::Result<()> { let array = self.to_be_byte_array(); UintRef::new(&array)?.encode_value(encoder) } } impl FixedTag for Uint where Uint: ArrayEncoding, { const TAG: Tag = Tag::Integer; } crypto-bigint-0.5.2/src/uint/encoding/rlp.rs000064400000000000000000000045061046102023000171260ustar 00000000000000//! Recursive Length Prefix (RLP) encoding support. use crate::{Encoding, Uint}; use rlp::{DecoderError, Rlp, RlpStream}; impl rlp::Encodable for Uint where Self: Encoding, { fn rlp_append(&self, stream: &mut RlpStream) { let bytes = self.to_be_bytes(); let mut bytes_stripped = bytes.as_ref(); while bytes_stripped.first().cloned() == Some(0) { bytes_stripped = &bytes_stripped[1..]; } stream.encoder().encode_value(bytes_stripped); } } impl rlp::Decodable for Uint where Self: Encoding, ::Repr: Default, { fn decode(rlp: &Rlp<'_>) -> Result { rlp.decoder().decode_value(|bytes| { if bytes.first().cloned() == Some(0) { Err(rlp::DecoderError::RlpInvalidIndirection) } else { let mut repr = ::Repr::default(); let offset = repr .as_ref() .len() .checked_sub(bytes.len()) .ok_or(DecoderError::RlpIsTooBig)?; repr.as_mut()[offset..].copy_from_slice(bytes); Ok(Self::from_be_bytes(repr)) } }) } } #[cfg(test)] mod tests { use crate::U256; use hex_literal::hex; /// U256 test vectors from the `rlp` crate. /// /// const U256_VECTORS: &[(U256, &[u8])] = &[ (U256::ZERO, &hex!("80")), ( U256::from_be_hex("0000000000000000000000000000000000000000000000000000000001000000"), &hex!("8401000000"), ), ( U256::from_be_hex("00000000000000000000000000000000000000000000000000000000ffffffff"), &hex!("84ffffffff"), ), ( U256::from_be_hex("8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0"), &hex!("a08090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0"), ), ]; #[test] fn round_trip() { for &(uint, expected_bytes) in U256_VECTORS { assert_eq!(rlp::encode(&uint), expected_bytes); assert_eq!(rlp::decode::(expected_bytes).unwrap(), uint); } } } crypto-bigint-0.5.2/src/uint/encoding.rs000064400000000000000000000164671046102023000163420ustar 00000000000000//! Const-friendly decoding operations for [`Uint`] #[cfg(all(feature = "der", feature = "generic-array"))] mod der; #[cfg(feature = "rlp")] mod rlp; use super::Uint; use crate::{Encoding, Limb, Word}; impl Uint { /// Create a new [`Uint`] from the provided big endian bytes. pub const fn from_be_slice(bytes: &[u8]) -> Self { assert!( bytes.len() == Limb::BYTES * LIMBS, "bytes are not the expected size" ); let mut res = [Limb::ZERO; LIMBS]; let mut buf = [0u8; Limb::BYTES]; let mut i = 0; while i < LIMBS { let mut j = 0; while j < Limb::BYTES { buf[j] = bytes[i * Limb::BYTES + j]; j += 1; } res[LIMBS - i - 1] = Limb(Word::from_be_bytes(buf)); i += 1; } Uint::new(res) } /// Create a new [`Uint`] from the provided big endian hex string. pub const fn from_be_hex(hex: &str) -> Self { let bytes = hex.as_bytes(); assert!( bytes.len() == Limb::BYTES * LIMBS * 2, "hex string is not the expected size" ); let mut res = [Limb::ZERO; LIMBS]; let mut buf = [0u8; Limb::BYTES]; let mut i = 0; while i < LIMBS { let mut j = 0; while j < Limb::BYTES { let offset = (i * Limb::BYTES + j) * 2; buf[j] = decode_hex_byte([bytes[offset], bytes[offset + 1]]); j += 1; } res[LIMBS - i - 1] = Limb(Word::from_be_bytes(buf)); i += 1; } Uint::new(res) } /// Create a new [`Uint`] from the provided little endian bytes. pub const fn from_le_slice(bytes: &[u8]) -> Self { assert!( bytes.len() == Limb::BYTES * LIMBS, "bytes are not the expected size" ); let mut res = [Limb::ZERO; LIMBS]; let mut buf = [0u8; Limb::BYTES]; let mut i = 0; while i < LIMBS { let mut j = 0; while j < Limb::BYTES { buf[j] = bytes[i * Limb::BYTES + j]; j += 1; } res[i] = Limb(Word::from_le_bytes(buf)); i += 1; } Uint::new(res) } /// Create a new [`Uint`] from the provided little endian hex string. pub const fn from_le_hex(hex: &str) -> Self { let bytes = hex.as_bytes(); assert!( bytes.len() == Limb::BYTES * LIMBS * 2, "bytes are not the expected size" ); let mut res = [Limb::ZERO; LIMBS]; let mut buf = [0u8; Limb::BYTES]; let mut i = 0; while i < LIMBS { let mut j = 0; while j < Limb::BYTES { let offset = (i * Limb::BYTES + j) * 2; buf[j] = decode_hex_byte([bytes[offset], bytes[offset + 1]]); j += 1; } res[i] = Limb(Word::from_le_bytes(buf)); i += 1; } Uint::new(res) } /// Serialize this [`Uint`] as big-endian, writing it into the provided /// byte slice. #[inline] pub(crate) fn write_be_bytes(&self, out: &mut [u8]) { debug_assert_eq!(out.len(), Limb::BYTES * LIMBS); for (src, dst) in self .limbs .iter() .rev() .cloned() .zip(out.chunks_exact_mut(Limb::BYTES)) { dst.copy_from_slice(&src.to_be_bytes()); } } /// Serialize this [`Uint`] as little-endian, writing it into the provided /// byte slice. #[inline] pub(crate) fn write_le_bytes(&self, out: &mut [u8]) { debug_assert_eq!(out.len(), Limb::BYTES * LIMBS); for (src, dst) in self .limbs .iter() .cloned() .zip(out.chunks_exact_mut(Limb::BYTES)) { dst.copy_from_slice(&src.to_le_bytes()); } } } /// Decode a single byte encoded as two hexadecimal characters. const fn decode_hex_byte(bytes: [u8; 2]) -> u8 { let mut i = 0; let mut result = 0u8; while i < 2 { result <<= 4; result |= match bytes[i] { b @ b'0'..=b'9' => b - b'0', b @ b'a'..=b'f' => 10 + b - b'a', b @ b'A'..=b'F' => 10 + b - b'A', b => { assert!( matches!(b, b'0'..=b'9' | b'a' ..= b'f' | b'A'..=b'F'), "invalid hex byte" ); 0 } }; i += 1; } result } #[cfg(test)] mod tests { use crate::Limb; use hex_literal::hex; #[cfg(feature = "alloc")] use {crate::U128, alloc::format}; #[cfg(target_pointer_width = "32")] use crate::U64 as UintEx; #[cfg(target_pointer_width = "64")] use crate::U128 as UintEx; #[test] #[cfg(target_pointer_width = "32")] fn from_be_slice() { let bytes = hex!("0011223344556677"); let n = UintEx::from_be_slice(&bytes); assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]); } #[test] #[cfg(target_pointer_width = "64")] fn from_be_slice() { let bytes = hex!("00112233445566778899aabbccddeeff"); let n = UintEx::from_be_slice(&bytes); assert_eq!( n.as_limbs(), &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)] ); } #[test] #[cfg(target_pointer_width = "32")] fn from_le_slice() { let bytes = hex!("7766554433221100"); let n = UintEx::from_le_slice(&bytes); assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]); } #[test] #[cfg(target_pointer_width = "64")] fn from_le_slice() { let bytes = hex!("ffeeddccbbaa99887766554433221100"); let n = UintEx::from_le_slice(&bytes); assert_eq!( n.as_limbs(), &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)] ); } #[test] #[cfg(target_pointer_width = "32")] fn from_be_hex() { let n = UintEx::from_be_hex("0011223344556677"); assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]); } #[test] #[cfg(target_pointer_width = "64")] fn from_be_hex() { let n = UintEx::from_be_hex("00112233445566778899aabbccddeeff"); assert_eq!( n.as_limbs(), &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)] ); } #[test] #[cfg(target_pointer_width = "32")] fn from_le_hex() { let n = UintEx::from_le_hex("7766554433221100"); assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]); } #[test] #[cfg(target_pointer_width = "64")] fn from_le_hex() { let n = UintEx::from_le_hex("ffeeddccbbaa99887766554433221100"); assert_eq!( n.as_limbs(), &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)] ); } #[cfg(feature = "alloc")] #[test] fn hex_upper() { let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD"; let n = U128::from_be_hex(hex); assert_eq!(hex, format!("{:X}", n)); } #[cfg(feature = "alloc")] #[test] fn hex_lower() { let hex = "aaaaaaaabbbbbbbbccccccccdddddddd"; let n = U128::from_be_hex(hex); assert_eq!(hex, format!("{:x}", n)); } } crypto-bigint-0.5.2/src/uint/from.rs000064400000000000000000000153251046102023000155070ustar 00000000000000//! `From`-like conversions for [`Uint`]. use crate::{Limb, Uint, WideWord, Word, U128, U64}; impl Uint { /// Create a [`Uint`] from a `u8` (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable pub const fn from_u8(n: u8) -> Self { assert!(LIMBS >= 1, "number of limbs must be greater than zero"); let mut limbs = [Limb::ZERO; LIMBS]; limbs[0].0 = n as Word; Self { limbs } } /// Create a [`Uint`] from a `u16` (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable pub const fn from_u16(n: u16) -> Self { assert!(LIMBS >= 1, "number of limbs must be greater than zero"); let mut limbs = [Limb::ZERO; LIMBS]; limbs[0].0 = n as Word; Self { limbs } } /// Create a [`Uint`] from a `u32` (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable #[allow(trivial_numeric_casts)] pub const fn from_u32(n: u32) -> Self { assert!(LIMBS >= 1, "number of limbs must be greater than zero"); let mut limbs = [Limb::ZERO; LIMBS]; limbs[0].0 = n as Word; Self { limbs } } /// Create a [`Uint`] from a `u64` (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable #[cfg(target_pointer_width = "32")] pub const fn from_u64(n: u64) -> Self { assert!(LIMBS >= 2, "number of limbs must be two or greater"); let mut limbs = [Limb::ZERO; LIMBS]; limbs[0].0 = (n & 0xFFFFFFFF) as u32; limbs[1].0 = (n >> 32) as u32; Self { limbs } } /// Create a [`Uint`] from a `u64` (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable #[cfg(target_pointer_width = "64")] pub const fn from_u64(n: u64) -> Self { assert!(LIMBS >= 1, "number of limbs must be greater than zero"); let mut limbs = [Limb::ZERO; LIMBS]; limbs[0].0 = n; Self { limbs } } /// Create a [`Uint`] from a `u128` (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable pub const fn from_u128(n: u128) -> Self { assert!( LIMBS >= (128 / Limb::BITS), "number of limbs must be greater than zero" ); let lo = U64::from_u64((n & 0xffff_ffff_ffff_ffff) as u64); let hi = U64::from_u64((n >> 64) as u64); let mut limbs = [Limb::ZERO; LIMBS]; let mut i = 0; while i < lo.limbs.len() { limbs[i] = lo.limbs[i]; i += 1; } let mut j = 0; while j < hi.limbs.len() { limbs[i + j] = hi.limbs[j]; j += 1; } Self { limbs } } /// Create a [`Uint`] from a `Word` (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable pub const fn from_word(n: Word) -> Self { assert!(LIMBS >= 1, "number of limbs must be greater than zero"); let mut limbs = [Limb::ZERO; LIMBS]; limbs[0].0 = n; Self { limbs } } /// Create a [`Uint`] from a `WideWord` (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable pub const fn from_wide_word(n: WideWord) -> Self { assert!(LIMBS >= 2, "number of limbs must be two or greater"); let mut limbs = [Limb::ZERO; LIMBS]; limbs[0].0 = n as Word; limbs[1].0 = (n >> Limb::BITS) as Word; Self { limbs } } } impl From for Uint { fn from(n: u8) -> Self { // TODO(tarcieri): const where clause when possible debug_assert!(LIMBS > 0, "limbs must be non-zero"); Self::from_u8(n) } } impl From for Uint { fn from(n: u16) -> Self { // TODO(tarcieri): const where clause when possible debug_assert!(LIMBS > 0, "limbs must be non-zero"); Self::from_u16(n) } } impl From for Uint { fn from(n: u32) -> Self { // TODO(tarcieri): const where clause when possible debug_assert!(LIMBS > 0, "limbs must be non-zero"); Self::from_u32(n) } } impl From for Uint { fn from(n: u64) -> Self { // TODO(tarcieri): const where clause when possible debug_assert!(LIMBS >= (64 / Limb::BITS), "not enough limbs"); Self::from_u64(n) } } impl From for Uint { fn from(n: u128) -> Self { // TODO(tarcieri): const where clause when possible debug_assert!(LIMBS >= (128 / Limb::BITS), "not enough limbs"); Self::from_u128(n) } } #[cfg(target_pointer_width = "32")] impl From for u64 { fn from(n: U64) -> u64 { (n.limbs[0].0 as u64) | ((n.limbs[1].0 as u64) << 32) } } #[cfg(target_pointer_width = "64")] impl From for u64 { fn from(n: U64) -> u64 { n.limbs[0].into() } } impl From for u128 { fn from(n: U128) -> u128 { let (hi, lo) = n.split(); (u64::from(hi) as u128) << 64 | (u64::from(lo) as u128) } } impl From<[Word; LIMBS]> for Uint { fn from(arr: [Word; LIMBS]) -> Self { Self::from_words(arr) } } impl From> for [Word; LIMBS] { fn from(n: Uint) -> [Word; LIMBS] { *n.as_ref() } } impl From<[Limb; LIMBS]> for Uint { fn from(limbs: [Limb; LIMBS]) -> Self { Self { limbs } } } impl From> for [Limb; LIMBS] { fn from(n: Uint) -> [Limb; LIMBS] { n.limbs } } impl From for Uint { fn from(limb: Limb) -> Self { limb.0.into() } } #[cfg(test)] mod tests { use crate::{Limb, Word, U128}; #[cfg(target_pointer_width = "32")] use crate::U64 as UintEx; #[cfg(target_pointer_width = "64")] use crate::U128 as UintEx; #[test] fn from_u8() { let n = UintEx::from(42u8); assert_eq!(n.as_limbs(), &[Limb(42), Limb(0)]); } #[test] fn from_u16() { let n = UintEx::from(42u16); assert_eq!(n.as_limbs(), &[Limb(42), Limb(0)]); } #[test] fn from_u64() { let n = UintEx::from(42u64); assert_eq!(n.as_limbs(), &[Limb(42), Limb(0)]); } #[test] fn from_u128() { let n = U128::from(42u128); assert_eq!(&n.as_limbs()[..2], &[Limb(42), Limb(0)]); assert_eq!(u128::from(n), 42u128); } #[test] fn array_round_trip() { let arr1 = [1, 2]; let n = UintEx::from(arr1); let arr2: [Word; 2] = n.into(); assert_eq!(arr1, arr2); } } crypto-bigint-0.5.2/src/uint/inv_mod.rs000064400000000000000000000165541046102023000162040ustar 00000000000000use super::Uint; use crate::{CtChoice, Limb}; impl Uint { /// Computes 1/`self` mod 2^k as specified in Algorithm 4 from /// A Secure Algorithm for Inversion Modulo 2k by /// Sadiel de la Fe and Carles Ferrer. See /// . /// /// Conditions: `self` < 2^k and `self` must be odd pub const fn inv_mod2k(&self, k: usize) -> Self { let mut x = Self::ZERO; let mut b = Self::ONE; let mut i = 0; while i < k { let mut x_i = Self::ZERO; let j = b.limbs[0].0 & 1; x_i.limbs[0] = Limb(j); x = x.bitor(&x_i.shl_vartime(i)); let t = b.wrapping_sub(self); b = Self::ct_select(&b, &t, CtChoice::from_lsb(j)).shr_vartime(1); i += 1; } x } /// Computes the multiplicative inverse of `self` mod `modulus`, where `modulus` is odd. /// In other words `self^-1 mod modulus`. /// `bits` and `modulus_bits` are the bounds on the bit size /// of `self` and `modulus`, respectively /// (the inversion speed will be proportional to `bits + modulus_bits`). /// The second element of the tuple is the truthy value if an inverse exists, /// otherwise it is a falsy value. /// /// **Note:** variable time in `bits` and `modulus_bits`. /// /// The algorithm is the same as in GMP 6.2.1's `mpn_sec_invert`. pub const fn inv_odd_mod_bounded( &self, modulus: &Self, bits: usize, modulus_bits: usize, ) -> (Self, CtChoice) { debug_assert!(modulus.ct_is_odd().is_true_vartime()); let mut a = *self; let mut u = Uint::ONE; let mut v = Uint::ZERO; let mut b = *modulus; // `bit_size` can be anything >= `self.bits()` + `modulus.bits()`, setting to the minimum. let bit_size = bits + modulus_bits; let mut m1hp = *modulus; let (m1hp_new, carry) = m1hp.shr_1(); debug_assert!(carry.is_true_vartime()); m1hp = m1hp_new.wrapping_add(&Uint::ONE); let mut i = 0; while i < bit_size { debug_assert!(b.ct_is_odd().is_true_vartime()); let self_odd = a.ct_is_odd(); // Set `self -= b` if `self` is odd. let (new_a, swap) = a.conditional_wrapping_sub(&b, self_odd); // Set `b += self` if `swap` is true. b = Uint::ct_select(&b, &b.wrapping_add(&new_a), swap); // Negate `self` if `swap` is true. a = new_a.conditional_wrapping_neg(swap); let (new_u, new_v) = Uint::ct_swap(&u, &v, swap); let (new_u, cy) = new_u.conditional_wrapping_sub(&new_v, self_odd); let (new_u, cyy) = new_u.conditional_wrapping_add(modulus, cy); debug_assert!(cy.is_true_vartime() == cyy.is_true_vartime()); let (new_a, overflow) = a.shr_1(); debug_assert!(!overflow.is_true_vartime()); let (new_u, cy) = new_u.shr_1(); let (new_u, cy) = new_u.conditional_wrapping_add(&m1hp, cy); debug_assert!(!cy.is_true_vartime()); a = new_a; u = new_u; v = new_v; i += 1; } debug_assert!(!a.ct_is_nonzero().is_true_vartime()); (v, Uint::ct_eq(&b, &Uint::ONE)) } /// Computes the multiplicative inverse of `self` mod `modulus`, where `modulus` is odd. /// Returns `(inverse, Word::MAX)` if an inverse exists, otherwise `(undefined, Word::ZERO)`. pub const fn inv_odd_mod(&self, modulus: &Self) -> (Self, CtChoice) { self.inv_odd_mod_bounded(modulus, Uint::::BITS, Uint::::BITS) } } #[cfg(test)] mod tests { use crate::{U1024, U256, U64}; #[test] fn inv_mod2k() { let v = U256::from_be_hex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"); let e = U256::from_be_hex("3642e6faeaac7c6663b93d3d6a0d489e434ddc0123db5fa627c7f6e22ddacacf"); let a = v.inv_mod2k(256); assert_eq!(e, a); let v = U256::from_be_hex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); let e = U256::from_be_hex("261776f29b6b106c7680cf3ed83054a1af5ae537cb4613dbb4f20099aa774ec1"); let a = v.inv_mod2k(256); assert_eq!(e, a); } #[test] fn test_invert() { let a = U1024::from_be_hex(concat![ "000225E99153B467A5B451979A3F451DAEF3BF8D6C6521D2FA24BBB17F29544E", "347A412B065B75A351EA9719E2430D2477B11CC9CF9C1AD6EDEE26CB15F463F8", "BCC72EF87EA30288E95A48AA792226CEC959DCB0672D8F9D80A54CBBEA85CAD8", "382EC224DEB2F5784E62D0CC2F81C2E6AD14EBABE646D6764B30C32B87688985" ]); let m = U1024::from_be_hex(concat![ "D509E7854ABDC81921F669F1DC6F61359523F3949803E58ED4EA8BC16483DC6F", "37BFE27A9AC9EEA2969B357ABC5C0EE214BE16A7D4C58FC620D5B5A20AFF001A", "D198D3155E5799DC4EA76652D64983A7E130B5EACEBAC768D28D589C36EC749C", "558D0B64E37CD0775C0D0104AE7D98BA23C815185DD43CD8B16292FD94156767" ]); let (res, is_some) = a.inv_odd_mod(&m); let expected = U1024::from_be_hex(concat![ "B03623284B0EBABCABD5C5881893320281460C0A8E7BF4BFDCFFCBCCBF436A55", "D364235C8171E46C7D21AAD0680676E57274A8FDA6D12768EF961CACDD2DAE57", "88D93DA5EB8EDC391EE3726CDCF4613C539F7D23E8702200CB31B5ED5B06E5CA", "3E520968399B4017BF98A864FABA2B647EFC4998B56774D4F2CB026BC024A336" ]); assert!(is_some.is_true_vartime()); assert_eq!(res, expected); } #[test] fn test_invert_bounded() { let a = U1024::from_be_hex(concat![ "0000000000000000000000000000000000000000000000000000000000000000", "347A412B065B75A351EA9719E2430D2477B11CC9CF9C1AD6EDEE26CB15F463F8", "BCC72EF87EA30288E95A48AA792226CEC959DCB0672D8F9D80A54CBBEA85CAD8", "382EC224DEB2F5784E62D0CC2F81C2E6AD14EBABE646D6764B30C32B87688985" ]); let m = U1024::from_be_hex(concat![ "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "D198D3155E5799DC4EA76652D64983A7E130B5EACEBAC768D28D589C36EC749C", "558D0B64E37CD0775C0D0104AE7D98BA23C815185DD43CD8B16292FD94156767" ]); let (res, is_some) = a.inv_odd_mod_bounded(&m, 768, 512); let expected = U1024::from_be_hex(concat![ "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0DCC94E2FE509E6EBBA0825645A38E73EF85D5927C79C1AD8FFE7C8DF9A822FA", "09EB396A21B1EF05CBE51E1A8EF284EF01EBDD36A9A4EA17039D8EEFDD934768" ]); assert!(is_some.is_true_vartime()); assert_eq!(res, expected); } #[test] fn test_invert_small() { let a = U64::from(3u64); let m = U64::from(13u64); let (res, is_some) = a.inv_odd_mod(&m); assert!(is_some.is_true_vartime()); assert_eq!(U64::from(9u64), res); } #[test] fn test_no_inverse_small() { let a = U64::from(14u64); let m = U64::from(49u64); let (_res, is_some) = a.inv_odd_mod(&m); assert!(!is_some.is_true_vartime()); } } crypto-bigint-0.5.2/src/uint/modular/add.rs000064400000000000000000000003031046102023000167250ustar 00000000000000use crate::Uint; pub(crate) const fn add_montgomery_form( a: &Uint, b: &Uint, modulus: &Uint, ) -> Uint { a.add_mod(b, modulus) } crypto-bigint-0.5.2/src/uint/modular/constant_mod/const_add.rs000064400000000000000000000052621046102023000226340ustar 00000000000000use core::ops::{Add, AddAssign}; use crate::modular::add::add_montgomery_form; use super::{Residue, ResidueParams}; impl, const LIMBS: usize> Residue { /// Adds `rhs`. pub const fn add(&self, rhs: &Residue) -> Self { Self { montgomery_form: add_montgomery_form( &self.montgomery_form, &rhs.montgomery_form, &MOD::MODULUS, ), phantom: core::marker::PhantomData, } } } impl, const LIMBS: usize> Add<&Residue> for &Residue { type Output = Residue; fn add(self, rhs: &Residue) -> Residue { self.add(rhs) } } impl, const LIMBS: usize> Add> for &Residue { type Output = Residue; #[allow(clippy::op_ref)] fn add(self, rhs: Residue) -> Residue { self + &rhs } } impl, const LIMBS: usize> Add<&Residue> for Residue { type Output = Residue; #[allow(clippy::op_ref)] fn add(self, rhs: &Residue) -> Residue { &self + rhs } } impl, const LIMBS: usize> Add> for Residue { type Output = Residue; fn add(self, rhs: Residue) -> Residue { &self + &rhs } } impl, const LIMBS: usize> AddAssign<&Self> for Residue { fn add_assign(&mut self, rhs: &Self) { *self = *self + rhs; } } impl, const LIMBS: usize> AddAssign for Residue { fn add_assign(&mut self, rhs: Self) { *self += &rhs; } } #[cfg(test)] mod tests { use crate::{const_residue, impl_modulus, modular::constant_mod::ResidueParams, U256}; impl_modulus!( Modulus, U256, "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551" ); #[test] fn add_overflow() { let x = U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); let mut x_mod = const_residue!(x, Modulus); let y = U256::from_be_hex("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"); let y_mod = const_residue!(y, Modulus); x_mod += &y_mod; let expected = U256::from_be_hex("1a2472fde50286541d97ca6a3592dd75beb9c9646e40c511b82496cfc3926956"); assert_eq!(expected, x_mod.retrieve()); } } crypto-bigint-0.5.2/src/uint/modular/constant_mod/const_inv.rs000064400000000000000000000040631046102023000226760ustar 00000000000000use core::marker::PhantomData; use subtle::CtOption; use crate::{modular::inv::inv_montgomery_form, traits::Invert, CtChoice, NonZero}; use super::{Residue, ResidueParams}; impl, const LIMBS: usize> Residue { /// Computes the residue `self^-1` representing the multiplicative inverse of `self`. /// I.e. `self * self^-1 = 1`. /// If the number was invertible, the second element of the tuple is the truthy value, /// otherwise it is the falsy value (in which case the first element's value is unspecified). pub const fn invert(&self) -> (Self, CtChoice) { let (montgomery_form, is_some) = inv_montgomery_form( &self.montgomery_form, &MOD::MODULUS, &MOD::R3, MOD::MOD_NEG_INV, ); let value = Self { montgomery_form, phantom: PhantomData, }; (value, is_some) } } impl, const LIMBS: usize> Invert for Residue { type Output = CtOption; fn invert(&self) -> Self::Output { let (value, is_some) = self.invert(); CtOption::new(value, is_some.into()) } } impl, const LIMBS: usize> Invert for NonZero> { type Output = Self; fn invert(&self) -> Self::Output { // Always succeeds for a non-zero argument let (value, _is_some) = self.as_ref().invert(); NonZero::new(value).unwrap() } } #[cfg(test)] mod tests { use crate::{const_residue, impl_modulus, modular::constant_mod::ResidueParams, U256}; impl_modulus!( Modulus, U256, "15477BCCEFE197328255BFA79A1217899016D927EF460F4FF404029D24FA4409" ); #[test] fn test_self_inverse() { let x = U256::from_be_hex("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685"); let x_mod = const_residue!(x, Modulus); let (inv, _is_some) = x_mod.invert(); let res = &x_mod * &inv; assert_eq!(res.retrieve(), U256::ONE); } } crypto-bigint-0.5.2/src/uint/modular/constant_mod/const_mul.rs000064400000000000000000000047271046102023000227060ustar 00000000000000use core::{ marker::PhantomData, ops::{Mul, MulAssign}, }; use crate::{ modular::mul::{mul_montgomery_form, square_montgomery_form}, traits::Square, }; use super::{Residue, ResidueParams}; impl, const LIMBS: usize> Residue { /// Multiplies by `rhs`. pub const fn mul(&self, rhs: &Self) -> Self { Self { montgomery_form: mul_montgomery_form( &self.montgomery_form, &rhs.montgomery_form, &MOD::MODULUS, MOD::MOD_NEG_INV, ), phantom: PhantomData, } } /// Computes the (reduced) square of a residue. pub const fn square(&self) -> Self { Self { montgomery_form: square_montgomery_form( &self.montgomery_form, &MOD::MODULUS, MOD::MOD_NEG_INV, ), phantom: PhantomData, } } } impl, const LIMBS: usize> Mul<&Residue> for &Residue { type Output = Residue; fn mul(self, rhs: &Residue) -> Residue { self.mul(rhs) } } impl, const LIMBS: usize> Mul> for &Residue { type Output = Residue; #[allow(clippy::op_ref)] fn mul(self, rhs: Residue) -> Residue { self * &rhs } } impl, const LIMBS: usize> Mul<&Residue> for Residue { type Output = Residue; #[allow(clippy::op_ref)] fn mul(self, rhs: &Residue) -> Residue { &self * rhs } } impl, const LIMBS: usize> Mul> for Residue { type Output = Residue; fn mul(self, rhs: Residue) -> Residue { &self * &rhs } } impl, const LIMBS: usize> MulAssign<&Self> for Residue { fn mul_assign(&mut self, rhs: &Residue) { *self = *self * rhs; } } impl, const LIMBS: usize> MulAssign for Residue { fn mul_assign(&mut self, rhs: Self) { *self *= &rhs; } } impl, const LIMBS: usize> Square for Residue { fn square(&self) -> Self { Residue::square(self) } } crypto-bigint-0.5.2/src/uint/modular/constant_mod/const_neg.rs000064400000000000000000000023521046102023000226520ustar 00000000000000use core::ops::Neg; use super::{Residue, ResidueParams}; impl, const LIMBS: usize> Residue { /// Negates the number. pub const fn neg(&self) -> Self { Self::ZERO.sub(self) } } impl, const LIMBS: usize> Neg for Residue { type Output = Self; fn neg(self) -> Self { Residue::neg(&self) } } impl, const LIMBS: usize> Neg for &Residue { type Output = Residue; fn neg(self) -> Residue { Residue::neg(self) } } #[cfg(test)] mod tests { use crate::{const_residue, impl_modulus, modular::constant_mod::ResidueParams, U256}; impl_modulus!( Modulus, U256, "15477BCCEFE197328255BFA79A1217899016D927EF460F4FF404029D24FA4409" ); #[test] fn test_negate() { let x = U256::from_be_hex("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685"); let x_mod = const_residue!(x, Modulus); let res = -x_mod; let expected = U256::from_be_hex("089B67BB2C124F084701AD76E8750D321385E35044C74CE457301A2A9BE061B1"); assert_eq!(res.retrieve(), expected); } } crypto-bigint-0.5.2/src/uint/modular/constant_mod/const_pow.rs000064400000000000000000000060441046102023000227100ustar 00000000000000use crate::{modular::pow::pow_montgomery_form, PowBoundedExp, Uint}; use super::{Residue, ResidueParams}; impl, const LIMBS: usize> Residue { /// Raises to the `exponent` power. pub const fn pow(&self, exponent: &Uint) -> Residue { self.pow_bounded_exp(exponent, Uint::::BITS) } /// Raises to the `exponent` power, /// with `exponent_bits` representing the number of (least significant) bits /// to take into account for the exponent. /// /// NOTE: `exponent_bits` may be leaked in the time pattern. pub const fn pow_bounded_exp( &self, exponent: &Uint, exponent_bits: usize, ) -> Residue { Self { montgomery_form: pow_montgomery_form( &self.montgomery_form, exponent, exponent_bits, &MOD::MODULUS, &MOD::R, MOD::MOD_NEG_INV, ), phantom: core::marker::PhantomData, } } } impl, const LIMBS: usize> PowBoundedExp> for Residue { fn pow_bounded_exp(&self, exponent: &Uint, exponent_bits: usize) -> Self { self.pow_bounded_exp(exponent, exponent_bits) } } #[cfg(test)] mod tests { use crate::{const_residue, impl_modulus, modular::constant_mod::ResidueParams, U256}; impl_modulus!( Modulus, U256, "9CC24C5DF431A864188AB905AC751B727C9447A8E99E6366E1AD78A21E8D882B" ); #[test] fn test_powmod_small_base() { let base = U256::from(105u64); let base_mod = const_residue!(base, Modulus); let exponent = U256::from_be_hex("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685"); let res = base_mod.pow(&exponent); let expected = U256::from_be_hex("7B2CD7BDDD96C271E6F232F2F415BB03FE2A90BD6CCCEA5E94F1BFD064993766"); assert_eq!(res.retrieve(), expected); } #[test] fn test_powmod_small_exponent() { let base = U256::from_be_hex("3435D18AA8313EBBE4D20002922225B53F75DC4453BB3EEC0378646F79B524A4"); let base_mod = const_residue!(base, Modulus); let exponent = U256::from(105u64); let res = base_mod.pow(&exponent); let expected = U256::from_be_hex("89E2A4E99F649A5AE2C18068148C355CA927B34A3245C938178ED00D6EF218AA"); assert_eq!(res.retrieve(), expected); } #[test] fn test_powmod() { let base = U256::from_be_hex("3435D18AA8313EBBE4D20002922225B53F75DC4453BB3EEC0378646F79B524A4"); let base_mod = const_residue!(base, Modulus); let exponent = U256::from_be_hex("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685"); let res = base_mod.pow(&exponent); let expected = U256::from_be_hex("3681BC0FEA2E5D394EB178155A127B0FD2EF405486D354251C385BDD51B9D421"); assert_eq!(res.retrieve(), expected); } } crypto-bigint-0.5.2/src/uint/modular/constant_mod/const_sub.rs000064400000000000000000000052501046102023000226720ustar 00000000000000use core::ops::{Sub, SubAssign}; use crate::modular::sub::sub_montgomery_form; use super::{Residue, ResidueParams}; impl, const LIMBS: usize> Residue { /// Subtracts `rhs`. pub const fn sub(&self, rhs: &Self) -> Self { Self { montgomery_form: sub_montgomery_form( &self.montgomery_form, &rhs.montgomery_form, &MOD::MODULUS, ), phantom: core::marker::PhantomData, } } } impl, const LIMBS: usize> Sub<&Residue> for &Residue { type Output = Residue; fn sub(self, rhs: &Residue) -> Residue { self.sub(rhs) } } impl, const LIMBS: usize> Sub> for &Residue { type Output = Residue; #[allow(clippy::op_ref)] fn sub(self, rhs: Residue) -> Residue { self - &rhs } } impl, const LIMBS: usize> Sub<&Residue> for Residue { type Output = Residue; #[allow(clippy::op_ref)] fn sub(self, rhs: &Residue) -> Residue { &self - rhs } } impl, const LIMBS: usize> Sub> for Residue { type Output = Residue; fn sub(self, rhs: Residue) -> Residue { &self - &rhs } } impl, const LIMBS: usize> SubAssign<&Self> for Residue { fn sub_assign(&mut self, rhs: &Self) { *self = *self - rhs; } } impl, const LIMBS: usize> SubAssign for Residue { fn sub_assign(&mut self, rhs: Self) { *self -= &rhs; } } #[cfg(test)] mod tests { use crate::{const_residue, impl_modulus, modular::constant_mod::ResidueParams, U256}; impl_modulus!( Modulus, U256, "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551" ); #[test] fn sub_overflow() { let x = U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); let mut x_mod = const_residue!(x, Modulus); let y = U256::from_be_hex("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"); let y_mod = const_residue!(y, Modulus); x_mod -= &y_mod; let expected = U256::from_be_hex("6f357a71e1d5a03167f34879d469352add829491c6df41ddff65387d7ed56f56"); assert_eq!(expected, x_mod.retrieve()); } } crypto-bigint-0.5.2/src/uint/modular/constant_mod/macros.rs000064400000000000000000000047021046102023000221600ustar 00000000000000// TODO: Use `adt_const_params` once stabilized to make a `Residue` generic around a modulus rather than having to implement a ZST + trait #[macro_export] /// Implements a modulus with the given name, type, and value, in that specific order. Please `use crypto_bigint::traits::Encoding` to make this work. /// For example, `impl_modulus!(MyModulus, U256, "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001");` implements a 256-bit modulus named `MyModulus`. macro_rules! impl_modulus { ($name:ident, $uint_type:ty, $value:expr) => { #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] pub struct $name {} impl $crate::modular::constant_mod::ResidueParams<{ $crate::nlimbs!(<$uint_type>::BITS) }> for $name where $crate::Uint<{ $crate::nlimbs!(<$uint_type>::BITS) }>: $crate::Concat>, { const LIMBS: usize = { $crate::nlimbs!(<$uint_type>::BITS) }; const MODULUS: $crate::Uint<{ $crate::nlimbs!(<$uint_type>::BITS) }> = <$uint_type>::from_be_hex($value); const R: $crate::Uint<{ $crate::nlimbs!(<$uint_type>::BITS) }> = $crate::Uint::MAX .const_rem(&Self::MODULUS) .0 .wrapping_add(&$crate::Uint::ONE); const R2: $crate::Uint<{ $crate::nlimbs!(<$uint_type>::BITS) }> = $crate::Uint::const_rem_wide(Self::R.square_wide(), &Self::MODULUS).0; const MOD_NEG_INV: $crate::Limb = $crate::Limb( $crate::Word::MIN.wrapping_sub( Self::MODULUS .inv_mod2k($crate::Word::BITS as usize) .as_limbs()[0] .0, ), ); const R3: $crate::Uint<{ $crate::nlimbs!(<$uint_type>::BITS) }> = $crate::modular::montgomery_reduction( &Self::R2.square_wide(), &Self::MODULUS, Self::MOD_NEG_INV, ); } }; } #[macro_export] /// Creates a `Residue` with the given value for a specific modulus. /// For example, `residue!(U256::from(105u64), MyModulus);` creates a `Residue` for 105 mod `MyModulus`. macro_rules! const_residue { ($variable:ident, $modulus:ident) => { $crate::modular::constant_mod::Residue::<$modulus, { $modulus::LIMBS }>::new(&$variable) }; } crypto-bigint-0.5.2/src/uint/modular/constant_mod.rs000064400000000000000000000144431046102023000206770ustar 00000000000000use core::{fmt::Debug, marker::PhantomData}; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; use crate::{Limb, Uint, Zero}; use super::{div_by_2::div_by_2, reduction::montgomery_reduction, Retrieve}; #[cfg(feature = "rand_core")] use crate::{rand_core::CryptoRngCore, NonZero, Random, RandomMod}; #[cfg(feature = "serde")] use { crate::Encoding, serdect::serde::de::Error, serdect::serde::{Deserialize, Deserializer, Serialize, Serializer}, }; /// Additions between residues with a constant modulus mod const_add; /// Multiplicative inverses of residues with a constant modulus mod const_inv; /// Multiplications between residues with a constant modulus mod const_mul; /// Negations of residues with a constant modulus mod const_neg; /// Exponentiation of residues with a constant modulus mod const_pow; /// Subtractions between residues with a constant modulus mod const_sub; /// Macros to remove the boilerplate code when dealing with constant moduli. #[macro_use] mod macros; pub use macros::*; /// The parameters to efficiently go to and from the Montgomery form for a given odd modulus. An easy way to generate these parameters is using the `impl_modulus!` macro. These parameters are constant, so they cannot be set at runtime. /// /// Unfortunately, `LIMBS` must be generic for now until const generics are stabilized. pub trait ResidueParams: Copy + Debug + Default + Eq + Send + Sync + 'static { /// Number of limbs required to encode a residue const LIMBS: usize; /// The constant modulus const MODULUS: Uint; /// Parameter used in Montgomery reduction const R: Uint; /// R^2, used to move into Montgomery form const R2: Uint; /// R^3, used to perform a multiplicative inverse const R3: Uint; /// The lowest limbs of -(MODULUS^-1) mod R // We only need the LSB because during reduction this value is multiplied modulo 2**Limb::BITS. const MOD_NEG_INV: Limb; } #[derive(Debug, Clone, Copy, PartialEq, Eq)] /// A residue mod `MOD`, represented using `LIMBS` limbs. The modulus of this residue is constant, so it cannot be set at runtime. pub struct Residue where MOD: ResidueParams, { montgomery_form: Uint, phantom: PhantomData, } #[cfg(feature = "zeroize")] impl, const LIMBS: usize> zeroize::DefaultIsZeroes for Residue { } impl, const LIMBS: usize> Residue { /// The representation of 0 mod `MOD`. pub const ZERO: Self = Self { montgomery_form: Uint::::ZERO, phantom: PhantomData, }; /// The representation of 1 mod `MOD`. pub const ONE: Self = Self { montgomery_form: MOD::R, phantom: PhantomData, }; /// Instantiates a new `Residue` that represents this `integer` mod `MOD`. pub const fn new(integer: &Uint) -> Self { let product = integer.mul_wide(&MOD::R2); let montgomery_form = montgomery_reduction::(&product, &MOD::MODULUS, MOD::MOD_NEG_INV); Self { montgomery_form, phantom: PhantomData, } } /// Retrieves the integer currently encoded in this `Residue`, guaranteed to be reduced. pub const fn retrieve(&self) -> Uint { montgomery_reduction::( &(self.montgomery_form, Uint::ZERO), &MOD::MODULUS, MOD::MOD_NEG_INV, ) } /// Performs the modular division by 2, that is for given `x` returns `y` /// such that `y * 2 = x mod p`. This means: /// - if `x` is even, returns `x / 2`, /// - if `x` is odd, returns `(x + p) / 2` /// (since the modulus `p` in Montgomery form is always odd, this divides entirely). pub fn div_by_2(&self) -> Self { Self { montgomery_form: div_by_2(&self.montgomery_form, &MOD::MODULUS), phantom: PhantomData, } } } impl + Copy, const LIMBS: usize> ConditionallySelectable for Residue { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Residue { montgomery_form: Uint::conditional_select( &a.montgomery_form, &b.montgomery_form, choice, ), phantom: PhantomData, } } } impl, const LIMBS: usize> ConstantTimeEq for Residue { fn ct_eq(&self, other: &Self) -> Choice { ConstantTimeEq::ct_eq(&self.montgomery_form, &other.montgomery_form) } } impl, const LIMBS: usize> Default for Residue { fn default() -> Self { Self::ZERO } } impl, const LIMBS: usize> Zero for Residue { const ZERO: Self = Self::ZERO; } #[cfg(feature = "rand_core")] impl Random for Residue where MOD: ResidueParams, { #[inline] fn random(rng: &mut impl CryptoRngCore) -> Self { Self::new(&Uint::random_mod(rng, &NonZero::from_uint(MOD::MODULUS))) } } impl, const LIMBS: usize> Retrieve for Residue { type Output = Uint; fn retrieve(&self) -> Self::Output { self.retrieve() } } #[cfg(feature = "serde")] impl<'de, MOD, const LIMBS: usize> Deserialize<'de> for Residue where MOD: ResidueParams, Uint: Encoding, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { Uint::::deserialize(deserializer).and_then(|montgomery_form| { if Uint::ct_lt(&montgomery_form, &MOD::MODULUS).into() { Ok(Self { montgomery_form, phantom: PhantomData, }) } else { Err(D::Error::custom("montgomery form must be reduced")) } }) } } #[cfg(feature = "serde")] impl Serialize for Residue where MOD: ResidueParams, Uint: Encoding, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.montgomery_form.serialize(serializer) } } crypto-bigint-0.5.2/src/uint/modular/div_by_2.rs000064400000000000000000000025531046102023000177030ustar 00000000000000use crate::Uint; pub(crate) fn div_by_2(a: &Uint, modulus: &Uint) -> Uint { // We are looking for such `x` that `x * 2 = y mod modulus`, // where the given `a = M(y)` is the Montgomery representation of some `y`. // This means that in Montgomery representation it would still apply: // `M(x) + M(x) = a mod modulus`. // So we can just forget about Montgomery representation, and return whatever is // `a` divided by 2, and this will be the Montgomery representation of `x`. // (Which means that this function works regardless of whether `a` // is in Montgomery representation or not, but the algorithm below // does need `modulus` to be odd) // Two possibilities: // - if `a` is even, we can just divide by 2; // - if `a` is odd, we divide `(a + modulus)` by 2. // To stay within the modulus we open the parentheses turning it into `a / 2 + modulus / 2 + 1` // ("+1" because both `a` and `modulus` are odd, we lose 0.5 in each integer division). // This will not overflow, so we can just use wrapping operations. let (half, is_odd) = a.shr_1(); let half_modulus = modulus.shr_vartime(1); let if_even = half; let if_odd = half .wrapping_add(&half_modulus) .wrapping_add(&Uint::::ONE); Uint::::ct_select(&if_even, &if_odd, is_odd) } crypto-bigint-0.5.2/src/uint/modular/inv.rs000064400000000000000000000006371046102023000170030ustar 00000000000000use crate::{modular::reduction::montgomery_reduction, CtChoice, Limb, Uint}; pub const fn inv_montgomery_form( x: &Uint, modulus: &Uint, r3: &Uint, mod_neg_inv: Limb, ) -> (Uint, CtChoice) { let (inverse, is_some) = x.inv_odd_mod(modulus); ( montgomery_reduction(&inverse.mul_wide(r3), modulus, mod_neg_inv), is_some, ) } crypto-bigint-0.5.2/src/uint/modular/mul.rs000064400000000000000000000011321046102023000167730ustar 00000000000000use crate::{Limb, Uint}; use super::reduction::montgomery_reduction; pub(crate) const fn mul_montgomery_form( a: &Uint, b: &Uint, modulus: &Uint, mod_neg_inv: Limb, ) -> Uint { let product = a.mul_wide(b); montgomery_reduction::(&product, modulus, mod_neg_inv) } pub(crate) const fn square_montgomery_form( a: &Uint, modulus: &Uint, mod_neg_inv: Limb, ) -> Uint { let product = a.square_wide(); montgomery_reduction::(&product, modulus, mod_neg_inv) } crypto-bigint-0.5.2/src/uint/modular/pow.rs000064400000000000000000000046071046102023000170150ustar 00000000000000use crate::{Limb, Uint, Word}; use super::mul::{mul_montgomery_form, square_montgomery_form}; /// Performs modular exponentiation using Montgomery's ladder. /// `exponent_bits` represents the number of bits to take into account for the exponent. /// /// NOTE: this value is leaked in the time pattern. pub const fn pow_montgomery_form( x: &Uint, exponent: &Uint, exponent_bits: usize, modulus: &Uint, r: &Uint, mod_neg_inv: Limb, ) -> Uint { if exponent_bits == 0 { return *r; // 1 in Montgomery form } const WINDOW: usize = 4; const WINDOW_MASK: Word = (1 << WINDOW) - 1; // powers[i] contains x^i let mut powers = [*r; 1 << WINDOW]; powers[1] = *x; let mut i = 2; while i < powers.len() { powers[i] = mul_montgomery_form(&powers[i - 1], x, modulus, mod_neg_inv); i += 1; } let starting_limb = (exponent_bits - 1) / Limb::BITS; let starting_bit_in_limb = (exponent_bits - 1) % Limb::BITS; let starting_window = starting_bit_in_limb / WINDOW; let starting_window_mask = (1 << (starting_bit_in_limb % WINDOW + 1)) - 1; let mut z = *r; // 1 in Montgomery form let mut limb_num = starting_limb + 1; while limb_num > 0 { limb_num -= 1; let w = exponent.as_limbs()[limb_num].0; let mut window_num = if limb_num == starting_limb { starting_window + 1 } else { Limb::BITS / WINDOW }; while window_num > 0 { window_num -= 1; let mut idx = (w >> (window_num * WINDOW)) & WINDOW_MASK; if limb_num == starting_limb && window_num == starting_window { idx &= starting_window_mask; } else { let mut i = 0; while i < WINDOW { i += 1; z = square_montgomery_form(&z, modulus, mod_neg_inv); } } // Constant-time lookup in the array of powers let mut power = powers[0]; let mut i = 1; while i < 1 << WINDOW { let choice = Limb::ct_eq(Limb(i as Word), Limb(idx)); power = Uint::::ct_select(&power, &powers[i], choice); i += 1; } z = mul_montgomery_form(&z, &power, modulus, mod_neg_inv); } } z } crypto-bigint-0.5.2/src/uint/modular/reduction.rs000064400000000000000000000034411046102023000201770ustar 00000000000000use crate::{Limb, Uint, WideWord, Word}; /// Returns `(hi, lo)` such that `hi * R + lo = x * y + z + w`. #[inline(always)] const fn muladdcarry(x: Word, y: Word, z: Word, w: Word) -> (Word, Word) { let res = (x as WideWord) .wrapping_mul(y as WideWord) .wrapping_add(z as WideWord) .wrapping_add(w as WideWord); ((res >> Word::BITS) as Word, res as Word) } /// Algorithm 14.32 in Handbook of Applied Cryptography pub const fn montgomery_reduction( lower_upper: &(Uint, Uint), modulus: &Uint, mod_neg_inv: Limb, ) -> Uint { let (mut lower, mut upper) = *lower_upper; let mut meta_carry = Limb(0); let mut new_sum; let mut i = 0; while i < LIMBS { let u = lower.limbs[i].0.wrapping_mul(mod_neg_inv.0); let (mut carry, _) = muladdcarry(u, modulus.limbs[0].0, lower.limbs[i].0, 0); let mut new_limb; let mut j = 1; while j < (LIMBS - i) { (carry, new_limb) = muladdcarry(u, modulus.limbs[j].0, lower.limbs[i + j].0, carry); lower.limbs[i + j] = Limb(new_limb); j += 1; } while j < LIMBS { (carry, new_limb) = muladdcarry(u, modulus.limbs[j].0, upper.limbs[i + j - LIMBS].0, carry); upper.limbs[i + j - LIMBS] = Limb(new_limb); j += 1; } (new_sum, meta_carry) = upper.limbs[i].adc(Limb(carry), meta_carry); upper.limbs[i] = new_sum; i += 1; } // Division is simply taking the upper half of the limbs // Final reduction (at this point, the value is at most 2 * modulus, // so `meta_carry` is either 0 or 1) upper.sub_mod_with_carry(meta_carry, modulus, modulus) } crypto-bigint-0.5.2/src/uint/modular/runtime_mod/runtime_add.rs000064400000000000000000000051041046102023000230160ustar 00000000000000use core::ops::{Add, AddAssign}; use crate::modular::add::add_montgomery_form; use super::DynResidue; impl DynResidue { /// Adds `rhs`. pub const fn add(&self, rhs: &Self) -> Self { Self { montgomery_form: add_montgomery_form( &self.montgomery_form, &rhs.montgomery_form, &self.residue_params.modulus, ), residue_params: self.residue_params, } } } impl Add<&DynResidue> for &DynResidue { type Output = DynResidue; fn add(self, rhs: &DynResidue) -> DynResidue { debug_assert_eq!(self.residue_params, rhs.residue_params); self.add(rhs) } } impl Add> for &DynResidue { type Output = DynResidue; #[allow(clippy::op_ref)] fn add(self, rhs: DynResidue) -> DynResidue { self + &rhs } } impl Add<&DynResidue> for DynResidue { type Output = DynResidue; #[allow(clippy::op_ref)] fn add(self, rhs: &DynResidue) -> DynResidue { &self + rhs } } impl Add> for DynResidue { type Output = DynResidue; fn add(self, rhs: DynResidue) -> DynResidue { &self + &rhs } } impl AddAssign<&DynResidue> for DynResidue { fn add_assign(&mut self, rhs: &DynResidue) { *self = *self + rhs; } } impl AddAssign> for DynResidue { fn add_assign(&mut self, rhs: DynResidue) { *self += &rhs; } } #[cfg(test)] mod tests { use crate::{ modular::runtime_mod::{DynResidue, DynResidueParams}, U256, }; #[test] fn add_overflow() { let params = DynResidueParams::new(&U256::from_be_hex( "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", )); let x = U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); let mut x_mod = DynResidue::new(&x, params); let y = U256::from_be_hex("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"); let y_mod = DynResidue::new(&y, params); x_mod += &y_mod; let expected = U256::from_be_hex("1a2472fde50286541d97ca6a3592dd75beb9c9646e40c511b82496cfc3926956"); assert_eq!(expected, x_mod.retrieve()); } } crypto-bigint-0.5.2/src/uint/modular/runtime_mod/runtime_inv.rs000064400000000000000000000021721046102023000230640ustar 00000000000000use subtle::CtOption; use crate::{modular::inv::inv_montgomery_form, traits::Invert, CtChoice}; use super::DynResidue; impl DynResidue { /// Computes the residue `self^-1` representing the multiplicative inverse of `self`. /// I.e. `self * self^-1 = 1`. /// If the number was invertible, the second element of the tuple is the truthy value, /// otherwise it is the falsy value (in which case the first element's value is unspecified). pub const fn invert(&self) -> (Self, CtChoice) { let (montgomery_form, is_some) = inv_montgomery_form( &self.montgomery_form, &self.residue_params.modulus, &self.residue_params.r3, self.residue_params.mod_neg_inv, ); let value = Self { montgomery_form, residue_params: self.residue_params, }; (value, is_some) } } impl Invert for DynResidue { type Output = CtOption; fn invert(&self) -> Self::Output { let (value, is_some) = self.invert(); CtOption::new(value, is_some.into()) } } crypto-bigint-0.5.2/src/uint/modular/runtime_mod/runtime_mul.rs000064400000000000000000000045241046102023000230700ustar 00000000000000use core::ops::{Mul, MulAssign}; use crate::{ modular::mul::{mul_montgomery_form, square_montgomery_form}, traits::Square, }; use super::DynResidue; impl DynResidue { /// Multiplies by `rhs`. pub const fn mul(&self, rhs: &Self) -> Self { Self { montgomery_form: mul_montgomery_form( &self.montgomery_form, &rhs.montgomery_form, &self.residue_params.modulus, self.residue_params.mod_neg_inv, ), residue_params: self.residue_params, } } /// Computes the (reduced) square of a residue. pub const fn square(&self) -> Self { Self { montgomery_form: square_montgomery_form( &self.montgomery_form, &self.residue_params.modulus, self.residue_params.mod_neg_inv, ), residue_params: self.residue_params, } } } impl Mul<&DynResidue> for &DynResidue { type Output = DynResidue; fn mul(self, rhs: &DynResidue) -> DynResidue { debug_assert_eq!(self.residue_params, rhs.residue_params); self.mul(rhs) } } impl Mul> for &DynResidue { type Output = DynResidue; #[allow(clippy::op_ref)] fn mul(self, rhs: DynResidue) -> DynResidue { self * &rhs } } impl Mul<&DynResidue> for DynResidue { type Output = DynResidue; #[allow(clippy::op_ref)] fn mul(self, rhs: &DynResidue) -> DynResidue { &self * rhs } } impl Mul> for DynResidue { type Output = DynResidue; fn mul(self, rhs: DynResidue) -> DynResidue { &self * &rhs } } impl MulAssign<&DynResidue> for DynResidue { fn mul_assign(&mut self, rhs: &DynResidue) { *self = *self * rhs; } } impl MulAssign> for DynResidue { fn mul_assign(&mut self, rhs: DynResidue) { *self *= &rhs; } } impl Square for DynResidue { fn square(&self) -> Self { DynResidue::square(self) } } crypto-bigint-0.5.2/src/uint/modular/runtime_mod/runtime_neg.rs000064400000000000000000000010201046102023000230300ustar 00000000000000use core::ops::Neg; use super::DynResidue; impl DynResidue { /// Negates the number. pub const fn neg(&self) -> Self { Self::zero(self.residue_params).sub(self) } } impl Neg for DynResidue { type Output = Self; fn neg(self) -> Self { DynResidue::neg(&self) } } impl Neg for &DynResidue { type Output = DynResidue; fn neg(self) -> DynResidue { DynResidue::neg(self) } } crypto-bigint-0.5.2/src/uint/modular/runtime_mod/runtime_pow.rs000064400000000000000000000023551046102023000231000ustar 00000000000000use crate::{modular::pow::pow_montgomery_form, PowBoundedExp, Uint}; use super::DynResidue; impl DynResidue { /// Raises to the `exponent` power. pub const fn pow(&self, exponent: &Uint) -> DynResidue { self.pow_bounded_exp(exponent, Uint::::BITS) } /// Raises to the `exponent` power, /// with `exponent_bits` representing the number of (least significant) bits /// to take into account for the exponent. /// /// NOTE: `exponent_bits` may be leaked in the time pattern. pub const fn pow_bounded_exp(&self, exponent: &Uint, exponent_bits: usize) -> Self { Self { montgomery_form: pow_montgomery_form( &self.montgomery_form, exponent, exponent_bits, &self.residue_params.modulus, &self.residue_params.r, self.residue_params.mod_neg_inv, ), residue_params: self.residue_params, } } } impl PowBoundedExp> for DynResidue { fn pow_bounded_exp(&self, exponent: &Uint, exponent_bits: usize) -> Self { self.pow_bounded_exp(exponent, exponent_bits) } } crypto-bigint-0.5.2/src/uint/modular/runtime_mod/runtime_sub.rs000064400000000000000000000051111046102023000230550ustar 00000000000000use core::ops::{Sub, SubAssign}; use crate::modular::sub::sub_montgomery_form; use super::DynResidue; impl DynResidue { /// Subtracts `rhs`. pub const fn sub(&self, rhs: &Self) -> Self { Self { montgomery_form: sub_montgomery_form( &self.montgomery_form, &rhs.montgomery_form, &self.residue_params.modulus, ), residue_params: self.residue_params, } } } impl Sub<&DynResidue> for &DynResidue { type Output = DynResidue; fn sub(self, rhs: &DynResidue) -> DynResidue { debug_assert_eq!(self.residue_params, rhs.residue_params); self.sub(rhs) } } impl Sub> for &DynResidue { type Output = DynResidue; #[allow(clippy::op_ref)] fn sub(self, rhs: DynResidue) -> DynResidue { self - &rhs } } impl Sub<&DynResidue> for DynResidue { type Output = DynResidue; #[allow(clippy::op_ref)] fn sub(self, rhs: &DynResidue) -> DynResidue { &self - rhs } } impl Sub> for DynResidue { type Output = DynResidue; fn sub(self, rhs: DynResidue) -> DynResidue { &self - &rhs } } impl SubAssign<&DynResidue> for DynResidue { fn sub_assign(&mut self, rhs: &DynResidue) { *self = *self - rhs; } } impl SubAssign> for DynResidue { fn sub_assign(&mut self, rhs: DynResidue) { *self -= &rhs; } } #[cfg(test)] mod tests { use crate::{ modular::runtime_mod::{DynResidue, DynResidueParams}, U256, }; #[test] fn sub_overflow() { let params = DynResidueParams::new(&U256::from_be_hex( "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", )); let x = U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); let mut x_mod = DynResidue::new(&x, params); let y = U256::from_be_hex("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251"); let y_mod = DynResidue::new(&y, params); x_mod -= &y_mod; let expected = U256::from_be_hex("6f357a71e1d5a03167f34879d469352add829491c6df41ddff65387d7ed56f56"); assert_eq!(expected, x_mod.retrieve()); } } crypto-bigint-0.5.2/src/uint/modular/runtime_mod.rs000064400000000000000000000112021046102023000205170ustar 00000000000000use crate::{Limb, Uint, Word}; use super::{div_by_2::div_by_2, reduction::montgomery_reduction, Retrieve}; /// Additions between residues with a modulus set at runtime mod runtime_add; /// Multiplicative inverses of residues with a modulus set at runtime mod runtime_inv; /// Multiplications between residues with a modulus set at runtime mod runtime_mul; /// Negations of residues with a modulus set at runtime mod runtime_neg; /// Exponentiation of residues with a modulus set at runtime mod runtime_pow; /// Subtractions between residues with a modulus set at runtime mod runtime_sub; /// The parameters to efficiently go to and from the Montgomery form for a modulus provided at runtime. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DynResidueParams { // The constant modulus modulus: Uint, // Parameter used in Montgomery reduction r: Uint, // R^2, used to move into Montgomery form r2: Uint, // R^3, used to compute the multiplicative inverse r3: Uint, // The lowest limbs of -(MODULUS^-1) mod R // We only need the LSB because during reduction this value is multiplied modulo 2**Limb::BITS. mod_neg_inv: Limb, } impl DynResidueParams { /// Instantiates a new set of `ResidueParams` representing the given `modulus`. pub const fn new(modulus: &Uint) -> Self { let r = Uint::MAX.const_rem(modulus).0.wrapping_add(&Uint::ONE); let r2 = Uint::const_rem_wide(r.square_wide(), modulus).0; // Since we are calculating the inverse modulo (Word::MAX+1), // we can take the modulo right away and calculate the inverse of the first limb only. let modulus_lo = Uint::<1>::from_words([modulus.limbs[0].0]); let mod_neg_inv = Limb(Word::MIN.wrapping_sub(modulus_lo.inv_mod2k(Word::BITS as usize).limbs[0].0)); let r3 = montgomery_reduction(&r2.square_wide(), modulus, mod_neg_inv); Self { modulus: *modulus, r, r2, r3, mod_neg_inv, } } /// Returns the modulus which was used to initialize these parameters. pub const fn modulus(&self) -> &Uint { &self.modulus } } /// A residue represented using `LIMBS` limbs. The odd modulus of this residue is set at runtime. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DynResidue { montgomery_form: Uint, residue_params: DynResidueParams, } impl DynResidue { /// Instantiates a new `Residue` that represents this `integer` mod `MOD`. pub const fn new(integer: &Uint, residue_params: DynResidueParams) -> Self { let product = integer.mul_wide(&residue_params.r2); let montgomery_form = montgomery_reduction( &product, &residue_params.modulus, residue_params.mod_neg_inv, ); Self { montgomery_form, residue_params, } } /// Retrieves the integer currently encoded in this `Residue`, guaranteed to be reduced. pub const fn retrieve(&self) -> Uint { montgomery_reduction( &(self.montgomery_form, Uint::ZERO), &self.residue_params.modulus, self.residue_params.mod_neg_inv, ) } /// Instantiates a new `Residue` that represents zero. pub const fn zero(residue_params: DynResidueParams) -> Self { Self { montgomery_form: Uint::::ZERO, residue_params, } } /// Instantiates a new `Residue` that represents 1. pub const fn one(residue_params: DynResidueParams) -> Self { Self { montgomery_form: residue_params.r, residue_params, } } /// Returns the parameter struct used to initialize this residue. pub const fn params(&self) -> &DynResidueParams { &self.residue_params } /// Performs the modular division by 2, that is for given `x` returns `y` /// such that `y * 2 = x mod p`. This means: /// - if `x` is even, returns `x / 2`, /// - if `x` is odd, returns `(x + p) / 2` /// (since the modulus `p` in Montgomery form is always odd, this divides entirely). pub fn div_by_2(&self) -> Self { Self { montgomery_form: div_by_2(&self.montgomery_form, &self.residue_params.modulus), residue_params: self.residue_params, } } } impl Retrieve for DynResidue { type Output = Uint; fn retrieve(&self) -> Self::Output { self.retrieve() } } crypto-bigint-0.5.2/src/uint/modular/sub.rs000064400000000000000000000003031046102023000167660ustar 00000000000000use crate::Uint; pub(crate) const fn sub_montgomery_form( a: &Uint, b: &Uint, modulus: &Uint, ) -> Uint { a.sub_mod(b, modulus) } crypto-bigint-0.5.2/src/uint/modular.rs000064400000000000000000000111021046102023000161740ustar 00000000000000mod reduction; /// Implements `Residue`s, supporting modular arithmetic with a constant modulus. pub mod constant_mod; /// Implements `DynResidue`s, supporting modular arithmetic with a modulus set at runtime. pub mod runtime_mod; mod add; mod div_by_2; mod inv; mod mul; mod pow; mod sub; pub use reduction::montgomery_reduction; /// A generalization for numbers kept in optimized representations (e.g. Montgomery) /// that can be converted back to the original form. pub trait Retrieve { /// The original type. type Output; /// Convert the number back from the optimized representation. fn retrieve(&self) -> Self::Output; } #[cfg(test)] mod tests { use crate::{ const_residue, impl_modulus, modular::{ constant_mod::Residue, constant_mod::ResidueParams, reduction::montgomery_reduction, }, NonZero, Uint, U256, U64, }; impl_modulus!( Modulus1, U256, "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001" ); #[test] fn test_montgomery_params() { assert_eq!( Modulus1::R, U256::from_be_hex("1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffe") ); assert_eq!( Modulus1::R2, U256::from_be_hex("0748d9d99f59ff1105d314967254398f2b6cedcb87925c23c999e990f3f29c6d") ); assert_eq!( Modulus1::MOD_NEG_INV, U64::from_be_hex("fffffffeffffffff").limbs[0] ); } impl_modulus!( Modulus2, U256, "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551" ); #[test] fn test_reducing_r() { // Divide the value R by R, which should equal 1 assert_eq!( montgomery_reduction::<{ Modulus2::LIMBS }>( &(Modulus2::R, Uint::ZERO), &Modulus2::MODULUS, Modulus2::MOD_NEG_INV ), Uint::ONE ); } #[test] fn test_reducing_r2() { // Divide the value R^2 by R, which should equal R assert_eq!( montgomery_reduction::<{ Modulus2::LIMBS }>( &(Modulus2::R2, Uint::ZERO), &Modulus2::MODULUS, Modulus2::MOD_NEG_INV ), Modulus2::R ); } #[test] fn test_reducing_r2_wide() { // Divide the value R^2 by R, which should equal R let (hi, lo) = Modulus2::R.square().split(); assert_eq!( montgomery_reduction::<{ Modulus2::LIMBS }>( &(lo, hi), &Modulus2::MODULUS, Modulus2::MOD_NEG_INV ), Modulus2::R ); } #[test] fn test_reducing_xr_wide() { // Reducing xR should return x let x = U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); let product = x.mul_wide(&Modulus2::R); assert_eq!( montgomery_reduction::<{ Modulus2::LIMBS }>( &product, &Modulus2::MODULUS, Modulus2::MOD_NEG_INV ), x ); } #[test] fn test_reducing_xr2_wide() { // Reducing xR^2 should return xR let x = U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); let product = x.mul_wide(&Modulus2::R2); // Computing xR mod modulus without Montgomery reduction let (lo, hi) = x.mul_wide(&Modulus2::R); let c = hi.concat(&lo); let red = c.rem(&NonZero::new(U256::ZERO.concat(&Modulus2::MODULUS)).unwrap()); let (hi, lo) = red.split(); assert_eq!(hi, Uint::ZERO); assert_eq!( montgomery_reduction::<{ Modulus2::LIMBS }>( &product, &Modulus2::MODULUS, Modulus2::MOD_NEG_INV ), lo ); } #[test] fn test_new_retrieve() { let x = U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); let x_mod = Residue::::new(&x); // Confirm that when creating a Modular and retrieving the value, that it equals the original assert_eq!(x, x_mod.retrieve()); } #[test] fn test_residue_macro() { let x = U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56"); assert_eq!( Residue::::new(&x), const_residue!(x, Modulus2) ); } } crypto-bigint-0.5.2/src/uint/mul.rs000064400000000000000000000237371046102023000153470ustar 00000000000000//! [`Uint`] addition operations. use crate::{Checked, CheckedMul, Concat, Limb, Uint, WideWord, Word, Wrapping, Zero}; use core::ops::{Mul, MulAssign}; use subtle::CtOption; impl Uint { /// Compute "wide" multiplication, with a product twice the size of the input. /// /// Returns a tuple containing the `(lo, hi)` components of the product. /// /// # Ordering note /// /// Releases of `crypto-bigint` prior to v0.3 used `(hi, lo)` ordering /// instead. This has been changed for better consistency with the rest of /// the APIs in this crate. /// /// For more info see: // TODO(tarcieri): use `concat` to construct a wide output pub const fn mul_wide(&self, rhs: &Self) -> (Self, Self) { let mut i = 0; let mut lo = Self::ZERO; let mut hi = Self::ZERO; // Schoolbook multiplication. // TODO(tarcieri): use Karatsuba for better performance? while i < LIMBS { let mut j = 0; let mut carry = Limb::ZERO; while j < LIMBS { let k = i + j; if k >= LIMBS { let (n, c) = hi.limbs[k - LIMBS].mac(self.limbs[i], rhs.limbs[j], carry); hi.limbs[k - LIMBS] = n; carry = c; } else { let (n, c) = lo.limbs[k].mac(self.limbs[i], rhs.limbs[j], carry); lo.limbs[k] = n; carry = c; } j += 1; } hi.limbs[i + j - LIMBS] = carry; i += 1; } (lo, hi) } /// Perform saturating multiplication, returning `MAX` on overflow. pub const fn saturating_mul(&self, rhs: &Self) -> Self { let (res, overflow) = self.mul_wide(rhs); let mut i = 0; let mut accumulator = 0; while i < LIMBS { accumulator |= overflow.limbs[i].0; i += 1; } if accumulator == 0 { res } else { Self::MAX } } /// Perform wrapping multiplication, discarding overflow. pub const fn wrapping_mul(&self, rhs: &Self) -> Self { self.mul_wide(rhs).0 } /// Square self, returning a concatenated "wide" result. pub fn square(&self) -> ::Output where Self: Concat, { let (lo, hi) = self.square_wide(); hi.concat(&lo) } /// Square self, returning a "wide" result in two parts as (lo, hi). pub const fn square_wide(&self) -> (Self, Self) { // Translated from https://github.com/ucbrise/jedi-pairing/blob/c4bf151/include/core/bigint.hpp#L410 // // Permission to relicense the resulting translation as Apache 2.0 + MIT was given // by the original author Sam Kumar: https://github.com/RustCrypto/crypto-bigint/pull/133#discussion_r1056870411 let mut lo = Self::ZERO; let mut hi = Self::ZERO; // Schoolbook multiplication, but only considering half of the multiplication grid let mut i = 1; while i < LIMBS { let mut j = 0; let mut carry = Limb::ZERO; while j < i { let k = i + j; if k >= LIMBS { let (n, c) = hi.limbs[k - LIMBS].mac(self.limbs[i], self.limbs[j], carry); hi.limbs[k - LIMBS] = n; carry = c; } else { let (n, c) = lo.limbs[k].mac(self.limbs[i], self.limbs[j], carry); lo.limbs[k] = n; carry = c; } j += 1; } if (2 * i) < LIMBS { lo.limbs[2 * i] = carry; } else { hi.limbs[2 * i - LIMBS] = carry; } i += 1; } // Double the current result, this accounts for the other half of the multiplication grid. // TODO: The top word is empty so we can also use a special purpose shl. (lo, hi) = Self::shl_vartime_wide((lo, hi), 1); // Handle the diagonal of the multiplication grid, which finishes the multiplication grid. let mut carry = Limb::ZERO; let mut i = 0; while i < LIMBS { if (i * 2) < LIMBS { let (n, c) = lo.limbs[i * 2].mac(self.limbs[i], self.limbs[i], carry); lo.limbs[i * 2] = n; carry = c; } else { let (n, c) = hi.limbs[i * 2 - LIMBS].mac(self.limbs[i], self.limbs[i], carry); hi.limbs[i * 2 - LIMBS] = n; carry = c; } if (i * 2 + 1) < LIMBS { let n = lo.limbs[i * 2 + 1].0 as WideWord + carry.0 as WideWord; lo.limbs[i * 2 + 1] = Limb(n as Word); carry = Limb((n >> Word::BITS) as Word); } else { let n = hi.limbs[i * 2 + 1 - LIMBS].0 as WideWord + carry.0 as WideWord; hi.limbs[i * 2 + 1 - LIMBS] = Limb(n as Word); carry = Limb((n >> Word::BITS) as Word); } i += 1; } (lo, hi) } } impl CheckedMul<&Uint> for Uint { type Output = Self; fn checked_mul(&self, rhs: &Self) -> CtOption { let (lo, hi) = self.mul_wide(rhs); CtOption::new(lo, hi.is_zero()) } } impl Mul for Wrapping> { type Output = Self; fn mul(self, rhs: Self) -> Wrapping> { Wrapping(self.0.wrapping_mul(&rhs.0)) } } impl Mul<&Wrapping>> for Wrapping> { type Output = Wrapping>; fn mul(self, rhs: &Wrapping>) -> Wrapping> { Wrapping(self.0.wrapping_mul(&rhs.0)) } } impl Mul>> for &Wrapping> { type Output = Wrapping>; fn mul(self, rhs: Wrapping>) -> Wrapping> { Wrapping(self.0.wrapping_mul(&rhs.0)) } } impl Mul<&Wrapping>> for &Wrapping> { type Output = Wrapping>; fn mul(self, rhs: &Wrapping>) -> Wrapping> { Wrapping(self.0.wrapping_mul(&rhs.0)) } } impl MulAssign for Wrapping> { fn mul_assign(&mut self, other: Self) { *self = *self * other; } } impl MulAssign<&Wrapping>> for Wrapping> { fn mul_assign(&mut self, other: &Self) { *self = *self * other; } } impl Mul for Checked> { type Output = Self; fn mul(self, rhs: Self) -> Checked> { Checked(self.0.and_then(|a| rhs.0.and_then(|b| a.checked_mul(&b)))) } } impl Mul<&Checked>> for Checked> { type Output = Checked>; fn mul(self, rhs: &Checked>) -> Checked> { Checked(self.0.and_then(|a| rhs.0.and_then(|b| a.checked_mul(&b)))) } } impl Mul>> for &Checked> { type Output = Checked>; fn mul(self, rhs: Checked>) -> Checked> { Checked(self.0.and_then(|a| rhs.0.and_then(|b| a.checked_mul(&b)))) } } impl Mul<&Checked>> for &Checked> { type Output = Checked>; fn mul(self, rhs: &Checked>) -> Checked> { Checked(self.0.and_then(|a| rhs.0.and_then(|b| a.checked_mul(&b)))) } } impl MulAssign for Checked> { fn mul_assign(&mut self, other: Self) { *self = *self * other; } } impl MulAssign<&Checked>> for Checked> { fn mul_assign(&mut self, other: &Self) { *self = *self * other; } } #[cfg(test)] mod tests { use crate::{CheckedMul, Zero, U256, U64}; #[test] fn mul_wide_zero_and_one() { assert_eq!(U64::ZERO.mul_wide(&U64::ZERO), (U64::ZERO, U64::ZERO)); assert_eq!(U64::ZERO.mul_wide(&U64::ONE), (U64::ZERO, U64::ZERO)); assert_eq!(U64::ONE.mul_wide(&U64::ZERO), (U64::ZERO, U64::ZERO)); assert_eq!(U64::ONE.mul_wide(&U64::ONE), (U64::ONE, U64::ZERO)); } #[test] fn mul_wide_lo_only() { let primes: &[u32] = &[3, 5, 17, 257, 65537]; for &a_int in primes { for &b_int in primes { let (lo, hi) = U64::from_u32(a_int).mul_wide(&U64::from_u32(b_int)); let expected = U64::from_u64(a_int as u64 * b_int as u64); assert_eq!(lo, expected); assert!(bool::from(hi.is_zero())); } } } #[test] fn checked_mul_ok() { let n = U64::from_u32(0xffff_ffff); assert_eq!( n.checked_mul(&n).unwrap(), U64::from_u64(0xffff_fffe_0000_0001) ); } #[test] fn checked_mul_overflow() { let n = U64::from_u64(0xffff_ffff_ffff_ffff); assert!(bool::from(n.checked_mul(&n).is_none())); } #[test] fn saturating_mul_no_overflow() { let n = U64::from_u8(8); assert_eq!(n.saturating_mul(&n), U64::from_u8(64)); } #[test] fn saturating_mul_overflow() { let a = U64::from(0xffff_ffff_ffff_ffffu64); let b = U64::from(2u8); assert_eq!(a.saturating_mul(&b), U64::MAX); } #[test] fn square() { let n = U64::from_u64(0xffff_ffff_ffff_ffff); let (hi, lo) = n.square().split(); assert_eq!(lo, U64::from_u64(1)); assert_eq!(hi, U64::from_u64(0xffff_ffff_ffff_fffe)); } #[test] fn square_larger() { let n = U256::MAX; let (hi, lo) = n.square().split(); assert_eq!(lo, U256::ONE); assert_eq!(hi, U256::MAX.wrapping_sub(&U256::ONE)); } } crypto-bigint-0.5.2/src/uint/mul_mod.rs000064400000000000000000000121101046102023000161650ustar 00000000000000//! [`Uint`] multiplication modulus operations. use crate::{Limb, Uint, WideWord, Word}; impl Uint { /// Computes `self * rhs mod p` in constant time for the special modulus /// `p = MAX+1-c` where `c` is small enough to fit in a single [`Limb`]. /// For the modulus reduction, this function implements Algorithm 14.47 from /// the "Handbook of Applied Cryptography", by A. Menezes, P. van Oorschot, /// and S. Vanstone, CRC Press, 1996. pub const fn mul_mod_special(&self, rhs: &Self, c: Limb) -> Self { // We implicitly assume `LIMBS > 0`, because `Uint<0>` doesn't compile. // Still the case `LIMBS == 1` needs special handling. if LIMBS == 1 { let prod = self.limbs[0].0 as WideWord * rhs.limbs[0].0 as WideWord; let reduced = prod % Word::MIN.wrapping_sub(c.0) as WideWord; return Self::from_word(reduced as Word); } let (lo, hi) = self.mul_wide(rhs); // Now use Algorithm 14.47 for the reduction let (lo, carry) = mac_by_limb(&lo, &hi, c, Limb::ZERO); let (lo, carry) = { let rhs = (carry.0 + 1) as WideWord * c.0 as WideWord; lo.adc(&Self::from_wide_word(rhs), Limb::ZERO) }; let (lo, _) = { let rhs = carry.0.wrapping_sub(1) & c.0; lo.sbb(&Self::from_word(rhs), Limb::ZERO) }; lo } } /// Computes `a + (b * c) + carry`, returning the result along with the new carry. const fn mac_by_limb( a: &Uint, b: &Uint, c: Limb, carry: Limb, ) -> (Uint, Limb) { let mut i = 0; let mut a = *a; let mut carry = carry; while i < LIMBS { let (n, c) = a.limbs[i].mac(b.limbs[i], c, carry); a.limbs[i] = n; carry = c; i += 1; } (a, carry) } #[cfg(all(test, feature = "rand"))] mod tests { use crate::{Limb, NonZero, Random, RandomMod, Uint}; use rand_core::SeedableRng; macro_rules! test_mul_mod_special { ($size:expr, $test_name:ident) => { #[test] fn $test_name() { let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); let moduli = [ NonZero::::random(&mut rng), NonZero::::random(&mut rng), ]; for special in &moduli { let p = &NonZero::new(Uint::ZERO.wrapping_sub(&Uint::from_word(special.0))) .unwrap(); let minus_one = p.wrapping_sub(&Uint::ONE); let base_cases = [ (Uint::ZERO, Uint::ZERO, Uint::ZERO), (Uint::ONE, Uint::ZERO, Uint::ZERO), (Uint::ZERO, Uint::ONE, Uint::ZERO), (Uint::ONE, Uint::ONE, Uint::ONE), (minus_one, minus_one, Uint::ONE), (minus_one, Uint::ONE, minus_one), (Uint::ONE, minus_one, minus_one), ]; for (a, b, c) in &base_cases { let x = a.mul_mod_special(&b, *special.as_ref()); assert_eq!(*c, x, "{} * {} mod {} = {} != {}", a, b, p, x, c); } for _i in 0..100 { let a = Uint::<$size>::random_mod(&mut rng, p); let b = Uint::<$size>::random_mod(&mut rng, p); let c = a.mul_mod_special(&b, *special.as_ref()); assert!(c < **p, "not reduced: {} >= {} ", c, p); let expected = { let (lo, hi) = a.mul_wide(&b); let mut prod = Uint::<{ 2 * $size }>::ZERO; prod.limbs[..$size].clone_from_slice(&lo.limbs); prod.limbs[$size..].clone_from_slice(&hi.limbs); let mut modulus = Uint::ZERO; modulus.limbs[..$size].clone_from_slice(&p.as_ref().limbs); let reduced = prod.rem(&NonZero::new(modulus).unwrap()); let mut expected = Uint::ZERO; expected.limbs[..].clone_from_slice(&reduced.limbs[..$size]); expected }; assert_eq!(c, expected, "incorrect result"); } } } }; } test_mul_mod_special!(1, mul_mod_special_1); test_mul_mod_special!(2, mul_mod_special_2); test_mul_mod_special!(3, mul_mod_special_3); test_mul_mod_special!(4, mul_mod_special_4); test_mul_mod_special!(5, mul_mod_special_5); test_mul_mod_special!(6, mul_mod_special_6); test_mul_mod_special!(7, mul_mod_special_7); test_mul_mod_special!(8, mul_mod_special_8); test_mul_mod_special!(9, mul_mod_special_9); test_mul_mod_special!(10, mul_mod_special_10); test_mul_mod_special!(11, mul_mod_special_11); test_mul_mod_special!(12, mul_mod_special_12); } crypto-bigint-0.5.2/src/uint/neg.rs000064400000000000000000000011451046102023000153100ustar 00000000000000use core::ops::Neg; use crate::{CtChoice, Uint, Wrapping}; impl Neg for Wrapping> { type Output = Self; fn neg(self) -> Self::Output { let shifted = Wrapping(self.0.shl_vartime(1)); self - shifted } } impl Uint { /// Negates based on `choice` by wrapping the integer. pub(crate) const fn conditional_wrapping_neg(&self, choice: CtChoice) -> Uint { let (shifted, _) = self.shl_1(); let negated_self = self.wrapping_sub(&shifted); Uint::ct_select(self, &negated_self, choice) } } crypto-bigint-0.5.2/src/uint/neg_mod.rs000064400000000000000000000037551046102023000161600ustar 00000000000000//! [`Uint`] negation modulus operations. use crate::{Limb, NegMod, Uint}; impl Uint { /// Computes `-a mod p` in constant time. /// Assumes `self` is in `[0, p)`. pub const fn neg_mod(&self, p: &Self) -> Self { let z = self.ct_is_nonzero(); let mut ret = p.sbb(self, Limb::ZERO).0; let mut i = 0; while i < LIMBS { // Set ret to 0 if the original value was 0, in which // case ret would be p. ret.limbs[i].0 = z.if_true(ret.limbs[i].0); i += 1; } ret } /// Computes `-a mod p` in constant time for the special modulus /// `p = MAX+1-c` where `c` is small enough to fit in a single [`Limb`]. pub const fn neg_mod_special(&self, c: Limb) -> Self { Self::ZERO.sub_mod_special(self, c) } } impl NegMod for Uint { type Output = Self; fn neg_mod(&self, p: &Self) -> Self { debug_assert!(self < p); self.neg_mod(p) } } #[cfg(test)] mod tests { use crate::U256; #[test] fn neg_mod_random() { let x = U256::from_be_hex("8d16e171674b4e6d8529edba4593802bf30b8cb161dd30aa8e550d41380007c2"); let p = U256::from_be_hex("928334a4e4be0843ec225a4c9c61df34bdc7a81513e4b6f76f2bfa3148e2e1b5"); let actual = x.neg_mod(&p); let expected = U256::from_be_hex("056c53337d72b9d666f86c9256ce5f08cabc1b63b207864ce0d6ecf010e2d9f3"); assert_eq!(expected, actual); } #[test] fn neg_mod_zero() { let x = U256::from_be_hex("0000000000000000000000000000000000000000000000000000000000000000"); let p = U256::from_be_hex("928334a4e4be0843ec225a4c9c61df34bdc7a81513e4b6f76f2bfa3148e2e1b5"); let actual = x.neg_mod(&p); let expected = U256::from_be_hex("0000000000000000000000000000000000000000000000000000000000000000"); assert_eq!(expected, actual); } } crypto-bigint-0.5.2/src/uint/rand.rs000064400000000000000000000050361046102023000154660ustar 00000000000000//! Random number generator support use super::Uint; use crate::{Limb, NonZero, Random, RandomMod}; use rand_core::CryptoRngCore; use subtle::ConstantTimeLess; impl Random for Uint { /// Generate a cryptographically secure random [`Uint`]. fn random(mut rng: &mut impl CryptoRngCore) -> Self { let mut limbs = [Limb::ZERO; LIMBS]; for limb in &mut limbs { *limb = Limb::random(&mut rng) } limbs.into() } } impl RandomMod for Uint { /// Generate a cryptographically secure random [`Uint`] which is less than /// a given `modulus`. /// /// This function uses rejection sampling, a method which produces an /// unbiased distribution of in-range values provided the underlying /// CSRNG is unbiased, but runs in variable-time. /// /// The variable-time nature of the algorithm should not pose a security /// issue so long as the underlying random number generator is truly a /// CSRNG, where previous outputs are unrelated to subsequent /// outputs and do not reveal information about the RNG's internal state. fn random_mod(mut rng: &mut impl CryptoRngCore, modulus: &NonZero) -> Self { let mut n = Self::ZERO; let n_bits = modulus.as_ref().bits_vartime(); let n_limbs = (n_bits + Limb::BITS - 1) / Limb::BITS; let mask = Limb::MAX >> (Limb::BITS * n_limbs - n_bits); loop { for i in 0..n_limbs { n.limbs[i] = Limb::random(&mut rng); } n.limbs[n_limbs - 1] = n.limbs[n_limbs - 1] & mask; if n.ct_lt(modulus).into() { return n; } } } } #[cfg(test)] mod tests { use crate::{NonZero, RandomMod, U256}; use rand_core::SeedableRng; #[test] fn random_mod() { let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); // Ensure `random_mod` runs in a reasonable amount of time let modulus = NonZero::new(U256::from(42u8)).unwrap(); let res = U256::random_mod(&mut rng, &modulus); // Sanity check that the return value isn't zero assert_ne!(res, U256::ZERO); // Ensure `random_mod` runs in a reasonable amount of time // when the modulus is larger than 1 limb let modulus = NonZero::new(U256::from(0x10000000000000001u128)).unwrap(); let res = U256::random_mod(&mut rng, &modulus); // Sanity check that the return value isn't zero assert_ne!(res, U256::ZERO); } } crypto-bigint-0.5.2/src/uint/resize.rs000064400000000000000000000017431046102023000160440ustar 00000000000000use super::Uint; impl Uint { /// Construct a `Uint` from the unsigned integer value, /// truncating the upper bits if the value is too large to be /// represented. #[inline(always)] pub const fn resize(&self) -> Uint { let mut res = Uint::ZERO; let mut i = 0; let dim = if T < LIMBS { T } else { LIMBS }; while i < dim { res.limbs[i] = self.limbs[i]; i += 1; } res } } #[cfg(test)] mod tests { use crate::{U128, U64}; #[test] fn resize_larger() { let u = U64::from_be_hex("AAAAAAAABBBBBBBB"); let u2: U128 = u.resize(); assert_eq!(u2, U128::from_be_hex("0000000000000000AAAAAAAABBBBBBBB")); } #[test] fn resize_smaller() { let u = U128::from_be_hex("AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD"); let u2: U64 = u.resize(); assert_eq!(u2, U64::from_be_hex("CCCCCCCCDDDDDDDD")); } } crypto-bigint-0.5.2/src/uint/shl.rs000064400000000000000000000145031046102023000153270ustar 00000000000000//! [`Uint`] bitwise left shift operations. use crate::{limb::HI_BIT, CtChoice, Limb, Uint, Word}; use core::ops::{Shl, ShlAssign}; impl Uint { /// Computes `self << 1` in constant-time, returning the overflowing bit as a `CtChoice`. pub(crate) const fn shl_1(&self) -> (Self, CtChoice) { let mut shifted_bits = [0; LIMBS]; let mut i = 0; while i < LIMBS { shifted_bits[i] = self.limbs[i].0 << 1; i += 1; } let mut carry_bits = [0; LIMBS]; let mut i = 0; while i < LIMBS { carry_bits[i] = self.limbs[i].0 >> HI_BIT; i += 1; } let mut limbs = [Limb(0); LIMBS]; limbs[0] = Limb(shifted_bits[0]); let mut i = 1; while i < LIMBS { limbs[i] = Limb(shifted_bits[i] | carry_bits[i - 1]); i += 1; } (Uint::new(limbs), CtChoice::from_lsb(carry_bits[LIMBS - 1])) } /// Computes `self << shift` where `0 <= shift < Limb::BITS`, /// returning the result and the carry. #[inline(always)] pub(crate) const fn shl_limb(&self, n: usize) -> (Self, Limb) { let mut limbs = [Limb::ZERO; LIMBS]; let nz = Limb(n as Word).ct_is_nonzero(); let lshift = n as Word; let rshift = Limb::ct_select(Limb::ZERO, Limb((Limb::BITS - n) as Word), nz).0; let carry = Limb::ct_select( Limb::ZERO, Limb(self.limbs[LIMBS - 1].0.wrapping_shr(Word::BITS - n as u32)), nz, ); let mut i = LIMBS - 1; while i > 0 { let mut limb = self.limbs[i].0 << lshift; let hi = self.limbs[i - 1].0 >> rshift; limb |= nz.if_true(hi); limbs[i] = Limb(limb); i -= 1 } limbs[0] = Limb(self.limbs[0].0 << lshift); (Uint::::new(limbs), carry) } /// Computes `self << shift`. /// /// NOTE: this operation is variable time with respect to `n` *ONLY*. /// /// When used with a fixed `n`, this function is constant-time with respect /// to `self`. #[inline(always)] pub const fn shl_vartime(&self, n: usize) -> Self { let mut limbs = [Limb::ZERO; LIMBS]; if n >= Limb::BITS * LIMBS { return Self { limbs }; } let shift_num = n / Limb::BITS; let rem = n % Limb::BITS; let mut i = LIMBS; while i > shift_num { i -= 1; limbs[i] = self.limbs[i - shift_num]; } let (new_lower, _carry) = (Self { limbs }).shl_limb(rem); new_lower } /// Computes a left shift on a wide input as `(lo, hi)`. /// /// NOTE: this operation is variable time with respect to `n` *ONLY*. /// /// When used with a fixed `n`, this function is constant-time with respect /// to `self`. #[inline(always)] pub const fn shl_vartime_wide(lower_upper: (Self, Self), n: usize) -> (Self, Self) { let (lower, mut upper) = lower_upper; let new_lower = lower.shl_vartime(n); upper = upper.shl_vartime(n); if n >= Self::BITS { upper = upper.bitor(&lower.shl_vartime(n - Self::BITS)); } else { upper = upper.bitor(&lower.shr_vartime(Self::BITS - n)); } (new_lower, upper) } } impl Shl for Uint { type Output = Uint; /// NOTE: this operation is variable time with respect to `rhs` *ONLY*. /// /// When used with a fixed `rhs`, this function is constant-time with respect /// to `self`. fn shl(self, rhs: usize) -> Uint { self.shl_vartime(rhs) } } impl Shl for &Uint { type Output = Uint; /// NOTE: this operation is variable time with respect to `rhs` *ONLY*. /// /// When used with a fixed `rhs`, this function is constant-time with respect /// to `self`. fn shl(self, rhs: usize) -> Uint { self.shl_vartime(rhs) } } impl ShlAssign for Uint { /// NOTE: this operation is variable time with respect to `rhs` *ONLY*. /// /// When used with a fixed `rhs`, this function is constant-time with respect /// to `self`. fn shl_assign(&mut self, rhs: usize) { *self = self.shl_vartime(rhs) } } #[cfg(test)] mod tests { use crate::{Limb, Uint, U128, U256}; const N: U256 = U256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); const TWO_N: U256 = U256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD755DB9CD5E9140777FA4BD19A06C8282"); const FOUR_N: U256 = U256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAEABB739ABD2280EEFF497A3340D90504"); const SIXTY_FIVE: U256 = U256::from_be_hex("FFFFFFFFFFFFFFFD755DB9CD5E9140777FA4BD19A06C82820000000000000000"); const EIGHTY_EIGHT: U256 = U256::from_be_hex("FFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD03641410000000000000000000000"); const SIXTY_FOUR: U256 = U256::from_be_hex("FFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD03641410000000000000000"); #[test] fn shl_simple() { let mut t = U256::from(1u8); assert_eq!(t << 1, U256::from(2u8)); t = U256::from(3u8); assert_eq!(t << 8, U256::from(0x300u16)); } #[test] fn shl1() { assert_eq!(N << 1, TWO_N); } #[test] fn shl2() { assert_eq!(N << 2, FOUR_N); } #[test] fn shl65() { assert_eq!(N << 65, SIXTY_FIVE); } #[test] fn shl88() { assert_eq!(N << 88, EIGHTY_EIGHT); } #[test] fn shl256() { assert_eq!(N << 256, U256::default()); } #[test] fn shl64() { assert_eq!(N << 64, SIXTY_FOUR); } #[test] fn shl_wide_1_1_128() { assert_eq!( Uint::shl_vartime_wide((U128::ONE, U128::ONE), 128), (U128::ZERO, U128::ONE) ); } #[test] fn shl_wide_max_0_1() { assert_eq!( Uint::shl_vartime_wide((U128::MAX, U128::ZERO), 1), (U128::MAX.sbb(&U128::ONE, Limb::ZERO).0, U128::ONE) ); } #[test] fn shl_wide_max_max_256() { assert_eq!( Uint::shl_vartime_wide((U128::MAX, U128::MAX), 256), (U128::ZERO, U128::ZERO) ); } } crypto-bigint-0.5.2/src/uint/shr.rs000064400000000000000000000113611046102023000153340ustar 00000000000000//! [`Uint`] bitwise right shift operations. use super::Uint; use crate::{limb::HI_BIT, CtChoice, Limb}; use core::ops::{Shr, ShrAssign}; impl Uint { /// Computes `self >> 1` in constant-time, returning [`CtChoice::TRUE`] if the overflowing bit /// was set, and [`CtChoice::FALSE`] otherwise. pub(crate) const fn shr_1(&self) -> (Self, CtChoice) { let mut shifted_bits = [0; LIMBS]; let mut i = 0; while i < LIMBS { shifted_bits[i] = self.limbs[i].0 >> 1; i += 1; } let mut carry_bits = [0; LIMBS]; let mut i = 0; while i < LIMBS { carry_bits[i] = self.limbs[i].0 << HI_BIT; i += 1; } let mut limbs = [Limb(0); LIMBS]; let mut i = 0; while i < (LIMBS - 1) { limbs[i] = Limb(shifted_bits[i] | carry_bits[i + 1]); i += 1; } limbs[LIMBS - 1] = Limb(shifted_bits[LIMBS - 1]); debug_assert!(carry_bits[LIMBS - 1] == 0 || carry_bits[LIMBS - 1] == (1 << HI_BIT)); ( Uint::new(limbs), CtChoice::from_lsb(carry_bits[0] >> HI_BIT), ) } /// Computes `self >> n`. /// /// NOTE: this operation is variable time with respect to `n` *ONLY*. /// /// When used with a fixed `n`, this function is constant-time with respect /// to `self`. #[inline(always)] pub const fn shr_vartime(&self, shift: usize) -> Self { let full_shifts = shift / Limb::BITS; let small_shift = shift & (Limb::BITS - 1); let mut limbs = [Limb::ZERO; LIMBS]; if shift > Limb::BITS * LIMBS { return Self { limbs }; } let n = LIMBS - full_shifts; let mut i = 0; if small_shift == 0 { while i < n { limbs[i] = Limb(self.limbs[i + full_shifts].0); i += 1; } } else { while i < n { let mut lo = self.limbs[i + full_shifts].0 >> small_shift; if i < (LIMBS - 1) - full_shifts { lo |= self.limbs[i + full_shifts + 1].0 << (Limb::BITS - small_shift); } limbs[i] = Limb(lo); i += 1; } } Self { limbs } } /// Computes a right shift on a wide input as `(lo, hi)`. /// /// NOTE: this operation is variable time with respect to `n` *ONLY*. /// /// When used with a fixed `n`, this function is constant-time with respect /// to `self`. #[inline(always)] pub const fn shr_vartime_wide(lower_upper: (Self, Self), n: usize) -> (Self, Self) { let (mut lower, upper) = lower_upper; let new_upper = upper.shr_vartime(n); lower = lower.shr_vartime(n); if n >= Self::BITS { lower = lower.bitor(&upper.shr_vartime(n - Self::BITS)); } else { lower = lower.bitor(&upper.shl_vartime(Self::BITS - n)); } (lower, new_upper) } } impl Shr for Uint { type Output = Uint; /// NOTE: this operation is variable time with respect to `rhs` *ONLY*. /// /// When used with a fixed `rhs`, this function is constant-time with respect /// to `self`. fn shr(self, rhs: usize) -> Uint { self.shr_vartime(rhs) } } impl Shr for &Uint { type Output = Uint; /// NOTE: this operation is variable time with respect to `rhs` *ONLY*. /// /// When used with a fixed `rhs`, this function is constant-time with respect /// to `self`. fn shr(self, rhs: usize) -> Uint { self.shr_vartime(rhs) } } impl ShrAssign for Uint { fn shr_assign(&mut self, rhs: usize) { *self = self.shr_vartime(rhs); } } #[cfg(test)] mod tests { use crate::{Uint, U128, U256}; const N: U256 = U256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); const N_2: U256 = U256::from_be_hex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0"); #[test] fn shr1() { assert_eq!(N >> 1, N_2); } #[test] fn shr_wide_1_1_128() { assert_eq!( Uint::shr_vartime_wide((U128::ONE, U128::ONE), 128), (U128::ONE, U128::ZERO) ); } #[test] fn shr_wide_0_max_1() { assert_eq!( Uint::shr_vartime_wide((U128::ZERO, U128::MAX), 1), (U128::ONE << 127, U128::MAX >> 1) ); } #[test] fn shr_wide_max_max_256() { assert_eq!( Uint::shr_vartime_wide((U128::MAX, U128::MAX), 256), (U128::ZERO, U128::ZERO) ); } } crypto-bigint-0.5.2/src/uint/split.rs000064400000000000000000000035741046102023000157020ustar 00000000000000// TODO(tarcieri): use `const_evaluatable_checked` when stable to make generic around bits. macro_rules! impl_split { ($(($name:ident, $bits:expr)),+) => { $( impl $name { /// Split this number in half, returning its high and low components /// respectively. pub const fn split(&self) -> (Uint<{nlimbs!($bits) / 2}>, Uint<{nlimbs!($bits) / 2}>) { let mut lo = [Limb::ZERO; nlimbs!($bits) / 2]; let mut hi = [Limb::ZERO; nlimbs!($bits) / 2]; let mut i = 0; let mut j = 0; while j < (nlimbs!($bits) / 2) { lo[j] = self.limbs[i]; i += 1; j += 1; } j = 0; while j < (nlimbs!($bits) / 2) { hi[j] = self.limbs[i]; i += 1; j += 1; } (Uint { limbs: hi }, Uint { limbs: lo }) } } impl Split for $name { type Output = Uint<{nlimbs!($bits) / 2}>; fn split(&self) -> (Self::Output, Self::Output) { self.split() } } impl From<$name> for (Uint<{nlimbs!($bits) / 2}>, Uint<{nlimbs!($bits) / 2}>) { fn from(num: $name) -> (Uint<{nlimbs!($bits) / 2}>, Uint<{nlimbs!($bits) / 2}>) { num.split() } } )+ }; } #[cfg(test)] mod tests { use crate::{U128, U64}; #[test] fn split() { let (hi, lo) = U128::from_be_hex("00112233445566778899aabbccddeeff").split(); assert_eq!(hi, U64::from_u64(0x0011223344556677)); assert_eq!(lo, U64::from_u64(0x8899aabbccddeeff)); } } crypto-bigint-0.5.2/src/uint/sqrt.rs000064400000000000000000000111231046102023000155250ustar 00000000000000//! [`Uint`] square root operations. use super::Uint; use crate::{Limb, Word}; use subtle::{ConstantTimeEq, CtOption}; impl Uint { /// Computes √(`self`) /// Uses Brent & Zimmermann, Modern Computer Arithmetic, v0.5.9, Algorithm 1.13 /// /// Callers can check if `self` is a square by squaring the result pub const fn sqrt(&self) -> Self { let max_bits = (self.bits_vartime() + 1) >> 1; let cap = Self::ONE.shl_vartime(max_bits); let mut guess = cap; // ≥ √(`self`) let mut xn = { let q = self.wrapping_div(&guess); let t = guess.wrapping_add(&q); t.shr_vartime(1) }; // If guess increased, the initial guess was low. // Repeat until reverse course. while Uint::ct_lt(&guess, &xn).is_true_vartime() { // Sometimes an increase is too far, especially with large // powers, and then takes a long time to walk back. The upper // bound is based on bit size, so saturate on that. let le = Limb::ct_le(Limb(xn.bits_vartime() as Word), Limb(max_bits as Word)); guess = Self::ct_select(&cap, &xn, le); xn = { let q = self.wrapping_div(&guess); let t = guess.wrapping_add(&q); t.shr_vartime(1) }; } // Repeat while guess decreases. while Uint::ct_gt(&guess, &xn).is_true_vartime() && xn.ct_is_nonzero().is_true_vartime() { guess = xn; xn = { let q = self.wrapping_div(&guess); let t = guess.wrapping_add(&q); t.shr_vartime(1) }; } Self::ct_select(&Self::ZERO, &guess, self.ct_is_nonzero()) } /// Wrapped sqrt is just normal √(`self`) /// There’s no way wrapping could ever happen. /// This function exists, so that all operations are accounted for in the wrapping operations. pub const fn wrapping_sqrt(&self) -> Self { self.sqrt() } /// Perform checked sqrt, returning a [`CtOption`] which `is_some` /// only if the √(`self`)² == self pub fn checked_sqrt(&self) -> CtOption { let r = self.sqrt(); let s = r.wrapping_mul(&r); CtOption::new(r, ConstantTimeEq::ct_eq(self, &s)) } } #[cfg(test)] mod tests { use crate::{Limb, U256}; #[cfg(feature = "rand")] use { crate::{CheckedMul, Random, U512}, rand_chacha::ChaChaRng, rand_core::{RngCore, SeedableRng}, }; #[test] fn edge() { assert_eq!(U256::ZERO.sqrt(), U256::ZERO); assert_eq!(U256::ONE.sqrt(), U256::ONE); let mut half = U256::ZERO; for i in 0..half.limbs.len() / 2 { half.limbs[i] = Limb::MAX; } assert_eq!(U256::MAX.sqrt(), half,); } #[test] fn simple() { let tests = [ (4u8, 2u8), (9, 3), (16, 4), (25, 5), (36, 6), (49, 7), (64, 8), (81, 9), (100, 10), (121, 11), (144, 12), (169, 13), ]; for (a, e) in &tests { let l = U256::from(*a); let r = U256::from(*e); assert_eq!(l.sqrt(), r); assert_eq!(l.checked_sqrt().is_some().unwrap_u8(), 1u8); } } #[test] fn nonsquares() { assert_eq!(U256::from(2u8).sqrt(), U256::from(1u8)); assert_eq!(U256::from(2u8).checked_sqrt().is_some().unwrap_u8(), 0); assert_eq!(U256::from(3u8).sqrt(), U256::from(1u8)); assert_eq!(U256::from(3u8).checked_sqrt().is_some().unwrap_u8(), 0); assert_eq!(U256::from(5u8).sqrt(), U256::from(2u8)); assert_eq!(U256::from(6u8).sqrt(), U256::from(2u8)); assert_eq!(U256::from(7u8).sqrt(), U256::from(2u8)); assert_eq!(U256::from(8u8).sqrt(), U256::from(2u8)); assert_eq!(U256::from(10u8).sqrt(), U256::from(3u8)); } #[cfg(feature = "rand")] #[test] fn fuzz() { let mut rng = ChaChaRng::from_seed([7u8; 32]); for _ in 0..50 { let t = rng.next_u32() as u64; let s = U256::from(t); let s2 = s.checked_mul(&s).unwrap(); assert_eq!(s2.sqrt(), s); assert_eq!(s2.checked_sqrt().is_some().unwrap_u8(), 1); } for _ in 0..50 { let s = U256::random(&mut rng); let mut s2 = U512::ZERO; s2.limbs[..s.limbs.len()].copy_from_slice(&s.limbs); assert_eq!(s.square().sqrt(), s2); } } } crypto-bigint-0.5.2/src/uint/sub.rs000064400000000000000000000131511046102023000153300ustar 00000000000000//! [`Uint`] addition operations. use super::Uint; use crate::{Checked, CheckedSub, CtChoice, Limb, Wrapping, Zero}; use core::ops::{Sub, SubAssign}; use subtle::CtOption; impl Uint { /// Computes `a - (b + borrow)`, returning the result along with the new borrow. #[inline(always)] pub const fn sbb(&self, rhs: &Self, mut borrow: Limb) -> (Self, Limb) { let mut limbs = [Limb::ZERO; LIMBS]; let mut i = 0; while i < LIMBS { let (w, b) = self.limbs[i].sbb(rhs.limbs[i], borrow); limbs[i] = w; borrow = b; i += 1; } (Self { limbs }, borrow) } /// Perform saturating subtraction, returning `ZERO` on underflow. pub const fn saturating_sub(&self, rhs: &Self) -> Self { let (res, underflow) = self.sbb(rhs, Limb::ZERO); if underflow.0 == 0 { res } else { Self::ZERO } } /// Perform wrapping subtraction, discarding underflow and wrapping around /// the boundary of the type. pub const fn wrapping_sub(&self, rhs: &Self) -> Self { self.sbb(rhs, Limb::ZERO).0 } /// Perform wrapping subtraction, returning the truthy value as the second element of the tuple /// if an underflow has occurred. pub(crate) const fn conditional_wrapping_sub( &self, rhs: &Self, choice: CtChoice, ) -> (Self, CtChoice) { let actual_rhs = Uint::ct_select(&Uint::ZERO, rhs, choice); let (res, borrow) = self.sbb(&actual_rhs, Limb::ZERO); (res, CtChoice::from_mask(borrow.0)) } } impl CheckedSub<&Uint> for Uint { type Output = Self; fn checked_sub(&self, rhs: &Self) -> CtOption { let (result, underflow) = self.sbb(rhs, Limb::ZERO); CtOption::new(result, underflow.is_zero()) } } impl Sub for Wrapping> { type Output = Self; fn sub(self, rhs: Self) -> Wrapping> { Wrapping(self.0.wrapping_sub(&rhs.0)) } } impl Sub<&Wrapping>> for Wrapping> { type Output = Wrapping>; fn sub(self, rhs: &Wrapping>) -> Wrapping> { Wrapping(self.0.wrapping_sub(&rhs.0)) } } impl Sub>> for &Wrapping> { type Output = Wrapping>; fn sub(self, rhs: Wrapping>) -> Wrapping> { Wrapping(self.0.wrapping_sub(&rhs.0)) } } impl Sub<&Wrapping>> for &Wrapping> { type Output = Wrapping>; fn sub(self, rhs: &Wrapping>) -> Wrapping> { Wrapping(self.0.wrapping_sub(&rhs.0)) } } impl SubAssign for Wrapping> { fn sub_assign(&mut self, other: Self) { *self = *self - other; } } impl SubAssign<&Wrapping>> for Wrapping> { fn sub_assign(&mut self, other: &Self) { *self = *self - other; } } impl Sub for Checked> { type Output = Self; fn sub(self, rhs: Self) -> Checked> { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))), ) } } impl Sub<&Checked>> for Checked> { type Output = Checked>; fn sub(self, rhs: &Checked>) -> Checked> { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))), ) } } impl Sub>> for &Checked> { type Output = Checked>; fn sub(self, rhs: Checked>) -> Checked> { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))), ) } } impl Sub<&Checked>> for &Checked> { type Output = Checked>; fn sub(self, rhs: &Checked>) -> Checked> { Checked( self.0 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))), ) } } impl SubAssign for Checked> { fn sub_assign(&mut self, other: Self) { *self = *self - other; } } impl SubAssign<&Checked>> for Checked> { fn sub_assign(&mut self, other: &Self) { *self = *self - other; } } #[cfg(test)] mod tests { use crate::{CheckedSub, Limb, U128}; #[test] fn sbb_no_borrow() { let (res, borrow) = U128::ONE.sbb(&U128::ONE, Limb::ZERO); assert_eq!(res, U128::ZERO); assert_eq!(borrow, Limb::ZERO); } #[test] fn sbb_with_borrow() { let (res, borrow) = U128::ZERO.sbb(&U128::ONE, Limb::ZERO); assert_eq!(res, U128::MAX); assert_eq!(borrow, Limb::MAX); } #[test] fn wrapping_sub_no_borrow() { assert_eq!(U128::ONE.wrapping_sub(&U128::ONE), U128::ZERO); } #[test] fn wrapping_sub_with_borrow() { assert_eq!(U128::ZERO.wrapping_sub(&U128::ONE), U128::MAX); } #[test] fn checked_sub_ok() { let result = U128::ONE.checked_sub(&U128::ONE); assert_eq!(result.unwrap(), U128::ZERO); } #[test] fn checked_sub_overflow() { let result = U128::ZERO.checked_sub(&U128::ONE); assert!(!bool::from(result.is_some())); } } crypto-bigint-0.5.2/src/uint/sub_mod.rs000064400000000000000000000162561046102023000162000ustar 00000000000000//! [`Uint`] subtraction modulus operations. use crate::{Limb, SubMod, Uint}; impl Uint { /// Computes `self - rhs mod p` in constant time. /// /// Assumes `self - rhs` as unbounded signed integer is in `[-p, p)`. pub const fn sub_mod(&self, rhs: &Uint, p: &Uint) -> Uint { let (out, borrow) = self.sbb(rhs, Limb::ZERO); // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. let mask = Uint::from_words([borrow.0; LIMBS]); out.wrapping_add(&p.bitand(&mask)) } /// Returns `(self..., carry) - (rhs...) mod (p...)`, where `carry <= 1`. /// Assumes `-(p...) <= (self..., carry) - (rhs...) < (p...)`. #[inline(always)] pub(crate) const fn sub_mod_with_carry(&self, carry: Limb, rhs: &Self, p: &Self) -> Self { debug_assert!(carry.0 <= 1); let (out, borrow) = self.sbb(rhs, Limb::ZERO); // The new `borrow = Word::MAX` iff `carry == 0` and `borrow == Word::MAX`. let borrow = (!carry.0.wrapping_neg()) & borrow.0; // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. let mask = Uint::from_words([borrow; LIMBS]); out.wrapping_add(&p.bitand(&mask)) } /// Computes `self - rhs mod p` in constant time for the special modulus /// `p = MAX+1-c` where `c` is small enough to fit in a single [`Limb`]. /// /// Assumes `self - rhs` as unbounded signed integer is in `[-p, p)`. pub const fn sub_mod_special(&self, rhs: &Self, c: Limb) -> Self { let (out, borrow) = self.sbb(rhs, Limb::ZERO); // If underflow occurred, then we need to subtract `c` to account for // the underflow. This cannot underflow due to the assumption // `self - rhs >= -p`. let l = borrow.0 & c.0; out.wrapping_sub(&Uint::from_word(l)) } } impl SubMod for Uint { type Output = Self; fn sub_mod(&self, rhs: &Self, p: &Self) -> Self { debug_assert!(self < p); debug_assert!(rhs < p); self.sub_mod(rhs, p) } } #[cfg(all(test, feature = "rand"))] mod tests { use crate::{Limb, NonZero, Random, RandomMod, Uint}; use rand_core::SeedableRng; macro_rules! test_sub_mod { ($size:expr, $test_name:ident) => { #[test] fn $test_name() { let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); let moduli = [ NonZero::>::random(&mut rng), NonZero::>::random(&mut rng), ]; for p in &moduli { let base_cases = [ (1u64, 0u64, 1u64.into()), (0, 1, p.wrapping_sub(&1u64.into())), (0, 0, 0u64.into()), ]; for (a, b, c) in &base_cases { let a: Uint<$size> = (*a).into(); let b: Uint<$size> = (*b).into(); let x = a.sub_mod(&b, p); assert_eq!(*c, x, "{} - {} mod {} = {} != {}", a, b, p, x, c); } if $size > 1 { for _i in 0..100 { let a: Uint<$size> = Limb::random(&mut rng).into(); let b: Uint<$size> = Limb::random(&mut rng).into(); let (a, b) = if a < b { (b, a) } else { (a, b) }; let c = a.sub_mod(&b, p); assert!(c < **p, "not reduced"); assert_eq!(c, a.wrapping_sub(&b), "result incorrect"); } } for _i in 0..100 { let a = Uint::<$size>::random_mod(&mut rng, p); let b = Uint::<$size>::random_mod(&mut rng, p); let c = a.sub_mod(&b, p); assert!(c < **p, "not reduced: {} >= {} ", c, p); let x = a.wrapping_sub(&b); if a >= b && x < **p { assert_eq!(c, x, "incorrect result"); } } } } }; } macro_rules! test_sub_mod_special { ($size:expr, $test_name:ident) => { #[test] fn $test_name() { let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1); let moduli = [ NonZero::::random(&mut rng), NonZero::::random(&mut rng), ]; for special in &moduli { let p = &NonZero::new(Uint::ZERO.wrapping_sub(&Uint::from_word(special.0))) .unwrap(); let minus_one = p.wrapping_sub(&Uint::ONE); let base_cases = [ (Uint::ZERO, Uint::ZERO, Uint::ZERO), (Uint::ONE, Uint::ZERO, Uint::ONE), (Uint::ZERO, Uint::ONE, minus_one), (minus_one, minus_one, Uint::ZERO), (Uint::ZERO, minus_one, Uint::ONE), ]; for (a, b, c) in &base_cases { let x = a.sub_mod_special(&b, *special.as_ref()); assert_eq!(*c, x, "{} - {} mod {} = {} != {}", a, b, p, x, c); } for _i in 0..100 { let a = Uint::<$size>::random_mod(&mut rng, p); let b = Uint::<$size>::random_mod(&mut rng, p); let c = a.sub_mod_special(&b, *special.as_ref()); assert!(c < **p, "not reduced: {} >= {} ", c, p); let expected = a.sub_mod(&b, p); assert_eq!(c, expected, "incorrect result"); } } } }; } // Test requires 1-limb is capable of representing a 64-bit integer #[cfg(target_pointer_width = "64")] test_sub_mod!(1, sub1); test_sub_mod!(2, sub2); test_sub_mod!(3, sub3); test_sub_mod!(4, sub4); test_sub_mod!(5, sub5); test_sub_mod!(6, sub6); test_sub_mod!(7, sub7); test_sub_mod!(8, sub8); test_sub_mod!(9, sub9); test_sub_mod!(10, sub10); test_sub_mod!(11, sub11); test_sub_mod!(12, sub12); test_sub_mod_special!(1, sub_mod_special_1); test_sub_mod_special!(2, sub_mod_special_2); test_sub_mod_special!(3, sub_mod_special_3); test_sub_mod_special!(4, sub_mod_special_4); test_sub_mod_special!(5, sub_mod_special_5); test_sub_mod_special!(6, sub_mod_special_6); test_sub_mod_special!(7, sub_mod_special_7); test_sub_mod_special!(8, sub_mod_special_8); test_sub_mod_special!(9, sub_mod_special_9); test_sub_mod_special!(10, sub_mod_special_10); test_sub_mod_special!(11, sub_mod_special_11); test_sub_mod_special!(12, sub_mod_special_12); } crypto-bigint-0.5.2/src/uint.rs000064400000000000000000000316441046102023000145460ustar 00000000000000//! Big unsigned integers. #![allow( clippy::needless_range_loop, clippy::many_single_char_names, clippy::derive_hash_xor_eq )] #[macro_use] mod concat; #[macro_use] mod split; mod add; mod add_mod; mod bit_and; mod bit_not; mod bit_or; mod bit_xor; mod bits; mod cmp; mod div; pub(crate) mod div_limb; mod encoding; mod from; mod inv_mod; mod mul; mod mul_mod; mod neg; mod neg_mod; mod resize; mod shl; mod shr; mod sqrt; mod sub; mod sub_mod; /// Implements modular arithmetic for constant moduli. pub mod modular; #[cfg(feature = "generic-array")] mod array; #[cfg(feature = "rand_core")] mod rand; use crate::{Bounded, Concat, Encoding, Integer, Limb, Split, Word, Zero}; use core::fmt; use subtle::{Choice, ConditionallySelectable}; #[cfg(feature = "serde")] use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "zeroize")] use zeroize::DefaultIsZeroes; /// Big unsigned integer. /// /// Generic over the given number of `LIMBS` /// /// # Encoding support /// This type supports many different types of encodings, either via the /// [`Encoding`][`crate::Encoding`] trait or various `const fn` decoding and /// encoding functions that can be used with [`Uint`] constants. /// /// Optional crate features for encoding (off-by-default): /// - `generic-array`: enables [`ArrayEncoding`][`crate::ArrayEncoding`] trait which can be used to /// [`Uint`] as `GenericArray` and a [`ArrayDecoding`][`crate::ArrayDecoding`] trait which /// can be used to `GenericArray` as [`Uint`]. /// - `rlp`: support for [Recursive Length Prefix (RLP)][RLP] encoding. /// /// [RLP]: https://eth.wiki/fundamentals/rlp // TODO(tarcieri): make generic around a specified number of bits. #[derive(Copy, Clone, Hash)] pub struct Uint { /// Inner limb array. Stored from least significant to most significant. limbs: [Limb; LIMBS], } impl Uint { /// The value `0`. pub const ZERO: Self = Self::from_u8(0); /// The value `1`. pub const ONE: Self = Self::from_u8(1); /// Maximum value this [`Uint`] can express. pub const MAX: Self = Self { limbs: [Limb::MAX; LIMBS], }; /// Total size of the represented integer in bits. pub const BITS: usize = LIMBS * Limb::BITS; /// Total size of the represented integer in bytes. pub const BYTES: usize = LIMBS * Limb::BYTES; /// The number of limbs used on this platform. pub const LIMBS: usize = LIMBS; /// Const-friendly [`Uint`] constructor. pub const fn new(limbs: [Limb; LIMBS]) -> Self { Self { limbs } } /// Create a [`Uint`] from an array of [`Word`]s (i.e. word-sized unsigned /// integers). #[inline] pub const fn from_words(arr: [Word; LIMBS]) -> Self { let mut limbs = [Limb::ZERO; LIMBS]; let mut i = 0; while i < LIMBS { limbs[i] = Limb(arr[i]); i += 1; } Self { limbs } } /// Create an array of [`Word`]s (i.e. word-sized unsigned integers) from /// a [`Uint`]. #[inline] pub const fn to_words(self) -> [Word; LIMBS] { let mut arr = [0; LIMBS]; let mut i = 0; while i < LIMBS { arr[i] = self.limbs[i].0; i += 1; } arr } /// Borrow the inner limbs as an array of [`Word`]s. pub const fn as_words(&self) -> &[Word; LIMBS] { // SAFETY: `Limb` is a `repr(transparent)` newtype for `Word` #[allow(trivial_casts, unsafe_code)] unsafe { &*((&self.limbs as *const _) as *const [Word; LIMBS]) } } /// Borrow the inner limbs as a mutable array of [`Word`]s. pub fn as_words_mut(&mut self) -> &mut [Word; LIMBS] { // SAFETY: `Limb` is a `repr(transparent)` newtype for `Word` #[allow(trivial_casts, unsafe_code)] unsafe { &mut *((&mut self.limbs as *mut _) as *mut [Word; LIMBS]) } } /// Borrow the limbs of this [`Uint`]. pub const fn as_limbs(&self) -> &[Limb; LIMBS] { &self.limbs } /// Borrow the limbs of this [`Uint`] mutably. pub fn as_limbs_mut(&mut self) -> &mut [Limb; LIMBS] { &mut self.limbs } /// Convert this [`Uint`] into its inner limbs. pub const fn to_limbs(self) -> [Limb; LIMBS] { self.limbs } } impl AsRef<[Word; LIMBS]> for Uint { fn as_ref(&self) -> &[Word; LIMBS] { self.as_words() } } impl AsMut<[Word; LIMBS]> for Uint { fn as_mut(&mut self) -> &mut [Word; LIMBS] { self.as_words_mut() } } impl AsRef<[Limb]> for Uint { fn as_ref(&self) -> &[Limb] { self.as_limbs() } } impl AsMut<[Limb]> for Uint { fn as_mut(&mut self) -> &mut [Limb] { self.as_limbs_mut() } } impl ConditionallySelectable for Uint { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { let mut limbs = [Limb::ZERO; LIMBS]; for i in 0..LIMBS { limbs[i] = Limb::conditional_select(&a.limbs[i], &b.limbs[i], choice); } Self { limbs } } } impl Default for Uint { fn default() -> Self { Self::ZERO } } impl Integer for Uint { const ONE: Self = Self::ONE; const MAX: Self = Self::MAX; const BITS: usize = Self::BITS; const BYTES: usize = Self::BYTES; const LIMBS: usize = Self::LIMBS; fn is_odd(&self) -> Choice { self.limbs .first() .map(|limb| limb.is_odd()) .unwrap_or_else(|| Choice::from(0)) } } impl Zero for Uint { const ZERO: Self = Self::ZERO; } impl Bounded for Uint { const BITS: usize = Self::BITS; const BYTES: usize = Self::BYTES; } impl fmt::Debug for Uint { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Uint(0x{self:X})") } } impl fmt::Display for Uint { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::UpperHex::fmt(self, f) } } impl fmt::LowerHex for Uint { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for limb in self.limbs.iter().rev() { fmt::LowerHex::fmt(limb, f)?; } Ok(()) } } impl fmt::UpperHex for Uint { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for limb in self.limbs.iter().rev() { fmt::UpperHex::fmt(limb, f)?; } Ok(()) } } #[cfg(feature = "serde")] impl<'de, const LIMBS: usize> Deserialize<'de> for Uint where Uint: Encoding, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let mut buffer = Self::ZERO.to_le_bytes(); serdect::array::deserialize_hex_or_bin(buffer.as_mut(), deserializer)?; Ok(Self::from_le_bytes(buffer)) } } #[cfg(feature = "serde")] impl Serialize for Uint where Uint: Encoding, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serdect::array::serialize_hex_lower_or_bin(&Encoding::to_le_bytes(self), serializer) } } #[cfg(feature = "zeroize")] impl DefaultIsZeroes for Uint {} // TODO(tarcieri): use `const_evaluatable_checked` when stable to make generic around bits. macro_rules! impl_uint_aliases { ($(($name:ident, $bits:expr, $doc:expr)),+) => { $( #[doc = $doc] #[doc="unsigned big integer."] pub type $name = Uint<{nlimbs!($bits)}>; impl Encoding for $name { type Repr = [u8; $bits / 8]; #[inline] fn from_be_bytes(bytes: Self::Repr) -> Self { Self::from_be_slice(&bytes) } #[inline] fn from_le_bytes(bytes: Self::Repr) -> Self { Self::from_le_slice(&bytes) } #[inline] fn to_be_bytes(&self) -> Self::Repr { let mut result = [0u8; $bits / 8]; self.write_be_bytes(&mut result); result } #[inline] fn to_le_bytes(&self) -> Self::Repr { let mut result = [0u8; $bits / 8]; self.write_le_bytes(&mut result); result } } )+ }; } // TODO(tarcieri): use `const_evaluatable_checked` when stable to make generic around bits. impl_uint_aliases! { (U64, 64, "64-bit"), (U128, 128, "128-bit"), (U192, 192, "192-bit"), (U256, 256, "256-bit"), (U320, 320, "320-bit"), (U384, 384, "384-bit"), (U448, 448, "448-bit"), (U512, 512, "512-bit"), (U576, 576, "576-bit"), (U640, 640, "640-bit"), (U768, 768, "768-bit"), (U896, 896, "896-bit"), (U1024, 1024, "1024-bit"), (U1280, 1280, "1280-bit"), (U1536, 1536, "1536-bit"), (U1792, 1792, "1792-bit"), (U2048, 2048, "2048-bit"), (U3072, 3072, "3072-bit"), (U3584, 3584, "3584-bit"), (U4096, 4096, "4096-bit"), (U6144, 6144, "6144-bit"), (U8192, 8192, "8192-bit") } #[cfg(target_pointer_width = "32")] impl_uint_aliases! { (U224, 224, "224-bit"), // For NIST P-224 (U544, 544, "544-bit") // For NIST P-521 } // TODO(tarcieri): use `const_evaluatable_checked` when stable to make generic around bits. impl_concat! { (U64, 64), (U128, 128), (U192, 192), (U256, 256), (U320, 320), (U384, 384), (U448, 448), (U512, 512), (U640, 640), (U768, 768), (U896, 896), (U1024, 1024), (U1536, 1536), (U1792, 1792), (U2048, 2048), (U3072, 3072), (U4096, 4096) } // TODO(tarcieri): use `const_evaluatable_checked` when stable to make generic around bits. impl_split! { (U128, 128), (U256, 256), (U384, 384), (U512, 512), (U640, 640), (U768, 768), (U896, 896), (U1024, 1024), (U1280, 1280), (U1536, 1536), (U1792, 1792), (U2048, 2048), (U3072, 3072), (U3584, 3584), (U4096, 4096), (U6144, 6144), (U8192, 8192) } #[cfg(test)] mod tests { use crate::{Encoding, U128}; use subtle::ConditionallySelectable; #[cfg(feature = "alloc")] use alloc::format; #[cfg(feature = "serde")] use crate::U64; #[cfg(feature = "alloc")] #[test] fn debug() { let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD"; let n = U128::from_be_hex(hex); assert_eq!( format!("{:?}", n), "Uint(0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD)" ); } #[cfg(feature = "alloc")] #[test] fn display() { let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD"; let n = U128::from_be_hex(hex); use alloc::string::ToString; assert_eq!(hex, n.to_string()); let hex = "AAAAAAAABBBBBBBB0000000000000000"; let n = U128::from_be_hex(hex); assert_eq!(hex, n.to_string()); let hex = "AAAAAAAABBBBBBBB00000000DDDDDDDD"; let n = U128::from_be_hex(hex); assert_eq!(hex, n.to_string()); let hex = "AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD"; let n = U128::from_be_hex(hex); assert_eq!(hex, n.to_string()); } #[test] fn from_bytes() { let a = U128::from_be_hex("AAAAAAAABBBBBBBB0CCCCCCCDDDDDDDD"); let be_bytes = a.to_be_bytes(); let le_bytes = a.to_le_bytes(); for i in 0..16 { assert_eq!(le_bytes[i], be_bytes[15 - i]); } let a_from_be = U128::from_be_bytes(be_bytes); let a_from_le = U128::from_le_bytes(le_bytes); assert_eq!(a_from_be, a_from_le); assert_eq!(a_from_be, a); } #[test] fn conditional_select() { let a = U128::from_be_hex("00002222444466668888AAAACCCCEEEE"); let b = U128::from_be_hex("11113333555577779999BBBBDDDDFFFF"); let select_0 = U128::conditional_select(&a, &b, 0.into()); assert_eq!(a, select_0); let select_1 = U128::conditional_select(&a, &b, 1.into()); assert_eq!(b, select_1); } #[cfg(feature = "serde")] #[test] fn serde() { const TEST: U64 = U64::from_u64(0x0011223344556677); let serialized = bincode::serialize(&TEST).unwrap(); let deserialized: U64 = bincode::deserialize(&serialized).unwrap(); assert_eq!(TEST, deserialized); } #[cfg(feature = "serde")] #[test] fn serde_owned() { const TEST: U64 = U64::from_u64(0x0011223344556677); let serialized = bincode::serialize(&TEST).unwrap(); let deserialized: U64 = bincode::deserialize_from(serialized.as_slice()).unwrap(); assert_eq!(TEST, deserialized); } } crypto-bigint-0.5.2/src/wrapping.rs000064400000000000000000000060551046102023000154140ustar 00000000000000//! Wrapping arithmetic. use crate::Zero; use core::fmt; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; #[cfg(feature = "rand_core")] use {crate::Random, rand_core::CryptoRngCore}; #[cfg(feature = "serde")] use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer}; /// Provides intentionally-wrapped arithmetic on `T`. /// /// This is analogous to [`core::num::Wrapping`] but allows this crate to /// define trait impls for this type. #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] pub struct Wrapping(pub T); impl Zero for Wrapping { const ZERO: Self = Self(T::ZERO); } impl fmt::Display for Wrapping { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } impl fmt::Binary for Wrapping { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } impl fmt::Octal for Wrapping { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } impl fmt::LowerHex for Wrapping { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } impl fmt::UpperHex for Wrapping { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } impl ConditionallySelectable for Wrapping { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Wrapping(T::conditional_select(&a.0, &b.0, choice)) } } impl ConstantTimeEq for Wrapping { fn ct_eq(&self, other: &Self) -> Choice { self.0.ct_eq(&other.0) } } #[cfg(feature = "rand_core")] impl Random for Wrapping { fn random(rng: &mut impl CryptoRngCore) -> Self { Wrapping(Random::random(rng)) } } #[cfg(feature = "serde")] impl<'de, T: Deserialize<'de>> Deserialize<'de> for Wrapping { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { Ok(Self(T::deserialize(deserializer)?)) } } #[cfg(feature = "serde")] impl Serialize for Wrapping { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.0.serialize(serializer) } } #[cfg(all(test, feature = "serde"))] mod tests { use crate::{Wrapping, U64}; #[test] fn serde() { const TEST: Wrapping = Wrapping(U64::from_u64(0x0011223344556677)); let serialized = bincode::serialize(&TEST).unwrap(); let deserialized: Wrapping = bincode::deserialize(&serialized).unwrap(); assert_eq!(TEST, deserialized); } #[test] fn serde_owned() { const TEST: Wrapping = Wrapping(U64::from_u64(0x0011223344556677)); let serialized = bincode::serialize(&TEST).unwrap(); let deserialized: Wrapping = bincode::deserialize_from(serialized.as_slice()).unwrap(); assert_eq!(TEST, deserialized); } } crypto-bigint-0.5.2/tests/const_residue.rs000064400000000000000000000004771046102023000170100ustar 00000000000000//! Test to ensure that `const_residue!` works from outside this crate. use crypto_bigint::{const_residue, impl_modulus, modular::constant_mod::ResidueParams, U64}; impl_modulus!(TestMod, U64, "30e4b8f030ab42f3"); fn _test_fun() { let base = U64::from(2u64); let _base_mod = const_residue!(base, TestMod); } crypto-bigint-0.5.2/tests/impl_modulus.rs000064400000000000000000000002421046102023000166410ustar 00000000000000//! Test to ensure that `impl_modulus!` works from outside this crate. use crypto_bigint::{impl_modulus, U64}; impl_modulus!(TestMod, U64, "30e4b8f030ab42f3"); crypto-bigint-0.5.2/tests/proptests.rs000064400000000000000000000175631046102023000162110ustar 00000000000000//! Equivalence tests between `num-bigint` and `crypto-bigint` use crypto_bigint::{ modular::runtime_mod::{DynResidue, DynResidueParams}, Encoding, Limb, NonZero, Word, U256, }; use num_bigint::BigUint; use num_integer::Integer; use num_traits::identities::Zero; use proptest::prelude::*; use std::mem; /// Example prime number (NIST P-256 curve order) const P: U256 = U256::from_be_hex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"); fn to_biguint(uint: &U256) -> BigUint { BigUint::from_bytes_le(uint.to_le_bytes().as_ref()) } fn to_uint(big_uint: BigUint) -> U256 { let mut input = [0u8; U256::BYTES]; let encoded = big_uint.to_bytes_le(); let l = encoded.len().min(U256::BYTES); input[..l].copy_from_slice(&encoded[..l]); U256::from_le_slice(&input) } prop_compose! { fn uint()(bytes in any::<[u8; 32]>()) -> U256 { U256::from_le_slice(&bytes) } } prop_compose! { fn uint_mod_p(p: U256)(a in uint()) -> U256 { a.wrapping_rem(&p) } } prop_compose! { fn nonzero_limb()(x in any::()) -> Limb { if x == 0 { Limb::from(1u32) } else {Limb::from(x)} } } proptest! { #[test] fn roundtrip(a in uint()) { assert_eq!(a, to_uint(to_biguint(&a))); } #[test] fn shl_vartime(a in uint(), shift in any::()) { let a_bi = to_biguint(&a); let expected = to_uint(a_bi << shift); let actual = a.shl_vartime(shift as usize); assert_eq!(expected, actual); } #[test] fn wrapping_add(a in uint(), b in uint()) { let a_bi = to_biguint(&a); let b_bi = to_biguint(&b); let expected = to_uint(a_bi + b_bi); let actual = a.wrapping_add(&b); assert_eq!(expected, actual); } #[test] fn add_mod_nist_p256(a in uint_mod_p(P), b in uint_mod_p(P)) { assert!(a < P); assert!(b < P); let a_bi = to_biguint(&a); let b_bi = to_biguint(&b); let p_bi = to_biguint(&P); let expected = to_uint((a_bi + b_bi) % p_bi); let actual = a.add_mod(&b, &P); assert!(expected < P); assert!(actual < P); assert_eq!(expected, actual); } #[test] fn sub_mod_nist_p256(mut a in uint_mod_p(P), mut b in uint_mod_p(P)) { if b > a { mem::swap(&mut a, &mut b); } assert!(a < P); assert!(b < P); let a_bi = to_biguint(&a); let b_bi = to_biguint(&b); let p_bi = to_biguint(&P); let expected = to_uint((a_bi - b_bi) % p_bi); let actual = a.sub_mod(&b, &P); assert!(expected < P); assert!(actual < P); assert_eq!(expected, actual); } #[test] fn wrapping_sub(mut a in uint(), mut b in uint()) { if b > a { mem::swap(&mut a, &mut b); } let a_bi = to_biguint(&a); let b_bi = to_biguint(&b); let expected = to_uint(a_bi - b_bi); let actual = a.wrapping_sub(&b); assert_eq!(expected, actual); } #[test] fn wrapping_mul(a in uint(), b in uint()) { let a_bi = to_biguint(&a); let b_bi = to_biguint(&b); let expected = to_uint(a_bi * b_bi); let actual = a.wrapping_mul(&b); assert_eq!(expected, actual); } #[test] fn wrapping_div(a in uint(), b in uint()) { let a_bi = to_biguint(&a); let b_bi = to_biguint(&b); if !b_bi.is_zero() { let expected = to_uint(a_bi / b_bi); let actual = a.wrapping_div(&b); assert_eq!(expected, actual); } } #[test] fn div_rem_limb(a in uint(), b in nonzero_limb()) { let a_bi = to_biguint(&a); let b_bi = to_biguint(&U256::from(b)); let (expected_quo, expected_rem) = a_bi.div_rem(&b_bi); let (actual_quo, actual_rem) = a.div_rem_limb(NonZero::new(b).unwrap()); assert_eq!(to_uint(expected_quo), actual_quo); assert_eq!(to_uint(expected_rem), U256::from(actual_rem)); } #[test] fn div_rem_limb_min_max(a in uint()) { let a_bi = to_biguint(&a); for b in [Limb::from(1u32), Limb::MAX] { let b_bi = to_biguint(&U256::from(b)); let (expected_quo, expected_rem) = a_bi.div_rem(&b_bi); let (actual_quo, actual_rem) = a.div_rem_limb(NonZero::new(b).unwrap()); assert_eq!(to_uint(expected_quo), actual_quo); assert_eq!(to_uint(expected_rem), U256::from(actual_rem)); } } #[test] fn wrapping_rem(a in uint(), b in uint()) { let a_bi = to_biguint(&a); let b_bi = to_biguint(&b); if b_bi.is_zero() { let expected = to_uint(a_bi % b_bi); let actual = a.wrapping_rem(&b); assert_eq!(expected, actual); } } #[test] fn wrapping_sqrt(a in uint()) { let a_bi = to_biguint(&a); let expected = to_uint(a_bi.sqrt()); let actual = a.wrapping_sqrt(); assert_eq!(expected, actual); } #[test] fn wrapping_or(a in uint(), b in uint()) { let a_bi = to_biguint(&a); let b_bi = to_biguint(&b); if !b_bi.is_zero() { let expected = to_uint(a_bi | b_bi); let actual = a.wrapping_or(&b); assert_eq!(expected, actual); } } #[test] fn wrapping_and(a in uint(), b in uint()) { let a_bi = to_biguint(&a); let b_bi = to_biguint(&b); if !b_bi.is_zero() { let expected = to_uint(a_bi & b_bi); let actual = a.wrapping_and(&b); assert_eq!(expected, actual); } } #[test] fn wrapping_xor(a in uint(), b in uint()) { let a_bi = to_biguint(&a); let b_bi = to_biguint(&b); if !b_bi.is_zero() { let expected = to_uint(a_bi ^ b_bi); let actual = a.wrapping_xor(&b); assert_eq!(expected, actual); } } #[test] fn encoding(a in uint()) { assert_eq!(a, U256::from_be_bytes(a.to_be_bytes())); assert_eq!(a, U256::from_le_bytes(a.to_le_bytes())); } #[test] fn encoding_reverse(a in uint()) { let mut bytes = a.to_be_bytes(); bytes.reverse(); assert_eq!(a, U256::from_le_bytes(bytes)); let mut bytes = a.to_le_bytes(); bytes.reverse(); assert_eq!(a, U256::from_be_bytes(bytes)); } #[test] fn residue_pow(a in uint_mod_p(P), b in uint()) { let a_bi = to_biguint(&a); let b_bi = to_biguint(&b); let p_bi = to_biguint(&P); let expected = to_uint(a_bi.modpow(&b_bi, &p_bi)); let params = DynResidueParams::new(&P); let a_m = DynResidue::new(&a, params); let actual = a_m.pow(&b).retrieve(); assert_eq!(expected, actual); } #[test] fn residue_pow_bounded_exp(a in uint_mod_p(P), b in uint(), exponent_bits in any::()) { let b_masked = b & (U256::ONE << exponent_bits.into()).wrapping_sub(&U256::ONE); let a_bi = to_biguint(&a); let b_bi = to_biguint(&b_masked); let p_bi = to_biguint(&P); let expected = to_uint(a_bi.modpow(&b_bi, &p_bi)); let params = DynResidueParams::new(&P); let a_m = DynResidue::new(&a, params); let actual = a_m.pow_bounded_exp(&b, exponent_bits.into()).retrieve(); assert_eq!(expected, actual); } #[test] fn residue_div_by_2(a in uint_mod_p(P)) { let a_bi = to_biguint(&a); let p_bi = to_biguint(&P); let two = BigUint::from(2u32); let expected = if a_bi.is_even() { &a_bi / two } else { (&a_bi + &p_bi) / two }; let expected = to_uint(expected); let params = DynResidueParams::new(&P); let a_m = DynResidue::new(&a, params); let actual = a_m.div_by_2().retrieve(); assert_eq!(expected, actual); } }