chore: checkpoint before Python removal

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

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,6 @@
{
"git": {
"sha1": "98f29002552211cbd37dd09d354d1514d84158c4"
},
"path_in_vcs": ""
}

View File

@@ -0,0 +1,12 @@
version: 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

View File

@@ -0,0 +1,148 @@
name: 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@v4
- 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@v4
- 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@v4
- 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@v4
- 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@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: 1.72.0
components: clippy
- run: cargo clippy --all --all-features -- -D warnings
rustfmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- 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@v4
- 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@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- run: cargo doc --all-features

View File

@@ -0,0 +1,24 @@
name: 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@v4
- 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 }}

422
vendor/crypto-bigint/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,422 @@
# 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.5 (2023-11-18)
### Added
- Multi-exponentiation ([#248])
- `const_assert_eq!` and `const_assert_ne!` macros ([#293])
[#248]: https://github.com/RustCrypto/crypto-bigint/pull/248
[#293]: https://github.com/RustCrypto/crypto-bigint/pull/293
## 0.5.4 (2023-11-12)
### Added
- `trailing_ones[_vartime]()`, `trailing_zeros_vartime()`, `leading_zeros_vartime()` ([#282])
- Implement `ArrayEncoding` for `U832` ([#288])
### Changed
- Make `Uint::random_mod()` work identically on 32- and 64-bit targets ([#285])
[#282]: https://github.com/RustCrypto/crypto-bigint/pull/282
[#285]: https://github.com/RustCrypto/crypto-bigint/pull/285
[#288]: https://github.com/RustCrypto/crypto-bigint/pull/288
## 0.5.3 (2023-09-04)
### Added
- `BoxedUint`: heap-allocated fixed-precision integers ([#221])
- `extra-sizes` feature ([#229])
- `U4224` and `U4352` ([#233])
- Zeroizing support for `DynResidue` ([#235])
- `cmp_vartime`, `ct_cmp` ([#238])
- Expose Montgomery form in `Residue`/`DynResidue` ([#239])
- Make `Uint::pow` work with different sized exponents ([#251])
- Expose `wrapping_neg` ([#252])
- Make `concat`, `split`, and multiply work with different sized operands ([#253])
- `U16384` and `U32768` ([#255])
- `Uint::{inv_mod, inv_mod2k_vartime}` ([#263])
- `const fn` constructors for `NonZero<Uint>` and `NonZero<Limb>` ([#266])
- Constant-time `Uint::shr()` and `Uint::shl()` ([#267])
- Subtle trait impls for `DynResidue` and `DynResidueParams` ([#269])
### Changed
- Modular inversion improvements ([#263])
### Fixed
- `serdect` usage ([#222])
- Enforce valid modulus for `DynResidueParams` ([#240])
- Enforce valid modulus for `Residue` and associated macros ([#243])
- Make `Uint::{from_be_hex, from_le_hex}` constant-time ([#254])
- Remove conditionals in `Uint::saturating_add()` and `saturating_mul()` ([#256])
- More logical checks in the `Uint::random_mod()` test ([#256])
- Mark `sqrt` for renaming, to explicitly describe it as vartime ([#256])
[#221]: https://github.com/RustCrypto/crypto-bigint/pull/221
[#222]: https://github.com/RustCrypto/crypto-bigint/pull/222
[#229]: https://github.com/RustCrypto/crypto-bigint/pull/229
[#233]: https://github.com/RustCrypto/crypto-bigint/pull/233
[#235]: https://github.com/RustCrypto/crypto-bigint/pull/235
[#238]: https://github.com/RustCrypto/crypto-bigint/pull/238
[#239]: https://github.com/RustCrypto/crypto-bigint/pull/239
[#240]: https://github.com/RustCrypto/crypto-bigint/pull/240
[#243]: https://github.com/RustCrypto/crypto-bigint/pull/243
[#251]: https://github.com/RustCrypto/crypto-bigint/pull/251
[#252]: https://github.com/RustCrypto/crypto-bigint/pull/252
[#253]: https://github.com/RustCrypto/crypto-bigint/pull/253
[#254]: https://github.com/RustCrypto/crypto-bigint/pull/254
[#255]: https://github.com/RustCrypto/crypto-bigint/pull/255
[#256]: https://github.com/RustCrypto/crypto-bigint/pull/256
[#263]: https://github.com/RustCrypto/crypto-bigint/pull/263
[#266]: https://github.com/RustCrypto/crypto-bigint/pull/266
[#267]: https://github.com/RustCrypto/crypto-bigint/pull/267
[#269]: https://github.com/RustCrypto/crypto-bigint/pull/269
## 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<UInt>` ([#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

119
vendor/crypto-bigint/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,119 @@
# 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.5"
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.5"
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 = ["serdect?/alloc"]
default = ["rand"]
extra-sizes = []
rand = ["rand_core/std"]
serde = ["dep:serdect"]

201
vendor/crypto-bigint/LICENSE-APACHE vendored Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

25
vendor/crypto-bigint/LICENSE-MIT vendored Normal file
View File

@@ -0,0 +1,25 @@
Copyright (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.

79
vendor/crypto-bigint/README.md vendored Normal file
View File

@@ -0,0 +1,79 @@
# [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
- Supports `no_std`-friendly const generic stack-allocated big integers.
- 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.
## Security Notes
This crate has been [audited by NCC Group] with no significant
findings. We would like to thank [Entropy] for funding the audit.
All functions contained in the crate are designed to execute in constant
time unless explicitly specified otherwise (via a `*_vartime` name suffix).
This library is not suitable for use on processors with a variable-time
multiplication operation (e.g. short circuit on multiply-by-zero /
multiply-by-one, such as certain 32-bit PowerPC CPUs and some non-ARM
microcontrollers).
## 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
[audited by NCC Group]: https://research.nccgroup.com/2023/08/30/public-report-entropy-rust-cryptography-review/
[Entropy]: https://entropy.xyz/

17
vendor/crypto-bigint/SECURITY.md vendored Normal file
View File

@@ -0,0 +1,17 @@
# 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.

264
vendor/crypto-bigint/benches/bench.rs vendored Normal file
View File

@@ -0,0 +1,264 @@
use criterion::{
criterion_group, criterion_main, measurement::Measurement, BatchSize, BenchmarkGroup, Criterion,
};
use crypto_bigint::{
modular::runtime_mod::{DynResidue, DynResidueParams},
Limb, MultiExponentiate, NonZero, Random, Reciprocal, U128, U2048, U256,
};
use rand_core::OsRng;
fn bench_division<M: Measurement>(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<M: Measurement>(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,
)
});
for i in [1, 2, 3, 4, 10, 100] {
group.bench_function(
format!("multi_exponentiate for {i} bases, U256^U256"),
|b| {
b.iter_batched(
|| {
let bases_and_exponents: Vec<(DynResidue<{ U256::LIMBS }>, U256)> = (1..=i)
.map(|_| {
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)
})
.collect();
bases_and_exponents
},
|bases_and_exponents| {
DynResidue::<{ U256::LIMBS }>::multi_exponentiate(
bases_and_exponents.as_slice(),
)
},
BatchSize::SmallInput,
)
},
);
}
}
fn bench_montgomery_conversion<M: Measurement>(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_shifts<M: Measurement>(group: &mut BenchmarkGroup<'_, M>) {
group.bench_function("shl_vartime, small, U2048", |b| {
b.iter_batched(|| U2048::ONE, |x| x.shl_vartime(10), BatchSize::SmallInput)
});
group.bench_function("shl_vartime, large, U2048", |b| {
b.iter_batched(
|| U2048::ONE,
|x| x.shl_vartime(1024 + 10),
BatchSize::SmallInput,
)
});
group.bench_function("shl, U2048", |b| {
b.iter_batched(|| U2048::ONE, |x| x.shl(1024 + 10), BatchSize::SmallInput)
});
group.bench_function("shr, U2048", |b| {
b.iter_batched(|| U2048::ONE, |x| x.shr(1024 + 10), BatchSize::SmallInput)
});
}
fn bench_inv_mod<M: Measurement>(group: &mut BenchmarkGroup<'_, M>) {
group.bench_function("inv_odd_mod, U256", |b| {
b.iter_batched(
|| {
let m = U256::random(&mut OsRng) | U256::ONE;
loop {
let x = U256::random(&mut OsRng);
let (_, is_some) = x.inv_odd_mod(&m);
if is_some.into() {
break (x, m);
}
}
},
|(x, m)| x.inv_odd_mod(&m),
BatchSize::SmallInput,
)
});
group.bench_function("inv_mod, U256, odd modulus", |b| {
b.iter_batched(
|| {
let m = U256::random(&mut OsRng) | U256::ONE;
loop {
let x = U256::random(&mut OsRng);
let (_, is_some) = x.inv_odd_mod(&m);
if is_some.into() {
break (x, m);
}
}
},
|(x, m)| x.inv_mod(&m),
BatchSize::SmallInput,
)
});
group.bench_function("inv_mod, U256", |b| {
b.iter_batched(
|| {
let m = U256::random(&mut OsRng);
loop {
let x = U256::random(&mut OsRng);
let (_, is_some) = x.inv_mod(&m);
if is_some.into() {
break (x, m);
}
}
},
|(x, m)| x.inv_mod(&m),
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();
}
fn bench_modular_ops(c: &mut Criterion) {
let mut group = c.benchmark_group("modular ops");
bench_shifts(&mut group);
bench_inv_mod(&mut group);
group.finish();
}
criterion_group!(
benches,
bench_wrapping_ops,
bench_montgomery,
bench_modular_ops
);
criterion_main!(benches);

38
vendor/crypto-bigint/src/array.rs vendored Normal file
View File

@@ -0,0 +1,38 @@
//! 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<T> = GenericArray<u8, <T as ArrayEncoding>::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<u8> + Add + Eq + Ord + Unsigned;
/// Deserialize from a big-endian byte array.
fn from_be_byte_array(bytes: ByteArray<Self>) -> Self;
/// Deserialize from a little-endian byte array.
fn from_le_byte_array(bytes: ByteArray<Self>) -> Self;
/// Serialize to a big-endian byte array.
fn to_be_byte_array(&self) -> ByteArray<Self>;
/// Serialize to a little-endian byte array.
fn to_le_byte_array(&self) -> ByteArray<Self>;
}
/// 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;
}

3
vendor/crypto-bigint/src/boxed.rs vendored Normal file
View File

@@ -0,0 +1,3 @@
//! Heap-allocated "boxed" types.
pub(crate) mod uint;

231
vendor/crypto-bigint/src/boxed/uint.rs vendored Normal file
View File

@@ -0,0 +1,231 @@
//! Heap-allocated big unsigned integers.
mod add;
mod cmp;
use crate::{Limb, Word};
use alloc::{vec, vec::Vec};
use core::fmt;
#[cfg(feature = "zeroize")]
use zeroize::Zeroize;
/// Fixed-precision heap-allocated big unsigned integer.
///
/// Alternative to the stack-allocated [`Uint`][`crate::Uint`] but with a
/// fixed precision chosen at runtime instead of compile time.
///
/// Unlike many other heap-allocated big integer libraries, this type is not
/// arbitrary precision and will wrap at its fixed-precision rather than
/// automatically growing.
#[derive(Clone, Default)]
pub struct BoxedUint {
/// Inner limb vector. Stored from least significant to most significant.
limbs: Vec<Limb>,
}
impl BoxedUint {
/// Get the value `0`, represented as succinctly as possible.
pub fn zero() -> Self {
Self::default()
}
/// Get the value `1`, represented as succinctly as possible.
pub fn one() -> Self {
Self {
limbs: vec![Limb::ONE; 1],
}
}
/// Create a new [`BoxedUint`] with the given number of bits of precision.
///
/// Returns `None` if the number of bits is not a multiple of the
/// [`Limb`] size.
pub fn new(bits_precision: usize) -> Option<Self> {
if bits_precision == 0 || bits_precision % Limb::BITS != 0 {
return None;
}
let nlimbs = bits_precision / Limb::BITS;
Some(Self {
limbs: vec![Limb::ZERO; nlimbs],
})
}
/// Get the maximum value for a given number of bits of precision.
///
/// Returns `None` if the number of bits is not a multiple of the
/// [`Limb`] size.
pub fn max(bits_precision: usize) -> Option<Self> {
let mut ret = Self::new(bits_precision)?;
for limb in &mut ret.limbs {
*limb = Limb::MAX;
}
Some(ret)
}
/// Create a [`BoxedUint`] from an array of [`Word`]s (i.e. word-sized unsigned
/// integers).
#[inline]
pub fn from_words(words: &[Word]) -> Self {
Self {
limbs: words.iter().copied().map(Into::into).collect(),
}
}
/// Create an array of [`Word`]s (i.e. word-sized unsigned integers) from
/// a [`BoxedUint`].
#[inline]
pub fn to_words(&self) -> Vec<Word> {
self.limbs.iter().copied().map(Into::into).collect()
}
/// Borrow the inner limbs as a slice of [`Word`]s.
pub fn as_words(&self) -> &[Word] {
// SAFETY: `Limb` is a `repr(transparent)` newtype for `Word`
#[allow(trivial_casts, unsafe_code)]
unsafe {
&*((self.limbs.as_slice() as *const _) as *const [Word])
}
}
/// Borrow the inner limbs as a mutable array of [`Word`]s.
pub fn as_words_mut(&mut self) -> &mut [Word] {
// SAFETY: `Limb` is a `repr(transparent)` newtype for `Word`
#[allow(trivial_casts, unsafe_code)]
unsafe {
&mut *((self.limbs.as_mut_slice() as *mut _) as *mut [Word])
}
}
/// Borrow the limbs of this [`BoxedUint`].
pub fn as_limbs(&self) -> &[Limb] {
self.limbs.as_ref()
}
/// Borrow the limbs of this [`BoxedUint`] mutably.
pub fn as_limbs_mut(&mut self) -> &mut [Limb] {
self.limbs.as_mut()
}
/// Convert this [`BoxedUint`] into its inner limbs.
pub fn to_limbs(&self) -> Vec<Limb> {
self.limbs.clone()
}
/// Convert this [`BoxedUint`] into its inner limbs.
pub fn into_limbs(self) -> Vec<Limb> {
self.limbs
}
/// Get the precision of this [`BoxedUint`] in bits.
pub fn bits(&self) -> usize {
self.limbs.len() * Limb::BITS
}
/// Sort two [`BoxedUint`]s by precision, returning a tuple of the shorter
/// followed by the longer, or the original order if their precision is
/// equal.
fn sort_by_precision<'a>(a: &'a Self, b: &'a Self) -> (&'a Self, &'a Self) {
if a.limbs.len() <= b.limbs.len() {
(a, b)
} else {
(b, a)
}
}
/// Perform a carry chain-like operation over the limbs of the inputs,
/// constructing a result from the returned limbs and carry.
///
/// If one of the two values has fewer limbs than the other, passes
/// [`Limb::ZERO`] as the value for that limb.
fn chain<F>(a: &Self, b: &Self, mut carry: Limb, f: F) -> (Self, Limb)
where
F: Fn(Limb, Limb, Limb) -> (Limb, Limb),
{
let (shorter, longer) = Self::sort_by_precision(a, b);
let mut limbs = Vec::with_capacity(longer.limbs.len());
for i in 0..longer.limbs.len() {
let &a = shorter.limbs.get(i).unwrap_or(&Limb::ZERO);
let &b = longer.limbs.get(i).unwrap_or(&Limb::ZERO);
let (limb, c) = f(a, b, carry);
limbs.push(limb);
carry = c;
}
(Self { limbs }, carry)
}
}
impl AsRef<[Word]> for BoxedUint {
fn as_ref(&self) -> &[Word] {
self.as_words()
}
}
impl AsMut<[Word]> for BoxedUint {
fn as_mut(&mut self) -> &mut [Word] {
self.as_words_mut()
}
}
impl AsRef<[Limb]> for BoxedUint {
fn as_ref(&self) -> &[Limb] {
self.as_limbs()
}
}
impl AsMut<[Limb]> for BoxedUint {
fn as_mut(&mut self) -> &mut [Limb] {
self.as_limbs_mut()
}
}
impl fmt::Debug for BoxedUint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "BoxedUint(0x{self:X})")
}
}
impl fmt::Display for BoxedUint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::UpperHex::fmt(self, f)
}
}
impl fmt::LowerHex for BoxedUint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.limbs.is_empty() {
return fmt::LowerHex::fmt(&Limb::ZERO, f);
}
for limb in self.limbs.iter().rev() {
fmt::LowerHex::fmt(limb, f)?;
}
Ok(())
}
}
impl fmt::UpperHex for BoxedUint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.limbs.is_empty() {
return fmt::LowerHex::fmt(&Limb::ZERO, f);
}
for limb in self.limbs.iter().rev() {
fmt::UpperHex::fmt(limb, f)?;
}
Ok(())
}
}
#[cfg(feature = "zeroize")]
impl Zeroize for BoxedUint {
fn zeroize(&mut self) {
self.limbs.zeroize();
}
}

View File

@@ -0,0 +1,62 @@
//! [`BoxedUint`] addition operations.
use crate::{BoxedUint, CheckedAdd, Limb, Zero};
use subtle::CtOption;
impl BoxedUint {
/// Computes `a + b + carry`, returning the result along with the new carry.
#[inline(always)]
pub fn adc(&self, rhs: &Self, carry: Limb) -> (Self, Limb) {
Self::chain(self, rhs, carry, |a, b, c| a.adc(b, c))
}
/// Perform wrapping addition, discarding overflow.
pub fn wrapping_add(&self, rhs: &Self) -> Self {
self.adc(rhs, Limb::ZERO).0
}
}
impl CheckedAdd<&BoxedUint> for BoxedUint {
type Output = Self;
fn checked_add(&self, rhs: &Self) -> CtOption<Self> {
let (result, carry) = self.adc(rhs, Limb::ZERO);
CtOption::new(result, carry.is_zero())
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::{BoxedUint, CheckedAdd, Limb};
#[test]
fn adc_no_carry() {
let (res, carry) = BoxedUint::zero().adc(&BoxedUint::one(), Limb::ZERO);
assert_eq!(res, BoxedUint::one());
assert_eq!(carry, Limb::ZERO);
}
#[test]
fn adc_with_carry() {
let (res, carry) = BoxedUint::max(Limb::BITS)
.unwrap()
.adc(&BoxedUint::one(), Limb::ZERO);
assert_eq!(res, BoxedUint::zero());
assert_eq!(carry, Limb::ONE);
}
#[test]
fn checked_add_ok() {
let result = BoxedUint::zero().checked_add(&BoxedUint::one());
assert_eq!(result.unwrap(), BoxedUint::one());
}
#[test]
fn checked_add_overflow() {
let result = BoxedUint::max(Limb::BITS)
.unwrap()
.checked_add(&BoxedUint::one());
assert!(!bool::from(result.is_some()));
}
}

View File

@@ -0,0 +1,47 @@
//! [`BoxedUint`] comparisons.
//!
//! By default these are all constant-time and use the `subtle` crate.
use super::BoxedUint;
use crate::Limb;
use subtle::{Choice, ConstantTimeEq};
impl ConstantTimeEq for BoxedUint {
#[inline]
fn ct_eq(&self, other: &Self) -> Choice {
let (shorter, longer) = Self::sort_by_precision(self, other);
let mut ret = Choice::from(1u8);
for i in 0..longer.limbs.len() {
let a = shorter.limbs.get(i).unwrap_or(&Limb::ZERO);
let b = longer.limbs.get(i).unwrap_or(&Limb::ZERO);
ret &= a.ct_eq(b);
}
ret
}
}
impl Eq for BoxedUint {}
impl PartialEq for BoxedUint {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}
#[cfg(test)]
mod tests {
use super::BoxedUint;
use subtle::ConstantTimeEq;
#[test]
fn ct_eq() {
let a = BoxedUint::zero();
let b = BoxedUint::one();
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)));
}
}

131
vendor/crypto-bigint/src/checked.rs vendored Normal file
View File

@@ -0,0 +1,131 @@
//! 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.
#[derive(Copy, Clone, Debug)]
pub struct Checked<T>(pub CtOption<T>);
impl<T> Checked<T> {
/// Create a new checked arithmetic wrapper for the given value.
pub fn new(val: T) -> Self {
Self(CtOption::new(val, Choice::from(1)))
}
}
impl<T> Default for Checked<T>
where
T: Default,
{
fn default() -> Self {
Self::new(T::default())
}
}
impl<T: ConditionallySelectable> ConditionallySelectable for Checked<T> {
#[inline]
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self(CtOption::conditional_select(&a.0, &b.0, choice))
}
}
impl<T: ConstantTimeEq> ConstantTimeEq for Checked<T> {
#[inline]
fn ct_eq(&self, rhs: &Self) -> Choice {
self.0.ct_eq(&rhs.0)
}
}
impl<T> From<Checked<T>> for CtOption<T> {
fn from(checked: Checked<T>) -> CtOption<T> {
checked.0
}
}
impl<T> From<CtOption<T>> for Checked<T> {
fn from(ct_option: CtOption<T>) -> Checked<T> {
Checked(ct_option)
}
}
impl<T> From<Checked<T>> for Option<T> {
fn from(checked: Checked<T>) -> Option<T> {
checked.0.into()
}
}
#[cfg(feature = "serde")]
impl<'de, T: Default + Deserialize<'de>> Deserialize<'de> for Checked<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value = Option::<T>::deserialize(deserializer)?;
let choice = Choice::from(value.is_some() as u8);
Ok(Self(CtOption::new(value.unwrap_or_default(), choice)))
}
}
#[cfg(feature = "serde")]
impl<T: Copy + Serialize> Serialize for Checked<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
Option::<T>::from(self.0).serialize(serializer)
}
}
#[cfg(all(test, feature = "serde"))]
#[allow(clippy::unwrap_used)]
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<U64> = 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<U64> = 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<U64> = 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<U64> = bincode::deserialize_from(serialized.as_slice()).unwrap();
assert!(bool::from(test.ct_eq(&deserialized)));
}
}

104
vendor/crypto-bigint/src/ct_choice.rs vendored Normal file
View File

@@ -0,0 +1,104 @@
use 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())
}
/// Returns the truthy value if `value != 0`, and the falsy value otherwise.
pub(crate) const fn from_usize_being_nonzero(value: usize) -> Self {
const HI_BIT: u32 = usize::BITS - 1;
Self::from_lsb(((value | value.wrapping_neg()) >> HI_BIT) as Word)
}
/// Returns the truthy value if `x == y`, and the falsy value otherwise.
pub(crate) const fn from_usize_equality(x: usize, y: usize) -> Self {
Self::from_usize_being_nonzero(x.wrapping_sub(y)).not()
}
/// Returns the truthy value if `x < y`, and the falsy value otherwise.
pub(crate) const fn from_usize_lt(x: usize, y: usize) -> Self {
let bit = (((!x) & y) | (((!x) | y) & (x.wrapping_sub(y)))) >> (usize::BITS - 1);
Self::from_lsb(bit as Word)
}
pub(crate) const fn not(&self) -> Self {
Self(!self.0)
}
pub(crate) const fn or(&self, other: Self) -> Self {
Self(self.0 | other.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
}
pub(crate) const fn to_u8(self) -> u8 {
(self.0 as u8) & 1
}
}
impl From<CtChoice> for Choice {
fn from(choice: CtChoice) -> Self {
Choice::from(choice.to_u8())
}
}
impl From<CtChoice> 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);
}
}

217
vendor/crypto-bigint/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,217 @@
#![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(feature = "alloc")]
#[allow(unused_imports)]
#[macro_use]
extern crate alloc;
#[macro_use]
mod macros;
#[cfg(feature = "generic-array")]
mod array;
#[cfg(feature = "alloc")]
mod boxed;
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 = "alloc")]
pub use crate::boxed::uint::BoxedUint;
#[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));
}

176
vendor/crypto-bigint/src/limb.rs vendored Normal file
View File

@@ -0,0 +1,176 @@
//! Big integers are represented as an array of smaller CPU word-size integers
//! called "limbs".
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 neg;
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".
// Our PartialEq impl only differs from the default one by being constant-time, so this is safe
#[allow(clippy::derived_hash_with_manual_eq)]
#[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<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(Self(Word::deserialize(deserializer)?))
}
}
#[cfg(feature = "serde")]
impl Serialize for Limb {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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)");
}
}

180
vendor/crypto-bigint/src/limb/add.rs vendored Normal file
View File

@@ -0,0 +1,180 @@
//! 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<Self> {
let (result, carry) = self.adc(rhs, Limb::ZERO);
CtOption::new(result, carry.is_zero())
}
}
impl Add for Wrapping<Limb> {
type Output = Self;
fn add(self, rhs: Self) -> Wrapping<Limb> {
Wrapping(self.0.wrapping_add(rhs.0))
}
}
impl Add<&Wrapping<Limb>> for Wrapping<Limb> {
type Output = Wrapping<Limb>;
fn add(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb> {
Wrapping(self.0.wrapping_add(rhs.0))
}
}
impl Add<Wrapping<Limb>> for &Wrapping<Limb> {
type Output = Wrapping<Limb>;
fn add(self, rhs: Wrapping<Limb>) -> Wrapping<Limb> {
Wrapping(self.0.wrapping_add(rhs.0))
}
}
impl Add<&Wrapping<Limb>> for &Wrapping<Limb> {
type Output = Wrapping<Limb>;
fn add(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb> {
Wrapping(self.0.wrapping_add(rhs.0))
}
}
impl AddAssign for Wrapping<Limb> {
fn add_assign(&mut self, other: Self) {
*self = *self + other;
}
}
impl AddAssign<&Wrapping<Limb>> for Wrapping<Limb> {
fn add_assign(&mut self, other: &Self) {
*self = *self + other;
}
}
impl Add for Checked<Limb> {
type Output = Self;
fn add(self, rhs: Self) -> Checked<Limb> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(rhs))),
)
}
}
impl Add<&Checked<Limb>> for Checked<Limb> {
type Output = Checked<Limb>;
fn add(self, rhs: &Checked<Limb>) -> Checked<Limb> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(rhs))),
)
}
}
impl Add<Checked<Limb>> for &Checked<Limb> {
type Output = Checked<Limb>;
fn add(self, rhs: Checked<Limb>) -> Checked<Limb> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(rhs))),
)
}
}
impl Add<&Checked<Limb>> for &Checked<Limb> {
type Output = Checked<Limb>;
fn add(self, rhs: &Checked<Limb>) -> Checked<Limb> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(rhs))),
)
}
}
impl AddAssign for Checked<Limb> {
fn add_assign(&mut self, other: Self) {
*self = *self + other;
}
}
impl AddAssign<&Checked<Limb>> for Checked<Limb> {
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()));
}
}

View File

@@ -0,0 +1,21 @@
//! 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)
}
}

View File

@@ -0,0 +1,19 @@
//! 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) -> <Self as Not>::Output {
self.not()
}
}

19
vendor/crypto-bigint/src/limb/bit_or.rs vendored Normal file
View File

@@ -0,0 +1,19 @@
//! 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)
}
}

View File

@@ -0,0 +1,19 @@
//! 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)
}
}

23
vendor/crypto-bigint/src/limb/bits.rs vendored Normal file
View File

@@ -0,0 +1,23 @@
use 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
}
/// Calculate the number of trailing ones the binary representation of this number.
pub const fn trailing_ones(self) -> usize {
self.0.trailing_ones() as usize
}
}

200
vendor/crypto-bigint/src/limb/cmp.rs vendored Normal file
View File

@@ -0,0 +1,200 @@
//! 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<Ordering> {
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);
}
}

View File

@@ -0,0 +1,64 @@
//! 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::<Word>()) -> 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));
}
}
}

74
vendor/crypto-bigint/src/limb/from.rs vendored Normal file
View File

@@ -0,0 +1,74 @@
//! `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<u8>` 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<u16>` 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<u32>` 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<u64>` when stable
#[cfg(target_pointer_width = "64")]
pub const fn from_u64(n: u64) -> Self {
Limb(n)
}
}
impl From<u8> for Limb {
#[inline]
fn from(n: u8) -> Limb {
Limb(n.into())
}
}
impl From<u16> for Limb {
#[inline]
fn from(n: u16) -> Limb {
Limb(n.into())
}
}
impl From<u32> for Limb {
#[inline]
fn from(n: u32) -> Limb {
Limb(n.into())
}
}
#[cfg(target_pointer_width = "64")]
impl From<u64> for Limb {
#[inline]
fn from(n: u64) -> Limb {
Limb(n)
}
}
impl From<Limb> for Word {
#[inline]
fn from(limb: Limb) -> Word {
limb.0
}
}
impl From<Limb> for WideWord {
#[inline]
fn from(limb: Limb) -> WideWord {
limb.0.into()
}
}

195
vendor/crypto-bigint/src/limb/mul.rs vendored Normal file
View File

@@ -0,0 +1,195 @@
//! 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<Self> {
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<Limb> {
type Output = Self;
fn mul(self, rhs: Self) -> Wrapping<Limb> {
Wrapping(self.0.wrapping_mul(rhs.0))
}
}
impl Mul<&Wrapping<Limb>> for Wrapping<Limb> {
type Output = Wrapping<Limb>;
fn mul(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb> {
Wrapping(self.0.wrapping_mul(rhs.0))
}
}
impl Mul<Wrapping<Limb>> for &Wrapping<Limb> {
type Output = Wrapping<Limb>;
fn mul(self, rhs: Wrapping<Limb>) -> Wrapping<Limb> {
Wrapping(self.0.wrapping_mul(rhs.0))
}
}
impl Mul<&Wrapping<Limb>> for &Wrapping<Limb> {
type Output = Wrapping<Limb>;
fn mul(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb> {
Wrapping(self.0.wrapping_mul(rhs.0))
}
}
impl MulAssign for Wrapping<Limb> {
fn mul_assign(&mut self, other: Self) {
*self = *self * other;
}
}
impl MulAssign<&Wrapping<Limb>> for Wrapping<Limb> {
fn mul_assign(&mut self, other: &Self) {
*self = *self * other;
}
}
impl Mul for Checked<Limb> {
type Output = Self;
fn mul(self, rhs: Self) -> Checked<Limb> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(rhs))),
)
}
}
impl Mul<&Checked<Limb>> for Checked<Limb> {
type Output = Checked<Limb>;
fn mul(self, rhs: &Checked<Limb>) -> Checked<Limb> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(rhs))),
)
}
}
impl Mul<Checked<Limb>> for &Checked<Limb> {
type Output = Checked<Limb>;
fn mul(self, rhs: Checked<Limb>) -> Checked<Limb> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(rhs))),
)
}
}
impl Mul<&Checked<Limb>> for &Checked<Limb> {
type Output = Checked<Limb>;
fn mul(self, rhs: &Checked<Limb>) -> Checked<Limb> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(rhs))),
)
}
}
impl MulAssign for Checked<Limb> {
fn mul_assign(&mut self, other: Self) {
*self = *self * other;
}
}
impl MulAssign<&Checked<Limb>> for Checked<Limb> {
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()));
}
}

20
vendor/crypto-bigint/src/limb/neg.rs vendored Normal file
View File

@@ -0,0 +1,20 @@
//! Limb negation
use crate::{Limb, Wrapping};
use core::ops::Neg;
impl Neg for Wrapping<Limb> {
type Output = Self;
fn neg(self) -> Self::Output {
Self(self.0.wrapping_neg())
}
}
impl Limb {
/// Perform wrapping negation.
#[inline(always)]
pub const fn wrapping_neg(self) -> Self {
Limb(self.0.wrapping_neg())
}
}

38
vendor/crypto-bigint/src/limb/rand.rs vendored Normal file
View File

@@ -0,0 +1,38 @@
//! 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>) -> Self {
let mut bytes = <Self as Encoding>::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;
}
}
}
}

74
vendor/crypto-bigint/src/limb/shl.rs vendored Normal file
View File

@@ -0,0 +1,74 @@
//! Limb left bitshift
use crate::{Limb, Word};
use core::ops::{Shl, ShlAssign};
impl Limb {
/// Computes `self << rhs`.
/// Panics if `rhs` overflows `Limb::BITS`.
#[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<usize> 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<usize> 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));
}
}

74
vendor/crypto-bigint/src/limb/shr.rs vendored Normal file
View File

@@ -0,0 +1,74 @@
//! Limb right bitshift
use crate::{Limb, Word};
use core::ops::{Shr, ShrAssign};
impl Limb {
/// Computes `self >> rhs`.
/// Panics if `rhs` overflows `Limb::BITS`.
#[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<usize> 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<usize> 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));
}
}

182
vendor/crypto-bigint/src/limb/sub.rs vendored Normal file
View File

@@ -0,0 +1,182 @@
//! 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<Self> {
let (result, underflow) = self.sbb(rhs, Limb::ZERO);
CtOption::new(result, underflow.is_zero())
}
}
impl Sub for Wrapping<Limb> {
type Output = Self;
fn sub(self, rhs: Self) -> Wrapping<Limb> {
Wrapping(self.0.wrapping_sub(rhs.0))
}
}
impl Sub<&Wrapping<Limb>> for Wrapping<Limb> {
type Output = Wrapping<Limb>;
fn sub(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb> {
Wrapping(self.0.wrapping_sub(rhs.0))
}
}
impl Sub<Wrapping<Limb>> for &Wrapping<Limb> {
type Output = Wrapping<Limb>;
fn sub(self, rhs: Wrapping<Limb>) -> Wrapping<Limb> {
Wrapping(self.0.wrapping_sub(rhs.0))
}
}
impl Sub<&Wrapping<Limb>> for &Wrapping<Limb> {
type Output = Wrapping<Limb>;
fn sub(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb> {
Wrapping(self.0.wrapping_sub(rhs.0))
}
}
impl SubAssign for Wrapping<Limb> {
fn sub_assign(&mut self, other: Self) {
*self = *self - other;
}
}
impl SubAssign<&Wrapping<Limb>> for Wrapping<Limb> {
fn sub_assign(&mut self, other: &Self) {
*self = *self - other;
}
}
impl Sub for Checked<Limb> {
type Output = Self;
fn sub(self, rhs: Self) -> Checked<Limb> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))),
)
}
}
impl Sub<&Checked<Limb>> for Checked<Limb> {
type Output = Checked<Limb>;
fn sub(self, rhs: &Checked<Limb>) -> Checked<Limb> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))),
)
}
}
impl Sub<Checked<Limb>> for &Checked<Limb> {
type Output = Checked<Limb>;
fn sub(self, rhs: Checked<Limb>) -> Checked<Limb> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))),
)
}
}
impl Sub<&Checked<Limb>> for &Checked<Limb> {
type Output = Checked<Limb>;
fn sub(self, rhs: &Checked<Limb>) -> Checked<Limb> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))),
)
}
}
impl SubAssign for Checked<Limb> {
fn sub_assign(&mut self, other: Self) {
*self = *self - other;
}
}
impl SubAssign<&Checked<Limb>> for Checked<Limb> {
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()));
}
}

79
vendor/crypto-bigint/src/macros.rs vendored Normal file
View File

@@ -0,0 +1,79 @@
//! Macro definitions which are a part of the public API.
/// Internal implementation detail of [`const_assert_eq`] and [`const_assert_ne`].
#[doc(hidden)]
#[macro_export]
macro_rules! const_assert_n {
($n:expr, $($arg:tt)*) => {{
// TODO(tarcieri): gensym a name so it's unique per invocation of the macro?
mod __const_assert {
pub(super) struct Assert<const N: usize>;
impl<const N: usize> Assert<N> {
pub(super) const ASSERT: () = assert!($($arg)*);
}
}
__const_assert::Assert::<$n>::ASSERT
}};
}
/// Const-friendly assertion that two values are equal.
///
/// ```
/// const _: () = crypto_bigint::const_assert_eq!(0, 0, "zero equals zero");
/// ```
#[macro_export]
macro_rules! const_assert_eq {
($left:expr, $right:expr $(,)?) => (
$crate::const_assert_n!($left, $left == $right)
);
($left:expr, $right:expr, $($arg:tt)+) => (
$crate::const_assert_n!($left, $left == $right, $($arg)+)
);
}
/// Const-friendly assertion that two values are NOT equal.
///
/// ```
/// const _: () = crypto_bigint::const_assert_ne!(0, 1, "zero is NOT equal to one");
/// ```
#[macro_export]
macro_rules! const_assert_ne {
($left:expr, $right:expr $(,)?) => (
$crate::const_assert_n!($left, $left != $right)
);
($left:expr, $right:expr, $($arg:tt)+) => (
$crate::const_assert_n!($left, $left != $right, $($arg)+)
);
}
/// 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);
}
}

393
vendor/crypto-bigint/src/non_zero.rs vendored Normal file
View File

@@ -0,0 +1,393 @@
//! Wrapper type for non-zero integers.
use crate::{CtChoice, 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: Zero>(T);
impl NonZero<Limb> {
/// Creates a new non-zero limb in a const context.
/// The second return value is `FALSE` if `n` is zero, `TRUE` otherwise.
pub const fn const_new(n: Limb) -> (Self, CtChoice) {
(Self(n), n.ct_is_nonzero())
}
}
impl<const LIMBS: usize> NonZero<Uint<LIMBS>> {
/// Creates a new non-zero integer in a const context.
/// The second return value is `FALSE` if `n` is zero, `TRUE` otherwise.
pub const fn const_new(n: Uint<LIMBS>) -> (Self, CtChoice) {
(Self(n), n.ct_is_nonzero())
}
}
impl<T> NonZero<T>
where
T: Zero,
{
/// Create a new non-zero integer.
pub fn new(n: T) -> CtOption<Self> {
let is_zero = n.is_zero();
CtOption::new(Self(n), !is_zero)
}
}
impl<T> NonZero<T>
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<T> NonZero<T>
where
T: Encoding + Zero,
{
/// Decode from big endian bytes.
pub fn from_be_bytes(bytes: T::Repr) -> CtOption<Self> {
Self::new(T::from_be_bytes(bytes))
}
/// Decode from little endian bytes.
pub fn from_le_bytes(bytes: T::Repr) -> CtOption<Self> {
Self::new(T::from_le_bytes(bytes))
}
}
#[cfg(feature = "generic-array")]
impl<T> NonZero<T>
where
T: ArrayEncoding + Zero,
{
/// Decode a non-zero integer from big endian bytes.
pub fn from_be_byte_array(bytes: ByteArray<T>) -> CtOption<Self> {
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<T>) -> CtOption<Self> {
Self::new(T::from_be_byte_array(bytes))
}
}
impl<T> AsRef<T> for NonZero<T>
where
T: Zero,
{
fn as_ref(&self) -> &T {
&self.0
}
}
impl<T> ConditionallySelectable for NonZero<T>
where
T: ConditionallySelectable + Zero,
{
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self(T::conditional_select(&a.0, &b.0, choice))
}
}
impl<T> ConstantTimeEq for NonZero<T>
where
T: Zero,
{
fn ct_eq(&self, other: &Self) -> Choice {
self.0.ct_eq(&other.0)
}
}
impl<T> Deref for NonZero<T>
where
T: Zero,
{
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
#[cfg(feature = "rand_core")]
impl<T> Random for NonZero<T>
where
T: Random + Zero,
{
/// Generate a random `NonZero<T>`.
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<T> fmt::Display for NonZero<T>
where
T: fmt::Display + Zero,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl<T> fmt::Binary for NonZero<T>
where
T: fmt::Binary + Zero,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Binary::fmt(&self.0, f)
}
}
impl<T> fmt::Octal for NonZero<T>
where
T: fmt::Octal + Zero,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Octal::fmt(&self.0, f)
}
}
impl<T> fmt::LowerHex for NonZero<T>
where
T: fmt::LowerHex + Zero,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::LowerHex::fmt(&self.0, f)
}
}
impl<T> fmt::UpperHex for NonZero<T>
where
T: fmt::UpperHex + Zero,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::UpperHex::fmt(&self.0, f)
}
}
impl NonZero<Limb> {
/// Create a [`NonZero<Limb>`] from a [`NonZeroU8`] (const-friendly)
// TODO(tarcieri): replace with `const impl From<NonZeroU8>` when stable
pub const fn from_u8(n: NonZeroU8) -> Self {
Self(Limb::from_u8(n.get()))
}
/// Create a [`NonZero<Limb>`] from a [`NonZeroU16`] (const-friendly)
// TODO(tarcieri): replace with `const impl From<NonZeroU16>` when stable
pub const fn from_u16(n: NonZeroU16) -> Self {
Self(Limb::from_u16(n.get()))
}
/// Create a [`NonZero<Limb>`] from a [`NonZeroU32`] (const-friendly)
// TODO(tarcieri): replace with `const impl From<NonZeroU32>` when stable
pub const fn from_u32(n: NonZeroU32) -> Self {
Self(Limb::from_u32(n.get()))
}
/// Create a [`NonZero<Limb>`] from a [`NonZeroU64`] (const-friendly)
// TODO(tarcieri): replace with `const impl From<NonZeroU64>` when stable
#[cfg(target_pointer_width = "64")]
pub const fn from_u64(n: NonZeroU64) -> Self {
Self(Limb::from_u64(n.get()))
}
}
impl From<NonZeroU8> for NonZero<Limb> {
fn from(integer: NonZeroU8) -> Self {
Self::from_u8(integer)
}
}
impl From<NonZeroU16> for NonZero<Limb> {
fn from(integer: NonZeroU16) -> Self {
Self::from_u16(integer)
}
}
impl From<NonZeroU32> for NonZero<Limb> {
fn from(integer: NonZeroU32) -> Self {
Self::from_u32(integer)
}
}
#[cfg(target_pointer_width = "64")]
impl From<NonZeroU64> for NonZero<Limb> {
fn from(integer: NonZeroU64) -> Self {
Self::from_u64(integer)
}
}
impl<const LIMBS: usize> NonZero<Uint<LIMBS>> {
/// Create a [`NonZero<Uint>`] from a [`Uint`] (const-friendly)
pub const fn from_uint(n: Uint<LIMBS>) -> 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<Uint>`] from a [`NonZeroU8`] (const-friendly)
// TODO(tarcieri): replace with `const impl From<NonZeroU8>` when stable
pub const fn from_u8(n: NonZeroU8) -> Self {
Self(Uint::from_u8(n.get()))
}
/// Create a [`NonZero<Uint>`] from a [`NonZeroU16`] (const-friendly)
// TODO(tarcieri): replace with `const impl From<NonZeroU16>` when stable
pub const fn from_u16(n: NonZeroU16) -> Self {
Self(Uint::from_u16(n.get()))
}
/// Create a [`NonZero<Uint>`] from a [`NonZeroU32`] (const-friendly)
// TODO(tarcieri): replace with `const impl From<NonZeroU32>` when stable
pub const fn from_u32(n: NonZeroU32) -> Self {
Self(Uint::from_u32(n.get()))
}
/// Create a [`NonZero<Uint>`] from a [`NonZeroU64`] (const-friendly)
// TODO(tarcieri): replace with `const impl From<NonZeroU64>` when stable
pub const fn from_u64(n: NonZeroU64) -> Self {
Self(Uint::from_u64(n.get()))
}
/// Create a [`NonZero<Uint>`] from a [`NonZeroU128`] (const-friendly)
// TODO(tarcieri): replace with `const impl From<NonZeroU128>` when stable
pub const fn from_u128(n: NonZeroU128) -> Self {
Self(Uint::from_u128(n.get()))
}
}
impl<const LIMBS: usize> From<NonZeroU8> for NonZero<Uint<LIMBS>> {
fn from(integer: NonZeroU8) -> Self {
Self::from_u8(integer)
}
}
impl<const LIMBS: usize> From<NonZeroU16> for NonZero<Uint<LIMBS>> {
fn from(integer: NonZeroU16) -> Self {
Self::from_u16(integer)
}
}
impl<const LIMBS: usize> From<NonZeroU32> for NonZero<Uint<LIMBS>> {
fn from(integer: NonZeroU32) -> Self {
Self::from_u32(integer)
}
}
impl<const LIMBS: usize> From<NonZeroU64> for NonZero<Uint<LIMBS>> {
fn from(integer: NonZeroU64) -> Self {
Self::from_u64(integer)
}
}
impl<const LIMBS: usize> From<NonZeroU128> for NonZero<Uint<LIMBS>> {
fn from(integer: NonZeroU128) -> Self {
Self::from_u128(integer)
}
}
#[cfg(feature = "serde")]
impl<'de, T: Deserialize<'de> + Zero> Deserialize<'de> for NonZero<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
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<T: Serialize + Zero> Serialize for NonZero<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(serializer)
}
}
#[cfg(all(test, feature = "serde"))]
#[allow(clippy::unwrap_used)]
mod tests {
use crate::{NonZero, U64};
use bincode::ErrorKind;
#[test]
fn serde() {
let test =
Option::<NonZero<U64>>::from(NonZero::new(U64::from_u64(0x0011223344556677))).unwrap();
let serialized = bincode::serialize(&test).unwrap();
let deserialized: NonZero<U64> = bincode::deserialize(&serialized).unwrap();
assert_eq!(test, deserialized);
let serialized = bincode::serialize(&U64::ZERO).unwrap();
assert!(matches!(
*bincode::deserialize::<NonZero<U64>>(&serialized).unwrap_err(),
ErrorKind::Custom(message) if message == "invalid value: zero, expected a non-zero value"
));
}
#[test]
fn serde_owned() {
let test =
Option::<NonZero<U64>>::from(NonZero::new(U64::from_u64(0x0011223344556677))).unwrap();
let serialized = bincode::serialize(&test).unwrap();
let deserialized: NonZero<U64> = bincode::deserialize_from(serialized.as_slice()).unwrap();
assert_eq!(test, deserialized);
let serialized = bincode::serialize(&U64::ZERO).unwrap();
assert!(matches!(
*bincode::deserialize_from::<_, NonZero<U64>>(serialized.as_slice()).unwrap_err(),
ErrorKind::Custom(message) if message == "invalid value: zero, expected a non-zero value"
));
}
}

341
vendor/crypto-bigint/src/traits.rs vendored Normal file
View File

@@ -0,0 +1,341 @@
//! 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<Output = Self>
+ BitOr<Output = Self>
+ BitXor<Output = Self>
+ 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<NonZero<Self>, Output = Self>
+ Eq
+ From<u64>
+ Not
+ Ord
+ Rem<NonZero<Self>, Output = Self>
+ Send
+ Sized
+ Shl<usize, Output = Self>
+ Shr<usize, Output = Self>
+ 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>) -> Self;
}
/// Compute `self + rhs mod p`.
pub trait AddMod<Rhs = Self> {
/// 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<Rhs = Self> {
/// 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<Rhs = Self> {
/// 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<Rhs = Self>: 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<Self>;
}
/// Checked multiplication.
pub trait CheckedMul<Rhs = Self>: 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<Self>;
}
/// Checked subtraction.
pub trait CheckedSub<Rhs = Self>: 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<Self>;
}
/// Concatenate two numbers into a "wide" double-width value, using the `lo`
/// value as the least significant value.
pub trait Concat: ConcatMixed<Self, MixedOutput = Self::Output> {
/// Concatenated output: twice the width of `Self`.
type Output;
/// Concatenate the two halves, with `self` as most significant and `lo`
/// as the least significant.
fn concat(&self, lo: &Self) -> Self::Output {
self.concat_mixed(lo)
}
}
/// Concatenate two numbers into a "wide" combined-width value, using the `lo`
/// value as the least significant value.
pub trait ConcatMixed<Lo: ?Sized = Self> {
/// Concatenated output: combination of `Lo` and `Self`.
type MixedOutput;
/// Concatenate the two values, with `self` as most significant and `lo`
/// as the least significant.
fn concat_mixed(&self, lo: &Lo) -> Self::MixedOutput;
}
/// Split a number in half, returning the most significant half followed by
/// the least significant.
pub trait Split: SplitMixed<Self::Output, Self::Output> {
/// 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) {
self.split_mixed()
}
}
/// Split a number into parts, returning the most significant part followed by
/// the least significant.
pub trait SplitMixed<Hi, Lo> {
/// Split this number into parts, returning its high and low components
/// respectively.
fn split_mixed(&self) -> (Hi, Lo);
}
/// 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<Exponent> {
/// Raises to the `exponent` power.
fn pow(&self, exponent: &Exponent) -> Self;
}
impl<T: PowBoundedExp<Exponent>, Exponent: Bounded> Pow<Exponent> 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<Exponent> {
/// 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;
}
/// Performs modular multi-exponentiation using Montgomery's ladder.
///
/// See: Straus, E. G. Problems and solutions: Addition chains of vectors. American Mathematical Monthly 71 (1964), 806808.
pub trait MultiExponentiate<Exponent, BasesAndExponents>: Pow<Exponent> + Sized
where
BasesAndExponents: AsRef<[(Self, Exponent)]> + ?Sized,
{
/// Calculates `x1 ^ k1 * ... * xn ^ kn`.
fn multi_exponentiate(bases_and_exponents: &BasesAndExponents) -> Self;
}
impl<T, Exponent, BasesAndExponents> MultiExponentiate<Exponent, BasesAndExponents> for T
where
T: MultiExponentiateBoundedExp<Exponent, BasesAndExponents>,
Exponent: Bounded,
BasesAndExponents: AsRef<[(Self, Exponent)]> + ?Sized,
{
fn multi_exponentiate(bases_and_exponents: &BasesAndExponents) -> Self {
Self::multi_exponentiate_bounded_exp(bases_and_exponents, Exponent::BITS)
}
}
/// Performs modular multi-exponentiation using Montgomery's ladder.
/// `exponent_bits` represents the number of bits to take into account for the exponent.
///
/// See: Straus, E. G. Problems and solutions: Addition chains of vectors. American Mathematical Monthly 71 (1964), 806808.
///
/// NOTE: this value is leaked in the time pattern.
pub trait MultiExponentiateBoundedExp<Exponent, BasesAndExponents>: Pow<Exponent> + Sized
where
BasesAndExponents: AsRef<[(Self, Exponent)]> + ?Sized,
{
/// Calculates `x1 ^ k1 * ... * xn ^ kn`.
fn multi_exponentiate_bounded_exp(
bases_and_exponents: &BasesAndExponents,
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;
}

491
vendor/crypto-bigint/src/uint.rs vendored Normal file
View File

@@ -0,0 +1,491 @@
//! Stack-allocated big unsigned integers.
#![allow(clippy::needless_range_loop, clippy::many_single_char_names)]
#[macro_use]
mod macros;
mod add;
mod add_mod;
mod bit_and;
mod bit_not;
mod bit_or;
mod bit_xor;
mod bits;
mod cmp;
mod concat;
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 split;
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, Encoding, Integer, Limb, 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;
/// Stack-allocated 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<u8, N>` and a [`ArrayDecoding`][`crate::ArrayDecoding`] trait which
/// can be used to `GenericArray<u8, N>` 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.
// Our PartialEq impl only differs from the default one by being constant-time, so this is safe
#[allow(clippy::derived_hash_with_manual_eq)]
#[derive(Copy, Clone, Hash)]
pub struct Uint<const LIMBS: usize> {
/// Inner limb array. Stored from least significant to most significant.
limbs: [Limb; LIMBS],
}
impl<const LIMBS: usize> Uint<LIMBS> {
/// 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;
/// Bit size of `BITS`.
// Note: assumes the type of `BITS` is `usize`. Any way to assert that?
pub(crate) const LOG2_BITS: usize = (usize::BITS - Self::BITS.leading_zeros()) as usize;
/// 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<const LIMBS: usize> AsRef<[Word; LIMBS]> for Uint<LIMBS> {
fn as_ref(&self) -> &[Word; LIMBS] {
self.as_words()
}
}
impl<const LIMBS: usize> AsMut<[Word; LIMBS]> for Uint<LIMBS> {
fn as_mut(&mut self) -> &mut [Word; LIMBS] {
self.as_words_mut()
}
}
impl<const LIMBS: usize> AsRef<[Limb]> for Uint<LIMBS> {
fn as_ref(&self) -> &[Limb] {
self.as_limbs()
}
}
impl<const LIMBS: usize> AsMut<[Limb]> for Uint<LIMBS> {
fn as_mut(&mut self) -> &mut [Limb] {
self.as_limbs_mut()
}
}
impl<const LIMBS: usize> ConditionallySelectable for Uint<LIMBS> {
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<const LIMBS: usize> Default for Uint<LIMBS> {
fn default() -> Self {
Self::ZERO
}
}
impl<const LIMBS: usize> Integer for Uint<LIMBS> {
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<const LIMBS: usize> Zero for Uint<LIMBS> {
const ZERO: Self = Self::ZERO;
}
impl<const LIMBS: usize> Bounded for Uint<LIMBS> {
const BITS: usize = Self::BITS;
const BYTES: usize = Self::BYTES;
}
impl<const LIMBS: usize> fmt::Debug for Uint<LIMBS> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Uint(0x{self:X})")
}
}
impl<const LIMBS: usize> fmt::Display for Uint<LIMBS> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::UpperHex::fmt(self, f)
}
}
impl<const LIMBS: usize> fmt::LowerHex for Uint<LIMBS> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for limb in self.limbs.iter().rev() {
fmt::LowerHex::fmt(limb, f)?;
}
Ok(())
}
}
impl<const LIMBS: usize> fmt::UpperHex for Uint<LIMBS> {
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<LIMBS>
where
Uint<LIMBS>: Encoding,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
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<const LIMBS: usize> Serialize for Uint<LIMBS>
where
Uint<LIMBS>: Encoding,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serdect::array::serialize_hex_lower_or_bin(&Encoding::to_le_bytes(self), serializer)
}
}
#[cfg(feature = "zeroize")]
impl<const LIMBS: usize> DefaultIsZeroes for Uint<LIMBS> {}
// TODO(tarcieri): use `generic_const_exprs` 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"),
(U704, 704, "704-bit"),
(U768, 768, "768-bit"),
(U832, 832, "832-bit"),
(U896, 896, "896-bit"),
(U960, 960, "960-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"),
(U4224, 4224, "4224-bit"),
(U4352, 4352, "4352-bit"),
(U6144, 6144, "6144-bit"),
(U8192, 8192, "8192-bit"),
(U16384, 16384, "16384-bit"),
(U32768, 32768, "32768-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
}
#[cfg(target_pointer_width = "32")]
impl_uint_concat_split_even! {
U64,
}
// Implement concat and split for double-width Uint sizes: these should be
// multiples of 128 bits.
impl_uint_concat_split_even! {
U128,
U256,
U384,
U512,
U640,
U768,
U896,
U1024,
U1280,
U1536,
U1792,
U2048,
U3072,
U3584,
U4096,
U4224,
U4352,
U6144,
U8192,
U16384,
}
// Implement mixed concat and split for combinations not implemented by
// impl_uint_concat_split_even. The numbers represent the size of each
// component Uint in multiple of 64 bits. For example,
// (U256, [1, 3]) will allow splitting U256 into (U64, U192) as well as
// (U192, U64), while the (U128, U128) combination is already covered.
impl_uint_concat_split_mixed! {
(U192, [1, 2]),
(U256, [1, 3]),
(U320, [1, 2, 3, 4]),
(U384, [1, 2, 4, 5]),
(U448, [1, 2, 3, 4, 5, 6]),
(U512, [1, 2, 3, 5, 6, 7]),
(U576, [1, 2, 3, 4, 5, 6, 7, 8]),
(U640, [1, 2, 3, 4, 6, 7, 8, 9]),
(U704, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
(U768, [1, 2, 3, 4, 5, 7, 8, 9, 10, 11]),
(U832, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
(U896, [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13]),
(U960, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]),
(U1024, [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15]),
}
#[cfg(feature = "extra-sizes")]
mod extra_sizes;
#[cfg(feature = "extra-sizes")]
pub use extra_sizes::*;
#[cfg(test)]
#[allow(clippy::unwrap_used)]
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);
}
}

206
vendor/crypto-bigint/src/uint/add.rs vendored Normal file
View File

@@ -0,0 +1,206 @@
//! [`Uint`] addition operations.
use crate::{Checked, CheckedAdd, CtChoice, Limb, Uint, Wrapping, Zero};
use core::ops::{Add, AddAssign};
use subtle::CtOption;
impl<const LIMBS: usize> Uint<LIMBS> {
/// 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);
Self::ct_select(&res, &Self::MAX, CtChoice::from_lsb(overflow.0))
}
/// 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<const LIMBS: usize> CheckedAdd<&Uint<LIMBS>> for Uint<LIMBS> {
type Output = Self;
fn checked_add(&self, rhs: &Self) -> CtOption<Self> {
let (result, carry) = self.adc(rhs, Limb::ZERO);
CtOption::new(result, carry.is_zero())
}
}
impl<const LIMBS: usize> Add for Wrapping<Uint<LIMBS>> {
type Output = Self;
fn add(self, rhs: Self) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.wrapping_add(&rhs.0))
}
}
impl<const LIMBS: usize> Add<&Wrapping<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn add(self, rhs: &Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.wrapping_add(&rhs.0))
}
}
impl<const LIMBS: usize> Add<Wrapping<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn add(self, rhs: Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.wrapping_add(&rhs.0))
}
}
impl<const LIMBS: usize> Add<&Wrapping<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn add(self, rhs: &Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.wrapping_add(&rhs.0))
}
}
impl<const LIMBS: usize> AddAssign for Wrapping<Uint<LIMBS>> {
fn add_assign(&mut self, other: Self) {
*self = *self + other;
}
}
impl<const LIMBS: usize> AddAssign<&Wrapping<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
fn add_assign(&mut self, other: &Self) {
*self = *self + other;
}
}
impl<const LIMBS: usize> Add for Checked<Uint<LIMBS>> {
type Output = Self;
fn add(self, rhs: Self) -> Checked<Uint<LIMBS>> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))),
)
}
}
impl<const LIMBS: usize> Add<&Checked<Uint<LIMBS>>> for Checked<Uint<LIMBS>> {
type Output = Checked<Uint<LIMBS>>;
fn add(self, rhs: &Checked<Uint<LIMBS>>) -> Checked<Uint<LIMBS>> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))),
)
}
}
impl<const LIMBS: usize> Add<Checked<Uint<LIMBS>>> for &Checked<Uint<LIMBS>> {
type Output = Checked<Uint<LIMBS>>;
fn add(self, rhs: Checked<Uint<LIMBS>>) -> Checked<Uint<LIMBS>> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))),
)
}
}
impl<const LIMBS: usize> Add<&Checked<Uint<LIMBS>>> for &Checked<Uint<LIMBS>> {
type Output = Checked<Uint<LIMBS>>;
fn add(self, rhs: &Checked<Uint<LIMBS>>) -> Checked<Uint<LIMBS>> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))),
)
}
}
impl<const LIMBS: usize> AddAssign for Checked<Uint<LIMBS>> {
fn add_assign(&mut self, other: Self) {
*self = *self + other;
}
}
impl<const LIMBS: usize> AddAssign<&Checked<Uint<LIMBS>>> for Checked<Uint<LIMBS>> {
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 saturating_add_no_carry() {
assert_eq!(U128::ZERO.saturating_add(&U128::ONE), U128::ONE);
}
#[test]
fn saturating_add_with_carry() {
assert_eq!(U128::MAX.saturating_add(&U128::ONE), U128::MAX);
}
#[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()));
}
}

128
vendor/crypto-bigint/src/uint/add_mod.rs vendored Normal file
View File

@@ -0,0 +1,128 @@
//! [`Uint`] addition modulus operations.
use crate::{AddMod, Limb, Uint};
impl<const LIMBS: usize> Uint<LIMBS> {
/// Computes `self + rhs mod p`.
///
/// Assumes `self + rhs` as unbounded integer is `< 2p`.
pub const fn add_mod(&self, rhs: &Uint<LIMBS>, p: &Uint<LIMBS>) -> Uint<LIMBS> {
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` 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<const LIMBS: usize> AddMod for Uint<LIMBS> {
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::<Limb>::random(&mut rng),
NonZero::<Limb>::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);
}

194
vendor/crypto-bigint/src/uint/array.rs vendored Normal file
View File

@@ -0,0 +1,194 @@
//! `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 {
Self::from_be_slice(&bytes)
}
#[inline]
fn from_le_byte_array(bytes: ByteArray<Self>) -> Self {
Self::from_le_slice(&bytes)
}
#[inline]
fn to_be_byte_array(&self) -> ByteArray<Self> {
let mut result = GenericArray::default();
self.write_be_bytes(&mut result);
result
}
#[inline]
fn to_le_byte_array(&self) -> ByteArray<Self> {
let mut result = GenericArray::default();
self.write_le_bytes(&mut result);
result
}
}
impl ArrayDecoding for GenericArray<u8, $bytes> {
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 `generic_const_exprs` 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),
(U832, typenum::U104),
(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<UintEx>;
#[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);
}
}

146
vendor/crypto-bigint/src/uint/bit_and.rs vendored Normal file
View File

@@ -0,0 +1,146 @@
//! [`Uint`] bitwise and operations.
use super::Uint;
use crate::{Limb, Wrapping};
use core::ops::{BitAnd, BitAndAssign};
use subtle::{Choice, CtOption};
impl<const LIMBS: usize> Uint<LIMBS> {
/// 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<Self> {
let result = self.bitand(rhs);
CtOption::new(result, Choice::from(1))
}
}
impl<const LIMBS: usize> BitAnd for Uint<LIMBS> {
type Output = Self;
fn bitand(self, rhs: Self) -> Uint<LIMBS> {
self.bitand(&rhs)
}
}
impl<const LIMBS: usize> BitAnd<&Uint<LIMBS>> for Uint<LIMBS> {
type Output = Uint<LIMBS>;
#[allow(clippy::needless_borrow)]
fn bitand(self, rhs: &Uint<LIMBS>) -> Uint<LIMBS> {
(&self).bitand(rhs)
}
}
impl<const LIMBS: usize> BitAnd<Uint<LIMBS>> for &Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn bitand(self, rhs: Uint<LIMBS>) -> Uint<LIMBS> {
self.bitand(&rhs)
}
}
impl<const LIMBS: usize> BitAnd<&Uint<LIMBS>> for &Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn bitand(self, rhs: &Uint<LIMBS>) -> Uint<LIMBS> {
self.bitand(rhs)
}
}
impl<const LIMBS: usize> BitAndAssign for Uint<LIMBS> {
#[allow(clippy::assign_op_pattern)]
fn bitand_assign(&mut self, other: Self) {
*self = *self & other;
}
}
impl<const LIMBS: usize> BitAndAssign<&Uint<LIMBS>> for Uint<LIMBS> {
#[allow(clippy::assign_op_pattern)]
fn bitand_assign(&mut self, other: &Self) {
*self = *self & other;
}
}
impl<const LIMBS: usize> BitAnd for Wrapping<Uint<LIMBS>> {
type Output = Self;
fn bitand(self, rhs: Self) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.bitand(&rhs.0))
}
}
impl<const LIMBS: usize> BitAnd<&Wrapping<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn bitand(self, rhs: &Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.bitand(&rhs.0))
}
}
impl<const LIMBS: usize> BitAnd<Wrapping<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn bitand(self, rhs: Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.bitand(&rhs.0))
}
}
impl<const LIMBS: usize> BitAnd<&Wrapping<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn bitand(self, rhs: &Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.bitand(&rhs.0))
}
}
impl<const LIMBS: usize> BitAndAssign for Wrapping<Uint<LIMBS>> {
#[allow(clippy::assign_op_pattern)]
fn bitand_assign(&mut self, other: Self) {
*self = *self & other;
}
}
impl<const LIMBS: usize> BitAndAssign<&Wrapping<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
#[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);
}
}

View File

@@ -0,0 +1,49 @@
//! [`Uint`] bitwise not operations.
use super::Uint;
use crate::{Limb, Wrapping};
use core::ops::Not;
impl<const LIMBS: usize> Uint<LIMBS> {
/// 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<const LIMBS: usize> Not for Uint<LIMBS> {
type Output = Self;
#[allow(clippy::needless_borrow)]
fn not(self) -> <Self as Not>::Output {
(&self).not()
}
}
impl<const LIMBS: usize> Not for Wrapping<Uint<LIMBS>> {
type Output = Self;
fn not(self) -> <Self as Not>::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);
}
}

142
vendor/crypto-bigint/src/uint/bit_or.rs vendored Normal file
View File

@@ -0,0 +1,142 @@
//! [`Uint`] bitwise or operations.
use super::Uint;
use crate::{Limb, Wrapping};
use core::ops::{BitOr, BitOrAssign};
use subtle::{Choice, CtOption};
impl<const LIMBS: usize> Uint<LIMBS> {
/// 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<Self> {
let result = self.bitor(rhs);
CtOption::new(result, Choice::from(1))
}
}
impl<const LIMBS: usize> BitOr for Uint<LIMBS> {
type Output = Self;
fn bitor(self, rhs: Self) -> Uint<LIMBS> {
self.bitor(&rhs)
}
}
impl<const LIMBS: usize> BitOr<&Uint<LIMBS>> for Uint<LIMBS> {
type Output = Uint<LIMBS>;
#[allow(clippy::needless_borrow)]
fn bitor(self, rhs: &Uint<LIMBS>) -> Uint<LIMBS> {
(&self).bitor(rhs)
}
}
impl<const LIMBS: usize> BitOr<Uint<LIMBS>> for &Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn bitor(self, rhs: Uint<LIMBS>) -> Uint<LIMBS> {
self.bitor(&rhs)
}
}
impl<const LIMBS: usize> BitOr<&Uint<LIMBS>> for &Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn bitor(self, rhs: &Uint<LIMBS>) -> Uint<LIMBS> {
self.bitor(rhs)
}
}
impl<const LIMBS: usize> BitOrAssign for Uint<LIMBS> {
fn bitor_assign(&mut self, other: Self) {
*self = *self | other;
}
}
impl<const LIMBS: usize> BitOrAssign<&Uint<LIMBS>> for Uint<LIMBS> {
fn bitor_assign(&mut self, other: &Self) {
*self = *self | other;
}
}
impl<const LIMBS: usize> BitOr for Wrapping<Uint<LIMBS>> {
type Output = Self;
fn bitor(self, rhs: Self) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.bitor(&rhs.0))
}
}
impl<const LIMBS: usize> BitOr<&Wrapping<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn bitor(self, rhs: &Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.bitor(&rhs.0))
}
}
impl<const LIMBS: usize> BitOr<Wrapping<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn bitor(self, rhs: Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.bitor(&rhs.0))
}
}
impl<const LIMBS: usize> BitOr<&Wrapping<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn bitor(self, rhs: &Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.bitor(&rhs.0))
}
}
impl<const LIMBS: usize> BitOrAssign for Wrapping<Uint<LIMBS>> {
fn bitor_assign(&mut self, other: Self) {
*self = *self | other;
}
}
impl<const LIMBS: usize> BitOrAssign<&Wrapping<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
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);
}
}

142
vendor/crypto-bigint/src/uint/bit_xor.rs vendored Normal file
View File

@@ -0,0 +1,142 @@
//! [`Uint`] bitwise xor operations.
use super::Uint;
use crate::{Limb, Wrapping};
use core::ops::{BitXor, BitXorAssign};
use subtle::{Choice, CtOption};
impl<const LIMBS: usize> Uint<LIMBS> {
/// 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<Self> {
let result = self.bitxor(rhs);
CtOption::new(result, Choice::from(1))
}
}
impl<const LIMBS: usize> BitXor for Uint<LIMBS> {
type Output = Self;
fn bitxor(self, rhs: Self) -> Uint<LIMBS> {
self.bitxor(&rhs)
}
}
impl<const LIMBS: usize> BitXor<&Uint<LIMBS>> for Uint<LIMBS> {
type Output = Uint<LIMBS>;
#[allow(clippy::needless_borrow)]
fn bitxor(self, rhs: &Uint<LIMBS>) -> Uint<LIMBS> {
(&self).bitxor(rhs)
}
}
impl<const LIMBS: usize> BitXor<Uint<LIMBS>> for &Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn bitxor(self, rhs: Uint<LIMBS>) -> Uint<LIMBS> {
self.bitxor(&rhs)
}
}
impl<const LIMBS: usize> BitXor<&Uint<LIMBS>> for &Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn bitxor(self, rhs: &Uint<LIMBS>) -> Uint<LIMBS> {
self.bitxor(rhs)
}
}
impl<const LIMBS: usize> BitXorAssign for Uint<LIMBS> {
fn bitxor_assign(&mut self, other: Self) {
*self = *self ^ other;
}
}
impl<const LIMBS: usize> BitXorAssign<&Uint<LIMBS>> for Uint<LIMBS> {
fn bitxor_assign(&mut self, other: &Self) {
*self = *self ^ other;
}
}
impl<const LIMBS: usize> BitXor for Wrapping<Uint<LIMBS>> {
type Output = Self;
fn bitxor(self, rhs: Self) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.bitxor(&rhs.0))
}
}
impl<const LIMBS: usize> BitXor<&Wrapping<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn bitxor(self, rhs: &Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.bitxor(&rhs.0))
}
}
impl<const LIMBS: usize> BitXor<Wrapping<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn bitxor(self, rhs: Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.bitxor(&rhs.0))
}
}
impl<const LIMBS: usize> BitXor<&Wrapping<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn bitxor(self, rhs: &Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.bitxor(&rhs.0))
}
}
impl<const LIMBS: usize> BitXorAssign for Wrapping<Uint<LIMBS>> {
fn bitxor_assign(&mut self, other: Self) {
*self = *self ^ other;
}
}
impl<const LIMBS: usize> BitXorAssign<&Wrapping<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
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);
}
}

360
vendor/crypto-bigint/src/uint/bits.rs vendored Normal file
View File

@@ -0,0 +1,360 @@
use crate::{CtChoice, Limb, Uint, Word};
impl<const LIMBS: usize> Uint<LIMBS> {
/// Returns `true` if the bit at position `index` is set, `false` otherwise.
///
/// # Remarks
/// This operation is variable time with respect to `index` only.
#[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.
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];
Limb::BITS * (i + 1) - limb.leading_zeros()
}
/// 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 leading zeros in the binary representation of this number,
/// variable time in `self`.
pub const fn leading_zeros_vartime(&self) -> usize {
let limbs = self.as_limbs();
let mut count = 0;
let mut i = LIMBS;
while i > 0 {
i -= 1;
let l = limbs[i];
let z = l.leading_zeros();
count += z;
if z != Limb::BITS {
break;
}
}
count
}
/// 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 trailing zeros in the binary representation of this number,
/// variable time in `self`.
pub const fn trailing_zeros_vartime(&self) -> usize {
let limbs = self.as_limbs();
let mut count = 0;
let mut i = 0;
while i < LIMBS {
let l = limbs[i];
let z = l.trailing_zeros();
count += z;
if z != Limb::BITS {
break;
}
i += 1;
}
count
}
/// Calculate the number of trailing ones in the binary representation of this number.
pub const fn trailing_ones(&self) -> usize {
let limbs = self.as_limbs();
let mut count: Word = 0;
let mut i = 0;
let mut nonmax_limb_not_encountered = CtChoice::TRUE;
while i < LIMBS {
let l = limbs[i];
let z = l.trailing_ones() as Word;
count += nonmax_limb_not_encountered.if_true(z);
nonmax_limb_not_encountered =
nonmax_limb_not_encountered.and(Limb::ct_eq(l, Limb::MAX));
i += 1;
}
count as usize
}
/// Calculate the number of trailing ones in the binary representation of this number,
/// variable time in `self`.
pub const fn trailing_ones_vartime(&self) -> usize {
let limbs = self.as_limbs();
let mut count = 0;
let mut i = 0;
while i < LIMBS {
let l = limbs[i];
let z = l.trailing_ones();
count += z;
if z != Limb::BITS {
break;
}
i += 1;
}
count
}
/// 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 = index / Limb::BITS;
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 = CtChoice::from_usize_equality(i, limb_num);
result |= is_right_limb.if_true(bit);
i += 1;
}
CtChoice::from_lsb(result >> index_in_limb)
}
/// Sets the bit at `index` to 0 or 1 depending on the value of `bit_value`.
pub(crate) const fn set_bit(self, index: usize, bit_value: CtChoice) -> Self {
let mut result = self;
let limb_num = index / Limb::BITS;
let index_in_limb = index % Limb::BITS;
let index_mask = 1 << index_in_limb;
let mut i = 0;
while i < LIMBS {
let is_right_limb = CtChoice::from_usize_equality(i, limb_num);
let old_limb = result.limbs[i].0;
let new_limb = bit_value.select(old_limb & !index_mask, old_limb | index_mask);
result.limbs[i] = Limb(is_right_limb.select(old_limb, new_limb));
i += 1;
}
result
}
}
#[cfg(test)]
mod tests {
use crate::{CtChoice, 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(), 15);
let u = uint_with_bits_at(&[256 - 79, 256 - 207]);
assert_eq!(u.leading_zeros(), 78);
let u = uint_with_bits_at(&[256 - 207]);
assert_eq!(u.leading_zeros(), 206);
let u = uint_with_bits_at(&[256 - 1, 256 - 75, 256 - 150]);
assert_eq!(u.leading_zeros(), 0);
let u = U256::ZERO;
assert_eq!(u.leading_zeros(), 256);
}
#[test]
fn leading_zeros_vartime() {
let u = uint_with_bits_at(&[256 - 16, 256 - 79, 256 - 207]);
assert_eq!(u.leading_zeros_vartime(), 15);
let u = uint_with_bits_at(&[256 - 79, 256 - 207]);
assert_eq!(u.leading_zeros_vartime(), 78);
let u = uint_with_bits_at(&[256 - 207]);
assert_eq!(u.leading_zeros_vartime(), 206);
let u = uint_with_bits_at(&[256 - 1, 256 - 75, 256 - 150]);
assert_eq!(u.leading_zeros_vartime(), 0);
let u = U256::ZERO;
assert_eq!(u.leading_zeros_vartime(), 256);
}
#[test]
fn trailing_zeros() {
let u = uint_with_bits_at(&[16, 79, 150]);
assert_eq!(u.trailing_zeros(), 16);
let u = uint_with_bits_at(&[79, 150]);
assert_eq!(u.trailing_zeros(), 79);
let u = uint_with_bits_at(&[150, 207]);
assert_eq!(u.trailing_zeros(), 150);
let u = uint_with_bits_at(&[0, 150, 207]);
assert_eq!(u.trailing_zeros(), 0);
let u = U256::ZERO;
assert_eq!(u.trailing_zeros(), 256);
}
#[test]
fn trailing_zeros_vartime() {
let u = uint_with_bits_at(&[16, 79, 150]);
assert_eq!(u.trailing_zeros_vartime(), 16);
let u = uint_with_bits_at(&[79, 150]);
assert_eq!(u.trailing_zeros_vartime(), 79);
let u = uint_with_bits_at(&[150, 207]);
assert_eq!(u.trailing_zeros_vartime(), 150);
let u = uint_with_bits_at(&[0, 150, 207]);
assert_eq!(u.trailing_zeros_vartime(), 0);
let u = U256::ZERO;
assert_eq!(u.trailing_zeros_vartime(), 256);
}
#[test]
fn trailing_ones() {
let u = !uint_with_bits_at(&[16, 79, 150]);
assert_eq!(u.trailing_ones(), 16);
let u = !uint_with_bits_at(&[79, 150]);
assert_eq!(u.trailing_ones(), 79);
let u = !uint_with_bits_at(&[150, 207]);
assert_eq!(u.trailing_ones(), 150);
let u = !uint_with_bits_at(&[0, 150, 207]);
assert_eq!(u.trailing_ones(), 0);
let u = U256::MAX;
assert_eq!(u.trailing_ones(), 256);
}
#[test]
fn trailing_ones_vartime() {
let u = !uint_with_bits_at(&[16, 79, 150]);
assert_eq!(u.trailing_ones_vartime(), 16);
let u = !uint_with_bits_at(&[79, 150]);
assert_eq!(u.trailing_ones_vartime(), 79);
let u = !uint_with_bits_at(&[150, 207]);
assert_eq!(u.trailing_ones_vartime(), 150);
let u = !uint_with_bits_at(&[0, 150, 207]);
assert_eq!(u.trailing_ones_vartime(), 0);
let u = U256::MAX;
assert_eq!(u.trailing_ones_vartime(), 256);
}
#[test]
fn set_bit() {
let u = uint_with_bits_at(&[16, 79, 150]);
assert_eq!(
u.set_bit(127, CtChoice::TRUE),
uint_with_bits_at(&[16, 79, 127, 150])
);
let u = uint_with_bits_at(&[16, 79, 150]);
assert_eq!(
u.set_bit(150, CtChoice::TRUE),
uint_with_bits_at(&[16, 79, 150])
);
let u = uint_with_bits_at(&[16, 79, 150]);
assert_eq!(
u.set_bit(127, CtChoice::FALSE),
uint_with_bits_at(&[16, 79, 150])
);
let u = uint_with_bits_at(&[16, 79, 150]);
assert_eq!(
u.set_bit(150, CtChoice::FALSE),
uint_with_bits_at(&[16, 79])
);
}
}

275
vendor/crypto-bigint/src/uint/cmp.rs vendored Normal file
View File

@@ -0,0 +1,275 @@
//! [`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<const LIMBS: usize> Uint<LIMBS> {
/// 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)
}
/// Returns the ordering between `self` and `rhs` as an i8.
/// Values correspond to the Ordering enum:
/// -1 is Less
/// 0 is Equal
/// 1 is Greater
#[inline]
pub(crate) const fn ct_cmp(lhs: &Self, rhs: &Self) -> i8 {
let mut i = 0;
let mut borrow = Limb::ZERO;
let mut diff = Limb::ZERO;
while i < LIMBS {
let (w, b) = rhs.limbs[i].sbb(lhs.limbs[i], borrow);
diff = diff.bitor(w);
borrow = b;
i += 1;
}
let sgn = ((borrow.0 & 2) as i8) - 1;
(diff.ct_is_nonzero().to_u8() as i8) * sgn
}
/// Returns the Ordering between `self` and `rhs` in variable time.
pub const fn cmp_vartime(&self, rhs: &Self) -> Ordering {
let mut i = LIMBS - 1;
loop {
let (val, borrow) = self.limbs[i].sbb(rhs.limbs[i], Limb::ZERO);
if val.0 != 0 {
return if borrow.0 != 0 {
Ordering::Less
} else {
Ordering::Greater
};
}
if i == 0 {
return Ordering::Equal;
}
i -= 1;
}
}
}
impl<const LIMBS: usize> ConstantTimeEq for Uint<LIMBS> {
#[inline]
fn ct_eq(&self, other: &Self) -> Choice {
Uint::ct_eq(self, other).into()
}
}
impl<const LIMBS: usize> ConstantTimeGreater for Uint<LIMBS> {
#[inline]
fn ct_gt(&self, other: &Self) -> Choice {
Uint::ct_gt(self, other).into()
}
}
impl<const LIMBS: usize> ConstantTimeLess for Uint<LIMBS> {
#[inline]
fn ct_lt(&self, other: &Self) -> Choice {
Uint::ct_lt(self, other).into()
}
}
impl<const LIMBS: usize> Eq for Uint<LIMBS> {}
impl<const LIMBS: usize> Ord for Uint<LIMBS> {
fn cmp(&self, other: &Self) -> Ordering {
let c = Self::ct_cmp(self, other);
match c {
-1 => Ordering::Less,
0 => Ordering::Equal,
_ => Ordering::Greater,
}
}
}
impl<const LIMBS: usize> PartialOrd for Uint<LIMBS> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<const LIMBS: usize> PartialEq for Uint<LIMBS> {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}
#[cfg(test)]
mod tests {
use crate::{Integer, Zero, U128};
use core::cmp::Ordering;
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)));
}
#[test]
fn cmp() {
let a = U128::ZERO;
let b = U128::ONE;
let c = U128::MAX;
assert_eq!(a.cmp(&b), Ordering::Less);
assert_eq!(a.cmp(&c), Ordering::Less);
assert_eq!(b.cmp(&c), Ordering::Less);
assert_eq!(a.cmp(&a), Ordering::Equal);
assert_eq!(b.cmp(&b), Ordering::Equal);
assert_eq!(c.cmp(&c), Ordering::Equal);
assert_eq!(b.cmp(&a), Ordering::Greater);
assert_eq!(c.cmp(&a), Ordering::Greater);
assert_eq!(c.cmp(&b), Ordering::Greater);
}
#[test]
fn cmp_vartime() {
let a = U128::ZERO;
let b = U128::ONE;
let c = U128::MAX;
assert_eq!(a.cmp_vartime(&b), Ordering::Less);
assert_eq!(a.cmp_vartime(&c), Ordering::Less);
assert_eq!(b.cmp_vartime(&c), Ordering::Less);
assert_eq!(a.cmp_vartime(&a), Ordering::Equal);
assert_eq!(b.cmp_vartime(&b), Ordering::Equal);
assert_eq!(c.cmp_vartime(&c), Ordering::Equal);
assert_eq!(b.cmp_vartime(&a), Ordering::Greater);
assert_eq!(c.cmp_vartime(&a), Ordering::Greater);
assert_eq!(c.cmp_vartime(&b), Ordering::Greater);
}
}

70
vendor/crypto-bigint/src/uint/concat.rs vendored Normal file
View File

@@ -0,0 +1,70 @@
use crate::{Concat, ConcatMixed, Limb, Uint};
impl<T> Concat for T
where
T: ConcatMixed<T>,
{
type Output = Self::MixedOutput;
}
/// Concatenate the two values, with `lo` as least significant and `hi`
/// as the most significant.
#[inline]
pub(crate) const fn concat_mixed<const L: usize, const H: usize, const O: usize>(
lo: &Uint<L>,
hi: &Uint<H>,
) -> Uint<O> {
let top = L + H;
let top = if top < O { top } else { O };
let mut limbs = [Limb::ZERO; O];
let mut i = 0;
while i < top {
if i < L {
limbs[i] = lo.limbs[i];
} else {
limbs[i] = hi.limbs[i - L];
}
i += 1;
}
Uint { limbs }
}
#[cfg(test)]
mod tests {
use crate::{ConcatMixed, U128, U192, 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 concat_mixed() {
let a = U64::from_u64(0x0011223344556677);
let b = U128::from_u128(0x8899aabbccddeeff_8899aabbccddeeff);
assert_eq!(
a.concat_mixed(&b),
U192::from_be_hex("00112233445566778899aabbccddeeff8899aabbccddeeff")
);
assert_eq!(
b.concat_mixed(&a),
U192::from_be_hex("8899aabbccddeeff8899aabbccddeeff0011223344556677")
);
}
#[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);
}
}

745
vendor/crypto-bigint/src/uint/div.rs vendored Normal file
View File

@@ -0,0 +1,745 @@
//! [`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<const LIMBS: usize> Uint<LIMBS> {
/// 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<Reciprocal>,
) -> 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<Limb>) -> (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, 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>) -> 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`
/// Theres 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<Self> {
NonZero::new(*rhs).map(|rhs| {
let (q, _r) = self.div_rem(&rhs);
q
})
}
/// Wrapped (modular) remainder calculation is just `self` % `rhs`.
/// Theres 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<Self> {
NonZero::new(*rhs).map(|rhs| self.rem(&rhs))
}
}
//
// Division by a single limb
//
impl<const LIMBS: usize> Div<&NonZero<Limb>> for &Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn div(self, rhs: &NonZero<Limb>) -> Self::Output {
*self / *rhs
}
}
impl<const LIMBS: usize> Div<&NonZero<Limb>> for Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn div(self, rhs: &NonZero<Limb>) -> Self::Output {
self / *rhs
}
}
impl<const LIMBS: usize> Div<NonZero<Limb>> for &Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn div(self, rhs: NonZero<Limb>) -> Self::Output {
*self / rhs
}
}
impl<const LIMBS: usize> Div<NonZero<Limb>> for Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn div(self, rhs: NonZero<Limb>) -> Self::Output {
let (q, _, _) = self.ct_div_rem_limb(*rhs);
q
}
}
impl<const LIMBS: usize> DivAssign<&NonZero<Limb>> for Uint<LIMBS> {
fn div_assign(&mut self, rhs: &NonZero<Limb>) {
*self /= *rhs;
}
}
impl<const LIMBS: usize> DivAssign<NonZero<Limb>> for Uint<LIMBS> {
fn div_assign(&mut self, rhs: NonZero<Limb>) {
*self = *self / rhs;
}
}
impl<const LIMBS: usize> Div<NonZero<Limb>> for Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn div(self, rhs: NonZero<Limb>) -> Self::Output {
Wrapping(self.0 / rhs)
}
}
impl<const LIMBS: usize> Div<NonZero<Limb>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn div(self, rhs: NonZero<Limb>) -> Self::Output {
*self / rhs
}
}
impl<const LIMBS: usize> Div<&NonZero<Limb>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn div(self, rhs: &NonZero<Limb>) -> Self::Output {
*self / *rhs
}
}
impl<const LIMBS: usize> Div<&NonZero<Limb>> for Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn div(self, rhs: &NonZero<Limb>) -> Self::Output {
self / *rhs
}
}
impl<const LIMBS: usize> DivAssign<&NonZero<Limb>> for Wrapping<Uint<LIMBS>> {
fn div_assign(&mut self, rhs: &NonZero<Limb>) {
*self = Wrapping(self.0 / rhs)
}
}
impl<const LIMBS: usize> DivAssign<NonZero<Limb>> for Wrapping<Uint<LIMBS>> {
fn div_assign(&mut self, rhs: NonZero<Limb>) {
*self /= &rhs;
}
}
impl<const LIMBS: usize> Rem<&NonZero<Limb>> for &Uint<LIMBS> {
type Output = Limb;
fn rem(self, rhs: &NonZero<Limb>) -> Self::Output {
*self % *rhs
}
}
impl<const LIMBS: usize> Rem<&NonZero<Limb>> for Uint<LIMBS> {
type Output = Limb;
fn rem(self, rhs: &NonZero<Limb>) -> Self::Output {
self % *rhs
}
}
impl<const LIMBS: usize> Rem<NonZero<Limb>> for &Uint<LIMBS> {
type Output = Limb;
fn rem(self, rhs: NonZero<Limb>) -> Self::Output {
*self % rhs
}
}
impl<const LIMBS: usize> Rem<NonZero<Limb>> for Uint<LIMBS> {
type Output = Limb;
fn rem(self, rhs: NonZero<Limb>) -> Self::Output {
let (_, r, _) = self.ct_div_rem_limb(*rhs);
r
}
}
impl<const LIMBS: usize> RemAssign<&NonZero<Limb>> for Uint<LIMBS> {
fn rem_assign(&mut self, rhs: &NonZero<Limb>) {
*self = (*self % rhs).into();
}
}
impl<const LIMBS: usize> RemAssign<NonZero<Limb>> for Uint<LIMBS> {
fn rem_assign(&mut self, rhs: NonZero<Limb>) {
*self %= &rhs;
}
}
impl<const LIMBS: usize> Rem<NonZero<Limb>> for Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Limb>;
fn rem(self, rhs: NonZero<Limb>) -> Self::Output {
Wrapping(self.0 % rhs)
}
}
impl<const LIMBS: usize> Rem<NonZero<Limb>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Limb>;
fn rem(self, rhs: NonZero<Limb>) -> Self::Output {
*self % rhs
}
}
impl<const LIMBS: usize> Rem<&NonZero<Limb>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Limb>;
fn rem(self, rhs: &NonZero<Limb>) -> Self::Output {
*self % *rhs
}
}
impl<const LIMBS: usize> Rem<&NonZero<Limb>> for Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Limb>;
fn rem(self, rhs: &NonZero<Limb>) -> Self::Output {
self % *rhs
}
}
impl<const LIMBS: usize> RemAssign<NonZero<Limb>> for Wrapping<Uint<LIMBS>> {
fn rem_assign(&mut self, rhs: NonZero<Limb>) {
*self %= &rhs;
}
}
impl<const LIMBS: usize> RemAssign<&NonZero<Limb>> for Wrapping<Uint<LIMBS>> {
fn rem_assign(&mut self, rhs: &NonZero<Limb>) {
*self = Wrapping((self.0 % rhs).into())
}
}
//
// Division by an Uint
//
impl<const LIMBS: usize> Div<&NonZero<Uint<LIMBS>>> for &Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn div(self, rhs: &NonZero<Uint<LIMBS>>) -> Self::Output {
*self / *rhs
}
}
impl<const LIMBS: usize> Div<&NonZero<Uint<LIMBS>>> for Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn div(self, rhs: &NonZero<Uint<LIMBS>>) -> Self::Output {
self / *rhs
}
}
impl<const LIMBS: usize> Div<NonZero<Uint<LIMBS>>> for &Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn div(self, rhs: NonZero<Uint<LIMBS>>) -> Self::Output {
*self / rhs
}
}
impl<const LIMBS: usize> Div<NonZero<Uint<LIMBS>>> for Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn div(self, rhs: NonZero<Uint<LIMBS>>) -> Self::Output {
let (q, _) = self.div_rem(&rhs);
q
}
}
impl<const LIMBS: usize> DivAssign<&NonZero<Uint<LIMBS>>> for Uint<LIMBS> {
fn div_assign(&mut self, rhs: &NonZero<Uint<LIMBS>>) {
*self /= *rhs
}
}
impl<const LIMBS: usize> DivAssign<NonZero<Uint<LIMBS>>> for Uint<LIMBS> {
fn div_assign(&mut self, rhs: NonZero<Uint<LIMBS>>) {
*self = *self / rhs;
}
}
impl<const LIMBS: usize> Div<NonZero<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn div(self, rhs: NonZero<Uint<LIMBS>>) -> Self::Output {
Wrapping(self.0 / rhs)
}
}
impl<const LIMBS: usize> Div<NonZero<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn div(self, rhs: NonZero<Uint<LIMBS>>) -> Self::Output {
*self / rhs
}
}
impl<const LIMBS: usize> Div<&NonZero<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn div(self, rhs: &NonZero<Uint<LIMBS>>) -> Self::Output {
*self / *rhs
}
}
impl<const LIMBS: usize> Div<&NonZero<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn div(self, rhs: &NonZero<Uint<LIMBS>>) -> Self::Output {
self / *rhs
}
}
impl<const LIMBS: usize> DivAssign<&NonZero<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
fn div_assign(&mut self, rhs: &NonZero<Uint<LIMBS>>) {
*self = Wrapping(self.0 / rhs);
}
}
impl<const LIMBS: usize> DivAssign<NonZero<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
fn div_assign(&mut self, rhs: NonZero<Uint<LIMBS>>) {
*self /= &rhs;
}
}
impl<const LIMBS: usize> Rem<&NonZero<Uint<LIMBS>>> for &Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn rem(self, rhs: &NonZero<Uint<LIMBS>>) -> Self::Output {
*self % *rhs
}
}
impl<const LIMBS: usize> Rem<&NonZero<Uint<LIMBS>>> for Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn rem(self, rhs: &NonZero<Uint<LIMBS>>) -> Self::Output {
self % *rhs
}
}
impl<const LIMBS: usize> Rem<NonZero<Uint<LIMBS>>> for &Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn rem(self, rhs: NonZero<Uint<LIMBS>>) -> Self::Output {
*self % rhs
}
}
impl<const LIMBS: usize> Rem<NonZero<Uint<LIMBS>>> for Uint<LIMBS> {
type Output = Uint<LIMBS>;
fn rem(self, rhs: NonZero<Uint<LIMBS>>) -> Self::Output {
Self::rem(&self, &rhs)
}
}
impl<const LIMBS: usize> RemAssign<&NonZero<Uint<LIMBS>>> for Uint<LIMBS> {
fn rem_assign(&mut self, rhs: &NonZero<Uint<LIMBS>>) {
*self %= *rhs
}
}
impl<const LIMBS: usize> RemAssign<NonZero<Uint<LIMBS>>> for Uint<LIMBS> {
fn rem_assign(&mut self, rhs: NonZero<Uint<LIMBS>>) {
*self = *self % rhs;
}
}
impl<const LIMBS: usize> Rem<NonZero<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn rem(self, rhs: NonZero<Uint<LIMBS>>) -> Self::Output {
Wrapping(self.0 % rhs)
}
}
impl<const LIMBS: usize> Rem<NonZero<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn rem(self, rhs: NonZero<Uint<LIMBS>>) -> Self::Output {
*self % rhs
}
}
impl<const LIMBS: usize> Rem<&NonZero<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn rem(self, rhs: &NonZero<Uint<LIMBS>>) -> Self::Output {
*self % *rhs
}
}
impl<const LIMBS: usize> Rem<&NonZero<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn rem(self, rhs: &NonZero<Uint<LIMBS>>) -> Self::Output {
self % *rhs
}
}
impl<const LIMBS: usize> RemAssign<NonZero<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
fn rem_assign(&mut self, rhs: NonZero<Uint<LIMBS>>) {
*self %= &rhs;
}
}
impl<const LIMBS: usize> RemAssign<&NonZero<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
fn rem_assign(&mut self, rhs: &NonZero<Uint<LIMBS>>) {
*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);
}
}
#[allow(clippy::op_ref)]
#[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);
}
}

View File

@@ -0,0 +1,287 @@
//! 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, <https://gmplib.org/~tege/division-paper.pdf>).
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`, 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<Self> {
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<const L: usize>(
u: &Uint<L>,
reciprocal: &Reciprocal,
) -> (Uint<L>, 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::<L>::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)
);
}
}

View File

@@ -0,0 +1,292 @@
//! 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<const LIMBS: usize> Uint<LIMBS> {
/// 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;
let mut err = 0;
while i < LIMBS {
let mut j = 0;
while j < Limb::BYTES {
let offset = (i * Limb::BYTES + j) * 2;
let (result, byte_err) = decode_hex_byte([bytes[offset], bytes[offset + 1]]);
err |= byte_err;
buf[j] = result;
j += 1;
}
res[LIMBS - i - 1] = Limb(Word::from_be_bytes(buf));
i += 1;
}
assert!(err == 0, "invalid hex byte");
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;
let mut err = 0;
while i < LIMBS {
let mut j = 0;
while j < Limb::BYTES {
let offset = (i * Limb::BYTES + j) * 2;
let (result, byte_err) = decode_hex_byte([bytes[offset], bytes[offset + 1]]);
err |= byte_err;
buf[j] = result;
j += 1;
}
res[i] = Limb(Word::from_le_bytes(buf));
i += 1;
}
assert!(err == 0, "invalid hex byte");
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 nibble of upper or lower hex
#[inline(always)]
const fn decode_nibble(src: u8) -> u16 {
let byte = src as i16;
let mut ret: i16 = -1;
// 0-9 0x30-0x39
// if (byte > 0x2f && byte < 0x3a) ret += byte - 0x30 + 1; // -47
ret += (((0x2fi16 - byte) & (byte - 0x3a)) >> 8) & (byte - 47);
// A-F 0x41-0x46
// if (byte > 0x40 && byte < 0x47) ret += byte - 0x41 + 10 + 1; // -54
ret += (((0x40i16 - byte) & (byte - 0x47)) >> 8) & (byte - 54);
// a-f 0x61-0x66
// if (byte > 0x60 && byte < 0x67) ret += byte - 0x61 + 10 + 1; // -86
ret += (((0x60i16 - byte) & (byte - 0x67)) >> 8) & (byte - 86);
ret as u16
}
/// Decode a single byte encoded as two hexadecimal characters.
/// Second element of the tuple is non-zero if the `bytes` values are not in the valid range
/// (0-9, a-z, A-Z).
#[inline(always)]
const fn decode_hex_byte(bytes: [u8; 2]) -> (u8, u16) {
let hi = decode_nibble(bytes[0]);
let lo = decode_nibble(bytes[1]);
let byte = (hi << 4) | lo;
let err = byte >> 8;
let result = byte as u8;
(result, err)
}
#[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));
}
}

View File

@@ -0,0 +1,64 @@
//! 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<AnyRef<'a>> for Uint<LIMBS>
where
Uint<LIMBS>: ArrayEncoding,
{
type Error = der::Error;
fn try_from(any: AnyRef<'a>) -> der::Result<Uint<LIMBS>> {
UintRef::try_from(any)?.try_into()
}
}
impl<'a, const LIMBS: usize> TryFrom<UintRef<'a>> for Uint<LIMBS>
where
Uint<LIMBS>: ArrayEncoding,
{
type Error = der::Error;
fn try_from(bytes: UintRef<'a>) -> der::Result<Uint<LIMBS>> {
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<LIMBS>
where
Uint<LIMBS>: ArrayEncoding,
{
fn decode_value<R: der::Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
UintRef::decode_value(reader, header)?.try_into()
}
}
impl<const LIMBS: usize> EncodeValue for Uint<LIMBS>
where
Uint<LIMBS>: ArrayEncoding,
{
fn value_len(&self) -> der::Result<Length> {
// 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<const LIMBS: usize> FixedTag for Uint<LIMBS>
where
Uint<LIMBS>: ArrayEncoding,
{
const TAG: Tag = Tag::Integer;
}

View File

@@ -0,0 +1,78 @@
//! Recursive Length Prefix (RLP) encoding support.
use crate::{Encoding, Uint};
use rlp::{DecoderError, Rlp, RlpStream};
impl<const LIMBS: usize> rlp::Encodable for Uint<LIMBS>
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<const LIMBS: usize> rlp::Decodable for Uint<LIMBS>
where
Self: Encoding,
<Self as Encoding>::Repr: Default,
{
fn decode(rlp: &Rlp<'_>) -> Result<Self, DecoderError> {
rlp.decoder().decode_value(|bytes| {
if bytes.first().cloned() == Some(0) {
Err(rlp::DecoderError::RlpInvalidIndirection)
} else {
let mut repr = <Self as Encoding>::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)]
#[allow(clippy::unwrap_used)]
mod tests {
use crate::U256;
use hex_literal::hex;
/// U256 test vectors from the `rlp` crate.
///
/// <https://github.com/paritytech/parity-common/blob/faad8b6/rlp/tests/tests.rs#L216-L222>
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::<U256>(expected_bytes).unwrap(), uint);
}
}
}

View File

@@ -0,0 +1,160 @@
//! Support for additional integer sizes beyond the core set which is defined
//! in the toplevel module.
//!
//! These are feature-gated to keep compile times down for applications which
//! do not need them.
// TODO(tarcieri): switch to a fully const generic implementation using `generic_const_exprs`
use super::*;
impl_uint_aliases! {
(U1088, 1088, "1088-bit"),
(U1152, 1152, "1152-bit"),
(U1216, 1216, "1216-bit"),
(U1344, 1344, "1344-bit"),
(U1408, 1408, "1408-bit"),
(U1472, 1472, "1472-bit"),
(U1600, 1600, "1600-bit"),
(U1664, 1664, "1664-bit"),
(U1728, 1728, "1728-bit"),
(U1856, 1856, "1856-bit"),
(U1920, 1920, "1920-bit"),
(U1984, 1984, "1984-bit"),
(U2112, 2112, "2112-bit"),
(U2176, 2176, "2176-bit"),
(U2240, 2240, "2240-bit"),
(U2304, 2304, "2304-bit"),
(U2368, 2368, "2368-bit"),
(U2432, 2432, "2432-bit"),
(U2496, 2496, "2496-bit"),
(U2560, 2560, "2560-bit"),
(U2624, 2624, "2624-bit"),
(U2688, 2688, "2688-bit"),
(U2752, 2752, "2752-bit"),
(U2816, 2816, "2816-bit"),
(U2880, 2880, "2880-bit"),
(U2944, 2944, "2944-bit"),
(U3008, 3008, "3008-bit"),
(U3136, 3136, "3136-bit"),
(U3200, 3200, "3200-bit"),
(U3264, 3264, "3264-bit"),
(U3328, 3328, "3328-bit"),
(U3392, 3392, "3392-bit"),
(U3456, 3456, "3456-bit"),
(U3520, 3520, "3520-bit"),
(U3648, 3648, "3648-bit"),
(U3712, 3712, "3712-bit"),
(U3776, 3776, "3776-bit"),
(U3840, 3840, "3840-bit"),
(U3904, 3904, "3904-bit"),
(U3968, 3968, "3968-bit"),
(U4032, 4032, "4032-bit"),
(U4160, 4160, "4160-bit"),
(U4288, 4288, "4288-bit"),
(U4416, 4416, "4416-bit"),
(U4480, 4480, "4480-bit"),
(U4544, 4544, "4544-bit"),
(U4608, 4608, "4608-bit"),
(U4672, 4672, "4672-bit"),
(U4736, 4736, "4736-bit"),
(U4800, 4800, "4800-bit"),
(U4864, 4864, "4864-bit"),
(U4928, 4928, "4928-bit"),
(U4992, 4992, "4992-bit"),
(U5056, 5056, "5056-bit"),
(U5120, 5120, "5120-bit"),
(U5184, 5184, "5184-bit"),
(U5248, 5248, "5248-bit"),
(U5312, 5312, "5312-bit"),
(U5376, 5376, "5376-bit"),
(U5440, 5440, "5440-bit"),
(U5504, 5504, "5504-bit"),
(U5568, 5568, "5568-bit"),
(U5632, 5632, "5632-bit"),
(U5696, 5696, "5696-bit"),
(U5760, 5760, "5760-bit"),
(U5824, 5824, "5824-bit"),
(U5888, 5888, "5888-bit"),
(U5952, 5952, "5952-bit"),
(U6016, 6016, "6016-bit"),
(U6080, 6080, "6080-bit"),
(U6208, 6208, "6208-bit"),
(U6272, 6272, "6272-bit"),
(U6336, 6336, "6336-bit"),
(U6400, 6400, "6400-bit"),
(U6464, 6464, "6464-bit"),
(U6528, 6528, "6528-bit"),
(U6592, 6592, "6592-bit"),
(U6656, 6656, "6656-bit"),
(U6720, 6720, "6720-bit"),
(U6784, 6784, "6784-bit"),
(U6848, 6848, "6848-bit"),
(U6912, 6912, "6912-bit"),
(U6976, 6976, "6976-bit"),
(U7040, 7040, "7040-bit"),
(U7104, 7104, "7104-bit"),
(U7168, 7168, "7168-bit"),
(U7232, 7232, "7232-bit"),
(U7296, 7296, "7296-bit"),
(U7360, 7360, "7360-bit"),
(U7424, 7424, "7424-bit"),
(U7488, 7488, "7488-bit"),
(U7552, 7552, "7552-bit"),
(U7616, 7616, "7616-bit"),
(U7680, 7680, "7680-bit"),
(U7744, 7744, "7744-bit"),
(U7808, 7808, "7808-bit"),
(U7872, 7872, "7872-bit"),
(U7936, 7936, "7936-bit"),
(U8000, 8000, "8000-bit"),
(U8064, 8064, "8064-bit"),
(U8128, 8128, "8128-bit")
}
impl_uint_concat_split_even! {
U1152,
U1408,
U1664,
U1920,
U2176,
U2304,
U2432,
U2560,
U2688,
U2816,
U2944,
U3200,
U3328,
U3456,
U3712,
U3840,
U3968,
U4480,
U4608,
U4736,
U4864,
U4992,
U5120,
U5248,
U5376,
U5504,
U5632,
U5760,
U5888,
U6016,
U6272,
U6400,
U6528,
U6656,
U6784,
U6912,
U7040,
U7168,
U7296,
U7424,
U7552,
U7680,
U7808,
U7936,
U8064,
}

271
vendor/crypto-bigint/src/uint/from.rs vendored Normal file
View File

@@ -0,0 +1,271 @@
//! `From`-like conversions for [`Uint`].
use crate::{ConcatMixed, Limb, Uint, WideWord, Word, U128, U64};
impl<const LIMBS: usize> Uint<LIMBS> {
/// Create a [`Uint`] from a `u8` (const-friendly)
// TODO(tarcieri): replace with `const impl From<u8>` 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<u16>` 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<u32>` 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<u64>` 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<u64>` 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<u128>` 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<Word>` 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<WideWord>` 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<const LIMBS: usize> From<u8> for Uint<LIMBS> {
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<const LIMBS: usize> From<u16> for Uint<LIMBS> {
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<const LIMBS: usize> From<u32> for Uint<LIMBS> {
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<const LIMBS: usize> From<u64> for Uint<LIMBS> {
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<const LIMBS: usize> From<u128> for Uint<LIMBS> {
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<U64> 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<U64> for u64 {
fn from(n: U64) -> u64 {
n.limbs[0].into()
}
}
impl From<U128> for u128 {
fn from(n: U128) -> u128 {
let mut i = U128::LIMBS - 1;
let mut res = n.limbs[i].0 as u128;
while i > 0 {
i -= 1;
res = (res << Limb::BITS) | (n.limbs[i].0 as u128);
}
res
}
}
impl<const LIMBS: usize> From<[Word; LIMBS]> for Uint<LIMBS> {
fn from(arr: [Word; LIMBS]) -> Self {
Self::from_words(arr)
}
}
impl<const LIMBS: usize> From<Uint<LIMBS>> for [Word; LIMBS] {
fn from(n: Uint<LIMBS>) -> [Word; LIMBS] {
*n.as_ref()
}
}
impl<const LIMBS: usize> From<[Limb; LIMBS]> for Uint<LIMBS> {
fn from(limbs: [Limb; LIMBS]) -> Self {
Self { limbs }
}
}
impl<const LIMBS: usize> From<Uint<LIMBS>> for [Limb; LIMBS] {
fn from(n: Uint<LIMBS>) -> [Limb; LIMBS] {
n.limbs
}
}
impl<const LIMBS: usize> From<Limb> for Uint<LIMBS> {
fn from(limb: Limb) -> Self {
limb.0.into()
}
}
impl<const L: usize, const H: usize, const LIMBS: usize> From<(Uint<L>, Uint<H>)> for Uint<LIMBS>
where
Uint<H>: ConcatMixed<Uint<L>, MixedOutput = Uint<LIMBS>>,
{
fn from(nums: (Uint<L>, Uint<H>)) -> Uint<LIMBS> {
nums.1.concat_mixed(&nums.0)
}
}
impl<const L: usize, const H: usize, const LIMBS: usize> From<&(Uint<L>, Uint<H>)> for Uint<LIMBS>
where
Uint<H>: ConcatMixed<Uint<L>, MixedOutput = Uint<LIMBS>>,
{
fn from(nums: &(Uint<L>, Uint<H>)) -> Uint<LIMBS> {
nums.1.concat_mixed(&nums.0)
}
}
impl<const L: usize, const H: usize, const LIMBS: usize> From<Uint<LIMBS>> for (Uint<L>, Uint<H>) {
fn from(num: Uint<LIMBS>) -> (Uint<L>, Uint<H>) {
crate::uint::split::split_mixed(&num)
}
}
impl<const LIMBS: usize, const LIMBS2: usize> From<&Uint<LIMBS>> for Uint<LIMBS2> {
fn from(num: &Uint<LIMBS>) -> Uint<LIMBS2> {
num.resize()
}
}
#[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);
}
}

306
vendor/crypto-bigint/src/uint/inv_mod.rs vendored Normal file
View File

@@ -0,0 +1,306 @@
use super::Uint;
use crate::CtChoice;
impl<const LIMBS: usize> Uint<LIMBS> {
/// Computes 1/`self` mod `2^k`.
/// This method is constant-time w.r.t. `self` but not `k`.
///
/// Conditions: `self` < 2^k and `self` must be odd
pub const fn inv_mod2k_vartime(&self, k: usize) -> Self {
// Using the Algorithm 3 from "A Secure Algorithm for Inversion Modulo 2k"
// by Sadiel de la Fe and Carles Ferrer.
// See <https://www.mdpi.com/2410-387X/2/3/23>.
// Note that we are not using Alrgorithm 4, since we have a different approach
// of enforcing constant-timeness w.r.t. `self`.
let mut x = Self::ZERO; // keeps `x` during iterations
let mut b = Self::ONE; // keeps `b_i` during iterations
let mut i = 0;
while i < k {
// X_i = b_i mod 2
let x_i = b.limbs[0].0 & 1;
let x_i_choice = CtChoice::from_lsb(x_i);
// b_{i+1} = (b_i - a * X_i) / 2
b = Self::ct_select(&b, &b.wrapping_sub(self), x_i_choice).shr_vartime(1);
// Store the X_i bit in the result (x = x | (1 << X_i))
x = x.bitor(&Uint::from_word(x_i).shl_vartime(i));
i += 1;
}
x
}
/// Computes 1/`self` mod `2^k`.
///
/// Conditions: `self` < 2^k and `self` must be odd
pub const fn inv_mod2k(&self, k: usize) -> Self {
// This is the same algorithm as in `inv_mod2k_vartime()`,
// but made constant-time w.r.t `k` as well.
let mut x = Self::ZERO; // keeps `x` during iterations
let mut b = Self::ONE; // keeps `b_i` during iterations
let mut i = 0;
while i < Self::BITS {
// Only iterations for i = 0..k need to change `x`,
// the rest are dummy ones performed for the sake of constant-timeness.
let within_range = CtChoice::from_usize_lt(i, k);
// X_i = b_i mod 2
let x_i = b.limbs[0].0 & 1;
let x_i_choice = CtChoice::from_lsb(x_i);
// b_{i+1} = (b_i - a * X_i) / 2
b = Self::ct_select(&b, &b.wrapping_sub(self), x_i_choice).shr_vartime(1);
// Store the X_i bit in the result (x = x | (1 << X_i))
// Don't change the result in dummy iterations.
let x_i_choice = x_i_choice.and(within_range);
x = x.set_bit(i, x_i_choice);
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, CtChoice::TRUE)` if an inverse exists,
/// otherwise `(undefined, CtChoice::FALSE)`.
pub const fn inv_odd_mod(&self, modulus: &Self) -> (Self, CtChoice) {
self.inv_odd_mod_bounded(modulus, Uint::<LIMBS>::BITS, Uint::<LIMBS>::BITS)
}
/// Computes the multiplicative inverse of `self` mod `modulus`.
/// Returns `(inverse, CtChoice::TRUE)` if an inverse exists,
/// otherwise `(undefined, CtChoice::FALSE)`.
pub const fn inv_mod(&self, modulus: &Self) -> (Self, CtChoice) {
// Decompose `modulus = s * 2^k` where `s` is odd
let k = modulus.trailing_zeros();
let s = modulus.shr(k);
// Decompose `self` into RNS with moduli `2^k` and `s` and calculate the inverses.
// Using the fact that `(z^{-1} mod (m1 * m2)) mod m1 == z^{-1} mod m1`
let (a, a_is_some) = self.inv_odd_mod(&s);
let b = self.inv_mod2k(k);
// inverse modulo 2^k exists either if `k` is 0 or if `self` is odd.
let b_is_some = CtChoice::from_usize_being_nonzero(k)
.not()
.or(self.ct_is_odd());
// Restore from RNS:
// self^{-1} = a mod s = b mod 2^k
// => self^{-1} = a + s * ((b - a) * s^(-1) mod 2^k)
// (essentially one step of the Garner's algorithm for recovery from RNS).
let m_odd_inv = s.inv_mod2k(k); // `s` is odd, so this always exists
// This part is mod 2^k
let mask = Uint::ONE.shl(k).wrapping_sub(&Uint::ONE);
let t = (b.wrapping_sub(&a).wrapping_mul(&m_odd_inv)).bitand(&mask);
// Will not overflow since `a <= s - 1`, `t <= 2^k - 1`,
// so `a + s * t <= s * 2^k - 1 == modulus - 1`.
let result = a.wrapping_add(&s.wrapping_mul(&t));
(result, a_is_some.and(b_is_some))
}
}
#[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_odd() {
let a = U1024::from_be_hex(concat![
"000225E99153B467A5B451979A3F451DAEF3BF8D6C6521D2FA24BBB17F29544E",
"347A412B065B75A351EA9719E2430D2477B11CC9CF9C1AD6EDEE26CB15F463F8",
"BCC72EF87EA30288E95A48AA792226CEC959DCB0672D8F9D80A54CBBEA85CAD8",
"382EC224DEB2F5784E62D0CC2F81C2E6AD14EBABE646D6764B30C32B87688985"
]);
let m = U1024::from_be_hex(concat![
"D509E7854ABDC81921F669F1DC6F61359523F3949803E58ED4EA8BC16483DC6F",
"37BFE27A9AC9EEA2969B357ABC5C0EE214BE16A7D4C58FC620D5B5A20AFF001A",
"D198D3155E5799DC4EA76652D64983A7E130B5EACEBAC768D28D589C36EC749C",
"558D0B64E37CD0775C0D0104AE7D98BA23C815185DD43CD8B16292FD94156767"
]);
let expected = U1024::from_be_hex(concat![
"B03623284B0EBABCABD5C5881893320281460C0A8E7BF4BFDCFFCBCCBF436A55",
"D364235C8171E46C7D21AAD0680676E57274A8FDA6D12768EF961CACDD2DAE57",
"88D93DA5EB8EDC391EE3726CDCF4613C539F7D23E8702200CB31B5ED5B06E5CA",
"3E520968399B4017BF98A864FABA2B647EFC4998B56774D4F2CB026BC024A336"
]);
let (res, is_some) = a.inv_odd_mod(&m);
assert!(is_some.is_true_vartime());
assert_eq!(res, expected);
// Even though it is less efficient, it still works
let (res, is_some) = a.inv_mod(&m);
assert!(is_some.is_true_vartime());
assert_eq!(res, expected);
}
#[test]
fn test_invert_even() {
let a = U1024::from_be_hex(concat![
"000225E99153B467A5B451979A3F451DAEF3BF8D6C6521D2FA24BBB17F29544E",
"347A412B065B75A351EA9719E2430D2477B11CC9CF9C1AD6EDEE26CB15F463F8",
"BCC72EF87EA30288E95A48AA792226CEC959DCB0672D8F9D80A54CBBEA85CAD8",
"382EC224DEB2F5784E62D0CC2F81C2E6AD14EBABE646D6764B30C32B87688985"
]);
let m = U1024::from_be_hex(concat![
"D509E7854ABDC81921F669F1DC6F61359523F3949803E58ED4EA8BC16483DC6F",
"37BFE27A9AC9EEA2969B357ABC5C0EE214BE16A7D4C58FC620D5B5A20AFF001A",
"D198D3155E5799DC4EA76652D64983A7E130B5EACEBAC768D28D589C36EC749C",
"558D0B64E37CD0775C0D0104AE7D98BA23C815185DD43CD8B16292FD94156000"
]);
let expected = U1024::from_be_hex(concat![
"1EBF391306817E1BC610E213F4453AD70911CCBD59A901B2A468A4FC1D64F357",
"DBFC6381EC5635CAA664DF280028AF4651482C77A143DF38D6BFD4D64B6C0225",
"FC0E199B15A64966FB26D88A86AD144271F6BDCD3D63193AB2B3CC53B99F21A3",
"5B9BFAE5D43C6BC6E7A9856C71C7318C76530E9E5AE35882D5ABB02F1696874D",
]);
let (res, is_some) = a.inv_mod(&m);
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());
}
}

115
vendor/crypto-bigint/src/uint/macros.rs vendored Normal file
View File

@@ -0,0 +1,115 @@
// TODO(tarcieri): use `generic_const_exprs` 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
}
}
)+
};
}
macro_rules! impl_uint_concat_split_mixed {
($name:ident, $size:literal) => {
impl $crate::traits::ConcatMixed<Uint<{ U64::LIMBS * $size }>> for Uint<{ <$name>::LIMBS - U64::LIMBS * $size }>
{
type MixedOutput = $name;
fn concat_mixed(&self, lo: &Uint<{ U64::LIMBS * $size }>) -> Self::MixedOutput {
$crate::uint::concat::concat_mixed(lo, self)
}
}
impl $crate::traits::SplitMixed<Uint<{ U64::LIMBS * $size }>, Uint<{ <$name>::LIMBS - U64::LIMBS * $size }>> for $name
{
fn split_mixed(&self) -> (Uint<{ U64::LIMBS * $size }>, Uint<{ <$name>::LIMBS - U64::LIMBS * $size }>) {
$crate::uint::split::split_mixed(self)
}
}
};
($name:ident, [ $($size:literal),+ ]) => {
$(
impl_uint_concat_split_mixed!($name, $size);
)+
};
($( ($name:ident, $sizes:tt), )+) => {
$(
impl_uint_concat_split_mixed!($name, $sizes);
)+
};
}
macro_rules! impl_uint_concat_split_even {
($name:ident) => {
impl $crate::traits::ConcatMixed<Uint<{ <$name>::LIMBS / 2 }>> for Uint<{ <$name>::LIMBS / 2 }>
{
type MixedOutput = $name;
fn concat_mixed(&self, lo: &Uint<{ <$name>::LIMBS / 2 }>) -> Self::MixedOutput {
$crate::uint::concat::concat_mixed(lo, self)
}
}
impl Uint<{ <$name>::LIMBS / 2 }> {
/// Concatenate the two values, with `self` as most significant and `rhs`
/// as the least significant.
pub const fn concat(&self, lo: &Uint<{ <$name>::LIMBS / 2 }>) -> $name {
$crate::uint::concat::concat_mixed(lo, self)
}
}
impl $crate::traits::SplitMixed<Uint<{ <$name>::LIMBS / 2 }>, Uint<{ <$name>::LIMBS / 2 }>> for $name
{
fn split_mixed(&self) -> (Uint<{ <$name>::LIMBS / 2 }>, Uint<{ <$name>::LIMBS / 2 }>) {
$crate::uint::split::split_mixed(self)
}
}
impl $crate::traits::Split for $name
{
type Output = Uint<{ <$name>::LIMBS / 2 }>;
}
impl $name {
/// Split this number in half, returning its high and low components
/// respectively.
pub const fn split(&self) -> (Uint<{ <$name>::LIMBS / 2 }>, Uint<{ <$name>::LIMBS / 2 }>) {
$crate::uint::split::split_mixed(self)
}
}
};
($($name:ident,)+) => {
$(
impl_uint_concat_split_even!($name);
)+
}
}

164
vendor/crypto-bigint/src/uint/modular.rs vendored Normal file
View File

@@ -0,0 +1,164 @@
mod 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::<Modulus2, { Modulus2::LIMBS }>::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::<Modulus2, { Modulus2::LIMBS }>::new(&x),
const_residue!(x, Modulus2)
);
}
}

View File

@@ -0,0 +1,9 @@
use crate::Uint;
pub(crate) const fn add_montgomery_form<const LIMBS: usize>(
a: &Uint<LIMBS>,
b: &Uint<LIMBS>,
modulus: &Uint<LIMBS>,
) -> Uint<LIMBS> {
a.add_mod(b, modulus)
}

View File

@@ -0,0 +1,254 @@
use core::{fmt::Debug, marker::PhantomData};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
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<const LIMBS: usize>:
Copy + Debug + Default + Eq + Send + Sync + 'static
{
/// Number of limbs required to encode a residue
const LIMBS: usize;
/// The constant modulus
const MODULUS: Uint<LIMBS>;
/// Parameter used in Montgomery reduction
const R: Uint<LIMBS>;
/// R^2, used to move into Montgomery form
const R2: Uint<LIMBS>;
/// R^3, used to perform a multiplicative inverse
const R3: Uint<LIMBS>;
/// 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.
/// Internally, the value is stored in Montgomery form (multiplied by MOD::R) until it is retrieved.
pub struct Residue<MOD, const LIMBS: usize>
where
MOD: ResidueParams<LIMBS>,
{
montgomery_form: Uint<LIMBS>,
phantom: PhantomData<MOD>,
}
#[cfg(feature = "zeroize")]
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> zeroize::DefaultIsZeroes
for Residue<MOD, LIMBS>
{
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
/// The representation of 0 mod `MOD`.
pub const ZERO: Self = Self {
montgomery_form: Uint::<LIMBS>::ZERO,
phantom: PhantomData,
};
/// The representation of 1 mod `MOD`.
pub const ONE: Self = Self {
montgomery_form: MOD::R,
phantom: PhantomData,
};
// Internal helper function to generate a residue; this lets us wrap the constructors more cleanly
const fn generate_residue(integer: &Uint<LIMBS>) -> Self {
let product = integer.mul_wide(&MOD::R2);
let montgomery_form =
montgomery_reduction::<LIMBS>(&product, &MOD::MODULUS, MOD::MOD_NEG_INV);
Self {
montgomery_form,
phantom: PhantomData,
}
}
/// Instantiates a new `Residue` that represents this `integer` mod `MOD`.
/// If the modulus represented by `MOD` is not odd, this function will panic; use [`new_checked`][`Residue::new_checked`] if you want to be able to detect an invalid modulus.
pub const fn new(integer: &Uint<LIMBS>) -> Self {
// A valid modulus must be odd
if MOD::MODULUS.ct_is_odd().to_u8() == 0 {
panic!("modulus must be odd");
}
Self::generate_residue(integer)
}
/// Instantiates a new `Residue` that represents this `integer` mod `MOD` if the modulus is odd.
/// Returns a `CtOption` that is `None` if the provided modulus is not odd; this is a safer version of [`new`][`Residue::new`], which can panic.
// TODO: remove this method when we can use `generic_const_exprs.` to ensure the modulus is
// always valid.
pub fn new_checked(integer: &Uint<LIMBS>) -> CtOption<Self> {
// A valid modulus must be odd.
CtOption::new(
Self::generate_residue(integer),
MOD::MODULUS.ct_is_odd().into(),
)
}
/// Retrieves the integer currently encoded in this `Residue`, guaranteed to be reduced.
pub const fn retrieve(&self) -> Uint<LIMBS> {
montgomery_reduction::<LIMBS>(
&(self.montgomery_form, Uint::ZERO),
&MOD::MODULUS,
MOD::MOD_NEG_INV,
)
}
/// Access the `Residue` value in Montgomery form.
pub const fn as_montgomery(&self) -> &Uint<LIMBS> {
&self.montgomery_form
}
/// Mutably access the `Residue` value in Montgomery form.
pub fn as_montgomery_mut(&mut self) -> &mut Uint<LIMBS> {
&mut self.montgomery_form
}
/// Create a `Residue` from a value in Montgomery form.
pub const fn from_montgomery(integer: Uint<LIMBS>) -> Self {
Self {
montgomery_form: integer,
phantom: PhantomData,
}
}
/// Extract the value from the `Residue` in Montgomery form.
pub const fn to_montgomery(&self) -> Uint<LIMBS> {
self.montgomery_form
}
/// 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<MOD: ResidueParams<LIMBS> + Copy, const LIMBS: usize> ConditionallySelectable
for Residue<MOD, LIMBS>
{
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<MOD: ResidueParams<LIMBS>, const LIMBS: usize> ConstantTimeEq for Residue<MOD, LIMBS> {
fn ct_eq(&self, other: &Self) -> Choice {
ConstantTimeEq::ct_eq(&self.montgomery_form, &other.montgomery_form)
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Default for Residue<MOD, LIMBS> {
fn default() -> Self {
Self::ZERO
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Zero for Residue<MOD, LIMBS> {
const ZERO: Self = Self::ZERO;
}
#[cfg(feature = "rand_core")]
impl<MOD, const LIMBS: usize> Random for Residue<MOD, LIMBS>
where
MOD: ResidueParams<LIMBS>,
{
#[inline]
fn random(rng: &mut impl CryptoRngCore) -> Self {
Self::new(&Uint::random_mod(rng, &NonZero::from_uint(MOD::MODULUS)))
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Retrieve for Residue<MOD, LIMBS> {
type Output = Uint<LIMBS>;
fn retrieve(&self) -> Self::Output {
self.retrieve()
}
}
#[cfg(feature = "serde")]
impl<'de, MOD, const LIMBS: usize> Deserialize<'de> for Residue<MOD, LIMBS>
where
MOD: ResidueParams<LIMBS>,
Uint<LIMBS>: Encoding,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Uint::<LIMBS>::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<MOD, const LIMBS: usize> Serialize for Residue<MOD, LIMBS>
where
MOD: ResidueParams<LIMBS>,
Uint<LIMBS>: Encoding,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.montgomery_form.serialize(serializer)
}
}

View File

@@ -0,0 +1,98 @@
use core::ops::{Add, AddAssign};
use crate::modular::add::add_montgomery_form;
use super::{Residue, ResidueParams};
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
/// Adds `rhs`.
pub const fn add(&self, rhs: &Residue<MOD, LIMBS>) -> Self {
Self {
montgomery_form: add_montgomery_form(
&self.montgomery_form,
&rhs.montgomery_form,
&MOD::MODULUS,
),
phantom: core::marker::PhantomData,
}
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Add<&Residue<MOD, LIMBS>>
for &Residue<MOD, LIMBS>
{
type Output = Residue<MOD, LIMBS>;
fn add(self, rhs: &Residue<MOD, LIMBS>) -> Residue<MOD, LIMBS> {
self.add(rhs)
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Add<Residue<MOD, LIMBS>>
for &Residue<MOD, LIMBS>
{
type Output = Residue<MOD, LIMBS>;
#[allow(clippy::op_ref)]
fn add(self, rhs: Residue<MOD, LIMBS>) -> Residue<MOD, LIMBS> {
self + &rhs
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Add<&Residue<MOD, LIMBS>>
for Residue<MOD, LIMBS>
{
type Output = Residue<MOD, LIMBS>;
#[allow(clippy::op_ref)]
fn add(self, rhs: &Residue<MOD, LIMBS>) -> Residue<MOD, LIMBS> {
&self + rhs
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Add<Residue<MOD, LIMBS>>
for Residue<MOD, LIMBS>
{
type Output = Residue<MOD, LIMBS>;
fn add(self, rhs: Residue<MOD, LIMBS>) -> Residue<MOD, LIMBS> {
&self + &rhs
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> AddAssign<&Self> for Residue<MOD, LIMBS> {
fn add_assign(&mut self, rhs: &Self) {
*self = *self + rhs;
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> AddAssign<Self> for Residue<MOD, LIMBS> {
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());
}
}

View File

@@ -0,0 +1,69 @@
use core::marker::PhantomData;
use subtle::CtOption;
use crate::{modular::inv::inv_montgomery_form, traits::Invert, CtChoice, NonZero};
use super::{Residue, ResidueParams};
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
/// 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<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Invert for Residue<MOD, LIMBS> {
type Output = CtOption<Self>;
fn invert(&self) -> Self::Output {
let (value, is_some) = self.invert();
CtOption::new(value, is_some.into())
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Invert for NonZero<Residue<MOD, LIMBS>> {
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);
}
}

View File

@@ -0,0 +1,94 @@
use core::{
marker::PhantomData,
ops::{Mul, MulAssign},
};
use crate::{
modular::mul::{mul_montgomery_form, square_montgomery_form},
traits::Square,
};
use super::{Residue, ResidueParams};
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
/// 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<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Mul<&Residue<MOD, LIMBS>>
for &Residue<MOD, LIMBS>
{
type Output = Residue<MOD, LIMBS>;
fn mul(self, rhs: &Residue<MOD, LIMBS>) -> Residue<MOD, LIMBS> {
self.mul(rhs)
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Mul<Residue<MOD, LIMBS>>
for &Residue<MOD, LIMBS>
{
type Output = Residue<MOD, LIMBS>;
#[allow(clippy::op_ref)]
fn mul(self, rhs: Residue<MOD, LIMBS>) -> Residue<MOD, LIMBS> {
self * &rhs
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Mul<&Residue<MOD, LIMBS>>
for Residue<MOD, LIMBS>
{
type Output = Residue<MOD, LIMBS>;
#[allow(clippy::op_ref)]
fn mul(self, rhs: &Residue<MOD, LIMBS>) -> Residue<MOD, LIMBS> {
&self * rhs
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Mul<Residue<MOD, LIMBS>>
for Residue<MOD, LIMBS>
{
type Output = Residue<MOD, LIMBS>;
fn mul(self, rhs: Residue<MOD, LIMBS>) -> Residue<MOD, LIMBS> {
&self * &rhs
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> MulAssign<&Self> for Residue<MOD, LIMBS> {
fn mul_assign(&mut self, rhs: &Residue<MOD, LIMBS>) {
*self = *self * rhs;
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> MulAssign<Self> for Residue<MOD, LIMBS> {
fn mul_assign(&mut self, rhs: Self) {
*self *= &rhs;
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Square for Residue<MOD, LIMBS> {
fn square(&self) -> Self {
Residue::square(self)
}
}

View File

@@ -0,0 +1,48 @@
use core::ops::Neg;
use super::{Residue, ResidueParams};
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
/// Negates the number.
pub const fn neg(&self) -> Self {
Self::ZERO.sub(self)
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Neg for Residue<MOD, LIMBS> {
type Output = Self;
fn neg(self) -> Self {
Residue::neg(&self)
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Neg for &Residue<MOD, LIMBS> {
type Output = Residue<MOD, LIMBS>;
fn neg(self) -> Residue<MOD, LIMBS> {
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);
}
}

View File

@@ -0,0 +1,233 @@
use crate::{modular::pow::pow_montgomery_form, MultiExponentiateBoundedExp, PowBoundedExp, Uint};
use super::{Residue, ResidueParams};
use crate::modular::pow::multi_exponentiate_montgomery_form_array;
#[cfg(feature = "alloc")]
use crate::modular::pow::multi_exponentiate_montgomery_form_slice;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
/// Raises to the `exponent` power.
pub const fn pow<const RHS_LIMBS: usize>(
&self,
exponent: &Uint<RHS_LIMBS>,
) -> Residue<MOD, LIMBS> {
self.pow_bounded_exp(exponent, Uint::<RHS_LIMBS>::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<const RHS_LIMBS: usize>(
&self,
exponent: &Uint<RHS_LIMBS>,
exponent_bits: usize,
) -> Residue<MOD, LIMBS> {
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<MOD: ResidueParams<LIMBS>, const LIMBS: usize, const RHS_LIMBS: usize>
PowBoundedExp<Uint<RHS_LIMBS>> for Residue<MOD, LIMBS>
{
fn pow_bounded_exp(&self, exponent: &Uint<RHS_LIMBS>, exponent_bits: usize) -> Self {
self.pow_bounded_exp(exponent, exponent_bits)
}
}
impl<const N: usize, MOD: ResidueParams<LIMBS>, const LIMBS: usize, const RHS_LIMBS: usize>
MultiExponentiateBoundedExp<Uint<RHS_LIMBS>, [(Self, Uint<RHS_LIMBS>); N]>
for Residue<MOD, LIMBS>
{
fn multi_exponentiate_bounded_exp(
bases_and_exponents: &[(Self, Uint<RHS_LIMBS>); N],
exponent_bits: usize,
) -> Self {
let mut bases_and_exponents_montgomery_form =
[(Uint::<LIMBS>::ZERO, Uint::<RHS_LIMBS>::ZERO); N];
let mut i = 0;
while i < N {
let (base, exponent) = bases_and_exponents[i];
bases_and_exponents_montgomery_form[i] = (base.montgomery_form, exponent);
i += 1;
}
Self {
montgomery_form: multi_exponentiate_montgomery_form_array(
&bases_and_exponents_montgomery_form,
exponent_bits,
&MOD::MODULUS,
&MOD::R,
MOD::MOD_NEG_INV,
),
phantom: core::marker::PhantomData,
}
}
}
#[cfg(feature = "alloc")]
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize, const RHS_LIMBS: usize>
MultiExponentiateBoundedExp<Uint<RHS_LIMBS>, [(Self, Uint<RHS_LIMBS>)]>
for Residue<MOD, LIMBS>
{
fn multi_exponentiate_bounded_exp(
bases_and_exponents: &[(Self, Uint<RHS_LIMBS>)],
exponent_bits: usize,
) -> Self {
let bases_and_exponents: Vec<(Uint<LIMBS>, Uint<RHS_LIMBS>)> = bases_and_exponents
.iter()
.map(|(base, exp)| (base.montgomery_form, *exp))
.collect();
Self {
montgomery_form: multi_exponentiate_montgomery_form_slice(
&bases_and_exponents,
exponent_bits,
&MOD::MODULUS,
&MOD::R,
MOD::MOD_NEG_INV,
),
phantom: core::marker::PhantomData,
}
}
}
#[cfg(test)]
mod tests {
use crate::traits::MultiExponentiate;
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);
}
#[test]
fn test_multi_exp_array() {
let base = U256::from(2u8);
let base_mod = const_residue!(base, Modulus);
let exponent = U256::from(33u8);
let bases_and_exponents = [(base_mod, exponent)];
let res =
crate::modular::constant_mod::Residue::<Modulus, { U256::LIMBS }>::multi_exponentiate(
&bases_and_exponents,
);
let expected =
U256::from_be_hex("0000000000000000000000000000000000000000000000000000000200000000");
assert_eq!(res.retrieve(), expected);
let base2 =
U256::from_be_hex("3435D18AA8313EBBE4D20002922225B53F75DC4453BB3EEC0378646F79B524A4");
let base2_mod = const_residue!(base2, Modulus);
let exponent2 =
U256::from_be_hex("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685");
let expected = base_mod.pow(&exponent) * base2_mod.pow(&exponent2);
let bases_and_exponents = [(base_mod, exponent), (base2_mod, exponent2)];
let res =
crate::modular::constant_mod::Residue::<Modulus, { U256::LIMBS }>::multi_exponentiate(
&bases_and_exponents,
);
assert_eq!(res, expected);
}
#[cfg(feature = "alloc")]
#[test]
fn test_multi_exp_slice() {
let base = U256::from(2u8);
let base_mod = const_residue!(base, Modulus);
let exponent = U256::from(33u8);
let bases_and_exponents = vec![(base_mod, exponent)];
let res =
crate::modular::constant_mod::Residue::<Modulus, { U256::LIMBS }>::multi_exponentiate(
bases_and_exponents.as_slice(),
);
let expected =
U256::from_be_hex("0000000000000000000000000000000000000000000000000000000200000000");
assert_eq!(res.retrieve(), expected);
let base2 =
U256::from_be_hex("3435D18AA8313EBBE4D20002922225B53F75DC4453BB3EEC0378646F79B524A4");
let base2_mod = const_residue!(base2, Modulus);
let exponent2 =
U256::from_be_hex("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685");
let expected = base_mod.pow(&exponent) * base2_mod.pow(&exponent2);
let bases_and_exponents = vec![(base_mod, exponent), (base2_mod, exponent2)];
let res =
crate::modular::constant_mod::Residue::<Modulus, { U256::LIMBS }>::multi_exponentiate(
bases_and_exponents.as_slice(),
);
assert_eq!(res, expected);
}
}

View File

@@ -0,0 +1,98 @@
use core::ops::{Sub, SubAssign};
use crate::modular::sub::sub_montgomery_form;
use super::{Residue, ResidueParams};
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
/// 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<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Sub<&Residue<MOD, LIMBS>>
for &Residue<MOD, LIMBS>
{
type Output = Residue<MOD, LIMBS>;
fn sub(self, rhs: &Residue<MOD, LIMBS>) -> Residue<MOD, LIMBS> {
self.sub(rhs)
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Sub<Residue<MOD, LIMBS>>
for &Residue<MOD, LIMBS>
{
type Output = Residue<MOD, LIMBS>;
#[allow(clippy::op_ref)]
fn sub(self, rhs: Residue<MOD, LIMBS>) -> Residue<MOD, LIMBS> {
self - &rhs
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Sub<&Residue<MOD, LIMBS>>
for Residue<MOD, LIMBS>
{
type Output = Residue<MOD, LIMBS>;
#[allow(clippy::op_ref)]
fn sub(self, rhs: &Residue<MOD, LIMBS>) -> Residue<MOD, LIMBS> {
&self - rhs
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Sub<Residue<MOD, LIMBS>>
for Residue<MOD, LIMBS>
{
type Output = Residue<MOD, LIMBS>;
fn sub(self, rhs: Residue<MOD, LIMBS>) -> Residue<MOD, LIMBS> {
&self - &rhs
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> SubAssign<&Self> for Residue<MOD, LIMBS> {
fn sub_assign(&mut self, rhs: &Self) {
*self = *self - rhs;
}
}
impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> SubAssign<Self> for Residue<MOD, LIMBS> {
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());
}
}

View File

@@ -0,0 +1,57 @@
// 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`.
/// The modulus _must_ be odd, or this will panic.
macro_rules! impl_modulus {
($name:ident, $uint_type:ty, $value:expr) => {
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct $name {}
impl<const DLIMBS: usize>
$crate::modular::constant_mod::ResidueParams<{ <$uint_type>::LIMBS }> for $name
where
$uint_type: $crate::ConcatMixed<MixedOutput = $crate::Uint<DLIMBS>>,
{
const LIMBS: usize = <$uint_type>::LIMBS;
const MODULUS: $uint_type = {
let res = <$uint_type>::from_be_hex($value);
// Check that the modulus is odd
if res.as_limbs()[0].0 & 1 == 0 {
panic!("modulus must be odd");
}
res
};
const R: $uint_type = $crate::Uint::MAX
.const_rem(&Self::MODULUS)
.0
.wrapping_add(&$crate::Uint::ONE);
const R2: $uint_type =
$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_vartime($crate::Word::BITS as usize)
.as_limbs()[0]
.0,
),
);
const R3: $uint_type = $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`.
/// The modulus _must_ be odd, or this will panic.
macro_rules! const_residue {
($variable:ident, $modulus:ident) => {
$crate::modular::constant_mod::Residue::<$modulus, { $modulus::LIMBS }>::new(&$variable)
};
}

View File

@@ -0,0 +1,30 @@
use crate::Uint;
pub(crate) fn div_by_2<const LIMBS: usize>(a: &Uint<LIMBS>, modulus: &Uint<LIMBS>) -> Uint<LIMBS> {
// 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::<LIMBS>::ONE);
Uint::<LIMBS>::ct_select(&if_even, &if_odd, is_odd)
}

View File

@@ -0,0 +1,14 @@
use crate::{modular::reduction::montgomery_reduction, CtChoice, Limb, Uint};
pub const fn inv_montgomery_form<const LIMBS: usize>(
x: &Uint<LIMBS>,
modulus: &Uint<LIMBS>,
r3: &Uint<LIMBS>,
mod_neg_inv: Limb,
) -> (Uint<LIMBS>, CtChoice) {
let (inverse, is_some) = x.inv_odd_mod(modulus);
(
montgomery_reduction(&inverse.mul_wide(r3), modulus, mod_neg_inv),
is_some,
)
}

View File

@@ -0,0 +1,22 @@
use crate::{Limb, Uint};
use super::reduction::montgomery_reduction;
pub(crate) const fn mul_montgomery_form<const LIMBS: usize>(
a: &Uint<LIMBS>,
b: &Uint<LIMBS>,
modulus: &Uint<LIMBS>,
mod_neg_inv: Limb,
) -> Uint<LIMBS> {
let product = a.mul_wide(b);
montgomery_reduction::<LIMBS>(&product, modulus, mod_neg_inv)
}
pub(crate) const fn square_montgomery_form<const LIMBS: usize>(
a: &Uint<LIMBS>,
modulus: &Uint<LIMBS>,
mod_neg_inv: Limb,
) -> Uint<LIMBS> {
let product = a.square_wide();
montgomery_reduction::<LIMBS>(&product, modulus, mod_neg_inv)
}

View File

@@ -0,0 +1,178 @@
use crate::{Limb, Uint, Word};
use super::mul::{mul_montgomery_form, square_montgomery_form};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
const WINDOW: usize = 4;
const WINDOW_MASK: Word = (1 << WINDOW) - 1;
/// 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<const LIMBS: usize, const RHS_LIMBS: usize>(
x: &Uint<LIMBS>,
exponent: &Uint<RHS_LIMBS>,
exponent_bits: usize,
modulus: &Uint<LIMBS>,
r: &Uint<LIMBS>,
mod_neg_inv: Limb,
) -> Uint<LIMBS> {
multi_exponentiate_montgomery_form_array(
&[(*x, *exponent)],
exponent_bits,
modulus,
r,
mod_neg_inv,
)
}
pub const fn multi_exponentiate_montgomery_form_array<
const LIMBS: usize,
const RHS_LIMBS: usize,
const N: usize,
>(
bases_and_exponents: &[(Uint<LIMBS>, Uint<RHS_LIMBS>); N],
exponent_bits: usize,
modulus: &Uint<LIMBS>,
r: &Uint<LIMBS>,
mod_neg_inv: Limb,
) -> Uint<LIMBS> {
if exponent_bits == 0 {
return *r; // 1 in Montgomery form
}
let mut powers_and_exponents =
[([Uint::<LIMBS>::ZERO; 1 << WINDOW], Uint::<RHS_LIMBS>::ZERO); N];
let mut i = 0;
while i < N {
let (base, exponent) = bases_and_exponents[i];
powers_and_exponents[i] = (compute_powers(&base, modulus, r, mod_neg_inv), exponent);
i += 1;
}
multi_exponentiate_montgomery_form_internal(
&powers_and_exponents,
exponent_bits,
modulus,
r,
mod_neg_inv,
)
}
/// Performs modular multi-exponentiation using Montgomery's ladder.
/// `exponent_bits` represents the number of bits to take into account for the exponent.
///
/// See: Straus, E. G. Problems and solutions: Addition chains of vectors. American Mathematical Monthly 71 (1964), 806808.
///
/// NOTE: this value is leaked in the time pattern.
#[cfg(feature = "alloc")]
pub fn multi_exponentiate_montgomery_form_slice<const LIMBS: usize, const RHS_LIMBS: usize>(
bases_and_exponents: &[(Uint<LIMBS>, Uint<RHS_LIMBS>)],
exponent_bits: usize,
modulus: &Uint<LIMBS>,
r: &Uint<LIMBS>,
mod_neg_inv: Limb,
) -> Uint<LIMBS> {
if exponent_bits == 0 {
return *r; // 1 in Montgomery form
}
let powers_and_exponents: Vec<([Uint<LIMBS>; 1 << WINDOW], Uint<RHS_LIMBS>)> =
bases_and_exponents
.iter()
.map(|(base, exponent)| (compute_powers(base, modulus, r, mod_neg_inv), *exponent))
.collect();
multi_exponentiate_montgomery_form_internal(
powers_and_exponents.as_slice(),
exponent_bits,
modulus,
r,
mod_neg_inv,
)
}
const fn compute_powers<const LIMBS: usize>(
x: &Uint<LIMBS>,
modulus: &Uint<LIMBS>,
r: &Uint<LIMBS>,
mod_neg_inv: Limb,
) -> [Uint<LIMBS>; 1 << WINDOW] {
// 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;
}
powers
}
const fn multi_exponentiate_montgomery_form_internal<const LIMBS: usize, const RHS_LIMBS: usize>(
powers_and_exponents: &[([Uint<LIMBS>; 1 << WINDOW], Uint<RHS_LIMBS>)],
exponent_bits: usize,
modulus: &Uint<LIMBS>,
r: &Uint<LIMBS>,
mod_neg_inv: Limb,
) -> Uint<LIMBS> {
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 mut window_num = if limb_num == starting_limb {
starting_window + 1
} else {
Limb::BITS / WINDOW
};
while window_num > 0 {
window_num -= 1;
if limb_num != starting_limb || window_num != starting_window {
let mut i = 0;
while i < WINDOW {
i += 1;
z = square_montgomery_form(&z, modulus, mod_neg_inv);
}
}
let mut i = 0;
while i < powers_and_exponents.len() {
let (powers, exponent) = powers_and_exponents[i];
let w = exponent.as_limbs()[limb_num].0;
let mut idx = (w >> (window_num * WINDOW)) & WINDOW_MASK;
if limb_num == starting_limb && window_num == starting_window {
idx &= starting_window_mask;
}
// Constant-time lookup in the array of powers
let mut power = powers[0];
let mut j = 1;
while j < 1 << WINDOW {
let choice = Limb::ct_eq(Limb(j as Word), Limb(idx));
power = Uint::<LIMBS>::ct_select(&power, &powers[j], choice);
j += 1;
}
z = mul_montgomery_form(&z, &power, modulus, mod_neg_inv);
i += 1;
}
}
}
z
}

View File

@@ -0,0 +1,55 @@
use 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 <https://cacr.uwaterloo.ca/hac/about/chap14.pdf>
pub const fn montgomery_reduction<const LIMBS: usize>(
lower_upper: &(Uint<LIMBS>, Uint<LIMBS>),
modulus: &Uint<LIMBS>,
mod_neg_inv: Limb,
) -> Uint<LIMBS> {
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)
}

View File

@@ -0,0 +1,300 @@
use crate::{Limb, Uint, Word};
use super::{
constant_mod::{Residue, ResidueParams},
div_by_2::div_by_2,
reduction::montgomery_reduction,
Retrieve,
};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
/// 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 an odd modulus provided at runtime.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DynResidueParams<const LIMBS: usize> {
// The constant modulus
modulus: Uint<LIMBS>,
// Parameter used in Montgomery reduction
r: Uint<LIMBS>,
// R^2, used to move into Montgomery form
r2: Uint<LIMBS>,
// R^3, used to compute the multiplicative inverse
r3: Uint<LIMBS>,
// 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<const LIMBS: usize> DynResidueParams<LIMBS> {
// Internal helper function to generate parameters; this lets us wrap the constructors more cleanly
const fn generate_params(modulus: &Uint<LIMBS>) -> 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_vartime(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,
}
}
/// Instantiates a new set of `ResidueParams` representing the given `modulus`, which _must_ be odd.
/// If `modulus` is not odd, this function will panic; use [`new_checked`][`DynResidueParams::new_checked`] if you want to be able to detect an invalid modulus.
pub const fn new(modulus: &Uint<LIMBS>) -> Self {
// A valid modulus must be odd
if modulus.ct_is_odd().to_u8() == 0 {
panic!("modulus must be odd");
}
Self::generate_params(modulus)
}
/// Instantiates a new set of `ResidueParams` representing the given `modulus` if it is odd.
/// Returns a `CtOption` that is `None` if the provided modulus is not odd; this is a safer version of [`new`][`DynResidueParams::new`], which can panic.
#[deprecated(
since = "0.5.3",
note = "This functionality will be moved to `new` in a future release."
)]
pub fn new_checked(modulus: &Uint<LIMBS>) -> CtOption<Self> {
// A valid modulus must be odd.
CtOption::new(Self::generate_params(modulus), modulus.ct_is_odd().into())
}
/// Returns the modulus which was used to initialize these parameters.
pub const fn modulus(&self) -> &Uint<LIMBS> {
&self.modulus
}
/// Create `DynResidueParams` corresponding to a `ResidueParams`.
pub const fn from_residue_params<P>() -> Self
where
P: ResidueParams<LIMBS>,
{
Self {
modulus: P::MODULUS,
r: P::R,
r2: P::R2,
r3: P::R3,
mod_neg_inv: P::MOD_NEG_INV,
}
}
}
impl<const LIMBS: usize> ConditionallySelectable for DynResidueParams<LIMBS> {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self {
modulus: Uint::conditional_select(&a.modulus, &b.modulus, choice),
r: Uint::conditional_select(&a.r, &b.r, choice),
r2: Uint::conditional_select(&a.r2, &b.r2, choice),
r3: Uint::conditional_select(&a.r3, &b.r3, choice),
mod_neg_inv: Limb::conditional_select(&a.mod_neg_inv, &b.mod_neg_inv, choice),
}
}
}
impl<const LIMBS: usize> ConstantTimeEq for DynResidueParams<LIMBS> {
fn ct_eq(&self, other: &Self) -> Choice {
self.modulus.ct_eq(&other.modulus)
& self.r.ct_eq(&other.r)
& self.r2.ct_eq(&other.r2)
& self.r3.ct_eq(&other.r3)
& self.mod_neg_inv.ct_eq(&other.mod_neg_inv)
}
}
/// 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<const LIMBS: usize> {
montgomery_form: Uint<LIMBS>,
residue_params: DynResidueParams<LIMBS>,
}
impl<const LIMBS: usize> DynResidue<LIMBS> {
/// Instantiates a new `Residue` that represents this `integer` mod `MOD`.
pub const fn new(integer: &Uint<LIMBS>, residue_params: DynResidueParams<LIMBS>) -> 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<LIMBS> {
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<LIMBS>) -> Self {
Self {
montgomery_form: Uint::<LIMBS>::ZERO,
residue_params,
}
}
/// Instantiates a new `Residue` that represents 1.
pub const fn one(residue_params: DynResidueParams<LIMBS>) -> Self {
Self {
montgomery_form: residue_params.r,
residue_params,
}
}
/// Returns the parameter struct used to initialize this residue.
pub const fn params(&self) -> &DynResidueParams<LIMBS> {
&self.residue_params
}
/// Access the `DynResidue` value in Montgomery form.
pub const fn as_montgomery(&self) -> &Uint<LIMBS> {
&self.montgomery_form
}
/// Mutably access the `DynResidue` value in Montgomery form.
pub fn as_montgomery_mut(&mut self) -> &mut Uint<LIMBS> {
&mut self.montgomery_form
}
/// Create a `DynResidue` from a value in Montgomery form.
pub const fn from_montgomery(
integer: Uint<LIMBS>,
residue_params: DynResidueParams<LIMBS>,
) -> Self {
Self {
montgomery_form: integer,
residue_params,
}
}
/// Extract the value from the `DynResidue` in Montgomery form.
pub const fn to_montgomery(&self) -> Uint<LIMBS> {
self.montgomery_form
}
/// 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<const LIMBS: usize> Retrieve for DynResidue<LIMBS> {
type Output = Uint<LIMBS>;
fn retrieve(&self) -> Self::Output {
self.retrieve()
}
}
impl<const LIMBS: usize, P: ResidueParams<LIMBS>> From<&Residue<P, LIMBS>> for DynResidue<LIMBS> {
fn from(residue: &Residue<P, LIMBS>) -> Self {
Self {
montgomery_form: residue.to_montgomery(),
residue_params: DynResidueParams::from_residue_params::<P>(),
}
}
}
impl<const LIMBS: usize> ConditionallySelectable for DynResidue<LIMBS> {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self {
montgomery_form: Uint::conditional_select(
&a.montgomery_form,
&b.montgomery_form,
choice,
),
residue_params: DynResidueParams::conditional_select(
&a.residue_params,
&b.residue_params,
choice,
),
}
}
}
impl<const LIMBS: usize> ConstantTimeEq for DynResidue<LIMBS> {
fn ct_eq(&self, other: &Self) -> Choice {
self.montgomery_form.ct_eq(&other.montgomery_form)
& self.residue_params.ct_eq(&other.residue_params)
}
}
/// NOTE: this does _not_ zeroize the parameters, in order to maintain some form of type consistency
#[cfg(feature = "zeroize")]
impl<const LIMBS: usize> zeroize::Zeroize for DynResidue<LIMBS> {
fn zeroize(&mut self) {
self.montgomery_form.zeroize()
}
}
#[cfg(test)]
mod test {
use super::*;
const LIMBS: usize = nlimbs!(64);
#[test]
#[allow(deprecated)]
// Test that a valid modulus yields `DynResidueParams`
fn test_valid_modulus() {
let valid_modulus = Uint::<LIMBS>::from(3u8);
DynResidueParams::<LIMBS>::new_checked(&valid_modulus).unwrap();
DynResidueParams::<LIMBS>::new(&valid_modulus);
}
#[test]
#[allow(deprecated)]
// Test that an invalid checked modulus does not yield `DynResidueParams`
fn test_invalid_checked_modulus() {
assert!(bool::from(
DynResidueParams::<LIMBS>::new_checked(&Uint::from(2u8)).is_none()
))
}
#[test]
#[should_panic]
// Tets that an invalid modulus panics
fn test_invalid_modulus() {
DynResidueParams::<LIMBS>::new(&Uint::from(2u8));
}
}

View File

@@ -0,0 +1,92 @@
use core::ops::{Add, AddAssign};
use crate::modular::add::add_montgomery_form;
use super::DynResidue;
impl<const LIMBS: usize> DynResidue<LIMBS> {
/// 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<const LIMBS: usize> Add<&DynResidue<LIMBS>> for &DynResidue<LIMBS> {
type Output = DynResidue<LIMBS>;
fn add(self, rhs: &DynResidue<LIMBS>) -> DynResidue<LIMBS> {
debug_assert_eq!(self.residue_params, rhs.residue_params);
self.add(rhs)
}
}
impl<const LIMBS: usize> Add<DynResidue<LIMBS>> for &DynResidue<LIMBS> {
type Output = DynResidue<LIMBS>;
#[allow(clippy::op_ref)]
fn add(self, rhs: DynResidue<LIMBS>) -> DynResidue<LIMBS> {
self + &rhs
}
}
impl<const LIMBS: usize> Add<&DynResidue<LIMBS>> for DynResidue<LIMBS> {
type Output = DynResidue<LIMBS>;
#[allow(clippy::op_ref)]
fn add(self, rhs: &DynResidue<LIMBS>) -> DynResidue<LIMBS> {
&self + rhs
}
}
impl<const LIMBS: usize> Add<DynResidue<LIMBS>> for DynResidue<LIMBS> {
type Output = DynResidue<LIMBS>;
fn add(self, rhs: DynResidue<LIMBS>) -> DynResidue<LIMBS> {
&self + &rhs
}
}
impl<const LIMBS: usize> AddAssign<&DynResidue<LIMBS>> for DynResidue<LIMBS> {
fn add_assign(&mut self, rhs: &DynResidue<LIMBS>) {
*self = *self + rhs;
}
}
impl<const LIMBS: usize> AddAssign<DynResidue<LIMBS>> for DynResidue<LIMBS> {
fn add_assign(&mut self, rhs: DynResidue<LIMBS>) {
*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());
}
}

View File

@@ -0,0 +1,35 @@
use subtle::CtOption;
use crate::{modular::inv::inv_montgomery_form, traits::Invert, CtChoice};
use super::DynResidue;
impl<const LIMBS: usize> DynResidue<LIMBS> {
/// 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<const LIMBS: usize> Invert for DynResidue<LIMBS> {
type Output = CtOption<Self>;
fn invert(&self) -> Self::Output {
let (value, is_some) = self.invert();
CtOption::new(value, is_some.into())
}
}

View File

@@ -0,0 +1,84 @@
use core::ops::{Mul, MulAssign};
use crate::{
modular::mul::{mul_montgomery_form, square_montgomery_form},
traits::Square,
};
use super::DynResidue;
impl<const LIMBS: usize> DynResidue<LIMBS> {
/// 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<const LIMBS: usize> Mul<&DynResidue<LIMBS>> for &DynResidue<LIMBS> {
type Output = DynResidue<LIMBS>;
fn mul(self, rhs: &DynResidue<LIMBS>) -> DynResidue<LIMBS> {
debug_assert_eq!(self.residue_params, rhs.residue_params);
self.mul(rhs)
}
}
impl<const LIMBS: usize> Mul<DynResidue<LIMBS>> for &DynResidue<LIMBS> {
type Output = DynResidue<LIMBS>;
#[allow(clippy::op_ref)]
fn mul(self, rhs: DynResidue<LIMBS>) -> DynResidue<LIMBS> {
self * &rhs
}
}
impl<const LIMBS: usize> Mul<&DynResidue<LIMBS>> for DynResidue<LIMBS> {
type Output = DynResidue<LIMBS>;
#[allow(clippy::op_ref)]
fn mul(self, rhs: &DynResidue<LIMBS>) -> DynResidue<LIMBS> {
&self * rhs
}
}
impl<const LIMBS: usize> Mul<DynResidue<LIMBS>> for DynResidue<LIMBS> {
type Output = DynResidue<LIMBS>;
fn mul(self, rhs: DynResidue<LIMBS>) -> DynResidue<LIMBS> {
&self * &rhs
}
}
impl<const LIMBS: usize> MulAssign<&DynResidue<LIMBS>> for DynResidue<LIMBS> {
fn mul_assign(&mut self, rhs: &DynResidue<LIMBS>) {
*self = *self * rhs;
}
}
impl<const LIMBS: usize> MulAssign<DynResidue<LIMBS>> for DynResidue<LIMBS> {
fn mul_assign(&mut self, rhs: DynResidue<LIMBS>) {
*self *= &rhs;
}
}
impl<const LIMBS: usize> Square for DynResidue<LIMBS> {
fn square(&self) -> Self {
DynResidue::square(self)
}
}

View File

@@ -0,0 +1,24 @@
use core::ops::Neg;
use super::DynResidue;
impl<const LIMBS: usize> DynResidue<LIMBS> {
/// Negates the number.
pub const fn neg(&self) -> Self {
Self::zero(self.residue_params).sub(self)
}
}
impl<const LIMBS: usize> Neg for DynResidue<LIMBS> {
type Output = Self;
fn neg(self) -> Self {
DynResidue::neg(&self)
}
}
impl<const LIMBS: usize> Neg for &DynResidue<LIMBS> {
type Output = DynResidue<LIMBS>;
fn neg(self) -> DynResidue<LIMBS> {
DynResidue::neg(self)
}
}

View File

@@ -0,0 +1,113 @@
use super::DynResidue;
use crate::modular::pow::multi_exponentiate_montgomery_form_array;
#[cfg(feature = "alloc")]
use crate::modular::pow::multi_exponentiate_montgomery_form_slice;
use crate::{modular::pow::pow_montgomery_form, MultiExponentiateBoundedExp, PowBoundedExp, Uint};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
impl<const LIMBS: usize> DynResidue<LIMBS> {
/// Raises to the `exponent` power.
pub const fn pow<const RHS_LIMBS: usize>(
&self,
exponent: &Uint<RHS_LIMBS>,
) -> DynResidue<LIMBS> {
self.pow_bounded_exp(exponent, Uint::<RHS_LIMBS>::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<const RHS_LIMBS: usize>(
&self,
exponent: &Uint<RHS_LIMBS>,
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<const LIMBS: usize, const RHS_LIMBS: usize> PowBoundedExp<Uint<RHS_LIMBS>>
for DynResidue<LIMBS>
{
fn pow_bounded_exp(&self, exponent: &Uint<RHS_LIMBS>, exponent_bits: usize) -> Self {
self.pow_bounded_exp(exponent, exponent_bits)
}
}
impl<const N: usize, const LIMBS: usize, const RHS_LIMBS: usize>
MultiExponentiateBoundedExp<Uint<RHS_LIMBS>, [(Self, Uint<RHS_LIMBS>); N]>
for DynResidue<LIMBS>
{
fn multi_exponentiate_bounded_exp(
bases_and_exponents: &[(Self, Uint<RHS_LIMBS>); N],
exponent_bits: usize,
) -> Self {
const_assert_ne!(N, 0, "bases_and_exponents must not be empty");
let residue_params = bases_and_exponents[0].0.residue_params;
let mut bases_and_exponents_montgomery_form =
[(Uint::<LIMBS>::ZERO, Uint::<RHS_LIMBS>::ZERO); N];
let mut i = 0;
while i < N {
let (base, exponent) = bases_and_exponents[i];
bases_and_exponents_montgomery_form[i] = (base.montgomery_form, exponent);
i += 1;
}
Self {
montgomery_form: multi_exponentiate_montgomery_form_array(
&bases_and_exponents_montgomery_form,
exponent_bits,
&residue_params.modulus,
&residue_params.r,
residue_params.mod_neg_inv,
),
residue_params,
}
}
}
#[cfg(feature = "alloc")]
impl<const LIMBS: usize, const RHS_LIMBS: usize>
MultiExponentiateBoundedExp<Uint<RHS_LIMBS>, [(Self, Uint<RHS_LIMBS>)]> for DynResidue<LIMBS>
{
fn multi_exponentiate_bounded_exp(
bases_and_exponents: &[(Self, Uint<RHS_LIMBS>)],
exponent_bits: usize,
) -> Self {
assert!(
!bases_and_exponents.is_empty(),
"bases_and_exponents must not be empty"
);
let residue_params = bases_and_exponents[0].0.residue_params;
let bases_and_exponents: Vec<(Uint<LIMBS>, Uint<RHS_LIMBS>)> = bases_and_exponents
.iter()
.map(|(base, exp)| (base.montgomery_form, *exp))
.collect();
Self {
montgomery_form: multi_exponentiate_montgomery_form_slice(
&bases_and_exponents,
exponent_bits,
&residue_params.modulus,
&residue_params.r,
residue_params.mod_neg_inv,
),
residue_params,
}
}
}

View File

@@ -0,0 +1,92 @@
use core::ops::{Sub, SubAssign};
use crate::modular::sub::sub_montgomery_form;
use super::DynResidue;
impl<const LIMBS: usize> DynResidue<LIMBS> {
/// 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<const LIMBS: usize> Sub<&DynResidue<LIMBS>> for &DynResidue<LIMBS> {
type Output = DynResidue<LIMBS>;
fn sub(self, rhs: &DynResidue<LIMBS>) -> DynResidue<LIMBS> {
debug_assert_eq!(self.residue_params, rhs.residue_params);
self.sub(rhs)
}
}
impl<const LIMBS: usize> Sub<DynResidue<LIMBS>> for &DynResidue<LIMBS> {
type Output = DynResidue<LIMBS>;
#[allow(clippy::op_ref)]
fn sub(self, rhs: DynResidue<LIMBS>) -> DynResidue<LIMBS> {
self - &rhs
}
}
impl<const LIMBS: usize> Sub<&DynResidue<LIMBS>> for DynResidue<LIMBS> {
type Output = DynResidue<LIMBS>;
#[allow(clippy::op_ref)]
fn sub(self, rhs: &DynResidue<LIMBS>) -> DynResidue<LIMBS> {
&self - rhs
}
}
impl<const LIMBS: usize> Sub<DynResidue<LIMBS>> for DynResidue<LIMBS> {
type Output = DynResidue<LIMBS>;
fn sub(self, rhs: DynResidue<LIMBS>) -> DynResidue<LIMBS> {
&self - &rhs
}
}
impl<const LIMBS: usize> SubAssign<&DynResidue<LIMBS>> for DynResidue<LIMBS> {
fn sub_assign(&mut self, rhs: &DynResidue<LIMBS>) {
*self = *self - rhs;
}
}
impl<const LIMBS: usize> SubAssign<DynResidue<LIMBS>> for DynResidue<LIMBS> {
fn sub_assign(&mut self, rhs: DynResidue<LIMBS>) {
*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());
}
}

View File

@@ -0,0 +1,9 @@
use crate::Uint;
pub(crate) const fn sub_montgomery_form<const LIMBS: usize>(
a: &Uint<LIMBS>,
b: &Uint<LIMBS>,
modulus: &Uint<LIMBS>,
) -> Uint<LIMBS> {
a.sub_mod(b, modulus)
}

414
vendor/crypto-bigint/src/uint/mul.rs vendored Normal file
View File

@@ -0,0 +1,414 @@
//! [`Uint`] addition operations.
use crate::{Checked, CheckedMul, Concat, ConcatMixed, Limb, Uint, WideWord, Word, Wrapping, Zero};
use core::ops::{Mul, MulAssign};
use subtle::CtOption;
impl<const LIMBS: usize> Uint<LIMBS> {
/// Multiply `self` by `rhs`, returning a concatenated "wide" result.
pub fn mul<const HLIMBS: usize>(
&self,
rhs: &Uint<HLIMBS>,
) -> <Uint<HLIMBS> as ConcatMixed<Self>>::MixedOutput
where
Uint<HLIMBS>: ConcatMixed<Self>,
{
let (lo, hi) = self.mul_wide(rhs);
hi.concat_mixed(&lo)
}
/// 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: <https://github.com/RustCrypto/crypto-bigint/issues/4>
pub const fn mul_wide<const HLIMBS: usize>(&self, rhs: &Uint<HLIMBS>) -> (Self, Uint<HLIMBS>) {
let mut i = 0;
let mut lo = Self::ZERO;
let mut hi = Uint::<HLIMBS>::ZERO;
// Schoolbook multiplication.
// TODO(tarcieri): use Karatsuba for better performance?
while i < LIMBS {
let mut j = 0;
let mut carry = Limb::ZERO;
while j < HLIMBS {
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;
}
if i + j >= LIMBS {
hi.limbs[i + j - LIMBS] = carry;
} else {
lo.limbs[i + j] = carry;
}
i += 1;
}
(lo, hi)
}
/// Perform saturating multiplication, returning `MAX` on overflow.
pub const fn saturating_mul<const HLIMBS: usize>(&self, rhs: &Uint<HLIMBS>) -> Self {
let (res, overflow) = self.mul_wide(rhs);
Self::ct_select(&res, &Self::MAX, overflow.ct_is_nonzero())
}
/// Perform wrapping multiplication, discarding overflow.
pub const fn wrapping_mul<const H: usize>(&self, rhs: &Uint<H>) -> Self {
self.mul_wide(rhs).0
}
/// Square self, returning a concatenated "wide" result.
pub fn square(&self) -> <Self as Concat>::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<const LIMBS: usize, const HLIMBS: usize> CheckedMul<&Uint<HLIMBS>> for Uint<LIMBS> {
type Output = Self;
fn checked_mul(&self, rhs: &Uint<HLIMBS>) -> CtOption<Self> {
let (lo, hi) = self.mul_wide(rhs);
CtOption::new(lo, hi.is_zero())
}
}
impl<const LIMBS: usize, const HLIMBS: usize> Mul<Wrapping<Uint<HLIMBS>>>
for Wrapping<Uint<LIMBS>>
{
type Output = Self;
fn mul(self, rhs: Wrapping<Uint<HLIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.wrapping_mul(&rhs.0))
}
}
impl<const LIMBS: usize, const HLIMBS: usize> Mul<&Wrapping<Uint<HLIMBS>>>
for Wrapping<Uint<LIMBS>>
{
type Output = Self;
fn mul(self, rhs: &Wrapping<Uint<HLIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.wrapping_mul(&rhs.0))
}
}
impl<const LIMBS: usize, const HLIMBS: usize> Mul<Wrapping<Uint<HLIMBS>>>
for &Wrapping<Uint<LIMBS>>
{
type Output = Wrapping<Uint<LIMBS>>;
fn mul(self, rhs: Wrapping<Uint<HLIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.wrapping_mul(&rhs.0))
}
}
impl<const LIMBS: usize, const HLIMBS: usize> Mul<&Wrapping<Uint<HLIMBS>>>
for &Wrapping<Uint<LIMBS>>
{
type Output = Wrapping<Uint<LIMBS>>;
fn mul(self, rhs: &Wrapping<Uint<HLIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.wrapping_mul(&rhs.0))
}
}
impl<const LIMBS: usize, const HLIMBS: usize> MulAssign<Wrapping<Uint<HLIMBS>>>
for Wrapping<Uint<LIMBS>>
{
fn mul_assign(&mut self, other: Wrapping<Uint<HLIMBS>>) {
*self = *self * other;
}
}
impl<const LIMBS: usize, const HLIMBS: usize> MulAssign<&Wrapping<Uint<HLIMBS>>>
for Wrapping<Uint<LIMBS>>
{
fn mul_assign(&mut self, other: &Wrapping<Uint<HLIMBS>>) {
*self = *self * other;
}
}
impl<const LIMBS: usize, const HLIMBS: usize> Mul<Checked<Uint<HLIMBS>>> for Checked<Uint<LIMBS>> {
type Output = Self;
fn mul(self, rhs: Checked<Uint<HLIMBS>>) -> Checked<Uint<LIMBS>> {
Checked(self.0.and_then(|a| rhs.0.and_then(|b| a.checked_mul(&b))))
}
}
impl<const LIMBS: usize, const HLIMBS: usize> Mul<&Checked<Uint<HLIMBS>>> for Checked<Uint<LIMBS>> {
type Output = Checked<Uint<LIMBS>>;
fn mul(self, rhs: &Checked<Uint<HLIMBS>>) -> Checked<Uint<LIMBS>> {
Checked(self.0.and_then(|a| rhs.0.and_then(|b| a.checked_mul(&b))))
}
}
impl<const LIMBS: usize, const HLIMBS: usize> Mul<Checked<Uint<HLIMBS>>> for &Checked<Uint<LIMBS>> {
type Output = Checked<Uint<LIMBS>>;
fn mul(self, rhs: Checked<Uint<HLIMBS>>) -> Checked<Uint<LIMBS>> {
Checked(self.0.and_then(|a| rhs.0.and_then(|b| a.checked_mul(&b))))
}
}
impl<const LIMBS: usize, const HLIMBS: usize> Mul<&Checked<Uint<HLIMBS>>>
for &Checked<Uint<LIMBS>>
{
type Output = Checked<Uint<LIMBS>>;
fn mul(self, rhs: &Checked<Uint<HLIMBS>>) -> Checked<Uint<LIMBS>> {
Checked(self.0.and_then(|a| rhs.0.and_then(|b| a.checked_mul(&b))))
}
}
impl<const LIMBS: usize, const HLIMBS: usize> MulAssign<Checked<Uint<HLIMBS>>>
for Checked<Uint<LIMBS>>
{
fn mul_assign(&mut self, other: Checked<Uint<HLIMBS>>) {
*self = *self * other;
}
}
impl<const LIMBS: usize, const HLIMBS: usize> MulAssign<&Checked<Uint<HLIMBS>>>
for Checked<Uint<LIMBS>>
{
fn mul_assign(&mut self, other: &Checked<Uint<HLIMBS>>) {
*self = *self * other;
}
}
impl<const LIMBS: usize, const HLIMBS: usize> Mul<Uint<HLIMBS>> for Uint<LIMBS>
where
Uint<HLIMBS>: ConcatMixed<Uint<LIMBS>>,
{
type Output = <Uint<HLIMBS> as ConcatMixed<Self>>::MixedOutput;
fn mul(self, other: Uint<HLIMBS>) -> Self::Output {
Uint::mul(&self, &other)
}
}
impl<const LIMBS: usize, const HLIMBS: usize> Mul<&Uint<HLIMBS>> for Uint<LIMBS>
where
Uint<HLIMBS>: ConcatMixed<Uint<LIMBS>>,
{
type Output = <Uint<HLIMBS> as ConcatMixed<Self>>::MixedOutput;
fn mul(self, other: &Uint<HLIMBS>) -> Self::Output {
Uint::mul(&self, other)
}
}
impl<const LIMBS: usize, const HLIMBS: usize> Mul<Uint<HLIMBS>> for &Uint<LIMBS>
where
Uint<HLIMBS>: ConcatMixed<Uint<LIMBS>>,
{
type Output = <Uint<HLIMBS> as ConcatMixed<Uint<LIMBS>>>::MixedOutput;
fn mul(self, other: Uint<HLIMBS>) -> Self::Output {
Uint::mul(self, &other)
}
}
impl<const LIMBS: usize, const HLIMBS: usize> Mul<&Uint<HLIMBS>> for &Uint<LIMBS>
where
Uint<HLIMBS>: ConcatMixed<Uint<LIMBS>>,
{
type Output = <Uint<HLIMBS> as ConcatMixed<Uint<LIMBS>>>::MixedOutput;
fn mul(self, other: &Uint<HLIMBS>) -> Self::Output {
Uint::mul(self, other)
}
}
#[cfg(test)]
mod tests {
use crate::{CheckedMul, Zero, U128, U192, 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 mul_concat_even() {
assert_eq!(U64::ZERO * U64::MAX, U128::ZERO);
assert_eq!(U64::MAX * U64::ZERO, U128::ZERO);
assert_eq!(
U64::MAX * U64::MAX,
U128::from_u128(0xfffffffffffffffe_0000000000000001)
);
assert_eq!(
U64::ONE * U64::MAX,
U128::from_u128(0x0000000000000000_ffffffffffffffff)
);
}
#[test]
fn mul_concat_mixed() {
let a = U64::from_u64(0x0011223344556677);
let b = U128::from_u128(0x8899aabbccddeeff_8899aabbccddeeff);
assert_eq!(a * b, U192::from(&a).saturating_mul(&b));
assert_eq!(b * a, U192::from(&b).saturating_mul(&a));
}
#[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));
}
}

133
vendor/crypto-bigint/src/uint/mul_mod.rs vendored Normal file
View File

@@ -0,0 +1,133 @@
//! [`Uint`] multiplication modulus operations.
use crate::{Limb, Uint, WideWord, Word};
impl<const LIMBS: usize> Uint<LIMBS> {
/// Computes `self * rhs mod p` 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<const LIMBS: usize>(
a: &Uint<LIMBS>,
b: &Uint<LIMBS>,
c: Limb,
carry: Limb,
) -> (Uint<LIMBS>, 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::<Limb>::random(&mut rng),
NonZero::<Limb>::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);
}

51
vendor/crypto-bigint/src/uint/neg.rs vendored Normal file
View File

@@ -0,0 +1,51 @@
use core::ops::Neg;
use crate::{CtChoice, Limb, Uint, WideWord, Word, Wrapping};
impl<const LIMBS: usize> Neg for Wrapping<Uint<LIMBS>> {
type Output = Self;
fn neg(self) -> Self::Output {
Self(self.0.wrapping_neg())
}
}
impl<const LIMBS: usize> Uint<LIMBS> {
/// Negates based on `choice` by wrapping the integer.
pub(crate) const fn conditional_wrapping_neg(&self, choice: CtChoice) -> Uint<LIMBS> {
Uint::ct_select(self, &self.wrapping_neg(), choice)
}
/// Perform wrapping negation.
pub const fn wrapping_neg(&self) -> Self {
let mut ret = [Limb::ZERO; LIMBS];
let mut carry = 1;
let mut i = 0;
while i < LIMBS {
let r = (!self.limbs[i].0 as WideWord) + carry;
ret[i] = Limb(r as Word);
carry = r >> Limb::BITS;
i += 1;
}
Uint::new(ret)
}
}
#[cfg(test)]
mod tests {
use crate::U256;
#[test]
fn wrapping_neg() {
assert_eq!(U256::ZERO.wrapping_neg(), U256::ZERO);
assert_eq!(U256::MAX.wrapping_neg(), U256::ONE);
assert_eq!(
U256::from_u64(13).wrapping_neg(),
U256::from_u64(13).not().saturating_add(&U256::ONE)
);
assert_eq!(
U256::from_u64(42).wrapping_neg(),
U256::from_u64(42).saturating_sub(&U256::ONE).not()
);
}
}

View File

@@ -0,0 +1,68 @@
//! [`Uint`] negation modulus operations.
use crate::{Limb, NegMod, Uint};
impl<const LIMBS: usize> Uint<LIMBS> {
/// Computes `-a mod p`.
/// 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` 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<const LIMBS: usize> NegMod for Uint<LIMBS> {
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);
}
}

90
vendor/crypto-bigint/src/uint/rand.rs vendored Normal file
View File

@@ -0,0 +1,90 @@
//! Random number generator support
use super::Uint;
use crate::{Encoding, Limb, NonZero, Random, RandomMod};
use rand_core::CryptoRngCore;
use subtle::ConstantTimeLess;
impl<const LIMBS: usize> Random for Uint<LIMBS> {
/// 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<const LIMBS: usize> RandomMod for Uint<LIMBS> {
/// 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(rng: &mut impl CryptoRngCore, modulus: &NonZero<Self>) -> Self {
let mut n = Self::ZERO;
let n_bits = modulus.as_ref().bits_vartime();
let n_bytes = (n_bits + 7) / 8;
let n_limbs = (n_bits + Limb::BITS - 1) / Limb::BITS;
let hi_bytes = n_bytes - (n_limbs - 1) * Limb::BYTES;
let mut bytes = Limb::ZERO.to_le_bytes();
loop {
for i in 0..n_limbs - 1 {
rng.fill_bytes(bytes.as_mut());
// Need to deserialize from little-endian to make sure that two 32-bit limbs
// deserialized sequentially are equal to one 64-bit limb produced from the same
// byte stream.
n.limbs[i] = Limb::from_le_bytes(bytes);
}
// Generate the high limb which may need to only be filled partially.
bytes.as_mut().fill(0);
rng.fill_bytes(&mut (bytes.as_mut()[0..hi_bytes]));
n.limbs[n_limbs - 1] = Limb::from_le_bytes(bytes);
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);
// Check that the value is in range
assert!(res >= U256::ZERO);
assert!(res < U256::from(42u8));
// 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);
// Check that the value is in range
assert!(res >= U256::ZERO);
assert!(res < U256::from(0x10000000000000001u128));
}
}

37
vendor/crypto-bigint/src/uint/resize.rs vendored Normal file
View File

@@ -0,0 +1,37 @@
use super::Uint;
impl<const LIMBS: usize> Uint<LIMBS> {
/// Construct a `Uint<T>` from the unsigned integer value,
/// truncating the upper bits if the value is too large to be
/// represented.
#[inline(always)]
pub const fn resize<const T: usize>(&self) -> Uint<T> {
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"));
}
}

216
vendor/crypto-bigint/src/uint/shl.rs vendored Normal file
View File

@@ -0,0 +1,216 @@
//! [`Uint`] bitwise left shift operations.
use crate::{CtChoice, Limb, Uint, Word};
use core::ops::{Shl, ShlAssign};
impl<const LIMBS: usize> Uint<LIMBS> {
/// 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::<LIMBS>::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)
}
/// Computes `self << n`.
/// Returns zero if `n >= Self::BITS`.
pub const fn shl(&self, shift: usize) -> Self {
let overflow = CtChoice::from_usize_lt(shift, Self::BITS).not();
let shift = shift % Self::BITS;
let mut result = *self;
let mut i = 0;
while i < Self::LOG2_BITS {
let bit = CtChoice::from_lsb((shift as Word >> i) & 1);
result = Uint::ct_select(&result, &result.shl_vartime(1 << i), bit);
i += 1;
}
Uint::ct_select(&result, &Self::ZERO, overflow)
}
}
impl<const LIMBS: usize> Shl<usize> for Uint<LIMBS> {
type Output = Uint<LIMBS>;
/// 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<LIMBS> {
Uint::<LIMBS>::shl(&self, rhs)
}
}
impl<const LIMBS: usize> Shl<usize> for &Uint<LIMBS> {
type Output = Uint<LIMBS>;
/// 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<LIMBS> {
self.shl(rhs)
}
}
impl<const LIMBS: usize> ShlAssign<usize> for Uint<LIMBS> {
/// 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(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)
);
}
}

186
vendor/crypto-bigint/src/uint/shr.rs vendored Normal file
View File

@@ -0,0 +1,186 @@
//! [`Uint`] bitwise right shift operations.
use super::Uint;
use crate::{limb::HI_BIT, CtChoice, Limb, Word};
use core::ops::{Shr, ShrAssign};
impl<const LIMBS: usize> Uint<LIMBS> {
/// 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)
}
/// Computes `self << n`.
/// Returns zero if `n >= Self::BITS`.
pub const fn shr(&self, shift: usize) -> Self {
let overflow = CtChoice::from_usize_lt(shift, Self::BITS).not();
let shift = shift % Self::BITS;
let mut result = *self;
let mut i = 0;
while i < Self::LOG2_BITS {
let bit = CtChoice::from_lsb((shift as Word >> i) & 1);
result = Uint::ct_select(&result, &result.shr_vartime(1 << i), bit);
i += 1;
}
Uint::ct_select(&result, &Self::ZERO, overflow)
}
}
impl<const LIMBS: usize> Shr<usize> for Uint<LIMBS> {
type Output = Uint<LIMBS>;
/// 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<LIMBS> {
Uint::<LIMBS>::shr(&self, rhs)
}
}
impl<const LIMBS: usize> Shr<usize> for &Uint<LIMBS> {
type Output = Uint<LIMBS>;
/// 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<LIMBS> {
self.shr(rhs)
}
}
impl<const LIMBS: usize> ShrAssign<usize> for Uint<LIMBS> {
fn shr_assign(&mut self, rhs: usize) {
*self = self.shr(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)
);
}
}

37
vendor/crypto-bigint/src/uint/split.rs vendored Normal file
View File

@@ -0,0 +1,37 @@
use crate::{Limb, Uint};
/// Split this number in half, returning its high and low components
/// respectively.
#[inline]
pub(crate) const fn split_mixed<const L: usize, const H: usize, const O: usize>(
n: &Uint<O>,
) -> (Uint<H>, Uint<L>) {
let top = L + H;
let top = if top < O { top } else { O };
let mut lo = [Limb::ZERO; L];
let mut hi = [Limb::ZERO; H];
let mut i = 0;
while i < top {
if i < L {
lo[i] = n.limbs[i];
} else {
hi[i - L] = n.limbs[i];
}
i += 1;
}
(Uint { limbs: hi }, Uint { limbs: lo })
}
#[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));
}
}

177
vendor/crypto-bigint/src/uint/sqrt.rs vendored Normal file
View File

@@ -0,0 +1,177 @@
//! [`Uint`] square root operations.
use super::Uint;
use crate::{Limb, Word};
use subtle::{ConstantTimeEq, CtOption};
impl<const LIMBS: usize> Uint<LIMBS> {
/// See [`Self::sqrt_vartime`].
#[deprecated(
since = "0.5.3",
note = "This functionality will be moved to `sqrt_vartime` in a future release."
)]
pub const fn sqrt(&self) -> Self {
self.sqrt_vartime()
}
/// 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_vartime(&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())
}
/// See [`Self::wrapping_sqrt_vartime`].
#[deprecated(
since = "0.5.3",
note = "This functionality will be moved to `wrapping_sqrt_vartime` in a future release."
)]
pub const fn wrapping_sqrt(&self) -> Self {
self.wrapping_sqrt_vartime()
}
/// Wrapped sqrt is just normal √(`self`)
/// Theres 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_vartime(&self) -> Self {
self.sqrt_vartime()
}
/// See [`Self::checked_sqrt_vartime`].
#[deprecated(
since = "0.5.3",
note = "This functionality will be moved to `checked_sqrt_vartime` in a future release."
)]
pub fn checked_sqrt(&self) -> CtOption<Self> {
self.checked_sqrt_vartime()
}
/// Perform checked sqrt, returning a [`CtOption`] which `is_some`
/// only if the √(`self`)² == self
pub fn checked_sqrt_vartime(&self) -> CtOption<Self> {
let r = self.sqrt_vartime();
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_vartime(), U256::ZERO);
assert_eq!(U256::ONE.sqrt_vartime(), 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_vartime(), 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_vartime(), r);
assert_eq!(l.checked_sqrt_vartime().is_some().unwrap_u8(), 1u8);
}
}
#[test]
fn nonsquares() {
assert_eq!(U256::from(2u8).sqrt_vartime(), U256::from(1u8));
assert_eq!(
U256::from(2u8).checked_sqrt_vartime().is_some().unwrap_u8(),
0
);
assert_eq!(U256::from(3u8).sqrt_vartime(), U256::from(1u8));
assert_eq!(
U256::from(3u8).checked_sqrt_vartime().is_some().unwrap_u8(),
0
);
assert_eq!(U256::from(5u8).sqrt_vartime(), U256::from(2u8));
assert_eq!(U256::from(6u8).sqrt_vartime(), U256::from(2u8));
assert_eq!(U256::from(7u8).sqrt_vartime(), U256::from(2u8));
assert_eq!(U256::from(8u8).sqrt_vartime(), U256::from(2u8));
assert_eq!(U256::from(10u8).sqrt_vartime(), 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_vartime(), s);
assert_eq!(s2.checked_sqrt_vartime().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_vartime(), s2);
}
}
}

215
vendor/crypto-bigint/src/uint/sub.rs vendored Normal file
View File

@@ -0,0 +1,215 @@
//! [`Uint`] addition operations.
use super::Uint;
use crate::{Checked, CheckedSub, CtChoice, Limb, Wrapping, Zero};
use core::ops::{Sub, SubAssign};
use subtle::CtOption;
impl<const LIMBS: usize> Uint<LIMBS> {
/// 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);
Self::ct_select(&res, &Self::ZERO, CtChoice::from_mask(underflow.0))
}
/// 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<const LIMBS: usize> CheckedSub<&Uint<LIMBS>> for Uint<LIMBS> {
type Output = Self;
fn checked_sub(&self, rhs: &Self) -> CtOption<Self> {
let (result, underflow) = self.sbb(rhs, Limb::ZERO);
CtOption::new(result, underflow.is_zero())
}
}
impl<const LIMBS: usize> Sub for Wrapping<Uint<LIMBS>> {
type Output = Self;
fn sub(self, rhs: Self) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.wrapping_sub(&rhs.0))
}
}
impl<const LIMBS: usize> Sub<&Wrapping<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn sub(self, rhs: &Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.wrapping_sub(&rhs.0))
}
}
impl<const LIMBS: usize> Sub<Wrapping<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn sub(self, rhs: Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.wrapping_sub(&rhs.0))
}
}
impl<const LIMBS: usize> Sub<&Wrapping<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
type Output = Wrapping<Uint<LIMBS>>;
fn sub(self, rhs: &Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
Wrapping(self.0.wrapping_sub(&rhs.0))
}
}
impl<const LIMBS: usize> SubAssign for Wrapping<Uint<LIMBS>> {
fn sub_assign(&mut self, other: Self) {
*self = *self - other;
}
}
impl<const LIMBS: usize> SubAssign<&Wrapping<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
fn sub_assign(&mut self, other: &Self) {
*self = *self - other;
}
}
impl<const LIMBS: usize> Sub for Checked<Uint<LIMBS>> {
type Output = Self;
fn sub(self, rhs: Self) -> Checked<Uint<LIMBS>> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))),
)
}
}
impl<const LIMBS: usize> Sub<&Checked<Uint<LIMBS>>> for Checked<Uint<LIMBS>> {
type Output = Checked<Uint<LIMBS>>;
fn sub(self, rhs: &Checked<Uint<LIMBS>>) -> Checked<Uint<LIMBS>> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))),
)
}
}
impl<const LIMBS: usize> Sub<Checked<Uint<LIMBS>>> for &Checked<Uint<LIMBS>> {
type Output = Checked<Uint<LIMBS>>;
fn sub(self, rhs: Checked<Uint<LIMBS>>) -> Checked<Uint<LIMBS>> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))),
)
}
}
impl<const LIMBS: usize> Sub<&Checked<Uint<LIMBS>>> for &Checked<Uint<LIMBS>> {
type Output = Checked<Uint<LIMBS>>;
fn sub(self, rhs: &Checked<Uint<LIMBS>>) -> Checked<Uint<LIMBS>> {
Checked(
self.0
.and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))),
)
}
}
impl<const LIMBS: usize> SubAssign for Checked<Uint<LIMBS>> {
fn sub_assign(&mut self, other: Self) {
*self = *self - other;
}
}
impl<const LIMBS: usize> SubAssign<&Checked<Uint<LIMBS>>> for Checked<Uint<LIMBS>> {
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 saturating_sub_no_borrow() {
assert_eq!(
U128::from(5u64).saturating_sub(&U128::ONE),
U128::from(4u64)
);
}
#[test]
fn saturating_sub_with_borrow() {
assert_eq!(
U128::from(4u64).saturating_sub(&U128::from(5u64)),
U128::ZERO
);
}
#[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()));
}
}

191
vendor/crypto-bigint/src/uint/sub_mod.rs vendored Normal file
View File

@@ -0,0 +1,191 @@
//! [`Uint`] subtraction modulus operations.
use crate::{Limb, SubMod, Uint};
impl<const LIMBS: usize> Uint<LIMBS> {
/// Computes `self - rhs mod p`.
///
/// Assumes `self - rhs` as unbounded signed integer is in `[-p, p)`.
pub const fn sub_mod(&self, rhs: &Uint<LIMBS>, p: &Uint<LIMBS>) -> Uint<LIMBS> {
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` 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<const LIMBS: usize> SubMod for Uint<LIMBS> {
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::<Uint<$size>>::random(&mut rng),
NonZero::<Uint<$size>>::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::<Limb>::random(&mut rng),
NonZero::<Limb>::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);
}

117
vendor/crypto-bigint/src/wrapping.rs vendored Normal file
View File

@@ -0,0 +1,117 @@
//! 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<T>(pub T);
impl<T: Zero> Zero for Wrapping<T> {
const ZERO: Self = Self(T::ZERO);
}
impl<T: fmt::Display> fmt::Display for Wrapping<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T: fmt::Binary> fmt::Binary for Wrapping<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T: fmt::Octal> fmt::Octal for Wrapping<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T: fmt::LowerHex> fmt::LowerHex for Wrapping<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T: fmt::UpperHex> fmt::UpperHex for Wrapping<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T: ConditionallySelectable> ConditionallySelectable for Wrapping<T> {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Wrapping(T::conditional_select(&a.0, &b.0, choice))
}
}
impl<T: ConstantTimeEq> ConstantTimeEq for Wrapping<T> {
fn ct_eq(&self, other: &Self) -> Choice {
self.0.ct_eq(&other.0)
}
}
#[cfg(feature = "rand_core")]
impl<T: Random> Random for Wrapping<T> {
fn random(rng: &mut impl CryptoRngCore) -> Self {
Wrapping(Random::random(rng))
}
}
#[cfg(feature = "serde")]
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Wrapping<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(Self(T::deserialize(deserializer)?))
}
}
#[cfg(feature = "serde")]
impl<T: Serialize> Serialize for Wrapping<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(serializer)
}
}
#[cfg(all(test, feature = "serde"))]
#[allow(clippy::unwrap_used)]
mod tests {
use crate::{Wrapping, U64};
#[test]
fn serde() {
const TEST: Wrapping<U64> = Wrapping(U64::from_u64(0x0011223344556677));
let serialized = bincode::serialize(&TEST).unwrap();
let deserialized: Wrapping<U64> = bincode::deserialize(&serialized).unwrap();
assert_eq!(TEST, deserialized);
}
#[test]
fn serde_owned() {
const TEST: Wrapping<U64> = Wrapping(U64::from_u64(0x0011223344556677));
let serialized = bincode::serialize(&TEST).unwrap();
let deserialized: Wrapping<U64> = bincode::deserialize_from(serialized.as_slice()).unwrap();
assert_eq!(TEST, deserialized);
}
}

Binary file not shown.

View File

@@ -0,0 +1 @@
{"name":"crypto-bigint","vers":"0.5.5","deps":[{"name":"der","req":"^0.7","features":[],"optional":true,"default_features":false,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"generic-array","req":"^0.14","features":[],"optional":true,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"rand_core","req":"^0.6.4","features":[],"optional":true,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"rlp","req":"^0.5","features":[],"optional":true,"default_features":false,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"serdect","req":"^0.2","features":[],"optional":true,"default_features":false,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"subtle","req":"^2.4","features":[],"optional":false,"default_features":false,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"zeroize","req":"^1","features":[],"optional":true,"default_features":false,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"bincode","req":"^1","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"criterion","req":"^0.5","features":["html_reports"],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"hex-literal","req":"^0.4","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"num-bigint","req":"^0.4","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"num-integer","req":"^0.1","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"num-traits","req":"^0.2","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"proptest","req":"^1","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"rand_chacha","req":"^0.3","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"rand_core","req":"^0.6","features":["std"],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false}],"features":{"alloc":["serdect?/alloc"],"default":["rand"],"extra-sizes":[],"rand":["rand_core/std"],"serde":["dep:serdect"]},"features2":null,"cksum":"14442bac7ed2d058ebb3c097bf9855e3b60a75e32e80d4a712fd90ed782296e0","yanked":null,"links":null,"rust_version":null,"v":2}

View File

@@ -0,0 +1,10 @@
//! 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);
}

Some files were not shown because too many files have changed in this diff Show More